微调
微调
1. 指令微调
基本概念
指令微调是收集大量覆盖不同任务的 (指令, 输出) 数据对,然后用这些数据去微调一个已经预训练好的语言模型(LM)。
一个重要的发现是,我们可以利用一个非常强大的模型(如GPT-4)来生成大量的指令和回答,然后用这些生成的数据去微调一个规模小一些的开源模型。
对齐,“少即是多” (Less Is More for Alignment):对于指令微调来说,数据的质量和多样性可能比单纯的数量更加重要。
指令微调的局限性
指令微调具有如下的局限性:
- 数据成本高昂:这是最直接的问题。制作高质量的(指令, 输出)数据对需要大量的人工。每个任务都需要人来精心设计指令,并写出高质量的、作为“标准答案”的输出。
- 微妙的局限性:这是更深层次的问题。指令微调的目标和我们真正想要的目标(满足人类偏好)之间仍然存在偏差。
- 开放式、创造性任务没有唯一的“正确答案”
- 如让模型“写一个关于一只小狗和它的宠物蚱蜢的故事”。世界上可以有无数个同样精彩、但内容完全不同的故事。在指令微调的框架下,我们只能提供一个故事作为“标准答案”。如果模型生成了另一个同样优秀但措辞不同的故事,训练算法仍然会因为它与“标准答案”在字词上不匹配而“惩罚”模型。这显然是不合理的。
- 模型对所有错误的惩罚是平等的,但对人类来说,不同的错误的严重性有很大差别
- 语言模型的训练目标是最小化预测错误,它在词元层面(token-level)上计算损失。这意味着,模型犯的任何错误,无论大小,惩罚可能都是一样的。
- 开放式、创造性任务没有唯一的“正确答案”
为人类偏好优化
为解决指令微调的微妙局限性,我们引入一个新的、更强大的范式,它的核心思想是:不再告诉模型什么是“对”的,而是告诉它什么是“更好”的。这个过程被称为 RLHF (Reinforcement Learning from Human Feedback),即“从人类反馈中进行强化学习”。
基本概念与流程
我们引入奖励(Reward)概念:
- 我们不再需要一个唯一的标准答案,而是让模型针对一个指令(Prompt)生成多个不同的输出。
- 然后,我们评估这些输出,并给出一个分数 (reward),分数越高代表越好。
这样,我们的目标函数变成了最大化模型输出的期望奖励 (Maximize the expected reward):
RLHF 并不是要取代指令微调,而是建立在它的基础之上。我们首先需要一个经过指令微调的、已经具备基本能力的模型作为起点。然后,我们需要训练一个奖励模型 (Reward Model)来模拟人类的偏好,然后使用强化学习算法(如PPO)来根据这个奖励模型的打分,进一步优化语言模型本身。
策略梯度
我们的目标是调整语言模型的参数 ,来最大化模型输出的期望奖励 。最自然的想法是使用梯度上升 (gradient ascent)。即,我们计算期望奖励关于模型参数的梯度 ,然后让参数 沿着这个梯度的方向更新,这样就能让期望奖励变大:
我们将这个梯度式子展开:
这个式子有一个严重的问题:奖励函数 来自人类的打分(或者一个模仿人类打分的模型),它是一个“黑箱”,我们无法对它进行求导,因此梯度 无法通过 进行反向传播。
于是我们使用一个“对数导数技巧” (log-derivative trick):这是一个非常巧妙的数学变换:
于是原来的式子变为:
这个新的求和形式,正好是另一个期望的定义:
这样,我们成功地将 变换成了 。梯度 现在只作用于 这个模型的对数概率。这在神经网络中是完全可求导的。 而不可求导的奖励函数 被分离了出来,只是一个普通的权重,不再参与求导。
接下来我们需要解决如何估计这个期望的问题。我们采用蒙特卡洛近似的方法:我们让模型生成 个输出 ,并得到它们各自的奖励 。然后,我们用这些样本的平均值来近似整个期望:
这样,我们沿梯度方向更新的式子就变成了:
在这个式子中,如果奖励 是一个很大的正数 (+++):意味着模型生成的输出非常好,更新的方向就是 + ,这会增大 的概率。反之亦然。
奖励模型的训练
单纯让模型输出一个具体的奖励值有如下的问题:人类的绝对判断是既主观又不稳定的。对此,我们引入成对比较法:与其问“这个东西值多少分?”,不如问一个更简单、更客观的问题:“A和B这两个,你觉得哪个更好?”
这样,奖励模型的完整训练流程可以整理如下:
- 数据收集:
- 针对同一个指令(Prompt),让语言模型生成多个不同的回答(如)。
- 将这些回答两两组合,让标注员进行比较,选出较好的回答。例如,标注员认为 并且 。这些成对的比较结果就构成了我们的训练数据集。
- 奖励模型的训练目标:
- 奖励模型 的工作是给任何输入的文本打一个分。它并不需要精确地拟合某个分数,而是需要让结果能够正确地反映人类的比较偏好。也就是说,如果人类认为 ,那么我们的奖励模型经过训练后,也应该满足 。
- 损失函数 (Loss Function):损失函数的计算方式如下:
其中 是“获胜”的样本, 是“落败”的样本。 是奖励模型给出的分差。我们的目标是让这个分差尽可能地大。
完整的 RLFH 流程
根据先前的讨论,我们已经拥有了下面的组件:
- 预训练好的基础语言模型
- 奖励模型
- 策略梯度优化算法
于是完整的 RLFH(Reinforcement learning from human preferences) 流程如下:
- 我们复制一份基础模型 ,得到一个我们将要优化的策略模型。训练开始时, 参数和 的完全一样。
- 我们使用强化学习算法来优化这个策略模型,但我们优化的目标不仅仅是奖励模型的分数,而是一个复合的奖励函数:
- 是激励项,它鼓励我们的策略模型 生成能够从奖励模型 那里获得高分的文本。
- 是惩罚项,防止我们的策略模型 与最初的参考模型 偏离得太远。
原始参考模型中包含了海量的世界知识、语法结构和常识。惩罚项就像一个锚,将优化过程中的模型牢牢地拴在这些知识基础上,确保它在学习“讨人喜欢”的同时,不会忘记如何保持事实的连贯性和逻辑性。
2. InstructGPT & ChatGPT
InstructGPT是OpenAI在2022年发布的一个里程碑式的项目。这个项目首次完整且成功地将在数万个任务上进行的大规模RLHF流程公之于众,深刻地影响了整个领域。整个流程如下:
- 监督微调 (Supervised Finetuning, SFT):收集示范数据,训练一个监督策略。这步就是前面所说的指令微调。
- 训练奖励模型 (Reward Model, RM):收集比较数据,训练一个奖励模型。这步的具体做法如下:
- 拿第一步训练好的SFT模型,让它针对一批新的指令,生成多个不同的回答。
- 让标注员对这几个回答进行排序,根据他们的偏好给出排名。这种排序的方式,本质上就是我们之前讨论的成对比较法。
- 收集大量这种包含了人类偏好排序的数据。
- 使用PPO算法进行强化学习 (Reinforcement Learning with PPO):我们将第一步得到的SFT模型作为初始策略,然后进入一个强化学习的循环:
- 从指令库中随机取一个指令,让当前策略模型生成一个回答。
- 将这个回答喂给第二步训练好的奖励模型,得到一个奖励分数 。
- 被用来计算一个梯度,然后通过PPO算法来更新策略模型的参数。
InstructGPT项目证明了,通过 “SFT → RM → RL”这套三步走的RLHF流程,可以有效地将一个庞大的、只懂语言知识的预训练模型,“对齐” (Align)到复杂、细致、多样的人类价值观和偏好上。
为了训练InstructGPT,OpenAI使用了下面的指令:
- 普通指令 :直接让标注员自由发挥,构思出任意类型的任务指令。
- 这是为了获取最广泛、最多样化的指令。标注员需要确保他们提出的任务五花八门,覆盖尽 可能多的领域和类型,避免数据单一。这就像一个“头脑风暴”式的收集过程。
- 少样本指令 (Few-shot):让标注员不仅提供一个指令,还要为这个指令提供多个“提问/回答”的范例。
- 这种格式旨在教会模型如何进行“上下文学习”或“少样本学习”。当模型看到一个包含范例的指令时,它能更好地理解任务的要求和期望的输出格式。例如,指令可能是“把句子翻译成法语”,后面会跟着几个“英语句子 -> 法语句子”的例子。
- 基于用户的指令:OpenAI分析了申请使用其API的用户的真实应用场景(Use-case)。然后,他们让标注员根据这些真实世界的需求来创造相应的指令。
- 这是最重要的一种数据来源。它确保了训练数据与用户的实际需求高度相关,从而让训练出的模型在解决真实问题时更有用。
和InstructGPT不同,ChatGPT 的训练数据从单轮的“指令-回答”全面转向了多轮的“对话”。ChatGPT训练的第二步和第三步,即RM的训练和最终的RL优化和InstructGPT也有一些区别:
- RM阶段的优化:与InstructGPT的不同,ChatGPT的比较和排序是针对对话中的某一步进行的,而不是像InstructGPT那样对一个指令的初始回复进行排序。这使得奖励模型能够更精细地学习到在对话的上下文中,什么样的回复是更好的。
- RL阶段的优化:ChatGPT会使用多次迭代 (Several iterations)来进行学习。这说明ChatGPT的训练不是一个线性的“SFT→RM→RL”过程,而是一个循环迭代、不断精进的过程。
3. PPO
PPO 由 OpenAI 在 2017 年提出,它的核心目标是解决传统策略梯度(Policy Gradient)算法中的一个关键痛点:更新步长难以确定。
PPO 的核心思想是:在“信赖域”内稳定更新。它设计了一个新颖的、更容易优化的目标函数(Objective Function),通过裁剪(Clipping)的方式来间接限制策略更新的幅度。
PPO 最核心、最常用的部分就是它的裁剪代理目标函数(Clipped Surrogate Objective Function)。它的详细工作流程如下:
首先,我们定义一个比率 :
这个公式衡量的是新策略 在状态 下选择动作 的概率,与旧策略 的概率之比:
- 如果 ,说明这个动作在新策略下变得更可能被选中。
- 如果 ,说明这个动作在新策略下变得更不可能被选中。
我们还需要一个概念叫做优势函数 。它衡量在状态 下,执行动作 到底有多好。
- 如果 ,说明 是一个好于平均的动作,我们应该鼓励它。
- 如果 ,说明 是一个差于平均的动作,我们应该抑制它。
PPO-Clip 的目标函数如下:
这里的关键是 和 这两个操作:
- 是一个很小的超参数,如 0.2。
- 的意思是把比率 强制“裁剪”并限制在 这个区间内。
这个目标函数是如何实现稳定更新的呢? 我们分两种情况讨论:
- 优势 为正(这是一个好动作)
- 我们希望增加这个动作的概率,也就是增大 。
- 此时目标函数变为 。
- 因为 是正数,所以 越大, 也越大。
- 但是 min 函数的存在给它加了一个“天花板”:目标函数的增长不会超过 。这就防止了我们因为一个特别好的动作,而让策略更新得过于“激动”,从而保证了稳定性。
- 优势 为负(这是一个坏动作)
- 我们希望减小这个动作的概率,也就是减小 。
- 此时目标函数变为 。
- 因为 是负数,所以这是一个“比谁更小”的游戏。
- 函数会把 限制在 以上。 函数会选择两者中更小(更负)的值作为最终的目标。这相当于对策略施加了一个更大的惩罚,阻止其变化过大。这同样也给策略的更新加了一个“地板”,防止因为一个坏动作而过度惩罚,导致策略剧烈变化。
通过这种巧妙的“软限制”,PPO既允许策略向好的方向更新,又防止了更新幅度过大,从而实现了稳定、高效的训练。
PPO 通常在 Actor-Critic (演员-评论家) 框架下实现:
- 数据收集 (Sampling):使用当前的策略(Actor)与环境交互,收集一批数据(状态、动作、奖励等)。
- 计算优势 (Advantage Estimation):对于收集到的每一步,用评论家(Critic)网络计算优势函数 的估计值。
- 多次优化 (Optimization):将收集到的一批数据重复使用,用梯度上升法对我们上面提到的 目标函数进行多轮(epochs)优化,更新策略网络(Actor)的参数。
- 重复:回到第一步,使用更新后的策略继续收集数据,循环往复,直到策略收敛。
数据复用是 PPO 相比于传统策略梯度算法的一个巨大优势,它显著提高了样本的利用效率。
4. DPO
DPO(Direct Preference Optimization)的理论基础是移除RLHF中的“RL”部分。我们知道RLHF的目标是最大化一个复合函数:。这需要通过迭代式的强化学习来求解。而研究者发现,上述这个优化问题有一个理论上的封闭解:可以直接写出最优策略 的数学表达式,而无需一步步地去迭代求解。
既然有了最优策略和奖励模型之间的直接关系,我们可以反过来,用下面的公式来定义奖励模型:
这意味着,奖励分数可以被隐式地定义为“最优策略”和“原始策略”在同一个回答上的概率比。我们不再需要一个独立训练出来的、显式的奖励模型了。
我们从训练奖励模型时使用的偏好损失函数出发:
然后我们将前面推导出的隐式奖励模型代入:
这样,我们不再需要 RM 或 RL。这个损失函数直接关联了我们正在优化的模型 和原始的参考模型 。
- 它的目标是:调整参数 ,使得对于人类偏好的“获胜”回答 ,给出的概率相对于 的增长幅度,要大于它在“落败”回答 上的增长幅度。
本质上,这个式子是在直接利用偏好数据,通过一个简单的分类损失,来优化语言模型本身。
Comments