flowchart TD
A["train.yaml: model.vision_parallel"] --> B["get_vision_parallel_config"]
B --> C{"dp_shard"}
C -->|"1"| D["Visual Encoder params replicated"]
C -->|"global dp_shard"| E["Visual Encoder uses visual FSDP mesh"]
B --> F{"cp > 1"}
F -->|"no"| G["Visual DP only"]
F -->|"yes"| H["Resolve train.accelerator.cp mesh"]
H --> I["visual.set_context_parallel_mesh(cp_mesh)"]
I --> J{"async_cp"}
J -->|"false"| K["ContextParallel on block.attn.sdpa_core"]
J -->|"true"| L["AsyncContextParallel on sdpa_core with q/k/v boundaries"]
前向数据流
flowchart LR
A["CP-local micro batch"] --> B["Gather full text sequence for VL fusion"]
B --> C["Visual patch embedding<br/>Conv3d weights, linear compute"]
C --> D["Shard packed visual sequence by CP rank"]
D --> E["Visual blocks<br/>sdpa_core CP"]
E --> F["Gather visual output and DeepStack features"]
F --> G["Scatter image embeddings into text tokens"]
G --> H["Build mRoPE position ids"]
H --> I["Slice text sequence, masks and DeepStack features"]
I --> J["Text Decoder CP/FSDP path"]
J --> K["Logits and shifted-token loss"]
验证结果
功能与精度
验证项
结果
DeepStack CP 切片校验
3 个检查通过
Qwen3-VL-MoE 视觉塔 CPU parity
通过
1 卡 baseline smoke
通过
2 卡 baseline DP/FSDP smoke
通过
2 卡 Visual Encoder DP (dp_shard=1)
通过
2 卡 Visual Encoder CP Pure Colossal (cp=2, ulysses_degree=1)
通过
2 卡 Visual Encoder CP Pure Ulysses (cp=2, ulysses_degree=2)
通过
2 卡 Visual Encoder async CP Pure Colossal
通过
首步 loss 对齐结果:
模式
首步 loss
baseline DP
11.931214332580566
visual DP1
11.931214332580566
visual CP Pure Colossal
11.931214332580566
visual CP Pure Ulysses
11.931214332580566
visual async CP Pure Colossal
11.931214332580566
首步 loss 在 rel_tol=1e-6、abs_tol=1e-5 下完成对齐。100 step loss 对齐通过:最大绝对误差 0.00095845,平均绝对误差 0.00026391,首步误差 0,末步误差 0.00037098,满足 0.005 容差要求。
两卡性能对比
性能采样使用 tiny vl_dummy 配置,world_size=2,global_batch_size=2,max_seq_len=32,视觉 grid 为 2 x 2 x 2,warmup 2 step,统计 10 step。该结果用于同口径对比不同视觉并行路径。
关联PR:https://atomgit.com/mindspore/hyper-parallel/pull/1036
qwen3_vl_moe 支持 Visual Encoder 独立 DP/CP/异步 CP
背景
多模态训练中,Visual Encoder 与文本 Decoder 的输入形态和并行瓶颈并不一致。视觉侧需要处理图像或视频 patch embedding、变长视觉序列 attention、patch merge 以及 DeepStack 视觉特征注入;文本侧则主要沿用 LLM Decoder 的 FSDP/TP/CP/EP 组合。如果视觉塔只能跟随文本 Decoder 的全局并行策略,就难以单独控制视觉侧参数复制、视觉 attention 序列切分和通信开销。
本次任务面向
qwen3_vl_moe,在现有 HyperParallel 声明式并行能力之上,补齐 Visual Encoder 局部 DP/CP 配置、视觉 attention CP 边界、多模态 CP 数据流、精度对齐、性能对比、样例和文档。任务目标
model.vision_parallel下提供 Visual Encoder 局部并行配置入口;最终差异
model.vision_parallel,视觉塔可独立配置dp_shard、cp、ulysses_degree和async_cp。Qwen3VLMoeVisionSdpaCore,仅在视觉 attention core 上挂载ContextParallel或AsyncContextParallel。grid_thw -> cu_seqlens -> sequence_lengths对每个 packed 视觉序列切分,block 后再按原顺序 gather。Conv3dforward/backward 路径。Conv3d参数名和布局,forward 使用等价F.linear投影,保证 checkpoint 兼容并规避 Ascend A2Conv3d backward不稳定路径。配置入口
推荐在模型侧显式配置视觉并行策略:
model: name: qwen3_vl_moe vision_parallel: dp_shard: 1 cp: 2 ulysses_degree: 1 async_cp: false config_overrides: vl: true train: accelerator: dp_shard: 1 cp: 2配置项说明:
dp_shard1表示视觉参数复制;未配置时跟随全局train.accelerator.dp_shard。当前支持1或全局 DP shard size。cp1时需要与train.accelerator.cp的 mesh size 匹配。ulysses_degree1表示 Pure Colossal,2表示 Pure Ulysses。async_cp方案设计
1. 视觉并行配置解析
ModelConfig提供vision_parallel字段,模型并行化阶段通过get_vision_parallel_config()统一读取视觉侧局部并行参数。这样视觉侧 DP/CP 不需要塞进文本 Decoder 的通用并行配置,也避免模型代码在多个位置重复解析 YAML。2. Visual Encoder 独立 DP
视觉塔的 DP 逻辑由
hyper_parallel/models/qwen3_vl_moe/parallelize.py处理:_resolve_vision_dp_shard_size()根据model.vision_parallel.dp_shard和全局train.accelerator.dp_shard得到视觉塔 DP shard size;vision_parallel.dp_shard=1时,_extend_visual_replicate_params()将model.visual参数加入 FSDPreplicate_params,视觉塔参数保持复制;_apply_vl_visual_tower()将视觉 blocks、merger、DeepStack mergers 和视觉塔 root 作为单独 FSDP group 包装;3. Visual Encoder 独立 CP 与异步 CP
视觉 CP 作用在视觉 attention core 上:
ContextParallel(seq_dim=1, head_dim=2, ulysses_degree=...) AsyncContextParallel(seq_dim=1, head_dim=2, ulysses_degree=...)实现上将视觉 attention 拆为两层:
Qwen3VLMoeVisionAttention:负责qkv投影、RoPE、变长序列 split/cat 和输出投影;Qwen3VLMoeVisionSdpaCore:只负责core_attn(q, k, v),输入输出采用 BSHD 布局,是 CP 注册边界。普通 CP 通过
ContextParallel挂载到block.attn.sdpa_core;异步 CP 通过AsyncContextParallel挂载到同一个 core,并复用q_cp_boundary、k_cp_boundary、v_cp_boundary作为投影边界。这样 CP 通信只包住视觉 attention 的核心计算,不影响 patch embedding、MLP、merger 和文本 Decoder。4. 多模态 CP 数据流
文本 CP 下,Trainer 会先按 CP rank 切分
input_ids、position_ids、attention_mask、labels,并同步切分mm_token_type_ids,保证 loss shift 后的本地 label 与本地 logits 对齐。进入
Qwen3VLMoeModel.forward()后,模型会在多模态融合前 gather 完整文本序列,用完整序列完成视觉 token mask、image embedding scatter 和 mRoPE position ids 计算;融合完成后再按 CP rank 将inputs_embeds、position_ids、attention_mask、visual_pos_masks和 DeepStack 视觉特征切回本地 shard,交给文本 Decoder 的 CP 路径继续训练。视觉塔内部则对 packed visual sequence 做局部 CP:根据
grid_thw生成cu_seqlens和每个图片/帧序列长度,在进入视觉 blocks 前按 CP rank 切分hidden_states和rotary_pos_emb,视觉 attention core 完成 CP 计算后,再将last_hidden_state和deepstack_featuresgather 回完整视觉序列,供后续 image token 注入使用。5. patch embedding 兼容性
Qwen3VLMoeVisionPatchEmbed继续保留self.proj = nn.Conv3d(...),因此 checkpoint 中的参数名和参数布局不变;实际 forward 将输入 flatten 后使用F.linear(hidden_states, self.proj.weight.view(...), self.proj.bias)做等价投影。该方式不改变权重加载语义,同时避开 Ascend A2 上Conv3d backward的不稳定路径。流程图
并行配置流程
flowchart TD A["train.yaml: model.vision_parallel"] --> B["get_vision_parallel_config"] B --> C{"dp_shard"} C -->|"1"| D["Visual Encoder params replicated"] C -->|"global dp_shard"| E["Visual Encoder uses visual FSDP mesh"] B --> F{"cp > 1"} F -->|"no"| G["Visual DP only"] F -->|"yes"| H["Resolve train.accelerator.cp mesh"] H --> I["visual.set_context_parallel_mesh(cp_mesh)"] I --> J{"async_cp"} J -->|"false"| K["ContextParallel on block.attn.sdpa_core"] J -->|"true"| L["AsyncContextParallel on sdpa_core with q/k/v boundaries"]前向数据流
验证结果
功能与精度
dp_shard=1)cp=2, ulysses_degree=1)cp=2, ulysses_degree=2)首步 loss 对齐结果:
首步 loss 在
rel_tol=1e-6、abs_tol=1e-5下完成对齐。100 step loss 对齐通过:最大绝对误差0.00095845,平均绝对误差0.00026391,首步误差0,末步误差0.00037098,满足0.005容差要求。两卡性能对比
性能采样使用 tiny
vl_dummy配置,world_size=2,global_batch_size=2,max_seq_len=32,视觉 grid 为2 x 2 x 2,warmup 2 step,统计 10 step。该结果用于同口径对比不同视觉并行路径。在该短序列 tiny 配置下,CP 通信开销占比较高,因此 CP 吞吐低于 visual DP1 属于预期范围;性能 PASS 的含义是五组数据完整、可比较,且对应训练链路均可正常执行。
使用入口
训练模板:
使用文档:
视觉塔回归测试入口:
export HYPER_PARALLEL_PLATFORM=torch python -m pytest -q tests/torch/qwen3_vl_moe/test_qwen3_vl_moe_vision_parity.py2 卡 VL Trainer smoke 与 loss 对齐入口:
export HYPER_PARALLEL_PLATFORM=torch export ASCEND_VISIBLE_DEVICES=0,1 export TORCH_DEVICE_BACKEND_AUTOLOAD=0 python -m pytest -q tests/torch/qwen3_vl_moe/test_qwen3_vl_moe_vl_trainer.py -s涉及文件
核心代码:
hyper_parallel/models/qwen3_vl_vision/model.pyhyper_parallel/models/qwen3_vl_moe/model.pyhyper_parallel/models/qwen3_vl_moe/parallelize.pyhyper_parallel/trainer/base.py文档与示例:
docs/guide/qwen3_vl_moe.mdexamples/README.mdexamples/qwen3_vl_30b_a3b_instruct/train.yaml测试:
tests/torch/qwen3_vl_moe/_test_qwen3_vl_moe_vl_trainer.pytests/torch/qwen3_vl_moe/test_qwen3_vl_moe_vl_trainer.py范围边界
qwen3_vl_moe的 Visual Encoder 局部并行;vision_parallel.cp > 1依赖已有train.accelerator.cpmesh,且视觉 packed sequence 长度需要满足 CP 切分要求;vision_parallel.dp_shard当前支持1或全局 DP shard size;预期收益
qwen3_vl_moe可以在不改变文本 Decoder 主并行策略的情况下,独立调整 Visual Encoder DP/CP/异步 CP;sdpa_core边界,减少对视觉 block 其它模块和文本 Decoder 的影响;