版本信息最后核对:2026-10-25
训练 checkpoint 损坏与恢复失败:保存中断、分片缺失、并行策略不兼容的排查路径。
训练任务在保存 checkpoint 时被抢占、重启或磁盘写满,之后恢复报错;也可能保存日志显示成功,加载时却在解析文件、映射参数或恢复优化器状态时失败。典型报错包括 PytorchStreamReader failed locating file、unexpected end of file、Invalid magic number、KeyError、size mismatch、Missing key(s) in state_dict、shard ... not found,分布式 checkpoint 还会提示元数据或分片缺失。
另一类更隐蔽:文件能加载,但恢复后 step 从零开始、loss 突然变差、学习率重新 warmup,或者训练几步后梯度异常。这说明损坏不在字节层,而在“状态不完整”或“并行策略不兼容”。还有任务把不完整的 checkpoint 通过符号链接发布为 latest,后续所有恢复都指向坏副本。
排查时先分清三层:文件是否完整、结构是否匹配、训练状态是否齐全。三层的修复方式完全不同。
先冻结现场,不要删除或覆盖任何 checkpoint:
ls -lh <ckpt-dir>
find <ckpt-dir> -maxdepth 2 -type f -printf '%TY-%Tm-%Td %TH:%TM %s %p\n' | sort
df -h <ckpt-dir>
du -sh <ckpt-dir>
找临时目录、.tmp 文件、未完成的上传和 latest 指针,确认最后一个完整副本。文件明显偏小、修改时间停在任务被杀时刻,通常就是中断现场。
在隔离的 CPU 进程中做最小加载测试,避免一上来占满 GPU:
python - <<'PY'
import torch
path = "<ckpt-file>"
obj = torch.load(path, map_location="cpu", weights_only=True)
print(type(obj))
if isinstance(obj, dict):
print(list(obj)[:20])
PY
只对可信来源反序列化;weights_only=True 能降低任意代码执行风险,但某些框架需要专用加载器。分片 checkpoint 还要核对索引中的每个分片是否存在、非零,并按清单校验摘要。
| 线索 | 更可能的方向 |
|---|---|
| 打开或反序列化即失败 | 文件截断、存储故障、上传不完整 |
| 参数名或形状不匹配 | 版本、模型结构、并行策略变化 |
| 提示分片或元数据缺失 | 保存未完成、分片被清理、索引过期 |
| 加载成功但 step 归零、loss 跳变 | 优化器、scheduler、RNG、sampler 状态缺失 |
| 只在另一个 world size 下失败 | 分片布局或并行策略不兼容 |
| 同一份文件在不同节点表现不同 | 挂载、缓存、权限或文件系统问题 |
回答四个问题:
任务被抢占、进程收到终止信号、节点重启、OOM Killer、保存超时、磁盘写满,都会留下不完整文件。很多实现先写分片再写元数据,如果元数据已经落盘而部分分片没写完,加载时就会表现为“索引存在但分片缺失”。
NFS 的属性缓存和延迟写入会让“写完”与“可见”不同步;对象存储的 multipart 上传未完成时可能留下看似存在的对象;配额耗尽、权限变化、挂载失效和文件系统错误都会造成截断。
索引与实际文件不一致、分片重复或遗漏、不同 step 混在同一目录、元数据先于分片完成,都会让加载器找不到完整状态。使用符号链接或“最新指针”时,指针更新与分片写入如果不是原子操作,恢复可能读到新旧混合的版本。
框架升级改变了序列化格式、默认加载参数或参数命名;模型结构、词表大小、绑定权重处理发生变化;FSDP 与 DeepSpeed 的分片方式、ZeRO stage、张量并行和流水并行布局与保存时不同;优化器实现或参数分组改变。以上都可能让文件“能打开但装不回去”。world size 变化时,分片数与参数映射也需要框架支持重分片。
只保存模型权重,没有保存优化器动量、scheduler、loss scale、RNG、数据 sampler、step/epoch 和 EMA,会出现文件正常但训练不连续。恢复脚本若重新初始化优化器或把 step 置零,学习率会回到 warmup 起点,数据顺序也会重置。这类问题不应称为“checkpoint 损坏”,但现场表现很相似。
没有清单、校验和与“保存完成”标记,就无法区分完整副本和半成品;latest 被原地覆盖后,坏文件会立刻成为唯一入口;保留策略还可能删除旧 checkpoint 依赖的分片。没有恢复演练时,这些问题往往直到真正故障才暴露。
列出所有 checkpoint 的路径、大小、时间、分片数、索引和指针,标记最后一个已知可用版本。暂停清理和覆盖式上传,避免证据被删。不要在原目录修复或重命名关键文件。
先读元数据和目录结构,再在 CPU 上做最小加载。核对索引中的分片、文件头、大小和校验和;对象存储确认上传完成,NFS 换客户端复核可见性。A 节点可读、B 节点报错时,优先查挂载和缓存。
打开或反序列化失败按文件损坏处理;参数名、形状或类型不匹配按结构或版本处理;加载成功但 step、loss 或学习率异常按状态不完整处理。保存完整 traceback 和出错对象名,不要只看最后一行。
查找保存开始与结束、异常、终止信号、磁盘空间和上传结果。确认写入是否原子:先写临时目录、校验后重命名,所有 rank 完成后才发布元数据,被抢占时能安全退出。没有“完成”记录的 checkpoint 默认不可信。
把保存时的框架版本、模型配置、并行策略、world size、优化器类型和参数名,与恢复环境逐项对比。优先用随 checkpoint 落盘的配置,而不是当前代码默认值。改变并行度时确认框架支持重分片,不要手工拼接不同布局的分片。
检查 map_location、严格模式,以及优化器、scheduler、loss scale、RNG、sampler 和 step 是否恢复。恢复后先用固定 batch 比较 loss、学习率和梯度范数,再连续跑若干 step 看曲线。缺优化器状态时明确标记为热启动。
优先回滚到上一个验证过的 checkpoint。原任务仍在运行时,可把当前状态另存到新路径再恢复;不要覆盖坏副本,也不要把不同 step 的分片拼在一起。只有在测试环境确认结构可读时,才考虑从残片提取权重。
权重完整、优化器状态缺失时可热启动,但要重新校准学习率、step 和数据顺序;结构损坏且无旧副本时,只能从更早 checkpoint 或预训练权重重训。把选择和影响记入元数据,避免后续误判曲线。
保存侧改成原子发布:先写临时目录或对象,校验分片数量和摘要,写清单与完成标记,最后原子重命名或切换指针。保留若干完整副本,不原地覆盖最佳模型,清理只删除带完成标记且过期的目录。保存后立即校验元数据,失败就告警。
按损坏类型处理:
验证至少覆盖:
删除、覆盖或强制修复 checkpoint 都属于高风险操作:先在测试环境验证,保留只读备份,不要在共享存储上直接执行不可逆的清理命令。
latest 指针切换必须原子,最佳模型不原地覆盖。合上页面,先回答,再展开对照。
小程序版
微信扫码,随时查命令