@@ -182,60 +182,61 @@ def _layer_norm_fwd_1pass_kernel_npu(
182182 if HAS_BIAS :
183183 B += group * N
184184
185- # Compute row indices for this program
186- rows = pid_m * BLOCK_M + tl .arange (0 , BLOCK_M )
185+ # Load weight once (broadcasted over rows)
187186 cols = tl .arange (0 , BLOCK_N )
188-
189- # Mask for valid rows and cols
190- row_mask = rows < M
191187 col_mask = cols < N
192-
193- # Load weight once (broadcasted over rows)
194188 w = tl .load (W + cols , mask = col_mask ).to (tl .float32 )
195189 if HAS_BIAS :
196190 b = tl .load (B + cols , mask = col_mask ).to (tl .float32 )
197191
198- # Load X: shape [BLOCK_M, BLOCK_N]
199- x_ptrs = X + rows [:, None ] * stride_x_row + cols [None , :] + group * N
200- x = tl .load (x_ptrs , mask = row_mask [:, None ] & col_mask [None , :]).to (tl .float32 )
192+ for row_block_start in tl .range (pid_m * BLOCK_M , M , BLOCK_M * tl .num_programs (0 )):
193+ # Compute row indices for this program
194+ rows = row_block_start + tl .arange (0 , BLOCK_M )
195+ row_mask = rows < M
201196
202- # Load Z if needed
203- if HAS_Z :
204- z_ptrs = Z + rows [:, None ] * stride_z_row + cols [None , :] + group * N
205- z = tl .load (z_ptrs , mask = row_mask [:, None ] & col_mask [None , :]).to (tl .float32 )
206- if not NORM_BEFORE_GATE :
207- x *= z * tl .sigmoid (z )
197+ # Load X: shape [BLOCK_M, BLOCK_N]
198+ x_ptrs = X + rows [:, None ] * stride_x_row + cols [None , :] + group * N
199+ x = tl .load (x_ptrs , mask = row_mask [:, None ] & col_mask [None , :]).to (tl .float32 )
208200
209- # Compute statistics per row
210- if not IS_RMS_NORM :
211- mean = tl .sum (x , axis = 1 ) / N # [BLOCK_M]
212- xbar = tl .where (col_mask [None , :], x - mean [:, None ], 0.0 )
213- var = tl .sum (xbar * xbar , axis = 1 ) / N
214- tl .store (Mean + rows , mean , mask = row_mask )
215- else :
216- xbar = tl .where (col_mask [None , :], x , 0.0 )
217- var = tl .sum (xbar * xbar , axis = 1 ) / N
201+ # Load Z if needed
202+ if HAS_Z :
203+ z_ptrs = Z + rows [:, None ] * stride_z_row + cols [None , :] + group * N
204+ z = tl .load (z_ptrs , mask = row_mask [:, None ] & col_mask [None , :]).to (
205+ tl .float32
206+ )
207+ if not NORM_BEFORE_GATE :
208+ x *= z * tl .sigmoid (z )
209+
210+ # Compute statistics per row
211+ if not IS_RMS_NORM :
212+ mean = tl .sum (x , axis = 1 ) / N # [BLOCK_M]
213+ xbar = tl .where (col_mask [None , :], x - mean [:, None ], 0.0 )
214+ var = tl .sum (xbar * xbar , axis = 1 ) / N
215+ tl .store (Mean + rows , mean , mask = row_mask )
216+ else :
217+ xbar = tl .where (col_mask [None , :], x , 0.0 )
218+ var = tl .sum (xbar * xbar , axis = 1 ) / N
218219
219- rstd = 1.0 / tl .sqrt (var + eps ) # [BLOCK_M]
220- tl .store (Rstd + rows , rstd , mask = row_mask )
220+ rstd = 1.0 / tl .sqrt (var + eps ) # [BLOCK_M]
221+ tl .store (Rstd + rows , rstd , mask = row_mask )
221222
222- # Normalize
223- if not IS_RMS_NORM :
224- x_hat = (x - mean [:, None ]) * rstd [:, None ]
225- else :
226- x_hat = x * rstd [:, None ]
223+ # Normalize
224+ if not IS_RMS_NORM :
225+ x_hat = (x - mean [:, None ]) * rstd [:, None ]
226+ else :
227+ x_hat = x * rstd [:, None ]
227228
228- y = x_hat * w [None , :]
229- if HAS_BIAS :
230- y += b [None , :]
229+ y = x_hat * w [None , :]
230+ if HAS_BIAS :
231+ y += b [None , :]
231232
232- # Post-gate
233- if HAS_Z and NORM_BEFORE_GATE :
234- y *= z * tl .sigmoid (z )
233+ # Post-gate
234+ if HAS_Z and NORM_BEFORE_GATE :
235+ y *= z * tl .sigmoid (z )
235236
236- # Store output
237- y_ptrs = Y + rows [:, None ] * stride_y_row + cols [None , :] + group * N
238- tl .store (y_ptrs , y , mask = row_mask [:, None ] & col_mask [None , :])
237+ # Store output
238+ y_ptrs = Y + rows [:, None ] * stride_y_row + cols [None , :] + group * N
239+ tl .store (y_ptrs , y , mask = row_mask [:, None ] & col_mask [None , :])
239240
240241
241242def layer_norm_fwd_npu (
@@ -284,10 +285,12 @@ def layer_norm_fwd_npu(
284285 raise RuntimeError ("Feature dim too large." )
285286
286287 # Choose BLOCK_M: e.g., 16, 32, 64 — depends on NPU vector core capacity
287- BLOCK_M = 64 # Tune this based on your NPU's register/shared memory
288+ BLOCK_M = 48
289+ _ , num_vectorcore = get_device_properties ()
290+ num_blocks_m = min (triton .cdiv (M , BLOCK_M ), num_vectorcore )
288291
289292 # Now grid is (num blocks over M, num groups)
290- grid = (triton . cdiv ( M , BLOCK_M ) , ngroups )
293+ grid = (num_blocks_m , ngroups )
291294 _layer_norm_fwd_1pass_kernel_npu [grid ](
292295 x ,
293296 out ,
0 commit comments