| |
| |
|
|
| import math |
| import os |
| from typing import Any |
| import torch |
| import torch.nn as nn |
| from diffusers.configuration_utils import ConfigMixin, register_to_config |
| from diffusers.models.modeling_utils import ModelMixin |
| from wan.modules.model import SimpleAdapter, MLPProj, WanI2VCrossAttention |
|
|
| from torch.nn.attention.flex_attention import ( |
| flex_attention, |
| create_block_mask, |
| BlockMask, |
| ) |
|
|
| from wan.modules.attention import attention |
| from wan.modules.model import ( |
| WanRMSNorm, |
| rope_apply, |
| WanLayerNorm, |
| rope_params, |
| sinusoidal_embedding_1d, |
| WanSelfAttention, |
| ) |
|
|
| from wan.modules.attention import flash_attention |
|
|
|
|
| |
|
|
| def _dbg_tensor(name, x): |
| if torch.is_tensor(x): |
| return f"{name}: shape={tuple(x.shape)}, dtype={x.dtype}, device={x.device}" |
| return f"{name}: {type(x)}={x}" |
|
|
|
|
| def _dbg_print(tag, **kwargs): |
| print(f"\n[DEBUG][{tag}]") |
| for k, v in kwargs.items(): |
| try: |
| print(" ", _dbg_tensor(k, v)) |
| except Exception as e: |
| print(f" {k}: <print failed: {e}>") |
|
|
|
|
| def _dbg_block_mask(mask): |
| |
| try: |
| return repr(mask) |
| except Exception as e: |
| return f"<BlockMask repr failed: {e}>" |
|
|
|
|
| def _is_checkpoint_stop_signal(err: BaseException) -> bool: |
| """gradient checkpoint 重算时使用的内部控制流,不是真实错误;勿打印 DEBUG failed。""" |
| return type(err).__name__ == "_StopRecomputationError" |
|
|
|
|
| |
|
|
| @torch.amp.autocast('cuda', enabled=False) |
| def causal_rope_apply(x, grid_sizes, freqs, start_frame=0): |
| """ |
| 与 2.1 causal 版本一致:在时间维上加入起始帧偏移,用于推理时逐帧累积。 |
| """ |
| n, c = x.size(2), x.size(3) // 2 |
| freqs = freqs.split([c - 2 * (c // 3), c // 3, c // 3], dim=1) |
|
|
| output = [] |
| for i, (f, h, w) in enumerate(grid_sizes.tolist()): |
| seq_len = f * h * w |
|
|
| try: |
| x_i = torch.view_as_complex(x[i, :seq_len].to(torch.float64).reshape( |
| seq_len, n, -1, 2)) |
| freqs_i = torch.cat([ |
| freqs[0][start_frame:start_frame + f].view(f, 1, 1, -1).expand(f, h, w, -1), |
| freqs[1][:h].view(1, h, 1, -1).expand(f, h, w, -1), |
| freqs[2][:w].view(1, 1, w, -1).expand(f, h, w, -1) |
| ], dim=-1).reshape(seq_len, 1, -1) |
|
|
| x_i = torch.view_as_real(x_i * freqs_i).flatten(2) |
| x_i = torch.cat([x_i, x[i, seq_len:]]) |
| output.append(x_i) |
| except Exception as e: |
| if _is_checkpoint_stop_signal(e): |
| raise |
| _dbg_print( |
| "causal_rope_apply.failed", |
| error=repr(e), |
| x=x, |
| grid_sizes=grid_sizes, |
| freqs=freqs, |
| start_frame=start_frame, |
| batch_index=i, |
| f=f, |
| h=h, |
| w=w, |
| seq_len=seq_len, |
| n=n, |
| c=c, |
| ) |
| raise |
| return torch.stack(output).float() |
|
|
|
|
| |
| |
| |
| |
| _REL_FREQS_I_CACHE: dict = {} |
|
|
|
|
| def _get_relative_freqs_i(freqs, f, h, w, t_index, device): |
| c = int(freqs.size(1)) |
| cache_key = (int(f), int(h), int(w), tuple(t_index.tolist()), c, str(device)) |
| cached = _REL_FREQS_I_CACHE.get(cache_key) |
| if cached is not None: |
| return cached |
|
|
| freqs_split = freqs.split([c - 2 * (c // 3), c // 3, c // 3], dim=1) |
| freqs_i = torch.cat([ |
| freqs_split[0][t_index].view(f, 1, 1, -1).expand(f, h, w, -1), |
| freqs_split[1][:h].view(1, h, 1, -1).expand(f, h, w, -1), |
| freqs_split[2][:w].view(1, 1, w, -1).expand(f, h, w, -1), |
| ], dim=-1).reshape(f * h * w, 1, -1).to(torch.complex64) |
| _REL_FREQS_I_CACHE[cache_key] = freqs_i |
| return freqs_i |
|
|
|
|
| @torch.amp.autocast('cuda', enabled=False) |
| def relative_rope_apply(x, grid_sizes, freqs, frame_indices=None): |
| """ |
| Apply RoPE with frame ids local to the currently visible attention window. |
| |
| KV-cache inference can evict old frames. When relative RoPE is enabled we |
| keep raw keys in cache and re-apply RoPE to the visible window so the query |
| and keys share a stable local coordinate system instead of growing absolute |
| frame ids forever. |
| """ |
| n = x.size(2) |
|
|
| output = [] |
| for i, (f, h, w) in enumerate(grid_sizes.tolist()): |
| seq_len = f * h * w |
| |
| |
| x_i = torch.view_as_complex( |
| x[i, :seq_len].to(torch.float32).reshape(seq_len, n, -1, 2) |
| ) |
| if frame_indices is None: |
| t_index = torch.arange(f, device=x.device, dtype=torch.long) |
| else: |
| t_index = frame_indices[:f].to(device=x.device, dtype=torch.long) |
| |
| |
| t_index = torch.clamp(t_index, min=0, max=20) |
|
|
| freqs_i = _get_relative_freqs_i(freqs, f, h, w, t_index, x.device) |
|
|
| x_i = torch.view_as_real(x_i * freqs_i).flatten(2) |
| x_i = torch.cat([x_i, x[i, seq_len:]]) |
| output.append(x_i) |
| return torch.stack(output).float() |
|
|
|
|
| def freqs_at(indices, dim, theta=10000, device='cpu'): |
| assert dim % 2 == 0 |
| t = torch.tensor(indices, dtype=torch.float64, device=device) |
| freqs = torch.outer( |
| t, |
| 1.0 / torch.pow(theta, torch.arange(0, dim, 2, device=device, dtype=torch.float64).div(dim)) |
| ) |
| return torch.polar(torch.ones_like(freqs), freqs) |
|
|
|
|
| def rope_apply_with_refimg(x, freqs, num_heads): |
| if x.dim() == 3: |
| b, s, _ = x.shape |
| x = x.view(b, s, num_heads, -1) |
| |
| |
| x_out = torch.view_as_complex(x.to(torch.float32).reshape( |
| x.shape[0], x.shape[1], x.shape[2], -1, 2 |
| )) |
| freqs = freqs.to(device=x.device) |
| if freqs.dtype != torch.complex64: |
| freqs = freqs.to(torch.complex64) |
| x_out = torch.view_as_real(x_out * freqs).flatten(3) |
| return x_out.to(x.dtype) |
|
|
|
|
| |
| |
| |
| _REF_FREQS_CACHE: dict = {} |
|
|
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| _REL_ROPE_CACHE_ENABLED = os.environ.get("REL_ROPE_CACHE", "1") != "0" |
| |
| |
| _REL_ROPE_REBASE_MAX_POS = int(os.environ.get("REL_ROPE_REBASE_MAX_POS", "256")) |
| _REL_ROPE_DEBUG = os.environ.get("REL_ROPE_DEBUG", "0").lower() in {"1", "true", "yes", "on"} |
| _REL_ROPE_DEBUG_LIMIT = int(os.environ.get("REL_ROPE_DEBUG_LIMIT", "50")) |
| _REL_ROPE_DEBUG_COUNT = 0 |
| _REL_ROPE_DEBUG_ONCE_KEYS = set() |
|
|
|
|
| def _rel_rope_debug_print(tag, once_key=None, **kwargs): |
| global _REL_ROPE_DEBUG_COUNT |
| if not _REL_ROPE_DEBUG or _REL_ROPE_DEBUG_COUNT >= _REL_ROPE_DEBUG_LIMIT: |
| return |
| if once_key is not None: |
| if once_key in _REL_ROPE_DEBUG_ONCE_KEYS: |
| return |
| _REL_ROPE_DEBUG_ONCE_KEYS.add(once_key) |
| _REL_ROPE_DEBUG_COUNT += 1 |
| parts = [] |
| for key, value in kwargs.items(): |
| if torch.is_tensor(value): |
| if value.numel() == 1: |
| value = value.item() |
| else: |
| value = tuple(value.shape) |
| parts.append(f"{key}={value}") |
| print(f"[REL_ROPE_DEBUG][{tag}] " + " ".join(parts), flush=True) |
|
|
|
|
| def _build_ref_freqs(freqs, num_slots, tokens_per_slot, ref_grid, device): |
| patch_t, patch_h, patch_w = [int(v) for v in ref_grid] |
| freq_dim = int(freqs.shape[1]) |
| cache_key = ( |
| int(num_slots), int(tokens_per_slot), patch_t, patch_h, patch_w, |
| freq_dim, str(device), |
| ) |
| cached = _REF_FREQS_CACHE.get(cache_key) |
| if cached is not None: |
| return cached |
|
|
| f_band = freq_dim - 2 * (freq_dim // 3) |
| h_band = freq_dim // 3 |
| w_band = freq_dim // 3 |
| temporal_step = max(int(tokens_per_slot), 256) |
| neg_temporal = [-(int(num_slots) - i) * temporal_step for i in range(int(num_slots))] |
| t_freqs = freqs_at(neg_temporal, 2 * f_band, device=device) |
| freqs_split = freqs.split([f_band, h_band, w_band], dim=1) |
| h_freqs = freqs_split[1][:patch_h].to(device) |
| w_freqs = freqs_split[2][:patch_w].to(device) |
| ref_freqs = torch.cat([ |
| t_freqs[:, None, None, None, :].expand(num_slots, patch_t, patch_h, patch_w, f_band), |
| h_freqs[None, None, :, None, :].expand(num_slots, patch_t, patch_h, patch_w, h_band), |
| w_freqs[None, None, None, :, :].expand(num_slots, patch_t, patch_h, patch_w, w_band), |
| ], dim=-1).reshape(int(num_slots) * int(tokens_per_slot), 1, -1).to(torch.complex64) |
| _REF_FREQS_CACHE[cache_key] = ref_freqs |
| return ref_freqs |
|
|
|
|
| |
|
|
| |
| |
| flex_attention = torch.compile( |
| flex_attention, dynamic=False, mode="max-autotune-no-cudagraphs" |
| ) |
|
|
| |
| |
| |
| |
| |
| |
|
|
|
|
| class CausalWanSelfAttention(nn.Module): |
|
|
| def __init__(self, |
| dim, |
| num_heads, |
| local_attn_size=-1, |
| sink_size=0, |
| qk_norm=True, |
| eps=1e-6, |
| use_relative_rope=False): |
| assert dim % num_heads == 0 |
| super().__init__() |
| self.dim = dim |
| self.num_heads = num_heads |
| self.head_dim = dim // num_heads |
| self.local_attn_size = local_attn_size |
| self.sink_size = sink_size |
| self.qk_norm = qk_norm |
| self.eps = eps |
| self.use_relative_rope = bool(use_relative_rope) |
| |
| self.max_attention_size = 880 * 21 if local_attn_size == -1 else local_attn_size * 880 |
| |
| print( |
| f"CausalWanSelfAttention: max_attention_size={self.max_attention_size}, local_attn_size={self.local_attn_size}, sink_size={self.sink_size}") |
| self.q = nn.Linear(dim, dim) |
| self.k = nn.Linear(dim, dim) |
| self.v = nn.Linear(dim, dim) |
| self.o = nn.Linear(dim, dim) |
| self.norm_q = WanRMSNorm(dim, eps=eps) if qk_norm else nn.Identity() |
| self.norm_k = WanRMSNorm(dim, eps=eps) if qk_norm else nn.Identity() |
|
|
| def _run_flex_attention( |
| self, |
| *, |
| query, |
| key, |
| value, |
| block_mask, |
| padded_length=0, |
| tag="self_attn.flex_attention.failed", |
| **debug_ctx, |
| ): |
| """ |
| flex_attention 的薄封装:正常时不打印;只在 kernel/shape/mask 崩时打印关键上下文。 |
| """ |
| try: |
| out = flex_attention( |
| query=query.transpose(2, 1), |
| key=key.transpose(2, 1), |
| value=value.transpose(2, 1), |
| block_mask=block_mask, |
| ) |
| if padded_length > 0: |
| out = out[:, :, :-padded_length] |
| return out.transpose(2, 1) |
| except Exception as e: |
| if _is_checkpoint_stop_signal(e): |
| raise |
| _dbg_print( |
| tag, |
| error=repr(e), |
| query=query, |
| key=key, |
| value=value, |
| query_t=query.transpose(2, 1), |
| key_t=key.transpose(2, 1), |
| value_t=value.transpose(2, 1), |
| block_mask=_dbg_block_mask(block_mask), |
| padded_length=padded_length, |
| **debug_ctx, |
| ) |
| raise |
|
|
| def forward( |
| self, |
| x, |
| seq_lens, |
| grid_sizes, |
| freqs, |
| block_mask: BlockMask | None = None, |
| kv_cache: dict | None = None, |
| current_start: int = 0, |
| cache_start: int | None = None, |
| ): |
| """ |
| 训练:kv_cache is None,使用 flex_attention + block_mask |
| 推理:kv_cache not None,使用显式 KV cache + attention() |
| """ |
| b, s, n, d = *x.shape[:2], self.num_heads, self.head_dim |
|
|
| if cache_start is None: |
| cache_start = current_start |
|
|
| def qkv_fn(x_): |
| q = self.norm_q(self.q(x_)).view(b, s, n, d) |
| k = self.norm_k(self.k(x_)).view(b, s, n, d) |
| v = self.v(x_).view(b, s, n, d) |
| return q, k, v |
|
|
| try: |
| q, k, v = qkv_fn(x) |
| except Exception as e: |
| if _is_checkpoint_stop_signal(e): |
| raise |
| _dbg_print( |
| "self_attn.qkv.failed", |
| error=repr(e), |
| x=x, |
| b=b, |
| s=s, |
| n=n, |
| d=d, |
| seq_lens=seq_lens, |
| grid_sizes=grid_sizes, |
| ) |
| raise |
|
|
| if kv_cache is None: |
| frame_seqlen = int(math.prod(grid_sizes[0][1:]).item()) |
| current_start_frame = current_start // frame_seqlen if frame_seqlen > 0 else 0 |
| num_ref = int(getattr(self, "_num_ref_tokens", 0) or 0) |
| try: |
| is_tf = bool(getattr(self, "_is_teacher_forcing", False)) or ( |
| num_ref == 0 and s == seq_lens[0].item() * 2 |
| ) or ( |
| num_ref > 0 and s == num_ref + seq_lens[0].item() * 2 |
| ) |
| except Exception: |
| is_tf = False |
|
|
| if num_ref > 0: |
| ref_info = { |
| "num_slots": int(getattr(self, "_ref_num_slots", 0) or 0), |
| "tokens_per_slot": int(getattr(self, "_ref_tokens_per_frame", 0) or 0), |
| "grid": getattr(self, "_ref_grid_sizes", None), |
| } |
| if ref_info["num_slots"] <= 0 or ref_info["tokens_per_slot"] <= 0 or ref_info["grid"] is None: |
| raise RuntimeError("Ref tokens are present but ref RoPE metadata is incomplete.") |
| ref_freqs = _build_ref_freqs( |
| freqs=freqs, |
| num_slots=ref_info["num_slots"], |
| tokens_per_slot=ref_info["tokens_per_slot"], |
| ref_grid=ref_info["grid"], |
| device=q.device, |
| ) |
|
|
| if is_tf: |
| branch_len = (s - num_ref) // 2 |
| roped_query = torch.cat([ |
| rope_apply_with_refimg(q[:, :num_ref], ref_freqs, self.num_heads), |
| rope_apply(q[:, num_ref:num_ref + branch_len], grid_sizes, freqs), |
| rope_apply(q[:, num_ref + branch_len:], grid_sizes, freqs), |
| ], dim=1).type_as(v) |
| roped_key = torch.cat([ |
| rope_apply_with_refimg(k[:, :num_ref], ref_freqs, self.num_heads), |
| rope_apply(k[:, num_ref:num_ref + branch_len], grid_sizes, freqs), |
| rope_apply(k[:, num_ref + branch_len:], grid_sizes, freqs), |
| ], dim=1).type_as(v) |
| else: |
| roped_query = torch.cat([ |
| rope_apply_with_refimg(q[:, :num_ref], ref_freqs, self.num_heads), |
| causal_rope_apply( |
| q[:, num_ref:], |
| grid_sizes, |
| freqs, |
| start_frame=current_start_frame, |
| ), |
| ], dim=1).type_as(v) |
| roped_key = torch.cat([ |
| rope_apply_with_refimg(k[:, :num_ref], ref_freqs, self.num_heads), |
| causal_rope_apply( |
| k[:, num_ref:], |
| grid_sizes, |
| freqs, |
| start_frame=current_start_frame, |
| ), |
| ], dim=1).type_as(v) |
|
|
| padded_length = math.ceil(q.shape[1] / 128) * 128 - q.shape[1] |
| if padded_length > 0: |
| roped_query = torch.cat( |
| [roped_query, roped_query.new_zeros(q.shape[0], padded_length, q.shape[2], q.shape[3])], |
| dim=1, |
| ) |
| roped_key = torch.cat( |
| [roped_key, roped_key.new_zeros(k.shape[0], padded_length, k.shape[2], k.shape[3])], |
| dim=1, |
| ) |
| v = torch.cat( |
| [v, v.new_zeros(v.shape[0], padded_length, v.shape[2], v.shape[3])], |
| dim=1, |
| ) |
| x = self._run_flex_attention( |
| query=roped_query, |
| key=roped_key, |
| value=v, |
| block_mask=block_mask, |
| padded_length=padded_length, |
| x=x, |
| q=q, |
| k=k, |
| v=v, |
| roped_query=roped_query, |
| roped_key=roped_key, |
| seq_lens=seq_lens, |
| grid_sizes=grid_sizes, |
| is_tf=is_tf, |
| ) |
| elif is_tf: |
| q_chunk = torch.chunk(q, 2, dim=1) |
| k_chunk = torch.chunk(k, 2, dim=1) |
| roped_query = [] |
| roped_key = [] |
| |
| for ii in range(2): |
| try: |
| rq = rope_apply(q_chunk[ii], grid_sizes, freqs).type_as(v) |
| rk = rope_apply(k_chunk[ii], grid_sizes, freqs).type_as(v) |
| except Exception as e: |
| if _is_checkpoint_stop_signal(e): |
| raise |
| _dbg_print( |
| "self_attn.rope_apply.tf.failed", |
| error=repr(e), |
| ii=ii, |
| q=q, |
| k=k, |
| v=v, |
| q_chunk=q_chunk[ii], |
| k_chunk=k_chunk[ii], |
| grid_sizes=grid_sizes, |
| freqs=freqs, |
| seq_lens=seq_lens, |
| ) |
| raise |
| roped_query.append(rq) |
| roped_key.append(rk) |
|
|
| roped_query = torch.cat(roped_query, dim=1) |
| roped_key = torch.cat(roped_key, dim=1) |
|
|
| padded_length = math.ceil(q.shape[1] / 128) * 128 - q.shape[1] |
| if padded_length > 0: |
| padded_roped_query = torch.cat( |
| [roped_query, |
| torch.zeros([q.shape[0], padded_length, q.shape[2], q.shape[3]], |
| device=q.device, dtype=v.dtype)], |
| dim=1 |
| ) |
|
|
| padded_roped_key = torch.cat( |
| [roped_key, |
| torch.zeros([k.shape[0], padded_length, k.shape[2], k.shape[3]], |
| device=k.device, dtype=v.dtype)], |
| dim=1 |
| ) |
|
|
| padded_v = torch.cat( |
| [v, torch.zeros([v.shape[0], padded_length, v.shape[2], v.shape[3]], |
| device=v.device, dtype=v.dtype)], |
| dim=1 |
| ) |
|
|
| x = self._run_flex_attention( |
| query=padded_roped_query, |
| key=padded_roped_key, |
| value=padded_v, |
| block_mask=block_mask, |
| padded_length=padded_length, |
| x=x, |
| q=q, |
| k=k, |
| v=v, |
| roped_query=roped_query, |
| roped_key=roped_key, |
| seq_lens=seq_lens, |
| grid_sizes=grid_sizes, |
| is_tf=is_tf, |
| ) |
| else: |
| x = self._run_flex_attention( |
| query=roped_query, |
| key=roped_key, |
| value=v, |
| block_mask=block_mask, |
| padded_length=0, |
| x=x, |
| q=q, |
| k=k, |
| v=v, |
| roped_query=roped_query, |
| roped_key=roped_key, |
| seq_lens=seq_lens, |
| grid_sizes=grid_sizes, |
| is_tf=is_tf, |
| ) |
|
|
| else: |
| try: |
| roped_query = causal_rope_apply( |
| q, |
| grid_sizes, |
| freqs, |
| start_frame=current_start_frame, |
| ).type_as(v) |
| roped_key = causal_rope_apply( |
| k, |
| grid_sizes, |
| freqs, |
| start_frame=current_start_frame, |
| ).type_as(v) |
| except Exception as e: |
| if _is_checkpoint_stop_signal(e): |
| raise |
| _dbg_print( |
| "self_attn.rope_apply.failed", |
| error=repr(e), |
| x=x, |
| q=q, |
| k=k, |
| v=v, |
| grid_sizes=grid_sizes, |
| freqs=freqs, |
| seq_lens=seq_lens, |
| ) |
| raise |
|
|
| padded_length = math.ceil(q.shape[1] / 128) * 128 - q.shape[1] |
| if padded_length > 0: |
| padded_roped_query = torch.cat( |
| [roped_query, |
| torch.zeros([q.shape[0], padded_length, q.shape[2], q.shape[3]], |
| device=q.device, dtype=v.dtype)], |
| dim=1 |
| ) |
|
|
| padded_roped_key = torch.cat( |
| [roped_key, |
| torch.zeros([k.shape[0], padded_length, k.shape[2], k.shape[3]], |
| device=k.device, dtype=v.dtype)], |
| dim=1 |
| ) |
|
|
| padded_v = torch.cat( |
| [v, torch.zeros([v.shape[0], padded_length, v.shape[2], v.shape[3]], |
| device=v.device, dtype=v.dtype)], |
| dim=1 |
| ) |
|
|
| x = self._run_flex_attention( |
| query=padded_roped_query, |
| key=padded_roped_key, |
| value=padded_v, |
| block_mask=block_mask, |
| padded_length=padded_length, |
| x=x, |
| q=q, |
| k=k, |
| v=v, |
| roped_query=roped_query, |
| roped_key=roped_key, |
| seq_lens=seq_lens, |
| grid_sizes=grid_sizes, |
| is_tf=is_tf, |
| ) |
| else: |
| x = self._run_flex_attention( |
| query=roped_query, |
| key=roped_key, |
| value=v, |
| block_mask=block_mask, |
| padded_length=0, |
| x=x, |
| q=q, |
| k=k, |
| v=v, |
| roped_query=roped_query, |
| roped_key=roped_key, |
| seq_lens=seq_lens, |
| grid_sizes=grid_sizes, |
| is_tf=is_tf, |
| ) |
| else: |
| try: |
| frame_seqlen = int(math.prod(grid_sizes[0][1:]).item()) |
| ref_token_len = int(getattr(self, "_num_ref_tokens", 0) or 0) |
| query_ref_token_len = int(getattr(self, "_query_ref_token_len", 0) or 0) |
| video_token_len = q.shape[1] - query_ref_token_len |
| num_video_frames = video_token_len // frame_seqlen if frame_seqlen > 0 else 0 |
| video_grid_sizes = grid_sizes.clone() |
| video_grid_sizes[:, 0] = num_video_frames |
| ref_info = { |
| "num_slots": int(getattr(self, "_ref_num_slots", 0) or 0), |
| "tokens_per_slot": int(getattr(self, "_ref_tokens_per_frame", 0) or 0), |
| "grid": getattr(self, "_ref_grid_sizes", None), |
| } |
| if "ref_token_len" not in kv_cache: |
| kv_cache["ref_token_len"] = torch.tensor( |
| [0], dtype=torch.long, device=q.device |
| ) |
| kv_cache["ref_token_len"].fill_(ref_token_len) |
| sink_tokens = ref_token_len + self.sink_size * frame_seqlen |
| kv_cache_size = kv_cache["k"].shape[1] |
| cache_current_start = current_start + ref_token_len |
| if query_ref_token_len > 0: |
| cache_current_start = 0 |
| cache_current_end = ref_token_len + current_start + video_token_len |
|
|
| if self.use_relative_rope: |
| fast_rel = _REL_ROPE_CACHE_ENABLED and int(self.sink_size) == 0 |
| if "k_raw" not in kv_cache or kv_cache["k_raw"].shape != kv_cache["k"].shape: |
| kv_cache["k_raw"] = torch.empty_like(kv_cache["k"]) |
| if fast_rel: |
| kv_cache["k_roped"] = torch.empty_like(kv_cache["k"]) |
| kv_cache["rel_rope_base_frame"] = 0 |
| if fast_rel and "k_roped" not in kv_cache: |
| kv_cache["k_roped"] = torch.empty_like(kv_cache["k"]) |
| kv_cache["rel_rope_base_frame"] = 0 |
| |
| |
| if fast_rel and int(kv_cache["global_end_index"].item()) == 0: |
| kv_cache["rel_rope_base_frame"] = 0 |
|
|
| if self.local_attn_size != -1 and (cache_current_end > kv_cache["global_end_index"].item()) and ( |
| video_token_len + kv_cache["local_end_index"].item() > kv_cache_size): |
| num_evicted_tokens = video_token_len + kv_cache["local_end_index"].item() - kv_cache_size |
| num_rolled_tokens = kv_cache["local_end_index"].item() - num_evicted_tokens - sink_tokens |
|
|
| if num_evicted_tokens < 0 or num_rolled_tokens < 0: |
| _dbg_print( |
| "relative_kv_cache.roll.bad_sizes", |
| current_start=current_start, |
| current_end=cache_current_end, |
| frame_seqlen=frame_seqlen, |
| ref_token_len=ref_token_len, |
| query_ref_token_len=query_ref_token_len, |
| sink_tokens=sink_tokens, |
| kv_cache_size=kv_cache_size, |
| video_token_len=video_token_len, |
| num_evicted_tokens=num_evicted_tokens, |
| num_rolled_tokens=num_rolled_tokens, |
| ) |
| raise RuntimeError( |
| f"Invalid relative KV cache roll sizes: " |
| f"evict={num_evicted_tokens}, roll={num_rolled_tokens}" |
| ) |
|
|
| kv_cache["k_raw"][:, sink_tokens:sink_tokens + num_rolled_tokens] = \ |
| kv_cache["k_raw"][:, |
| sink_tokens + num_evicted_tokens:sink_tokens + num_evicted_tokens + num_rolled_tokens].clone() |
| kv_cache["v"][:, sink_tokens:sink_tokens + num_rolled_tokens] = \ |
| kv_cache["v"][:, |
| sink_tokens + num_evicted_tokens:sink_tokens + num_evicted_tokens + num_rolled_tokens].clone() |
| if fast_rel: |
| kv_cache["k_roped"][:, sink_tokens:sink_tokens + num_rolled_tokens] = \ |
| kv_cache["k_roped"][:, |
| sink_tokens + num_evicted_tokens:sink_tokens + num_evicted_tokens + num_rolled_tokens].clone() |
|
|
| local_end_index = kv_cache["local_end_index"].item() + cache_current_end - \ |
| kv_cache["global_end_index"].item() - num_evicted_tokens |
| else: |
| local_end_index = kv_cache["local_end_index"].item() + cache_current_end - kv_cache[ |
| "global_end_index"].item() |
| local_start_index = local_end_index - video_token_len |
|
|
| if local_start_index < sink_tokens or local_end_index > kv_cache["k_raw"].shape[1]: |
| _dbg_print( |
| "relative_kv_cache.index.out_of_range", |
| current_start=current_start, |
| current_end=cache_current_end, |
| frame_seqlen=frame_seqlen, |
| ref_token_len=ref_token_len, |
| query_ref_token_len=query_ref_token_len, |
| sink_tokens=sink_tokens, |
| kv_cache_size=kv_cache_size, |
| video_token_len=video_token_len, |
| local_start_index=local_start_index, |
| local_end_index=local_end_index, |
| kv_cache_k_raw=kv_cache["k_raw"], |
| kv_cache_v=kv_cache["v"], |
| global_end_index=kv_cache["global_end_index"], |
| local_end_index_tensor=kv_cache["local_end_index"], |
| ) |
| raise RuntimeError( |
| f"Relative KV cache write out of range: " |
| f"[{local_start_index}:{local_end_index}] vs cache_len={kv_cache['k_raw'].shape[1]}" |
| ) |
|
|
| if query_ref_token_len > 0: |
| kv_cache["k_raw"][:, :ref_token_len] = k[:, :query_ref_token_len].detach() |
| kv_cache["v"][:, :ref_token_len] = v[:, :query_ref_token_len] |
| kv_cache["k_raw"][:, local_start_index:local_end_index] = k[:, query_ref_token_len:].detach() |
| kv_cache["v"][:, local_start_index:local_end_index] = v[:, query_ref_token_len:] |
|
|
| max_attention_tokens = ( |
| local_end_index - sink_tokens |
| if self.local_attn_size == -1 |
| else int(self.local_attn_size) * frame_seqlen |
| ) |
| recent_start = max(sink_tokens, local_end_index - max_attention_tokens) |
| visible_recent_tokens = local_end_index - recent_start |
| misalign = visible_recent_tokens % frame_seqlen |
| if misalign: |
| recent_start += misalign |
| visible_recent_tokens = local_end_index - recent_start |
|
|
| protected_video_tokens = max(0, sink_tokens - ref_token_len) |
|
|
| if not fast_rel: |
| video_key_parts = [] |
| video_value_parts = [] |
| if protected_video_tokens > 0: |
| video_key_parts.append(kv_cache["k_raw"][:, ref_token_len:sink_tokens]) |
| video_value_parts.append(kv_cache["v"][:, ref_token_len:sink_tokens]) |
| if visible_recent_tokens > 0: |
| video_key_parts.append(kv_cache["k_raw"][:, recent_start:local_end_index]) |
| video_value_parts.append(kv_cache["v"][:, recent_start:local_end_index]) |
| visible_video_raw = torch.cat(video_key_parts, dim=1) if video_key_parts else kv_cache["k_raw"][:, :0] |
| visible_video_v = torch.cat(video_value_parts, dim=1) if video_value_parts else kv_cache["v"][:, :0] |
| visible_video_frames = visible_video_raw.shape[1] // frame_seqlen if frame_seqlen > 0 else 0 |
|
|
| attn_k_parts = [] |
| attn_v_parts = [] |
| query_parts = [] |
| if ref_token_len > 0: |
| if ref_info["num_slots"] <= 0 or ref_info["tokens_per_slot"] <= 0 or ref_info["grid"] is None: |
| raise RuntimeError("Ref cache write requested but ref RoPE metadata is incomplete.") |
| ref_freqs = _build_ref_freqs( |
| freqs=freqs, |
| num_slots=ref_info["num_slots"], |
| tokens_per_slot=ref_info["tokens_per_slot"], |
| ref_grid=ref_info["grid"], |
| device=q.device, |
| ) |
| attn_k_parts.append( |
| rope_apply_with_refimg( |
| kv_cache["k_raw"][:, :ref_token_len], |
| ref_freqs, |
| self.num_heads, |
| ).type_as(v) |
| ) |
| attn_v_parts.append(kv_cache["v"][:, :ref_token_len]) |
| if query_ref_token_len > 0: |
| query_parts.append( |
| rope_apply_with_refimg( |
| q[:, :query_ref_token_len], |
| ref_freqs, |
| self.num_heads, |
| ).type_as(v) |
| ) |
|
|
| if visible_video_frames > 0: |
| visible_video_grid_sizes = grid_sizes.clone() |
| visible_video_grid_sizes[:, 0] = visible_video_frames |
| rel_k_frame_indices = torch.arange( |
| visible_video_frames, device=q.device, dtype=torch.long |
| ) |
| attn_k_parts.append( |
| relative_rope_apply( |
| visible_video_raw, |
| visible_video_grid_sizes, |
| freqs, |
| frame_indices=rel_k_frame_indices, |
| ).type_as(v) |
| ) |
| attn_v_parts.append(visible_video_v) |
| if num_video_frames <= visible_video_frames: |
| rel_q_frame_indices = rel_k_frame_indices[-num_video_frames:] |
| else: |
| rel_q_frame_indices = torch.arange( |
| num_video_frames, device=q.device, dtype=torch.long |
| ) |
| _rel_rope_debug_print( |
| "window_local", |
| once_key=("window_local", int(current_start)), |
| current_start=current_start, |
| frame_seqlen=frame_seqlen, |
| abs_frame_start=current_start // frame_seqlen if frame_seqlen > 0 else 0, |
| visible_video_frames=visible_video_frames, |
| num_video_frames=num_video_frames, |
| recent_start=recent_start, |
| local_start_index=local_start_index, |
| local_end_index=local_end_index, |
| rel_k_first=rel_k_frame_indices[0] if rel_k_frame_indices.numel() else -1, |
| rel_k_last=rel_k_frame_indices[-1] if rel_k_frame_indices.numel() else -1, |
| rel_q_first=rel_q_frame_indices[0] if rel_q_frame_indices.numel() else -1, |
| rel_q_last=rel_q_frame_indices[-1] if rel_q_frame_indices.numel() else -1, |
| ref_token_len=ref_token_len, |
| ) |
| query_parts.append( |
| relative_rope_apply( |
| q[:, query_ref_token_len:], |
| video_grid_sizes, |
| freqs, |
| frame_indices=rel_q_frame_indices, |
| ).type_as(v) |
| ) |
|
|
| roped_query = torch.cat(query_parts, dim=1) if len(query_parts) > 1 else query_parts[0] |
| attn_k = torch.cat(attn_k_parts, dim=1) if len(attn_k_parts) > 1 else attn_k_parts[0] |
| attn_v = torch.cat(attn_v_parts, dim=1) if len(attn_v_parts) > 1 else attn_v_parts[0] |
| x = attention(roped_query, attn_k, attn_v) |
| else: |
| |
| |
| |
| |
| |
| |
| visible_video_frames = ( |
| visible_recent_tokens // frame_seqlen if frame_seqlen > 0 else 0 |
| ) |
| abs_frame_start = current_start // frame_seqlen |
| base_frame = int(kv_cache["rel_rope_base_frame"]) |
| new_start_pos = abs_frame_start - base_frame |
|
|
| rope_table = int(freqs.shape[0]) |
| rebase_limit = min( |
| _REL_ROPE_REBASE_MAX_POS, |
| rope_table - int(self.local_attn_size) - num_video_frames, |
| ) |
| need_rebase = visible_video_frames > 0 and ( |
| (new_start_pos + num_video_frames) > rebase_limit |
| or new_start_pos < 0 |
| ) |
| debug_new_start_pos_before_rebase = new_start_pos |
|
|
| if need_rebase: |
| |
| |
| oldest_visible_abs = ( |
| abs_frame_start + num_video_frames - visible_video_frames |
| ) |
| base_frame = oldest_visible_abs |
| kv_cache["rel_rope_base_frame"] = base_frame |
| win_grid = grid_sizes.clone() |
| win_grid[:, 0] = visible_video_frames |
| kv_cache["k_roped"][:, recent_start:local_end_index] = causal_rope_apply( |
| kv_cache["k_raw"][:, recent_start:local_end_index], |
| win_grid, |
| freqs, |
| start_frame=0, |
| ).type_as(v) |
| new_start_pos = abs_frame_start - base_frame |
| else: |
| |
| kv_cache["k_roped"][:, local_start_index:local_end_index] = causal_rope_apply( |
| k[:, query_ref_token_len:], |
| video_grid_sizes, |
| freqs, |
| start_frame=new_start_pos, |
| ).type_as(v) |
|
|
| _rel_rope_debug_print( |
| "fast_cache", |
| once_key=("fast_cache", int(current_start)), |
| current_start=current_start, |
| frame_seqlen=frame_seqlen, |
| abs_frame_start=abs_frame_start, |
| base_frame=base_frame, |
| new_start_pos=new_start_pos, |
| temporal_index_start=new_start_pos, |
| temporal_index_end=new_start_pos + num_video_frames - 1, |
| new_start_pos_before_rebase=debug_new_start_pos_before_rebase, |
| num_video_frames=num_video_frames, |
| visible_video_frames=visible_video_frames, |
| recent_start=recent_start, |
| local_start_index=local_start_index, |
| local_end_index=local_end_index, |
| ref_token_len=ref_token_len, |
| rebase_limit=rebase_limit, |
| need_rebase=need_rebase, |
| rope_table=rope_table, |
| ) |
|
|
| roped_video_query = causal_rope_apply( |
| q[:, query_ref_token_len:], |
| video_grid_sizes, |
| freqs, |
| start_frame=new_start_pos, |
| ).type_as(v) |
|
|
| video_k = kv_cache["k_roped"][:, recent_start:local_end_index] |
| video_v = kv_cache["v"][:, recent_start:local_end_index] |
|
|
| if ref_token_len > 0: |
| if ref_info["num_slots"] <= 0 or ref_info["tokens_per_slot"] <= 0 or ref_info["grid"] is None: |
| raise RuntimeError("Ref cache write requested but ref RoPE metadata is incomplete.") |
| ref_freqs = _build_ref_freqs( |
| freqs=freqs, |
| num_slots=ref_info["num_slots"], |
| tokens_per_slot=ref_info["tokens_per_slot"], |
| ref_grid=ref_info["grid"], |
| device=q.device, |
| ) |
| ref_k = rope_apply_with_refimg( |
| kv_cache["k_raw"][:, :ref_token_len], |
| ref_freqs, |
| self.num_heads, |
| ).type_as(v) |
| attn_k = torch.cat([ref_k, video_k], dim=1) |
| attn_v = torch.cat([kv_cache["v"][:, :ref_token_len], video_v], dim=1) |
| if query_ref_token_len > 0: |
| ref_q = rope_apply_with_refimg( |
| q[:, :query_ref_token_len], |
| ref_freqs, |
| self.num_heads, |
| ).type_as(v) |
| roped_query = torch.cat([ref_q, roped_video_query], dim=1) |
| else: |
| roped_query = roped_video_query |
| else: |
| attn_k = video_k |
| attn_v = video_v |
| roped_query = roped_video_query |
|
|
| x = attention(roped_query, attn_k, attn_v) |
|
|
| kv_cache["global_end_index"].fill_(cache_current_end) |
| kv_cache["local_end_index"].fill_(local_end_index) |
| else: |
| current_start_frame = current_start // frame_seqlen |
|
|
| if query_ref_token_len > 0: |
| if ref_info["num_slots"] <= 0 or ref_info["tokens_per_slot"] <= 0 or ref_info["grid"] is None: |
| raise RuntimeError("Ref cache write requested but ref RoPE metadata is incomplete.") |
| ref_freqs = _build_ref_freqs( |
| freqs=freqs, |
| num_slots=ref_info["num_slots"], |
| tokens_per_slot=ref_info["tokens_per_slot"], |
| ref_grid=ref_info["grid"], |
| device=q.device, |
| ) |
| roped_query = torch.cat([ |
| rope_apply_with_refimg(q[:, :query_ref_token_len], ref_freqs, self.num_heads), |
| causal_rope_apply( |
| q[:, query_ref_token_len:], |
| video_grid_sizes, |
| freqs, |
| start_frame=current_start_frame, |
| ), |
| ], dim=1).type_as(v) |
| roped_key = torch.cat([ |
| rope_apply_with_refimg(k[:, :query_ref_token_len], ref_freqs, self.num_heads), |
| causal_rope_apply( |
| k[:, query_ref_token_len:], |
| video_grid_sizes, |
| freqs, |
| start_frame=current_start_frame, |
| ), |
| ], dim=1).type_as(v) |
| else: |
| roped_query = causal_rope_apply( |
| q, grid_sizes, freqs, start_frame=current_start_frame).type_as(v) |
| roped_key = causal_rope_apply( |
| k, grid_sizes, freqs, start_frame=current_start_frame).type_as(v) |
|
|
| num_new_tokens = roped_query.shape[1] |
|
|
| if self.local_attn_size != -1 and (cache_current_end > kv_cache["global_end_index"].item()) and ( |
| num_new_tokens + kv_cache["local_end_index"].item() > kv_cache_size): |
| num_evicted_tokens = num_new_tokens + kv_cache["local_end_index"].item() - kv_cache_size |
| num_rolled_tokens = kv_cache["local_end_index"].item() - num_evicted_tokens - sink_tokens |
|
|
| if num_evicted_tokens < 0 or num_rolled_tokens < 0: |
| _dbg_print( |
| "kv_cache.roll.bad_sizes", |
| current_start=current_start, |
| current_end=cache_current_end, |
| current_start_frame=current_start_frame, |
| frame_seqlen=frame_seqlen, |
| ref_token_len=ref_token_len, |
| query_ref_token_len=query_ref_token_len, |
| sink_tokens=sink_tokens, |
| kv_cache_size=kv_cache_size, |
| num_new_tokens=num_new_tokens, |
| num_evicted_tokens=num_evicted_tokens, |
| num_rolled_tokens=num_rolled_tokens, |
| kv_cache_k=kv_cache["k"], |
| kv_cache_v=kv_cache["v"], |
| global_end_index=kv_cache["global_end_index"], |
| local_end_index_tensor=kv_cache["local_end_index"], |
| grid_sizes=grid_sizes, |
| ) |
| raise RuntimeError( |
| f"Invalid KV cache roll sizes: evict={num_evicted_tokens}, roll={num_rolled_tokens}" |
| ) |
|
|
| kv_cache["k"][:, sink_tokens:sink_tokens + num_rolled_tokens] = \ |
| kv_cache["k"][:, |
| sink_tokens + num_evicted_tokens:sink_tokens + num_evicted_tokens + num_rolled_tokens].clone() |
| kv_cache["v"][:, sink_tokens:sink_tokens + num_rolled_tokens] = \ |
| kv_cache["v"][:, |
| sink_tokens + num_evicted_tokens:sink_tokens + num_evicted_tokens + num_rolled_tokens].clone() |
|
|
| local_end_index = kv_cache["local_end_index"].item() + cache_current_end - \ |
| kv_cache["global_end_index"].item() - num_evicted_tokens |
| local_start_index = local_end_index - num_new_tokens |
| else: |
| local_end_index = kv_cache["local_end_index"].item() + cache_current_end - kv_cache[ |
| "global_end_index"].item() |
| local_start_index = local_end_index - num_new_tokens |
|
|
| |
| if local_start_index < 0 or local_end_index > kv_cache["k"].shape[1]: |
| _dbg_print( |
| "kv_cache.index.out_of_range", |
| current_start=current_start, |
| current_end=cache_current_end, |
| current_start_frame=current_start_frame, |
| frame_seqlen=frame_seqlen, |
| ref_token_len=ref_token_len, |
| query_ref_token_len=query_ref_token_len, |
| sink_tokens=sink_tokens, |
| kv_cache_size=kv_cache_size, |
| num_new_tokens=num_new_tokens, |
| cache_current_start=cache_current_start, |
| kv_cache_k=kv_cache["k"], |
| kv_cache_v=kv_cache["v"], |
| roped_key=roped_key, |
| value=v, |
| global_end_index=kv_cache["global_end_index"], |
| local_end_index_tensor=kv_cache["local_end_index"], |
| grid_sizes=grid_sizes, |
| ) |
| raise RuntimeError( |
| f"KV cache write out of range: " |
| f"[{local_start_index}:{local_end_index}] vs cache_len={kv_cache['k'].shape[1]}" |
| ) |
|
|
| kv_cache["k"][:, local_start_index:local_end_index] = roped_key.detach() |
| kv_cache["v"][:, local_start_index:local_end_index] = v |
|
|
| attn_start = max(sink_tokens, local_end_index - self.max_attention_size) |
| if sink_tokens > 0 and attn_start > sink_tokens: |
| attn_k = torch.cat([ |
| kv_cache["k"][:, :sink_tokens], |
| kv_cache["k"][:, attn_start:local_end_index], |
| ], dim=1) |
| attn_v = torch.cat([ |
| kv_cache["v"][:, :sink_tokens], |
| kv_cache["v"][:, attn_start:local_end_index], |
| ], dim=1) |
| else: |
| attn_k = kv_cache["k"][:, :local_end_index] |
| attn_v = kv_cache["v"][:, :local_end_index] |
| x = attention(roped_query, attn_k, attn_v) |
| kv_cache["global_end_index"].fill_(cache_current_end) |
| kv_cache["local_end_index"].fill_(local_end_index) |
| except Exception as e: |
| if _is_checkpoint_stop_signal(e): |
| raise |
| _dbg_print( |
| "self_attn.kv_cache_path.failed", |
| error=repr(e), |
| x=x, |
| q=q, |
| k=k, |
| v=v, |
| seq_lens=seq_lens, |
| grid_sizes=grid_sizes, |
| current_start=current_start, |
| cache_start=cache_start, |
| kv_cache_k=kv_cache.get("k", None) if isinstance(kv_cache, dict) else None, |
| kv_cache_v=kv_cache.get("v", None) if isinstance(kv_cache, dict) else None, |
| global_end_index=kv_cache.get("global_end_index", None) if isinstance(kv_cache, dict) else None, |
| local_end_index_tensor=kv_cache.get("local_end_index", None) if isinstance(kv_cache, |
| dict) else None, |
| ) |
| raise |
|
|
| x = x.flatten(2) |
| try: |
| x = self.o(x) |
| except Exception as e: |
| if _is_checkpoint_stop_signal(e): |
| raise |
| _dbg_print( |
| "self_attn.output_proj.failed", |
| error=repr(e), |
| x=x, |
| ) |
| raise |
| return x |
|
|
|
|
| |
| |
| |
|
|
| class CausalWanCrossAttention(WanSelfAttention): |
|
|
| def forward(self, x, context, context_lens, crossattn_cache=None): |
| b, n, d = x.size(0), self.num_heads, self.head_dim |
|
|
| q = self.norm_q(self.q(x)).view(b, -1, 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)).view(b, -1, n, d) |
| v = self.v(context).view(b, -1, 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)).view(b, -1, n, d) |
| v = self.v(context).view(b, -1, n, d) |
|
|
| x = flash_attention(q, k, v, k_lens=context_lens) |
| x = x.flatten(2) |
| x = self.o(x) |
| return x |
|
|
|
|
| class CausalWanI2VCrossAttention(WanI2VCrossAttention): |
|
|
| def forward(self, x, context, context_lens, crossattn_cache=None): |
| context_img = context[:, :257] |
| context = context[:, 257:] |
| b, n, d = x.size(0), self.num_heads, self.head_dim |
|
|
| q = self.norm_q(self.q(x)).view(b, -1, 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)).view(b, -1, n, d) |
| v = self.v(context).view(b, -1, n, d) |
| k_img = self.norm_k_img(self.k_img(context_img)).view(b, -1, n, d) |
| v_img = self.v_img(context_img).view(b, -1, n, d) |
| crossattn_cache["k"] = k |
| crossattn_cache["v"] = v |
| crossattn_cache["k_img"] = k_img |
| crossattn_cache["v_img"] = v_img |
| else: |
| k = crossattn_cache["k"] |
| v = crossattn_cache["v"] |
| k_img = crossattn_cache["k_img"] |
| v_img = crossattn_cache["v_img"] |
| else: |
| k_img = self.norm_k_img(self.k_img(context_img)).view(b, -1, n, d) |
| v_img = self.v_img(context_img).view(b, -1, n, d) |
| k = self.norm_k(self.k(context)).view(b, -1, n, d) |
| v = self.v(context).view(b, -1, n, d) |
|
|
| img_x = flash_attention(q, k_img, v_img, k_lens=None) |
| x = flash_attention(q, k, v, k_lens=context_lens) |
|
|
| 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': CausalWanCrossAttention, |
| 'i2v_cross_attn': CausalWanI2VCrossAttention, |
| } |
|
|
|
|
| class CausalWanAttentionBlock(nn.Module): |
|
|
| def __init__(self, |
| dim, |
| ffn_dim, |
| num_heads, |
| local_attn_size=-1, |
| sink_size=0, |
| qk_norm=True, |
| cross_attn_norm=False, |
| eps=1e-6, |
| cross_attn_type="t2v_cross_attn", |
| use_relative_rope=False): |
| super().__init__() |
| self.dim = dim |
| self.ffn_dim = ffn_dim |
| self.num_heads = num_heads |
| self.local_attn_size = local_attn_size |
| self.qk_norm = qk_norm |
| self.cross_attn_norm = cross_attn_norm |
| self.eps = eps |
|
|
| self.norm1 = WanLayerNorm(dim, eps) |
| self.self_attn = CausalWanSelfAttention( |
| dim, num_heads, local_attn_size, sink_size, qk_norm, eps, |
| use_relative_rope=use_relative_rope, |
| ) |
| 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( |
| nn.Linear(dim, ffn_dim), nn.GELU(approximate='tanh'), |
| nn.Linear(ffn_dim, dim) |
| ) |
|
|
| self.modulation = nn.Parameter(torch.randn(1, 6, dim) / dim ** 0.5) |
|
|
| def forward( |
| self, |
| x, |
| e, |
| seq_lens, |
| grid_sizes, |
| freqs, |
| context, |
| context_lens, |
| block_mask: BlockMask | None = None, |
| kv_cache: dict | None = None, |
| crossattn_cache=None, |
| current_start: int = 0, |
| cache_start: int | None = None, |
| ): |
| token_level_modulation = e.shape[1] == x.shape[1] |
| num_frames = e.shape[1] |
| if (not token_level_modulation) and x.shape[1] % num_frames != 0: |
| _dbg_print( |
| "attention_block.bad_frame_token_split", |
| x=x, |
| e=e, |
| seq_lens=seq_lens, |
| grid_sizes=grid_sizes, |
| current_start=current_start, |
| cache_start=cache_start, |
| ) |
| raise RuntimeError( |
| f"x token length {x.shape[1]} is not divisible by e frames {num_frames}" |
| ) |
| if token_level_modulation: |
| num_frames, frame_seqlen = x.shape[1], 1 |
| else: |
| frame_seqlen = x.shape[1] // num_frames |
|
|
| try: |
| e = (self.modulation.unsqueeze(0) + e).chunk(6, dim=2) |
|
|
| def modulate_norm1(value): |
| normed = self.norm1(value) |
| if token_level_modulation: |
| return normed * (1 + e[1].squeeze(2)) + e[0].squeeze(2) |
| return ( |
| normed.unflatten(dim=1, sizes=(num_frames, frame_seqlen)) * (1 + e[1]) + e[0] |
| ).flatten(1, 2) |
|
|
| def modulate_norm2(value): |
| normed = self.norm2(value) |
| if token_level_modulation: |
| return normed * (1 + e[4].squeeze(2)) + e[3].squeeze(2) |
| return ( |
| normed.unflatten(dim=1, sizes=(num_frames, frame_seqlen)) * (1 + e[4]) + e[3] |
| ).flatten(1, 2) |
|
|
| def apply_gate(value, gate): |
| if token_level_modulation: |
| return value * gate.squeeze(2) |
| return (value.unflatten(dim=1, sizes=(num_frames, frame_seqlen)) * gate).flatten(1, 2) |
|
|
| y = self.self_attn( |
| modulate_norm1(x), |
| seq_lens, |
| grid_sizes, |
| freqs, |
| block_mask=block_mask, |
| kv_cache=kv_cache, |
| current_start=current_start, |
| cache_start=cache_start, |
| ) |
| x = x + apply_gate(y, e[2]) |
|
|
| def cross_attn_ffn(x, context, context_lens, e, crossattn_cache=None): |
| x = x + self.cross_attn(self.norm3(x), context, |
| context_lens, crossattn_cache=crossattn_cache) |
| y = self.ffn(modulate_norm2(x)) |
| x = x + apply_gate(y, e[5]) |
| return x |
|
|
| x = cross_attn_ffn(x, context, context_lens, e, crossattn_cache) |
| return x |
| except Exception as err: |
| if _is_checkpoint_stop_signal(err): |
| raise |
| _dbg_print( |
| "attention_block.forward.failed", |
| error=repr(err), |
| x=x, |
| e0=e[0] if isinstance(e, tuple) else e, |
| seq_lens=seq_lens, |
| grid_sizes=grid_sizes, |
| context=context, |
| context_lens=context_lens, |
| block_mask=_dbg_block_mask(block_mask), |
| kv_cache_is_none=(kv_cache is None), |
| crossattn_cache_is_none=(crossattn_cache is None), |
| current_start=current_start, |
| cache_start=cache_start, |
| num_frames=num_frames, |
| frame_seqlen=frame_seqlen, |
| ) |
| raise |
|
|
|
|
| |
|
|
| class CausalHead(nn.Module): |
|
|
| def __init__(self, dim, out_dim, patch_size, eps=1e-6): |
| super().__init__() |
| self.dim = dim |
| self.out_dim = out_dim |
| self.patch_size = patch_size |
| self.eps = eps |
|
|
| out_dim_ = math.prod(patch_size) * out_dim |
| self.norm = WanLayerNorm(dim, eps) |
| self.head = nn.Linear(dim, out_dim_) |
|
|
| self.modulation = nn.Parameter(torch.randn(1, 2, dim) / dim ** 0.5) |
|
|
| def forward(self, x, e): |
| """ |
| 和 2.2 一样: |
| x: [B, L_token, C] |
| e: [B, F, 1, C] or [B, F, C] before unsqueeze |
| """ |
| num_frames = e.shape[1] |
| if x.shape[1] % num_frames != 0: |
| _dbg_print( |
| "head.bad_frame_token_split", |
| x=x, |
| e=e, |
| num_frames=num_frames, |
| ) |
| raise RuntimeError( |
| f"Head split failed: x_len={x.shape[1]}, e_frames={num_frames}" |
| ) |
| frame_seqlen = x.shape[1] // num_frames |
|
|
| try: |
| e = (self.modulation.unsqueeze(1) + e).chunk(2, dim=2) |
| x = self.head( |
| self.norm(x).unflatten(dim=1, sizes=(num_frames, frame_seqlen)) * (1 + e[1]) + e[0] |
| ) |
| return x |
| except Exception as err: |
| if _is_checkpoint_stop_signal(err): |
| raise |
| _dbg_print( |
| "head.forward.failed", |
| error=repr(err), |
| x=x, |
| e=e[0] if isinstance(e, tuple) else e, |
| num_frames=num_frames, |
| frame_seqlen=frame_seqlen, |
| ) |
| raise |
|
|
|
|
| |
|
|
| class CausalWanModel(ModelMixin, ConfigMixin): |
| """ |
| 基于 Wan 2.2 结构,加入: |
| - causal / blockwise / local attention |
| - flex_attention + BlockMask 训练 |
| - KV cache 推理 |
| - teacher forcing (通过 clean_x / aug_t) |
| """ |
|
|
| ignore_for_config = [ |
| 'patch_size', 'cross_attn_norm', 'qk_norm', 'text_dim', 'window_size' |
| ] |
| _no_split_modules = ['WanAttentionBlock'] |
| _supports_gradient_checkpointing = True |
|
|
| @register_to_config |
| def __init__(self, |
| model_type='t2v', |
| patch_size=(1, 2, 2), |
| text_len=512, |
| in_dim=16, |
| dim=2048, |
| ffn_dim=8192, |
| freq_dim=256, |
| text_dim=4096, |
| out_dim=16, |
| num_heads=16, |
| num_layers=32, |
| window_size=(-1, -1), |
| local_attn_size=-1, |
| num_frame_per_block=3, |
| sink_size=0, |
| qk_norm=True, |
| cross_attn_norm=True, |
| eps=1e-6, |
| act_control_in_dim=32, |
| use_relative_rope=False, |
| downscale_factor_control_adapter=8): |
| super().__init__() |
| print(f"Initializing CausalWanModel with model_type={model_type}, use_relative_rope={use_relative_rope}") |
| assert model_type in ['t2v', 'i2v', 'ti2v', 's2v', 'ci2v'] |
| self.model_type = model_type |
|
|
| self.patch_size = patch_size |
| self.text_len = text_len |
| self.in_dim = in_dim |
| self.dim = dim |
| self.ffn_dim = ffn_dim |
| self.freq_dim = freq_dim |
| self.text_dim = text_dim |
| self.out_dim = out_dim |
| self.num_heads = num_heads |
| self.num_layers = num_layers |
| self.window_size = window_size |
| self.local_attn_size = local_attn_size |
| self.sink_size = sink_size |
| self.qk_norm = qk_norm |
| self.cross_attn_norm = cross_attn_norm |
| self.eps = eps |
| self.use_relative_rope = bool(use_relative_rope) |
|
|
| self.patch_embedding = nn.Conv3d( |
| in_dim, dim, kernel_size=patch_size, stride=patch_size |
| ) |
| 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 = 'i2v_cross_attn' if model_type in ['i2v'] else 't2v_cross_attn' |
|
|
| self.blocks = nn.ModuleList([ |
| CausalWanAttentionBlock( |
| dim, ffn_dim, num_heads, |
| local_attn_size=local_attn_size, |
| sink_size=sink_size, |
| qk_norm=qk_norm, |
| cross_attn_norm=cross_attn_norm, |
| eps=eps, |
| cross_attn_type=cross_attn_type, |
| use_relative_rope=use_relative_rope, |
| ) |
| for _ in range(num_layers) |
| ]) |
|
|
| self.head = CausalHead(dim, out_dim, patch_size, eps) |
| self.act_control_adapter = SimpleAdapter( |
| act_control_in_dim, self.dim, |
| kernel_size=self.patch_size[1:], stride=self.patch_size[1:], |
| downscale_factor=downscale_factor_control_adapter) |
| self.act_control_adapter.requires_grad_(False) |
|
|
| assert (dim % num_heads) == 0 and (dim // num_heads) % 2 == 0 |
| d = dim // num_heads |
| self.freqs = torch.cat([ |
| rope_params(1024, d - 4 * (d // 6)), |
| rope_params(1024, 2 * (d // 6)), |
| rope_params(1024, 2 * (d // 6)) |
| ], dim=1) |
|
|
| self.init_weights() |
| self.gradient_checkpointing = False |
| self.block_mask: BlockMask | None = None |
| self._block_mask_cache_key = None |
| self._block_mask_cache = {} |
| self.num_frame_per_block = num_frame_per_block |
| self.independent_first_frame = False |
|
|
| def _set_gradient_checkpointing(self, module, value: bool = False): |
| self.gradient_checkpointing = value |
|
|
| @staticmethod |
| def _frame_block_token_ranges( |
| device: torch.device | str, |
| num_frames: int, |
| frame_seqlen: int, |
| num_frame_per_block=1, |
| independent_first_frame=False, |
| ): |
| if independent_first_frame and num_frames > 0: |
| starts = [0] |
| ends = [frame_seqlen] |
| for frame_start in range(1, num_frames, num_frame_per_block): |
| frame_end = min(frame_start + num_frame_per_block, num_frames) |
| starts.append(frame_start * frame_seqlen) |
| ends.append(frame_end * frame_seqlen) |
| else: |
| starts = list(range(0, num_frames * frame_seqlen, frame_seqlen * num_frame_per_block)) |
| ends = [ |
| min(start + frame_seqlen * num_frame_per_block, num_frames * frame_seqlen) |
| for start in starts |
| ] |
|
|
| return ( |
| torch.tensor(starts, device=device, dtype=torch.long), |
| torch.tensor(ends, device=device, dtype=torch.long), |
| ) |
|
|
| @staticmethod |
| def _build_block_mask_from_visibility( |
| block_visibility: torch.Tensor, |
| mask_mod, |
| seq_length: int, |
| device: torch.device | str, |
| block_size: int = 128, |
| ) -> BlockMask: |
| """Create a BlockMask from block-level visibility without materializing a dense token mask.""" |
| dense_blocks = block_visibility.unsqueeze(0).unsqueeze(0).to(dtype=torch.int32) |
| kv_num_blocks = dense_blocks.sum(dim=-1).to(torch.int32, memory_format=torch.contiguous_format) |
| kv_indices = torch.argsort(dense_blocks, dim=-1, descending=True, stable=True).to( |
| torch.int32, memory_format=torch.contiguous_format |
| ) |
| return BlockMask.from_kv_blocks( |
| kv_num_blocks.to(device), |
| kv_indices.to(device), |
| full_kv_num_blocks=None, |
| full_kv_indices=None, |
| BLOCK_SIZE=(block_size, block_size), |
| mask_mod=mask_mod, |
| seq_lengths=(seq_length, seq_length), |
| ) |
|
|
| @staticmethod |
| def _blockwise_causal_visibility( |
| total_padded: int, |
| total_length: int, |
| ref_token_len: int, |
| video_length: int, |
| block_starts: torch.Tensor, |
| block_ends: torch.Tensor, |
| frame_seqlen: int, |
| local_attn_size=-1, |
| block_size: int = 128, |
| ) -> torch.Tensor: |
| """Build only [query_block, key_block] visibility, avoiding seq_len^2 dense masks.""" |
| q_blocks = math.ceil(total_padded / block_size) |
| block_visibility = torch.zeros((q_blocks, q_blocks), dtype=torch.bool) |
| ref_token_len = int(ref_token_len) |
| video_offset = ref_token_len |
| video_end = ref_token_len + int(video_length) |
|
|
| def mark_token_interval(row: int, start: int, end: int): |
| start = max(0, min(int(start), total_padded)) |
| end = max(0, min(int(end), total_padded)) |
| if start >= end: |
| return |
| block_start = start // block_size |
| block_end = (end - 1) // block_size + 1 |
| block_visibility[row, block_start:block_end] = True |
|
|
| frame_ranges = [(int(s), int(e)) for s, e in zip(block_starts.tolist(), block_ends.tolist())] |
|
|
| for q_block in range(q_blocks): |
| q_start = q_block * block_size |
| q_end = min((q_block + 1) * block_size, total_padded) |
| block_visibility[q_block, q_block] = True |
|
|
| q_has_ref = ref_token_len > 0 and q_start < ref_token_len and q_end > 0 |
| if q_has_ref: |
| mark_token_interval(q_block, 0, ref_token_len) |
|
|
| q_video_start = max(q_start, video_offset) |
| q_video_end = min(q_end, video_end) |
| if q_video_start >= q_video_end: |
| continue |
|
|
| if ref_token_len > 0: |
| mark_token_interval(q_block, 0, ref_token_len) |
|
|
| q_video_start -= video_offset |
| q_video_end -= video_offset |
| for frame_block_start, frame_block_end in frame_ranges: |
| if max(q_video_start, frame_block_start) >= min(q_video_end, frame_block_end): |
| continue |
| if local_attn_size == -1: |
| visible_start = 0 |
| else: |
| visible_start = max(0, frame_block_end - int(local_attn_size) * int(frame_seqlen)) |
| mark_token_interval(q_block, video_offset + visible_start, video_offset + frame_block_end) |
|
|
| return block_visibility |
|
|
| @staticmethod |
| def _prepare_blockwise_causal_attn_mask( |
| device: torch.device | str, |
| num_frames: int, |
| frame_seqlen: int, |
| num_frame_per_block=1, |
| local_attn_size=-1, |
| independent_first_frame=False, |
| ) -> BlockMask: |
| total_length = num_frames * frame_seqlen |
| padded_length = math.ceil(total_length / 128) * 128 - total_length |
|
|
| ends = torch.zeros( |
| total_length + padded_length, device=device, dtype=torch.long |
| ) |
|
|
| block_starts, block_ends = CausalWanModel._frame_block_token_ranges( |
| device=device, |
| num_frames=num_frames, |
| frame_seqlen=frame_seqlen, |
| num_frame_per_block=num_frame_per_block, |
| independent_first_frame=independent_first_frame, |
| ) |
| for start, end in zip(block_starts, block_ends): |
| ends[start:end] = end |
|
|
| def attention_mask(b, h, q_idx, kv_idx): |
| if local_attn_size == -1: |
| return (kv_idx < ends[q_idx]) | (q_idx == kv_idx) |
| else: |
| return ( |
| (kv_idx < ends[q_idx]) |
| & (kv_idx >= (ends[q_idx] - local_attn_size * frame_seqlen)) |
| ) | (q_idx == kv_idx) |
|
|
| block_visibility = CausalWanModel._blockwise_causal_visibility( |
| total_padded=total_length + padded_length, |
| total_length=total_length, |
| ref_token_len=0, |
| video_length=total_length, |
| block_starts=block_starts, |
| block_ends=block_ends, |
| frame_seqlen=frame_seqlen, |
| local_attn_size=local_attn_size, |
| ) |
| return CausalWanModel._build_block_mask_from_visibility( |
| block_visibility, |
| mask_mod=attention_mask, |
| seq_length=total_length + padded_length, |
| device=device, |
| ) |
|
|
| @staticmethod |
| def _prepare_teacher_forcing_mask( |
| device: torch.device | str, |
| num_frames: int, |
| frame_seqlen: int, |
| num_frame_per_block=1, |
| independent_first_frame=False, |
| ) -> BlockMask: |
| total_length = num_frames * frame_seqlen * 2 |
| padded_length = math.ceil(total_length / 128) * 128 - total_length |
|
|
| clean_ends = num_frames * frame_seqlen |
|
|
| context_ends = torch.zeros( |
| total_length + padded_length, device=device, dtype=torch.long |
| ) |
| noise_context_starts = torch.zeros( |
| total_length + padded_length, device=device, dtype=torch.long |
| ) |
| noise_context_ends = torch.zeros( |
| total_length + padded_length, device=device, dtype=torch.long |
| ) |
| noise_noise_starts = torch.zeros( |
| total_length + padded_length, device=device, dtype=torch.long |
| ) |
| noise_noise_ends = torch.zeros( |
| total_length + padded_length, device=device, dtype=torch.long |
| ) |
|
|
| block_starts, block_ends = CausalWanModel._frame_block_token_ranges( |
| device=device, |
| num_frames=num_frames, |
| frame_seqlen=frame_seqlen, |
| num_frame_per_block=num_frame_per_block, |
| independent_first_frame=independent_first_frame, |
| ) |
|
|
| for start, end in zip(block_starts, block_ends): |
| clean_end = torch.minimum(end, end.new_tensor(clean_ends)) |
| context_ends[start:end] = clean_end |
|
|
| for clean_start, clean_end in zip(block_starts, block_ends): |
| start = clean_ends + clean_start |
| end = clean_ends + clean_end |
| noise_noise_starts[start:end] = start |
| noise_noise_ends[start:end] = end |
| noise_context_ends[start:end] = clean_start |
|
|
| def attention_mask(b, h, q_idx, kv_idx): |
| clean_mask = (q_idx < clean_ends) & (kv_idx < context_ends[q_idx]) |
|
|
| C1 = (kv_idx < noise_noise_ends[q_idx]) & (kv_idx >= noise_noise_starts[q_idx]) |
| C2 = (kv_idx < noise_context_ends[q_idx]) & (kv_idx >= noise_context_starts[q_idx]) |
| noise_mask = (q_idx >= clean_ends) & (C1 | C2) |
|
|
| eye_mask = (q_idx == kv_idx) |
| return eye_mask | clean_mask | noise_mask |
|
|
| block_mask = create_block_mask( |
| attention_mask, |
| B=None, |
| H=None, |
| Q_LEN=total_length + padded_length, |
| KV_LEN=total_length + padded_length, |
| _compile=False, |
| device=device, |
| ) |
| return block_mask |
|
|
| @staticmethod |
| def _prepare_blockwise_causal_attn_mask_with_ref( |
| device: torch.device | str, |
| num_frames: int, |
| frame_seqlen: int, |
| ref_token_len: int, |
| num_frame_per_block=1, |
| local_attn_size=-1, |
| independent_first_frame=False, |
| ) -> BlockMask: |
| video_length = num_frames * frame_seqlen |
| total_length = int(ref_token_len) + video_length |
| padded_length = math.ceil(total_length / 128) * 128 - total_length |
| ends = torch.zeros(video_length + padded_length, device=device, dtype=torch.long) |
| block_starts, block_ends = CausalWanModel._frame_block_token_ranges( |
| device=device, |
| num_frames=num_frames, |
| frame_seqlen=frame_seqlen, |
| num_frame_per_block=num_frame_per_block, |
| independent_first_frame=independent_first_frame, |
| ) |
| for start, end in zip(block_starts, block_ends): |
| ends[start:end] = end |
|
|
| def attention_mask(b, h, q_idx, kv_idx): |
| q_is_ref = q_idx < ref_token_len |
| kv_is_ref = kv_idx < ref_token_len |
| q_video = torch.clamp(q_idx - ref_token_len, min=0, max=max(video_length - 1, 0)) |
| kv_video = torch.clamp(kv_idx - ref_token_len, min=0, max=max(video_length - 1, 0)) |
| if local_attn_size == -1: |
| video_visible = (kv_video < ends[q_video]) | (q_video == kv_video) |
| else: |
| video_visible = ( |
| (kv_video < ends[q_video]) |
| & (kv_video >= (ends[q_video] - local_attn_size * frame_seqlen)) |
| ) | (q_video == kv_video) |
| video_mask = (q_idx >= ref_token_len) & (q_idx < total_length) & ( |
| kv_is_ref | ((kv_idx >= ref_token_len) & (kv_idx < total_length) & video_visible) |
| ) |
| return (q_is_ref & kv_is_ref) | video_mask | (q_idx == kv_idx) |
|
|
| block_visibility = CausalWanModel._blockwise_causal_visibility( |
| total_padded=total_length + padded_length, |
| total_length=total_length, |
| ref_token_len=ref_token_len, |
| video_length=video_length, |
| block_starts=block_starts, |
| block_ends=block_ends, |
| frame_seqlen=frame_seqlen, |
| local_attn_size=local_attn_size, |
| ) |
| return CausalWanModel._build_block_mask_from_visibility( |
| block_visibility, |
| mask_mod=attention_mask, |
| seq_length=total_length + padded_length, |
| device=device, |
| ) |
|
|
| @staticmethod |
| def _prepare_teacher_forcing_mask_with_ref_i2v( |
| device: torch.device | str, |
| num_frames: int, |
| frame_seqlen: int, |
| ref_token_len: int, |
| num_frame_per_block=1, |
| independent_first_frame=False, |
| ) -> BlockMask: |
| branch_len = num_frames * frame_seqlen |
| total_length = int(ref_token_len) + branch_len * 2 |
| padded_length = math.ceil(total_length / 128) * 128 - total_length |
| total_padded = total_length + padded_length |
| clean_offset = int(ref_token_len) |
| noisy_offset = clean_offset + branch_len |
|
|
| context_ends = torch.zeros(total_padded, device=device, dtype=torch.long) |
| noise_context_ends = torch.zeros(total_padded, device=device, dtype=torch.long) |
| noise_noise_starts = torch.zeros(total_padded, device=device, dtype=torch.long) |
| noise_noise_ends = torch.zeros(total_padded, device=device, dtype=torch.long) |
|
|
| block_starts, block_ends = CausalWanModel._frame_block_token_ranges( |
| device=device, |
| num_frames=num_frames, |
| frame_seqlen=frame_seqlen, |
| num_frame_per_block=num_frame_per_block, |
| independent_first_frame=independent_first_frame, |
| ) |
| for start, end in zip(block_starts, block_ends): |
| context_ends[clean_offset + start:clean_offset + end] = clean_offset + end |
| noise_start = noisy_offset + start |
| noise_end = noisy_offset + end |
| noise_noise_starts[noise_start:noise_end] = noise_start |
| noise_noise_ends[noise_start:noise_end] = noise_end |
| noise_context_ends[noise_start:noise_end] = clean_offset + start |
|
|
| def attention_mask(b, h, q_idx, kv_idx): |
| q_is_ref = q_idx < ref_token_len |
| kv_is_ref = kv_idx < ref_token_len |
| clean_q = (q_idx >= clean_offset) & (q_idx < noisy_offset) |
| noisy_q = (q_idx >= noisy_offset) & (q_idx < total_length) |
| clean_mask = clean_q & (kv_idx >= clean_offset) & (kv_idx < context_ends[q_idx]) |
| noisy_self = noisy_q & (kv_idx >= noise_noise_starts[q_idx]) & (kv_idx < noise_noise_ends[q_idx]) |
| noisy_history = noisy_q & (kv_idx >= clean_offset) & (kv_idx < noise_context_ends[q_idx]) |
| return (q_is_ref & kv_is_ref) | ((~q_is_ref) & (kv_is_ref | clean_mask | noisy_self | noisy_history)) | (q_idx == kv_idx) |
|
|
| return create_block_mask( |
| attention_mask, |
| B=None, |
| H=None, |
| Q_LEN=total_padded, |
| KV_LEN=total_padded, |
| _compile=False, |
| device=device, |
| ) |
|
|
| def _maybe_build_block_mask( |
| self, |
| device, |
| num_frames, |
| frame_seqlen, |
| is_teacher_forcing, |
| ref_token_len=0, |
| independent_first_frame=None, |
| ): |
| """ |
| 只有 mask 配置变化时重建,避免不同帧数/分辨率/TF 状态复用旧 BlockMask。 |
| 正常不打印;只有后续 flex_attention 崩时会打印 mask repr 和 shape 上下文。 |
| """ |
| if independent_first_frame is None: |
| independent_first_frame = self.independent_first_frame |
| cache_key = ( |
| str(device), |
| int(num_frames), |
| int(frame_seqlen), |
| int(self.num_frame_per_block), |
| int(self.local_attn_size), |
| bool(is_teacher_forcing), |
| bool(independent_first_frame), |
| int(ref_token_len), |
| ) |
| cached_mask = self._block_mask_cache.get(cache_key) |
| if cached_mask is not None: |
| self.block_mask = cached_mask |
| self._block_mask_cache_key = cache_key |
| return |
|
|
| if is_teacher_forcing and ref_token_len > 0: |
| block_mask = self._prepare_teacher_forcing_mask_with_ref_i2v( |
| device, |
| num_frames=num_frames, |
| frame_seqlen=frame_seqlen, |
| ref_token_len=ref_token_len, |
| num_frame_per_block=self.num_frame_per_block, |
| independent_first_frame=bool(independent_first_frame), |
| ) |
| elif is_teacher_forcing: |
| block_mask = self._prepare_teacher_forcing_mask( |
| device, |
| num_frames=num_frames, |
| frame_seqlen=frame_seqlen, |
| num_frame_per_block=self.num_frame_per_block, |
| independent_first_frame=bool(independent_first_frame), |
| ) |
| elif ref_token_len > 0: |
| block_mask = self._prepare_blockwise_causal_attn_mask_with_ref( |
| device, |
| num_frames=num_frames, |
| frame_seqlen=frame_seqlen, |
| ref_token_len=ref_token_len, |
| num_frame_per_block=self.num_frame_per_block, |
| local_attn_size=self.local_attn_size, |
| independent_first_frame=bool(independent_first_frame), |
| ) |
| else: |
| block_mask = self._prepare_blockwise_causal_attn_mask( |
| device, |
| num_frames=num_frames, |
| frame_seqlen=frame_seqlen, |
| num_frame_per_block=self.num_frame_per_block, |
| local_attn_size=self.local_attn_size, |
| independent_first_frame=bool(independent_first_frame), |
| ) |
| self.block_mask = block_mask |
| self._block_mask_cache_key = cache_key |
| self._block_mask_cache[cache_key] = block_mask |
|
|
| def _apply_control_adapters(self, x, act_context=None, act_context_scale=1.0): |
| """复用action control adapter 逻辑;异常时打印 shape。""" |
| try: |
| y_action = None |
|
|
| if act_context is not None and hasattr(self, |
| "act_control_adapter") and self.act_control_adapter is not None: |
| x_new = [] |
| y_action = [self.act_control_adapter(u.unsqueeze(0)) for u in act_context] |
| for u, v in zip(x, y_action): |
| t_f = u.shape[2] |
| c_f = v.shape[2] |
| if t_f > c_f: |
| offset = t_f - c_f |
| u = torch.cat([u[:, :, :offset], u[:, :, offset:] + v * act_context_scale], dim=2) |
| else: |
| u = u + v * act_context_scale |
| x_new.append(u) |
| x = x_new |
| return x, y_action |
| except Exception as e: |
| if _is_checkpoint_stop_signal(e): |
| raise |
| _dbg_print( |
| "control_adapter.failed", |
| error=repr(e), |
| act_context=act_context, |
| act_context_scale=act_context_scale, |
| ) |
| raise |
|
|
| def _prepare_ref_tokens(self, ref_latents=None, ref_mask=None, batch_size=None, device=None, dtype=None): |
| if ref_latents is None: |
| return None |
| ref_latents = ref_latents.detach() |
| in_ch_need = self.patch_embedding.in_channels |
| if ref_latents.ndim == 4: |
| ref_latents = ref_latents.unsqueeze(0).unsqueeze(3) |
| elif ref_latents.ndim == 5 and ref_latents.shape[2] == in_ch_need: |
| ref_latents = ref_latents.unsqueeze(3) |
| elif ref_latents.ndim == 5: |
| ref_latents = ref_latents.unsqueeze(0) |
| if ref_latents.ndim != 6: |
| raise ValueError( |
| f"ref_latents must be [B,K,C,T,H,W], [K,C,T,H,W], or [K,C,H,W], got {tuple(ref_latents.shape)}" |
| ) |
| if device is not None or dtype is not None: |
| ref_latents = ref_latents.to(device=device, dtype=dtype) |
| B, K, C, T, H, W = ref_latents.shape |
| if batch_size is not None and B == 1 and batch_size != 1: |
| ref_latents = ref_latents.expand(batch_size, -1, -1, -1, -1, -1) |
| B = batch_size |
| elif batch_size is not None and B != batch_size: |
| raise ValueError(f"ref_latents batch size {B} does not match video batch size {batch_size}") |
|
|
| if ref_mask is not None: |
| ref_mask = ref_mask.detach() |
| if device is not None or dtype is not None: |
| ref_mask = ref_mask.to(device=device, dtype=dtype) |
| if ref_mask.ndim == 1: |
| ref_mask = ref_mask.unsqueeze(0) |
| if ref_mask.shape[0] == 1 and B != 1: |
| ref_mask = ref_mask.expand(B, -1) |
| if ref_mask.shape[:2] != (B, K): |
| raise ValueError(f"ref_mask shape {tuple(ref_mask.shape)} does not match ref slots {(B, K)}") |
| else: |
| ref_mask = ref_latents.new_ones(B, K) |
|
|
| ref_flat = ref_latents.reshape(B * K, C, T, H, W) |
| if C < in_ch_need: |
| pad = ref_flat.new_zeros(B * K, in_ch_need - C, T, H, W) |
| ref_flat = torch.cat([ref_flat, pad], dim=1) |
| elif C > in_ch_need: |
| ref_flat = ref_flat[:, :in_ch_need] |
| ref_features = self.patch_embedding(ref_flat) |
| _, _, patch_t, patch_h, patch_w = ref_features.shape |
| tokens_per_slot = patch_t * patch_h * patch_w |
| ref_tokens = ref_features.flatten(2).transpose(1, 2) |
| ref_tokens = ref_tokens.reshape(B, K, tokens_per_slot, self.dim) |
| ref_tokens = ref_tokens * ref_mask[:, :, None, None].to(dtype=ref_tokens.dtype) |
| return { |
| "tokens": ref_tokens.reshape(B, K * tokens_per_slot, self.dim), |
| "num_slots": int(K), |
| "tokens_per_slot": int(tokens_per_slot), |
| "token_len": int(K * tokens_per_slot), |
| "grid": (int(patch_t), int(patch_h), int(patch_w)), |
| } |
|
|
| def _estimate_ref_token_len(self, ref_latents=None): |
| if ref_latents is None: |
| return 0 |
|
|
| in_ch_need = self.patch_embedding.in_channels |
| if ref_latents.ndim == 4: |
| k, _, h, w = ref_latents.shape |
| t = 1 |
| elif ref_latents.ndim == 5 and ref_latents.shape[2] == in_ch_need: |
| _, k, _, h, w = ref_latents.shape |
| t = 1 |
| elif ref_latents.ndim == 5: |
| k, _, t, h, w = ref_latents.shape |
| elif ref_latents.ndim == 6: |
| _, k, _, t, h, w = ref_latents.shape |
| else: |
| return 0 |
|
|
| patch_t, patch_h, patch_w = self.patch_size |
| return int(k) * (int(t) // int(patch_t)) * (int(h) // int(patch_h)) * (int(w) // int(patch_w)) |
|
|
| def _prepend_ref_tokens(self, x, e=None, ref_info=None, *args, **kwargs): |
| return x, e |
|
|
| def _expand_frame_modulation_to_tokens(self, e0, frame_seqlen): |
| if e0.shape[1] == 0: |
| return e0 |
| return e0.repeat_interleave(int(frame_seqlen), dim=1) |
|
|
| def _zero_ref_modulation(self, batch_size, token_len, device, dtype): |
| ref_t = torch.zeros((batch_size, 1), dtype=torch.long, device=device) |
| ref_e = self.time_embedding( |
| sinusoidal_embedding_1d(self.freq_dim, ref_t.flatten()).to(dtype) |
| ) |
| ref_e0 = self.time_projection(ref_e).unflatten(1, (6, self.dim)).unflatten(dim=0, sizes=ref_t.shape) |
| return ref_e0.expand(-1, int(token_len), -1, -1) |
|
|
| |
|
|
| def _forward_inference( |
| self, |
| x, |
| t, |
| context, |
| seq_len, |
| y=None, |
| kv_cache: list[dict] | None = None, |
| crossattn_cache: dict = None, |
| current_start: int = 0, |
| cache_start: int = 0, |
| clip_fea=None, |
| act_context=None, |
| ref_latents=None, |
| ref_mask=None, |
| act_context_scale=1.0, |
| ): |
| if torch.is_grad_enabled(): |
| return self._forward_train( |
| x=x, |
| t=t, |
| context=context, |
| seq_len=seq_len, |
| y=y, |
| clip_fea=clip_fea, |
| act_context=act_context, |
| ref_latents=ref_latents, |
| ref_mask=ref_mask, |
| act_context_scale=act_context_scale, |
| ) |
|
|
| if self.model_type == 'i2v': |
| assert y is not None |
| device = self.patch_embedding.weight.device |
| if self.freqs.device != device: |
| self.freqs = self.freqs.to(device) |
|
|
| if seq_len is None: |
| seq_len = x.shape[2] * x.shape[-2] * x.shape[-1] // ( |
| self.patch_size[1] * self.patch_size[2] * self.patch_size[0]) |
|
|
| if y is not None and self.model_type in ['i2v', 'ti2v']: |
| x = [torch.cat([u, v], dim=0) for u, v in zip(x, y)] |
|
|
| x = [self.patch_embedding(u.unsqueeze(0)) for u in x] |
| x, _ = self._apply_control_adapters( |
| x, |
| act_context=act_context, |
| act_context_scale=act_context_scale, |
| ) |
|
|
| grid_sizes = torch.stack( |
| [torch.tensor(u.shape[2:], dtype=torch.long, device=device) for u in x] |
| ) |
| x = [u.flatten(2).transpose(1, 2) for u in x] |
| seq_lens = torch.tensor([u.size(1) for u in x], dtype=torch.long, device=device) |
| assert seq_lens.max() <= seq_len |
| x = torch.cat(x, dim=0) |
|
|
| e = self.time_embedding( |
| sinusoidal_embedding_1d(self.freq_dim, t.flatten()).to(x.dtype)) |
| e0 = self.time_projection(e).unflatten(1, (6, self.dim)).unflatten(dim=0, sizes=t.shape) |
|
|
| context_lens = None |
| context = self.text_embedding( |
| torch.stack([ |
| torch.cat( |
| [u, u.new_zeros(self.text_len - u.size(0), u.size(1))] |
| ) |
| for u in context |
| ]) |
| ) |
|
|
| if clip_fea is not None and hasattr(self, "img_emb"): |
| context_clip = self.img_emb(clip_fea) |
| context = torch.concat([context_clip, context], dim=1) |
|
|
| ref_info = self._prepare_ref_tokens( |
| ref_latents=ref_latents, |
| ref_mask=ref_mask, |
| batch_size=x.shape[0], |
| device=device, |
| dtype=x.dtype, |
| ) |
| N_r = ref_info["token_len"] if ref_info is not None else 0 |
| include_ref_tokens = ref_info is not None and (kv_cache is None or current_start == 0) |
| query_ref_token_len = N_r if include_ref_tokens else 0 |
| if include_ref_tokens: |
| ref_tokens = ref_info["tokens"] |
| e0 = self._expand_frame_modulation_to_tokens(e0, math.prod(grid_sizes[0][1:]).item()) |
| ref_e0 = self._zero_ref_modulation( |
| batch_size=x.shape[0], |
| token_len=query_ref_token_len, |
| device=device, |
| dtype=x.dtype, |
| ) |
| x = torch.cat([ref_tokens, x], dim=1) |
| e0 = torch.cat([ref_e0, e0], dim=1) |
|
|
| for block in self.blocks: |
| block.self_attn._is_teacher_forcing = False |
| block.self_attn._num_ref_tokens = N_r |
| block.self_attn._query_ref_token_len = query_ref_token_len |
| if ref_info is not None: |
| block.self_attn._ref_num_slots = ref_info["num_slots"] |
| block.self_attn._ref_tokens_per_frame = ref_info["tokens_per_slot"] |
| block.self_attn._ref_grid_sizes = ref_info["grid"] |
| else: |
| block.self_attn._ref_num_slots = 0 |
| block.self_attn._ref_tokens_per_frame = None |
| block.self_attn._ref_grid_sizes = None |
|
|
| kwargs = dict( |
| e=e0, |
| seq_lens=seq_lens, |
| grid_sizes=grid_sizes, |
| freqs=self.freqs, |
| context=context, |
| context_lens=context_lens, |
| block_mask=self.block_mask, |
| ) |
|
|
| def create_custom_forward(module): |
| def custom_forward(*inputs, **kw): |
| return module(*inputs, **kw) |
|
|
| return custom_forward |
|
|
| for idx, block in enumerate(self.blocks): |
| if torch.is_grad_enabled() and self.gradient_checkpointing: |
| kwargs.update( |
| dict( |
| kv_cache=kv_cache[idx], |
| current_start=current_start, |
| cache_start=cache_start, |
| ) |
| ) |
| x = torch.utils.checkpoint.checkpoint( |
| create_custom_forward(block), |
| x, **kwargs, use_reentrant=False, |
| ) |
| else: |
| kwargs.update( |
| { |
| "kv_cache": kv_cache[idx], |
| "crossattn_cache": crossattn_cache[idx] if crossattn_cache is not None else None, |
| "current_start": current_start, |
| "cache_start": cache_start |
| } |
| ) |
| x = block(x, **kwargs) |
|
|
| if query_ref_token_len > 0: |
| x = x[:, query_ref_token_len:] |
| x = self.head(x, e.unflatten(dim=0, sizes=t.shape).unsqueeze(2)) |
| x = self.unpatchify(x, grid_sizes) |
| return torch.stack(x) |
|
|
| |
|
|
| def _forward_train( |
| self, |
| x, |
| t, |
| context, |
| seq_len, |
| y=None, |
| clean_x=None, |
| aug_t=None, |
| clip_fea=None, |
| act_context=None, |
| ref_latents=None, |
| ref_mask=None, |
| act_context_scale=1.0, |
| current_start: int = 0, |
| ): |
| try: |
| if self.model_type == 'i2v': |
| assert y is not None |
| device = self.patch_embedding.weight.device |
| if self.freqs.device != device: |
| self.freqs = self.freqs.to(device) |
|
|
| if seq_len is None: |
| seq_len = x.shape[2] * x.shape[-2] * x.shape[-1] // ( |
| self.patch_size[1] * self.patch_size[2] * self.patch_size[0]) |
|
|
| num_frames = x.shape[2] |
| frame_seqlen = x.shape[-2] * x.shape[-1] // (self.patch_size[1] * self.patch_size[2]) |
| print("_forward_train: x[0]", x[0].shape) |
| absolute_start_frame = int(current_start) // int(frame_seqlen) if frame_seqlen > 0 else 0 |
| mask_independent_first_frame = bool(self.independent_first_frame) and absolute_start_frame == 0 |
| ref_token_len = self._estimate_ref_token_len(ref_latents) |
| self._maybe_build_block_mask( |
| device=device, |
| num_frames=num_frames, |
| frame_seqlen=frame_seqlen, |
| is_teacher_forcing=(clean_x is not None), |
| ref_token_len=ref_token_len, |
| independent_first_frame=mask_independent_first_frame, |
| ) |
| if y is not None and self.model_type in ['i2v', 'ti2v']: |
| x = [torch.cat([u, v], dim=0) for u, v in zip(x, y)] |
|
|
| x = [self.patch_embedding(u.unsqueeze(0)) for u in x] |
| x, y_action = self._apply_control_adapters( |
| x, |
| act_context=act_context, |
| act_context_scale=act_context_scale, |
| ) |
|
|
| grid_sizes = torch.stack( |
| [torch.tensor(u.shape[2:], dtype=torch.long, device=device) for u in x] |
| ) |
| x = [u.flatten(2).transpose(1, 2) for u in x] |
| seq_lens = torch.tensor([u.size(1) for u in x], dtype=torch.long, device=device) |
| assert seq_lens.max() <= seq_len |
|
|
| max_len = seq_lens[0].item() |
| x = torch.cat([ |
| torch.cat([u, u.new_zeros(1, max_len - u.size(1), u.size(2))], dim=1) |
| for u in x |
| ]) |
|
|
| e = self.time_embedding( |
| sinusoidal_embedding_1d(self.freq_dim, t.flatten()).to(x.dtype)) |
| e0 = self.time_projection(e).unflatten(1, (6, self.dim)).unflatten(dim=0, sizes=t.shape) |
|
|
| context_lens = None |
| context = self.text_embedding( |
| torch.stack([ |
| torch.cat( |
| [u, u.new_zeros(self.text_len - u.size(0), u.size(1))] |
| ) |
| for u in context |
| ]) |
| ) |
|
|
| if clip_fea is not None and hasattr(self, "img_emb"): |
| context_clip = self.img_emb(clip_fea) |
| context = torch.concat([context_clip, context], dim=1) |
|
|
| ref_info = self._prepare_ref_tokens( |
| ref_latents=ref_latents, |
| ref_mask=ref_mask, |
| batch_size=x.shape[0], |
| device=device, |
| dtype=x.dtype, |
| ) |
| N_r = ref_info["token_len"] if ref_info is not None else 0 |
| if N_r != ref_token_len: |
| ref_token_len = N_r |
| self._maybe_build_block_mask( |
| device=device, |
| num_frames=num_frames, |
| frame_seqlen=frame_seqlen, |
| is_teacher_forcing=(clean_x is not None), |
| ref_token_len=ref_token_len, |
| independent_first_frame=mask_independent_first_frame, |
| ) |
|
|
| if clean_x is not None: |
| if y is not None and self.model_type in ['i2v', 'ti2v']: |
| clean_x = [torch.cat([u, v], dim=0) for u, v in zip(clean_x, y)] |
|
|
| clean_x = [self.patch_embedding(u.unsqueeze(0)) for u in clean_x] |
|
|
|
|
|
|
| if act_context is not None and hasattr(self, |
| "act_control_adapter") and self.act_control_adapter is not None: |
| x_new = [] |
| for u, v in zip(clean_x, y_action): |
| t_f = u.shape[2] |
| c_f = v.shape[2] |
| if t_f > c_f: |
| offset = t_f - c_f |
| u = torch.cat([u[:, :, :offset], u[:, :, offset:] + v * act_context_scale], dim=2) |
| else: |
| u = u + v * act_context_scale |
| x_new.append(u) |
| clean_x = x_new |
|
|
| clean_x = [u.flatten(2).transpose(1, 2) for u in clean_x] |
| seq_lens_clean = torch.tensor( |
| [u.size(1) for u in clean_x], dtype=torch.long, device=device |
| ) |
| assert seq_lens_clean.max() <= seq_len |
| max_len_clean = seq_lens_clean[0].item() |
| clean_x = torch.cat([ |
| torch.cat( |
| [u, u.new_zeros(1, max_len_clean - u.size(1), u.size(2))], dim=1 |
| ) |
| for u in clean_x |
| ]) |
|
|
| if clean_x.shape[1] != x.shape[1]: |
| _dbg_print( |
| "teacher_forcing.clean_noisy_len_mismatch", |
| clean_x=clean_x, |
| x=x, |
| seq_lens_clean=seq_lens_clean, |
| seq_lens=seq_lens, |
| grid_sizes=grid_sizes, |
| ) |
| raise RuntimeError( |
| f"clean_x token len {clean_x.shape[1]} != noisy x token len {x.shape[1]}" |
| ) |
|
|
| if aug_t is None: |
| aug_t = torch.zeros_like(t) |
| e_clean = self.time_embedding( |
| sinusoidal_embedding_1d(self.freq_dim, aug_t.flatten()).to(x.dtype)) |
| e0_clean = self.time_projection(e_clean).unflatten(1, (6, self.dim)).unflatten(dim=0, sizes=t.shape) |
| if ref_info is not None: |
| ref_tokens = ref_info["tokens"] |
| branch_token_len = x.shape[1] |
| ref_e0 = self._zero_ref_modulation( |
| batch_size=x.shape[0], |
| token_len=N_r, |
| device=device, |
| dtype=x.dtype, |
| ) |
| e0 = self._expand_frame_modulation_to_tokens(e0, frame_seqlen) |
| e0_clean = self._expand_frame_modulation_to_tokens(e0_clean, frame_seqlen) |
| x = torch.cat([ref_tokens, clean_x, x], dim=1) |
| e0 = torch.cat([ref_e0, e0_clean, e0], dim=1) |
| noisy_branch_start = ref_token_len + branch_token_len |
| else: |
| x = torch.cat([clean_x, x], dim=1) |
| e0 = torch.cat([e0_clean, e0], dim=1) |
| noisy_branch_start = x.shape[1] // 2 |
| elif ref_info is not None: |
| ref_tokens = ref_info["tokens"] |
| branch_token_len = x.shape[1] |
| ref_e0 = self._zero_ref_modulation( |
| batch_size=x.shape[0], |
| token_len=N_r, |
| device=device, |
| dtype=x.dtype, |
| ) |
| e0 = self._expand_frame_modulation_to_tokens(e0, frame_seqlen) |
| x = torch.cat([ref_tokens, x], dim=1) |
| e0 = torch.cat([ref_e0, e0], dim=1) |
| noisy_branch_start = ref_token_len |
| else: |
| noisy_branch_start = 0 |
|
|
| for block in self.blocks: |
| block.self_attn._is_teacher_forcing = clean_x is not None |
| block.self_attn._num_ref_tokens = N_r |
| block.self_attn._query_ref_token_len = N_r |
| if ref_info is not None: |
| block.self_attn._ref_num_slots = ref_info["num_slots"] |
| block.self_attn._ref_tokens_per_frame = ref_info["tokens_per_slot"] |
| block.self_attn._ref_grid_sizes = ref_info["grid"] |
| else: |
| block.self_attn._ref_num_slots = 0 |
| block.self_attn._ref_tokens_per_frame = None |
| block.self_attn._ref_grid_sizes = None |
|
|
| kwargs = dict( |
| e=e0, |
| seq_lens=seq_lens, |
| grid_sizes=grid_sizes, |
| freqs=self.freqs, |
| context=context, |
| context_lens=context_lens, |
| block_mask=self.block_mask, |
| current_start=current_start, |
| ) |
|
|
| def create_custom_forward(module): |
| def custom_forward(*inputs, **kw): |
| return module(*inputs, **kw) |
|
|
| return custom_forward |
|
|
| for block_idx, block in enumerate(self.blocks): |
| try: |
| if torch.is_grad_enabled() and self.gradient_checkpointing: |
| x = torch.utils.checkpoint.checkpoint( |
| create_custom_forward(block), |
| x, **kwargs, use_reentrant=False, |
| ) |
| else: |
| x = block(x, **kwargs) |
| except Exception as e_block: |
| if _is_checkpoint_stop_signal(e_block): |
| raise |
| _dbg_print( |
| "model.forward_train.block.failed", |
| error=repr(e_block), |
| block_idx=block_idx, |
| x=x, |
| e=e0, |
| seq_lens=seq_lens, |
| grid_sizes=grid_sizes, |
| context=context, |
| block_mask=_dbg_block_mask(self.block_mask), |
| clean_x_is_not_none=(clean_x is not None), |
| ) |
| raise |
|
|
| if ref_info is not None or clean_x is not None: |
| x = x[:, noisy_branch_start:] |
| elif clean_x is not None: |
| x = x[:, x.shape[1] // 2:] |
|
|
| x = self.head(x, e.unflatten(dim=0, sizes=t.shape).unsqueeze(2)) |
| x = self.unpatchify(x, grid_sizes) |
| return torch.stack(x) |
| except Exception as err: |
| if _is_checkpoint_stop_signal(err): |
| raise |
| _dbg_print( |
| "model.forward_train.failed", |
| error=repr(err), |
| t=t, |
| seq_len=seq_len, |
| y=y, |
| clean_x_is_not_none=(clean_x is not None), |
| aug_t=aug_t, |
| clip_fea=clip_fea, |
| act_context=act_context, |
| ) |
| raise |
|
|
| |
|
|
| |
| |
| |
| |
| |
| def forward(self, *args, **kwargs): |
| |
| |
| if torch.is_grad_enabled() and kwargs.get("kv_cache", None) is not None: |
| for k in ["kv_cache", "crossattn_cache", "current_start", "cache_start"]: |
| kwargs.pop(k, None) |
| return self._forward_train(*args, **kwargs) |
|
|
| if kwargs.get("kv_cache", None) is not None: |
| return self._forward_inference(*args, **kwargs) |
|
|
| return self._forward_train(*args, **kwargs) |
|
|
| |
|
|
| def unpatchify(self, x, grid_sizes): |
| c = self.out_dim |
| out = [] |
| try: |
| for u, v in zip(x, grid_sizes.tolist()): |
| u = u[:math.prod(v)].view(*v, *self.patch_size, c) |
| u = torch.einsum('fhwpqrc->cfphqwr', u) |
| u = u.reshape(c, *[i * j for i, j in zip(v, self.patch_size)]) |
| out.append(u) |
| return out |
| except Exception as e: |
| if _is_checkpoint_stop_signal(e): |
| raise |
| _dbg_print( |
| "unpatchify.failed", |
| error=repr(e), |
| x=x, |
| grid_sizes=grid_sizes, |
| out_dim=c, |
| patch_size=self.patch_size, |
| ) |
| raise |
|
|
| def init_weights(self): |
| for m in self.modules(): |
| if isinstance(m, nn.Linear): |
| nn.init.xavier_uniform_(m.weight) |
| if m.bias is not None: |
| nn.init.zeros_(m.bias) |
|
|
| nn.init.xavier_uniform_(self.patch_embedding.weight.flatten(1)) |
| for m in self.text_embedding.modules(): |
| if isinstance(m, nn.Linear): |
| nn.init.normal_(m.weight, std=.02) |
| for m in self.time_embedding.modules(): |
| if isinstance(m, nn.Linear): |
| nn.init.normal_(m.weight, std=.02) |
|
|
| nn.init.zeros_(self.head.head.weight) |
|
|