Repository navigation
[moe] remove DPGradScaler that over-scales expert grads under moe_dp - #6467
Merged
Merged
Conversation
DPGradScaler multiplied an expert's gradient by moe_dp / k, where k is the number of moe_dp replicas that routed tokens to it. Replicas that skip an expert contribute a zero gradient, and that zero is part of the correct data-parallel average, so ZeRO's division by moe_dp is already right. The extra factor inflated expert grads by up to moe_dp whenever an expert was cold on some replica (2x with ep=2, moe_dp=2; 4x / 1.33x with moe_dp=4). Remove DPGradScalerIn/Out and the per-layer activate_experts all-reduce from Mixtral, DeepSeek and DeepSeek-V3. EPGradScaler (1/ep) is kept. This also drops the per-chunk host sync from the assert, making the EP layer about 1.5x faster with bit-identical outputs. Add test_moe_ep_zero_grad_scale.py: forced routing so each expert is used by only part of the moe_dp group, compared against DDP and against a single-GPU fp32 model run on the concatenated global batch. It fails on main and passes with this change. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
for more information, see https://pre-commit.ci
JazyJiang
marked this pull request as ready for review
October 15, 2026 10:58
This was referenced Oct 15, 2026
Merged
yuxuan-lou
approved these changes
Oct 19, 2026
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.
Related issue
Fixes #6464
Related to #6465 (ZeRO grad norm with EP) and #6466 (expert grad sync with SP + EP). Both are separate bugs and are not changed here.
Background
With
MoeHybridParallelPlugin(EP > 1, moe_dp > 1),DPGradScalerIn/Outmultiply an expert's gradient bymoe_dp / k, wherekis the number of moe_dp replicas that routed at least one token to that expert. The correct gradient is the average over the whole data-parallel group, in which a replica that skips the expert contributes zero. ZeRO already divides expert gradients by moe_dp andEPGradScalersupplies the 1/ep, so the extra factor inflates the gradient of any expert that is cold on some replica, by up tomoe_dp×. Megatron-Core scales expert gradients by 1/dp_size with no routing-dependent factor.Reproduction (from #6464, latest main, 4 GPUs, ep=2, moe_dp=2, routing forced so that each expert is used by k=1 replica):
layers.0.self_attn.q_proj.weight(dense)layers.0.block_sparse_moe.experts.0.w1.weightWith 8 GPUs (moe_dp=4) the ratios are 4.000 (k=1) and 1.337 (k=3). The existing
test_moe_ep_zero.pydid not catch this: it routes randomly, sok == moe_dpand the factor is 1, and it is skipped.Changes
colossalai/moe/_operation.py: removeDPGradScalerInandDPGradScalerOut.colossalai/shardformer/modeling/{mixtral,deepseek,deepseek_v3}.py: remove their use around each expert, and the per-layeractivate_expertscomputation and all-reduce over the moe_dp group (including itsall_reduce_fp8variant) that only fed them.EPGradScalerIn/Outare unchanged.tests/test_moe/test_moe_ep_zero_grad_scale.py(new): ep=2, ZeRO-1, bf16, routing forced so that each expert is used by only part of the moe_dp group. Every parameter's gradient is compared, with relative L2 error < 2e-2, against two references: DDP over the dp group, and a single-GPU fp32 copy of the model run on the concatenation of all ranks' batches. The single-GPU reference has no parallel logic, so it also checks that DDP is the right target. Parametrized for 4 GPUs (moe_dp=2) and 8 GPUs (moe_dp=4); the 8-GPU case skips when fewer GPUs are visible.Not in this PR:
DPGradScalerand should drop it there.EPGradScalerstays in the model forward. Moving the 1/ep factor into the gradient sync belongs to the EP layer refactor.User and compatibility impact
assert activated_experts != 0on a GPU tensor no longer forces a host sync per expert chunk. In a single-layer benchmark of the old EP forward (Qwen3.5-like shape, 256 experts top-8, EP=4, forward + backward), time goes from 94.6 ms to 60.2 ms, with bit-identical outputs.DPGradScalerIn/Outare removed fromcolossalai.moe._operation, a private module. No other code in the repository uses them.Test environment
nvidia-smiCUDA Version: 13.2)torch.version.cuda: 12.8, NCCL 2.28.9)nvcc --version): 12.8 (V12.8.61)4c745136on top of main250c903cNote: this is the team's torch 2.11 dev environment. CI uses torch 2.13 / CUDA 13.0, and the CI results will be added below.
Test commands and results
All runs used
FAST_TESTunset, on GPUs reserved viagpu-run 0,1,2,3,4,5,6,7.tests/test_moe(this branch)tests/test_moe/test_moe_ep_zero_grad_scale.pyon main250c903c(control)[4]and[8], as expectedPassed:
test_moe_checkpoint::test_mixtral_moe_layer[4],test_moe_ep_zero_grad_scale[4],test_moe_ep_zero_grad_scale[8],test_mixtral[4],test_mixtral_3d[8],test_deepseek[4],test_deepseek_3d[8],test_deepseek_v3[4].The 6 skips are all pre-existing markers in the repository and are not touched by this PR: 4 × "tested in corresponding sharderformer" (
test_deepseek_layer,test_mixtral_layer,test_moe_ep_tp,test_moe_ep_zero) and 2 × "requires MOE_TENSOR_PATH reference tensors" (test_kernel).Logs and JUnit XML are kept on the team cluster in
test-results/pr_a_regression_20261015/.CI (torch 2.13.0+cu130 image
sha256:a7c63f5a…, head799f367c):8 9,fast_mode=false(run 38729167313)Layer 3 details from the JUnit reports:
test_moe_ep_zero_grad_scale[4]andtest_moe_checkpoint::test_mixtral_moe_layer[4]passed;test_moe_ep_zero_grad_scale[8]skipped (needs 8 GPUs). The other MoE skips are the pre-existing markers listed above.test_shard_mixtral::test_mixtral[4]passed; the DeepSeek ShardFormer tests are not collected offline (see Known issues).Known issues
hf-mirror.comreturned429 Too Many Requestswhen downloading the remote-codeconfig.jsonfordeepseek-ai/DeepSeek-V3, and it was not in the local cache. It passed when rerun alone on GPUs 0–3. Not introduced by this PR.test_shard_deepseek.pyandtest_shard_deepseek_v3.pywhen no local Hub snapshot is present. Coverage for these two models comes from the local run above.test_moe_ep_zero_grad_scale[8]skips there (confirmed in the batch 8 report). It passed locally, as didtest_mixtral_3d[8]andtest_deepseek_3d[8](above).skip,xfail,--ignoreor loosened tolerance is added. The new test's tolerance (relative L2 < 2e-2) is explained in the file: bf16 noise is below 1e-2, while the removed factor was off by 0.33×–3× on experts.Risk and rollback
Documentation and release impact
None: no README, installation, API docs, Docker,
version.txt, PyPI or DockerHub changes. A changelog line for the next release: "Fix expert gradients being over-scaled under expert parallelism when an expert is not used by every moe_dp replica (#6464)."