首先我们先跑个它官方给的math 数据集:

https://verl.readthedocs.io/en/latest/start/quickstart.html

RL 背景知识

组成

Actor 是“大脑”,告诉 agent 怎么行动。(模型)
Rollout 是“实地采样”,让 actor 去环境里试一试。(一个数据生成过程)
Critic 是“参谋”,告诉 actor 这个状态/动作好不好。(价值估计)

组件 作用 典型任务
Actor (策略网络) 负责生成动作(在文本生成里就是生成下一 token 的策略) 训练 PPO 时更新策略梯度
Rollout (采样器 / 推理引擎) 使用 actor 模型生成训练样本(状态-动作-奖励序列) 产生训练数据,用于计算 advantage
Critic (值函数网络) 评估当前状态的价值 V(s) 用来计算优势函数 A(s,a) = R - V(s) → actor 更新用

符号定义

符号 解释
s_t state(状态),表示在时间步 t 下环境/模型的观测信息
a_t action(动作),表示 agent 在 s_t 下做出的选择

state (s_t)

表示 当前生成的上下文

对应的就是 prompt + 已生成的 tokens

每生成一个 token,state 就更新一次(下一个 token 的上下文加上前面的 tokens)

换句话说:state 是你模型看到的“写到哪了”的信息。

action (a_t)

表示 模型生成的下一个 token

所以每步 a_t 是一个离散动作(词表里的 token)

log_prob(a_t) 会被用在 PPO 的 loss 里

e.g 

t s_t a_t
0 "2 + 3 = " "5"
1 "2 + 3 = 5" 结束 token

名称 作用
reward Actor生成序列后得到的标量评分(已知)
return_t 从 s_t 开始实际得到的累计 reward(由 reward + γ 计算)
V(s_t) Critic 对 return_t 的预测
A_t return_t 与 V(s_t) 的差值,用于指导 Actor 更新

Actor

最终保存、拿去推理 / 部署 / vLLM 用的 checkpoint

目标:生成的 token 能拿高 reward

head:语言模型 head

输出:

1. rollout序列:token, log_prob
2. reward:来自reward model / rule / environment)

loss:PPO policy loss + KL

Rollout

s_0, a_0, log_prob(a_0), s_1, a_1, log_prob(a_1), ..., s_T, a_T, log_prob(a_T)

符号 含义
s_t 当前状态 = prompt + 已生成的 tokens
a_t 当前动作 = 生成的下一个 token
log_prob(a_t) 模型生成 a_t 的概率对数,用于 PPO loss

e.g 

s_0 = "2 + 3 = "
a_0 = "5"
log_prob(a_0) = -0.2

s_1 = "2 + 3 = 5"
a_1 = <end>
log_prob(a_1) = -0.1
 

Reward 函数

reward 函数的输出,是一个「标量分数」,用来评价“这一次完整生成好不好”

注意, reward 不是 per-token 的, 而是一条完整序列 → 一个标量

(prompt, response) → r ∈ ℝ

input: prompt + actor output

output: scalar reward

同时, reward函数的设计并非二元的, 每条生成可以先对每个指标给一个分数(比如 0/1 或 0~1 连续值),然后汇总成一个 最终 scalar reward, 比如reward = w1 * correctness + w2 * format + w3 * fluency

经过计算, 得到Return_t

从 s_t 开始,实际获得的未来 reward(由 reward function 给出)

Critic

训练时的“教练”,训练完基本可以丢掉

目标:预测从当前状态开始,未来能得到的 reward 总和(value function)

  • head:value head(通常是 1 维)

  • input:  状态state s_t (或 state+action)

  • 输出:V(s_t) = value_head(backbone(s_t)) ≈ E[future reward]  从这个状态开始,未来能够得到的总 reward 。 得到V(s_0), V(s_1), V(s_2), …, V(s_T)

  • loss:value regression loss: (V(s_t) - return_t)^2

计算步骤

1. 编码 state
把 s_t (prompt + 已生成 tokens)编码成向量
LLM backbone 可以是 Transformer,输出每个 token 的 hidden state

2. 取最后一个 token 的 hidden state
这是当前上下文的 summary
也可以做 pooling 或者 attention

hidden state:  每个 token 的 hidden state都包含它左边所有 token 的信息(因为是 causal attention), 最后一个 token 的 hidden state包含了整个生成序列的上下文,是对整个生成序列的“压缩总结”,可以用来预测未来 reward。

3. value head
一个小的线性层,把 hidden vector → scalar
输出 V(s_t)
这个 scalar 就是 critic 预测的“从 s_t 开始未来能得到的 reward 的期望”

*reward 是已经算好的监督信号;critic 只是拿 reward 当 label,学一个 value function。

Advantage 函数

定义:衡量某个动作 a_t 相比“平均水平”(V(s_t))好多少

用来更新 Actor 策略

训练流程

一次 PPO update,用的是「一整批 rollout 数据」

Rollout 生成数据 + 计算 Reward
Rollout 用 actor 生成一批序列(状态、动作、log_prob)。
Reward 计算
   - task reward / rule / voting
   - KL penalty(actor vs ref)

Critic计算价值
Critic 估计每个状态的价值 V(s)。
然后计算优势函数 A(s,a) = R + γ V(s') - V(s)。

Actor (策略网络) 更新
使用 PPO objective(剪切概率比)用 Advantage 更新更新策略。
使用 mini-batch + micro-batch 分布式梯度累积。

Critic更新
使用 value loss 更新 critic。
也可以用 mini-batch/micro-batch 控制显存。

{
  prompt:       "请解释 PPO 是什么",
  response:     "PPO 是一种……",
  tokens:       [101, 2345, ...],
  logprobs:     [-1.2, -0.8, ...],   # actor 当时的概率
  values:       [0.3, 0.4, ...],     # critic 的估计
  reward:       0.76,                # 外部/内部打分
  advantages:   ...                  # 算出来的
}

batch理解***

带点数值进去理解吧

train_batch_size= 256(最顶层)  “每一轮 PPO 训练”用到的 rollout 数据总量

Actor rollout 一次,一共收集 256 条样本

每条样本 = prompt + response + reward + log_prob + value

这一步是 数据收集阶段,还没开始更新参数

actor.ppo_mini_batch_size = 128(PPO 优化层)

256 条 rollout 数据
→ 拆成 train_batch_size/actor.ppo_mini_batch_size (256/128=2)个 PPO mini-batch
→ 每个 mini-batch 更新一次 actor / critic

actor.ppo_micro_batch_size_per_gpu = 16

每张 GPU 实际一次 forward/backward 吃的数据量

e.g

GPU 数 = 8

单个 mini-batch = 128
每 GPU micro-batch = 16

一次 forward/backward:16 × 8 = 128(正好 1 次完成 1 个 mini-batch)

critic.ppo_micro_batch_size_per_gpu = 4

critic 为啥更小?

critic 需要forward value, backward value loss, 常常比 actor 更容易 OOM(尤其是大模型)

GPU 数 = 8

单个 mini-batch = 128
每 GPU micro-batch = 4

一次 forward/backward:4 × 8 = 32 ( 4 次梯度累积才完成 1 个 mini-batch)

Data Process

这里它有个把json 转化成parquet 的过程

.parquet 是列式存储的二进制数据格式,专门为「大规模、高吞吐训练」设计的;
json 更像是“人能看”的格式,不是“GPU 能高效吃”的格式。

prompt            | response           | reward | length
--------------------------------------------------------
"hi"              | "hello"            | 0.9    | 5
"tell me a joke"  | "..."              | 0.2    | 32
 

verl 的数据特点

通常包含:

  • prompt

  • response / completion

  • reward / advantage

  • logprob / ref_logprob

  • length / mask

  • rollout metadata

环境配置

之前因为requirements.txt 和版本不匹配折腾半天

总之 v0.4 的时候是 vllm 0.84, 后边都换新的vllm 框架了

训练参数

官方文档: 

https://verl.readthedocs.io/en/latest/examples/config.html

defaults

  - actor@actor_rollout_ref.actor: dp_actor
  - data@data: legacy_data
  - reward_manager@reward_manager
  - ref@actor_rollout_ref.ref: dp_ref
  - rollout@actor_rollout_ref.rollout: rollout
  - model@actor_rollout_ref.model: hf_model
  - critic@critic: dp_critic
  - reward_model@reward_model: dp_reward_loop
  - algorithm@algorithm.rollout_correction: rollout_correction
  - _self_

  • 作用:指定各个组件的默认配置文件(YAML 或者 dataclass)。

  • 示例

    • actor_rollout_ref.actor → actor 模型的具体配置。

    • data → 数据集相关配置。

    • _self_ → 当前 YAML 的字段会覆盖以上 defaults。

custom_reward_function

  • path:自定义奖励函数的 Python 文件路径,如果为空则使用内置奖励。

  • name:自定义奖励函数的函数名,默认 compute_score

actor_rollout

策略网络,负责 PPO 的策略梯度更新

actor_rollout_ref.model.path     
指定 actor 模型的权重初始化路径。

actor_rollout_ref.actor.optim.lr   
Actor 的学习率

actor_rollout_ref.actor.ppo_mini_batch_size   
PPO 的 mini-batch 大小
Rollout 收集数据 → 一个 batch(比如 256 条经验)
划分 mini-batch → 128 条/mini-batch
每个 mini-batch 更新 actor
影响:mini-batch 越小,更新越频繁但噪声大;越大,更新稳定但显存压力大。

actor_rollout_ref.actor.ppo_micro_batch_size_per_gpu
分布式训练时,每个 GPU 上的小 batch。
如果你有 8 张 GPU,且 mini-batch=128
每个 GPU micro-batch=16
那么每轮更新会拆成 128 / 16 = 8 步 GPU 梯度累积

actor_rollout_ref.rollout.tensor_model_parallel_size=1
 并行大小。

critic.model.path=$MODEL_PATH
critic 的初始化权重路径。

critic.ppo_micro_batch_size_per_gpu=4 
critic 的微 batch 大小。

algorithm

  • gamma:折扣因子 γ,越小未来奖励越不重要(PPO标准)。

  • lam:GAE(广义优势估计)参数 λ,调节 bias/variance 平衡。

  • adv_estimator:优势估计方法,gae 最常用。

  • norm_adv_by_std_in_grpo:GRPO 时是否用标准差归一化优势。

  • use_kl_in_reward:是否将 KL 罚项加入奖励。

  • kl_penalty:KL估计方法,可选 kl/abs/mse

  • kl_ctrl

    • type:KL控制类型(固定或自适应)。

    • kl_coef:KL罚系数。

    • horizon / target_kl:自适应KL控制用。

  • use_pf_ppo:是否启用 Preference Feedback PPO(用人工偏好训练)。

  • pf_ppo.reweight_method:样本加权方法。

  • pf_ppo.weight_pow:pow 方法的指数。

trainer

  • balance_batch:分布式训练时是否平衡 batch。

  • total_epochs:训练轮数。

  • total_training_steps:训练总步数,可覆盖 epoch。

  • project_name / experiment_name:用于日志追踪(WandB)。

  • logger:日志后端。

  • log_val_generations:验证时记录多少生成样本。

  • rollout_data_dir / validation_data_dir:保存数据路径。

  • nnodes / n_gpus_per_node:分布式训练节点和GPU数量。

  • save_freq:模型 checkpoint 保存频率。

  • esi_redundant_time:弹性训练实例(Elastic Server Instance)冗余时间。

  • resume_mode:自动恢复训练模式。

  • val_before_train / val_only:训练前验证或仅验证。

  • test_freq:验证频率。

  • critic_warmup:先训练多少步 critic 再更新 actor。

  • device:训练设备。

Wandb 指标

Actor(策略)

actor/ppo_kl

  • 是什么:新策略 π_new 和旧策略 π_old 的 KL 距离(PPO 用它来防止策略一步走太远)。

  • 怎么看

    • 太大:更新太猛,容易崩/性能抖动。

    • 太小/接近 0:基本没学到(策略几乎没变化),常见原因:LR 太小、adv 太小、奖励太弱/全 0、clip 太严、或者梯度被截掉了。

actor/pg_loss

  • 是什么:policy gradient 的损失(通常是要最小化 -E[adv * logπ] 的某种形式)。

  • 怎么看

    • 它的绝对值没那么重要,更重要是:有没有稳定趋势、是否和 reward 同向变化。

    • 大幅来回跳:优势估计噪声大、batch 太小、奖励稀疏、学习率/clip 不合适。

  • 你图里:有明显抖动,后期变正且偏大 → 可能优势分布/奖励尺度不稳定。

actor/pg_clipfrac

  • 是什么:PPO clipping 触发比例(有多少样本的 ratio 被 clip 到区间边界)。

  • 怎么看(经验)

    • 0 附近长期不动:几乎没发生有效 PPO 更新(ratio 都在 1 附近)→ 更新太小。

    • 很高(比如 0.3~0.8):更新太猛(ratio 经常越界)→ 可能不稳。

    • 很多项目里比较舒服的区间:大概 0.05~0.3 左右(因任务而异)。

  • 你图里1e-4 级别,基本≈0 → 几乎没 clip,说明策略几乎没变化(这和你 KL 很小是同一个信号)。

actor/pg_clipfrac_lower

  • 是什么:通常指被 clip 到下界(ratio < 1-ε)的比例(不同实现命名略有差异)。

  • 你图里:全程一条直线 0。

  • 常见原因

    1. 真的没有 ratio 掉到下界(但你 pg_clipfrac 也几乎 0,所以也合理)

    2. 或者日志没接好/这个项没启用(更少见)

  • 结论:和 pg_clipfrac≈0 一致:策略更新太小

actor/lr

  • 是什么:当前学习率。

  • 你图里1e-6 级别的常数。

  • 这非常关键:对 PPO 来说,这个 LR 往往偏小(除非你是超大模型+LoRA 还特别保守)。
    如果你用的是 LoRA / 小 batch / reward 很稀疏,1e-6 常常会导致:KL 小、clipfrac≈0、reward 不动。

actor/grad_norm

  • 是什么:actor 梯度范数。

  • 你图里:0.44~0.57 左右,挺正常,不像梯度爆炸/全 0。

  • 解释:梯度“有”,但更新“没效果”往往是 LR 太小 或者 adv/reward 太弱被强 clip/强正则限制

Critic(价值网络)

critic/vf_loss

  • 是什么:value function 回归损失(预测 V(s) vs 目标回报/GAE return)。

  • 怎么看

    • 一般训练中会下降并趋于平稳。

  • 你图里:从 ~1 降到接近 0.05 左右 → critic 在拟合(至少 loss 在降)。

critic/vf_explained_var

  • 是什么:解释方差(explained variance),衡量 V 预测对回报的解释能力。

    • 常见定义:1 - Var(y - y_pred)/Var(y)

    • 理想:接近 1

    • 还行:0~0.5

    • 很差:负数(代表“还不如直接预测均值”)

  • 你图里:非常夸张的负数(-200k 这种量级)并缓慢上升但仍很负。

  • 这几乎一定是“尺度/归一化/目标有问题”信号,常见原因:

    1. returns 的方差极小(分母 Var(y)≈0,导致数值炸裂)

    2. reward 几乎全一样/全 0(例如你 eval reward mean@1 是 0)

    3. value 目标的计算/记录口径不对(比如把 token-level / sequence-level 搞混)

  • 结论:你现在的 critic 指标看起来“不健康”,这会直接让 advantage 质量很差,从而让 actor 学不动。

critic/vpred_mean

  • 是什么:critic 预测的 V 的均值。

  • 你图里:在 -0.2 到 0.2 来回。

  • 单独看意义不大,但配合 values/min 能看出 value 分布是否漂移。

critic/values/mincritic/values/mean

  • 是什么:value 输出(或目标 value/return,取决于记录)在 batch 里的最小值/均值。

  • 你图里:min 从大约 -6 往 -1 走(越来越不负),mean 在 -0.2~0.2 摇摆。

  • 可能解释:回报尺度可能在变、或者 value 在被拉回(但 explained_var 极负说明“拟合关系”仍不对)。

critic/vf_clipfrac

  • 是什么:value clipping 触发比例(PPO 有时也会 clip value 更新)。

  • 你图里:除了一次尖峰(~0.085),其余几乎 0。

  • 说明:value 更新也比较“温柔”,不太像爆掉。

Val

就是验证结果啦,可以看到正在长高就是正常的

更多推荐