预训练阶段(Pretraining Stage)
Pretraining 的思路很简单,就是输入一堆文本,让模型做 Next Token Prediction 的任务
数据源采样
通过「数据源」采样的方式,能够缓解模型在训练的时候受到「数据集规模大小」的影响。对于相对较大的数据集(Common Crawl)会使用相对较大的采样比例(60%),而对于规模比较小的数据集(Wikipedia),则将多被训练几次(3.4 个 epoch)。这样一来就能使得模型不会太偏向于规模较大的数据集,从而失去对规模小但作用大的数据集上的学习信息。
数据预处理
数据预处理主要指如何将「文档」进行向量化。通常来讲,在 Finetune 任务中,我们通常会直接使用 truncation 将超过阈值(2048)的文本给截断,但在 Pretrain 任务中,这种方式显得有些浪费。以书籍数据为例,一本书的内容肯定远远多余 2048 个 token,但如果采用头部截断的方式,则每本书永远只能够学习到开头的 2048 tokens 的内容(连序章都不一定能看完)。因此,最好的方式是将长文章按照 seq_len(2048)作分割,将切割后的向量喂给模型做训练。
模型结构
- 为了加快模型的训练速度,通常会在 decoder 模型中加入一些 tricks 来缩短模型训练周期。目前大部分加速 tricks 都集中在 Attention 计算上(如:MQA 和 Flash Attention 等);
- 为了让模型能够在不同长度的样本上都具备较好的推理能力,通常也会在 Position Embedding 上进行些处理,选用 ALiBi([Bloom])或 RoPE([GLM-130B])等。
指令微调阶段
- 由于预训练任务的本质在于「续写」,而「续写」的方式并一定能够很好的回答用户的问题。因为训练大多来自互联网中的数据,我们无法保证数据中只存在存在规范的「一问一答」格式,这就会造成预训练模型通常无法直接给出人们想要的答案。
- Self Instruction 的思路,即通过 ChatGPT 的输入输出来蒸馏自己的模型。
- 开源数据集有:Alpaca、BELLE、Vicuna、BAIZE
奖励模型
Reward 模型基于 SFT 模型进行初始化
奖励模型的必要性
- 其实,当我们在做完 SFT 后,我们大概率已经能得到一个还不错的模型。但我们回想一下 SFT 的整个过程:我们一直都在告诉模型什么是「好」的数据,却没有给出「不好」的数据。我们更倾向于 SFT 的目的只是将 Pretrained Model 中的知识给引导出来的一种手段,而在SFT 数据有限的情况下,我们对模型的「引导能力」就是有限的。这将导致预训练模型中原先「错误」或「有害」的知识没能在 SFT 数据中被纠正,从而出现「有害性」或「幻觉」的问题。
- 为此,一些让模型脱离昂贵标注数据,自我进行迭代的方法被提出,比如:[RLHF],[DPO],但无论是 RL 还是 DPO,我们都需要让告知模型什么是「好的数据」,什么是「不好的数据」。RL 是直接告诉模型当前样本的(好坏)得分,DPO 是同时给模型一条好的样本和一条坏的样本。而判断样本数据的「好坏」除了昂贵的人工标注之外,那就是 Reward Model 大显身手的时候了。
利用偏序对训练奖励模型
偏序对是指不直接为每一个样本直接打分,而是标注这些样本的好坏顺序。模型通过尝试最大化「好句子得分和坏句子得分之间的分差」,从而学会自动给每一个句子判分。
强化学习
Direct Preference Optimisation(DPO)
DPO 相比 PPO 阶段的 reward 模型的 acurracy 是下降的,DPO 效果相比 PPO 可能会下降,这可能也是大模型还没广泛应用 DPO 的原因。
Proximal Policy Optimization(PPO)
- 在 LLM 的训练中,使用 PPO 需要同时载入 4 个模型:
- Actor Model:真正优化的,需训练
- Critic Model:评估的,需训练
- Ref Model:SFT 模型,通过 KL 来限制 Actor 模型的训练方向,无需训练
- Reward Model:上一步获得的奖励模型,用于指导 Actor 无需训练
- PPO 的训练目标如下:第一项的 reward 要尽可能大,同时第二项与 SFT 模型的偏移尽可能小
- 为了节省显存,通常会将 actor / critic 共享一个 backbone,这样只用同时载入 3 个模型。PPO 以其「训练过程不稳定」和「效果不稳定」著称,而且十分消耗资源