← Back to C-Kernel-Engine Docs Doxygen Source Documentation
 
Loading...
Searching...
No Matches
rmsnorm_kernels.c File Reference

RMSNorm forward/backward kernels with SIMD (SSE/AVX/AVX512) More...

#include "bf16_utils.h"
#include "ckernel_engine.h"
#include <math.h>
#include <stddef.h>
#include <stdlib.h>

Go to the source code of this file.

Functions

void gemma4_v_norm_forward (const float *input, float *output, float *rstd_cache, int tokens, int num_kv_heads, int head_dim, float eps)
 
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)
 
static void rmsnorm_backward_strict_scalar (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_kv_lora (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_no_weight (const float *input, 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)
 
static void rmsnorm_forward_pytorch_bf16_storage_impl (const float *input, const float *gamma, float *output, float *rstd_cache, int tokens, int d_model, int input_stride, int output_stride, float eps, int qwen3next_weight_order)
 
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)
 
static void rmsnorm_forward_strict_scalar (const float *input, const float *gamma, float *output, float *rstd_cache, int tokens, int d_model, int input_stride, int output_stride, float eps)
 
void rmsnorm_forward_strided_f32 (const float *input, const float *gamma, float *output, float *rstd_cache, int tokens, int d_model, int input_stride, int output_stride, float eps)
 
void rmsnorm_forward_strided_pytorch_bf16_storage (const float *input, const float *gamma, float *output, float *rstd_cache, int tokens, int d_model, int input_stride, int output_stride, float eps)
 
static float rmsnorm_llama_production_rstd (float mean_eps)
 

Detailed Description

RMSNorm forward/backward kernels with SIMD (SSE/AVX/AVX512)

CK-ENGINE KERNEL RULES:

  1. NO malloc/free - memory via bump allocator, pointers passed in
  2. NO OpenMP - parallelization at orchestrator/codegen layer
  3. API must define: inputs, outputs, workspace, and memory layouts
  4. Pure computation - deterministic, no side effects

After changes: make test && make llamacpp-parity-full

RMSNorm: y[i] = gamma[i] * x[i] / sqrt(mean(x^2) + eps)

Definition in file rmsnorm_kernels.c.

Function Documentation

◆ gemma4_v_norm_forward()

void gemma4_v_norm_forward ( const float *  input,
float *  output,
float *  rstd_cache,
int  tokens,
int  num_kv_heads,
int  head_dim,
float  eps 
)

Definition at line 687 of file rmsnorm_kernels.c.

694{
695 if (!input || !output || tokens <= 0 || num_kv_heads <= 0 || head_dim <= 0) {
696 return;
697 }
698 rmsnorm_forward_no_weight(input, output, rstd_cache,
699 tokens * num_kv_heads, head_dim, head_dim, eps);
700}
void rmsnorm_forward_no_weight(const float *input, float *output, float *rstd_cache, int tokens, int d_model, int aligned_embed_dim, float eps)

References rmsnorm_forward_no_weight().

◆ rmsnorm_backward()

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:

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.

724{
725 int T = tokens;
726 int D = d_model;
727 int aligned = aligned_embed_dim;
728
730 rmsnorm_backward_strict_scalar(d_output, input, gamma, rstd_cache, d_input, d_gamma, T, D, aligned);
731 return;
732 }
733
734 // Zero parameter gradients
735#if defined(__AVX512F__)
736 {
737 int d = 0;
738 for (; d + 16 <= D; d += 16) {
739 _mm512_storeu_ps(&d_gamma[d], _mm512_setzero_ps());
740 }
741 for (; d < D; ++d) {
742 d_gamma[d] = 0.0f;
743 }
744 }
745#elif defined(__AVX__)
746 {
747 int d = 0;
748 for (; d + 8 <= D; d += 8) {
749 _mm256_storeu_ps(&d_gamma[d], _mm256_setzero_ps());
750 }
751 for (; d < D; ++d) {
752 d_gamma[d] = 0.0f;
753 }
754 }
755#else
756 for (int d = 0; d < D; ++d) {
757 d_gamma[d] = 0.0f;
758 }
759#endif
760
761 for (int t = 0; t < T; ++t) {
762 const float *x = input + (size_t)t * aligned;
763 const float *dY = d_output + (size_t)t * aligned;
764 float *dX = d_input + (size_t)t * aligned;
765
766 float rstd = rstd_cache[t];
767
768#if defined(__AVX512F__)
769 // Compute m = (1/D) * sum_j (dY_j * gamma_j * x_hat_j)
770 __m512 rstd_vec = _mm512_set1_ps(rstd);
771 __m512 sum_vec = _mm512_setzero_ps();
772 int d = 0;
773
774 for (; d + 16 <= D; d += 16) {
775 __m512 xv = _mm512_loadu_ps(&x[d]);
776 __m512 dyv = _mm512_loadu_ps(&dY[d]);
777 __m512 gv = _mm512_loadu_ps(&gamma[d]);
778 __m512 x_hat = _mm512_mul_ps(xv, rstd_vec);
779 // sum += dY * gamma * x_hat
780 __m512 prod = _mm512_mul_ps(dyv, gv);
781 sum_vec = _mm512_fmadd_ps(prod, x_hat, sum_vec);
782 }
783 float sum_dY_g_xhat = _mm512_reduce_add_ps(sum_vec);
784
785 // Handle remaining elements
786 for (; d < D; ++d) {
787 float x_hat = x[d] * rstd;
788 sum_dY_g_xhat += dY[d] * gamma[d] * x_hat;
789 }
790 float m = sum_dY_g_xhat / (float)D;
791
792 // Compute dX and accumulate dGamma (vectorized)
793 __m512 m_vec = _mm512_set1_ps(m);
794 d = 0;
795 for (; d + 16 <= D; d += 16) {
796 __m512 xv = _mm512_loadu_ps(&x[d]);
797 __m512 dyv = _mm512_loadu_ps(&dY[d]);
798 __m512 gv = _mm512_loadu_ps(&gamma[d]);
799 __m512 dgv = _mm512_loadu_ps(&d_gamma[d]);
800
801 __m512 x_hat = _mm512_mul_ps(xv, rstd_vec);
802
803 // dX = rstd * (dY * gamma - x_hat * m)
804 __m512 dy_g = _mm512_mul_ps(dyv, gv);
805 __m512 xhat_m = _mm512_mul_ps(x_hat, m_vec);
806 __m512 diff = _mm512_sub_ps(dy_g, xhat_m);
807 __m512 dxv = _mm512_mul_ps(rstd_vec, diff);
808 _mm512_storeu_ps(&dX[d], dxv);
809
810 // d_gamma += dY * x_hat
811 dgv = _mm512_fmadd_ps(dyv, x_hat, dgv);
812 _mm512_storeu_ps(&d_gamma[d], dgv);
813 }
814 // Handle remaining elements
815 for (; d < D; ++d) {
816 float x_hat = x[d] * rstd;
817 float dy = dY[d];
818 dX[d] = rstd * (dy * gamma[d] - x_hat * m);
819 d_gamma[d] += dy * x_hat;
820 }
821
822#elif defined(__AVX__)
823 // Compute m = (1/D) * sum_j (dY_j * gamma_j * x_hat_j)
824 __m256 rstd_vec = _mm256_set1_ps(rstd);
825 __m256 sum_vec = _mm256_setzero_ps();
826 int d = 0;
827
828 for (; d + 8 <= D; d += 8) {
829 __m256 xv = _mm256_loadu_ps(&x[d]);
830 __m256 dyv = _mm256_loadu_ps(&dY[d]);
831 __m256 gv = _mm256_loadu_ps(&gamma[d]);
832 __m256 x_hat = _mm256_mul_ps(xv, rstd_vec);
833 // sum += dY * gamma * x_hat (no FMA, use mul + mul + add)
834 __m256 prod = _mm256_mul_ps(dyv, gv);
835 __m256 prod2 = _mm256_mul_ps(prod, x_hat);
836 sum_vec = _mm256_add_ps(sum_vec, prod2);
837 }
838 float sum_dY_g_xhat = hsum256_ps_rmsnorm(sum_vec);
839
840 // Handle remaining elements
841 for (; d < D; ++d) {
842 float x_hat = x[d] * rstd;
843 sum_dY_g_xhat += dY[d] * gamma[d] * x_hat;
844 }
845 float m = sum_dY_g_xhat / (float)D;
846
847 // Compute dX and accumulate dGamma (vectorized)
848 __m256 m_vec = _mm256_set1_ps(m);
849 d = 0;
850 for (; d + 8 <= D; d += 8) {
851 __m256 xv = _mm256_loadu_ps(&x[d]);
852 __m256 dyv = _mm256_loadu_ps(&dY[d]);
853 __m256 gv = _mm256_loadu_ps(&gamma[d]);
854 __m256 dgv = _mm256_loadu_ps(&d_gamma[d]);
855
856 __m256 x_hat = _mm256_mul_ps(xv, rstd_vec);
857
858 // dX = rstd * (dY * gamma - x_hat * m)
859 __m256 dy_g = _mm256_mul_ps(dyv, gv);
860 __m256 xhat_m = _mm256_mul_ps(x_hat, m_vec);
861 __m256 diff = _mm256_sub_ps(dy_g, xhat_m);
862 __m256 dxv = _mm256_mul_ps(rstd_vec, diff);
863 _mm256_storeu_ps(&dX[d], dxv);
864
865 // d_gamma += dY * x_hat
866 __m256 dy_xhat = _mm256_mul_ps(dyv, x_hat);
867 dgv = _mm256_add_ps(dgv, dy_xhat);
868 _mm256_storeu_ps(&d_gamma[d], dgv);
869 }
870 // Handle remaining elements
871 for (; d < D; ++d) {
872 float x_hat = x[d] * rstd;
873 float dy = dY[d];
874 dX[d] = rstd * (dy * gamma[d] - x_hat * m);
875 d_gamma[d] += dy * x_hat;
876 }
877
878#else
879 // Scalar fallback
880 // Compute m = (1/D) * sum_j (dY_j * gamma_j * x_hat_j)
881 float sum_dY_g_xhat = 0.0f;
882 for (int d = 0; d < D; ++d) {
883 float x_hat = x[d] * rstd;
884 sum_dY_g_xhat += dY[d] * gamma[d] * x_hat;
885 }
886 float m = sum_dY_g_xhat / (float)D;
887
888 // Compute dX and accumulate dGamma
889 for (int d = 0; d < D; ++d) {
890 float x_hat = x[d] * rstd;
891 float dy = dY[d];
892 dX[d] = rstd * (dy * gamma[d] - x_hat * m);
893 d_gamma[d] += dy * x_hat;
894 }
895#endif
896
897 // Zero padding gradients (if any)
898 for (int d = D; d < aligned; ++d) {
899 dX[d] = 0.0f;
900 }
901 }
902}
int ck_strict_parity_enabled(void)
static void rmsnorm_backward_strict_scalar(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)

References ck_strict_parity_enabled(), and rmsnorm_backward_strict_scalar().

Referenced by ck_layer_backward_rmsnorm_swiglu(), qk_norm_backward(), rmsnorm_backward_int4(), and rmsnorm_backward_int8().

◆ rmsnorm_backward_strict_scalar()

static void rmsnorm_backward_strict_scalar ( 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 
)
static

Definition at line 439 of file rmsnorm_kernels.c.

448{
449 const float inv_d = 1.0f / (float)d_model;
450 for (int d = 0; d < d_model; ++d) {
451 d_gamma[d] = 0.0f;
452 }
453
454 for (int t = 0; t < tokens; ++t) {
455 const float *x = input + (size_t)t * (size_t)aligned_embed_dim;
456 const float *dY = d_output + (size_t)t * (size_t)aligned_embed_dim;
457 float *dX = d_input + (size_t)t * (size_t)aligned_embed_dim;
458 const float rstd = rstd_cache[t];
459
460 float sum_dY_g_xhat = 0.0f;
461 for (int d = 0; d < d_model; ++d) {
462 const float x_hat = x[d] * rstd;
463 const float grad_x_hat = dY[d] * gamma[d];
464 sum_dY_g_xhat += x_hat * grad_x_hat;
465 }
466
467 for (int d = 0; d < d_model; ++d) {
468 const float x_hat = x[d] * rstd;
469 const float grad_x_hat = dY[d] * gamma[d];
470 dX[d] = (grad_x_hat - (x_hat * inv_d) * sum_dY_g_xhat) * rstd;
471 d_gamma[d] += dY[d] * x_hat;
472 }
473 for (int d = d_model; d < aligned_embed_dim; ++d) {
474 dX[d] = 0.0f;
475 }
476 }
477}

Referenced by rmsnorm_backward().

◆ rmsnorm_forward()

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.

629{
631 input,
632 gamma,
633 output,
634 rstd_cache,
635 tokens,
636 d_model,
637 aligned_embed_dim,
638 aligned_embed_dim,
639 eps
640 );
641}
void rmsnorm_forward_strided_f32(const float *input, const float *gamma, float *output, float *rstd_cache, int tokens, int d_model, int input_stride, int output_stride, float eps)

References rmsnorm_forward_strided_f32().

Referenced by ck_layer_forward_rmsnorm_swiglu(), ck_layer_forward_rmsnorm_swiglu_decode(), ck_layer_forward_rmsnorm_swiglu_decode_fused(), ck_layer_forward_rmsnorm_swiglu_decode_fused_attn_impl(), ck_layer_forward_rmsnorm_swiglu_decode_q4_k(), ck_layer_forward_rmsnorm_swiglu_decode_quant(), ck_layer_forward_rmsnorm_swiglu_q4_k(), ck_layer_forward_rmsnorm_swiglu_quant(), ck_layer_forward_rmsnorm_swiglu_ref(), ck_test_rmsnorm(), mega_fused_attention_decode_q5_0(), mega_fused_attention_decode_q5_0_parallel_simd(), mega_fused_outproj_mlp_prefill(), model_decode_token(), model_decode_token(), model_decode_token(), model_decode_token(), model_forward_prefill_impl(), model_forward_prefill_impl(), model_forward_prefill_impl(), model_forward_prefill_impl(), model_layer_0_decode(), model_layer_0_decode(), model_layer_0_decode(), model_layer_0_decode(), model_layer_0_prefill(), model_layer_0_prefill(), model_layer_0_prefill(), model_layer_0_prefill(), model_layer_10_decode(), model_layer_10_decode(), model_layer_10_decode(), model_layer_10_decode(), model_layer_10_prefill(), model_layer_10_prefill(), model_layer_10_prefill(), model_layer_10_prefill(), model_layer_11_decode(), model_layer_11_decode(), model_layer_11_decode(), model_layer_11_decode(), model_layer_11_prefill(), model_layer_11_prefill(), model_layer_11_prefill(), model_layer_11_prefill(), model_layer_12_decode(), model_layer_12_decode(), model_layer_12_decode(), model_layer_12_decode(), model_layer_12_prefill(), model_layer_12_prefill(), model_layer_12_prefill(), model_layer_12_prefill(), model_layer_13_decode(), model_layer_13_decode(), model_layer_13_decode(), model_layer_13_decode(), model_layer_13_prefill(), model_layer_13_prefill(), model_layer_13_prefill(), model_layer_13_prefill(), model_layer_14_decode(), model_layer_14_decode(), model_layer_14_decode(), model_layer_14_decode(), model_layer_14_prefill(), model_layer_14_prefill(), model_layer_14_prefill(), model_layer_14_prefill(), model_layer_15_decode(), model_layer_15_decode(), model_layer_15_decode(), model_layer_15_decode(), model_layer_15_prefill(), model_layer_15_prefill(), model_layer_15_prefill(), model_layer_15_prefill(), model_layer_16_decode(), model_layer_16_decode(), model_layer_16_decode(), model_layer_16_decode(), model_layer_16_prefill(), model_layer_16_prefill(), model_layer_16_prefill(), model_layer_16_prefill(), model_layer_17_decode(), model_layer_17_decode(), model_layer_17_decode(), model_layer_17_decode(), model_layer_17_prefill(), model_layer_17_prefill(), model_layer_17_prefill(), model_layer_17_prefill(), model_layer_18_decode(), model_layer_18_decode(), model_layer_18_decode(), model_layer_18_decode(), model_layer_18_prefill(), model_layer_18_prefill(), model_layer_18_prefill(), model_layer_18_prefill(), model_layer_19_decode(), model_layer_19_decode(), model_layer_19_decode(), model_layer_19_decode(), model_layer_19_prefill(), model_layer_19_prefill(), model_layer_19_prefill(), model_layer_19_prefill(), model_layer_1_decode(), model_layer_1_decode(), model_layer_1_decode(), model_layer_1_decode(), model_layer_1_prefill(), model_layer_1_prefill(), model_layer_1_prefill(), model_layer_1_prefill(), model_layer_20_decode(), model_layer_20_decode(), model_layer_20_decode(), model_layer_20_decode(), model_layer_20_prefill(), model_layer_20_prefill(), model_layer_20_prefill(), model_layer_20_prefill(), model_layer_21_decode(), model_layer_21_decode(), model_layer_21_decode(), model_layer_21_decode(), model_layer_21_prefill(), model_layer_21_prefill(), model_layer_21_prefill(), model_layer_21_prefill(), model_layer_22_decode(), model_layer_22_decode(), model_layer_22_decode(), model_layer_22_decode(), model_layer_22_prefill(), model_layer_22_prefill(), model_layer_22_prefill(), model_layer_22_prefill(), model_layer_23_decode(), model_layer_23_decode(), model_layer_23_decode(), model_layer_23_decode(), model_layer_23_prefill(), model_layer_23_prefill(), model_layer_23_prefill(), model_layer_23_prefill(), model_layer_2_decode(), model_layer_2_decode(), model_layer_2_decode(), model_layer_2_decode(), model_layer_2_prefill(), model_layer_2_prefill(), model_layer_2_prefill(), model_layer_2_prefill(), model_layer_3_decode(), model_layer_3_decode(), model_layer_3_decode(), model_layer_3_decode(), model_layer_3_prefill(), model_layer_3_prefill(), model_layer_3_prefill(), model_layer_3_prefill(), model_layer_4_decode(), model_layer_4_decode(), model_layer_4_decode(), model_layer_4_decode(), model_layer_4_prefill(), model_layer_4_prefill(), model_layer_4_prefill(), model_layer_4_prefill(), model_layer_5_decode(), model_layer_5_decode(), model_layer_5_decode(), model_layer_5_decode(), model_layer_5_prefill(), model_layer_5_prefill(), model_layer_5_prefill(), model_layer_5_prefill(), model_layer_6_decode(), model_layer_6_decode(), model_layer_6_decode(), model_layer_6_decode(), model_layer_6_prefill(), model_layer_6_prefill(), model_layer_6_prefill(), model_layer_6_prefill(), model_layer_7_decode(), model_layer_7_decode(), model_layer_7_decode(), model_layer_7_decode(), model_layer_7_prefill(), model_layer_7_prefill(), model_layer_7_prefill(), model_layer_7_prefill(), model_layer_8_decode(), model_layer_8_decode(), model_layer_8_decode(), model_layer_8_decode(), model_layer_8_prefill(), model_layer_8_prefill(), model_layer_8_prefill(), model_layer_8_prefill(), model_layer_9_decode(), model_layer_9_decode(), model_layer_9_decode(), model_layer_9_decode(), model_layer_9_prefill(), model_layer_9_prefill(), model_layer_9_prefill(), model_layer_9_prefill(), q_norm_forward(), qk_norm_forward(), qwen2_0_5b_decode_decode_token(), qwen2_0_5b_decode_decode_token(), qwen2_0_5b_decode_decode_token(), qwen2_0_5b_decode_decode_token(), qwen2_0_5b_decode_decode_token(), qwen2_0_5b_decode_forward_prefill_impl(), qwen2_0_5b_decode_forward_prefill_impl(), qwen2_0_5b_decode_forward_prefill_impl(), qwen2_0_5b_decode_forward_prefill_impl(), qwen2_0_5b_decode_forward_prefill_impl(), qwen2_0_5b_decode_layer_0_decode(), qwen2_0_5b_decode_layer_0_decode(), qwen2_0_5b_decode_layer_0_decode(), qwen2_0_5b_decode_layer_0_decode(), qwen2_0_5b_decode_layer_0_decode(), qwen2_0_5b_decode_layer_0_prefill(), qwen2_0_5b_decode_layer_0_prefill(), qwen2_0_5b_decode_layer_0_prefill(), qwen2_0_5b_decode_layer_0_prefill(), qwen2_0_5b_decode_layer_10_decode(), qwen2_0_5b_decode_layer_10_decode(), qwen2_0_5b_decode_layer_10_decode(), qwen2_0_5b_decode_layer_10_decode(), qwen2_0_5b_decode_layer_10_decode(), qwen2_0_5b_decode_layer_10_prefill(), qwen2_0_5b_decode_layer_10_prefill(), qwen2_0_5b_decode_layer_10_prefill(), qwen2_0_5b_decode_layer_10_prefill(), qwen2_0_5b_decode_layer_11_decode(), qwen2_0_5b_decode_layer_11_decode(), qwen2_0_5b_decode_layer_11_decode(), qwen2_0_5b_decode_layer_11_decode(), qwen2_0_5b_decode_layer_11_decode(), qwen2_0_5b_decode_layer_11_prefill(), qwen2_0_5b_decode_layer_11_prefill(), qwen2_0_5b_decode_layer_11_prefill(), qwen2_0_5b_decode_layer_11_prefill(), qwen2_0_5b_decode_layer_12_decode(), qwen2_0_5b_decode_layer_12_decode(), qwen2_0_5b_decode_layer_12_decode(), qwen2_0_5b_decode_layer_12_decode(), qwen2_0_5b_decode_layer_12_decode(), qwen2_0_5b_decode_layer_12_prefill(), qwen2_0_5b_decode_layer_12_prefill(), qwen2_0_5b_decode_layer_12_prefill(), qwen2_0_5b_decode_layer_12_prefill(), qwen2_0_5b_decode_layer_13_decode(), qwen2_0_5b_decode_layer_13_decode(), qwen2_0_5b_decode_layer_13_decode(), qwen2_0_5b_decode_layer_13_decode(), qwen2_0_5b_decode_layer_13_decode(), qwen2_0_5b_decode_layer_13_prefill(), qwen2_0_5b_decode_layer_13_prefill(), qwen2_0_5b_decode_layer_13_prefill(), qwen2_0_5b_decode_layer_13_prefill(), qwen2_0_5b_decode_layer_14_decode(), qwen2_0_5b_decode_layer_14_decode(), qwen2_0_5b_decode_layer_14_decode(), qwen2_0_5b_decode_layer_14_decode(), qwen2_0_5b_decode_layer_14_decode(), qwen2_0_5b_decode_layer_14_prefill(), qwen2_0_5b_decode_layer_14_prefill(), qwen2_0_5b_decode_layer_14_prefill(), qwen2_0_5b_decode_layer_14_prefill(), qwen2_0_5b_decode_layer_15_decode(), qwen2_0_5b_decode_layer_15_decode(), qwen2_0_5b_decode_layer_15_decode(), qwen2_0_5b_decode_layer_15_decode(), qwen2_0_5b_decode_layer_15_decode(), qwen2_0_5b_decode_layer_15_prefill(), qwen2_0_5b_decode_layer_15_prefill(), qwen2_0_5b_decode_layer_15_prefill(), qwen2_0_5b_decode_layer_15_prefill(), qwen2_0_5b_decode_layer_16_decode(), qwen2_0_5b_decode_layer_16_decode(), qwen2_0_5b_decode_layer_16_decode(), qwen2_0_5b_decode_layer_16_decode(), qwen2_0_5b_decode_layer_16_decode(), qwen2_0_5b_decode_layer_16_prefill(), qwen2_0_5b_decode_layer_16_prefill(), qwen2_0_5b_decode_layer_16_prefill(), qwen2_0_5b_decode_layer_16_prefill(), qwen2_0_5b_decode_layer_17_decode(), qwen2_0_5b_decode_layer_17_decode(), qwen2_0_5b_decode_layer_17_decode(), qwen2_0_5b_decode_layer_17_decode(), qwen2_0_5b_decode_layer_17_decode(), qwen2_0_5b_decode_layer_17_prefill(), qwen2_0_5b_decode_layer_17_prefill(), qwen2_0_5b_decode_layer_17_prefill(), qwen2_0_5b_decode_layer_17_prefill(), qwen2_0_5b_decode_layer_18_decode(), qwen2_0_5b_decode_layer_18_decode(), qwen2_0_5b_decode_layer_18_decode(), qwen2_0_5b_decode_layer_18_decode(), qwen2_0_5b_decode_layer_18_decode(), qwen2_0_5b_decode_layer_18_prefill(), qwen2_0_5b_decode_layer_18_prefill(), qwen2_0_5b_decode_layer_18_prefill(), qwen2_0_5b_decode_layer_18_prefill(), qwen2_0_5b_decode_layer_19_decode(), qwen2_0_5b_decode_layer_19_decode(), qwen2_0_5b_decode_layer_19_decode(), qwen2_0_5b_decode_layer_19_decode(), qwen2_0_5b_decode_layer_19_decode(), qwen2_0_5b_decode_layer_19_prefill(), qwen2_0_5b_decode_layer_19_prefill(), qwen2_0_5b_decode_layer_19_prefill(), qwen2_0_5b_decode_layer_19_prefill(), qwen2_0_5b_decode_layer_1_decode(), qwen2_0_5b_decode_layer_1_decode(), qwen2_0_5b_decode_layer_1_decode(), qwen2_0_5b_decode_layer_1_decode(), qwen2_0_5b_decode_layer_1_decode(), qwen2_0_5b_decode_layer_1_prefill(), qwen2_0_5b_decode_layer_1_prefill(), qwen2_0_5b_decode_layer_1_prefill(), qwen2_0_5b_decode_layer_1_prefill(), qwen2_0_5b_decode_layer_20_decode(), qwen2_0_5b_decode_layer_20_decode(), qwen2_0_5b_decode_layer_20_decode(), qwen2_0_5b_decode_layer_20_decode(), qwen2_0_5b_decode_layer_20_decode(), qwen2_0_5b_decode_layer_20_prefill(), qwen2_0_5b_decode_layer_20_prefill(), qwen2_0_5b_decode_layer_20_prefill(), qwen2_0_5b_decode_layer_20_prefill(), qwen2_0_5b_decode_layer_21_decode(), qwen2_0_5b_decode_layer_21_decode(), qwen2_0_5b_decode_layer_21_decode(), qwen2_0_5b_decode_layer_21_decode(), qwen2_0_5b_decode_layer_21_decode(), qwen2_0_5b_decode_layer_21_prefill(), qwen2_0_5b_decode_layer_21_prefill(), qwen2_0_5b_decode_layer_21_prefill(), qwen2_0_5b_decode_layer_21_prefill(), qwen2_0_5b_decode_layer_22_decode(), qwen2_0_5b_decode_layer_22_decode(), qwen2_0_5b_decode_layer_22_decode(), qwen2_0_5b_decode_layer_22_decode(), qwen2_0_5b_decode_layer_22_decode(), qwen2_0_5b_decode_layer_22_prefill(), qwen2_0_5b_decode_layer_22_prefill(), qwen2_0_5b_decode_layer_22_prefill(), qwen2_0_5b_decode_layer_22_prefill(), qwen2_0_5b_decode_layer_23_decode(), qwen2_0_5b_decode_layer_23_decode(), qwen2_0_5b_decode_layer_23_decode(), qwen2_0_5b_decode_layer_23_decode(), qwen2_0_5b_decode_layer_23_decode(), qwen2_0_5b_decode_layer_23_prefill(), qwen2_0_5b_decode_layer_23_prefill(), qwen2_0_5b_decode_layer_23_prefill(), qwen2_0_5b_decode_layer_23_prefill(), qwen2_0_5b_decode_layer_2_decode(), qwen2_0_5b_decode_layer_2_decode(), qwen2_0_5b_decode_layer_2_decode(), qwen2_0_5b_decode_layer_2_decode(), qwen2_0_5b_decode_layer_2_decode(), qwen2_0_5b_decode_layer_2_prefill(), qwen2_0_5b_decode_layer_2_prefill(), qwen2_0_5b_decode_layer_2_prefill(), qwen2_0_5b_decode_layer_2_prefill(), qwen2_0_5b_decode_layer_3_decode(), qwen2_0_5b_decode_layer_3_decode(), qwen2_0_5b_decode_layer_3_decode(), qwen2_0_5b_decode_layer_3_decode(), qwen2_0_5b_decode_layer_3_decode(), qwen2_0_5b_decode_layer_3_prefill(), qwen2_0_5b_decode_layer_3_prefill(), qwen2_0_5b_decode_layer_3_prefill(), qwen2_0_5b_decode_layer_3_prefill(), qwen2_0_5b_decode_layer_4_decode(), qwen2_0_5b_decode_layer_4_decode(), qwen2_0_5b_decode_layer_4_decode(), qwen2_0_5b_decode_layer_4_decode(), qwen2_0_5b_decode_layer_4_decode(), qwen2_0_5b_decode_layer_4_prefill(), qwen2_0_5b_decode_layer_4_prefill(), qwen2_0_5b_decode_layer_4_prefill(), qwen2_0_5b_decode_layer_4_prefill(), qwen2_0_5b_decode_layer_5_decode(), qwen2_0_5b_decode_layer_5_decode(), qwen2_0_5b_decode_layer_5_decode(), qwen2_0_5b_decode_layer_5_decode(), qwen2_0_5b_decode_layer_5_decode(), qwen2_0_5b_decode_layer_5_prefill(), qwen2_0_5b_decode_layer_5_prefill(), qwen2_0_5b_decode_layer_5_prefill(), qwen2_0_5b_decode_layer_5_prefill(), qwen2_0_5b_decode_layer_6_decode(), qwen2_0_5b_decode_layer_6_decode(), qwen2_0_5b_decode_layer_6_decode(), qwen2_0_5b_decode_layer_6_decode(), qwen2_0_5b_decode_layer_6_decode(), qwen2_0_5b_decode_layer_6_prefill(), qwen2_0_5b_decode_layer_6_prefill(), qwen2_0_5b_decode_layer_6_prefill(), qwen2_0_5b_decode_layer_6_prefill(), qwen2_0_5b_decode_layer_7_decode(), qwen2_0_5b_decode_layer_7_decode(), qwen2_0_5b_decode_layer_7_decode(), qwen2_0_5b_decode_layer_7_decode(), qwen2_0_5b_decode_layer_7_decode(), qwen2_0_5b_decode_layer_7_prefill(), qwen2_0_5b_decode_layer_7_prefill(), qwen2_0_5b_decode_layer_7_prefill(), qwen2_0_5b_decode_layer_7_prefill(), qwen2_0_5b_decode_layer_8_decode(), qwen2_0_5b_decode_layer_8_decode(), qwen2_0_5b_decode_layer_8_decode(), qwen2_0_5b_decode_layer_8_decode(), qwen2_0_5b_decode_layer_8_decode(), qwen2_0_5b_decode_layer_8_prefill(), qwen2_0_5b_decode_layer_8_prefill(), qwen2_0_5b_decode_layer_8_prefill(), qwen2_0_5b_decode_layer_8_prefill(), qwen2_0_5b_decode_layer_9_decode(), qwen2_0_5b_decode_layer_9_decode(), qwen2_0_5b_decode_layer_9_decode(), qwen2_0_5b_decode_layer_9_decode(), qwen2_0_5b_decode_layer_9_decode(), qwen2_0_5b_decode_layer_9_prefill(), qwen2_0_5b_decode_layer_9_prefill(), qwen2_0_5b_decode_layer_9_prefill(), qwen2_0_5b_decode_layer_9_prefill(), rmsnorm_forward_int4(), rmsnorm_forward_int8(), rmsnorm_forward_kv_lora(), and rmsnorm_qkv_q4k_fused().

◆ rmsnorm_forward_fp64_sum()

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.

145{
146 for (int t = 0; t < tokens; ++t) {
147 const float *x = input + (size_t)t * (size_t)aligned_embed_dim;
148 float *y = output + (size_t)t * (size_t)aligned_embed_dim;
149 /* This provider's contract requires an ascending scalar reduction.
150 * Keep the accumulator volatile so whole-program optimization cannot
151 * reassociate the sum or replace it with SIMD partial reductions. */
152 volatile double sum_sq = 0.0;
153 for (int d = 0; d < d_model; ++d) {
154 const float square = x[d] * x[d];
155 sum_sq = sum_sq + (double)square;
156 }
157 const float mean_sq = (float)(sum_sq / (double)d_model);
158 const float rstd = 1.0f / sqrtf(mean_sq + eps);
159 if (rstd_cache) {
160 rstd_cache[t] = rstd;
161 }
162 for (int d = 0; d < d_model; ++d) {
163 const float normalized = x[d] * rstd;
164 y[d] = normalized * gamma[d];
165 }
166 for (int d = d_model; d < aligned_embed_dim; ++d) {
167 y[d] = 0.0f;
168 }
169 }
170}

Referenced by qk_norm_forward_fp64_sum().

◆ rmsnorm_forward_kv_lora()

void rmsnorm_forward_kv_lora ( 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 643 of file rmsnorm_kernels.c.

651{
652 rmsnorm_forward(input, gamma, output, rstd_cache, tokens, d_model, aligned_embed_dim, eps);
653}
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)

References rmsnorm_forward().

◆ rmsnorm_forward_llama_production()

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.

204{
205 for (int t = 0; t < tokens; ++t) {
206 const float *x = input + (size_t)t * (size_t)aligned_embed_dim;
207 float *y = output + (size_t)t * (size_t)aligned_embed_dim;
208 volatile double sum_sq = 0.0;
209 for (int d = 0; d < d_model; ++d) {
210 const float square = x[d] * x[d];
211 sum_sq = sum_sq + (double)square;
212 }
213 const float mean_sq = (float)(sum_sq / (double)d_model);
214 const float rstd = rmsnorm_llama_production_rstd(mean_sq + eps);
215 if (rstd_cache) {
216 rstd_cache[t] = rstd;
217 }
218 for (int d = 0; d < d_model; ++d) {
219 /*
220 * Keep the RMSNorm + scale expression fused at the source level.
221 * llama.cpp's CPU graph fuses GGML_OP_RMS_NORM followed by
222 * GGML_OP_MUL and evaluates this left-associative expression in
223 * one kernel. Materializing the normalized value as a named
224 * float introduces a store/load rounding boundary under ICX and
225 * differs by one ULP for otherwise identical inputs.
226 */
227 y[d] = x[d] * rstd * gamma[d];
228 }
229 for (int d = d_model; d < aligned_embed_dim; ++d) {
230 y[d] = 0.0f;
231 }
232 }
233}
static float rmsnorm_llama_production_rstd(float mean_eps)

References rmsnorm_llama_production_rstd().

Referenced by qk_norm_forward_llama_production(), qwen4_group_rmsnorm_llama(), recurrent_norm_gate_llama_avx2_forward(), and recurrent_norm_sigmoid_gate_llama_avx2_forward().

◆ rmsnorm_forward_no_weight()

void rmsnorm_forward_no_weight ( const float *  input,
float *  output,
float *  rstd_cache,
int  tokens,
int  d_model,
int  aligned_embed_dim,
float  eps 
)

Definition at line 655 of file rmsnorm_kernels.c.

662{
663 if (!input || !output || tokens <= 0 || d_model <= 0 || aligned_embed_dim <= 0) {
664 return;
665 }
666 const float inv_d = 1.0f / (float)d_model;
667 for (int t = 0; t < tokens; ++t) {
668 const float *x = input + (size_t)t * (size_t)aligned_embed_dim;
669 float *y = output + (size_t)t * (size_t)aligned_embed_dim;
670 double sum_sq = 0.0;
671 for (int d = 0; d < d_model; ++d) {
672 sum_sq += (double)x[d] * (double)x[d];
673 }
674 const float rstd = 1.0f / sqrtf((float)(sum_sq * (double)inv_d) + eps);
675 if (rstd_cache) {
676 rstd_cache[t] = rstd;
677 }
678 for (int d = 0; d < d_model; ++d) {
679 y[d] = x[d] * rstd;
680 }
681 for (int d = d_model; d < aligned_embed_dim; ++d) {
682 y[d] = 0.0f;
683 }
684 }
685}

Referenced by gemma4_v_norm_forward().

◆ rmsnorm_forward_pytorch_bf16_storage()

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.

403{
405 input, gamma, output, rstd_cache, tokens, d_model,
406 aligned_embed_dim, aligned_embed_dim, eps, 0);
407}
static void rmsnorm_forward_pytorch_bf16_storage_impl(const float *input, const float *gamma, float *output, float *rstd_cache, int tokens, int d_model, int input_stride, int output_stride, float eps, int qwen3next_weight_order)

References rmsnorm_forward_pytorch_bf16_storage_impl().

Referenced by qk_norm_forward_pytorch_bf16_storage(), recurrent_norm_gate_pytorch_bf16_storage(), and recurrent_norm_sigmoid_gate_pytorch_bf16_storage().

◆ rmsnorm_forward_pytorch_bf16_storage_impl()

static void rmsnorm_forward_pytorch_bf16_storage_impl ( const float *  input,
const float *  gamma,
float *  output,
float *  rstd_cache,
int  tokens,
int  d_model,
int  input_stride,
int  output_stride,
float  eps,
int  qwen3next_weight_order 
)
static

Definition at line 254 of file rmsnorm_kernels.c.

264{
265 for (int t = 0; t < tokens; ++t) {
266 const float *x = input + (size_t)t * (size_t)input_stride;
267 float *y = output + (size_t)t * (size_t)output_stride;
268 float sum_sq = 0.0f;
269
270#if defined(__AVX2__)
271 /* Match the installed ATen build's AVX2 floating-point cascade_sum
272 * contract. It treats the
273 * contiguous row as four interleaved vector streams, accumulates
274 * 16-item blocks through four hierarchy levels, then folds the four
275 * streams and vector lanes left-to-right. PyTorch materializes pow(2)
276 * before mean(), so keep the multiply separate from accumulation.
277 * The host supports AVX-512, but this PyTorch build has AVX2 reduction
278 * providers only; provider ISA is part of the numerical contract. */
279 __m256 level[4][4];
280 for (int hierarchy = 0; hierarchy < 4; ++hierarchy) {
281 for (int stream = 0; stream < 4; ++stream) {
282 level[hierarchy][stream] = _mm256_setzero_ps();
283 }
284 }
285 int d = 0;
286 const int vector_count = d_model / 8;
287 const int cascade_items = vector_count / 4;
288 int level_power = 4;
289 if (cascade_items > 1) {
290 int ceil_log2 = 0;
291 unsigned int value = (unsigned int)(cascade_items - 1);
292 while (value != 0) {
293 value >>= 1;
294 ++ceil_log2;
295 }
296 const int candidate = ceil_log2 / 4;
297 if (candidate > level_power) level_power = candidate;
298 }
299 const int level_step = 1 << level_power;
300 const int level_mask = level_step - 1;
301 int item = 0;
302 for (; item + level_step <= cascade_items;) {
303 for (int block = 0; block < level_step; ++block, ++item) {
304 for (int stream = 0; stream < 4; ++stream) {
305 const int offset = (item * 4 + stream) * 8;
306 const __m256 values = rmsnorm_load_bf16_values_avx2(x + offset);
307 const __m256 squared = rmsnorm_square_avx2_no_contract(values);
308 level[0][stream] = rmsnorm_add_avx2_ordered(
309 level[0][stream], squared
310 );
311 }
312 }
313 for (int hierarchy = 1; hierarchy < 4; ++hierarchy) {
314 for (int stream = 0; stream < 4; ++stream) {
315 level[hierarchy][stream] = rmsnorm_add_avx2_ordered(
316 level[hierarchy][stream], level[hierarchy - 1][stream]
317 );
318 level[hierarchy - 1][stream] = _mm256_setzero_ps();
319 }
320 const int mask = level_mask << (hierarchy * level_power);
321 if ((item & mask) != 0) break;
322 }
323 }
324 for (; item < cascade_items; ++item) {
325 for (int stream = 0; stream < 4; ++stream) {
326 const int offset = (item * 4 + stream) * 8;
327 const __m256 values = rmsnorm_load_bf16_values_avx2(x + offset);
328 const __m256 squared = rmsnorm_square_avx2_no_contract(values);
329 level[0][stream] = rmsnorm_add_avx2_ordered(
330 level[0][stream], squared
331 );
332 }
333 }
334 for (int hierarchy = 1; hierarchy < 4; ++hierarchy) {
335 for (int stream = 0; stream < 4; ++stream) {
336 level[0][stream] = rmsnorm_add_avx2_ordered(
337 level[0][stream], level[hierarchy][stream]
338 );
339 }
340 }
341 __m256 reduced = level[0][0];
342 for (int stream = 1; stream < 4; ++stream) {
343 reduced = rmsnorm_add_avx2_ordered(reduced, level[0][stream]);
344 }
345 d = cascade_items * 4 * 8;
346 for (; d + 8 <= d_model; d += 8) {
347 const __m256 values = rmsnorm_load_bf16_values_avx2(x + d);
348 const __m256 squared = rmsnorm_square_avx2_no_contract(values);
349 reduced = rmsnorm_add_avx2_ordered(reduced, squared);
350 }
351 _Alignas(32) float lanes[8];
352 _mm256_store_ps(lanes, reduced);
353 volatile float ordered_sum = 0.0f;
354 for (int lane = 0; lane < 8; ++lane) {
355 ordered_sum = ordered_sum + lanes[lane];
356 }
357 sum_sq = ordered_sum;
358 for (; d < d_model; ++d) {
359 const float value = bf16_to_float(float_to_bf16(x[d]));
360 sum_sq += value * value;
361 }
362#else
363 for (int d = 0; d < d_model; ++d) {
364 const float value = bf16_to_float(float_to_bf16(x[d]));
365 sum_sq += value * value;
366 }
367#endif
368
369#if defined(__i386__) || defined(__x86_64__)
370 const float variance = rmsnorm_div_f32_ordered(sum_sq, (float)d_model);
371 const float rstd = rmsnorm_div_f32_ordered(1.0f, sqrtf(variance + eps));
372#else
373 const float variance = sum_sq / (float)d_model;
374 const float rstd = 1.0f / sqrtf(variance + eps);
375#endif
376 if (rstd_cache) rstd_cache[t] = rstd;
377 for (int d = 0; d < d_model; ++d) {
378 const float value = bf16_to_float(float_to_bf16(x[d]));
379 if (qwen3next_weight_order) {
380 /* Qwen3Next: (FP32 normalized * FP32 weight).to(BF16). */
382 (value * rstd) * gamma[d]));
383 } else {
384 const float weight =
385 bf16_to_float(float_to_bf16(gamma[d]));
386 const float normalized =
387 bf16_to_float(float_to_bf16(value * rstd));
388 y[d] = bf16_to_float(float_to_bf16(normalized * weight));
389 }
390 }
391 for (int d = d_model; d < output_stride; ++d) y[d] = 0.0f;
392 }
393}
static uint16_t float_to_bf16(float f)
Definition bf16_utils.h:90
static float bf16_to_float(uint16_t v)
Definition bf16_utils.h:38
int32_t int32_t int32_t int32_t int32_t mask
Definition tokenizer.h:234

References bf16_to_float(), float_to_bf16(), and mask.

Referenced by rmsnorm_forward_pytorch_bf16_storage(), rmsnorm_forward_qwen3next_pytorch_bf16_storage(), and rmsnorm_forward_strided_pytorch_bf16_storage().

◆ rmsnorm_forward_qwen3next_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.

433{
435 input, gamma, output, rstd_cache, tokens, d_model,
436 aligned_embed_dim, aligned_embed_dim, eps, 1);
437}

References rmsnorm_forward_pytorch_bf16_storage_impl().

Referenced by hyper_connection_mix_bf16(), qk_norm_forward_qwen4_pytorch_bf16_storage(), and qwen4_group_rmsnorm_pytorch_bf16().

◆ rmsnorm_forward_strict_scalar()

static void rmsnorm_forward_strict_scalar ( const float *  input,
const float *  gamma,
float *  output,
float *  rstd_cache,
int  tokens,
int  d_model,
int  input_stride,
int  output_stride,
float  eps 
)
static

Definition at line 96 of file rmsnorm_kernels.c.

105{
106 const float inv_d = 1.0f / (float)d_model;
107 for (int t = 0; t < tokens; ++t) {
108 const float *x = input + (size_t)t * (size_t)input_stride;
109 float *y = output + (size_t)t * (size_t)output_stride;
110
111 float sum_sq = 0.0f;
112 for (int d = 0; d < d_model; ++d) {
113 const float v = x[d];
114 sum_sq += v * v;
115 }
116 const float mean_sq = sum_sq * inv_d;
117 const float rstd = 1.0f / sqrtf(mean_sq + eps);
118 if (rstd_cache) {
119 rstd_cache[t] = rstd;
120 }
121
122 for (int d = 0; d < d_model; ++d) {
123 const float x_hat = x[d] * rstd;
124 y[d] = x_hat * gamma[d];
125 }
126 for (int d = d_model; d < output_stride; ++d) {
127 y[d] = 0.0f;
128 }
129 }
130}

Referenced by rmsnorm_forward_strided_f32().

◆ rmsnorm_forward_strided_f32()

void rmsnorm_forward_strided_f32 ( const float *  input,
const float *  gamma,
float *  output,
float *  rstd_cache,
int  tokens,
int  d_model,
int  input_stride,
int  output_stride,
float  eps 
)

RMSNorm forward pass

Test:

test_rmsnorm.py::TestRMSNormForward::test_fp32_tokens

test_rmsnorm.py::TestRMSNormForward::test_fp32_single

test_rmsnorm.py::TestRMSNormForward::test_perf_rolled

test_layernorm.py::TestLayerNormForward::test_rmsnorm_compat

test_parity.py::test_rmsnorm_parity

RMSNorm: y[i] = gamma[i] * x[i] / sqrt(mean(x^2) + eps)

After changes: make test && make llamacpp-parity-full

Definition at line 492 of file rmsnorm_kernels.c.

501{
502 int T = tokens;
503 int D = d_model;
504
505 const char *exact_env = getenv("CK_RMSNORM_EXACT");
506 if (ck_strict_parity_enabled() || (exact_env && atoi(exact_env) != 0)) {
508 input, gamma, output, rstd_cache, T, D, input_stride, output_stride, eps
509 );
510 return;
511 }
512
513 for (int t = 0; t < T; ++t) {
514 const float *x = input + (size_t)t * (size_t)input_stride;
515 float *y = output + (size_t)t * (size_t)output_stride;
516
517#if defined(__AVX512F__)
518 // AVX-512: Process 16 floats at a time
519 __m512 sum_sq_vec = _mm512_setzero_ps();
520 int d = 0;
521
522 // Vectorized sum of squares
523 for (; d + 16 <= D; d += 16) {
524 __m512 xv = _mm512_loadu_ps(&x[d]);
525 sum_sq_vec = _mm512_fmadd_ps(xv, xv, sum_sq_vec);
526 }
527 float sum_sq = _mm512_reduce_add_ps(sum_sq_vec);
528
529 // Handle remaining elements
530 for (; d < D; ++d) {
531 sum_sq += x[d] * x[d];
532 }
533
534 float mean_sq = sum_sq / (float)D;
535 float rstd = 1.0f / sqrtf(mean_sq + eps);
536 if (rstd_cache) {
537 rstd_cache[t] = rstd;
538 }
539
540 // Apply normalization and scale (vectorized)
541 __m512 rstd_vec = _mm512_set1_ps(rstd);
542 d = 0;
543 for (; d + 16 <= D; d += 16) {
544 __m512 xv = _mm512_loadu_ps(&x[d]);
545 __m512 gv = _mm512_loadu_ps(&gamma[d]);
546 __m512 x_hat = _mm512_mul_ps(xv, rstd_vec);
547 __m512 yv = _mm512_mul_ps(x_hat, gv);
548 _mm512_storeu_ps(&y[d], yv);
549 }
550 // Handle remaining elements
551 for (; d < D; ++d) {
552 y[d] = x[d] * rstd * gamma[d];
553 }
554
555#elif defined(__AVX__)
556 // AVX: Process 8 floats at a time
557 __m256 sum_sq_vec = _mm256_setzero_ps();
558 int d = 0;
559
560 // Vectorized sum of squares (no FMA in AVX1, use mul + add)
561 for (; d + 8 <= D; d += 8) {
562 __m256 xv = _mm256_loadu_ps(&x[d]);
563 __m256 xv_sq = _mm256_mul_ps(xv, xv);
564 sum_sq_vec = _mm256_add_ps(sum_sq_vec, xv_sq);
565 }
566 float sum_sq = hsum256_ps_rmsnorm(sum_sq_vec);
567
568 // Handle remaining elements
569 for (; d < D; ++d) {
570 sum_sq += x[d] * x[d];
571 }
572
573 float mean_sq = sum_sq / (float)D;
574 float rstd = 1.0f / sqrtf(mean_sq + eps);
575 if (rstd_cache) {
576 rstd_cache[t] = rstd;
577 }
578
579 // Apply normalization and scale (vectorized)
580 __m256 rstd_vec = _mm256_set1_ps(rstd);
581 d = 0;
582 for (; d + 8 <= D; d += 8) {
583 __m256 xv = _mm256_loadu_ps(&x[d]);
584 __m256 gv = _mm256_loadu_ps(&gamma[d]);
585 __m256 x_hat = _mm256_mul_ps(xv, rstd_vec);
586 __m256 yv = _mm256_mul_ps(x_hat, gv);
587 _mm256_storeu_ps(&y[d], yv);
588 }
589 // Handle remaining elements
590 for (; d < D; ++d) {
591 y[d] = x[d] * rstd * gamma[d];
592 }
593
594#else
595 // Scalar fallback
596 float sum_sq = 0.0f;
597 for (int d = 0; d < D; ++d) {
598 float v = x[d];
599 sum_sq += v * v;
600 }
601 float mean_sq = sum_sq / (float)D;
602 float rstd = 1.0f / sqrtf(mean_sq + eps);
603 if (rstd_cache) {
604 rstd_cache[t] = rstd;
605 }
606
607 // Apply normalization and scale
608 for (int d = 0; d < D; ++d) {
609 float x_hat = x[d] * rstd;
610 y[d] = x_hat * gamma[d];
611 }
612#endif
613
614 // Zero padding (if any)
615 for (int d = D; d < output_stride; ++d) {
616 y[d] = 0.0f;
617 }
618 }
619}
static void rmsnorm_forward_strict_scalar(const float *input, const float *gamma, float *output, float *rstd_cache, int tokens, int d_model, int input_stride, int output_stride, float eps)

References ck_strict_parity_enabled(), and rmsnorm_forward_strict_scalar().

Referenced by rmsnorm_forward().

◆ rmsnorm_forward_strided_pytorch_bf16_storage()

void rmsnorm_forward_strided_pytorch_bf16_storage ( const float *  input,
const float *  gamma,
float *  output,
float *  rstd_cache,
int  tokens,
int  d_model,
int  input_stride,
int  output_stride,
float  eps 
)

Definition at line 409 of file rmsnorm_kernels.c.

418{
420 input, gamma, output, rstd_cache, tokens, d_model,
421 input_stride, output_stride, eps, 0);
422}

References rmsnorm_forward_pytorch_bf16_storage_impl().

◆ rmsnorm_llama_production_rstd()

static float rmsnorm_llama_production_rstd ( float  mean_eps)
inlinestatic

Definition at line 172 of file rmsnorm_kernels.c.

173{
174 /*
175 * ggml's production CPU RMSNorm emits scalar sqrt followed by scalar
176 * division. With -fno-math-errno ICX otherwise strength-reduces the C
177 * expression to vrsqrt14ss plus one Newton step. That estimate differs by
178 * one ULP for some rows and the error is amplified by quantized
179 * projections in deep recurrent models.
180 */
181#if defined(CK_TARGET_X86)
182 const __m128 value = _mm_set_ss(mean_eps);
183 const __m128 root = _mm_sqrt_ss(value);
184 return _mm_cvtss_f32(_mm_div_ss(_mm_set_ss(1.0f), root));
185#else
186 const volatile float root = sqrtf(mean_eps);
187 return 1.0f / root;
188#endif
189}

Referenced by rmsnorm_forward_llama_production().