大模型训练把权重、梯度、优化器状态切散在多个 rank 上,检查点随之从单文件变成一整套分片目录:Megatron-LM、DeepSpeed ZeRO、PyTorch FSDP 各有一套格式。读懂目录结构、保住优化器分片、对齐并行度,是断点续训与格式导出的三条命脉。
检查点版图三分:模型权重保存 讲 PyTorch 原生 torch.save 机制,推理模型格式 讲 HF / safetensors / GGUF 等推理态格式,本篇专讲训练态分片检查点。TP / PP / DP / ZeRO 等并行策略本身的原理见 分布式训练总览,这里只关心它们如何决定落盘形态。三大框架的共性:按 rank 分片落盘、附带 optimizer 与 RNG 状态、与并行拓扑强绑定——因此不能 torch.load 直读,续训受并行度约束。
Megatron-LM:TP/PP/DP 三级分片目录
Megatron-LM(含 Megatron-DeepSpeed、NeMo 等衍生分支)按 TP → PP → DP 组织目录:每个 TP×PP 组合一个目录;DP 组内权重相同,不占目录层级(分布式优化器状态才按 DP 维再切片落盘)。
iter_0068000/ # 按全局迭代步命名
├── latest_checkpointed_iteration.txt # 最新迭代标记,加载入口
├── mp_rank_00/ # TP rank 0
│ ├── pp_rank_00/ # PP stage 0
│ │ ├── model_optim_rng.pt # 权重分片 + 优化器超参 + RNG 状态
│ │ └── distrib_optim.pt # 分布式优化器分片(Adam 的 m/v)
│ └── pp_rank_01/
└── mp_rank_01/ # TP rank 1model_optim_rng.pt三合一:权重切片、optimizer 超参、RNG 状态——续训时 dropout 与数据 shuffle 精确对齐靠它distrib_optim.pt仅在启用 Distributed Optimizer 时存在,Adam 动量按 DP 维分片;丢失后续训等效换优化器,loss 必跳变- 目录缺
pp_rank层即 PP=1;mp_rank个数即 TP 度 - 新版 Megatron-LM 另支持基于 PyTorch DCP 的统一分片格式(
.distcp+.metadata),可跨并行度 resharding,但旧式目录仍是存量主流
加载约束:MP/PP/DP 必须与保存时严格一致;任一分片缺失即失败;单分片只是切片,必须由 Megatron 按拓扑重建模型后填充;各分支目录细节有差异,不能互相混用。
DeepSpeed ZeRO:stage 决定分什么
| Stage | 训练时分片对象 | 检查点形态 |
|---|---|---|
| ZeRO-1 | optimizer states | 每 rank 文件内权重为完整冗余副本 |
| ZeRO-2 | + gradients | 同上(梯度不落盘) |
| ZeRO-3 | + parameters | 权重真分片,需全部 rank 文件才能重建全量 |
checkpoint/
├── latest # 文本文件,指向最新 step 目录
└── global_step_1000/
├── zero_pp_rank_0_model_states.pt # 各 rank 的权重(形态随 stage)
├── zero_pp_rank_1_model_states.pt
├── zero_pp_rank_0_optim_states.pt # 各 rank 的优化器状态分片
└── zero_pp_rank_1_optim_states.pt命名中的 pp 指 ZeRO 参数分区序号(沿 DP 维),与 Megatron 的流水线 pp_rank 无关,勿混淆。
标准 ZeRO 检查点与 world size、stage 强耦合,换卡数、换 stage 都无法直接续训。Universal Checkpoint 解决这一点:用 ds_to_universal.py 把标准检查点改写为统一命名、按参数连续存储的布局,加载侧设 load_universal: true,即可跨 ZeRO 配置、跨 world size 续训——训练中扩缩容、多人接力训练的标准做法。
PyTorch FSDP:三种保存模式与 DCP
| StateDictType | 落盘形态 | 通信开销 | 用途 |
|---|---|---|---|
FULL_STATE_DICT | rank 0 gather 合并全量单文件 | 高 | 导出推理、跨框架迁移 |
LOCAL_STATE_DICT | 每 rank 写自身分片 | 零 | 同拓扑断点续训 |
SHARDED_STATE_DICT | DCP 目录:.distcp 分片 + .metadata | 低 | 超大模型训练主力 |
DCP(torch.distributed.checkpoint)是 PyTorch 官方分布式检查点后端:各 rank 并行写自身分片,元数据记录每个张量在各文件中的字节区间,加载时按新拓扑重新切分——保存与加载的 world size 可以不同(resharding),这是它取代 LOCAL 模式的本质优势,也是 torchtitan 等官方参考实现的标准选择。协调依赖 torch.distributed 通信原语 的进程组;加载必须走 torch.distributed.checkpoint.load,不支持 torch.load。
from torch.distributed.checkpoint import save
from torch.distributed.checkpoint.state_dict import (
get_model_state_dict, get_optimizer_state_dict)
# FSDP2 + DCP:各 rank 并行写分片,无全局 gather,支持异步保存
state = {"model": get_model_state_dict(model),
"optim": get_optimizer_state_dict(optimizer), "step": step}
save(state, checkpoint_id="ckpt/step_1000") # 生成 __0_0.distcp... + .metadata并行度匹配与续训铁律
- 续训并行度与保存时严格一致:Megatron 旧式目录 MP/PP/DP 全对齐,ZeRO 对齐 stage 与 world size,FSDP LOCAL 对齐分片数。错配表现为维度不匹配或权重缺失,是分布式加载失败的头号原因
- 例外仅限显式支持 resharding 的格式:DCP 系(FSDP SHARDED、新版 Megatron)与 Universal Checkpoint,且需按文档声明加载配置
- 分片完整性:手删”看似冗余”的 rank 文件(尤其
optim_states、distrib_optim.pt)会破坏优化器状态;只要权重推理,应走官方转换抽取,而非手动删文件 - RNG 与调度器状态决定”无缝”续训:只用权重热启动是另一种训练策略,不是续训
格式转换
跨格式转换一律官方工具,不手拼权重:
| 转换 | 工具 |
|---|---|
| Megatron → HF | Megatron-LM tools/checkpoint/convert.py(旧称 checkpoint_util / convert_checkpoint 一族);Megatron-DeepSpeed 用 megatron_to_transformers.py |
| ZeRO 分片 → 全量单文件 | 检查点目录内自动生成的 zero_to_fp32.py |
| ZeRO → Universal | ds_to_universal.py |
| FSDP → HF | FULL_STATE_DICT 合并后 save_pretrained |
# 合并 ZeRO-3 分片为全量 fp32 权重(脚本随检查点自动生成)
cd checkpoint/global_step_1000
python zero_to_fp32.py . pytorch_model.bin转换的通用路径是「分片目录 → 全量单文件 → 推理态格式」。用 Accelerate 训练时,底层无论 FSDP 还是 DeepSpeed,save_model 已封装 gather 逻辑,通常无需手动转换。