3939def _fused_linear_softsign_glu_fwd_kernel (
4040 x_ptr , w_left_ptr , w_right_ptr , b_left_ptr , b_right_ptr ,
4141 y_ptr , left_ptr , gate_ptr ,
42- M , K ,
42+ M , N , K ,
4343 stride_x_b , stride_x_k ,
4444 stride_wl_n , stride_wl_k ,
4545 stride_wr_n , stride_wr_k ,
@@ -50,13 +50,15 @@ def _fused_linear_softsign_glu_fwd_kernel(
5050):
5151 """
5252 y = (x @ W_left^T + b_left) * softsign(x @ W_right^T + b_right)
53- where softsign(x) = x / (1 + |x|).
5453
55- 2D grid over (M // BLOCK_M, K // BLOCK_N).
54+ N = output dim per GLU half (= inner_dim = dim × expansion_factor)
55+ K = input feature dim (= dim for first Linear, inner_dim for second)
56+
57+ 2D grid over (M // BLOCK_M, N // BLOCK_N).
5658 """
5759 pid = tl .program_id (0 )
5860 num_pid_m = tl .cdiv (M , BLOCK_M )
59- num_pid_n = tl .cdiv (K , BLOCK_N )
61+ num_pid_n = tl .cdiv (N , BLOCK_N )
6062 pid_m = pid // num_pid_n
6163 pid_n = pid % num_pid_n
6264
@@ -65,9 +67,9 @@ def _fused_linear_softsign_glu_fwd_kernel(
6567 offs_k = tl .arange (0 , BLOCK_K )
6668
6769 m_mask_2d = offs_m [:, None ] < M
68- n_mask_nk = offs_n [:, None ] < K # [BLOCK_N, 1] for N×K weight access
69- n_mask_mn = offs_n [None , :] < K # [1, BLOCK_N] for M×N output access
70- n_mask_1d = offs_n < K
70+ n_mask_nk = offs_n [:, None ] < N # [BLOCK_N, 1] for N×K weight access
71+ n_mask_mn = offs_n [None , :] < N # [1, BLOCK_N] for M×N output access
72+ n_mask_1d = offs_n < N
7173
7274 acc_left = tl .zeros ([BLOCK_M , BLOCK_N ], dtype = tl .float32 )
7375 acc_gate = tl .zeros ([BLOCK_M , BLOCK_N ], dtype = tl .float32 )
@@ -137,7 +139,7 @@ def _fused_linear_softsign_glu_bwd_kernel(
137139 left_ptr , gate_ptr , grad_y_ptr ,
138140 grad_x_ptr ,
139141 w_left_ptr , w_right_ptr ,
140- M , K ,
142+ M , K , N ,
141143 stride_l_b , stride_l_n ,
142144 stride_g_b , stride_g_n ,
143145 stride_gy_b , stride_gy_n ,
@@ -166,10 +168,10 @@ def _fused_linear_softsign_glu_bwd_kernel(
166168 k_mask_nk = offs_k [None , :] < K
167169 acc = tl .zeros ([BLOCK_M , BLOCK_K ], dtype = tl .float32 )
168170
169- for n_start in range (0 , K , BLOCK_N ):
171+ for n_start in range (0 , N , BLOCK_N ):
170172 n_offs = n_start + offs_n
171- n_mask_mn = n_offs [None , :] < K
172- n_mask_nk = n_offs [:, None ] < K
173+ n_mask_mn = n_offs [None , :] < N
174+ n_mask_nk = n_offs [:, None ] < N
173175
174176 left = tl .load (
175177 left_ptr + offs_m [:, None ] * stride_l_b + n_offs [None , :] * stride_l_n ,
@@ -278,24 +280,25 @@ class FusedLinearSoftSignGLUFn(torch.autograd.Function):
278280 @staticmethod
279281 def forward (ctx , x , weight , bias ):
280282 orig_shape = x .shape
281- K = weight .shape [1 ]
283+ K = weight .shape [1 ] # input feature dim (contraction dim)
284+ N = weight .shape [0 ] // 2 # output dim per GLU half
282285 x_2d = x .reshape (- 1 , K )
283286 M = x_2d .shape [0 ]
284287
285- w_left , w_right = weight .split (K , dim = 0 )
286- b_left , b_right = bias .split (K , dim = 0 )
288+ w_left , w_right = weight .split (N , dim = 0 )
289+ b_left , b_right = bias .split (N , dim = 0 )
287290
288- out = torch .empty (M , K , device = x .device , dtype = x .dtype )
289- left = torch .empty (M , K , device = x .device , dtype = x .dtype )
290- gate = torch .empty (M , K , device = x .device , dtype = x .dtype )
291+ out = torch .empty (M , N , device = x .device , dtype = x .dtype )
292+ left = torch .empty (M , N , device = x .device , dtype = x .dtype )
293+ gate = torch .empty (M , N , device = x .device , dtype = x .dtype )
291294
292295 def grid (meta ):
293- return (triton .cdiv (M , meta ['BLOCK_M' ]) * triton .cdiv (K , meta ['BLOCK_N' ]),)
296+ return (triton .cdiv (M , meta ['BLOCK_M' ]) * triton .cdiv (N , meta ['BLOCK_N' ]),)
294297
295298 _fused_linear_softsign_glu_fwd_kernel [grid ](
296299 x_2d , w_left , w_right , b_left , b_right ,
297300 out , left , gate ,
298- M , K ,
301+ M , N , K ,
299302 x_2d .stride (0 ), x_2d .stride (1 ),
300303 w_left .stride (0 ), w_left .stride (1 ),
301304 w_right .stride (0 ), w_right .stride (1 ),
@@ -305,34 +308,36 @@ def grid(meta):
305308 )
306309
307310 if x .dim () > 2 :
308- out = out .view (* orig_shape [:- 1 ], K )
309- left = left .view (M , K )
310- gate = gate .view (M , K )
311+ out = out .view (* orig_shape [:- 1 ], N )
312+ left = left .view (M , N )
313+ gate = gate .view (M , N )
311314
312315 ctx .save_for_backward (x_2d , weight , left , gate )
313316 ctx .orig_x_shape = orig_shape
317+ ctx .N = N
314318 return out
315319
316320 @staticmethod
317321 def backward (ctx , grad_y ):
318322 x , weight , left , gate = ctx .saved_tensors
319323 M , K = x .shape
320- w_left , w_right = weight .split (K , dim = 0 )
324+ N = ctx .N
325+ w_left , w_right = weight .split (N , dim = 0 )
321326
322327 if grad_y .dim () > 2 :
323- grad_y = grad_y .reshape (- 1 , K )
328+ grad_y = grad_y .reshape (- 1 , N )
324329
325330 # Step 1: Fused element-wise SoftSignGLU backward
326- grad_left_pre = torch .empty (M , K , device = x .device , dtype = x .dtype )
327- grad_gate = torch .empty (M , K , device = x .device , dtype = x .dtype )
331+ grad_left_pre = torch .empty (M , N , device = x .device , dtype = x .dtype )
332+ grad_gate = torch .empty (M , N , device = x .device , dtype = x .dtype )
328333
329334 def elem_grid (meta ):
330- return (triton .cdiv (M , meta ['BLOCK_M' ]) * triton .cdiv (K , meta ['BLOCK_K' ]),)
335+ return (triton .cdiv (M , meta ['BLOCK_M' ]) * triton .cdiv (N , meta ['BLOCK_K' ]),)
331336
332337 _softsign_glu_bwd_elem_kernel [elem_grid ](
333338 left , gate , grad_y ,
334339 grad_left_pre , grad_gate ,
335- M , K ,
340+ M , N , N ,
336341 left .stride (0 ), left .stride (1 ),
337342 gate .stride (0 ), gate .stride (1 ),
338343 grad_y .stride (0 ), grad_y .stride (1 ),
@@ -356,7 +361,7 @@ def bwd_grid(meta):
356361 left , gate , grad_y ,
357362 grad_x ,
358363 w_left , w_right ,
359- M , K ,
364+ M , K , N ,
360365 left .stride (0 ), left .stride (1 ),
361366 gate .stride (0 ), gate .stride (1 ),
362367 grad_y .stride (0 ), grad_y .stride (1 ),
@@ -376,20 +381,22 @@ def bwd_grid(meta):
376381# ---------------------------------------------------------------------------
377382
378383def fused_linear_softsign_glu (x , weight , bias ):
379- """Fused Linear(2K, K ) + SoftSignGLU.
384+ """Fused Linear(C, 2*C ) + SoftSignGLU, where C = dim (expansion_factor×dim) .
380385
381386 y = left * gate / (1 + |gate|)
382387
388+ Supports expansion_factor != 1 by splitting weight at midpoint.
389+
383390 Args:
384- x: Input [..., K]
385- weight: [2*K , K]
386- bias: [2*K ]
391+ x: Input [..., K] where K = weight.shape[1] (input dim)
392+ weight: [2*N , K] where N = output dim per GLU half (= K × expansion_factor)
393+ bias: [2*N ]
387394
388395 Returns:
389- [..., K ]
396+ [..., N ]
390397 """
391- assert weight .shape [0 ] == 2 * weight . shape [ 1 ], \
392- f"Expected [2*K, K], got { weight .shape } "
398+ N = weight .shape [0 ] // 2
399+ K = weight .shape [ 1 ]
393400 # Match weight/bias dtype to input (handles 16-mixed precision where
394401 # weights are fp32 but activations are autocast to fp16)
395402 if weight .dtype != x .dtype :
0 commit comments