2222import torch
2323import torch .nn as nn
2424import torch .nn .functional as F
25+ import transformer_engine .pytorch as te
2526from einops import rearrange
2627
2728from loongforge .embodied .model .fastwam .utils .gradient import gradient_checkpoint_forward
@@ -177,28 +178,75 @@ def create_group_causal_attn_mask(
177178 return attn_mask
178179
179180
180- class RMSNorm (nn .Module ):
181- """Root-mean-square normalization for Wan DiT projections."""
181+ class WanRMSNorm (nn .Module ):
182+ """Root-mean-square normalization for Wan DiT projections via ``F.rms_norm``.
183+
184+ This is upstream Wan's own implementation, hence the name.
185+ """
182186
183187 def __init__ (self , dim , eps = 1e-5 ):
184188 """Initialize RMSNorm scale and epsilon."""
185189 super ().__init__ ()
186190 self .eps = eps
187191 self .weight = nn .Parameter (torch .ones (dim ))
188192
189- def norm (self , x ):
190- """Normalize input by root mean square magnitude."""
191- return x * torch .rsqrt (x .pow (2 ).mean (dim = - 1 , keepdim = True ) + self .eps )
192-
193193 def forward (self , x ):
194- """Apply RMS normalization and learned scaling via the fused ATen kernel."""
194+ """Apply RMS normalization and learned scaling via the ATen kernel."""
195195 # F.rms_norm only fuses when weight and x share a dtype; otherwise scale
196196 # separately to keep the original dtype promotion (fp32 weight -> fp32 out).
197197 if self .weight .dtype == x .dtype :
198198 return F .rms_norm (x , self .weight .shape , weight = self .weight , eps = self .eps )
199199 return F .rms_norm (x , self .weight .shape , eps = self .eps ) * self .weight
200200
201201
202+ class TERMSNorm (te .RMSNorm ):
203+ """Transformer Engine RMSNorm for Wan DiT attention projections."""
204+
205+ def __init__ (self , dim , eps = 1e-5 ):
206+ """Initialize a standard (non-zero-centered) RMSNorm."""
207+ # FastWAM constructs experts on CPU before moving them to the target GPU.
208+ super ().__init__ (dim , eps = eps , device = "cpu" , zero_centered_gamma = False )
209+
210+
211+ def make_rmsnorm (dim : int , eps : float , impl : str ) -> nn .Module :
212+ """Build the q/k RMSNorm module selected by ``impl``.
213+
214+ Both implementations expose a single ``weight`` parameter of shape ``(dim,)``,
215+ so checkpoints are interchangeable except for the ``_extra_state`` key that TE
216+ modules add (see ``utils.state_dict.drop_extra_state``).
217+
218+ Which one is faster depends on the torch build, so the choice is configuration
219+ rather than autodetection:
220+
221+ * **torch < 2.9.0** has no fused ``rms_norm`` CUDA kernel — ``F.rms_norm``
222+ decomposes into seven fp32 elementwise/reduction kernels, and TE is ~9.5x
223+ faster. Use ``te``.
224+ * **torch >= 2.9.0** ships ``vectorized_layer_norm_kernel<..., rms_norm=true>``
225+ (22 registers, 100% occupancy). TE 2.9 only precompiles tuned kernels for
226+ hidden sizes {512, 768, 1024, 2048, 4096, 8192}, so the DiT's 3072 falls back
227+ to ``rmsnorm_fwd_general_kernel`` (182 registers, 12.5% occupancy) and the
228+ native kernel is ~2.0x faster. Use ``wan``.
229+
230+ Args:
231+ dim: Normalized (last) dimension size.
232+ eps: Epsilon added to the mean square before the reciprocal square root.
233+ impl: ``"wan"`` (upstream ``F.rms_norm`` module) or ``"te"``.
234+
235+ Returns:
236+ The constructed RMSNorm module.
237+
238+ Raises:
239+ ValueError: If ``impl`` is not a recognized implementation name.
240+ """
241+ if impl == "wan" :
242+ return WanRMSNorm (dim , eps = eps )
243+ if impl == "te" :
244+ return TERMSNorm (dim , eps = eps )
245+ raise ValueError (
246+ f"Unknown RMSNorm implementation { impl !r} ; expected one of ['wan', 'te']."
247+ )
248+
249+
202250class AttentionModule (nn .Module ):
203251 """Small wrapper around FastWAM flash attention."""
204252
@@ -216,7 +264,14 @@ def forward(self, q, k, v, ctx_mask=None):
216264class SelfAttention (nn .Module ):
217265 """Wan DiT self-attention block with RoPE."""
218266
219- def __init__ (self , hidden_dim : int , attn_head_dim : int , num_heads : int , eps : float = 1e-6 ):
267+ def __init__ (
268+ self ,
269+ hidden_dim : int ,
270+ attn_head_dim : int ,
271+ num_heads : int ,
272+ eps : float = 1e-6 ,
273+ rmsnorm_impl : str = "wan" ,
274+ ):
220275 """Initialize self-attention projections and RMS norms."""
221276 super ().__init__ ()
222277 self .hidden_dim = hidden_dim
@@ -228,8 +283,8 @@ def __init__(self, hidden_dim: int, attn_head_dim: int, num_heads: int, eps: flo
228283 self .k = nn .Linear (hidden_dim , self .attn_hidden_dim )
229284 self .v = nn .Linear (hidden_dim , self .attn_hidden_dim )
230285 self .o = nn .Linear (self .attn_hidden_dim , hidden_dim )
231- self .norm_q = RMSNorm (self .attn_hidden_dim , eps = eps )
232- self .norm_k = RMSNorm (self .attn_hidden_dim , eps = eps )
286+ self .norm_q = make_rmsnorm (self .attn_hidden_dim , eps = eps , impl = rmsnorm_impl )
287+ self .norm_k = make_rmsnorm (self .attn_hidden_dim , eps = eps , impl = rmsnorm_impl )
233288
234289 # self.attn = AttentionModule(self.num_heads)
235290
@@ -247,7 +302,14 @@ def forward(self, x, freqs, self_attn_mask: Optional[torch.Tensor] = None):
247302class CrossAttention (nn .Module ):
248303 """Wan DiT cross-attention block for text context."""
249304
250- def __init__ (self , hidden_dim : int , attn_head_dim : int , num_heads : int , eps : float = 1e-6 ):
305+ def __init__ (
306+ self ,
307+ hidden_dim : int ,
308+ attn_head_dim : int ,
309+ num_heads : int ,
310+ eps : float = 1e-6 ,
311+ rmsnorm_impl : str = "wan" ,
312+ ):
251313 """Initialize cross-attention projections and RMS norms."""
252314 super ().__init__ ()
253315 self .hidden_dim = hidden_dim
@@ -259,8 +321,8 @@ def __init__(self, hidden_dim: int, attn_head_dim: int, num_heads: int, eps: flo
259321 self .k = nn .Linear (hidden_dim , self .attn_hidden_dim )
260322 self .v = nn .Linear (hidden_dim , self .attn_hidden_dim )
261323 self .o = nn .Linear (self .attn_hidden_dim , hidden_dim )
262- self .norm_q = RMSNorm (self .attn_hidden_dim , eps = eps )
263- self .norm_k = RMSNorm (self .attn_hidden_dim , eps = eps )
324+ self .norm_q = make_rmsnorm (self .attn_hidden_dim , eps = eps , impl = rmsnorm_impl )
325+ self .norm_k = make_rmsnorm (self .attn_hidden_dim , eps = eps , impl = rmsnorm_impl )
264326
265327 # self.attn = AttentionModule(self.num_heads)
266328
@@ -288,16 +350,24 @@ def forward(self, x, gate, residual):
288350class DiTBlock (nn .Module ):
289351 """Wan DiT transformer block with self-attention, cross-attention, and MLP."""
290352
291- def __init__ (self , hidden_dim : int , attn_head_dim : int , num_heads : int , ffn_dim : int , eps : float = 1e-6 ):
353+ def __init__ (
354+ self ,
355+ hidden_dim : int ,
356+ attn_head_dim : int ,
357+ num_heads : int ,
358+ ffn_dim : int ,
359+ eps : float = 1e-6 ,
360+ rmsnorm_impl : str = "wan" ,
361+ ):
292362 """Initialize one DiT block."""
293363 super ().__init__ ()
294364 self .hidden_dim = hidden_dim
295365 self .attn_head_dim = attn_head_dim
296366 self .num_heads = num_heads
297367 self .ffn_dim = ffn_dim
298368
299- self .self_attn = SelfAttention (hidden_dim , attn_head_dim , num_heads , eps )
300- self .cross_attn = CrossAttention (hidden_dim , attn_head_dim , num_heads , eps )
369+ self .self_attn = SelfAttention (hidden_dim , attn_head_dim , num_heads , eps , rmsnorm_impl )
370+ self .cross_attn = CrossAttention (hidden_dim , attn_head_dim , num_heads , eps , rmsnorm_impl )
301371 self .norm1 = nn .LayerNorm (hidden_dim , eps = eps , elementwise_affine = False )
302372 self .norm2 = nn .LayerNorm (hidden_dim , eps = eps , elementwise_affine = False )
303373 self .norm3 = nn .LayerNorm (hidden_dim , eps = eps )
@@ -416,6 +486,7 @@ def __init__(
416486 action_group_causal_mask_mode : str = "causal" ,
417487 video_attention_mask_mode : str = "bidirectional" ,
418488 use_gradient_checkpointing : bool = False ,
489+ rmsnorm_impl : str = "wan" ,
419490 ):
420491 """Initialize patch, text, time, transformer, and output modules."""
421492 super ().__init__ ()
@@ -459,7 +530,10 @@ def __init__(
459530 )
460531 self .time_projection = nn .Sequential (nn .SiLU (), nn .Linear (hidden_dim , hidden_dim * 6 ))
461532 self .blocks = nn .ModuleList (
462- [DiTBlock (hidden_dim , attn_head_dim , num_heads , ffn_dim , eps ) for _ in range (num_layers )]
533+ [
534+ DiTBlock (hidden_dim , attn_head_dim , num_heads , ffn_dim , eps , rmsnorm_impl )
535+ for _ in range (num_layers )
536+ ]
463537 )
464538 self .head = Head (hidden_dim , out_dim , patch_size , eps )
465539 self .freqs = precompute_freqs_cis_3d (attn_head_dim )
0 commit comments