feat(KERNEL-QUANT-CIQ-GEMM-ROCM): keep-quant GEMM providers on kROCM - #1
Closed
ghazni101 wants to merge 3 commits into
Closed
feat(KERNEL-QUANT-CIQ-GEMM-ROCM): keep-quant GEMM providers on kROCM#1ghazni101 wants to merge 3 commits into
ghazni101 wants to merge 3 commits into
Conversation
…tion call site (mudler#1273) Closes the "Owed" item from mudler#1065: CheckKvCacheShape's production call site in GPUModelRunner::initialize_kv_cache now has a test. Building the runner with a non-multiple-of-16 block size (kBlockSize = 8) asserts the throw at construction, from the FLASH_ATTN backend's own get_kv_cache_shape — the executable statement of the contract the server's --block-size validation and the bench rounding exist to prevent at the entry points. Validated on gfx1151 (Strix Halo, ROCm 7.2.3) as part of the mudler#41 M3 battery: test_runner 20/20 cases, 544 assertions, on the current-main build with mudler#1056 + mudler#1065 merged. Issue: mudler#41 FOLLOWING_AGENTS_PROTOCOL Following-Agents-Protocol: true AI-Assisted: true Assisted-by: DeepSeekV4:Flash [Freebuff]
The ROCm backend registers no quantized-weight GEMM provider, so every GGUF k-quant weight on an AMD card computes off device. The spec scopes W1 as kMatmulBTQuant and kMatmulBTQuantGrouped providers mirroring the CUDA sibling, which the GGUF loader reaches automatically once they are registered, and owes the upstream csrc/rocm W4A16 family behind a loader consumer that does not exist yet. The issue index gains the three 2026-08-21 campaign issues: mudler#1586 toolchain adoption and optimization, mudler#1587 this row, mudler#1588 the Qwen3.5-0.8B numerics characterization. FOLLOWING_AGENTS_PROTOCOL Following-Agents-Protocol: true AI-Assisted: true Assisted-by: AGENT:ox-alpha [omp]
… kROCM The GGUF loader routes a block-typed weight to MatmulBTQuant whenever the running device has the provider, so registering these two ops lights up keep-quant compute on every ROCm board with no model-path change: the dense and grouped MoE towers stage once through ResidentWeight and dispatch to the new device GEMM. Coverage mirrors the CUDA sibling exactly — the ten Q8_K-family encodings plus a native Q8_0 arm. The integer dots are the portable scalar forms of the CPU reference bodies in the CPU accumulation order, because gfx1100 exposes no signed byte dot (v_dot4_i32_iu8 is unsigned-only; sdot4 needs a feature this target does not offer), and the gate is bit-exactness against the CPU tier at NMSE 1e-6 with the f64 dequant band at 5e-4. Unsupported dtypes throw naming the dtype instead of silently falling back to a host kernel that cannot follow device pointers; VT_GGUF_KEEP_QUANT=0 restores load-time expansion. Gates on gfx1100 / ROCm 7.14.0: test_rocm_quant_dot 132,094 assertions green across all ten encodings (decode through prefill shapes, broadcast and per-row grouped arms over a poisoned output buffer), focused ctest 'rocm|cross_device|quant' 20/21 with only the pre-existing MoeSiluMul bf16 exactness failure (mudler#1588) remaining, and an end-to-end Qwen3.5-0.8B Q4_K_M decode that is deterministic on device. FOLLOWING_AGENTS_PROTOCOL Following-Agents-Protocol: true AI-Assisted: true Assisted-by: AGENT:ox-alpha [omp]
ghazni101
pushed a commit
that referenced
this pull request
Aug 27, 2026
…ion twice, and the row that nearly replaced this one was refuted (mudler#2061) (mudler#2062) Opens W11's re-ranked lever #1 as its own campaign, and corrects the record that briefly recommended a different one. THE LEVER. `LagunaFfnBlock`'s grouped-MoE arm issues two `LqGemmGrouped` calls over the same activation, one for gate and one for up, and each re-quantizes it to Q8_K internally. W11 measured `QuantizeQ8KKernel` at 12.4% of decode GPU time and half of that is duplicate. `vt::MoeGateUpSwiGLUGrouped` quantizes once, runs both GEMMs and applies the SwiGLU in its epilogue. It is also a shared-seam obligation independent of speed, because AGENTS.md routes mergeable MLP projections through the fused group and Laguna runs two separate ones. TWO HAZARDS W11 DOES NOT NAME, and the second may bound the row. The fused op takes a broadcast activation, so the `Pk x H` staging buffer and its host copy loop may disappear as well. And the op requires both expert towers to share a block-quant dtype, while `UD-Q4_K_XL` is a DYNAMIC quant that varies type per tensor BY DESIGN — so the gate model may be exactly the checkpoint that cannot take this path. W1 reads the real tensor table before any code is written, because that is a fact about a file rather than something to discover from a failing test. WHAT THIS SPEC CORRECTS. A previous change recommended reworking Laguna's host-orchestrated FFN and this row nearly became that. W11 had already taken a GO/NO-GO on it and DEMOTED device-residency: after W8 and W9 landed, GPU-busy (2.56 s) is approximately the host sync time (2.59 s) is approximately the decode wall, so the host is serially WAITING on real kernels rather than idling between them, and the rework recovers the ~0.02 s/tok W11 already priced. The host loops are real code and were read correctly; the conclusion drawn from them was stale by a month. Source inspection identifies candidates and the trace identifies the executed path — and here the trace existed before the inference did. The placement records carried the same error in a second form and are corrected in both public documents and the row spec. They said Laguna has no device-resident expert compute for a placement to move. It HAS device-resident expert compute: `LqGemmGrouped` dispatches `vt::MatmulBTQuantGrouped`. What it lacks is a `[T,H] -> DBuf` ENTRY, because the FFN boundary is a per-token host float row. That is a shape gap, and it is now stated as one — which also separates Laguna from DeepSeek-V4 and Kimi-Linear, whose experts genuinely do run on the host. The bit-exactness gate is written to refuse a near-tie. Either the fused arm reproduces the two-call arm byte for byte, or the row records the divergence and stops; 6% is not worth a value change, and the two-call arm stays as the reference either way. No number from the W7 spec's llama.cpp denominator is quoted here. `27.8 tok/s` and every ratio derived from it came from an unrecorded fork branch with no commit SHA and are superseded under mudler#1003. This row reports ours-versus-ours. Gates: `check-agent-record` ok. `agent-preflight` reports `audit-live-rows` red, verified INHERITED rather than caused: `audit-live-rows.py --check` returns 1 on clean `origin/main` and identically with this change, and the rows it names are ones this change does not touch. FOLLOWING_AGENTS_PROTOCOL Following-Agents-Protocol: true AI-Assisted: true Assisted-by: Claude:claude-opus-5 [Claude Code] Co-authored-by: Ettore Di Giacinto <mudler@localai.io>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What changed
W1 of KERNEL-QUANT-CIQ-GEMM-ROCM (mudler#1587): the kROCM providers for
OpId::kMatmulBTQuantandOpId::kMatmulBTQuantGrouped, in the newsrc/vt/rocm/rocm_quant_dot.hip, plus the committed spec(
.agents/specs/kernel-quant-ciq-gemm-rocm.md) and a red-first gate(
tests/vt/test_rocm_quant_dot.cpp).Registering the providers flips
GgufQuantComputeAvailable()true onROCm, so every GGUF k-quant model now computes on the AMD GPU through
the existing seams (loader policy ->
vt::MatmulBT[Quant]->GetOp(kROCM)) with zero model-path edits. Towers stage once throughthe existing
ResidentWeightpath.Coverage mirrors the CUDA sibling exactly: ten Q8_K-family encodings
(Q2_K, Q3_K, Q4_K, Q5_K, Q6_K, IQ2_XXS, IQ3_XXS, IQ2_S, IQ1_S,
IQ1_XXXS) plus a native Q8_0 arm. The IQ codebooks reuse
cuda_quant_iq_tables.cuhas the single source — pure__device__syntax, no CUDA — so no transcription drift is possible.
Why
The ROCm backend had no quantized-weight GEMM provider: every GGUF
k-quant weight on an AMD card computed off device (bf16 expansion at
load). AGENTS.md makes quantized arms a standing requirement. Upstream
pins an RDNA3 W4A16 family in
csrc/rocm(gptq_gemm_rdna3gatedVLLM_ROCM_GFX1100) but nothing in this tree can reach it yet — noAWQ/GPTQ consumer exists — so that family stays under
## Owedin thespec (W2), per the reachability rule.
HIP delta that shaped the implementation (measured on gfx1100 /
ROCm 7.14.0)
gfx1100 exposes NO signed byte dot:
__dp4adoes not exist;__builtin_amdgcn_sdot4needs target featuredot1-insts, which clangrejects for this target ("not a recognized feature"); the one hardware
dot that assembles (
v_dot4_i32_iu8) is UNSIGNEDxUNSIGNED and computeswrong over signed Q8 activations (verified by device experiment:
byte 0xFD contributed +253x, not -3x). The integer dots therefore ship
as portable scalar loops in the CPU reference's exact accumulation
order — which is what makes the bit-exactness gate achievable. The ISA
dots are recorded as W2 levers with their own exactness arguments.
__shfl_down_syncalso requires a 64-bit mask on this target.Unsupported dtypes (Q4_0/MXFP4, Q8_0-activation) THROW naming the dtype
instead of falling back to a host kernel that cannot follow device
pointers on a discrete card;
VT_GGUF_KEEP_QUANT=0restores load-timebf16 expansion.
How to verify
On gfx1100 / ROCm 7.14.0 (container
rocm-dev:7.14.0):Measured on this tree:
test_rocm_quant_dot: 132,094 assertions green — all ten encodings xdecode/prefill shapes x broadcast/per-row grouped arms, output buffer
poisoned before every launch so a silent no-op fails (ENG-EXPERT-STREAM: the CUDA arm for IQ1_S and IQ1_XXXS, verified on GB10 mudler/vllm.cpp#967 class).
ctest -R 'rocm|cross_device|quant': 20 of 21 pass;the one failure is the PRE-EXISTING MoeSiluMul bf16 exactness case
tracked in Characterize Qwen3.5-0.8B CPU against ROCm numerics on gfx1100 mudler/vllm.cpp#1588 (present on main before this change).
deterministic across runs, coherent output, warm ~27.6 tok/s at 4B.
What remains unverified or out of scope
a recorded deviation (subagent runtime had no model configured). A
fresh review pass against the spec is still owed before merge.
win; the unsigned-dot/dot2 ISA levers are W2 with their own exactness
arguments.
the spec's
## Owed.riding the follow-up rather than widening this PR.
Closes mudler#1587
FOLLOWING_AGENTS_PROTOCOL
Following-Agents-Protocol: true
AI-Assisted: true
Assisted-by: AGENT:ox-alpha [omp]