Skip to content

Commit f122f34

Browse files
yzw1128claude
andcommitted
[KernelGen][Ascend] Add gemma_rms_norm operator with Triton kernel for Ascend
Add Ascend-optimized Gemma RMSNorm Triton kernel implementation under the _ascend backend ops directory. The implementation provides: - _gemma_rmsnorm_kernel: standard RMSNorm with (1 + w) scaling - _gemma_fused_add_rmsnorm_kernel: fused residual-add + RMSNorm - gemma_rms_norm: unified entry point matching the existing tensor-based API (x, weight, eps, residual) Co-Authored-By: Claude <noreply@anthropic.com>
1 parent 4700b12 commit f122f34

3 files changed

Lines changed: 172 additions & 0 deletions

File tree

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
from flaggems_sglang.runtime.backend.backend_utils import VendorInfoBase
2+
3+
vendor_info = VendorInfoBase(
4+
vendor_name="ascend",
5+
device_name="npu",
6+
device_query_cmd="npu-smi info",
7+
dispatch_key="PrivateUse1",
8+
)
9+
10+
CUSTOMIZED_UNUSED_OPS = ()
11+
12+
__all__ = ["*"]
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
from flaggems_sglang.runtime.backend._ascend.ops.gemma_rms_norm import gemma_rms_norm
2+
3+
__all__ = [
4+
"gemma_rms_norm",
5+
]
Lines changed: 155 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,155 @@
1+
"""Gemma RMSNorm Triton kernel optimized for Ascend NPU.
2+
3+
Provides gemma_rms_norm(x, weight, eps, residual) with two kernels:
4+
- _gemma_rmsnorm_kernel: standard RMSNorm with (1 + w) scaling
5+
- _gemma_fused_add_rmsnorm_kernel: fused residual-add + RMSNorm
6+
"""
7+
8+
import torch
9+
import triton
10+
import triton.language as tl
11+
12+
13+
@triton.jit
14+
def _gemma_rmsnorm_kernel(
15+
X_ptr,
16+
W_ptr,
17+
Out_ptr,
18+
stride_x_row,
19+
stride_out_row,
20+
N,
21+
eps,
22+
BLOCK_N: tl.constexpr,
23+
):
24+
row_idx = tl.program_id(0)
25+
x_row_ptr = X_ptr + row_idx * stride_x_row
26+
out_row_ptr = Out_ptr + row_idx * stride_out_row
27+
28+
cols = tl.arange(0, BLOCK_N)
29+
mask = cols < N
30+
31+
x = tl.load(x_row_ptr + cols, mask=mask, other=0.0).to(tl.float32)
32+
w = tl.load(W_ptr + cols, mask=mask, other=0.0).to(tl.float32)
33+
34+
mean_sq = tl.sum(x * x, axis=0) / N
35+
rrms = tl.rsqrt(mean_sq + eps)
36+
37+
out = x * rrms * (1.0 + w)
38+
39+
tl.store(out_row_ptr + cols, out.to(tl.load(x_row_ptr + cols, mask=mask).dtype), mask=mask)
40+
41+
42+
@triton.jit
43+
def _gemma_fused_add_rmsnorm_kernel(
44+
X_ptr,
45+
Residual_ptr,
46+
W_ptr,
47+
Out_ptr,
48+
ResidualOut_ptr,
49+
stride_x_row,
50+
stride_res_row,
51+
stride_out_row,
52+
stride_resout_row,
53+
N,
54+
eps,
55+
BLOCK_N: tl.constexpr,
56+
):
57+
row_idx = tl.program_id(0)
58+
x_row_ptr = X_ptr + row_idx * stride_x_row
59+
res_row_ptr = Residual_ptr + row_idx * stride_res_row
60+
out_row_ptr = Out_ptr + row_idx * stride_out_row
61+
resout_row_ptr = ResidualOut_ptr + row_idx * stride_resout_row
62+
63+
cols = tl.arange(0, BLOCK_N)
64+
mask = cols < N
65+
66+
x = tl.load(x_row_ptr + cols, mask=mask, other=0.0).to(tl.float32)
67+
residual = tl.load(res_row_ptr + cols, mask=mask, other=0.0).to(tl.float32)
68+
w = tl.load(W_ptr + cols, mask=mask, other=0.0).to(tl.float32)
69+
70+
hidden = x + residual
71+
72+
orig_dtype = tl.load(x_row_ptr + cols, mask=mask).dtype
73+
tl.store(resout_row_ptr + cols, hidden.to(orig_dtype), mask=mask)
74+
75+
mean_sq = tl.sum(hidden * hidden, axis=0) / N
76+
rrms = tl.rsqrt(mean_sq + eps)
77+
78+
out = hidden * rrms * (1.0 + w)
79+
80+
tl.store(out_row_ptr + cols, out.to(orig_dtype), mask=mask)
81+
82+
83+
def _next_power_of_2(n):
84+
n -= 1
85+
n |= n >> 1
86+
n |= n >> 2
87+
n |= n >> 4
88+
n |= n >> 8
89+
n |= n >> 16
90+
n += 1
91+
return n
92+
93+
94+
def gemma_rmsnorm(x: torch.Tensor, weight: torch.Tensor, eps: float = 1e-6) -> torch.Tensor:
95+
if not x.is_contiguous():
96+
x = x.contiguous()
97+
orig_shape = x.shape
98+
if x.dim() != 2:
99+
x = x.reshape(-1, orig_shape[-1])
100+
101+
M, N = x.shape
102+
out = torch.empty_like(x)
103+
BLOCK_N = _next_power_of_2(N)
104+
105+
_gemma_rmsnorm_kernel[(M,)](
106+
x, weight, out,
107+
x.stride(0), out.stride(0),
108+
N, eps,
109+
BLOCK_N=BLOCK_N,
110+
)
111+
112+
if len(orig_shape) != 2:
113+
out = out.reshape(orig_shape)
114+
return out
115+
116+
117+
def gemma_fused_add_rmsnorm(
118+
x: torch.Tensor,
119+
residual: torch.Tensor,
120+
weight: torch.Tensor,
121+
eps: float = 1e-6,
122+
) -> tuple[torch.Tensor, torch.Tensor]:
123+
if not x.is_contiguous():
124+
x = x.contiguous()
125+
if not residual.is_contiguous():
126+
residual = residual.contiguous()
127+
assert x.shape == residual.shape
128+
129+
orig_shape = x.shape
130+
if x.dim() != 2:
131+
x = x.reshape(-1, orig_shape[-1])
132+
residual = residual.reshape(-1, orig_shape[-1])
133+
134+
M, N = x.shape
135+
out = torch.empty_like(x)
136+
residual_out = torch.empty_like(x)
137+
BLOCK_N = _next_power_of_2(N)
138+
139+
_gemma_fused_add_rmsnorm_kernel[(M,)](
140+
x, residual, weight, out, residual_out,
141+
x.stride(0), residual.stride(0), out.stride(0), residual_out.stride(0),
142+
N, eps,
143+
BLOCK_N=BLOCK_N,
144+
)
145+
146+
if len(orig_shape) != 2:
147+
out = out.reshape(orig_shape)
148+
residual_out = residual_out.reshape(orig_shape)
149+
return out, residual_out
150+
151+
152+
def gemma_rms_norm(x, weight, eps=1e-6, residual=None):
153+
if residual is not None:
154+
return gemma_fused_add_rmsnorm(x, residual, weight, eps)
155+
return gemma_rmsnorm(x, weight, eps)

0 commit comments

Comments
 (0)