Kl Divergence Rlhf Tutorial
§0 TL;DR Cheat Sheet
一页拿下面试核心要点(详见后文 §1–§8 推导)。
- 定义:$\text{KL}(p \| q) = \mathbb{E}_{x \sim p}[\log(p(x)/q(x))]$,非负、不对称、非度量;在 RLHF 里 $p = \pi_\theta$、$q = \pi_\text{ref}$,作用是把 RL 后的 policy 锚在 SFT 附近防止 reward hacking。
- Forward vs Reverse:约定 $p$ 为数据/目标、$q_\theta$ 为变分/优化分布——Forward KL = $\text{KL}(p\|q_\theta)$(mass-covering),Reverse KL = $\text{KL}(q_\theta\|p)$(mode-seeking)。RLHF 用 $\text{KL}(\pi_\theta \| \pi_\text{ref})$,按这个约定属于 reverse KL($\pi_\theta$ 是变分一侧),mode-seeking 性质正好符合 RL 目标:让 $\pi_\theta$ 在 $\pi_\text{ref}$ 高密度区域选 reward 高的 mode;工程上也可行——直接对 rollout 采样估计即可。注意不同社区命名稍有差异,但 DPO / RLOO / "Rethinking KL" / "Comedy of Estimators" 这类 2024-2026 RLHF 文献都把 $\text{KL}(\pi_\theta \| \pi_\text{ref})$ 称 reverse KL。
三大 KL Estimator (Schulman 2020 blog
joschu.net/blog/kl-approx.html):- k1 = $\log(\pi_\theta/\pi_\text{ref})$ — 无偏但方差大、可负(不可读做"距离")。
- k2 = $\tfrac{1}{2}(\log(\pi_\theta/\pi_\text{ref}))^2$ — 总是非负但有偏(二阶 Taylor 近似)。
- k3 = $(\pi_\text{ref}/\pi_\theta) - \log(\pi_\text{ref}/\pi_\theta) - 1$ — 无偏 + 非负 + 低方差,从恒等式 $\mathbb{E}_q[f(\log p/q)]$($f(x)=e^x-x-1$)导出。
- 两种放置:(a) In-reward shaping:$\tilde{r}_t = r_t - \beta \cdot \text{KL}_t$,与 advantage / GAE 一起算;(b) In-loss regularization:$\mathcal{L} = \mathcal{L}_\text{PG} + \beta \cdot \mathbb{E}[\text{KL}]$。InstructGPT/Anthropic PPO 用 (a);GRPO 用 (b) + k3 estimator。目标函数相同,但梯度路径不同——在 principled estimator 下(如 (a) k1-in-reward 或 (b) k2-as-loss)on-policy 是 gradient-equivalent;GRPO 的 (b) k3-as-loss 实际有 $O(\Delta^2)$ first-order Taylor bias(见 §3.6 + Rethinking KL 2510.01555)。两种 placement 对 PPO clip / importance ratio 截断的响应也不同。
- β 调度:固定 β(最简单)、Adaptive β(PPO-Penalty 原版,按 measured KL 距 target 拉 β)、Annealing β(早期紧后期松,类似 SFT-to-RL 过渡)。β 过大学不到东西(policy 卡在 ref 附近),β 过小 reward hack(policy 漂掉、长答案/谄媚)。
- KL-regularized RL 闭式最优 policy:对 BT-style reward 目标 $\max_\pi \mathbb{E}[r] - \beta \cdot \text{KL}(\pi\|\pi_\text{ref})$ 求解,唯一闭式解为 $\pi^*(y|x) \propto \pi_\text{ref}(y|x) \exp(r(x,y)/\beta)$。DPO 就是把这个反解代入 Bradley-Terry,得到 $r = \beta \log(\pi^*/\pi_\text{ref}) + \beta\log Z$,partition function $\log Z$ 在 pairwise 差里消掉。
- DPO/GRPO/SimPO 中 KL 的位置:DPO 的 implicit reward $\hat r_\theta = \beta\log(\pi_\theta/\pi_\text{ref})$ 是 sequence-level log-ratio(取 $y\sim\pi_\theta$ 期望才等于 $\beta\cdot$KL,DPO 训练时 $y$ 来自 preference 数据所以不是 KL 本身,但 reference 出现在分母里仍带来隐式 anchoring);GRPO 用 k3 KL 进 loss(注意 k3-as-loss 的 gradient 是 first-order 近似,见 §3.6);SimPO 直接砍掉 reference,所以没有 KL 约束——对 β/γ/length-norm 更敏感。
- 失败模式:KL 爆炸(β 过小、importance ratio 过大)、KL collapse(β 过大或 entropy 太低,policy 卡死)、Reward Overoptimization (Gao 2023 ICML):proxy reward 随 KL 单调升,gold reward 先升后降(inverted-U),KL 距离是 overoptimization 的天然 axis。
§1 KL 基础
1.1 定义、性质、记号
定义(离散):
$$\boxed{\;\text{KL}(p \| q) \triangleq \sum_x p(x) \log \frac{p(x)}{q(x)} = \mathbb{E}_{x \sim p}\!\left[\log \frac{p(x)}{q(x)}\right]\;}$$
约定 $0 \log 0 = 0$、$0 \log(0/0) = 0$、$p \log(p/0) = +\infty$。连续分布把 $\sum$ 换成 $\int$。
核心性质(面试常被串问):
| 性质 | 一句话表述 | 简证 |
|---|---|---|
| 非负 | $\text{KL} \ge 0$ | Jensen + $-\log$ 凸:$\text{KL} = -\mathbb{E}_p \log(q/p) \ge -\log \mathbb{E}_p(q/p) = 0$ |
| 等号 | $\text{KL} = 0$ 当且仅当 $p = q$ a.e. | Jensen 等号条件 |
| 不对称 | $\text{KL}(p,q) \ne \text{KL}(q,p)$(在 $\text{KL}$ 的不对称参数中) | 直接构造例子可见 |
| 不满足三角不等式 | 不是 metric | 故"KL distance"是不严谨的口语化 |
| 凸性 | $\text{KL}(\cdot,\cdot)$ 对 $(p,q)$ 联合凸 | log-sum 不等式 |
| 链式法则 | 联合 KL 等于边际 KL 加条件 KL 期望(见下方 display 公式) | 直接拆 log |
| 参数化不变 | 对 $x \mapsto T(x)$ 同形变换不变(仅在可逆 $T$ 下取等号) | 测度变换 + Jacobian 抵消 |
链式法则的完整形式:
$$\text{KL}(p(x,y) \,\|\, q(x,y)) = \text{KL}(p(x) \,\|\, q(x)) + \mathbb{E}_{p(x)}\!\big[\text{KL}(p(y|x) \,\|\, q(y|x))\big]$$
Sequence-level KL 是 trajectory log-ratio 之和的期望:$\text{KL}_\text{seq} = \mathbb{E}_{y\sim\pi_\theta}[\sum_t \log\pi_\theta(y_t|s_t)/\pi_\text{ref}(y_t|s_t)]$。实际实现里对每条 rollout 做 $\sum_t \log r_t$ 是单条 MC estimator(k1 的 sequence 形式);要得到 true expected KL 需对 batch 内 rollout 平均。真实的 token-level KL $D_\text{KL}(\pi_\theta(\cdot|s_t)\|\pi_\text{ref}(\cdot|s_t))$ 还需对该 prefix 上整个 vocab 求和(full-vocab KL),而非只在 sampled token 上算 log-ratio。这两者期望相等但 estimator 形式不同:sum-over-rollout 的 sampled log-ratio 是 cheap-but-noisy estimator。
1.2 Forward KL vs Reverse KL:mass-covering 还是 mode-seeking?
记 $p$ 是数据/真实分布,$q_\theta$ 是参数化模型。两种 KL 在拟合策略上行为完全不同:
| 方向 | 形式(见下方 display) | 期望对谁取 | 行为 | 经典用途 | |
|---|---|---|---|---|---|
| Forward KL | $\text{KL}(p\,\ | \,q_\theta) = \mathbb{E}{p}[\log(p/q\theta)]$ | $p$(数据/目标) | mass-covering / mean-seeking:哪里 $p > 0$,$q_\theta$ 必须 > 0,否则 $\log(p/q) \to \infty$ | MLE / 蒸馏(学生覆盖老师) |
| Reverse KL | $\text{KL}(q_\theta\,\ | \,p) = \mathbb{E}{q\theta}[\log(q_\theta/p)]$ | $q_\theta$(变分/优化分布) | mode-seeking / minorization:哪里 $q_\theta > 0$,$p$ 必须 > 0;$q_\theta$ 倾向找单一 mode 缩进去 | VI、RLHF、GAN-like 训练 |
记号约定:
$$\text{Forward KL}: \text{KL}(p \,\|\, q_\theta) = \mathbb{E}_{p}\!\left[\log\frac{p}{q_\theta}\right],\qquad \text{Reverse KL}: \text{KL}(q_\theta \,\|\, p) = \mathbb{E}_{q_\theta}\!\left[\log\frac{q_\theta}{p}\right]$$
经典图(双峰 $p$,单峰 $q_\theta$):
- Forward KL 拟合 → $q_\theta$ 拉宽,跨越两个 mode(mass-covering)。
- Reverse KL 拟合 → $q_\theta$ 选其中一个 mode 缩进(mode-seeking)。
变分推断、DPO、RLOO、"Rethinking KL Regularization in RLHF" (arXiv 2510.01555)、"A Comedy of Estimators" (arXiv 2512.21852) 等 2024-2026 RLHF 文献都用统一约定:$\text{KL}(q_\theta\|p)$ 叫 reverse KL($q_\theta$ 是变分/优化分布),$\text{KL}(p\|q_\theta)$ 叫 forward KL。本教程跟随这个标准约定。少数早期 RL 教材按采样分布命名,建议在面试时直接给出公式,避免标签歧义。
RLHF 用哪一种? 几乎所有主流实现(InstructGPT / Anthropic PPO / DeepSeekMath GRPO)都用 $\text{KL}(\pi_\theta \| \pi_\text{ref})$(reverse KL 形式:$\pi_\theta$ 是变分一侧,$\pi_\text{ref}$ 是 target)。根本原因:训练时我们已经从 $\pi_\theta$ 采样(rollout),算 $\mathbb{E}_{\pi_\theta}[\log \pi_\theta/\pi_\text{ref}]$ 直接用样本就行;同时 reverse KL 的 mode-seeking 行为正好符合 RL 目标——在 $\pi_\text{ref}$ 高密度区找 reward 高的 mode,而不是"覆盖整个 $\pi_\text{ref}$"。
注意:把 $\pi_\theta$ 与 $\pi_\text{ref}$ 角色对调时(forward KL = $\text{KL}(\pi_\text{ref}\|\pi_\theta)$),要从 $\pi_\text{ref}$ 采样,工程上需要 IS、贵且语义不直接(我们要训的是 $\pi_\theta$ 不是 $\pi_\text{ref}$)。所以 RLHF 极少用 forward 方向。
1.3 与其他 divergence 的关系
| Divergence | 定义(见下方 display) | 特点 | 备注 |
|---|---|---|---|
| JS | KL 到混合 $m = (p+q)/2$ 的对称平均 | 对称、有界($\le \log 2$)、是 metric 的平方根 | $\sqrt{\text{JS}}$ 是 metric(Endres-Schindelin 2003 IEEE TIT 49(7));GAN 原版判别 loss 等价于 $2\cdot\text{JSD} - \log 4$;RLHF 极少用 |
| α-divergence | $\frac{1}{\alpha(1-\alpha)}(1 - \int p^\alpha q^{1-\alpha})$ | 含 KL 作为极限 | 统一框架,$\alpha \to 1$ 给 forward KL、$\alpha \to 0$ 给 reverse KL |
| Hellinger | $H^2(p,q) = \tfrac{1}{2}\int(\sqrt{p}-\sqrt{q})^2$ | 对称、有界、$0 \le H^2 \le 1$ | 与 KL 关系:$H^2 \le \tfrac{1}{2}\text{KL}$ |
| $\chi^2$ | $\chi^2(p,q) = \int \frac{(p-q)^2}{q}$ | 是 $f$-divergence 在 $f(t) = (t-1)^2$ 时的特例 | 与 KL 关系:$\text{KL} \le \log(1 + \chi^2)$ |
| TV | $\tfrac{1}{2}\int \lvert p-q\rvert$ | 是 metric、$\in [0,1]$ | Pinsker:$\text{TV} \le \sqrt{\text{KL}/2}$ |
四个常见 $f$-divergence 的完整形式:
$$\text{JS}(p, q) = \tfrac{1}{2}\text{KL}(p \,\|\, m) + \tfrac{1}{2}\text{KL}(q \,\|\, m),\quad m = (p+q)/2$$
$$\chi^2(p, q) = \int \frac{(p(x) - q(x))^2}{q(x)}\,dx,\qquad \text{Pinsker: } \mathrm{TV}(p,q) \le \sqrt{\text{KL}(p \,\|\, q) / 2}$$
主要是工程惯性 + 闭式优势:在 PPO/DPO 框架里 KL 有干净的 per-token 拆分(链式法则)、闭式最优解(softmax-style),且 likelihood ratio 直接给出 KL token 增量,免去额外网络估计。JS / α-divergence 要么数学没这么干净,要么需要额外 density ratio estimator。
1.4 为什么 RLHF 要加 KL?
把"无 KL"和"有 KL"的目标摆一起:
$$\text{无 KL}:\quad \max_\pi \mathbb{E}_{x,\,y \sim \pi(\cdot|x)}[r(x,y)]$$
$$\text{有 KL}:\quad \max_\pi \mathbb{E}_{x,\,y \sim \pi(\cdot|x)}[r(x,y)] - \beta\,\mathbb{E}_x\,\text{KL}\!\big(\pi(\cdot|x)\,\big\|\,\pi_\text{ref}(\cdot|x)\big)$$
没有 KL 会发生什么?
- Reward hacking:policy 找到 RM 盲点(更长答案 / "As an AI..." 套话 / 谄媚 / 格式 hack)拿高 RM 分,人感受变差。
- 语言流畅性塌掉:policy 会输出 RM "喜欢"但人类看着像鬼话的 token 序列(极端时退化到只重复某 token / 完全不语法)。
- Distribution shift:policy 跑远了 $\pi_\text{ref}$,连 RM 自己都很难评分(off-distribution,RM 越没把握、reward 越随机)。
加 KL 后:
- β 提供 RM error 的 implicit regularization:当 RM 不可靠时,KL 把 policy 拉回 SFT 已知良好分布。
- 闭式最优 policy 存在(§6.1 推导),整个 RLHF 有数学基础。
- DPO / KTO / GRPO 都依赖这条 KL anchor:去掉 reference 的 SimPO 实测对超参更敏感。
§2 KL Estimators(k1 / k2 / k3):面试核心
2.1 问题设置
实际训练里我们要在每一个 mini-batch 估计 $\text{KL}(\pi_\theta \| \pi_\text{ref})$。但完整求和 $\sum_y \pi_\theta(y) \log \pi_\theta(y)/\pi_\text{ref}(y)$ 不可行($y$ 是整段 response,组合爆炸)。只能 Monte Carlo:用从 $\pi_\theta$ 采样的样本估 KL。
记 $\log r = \log(\pi_\theta(y)/\pi_\text{ref}(y))$(不是 importance ratio,是策略 log-ratio)。我们有 $y \sim \pi_\theta$ 的样本,想估 $\mathbb{E}_{\pi_\theta}[\log r] = \text{KL}(\pi_\theta \| \pi_\text{ref})$。
本节 $\log r$ 始终表示 policy log-ratio $\log \pi_\theta - \log \pi_\text{ref}$(不是 PPO importance ratio $\pi_\theta / \pi_\text{old}$)。两者形式相近但含义不同:前者衡量"离 reference 多远",后者衡量"离 sampling policy 多远"。
2.2 k1 estimator —— "直接代入定义"
$$\boxed{\;\widehat{\text{KL}}_1 = \log\frac{\pi_\theta(y)}{\pi_\text{ref}(y)} = \log r\;}$$
- 无偏:$\mathbb{E}_{y\sim\pi_\theta}[\log r] = \text{KL}(\pi_\theta\|\pi_\text{ref})$ by definition。
- 可负:单个样本下 $\log r$ 可正可负(log-ratio 没有"非负"约束)。
- 方差大:tails 上 $\log r$ 可以非常大或非常小,特别是 $\pi_\theta$ 和 $\pi_\text{ref}$ 不重叠的区域。
问题:用 k1 作为"KL 监控指标"会看到负值,工程上会让 logger 显示负 KL,新人会困惑(KL 不该非负吗?)。这是因为期望非负不代表每个样本非负。但作为 reward shaping 的 per-token KL,可以接受(关键是均值无偏)。
2.3 k2 estimator —— "$L^2$ form"
$$\boxed{\;\widehat{\text{KL}}_2 = \tfrac{1}{2}\!\left(\log\frac{\pi_\theta(y)}{\pi_\text{ref}(y)}\right)^2 = \tfrac{1}{2}(\log r)^2\;}$$
- 总是非负 ✓
- 有偏:$\mathbb{E}[\tfrac{1}{2}(\log r)^2] \ne \text{KL}$。
- 小 KL 极限下:Taylor 展开 $\log r = (r - 1) - \tfrac{1}{2}(r-1)^2 + O((r-1)^3)$,当 $\pi_\theta \approx \pi_\text{ref}$ 时 $\log r$ 小,$\tfrac{1}{2}(\log r)^2$ 与 KL 在二阶近似下相等(KL 在 $p=q$ 附近 = Fisher 信息度规的二次型)。
- 方差小于 k1:因为平方后正负不再相消,但仍然不是最优。
实践中 k2 主要用于监控(提供"non-negative,但有偏"的视觉化指标);很少用于 reward shaping。
2.4 k3 estimator (Schulman 2020 blog) —— 非负无偏 value estimator(但作为 loss 项是 biased gradient,见 §3.6)
2.4.1 构造
考虑函数 $f(x) = e^x - x - 1$。由 $e^x \ge 1 + x$(实数 $x$)得 $f(x) \ge 0$,且 $f(0) = 0$。
把 $x = \log(\pi_\text{ref}(y)/\pi_\theta(y)) = -\log r$ 代入:
$$f(-\log r) = e^{-\log r} - (-\log r) - 1 = \frac{1}{r} + \log r - 1 = \frac{\pi_\text{ref}(y)}{\pi_\theta(y)} + \log\frac{\pi_\theta(y)}{\pi_\text{ref}(y)} - 1$$
等价地(用 $\Delta = -\log r = \log(\pi_\text{ref}/\pi_\theta)$ 写):$\frac{\pi_\text{ref}}{\pi_\theta} - \log\frac{\pi_\text{ref}}{\pi_\theta} - 1$(注意 $-\log(\pi_\text{ref}/\pi_\theta) = \log(\pi_\theta/\pi_\text{ref})$,两形式等价)。
等价地(这是 Schulman blog 中的标准写法):
$$\boxed{\;\widehat{\text{KL}}_3 = \frac{\pi_\text{ref}(y)}{\pi_\theta(y)} - \log\frac{\pi_\text{ref}(y)}{\pi_\theta(y)} - 1 = e^{\Delta} - \Delta - 1,\quad \Delta = \log\frac{\pi_\text{ref}(y)}{\pi_\theta(y)} = -\log r\;}$$
2.4.2 三大性质(必考)
性质 1(非负):
由 $e^\Delta - \Delta - 1 \ge 0$ 对所有 $\Delta \in \mathbb{R}$(凸函数 $e^\Delta$ 在 $\Delta = 0$ 切线 $1 + \Delta$ 之上),$\widehat{\text{KL}}_3 \ge 0$ 总是成立。
性质 2(无偏):
要证 $\mathbb{E}_{y \sim \pi_\theta}[\widehat{\text{KL}}_3] = \text{KL}(\pi_\theta\|\pi_\text{ref})$。
$$\mathbb{E}_{\pi_\theta}\!\left[\frac{\pi_\text{ref}}{\pi_\theta}\right] = \sum_y \pi_\theta(y) \cdot \frac{\pi_\text{ref}(y)}{\pi_\theta(y)} = \sum_y \pi_\text{ref}(y) = 1$$
$$\mathbb{E}_{\pi_\theta}\!\left[-\log\frac{\pi_\text{ref}}{\pi_\theta}\right] = \mathbb{E}_{\pi_\theta}\!\left[\log\frac{\pi_\theta}{\pi_\text{ref}}\right] = \text{KL}(\pi_\theta\|\pi_\text{ref})$$
所以:
$$\mathbb{E}_{\pi_\theta}[\widehat{\text{KL}}_3] = 1 + \text{KL}(\pi_\theta\|\pi_\text{ref}) - 1 = \text{KL}(\pi_\theta\|\pi_\text{ref}) \quad \checkmark$$
性质 3(方差通常小于 k1):
直观:$\widehat{\text{KL}}_3$ 把 $\log r$ 的线性项($-\log r/\pi_\theta$ 部分,即 k1 的等价形式 $\mathbb{E}_{\pi_\theta}[-\log(\pi_\text{ref}/\pi_\theta)]$)和一个期望为 1 的控制变量 $\pi_\text{ref}/\pi_\theta - 1$ 相加。控制变量降方差(control variate):当 $r$ 大时 $\log r$ 大但 $1/r$ 小,反之亦然,两者负相关,加起来方差比单独 k1 小。
形式化:$\widehat{\text{KL}}_3 = \widehat{\text{KL}}_1 + (\frac{\pi_\text{ref}}{\pi_\theta} - 1)$,加项 $(\frac{\pi_\text{ref}}{\pi_\theta} - 1)$ 期望为 0,但与 $\log r$ 强负相关 → 减方差。
Schulman blog 2020 给出的 derivation 等价于上面:他先找一个 $f(x) \ge 0$ 且 $\mathbb{E}_q f(\log p/q) = \text{KL}$ 的函数,然后挑 $f(x) = e^x - x - 1$(最简单的非负、可微、不是 trivial 的选择)。所以 k3 不是"灵感来的"——它是"非负 + 无偏"约束下的最自然构造。
2.4.3 变种与简化
实际代码经常写成(对 PPO ratio $r = \pi_\theta / \pi_\text{old}$ 同样适用,但语义不同——这是 importance ratio approx,不是 policy log-ratio):
approx_kl_to_old = ((ratio - 1) - torch.log(ratio.clamp_min(1e-8))).mean()
即 $\widehat{\text{KL}}_3 \approx (r - 1) - \log r$,是上面 $e^\Delta - \Delta - 1$ 的等价对偶(把 $r = e^{\log r}$ 视作 $e^\Delta$ 即可,符号约定换一下)。TRL / OpenRLHF / verl 默认 approx_kl 都是这个。
2.5 三者对比表
| Estimator | 形式 | 无偏? | 非负? | 方差 | 在 RLHF 里典型用途 |
|---|---|---|---|---|---|
| k1 | $\log r$ | ✅ | ❌ | 大 | InstructGPT PPO reward shaping(per-token KL) |
| k2 | $\tfrac{1}{2}(\log r)^2$ | ❌ value-estimator 有偏(二阶近似 KL) | ✅ | 中 | value 视角常用作监控;loss-gradient 视角是 principled k2-as-loss——on-policy 下与 k1-in-reward gradient-equivalent,见 §3.6 |
| k3 | $e^{-\log r} + \log r - 1$ | ✅(作为 value estimator) | ✅ | 小 | DeepSeekMath GRPO / DAPO 历史用法(作为 loss 时其梯度是 biased first-order approx,见 §3.6 + Rethinking KL 论文) |
2.6 代码:三估计器 + variance 对比 simulation
import torch
import torch.nn.functional as F
def k1_estimator(logp_theta, logp_ref):
"""k1: log(π_θ / π_ref) — unbiased, but can be negative, high variance."""
return logp_theta - logp_ref # [B, T]
def k2_estimator(logp_theta, logp_ref):
"""k2: 0.5 (log(π_θ / π_ref))^2 — biased, non-negative, mid variance."""
return 0.5 * (logp_theta - logp_ref) ** 2
def k3_estimator(logp_theta, logp_ref):
"""k3 (Schulman 2020): exp(log π_ref - log π_θ) + log(π_θ/π_ref) - 1
= (π_ref/π_θ) - log(π_ref/π_θ) - 1 [letting Δ = log π_ref - log π_θ]
Value-estimator properties: unbiased, non-negative, low variance.
⚠️ Recommended for KL value MONITORING, NOT as a loss term — k3-as-loss
gives gradient (1 - e^{-Δ})∇logπ_θ = (Δ - ½Δ² + O(Δ³))∇logπ_θ, a
first-order Taylor approximation of reverse-KL gradient with O(Δ²) bias.
For principled reverse-KL gradient, use k2-as-loss (gradient-equivalent
to k1-in-reward on-policy) or k1-in-reward via score function. See §3.6.
"""
log_r = logp_theta - logp_ref # log(π_θ/π_ref)
log_ratio_rev = -log_r # Δ = log(π_ref/π_θ)
return torch.exp(log_ratio_rev) - log_ratio_rev - 1
# Variance comparison: 1D synthetic
def compare_kl_estimators(n_samples=10_000, seed=0):
"""
Synthetic: π_θ = N(0, 1), π_ref = N(μ, 1). True KL = μ^2 / 2.
Sample y ~ π_θ; evaluate the three estimators.
"""
torch.manual_seed(seed)
mu = 0.5
true_kl = mu ** 2 / 2.0 # closed-form for Gaussians w/ same σ
y = torch.randn(n_samples) # y ~ N(0, 1) = π_θ
# log-pdf of N(0,1) vs N(μ,1) at y (drop common -0.5 log 2π):
logp_theta = -0.5 * y ** 2
logp_ref = -0.5 * (y - mu) ** 2
k1 = k1_estimator(logp_theta, logp_ref)
k2 = k2_estimator(logp_theta, logp_ref)
k3 = k3_estimator(logp_theta, logp_ref)
print(f"true KL = {true_kl:.4f}")
for name, vals in [("k1", k1), ("k2", k2), ("k3", k3)]:
print(f" {name}: mean={vals.mean().item():+.4f} var={vals.var().item():.4f} "
f"min={vals.min().item():+.3f} max={vals.max().item():+.3f}")
# Expected output: k1 mean ≈ 0.125 (unbiased), but min < 0;
# k2 mean > 0.125 (biased upward);
# k3 mean ≈ 0.125 (unbiased), min ≥ 0, var(k3) < var(k1).
- k1 mean ≈ 0.125, min 约 −1.5(可负),var 大。
- k2 mean ≈ 0.18(偏高),min ≥ 0,var 中。
- k3 mean ≈ 0.125(无偏),min ≥ 0,var 明显小于 k1。
这正是 Schulman blog 给出的 takeaway:k3 同时拿到 unbiased + non-negative + 较低方差。
§3 KL 在 RLHF 中的两种放置
3.1 Option A:In-reward shaping(PPO RLHF / InstructGPT 标准做法)
把 KL 塞进 per-token reward,再正常跑 PPO + GAE:
$$\boxed{\;\tilde{r}_t = \underbrace{\mathbb{1}[t = T] \cdot R(x, y)}_{\text{terminal RM reward}} - \beta \cdot \underbrace{\log\frac{\pi_\theta(y_t \mid x, y_{ 注意细节: 放完后跑 GAE: $$\delta_t = \tilde{r}_t + \gamma V(s_{t+1}) - V(s_t),\quad A_t^{\text{GAE}} = \sum_{l \ge 0} (\gamma\lambda)^l \delta_{t+l}$$ KL penalty 通过 advantage 自然 propagate 到 policy gradient:每步 token 的"动作概率提升"被 KL "拉回 reference" 抵消,最终 RL 目标 = expected $R$ − $\beta$ · KL。 把 KL 不放 reward,作为单独 loss 项: $$\boxed{\;\mathcal{L}_\text{full}(\theta) = -\underbrace{\mathbb{E}\!\left[\min(\rho_t A_t, \text{clip}(\rho_t, 1\!-\!\epsilon, 1\!+\!\epsilon) A_t)\right]}_{\text{PPO surrogate / GRPO surrogate}} + \beta \cdot \underbrace{\mathbb{E}\!\left[\widehat{\text{KL}}_\text{loss}(\pi_\theta \| \pi_\text{ref})\right]}_{\text{KL loss term}}\;}$$ GRPO 的历史实现(DeepSeekMath / DAPO)把 $\widehat{\text{KL}}_\text{loss}$ 取作 k3(per-token): 把 k3 直接当 loss 反传不是精确的 reverse-KL gradient——它是一个 biased first-order approximation(详见 §3.6 + 2025 "Rethinking KL Regularization in RLHF" 论文)。on-policy 下更 principled 的两种选择是:(1) k1 in reward(KL 进 reward,PPO/GRPO 通过 score-function 反传,gradient 严格无偏);(2) k2 as loss($\tfrac12 (\log r)^2$,$\nabla\mathcal L = \Delta\,\nabla\log\pi_\theta$,on-policy 下与 (1) gradient-equivalent,都是严格 reverse-KL gradient)。off-policy 还需 IS correction。下方 §3.6 给出对比表。 数学:两种放法本质都是优化同一个目标: $$J(\pi) = \mathbb{E}_{\pi}[R] - \beta \cdot \text{KL}(\pi \| \pi_\text{ref})$$ 只是梯度 propagate 路径不同: 工程差异: 在 Option A 中,当 importance ratio $\rho_t$ 落在 clip 之外($\rho_t > 1+\epsilon$ 且 $\tilde A_t > 0$ 或 $\rho_t < 1-\epsilon$ 且 $\tilde A_t < 0$),PPO 把 surrogate 截断为常数(对 θ 梯度为 0),此时该 step 的 $\tilde r_t$ 里的 KL 项也一并失效。这意味着当 policy 偏离过大时,PPO clip 反而让 KL anchor 失效——这是 Option B 把 KL 放 loss 的部分动机(KL 永远生效)。 字节 verl 团队的工程报告里多次提到,KL 项在大规模数学/代码 RL 训练中经常关掉或设很小 β($10^{-4}$ 量级),原因:reward 已经是 rule-based(接近 ground truth),不存在 RM hacking,KL anchor 反而拖训练。这是"Option B + β ≈ 0"的极端版本。 Kezhao Liu et al., "Rethinking KL Regularization in RLHF: From Value Estimation to Gradient Optimization", arXiv 2510.01555 (2025-10-02)。这篇文章系统区分 value estimation("KL 量本身估得准不准")与 gradient optimization("对 θ 求导后是不是真的 reverse-KL gradient"),结论与历史 GRPO 实现不完全一致。 为简洁起见,令 $\Delta_t = \log\!\frac{\pi_\theta(y_t|s_t)}{\pi_\text{ref}(y_t|s_t)}$(per-token log-ratio,带 θ 梯度),$\hat\Delta_t = \text{stop\_grad}(\Delta_t)$(在 rollout 时记录的 detached 副本)。三种常见 placement: k3 作为 value estimator(计算 KL 的数值)是无偏的:$\mathbb{E}_{\pi_\theta}[\widehat{\text{KL}}_3] = \text{KL}(\pi_\theta\|\pi_\text{ref})$(见 §2.4.2 性质 2)。但当 对 θ 反传时,autograd 计算的是 $\nabla_\theta\widehat{\text{KL}}_3$,而不是 $\nabla_\theta\,\mathbb{E}_{\pi_\theta}[\widehat{\text{KL}}_3]$。后者由 score-function trick 给出: $$\nabla_\theta\,\text{KL}(\pi_\theta\|\pi_\text{ref}) = \mathbb{E}_{y\sim\pi_\theta}\!\big[\nabla_\theta\log\pi_\theta(y) \cdot \log(\pi_\theta(y)/\pi_\text{ref}(y))\big] \;+\; \mathbb{E}_{\pi_\theta}[\nabla_\theta\log\pi_\theta]\,\quad\text{(=0)}$$ = $\mathbb{E}[\nabla\log\pi_\theta \cdot \Delta]$(这是 (P1) 给的 gradient,等价于把 $\Delta$ 当 detached reward 走 score function)。 而 (P3) 总结口径(面试推荐说法):k3 是优秀的 KL value estimator(unbiased + non-negative + low variance);但作为 loss 反传的 gradient 是 reverse-KL gradient 的 first-order Taylor approximation,有 bias。Rethinking KL 推荐 on-policy 用 (P1) 或 (P2);DAPO/GRPO 历史用 (P3) 主要是工程惯例 + 在小 β 区间近似成立。 最常见。$\beta \in [0.01, 0.5]$,InstructGPT 报告中 β = 0.02 是参考值(per-token KL)。优点:简单可重现。缺点:训练中 KL 通常先小后大,固定 β 后期可能"压不住"或"过度压制"。 PPO 论文(Schulman 2017 arXiv 1707.06347)原本提了两个版本:Clip(现在主流)和 Penalty(adaptive KL)。Penalty 形式: $$\mathcal{L} = \mathbb{E}[r_t A_t] - \beta_k \cdot \text{KL}(\pi_{\theta_\text{old}} \| \pi_\theta)$$ β 自适应规则(每 epoch 之后看 measured KL $d$): 直觉:把 β 当 PID controller 的 P term,target 是预期 KL(比如 $d_\text{target} = 0.01$)。这条思路在 InstructGPT 和后续 Anthropic 工作里也出现过(Anthropic 论文 1707.06347 之后的 helpfulness/harmlessness 报告里有类似 adaptive β 描述)。 把 β 看作时间函数 $\beta(t)$: 在 RLHF 工程实践中 annealing 用得不多——adaptive β 比 schedule 更鲁棒(不需调 schedule shape)。 答案因任务而异。Math/code RL 通常需要更小 β(DeepSeekMath 报告 β ≈ 0.04,DAPO 的 β 经常更小或为 0),因为 reward 接近 ground truth。Helpfulness/safety RL 需要更大 β(≥ 0.1)防 reward hacking,因为 neural RM 容易被 hack。这是为什么"β 不是 universal hyperparameter"。 用法: 上面只有 P 项(proportional);HuggingFace TRL 里的实现也只用 P。完全可以加 I(integral:累计误差)和 D(derivative:变化率)做 PID,但实测 P 已经够了,加 D 反而容易在 noisy KL 估计下振荡。 DPO 的 implicit reward 是 $\hat{r}_\theta(x, y) = \beta \log(\pi_\theta(y|x) / \pi_\text{ref}(y|x))$,即整段 $y$ 的 sequence-level log-density ratio: $$\hat{r}_\theta(x, y) = \beta \sum_t \log\frac{\pi_\theta(y_t | x, y_{ $\hat{r}_\theta$ 是单条 sequence 的 pointwise log-ratio,不是 KL。只有当对 $y\sim\pi_\theta$ 取期望时,$\mathbb{E}_{y\sim\pi_\theta}[\hat{r}_\theta(x,y)] = \beta\cdot\text{KL}(\pi_\theta(\cdot|x)\,\|\,\pi_\text{ref}(\cdot|x))$(这是 k1 KL estimator 的 sequence-level 形式)。但 DPO 训练时 $y_w, y_l$ 不是从 $\pi_\theta$ 采的,而是来自固定 preference 数据,所以训练阶段的 $\hat{r}_\theta$ 不能直接读作 KL;它只是 pairwise log-ratio 差异。 正确表述:DPO loss 的对偶 RLHF 解释是把 $\hat{r}_\theta$ 当 reward,BT model 给概率 $\sigma(\hat{r}_w - \hat{r}_l)$;它对应"KL-regularized RL 闭式最优 policy $\pi^* \propto \pi_\text{ref}\exp(r/\beta)$"反解出的 reward 表达式。$\pi_\theta$ 在 implicit RLHF 视角下隐式被 KL 约束(因为 $\hat r_\theta$ 形式里 $\pi_\theta/\pi_\text{ref}$ 出现),但 DPO 优化的是 pairwise margin 而非显式 KL margin。 KL-regularized 目标: $$\max_\pi \mathbb{E}_{x,\, y \sim \pi}[r(x, y)] - \beta\, \text{KL}(\pi \| \pi_\text{ref})$$ 对单个 $x$ 用 Lagrangian + 求导(详细推导见 §6.1),得: $$\pi^*(y|x) = \frac{1}{Z(x)} \pi_\text{ref}(y|x) \exp\!\left(\frac{r(x, y)}{\beta}\right)$$ 反解: $$r(x, y) = \beta \log\frac{\pi^*(y|x)}{\pi_\text{ref}(y|x)} + \beta \log Z(x)$$ 代入 Bradley-Terry $P(y_w \succ y_l | x) = \sigma(r(x, y_w) - r(x, y_l))$,$\beta \log Z$ 消掉,得 DPO: $$\boxed{\;\mathcal{L}_\text{DPO}(\theta) = -\mathbb{E}_{(x,y_w,y_l)}\log\sigma\!\left(\beta\log\frac{\pi_\theta(y_w|x)}{\pi_\text{ref}(y_w|x)} - \beta\log\frac{\pi_\theta(y_l|x)}{\pi_\text{ref}(y_l|x)}\right)\;}$$ $$\nabla_\theta \mathcal{L}_\text{DPO} = -\beta \mathbb{E}\!\Big[\sigma(\hat{r}_l - \hat{r}_w)\big(\nabla_\theta \log\pi_\theta(y_w|x) - \nabla_\theta \log\pi_\theta(y_l|x)\big)\Big]$$ 解释: DPO 调 β 不直接对应 RLHF 调 β 的语义。在 PPO 中 β 只影响 KL penalty 强度,在 DPO 中 β 同时影响:(1) implicit reward scale、(2) 梯度幅值(外层 β)、(3) sigmoid 饱和位置(内层 β)。经验值 $\beta \in [0.05, 0.5]$ 但每个任务最优 β 不同。 DeepSeekMath GRPO 用 k3,KL 作为独立 loss 项: $$L^\text{GRPO}(\theta) = \mathbb{E}\!\left[\frac{1}{G}\sum_{i=1}^G \frac{1}{|y_i|}\sum_{t=1}^{|y_i|}\!\Big(\min(\rho_{i,t} \hat{A}_{i,t}, \text{clip}(\rho_{i,t}, 1{-}\epsilon, 1{+}\epsilon)\hat{A}_{i,t}) - \beta\,\widehat{\text{KL}}_3^{i,t}\Big)\right]$$ 其中 $\widehat{\text{KL}}_3^{i,t} = e^{-\log r_{i,t}} + \log r_{i,t} - 1$(per-token k3),$\log r_{i,t} = \log\pi_\theta(y_{i,t}|\cdot) - \log\pi_\text{ref}(y_{i,t}|\cdot)$。 为什么 GRPO 历史上选 k3(注意:这些都是 value-estimator 性质,不直接保证 loss gradient 正确,见 §3.6): Rethinking KL (arXiv 2510.01555) 系统分析显示 on-policy 下 (P1) k1-in-reward 或 (P2) k2-as-loss 是严格 reverse-KL gradient;GRPO/DAPO 实际工程上 $\beta$ 锁得紧、$\Delta$ 很小,所以 first-order approximation 误差有限——但面试中应能区分 "value-estimator 优势" 与 "loss-gradient 正确性"。 SimPO 把 implicit reward 改成 length-normalized log-prob: $$r_\text{SimPO}(x, y) = \frac{\beta}{|y|} \log \pi_\theta(y|x)$$ 关键差异:没有 $\pi_\text{ref}$,所以没有 KL 项。损失: $$\mathcal{L}_\text{SimPO} = -\mathbb{E}\log\sigma\!\left(\frac{\beta}{|y_w|}\log\pi(y_w) - \frac{\beta}{|y_l|}\log\pi(y_l) - \gamma\right)$$ 后果: 工程上发现 SimPO 训完的 model 在重复模式、生成长度、对 prompt 微扰的鲁棒性上都比 DPO 差。这是为什么很多生产 RLHF 仍然用 DPO + small β 而不是 SimPO——KL anchor 是有代价但有价值。 定理(KL-regularized policy optimization 的闭式解): 考虑: $$\max_\pi J(\pi) = \mathbb{E}_{y \sim \pi(\cdot|x)}[r(x, y)] - \beta\, \text{KL}\!\big(\pi(\cdot|x) \| \pi_\text{ref}(\cdot|x)\big)$$ 其中 $\pi$ 是对任意 $x$ 的分布,$\pi_\text{ref}$ 严格正($\pi_\text{ref}(y|x) > 0$ 对所有 $y$)。 唯一最优解: $$\boxed{\;\pi^*(y|x) = \frac{1}{Z(x)}\, \pi_\text{ref}(y|x)\, \exp\!\left(\frac{r(x, y)}{\beta}\right),\quad Z(x) = \sum_{y'} \pi_\text{ref}(y'|x) \exp\!\left(\frac{r(x, y')}{\beta}\right)\;}$$ 证明(Lagrangian): 固定 $x$,写目标(连续/离散通用,离散表示): $$\mathcal{L}_x[\pi] = \sum_y \pi(y|x) r(x, y) - \beta \sum_y \pi(y|x) \log\frac{\pi(y|x)}{\pi_\text{ref}(y|x)} - \mu\!\left(\sum_y \pi(y|x) - 1\right)$$ 其中 $\mu$ 是 normalization 约束的 Lagrange multiplier(注意符号:从 max 推 KKT 时把 $\sum_y\pi = 1$ 写成 $-\mu(\sum - 1)$ 是为了内点最优条件简洁)。 对 $\pi(y|x)$ 求偏导: $$\frac{\partial \mathcal{L}_x}{\partial \pi(y|x)} = r(x, y) - \beta \log\frac{\pi(y|x)}{\pi_\text{ref}(y|x)} - \beta - \mu = 0$$ 整理: $$\log\frac{\pi(y|x)}{\pi_\text{ref}(y|x)} = \frac{r(x, y) - \mu - \beta}{\beta}$$ 指数化: $$\pi(y|x) = \pi_\text{ref}(y|x) \exp\!\left(\frac{r(x, y) - \mu - \beta}{\beta}\right) = \pi_\text{ref}(y|x) \exp\!\left(\frac{r(x, y)}{\beta}\right) \cdot e^{-(\mu+\beta)/\beta}$$ 代入归一化条件 $\sum_y \pi(y|x) = 1$: $$e^{(\mu+\beta)/\beta} = \sum_y \pi_\text{ref}(y|x) \exp\!\left(\frac{r(x, y)}{\beta}\right) = Z(x)$$ 所以 $e^{-(\mu+\beta)/\beta} = 1/Z(x)$,得: $$\pi^*(y|x) = \frac{1}{Z(x)} \pi_\text{ref}(y|x) \exp\!\left(\frac{r(x, y)}{\beta}\right) \quad \blacksquare$$ 唯一性:因为 $J$ 在 $\pi$ 上是严格凹的(KL 是凸的,加负号变严格凹,且 reward 是 linear),凹优化有唯一最优。 把 §6.1 的 $\pi^*$ 取 log: $$\log\pi^*(y|x) = \log\pi_\text{ref}(y|x) + \frac{r(x, y)}{\beta} - \log Z(x)$$ 反解 $r$: $$\boxed{\;r(x, y) = \beta\log\frac{\pi^*(y|x)}{\pi_\text{ref}(y|x)} + \beta\log Z(x)\;}$$ 这就是 DPO 的 implicit reward。$\beta \log Z(x)$ 是 partition function,只依赖 $x$,不依赖 $y$——在 Bradley-Terry 的 $r(x, y_w) - r(x, y_l)$ 差里消掉。 BT 模型:$P(y_w \succ y_l | x) = \sigma(r(x, y_w) - r(x, y_l))$。 代入 §6.2: $$r(x, y_w) - r(x, y_l) = \beta \log\frac{\pi^*(y_w|x)}{\pi_\text{ref}(y_w|x)} - \beta\log\frac{\pi^*(y_l|x)}{\pi_\text{ref}(y_l|x)}$$ 替换 $\pi^*$ 为可学 $\pi_\theta$,对偏好数据 NLL: $$\mathcal{L}_\text{DPO}(\theta) = -\mathbb{E}\log\sigma\!\left(\beta\log\frac{\pi_\theta(y_w|x)}{\pi_\text{ref}(y_w|x)} - \beta\log\frac{\pi_\theta(y_l|x)}{\pi_\text{ref}(y_l|x)}\right)$$ 这是 §5.1 的 DPO 公式。所以DPO ≡ Bradley-Terry preference + KL-regularized RL 闭式解 + 偏好数据 NLL,三件套合一。 记 gold reward $r_g$(人感受的真实质量)、proxy reward $r_p$(RM 估的)。RM 用偏好数据学,但偏好数据有限 → $r_p \ne r_g$。 随着 RL 训练 KL 距离 $d = \text{KL}(\pi_\theta \| \pi_\text{ref})$ 增大: Gao 2023 用大量 RM size + KL 实验,给出 gold reward 关于 KL 距离 $d$ 的拟合形式(用 $\sqrt{d}$ 当 x-axis): $$R_g(d) = d \cdot (\alpha_g - \gamma_g \cdot d) \quad \text{(BoN)}$$ $$R_g(d) = d \cdot (\alpha_g - \gamma_g \cdot d) - \delta_g\, d^{3/2}\quad \text{(PPO, 多了高阶项)}$$ 其中 $\alpha_g, \gamma_g, \delta_g$ 是与 RM size 相关的系数;RM 越大,"高阶项 / 二次项"权重越小,过优化越慢。 无论是 BoN、PPO 还是 DPO(按 implicit reward 累积),都可以把训练曲线画成"KL 距离 vs gold reward"图。Gao 2023 发现: 面试 takeaway:在 RLHF 监控里,把 KL 与 $\chi^2$ 在 Pinsker 类不等式族里有关系: $$\text{TV} \le \sqrt{\text{KL}/2}\qquad \text{(Pinsker)}$$ $$\text{KL} \le \log(1 + \chi^2)$$ 在 RLHF 里 $\chi^2$ 偶尔被作为 KL 的"敏感"上界使用:当 $\chi^2$ 大但 KL 小,意味着 $\pi_\theta$ 有重 tail 偏离 $\pi_\text{ref}$(高方差但低 mean)。某些工作(Yu et al. 2024 / others)在监控 reward hacking 时同时画 KL 和 $\chi^2$,看 tail 行为。 由 §1.1 的链式法则: $$\text{KL}(\pi_\theta(\cdot|x) \| \pi_\text{ref}(\cdot|x)) = \mathbb{E}_{y \sim \pi_\theta}\!\left[\sum_t \log\frac{\pi_\theta(y_t | x, y_{ 即 sequence-level KL = token-level KL 之和的期望(自回归 chain rule)。注意:单条 rollout 上把 $\sum_t \log\pi_\theta(y_t)/\pi_\text{ref}(y_t)$ 直接当 KL 是 k1 estimator(unbiased 但 per-rollout 方差大);若要 true token-level KL $D(\pi_\theta(\cdot|s_t)\|\pi_\text{ref}(\cdot|s_t))$ 还需 full-vocab forward。两者期望相等,工程上选 sampled log-ratio 是因为 vocab 求和昂贵。 但有两个implementation trick 与 token-level 相关: 症状: 原因: 修复: 症状: 原因: 修复: 症状: 原因:见 §6.4,RM 与 gold reward 的本质不同。 修复: 症状: 原因:DPO loss 是 sequence-level log-ratio 差。$y_w$ 通常更长(人选更详尽答案),longer $y_w$ → 更负的 $\log\pi(y_w)$ → log-ratio 差更大 → loss 减小。但这是 RM scale 而非 reasoning quality。 修复: 症状:训练正常但下游 eval 极差。 原因:用了错误的 ref checkpoint(比如 pretrain base 而不是 SFT)。KL anchor 锚到了"语言模型"而不是"指令模型"。 修复:reference 必须是 immediate-previous-stage SFT checkpoint,不能跳层级。 按难度分 3 档:L1 = 任何 LLM 工程岗都会问;L2 = research / alignment 团队会问;L3 = 顶级 lab / DeepSeek 量级团队的硬核题。每题点开看答案要点 + 易踩坑。 说 KL 是"距离"——错(不满足三角不等式);或不知道凸性。 只说"防过拟合"——不够具体;不知道 reward hacking。 把单 estimator 和期望混淆;或不知 expectation 非负 ≠ pointwise 非负。 只背公式不知道 derivation;或不知道它非负。 说两者完全等价——目标相同梯度不等价;说 k3-as-loss 是 principled——它是 first-order approximation,理论不严格。 只说"看着调";不知 β 的工程量级。 不知道命名约定(少数早期 RL 教材以采样分布命名,会把 reverse 标成 forward;面试时给公式更稳);或反过来说 forward 更好。 说 DPO 没有 KL(错,是隐式 anchor);或把 $\hat r$ 直接读作 KL / KL margin(错,需要 y~π_θ 期望条件)。 只说"过拟合"——太笼统;不知道 KL 是 over-optimization 的 axis。 只说 k3 "三优满足"不给 gradient bias caveat;不知道 (P2) k2-as-loss 是 P1 的 gradient-equivalent 替代。 需要证 $\mathbb{E}_{y\sim\pi_\theta}[(\pi_\text{ref}/\pi_\theta) - \log(\pi_\text{ref}/\pi_\theta) - 1] = \text{KL}(\pi_\theta\|\pi_\text{ref})$。 关键:用 $\sum_y\pi_\text{ref} = 1$。如果你忘了 $\pi_\text{ref}/\pi_\theta$ 这一项是 expectation 1 的 control variate,证不出无偏。 构造性证明: 取 $x = \log(\pi_\text{ref}(y)/\pi_\theta(y)) = -\log r$: 所以 k3 = $f(\log p/q)$ 的特殊形式,恰好满足"非负 + 无偏 + 含 control variate" 三个性质。 只写公式不解释 $f$ 的构造动机;或不知道凸函数切线 → 非负。 目标:$\max_\pi \mathbb{E}_{y\sim\pi}[r(x,y)] - \beta\,\text{KL}(\pi\|\pi_\text{ref})$。 注意:$J$ 在 $\pi$ 上严格凹,最优唯一。 漏 normalization 约束;漏 strict concavity argument;或把 sign 搞反。 关键 trick:$\log Z$ 不依赖 $y$,所以在 pairwise 差里抵消(这是 DPO 不需要采样的根本原因)。 不解释 $\log Z$ 为什么消掉;或不知道 BT 的 sigmoid。 记 $h_\theta = \beta\log(\pi_\theta(y_w)/\pi_\text{ref}(y_w)) - \beta\log(\pi_\theta(y_l)/\pi_\text{ref}(y_l))$(implicit reward margin)。 $\mathcal{L}_\text{DPO} = -\mathbb{E}\log\sigma(h_\theta)$,$\nabla = -\mathbb{E}\sigma'(h_\theta)/\sigma(h_\theta) \cdot \nabla h_\theta$。 用 $\sigma'(x) = \sigma(x)\sigma(-x)$,$\sigma'(h)/\sigma(h) = \sigma(-h) = \sigma(\hat{r}_l - \hat{r}_w)$(即"错位置信度")。 $\nabla h_\theta = \beta(\nabla\log\pi_\theta(y_w) - \nabla\log\pi_\theta(y_l))$($\pi_\text{ref}$ 是常数,求 $\theta$ 导为 0)。 合并: $$\nabla\mathcal{L}_\text{DPO} = -\beta\mathbb{E}[\sigma(\hat{r}_l - \hat{r}_w)(\nabla\log\pi_\theta(y_w) - \nabla\log\pi_\theta(y_l))]$$ 解读: 少推一步 sigmoid' 公式;或不知道 $\sigma'(x) = \sigma(x)\sigma(-x)$。 记 $r = \pi_\theta/\pi_\text{ref}$,$y \sim \pi_\theta$,$\text{KL}(\pi_\theta\|\pi_\text{ref}) = \mathbb{E}_{\pi_\theta}[\log r]$。 关键修正:旧版本写 "$\mathbb{E}[r-1] = 0$" 是错的——在 $y\sim\pi_\theta$ 下 $\mathbb{E}[r] = \mathbb{E}_{\pi_\theta}[\pi_\theta/\pi_\text{ref}]$ 一般 $\ne 1$。$\mathbb{E}[s] = 1$ 才是正确的恒等式(这是 importance sampling 的标准结果)。 只说"二阶近似";不展开 Taylor,或者错用 $r$ 而非 $s$ 做 mean-1 展开。 只说 "类似 P controller" 不展开;或加上 D 项不知会出问题。 不知 β 与 reward scale 的耦合;或机械套 β = 0.04。 说 SimPO 一定更好;或不知道 length-norm + margin 是 KL 的替代。 混淆两者;或不知道 mask only assistant tokens 的必要性。 非负证明: $f(x) = e^x - x - 1$。$f'(x) = e^x - 1$,$f'(x) = 0$ ⟺ $x = 0$。$f''(x) = e^x > 0$,$f$ 严格凸,$x = 0$ 是全局最小,$f(0) = 0$。所以 $f(x) \ge 0$ 对所有 $x$。✓ k3 非负性:取 $x = \log(\pi_\text{ref}/\pi_\theta) = -\log r$,则 $\widehat{\text{KL}}_3 = f(-\log r) \ge 0$ 总成立。✓ k3 无偏性: $\mathbb{E}_{\pi_\theta}[\widehat{\text{KL}}_3] = \mathbb{E}_{\pi_\theta}[e^{-\log r}] + \mathbb{E}_{\pi_\theta}[\log r] - 1 = 1 + \text{KL} - 1 = \text{KL}$ ✓ 哪个性质对 loss 加项更关键? 所以 k3 在 value-monitoring 层面最方便(非负 + value-unbiased + 低方差)。但对于 "as loss addend" 的 principled 性,关键不是非负,而是 loss-gradient 是否匹配真实 reverse-KL gradient——k3-as-loss 的 gradient $(1 - e^{-\Delta})\nabla\log\pi_\theta$ 只是 first-order Taylor approximation,有 $O(\Delta^2)$ bias;on-policy 下严格 principled 的 loss 是 (P2) k2-as-loss 或 (P1) k1-in-reward。GRPO/DAPO 历史用 k3 主要是工程惯例 + 小 β 时 bias 可忽略。 易错:把非负当作 "loss addend 的 key" —— 那只是数值显示层面的优势;真正决定 principled 性的是 gradient correctness。理想组合是 "value-side k3 monitor + loss-side k2/k1-in-reward gradient"。 设定:$\max_\pi \mathbb{E}_\pi[r] - \beta\,\text{KL}(\pi\|\pi_\text{ref})$,闭式解 $\pi^*(y|x) = \pi_\text{ref}\exp(r/\beta)/Z$。 RL 视角:当 reward $r$ 给定时,最优 policy 通过 importance-weighted update 朝 $\pi^*$ 走。Score function policy gradient: $\nabla_\theta J = \mathbb{E}_{\pi_\theta}[\nabla\log\pi_\theta \cdot (r - \beta\log(\pi_\theta/\pi_\text{ref}))]$ DPO 视角:把 $\pi$ 直接看作待学 $\pi_\theta$,用 BT 反解 implicit reward $\hat{r} = \beta\log(\pi_\theta/\pi_\text{ref}) + \beta\log Z$,对偏好对做 NLL。 等价性: 关键:DPO 不是 RL 的替代,是对同一目标的不同 reduction——RL 通过 sampling-based PG,DPO 通过 closed-form + supervised learning。"DPO 没有 RL" 是误读。 只说"DPO 推 RL 闭式解"不展开 gradient 等价性;或不知道两者 fixed point 相同。 Gao 2023 的 BoN gold reward 拟合:$R_g(d) = d(\alpha_g - \gamma_g d)$,$d = \sqrt{\text{KL}}$。 求 peak:$dR_g/dd = \alpha_g - 2\gamma_g d = 0$ → $d_\text{peak} = \alpha_g / (2\gamma_g)$。 对应 KL distance:$\text{KL}_\text{peak} = d_\text{peak}^2 = \alpha_g^2 / (4\gamma_g^2)$。 安全 budget:要在 peak 之前停下来。一般选 $\text{KL}_\text{stop} = 0.5 \cdot \text{KL}_\text{peak}$(留 50% safety margin)。 怎么估 $\alpha_g, \gamma_g$? 需要 gold reward 信号(人工 / 强 RM ensemble)。在小规模 pilot run 跑几个 KL 点,拟合 $R_g(d)$。 RM 越大,越靠右:Gao 2023 给的 scaling law 表明 $\alpha_g, \gamma_g$ 随 RM size 改变(拟合系数本身依赖于 RM 规模和数据),更大 RM 的 $\text{KL}_\text{peak}$ 更靠右,但 $R_g(\text{peak})$ 也更高。这是为什么大 RM 既"对得起 budget" 又能拿更高 gold。 PPO 比 BoN 复杂一点:$R_g(d) = d(\alpha_g - \gamma_g d) - \delta_g d^{3/2}$,三阶项使 peak 稍微靠左。 应用:实际工程里把 measured KL 限制在 $\text{KL}_\text{peak} \cdot 0.5$ 作 early stop,即 "$\sqrt{\text{KL}}$ < $d_\text{peak}/2$"。 不展开 derivative;或不知 RM size 与 peak 的 scaling。 动机(按标准约定:reverse = $\text{KL}(q\|p)$ mode-seeking,forward = $\text{KL}(p\|q)$ mass-covering): 问题:forward KL 需要从 $\pi_\text{ref}$ 采样,工程上没意义(要训的是 $\pi_\theta$ 不是 $\pi_\text{ref}$)。 绕路方案 (theoretical): 实际工业方案(更简单): 总结:forward KL 在 RLHF 里"理论吸引但工程难",主流做法是用 entropy / multiple policies 替代。 只说"两个都加上"——太天真,要给出工程方案;不知道 forward KL 的 sampling 障碍。 方向 1:Adaptive KL estimator per token 方向 2:Per-task β controller 方向 3:Adversarial KL 方向 4:Distributional reward + W2 KL 方向 5:Hierarchical KL 方向 6:KL-free 但 trust-region 替代 只罗列没 trade-off;或不知道 SimPO / IPO 已部分探索 KL-free 路线。 按章节分组。本节为草稿初版,arXiv ID 与精确发表场所未经在线核实——校验时应通过 KL 基础与 estimators RLHF / PPO DPO 系 GRPO 系 / RL with k3 KL Reward Overoptimization Critic-free RL(与 KL 放置相关) 两篇 2024-2026 KL-in-RLHF 系统分析论文(已核验 arXiv 元数据) Zhihu 中文资料 与本文紧密相关的内部教程3.2 Option B:In-loss regularization(GRPO / DAPO 做法)
3.3 两者数学上等价?工程上不等价
维度 In-reward (Option A) In-loss (Option B) KL 估计器 k1(单 token 可负,作为 reward 接受) k3(无偏 + 非负,更稳) 与 PPO clip 的关系 KL 被 clip 截断(importance ratio 截断把 KL 一并截了) KL 独立,不被 clip 影响 Advantage 解释 advantage 内含 KL → "净 advantage" advantage 仅 reward-based → "纯 advantage" 调参敏感度 β 直接影响 reward scale → 需要和 RM scale 协调 β 与 reward 独立,但 KL 与 PG 比重要平衡 监控指标 看 token-level KL 进了 reward 看 KL loss 独立曲线 3.4 实操:哪一种用在哪?
算法 KL 放置 估计器 来源 InstructGPT PPO In-reward k1 Ouyang 2022 NeurIPS Anthropic RLHF In-reward k1 + adaptive β Bai 2022 arXiv 2204.05862 GRPO / DeepSeekMath In-loss k3 Shao 2024 arXiv 2402.03300 DAPO In-loss(实际配置中 KL 项常被关掉或权重很低) k3 Yu 2025 arXiv 2503.14476 DPO 隐式 in-loss(通过 $\pi_\text{ref}$ 在 log-ratio 分母) — Rafailov 2023 NeurIPS SimPO 去掉 reference, 无 KL — Meng 2024 NeurIPS 3.6 Estimator placement 的 gradient bias 分析(Rethinking KL Regularization in RLHF)
设定与三种 estimator placement
方案 KL 出现的位置 单 token 形式 对 θ 的梯度贡献 (P1) k1 in reward 进 reward / advantage $\hat r_t \leftarrow r_t - \beta\,\hat\Delta_t$,再走 PPO surrogate $-\beta\cdot \mathbb{E}[\nabla_\theta\log\pi_\theta\cdot \hat\Delta_t]$,严格的 reverse-KL score-function gradient(on-policy) (P2) k2 as loss 直接 loss 项 $\mathcal{L}_\text{KL} = \tfrac12 \Delta_t^2$ $\nabla\mathcal{L}_\text{KL} = \Delta_t\,\nabla_\theta\log\pi_\theta$(用 $\nabla_\theta\Delta_t = \nabla_\theta\log\pi_\theta$)。on-policy 下 $\mathbb{E}_{y\sim\pi_\theta}[\Delta\,\nabla\log\pi_\theta] = \nabla\text{KL}$,与 (P1) gradient-equivalent——严格 principled (P3) k3 as loss 直接 loss 项 $\mathcal{L}_\text{KL} = e^{-\Delta_t} + \Delta_t - 1$ $\nabla\mathcal{L}_\text{KL} = (1 - e^{-\Delta_t})\nabla_\theta\log\pi_\theta$;这是 reverse-KL gradient 的 first-order Taylor approximation,$1-e^{-\Delta} = \Delta - \tfrac12\Delta^2 + O(\Delta^3)$,有 $O(\Delta^2)$ bias 为什么 k3 as loss 是 biased gradient(关键直觉)
loss.backward() 给的是 $\nabla_\theta(e^{-\Delta} + \Delta - 1) = (1 - e^{-\Delta})\nabla_\theta\Delta = (1 - 1/r)\nabla_\theta\log\pi_\theta$。Taylor 展开:$1 - 1/r = \Delta - \tfrac12\Delta^2 + O(\Delta^3)$。所以 (P3) ≈ (P1) 只在 $\Delta\to 0$ 邻域成立;远离 0 时有 $O(\Delta^2)$ bias。实践规则(结合 Rethinking KL + Comedy of Estimators)
场景 推荐 placement 备注 on-policy(rollout 当步反传,无 PPO mini-batch 多步 update) (P1) k1 in reward 或 (P2) k2 as loss 两者在 on-policy 下 gradient-equivalent,都是严格 reverse-KL gradient off-policy(PPO mini-batch 多次走 same data) (P1) k1 in reward + IS correction:$\rho\cdot\Delta$,$\rho = \pi_\theta^\text{new}/\pi_\theta^\text{old}$ 否则 reward 与当前 policy mismatch 历史 GRPO/DeepSeekMath/DAPO 实现 (P3) k3 as loss 有 $O(\Delta^2)$ gradient bias,实际工程里 $\Delta$ 很小(β 锚得紧),所以仍能跑;但不是理论 principled value-side monitoring(看 KL 数值多大) k3 estimator 仍是首选 无偏、非负、低方差——这就是 §2.4 那三大性质 §4 β 调度
4.1 固定 β —— baseline
4.2 Adaptive β —— Schulman PPO-Penalty 原版
4.3 β annealing schedule —— 类似 learning rate schedule
4.4 β 失败模式
β 设置 现象 诊断 β 太大 ($> 1$) KL ≈ 0,policy 卡在 ref 附近,RM reward 不涨 看 reward curve 是平的 / chosen_logp - rejected_logp 不分离β 太小 ($< 0.001$) KL 爆炸(runaway),policy 越来越长 / 谄媚 / 重复 看 KL 曲线持续上升、generation length 上升、人工评测下降 β 突变 训练 loss 跳跃 adaptive 频率太高 / target_kl 太严 4.5 Adaptive β 代码示例
class AdaptiveKLController:
"""
Schulman 2017 PPO-Penalty style adaptive β controller.
每个 PPO epoch 后调用 update(measured_kl)。
"""
def __init__(self, beta_init=0.02, target_kl=0.01, horizon=10000):
self.beta = beta_init
self.target_kl = target_kl
self.horizon = horizon # 平滑系数 (越大越缓)
def update(self, measured_kl, n_steps):
# proportional update; clip to prevent extreme jumps
proportional_error = max(-0.2, min(0.2,
measured_kl / self.target_kl - 1.0))
mult = 1.0 + proportional_error * n_steps / self.horizon
self.beta *= mult
# safety clamp
self.beta = max(1e-4, min(1.0, self.beta))
return self.betakl_ctrl = AdaptiveKLController(beta_init=0.02, target_kl=0.01)
for epoch in range(num_epochs):
# ... rollout and PPO update ...
measured_kl = compute_mean_kl(policy, ref_policy, batch) # k3 推荐
kl_ctrl.update(measured_kl, n_steps=batch_size)
current_beta = kl_ctrl.beta§5 KL 与 DPO / GRPO / SimPO / KTO / IPO 的关系
5.1 DPO:implicit reward = β × sequence log-density ratio
5.1.1 DPO 闭式推导回顾
5.1.2 DPO 梯度的 KL 解释
5.2 GRPO:k3 KL in loss
5.3 SimPO:去掉 reference,没有 KL anchor
5.4 KTO / IPO / ORPO 的 KL 处理
算法 KL 形式 备注 KTO (Ethayarajh 2024 ICML) 通过 reference point $z_0 = \mathbb{E}[\beta\cdot\text{KL}]$(batch mismatched pair 估,detach) KL 隐式地"作 anchor":implicit reward 偏离 $z_0$ 多远 IPO (Azar 2024 AISTATS) 与 DPO 同($\log(\pi/\pi_\text{ref})$),但损失从 sigmoid 改 squared 防止 deterministic preference 下 $\hat{r}$ 无界增长 ORPO (Hong 2024 EMNLP) 无 reference model(与 SimPO 类似),用 odds-ratio 代替 一阶段同时做 SFT + preference;KL anchor 隐含在 SFT loss 里 5.5 Recent papers (2024-2026)
论文 主张 KL 角度 DeepSeekMath GRPO (Shao et al. 2024 arXiv 2402.03300) 组内归一化 + k3 KL in loss 第一个在 LLM RL 中默认 k3 KL DPO Implicit Reward Models (Rafailov 2023 NeurIPS) DPO 的 implicit reward 等价于 KL log-ratio DPO 本质是 KL-regularized 优化的反解 Reward Model Overoptimization Scaling Laws (Gao, Schulman, Hilton 2023 ICML) gold reward 在 KL 距离上 inverted-U KL 是 overoptimization 的天然 x-axis DAPO (Yu et al. 2025 ByteDance arXiv 2503.14476) clip-higher + dynamic sampling + token-level loss KL 项常被设小或关掉,加入清理 prompt 的 dynamic sampling Cohere DRO / OPO (各种 2024-2025 工作) offline IS-correction RL with KL 把 IS-correction 与 KL anchor 联合 "Rethinking KL Regularization in RLHF: From Value Estimation to Gradient Optimization" (Kezhao Liu et al. 2025-10, arXiv 2510.01555) 系统区分 KL value estimation 与 gradient optimization:k3-as-loss 是 biased first-order approximation;推荐 (1) k1 in reward(严格 reverse-KL score-function gradient)或 (2) k2 as loss(value estimator 有偏,但 on-policy loss gradient 严格等价于 k1-in-reward / reverse-KL gradient);off-policy 还需 IS correction 历史 GRPO 的"k3 as loss"是工程惯例不是理论 principled "A Comedy of Estimators: On KL Regularization in RL Training of LLMs" (Vedant Shah et al. 2025-12, arXiv 2512.21852, v3 2026-03) 在多种 RL 算法 + estimator placement 组合上系统对比 k1/k2/k3 的 estimator bias 与 gradient bias;分析 placement-effect 不存在 universally 最好的 estimator;reward-shaping vs loss-term 各有适用场景 §6 Theoretical:KL-Regularized RL 的最优 policy + Reward Overoptimization
6.1 KL-Regularized RL 闭式解(DPO 的数学基础)
6.2 从最优 policy 反解 implicit reward
6.3 Bradley-Terry 偏好模型下的 RL 等价于 DPO
6.4 Reward Overoptimization(Gao, Schulman, Hilton 2023 ICML)
6.4.1 问题表述
6.4.2 Gao 2023 给的拟合形式
6.4.3 KL 是 overoptimization 的"天然 axis"
(measured_KL, gold_reward) 画图,看是否进入下降区——这是最直接的 "stop 早一点" 信号。6.5 KL 与 $\chi^2$ gap 的关系
6.6 Sequence-level vs Token-level KL
# Per-token KL with action mask (chat / agentic RL setting)
def per_token_kl_with_mask(logp_theta, logp_ref, action_mask, estimator="k3"):
"""
logp_theta, logp_ref: [B, T] per-token log-prob
action_mask: [B, T] 1 = assistant token, 0 = prompt/system/pad
estimator: "k1" | "k2" | "k3"
Returns: mean KL over assistant tokens, scalar.
"""
log_r = logp_theta - logp_ref
if estimator == "k1":
kl_per_tok = log_r
elif estimator == "k2":
kl_per_tok = 0.5 * log_r ** 2
elif estimator == "k3":
delta = -log_r # log(π_ref / π_θ)
kl_per_tok = torch.exp(delta) - delta - 1.0
else:
raise ValueError(f"Unknown estimator: {estimator}")
masked = (kl_per_tok * action_mask).sum()
n = action_mask.sum().clamp_min(1.0)
return masked / n§7 实践 + 代码
7.1 PPO 风格:In-reward shaping 实现
import torch
import torch.nn.functional as F
def ppo_reward_with_kl(rewards_terminal, rollout_logp_theta, logp_ref,
action_mask, beta=0.02):
"""
PPO / InstructGPT style: KL penalty in reward (k1 estimator).
rewards_terminal: [B] only the last assistant token gets the RM reward
rollout_logp_theta: [B, T] log π_θ_old(y_t | ...), recorded during rollout, DETACHED
logp_ref: [B, T] log π_ref(y_t | ...), reference policy frozen
action_mask: [B, T] 1 = assistant token
Returns: shaped_reward [B, T] per-token reward with KL penalty baked in.
⚠️ 关键:rollout_logp_theta 和 logp_ref 必须是 detached scalars(rollout 阶段记录或 no_grad
forward)。这里 shaped reward 是 PPO/score-function 反传中的 reward tensor,**不能携带梯度**;
否则 backward 时 KL 项会和 PG surrogate 双重反传,破坏 score-function 语义。生产代码里通常在
rollout buffer 中把 logp_old 当固定数据保存,update 阶段重新 forward 拿 new_logp。
"""
B, T = rollout_logp_theta.shape
# k1 KL per token (signed; mean is unbiased). Both inputs assumed detached.
kl_per_tok = (rollout_logp_theta.detach() - logp_ref.detach()) * action_mask # [B, T]
# spread terminal reward to last assistant token
last_token_idx = action_mask.cumsum(dim=-1).argmax(dim=-1) # [B]
R_per_tok = torch.zeros_like(kl_per_tok)
R_per_tok[torch.arange(B), last_token_idx] = rewards_terminal
# combine
shaped = R_per_tok - beta * kl_per_tok
return shaped # 整个 tensor 是 detached / 无梯度,作为 PPO advantage 计算的数据输入7.2 GRPO 风格:In-loss regularization 实现(k3)
def grpo_loss_with_k3_kl(policy, ref_policy, batch, eps_clip=0.2, beta=0.04):
"""
GRPO / DeepSeekMath style: KL penalty in loss (k3 estimator).
batch:
input_ids: [N, L] N = sum_b G_b samples
action_mask: [N, L]
old_log_probs: [N, L]
rewards: [N] sequence-level reward
group_id: [N] which prompt
"""
rewards = batch["rewards"]
gid = batch["group_id"].long()
num_groups = int(gid.max().item()) + 1
# Group-relative advantage (z-score within group)
counts = torch.zeros(num_groups, device=rewards.device).scatter_add_(
0, gid, torch.ones_like(rewards))
sums = torch.zeros(num_groups, device=rewards.device).scatter_add_(
0, gid, rewards)
group_mean = sums / counts.clamp_min(1.0)
diff_sq = (rewards - group_mean[gid]) ** 2
sq_sums = torch.zeros(num_groups, device=rewards.device).scatter_add_(
0, gid, diff_sq)
group_std = (sq_sums / counts.clamp_min(1.0)).sqrt()
A = (rewards - group_mean[gid]) / (group_std[gid] + 1e-8)
A = A.unsqueeze(-1) # [N, 1] shared per token
# Forward pass policy + ref
logits = policy(batch["input_ids"]).logits[:, :-1]
log_probs = F.log_softmax(logits, dim=-1)
tgt = batch["input_ids"][:, 1:].unsqueeze(-1)
new_log_probs = log_probs.gather(-1, tgt).squeeze(-1)
new_log_probs = F.pad(new_log_probs, (1, 0)) # [N, L]
mask = batch["action_mask"].float()
with torch.no_grad():
ref_logits = ref_policy(batch["input_ids"]).logits[:, :-1]
ref_log_probs = F.log_softmax(ref_logits, dim=-1)
ref_token_lp = ref_log_probs.gather(-1, tgt).squeeze(-1)
ref_token_lp = F.pad(ref_token_lp, (1, 0))
# PPO-Clip surrogate (advantage shared per sample)
ratio = torch.exp(new_log_probs - batch["old_log_probs"])
surr1 = ratio * A
surr2 = torch.clamp(ratio, 1 - eps_clip, 1 + eps_clip) * A
pg_per_tok = torch.min(surr1, surr2) # [N, L]
# k3 KL per token: exp(Δ) - Δ - 1, Δ = log(π_ref / π_θ)
delta = ref_token_lp - new_log_probs # log(π_ref / π_θ)
kl_per_tok_k3 = torch.exp(delta) - delta - 1.0 # ≥ 0
# Combine: maximize PG - β·KL → minimize -PG + β·KL
token_obj = pg_per_tok - beta * kl_per_tok_k3
seq_len = mask.sum(dim=-1).clamp_min(1.0)
per_seq = (token_obj * mask).sum(dim=-1) / seq_len
loss = -per_seq.mean()
with torch.no_grad():
kl_mean = (kl_per_tok_k3 * mask).sum() / mask.sum().clamp_min(1.0)
return loss, {"kl_k3": kl_mean.item(), "advantage_std": A.std().item()}7.3 DPO 闭式 loss + implicit reward 监控
def dpo_loss_with_implicit_reward_monitor(policy, ref_policy, batch, beta=0.1):
"""
DPO loss + implicit reward margin (β × pointwise sequence log-density ratio on
preference data; this is NOT a KL estimator on preference data — only equals
β·KL when expectation is taken under y~π_θ, which doesn't hold for fixed preference pairs).
"""
def log_prob_sum(model, ids, mask):
logits = model(ids).logits[:, :-1]
logp = F.log_softmax(logits, dim=-1)
tgt = ids[:, 1:].unsqueeze(-1)
token_logp = logp.gather(-1, tgt).squeeze(-1)
token_mask = mask[:, 1:]
return (token_logp * token_mask).sum(dim=-1)
pi_w = log_prob_sum(policy, batch["chosen_ids"], batch["chosen_mask"])
pi_l = log_prob_sum(policy, batch["rejected_ids"], batch["rejected_mask"])
with torch.no_grad():
ref_w = log_prob_sum(ref_policy, batch["chosen_ids"], batch["chosen_mask"])
ref_l = log_prob_sum(ref_policy, batch["rejected_ids"], batch["rejected_mask"])
# sequence-level log-density ratios on preference data
log_ratio_w = pi_w - ref_w # Σ_t log(π_θ/π_ref) on y_w
log_ratio_l = pi_l - ref_l
diff = beta * (log_ratio_w - log_ratio_l)
loss = -F.logsigmoid(diff).mean()
# implicit rewards (DPO 定义:β × pointwise sequence log-ratio,detached for logging)
chosen_reward = beta * log_ratio_w.detach()
rejected_reward = beta * log_ratio_l.detach()
margin = (chosen_reward - rejected_reward).mean()
# ⚠️ 注意:preference data 上的 log-ratio 平均**不是** KL estimator——KL 需要 y ~ π_θ 采样。
# 这里只能监控"模型在 preference 数据上偏离 ref 的程度",是 DPO 训练健康度指标,不能当 KL 看。
avg_pref_log_ratio = ((log_ratio_w.detach() + log_ratio_l.detach()) / 2).mean()
return loss, {"margin": margin.item(),
"avg_pref_log_ratio": avg_pref_log_ratio.item(),
"chosen_reward": chosen_reward.mean().item(),
"rejected_reward": rejected_reward.mean().item()}7.4 Reward overoptimization 监控
def overoptimization_monitor(policy, ref_policy, gold_reward_fn, prompts,
checkpoints_kl, gold_at_kl):
"""
Track gold reward as a function of measured KL distance during training.
Call periodically; plot (measured_KL, gold_reward) to visualize the inverted-U.
Args:
policy: current π_θ
ref_policy: frozen π_ref
gold_reward_fn: callable (text -> float), uses gold RM or human eval
prompts: list of held-out prompts (small, e.g. 64)
checkpoints_kl: running list of KL values across training
gold_at_kl: running list of gold reward values
"""
measured_kl_total = 0.0
gold_reward_total = 0.0
for prompt in prompts:
# Generate from policy and ref; compute per-token k3 KL on policy generation
out_policy = policy.generate(prompt, do_sample=True)
# ... (use generate to get logits, mask, compute k3 KL) ...
# For simplicity here, just track the average sequence-level KL
kl_seq = compute_seq_kl_k3(policy, ref_policy, out_policy)
gold = gold_reward_fn(out_policy)
measured_kl_total += kl_seq
gold_reward_total += gold
avg_kl = measured_kl_total / len(prompts)
avg_gold = gold_reward_total / len(prompts)
checkpoints_kl.append(avg_kl)
gold_at_kl.append(avg_gold)
# Detection heuristic: if last 5 gold values are decreasing while KL is rising,
# we are likely in the over-optimization regime.
if len(gold_at_kl) >= 5:
recent_gold = gold_at_kl[-5:]
recent_kl = checkpoints_kl[-5:]
if all(recent_gold[i] >= recent_gold[i+1] for i in range(4)) \
and all(recent_kl[i] <= recent_kl[i+1] for i in range(4)):
print(f"⚠️ Possible reward over-optimization: KL ↑, gold ↓ over 5 checkpoints")
return avg_kl, avg_gold7.5 工程清单(debug checklist)
ref_policy.eval() + torch.no_grad(),ref 跟着训,KL 变成 self-distillation。exp(delta) - delta - 1 在 $\Delta$ 大时仍可能溢出,可以加 torch.clamp(delta, max=10) 或换数值稳定 form。§8 失败模式:KL Collapse / Runaway / Reward Hacking
8.1 KL Collapse(β 过大或 entropy 太低)
8.2 KL Runaway(β 过小或 reward 信号太强)
8.3 Reward Overoptimization(KL 距离的 inverted-U)
8.4 Length bias(DPO 特有,也可视作 KL anchor 不够强)
8.5 Reference policy "wrong checkpoint" failure
§9 25 高频面试题
L1 必会题(10 题)
Q1.KL 散度的定义和 3 个核心性质?
Q2.RLHF 里为什么要加 KL penalty?
Q3.k1 estimator 是什么?为什么单样本可以为负?
Q4.k3 estimator (Schulman 2020) 公式是什么?三大性质?
Q5.KL 在 RLHF 中有哪两种放置?区别?
Q6.β 怎么调?太大太小各有什么症状?
Q7.Forward KL vs Reverse KL 在 RLHF 里用哪个?为什么?
Q8.DPO 的 implicit reward 跟 KL 有什么关系?
Q9.Reward overoptimization 是什么?为什么发生?
Q10.GRPO 为什么历史上用 k3 不用 k1?
L2 进阶题(10 题)
Q11.推导 k3 的无偏性。
Q12.从 $f(x) = e^x - x - 1$ 推导 k3 estimator。
Q13.推 BT preference 下 KL-regularized RL 的闭式最优 policy。
Q14.推 DPO loss 从 §6.1 的闭式 $\pi^*$ 开始。
Q15.推 DPO 梯度。
Q16.k2 estimator 为什么有偏?小 KL 极限下偏多少?
Q17.Adaptive β 与 PID controller 的类比?
Q18.GRPO 的 k3 KL 在 reward 是 binary (0/1) 时怎么调 β?
Q19.SimPO 没有 reference model,为什么还能 work?没了 KL anchor 不是会 reward hack 吗?
Q20.Per-token KL 和 sequence-level KL 是什么关系?
L3 顶级 lab 题(5 题)
Q21.证明 $f(x) = e^x - x - 1 \ge 0$ 对所有 $x \in \mathbb{R}$。从该不等式出发,推导 k3 的非负性、无偏性。哪个性质对 "KL 作为 loss 加项" 更关键,为什么?
Q22.推导 DPO 的 implicit reward 与 KL-regularized RL 的 policy gradient 之间的"对偶等价性"。
Q23.从 $\sqrt{\text{KL}}$ 和 inverted-U gold curve 推 reward overoptimization 的"安全 KL budget"。
Q24.如果让你设计一个 RLHF 算法,把 reverse + forward KL 联合用,会怎么用?
Q25.下一代 RLHF 算法可能怎么改进 KL regularization?给 3 个方向 + trade-off。
§A 附录:参考文献清单
/arxiv 或 codex web_search 重新查证。http://joschu.net/blog/kl-approx.html(k1 / k2 / k3 estimator 的标准来源)https://zhuanlan.zhihu.com/p/1979720260128118305 — KL 进阶:Forward KL、Reverse KL、KL 估计与应用(已核验,主题与 RLHF KL estimator 一致)https://zhuanlan.zhihu.com/p/1892008158626546312 — [needs-verify URL accessibility] 题目疑似涉及 k2-loss vs k3-loss / GRPO off-policy / clip_std;用户校验时若链接失效可替换。docs/tutorials/rlhf_dpo_grpo_ppo_tutorial.md — RLHF / DPO / GRPO / PPO 总览(包含 BT + 闭式 + DPO 推导)docs/tutorials/reasoning_models_tutorial.md — Reasoning models 的 RL 训练细节docs/tutorials/agentic_rl_tutorial.md — Agentic setting 下的 token mask + KL 讨论