如果直接用人的偏好(或者说人的反馈)来对模型整体的输出结果计算reward或loss,显然是要比上面传统的“给定上下文,预测下一个词”(自回归损失)的损失函数合理的多。基于这个思想,便引出了本文要讨论的对象——RLHF(Reinforcement Learning from Human Feedback):即,使用强化学习的方法,利用人类反馈信号直接优化语言模型。
RLHF也是最近大火的ChatGPT背后的训练方法。
RLHF的训练过程可以分解为三个核心步骤:
- 预训练语言模型(LM)
- 收集数据并训练奖励模型
- 通过强化学习微调 LM
首先,我们需要选一个经典的预训练语言模型作为初始模型。例如,OpenAI 在其第一个RLHF 模型 InstructGPT 中用的小规模参数版本的 GPT-3;DeepMind 则使用了2800 亿参数的 Gopher 模型。这些语言模型往往见过大量的 [Prompt,Text] 对,输入一个prompt(提示),模型往往能输出还不错的一段文本。
预训练模型可以在人工精心撰写的语料上进行微调,但这一步不是必要的。例如,OpenAI在人工撰写的优质语料上对预训练模型进行了微调;Anthropic将他们的语言模型在“有用、真实、无害”价值观导向的语料上做了一步模型蒸馏。不过,这种人工撰写的优质语料一般成本是非常高的。
总之,预训练任务为输入一个prompt,生成目标text。
一个奖励模型(RM)的目标是刻画模型的输出是否在人类看来表现不错。即,输入 [提示(prompt),模型生成的文本] ,输出一个刻画文本质量的标量数字(score)。
用于训练奖励模型的Prompt数据一般来自于一个预先富集的数据集,比如Anthropic的Prompt数据主要来自Amazon Mechanical Turk上面的一个聊天工具;OpenAI的Prompt数据则主要来自那些调用GPT API的用户。这些prompts会被丢进初始的语言模型(第一阶段的模型)里来生成文本。
整体流程如图所示:
奖励模型可以看做一个判别式的语言模型,因此我们可以用一个预训练语言模型热启,而后在 [x=[prompt,模型回答], y=人类满意度(人力参与标注)] 构成的标注语料上去微调,也可以直接随机初始化,在语料上直接训练。
如上图所示,标注人员的任务则是对初始语言模型生成的文本进行排序。有人可能会奇怪,为啥不直接让标注人员对文本进行打分呢?
这是因为研究人员发现不同的标注员,打分的偏好会有很大的差异(比如同样一段精彩的文本,有人认为可以打1.0,但有人认为只能打0.8),而这种差异就会导致出现大量的噪声样本。若改成标注排序,则发现不同的标注员的打分一致性就大大提升了。
那具体怎么操作呢?一种比较有效的做法是“pair-wise”,即给定同一个prompt,让两个语言模型同时生成文本,然后比较这两段文本哪个好。最终,这些不同的排序结果会通过某种归一化的方式变成标量信号(即point-wise)丢给模型训练(?)。
一个比较有趣的观测是,奖励模型的大小最好是跟生成模型的大小相近,这样效果会比较好。一种比较直观的解释就是,要理解生成模型的输出内容,这份理解能力所需要的模型参数规模就得恰好是跟生成模型相近才能做到(当然,如果奖励模型规模更大那应该更没问题,但理论上没必要)。
至此,我们有了一个初始的语言模型来生成文本,以及一个奖励模型(RM)来判断模型生成的文本是否优质(迎合人类偏好)。接下来会讲解如何使用强化学习(RL)来基于奖励模型来优化初始的语言模型。
我们将初始语言模型的微调任务建模为强化学习(RL)问题,因此需要定义策略(policy)、动作空间(action space)和奖励函数(reward function)等基本要素。
显然,策略就是基于该语言模型,接收prompt作为输入,然后输出一系列文本(或文本的概率分布);而动作空间就是词表所有token在所有输出位置的排列组合(单个位置通常有50k左右的token候选);观察空间则是可能的输入token序列(即prompt),显然也相当大,为词表所有token在所有输入位置的排列组合;而奖励函数(reward)则是基于上一章节我们训好的RM模型计算得到初始reward,再叠加上一个约束项来。
然后我们来看一下最后提到的这个约束项是什么。
首先,基于前面提到的预先富集的数据,从里面采样prompt输入,同时丢给初始的语言模型和我们当前训练中的语言模型(policy),得到俩模型的输出文本y1,y2。然后用奖励模型RM对y1、y2打分,判断谁更优秀。显然,打分的差值便可以作为训练策略模型参数的信号,这个信号一般通过KL散度来计算“奖励/惩罚”的大小。显然,y2文本的打分比y1高的越多,奖励就越大,反之惩罚则越大。这个信号就反映了当前模型有没有在围着初始模型“绕圈”,避免模型通过一些“取巧”的方式骗过RM模型获取高额reward(通过RM指导第一步的预训练微调)。
最后,便是根据 Proximal Policy Optimization (PPO) 算法来更新模型参数了。
该阶段流程如下图所示:
RL policy和RM是同步迭代更新的。
容易理解: KL散度让预训练后的模型输出和训练之前的尽可能拉开,拉开的同时还要保证RM的rank loss也低。
InstructGPT论文中,给出了上述三个步骤,分别制造/标注了多少样本:
- SFT数据集(即第一步人类根据prompt自己写理想的输出,SFT:supervised fine-tuning),包含13K的prompts;
- RM数据集(即第二步用来训练打分模型的数据),包含33K的prompts;
- PPO数据集(即第三步用来训练强化学习PPO模型的数据),包含31K的prompts。
其中πθ为语言模型输出,t 为生成序列的 index,A 代表的是这次语言模型输出的序列在每一个 index 上时候可以获得的预期期望。values 是一个[batch_size, seq_len]的shape,可以理解成句子生成到这个 token 时可以给这个流程打的总分:假设大模型生成了序列“abcde”,values 向量的值是[1,2,3,4,5],那么t=2 这个时间点对应的 values[2]的数值可以理解为 critic 模型对语言模型生成"abc"这三个 tokens 打得分。
- 对于 A 的概念中“预期期望”的理解可以是如下:假设语言模型为输入 query 生成了输出“abcde”共 5 个 tokens,那么在 t=1的时候,也就是在生成字母b 的时刻,会以token b后续生成的 tokens ”cde“的 values 值根据类似加权求和的方式求出在 t=2 这个时刻,模型给出token ‘b’这个预测行为的奖励期望,这是一个根据结果评判过程的方式,先有了整个结果在对生成过程进行复盘评价。