Skip to content

Commit 4022cdd

Browse files
Flink-dddEthanZero2Hero
authored andcommitted
Merge branch 'main' into feat/issue-145
2 parents f9a9779 + 063a261 commit 4022cdd

13 files changed

Lines changed: 311 additions & 648 deletions

File tree

‎benchmarks/benchmark_rmsnorm.py‎

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,15 @@
33

44
import torch
55

6-
from rl_engine.kernels.ops.pytorch.norm.rmsnorm_ref import rmsnorm_ref_custom
6+
from rl_engine.kernels.ops.pytorch.norm.rms_norm import NativeRMSNormOp
77
from rl_engine.kernels.ops.triton.rmsnorm_triton import rmsnorm_triton
88

99
try:
10+
from rl_engine.kernels.ops.base import _C, _EXT_AVAILABLE
1011
from rl_engine.kernels.ops.cuda.norm.rmsnorm import rmsnorm_cuda
1112

12-
HAS_CUDA_EXT = True
13-
except Exception:
13+
HAS_CUDA_EXT = _EXT_AVAILABLE and hasattr(_C, "rmsnorm_forward")
14+
except ImportError:
1415
HAS_CUDA_EXT = False
1516

1617

@@ -54,8 +55,10 @@ def make_inputs():
5455
w_base.detach().clone().requires_grad_(True),
5556
)
5657

58+
native = NativeRMSNormOp()
59+
5760
x, w = make_inputs()
58-
t_ref = bench(lambda a, b: rmsnorm_ref_custom(a, b), x, w, dy)
61+
t_ref = bench(lambda a, b: native.forward(a, b), x, w, dy)
5962
print(f"pytorch ref : {t_ref:.4f} ms")
6063

6164
x, w = make_inputs()

‎ci/run_gpu_ci.sh‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -186,7 +186,7 @@ TORCH_INDEX_URL="${TORCH_INDEX_URL:-https://download.pytorch.org/whl/cu124}"
186186
# --no-build-isolation: torch must be visible to setup.py, else the extension is silently skipped.
187187
# --no-deps: keep the pinned torch; do not let the editable install re-resolve it.
188188
"$PY" -m pip install --no-build-isolation --no-deps -e .
189-
"$PY" -m pip install --no-cache-dir numpy tabulate accelerate transformers pytest
189+
"$PY" -m pip install --no-cache-dir numpy tabulate accelerate "transformers==5.13.1" pytest
190190
nvidia-smi
191191
# Fail fast if _C did not build or cannot launch, instead of silently using native fallbacks.
192192
"$PY" scripts/ci_smoke.py

‎csrc/cuda/rmsnorm.cu‎

Lines changed: 38 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,9 @@ static int choose_threads(int H) {
6666
return 512;
6767
}
6868

69+
constexpr int RMSNORM_DW_ROWS_PER_CHUNK = 256;
70+
constexpr int RMSNORM_DW_H_TILE = 128;
71+
6972

7073
template <typename scalar_t, typename weight_t>
7174
__global__ void rmsnorm_fwd_kernel(
@@ -164,46 +167,48 @@ __global__ void rmsnorm_partial_dw_kernel(
164167
int T,
165168
int H
166169
) {
167-
int idx = blockIdx.x * blockDim.x + threadIdx.x;
168-
int total = T * H;
169-
170-
if (idx >= total) return;
171-
172-
int row = idx / H;
173-
174-
if (!mask[row]) {
175-
partial_dw[idx] = 0.0f;
170+
int chunk = blockIdx.x;
171+
int h = blockIdx.y * RMSNORM_DW_H_TILE + threadIdx.x;
172+
if (h >= H) {
176173
return;
177174
}
178175

179-
float dyv = load_as_float<scalar_t>(dy + idx);
180-
float xv = load_as_float<scalar_t>(x + idx);
181-
float r = rstd[row];
176+
int t0 = chunk * RMSNORM_DW_ROWS_PER_CHUNK;
177+
float acc = 0.0f;
178+
179+
#pragma unroll
180+
for (int i = 0; i < RMSNORM_DW_ROWS_PER_CHUNK; ++i) {
181+
int row = t0 + i;
182+
float contrib = 0.0f;
183+
if (row < T && mask[row]) {
184+
int idx = row * H + h;
185+
float dyv = load_as_float<scalar_t>(dy + idx);
186+
float xv = load_as_float<scalar_t>(x + idx);
187+
contrib = dyv * xv * rstd[row];
188+
}
189+
acc += contrib;
190+
}
182191

183-
partial_dw[idx] = dyv * xv * r;
192+
partial_dw[chunk * H + h] = acc;
184193
}
185194

186195

187196
__global__ void rmsnorm_reduce_dw_kernel(
188197
const float* __restrict__ partial_dw,
189198
float* __restrict__ dw,
190-
int T,
199+
int chunks,
191200
int H
192201
) {
193-
int h = blockIdx.x;
194-
int tid = threadIdx.x;
195-
196-
float local_sum = 0.0f;
197-
198-
for (int t = tid; t < T; t += blockDim.x) {
199-
local_sum += partial_dw[t * H + h];
202+
int h = blockIdx.x * RMSNORM_DW_H_TILE + threadIdx.x;
203+
if (h >= H) {
204+
return;
200205
}
201206

202-
float sum = block_reduce_sum(local_sum);
203-
204-
if (tid == 0) {
205-
dw[h] = sum;
207+
float acc = 0.0f;
208+
for (int chunk = 0; chunk < chunks; ++chunk) {
209+
acc += partial_dw[chunk * H + h];
206210
}
211+
dw[h] = acc;
207212
}
208213

209214

@@ -280,10 +285,10 @@ void rmsnorm_backward_partial_dw_cuda(
280285
) {
281286
int T = x.size(0);
282287
int H = x.size(1);
283-
int total = T * H;
284288

285-
int threads = 256;
286-
int blocks = (total + threads - 1) / threads;
289+
int chunks = (T + RMSNORM_DW_ROWS_PER_CHUNK - 1) / RMSNORM_DW_ROWS_PER_CHUNK;
290+
dim3 blocks(chunks, (H + RMSNORM_DW_H_TILE - 1) / RMSNORM_DW_H_TILE);
291+
dim3 threads(RMSNORM_DW_H_TILE);
287292

288293
cudaStream_t stream = at::cuda::getCurrentCUDAStream();
289294

@@ -305,18 +310,18 @@ void rmsnorm_backward_reduce_dw_cuda(
305310
torch::Tensor partial_dw,
306311
torch::Tensor dw
307312
) {
308-
int T = partial_dw.size(0);
313+
int chunks = partial_dw.size(0);
309314
int H = partial_dw.size(1);
310315

311-
int threads = choose_threads(T);
312-
size_t smem = threads * sizeof(float);
316+
dim3 blocks((H + RMSNORM_DW_H_TILE - 1) / RMSNORM_DW_H_TILE);
317+
dim3 threads(RMSNORM_DW_H_TILE);
313318

314319
cudaStream_t stream = at::cuda::getCurrentCUDAStream();
315320

316-
rmsnorm_reduce_dw_kernel<<<H, threads, smem, stream>>>(
321+
rmsnorm_reduce_dw_kernel<<<blocks, threads, 0, stream>>>(
317322
partial_dw.data_ptr<float>(),
318323
dw.data_ptr<float>(),
319-
T,
324+
chunks,
320325
H
321326
);
322327
}

‎csrc/ops.cpp‎

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,8 @@ torch::Tensor deterministic_logp_forward_indexed_fp32(torch::Tensor logits, torc
7777

7878
// RMSNorm Declarations & Wrappers
7979

80+
constexpr int RMSNORM_DW_ROWS_PER_CHUNK = 256;
81+
8082
void rmsnorm_forward_cuda(
8183
torch::Tensor x,
8284
torch::Tensor weight,
@@ -173,8 +175,9 @@ torch::Tensor rmsnorm_backward_dw(
173175

174176
auto T = x.size(0);
175177
auto H = x.size(1);
178+
auto chunks = (T + RMSNORM_DW_ROWS_PER_CHUNK - 1) / RMSNORM_DW_ROWS_PER_CHUNK;
176179

177-
auto partial_dw = torch::empty({T, H}, x.options().dtype(torch::kFloat32));
180+
auto partial_dw = torch::empty({chunks, H}, x.options().dtype(torch::kFloat32));
178181
auto dw = torch::empty({H}, x.options().dtype(torch::kFloat32));
179182

180183
rmsnorm_backward_partial_dw_cuda(dy, x, rstd, mask, partial_dw);

‎pyproject.toml‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ dependencies = [
1717
"tabulate",
1818
"numpy",
1919
"accelerate",
20-
"transformers",
20+
"transformers==5.13.1",
2121
]
2222

2323
[project.optional-dependencies]

‎rl_engine/kernels/gtest/operator_specs.py‎

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,19 @@ def _load_object(path: str) -> Any:
3232

3333

3434
OP_SPECS = {
35+
"rms_norm": OperatorSpec(
36+
name="rms_norm",
37+
op_class="reduction",
38+
gold_path="rl_engine.kernels.ops.pytorch.norm.rms_norm.NativeRMSNormOp",
39+
gold_method="forward_fp32",
40+
candidate_paths={
41+
"pytorch": "rl_engine.kernels.ops.pytorch.norm.rms_norm.NativeRMSNormOp",
42+
"triton": "rl_engine.kernels.ops.triton.rmsnorm_triton.RMSNormTritonOp",
43+
"cuda": "rl_engine.kernels.ops.cuda.norm.rmsnorm.RMSNormCudaOp",
44+
"cuda-sm90": "rl_engine.kernels.ops.cuda.norm.rmsnorm.RMSNormCudaOp",
45+
},
46+
grad_input_names=("x", "weight"),
47+
),
3548
"logp": OperatorSpec(
3649
name="logp",
3750
op_class="logprob",

‎rl_engine/kernels/ops/cuda/norm/rmsnorm.py‎

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,3 +74,16 @@ def rmsnorm_cuda(x, weight, eps=1e-6, mask=None):
7474
y = rmsnorm_cuda(x, weight, mask=mask)
7575
"""
7676
return RMSNormCuda.apply(x, weight, mask, eps)
77+
78+
79+
class RMSNormCudaOp:
80+
"""CUDA RMSNorm wrapper compatible with the shared operator harness."""
81+
82+
def __call__(self, x, weight, *, eps=1e-6):
83+
return self.forward(x, weight, eps=eps)
84+
85+
def forward(self, x, weight, *, eps=1e-6):
86+
hidden = x.shape[-1]
87+
x_2d = x.contiguous().view(-1, hidden)
88+
y_2d = rmsnorm_cuda(x_2d, weight.contiguous(), eps=eps)
89+
return y_2d.view_as(x)

‎rl_engine/kernels/ops/pytorch/norm/rmsnorm_native.py‎

Lines changed: 0 additions & 63 deletions
This file was deleted.

‎rl_engine/kernels/ops/pytorch/norm/rmsnorm_ref.py‎

Lines changed: 0 additions & 56 deletions
This file was deleted.

‎rl_engine/kernels/ops/triton/rmsnorm_triton.py‎

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,3 +96,16 @@ def backward(ctx, grad_out):
9696

9797
def rmsnorm_triton(x, weight, eps: float = 1e-6):
9898
return RMSNormTriton.apply(x, weight, eps)
99+
100+
101+
class RMSNormTritonOp:
102+
"""Triton RMSNorm wrapper compatible with the shared operator harness."""
103+
104+
def __call__(self, x, weight, *, eps: float = 1e-6):
105+
return self.forward(x, weight, eps=eps)
106+
107+
def forward(self, x, weight, *, eps: float = 1e-6):
108+
hidden = x.shape[-1]
109+
x_2d = x.contiguous().view(-1, hidden)
110+
y_2d = rmsnorm_triton(x_2d, weight.contiguous(), eps=eps)
111+
return y_2d.view_as(x)

0 commit comments

Comments
 (0)