# SPDX-License-Identifier: Apache-2.0 # SPDX-FileCopyrightText: Copyright contributors to the vLLM project """CausalWanModel — 40-layer DiT with causal attention and KV cache. Key differences from WanTransformer3DModel: - Causal self-attention (new frames only see history) - KV cache for streaming inference - Action/state token support (appended after video tokens) - Extended RoPE with action/state-specific frequencies - Inference-only forward with KV cache """ from __future__ import annotations import math from typing import Any import torch import torch.nn as nn from vllm.distributed import ( get_tensor_model_parallel_rank, get_tensor_model_parallel_world_size, get_tp_group, ) from vllm.model_executor.layers.conv import Conv3dLayer from vllm.model_executor.layers.linear import ( ColumnParallelLinear, RowParallelLinear, ) from vllm.model_executor.utils import set_weight_attrs from vllm_omni.diffusion.attention.layer import Attention from vllm_omni.diffusion.models.dreamzero.action_encoder import ( CategorySpecificMLP, MultiEmbodimentActionEncoder, ) # ── RoPE utilities ────────────────────────────────────────────────── def sinusoidal_embedding_1d(dim: int, position: torch.Tensor) -> torch.Tensor: """Sinusoidal positional embedding for timesteps.""" if dim % 2 != 0: raise ValueError(f"dim must be even, got {dim}.") half = dim // 2 position = position.type(torch.float64) sinusoid = torch.outer( position, torch.pow(10000, -torch.arange(half, dtype=position.dtype, device=position.device).div(half)), ) x = torch.cat([torch.cos(sinusoid), torch.sin(sinusoid)], dim=1) return x def rope_params(max_seq_len: int, dim: int) -> torch.Tensor: """Precompute complex-valued RoPE frequencies (polar form). Returns: complex tensor [max_seq_len, dim // 2] """ if dim % 2 != 0: raise ValueError(f"dim must be even, got {dim}.") freqs = torch.outer( torch.arange(max_seq_len), 1.0 / torch.pow(10000, torch.arange(0, dim, 2).to(torch.float64).div(dim)), ) freqs = torch.polar(torch.ones_like(freqs), freqs) return freqs def rope_apply(x: torch.Tensor, freqs: torch.Tensor) -> torch.Tensor: """Apply RoPE to x using precomputed complex freqs.""" B, seq_len, n, _ = x.shape x = torch.view_as_complex(x.to(torch.float64).reshape(B, seq_len, n, -1, 2)) freqs = freqs.unsqueeze(0) x = torch.view_as_real(x * freqs).flatten(3) return x def rope_action_apply( x: torch.Tensor, freqs: torch.Tensor, freqs_action: torch.Tensor, freqs_state: torch.Tensor, action_register_length: int | None, num_action_per_block: int = 32, num_state_per_block: int = 1, ) -> torch.Tensor: """RoPE with action/state frequency tables for multi-step sequences.""" B, seq_len, n, _ = x.shape x = torch.view_as_complex(x.to(torch.float64).reshape(B, seq_len, n, -1, 2)) if action_register_length is not None: if num_action_per_block is None: raise ValueError("num_action_per_block is required when action_register_length is set.") if num_state_per_block is None: raise ValueError("num_state_per_block is required when action_register_length is set.") chunk_size = action_register_length // (num_action_per_block + num_state_per_block) freqs_1d_action = freqs_action[: chunk_size * num_action_per_block].view( chunk_size * num_action_per_block, 1, -1 ) freqs_1d_state = freqs_state[: chunk_size * num_state_per_block].view(chunk_size * num_state_per_block, 1, -1) freqs = torch.cat([freqs, freqs_1d_action, freqs_1d_state], dim=0) freqs = freqs.unsqueeze(0) x = torch.view_as_real(x * freqs).flatten(3) return x def causal_rope_action_apply( x: torch.Tensor, freqs: torch.Tensor, freqs_action: torch.Tensor, freqs_state: torch.Tensor, action_register_length: int | None, num_action_per_block: int, num_state_per_block: int, action_state_index: int, ) -> torch.Tensor: """RoPE for single inference step (causal / KV-cache mode).""" B, seq_len, n, _ = x.shape x = torch.view_as_complex(x.to(torch.float64).reshape(B, seq_len, n, -1, 2)) if action_register_length is not None: expected_length = num_action_per_block + num_state_per_block if action_register_length != expected_length: raise ValueError( f"action_register_length must equal num_action_per_block + num_state_per_block " f"({expected_length}), got {action_register_length}." ) freqs_action = freqs_action[ action_state_index * num_action_per_block : (action_state_index + 1) * num_action_per_block ] freqs_state = freqs_state[ action_state_index * num_state_per_block : (action_state_index + 1) * num_state_per_block ] freqs_1d = torch.cat([freqs_action, freqs_state], dim=0).view(action_register_length, 1, -1) freqs = torch.cat([freqs, freqs_1d], dim=0) freqs = freqs.unsqueeze(0) x = torch.view_as_real(x * freqs).flatten(3) return x # ── Normalization ─────────────────────────────────────────────────── class WanLayerNorm(nn.LayerNorm): """LayerNorm wrapper used by DreamZero blocks.""" def __init__(self, dim: int, eps: float = 1e-6, elementwise_affine: bool = False) -> None: super().__init__(dim, eps=eps, elementwise_affine=elementwise_affine) class DistributedRMSNorm(nn.Module): """RMSNorm that computes global RMS across tensor parallel ranks.""" def __init__(self, hidden_size: int, eps: float = 1e-6): super().__init__() self.eps = eps self.weight = nn.Parameter(torch.ones(hidden_size)) set_weight_attrs(self.weight, {"weight_loader": self.weight_loader}) def weight_loader(self, param: torch.Tensor, loaded_weight: torch.Tensor) -> None: if param.shape == loaded_weight.shape: param.data.copy_(loaded_weight) return tp_size = get_tensor_model_parallel_world_size() if loaded_weight.shape[0] % tp_size != 0: raise ValueError( f"Cannot shard RMSNorm weight of shape {tuple(loaded_weight.shape)} across tp_size={tp_size}." ) shard_size = loaded_weight.shape[0] // tp_size start_idx = get_tensor_model_parallel_rank() * shard_size shard = loaded_weight.narrow(0, start_idx, shard_size) if param.shape != shard.shape: raise ValueError(f"RMSNorm shard shape mismatch: param={tuple(param.shape)}, shard={tuple(shard.shape)}.") param.data.copy_(shard) def forward(self, x: torch.Tensor) -> torch.Tensor: tp_size = get_tensor_model_parallel_world_size() x_float = x.float() local_sum_sq = x_float.pow(2).sum(dim=-1, keepdim=True) local_count = x.shape[-1] if tp_size > 1: global_sum_sq = local_sum_sq.clone() torch.distributed.all_reduce(global_sum_sq, group=get_tp_group().device_group) global_count = local_count * tp_size else: global_sum_sq = local_sum_sq global_count = local_count mean_sq = global_sum_sq / global_count return (x_float * torch.rsqrt(mean_sq + self.eps)).type_as(x) * self.weight # ── Projections ───────────────────────────────────────────────────── class MLPProj(nn.Module): """CLIP feature projection for i2v. Uses ColumnParallelLinear + RowParallelLinear (Qwen3_VisionMLP pattern). """ def __init__(self, in_dim: int, out_dim: int) -> None: super().__init__() self.norm1 = nn.LayerNorm(in_dim) self.fc1 = ColumnParallelLinear( in_dim, in_dim, bias=True, return_bias=False, ) self.act = nn.GELU() self.fc2 = RowParallelLinear( in_dim, out_dim, bias=True, return_bias=False, ) self.norm2 = nn.LayerNorm(out_dim) def forward(self, image_embeds: torch.Tensor) -> torch.Tensor: x = self.norm1(image_embeds) x = self.fc1(x) x = self.act(x) x = self.fc2(x) x = self.norm2(x) return x # ── Cross-Attention ───────────────────────────────────────────────── # T2V and I2V cross-attention variants class WanT2VCrossAttention(nn.Module): """Text-to-video cross-attention. Uses vllm-omni Attention for FlashAttn backend. """ def __init__(self, dim: int, num_heads: int, window_size=(-1, -1), qk_norm: bool = True, eps: float = 1e-6) -> None: super().__init__() if dim % num_heads != 0: raise ValueError(f"dim={dim} must be divisible by num_heads={num_heads}.") self.dim = dim self.num_heads = num_heads self.head_dim = dim // num_heads tp_size = get_tensor_model_parallel_world_size() if num_heads % tp_size != 0: raise ValueError(f"num_heads={num_heads} must be divisible by tp_size={tp_size}.") self.tp_num_heads = num_heads // tp_size self.tp_inner_dim = self.tp_num_heads * self.head_dim self.q = ColumnParallelLinear(dim, dim, bias=True, gather_output=False, return_bias=False) self.k = ColumnParallelLinear(dim, dim, bias=True, gather_output=False, return_bias=False) self.v = ColumnParallelLinear(dim, dim, bias=True, gather_output=False, return_bias=False) self.o = RowParallelLinear(dim, dim, bias=True, input_is_parallel=True, return_bias=False) self.norm_q = DistributedRMSNorm(self.tp_inner_dim, eps=eps) if qk_norm else nn.Identity() self.norm_k = DistributedRMSNorm(self.tp_inner_dim, eps=eps) if qk_norm else nn.Identity() self.attn = Attention( self.tp_num_heads, self.head_dim, causal=False, softmax_scale=self.head_dim**-0.5, skip_sequence_parallel=True, ) def forward( self, x: torch.Tensor, context: torch.Tensor, context_lens: torch.Tensor | None = None, crossattn_cache: dict | None = None, ) -> torch.Tensor: del context_lens n, d = self.tp_num_heads, self.head_dim q = self.norm_q(self.q(x)).unflatten(2, (n, d)) if crossattn_cache is not None: if not crossattn_cache["is_init"]: crossattn_cache["is_init"] = True k = self.norm_k(self.k(context)).unflatten(2, (n, d)) v = self.v(context).unflatten(2, (n, d)) crossattn_cache["k"] = k crossattn_cache["v"] = v else: k = crossattn_cache["k"] v = crossattn_cache["v"] else: k = self.norm_k(self.k(context)).unflatten(2, (n, d)) v = self.v(context).unflatten(2, (n, d)) x = self.attn(q, k, v) x = x.flatten(2) x = self.o(x) return x class WanI2VCrossAttention(nn.Module): """Image-to-video cross-attention (splits first 257 image tokens). Uses vllm-omni Attention for FlashAttn backend. """ def __init__(self, dim: int, num_heads: int, window_size=(-1, -1), qk_norm: bool = True, eps: float = 1e-6) -> None: super().__init__() if dim % num_heads != 0: raise ValueError(f"dim={dim} must be divisible by num_heads={num_heads}.") self.dim = dim self.num_heads = num_heads self.head_dim = dim // num_heads tp_size = get_tensor_model_parallel_world_size() if num_heads % tp_size != 0: raise ValueError(f"num_heads={num_heads} must be divisible by tp_size={tp_size}.") self.tp_num_heads = num_heads // tp_size self.tp_inner_dim = self.tp_num_heads * self.head_dim self.q = ColumnParallelLinear(dim, dim, bias=True, gather_output=False, return_bias=False) self.k = ColumnParallelLinear(dim, dim, bias=True, gather_output=False, return_bias=False) self.v = ColumnParallelLinear(dim, dim, bias=True, gather_output=False, return_bias=False) self.o = RowParallelLinear(dim, dim, bias=True, input_is_parallel=True, return_bias=False) self.norm_q = DistributedRMSNorm(self.tp_inner_dim, eps=eps) if qk_norm else nn.Identity() self.norm_k = DistributedRMSNorm(self.tp_inner_dim, eps=eps) if qk_norm else nn.Identity() self.k_img = ColumnParallelLinear(dim, dim, bias=True, gather_output=False, return_bias=False) self.v_img = ColumnParallelLinear(dim, dim, bias=True, gather_output=False, return_bias=False) self.norm_k_img = DistributedRMSNorm(self.tp_inner_dim, eps=eps) if qk_norm else nn.Identity() self.attn = Attention( self.tp_num_heads, self.head_dim, causal=False, softmax_scale=self.head_dim**-0.5, skip_sequence_parallel=True, ) def forward( self, x: torch.Tensor, context: torch.Tensor, context_lens: torch.Tensor | None = None, crossattn_cache: dict | None = None, ) -> torch.Tensor: del context_lens context_img = context[:, :257] context = context[:, 257:] n, d = self.tp_num_heads, self.head_dim q = self.norm_q(self.q(x)).unflatten(2, (n, d)) if crossattn_cache is not None: if not crossattn_cache["is_init"]: crossattn_cache["is_init"] = True k = self.norm_k(self.k(context)).unflatten(2, (n, d)) v = self.v(context).unflatten(2, (n, d)) crossattn_cache["k"] = k crossattn_cache["v"] = v else: k = crossattn_cache["k"] v = crossattn_cache["v"] else: k = self.norm_k(self.k(context)).unflatten(2, (n, d)) v = self.v(context).unflatten(2, (n, d)) x = self.attn(q, k, v) k_img = self.norm_k_img(self.k_img(context_img)).unflatten(2, (n, d)) v_img = self.v_img(context_img).unflatten(2, (n, d)) img_x = self.attn(q, k_img, v_img) x = x.flatten(2) img_x = img_x.flatten(2) x = x + img_x x = self.o(x) return x WAN_CROSSATTENTION_CLASSES = { "t2v_cross_attn": WanT2VCrossAttention, "i2v_cross_attn": WanI2VCrossAttention, } # ── Self-Attention with causal masking + KV cache ─────────────────── class CausalWanSelfAttention(nn.Module): """Causal self-attention with KV cache + action/state tokens.""" def __init__( self, dim: int, num_heads: int, frame_seqlen: int, local_attn_size: int = -1, sink_size: int = 0, num_frame_per_block: int = 1, qk_norm: bool = True, eps: float = 1e-6, num_action_per_block: int = 32, num_state_per_block: int = 1, ) -> None: super().__init__() if dim % num_heads != 0: raise ValueError(f"dim={dim} must be divisible by num_heads={num_heads}.") self.dim = dim self.num_heads = num_heads self.head_dim = dim // num_heads tp_size = get_tensor_model_parallel_world_size() if num_heads % tp_size != 0: raise ValueError(f"num_heads={num_heads} must be divisible by tp_size={tp_size}.") self.tp_num_heads = num_heads // tp_size self.tp_inner_dim = self.tp_num_heads * self.head_dim self.local_attn_size = local_attn_size self.num_frame_per_block = num_frame_per_block self.frame_seqlen = frame_seqlen self.num_action_per_block = num_action_per_block self.num_state_per_block = num_state_per_block self.max_attention_size = 21 * frame_seqlen if local_attn_size == -1 else local_attn_size * frame_seqlen self.q = ColumnParallelLinear(dim, dim, bias=True, gather_output=False, return_bias=False) self.k = ColumnParallelLinear(dim, dim, bias=True, gather_output=False, return_bias=False) self.v = ColumnParallelLinear(dim, dim, bias=True, gather_output=False, return_bias=False) self.o = RowParallelLinear(dim, dim, bias=True, input_is_parallel=True, return_bias=False) self.norm_q = DistributedRMSNorm(self.tp_inner_dim, eps=eps) if qk_norm else nn.Identity() self.norm_k = DistributedRMSNorm(self.tp_inner_dim, eps=eps) if qk_norm else nn.Identity() self.attn = Attention( self.tp_num_heads, self.head_dim, causal=False, softmax_scale=self.head_dim**-0.5, skip_sequence_parallel=True, ) def forward( self, x: torch.Tensor, freqs: torch.Tensor, freqs_action: torch.Tensor, freqs_state: torch.Tensor, action_register_length: int | None, kv_cache: torch.Tensor | None = None, current_start_frame: int = 0, is_tf: bool = True, ) -> tuple[torch.Tensor, torch.Tensor | None]: """Inference-only forward (KV cache path).""" n, d = self.tp_num_heads, self.head_dim q = self.norm_q(self.q(x)).unflatten(2, (n, d)) k = self.norm_k(self.k(x)).unflatten(2, (n, d)) v = self.v(x).unflatten(2, (n, d)) updated_kv_cache: torch.Tensor | None = None if kv_cache is None: raise RuntimeError("Inference only: kv_cache is required.") action_state_index = max(0, (current_start_frame - 1) // self.num_frame_per_block) roped_query = causal_rope_action_apply( q, freqs, freqs_action, freqs_state, action_register_length, self.num_action_per_block, self.num_state_per_block, action_state_index, ).type_as(v) roped_key = causal_rope_action_apply( k, freqs, freqs_action, freqs_state, action_register_length, self.num_action_per_block, self.num_state_per_block, action_state_index, ).type_as(v) roped_action_query = None roped_action_key = None action_v = None if action_register_length is not None: roped_action_query = roped_query[:, -action_register_length:] roped_query = roped_query[:, :-action_register_length] roped_action_key = roped_key[:, -action_register_length:] roped_key = roped_key[:, :-action_register_length] action_v = v[:, -action_register_length:] v = v[:, :-action_register_length] updated_k = kv_cache[0] updated_v = kv_cache[1] new_k = torch.cat([updated_k, roped_key], dim=1) new_v = torch.cat([updated_v, v], dim=1) new_k = new_k[:, -self.max_attention_size :] new_v = new_v[:, -self.max_attention_size :] if action_register_length is not None: q_cat = torch.cat([roped_query, roped_action_query], dim=1) k_cat = torch.cat([new_k, roped_action_key], dim=1) v_cat = torch.cat([new_v, action_v], dim=1) else: q_cat = roped_query k_cat = new_k v_cat = new_v x = self.attn(q_cat, k_cat, v_cat) updated_kv_cache = torch.stack([new_k, new_v], dim=0) x = x.flatten(2) x = self.o(x) return x, updated_kv_cache # ── Attention Block ───────────────────────────────────────────────── class CausalWanAttentionBlock(nn.Module): """Transformer block: self-attn + cross-attn + FFN with 6-param modulation.""" def __init__( self, cross_attn_type: str, dim: int, ffn_dim: int, num_heads: int, frame_seqlen: int, local_attn_size: int = -1, sink_size: int = 0, num_frame_per_block: int = 1, qk_norm: bool = True, cross_attn_norm: bool = False, eps: float = 1e-6, num_action_per_block: int = 32, num_state_per_block: int = 1, ) -> None: super().__init__() self.norm1 = WanLayerNorm(dim, eps) self.self_attn = CausalWanSelfAttention( dim=dim, num_heads=num_heads, frame_seqlen=frame_seqlen, local_attn_size=local_attn_size, sink_size=sink_size, num_frame_per_block=num_frame_per_block, qk_norm=qk_norm, eps=eps, num_action_per_block=num_action_per_block, num_state_per_block=num_state_per_block, ) self.norm3 = WanLayerNorm(dim, eps, elementwise_affine=True) if cross_attn_norm else nn.Identity() self.cross_attn = WAN_CROSSATTENTION_CLASSES[cross_attn_type](dim, num_heads, (-1, -1), qk_norm, eps) self.norm2 = WanLayerNorm(dim, eps) self.ffn = nn.Sequential( ColumnParallelLinear(dim, ffn_dim, bias=True, gather_output=False, return_bias=False), nn.GELU(approximate="tanh"), RowParallelLinear(ffn_dim, dim, bias=True, input_is_parallel=True, return_bias=False), ) self.modulation = nn.Parameter(torch.randn(1, 6, dim) / dim**0.5) def forward( self, x: torch.Tensor, e: torch.Tensor, freqs: torch.Tensor, freqs_action: torch.Tensor, freqs_state: torch.Tensor, context: torch.Tensor, action_register_length: int | None = None, kv_cache: torch.Tensor | None = None, crossattn_cache: dict | None = None, current_start_frame: int = 0, is_tf: bool = True, ) -> tuple[torch.Tensor, torch.Tensor | None]: e = (self.modulation.unsqueeze(1) + e).chunk(6, dim=2) y, updated_kv_cache = self.self_attn( x=(self.norm1(x) * (1 + e[1].squeeze(2)) + e[0].squeeze(2)), freqs=freqs, freqs_action=freqs_action, freqs_state=freqs_state, action_register_length=action_register_length, kv_cache=kv_cache, is_tf=is_tf, current_start_frame=current_start_frame, ) x = x + (y * e[2].squeeze(2)) x = x + self.cross_attn(self.norm3(x), context, crossattn_cache=crossattn_cache) y = self.ffn(self.norm2(x) * (1 + e[4].squeeze(2)) + e[3].squeeze(2)) x = x + (y * e[5].squeeze(2)) return x, updated_kv_cache # ── Output Head ───────────────────────────────────────────────────── class CausalHead(nn.Module): """Output norm + linear with 2-param modulation. Runs once per step (not TP-critical), uses nn.Linear. """ def __init__(self, dim: int, out_dim: int, patch_size: tuple, eps: float = 1e-6) -> None: super().__init__() self.dim = dim self.out_dim = out_dim self.patch_size = patch_size out_channels = math.prod(patch_size) * out_dim self.norm = WanLayerNorm(dim, eps) self.head = nn.Linear(dim, out_channels) self.modulation = nn.Parameter(torch.randn(1, 2, dim) / dim**0.5) def forward(self, x: torch.Tensor, e: torch.Tensor) -> torch.Tensor: """ Args: x: [B, L1, C] e: [B, F, 1, C] (time embedding, unsqueezed) """ e = (self.modulation.unsqueeze(1) + e).chunk(2, dim=2) x = self.head(self.norm(x) * (1 + e[1].squeeze(2)) + e[0].squeeze(2)) return x # ── Main Model ────────────────────────────────────────────────────── class CausalWanModel(nn.Module): """Causal video diffusion transformer for DreamZero. Architecture (14B): 40 layers, dim=5120, heads=40, ffn=13824 """ def __init__( self, model_type: str = "t2v", patch_size: tuple[int, int, int] = (1, 2, 2), frame_seqlen: int = 220, text_len: int = 512, in_dim: int = 16, dim: int = 2048, ffn_dim: int = 8192, freq_dim: int = 256, text_dim: int = 4096, out_dim: int = 16, num_heads: int = 16, num_layers: int = 32, max_chunk_size: int = -1, sink_size: int = 0, qk_norm: bool = True, cross_attn_norm: bool = True, eps: float = 1e-6, num_frame_per_block: int = 1, action_dim: int = 32, num_registers: int = 8, max_state_dim: int = 64, max_num_embodiments: int = 32, hidden_size: int = 1024, diffusion_model_pretrained_path: str | None = None, num_action_per_block: int = 32, num_state_per_block: int = 1, ) -> None: super().__init__() if model_type not in ["t2v", "i2v", "ti2v"]: raise ValueError(f"Unsupported model_type={model_type!r}; expected one of ['t2v', 'i2v', 'ti2v'].") self.model_type = model_type self.patch_size = patch_size self.frame_seqlen = frame_seqlen self.text_len = text_len self.dim = dim self.freq_dim = freq_dim self.out_dim = out_dim self.num_heads = num_heads self.num_layers = num_layers self.local_attn_size = max_chunk_size * num_frame_per_block + 1 if max_chunk_size != -1 else -1 self.num_frame_per_block = num_frame_per_block self.action_dim = action_dim self.num_action_per_block = num_action_per_block self.num_state_per_block = num_state_per_block max_num_embodiments_local = 1 self.state_encoder = CategorySpecificMLP( num_categories=max_num_embodiments_local, input_dim=max_state_dim, hidden_dim=hidden_size, output_dim=dim, ) self.action_encoder = MultiEmbodimentActionEncoder( action_dim=action_dim, hidden_size=dim, num_embodiments=max_num_embodiments_local, ) self.action_decoder = CategorySpecificMLP( num_categories=max_num_embodiments_local, input_dim=dim, hidden_dim=hidden_size, output_dim=action_dim, ) # Disable the Conv3d GEMM rewrite for patch embedding. self.patch_embedding = Conv3dLayer( in_dim, dim, kernel_size=patch_size, stride=patch_size, ) self.patch_embedding.enable_linear = False self.text_embedding = nn.Sequential( nn.Linear(text_dim, dim), nn.GELU(approximate="tanh"), nn.Linear(dim, dim), ) self.time_embedding = nn.Sequential( nn.Linear(freq_dim, dim), nn.SiLU(), nn.Linear(dim, dim), ) self.time_projection = nn.Sequential( nn.SiLU(), nn.Linear(dim, dim * 6), ) cross_attn_type = "t2v_cross_attn" if model_type == "t2v" else "i2v_cross_attn" self.blocks = nn.ModuleList( [ CausalWanAttentionBlock( cross_attn_type, dim, ffn_dim, num_heads, frame_seqlen, self.local_attn_size, sink_size, num_frame_per_block, qk_norm, cross_attn_norm, eps, num_action_per_block, num_state_per_block, ) for _ in range(num_layers) ] ) self.head = CausalHead(dim, out_dim, patch_size, eps) if dim % num_heads != 0: raise ValueError(f"dim={dim} must be divisible by num_heads={num_heads}.") if (dim // num_heads) % 2 != 0: raise ValueError(f"dim // num_heads must be even, got {dim // num_heads}.") d = dim // num_heads self.freqs_action = rope_params(1024 * 10, d) self.freqs_state = rope_params(1024, d) self.freqs = [ rope_params(1024, d - 4 * (d // 6)), rope_params(1024, 2 * (d // 6)), rope_params(1024, 2 * (d // 6)), ] if model_type == "i2v": self.img_emb = MLPProj(1280, dim) self.init_weights() def init_weights(self) -> None: """Initialize parameters.""" def _init_linear_like(module: nn.Module) -> None: if isinstance(module, nn.Linear): nn.init.xavier_uniform_(module.weight) if module.bias is not None: nn.init.zeros_(module.bias) return if isinstance(module, (ColumnParallelLinear, RowParallelLinear)): fan_in = module.input_size fan_out = module.output_size bound = math.sqrt(6.0 / float(fan_in + fan_out)) nn.init.uniform_(module.weight, -bound, bound) if module.bias is not None: nn.init.zeros_(module.bias) for module in self.modules(): _init_linear_like(module) nn.init.xavier_uniform_(self.patch_embedding.weight.flatten(1)) if self.patch_embedding.bias is not None: fan_in = self.patch_embedding.in_channels * math.prod(self.patch_embedding.kernel_size) bound = 1 / math.sqrt(fan_in) nn.init.uniform_(self.patch_embedding.bias, -bound, bound) for module in self.text_embedding.modules(): if isinstance(module, nn.Linear): nn.init.normal_(module.weight, std=0.02) for module in self.time_embedding.modules(): if isinstance(module, nn.Linear): nn.init.normal_(module.weight, std=0.02) nn.init.zeros_(self.head.head.weight) def _create_freqs(self, grid_size: torch.Tensor, start_frame: int) -> torch.Tensor: """Create 3D RoPE frequency tensor.""" device = self.patch_embedding.weight.device if any(freq.device != device for freq in self.freqs): self.freqs = [freq.to(device) for freq in self.freqs] if self.freqs_action.device != device: self.freqs_action = self.freqs_action.to(device) if self.freqs_state.device != device: self.freqs_state = self.freqs_state.to(device) f, h, w = grid_size.tolist() freqs = torch.cat( [ self.freqs[0][start_frame : start_frame + f].view(f, 1, 1, -1).expand(f, h, w, -1), self.freqs[1][:h].view(1, h, 1, -1).expand(f, h, w, -1), self.freqs[2][:w].view(1, 1, w, -1).expand(f, h, w, -1), ], dim=-1, ).reshape(f * h * w, 1, -1) return freqs def unpatchify(self, x: torch.Tensor, grid_size: torch.Tensor) -> torch.Tensor: """Reconstruct video from patch embeddings.""" B = x.shape[0] c = self.out_dim grid_size = grid_size.tolist() expected_seq_len = math.prod(grid_size) if x.shape[1] != expected_seq_len: raise ValueError(f"x sequence length must equal product(grid_size)={expected_seq_len}, got {x.shape[1]}.") x = x.view(B, *grid_size, *self.patch_size, c) x = torch.einsum("bfhwpqrc->bcfphqwr", x) x = x.reshape(B, c, *[i * j for i, j in zip(grid_size, self.patch_size)]) return x def _forward_blocks( self, x: torch.Tensor, seq_len: int, freqs: torch.Tensor, timestep: torch.Tensor, context: torch.Tensor, clip_feature: torch.Tensor | None, embodiment_id: torch.Tensor | None, action: torch.Tensor | None, timestep_action: torch.Tensor | None, state: torch.Tensor | None, kv_cache: list[torch.Tensor], current_start_frame: int, ) -> tuple[torch.Tensor, torch.Tensor | None, list[torch.Tensor]]: x = x.flatten(start_dim=2).transpose(1, 2) B = x.shape[0] F_t = timestep.shape[1] if action is not None: # Current DreamZero checkpoints have one local action/state adapter. # Global embodiment IDs are used by transforms and normalization. adapter_category_id = torch.zeros(B, dtype=torch.long, device=x.device) action_features = self.action_encoder(action, timestep_action, adapter_category_id) state_features = self.state_encoder(state, adapter_category_id) action_register = torch.cat([action_features, state_features], dim=1) action_length = action_features.shape[1] action_register_length = action_register.shape[1] x = torch.cat([x, action_register], dim=1) else: action_length = 0 action_register_length = None timestep = timestep.unsqueeze(-1).expand(B, F_t, seq_len // F_t).reshape(B, -1) if action is not None: if timestep_action is None or state is None: raise RuntimeError("timestep_action and state are required when action is provided.") state_features_t = self.state_encoder(state, adapter_category_id) stride = timestep_action.shape[1] // state_features_t.shape[1] timestep_state = timestep_action[:, ::stride] timestep = torch.cat([timestep, timestep_action, timestep_state], dim=1) e = self.time_embedding(sinusoidal_embedding_1d(self.freq_dim, timestep.flatten()).type_as(x)) e = e.unflatten(dim=0, sizes=(B, -1)) e0 = self.time_projection(e) e0 = e0.unflatten(dim=2, sizes=(6, self.dim)) context = self.text_embedding(context) if clip_feature is not None: clip_embedding = self.img_emb(clip_feature) context = torch.cat([clip_embedding, context], dim=1) updated_kv_caches: list[torch.Tensor] = [] for block_index, block in enumerate(self.blocks): x, updated_kv_cache = block( x=x, e=e0, freqs=freqs, freqs_action=self.freqs_action, freqs_state=self.freqs_state, context=context, action_register_length=action_register_length, kv_cache=kv_cache[block_index] if kv_cache else None, current_start_frame=current_start_frame, ) updated_kv_caches.append(updated_kv_cache) if action is not None: action_noise_pred = x[:, seq_len : seq_len + action_length] action_noise_pred = self.action_decoder(action_noise_pred, adapter_category_id) else: action_noise_pred = None x_video = x[:, :seq_len] e_video = e[:, :seq_len] x_video = self.head(x_video, e_video.unsqueeze(2)) return x_video, action_noise_pred, updated_kv_caches def _forward_inference( self, x: torch.Tensor, timestep: torch.Tensor, context: torch.Tensor, seq_len: int, kv_cache: list[torch.Tensor], crossattn_cache: list[torch.Tensor], current_start_frame: int, y: torch.Tensor | None = None, clip_feature: torch.Tensor | None = None, action: torch.Tensor | None = None, timestep_action: torch.Tensor | None = None, state: torch.Tensor | None = None, embodiment_id: torch.Tensor | None = None, ) -> tuple[torch.Tensor, torch.Tensor | None, list[torch.Tensor]]: if self.model_type == "i2v": if clip_feature is None or y is None: raise RuntimeError("clip_feature and y are required for i2v inference.") if context.shape[1] != self.text_len: raise ValueError(f"context length must be {self.text_len}, got {context.shape[1]}.") if y is not None: x = torch.cat([x, y.to(dtype=x.dtype)], dim=1) x = self.patch_embedding(x) grid_size = torch.tensor(x.shape[2:], dtype=torch.long) freqs = self._create_freqs(grid_size, current_start_frame) x_video, action_noise_pred, updated_kv_caches = self._forward_blocks( x=x, seq_len=seq_len, freqs=freqs, timestep=timestep, context=context, clip_feature=clip_feature, embodiment_id=embodiment_id, action=action, timestep_action=timestep_action, state=state, kv_cache=kv_cache, current_start_frame=current_start_frame, ) x_video = x_video.clone() if action_noise_pred is not None: action_noise_pred = action_noise_pred.clone() video_noise_pred = self.unpatchify(x_video, grid_size) return video_noise_pred, action_noise_pred, updated_kv_caches def forward(self, *args: Any, **kwargs: Any): """Inference only. Requires kv_cache.""" return self._forward_inference(*args, **kwargs)