Skip to content

[ROCm][MiniMax-M3] MXFP4 mode for the fused norm / RoPE / KV insert - #65194

Draft
amd-dlimpus wants to merge 9 commits into
vllm-project:mainfrom
amd-dlimpus:cursor/m31-mxfp4-kv-writer-a294
Draft

amd-dlimpus wants to merge 9 commits into
vllm-project:mainfrom
amd-dlimpus:cursor/m31-mxfp4-kv-writer-a294

Conversation

@amd-dlimpus

Copy link
Copy Markdown

Replaces #64359, which GitHub closed when its base branch minimax-m31-flash was deleted after #64111 merged into main.

Overview

Adds an MXFP4 mode to MiniMax-M3's fused FlyDSL norm / RoPE / KV insert on ROCm (gfx950). The same launch that writes NVFP4 pages can write K, V and index-K as MXFP4 pages: E2M1 data with one E8M0 scale per 32 dims and no global scale. That takes 68 B per token and head, against NVFP4's 72.

Stacked on #64358 (the mxfp4 KV dtype; its two commits come first here). Review the writer commit, 425d35ac5; the rest is #64358 and merges of main.

Changes

  • norm_rope_nvfp4_insert/kernel.py: compile_norm_rope_insert(..., mx=True) swaps the scale step and the scale addresses. Norm, RoPE, the E2M1 data layout, V's octet runs and the index-q output are unchanged.
    • The scale is 2^ceil(log2(amax / 6)) from the fp32 quotient's exponent bits, clamped at 2^-126, and 2^0 for an all-zero group. It reduces over 8 lanes (32 dims) instead of 4.
    • Elements are scaled by the exact power of two, then converted with the RNE cvt_scalef32_pk_fp4_f32 the NVFP4 path already uses.
    • Scale layout: K and index-K [token][4], V [group][token]; per head and page, 8192 B of data plus 512 B of scales.
  • host.py: mxfp4= keyword. The slot width comes from mxfp4_kv_cache_full_dim / nvfp4_kv_cache_full_dim, and k_scale / v_scale are ignored in MXFP4 mode.
  • The NVFP4 path compiles to the same code as before (mx=False).

The readers (sparse decode / prefill and the index kernels on scaled MFMA) and the backend's customize_spec follow in later PRs. Nothing calls mxfp4=True yet.

Validation

tests/kernels/attention/test_minimax_m3_norm_rope_nvfp4_insert.py runs on MI355X: 45 passed. That's the existing 31 NVFP4 cases, plus the MXFP4 cases for the two-kernel comparison, the all-padding batch and graph replay. Every output byte is compared, stale page bytes included. The cases cover a single decode token, octet- and page-crossing runs, DSpark decode rows, unaligned prefill chunks and 4K-token prefill, at TP4 and TP1 head counts.

The reference (minimax_m3_nvfp4_ref.py) gains an MXFP4 quantizer written with torch.frexp, independent of the kernel's bit arithmetic. On CPU it matches a brute-force OCP MXFP4 quantizer on random data at three magnitudes, exact ties, all-zero groups and the 2^-126 clamp.

Accuracy of MXFP4 KV for M3.1

The same values were emulated by rounding K, V and index-K to MXFP4 before the FP8 KV insert. Against the NVFP4-KV baseline (Quark MXFP4 experts, seed 42, paired exact McNemar): GSM8K 94.31% vs 94.31% (p = 1.0), GPQA-Diamond 83.33% vs 80.30% (p = 0.39), RULER NIAH multikey-2 32k 100% vs 100% (p = 1.0).


Pull Request Checklist
  • I used vLLM's /pr-checklist skill. (Mandatory for agents, optional for humans).

  • AI assistance was used during the creation of this PR.

  • Design Fit: Minimizes impact on core components, reuses existing functionality, and justifies added complexity.

  • Testing and Validation: Validates the change and ensures any added tests are meaningful and reliable, with CI coverage or documented CI resource constraints and validation performed outside CI.

  • Code Quality and Style: Keeps code and comments clear and concise, and updates relevant documentation and examples.

  • Pull Request Contents: Includes a brief summary and relevant links, supports claims with evidence, explains root causes and implementation trade-offs, and follows the contributing guide.

zyongye and others added 9 commits October 27, 2026 06:40
… ROCm

Squash of the MiniMax-M3.1 serving branch, rebased on 5d35ce3.

NVIDIA:
- Route NVFP4 routed experts in MXFP8 checkpoints to the CT NVFP4 MoE
- NVFP4 KV cache on the MSA sparse attention path, served only by the
  CUTLASS Q8KV4 kernels (E4M3 query) on SM100/SM103/SM107
- NVFP4 index-K cache via the MSA Q8KV4/Q8KV8 indexers; opt-in decode
  context parallelism for the NVFP4 indexer at TP4
- Vendor fmha_sm100 from vllm-project/MSA dev 25c1447
- NVFP4 MSA decode past 512 sequences: Q8KV4 limits, bounded indexer and
  plan memory
- Decode metadata before the forward: 13 ops -> 2; in-place indexer I/O,
  no counter reset, PDL chain for the NVFP4 sparse decode
- DeepGEMM NVFP4 MegaMoE on the unified DeepGemmMegaMoEExperts layer;
  per-token FC1 input scales outside MegaMoE; split staging rows over
  programs
- Fuse small-batch MoE finalize into the all-reduce + Gemma norm + MXFP8
  quant
- QKV+indexer MXFP8 GEMM with fused epilogue; SM100 fused dense GEMM1
- Fused QK-norm/RoPE/KV insert: persistent row-group kernel
- Read aux hidden states after the deferred TP all-reduce
- FA4: pass no FP8 descale for a unit per-tensor scale
- Keep KV cache zeroing for mixed-precision UniformTypeKVCacheSpecs groups
- Clear per-token A4 metadata for NVFP4 W4A16 MoE kernels (Marlin only)
- Hand the Q8KV4 prefill a per-device split workspace
- Align image preprocessing: long-side resize with detail tiers, fp32
  patch embedding
- NIXL KV-head re-sharding for per-head-contiguous NVFP4 pages; BLHNC
  layout for NIXL transfer
- SimpleCPUOffload: 1 GiB HugeTLB host buffer + PreferCE batch copies

Spec decode:
- DSpark for MiniMax-M3.1: draft model, fixes and perf; default the draft
  to the checkpoint's dspark/ subfolder
- Fuse the draft's q/k norm + RoPE and its context-K/V write
- FLASHINFER_TS: prims_ts paged decode for non-causal draft blocks
- Store the draft tokens' K/V under torch.compile
- Markov sampling: one step helper, bias in the Gumbel kernel
- DFlash: pad the prepared inputs in wide blocks on every platform

ROCm:
- Re-quantize the NVFP4 routed experts to MXFP8 (or MXFP4) at load;
  NVFP4 -> MXFP4 re-quantization and fused shared experts through the
  online quantization API
- Mono decode (one FlyDSL launch per layer): native MXFP8 shared expert,
  top-16 sort/merge, aux hidden states, indexer CP
- NVFP4 KV + NVFP4 indexer on gfx950, decode indexer CP
- Tune small-M MXFP8 linears
- Sequence-parallel prefill under pure TP (opt-in), with MXFP4 MoE
  support; TBO/DBO under pure TP; warm the microbatch threads' hipBLASLt
  handles at init
- gfx942: avoid the load-time FP8 MoE quant crash; fall back from the
  fused QK-norm
- Keep the NVFP4 KV-insert helpers CUDA-only so the fused kernel builds
  on HIP

Co-authored-by: Taoyu Zhu <zhutaoyu97@gmail.com>
Co-authored-by: Hongxia Yang <hongxia.yang@amd.com>
Co-authored-by: qizixi <22851944+zixi-qi@users.noreply.github.com>
Co-authored-by: indivats <Indira.Vats@amd.com>
Co-authored-by: andyluo7 <43718156+andyluo7@users.noreply.github.com>
Co-authored-by: Thien Tran <gau.nernst@yahoo.com.sg>
Co-authored-by: Jee Jee Li <pandaleefree@gmail.com>
Co-authored-by: fxmarty-amd <felmarty@amd.com>
Co-authored-by: Jiejing Zhang <280536569+jiejingzhangamd@users.noreply.github.com>
Co-authored-by: Prasun Gera <pgera@users.noreply.github.com>
Co-authored-by: Dao Le <daole@inferact.ai>
Co-authored-by: Isotr0py <mozf@inferact.ai>
Co-authored-by: Neha Prakriya <neha.prakriya@amd.com>
Co-authored-by: Summer Yang <girasoley@inferact.ai>
Co-authored-by: Zhewen Li <jerven.vllm@gmail.com>
Co-authored-by: Zijing Liu <liuzijing2014@users.noreply.github.com>
Co-authored-by: xiaozhoupy <peiyuanzhou1994@gmail.com>
Co-authored-by: v <v@inferact.ai>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Yongye Zhu <zyy1102000@gmail.com>
…wn PRs (vllm-project#63490)

Signed-off-by: Taoyu Zhu <zhutaoyu97@gmail.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
…ssage (vllm-project#63492)

Signed-off-by: Seungmin Kim <8457324+ehfd@users.noreply.github.com>
Per-head MXFP4 KV: E2M1 data plus one E8M0 scale per 32 elements, stored
as uint8 (head_size/2 + head_size/32 bytes per head row, 68 for 128),
with its own KVQuantMode.MXFP4. Backends opt in through
supported_kv_cache_dtypes.

Signed-off-by: Limpus, David <dlimpus@amd.com>
Writes K, V and index-K as MXFP4 pages (E2M1 data, E8M0 scale per 32 dims,
no global scale; 68 B per token and head) from the same FlyDSL launch as
the NVFP4 insert. The data layout is NVFP4's; K and index-K scales are
[token][4], V scales [group][token]. The scale is 2^ceil(log2(amax / 6)),
2^0 for an all-zero group.

The bit-exact test runs both formats against a torch reference.

Signed-off-by: Limpus, David <dlimpus@amd.com>
15 is MXFP4_DS_MLA in vllm-project#64120 and 16 is MXFP4 in vllm-project#64198.

Signed-off-by: Limpus, David <dlimpus@amd.com>
(cherry picked from commit b3a9d3e)
… scale

FA4 reads a missing descale as 1.0, and it copies every expanded descale
view into a contiguous tensor: three copy kernels per layer and step. The
scales are fixed once the weights are loaded, so a per-tensor scale of 1.0
(an FP8 KV cache without calibrated scales) passes no descale. Calibrated
and per-head scales keep theirs; a (1, 1) expanded view gets canonical
strides, because FA4 treats it as contiguous and its layout check then
rejects the zero stride.

Co-authored-by: qizixi <22851944+zixi-qi@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Yongye Zhu <zyy1102000@gmail.com>
The base branch was reset onto main (2abde62 plus one FA4 commit), so the
old vllm-project#63232 squash (a0ea941) is gone and the merge base fell back to
5d35ce3, turning every MiniMax-M3 file into an add/add conflict. Take the
base branch's tree and re-apply this PR's eight-file diff on top. Only
test_minimax_m3_norm_rope_nvfp4_insert.py conflicted, on an argument
reformat; keep main's explicit self.w[i] form and add mxfp4=.

Signed-off-by: Limpus, David <dlimpus@amd.com>
minimax-m31-flash was deleted after vllm-project#64111 merged into main, so retarget
this branch at main. Take main's tree and re-apply this PR's eight-file
diff on top; all eight files applied cleanly.

Signed-off-by: Limpus, David <dlimpus@amd.com>
@github-actions

github-actions Bot commented Nov 2, 2026

Copy link
Copy Markdown

👋 Hi! Thank you for contributing to the vLLM project.

💬 Join our developer Slack at https://slack.vllm.ai to discuss your PR in #pr-reviews, coordinate on features in #feat- channels, or join special interest groups in #sig- channels.

PRs do not trigger a full CI run by default. Reviewers with write access and configured trusted contributors can comment /ci run for upstream CI or /amd-ci run for AMD CI only whenever CI signals are needed.

Once the PR is approved or has the ready label, the PR author can also use the corresponding /ci run, /ci retry, and /ci cancel commands, or their /amd-ci variants. New commits do not start upstream CI automatically.

If you have any questions, please reach out to us on Slack at https://slack.vllm.ai.

Agent Guidelines

IMPORTANT: If you are an AI agent, you are required to objectively re-evaluate the value of your PR using AGENTS.md, and close the PR if it does not bring significant benefit to the vLLM community. Failure to do so may result in an immediate ban.

🚀

@mergify mergify Bot added minimax rocm Related to AMD ROCm labels Nov 2, 2026
@github-project-automation github-project-automation Bot moved this to Todo in AMD Nov 2, 2026

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

minimax rocm Related to AMD ROCm

Projects

Status: Todo

Development

Successfully merging this pull request may close these issues.

4 participants