LLM 微调 之 InstructGPT中的微调与对齐
LLM 我们不一定要预训练模型,但是一定要会微调。InstructGPT更是微调的最经典的文章。这里详细介绍InstructGPT的微调技术。
技术概览
InstructGPT中的微调与对齐
InstructGPT 里面提到LLM的微调技术, 分为2个阶段:
- 指令微调:使得模型有指令遵循的能力
- 对齐微调:对齐人类价值观
大体步骤
在GPT3/3.5的基础上,要解决的问题是 跟人类期待匹配。 最直接的方法就是人工构造一批数据(人类自己写prompt 和 期望的输出) 然后交给模型去学习,使得模型学到人类期望输出。但是这个代价太大,人类自己写prompt和答案 构造者个数据集 代价太大。
所以才有了微调和对齐模型,大体步骤如下:
- 有监督微调SFT: 我们称原始模型为V0,也就是GPT-3。人工先构造一批数据,数据量不用很大,先让模型学一学,得到模型V1(SFT) 让模型有基本指令遵循能力。
- 人类偏好对齐:(Reward model + PPO) 持续重复进行。
- 人类偏好对齐用强化学习的方式来微调模型,输入prompt 输出几个答案,人类对答案进行评价反馈(相当于环境反馈),模型根据评价的结果来继续优化,反复迭代使得最后模型输出符合人类偏好。
- 那么问题是人类如何反馈,这套机制如何建立? Reward Model 奖励模型。
- 最直接的方法肯定是 输入prompt 模型有几个输出,然后人类给每个输出打出高低分数,模型收到评价 再反向传播迭代更新。人类在根据更新后的模型,输入prompt 等新模型输出 再打分,模型再迭代。
- 但是人类不可能在模型前面等他输出一个个打分的。所以这里需要一个自动评分的模型 替代人类做 反馈。 于是就有了 reward model 这个模型输入就是prompt和模型的answer,是输出是得分。
- 为了得到这个RM模型,制作训练集,让模型对一个prompt输出多个答案,然后人类对这个答案进行打分排序。打分排序比自己写训练数据要方便多了,从而得到更多的标注数据(prompt,answer,score).
- 用这个训练集 来训练RM model,作用是对 prompt和answer pair 进行打分,评价这个pair是否搭配。
- 有了打分模型,接下来就要微调第一步得到的SFT(V1)模型。采用PPO方法
- 这里给定一些prompt,得到输出,把prompt和输出 一起给RM 模型,得到打分(外界环境的反馈),然后借助强化学习的方法,训练SFT,反复迭代最终得到V2模型也就是InstructGPT.
步骤 1 只进行一次,而步骤Reward model 和PPO算法可以持续重复进行:在当前最佳策略模型上收集更多的比较数据,用于训练新的 RM 模型,然后训练新的策略。
标注数据量
上述三个步骤分别制造和标注了多少样本呢?
- SFT 数据,第一步分类根据prompt自己写理想输出,SFT supervised fine tuning 有13k的prompt.(人工标注的占比高一些,11.3k,API 1.5k)
- RewardModel数据,第二步用来训练打分模型的数据,包含33k的prompts
- PPO数据,第三步用来训练强化学习PPO模型的数据,包含31k的prompts。
其中前2步的prompts 来自OpenAI的 API上用户使用数据和人工标注写的数据,最后一步全是从API上采样的数据。(第一步人工占比高,第二步人工占比低)。
初始种子数据集:需要标注者来编写prompts。
- plain:自己随便想一些prompts,同时尽可能保证任务多样性。(各种问题和要求)
- Few-shot: 不仅仅需要写prompts,还需要写对应的outputs(这部分是最耗人力的,也就是SFT的主要组成)
- User-based: 标注者根据openAI的waitlist里面的task 来编写一些prompts(相当于告诉标注人员,用户期待的功能,你们来写prompt 答案)
API中的数据
模型训练
这里面3个步骤 分别是如何训练的呢?
1. SFT 是如何训练的
- 训练数据: SFT是有监督的微调,训练数据是通过给定一个提示列表,人工写对应的输出得到的。大概13k左右。这里面的提示列表有来自人工自己写的也有API收集的。(这一步主要为了让模型有指令遵循的能力,人工写的比例高一些,因为API很多数据都是扩写 不使用这个任务。)
- 模型初始化:InstructGPT 是从GPT3初始化的,chatGPT是从GPT3.5初始化的。
- 训练:在Fine-tuning的过程中同样采用自回归的方式,将Prompt和对应的label answer串联在一起进行训练(下一个词预测训练目标)。
这一步finetuning时,1个epoch就已经overfit了 但是由于这个不是最终的模型,并且train epoch越多对后面两步越有帮助,所以train了16个epoch。
由于该步骤的数据量也有限,该过程获得的 SFT 模型可能会输出仍然并非用户关注的文本,并且通常会出现不一致问题。这里的问题是监督学习步骤的 可扩展性成本高 不可能让标注人员把所有的问题都写一遍。
所以需要让模型学到人类的喜爱偏好(训练出一个RM模型作为机器裁判从而代替人类当裁判) 也就是使用的策略是让人工标注者对 SFT 模型的不同输出进行排序以创建 RM 模型,而不是让人工标注者创建一个更大的精选数据集
2. Reward Model是如何训练的
- 初始化: OpenAI使用了指令微调16个epoch的6B模型作为奖励模型的初始模型。通过『移除了最后一层unembedding layer的上一阶段的SFT模型』初始化出我们的RM模型,且考虑到175B计算量大且不稳定不适合作为奖励函数,故最后用的6B版本的SFT初始化RM模型。
- 模型训练:训练方式是两两对比计crossentropy(其实就是logist 二分类损失,这里是两两组合),其中rθ 是奖励函数对指令x和回复y的打分,如下 (a>b>c) 两两组合 计算loss
l o s s ( θ ) = − 1 ( 2 k ) E ( x , y w , y l ) D [ l o g ( σ ( r θ ( x , y w ) − r θ ( x , y l ) ) ) ] loss(\theta) = -\frac{1}{(^k_2)} E_{(x,y_w,y_l)~D}[log(\sigma(r_{\theta}(x,y_w) - r_{\theta}(x,y_l)))] loss(θ)=−(2k)1E(x,yw,yl) D[log(σ(rθ(x,yw)−rθ(x,yl)))]
-
数据收集:让阶段1的SFT模型回答来自OpenAI API和labeler-written且规模大小为33k的数据集的一些问题比如 x n + 1 x_{n+1} xn+1,接着针对每个问题收集4-9个不同的模型输出从而获取4-9个回答。
为什么模型会有多个回答呢?在于模型每次预测一个词都有对应的概率,根据不同的概率大小可以采样出很多答案,比如通过beam search保留k个当前最优的答案(beam search相当于贪心算法的加强版,除了最好的答案外,还会保留多个比较好的答案供选择)。
人工对这4-9个回答的好坏进行标注且排序,排序的结果用来训练一个奖励模型RM,具体做法就是学习排序结果从而理解人类的偏好。 对于标注者来说,对输出进行排序比从头开始打标要容易得多,这一过程可以更有效地扩展。在实践中,所选择的 prompt 的数量大约为 30-40k,并且包括排序输出的不同组合。
-
训练技巧:OpenAI发现如果对数据进行Shuffle,则训练一轮就会过拟合,但如果把针对1个指令模型的K个回复,K在4~9之间,得到 C K 2 C^2_K CK2 个pairwise对,放在一个batch里进行训练,会得到显著更高的准确率。这里一个batch包括64个指令生成的所有回复对,其中排名相同的样本对被剔除。这里感觉和对比学习要用大batch_size进行拟合的思路有些相似,是为了保证对比的全面性和充分性,使用全面对比后计算的梯度对模型进行更新。另一个原因可能是不同标注人员之间的偏好差异,shuffle之后这种偏好差异带来的样本之间的冲突性更高。
3. RLHF 是如何训练的
大体步骤:
- 首先 初始化PPO模型,
- 然后 让PPO模型去回答问题(这些问题没有人类标注,都是新问题)此时不用人工评估,而是让阶段二的RM来对结果进行打分,进而进行排序。
- 之后,通过不断更大化奖励而优化PPO模型的生成策略(因为生成策略更好,模型的回答便会更好),策略优化的过程中使用PPO算法限制策略更新范围
- 最后,根据优化后的策略再次生成 -> RM再评估 -> 模型再优化后再生成,如此循环进行,直到策略最优为止.
o b j e c t i v e ( ∅ ) = E ( x , y ) D π ∅ R L [ r θ ( x , y ) − β l o g ( π ∅ R L ( y ∣ x ) / π S F T ( y ∣ x ) ) ] + γ E x D p r e t r a i n [ l o g ( π ∅ R L ( x ) ) ] objective(\varnothing) = E_{(x,y)~D_{\pi_{\varnothing}RL}}[r_\theta(x,y) - \beta log(\pi_{\varnothing}^{RL}(y|x)/\pi^{SFT}(y|x))] + \gamma E_{x~D_{pretrain}}[log(\pi_{\varnothing}^{RL}(x))] objective(∅)=E(x,y) Dπ∅RL[rθ(x,y)−βlog(π∅RL(y∣x)/πSFT(y∣x))]+γEx Dpretrain[log(π∅RL(x))]
在RL微调的部分,OpenAI使用了PPO算法,基于Reward模型的打分进行微调,微调了2个epoch。在此基础上加入了两个目标:
- 微调模型和原始模型在token预测上的KL散度,避免模型过度拟合奖励函数偏离原始模型。后面也论证了KL的加入,可以加速RL收敛,核心是在相同的KL下最大化模型偏好的提升
- 10%的预训练目标(PPO-PTX): 降低RL对模型语言能力的影响
且论文提到样本的收集和RL训练是多次迭代的,也就是使用RL微调后的模型上线收集更多的用户请求,重新训练RM,再更新模型。不停在优化后