Chapter 08

配置系统:Hydra YAML

📌 本章源码引用基于 verl/trainer/config/ · commit 9c38b8bb1876 。Hydra 文档: hydra.cc 。

8.1 为什么 verl 用 Hydra

verl 一份训练 config 有几百个字段,分散在 actor / critic / rollout / data / algorithm 等 10+ 个子组件。Hydra 解决"把若干 YAML 文件按层级组合"的问题

8.2 配置目录长什么样

verl/trainer/config/
├── ppo_trainer.yaml          ← 顶层,组合所有子组件
├── _generated_ppo_trainer.yaml          ← Hydra 渲染后的扁平产物
├── _generated_ppo_megatron_trainer.yaml ← Megatron 后端的渲染产物
├── _generated_ppo_torchtitan_trainer.yaml
├── _generated_ppo_veomni_trainer.yaml
├── actor/                    ← actor 子组件,按后端分文件
│   ├── dp_actor.yaml         ← FSDP actor
│   ├── megatron_actor.yaml   ← Megatron actor
│   └── ...
├── critic/                   ← critic 子组件
├── data/                     ← 数据 pipeline 配置
│   └── legacy_data.yaml
├── algorithm/                ← 算法字段(GAE / GRPO / KL)
├── engine/                   ← 训练后端通用字段
├── distillation/             ← 蒸馏配置
├── evaluation.yaml           ← 评测配置
└── legacy_reward_impl.yaml   ← reward 配置

8.3 顶层 ppo_trainer.yaml 的 defaults 段

从源码 verl/trainer/config/ppo_trainer.yaml 摘出来:

defaults:

  - model_engine: dp                                              # 默认走 FSDP 风格
  - actor@actor_rollout_ref.actor: ${model_engine}_actor          # = dp_actor / megatron_actor
  - data@data: legacy_data
  - ref@actor_rollout_ref.ref: ${model_engine}_ref
  - rollout@actor_rollout_ref.rollout: rollout
  - model@actor_rollout_ref.model: hf_model
  - critic@critic: ${model_engine}_critic
  - model@critic.model: hf_model
  - legacy_reward_impl
  - reward@reward: reward
  - algorithm@algorithm.rollout_correction: rollout_correction
  - distillation@distillation: distillation
  - _self_

这段读法:

语法含义
- model_engine: dp 定义变量 model_engine 默认值 = "dp"
- actor@actor_rollout_ref.actor: ${model_engine}_actoractor/${model_engine}_actor.yaml 装载到 actor_rollout_ref.actor 这一层级
${model_engine} 变量插值;命令行改 model_engine 就会切到对应文件
- _self_ 当前 YAML 的字段覆盖前面所有 default

8.4 命令行 override 全套语法

语法含义
data.train_files=/path/to/train.parquet 设置字段
actor_rollout_ref.actor.optim.lr=1e-6 深层字段
+data.new_field=42 新增不存在的字段
~data.train_files 删除字段
trainer.logger=[wandb,tensorboard] 列表值
algorithm.adv_estimator=grpo 切换算法(见第 9 章)
model_engine=megatron 整组切换到 Megatron 后端

8.5 几个最常被改的字段速查

数据 & batch

字段含义
data.train_files 训练数据 parquet 路径
data.val_files 验证集
data.train_batch_size 每次 rollout 的 prompt 数
data.max_prompt_length prompt 截断长度
data.max_response_length response 生成长度上限
data.filter_overlong_prompts 过长 prompt 是否丢
data.truncation error / left / right

actor

字段含义
actor_rollout_ref.actor.optim.lr 学习率,PPO/GRPO 通常 1e-6 ~ 5e-7
actor_rollout_ref.actor.ppo_mini_batch_size 训练 actor 的 mini batch
actor_rollout_ref.actor.ppo_micro_batch_size_per_gpu单卡 micro batch
actor_rollout_ref.actor.ppo_epochs 每批 PPO 迭代轮数
actor_rollout_ref.actor.use_kl_loss 是否在 loss 里加 KL 项
actor_rollout_ref.actor.kl_loss_coef KL 系数
actor_rollout_ref.actor.entropy_coef 熵奖励系数
actor_rollout_ref.actor.clip_ratio PPO clip 阈值,默认 0.2

算法

字段含义
algorithm.adv_estimator gae / grpo / reinforce_plus_plus / dapo
algorithm.gamma 折扣因子
algorithm.lam GAE λ
algorithm.use_kl_in_reward 是否把 KL 加到 reward(vs 加到 loss)
algorithm.kl_penalty kl / abs / mse / low_var_kl / full
algorithm.norm_adv_by_std_in_grpoGRPO 是否用 std 归一

训练器

字段含义
trainer.project_name WandB / TB 项目名
trainer.experiment_name 实验名
trainer.total_epochs 总训练轮数
trainer.save_freq 多少 step 保存一次
trainer.test_freq 多少 step 跑一次验证
trainer.logger [wandb] / [tensorboard] / [console]
trainer.n_gpus_per_node 每节点 GPU 数
trainer.nnodes 节点数
trainer.default_local_dir checkpoint 保存目录

8.6 字段查不到怎么办

  1. _generated_ppo_trainer.yaml(Hydra 渲染产物)grep:所有"扁平"字段名都在这里;
  2. 找不到 → 在 verl/trainer/config/*/*.yaml 里 grep;
  3. 还是找不到 → 看 verl/trainer/config/config.py(dataclass 定义);
  4. 都没有 → 拼错了,Hydra 默认会 silently 忽略未知字段,要打开 strict 模式:
    HYDRA_FULL_ERROR=1 python -m verl.trainer.main_ppo ...

8.7 写自己的 YAML 而不是命令行长串

命令行越来越长时,把 override 抽成一份 my_config.yaml

# my_config.yaml
defaults:
  - ppo_trainer        # 继承 verl 默认
  - _self_

data:
  train_files: ${oc.env:HOME}/data/gsm8k/train.parquet
  val_files: ${oc.env:HOME}/data/gsm8k/test.parquet
  max_response_length: 4096

actor_rollout_ref:
  model:
    path: Qwen/Qwen3-4B
  actor:
    optim:
      lr: 1.0e-6
    ppo_mini_batch_size: 256
  rollout:
    n: 8
    temperature: 1.0

algorithm:
  adv_estimator: grpo

trainer:
  project_name: my_grpo
  experiment_name: qwen3_4b_gsm8k
  total_epochs: 10

启动:

python -m verl.trainer.main_ppo \
  --config-path . --config-name my_config

8.8 多机配置的 Hydra 风格

trainer.nnodes=2 \
trainer.n_gpus_per_node=8 \
+ray_init.address=10.0.0.1:6379          # ★ 加号表示新增字段

8.9 Hydra 调试技巧

命令用途
HYDRA_FULL_ERROR=1 python -m verl.trainer.main_ppo ...完整堆栈
python -m verl.trainer.main_ppo --help 看顶层选项
python -m verl.trainer.main_ppo --cfg job 打印最终生效的扁平 config(不会真跑训练)
python -m verl.trainer.main_ppo --info 看 Hydra 解析结果

--cfg job调试 Hydra 最有用的开关——所有 override 后的字段一目了然。

8.10 ppo_trainer.yaml 的 defaults 组合顺序

verl 的顶层 config 文件是 verl/trainer/config/ppo_trainer.yaml,开头那段 defaults:(line 8–47)就是 Hydra 的合成总账。读源码定位字段时这块必须先看:

# ppo_trainer.yaml 节选
defaults:
  - model_engine: dp                       # actor / critic / ref 默认走 dp(→ FSDP)
  - actor:        dp_actor                 # → trainer/config/actor/dp_actor.yaml
  - critic:       dp_critic                # → critic/dp_critic.yaml
  - ref:          dp_ref                   # → ref/dp_ref.yaml
  - rollout:      vllm                     # → rollout/vllm.yaml
  - reward_model: ~                        # 默认无神经 reward
  - distillation: ~                        # 默认无在线蒸馏
  - reward_correction: ~                   # 默认无 rollout correction
  - data:         default
  - trainer:      default
  - algorithm:    default
  - hydra:        default
  - _self_                                 # ★ 当前文件覆盖所有 defaults

两个值得知道的细节:

8.11 algorithm 段全字段

RL 算法的字段几乎全在 algorithm 这一组里。verl 把它落到 verl/trainer/config/algorithm.pyAlgoConfig dataclass,下表是最常碰的:

字段含义 / 取值
adv_estimator "gae" / "grpo" / "rloo" / "reinforce_plus_plus" / "remax" / "opo" / "gdpo" / "grpo_passk" / "gpg" / "rloo_vectorized" / "grpo_vectorized" / "optimal_token_baseline" / "tir_optimal_token_baseline"(详见 ch09)
gamma 折扣(GAE / R++)
lam GAE λ
use_kl_in_reward KL 加到 reward 上做 token-level shaping(默认 False)
kl_penalty "kl" / "abs" / "mse" / "low_var_kl" / "full"
kl_ctrl.type "fixed" / "adaptive"
kl_ctrl.kl_coef 固定时的 β
kl_ctrl.target_kl adaptive 时的目标 KL
norm_adv_by_std_in_grpoTrue = GRPO;False = Dr.GRPO(不除 std)
use_pf_ppo ICML25 Priority Filtering PPO
filter_groups DAPO 风格 group-level 过滤(去掉无信号 group)
rollout_correction off-policy IS / RS 矫正子段
gdpo_reward_keys GDPO 时各维度 reward 的 key 列表
gdpo_reward_weights 多维 reward 的聚合权重
transfer_queue 非 None 即启用 TransferQueue 异步数据通道

8.12 PolicyLossConfig:actor 段最难懂的字段

PPO loss 不是只有一种——actor.policy_loss 子段(来自 workers/config/actor.py:78PolicyLossConfig)选择具体公式:

policy_loss.mode背后函数典型场景
vanilla(默认) compute_policy_loss_vanilla() 经典 PPO clip,绝大多数情况
clip-cov compute_policy_loss_clip_cov() token 重要性加权 clip
kl-cov compute_policy_loss_kl_cov() KL 协方差正则
gspo compute_policy_loss_gspo() 序列级 IS × token-level ratio(2025-11)
sapo compute_policy_loss_sapo() sigmoid soft-clip(2025-11)
gpg compute_policy_loss_gpg() group policy gradient
cispo compute_policy_loss_cispo() clipped IS PPO(rollout IS 矫正)
geo_mean compute_policy_loss_geo_mean() 序列长度归一的几何均值,数值稳定
dppo_tv / dppo_klcompute_policy_loss_dppo_*()DPPO 双策略约束
bypass_mode compute_policy_loss_bypass_mode() off-policy 矫正路径(搭 rollout_correction)

所有函数都在 verl/trainer/ppo/core_algos.py,通过 POLICY_LOSS_REGISTRY + @register_policy_loss(name) 注册。ch09.10–9.12 会展开公式细节。

8.13 RolloutCorrectionConfig:off-policy 矫正预设

2025-11 加入的 rollout correction 是为了应对"rollout 完后训练阶段策略已经变了"的 off-policy 情况。配置在 algorithm.rollout_correction

字段含义
bypass_mode True = 用 rollout 的 logprob 当 old_logprob(2 策略);False = 重新算 old_logprob(3 策略)
rollout_is "token" / "sequence" —— 重要性采样粒度
rollout_rs "token_k1/k2/k3" / "seq_*_k1/k2/k3" —— 拒绝采样阈值

仓库给了几个开箱预设(函数式调用而非 YAML 一行字段):

预设组合
decoupled_token_is() 3-策略 + token-IS
decoupled_seq_is() 3-策略 + sequence-IS
bypass_ppo_clip_geo_rs() 2-策略 + PPO clip + 几何 RS

不熟时先用 bypass_mode=False 跑同步路径(默认),等观察到 IS ratio 显著偏离 1 再开矫正

8.14 EngineConfig / EngineRouterReplayConfig 速览

这两组字段在 ch06 已经讲过实现——这里给 YAML 写法快查:

actor_rollout_ref:
  actor:
    strategy: fsdp                # or megatron / torchtitan / veomni / automodel / mindspeed
    use_dynamic_bsz: true
    max_token_len_per_gpu: 16384
    infer_max_token_len_per_gpu: 16384
    param_offload: false
    optimizer_offload: false
    grad_offload: false
    router_replay:
      mode: "R2"                  # disabled / R2 / R3(MoE 用)

8.15 这章你需要带走什么