强化学习里的 RLHF(Reinforcement Learning from Human Feedback)是让大模型对齐人类偏好的核心路线,而 REINFORCE 算法又是这条路线里几乎所有策略优化方法的起点。这篇文章想做的事情很明确:把 REINFORCE 的数学公式一步一步拆开,说明白它为什么能用“采样轨迹”来估计策略梯度,再把它放到 RLHF 的完整流程里看它承担什么角色。适合刚接触强化学习的人,也适合已经跑过 PPO 但想回头补基础的人。
推导过程只用到概率论里最基本的链式法则和期望求导交换,我会把每一步怎么来的都写出来。全文按“先理解任务,再统一符号,再推导,再落地,最后排错”的顺序走,这样你拿到的不只是一个公式,而是一套能迁移到其他策略梯度方法的思考方式。
1. 先用一个生成任务想清楚 RLHF 在优化哪个环节
1.1 从 SFT 到奖励模型:三个阶段依次解决什么问题
RLHF 不是单个算法,而是一条流水线。最常见的拆法是三段:
- 第一阶段:SFT(Supervised Fine-Tuning),用人工标注的高质量问答数据微调预训练模型,让模型先学会“像人一样说话”。
- 第二阶段:训练奖励模型,让模型对同一个问题的多个回答打分,学习“哪种回答更符合人类偏好”。
- 第三阶段:用强化学习优化策略模型,让模型在生成回答时倾向于拿到更高的奖励分数。
REINFORCE 出现在第三阶段。它做的事可以概括成一句话:给定一个提示词,让当前策略模型生成一段回答,用奖励模型给这段回答打分,然后根据分数调整策略参数。分数高就增加这段回答的生成概率,分数低就降低这段回答的生成概率。
听起来很像“简单重复好行为”,但它真正的难点在于:生成回答这个过程是离散采样,不是连续可微函数。你没法直接对“采样”求导,必须借助策略梯度绕过去。
1.2 策略模型在 RLHF 阶段被反复采样更新
很多人第一次看 RLHF 会觉得奇怪:为什么要反复让模型生成回答?直接拿奖励模型当损失函数微调不就行了吗?
问题在于奖励模型的输出只对“已经生成出来的文本”有意义。你要知道模型生成某个词的概率是高是低,更新参数后模型重新生成会不会更好,这些都需要反复采样。每一次采样都是一次“试探”,每一次试探都会留下一条轨迹,REINFORCE 就是把这些轨迹变成梯度信号的数学工具。
所以在实际项目里,RLHF 阶段的显存占用、计算量都明显高于普通微调。原因不是模型本身变大了,而是你要同时跑策略模型、奖励模型、参考模型,还要维护一批生成样本。先把这点记在心里,后面落地步骤会反复用到。
2. 统一符号:先搞清楚 REINFORCE 在优化什么
2.1 轨迹、状态、动作:定义要提前对齐
推导公式前,符号必须统一。RLHF 里的“动作”和普通强化学习里的动作含义不完全一样,但数学形式是一致的。
我用下面这套记号:
- $s_t$:状态,泛指模型当前所处的上下文。在 RLHF 里,通常把提示词和已经生成的前缀文本合并看成状态。
- $a_t$:动作,指模型在时间步 $t$ 生成的一个 token。
- $\pi_\theta(a_t|s_t)$:带参数 $\theta$ 的策略模型,表示在状态 $s_t$ 下生成动作 $a_t$ 的概率。
- $\tau = (s_0, a_0, s_1, a_1, \dots, s_T)$:一条完整轨迹,也就是从第一个 token 生成到结束符的完整序列。
- $R(\tau)$:整条轨迹的累积奖励。在 RLHF 里,$R(\tau)$ 就是奖励模型给整段回答打的总分。
- $p(s_{t+1}|s_t, a_t)$:环境转移概率。文本生成任务里,这个转移几乎是确定的:生成一个 token 后,新状态就是原来的上下文加上这个 token。
这里要强调:REINFORCE 是 on-policy 算法,意思是更新参数用的样本必须来自当前策略。如果用的生成样本是旧模型产出的,就属于 off-policy,需要额外处理,否则梯度估计是有偏的。
2.2 目标函数:期望奖励为什么不能直接求导
REINFORCE 的优化目标很简单:
$$J(\theta) = \mathbb{E}{\tau \sim \pi\theta(\tau)}[R(\tau)]$$
展开成积分形式:
$$J(\theta) = \int \pi_\theta(\tau) R(\tau) , d\tau$$
这里的 $\pi_\theta(\tau)$ 是整条轨迹的概率:
$$\pi_\theta(\tau) = p(s_0) \prod_{t=0}^{T-1} \pi_\theta(a_t|s_t) p(s_{t+1}|s_t, a_t)$$
问题就在这里:目标函数里含有期望,而期望是通过采样得到的。你手里只有一批从 $\pi_\theta$ 采样出来的轨迹样本,没有解析的积分表达式。直接对 $J(\theta)$ 求 $\theta$ 的导数,没法把期望符号和求导符号直接交换,因为被积函数里的 $\pi_\theta(\tau)$ 和 $R(\tau)$ 都跟采样过程纠缠在一起。
解决办法就是接下来要讲的 log 技巧。
3. 数学公式推导:从期望到策略梯度的完整过程
3.1 log 技巧:核心的一步换元
对 $\nabla_\theta J(\theta)$ 做展开:
$$\nabla_\theta J(\theta) = \int \nabla_\theta \pi_\theta(\tau) R(\tau) , d\tau$$
现在 $\nabla_\theta \pi_\theta(\tau)$ 不能直接算,因为 $\pi_\theta(\tau)$ 是多项概率的连乘。这时候用对数求导的恒等式:
$$\nabla_\theta \pi_\theta(\tau) = \pi_\theta(\tau) \nabla_\theta \log \pi_\theta(\tau)$$
代入回去:
$$\nabla_\theta J(\theta) = \int \pi_\theta(\tau) \nabla_\theta \log \pi_\theta(\tau) R(\tau) , d\tau$$
写成期望形式:
$$\nabla_\theta J(\theta) = \mathbb{E}{\tau \sim \pi\theta(\tau)}[\nabla_\theta \log \pi_\theta(\tau) R(\tau)]$$
这一步就是 REINFORCE 的数学基础。它把一个“不知道期望怎么求导”的问题,变成了“采样后统计 $\nabla_\theta \log \pi_\theta(\tau) R(\tau)$ 的均值”的问题。只要你能从策略模型里采样轨迹,就能用这批样本估计梯度。
这里要提醒:$\log$ 技巧不是法术,它没有改变梯度的真实值,只是把 $\pi_\theta(\tau)$ 从分母挪到了采样分布的位置。换一种等价写法,梯度估计仍然成立,但数值稳定性和方差特性会不一样,后面会专门讲方差。
3.2 从轨迹概率到每一步动作的概率
现在处理 $\nabla_\theta \log \pi_\theta(\tau)$。把轨迹概率的连乘形式取对数,连乘变成连加:
$$\log \pi_\theta(\tau) = \log p(s_0) + \sum_{t=0}^{T-1} \left[ \log \pi_\theta(a_t|s_t) + \log p(s_{t+1}|s_t, a_t) \right]$$
对 $\theta$ 求导时,$p(s_0)$ 和 $p(s_{t+1}|s_t, a_t)$ 都不含参数 $\theta$,导数直接消掉。于是:
$$\nabla_\theta \log \pi_\theta(\tau) = \sum_{t=0}^{T-1} \nabla_\theta \log \pi_\theta(a_t|s_t)$$
这个结果很关键:整条轨迹的梯度,等于轨迹上每个 token 的“对数概率梯度”相加。也就是说,优化策略模型时,每个生成过的 token 都会贡献一份梯度,贡献大小由整条轨迹的奖励 $R(\tau)$ 统一加权。
代入梯度期望:
$$\nabla_\theta J(\theta) = \mathbb{E}{\tau \sim \pi\theta(\tau)}\left[\sum_{t=0}^{T-1} \nabla_\theta \log \pi_\theta(a_t|s_t) R(\tau)\right]$$
3.3 蒙特卡洛估计和参数更新公式
实际训练时没有期望的解析形式,只能用 $N$ 条采样轨迹做蒙特卡洛估计:
$$\nabla_\theta J(\theta) \approx \frac{1}{N} \sum_{i=1}^{N} \sum_{t=0}^{T-1} \nabla_\theta \log \pi_\theta(a_t^{(i)}|s_t^{(i)}) R(\tau^{(i)})$$
参数更新:
$$\theta \leftarrow \theta + \alpha \nabla_\theta J(\theta)$$
其中 $\alpha$ 是学习率。这就是 REINFORCE 最原始的更新公式。
如果按“因果性”改进,可以把整条轨迹的奖励 $R(\tau)$ 换成从时刻 $t$ 开始的折扣回报 $G_t$:
$$G_t = \sum_{k=0}^{T-t} \gamma^k r_{t+k}$$
于是逐时间步的更新形式变成:
$$\theta \leftarrow \theta + \alpha \sum_{t=0}^{T-1} G_t \nabla_\theta \log \pi_\theta(a_t|s_t)$$
为什么要换成 $G_t$?因为时刻 $t$ 之前已经生成的动作,不应该被 $t$ 之后的回报“回溯奖励”。这个因果性改进能降低一部分方差,也是 REINFORCE 变体里最常见的一版。
4. 回到 RLHF:REINFORCE 的落地流程与代码思路
4.1 RLHF 里的输入、输出和奖励来源
把上面的通用框架映射到 RLHF,每一环的细节都要对应清楚:
| 强化学习概念 | RLHF 里的对应物 | 说明 |
|---|---|---|
| 状态 $s_t$ | 提示词 + 已生成前缀 | 通常由模型内部维护 |
| 动作 $a_t$ | 生成的单个 token | 离散动作空间,即词表 |
| 策略 $\pi_\theta$ | 正在微调的语言模型 | 生成概率来自 softmax |
| 奖励 $r_t$ | 奖励模型对整段回答的打分 | 可以每个 token 都填总分,也可以只在末尾给分 |
| 轨迹 $\tau$ | 一段完整回答 | 从提示词到生成结束符 |
在 RLHF 里,最朴素的做法是:生成完一整段回答后,奖励模型给一个总分 $r$,然后把 $r$ 当作轨迹上每个 token 的共享奖励。这样 $R(\tau)$ 就是 $r$,$G_t$ 也简化成 $r$(不考虑折扣时)。这种叫“稀疏奖励”,实现简单,但每个 token 都分到同一个奖励,梯度方差会偏大。
更精细的做法是给每个 token 分配不同的奖励,例如在末尾位置加权、或者按 token 级别训练奖励模型。但很多项目实际跑 RLHF 时,还是会先退回整段打分,因为 token 级奖励模型训练成本高、收益不一定明显。
4.2 一次迭代的最小伪代码
用伪代码把一次 RLHF 策略更新写清楚:
输入:策略模型 π_θ,奖励模型 r_φ,提示词数据集 D,学习率 α 1. 从 D 中采样一个 batch 的提示词 x 2. 用当前策略 π_θ 对每个 x 采样一段回答 y y ~ π_θ(·|x) 3. 用奖励模型打分:r = r_φ(x, y) 4. 计算每个 token 的对数概率 log π_θ(a_t | x, y_<t) 5. 计算梯度: grad = (1 / (N * T)) * Σ_i Σ_t ∇_θ log π_θ(a_t | x_i, y_{<t}) * r_i 6. 更新参数:θ ← θ + α * grad 7. 回到第 1 步,直到奖励稳定第 5 步是 REINFORCE 的核心,也是很多新手写错的地方。常见错误是把整段回答当成一个动作直接求 log prob,或者忘记了生成 y 时要用 stop-gradient 的旧策略采样,更新时又要用当前策略计算 log prob。这两者必须使用同一份参数吗?理论上是,但实际实现中会因为梯度回传路径不同而出现偏差。
写代码时要注意:
- 记录生成时的 log prob 和更新时的 log prob,两个值要能对得上。
- 奖励值先做标准化,例如减均值除标准差,能让训练稳定很多。
- 不要直接更新完整参数,先跑一个小 batch 验证 loss 数值是否在合理范围。
4.3 为什么真实 RLHF 项目里更常看到 PPO
说到这里可能有人会问:既然 REINFORCE 推导这么干净,为什么主流的 RLHF 框架用的都是 PPO?
核心原因是 REINFORCE 的梯度方差太大。纯 REINFORCE 用整条轨迹的累计奖励去加权所有 token 的梯度,一条回答里可能只有末尾一个地方出了问题,但整条轨迹的奖励都变了。这会导致同一批样本里梯度方向差异很大,训练曲线跳来跳去,学习率稍大一点就崩。
PPO 在 REINFORCE 之上做了三件事:
- 引入重要性采样,允许用旧策略采样,提高样本利用率。
- 用 clip 操作限制新旧策略的更新幅度,防止一步更新过大。
- 用 advantage 代替原始奖励,配合 critic 网络降低方差。
所以你可以把 PPO 理解为“REINFORCE 的工程增强版”。REINFORCE 是底层的策略梯度估计器,PPO 是加了稳定性措施的同一个思想。理解 REINFORCE 之后再看 PPO,会顺很多,因为 PPO 的目标函数里依然存在 $\nabla_\theta \log \pi_\theta(a_t|s_t)$ 这个核心项。
5. 方差、基线函数与训练不稳定的排查手势
5.1 为什么方差大,基线为什么有用
REINFORCE 的梯度估计有一个明显问题:不同轨迹的奖励 $R(\tau)$ 可能差异很大。有的回答质量高,奖励是 2;有的回答跑题,奖励是 -1。直接用这些原始奖励加权梯度,相当于让每一次采样都带一个很大的随机噪声。
解决办法之一是引入基线 $b(s_t)$,把梯度改成:
$$\nabla_\theta J(\theta) = \mathbb{E}\left[\sum_{t=0}^{T-1} \nabla_\theta \log \pi_\theta(a_t|s_t) \left(G_t - b(s_t)\right)\right]$$
基线的作用是让加权项从“绝对回报”变成“相对优势”。奖励高不意味着这个动作就好,要看它比“平均情况下的期望奖励”高多少。$b(s_t)$ 通常取状态值的估计,或者直接用当前 batch 的奖励均值。
为什么减基线不改变梯度的期望?因为:
$$\mathbb{E}\left[\nabla_\theta \log \pi_\theta(a_t|s_t) b(s_t)\right] = \int \nabla_\theta \pi_\theta(a_t|s_t) b(s_t) , da_t = b(s_t) \nabla_\theta \int \pi_\theta(a_t|s_t) , da_t = 0$$
积分结果为 1,对常数求导为 0。所以基线只改变方差,不改变梯度期望。这个性质是策略梯度方法里最漂亮也最实用的结论之一。
5.2 训练不稳定的排查顺序
如果 RLHF 训练时奖励长期不涨、或者 loss 直接变成 NaN,建议按下面顺序排查:
- 先看奖励分布。奖励模型给出的分数是否分布太集中?集中到 0 附近时梯度信号太弱。
- 再看 log prob。生成回答里是否出现大量重复 token,导致某些 token 的 log prob 异常小。
- 然后看学习率。REINFORCE 类方法对学习率非常敏感,建议从 1e-6 到 1e-5 这个量级起步,对比几次再确定。
- 接着看 batch size。batch 太小,蒙特卡洛估计噪声大;batch 太大,显存不够。先跑 8 条轨迹看梯度方向是否稳定。
- 看是否用了参考模型和 KL 惩罚。RLHF 场景里,策略模型和 SFT 模型差距过大会导致回答格式崩坏,所以通常会加 KL 惩罚项。
- 最后看奖励是否被 hack。模型可能学会了输出很长但内容空洞的回答来骗取高分。如果奖励不断上升但回答质量明显下降,优先检查奖励模型和 KL 权重。
5.3 新手最容易踩的几个坑
第一个坑是忘了 stop-gradient。生成回答时,模型在采样;计算梯度时,模型在反向传播。这两个阶段的模型参数必须是同一个,但生成阶段不能把采样路径的梯度传回去。实现时一般把采样的 log prob 和更新时的 log prob 分开记录。
第二个坑是符号方向搞错。梯度上升还是梯度下降取决于框架习惯。PyTorch 的 optimizer.step() 默认做梯度下降,所以要把策略梯度目标写成负值,或者手动对损失取负号。很多人第一次跑通发现奖励越来越低,多半是这个原因。
第三个坑是奖励没有归一化。不同提示词的奖励尺度可能差很多,比如长回答的分数天然偏高,短回答偏低。直接把原始奖励拿来加权梯度,更新会被长回答主导。建议每个 batch 内做一次标准化。
第四个坑是忽略 KL 惩罚。纯 REINFORCE 不加约束时,模型会快速走向奖励模型的弱点区域。一般会把目标改成:
$$\nabla_\theta J(\theta) = \mathbb{E}\left[\sum_t \nabla_\theta \log \pi_\theta(a_t|s_t) \left(r(x, y) - \beta \log \frac{\pi_\theta(y|x)}{\pi_{\text{ref}}(y|x)}\right)\right]$$
其中 $\pi_{\text{ref}}$ 是 SFT 阶段的参考模型,$\beta$ 控制偏离程度。这样既能优化奖励,又不会让模型跑得太远。这个 KL 项在实际 RLHF 工程里几乎必加。
6. 从 REINFORCE 出发还能往哪走
REINFORCE 不是终点,但它是一把钥匙。理解了它的推导,后面的策略梯度家族都会好懂很多:
- Actor-Critic:用 critic 网络估计状态值,替代简单基线,进一步降低方差。
- PPO:在策略梯度上加重要性采样和 clip,让更新更稳。
- GAE(广义优势估计):用多步 TD 折中偏差和方差,是现代强化学习的标配组件。
- DPO(Direct Preference Optimization):直接绕开显式奖励模型,用偏好数据优化策略,但其推导里依然有“对数概率差”和“隐式奖励”的影子。
如果你现在是在学习阶段,建议亲手做一个最小的文本生成实验:用一个小模型、几组提示词,把 REINFORCE 更新跑通,打印每个 token 的 log prob、gradient norm 和奖励值。这样比直接加载一个大型 RLHF 框架更能理解内部机制。等你能预测某一步梯度变化大概会带来什么效果时,再上 PPO 或者接入完整 RLHF 管线,会从容很多。
最后留几个我自己排查时会优先看的点:训练曲线的奖励是否与人工评估一致,KL 惩罚项是否失控,采样回答的平均长度是否有突变,以及模型是否开始出现重复或空洞的套话。这些信号比 loss 数值本身更能说明问题。真正的 RLHF 工程,不只是调好一个公式,而是要把采样、奖励、KL、日志和人工抽检整条链路都管住。