Repository navigation
[Kernel][Perf] Run DeepGEMM Mega MoE on SM90 with MXFP4 experts - #64061
simon-veitner-redhat wants to merge 4 commits into
Conversation
|
We mapped this onto an offline DeepInfer Hopper engine that already runs MXFP4 experts through DeepEP V2 + humming (gs32), not through DeepGEMM Mega MoE. Our vendor pin is deepseek-ai/DeepGEMM @ 1fc9c66; a CPU-safe probe there still reports SM100 fp8_fp4_mega_moe only, no sm90_fp8_fp4_mega_moe kernel files, and we reject A/B until that SM90 path is actually in the pin. We are treating the DP8+EP8 throughput comparison in this PR as an author claim for the vLLM stack, not as a number to copy, and we will not bump our DeepGEMM pin without a humming baseline JSONL on H200. Question: once vllm-project/DeepGEMM#44 lands, is the SM90 kernel expected to upstream into deepseek-ai/DeepGEMM, or should downstreams plan on the vLLM fork pin indefinitely? |
30f7bf6 to
ba72d59
Compare
|
This pull request has merge conflicts that must be resolved before it can be |
5970040 to
1cab635
Compare
The deep_gemm_mega_moe backend runs on SM90 (H200) with MXFP4 routed experts and swiglu, using DeepGEMM's SM90 FP8 x FP4 Mega MoE kernel, within one NVLink domain like SM100. Activations are dispatched as FP8 with one UE8M0 scale per 128 channels (MEGA_MOE_MXFP4_SM90). The weight loader relayouts routed FP4 shards and repacks their scales with DeepGEMM's SM90 transforms, and requantizes fused FP8 shared experts once all their shards are loaded. Every rank of a launch picks BLOCK_M from the mean tokens per EP rank of the step (num_tokens_for_block_m), so idle DP ranks do not run small blocks next to busy ones. DeepSeek V4 routes with GateLinear and fused_topk_bias off SM100, where bf16_mega_gate does not exist, and warmup skips its configs there. The MegaMoE kernel, layout and DeepSeek V4 model tests run on SM90. Signed-off-by: Simon Veitner <sveitner@redhat.com> Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
DeepGEMM's SM90 fp8_fp4_mega_moe kernel now reads FP32 activation scales (amax / 448 per 128 channels) instead of UE8M0 exponents. MEGA_MOE_MXFP4_SM90 quantizes the hidden states with FP32 scales, and prepare_megamoe_inputs stores their bits into the int32 x_sf buffer and into the shared-expert scale layout. SM100 keeps UE8M0. The staging kernel computes the scale as amax * (1 / 448) and the inverse scale with a correctly rounded division, like DeepGEMM's per_token_cast_to_fp8 in PyTorch, so that FP32 scales and values match it bit for bit (UE8M0 results are unchanged). The staging tests check the per-128 FP32 case. Signed-off-by: Simon Veitner <sveitner@redhat.com> Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
DeepGEMM now types the SM90 activation SF slices as float32. The staging kernel's bitcast store handles both dtypes, so only the comment changes. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Signed-off-by: Simon Veitner <sveitner@redhat.com>
DeepGEMM's per_token_cast_to_fp8 now computes amax / 448 correctly rounded instead of amax * fl(1 / 448). Use tl.math.div_rn in the staging kernel so its FP32 scales and FP8 payload stay bit-exact with that cast. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Signed-off-by: Simon Veitner <sveitner@redhat.com>
1cab635 to
6e3c8a0
Compare
Requested by Simon
Overview
This PR enables the
deep_gemm_mega_moeMoE backend on SM90 (H200) for MXFP4 routed experts. It uses DeepGEMM's new SM90 FP8 x FP4 Mega MoE kernel, which fuses dispatch, L1 GEMM, SwiGLU with FP8 quant, L2 GEMM and combine into one persistent kernel over NVLink symmetric memory.Depends on vllm-project/DeepGEMM#44. The DeepGEMM pin in
cmake/external_projects/deepgemm.cmakemust be bumped once that PR lands. Until then the SM90 test cases skip.Claims
moe_backend=deep_gemm_mega_moeworks on SM90 with MXFP4 experts, with the same functionality as SM100 within one NVLink domain.Validation
All runs on 8x H200, DeepSeek-V4.1-Flash, MXFP4 experts.
Tests
tests/kernels/moe/test_deep_gemm_mega_moe.py,tests/models/test_deepseek_v4_mega_moe.pyon the final revision: 120 passed, 12 skipped (the skips are SM100-only NVFP4 cases). They include the FP32 staging cases, bit-exact against DeepGEMM'sper_token_cast_to_fp8.tests/model_executor/test_deep_gemm_warmup.pyand the FlashInfer EP tests: 29 passed.Final revision vs the measured one
The final revision (FP32 activation scales and the review fixes) was compared end to end with the revision measured below, on one node with three fresh servers each: +1.2% output tok/s at c=1024, +1.9% total tok/s and −2.2% mean TTFT on a prefill-heavy load (4096 in / 16 out, c=256), and +0.5% TPOT at c=1 (8.55 vs 8.51 ms). GSM8K (lm_eval, 5-shot, 1319 questions) is 92.93 vs 92.72, equal within the ±0.5 pt resolution. The throughput tables below were measured on the earlier revision (see Reproduction).
Throughput, single node DP8+EP8 (random 1024 input / 256 output, prompts = max(32, 4 x concurrency))
Cells are output tok/s / mean TPOT (ms). main default is HUMMING with block-FP8 activations (#61875). Mega MoE and main default use allgather_reducescatter. main deepep_v2 is main's fastest all2all backend here. Each cell is the mean of two runs, one on each of two nodes at the same time; the two runs agree within 7%, and most within 2%. The exception is deepep_v2 at c=16, which is one run because the other run had a one-off 1.4 s TTFT stall.
Throughput, two nodes (2x8 H200, same workload, concurrency is the total)
Mega MoE needs EP within one NVLink domain, so every arm runs as two DP8+EP8 replicas with half the requests each. Cells are the summed output tok/s / mean TPOT (ms), one run per row. Main as one DP16+EP16 server with deepep_v2 internode was not measured.
AgentX P/D, 2 nodes
With the prefill and decode roles on separate nodes, Mega MoE beats main HUMMING + deepep_v2 by +1.5% / +4.3% / +4.0% tok/s/GPU at c=128 / 256 / 512. It also cuts ITL p50 by 10-11% and TTFT p50 by 12-17%. The agentic trace has idle gaps, and they cap throughput. Harness: agentx-harness at 89b2186 (a public fork of SemiAnalysisAI/agentx-harness), scenario
agentx, datasetsemianalysis_cc_traces_weka_062126.Reproduction
Mega MoE is vLLM main 9633997 with this PR applied and DeepGEMM at the SM90 PR head (f4685f2), the revision before the FP32 activation scales. main is vLLM main 9633997.
Correctness
Greedy samples on five prompts (temperature 0, max 4096 tokens) from Mega MoE and main default, single node DP8+EP8. All outputs are coherent and finish normally. Each pair reaches the same answer and differs only in wording and small details; for example, main's code returns tuples. On the multi-turn prompt, Mega MoE recommends Day 3 and main recommends Day 2, and each calls the other day a close second. On the final revision, 10 further prompts (each sent greedy twice and sampled twice, on three fresh servers) all finish with correct answers, the same as on the earlier revision.
Generation samples (final answers; reasoning omitted, long answers cut after the first paragraph)
Math. Solve step by step: A train leaves at 3:15 pm traveling 84 km/h. Another leaves the same station at 4:00 pm traveling 105 km/h on the same track in the same direction. At what time does the second train catch the first? Give the final answer on its own line.
Mega MoE:
main default:
Code. Write a Python function
merge_intervals(intervals)that merges overlapping closed intervals and returns them sorted. Include a short docstring.Mega MoE:
main default:
Factual. Why is the sky blue but sunsets red? Explain in four sentences.
Mega MoE:
main default:
Multi-turn chat. Three turns. User: "I am planning a 3-day trip to Kyoto in November. Suggest one main sight per day." Assistant: "Day 1: Fushimi Inari Taisha. Day 2: Arashiyama bamboo grove and Tenryu-ji. Day 3: Kiyomizu-dera and the Higashiyama streets." User: "Which of those days is best for autumn leaves, and what time of day should I go to avoid crowds?"
Mega MoE:
main default:
Long-form (about 300 words). Write about 300 words, for a first-year computer science student, on how a hash table works: hashing, collisions (chaining and open addressing), load factor and resizing.
Mega MoE:
main default:
Kernel time (8 ranks)
DeepSeek-V4.1-Flash shape, slowest rank, median of 3 runs. T=8192 reaches about 675 TFLOPS per rank. The kernel's decode tuning cuts kernel time by 2.0-2.7% at T=1-128 and by 8.5% at T=512 against the untuned kernel; prefill sizes are unchanged. With FP32 activation scales, the final revision is a further 0.5-0.8% faster at T=1-512 and 4.1% faster at T=8192 than the revision in this table (mean over ranks, 3 interleaved reps).
Details
deep_gemm_mega_moe.py: on SM90, activations are dispatched as FP8 with one FP32 scale per 128 channels (MEGA_MOE_MXFP4_SM90).prepare_megamoe_inputscomputes it asamax * (1 / 448)with a correctly rounded inverse, so scales and values match DeepGEMM'sper_token_cast_to_fp8bit for bit, and stores its bits in the int32x_sfbuffer and in the shared-expert scale layout. SM100 keeps UE8M0. The weight loader relayouts routed FP4 shards and repacks their scales with DeepGEMM's SM90 transforms. Fused FP8 shared experts are requantized once all their shards are loaded.num_tokens_for_block_m, the mean tokens per EP rank of the step. All ranks then pick the same BLOCK_M, so idle DP ranks do not run small blocks next to busy ones. Without the hint, ragged steps are 1.5-1.9x slower on the slowest rank.GateLinearandfused_topk_biasoff SM100, becausebf16_mega_gatedoes not exist there. Warmup skips those configs on SM90.Follow-ups
Pull Request Checklist
I used vLLM's
/pr-checklistskill. (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.
This PR was prepared with Claude Code and reviewed by a human (@simon-veitner-redhat).