44import math
55from typing import Any , Optional , Tuple
66
7- import numpy as np
87import torch
9- from einops import rearrange , repeat
108from einops .layers .torch import Rearrange
119from torch import nn
1210import torch .nn .functional as F
@@ -461,9 +459,9 @@ def generate_embeddings(
461459
462460 em_T_H_W_D = torch .cat (
463461 [
464- repeat ( half_emb_t , "t d -> t h w d" , h = H , w = W ),
465- repeat ( half_emb_h , "h d -> t h w d" , t = T , w = W ),
466- repeat ( half_emb_w , "w d -> t h w d" , t = T , h = H ),
462+ half_emb_t [:, None , None , :]. expand ( - 1 , H , W , - 1 ),
463+ half_emb_h [ None , :, None , :]. expand ( T , - 1 , W , - 1 ),
464+ half_emb_w [ None , None , :, :]. expand ( T , H , - 1 , - 1 ),
467465 ]
468466 * 2 ,
469467 dim = - 1 ,
@@ -527,16 +525,16 @@ def generate_embeddings(self, B_T_H_W_C: torch.Size, fps: Optional[torch.Tensor]
527525 emb_w_W = self .pos_emb_w [:W ]
528526 emb_t_T = self .pos_emb_t [:T ]
529527 emb = (
530- repeat ( emb_t_T , "t d-> b t h w d" , b = B , h = H , w = W )
531- + repeat ( emb_h_H , "h d-> b t h w d" , b = B , t = T , w = W )
532- + repeat ( emb_w_W , "w d-> b t h w d" , b = B , t = T , h = H )
528+ emb_t_T [ None , :, None , None , :]. expand ( B , - 1 , H , W , - 1 )
529+ + emb_h_H [ None , None , :, None , :]. expand ( B , T , - 1 , W , - 1 )
530+ + emb_w_W [ None , None , None , :, :]. expand ( B , T , H , - 1 , - 1 )
533531 )
534532 assert list (emb .shape )[:4 ] == [B , T , H , W ], f"bad shape: { list (emb .shape )[:4 ]} != { B , T , H , W } "
535533 else :
536534 raise ValueError (f"Unknown interpolation method { self .interpolation } " )
537535
538536 norm = torch .linalg .vector_norm (emb , dim = - 1 , keepdim = True , dtype = torch .float32 )
539- norm = torch .add (1e-6 , norm , alpha = np .sqrt (norm .numel () / emb .numel ()))
537+ norm = torch .add (1e-6 , norm , alpha = math .sqrt (norm .numel () / emb .numel ()))
540538 return emb / norm .to (emb .dtype )
541539
542540
@@ -557,7 +555,7 @@ def forward(self, timesteps_B_T: torch.Tensor) -> torch.Tensor:
557555 exponent = exponent / (half_dim - 0.0 )
558556
559557 emb = torch .exp (exponent )
560- emb = timesteps [:, None ]. float () * emb [None , :]
558+ emb = timesteps [:, None ] * emb [None , :]
561559
562560 sin_emb = torch .sin (emb )
563561 cos_emb = torch .cos (emb )
@@ -603,33 +601,6 @@ def forward(self, sample: torch.Tensor) -> Tuple[torch.Tensor, Optional[torch.Te
603601
604602 return emb_B_T_D , adaln_lora_B_T_3D
605603
606-
607- # Commented out Fourier Features (not used in Anima). Kept for reference.
608- # class FourierFeatures(nn.Module):
609- # """Fourier feature transform: [B] -> [B, D]."""
610-
611- # def __init__(self, num_channels: int, bandwidth: int = 1, normalize: bool = False):
612- # super().__init__()
613- # self.register_buffer("freqs", 2 * np.pi * bandwidth * torch.randn(num_channels), persistent=True)
614- # self.register_buffer("phases", 2 * np.pi * torch.rand(num_channels), persistent=True)
615- # self.gain = np.sqrt(2) if normalize else 1
616- # self.bandwidth = bandwidth
617- # self.num_channels = num_channels
618- # self.reset_parameters()
619-
620- # def reset_parameters(self) -> None:
621- # generator = torch.Generator()
622- # generator.manual_seed(0)
623- # self.freqs = 2 * np.pi * self.bandwidth * torch.randn(self.num_channels, generator=generator).to(self.freqs.device)
624- # self.phases = 2 * np.pi * torch.rand(self.num_channels, generator=generator).to(self.freqs.device)
625-
626- # def forward(self, x: torch.Tensor, gain: float = 1.0) -> torch.Tensor:
627- # in_dtype = x.dtype
628- # x = x.to(torch.float32).ger(self.freqs.to(torch.float32)).add(self.phases.to(torch.float32))
629- # x = x.cos().mul(self.gain * gain).to(in_dtype)
630- # return x
631-
632-
633604# Patch Embedding
634605class PatchEmbed (nn .Module ):
635606 """Patch embedding: (B, C, T, H, W) -> (B, T', H', W', D)"""
@@ -904,7 +875,7 @@ def _adaln_fn(_x, _norm_layer, _scale, _shift):
904875 result = self .self_attn (
905876 x_flat ,
906877 attn_params ,
907- None ,
878+ x_flat ,
908879 rope_cos_sin = rope_cos_sin ,
909880 ).unflatten (1 , (T , H , W ))
910881 x_B_T_H_W_D = x_B_T_H_W_D + gate_self_attn_B_T_1_1_D * result
@@ -1457,27 +1428,110 @@ def __init__(self, query_dim, context_dim, n_heads, head_dim):
14571428
14581429 self .o_proj = nn .Linear (inner_dim , query_dim , bias = False )
14591430
1460- def forward (self , x , mask = None , context = None , position_embeddings = None , position_embeddings_context = None ):
1431+ def forward (
1432+ self ,
1433+ x ,
1434+ q_mask = None ,
1435+ kv_mask = None ,
1436+ context = None ,
1437+ position_embeddings = None ,
1438+ position_embeddings_context = None ,
1439+ ):
1440+ """
1441+ Args:
1442+ x: Query input [B, L_q, D].
1443+ q_mask: Optional 2-D bool mask [B, L_q] — True = valid token.
1444+ kv_mask: Optional 2-D bool mask [B, L_kv] — True = valid token.
1445+ context: Key/Value input [B, L_kv, D]. Defaults to x (self-attention).
1446+ position_embeddings: (cos, sin) for query RoPE.
1447+ position_embeddings_context: (cos, sin) for key RoPE.
1448+ """
14611449 context = x if context is None else context
14621450 input_shape = x .shape [:- 1 ]
14631451 q_shape = (* input_shape , self .n_heads , self .head_dim )
14641452 context_shape = context .shape [:- 1 ]
14651453 kv_shape = (* context_shape , self .n_heads , self .head_dim )
14661454
1467- query_states = self .q_norm (self .q_proj (x ).view (q_shape )).transpose (1 , 2 )
1468- key_states = self .k_norm (self .k_proj (context ).view (kv_shape )).transpose (1 , 2 )
1469- value_states = self .v_proj (context ).view (kv_shape ).transpose (1 , 2 )
1455+ # [B, L, H, D] layout — native for flash_attn
1456+ query_states = self .q_norm (self .q_proj (x ).view (q_shape ))
1457+ key_states = self .k_norm (self .k_proj (context ).view (kv_shape ))
1458+ value_states = self .v_proj (context ).view (kv_shape )
14701459
14711460 if position_embeddings is not None :
14721461 assert position_embeddings_context is not None
1462+ # RoPE expects [B, H, L, D] layout
14731463 cos , sin = position_embeddings
1474- query_states = _adapter_apply_rotary_pos_emb (query_states , cos , sin )
1464+ query_states = _adapter_apply_rotary_pos_emb (
1465+ query_states .transpose (1 , 2 ), cos , sin
1466+ ).transpose (1 , 2 )
14751467 cos , sin = position_embeddings_context
1476- key_states = _adapter_apply_rotary_pos_emb (key_states , cos , sin )
1468+ key_states = _adapter_apply_rotary_pos_emb (
1469+ key_states .transpose (1 , 2 ), cos , sin
1470+ ).transpose (1 , 2 )
1471+
1472+ can_use_flash = (
1473+ attention .flash_attn_varlen_func is not None
1474+ and query_states .dtype in (torch .float16 , torch .bfloat16 )
1475+ )
1476+
1477+ if can_use_flash and q_mask is None and kv_mask is None :
1478+ # No masking — simple flash attention, [B, L, H, D] layout
1479+ attn_output = attention .flash_attn_func (
1480+ query_states , key_states , value_states
1481+ )
1482+ elif can_use_flash :
1483+ # Varlen flash attention: pack valid tokens, attend, unpack
1484+ B , L_q = query_states .shape [:2 ]
1485+ L_kv = key_states .shape [1 ]
1486+
1487+ eff_q_mask = (
1488+ q_mask
1489+ if q_mask is not None
1490+ else query_states .new_ones (B , L_q , dtype = torch .bool )
1491+ )
1492+ eff_kv_mask = (
1493+ kv_mask
1494+ if kv_mask is not None
1495+ else key_states .new_ones (B , L_kv , dtype = torch .bool )
1496+ )
14771497
1478- attn_output = F .scaled_dot_product_attention (query_states , key_states , value_states , attn_mask = mask )
1498+ q_seqlens = eff_q_mask .sum (dim = 1 , dtype = torch .int32 )
1499+ kv_seqlens = eff_kv_mask .sum (dim = 1 , dtype = torch .int32 )
1500+
1501+ cu_seqlens_q = F .pad (q_seqlens .cumsum (0 , dtype = torch .int32 ), (1 , 0 ))
1502+ cu_seqlens_kv = F .pad (kv_seqlens .cumsum (0 , dtype = torch .int32 ), (1 , 0 ))
1503+
1504+ # Pack by removing padding: [B, L, H, D] -> [total_valid, H, D]
1505+ q_packed = query_states [eff_q_mask ]
1506+ k_packed = key_states [eff_kv_mask ]
1507+ v_packed = value_states [eff_kv_mask ]
1508+
1509+ out_packed = attention .flash_attn_varlen_func (
1510+ q_packed ,
1511+ k_packed ,
1512+ v_packed ,
1513+ cu_seqlens_q ,
1514+ cu_seqlens_kv ,
1515+ L_q ,
1516+ L_kv ,
1517+ )
14791518
1480- attn_output = attn_output .transpose (1 , 2 ).reshape (* input_shape , - 1 ).contiguous ()
1519+ # Unpack: [total_valid_q, H, D] -> [B, L_q, H, D]
1520+ attn_output = query_states .new_zeros (B , L_q , self .n_heads , self .head_dim )
1521+ attn_output [eff_q_mask ] = out_packed
1522+ else :
1523+ # Fallback to PyTorch SDPA: needs [B, H, L, D] layout
1524+ # Expand kv_mask to 4D for SDPA broadcasting: [B, L] -> [B, 1, 1, L]
1525+ sdpa_mask = kv_mask [:, None , None , :] if kv_mask is not None else None
1526+ attn_output = F .scaled_dot_product_attention (
1527+ query_states .transpose (1 , 2 ),
1528+ key_states .transpose (1 , 2 ),
1529+ value_states .transpose (1 , 2 ),
1530+ attn_mask = sdpa_mask ,
1531+ )
1532+ attn_output = attn_output .transpose (1 , 2 )
1533+
1534+ attn_output = attn_output .reshape (* input_shape , - 1 ).contiguous ()
14811535 attn_output = self .o_proj (attn_output )
14821536 return attn_output
14831537
@@ -1525,7 +1579,8 @@ def forward(
15251579 normed = self .norm_self_attn (x )
15261580 attn_out = self .self_attn (
15271581 normed ,
1528- mask = target_attention_mask ,
1582+ q_mask = target_attention_mask ,
1583+ kv_mask = target_attention_mask ,
15291584 position_embeddings = position_embeddings ,
15301585 position_embeddings_context = position_embeddings ,
15311586 )
@@ -1534,7 +1589,8 @@ def forward(
15341589 normed = self .norm_cross_attn (x )
15351590 attn_out = self .cross_attn (
15361591 normed ,
1537- mask = source_attention_mask ,
1592+ q_mask = target_attention_mask ,
1593+ kv_mask = source_attention_mask ,
15381594 context = context ,
15391595 position_embeddings = position_embeddings ,
15401596 position_embeddings_context = position_embeddings_context ,
@@ -1577,15 +1633,17 @@ def __init__(
15771633 self .norm = LLMAdapterRMSNorm (target_dim )
15781634
15791635 def forward (self , source_hidden_states , target_input_ids , target_attention_mask = None , source_attention_mask = None ):
1636+ # Keep masks as 2D [B, L] bool tensors — the attention layer handles
1637+ # expansion to 4D for SDPA or packing for flash_attn_varlen_func.
15801638 if target_attention_mask is not None :
15811639 target_attention_mask = target_attention_mask .to (torch .bool )
1582- if target_attention_mask .ndim == 2 :
1583- target_attention_mask = target_attention_mask .unsqueeze (1 ).unsqueeze (1 )
1640+ if target_attention_mask .ndim == 4 :
1641+ target_attention_mask = target_attention_mask .squeeze (1 ).squeeze (1 )
15841642
15851643 if source_attention_mask is not None :
15861644 source_attention_mask = source_attention_mask .to (torch .bool )
1587- if source_attention_mask .ndim == 2 :
1588- source_attention_mask = source_attention_mask .unsqueeze (1 ).unsqueeze (1 )
1645+ if source_attention_mask .ndim == 4 :
1646+ source_attention_mask = source_attention_mask .squeeze (1 ).squeeze (1 )
15891647
15901648 x = self .in_proj (self .embed (target_input_ids ))
15911649 context = source_hidden_states
@@ -1604,57 +1662,3 @@ def forward(self, source_hidden_states, target_input_ids, target_attention_mask=
16041662 )
16051663 return self .norm (self .out_proj (x ))
16061664
1607-
1608- # Not used currently, but kept for reference
1609-
1610- # def get_dit_config(state_dict, key_prefix=""):
1611- # """Derive DiT configuration from state_dict weight shapes."""
1612- # dit_config = {}
1613- # dit_config["max_img_h"] = 512
1614- # dit_config["max_img_w"] = 512
1615- # dit_config["max_frames"] = 128
1616- # concat_padding_mask = True
1617- # dit_config["in_channels"] = (state_dict["{}x_embedder.proj.1.weight".format(key_prefix)].shape[1] // 4) - int(
1618- # concat_padding_mask
1619- # )
1620- # dit_config["out_channels"] = 16
1621- # dit_config["patch_spatial"] = 2
1622- # dit_config["patch_temporal"] = 1
1623- # dit_config["model_channels"] = state_dict["{}x_embedder.proj.1.weight".format(key_prefix)].shape[0]
1624- # dit_config["concat_padding_mask"] = concat_padding_mask
1625- # dit_config["crossattn_emb_channels"] = 1024
1626- # dit_config["pos_emb_cls"] = "rope3d"
1627- # dit_config["pos_emb_learnable"] = True
1628- # dit_config["pos_emb_interpolation"] = "crop"
1629- # dit_config["min_fps"] = 1
1630- # dit_config["max_fps"] = 30
1631-
1632- # dit_config["use_adaln_lora"] = True
1633- # dit_config["adaln_lora_dim"] = 256
1634- # if dit_config["model_channels"] == 2048:
1635- # dit_config["num_blocks"] = 28
1636- # dit_config["num_heads"] = 16
1637- # elif dit_config["model_channels"] == 5120:
1638- # dit_config["num_blocks"] = 36
1639- # dit_config["num_heads"] = 40
1640- # elif dit_config["model_channels"] == 1280:
1641- # dit_config["num_blocks"] = 20
1642- # dit_config["num_heads"] = 20
1643-
1644- # if dit_config["in_channels"] == 16:
1645- # dit_config["extra_per_block_abs_pos_emb"] = False
1646- # dit_config["rope_h_extrapolation_ratio"] = 4.0
1647- # dit_config["rope_w_extrapolation_ratio"] = 4.0
1648- # dit_config["rope_t_extrapolation_ratio"] = 1.0
1649- # elif dit_config["in_channels"] == 17:
1650- # dit_config["extra_per_block_abs_pos_emb"] = False
1651- # dit_config["rope_h_extrapolation_ratio"] = 3.0
1652- # dit_config["rope_w_extrapolation_ratio"] = 3.0
1653- # dit_config["rope_t_extrapolation_ratio"] = 1.0
1654-
1655- # dit_config["extra_h_extrapolation_ratio"] = 1.0
1656- # dit_config["extra_w_extrapolation_ratio"] = 1.0
1657- # dit_config["extra_t_extrapolation_ratio"] = 1.0
1658- # dit_config["rope_enable_fps_modulation"] = False
1659-
1660- # return dit_config
0 commit comments