Skip to content

Add NVFP4/FP8 Q/K/P/V + 2:4 attention quantization for MLA (vLLM TRITON_MLA) - #2244

Draft
kaix-nv wants to merge 5 commits into
mainfrom
kaix/mla_opt
Draft

Add NVFP4/FP8 Q/K/P/V + 2:4 attention quantization for MLA (vLLM TRITON_MLA)#2244
kaix-nv wants to merge 5 commits into
mainfrom
kaix/mla_opt

Conversation

@kaix-nv

@kaix-nv kaix-nv commented Aug 25, 2026

Copy link
Copy Markdown
Contributor

What does this PR do?

Type of change: new feature

Adds fused NVFP4/FP8 Q/K/P/V and 2:4 attention quantization for MLA models
(DeepSeek-family) on the vLLM TRITON_MLA backend, closing the gap where the
compact attention-quant path (install_vllm_nvfp4_attention) supported only
regular GQA/MHA attention.

The design follows the quantized-BMM-operand model (matching the dense
Q/K/P/V path and the MNI reference): the latent KV cache stays raw, and every
attention BMM operand is fake-quantized once, in-kernel, along its own
contraction axis.

  • Decode (mla_decode.py, split-K absorbed MQA): reads the raw latent and
    quantizes K along the feature axis (k_format), V along the token axis
    (v_format) — independently — plus P after the softmax row-sum and a
    caller-side FP32-carrier Q. V groups are block-16 at absolute token positions
    (split-deterministic).
  • Prefill (mla_prefill.py, varlen, asymmetric 192/128 head dims): quantizes
    the projected Q/K/P/V operands once from the bf16 latent, with optional
    token-exact N:M (2:4) score sparsity on new-token attention.
  • Integration: ModelOptMLAImpl reclasses TritonMLAImpl and overrides
    forward_mha/forward_mqa; _QuantVLLMMLAAttention skips the module-level
    latent QDQ (_skip_module_kv_quant) so the cache stays raw; the installer
    discovers MLAAttention with MLA-specific gates (fp8 cache, sparse indexer,
    q-padding, skip-softmax rejected) under the existing validate-then-publish
    flow.

Contract notes: NVFP4 is 1×16 along the contraction axis (E4M3 block scale,
amax/(6·448)); the softmax denominator stays unquantized; on-read V trades the
write-once cache's tail-block stability for an independent v_format — the
faithful quantized-BMM behavior.

Usage

# DeepSeek-family MLA model, fused NVFP4 Q/K/P/V attention on TRITON_MLA
python examples/vllm_serve/vllm_serve_sparse_attn.py <MODEL_PATH> -tp 8 \
  --attention-backend TRITON_MLA --enforce-eager --no-enable-prefix-caching \
  --worker-cls sparse_attn_worker.QuantSparseAttnWorker

# Per-operand formats (nvfp4 | fp8), e.g. FP8 P/V:
#   --additional-config '{"modelopt_attn_quant": {"p_format": "fp8", "v_format": "fp8"}}'

Testing

Verified in the CI-pinned vllm/vllm-openai:v0.26.0 container on an RTX A5000
(SM86):

  • MLA decode + prefill kernel golden tests (baselines), the MLA and dense vLLM
    runtime installer/adapter suites, and the dense attention kernel regression:
    94 passed (E4M3 quant-path tests are compute-capability-gated and skipped
    on SM86).
  • Smoke-compiled the NVFP4/FP8 K/V/P decode branches: they compile past all
    structural stages and gate only at the SM89 fp8e4nv cast, so their numerics
    validate on an SM89+ run.

Pending on SM89+ hardware (draft): the E4M3 numeric golden tests
(decode/prefill K/V/P quant vs. eager oracles) and the tiny-DeepSeek
install→generate end-to-end.

Before your PR is "Ready for review"

  • Is this change backward compatible?: ✅ (new opt-in path; MLA layers were
    previously unsupported by the compact attention installer)
  • If you copied code from any other sources or added a new PIP dependency, did
    you follow guidance in CONTRIBUTING.md: N/A
  • Did you write any new necessary tests?: ✅ (kernel golden tests with eager
    oracles + synthetic vLLM runtime/adapter tests)
  • Did you update Changelog?: ✅
  • Did you get Claude approval on this PR?: ❌ (draft — pending SM89 numeric run)

Additional Information

Draft: functionally complete and structurally verified on SM86; kept as draft
until the E4M3 numeric suite runs on SM89+ hardware.

@copy-pr-bot

copy-pr-bot Bot commented Aug 25, 2026

Copy link
Copy Markdown

This pull request requires additional validation before any workflows can run on NVIDIA's runners.

Pull request vetters can view their responsibilities here.

Contributors can view more details about this message here.

@coderabbitai

coderabbitai Bot commented Aug 25, 2026

Copy link
Copy Markdown
Contributor

Important

Draft PR not reviewed

Draft PRs are not automatically reviewed by default.

  • Trigger a manual review

To automatically review draft PRs, update your CodeRabbit configuration:

reviews:
  auto_review:
    drafts: true

Comment @coderabbitai help to get the list of available commands.

MLA kernels (modelopt/torch/kernels/quantization/attention/mla/):
- mla_prefill: varlen prefill with asymmetric head dims, fused Q/K/P/V
  fake quant (NVFP4 1x16-along-contraction / per-tensor FP8), token-exact
  N:M score sparsity, natural-log LSE for chunked-context merging.
- mla_decode: split-K absorbed decode over the paged latent cache with
  grouped query heads and fused P QDQ. The write-once quantized latent
  (module-level kv_c/k_pe QDQ before the cache write) is the single
  representation both BMM1-K and BMM2-V consume - no on-read re-quant.
- reference: independent eager oracles replicating the kernel schedules.

vLLM integration (TRITON_MLA, vLLM >= 0.26):
- ModelOptMLAImpl reclasses TritonMLAImpl; forward_mha swaps a per-layer
  prefill backend around the inherited kv_b_proj/chunked-context plumbing,
  forward_mqa runs the FP32-carrier absorbed-Q QDQ + decode kernel.
- Installer discovers MLAAttention on the quantize path with MLA gates
  (fp8 cache, sparse indexer, q padding, skip-softmax rejected) and the
  existing validate-then-publish/rollback flow.
- configure_vllm_nvfp4_mla_quantizers: k_format governs kv_c/k_pe/k_mha,
  v_format the prefill projected V (k_mha/v_mha named to stay outside the
  *[kv]_bmm_quantizer calibration patterns).
- Fix stale vllm.attention.layer MLA import in vllm_ptq_utils; extend the
  reload key rewrite to kv_c/k_pe quantizers.

Verified in vllm/vllm-openai:v0.26.0 on RTX A5000 (SM86): MLA kernel
golden tests 28 passed, dense kernel regression 33 passed, runtime and
worker suites 84 passed, dynamic-modules e2e 10 passed. E4M3 quant-path
tests are capability-gated and still need an SM89+ run.

Signed-off-by: Kai Xu <kaix@nvidia.com>
The module-level kv_c/k_pe latent QDQ was applied in
_QuantVLLMMLAAttention.forward before super().forward, so vLLM's prefill
kv_b_proj projected an already-quantized latent, which the prefill kernel
then quantized again (k_mha/v_mha) — double-quantizing the new-tokens
prefill K/V operands. Decode was unaffected (single write-once latent,
consumed as-is).

Move the latent QDQ off the module forward and into a
ModelOptMLAImpl.do_kv_cache_update override that quantizes out-of-place at
cache-write time. vLLM calls do_kv_cache_update before forward_impl and
passes forward_impl the same tensors, so the quantized copy reaches the
cache (read by decode) while prefill projects the bf16 latent — making the
new-tokens prefill operands single-quant. Gated by a
_kv_quant_in_cache_write flag so the fakequant/calibration path (fused impl
not installed) still quantizes module-side.

Residual, documented in the README: cached-context prefill chunks gather
from the quantized paged cache and re-quantize, so those chunks stay
double-quant — inherent to reading a stored quantized latent, and absent
for single-chunk prompts.

Verified: MLA + dense vLLM runtime synthetic suites 35 passed in
vllm/vllm-openai:v0.26.0; numeric single-quant behavior exercised by the
SM89+ tiny-DeepSeek install+generate e2e.

Signed-off-by: Kai Xu <kaix@nvidia.com>
The decode kernel consumes the write-once quantized latent as-is for both
BMMs (V = trans(k_nope)), so decode V reuses the latent's K-side
feature-axis quantization — it does not honor v_format, which applies to
prefill only. A shared latent cannot be stored quantized along both K's
feature axis and V's token axis; independent token-axis decode V would
require an on-read re-quant (double-quant) or a raw-cache on-read model,
either of which forfeits the write-once step/split stability. Correct the
README and decode kernel docstring to state the actual contract.

Signed-off-by: Kai Xu <kaix@nvidia.com>
…uant)

Switch the fused MLA quant model from a compressed write-once NVFP4 latent
cache to the faithful quantized-BMM-operand model used by the MNI reference
and the dense Q/K/P/V path: the latent cache stays RAW (bf16), and every BMM
operand is fake-quantized once, in-kernel, along its own contraction axis.

Decode now honors k_format and v_format independently — it reads the raw
latent and quantizes K along the feature axis and V along the token axis
separately (plus the existing in-kernel P and caller-side Q). This fixes the
prior contract gap where decode V inherited k_format and v_format was ignored.

Kernel (mla_decode.py): add K_QDQ/V_QDQ constexprs + k_qdq/v_qdq host args;
capture raw V before the K on-read quant; independent feature-axis K and
token-axis V QDQ via _v_qdq_nvfp4/fp8_scalar_qdq; IEEE fp32 dots when an
operand is NVFP4. V groups are block-16 at absolute token positions (split
determinism); the open tail block re-quantizes as the sequence grows (the
on-read tradeoff vs write-once, documented).

Integration: keep the latent cache raw — _QuantVLLMMLAAttention.forward skips
the module kv_c/k_pe QDQ under the renamed _skip_module_kv_quant flag, and
ModelOptMLAImpl no longer overrides do_kv_cache_update (removed the
write-once/double-quant machinery from the prior two commits). quant_kw.decode
carries k_qdq/v_qdq from k_format/v_format; forward_mqa passes them.

Reference oracle + tests updated for independent on-read K/V quant; README
rewritten for the quantized-BMM model.

Verified in vllm/vllm-openai:v0.26.0 on RTX A5000 (SM86): decode/prefill
kernel baselines, MLA + dense vLLM runtime suites, and dense kernel
regression all pass (94 passed); the NVFP4/FP8 K/V/P decode branches compile
past all structural stages and gate only at the SM89 fp8e4nv cast, so their
numerics validate on the pending SM89 cluster run.

Signed-off-by: Kai Xu <kaix@nvidia.com>
Signed-off-by: Kai Xu <kaix@nvidia.com>
@copy-pr-bot

copy-pr-bot Bot commented Aug 25, 2026

Copy link
Copy Markdown

Auto-sync is disabled for draft pull requests in this repository. Workflows must be run manually.

Contributors can view more details about this message here.

@github-actions

github-actions Bot commented Aug 25, 2026

Copy link
Copy Markdown
Contributor
PR Preview Action v1.8.1

QR code for preview link

🚀 View preview at
https://NVIDIA.github.io/Model-Optimizer/pr-preview/pr-2244/

Built to branch gh-pages at 2026-08-25 00:43 UTC.
Preview will be ready when the GitHub Pages deployment is complete.

@codecov

codecov Bot commented Aug 25, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 0% with 682 lines in your changes missing coverage. Please review.
✅ Project coverage is 77.76%. Comparing base (94915a1) to head (f0683c8).
⚠️ Report is 5 commits behind head on main.

Files with missing lines Patch % Lines
...ch/kernels/quantization/attention/mla/reference.py 0.00% 187 Missing ⚠️
.../kernels/quantization/attention/mla/mla_prefill.py 0.00% 154 Missing ⚠️
...h/kernels/quantization/attention/mla/mla_decode.py 0.00% 148 Missing ⚠️
...ch/sparsity/attention_sparsity/plugins/vllm_mla.py 0.00% 89 Missing ⚠️
...parsity/attention_sparsity/plugins/vllm_runtime.py 0.00% 59 Missing ⚠️
modelopt/torch/quantization/plugins/vllm.py 0.00% 36 Missing ⚠️
...t/torch/kernels/quantization/attention/bmm2_qdq.py 0.00% 6 Missing ⚠️
...rch/kernels/quantization/attention/mla/__init__.py 0.00% 3 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #2244      +/-   ##
==========================================
- Coverage   78.95%   77.76%   -1.20%     
==========================================
  Files         522      528       +6     
  Lines       60550    62468    +1918     
==========================================
+ Hits        47810    48576     +766     
- Misses      12740    13892    +1152     
Flag Coverage Δ
unit 55.06% <0.00%> (-0.50%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

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