Skip to content

int8 per-(token,head) KV cache for the Qwen3.8-Flash-Next QSA path - #1

Open
rmagur1203 wants to merge 2 commits into
mainfrom
qsa-int8-kv
Open

rmagur1203 wants to merge 2 commits into
mainfrom
qsa-int8-kv

Conversation

@rmagur1203

Copy link
Copy Markdown
Owner

Tracking PR inside my own fork — not intended for vllm-project/vllm as-is.

Why this is not an upstream PR yet

  • These are runtime patch scripts against the pinned preview image
    vllm/vllm-openai:qwen38-flash-next-arm64-cu130 (0.1.dev20073+g8e685d198), whose module
    is vllm/models/qwen3_8_flash_next/. Upstream renamed it to vllm/models/qwen4_exp/.
  • Upstream main has no KV quantization plumbing in that module at all
    _cast_kv_tile, KV_QUANT_MODE, k_scale_ptr all return 0 occurrences. The fp8
    groundwork this builds on is still in review as [Model] Qwen4Exp: fp8_e4m3 main KV cache on the QSA path vllm-project/vllm#55557, so an int8 PR
    would have to duplicate an active review.
  • I cannot test against main on this hardware: PLE CPU offload
    (VLLM_PLE_CPU_OFFLOAD, vllm/v1/ple_offload/) is not upstream, and without it the 125B
    checkpoint does not load on a single 121 GiB GB10.

Opened so the code behind vllm-project#56081 and my comment on
vllm-project#54426 is inspectable, and so the work has a stable URL.

What is in here

qsa-kv-int8/ — patches, tools, and the measurement grids. See the README for the full
write-up.

Headline result

int8 per-(token,head) KV on the QSA sparse-attention path, 9-cell grid, matched
background load, KV pool pinned to 13.75 GiB:

bf16 fp8_e4m3 int8 int8 vs fp8
TTFT 23.74 s 24.75 s 22.79 s −7.9 %
Decode 13.57 tok/s 12.74 tok/s 13.41 tok/s +5.2 %
MTP acceptance 60.63 % 57.90 % 59.79 % +1.9 pts
KV pool 428,699 857,210 857,210 same

The finding worth upstreaming (vllm-project#56081)

vLLM stores per-(token,head) scales inline after each head's data, making the slot
260 B. That is not a multiple of 128. Contiguous-access kernels tolerate it; QSA gathers
scattered tokens and pays 6.3× (9.6 ms → 60.2 ms at 2048 rows / topk 1024). Moving the
scales to a side tensor restores alignment at identical memory cost.

I nearly abandoned int8 over this — the first end-to-end run showed a 40 % prefill
regression, and it took four wrong hypotheses before isolating the kernel showed int8 was
in fact faster than both fp8 and bf16 and the whole regression was the layout.

Attribution

patches/apply_qsa_fp8_kv.sh / qsa_fp8_kv_sm121.patch are not mine — the patch
attached to vllm-project#54426 by @Nanetnounou, included because the int8 work builds
on it. fix_ple_mixed_precision.py and fix_mtp_block_fp8.py are ports of upstream
d4d703ca and vllm-project#55513 to the pre-rename module name.

Runtime patches + measurements for --kv-cache-dtype int8_per_token_head on the
sparse QSA attention path, GB10 / sm_121.

Key finding: vLLM's inline per-token-head scale layout makes the slot 260B, which
breaks 128B alignment and costs 6.3x in a gather-based kernel (9.6ms -> 60.2ms).
Keeping the scales in a side tensor restores alignment; int8 then beats fp8 on
TTFT (-7.9%), decode (+5.2%) and MTP acceptance (+1.9pts) at an identical KV pool.

Reported upstream: vllm-project#56081, and as corroboration on vllm-project#54426.
Not upstreamable as-is: targets the pre-rename module and stacks on unmerged vllm-project#55557.
The "vllm-project#54426 (comment)" link pointed at the issue body; point it at the
actual corroboration comment (issuecomment-5602282777).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant