使用检查点支持容错训练

Last updated: 06/25/2025.

在整个 RLHF(Reinforcement Learning from Human Feedback,人机反馈强化学习)训练过程中,可能会出现训练错误或机器故障,因此建议启用检查点,以尽量减少损失。

API 接口已在 config-explain-page 中列出,我们不会重复说明。但仍然有一些技术细节需要澄清。

Note

注意,checkpoint.contents 字段对 FSDP 检查点无效(除非包含 hf_model),其他 3 个字段绑定在一起用于保存和加载。我们推荐同时包含 modeloptimizerextra

检查点保存目录结构

通常,我们使用 ppo_trainer.yamlppo_megatron_trainer.yml 中声明的 default_local_dir 作为保存检查点时的前缀,即 checkpoints/${trainer.project_name}/${trainer.experiment_name}

因此,FSDP 的内部检查点结构如下:

checkpoints/${trainer.project_name}/${trainer.experiment_name}
├── global_steps_${i}
│   ├── actor
│   │   ├── huggingface      # default save config and tokenizer, save huggingface model if include ``hf_model`` in checkpoint.contents
│   │   └── fsdp_config.json # FSDP config file, including world_size and fsdp version
│   │   ├── model_world_size_{self.world_size}_rank_{self.rank}.pt
│   │   ├── optim_world_size_{self.world_size}_rank_{self.rank}.pt
│   │   └── extra_state_world_size_{self.world_size}_rank_{self.rank}.pt
│   ├── critic
│   │   ├── huggingface
│   │   └── fsdp_config.json
│   │   ├── model_world_size_{self.world_size}_rank_{self.rank}.pt
│   │   ├── optim_world_size_{self.world_size}_rank_{self.rank}.pt
│   │   └── extra_state_world_size_{self.world_size}_rank_{self.rank}.pt
└── latest_checkpointed_iteration.txt

所有模型分片、优化器和额外状态都以分片和分布式的方式一起存储。

Megatron 当前的检查点结构为:

checkpoints/${trainer.project_name}/${trainer.experiment_name}
├── global_steps_${i}
│   ├── actor
│   │   ├── huggingface     # default save config and tokenizer, save huggingface model if include ``hf_mode`` in checkpoint.contents
│   │   └── dist_ckpt       # save sharded model/optimizer/rng_states, naming the same as Megatron
│   └── critic
│   │   ├── huggingface
│   │   └── dist_ckpt
└── latest_checkpointed_iteration.txt

将 FSDP 和 Megatron 检查点转换为 HuggingFace 格式模型

我们提供了一个工具,用于将 FSDP 和 Megatron 检查点转换为 HuggingFace 格式模型。该工具位于 verl/model_merger。对于较旧版本的 verl(检查点中不包含 fsdp_config.json),可以使用位于 verl/scripts/legacy_model_merger.py 的旧版模型合并器。

该脚本支持两个主要子命令:``merge``(用于转换和保存检查点)和 ``test``(用于验证合并后的检查点是否与参考模型一致)。

merge 子命令的参数如下:

usage: python -m verl.model_merger merge [-h] --backend {fsdp,megatron} [--local_dir LOCAL_DIR] [--tie-word-embedding] [--is-value-model] [--use_cpu_initialization] [--target_dir TARGET_DIR]
                     [--hf_upload_path HF_UPLOAD_PATH] [--private]

options:
-h, --help            show this help message and exit
--backend {fsdp,megatron}
                        The backend of the model
--local_dir LOCAL_DIR
                        Path to the saved model checkpoints
--tie-word-embedding  Whether to tie word embedding weights (currently only Megatron supported)
--is-value-model      Whether the model is a value model (currently only Megatron supported)
--use_cpu_initialization
                        Whether to use CPU initialization for the model. This is useful for large models that cannot fit into GPU memory during initialization.
--target_dir TARGET_DIR
                        Directory to save the merged huggingface model
--hf_upload_path HF_UPLOAD_PATH
                        Hugging Face repository ID to upload the model
--private             Whether to upload the model to a private Hugging Face repository

合并 Megatron 检查点的示例用法:

python -m verl.model_merger merge \
    --backend megatron \
    --tie-word-embedding \
    --local_dir checkpoints/verl_megatron_gsm8k_examples/qwen2_5_0b5_megatron_saveload/global_step_1/actor \
    --target_dir /path/to/merged_hf_model

分布式合并 Megatron 检查点的示例用法:

torchrun --nproc_per_node 1 --nnodes 8 --node_rank ${RANK} -m verl.model_merger merge \
    --backend megatron \
    --tie-word-embedding \
    --local_dir checkpoints/verl_megatron_gsm8k_examples/qwen2_5_0b5_megatron_saveload/global_step_1/actor \
    --target_dir /path/to/merged_hf_model

合并 FSDP 检查点的示例用法:

python -m verl.model_merger merge \
    --backend fsdp \
    --local_dir checkpoints/verl_fsdp_gsm8k_examples/qwen2_5_0b5_fsdp_saveload/global_step_1/actor \
    --target_dir /path/to/merged_hf_model

Megatron 合并器详情

当前解码器层的实现使用 nn.ModuleList 来存储层,因此每个 PP(Pipeline Parallel,管道并行)排名和 VPP(Virtual Pipeline Parallel,虚拟管道并行)排名上的模型层索引都从 0 开始。

有 3 种方式可以纠正此行为:

  1. 修改解码器层的 state_dict,向每个层的索引添加 offset,从而重写 nn.ModuleList 的实现。

  2. 在保存检查点时修改层索引,并在加载检查点时恢复它们。

  3. 检查点合并器仅从 state_dict 计算实际的 offset,这有点复杂。

当前实现使用方案 2。

HuggingFace 到 Megatron DistCheckpoint 的详情

如果您的模型非常庞大,我们推荐使用 Megatron dist-checkpoint 来加载模型。Megatron dist-checkpoint 支持在不同类型的模型并行下加载,并且比原始检查点加载快得多。

要将原始 HuggingFace 模型转换为 Megatron dist-checkpoint,您可以使用 scripts/converter_hf_to_mcore.py 脚本。大型的 MoE 模型暂时支持通过 CPU 初始化来加载,这会稍微慢一些。我们正在致力于更好的解决方案来支持大型模型。

转换模型的示例命令如下:

python scripts/converter_hf_to_mcore.py \
    --hf_model_path Qwen/Qwen1.5-MoE-A2.7B-Chat \
    --output_path /mnt/disk/Qwen/Qwen1.5-MoE-A2.7B-Chat \
    --use_cpu_initialization    # Only work for MoE models

分布式转换像 deepseekv3 671B 这样的大型模型的示例命令如下:

torchrun --nproc_per_node 1 --nnodes 8 --node_rank ${RANK} scripts/converter_hf_to_mcore.py \
    --hf_model_path deepseek-ai/DeepSeek-V3 \
    --output_path /mnt/disk/deepseek-ai/DeepSeek-V3 \
    --use_cpu_initialization    # Only work for MoE models

原始检查点工具

原始检查点工具是指 verl/models/[model]/megatron/checkpoint_utils 中的原始检查点实现。

现在我们只需使用原始检查点工具中的 [model]_loader.py,因为我们不再每次都存储 ``hf_model``(这对于大型模型训练不推荐,如果可能的话,只保存分片模型)。

Note

注意,[model]_loader 只支持**存储集群能够与每个计算节点连接的环境**。因为它利用**分片加载方式来最小化加载检查点开销**。每个排名从 state_dict 加载自己的数据,这些数据所有排名都可以访问。同时,由于保存的 state_dict 仅由 DP(Data Parallel,数据并行)排名 0 生成,因此不需要在 DP 排名之间广播。

对于**只能在单个设备上放置 HuggingFace 模型的用户**,我们保留了旧版成本较高的实现,即 [model]_loader_deprecated。此实现中,排名 0 将所有权重广播到每个 TP(Tensor Parallel,张量并行)和 PP 排名,然后 DP 排名 0 广播到所有 DP 排名。可能会存在内存不足的风险。

要使用已弃用的加载器,请更改 load_state_dict_to_megatron_llama 的导入包。