fix(moe): equalize and align per-rank token counts for HybridEP dispatch - #3641
Merged
Merged
Conversation
HybridEP's fused all-to-all exchanges fixed-extent buffers, and its metadata allgather asserts 16-byte alignment on a 4-byte-per-token array. Unequal per-rank token counts deadlock the collective, and counts that are not multiples of 4 abort it outright — so dynamic batches (variable-length or packed sequences) could not train on the hybridep backend at all. _HybridEPManager.dispatch() now all-reduces the EP-group maximum token count, rounds it up to the 4-token kernel alignment, and pads this rank's hidden states, routing map, and probabilities to that extent; padded rows route to no expert, and combine() slices them back off. 2-GPU parity: forward and backward outputs of unequal/unaligned runs bitwise-match the equal-count run. Signed-off-by: HuiyingLi <willwin.lee@gmail.com>
This was referenced Aug 25, 2026
akoumpa
approved these changes
Aug 25, 2026
Contributor
Author
|
/ok to test b02855c |
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.
Problem
HybridEP's fused all-to-all exchanges fixed-extent buffers, and its metadata allgather asserts
bytes_per_rank % 16 == 0on a 4-byte-per-token array. That imposes two hard constraints the dispatcher did not enforce:hybrid_ep/extension/allgather.cu:97; 4/8/12/16 pass).Static SFT batches satisfy both by construction (the collater emits one fixed length), but dynamic batches — variable-length or packed sequences, e.g. RL rollouts — violate them almost every step, so such workloads could not train on the
hybridepbackend at all. Callers could only work around this by pre-padding batches themselves, duplicating a kernel constraint outside the dispatcher.Fix
_HybridEPManager.dispatch()all-reduces the EP-group max token count, rounds it up to the 4-token alignment, and pads this rank's hidden states, routing map, and probabilities to that extent. Padded rows route to no expert (all-False routing map, zero probs), andcombine()slices them back off.deepepanduccl_epare untouched — the added all-reduce runs only on thehybridepbackend, the only one with this constraint.Cost: one 8-byte all-reduce over the EP group per MoE layer; zero extra copies when counts are already equal and aligned.
Testing
tests/unit_tests/moe/test_token_dispatcher.py): pad-and-slice round trip to the aligned group max, equal-but-unaligned padding, and the aligned no-pad fast path (kernel and collectives mocked).tests/functional_tests/moe/run_hybridep_unequal_tokens.py, new, 2×H100 through the real hybrid-ep kernels): with identity experts each token's combined output depends only on its own routing, so an unequal/unaligned run must reproduce the equal-count run exactly. Forward and backward outputs are bitwise-identical for token-count combos 8&3, 6&6, 5&3, and 13&7:Nightly NeMo-CI dynamic-batch A/B
Validated the PR base (
a12b237) against this head (b02855c) with the nightly container, existing finetune recipes,dispatcher=hybridep, dynamic/no-fixed-padding inputs, and 10 training steps.seq_len=2047):cudaErrorIllegalAddress, thenHYBRID-EP ALLGATHER TIMEOUT ... expecting 8 got 7and SIGABRT.[456, ...]vs recomputed[464, ...]).RECVtimed out after 600 seconds when the upstream MoE path stopped making progress.71, 47, 97, 60, 76, 46, 44, 72, 41, 47.The VLM cases used
collate_fn.max_length=null; the DSV4 case usedpad_to_max_length=falseandpad_seq_len_divisible=nullwhile preserving the recipe's native GBS/LBS (256/8) and PP/EP topology.🤖 Generated with Claude Code