From 2c0380d183bae39f5356dc067fcecdd6ed08031c Mon Sep 17 00:00:00 2001 From: quantumaikr Date: Fri, 10 Apr 2026 14:54:56 +0900 Subject: [PATCH] Fix Qwen3 garbage output: apply RMSNorm +1 to all Qwen-family models MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Qwen's RMSNorm computes `output = norm(x) * (1 + weight)`, not `norm(x) * weight`. The +1 weight adjustment was only applied when `delta_n_heads > 0` (DeltaNet/Qwen3.5-hybrid) or `model_type == 1` (Gemma). Plain Qwen3 (and Qwen2/2.5) models have `delta_n_heads=0` and `model_type=0`, so the adjustment was skipped entirely. Without it, RMSNorm produces wrong scales and activations explode by layer 2 (values reaching 6000+), generating garbage tokens. Fix: detect any Qwen-family model via `strstr(gguf->arch, "qwen")` in addition to the existing DeltaNet check. This covers qwen2, qwen2moe, qwen3, qwen3_5 — all use the same (1+w) RMSNorm. Applied to tq_model.c (library) + quant.h (single-header/WASM). WASM binary rebuilt to include the fix. Co-Authored-By: Claude Opus 4.6 (1M context) --- quant.h | 14 ++++++++++---- src/engine/tq_model.c | 14 ++++++++++---- wasm/quant.wasm | Bin 244115 -> 244160 bytes 3 files changed, 20 insertions(+), 8 deletions(-) diff --git a/quant.h b/quant.h index 39a3a75..2070249 100644 --- a/quant.h +++ b/quant.h @@ -9982,7 +9982,7 @@ static tq_model_t* tq_load_safetensors(const char* path) { free(tensors); - /* Qwen3.5 RMSNorm adjustment: Qwen3_5RMSNorm computes + /* Qwen RMSNorm adjustment: Qwen's RMSNorm computes * output = norm(x) * (1.0 + weight), NOT norm(x) * weight. * We bake the "+1" into the weight so tq_rmsnorm can stay as * out = x * rsqrt * weight. @@ -9992,8 +9992,14 @@ static tq_model_t* tq_load_safetensors(const char* path) { * It does NOT apply to: linear_attn.norm (Qwen3_5RMSNormGated * uses plain weight without +1). * - * We detect Qwen3.5 by the presence of DeltaNet layers. */ - if (model->config.delta_n_heads > 0) { + * Applies to all Qwen-family models (qwen2, qwen3, qwen3_5, etc.) + * Detected by arch string or DeltaNet presence. */ + int is_qwen_family = (model->config.delta_n_heads > 0); + if (model->gguf_ctx) { + const tq_gguf_ctx_t* gctx = (const tq_gguf_ctx_t*)model->gguf_ctx; + if (strstr(gctx->arch, "qwen") != NULL) is_qwen_family = 1; + } + if (is_qwen_family) { int dim_h = model->config.hidden_dim; int head_dim_h = model->config.head_dim; @@ -10022,7 +10028,7 @@ static tq_model_t* tq_load_safetensors(const char* path) { for (int i = 0; i < dim_h; i++) model->output_norm[i] += 1.0f; } - fprintf(stderr, "tq_load_model: applied Qwen3.5 RMSNorm +1 weight adjustment\n"); + fprintf(stderr, "tq_load_model: applied Qwen RMSNorm +1 weight adjustment\n"); } /* Gemma3 RMSNorm adjustment: same (1+w) scaling as Qwen3.5 */ diff --git a/src/engine/tq_model.c b/src/engine/tq_model.c index d2b094f..e0a0113 100644 --- a/src/engine/tq_model.c +++ b/src/engine/tq_model.c @@ -1517,7 +1517,7 @@ static tq_model_t* tq_load_safetensors(const char* path) { free(tensors); - /* Qwen3.5 RMSNorm adjustment: Qwen3_5RMSNorm computes + /* Qwen RMSNorm adjustment: Qwen's RMSNorm computes * output = norm(x) * (1.0 + weight), NOT norm(x) * weight. * We bake the "+1" into the weight so tq_rmsnorm can stay as * out = x * rsqrt * weight. @@ -1527,8 +1527,14 @@ static tq_model_t* tq_load_safetensors(const char* path) { * It does NOT apply to: linear_attn.norm (Qwen3_5RMSNormGated * uses plain weight without +1). * - * We detect Qwen3.5 by the presence of DeltaNet layers. */ - if (model->config.delta_n_heads > 0) { + * Applies to all Qwen-family models (qwen2, qwen3, qwen3_5, etc.) + * Detected by arch string or DeltaNet presence. */ + int is_qwen_family = (model->config.delta_n_heads > 0); + if (model->gguf_ctx) { + const tq_gguf_ctx_t* gctx = (const tq_gguf_ctx_t*)model->gguf_ctx; + if (strstr(gctx->arch, "qwen") != NULL) is_qwen_family = 1; + } + if (is_qwen_family) { int dim_h = model->config.hidden_dim; int head_dim_h = model->config.head_dim; @@ -1557,7 +1563,7 @@ static tq_model_t* tq_load_safetensors(const char* path) { for (int i = 0; i < dim_h; i++) model->output_norm[i] += 1.0f; } - fprintf(stderr, "tq_load_model: applied Qwen3.5 RMSNorm +1 weight adjustment\n"); + fprintf(stderr, "tq_load_model: applied Qwen RMSNorm +1 weight adjustment\n"); } /* Gemma3 RMSNorm adjustment: same (1+w) scaling as Qwen3.5 */ diff --git a/wasm/quant.wasm b/wasm/quant.wasm index 7c3b273871b650be2050b44e3bd626468d46cfd3..850de4be2b2773ddf0c2c5cdb4d671686d903448 100755 GIT binary patch delta 11208 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