Repository navigation
[MoE] Overlap shared expert compute with routed branches - #5554
sanketpurandare wants to merge 1 commit into
Conversation
| [pipeline slots](https://github.com/meta-pytorch/dist_moe/blob/main/docs/pipeline_activation_slots.md), | ||
| and [VMM](https://github.com/meta-pytorch/dist_moe/blob/main/docs/vmm.md) | ||
| documentation for byte-level layouts and planner behavior. | ||
| # Shared-expert stream overlap |
There was a problem hiding this comment.
I got a little confused: DistMoE has routed experts comm-comp overlap. Why'd we still need shared expert overlap?
There was a problem hiding this comment.
Dist-MoE's communication/GEMM overlap is inside the routed branch; it doesn't enqueue the separate shared FFN. This launches that independent branch before routed metadata/barrier work and joins it before the outputs are combined.
52de26e to
3ee4985
Compare
Enqueue independent shared experts before router/dispatch/routed compute on a separate lower-priority CUDA stream and join both branches before combination. Reuse the common MoE boundary, including Kimi's latent routed projection, without duplicating router/sharding/TP-add logic. Dist-MoE's BF16 and MXFP8 transforms opt in automatically; no-shared-expert modules are unaffected. The caller may already have lowest priority, so cache one routed priority-1 and shared priority0 stream per indexed device rather than changing global stream policy. Initialize them before graph capture. Explicit waits and record_stream retain input/output allocator ownership in train and no-grad eval. Autograd uses each branch's forward stream during backward. Moving branch readiness can change BF16 input-gradient rounding. A storage-free input fork combines shared+routed+router contributions in the original order, including separate TP-sharded input edges and unused gradients. No parameter gradient cache, extra tensor copy, precision change or owned output is added. GraphTrainer's own parallel-branch lowering remains downstream work. Related DeepEP-specific #5263 by @yuweih205 uses a different dispatch callback; this is generic MoE/Dist-MoE integration and does not copy that implementation. ```bash python -m pytest tests/unit_tests/cpu/models/common/test_moe.py tests/unit_tests/cpu/models/common/test_dist_moe.py tests/unit_tests/gpu/models/common/test_dist_moe.py -q pre-commit run --all-files ``` 93 current CPU/GPU checks passed, including exact BF16 gradients, nonassociative fan-in, alias/distinct/unused edges, forward/backward stream identity, cache priming and capture/replay. Four real-NCCL PP2/DP2/EP2 and PP4/DP1/EP1 OFF/ON runs passed ten train/validation updates each: full model/optimizer state was bitwise equal on every rank, with MXFP8/FSDP, all three fusions, dense/fused MLA, optimizer/training/validation graphs and clean teardown. Profiling was disabled; these correctness runs are not 671B throughput evidence. Strict README/config Sphinx and staged-aware non-type lint passed. Existing unrelated video type error remains excluded; no full-cluster convergence/performance claim.
3ee4985 to
9e5855a
Compare
|
@claude review |
|
Claude finished @tianyu-l's task in 4m 29s —— View job Review: request changesThe design holds up and the gradient-order handling is careful. Two things block it. Turning this on unconditionally from Blocking1. Seed-checkpoint creation now raises. 2. The opt-in lives on the wrong switch and is always on.
The PR body says the evidence is "debug-model contract checks, not 671B throughput or convergence results". Per "protect battle-tested code paths", please pick one:
Either would also answer @tianyu-l's question concretely. The README explains where overlap could happen, not that it does. Correctness question3.
If the local redistribute allocates new memory instead of returning a dim-0 view of Please either Non-blocking
Looks good
|
Enqueue independent shared experts before router/dispatch/routed compute on
a separate lower-priority CUDA stream and join both branches before combination.
Reuse the common MoE boundary, including Kimi's latent routed projection,
without duplicating router/sharding/TP-add logic. Dist-MoE's BF16 and MXFP8
transforms opt in automatically; no-shared-expert modules are unaffected.
The caller may already have lowest priority, so cache one routed priority-1
and shared priority0 stream per indexed device rather than changing global
stream policy. Initialize them before graph capture. Explicit waits and
record_stream retain input/output allocator ownership in train and no-grad eval.
Autograd uses each branch's forward stream during backward.
Moving branch readiness can change BF16 input-gradient rounding. A storage-free
input fork combines shared+routed+router contributions in the original order,
including separate TP-sharded input edges and unused gradients. No parameter
gradient cache, extra tensor copy, precision change or owned output is added.
GraphTrainer's own parallel-branch lowering remains downstream work.
Related DeepEP-specific #5263 by @yuweih205 uses a different dispatch callback;
this is generic MoE/Dist-MoE integration and does not copy that implementation.
Verification
Owning-commit CPU checks: 82 passed in 7.77s.
Strict relevant Sphinx builds and all non-type repository hooks passed.
Three unchanged main type findings remain attributed, not reported as a clean
full type run. External reviewer and CI acceptance are separate, still pending.
Complete-stack integration (not this PR in isolation): real four-GPU PP2/DP2/
EP2 and PP4/DP1/EP1 ran ten updates with exact model/optimizer tensor parity,
optimizer graphs and sequential validation. A fresh native PP2/PP4 checkpoint
matrix matched resumed state exactly. These are debug-model contract checks,
not 671B throughput or convergence results.
The final 207-case GPU matrix covers in-place gradients, dense attention, PP/FSDP train/eval graphs, shared-stream backward/capture and fused numerical contracts.