Skip to main content
字节 verl 作为一等运行时,catalog 版本 0.9.0。方法有:verl/grpodapopporlooreinforce-baselineremaxdistillationsft 和 NeMo-RL 不同,verl 提交时需要 --model--train-data。可观测性是 platform
verl 镜像是部署侧的产物(FORGE_IMAGE_VERLFORGE_RUNTIME_REGISTRY_FILE)。 管理员先发布它,别人才提交得了;没有它时提交失败,错误会点名缺的是运行时,而不是方法。

创建时写明版本

0.9 用统一的 verl.trainer.main_ppo(sync V1);0.8 的 main_ppo_sync 已被上游移除,catalog 不再保留旧运行时。 如果存在 experiments/my-verl/main.py,就用这个文件当入口(verl-recipe 风格:子类化 TaskRunner / RayPPOTrainer)。只改奖励可以继续用配置里的 custom_reward_function.path

模型和数据在提交时必填

和 NeMo-RL 不同,verl 绑定要显式路径。recipe 映射:
平台数据集:
优先写在配置的 data.train.dataset;CLI 只是覆盖。数据集 缺了必填的模型/数据声明,sf validate 会在本地失败。

RL 方法怎么选

这里的 RL 方法跑的都是同一个 verl.trainer.main_ppo;recipe 只钉死一件事——algorithm.adv_estimator,而它就是方法本身。 config.yaml 里写 algorithm.adv_estimator 会在提交时被拒:它是方法的身份,不是旋钮。要换 estimator 就换方法。 loss 变体(GSPO、CISPO、GMPO、clip-cov / kl-cov、GPG)才是旋钮——在上面任一 recipe 上设 policy_loss_mode

DAPO

verl/dapo 是配置,不是自带的 trainer:0.9 的主干 main_ppo 已经包含论文里的四件套,所以 recipe 只钉死 algorithm.filter_groups.enabledapo reward manager,论文取值作为参数默认值下发(裁剪 0.2/0.28、 token-mean、4096 token 超长软区、惩罚系数 1.0、每题 16 条、两条路径的 KL 全关)。 提交前有两件事要知道:
  • 动态采样是在 rollout 阶段filter_metric 判定一组的,所以那时奖励必须已经算出来:要么用规则奖励函数, 要么让奖励模型独占一个资源池。共卡的奖励模型是在采样之后才打分的,上游会直接 assert。
  • 每步耗时天然是波动的——合格的组不够就继续补采。想要「DAPO 去掉动态采样」那一档,用 verl/grpoclip_ratio_high=0.28loss_agg_mode=token-mean

rollout 校正(TIS / IcePop)

即使权重完全一致,rollout 引擎(vLLM,bf16)和训练器(FSDP,fp32)也不是同一个策略;rollout 变旧或被补采 会把这个差距进一步拉大。每个 verl RL 方法都暴露了校正开关:
rollout_calculate_log_probs 不是可选项:没有 rollout 侧自己的 log-prob,就没有可比对的行为策略;平台会在编译期 直接拒绝这种组合,而不是让它悄悄不生效。rollout_is 不设时只出 mismatch 指标、不做校正——新环境上先这么跑一轮 是合理的第一步。

On-policy 蒸馏要两个资源池

verl/distillation 的教师推理服务跑在自己的 Ray placement group 里,是叠加在训练池之上申请的。 所以作业要声明两个资源池,并把 teacher 角色映射到第二个:
平台用学生池填 trainer.nnodes,用教师池填 distillation.nnodes。只给一个池的提交会在编译期被拒, 而不是挂在等资源上。多池作业只支持 kuberay 与 slurm 后端。

拓扑

adapter 用 FORGE_CLUSTER_*trainer.nnodes / trainer.n_gpus_per_node(有教师池时用主池的形状)。

导出 / 评测

SFT 的 sf eval 可以把验证样本挂回训练 run(带 --run-id)。见流水线