执行摘要
- 一句话:重构 Megatron 检查点管理器,引入 v2 布局与迁移脚本
- 推荐动作:本 PR 是重要的基础设施重构,推荐所有 Megatron 后端用户和开发者精读。重点关注:
1) 分层构建器模式如何解耦状态字典构造与 save/load;
2) 路径工具函数的组合与目录保障;
3) 迁移脚本的幂等设计和硬链接使用;
4) 配置类的继承设计;
5) ISEEKYAN 对 use_mbridge 命名的质疑提示 API 命名应清晰。
功能与动机
根据关联 Issue #5630,当前 mcore 检查点管理有多个后端(mbridge、dist_checkpointing、verl 原始实现),且两个模型相关 save_contents API(model、hf_model)实现复杂、命名混乱,使用户难以理解。通过与 FSDP 检查点管理器风格对齐,使代码更清晰、维护更简单。
实现拆解
- 定义新的检查点目录结构 (v2 layout):在
verl/utils/megatron_utils.py 中新增路径工具函数,将检查点拆分为 model/(含 huggingface/ 和 dist_ckpt/)、optimizer/dist_ckpt/、extra/dist_ckpt/ 三个独立子树,并提供规范的路径生成函数。同时保留对 v1 布局的检测。
- 重构
MegatronCheckpointManager:将 generate_state_dict 拆分为 _build_model_sharded_state_dict、_build_optimizer_state_dict、_build_extra_state_dict 等构建器,分别构造所需的 sharded state dict。save_checkpoint 和 load_checkpoint 基于 save_contents/load_contents 动态调度到对应后端(mbridge/dist_checkpointing/PEFT)。__init__ 中提前验证 save_contents 与后端矩阵的合法性。
- 引入
use_mbridge 标志:废弃 use_dist_checkpointing,新增 use_mbridge 作为正向标志(use_mbridge = not use_dist_checkpointing)。use_dist_checkpointing 作为遗留别名仍接受。hf_model 内容仅在 mbridge 启用时可用。
- 新增迁移脚本
scripts/migrate_megatron_checkpoint_layout.py:支持将 v1 布局(dist_ckpt/ 单目录)转换为 v2 布局。利用 Megatron dist_checkpointing.load 的 key-driven 特性,默认使用硬链接(不增加磁盘占用),支持 symlink 和 copy 模式。脚本幂等。
- 后端配置抽取:在
verl/workers/config/checkpoint.py 中新增 McoreCheckpointConfig 和 MindSpeedCheckpointConfig 子类,将 mbridge 额外参数从通用配置中分离。
- 适配模型合并器等消费者:
verl/model_merger/base_model_merger.py 新增 _default_hf_model_config_path 函数,根据后端类型选择正确的 HF 模型配置路径。
- 添加全面的单元测试:在
tests/utils/ckpt/test_megatron_checkpoint_manager_on_cpu.py 中新增 657 行测试,覆盖 flag 解析、构建器组合、save/load 调度以及边界情况。
关键文件:
scripts/migrate_megatron_checkpoint_layout.py(模块 迁移脚本;类别 source;类型 migration-tool;符号 _is_v2_layout, _is_legacy_layout, _link_tree, _move): 新增迁移脚本,实现从 v1 到 v2 布局的幂等迁移,是整个重构的配套工具,关系用户升级路径。
verl/utils/checkpoint/megatron_checkpoint_manager.py(模块 检查点管理器;类别 source;类型 core-logic;符号 should_save_hf_model, should_save_dist_ckpt_model, should_load_hf_model, should_load_dist_ckpt_model): 核心重构文件,修改量最大(+806/-436),实现分层构建器、新布局 save/load 和 flag 解析。
verl/utils/megatron_utils.py(模块 路径工具;类别 source;类型 core-logic;符号 get_model_checkpoint_path, get_optimizer_checkpoint_path, get_extra_checkpoint_path, get_model_dist_checkpoint_path): 新增路径工具函数集,定义 v2 布局的每个子目录路径,是布局的规范定义。
tests/utils/ckpt/test_megatron_checkpoint_manager_on_cpu.py(模块 CPU测试;类别 test;类型 test-coverage;符号 _init_distributed, _MegatronSub, _RoleCfg, _MinimalModel): 新增 657 行单元测试,覆盖新管理器的核心路径和边界条件,是重构的质量保障。
verl/workers/config/checkpoint.py(模块 配置;类别 config;类型 configuration;符号 McoreCheckpointConfig, MindSpeedCheckpointConfig): 新增 McoreCheckpointConfig 和 MindSpeedCheckpointConfig 配置子类,分离后端特定配置。
verl/model_merger/base_model_merger.py(模块 模型合并器;类别 source;类型 data-contract;符号 _default_hf_model_config_path): 适配新布局,使 HF 模型配置路径根据后端类型自动选择 model/huggingface/ 或 huggingface/。
关键符号:_is_v2_layout, _is_legacy_layout, migrate_one, should_save_hf_model, should_save_dist_ckpt_model, _build_model_sharded_state_dict, _build_optimizer_state_dict, _build_extra_state_dict, _default_hf_model_config_path
关键源码片段
scripts/migrate_megatron_checkpoint_layout.py
新增迁移脚本,实现从 v1 到 v2 布局的幂等迁移,是整个重构的配套工具,关系用户升级路径。
def _is_v2_layout(ckpt_dir: Path) -> bool:
# 检测是否为 v2 布局:只需检查是否存在 model/、optimizer/、extra/ 之一
return any((ckpt_dir / sub).is_dir() for sub in ("model", "optimizer", "extra"))
def _is_legacy_layout(ckpt_dir: Path) -> bool:
# 检测是否为 v1 旧布局:通过 dist_ckpt/ 或 huggingface/ 目录的存在来判断
return (ckpt_dir / "dist_ckpt").is_dir() or (ckpt_dir / "huggingface").is_dir()
def migrate_one(ckpt_dir: Path, *, dry_run: bool, mode: str) -> str:
# 迁移单个 checkpoint 目录(幂等),返回状态字符串
if _is_v2_layout(ckpt_dir):
return "skipped (already v2)"
if not _is_legacy_layout(ckpt_dir):
return "skipped (no recognised layout)"
legacy_dist = ckpt_dir / "dist_ckpt"
legacy_hf = ckpt_dir / "huggingface"
new_model = ckpt_dir / "model"
new_optimizer = ckpt_dir / "optimizer"
new_extra = ckpt_dir / "extra"
# 利用 Megatron key-driven load 特性,三个 dist_ckpt/ 指向同一物理数据
_link_tree(legacy_dist, new_model / "dist_ckpt", mode)
_link_tree(legacy_dist, new_optimizer / "dist_ckpt", mode)
_link_tree(legacy_dist, new_extra / "dist_ckpt", mode)
# huggingface 目录直接移动到 model/huggingface/
if legacy_hf.is_dir():
_move(legacy_hf, new_model / "huggingface")
return "migrated"
verl/utils/checkpoint/megatron_checkpoint_manager.py
核心重构文件,修改量最大(+806/-436),实现分层构建器、新布局 save/load 和 flag 解析。
class MegatronCheckpointManager(BaseCheckpointManager):
def __init__(self, ..., use_mbridge: Optional[bool] = None,
use_dist_checkpointing: Optional[bool] = None):
# 处理遗留的 use_dist_checkpointing 参数,将其转换为 use_mbridge
if use_mbridge is None and use_dist_checkpointing is not None:
use_mbridge = not use_dist_checkpointing
self.use_mbridge = use_mbridge if use_mbridge is not None else True
# 验证 save_contents 与 backends 的兼容性
if "hf_model" in self.save_contents and not self.use_mbridge:
raise ValueError("hf_model is only supported with mbridge enabled")
if not self.use_mbridge and "model" not in self.save_contents:
raise ValueError("When mbridge is disabled, save_contents must include 'model'")
...
def _build_model_sharded_state_dict(self, model):
# 根据后端选择构建模型 sharded state dict
if self.use_mbridge and "hf_model" in self.save_contents:
return None # mbridge 模式下 HF 保存不需要 sharded dict
# 否则使用 dist_checkpointing 的 sharded_state_dict
if hasattr(model, "module"):
model = model.module
return model.sharded_state_dict()
def _build_optimizer_state_dict(self, optimizer):
# 总是使用 dist_checkpointing 保存优化器状态
return optimizer.sharded_state_dict() if optimizer else None
评论区精华
Review 中主要讨论了以下几点:
风险与影响
- 风险:兼容性风险:旧版 checkpoint(v1 布局)无法直接加载,必须运行迁移脚本。虽然脚本默认硬链接不增加磁盘,但跨文件系统时回退到 symlink 或 copy 可能带来额外空间/性能开销。
use_mbridge 替换 use_dist_checkpointing 可能破坏现有 YAML 配置,但已保留向后别名。回归风险:核心 save/load 路径全面重构,多个 backend 组合可能引入回归,尤其是 PEFT 场景。测试覆盖新增 657 行单元测试,但未覆盖 HDFS 等分布式场景。安全风险:迁移脚本仅使用硬链接/拷贝,无特殊权限操作。性能风险:新布局新增目录创建和原子 rename 步骤,对训练整体影响可忽略。
- 影响:对用户:新版本 checkpoint 使用 v2 目录结构,需更新自定义消费脚本(模型合并器已适配);从旧版本恢复训练需运行迁移脚本。对系统:内部逻辑简化,消除了复杂条件判断,减少 bug 风险;目录结构标准化便于与 FSDP 共享工具。对团队:代码可读性和可维护性显著提升;配置类分离降低耦合。
- 风险标记:旧布局需迁移脚本, 核心路径重构, 配置字段重命名, 跨文件系统硬链接回退, PEFT 场景回归风险
关联脉络
- PR #6507 [ckpt] feat: pass global steps to checkpoint engines: 同期修改了 checkpoint 引擎基础接口,与本 PR 的检查点管理器重构存在依赖关系,共同完善检查点基础设施。
参与讨论