Repository navigation
[CUDA] Add dense and MoE GGUF MMQ kernels for eight I-quant types - #36122
liuhao-labs wants to merge 6 commits into
Conversation
Add dense and batched MoE MMQ kernels for eight supported I-quant GGUF formats, with conservative routing and compatibility fallback for older sglang-kernel wheels. Fixes sgl-project#35019 Signed-off-by: Hao Liu <liuhao24@sjtu.edu.cn>
GB10 dense IQ MMQ crossoverThis plot uses the revision-pinned At the sampled MMQ boundary M=16, the two-run ranges retain at least Run the underlying benchmark twice from for run in 1 2; do
python benchmark/bench_gguf_mmq.py \
--batch-sizes 9,16,17,24,32 \
--shape 18944x1024 \
--local-files-only | tee "/tmp/gguf-mmq-run-${run}.md"
doneThe heatmap was rendered from those two benchmark tables; the plotting-only |
Additional end-to-end compatibility checkI ran the revision-pinned
Both greedy requests produced byte-for-byte identical output: The runs used read-only source/wheel/model mounts, no network or host port, a This is a small dense IQ3_S serving and released-wheel fallback check. It does |
Signed-off-by: Hao Liu <liuhao24@sjtu.edu.cn>
Signed-off-by: Hao Liu <liuhao24@sjtu.edu.cn>
Refreshed-head validationThe Draft branch is now synchronized and pinned to:
The feature diff from Validation on one GB10 (
I also reran the small revision-pinned IQ3_S serving check on
The two client JSON files were byte-for-byte identical (SHA-256 This remains a Draft. The original approximately 100 GB routed-expert 4k/16k A/B, official H100/B200 AOT runs, and official x86_64/aarch64 wheel CI are still pending. |
|
Thanks @liuhao-labs — the pinned-protocol run is done, on the exact setup from #35019: same GB10 box (sm_121a, CUDA 13, aarch64), same 100 GiB DeepSeek-V4-Flash 0731 GGUF recipe, same harness. Pins and gates — verified
ModelThe exact GGUF behind the issue's numbers had been deleted from disk. I reconstructed it from the surviving Unsloth UD-IQ3_XXS shards: the two MXFP4 routed-expert tensors ( All 127 I-quant tensors are routed-expert tensors ( ArmsArms 2 and 3 share an identical SGLang source tree — only the kernel wheel differs.
Arm 1 ( Route evidence (not the capability flag)The capability boolean is insufficient on its own, so the PR's own dispatch functions were called from the installed wheel against the installed source at real model shapes (hidden 4096, moe_intermediate 2048, E=256, top_k=6, IQ3_XXS): Arm 2 — H + released wheel: Arm 3 — H + wheel built from H: So One scoping observation: issue #35019 named two fallbacks — dense projections and MoE experts. This PR closes the MoE one. The dense path still routes to Measured — ctx 4k, frozen argv, cold prefillFrozen argv, identical for every arm, only the kernel wheel differs: with
Per-run ( The decode column is the control. Decode runs at M = 1, below the Arm 3 also uses about 1 GiB less memory at the same workload, consistent with MMQ consuming the quantised weights directly instead of materialising them. On a box where this model leaves only a couple of GiB of headroom, that matters as much as the throughput. Correctness, temperature 0, both arms — coherent, no NaN or garbage: Baseline reproduction (control on the reconstructed model)The original issue image
Prefill within 2.5 % and decode within 3 % of the published figures — so the reconstructed checkpoint and this box both reproduce the issue's baseline. That is the control the arm numbers hang off. Notes for reproduction
16k — not run, reason documentedThe 4k arms already sit at 2–3 GiB of free unified memory; a 16k KV pool does not fit alongside ~99 GiB of weights on this box under the frozen memory constraints, so ctx 16k was not attempted rather than misreported. If you want the 16k column anyway, I can attempt it with the same arms and a documented memory trade-off — just say the word. Preliminary: prefill 4k improves +59.8%, TTFT −40%, decode flat, peak-memory headroom +1 GiB, on identical args, cold prefill, route-verified. This is exactly the class of result I hoped this PR would produce; the conservative gating and the capability handshake make the separation between arms clean. |
|
Quick follow-up, separate from the data: thanks for the pinned protocol — it's what made this run interpretable, and that's genuinely rare. Arms 2 vs 3 differing by exactly one wheel, with the route selection visible in the logs rather than hidden behind a capability flag, is the shape that lets a result stand on its own instead of on trust. I'm around if the 16k column is wanted. |
|
Thanks for the H-pinned 4k validation in the latest result. I have updated the PR body with the reconstructed-checkpoint caveat and the published aarch64 wheel hash. The result is:
The literal U arm was not run separately, and 16k does not fit the reported 121 GiB unified-memory budget after the approximately 99 GiB reconstructed checkpoint. Those limitations are now explicit in the body. The reconstructed checkpoint is targeted evidence, not a bit-identical copy of the deleted original. The PR is now Ready for review and CODEOWNERS have been requested. Could a maintainer please review the AOT/SRT changes and trigger the normal platform CI when convenient? The earlier red checks were Draft-gate failures; the H-specific lint workflow passed. |
|
/tag-and-rerun-ci |
|
@BBuf @merrymercy @HaiShaw @ispobock The PR is now Ready for review, and the H-specific lint check is green. The issue reporter has completed the H-pinned 4k external A/B (+59.8% prefill, -40% TTFT; decode control stable); the reconstructed-checkpoint and 16k memory caveats are documented in the body. Could a maintainer please review the AOT/SRT changes and add the |
|
The current red checks are still stopping in I also tried adding |
|
Follow-up on the CI gate (2026-10-08): @BBuf @HaiShaw @ispobock @merrymercy could one of you please add the repository I rechecked the current H head ( |
|
The branch is now refreshed against the current upstream @BBuf @HaiShaw @ispobock @merrymercy, the new head's workflows still stop at the same |
|
Final sync note: upstream @BBuf @HaiShaw @ispobock @merrymercy, please add |
Reviewer evidence packet and merge assessmentI added a reproducibility packet with the current source provenance, route logs, test counts, external A/B data, gate log, and explicit limitations: My assessment of the evidence:
The only missing merge evidence is repository-owned: |
|
The evidence packet is now aligned with the final refreshed head The benchmark PNGs and the reviewer matrix are linked in the packet. The packet deliberately separates high-confidence kernel correctness evidence, medium-to-high-confidence routed-MoE A/B evidence, and the still-pending official CI/CODEOWNER review. |
|
I also uploaded the captured text logs so the route and gate claims are inspectable without relying on screenshots: The route log records capability, dense/MoE dispatch transitions, CUDA Graph replay, old-wheel fallback, and the client-output hash. The gate log records that the latest head is not draft and is stopped specifically by the missing |
Revalidation after main #43236: shared GGUF activation mathI verified a semantic dependency change outside this PR's 15 paths: main Pinned report, raw logs, compiler commands, scripts and SHA256 manifest
Scope: this run uses Torch 2.11/CUDA13 and freshly compiled GGUF sources in The original PR head remains |
Released 0.4.9 ABI and current-source paired serving follow-upThe cached 0.4.4 startup gap from my component report was resolved in an Pinned runtime report, server/client logs, wheel hashes and scripts Main Evidence scope: published 0.4.9 does not contain the new capability, so The first 0.03 static-memory attempt failed the real KV-budget guard; both The PR branch remains clean at H, with no feature-code change indicated. |
|
Published-wheel MoE follow-up with matched Torch 2.14.1/CUDA13:
Pinned report, raw numeric outputs, exact commands, three Docker OOM events and reproducible scripts The earlier component/test-namespace results and historical +59.8% prefill / -40% TTFT retain their original scope/runtime; they are not new full-wheel or current-main throughput results. Official H100/B200 CI and the existing |

Motivation
SGLang supports I-quant GGUF weights for dequantization and MMVQ, but does not
currently include them in dense or batched-MoE MMQ dispatch. Beyond the
small-batch MMVQ boundary, dense I-quant prefill dequantizes the full weight to
BF16, while I-quant MoE prefill remains on the decode-oriented vector kernel.
This change adds the eight I-quant formats supported by the upstream MMQ
implementation.
IQ1_Mremains on fallback because that implementation doesnot provide its MMQ dot product.
Fixes #35019
Modifications
IQ1_S,IQ2_XXS,IQ2_XS,IQ2_S,IQ3_XXS,IQ3_S,IQ4_NL, andIQ4_XS.MMQ for M=9..16, and dequantization from M=17. Narrow matrices retain MMVQ
through M=16 and dequantization from M=17.
reuse, expert count, CUDA grid capacity, and both projection K alignments are
suitable.
sglang-kernelexposes that capability.Q8_1in the high-level selector and direct CUDA GGUFcompute entry points.
strides, padded-tail bounds, complete q8 scale-tile loading, low-level
alignment checks, and deterministic zero output for invalid or remote
experts.
coverage, and a checked-in dense benchmark using a revision-pinned GGUF
fixture.
The SRT caller enables IQ MMQ only when its loaded kernel package exposes the
new capability; otherwise it retains the vector/dequantization fallback. The
historical compatibility tests below used
sglang-kernel==0.4.6.post1.At the current PR head and the latest tested main, the dependency pins have
advanced to
sglang-kernel==0.4.9andtorch==2.14.1. A kernel releasecontaining the new capability and a follow-up pin update are still needed to
enable IQ MMQ in normal installations. This PR does not set an unreleased pin.
The kernel implementation is adapted from
aimbit-ni/vllm@037e1d547c15313aa7e2bb5fc83390ab0c857314and the algorithmsin
ggml-org/llama.cpp#8495.THIRDPARTYNOTICES.txtincludes the ggml MITnotice.
Accuracy Tests
Shared activation-policy revalidation, 2026-10-13
Latest tested main
7ff3a112846a3fcc12a27bba09d644885a226e4d(#43236)enables
--use_fast_mathon Blackwell in the shared activation called byGGUF MoE. I tested main and a clean detached merge with the unchanged PR head
0a39ec3a8754e3c4426950a5a93046c048a03f07; the integration tree is36909c6658f0ce1ed346db5b85a3568325b9357d, still 15 files (+4127/-81).The original PR branch was not rewritten or advanced for this verification.
Pinned report with raw logs, compiler invocations and reproduction scripts
main and 60 on main+PR, all finite and within existing
0.01/0.01bounds.source, covering FP16/BF16, SiLU/GELU, eight IQ types, mixed Q5_0 directions
and M=1/127/128/129. Fast-vs-precise max difference:
3.05176e-5.54 passed; existing GGUF AOT module: 153 passed. Four main+PR full MoE
CUDA Graph replays match eager outputs exactly.
The component checks use Torch 2.11/CUDA13, newly compiled GGUF functions in an
isolated test namespace and the recorded auxiliary 0.4.4 wheel. They do not
prove the PR-built full wheel's ABI. No numerical kernel is mocked.
I then resolved the cached-image gap using the official hash-verified
sglang-kernel 0.4.9wheel with matched Torch 2.14.1, Transformers 5.19.0,FlashInfer 0.7.1, CUTLASS DSL 4.8.0 and Triton 3.8.0 in a separate environment.
The unmodified published wheel loaded successfully (SHA256
384a0d2158740f5ab42cfc64c872640bb3c80f3b0ec3b4666bc3efb553254bc4).Both pinned main and main+PR loaded the exact prior 0.5B IQ3_S GGUF model and
returned health/generate HTTP 200, 8 prompt / 16 completion tokens, zero
cached tokens, and identical output token IDs/text. The canonical output hash
is
2604448b1bc1b2c9a10961f6b562bed70aab5041db4cb8a7db54e83f9cfde287.Paired serving provenance, raw logs and comparison
No test-namespace operator replacement or version-check bypass was used in
these serving runs; capability is false with the published wheel.
This proves the current released-wheel small dense-model fallback/serving path,
not enabled IQ MMQ full-model serving or the PR-built full wheel's ABI. Official
CI and H100/B200 remain separate requirements. The first 0.03 memory-fraction
attempt hit the real KV budget guard, so both final arms used 0.05, the same
1024-token cap, one request and a 10 GiB container limit. No PR-related
numerical regression or required feature-code change was found.
Published MoE binding follow-up, 2026-10-13
I additionally tested latest main
27b68303d043ddbddf9861c55c26bc8617ea7c35and its clean detached merge withthis PR (
449c32e493e80e67190fcf1f61976dc6045159e9, treebb5c83cc334e80c51e6a0eb44045a5358c189162) using the unmodified official0.4.9 production common_ops and Torch 2.14.1/CUDA13. Each source passed
32 real two-projection expert-layer cases: eight IQ formats, FP16/BF16,
SiLU/GELU, M=128/E=8/top-k=2, input/intermediate width 256. Outputs were
finite and within
atol=1, rtol=0.1of the dequantized reference; maximumabsolute error was 0.00366211. All 32 paired outputs were bit-identical.
Profiler records two real
sgl_kernel::ggml_moe_a8_veccalls and the shareddefault fast-math activation; fresh caches and actual compiler flags were
recorded. Capability remains false, so this is released-wheel expert-layer
fallback validation, not enabled IQ MMQ or full expert-model serving.
Raw outputs, library hashes, compiler commands and build attempts
I attempted the complete current-source AOT wheel with matched Torch and
one build worker/NVCC thread. Default builds hit cgroup OOM at 10 and 14 GiB
in existing FP8 units; an all-source/all-default-target build with SM121a-only
common_ops also hit 14 GiB OOM in the same existing
fp8_gemm_kernel.cu.Those failing source units are identical on latest main and main+PR.
Commands, exit 137, three Docker OOM events and resource samples are included.
No wheel was emitted: the prepared 80 enabled-production cases and 153-test
GGUF run against a new full wheel were not executed. New full-wheel ABI,
capability=true expert validation and official H100/B200 CI remain outstanding.
The earlier component/test-namespace passes do not fill these gaps.
The 15 upstream commits since the earlier frozen main did not change GGUF,
shared activation/JIT core or AOT build metadata by blob. The clean merge
still has the same 15-file feature diff; the original PR head was not rewritten.
Latest main and official 0.4.9 still lack IQ-MMQ capability, so the proposed
support remains necessary. This follow-up is correctness/build evidence;
historical speed figures below retain their original pinned runtime.
Historical pinned-runtime validation
Local validation used the installed CUDA 13/aarch64 AOT wheel on one NVIDIA
GB10 (
sm_121), rather than JIT-compiled kernels.The prior validation used upstream base
0c84eaba7f8d6674a360839426cacde4e1acd851and clean local head4c3e4c2350f4d6c4ff2a785e9b294938766a3cc6. On 2026-10-09, upstreammainwas synchronized through
6e7beace143964386ce2e4418401b7369f0dabd0into thecurrent PR head
0a39ec3a8754e3c4426950a5a93046c048a03f07. The three-way mergewas clean and the feature diff remains exactly 15 files (+4127/-81). The 67
intervening main commits have no path overlap with the feature files; the four
overlapping paths from the earlier sync contained only AOT cleanup and
formatting, not GGUF MMQ logic. The local numbers below belong to the historical
validation head and runtime; they do not validate the current upstream runtime
end to end. The refreshed head is pending official CI.
626d6ee79dd37dae2242f2f18a97b0536c95dfa4c053cb56d7573de23324c6e010 passed57 passedpython/sglang/kernels/aot/tests/test_gguf.py:153 passedUsing the same CUDA 13/aarch64 build configuration, the compressed wheel grew
from 29.473 MiB to 30.999 MiB: +1.527 MiB (+5.18%). Each bundled
architecture-specific
common_opsshared object grew by 917,504 bytes.The historical wheel was built before the August main-only merge. Its AOT tree,
SRT GGUF selector and registered routing test matched the August validation head
4c3e4c2350f4d6c4ff2a785e9b294938766a3cc6. That source-equivalence statementdoes not extend to the October runtime or today's shared activation policy.
The production smoke observed the new capability as enabled and covered:
Q8_1rejection, K-alignment guards, and invalid-expert zero outputMaximum reserved GPU memory during the production smoke was 528 MiB.
A compatibility smoke combined the patched SRT source with a locally cached
sglang-kernel==0.4.6.post1baseline artifact (SHA-256c7aac3ab20ff3c704e2bbc1a2fa78e5142a65150f12bca74f8e4cbd4f651d958). This isnot the published PyPI artifact. The published aarch64 wheel has SHA-256
7eccd61408b44b55ab35cdbcf8a05243ce2a9a5e781fabb00da375af7d7130a1; theexternal 4k run below used that published wheel. The local smoke observed
capability=False, selecteddequantizefor an IQ dense input, and returnedshape
[9, 18944]. This verifies that the combined source remains correctbefore the new kernel wheel is released.
A final-head bounded end-to-end serving sanity check also passed with the
artifacts in
/tmp/sglang-36122-e2e-final.XwQYAuand the revision-pinnedlegraphista/Qwen2.5-0.5B-Instruct-IMat-GGUFQwen2.5-0.5B-Instruct.IQ3_S.gguffile (SHA-256b7685f565fc6e49a8f9bc0fe09b9bb22ca0d5e4b10635cd4b181597f113794b6).The installed patch wheel (SHA-256
626d6ee7...) reportedcapability=True;the same synced SRT with the local baseline artifact (SHA-256
c7aac3ab...)reported
capability=False. Both configurations loaded the model, returnedHTTP 200 from the health and generation requests, and recorded zero cached
tokens for generation. Their client JSON files were byte-for-byte identical
with SHA-256
bd3c11d390f7a373e534f5361807119b2c040bc325cfe1f6fd2c8165d4426933:11 prompt tokens, 16 completion tokens, a length finish, and text:
Both runs used a single GB10 (
sm_121, CUDA 13, aarch64), read-only source,wheel, and model mounts, no network or host port, a 10 GiB container memory
limit,
--mem-fraction-static 0.03,--max-total-tokens 1024, one runningrequest, Triton attention, PyTorch sampling, and CUDA graphs disabled. The patch
run loaded 0.88 GB of weights and allocated approximately 0.02 GB of KV cache.
This validates a small dense IQ3_S model and the released-wheel fallback; it
does not replace testing the original approximately 100 GB routed-expert model.
The critical server-log scan found no traceback, CUDA error, NaN, or
illegal-memory failure; the remaining messages were the expected
nvidia-smifallback and shared local-tokenizer warnings.
The H-specific Lint workflow
passed, including the repository pre-commit checks, documentation checks, and
the dedicated sgl-kernel clang-format check. The older
Lint workflow
also passed for prior head
0137a1e.... Normal platform CI is gated on therepository's
run-cilabel.The complete local AOT collection is not claimed as passing. A bounded run
reached 971 passed and 2 skipped before an unrelated large AWQ parameter
exceeded the allocator cap. Excluding AWQ reached 970 passed and 2,310 skipped
before FlashMLA sparse prefill rejected SM121.
Normal/full PR CI is still pending because the repository's required
run-cilabel has not yet been added. The current red PR Test entries are gate failures
for that missing label, and their wheel, H100, and B200 jobs were skipped; they
are not kernel test failures. A maintainer must add
run-ci(or run theproject's authorized slash command) so the normal workflow builds and installs
the PR-local wheel on the official x86_64/aarch64 and H100/B200 environments.
The Issue reporter subsequently completed a frozen 4k cold-prefill comparison
on this H-pinned source using a reconstructed approximately 99.18 GiB
DeepSeek-V4-Flash 0731 checkpoint (report,
follow-up).
The checkpoint is a reconstruction from surviving Unsloth shards rather than a
bit-identical copy of the deleted original: two MXFP4 expert tensors were
converted to Q8_0 and the remaining tensors were byte-copied. The H source with
the published released aarch64 wheel selected the vector MoE path, while H with
the H-built wheel selected batched MMQ at M>=128; both arms used the same H
source and passed the route and correctness checks.
Across three measured 4k runs (concurrency 1, cold prefill), prefill throughput
was 60.93 versus 97.37 tokens/s (+59.8%), TTFT was 26,513 versus 15,912 ms
(-40.0%), and decode TPOT was 61.60 versus 62.09 ms (+0.8%). The literal U plus
released-wheel arm was not run separately; the reporter's historical 0.5.18
baseline reproduced the issue-scale result. A 16k run was not feasible under
the frozen approximately 99 GiB model and 121 GiB unified-memory budget because
the 4k run left only about 2-3 GiB for KV growth. The reconstructed model also
required an out-of-tree loader patch, so these numbers are targeted external
validation, not an official full-main serving result.
Speed Tests and Profiling
These are directional route-selection microbenchmarks from a shared GB10 that
retained a live Qwen service. They are not uncontended end-to-end throughput or
cross-architecture claims. They predate the main sync and were not rerun; the
sync did not change the IQ kernel patch represented by these measurements.
The checked-in benchmark compares direct MMQ with dequantization plus BF16
matmul using revision-pinned
18944x1024GGUF fixtures. The table below usestwo independent benchmark invocations. Each value is the mean speedup, with the
two-run range in brackets; speedup is
(dequantize + BF16 matmul) / MMQ.The full M=9/16/17/24/32 matrix and reproduction notes are in the
benchmark comment.
The M=16 ranges retain at least 1.24x measured headroom across all eight
formats. Although the isolated M=17 sample was also faster, M=18..23 were not
measured and M=24 regressed on multiple formats. The shared GB10 measurements
do not justify interpolating a larger universal CUDA gate, so this PR uses the
conservative M<=16 boundary. M=17 and above retain dequantization.
Directional MoE measurements were:
The external 4k result above is a targeted serving throughput validation; it is
not a claim about uncontended throughput or a literal bit-identical checkpoint.
The 16k comparison and a separately measured literal-U arm remain unavailable
under the reported hardware/model constraints. Official x86_64/aarch64,
H100/B200 CI and maintainer review are still pending; see the
original reviewer response
and the
pinned U/H protocol.
Checklist
Review and Merge Process
/tag-and-rerun-ci,/tag-run-ci-label,/rerun-failed-ciCI States
Latest PR Test (Base): ❌ Run #37882097010
Latest PR Test (Extra): ❌ Run #37882096734
Latest PR Test (AMD ROCm 10): ❌ Run #37882097020