ALSv/self-forcing
0
1from wan.modules.attention import attention2from wan.modules.model import (3 WanRMSNorm,4 rope_apply,5 WanLayerNorm,6 WAN_CROSSATTENTION_CLASSES,7 rope_params,8 MLPProj,9 sinusoidal_embedding_1d10)11from torch.nn.attention.flex_attention import create_block_mask, flex_attention12from diffusers.configuration_utils import ConfigMixin, register_to_config13from torch.nn.attention.flex_attention import BlockMask14from diffusers.models.modeling_utils import ModelMixin15import torch.nn as nn16import torch17import math18import torch.distributed as dist19 20# wan 1.3B model has a weird channel / head configurations and require max-autotune to work with flexattention21# see https://github.com/pytorch/pytorch/issues/13325422# change to default for other models23flex_attention = torch.compile(24 flex_attention, dynamic=False, mode="max-autotune-no-cudagraphs")25 26 27def causal_rope_apply(x, grid_sizes, freqs, start_frame=0):28 n, c = x.size(2), x.size(3) // 229 30 # split freqs31 freqs = freqs.split([c - 2 * (c // 3), c // 3, c // 3], dim=1)32 33 # loop over samples34 output = []35 36 for i, (f, h, w) in enumerate(grid_sizes.tolist()):37 seq_len = f * h * w38 39 # precompute multipliers40 x_i = torch.view_as_complex(x[i, :seq_len].to(torch.float64).reshape(41 seq_len, n, -1, 2))42 freqs_i = torch.cat([43 freqs[0][start_frame:start_frame + f].view(f, 1, 1, -1).expand(f, h, w, -1),44 freqs[1][:h].view(1, h, 1, -1).expand(f, h, w, -1),45 freqs[2][:w].view(1, 1, w, -1).expand(f, h, w, -1)46 ],47 dim=-1).reshape(seq_len, 1, -1)48 49 # apply rotary embedding50 x_i = torch.view_as_real(x_i * freqs_i).flatten(2)51 x_i = torch.cat([x_i, x[i, seq_len:]])52 53 # append to collection54 output.append(x_i)55 return torch.stack(output).type_as(x)56 57 58class CausalWanSelfAttention(nn.Module):59 60 def __init__(self,61 dim,62 num_heads,63 local_attn_size=-1,64 sink_size=0,65 qk_norm=True,66 eps=1e-6):67 assert dim % num_heads == 068 super().__init__()69 self.dim = dim70 self.num_heads = num_heads71 self.head_dim = dim // num_heads72 self.local_attn_size = local_attn_size73 self.sink_size = sink_size74 self.qk_norm = qk_norm75 self.eps = eps76 self.max_attention_size = 32760 if local_attn_size == -1 else local_attn_size * 156077 78 # layers79 self.q = nn.Linear(dim, dim)80 self.k = nn.Linear(dim, dim)81 self.v = nn.Linear(dim, dim)82 self.o = nn.Linear(dim, dim)83 self.norm_q = WanRMSNorm(dim, eps=eps) if qk_norm else nn.Identity()84 self.norm_k = WanRMSNorm(dim, eps=eps) if qk_norm else nn.Identity()85 86 def forward(87 self,88 x,89 seq_lens,90 grid_sizes,91 freqs,92 block_mask,93 kv_cache=None,94 current_start=0,95 cache_start=None96 ):97 r"""98 Args:99 x(Tensor): Shape [B, L, num_heads, C / num_heads]100 seq_lens(Tensor): Shape [B]101 grid_sizes(Tensor): Shape [B, 3], the second dimension contains (F, H, W)102 freqs(Tensor): Rope freqs, shape [1024, C / num_heads / 2]103 block_mask (BlockMask)104 """105 b, s, n, d = *x.shape[:2], self.num_heads, self.head_dim106 if cache_start is None:107 cache_start = current_start108 109 # query, key, value function110 def qkv_fn(x):111 q = self.norm_q(self.q(x)).view(b, s, n, d)112 k = self.norm_k(self.k(x)).view(b, s, n, d)113 v = self.v(x).view(b, s, n, d)114 return q, k, v115 116 q, k, v = qkv_fn(x)117 118 if kv_cache is None:119 # if it is teacher forcing training?120 is_tf = (s == seq_lens[0].item() * 2)121 if is_tf:122 q_chunk = torch.chunk(q, 2, dim=1)123 k_chunk = torch.chunk(k, 2, dim=1)124 roped_query = []125 roped_key = []126 # rope should be same for clean and noisy parts127 for ii in range(2):128 rq = rope_apply(q_chunk[ii], grid_sizes, freqs).type_as(v)129 rk = rope_apply(k_chunk[ii], grid_sizes, freqs).type_as(v)130 roped_query.append(rq)131 roped_key.append(rk)132 133 roped_query = torch.cat(roped_query, dim=1)134 roped_key = torch.cat(roped_key, dim=1)135 136 padded_length = math.ceil(q.shape[1] / 128) * 128 - q.shape[1]137 padded_roped_query = torch.cat(138 [roped_query,139 torch.zeros([q.shape[0], padded_length, q.shape[2], q.shape[3]],140 device=q.device, dtype=v.dtype)],141 dim=1142 )143 144 padded_roped_key = torch.cat(145 [roped_key, torch.zeros([k.shape[0], padded_length, k.shape[2], k.shape[3]],146 device=k.device, dtype=v.dtype)],147 dim=1148 )149 150 padded_v = torch.cat(151 [v, torch.zeros([v.shape[0], padded_length, v.shape[2], v.shape[3]],152 device=v.device, dtype=v.dtype)],153 dim=1154 )155 156 x = flex_attention(157 query=padded_roped_query.transpose(2, 1),158 key=padded_roped_key.transpose(2, 1),159 value=padded_v.transpose(2, 1),160 block_mask=block_mask161 )[:, :, :-padded_length].transpose(2, 1)162 163 else:164 roped_query = rope_apply(q, grid_sizes, freqs).type_as(v)165 roped_key = rope_apply(k, grid_sizes, freqs).type_as(v)166 167 padded_length = math.ceil(q.shape[1] / 128) * 128 - q.shape[1]168 padded_roped_query = torch.cat(169 [roped_query,170 torch.zeros([q.shape[0], padded_length, q.shape[2], q.shape[3]],171 device=q.device, dtype=v.dtype)],172 dim=1173 )174 175 padded_roped_key = torch.cat(176 [roped_key, torch.zeros([k.shape[0], padded_length, k.shape[2], k.shape[3]],177 device=k.device, dtype=v.dtype)],178 dim=1179 )180 181 padded_v = torch.cat(182 [v, torch.zeros([v.shape[0], padded_length, v.shape[2], v.shape[3]],183 device=v.device, dtype=v.dtype)],184 dim=1185 )186 187 x = flex_attention(188 query=padded_roped_query.transpose(2, 1),189 key=padded_roped_key.transpose(2, 1),190 value=padded_v.transpose(2, 1),191 block_mask=block_mask192 )[:, :, :-padded_length].transpose(2, 1)193 else:194 frame_seqlen = math.prod(grid_sizes[0][1:]).item()195 current_start_frame = current_start // frame_seqlen196 roped_query = causal_rope_apply(197 q, grid_sizes, freqs, start_frame=current_start_frame).type_as(v)198 roped_key = causal_rope_apply(199 k, grid_sizes, freqs, start_frame=current_start_frame).type_as(v)200 201 current_end = current_start + roped_query.shape[1]202 sink_tokens = self.sink_size * frame_seqlen203 # If we are using local attention and the current KV cache size is larger than the local attention size, we need to truncate the KV cache204 kv_cache_size = kv_cache["k"].shape[1]205 num_new_tokens = roped_query.shape[1]206 if self.local_attn_size != -1 and (current_end > kv_cache["global_end_index"].item()) and (207 num_new_tokens + kv_cache["local_end_index"].item() > kv_cache_size):208 # Calculate the number of new tokens added in this step209 # Shift existing cache content left to discard oldest tokens210 # Clone the source slice to avoid overlapping memory error211 num_evicted_tokens = num_new_tokens + kv_cache["local_end_index"].item() - kv_cache_size212 num_rolled_tokens = kv_cache["local_end_index"].item() - num_evicted_tokens - sink_tokens213 kv_cache["k"][:, sink_tokens:sink_tokens + num_rolled_tokens] = \214 kv_cache["k"][:, sink_tokens + num_evicted_tokens:sink_tokens + num_evicted_tokens + num_rolled_tokens].clone()215 kv_cache["v"][:, sink_tokens:sink_tokens + num_rolled_tokens] = \216 kv_cache["v"][:, sink_tokens + num_evicted_tokens:sink_tokens + num_evicted_tokens + num_rolled_tokens].clone()217 # Insert the new keys/values at the end218 local_end_index = kv_cache["local_end_index"].item() + current_end - \219 kv_cache["global_end_index"].item() - num_evicted_tokens220 local_start_index = local_end_index - num_new_tokens221 kv_cache["k"][:, local_start_index:local_end_index] = roped_key222 kv_cache["v"][:, local_start_index:local_end_index] = v223 else:224 # Assign new keys/values directly up to current_end225 local_end_index = kv_cache["local_end_index"].item() + current_end - kv_cache["global_end_index"].item()226 local_start_index = local_end_index - num_new_tokens227 kv_cache["k"][:, local_start_index:local_end_index] = roped_key228 kv_cache["v"][:, local_start_index:local_end_index] = v229 x = attention(230 roped_query,231 kv_cache["k"][:, max(0, local_end_index - self.max_attention_size):local_end_index],232 kv_cache["v"][:, max(0, local_end_index - self.max_attention_size):local_end_index]233 )234 kv_cache["global_end_index"].fill_(current_end)235 kv_cache["local_end_index"].fill_(local_end_index)236 237 # output238 x = x.flatten(2)239 x = x.to(self.o.weight.dtype)240 x = self.o(x)241 return x242 243 244class CausalWanAttentionBlock(nn.Module):245 246 def __init__(self,247 cross_attn_type,248 dim,249 ffn_dim,250 num_heads,251 local_attn_size=-1,252 sink_size=0,253 qk_norm=True,254 cross_attn_norm=False,255 eps=1e-6):256 super().__init__()257 self.dim = dim258 self.ffn_dim = ffn_dim259 self.num_heads = num_heads260 self.local_attn_size = local_attn_size261 self.qk_norm = qk_norm262 self.cross_attn_norm = cross_attn_norm263 self.eps = eps264 265 # layers266 self.norm1 = WanLayerNorm(dim, eps)267 self.self_attn = CausalWanSelfAttention(dim, num_heads, local_attn_size, sink_size, qk_norm, eps)268 self.norm3 = WanLayerNorm(269 dim, eps,270 elementwise_affine=True) if cross_attn_norm else nn.Identity()271 self.cross_attn = WAN_CROSSATTENTION_CLASSES[cross_attn_type](dim,272 num_heads,273 (-1, -1),274 qk_norm,275 eps)276 self.norm2 = WanLayerNorm(dim, eps)277 self.ffn = nn.Sequential(278 nn.Linear(dim, ffn_dim), nn.GELU(approximate='tanh'),279 nn.Linear(ffn_dim, dim))280 281 # modulation282 self.modulation = nn.Parameter(torch.randn(1, 6, dim) / dim**0.5)283 284 def forward(285 self,286 x,287 e,288 seq_lens,289 grid_sizes,290 freqs,291 context,292 context_lens,293 block_mask,294 kv_cache=None,295 crossattn_cache=None,296 current_start=0,297 cache_start=None298 ):299 r"""300 Args:301 x(Tensor): Shape [B, L, C]302 e(Tensor): Shape [B, F, 6, C]303 seq_lens(Tensor): Shape [B], length of each sequence in batch304 grid_sizes(Tensor): Shape [B, 3], the second dimension contains (F, H, W)305 freqs(Tensor): Rope freqs, shape [1024, C / num_heads / 2]306 """307 num_frames, frame_seqlen = e.shape[1], x.shape[1] // e.shape[1]308 # assert e.dtype == torch.float32309 # with amp.autocast(dtype=torch.float32):310 e = (self.modulation.unsqueeze(1) + e).chunk(6, dim=2)311 # assert e[0].dtype == torch.float32312 313 # self-attention314 y = self.self_attn(315 (self.norm1(x).unflatten(dim=1, sizes=(num_frames, frame_seqlen)) * (1 + e[1]) + e[0]).flatten(1, 2),316 seq_lens, grid_sizes,317 freqs, block_mask, kv_cache, current_start, cache_start)318 319 # with amp.autocast(dtype=torch.float32):320 x = x + (y.unflatten(dim=1, sizes=(num_frames, frame_seqlen)) * e[2]).flatten(1, 2)321 322 # cross-attention & ffn function323 def cross_attn_ffn(x, context, context_lens, e, crossattn_cache=None):324 x = x + self.cross_attn(self.norm3(x), context,325 context_lens, crossattn_cache=crossattn_cache)326 y = self.ffn(327 (self.norm2(x).unflatten(dim=1, sizes=(num_frames,328 frame_seqlen)) * (1 + e[4]) + e[3]).flatten(1, 2)329 )330 # with amp.autocast(dtype=torch.float32):331 x = x + (y.unflatten(dim=1, sizes=(num_frames,332 frame_seqlen)) * e[5]).flatten(1, 2)333 return x334 335 x = cross_attn_ffn(x, context, context_lens, e, crossattn_cache)336 return x337 338 339class CausalHead(nn.Module):340 341 def __init__(self, dim, out_dim, patch_size, eps=1e-6):342 super().__init__()343 self.dim = dim344 self.out_dim = out_dim345 self.patch_size = patch_size346 self.eps = eps347 348 # layers349 out_dim = math.prod(patch_size) * out_dim350 self.norm = WanLayerNorm(dim, eps)351 self.head = nn.Linear(dim, out_dim)352 353 # modulation354 self.modulation = nn.Parameter(torch.randn(1, 2, dim) / dim**0.5)355 356 def forward(self, x, e):357 r"""358 Args:359 x(Tensor): Shape [B, L1, C]360 e(Tensor): Shape [B, F, 1, C]361 """362 # assert e.dtype == torch.float32363 # with amp.autocast(dtype=torch.float32):364 num_frames, frame_seqlen = e.shape[1], x.shape[1] // e.shape[1]365 e = (self.modulation.unsqueeze(1) + e).chunk(2, dim=2)366 x = (self.head(self.norm(x).unflatten(dim=1, sizes=(num_frames, frame_seqlen)) * (1 + e[1]) + e[0]))367 return x368 369 370class CausalWanModel(ModelMixin, ConfigMixin):371 r"""372 Wan diffusion backbone supporting both text-to-video and image-to-video.373 """374 375 ignore_for_config = [376 'patch_size', 'cross_attn_norm', 'qk_norm', 'text_dim'377 ]378 _no_split_modules = ['WanAttentionBlock']379 _supports_gradient_checkpointing = True380 381 @register_to_config382 def __init__(self,383 model_type='t2v',384 patch_size=(1, 2, 2),385 text_len=512,386 in_dim=16,387 dim=2048,388 ffn_dim=8192,389 freq_dim=256,390 text_dim=4096,391 out_dim=16,392 num_heads=16,393 num_layers=32,394 local_attn_size=-1,395 sink_size=0,396 qk_norm=True,397 cross_attn_norm=True,398 eps=1e-6):399 r"""400 Initialize the diffusion model backbone.401 402 Args:403 model_type (`str`, *optional*, defaults to 't2v'):404 Model variant - 't2v' (text-to-video) or 'i2v' (image-to-video)405 patch_size (`tuple`, *optional*, defaults to (1, 2, 2)):406 3D patch dimensions for video embedding (t_patch, h_patch, w_patch)407 text_len (`int`, *optional*, defaults to 512):408 Fixed length for text embeddings409 in_dim (`int`, *optional*, defaults to 16):410 Input video channels (C_in)411 dim (`int`, *optional*, defaults to 2048):412 Hidden dimension of the transformer413 ffn_dim (`int`, *optional*, defaults to 8192):414 Intermediate dimension in feed-forward network415 freq_dim (`int`, *optional*, defaults to 256):416 Dimension for sinusoidal time embeddings417 text_dim (`int`, *optional*, defaults to 4096):418 Input dimension for text embeddings419 out_dim (`int`, *optional*, defaults to 16):420 Output video channels (C_out)421 num_heads (`int`, *optional*, defaults to 16):422 Number of attention heads423 num_layers (`int`, *optional*, defaults to 32):424 Number of transformer blocks425 local_attn_size (`int`, *optional*, defaults to -1):426 Window size for temporal local attention (-1 indicates global attention)427 sink_size (`int`, *optional*, defaults to 0):428 Size of the attention sink, we keep the first `sink_size` frames unchanged when rolling the KV cache429 qk_norm (`bool`, *optional*, defaults to True):430 Enable query/key normalization431 cross_attn_norm (`bool`, *optional*, defaults to False):432 Enable cross-attention normalization433 eps (`float`, *optional*, defaults to 1e-6):434 Epsilon value for normalization layers435 """436 437 super().__init__()438 439 assert model_type in ['t2v', 'i2v']440 self.model_type = model_type441 442 self.patch_size = patch_size443 self.text_len = text_len444 self.in_dim = in_dim445 self.dim = dim446 self.ffn_dim = ffn_dim447 self.freq_dim = freq_dim448 self.text_dim = text_dim449 self.out_dim = out_dim450 self.num_heads = num_heads451 self.num_layers = num_layers452 self.local_attn_size = local_attn_size453 self.qk_norm = qk_norm454 self.cross_attn_norm = cross_attn_norm455 self.eps = eps456 457 # embeddings458 self.patch_embedding = nn.Conv3d(459 in_dim, dim, kernel_size=patch_size, stride=patch_size)460 self.text_embedding = nn.Sequential(461 nn.Linear(text_dim, dim), nn.GELU(approximate='tanh'),462 nn.Linear(dim, dim))463 464 self.time_embedding = nn.Sequential(465 nn.Linear(freq_dim, dim), nn.SiLU(), nn.Linear(dim, dim))466 self.time_projection = nn.Sequential(467 nn.SiLU(), nn.Linear(dim, dim * 6))468 469 # blocks470 cross_attn_type = 't2v_cross_attn' if model_type == 't2v' else 'i2v_cross_attn'471 self.blocks = nn.ModuleList([472 CausalWanAttentionBlock(cross_attn_type, dim, ffn_dim, num_heads,473 local_attn_size, sink_size, qk_norm, cross_attn_norm, eps)474 for _ in range(num_layers)475 ])476 477 # head478 self.head = CausalHead(dim, out_dim, patch_size, eps)479 480 # buffers (don't use register_buffer otherwise dtype will be changed in to())481 assert (dim % num_heads) == 0 and (dim // num_heads) % 2 == 0482 d = dim // num_heads483 self.freqs = torch.cat([484 rope_params(1024, d - 4 * (d // 6)),485 rope_params(1024, 2 * (d // 6)),486 rope_params(1024, 2 * (d // 6))487 ],488 dim=1)489 490 if model_type == 'i2v':491 self.img_emb = MLPProj(1280, dim)492 493 # initialize weights494 self.init_weights()495 496 self.gradient_checkpointing = False497 498 self.block_mask = None499 500 self.num_frame_per_block = 1501 self.independent_first_frame = False502 503 def _set_gradient_checkpointing(self, module, value=False):504 self.gradient_checkpointing = value505 506 @staticmethod507 def _prepare_blockwise_causal_attn_mask(508 device: torch.device | str, num_frames: int = 21,509 frame_seqlen: int = 1560, num_frame_per_block=1, local_attn_size=-1510 ) -> BlockMask:511 """512 we will divide the token sequence into the following format513 [1 latent frame] [1 latent frame] ... [1 latent frame]514 We use flexattention to construct the attention mask515 """516 total_length = num_frames * frame_seqlen517 518 # we do right padding to get to a multiple of 128519 padded_length = math.ceil(total_length / 128) * 128 - total_length520 521 ends = torch.zeros(total_length + padded_length,522 device=device, dtype=torch.long)523 524 # Block-wise causal mask will attend to all elements that are before the end of the current chunk525 frame_indices = torch.arange(526 start=0,527 end=total_length,528 step=frame_seqlen * num_frame_per_block,529 device=device530 )531 532 for tmp in frame_indices:533 ends[tmp:tmp + frame_seqlen * num_frame_per_block] = tmp + \534 frame_seqlen * num_frame_per_block535 536 def attention_mask(b, h, q_idx, kv_idx):537 if local_attn_size == -1:538 return (kv_idx < ends[q_idx]) | (q_idx == kv_idx)539 else:540 return ((kv_idx < ends[q_idx]) & (kv_idx >= (ends[q_idx] - local_attn_size * frame_seqlen))) | (q_idx == kv_idx)541 # return ((kv_idx < total_length) & (q_idx < total_length)) | (q_idx == kv_idx) # bidirectional mask542 543 block_mask = create_block_mask(attention_mask, B=None, H=None, Q_LEN=total_length + padded_length,544 KV_LEN=total_length + padded_length, _compile=False, device=device)545 546 import torch.distributed as dist547 if not dist.is_initialized() or dist.get_rank() == 0:548 print(549 f" cache a block wise causal mask with block size of {num_frame_per_block} frames")550 print(block_mask)551 552 # import imageio553 # import numpy as np554 # from torch.nn.attention.flex_attention import create_mask555 556 # mask = create_mask(attention_mask, B=None, H=None, Q_LEN=total_length +557 # padded_length, KV_LEN=total_length + padded_length, device=device)558 # import cv2559 # mask = cv2.resize(mask[0, 0].cpu().float().numpy(), (1024, 1024))560 # imageio.imwrite("mask_%d.jpg" % (0), np.uint8(255. * mask))561 562 return block_mask563 564 @staticmethod565 def _prepare_teacher_forcing_mask(566 device: torch.device | str, num_frames: int = 21,567 frame_seqlen: int = 1560, num_frame_per_block=1568 ) -> BlockMask:569 """570 we will divide the token sequence into the following format571 [1 latent frame] [1 latent frame] ... [1 latent frame]572 We use flexattention to construct the attention mask573 """574 # debug575 DEBUG = False576 if DEBUG:577 num_frames = 9578 frame_seqlen = 256579 580 total_length = num_frames * frame_seqlen * 2581 582 # we do right padding to get to a multiple of 128583 padded_length = math.ceil(total_length / 128) * 128 - total_length584 585 clean_ends = num_frames * frame_seqlen586 # for clean context frames, we can construct their flex attention mask based on a [start, end] interval587 context_ends = torch.zeros(total_length + padded_length, device=device, dtype=torch.long)588 # for noisy frames, we need two intervals to construct the flex attention mask [context_start, context_end] [noisy_start, noisy_end]589 noise_context_starts = torch.zeros(total_length + padded_length, device=device, dtype=torch.long)590 noise_context_ends = torch.zeros(total_length + padded_length, device=device, dtype=torch.long)591 noise_noise_starts = torch.zeros(total_length + padded_length, device=device, dtype=torch.long)592 noise_noise_ends = torch.zeros(total_length + padded_length, device=device, dtype=torch.long)593 594 # Block-wise causal mask will attend to all elements that are before the end of the current chunk595 attention_block_size = frame_seqlen * num_frame_per_block596 frame_indices = torch.arange(597 start=0,598 end=num_frames * frame_seqlen,599 step=attention_block_size,600 device=device, dtype=torch.long601 )602 603 # attention for clean context frames604 for start in frame_indices:605 context_ends[start:start + attention_block_size] = start + attention_block_size606 607 noisy_image_start_list = torch.arange(608 num_frames * frame_seqlen, total_length,609 step=attention_block_size,610 device=device, dtype=torch.long611 )612 noisy_image_end_list = noisy_image_start_list + attention_block_size613 614 # attention for noisy frames615 for block_index, (start, end) in enumerate(zip(noisy_image_start_list, noisy_image_end_list)):616 # attend to noisy tokens within the same block617 noise_noise_starts[start:end] = start618 noise_noise_ends[start:end] = end619 # attend to context tokens in previous blocks620 # noise_context_starts[start:end] = 0621 noise_context_ends[start:end] = block_index * attention_block_size622 623 def attention_mask(b, h, q_idx, kv_idx):624 # first design the mask for clean frames625 clean_mask = (q_idx < clean_ends) & (kv_idx < context_ends[q_idx])626 # then design the mask for noisy frames627 # noisy frames will attend to all clean preceeding clean frames + itself628 C1 = (kv_idx < noise_noise_ends[q_idx]) & (kv_idx >= noise_noise_starts[q_idx])629 C2 = (kv_idx < noise_context_ends[q_idx]) & (kv_idx >= noise_context_starts[q_idx])630 noise_mask = (q_idx >= clean_ends) & (C1 | C2)631 632 eye_mask = q_idx == kv_idx633 return eye_mask | clean_mask | noise_mask634 635 block_mask = create_block_mask(attention_mask, B=None, H=None, Q_LEN=total_length + padded_length,636 KV_LEN=total_length + padded_length, _compile=False, device=device)637 638 if DEBUG:639 print(block_mask)640 import imageio641 import numpy as np642 from torch.nn.attention.flex_attention import create_mask643 644 mask = create_mask(attention_mask, B=None, H=None, Q_LEN=total_length +645 padded_length, KV_LEN=total_length + padded_length, device=device)646 import cv2647 mask = cv2.resize(mask[0, 0].cpu().float().numpy(), (1024, 1024))648 imageio.imwrite("mask_%d.jpg" % (0), np.uint8(255. * mask))649 650 return block_mask651 652 @staticmethod653 def _prepare_blockwise_causal_attn_mask_i2v(654 device: torch.device | str, num_frames: int = 21,655 frame_seqlen: int = 1560, num_frame_per_block=4, local_attn_size=-1656 ) -> BlockMask:657 """658 we will divide the token sequence into the following format659 [1 latent frame] [N latent frame] ... [N latent frame]660 The first frame is separated out to support I2V generation661 We use flexattention to construct the attention mask662 """663 total_length = num_frames * frame_seqlen664 665 # we do right padding to get to a multiple of 128666 padded_length = math.ceil(total_length / 128) * 128 - total_length667 668 ends = torch.zeros(total_length + padded_length,669 device=device, dtype=torch.long)670 671 # special handling for the first frame672 ends[:frame_seqlen] = frame_seqlen673 674 # Block-wise causal mask will attend to all elements that are before the end of the current chunk675 frame_indices = torch.arange(676 start=frame_seqlen,677 end=total_length,678 step=frame_seqlen * num_frame_per_block,679 device=device680 )681 682 for idx, tmp in enumerate(frame_indices):683 ends[tmp:tmp + frame_seqlen * num_frame_per_block] = tmp + \684 frame_seqlen * num_frame_per_block685 686 def attention_mask(b, h, q_idx, kv_idx):687 if local_attn_size == -1:688 return (kv_idx < ends[q_idx]) | (q_idx == kv_idx)689 else:690 return ((kv_idx < ends[q_idx]) & (kv_idx >= (ends[q_idx] - local_attn_size * frame_seqlen))) | \691 (q_idx == kv_idx)692 693 block_mask = create_block_mask(attention_mask, B=None, H=None, Q_LEN=total_length + padded_length,694 KV_LEN=total_length + padded_length, _compile=False, device=device)695 696 if not dist.is_initialized() or dist.get_rank() == 0:697 print(698 f" cache a block wise causal mask with block size of {num_frame_per_block} frames")699 print(block_mask)700 701 # import imageio702 # import numpy as np703 # from torch.nn.attention.flex_attention import create_mask704 705 # mask = create_mask(attention_mask, B=None, H=None, Q_LEN=total_length +706 # padded_length, KV_LEN=total_length + padded_length, device=device)707 # import cv2708 # mask = cv2.resize(mask[0, 0].cpu().float().numpy(), (1024, 1024))709 # imageio.imwrite("mask_%d.jpg" % (0), np.uint8(255. * mask))710 711 return block_mask712 713 def _forward_inference(714 self,715 x,716 t,717 context,718 seq_len,719 clip_fea=None,720 y=None,721 kv_cache: dict = None,722 crossattn_cache: dict = None,723 current_start: int = 0,724 cache_start: int = 0725 ):726 r"""727 Run the diffusion model with kv caching.728 See Algorithm 2 of CausVid paper https://arxiv.org/abs/2412.07772 for details.729 This function will be run for num_frame times.730 Process the latent frames one by one (1560 tokens each)731 732 Args:733 x (List[Tensor]):734 List of input video tensors, each with shape [C_in, F, H, W]735 t (Tensor):736 Diffusion timesteps tensor of shape [B]737 context (List[Tensor]):738 List of text embeddings each with shape [L, C]739 seq_len (`int`):740 Maximum sequence length for positional encoding741 clip_fea (Tensor, *optional*):742 CLIP image features for image-to-video mode743 y (List[Tensor], *optional*):744 Conditional video inputs for image-to-video mode, same shape as x745 746 Returns:747 List[Tensor]:748 List of denoised video tensors with original input shapes [C_out, F, H / 8, W / 8]749 """750 751 if self.model_type == 'i2v':752 assert clip_fea is not None and y is not None753 # params754 device = self.patch_embedding.weight.device755 if self.freqs.device != device:756 self.freqs = self.freqs.to(device)757 758 if y is not None:759 x = [torch.cat([u, v], dim=0) for u, v in zip(x, y)]760 761 # embeddings762 x = [self.patch_embedding(u.unsqueeze(0)) for u in x]763 grid_sizes = torch.stack(764 [torch.tensor(u.shape[2:], dtype=torch.long) for u in x])765 x = [u.flatten(2).transpose(1, 2) for u in x]766 seq_lens = torch.tensor([u.size(1) for u in x], dtype=torch.long)767 assert seq_lens.max() <= seq_len768 x = torch.cat(x)769 """770 torch.cat([771 torch.cat([u, u.new_zeros(1, seq_len - u.size(1), u.size(2))],772 dim=1) for u in x773 ])774 """775 776 # time embeddings777 # with amp.autocast(dtype=torch.float32):778 e = self.time_embedding(779 sinusoidal_embedding_1d(self.freq_dim, t.flatten()).type_as(x))780 e0 = self.time_projection(e).unflatten(781 1, (6, self.dim)).unflatten(dim=0, sizes=t.shape)782 # assert e.dtype == torch.float32 and e0.dtype == torch.float32783 784 # context785 context_lens = None786 context = self.text_embedding(787 torch.stack([788 torch.cat(789 [u, u.new_zeros(self.text_len - u.size(0), u.size(1))])790 for u in context791 ]))792 793 if clip_fea is not None:794 context_clip = self.img_emb(clip_fea) # bs x 257 x dim795 context = torch.concat([context_clip, context], dim=1)796 797 # arguments798 kwargs = dict(799 e=e0,800 seq_lens=seq_lens,801 grid_sizes=grid_sizes,802 freqs=self.freqs,803 context=context,804 context_lens=context_lens,805 block_mask=self.block_mask806 )807 808 def create_custom_forward(module):809 def custom_forward(*inputs, **kwargs):810 return module(*inputs, **kwargs)811 return custom_forward812 813 for block_index, block in enumerate(self.blocks):814 if torch.is_grad_enabled() and self.gradient_checkpointing:815 kwargs.update(816 {817 "kv_cache": kv_cache[block_index],818 "current_start": current_start,819 "cache_start": cache_start820 }821 )822 x = torch.utils.checkpoint.checkpoint(823 create_custom_forward(block),824 x, **kwargs,825 use_reentrant=False,826 )827 else:828 kwargs.update(829 {830 "kv_cache": kv_cache[block_index],831 "crossattn_cache": crossattn_cache[block_index],832 "current_start": current_start,833 "cache_start": cache_start834 }835 )836 x = block(x, **kwargs)837 838 # head839 x = self.head(x, e.unflatten(dim=0, sizes=t.shape).unsqueeze(2))840 # unpatchify841 x = self.unpatchify(x, grid_sizes)842 return torch.stack(x)843 844 def _forward_train(845 self,846 x,847 t,848 context,849 seq_len,850 clean_x=None,851 aug_t=None,852 clip_fea=None,853 y=None,854 ):855 r"""856 Forward pass through the diffusion model857 858 Args:859 x (List[Tensor]):860 List of input video tensors, each with shape [C_in, F, H, W]861 t (Tensor):862 Diffusion timesteps tensor of shape [B]863 context (List[Tensor]):864 List of text embeddings each with shape [L, C]865 seq_len (`int`):866 Maximum sequence length for positional encoding867 clip_fea (Tensor, *optional*):868 CLIP image features for image-to-video mode869 y (List[Tensor], *optional*):870 Conditional video inputs for image-to-video mode, same shape as x871 872 Returns:873 List[Tensor]:874 List of denoised video tensors with original input shapes [C_out, F, H / 8, W / 8]875 """876 if self.model_type == 'i2v':877 assert clip_fea is not None and y is not None878 # params879 device = self.patch_embedding.weight.device880 if self.freqs.device != device:881 self.freqs = self.freqs.to(device)882 883 # Construct blockwise causal attn mask884 if self.block_mask is None:885 if clean_x is not None:886 if self.independent_first_frame:887 raise NotImplementedError()888 else:889 self.block_mask = self._prepare_teacher_forcing_mask(890 device, num_frames=x.shape[2],891 frame_seqlen=x.shape[-2] * x.shape[-1] // (self.patch_size[1] * self.patch_size[2]),892 num_frame_per_block=self.num_frame_per_block893 )894 else:895 if self.independent_first_frame:896 self.block_mask = self._prepare_blockwise_causal_attn_mask_i2v(897 device, num_frames=x.shape[2],898 frame_seqlen=x.shape[-2] * x.shape[-1] // (self.patch_size[1] * self.patch_size[2]),899 num_frame_per_block=self.num_frame_per_block,900 local_attn_size=self.local_attn_size901 )902 else:903 self.block_mask = self._prepare_blockwise_causal_attn_mask(904 device, num_frames=x.shape[2],905 frame_seqlen=x.shape[-2] * x.shape[-1] // (self.patch_size[1] * self.patch_size[2]),906 num_frame_per_block=self.num_frame_per_block,907 local_attn_size=self.local_attn_size908 )909 910 if y is not None:911 x = [torch.cat([u, v], dim=0) for u, v in zip(x, y)]912 913 # embeddings914 x = [self.patch_embedding(u.unsqueeze(0)) for u in x]915 916 grid_sizes = torch.stack(917 [torch.tensor(u.shape[2:], dtype=torch.long) for u in x])918 x = [u.flatten(2).transpose(1, 2) for u in x]919 920 seq_lens = torch.tensor([u.size(1) for u in x], dtype=torch.long)921 assert seq_lens.max() <= seq_len922 x = torch.cat([923 torch.cat([u, u.new_zeros(1, seq_lens[0] - u.size(1), u.size(2))],924 dim=1) for u in x925 ])926 927 # time embeddings928 # with amp.autocast(dtype=torch.float32):929 e = self.time_embedding(930 sinusoidal_embedding_1d(self.freq_dim, t.flatten()).type_as(x))931 e0 = self.time_projection(e).unflatten(932 1, (6, self.dim)).unflatten(dim=0, sizes=t.shape)933 # assert e.dtype == torch.float32 and e0.dtype == torch.float32934 935 # context936 context_lens = None937 context = self.text_embedding(938 torch.stack([939 torch.cat(940 [u, u.new_zeros(self.text_len - u.size(0), u.size(1))])941 for u in context942 ]))943 944 if clip_fea is not None:945 context_clip = self.img_emb(clip_fea) # bs x 257 x dim946 context = torch.concat([context_clip, context], dim=1)947 948 if clean_x is not None:949 clean_x = [self.patch_embedding(u.unsqueeze(0)) for u in clean_x]950 clean_x = [u.flatten(2).transpose(1, 2) for u in clean_x]951 952 seq_lens_clean = torch.tensor([u.size(1) for u in clean_x], dtype=torch.long)953 assert seq_lens_clean.max() <= seq_len954 clean_x = torch.cat([955 torch.cat([u, u.new_zeros(1, seq_lens_clean[0] - u.size(1), u.size(2))], dim=1) for u in clean_x956 ])957 958 x = torch.cat([clean_x, x], dim=1)959 if aug_t is None:960 aug_t = torch.zeros_like(t)961 e_clean = self.time_embedding(962 sinusoidal_embedding_1d(self.freq_dim, aug_t.flatten()).type_as(x))963 e0_clean = self.time_projection(e_clean).unflatten(964 1, (6, self.dim)).unflatten(dim=0, sizes=t.shape)965 e0 = torch.cat([e0_clean, e0], dim=1)966 967 # arguments968 kwargs = dict(969 e=e0,970 seq_lens=seq_lens,971 grid_sizes=grid_sizes,972 freqs=self.freqs,973 context=context,974 context_lens=context_lens,975 block_mask=self.block_mask)976 977 def create_custom_forward(module):978 def custom_forward(*inputs, **kwargs):979 return module(*inputs, **kwargs)980 return custom_forward981 982 for block in self.blocks:983 if torch.is_grad_enabled() and self.gradient_checkpointing:984 x = torch.utils.checkpoint.checkpoint(985 create_custom_forward(block),986 x, **kwargs,987 use_reentrant=False,988 )989 else:990 x = block(x, **kwargs)991 992 if clean_x is not None:993 x = x[:, x.shape[1] // 2:]994 995 # head996 x = self.head(x, e.unflatten(dim=0, sizes=t.shape).unsqueeze(2))997 998 # unpatchify999 x = self.unpatchify(x, grid_sizes)1000 return torch.stack(x)1001 1002 def forward(1003 self,1004 *args,1005 **kwargs1006 ):1007 if kwargs.get('kv_cache', None) is not None:1008 return self._forward_inference(*args, **kwargs)1009 else:1010 return self._forward_train(*args, **kwargs)1011 1012 def unpatchify(self, x, grid_sizes):1013 r"""1014 Reconstruct video tensors from patch embeddings.1015 1016 Args:1017 x (List[Tensor]):1018 List of patchified features, each with shape [L, C_out * prod(patch_size)]1019 grid_sizes (Tensor):1020 Original spatial-temporal grid dimensions before patching,1021 shape [B, 3] (3 dimensions correspond to F_patches, H_patches, W_patches)1022 1023 Returns:1024 List[Tensor]:1025 Reconstructed video tensors with shape [C_out, F, H / 8, W / 8]1026 """1027 1028 c = self.out_dim1029 out = []1030 for u, v in zip(x, grid_sizes.tolist()):1031 u = u[:math.prod(v)].view(*v, *self.patch_size, c)1032 u = torch.einsum('fhwpqrc->cfphqwr', u)1033 u = u.reshape(c, *[i * j for i, j in zip(v, self.patch_size)])1034 out.append(u)1035 return out1036 1037 def init_weights(self):1038 r"""1039 Initialize model parameters using Xavier initialization.1040 """1041 1042 # basic init1043 for m in self.modules():1044 if isinstance(m, nn.Linear):1045 nn.init.xavier_uniform_(m.weight)1046 if m.bias is not None:1047 nn.init.zeros_(m.bias)1048 1049 # init embeddings1050 nn.init.xavier_uniform_(self.patch_embedding.weight.flatten(1))1051 for m in self.text_embedding.modules():1052 if isinstance(m, nn.Linear):1053 nn.init.normal_(m.weight, std=.02)1054 for m in self.time_embedding.modules():1055 if isinstance(m, nn.Linear):1056 nn.init.normal_(m.weight, std=.02)1057 1058 # init output layer1059 nn.init.zeros_(self.head.head.weight)1060 