Repository navigation
Conversation
DeepGEMM's DSV4.1 kernels already pass FP8 activations to each other, but vLLM took their BF16 outputs and re-quantized them with a standalone MXFP8 kernel before every dense projection (127 launches per decode step at C1). Behind VLLM_DSV41_DEEPGEMM_FP8_CHAIN=1 (default off): - mega_mhc emits the attention-pre norm output as FP8 with DeepGEMM packed UE8M0 scales (y_fp8 / y_gemm_sf) next to its BF16 output; fused_wqa_wkv consumes it directly. - mega_mhc writes the FFN-pre output straight into the Mega MoE symmetric buffer (y_fp8 / y_routed_sf / y_shared_sf), so prepare_megamoe_inputs only repacks the routing tensors (skip_quant). - fp8_einsum emits wo_a's output z as an FP8 (d, sfd) pair; wo_b consumes it. - fused_wqa_wkv and wo_b run on a new 2D DeepGemmMxfp8LinearKernel (fp8_gemm_nt, recipe (1,1,32)) that accepts kMxfp8DynamicDeepGemm activations, a distinct QuantKey (int32 packed scales) so FlashInfer-layout producers can never be routed to a DeepGEMM consumer or vice versa. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Signed-off-by: Canlin <canlinguosdu@gmail.com>
Under SP the attention input is all-gathered in BF16 after the pre-norm, so Mega mHC's per-rank FP8 copy cannot feed fused_wqa_wkv; the DeepGEMM kernel then quantized the gathered input itself (per_token_group_quant, 40 x 6 us per step at C1), which is slower than FlashInfer's own quantize. Bind only wo_b (and the MoE input) in that topology and do not request the unused FP8 mHC output. An FP8 all-gather with scale repack is future work. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Signed-off-by: Canlin <canlinguosdu@gmail.com>
Pre-compile fp8_gemm_nt with recipe (1, 1, 32) and packed UE8M0 scales for every M bucket of each layer routed to DeepGemmMxfp8LinearKernel, through the existing DeepGEMM warmup, so the FP8 chain does not JIT-compile during serving. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Signed-off-by: Canlin <canlinguosdu@gmail.com>
The chain only binds where DeepGEMM and SM100 are available and every precondition is checked at construction (falling back with a warning), the outputs are identical, GSM8K is unchanged, and it is faster at every concurrency measured. VLLM_DSV41_DEEPGEMM_FP8_CHAIN=0 keeps the FlashInfer MXFP8 path. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Signed-off-by: Canlin <canlinguosdu@gmail.com>
Architecture Review: MXFP8 Activation Retention between DeepGEMM KernelsReview Highlights:
Great performance enhancement for DeepSeek model serving on Hopper / Blackwell architectures! |
Drop VLLM_DSV41_DEEPGEMM_FP8_CHAIN: the chain binds whenever SM100 and DeepGEMM are present (every precondition is checked at construction and other platforms keep their kernels with a logged reason). Also satisfy mypy: unpack the Mega-mHC outputs by name, narrow the attention-pre FP8 result before handing it to attention, cast the quant_method for the kernel swap, and give the ROCm / FlashInfer-MoE / Kimi-K3 overrides the new optional parameters. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Signed-off-by: Canlin <canlinguosdu@gmail.com>
Contributor
|
This pull request has merge conflicts that must be resolved before it can be |
Keep DeepseekV4MegaMoEExperts.forward's signature unchanged so the Kimi-K3 and FlashInfer-MoE subclasses are untouched: DeepseekV4MoE.forward sets input_prequantized on the DSV4.1 experts for the call, and fp8_input_target answers only for that exact class. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Signed-off-by: Canlin <canlinguosdu@gmail.com>
- Select DeepGemmMxfp8LinearKernel through Mxfp8LinearLayerConfig / init_mxfp8_linear_kernel(deep_gemm_activations=True) from ModelOpt's post-load, driven by a `deep_gemm_activations` layer marker (same door as `is_bmm`), instead of swapping quant_method.kernel from the model. - Report Mega mHC's FP8 outputs as a typed MegaMhcFp8Outputs (gemm_input / moe_staged) instead of a str-keyed request and a QuantizedActivation | bool | None result. - Pass the staged Mega-MoE input explicitly (DeepseekV4MoE.forward(staged=) -> experts.forward_staged) instead of a mutable flag on the experts module; the shared-expert block_m computed for the target is reused. - Give the routing-only staging its own kernel and entry point (stage_megamoe_routing); prepare_megamoe_inputs is back to its upstream signature. - Share the wo_a einsum -> wo_b tail between the FlashInfer/FlashMLA o_proj and the mega-attention backend. - Warmup discovers layers through the deep_gemm_warmup_provider protocol. Signed-off-by: Canlin <canlinguosdu@gmail.com> Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Resolves conflicts with vllm-project#57874 (can_use_mega_mhc) and vllm-project#57651 (engram table sharing import) against the typed Mega-mHC FP8 outputs. Signed-off-by: Canlin <canlinguosdu@gmail.com> Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
gcanlin
marked this pull request as ready for review
September 21, 2026 18:55
gcanlin
requested review from
AndreasKaratzas,
WoosukKwon,
dllehr-amd,
hongxiayang,
mgoin,
tjtanaa,
tlrmchlsmth,
yewentao256 and
zyongye
as code owners
September 21, 2026 18:55
gcanlin
requested review from
pavanimajety and
robertgshaw2-redhat
as code owners
September 21, 2026 18:55
gcanlin
marked this pull request as draft
September 22, 2026 03:15
Contributor
|
This pull request has merge conflicts that must be resolved before it can be |
6 tasks done
5 of 6 tasks
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.
Purpose
DeepGEMM's DeepSeek-V4.1 kernels can hand FP8 activations to each other, but vLLM re-quantized their BF16 outputs before every dense projection: 127 standalone MXFP8 quantize launches per decode step at C1 (TP4), plus the quantize half of the Mega-MoE input staging. This PR wires the FP8 outputs DeepGEMM already provides to the consumers, and runs those consumers on DeepGEMM.
One decoder layer, decode step.
[q]= standalone MXFP8 quantize launch,sf= the UE8M0 group scales.Before — every DeepGEMM kernel returns BF16, and a FlashInfer quantize kernel re-creates MXFP8 before each consumer:
After — the producers emit MXFP8 with packed scales directly, the consumers run on DeepGEMM
fp8_gemm_nt:prepare_megamoe)fused_wqa_wkv), 0 otherwisefp8_gemm_nt(1,1,32) ×2Pieces:
DeepGemmMxfp8LinearKernel(2Dfp8_gemm_nt, recipe (1,1,32)); its activations carry a newQuantKeykMxfp8DynamicDeepGemm(int32 packed UE8M0 scales) so a FlashInfer-layout producer can never be routed to a DeepGEMM consumer or vice versa. The model markswo_b/fused_wqa_wkvwithdeep_gemm_activations, and ModelOpt's post-load selects the kernel for them the same way it does foris_bmmlayers.mega_mhcwrapper: optionaly_fp8/y_gemm_sfandy_fp8/y_routed_sf/y_shared_sfoutputs (DeepGEMM already implements them), reported as a typedMegaMhcFp8Outputs; the MoE leg is passed explicitly (DeepseekV4MoE.forward(staged=...)→experts.forward_staged) andstage_megamoe_routingrepacks only the top-k.deep_gemm_fp8_o_proj(fp8_z=True):fp8_einsumemits(z, sf); also in the mega-attention backend's_o_proj.fused_wqa_wkvstays on FlashInfer there (FP8 all-gather is follow-up work).fp8_gemm_ntvariants are pre-compiled by the existing DeepGEMM startup warmup (layers found through thedeep_gemm_warmup_providerprotocol).Duplicate check: searched open PRs for
mega_mhc y_fp8,y_gemm_sf,fp8_einsum,DeepGemmMxfp8LinearKernel,prepare_megamoe_inputs,wo_b quantize, and by touched file. #57679 (restores thewq_bquery-quant fusion) is complementary and untouched here; #56751 (skinny GEMM, M ≤ 4) quantizes in-kernel for the same projections at tiny M, a separate mechanism; #55505 (input-scale contract) does not conflict.Test Plan
pytest -v -s tests/kernels/test_dsv41_deepgemm_fp8_chain.py # SM100vllm serve deepseek-ai/DeepSeek-V4.1-Flash --tensor-parallel-size 4 --enable-expert-parallel \ --kernel-config '{"moe_backend":"deep_gemm_mega_moe"}' --attention-backend FLASHINFER_MLA_SPARSE_DSV41 \ --kv-cache-dtype fp8 --tokenizer-mode deepseek_v41 --max-model-len 32768 --max-num-batched-tokens 8192 --max-num-seqs 64Baseline: the same command on main.
vllm bench serverandom 4096/256, ignore-eos, one server at a time; GSM8K via lm-eval 0.4.12 (5-shot chat, thinking off, greedy, 1319 questions).Test Result
4×B200, TP4 + EP4, MegaMoE + SP, FlashInfer sparse MLA, fp8 KV.
mega_mhcFP8 outputs bit-exact MXFP8 of its BF16 output, MoE layout bit-identical toprepare_megamoe_inputs; einsum FP8 output vs quantized BF16 output; routing-only staging).After the plumbing refactor (kernel selection through ModelOpt post-load, typed mHC outputs, explicit staged MoE input): 21 unit tests pass, C1 TPOT 6.50 / 6.50 / 6.50 ms, GSM8K 0.9636 / 0.7915, greedy outputs coherent on 12 prompts.
At C1 the host loop (~6.5 ms/step) bounds TPOT, so most of the GPU saving shows from C4 up. The FP8-output
mega_mhcvariants JIT-compile on first use per prefill shape, like the BF16 variants today (cache persists underDG_JIT_CACHE_DIR).Developed with AI assistance (Claude Code); the human submitter reviewed every changed line and ran the measurements.
🤖 Generated with Claude Code