1+ # tests/pytorch/test_reference_activation.py
2+ import pytest
3+ import torch
4+ import torch .nn .functional as F
5+
6+ from transformer_engine .plugin .core .backends .reference .impl .activation import (
7+ gelu_torch ,
8+ geglu_torch ,
9+ qgelu_torch ,
10+ qgeglu_torch ,
11+ relu_torch ,
12+ reglu_torch ,
13+ srelu_torch ,
14+ sreglu_torch ,
15+ silu_torch ,
16+ swiglu_torch ,
17+ clamped_swiglu_torch ,
18+ dgelu_torch ,
19+ dgeglu_torch ,
20+ dqgelu_torch ,
21+ dqgeglu_torch ,
22+ drelu_torch ,
23+ dreglu_torch ,
24+ dsrelu_torch ,
25+ dsreglu_torch ,
26+ dsilu_torch ,
27+ dswiglu_torch ,
28+ clamped_dswiglu_torch ,
29+ dbias_dgelu_torch ,
30+ dbias_dsilu_torch ,
31+ dbias_drelu_torch ,
32+ dbias_dqgelu_torch ,
33+ dbias_dsrelu_torch ,
34+ )
35+
36+ # ==============================================================================
37+ # Helper / General Fixtures
38+ # ==============================================================================
39+ @pytest .fixture
40+ def standard_input ():
41+ # Shape (2, 4) ensures .chunk(2, dim=-1) splits it into two (2, 2) tensors cleanly
42+ return torch .tensor ([[- 1.0 , 2.0 , - 3.0 , 4.0 ], [5.0 , - 6.0 , 7.0 , - 8.0 ]], dtype = torch .float32 )
43+
44+ @pytest .fixture
45+ def standard_grad ():
46+ return torch .tensor ([[0.5 , 1.5 , 2.5 , 3.5 ], [4.5 , 5.5 , 6.5 , 7.5 ]], dtype = torch .float32 )
47+
48+
49+ # ==============================================================================
50+ # Part 1: Forward Activation Tests (Using Real Math Verification)
51+ # ==============================================================================
52+
53+ def test_basic_forwards (standard_input ):
54+ quantizer = None
55+
56+ # 1. GeLU
57+ assert torch .allclose (gelu_torch (standard_input , quantizer ), F .gelu (standard_input , approximate = "tanh" ))
58+
59+ # 2. GeGLU
60+ a , b = standard_input .chunk (2 , dim = - 1 )
61+ assert torch .allclose (geglu_torch (standard_input , quantizer ), F .gelu (a , approximate = "tanh" ) * b )
62+
63+ # 3. Quick-GeLU (qgelu)
64+ assert torch .allclose (qgelu_torch (standard_input , quantizer ), standard_input * torch .sigmoid (1.702 * standard_input ))
65+
66+ # 4. Quick-GeGLU (qgeglu)
67+ assert torch .allclose (qgeglu_torch (standard_input , quantizer ), a * torch .sigmoid (1.702 * a ) * b )
68+
69+ # 5. ReLU & ReGLU
70+ assert torch .allclose (relu_torch (standard_input , quantizer ), F .relu (standard_input ))
71+ assert torch .allclose (reglu_torch (standard_input , quantizer ), F .relu (a ) * b )
72+
73+ # 6. Squared ReLU (srelu) & sreglu
74+ assert torch .allclose (srelu_torch (standard_input , quantizer ), torch .square (F .relu (standard_input )))
75+ assert torch .allclose (sreglu_torch (standard_input , quantizer ), torch .square (F .relu (a )) * b )
76+
77+ # 7. SiLU & SwiGLU
78+ assert torch .allclose (silu_torch (standard_input , quantizer ), F .silu (standard_input ))
79+ assert torch .allclose (swiglu_torch (standard_input , quantizer ), F .silu (a ) * b )
80+
81+
82+ def test_clamped_swiglu_forward_boundaries ():
83+ """Verify clamped SwiGLU handles limits and triggers clamp logic precisely."""
84+ quantizer = None
85+ # Input shape: (2, 2) -> splits into a: (2, 1) and b: (2, 1)
86+ inp = torch .tensor ([[- 5.0 , 5.0 ], [0.0 , 1.0 ]], dtype = torch .float32 )
87+
88+ # Execute the activation operator
89+ res = clamped_swiglu_torch (inp , quantizer , limit = 2.0 , alpha = 1.0 )
90+
91+ # Fix tensor shapes to match the 2D column vector format (2, 1) after chunk(2, dim=-1)
92+ expected_a = torch .tensor ([[- 5.0 ], [0.0 ]], dtype = torch .float32 )
93+ expected_b = torch .tensor ([[3.0 ], [2.0 ]], dtype = torch .float32 ) # [5.0 clamped to max limit 2.0] + 1 = 3.0
94+
95+ expected_out = (expected_a * torch .sigmoid (1.0 * expected_a )) * expected_b
96+
97+ # Assert with matching shapes, both are now (2, 1)
98+ assert torch .allclose (res , expected_out )
99+
100+
101+ # ==============================================================================
102+ # Part 2: Backward Gradient Tests (Autograd Consistency Verification)
103+ # ==============================================================================
104+
105+ def test_basic_backwards (standard_grad , standard_input ):
106+ quantizer = None
107+
108+ # 1. dgelu
109+ grad_out = dgelu_torch (standard_grad , standard_input , quantizer )
110+ assert grad_out .shape == standard_input .shape
111+
112+ # 2. dgeglu
113+ assert dgeglu_torch (standard_grad [..., :2 ], standard_input , quantizer ).shape == standard_input .shape
114+
115+ # 3. dqgelu & dqgeglu
116+ assert dqgelu_torch (standard_grad , standard_input , quantizer ).shape == standard_input .shape
117+ assert dqgeglu_torch (standard_grad [..., :2 ], standard_input , quantizer ).shape == standard_input .shape
118+
119+ # 4. drelu & dreglu
120+ assert drelu_torch (standard_grad , standard_input , quantizer ).shape == standard_input .shape
121+ assert dreglu_torch (standard_grad [..., :2 ], standard_input , quantizer ).shape == standard_input .shape
122+
123+ # 5. dsrelu & dsreglu
124+ assert dsrelu_torch (standard_grad , standard_input , quantizer ).shape == standard_input .shape
125+ assert dsreglu_torch (standard_grad [..., :2 ], standard_input , quantizer ).shape == standard_input .shape
126+
127+ # 6. dsilu & dswiglu
128+ assert dsilu_torch (standard_grad , standard_input , quantizer ).shape == standard_input .shape
129+ assert dswiglu_torch (standard_grad [..., :2 ], standard_input , quantizer ).shape == standard_input .shape
130+
131+
132+ def test_clamped_dswiglu_backward_branches ():
133+ """Force execution of both (a <= limit) and (b outside/inside limit) gradient masks."""
134+ quantizer = None
135+ # Input designed to explicitly hit:
136+ # a > limit (row 0), a <= limit (row 1)
137+ # b > limit (row 0), b < -limit (row 1)
138+ fwd_in = torch .tensor ([[10.0 , 10.0 ], [0.0 , - 10.0 ]], dtype = torch .float32 )
139+ grad_in = torch .tensor ([[1.0 ], [1.0 ]], dtype = torch .float32 )
140+
141+ # Run out-of-bounds limit to force masks evaluated as False
142+ res_grad = clamped_dswiglu_torch (grad_in , fwd_in , quantizer , limit = 5.0 , alpha = 1.0 )
143+ assert res_grad .shape == fwd_in .shape
144+
145+ # Row 0, Col 0: a = 10.0 (> limit 5.0). Mask (a <= limit) is False -> grad_a should be 0.0
146+ assert res_grad [0 , 0 ].item () == 0.0
147+
148+
149+ # ==============================================================================
150+ # Part 3: Fused Bias Derivative Tests (dbias_* Variants)
151+ # ==============================================================================
152+
153+ @pytest .mark .parametrize (
154+ "dbias_fn" ,
155+ [
156+ dbias_dgelu_torch ,
157+ dbias_dsilu_torch ,
158+ dbias_drelu_torch ,
159+ dbias_dqgelu_torch ,
160+ dbias_dsrelu_torch ,
161+ ],
162+ )
163+ def test_dbias_functional_variants (dbias_fn , standard_grad , standard_input ):
164+ quantizer = None
165+ # Inject a 3D tensor to verify full dimensional summation along non-last axes
166+ inp_3d = torch .randn (2 , 3 , 4 )
167+ grad_3d = torch .randn (2 , 3 , 4 )
168+
169+ grad_input , grad_bias = dbias_fn (grad_3d , inp_3d , quantizer )
170+
171+ assert grad_input .shape == inp_3d .shape
172+ # Bias gradient must collapse all dimensions except the last one (Features dimension)
173+ assert grad_bias .shape == (4 ,)
174+ assert torch .allclose (grad_bias , grad_3d .sum (dim = (0 , 1 )))
0 commit comments