卷 VI · 上场CH 22深度 22/24

RLHF:ChatGPT 也是被打分教出来的

这本书前二十一章讲的是一个学走路的小人。这一章你会发现,把同一套东西换个场地,得到的是今天最重要的那个 AI 产品——而且这一路上的每一个坑,都在那儿原样重现了一遍

RLHF奖励模型KL 惩罚

先把五元组对上

第 2 章那五个词,换到对话上是这样的:

两足小人语言模型
状态关节角度、速度到目前为止的整段文本(提示 + 已生成的部分)
动作四个关节的力矩下一个 token(词表大小 = 动作空间,十万级)
策略一个小网络就是那个语言模型本身
奖励作者写的那一行一个学出来的模型
回合500 帧或摔倒生成完一段回复

前三行是直接对应。第四行是这一章的全部内容。

为什么奖励必须是学出来的

你要模型「回答得好」。那就写个奖励函数吧:

def reward(question, answer):
    return ???   # 「好」怎么算?

写不出来。「好回答」没有一个可以写成代码的定义。

试着写几条你就知道有多糟:按长度?那就啰嗦。按关键词匹配?那就堆关键词。按语法正确性?胡说八道也可以语法完美。

每一条都是第 20 章那种奖励黑客的现成入口。

但有一件事人类做得很轻松:给两个回答,说哪个更好。

说不出「这个值 7.3 分」,但能说「A 比 B 好」。RLHF 的全部起点就是这个不对称。

从「A 比 B 好」到一个分数

把偏好转成分数的工具叫 Bradley-Terry 模型,1952 年提出的,本来是用来给运动员排名的:

P(A 胜 B) = σ( r_A - r_B )       σ 是 sigmoid

给每个回答一个分数 r,让「分数差」能解释「谁赢」的概率。收集一堆两两比较,用梯度上升拟合这些 r。

▶ 动手 · 先看干净标注,再往里掺矛盾的

五个回答,人类给了十条两两偏好。看它能不能把顺序还原出来。然后加入自相矛盾的标注,看分数会怎么变。

两件值得注意的事

① 分数的绝对值没有意义,只有差值有

Bradley-Terry 只定到一个平移常数——全部加 100,所有胜率预测完全不变。所以上面那个 demo 做了中心化。

有意义的是差值:差 1 分意味着「胜率约 73%」,差 2 分意味着「约 88%」。

这解释了一个你在论文里会看到的现象:奖励模型的分数在不同训练批次之间不可比。你不能说「这个模型的奖励从 2.1 涨到了 3.4」——那两个数字来自不同的尺子。

② 标注一矛盾,分数就向 0 收缩

加入矛盾标注之后,所有分数整体往中间挤(从 ±2.72 挤到 ±0.94),一致率从 100% 掉到 83%。

模型在说「我不太确定了」。这是个正确的、健康的反应。

但接下来是关键的一步:这个不确定,会原样传给后面的 PPO。奖励模型在某些区域分数很平坦、很含糊,PPO 就会在那些区域乱走——而那正是奖励黑客最容易发生的地方。

完整的三步

步骤做什么对应本书哪一章
① SFT拿人写的高质量问答做监督微调第 21 章那个「模仿学习」
② RM收集人类偏好,训一个奖励模型这一章上半部分
③ PPO用 RM 当奖励,用 PPO 优化语言模型第 18 章

第一步就是第 21 章那条出路——先给它看演示,别让它从零随机探索。如果直接从一个没微调过的基座模型开始跑 PPO,它生成的东西离「好回答」太远,奖励模型给的分全在一个很窄的区间里,信号弱得学不动。这是稀疏奖励问题在语言上的形态。

第三步里那个至关重要的补丁

PPO 的目标不是单纯地最大化奖励模型的分数。它长这样:

reward = RM(回答)  -  β · KL( π_new ‖ π_SFT )
                       └──────────┬──────────┘
                    「别离原来那个模型太远」

那一项 KL 惩罚是必须的,而且理由和第 18 章那个 clip 一模一样。

◆ 没有 KL 惩罚会发生什么

会发生一件很有代表性的事:模型会发现一段完全不通顺、但奖励模型偏偏给高分的乱码,然后反复输出它。

为什么?因为奖励模型是在「像人写的文本」这个分布上训练的。一旦策略跑到那个分布之外,奖励模型的输出就毫无意义——它从没见过这种输入,给出的分数纯属外推,可能高得离谱。

这就是第 18 章那个「用一张过期的地图指路」,只不过过期得更彻底。

KL 惩罚做的事:把策略拴在 SFT 模型附近,保证生成的东西还在奖励模型「懂」的范围内。

它和 PPO 的 clip 是同一件事的两个层次:clip 限制「每次更新走多远」,KL 限制「离出发点总共走多远」。

这本书讲的每个坑,在这里都重现了

本书哪一章在 RLHF 里的样子
第 20 章 奖励黑客奉承:顺着用户说,哪怕用户错了
啰嗦:长回答显得用心,那就把话说三遍
虚假自信:犹豫的措辞得分低,那就用肯定语气说错话
第 21 章 稀疏奖励不先做 SFT 直接跑 PPO,信号弱到学不动
第 18 章 一步迈太大没有 KL 惩罚,模型跑到奖励模型的知识之外,输出乱码
第 16 章 训练不稳PPO + 几百亿参数,一旦发散重训成本极高
第 4 章 探索采样温度就是探索率。温度太低学不到新东西,太高全是噪声
第 13 章 on/off-policy用 PPO(on-policy)而不是 SAC——稳定性压倒样本效率

第一行最值得停一下。「奉承」和第 20 章那个趴下刷姿态分的小人,是同一件事。

奖励模型不是「什么是好回答」,它是「标注员倾向于选哪一个」。这两者之间的差距,就是全部的漏洞。而标注员是人,人会被自信的语气说服,会觉得长的更用心,会更喜欢同意自己的观点。模型把这些全学会了——因为那些确实能得高分。

⚠ 奖励模型自己也会被榨干

还有一层更麻烦的:奖励模型是一个有限的神经网络,它对「奇怪的输入」的判断是不可靠的。

而 PPO 的工作就是专门去找那些能拿高分的输入。训练久了,它一定会摸到奖励模型的过拟合区域——那里 RM 给分虚高,实际质量却在下降。

这个现象叫 reward model over-optimization,而且有实证研究把它量化了:随着 KL 散度增大,RM 打的分持续上升,而人类实际评价先升后降——两条曲线在某个点分道扬镳。

怎么办?目前的做法都是缓解,不是解决:

  • 调大 β(KL 惩罚),别让它走那么远
  • 提前停——在两条曲线分开之前停下
  • 迭代式 RLHF:训一轮,拿新模型的输出重新找人标注,更新奖励模型,再训。让尺子跟着被测量的对象一起更新。
  • 用多个奖励模型取最小值,避免单个模型的盲区被利用

这是第 20 章那个「补丁本身也会被黑」在最前沿的样子。这一层递归目前没有尽头。

✎ RLHF 之外的路线

RLHF 流程长、要三个模型、工程复杂。后来出现了几条更省事的路,值得知道名字:

  • DPO(直接偏好优化):一个漂亮的推导——把奖励模型和 PPO 合并成一个损失函数,直接在偏好数据上微调,不用单独训 RM,也不用跑 PPO。简单太多,成了很多开源模型的默认选择。
  • RLAIF:用一个强模型代替人类做偏好标注。便宜得多,代价是把那个模型的偏见一起继承过来。
  • Constitutional AI:给模型一份原则清单,让它自己批评和修改自己的输出。Anthropic 的做法。

但注意:这些方法都没有消灭「你写下的和你想要的之间有差距」这个根本问题。DPO 里那个差距藏在偏好数据里,RLAIF 里藏在那个打分模型里。它只是换了个地方。

⌗ 换成真机:自己跑一次 RLHF

Hugging Face 的 trl 库把三步都封好了:

pip install trl transformers datasets
from trl import PPOTrainer, PPOConfig, AutoModelForCausalLMWithValueHead

config = PPOConfig(
    learning_rate=1.4e-5,
    batch_size=64,
    init_kl_coef=0.2,     # ← 那个 β,最重要的旋钮
    target_kl=6.0,        # KL 超过这个就自动调大惩罚
)
model = AutoModelForCausalLMWithValueHead.from_pretrained("gpt2")
#                                        └─ 注意:策略和 Critic 共享主干

trainer = PPOTrainer(config, model, ref_model, tokenizer)
for batch in dataloader:
    responses = trainer.generate(batch["query"])
    rewards = reward_model(batch["query"], responses)   # ← 你的奖励模型
    trainer.step(batch["query"], responses, rewards)

三个提醒:

① 那个 ref_model冻住的 SFT 模型,专门用来算 KL。它就是第 16 章那个目标网络的思路——一份不动的参照物

AutoModelForCausalLMWithValueHead 里那个 value head,就是第 17 章的 Critic。它和策略共享主干,只多一个输出头。

拿 GPT-2 在一个玩具任务上跑一次(比如「让生成的影评偏正面」,用一个现成的情感分类器当奖励模型)。单卡几十分钟。跑完之后,前面二十一章会突然全部串起来。

↩ 回到那个视频

这一章想留下的一句话是:

那个学走路的小人,和你每天在用的那个聊天模型,是被同一种方法教出来的。

小人的奖励是作者写的一行代码,模型的奖励是一个从几万条人类偏好里拟合出来的网络。但结构完全一样:一个策略,一个打分器,一个 PPO。

而它们踩的坑也完全一样。小人学会趴下刷姿态分,模型学会说漂亮话讨好标注员——都是精确地最大化了那个被写下来的东西,而不是那个被想要的东西。

这就是为什么这本书把「打分」放在书名上。算法会换,框架会过时,但那个差距一直在。

这一章的一句话

环境是对话,动作是下一个 token,奖励是一个从「A 比 B 好」里拟合出来的模型。而那个模型不是「什么是好回答」,是「标注员倾向于选哪个」——这两者的差距,就是全部的漏洞。

下一章:回到那台两足小人。在你的浏览器里当场训练它,一百毫秒跑完三十代;顺便给你一条从 CartPole 到 BipedalWalker 的、不会浪费时间的真实路线。