Conversation
vLLM writes the packed fp8_ds_mla tile scales as raw fp32 amax/448 in every writer, but this backend asked FlashInfer to read them as pow2_fp32, which keeps only the exponent bits and dequantizes with a scale up to 2x too small. The reader was picked from a model_type allowlist covering only glm*, so every other sparse model landing here reads its scales wrong: DeepSeek-V3.2 today, and HY V4 once it can select this backend. The encoding belongs to the cache layout, not the model, so drop the lookup. Measured on an SM120 (RTX PRO 4500 Blackwell, flashinfer 0.6.17) by packing a cache the way vLLM's writer does and calling the same decode API per format: 4083 of 4096 stored scales are not powers of two, and arbitrary_fp32 tracks the writer reference 7x closer than pow2_fp32 (rel L2 0.0030 vs 0.0213), widening to 0.0196 vs 0.1985 as per-tile scale spread grows. AI assistance was used for the FlashInfer/vLLM kernel cross-check, the hardware A/B and the test. Test: python -m pytest tests/v1/attention/test_flashinfer_sparse_mla_sm120_api.py Co-authored-by: Cursor Claude Opus 5 Signed-off-by: oops-oom <73481342@qq.com>
Describe the fix in terms of vLLM's 656-byte writer contract so the distinct DeepSeek V4 footer-scale layout is not accidentally included. Co-authored-by: Cursor GPT-5.6 Sol <cursoragent@cursor.com> Signed-off-by: oops-oom <73481342@qq.com>
Remove the unrelated dense Kimi-K3 path and redundant explanatory comments so the regression test only names models that can select this backend. Co-authored-by: Cursor GPT-5.6 Sol <cursoragent@cursor.com> Signed-off-by: oops-oom <73481342@qq.com>
Contributor
Author
|
Hi @lucifer1004, could you help sanity-check the intended scale semantics here? |
Contributor
|
This pull request has merge conflicts that must be resolved before it can be |
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.
Purpose
The read format has to match the write format. The vLLM writers used with this backend store each tile scale as raw fp32 amax / 448 (concat_and_cache_ds_mla and the DeepSeek-V3.2 fused Triton path). However,
FLASHINFER_MLA_SPARSE_SM120asked FlashInfer forpow2_fp32, which extracts the exponent and reconstructs2^floor(log2(scale)). For a non-power-of-two scale written by vLLM, that is smaller by a factor in(0.5, 1].The format was chosen from a
model_typeallowlist that only sentglm*to the correct reader, so every other sparse model landing here reads its scales wrong: DeepSeek-V3.2 today, and HY V4 as soon as it can select this backend (it needsthe sink support in the stacked follow-up, since
learnable_sinkdefaults to on). #54434FlashInfer supports both scale conventions for the same 656-byte physical layout, but vLLM's writer contract currently always stores arbitrary fp32 scales. Kimi-K3 demonstrates that this convention is not tied to the model label: its dense MLA path writes the same layout even though it never reaches this sparse backend. This backend accepts no other layout (it raises unless
kv_cache_dtype == "fp8_ds_mla"), so its reader format becomes a constant.DeepSeek-V4 is not a counterexample. It reuses the
fp8_ds_mlastring for a different footer-scale layout: 576 bytes of per-token data plus 8 bytes of UE8M02^(u8-127)scales in the page footer, or 584 logical bytes per token.That layout is written by DSv4's own CuteDSL/Triton insert rather than
concat_and_cache_ds_mla, and DSv4 is rejected here:FLASHINFER_MLA_SPARSE_SM120is not a DSv4 backend; those models must useFLASHINFER_MLA_SPARSE_DSV4.Test Plan
Run on real SM120 hardware (AWS
g7.2xlarge: RTX PRO 4500 Blackwell, sm_120, driver 595.91.07, CUDA 13.2, torch 2.13.0+cu132, flashinfer 0.6.17).Because this patch changes how bytes are dequantized, the decisive test is a kernel-level A/B: pack a
fp8_ds_mlacache exactly the way vLLM's writer does (amax / 448stored as raw fp32), call the same public FlashInfer decode APIthis backend calls, once per
kv_scale_format, and compare both against an fp32 dequant-then-attention reference computed from the same bytes.Test Result
Unit tests: 18 passed.
Neighbouring suite
test_sparse_mla_backends.py: 46 passed, 504 skipped, 4 failed — the same 4masked_mhaprefill cases fail on the unpatched base commit (d3d79ffc1e) on this GPU, so they are pre-existing and unrelated.Scale A/B, 1024-token cache, 32 heads, top-k 2048. 4083 of 4096 stored tile scales are not powers of two (mean
pow2/truefactor 0.776, min 0.505), so the two readers genuinely disagree:arbitrary_fp32(this PR)pow2_fp32(before)The gap widens with per-tile scale spread, which is what real K vectors look like (outlier channels in the nope tiles):
arbitrary_fp32pow2_fp32FlashInfer's own docstring confirms the two semantics:
"auto"/"pow2_fp32""select DSv3.2 power-of-2 FP32 inline scales","arbitrary_fp32""selects GLM-style arbitrary FP32 inline scales".No end-to-end eval: every model that can reach this backend (DeepSeek-V3.2, GLM, HY V4) is far larger than the biggest single SM120 (96 GB), so a serving eval is not reachable on this hardware. The A/B above measures exactly the quantity this patch changes, on the kernel this patch configures.
A/B harness (abridged)
Why this is not duplicating an existing PR
Checked per AGENTS.md:
No open PR changes the model-dependent
kv_scale_formatselection fixed here (both explicit format searches return nothing). #47527 wires the packed-cache arguments, includingkv_scale_format, into the released FlashInfer API butpreserves the existing selection; this PR fixes the value passed through that API. #53969 adds NoPE support and validates the effective top-k buffer width. Both touch the same files, so textual conflicts are possible, but neither duplicates this change.
AI assistance disclosure (per AGENTS.md)
AI assistance was used to cross-check the vLLM writer kernels against FlashInfer's reader paths, to run the SM120 hardware A/B above, and to write the test. The submitter reviewed every changed line.