Repository navigation
AutoEP: support combine_impl="fused_weighted_sum" with AutoEP+AutoTP folding - #8847
Draft
pengdurice wants to merge 1 commit into
Draft
pengdurice wants to merge 1 commit into
pengdurice wants to merge 1 commit into
Conversation
…folding Signed-off-by: pengdurice <pengduhit@gmail.com>
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.
AutoEP: support
combine_impl="fused_weighted_sum"with AutoEP+AutoTP foldingPart of: #8672 (Q4 2026 roadmap), "Mixture-of-Expert (MoE) Training Scaling and Kernel Development": "AutoEP Performance Optimization & Parallel Folding (AutoEP + AutoTP)" (PoC @tohtana @pengdurice). Follows #8670.
Problem
combine_impl="fused_weighted_sum"was refused whenevertensor_parallel.autotp_size > 1:deepspeed/module_inject/auto_ep_config.py(validate_autoep_config) raisedValueError.deepspeed/module_inject/auto_ep_layer.py(set_deepspeed_parallelism) raised the same error.The reason was that the folded path restores tokens with its own function,
restore_combinedindeepspeed/moe/ep_tp_dispatch.py, and the fused kernel was only wired into the unfolded path.restore_combinedworks like this:partition_assignments).TP group.
index_add_pertop-k slot, all in the activation dtype.
So under folding, users could not get the memory saving and the FP32 accumulation of the fused kernel, and the
folded restore did its arithmetic in bf16.
Change
restore_combined_fusedindeepspeed/moe/ep_tp_dispatch.py:restore_combinedfor the rows and the routing weights, so thetp_sizegradient factor that the folded AVERAGE and EXPERT_TP_CANCEL strategies cancel is unchanged.token * top_k + slot) instead of the token index and the slot separately.[tokens, top_k], and calls the existingfused_weighted_restore. The kernel is unchanged.RuntimeErrorif the gathered rows do not cover every (token, slot). The folded payload neverdrops or pads assignments today, so this cannot trigger now; it protects the kernel from reading an unset source
row if capacity dropping is added later.
validate_coverage=Trueruns the same coverage check asrestore_combined.AutoEPMoELayer._forwardcallsrestore_combined_fusedin the folded branch whencombine_impl == "fused_weighted_sum". The default ("auto"→"weighted_sum") still callsrestore_combined.autotp_size > 1refusals are removed. The other fused refusals stay:expert_tensor_parallel_size > 1,DeepEP,
score_applyother than"post", and unsupported device or dtype.docs/code-docs/source/autoep.rstdescribes the folded fused restore and drops the refusal from the list;docs/_pages/config-json.mddrops theautotp_size=1requirement.Tests
All GPU runs: one node of 8 NVIDIA H200 GPUs. torch 2.8.0+cu126 with Triton 3.4.0, and torch 2.9.1+cu128 with Triton 3.5.1.
test_autoep_unit.py::TestAutoEPConfig::test_fused_combine_accepts_folded_tensor_parallelism(was..._rejects_...)tp_size=2test_autoep_autotp_dispatch.py::test_restore_combined_fused_rejects_a_missing_assignmenttest_autoep_autotp_dispatch.py::TestRestoreCombinedFusedTensorParallel(fp32 and bf16 rows)fused_weighted_restore, and the row and score gradients, summed over the peers, match the unpartitioned gradientstest_autoep_fused_parity.py::TestAutoEPFusedParityFoldedTensorParallel(ZeRO 0 and 2, with and without activation checkpointing)test_autoep_autotp_dispatch.pyrestore_combinedtest_autoep_fused_token_ops.pytest_autoep_autotp_grad_parity.pywithDEEPSPEED_RUN_H100_TESTS=1test_autoep_unit.pyRerun on master
d371f33ccwith this change (torch 2.8.0+cu126):test_autoep_autotp_dispatch.py12passed;
test_autoep_fused_parity.py4 passed (the 4 new folded cases) and 3 failed;test_autoep_unit.py198 passed.The 3 failures are existing cases (
TestAutoEPFusedParityExpertParallelx 2,TestAutoEPFusedParityLocalExperts) andfail the same on master without this change: "Expected mat_a to be BFloat16 matrix got Half", torch 2.8's
_grouped_mmtakes bf16 only and these cases run in fp16.The end-to-end folded test runs in FP32, on
MockMoEOnlyTransformer, without grouped GEMM:two restores differ by 1 to 1.5 units in the last place of the MoE output (about 1,600 in this model), which is more
than
PARITY_TOLERANCEallows after the LM head. In FP32 the two forward passes are bitwise equal.nn.MultiheadAttentionhas a true gradient of zero, so its computed gradient isrounding noise, and Adam's first step turns that noise into ±lr. The parameter-update check then fails by 2 × lr no
matter which restore is used.
torch._grouped_mmaccepts only bf16, so the fp32 run would fail before reaching therestore.
Existing tests in
test_autoep_fused_parity.pythat fail on masterc6af3faf2in this environment, before this change(not changed here):
RuntimeError: Expected mat_a to be BFloat16 matrix got Half. The tests use fp16 andthe default grouped GEMM.
TestAutoEPFusedParityExpertParallel(2 cases) fails on the input gradient: 5 of 1,024 elements, withthe largest relative difference 2.1% against a 1% limit. Under fp16 the input gradient still carries the loss scale
of 256.
TestAutoEPFusedParityLocalExpertspasses.On master 5f266e2 (2026-10-15; 1 node of 8 H200, driver 580.126.09, torch 2.8.0+cu126): 214 passed, 3 failed: the 3 fp16 cases of
test_autoep_fused_parity.py(TestAutoEPFusedParityExpertParallelx2,TestAutoEPFusedParityLocalExperts: torch 2.8_grouped_mmtakes bf16 only), which fail the same way on master 5f266e2 without this change.Failures that also fail on master are rerun on master in the same job.
Benchmark
One TP group of 2 H200 GPUs on one node. bf16 rows, FP32 routing weights, random routing with distinct experts per
token. The hidden size, top-k and expert count are the MiniMax-M3 and GLM-5.2 values. Memory is the peak above the
inputs. Time is one forward and backward, averaged over 10 runs after 3 warm-up runs, and includes the identical
partition step. Errors are against an FP64 reference.
The fused output error of 1.66e-3 is the rounding of the bf16 output itself. The score gradient is the router
gradient; the default folded path computes it through bf16 weights, the fused path in FP32.
Script:
bench_folded_restore.py(run withtorchrun --nproc_per_node=2).Notes
multiplies and adds in the activation dtype.
Duplicate check
Searched open and recent pull requests on 2026-10-15 ("fused_weighted_sum", "combine", "folding", "AutoEP + AutoTP"): none enables the fused combine under folding. #8829 (optimizer offload under folding) and #8823 (ZeRO-1/2 clipping under folding) change other parts of folding; #8745 and #8739 change the DeepEP combine.
Proposal
New functionality: per CONTRIBUTING.md it needs an accepted proposal issue first. Draft:
descriptions/r3/peng-autoep-fused-combine-folded-tp-v2-proposal-issue.md. TODO(user): open the issue, wait for acceptance, then link it here.AI assistance
This change, its tests and this description were prepared with AI assistance (Claude).