算法:PPO / GRPO / RLOO / REINFORCE++ / DAPO
OpenRLHF 把所有"PPO 家族"算法统一收口到 train_ppo_ray 入口,通过
--algo.advantage_estimator 一个开关切换。本章把支持的 5 种算法的数学公式、
关键差异、何时选哪个讲清楚。
9.1算法谱系
| 算法 | advantage_estimator | 需要 Critic | n_samples | 核心思路 |
|---|---|---|---|---|
| PPO | gae | ✓ | 1 | 经典 actor-critic + clipped ratio |
| GRPO | group_norm | ✗ | 4-16 | 组内归一替代 critic |
| RLOO | rloo | ✗ | 2-8 | leave-one-out 平均 |
| REINFORCE++ | reinforce_plus_plus | ✗ | 1 | reward 标准化 + 一些工程改进 |
| REINFORCE++-baseline | reinforce_plus_plus_baseline | ✗ | ≥2 | 组均值当 baseline(ScaleRL 验证) |
| DAPO(变体) | 同 group_norm + 特殊 flag | ✗ | 16+ | 动态采样 + clip higher |
9.2共同的 policy loss
无论哪种算法,policy 更新公式都是 PPO clipped objective:
$$ \mathcal{L}_\text{policy} = -\mathbb{E}\!\left[\min\!\big(\rho_t \hat A_t,\;\mathrm{clip}(\rho_t,\,1-\epsilon,\,1+\epsilon)\hat A_t\big)\right] $$
差别只在 advantage $\hat A_t$ 怎么算。这就是为什么 OpenRLHF 能用一份代码支持所有算法——只是 advantage estimator 不同。
9.3PPO:经典 GAE
公式
$$ \hat A_t^\text{GAE} = \sum_{l=0}^{\infty} (\gamma\lambda)^l \delta_{t+l}, \quad \delta_t = r_t + \gamma V(s_{t+1}) - V(s_t) $$
这是 PPO 标配。需要 critic 给 $V$。
典型配置
--algo.advantage_estimator gae \
--algo.gamma 1.0 \
--algo.lam 0.95 \
--rollout.n_samples_per_prompt 1 \
--critic.model_name_or_path <RM 路径>
何时用
- 有训练好的 RM;
- 需要 token-level advantage(更精细的信用分配);
- 对收敛稳定性最敏感的场景。
9.4GRPO:组内归一
公式
同一 prompt 采样 $G$ 个 response $\{y_1, ..., y_G\}$,对每个的 reward $r_i$ 做组内归一:
$$ \hat A_i = \frac{r_i - \mathrm{mean}(\{r_j\})}{\mathrm{std}(\{r_j\})} $$
每个 response 内的所有 token 共享同一个 advantage(即 outcome-level)。
典型配置
--algo.advantage_estimator group_norm \
--rollout.n_samples_per_prompt 8 \
# 不需要 critic:
# 删掉 --critic.* 参数
何时用
- 有可验证 reward(数学、代码、规则);
- 显存不够跑 critic;
- 训推理模型(R1 / DeepSeek 风格)。
OpenRLHF 0.10 的 GRPO 增强
| flag | 含义 |
|---|---|
--algo.dynamic_filtering_enable | 组内 reward 全相同(全对或全错)时丢掉该组 |
--algo.dynamic_filtering_range 0.0 1.0 | 定义"全对/全错"阈值 |
--algo.advantage.is_correction_enable | importance sampling 修正(训推 mismatch) |
--algo.advantage.normalize_by_std | 是否除 std(关掉 = 只减均值) |
9.5RLOO:Leave-One-Out
公式
同一 prompt 的 $G$ 个 response,对每个 $i$,advantage = 自己的 reward 减其他 $G-1$ 个的平均:
$$ \hat A_i = r_i - \frac{1}{G-1}\sum_{j\neq i} r_j = \frac{G}{G-1}\big(r_i - \bar r\big) $$
和 GRPO 的差别:不除 std。
典型配置
--algo.advantage_estimator rloo \
--rollout.n_samples_per_prompt 4
何时用
- GRPO 训不稳(reward 分布不均匀让 std 噪声大);
- 论文复现:Cohere RLOO 论文用这个。
9.6REINFORCE++
OpenRLHF 自家提出的简化算法。原理:
$$ \hat A_t = r_\tau - \mu_\tau / \sigma_\tau $$
其中 $r_\tau$ 是带 KL 惩罚的整段 trajectory reward,$\mu_\tau, \sigma_\tau$ 是当前 batch 上的全局均值方差。 不需要 critic、不需要 leave-one-out。
典型配置
--algo.advantage_estimator reinforce_plus_plus \
--rollout.n_samples_per_prompt 1
何时用
- 显存最紧、训练数据巨大;
- 不需要 n_samples_per_prompt > 1,单条采样也能训;
- Magistral / 字节大模型用过类似方法。
9.7REINFORCE++-baseline(v0.10 新增)
ScaleRL 论文(2025/10)验证有效。原理:
$$ \hat A_i = r_i - \mathrm{mean}(\{r_j\}_{j=1}^G) $$
看着像 GRPO 不除 std。差别:
| GRPO | REINFORCE++-baseline | RLOO | |
|---|---|---|---|
| 减均值 | ✓ | ✓ | ✓(leave-one-out 形式) |
| 除 std | ✓ | ✗ | ✗ |
| leave-self-out | ✗ | ✗ | ✓ |
典型配置
--algo.advantage_estimator reinforce_plus_plus_baseline \
--rollout.n_samples_per_prompt 8
ProRL V2 / ScaleRL 经验
2026/2 NVIDIA ProRL V2 用 REINFORCE++-baseline + 长训练复现了 1.5B SOTA 推理模型。仓库有专用脚本:
bash examples/scripts/train_prorlv2_math_hybrid_engine.sh
9.8DAPO:动态采样 + clip higher
字节 DAPO 论文提出的 GRPO 改进,OpenRLHF 通过组合 flag 实现:
--algo.advantage_estimator group_norm \
--algo.dynamic_filtering_enable \ # 全对/全错的组丢掉
--algo.dynamic_filtering_range 0.0 1.0 \
--algo.clip_ratio_low 0.2 \ # ★ 非对称 clip
--algo.clip_ratio_high 0.28 \
--algo.token_level_loss \ # ★ token 级 loss(避免长 response 主导)
--rollout.n_samples_per_prompt 16
仓库有专用脚本:
bash examples/scripts/train_dapo_ray_hybrid_engine.sh
9.9KL 项的两种放法
| 放法 | 含义 | flag |
|---|---|---|
| KL → reward | $r_\text{total} = r - \beta_\text{KL} \cdot (\log\pi_\theta - \log\pi_\text{ref})$ | --algo.kl.in_reward(默认) |
| KL → loss | policy loss 里加额外 KL 正则 | --algo.kl.in_loss |
KL 系数控制
| flag | 含义 |
|---|---|
--algo.kl.init_coef | 初始系数(典型 0.001 - 0.01) |
--algo.kl.target | 目标 KL(开自适应) |
--algo.kl.horizon | 自适应控制器周期 |
--algo.kl.use_adaptive | 开自适应(推荐) |
自适应 KL:
$$ \beta_{t+1} = \beta_t \cdot \begin{cases} 1 + \alpha & \text{if } \mathrm{KL}_t > 2\,\text{target} \\ 1 - \alpha & \text{if } \mathrm{KL}_t < 0.5\,\text{target} \\ 1 & \text{otherwise} \end{cases} $$
OpenAI 经典做法,让 KL 维持在 target 附近。
9.10选哪个算法
| 场景 | 推荐 | 理由 |
|---|---|---|
| 有偏好数据 + RM 训好了 | PPO | 能用 token-level advantage |
| 可验证 reward(数学 / 代码) | GRPO / RLOO | 不用 critic,省显存 |
| R1 风格长思考链 | GRPO + DAPO | token-level loss + clip higher 稳定长 response |
| 1.5B 小模型推理 RL | REINFORCE++-baseline | ProRL V2 / ScaleRL 验证 |
| 显存极紧 | REINFORCE++ | n_samples=1 也能跑 |
| 偏好对齐(不是推理) | PPO 或 DPO | DPO 见下一节 |
9.11顺便讲:DPO(offline)
OpenRLHF 也支持 DPO 系,但走独立 CLI(不通过 train_ppo_ray):
python -m openrlhf.cli.train_dpo \
--pretrain <SFT 模型> \
--dataset <preference 数据> \
--apply_chat_template \
--max_len 4096 \
--train_batch_size 256 \
--micro_train_batch_size 4 \
--learning_rate 5e-7 \
--beta 0.1 \
--save_path ./dpo_output
# 其他变体
--ipo # IPO
--label_smoothing 0.1 # cDPO
DPO 是 offline 算法,不需要 vLLM rollout 和四个 Ray group,资源消耗只有 PPO 的 1/4。偏好对齐任务首选。
9.126 个 advantage estimator 完整对照
本章前面提了 PPO / GRPO / RLOO / REINFORCE++。实际仓库 --algo.advantage.estimator 接受 6 种值(openrlhf/trainer/ppo_utils/experience_maker.py:35)。这是切算法时的查表:
| estimator | baseline | 需要 critic | 典型用 |
|---|---|---|---|
"gae"(默认) | GAE: $\hat A_t = \sum_l (\gamma\lambda)^l \delta_{t+l}$ | ✅ | 经典 PPO |
"reinforce" | 纯收益 $\sum \gamma^t r_t$(无 baseline) | ❌ | 极简 REINFORCE |
"reinforce_baseline" | batch mean: $R - \mathrm{mean}(R)$ | ❌ | ★ REINFORCE++-baseline,推理任务首选 |
"rloo" | 留一法:$\tfrac{1}{n-1}\sum_{j\neq i} R_j$ | ❌ | 多样本 per-prompt 时 |
"group_norm" | GRPO group z-score:$\tfrac{R-\mu}{\sigma+\varepsilon}$ | ❌ | 组内归一 |
"dr_grpo" | Dr.GRPO:组内减均值不除 std | ❌ | 简化版 GRPO,避免 std 退化 |
选 estimator 的速决:
- 有可信 RM + 求稳:GAE(经典 PPO);
- 推理任务 + 规则 reward:reinforce_baseline(ProRL V2 / ScaleRL 都用这个);
- R1 风格 + 多样本:group_norm(GRPO);
- 显存极紧:reinforce 或 reinforce_baseline(无 critic 省 25%)。
9.13vLLM Importance Sampling 矫正三种
多样本 / 异步训练时 vLLM 采样的 logp 和训练侧重新算的 logp 不完全一致(quantization、kernel 差异),需要 IS 矫正。openrlhf/models/loss.py:188–210 的 PolicyLoss 提供三种:
| --algo.is.mode | 原理 | 什么时候用 |
|---|---|---|
"tis"(Token IS) | 对 token-level ratio 做 clamp(ratio, lo, hi) | 常规多样本 |
"icepop" | 把 ratio 偏离 1 太远的 token 系数置 0(filter outlier) | vLLM/training 数值差异大时 |
"seq-mask-tis" | 序列级 mask + token 级 TIS(混合) | 长 CoT,部分 token 失真 |
启用方式:--algo.advantage.is_correction_enable --algo.is.mode icepop。ProRL V2 默认走 icepop。
9.14DAPO 的两个独门改进
DAPO 不是新算法本体,而是"GRPO + 训练技巧组合"。看 train_dapo_ray_hybrid_engine.sh 能找到这两个关键 flag:
| flag | 含义 |
|---|---|
--actor.eps_clip_low_high 0.2 0.27 | 非对称 PPO clip:上界 0.27 大于下界 0.2,鼓励探索 |
--algo.dynamic_filtering_enable --algo.dynamic_filtering_range 0 1 | 过滤 group 内"全对/全错"无信号样本,省 RL step |
--actor.token_level_loss_enable | token 级 loss reduction(更适合长 CoT) |
--reward.stop_properly_penalty_coef 0.0 | 关掉"未停止"惩罚,让长 CoT 自由产生 |
这四个 flag 单独看都不大,但配合起来让 R1 风格训练长度涌现更稳定。
9.15这章你需要带走的
- OpenRLHF 5 种 RL 算法 + DPO 都收口在统一抽象下;
- 切算法 = 改一个 advantage_estimator flag;
- 有 critic = PPO;无 critic = GRPO / RLOO / REINFORCE++ 系;
- KL 默认进 reward,OpenAI 经典做法;KL 自适应控制器维持在 target;
- 可验证 reward 选 GRPO;偏好对齐选 DPO;最小显存选 REINFORCE++;
- DAPO = GRPO + 动态采样 + 非对称 clip + token 级 loss。