[RFC]: dualmode-trainer 支持FSDPManager
Nobody has claimed this yet.
Assessment
- Difficulty
- 5/5
- Estimated time
- Over a week
- Newbie friendliness
- 25/100
- Issue type
- Feature
- Clarity
- Mostly clear
- Activity status
- Active
- Tech stack
- python, pytorch
- Domain
- distributed-systems, machine-learning
Research direction
Start with the PyTorch dual-mode Trainer entry point and the planned FSDP2Manager.parallelize() flow; the issue does not name specific files or tests. Trace how device_mesh, fsdp_non_moe_mesh, fsdp_moe_mesh, fsdp_config, and Trainer gradient accumulation are currently represented. Done requires the full YAML, topology, dense/MoE, mixed-precision, offload, prefetch, communication, and numerical acceptance matrix to pass.
Written by the indexing model from the issue text.
Description
Dual-mode Trainer:FSDP2Manager 配置化接入
1. 目标与范围
Dual-mode Trainer 通过顶层 fsdp_config 配置 FSDP/HSDP 行为,并在分布式拓扑形成有效 FSDP domain 时创建 FSDP2Manager。
本 issue 交付以下能力:
- dense/non-MoE transformer block 和 root module 的嵌套 FSDP;
- routed expert 使用独立 EDP shard domain;
- FSDP 与 TP、CP、EP、PP 拓扑组合;
- TP/EP 参数 source layout 接入 FSDP;
- 参数复制、混合精度、CPU offload、reshard、梯度同步、prefetch 和通信融合;
- Trainer 梯度累积流程对 FSDP reshard、gradient sync 的控制。
当前 dual-mode Trainer 是 PyTorch 路径,本 issue 不以 MindSpore dual-mode 为验收范围。
FSDP2Manager 不负责重复构造 rank layout。分布式基础设施统一构造 device_mesh、fsdp_non_moe_mesh 和 fsdp_moe_mesh,Manager 负责选择对应 sub-mesh、解析配置、划分 FSDP unit,并调用 fully_shard()。
2. YAML 配置接口
以下为 FSDP 相关配置片段:
accelerator:
tp_size: 1
cp_size: 1
ep_size: 1
pp_size: 1
sequence_parallel: false
loss_parallel: false
fsdp_config:
dp_shard_size: 4
edp_shard_size: 1
replicate_params: []
mix_precision:
param_dtype: bfloat16
reduce_dtype: float32
output_dtype: bfloat16
cast_forward_inputs: true
fp32_main_grad: false
enable_offload: false
reshard_after_forward: true
reshard_after_backward: true
requires_grad_sync: true
forward_prefetch_depth: 1
backward_prefetch_depth: 1
comm_fusion: false
comm_fusion_zero_copy: null
optimizer:
_target_: <optimizer target>
fp32_main_params: false
FSDP 没有单独的 enabled 开关。Trainer 根据 world size、parallel topology、dp_shard_size、推导出的 replicate size 和 edp_shard_size 判断是否需要创建 FSDP2Manager。单卡或不存在有效 FSDP domain 时跳过 FSDP wrap。
2.1 拓扑与参数配置
| YAML 配置 | 默认值 | 效果 |
|---|---|---|
fsdp_config.dp_shard_size |
1 |
dense/non-MoE 参数的 FSDP shard degree;剩余 DP×CP domain 自动成为 replicate domain |
fsdp_config.edp_shard_size |
1 |
routed expert 参数的 EDP shard degree,仅在 ep_size > 1 时有意义 |
fsdp_config.replicate_params |
[] |
按最终模型参数 FQN 指定不分片参数;参数保持 replicated,但梯度仍在所属 FSDP domain 做 all-reduce |
dp_replicate_size 不是 YAML 配置项,由运行时拓扑推导:
dp_size = world_size / (tp_size × cp_size × pp_size)
fsdp_data_parallel_size = dp_size × cp_size
dp_replicate_size = fsdp_data_parallel_size / dp_shard_size
CP 不扩大 dp_shard_size 指定的参数 shard degree。
2.2 混合精度配置
| YAML 配置 | 默认值 | 效果 |
|---|---|---|
mix_precision.param_dtype |
null |
unshard 后参数参与 forward/backward 计算的 dtype |
mix_precision.reduce_dtype |
null |
reduce-scatter/all-reduce 使用的梯度通信 dtype |
mix_precision.output_dtype |
null |
FSDP module 输出转换到的 dtype |
mix_precision.cast_forward_inputs |
true |
设置了 param_dtype 时,将浮点 forward 输入转换到参数计算 dtype |
mix_precision.fp32_main_grad |
false |
FSDP 将规约后的梯度写入 fp32 main_grad,供 fp32 main-param optimizer wrapper 使用 |
三个 dtype 支持:
float16
bfloat16
float32
三个 dtype 都为 null 时,不执行显式 FSDP mixed-precision dtype 转换。
2.3 内存与参数生命周期
| YAML 配置 | 默认值 | 效果 |
|---|---|---|
enable_offload |
false |
使用 CPU offload;sharded 参数和梯度在非计算阶段保存在 CPU,计算前后进行 H2D/D2H |
reshard_after_forward |
true |
child FSDP unit forward 后立即 reshard,降低峰值显存;关闭后保留 unsharded 参数供 backward 使用 |
reshard_after_backward |
true |
控制梯度累积期间 backward 后是否立即 reshard;关闭时非最后一个 micro-batch 可继续保留 unsharded 参数,最后一个 micro-batch 强制恢复 reshard |
requires_grad_sync |
true |
多 micro-batch 梯度累积时是否每个 micro-batch 都执行 FSDP gradient sync;关闭时非最后一个 micro-batch 跳过,最后一个必须同步 |
root module 的 reshard_after_forward 固定为 False,YAML 中的 reshard_after_forward 作用于 child FSDP unit。
reshard_after_backward 和 requires_grad_sync 由 Trainer 训练循环消费,不由 FSDP2Manager.parallelize() 直接消费。
2.4 Prefetch 与通信融合
| YAML 配置 | 默认值 | 效果 |
|---|---|---|
forward_prefetch_depth |
1 |
为当前 FSDP unit 预取后续 N 个 unit;0 表示关闭 forward prefetch |
backward_prefetch_depth |
1 |
backward 时预取前序 N 个 unit;0 表示关闭 backward prefetch |
comm_fusion |
false |
融合 FSDP unit 内的 all-gather 和 reduce-scatter,减少 collective 次数 |
comm_fusion_zero_copy |
null |
控制通信融合的零拷贝存储路径;PyTorch 下 null 在 comm_fusion=true 时默认开启,false 使用 copy-in 路径 |
Prefetch 顺序依据模型 module traversal/declaration 顺序生成,不按 dense/expert mesh 分组。
3. FSDP2Manager 行为
FSDP2Manager.parallelize() 执行以下流程:
- 将 planner 提供的参数 FQN source layout 解析到模型最终 Parameter。
- 校验 TP/EP source metadata,不接受未知 FQN、
Partialplacement 或 tied parameter 冲突布局。 - 根据最终参数 FQN 解析
replicate_params。 - 找到 transformer block,并补充 routed expert 的嵌套 FSDP unit。
- 参数归属到最深的 FSDP unit,按 bottom-up 顺序 wrap child unit。
- dense unit 使用 dense FSDP domain,expert unit 使用 EDP FSDP domain。
- 最后 wrap root module,并固定 root
reshard_after_forward=False。 - 对带 TP/EP source layout 的 unit 配置梯度规约和全局平均缩放。
- 按 module traversal/declaration 顺序配置 forward/backward prefetch。
Manager 当前使用固定 transformer-block wrap 规则,YAML 不暴露自定义 wrap policy。
4. 配置约束
4.1 配置阶段必须失败的组合
以下组合不支持,必须在训练开始前给出明确错误:
dp_shard_size < 1。edp_shard_size < 1。forward_prefetch_depth < 0或backward_prefetch_depth < 0。world_size不能被tp_size × cp_size × pp_size整除。- DP×CP domain 不能被
dp_shard_size整除。 - expert domain 不能被
ep_size整除。 - EDP size 不能被
edp_shard_size整除。 fp32_main_grad=true,但reduce_dtype未配置为float32。fsdp_config.mix_precision.fp32_main_grad与optimizer.fp32_main_params没有同时开启或同时关闭。- FSDP 开启时配置顶层
compile.fullgraph=true。 replicate_params或 source metadata 包含模型中不存在的参数 FQN。
4.2 有前置条件才生效的配置
以下不是互斥配置,但只有满足前置条件才有可观察效果:
edp_shard_size:需要ep_size > 1且模型包含 routed expert。cast_forward_inputs:需要配置非空param_dtype。comm_fusion_zero_copy:需要comm_fusion=true。reshard_after_backward、requires_grad_sync:需要一个 optimizer step 包含多个 micro-batch。replicate_params:必须填写最终模型可以解析的参数 FQN。
除上述约束外,不额外定义 offload、mixed precision、prefetch、通信融合之间的配置优先级。
5. 验收点
5.1 YAML 解析与默认值
- 最小 YAML 不填写可选字段时,resolved config 中包含
FSDP2Config的完整默认值。 - 配置支持命令行 dotted override。
- 已删除字段和未知字段必须在配置解析阶段失败,不能静默忽略。
- 所有非法拓扑、非法 prefetch depth 和非法精度组合返回包含具体配置路径及修复方向的错误。
5.2 FSDP 启用、跳过和 wrap
- 有效 FSDP/HSDP 拓扑能够完成初始化、至少两个 forward/backward/optimizer step,loss 为有限值。
- 单卡或不存在有效 FSDP domain 时跳过
FSDP2Manager。 - 支持模型的 transformer block 被逐层 wrap,root module 最后 wrap。
- 日志可观察被 wrap 的 transformer block 数量。
- root module forward 后保持 unsharded,child unit 行为由
reshard_after_forward控制。
5.3 Dense FSDP 与 HSDP
至少覆盖:
纯 FSDP shard
replicate × shard HSDP
验收结果:
- dense 参数实际 shard degree 等于
dp_shard_size。 - HSDP replicate group 内参数和更新后权重一致。
- 使用相同 seed 和 batch 时,loss、梯度及更新后权重与单卡或非 FSDP 参考在对应 dtype 容差内对齐。
- CP 打开后不扩大 dense 参数 shard degree。
5.4 FSDP 与 TP、CP、PP 组合
至少覆盖具有代表性的组合:
FSDP + TP
FSDP + CP
FSDP + TP + CP
验收结果:
- 各组合可以完成训练 step,不出现 source layout、mesh concat 或 collective group 错误。
- TP/CP 参数布局在 FSDP wrap 后保持正确。
- 各 rank loss、梯度同步及更新后权重符合对应并行语义。
- PP 场景每个 pipeline stage 仅使用当前 stage ranks 构造 FSDP domain。
- 不以直接断言内部 Mesh 对象身份作为主要验收方式。
5.5 MoE EP/EDP
ep_size > 1时构造 routed expert 的独立 EDP FSDP domain。- dense 参数使用
dp_shard_size,expert 参数使用edp_shard_size。 - expert FSDP unit 使用 EP source metadata,dense unit 使用 TP source metadata。
- routed expert 不得残留在 root FSDP unit。
- 相同输入下,loss、expert 梯度和更新后权重与参考实现对齐。
- 非法 expert/EDP 拓扑在训练开始前失败。
5.6 replicate_params
- YAML 指定的参数保持完整形状,不参与参数 shard。
- replicated 参数梯度仍执行 all-reduce,各 rank 更新结果一致。
- 同一 FSDP unit 可以同时包含 sharded 参数和 replicated 参数。
- 与不使用
replicate_params的数值参考在预期语义下对齐。 - 不存在的参数 FQN 明确报错。
5.7 混合精度
分别验证:
param_dtype控制 forward/backward 参数计算 dtype。reduce_dtype控制 reduce-scatter/all-reduce dtype。output_dtype控制 FSDP unit 输出 dtype。cast_forward_inputs=true时浮点输入转换到param_dtype。cast_forward_inputs=false时不由 FSDP 自动转换输入。- dtype 全为
null时不进行显式 dtype 转换。 - float16、bfloat16、float32 配置均能正确解析。
- 混合精度训练 loss 为有限值,并与对应精度参考在合理容差内对齐。
5.8 fp32 main-grad
完整开启:
fsdp_config:
mix_precision:
reduce_dtype: float32
fp32_main_grad: true
optimizer:
fp32_main_params: true
验收结果:
- FSDP 规约后的梯度保存在 fp32
main_grad。 - AdamW/Muon 只更新 fp32 main-param,更新后回刷模型计算参数。
- 模型计算参数使用低精度时,main-param 和 main-grad 仍为 float32。
- 只开启任意一侧、未配置
reduce_dtype或配置非 float32 时必须失败,不能静默修正。
5.9 CPU offload 与 reshard
enable_offload=true时,sharded 参数和梯度在非计算阶段位于 CPU。- profiler/trace 中可观察 H2D、D2H,训练可以正常完成。
- 相同模型下,offload 路径的设备峰值参数内存低于关闭路径。
reshard_after_forward=true时 child unit forward 后释放 unsharded 参数,backward 前重新 all-gather。reshard_after_forward=false时 child unit 参数保留到 backward,collective 次数或时序发生对应变化。reshard_after_backward=false且存在多个 micro-batch 时,非最后一个 micro-batch 保留 unsharded 参数,最后一个 micro-batch 恢复 reshard。- 各路径最终梯度和更新后权重与参考对齐。
5.10 梯度累积与 gradient sync
在 dp_shard_size > 1 且一个 optimizer step 包含多个 micro-batch 的场景验证:
requires_grad_sync=true时每个 micro-batch 执行 FSDP gradient sync。requires_grad_sync=false时非最后一个 micro-batch 不执行 reduce-scatter,最后一个必须同步。- HSDP replicate all-reduce 在 optimizer step 最后一个 micro-batch 执行。
- 两种策略累积出的最终梯度和参数更新结果一致。
5.11 Prefetch 与通信融合
forward_prefetch_depth=0、backward_prefetch_depth=0时不设置 prefetch target。- depth 为 N 时,trace 中可以观察相邻 N 个 unit 的提前 all-gather。
- prefetch 不改变 loss、梯度和参数更新结果。
comm_fusion=true时,多参数 FSDP unit 的 all-gather/reduce-scatter collective 次数减少并使用融合 buffer。comm_fusion_zero_copy=false使用 copy-in 路径。- PyTorch 下
comm_fusion=true、comm_fusion_zero_copy=null使用默认零拷贝路径。 - 显式
comm_fusion_zero_copy=true时 optimizer step 能正确更新 view-backed parameter storage。 - 通信融合及零拷贝开关不改变训练数值。
6. 实现约束
Mesh 构造保留以下内部约束,但不作为端到端测试的主要验收视角:
device_mesh保持(dp, cp, tp)拓扑,供 Planner、TP/CP、batch 和 loss 使用。fsdp_non_moe_mesh保持(fsdp_replicate, fsdp_shard, tp)根域。- dense FSDP child 和 TP source child 来自同一个
fsdp_non_moe_mesh。 fsdp_moe_mesh保持 EDP shard/replicate 和 EP 根域。- expert FSDP child 和 EP source child 来自同一个
fsdp_moe_mesh。 - FSDPManager 只选择已经构造的 sub-mesh,不重新计算 rank layout。
- TP source rank group/local rank 必须与原 TP 拓扑一致。
- CP 不写入 TP source placement,也不扩大 dense 参数 shard degree。
Mesh shape、sub-mesh 来源和 concat 关系由 UT/ST 做内部结构验证;端到端验收以 YAML 行为、训练数值、dtype、collective trace、显存及错误信息为准。
schema_version: 1
source: gitcode
gitcode_repo: mindspore/hyper-parallel
gitcode_issue: 322
source_url: https://gitcode.com/mindspore/hyper-parallel/issues/322
- Dominant language
- Python
- Stars
- 53
- Forks
- 63
- Avg merge
- 23h 45m
- Merged PRs (30d)
- 63
Contributor guide
No contributing guide indexed for this repository
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
More from mindspore-ai/hyper-parallel
-
Difficulty 2/5 1-3 hours Newbie friendliness 68/100
mindspore-ai/hyper-parallel#713 ·
-
Difficulty 2/5 1-3 hours Newbie friendliness 72/100
mindspore-ai/hyper-parallel#711 ·
-
Difficulty 2/5 Half a day Newbie friendliness 86/100
mindspore-ai/hyper-parallel#703 ·
-
Difficulty 2/5 1-3 hours Newbie friendliness 78/100
mindspore-ai/hyper-parallel#698 ·
-
更新issue模版 Open
Difficulty 2/5 1-3 hours Newbie friendliness 62/100
mindspore-ai/hyper-parallel#686 ·
All issues in mindspore-ai/hyper-parallel
Similar issues
-
Difficulty 2/5 1-3 hours Newbie friendliness 74/100
bancolombia/sentinel#23 ·
-
test md OpenCI
Difficulty 2/5 1-3 hours Newbie friendliness 74/100
-
integration:quickjs org:external priority:backlog topic:code-interpreter topic:middleware type:feature
Difficulty 2/5 1-3 hours Newbie friendliness 74/100
langchain-ai/deepagents#6450 ·
-
bug client
Difficulty 2/5 1-3 hours Newbie friendliness 88/100
-
Difficulty 2/5 1-3 hours Newbie friendliness 74/100