部署校正

作者: Yingru Li

最后更新时间:10/30/2025。


📖 文档结构

  • 本文档 - 实用使用指南:配置、预设、故障排除

  • 数学公式 - 理论基础、推导和算法细节

开始这里了解实现,请参考数学文档了解理论和设计原理。


本文档提供了对 verl 中部署校正实现的全貌概述。

命名说明:这个功能称为“部署校正”,以反映完整的功能性:重要性采样(IS)权重、拒绝采样(RS)和否决机制。内部变量 rollout_is_weights 保留其名称,因为它专门指 IS 权重组件。

BibTeX 引用

@misc{liu-li-2025,
  title = {When Speed Kills Stability: Demystifying RL Collapse from the Training-Inference Mismatch},
  url = {https://yingru.notion.site/When-Speed-Kills-Stability-Demystifying-RL-Collapse-from-the-Training-Inference-Mismatch-271211a558b7808d8b12d403fd15edda},
  author = {Jiacai Liu and Yingru Li and Yuqian Fu and Jiawei Wang and Qian Liu and Yu Shen},
  year = {2025},
  month = sep,
}

概述

部署校正提供了一个统一的框架来处理 RL 训练中的一般离线策略问题。任何数据收集分布与训练分布不同的场景都可以从这些方法中受益。

常见离线策略场景:

  1. 策略不匹配(实现差异)

    • 不同的精度:FP8 vs FP16 vs BF16 vs FP32

    • 不同的后端:vLLM vs SGLang vs FSDP vs Megatron

    • 即使权重相同,不同的实现

  2. 时滞(模型陈旧)

    • 部署时使用较旧的检查点,而训练已进展

    • 异步部署工作进程,具有陈旧参数

    • 分布式/异步 RL 系统中的常见问题

  3. 回放缓冲区

    • 在早期迭代的历史轨迹上训练

    • 来自不同策略版本的经验回放

    • 数据增强或重采样策略

  4. 离线策略算法

    • 专家演示的行为克隆

    • DAPO(来自辅助策略的数据)

    • 使用来自不同策略轨迹的任何算法

  5. 数据质量过滤

    • 对收集数据进行重新加权或过滤

    • 参考学习中修改的分布

    • 具有分布转移的课程学习

这些离线策略差距可能导致训练不稳定和策略崩溃。部署校正使用重要性采样(IS)权重和拒绝采样(RS)来校正数据收集和训练之间的任何分布转移。

重要说明:常见实现错误

许多 LLM-RL 实现错误地应用 PPO,忽略实际部署策略 π_rollout 并假设训练参考策略 π_old 是行为策略。这在 π_rollout ≠ π_old 时在数学上是错误的(这在 LLM-RL 中由于部署和训练之间的精度/后端差异而典型)。

这不是 PPO 的错 - PPO 本身在数学上是正确的。问题在于错误假设 π_old = π_rollout 在天真的实现中。

这份文档中引入的部署校正框架,正是为了解决这种关键实现错误。这种错误导致 RL 训练崩溃,被博客文章 “When Speed Kills Stability: Demystifying RL Collapse from the Training-Inference Mismatch” 识别并激发其开发。

数学上正确的方法:

  • 解耦模式:三个策略(π_rollout, π_old, π_θ),IS 从 π_rollout 到 π_old 校正

  • 旁路模式:两个策略(π_rollout = π_old, π_θ),使用实际部署策略作为 PPO 锚点

  • 旁路 + 策略梯度模式:两个策略(π_rollout, π_θ),IS/RS 校正和无 PPO 裁剪

详见数学公式部分。

关键设计原则:IS 权重和拒绝采样的分离

实现干净地分离了两个正交机制:

  1. IS 权重rollout_is_weights):用于梯度校正的连续重新加权

    • 策略比率:解耦模式下的 π_old/π_rollout 或旁路模式下的 π_θ/π_rollout

    • 安全绑定:截断到 [exp(-20), exp(20)] ≈ [2e-9, 5e8] 以防止溢出

      • 令牌级别:绑定每令牌比率

      • 序列级别:绑定比率乘积(广播到所有令牌)

    • 截断:通过 .clamp(max=rollout_is_threshold) 上限截断(TIS:截断重要性采样)

    • 在填充处置零:乘以 response_mask 以在填充位置置零

    • 用于加权策略梯度(方差降低)

  2. 拒绝采样modified_response_mask):二进制过滤用于异常排除

    • 创建二进制掩码:1 = 保留,0 = 拒绝

    • 拒绝 IS 比率在 [lower_threshold, upper_threshold] 之外的令牌/序列

    • 否决机制:独立拒绝包含灾难性令牌的序列

    • 修改 response_mask 以从训练中排除被拒绝样本

    • 用于损失聚合(被拒绝样本不贡献梯度或分母)

这种分离确保:

  • ✅ IS 权重提供连续重新加权(降低方差)

  • ✅ 拒绝采样提供硬过滤(移除极端异常值)

  • ✅ 两个机制可以独立启用或一起使用

  • ✅ 正确损失归一化(被拒绝样本从所有计算中排除)

  • ✅ 安全绑定防止所有情况下的数值溢出

快速开始:使用验证预设

新增:我们现在提供了类型化配置与验证预设,用于常见场景。这些预设已在各种模型和训练场景中经过数万 GPU 小时验证。

Python API

from verl.trainer.config.algorithm import RolloutCorrectionConfig

# 解耦模式与令牌级别 IS
config = RolloutCorrectionConfig.decoupled_token_is()

# 解耦模式与序列级别 IS
config = RolloutCorrectionConfig.decoupled_seq_is()

# 解耦模式与序列 IS + 拒绝采样
config = RolloutCorrectionConfig.decoupled_seq_is_rs()

# 解耦模式与几何 RS + 否决(最大异常敏感度)
config = RolloutCorrectionConfig.decoupled_geo_rs()

# 性能模式:PPO 与旁路
config = RolloutCorrectionConfig.ppo_is_bypass()

# 高级:纯策略梯度与 IS
config = RolloutCorrectionConfig.pg_is()

# 高级:纯策略梯度与拒绝采样(旁路 + 纯 + 几何 RS)
config = RolloutCorrectionConfig.pg_rs()

# 指标仅模式(无校正)
config = RolloutCorrectionConfig.disabled()

YAML 配置(高级)

对于高级定制或 YAML 基础配置:

algorithm:
  rollout_correction:
    rollout_is: token                      # IS 权重:"token", "sequence", 或 null
    rollout_is_threshold: 2.0              # IS 权重上阈值
    rollout_is_batch_normalize: false      # 批量归一化 IS 权重到 mean=1.0
    rollout_rs: null                       # 拒绝采样:"token", "sequence", "geometric", 或 null
    rollout_rs_threshold: null             # RS 上阈值(如果启用 rollout_rs 则必需)
    rollout_rs_threshold_lower: null       # RS 下阈值(如果为 null 则自动取倒数)
    rollout_token_veto_threshold: null     # 每令牌否决阈值(null = 禁用)
    bypass_mode: false  # 跳过 old_log_prob 计算
    use_policy_gradient: false     # 使用策略梯度损失(vs PPO 损失)

# 必需:启用 log prob 计算
actor_rollout_ref:
  rollout:
    calculate_log_probs: true

文件

核心实现

  • verl/trainer/ppo/rollout_corr_helper.py - 包含 compute_rollout_correction_and_rejection_mask()compute_offpolicy_metrics()

  • verl/trainer/ppo/core_algos.py - 部署校正与 PPO 和纯 IS 模式的集成(compute_policy_loss_with_rollout_correction()

  • verl/trainer/ppo/ray_trainer.py - 旁路模式实现(跳过 old_log_prob 计算)

  • verl/workers/actor/dp_actor.py - 模式选择逻辑和指标收集

配置文件

  • verl/trainer/config/algorithm.py - AlgoConfig 中的部署校正参数

  • verl/workers/config/actor.py - ActorConfig 中的部署校正参数

  • verl/trainer/config/actor/actor.yaml - 部署校正配置节

  • verl/trainer/config/ppo_trainer.yaml - 带有部署校正的算法配置

文档

  • docs/examples/config.rst - 配置参数描述

示例脚本

  • recipe/dapo/run_dapo_qwen2.5_32b_rollout_corr.sh - 带有部署校正的 DAPO 示例

  • examples/rollout_correction/run_with_rollout_corr.sh - 基本示例

测试

  • tests/trainer/ppo/test_rollout_corr.py - IS/RS 机制的单元测试

  • tests/trainer/ppo/test_rollout_corr_integration.py - 集成测试

配置参数

所有参数位于 algorithm.rollout_correction 下:

rollout_is (str 或 null)

重要性采样权重聚合级别:

  • null = 不计算 IS 权重(指标仅模式)

  • "token":每令牌 IS 权重

    • 解耦模式:ρ_t = π_old(t)/π_rollout(t)

    • 旁路/纯 IS 模式:ρ_t = π_θ(t)/π_rollout(t)

    • 每令牌独立截断

    • 典型阈值:1.5 - 5.0

  • "sequence":每序列权重 ρ_seq = ∏_t ρ_t

    • 跨序列乘法聚合

    • 典型阈值:2.0 - 10.0

所有 IS 权重安全绑定到 [exp(-20), exp(20)] ≈ [2e-9, 5e8]

rollout_is_threshold (float)

IS 权重截断的上阈值。默认:2.0

  • 通过 .clamp(max=rollout_is_threshold) 截断 IS 权重(TIS:截断重要性采样)

  • 用于方差降低的应用到 IS 权重

  • 与拒绝采样分离(由 rollout_rs 参数控制)

rollout_rs (str 或 null)

拒绝采样聚合级别:

  • null = 无拒绝采样

  • "token":拒绝异常比率的个别令牌

  • "sequence":拒绝异常比率的整个序列

  • "geometric":几何平均聚合用于拒绝

    • 典型阈值:1.0002 - 1.001

rollout_rs_threshold (float 或 null)

拒绝采样的上阈值。默认:null

  • 必需rollout_rs 启用时(必须明确设置)

  • 比率 > 阈值的令牌/序列被屏蔽

rollout_rs_threshold_lower (float 或 null)

拒绝采样的下阈值。默认:null

  • 如果 null,使用上阈值的倒数(1/upper)

  • 比率 < 阈值的令牌/序列被屏蔽

rollout_token_veto_threshold (float 或 null)

灾难异常下的每令牌否决。默认:null

  • 检查未绑定每令牌比率,在安全绑定之前

  • 如果任何令牌比率 < 阈值,整个序列被拒绝

  • 独立于 rollout_isrollout_rs 设置

  • 典型值:启用时为 1e-41e-6

  • 示例:1e-4 捕获 10,000x 不太可能的令牌

rollout_is_batch_normalize (bool)

对 IS 权重应用批量归一化。默认:False

  • True:归一化 IS 权重以在每个批次中具有 mean=1.0

    • 令牌级别 IS:归一化所有令牌权重

    • 序列级别 IS:归一化序列平均值(每序列一个权重)

  • False:使用原始(截断)IS 权重

  • 通过确保每批次平均权重为 1.0 降低方差

  • 应用于截断后以保留截断语义

  • 仅影响 IS 权重值,不影响拒绝采样

理解框架:组件和组合

部署校正框架建立在正交组件上,可以灵活组合。理解这些组件有助于为你的场景选择正确的配置。

关键组件

  1. 操作模式(节:操作模式

    • 解耦:三个策略(π_rollout, π_old, π_θ),分离 π_old 计算

    • 旁路:两个策略(π_rollout = π_old, π_θ),跳过 π_old 计算

  2. 损失函数

    • PPO:带裁剪的标准 RL 训练

    • 纯 IS:策略梯度仅(无裁剪)

  3. IS/RS 聚合级别

    • 令牌:每令牌 IS 权重/拒绝

    • 序列:序列级别 IS 权重/拒绝

    • 几何:几何平均(仅用于拒绝)

  4. 安全机制

    • 否决:拒绝包含灾难令牌的序列

详见数学公式


预设配置指南

本节提供了对验证预设的详细指导,每个预设是针对常见场景优化的组件特定组合。

理解预设

可用预设方法

预设方法

模式

IS 级别

RS 级别

属性

decoupled_token_is()

解耦

token

-

每令牌 IS 权重

decoupled_seq_is()

解耦

sequence

-

序列级别 IS 权重

decoupled_seq_is_rs()

解耦

sequence

sequence

序列 IS + 序列 RS

decoupled_geo_rs()

解耦

-

geometric + veto

几何 RS + 否决,无 IS 权重

ppo_is_bypass()

旁路

-

-

旁路模式,跳过 old_log_prob

pg_rs()

旁路

-

geometric + veto

策略梯度与 RS(无 IS 权重)

pg_is()

旁路

sequence

-

策略梯度与 IS

disabled()

-

-

-

指标仅,无校正

注意: 所有预设都使用 PPO 损失,除了 pg_is()pg_rs(),它们使用策略梯度(两者都需要 use_policy_gradient=True)。

其他支持组合(需要手动配置)

预设方法之外的其他支持组合:

  • 令牌 IS + 令牌 RS:在配置中手动组合

  • 纯令牌 RS:令牌级别 RS 仅,无 IS 权重

  • 纯序列 RS:序列级别 RS 仅,无 IS 权重

详见下面的详细配置示例

关键属性:

  • 任何聚合级别(token/sequence/geometric)在解耦或旁路模式下均有效

  • 所有组合由实现完全支持

  • 拒绝采样独立于 IS 加权

  • 纯 RS(pg_rs)使用旁路 + 几何 RS 与 use_policy_gradient=True(无 IS 权重)


1. 解耦模式与令牌级别重要性采样(decoupled_token_is

配置:

config = RolloutCorrectionConfig.decoupled_token_is(threshold=2.0)

组件:

  • 操作模式:解耦(3 个策略)

  • 损失:带裁剪的 PPO

  • IS 聚合:令牌级别

  • RS:无(可单独添加)

等价 YAML:

algorithm:
  rollout_correction:
    rollout_is: token
    rollout_is_threshold: 2.0
    rollout_rs: null
    bypass_mode: false  # 解耦模式

属性:

  • 每令牌独立截断

  • 低于序列级别方差(比率乘积单独绑定)

  • 典型阈值:1.5 - 5.0

理论: 详见rollout_corr_math.md §3.3.1


2. 解耦模式与序列级别重要性采样(decoupled_seq_is

配置:

config = RolloutCorrectionConfig.decoupled_seq_is(threshold=2.0)

组件:

  • 操作模式:解耦(3 个策略)

  • 损失:带裁剪的 PPO

  • IS 聚合:序列级别

  • RS:无(可单独添加)

等价 YAML:

algorithm:
  rollout_correction:
    rollout_is: sequence
    rollout_is_threshold: 2.0
    rollout_rs: null
    bypass_mode: false  # 解耦模式

属性:

  • 跨序列乘法聚合

  • 对异常值比序列级别更敏感

  • 典型阈值:2.0 - 10.0(高于令牌级别)

理论: 详见rollout_corr_math.md §3.3.2


3. 解耦模式与序列级别 IS + 拒绝采样(decoupled_seq_is_rs

配置:

config = RolloutCorrectionConfig.decoupled_seq_is_rs(is_threshold=2.0, rs_threshold=2.0)

组件:

  • 操作模式:解耦(3 个策略)

  • 损失:带裁剪的 PPO

  • IS 聚合:序列级别

  • RS:序列级别拒绝

等价 YAML:

algorithm:
  rollout_correction:
    rollout_is: sequence
    rollout_is_threshold: 2.0
    rollout_rs: sequence
    rollout_rs_threshold: 2.0
    rollout_rs_threshold_lower: 0.5  # 阈值倒数
    bypass_mode: false  # 解耦模式

属性:

  • 双机制:IS 重新加权 + 拒绝过滤

  • 降低有效样本大小(拒绝异常值)

  • 用于严重的离线策略差距

理论: 详见rollout_corr_math.md §3.4


4. 解耦模式与几何拒绝采样(decoupled_geo_rs

配置:

config = RolloutCorrectionConfig.decoupled_geo_rs(rs_threshold=1.001, veto_threshold=1e-4)

组件:

  • 操作模式:解耦(3 个策略)

  • 损失:带裁剪的 PPO

  • IS 聚合:无(纯拒绝)

  • RS:几何级别拒绝

  • 否决:启用

等价 YAML:

algorithm:
  rollout_correction:
    rollout_is: null
    rollout_rs: geometric
    rollout_rs_threshold: 1.001
    rollout_rs_threshold_lower: 0.999
    rollout_token_veto_threshold: 1e-4
    bypass_mode: false  # 解耦模式

属性:

  • 无 IS 权重(纯拒绝)

  • 几何平均聚合(比算术乘积更敏感)

  • 典型阈值:1.0001 - 1.001(比序列/令牌级别更紧)

  • 基于平均每令牌比率偏差拒绝序列

为什么紧阈值? 几何平均非常敏感。对每个比率 1.01 的 100 个令牌:

  • 乘积:1.01^100 ≈ 2.7

  • 几何平均:1.01

阈值 1.001 拒绝平均每令牌偏差 > 0.1% 的序列。

理论: 详见rollout_corr_math.md §3.3.3


5. PPO 与旁路模式(ppo_is_bypass

配置:

config = RolloutCorrectionConfig.ppo_is_bypass(threshold=2.0)

组件:

  • 操作模式:旁路(2 个策略:π_rollout = π_old, π_θ)

  • 损失:带裁剪的 PPO

  • IS 聚合:不需要(π_old = π_rollout)

  • RS:无

等价 YAML:

algorithm:
  rollout_correction:
    rollout_is: token  # 指标占位符
    rollout_is_threshold: 2.0
    rollout_rs: null
    bypass_mode: true  # 旁路模式
    use_policy_gradient: false

属性:

  • 跳过 actor.compute_log_prob() 前向传递

  • PPO 针对 π_rollout 裁剪(行为策略)

  • 设置 π_old = π_rollout(两策略设置)

  • 不分离近端策略和行为策略

配置要求:

  • 设置 actor_rollout_ref.rollout.calculate_log_probs: true

理论: 详见rollout_corr_math.md §3.1.2


6. 策略梯度与 IS(pg_is

配置:

config = RolloutCorrectionConfig.pg_is(threshold=2.0)

组件:

  • 操作模式:旁路(2 个策略:π_rollout, π_θ)

  • 损失:纯 IS(策略梯度仅,无 PPO 裁剪)

  • IS 聚合:序列级别

  • RS:无

等价 YAML:

algorithm:
  rollout_correction:
    rollout_is: sequence
    rollout_is_threshold: 2.0
    rollout_rs: null
    bypass_mode: true  # 必需
    use_policy_gradient: true  # 使用策略梯度损失(无 PPO 裁剪)

属性:

  • 策略梯度损失(无 PPO 裁剪)

  • 单前向传递(跳过 old_log_prob 计算)

  • IS 权重即时计算在损失函数中

理论: 详见rollout_corr_math.md §3.2.2


7. 策略梯度与拒绝采样(pg_rs

配置:

config = RolloutCorrectionConfig.pg_rs(
    rs_threshold=1.001,
    veto_threshold=1e-4
)

组件:

  • 操作模式:旁路(2 个策略:π_rollout, π_θ)

  • 损失:纯策略梯度(无 PPO 裁剪,use_policy_gradient=True 通过)

  • IS 聚合:无

  • RS:几何级别拒绝

  • 否决:启用

等价 YAML:

algorithm:
  rollout_correction:
    rollout_is: null
    rollout_rs: geometric
    rollout_rs_threshold: 1.001
    rollout_rs_threshold_lower: 0.999
    rollout_token_veto_threshold: 1e-4
    bypass_mode: true
    use_policy_gradient: true

属性:

  • 纯几何 RS(无 IS 权重,仅拒绝)

  • 跳过 actor.compute_log_prob() 前向传递(旁路模式)

  • 否决机制启用

  • 典型阈值:1.0001 - 1.001(比序列/令牌级别更紧)

理论: §3.1.2 (Bypass) + §3.3.3 (Geometric)


附加有用配置(未作为预设公开)

这些配置完全支持但还没有便利预设方法。

1. 令牌 IS + 令牌 RS(token_is_rs

令牌级别 IS 权重与令牌级别 RS 遮罩。

Python:

config = RolloutCorrectionConfig(
    rollout_is="token",
    rollout_is_threshold=2.0,
    rollout_rs="token",
    rollout_rs_threshold=2.0,
)

属性: 每令牌 IS 权重 + 每令牌 RS 遮罩。

2. 纯令牌 RS(token_rs

令牌级别 RS 仅,无 IS 权重。

Python:

config = RolloutCorrectionConfig(
    rollout_is=None,
    rollout_rs="token",
    rollout_rs_threshold=2.0,
)

属性: 令牌级别 RS 遮罩,无 IS 重新加权。

3. 纯序列 RS(seq_rs

序列级别 RS 仅,无 IS 权重。

Python:

config = RolloutCorrectionConfig(
    rollout_is=None,
    rollout_rs="sequence",
    rollout_rs_threshold=2.0,
)

属性: 序列级别 RS 遮罩,无 IS 重新加权。


总结:IS 权重的处理方式

IS 权重(rollout_is_weights)经过固定处理管道:

阶段 1:安全绑定(防止溢出)

  • 令牌级别:exp(clamp(log_ratio, -20, 20)) 每令牌 → 绑定每个令牌到 [2e-9, 5e8]

  • 序列级别:exp(clamp(sum(log_ratio), -20, 20)) → 绑定乘积到 [2e-9, 5e8],广播到所有令牌

阶段 2:截断(降低方差)

  • .clamp(max=rollout_is_threshold) → 在上阈值处截断权重(TIS:截断重要性采样)

  • 无下限截断(保留小权重下的无偏性质)

阶段 3:填充零化(正确聚合)

  • weights * response_mask → 在填充位置置零

阶段 4:可选批量归一化

  • 如果 rollout_is_batch_normalize=True:归一化权重到每批次 mean=1.0

  • 在截断后应用以保留截断语义

拒绝采样(分离机制)

拒绝采样通过 compute_rollout_rejection_mask() 修改 response_mask(NOT 权重):

  • 独立计算安全绑定比率

  • 创建二进制遮罩:在 [lower_threshold, upper_threshold] 之外的令牌/序列 → 0(拒绝)

  • 否决:检查未绑定每令牌比率(在安全绑定前),拒绝包含灾难令牌的整个序列

  • 修改遮罩用于损失聚合(被拒绝样本从训练中排除)

操作模式

框架提供两种操作模式用于计算 π_old,可以与不同损失函数组合。

操作模式和配置

配置

bypass_mode

use_policy_gradient

操作模式

损失函数

描述

解耦

false

false

解耦

PPO

单独计算 old_log_prob 通过 actor.compute_log_prob()

旁路

true

false

旁路

PPO

设置 old_log_prob = rollout_log_prob,PPO 针对部署策略裁剪

旁路 + PG

true

true

旁路

策略梯度

具有策略梯度损失的旁路模式(无 PPO 裁剪)

操作模式细节

解耦模式(三个策略)

策略设置:

  • π_rollout:行为策略(数据收集)

  • π_old:近端策略(在训练时期开始通过 actor.compute_log_prob() 计算)

  • π_θ:当前策略(正被更新)

配置: bypass_mode = false

属性:

  • ✅ 实现批次大小不变性

  • ✅ 单独校正漂移 1(rollout→old)和漂移 2(old→current)

  • ✅ 高效陈旧数据利用

  • ❌ 需要额外前向传递(actor.compute_log_prob()

理论: 详见rollout_corr_math.md §3.1.1

旁路模式(两个策略)

策略设置:

  • π_rollout:行为策略(数据收集)

  • π_old = π_rollout:近端策略等于行为策略

  • π_θ:当前策略(正被更新)

配置: bypass_mode = true

属性:

  • ✅ 跳过 actor.compute_log_prob() 调用(更快)

  • ✅ 处理使用策略梯度的离线策略校正(IS/RS 时)

  • ✅ 使用两个策略而不是三个(π_rollout = π_old)

  • ⚠️ 不分离近端策略和行为策略(与解耦模式不同)

理论: 详见rollout_corr_math.md §3.1.2


IS/RS 聚合级别(相对于操作模式正交)

聚合级别可以独立于操作模式选择。任何聚合级别在解耦或旁路模式下有效。

rollout_is

rollout_rs

行为

null

null

禁用:无计算,无指标,无拒绝

null

"token", "sequence", 或 "geometric"

拒绝仅:计算指标,NO 权重校正,YES 拒绝采样

"token""sequence"

null

IS 权重仅:权重校正启用,NO 拒绝采样

"token""sequence"

"token", "sequence", 或 "geometric"

全校正:权重校正和拒绝采样均启用

关键洞察

  • ✅ 任何 IS/RS 聚合级别(token/sequence/geometric)可在任一解耦或旁路模式下使用

  • ✅ 你可以单独使用拒绝采样而无 IS 权重校正(rollout_is=null, rollout_rs="token"

  • ✅ 你可以单独使用 IS 权重而无异常值拒绝(rollout_is="token", rollout_rs=null

  • ✅ 你可以一起使用两者rollout_is="token", rollout_rs="token"

  • ✅ 你可以仅监控指标而不应用校正,通过设置两者为 null 但仍提供 rollout_log_probs

否决拒绝(如果通过 rollout_token_veto_threshold 启用)独立于 IS 和 RS 设置应用。

理论: 详见rollout_corr_math.md §3.3 以获取聚合级别详情。

示例工作流

推荐:旁路 + 策略梯度模式

此工作流使用旁路模式和纯策略梯度损失以提高效率。

  1. 首先使用指标仅来理解离线策略差距:

    algorithm:
      rollout_correction:
        rollout_is: null
        rollout_rs: null
        bypass_mode: true  # 旁路模式(推荐)
        use_policy_gradient: true  # 纯策略梯度(推荐)
    

    监控 rollout_corr/kl, rollout_corr/log_ppl_abs_diff, rollout_corr/chi2_token 来评估离线策略差距。

  2. 如果看到高异常分数,则启用拒绝采样

    algorithm:
      rollout_correction:
        rollout_is: null
        rollout_rs: sequence  # 或 "geometric" 以获得更高敏感度
        rollout_rs_threshold: 2.0
        bypass_mode: true  # 旁路模式
        use_policy_gradient: true  # 纯策略梯度
    

    这将异常值从训练中排除而不修改梯度。

  3. 一旦舒适指标,则启用全 IS 校正

    algorithm:
      rollout_correction:
        rollout_is: sequence  # 推荐:无偏,适合大多数情况
        rollout_is_threshold: 2.0
        rollout_rs: sequence  # 或 "geometric" 以进行更激进过滤
        rollout_rs_threshold: 2.0
        bypass_mode: true  # 旁路模式
        use_policy_gradient: true  # 纯策略梯度
    

旁路 + 策略梯度模式的优势:

  • ✅ 跳过昂贵的 actor.compute_log_prob() 前向传递(更快)

  • ✅ 在损失函数中即时计算 IS 权重(π_θ / π_rollout)

  • ✅ 比 PPO 简单(无裁剪,纯策略梯度带 IS/RS)

  • ✅ 对所有 IS/RS 组合有效

使用

基本设置

algorithm:
  rollout_correction:
    rollout_is: token           # 在令牌级别启用 IS 权重
    rollout_is_threshold: 2.0   # IS 权重阈值
    rollout_rs: null            # 无拒绝采样
    rollout_token_veto_threshold: null  # 无否决

actor_rollout_ref:
  rollout:
    calculate_log_probs: true  # 必需!

指标

所有指标以 rollout_corr/ 为前缀记录。例如,rollout_is_mean 显示为 rollout_corr/rollout_is_mean

这些涵盖:

  • 诊断指标:KL 发散,困惑度差异(测量离线策略差距)

  • 校正统计:IS 权重,拒绝率,否决统计(测量应用校正)

核心 IS 权重指标

  • rollout_is_mean:跨所有有效令牌的平均重要性采样权重

    • 值接近 1.0 表示最小离线策略差距

  • rollout_is_std:IS 权重的标准差

    • 更高值表示 IS 权重更大的方差

  • rollout_is_min:观察到的最小 IS 权重

    • 显示最欠权重令牌/序列

    • 对于 sequence/geometric:从未绑定对数空间比率计算(真最小)

    • 对于 token:从安全绑定权重计算

  • rollout_is_max:观察到的最大 IS 权重

    • 显示最过权重令牌/序列

    • 对于 sequence/geometric:从未绑定对数空间比率计算(真最大,在安全绑定前)

    • 对于 token:从安全绑定权重计算(在阈值裁剪前)

    • rollout_is_threshold 比较以查看裁剪影响

有效样本大小

  • rollout_is_eff_sample_size:IS 加权后的有效样本大小

    • 公式1 / mean(weights²) ,权重归一化

    • 范围:0.0 到 1.0(作为原始批次的比率)

    • 较低值表示权重集中在较少样本上

否决机制指标

  • rollout_is_veto_fraction:被否决机制拒绝的序列分数

    • 重要:序列通过 response_mask=0 拒绝,NOT 通过修改 IS 权重

    • IS 权重不受否决影响:已安全绑定和截断

    • 否决检查未绑定每令牌比率(在安全绑定前的真比率)

      • 解耦模式:π_old(t)/π_rollout(t)

      • 旁路/纯 IS 模式:π_θ(t)/π_rollout(t)

    • 检测灾难令牌(真比率 < veto_threshold,如 < 1e-4)

  • rollout_is_catastrophic_token_fraction:低于否决阈值的令牌分数

    • 在应用序列级别否决之前识别问题令牌

    • 检查未绑定每令牌比率(真比率,不安全绑定)

    • 每个灾难令牌导致其整个序列拒绝

阈值超出指标

  • rollout_is_ratio_fraction_high:超过上阈值的权重分数

    • 显示高位的裁剪/遮罩发生频率

    • 对于 sequence/geometric:从未绑定对数空间比率计算(真超出)

    • 对于 token:从安全绑定权重计算(在阈值裁剪前)

  • rollout_is_ratio_fraction_low:低于下阈值(1/upper_threshold)的权重分数

    • 诊断指标显示低于倒数阈值的权重有多少

    • 对于 sequence/geometric:从未绑定对数空间比率计算(真超出)

    • 对于 token:从安全绑定权重计算(在裁剪前)

序列级别指标(序列聚合)

  • rollout_is_seq_mean:序列级别平均 IS 权重

    • 对于序列级别聚合应匹配 rollout_is_mean

  • rollout_is_seq_std:序列级别 IS 权重的标准差

  • rollout_is_seq_min:最小序列级别 IS 权重

  • rollout_is_seq_max:最大序列级别 IS 权重

  • rollout_is_seq_max_deviation:序列级别最大绝对偏差从 1.0

    • 显示最坏序列离线策略差距

  • rollout_is_seq_fraction_high:超过上阈值的序列分数

  • rollout_is_seq_fraction_low:低于下阈值的序列分数

拒绝采样指标rollout_rs 启用时)

  • rollout_rs_masked_fraction:拒绝采样遮罩的令牌分数

    • 重要:拒绝采样修改 response_mask(将拒绝令牌置 0)

    • 独立于 IS 权重:IS 权重仍被截断;拒绝是独立的过滤步骤

    • 仅在 rollout_rs 启用时(token/sequence/geometric)出现

  • rollout_rs_seq_masked_fraction:具有至少一个拒绝令牌的序列分数

    • 显示拒绝采样的序列级别影响

    • 令牌级别 RS:如果任何令牌在 [lower, upper] 之外则序列拒绝

    • 序列级别 RS:基于序列级别比率接受/拒绝整个序列

    • 几何 RS:基于几何平均接受/拒绝整个序列

离线策略诊断指标(训练 vs 部署策略)

术语说明: 这些指标使用 “training” 来指训练参考策略,使用 “rollout” 来指 π_rollout(用于数据收集的行为策略)。

  • 解耦模式:”training” = π_old(在训练时期开始计算)

  • 旁路/纯 IS 模式:”training” = π_θ(正被训练的当前策略)

在旁路/纯 IS 模式下,指标直接测量 π_θ 和 π_rollout 之间的漂移。

  • training_ppl:训练参考策略的困惑度(解耦模式中的 π_old,旁路/纯 IS 模式中的 π_θ)

    • 公式exp(-mean(log_probs))

    • 较低值表示更高模型信心

  • rollout_ppl:部署策略 π_rollout 的困惑度(例如 vLLM BF16)

  • ppl_ratio:训练 PPL 与部署 PPL 的比率

    • 公式exp(mean(log(training_ppl / rollout_ppl)))

    • 含义:> 1.0 意味着训练比部署更没信心

  • training_log_ppl:训练策略的对数困惑度

    • 用于识别趋势(线性刻度)

  • rollout_log_ppl:部署策略的对数困惑度

  • log_ppl_diff:对数困惑度的平均差异

    • 公式mean(log_ppl_rollout - log_ppl_training)

    • 符号指示哪种策略更自信

  • log_ppl_abs_diff:平均绝对对数困惑度差异

    • 不考虑方向的离线策略差距大小

  • log_ppl_diff_max:跨序列的最大对数困惑度差异

    • 识别最坏序列

  • log_ppl_diff_min:最小对数困惑度差异

  • kl:KL 发散 KL(π_rollout || π_training)

    • 公式mean(log_prob_rollout - log_prob_training)

    • 注意:可以为负(deploy 是更没信心)

  • k3_kl:K3 KL 估计器

    • 公式mean(exp(log_ratio) - log_ratio - 1)

    • 小 KL 值更稳定

    • 始终非负

  • chi2_token:令牌级别的卡方发散

    • 公式mean(ratio²) - 1 ,比率 = π_training/π_rollout

    • 测量 IS 权重分布的二阶矩

    • 始终非负

  • chi2_seq:序列级别的卡方发散

    • 公式mean((∏_t ratio_t)²) - 1

    • IS 权重的序列级别二阶矩

    • 比令牌级别对卡方更敏感

示例:代码中访问指标

# 指标从 compute_rollout_correction_and_rejection_mask 返回
from verl.trainer.ppo.rollout_corr_helper import compute_rollout_correction_and_rejection_mask

# 返回 3 值(权重,modified_response_mask,指标)
weights_proto, modified_response_mask, metrics = compute_rollout_correction_and_rejection_mask(
    old_log_prob=training_log_probs,      # 从训练策略
    rollout_log_prob=rollout_log_probs,   # 从部署策略
    response_mask=response_mask,
    rollout_is="token",  # 在令牌级别启用 IS 权重
    rollout_is_threshold=2.0,
    rollout_rs="token",  # 在令牌级别启用拒绝采样
    rollout_rs_threshold=2.0,
    rollout_rs_threshold_lower=0.5,
    rollout_token_veto_threshold=1e-4,  # 为灾难异常启用否决
)

# 提取 IS 权重(处理过,在填充处置零)
is_weights = weights_proto.batch["rollout_is_weights"]

# IS 权重处理(令牌级别 IS 启用时):
# 1. 安全绑定:exp(clamp(log_ratio, -20, 20)) 每令牌
# 2. 截断:.clamp(max=2.0) 以限制极端权重
# 3. 置零填充:在填充位置置零
# 注意:IS 权重始终截断(TIS:截断重要性采样)

# modified_response_mask 应用拒绝(由于 rollout_rs="token"):
# 1. RS 拒绝:在 [0.5, 2.0] 之外的令牌通过 response_mask 置零
# 2. 否决拒绝:具有灾难令牌的序列通过置零
# 注意:否决检查未绑定每令牌比率(在安全绑定前)
# 注意:RS 和 IS 是分离机制 - 两者均可独立启用

# 所有指标具有 'rollout_corr/' 前缀
print(f"Mean IS weight: {metrics['rollout_corr/rollout_is_mean']:.3f}")
print(f"Effective sample size: {metrics['rollout_corr/rollout_is_eff_sample_size']:.3f}")
print(f"Veto fraction: {metrics['rollout_corr/rollout_is_veto_fraction']:.3f}")
print(f"RS masked fraction: {metrics['rollout_corr/rollout_rs_masked_fraction']:.3f}")
print(f"KL divergence: {metrics['rollout_corr/kl']:.3f}")

# 检查有效令牌的 IS 权重(非填充)
valid_weights = is_weights[response_mask.bool()]