Per-head RMSNorm on Q and K (Qwen3-style QK norm) More...
#include <math.h>#include <stddef.h>#include <stdlib.h>#include <string.h>Go to the source code of this file.
Enumerations | |
| enum | QKNormISA { QK_NORM_ISA_SCALAR = 0 , QK_NORM_ISA_AVX = 1 , QK_NORM_ISA_AVX2 = 2 , QK_NORM_ISA_AVX_VNNI = 3 , QK_NORM_ISA_AUTO = -1 } |
Functions | |
| void | q_norm_forward (float *q, const float *q_gamma, int num_heads, int num_tokens, int head_dim, float eps) |
| void | qk_norm_backward (const float *d_q_out, const float *d_k_out, const float *q_in, const float *k_in, const float *q_gamma, const float *k_gamma, float *d_q_in, float *d_k_in, float *d_q_gamma, float *d_k_gamma, int num_heads, int num_kv_heads, int num_tokens, int head_dim, float eps) |
| int | qk_norm_backward_last_isa (void) |
| static void | qk_norm_compute_rstd (const float *input, float *rstd_cache, int rows, int head_dim, float eps) |
| static void | qk_norm_compute_rstd_scalar (const float *input, float *rstd_cache, int rows, int head_dim, float eps) |
| void | qk_norm_forward (float *q, float *k, const float *q_gamma, const float *k_gamma, int num_heads, int num_kv_heads, int num_tokens, int head_dim, float eps) |
| void | qk_norm_forward_fp64_sum (float *q, float *k, const float *q_gamma, const float *k_gamma, int num_heads, int num_kv_heads, int num_tokens, int head_dim, float eps) |
| void | qk_norm_forward_llama_production (float *q, float *k, const float *q_gamma, const float *k_gamma, int num_heads, int num_kv_heads, int num_tokens, int head_dim, float eps) |
| void | qk_norm_forward_pytorch_bf16_storage (float *q, float *k, const float *q_gamma, const float *k_gamma, int num_heads, int num_kv_heads, int num_tokens, int head_dim, float eps) |
| void | qk_norm_forward_qwen4_pytorch_bf16_storage (float *q, float *k, const float *q_gamma, const float *k_gamma, int num_heads, int num_kv_heads, int num_tokens, int head_dim, float eps) |
| static int | qk_norm_isa_compiled (QKNormISA isa) |
| static QKNormISA | qk_norm_parse_forced_isa (void) |
| static QKNormISA | qk_norm_select_isa (void) |
| void | rmsnorm_backward (const float *d_output, const float *input, const float *gamma, const float *rstd_cache, float *d_input, float *d_gamma, int tokens, int d_model, int aligned_embed_dim) |
| void | rmsnorm_forward (const float *input, const float *gamma, float *output, float *rstd_cache, int tokens, int d_model, int aligned_embed_dim, float eps) |
| void | rmsnorm_forward_fp64_sum (const float *input, const float *gamma, float *output, float *rstd_cache, int tokens, int d_model, int aligned_embed_dim, float eps) |
| void | rmsnorm_forward_llama_production (const float *input, const float *gamma, float *output, float *rstd_cache, int tokens, int d_model, int aligned_embed_dim, float eps) |
| void | rmsnorm_forward_pytorch_bf16_storage (const float *input, const float *gamma, float *output, float *rstd_cache, int tokens, int d_model, int aligned_embed_dim, float eps) |
| void | rmsnorm_forward_qwen3next_pytorch_bf16_storage (const float *input, const float *gamma, float *output, float *rstd_cache, int tokens, int d_model, int aligned_embed_dim, float eps) |
Variables | |
| static int | g_qk_norm_last_isa = QK_NORM_ISA_SCALAR |
Per-head RMSNorm on Q and K (Qwen3-style QK norm)
After changes: make v7-qk-norm-backward-parity-isa python unittest/test_qk_norm.py
QK Norm normalizes each head's query/key vectors independently before RoPE. This stabilizes Q*K^T dot products before softmax, preventing attention collapse from large magnitude vectors.
Why only Q and K, not V? V does not participate in the attention score computation (Q*K^T). The softmax saturation problem comes from large Q*K^T values, so only Q and K magnitudes matter. V is linearly combined after softmax weights are computed – normalizing it would change output scale but not fix attention stability.
Data layout after QKV projection (head-major): Q: [num_heads, num_tokens, head_dim] contiguous K: [num_kv_heads, num_tokens, head_dim] contiguous
We treat Q as [num_heads * num_tokens] rows of [head_dim] elements. rmsnorm_forward normalizes each row independently. The gamma weight [head_dim] is shared across all heads (Qwen3 design: one gamma per Q, one per K).
Definition in file qk_norm_kernels.c.
| enum QKNormISA |
| Enumerator | |
|---|---|
| QK_NORM_ISA_SCALAR | |
| QK_NORM_ISA_AVX | |
| QK_NORM_ISA_AVX2 | |
| QK_NORM_ISA_AVX_VNNI | |
| QK_NORM_ISA_AUTO | |
Definition at line 101 of file qk_norm_kernels.c.
| void q_norm_forward | ( | float * | q, |
| const float * | q_gamma, | ||
| int | num_heads, | ||
| int | num_tokens, | ||
| int | head_dim, | ||
| float | eps | ||
| ) |
Forward pass for Gemma4-assistant q-only per-head RMSNorm.
Some Gemma4 assistant/drafter checkpoints project only Q and then reuse Q as the shared K/V stream. This wrapper keeps that public kernel contract explicit while reusing the same row-wise RMSNorm implementation as qk_norm_forward.
Definition at line 405 of file qk_norm_kernels.c.
References rmsnorm_forward().
| void qk_norm_backward | ( | const float * | d_q_out, |
| const float * | d_k_out, | ||
| const float * | q_in, | ||
| const float * | k_in, | ||
| const float * | q_gamma, | ||
| const float * | k_gamma, | ||
| float * | d_q_in, | ||
| float * | d_k_in, | ||
| float * | d_q_gamma, | ||
| float * | d_k_gamma, | ||
| int | num_heads, | ||
| int | num_kv_heads, | ||
| int | num_tokens, | ||
| int | head_dim, | ||
| float | eps | ||
| ) |
Backward pass for per-head QK RMSNorm.
This computes:
Implementation is reference-first and deterministic: 1) recompute row rstd values from saved q/k inputs 2) call rmsnorm_backward on flattened [rows, head_dim] views
Definition at line 427 of file qk_norm_kernels.c.
References qk_norm_compute_rstd(), and rmsnorm_backward().
| int qk_norm_backward_last_isa | ( | void | ) |
|
static |
Definition at line 279 of file qk_norm_kernels.c.
References g_qk_norm_last_isa, qk_norm_compute_rstd_scalar(), QK_NORM_ISA_AUTO, QK_NORM_ISA_AVX, QK_NORM_ISA_AVX2, QK_NORM_ISA_AVX_VNNI, QK_NORM_ISA_SCALAR, and qk_norm_select_isa().
Referenced by qk_norm_backward().
|
static |
Definition at line 178 of file qk_norm_kernels.c.
Referenced by qk_norm_compute_rstd().
| void qk_norm_forward | ( | float * | q, |
| float * | k, | ||
| const float * | q_gamma, | ||
| const float * | k_gamma, | ||
| int | num_heads, | ||
| int | num_kv_heads, | ||
| int | num_tokens, | ||
| int | head_dim, | ||
| float | eps | ||
| ) |
Per-head RMSNorm on Q and K.
| q | Q scratch buffer [num_heads * num_tokens * head_dim], in-place |
| k | K scratch buffer [num_kv_heads * num_tokens * head_dim], in-place |
| q_gamma | Q norm gamma weights [head_dim] |
| k_gamma | K norm gamma weights [head_dim] |
| num_heads | Number of query heads (e.g. 32 for Qwen3-8B) |
| num_kv_heads | Number of KV heads (e.g. 8 for Qwen3-8B with GQA) |
| num_tokens | Number of tokens (1 for decode, T for prefill) |
| head_dim | Dimension per head (e.g. 128) |
| eps | RMSNorm epsilon (e.g. 1e-6) |
Definition at line 326 of file qk_norm_kernels.c.
References rmsnorm_forward().
| void qk_norm_forward_fp64_sum | ( | float * | q, |
| float * | k, | ||
| const float * | q_gamma, | ||
| const float * | k_gamma, | ||
| int | num_heads, | ||
| int | num_kv_heads, | ||
| int | num_tokens, | ||
| int | head_dim, | ||
| float | eps | ||
| ) |
Definition at line 342 of file qk_norm_kernels.c.
References rmsnorm_forward_fp64_sum().
| void qk_norm_forward_llama_production | ( | float * | q, |
| float * | k, | ||
| const float * | q_gamma, | ||
| const float * | k_gamma, | ||
| int | num_heads, | ||
| int | num_kv_heads, | ||
| int | num_tokens, | ||
| int | head_dim, | ||
| float | eps | ||
| ) |
Definition at line 353 of file qk_norm_kernels.c.
References rmsnorm_forward_llama_production().
| void qk_norm_forward_pytorch_bf16_storage | ( | float * | q, |
| float * | k, | ||
| const float * | q_gamma, | ||
| const float * | k_gamma, | ||
| int | num_heads, | ||
| int | num_kv_heads, | ||
| int | num_tokens, | ||
| int | head_dim, | ||
| float | eps | ||
| ) |
Definition at line 366 of file qk_norm_kernels.c.
References rmsnorm_forward_pytorch_bf16_storage().
| void qk_norm_forward_qwen4_pytorch_bf16_storage | ( | float * | q, |
| float * | k, | ||
| const float * | q_gamma, | ||
| const float * | k_gamma, | ||
| int | num_heads, | ||
| int | num_kv_heads, | ||
| int | num_tokens, | ||
| int | head_dim, | ||
| float | eps | ||
| ) |
Definition at line 381 of file qk_norm_kernels.c.
References rmsnorm_forward_qwen3next_pytorch_bf16_storage().
|
static |
Definition at line 138 of file qk_norm_kernels.c.
References QK_NORM_ISA_AVX, QK_NORM_ISA_AVX2, QK_NORM_ISA_AVX_VNNI, and QK_NORM_ISA_SCALAR.
Referenced by qk_norm_select_isa().
|
static |
Definition at line 116 of file qk_norm_kernels.c.
References QK_NORM_ISA_AUTO, QK_NORM_ISA_AVX, QK_NORM_ISA_AVX2, QK_NORM_ISA_AVX_VNNI, and QK_NORM_ISA_SCALAR.
Referenced by qk_norm_select_isa().
|
static |
Definition at line 160 of file qk_norm_kernels.c.
References QK_NORM_ISA_AUTO, QK_NORM_ISA_AVX, QK_NORM_ISA_AVX2, QK_NORM_ISA_AVX_VNNI, qk_norm_isa_compiled(), QK_NORM_ISA_SCALAR, and qk_norm_parse_forced_isa().
Referenced by qk_norm_compute_rstd().
| void rmsnorm_backward | ( | const float * | d_output, |
| const float * | input, | ||
| const float * | gamma, | ||
| const float * | rstd_cache, | ||
| float * | d_input, | ||
| float * | d_gamma, | ||
| int | tokens, | ||
| int | d_model, | ||
| int | aligned_embed_dim | ||
| ) |
RMSNorm backward pass
test_rmsnorm.py::TestRMSNormBackward::test_backward_tokens
test_rmsnorm.py::TestRMSNormBackward::test_backward_single
test_parity.py::test_rmsnorm_backward_parity
Computes dX and dGamma given dY, X, gamma, and cached rstd. dX_i = rstd * (dY_i * gamma_i - x_hat_i * m) dGamma_i = sum_t (dY_i * x_hat_i)
After changes: make test && make llamacpp-parity-full
Definition at line 715 of file rmsnorm_kernels.c.
Referenced by qk_norm_backward().
| void rmsnorm_forward | ( | const float * | input, |
| const float * | gamma, | ||
| float * | output, | ||
| float * | rstd_cache, | ||
| int | tokens, | ||
| int | d_model, | ||
| int | aligned_embed_dim, | ||
| float | eps | ||
| ) |
Definition at line 621 of file rmsnorm_kernels.c.
Referenced by q_norm_forward(), qk_norm_forward(), and rmsnorm_forward_kv_lora().
| void rmsnorm_forward_fp64_sum | ( | const float * | input, |
| const float * | gamma, | ||
| float * | output, | ||
| float * | rstd_cache, | ||
| int | tokens, | ||
| int | d_model, | ||
| int | aligned_embed_dim, | ||
| float | eps | ||
| ) |
Definition at line 137 of file rmsnorm_kernels.c.
Referenced by qk_norm_forward_fp64_sum().
| void rmsnorm_forward_llama_production | ( | const float * | input, |
| const float * | gamma, | ||
| float * | output, | ||
| float * | rstd_cache, | ||
| int | tokens, | ||
| int | d_model, | ||
| int | aligned_embed_dim, | ||
| float | eps | ||
| ) |
Definition at line 196 of file rmsnorm_kernels.c.
Referenced by qk_norm_forward_llama_production().
| void rmsnorm_forward_pytorch_bf16_storage | ( | const float * | input, |
| const float * | gamma, | ||
| float * | output, | ||
| float * | rstd_cache, | ||
| int | tokens, | ||
| int | d_model, | ||
| int | aligned_embed_dim, | ||
| float | eps | ||
| ) |
Definition at line 395 of file rmsnorm_kernels.c.
Referenced by qk_norm_forward_pytorch_bf16_storage().
| void rmsnorm_forward_qwen3next_pytorch_bf16_storage | ( | const float * | input, |
| const float * | gamma, | ||
| float * | output, | ||
| float * | rstd_cache, | ||
| int | tokens, | ||
| int | d_model, | ||
| int | aligned_embed_dim, | ||
| float | eps | ||
| ) |
Definition at line 424 of file rmsnorm_kernels.c.
Referenced by qk_norm_forward_qwen4_pytorch_bf16_storage().
|
static |
Definition at line 109 of file qk_norm_kernels.c.
Referenced by qk_norm_backward_last_isa(), and qk_norm_compute_rstd().