后训练笔记 02:强化学习基础

大模型后训练里的 RL 和传统 RL 不太一样。传统 RL 常见场景是 agent 在环境里反复交互,比如机器人控制、游戏、推荐系统。LLM 后训练里的“环境”往往更窄:给一个 prompt,模型生成 response,然后由人类偏好、reward model、规则 verifier、测试用例或者答案匹配器给出反馈。

有一说一,传统RL学起来真有点绕脑子的😓

RL的基本概念

为了搞清楚 RL,先把 terminology 理清楚很重要。

RL 的一部分要从随机过程讲起。更准确地说,RL 的目标是在不确定的交互过程中,通过学习 policy 来最大化期望累计回报。 在公式中,大写字母 \(X\) 表示随机变量,小写字母 \(x\) 表示观测到的具体值,比如 \(x_0 = 1\)\(x_1 = 0\)

强化学习中的 agent-environment 交互

然后引入一些定义 - agent:实际选择 action 的主体,与 environment 交互,目标是最大化 expected return。 - environment:agent 用来交互的环境。 - action:agent 可以采取的行为,比如在马里奥游戏中向左、向右或向前移动。 - state:描述当前环境状况的信息;agent 执行 action 后,environment 会转移到新的 state。

state space 和 action space 分别是所有可能 state 和 action 的集合。

  • trajectory:一条完整的交互轨迹可以写成:

\[ \tau = (s_0, a_0, r_0, s_1, a_1, r_1, \ldots, s_{T-1}, a_{T-1}, r_{T-1}, s_T) \]

  • reward:与环境交互后获得的奖励。

  • return:cumulative future reward,表示从当前时刻开始累计得到的 reward。 一般用大写 \(R_t\) 表示随机 reward,用大写 \(U_t\) 表示随机 return。先不考虑折扣时:

\[ U_t = \sum_{k=t}^{T-1} R_k \]

当一条具体轨迹采样完成后,\(R_k\) 变成观测到的 reward \(r_k\),对应的 return 可以写成 \(u_t\)。很多 RL 文献也会直接用 \(G_t\) 表示这条轨迹上的 return。

\[ G_t \equiv u_t = \sum_{k=t}^{T-1} r_k \]

  • discounted return:由于即时奖励和之后的奖励不能一概而论(比如现在拿 100 和一年后拿 100),所以引入折扣率 \(\gamma\) 来控制未来 reward 的影响程度。

\[ U_t = \sum_{k=t}^{T-1} \gamma^{k-t} R_k \qquad\text{and}\qquad G_t \equiv u_t = \sum_{k=t}^{T-1} \gamma^{k-t} r_k \]

如果不区分“随机 return”和“采样后的具体 return”,也可以把它们都简写成 \(G_t = U_t\)。这里保留这个区分,是为了和 PDF 中的记号保持一致。

另一个更形式化的表示方式是Markov Decition Process,把Agent与环境的交互过程建模成一个五元组。 M = (S, A, T, R, gamma)

分别表示状态空间,动作空间,状态转移方程,奖励函数,和折扣率。 在 MDP 的定义里,即时奖励只由 (s,a,s’) 三者决定—— 只要确定了 “从 s 出发、做动作 a、落到 s’”,奖励就是确定的。

交互中的随机性来源

RL中的随机性主要来源于两个部分 1. policy选择动作时的随机性 2. 状态转移函数带来的随机性

policy function:一个概率函数,用来输出给定当前 state 时执行某个 action 的概率。

\[ \pi_\theta(a_t \mid s_t) = P(A_t = a_t \mid S_t = s_t) \]

state transition function 一个旧的state转移到新的state的概率函数

\[ P(s'|s,a) = P(S_{t+1}=s' \mid S_t=s, A_t=a) \]

价值函数(Value function)

Action-value function\(Q_{\pi}(s_t, a_t)\) 用来表示当前的state,policy下,使用action a_t所能得到的return。 这样就可以衡量一个action的好坏。不过由于state一般认为不变,一个更好的policy 也可以提升action的return。

\[ Q^\pi(s_t, a_t) = \mathbb{E}_\pi\left[U_t \mid S_t = s_t, A_t = a_t\right] \]

这里的期望是在固定当前 \((s_t, a_t)\) 后,对后续 state 和 action 的随机性求平均。这样就能比较同一个 state 下不同 action 的长期价值。

State-value function 状态价值函数进一步对当前 action 取期望:

\[ \begin{align*} V^\pi(s_t) &= \mathbb{E}_{A_t \sim \pi(\cdot \mid s_t)}\left[Q^\pi(s_t, A_t)\right] \\ &= \sum_a \pi(a \mid s_t) * Q^\pi(s_t, a) \end{align*} \] 这里进一步对当前 action 取期望,把 action 选择本身的随机性也纳入 value function。

Return 的估计:DP、MC 与 TD

动作价值函数和状态价值函数都在衡量长期 return,但 \(V^\pi(s)\)\(Q^\pi(s,a)\) 到底怎样得到,需要看我们掌握了哪些信息。

经典方法可以分成三类:

  1. Dynamic Programming(DP):已知完整的环境模型,对所有可能的下一状态求期望;
  2. Monte Carlo(MC):不知道环境模型,等完整 episode 结束后使用实际 return;
  3. Temporal-Difference(TD):不知道环境模型,用一步真实 reward 和下一状态的 value estimate 做 bootstrap。

动态规划(Dynamic Programming):已知环境模型时直接算期望

DP 假设 MDP 的环境模型已知,也就是我们知道状态转移概率 \(P(s'\mid s,a)\) 和期望即时奖励 \(r(s,a,s')\)。因此它不必先采样出一条具体 trajectory,而是可以枚举所有可能的 action 和下一状态,直接做 Bellman expectation backup:

\[ V_{k+1}(s) = \sum_a \pi(a\mid s) \sum_{s'}P(s'\mid s,a) \left[r(s,a,s')+\gamma V_k(s')\right] \]

这里 \(V_k\) 是第 \(k\) 轮的 value estimate。对所有状态反复应用这个更新,\(V_k\) 会逐渐收敛到固定 policy \(\pi\) 的真实价值 \(V^\pi\),这个过程叫 iterative policy evaluation。

如果目标不是评估一个固定 policy,而是寻找最优 policy,可以在每次更新时直接选择期望回报最大的 action:

\[ V_{k+1}(s) = \max_a\sum_{s'}P(s'\mid s,a) \left[r(s,a,s')+\gamma V_k(s')\right] \]

这就是 value iteration 使用的 Bellman optimality backup。

DP 的优势是更新目标来自对完整环境模型的精确求和,没有单条 trajectory 带来的采样噪声,也不需要等待 episode 结束。问题是它必须知道环境模型,还要遍历状态空间。对于小型 grid world 可以这样做;但围棋、机器人控制以及语言模型的 token state space 都大得无法枚举,所以实际的大规模 RL 通常只能从样本中学习。

上面直接使用了 Bellman equation 的结论,后面会再完整推导它为什么成立。

蒙特卡洛(Monte Carlo):等 episode 结束后再算

Monte Carlo(MC)的思路很直接:让 agent 按照当前 policy 跑完一整条 trajectory,等所有 reward 都拿到之后,再从后往前计算每个时刻的 return。

假设一条 trajectory 上的 reward 是:

1
r_0 = 0,  r_1 = 1,  r_2 = 2

\(\gamma = 0.9\),那么:

\[ G_2 = r_2 = 2 \]

\[ G_1 = r_1 + \gamma r_2 = 1 + 0.9 \times 2 = 2.8 \]

\[ G_0 = r_0 + \gamma r_1 + \gamma^2 r_2 = 0 + 0.9 \times 1 + 0.9^2 \times 2 = 2.52 \]

如果同一个 state \(s\) 在不同 trajectory 中被访问了多次,就可以用这些 trajectory return 的平均值估计 state value:

\[ V^\pi(s) \approx \frac{1}{N(s)}\sum_{i=1}^{N(s)} G_t^{(i)} \]

同理,也可以只统计在 \((s,a)\) 处采取 action \(a\) 后得到的 return,估计 action value:

\[ Q^\pi(s,a) \approx \frac{1}{N(s,a)}\sum_{i=1}^{N(s,a)} G_t^{(i)} \]

MC 的优点是目标值来自完整 trajectory,不需要提前知道环境的 transition function,也不会用当前 value estimate 去构造自己的训练目标。只要 trajectory 是按照 policy \(\pi\) 采样的,样本数量足够多,平均 return 就能收敛到真实的 value。

它的问题也很明显:必须等 episode 结束才能计算 return。对于游戏还好,但对于没有明确终点的环境,或者 LLM 生成很长 response 的场景,等待成本会比较高。而且一条 trajectory 中任何一个 reward 的随机性都会传到前面所有时刻,所以 MC 的 variance 往往比较大。

贝尔曼方程(Bellman equation)

要了解TD,先看下TD算法的核心思想:贝尔曼方程

完整推导链路

\[ \begin{aligned} Q^\pi(s,a) &= \mathbb{E}_\pi\left[G_t \mid S_t=s, A_t=a\right] && \text{(definition)} \\[6pt] &= \mathbb{E}_\pi\left[R_{t+1}+\gamma G_{t+1} \mid S_t=s, A_t=a\right] && \text{(1)} \\[6pt] &= \mathbb{E}\left[R_{t+1}\mid S_t=s,A_t=a\right] + \gamma\mathbb{E}_\pi\left[G_{t+1}\mid S_t=s,A_t=a\right] && \text{(2)} \\[6pt] &= \sum_{s'\in\mathcal{S}}P(s'\mid s,a)R(s,a,s') + \gamma\sum_{s'\in\mathcal{S}}P(s'\mid s,a)V^\pi(s') && \text{(3)} \\[6pt] &= \sum_{s'\in\mathcal{S}}P(s'\mid s,a) \left[R(s,a,s')+\gamma V^\pi(s')\right] && \text{(4)} \end{aligned} \]

  1. 动作价值函数定义、
  2. 拆分回报、
  3. 期望的线性性质展开、
  4. 全期望公式与马尔可夫性
  5. 最后合并同类项。

步骤1:回报递归拆分

根据贝尔曼方程,把折扣回报 \(G_t\) 拆成「第1步即时奖励」和「第2步及以后的全部回报折扣值」 \[G_t = R_{t+1} + \gamma \cdot G_{t+1}\]


步骤2:期望线性性质

把条件期望拆成两个独立期望的和,折扣因子 \(\gamma\) 作为常数提出期望符号外。 \[ \mathbb{E}[X + cY \mid Z] = \mathbb{E}[X \mid Z] + c \cdot \mathbb{E}[Y \mid Z] \]

\[ \begin{aligned} \mathbb{E}\left[R_{t+1}\mid S_t=s,A_t=a\right] &= \sum_{s'\in\mathcal{S}} \underbrace{ \mathbb{E}\left[R_{t+1}\mid S_t=s,A_t=a,S_{t+1}=s'\right] }_{\text{到达下一状态后的奖励期望}} \\[4pt] &\qquad\cdot \underbrace{ P\left(S_{t+1}=s'\mid S_t=s,A_t=a\right) }_{\text{到达下一状态的概率}} \end{aligned} \]

说明:把整体期望拆成「即时奖励的期望」和「未来回报的期望」两部分,方便分别计算。


步骤3:全期望公式 + 马尔可夫性

这是最核心的一步,我们对步骤2得到的两个期望项分别套用全期望公式,引入下一状态 \(s'\) 展开求和。

全期望公式: 对于随机变量 \(X\) 和中间随机变量 \(Y\),有: \[ \mathbb{E}[X \mid Z] = \sum_{y} \mathbb{E}[X \mid Z,\ Y=y] \cdot P(Y=y \mid Z) \]

(通俗理解:要算整体期望,先枚举中间变量所有可能的取值,按每种取值的概率加权,再乘以该取值下的条件期望。)

这里我们取下一状态 \(S_{t+1}\) 作为中间变量,它服从转移概率 \(P(s'\mid s,a)=P(S_{t+1}=s'\mid S_t=s,A_t=a)\)


3.1 第一项:即时奖励的期望展开

原项:\(\boldsymbol{\mathbb{E}\left[R_{t+1}\mid S_t=s,A_t=a\right]}\)

套用全期望公式,引入下一状态 \(s'\) 展开: \[ \begin{aligned} \mathbb{E}\left[R_{t+1}\mid S_t=s,A_t=a\right] &= \sum_{s'\in\mathcal{S}} \underbrace{ \mathbb{E}\left[R_{t+1}\mid S_t=s,A_t=a,S_{t+1}=s'\right] }_{\text{到达下一状态后的奖励期望}} \\[4pt] &\qquad\cdot \underbrace{ P\left(S_{t+1}=s'\mid S_t=s,A_t=a\right) }_{\text{到达下一状态的概率}} \end{aligned} \]

化简依据:MDP中即时奖励的定义——奖励 \(R_{t+1}\) 完全由转移三元组 \((s,a,s')\) 决定。只要确定了“从 \(s\) 出发、执行动作 \(a\)、落到状态 \(s'\)”,奖励就是确定值 \(R(s,a,s')\),它的期望等于它本身: \[ \mathbb{E}\left[R_{t+1}\mid S_t=s,A_t=a,S_{t+1}=s'\right] = R(s,a,s') \]

将转移概率简记为 \(P(s'\mid s,a)\),代入后得到: \[ \mathbb{E}\left[R_{t+1}\mid S_t=s,A_t=a\right] = \sum_{s'\in\mathcal{S}}P(s'\mid s,a)R(s,a,s') \]


3.2 第二项:未来回报的期望展开

原项:\(\boldsymbol{\mathbb{E}_\pi\left[G_{t+1}\mid S_t=s,A_t=a\right]}\)

同样套用全期望公式,引入下一状态 \(s'\) 展开: \[ \mathbb{E}_\pi\left[G_{t+1}\mid S_t=s,A_t=a\right] = \sum_{s'\in\mathcal{S}} \mathbb{E}_\pi\left[G_{t+1}\mid S_t=s,A_t=a,S_{t+1}=s'\right] P(s'\mid s,a) \]

化简1:马尔可夫性 MDP的核心性质:给定当前状态 \(S_{t+1}=s'\),未来的所有过程(回报、动作、后续状态)都只和 \(s'\) 有关,和更早的历史(\(S_t=s, A_t=a\))完全无关。因此更早的条件可以消去: \[ \mathbb{E}_\pi\left[G_{t+1}\mid S_t=s,A_t=a,S_{t+1}=s'\right] = \mathbb{E}_\pi\left[G_{t+1}\mid S_{t+1}=s'\right] \]

化简2:状态价值函数的定义 \(V^\pi(s')\) 的定义就是:在状态 \(s'\) 下,全程遵循策略 \(\pi\) 能获得的期望折扣回报,即: \[ V^\pi(s') = \mathbb{E}_\pi\left[ G_{t+1} \mid S_{t+1}=s' \right] \]

代入后得到: \[ \mathbb{E}_\pi\left[G_{t+1}\mid S_t=s,A_t=a\right] = \sum_{s'\in\mathcal{S}}P(s'\mid s,a)V^\pi(s') \]


步骤4:合并整理

变换:提取两项共同的状态转移概率 \(P(s'\mid s,a)\),把求和合并。 依据:乘法分配律。 结果:得到最终的贝尔曼期望方程紧凑形式: \[ Q^\pi(s,a) = \sum_{s'\in\mathcal{S}}P(s'\mid s,a) \left[R(s,a,s')+\gamma V^\pi(s')\right] \]

贝尔曼方程,贝尔曼期望方程与贝尔曼最优方程(区分一下)

贝尔曼方程的核心是把 return 拆成当前 reward 和下一时刻的 return (而这里的return又可以用V来表示)那么问题就被转换成是否能找到一个好的(state)Value function,对于下一个state给出准确的最终回报估计

\[ U_t = R_t + \gamma U_{t+1} \]

对当前 state 和 policy 取期望,就得到 Bellman expectation equation

\[ V^\pi(s) = \sum_a \pi(a \mid s)\sum_{s'}P(s' \mid s,a) \left[r(s,a,s') + \gamma V^\pi(s')\right] \]

它表达的是:当前 state 的价值,等于当前 action 得到的 immediate reward,加上下一 state 的价值,再对 policy 和 state transition 的随机性取平均。

对应的 action-value 形式是:

\[ Q^\pi(s,a) = \sum_{s'}p(s' \mid s,a) \left[r(s,a,s') + \gamma\sum_{a'}\pi(a' \mid s')Q^\pi(s',a')\right] \]

这两个式子用于 policy evaluation:policy \(\pi\) 已经给定,目标是计算它的 \(V^\pi\)\(Q^\pi\)

如果目标不是评估一个固定 policy,而是直接寻找最优策略,就得到 Bellman optimality equation

\[ V^*(s) = \max_a \sum_{s'}p(s' \mid s,a) \left[r(s,a,s') + \gamma V^*(s')\right] \]

\[ Q^*(s,a) = \sum_{s'}p(s' \mid s,a) \left[r(s,a,s') + \gamma\max_{a'}Q^*(s',a')\right] \]

这里的 \(\max\) 体现了最优 action 选择,而 Bellman expectation equation 里的 \(\pi(a \mid s)\) 体现的是按照给定 policy 采样 action。

单步 TD:走一步就能更新

回到return估计环节, 时序差分方法和蒙特卡洛的相似之处在于可以从样本数据中学习,不需要事先知道环境;和动态规划的相似之处在于根据贝尔曼方程的思想,利用后续状态的价值估计来更新当前状态的价值估计。

不需要等整条 trajectory 结束。单步 TD 只使用当前 transition:

  1. 执行 action,得到即时 reward \(r_t\) 和下一状态 \(s_{t+1}\)
  2. 用当前 value function 估计未来价值。
  3. 立刻计算 TD error,并更新 critic,甚至可以用它更新 actor。

\[ \delta_t^V = r_t + \gamma V(s_{t+1}) - V(s_t) \]

这里的 \(V(s_{t+1})\) 不是完整的真实 return,而是当前 value function 对未来的估计,所以单步 TD 可以在线更新,但会引入 bootstrap bias。它只看一步真实 reward,后面的结果完全依赖 value estimate,方差通常较低,但偏差可能比较大。

Sarsa和Q learning都是TD算法的后续研究,有时间的话我再补充下细节吧。

广义优势估计(GAE)

PPO 中常用的 GAE(Generalized Advantage Estimation)是一种介于MC和单步TD之间的估计 advantage 的方法。它先计算每一步的 TD error,再把未来多个时间步的 TD error 做指数加权:

\[ A_t^{\mathrm{GAE}(\gamma,\lambda)} = \sum_{l=0}^{\infty}(\gamma\lambda)^l\delta_{t+l}^V \]

其中:

  • \(\gamma\) 控制未来 reward 的折扣;
  • \(\lambda\) 控制 GAE 向多步 return 延伸的程度;
  • \(\delta_t^V\) 是当前时刻的 TD error。

在有限长度的 rollout 中,实际计算会在轨迹片段末尾截断:

\[ \hat A_t = \delta_t^V + \gamma\lambda\hat A_{t+1} \]

从最后一个时间步开始反向递推即可。若最后状态不是 terminal state,就用 value function 对下一状态进行 bootstrap:

\[ \delta_{H-1}^V = r_{H-1} + \gamma V(s_H) - V(s_{H-1}) \]

如果最后状态确实是 terminal state,则终止状态之后没有未来 reward,通常令 bootstrap value 为 0。

实际实现中通常用 \(d_t\) 区分 terminal 和 rollout truncation:真正结束时 \(d_t=1\),只是达到固定采样长度时 \(d_t=0\)。于是 TD error 可以统一写成:

\[ \delta_t^V = r_t + \gamma(1-d_t)V(s_{t+1}) - V(s_t) \]

这样,固定长度截断仍然保留 \(V(s_{t+1})\) 的 bootstrap;只有 episode 真正结束时才移除未来价值。

GAE 的定位可以这样理解:

  • \(\lambda=0\) 时,只保留当前一步 TD error,接近单步 TD;
  • \(\lambda\) 接近 1 时,会融合更长范围的 TD error,接近 Monte Carlo;
  • 中间的 \(\lambda\) 用来平衡 bias 和 variance。

所以 GAE 不能做到“刚走一步就算出完整的 \(A_t\)”。\(A_t\) 依赖后面多个时间步的 TD error,至少要等一段 rollout 收集完之后才能反向计算。但它也不需要等完整 episode 结束:只要收集固定长度的轨迹片段,就可以在片段末尾用 \(V(s_H)\) 自举。

实际实现会从 rollout 的最后一步反向递推。valuesrewards 多一个元素,其中最后的 values[-1] 是 rollout 被截断时使用的 bootstrap value:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
import numpy as np

def compute_gae(rewards, values, dones, gamma=0.99, gae_lambda=0.95):
"""
rewards: [T]
values: [T + 1],包含最后状态的 bootstrap value
dones: [T],真正 terminal 的位置为 1,普通 rollout 截断为 0
"""
advantages = np.zeros_like(rewards, dtype=np.float32)
next_advantage = 0.0

for t in reversed(range(len(rewards))):
not_terminal = 1.0 - dones[t]
delta = (
rewards[t]
+ gamma * not_terminal * values[t + 1]
- values[t]
)
next_advantage = (
delta
+ gamma * gae_lambda * not_terminal * next_advantage
)
advantages[t] = next_advantage

returns = advantages + values[:-1]
return advantages, returns

如果最后一步只是达到固定 rollout 长度,dones[-1]=0,代码会保留 values[-1];如果 episode 真正结束,dones[-1]=1,未来 value 和 advantage 都会在这里截断。

方法 target 从哪里来 是否需要等 episode 结束 典型特点
DP 对已知环境模型中的全部转移求期望 不需要 无采样噪声,但需要模型并遍历状态空间
Monte Carlo 完整 trajectory 的实际 return \(G_t\) 需要 无 bootstrap,方差较大
单步 TD \(r_t + \gamma V(s_{t+1})\) 不需要 可以在线更新,但 bootstrap bias 较大
GAE 多个 TD error 的指数加权和 不需要等完整 episode,但要等一段 rollout 属于多步 TD 思路,用 \(\lambda\) 平衡 bias 和 variance

Actor-critic 方法通常正是用 critic 估计 value,再用 GAE 产生 advantage,给 actor 提供更新方向。

语言模型里的 policy 是什么

在 RL 里,policy 通常写成:

\[ \pi_\theta(a \mid s) \]

它表示在状态 \(s\) 下采取动作 \(a\) 的概率。

放到语言模型里,可以这样对应:

  • 状态(state):当前 prompt 加上已经生成的 tokens
  • 动作(action):下一个 token
  • policy:语言模型给下一个 token 的概率分布

如果把完整回答看成一个 token 序列:

\[ y = (y_1, y_2, ..., y_T) \]

那么模型生成这个回答的概率是:

\[ \pi_\theta(y \mid x) = \prod_{t=1}^{T} \pi_\theta(y_t \mid x, y_{<t}) \]

其中 \(x\) 是 prompt。

这也是为什么很多后训练算法会用 log probability:

\[ \log \pi_\theta(y \mid x) = \sum_{t=1}^{T} \log \pi_\theta(y_t \mid x, y_{<t}) \]

因为整段 response 的概率是 token 概率连乘,直接乘容易数值很小,取 log 后就变成求和。

LLM里的Reward

Reward 可以来自很多地方。

在人类偏好场景里,reward 可能来自 reward model:

\[ r_\phi(x, y) \]

它输入 prompt 和 response,输出一个标量分数。

在 reasoning / coding 场景里,reward 经常是 verifiable reward:

  • 数学题最终答案是否匹配
  • 代码是否通过单元测试
  • 格式是否满足要求
  • 工具调用是否成功

这类方法常被叫做 RLVR,也就是 reinforcement learning from verifiable rewards。

RLVR 的优势是 reward 更客观,不需要每个样本都人工标注偏好。

但它也有明显局限:reward 很稀疏。一个数学题只有最终答案对/错,模型并不知道中间哪一步推理值得奖励。

这也是为什么 reasoning model 训练里经常会关心:

  • 如何采样更多候选
  • 如何过滤高质量 reasoning traces
  • 如何避免只学会猜答案
  • 如何让 reward 不只看最终答案

KL constraint:限制模型更新幅度

后训练里通常会保留一个 reference model,记作 \(\pi_{\mathrm{ref}}\)

它通常是 SFT 后的模型,或者训练开始前的 policy snapshot。

更新 policy 时,会惩罚当前模型和 reference model 的差异:

\[ D_{KL}(\pi_\theta || \pi_{\mathrm{ref}}) \]

直觉上,KL constraint 在说:

可以朝高 reward 方向走,但不要走到完全不像原来的模型。

没有 KL 约束会有什么问题?

模型可能为了骗 reward model 生成奇怪模式。比如 reward model 偏好长回答,模型就越来越啰嗦;reward model 偏好自信语气,模型就更容易胡说;verifier 只看最终答案,模型可能学会投机格式。

所以后训练不是简单最大化 reward,而是:

\[ \max_\theta \mathbb{E}[r(x,y)] - \beta D_{KL}(\pi_\theta || \pi_{\mathrm{ref}}) \]

这里 \(\beta\) 控制 reward 优化和保持原模型分布之间的平衡。

On-policy 和 off-policy

On-policy 指训练数据来自当前 policy。

Off-policy 指训练数据来自旧 policy、其他模型,或者离线数据集。

LLM 后训练里,这个区别非常关键。

如果模型训练时看到的是自己当前会生成的回答,那训练分布和推理分布更接近。这是 on-policy 的优势。

但 on-policy 代价高,因为训练过程中要不断采样新 responses。

Off-policy 成本低,可以直接用已有数据训练。但如果数据分布和当前模型差很多,模型学到的更新可能不稳定。

这就是为什么 PPO / GRPO / OPD 都强调 on-policy 或接近 on-policy。它们希望模型在自己的生成分布上学习,而不是只模仿静态数据。

为什么 reasoning model 更依赖 RL:RL 和 SFT 的本质区别

我觉得应该这么理解,虽然SFT 可以让模型学会解题格式,但它本质上是模仿。 而在reasoning问题上,潜在的解题方式有很多,比如1+1=2可以通过一堆不一样的复杂公式来给出同样的结果,这种情况下的action space太大了,只靠SFT是模仿不完的。所以需要用RL来自己探索。

比如 RLVR 可以直接优化最终正确率。同一个数学题,模型生成多个答案,只有正确答案拿到 reward。经过训练,模型会提高能够得到正确答案的生成轨迹概率。只要合理设置 reward(比如答案是否正确、输出长度、步骤数等),就可以让模型自己探索解题空间。

这也是 DeepSeek-R1 这类 reasoning model 重要的地方:它不是只靠人工写好的 CoT,而是通过可验证 reward 强化推理行为。

不过这也带来风险。

如果 reward 只看最终答案,模型可能学到短路策略。比如中间推理不可靠,但答案格式正确;或者生成更长 reasoning 来提高偶然命中率。

后训练里的几个常见失败模式

第一,reward hacking。

典中典问题,模型学会利用 reward 的漏洞,靠作弊来拿分。

“Learning to Summarize with Human Feedback” (OpenAI) 在 RLHF 训练摘要模型时,明确观察到模型学会利用 reward model 的偏差。

第二,entropy collapse。

熵塌陷,模型输出变得单一,更倾向于高概率的token,而缺少对低概率token的探索,导致模型可能会陷入local minimum,达不到最优值。

第三,length inflation/hacking。

收到长度奖励的影响,模型生成越来越长,因为长回答更容易看起来努力,或者更容易覆盖答案。

第四,over-optimization。

训练集 reward 越来越高,但真实评估变差。

“Scaling Laws for Reward Model Overoptimization” (Anthropic) 定量研究了 reward model score 持续升高而真实人类偏好评分反而下降的现象,提出了 over-optimization 的标度律。

Goodhart’s Law: “当某个度量变成目标时,它就不再是一个好的度量。”

第五,distribution drift。

policy 离 reference model 太远,语言能力或安全边界受损。

小结

RL基础,回答几个问题 1. RL的基本概念定义有些什么/MDP五元组有些什么 2. 随机性来源于什么地方呢 3. 两个价值函数代表什么意义 4. 对于估计回报,有些什么方式?(Q,V函数又是如何得到的呢) 5. 贝尔曼期望方程的公式和推导

参考资料