检查点#
本文档描述 AReaL 的检查点系统,用于在分布式 RL 训练期间保存模型以进行评估和容错恢复。
概述#
AReaL 提供两种互补的检查点机制:
机制 |
用途 |
格式 |
包含优化器/数据加载器状态 |
|---|---|---|---|
Saver |
导出模型用于评估或发布 |
HuggingFace |
否 |
RecoverHandler |
故障后恢复训练 |
DCP(分布式检查点) |
是 |
两种机制在训练期间自动调用,可分别通过 config.saver 和 config.recover 进行配置。
检查点格式#
HuggingFace 格式#
由 Saver 用于模型导出:
标准 HuggingFace 模型格式(safetensors + config.json)
兼容
transformers.AutoModel.from_pretrained()可上传到 HuggingFace Hub
不包含优化器状态
DCP 格式(分布式检查点)#
由 RecoverHandler 用于容错:
后端原生分布式检查点格式(
torch.distributed.checkpoint或 Megatron 分布式检查点)跨所有 rank 分片以实现高效的并行 I/O
包含模型权重、优化器状态、RNG 状态等
后端特定:检查点仅与相同并行配置兼容
在 single-controller 模式下写入不可变 generation,并通过
LATEST指针原子发布SPMD 模式继续使用原有的覆盖写入布局
以 with_optim=True 保存的 FSDP 检查点还包含 lr_scheduler.pt,用于在加载优化器时恢复学习率调度进度。 这适用于 DCP 和 HF
训练检查点。恢复训练时,应保持学习率调度配置和训练总步数不变。缺少该文件的旧检查点仍可加载,
但会输出警告并保留当前调度器状态,无法精确恢复原来的学习率轨迹。仅加载模型权重(with_optim=False)时不会恢复调度器状态。
架构#
PPOTrainer.train()
│
├── 训练循环
│ ├── Rollout、计算值、PPO 更新...
│ │
│ ├── _save_hf() # HuggingFace 导出
│ │ └── Saver.save()
│ │ └── engine.save(weight_format="hf")
│ │
│ └── _save_recover_checkpoint() # 容错
│ └── RecoverHandler.dump()
│ └── engine.save(weight_format="dcp", with_optim=True)
│
└── 重启时
└── RecoverHandler.load()
├── 恢复 dataloader、saver、evaluator 状态
└── engine.load(weight_format="dcp", with_optim=True)
Saver:HuggingFace 模型导出#
Saver 定期以
HuggingFace 格式导出模型权重,用于评估或部署。
保存模式#
mode 参数控制检查点的写入方式:
模式 |
行为 |
|---|---|
|
对 Archon 引擎使用异步,其他使用同步(默认)。对所有引擎都是零配置最优选择。 |
|
始终同步 |
|
始终使用进程内异步,带有固定内存暂存。仅适用于 Archon 引擎;其他引擎回退到同步并发出警告。额外的 CPU 固定内存与每 rank 模型分片大小成正比(例如,70B 模型在 8 GPU 上每 rank 约 17.5 GB)。 |
使用默认的 auto 模式,Archon 引擎用户自动获得异步检查点保存 —— 训练循环仅在检查点暂存到固定 CPU 内存时阻塞,实际磁盘 I/O 在后台进程中发生。
配置#
通过 config.saver 配置:
参数 |
类型 |
默认值 |
描述 |
|---|---|---|---|
|
str |
|
保存模式(见上文)。 |
|
int | None |
None |
每 N 个 epoch 保存一次。None 禁用。 |
|
int | None |
None |
每 N 步保存一次。None 禁用。 |
|
int | None |
None |
每 N 秒保存一次。None 禁用。 |
配置示例:
saver:
freq_epochs: 1 # 每个 epoch 结束时保存
freq_steps: null # 禁用
freq_secs: null # 禁用
# mode 默认为 "auto" - Archon 用户自动获得异步
当满足 epoch/步数/时间任一条件时触发保存。
输出位置#
检查点保存到:
{fileroot}/checkpoints/{user}/{experiment_name}/{trial_name}/default/
└── epoch{E}epochstep{S}globalstep{G}/
├── config.json
├── model.safetensors(或 model-00001-of-00002.safetensors 等)
├── tokenizer.json
└── ...
使用方式#
使用标准 HuggingFace API 加载保存的检查点:
from transformers import AutoModelForCausalLM, AutoTokenizer
model = AutoModelForCausalLM.from_pretrained(
"/path/to/checkpoint/epoch0epochstep99globalstep99"
)
tokenizer = AutoTokenizer.from_pretrained(
"/path/to/checkpoint/epoch0epochstep99globalstep99"
)
RecoverHandler:容错#
RecoverHandler
通过保存完整训练状态实现故障后恢复训练。
配置#
通过 config.recover 配置:
参数 |
类型 |
默认值 |
描述 |
|---|---|---|---|
|
str |
“disabled” |
恢复模式:”on”/”auto” 或 “off”/”disabled” |
|
int | None |
None |
每 N 个 epoch 检查点 |
|
int | None |
None |
每 N 步检查点 |
|
int | None |
None |
每 N 秒检查点 |
|
int |
3 |
启用恢复时的恢复重试次数 |
恢复模式#
模式 |
行为 |
|---|---|
|
如果存在有效检查点则自动恢复 |
|
不进行检检查点或恢复 |
启用恢复(on/auto)时,系统将:
定期保存恢复检查点(模型权重、优化器状态、dataloader 位置)
重启时自动从最后一个有效检查点恢复
失败时重试最多
retries次
配置示例:
recover:
mode: on # 或 "auto"(向后兼容)
freq_steps: 100 # 每 100 步检查点
retries: 3
保存的内容#
RecoverHandler 保存完整训练状态:
组件 |
内容 |
|---|---|
模型权重 |
DCP 格式,跨 rank 分片 |
优化器状态 |
动量、方差(Adam)、学习率调度器 |
RNG 状态 |
Python、NumPy、PyTorch、CUDA 随机状态 |
Dataloader 状态 |
数据集中的当前位置 |
训练进度 |
Epoch、step、global_step 计数器 |
辅助状态 |
Saver、Evaluator、StatsLogger 状态 |
输出位置#
在 single-controller 模式下,恢复检查点保存为不可变 generation:
{fileroot}/checkpoints/{user}/{experiment_name}/{trial_name}/
├── LATEST # 原子 JSON 指针,指向一个完整 generation
└── checkpoint_generations/
└── generation_step00000123/
├── manifest/ # Dataloader 和训练进度元数据
└── payloads/
├── default/ # 模型 + 优化器(DCP 格式)
└── critic/ # 保存 critic 时存在
只有所有 payload 都持久化后才更新指针。当一个 generation 包含多个训练引擎时,RecoverHandler
会先等待除最后一个异步引擎以外的所有保存完成,再调度最后一个异步引擎。发布操作只追加到该引擎的 MCore finalize
callback,因此仍可让一次后台保存与训练重叠,同时不会暴露只写完 actor 或 critic 的 generation。 进程崩溃可能在磁盘上留下未发布的
generation,但恢复仍使用 LATEST 选中的 generation。指针成功切换后才删除上一个已发布 generation。
为保持兼容性,SPMD trainer 继续使用原有的 recover_info/ 和 <engine>/recover_checkpoint/
布局。恢复逻辑可以读取两种布局。
恢复过程#
恢复训练时:
RecoverHandler.load()恢复所有保存的状态(如有)训练从
last_step_info.next().global_step继续推理引擎权重同步以匹配恢复的状态
最佳实践#
频率指南#
场景 |
推荐设置 |
|---|---|
长时间训练 |
|
不可预测的时间 |
|
不稳定的集群 |
|
磁盘空间有限 |
较低频率,依赖最终检查点 |
调试 |
|
磁盘空间注意事项#
Saver:每次保存创建新目录。高频率会消耗大量空间。
RecoverHandler:通常保留一个已发布 generation,以及可能存在的正在写入或崩溃遗留 generation。SPMD 模式继续覆盖原有路径。
恢复技巧#
验证检查点有效性:读取
LATEST,再检查其选中 generation 的manifest/step_info.json需要相同配置:DCP 检查点需要相同的并行配置、实验名称和试次名称
每个 trial 仅一个 writer:不要让多个检查点 writer 并发写入同一实验和 trial 目录
干净重启:同时删除
LATEST和checkpoint_generations/。对于旧版 SPMD 检查点, 删除recover_info/和每个引擎的recover_checkpoint/