From 4f3ce8e1921af2224a98378a4dadb2be373b4bbb Mon Sep 17 00:00:00 2001 From: bjf-frz Date: Tue, 3 Nov 2026 03:53:39 +0000 Subject: [PATCH 1/2] feat(kernels): add Ouro-compatible fused RMSNorm --- benchmarks/kernels/rms_norm.py | 193 ++++++++++ csrc/normalization/rms_norm.cu | 575 ++++++++++++++++++++++++++++++ csrc/ops.h | 2 + csrc/torch_bindings.cpp | 2 + docs/kernels.md | 69 +++- setup.py | 1 + tests/test_normalization.py | 260 ++++++++++++++ vllm_rlt/kernels/__init__.py | 3 +- vllm_rlt/kernels/normalization.py | 109 ++++++ vllm_rlt/layers/normalization.py | 12 +- vllm_rlt/models/ouro.py | 22 +- 11 files changed, 1235 insertions(+), 13 deletions(-) create mode 100644 benchmarks/kernels/rms_norm.py create mode 100644 csrc/normalization/rms_norm.cu create mode 100644 vllm_rlt/kernels/normalization.py diff --git a/benchmarks/kernels/rms_norm.py b/benchmarks/kernels/rms_norm.py new file mode 100644 index 00000000..9b366bc7 --- /dev/null +++ b/benchmarks/kernels/rms_norm.py @@ -0,0 +1,193 @@ +"""Matched RMSNorm / RMSNorm-then-residual accuracy and latency comparison. + +The optional vLLM library must expose the source-built ``vllm_rms_review`` +namespace. Its RMSNorm multiplication rounds differently from Ouro, so its +error against the staged reference is reported separately from its latency. +""" + +import argparse +import hashlib +import json +import os +import subprocess +from pathlib import Path + +import torch + +from benchmarks.kernels.silu_and_mul import errors, measure, profile +from vllm_rlt.kernels._extension import load_extension +from vllm_rlt.kernels.normalization import _torch_order_validated, rms_norm, rms_norm_reference + + +def oracle(x, weight, epsilon, residual): + value = x.double() + normalized = (value * torch.rsqrt(value.square().mean(-1, keepdim=True) + epsilon)).to(x.dtype) + result = (normalized.double() * weight.double()).to(x.dtype) + return result if residual is None else (residual.double() + result.double()).to(x.dtype) + + +def main(): + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument("--output", type=Path, required=True) + parser.add_argument("--vllm-library", type=Path) + parser.add_argument("--vllm-namespace", default="vllm_rms_review") + parser.add_argument( + "--vllm-source-commit", help="Source revision used to build the vLLM library" + ) + parser.add_argument("--tokens", default="1,2,4,8,16,32,64,128,256,1024") + parser.add_argument("--widths", default="128,768,2048,2049,4096") + parser.add_argument("--dtypes", default="bfloat16,float16,float32") + parser.add_argument("--repeats", type=int, default=3) + parser.add_argument("--iterations", type=int, default=30) + parser.add_argument("--profile-dir", type=Path) + args = parser.parse_args() + load_extension() + vllm_op = None + if args.vllm_library is not None: + torch.ops.load_library(str(args.vllm_library.resolve())) + vllm_op = getattr(getattr(torch.ops, args.vllm_namespace), "rms_norm") + torch.manual_seed(42) + torch.set_num_threads(1) + patch = subprocess.check_output(["git", "diff", "HEAD", "--binary"]) + # New kernels often have not been added to the Git index yet. Include their + # complete contents rather than recording a misleading, incomplete hash. + untracked = subprocess.check_output( + ["git", "ls-files", "--others", "--exclude-standard", "-z"] + ).split(b"\0") + for path in filter(None, untracked): + diff = subprocess.run( + ["git", "diff", "--no-index", "--binary", "--", "/dev/null", os.fsdecode(path)], + capture_output=True, + check=False, + ) + if diff.returncode not in (0, 1): + raise RuntimeError(diff.stderr.decode(errors="replace")) + patch += diff.stdout + args.output.parent.mkdir(parents=True, exist_ok=True) + args.output.with_suffix(".patch").write_bytes(patch) + report = { + "torch": torch.__version__, + "cuda": torch.version.cuda, + "gpu": torch.cuda.get_device_name(), + "capability": torch.cuda.get_device_capability(), + "torch_order_native_validated": _torch_order_validated(torch.cuda.current_device()), + "git_head": subprocess.check_output(["git", "rev-parse", "HEAD"], text=True).strip(), + "diff_sha256": hashlib.sha256(patch).hexdigest(), + "vllm_library": str(args.vllm_library.resolve()) if args.vllm_library else None, + "vllm_library_sha256": ( + hashlib.sha256(args.vllm_library.read_bytes()).hexdigest() + if args.vllm_library + else None + ), + "vllm_source_commit": args.vllm_source_commit, + "seed": 42, + "epsilon": 1e-6, + "repeats": args.repeats, + "iterations": args.iterations, + "graph_unroll": 32, + "device_status_before": subprocess.check_output( + [ + "nvidia-smi", + "--query-gpu=index,memory.used,utilization.gpu,clocks.sm", + "--format=csv", + ], + text=True, + ), + "rows": [], + } + args.output.write_text(json.dumps(report, indent=2)) + with torch.inference_mode(): + for dtype_name in args.dtypes.split(","): + dtype = getattr(torch, dtype_name) + for width in map(int, args.widths.split(",")): + for tokens in map(int, args.tokens.split(",")): + x = torch.randn(tokens, width, dtype=dtype, device="cuda") + residual = torch.randn_like(x) + weight = (torch.randn(width, device="cuda") * 0.1 + 1).to(dtype) + + def vllm(): + output = torch.empty(x.shape, device=x.device, dtype=x.dtype) + vllm_op(output, x, weight, 1e-6) + return output + + for add in (False, True): + res = residual if add else None + funcs = { + "torch": lambda: rms_norm_reference(x, weight, 1e-6, res), + "rlt_fused": lambda: rms_norm(x, weight, 1e-6, res), + } + if vllm_op is not None: + funcs["vllm"] = (lambda: vllm() + residual) if add else vllm + if ( + report["torch_order_native_validated"] + and width == 2048 + and dtype in (torch.float16, torch.bfloat16) + ): + funcs["rlt_torch_order"] = lambda: rms_norm( + x, weight, 1e-6, res, match_torch=True + ) + if add: + funcs["rlt_separate"] = lambda: rms_norm(x, weight, 1e-6) + residual + if "rlt_torch_order" in funcs: + funcs["rlt_torch_order_separate"] = ( + lambda: rms_norm(x, weight, 1e-6, match_torch=True) + residual + ) + ref = funcs["torch"]() + exact = oracle(x, weight, 1e-6, res) + accuracy = {} + for name, fn in funcs.items(): + result = fn() + accuracy[name] = { + "vs_ouro": errors(result, ref), + "vs_fp64_staged": errors(result, exact), + } + row = { + "dtype": dtype_name, + "tokens": tokens, + "width": width, + "residual": add, + "accuracy": accuracy, + "timing": measure(funcs, args.repeats, args.iterations), + } + report["rows"].append(row) + args.output.write_text(json.dumps(report, indent=2)) + print( + dtype_name, + width, + tokens, + "add" if add else "norm", + {k: round(v["graph_median_us"], 3) for k, v in row["timing"].items()}, + flush=True, + ) + del x, residual, weight, result, ref, exact, funcs + if args.profile_dir: + x = torch.randn(128, 2048, device="cuda", dtype=torch.bfloat16) + weight = torch.ones(2048, device="cuda", dtype=x.dtype) + residual = torch.randn_like(x) + + def vllm_profile(): + output = torch.empty_like(x) + vllm_op(output, x, weight, 1e-6) + return output + residual + + functions = { + "torch_norm_add": lambda: rms_norm_reference(x, weight, 1e-6, residual), + "rlt_norm_add": lambda: rms_norm(x, weight, 1e-6, residual), + } + if vllm_op is not None: + functions["vllm_norm_add"] = vllm_profile + if report["torch_order_native_validated"]: + functions["rlt_torch_order_norm_add"] = lambda: rms_norm( + x, weight, 1e-6, residual, match_torch=True + ) + profile(functions, args.profile_dir) + report["device_status_after"] = subprocess.check_output( + ["nvidia-smi", "--query-gpu=index,memory.used,utilization.gpu,clocks.sm", "--format=csv"], + text=True, + ) + report["complete"] = True + args.output.write_text(json.dumps(report, indent=2)) + + +if __name__ == "__main__": + main() diff --git a/csrc/normalization/rms_norm.cu b/csrc/normalization/rms_norm.cu new file mode 100644 index 00000000..612db480 --- /dev/null +++ b/csrc/normalization/rms_norm.cu @@ -0,0 +1,575 @@ +// SPDX-License-Identifier: Apache-2.0 +#include "../ops.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +namespace vllm_rlt { +namespace { + +template +struct alignas(16) Vector { + T val[16 / sizeof(T)]; +}; + +// Return one logical 16-byte vector without reading outside the input view. +// Aligned words are combined in registers when the logical start is shifted. +template +__device__ __forceinline__ Vector load_vector(const T* input, int index, int count) { + constexpr int elements = 16 / sizeof(T); + const int offset_bytes = reinterpret_cast(input + index) & 15; + Vector result; + if (offset_bytes == 0) { + *reinterpret_cast(&result) = *reinterpret_cast(input + index); + return result; + } + const int offset = offset_bytes / sizeof(T); + const int lower = index - offset; + Vector head{}, tail{}; + if (lower >= 0) { + *reinterpret_cast(&head) = *reinterpret_cast(input + lower); + } else { +#pragma unroll + for (int j = 0; j < elements; ++j) { + if (j >= offset) head.val[j] = input[lower + j]; + } + } + if (lower + 2 * elements <= count) { + *reinterpret_cast(&tail) = *reinterpret_cast(input + lower + elements); + } else { +#pragma unroll + for (int j = 0; j < elements; ++j) { + if (j < offset) tail.val[j] = input[lower + elements + j]; + } + } + uint4 lo = *reinterpret_cast(&head); + uint4 hi = *reinterpret_cast(&tail); + if (offset_bytes & 8) { + lo = make_uint4(lo.z, lo.w, hi.x, hi.y); + hi = make_uint4(hi.z, hi.w, 0, 0); + } + if (offset_bytes & 4) { + lo = make_uint4(lo.y, lo.z, lo.w, hi.x); + hi.x = hi.y; + } + if constexpr (sizeof(T) == 2) { + if (offset_bytes & 2) { + lo = make_uint4(__funnelshift_r(lo.x, lo.y, 16), __funnelshift_r(lo.y, lo.z, 16), + __funnelshift_r(lo.z, lo.w, 16), __funnelshift_r(lo.w, hi.x, 16)); + } + } + *reinterpret_cast(&result) = lo; + return result; +} + +__device__ __forceinline__ float2 mul2(float2 a, float2 b) { +#if defined(__CUDA_ARCH__) && __CUDA_ARCH__ >= 1000 + return __fmul2_rn(a, b); +#else + return make_float2(__fmul_rn(a.x, b.x), __fmul_rn(a.y, b.y)); +#endif +} + +__device__ __forceinline__ float2 add2(float2 a, float2 b) { +#if defined(__CUDA_ARCH__) && __CUDA_ARCH__ >= 1000 + return __fadd2_rn(a, b); +#else + return make_float2(__fadd_rn(a.x, b.x), __fadd_rn(a.y, b.y)); +#endif +} + +template +struct Arithmetic; + +template <> +struct Arithmetic<__half> { + using Pair = __half2; + __device__ static float scalar(__half x) { return __half2float(x); } + __device__ static __half cast(float x) { return __float2half_rn(x); } + __device__ static float2 pair(Pair x) { return __half22float2(x); } + __device__ static Pair cast2(float2 x) { return __floats2half2_rn(x.x, x.y); } + __device__ static __half mul(__half a, __half b) { return __hmul_rn(a, b); } + __device__ static __half add(__half a, __half b) { return __hadd_rn(a, b); } + __device__ static Pair mul_pair(Pair a, Pair b) { return __hmul2_rn(a, b); } + __device__ static Pair add_pair(Pair a, Pair b) { return __hadd2_rn(a, b); } +}; + +template <> +struct Arithmetic<__nv_bfloat16> { + using Pair = __nv_bfloat162; + __device__ static float scalar(__nv_bfloat16 x) { return __bfloat162float(x); } + __device__ static __nv_bfloat16 cast(float x) { return __float2bfloat16_rn(x); } + __device__ static float2 pair(Pair x) { return __bfloat1622float2(x); } + __device__ static Pair cast2(float2 x) { return __floats2bfloat162_rn(x.x, x.y); } + __device__ static __nv_bfloat16 mul(__nv_bfloat16 a, __nv_bfloat16 b) { + return __hmul_rn(a, b); + } + __device__ static __nv_bfloat16 add(__nv_bfloat16 a, __nv_bfloat16 b) { + return __hadd_rn(a, b); + } + __device__ static Pair mul_pair(Pair a, Pair b) { return __hmul2_rn(a, b); } + __device__ static Pair add_pair(Pair a, Pair b) { return __hadd2_rn(a, b); } +}; + +template <> +struct Arithmetic { + using Pair = float2; + __device__ static float scalar(float x) { return x; } + __device__ static float cast(float x) { return x; } + __device__ static float2 pair(Pair x) { return x; } + __device__ static Pair cast2(float2 x) { return x; } + __device__ static float mul(float a, float b) { return __fmul_rn(a, b); } + __device__ static float add(float a, float b) { return __fadd_rn(a, b); } + __device__ static Pair mul_pair(Pair a, Pair b) { return mul2(a, b); } + __device__ static Pair add_pair(Pair a, Pair b) { return add2(a, b); } +}; + +struct RowLayout { + int64_t sizes[3]; + int64_t input_strides[3]; + int64_t residual_strides[3]; + int64_t input_linear_stride; + int64_t residual_linear_stride; + int hidden_size; +}; + +__device__ __forceinline__ int64_t row_offset(int row, const int64_t* sizes, + const int64_t* strides) { + const int64_t index2 = row % sizes[2]; + row /= sizes[2]; + const int64_t index1 = row % sizes[1]; + const int64_t index0 = row / sizes[1]; + return index0 * strides[0] + index1 * strides[1] + index2 * strides[2]; +} + +// Ouro's 2048-wide BF16/FP16 reference uses torch.mean on an FP32 squared +// tensor. Reproduce that reduction tree, including its row-count-dependent +// width, because small differences can change early-exit decisions. +template +__global__ void rms_norm_torch_order_kernel(T* out, const T* input, const T* weight, + const T* residual, int64_t input_stride, + int64_t residual_stride, float epsilon) { + using A = Arithmetic; + using Pair = typename A::Pair; + constexpr int H = 2048; + constexpr int Packs = H / (Threads * 4); + const T* x = input + static_cast(blockIdx.x) * input_stride; + const T* r = nullptr; + if constexpr (AddResidual) r = residual + static_cast(blockIdx.x) * residual_stride; + T* y = out + static_cast(blockIdx.x) * H; + uint2 cached[Packs]; + float sums[4] = {0.f, 0.f, 0.f, 0.f}; +#pragma unroll + for (int k = 0; k < Packs; ++k) { + int index = 4 * (threadIdx.x + k * Threads); + cached[k] = *reinterpret_cast(x + index); + const Pair* pairs = reinterpret_cast(&cached[k]); + float2 a = A::pair(pairs[0]); + float2 b = A::pair(pairs[1]); + sums[0] = __fadd_rn(sums[0], __fmul_rn(a.x, a.x)); + sums[1] = __fadd_rn(sums[1], __fmul_rn(a.y, a.y)); + sums[2] = __fadd_rn(sums[2], __fmul_rn(b.x, b.x)); + sums[3] = __fadd_rn(sums[3], __fmul_rn(b.y, b.y)); + } + float sum = __fadd_rn(__fadd_rn(__fadd_rn(sums[0], sums[1]), sums[2]), sums[3]); + __shared__ float partial[Threads]; + if constexpr (Threads > 32) { + partial[threadIdx.x] = sum; + for (int offset = Threads / 2; offset >= 32; offset /= 2) { + __syncthreads(); + if (threadIdx.x < offset) { + sum = __fadd_rn(sum, partial[threadIdx.x + offset]); + partial[threadIdx.x] = sum; + } + } + __syncthreads(); + } +#pragma unroll + for (int offset = 16; offset > 0; offset /= 2) { + sum = __fadd_rn(sum, __shfl_down_sync(0xffffffff, sum, offset)); + } + float scale; + if constexpr (Threads == 32) { + scale = threadIdx.x == 0 ? rsqrtf(__fadd_rn(__fmul_rn(sum, 1.f / H), epsilon)) : 0.f; + scale = __shfl_sync(0xffffffff, scale, 0); + } else { + __shared__ float shared_scale; + if (threadIdx.x == 0) shared_scale = rsqrtf(__fadd_rn(__fmul_rn(sum, 1.f / H), epsilon)); + __syncthreads(); + scale = shared_scale; + } +#pragma unroll + for (int k = 0; k < Packs; ++k) { + int index = 4 * (threadIdx.x + k * Threads); + uint2 w = *reinterpret_cast(weight + index); + uint2 rv{}; + if constexpr (AddResidual) rv = *reinterpret_cast(r + index); + uint2 result; + const Pair* xp = reinterpret_cast(&cached[k]); + const Pair* wp = reinterpret_cast(&w); + const Pair* rp = reinterpret_cast(&rv); + Pair* yp = reinterpret_cast(&result); +#pragma unroll + for (int j = 0; j < 2; ++j) { + float2 f = A::pair(xp[j]); + Pair normalized = A::cast2(make_float2(__fmul_rn(f.x, scale), __fmul_rn(f.y, scale))); + Pair value = A::mul_pair(normalized, wp[j]); + if constexpr (AddResidual) value = A::add_pair(rp[j], value); + yp[j] = value; + } + *reinterpret_cast(y + index) = result; + } +} + +template +void launch_torch_order(at::Tensor& out, const at::Tensor& input, const at::Tensor& weight, + const std::optional& residual, float epsilon) { + const int rows = static_cast(input.size(0)); + const T* x = reinterpret_cast(input.const_data_ptr()); + const T* w = reinterpret_cast(weight.const_data_ptr()); + const T* r = AddResidual ? reinterpret_cast(residual->const_data_ptr()) : nullptr; + T* y = reinterpret_cast(out.mutable_data_ptr()); + const int64_t residual_stride = AddResidual ? residual->stride(0) : 0; + auto stream = c10::cuda::getCurrentCUDAStream(input.get_device()); +#define RUN_TORCH_ORDER(N) \ + rms_norm_torch_order_kernel<<>>( \ + y, x, w, r, input.stride(0), residual_stride, epsilon) + if (rows < 2) { RUN_TORCH_ORDER(512); } + else if (rows < 4) { RUN_TORCH_ORDER(256); } + else if (rows < 8) { RUN_TORCH_ORDER(128); } + else if (rows < 16) { RUN_TORCH_ORDER(64); } + else { RUN_TORCH_ORDER(32); } +#undef RUN_TORCH_ORDER + C10_CUDA_KERNEL_LAUNCH_CHECK(); +} + +template +__device__ __forceinline__ float2 accumulate(Vector x, float2 accum) { + using A = Arithmetic; + using Pair = typename A::Pair; + constexpr int pairs = 16 / sizeof(Pair); +#pragma unroll + for (int j = 0; j < pairs; ++j) { + Pair p = reinterpret_cast(&x)[j]; + float2 f = A::pair(p); + accum = add2(accum, mul2(f, f)); + } + return accum; +} + +template +__device__ __forceinline__ T finish_scalar(T x, T w, T residual, float scale) { + using A = Arithmetic; + T norm = A::cast(__fmul_rn(A::scalar(x), scale)); + T result = A::mul(norm, w); + if constexpr (AddResidual) result = A::add(residual, result); + return result; +} + +template +__device__ __forceinline__ Vector finish_vector(Vector x, Vector w, + Vector residual, float scale) { + using A = Arithmetic; + using Pair = typename A::Pair; + constexpr int pairs = 16 / sizeof(Pair); + Vector result; +#pragma unroll + for (int j = 0; j < pairs; ++j) { + Pair x_pair = reinterpret_cast(&x)[j]; + Pair w_pair = reinterpret_cast(&w)[j]; + Pair normalized = A::cast2(mul2(A::pair(x_pair), make_float2(scale, scale))); + Pair value = A::mul_pair(normalized, w_pair); + if constexpr (AddResidual) { + Pair r_pair = reinterpret_cast(&residual)[j]; + value = A::add_pair(r_pair, value); + } + reinterpret_cast(&result)[j] = value; + } + return result; +} + +template +__device__ __forceinline__ void write_vector(T* out, const T* weight, const T* residual, + Vector x, int index, int H, float scale) { + Vector w, r{}; + if constexpr (Aligned) { + *reinterpret_cast(&w) = *reinterpret_cast(weight + index); + if constexpr (AddResidual) { + *reinterpret_cast(&r) = *reinterpret_cast(residual + index); + } + } else { + w = load_vector(weight, index, H); + if constexpr (AddResidual) r = load_vector(residual, index, H); + } + Vector result = finish_vector(x, w, r, scale); + *reinterpret_cast(out + index) = *reinterpret_cast(&result); +} + +template +__global__ void rms_norm_kernel(T* out, const T* input, const T* weight, + const T* residual, RowLayout layout, float epsilon) { + constexpr int elements = 16 / sizeof(T); + const int H = StaticH ? StaticH : layout.hidden_size; + const int row = blockIdx.x; + const T* x = input + (layout.input_linear_stride >= 0 + ? static_cast(row) * layout.input_linear_stride + : row_offset(row, layout.sizes, layout.input_strides)); + const T* r = nullptr; + if constexpr (AddResidual) { + r = residual + (layout.residual_linear_stride >= 0 + ? static_cast(row) * layout.residual_linear_stride + : row_offset(row, layout.sizes, layout.residual_strides)); + } + T* y = out + static_cast(row) * H; + int prefix = 0; + if constexpr (!Aligned) { + prefix = min(H, static_cast(((16 - (reinterpret_cast(y) & 15)) & 15) / + sizeof(T))); + } + const int vectors = (H - prefix) / elements; + const int tail_start = prefix + vectors * elements; + Vector cached[CachePacks > 0 ? CachePacks : 1]; + float2 accum = make_float2(0.0f, 0.0f); + T head_value{}, tail_value{}; + float edge_sum = 0.0f; + if (threadIdx.x < prefix) { + head_value = x[threadIdx.x]; + float f = Arithmetic::scalar(head_value); + edge_sum = __fmul_rn(f, f); + } + if (tail_start + threadIdx.x < H) { + tail_value = x[tail_start + threadIdx.x]; + float f = Arithmetic::scalar(tail_value); + edge_sum = __fadd_rn(edge_sum, __fmul_rn(f, f)); + } + if constexpr (CachePacks > 0) { +#pragma unroll + for (int k = 0; k < CachePacks; ++k) { + int index = threadIdx.x + k * Threads; + if (index < vectors) { + int j = prefix + index * elements; + if constexpr (Aligned) { + *reinterpret_cast(&cached[k]) = *reinterpret_cast(x + j); + } else { + cached[k] = load_vector(x, j, H); + } + accum = accumulate(cached[k], accum); + } + } + } else { + for (int index = threadIdx.x; index < vectors; index += Threads) { + int j = prefix + index * elements; + Vector value; + if constexpr (Aligned) { + *reinterpret_cast(&value) = *reinterpret_cast(x + j); + } else { + value = load_vector(x, j, H); + } + accum = accumulate(value, accum); + } + } + float sum = __fadd_rn(__fadd_rn(accum.x, accum.y), edge_sum); + float scale; + if constexpr (Threads == 32) { +#pragma unroll + for (int delta = 16; delta > 0; delta /= 2) { + sum = __fadd_rn(sum, __shfl_down_sync(0xffffffff, sum, delta)); + } + scale = threadIdx.x == 0 ? rsqrtf(sum / H + epsilon) : 0.0f; + scale = __shfl_sync(0xffffffff, scale, 0); + } else { + using Reduce = cub::BlockReduce; + __shared__ typename Reduce::TempStorage storage; + __shared__ float shared_scale; + sum = Reduce(storage).Sum(sum); + if (threadIdx.x == 0) shared_scale = rsqrtf(sum / H + epsilon); + __syncthreads(); + scale = shared_scale; + } + if (threadIdx.x < prefix) { + int j = threadIdx.x; + T rv{}; + if constexpr (AddResidual) rv = r[j]; + y[j] = finish_scalar(head_value, weight[j], rv, scale); + } + if (tail_start + threadIdx.x < H) { + int j = tail_start + threadIdx.x; + T rv{}; + if constexpr (AddResidual) rv = r[j]; + y[j] = finish_scalar(tail_value, weight[j], rv, scale); + } + if constexpr (CachePacks > 0) { + // Constant indices let nvcc keep each saved vector in registers. +#pragma unroll + for (int k = 0; k < CachePacks; ++k) { + int index = threadIdx.x + k * Threads; + if (index < vectors) { + int j = prefix + index * elements; + write_vector(y, weight, r, cached[k], j, H, scale); + } + } + } else { + for (int index = threadIdx.x; index < vectors; index += Threads) { + int j = prefix + index * elements; + Vector xv; + if constexpr (Aligned) { + *reinterpret_cast(&xv) = *reinterpret_cast(x + j); + } else { + xv = load_vector(x, j, H); + } + write_vector(y, weight, r, xv, j, H, scale); + } + } +} + +template +void launch_layout(at::Tensor& out, const at::Tensor& input, const at::Tensor& weight, + const std::optional& residual, RowLayout layout, int rows, + float epsilon, cudaStream_t stream) { + const T* x = reinterpret_cast(input.const_data_ptr()); + const T* w = reinterpret_cast(weight.const_data_ptr()); + const T* r = residual ? reinterpret_cast(residual->const_data_ptr()) : nullptr; + T* y = reinterpret_cast(out.mutable_data_ptr()); + constexpr int elements = 16 / sizeof(T); +#define RUN_RMS(H, K) \ + rms_norm_kernel<<>>( \ + y, x, w, r, layout, epsilon) + if constexpr (Aligned && Threads == 256) { + if (layout.hidden_size == 2048) { + RUN_RMS(2048, (2048 + Threads * elements - 1) / (Threads * elements)); + return; + } + } + // Cache small rows; stream very wide rows to avoid unbounded register pressure. + const int packs = (layout.hidden_size + Threads * elements - 1) / (Threads * elements); + if (packs <= 1) { RUN_RMS(0, 1); } + else if (packs <= 2) { RUN_RMS(0, 2); } + else if (packs <= 4) { RUN_RMS(0, 4); } + else { RUN_RMS(0, 0); } +#undef RUN_RMS +} + +template +void launch(at::Tensor& out, const at::Tensor& input, const at::Tensor& weight, + const std::optional& residual, float epsilon) { + constexpr int elements = 16 / sizeof(T); + RowLayout layout{}; + for (int i = 0; i < 3; ++i) layout.sizes[i] = 1; + const int outer = input.dim() - 1; + // A singleton penultimate dimension can have an arbitrary stride even when + // the tensor is contiguous, so a contiguous row advances by hidden_size. + layout.input_linear_stride = input.is_contiguous() + ? (outer ? input.size(-1) : 0) + : (input.dim() <= 2 ? input.stride(-2) : -1); + if constexpr (AddResidual) { + layout.residual_linear_stride = residual->is_contiguous() + ? (outer ? residual->size(-1) : 0) + : (residual->dim() <= 2 ? residual->stride(-2) : -1); + } + bool aligned = ((reinterpret_cast(input.const_data_ptr()) | + reinterpret_cast(weight.const_data_ptr()) | + reinterpret_cast(out.mutable_data_ptr())) & 15) == 0; + if constexpr (AddResidual) { + aligned = aligned && (reinterpret_cast(residual->const_data_ptr()) & 15) == 0; + } + for (int d = 0; d < outer; ++d) { + int target = 3 - outer + d; + layout.sizes[target] = input.size(d); + layout.input_strides[target] = input.stride(d); + aligned = aligned && (input.size(d) == 1 || input.stride(d) % elements == 0); + if constexpr (AddResidual) { + layout.residual_strides[target] = residual->stride(d); + aligned = aligned && (input.size(d) == 1 || residual->stride(d) % elements == 0); + } + } + layout.hidden_size = static_cast(input.size(-1)); + aligned = aligned && layout.hidden_size % elements == 0; + const int rows = static_cast(input.numel() / layout.hidden_size); + auto stream = c10::cuda::getCurrentCUDAStream(input.get_device()); + if (layout.hidden_size <= 256) { + if (aligned) launch_layout(out, input, weight, residual, layout, rows, epsilon, stream); + else launch_layout(out, input, weight, residual, layout, rows, epsilon, stream); + } else { + if (aligned) launch_layout(out, input, weight, residual, layout, rows, epsilon, stream); + else launch_layout(out, input, weight, residual, layout, rows, epsilon, stream); + } + C10_CUDA_KERNEL_LAUNCH_CHECK(); +} + +} // namespace + +at::Tensor rms_norm_cuda(const at::Tensor& input, const at::Tensor& weight, double epsilon, + const std::optional& residual, bool match_torch) { + TORCH_CHECK(input.is_cuda() && weight.is_cuda(), "rms_norm expects CUDA inputs"); + TORCH_CHECK(input.device() == weight.device(), "rms_norm expects inputs on the same device"); + TORCH_CHECK(input.dim() >= 1 && input.dim() <= 4, "rms_norm expects rank 1 through 4"); + TORCH_CHECK(input.stride(-1) == 1, "rms_norm expects a contiguous last dimension"); + TORCH_CHECK(weight.dim() == 1 && weight.is_contiguous() && weight.size(0) == input.size(-1), + "rms_norm expects contiguous weight with shape [hidden_size]"); + TORCH_CHECK(input.scalar_type() == weight.scalar_type(), "rms_norm expects matching dtypes"); + TORCH_CHECK(input.scalar_type() == at::kFloat || input.scalar_type() == at::kHalf || + input.scalar_type() == at::kBFloat16, + "rms_norm supports float32, float16 and bfloat16"); + if (residual) { + TORCH_CHECK(residual->is_cuda() && residual->device() == input.device(), + "rms_norm expects residual on the input device"); + TORCH_CHECK(residual->sizes() == input.sizes() && residual->stride(-1) == 1 && + residual->scalar_type() == input.scalar_type(), + "rms_norm expects matching residual shape, dtype and contiguous last dimension"); + } + TORCH_CHECK(!at::GradMode::is_enabled() || + (!input.requires_grad() && !weight.requires_grad() && + (!residual || !residual->requires_grad())), + "rms_norm is inference-only; use torch.no_grad() or the Torch reference"); + TORCH_CHECK(input.size(-1) <= std::numeric_limits::max(), "hidden size is too large"); + const c10::cuda::CUDAGuard guard(input.device()); + auto out = at::empty(input.sizes(), input.options()); + if (input.numel() == 0) return out; + TORCH_CHECK(input.numel() / input.size(-1) <= std::numeric_limits::max(), + "too many rms_norm rows"); + if (match_torch) { + TORCH_CHECK(input.dim() == 2 && input.size(-1) == 2048 && + (input.scalar_type() == at::kHalf || input.scalar_type() == at::kBFloat16), + "torch-order rms_norm requires 2D FP16/BF16 input of width 2048"); + TORCH_CHECK((reinterpret_cast(input.const_data_ptr()) & 7) == 0 && + (reinterpret_cast(weight.const_data_ptr()) & 7) == 0 && + (input.size(0) == 1 || input.stride(0) % 4 == 0), + "torch-order rms_norm requires 8-byte-aligned rows and weight"); + if (residual) { + TORCH_CHECK((reinterpret_cast(residual->const_data_ptr()) & 7) == 0 && + (residual->size(0) == 1 || residual->stride(0) % 4 == 0), + "torch-order rms_norm requires 8-byte-aligned residual rows"); + } +#define LAUNCH_TORCH_ORDER(T) \ + if (residual) launch_torch_order(out, input, weight, residual, epsilon); \ + else launch_torch_order(out, input, weight, residual, epsilon) + if (input.scalar_type() == at::kHalf) { LAUNCH_TORCH_ORDER(__half); } + else { LAUNCH_TORCH_ORDER(__nv_bfloat16); } +#undef LAUNCH_TORCH_ORDER + return out; + } +#define LAUNCH_RMS(T) \ + if (residual) launch(out, input, weight, residual, epsilon); \ + else launch(out, input, weight, residual, epsilon) + switch (input.scalar_type()) { + case at::kHalf: LAUNCH_RMS(__half); break; + case at::kBFloat16: LAUNCH_RMS(__nv_bfloat16); break; + case at::kFloat: LAUNCH_RMS(float); break; + default: TORCH_CHECK(false, "unsupported dtype"); + } +#undef LAUNCH_RMS + return out; +} + +} // namespace vllm_rlt diff --git a/csrc/ops.h b/csrc/ops.h index e00c054e..68fe28a3 100644 --- a/csrc/ops.h +++ b/csrc/ops.h @@ -6,5 +6,7 @@ namespace vllm_rlt { at::Tensor silu_and_mul_cuda(const at::Tensor& gate, const at::Tensor& up); +at::Tensor rms_norm_cuda(const at::Tensor& input, const at::Tensor& weight, double epsilon, + const std::optional& residual, bool match_torch); } // namespace vllm_rlt diff --git a/csrc/torch_bindings.cpp b/csrc/torch_bindings.cpp index afd5cf41..9376c633 100644 --- a/csrc/torch_bindings.cpp +++ b/csrc/torch_bindings.cpp @@ -6,10 +6,12 @@ TORCH_LIBRARY(vllm_rlt, ops) { ops.def("silu_and_mul(Tensor gate, Tensor up) -> Tensor"); + ops.def("rms_norm(Tensor input, Tensor weight, float epsilon, Tensor? residual=None, bool match_torch=False) -> Tensor"); } TORCH_LIBRARY_IMPL(vllm_rlt, CUDA, ops) { ops.impl("silu_and_mul", &vllm_rlt::silu_and_mul_cuda); + ops.impl("rms_norm", &vllm_rlt::rms_norm_cuda); } PYBIND11_MODULE(TORCH_EXTENSION_NAME, module) {} diff --git a/docs/kernels.md b/docs/kernels.md index a1fda4e1..37325e91 100644 --- a/docs/kernels.md +++ b/docs/kernels.md @@ -13,9 +13,13 @@ fallbacks. It neither compiles code nor creates a CUDA context. | `csrc/ops.h` | Native operator declarations | | `csrc/torch_bindings.cpp` | Operator schemas and CUDA dispatch registration | | `csrc/activation/silu_and_mul.cu` | SiLU-and-Mul CUDA validation, launch and computation | +| `csrc/normalization/rms_norm.cu` | RMSNorm and RMSNorm-then-residual CUDA kernels | +| `vllm_rlt/kernels/normalization.py` | RMSNorm Python entry and Torch reference | | `setup.py` | Optional build of `vllm_rlt._C` | | `tests/test_activation.py` | Reference, CUDA numerics, layouts, tails and graph replay | +| `tests/test_normalization.py` | RMSNorm numerics, strides, alignment and graph replay | | `benchmarks/kernels/silu_and_mul.py` | Matched Torch/native/vLLM accuracy and latency comparison | +| `benchmarks/kernels/rms_norm.py` | RMSNorm and residual accuracy and latency comparison | Add future kernels to the same extension and group sources by operation family. No backend registry or base class is required. Put future kernel performance @@ -73,6 +77,54 @@ are disabled, consistent with Ouro's inference-only model. `torch.compile` has no fake kernel registration. Tests cover the operator and Ouro MLP, including CUDA Graph capture/replay. +## RMSNorm and residual contract + +`rms_norm(hidden, weight, epsilon, residual=None)` returns a new tensor. Its +reference computes the mean square and inverse square root in FP32, multiplies +the input by that scale, rounds the normalized values to the input dtype, then +multiplies by `weight`. When supplied, the residual is added after the weight +multiplication. In Ouro, this fuses the existing `residual + RMSNorm(hidden)` +order; it does not implement `RMSNorm(residual + hidden)`. The weight is a +one-dimensional tensor of shape `[hidden_size]` and is shared across rows. + +With the extension installed, the native inference path supports CUDA FP32, +FP16 and BF16 tensors of rank 1 through 4, matching one-dimensional contiguous +weights, and matching residuals. The last input and residual dimensions must +have stride 1. Outer dimensions may be strided, including views into a larger +row; input, weight and residual addresses may have independent offsets. The +output is contiguous and none of the inputs is modified. Empty tensors return +without a kernel launch. CPU tensors, autograd, mixed dtypes and other layouts +use the Torch reference. Nanbeige and Huginn continue to use their existing +Torch RMSNorm path. + +The general CUDA kernel assigns one block per row. It sums squares in FP32, +uses a warp reduction for widths up to 256 and a block reduction otherwise, +then writes the scaled and weighted values, optionally with a residual. The +aligned body loads and stores 16 bytes at a time and uses paired FP16/BF16 +arithmetic. Unaligned output heads and tails use scalar accesses; independently +shifted input, weight and residual vectors are reconstructed from safe aligned +reads, with scalar reads at view boundaries. Small rows retain their input +vectors in registers across the reduction; wider rows stream them again to bound +register usage. Aligned width 2048 has a specialized path. FP32 pairs use paired +arithmetic on SM100 and newer, with scalar FP32 operations on earlier +architectures. These launch choices are implementation details and are not +claimed optimal for every GPU. + +The general native reduction can use a different floating-point summation order +from PyTorch, so its result need not be bitwise equal. Ouro uses a separate +2048-wide FP16/BF16 compatibility path that reproduces the tested PyTorch mean +reduction order, including its row-count-dependent block width. This path +fuses the residual, uses 8-byte vector loads and stores and paired arithmetic, +and keeps each thread's input values in registers across the reduction. It +supports two-dimensional inputs and residuals with 8-byte-aligned rows, including +strided views. Since the reduction tree is a PyTorch implementation detail, +this path is currently enabled only for PyTorch 2.13.0 on SM103; Ouro falls +back to the Torch reference for other versions, GPUs, shapes or alignments. +The general kernel remains available through `rms_norm(..., match_torch=False)`. +The tested compatibility path and the general path both retain the explicit +intermediate dtype roundings and residual order. CUDA Graph replay is supported; +a fake kernel for `torch.compile` is not registered. + ## Build and reference checks The extension builds automatically when the build environment has CUDA-enabled @@ -87,7 +139,7 @@ python -m pip install "torch>=2.5" setuptools wheel ninja python -m pip install --no-build-isolation -e . python -m pytest tests/test_activation.py -q CUDA_VISIBLE_DEVICES= python -m pytest \ - tests/test_activation.py --run-gpu -q + tests/test_activation.py tests/test_normalization.py --run-gpu -q ``` `pip` invokes setuptools, whose PyTorch `CUDAExtension`/`BuildExtension` compiles @@ -145,3 +197,18 @@ commit. The report retains library hashes, the local diff and raw measurements. Optional ops-only/full profiles are captured separately after timing; full capture enables shapes, memory and stacks. Large traces stay under ignored `artifacts/`. + +For RMSNorm, compare the Torch reference and both native paths without vLLM: + +```bash +CUDA_VISIBLE_DEVICES= python -m benchmarks.kernels.rms_norm \ + --output artifacts/rmsnorm/results.json \ + --profile-dir artifacts/rmsnorm/profiles +``` + +An optional source-built vLLM comparison can be supplied with +`--vllm-library --vllm-namespace --vllm-source-commit `. +Its different intermediate rounding is reported separately from the reference +semantics. The general native path can use a different reduction order than +PyTorch; use the `rlt_torch_order` measurements when assessing Ouro's actual +compatibility path. diff --git a/setup.py b/setup.py index b83b309d..c72d9c75 100644 --- a/setup.py +++ b/setup.py @@ -37,6 +37,7 @@ def native_build_options(): sources=[ "csrc/torch_bindings.cpp", "csrc/activation/silu_and_mul.cu", + "csrc/normalization/rms_norm.cu", ], extra_compile_args={"cxx": ["-O3"], "nvcc": ["-O3"]}, ) diff --git a/tests/test_normalization.py b/tests/test_normalization.py index f7111244..3f67cd8e 100644 --- a/tests/test_normalization.py +++ b/tests/test_normalization.py @@ -4,6 +4,7 @@ import pytest import torch +from vllm_rlt.kernels.normalization import rms_norm, rms_norm_reference from vllm_rlt.layers import RMSNorm from vllm_rlt.models.nanbeige import NanbeigeRMSNorm from vllm_rlt.models.ouro import OuroRMSNorm @@ -69,3 +70,262 @@ def test_rmsnorm_explicit_epsilon(): # Variance of ones is 1.0; 1.0 / sqrt(1.0 + 1.0) = 1.0 / sqrt(2) ≈ 0.7071 expected_large = 1.0 / (2.0**0.5) assert torch.allclose(out_large, torch.full_like(x, expected_large), atol=1e-4) + + +def test_opt_in_residual_preserves_cpu_autograd_and_mixed_dtype(): + norm = RMSNorm(5, use_native=True) + x = torch.randn(2, 5, dtype=torch.bfloat16, requires_grad=True) + residual = torch.randn(2, 5, dtype=torch.float32, requires_grad=True) + actual = norm(x, residual=residual) + expected = rms_norm_reference(x, norm.weight, norm.variance_epsilon, residual) + assert actual.dtype == torch.float32 + torch.testing.assert_close(actual, expected, rtol=0, atol=0) + actual.sum().backward() + assert x.grad is not None and residual.grad is not None and norm.weight.grad is not None + + +@pytest.fixture +def native_rms_norm(): + from vllm_rlt.kernels._extension import load_extension + + load_extension() + assert torch._C._dispatch_has_kernel_for_dispatch_key("vllm_rlt::rms_norm", "CUDA") + return rms_norm + + +@pytest.mark.gpu +@pytest.mark.parametrize("dtype", [torch.float32, torch.float16, torch.bfloat16]) +@pytest.mark.parametrize("width", [8, 17, 128, 256, 257, 768, 2048, 2049, 4096, 8193]) +@pytest.mark.parametrize("add_residual", [False, True]) +@torch.inference_mode() +def test_rmsnorm_cuda_values_tail_and_staged_rounding(native_rms_norm, dtype, width, add_residual): + torch.manual_seed(42) + x = torch.randn(3, width, device="cuda", dtype=dtype) + weight = (torch.randn(width, device="cuda") * 0.1 + 1).to(dtype) + residual = torch.randn_like(x) if add_residual else None + x_before, w_before = x.clone(), weight.clone() + r_before = residual.clone() if residual is not None else None + result = native_rms_norm(x, weight, 1e-6, residual) + expected = rms_norm_reference(x, weight, 1e-6, residual) + # CUDA's reduction order differs from torch.mean; keep the dtype rounding + # boundaries and independently check the residual's input is untouched. + tolerance = { + torch.float32: (2e-6, 2e-6), + torch.float16: (2e-3, 2e-3), + torch.bfloat16: (1e-2, 1e-2), + }[dtype] + torch.testing.assert_close(result, expected, rtol=tolerance[0], atol=tolerance[1]) + assert result.shape == x.shape and result.dtype == x.dtype and result.is_contiguous() + assert result.data_ptr() not in (x.data_ptr(), weight.data_ptr()) + assert torch.equal(x, x_before) and torch.equal(weight, w_before) + if residual is not None: + assert result.data_ptr() != residual.data_ptr() + assert torch.equal(residual, r_before) + + +@pytest.mark.gpu +@pytest.mark.parametrize("dtype", [torch.float16, torch.bfloat16]) +@pytest.mark.parametrize("rows", [1, 2, 3, 4, 5, 8, 15, 16, 17, 128, 1024]) +@pytest.mark.parametrize("add_residual", [False, True]) +@torch.inference_mode() +def test_rmsnorm_cuda_torch_order_is_exact(native_rms_norm, dtype, rows, add_residual): + # The row count changes torch.mean's reduction tree. Cover the boundaries + # where the compatibility kernel changes its block width. + from vllm_rlt.kernels.normalization import _torch_order_validated + + if not _torch_order_validated(torch.cuda.current_device()): + pytest.skip("the Torch-order CUDA kernel is not enabled on this Torch/GPU combination") + x = torch.randn(rows, 2048, dtype=dtype, device="cuda") + weight = torch.randn(2048, dtype=dtype, device="cuda") + residual = torch.randn_like(x) if add_residual else None + actual = native_rms_norm(x, weight, 1e-6, residual, match_torch=True) + expected = rms_norm_reference(x, weight, 1e-6, residual) + torch.testing.assert_close(actual, expected, rtol=0, atol=0) + + +@pytest.mark.gpu +@pytest.mark.parametrize("dtype", [torch.float16, torch.bfloat16]) +@torch.inference_mode() +def test_rmsnorm_cuda_torch_order_strides_and_fallback(native_rms_norm, dtype): + # An aligned SP-style slice can use the exact kernel, while an offset that + # cannot safely use its vector loads falls back to the Torch reference. + rows, width = 4, 2048 + base = torch.randn(rows, width * 2 + 8, dtype=dtype, device="cuda") + residual_base = torch.randn_like(base) + weight = torch.randn(width + 1, dtype=dtype, device="cuda") + for offset in (0, 1): + x = base[:, offset : offset + width] + residual = residual_base[:, offset : offset + width] + w = weight[offset : offset + width] + actual = native_rms_norm(x, w, 1e-6, residual, match_torch=True) + expected = rms_norm_reference(x, w, 1e-6, residual) + torch.testing.assert_close(actual, expected, rtol=0, atol=0) + + +@pytest.mark.gpu +@pytest.mark.parametrize("dtype", [torch.float16, torch.bfloat16]) +@torch.inference_mode() +def test_rmsnorm_cuda_torch_order_nonfinite(native_rms_norm, dtype): + x = torch.zeros(4, 2048, dtype=dtype, device="cuda") + x[1, 0] = float("inf") + x[2, 0] = float("-inf") + x[3, 0] = float("nan") + weight = torch.randn(2048, dtype=dtype, device="cuda") + residual = torch.randn_like(x) + actual = native_rms_norm(x, weight, 1e-6, residual, match_torch=True) + expected = rms_norm_reference(x, weight, 1e-6, residual) + torch.testing.assert_close(actual, expected, rtol=0, atol=0, equal_nan=True) + + +@pytest.mark.gpu +@torch.inference_mode() +def test_rmsnorm_cuda_torch_order_graph_replay(native_rms_norm): + dtype = torch.bfloat16 + x = torch.randn(17, 2048, dtype=dtype, device="cuda") + weight = torch.randn(2048, dtype=dtype, device="cuda") + residual = torch.randn_like(x) + native_rms_norm(x, weight, 1e-6, residual, match_torch=True) + graph = torch.cuda.CUDAGraph() + with torch.cuda.graph(graph): + actual = native_rms_norm(x, weight, 1e-6, residual, match_torch=True) + x.fill_(0.25) + residual.fill_(0.5) + graph.replay() + expected = rms_norm_reference(x, weight, 1e-6, residual) + torch.testing.assert_close(actual, expected, rtol=0, atol=0) + + +@pytest.mark.gpu +@pytest.mark.parametrize("dtype", [torch.float32, torch.float16, torch.bfloat16]) +@pytest.mark.parametrize("rank", [1, 2, 3, 4]) +@pytest.mark.parametrize("add_residual", [False, True]) +@torch.inference_mode() +def test_rmsnorm_cuda_strides_and_independent_offsets(native_rms_norm, dtype, rank, add_residual): + torch.manual_seed(123) + width = 33 + shape = (width,) if rank == 1 else (*((2,) * (rank - 1)), width) + base_shape = (*shape[:-1], width + 3) + x = torch.randn(base_shape, device="cuda", dtype=dtype)[..., 1 : width + 1] + residual = torch.randn(base_shape, device="cuda", dtype=dtype)[..., 2 : width + 2] + weight = torch.randn(width + 1, device="cuda", dtype=dtype)[1:] + if not add_residual: + residual = None + actual = native_rms_norm(x, weight, 1e-6, residual) + expected = rms_norm_reference(x, weight, 1e-6, residual) + tol = 2e-6 if dtype == torch.float32 else 2e-3 if dtype == torch.float16 else 1e-2 + torch.testing.assert_close(actual, expected, rtol=tol, atol=tol) + assert actual.is_contiguous() and actual.shape == x.shape + + +@pytest.mark.gpu +@pytest.mark.parametrize("dtype", [torch.float32, torch.float16, torch.bfloat16]) +@torch.inference_mode() +def test_rmsnorm_cuda_contiguous_with_arbitrary_singleton_stride(native_rms_norm, dtype): + # PyTorch ignores singleton strides in is_contiguous(); flattened rows must + # still advance by width, not by the arbitrary penultimate stride. + width = 33 + x = torch.randn(4, width, device="cuda", dtype=dtype).as_strided( + (4, 1, width), (width, 7 * width, 1) + ) + residual = torch.randn(4, width, device="cuda", dtype=dtype).as_strided( + (4, 1, width), (width, 5 * width, 1) + ) + assert x.is_contiguous() and residual.is_contiguous() + weight = torch.randn(width, device="cuda", dtype=dtype) + actual = native_rms_norm(x, weight, 1e-6, residual) + expected = rms_norm_reference(x, weight, 1e-6, residual) + tol = 2e-6 if dtype == torch.float32 else 2e-3 if dtype == torch.float16 else 1e-2 + torch.testing.assert_close(actual, expected, rtol=tol, atol=tol) + + +@pytest.mark.gpu +@pytest.mark.parametrize("dtype", [torch.float32, torch.float16, torch.bfloat16]) +@torch.inference_mode() +def test_rmsnorm_cuda_all_alignment_combinations(native_rms_norm, dtype): + # Each row begins at a different offset; input, residual and weight offsets + # vary independently across every possible 16-byte alignment. + torch.manual_seed(7) + elements = 16 // torch.empty((), dtype=dtype).element_size() + width = 2 * elements + 1 + x_base = torch.randn(2, width + elements, device="cuda", dtype=dtype) + r_base = torch.randn_like(x_base) + w_base = torch.randn(width + elements, device="cuda", dtype=dtype) + tol = 2e-6 if dtype == torch.float32 else 2e-3 if dtype == torch.float16 else 1e-2 + for x_offset in range(elements): + x = x_base[:, x_offset : x_offset + width] + for w_offset in range(elements): + weight = w_base[w_offset : w_offset + width] + for r_offset in range(elements): + residual = r_base[:, r_offset : r_offset + width] + actual = native_rms_norm(x, weight, 1e-6, residual) + expected = rms_norm_reference(x, weight, 1e-6, residual) + torch.testing.assert_close(actual, expected, rtol=tol, atol=tol) + + +@pytest.mark.gpu +@pytest.mark.parametrize("dtype", [torch.float32, torch.float16, torch.bfloat16]) +@torch.inference_mode() +def test_rmsnorm_cuda_nonfinite_and_zero_rows(native_rms_norm, dtype): + x = torch.zeros(4, 33, dtype=dtype, device="cuda") + x[1, 0] = float("inf") + x[2, 0] = float("-inf") + x[3, 0] = float("nan") + weight = torch.randn(33, dtype=dtype, device="cuda") + residual = torch.randn_like(x) + actual = native_rms_norm(x, weight, 1e-6, residual) + expected = rms_norm_reference(x, weight, 1e-6, residual) + torch.testing.assert_close(actual, expected, rtol=0, atol=0, equal_nan=True) + + +@pytest.mark.gpu +@torch.inference_mode() +def test_rmsnorm_cuda_falls_back_for_other_layouts_and_mixed_dtypes(native_rms_norm): + width = 33 + inputs = ( + torch.randn(2, width * 2, device="cuda")[..., ::2], + torch.randn(2, 1, 2, 1, width, device="cuda"), + torch.randn(2, width, device="cuda", dtype=torch.bfloat16), + ) + for x in inputs: + # The last case intentionally has FP32 weight and BF16 activations. + weight = torch.randn(width, device="cuda", dtype=torch.float32) + residual = torch.randn_like(x) + actual = native_rms_norm(x, weight, 1e-6, residual) + expected = rms_norm_reference(x, weight, 1e-6, residual) + torch.testing.assert_close(actual, expected, rtol=0, atol=0) + + +@pytest.mark.gpu +@pytest.mark.parametrize("dtype", [torch.float32, torch.float16, torch.bfloat16]) +@pytest.mark.parametrize("shape", [(0, 2048), (2, 0)]) +@torch.inference_mode() +def test_rmsnorm_cuda_empty(native_rms_norm, dtype, shape): + x = torch.empty(shape, device="cuda", dtype=dtype) + weight = torch.empty(shape[-1], device="cuda", dtype=dtype) + actual = native_rms_norm(x, weight, 1e-6) + assert actual.shape == x.shape and actual.dtype == dtype and actual.numel() == 0 + + +@pytest.mark.gpu +@pytest.mark.parametrize("dtype", [torch.float32, torch.float16, torch.bfloat16]) +@pytest.mark.parametrize("add_residual", [False, True]) +@torch.inference_mode() +def test_rmsnorm_cuda_current_stream_and_graph_replay(native_rms_norm, dtype, add_residual): + stream = torch.cuda.Stream() + with torch.cuda.stream(stream), torch.inference_mode(): + x = torch.randn(7, 2049, device="cuda", dtype=dtype) + weight = torch.randn(2049, device="cuda", dtype=dtype) + residual = torch.randn_like(x) if add_residual else None + for _ in range(3): + native_rms_norm(x, weight, 1e-6, residual) + stream.synchronize() + graph = torch.cuda.CUDAGraph() + with torch.inference_mode(), torch.cuda.graph(graph, stream=stream): + actual = native_rms_norm(x, weight, 1e-6, residual) + x.fill_(0.5) + if residual is not None: + residual.fill_(0.25) + graph.replay() + expected = rms_norm_reference(x, weight, 1e-6, residual) + tol = 2e-6 if dtype == torch.float32 else 2e-3 if dtype == torch.float16 else 1e-2 + torch.testing.assert_close(actual, expected, rtol=tol, atol=tol) diff --git a/vllm_rlt/kernels/__init__.py b/vllm_rlt/kernels/__init__.py index 7cf7031f..a51348ab 100644 --- a/vllm_rlt/kernels/__init__.py +++ b/vllm_rlt/kernels/__init__.py @@ -1,5 +1,6 @@ """Register native and Torch kernels once without initializing a GPU.""" from .activation import silu_and_mul +from .normalization import rms_norm -__all__ = ["silu_and_mul"] +__all__ = ["rms_norm", "silu_and_mul"] diff --git a/vllm_rlt/kernels/normalization.py b/vllm_rlt/kernels/normalization.py new file mode 100644 index 00000000..a95b65fe --- /dev/null +++ b/vllm_rlt/kernels/normalization.py @@ -0,0 +1,109 @@ +"""Inference RMSNorm with an optional residual and a PyTorch reference.""" + +from functools import cache + +import torch + +from vllm_rlt.kernels._extension import try_load_extension + + +def rms_norm_reference( + hidden: torch.Tensor, + weight: torch.Tensor, + epsilon: float, + residual: torch.Tensor | None = None, +) -> torch.Tensor: + value = hidden.float() + value = value * torch.rsqrt(value.square().mean(-1, keepdim=True) + epsilon) + result = weight * value.to(hidden.dtype) + return result if residual is None else residual + result + + +_library = torch.library.Library("vllm_rlt", "FRAGMENT") +if not try_load_extension(): + _library.define( + "rms_norm(Tensor input, Tensor weight, float epsilon, Tensor? residual=None, " + "bool match_torch=False) -> Tensor" + ) + + +def _reference_dispatch(hidden, weight, epsilon, residual=None, match_torch=False): + return rms_norm_reference(hidden, weight, epsilon, residual) + + +_library.impl("rms_norm", _reference_dispatch, "CompositeExplicitAutograd") + + +@cache +def _torch_order_validated(device_index: int) -> bool: + # torch.mean's reduction tree is an implementation detail. Only use the + # compatibility kernel for the framework and GPU on which it was checked. + return torch.__version__.split("+", 1)[0] == "2.13.0" and torch.cuda.get_device_capability( + device_index + ) == (10, 3) + + +def rms_norm( + hidden: torch.Tensor, + weight: torch.Tensor, + epsilon: float, + residual: torch.Tensor | None = None, + *, + match_torch: bool = False, +) -> torch.Tensor: + """Use the native CUDA operator where its inference layout contract applies.""" + # The module historically accepts autograd, mixed dtypes and arbitrary views. + # Keep those semantics in Torch rather than copying or narrowing inputs. + supported = ( + hidden.is_cuda + and 1 <= hidden.ndim <= 4 + and hidden.stride(-1) == 1 + and hidden.dtype in (torch.float32, torch.float16, torch.bfloat16) + and weight.ndim == 1 + and weight.is_contiguous() + and weight.shape[0] == hidden.shape[-1] + and weight.dtype == hidden.dtype + and weight.device == hidden.device + and ( + residual is None + or ( + residual.shape == hidden.shape + and residual.device == hidden.device + and residual.dtype == hidden.dtype + and residual.stride(-1) == 1 + ) + ) + and ( + not torch.is_grad_enabled() + or not ( + hidden.requires_grad + or weight.requires_grad + or (residual is not None and residual.requires_grad) + ) + ) + ) + if not supported: + return rms_norm_reference(hidden, weight, epsilon, residual) + if match_torch: + # The model-compatible kernel reproduces torch.mean's CUDA reduction + # order only for these shapes and alignments. Preserve the Torch path + # elsewhere instead of silently changing early-exit behavior. + compatible = ( + hidden.ndim == 2 + and hidden.shape[-1] == 2048 + and hidden.dtype in (torch.float16, torch.bfloat16) + and _torch_order_validated(hidden.device.index) + and hidden.data_ptr() % 8 == 0 + and weight.data_ptr() % 8 == 0 + and (hidden.shape[0] <= 1 or hidden.stride(0) % 4 == 0) + and ( + residual is None + or ( + residual.data_ptr() % 8 == 0 + and (residual.shape[0] <= 1 or residual.stride(0) % 4 == 0) + ) + ) + ) + if not compatible: + return rms_norm_reference(hidden, weight, epsilon, residual) + return torch.ops.vllm_rlt.rms_norm(hidden, weight, epsilon, residual, match_torch) diff --git a/vllm_rlt/layers/normalization.py b/vllm_rlt/layers/normalization.py index 9d32247d..ac46b52b 100644 --- a/vllm_rlt/layers/normalization.py +++ b/vllm_rlt/layers/normalization.py @@ -4,6 +4,8 @@ import torch from torch import nn +from vllm_rlt.kernels import rms_norm + class RMSNorm(nn.Module): """Root Mean Square Layer Normalization. @@ -12,12 +14,16 @@ class RMSNorm(nn.Module): across all input activation dtypes (BF16/FP16/FP32). """ - def __init__(self, hidden_size: int, eps: float = 1e-6) -> None: + def __init__(self, hidden_size: int, eps: float = 1e-6, *, use_native: bool = False) -> None: super().__init__() self.weight = nn.Parameter(torch.ones(hidden_size)) self.variance_epsilon = eps + self.use_native = use_native - def forward(self, hidden: torch.Tensor) -> torch.Tensor: + def forward(self, hidden: torch.Tensor, residual: torch.Tensor | None = None) -> torch.Tensor: + if self.use_native: + return rms_norm(hidden, self.weight, self.variance_epsilon, residual, match_torch=True) value = hidden.float() value = value * torch.rsqrt(value.square().mean(-1, keepdim=True) + self.variance_epsilon) - return self.weight * value.to(hidden.dtype) + result = self.weight * value.to(hidden.dtype) + return result if residual is None else residual + result diff --git a/vllm_rlt/models/ouro.py b/vllm_rlt/models/ouro.py index 31b37f9c..90e00427 100644 --- a/vllm_rlt/models/ouro.py +++ b/vllm_rlt/models/ouro.py @@ -202,10 +202,16 @@ def __init__(self, config: OuroConfig, layer_idx: int) -> None: super().__init__() self.self_attn = OuroAttention(config, layer_idx) self.mlp = OuroMLP(config) - self.input_layernorm = RMSNorm(config.hidden_size, eps=config.rms_norm_eps) - self.input_layernorm_2 = RMSNorm(config.hidden_size, eps=config.rms_norm_eps) - self.post_attention_layernorm = RMSNorm(config.hidden_size, eps=config.rms_norm_eps) - self.post_attention_layernorm_2 = RMSNorm(config.hidden_size, eps=config.rms_norm_eps) + self.input_layernorm = RMSNorm(config.hidden_size, eps=config.rms_norm_eps, use_native=True) + self.input_layernorm_2 = RMSNorm( + config.hidden_size, eps=config.rms_norm_eps, use_native=True + ) + self.post_attention_layernorm = RMSNorm( + config.hidden_size, eps=config.rms_norm_eps, use_native=True + ) + self.post_attention_layernorm_2 = RMSNorm( + config.hidden_size, eps=config.rms_norm_eps, use_native=True + ) def forward( self, @@ -215,9 +221,9 @@ def forward( cache: "KVCacheManager", ) -> torch.Tensor: attention = self.self_attn(self.input_layernorm(hidden), position_embeddings, batch, cache) - hidden = hidden + self.input_layernorm_2(attention) - return hidden + self.post_attention_layernorm_2( - self.mlp(self.post_attention_layernorm(hidden)) + hidden = self.input_layernorm_2(attention, residual=hidden) + return self.post_attention_layernorm_2( + self.mlp(self.post_attention_layernorm(hidden)), residual=hidden ) @@ -228,7 +234,7 @@ def __init__(self, config: OuroConfig) -> None: self.layers = nn.ModuleList( OuroDecoderLayer(config, layer) for layer in range(config.num_hidden_layers) ) - self.norm = RMSNorm(config.hidden_size, eps=config.rms_norm_eps) + self.norm = RMSNorm(config.hidden_size, eps=config.rms_norm_eps, use_native=True) self.rotary_emb = RotaryEmbedding(head_dim=config.head_dim, rope_theta=config.rope_theta) self.early_exit_gate = nn.Linear(config.hidden_size, 1, bias=True) From 59f964cc741d38643fa22edaafb931da67291f8e Mon Sep 17 00:00:00 2001 From: bjf-frz Date: Tue, 3 Nov 2026 03:59:44 +0000 Subject: [PATCH 2/2] docs: illustrate RMSNorm graph execution --- .../performance/ouro-rmsnorm-graph-b300.png | Bin 0 -> 185028 bytes docs/kernels.md | 6 ++++++ 2 files changed, 6 insertions(+) create mode 100644 docs/assets/performance/ouro-rmsnorm-graph-b300.png diff --git a/docs/assets/performance/ouro-rmsnorm-graph-b300.png b/docs/assets/performance/ouro-rmsnorm-graph-b300.png new file mode 100644 index 0000000000000000000000000000000000000000..2e69d2c78c4e2670a344c2e08589e5a71fb0785e GIT binary patch literal 185028 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%0A*1V1#{HRU=h_65Ub79?Z{1P| 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 qBEHg|1= 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 literal 0 HcmV?d00001 diff --git a/docs/kernels.md b/docs/kernels.md index 37325e91..93483333 100644 --- a/docs/kernels.md +++ b/docs/kernels.md @@ -212,3 +212,9 @@ Its different intermediate rounding is reported separately from the reference semantics. The general native path can use a different reduction order than PyTorch; use the `rlt_torch_order` measurements when assessing Ouro's actual compatibility path. + +For one example of the model-level execution change, see the +[matched B300 Graph timeline](assets/performance/ouro-rmsnorm-graph-b300.png) +for an Ouro-1.4B BF16 request with 128 input tokens and 2 output tokens. The +profiler trace illustrates work and launch counts; use separate unprofiled +measurements for latency and throughput.