Skip to content

cuda: use the float4 RMS norm path by default, with a pinned rounding order - #418

Merged
bri-prism merged 3 commits into
prismfrom
cuda/rms-norm-vec-default
Oct 30, 2026
Merged

bri-prism merged 3 commits into
prismfrom
cuda/rms-norm-vec-default

Conversation

@bri-prism

@bri-prism bri-prism commented Oct 29, 2026 •

Copy link
Copy Markdown
Collaborator

Depends on #352 (stacked on its branch; the diff here is one commit).

What

  • The float4 CUDA RMS norm path is now the default. GGML_CUDA_RMS_NORM_VECTOR=0 restores the scalar reduction order.
  • The float4 path's rounding order (sum of squares, row scale, multiply-add) is pinned with explicit intrinsics.

Why

  • The upstream merge kept the scalar reduction as the default to keep packed-model output unchanged. The float4 path
    is faster on every model we measured, and the output change is small (below).
  • With fast math, sum / ncols + eps and the sum of squares could round differently in different template instances.
    Pinning the order makes the path reproducible, so fused kernels that include an RMS norm can match it bit for bit.

How

  • One switch read once (rms_norm_vector_enabled()), used by the existing dispatch. No other kernels change.

Testing

  • test-backend-ops RMS_NORM, NORM, ADD, MUL, MUL_MAT_VEC_FUSION pass (CUDA vs CPU).
  • KLD against the scalar path (wikitext-2, c = 512, 64 chunks): 27B PQ2_0 2.0e-4 (99.4% same top token), 9B PQ2_0
    2.9e-4 (99.2%, PPL ratio 1.0013 +- 0.0004). With GGML_CUDA_RMS_NORM_VECTOR=0 the output is identical to Merge upstream master (d854d98ba) into prism #352.
  • H200 tg128 vs Merge upstream master (d854d98ba) into prism #352 (alternating runs): 27B PQ2_0 174.7 -> 181.5 (+3.9%), 9B PQ2_0 411.9 -> 412.2, 4B PTQ1_0
    516.2 -> 534.0 (+3.4%). Models whose norms do not go through the fused norm + Hadamard kernels gain the most (up to about
    +7% decode). Prefill +0.3-2.5%.

The upstream merge kept the scalar CUDA RMS reduction as the default and the
float4 path behind GGML_CUDA_RMS_NORM_VECTOR=1. Make the float4 path the
default (GGML_CUDA_RMS_NORM_VECTOR=0 restores the scalar order) and pin its
rounding order (sum of squares, row scale, multiply-add) with explicit
intrinsics, so fused kernels can reproduce it bit for bit.
…s exact

With the float4 RMS norm path as the default, the tail kernel needs the same
reduction order to stay bit-identical. Add a float4 variant that mirrors
rms_norm_f32's float4 path (pinned sums and row scales), and fuse a tail only
when all of its norms take the same path at a width the fused kernel
reproduces.
@bri-prism
bri-prism changed the base branch from merge/upstream-20261011 to prism October 30, 2026 18:03
@bri-prism
bri-prism merged commit b2f181d into prism Oct 30, 2026
3 of 11 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant