Skip to content

perf(qwen36): Q4_K shared-expert FFN kernels + Q8_0/Q5_K→Q4_K requant of the MoE FFN stage (+3.1–3.8%)#360

Closed
petermilord wants to merge 1 commit into
gittensor-ai-lab:mainfrom
petermilord:perf/qwen36-shexp-ffn-q4k
Closed

perf(qwen36): Q4_K shared-expert FFN kernels + Q8_0/Q5_K→Q4_K requant of the MoE FFN stage (+3.1–3.8%)#360
petermilord wants to merge 1 commit into
gittensor-ai-lab:mainfrom
petermilord:perf/qwen36-shexp-ffn-q4k

Conversation

@petermilord

Copy link
Copy Markdown

Summary

The Qwen3.6-35B-A3B MoE FFN stage still reads its shared-expert projections at Q8_0 and its routed-expert down projection at Q5_K. Decode is memory-bandwidth bound, so these wide reads sit on the critical path every token. This PR:

  1. Adds Q4_K shared-expert FFN kernels (shared_gate_up_q4k_mmvq + shared_down_q4k_mmvq) in kernels/csrc/cuda/moe/expert_ffn_q4k.cu, mirroring the existing Q8 MMVQ path but using si_vec_dot_q4_K DP4A + shared-memory reduction, exposed via launch_shared_expert_q4k_mmvq.
  2. Requantizes the MoE FFN weights to Q4_K at load time for the Qwen3.6 UD fingerprint: shared-expert gate/up/down (Q8_0→Q4_K) and routed-expert down (Q5_K→Q4_K), reusing dev_quant_requant_q4k (extended to accept Q5_K as a source).

Net effect: less bytes/token moved in the FFN stage → higher decode tok/s. The path is gated to the Qwen3.6 UD fingerprint and toggleable (SPARKINFER_SHEXP_REQUANT_Q4K, SPARKINFER_ROUTED_DOWN_REQUANT_Q4K); other models (e.g. Qwythos-9B) are untouched.

Proof of speedup

Tested on RTX 5090 (sm_120)

Decode tok/s (end-to-end, from bench/scripts/bench.sh — required for evaluation):

decode tok/s
before (main) 407.81
after (this PR) 423.18
# Qwen3.6-35B-A3B UD-Q4_K_M — RTX 5090, same-box A/B, bench/scripts/bench.sh, n=64
# Headline pair above is ctx=8192 (strongest verified gain). Full context sweep below.

before @8192:  407.81 tok/s   after @8192:  423.18 tok/s   (+3.8%, ctx=8192 -- table above)
before @4096:  407.09 tok/s   after @4096:  421.96 tok/s   (+3.7%)
before @16384: 397.37 tok/s   after @16384: 411.19 tok/s   (+3.5%)
before @32768: 378.06 tok/s   after @32768: 389.62 tok/s   (+3.1%)

# Qwythos-9B Q4_K_M guard (Qwen3.6-only gate must leave it unaffected):
before @128:   278.73 tok/s   after @128:   279.73 tok/s   (+0.4%, noise)
before @512:   277.05 tok/s   after @512:   278.27 tok/s   (+0.4%, noise)
before @4096:  267.78 tok/s   after @4096:  268.05 tok/s   (+0.1%, noise)

Gain is consistent (+3.1–3.8%) across every context on Qwen3.6, clears the 2% significance gate, and the Qwythos guard is flat (within run-to-run noise), confirming the gate is correctly scoped.

Correctness

Q4_K requantization is lossy, so I verified top-1 agreement of the next-token argmax between the baseline (Q8_0/Q5_K) and this PR (Q4_K) over a fixed prompt set: ~95–96% top-1 agreement, above the 90% gate. The shared-expert and routed-down projections are the least sensitive FFN tensors to 4-bit requant, and the measured agreement confirms no meaningful quality regression.

Scope

Changes are confined to the contribution scope (kernels/, runtime/, moe/):

 kernels/csrc/cuda/moe/expert_ffn_q4k.cu   | new Q4_K shared-expert kernels + launcher
 kernels/include/sparkinfer/kernels/moe.h  | declare launch_shared_expert_q4k_mmvq
 runtime/src/models/qwen35.cpp             | dispatch + load-time requant (gated)
 .gitignore                                | ignore local model dirs / *.gguf

Test plan

  • Build (RTX 5090, sm_120)
  • bench/scripts/bench.sh A/B, before=main / after=this PR, Qwen3.6-35B: +3.1–3.8% across ctx 4096–32768
  • Qwythos-9B guard sweep: unaffected (within noise)
  • Top-1 argmax agreement vs Q8_0/Q5_K baseline: ~95–96% (> 90% gate)
  • Optimization gated to Qwen3.6 UD fingerprint; toggle env vars provided

- Introduced new shared expert kernels for Q4_K requantization in Qwen3.6.
- Updated model loading logic to support Q4_K weights for shared gate, up, and down projections.
- Enhanced .gitignore to exclude new model directories and files.
- Adjusted forward_token method to handle Q4_K shared expert conditions.
@github-actions

Copy link
Copy Markdown

🐈 Copycat warning (real-time guard)

1% containment + structural similarity (Levenshtein + bigram cosine both above threshold vs this PR's code shape) by a different author.

⚠️ Warning (strike 1/3). 3 copycat-like submissions will result in an automatic block. If this is a legitimate independent implementation, comment on this PR and a maintainer will review (label copycat-cleared removes the strike).

@skyrocket2026 skyrocket2026 added area:runtime subsystem (emission weight 0.26) area:kernels subsystem (emission weight 0.42) test-on-5090 Maintainer-approved to evaluate on RTX 5090 (greenlight) labels Jul 13, 2026
@skyrocket2026

Copy link
Copy Markdown
Member

⚠️ sparkinfer auto-eval errored for 8c8070f — re-run manually.

log tail
k-baseline P_LLAMA_32K_BASELINE] [--bidir]
                    [--p35-guard-128-baseline P35_GUARD_128_BASELINE]
                    [--p35-guard-512-baseline P35_GUARD_512_BASELINE]
                    [--p35-guard-4k-baseline P35_GUARD_4K_BASELINE]
                    [--g35-guard-128-baseline G35_GUARD_128_BASELINE]
                    [--g35-guard-512-baseline G35_GUARD_512_BASELINE]
                    [--g35-guard-4k-baseline G35_GUARD_4K_BASELINE] [--triple]
                    [--primary-quant {Q4_K_M,Q8_0,BF16}]
                    [--g36-guard-128-baseline G36_GUARD_128_BASELINE]
                    [--g36-guard-512-baseline G36_GUARD_512_BASELINE]
                    [--g36-guard-4k-baseline G36_GUARD_4K_BASELINE]
                    [--g36-guard-16k-baseline G36_GUARD_16K_BASELINE]
                    [--g36-guard-32k-baseline G36_GUARD_32K_BASELINE]
                    [--eval-mode {longctx,short}] [--reuse REUSE]
                    [--ssh HOST:PORT] [--keep] [--destroy] [--gpu GPU]
                    [--image IMAGE] [--reuse-timeout REUSE_TIMEOUT]
                    [--new-timeout NEW_TIMEOUT] [--no-recreate] [--pinned]
                    [--destroy-on-error] [--polaris] [--no-polaris]
                    [--baseline-only]
vast_eval.py: error: unrecognized arguments: --p35-guard-32k-baseline 241.17 --p35-guard-64k-baseline 204.26 --p35-guard-128k-baseline 159.13 --g35-guard-32k-baseline 241.17 --g35-guard-64k-baseline 204.26 --g35-guard-128k-baseline 159.13

@skyrocket2026 skyrocket2026 added eval:REJECT sparkinfer auto-eval verdict: REJECT eval-qwen35:REJECT eval-qwen36:REJECT 32k-context UI-only: strongest measured context in sparkinfer eval labels Jul 13, 2026
@skyrocket2026

Copy link
Copy Markdown
Member

❌ sparkinfer auto-eval — 8c8070f

metric value
label eval:REJECT
Qwen3.5 score eval-qwen35:REJECT (fail)
Qwen3.6 score eval-qwen36:REJECT (fail)
Qwen3.5 vs same-box main 240.81 tok/s → +0.4% (+1.0)
Qwen3.5 scored decode (32768 ctx · 32k-context) 241.84 tok/s
Qwen3.5 correctness top-1 90.0% · KL 0.0445
Qwen3.5 128-token no-regression gate 299.24 tok/s vs main 298.35 tok/s · pass
Qwen3.5 4k-context no-regression gate 283.09 tok/s vs main 282.9 tok/s · pass
Qwen3.5 32k-context no-regression gate 241.84 tok/s vs main 240.81 tok/s · pass
Qwen3.6 vs same-box main 426.9 tok/s → -6.5% (-27.7)
Qwen3.6 scored decode (32768 ctx · 32k-context) 399.17 tok/s
Qwen3.6 correctness top-1 93.0% · KL 0.0313
Qwen3.6 128-token no-regression gate 435.59 tok/s vs main 472.74 tok/s · fail
Qwen3.6 512-context no-regression gate 441.66 tok/s vs main 479.5 tok/s · fail
Qwen3.6 4k-context no-regression gate 424.67 tok/s vs main 457.59 tok/s · fail
Qwen3.6 16k-context no-regression gate 416.43 tok/s vs main 450.59 tok/s · fail
Qwen3.6 32k-context no-regression gate 399.17 tok/s vs main 426.9 tok/s · fail
Qwen3.5 optimize eval:REJECT · 241.84 tok/s · fail
Qwen3.5 optimize — Qwen3.6-35B-A3B guard accuracy top-1 93.0% · KL 0.0313 · pass
Qwen3.5 optimize — Qwen3.6-35B-A3B 128 435.3 tok/s · fail
Qwen3.5 optimize — Qwen3.6-35B-A3B 512 441.59 tok/s · fail
Qwen3.5 optimize — Qwen3.6-35B-A3B 4k 424.58 tok/s · fail
Qwen3.5 optimize — Qwen3.6-35B-A3B 16k 417.15 tok/s · fail
Qwen3.5 optimize — Qwen3.6-35B-A3B 32k 399.69 tok/s · fail
Qwen3.6 optimize eval:REJECT · 399.17 tok/s · fail
Qwen3.6 optimize — Qwythos-9B (Q4_K_M) guard accuracy top-1 90.0% · KL 0.0445 · pass
Qwen3.6 optimize — Qwythos-9B (Q4_K_M) 128 298.32 tok/s · pass
Qwen3.6 optimize — Qwythos-9B (Q4_K_M) 4k 282.3 tok/s · pass
Qwen3.6 optimize — Qwythos-9B (Q4_K_M) 32k 241.83 tok/s · pass
regressions regression-qwen36-128, regression-qwen36-512, regression-qwen36-4k, regression-qwen36-16k, regression-qwen36-32k

No context cleared the 2% significance gate while at least one context regressed. Auto-closing this PR.

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.

skyrocket2026 added a commit that referenced this pull request Jul 13, 2026
Backfill PRs #355/#359/#360 from sparkinfer-log, bump origin/main
SHA in Qwen3.5/Qwen3.6 notes, and refresh the updated date.
@skyrocket2026

Copy link
Copy Markdown
Member

Closed: no activity for 2+ days

This PR has had no updates (commits, comments, reviews, or label changes) for 2 days (threshold: 2 days).

Reopen this PR or open a fresh one when you're ready to continue.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

32k-context UI-only: strongest measured context in sparkinfer eval area:kernels subsystem (emission weight 0.42) area:runtime subsystem (emission weight 0.26) copycat-warn eval:REJECT sparkinfer auto-eval verdict: REJECT eval-qwen35:REJECT eval-qwen36:REJECT test-on-5090 Maintainer-approved to evaluate on RTX 5090 (greenlight)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants