perf(qwen35): Q4_K requant for Qwythos Q6 decode reads#329
Conversation
⏸ Merge conflict — rebase before evalThis branch conflicts with Please rebase onto |
|
The round's |
1 similar comment
|
The round's |
0a649eb to
acc253b
Compare
acc253b to
47f2e8e
Compare
✅ sparkinfer auto-eval —
|
| metric | value |
|---|---|
| label | eval:M |
| Qwen3.5 score | eval-qwen35:M (pass) |
| Qwen3.6 score | eval-qwen36:none (pass) |
| Qwen3.5 vs same-box main | 283.18 tok/s → +7.1% (+20.0) |
| Qwen3.5 scored decode (128 ctx · 128-context) | 303.18 tok/s |
| Qwen3.5 correctness | top-1 95.2% · KL 0.0301 |
| Qwen3.5 128-token no-regression gate | 303.18 tok/s vs main 283.18 tok/s · pass |
| Qwen3.5 512-context no-regression gate | 299.26 tok/s vs main 280.25 tok/s · pass |
| Qwen3.5 4k-context no-regression gate | 289.19 tok/s vs main 272.14 tok/s · pass |
| Qwen3.6 vs same-box main | 381.72 tok/s → +0.0% (+0.1) |
| Qwen3.6 scored decode (16384 ctx · 16k-context) | 381.86 tok/s |
| Qwen3.6 correctness | top-1 97.3% · KL 0.0147 |
| Qwen3.6 128-token no-regression gate | 427.25 tok/s vs main 427.74 tok/s · pass |
| Qwen3.6 512-context no-regression gate | 422.28 tok/s vs main 422.84 tok/s · pass |
| Qwen3.6 4k-context no-regression gate | 405.57 tok/s vs main 405.82 tok/s · pass |
| Qwen3.6 16k-context no-regression gate | 381.86 tok/s vs main 381.72 tok/s · pass |
| Qwen3.6 32k-context no-regression gate | 354.47 tok/s vs main 354.56 tok/s · pass |
| Qwen3.5 optimize | eval:M · 303.18 tok/s · pass |
| Qwen3.5 optimize — Qwen3.6-35B-A3B guard accuracy | top-1 97.3% · KL 0.0147 · pass |
| Qwen3.5 optimize — Qwen3.6-35B-A3B 128 | 426.98 tok/s · pass |
| Qwen3.5 optimize — Qwen3.6-35B-A3B 512 | 422.22 tok/s · pass |
| Qwen3.5 optimize — Qwen3.6-35B-A3B 4k | 405.41 tok/s · pass |
| Qwen3.5 optimize — Qwen3.6-35B-A3B 16k | 381.8 tok/s · pass |
| Qwen3.5 optimize — Qwen3.6-35B-A3B 32k | 354.45 tok/s · pass |
| Qwen3.6 optimize | eval:none · 381.86 tok/s · pass |
| Qwen3.6 optimize — Qwythos-9B (Q4_K_M) guard accuracy | top-1 95.2% · KL 0.0301 · pass |
| Qwen3.6 optimize — Qwythos-9B (Q4_K_M) 128 | 302.96 tok/s · pass |
| Qwen3.6 optimize — Qwythos-9B (Q4_K_M) 512 | 299.1 tok/s · pass |
| Qwen3.6 optimize — Qwythos-9B (Q4_K_M) 4k | 289.24 tok/s · pass |
Verified speedup over same-box origin/main — 303.18 tok/s (main was 283.18 tok/s).
RTX 5090 (sm_120) · 128/512/4k/16k/32k guarded · scored vs same-box main · strongest context scores · built from source · correctness vs llama.cpp. Automated — not merged; merge manually after review.
|
✅ Auto-merged as the round's |
gittensor-ai-lab#329 merged the shared Q6_K->Q4_K load-time requant (dev_quant_requant_q4k) plus the int8 dp4a Q4_K MMVQ LM-head dispatch, but defaults the LM-head requant on only for the dense-9B Qwythos config. The scored Qwen3.6-35B-A3B hybrid-MoE (hidden 2048, 40 layers, 256 experts, top_k 8) is not dense_ffn, so its Q6_K output projection -- the single largest weight read per decoded token (vocab 248320 x 2048) -- stays Q6_K. Enable req_lm_q4 for that exact config so the LM head is requantized to Q4_K at load through the already-merged helper and decoded via the existing mmvq_q4k_f32 path. ~2 bits/weight off the largest per-token read. SPARKINFER_LMHEAD_REQUANT_Q4K=0 restores Q6_K. Prior same-box A/B on the equivalent Q4_K path (pre-gittensor-ai-lab#329 tree): +3.1-3.4% decode (128-4k ctx), no regression; top-1 0.970 (bar >=0.90), KL 0.020 nats (bar <=0.20), PPL 2.83 -> 2.86. The RTX 5090 eval bot re-confirms the marginal gain on the post-gittensor-ai-lab#329 frontier. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Summary
Requantize the remaining high-traffic Q6_K decode reads for Qwythos/Qwen3.5 dense-9B to Q4_K at load time, using the existing GGUF dequant/requant path and existing Q4_K MMVQ decode kernels. This covers dense FFN down weights, selected linear-attention QKV weights, and the LM head under the dense-9B shape guard.
The Qwythos dense-9B path is default-on with the upstream
SPARKINFER_DOWN_REQUANT_Q4Ksemantics: unset or nonzero enables it, andSPARKINFER_DOWN_REQUANT_Q4K=0keeps the native Q6_K reads.Proof of speedup
sm_120)Decode tok/s (end-to-end, from
bench/scripts/bench.sh/qwen3_gguf_bench— required for evaluation):Additional same-box medians on the rebased candidate:
Accuracy
bench/scripts/accuracy.sh, same GGUF, seedq35-broad-requant-check:Implementation notes
dev_quant_requant_q4k(name, qtype, enabled).SPARKINFER_DOWN_REQUANT_Q4K=0disables, unset enables.SPARKINFER_ATTN_REQUANT_Q4K,SPARKINFER_ATTN_REQUANT_Q4K_QKV_LAYERS,SPARKINFER_ATTN_REQUANT_Q4K_QKV_LIMIT, andSPARKINFER_LMHEAD_REQUANT_Q4K.qkv_all/all_attnsweeps were only about 0.3% faster than the safer default and include an accuracy-sensitive layer, so they are left as env-controlled options instead of defaults.Test plan
origin/main@95b93cegit diff --checksm_120285.38 tok/s, PR304.59 tok/sbench/scripts/accuracy.shvs llama.cpp reference on held-out seedq35-broad-requant-check