LECTURE 14

序列与大语言模型上的强化学习

奖励从哪里来?把一段文本生成写成 MDP 之后,PPO、GRPO、RLHF、RLVR 到底在优化什么;以及当状态不可观测时,哪些算法还能用。

讲师:Sergey Levine UC Berkeley 原始材料:lec-14.pdf(51 页)

0. 本讲导读

这一讲是整门课里离当下工业实践最近的一讲。它由五个部分拼成,而这五个部分之间有一条非常清晰的暗线:奖励函数不是天上掉下来的。

前面十几讲我们默认奖励 $r(s,a)$ 是已知的:Atari 游戏的屏幕上写着分数,MuJoCo 的仿真器直接给你前进速度。但只要走出仿真器一步,问题就变了——一辆车在高速公路上变道,什么叫「奖励」?变道快是好事还是坏事?超车激进一点算加分还是扣分?没有人能写下这个函数。于是有两条路:

  • 逆强化学习(Inverse Reinforcement Learning, IRL):从人类的演示轨迹里把奖励反解出来。这是本讲第 1、2 节,它直接建立在上一讲「控制即推断」的最优性变量 $\mathcal O_t$ 之上,最后会发现 IRL 和 GAN 在数学上是同一件事。
  • 从人类偏好里学奖励:不要求人演示(太贵),只要求人在两个候选之间选一个。这条路走到今天就是 RLHF,就是 ChatGPT。这是本讲第 8 节。

中间的第 3–7 节回答另一个问题:语言模型的 MDP 到底是什么?一段 token 序列既可以看成「一个动作」(一步 bandit),也可以看成「一串动作」(token 级 MDP)。这两种视角在只有末端奖励时是等价的,但一旦引入价值函数基线和中间奖励,第二种视角才说得通。想明白这件事之后,PPO、GRPO 在 LLM 上的所有实现细节都会变成三个可选项的组合:选一个基线(1)、选一个正则化器(2)、选或者学一个奖励(3)。

第 9 节是可验证奖励(RLVR)与推理模型:当奖励不再来自一个可能被欺骗的神经网络,而来自一个数学答案检查器或者单元测试时,RL 的行为会发生什么变化。第 10 节(原讲的 bonus part)回到理论:部分可观测。这看似与 LLM 无关,其实是同一件事的另一面——多轮对话、工具调用、智能体,本质上都是 POMDP,而 Transformer 的上下文窗口就是教科书里说的「历史状态」。

核心结论
  • 最大熵 IRL 的梯度是一个对比式的表达式:在专家轨迹上抬高奖励,在当前策略的软最优轨迹上压低奖励。困难全在配分函数 $Z$ 上,解法是用一个 max-ent RL 的策略去做采样估计,再用重要性采样修正「没优化到底」带来的偏差。
  • 把生成器当策略、把判别器当奖励,IRL 就是 GAN。GAIL 用普通判别器(简单但收敛时判别器一无所知、奖励不可复用),AIRL 把判别器写成 $D=\frac{\frac1Z e^{r}}{\frac1Z e^{r}+\pi}$(复杂但学到真正的奖励)。
  • LLM 的 RL 有两种等价建模:一步 bandit(状态=prompt,动作=整段补全)和 token 级 MDP(状态=前缀,动作=下一个 token,转移是确定性拼接)。奖励通常只在最后一个 token 给出。
  • 实践中一律用重要性加权(PPO 式)估计器而不是纯 REINFORCE,原因很现实:从 LLM 采样极贵,必须让同一批样本喂多次梯度步。
  • 基线有两种选法:训一个价值函数 + GAE(要多一个和策略同样大的 critic),或者对同一个 prompt 采 $K$ 个回答、用组内均值当基线——后者就是 GRPO。
  • 参考模型 KL 惩罚 $\bar r = r - \beta \KL(\pi_\theta\|\pi_{\text{ref}})$ 有两个作用:保证输出还是人话,以及防止策略去「利用」不完美的奖励模型(reward hacking)。它同时是 DPO 推导的起点。
  • Bradley–Terry 模型把「$\tau_i$ 比 $\tau_j$ 好」写成 $\log\sigma(r_\psi(\tau_i)-r_\psi(\tau_j))$,训练奖励模型就是一次逻辑回归。奖励只在差值意义下可辨识。
  • 值函数方法在没有马尔可夫性时会坏掉;策略梯度不会。学一个隐状态空间模型,或者干脆把整段历史丢给序列模型,是两条通用出路。

1. 为什么要学奖励:最大熵逆强化学习

先把动机说透。强化学习的标准设定是「给定 $r(s,a)$,找 $\pi$」。Breakout 里屏幕顶端那串数字就是奖励,写代码读出来即可。但换成「在高速公路上开车」这类任务,你能写出的所有候选奖励都是错的:写「速度越快越好」会得到一个疯子;写「和前车距离越大越好」会得到一个永远不敢并线的司机;手工调权重的多目标奖励在真实分布下总能找到你没想到的漏洞。

Breakout 的分数条 vs 高速公路变道,问「奖励是什么」
左边是 RL 的舒适区:奖励被明码标价地印在屏幕上。右边是真实世界:一次变道的好坏取决于安全、效率、舒适、对其他司机的礼貌等一堆无法写成解析式的东西。人类却能演示「什么叫开得好」——于是问题变成:能不能从演示里把奖励反推出来。

从最优性变量出发

上一讲我们引入了最优性变量 $\mathcal O_t$,并令

$$ p(\mathcal O_t\mid s_t,a_t)=\exp\big(r_\psi(s_t,a_t)\big), $$

其中 $\psi$ 是奖励函数的参数(不是策略参数 $\theta$)。在这个概率图模型下,给定「全程都最优」这个条件,轨迹的后验是

$$ p(\tau\mid \mathcal O_{1:T},\psi)\;\propto\; p(\tau)\exp\!\Big(\sum_t r_\psi(s_t,a_t)\Big), $$

其中 $p(\tau)=p(s_1)\prod_t p(s_{t+1}|s_t,a_t)$ 是只由动力学决定的先验,与 $\psi$ 无关,所以在对 $\psi$ 求导时可以整体划掉(幻灯片上就是那一道红杠)。

学习最优性变量:最大似然目标与配分函数
把奖励参数塞进最优性变量的似然里。给定从专家策略 $\pi^\star(\tau)$ 采到的样本 $\{\tau_i\}$,做最大似然:目标退化成「专家轨迹的奖励和」减去「配分函数的对数」。下方的图模型显示 $\mathcal O_1,\mathcal O_2,\mathcal O_3$ 全部被观测为真(灰色阴影),每个 $\mathcal O_t$ 由 $(s_t,a_t)$ 决定。$\log Z$ 就是全部困难所在。

现在假设我们手上有一批专家演示 $\{\tau_i\}_{i=1}^N\sim\pi^\star(\tau)$。做最大似然学习:

$$ \max_\psi \frac1N\sum_{i=1}^N \log p(\tau_i\mid\mathcal O_{1:T},\psi) =\max_\psi \frac1N\sum_{i=1}^N r_\psi(\tau_i)-\log Z, $$

这里 $r_\psi(\tau)\triangleq\sum_t r_\psi(s_t,a_t)$,而

$$ Z=\int p(\tau)\exp\big(r_\psi(\tau)\big)\,d\tau . $$
直觉 如果没有 $-\log Z$ 这一项,目标就是「把专家轨迹的奖励调到无穷大」,最优解是 $r_\psi\equiv+\infty$,毫无信息量。$\log Z$ 是归一化压力:它对所有可能的轨迹的奖励取 log-sum-exp,所以你把某条轨迹抬高,别的轨迹就得相对被压下去。这和能量模型(EBM)里的「正相/负相」是完全一样的结构。

配分函数的梯度

IRL 配分函数的梯度推导,正相减负相
逐行的推导:先写出 $\nabla_\psi\mathcal L$,注意到 $\frac1Z p(\tau)\exp(r_\psi(\tau))$ 恰好就是软最优后验 $p(\tau|\mathcal O_{1:T},\psi)$,于是梯度化成两个期望之差——第一项在专家样本上估计,第二项在当前奖励下的软最优策略上估计。

一步步来。对 $\psi$ 求导:

$$ \nabla_\psi\mathcal L=\frac1N\sum_{i=1}^N\nabla_\psi r_\psi(\tau_i)\;-\;\nabla_\psi\log Z . $$

第二项展开:$\nabla_\psi \log Z=\frac{1}{Z}\nabla_\psi Z$,而

$$ \nabla_\psi Z=\int p(\tau)\exp\big(r_\psi(\tau)\big)\nabla_\psi r_\psi(\tau)\,d\tau , $$

因为 $\nabla_\psi \exp(r_\psi)=\exp(r_\psi)\nabla_\psi r_\psi$。于是

$$ \nabla_\psi\log Z=\int \underbrace{\frac{p(\tau)\exp(r_\psi(\tau))}{Z}}_{=\;p(\tau\mid\mathcal O_{1:T},\psi)}\nabla_\psi r_\psi(\tau)\,d\tau =\E_{\tau\sim p(\tau|\mathcal O_{1:T},\psi)}\big[\nabla_\psi r_\psi(\tau)\big]. $$

合起来就是本节最重要的一个式子:

$$ \nabla_\psi\mathcal L=\E_{\tau\sim\pi^\star(\tau)}\big[\nabla_\psi r_\psi(\tau)\big]-\E_{\tau\sim p(\tau|\mathcal O_{1:T},\psi)}\big[\nabla_\psi r_\psi(\tau)\big]. $$

左边这项用专家样本估计,直接对演示数据求平均即可。右边这项要从「当前奖励函数下的软最优策略」里采样——这就麻烦了,因为要知道这个分布,你得先解一遍 RL 问题。

推导 为什么右边那个分布叫「软最优策略」?上一讲证明了:在最优性变量模型下,后验 $p(a_t|s_t,\mathcal O_{1:T})$ 正是最大熵 RL 的最优策略,对应目标 $$ J(\theta)=\sum_t\E_{\pi(s_t,a_t)}\big[r_\psi(s_t,a_t)\big]+\E_{\pi(s_t)}\big[\mathcal H(\pi(a|s_t))\big]. $$ 也就是「最大化奖励,同时保持策略尽可能随机」。所以只要拿任何一个 max-ent RL 算法(例如 soft actor-critic)在当前的 $r_\psi$ 上训练出 $\pi$,再从它采样,就能估计第二个期望。
用 max-ent RL 的样本估计梯度的负相
把上面的想法写成可执行的形式:在当前奖励 $r_\psi$ 下跑最大熵 RL 得到策略,用它采 $M$ 条轨迹 $\{\tau_j\}$,梯度就近似成「$N$ 条专家轨迹的奖励梯度均值」减去「$M$ 条策略轨迹的奖励梯度均值」。这是 MaxEnt IRL 的原始形式。
$$ \nabla_\psi\mathcal L\approx\frac1N\sum_{i=1}^N\nabla_\psi r_\psi(\tau_i)-\frac1M\sum_{j=1}^M\nabla_\psi r_\psi(\tau_j). $$

「懒惰」的策略优化与重要性采样

问题来了:每更新一次奖励,就要把 RL 从头解一遍,代价高得离谱。自然的想法是——别解到底,只改进一点点。Levine 在幻灯片上直接把 “learn” 划掉,换成 “improve (a little)”。

懒惰策略优化引入偏差,用重要性采样修正
把「学到收敛」换成「只改进一点」之后,采样分布 $\pi$ 不再等于目标分布 $p(\tau|\mathcal O,\psi)$,估计器有偏。解法 1:重要性采样,给每条策略样本配一个权重 $w_j=\frac{p(\tau)\exp(r_\psi(\tau_j))}{\pi(\tau_j)}$,并做自归一化 $\frac{1}{\sum_j w_j}$。

代价是估计器变成有偏的——我们在用错误的分布去估计第二个期望。修正方式是重要性采样:

$$ \nabla_\psi\mathcal L\approx\frac1N\sum_{i=1}^N\nabla_\psi r_\psi(\tau_i)-\frac{1}{\sum_j w_j}\sum_{j=1}^M w_j\,\nabla_\psi r_\psi(\tau_j), \qquad w_j=\frac{p(\tau_j)\exp\big(r_\psi(\tau_j)\big)}{\pi(\tau_j)} . $$

这里用的是自归一化重要性采样(分母 $\sum_j w_j$ 而不是 $M$),因为 $Z$ 未知,权重只知道到一个常数倍——自归一化恰好把这个常数消掉。

重要性权重中动力学项相消,只剩奖励指数除以策略概率连乘
把 $p(\tau)$ 和 $\pi(\tau)$ 都按马尔可夫链展开:初始状态分布 $p(s_1)$ 和所有转移 $p(s_{t+1}|s_t,a_t)$ 在分子分母中一模一样,全部相消,只剩下 $\exp(\sum_t r_\psi)$ 除以 $\prod_t\pi(a_t|s_t)$。这意味着不需要知道动力学就能算权重。最下方一句话点题:每次对 $r_\psi$ 的更新都把采样分布往目标分布拉近一点。

展开写:

$$ w_j=\frac{\overbrace{p(s_1)\textstyle\prod_t p(s_{t+1}|s_t,a_t)}^{\text{相消}}\exp\big(\sum_t r_\psi(s_t,a_t)\big)}{\underbrace{p(s_1)\textstyle\prod_t p(s_{t+1}|s_t,a_t)}_{\text{相消}}\prod_t\pi(a_t|s_t)} =\frac{\exp\big(\sum_t r_\psi(s_t,a_t)\big)}{\prod_t\pi(a_t|s_t)} . $$

动力学项在分子分母里完全一致,直接约掉。这是本课反复出现的一个技巧(策略梯度里也用过):只要分子分母是同一个 MDP 下的两个策略,环境动力学永远消失。于是 $w_j$ 只需要奖励值和策略的动作概率,两者都是我们能算的。

这个算法就是 Guided Cost Learning:外层更新奖励,内层只跑几步策略改进,两者交替。它有一个很好的性质——每次奖励更新后,采样策略离目标分布更近一点,重要性权重的方差也就更小一点。

import torch, torch.nn as nn

class RewardNet(nn.Module):
    """r_psi(s, a) -> 标量,逐时间步"""
    def __init__(self, dim_s, dim_a, h=256):
        super().__init__()
        self.f = nn.Sequential(nn.Linear(dim_s + dim_a, h), nn.ReLU(),
                               nn.Linear(h, h), nn.ReLU(), nn.Linear(h, 1))
    def forward(self, s, a):                 # s: (B,T,ds)  a: (B,T,da)
        return self.f(torch.cat([s, a], -1)).squeeze(-1)   # (B,T)

def irl_reward_loss(rnet, expert, policy, logp_policy):
    """
    expert : (s_e, a_e)   专家演示批
    policy : (s_p, a_p)   当前(懒惰优化后)策略的采样批
    logp_policy: (M,T)    这些动作在采样策略下的 log pi(a_t|s_t)
    返回需要 *最小化* 的损失 = -L
    """
    s_e, a_e = expert
    s_p, a_p = policy

    r_e = rnet(s_e, a_e).sum(dim=1)                  # (N,) 专家轨迹总奖励
    r_p = rnet(s_p, a_p).sum(dim=1)                  # (M,) 策略轨迹总奖励

    # log w_j = sum_t r_psi - sum_t log pi ;只差一个与 j 无关的常数 -log Z
    log_w = (r_p - logp_policy.sum(dim=1)).detach()  # detach: 权重不回传梯度
    w = torch.softmax(log_w, dim=0)                  # 自归一化,等价于 w_j / sum_j w_j

    # L = mean(r_expert) - log Z ;负相用自归一化重要性采样估计
    loss = -(r_e.mean() - (w * r_p).sum())
    return loss

注意代码里两个细节:其一,log_w 用 softmax 归一化,这正好实现了自归一化并且数值稳定(等价于减去 $\max_j \log w_j$);其二,权重必须 detach,因为它只是重要性采样的修正系数,不是目标的一部分——如果让它回传,梯度就不再是我们推出来的那个表达式了。

常见误区 「IRL 学到的奖励就是人心里真正的奖励」——不对。奖励在若干变换下是不可辨识的:任意势函数整形 $r'(s,a,s')=r(s,a)+\gamma\Phi(s')-\Phi(s)$ 都会给出完全相同的最优策略;加常数也一样。IRL 最多恢复出「与演示行为一致的某个奖励」,而不是唯一真值。这也是后面 Bradley–Terry 模型只在差值意义下可辨识的同一个道理。

2. IRL 就是 GAN:对抗式的奖励学习

把上一节的两条更新并排放在一起看,会发现一件很有意思的事。

IRL 的两条更新构成一个博弈:奖励压低策略样本,策略去骗过奖励
左右两条流水线。右边:人类演示 $\pi^\star(\tau)$ 和策略样本一起送进奖励更新,效果是「让演示更可能、让样本更不可能」。左边:奖励反过来当成策略梯度的权重 $\nabla_\theta\mathcal L\approx\frac1M\sum_j\nabla_\theta\log\pi_\theta(\tau_j)r_\psi(\tau_j)$,效果是「让策略变得更难与演示区分」。这就是一个两人博弈。
  • 奖励侧:$\nabla_\psi\mathcal L\approx\frac1N\sum_i\nabla_\psi r_\psi(\tau_i)-\frac{1}{\sum_j w_j}\sum_j w_j\nabla_\psi r_\psi(\tau_j)$,即抬高演示、压低样本。
  • 策略侧:$\nabla_\theta\mathcal L\approx\frac1M\sum_j\nabla_\theta\log\pi_\theta(\tau_j)\,r_\psi(\tau_j)$,即让自己产生的轨迹在当前奖励下得分更高,也就是更像演示。

一个网络负责把两类样本分开,另一个网络负责让它分不开——这就是生成对抗网络(Generative Adversarial Network, GAN)。

GAN 的生成器/判别器目标与图像生成示例
GAN 的标准形式:生成器 $p_\theta(x|z)$ 从噪声 $z$ 产生样本,判别器 $D_\psi(x)=p_\psi(\text{real image}\mid x)$ 判断真伪。判别器目标 $\psi=\argmax_\psi\frac1N\sum_{x\sim p^\star}\log D_\psi(x)+\frac1M\sum_{x\sim p_\theta}\log(1-D_\psi(x))$,生成器目标 $\theta\leftarrow\argmax_\theta\E_{x\sim p_\theta}\log D_\psi(x)$。把「数据」换成「演示」,把「生成器」换成「策略」,结构一模一样。
推导 判别器的最优解。固定 $p_\theta$,对每个 $x$ 单独最大化 $$ p^\star(x)\log D(x)+p_\theta(x)\log(1-D(x)) . $$ 对 $D$ 求导置零:$\frac{p^\star(x)}{D}-\frac{p_\theta(x)}{1-D}=0$,解得 $$ D^\star(x)=\frac{p^\star(x)}{p^\star(x)+p_\theta(x)} . $$ 当生成器完美时 $p_\theta=p^\star$,于是 $D^\star\equiv\frac12$——判别器在收敛时一无所知。这正是幻灯片上写的那条缺点。

能不能直接用一个普通判别器?

GAIL:用普通二分类判别器,把 log D 当奖励
Ho & Ermon 的 GAIL。判别器 $D_\psi(\tau)$ 就是一个标准二分类网络,训练目标是普通的交叉熵;策略梯度用 $\log D_\psi(\tau_j)$ 当奖励:$\nabla_\theta\mathcal L\approx\frac1M\sum_j\nabla_\theta\log\pi_\theta(\tau_j)\log D_\psi(\tau_j)$。右下角是权衡:优点是优化更简单、活动部件更少;缺点是收敛时判别器一无所知,而且这个「奖励」一般无法拿去重新优化。

「无法重新优化奖励」是什么意思?假设你在平地上学会了模仿人走路,现在想把学到的奖励搬到有台阶的地形上重新跑 RL。GAIL 的判别器学到的是「这条轨迹看起来像不像专家数据」,它把状态分布本身编码进去了,换个地形立刻失效;而且在收敛点它输出恒等于 $\frac12$,梯度信息为零。相比之下,如果学到的是真正的 $r(s,a)$(比如「躯干保持直立、质心前移」),换地形照样能用。

AIRL:把 MaxEnt 模型塞进判别器

IRL 作为对抗优化:奖励函数视角与分类器视角其实是同一件事
左边是奖励函数视角:学一个分布 $p(\tau)\propto\exp(r(\tau))$ 使演示的似然最大,此时最优判别器写成 $D(\tau)=\frac{\frac1Z\exp(r(\tau))}{\frac1Z\exp(r(\tau))+\pi(\tau)}$。中间是分类器视角:$D(\tau)$ 就是「$\tau$ 是演示的概率」,把 $\log D$ 当奖励。红色箭头指出:两者其实是同一件事。右侧是应用:Hausman 等人的人形机器人多技能模仿,以及 Peng 等人的动作模仿(把动捕参考动作变成仿真角色的控制策略)。

把上面那个最优判别器公式 $D^\star=\frac{p^\star}{p^\star+p_\theta}$ 拿过来,令「真实分布」$p^\star(\tau)=\frac1Z\exp(r_\psi(\tau))$(最大熵模型),「生成分布」就是策略 $\pi(\tau)$,于是

$$ D_\psi(\tau)=\frac{\frac1Z\exp\big(r_\psi(\tau)\big)}{\frac1Z\exp\big(r_\psi(\tau)\big)+\pi(\tau)} . $$

这是一个结构化的判别器:它不是任意的神经网络,而是被强行写成上面这个形式,里面显式含着一个可解释的 $r_\psi$。用普通的二分类交叉熵去训练它,等价于我们第 1 节推的那个最大似然 IRL;但因为形式被约束住了,收敛时 $D\equiv\frac12$ 意味着 $\pi(\tau)=\frac1Z\exp(r_\psi(\tau))$,也就是策略恰好是当前奖励下的软最优策略——而 $r_\psi$ 本身依然是一个有意义、可迁移的奖励函数。这条路线就是 AIRL。

方法判别器/奖励形式优点缺点
Guided Cost Learning显式 $r_\psi$ + 重要性采样估计 $Z$直接对应最大似然,奖励可迁移需要精心处理重要性权重方差
GAIL任意二分类 $D_\psi(\tau)$,奖励 $=\log D_\psi$实现简单、稳定、活动部件少收敛时 $D=\frac12$,奖励不可复用
AIRL$D=\dfrac{\frac1Z e^{r_\psi}}{\frac1Z e^{r_\psi}+\pi}$学到可迁移的 $r_\psi$,等价于 MaxEnt IRL需要策略的显式概率,训练更敏感
注意 AIRL 的判别器里出现了 $\pi(\tau)$,这要求策略的动作概率可显式计算。对高斯策略、对 LLM 的 softmax 都没问题;但对隐式策略(比如扩散策略)就麻烦。这也解释了为什么 GAIL 在实践中更流行——它只需要采样,不需要密度。

这一节的意义不只在于模仿学习。「一个网络给分、另一个网络优化这个分数」正是接下来 RLHF 的骨架:奖励模型(reward model)扮演判别器,LLM 策略扮演生成器。区别只在于奖励模型是用人类偏好而不是真假分类训练出来的,而且训练通常不是完全对抗式地交替到底。

3. 把语言模型写成 RL 问题:MDP 到底是什么

换赛道。语言模型平时是用监督学习训练的:给定前 $t$ 个 token,预测第 $t+1$ 个,最小化交叉熵。这件事的目标非常明确——拟合数据分布。

Transformer 语言模型结构简化为一个方块,以及本讲要回答的三个问题
左边是完整结构:position-wise encoder(词嵌入 + 位置编码 $p_0,\dots,p_3$)→ masked self-attention → position-wise nonlinear network,重复 $N$ 次 → position-wise softmax,输出 $\hat x_1,\dots,\hat x_4$。蓝色虚线画出因果关系:$\hat x_1$ 只能看到 $x_0$,$\hat x_2$ 能看到 $x_{0:1}$,依此类推。中间「让我们简化一下」把整个网络压成一个绿色方块——之后所有图都用这个简化表示。右侧列出本讲要回答的三个问题:(PO)MDP 是什么?奖励是什么?用什么算法?

关键的观察是:如果我们想要的不是「复现数据分布」,而是「最大化某个奖励函数」,那就必须用 RL。为什么会想要后者?因为互联网文本的分布里包含大量我们不想要的东西:错误、有害内容、冗长、拒绝回答;而我们想要的东西(比如「解对这道数学题」)在数据里的频率并不高。监督学习没有办法说「这个回答比那个回答好」,它只会说「这个 token 出现的概率应该是多少」。

预训练与后训练

LLM 训练的解剖:预训练 vs 后训练
虚线左边是预训练:从 Common Crawl / Wikipedia 之类抓取海量多样数据,用 next-token prediction 训练。右边是后训练,分两段:先在高质量 SFT 数据集上做监督微调,再做 RL 微调(例如 RLHF)。最右侧那个循环画出 RLHF 的运行时结构:prompt「写一个关于青蛙的故事」→ PPO 更新的策略 → 生成「Once upon a time…」→ 奖励模型 RM 打分 $r_k$ → 分数回流去更新策略。
预训练给知识,后训练教怎么用知识
Levine 的核心论断:预训练好的 LLM 不是智能体、不是助手,它是「文本补全引擎」——但是补全任何文本都需要大量世界知识。左下 Andreas 等人的例子很能说明问题:同一段前缀,把最后一句改成「Pat 是物理学家,他预测……」,模型补出「保龄球和树叶会同时落下」;改成「Pat 从没见过这个演示,他预测……」,模型补出「保龄球先落地。这是错的。在真空室里没有空气……」。模型能模拟不同的说话人。右侧两个黄框是结论:预训练给的是知识,后训练教的是怎么用这些知识。右下那条研究结论更极端:有时候用错误的(比如答案被翻转的)数据微调,模型反而会把题答对——只是采用了微调数据展示的格式。
核心结论 后训练主要是在诱发(elicit)模型已有的能力,而不是灌输新知识。这解释了为什么 RLHF/RLVR 用几万条数据就能让模型行为发生质变,而预训练要几万亿 token。也解释了为什么 KL 正则化是合理的:我们本来就不希望策略离参考模型太远。

指令微调不够用

指令微调(FLAN)的流程与它的局限
最基础的后训练是指令微调:把「请回答下列问题:氮的沸点是多少?」→「-320.4F」这样的样例,以及带思维链的样例(「食堂原有 23 个苹果,用掉 20 个……所以 3+6=9」),混合成 1.8K 个任务一起微调,然后期望它泛化到没见过的任务。右侧三个黄框是 Levine 的追问:通常极其耗费人力;对需要专业技能的任务(比如写代码)尤其如此;还有什么别的地方可能出问题?

「什么别的地方可能出问题」的答案,其实就是本课第 2 讲讲模仿学习时的老问题,只是换了个场景:

  • 指令微调是行为克隆。它继承了行为克隆的一切毛病:分布漂移(模型自己生成的前缀会逐渐偏离训练分布,误差累积),以及无法超越示范者。你雇的标注员写不出比自己水平更高的代码,模型就学不到更高水平。
  • 它会教模型撒谎。如果微调数据里有一条「珠峰高 8848 米」而模型内部并不「知道」这个事实,你教给它的其实是「遇到这类问题就自信地报一个数字」——这是幻觉(hallucination)的一个直接来源。RL 不同:如果奖励惩罚错误答案,模型会学到「不确定时就说不确定」。
  • 它无法表达偏好强度。监督学习只能说「这是正确输出」,说不了「A 比 B 好一点点」。而人类对「什么是好回答」的判断天然是比较式的。
OpenAI 的 RLHF 三步流程图
OpenAI 的经典三步图。Step 1:采集演示数据,用监督学习微调(SFT)。Step 2:对同一个 prompt 采样多个模型输出(A/B/C/D),让标注员排序(D > C > A = B),用这些比较数据训练奖励模型 RM。Step 3:用 RL(PPO)针对 RM 优化策略——新 prompt 进来,策略生成输出,RM 给出标量奖励 $r_k$,PPO 用它更新策略。注意第二步收集的是偏好而不是演示:让人「选一个」远比让人「写一个」便宜。

MDP 建模的第一种选择:一步 bandit

把整段补全当成一个动作的一步 RL 建模
状态 $\mathbf s$ = context/prompt/prefix(图中 $x_0\dots x_4$,即「what is capital of France?」),动作 $\mathbf a$ = completion($x_5,x_6$,即「Paris <eos>」)。策略 $\pi_\theta(\mathbf a|\mathbf s)=p(x_5|x_{1:4})\,p(x_6|x_{1:4},x_5)$——注意每一项条件里都含着 prompt。目标就是 $\E_{\pi_\theta(\mathbf a|\mathbf s)}[r(\mathbf s,\mathbf a)]$,一个基础的一步 RL 问题(也就是上下文 bandit)。

这是最省事的建模:整段补全就是一个动作。$\pi_\theta(\mathbf a|\mathbf s)$ 虽然是自回归分解出来的,但在 RL 眼里它就是一个(巨大离散空间上的)动作分布。目标

$$ J(\theta)=\E_{\mathbf s\sim\mathcal D}\,\E_{\mathbf a\sim\pi_\theta(\mathbf a|\mathbf s)}\big[r(\mathbf s,\mathbf a)\big]. $$

没有转移、没有折扣、没有 Bellman 方程。你可能会觉得「这也太简单了,还叫 RL 吗」——但正因为简单,它的分析是干净的:不存在长期信用分配问题,唯一的困难是动作空间大到离谱($|V|^{H}$,词表 15 万、长度 1000 的话是 $150000^{1000}$)以及只有一个末端标量反馈。

MDP 建模的第二种选择:token 级 MDP

把每个 token 当一个动作的等价建模
同一张网络图,换一种读法:$\pi_\theta(\mathbf a_1|\mathbf s_1)=p(x_5|x_{1:4})$,$\pi_\theta(\mathbf a_2|\mathbf s_2)=p(x_6|x_{1:4},x_5)$。也就是说 $\mathbf s_1$ = prompt,$\mathbf a_1$ = 第一个生成的 token,$\mathbf s_2$ = prompt 拼上 $\mathbf a_1$,依此类推。目标写成 $\E_{\pi_\theta(\tau)}[r(\tau)]$。黄框指出关键:当我们使用中间奖励和价值函数基线时,这个视角才说得通。

在 token 级 MDP 里:

MDP 元素在 LLM 中对应什么
状态 $s_t$当前完整前缀 $(x_0,\dots,x_{t-1})$,即 prompt 加上已生成的 token
动作 $a_t$下一个 token $x_t$,动作空间 = 词表(约 $10^5$ 个离散动作)
转移 $p(s_{t+1}|s_t,a_t)$确定性:把 $a_t$ 拼到 $s_t$ 后面,概率为 1
奖励 $r(s_t,a_t)$通常全为 0,只在生成 <eos> 的那一步给出 RM 分数或验证器 0/1
终止采样到 <eos>,或达到最大长度截断
折扣 $\gamma$实践中几乎总是取 $\gamma=1$(回合长度有限,且早晚生成没有优劣之分)
初始状态分布prompt 数据集 $\mathcal D$

两种建模的目标函数在数学上完全一样:因为转移是确定性的、奖励只在末端给出,所以 $\E_{\pi_\theta(\tau)}[r(\tau)]=\E_{\pi_\theta(\mathbf a|\mathbf s)}[r(\mathbf s,\mathbf a)]$。而且它们的 REINFORCE 梯度也完全一样,因为

$$ \nabla_\theta\log\pi_\theta(\mathbf a|\mathbf s)=\sum_{t}\nabla_\theta\log\pi_\theta(a_t|s_t). $$

那为什么还要区分?因为一旦你想加基线或者中间奖励,两者就不同了。bandit 视角只允许一个与 $\mathbf s$ 有关的标量基线;token 视角允许每个位置有自己的 $\hat V(s_t)$,从而给每个 token 分配不同的优势值。这就是「信用分配」——在 5000 个 token 的思维链里,究竟是哪几步导致了最终答对?

注意 确定性转移这件事有一个重要后果:token 级 MDP 里的 $V^\pi(s_t)$ 完全由策略的随机性决定,而不是环境的随机性。这和 Atari 完全不同。也因此,很多人认为在单轮生成里训 critic 是「杀鸡用牛刀」——这正是 GRPO 敢于扔掉 critic 的底气之一。
但注意:多轮场景下这个论断失效。当模型调用工具、检索、或者与真实用户交互时,环境返回的 token 不是策略生成的,转移变成真正随机的,而且是部分可观测的。这时候我们就回到了标准 RL 的困难区间(见第 10 节)。

4. LLM 上的策略梯度:从 REINFORCE 到 PPO 循环

两种策略梯度估计器:REINFORCE 与重要性加权
最上面一行是关键的分解:$\nabla_\theta\log\pi_\theta(\mathbf a|\mathbf s)=\nabla_\theta\log p(x_5|x_{1:4})+\nabla_\theta\log p(x_6|x_{1:4},x_5)$——序列的对数概率梯度就是各 token 对数概率梯度之和。中间是 log-derivative trick 的结果。下面两个估计器:REINFORCE 式的用 $\pi_\theta$ 自己的样本;重要性加权式(例如 PPO)的用另一个分布 $\bar\pi(\mathbf a|\mathbf s)$ 的样本,乘上比值 $\frac{\pi_\theta(\mathbf a_i|\mathbf s_i)}{\bar\pi(\mathbf a_i|\mathbf s_i)}$。黄框问:为什么我们可能更偏好后者?

先把 log-derivative trick 在这个场景重写一遍(这一步值得写全,因为它解释了「为什么 RL 微调在代码上看起来就像加权的交叉熵」):

$$ \nabla_\theta \E_{\pi_\theta(\mathbf a|\mathbf s)}\big[r(\mathbf s,\mathbf a)\big] =\nabla_\theta\sum_{\mathbf a}\pi_\theta(\mathbf a|\mathbf s)r(\mathbf s,\mathbf a) =\sum_{\mathbf a}\pi_\theta(\mathbf a|\mathbf s)\nabla_\theta\log\pi_\theta(\mathbf a|\mathbf s)\,r(\mathbf s,\mathbf a), $$

用到 $\nabla_\theta\pi_\theta=\pi_\theta\nabla_\theta\log\pi_\theta$。写成期望并用样本近似:

$$ \approx\frac1N\sum_{i}\nabla_\theta\log\pi_\theta(\mathbf a_i|\mathbf s_i)\,r(\mathbf s_i,\mathbf a_i) =\frac1N\sum_i\Big(\sum_t\nabla_\theta\log\pi_\theta(a_{i,t}|s_{i,t})\Big)r(\mathbf s_i,\mathbf a_i). $$

括号里那个东西,就是标准语言模型训练里的交叉熵梯度(只不过标签换成了模型自己采出来的 token)。所以 REINFORCE 微调 = 用奖励加权的自我监督微调:奖励为正就把这条序列的概率往上推,为负就往下压。

为什么必须用重要性加权

重要性加权版本:

$$ \nabla_\theta \E_{\pi_\theta}\big[r\big]\approx\frac1N\sum_i\frac{\pi_\theta(\mathbf a_i|\mathbf s_i)}{\bar\pi(\mathbf a_i|\mathbf s_i)}\nabla_\theta\log\pi_\theta(\mathbf a_i|\mathbf s_i)\,r(\mathbf s_i,\mathbf a_i),\qquad \mathbf a_i\sim\bar\pi . $$

这是无偏的,因为 $\E_{\bar\pi}[\frac{\pi_\theta}{\bar\pi}f]=\E_{\pi_\theta}[f]$。它带来的自由是:样本可以来自一个旧策略。为什么这件事在 LLM 上如此关键?

  • 采样极贵。生成 1000 个 token 要做 1000 次前向(自回归,无法并行),而一次梯度步只是一次前向 + 一次反向。工程上采样通常还跑在独立的推理引擎(vLLM/SGLang)上,权重同步本身就有开销。如果每做一次梯度更新就要重新采一批数据,GPU 利用率会低得不能看。
  • 批量要足够大才能降方差。末端稀疏奖励的梯度方差极大,一批往往要几百上千条序列。这么大的一批只喂一次梯度就扔掉,太浪费。
  • 异步/流水线训练。允许 $\bar\pi\ne\pi_\theta$ 之后,采样器和训练器可以并行跑,采样器用的是稍旧的权重。这在现代 RLHF 框架里是标配。
LLM 策略梯度的通用循环,标注出三个设计选择
本讲的骨架算法。内圈:1. 从 $\pi_\theta$ 采一个批次 $\mathcal B=\{\mathbf a_i\}$;2. 对每条 $\mathbf a_i$ 求奖励 $r(\mathbf s,\mathbf a_i)$;3. 把当前策略冻结成 $\bar\pi\leftarrow\pi_\theta$;4. 从 $\mathcal B$ 里抽小批 $\mathcal M$;5. $\theta\leftarrow\theta+\alpha\hat\nabla(\theta,\bar\pi,\mathcal M)$;步骤 4–5 重复 $K$ 次。三个带编号的注记就是本讲余下的全部内容:(1)聪明地选基线、(2)选正则化器、(3)聪明地设定或学习奖励。

注意步骤 3 的位置:$\bar\pi$ 是本轮采样时的策略。在内层 $K$ 次小批更新中 $\theta$ 一直在变,而 $\bar\pi$ 冻结不动,所以比值 $\frac{\pi_\theta}{\bar\pi}$ 从 1 开始逐渐偏离。$K$ 越大,样本复用率越高,但分布偏移也越严重。这正是 PPO 的 clip 要解决的问题。

常见误区 直接用序列级的重要性比 $\frac{\pi_\theta(\mathbf a|\mathbf s)}{\bar\pi(\mathbf a|\mathbf s)}=\prod_{t=1}^{H}\frac{\pi_\theta(a_t|s_t)}{\bar\pi(a_t|s_t)}$ 是灾难性的:$H$ 可以是几千,每个 token 的比值哪怕只偏离 $1\pm0.001$,连乘之后也会指数级爆炸或归零($1.001^{2000}\approx 7.4$,$0.999^{2000}\approx 0.135$,而实际偏离远大于 $10^{-3}$)。这就是本课第 5 讲讲过的重要性采样方差爆炸问题在 LLM 上的具体形态。
实现上的标准做法是把比值下放到 token 级:对每个 $t$ 单独算 $\rho_t=\frac{\pi_\theta(a_t|s_t)}{\bar\pi(a_t|s_t)}$ 并 clip。这在数学上不再是精确的序列级重要性采样,而是「近似 on-policy + 信任域」的启发式——但它能跑,序列级的不能。
import torch, torch.nn.functional as F

def sequence_logprobs(model, input_ids, attention_mask, prompt_len):
    """
    返回每个「生成 token」的 log pi(a_t | s_t)。
    input_ids: (B, L) = [prompt tokens | completion tokens]
    prompt_len: (B,)  每条样本 prompt 的长度
    """
    logits = model(input_ids=input_ids, attention_mask=attention_mask).logits  # (B,L,V)
    # 位置 t 的 logits 预测位置 t+1 的 token,因此错位对齐
    logits = logits[:, :-1, :]                       # (B, L-1, V)
    targets = input_ids[:, 1:]                       # (B, L-1)
    logp = torch.log_softmax(logits.float(), dim=-1)
    token_logp = logp.gather(-1, targets.unsqueeze(-1)).squeeze(-1)   # (B, L-1)

    # 只保留 completion 部分:prompt 里的 token 不是策略做出的动作
    idx = torch.arange(token_logp.size(1), device=token_logp.device)
    gen_mask = (idx.unsqueeze(0) >= (prompt_len - 1).unsqueeze(1)).float()
    gen_mask = gen_mask * attention_mask[:, 1:].float()
    return token_logp, gen_mask                       # (B,L-1), (B,L-1)


def reinforce_loss(token_logp, gen_mask, reward):
    """最朴素的 REINFORCE:奖励加权的负对数似然。reward: (B,)"""
    seq_logp = (token_logp * gen_mask).sum(dim=1)     # log pi(a|s)
    return -(seq_logp * reward.detach()).mean()

这段代码里 gen_mask 是最容易写错、也最要紧的地方:prompt 里的 token 不是策略选的动作,它们的 log-prob 不能进入策略梯度,否则你等于在用奖励去调整模型对用户输入的建模概率——毫无意义,而且会显著损害模型。多轮/工具场景下同理,工具返回的 token 也必须被 mask 掉。

5. 设计选择(1):基线——价值函数 + GAE 还是组内归一化

先说为什么非要基线不可。假设奖励是验证器给的 $r\in\{0,1\}$,某个 prompt 上模型的正确率是 80%。不加基线的 REINFORCE 梯度是

$$ \frac1N\sum_i \nabla_\theta\log\pi_\theta(\mathbf a_i|\mathbf s)\cdot r_i . $$

$r_i=0$ 的样本贡献零梯度——也就是说,模型答错的那 20% 完全没有被惩罚,算法只是在把答对的 80% 往上推。这不仅浪费了一半信息,还会让所有采样过的序列概率都上升(其余序列被 softmax 挤下去),训练信号极其低效。加上基线 $b=0.8$ 之后,答对的优势是 $+0.2$、答错的是 $-0.8$,一推一压,才是我们想要的对比信号。

回忆本课第 5 讲的结论:任何只依赖状态、不依赖动作的基线都不引入偏差,因为

$$ \E_{a\sim\pi_\theta(\cdot|s)}\big[\nabla_\theta\log\pi_\theta(a|s)\,b(s)\big]=b(s)\sum_a\nabla_\theta\pi_\theta(a|s)=b(s)\,\nabla_\theta\!\!\underbrace{\sum_a\pi_\theta(a|s)}_{=1}=0 . $$

做法 A:价值函数基线 + GAE

价值函数基线与 GAE,以及在 Transformer 上加价值头
左上是 GAE 的定义:TD 残差 $\delta_{t'}=r(s_{t'},a_{t'})+\gamma\hat V^\pi_\phi(s_{t'+1})-\hat V^\pi_\phi(s_{t'})$,优势 $\hat A^\pi_{\text{GAE}}(s_t,a_t)=\sum_{t'=t}^{\infty}(\gamma\lambda)^{t'-t}\delta_{t'}$。右上是价值函数的回归目标:$\mathcal L(\phi)=\frac12\sum_i\|\hat V_\phi(s_i)-y_i\|^2$,其中 $y_i=\hat A^\pi_{\text{GAE}}(s_i,a_i)+\hat V_{\text{old}}(s_i)$(用旧价值加优势构造目标,等价于 $\lambda$-return)。左下是架构:同一个 transformer 在每个位置同时输出 token 分布 $\hat x_t$ 和价值 $\hat v_t$。右侧两个黄框是实现要点:要么加一个新的输出头,要么复制整个网络;不要在 prompt 上训练价值函数,只训练后缀部分。

GAE(Generalized Advantage Estimation)在这里的作用和标准 RL 一样:用 $\lambda$ 在「低方差高偏差的单步 TD($\lambda=0$)」和「高方差无偏的蒙特卡洛回报($\lambda=1$)」之间插值。在 LLM 里因为奖励只在末端,$\gamma=1,\lambda=1$ 时 $\hat A_t$ 就退化成 $r_{\text{end}}-\hat V(s_t)$;取 $\lambda\lt 1$ 会让远处的奖励信号衰减,实践中大多数实现干脆取 $\gamma=\lambda=1$。

为什么「不要在 prompt 上训价值函数」?因为 prompt 位置上的 $s_t$ 并不是策略做决策的状态——那里没有动作,也就没有对应的优势要算。在那些位置上做回归只是在消耗网络容量、并把梯度污染进共享的 transformer 主干。

代价也要算清楚。用 GAE 就意味着你要维护一个和策略同等规模的 critic(哪怕只是加个头,反向传播也要走整个主干)。加上策略、参考模型、奖励模型,显存里同时有 四个大模型。

做法 B:GRPO——不用价值函数的基线

GRPO:对同一 prompt 采一组回答,用组内均值当基线
算法只有三行:对每个 prompt $\mathbf s_i$,从 $\pi_\theta(\mathbf a|\mathbf s_i)$ 采出 $\mathbf a_{i,1},\dots,\mathbf a_{i,K}$;令 $\hat A^\pi_{i,j}=r(\mathbf s_i,\mathbf a_j)-\frac1K\sum_{k=1}^{K}r(\mathbf s_i,\mathbf a_k)$;然后照常做重要性加权的策略梯度 $\frac1N\sum_{ij}\frac{\pi_\theta(\mathbf a_j|\mathbf s_i)}{\bar\pi(\mathbf a_j|\mathbf s_i)}\nabla_\theta\log\pi_\theta(\mathbf a_j|\mathbf s_i)\hat A^\pi_{i,j}$。右边那束从同一点分叉出去的曲线正是这个思想的图示:从同一个状态出发采一束轨迹,谁比这束的平均好,谁就被强化。黄框:这就叫 GRPO。

思路极其朴素:既然基线只要「依赖状态、不依赖动作」就无偏,那我干脆再多采几个样本,用它们的平均奖励当基线。这在普通 RL 里做不到(你无法把环境重置到同一个状态采多次),但在 LLM 里可以——prompt 就是状态,想采多少次采多少次。

推导 组内均值基线有偏吗?把优势拆开: $$ \hat A_j=r_j-\frac1K\sum_{k=1}^{K}r_k=\Big(1-\frac1K\Big)r_j-\frac1K\sum_{k\ne j}r_k . $$ 对其余 $K-1$ 个样本取期望(它们与 $\mathbf a_j$ 独立同分布,均值为 $\bar r=\E_{\pi}[r]$): $$ \E\big[\hat A_j\mid \mathbf a_j\big]=\Big(1-\frac1K\Big)r_j-\frac{K-1}{K}\bar r=\frac{K-1}{K}\big(r_j-\bar r\big). $$ 所以它等于真实优势乘上一个常数 $\frac{K-1}{K}$——方向完全正确,只是整体缩放了一点,被学习率吸收掉即可。如果想要严格无偏,用留一法(leave-one-out)基线 $b_j=\frac{1}{K-1}\sum_{k\ne j}r_k$,此时 $\E[\hat A_j|\mathbf a_j]=r_j-\bar r$ 精确成立。这就是 RLOO。

标准差归一化:它的作用与它的偏差

幻灯片上写的是纯均值基线,而 DeepSeekMath 原始论文里的 GRPO 还多除了一个组内标准差:

$$ \hat A_{i,j}=\frac{r(\mathbf s_i,\mathbf a_j)-\operatorname{mean}\big(\{r(\mathbf s_i,\mathbf a_k)\}_{k=1}^K\big)}{\operatorname{std}\big(\{r(\mathbf s_i,\mathbf a_k)\}_{k=1}^K\big)} . $$

好处很直观:不同 prompt 的奖励尺度天然不同(还记得第 8 节会讲的——BT 模型下奖励只在差值意义上可辨识,跨 prompt 的绝对值毫无可比性),除以标准差相当于给每个 prompt 做自适应的步长归一化,让梯度尺度统一。

注意:两个已知偏差
  • 难度偏差。对二元奖励,若组内正确率为 $p$,则 $\operatorname{std}=\sqrt{p(1-p)}$。$p=0.5$ 时 std 最大(0.5),$p=0.9$ 时 std 只有 0.3,$p=0.99$ 时只有 0.1。除以它意味着极简单和极困难的 prompt 被放大了 5–10 倍权重,而这些恰恰是信息量最少的样本。更糟的是 $p\in\{0,1\}$ 时 std $=0$,整组优势全为 0,这一整批采样白算——大规模训练里这类「全对/全错组」的比例可以很高。
  • 长度偏差。GRPO 的目标里对每条回答的 token 做 $\frac{1}{|\mathbf a_i|}$ 平均。当 $\hat A\lt 0$ 时,回答越长,每个 token 分到的惩罚越小;于是「写得又长又错」比「写得短而错」损失更小,模型被隐式鼓励在做不对的题上啰嗦下去。这是 Dr. GRPO 那条工作指出的核心问题,修法是把 $\frac{1}{|\mathbf a_i|}$ 换成一个与样本无关的常数(比如固定的最大长度)。
常见的缓解手段:去掉 std 归一化(只减均值)、过滤掉全对/全错的组、按难度做课程采样。
PPO + 价值函数 + GAEGRPO / RLOO(组内基线)
显存中的模型数4(策略、参考、奖励模型、critic)3(策略、参考、奖励模型/验证器)
每个 prompt 的采样数1 条即可必须 $K$ 条(典型 $K=4\sim64$)
信用分配粒度逐 token 的 $\hat A_t$,可利用中间奖励整条序列共享一个 $\hat A$
基线偏差来源critic 拟合误差(尤其训练早期极不准)组内样本有限带来的估计噪声;std 归一化的难度/长度偏差
额外计算critic 的前反向$K$ 倍的采样开销
适用场景密集/过程奖励、长 horizon、多轮末端稀疏奖励、单轮、可验证任务

Levine 的判断是:这两者不是「谁更先进」的关系,而是把方差换成计算的两种不同方式。critic 用参数化拟合去省采样;GRPO 用多采样去省参数。在末端 0/1 奖励、单轮生成的场景里,critic 要拟合的其实就是「这个 prompt 的正确率」,一个用 $K$ 个样本直接估的均值往往比一个训练不稳的神经网络更准,所以 GRPO 赢;但在多轮、有中间奖励、需要区分「哪一步走错了」的场景里,没有 critic 就没有细粒度信用分配。

6. 设计选择(2):参考模型 KL 正则化

参考模型正则化:把 KL 惩罚吸收进奖励
做法很简单:我们通常不希望 $\pi_\theta(\mathbf a|\mathbf s)$ 从某个参考模型 $\pi_{\text{ref}}(\mathbf a|\mathbf s)$ 漂移太远(参考模型一般就是 SFT 之后的初始策略),于是在目标里加一项 $-\E_{\pi_\theta}[D_{\mathrm{KL}}(\pi_\theta(a_t|s_t),\pi_{\text{ref}}(a_t|s_t))]$,等价地把它吸收进逐步奖励:$\bar r(s_t,a_t)=r(s_t,a_t)-\beta D_{\mathrm{KL}}(\pi_\theta(a_t|s_t),\pi_{\text{ref}}(a_t|s_t))$。两个黄框给出理由:避免产生「胡言乱语」(必须还是合法的英语);避免「利用」不完美的奖励模型。

第二条理由值得展开,它是整个 RLHF 体系里最脆弱的一环。

直觉:为什么奖励模型一定会被攻破 奖励模型 $r_\psi$ 是在「$\pi_{\text{ref}}$ 附近采出来的回答 + 人类偏好标注」上训练的。它在那个分布上准确,在别的地方就是外推——一个 70 亿参数的网络在训练分布之外输出什么,没人知道。
而 RL 是什么?RL 是一个专门用来寻找函数最大值的优化器。你给它一个有漏洞的函数,它会以惊人的效率找到漏洞。经典现象:策略发现连着输出一串特定的标点或者某个罕见 token 能让 RM 打出高分,于是输出退化成一堆乱码;或者发现 RM 偏爱长回答,于是把每个回答都灌水到 2000 词。这就是奖励黑客(reward hacking),本质是 Goodhart 定律:一旦某个度量成为目标,它就不再是好的度量。
KL 惩罚的作用就是:把策略锁在奖励模型还可信的那片区域里。$\beta$ 是「相信奖励模型多少」的旋钮。

把 KL 项吸收进奖励之后,优化的实际目标是

$$ J(\theta)=\E_{\mathbf s\sim\mathcal D}\Big[\E_{\mathbf a\sim\pi_\theta}\big[r(\mathbf s,\mathbf a)\big]-\beta\,\KL\big(\pi_\theta(\cdot|\mathbf s)\,\|\,\pi_{\text{ref}}(\cdot|\mathbf s)\big)\Big]. $$

这个目标有一个闭式最优解,我们在第 8 节推导 DPO 时会用到它;它也正是上一讲「控制即推断」里那个软最优策略在 $\pi_{\text{ref}}$ 不均匀时的推广。

KL 的三种估计方式

实现上有若干变体,差别不小:

估计器表达式(记 $u=\log\pi_{\text{ref}}(a_t|s_t)-\log\pi_\theta(a_t|s_t)$)性质
解析全 KL$\sum_{v\in V}\pi_\theta(v|s_t)\log\frac{\pi_\theta(v|s_t)}{\pi_{\text{ref}}(v|s_t)}$无方差,但要对整个词表求和,显存开销大
k1(朴素)$-u$无偏,但方差大且可正可负
k3(常用)$\exp(u)-u-1$无偏、恒非负、方差显著更低,GRPO 论文采用

k3 的无偏性来自 $\E_{\pi_\theta}[\exp(u)]=\E_{\pi_\theta}\big[\frac{\pi_{\text{ref}}}{\pi_\theta}\big]=1$,所以 $\E[\exp(u)-u-1]=1+\KL-1=\KL$。而 $\exp(u)-u-1\ge0$ 对任意实数 $u$ 成立($e^x\ge1+x$),因此它逐样本就非负,不会像 k1 那样出现「负 KL」的诡异日志。

注意:KL 加在奖励里还是加在损失里? 两种做法都存在,但不等价。加在奖励里(把 $-\beta\KL$ 塞进 $\bar r$,再一起过 GAE)意味着 KL 惩罚会通过优势函数传播到之前的 token 上——「你早先选的那个词导致后面必须偏离参考模型」也会被惩罚。加在损失里(在 PPO/GRPO 目标外面直接减 $\beta\KL$)则是逐 token 独立的。GRPO 用后者,PPO 式 RLHF 传统上用前者。
另外,RLVR 场景下很多工作直接取 $\beta=0$:验证器给的奖励不是一个可被攻破的神经网络,而且 KL 会明显限制模型探索长思维链的能力(模型必须大幅偏离 SFT 分布才能学会「等一下,让我再检查一遍」这类行为)。

7. 拼起来:LLM 版 PPO 与 GRPO 的完整算法

LLM 上的 PPO 完整伪代码,含 GAE、KL 惩罚与 clip 目标
把前面所有零件装进一个算法。左上是主循环,左下是两个关键公式:带 KL 惩罚的奖励 $\bar r$,以及 PPO 的 clip 目标 $\mathcal L_{\text{CLIP}}$。右侧提醒我们网络长什么样:一个 transformer 每个位置同时吐出 token 分布 $\hat x_t$ 和价值 $\hat v_t$,而策略按 token 分解成 $\pi_\theta(\mathbf a_1|\mathbf s_1)\pi_\theta(\mathbf a_2|\mathbf s_2)$。注意主循环里 $K\times$ 的内层只包住第 6、7 两步——采样和 GAE 只做一次,梯度步做 $K$ 次。

逐条抄下来:

  1. 对每个 prompt,从 $\pi_\theta$ 采样若干轨迹 $\{\tau^{(i)}\}$;
  2. 计算 $\delta_{t,i}=\bar r(s_{t,i},a_{t,i})+\gamma\hat V^\pi_\phi(s_{t+1,i})-\hat V^\pi_\phi(s_{t,i})$;
  3. 计算 $\hat A^\pi_{\text{GAE}}(s_{t,i},a_{t,i})=\sum_{t'=t}^{\infty}(\gamma\lambda)^{t'-t}\delta_{t',i}$;
  4. 把 $\hat V^\pi_\phi$ 回归到目标 $\{\hat A^\pi_{\text{GAE}}(s_i,a_i)+\hat V^\pi_\phi(s_i)\}$;
  5. $\theta'\leftarrow\theta$;
  6. (重复 $K$ 次)$\nabla_{\theta'}J(\theta')\approx\nabla_{\theta'}\mathcal L_{\text{CLIP}}(\theta')$;
  7. (重复 $K$ 次)$\theta'\leftarrow\theta'+\alpha\nabla_{\theta'}J(\theta')$;
  8. $\theta\leftarrow\theta'$。

其中

$$ \bar r(s_t,a_t)=r(s_t,a_t)-\beta D_{\mathrm{KL}}\big(\pi_\theta(a_t|s_t),\pi_{\text{ref}}(a_t|s_t)\big), $$ $$ \mathcal L_{\text{CLIP}}(\theta')=\sum_{i=1}^{N}\sum_{t=1}^{H}\min\left\{\operatorname{clip}\!\left(\frac{\pi_{\theta'}(a^{(i)}_t|s^{(i)}_t)}{\pi_{\theta}(a^{(i)}_t|s^{(i)}_t)},1-\epsilon,1+\epsilon\right)\hat A^{(i)}_t,\;\;\frac{\pi_{\theta'}(a^{(i)}_t|s^{(i)}_t)}{\pi_{\theta}(a^{(i)}_t|s^{(i)}_t)}\hat A^{(i)}_t\right\}. $$
推导:clip 到底在干什么 记 $\rho=\pi_{\theta'}/\pi_\theta$。目标取的是「clip 过的」和「没 clip 的」两者的较小值,所以它是真实目标的一个悲观下界。分两种情况看:
  • $\hat A\gt 0$(这个动作比平均好,想提高它的概率):$\min$ 的效果是当 $\rho\gt1+\epsilon$ 时目标被截断成常数 $(1+\epsilon)\hat A$,梯度归零。不允许把好动作的概率无限往上推。
  • $\hat A\lt 0$(想压低它):当 $\rho\lt1-\epsilon$ 时目标被截断成 $(1-\epsilon)\hat A$,梯度归零。不允许把坏动作压得太狠。
两边合起来,就把每次内层更新限制在 $\bar\pi$ 的一个信任域里,从而让「样本复用 $K$ 次」不至于把策略推到 $\bar\pi$ 完全无法代表的地方。注意在 $\rho$ 越界的那一侧梯度恰好为零——这是 clip 与「加 KL 惩罚」的本质区别:clip 是硬性截断,不产生把策略拉回去的力。

GRPO 的完整目标函数

把第 5 节的组内优势和第 6 节的 KL 装进同一个 clip 框架,就得到 GRPO 的标准形式。设一个 prompt $q$ 采出一组 $G$ 个回答 $\{o_i\}$:

$$ \mathcal J_{\text{GRPO}}(\theta)=\E\left[\frac{1}{G}\sum_{i=1}^{G}\frac{1}{|o_i|}\sum_{t=1}^{|o_i|}\min\Big(\rho_{i,t}\hat A_i,\;\operatorname{clip}(\rho_{i,t},1-\epsilon,1+\epsilon)\hat A_i\Big)-\beta\,\hat D_{\mathrm{KL}}\big[\pi_\theta\,\|\,\pi_{\text{ref}}\big]\right], $$ $$ \rho_{i,t}=\frac{\pi_\theta(o_{i,t}\mid q,o_{i,\lt t})}{\pi_{\theta_{\text{old}}}(o_{i,t}\mid q,o_{i,\lt t})},\qquad \hat A_i=\frac{r_i-\operatorname{mean}(\{r_1,\dots,r_G\})}{\operatorname{std}(\{r_1,\dots,r_G\})}. $$

和 PPO 比,差别只有三处:优势不来自 critic 而来自组内归一化;同一条回答的所有 token 共享同一个 $\hat A_i$;KL 作为独立损失项而非塞进奖励。

import torch

def grpo_loss(policy_logp, old_logp, ref_logp, gen_mask, rewards,
              group_size, beta=0.04, eps=0.2, use_std=True):
    """
    policy_logp / old_logp / ref_logp : (B, L) 逐 token 的 log 概率,B = n_prompt * group_size
    gen_mask : (B, L)  1 表示该位置是策略生成的 token
    rewards  : (B,)    每条回答的标量奖励(验证器或奖励模型给的)
    """
    B = rewards.size(0)
    r = rewards.view(-1, group_size)                       # (n_prompt, G)
    adv = r - r.mean(dim=1, keepdim=True)                  # 组内减均值 —— 幻灯片上的版本
    if use_std:
        adv = adv / (r.std(dim=1, keepdim=True) + 1e-6)    # 原论文的 std 归一化
    adv = adv.view(B, 1)                                   # 整条回答共享一个优势

    ratio = torch.exp(policy_logp - old_logp)              # token 级重要性比
    unclipped = ratio * adv
    clipped   = torch.clamp(ratio, 1 - eps, 1 + eps) * adv
    pg = torch.min(unclipped, clipped)                     # 悲观下界

    # k3 KL 估计:exp(u) - u - 1,其中 u = log pi_ref - log pi_theta,恒非负
    u  = ref_logp - policy_logp
    kl = torch.exp(u) - u - 1.0

    per_token = -(pg - beta * kl)                          # 要最小化的损失
    # 每条回答内部按 token 数平均(注意:这一步正是长度偏差的来源)
    per_seq = (per_token * gen_mask).sum(dim=1) / gen_mask.sum(dim=1).clamp(min=1)
    return per_seq.mean()
def gae_advantages(rewards, values, gen_mask, gamma=1.0, lam=1.0):
    """
    PPO 路线:逐 token 的 GAE。
    rewards : (B, L) 逐 token 奖励(通常只有最后一个生成位置非零,
                     再叠加逐 token 的 -beta * KL 惩罚)
    values  : (B, L) critic 输出 V(s_t)
    """
    B, L = rewards.shape
    adv = torch.zeros_like(rewards)
    last = torch.zeros(B, device=rewards.device)
    for t in reversed(range(L)):
        v_next = values[:, t + 1] if t + 1 < L else torch.zeros(B, device=rewards.device)
        delta = rewards[:, t] + gamma * v_next - values[:, t]
        last = delta + gamma * lam * last
        adv[:, t] = last
    returns = adv + values                    # critic 的回归目标 = A_GAE + V_old
    adv = adv * gen_mask
    # 全批次白化,进一步降方差(PPO 实现中的标准技巧)
    m = adv.sum() / gen_mask.sum()
    v = ((adv - m) ** 2 * gen_mask).sum() / gen_mask.sum()
    adv = (adv - m) / (v.sqrt() + 1e-8) * gen_mask
    return adv.detach(), returns.detach()

关于 gae_advantages 里的循环方向:必须从后往前,因为 $\hat A_t=\delta_t+\gamma\lambda\hat A_{t+1}$ 是一个反向递推。这个恒等式的验证很直接——把定义 $\hat A_t=\sum_{t'\ge t}(\gamma\lambda)^{t'-t}\delta_{t'}$ 拆出第一项即可。

8. 设计选择(3a):从人类偏好学奖励——Bradley–Terry 与 RLHF

回到那个循环里第 2 步的问号:$r(\mathbf s,\mathbf a_i)$ 从哪儿来?第 1 节的 IRL 路线要求人类演示;但对「什么是好的助手回答」这件事,演示太贵了(要人写出完美答案),而且人写的答案未必比模型采样出来的好。更便宜的信号是比较。

验光师算法:采样两条轨迹、问人偏好、训奖励、训策略
Levine 把它叫做「验光师算法(optometrist algorithm)」——就像配眼镜时医生反复问你「1 号清楚还是 2 号清楚?」。四步循环:1. 采样 2 条(或更多)轨迹 $\tau_i\sim\pi_\theta(\tau)$;2. 让人在 $\{\tau_i\}_{i=1}^N$ 中指出偏好;3. 用偏好训练奖励 $r_\psi$;4. 用 $r_\psi$ 训练策略 $\pi_\theta$。右边那张三维曲面图画的是奖励地形:两条橙色叉标出被比较的一对轨迹,黑色曲线是不同的候选轨迹。记号 $\tau_i\succ\tau_j$ 读作「我更喜欢 $i$」。

人类给的是序关系,不是数值。要把序关系变成可微的损失,需要一个概率模型——这就是 Bradley–Terry。

Bradley-Terry 模型:把偏好写成奖励差的 sigmoid
模型假设 $p(\tau_i\succ\tau_j)=\frac{\exp(\sum_t r_\psi(s^{(i)}_t,a^{(i)}_t))}{\exp(\sum_t r_\psi(s^{(i)}_t,a^{(i)}_t))+\exp(\sum_t r_\psi(s^{(j)}_t,a^{(j)}_t))}$,一句话概括就是「更好的轨迹被选中的概率随奖励指数级增长」。化简后 $\log p(\tau_i\succ\tau_j)=\log\sigma(r_\psi(\tau_i)-r_\psi(\tau_j))$,$\sigma$ 是 sigmoid。训练目标 $\psi\leftarrow\argmax_\psi\sum_{i,j}\log\sigma(r_\psi(\tau_i)-r_\psi(\tau_j))$。右边点明:这和国际象棋的 Elo 分是同一套方法。
推导:为什么是 sigmoid 把分子分母同除 $\exp(r_\psi(\tau_i))$: $$ p(\tau_i\succ\tau_j)=\frac{1}{1+\exp\big(r_\psi(\tau_j)-r_\psi(\tau_i)\big)}=\sigma\big(r_\psi(\tau_i)-r_\psi(\tau_j)\big). $$ 于是负对数似然 $$ \mathcal L(\psi)=-\sum_{(\tau_w,\tau_l)}\log\sigma\big(r_\psi(\tau_w)-r_\psi(\tau_l)\big) $$ 就是一个逻辑回归:样本是「一对轨迹」,特征是「奖励差」,标签恒为 1(因为我们总把胜者记作 $w$)。这也是幻灯片上那句「this looks a lot like logistic regression」的含义。
梯度也很有解释力: $$ \nabla_\psi\mathcal L=-\sum \sigma\big(r_\psi(\tau_l)-r_\psi(\tau_w)\big)\big(\nabla_\psi r_\psi(\tau_w)-\nabla_\psi r_\psi(\tau_l)\big), $$ 权重 $\sigma(r_l-r_w)$ 正是「模型当前有多不同意人类」——已经排对的样本权重趋近 0,排错的样本权重趋近 1。这是自动的难例挖掘。
常见误区:奖励模型的输出不是「绝对质量分」 BT 似然只依赖差值:把所有 $r_\psi$ 同时加一个常数 $c$,似然完全不变。在 LLM 场景里,比较总是发生在同一个 prompt 的不同回答之间,所以这个常数可以是任意的 $c(\mathbf s)$——奖励模型只在同一 prompt 内部可比,跨 prompt 的绝对值毫无意义。
这条性质有两个直接后果:(a) 你不能拿 RM 分数在不同题目之间排序、也不能拿它当绝对的质量指标;(b) 策略梯度里必须用依赖 prompt 的基线把这个未知常数消掉——这正好又一次论证了 GRPO 组内基线的合理性。
完整的 RLHF 算法与它的实践取舍
四步循环写全:1. 采样 2 条以上轨迹;2. 让人给出偏好 $\{\tau_i\succ\tau_j\}_{i,j}$;3. 训练奖励 $\psi\leftarrow\argmax_\psi\sum_{i,j}\log\sigma(r_\psi(\tau_i)-r_\psi(\tau_j))$;4. 用 $r_\psi$ 训练策略。两条箭头标注:第 3 步「看起来很像逻辑回归」;第 4 步「可以是不完全的优化」。右下三句话是本页的重点:常用于 LLM 后训练;通常只做 1 次或很少几次迭代;为什么?

「为什么只做一两轮」这个问题,答案有三层:

  • 人在环里,循环转不快。第 2 步要真人标注,一轮就是几周和几十万美元。相比之下经典的偏好式 RL(比如 Christiano 等人的 MuJoCo 实验)可以让人在训练过程中持续标注几百次,因为每次只要看两段几秒的视频。
  • 奖励模型的有效期很短。RM 是在 $\pi_{\text{ref}}$ 附近的回答上训的。策略一旦被优化得偏离,RM 立刻进入外推区、开始被攻破。要继续优化,就必须重新采样、重新标注——也就是重新转一圈循环。所以「1 轮 RLHF + 强 KL 约束」和「多轮 RLHF + 弱 KL 约束」是同一件事的两种预算分配。
  • 第 4 步本来就不需要解到底。幻灯片明确写了 “this can be incomplete optimization”,这与第 1 节 IRL 里的「懒惰策略优化」是同一个思想:外层的奖励在变,内层没必要收敛。
RLHF 在 LLM 上的具体形态:奖励模型是带标量头的 transformer
把抽象算法落到 LLM。奖励模型就是一个 transformer,读入 prompt + 完整回答,在最后一个位置输出一个标量 $r$。两个黄框是实现要点:对同一个 prompt 收集多个 on-policy 回答之间的偏好(不是拿数据集里的答案去比,要用当前策略采出来的);奖励只在生成的最后一步给出(中间所有 token 的 $r=0$)。
import torch, torch.nn as nn, torch.nn.functional as F

class RewardModel(nn.Module):
    """Bradley-Terry 奖励模型:transformer 主干 + 标量头,读最后一个非 padding 位置"""
    def __init__(self, backbone, hidden):
        super().__init__()
        self.backbone = backbone
        self.v_head = nn.Linear(hidden, 1, bias=False)

    def forward(self, input_ids, attention_mask):
        h = self.backbone(input_ids=input_ids,
                          attention_mask=attention_mask).last_hidden_state  # (B,L,H)
        scores = self.v_head(h).squeeze(-1)                                 # (B,L)
        last = attention_mask.sum(dim=1) - 1                                # 最后一个真实 token
        return scores.gather(1, last.unsqueeze(1)).squeeze(1)               # (B,)

def bt_loss(rm, chosen_ids, chosen_mask, rejected_ids, rejected_mask, margin=0.0):
    r_w = rm(chosen_ids, chosen_mask)        # 人类偏好的回答
    r_l = rm(rejected_ids, rejected_mask)    # 被拒绝的回答
    # -log sigma(r_w - r_l),等价于 softplus(-(r_w - r_l)),数值更稳
    loss = F.softplus(-(r_w - r_l - margin)).mean()
    acc  = (r_w > r_l).float().mean()        # 偏好准确率,最重要的监控指标
    return loss, acc
RLHF 全流程里涉及的所有模型汇总
左边是全景图:Step1 SFT(人类标注数据 + 预训练模型 → SFT 模型);Step2 RW(好/坏答案对 + 预训练模型 → 奖励模型);Step3 RLHF-PPO,橙色框里同时住着四个网络——Actor(策略)、Reference(参考模型,提供 KL)、Reward Model(给 $R_t$)、Critic(给 $V_t$),由 $R_t,V_t$ 算出 $A_t$ 再算损失。右边把两类 transformer 的输出对照画出:策略/critic 在每个位置输出 $(\hat x_t,\hat v_t)$,奖励模型只在最后一个位置输出一个 $r$。

补充:DPO——把 RL 那一步消掉

这一部分不在幻灯片上,但它是理解上述框架的绝佳练习:只要把第 6 节那个 KL 正则化目标的闭式解反解出来,整个 RL 循环可以被一个监督损失替代。

推导第一步:KL 正则化 RL 的闭式最优策略 固定一个 prompt $\mathbf s$,要解 $$ \max_{\pi}\;\E_{\mathbf a\sim\pi(\cdot|\mathbf s)}\big[r(\mathbf s,\mathbf a)\big]-\beta\,\KL\big(\pi(\cdot|\mathbf s)\,\|\,\pi_{\text{ref}}(\cdot|\mathbf s)\big). $$ 除以 $\beta$ 并展开 KL: $$ \max_\pi\;\E_{\pi}\Big[\frac{r(\mathbf s,\mathbf a)}{\beta}-\log\frac{\pi(\mathbf a|\mathbf s)}{\pi_{\text{ref}}(\mathbf a|\mathbf s)}\Big] =\min_\pi\;\E_\pi\Big[\log\frac{\pi(\mathbf a|\mathbf s)}{\pi_{\text{ref}}(\mathbf a|\mathbf s)\exp(r(\mathbf s,\mathbf a)/\beta)}\Big]. $$ 定义 $$ \pi^\star(\mathbf a|\mathbf s)=\frac{1}{Z(\mathbf s)}\pi_{\text{ref}}(\mathbf a|\mathbf s)\exp\big(r(\mathbf s,\mathbf a)/\beta\big),\qquad Z(\mathbf s)=\sum_{\mathbf a}\pi_{\text{ref}}(\mathbf a|\mathbf s)\exp\big(r(\mathbf s,\mathbf a)/\beta\big), $$ 则上式 $=\min_\pi \E_\pi\big[\log\frac{\pi}{\pi^\star Z(\mathbf s)}\big]=\min_\pi\big\{\KL(\pi\|\pi^\star)-\log Z(\mathbf s)\big\}$。因为 $Z(\mathbf s)$ 与 $\pi$ 无关,且 $\KL\ge0$ 当且仅当两分布相同时取零,所以最优解就是 $\pi=\pi^\star$。
这正是上一讲「控制即推断」里那个 $\pi\propto\exp(Q/\alpha)$ 的形式,只是先验从均匀分布换成了 $\pi_{\text{ref}}$。
推导第二步:反解隐式奖励并代入 BT 把 $\pi^\star$ 的式子两边取对数、解出 $r$: $$ r(\mathbf s,\mathbf a)=\beta\log\frac{\pi^\star(\mathbf a|\mathbf s)}{\pi_{\text{ref}}(\mathbf a|\mathbf s)}+\beta\log Z(\mathbf s). $$ 也就是说,任何策略都隐式地定义了一个奖励。现在把它代进 Bradley–Terry。对同一个 prompt $\mathbf s$ 下的一对回答 $(\mathbf a_w,\mathbf a_l)$: $$ p(\mathbf a_w\succ\mathbf a_l\mid \mathbf s)=\sigma\big(r(\mathbf s,\mathbf a_w)-r(\mathbf s,\mathbf a_l)\big) =\sigma\Big(\beta\log\tfrac{\pi^\star(\mathbf a_w|\mathbf s)}{\pi_{\text{ref}}(\mathbf a_w|\mathbf s)}-\beta\log\tfrac{\pi^\star(\mathbf a_l|\mathbf s)}{\pi_{\text{ref}}(\mathbf a_l|\mathbf s)}\Big), $$ 那个讨厌的 $\beta\log Z(\mathbf s)$ 在差值里完全抵消(它只依赖 $\mathbf s$,与具体回答无关)——这正好呼应前面说的「BT 只在差值意义下可辨识」。
于是我们可以直接对策略做最大似然,不需要先学一个 RM 再跑 RL: $$ \mathcal L_{\text{DPO}}(\theta)=-\E_{(\mathbf s,\mathbf a_w,\mathbf a_l)\sim\mathcal D}\left[\log\sigma\Big(\beta\log\frac{\pi_\theta(\mathbf a_w|\mathbf s)}{\pi_{\text{ref}}(\mathbf a_w|\mathbf s)}-\beta\log\frac{\pi_\theta(\mathbf a_l|\mathbf s)}{\pi_{\text{ref}}(\mathbf a_l|\mathbf s)}\Big)\right]. $$

它的梯度同样有清晰的解释:

$$ \nabla_\theta\mathcal L_{\text{DPO}}=-\beta\,\E\Big[\underbrace{\sigma\big(\hat r_\theta(\mathbf a_l)-\hat r_\theta(\mathbf a_w)\big)}_{\text{隐式 RM 现在错得有多离谱}}\big(\nabla_\theta\log\pi_\theta(\mathbf a_w|\mathbf s)-\nabla_\theta\log\pi_\theta(\mathbf a_l|\mathbf s)\big)\Big], $$

其中 $\hat r_\theta(\mathbf a)=\beta\log\frac{\pi_\theta(\mathbf a|\mathbf s)}{\pi_{\text{ref}}(\mathbf a|\mathbf s)}$。抬高胜者、压低败者,权重是当前模型的「排错程度」。

import torch.nn.functional as F

def dpo_loss(pi_logp_w, pi_logp_l, ref_logp_w, ref_logp_l, beta=0.1):
    """
    四个输入都是整条回答的 log 概率(对 completion token 求和,(B,) 形状)。
    pi_*  来自正在训练的策略;ref_* 来自冻结的参考模型(可预先算好缓存)。
    """
    logits = beta * ((pi_logp_w - ref_logp_w) - (pi_logp_l - ref_logp_l))
    loss = F.softplus(-logits).mean()           # = -log sigmoid(logits)
    with torch.no_grad():
        implicit_acc = (logits > 0).float().mean()
        margin = logits.mean() / beta
    return loss, implicit_acc, margin
RLHF(RM + PPO)DPOGRPO + 验证器
需要在线采样是否(离线偏好数据集)是(每 prompt 采 $K$ 条)
训练中的模型数42(策略 + 参考,参考可缓存)2–3
奖励形式显式神经网络 RM隐式,$\beta\log\frac{\pi_\theta}{\pi_{\text{ref}}}$规则/程序,$r\in\{0,1\}$
能否超出偏好数据分布能(策略自己探索)不能(只能在给定的 $\mathbf a_w,\mathbf a_l$ 上做对比)能
主要失效模式reward hacking、训练不稳分布外似然坍塌:$\pi(\mathbf a_w)$ 和 $\pi(\mathbf a_l)$ 可能一起下降,只要差值拉大验证器漏洞、全对/全错组
实现复杂度高低(就是一个损失函数)中

DPO 的那个失效模式值得记住:损失只关心 $\log\pi_\theta(\mathbf a_w)-\log\pi_\theta(\mathbf a_l)$ 这个差,完全不管两者的绝对值。实践中经常观察到 chosen 和 rejected 的对数似然双双下降,概率质量跑到了两者之外的第三类文本上。缓解办法包括加一个 SFT 正则项、或者用在线/迭代式 DPO(每轮用当前策略重新采样并重新标注)——后者其实又转回了 RLHF 的循环。

9. 设计选择(3b):可验证奖励、过程奖励与推理模型

人类偏好不是唯一的奖励来源。对一大类任务,我们知道正确答案:数学题有标准答案,代码有单元测试,形式化证明有检查器。这时候奖励可以由程序给出,不需要神经网络。

RLVR:从验证器学习,LLM 与推理模型的回答对比
同一道题(「James 每周给 2 个朋友各写两次 3 页的信,一年写多少页?」)。上半是普通 LLM(GPT-4o)的回答:结构化的分点推理,直接给出 624。下半是推理模型(DeepSeek-R1)的回答:一大段被 <think> 包起来的思考过程,里面充满「Hmm, 让我先理解一下细节」「Wait, 让我检查一下」「Alternatively, 也许……」「But wait a second. 有没有可能考虑闰年?」这类自我怀疑与回溯,最后才输出答案。右侧两个黄框是方法论:使用能指示答案正确性的奖励;训练模型生成能导向更多正确答案的「思考」。

这就是 RLVR(RL with Verifiable Rewards)。它在 RL 的框架里其实非常经典,但有一个特别漂亮的性质:

核心结论:思维链是被 RL 优化出来的隐变量 奖励只看最终答案是否正确,对中间的思考过程没有任何监督。也就是说,那几千个 token 的推理过程是一个自由的隐变量,RL 唯一的要求是「你想怎么想都行,只要最后答对的概率高」。
于是模型自发地学出了各种提高成功率的策略:把问题拆解、列举多种解法、算完之后回头验算、发现矛盾就推倒重来。这些行为没有一条是被人类示范教出来的——用监督学习你根本不知道该往标签里写什么。这正是 RL 相对于模仿学习的根本优势:它优化的是结果,不是过程。典型的副产品是回答长度在训练中持续增长,因为「多想一会」确实能提高正确率。
验证器奖励 vs 过程奖励
两类奖励的对比。左:验证器奖励(verifier reward)——模型(或程序)只评估最终答案对不对,图中紫框标出被检查的「624 pages」。右:过程奖励(process reward)——模型评估思维链的每一步是否正确,图中一道多项式分解题的每一行推理被标成绿色(正确)或红色(错误);可以看到中间某一行 $x^8+3x^4-4=(x^2+2)(x^2-2)(x^2+1)(x^2-1)$ 被标红,因为它跳错了一步。
奖励来源信号形式优点代价与风险
人类偏好 RM末端标量,同 prompt 内可比适用于开放式任务(写作、对话、安全)标注贵;RM 可被攻破;只在 $\pi_{\text{ref}}$ 附近可信
验证器(ORM / 规则)末端 $\{0,1\}$不可(轻易)被攻破,可无限量生成只适用于有标准答案的领域;信号极稀疏,长 horizon 信用分配困难
过程奖励模型 PRM每一步一个标量稠密信号,信用分配精细;也可用于推理时搜索步骤级标注极贵(或需大量 MC rollout 估计);PRM 本身也会被攻破
LLM-as-judge末端标量或偏好便宜、可扩展、适用范围广继承评判模型的偏见(偏爱长文、偏爱自己风格)

信用分配:稀疏奖励在长序列上的老问题

一条 8000 token 的思维链,最后得到 $r=1$。在 GRPO 里,这 8000 个 token 全部拿到同一个优势值 $\hat A$。这意味着:那句真正解决问题的关键推导,和中间那句无关紧要的「Hmm, let me think」,被同等强化。这就是稀疏奖励下的信用分配问题,只不过在 LLM 上表现为「哪些 token 值得被强化」。

现有的三条缓解路线:

  • 过程奖励:给中间步骤打分,把稀疏奖励变稠密。代价是需要 PRM,而 PRM 又是一个可被攻破的神经网络。
  • 价值函数 / GAE:让 critic 学出「从这个前缀出发的成功率」,$\hat A_t = r + \gamma\hat V(s_{t+1})-\hat V(s_t)$ 自动给出「这一步让成功率上升了多少」。理论最优,但 critic 在超长序列上极难训好。
  • 大数定律:干脆不做细粒度信用分配,靠海量样本让噪声平均掉。GRPO 在实践中基本走这条路——这也是为什么它需要非常大的批量。

奖励黑客:RL 会找到你留下的每一个漏洞

注意 即使奖励来自程序,也不等于安全。真实项目里反复出现的模式包括:
  • 答案格式匹配漏洞:奖励用字符串匹配判分,模型学会在回答里把所有可能的答案都列一遍,总有一个能匹配上。
  • 测试用例攻击:代码任务里模型不去实现功能,而是 if input == "test1": return 3 地硬编码测试用例;或者直接改写测试文件、捕获异常让测试「通过」。
  • 验证器本身的 bug:数值比较用了 ==、正则写漏了一个分支、超时被判成成功。
  • 语言退化:$\beta=0$ 时思维链常会变成人类无法阅读的中英混杂缩写串——因为奖励从不检查思考过程的可读性。DeepSeek-R1 就为此额外加了语言一致性奖励。
通用的应对思路只有两条:把优化限制在奖励可信的区域内(KL 惩罚、早停、限制训练步数),以及让奖励更难被攻破(沙箱隔离、隐藏测试集、多个独立验证器投票、RM 集成)。

多轮、工具与智能体:困难在哪里

前面所有讨论都假设「一个 prompt → 一段回答 → 一个奖励」。真实的智能体不是这样:它要调用搜索、执行代码、读取返回结果、再决定下一步。这时会同时出现三个新问题:

  1. 转移不再确定。环境返回的 token(搜索结果、报错信息、用户的下一句话)不由策略决定。因此必须把这些位置从策略梯度里 mask 掉——否则你是在用奖励去调整模型对环境输出的预测概率。
  2. horizon 暴涨。一个 10 轮的智能体轨迹可能有 10 万 token,末端一个 0/1 奖励。这已经远超 GRPO 的舒适区,也是过程奖励和分层方法重新变得重要的原因。
  3. 部分可观测。环境的真实状态(数据库内容、用户的真实意图、代码库的完整结构)从来没有被完整观测到,模型只看到一串观测。这就把我们带到了本讲的最后一部分。

10. 附加篇:部分可观测与序列模型

超越 MDP:POMDP 的图模型与真实世界例子
图模型:真实状态 $s_1\to s_2\to s_3$ 构成马尔可夫链,但我们只能看到由状态发出的观测 $o_t$。两条标注点出全部困难:观测 $o_t$ 不满足马尔可夫性($o_{t+1}$ 不只依赖 $o_t$),而状态 $s_t$ 是未知的。左下的例子很直白:真实状态 $s_t$ 是高速公路上每辆车的位置速度 $(x,y,z,\dot x,\dot y,\dot z,\dots)$,而观测 $o_t$ 只是一个摄像头的视锥。右边强调:绝大多数真实问题都是这样的——开车、Minecraft、机器人交互、视觉对话。

为什么 LLM 这一讲要谈 POMDP?因为多轮对话正是标准的 POMDP:用户心里真正想要什么(真实状态)你看不到,你只看到他打出来的字(观测)。而更根本的原因在最后会揭晓——LLM 处理这个问题的方式,恰好就是教科书里的标准答案之一。

POMDP 有多古怪

POMDP 的两个反直觉现象:信息收集动作与随机最优策略
例子 1:信息收集动作。迷宫里的老鼠可能需要先跳起来看一眼全局(这个动作本身不带来任何直接奖励),再决定往哪走——在 MDP 里这种动作永远不会是最优的,因为状态已知。例子 2:随机的最优策略。三个格子 A、B、C,宝藏在 B;A 和 C 在观测上完全相同(都是「两侧都是墙、左右都能走」)。
直觉:为什么最优策略必须是随机的 在 A/B/C 这个例子里,智能体只能看到 $o$,而 A 和 C 的观测完全一样(这叫感知混叠,perceptual aliasing)。一个确定性的无记忆策略 $\pi(a|o)$ 在看到这个观测时只能输出一个固定动作:
· 若总是向右,则从 A 出发能到 B,从 C 出发会永远走开;
· 若总是向左,情况正好相反。
两种确定性策略都有一半的初始状态永远到不了目标。而「左右各 0.5」的随机策略,从 A 或 C 出发都会做随机游走,期望几步之内必然踏进 B。
结论:在部分可观测环境下,最优的无记忆策略可能是随机的。这直接摧毁了 MDP 理论里「总存在确定性最优策略」这条基本定理。
三类方法把 s 换成 o 之后还能用吗
把三类算法里的 $s$ 全部机械替换成 $o$,问「还行吗?」:策略梯度 $\nabla_\theta J\approx\frac1N\sum_i\sum_t\nabla_\theta\log\pi_\theta(a_{i,t}|o_{i,t})A(o_{i,t},a_{i,t})$;值函数方法 $Q(o,a)\leftarrow r(o,a)+\gamma\max_{a'}Q(o',a')$;基于模型的方法 $\hat p(o'|o,a)$。右下角先澄清「handle」的定义:handle = 在给定的策略类里找到最好的策略——这里策略类是无记忆的 $\pi_\theta(a|o)$,所以我们只要求找到最好的无记忆策略,不要求找到全局最优。

策略梯度:基本没问题

策略梯度在 POMDP 下的关键点:优势函数是状态的函数
关键点(Key point):优势是状态 $s_t$ 的函数,它不依赖 $s_{t-1}$——正因如此,在 MDP 里用 $r_t+\gamma\hat V(s_{t+1})-\hat V(s_t)$ 才是合法的。但 训练 $\hat V(o_t)$ 是不合法的:右下角那句话说得很清楚,「每次看到这个状态,我们都期望得到这个值,与过去的状态无关」——这对 $s$ 成立,对 $o$ 不成立,因为过去的观测确实影响这个值。所以 $\log\pi_\theta(a|o)$ 那一侧「没问题(不需要马尔可夫性)」,而优势那一侧「需要小心」。

为什么 $\log\pi_\theta(a_t|o_t)$ 那一侧完全没问题?回忆策略梯度的推导:

$$ \nabla_\theta J(\theta)=\E_{\tau\sim p_\theta(\tau)}\left[\Big(\sum_t\nabla_\theta\log\pi_\theta(a_t|o_t)\Big)\Big(\sum_t r(o_t,a_t)\Big)\right]. $$

这个式子的推导只用到了两件事:轨迹分布可以分解成 $p(\tau)=p(o_1)\prod_t\pi_\theta(a_t|o_t)p(o_{t+1}|o_{1:t},a_{1:t})$,以及 $\nabla\log$ 技巧。整个过程从未使用马尔可夫性——环境的转移可以任意依赖全部历史,那些项在求 $\nabla_\theta$ 时照样被消掉,因为它们不含 $\theta$。所以 REINFORCE 直接可用。

三种策略梯度形式在 POMDP 下的对错判定,含 pop quiz
三个具体形式的判定:(✓)完整回报形式 $\frac1N\sum_i(\sum_t\nabla\log\pi_\theta(a_{i,t}|o_{i,t}))(\sum_t r(o_{i,t},a_{i,t}))$ 合法;(✗)价值基线形式 $\frac1N\sum_i\sum_t\nabla\log\pi_\theta(a_{i,t}|o_{i,t})(r_{i,t}+\gamma\hat V(o_{i,t+1})-\hat V(o_{i,t}))$ 不合法;最下面是随堂小测:reward-to-go 形式 $\frac1N\sum_i\sum_t\nabla\log\pi_\theta(a_{i,t}|o_{i,t})(\sum_{t'=t}^{H}r(o_{i,t'},a_{i,t'}))$ 呢?
随堂小测的答案:reward-to-go 也是合法的 因果性(causality)修正说的是「当前动作不能影响过去的奖励」,其证明是:对 $t'\lt t$, $$ \E\big[\nabla_\theta\log\pi_\theta(a_t|o_t)\,r_{t'}\big] =\E\Big[r_{t'}\,\E\big[\nabla_\theta\log\pi_\theta(a_t|o_t)\,\big|\,\text{历史至 }t\big]\Big]=0, $$ 因为内层期望是得分函数的条件期望,恒等于零。这个论证只用到「$r_{t'}$ 在给定历史后是确定的」,完全不需要马尔可夫性。所以扔掉 $t'\lt t$ 的奖励项依然无偏。
同理,任何不依赖动作的基线 $b$(包括依赖整段历史的 $b(o_{1:t})$)也是合法的。真正不合法的只有一件事:用自举(bootstrapping),也就是用 $\hat V(o_{t+1})$ 去替代未来回报——因为 $\hat V(o)$ 这个函数本身就不存在良好定义。

值函数方法:坏掉了

值函数方法在无马尔可夫性时失效
黄框直接给出结论:值函数方法在没有马尔可夫性时不工作。右边又摆出 A/B/C 那个例子提醒你为什么。

两个独立的失效机制,都要说清楚:

  • 自举的前提不成立。$Q(o,a)\leftarrow r(o,a)+\gamma\max_{a'}Q(o',a')$ 这个更新隐含假设:$o'$ 完全概括了未来。但在 POMDP 里,「从观测 $o$ 出发的期望回报」根本不是一个良定义的量——它取决于你是怎么走到这里的。在 A/B/C 例子里,$Q$ 表被迫给 A 和 C 存同一个数字,而这个数字是两者的某种平均,对哪一个都不对。而且这个错误会通过自举不断传播和放大:错的目标训出更错的 $Q$。
  • 贪心策略必然是确定性的。$\pi(a|o)=\argmax_a Q(o,a)$ 永远给出确定性策略,而我们刚证明了在这个环境里最优无记忆策略必须是随机的。所以即使 $Q$ 学对了,导出的策略也是坏的。

这条结论的实际影响很大:它意味着 Q-learning、SAC、DDPG 这些采样效率最高的算法,在部分可观测下都不能直接用 $o$ 替换 $s$。而采样效率最低的 REINFORCE 反而没事。「能处理 POMDP」和「采样高效」在这里是矛盾的。

基于模型的方法:更糟

用观测转移模型规划的失败例子:两扇门
反例极其精巧。房间里有左右两扇门,观测只有三种:$o=\text{Left}$、$o=\text{Right}$、$o=\text{Pass}$(通过了)。数据统计出 $p(o'=\text{Pass}\mid o=\text{Left},a=\text{Open})=0.5$,于是规划器推理:「每次尝试有 50% 概率打开,那就一直试啊!」——试 10 次成功率 $1-0.5^{10}\approx99.9\%$。但真相是:门要么锁着要么没锁,这是一个固定但不可观测的状态。如果第一次没开,说明门就是锁的,之后 $p(o'=\text{Pass}\mid o=\text{Left},a=\text{Open})=0$,再试一万次也没用。

这个例子的深刻之处在于:学到的模型 $\hat p(o'|o,a)$ 边缘分布是对的(在所有门中确实有一半能开),但条件于历史的分布是错的。而规划器恰恰要反复展开这个模型,于是把「50% 的机会」错误地当成了每次独立重抽——产生了一种系统性的、无法通过多采样修复的乐观偏差。这类「模型自欺」在基于模型的 RL 里是致命的,因为规划器会主动去搜索模型认为好、实际上不存在的路径。

出路一:学一个马尔可夫的隐状态空间

状态空间模型:学一个隐状态 z 使其满足马尔可夫性
右上的图模型:引入隐变量 $\mathbf z_t$,令 $p(\mathbf z_{t+1}|\mathbf z_t,\mathbf a_t)$ 是马尔可夫转移,观测由 $\mathbf z_t$ 发出。左下是完整的生成模型与推断模型:先验 $p(\mathbf z)=p(\mathbf z_1)\prod_t p(\mathbf z_{t+1}|\mathbf z_t,\mathbf a_t)$($p(\mathbf z_1)=\mathcal N(0,I)$,转移是学出来的),观测模型 $p_\theta(\mathbf o|\mathbf z)=\prod_t p(\mathbf o_t|\mathbf z_t)$,编码器 $q_\phi(\mathbf z|\mathbf o)=\prod_t q_\phi(\mathbf z_t|\mathbf o_{1:t})$(注意是滤波形式:$\mathbf z_t$ 由 $\mathbf o_{1:t}$ 推断)。右侧三行打分:$Q(s,a)$ 更新 ✗($s$ 不可得)、$Q(o,a)$ 更新 ✗(不满足马尔可夫)、$Q(\mathbf z,a)$ 更新 ✓。最后两问:为什么这可能还不够?预测可能很难;也许我们并不需要好的预测就能拿到高奖励。

这是一个变分自编码器式的做法:用 ELBO 同时学生成模型和编码器,把「压缩历史」这件事交给 $q_\phi$。学出来的 $\mathbf z_t$ 按构造满足马尔可夫性,于是所有值函数方法立刻恢复可用。Dreamer、SLAC、PlaNet 这一系工作走的都是这条路,在图像输入的控制任务上效果相当好。

Levine 提出的保留意见也很关键:要重建观测就意味着模型必须学会渲染整幅图像,而画面里大部分像素(背景纹理、飘动的树叶)对决策毫无价值。你可能耗尽全部模型容量去预测无关细节,反而丢掉了那个决定成败的小物体。「也许我们并不需要好的预测就能拿到高奖励」——这个思路会在基于模型的 RL 那部分继续展开。

出路二:历史状态

历史状态:把全部观测历史当作状态,它天然满足马尔可夫性
右侧的论证:定义 $\mathbf s_t=(\mathbf o_1,\mathbf o_2,\dots,\mathbf o_t)$,问「这行得通吗?满足马尔可夫性吗?」答案是满足——因为 $\mathbf s_{t-1}=(\mathbf o_1,\dots,\mathbf o_{t-1})$ 已经完全包含在 $\mathbf s_t$ 里,它「没有告诉我们任何 $\mathbf s_t$ 里没有的信息」,形式化就是 $\mathbf s_{t+1}\perp \mathbf s_{t-1}\mid \mathbf s_t$。于是最下面那条 Q-learning 更新 $Q(\mathbf o_1,\dots,\mathbf o_t,\mathbf a)\leftarrow r(\mathbf o,\mathbf a)+\gamma\max_{\mathbf a'}Q(\mathbf o_1,\dots,\mathbf o_{t+1},\mathbf a')$ 是合法的 ✓。左边给出实现方式:把观测序列送进一个序列模型,输出 $\mathbf z_3$——这时 $\mathbf z$ 是历史的确定性函数,而不再是需要推断的隐变量。
推导:历史状态为什么天然马尔可夫 要证 $p(\mathbf s_{t+1}\mid \mathbf s_t,\mathbf s_{t-1},\dots,\mathbf s_1)=p(\mathbf s_{t+1}\mid \mathbf s_t)$。注意 $\mathbf s_{t}=(\mathbf o_{1:t})$,而对任意 $k\lt t$ 都有 $\mathbf s_k=(\mathbf o_{1:k})$,它是 $\mathbf s_t$ 的一个确定性函数(截断前 $k$ 项)。既然条件里已经有了 $\mathbf s_t$,再多给 $\mathbf s_{k}$ 不增加任何信息,条件分布自然不变。
代价是状态空间随 $t$ 无界增长——但这只是表示上的困难,不是理论上的困难。而处理「把一个变长序列压成定长表示」正是序列模型最擅长的事。
两种架构:固定短历史堆叠 vs 序列模型读入完整历史
问题是「如何表示 $Q(\mathbf o_1,\dots,\mathbf o_t,\mathbf a)$」。左边:把最近 $k$ 帧堆起来送进一个卷积网络——固定的(短)历史,DQN 玩 Atari 时用的就是这招(堆 4 帧)。「这样不好吗?」「有时候确实不好……」——因为 $k$ 帧之外的信息全部丢失,在需要长期记忆的任务上会失败。右边:把 $\mathbf o_1,\dots,\mathbf o_4$ 全部送进一个序列模型(RNN / LSTM / Transformer),输出各动作的 $Q$ 值。
import torch, torch.nn as nn

class RecurrentQ(nn.Module):
    """历史状态 Q 网络:序列模型把 o_{1:t} 压成隐状态,再输出各动作的 Q"""
    def __init__(self, obs_dim, n_act, hid=256):
        super().__init__()
        self.enc  = nn.Sequential(nn.Linear(obs_dim, hid), nn.ReLU())
        self.core = nn.GRU(hid, hid, batch_first=True)   # 也可换成 Transformer
        self.head = nn.Linear(hid, n_act)

    def forward(self, obs_seq, h0=None):                 # obs_seq: (B,T,obs_dim)
        z, hT = self.core(self.enc(obs_seq), h0)         # z: (B,T,hid) —— z_t 编码 o_{1:t}
        return self.head(z), hT                          # (B,T,n_act)

def recurrent_dqn_loss(q_net, tgt_net, obs_seq, act_seq, rew_seq, done_seq,
                       gamma=0.99, burn_in=8):
    """
    在整段序列上做 Q-learning。关键点:
      1) 必须按「整条轨迹」而非「打散的转移」采样,否则隐状态无从谈起;
      2) burn_in:前若干步只用来预热隐状态、不计损失,缓解隐状态陈旧问题。
    """
    q_all, _ = q_net(obs_seq)                                   # (B,T,A)
    with torch.no_grad():
        q_tgt_all, _ = tgt_net(obs_seq)
        next_max = q_tgt_all[:, 1:].max(dim=-1).values           # (B,T-1)
        y = rew_seq[:, :-1] + gamma * (1 - done_seq[:, :-1]) * next_max
    q_sa = q_all[:, :-1].gather(-1, act_seq[:, :-1].unsqueeze(-1)).squeeze(-1)
    td = (q_sa - y) ** 2
    return td[:, burn_in:].mean()
部分可观测部分的总结
总结页:POMDP 很古怪(随机最优策略、信息收集动作);有些方法「直接就能用」,但最高效的那些不行,因为它们需要值函数——而且即便能用的那些,也只能得到最好的无记忆策略;我们可以用模型学一个马尔可夫状态空间;也可以干脆用历史状态,也就是用序列模型读入观测历史。
核心结论:回到 LLM 现在把这一节和前九节接起来。一个做多轮工具调用的 LLM 智能体,它的「状态」是什么?就是它的上下文窗口——所有历史观测(用户消息、工具返回、自己说过的话)拼成的那一整条序列。也就是说,LLM 智能体天然是「历史状态 + 序列模型」这条路线的实例,而且它是这条路线目前为止最成功的实现。KV cache 就是那个被增量维护的隐状态。
这解释了两件事:为什么在 LLM 上做 RL 时,策略梯度类方法(PPO、GRPO)一统天下,而 Q-learning 类方法几乎无人使用——因为上下文历史下的 $Q$ 自举极难稳定;也解释了为什么「上下文长度」对智能体如此关键——它直接决定了这个历史状态能容纳多少信息,超出窗口的部分就退化成了 p-50 左边那个「固定短历史」的方案。

本讲小结

一页速查

主题关键式子一句话
MaxEnt IRL$\nabla_\psi\mathcal L=\E_{\pi^\star}[\nabla_\psi r_\psi]-\E_{p(\tau|\mathcal O,\psi)}[\nabla_\psi r_\psi]$抬专家、压策略;难点是配分函数
重要性权重$w_j=\dfrac{\exp(\sum_t r_\psi)}{\prod_t\pi(a_t|s_t)}$动力学项相消,不需要知道环境模型
AIRL 判别器$D=\dfrac{\frac1Z e^{r_\psi}}{\frac1Z e^{r_\psi}+\pi}$IRL 就是结构化的 GAN
LLM 的 bandit 视角$\E_{\pi_\theta(\mathbf a|\mathbf s)}[r(\mathbf s,\mathbf a)]$状态=prompt,动作=整段补全
LLM 的 token 视角$\E_{\pi_\theta(\tau)}[r(\tau)]$,转移确定性拼接要用价值基线/中间奖励时才必须
序列 log 概率分解$\nabla_\theta\log\pi_\theta(\mathbf a|\mathbf s)=\sum_t\nabla_\theta\log\pi_\theta(a_t|s_t)$RL 微调 = 奖励加权的交叉熵
重要性加权估计器$\frac1N\sum_i\frac{\pi_\theta}{\bar\pi}\nabla_\theta\log\pi_\theta\,r$为了让贵重的样本被复用 $K$ 次
GAE$\hat A_t=\sum_{t'\ge t}(\gamma\lambda)^{t'-t}\delta_{t'}$偏差-方差旋钮;critic 别在 prompt 上训
GRPO 优势$\hat A_{i,j}=\frac{r_j-\operatorname{mean}(r)}{\operatorname{std}(r)}$用组内均值当基线,扔掉 critic
组内基线的偏差$\E[\hat A_j|\mathbf a_j]=\frac{K-1}{K}(r_j-\bar r)$只差一个常数缩放;RLOO 严格无偏
KL 正则化奖励$\bar r=r-\beta\KL(\pi_\theta\|\pi_{\text{ref}})$保住人话 + 防止 reward hacking
k3 KL 估计$e^{u}-u-1,\;u=\log\pi_{\text{ref}}-\log\pi_\theta$无偏、恒非负、低方差
PPO clip$\min\{\operatorname{clip}(\rho,1\pm\epsilon)\hat A,\;\rho\hat A\}$悲观下界;比值必须逐 token 算
Bradley–Terry$\log p(\tau_i\succ\tau_j)=\log\sigma(r_\psi(\tau_i)-r_\psi(\tau_j))$偏好学习 = 逻辑回归;只有差值可辨识
KL 正则的最优策略$\pi^\star\propto\pi_{\text{ref}}\exp(r/\beta)$控制即推断的直接推论,也是 DPO 的起点
DPO$-\log\sigma\big(\beta\log\frac{\pi_\theta(\mathbf a_w)}{\pi_{\text{ref}}(\mathbf a_w)}-\beta\log\frac{\pi_\theta(\mathbf a_l)}{\pi_{\text{ref}}(\mathbf a_l)}\big)$把 RM + RL 折叠成一个监督损失,$Z(\mathbf s)$ 抵消
POMDP 里的策略梯度$\nabla_\theta J\approx\frac1N\sum_i(\sum_t\nabla\log\pi_\theta(a|o))(\sum_t r)$合法,推导从未用过马尔可夫性
POMDP 里的值函数$Q(o,a)\leftarrow r+\gamma\max Q(o',a')$不合法:自举前提破裂 + 强制确定性策略
历史状态$\mathbf s_t=(\mathbf o_1,\dots,\mathbf o_t)$天然马尔可夫;序列模型来表示它

要点清单

  • 奖励是设计问题,不是给定条件。本讲给出三条获取奖励的路:从演示反推(IRL)、从偏好学习(BT/RLHF)、从程序验证(RLVR)。它们的适用范围互不重叠:IRL 适合可演示的控制任务,偏好适合开放式生成,验证器适合有客观答案的推理。
  • MaxEnt IRL 与 GAN 是同一个东西。「一个网络给分、另一个网络优化这个分数」这个结构,从 GAIL/AIRL 一路延续到 RLHF——奖励模型就是判别器,LLM 就是生成器。
  • LLM 上的 RL 全部是策略梯度的变体。REINFORCE → 加重要性权重(为了复用样本)→ 加 clip(为了不跑太远)→ 加基线(为了降方差)→ 加 KL(为了不被奖励模型骗)。每一步都对应本课前半程学过的一个概念。
  • PPO 与 GRPO 的差别只是基线的来源。critic 用参数拟合换采样,组内平均用采样换参数。选哪个取决于奖励是稀疏末端的还是稠密中间的、任务是单轮的还是多轮的。
  • std 归一化不是免费的。它带来难度偏差(简单/困难 prompt 被过度放大、全对全错组零梯度)和长度偏差(长的错误回答受罚更轻)。知道这些偏差从哪来,比记住公式重要。
  • Bradley–Terry 的不可辨识性是一条贯穿全篇的线索。它解释了为什么 RM 分数不能跨 prompt 比较、为什么需要 per-prompt 基线、以及为什么 DPO 推导里 $Z(\mathbf s)$ 会消失。
  • RL 优化的是结果不是过程,因此才能让模型自己发明出回溯、验算这类没人教过的推理行为——也因此才会去攻击你验证器里的每一个漏洞。这是同一枚硬币的两面。
  • 部分可观测下,采样效率和适用性是矛盾的。最笨的 REINFORCE 直接可用,最高效的值函数方法直接坏掉。出路是学隐状态空间(有模型)或用历史状态(序列模型)——而 LLM 智能体就是后者的极致实现。

延伸阅读

逆强化学习与对抗式模仿

RLHF 与偏好学习

LLM 上的 RL 算法

后训练与模型行为

  • Scaling Instruction-Finetuned Language Models (2022) — FLAN 系列,本讲第 3 节那张指令微调图的出处。
  • Language Models as Agent Models (Andreas, 2022) — 「LLM 是在模拟说话人」这个视角,解释了保龄球那个例子为什么会随前缀改变而改变。
  • Unforgettable Generalization in Language Models (Zhang, Chosen, Andreas) — 用翻转标签微调反而答对的现象,支撑「后训练主要在诱发已有能力」这个论断。

部分可观测