Support --moe-a2a-backend deepep_v2 for MiMoV2 - #39080
Open
whn09 wants to merge 1 commit into
Open
Conversation
MiMoV2MoE decides twice, by enumeration, whether an EP all-to-all backend is active, and neither list includes is_deepep_v2(). Under --moe-a2a-backend deepep_v2 both are therefore False, so _enable_a2a_moe routes the MoE through forward_normal, which ends in a TP all-reduce on top of the a2a-combine the v2 dispatcher has already done, and self.ep_size is never assigned. That is silently wrong output, not an error. deepseek_v2.py and kimi_k3.py list is_deepep_v2() in the same places; this adds the one clause to each of MiMoV2MoE's two, and adds MiMoV2ForCausalLM to the deepep_v2 architecture whitelist so the path is reachable. The two changes must land together: the whitelist entry alone would expose the double-reduce above.
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
MiMoV2MoEgates its EP path on three a2a backends and omitsdeepep_v2:so
--moe-a2a-backend deepep_v2on a MiMoV2 model silently builds the non-EP MoE — thedispatcher is never constructed,
self.ep_sizestays 1 and_enable_a2a_moestays False. Theserver starts and answers, so nothing looks wrong; the flag is just inert.
deepseek_v2.pyandkimi_k3.pyalready listis_deepep_v2()immediately afteris_deepep()in the same two places. This is the same two-line addition for MiMoV2, plus thearchitecture whitelist entry that
validate_deepep_v2_model_architecturerequires — withoutwhich the launch is rejected outright, which is why both files have to land together.
MiMo-V2.5-Pro is a good fit for the v2 path: 384 experts, top-8,
hidden_size=4096, FP8checkpoint, so it is EP-heavy in exactly the regime
deepep_v2targets.Modifications
models/mimo_v2.py:or get_moe_a2a_backend().is_deepep_v2()afteris_deepep()in boththe
self.ep_sizeblock and theself._enable_a2a_moeassignment. Ordering matchesdeepseek_v2.py.arg_groups/moe_hook.py:"MiMoV2ForCausalLM"added tovalidate_deepep_v2_model_architecture'svalidated_architectures, in alphabeticalposition.
Deliberately not claiming
MiMoV2FlashForCausalLM. It shares this file and would inheritthe gate change, but I have only validated the Pro checkpoint, and this whitelist means
"someone has actually run it". Flash can be added by whoever measures it.
Accuracy Tests
Numerics against the DeepEP v1 path on the same weights and prompts — v1 is the right
control, since it is the established EP dispatcher for this model and any difference is then
attributable to the dispatcher rather than to EP-vs-not.
XiaomiMiMo/MiMo-V2.5-Pro(FP8), 2 nodes × 8 B200,TP=EP=16, per-token logprobs over afixed 12-prompt set, greedy:
Sanity-checked separately that the flag is actually doing something after the patch:
Initialized DeepEP v2 ElasticBuffer: world_size=16 hidden_size=4096 num_topk=8 ...appearsin the log, which it does not on unpatched main.
Speed Tests and Profiling
Same fleet, 2 nodes × 8 B200 per role, PD-disaggregated, one image,
deep_gemmrunner onevery arm so the dispatcher is the only variable.
Decode, server-side ms/token per request (lower is better),
max_running_requests=512:deepep_v2none(plain TP)The slope is the point: over a 16× batch
deepep_v2grows 1.47×, plain TP 2.04×.Prefill, input tok/s at matched delivered chunk 16384: 73 836 (
deepep_v2) vs 35 541(
none) — 2.08×. This needsSGLANG_DEEPEP_V2_NUM_MAX_DISPATCH_TOKENS_PER_RANKraisedwell above its default for the prefill role; at a small value v2 prefill looks about half as
fast, which is a capacity bound rather than a property of the path.
One caveat worth recording, since it is not obvious: with
--moe-a2a-backend deepep_v2theMiMoV2 config-time override rewrites
moe_runner_backendauto→flashinfer_trtllmonsm100, and
flashinfer_trtllmhas no fused func registered fordeepep_v2, so model initdies with
Runner backend MoeRunnerBackend.FLASHINFER_TRTLLM requires a fused func for a2a backend deepep_v2, but none is registered.Either pass--moe-runner-backend deep_gemmexplicitly, or take the one-line guard in the companion PR (linked below). Every number above
is with
deep_gemm.Checklist
deepep_v2job, which CI does not haveReview and Merge Process
I cannot add the
run-cilabel myself, so this needs someone with write access to start CI.Companions, all independent of each other but a MiMoV2 server needs all of them:
CI States
Latest PR Test (Base): ❌ Run #34590446291
Latest PR Test (Extra): ❌ Run #34590445724
Latest PR Test (AMD ROCm 10): ❌ Run #34590446212