@@ -618,6 +618,57 @@ def test_batch_invariant_kernels_replay():
618618 )
619619
620620
621+ @pytest .mark .parametrize ("zero_centered_gamma" , [False , True ], ids = ["gamma" , "zero_centered_gamma" ])
622+ def test_batch_invariant_rmsnorm_replays_and_matches_reference (zero_centered_gamma ):
623+ """Replay the batch-invariant RMSNorm autograd function and check it against fp32 torch.
624+
625+ The weight is random on purpose. At ``weight == 1`` the input gradient with the weight
626+ factor applied twice equals the correct one, and under zero-centred gamma a forward that
627+ forgets the ``+ 1`` returns exactly zero at ``weight == 0`` -- so either default init hides
628+ one of the two defects this function has had. Only a non-unit, non-zero weight sees both.
629+ """
630+ from megatron .core .transformer .custom_layers .batch_invariant_kernels import (
631+ BatchInvariantRMSNormFn ,
632+ )
633+
634+ seeded ()
635+ rows , hidden , eps = 4096 , 2048 , 1e-5
636+ x = torch .randn (rows , hidden , device = "cuda" , dtype = torch .bfloat16 )
637+ weight = torch .randn (hidden , device = "cuda" , dtype = torch .bfloat16 )
638+ grad_output = torch .randn (rows , hidden , device = "cuda" , dtype = torch .bfloat16 )
639+
640+ def run (x , weight ):
641+ return BatchInvariantRMSNormFn .apply (x , weight , eps , zero_centered_gamma )
642+
643+ assert_replays_bit_exact (
644+ run ,
645+ (x .clone ().requires_grad_ (True ), weight .clone ().requires_grad_ (True )),
646+ replays = 3 ,
647+ grad_outputs = {"out" : grad_output },
648+ what = f"bik rmsnorm[zero_centered_gamma={ zero_centered_gamma } ]" ,
649+ )
650+
651+ # fp32 reference, the same arithmetic TE's RMSNorm defines. Its gradients come from
652+ # autograd, so the two defects (a dropped ``+ 1`` in forward, a duplicated weight factor in
653+ # the input gradient) each show up as a mismatch here and nowhere in the replay above.
654+ x_bik = x .clone ().requires_grad_ (True )
655+ w_bik = weight .clone ().requires_grad_ (True )
656+ out_bik = BatchInvariantRMSNormFn .apply (x_bik , w_bik , eps , zero_centered_gamma )
657+ out_bik .backward (grad_output )
658+
659+ x_ref = x .float ().requires_grad_ (True )
660+ w_ref = weight .float ().requires_grad_ (True )
661+ w_eff = w_ref + 1.0 if zero_centered_gamma else w_ref
662+ out_ref = x_ref * torch .rsqrt ((x_ref * x_ref ).mean (dim = - 1 , keepdim = True ) + eps ) * w_eff
663+ out_ref .backward (grad_output .float ())
664+
665+ # The function computes in fp32 and rounds once to the input dtype, so compare after the
666+ # same rounding of the reference; the only remaining difference is reduction order.
667+ torch .testing .assert_close (out_bik , out_ref .to (out_bik .dtype ))
668+ torch .testing .assert_close (x_bik .grad , x_ref .grad .to (x_bik .dtype ))
669+ torch .testing .assert_close (w_bik .grad , w_ref .grad .to (w_bik .dtype ))
670+
671+
621672def test_mask_routing_padding_replays ():
622673 from megatron .core .transformer .moe .inference_routing_mask_kernel import mask_routing_padding
623674
0 commit comments