kl_estimate 和 entropy_bonus,以及使用它们的更新、训练循环和序列 KL 辅助函数。
10.1 参考策略
参考策略 是一个固定的策略,实践中是 RL 开始时模型的一份冻结副本(SFT 或基座检查点)。KL 正则化的目标是 其中序列 KL 沿策略自身的前缀分解为逐 token 的项(附录 A.6)。文献中反复出现三个使用它的理由,而它们是不同的理由。第一,在 RLHF 中奖励是一个学出来的模型,只在其训练数据附近准确;KL 把策略留在奖励可信的区域。第二,参考策略携带着奖励不衡量的能力(流畅性、格式、知识),KL 限制了策略可以拿多少这类能力去交换。第三,KL 是一种累积的信赖域(trust region):PPO 的裁剪(第 8 章)限制一次更新离 多远,而 KL 限制整个运行离 多远。对于隐藏测试这类可验证奖励,第一个理由不复存在,这正是主张去掉 KL 的核心论据(10.7 节)。 正则化的目标想要什么?对于单次决策(老虎机(bandit)),答案有闭式解。记 为 个动作上的分布,奖励为 。则 其中 ,。由于 KL 非负,且仅在 时为零,最优解是 ,最优值为 。最优解用指数化的奖励对参考策略做倾斜: 是一个温度,在 ()与参考策略支撑集内的最优动作()之间插值。参考策略从不采取的动作,对任何 概率都保持为零。在 为均匀分布时做同样的推导,就得到熵奖励,因为 :最大化 等价于对均匀分布施加 KL 惩罚,最优解为 。第 15 章用同一个闭式解推导 DPO。10.2 从样本估计 KL
训练器从来看不到序列上的完整分布。它看到的是采样得到的 token ,以及每个 token 的两个数: 和 。把它们的差记为 。John Schulman 的笔记 Approximating KL Divergence(2020)比较了 的三种单样本估计量: 按定义无偏,在许多样本上取负值。 加上了 ,由于 ,这一项在 下均值为零;它就是加了控制变量(control variate)的 (附录 A.3),无偏,并且由于 而永不为负。 有偏:泰勒展开表明它在 的二阶上与 KL 一致,更高阶则高估。第 9 章把这三者都保存为kl_penalty。附录 A.7 在两个距离上对它们做了采样;这里我们穷举一个 50 类分布的每个结果,在策略与参考策略之间的四个距离上精确计算它们的均值和单样本标准差。
10.3 各估计量用作损失时产生的梯度
损失中的 KL 项是这样实现的:在批次中采样得到的 token 上计算估计量,把 乘以其均值加到损失上。自动求导随后通过 对估计量求导,采样到的 token 保持固定。它不会对“这些 token 是从 采样而来”这一事实求导。因此这种损失的期望梯度是 ,而不是 :缺少了 第 6 章的得分函数(score function)项 。 利用 和 逐一计算。对 ,单样本梯度是 ,其期望为零: 损失只贡献噪声。对 ,单样本梯度是 ,其期望正是反向 KL(reverse KL)的真实梯度: 有偏的估计量给出了无偏的梯度。对 ,单样本梯度是 ,且 无偏、低方差的估计量给出的却是前向 KL(forward KL)的梯度,即另一个方向。在 附近,两个方向在二阶上一致,因此它们的梯度在一阶上一致,差异随距离增大。我们用每个结果的(detach 后的)采样概率对它加权来精确检验这一切,这就是大批量样本会趋近的期望。kl_penalty 之上的简单封装,取值时直接调用它。它只增加了一点:以 + 结尾的类型使用直通(straight-through)构造 g - g.detach() + v.detach(),其前向值是估计量 (因此记录的数字是比如 ),而梯度是 的梯度(因此损失沿反向 KL 的梯度方向推动)。verl 用同样的 + 后缀实现了同一选项(core_algos.kl_penalty,commit 00094bd,2026-10-13 查阅),并附有注释说明 和 的期望值正确,但期望梯度不正确。
k3+ 恰好具有 的梯度。在训练实际达到的距离上, 的误差有多大?
low_var_kl)更接近前向 KL 惩罚。10.5 节说明方向为什么重要,10.7 节在 TinyAgent 上测量这一差别。
k3+)在任何距离上都对。没有哪个估计量能同时赢下三项,这正是直通组合存在的原因。
陷阱。 在 PPO 式的更新中,第一个小批次之后,批次中的行来自 ,而不是当前的 。上面的推导假设样本是 on-policy 的。在第 9 章默认设置的小比率下(裁剪比例约 0.1%),这只是一个较小的额外偏差;在多轮次(epoch)训练中,这是 KL 项的梯度只是近似等于其名称所指的又一个原因。
10.4 KL 放在奖励中与放在损失中
惩罚有两个可以放置的位置。KL 放在奖励中:从奖励中减去 乘以逐 token 的 (对数比率),交给策略梯度(policy gradient)处理,RLHF 风格的 PPO 就是这样做的。KL 放在损失中:把 乘以逐 token 估计量加到损失上,GRPO 就是这样做的。对单个 token 而言,奖励版本就是以 为奖励的 REINFORCE,其梯度为 ;这恰好是上面推导出的负反向 KL 梯度,因此对单个 token 而言,“把 放在奖励中”与“把 放在损失中”是一致的。 对序列则不然。由附录 A.6,序列 KL 为 ,其中 是前缀 处的逐 token KL。它的梯度有两部分:在前缀固定时每个 如何随参数变化,以及 token 的选择如何改变后续访问到哪些前缀,从而改变未来的哪些 KL。逐 token 的损失只捕捉了第一部分,因为每个 token 的损失项只是该 token 自身对数概率的函数。基于奖励的策略梯度两部分都捕捉到了,因为每个 token 的对数概率都被它之后所有内容的 KL 加权(即 6.5 节的剩余回报(reward-to-go))。差别在于对未来偏离的回报归因(credit assignment):一个把回合引向策略与参考策略分歧区域的 token,会被奖励版本惩罚,却不会被损失版本惩罚。 我们在一个词表大小为 4 的两 token 序列模型上检验这一点,它小到可以穷举全部 16 个序列:第一个 token 有自己的 logits,第二个 token 的 logits 取决于第一个。surrogate 为每种放置方式构建自动求导会看到的期望损失。对损失放置,每个序列在两个 token 上都贡献估计量。对奖励放置,每个 token 的对数概率乘以从该 token 到结尾的 之和(已 detach)。
algorithm.use_kl_in_reward,默认用 惩罚,可选自适应控制器;以及 actor.use_kl_loss,配合 kl_loss_type: low_var_kl(,截断到 ),默认系数 0.001(commit 00094bd,2026-10-13 查阅)。对智能体而言,未来偏离项比单轮任务更重要,因为早期一次调用的 token 决定了回合会到达哪些观测,进而到达哪些后续上下文。
10.5 前向 KL 与反向 KL
反向 KL 按当前策略取期望:策略若给参考策略概率极低的位置分配较多概率,就会受到较大惩罚;参考策略有、但当前策略忽略的区域则不会直接贡献这一项。前向 KL 按参考策略取期望:参考策略重视的区域若被当前策略漏掉,惩罚就会很大。前者常称为 mode-seeking,倾向于集中在某个高概率模式;后者常称为 mass-covering,倾向于覆盖参考分布的各个模式。最大似然和 SFT 最小化相对数据的前向 KL;第 16 章的 on-policy 蒸馏(on-policy distillation)最小化相对教师的反向 KL。当一个简单的分布族必须逼近它无法表示的分布时,差别最为明显。我们用梯度下降分别在两个方向上,把一个离散化的高斯分布拟合到两个高斯的混合分布上。10.6 熵坍缩及其对策
熵坍缩(entropy collapse)是指 RL 过程中策略的逐 token 熵持续下降,趋向一个每次都采样同样 token 的策略。它不是某个组件的 bug:当 softmax 策略的高概率选择得到奖励时,策略梯度就会对它这样做。机制可以用一行写出。对 个 token 上的 logits ,记 ,,求导得 ,因此 logits 的一个小变化 使熵变化 这里用到了 。当更新提高已经很可能的 token 的 logits 时,熵下降;当它提高不太可能的 token 的 logits 时,熵上升。Cui et al. 的 The Entropy Mechanism of Reinforcement Learning for Reasoning Language Models(2025-05-28)对策略梯度和自然梯度更新推导了这一协方差形式,并报告在不加干预时,熵与验证集性能沿一条拟合曲线此消彼长。在优势为 的采样 token 上做一步策略梯度,logits 的变化为 。四种情况涵盖了所有可能。- 熵奖励在损失中加入 ,它对每个 token 的 logits 的梯度为 :它提高每个对数概率低于 的 token,降低高概率的 token。在 316 个词的词表上(Qwen3 则是 151k 个 token),“每个不太可能的 token”大多是策略永远不该输出的 token。10.1 节用闭式解说明了同一件事:熵奖励就是朝均匀分布的 KL 惩罚。
- KL 惩罚把每个 token 的分布拉向参考策略的分布,后者具有参考策略的熵。它只能在参考策略本身不确定的范围内抵抗坍缩;而且作为反向 KL,它不惩罚丢弃参考策略原有的备选(10.5 节)。
- Clip-higher(DAPO)提高 。当 时,一旦 ,PPO 的裁剪就会去掉该 token 的梯度,因此一个 token 在裁剪生效之前能获得的绝对增量是 :概率为 0.9 的 token 是 0.18,概率为 0.01 的 token 是 0.002。所以上裁剪界作用于具有正优势的稀有 token,而这些恰好是上表中提高熵的更新。DAPO 给出的理由相同:“不太可能的‘探索’ token 的概率被限制得太紧,无法被提升”(“the probability of an unlikely ‘exploration’ token is too tightly bounded to be uplifted”),并把 从 0.2 提高到 0.28。只有裁剪生效时这个手段才起作用,这要求策略在一个批次内发生移动(多个小批次或多个轮次)。
- 采样温度 从 中采样。由于训练器在同一个 下计算对数概率(第 9 章的
rl_update把 logits 除以cfg.temperature),被优化的策略就是加温后的策略,网络可以把 变得更尖锐,从而抵消任何固定的 。更高的温度只能推迟坍缩,而不能阻止它;ProRL 报告,在提高 rollout 温度后,“熵仍随训练推进而稳定下降”(“entropy continues to decline steadily as training progresses”)。在比训练更低的温度下评估则是另一个需要专门做出的选择(第 17 章)。
train_rl 没有添加额外损失项的钩子,而第 9 章的函数又不能修改。因此我们保存 entropy_bonus,以及第 9 章更新和循环的正则化版本,它们由同样的已保存组件(sample_step、behavior_stats、compute_advantages、policy_loss)构建。entropy_bonus 是策略位置上全词表熵的掩码均值;与 KL 估计量不同,它在每个访问到的前缀处是精确值,而不是单样本估计,因为整个词表的 logits 已经算好了。
regularized_update 就是第 9 章的 rl_update,有两处不同:损失减去 entropy_coef 乘以熵奖励,KL 项使用 kl_estimate,因此 cfg.kl_kind 可以是 'k3+'。记录的 entropy 是每个小批次中熵奖励在更新步之前的值。
train_regularized 是去掉周期性评估的 train_rl,外加 10.4 节的奖励放置。当 kl_in_reward=True 时,每个回合的奖励变为 ,在计算优势之前由采样器的对数概率和参考策略算出,此时损失中不含 KL 项。sequence_kl 计算这个求和。
train_rl 相同,所以从同一起点各跑三步,参数应当完全一致。
train_rl 的区别,只在于它打开的那个正则项。
单批次上的 clip-higher
上裁剪界是否生效,取决于策略在一个批次内移动了多远,而第 9 章的默认设置(一个轮次、两个小批次)只裁剪了 0.13% 的 token,太少了, 无关紧要。为了看清裁剪生效时的作用,我们从 RL 基座智能体取一个 64 个回合的批次,在其上分别以 为 0.2、DAPO 的 0.28 和实际上无上界的设置运行 8 个全批次更新步。8 步之后,我们统计比率超过 的正优势策略 token 数,以及其中有多少起始概率低于 0.5。10.7 在 TinyAgent 上比较各种正则化手段
现在我们用默认配置训练 40 步(第 9 章的运行在这个阶段还有提升空间),共九种设置:不加正则;梯度正确(k3+)的损失内 KL 惩罚, 取 0.05、0.3 和 1.0;GRPO 风格的 损失,取 0.3;放在奖励中的 KL,取 0.3(10.4 节);熵奖励 0.03 和 0.1;以及采样温度 1.3。每次运行都从同一个 RL 基座智能体出发,随机种子为 0。除了留出 pass@1,我们还测量多样性。对一个 次尝试中有 次通过的任务,不放回地抽取 次尝试、其中至少有一次通过的概率为 ;第 17 章推导并保存这个估计量,所以这里它只是一个局部辅助函数。我们还统计每个任务 16 次尝试中不同动作序列的数量,并用 估计相对初始策略的逐 token KL。
- 熵。 不加正则时,策略 token 的熵在 40 步内从 0.52 降到 0.12。除最弱的 KL 外,每种正则化手段都减缓了下降,减缓程度大致与其强度成比例:KL 系数 0.3 把熵保持在 0.28,1.0 把它保持在起始水平(0.54),熵奖励 0.03 保持在 0.31。熵奖励 0.1 则把策略推向了均匀分布:5.707 nats,而 ,每个回合六次格式错误的调用,通过率为零。
- pass@1 与 pass@8。 不加正则的运行 pass@1 为 0.725,pass@8 只有 0.80:有两个留出任务在 16 次尝试中从未被解出,因为坍缩的策略在它们上面反复执行同一个错误流程。最弱的 KL(0.05)没有改变熵(0.124),却仍达到 1.000 的 pass@8,pass@1 也是表中最高的 0.80;在单个随机种子下,我们无法把这与噪声区分开。更强的 KL 以 pass@1 为代价换来了多样性: 时每个任务的不同动作序列数翻倍(8.3 对 4.3),pass@8 达到 0.99,而 pass@1 降到 0.59。 时,读代码没有占据主导(每回合 0.53 次读取),pass@1 为 0.23,接近 0.2 的盲目上限,而 pass@8 仍有 0.90,因为接近参考策略的策略会采样许多不同的猜测。
- 估计量。 时, 损失和
k3+损失最终的熵(0.294 和 0.284)、pass@1(0.594 和 0.588)以及与起点的距离几乎相同。在这些逐 token KL 下(约 0.1),10.3 节给出的梯度差异约为 25%,单个随机种子分辨不出它的影响。 - 放置位置。 同样 时,放在奖励中的 KL 比两种损失放置都强得多:pass@1 为 0.34,读取 0.48 次,与起点的距离是除 之外最小的(0.059)。这就是 10.4 节所说的尺度差异:奖励版本对回合中 12 到 14 个策略 token 的对数比率求和而不是取平均,然后进入一个按每组离散程度归一化的优势。
- 熵奖励与温度。 两者都让熵保持得更高,同时却让策略离起点更远,超过不加正则的情况(KL 0.325 和 0.517,对比 0.237),而且都增加了格式错误的调用(每回合 0.28 和 0.25 次,对比 0.04)。熵奖励把质量分散到任何策略都不该输出的 token 上;温度运行中的网络把 logits 变尖锐以补偿 ,因此在 下评估时,它离初始策略比除坍缩的熵奖励之外的任何设置都远。它在训练时的熵(在 下测量)仍从 0.78 降到了 0.47。
k3+ 损失走的路径几乎相同(两条绿色曲线,各在一列中);放在奖励中的 KL 让熵保持得最高、奖励最低。在这个每个任务只有一种正确流程的 gym 上,没有任何正则化手段在 40 步内提高训练奖励:它们换来的是样本的多样性,代价是 pass@1 的下降,且随强度增大。
证据。 本书测得:每种设置一个随机种子,40 步,每步 64 个回合,在 10 个留出任务上评估,每个任务 16 次尝试。小于约 0.08 的 pass@1 差异在这次评估的噪声之内(第 9 章测得默认运行在三个随机种子间的范围为 0.71 到 0.81)。按强度的定性排序(熵、不同序列数、与起点的距离)才是本节演示的机制。
主张去掉 KL 的理由
DAPO 去掉了 KL 项,理由是在训练长推理时,“模型分布可能与初始模型显著偏离,因此这一限制并无必要”(“the model distribution can diverge significantly from the initial model, thus this restriction is not necessary”)(DAPO,第 2.3 节,2025-03-18)。第 20 章中公开的代码智能体配方(DeepSWE、SkyRL-Agent)也报告没有使用 KL 损失和熵损失。当奖励是验证器(verifier)时,10.1 节的论证支持这一做法:没有可被利用的学习型奖励,所以需要参考策略的第一个理由不复存在,其余理由(保留未被衡量的能力、累积的信赖域)可以通过在其他任务上评估和 PPO 的逐步裁剪来处理。相反的立场是 ProRL(2505.24864,2025-05-30),它训练了 2,000 多步,报告“通过 KL 散度惩罚进行显式正则化提供了更强、更稳定的解决方案”(“explicit regularization via a KL divergence penalty provides a stronger and more stable solution”),有助于“保持熵”(“maintain entropy”),同时指出随着时间推移,“KL 项可能越来越主导损失,导致策略更新逐渐减弱”(“the KL term may increasingly dominate the loss, leading to diminishing policy updates”)。它的解决办法是重置参考策略,10.8 节复现了这一做法。两者都是大规模单轮推理上的报告,不是针对智能体的受控证据。10.8 实践中的设计问题
问题:训练早期的熵坍缩。
现象: 策略 token 的熵在运行的前十分之一内减半,而奖励仍然很低,零优势组的比例攀升,留出任务上的 pass@ 趋近 pass@1。
原因: 10.6 节的协方差:在每个组中,成功的尝试大多由策略已经高概率的 token 组成,所以大多数正优势更新都让分布变尖锐,而步长(学习率、轮次数)决定了变尖锐的速度。
可选方案: (a) 降低学习率或轮次数,这也会减慢学习;(b) 对初始策略施加 KL 惩罚,把熵保持在参考策略的水平附近,代价是 pass@1;(c) 熵奖励,使用小系数并监控格式错误的输出;(d) clip-higher,只有裁剪生效时才有帮助;(e) 更高的采样温度,能推迟坍缩。
建议做法: 本书的建议是从第一步就记录熵和 pass@,只有当 pass@ 下降或某个已知良好的行为消失时才把坍缩当作问题;先尝试使用 k3+ 梯度的 (b),再尝试 (c)。下面的历史记录显示了默认运行坍缩得有多快,以及 (b) 和 (c) 改变了什么。
问题:KL 系数过强或过弱。 现象: 过强时,记录的 KL 一直接近零,奖励过早进入平台期,参考策略很少表现出的行为(这里是读代码)始终无法占据主导;过弱时,KL 无限增长,这一项没有任何可测量的作用。 原因: 在 10.1 节的最优解处,策略用 对参考策略做倾斜,因此 必须与奖励差异相比较,逐 token KL 必须与逐 token 优势相比较。尺度还取决于放置位置:损失中的逐 token 均值与奖励中的逐回合求和相差策略 token 的数量(这里约 13 个,智能体则是数千个)。 可选方案: (a) 在对数网格上扫描 ,同时记录 KL;(b) 使用自适应控制器,把 向目标 KL 调整(verl 的AdaptiveKLController);(c) 不用 KL,配合留出的回归测试集。 建议做法: 对可验证奖励用 (c),遵循公开的代码智能体配方;当回路中有学习型奖励或评判模型时用 (b)。三次k3+运行的 KL 日志展示了这几种状态。
问题:参考模型的显存与计算成本。 现象: 启用 KL 项后训练器显存不足,或者步时间增加了一大块。 原因: 参考模型是第二个完整模型,必须为每个训练 token 产生对数概率。它只需要权重(不需要梯度或优化器状态),但它给一个训练步增加了一次前向传播,而原本一个训练步只包括训练器为 计算对数概率的一次传播(第 9 章会重新计算它)以及一次前向和一次反向传播。 可选方案: (a) 在 rollout 期间由推理集群计算参考对数概率,随批次一起传输;(b) 单独卸载或切分参考模型;(c) 在 LoRA 训练中,把禁用适配器的基座模型用作参考模型,不需要额外显存;(d) 去掉 KL。 建议做法: 奖励可验证时用 (d),否则用 (c) 或 (a)。下面是几种模型规模的计算,假设使用 bf16 权重和梯度,以及 fp32 主权重和 Adam 矩(每个训练参数 16 字节):
问题:重置参考策略。 现象: 使用 KL 惩罚时,记录的 KL 稳定在一个平台上,而奖励不再提高;起约束作用的已经是惩罚项,而不是任务本身。 原因: 参考策略是初始策略,所以训练需要离起点越远,KL 梯度抵消掉的每次更新的部分就越多。 可选方案: (a) 降低 ;(b) 把参考策略硬重置为当前策略(并像 ProRL 那样重置优化器状态),使 KL 成为局部信赖域,而不是锚定在起点;(c) 去掉 KL。 建议做法: 如果使用 KL,就按与验证集平台期挂钩的时间表重置,正如 ProRL 报告的做法。我们把 的运行继续训练 20 步两次,一次锚定在起点,一次把参考策略重置为当前策略;两次都重新初始化优化器。
小结
- KL 正则化目标有闭式最优解 :用指数化的奖励对参考策略做倾斜,永远不会离开参考策略的支撑集。熵奖励是参考分布为均匀分布时的同一个目标。
- 在 Schulman 的估计量中, 和 的取值无偏,并且在 KL 较小时 的离散程度远低于其他两者。用作损失时,它们给出不同的梯度: 的期望梯度为零, 给出反向 KL 梯度, 给出前向 KL 梯度,其相对反向方向的误差随距离增大。
kl_estimate(..., 'k3+')记录 的值,而按 求导。 - 对序列而言,逐 token 的 KL 损失忽略了一个 token 如何改变其后各 token 的 KL;放在奖励中的 KL 通过策略梯度给出精确的序列梯度。在 TinyAgent 上,同样的 下奖励放置的惩罚要强得多,因为它对 token 求和并进入优势。
- 反向 KL 倾向于集中在高概率模式,前向 KL 倾向于覆盖参考分布的多个模式;反向 KL 惩罚本身并不保留参考策略的备选。
- 当更新提高已经高概率的 token 时,熵下降,。在 TinyAgent 上,不加正则的运行在 40 步内从 0.52 nats 降到 0.12 nats,且十个留出任务中有两个在 16 次尝试内从未被解出;KL 惩罚和熵奖励减缓了坍缩并提高了 pass@8,代价是 pass@1;0.1 的熵奖励破坏了动作格式;clip-higher 对熵没有可测量的影响。这些是单随机种子的机制演示。
- 对于可验证奖励,去掉 KL(DAPO、DeepSWE)省掉了一个参考模型和一个需要调的旋钮;保留 KL(ProRL)则以 pass@1 换取熵,并需要重置参考策略,以免训练被锚定在起点。
练习
- 证明给 损失加上缺失的得分函数项 后得到反向 KL 梯度,并证明对 做同样的修正也是如此。用
expected_loss_grad式的穷举检验两者。为什么没有人实现修正后的 来代替k3+? - 把 展开到 的三阶,预测 10.2 节中小 KL 时的偏差列。你的近似在 KL 多大时失效?
- 改变一个假设:只用不加正则和
KL k3+ 0.05两种设置,把 10.7 节重新运行 80 步而不是 40 步。当不加正则的运行的熵达到第 9 章的 0.08 时,它的 pass@8 会低于正则化运行吗?对照三个随机种子的离散范围报告这一差异。 - 把 10.4 节的两 token 模型扩展到三个 token,并实现一种精确的损失放置:逐 token 的 损失,加上一个携带每个 token 未来 KL 的 REINFORCE 项。用精确梯度验证它,然后说明 GRPO 训练器必须在其损失中加入哪一部分才能实现它。
- 在
train_regularized的副本中实现自适应 KL 系数(每步 )。哪个目标 KL 能让 TinyAgent 学会读代码,同时让 pass@8 至少与不加正则的运行一样高? - 把熵奖励限制在每次工具观测之后的第一个策略 token 上(ARPO 认定的高熵位置;第 20 章)。在平均熵相同的条件下,与均匀熵奖励比较格式错误的调用和 pass@8。
- 设计评审:某团队用 verl 的默认设置
use_kl_loss=True、kl_loss_type=low_var_kl、kl_loss_coef=0.001,在测试执行奖励上训练 SWE 智能体。记录的kl_loss为 0.02,策略熵在 200 步内下降了 70%。根据本章,论证这个 KL 项是否在起作用、它计算的是哪个梯度、你接下来会记录什么,以及如果奖励是 LLM 评判而不是测试,你会做哪些改变。