已关闭
[Bug]: FSDP2 resume 时 optimizer 状态 save/load 标志不对称导致静默发散 #621
iceflysnow创建于 8月14日关闭于 9月18日
8月14日 添加了label:bug
Iiceflysnow
8月14日 关联了pull request:fix(train): warn on optimizer save/load asymmetry to prevent silent resume divergence
8月14日 关联了pull request:fix(train): warn on optimizer save/load asymmetry to prevent silent resume divergence
iceflysnow
9月3日 评论:
9月3日 评论:
已提交针对该问题的修复PR,请审核:https://gitcode.com/Ascend/MindSpeed-MM/merge_requests/2983 (在 save/load 两侧增加 optimizer 存盘/加载不对称的告警,兼容旧 checkpoint 行为)


9月17日 将 wanglikai1019 设为负责人
9月18日 添加了label:resolved
LKONE
9月18日 评论:
9月18日 评论:
您好,此issue已经超过一周没有更新,且关联PR已合入,现先将issue关闭,有需要可以重新打开,谢谢!


9月18日 issue状态由 TODO 改变为 DONE
9月18日 关闭了 issue
问题概述
FSDP2 训练在 resume 时,optimizer 状态的 save/load 由
no_save_optim与no_load_optim两个独立标志控制,二者之间没有任何一致性校验。当存盘时no_save_optim=true(不保存 optimizer)、而 resume 时no_load_optim=false(请求加载 optimizer)时,由于 DCPload采用allow_partial_load(非 strict),源 checkpoint 中不存在 optimizer 分片会被静默跳过,optimizer 保持全新初始化状态(AdamW 的 exp_avg / exp_avg_sq 为零),resume 后训练从冷启动 Adam 开始,可能造成发散且无任何告警。对照 RNG 状态路径:save 端(
train_engine.py:423)写torch_rng_state,load 端(:387-391)有显式守卫——if "torch_rng_state" not in state["extra_state"]: print_rank(..., "No RNG state found in checkpoint, skipping RNG loading")。optimizer 路径没有对等的守卫,形成 save/load 不对称。复现
环境:Ascend 910B2 ×8,CANN 8.5.2,master HEAD
f9b6ad7d,Qwen3.5-0.8B,FSDP2。no_save_optim: true、no_load_optim: true(从 HF 权重冷启动),训练 2 iter 存盘。检查 checkpoint 元数据:optimizer 张量数 = 0(no_save_optim=true确实未写入 optimizer 分片)。no_load_optim: false,从 Phase A 的 checkpoint resume。日志显示Loaded checkpoint from .../iter_0000002,且 RNG 路径触发No RNG state found in checkpoint, skipping RNG loading(因 Phase A 同时no_save_rng=true);但 optimizer 路径无任何告警,optimizer 静默停留在全新初始化状态。期望 / 实际
根因
mindspeed_mm/fsdp/train/train_engine.py::421-422):if not args.training.no_save_optim: state["optimizer"] = self.optimizer——no_save_optim=true时不写入 optimizer。:367-368):if not args.training.no_load_optim: state["optimizer"] = self.optimizer—— 把 optimizer 占位放入 state 后交由 DCPload填充;DCPallow_partial_load(非 strict)在源分片缺失时静默跳过,无日志无异常。:387-391)有not in守卫 + 告警;optimizer 路径无对等守卫。两个标志独立、无一致性校验 + DCP 静默跳过,共同导致 resume 静默发散。
修复建议
在 save 端记录
saved_optim标志到extra_state,在 load 端仿照 RNG 守卫检测 save/load 不对称并告警::422之后):state["extra_state"]["saved_optim"] = not args.training.no_save_optimif not args.training.no_load_optim: if not state["extra_state"].get("saved_optim", True): print_rank(logger.warning, "Optimizer state was not saved ...")get(..., True)默认 True,对修复前已存的 checkpoint 向后兼容(不会误报)。