Skip to content

Config:Hydra/OmegaConf 如何进入 trainer 和 worker

verl 的配置不是“运行参数列表”,而是算法、数据、worker 后端、rollout 引擎、checkpoint/weight sync 的连接层。很多训练行为不是在 Python 里硬编码,而是由 verl/trainer/config/ppo_trainer.yaml 的 defaults 和命令行 override 组合出来。

先验知识

读 config 前,需要知道:

  1. Hydra 会从一个主配置文件开始,根据 defaults 把多个 YAML 组合成一棵 OmegaConf DictConfig
  2. 命令行里的 a.b.c=value 会覆盖配置树里的同名字段。
  3. verl 同时使用两种配置形态:trainer 主循环里经常直接读 OmegaConf 字段,worker 初始化时又经常用 omega_conf_to_dataclass() 转成 dataclass。
  4. YAML 里的 _target_ 告诉 Hydra 或 omega_conf_to_dataclass() 这个配置应该实例化成哪个 Python 类。
  5. actor_rollout_ref 是一个组合命名空间,里面同时有 actor、rollout、reference、model 和 hybrid engine 相关配置。

本页原先不适合小白的地方

原说明列了常见字段,但缺少三条关键链路:

  • ppo_trainer.yaml 的 defaults 如何把 actor@actor_rollout_ref.actor 映射到实际字段。
  • config 如何进入 RayPPOTrainer,再进入 ActorRolloutRefWorkerTrainingWorker
  • YAML 字段如何对应 Python dataclass 字段,以及哪些字段仍在 trainer 中作为 DictConfig 直接读取。

入口:main_ppo.py

当前入口使用 Hydra:

python
@hydra.main(config_path="config", config_name="ppo_trainer", version_base=None)
def main(config):
    auto_set_device(config)
    config = migrate_legacy_reward_impl(config)
    run_ppo(config)

也就是说,默认配置来自:

text
verl/trainer/config/ppo_trainer.yaml

命令行示例:

bash
python -m verl.trainer.main_ppo \
  data.train_files=$HOME/data/gsm8k/train.parquet \
  actor_rollout_ref.model.path=Qwen/Qwen2.5-0.5B-Instruct \
  actor_rollout_ref.rollout.name=vllm \
  actor_rollout_ref.actor.ppo_micro_batch_size_per_gpu=4 \
  trainer.n_gpus_per_node=1

这些 override 会在 TaskRunner.run() 中被 OmegaConf.resolve(config) 解析,然后传给 RayPPOTrainer(config=...)

defaults 怎么映射到源码字段

ppo_trainer.yaml 的 defaults 是读配置的第一入口:

yaml
defaults:
  - model_engine: dp
  - actor@actor_rollout_ref.actor: ${model_engine}_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
  - reward@reward: reward
  - algorithm@algorithm.rollout_correction: rollout_correction
  - _self_

读法:

  • actor@actor_rollout_ref.actor: ${model_engine}_actor:从 trainer/config/actor/ 目录加载对应 YAML,并挂到 config.actor_rollout_ref.actor
  • 默认 model_engine: dp,所以 actor 默认来自 actor/dp_actor.yaml
  • dp_actor.yaml 又 defaults 到 actor.yaml,并补上 FSDP 相关字段。
  • critic@critic: ${model_engine}_critic 默认加载 critic/dp_critic.yaml
  • rollout@actor_rollout_ref.rollout: rollout 加载 rollout/rollout.yaml
  • model@actor_rollout_ref.model: hf_model 加载 HF 模型配置。

所以命令行里改 model_engine=megatron 会让 actor/ref/critic 默认换到 Megatron 系列配置,而不是只改一个字符串。

配置如何进入 trainer

TaskRunner.run() 做了这些事:

python
validate_config(config, use_reference_policy=..., use_critic=...)
tokenizer = hf_tokenizer(...)
train_dataset = create_rl_dataset(config.data.train_files, config.data, ...)
resource_pool_manager = ResourcePoolManager(...)
trainer = RayPPOTrainer(config=config, tokenizer=..., ...)
trainer.init_workers()
trainer.fit()

RayPPOTrainer.__init__() 保存整棵配置:

python
self.config = config
self.hybrid_engine = config.actor_rollout_ref.hybrid_engine
self.use_reference_policy = need_reference_policy(config)
self.use_rm = need_reward_model(config)
self.use_critic = need_critic(config)

所以 trainer 主循环读到的是完整的 OmegaConf DictConfig

配置如何进入 worker

init_workers() 把不同子树传给不同 worker:

python
actor_rollout_cls = RayClassWithInitArgs(
    cls=ActorRolloutRefWorker,
    config=self.config.actor_rollout_ref,
    distillation_config=self.config.get("distillation"),
    role=str(actor_role),
)

critic 路径会先转 dataclass,再包装成统一的 TrainingWorkerConfig

python
critic_cfg = omega_conf_to_dataclass(self.config.critic)
critic_cfg = TrainingWorkerConfig(
    model_type="value_model",
    model_config=orig_critic_cfg.model,
    engine_config=engine_config,
    optimizer_config=orig_critic_cfg.optim,
    checkpoint_config=orig_critic_cfg.checkpoint,
)

rollout checkpoint engine 也会转 dataclass:

python
checkpoint_engine_config = omega_conf_to_dataclass(
    self.config.actor_rollout_ref.rollout.checkpoint_engine
)

_target_ 和 dataclass

很多 YAML 都有 _target_

yaml
actor:
  _target_: verl.workers.config.ActorConfig

algorithm:
  _target_: verl.trainer.config.AlgoConfig

omega_conf_to_dataclass(config) 的规则:

  • 如果没传 dataclass_type,配置里必须有 _target_,然后用 hydra.utils.instantiate()
  • 如果传了 dataclass_type,会先 OmegaConf.structured(dataclass_type),再 merge 用户配置,最后 OmegaConf.to_object()

这些 dataclass 都继承 BaseConfig,所以既能像对象一样 cfg.field,也能像 dict 一样 cfg.get("field")。不过 BaseConfig 默认冻结已有字段,除非字段在 _mutable_fields 里。

常见字段和源码落点

配置字段源码落点作用
data.train_filesmain_ppo.py:create_rl_dataset()训练 parquet 路径
data.train_batch_sizedataloader、validate_config()每 step prompt 数
data.max_prompt_lengthdataset、rollout prompt lengthprompt padding/truncation 长度
data.max_response_lengthrollout response length生成最大长度
algorithm.adv_estimatorneed_critic()compute_advantage()决定 GAE/GRPO/RLOO 等路径
algorithm.use_kl_in_rewardneed_reference_policy()apply_kl_penalty()是否把 KL 从 reward 中扣掉
actor_rollout_ref.actor.ppo_mini_batch_size_update_actor()actor PPO mini-batch,trainer 会乘 rollout.n
actor_rollout_ref.actor.ppo_micro_batch_size_per_gpuworker engine config validation单卡 micro batch
actor_rollout_ref.actor.use_kl_lossneed_reference_policy()、actor loss是否在 actor loss 里加 KL
actor_rollout_ref.rollout.nameget_rollout_class()选择 vLLM/SGLang/TRTLLM/HF rollout
actor_rollout_ref.rollout.nfit().repeat()_update_actor()每 prompt 采样 response 数
actor_rollout_ref.rollout.checkpoint_engine.backendCheckpointEngineManager、worker update_weights()trainer 到 rollout 的权重同步后端
critic.enable / algorithm.adv_estimatorneed_critic()是否建 critic worker
reward.reward_model.enableneed_reward_model()RewardLoopManager是否使用模型 reward
trainer.balance_batch_balance_batch()是否按 token 工作量重排
trainer.save_freqfit()checkpoint 保存频率
trainer.test_freqfit() / _validate()validation 频率

batch size 名词

名称视角例子
data.train_batch_sizeprompt 数dataloader 每 step 取多少 prompt
actor_rollout_ref.rollout.n每 prompt response 数GRPO 常设为大于 1
有效 response 数train_batch_size * rollout.nactor/critic 实际看到的样本数
actor.ppo_mini_batch_sizePPO 更新 mini-batch_update_actor() 中会乘 rollout.n
actor.ppo_micro_batch_size_per_gpu单卡 micro batch控制显存峰值
rollout.max_num_batched_tokensrollout engine token 调度控制推理吞吐和显存

如果 train_batch_size=64rollout.n=8,一次 actor update 面对的是 512 条 response。读指标时也要按 response 数理解。

KL 放在哪里

verl 有两个常见 KL 位置:

  1. reward-side KL:algorithm.use_kl_in_reward=Trueapply_kl_penalty()token_level_rewards = token_level_scores - beta * KL
  2. actor loss KL:actor_rollout_ref.actor.use_kl_loss=True,actor loss 内部使用 reference logprob。

两者都可能需要 reference policy。validate_config() 会在两者同时开启时打印 NOTICE。

rollout 配置不要和训练后端混淆

训练后端主要由这些字段决定:

text
actor_rollout_ref.actor.strategy
critic.strategy
actor_rollout_ref.actor.fsdp_config / megatron / veomni / torchtitan

rollout 推理后端主要由这个字段决定:

text
actor_rollout_ref.rollout.name

例如你可以用 FSDP 训练 actor,同时用 vLLM 做 rollout。它们通过 checkpoint engine/weight sync 对接,不是同一个后端。

源码实现怎么读

建议这样读:

  1. ppo_trainer.yaml 的 defaults 开始,画出 actor_rollout_ref.actoractor_rollout_ref.rolloutcriticreward 四棵子树。
  2. 打开 actor/dp_actor.yaml,看它如何 defaults 到 actor.yamlengine/fsdp.yaml
  3. 打开 workers/config/actor.py,对照 ActorConfig 字段和 __post_init__() 校验。
  4. 打开 utils/config.py,看 validate_config() 如何检查 batch size、micro batch 和 reference/critic 条件。
  5. 回到 ray_trainer.py:init_workers(),看配置子树如何被传入 ActorRolloutRefWorkerTrainingWorker
  6. 最后回到 ray_trainer.py:fit(),搜索 self.config.,把字段和训练行为逐个连起来。

本节参考与延伸阅读

  • 源码:verl/trainer/main_ppo.py,重点读 @hydra.mainTaskRunner.run()validate_config()RayPPOTrainer(...)
  • 源码:verl/trainer/config/ppo_trainer.yamlalgorithm.pyconfig.pydata/legacy_data.yamlactor/critic/reward/rollout/engine/model_engine/
  • 源码:verl/base_config.pyverl/utils/config.py
  • 源码:verl/workers/config/actor.pycritic.pyrollout.pyreward.pyengine.py
  • 官方 docs:docs/examples/config.rstdocs/start/quickstart.rst
  • 外部资料:Hydra 官方文档、OmegaConf 官方文档、HybridFlow: A Flexible and Efficient RLHF Framework, arXiv:2409.19256。

面向源码阅读的 verl 学习文档。