Chapter 06

训练后端:FSDP / Megatron 两条路

📌 源码引用基于 verl/workers/engine/ 、 verl/trainer/config/actor/ · commit 9c38b8bb1876 。

6.1 verl 给你两条训练后端

verl 通过 actor_rollout_ref.actor.strategy(或顶层 model_engine)选择训练后端:

后端对应 Hydra 配置主战场
FSDP actor: fsdp_actor ≤ 70B 模型,灵活快速
FSDP2 actor: fsdp2_actor PyTorch 2.x 原生新版
Megatron-Coreactor: megatron_actor千亿级模型 + TP/PP
TorchTitan actor: torchtitan_actor实验性
VeOmni actor: veomni_actor 多模态 / 大型 MoE

在启动脚本里通过 model_engine 一次切换:

python -m verl.trainer.main_ppo \
  model_engine=fsdp \
  ... 其他 override

等价于 actor / critic / ref 全部用 FSDP。

6.2 FSDP 路径

什么时候用

关键配置(fsdp_actor.yaml

字段含义
actor.fsdp_config.fsdp_size FSDP shard 数量,通常 = DP world size
actor.fsdp_config.param_offload 参数卸载到 CPU
actor.fsdp_config.optimizer_offload 优化器卸载到 CPU
actor.fsdp_config.wrap_policy FSDP 包模块的策略:transformer_auto_wrap_policy 等
actor.fsdp_config.forward_prefetch 前向 prefetch
actor.fsdp_config.backward_prefetch 反向 prefetch
actor.fsdp_config.mixed_precision bf16 / fp16
actor.use_torch_compile 是否包 torch.compile
actor.use_remove_padding 变长序列去 padding,省算力
actor.enable_gradient_checkpointing 激活重算

FSDP vs FSDP2

差别FSDP1FSDP2
PyTorch 版本 ≥ 1.11 ≥ 2.4
API 风格 module wrapper tensor 级(DTensor)
显存碎片 偶有问题 更小
对自定义模型友好度 中等 更好
verl 支持 稳定 推荐用

6.3 Megatron 路径

什么时候用

关键配置(megatron_actor.yaml

字段含义
actor.megatron.tensor_model_parallel_size TP 度
actor.megatron.pipeline_model_parallel_size PP 度
actor.megatron.virtual_pipeline_model_parallel_sizeinterleaved PP
actor.megatron.expert_model_parallel_size EP 度(MoE 专用)
actor.megatron.context_parallel_size CP 度(长上下文)
actor.megatron.sequence_parallel 是否开 SP
actor.megatron.use_distributed_optimizer 类似 ZeRO-1,把优化器切到 DP
actor.megatron.use_mcore_models 用 Megatron-Core 新版模型实现

Megatron-Bridge:HF 模型 ↔ Megatron 互转

Megatron 路径有个挑战:HF 模型权重不能直接 load 进 Megatron,要转格式。verl 推荐用 NVIDIA 出的 Megatron-Bridge

# 训练前一次性把 HF checkpoint 转 Megatron 格式
python -m megatron_bridge.tools.convert_hf_to_megatron \
  --hf_model Qwen/Qwen3-30B-A3B \
  --output ckpt/qwen3_30b_a3b_mcore \
  --tp 4 --pp 2 --ep 8

# 训完用反向工具转回 HF
python -m megatron_bridge.tools.convert_megatron_to_hf \
  ...

6.4 怎么选:FSDP 还是 Megatron

指标FSDPMegatron
上手难度 简单 陡峭
显存效率 高(TP+PP 精细切)
训练吞吐(70B 内)很好 相当或略低
训练吞吐(≥ 100B)受限 明显领先
支持模型范围 广(任何 HF 模型) 需要适配模型层
多模态 原生支持 需要额外适配
MoE 训练 支持但低效 专家并行加持,吞吐高
checkpoint 互转 原生 HF 格式 要走 Megatron-Bridge

经验法则

6.5 hybrid: FSDP actor + Megatron critic?

verl 允许 actor / critic / ref 走不同后端。但常见做法是统一——除非有强需求,不建议 mix。配置举例:

actor_rollout_ref.actor.strategy=fsdp2
critic.strategy=megatron       # 不推荐这样混,除非你知道在干什么

6.6 模型并行尺寸推荐表(Megatron 路径)

模型TPPPEPDP总 GPU
Qwen3-7B 2 1 1 4 8
Qwen2.5-32B 4 2 1 2 16
Qwen3-30B-A3B (MoE) 2 1 4 1 8
Qwen3-235B-A22B (MoE)4 4 8 1 128
DeepSeek-V3 671B 4 8 16 1 512

关系仍然是:

$$W = \mathrm{TP} \times \mathrm{PP} \times \mathrm{DP} \times (\mathrm{EP}/\mathrm{TP\text{ for MoE}})$$

6.7 训练后端调优清单

问题FSDP 解Megatron 解
OOM param_offload + optimizer_offload调大 TP / PP;开 SP
throughput 低 use_remove_padding,开 torch.compilevirtual_pipeline_model_parallel_size
反向慢 backward_prefetch = backward_predistribute_saved_activations
长上下文 FSDP + flash-attn 开 CP(context parallel)
多模态 用 FSDP;vision tower 不切 需要 Megatron 多模态分支

6.8 EngineRegistry:两级 dispatch

讲了这么多后端,verl 怎么从一个 strategy: fsdp 字段最终拿到正确的实现类?看 verl/workers/engine/base.py:267EngineRegistry

class EngineRegistry:
    _registry: Dict[str, Dict[str, Dict[str, Type[BaseEngine]]]] = {}
    #              model_type    backend     device → class

    @classmethod
    def register(cls, model_type, backend, device):
        def decorator(engine_cls):
            cls._registry[model_type][backend][device] = engine_cls
            return engine_cls
        return decorator

    @classmethod
    def new(cls, model_type, backend, ...):
        return cls._registry[model_type][backend][device](...)

三个维度:

维度取值来源
model_type "transformer" / "value_head" / "lm_head"worker 构造时根据角色决定(actor → lm_head, critic → value_head)
backend "fsdp" / "megatron" / "torchtitan" / "veomni" / "mindspeed" / "automodel"YAML strategy: 字段
device "cuda" / "npu" / "rocm"auto_set_device(config) 在 main_ppo.py:46 自动判定

真实注册表(来自 workers/engine/__init__.py:14–65):

典型用途
FSDPEngine 纯 backbone(ref policy 用)
FSDPEngineWithLMHead 带 LM head(actor / rollout)
MegatronEngine backbone
MegatronEngineWithLMHead 带 LM head
MegatronEngineWithValueHead 带 value head(critic)
TorchTitanEngine PyTorch 官方 titan 路径(实验性)
VeOmniEngine VeRL-Omni 多模态后端
AutomodelEngine HF AutoModelForCausalLM 直跑(vexact / 调试)
MindspeedEngine 华为昇腾

6.9 EngineConfig 字段全景

每种 backend 的 YAML 都继承自共通的 EngineConfigworkers/config/engine.py:77)。下面这些字段不分后端都有,是调试时第一档要查的

字段含义
strategy 选 backend(fsdp / megatron / ...)
use_dynamic_bsz 按 token 预算自动调 micro batch size(变长序列必开)
max_token_len_per_gpu 训练时单卡 token 预算(一般 8192 / 16384)
micro_batch_size_per_gpu dynamic_bsz=False 时的固定 micro
infer_max_token_len_per_gpu 推理(log_prob / ref)时的 token 预算
infer_micro_batch_size_per_gpu 同上 micro batch
param_offload 参数 offload 到 CPU(hybrid engine sleep level=2 时配合)
optimizer_offload 优化器 offload
grad_offload 梯度 offload
forward_only ref / reward model 设 True,不建 optimizer,省一半显存
router_replay MoE 路由确定性,下节展开

6.10 MoE 的 Router Replay:R2 / R3

MoE 模型的训练和 rollout 之间有一个特别讨厌的不一致来源——router 输出。同一个 token 在训练侧路由到 expert A、rollout 侧路由到 expert B,importance ratio 就完全失真。verl 在 workers/config/engine.py 提供了 EngineRouterReplayConfig 字段管这个:

mode做什么代价
"disabled" 不管,训练和 rollout 各路由各的importance ratio 噪声大
"R2" 训练侧 replay rollout 的 router decision;training routing 强制和 rollout 对齐训练侧不能学到新的路由策略
"R3" 双向 replay:rollout 也用 training 的最新 router需要每步同步 router 权重;带通信开销

实战经验:

6.11 训练 → rollout 之间的 weight extraction

这是连接本章和 ch07 的核心点。每个 engine 必须实现 get_per_tensor_param()engine/base.py:150):

后端实现做的事
FSDP / FSDP2 对每个 sharded param 调 summon_full_params() 临时 all-gather;按 layer 分组 yield,yield 完立刻释放
Megatron 每个 PP stage 持有自己 layer 的权重;先 PP broadcast 全 stage 数据,再按 TP / DP 维度选择性发给 rollout
TorchTitan 类似 FSDP2 的 DTensor 路径
Automodel (vexact)HF 模型直接 state_dict(),对每个 tensor yield;最简单也最慢

对 LoRA 情形,peft_merge=True 时会先 merge adapter 到 base 再 yield;peft_merge=False 时分两条路 yield,base 一次性同步后只增量推 adapter(base_sync_done flag 控制)。这就是 LoRA RL 训练能比 full-finetune 快得多的关键——base 权重只需要在 step 0 同步一次。

6.12 切换后端的 YAML 长什么样

backend关键 YAML 片段
FSDP(默认) actor_rollout_ref.actor.strategy: fsdp
fsdp_config: { wrap_policy: ..., param_offload: false }
FSDP2 同上但 strategy: fsdp2,自动用 PyTorch 2.x 的 DTensor 路径
Megatron strategy: megatron
megatron: { tensor_model_parallel_size: 4, pipeline_model_parallel_size: 2, virtual_pp_size: 2 }
TorchTitan strategy: torchtitan(实验性,关注 examples/grpo_trainer/run_*_torchtitan.sh)
VeOmni strategy: veomni,配合 verl-omni 子项目
Mindspeed (NPU) strategy: mindspeed,硬件昇腾 NPU
Automodel (vexact)strategy: automodel,HF 直跑,调试用

换 backend 不需要改算法代码,YAML 一行字段就够。这是 verl 把 engine 抽象做对的回报。

6.13 这章你需要带走什么