1211 lines
124 KiB
HTML
1211 lines
124 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="zh-CN">
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||
<title>Kl Divergence Rlhf Tutorial</title>
|
||
|
||
<meta name="generator" content="ARIS render-html (academic, v1)">
|
||
<meta name="aris:source-path" content="docs/tutorials/kl_divergence_rlhf_tutorial.md">
|
||
<meta name="aris:source-sha256" content="f0b8b5e62023c40790eecc3c8e2e1afdf9fceea26ffa5b9859d0d4382cb7ea4a">
|
||
<meta name="aris:generated-at" content="2026-05-19 19:13 UTC">
|
||
|
||
<!-- MathJax 3 -->
|
||
<script>
|
||
window.MathJax = {
|
||
tex: { inlineMath: [['$', '$'], ['\\(', '\\)']], displayMath: [['$$', '$$'], ['\\[', '\\]']], processEscapes: true },
|
||
options: { skipHtmlTags: ['script', 'noscript', 'style', 'textarea', 'pre', 'code'] }
|
||
};
|
||
</script>
|
||
<script src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js" async></script>
|
||
|
||
<!-- highlight.js -->
|
||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/highlightjs/cdn-release@11.9.0/build/styles/atom-one-light.min.css">
|
||
<script src="https://cdn.jsdelivr.net/gh/highlightjs/cdn-release@11.9.0/build/highlight.min.js"></script>
|
||
<script>document.addEventListener('DOMContentLoaded', () => hljs.highlightAll());</script>
|
||
|
||
|
||
<style>
|
||
:root {
|
||
--bg: #fdfcf7;
|
||
--bg-soft: #f4f1ea;
|
||
--bg-code: #f8f5ec;
|
||
--ink: #1a1a1a;
|
||
--ink-soft: #4a4a4a;
|
||
--ink-muted: #6b6b6b;
|
||
--primary: #1a4a8c;
|
||
--primary-soft: #2d6cb8;
|
||
--accent: #b8390e;
|
||
--warn: #b45309;
|
||
--warn-bg: #fef3c7;
|
||
--info-bg: #dbeafe;
|
||
--good-bg: #d1fae5;
|
||
--good: #065f46;
|
||
--bad-bg: #fee2e2;
|
||
--bad: #991b1b;
|
||
--border: #d6d0c0;
|
||
--border-soft: #e8e3d5;
|
||
}
|
||
|
||
* { box-sizing: border-box; }
|
||
html { scroll-behavior: smooth; }
|
||
|
||
body {
|
||
font-family: "Source Serif Pro", "Source Serif 4", "Crimson Pro", "Georgia", "Songti SC", "STSong", serif;
|
||
line-height: 1.65;
|
||
color: var(--ink);
|
||
background: var(--bg);
|
||
margin: 0;
|
||
padding: 0;
|
||
font-size: 16px;
|
||
}
|
||
|
||
.layout {
|
||
max-width: 1280px;
|
||
margin: 0 auto;
|
||
display: grid;
|
||
grid-template-columns: 260px 1fr;
|
||
gap: 48px;
|
||
padding: 40px 32px;
|
||
}
|
||
|
||
nav.toc {
|
||
position: sticky;
|
||
top: 24px;
|
||
align-self: start;
|
||
font-size: 13px;
|
||
max-height: calc(100vh - 48px);
|
||
overflow-y: auto;
|
||
border-right: 1px solid var(--border-soft);
|
||
padding-right: 16px;
|
||
}
|
||
nav.toc h3 {
|
||
margin: 0 0 12px;
|
||
font-size: 12px;
|
||
text-transform: uppercase;
|
||
letter-spacing: 0.08em;
|
||
color: var(--ink-muted);
|
||
font-weight: 600;
|
||
}
|
||
nav.toc ol { list-style: none; padding: 0; margin: 0; counter-reset: toc; }
|
||
nav.toc ol li { margin: 5px 0; counter-increment: toc; }
|
||
nav.toc ol li::before { content: counter(toc) ". "; color: var(--ink-muted); margin-right: 4px; }
|
||
nav.toc a {
|
||
color: var(--ink-soft);
|
||
text-decoration: none;
|
||
border-bottom: 1px dotted transparent;
|
||
}
|
||
nav.toc a:hover { color: var(--primary); border-bottom-color: var(--primary); }
|
||
nav.toc ul { list-style: none; padding-left: 14px; margin: 3px 0; font-size: 12px; }
|
||
nav.toc ul li::before { content: "→ "; color: var(--border); }
|
||
|
||
main { min-width: 0; }
|
||
|
||
header.hero {
|
||
border-bottom: 3px double var(--primary);
|
||
padding-bottom: 24px;
|
||
margin-bottom: 32px;
|
||
}
|
||
header.hero .eyebrow {
|
||
color: var(--accent);
|
||
font-size: 13px;
|
||
text-transform: uppercase;
|
||
letter-spacing: 0.12em;
|
||
font-weight: 600;
|
||
margin-bottom: 8px;
|
||
}
|
||
header.hero h1 {
|
||
font-size: 32px;
|
||
line-height: 1.2;
|
||
margin: 0 0 12px;
|
||
color: var(--ink);
|
||
font-weight: 700;
|
||
letter-spacing: -0.01em;
|
||
}
|
||
header.hero .subtitle {
|
||
font-size: 16px;
|
||
color: var(--ink-soft);
|
||
margin: 0 0 8px;
|
||
font-style: italic;
|
||
}
|
||
header.hero .byline {
|
||
font-size: 14px;
|
||
color: var(--ink-soft);
|
||
margin: 0 0 20px;
|
||
}
|
||
header.hero .byline strong {
|
||
color: var(--ink);
|
||
font-weight: 600;
|
||
}
|
||
header.hero .meta {
|
||
display: flex;
|
||
gap: 20px;
|
||
flex-wrap: wrap;
|
||
font-size: 12px;
|
||
color: var(--ink-muted);
|
||
border-top: 1px solid var(--border-soft);
|
||
padding-top: 14px;
|
||
}
|
||
header.hero .meta span strong { color: var(--ink-soft); }
|
||
header.hero .meta code {
|
||
font-family: "JetBrains Mono", "SF Mono", "Menlo", "Consolas", monospace;
|
||
font-size: 11px;
|
||
background: var(--bg-soft);
|
||
padding: 1px 5px;
|
||
border-radius: 3px;
|
||
border: 1px solid var(--border-soft);
|
||
}
|
||
|
||
h2 {
|
||
font-size: 24px;
|
||
margin: 44px 0 14px;
|
||
padding-bottom: 8px;
|
||
border-bottom: 1px solid var(--border);
|
||
color: var(--ink);
|
||
font-weight: 700;
|
||
}
|
||
h2 .num { color: var(--primary); font-weight: 600; margin-right: 8px; }
|
||
h3 { font-size: 19px; margin: 28px 0 10px; color: var(--primary); font-weight: 600; }
|
||
h4 { font-size: 16px; margin: 20px 0 8px; color: var(--ink); font-weight: 600; }
|
||
|
||
p { margin: 10px 0; }
|
||
ul, ol { padding-left: 22px; margin: 10px 0; }
|
||
ul li, ol li { margin: 4px 0; }
|
||
ul li::marker { color: var(--primary); }
|
||
|
||
strong { color: var(--accent); font-weight: 600; }
|
||
em { color: var(--ink-soft); }
|
||
|
||
a { color: var(--primary); }
|
||
a:hover { color: var(--accent); }
|
||
|
||
code:not(.hljs) {
|
||
font-family: "JetBrains Mono", "SF Mono", "Menlo", "Consolas", monospace;
|
||
font-size: 0.86em;
|
||
background: var(--bg-code);
|
||
padding: 1px 5px;
|
||
border-radius: 3px;
|
||
border: 1px solid var(--border-soft);
|
||
color: var(--accent);
|
||
}
|
||
|
||
pre {
|
||
background: #fafaf6;
|
||
border: 1px solid var(--border);
|
||
border-left: 4px solid var(--primary);
|
||
padding: 0;
|
||
overflow-x: auto;
|
||
border-radius: 4px;
|
||
margin: 14px 0;
|
||
}
|
||
pre code, pre code.hljs {
|
||
background: transparent !important;
|
||
display: block;
|
||
padding: 14px 18px !important;
|
||
font-size: 13px;
|
||
line-height: 1.55;
|
||
font-family: "JetBrains Mono", "SF Mono", "Menlo", monospace;
|
||
color: var(--ink);
|
||
}
|
||
pre.diagram {
|
||
background: #f9f6ed;
|
||
border-left: 4px solid var(--accent);
|
||
font-size: 12.5px;
|
||
line-height: 1.4;
|
||
}
|
||
|
||
.callout {
|
||
margin: 16px 0;
|
||
padding: 12px 16px;
|
||
border-radius: 4px;
|
||
border-left: 4px solid;
|
||
font-size: 15px;
|
||
}
|
||
.callout-title {
|
||
font-weight: 600;
|
||
margin-bottom: 6px;
|
||
font-size: 12px;
|
||
text-transform: uppercase;
|
||
letter-spacing: 0.06em;
|
||
}
|
||
.callout-info { background: var(--info-bg); border-left-color: var(--primary); }
|
||
.callout-info .callout-title { color: var(--primary); }
|
||
.callout-warn { background: var(--warn-bg); border-left-color: var(--warn); }
|
||
.callout-warn .callout-title { color: var(--warn); }
|
||
.callout-good { background: var(--good-bg); border-left-color: var(--good); }
|
||
.callout-good .callout-title { color: var(--good); }
|
||
.callout-bad { background: var(--bad-bg); border-left-color: var(--bad); }
|
||
.callout-bad .callout-title { color: var(--bad); }
|
||
|
||
table {
|
||
width: 100%;
|
||
border-collapse: collapse;
|
||
margin: 16px 0;
|
||
font-size: 14px;
|
||
border: 1px solid var(--border);
|
||
border-radius: 4px;
|
||
overflow: hidden;
|
||
}
|
||
thead { background: var(--primary); color: white; }
|
||
th, td {
|
||
text-align: left;
|
||
padding: 9px 12px;
|
||
border-bottom: 1px solid var(--border-soft);
|
||
vertical-align: top;
|
||
}
|
||
th { font-weight: 600; font-size: 13px; letter-spacing: 0.02em; }
|
||
tr:last-child td { border-bottom: none; }
|
||
tbody tr:nth-child(even) { background: var(--bg-soft); }
|
||
|
||
details.qa, details {
|
||
background: white;
|
||
border: 1px solid var(--border-soft);
|
||
border-radius: 6px;
|
||
margin: 10px 0;
|
||
padding: 0;
|
||
}
|
||
details summary {
|
||
cursor: pointer;
|
||
padding: 10px 14px;
|
||
font-weight: 600;
|
||
font-size: 14px;
|
||
color: var(--primary);
|
||
list-style: none;
|
||
user-select: none;
|
||
}
|
||
details summary::-webkit-details-marker { display: none; }
|
||
details summary::before {
|
||
content: "▸ ";
|
||
margin-right: 4px;
|
||
display: inline-block;
|
||
transition: transform 0.15s;
|
||
}
|
||
details[open] summary::before { transform: rotate(90deg); }
|
||
details[open] summary { border-bottom: 1px solid var(--border-soft); }
|
||
details > :not(summary) { padding: 10px 14px; }
|
||
details p:first-of-type { margin-top: 8px; }
|
||
|
||
mjx-container[display="true"] { margin: 12px 0 !important; }
|
||
|
||
footer.aris-footer {
|
||
margin-top: 60px;
|
||
padding-top: 20px;
|
||
border-top: 1px solid var(--border);
|
||
font-size: 12px;
|
||
color: var(--ink-muted);
|
||
}
|
||
footer.aris-footer a { color: var(--ink-muted); border-bottom: 1px dotted var(--border); }
|
||
|
||
@media (max-width: 900px) {
|
||
.layout { grid-template-columns: 1fr; gap: 20px; padding: 20px 16px; }
|
||
nav.toc {
|
||
position: static;
|
||
max-height: none;
|
||
border-right: none;
|
||
border-bottom: 1px solid var(--border-soft);
|
||
padding-right: 0;
|
||
padding-bottom: 14px;
|
||
}
|
||
header.hero h1 { font-size: 24px; }
|
||
h2 { font-size: 20px; }
|
||
}
|
||
@media print {
|
||
nav.toc { display: none; }
|
||
.layout { grid-template-columns: 1fr; padding: 0; }
|
||
body { background: white; }
|
||
header.hero { border-bottom-color: var(--ink); }
|
||
}
|
||
</style>
|
||
</head>
|
||
<body>
|
||
<div class="layout">
|
||
|
||
<nav class="toc">
|
||
<h3>Contents</h3>
|
||
<ol>
|
||
<li><a href="#0-tldr-cheat-sheet">§0 TL;DR Cheat Sheet</a>
|
||
</li>
|
||
<li><a href="#1-kl-基础">§1 KL 基础</a>
|
||
<ul>
|
||
<li><a href="#11-定义性质记号">1.1 定义、性质、记号</a></li>
|
||
<li><a href="#12-forward-kl-vs-reverse-klmass-covering-还是-mode-seeking">1.2 Forward KL vs Reverse KL:mass-covering 还是 mode-seeking?</a></li>
|
||
<li><a href="#13-与其他-divergence-的关系">1.3 与其他 divergence 的关系</a></li>
|
||
<li><a href="#14-为什么-rlhf-要加-kl">1.4 为什么 RLHF 要加 KL?</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a href="#2-kl-estimatorsk1--k2--k3面试核心">§2 KL Estimators(k1 / k2 / k3):面试核心</a>
|
||
<ul>
|
||
<li><a href="#21-问题设置">2.1 问题设置</a></li>
|
||
<li><a href="#22-k1-estimator--直接代入定义">2.2 k1 estimator —— "直接代入定义"</a></li>
|
||
<li><a href="#23-k2-estimator--l2-form">2.3 k2 estimator —— "$L^2$ form"</a></li>
|
||
<li><a href="#24-k3-estimator-schulman-2020-blog--非负无偏-value-estimator但作为-loss-项是-biased-gradient见-36">2.4 k3 estimator (Schulman 2020 blog) —— **非负无偏 value estimator**(但作为 loss 项是 biased gradient,见 §3.6)</a></li>
|
||
<li><a href="#25-三者对比表">2.5 三者对比表</a></li>
|
||
<li><a href="#26-代码三估计器--variance-对比-simulation">2.6 代码:三估计器 + variance 对比 simulation</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a href="#3-kl-在-rlhf-中的两种放置">§3 KL 在 RLHF 中的两种放置</a>
|
||
<ul>
|
||
<li><a href="#31-option-ain-reward-shapingppo-rlhf--instructgpt-标准做法">3.1 Option A:In-reward shaping(PPO RLHF / InstructGPT 标准做法)</a></li>
|
||
<li><a href="#32-option-bin-loss-regularizationgrpo--dapo-做法">3.2 Option B:In-loss regularization(GRPO / DAPO 做法)</a></li>
|
||
<li><a href="#33-两者数学上等价工程上不等价">3.3 两者数学上等价?工程上不等价</a></li>
|
||
<li><a href="#34-实操哪一种用在哪">3.4 实操:哪一种用在哪?</a></li>
|
||
<li><a href="#36-estimator-placement-的-gradient-bias-分析rethinking-kl-regularization-in-rlhf">3.6 Estimator placement 的 gradient bias 分析(Rethinking KL Regularization in RLHF)</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a href="#4--调度">§4 β 调度</a>
|
||
<ul>
|
||
<li><a href="#41-固定---baseline">4.1 固定 β —— baseline</a></li>
|
||
<li><a href="#42-adaptive---schulman-ppo-penalty-原版">4.2 Adaptive β —— Schulman PPO-Penalty 原版</a></li>
|
||
<li><a href="#43--annealing-schedule--类似-learning-rate-schedule">4.3 β annealing schedule —— 类似 learning rate schedule</a></li>
|
||
<li><a href="#44--失败模式">4.4 β 失败模式</a></li>
|
||
<li><a href="#45-adaptive--代码示例">4.5 Adaptive β 代码示例</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a href="#5-kl-与-dpo--grpo--simpo--kto--ipo-的关系">§5 KL 与 DPO / GRPO / SimPO / KTO / IPO 的关系</a>
|
||
<ul>
|
||
<li><a href="#51-dpoimplicit-reward----sequence-log-density-ratio">5.1 DPO:implicit reward = β × sequence log-density ratio</a></li>
|
||
<li><a href="#52-grpok3-kl-in-loss">5.2 GRPO:k3 KL in loss</a></li>
|
||
<li><a href="#53-simpo去掉-reference没有-kl-anchor">5.3 SimPO:去掉 reference,没有 KL anchor</a></li>
|
||
<li><a href="#54-kto--ipo--orpo-的-kl-处理">5.4 KTO / IPO / ORPO 的 KL 处理</a></li>
|
||
<li><a href="#55-recent-papers-2024-2026">5.5 Recent papers (2024-2026)</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a href="#6-theoreticalkl-regularized-rl-的最优-policy--reward-overoptimization">§6 Theoretical:KL-Regularized RL 的最优 policy + Reward Overoptimization</a>
|
||
<ul>
|
||
<li><a href="#61-kl-regularized-rl-闭式解dpo-的数学基础">6.1 KL-Regularized RL 闭式解(DPO 的数学基础)</a></li>
|
||
<li><a href="#62-从最优-policy-反解-implicit-reward">6.2 从最优 policy 反解 implicit reward</a></li>
|
||
<li><a href="#63-bradley-terry-偏好模型下的-rl-等价于-dpo">6.3 Bradley-Terry 偏好模型下的 RL 等价于 DPO</a></li>
|
||
<li><a href="#64-reward-overoptimizationgao-schulman-hilton-2023-icml">6.4 Reward Overoptimization(Gao, Schulman, Hilton 2023 ICML)</a></li>
|
||
<li><a href="#65-kl-与-chi2-gap-的关系">6.5 KL 与 $\chi^2$ gap 的关系</a></li>
|
||
<li><a href="#66-sequence-level-vs-token-level-kl">6.6 Sequence-level vs Token-level KL</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a href="#7-实践--代码">§7 实践 + 代码</a>
|
||
<ul>
|
||
<li><a href="#71-ppo-风格in-reward-shaping-实现">7.1 PPO 风格:In-reward shaping 实现</a></li>
|
||
<li><a href="#72-grpo-风格in-loss-regularization-实现k3">7.2 GRPO 风格:In-loss regularization 实现(k3)</a></li>
|
||
<li><a href="#73-dpo-闭式-loss--implicit-reward-监控">7.3 DPO 闭式 loss + implicit reward 监控</a></li>
|
||
<li><a href="#74-reward-overoptimization-监控">7.4 Reward overoptimization 监控</a></li>
|
||
<li><a href="#75-工程清单debug-checklist">7.5 工程清单(debug checklist)</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a href="#8-失败模式kl-collapse--runaway--reward-hacking">§8 失败模式:KL Collapse / Runaway / Reward Hacking</a>
|
||
<ul>
|
||
<li><a href="#81-kl-collapse-过大或-entropy-太低">8.1 KL Collapse(β 过大或 entropy 太低)</a></li>
|
||
<li><a href="#82-kl-runaway-过小或-reward-信号太强">8.2 KL Runaway(β 过小或 reward 信号太强)</a></li>
|
||
<li><a href="#83-reward-overoptimizationkl-距离的-inverted-u">8.3 Reward Overoptimization(KL 距离的 inverted-U)</a></li>
|
||
<li><a href="#84-length-biasdpo-特有也可视作-kl-anchor-不够强">8.4 Length bias(DPO 特有,也可视作 KL anchor 不够强)</a></li>
|
||
<li><a href="#85-reference-policy-wrong-checkpoint-failure">8.5 Reference policy "wrong checkpoint" failure</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a href="#9-25-高频面试题">§9 25 高频面试题</a>
|
||
<ul>
|
||
<li><a href="#l1-必会题10-题">L1 必会题(10 题)</a></li>
|
||
<li><a href="#l2-进阶题10-题">L2 进阶题(10 题)</a></li>
|
||
<li><a href="#l3-顶级-lab-题5-题">L3 顶级 lab 题(5 题)</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a href="#a-附录参考文献清单">§A 附录:参考文献清单</a>
|
||
</li>
|
||
</ol>
|
||
</nav>
|
||
|
||
<main>
|
||
<header class="hero">
|
||
|
||
<h1>Kl Divergence Rlhf Tutorial</h1>
|
||
|
||
|
||
<div class="meta">
|
||
<span><strong>Source:</strong> <code>docs/tutorials/kl_divergence_rlhf_tutorial.md</code></span>
|
||
<span><strong>SHA256:</strong> <code>f0b8b5e62023</code></span>
|
||
<span><strong>Rendered:</strong> 2026-05-19 19:13 UTC</span>
|
||
|
||
</div>
|
||
</header>
|
||
|
||
<h2 id="0-tldr-cheat-sheet">§0 TL;DR Cheat Sheet</h2>
|
||
<div class="callout callout-info"><div class="callout-title">8 句话搞定 RLHF 里的 KL</div><p>一页拿下面试核心要点(详见后文 §1–§8 推导)。</p></div>
|
||
<ol><li><strong>定义</strong>:$\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。</li><li><strong>Forward vs Reverse</strong>:约定 $p$ 为数据/目标、$q_\theta$ 为变分/优化分布——<strong>Forward KL</strong> = $\text{KL}(p\|q_\theta)$(mass-covering),<strong>Reverse KL</strong> = $\text{KL}(q_\theta\|p)$(mode-seeking)。RLHF 用 $\text{KL}(\pi_\theta \| \pi_\text{ref})$,按这个约定属于 <strong>reverse KL</strong>($\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。</li><li><p><strong>三大 KL Estimator (Schulman 2020 blog <code>joschu.net/blog/kl-approx.html</code>)</strong>:</p>
|
||
<ul><li><strong>k1</strong> = $\log(\pi_\theta/\pi_\text{ref})$ — 无偏但方差大、可负(不可读做"距离")。</li><li><strong>k2</strong> = $\tfrac{1}{2}(\log(\pi_\theta/\pi_\text{ref}))^2$ — 总是非负但<strong>有偏</strong>(二阶 Taylor 近似)。</li><li><strong>k3</strong> = $(\pi_\text{ref}/\pi_\theta) - \log(\pi_\text{ref}/\pi_\theta) - 1$ — <strong>无偏 + 非负 + 低方差</strong>,从恒等式 $\mathbb{E}_q[f(\log p/q)]$($f(x)=e^x-x-1$)导出。</li></ul></li><li><strong>两种放置</strong>:(a) <strong>In-reward shaping</strong>:$\tilde{r}_t = r_t - \beta \cdot \text{KL}_t$,与 advantage / GAE 一起算;(b) <strong>In-loss regularization</strong>:$\mathcal{L} = \mathcal{L}_\text{PG} + \beta \cdot \mathbb{E}[\text{KL}]$。<strong>InstructGPT/Anthropic PPO 用 (a);GRPO 用 (b) + k3 estimator</strong>。<strong>目标函数相同,但梯度路径不同</strong>——在 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 截断的响应也不同。</li><li><strong>β 调度</strong>:固定 β(最简单)、<strong>Adaptive β</strong>(PPO-Penalty 原版,按 measured KL 距 target 拉 β)、Annealing β(早期紧后期松,类似 SFT-to-RL 过渡)。<strong>β 过大学不到东西</strong>(policy 卡在 ref 附近),<strong>β 过小 reward hack</strong>(policy 漂掉、长答案/谄媚)。</li><li><strong>KL-regularized RL 闭式最优 policy</strong>:对 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)$。<strong>DPO 就是把这个反解代入 Bradley-Terry</strong>,得到 $r = \beta \log(\pi^*/\pi_\text{ref}) + \beta\log Z$,partition function $\log Z$ 在 pairwise 差里<strong>消掉</strong>。</li><li><strong>DPO/GRPO/SimPO 中 KL 的位置</strong>: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 直接<strong>砍掉 reference</strong>,所以<strong>没有 KL 约束</strong>——对 β/γ/length-norm 更敏感。</li><li><strong>失败模式</strong>:KL 爆炸(β 过小、importance ratio 过大)、KL collapse(β 过大或 entropy 太低,policy 卡死)、<strong>Reward Overoptimization</strong> (Gao 2023 ICML):proxy reward 随 KL 单调升,gold reward 先升后降(inverted-U),KL 距离是 overoptimization 的天然 axis。</li></ol>
|
||
<h2 id="1-kl-基础">§1 KL 基础</h2>
|
||
<h3 id="11-定义性质记号">1.1 定义、性质、记号</h3>
|
||
<p><strong>定义</strong>(离散):</p>
|
||
<p>$$\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]\;}$$</p>
|
||
<p>约定 $0 \log 0 = 0$、$0 \log(0/0) = 0$、$p \log(p/0) = +\infty$。连续分布把 $\sum$ 换成 $\int$。</p>
|
||
<p><strong>核心性质</strong>(面试常被串问):</p>
|
||
<table><thead><tr><th>性质</th><th>一句话表述</th><th>简证</th></tr></thead><tbody><tr><td><strong>非负</strong></td><td>$\text{KL} \ge 0$</td><td>Jensen + $-\log$ 凸:$\text{KL} = -\mathbb{E}_p \log(q/p) \ge -\log \mathbb{E}_p(q/p) = 0$</td></tr><tr><td><strong>等号</strong></td><td>$\text{KL} = 0$ 当且仅当 $p = q$ a.e.</td><td>Jensen 等号条件</td></tr><tr><td><strong>不对称</strong></td><td>$\text{KL}(p,q) \ne \text{KL}(q,p)$(在 $\text{KL}$ 的不对称参数中)</td><td>直接构造例子可见</td></tr><tr><td><strong>不满足三角不等式</strong></td><td>不是 metric</td><td>故"KL distance"是不严谨的口语化</td></tr><tr><td><strong>凸性</strong></td><td>$\text{KL}(\cdot,\cdot)$ 对 $(p,q)$ 联合凸</td><td>log-sum 不等式</td></tr><tr><td><strong>链式法则</strong></td><td>联合 KL 等于边际 KL 加条件 KL 期望(见下方 display 公式)</td><td>直接拆 log</td></tr><tr><td><strong>参数化不变</strong></td><td>对 $x \mapsto T(x)$ 同形变换不变(仅在可逆 $T$ 下取等号)</td><td>测度变换 + Jacobian 抵消</td></tr></tbody></table>
|
||
<p>链式法则的完整形式:</p>
|
||
<p>$$\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]$$</p>
|
||
<div class="callout callout-good"><div class="callout-title">链式法则在 RLHF 里 = per-token KL 加总</div><p>Sequence-level KL 是 trajectory log-ratio 之和的<strong>期望</strong>:$\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$ 是<strong>单条 MC estimator</strong>(k1 的 sequence 形式);要得到 true expected KL 需对 batch 内 rollout 平均。<strong>真实的 token-level KL</strong> $D_\text{KL}(\pi_\theta(\cdot|s_t)\|\pi_\text{ref}(\cdot|s_t))$ 还需对该 prefix 上整个 vocab 求和(full-vocab KL),而非只在 sampled token 上算 log-ratio。这两者<strong>期望相等</strong>但 estimator 形式不同:sum-over-rollout 的 sampled log-ratio 是 cheap-but-noisy estimator。</p></div>
|
||
<h3 id="12-forward-kl-vs-reverse-klmass-covering-还是-mode-seeking">1.2 Forward KL vs Reverse KL:mass-covering 还是 mode-seeking?</h3>
|
||
<p>记 $p$ 是数据/真实分布,$q_\theta$ 是参数化模型。两种 KL 在拟合策略上行为完全不同:</p>
|
||
<table><thead><tr><th>方向</th><th>形式(见下方 display)</th><th>期望对谁取</th><th>行为</th><th>经典用途</th></tr></thead><tbody><tr><td><strong>Forward KL</strong></td><td>$\text{KL}(p\,\</td><td>\,q_\theta) = \mathbb{E}<em>{p}[\log(p/q</em>\theta)]$</td><td>$p$(数据/目标)</td><td><strong>mass-covering / mean-seeking</strong>:哪里 $p > 0$,$q_\theta$ 必须 > 0,否则 $\log(p/q) \to \infty$</td><td>MLE / 蒸馏(学生覆盖老师)</td></tr><tr><td><strong>Reverse KL</strong></td><td>$\text{KL}(q_\theta\,\</td><td>\,p) = \mathbb{E}<em>{q</em>\theta}[\log(q_\theta/p)]$</td><td>$q_\theta$(变分/优化分布)</td><td><strong>mode-seeking / minorization</strong>:哪里 $q_\theta > 0$,$p$ 必须 > 0;$q_\theta$ 倾向找单一 mode 缩进去</td><td>VI、RLHF、GAN-like 训练</td></tr></tbody></table>
|
||
<p>记号约定:</p>
|
||
<p>$$\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>
|
||
<p>经典图(双峰 $p$,单峰 $q_\theta$):</p>
|
||
<ul><li>Forward KL 拟合 → $q_\theta$ 拉宽,跨越两个 mode(<strong>mass-covering</strong>)。</li><li>Reverse KL 拟合 → $q_\theta$ 选其中一个 mode 缩进(<strong>mode-seeking</strong>)。</li></ul>
|
||
<div class="callout callout-warn"><div class="callout-title">命名约定的现代共识</div><p>变分推断、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 教材按采样分布命名,建议在面试时直接给出公式,避免标签歧义。</p></div>
|
||
<p><strong>RLHF 用哪一种?</strong> 几乎所有主流实现(InstructGPT / Anthropic PPO / DeepSeekMath GRPO)都用 $\text{KL}(\pi_\theta \| \pi_\text{ref})$(<strong>reverse KL</strong> 形式:$\pi_\theta$ 是变分一侧,$\pi_\text{ref}$ 是 target)。<strong>根本原因</strong>:训练时我们已经从 $\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}$"。</p>
|
||
<div class="callout callout-info"><div class="callout-title">Tip</div><p>注意:把 $\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 方向。</p></div>
|
||
<h3 id="13-与其他-divergence-的关系">1.3 与其他 divergence 的关系</h3>
|
||
<table><thead><tr><th>Divergence</th><th>定义(见下方 display)</th><th>特点</th><th>备注</th></tr></thead><tbody><tr><td><strong>JS</strong></td><td>KL 到混合 $m = (p+q)/2$ 的对称平均</td><td>对称、有界($\le \log 2$)、是 metric 的平方根</td><td>$\sqrt{\text{JS}}$ 是 metric(Endres-Schindelin 2003 IEEE TIT 49(7));GAN 原版判别 loss 等价于 $2\cdot\text{JSD} - \log 4$;RLHF 极少用</td></tr><tr><td><strong>α-divergence</strong></td><td>$\frac{1}{\alpha(1-\alpha)}(1 - \int p^\alpha q^{1-\alpha})$</td><td>含 KL 作为极限</td><td>统一框架,$\alpha \to 1$ 给 forward KL、$\alpha \to 0$ 给 reverse KL</td></tr><tr><td><strong>Hellinger</strong></td><td>$H^2(p,q) = \tfrac{1}{2}\int(\sqrt{p}-\sqrt{q})^2$</td><td>对称、有界、$0 \le H^2 \le 1$</td><td>与 KL 关系:$H^2 \le \tfrac{1}{2}\text{KL}$</td></tr><tr><td><strong>$\chi^2$</strong></td><td>$\chi^2(p,q) = \int \frac{(p-q)^2}{q}$</td><td>是 $f$-divergence 在 $f(t) = (t-1)^2$ 时的特例</td><td>与 KL 关系:$\text{KL} \le \log(1 + \chi^2)$</td></tr><tr><td><strong>TV</strong></td><td>$\tfrac{1}{2}\int \lvert p-q\rvert$</td><td>是 metric、$\in [0,1]$</td><td><strong>Pinsker</strong>:$\text{TV} \le \sqrt{\text{KL}/2}$</td></tr></tbody></table>
|
||
<p>四个常见 $f$-divergence 的完整形式:</p>
|
||
<p>$$\text{JS}(p, q) = \tfrac{1}{2}\text{KL}(p \,\|\, m) + \tfrac{1}{2}\text{KL}(q \,\|\, m),\quad m = (p+q)/2$$</p>
|
||
<p>$$\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}$$</p>
|
||
<div class="callout callout-info"><div class="callout-title">为什么 RLHF 没用 JS / α-divergence?</div><p>主要是工程惯性 + 闭式优势:在 PPO/DPO 框架里 KL 有干净的 per-token 拆分(链式法则)、闭式最优解(softmax-style),且 likelihood ratio 直接给出 KL token 增量,免去额外网络估计。JS / α-divergence 要么数学没这么干净,要么需要额外 density ratio estimator。</p></div>
|
||
<h3 id="14-为什么-rlhf-要加-kl">1.4 为什么 RLHF 要加 KL?</h3>
|
||
<p>把"无 KL"和"有 KL"的目标摆一起:</p>
|
||
<p>$$\text{无 KL}:\quad \max_\pi \mathbb{E}_{x,\,y \sim \pi(\cdot|x)}[r(x,y)]$$</p>
|
||
<p>$$\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)$$</p>
|
||
<p><strong>没有 KL 会发生什么?</strong></p>
|
||
<ol><li><strong>Reward hacking</strong>:policy 找到 RM 盲点(更长答案 / "As an AI..." 套话 / 谄媚 / 格式 hack)拿高 RM 分,人感受变差。</li><li><strong>语言流畅性塌掉</strong>:policy 会输出 RM "喜欢"但人类看着像鬼话的 token 序列(极端时退化到只重复某 token / 完全不语法)。</li><li><strong>Distribution shift</strong>:policy 跑远了 $\pi_\text{ref}$,连 RM 自己都很难评分(off-distribution,RM 越没把握、reward 越随机)。</li></ol>
|
||
<p>加 KL 后:</p>
|
||
<ul><li><strong>β 提供 RM error 的 implicit regularization</strong>:当 RM 不可靠时,KL 把 policy 拉回 SFT 已知良好分布。</li><li><strong>闭式最优 policy 存在</strong>(§6.1 推导),整个 RLHF 有数学基础。</li><li><strong>DPO / KTO / GRPO 都依赖这条 KL anchor</strong>:去掉 reference 的 SimPO 实测对超参更敏感。</li></ul>
|
||
<h2 id="2-kl-estimatorsk1--k2--k3面试核心">§2 KL Estimators(k1 / k2 / k3):面试核心</h2>
|
||
<h3 id="21-问题设置">2.1 问题设置</h3>
|
||
<p>实际训练里我们要在每一个 mini-batch 估计 $\text{KL}(\pi_\theta \| \pi_\text{ref})$。但完整求和 $\sum_y \pi_\theta(y) \log \pi_\theta(y)/\pi_\text{ref}(y)$ 不可行($y$ 是整段 response,组合爆炸)。<strong>只能 Monte Carlo</strong>:用从 $\pi_\theta$ 采样的样本估 KL。</p>
|
||
<p>记 $\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})$。</p>
|
||
<div class="callout callout-warn"><div class="callout-title">记号统一</div><p>本节 $\log r$ 始终表示 <strong>policy log-ratio</strong> $\log \pi_\theta - \log \pi_\text{ref}$(<strong>不是</strong> PPO importance ratio $\pi_\theta / \pi_\text{old}$)。两者形式相近但含义不同:前者衡量"离 reference 多远",后者衡量"离 sampling policy 多远"。</p></div>
|
||
<h3 id="22-k1-estimator--直接代入定义">2.2 k1 estimator —— "直接代入定义"</h3>
|
||
<p>$$\boxed{\;\widehat{\text{KL}}_1 = \log\frac{\pi_\theta(y)}{\pi_\text{ref}(y)} = \log r\;}$$</p>
|
||
<ul><li><strong>无偏</strong>:$\mathbb{E}_{y\sim\pi_\theta}[\log r] = \text{KL}(\pi_\theta\|\pi_\text{ref})$ by definition。</li><li><strong>可负</strong>:单个样本下 $\log r$ 可正可负(log-ratio 没有"非负"约束)。</li><li><strong>方差大</strong>:tails 上 $\log r$ 可以非常大或非常小,特别是 $\pi_\theta$ 和 $\pi_\text{ref}$ 不重叠的区域。</li></ul>
|
||
<p><strong>问题</strong>:用 k1 作为"KL 监控指标"会看到<strong>负值</strong>,工程上会让 logger 显示负 KL,新人会困惑(KL 不该非负吗?)。这是因为<strong>期望非负不代表每个样本非负</strong>。但作为 reward shaping 的 per-token KL,可以接受(关键是均值无偏)。</p>
|
||
<h3 id="23-k2-estimator--l2-form">2.3 k2 estimator —— "$L^2$ form"</h3>
|
||
<p>$$\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\;}$$</p>
|
||
<ul><li><strong>总是非负</strong> ✓</li><li><strong>有偏</strong>:$\mathbb{E}[\tfrac{1}{2}(\log r)^2] \ne \text{KL}$。</li><li><strong>小 KL 极限下</strong>: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 信息度规的二次型)。</li><li><strong>方差小于 k1</strong>:因为平方后正负不再相消,但仍然不是最优。</li></ul>
|
||
<p>实践中 k2 主要用于<strong>监控</strong>(提供"non-negative,但有偏"的视觉化指标);很少用于 reward shaping。</p>
|
||
<h3 id="24-k3-estimator-schulman-2020-blog--非负无偏-value-estimator但作为-loss-项是-biased-gradient见-36">2.4 k3 estimator (Schulman 2020 blog) —— <strong>非负无偏 value estimator</strong>(但作为 loss 项是 biased gradient,见 §3.6)</h3>
|
||
<h4 id="241-构造">2.4.1 构造</h4>
|
||
<p>考虑函数 $f(x) = e^x - x - 1$。由 $e^x \ge 1 + x$(实数 $x$)得 $f(x) \ge 0$,且 $f(0) = 0$。</p>
|
||
<p>把 $x = \log(\pi_\text{ref}(y)/\pi_\theta(y)) = -\log r$ 代入:</p>
|
||
<p>$$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$$</p>
|
||
<p>等价地(用 $\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})$,两形式等价)。</p>
|
||
<p>等价地(这是 Schulman blog 中的标准写法):</p>
|
||
<p>$$\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\;}$$</p>
|
||
<h4 id="242-三大性质必考">2.4.2 三大性质(必考)</h4>
|
||
<p><strong>性质 1(非负)</strong>:</p>
|
||
<p>由 $e^\Delta - \Delta - 1 \ge 0$ 对所有 $\Delta \in \mathbb{R}$(凸函数 $e^\Delta$ 在 $\Delta = 0$ 切线 $1 + \Delta$ 之上),$\widehat{\text{KL}}_3 \ge 0$ 总是成立。</p>
|
||
<p><strong>性质 2(无偏)</strong>:</p>
|
||
<p>要证 $\mathbb{E}_{y \sim \pi_\theta}[\widehat{\text{KL}}_3] = \text{KL}(\pi_\theta\|\pi_\text{ref})$。</p>
|
||
<p>$$\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$$</p>
|
||
<p>$$\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})$$</p>
|
||
<p>所以:</p>
|
||
<p>$$\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$$</p>
|
||
<p><strong>性质 3(方差通常小于 k1)</strong>:</p>
|
||
<p>直观:$\widehat{\text{KL}}_3$ 把 $\log r$ 的线性项($-\log r/\pi_\theta$ 部分,即 k1 的等价形式 $\mathbb{E}_{\pi_\theta}[-\log(\pi_\text{ref}/\pi_\theta)]$)和一个<strong>期望为 1 的控制变量</strong> $\pi_\text{ref}/\pi_\theta - 1$ 相加。控制变量降方差(control variate):当 $r$ 大时 $\log r$ 大但 $1/r$ 小,反之亦然,<strong>两者负相关</strong>,加起来方差比单独 k1 小。</p>
|
||
<p>形式化:$\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$ 强负相关 → 减方差。</p>
|
||
<div class="callout callout-info"><div class="callout-title">k3 的 elegance</div><p>Schulman blog 2020 给出的 derivation 等价于上面:他<strong>先找一个 $f(x) \ge 0$ 且 $\mathbb{E}_q f(\log p/q) = \text{KL}$ 的函数</strong>,然后挑 $f(x) = e^x - x - 1$(最简单的非负、可微、不是 trivial 的选择)。所以 k3 不是"灵感来的"——它是"非负 + 无偏"约束下的最自然构造。</p></div>
|
||
<h4 id="243-变种与简化">2.4.3 变种与简化</h4>
|
||
<p>实际代码经常写成(<strong>对 PPO ratio $r = \pi_\theta / \pi_\text{old}$ 同样适用</strong>,但语义不同——这是 importance ratio approx,不是 policy log-ratio):</p>
|
||
<pre><code class="language-python">approx_kl_to_old = ((ratio - 1) - torch.log(ratio.clamp_min(1e-8))).mean()</code></pre>
|
||
<p>即 $\widehat{\text{KL}}_3 \approx (r - 1) - \log r$,是上面 $e^\Delta - \Delta - 1$ 的等价对偶(把 $r = e^{\log r}$ 视作 $e^\Delta$ 即可,符号约定换一下)。<strong>TRL / OpenRLHF / verl 默认 <code>approx_kl</code> 都是这个</strong>。</p>
|
||
<h3 id="25-三者对比表">2.5 三者对比表</h3>
|
||
<table><thead><tr><th>Estimator</th><th>形式</th><th>无偏?</th><th>非负?</th><th>方差</th><th>在 RLHF 里典型用途</th></tr></thead><tbody><tr><td><strong>k1</strong></td><td>$\log r$</td><td>✅</td><td>❌</td><td>大</td><td>InstructGPT PPO reward shaping(per-token KL)</td></tr><tr><td><strong>k2</strong></td><td>$\tfrac{1}{2}(\log r)^2$</td><td>❌ value-estimator 有偏(二阶近似 KL)</td><td>✅</td><td>中</td><td>value 视角常用作监控;<strong>loss-gradient 视角是 principled k2-as-loss</strong>——on-policy 下与 k1-in-reward gradient-equivalent,见 §3.6</td></tr><tr><td><strong>k3</strong></td><td>$e^{-\log r} + \log r - 1$</td><td>✅(作为 <strong>value estimator</strong>)</td><td>✅</td><td>小</td><td>DeepSeekMath GRPO / DAPO 历史用法(作为 <strong>loss</strong> 时其梯度是 biased first-order approx,见 §3.6 + Rethinking KL 论文)</td></tr></tbody></table>
|
||
<h3 id="26-代码三估计器--variance-对比-simulation">2.6 代码:三估计器 + variance 对比 simulation</h3>
|
||
<pre><code class="language-python">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).</code></pre>
|
||
<div class="callout callout-good"><div class="callout-title">运行 simulation 你会看到</div></div>
|
||
<ul><li>k1 mean ≈ 0.125, min 约 −1.5(可负),var 大。</li><li>k2 mean ≈ 0.18(偏高),min ≥ 0,var 中。</li><li>k3 mean ≈ 0.125(无偏),min ≥ 0,var <strong>明显小于</strong> k1。</li></ul>
|
||
<p>这正是 Schulman blog 给出的 takeaway:<strong>k3 同时拿到 unbiased + non-negative + 较低方差</strong>。</p>
|
||
<h2 id="3-kl-在-rlhf-中的两种放置">§3 KL 在 RLHF 中的两种放置</h2>
|
||
<h3 id="31-option-ain-reward-shapingppo-rlhf--instructgpt-标准做法">3.1 Option A:In-reward shaping(PPO RLHF / InstructGPT 标准做法)</h3>
|
||
<p>把 KL <strong>塞进 per-token reward</strong>,再正常跑 PPO + GAE:</p>
|
||
<p>$$\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_{<t})}{\pi_\text{ref}(y_t \mid x, y_{<t})}}_{\text{per-token KL (k1)}}\;}$$</p>
|
||
<p>注意细节:</p>
|
||
<ul><li><strong>per-token</strong>:每生成一个 token,就计算这个 token 的 log-prob ratio,作为该步 reward 的一部分。</li><li><strong>k1 estimator</strong>:这里直接用 $\log(\pi_\theta/\pi_\text{ref})$(k1)。注意它<strong>单 token 可为负</strong>,但作为 reward shaping 只要均值/总和符合 KL 期望即可。</li><li><strong>terminal RM reward</strong>:RM 给整段答案的 scalar,只放在最后一个 token 上(其余 token RM reward = 0)。</li></ul>
|
||
<p>放完后跑 GAE:</p>
|
||
<p>$$\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}$$</p>
|
||
<p>KL penalty 通过 advantage 自然 propagate 到 policy gradient:<strong>每步 token 的"动作概率提升"被 KL "拉回 reference" 抵消</strong>,最终 RL 目标 = expected $R$ − $\beta$ · KL。</p>
|
||
<h3 id="32-option-bin-loss-regularizationgrpo--dapo-做法">3.2 Option B:In-loss regularization(GRPO / DAPO 做法)</h3>
|
||
<p>把 KL <strong>不放 reward</strong>,作为单独 loss 项:</p>
|
||
<p>$$\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}}\;}$$</p>
|
||
<p>GRPO 的<strong>历史实现</strong>(DeepSeekMath / DAPO)把 $\widehat{\text{KL}}_\text{loss}$ 取作 <strong>k3</strong>(per-token):</p>
|
||
<ul><li>用 k3 estimator(per-token)。</li><li>KL <strong>不进 advantage 计算</strong>;直接作为正则项加到 loss 上。</li><li>Advantage 由组内 reward 归一化得到($\hat{A}_i = (r_i - \bar{r})/\sigma_r$),所有 token 共享。</li></ul>
|
||
<div class="callout callout-warn"><div class="callout-title">重要 caveat</div><p>把 k3 直接当 loss 反传<strong>不是</strong>精确的 reverse-KL gradient——它是一个 biased first-order approximation(详见 §3.6 + 2025 "Rethinking KL Regularization in RLHF" 论文)。on-policy 下更 principled 的两种选择是:(1) <strong>k1 in reward</strong>(KL 进 reward,PPO/GRPO 通过 score-function 反传,gradient 严格无偏);(2) <strong>k2 as loss</strong>($\tfrac12 (\log r)^2$,$\nabla\mathcal L = \Delta\,\nabla\log\pi_\theta$,on-policy 下与 (1) <strong>gradient-equivalent</strong>,都是严格 reverse-KL gradient)。off-policy 还需 IS correction。下方 §3.6 给出对比表。</p></div>
|
||
<h3 id="33-两者数学上等价工程上不等价">3.3 两者数学上等价?工程上不等价</h3>
|
||
<p><strong>数学</strong>:两种放法本质都是优化同一个目标:</p>
|
||
<p>$$J(\pi) = \mathbb{E}_{\pi}[R] - \beta \cdot \text{KL}(\pi \| \pi_\text{ref})$$</p>
|
||
<p>只是<strong>梯度 propagate 路径不同</strong>:</p>
|
||
<ul><li>Option A:KL 作为 reward 一部分 → 经 GAE → 进入 advantage → 进入 PPO surrogate 梯度。</li><li>Option B:KL 作为独立 loss → 直接对 $\theta$ 求梯度。</li></ul>
|
||
<p><strong>工程差异</strong>:</p>
|
||
<table><thead><tr><th>维度</th><th>In-reward (Option A)</th><th>In-loss (Option B)</th></tr></thead><tbody><tr><td>KL 估计器</td><td>k1(单 token 可负,作为 reward 接受)</td><td>k3(无偏 + 非负,更稳)</td></tr><tr><td>与 PPO clip 的关系</td><td>KL 被 clip 截断(importance ratio 截断把 KL 一并截了)</td><td>KL 独立,不被 clip 影响</td></tr><tr><td>Advantage 解释</td><td>advantage 内含 KL → "净 advantage"</td><td>advantage 仅 reward-based → "纯 advantage"</td></tr><tr><td>调参敏感度</td><td>β 直接影响 reward scale → 需要和 RM scale 协调</td><td>β 与 reward 独立,但 KL 与 PG 比重要平衡</td></tr><tr><td>监控指标</td><td>看 token-level KL 进了 reward</td><td>看 KL loss 独立曲线</td></tr></tbody></table>
|
||
<div class="callout callout-warn"><div class="callout-title">PPO clip 抹掉 KL 信号的细节</div><p>在 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 项也一并失效。这意味着<strong>当 policy 偏离过大时,PPO clip 反而让 KL anchor 失效</strong>——这是 Option B 把 KL 放 loss 的部分动机(KL 永远生效)。</p></div>
|
||
<h3 id="34-实操哪一种用在哪">3.4 实操:哪一种用在哪?</h3>
|
||
<table><thead><tr><th>算法</th><th>KL 放置</th><th>估计器</th><th>来源</th></tr></thead><tbody><tr><td>InstructGPT PPO</td><td><strong>In-reward</strong></td><td>k1</td><td>Ouyang 2022 NeurIPS</td></tr><tr><td>Anthropic RLHF</td><td><strong>In-reward</strong></td><td>k1 + adaptive β</td><td>Bai 2022 arXiv 2204.05862</td></tr><tr><td>GRPO / DeepSeekMath</td><td><strong>In-loss</strong></td><td>k3</td><td>Shao 2024 arXiv 2402.03300</td></tr><tr><td>DAPO</td><td><strong>In-loss</strong>(实际配置中 KL 项常被关掉或权重很低)</td><td>k3</td><td>Yu 2025 arXiv 2503.14476</td></tr><tr><td>DPO</td><td><strong>隐式 in-loss</strong>(通过 $\pi_\text{ref}$ 在 log-ratio 分母)</td><td>—</td><td>Rafailov 2023 NeurIPS</td></tr><tr><td>SimPO</td><td><strong>去掉 reference, 无 KL</strong></td><td>—</td><td>Meng 2024 NeurIPS</td></tr></tbody></table>
|
||
<div class="callout callout-info"><div class="callout-title">DAPO 实战经验</div><p>字节 verl 团队的工程报告里多次提到,KL 项在大规模数学/代码 RL 训练中<strong>经常关掉或设很小</strong> β($10^{-4}$ 量级),原因:reward 已经是 rule-based(接近 ground truth),不存在 RM hacking,KL anchor 反而拖训练。这是"Option B + β ≈ 0"的极端版本。</p></div>
|
||
<h3 id="36-estimator-placement-的-gradient-bias-分析rethinking-kl-regularization-in-rlhf">3.6 Estimator placement 的 gradient bias 分析(Rethinking KL Regularization in RLHF)</h3>
|
||
<div class="callout callout-info"><div class="callout-title">关键参考</div><p>Kezhao Liu et al., "Rethinking KL Regularization in RLHF: From Value Estimation to Gradient Optimization", arXiv 2510.01555 (2025-10-02)。这篇文章系统区分 <strong>value estimation</strong>("KL 量本身估得准不准")与 <strong>gradient optimization</strong>("对 θ 求导后是不是真的 reverse-KL gradient"),结论与历史 GRPO 实现不完全一致。</p></div>
|
||
<h4 id="设定与三种-estimator-placement">设定与三种 estimator placement</h4>
|
||
<p>为简洁起见,令 $\Delta_t = \log\!\frac{\pi_\theta(y_t|s_t)}{\pi_\text{ref}(y_t|s_t)}$(per-token log-ratio,<strong>带 θ 梯度</strong>),$\hat\Delta_t = \text{stop\_grad}(\Delta_t)$(在 rollout 时记录的 detached 副本)。三种常见 placement:</p>
|
||
<table><thead><tr><th>方案</th><th>KL 出现的位置</th><th>单 token 形式</th><th>对 θ 的梯度贡献</th></tr></thead><tbody><tr><td><strong>(P1) k1 in reward</strong></td><td>进 reward / advantage</td><td>$\hat r_t \leftarrow r_t - \beta\,\hat\Delta_t$,再走 PPO surrogate</td><td>$-\beta\cdot \mathbb{E}[\nabla_\theta\log\pi_\theta\cdot \hat\Delta_t]$,<strong>严格的 reverse-KL score-function gradient</strong>(on-policy)</td></tr><tr><td><strong>(P2) k2 as loss</strong></td><td>直接 loss 项</td><td>$\mathcal{L}_\text{KL} = \tfrac12 \Delta_t^2$</td><td>$\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) <strong>gradient-equivalent</strong>——严格 principled</td></tr><tr><td><strong>(P3) k3 as loss</strong></td><td>直接 loss 项</td><td>$\mathcal{L}_\text{KL} = e^{-\Delta_t} + \Delta_t - 1$</td><td>$\nabla\mathcal{L}_\text{KL} = (1 - e^{-\Delta_t})\nabla_\theta\log\pi_\theta$;这是 reverse-KL gradient 的 <strong>first-order Taylor approximation</strong>,$1-e^{-\Delta} = \Delta - \tfrac12\Delta^2 + O(\Delta^3)$,有 $O(\Delta^2)$ bias</td></tr></tbody></table>
|
||
<h4 id="为什么-k3-as-loss-是-biased-gradient关键直觉">为什么 k3 as loss 是 biased gradient(关键直觉)</h4>
|
||
<p>k3 作为 <strong>value estimator</strong>(计算 KL 的数值)是无偏的:$\mathbb{E}_{\pi_\theta}[\widehat{\text{KL}}_3] = \text{KL}(\pi_\theta\|\pi_\text{ref})$(见 §2.4.2 性质 2)。但当 <strong>对 θ 反传</strong>时,autograd 计算的是 $\nabla_\theta\widehat{\text{KL}}_3$,而<strong>不是</strong> $\nabla_\theta\,\mathbb{E}_{\pi_\theta}[\widehat{\text{KL}}_3]$。后者由 score-function trick 给出:</p>
|
||
<p>$$\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)}$$</p>
|
||
<p>= $\mathbb{E}[\nabla\log\pi_\theta \cdot \Delta]$(<strong>这是 (P1) 给的 gradient</strong>,等价于把 $\Delta$ 当 detached reward 走 score function)。</p>
|
||
<p>而 (P3) <code>loss.backward()</code> 给的是 $\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。</p>
|
||
<h4 id="实践规则结合-rethinking-kl--comedy-of-estimators">实践规则(结合 Rethinking KL + Comedy of Estimators)</h4>
|
||
<table><thead><tr><th>场景</th><th>推荐 placement</th><th>备注</th></tr></thead><tbody><tr><td><strong>on-policy(rollout 当步反传,无 PPO mini-batch 多步 update)</strong></td><td><strong>(P1) k1 in reward</strong> 或 <strong>(P2) k2 as loss</strong></td><td>两者在 on-policy 下 <strong>gradient-equivalent</strong>,都是严格 reverse-KL gradient</td></tr><tr><td><strong>off-policy(PPO mini-batch 多次走 same data)</strong></td><td>(P1) k1 in reward + <strong>IS correction</strong>:$\rho\cdot\Delta$,$\rho = \pi_\theta^\text{new}/\pi_\theta^\text{old}$</td><td>否则 reward 与当前 policy mismatch</td></tr><tr><td><strong>历史 GRPO/DeepSeekMath/DAPO 实现</strong></td><td>(P3) k3 as loss</td><td>有 $O(\Delta^2)$ gradient bias,实际工程里 $\Delta$ 很小(β 锚得紧),所以仍能跑;但<strong>不是理论 principled</strong></td></tr><tr><td><strong>value-side monitoring</strong>(看 KL 数值多大)</td><td>k3 estimator 仍是首选</td><td>无偏、非负、低方差——这就是 §2.4 那三大性质</td></tr></tbody></table>
|
||
<div class="callout callout-info"><div class="callout-title">Tip</div><p><strong>总结口径</strong>(面试推荐说法):k3 是<strong>优秀的 KL value estimator</strong>(unbiased + non-negative + low variance);但作为 loss 反传的 gradient 是 reverse-KL gradient 的 first-order Taylor approximation,有 bias。Rethinking KL 推荐 on-policy 用 (P1) 或 (P2);DAPO/GRPO 历史用 (P3) 主要是工程惯例 + 在小 β 区间近似成立。</p></div>
|
||
<h2 id="4--调度">§4 β 调度</h2>
|
||
<h3 id="41-固定---baseline">4.1 固定 β —— baseline</h3>
|
||
<p>最常见。$\beta \in [0.01, 0.5]$,<strong>InstructGPT 报告中 β = 0.02 是参考值</strong>(per-token KL)。优点:简单可重现。缺点:训练中 KL 通常先小后大,固定 β 后期可能"压不住"或"过度压制"。</p>
|
||
<h3 id="42-adaptive---schulman-ppo-penalty-原版">4.2 Adaptive β —— Schulman PPO-Penalty 原版</h3>
|
||
<p>PPO 论文(Schulman 2017 arXiv 1707.06347)原本提了两个版本:<strong>Clip</strong>(现在主流)和 <strong>Penalty</strong>(adaptive KL)。Penalty 形式:</p>
|
||
<p>$$\mathcal{L} = \mathbb{E}[r_t A_t] - \beta_k \cdot \text{KL}(\pi_{\theta_\text{old}} \| \pi_\theta)$$</p>
|
||
<p><strong>β 自适应规则</strong>(每 epoch 之后看 measured KL $d$):</p>
|
||
<ul><li>若 $d < d_\text{target} / 1.5$:$\beta \leftarrow \beta / 2$(KL 比目标低,放松)</li><li>若 $d > d_\text{target} \times 1.5$:$\beta \leftarrow \beta \times 2$(KL 比目标高,加压)</li><li>否则 β 不变</li></ul>
|
||
<p>直觉:把 β 当 PID controller 的 P term,target 是预期 KL(比如 $d_\text{target} = 0.01$)。这条思路在 InstructGPT 和后续 Anthropic 工作里也出现过(Anthropic 论文 1707.06347 之后的 helpfulness/harmlessness 报告里有类似 adaptive β 描述)。</p>
|
||
<h3 id="43--annealing-schedule--类似-learning-rate-schedule">4.3 β annealing schedule —— 类似 learning rate schedule</h3>
|
||
<p>把 β 看作时间函数 $\beta(t)$:</p>
|
||
<ul><li><strong>早期紧后期松</strong>:$\beta(t) = \beta_0 \cdot \exp(-t / \tau)$。直觉:训练初期 policy 离 ref 近,加强 anchor 防 instability;后期 policy 学到了,放松让它 explore reward。</li><li><strong>早期松后期紧</strong>:相反方向,初期 explore RM 信号,后期 anchor。少见。</li><li><strong>Cosine / linear decay</strong>:参考 lr schedule。</li></ul>
|
||
<p>在 RLHF 工程实践中 annealing 用得不多——adaptive β 比 schedule 更鲁棒(不需调 schedule shape)。</p>
|
||
<h3 id="44--失败模式">4.4 β 失败模式</h3>
|
||
<table><thead><tr><th>β 设置</th><th>现象</th><th>诊断</th></tr></thead><tbody><tr><td><strong>β 太大</strong> ($> 1$)</td><td>KL ≈ 0,policy 卡在 ref 附近,RM reward 不涨</td><td>看 reward curve 是平的 / <code>chosen_logp - rejected_logp</code> 不分离</td></tr><tr><td><strong>β 太小</strong> ($< 0.001$)</td><td>KL 爆炸(runaway),policy 越来越长 / 谄媚 / 重复</td><td>看 KL 曲线持续上升、generation length 上升、人工评测下降</td></tr><tr><td><strong>β 突变</strong></td><td>训练 loss 跳跃</td><td>adaptive 频率太高 / target_kl 太严</td></tr></tbody></table>
|
||
<div class="callout callout-warn"><div class="callout-title">InstructGPT 论文 β = 0.02 真的合适吗?</div><p>答案因任务而异。<strong>Math/code RL</strong> 通常需要更小 β(DeepSeekMath 报告 β ≈ 0.04,DAPO 的 β 经常更小或为 0),因为 reward 接近 ground truth。<strong>Helpfulness/safety RL</strong> 需要更大 β(≥ 0.1)防 reward hacking,因为 neural RM 容易被 hack。这是为什么"β 不是 universal hyperparameter"。</p></div>
|
||
<h3 id="45-adaptive--代码示例">4.5 Adaptive β 代码示例</h3>
|
||
<pre><code class="language-python">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.beta</code></pre>
|
||
<p>用法:</p>
|
||
<pre><code class="language-python">kl_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</code></pre>
|
||
<div class="callout callout-info"><div class="callout-title">adaptive β 与 PID controller 的类比</div><p>上面只有 P 项(proportional);HuggingFace TRL 里的实现也只用 P。完全可以加 I(integral:累计误差)和 D(derivative:变化率)做 PID,但实测 P 已经够了,加 D 反而容易在 noisy KL 估计下振荡。</p></div>
|
||
<h2 id="5-kl-与-dpo--grpo--simpo--kto--ipo-的关系">§5 KL 与 DPO / GRPO / SimPO / KTO / IPO 的关系</h2>
|
||
<h3 id="51-dpoimplicit-reward----sequence-log-density-ratio">5.1 DPO:implicit reward = β × sequence log-density ratio</h3>
|
||
<p>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:</p>
|
||
<p>$$\hat{r}_\theta(x, y) = \beta \sum_t \log\frac{\pi_\theta(y_t | x, y_{<t})}{\pi_\text{ref}(y_t | x, y_{<t})}$$</p>
|
||
<div class="callout callout-warn"><div class="callout-title">注意区分:implicit reward 不是 KL 本身</div><p>$\hat{r}_\theta$ 是<strong>单条 sequence 的 pointwise log-ratio</strong>,<strong>不是</strong> 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 形式)。但 <strong>DPO 训练时 $y_w, y_l$ 不是从 $\pi_\theta$ 采的,而是来自固定 preference 数据</strong>,所以训练阶段的 $\hat{r}_\theta$ 不能直接读作 KL;它只是 pairwise log-ratio 差异。</p>
|
||
<p><strong>正确表述</strong>: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。</p></div>
|
||
<h4 id="511-dpo-闭式推导回顾">5.1.1 DPO 闭式推导回顾</h4>
|
||
<p>KL-regularized 目标:</p>
|
||
<p>$$\max_\pi \mathbb{E}_{x,\, y \sim \pi}[r(x, y)] - \beta\, \text{KL}(\pi \| \pi_\text{ref})$$</p>
|
||
<p>对单个 $x$ 用 Lagrangian + 求导(详细推导见 §6.1),得:</p>
|
||
<p>$$\pi^*(y|x) = \frac{1}{Z(x)} \pi_\text{ref}(y|x) \exp\!\left(\frac{r(x, y)}{\beta}\right)$$</p>
|
||
<p>反解:</p>
|
||
<p>$$r(x, y) = \beta \log\frac{\pi^*(y|x)}{\pi_\text{ref}(y|x)} + \beta \log Z(x)$$</p>
|
||
<p>代入 Bradley-Terry $P(y_w \succ y_l | x) = \sigma(r(x, y_w) - r(x, y_l))$,$\beta \log Z$ 消掉,得 DPO:</p>
|
||
<p>$$\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)\;}$$</p>
|
||
<h4 id="512-dpo-梯度的-kl-解释">5.1.2 DPO 梯度的 KL 解释</h4>
|
||
<p>$$\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]$$</p>
|
||
<p><strong>解释</strong>:</p>
|
||
<ul><li>$\sigma(\hat{r}_l - \hat{r}_w)$ 是"当前模型对偏好顺序错位的置信度"。</li><li>$\nabla \log\pi(y_w) - \nabla \log\pi(y_l)$ 是"提升 $y_w$ 概率 + 降低 $y_l$"。</li><li>$\beta$ 出现两次:一次进 implicit reward $\hat{r}$(决定 sigmoid 内部),一次显式作梯度系数。所以<strong>β 在 DPO 里同时调"KL 强度"和"梯度幅值"</strong>——与 RLHF 中 β 只调一个东西不同。</li></ul>
|
||
<div class="callout callout-warn"><div class="callout-title">DPO 的 β 调参隐患</div><p>DPO 调 β 不直接对应 RLHF 调 β 的语义。在 PPO 中 β 只影响 KL penalty 强度,在 DPO 中 β 同时影响:(1) implicit reward scale、(2) 梯度幅值(外层 β)、(3) sigmoid 饱和位置(内层 β)。<strong>经验值 $\beta \in [0.05, 0.5]$ 但每个任务最优 β 不同</strong>。</p></div>
|
||
<h3 id="52-grpok3-kl-in-loss">5.2 GRPO:k3 KL in loss</h3>
|
||
<p>DeepSeekMath GRPO 用 k3,KL 作为独立 loss 项:</p>
|
||
<p>$$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]$$</p>
|
||
<p>其中 $\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)$。</p>
|
||
<p><strong>为什么 GRPO 历史上选 k3</strong>(注意:这些都是 <strong>value-estimator</strong> 性质,不直接保证 loss gradient 正确,见 §3.6):</p>
|
||
<ol><li><strong>非负</strong>:作为 loss 数值显示直观(k1 数值可负,调试时容易让 optimizer 监控曲线看起来怪;但 k1 用在 reward 里是无害的)。</li><li><strong>value estimator 无偏</strong>:$\mathbb{E}_{\pi_\theta}[\widehat{\text{KL}}_3] = \text{KL}$(<strong>仅作为 KL 数值估计无偏;对 θ 反传时 gradient 是 first-order Taylor approximation,有 $O(\Delta^2)$ bias</strong>)。</li><li><strong>value estimator 低方差</strong>:相比 k1 数值,方差更小(log 监控曲线更平滑)。</li><li><strong>不进 advantage</strong>:与 In-reward 方案的耦合相对解开,便于诊断(KL loss 和 PG loss 独立监控)。</li></ol>
|
||
<div class="callout callout-warn"><div class="callout-title">GRPO 的 k3-as-loss 不是理论 principled 的最佳选择</div><p>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 误差有限——但<strong>面试中应能区分 "value-estimator 优势" 与 "loss-gradient 正确性"</strong>。</p></div>
|
||
<h3 id="53-simpo去掉-reference没有-kl-anchor">5.3 SimPO:去掉 reference,没有 KL anchor</h3>
|
||
<p>SimPO 把 implicit reward 改成 length-normalized log-prob:</p>
|
||
<p>$$r_\text{SimPO}(x, y) = \frac{\beta}{|y|} \log \pi_\theta(y|x)$$</p>
|
||
<p><strong>关键差异</strong>:<strong>没有 $\pi_\text{ref}$</strong>,所以<strong>没有 KL 项</strong>。损失:</p>
|
||
<p>$$\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)$$</p>
|
||
<p><strong>后果</strong>:</p>
|
||
<ul><li>✅ 训练时省一份 reference policy(显存减半)。</li><li>❌ 没有 KL anchor,policy 离 SFT 的距离<strong>完全不可控</strong>。</li><li>实测上 SimPO 在某些 benchmark(AlpacaEval-2 / Arena-Hard)上优于 DPO;但生成质量在 OOD prompt 上<strong>比 DPO 不稳</strong>。SimPO 的设计是"用 length-norm + margin 替代 KL anchor"——它假定了"短 prompt-response 任务下,长度归一 + margin 足以约束 policy",<strong>不是对所有任务都成立</strong>。</li></ul>
|
||
<div class="callout callout-info"><div class="callout-title">SimPO 没有 KL 的工程影响</div><p>工程上发现 SimPO 训完的 model 在重复模式、生成长度、对 prompt 微扰的鲁棒性上<strong>都比 DPO 差</strong>。这是为什么很多生产 RLHF 仍然用 DPO + small β 而不是 SimPO——KL anchor 是有代价但有价值。</p></div>
|
||
<h3 id="54-kto--ipo--orpo-的-kl-处理">5.4 KTO / IPO / ORPO 的 KL 处理</h3>
|
||
<table><thead><tr><th>算法</th><th>KL 形式</th><th>备注</th></tr></thead><tbody><tr><td><strong>KTO</strong> (Ethayarajh 2024 ICML)</td><td>通过 reference point $z_0 = \mathbb{E}[\beta\cdot\text{KL}]$(batch mismatched pair 估,detach)</td><td>KL 隐式地"作 anchor":implicit reward 偏离 $z_0$ 多远</td></tr><tr><td><strong>IPO</strong> (Azar 2024 AISTATS)</td><td>与 DPO 同($\log(\pi/\pi_\text{ref})$),但损失从 sigmoid 改 squared</td><td>防止 deterministic preference 下 $\hat{r}$ 无界增长</td></tr><tr><td><strong>ORPO</strong> (Hong 2024 EMNLP)</td><td><strong>无 reference model</strong>(与 SimPO 类似),用 odds-ratio 代替</td><td>一阶段同时做 SFT + preference;KL anchor 隐含在 SFT loss 里</td></tr></tbody></table>
|
||
<h3 id="55-recent-papers-2024-2026">5.5 Recent papers (2024-2026)</h3>
|
||
<table><thead><tr><th>论文</th><th>主张</th><th>KL 角度</th></tr></thead><tbody><tr><td><strong>DeepSeekMath GRPO</strong> (Shao et al. 2024 arXiv 2402.03300)</td><td>组内归一化 + k3 KL in loss</td><td>第一个在 LLM RL 中默认 k3 KL</td></tr><tr><td><strong>DPO Implicit Reward Models</strong> (Rafailov 2023 NeurIPS)</td><td>DPO 的 implicit reward 等价于 KL log-ratio</td><td>DPO 本质是 KL-regularized 优化的反解</td></tr><tr><td><strong>Reward Model Overoptimization Scaling Laws</strong> (Gao, Schulman, Hilton 2023 ICML)</td><td>gold reward 在 KL 距离上 inverted-U</td><td>KL 是 overoptimization 的天然 x-axis</td></tr><tr><td><strong>DAPO</strong> (Yu et al. 2025 ByteDance arXiv 2503.14476)</td><td>clip-higher + dynamic sampling + token-level loss</td><td>KL 项常被设小或关掉,加入清理 prompt 的 dynamic sampling</td></tr><tr><td><strong>Cohere DRO / OPO</strong> (各种 2024-2025 工作)</td><td>offline IS-correction RL with KL</td><td>把 IS-correction 与 KL anchor 联合</td></tr><tr><td><strong>"Rethinking KL Regularization in RLHF: From Value Estimation to Gradient Optimization"</strong> (Kezhao Liu et al. 2025-10, arXiv 2510.01555)</td><td>系统区分 KL value estimation 与 gradient optimization:k3-as-loss 是 biased first-order approximation;推荐 (1) k1 in reward(严格 reverse-KL score-function gradient)或 (2) <strong>k2 as loss</strong>(value estimator 有偏,但 on-policy loss gradient 严格等价于 k1-in-reward / reverse-KL gradient);off-policy 还需 IS correction</td><td>历史 GRPO 的"k3 as loss"是工程惯例不是理论 principled</td></tr><tr><td><strong>"A Comedy of Estimators: On KL Regularization in RL Training of LLMs"</strong> (Vedant Shah et al. 2025-12, arXiv 2512.21852, v3 2026-03)</td><td>在多种 RL 算法 + estimator placement 组合上系统对比 k1/k2/k3 的 estimator bias 与 gradient bias;分析 placement-effect</td><td>不存在 universally 最好的 estimator;reward-shaping vs loss-term 各有适用场景</td></tr></tbody></table>
|
||
<h2 id="6-theoreticalkl-regularized-rl-的最优-policy--reward-overoptimization">§6 Theoretical:KL-Regularized RL 的最优 policy + Reward Overoptimization</h2>
|
||
<h3 id="61-kl-regularized-rl-闭式解dpo-的数学基础">6.1 KL-Regularized RL 闭式解(DPO 的数学基础)</h3>
|
||
<p><strong>定理</strong>(KL-regularized policy optimization 的闭式解):</p>
|
||
<p>考虑:</p>
|
||
<p>$$\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)$$</p>
|
||
<p>其中 $\pi$ 是对任意 $x$ 的分布,$\pi_\text{ref}$ 严格正($\pi_\text{ref}(y|x) > 0$ 对所有 $y$)。</p>
|
||
<p><strong>唯一最优解</strong>:</p>
|
||
<p>$$\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)\;}$$</p>
|
||
<p><strong>证明</strong>(Lagrangian):</p>
|
||
<p>固定 $x$,写目标(连续/离散通用,离散表示):</p>
|
||
<p>$$\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)$$</p>
|
||
<p>其中 $\mu$ 是 normalization 约束的 Lagrange multiplier(注意符号:从 max 推 KKT 时把 $\sum_y\pi = 1$ 写成 $-\mu(\sum - 1)$ 是为了内点最优条件简洁)。</p>
|
||
<p>对 $\pi(y|x)$ 求偏导:</p>
|
||
<p>$$\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$$</p>
|
||
<p>整理:</p>
|
||
<p>$$\log\frac{\pi(y|x)}{\pi_\text{ref}(y|x)} = \frac{r(x, y) - \mu - \beta}{\beta}$$</p>
|
||
<p>指数化:</p>
|
||
<p>$$\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}$$</p>
|
||
<p>代入归一化条件 $\sum_y \pi(y|x) = 1$:</p>
|
||
<p>$$e^{(\mu+\beta)/\beta} = \sum_y \pi_\text{ref}(y|x) \exp\!\left(\frac{r(x, y)}{\beta}\right) = Z(x)$$</p>
|
||
<p>所以 $e^{-(\mu+\beta)/\beta} = 1/Z(x)$,得:</p>
|
||
<p>$$\pi^*(y|x) = \frac{1}{Z(x)} \pi_\text{ref}(y|x) \exp\!\left(\frac{r(x, y)}{\beta}\right) \quad \blacksquare$$</p>
|
||
<p><strong>唯一性</strong>:因为 $J$ 在 $\pi$ 上是<strong>严格凹</strong>的(KL 是凸的,加负号变严格凹,且 reward 是 linear),凹优化有唯一最优。</p>
|
||
<h3 id="62-从最优-policy-反解-implicit-reward">6.2 从最优 policy 反解 implicit reward</h3>
|
||
<p>把 §6.1 的 $\pi^*$ 取 log:</p>
|
||
<p>$$\log\pi^*(y|x) = \log\pi_\text{ref}(y|x) + \frac{r(x, y)}{\beta} - \log Z(x)$$</p>
|
||
<p>反解 $r$:</p>
|
||
<p>$$\boxed{\;r(x, y) = \beta\log\frac{\pi^*(y|x)}{\pi_\text{ref}(y|x)} + \beta\log Z(x)\;}$$</p>
|
||
<p><strong>这就是 DPO 的 implicit reward</strong>。$\beta \log Z(x)$ 是 partition function,<strong>只依赖 $x$,不依赖 $y$</strong>——在 Bradley-Terry 的 $r(x, y_w) - r(x, y_l)$ 差里<strong>消掉</strong>。</p>
|
||
<h3 id="63-bradley-terry-偏好模型下的-rl-等价于-dpo">6.3 Bradley-Terry 偏好模型下的 RL 等价于 DPO</h3>
|
||
<p>BT 模型:$P(y_w \succ y_l | x) = \sigma(r(x, y_w) - r(x, y_l))$。</p>
|
||
<p>代入 §6.2:</p>
|
||
<p>$$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)}$$</p>
|
||
<p>替换 $\pi^*$ 为可学 $\pi_\theta$,对偏好数据 NLL:</p>
|
||
<p>$$\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)$$</p>
|
||
<p><strong>这是 §5.1 的 DPO 公式</strong>。所以<strong>DPO ≡ Bradley-Terry preference + KL-regularized RL 闭式解 + 偏好数据 NLL</strong>,三件套合一。</p>
|
||
<h3 id="64-reward-overoptimizationgao-schulman-hilton-2023-icml">6.4 Reward Overoptimization(Gao, Schulman, Hilton 2023 ICML)</h3>
|
||
<h4 id="641-问题表述">6.4.1 问题表述</h4>
|
||
<p>记 gold reward $r_g$(人感受的真实质量)、proxy reward $r_p$(RM 估的)。RM 用偏好数据学,但偏好数据有限 → $r_p \ne r_g$。</p>
|
||
<p>随着 RL 训练 KL 距离 $d = \text{KL}(\pi_\theta \| \pi_\text{ref})$ 增大:</p>
|
||
<ul><li>$\mathbb{E}_{\pi_\theta}[r_p]$ 单调上升(policy 学到 RM 的偏好)。</li><li>$\mathbb{E}_{\pi_\theta}[r_g]$ 先升后降(<strong>inverted-U</strong>)—— 这是 reward overoptimization。</li></ul>
|
||
<h4 id="642-gao-2023-给的拟合形式">6.4.2 Gao 2023 给的拟合形式</h4>
|
||
<p>Gao 2023 用大量 RM size + KL 实验,给出 gold reward 关于 KL 距离 $d$ 的拟合形式(用 $\sqrt{d}$ 当 x-axis):</p>
|
||
<p>$$R_g(d) = d \cdot (\alpha_g - \gamma_g \cdot d) \quad \text{(BoN)}$$</p>
|
||
<p>$$R_g(d) = d \cdot (\alpha_g - \gamma_g \cdot d) - \delta_g\, d^{3/2}\quad \text{(PPO, 多了高阶项)}$$</p>
|
||
<p>其中 $\alpha_g, \gamma_g, \delta_g$ 是与 RM size 相关的系数;RM 越大,"高阶项 / 二次项"权重越小,过优化越慢。</p>
|
||
<h4 id="643-kl-是-overoptimization-的天然-axis">6.4.3 KL 是 overoptimization 的"天然 axis"</h4>
|
||
<p>无论是 BoN、PPO 还是 DPO(按 implicit reward 累积),都可以把训练曲线画成"<strong>KL 距离 vs gold reward</strong>"图。Gao 2023 发现:</p>
|
||
<ul><li><strong>不同算法(BoN / PPO)在同样 KL 下的 over-optimization 行为相似</strong>(同一 RM 给出的 gold 曲线形状一致)。</li><li><strong>更大 RM → 更慢的 over-optimization</strong>(gold curve peak 更靠右)。</li><li><strong>KL 是一个一维 progress indicator</strong>,比 step 数 / reward 数更能解释 over-optimization。</li></ul>
|
||
<p><strong>面试 takeaway</strong>:在 RLHF 监控里,把 <code>(measured_KL, gold_reward)</code> 画图,看是否进入下降区——这是最直接的 "stop 早一点" 信号。</p>
|
||
<h3 id="65-kl-与-chi2-gap-的关系">6.5 KL 与 $\chi^2$ gap 的关系</h3>
|
||
<p>KL 与 $\chi^2$ 在 Pinsker 类不等式族里有关系:</p>
|
||
<p>$$\text{TV} \le \sqrt{\text{KL}/2}\qquad \text{(Pinsker)}$$</p>
|
||
<p>$$\text{KL} \le \log(1 + \chi^2)$$</p>
|
||
<p>在 RLHF 里 $\chi^2$ 偶尔被作为 KL 的"敏感"上界使用:<strong>当 $\chi^2$ 大但 KL 小,意味着 $\pi_\theta$ 有重 tail 偏离 $\pi_\text{ref}$</strong>(高方差但低 mean)。某些工作(Yu et al. 2024 / others)在监控 reward hacking 时同时画 KL 和 $\chi^2$,看 tail 行为。</p>
|
||
<h3 id="66-sequence-level-vs-token-level-kl">6.6 Sequence-level vs Token-level KL</h3>
|
||
<p>由 §1.1 的<strong>链式法则</strong>:</p>
|
||
<p>$$\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_{<t})}{\pi_\text{ref}(y_t | x, y_{<t})}\right]$$</p>
|
||
<p>即 <strong>sequence-level KL = token-level KL 之和的期望</strong>(自回归 chain rule)。注意:单条 rollout 上把 $\sum_t \log\pi_\theta(y_t)/\pi_\text{ref}(y_t)$ 直接当 KL 是 <strong>k1 estimator</strong>(unbiased 但 per-rollout 方差大);若要 true token-level KL $D(\pi_\theta(\cdot|s_t)\|\pi_\text{ref}(\cdot|s_t))$ 还需 full-vocab forward。<strong>两者期望相等</strong>,工程上选 sampled log-ratio 是因为 vocab 求和昂贵。</p>
|
||
<p>但有两个<strong>implementation trick</strong> 与 token-level 相关:</p>
|
||
<ol><li><strong>Per-token clipping</strong>:单 token KL 偶尔很大(罕见 token、长 tail),可以对每 token KL 做 clip 防止单 token 拖飞 batch 总 KL。</li><li><strong>Mask on assistant tokens only</strong>:在 chat / agent setting 下,prompt token 不应该参与 KL 计算(prompt 是同一的,policy 和 ref 在 prompt 上完全一致,KL = 0;但浮点误差会污染)。所以 KL mask 与 PPO action_mask 重合,<strong>只在 assistant generation token 上算 KL</strong>。</li></ol>
|
||
<pre><code class="language-python"># 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</code></pre>
|
||
<h2 id="7-实践--代码">§7 实践 + 代码</h2>
|
||
<h3 id="71-ppo-风格in-reward-shaping-实现">7.1 PPO 风格:In-reward shaping 实现</h3>
|
||
<pre><code class="language-python">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 计算的数据输入</code></pre>
|
||
<h3 id="72-grpo-风格in-loss-regularization-实现k3">7.2 GRPO 风格:In-loss regularization 实现(k3)</h3>
|
||
<pre><code class="language-python">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()}</code></pre>
|
||
<h3 id="73-dpo-闭式-loss--implicit-reward-监控">7.3 DPO 闭式 loss + implicit reward 监控</h3>
|
||
<pre><code class="language-python">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()}</code></pre>
|
||
<h3 id="74-reward-overoptimization-监控">7.4 Reward overoptimization 监控</h3>
|
||
<pre><code class="language-python">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_gold</code></pre>
|
||
<h3 id="75-工程清单debug-checklist">7.5 工程清单(debug checklist)</h3>
|
||
<div class="callout callout-warn"><div class="callout-title">KL 相关 bug Top 8</div></div>
|
||
<ol><li><strong>KL 用错了 mask</strong>:在 prompt token 上算 KL 应该 = 0(同 prompt 输入),但 floating-point 噪声会污染,所以<strong>必须 mask only assistant tokens</strong>。</li><li><strong>k1 显示为负</strong>:log-ratio 单样本可负,但<strong>期望非负</strong>。不是 bug,是 estimator 性质。换 k3 / k2 看监控更直观。</li><li><strong>β 单位错</strong>:reward scale = O(1) 时 β = 0.02;reward scale = O(100) 时 β 要相应放大。否则 KL anchor 失效。</li><li><strong>adaptive β 振荡</strong>:target_kl 太严 / mult 太大。把 mult clip 到 [0.8, 1.2],update 频率降到每 100 steps。</li><li><strong>Reference policy 没冻结</strong>:忘记 <code>ref_policy.eval()</code> + <code>torch.no_grad()</code>,ref 跟着训,KL 变成 self-distillation。</li><li><strong>Per-token vs sequence-level KL 混淆</strong>:监控里有时报 per-token,有时报 sequence-level,看错就调错 β。统一一个单位。</li><li><strong>GRPO 中 KL 项缩 reward</strong>:当 reward 是 binary {0, 1}(数学题)且 β = 0.04,KL ≈ 0.5 时,KL penalty 已大于 reward 平均值——loss 被 KL 主导。<strong>降 β 到 1e-3 或更小</strong>。</li><li><strong>Float overflow on $\pi_\text{ref}/\pi_\theta$</strong>:当 policy 大幅偏离 ref,$\pi_\text{ref}/\pi_\theta$ 可能极大,$e^\Delta$ 溢出。<strong>用 log-space 写 k3</strong>:<code>exp(delta) - delta - 1</code> 在 $\Delta$ 大时仍可能溢出,可以加 <code>torch.clamp(delta, max=10)</code> 或换数值稳定 form。</li></ol>
|
||
<h2 id="8-失败模式kl-collapse--runaway--reward-hacking">§8 失败模式:KL Collapse / Runaway / Reward Hacking</h2>
|
||
<h3 id="81-kl-collapse-过大或-entropy-太低">8.1 KL Collapse(β 过大或 entropy 太低)</h3>
|
||
<p><strong>症状</strong>:</p>
|
||
<ul><li>KL 曲线 $\approx 0$,policy 等同 reference。</li><li>Reward 不上升。</li><li>Generation 与 SFT 完全相同。</li></ul>
|
||
<p><strong>原因</strong>:</p>
|
||
<ul><li>β 过大,KL penalty 主导 loss,PG 信号被压住。</li><li>Policy entropy 太低(SFT 后已经很 deterministic)→ 进一步 update 困难。</li></ul>
|
||
<p><strong>修复</strong>:</p>
|
||
<ul><li>降低 β(adaptive controller 应能自动处理)。</li><li>加 entropy bonus($+ c_e \cdot H[\pi_\theta]$)。</li><li>检查 PG 与 KL loss 的 magnitude ratio:理想 $|\text{PG}| / (\beta \cdot |\text{KL}|) \in [1, 10]$。</li></ul>
|
||
<h3 id="82-kl-runaway-过小或-reward-信号太强">8.2 KL Runaway(β 过小或 reward 信号太强)</h3>
|
||
<p><strong>症状</strong>:</p>
|
||
<ul><li>KL 持续上升,policy 与 ref 距离越来越大。</li><li>Generation 变长、出现重复模式、风格漂移。</li><li>Validation 上 gold reward 开始下降(reward overoptimization)。</li></ul>
|
||
<p><strong>原因</strong>:</p>
|
||
<ul><li>β 过小,KL anchor 失效。</li><li>Reward 信号过强(neural RM 给出 huge gradient)。</li><li>PPO importance ratio 经常超出 clip 范围,KL 信号被 clip 屏蔽(Option A 特有)。</li></ul>
|
||
<p><strong>修复</strong>:</p>
|
||
<ul><li>升 β(adaptive)。</li><li>加 max_kl_budget 提前停(当 measured KL > target 时停训)。</li><li>用 reward model ensemble + conservative aggregation(min / mean - std)。</li><li>若是 Option A,考虑切到 Option B(KL 不被 PPO clip 屏蔽)。</li></ul>
|
||
<h3 id="83-reward-overoptimizationkl-距离的-inverted-u">8.3 Reward Overoptimization(KL 距离的 inverted-U)</h3>
|
||
<p><strong>症状</strong>:</p>
|
||
<ul><li>Proxy reward 持续上升。</li><li>Gold reward 先升后降(inverted-U)。</li><li>人类评测:模型在 in-distribution 数据上看起来好,但 OOD prompt 上崩。</li></ul>
|
||
<p><strong>原因</strong>:见 §6.4,RM 与 gold reward 的本质不同。</p>
|
||
<p><strong>修复</strong>:</p>
|
||
<ol><li><strong>KL budget early stop</strong>:把 measured KL 限制在 inverted-U peak 之前(需要 gold reward 监控)。</li><li><strong>RM ensemble</strong>:多个 seed 的 RM,取 min 或 mean - $k\cdot\text{std}$。</li><li><strong>混 RL + DPO</strong>:先 DPO 拿 70%,再 small-β PPO 跑最后一公里。</li><li><strong>Rule-based reward 替代神经 RM</strong>:数学 / 代码任务的根本解法。</li><li><strong>PRM 替代 ORM</strong>:dense reward → 单步 over-optimization 受限。</li></ol>
|
||
<h3 id="84-length-biasdpo-特有也可视作-kl-anchor-不够强">8.4 Length bias(DPO 特有,也可视作 KL anchor 不够强)</h3>
|
||
<p><strong>症状</strong>:</p>
|
||
<ul><li>DPO 训完后输出明显变长。</li><li>AlpacaEval 上分数高但用户感受变啰嗦。</li></ul>
|
||
<p><strong>原因</strong>:DPO loss 是 sequence-level log-ratio 差。$y_w$ 通常更长(人选更详尽答案),longer $y_w$ → 更负的 $\log\pi(y_w)$ → log-ratio 差更大 → loss 减小。但这是 RM scale 而非 reasoning quality。</p>
|
||
<p><strong>修复</strong>:</p>
|
||
<ul><li>SimPO 的 length-normalization($r = (\beta/|y|)\log\pi$)。</li><li>Reward shaping 加 length penalty。</li><li>数据 curation:让 $y_w$ 和 $y_l$ 长度分布相似。</li></ul>
|
||
<h3 id="85-reference-policy-wrong-checkpoint-failure">8.5 Reference policy "wrong checkpoint" failure</h3>
|
||
<p><strong>症状</strong>:训练正常但下游 eval 极差。</p>
|
||
<p><strong>原因</strong>:用了错误的 ref checkpoint(比如 pretrain base 而不是 SFT)。KL anchor 锚到了"语言模型"而不是"指令模型"。</p>
|
||
<p><strong>修复</strong>:reference 必须是 immediate-previous-stage SFT checkpoint,不能跳层级。</p>
|
||
<h2 id="9-25-高频面试题">§9 25 高频面试题</h2>
|
||
<p>按难度分 3 档:L1 = 任何 LLM 工程岗都会问;L2 = research / alignment 团队会问;L3 = 顶级 lab / DeepSeek 量级团队的硬核题。每题点开看答案要点 + 易踩坑。</p>
|
||
<h3 id="l1-必会题10-题">L1 必会题(10 题)</h3>
|
||
<details>
|
||
|
||
<summary>Q1.KL 散度的定义和 3 个核心性质?</summary>
|
||
<ul><li>定义:$\text{KL}(p\|q) = \mathbb{E}_{x\sim p}[\log(p(x)/q(x))]$</li><li>非负(Jensen);等号 ⟺ $p = q$ a.e.</li><li>不对称($\text{KL}(p\|q) \ne \text{KL}(q\|p)$),不是 metric</li><li>联合凸,参数化变换下不变(reparam invariant)</li></ul>
|
||
<p>说 KL 是"距离"——错(不满足三角不等式);或不知道凸性。</p>
|
||
</details>
|
||
<details>
|
||
|
||
<summary>Q2.RLHF 里为什么要加 KL penalty?</summary>
|
||
<ul><li>防 reward hacking:policy 找 RM 盲点拿高分但人感受变差</li><li>防语言流畅性塌掉:no-KL 时模型可能输出"鬼话但 RM 给高分"</li><li>防 distribution shift:policy 离 SFT 太远,RM 自己也不准(OOD)</li><li>提供闭式最优 policy:$\pi^* \propto \pi_\text{ref}\exp(r/\beta)$</li></ul>
|
||
<p>只说"防过拟合"——不够具体;不知道 reward hacking。</p>
|
||
</details>
|
||
<details>
|
||
|
||
<summary>Q3.k1 estimator 是什么?为什么单样本可以为负?</summary>
|
||
<ul><li>k1: $\widehat{\text{KL}}_1 = \log(\pi_\theta(y)/\pi_\text{ref}(y))$(直接 log-ratio)</li><li><strong>期望</strong> $\mathbb{E}_{y\sim\pi_\theta}[\log r] = \text{KL}$(无偏),但<strong>单样本</strong> $\log r$ 可正可负</li><li>原因:单个样本 $y$ 上 $\pi_\theta$ 可能比 $\pi_\text{ref}$ 大也可能小,log-ratio 没有"非负"约束</li><li>工程影响:用 k1 做监控时看到负值不要慌,是 estimator 本性</li></ul>
|
||
<p>把单 estimator 和期望混淆;或不知 expectation 非负 ≠ pointwise 非负。</p>
|
||
</details>
|
||
<details>
|
||
|
||
<summary>Q4.k3 estimator (Schulman 2020) 公式是什么?三大性质?</summary>
|
||
<ul><li>公式:$\widehat{\text{KL}}_3 = e^\Delta - \Delta - 1$,$\Delta = \log(\pi_\text{ref}/\pi_\theta) = -\log r$</li><li>等价形式:$\widehat{\text{KL}}_3 = (\pi_\text{ref}/\pi_\theta) - \log(\pi_\text{ref}/\pi_\theta) - 1$</li><li><strong>无偏</strong>($\mathbb{E}_{\pi_\theta} = \text{KL}$,用 $\sum_y\pi_\text{ref} = 1$)</li><li><strong>非负</strong>($f(x) = e^x - x - 1 \ge 0$)</li><li><strong>低方差</strong>(带 expectation-0 control variate $\pi_\text{ref}/\pi_\theta - 1$)</li></ul>
|
||
<p>只背公式不知道 derivation;或不知道它非负。</p>
|
||
</details>
|
||
<details>
|
||
|
||
<summary>Q5.KL 在 RLHF 中有哪两种放置?区别?</summary>
|
||
<ul><li><strong>In-reward shaping (Option A)</strong>:$\tilde{r}_t = r_t - \beta \cdot \text{KL}_t$(用 k1),KL 进 advantage / GAE。InstructGPT 标准。</li><li><strong>In-loss regularization (Option B)</strong>:$\mathcal{L} = \mathcal{L}_\text{PG} + \beta \cdot \mathbb{E}[\text{KL}]$。GRPO / DAPO 历史选 k3 estimator。</li><li>目标函数相同,但<strong>梯度路径不同</strong>。<strong>Principled gradient</strong> 选择:(P1) k1 in reward;(P2) k2 as loss—— on-policy 下两者 gradient-equivalent,都是严格 reverse-KL gradient。<strong>GRPO 的 k3-as-loss</strong> 是 reverse-KL gradient 的 first-order Taylor approximation,有 $O(\Delta^2)$ bias(参见 §3.6 / Rethinking KL arXiv 2510.01555)。</li><li>PPO clip 在 Option A 会"屏蔽"超出 clip 的 KL(advantage 内含 KL 一并被 clip);Option B 不会。</li><li>实践:math/code RL 历史上选 B (k3) 因为 β 小、$\Delta$ 小,bias 可忽略;helpfulness / safety 多用 A (k1);如果要严格 principled,on-policy 用 P2 (k2-as-loss) 是 simplest principled 选择。</li></ul>
|
||
<p>说两者完全等价——目标相同梯度不等价;说 k3-as-loss 是 principled——它是 first-order approximation,理论不严格。</p>
|
||
</details>
|
||
<details>
|
||
|
||
<summary>Q6.β 怎么调?太大太小各有什么症状?</summary>
|
||
<ul><li>β 太大:KL ≈ 0,policy 卡在 ref,reward 不涨,模型基本等同 SFT</li><li>β 太小:KL runaway,policy 漂走,generation 变长 / 重复 / 谄媚,reward hacking</li><li>起点:InstructGPT 用 β ≈ 0.02(per-token);GRPO 数学任务 β ≈ 0.04 或更小;DAPO 经常 β ≈ 0</li><li>调法:固定 / adaptive(按 measured KL 距 target 拉 β) / annealing schedule</li></ul>
|
||
<p>只说"看着调";不知 β 的工程量级。</p>
|
||
</details>
|
||
<details>
|
||
|
||
<summary>Q7.Forward KL vs Reverse KL 在 RLHF 里用哪个?为什么?</summary>
|
||
<ul><li>RLHF 几乎都用 $\text{KL}(\pi_\theta \| \pi_\text{ref})$;按标准 VI/RLHF 约定(DPO/RLOO/Rethinking KL 等都采用)这是 <strong>reverse KL</strong>($\pi_\theta$ 是变分一侧),mode-seeking</li><li>因为训练时从 $\pi_\theta$ 采样(rollout),$\mathbb{E}_{\pi_\theta}[\log r]$ 直接用样本估</li><li><strong>Forward KL</strong> $\text{KL}(\pi_\text{ref} \| \pi_\theta)$ 需要从 $\pi_\text{ref}$ 采样,工程上无意义(要训 $\pi_\theta$ 不是 $\pi_\text{ref}$),且 mass-covering 行为不符合 RLHF 目标</li><li>Reverse KL 的 mode-seeking 性质正合规则:在 $\pi_\text{ref}$ 高密度区里选 reward 最高的 mode</li></ul>
|
||
<p>不知道命名约定(少数早期 RL 教材以采样分布命名,会把 reverse 标成 forward;面试时给公式更稳);或反过来说 forward 更好。</p>
|
||
</details>
|
||
<details>
|
||
|
||
<summary>Q8.DPO 的 implicit reward 跟 KL 有什么关系?</summary>
|
||
<ul><li>DPO implicit reward $\hat{r}_\theta(x, y) = \beta\log(\pi_\theta(y|x)/\pi_\text{ref}(y|x))$,即 <strong>β × pointwise sequence log-density ratio</strong></li><li>⚠️ <strong>不是 KL 本身</strong>:只有当 $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))$。<strong>DPO 训练时 $y_w, y_l$ 来自固定 preference 数据</strong>,所以这里的 $\hat r$ 不是 KL estimator,不是 KL margin</li><li>训练时 maximize $\hat{r}(y_w) - \hat{r}(y_l)$ ≡ pairwise log-ratio margin(preference 对的相对置信度),<strong>不是</strong> "KL margin"</li><li>KL anchor 是<strong>隐式</strong>的:通过 $\pi_\text{ref}$ 出现在 $\hat r$ 的分母带来 anchoring 效果——但显式 KL 不在 loss 里</li><li>对偶 RL 视角:DPO 反推自 KL-regularized 闭式最优 policy $\pi^* \propto \pi_\text{ref}\exp(r/\beta)$;隐式优化的目标是同一个 RLHF 目标,但 estimator 路径不同</li></ul>
|
||
<p>说 DPO 没有 KL(错,是隐式 anchor);或把 $\hat r$ 直接读作 KL / KL margin(错,需要 y~π_θ 期望条件)。</p>
|
||
</details>
|
||
<details>
|
||
|
||
<summary>Q9.Reward overoptimization 是什么?为什么发生?</summary>
|
||
<ul><li>Proxy reward(RM)随 KL 单调升,但 gold reward(人评)先升后降(<strong>inverted-U</strong>)</li><li>Gao, Schulman, Hilton 2023 ICML 给出 KL vs gold-reward 拟合形式</li><li>原因:RM 与 gold reward 不同(RM 是 finite-data 学的近似),policy 学到 RM 偏好但不一定是真实质量</li><li>缓解:KL budget early stop / RM ensemble / PRM / mix DPO + PPO</li></ul>
|
||
<p>只说"过拟合"——太笼统;不知道 KL 是 over-optimization 的 axis。</p>
|
||
</details>
|
||
<details>
|
||
|
||
<summary>Q10.GRPO 为什么历史上用 k3 不用 k1?</summary>
|
||
<ul><li><strong>工程动机</strong>:GRPO 把 KL 放 loss,k3 的 <strong>value-estimator</strong> 性质(非负 + value-side unbiased + 低方差)让 KL 监控曲线直观</li><li><strong>k1-as-loss 不可行</strong>:直接对 $\log r = \log\pi_\theta - \log\pi_\text{ref}$ 反传时,$\nabla = \nabla\log\pi_\theta$,在 on-policy 期望下为 0,<strong>不是</strong> reverse-KL gradient。k1 必须<strong>进 reward / advantage</strong>(作为 detached scalar 走 score-function trick)才能给出严格的 reverse-KL gradient。把 k1 当 loss 项加既数值上可负不好看,gradient 也错</li><li><strong>k3-as-loss 的真实代价</strong>:对 θ 反传的 gradient 是 reverse-KL gradient 的 <strong>first-order Taylor approximation</strong>,$1 - e^{-\Delta} = \Delta - \tfrac12\Delta^2 + O(\Delta^3)$,有 $O(\Delta^2)$ bias(见 §3.6 + Rethinking KL arXiv 2510.01555)</li><li><strong>Principled 替代</strong>:on-policy 下 (P1) k1 in reward 或 (P2) <strong>k2 as loss</strong>($\tfrac12\Delta^2$,$\nabla = \Delta\cdot\nabla\log\pi_\theta$,gradient-equivalent to P1)都是严格 reverse-KL gradient</li><li><strong>历史 DeepSeekMath / DAPO / verl 默认 k3</strong> 是工程惯例,$\beta$ 锁得紧、$\Delta$ 很小时 bias 可忽略——但这是经验合理化,不是理论 principled</li></ul>
|
||
<p>只说 k3 "三优满足"不给 gradient bias caveat;不知道 (P2) k2-as-loss 是 P1 的 gradient-equivalent 替代。</p>
|
||
</details>
|
||
<h3 id="l2-进阶题10-题">L2 进阶题(10 题)</h3>
|
||
<details>
|
||
|
||
<summary>Q11.推导 k3 的无偏性。</summary>
|
||
<p>需要证 $\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})$。</p>
|
||
<ol><li>$\mathbb{E}_{\pi_\theta}[\pi_\text{ref}/\pi_\theta] = \sum_y \pi_\theta(y)\cdot\pi_\text{ref}(y)/\pi_\theta(y) = \sum_y\pi_\text{ref}(y) = 1$</li><li>$\mathbb{E}_{\pi_\theta}[-\log(\pi_\text{ref}/\pi_\theta)] = \mathbb{E}_{\pi_\theta}[\log(\pi_\theta/\pi_\text{ref})] = \text{KL}(\pi_\theta\|\pi_\text{ref})$</li><li>合并:$\mathbb{E}[\widehat{\text{KL}}_3] = 1 + \text{KL} - 1 = \text{KL}$ ✓</li></ol>
|
||
<p>关键:用 $\sum_y\pi_\text{ref} = 1$。如果你忘了 $\pi_\text{ref}/\pi_\theta$ 这一项是 expectation 1 的 control variate,证不出无偏。</p>
|
||
</details>
|
||
<details>
|
||
|
||
<summary>Q12.从 $f(x) = e^x - x - 1$ 推导 k3 estimator。</summary>
|
||
<p>构造性证明:</p>
|
||
<ol><li>$f(x) = e^x - x - 1$ 在 $\mathbb{R}$ 非负(凸函数 $e^x$ 在 $x = 0$ 切线 $1 + x$ 之上)。</li><li><p>取 $x = \log(\pi_\text{ref}(y)/\pi_\theta(y)) = -\log r$:</p>
|
||
<ul><li>$e^{-\log r} = 1/r = \pi_\text{ref}/\pi_\theta$</li><li>$-(-\log r) = \log r = \log(\pi_\theta/\pi_\text{ref})$</li><li>$f(-\log r) = \pi_\text{ref}/\pi_\theta - \log(\pi_\text{ref}/\pi_\theta) - 1 = e^\Delta - \Delta - 1$,$\Delta = -\log r$</li></ul></li><li>期望:$\mathbb{E}_{\pi_\theta}[f(-\log r)] = \text{KL}$(已在 Q11 证)。</li></ol>
|
||
<p>所以 k3 = $f(\log p/q)$ 的特殊形式,恰好满足"非负 + 无偏 + 含 control variate" 三个性质。</p>
|
||
<p>只写公式不解释 $f$ 的构造动机;或不知道凸函数切线 → 非负。</p>
|
||
</details>
|
||
<details>
|
||
|
||
<summary>Q13.推 BT preference 下 KL-regularized RL 的闭式最优 policy。</summary>
|
||
<p>目标:$\max_\pi \mathbb{E}_{y\sim\pi}[r(x,y)] - \beta\,\text{KL}(\pi\|\pi_\text{ref})$。</p>
|
||
<ol><li>写 Lagrangian:$\sum_y \pi r - \beta\sum_y\pi\log(\pi/\pi_\text{ref}) - \mu(\sum_y\pi - 1)$</li><li>对 $\pi(y)$ 求偏导 = 0:$r - \beta(\log(\pi/\pi_\text{ref}) + 1) - \mu = 0$</li><li>整理:$\log(\pi/\pi_\text{ref}) = (r - \mu - \beta)/\beta$</li><li>指数化:$\pi(y) = \pi_\text{ref}(y)\exp((r - \mu - \beta)/\beta)$</li><li>用 $\sum_y\pi = 1$ 解 $\mu$:$e^{(\mu+\beta)/\beta} = \sum_y\pi_\text{ref}\exp(r/\beta) = Z$</li><li>得:$\pi^*(y|x) = \pi_\text{ref}(y|x)\exp(r/\beta)/Z(x)$</li></ol>
|
||
<p>注意:$J$ 在 $\pi$ 上严格凹,最优唯一。</p>
|
||
<p>漏 normalization 约束;漏 strict concavity argument;或把 sign 搞反。</p>
|
||
</details>
|
||
<details>
|
||
|
||
<summary>Q14.推 DPO loss 从 §6.1 的闭式 $\pi^*$ 开始。</summary>
|
||
<ol><li>§6.1 给 $\pi^*(y|x) = \pi_\text{ref}\exp(r/\beta)/Z(x)$</li><li>反解 $r(x,y) = \beta\log(\pi^*/\pi_\text{ref}) + \beta\log Z(x)$</li><li>Bradley-Terry: $P(y_w \succ y_l) = \sigma(r_w - r_l)$</li><li>关键观察:$\beta\log Z(x)$ 不依赖 $y$,<strong>在 $r_w - r_l$ 差里消掉</strong>: $r_w - r_l = \beta\log(\pi^*(y_w)/\pi_\text{ref}(y_w)) - \beta\log(\pi^*(y_l)/\pi_\text{ref}(y_l))$</li><li>把 $\pi^*$ 改为可学 $\pi_\theta$,对偏好数据做 NLL: $\mathcal{L}_\text{DPO} = -\mathbb{E}\log\sigma(\beta\log(\pi_\theta(y_w)/\pi_\text{ref}(y_w)) - \beta\log(\pi_\theta(y_l)/\pi_\text{ref}(y_l)))$</li></ol>
|
||
<p>关键 trick:<strong>$\log Z$ 不依赖 $y$</strong>,所以在 pairwise 差里抵消(这是 DPO 不需要采样的根本原因)。</p>
|
||
<p>不解释 $\log Z$ 为什么消掉;或不知道 BT 的 sigmoid。</p>
|
||
</details>
|
||
<details>
|
||
|
||
<summary>Q15.推 DPO 梯度。</summary>
|
||
<p>记 $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)。</p>
|
||
<p>$\mathcal{L}_\text{DPO} = -\mathbb{E}\log\sigma(h_\theta)$,$\nabla = -\mathbb{E}\sigma'(h_\theta)/\sigma(h_\theta) \cdot \nabla h_\theta$。</p>
|
||
<p>用 $\sigma'(x) = \sigma(x)\sigma(-x)$,$\sigma'(h)/\sigma(h) = \sigma(-h) = \sigma(\hat{r}_l - \hat{r}_w)$(即"错位置信度")。</p>
|
||
<p>$\nabla h_\theta = \beta(\nabla\log\pi_\theta(y_w) - \nabla\log\pi_\theta(y_l))$($\pi_\text{ref}$ 是常数,求 $\theta$ 导为 0)。</p>
|
||
<p>合并:</p>
|
||
<p>$$\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))]$$</p>
|
||
<p>解读:</p>
|
||
<ul><li>系数 $\sigma(\hat{r}_l - \hat{r}_w)$ 是 "当前 model 多大程度上错把 $y_l$ 排在前面" → hard-example mining</li><li>后面就是提升 $y_w$ 概率 + 降低 $y_l$ 概率</li></ul>
|
||
<p>少推一步 sigmoid' 公式;或不知道 $\sigma'(x) = \sigma(x)\sigma(-x)$。</p>
|
||
</details>
|
||
<details>
|
||
|
||
<summary>Q16.k2 estimator 为什么有偏?小 KL 极限下偏多少?</summary>
|
||
<p>记 $r = \pi_\theta/\pi_\text{ref}$,$y \sim \pi_\theta$,$\text{KL}(\pi_\theta\|\pi_\text{ref}) = \mathbb{E}_{\pi_\theta}[\log r]$。</p>
|
||
<ul><li><strong>k2</strong> 定义 $\mathbb{E}_{\pi_\theta}[\tfrac12(\log r)^2]$,一般 $\ne \mathbb{E}[\log r]$ — 所以<strong>有偏</strong>。</li><li><strong>正确的 Taylor 展开</strong> 要用 $s = \pi_\text{ref}/\pi_\theta = 1/r$(这是 $\mathbb{E}_{\pi_\theta}[s] = 1$ 的随机变量,可做 mean-1 展开)。$\log r = -\log s$,$\log s = (s-1) - \tfrac12 (s-1)^2 + O((s-1)^3)$。</li><li>$\mathbb{E}_{\pi_\theta}[\log r] = -\mathbb{E}[\log s] = -\mathbb{E}[s-1] + \tfrac12\mathbb{E}[(s-1)^2] + O(\cdot) = 0 + \tfrac12\mathrm{Var}(s) + O$. 这与 Fisher 二阶展开一致。</li><li>$\mathbb{E}_{\pi_\theta}[\tfrac12 (\log r)^2] = \tfrac12\mathbb{E}[(\log s)^2] = \tfrac12\mathbb{E}[(s-1)^2] + O((s-1)^3) = \tfrac12\mathrm{Var}(s) + O$.</li><li>所以<strong>小 KL(即 $r\approx 1$)极限下</strong>:$\mathbb{E}[k_2] \approx \mathbb{E}[\log r] = \text{KL}$,二阶等价。</li><li>大 KL 下 k2 系统性偏离 KL(高阶项不可忽略,方向取决于分布的高阶矩)。</li></ul>
|
||
<p><strong>关键修正</strong>:旧版本写 "$\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 的标准结果)。</p>
|
||
<p>只说"二阶近似";不展开 Taylor,或者错用 $r$ 而非 $s$ 做 mean-1 展开。</p>
|
||
</details>
|
||
<details>
|
||
|
||
<summary>Q17.Adaptive β 与 PID controller 的类比?</summary>
|
||
<ul><li>Adaptive β(PPO Schulman 2017)只用 P 项:若 KL > target → β ↑;若 KL < target → β ↓</li><li>对比 PID controller:$u(t) = K_p e + K_i\int e + K_d \dot{e}$</li><li>P 项 = 当前误差比例响应</li><li>I 项 = 累积误差(防 steady-state error),但 KL 是 stochastic,加 I 容易振荡</li><li>D 项 = 误差变化率(damping),但 KL 估计本身高方差,D 容易放大噪声</li><li>工程实践:<strong>只用 P 项</strong>最 robust(TRL 默认);某些 framework 加 small I 项做长期收敛</li></ul>
|
||
<p>只说 "类似 P controller" 不展开;或加上 D 项不知会出问题。</p>
|
||
</details>
|
||
<details>
|
||
|
||
<summary>Q18.GRPO 的 k3 KL 在 reward 是 binary (0/1) 时怎么调 β?</summary>
|
||
<ul><li>Reward = {0, 1},advantage scale ≈ O(1)</li><li>KL_k3 per-token 初始 ≈ 0(policy 与 ref 相同),训练中可达 0.1 ~ 0.5</li><li>若 β = 0.04,KL penalty per-token ≈ 0.04 × 0.3 ≈ 0.012,与 advantage 比合理</li><li>若 β = 1,KL penalty per-token ≈ 0.3,<strong>远大于</strong> advantage,loss 被 KL 主导</li><li>经验:数学任务起始 β = 0.01 ~ 0.04,看 KL 曲线调;DAPO 经常 β = 1e-3 或 0</li><li>对比 RLHF helpfulness 任务:reward scale 大(连续 [-5, 5])→ β 可以大些(0.1 ~ 0.5)</li></ul>
|
||
<p>不知 β 与 reward scale 的耦合;或机械套 β = 0.04。</p>
|
||
</details>
|
||
<details>
|
||
|
||
<summary>Q19.SimPO 没有 reference model,为什么还能 work?没了 KL anchor 不是会 reward hack 吗?</summary>
|
||
<ul><li>SimPO 用 <strong>length-normalization</strong> $r = (\beta/|y|)\log\pi(y)$ + <strong>target reward margin</strong> $\gamma$</li><li>没有 KL anchor,但 length-norm 阻止 "$y_w$ 越长越优" 的退化</li><li>Margin $\gamma$ 让 loss 在 $r_w - r_l > \gamma$ 时 saturate,避免 implicit reward 无界</li><li>实测某些 benchmark(AlpacaEval-2 / Arena-Hard)SimPO 优于 DPO</li><li>但<strong>没有 KL anchor 的代价</strong>:OOD 鲁棒性差、对 $\beta, \gamma$ 调参敏感、生成长度可能仍然偏大</li><li>实际生产中 DPO + small β 仍然主流,SimPO 是 "在某些 benchmark 上更强但 trade off 不同" 的选择</li></ul>
|
||
<p>说 SimPO 一定更好;或不知道 length-norm + margin 是 KL 的替代。</p>
|
||
</details>
|
||
<details>
|
||
|
||
<summary>Q20.Per-token KL 和 sequence-level KL 是什么关系?</summary>
|
||
<ul><li>由 KL 的<strong>链式法则</strong>(条件分解): $\text{KL}(\pi_\theta(\cdot|x) \| \pi_\text{ref}(\cdot|x)) = \mathbb{E}_{y\sim\pi_\theta}[\sum_t \log(\pi_\theta(y_t|x,y_{<t})/\pi_\text{ref}(y_t|x,y_{<t}))]$</li><li>即 <strong>sequence-level KL = token-level KL 之和的期望</strong></li><li>工程上只能 token-level 算(vocab 维度求和 OK,sequence 维度组合爆炸)</li><li>实际写 RLHF loss:per-token KL → mask assistant tokens → sum → average per sequence</li><li>注意:prompt token 上 policy 和 ref 输入相同,KL 应 = 0,但 floating-point 噪声会污染 → 必须 mask</li></ul>
|
||
<p>混淆两者;或不知道 mask only assistant tokens 的必要性。</p>
|
||
</details>
|
||
<h3 id="l3-顶级-lab-题5-题">L3 顶级 lab 题(5 题)</h3>
|
||
<details>
|
||
|
||
<summary>Q21.证明 $f(x) = e^x - x - 1 \ge 0$ 对所有 $x \in \mathbb{R}$。从该不等式出发,推导 k3 的非负性、无偏性。哪个性质对 "KL 作为 loss 加项" 更关键,为什么?</summary>
|
||
<p><strong>非负证明</strong>:</p>
|
||
<p>$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$。✓</p>
|
||
<p><strong>k3 非负性</strong>:取 $x = \log(\pi_\text{ref}/\pi_\theta) = -\log r$,则 $\widehat{\text{KL}}_3 = f(-\log r) \ge 0$ 总成立。✓</p>
|
||
<p><strong>k3 无偏性</strong>:</p>
|
||
<p>$\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}$ ✓</p>
|
||
<p><strong>哪个性质对 loss 加项更关键?</strong></p>
|
||
<ul><li><strong>非负 + value-side 无偏</strong>:这些是好的<strong>监控/数值显示</strong>性质——KL loss 曲线不会出现负值或大幅噪声。但 <strong>k3-as-loss 的关键问题不在数值层</strong>,而在 gradient 层。</li><li>⚠️ <strong>k3 作为 loss 反传时的 gradient 是 reverse-KL gradient 的 first-order Taylor approximation</strong>:$\nabla(e^{-\Delta} + \Delta - 1) = (1-e^{-\Delta})\nabla\Delta = (\Delta - \tfrac12\Delta^2 + O(\Delta^3))\,\nabla\log\pi_\theta$,有 $O(\Delta^2)$ bias(见 §3.6 + Rethinking KL arXiv 2510.01555)。</li><li><strong>真正 principled 的 loss 选择是 (P2) k2-as-loss</strong>:$\nabla(\tfrac12\Delta^2) = \Delta\,\nabla\log\pi_\theta$ 在 on-policy 期望下等于严格 reverse-KL gradient。k2 数值未 calibrated 但 gradient 正确,与 k1-in-reward gradient-equivalent。</li><li><strong>如果坚持要"非负 + 无偏 + 易监控"</strong> ⇒ k3 仍是最佳 <strong>value estimator</strong>;但要分清"value-side k3 monitor + loss-side k2/k1-in-reward gradient"这一组合,比 "k3-as-loss" 更 principled。</li></ul>
|
||
<p>所以 k3 在 <strong>value-monitoring 层面</strong>最方便(非负 + value-unbiased + 低方差)。但<strong>对于 "as loss addend" 的 principled 性,关键不是非负,而是 loss-gradient 是否匹配真实 reverse-KL gradient</strong>——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 可忽略。</p>
|
||
<p><strong>易错</strong>:把非负当作 "loss addend 的 key" —— 那只是数值显示层面的优势;真正决定 principled 性的是 gradient correctness。理想组合是 "value-side k3 monitor + loss-side k2/k1-in-reward gradient"。</p>
|
||
</details>
|
||
<details>
|
||
|
||
<summary>Q22.推导 DPO 的 implicit reward 与 KL-regularized RL 的 policy gradient 之间的"对偶等价性"。</summary>
|
||
<p>设定:$\max_\pi \mathbb{E}_\pi[r] - \beta\,\text{KL}(\pi\|\pi_\text{ref})$,闭式解 $\pi^*(y|x) = \pi_\text{ref}\exp(r/\beta)/Z$。</p>
|
||
<p><strong>RL 视角</strong>:当 reward $r$ 给定时,最优 policy 通过 importance-weighted update 朝 $\pi^*$ 走。Score function policy gradient:</p>
|
||
<p>$\nabla_\theta J = \mathbb{E}_{\pi_\theta}[\nabla\log\pi_\theta \cdot (r - \beta\log(\pi_\theta/\pi_\text{ref}))]$</p>
|
||
<p><strong>DPO 视角</strong>:把 $\pi$ 直接看作待学 $\pi_\theta$,用 BT 反解 implicit reward $\hat{r} = \beta\log(\pi_\theta/\pi_\text{ref}) + \beta\log Z$,对偏好对做 NLL。</p>
|
||
<p><strong>等价性</strong>:</p>
|
||
<ol><li>闭式解给出 $r = \beta\log(\pi^*/\pi_\text{ref}) + \beta\log Z$。</li><li>若 $\pi_\theta = \pi^*$(即 RL 已收敛),则 implicit reward 恢复真实 $r$(up to additive $\beta\log Z$,但 $\log Z$ 在 BT pairwise 中抵消)。</li><li>RL 梯度 $\propto r - \beta\log(\pi_\theta/\pi_\text{ref})$,在收敛时 $= \beta\log Z(x)$(常数 in $y$)→ 梯度为零(PG 在 $\pi^*$ 处停)。</li><li>DPO 梯度 $\propto \sigma(\hat{r}_l - \hat{r}_w)(\nabla\log\pi(y_w) - \nabla\log\pi(y_l))$,在 $\pi_\theta = \pi^*$ 处对应"BT 模型 perfectly fits" → 梯度同步消失。</li><li>两个视角的固定点(fixed point)都是 $\pi^*$,所以<strong>RL 和 DPO 都在 optimize 同一目标,只是从两个角度切入</strong>:RL 是 forward optimization(直接 max $J$),DPO 是 inverse optimization(用偏好数据 fit BT 模型)。</li></ol>
|
||
<p><strong>关键</strong>:DPO 不是 RL 的替代,是<strong>对同一目标的不同 reduction</strong>——RL 通过 sampling-based PG,DPO 通过 closed-form + supervised learning。"DPO 没有 RL" 是误读。</p>
|
||
<p>只说"DPO 推 RL 闭式解"不展开 gradient 等价性;或不知道两者 fixed point 相同。</p>
|
||
</details>
|
||
<details>
|
||
|
||
<summary>Q23.从 $\sqrt{\text{KL}}$ 和 inverted-U gold curve 推 reward overoptimization 的"安全 KL budget"。</summary>
|
||
<p>Gao 2023 的 BoN gold reward 拟合:$R_g(d) = d(\alpha_g - \gamma_g d)$,$d = \sqrt{\text{KL}}$。</p>
|
||
<p>求 peak:$dR_g/dd = \alpha_g - 2\gamma_g d = 0$ → $d_\text{peak} = \alpha_g / (2\gamma_g)$。</p>
|
||
<p>对应 KL distance:$\text{KL}_\text{peak} = d_\text{peak}^2 = \alpha_g^2 / (4\gamma_g^2)$。</p>
|
||
<p><strong>安全 budget</strong>:要在 peak 之前停下来。一般选 $\text{KL}_\text{stop} = 0.5 \cdot \text{KL}_\text{peak}$(留 50% safety margin)。</p>
|
||
<p><strong>怎么估 $\alpha_g, \gamma_g$?</strong> 需要 gold reward 信号(人工 / 强 RM ensemble)。在小规模 pilot run 跑几个 KL 点,拟合 $R_g(d)$。</p>
|
||
<p><strong>RM 越大,越靠右</strong>:Gao 2023 给的 scaling law 表明 $\alpha_g, \gamma_g$ 随 RM size 改变(拟合系数本身依赖于 RM 规模和数据),更大 RM 的 $\text{KL}_\text{peak}$ 更靠右,但 $R_g(\text{peak})$ 也更高。这是为什么大 RM 既"对得起 budget" 又能拿更高 gold。</p>
|
||
<p><strong>PPO 比 BoN 复杂一点</strong>:$R_g(d) = d(\alpha_g - \gamma_g d) - \delta_g d^{3/2}$,三阶项使 peak 稍微靠左。</p>
|
||
<p>应用:实际工程里把 measured KL 限制在 $\text{KL}_\text{peak} \cdot 0.5$ 作 early stop,即 "$\sqrt{\text{KL}}$ < $d_\text{peak}/2$"。</p>
|
||
<p>不展开 derivative;或不知 RM size 与 peak 的 scaling。</p>
|
||
</details>
|
||
<details>
|
||
|
||
<summary>Q24.如果让你设计一个 RLHF 算法,把 reverse + forward KL 联合用,会怎么用?</summary>
|
||
<p><strong>动机</strong>(按标准约定:reverse = $\text{KL}(q\|p)$ mode-seeking,forward = $\text{KL}(p\|q)$ mass-covering):</p>
|
||
<ul><li><strong>Reverse KL</strong> $\text{KL}(\pi_\theta\|\pi_\text{ref})$ = mode-seeking on $\pi_\theta$ → 选 ref 高密度区里 reward 高的 mode(合规则)。<strong>RLHF 默认就用这条</strong>。</li><li><strong>Forward KL</strong> $\text{KL}(\pi_\text{ref}\|\pi_\theta)$ = mass-covering on $\pi_\theta$ → 让 $\pi_\theta$ 覆盖 ref 的所有可能输出(防 mode collapse)。</li></ul>
|
||
<p><strong>问题</strong>:forward KL 需要从 $\pi_\text{ref}$ 采样,工程上没意义(要训的是 $\pi_\theta$ 不是 $\pi_\text{ref}$)。</p>
|
||
<p><strong>绕路方案 (theoretical)</strong>:</p>
|
||
<ol><li><strong>JSD-style combo</strong>:用 $\text{JS}(\pi_\theta\|\pi_\text{ref}) = \tfrac{1}{2}\text{KL}(\pi_\theta\|m) + \tfrac{1}{2}\text{KL}(\pi_\text{ref}\|m)$,$m = (\pi_\theta + \pi_\text{ref})/2$。对称、有界,可同时拿 mode-seeking 和 mass-covering。问题:$m$ 不是闭式(mixture distribution),梯度计算复杂。</li><li><strong>Importance sampling</strong>:从 $\pi_\theta$ 采样,但 reweight 成 $\pi_\text{ref}$ 期望:$\mathbb{E}_{\pi_\theta}[(\pi_\text{ref}/\pi_\theta)\log(\pi_\text{ref}/\pi_\theta)] = \text{KL}(\pi_\text{ref}\|\pi_\theta)$。问题:tail 上 $\pi_\text{ref}/\pi_\theta$ 极大,方差炸。</li><li><strong>Symmetric KL</strong>:$\text{KL}_\text{sym} = \tfrac{1}{2}(\text{KL}(\pi_\theta\|\pi_\text{ref}) + \text{KL}(\pi_\text{ref}\|\pi_\theta))$,对称但同样需要 forward 一侧的估计。</li><li><strong>Hybrid penalty</strong>:训练前期主要 reverse KL(让 policy 朝 mode 收)+ 后期加 small forward KL term 用 importance sampling 估,限制 mode collapse。</li></ol>
|
||
<p><strong>实际工业方案(更简单)</strong>:</p>
|
||
<ul><li>用 entropy bonus 替代 forward KL 的 "mass coverage" 目标——entropy 不需要 ref 采样。</li><li>用 ensemble policy 训练,多个 policy 各自 mode-seek 不同 mode,整体保持多样性。</li><li>用 BoN inference + DPO/PPO training 组合:训练时 mode-seek,推理时多样性来源于 BoN 采样。</li></ul>
|
||
<p><strong>总结</strong>:forward KL 在 RLHF 里"理论吸引但工程难",主流做法是用 entropy / multiple policies 替代。</p>
|
||
<p>只说"两个都加上"——太天真,要给出工程方案;不知道 forward KL 的 sampling 障碍。</p>
|
||
</details>
|
||
<details>
|
||
|
||
<summary>Q25.下一代 RLHF 算法可能怎么改进 KL regularization?给 3 个方向 + trade-off。</summary>
|
||
<p><strong>方向 1:Adaptive KL estimator per token</strong></p>
|
||
<ul><li>对每 token 单独决定用 k1 还是 k3:小 KL token 用 k1(无偏 + 简单),大 KL token 用 k3(防方差爆炸)。</li><li>Trade-off:实现复杂度 + per-token 阈值难定。</li></ul>
|
||
<p><strong>方向 2:Per-task β controller</strong></p>
|
||
<ul><li>不同 sub-task(数学 / 代码 / 对话 / safety)用不同 β,由 task classifier 在线分发。</li><li>Trade-off:要求 task labels 准确;β 之间的 cross-task 干扰需要研究。</li></ul>
|
||
<p><strong>方向 3:Adversarial KL</strong></p>
|
||
<ul><li>不固定 $\pi_\text{ref}$,让 $\pi_\text{ref}$ 也在线学(如 self-rewarding LM、iterative DPO),但每轮固定一个时间窗内的 $\pi_\text{ref}$。</li><li>Trade-off:可能 unstable(GAN-like);需要 fresh human label 防 drift。</li></ul>
|
||
<p><strong>方向 4:Distributional reward + W2 KL</strong></p>
|
||
<ul><li>把 reward 也建模成分布 $p(r|x,y)$,KL 用 Wasserstein-2 metric(geometric)替代。</li><li>Trade-off:W2 计算复杂、需 sliced approximation;理论收敛性不清。</li></ul>
|
||
<p><strong>方向 5:Hierarchical KL</strong></p>
|
||
<ul><li>句子级 KL + token 级 KL 联合:句子级控总 KL 预算,token 级做细粒度 anchoring。</li><li>类比:PRM (process reward) 之于 ORM (outcome reward)。</li><li>Trade-off:sentence boundary 在生成时不显式,需要额外标注或 heuristics。</li></ul>
|
||
<p><strong>方向 6:KL-free 但 trust-region 替代</strong></p>
|
||
<ul><li>完全去 KL,用 PPO clip 的 trust region 来约束("clip is enough")。</li><li>已有 IRL / SimPO 等尝试。</li><li>Trade-off:失去闭式 RL 数学基础(无 $\pi^* \propto \pi_\text{ref}\exp(r/\beta)$)。</li></ul>
|
||
<p>只罗列没 trade-off;或不知道 SimPO / IPO 已部分探索 KL-free 路线。</p>
|
||
</details>
|
||
<h2 id="a-附录参考文献清单">§A 附录:参考文献清单</h2>
|
||
<p>按章节分组。本节为草稿初版,<strong>arXiv ID 与精确发表场所未经在线核实</strong>——校验时应通过 <code>/arxiv</code> 或 codex web_search 重新查证。</p>
|
||
<p><strong>KL 基础与 estimators</strong></p>
|
||
<ul><li>Schulman 2020 blog <em>Approximating KL Divergence</em> <code>http://joschu.net/blog/kl-approx.html</code>(k1 / k2 / k3 estimator 的标准来源)</li><li>Endres & Schindelin 2003 IEEE TIT 49(7) <em>A New Metric for Probability Distributions</em>($\sqrt{\text{JS}}$ 是 metric 的证明)</li><li>Pinsker 1964(原始 Pinsker 不等式 $\text{TV} \le \sqrt{\text{KL}/2}$)</li></ul>
|
||
<p><strong>RLHF / PPO</strong></p>
|
||
<ul><li>Schulman et al. 2017 arXiv 1707.06347 <em>Proximal Policy Optimization Algorithms</em>(PPO-Clip + PPO-Penalty adaptive β)</li><li>Ouyang et al. 2022 NeurIPS <em>Training Language Models to Follow Instructions with Human Feedback</em>(InstructGPT,per-token KL in reward)</li><li>Bai et al. 2022 Anthropic arXiv 2204.05862 <em>Training a Helpful and Harmless Assistant with RLHF</em>(adaptive β controller)</li></ul>
|
||
<p><strong>DPO 系</strong></p>
|
||
<ul><li>Rafailov et al. 2023 NeurIPS <em>Direct Preference Optimization: Your Language Model is Secretly a Reward Model</em>(闭式 + 反解 + BT)</li><li>Azar et al. 2024 AISTATS <em>A General Theoretical Paradigm to Understand Learning from Human Preferences</em>(IPO,防 deterministic preference 下 reward 无界)</li><li>Ethayarajh et al. 2024 ICML <em>KTO: Model Alignment as Prospect Theoretic Optimization</em>(reference point 替代 KL)</li><li>Meng et al. 2024 NeurIPS <em>SimPO: Simple Preference Optimization with a Reference-Free Reward</em>(去 ref,length-norm + margin)</li><li>Hong et al. 2024 EMNLP <em>ORPO: Monolithic Preference Optimization without Reference Model</em>(odds-ratio 一阶段)</li></ul>
|
||
<p><strong>GRPO 系 / RL with k3 KL</strong></p>
|
||
<ul><li>Shao et al. 2024 arXiv 2402.03300 <em>DeepSeekMath: Pushing the Limits of Mathematical Reasoning</em>(GRPO 首次系统使用 k3 + group-relative advantage)</li><li>DeepSeek-AI 2025 arXiv 2501.12948 <em>DeepSeek-R1</em>(GRPO + rule-based reward + emergent CoT)</li><li>Yu et al. 2025 ByteDance arXiv 2503.14476 <em>DAPO: An Open-Source LLM Reinforcement Learning System at Scale</em>(clip-higher + dynamic sampling + token-level loss + 小 β)</li></ul>
|
||
<p><strong>Reward Overoptimization</strong></p>
|
||
<ul><li>Gao, Schulman, Hilton 2023 ICML <em>Scaling Laws for Reward Model Overoptimization</em>(KL distance vs gold reward 的 inverted-U + 拟合 form)</li><li>Coste et al. 2024 ICLR <em>Reward Model Ensembles Help Mitigate Overoptimization</em></li><li>Eisenstein et al. 2024 COLM (arXiv 2312.09244, 2023) <em>Helping or Herding? Reward Model Ensembles Mitigate but do not Eliminate Reward Hacking</em></li></ul>
|
||
<p><strong>Critic-free RL(与 KL 放置相关)</strong></p>
|
||
<ul><li>Ahmadian et al. 2024 ACL <em>Back to Basics: Revisiting REINFORCE Style Optimization</em>(RLOO,leave-one-out baseline,KL in reward)</li><li>Li et al. 2024 ICML <em>ReMax: A Simple, Effective, and Efficient Reinforcement Learning Method</em></li></ul>
|
||
<p><strong>两篇 2024-2026 KL-in-RLHF 系统分析论文(已核验 arXiv 元数据)</strong></p>
|
||
<ul><li>Kezhao Liu et al., <em>Rethinking KL Regularization in RLHF: From Value Estimation to Gradient Optimization</em>, arXiv 2510.01555 (2025-10-02). 系统区分 KL value estimation vs gradient optimization;指出 k3-as-loss 是 biased first-order approximation;推荐 (P1) k1 in reward 或 (P2) k2 as loss;off-policy 需 IS correction。本教程 §3.6 内容基于该论文。</li><li>Vedant Shah et al., <em>A Comedy of Estimators: On KL Regularization in RL Training of LLMs</em>, arXiv 2512.21852 (2025-12-26, v3 2026-03-18). 实证对比 k1/k2/k3 在多种 RL 算法 + placement 组合上的 estimator bias / gradient bias / placement-effect;结论:不存在 universally 最好的 estimator。</li></ul>
|
||
<p><strong>Zhihu 中文资料</strong></p>
|
||
<ul><li><code>https://zhuanlan.zhihu.com/p/1979720260128118305</code> — <em>KL 进阶:Forward KL、Reverse KL、KL 估计与应用</em>(已核验,主题与 RLHF KL estimator 一致)</li><li><code>https://zhuanlan.zhihu.com/p/1892008158626546312</code> — [needs-verify URL accessibility] 题目疑似涉及 k2-loss vs k3-loss / GRPO off-policy / clip_std;用户校验时若链接失效可替换。</li></ul>
|
||
<p><strong>与本文紧密相关的内部教程</strong></p>
|
||
<ul><li><code>docs/tutorials/rlhf_dpo_grpo_ppo_tutorial.md</code> — RLHF / DPO / GRPO / PPO 总览(包含 BT + 闭式 + DPO 推导)</li><li><code>docs/tutorials/reasoning_models_tutorial.md</code> — Reasoning models 的 RL 训练细节</li><li><code>docs/tutorials/agentic_rl_tutorial.md</code> — Agentic setting 下的 token mask + KL 讨论</li></ul>
|
||
|
||
<footer class="aris-footer">
|
||
Generated by <a href="https://github.com/wanshuiyin/Auto-claude-code-research-in-sleep/blob/main/skills/render-html/SKILL.md">ARIS <code>/render-html</code></a> ·
|
||
source path <code>docs/tutorials/kl_divergence_rlhf_tutorial.md</code> ·
|
||
SHA256 <code>f0b8b5e62023</code> ·
|
||
generated at 2026-05-19 19:13 UTC.
|
||
This is a generated view — edit the source Markdown, then re-render.
|
||
</footer>
|
||
</main>
|
||
|
||
</div>
|
||
</body>
|
||
</html>
|