2. RLHF 核心组件:奖励模型、策略模型、参考模型
好,咱们进入正题。RLHF 这套东西,说白了就是三个模型搭台唱戏。我刚开始接触的时候,也觉得这三个模型绕来绕去,容易搞混。但你拆开来看,每个角色其实都很清晰。
我个人习惯把这三个模型比作一个「师徒三人组」:
- 策略模型——那个正在学习的学生,它负责生成回答。
- 奖励模型——阅卷老师,给学生的回答打分。
- 参考模型——老版本的学霸笔记,用来约束学生别跑偏。
嗯,这个比喻虽然简单,但核心逻辑全在里面了。咱们一个一个说。
2.1 奖励模型(Reward Model)—— 那个打分的人
奖励模型是 RLHF 里最关键的「裁判」。它的任务很简单:给定一个 prompt 和一个 response,输出一个标量分数,表示这个回答有多好。
你可能会问:「为什么不直接用人工打分?」原因很简单——人太慢了。你想想看,每次策略模型生成几万条数据,都让人去打分,那成本和时间谁也扛不住。所以我们需要训练一个模型来模拟人类的偏好。
核心要点:奖励模型本质上是一个回归模型,输入是文本对,输出是一个连续值。它学的是「人类觉得什么好」。
我在项目中遇到过一个问题:奖励模型很容易过拟合到某些表面特征上。比如它发现「回答越长分数越高」,或者「包含某些关键词就加分」。这其实是个大坑。
避坑指南:我曾经在训练奖励模型时,发现模型对「谢谢」这个词有莫名的偏好。只要回答里带「谢谢」,分数就高。后来排查发现,标注数据里确实有很多礼貌用语被打了高分。这提醒我们:标注数据的质量,直接决定了奖励模型的上限。
训练奖励模型通常需要以下步骤:
- 收集人类偏好数据:对同一个 prompt,让标注员比较两个回答,选出更好的那个。
- 构建 pairwise 损失函数:让模型学会区分「好回答」和「差回答」。
- 训练一个打分器:最终输出一个连续的奖励值。
代码实现上,一个简单的奖励模型训练流程大概长这样:
# 伪代码:奖励模型训练
for prompt, response_good, response_bad in dataloader:
score_good = reward_model(prompt, response_good)
score_bad = reward_model(prompt, response_bad)
loss = -torch.log(sigmoid(score_good - score_bad))
loss.backward()
optimizer.step()
说白了,就是让好回答的分数比坏回答高。就这么简单。
2.2 策略模型(Policy Model)—— 那个学习的学生
策略模型就是我们最终要优化的那个大语言模型。它负责根据 prompt 生成回答,然后从奖励模型那里拿到反馈,再调整自己的参数。
你可能会问:「这不就是普通的强化学习吗?」嗯,对,也不全对。区别在于:
- 传统 RL 的 action 空间是离散的(比如上下左右),而这里 action 空间是整个词表——几万个 token。
- 传统 RL 的 reward 来自环境,这里的 reward 来自另一个神经网络(奖励模型)。
我个人习惯用 PPO(Proximal Policy Optimization)来训练策略模型。为什么是 PPO?因为它稳定。我试过其他算法,动不动就崩,PPO 至少能让我睡个安稳觉。
小技巧:训练策略模型时,我建议把学习率设得比预训练阶段小一个数量级。比如预训练用 1e-5,RLHF 阶段用 1e-6 甚至更低。步子迈大了,容易扯着蛋。
策略模型的更新公式大致如下:
# 伪代码:PPO 更新策略模型
for epoch in range(num_epochs):
# 用当前策略生成回答
responses = policy_model.generate(prompts)
# 奖励模型打分
rewards = reward_model(prompts, responses)
# 计算优势函数
advantages = compute_advantages(rewards)
# PPO 裁剪更新
loss = ppo_clip_loss(old_log_probs, new_log_probs, advantages)
loss.backward()
optimizer.step()
这里有个细节:old_log_probs 是更新前的概率,new_log_probs 是更新后的概率。PPO 通过裁剪(clip)来防止策略一步更新太大,导致模型崩掉。
2.3 参考模型(Reference Model)—— 那个定海神针
参考模型是很多人容易忽略的一个组件。它的作用是什么?防止策略模型「学歪了」。
你想想看,如果没有参考模型,策略模型可能会为了追求高奖励,生成一些奇怪的东西。比如:
- 回答变得冗长啰嗦(因为长回答更容易拿高分)
- 语言风格变得不自然(为了迎合奖励模型的偏好)
- 甚至开始胡编乱造(因为编故事可能更「精彩」)
参考模型就是那个「老版本」的策略模型。它不参与训练,参数冻结。它的作用是在 KL 散度损失中作为锚点,约束新策略不要偏离太远。
核心公式:RLHF 的总损失 = PPO 损失 - β × KL(新策略 || 参考策略)
其中 β 是一个超参数,控制「探索」和「约束」之间的平衡。
我在项目中遇到过一个问题:β 设得太小,模型开始放飞自我;β 设得太大,模型又学不到新东西。这个参数调起来挺折磨人的。我建议从 0.01 开始试,观察 KL 散度的变化,再逐步调整。
注意:参考模型和策略模型的结构必须完全一样。你不能用一个 7B 的参考模型去约束一个 13B 的策略模型,那 KL 散度算出来就没意义了。
2.4 三个模型的协作流程
好,咱们把这三个模型串起来,看看它们是怎么配合的。下面这张图可以帮你理清思路:
整个流程其实就四步:
- 生成:策略模型根据 prompt 生成回答。
- 打分:奖励模型给这个回答打分。
- 约束:参考模型计算 KL 散度,防止策略跑偏。
- 更新:策略模型根据奖励和 KL 散度联合更新参数。
嗯,这个流程说起来简单,但实际调参的时候坑不少。我建议你从一个小模型开始试,比如 1.5B 参数,跑通整个流程再上大模型。不然一次训练跑三天,结果发现奖励模型没训练好,那心态就崩了。
我的经验:刚开始做 RLHF 时,我犯过一个低级错误——忘了冻结参考模型的参数。结果参考模型跟着一起更新,KL 散度直接变成 0,整个训练失去了约束。这个错误我犯了两次才记住。嗯,希望你一次就记住。
2.5 三个模型的对比总结
| 组件 | 角色 | 是否参与训练 | 参数是否冻结 | 输出 |
|---|---|---|---|---|
| 策略模型 | 学生 | 是 | 否 | 生成的文本 |
| 奖励模型 | 老师 | 是(预训练阶段) | 是(RLHF 阶段) | 标量分数 |
| 参考模型 | 学霸笔记 | 否 | 是 | 概率分布(用于 KL 计算) |
这张表我建议你存一下。每次搞混的时候翻出来看看,一目了然。
好了,三个模型的核心内容就这些。说白了,RLHF 的精髓就是让这三个模型各司其职,互相配合。策略模型负责探索,奖励模型负责评价,参考模型负责兜底。缺一个,整个系统就容易出问题。