Repository navigation
[Fix] [AMD] MiniMax-M3.1-Flash-Quark-Mxfp4: requantize the FP8 shared expert so fusion can load - #46587
Open
tnguyeng wants to merge 7 commits into
Open
[Fix] [AMD] MiniMax-M3.1-Flash-Quark-Mxfp4: requantize the FP8 shared expert so fusion can load#46587tnguyeng wants to merge 7 commits into
tnguyeng wants to merge 7 commits into
Conversation
tnguyeng
marked this pull request as ready for review
October 26, 2026 12:50
tnguyeng
requested review from
1am9trash,
Alisehen,
AniZpZ,
BBuf,
BowenBao,
Edwardf0t1,
FlamingoPg,
Fridge003,
HaiShaw,
OrangeRedeng,
Ying1123,
b8zhong,
ch-wan,
hubertlu-tw,
ispobock,
kkHuang-amd,
merrymercy and
yichiche
as code owners
October 26, 2026 12:50
Quark MiniMax checkpoints store routed experts as packed MXFP4 and shared experts as block FP8. Copy is_fp4_experts onto Quark configs and requantize those shared experts into Quark's uint8 scale buffers. Co-authored-by: Cursor <cursoragent@cursor.com>
Only Quark checkpoints marked as MXFP4 routed experts take the new scale name, uint8 layout, and group-32 default. FP8 and ModelOpt still use w2_weight_scale_inv. Co-authored-by: Cursor <cursoragent@cursor.com>
Quark's block-FP8 shared-expert weights (scale_type float8_e8m0fnu) store the raw exponent byte as the weight scale. The block kernel expects a float scale, so leaving the byte undecoded corrupts every block-FP8 matmul in the shared experts and the model degenerates into repeating garbage tokens. Thread weight_scale_is_ue8m0 through Fp8Config from quark.py's _get_block_fp8_config, set it whenever the checkpoint's weight spec has scale_type == "float8_e8m0fnu", and decode weight_scale_inv = 2^(stored_byte - 127) once in Fp8LinearMethod.process_weights_after_loading_block_quant. Verified against amd/MiniMax-M3.1-preview2-dspark-private-Quark-MXFP4, disable-shared-experts-fusion: GSM8K (1314 questions, 5-shot) goes from 0.000 to 0.915 with --attention-backend triton and to 0.909 with --attention-backend aiter. Without this decode every GSM8K answer runs to the 4096-token cap on repeated text. Co-authored-by: Cursor <cursoragent@cursor.com>
The Flash Quark checkpoint marks routed experts as FP4 only in the global weight spec and stores shared-expert scales as weight_scale. Without that detection, omitting --disable-shared-experts-fusion copies the FP8 down projection into the packed MXFP4 buffer and the server crashes. Co-authored-by: Cursor <cursoragent@cursor.com>
tnguyeng
force-pushed
the
amd/draft-fix-minimax-m31-shared-expert-fusion
branch
from
October 26, 2026 12:59
56f4cde to
2c989fe
Compare
HaiShaw
reviewed
Oct 27, 2026
| logger.info( | ||
| "Detected MiniMax-M3 Quark mixed layout: routed experts are MXFP4." | ||
| ) | ||
|
|
Collaborator
There was a problem hiding this comment.
should avoid to put quark specific stuff here.
Contributor
Author
There was a problem hiding this comment.
Thank @HaiShaw for the review. I moved the MiniMax Quark check out of ModelConfig and into QuarkConfig. QuarkConfig now sets is_fp4_experts for minimax_m3_vl when the global weight dtype is fp4. The fused MoE loader still reads that flag, so the shared-expert requantize path is the same, and other Quark models are unchanged.
I applied the change then reran GSM8K with fusion on. Same TP4 DSpark setup as the fusion-off run.
| Fusion on (this rerun) | Fusion off (previous) | |
|---|---|---|
| GSM8K score | 0.9612 | 0.9665 |
| score std | 0.193 | 0.180 |
4 of 5 tasks
Keep the MiniMax global-FP4 check with QuarkConfig so ModelConfig stays free of Quark-specific layout detection. Co-authored-by: Cursor <cursoragent@cursor.com>
This was referenced Oct 28, 2026
Keep the NPU block-FP8 early return and the Quark E8M0 scale decode in process_weights_after_loading_block_quant. Co-authored-by: Cursor <cursoragent@cursor.com>
This branch has not been deployed
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.
Motivation
amd/MiniMax-M3.1-Flash-Quark-MXFP4crashes at startup when--disable-shared-experts-fusionis left off. Fusion is on by default.The routed experts are stored as packed MXFP4. The shared expert is still stored as block FP8, at full width. With fusion on, that shared expert is loaded into the same MoE weight buffer as the routed experts. The loader then copies the full-width FP8 tensor into the half-width MXFP4 buffer:
SGLang can requantize the FP8 shared expert to MXFP4 before the copy. This checkpoint never reaches that step: Quark does not mark the routed experts as MXFP4, and the scale tensor is named
weight_scalerather thanweight_scale_inv.This PR lets the server start without specifying
--disable-shared-experts-fusion.Modifications
Five files. No new flag.
python/sglang/srt/configs/model_config.pypython/sglang/srt/model_loader/loader.pyis_fp4_expertsontoQuarkConfigpython/sglang/srt/layers/moe/fused_moe_triton/layer.pyweight_scalepython/sglang/srt/layers/quantization/quark/quark.pyweight_scale_is_ue8m0forfloat8_e8m0fnublock-FP8 scalespython/sglang/srt/layers/quantization/fp8.py2^(byte - 127)on the unfused block-FP8 pathThe requantize happens on the full tensor, before the TP shard copy: FP8
(6144, 3072)becomes packed MXFP4(6144, 1536), then TP4 shards that to 384, which matchesw2.Reproduction
Fusion on, the command that crashed before this change. Run on the Flash image or a build of this branch, 4x MI355X:
Do not pass
--disable-shared-experts-fusion. The startup log should containShared experts fusion optimization enabled.andLoading FP8 shared expert weights into FP4 fused MoE weights.Adding the flag is the unfused baseline.Accuracy Tests
Paired runs on the same MI355X host, TP4, DSpark. The only intended difference is shared-expert fusion. GSM8K is
sglang_run_eval. NIAH islm_evalniah_single_2.The GSM8K gap is inside one standard deviation. NIAH at 64k and 128k matches exactly.
Benchmarking
sglang.bench_serve, datasetgenerated-shared-prefix. Same two runs as the accuracy table. Every point is one shared prefix:gsp-num-groups: 1gsp-range-ratio: 1.0gsp-system-prompt-len: 72000gsp-question-len: 8000gsp-output-len: 2000gsp-prompts-per-groupsteps with concurrency: 32, 64, 128, 256, 512, 1024. Concurrency 4 to 128. The radix cache is flushed after warmup. This is a crash fix, not a throughput win: output tokens/s stays within about 4%.Mean TTFT at concurrency 4 is 623 ms unfused and 792 ms fused. DSpark accept length stays around 2.7 to 2.9 on both.
Checklist
Review and Merge Process
/tag-and-rerun-ci,/tag-run-ci-label,/rerun-failed-ciCI States
Latest PR Test (Base): ❌ Run #40849198204
Latest PR Test (Extra): ❌ Run #40849198059
Latest PR Test (AMD ROCm 10): ❌ Run #40849198142