Repository navigation
Conversation
JazyJiang
force-pushed
the
feat/moe-ep-layer
branch
from
October 22, 2026 10:02
703eb88 to
0558530
Compare
JazyJiang
marked this pull request as ready for review
October 22, 2026 10:11
This was referenced Oct 27, 2026
Add the expert-parallel part of an MoE block as a model-independent layer in colossalai.moe, following the EP refactor design: models keep their own router and hand top-k ids and weights to EPMoELayer, which runs dispatch -> experts -> combine with pluggable backends. - dispatcher.py: DispatchOutput, the data contract between dispatchers and experts (rows grouped by local expert, global token order within an expert, per-expert counts on device and host), the Dispatcher protocol, and NCCLAllToAllDispatcher (one host sync per layer, fp32 weighted combine on the source rank). - experts.py: the Experts protocol, GroupedMMExperts (torch._grouped_mm, torch >= 2.8, per-expert padding before 2.11) and ReferenceExperts. - layer.py: EPMoELayer, holding the local experts in the transformers v5 layout (gate_up_proj [E_local, 2I, H], down_proj [E_local, H, I]); load_full_weights only writes .data so parameter objects stay valid. - moe_tensor/api.py: ExpertGradScale tag recording where the 1/ep factor of an expert grad is applied. EPMoELayer defaults to IN_FORWARD (scaled in the layer, like the existing EP models) until the plugins handle IN_REDUCTION. - colossalai.moe exports the new names lazily, like the existing ones. The layer is not wired into any model or plugin yet.
JazyJiang
force-pushed
the
feat/moe-ep-layer
branch
from
October 28, 2026 01:48
941eadc to
9a1c8b8
Compare
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
No tracking issue yet. This is the first step of the EP / MoE layer refactor. Background: #6464, #6465 and #6466 (fixed in #6467, #6469, #6468) came from the EP logic being copied into every model's forward. A follow-up that unifies the gradient sync groups of expert parameters builds on the
ExpertGradScaletag added here.Background
Today every EP model (Mixtral, DeepSeek, DeepSeek-V3, and Qwen3-MoE in #6450) carries its own copy of routing, permutation, all-to-all, the expert loop and the combine. That has two costs:
This PR adds the shared layer and the contract between its parts, so that new backends and model ports can be built on one definition. Nothing uses it yet.
Changes
colossalai/moe/dispatcher.pyDispatchOutput, the data contract handed to the experts:Dispatcherprotocol (dispatch/combine).NCCLAllToAllDispatcher: token-major sort, one host sync per layer (the split sizes NCCL needs),all_to_all_uneven, regroup by expert on the GPU.combineapplies the fp32 routing weights on the source rank, sums in fp32 and casts once.colossalai/moe/experts.pyExpertsprotocol: SwiGLU experts on the dispatched rows; outputs are not weighted.GroupedMMExperts: twotorch._grouped_mmcalls for all local experts. Needs torch ≥ 2.8; before 2.11 each expert's rows are padded to a multiple of 8.ReferenceExperts: oneF.linearpair per expert, for debugging and tests.colossalai/moe/layer.py—EPMoELayer:forward(hidden_states, topk_idx, topk_weights). The router stays in the model.gate_up_proj [E_local, 2I, H],down_proj [E_local, H, I].load_full_weightscopies this rank's experts by writing.dataonly, so parameter objects held by optimizers / ZeRO stay valid.ep_group=Noneand distributed initialized, the layer resolves the group todist.group.WORLDbefore building the default dispatcher and tagging the parameters, soget_ep_size(param)/get_ep_rank(param)work on its parameters ([BUG] Default EPMoELayer group is rejected by get_ep_size #6485, fixed in [moe] resolve the default EP group before tagging parameters #6486, which is merged into this branch).colossalai/tensor/moe_tensor/api.py—ExpertGradScalewithset_expert_grad_scale/get_expert_grad_scale. This records where the1/epfactor of an expert grad is applied:IN_FORWARD: in the layer's autograd, like the existingEPGradScaler;IN_REDUCTION: by the gradient reduction.Untagged expert params count as
IN_FORWARD.EPMoELayerdefaults toIN_FORWARD, so it is correct with the current plugins.IN_REDUCTIONis for plugins that read the tag; that support is being designed separately.colossalai/moe/__init__.py: the new names are exported lazily, like the existing_operationones; importingcolossalai.moestill loads no submodule.New
tests/test_moe/test_ep_moe_layer.py(4 GPUs):IN_FORWARD,IN_REDUCTION} × {uniform, half the experts unused}. Unused experts must get zero (not missing) grads.get_ep_size(param)matches, theExpertGradScaletag is set, andload_full_weightskeeps the parameter objects.New
tests/test_moe/test_ep_moe_layer_cpu.py(CPU, Gloo): default-group construction with distributed initialized and not initialized. Added to both CPU test lists (run_cpu_unit_tests.sh,run_colossalai_batch.sh).Not in this PR (follow-ups on top of this contract):
EPMoELayer(after support Transformers 5.17 in ShardFormer #6474's v4/v5 split settles);IN_REDUCTIONand unified expert sync groups.User and compatibility impact
colossalai.moe(EPMoELayer,DispatchOutput,Dispatcher,NCCLAllToAllDispatcher,Experts,GroupedMMExperts,ReferenceExperts) and new helpers incolossalai.tensor.moe_tensor.api. Nothing is removed or renamed.GroupedMMExpertsraises a clear error below torch 2.8;ReferenceExpertsworks on any version.Test environment
nvidia-smiCUDA Version: 13.2)torch.version.cuda: 12.8, NCCL 2.28.9)nvcc --version): 12.8 (V12.8.61)0ac6a922(rebased after the Transformers 5.17 upgrade, [ci]: upgrade Transformers to 5.17 and align CI dependencies #6476). The branch has since been rebased onto maind414d565; the CI results below are for that head.The local environment still has transformers 4.51.3, which main supports through the v4/v5 split of #6474; the new code does not use transformers. CI uses torch 2.13 / CUDA 13.0 with transformers 5.17; CI results will be added below.
Test commands and results
FAST_TESTunset, 4 GPUs reserved viagpu-run.test_ep_moe_layer.py0ac6a922)tests/test_moeEPGradScalerOutremoved from the layer, the test fails (input grad error 0.93 at ep=2).tests/test_moeare pre-existing:test_moe_ep_zero_grad_scale[8]needs 8 GPUs.import colossalai.moeloads no submodule, the old names still resolve, and the new names load on first access.torch._grouped_mmedge cases (checked on torch 2.11, H20): bf16 / fp16 / fp32, an expert with no rows, zero rows in total, and row counts that are not a multiple of 8 all work, and empty experts get zero weight grads.Logs and JUnit XML are kept on the team cluster in
test-results/ep_moe_layer_20261022/.CI (torch 2.13.0+cu130, transformers 5.17, head
9a1c8b8bon maind414d565):test_ep_moe_layer_cpu.py)8,fast_mode=false(run 40622247693)Earlier head
05585301(before the default-group fix): Layer 1, Draft smoke (batch 4a) and Layer 2 passed; Layer 3 batch 8 (run 39793007918) had the same 3 unrelated failures.test_ep_moe_layer[4]and bothtest_ep_moe_layer_cpucases passed. The other MoE tests (test_moe_checkpoint,test_moe_ep_sp_grad_sync,test_moe_ep_zero_grad_norm,test_moe_ep_zero_grad_scale[4]) and the MoE optimizer-checkpoint tests added on main by [checkpoint]: remove embedded pickle from async optimizer checkpoints #6479 also passed.test_booster/test_plugin/test_3d_plugin.py::test_3d_plugin:'GPT2Model' object has no attribute 'get_head_mask'.shardformer/modeling/gpt2.py:186still calls an API removed in Transformers v5.test_checkpoint_io/test_gemini_checkpoint_io.py::test_gemini_ckpIOandtest_gemini_torch_compability.py::test_gemini_ckpIO[2]:GeminiDDP.named_parameters() got an unexpected keyword argument 'remove_duplicate'.general_checkpoint_io.py:308(added in support Transformers 5.17 in ShardFormer #6474) passesremove_duplicate, whichGeminiDDP.named_parameters(prefix, recurse)does not accept.tests/test_booster, after one rank hit an NCCL out-of-memory error on the shared host, and was cancelled. This PR's tests had not started yet.Known issues
ep_group=Nonewas stored asNoneon the expert parameters, soget_ep_size(param)asserted ([BUG] Default EPMoELayer group is rejected by get_ep_size #6485). Fixed in this PR (see Changes) and covered by both the GPU and the CPU test.combinereshaped with an inferred-1dimension. This is fixed in this PR and covered by the test, not a pre-existing issue.expert_grad_scale=IN_REDUCTION, current plugins do not divide expert grads byep_size, so they would beep_sizetimes too large. The default isIN_FORWARD, and the docstring says to useIN_REDUCTIONonly with a plugin that reads the tag.skip,xfailor--ignore.Risk and rollback
colossalai.moelazy-export table is rewritten as a name → submodule map; the old names map to_operationas before.Documentation and release impact
API docstrings are included. No README, installation, Docker,
version.txt, PyPI or DockerHub changes. A changelog line: "Addcolossalai.moe.EPMoELayer, a model-independent expert-parallel MoE layer with pluggable dispatchers and experts backends (experimental)."