已合并
feat(qwen): support Qwen3.5 and Qwen3-VL-MoE parallel training #658
feat(qwen): support Qwen3.5 and Qwen3-VL-MoE parallel training #658
已合并
xuxinglei创建于 5月18日
xuxinglei成员
5月18日

What type of PR is this?

/kind feature


What does this PR do / why do we need it:

本 PR 为 Qwen3.5 dense、Qwen3.5-MoE 和 Qwen3-VL-MoE 补齐统一 Trainer 的真实训练链路:模型构造与 checkpoint 转换、数据 registry、meta 参数物化、优化器、以及 TP/CP/EP/FSDP/HSDP/PP/VPP 组合并行。

  • models/:三个模型族的模型定义、state-dict 转换和模型自有并行方案。
  • trainer/:配置、DeviceMesh、数据加载、PP stage、loss/gradient 汇总和 optimizer step。
  • data/:dummy、VL dummy、HF/JSON、preset tensor 和 Megatron 数据入口。
  • core/:组合并行实际触发的 PP 共享梯度、嵌套 FSDP、Partial Add/Sub 和 output reduction dtype 修复。

公共 core 修改的逐文件根因见 Issue #282。


Which issue(s) this PR fixes:

Fixes #282


Test Plan and Test result:What scenarios were tested, and what were the verification results(Function, performance, reliability, etc.):

1. 验证口径

模型 缩减配置 数据 优化器
Qwen3.5 dense 4 decoder layers,保持 checkpoint 宽度/heads dummy,seq=64 AdamW,lr=1e-4 constant
Qwen3.5-MoE 1 decoder layer,真实 256 experts dummy,seq=64 AdamW,lr=5e-6 cosine
Qwen3-VL-MoE 1 text layer,真实 VL checkpoint,冻结 vision tower vl_dummy,grid=2x2x2 AdamW,lr=1e-4 cosine

共同口径:20 个连续 optimizer steps;param_dtype=bfloat16、reduce_dtype=float32、max_grad_norm=0、global batch=4、micro batch=1、seed=1234。每个候选必须完整输出 steps 1..20 且 loss 全部有限;通过条件为相对同模型单卡基线的最大 loss 绝对误差 <= 0.005。

2. 支持的数据集

data.type 数据来源 关键字段 用途/说明
dummy 按 train.seed + sample index 确定性生成 token max_seq_len、train_size LM 单卡/并行快速验证,无需 tokenizer 文件
vl_dummy 确定性生成 token、pixel values 和 grid metadata max_seq_len、vl_grid_t/h/w、vl_video Qwen3-VL image/video 训练路径
hf_datasets HuggingFace hub、本地 dataset/Arrow train_path、subset、text_key、train_size tokenizer 动态 tokenize 后训练
json_file 本地 JSON/JSONL、Alpaca 风格 JSON train_path、template、text_key instruction/text 数据动态 tokenize
preset_pt torch.save(List[Dict[str, Tensor]]) train_path 预先 tokenized 的 LM/VL batch 原样读取
megatron Megatron .bin/.idx prefix 或 weighted blend train_path、megatron_seed、pad/eod_token_id .bin mmap;支持单 prefix、权重字符串和 pair list

当前仅支持 streaming: false;真实数据可配置 num_workers、prefetch_factor、pin_memory 和 shuffle。

3. Step-by-step 拉起方式

Step 1:准备环境

export HYPER_PARALLEL_PLATFORM=torch
export HCCL_DETERMINISTIC=true
export LCCL_DETERMINISTIC=1
export ASCEND_DETERMINISTIC=true
export FLASH_ATTENTION_DETERMINISTIC=1
export PYTORCH_NPU_ALLOC_CONF=expandable_segments:True

Step 2:创建单卡 dense YAML

YAML 可放在仓库外;下面的 checkpoint 路径替换为实际路径。

model:
  name: qwen3_5
  weights_path: /path/to/Qwen3.5-0.8B-Base
  tokenizer_path: /path/to/Qwen3.5-0.8B-Base
  config_overrides:
    num_hidden_layers: 4

data:
  type: dummy
  max_seq_len: 64

train:
  max_steps: 20
  num_train_epochs: 1
  global_batch_size: 4
  micro_batch_size: 1
  seed: 1234
  backend: torch
  init_device: meta
  accelerator:
    dp_shard: 1
    comm_fusion: true
  optimizer:
    type: adamw
    lr: 1.0e-4
    lr_min: 1.0e-4
    lr_decay_style: constant
    lr_warmup_ratio: 0.0
    max_grad_norm: 0.0
    weight_decay: 0.0
    loss_aggregation: token_weighted
    foreach: false
  mixed_precision:
    enabled: true
    param_dtype: bfloat16
    reduce_dtype: float32
    output_dtype: float32
  gradient_checkpointing:
    activation_checkpoint: none
  checkpoint:
    output_dir: outputs/qwen3_5_single
    save_steps: 0
    save_hf_weights: false
  logging:
    log_steps: 1
    report_throughput: false
  debug:
    deterministic: true

Step 3:切换模型

Qwen3.5-MoE 使用 scripts/train_lm.py,把 YAML 中的模型和优化器改为:

model:
  name: qwen3_5_moe
  weights_path: /path/to/Qwen3.5-35B-A3B
  tokenizer_path: /path/to/Qwen3.5-35B-A3B
  config_overrides:
    num_hidden_layers: 1
train:
  optimizer:
    type: adamw
    lr: 5.0e-6
    lr_min: 0.0
    lr_decay_style: cosine
    lr_warmup_ratio: 0.1
    max_grad_norm: 0.0
    weight_decay: 0.0
    loss_aggregation: token_weighted
    foreach: false

Qwen3-VL-MoE 使用 scripts/train_vl.py,替换模型和数据段:

model:
  name: qwen3_vl_moe
  weights_path: /path/to/Qwen3-VL-30B-A3B-Instruct
  tokenizer_path: /path/to/Qwen3-VL-30B-A3B-Instruct
  freeze_modules:
    - model.visual
  config_overrides:
    vl: true
    text_config:
      num_hidden_layers: 1
data:
  type: vl_dummy
  max_seq_len: 64
  vl_grid_t: 2
  vl_grid_h: 2
  vl_grid_w: 2

Step 4:运行单卡 baseline

ASCEND_RT_VISIBLE_DEVICES=0 python3 -m torch.distributed.run \
  --nproc-per-node=1 --master_addr=127.0.0.1 --master_port=29500 \
  scripts/train_lm.py /path/to/qwen3_5_single.yaml

ASCEND_RT_VISIBLE_DEVICES=0 python3 -m torch.distributed.run \
  --nproc-per-node=1 --master_addr=127.0.0.1 --master_port=29501 \
  scripts/train_vl.py /path/to/qwen3_vl_moe_single.yaml

Step 5:只修改 train.accelerator 生成并行 YAML

dense/MoE 表格结果使用 comm_fusion: true,VL-MoE 使用 comm_fusion: false;复现时应保持对应模型口径。EP 样例另保留 moe_token_dispatcher_type: all_to_all 和 npu_nums_per_device: 1。

组合 train.accelerator 修改 卡数 本次达标模型
single dp_shard: 1 1 dense / MoE / VL-MoE
DDP2 dp_replicate: 2, dp_shard: 1 2 dense / MoE / VL-MoE
HSDP2x2 dp_replicate: 2, dp_shard: 2 4 dense / MoE / VL-MoE
FSDP2 dp_shard: 2 2 dense / MoE / VL-MoE
TP2 tp: 2 2 dense / MoE / VL-MoE
CP2 cp: 2 2 dense / MoE / VL-MoE
EP2 ep: 2, etp: 1 2 MoE / VL-MoE
TP2+FSDP2 tp: 2, dp_shard: 2 4 dense / MoE / VL-MoE
CP2+FSDP2 cp: 2, dp_shard: 2 4 dense / MoE / VL-MoE
EP2+FSDP2 ep: 2, etp: 1, dp_shard: 2 4 MoE / VL-MoE
TP2+CP2 tp: 2, cp: 2 4 dense / VL-MoE
TP2+EP2 tp: 2, ep: 2, etp: 1 4 MoE / VL-MoE
CP2+EP2 cp: 2, ep: 2, etp: 1 4 MoE / VL-MoE
PP2+FSDP2 pp: 2, dp_shard: 2, pp_micro_batch_num: 2, pp_schedule: 1f1b 4 dense / VL-MoE(VL 显式 output_dtype: float32)
VPP2+FSDP2 pp: 2, pp_vpp: 2, dp_shard: 2, pp_micro_batch_num: 2 4 dense
TP2+CP2+FSDP2 tp: 2, cp: 2, dp_shard: 2 8 dense / VL-MoE
PP2+TP2+FSDP2 pp: 2, tp: 2, dp_shard: 2, pp_micro_batch_num: 2, pp_schedule: 1f1b 8 dense

Step 6:按卡数运行并行 YAML

ASCEND_RT_VISIBLE_DEVICES=0,1,2,3 python3 -m torch.distributed.run \
  --nproc-per-node=4 --master_addr=127.0.0.1 --master_port=29510 \
  scripts/train_lm.py /path/to/qwen3_5_tp2_fsdp2.yaml

其他组合只需同步修改 ASCEND_RT_VISIBLE_DEVICES、--nproc-per-node 和 YAML 的 train.accelerator;VL 模型将入口换成 scripts/train_vl.py。

4. 20-step 单卡与并行结果

Qwen3.5 dense

并行组合 卡数 steps max abs diff 最大差 step 单卡 step1 / step20 并行 step1 / step20
ddp2 2 20 7.2e-07 4 15.11113954 / 12.56648493 15.11113930 / 12.56648445
hsdp2x2 4 20 9.6e-07 11 15.11113954 / 12.56648493 15.11114025 / 12.56648540
fsdp2 2 20 7.2e-07 4 15.11113954 / 12.56648493 15.11113930 / 12.56648445
tp2 2 20 0.00199533 1 15.11113954 / 12.56648493 15.10914421 / 12.56618023
cp2 2 20 0.00133091 10 15.11113954 / 12.56648493 15.11114018 / 12.56626480
tp2_fsdp2 4 20 0.00199628 1 15.11113954 / 12.56648493 15.10914326 / 12.56604576
cp2_fsdp2 4 20 0.00133188 10 15.11113954 / 12.56648493 15.11113921 / 12.56626480
tp2_cp2 4 20 0.00199512 1 15.11113954 / 12.56648493 15.10914442 / 12.56644694
pp2_fsdp2 4 20 0.00147199 2 15.11113954 / 12.56648493 15.11113930 / 12.56610775
vpp2_fsdp2 4 20 0.00147199 2 15.11113954 / 12.56648493 15.11113930 / 12.56610775
tp2_cp2_fsdp2 8 20 0.00199609 1 15.11113954 / 12.56648493 15.10914345 / 12.56644694
pp2_tp2_fsdp2 8 20 0.00203276 2 15.11113954 / 12.56648493 15.10914421 / 12.56654549

Qwen3.5-MoE

并行组合 卡数 steps max abs diff 最大差 step 单卡 step1 / step20 并行 step1 / step20
ddp2 2 20 7.2e-07 12 14.30329132 / 14.27249193 14.30329132 / 14.27249241
hsdp2x2 4 20 9.6e-07 2 14.30329132 / 14.27249193 14.30329132 / 14.27249146
fsdp2 2 20 7.2e-07 12 14.30329132 / 14.27249193 14.30329132 / 14.27249241
tp2 2 20 0.00417256 14 14.30329132 / 14.27249193 14.30118275 / 14.27426338
cp2 2 20 0.00275634 8 14.30329132 / 14.27249193 14.30324785 / 14.27482775
ep2 2 20 0.00161362 8 14.30329132 / 14.27249193 14.30329132 / 14.27326012
tp2_fsdp2 4 20 0.00411439 14 14.30329132 / 14.27249193 14.30118370 / 14.27525139
cp2_fsdp2 4 20 0.00275634 8 14.30329132 / 14.27249193 14.30324785 / 14.27482775
ep2_fsdp2 4 20 0.00161362 8 14.30329132 / 14.27249193 14.30329132 / 14.27326012
tp2_ep2 4 20 0.00393463 17 14.30329132 / 14.27249193 14.30077267 / 14.27430439
cp2_ep2 4 20 0.00272155 10 14.30329132 / 14.27249193 14.30324745 / 14.27405643

Qwen3-VL-MoE

并行组合 卡数 steps max abs diff 最大差 step 单卡 step1 / step20 并行 step1 / step20
ddp2 2 20 0.00156413 6 15.73223567 / 0.33226188 15.73223591 / 0.33225435
hsdp2x2 4 20 0.00156425 6 15.73223567 / 0.33226188 15.73223591 / 0.33224586
fsdp2 2 20 0.00156413 6 15.73223567 / 0.33226188 15.73223591 / 0.33225435
tp2 2 20 0.00427765 4 15.73223567 / 0.33226188 15.73313141 / 0.33183819
cp2 2 20 0.00328843 5 15.73223567 / 0.33226188 15.73226783 / 0.33214881
ep2 2 20 0.00224160 7 15.73223567 /
likedislike
Pull Request已成功合入, 合并人@MindSpore-Bot
(感谢 xuxinglei 的贡献)
Xxuxinglei成员
5月18日 创建了 pull request,commit 65d68729
MindSpore-BotMindSpore-Bot成员
5月18日 添加了label:stat/needs-squash
MindSpore-BotMindSpore-Bot成员
5月18日 添加了label:mindspore-cla/yes
司小南(机器人)
司小南(机器人)成员
5月18日 评论:

@xuxinglei, 当前/check-pr未通过,原因如下:

以下Pull Request描述检查项未通过:
存在不符合模板的选项: pytest tests/torch/accuracy/test_qwen3_5_accuracy.py::test_qwen3_5_single_card_baseline
存在不符合模板的选项: pytest tests/torch/accuracy/test_qwen3_5_accuracy.py::test_qwen3_5_tp_fully_shard_accuracy
存在不符合模板的选项: pytest tests/torch/accuracy/test_qwen3_5_accuracy.py::test_qwen3_5_tp_cp_fully_shard_accuracy
部分检查项缺失 请重新使用模板
模板中'Test Plan and Test Result' 信息为空,请补充对应信息。

以下issue检查项未通过:
Pull Request未关联issue

请修改好上述检查错误后,重新使用/check-pr触发检查。

likedislike
MindSpore-BotMindSpore-Bot成员
5月18日 添加了label:no-pass-all-review
此处折叠了2685条消息 查看更多
Hhedongdong成员
7月10日 通过审查
阿苏阿苏成员
7月10日 通过审查
Yyao_yf成员
7月10日 通过审查
MindSpore-BotMindSpore-Bot成员
7月10日 删除了label:no-pass-all-review
MindSpore-BotMindSpore-Bot成员
7月10日 合入了pull request,合并节点 SHA:fbed2bc1c47a96409962e5141ea14282a0f330e6