Download livediffusion/model.py from kerzgrr/diffusionminer: direct link, hf CLI and curl.
- Browser
- Download file 34.9 kB
-
https://huggingface.co/kerzgrr/diffusionminer/resolve/main/livediffusion/model.py
- Command line
-
hf download hf://kerzgrr/diffusionminer/livediffusion/model.py
-
curl -L -o model.py https://huggingface.co/kerzgrr/diffusionminer/resolve/main/livediffusion/model.py
34.9 kB
| from __future__ import annotations | |
| import math | |
| from dataclasses import dataclass | |
| import torch | |
| import torch.nn.functional as F | |
| from torch import nn | |
| from torch.utils.checkpoint import checkpoint | |
| from livediffusion.config import ModelConfig | |
| class PrefixCache: | |
| key_values: tuple[tuple[torch.Tensor, torch.Tensor], ...] | |
| pooled: torch.Tensor | |
| MemoryCache = PrefixCache | |
| def _video_positions( | |
| frames: int, | |
| height: int, | |
| width: int, | |
| time_offset: int, | |
| device: torch.device, | |
| ) -> torch.Tensor: | |
| time = torch.arange(time_offset, time_offset + frames, device=device) | |
| y = torch.arange(height, device=device) | |
| x = torch.arange(width, device=device) | |
| grid = torch.meshgrid(time, y, x, indexing="ij") | |
| return torch.stack(grid, dim=-1).reshape(-1, 3).float() | |
| class Rotary3D(nn.Module): | |
| """3D RoPE with a shorter temporal base so time and space do not share a spectrum.""" | |
| def __init__( | |
| self, | |
| head_size: int, | |
| time_base: float = 1_000.0, | |
| space_base: float = 10_000.0, | |
| ) -> None: | |
| super().__init__() | |
| self.rotary_size = (head_size // 6) * 6 | |
| self.axis_size = self.rotary_size // 3 | |
| axis_half = self.axis_size // 2 | |
| steps = torch.arange(axis_half, dtype=torch.float32) / max(axis_half, 1) | |
| time_frequencies = torch.exp(-math.log(time_base) * steps) | |
| space_frequencies = torch.exp(-math.log(space_base) * steps) | |
| self.register_buffer( | |
| "frequencies", | |
| torch.stack((time_frequencies, space_frequencies, space_frequencies)), | |
| persistent=False, | |
| ) | |
| def _rotate_half(inputs: torch.Tensor) -> torch.Tensor: | |
| pairs = inputs.reshape(*inputs.shape[:-1], -1, 2) | |
| first, second = pairs.unbind(dim=-1) | |
| return torch.stack((-second, first), dim=-1).flatten(-2) | |
| def forward(self, inputs: torch.Tensor, positions: torch.Tensor) -> torch.Tensor: | |
| angles = torch.cat( | |
| [ | |
| positions[:, axis, None] * self.frequencies[axis][None] | |
| for axis in range(3) | |
| ], | |
| dim=-1, | |
| ) | |
| cosine = angles.cos().repeat_interleave(2, dim=-1)[None, None] | |
| sine = angles.sin().repeat_interleave(2, dim=-1)[None, None] | |
| rotary, remainder = inputs.split( | |
| (self.rotary_size, inputs.shape[-1] - self.rotary_size), | |
| dim=-1, | |
| ) | |
| rotated = rotary * cosine.to(rotary.dtype) | |
| rotated = rotated + self._rotate_half(rotary) * sine.to(rotary.dtype) | |
| return torch.cat((rotated, remainder), dim=-1) | |
| class ScalarEmbedding(nn.Module): | |
| def __init__(self, hidden_size: int) -> None: | |
| super().__init__() | |
| self.hidden_size = hidden_size | |
| self.mlp = nn.Sequential( | |
| nn.Linear(hidden_size, hidden_size), | |
| nn.SiLU(), | |
| nn.Linear(hidden_size, hidden_size), | |
| ) | |
| def forward(self, value: torch.Tensor) -> torch.Tensor: | |
| value = value.reshape(-1).float() | |
| half = self.hidden_size // 2 | |
| frequencies = torch.exp( | |
| -math.log(10_000.0) | |
| * torch.arange(half, device=value.device, dtype=torch.float32) | |
| / half | |
| ) | |
| angles = value[:, None] * frequencies[None] * 1_000.0 | |
| embedding = torch.cat((angles.cos(), angles.sin()), dim=-1) | |
| return self.mlp(embedding.to(dtype=self.mlp[0].weight.dtype)) | |
| class SwiGLU(nn.Module): | |
| def __init__(self, hidden_size: int, ratio: float) -> None: | |
| super().__init__() | |
| inner_size = int(hidden_size * ratio * 2 / 3) | |
| inner_size = ((inner_size + 63) // 64) * 64 | |
| self.input = nn.Linear(hidden_size, inner_size * 2, bias=False) | |
| self.output = nn.Linear(inner_size, hidden_size, bias=False) | |
| def forward(self, inputs: torch.Tensor) -> torch.Tensor: | |
| values, gates = self.input(inputs).chunk(2, dim=-1) | |
| return self.output(values * F.silu(gates)) | |
| class SelfAttention(nn.Module): | |
| def __init__(self, hidden_size: int, num_heads: int, qk_norm: bool) -> None: | |
| super().__init__() | |
| self.num_heads = num_heads | |
| self.head_size = hidden_size // num_heads | |
| self.qkv = nn.Linear(hidden_size, hidden_size * 3, bias=False) | |
| self.output = nn.Linear(hidden_size, hidden_size, bias=False) | |
| self.q_norm = ( | |
| nn.RMSNorm(self.head_size, eps=1e-6) | |
| if qk_norm | |
| else nn.Identity() | |
| ) | |
| self.k_norm = ( | |
| nn.RMSNorm(self.head_size, eps=1e-6) | |
| if qk_norm | |
| else nn.Identity() | |
| ) | |
| self.rotary = Rotary3D(self.head_size) | |
| def forward(self, inputs: torch.Tensor, positions: torch.Tensor) -> torch.Tensor: | |
| batch, tokens, channels = inputs.shape | |
| query, key, value = self.qkv(inputs).reshape( | |
| batch, | |
| tokens, | |
| 3, | |
| self.num_heads, | |
| self.head_size, | |
| ).unbind(dim=2) | |
| query = self.rotary(self.q_norm(query).transpose(1, 2), positions) | |
| key = self.rotary(self.k_norm(key).transpose(1, 2), positions) | |
| value = value.transpose(1, 2) | |
| attended = F.scaled_dot_product_attention(query, key, value) | |
| return self.output(attended.transpose(1, 2).reshape(batch, tokens, channels)) | |
| class PrefixAttention(nn.Module): | |
| """Target attention over the joint clean-prefix and noisy-target sequence. | |
| Keys and values may use fewer heads than queries. Prefix and target keys are | |
| concatenated, so both sides share the same reduced head count. | |
| """ | |
| def __init__( | |
| self, | |
| hidden_size: int, | |
| num_heads: int, | |
| qk_norm: bool, | |
| kv_heads: int = 0, | |
| ) -> None: | |
| super().__init__() | |
| self.num_heads = num_heads | |
| self.head_size = hidden_size // num_heads | |
| self.kv_heads = kv_heads or num_heads | |
| kv_size = self.kv_heads * self.head_size | |
| self.target_qkv = nn.Linear(hidden_size, hidden_size + kv_size * 2, bias=False) | |
| self.prefix_key_value = nn.Linear(hidden_size, kv_size * 2, bias=False) | |
| self.output = nn.Linear(hidden_size, hidden_size, bias=False) | |
| self.q_norm = ( | |
| nn.RMSNorm(self.head_size, eps=1e-6) | |
| if qk_norm | |
| else nn.Identity() | |
| ) | |
| self.k_norm = ( | |
| nn.RMSNorm(self.head_size, eps=1e-6) | |
| if qk_norm | |
| else nn.Identity() | |
| ) | |
| self.rotary = Rotary3D(self.head_size) | |
| def project_prefix( | |
| self, | |
| prefix: torch.Tensor, | |
| positions: torch.Tensor, | |
| ) -> tuple[torch.Tensor, torch.Tensor]: | |
| batch, tokens, _ = prefix.shape | |
| key, value = self.prefix_key_value(prefix).reshape( | |
| batch, | |
| tokens, | |
| 2, | |
| self.kv_heads, | |
| self.head_size, | |
| ).unbind(dim=2) | |
| key = self.rotary(self.k_norm(key).transpose(1, 2), positions) | |
| return key, value.transpose(1, 2) | |
| def forward_cached( | |
| self, | |
| target: torch.Tensor, | |
| target_positions: torch.Tensor, | |
| prefix_key_value: tuple[torch.Tensor, torch.Tensor], | |
| ) -> torch.Tensor: | |
| batch, tokens, channels = target.shape | |
| kv_size = self.kv_heads * self.head_size | |
| projected = self.target_qkv(target) | |
| query, key, value = projected.split((channels, kv_size, kv_size), dim=-1) | |
| query = query.reshape(batch, tokens, self.num_heads, self.head_size) | |
| key = key.reshape(batch, tokens, self.kv_heads, self.head_size) | |
| value = value.reshape(batch, tokens, self.kv_heads, self.head_size) | |
| query = self.rotary(self.q_norm(query).transpose(1, 2), target_positions) | |
| key = self.rotary(self.k_norm(key).transpose(1, 2), target_positions) | |
| value = value.transpose(1, 2) | |
| prefix_key, prefix_value = prefix_key_value | |
| key = torch.cat((prefix_key, key), dim=2) | |
| value = torch.cat((prefix_value, value), dim=2) | |
| attended = F.scaled_dot_product_attention( | |
| query, | |
| key, | |
| value, | |
| enable_gqa=self.kv_heads != self.num_heads, | |
| ) | |
| return self.output(attended.transpose(1, 2).reshape(batch, tokens, channels)) | |
| class WorldMemoryState: | |
| plane: torch.Tensor | |
| registers: torch.Tensor | |
| class WorldMemory(nn.Module): | |
| """Gated recurrent memory at latent resolution, plus global register state. | |
| The plane is a convolutional GRU over one cell per latent position, so an | |
| irreversible world edit stays represented after it scrolls out of the | |
| attention prefix. Registers carry frame-global state the plane cannot hold. | |
| """ | |
| def __init__( | |
| self, | |
| latent_channels: int, | |
| hidden_size: int, | |
| memory_channels: int, | |
| read_patch: int, | |
| register_tokens: int, | |
| ) -> None: | |
| super().__init__() | |
| self.memory_channels = memory_channels | |
| self.read_patch = read_patch | |
| self.register_tokens = register_tokens | |
| self.cell = nn.Conv2d( | |
| latent_channels + memory_channels, | |
| memory_channels * 3, | |
| kernel_size=3, | |
| padding=1, | |
| ) | |
| self.read = nn.Conv2d( | |
| memory_channels, | |
| hidden_size, | |
| kernel_size=read_patch, | |
| stride=read_patch, | |
| ) | |
| self.read_norm = nn.RMSNorm(hidden_size, eps=1e-6) | |
| self.scale_embedding = nn.Parameter(torch.zeros(1, 1, hidden_size)) | |
| self.register_update = ( | |
| nn.Linear(memory_channels + hidden_size, hidden_size * 2) | |
| if register_tokens > 0 | |
| else None | |
| ) | |
| def initial_state( | |
| self, | |
| batch: int, | |
| height: int, | |
| width: int, | |
| registers: torch.Tensor, | |
| device: torch.device, | |
| dtype: torch.dtype, | |
| ) -> WorldMemoryState: | |
| plane = torch.zeros( | |
| batch, | |
| self.memory_channels, | |
| height, | |
| width, | |
| device=device, | |
| dtype=dtype, | |
| ) | |
| return WorldMemoryState(plane, registers) | |
| def advance( | |
| self, | |
| state: WorldMemoryState, | |
| frames: torch.Tensor, | |
| ) -> WorldMemoryState: | |
| plane = state.plane | |
| for index in range(frames.shape[1]): | |
| latent = frames[:, index].to(plane.dtype) | |
| reset, update, candidate = self.cell( | |
| torch.cat((latent, plane), dim=1) | |
| ).chunk(3, dim=1) | |
| gate = torch.sigmoid(update) | |
| proposal = torch.tanh(candidate + torch.sigmoid(reset) * plane) | |
| plane = plane * (1.0 - gate) + proposal * gate | |
| registers = state.registers | |
| if self.register_update is not None: | |
| pooled = plane.mean(dim=(2, 3)) | |
| summary = torch.cat( | |
| (pooled[:, None].expand(-1, registers.shape[1], -1), registers), | |
| dim=-1, | |
| ) | |
| gate, proposal = self.register_update(summary).chunk(2, dim=-1) | |
| gate = torch.sigmoid(gate) | |
| registers = registers * (1.0 - gate) + torch.tanh(proposal) * gate | |
| return WorldMemoryState(plane, registers) | |
| def tokens(self, state: WorldMemoryState) -> torch.Tensor: | |
| read = self.read(state.plane).flatten(2).transpose(1, 2) | |
| return self.read_norm(read) + self.scale_embedding | |
| class SharedModulation(nn.Module): | |
| """One adaLN projection shared by every block, with per-block offsets. | |
| Per-block modulation costs 6 * hidden^2 each; sharing recovers that budget | |
| for depth while keeping each block independently steerable. | |
| """ | |
| def __init__(self, hidden_size: int, blocks: int) -> None: | |
| super().__init__() | |
| self.projection = nn.Linear(hidden_size, hidden_size * 6) | |
| self.offsets = nn.Parameter(torch.zeros(blocks, hidden_size * 6)) | |
| def forward(self, condition: torch.Tensor, block_index: int) -> torch.Tensor: | |
| return self.projection(F.silu(condition)) + self.offsets[block_index] | |
| class PrefixEncoderBlock(nn.Module): | |
| """Clean-context stack that runs before the joint prefix/target DiT.""" | |
| def __init__(self, config: ModelConfig) -> None: | |
| super().__init__() | |
| hidden_size = config.hidden_size | |
| self.norm1 = nn.RMSNorm(hidden_size, eps=1e-6) | |
| self.attention = SelfAttention( | |
| hidden_size, | |
| config.num_heads, | |
| config.qk_norm, | |
| ) | |
| self.norm2 = nn.RMSNorm(hidden_size, eps=1e-6) | |
| self.mlp = SwiGLU(hidden_size, config.mlp_ratio) | |
| self.attn_scale = nn.Parameter(torch.ones(hidden_size)) | |
| self.mlp_scale = nn.Parameter(torch.ones(hidden_size)) | |
| def forward(self, prefix: torch.Tensor, positions: torch.Tensor) -> torch.Tensor: | |
| prefix = prefix + self.attn_scale * self.attention(self.norm1(prefix), positions) | |
| return prefix + self.mlp_scale * self.mlp(self.norm2(prefix)) | |
| class PrefixDiTBlock(nn.Module): | |
| def __init__(self, config: ModelConfig) -> None: | |
| super().__init__() | |
| hidden_size = config.hidden_size | |
| self.prefix_norm1 = nn.RMSNorm(hidden_size, eps=1e-6) | |
| self.prefix_attention = SelfAttention( | |
| hidden_size, | |
| config.num_heads, | |
| config.qk_norm, | |
| ) | |
| self.prefix_norm2 = nn.RMSNorm(hidden_size, eps=1e-6) | |
| self.prefix_mlp = SwiGLU(hidden_size, config.mlp_ratio) | |
| self.prefix_projection_norm = nn.RMSNorm(hidden_size, eps=1e-6) | |
| self.target_norm1 = nn.RMSNorm( | |
| hidden_size, | |
| eps=1e-6, | |
| elementwise_affine=False, | |
| ) | |
| self.target_attention = PrefixAttention( | |
| hidden_size, | |
| config.num_heads, | |
| config.qk_norm, | |
| config.kv_heads, | |
| ) | |
| self.target_norm2 = nn.RMSNorm( | |
| hidden_size, | |
| eps=1e-6, | |
| elementwise_affine=False, | |
| ) | |
| self.target_mlp = SwiGLU(hidden_size, config.mlp_ratio) | |
| self.modulation = ( | |
| None | |
| if config.shared_modulation | |
| else nn.Linear(hidden_size, hidden_size * 6) | |
| ) | |
| def _modulate( | |
| inputs: torch.Tensor, | |
| shift: torch.Tensor, | |
| scale: torch.Tensor, | |
| ) -> torch.Tensor: | |
| return inputs * (1.0 + scale[:, None]) + shift[:, None] | |
| def advance_prefix( | |
| self, | |
| prefix: torch.Tensor, | |
| positions: torch.Tensor, | |
| ) -> torch.Tensor: | |
| prefix = prefix + self.prefix_attention(self.prefix_norm1(prefix), positions) | |
| return prefix + self.prefix_mlp(self.prefix_norm2(prefix)) | |
| def prefix_key_value( | |
| self, | |
| prefix: torch.Tensor, | |
| positions: torch.Tensor, | |
| ) -> tuple[torch.Tensor, torch.Tensor]: | |
| return self.target_attention.project_prefix( | |
| self.prefix_projection_norm(prefix), | |
| positions, | |
| ) | |
| def advance_target( | |
| self, | |
| target: torch.Tensor, | |
| condition: torch.Tensor, | |
| target_positions: torch.Tensor, | |
| prefix_key_value: tuple[torch.Tensor, torch.Tensor], | |
| modulation: torch.Tensor | None = None, | |
| ) -> torch.Tensor: | |
| if modulation is None: | |
| if self.modulation is None: | |
| raise RuntimeError("Shared modulation must be supplied by the trunk.") | |
| modulation = self.modulation(F.silu(condition)) | |
| shift1, scale1, gate1, shift2, scale2, gate2 = modulation.chunk(6, dim=-1) | |
| normalized = self._modulate(self.target_norm1(target), shift1, scale1) | |
| target = target + gate1[:, None] * self.target_attention.forward_cached( | |
| normalized, | |
| target_positions, | |
| prefix_key_value, | |
| ) | |
| normalized = self._modulate(self.target_norm2(target), shift2, scale2) | |
| return target + gate2[:, None] * self.target_mlp(normalized) | |
| def forward( | |
| self, | |
| prefix: torch.Tensor, | |
| target: torch.Tensor, | |
| condition: torch.Tensor, | |
| prefix_positions: torch.Tensor, | |
| target_positions: torch.Tensor, | |
| modulation: torch.Tensor | None = None, | |
| ) -> tuple[torch.Tensor, torch.Tensor]: | |
| prefix = self.advance_prefix(prefix, prefix_positions) | |
| key_value = self.prefix_key_value(prefix, prefix_positions) | |
| target = self.advance_target( | |
| target, | |
| condition, | |
| target_positions, | |
| key_value, | |
| modulation, | |
| ) | |
| return prefix, target | |
| class CausalLatentVideoDiT(nn.Module): | |
| """Multiscale clean-prefix/noisy-suffix latent video transformer.""" | |
| def __init__( | |
| self, | |
| model_config: ModelConfig, | |
| latent_channels: int, | |
| history_frames: int = 12, | |
| ) -> None: | |
| super().__init__() | |
| self.model_config = model_config | |
| self.latent_channels = latent_channels | |
| self.history_frames = history_frames | |
| self.gradient_checkpointing = False | |
| hidden_size = model_config.hidden_size | |
| target_patch = model_config.target_patch_size | |
| coarse_patch = model_config.memory_patch_size | |
| fine_patch = model_config.fine_memory_patch_size | |
| self.target_patch_embed = nn.Conv3d( | |
| latent_channels, | |
| hidden_size, | |
| kernel_size=(1, target_patch, target_patch), | |
| stride=(1, target_patch, target_patch), | |
| ) | |
| self.coarse_prefix_embed = nn.Conv3d( | |
| latent_channels, | |
| hidden_size, | |
| kernel_size=(1, coarse_patch, coarse_patch), | |
| stride=(1, coarse_patch, coarse_patch), | |
| ) | |
| self.fine_prefix_embed = nn.Conv3d( | |
| latent_channels, | |
| hidden_size, | |
| kernel_size=(1, fine_patch, fine_patch), | |
| stride=(1, fine_patch, fine_patch), | |
| ) | |
| self.motion_prefix_embed = nn.Conv3d( | |
| latent_channels, | |
| hidden_size, | |
| kernel_size=(1, fine_patch, fine_patch), | |
| stride=(1, fine_patch, fine_patch), | |
| ) | |
| self.coarse_scale_embedding = nn.Parameter(torch.zeros(1, 1, hidden_size)) | |
| self.fine_scale_embedding = nn.Parameter(torch.zeros(1, 1, hidden_size)) | |
| self.register_tokens = ( | |
| nn.Parameter(torch.randn(1, model_config.register_tokens, hidden_size) * 0.02) | |
| if model_config.register_tokens > 0 | |
| else None | |
| ) | |
| self.memory_blocks = nn.ModuleList( | |
| PrefixEncoderBlock(model_config) | |
| for _ in range(model_config.prefix_encoder_depth) | |
| ) | |
| self.t_embedding = ScalarEmbedding(hidden_size) | |
| self.r_embedding = ScalarEmbedding(hidden_size) | |
| self.delta_embedding = ScalarEmbedding(hidden_size) | |
| self.time_projection = nn.Sequential( | |
| nn.Linear(hidden_size * 3, hidden_size), | |
| nn.SiLU(), | |
| nn.Linear(hidden_size, hidden_size), | |
| ) | |
| self.prefix_condition = nn.Linear(hidden_size, hidden_size) | |
| self.action_projection = ( | |
| nn.Sequential( | |
| nn.Linear(model_config.action_dim, hidden_size), | |
| nn.SiLU(), | |
| nn.Linear(hidden_size, hidden_size), | |
| ) | |
| if model_config.action_dim > 0 | |
| else None | |
| ) | |
| self.context_projection = ( | |
| nn.Linear(model_config.context_dim, hidden_size, bias=False) | |
| if model_config.context_dim > 0 | |
| else None | |
| ) | |
| self.blocks = nn.ModuleList( | |
| PrefixDiTBlock(model_config) for _ in range(model_config.depth) | |
| ) | |
| self.shared_modulation = ( | |
| SharedModulation(hidden_size, model_config.depth) | |
| if model_config.shared_modulation | |
| else None | |
| ) | |
| self.world_memory = ( | |
| WorldMemory( | |
| latent_channels, | |
| hidden_size, | |
| model_config.memory_channels, | |
| coarse_patch, | |
| model_config.register_tokens, | |
| ) | |
| if model_config.memory_channels > 0 | |
| else None | |
| ) | |
| self.output_norm = nn.RMSNorm( | |
| hidden_size, | |
| eps=1e-6, | |
| elementwise_affine=False, | |
| ) | |
| self.output_modulation = nn.Linear(hidden_size, hidden_size * 2) | |
| self.output_projection = nn.Linear( | |
| hidden_size, | |
| target_patch * target_patch * latent_channels, | |
| ) | |
| self.outcome_norm = nn.RMSNorm(hidden_size, eps=1e-6) | |
| self.reward_head = nn.Linear(hidden_size, 1) | |
| self.terminal_head = nn.Linear(hidden_size, 1) | |
| self.reset_parameters() | |
| def enable_activation_checkpointing(self, enabled: bool = True) -> None: | |
| self.gradient_checkpointing = enabled | |
| def reset_parameters(self) -> None: | |
| for module in self.modules(): | |
| if isinstance(module, nn.Linear): | |
| nn.init.xavier_uniform_(module.weight) | |
| if module.bias is not None: | |
| nn.init.zeros_(module.bias) | |
| for embedding in ( | |
| self.target_patch_embed, | |
| self.coarse_prefix_embed, | |
| self.fine_prefix_embed, | |
| self.motion_prefix_embed, | |
| ): | |
| nn.init.normal_(embedding.weight, std=0.02) | |
| nn.init.normal_(self.coarse_scale_embedding, std=0.02) | |
| nn.init.normal_(self.fine_scale_embedding, std=0.02) | |
| for block in self.blocks: | |
| if block.modulation is not None: | |
| nn.init.zeros_(block.modulation.weight) | |
| nn.init.zeros_(block.modulation.bias) | |
| if self.shared_modulation is not None: | |
| nn.init.zeros_(self.shared_modulation.projection.weight) | |
| nn.init.zeros_(self.shared_modulation.projection.bias) | |
| nn.init.zeros_(self.shared_modulation.offsets) | |
| if self.world_memory is not None: | |
| nn.init.zeros_(self.world_memory.scale_embedding) | |
| nn.init.zeros_(self.output_modulation.weight) | |
| nn.init.zeros_(self.output_modulation.bias) | |
| nn.init.zeros_(self.output_projection.weight) | |
| nn.init.zeros_(self.output_projection.bias) | |
| nn.init.zeros_(self.reward_head.weight) | |
| nn.init.zeros_(self.reward_head.bias) | |
| nn.init.zeros_(self.terminal_head.weight) | |
| nn.init.zeros_(self.terminal_head.bias) | |
| def _patch( | |
| embedding: nn.Conv3d, | |
| video: torch.Tensor, | |
| time_offset: int, | |
| ) -> tuple[torch.Tensor, torch.Tensor]: | |
| tokens = embedding(video.transpose(1, 2)) | |
| _, _, frames, height, width = tokens.shape | |
| positions = _video_positions( | |
| frames, | |
| height, | |
| width, | |
| time_offset, | |
| video.device, | |
| ) | |
| return tokens.flatten(2).transpose(1, 2), positions | |
| def _encode_prefix( | |
| self, | |
| history: torch.Tensor, | |
| context: torch.Tensor | None = None, | |
| history_actions: torch.Tensor | None = None, | |
| ) -> tuple[torch.Tensor, torch.Tensor]: | |
| if history.shape[1] < self.history_frames: | |
| raise ValueError( | |
| f"Expected at least {self.history_frames} history frames, " | |
| f"got {history.shape[1]}." | |
| ) | |
| batch = history.shape[0] | |
| registers = ( | |
| self.register_tokens.expand(batch, -1, -1) | |
| if self.register_tokens is not None | |
| else None | |
| ) | |
| memory_tokens: torch.Tensor | None = None | |
| if self.world_memory is not None: | |
| # Every observed frame is folded into the recurrent state, including | |
| # frames older than the attention window. | |
| state = self.world_memory.initial_state( | |
| batch, | |
| history.shape[-2], | |
| history.shape[-1], | |
| registers | |
| if registers is not None | |
| else history.new_zeros(batch, 0, self.model_config.hidden_size), | |
| history.device, | |
| history.dtype, | |
| ) | |
| state = self.world_memory.advance(state, history) | |
| memory_tokens = self.world_memory.tokens(state) | |
| if registers is not None: | |
| registers = state.registers | |
| window = history[:, -self.history_frames :] | |
| coarse, coarse_positions = self._patch( | |
| self.coarse_prefix_embed, | |
| window, | |
| 0, | |
| ) | |
| if self.action_projection is not None and history_actions is not None: | |
| window_actions = history_actions[:, -self.history_frames :] | |
| tokens_per_frame = coarse.shape[1] // self.history_frames | |
| coarse = coarse + self.action_projection( | |
| window_actions | |
| ).repeat_interleave(tokens_per_frame, dim=1) | |
| history = window | |
| fine_frames = self.model_config.fine_history_frames | |
| fine_history = history[:, -fine_frames:] | |
| previous = history[:, -fine_frames - 1 : -1] | |
| if previous.shape[1] != fine_frames: | |
| previous = torch.cat((fine_history[:, :1], fine_history[:, :-1]), dim=1) | |
| motion = fine_history - previous | |
| fine, fine_positions = self._patch( | |
| self.fine_prefix_embed, | |
| fine_history, | |
| self.history_frames - fine_frames, | |
| ) | |
| motion_tokens, _ = self._patch( | |
| self.motion_prefix_embed, | |
| motion, | |
| self.history_frames - fine_frames, | |
| ) | |
| coarse = coarse + self.coarse_scale_embedding | |
| fine = fine + motion_tokens + self.fine_scale_embedding | |
| prefix = torch.cat((coarse, fine), dim=1) | |
| positions = torch.cat((coarse_positions, fine_positions), dim=0) | |
| if memory_tokens is not None: | |
| coarse_patch = self.model_config.memory_patch_size | |
| memory_positions = _video_positions( | |
| 1, | |
| history.shape[-2] // coarse_patch, | |
| history.shape[-1] // coarse_patch, | |
| -2, | |
| history.device, | |
| ) | |
| prefix = torch.cat((memory_tokens, prefix), dim=1) | |
| positions = torch.cat((memory_positions, positions), dim=0) | |
| if registers is not None: | |
| register_count = registers.shape[1] | |
| register_positions = torch.stack( | |
| ( | |
| torch.full((register_count,), -1.0, device=history.device), | |
| torch.zeros(register_count, device=history.device), | |
| torch.arange(register_count, device=history.device, dtype=torch.float32), | |
| ), | |
| dim=-1, | |
| ) | |
| prefix = torch.cat((registers, prefix), dim=1) | |
| positions = torch.cat((register_positions, positions), dim=0) | |
| if self.context_projection is not None and context is not None: | |
| projected = self.context_projection(context) | |
| prefix = torch.cat((prefix, projected), dim=1) | |
| positions = torch.cat( | |
| ( | |
| positions, | |
| torch.zeros(projected.shape[1], 3, device=history.device), | |
| ), | |
| dim=0, | |
| ) | |
| for block in self.memory_blocks: | |
| prefix = block(prefix, positions) | |
| return prefix, positions | |
| def _pool_prefix(self, prefix: torch.Tensor) -> torch.Tensor: | |
| register_count = self.model_config.register_tokens | |
| if register_count > 0: | |
| return prefix[:, :register_count].mean(dim=1) | |
| return prefix.mean(dim=1) | |
| def _condition( | |
| self, | |
| prefix: torch.Tensor, | |
| r: torch.Tensor, | |
| t: torch.Tensor, | |
| ) -> torch.Tensor: | |
| time = self.time_projection( | |
| torch.cat( | |
| ( | |
| self.t_embedding(t), | |
| self.r_embedding(r), | |
| self.delta_embedding(t - r), | |
| ), | |
| dim=-1, | |
| ) | |
| ) | |
| return time + self.prefix_condition(self._pool_prefix(prefix)) | |
| def build_memory_cache( | |
| self, | |
| history: torch.Tensor, | |
| context: torch.Tensor | None = None, | |
| history_actions: torch.Tensor | None = None, | |
| ) -> PrefixCache: | |
| prefix, positions = self._encode_prefix(history, context, history_actions) | |
| pooled = self.prefix_condition(self._pool_prefix(prefix)) | |
| key_values: list[tuple[torch.Tensor, torch.Tensor]] = [] | |
| for block in self.blocks: | |
| prefix = block.advance_prefix(prefix, positions) | |
| key_values.append(block.prefix_key_value(prefix, positions)) | |
| return PrefixCache(tuple(key_values), pooled) | |
| def predict_outcomes( | |
| self, | |
| history: torch.Tensor, | |
| actions: torch.Tensor | None = None, | |
| frame_count: int = 1, | |
| memory_cache: PrefixCache | None = None, | |
| history_actions: torch.Tensor | None = None, | |
| ) -> tuple[torch.Tensor, torch.Tensor]: | |
| if memory_cache is None: | |
| prefix, _ = self._encode_prefix(history, None, history_actions) | |
| pooled = self.prefix_condition(self._pool_prefix(prefix)) | |
| else: | |
| pooled = memory_cache.pooled | |
| hidden = pooled[:, None].expand(-1, frame_count, -1) | |
| if self.action_projection is not None: | |
| if actions is None or actions.shape[1] != frame_count: | |
| raise ValueError("Outcome actions must match frame_count.") | |
| hidden = hidden + self.action_projection(actions) | |
| hidden = self.outcome_norm(hidden) | |
| return self.reward_head(hidden).squeeze(-1), self.terminal_head(hidden).squeeze(-1) | |
| def _unpatchify( | |
| self, | |
| patches: torch.Tensor, | |
| frames: int, | |
| height: int, | |
| width: int, | |
| ) -> torch.Tensor: | |
| batch = patches.shape[0] | |
| patch = self.model_config.target_patch_size | |
| patches = patches.reshape( | |
| batch, | |
| frames, | |
| height, | |
| width, | |
| patch, | |
| patch, | |
| self.latent_channels, | |
| ) | |
| return patches.permute(0, 1, 6, 2, 4, 3, 5).reshape( | |
| batch, | |
| frames, | |
| self.latent_channels, | |
| height * patch, | |
| width * patch, | |
| ) | |
| def forward( | |
| self, | |
| noisy_target: torch.Tensor, | |
| history: torch.Tensor, | |
| r: torch.Tensor, | |
| t: torch.Tensor, | |
| actions: torch.Tensor | None = None, | |
| context: torch.Tensor | None = None, | |
| memory_cache: PrefixCache | None = None, | |
| history_actions: torch.Tensor | None = None, | |
| ) -> torch.Tensor: | |
| target_volume = self.target_patch_embed(noisy_target.transpose(1, 2)) | |
| batch, _, frames, height, width = target_volume.shape | |
| target = target_volume.flatten(2).transpose(1, 2) | |
| target_positions = _video_positions( | |
| frames, | |
| height, | |
| width, | |
| self.history_frames, | |
| noisy_target.device, | |
| ) | |
| if memory_cache is None: | |
| prefix, prefix_positions = self._encode_prefix( | |
| history, | |
| context, | |
| history_actions, | |
| ) | |
| condition = self._condition(prefix, r, t) | |
| else: | |
| prefix = None | |
| prefix_positions = None | |
| condition = self.time_projection( | |
| torch.cat( | |
| ( | |
| self.t_embedding(t), | |
| self.r_embedding(r), | |
| self.delta_embedding(t - r), | |
| ), | |
| dim=-1, | |
| ) | |
| ) + memory_cache.pooled | |
| if self.action_projection is not None: | |
| if actions is None or actions.shape[:2] != (batch, frames): | |
| raise ValueError("Actions must match [batch, target_frames, action_dim].") | |
| action_embedding = self.action_projection(actions) | |
| target = target + action_embedding.repeat_interleave(height * width, dim=1) | |
| condition = condition + action_embedding.mean(dim=1) | |
| for block_index, block in enumerate(self.blocks): | |
| modulation = ( | |
| self.shared_modulation(condition, block_index) | |
| if self.shared_modulation is not None | |
| else None | |
| ) | |
| if memory_cache is None: | |
| if prefix is None or prefix_positions is None: | |
| raise RuntimeError("Prefix state is unavailable.") | |
| if self.training and self.gradient_checkpointing: | |
| prefix, target = checkpoint( | |
| block, | |
| prefix, | |
| target, | |
| condition, | |
| prefix_positions, | |
| target_positions, | |
| modulation, | |
| use_reentrant=False, | |
| ) | |
| else: | |
| prefix, target = block( | |
| prefix, | |
| target, | |
| condition, | |
| prefix_positions, | |
| target_positions, | |
| modulation, | |
| ) | |
| else: | |
| target = block.advance_target( | |
| target, | |
| condition, | |
| target_positions, | |
| memory_cache.key_values[block_index], | |
| modulation, | |
| ) | |
| shift, scale = self.output_modulation(F.silu(condition)).chunk(2, dim=-1) | |
| target = self.output_norm(target) * (1.0 + scale[:, None]) + shift[:, None] | |
| return self._unpatchify( | |
| self.output_projection(target), | |
| frames, | |
| height, | |
| width, | |
| ) | |
| CausalVideoDiT = CausalLatentVideoDiT | |