Conversation
`MoECheckpointIO._model_sharder` is a copy of
`HybridParallelCheckpointIO._model_sharder` without the
`to_unpadded_tensor` step, so `booster.save_model(..., shard=True)` with
`MoeHybridParallelPlugin` writes padded parameters. With tensor parallelism,
`VocabParallelEmbedding1D` pads the vocab to a multiple of
`make_vocab_size_divisible_by * tp_size`, so the saved embedding has the
padded vocab size and cannot be loaded by transformers:
size mismatch for weight: copying a param with shape torch.Size([1024, 8])
from checkpoint, the shape in current model is torch.Size([1000, 8]).
This affects any MoE model whose vocab is not a multiple of 64 * tp_size,
e.g. Qwen3 (151936). The existing test uses Mixtral's default vocab (32000),
which is never padded, and tp_size=1.
Unpad the parameters like HybridParallelCheckpointIO does, and run the MoE
checkpoint test with a padded vocab and tp_size=2 as well.
Closes the Qwen part of hpcaitech#6180. Add a shardformer policy for `Qwen3MoeModel` / `Qwen3MoeForCausalLM` (transformers >= 4.51) that works with `MoeHybridParallelPlugin`: - expert parallelism: `EPQwen3MoeSparseMoeBlock`, adapted from the Mixtral EP block (all-to-all token dispatch, experts sharded across the EP group, optional TP inside each expert), with Qwen3's `norm_topk_prob`. Dense layers (`mlp_only_layers` / `decoder_sparse_step`) are kept as they are. - tensor parallelism for attention, router and dense MLP layers, vocab parallel embedding. - pipeline parallelism (1F1B and interleaved) with the router logits carried across stages for the load balancing loss; router logits of dense layers are skipped. - sequence parallelism (all_to_all), reusing the Qwen3 attention forward, since Qwen3MoeAttention is identical to Qwen3Attention. - ZeRO 1/2 through the plugin. Not supported yet (raise NotImplementedError): other SP modes, SP together with PP, and the zero bubble schedule. Tests: - tests/test_shardformer/test_model/test_shard_qwen3_moe.py: training (loss and weights) against a single-GPU reference for 11 combinations of EP / TP / PP / SP / ZeRO with a model that has dense and sparse layers and GQA, sharded checkpoint reloaded by `from_pretrained`, and the causal LM loss including the router aux loss for EP / PP / TP. - tests/test_moe/test_qwen3_moe_layer.py: fp32 layer-level check of the EP block (output, router logits and every gradient) against the transformers block, for 1 and 2 experts per rank and both `norm_topk_prob` values. The model-level test cannot catch wrong expert math, because the expert outputs are tiny compared to the residual stream at the default init; the layer test uses a larger init and catches e.g. a flipped `norm_topk_prob`.
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.
📌 Checklist before creating the PR
[doc/gemini/tensor/...]: A concise descriptionpip install pre-commit && pre-commit install(ran the pinned hooks manually instead: black 24.10.0--line-length=120, isort 5.13.2--profile black, autoflake 2.3.1, all clean)🚨 Issue number
Closes the Qwen part of #6180 ("Expert Parallel for qwen/deepseek"; DeepSeek EP already exists).
Depends on #6449: this branch contains that fix as its first commit, because the new test saves a Qwen3-MoE checkpoint with a padded vocab under TP. I will rebase once it is merged; please review only the second commit here.
📝 What does this PR do?
Adds shardformer support for Qwen3-MoE (
Qwen3MoeModel,Qwen3MoeForCausalLM, transformers >= 4.51, e.g. Qwen3-30B-A3B / Qwen3-235B-A22B) withMoeHybridParallelPlugin.EPQwen3MoeSparseMoeBlock: all-to-all token dispatch, experts sharded over the EP group, optional TP inside each expert, Qwen3'snorm_topk_probmlp_only_layers,decoder_sparse_step)Nonerouter logits are skippedall_to_all, reusing the Qwen3 attention forward (Qwen3MoeAttentionis identical toQwen3Attention)NotImplementedErrorThe EP block is adapted from
EPMixtralSparseMoeBlock; the policy mirrors the Mixtral / Qwen3 policies.Tests
tests/test_shardformer/test_model/test_shard_qwen3_moe.py(4 GPUs, plus an 8-GPUlargedistvariant like Mixtral's):Qwen3MoeModel.from_pretrainedand compared.Qwen3MoeForCausalLMloss including the router aux loss for EP=4, PP=4, TP=4 and EP=2×PP=2 (the reference is computed on the same micro batches, since the aux loss is not linear in the batch).tests/test_moe/test_qwen3_moe_layer.py(4 GPUs): fp32 comparison of the EP block with the transformers block — output, router logits, input grad and every parameter grad — for 1 and 2 experts per rank and bothnorm_topk_probvalues.A note on test sensitivity
The model-level test (same design as
test_shard_mixtral.py) cannot detect wrong expert math: at the defaultinitializer_rangethe expert outputs are ~1e-4 against a residual stream of ~1, so e.g. flippingnorm_topk_probin the EP block still passes it (max output error 0.0156 with or without the mutation, i.e. bf16 noise). The layer test uses a larger init and fails on that mutation on every rank, so I added it and did not skip it.test_mixtral_layer.pyis currently skipped as "tested in corresponding shardformer" — the same blind spot applies to Mixtral.Results (4x H200, torch 2.5.1+cu124, transformers 4.51.3)
test_shard_qwen3_moe.py::test_qwen3_moe(11 model configs + 4 causal LM configs)test_qwen3_moe_layer.py(ep 2/4 × norm_topk_prob on/off)norm_topk_probflipped in the EP blockSharding check: with ep=4 each rank holds 1 of the 4 experts in each of the 3 sparse layers.
Also found (upstream transformers, not changed here)
In transformers 4.51.3,
Qwen3MoeModel.forwardcollects the router logits of dense layers (None) andload_balancing_loss_functhen fails whenoutput_router_logits=Trueandmlp_only_layersis non-empty. The pipeline / SP forward in this PR skips them; the causal LM test uses only sparse layers so that the transformers reference can compute the aux loss.💥 Checklist before requesting a review
⭐️ Do you enjoy contributing to Colossal-AI?