RL 学习笔记 #11 PPO 在 RLHF 中的应用

本文最后更新于:2025年3月4日 晚上

在前面的章节中,我们介绍了通用的 RL 流程和基本概念,这些内容通常应用于游戏、机器人控制等序列决策任务。但随着大型语言模型(LLM)的发展,RL 在自然语言任务中的作用变得越来越重要。

那么,如何将强化学习的框架映射到 NLP 任务中呢?我们可以将强化学习的核心元素(MDP 序列决策)与文本生成任务中的组件对应起来:

  • 智能体(Agent):对应于语言模型,负责生成文本序列。
  • 环境(Environment):代表外部的反馈机制,例如人类用户的互动反馈。
  • 回合(Episode):始于输入文本,结束于模型输出文本的 EOS_token。
  • 状态(State, \(s_t\)):是当前的文本 Context,包括输入和已经生成的 Token 序列。
  • 动作(Action, \(a_t\)):是在给定状态下选择生成下一个 Token,通常会从词表中选择。
  • 奖励(Reward, \(r_t\)):反映生成文本的质量(序列级或 Token 级),由环境提供,用于指导模型的学习。

自 2023 年以来,基于人类反馈的强化学习(Reinforcement Learning from Human Feedback,RLHF)在 LLM 领域逐渐成为研究热点。RLHF 的核心思想是通过人类反馈来指导模型的学习过程,使其生成的文本更加符合人类的期望和价值观。

与传统的监督学习(SFT)不同,RLHF 通过训练一个奖励模型(Reward Model)来量化人类的偏好,并使用强化学习算法(如 PPO)来优化策略模型(Policy Model)。这种方法的优势在于能够处理复杂、多样的反馈信号,并在生成过程中动态调整策略,从而生成更符合人类期望的文本。接下来,我们将对 RLHF-PPO 算法进行详细介绍。

RLHF-PPO 中的四个模型

在 RLHF 的训练过程中,涉及到四个模型的协同工作:策略模型、参考模型、价值模型、奖励模型。这四个模型各自承担不同的角色,一起实现策略的优化:

  • 策略模型(Policy Model):即 Actor Model,用于生成文本,并根据奖励信号不断优化;
  • 参考模型(Reference Model):文本任务特有的模型,使用 SFT 模型初始化,防止其过度偏离初始点;
  • 奖励模型(Reward Model):文本任务特有的模型,衡量整个序列的人类偏好,并分配到每个 Token 上;
  • 价值模型(Value Model):即 Critic model,与配合 Reward 来估计优势和回报,从而引导策略更新。

PPO 的完整工作流程如下:

PPO 工作流

策略模型 | Policy Model

策略模型的基本用法与经典 PPO 中的 Actor 类似,需要注意的是,在 RLHF 中,它一般使用预训练语言模型的 SFT 后的版本初始化。其目标是通过生成符合人类偏好的文本来获得更高的奖励。

与经典 PPO 类似,直接优化策略模型可能会导致策略崩溃(Policy Collapse),即模型过度优化某些特定的生成模式来骗取奖励,导致生成的文本缺乏多样性甚至出现乱码。为此,RLHF 中也会使用 KL 散度来限制策略模型的更新幅度。但此时我们不会直接使用 PPO-Penalty 作为优化目标,而是使用 Refernce Model 计算完 KL 散度后直接与 Reward 结合\[ r_{\text {total }}=r(x, y)-\eta \mathrm{KL}\left(\pi_\theta^{\mathrm{RL}}(y \mid x) \parallel \pi^{\mathrm{SFT}}(y \mid x)\right) \] 其中,\(r(x, y)\) 是奖励模型给出的 Reward,\(\eta\) 是 KL 散度的惩罚系数。通过引入惩罚,策略模型在优化过程中不仅会追求更高的奖励,还会尽量保持与参考模型的生成行为一致,从而避免策略崩溃。

为了有效地计算策略模型与参考模型之间的 KL 散度,我们可以从对数概率(log_prob)的角度来实现这一过程: \[ \mathrm{KL}\left(\pi_\theta^{\mathrm{RL}}(y \mid x) \parallel \pi^{\mathrm{SFT}}(y \mid x)\right) = \sum_{t} \left( \log \pi_\theta^{\mathrm{RL}}(y_t \mid x, y_{<t}) - \log \pi^{\mathrm{SFT}}(y_t \mid x, y_{<t}) \right) \] 具体步骤如下:

  1. 使用策略模型进行采样:对输入 \(x\) 生成的输出 \(y\)
  2. 计算策略模型的对数概率(log_probs):计算策略模型在每个时间步(Token)的对数概率。
  3. 计算参考模型的对数概率(ref_log_probs):对相同的输入输出,使用参考模型计算逐 Token 的对数概率。
  4. 计算 KL 散度:通过对数概率之差累加得到策略模型与参考模型之间的 KL 散度。
  5. 整合奖励:Token 级的 KL 散度与奖励模型在输出 \(y\) 上序列级 Reward 组合,得到 \(r_{\text {total}}\)

参考模型 | Reference Model

参考模型在 RLHF 中扮演着「锚点」的角色,同样使用预训练语言模型的 SFT 后的版本初始化,并且全程冻结参数不更新。参考模型只在采样经验后计算 log_prob 时用到。

初学者可能会误认为参考模型就是经典 PPO 中的 \(\pi_{\theta_{\mathrm{old}}}^{\mathrm{RL}}\),但实际上 \(\pi_{\theta_{\mathrm{old}}}^{\mathrm{RL}}\) 只是相对不断更新的 \(\pi_\theta^{\mathrm{RL}}\) 的一个延迟拷贝(甚至不需要显式拷贝,只需要用 \(\pi_\theta^{\mathrm{RL}}\) 采样经验、计算 log_prob 后就可以放任其更新)。

奖励模型 | Reward Model

奖励模型是负责量化人类对生成文本的偏好。在传统 RL 任务中,奖励代表环境对于每个状态-动作对的即时反馈,但是在 LLM 训练中则是对整个序列赋予奖励。奖励模型通常是一个经过特殊微调的语言模型,其输入是生成的文本,输出是一个标量值,表示该文本的「质量」或「符合人类偏好的程度」。

从架构上看,奖励模型是在原始 SFT 模型基础上,添加了一个 Value Head 线性层(MLP)。这个 Head 的输入是序列的隐藏状态(Hidden States),输出是一个标量(Scalar),表示每个位置的得分预测。具体而言:

  • 输入:模型的隐藏状态,形状为 [batch_size, seq_length, hidden_size]
  • 价值头:线性层,将隐藏状态映射到奖励值,输出形状为 [batch_size, seq_length, 1]
  • 输出:通常只取最后一个标记(比如 EOS_token)的奖励值作为整个回复的得分,形状为 [batch_size, 1];也可以根据需要对所有位置的奖励值取平均(但考虑到 Decoder-only 模型的性质,只有 EOS_token 输出时才能看完整句子给出一个整体评价,一般不会用平均)。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# Reward Model 模型架构伪代码
class RewardModel(AutoModelForCausalLM):
def __init__(self, config, tokenizer):
super().__init__(config)
self.tokenizer = tokenizer
self.value_head = torch.nn.Linear(config.hidden_size, 1, bias=False)

def forward(self, input_ids, attention_mask):
# 获取基础模型的输出
outputs = self.model(
input_ids=input_ids,
attention_mask=attention_mask,
return_dict=True,
use_cache=False
)
hidden_states = outputs.last_hidden_state # [batch_size, seq_length, hidden_size]
rewards = self.value_head(hidden_states) # [batch_size, seq_length, 1]
# 取最后一个标记的得分作为整体得分
final_reward = rewards[:, -1, :] # [batch_size, 1]
return final_reward.squeeze(-1) # [batch_size]

在 PPO 训练阶段,奖励模型的参数通常是冻结的,不参与更新。而在这之前,奖励模型需要依赖成对偏好数据(Pairwise Preference Data)进行训练。这是因为直接对文本标注绝对分数可能存在标注者主观性和噪音,成对比较可以更有效地捕捉人类偏好 —— 出自 OpenAI 2020 年论文《Learning to Summarize with Human Feedback》。

具体而言,针对一组提示,我们使用指令微调后的模型生成多个不同的回复。再由人类标注者根据偏好进行排序,两两组合形成了成对的偏好数据,用于训练奖励模型。其中,每条训练数据由 \((x,y_\text{win},y_\text{lose})\) 三元组构成,其中 \(x\) 是查询,\(y_\text{win}\)\(y_\text{lose}\) 分别是被选中的回复和被拒绝的回复。

奖励模型通过最大化选中回复与拒绝回复得分的差异,学习人类的偏好,即成对排序损失(Pairwise Ranking Loss)\[ L^{\text{RM}}(\psi) = \log \sigma(r(x, y_w) - r(x, y_l)) \] 其中,\(r(x, y_w)\)\(r(x, y_l)\) 分别是奖励模型对选中回复与拒绝回复的标量预测值,\(\sigma\) 是 sigmoid 函数。在 2021 年 Anthropic 的论文《A General Language Assistant as a Laboratory for Alignment》中,为了使奖励模型不仅能够比较两个回复的优劣,还能够生成更符合人类偏好的回复,可以在损失函数中加入自回归语言模型的损失,即在选中回复上引入语言模型的对数似然项。奖励模型的整体损失函数可以表示为:

\[ L^{\text{RM}}(\psi) = -\lambda \mathbb{E}_{(x, y_w, y_l) \sim \mathcal{D}_{\text{rm}}} \left[ \log \sigma(r(x, y_w) - r(x, y_l)) \right] + \beta_{\text{rm}} \mathbb{E}_{(x, y_w) \sim \mathcal{D}_{\text{rm}}} \left[ \log(r'(x, y_w)) \right] \]

其中,\(\lambda\)\(\beta_{\text{rm}}\) 是超参数。\(r^′\)\(r\) 是除线性层外相同的模型,\(r^′(x,y_w)\) 是在给定提示 \(x\) 下,生成选中响应 \(y_w\) 时的似然。通过同时最小化排序损失和语言模型损失,奖励模型既学习了人类的偏好排序,也保留了生成高质量文本的能力。

价值模型 | Value Model

价值模型在 RLHF 中负责估计每个状态的价值函数,扮演经典 PPO 算法中的 Critic Model 角色。其作用是预测当前状态下(前缀序列)未来累积奖励的期望值,记为期望总收益 \(V_t\)。这个 \(V_t\) 则在采样时为策略模型提供优势函数(Advantage Function),帮助策略模型更好地理解哪些动作能够带来更高的奖励。

通常,价值模型是由奖励模型初始化而来,利用奖励模型对即时收益的评估能力,拓展到对未来累积奖励的估计。从架构上看,它们有着相似的结构,都是在语言模型的基础上添加了一个 Value Head,但价值模型会对序列中的每个状态进行评分,并全部返回。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# Critic Model 模型架构
class CriticModel(AutoModelForCausalLM):
def __init__(self, config, tokenizer):
super().__init__(config)
self.tokenizer = tokenizer
self.value_head = torch.nn.Linear(config.hidden_size, 1, bias=False)

def forward(self, input_ids, attention_mask):
# 获取基础模型的输出
outputs = self.model(
input_ids=input_ids,
attention_mask=attention_mask,
return_dict=True,
use_cache=False
)
# 获取每个时间步的隐藏状态
hidden_states = outputs.last_hidden_state # [batch_size, seq_length, hidden_size]

# 计算每个时间步的价值估计
values = self.value_head(hidden_states) # [batch_size, seq_length, 1]
values = values.squeeze(-1) # [batch_size, seq_length]

return values # 返回序列中每个位置的价值估计

价值模型在 PPO 训练过程中会不断更新,其学习目标是最小化其预测值与目标价值之间的差异,损失函数通常使用均方误差(Mean Squared Error,MSE)来定义: \[ L^{\text{Critic}}(\phi) = \mathbb{E}_{(x, y) \sim \mathcal{D}} \left[ \| V_\phi(x) - V_t^{\text{target}} \|^2 \right] \]

其中,\(V_\phi(x)\) 是价值模型对状态 \(x\) 的价值估计,\(V_t^{\text{target}}\) 可以是实际累积奖励的估计值 \(\hat{R}(x, y) =\sum_{l=0}^{\infty}\gamma^lr_{t+l}\),也可以是使用 TD Error 估计的优势价值

InstructGPT 论文解读

2022 年,OpenAI 发表了论文《Training language models to follow instructions with human feedback》,利用人类反馈微调语言模型,在多种任务上实现模型与用户意图对齐,得到 InstructGPT。InstructGPT 有三个版本,分别是 1.3B、6B、175B 参数量。在人类评估中,1.3B 参数 InstructGPT 模型的输出好于 175B GPT-3 的输出,同时参数少 100 倍。此外,InstructGPT 模型在输出的真实性、毒性输出等方面有改进,证明该方法是使语言模型与人类意图对齐的有前景方向。

InstructGPT(PPO-ptx)的表现

文中提出的三阶段训练方法开启了 LLM 训练的新范式:

训练LLM的三阶段:SFT、RM、RLHF
  1. 构造人类指令数据集,进行监督微调:作者聘请了 40 个人的团队来标注数据,主要是针对用户提交给 OpenAI API 的问题标了一些期望的回复(human-written demonstrations),并使用这个标注的数据微调 GPT-3,这一步是有监督的微调(Supervised Fine-Tuning,SFT)。但是值得注意的是,SFT 的数据集是一种对话形式的数据集,这种数据集的采集成本很大,所以通常数据的量级不大。

  2. 构造偏好对数据集,训练 Reward Model:对第一步训练的模型喂入一些 Prompt,使它输出多个结果。再让人类来打分,所得到的这些包含人类偏好的数据集用于训练一个奖励模型。这个模型的作用是预测人类更喜欢模型的哪个输出。

  3. 使用第二步的 RM + PPO 算法优化第一步训练的模型以最大化奖励:将第一步训练的 LLM 模型视为策略模型,采用 PPO 的 RL 方法训练 LLM 模型,得到最终的模型。

对齐税与 PPO-ptx

对齐税(Alignment Tax)指 LLM 在通过 RLHF 进行偏好对齐时,其通用任务能力可能出现的退化现象。其本质是对齐过程中施加的偏好约束(如安全准则、伦理规范)与预训练阶段的自由探索之间存在目标冲突

在大部分时候 PPO 算法中会使用 PPO-clip 作为目标函数: \[ \mathcal{L}_{\mathrm{ppo}-\mathrm{clip}}(\theta)=\hat{\mathbb{E}}_t\left[\min \left(\frac{\pi_\theta\left(a_t \mid s_t\right)}{\pi_{\theta_{\text {old }}}\left(a_t \mid s_t\right)} \hat{A}_t, \operatorname{clip}\left(\frac{\pi_\theta\left(a_t \mid s_t\right)}{\pi_{\theta_{\text {old }}}\left(a_t \mid s_t\right)}, 1-\epsilon, 1+\epsilon\right) \hat{A}_t\right)\right] \] 为了缓解对齐税的影响,作者还探索了将预处理数据纳入 RL 阶段。利用此方法的模型表示为 PPO-ptx,组合后的目标函数如下: \[ \mathcal{L}_{\text {ppo-ptx }}(\theta)=\mathcal{L}_{\text {ppo-clip }}(\theta)+\lambda_{\text {ptx }} \mathbb{E}_{x \sim \mathcal{D}_{\text {pretrain }}}\left[\log \left(\pi_\theta^{\mathrm{RL}}(x)\right)\right] \] 其中,\(\lambda_{\text {ptx}}\) 是预训练损失的占比,论文中将其设为 \(27.8\)

讨论:RLHF vs. SFT

  1. 奖励建模角度:有一些 LLM 需要的目标函数是难以通过规则定义的,比如说无害性、有帮助性,如果我们希望模型最后具有这些好的特性,就需要制定这样的训练目标函数;而用人类的偏好学习一个 reward model 再用 RL 来训练,就自然的可以将这些特性融合到 LLM 里面。
  2. 探索性角度:对于 SFT,人类的高质量样本确实很快速让模型学会指令输出,但样本始终是有限的,并且很多任务我们没法给出标准答案;而对于 RL,我们可以探索出无穷多的样本用于训练,偏好排序的形式也更适合筛选更合适的样本,甚至可能会探索到比 SFT 数据更优质的解
  3. 监督信号角度:SFT 中模型只要稍微偏移答案就会收到惩罚;而 RL 对不同的答案也可能给出正反馈,间接鼓励了模型输出的多样性。
  4. 幻觉角度:对于知识密集型任务,如果模型内部具有这个知识,那么 SFT 会让其将知识和问题联系起来;但如果模型预训练时压根没见过这个知识,则 SFT 可能会让模型学会说谎(强行拟合输出)。相比之下,RLHF 则可以根据答案的正确性和模型的置信度给出多样化的反馈,一定程度上减少了幻觉。

讨论:RLHF 与幻觉问题

相关资料:John Schulman - Reinforcement Learning from Human Feedback: Progress and Challenges - YouTube

LLMs 有一个众所周知的「硬伤」——它们经常会一本正经编造貌似真实的内容,俗称幻觉(Hallucination)。

当人们说幻觉时,主要指的是两类不同情况:

  • 第一类幻觉是语言模型的模式完成(Pattern Completion)行为。它们的训练目的是最大化文本可能性,使生成的内容看起来很像互联网上的文本。这主要有三个原因:
    1. 它不知道自己可以回答“我不知道”或者表达不确定性。如果告诉模型可以回答“我不知道”,那么在一定程度上能解决幻觉问题;
    2. 模型有时不愿意去质疑前提(premise),它认为前提是数据分布的一部分;
    3. 模型有时会陷入谎言之中。如果模型已经犯了一个错误,那么它会认为自己应该继续回答下去,生成一连串响应,这也意味着它会继续说谎。
  • 第二类幻觉就是单纯的「猜错了」。就像人类一样,你可能只遇到过一次某件事情,自己不能确定,感到很模糊,所以在回答时必须带点猜测,有时可能就会猜错。这主要有两个原因:
    1. 模型在训练时被倾向于输出更全面的答案。当答案中包含模糊的东西时,模型自动地将其补全,以便「骗过」奖励模型,取得更高的分数。
    2. 有监督微调(SFT)时教会了模型乱猜。这就涉及到行为克隆(Behavior Cloning)这一微调过程。

行为克隆造成幻觉

行为克隆(Behavior Cloning)是强化学习领域的一个术语,意思是有监督微调或最大化似然(Maximizing Likelihood),其目的是完成给定 Prompt 的最大化似然或最大化对数概率。通常我们认为在模型训练的三个阶段中,SFT 最容易引入幻觉。

这是由于,当我们进行 SFT 时,使用的是人类编写的正确指令对来训练,此时的监督训练目标是模仿指令对的输出(包括格式和内容)。当然,我们的本意是「教会模型按照我们想要的方式完成指令」,但如果此时训练集中含有关于 2022 年世界杯的问题,但第一阶段预训练的知识库截至于 2021 年,此时模型并不了解 2022 年比赛的结果。在这种情况下,我们实际上不是在训练模型输出正确答案,而是在训练它在这种问题上进行猜测

如果你使用行为克隆来训练模型,那么无法避免出现上述幻觉问题。同时也会出现相反的问题,即如果你想训练模型在某些情况下回答「我不知道」,那么它可能会隐瞒实际上已经知道的信息。例如,如果标注者不知道答案,他们可能会将「我不知道」列为目标答案,但实际上网络可能已经有了答案,而模型在预训练时已经学会,你只是在训练模型隐瞒信息。

因此,行为克隆或监督学习的问题在于:正确的目标实际上取决于神经网络中包含了哪些知识,而这对于收集数据或进行实验的人来说是未知的。因此,除非你有一种方法来查看模型中的内容,否则无法使用行为克隆训练出真实可信的模型。

模型对自身不确定性的认知

我们希望模型在不知道正确答案时能输出其知识的实际状态并表明不确定性,而不是进行猜测。那么模型是否知道自己的不确定性呢?比如给定一个问题,模型清楚自身是否知道答案吗?这个问题很难回答。什么是「知道」?如果模型知道某些东西,那么能否用最简单的东西将其反应出来?

John Schulman 认为模型肯定是知道自身的不确定性的。这是因为模型被训练为最小化对数损失,为此它必须输出概率。模型的下一个 token 预测是经过校准的(calibrated),校准后的对数损失是一个合适的表示不确定性的指标。

预训练目标产生了一个校准的模型,它必定输出合理的概率,这意味着,模型知道自身的不确定性,至少对于任何可以被转化为预测单个 token 的短答案的问题,它可以为该 token 给出一个合理的概率分布。Anthropic 的论文《Language Models (Mostly) Know What They Know》对这个现象给出了更详尽的分析。

因此,如果模型确实知道自己的不确定性,行为克隆无法利用这一点来避免幻觉,强化学习才是解决这个问题正道

部分幻觉仅因为模型陷入想要「给出完整答案」的模式或不知道如何表达不确定性而产生,因此这类幻觉很好解决。比如可在训练模型时给出一些表明「我不知道」、「我的知识截止于××日期」的示范,或者给出一些质疑用户提问的范例,这样模型至少能够表达不确定性,只是表达的时机可能不是那么恰当。

RLHF 用于缓解幻觉

一个很朴素的想法是,当模型给出一个答案,如果是非常自信的正确答案,将得到高额奖励;如果是模糊的正确答案,将得到稍差的奖励;如果是无信息的答案,例如“我不知道”,将得到一些惩罚;如果是模糊的错误答案和完全错误的答案,将得到更多的惩罚。这基本是一个适当的评分规则,能够激励模型给出自信的答案,如果它对错误答案过于自信,就会给出相应惩罚。

但通过强化学习训练语言模型来实现这一目标并不容易,因为你需要知道答案是否正确,但答案究竟正确与否我们无从知道。更复杂的情况,当模型输出 Long-form Answer 时,其中很可能包含正确与错误的部分——没有完美的答案,也没有完美的评判标准

因此,更合理的办法是让标注者对回答进行排序,并说出哪个更好。


RL 学习笔记 #11 PPO 在 RLHF 中的应用
https://hwcoder.top/RL-Note-11
作者
Wei He
发布于
2025年2月20日
许可协议