【LLM】从零开始训练大模型EBET易博app

  新闻资讯     |      2023-09-28 10:12

  在这篇文章中,我们将尽可能详细地梳理一个完整的 LLM 训练流程。包括模型预训练(Pretrain)、Tokenizer 训练、指令微调(Instruction Tuning)、奖励模型(Reward Model)和强化学习(RLHF)等环节。由于内容比较多,我们将逐步整理并完善这个文档。

  当前,不少工作选择在一个较强的基座模型上进行微调,且通常效果不错(如:[alpaca]、[vicuna] 等)。

  这种成功的前提在于:预训练模型和下游任务的差距不大,预训练模型中通常已经包含微调任务中所需要的知识。

  但在实际情况中,我们通常会遇到一些问题,使得我们无法直接使用一些开源 backbone:

  大多数开源基座对中文的支持都不太友好,例如:[Llama]、[mpt]、[falcon] 等,这些模型在英文上效果都很优秀,但在中文上却差强人意。

  杭州西湖是杭州的一个静静的一个游泳池,游泳池是杭州西湖的一个游泳池,游泳池是杭州西湖的一个游泳池,游泳池是杭州西湖的一个游泳池,

  杭州西湖是中国最大的湖泊,是中国最大的湖泊,是中国最大的湖泊,是中国最大的湖泊,是中国最大的湖泊,是中国最大的湖泊,是中国最大的湖泊,

  琅琊榜的导演是很多的人都不知道,因为他的父亲是一位杰作家,他的父亲的杰作家是一位杰作家,

  琅琊榜的导演是谁?Who are the directors of the Rolling Stone?琅琊榜的导演是谁?Who are the

  2.专业知识不足:当我们需要一个专业领域的 LLM 时,预训练模型中的知识就尤为重要。由于大多数预训练模型都是在通用训练语料上进行学习,对于一些特殊领域(金融、法律等)中的概念和名词无法具备很好的理解。我们通常需要在训练语料中加入一些领域数据(如:[xuanyuan 2.0]),以帮助模型在指定领域内获得更好的效果。

  基于上述原因,我们在进行 SFT 步骤之前,先来看看预训练任务是如何做的。

  因此,许多工作都尝试将在英语上表现比较优秀的模型用中文语料进行二次预训练,期望其能够将英语上的优秀能力迁移到中文任务中来。

  通俗来讲,tokenizer 的目的就是将一句话进行切词,并将切好词的列表喂给模型进行训练。

  WordPiece 很好理解,就是将所有的「常用字」和「常用词」都存到词表中,

  当遇到词表中不存在的字词时,tokenizer 会将其标记为特殊的字符 [UNK]:

  WordPiece 的方式很有效,但当字词数目过于庞大时这个方式就有点难以实现了。

  对于一些多语言模型来讲,要想穷举所有语言中的常用词(穷举不全会造成 OOV),

  BPE 不是按照中文字词为最小单位,而是按照unicode 编码作为最小粒度。

  因为平时我们不会拆开来看(毕竟中文汉字是不可拆分的),所以我一开始对这个概念也不太熟悉。

  通过 token 查找功能,我们可以发现「编」「码」在词表中,但「待」不在词表中。

  但任何 1 个汉字都是可以由 unicode 表示(只是组合顺序不同),因此「待」就被切成了 3 个 token。

  通常在模型训练不够充足的时候,模型会输出一些乱码(不合法的 unicode 序列):

  也就是将一些常见的汉字 token 手动添加到原来的 tokenizer 中,从而降低模型的训练难度。

  最后再在 3.2B 的中文语料上对这部分新扩展的 token embedding 做二次预训练。

  在扩充完 tokenizer 后,我们就可以开始正式进行模型的预训练步骤了。

  我们主要来讨论几种预训练过程中所用到的方法:数据源采样、数据预处理、模型结构。

  在 [gpt3] 的训练过程中,存在多个训练数据源,论文中提到:对不同的数据源会选择不同采样比例:

  通过「数据源」采样的方式,能够缓解模型在训练的时候受到「数据集规模大小」的影响。

  从上图中可以看到,相对较大的数据集(Common Crawl)会使用相对较大的采样比例(60%),

  这个比例远远小于该数据集在整体数据集中所占的规模(410 / 499 = 82.1%),

  而对于规模比较小的数据集(Wikipedia),则将多被训练几次(3.4 个 epoch)。

  这样一来就能使得模型不会太偏向于规模较大的数据集,从而失去对规模小但作用大的数据集上的学习信息。

  通常来讲,在 Finetune 任务中,我们通常会直接使用 truncation 将超过阈值(2048)的文本给截断,

  以书籍数据为例,一本书的内容肯定远远多余 2048 个 token,但如果采用头部截断的方式,

  则每本书永远只能够学习到开头的 2048 tokens 的内容(连序章都不一定能看完)。

  因此,最好的方式是将长文章按照 seq_len(2048)作分割,将切割后的向量喂给模型做训练。

  为了加快模型的训练速度,通常会在 decoder 模型中加入一些 tricks 来缩短模型训练周期。

  在继续预训练中,我们通常会使用 warmup 策略,此时我们按照 2 种不同情况划分:

  中文预训练数据集可以使用 [悟道],数据集分布如下(主要以百科、博客为主):

  但开源数据集可以用于实验,如果想突破性能,则需要我们自己进行数据集构建。

  仅使用「清洗后的互联网数据」就能够让模型比在「精心构建的数据集」上有更好的效果,

  可以简单理解为在生成结果和目标文本之间的 Cross Entropy Loss 上做了一些处理。

  大部分 LLM 都具备生成流畅和通顺语句能力,很难比较哪个好,哪个更好。

  一个很好的中文知识能力测试数据集是 [C-Eval],涵盖1.4w 道选择题,共 52 个学科。

  并让模型续写 1 个 token,判断这个续写 token 的答案是不是正确答案即可。

  但大部分没有精调过的预训练模型可能无法续写出「A B C D」这样的选项答案,

  于是,我们获得模型续写后的第一个 token 的概率分布(logits),

  并取出「A B C D」这 4 个字母的概率,通过 softmax 进行归一化:

  由于预训练任务的本质在于「续写」,而「续写」的方式并一定能够很好的回答用户的问题。

  因为训练大多来自互联网中的数据,我们无法保证数据中只存在存在规范的「一问一答」格式,

  但是,这并不代表预训练模型「无知」,只是需要我们用一些巧妙的「技巧」来引导出答案:

  既然模型知道这些知识,只是不符合我们人类的对话习惯,那么我们只要再去教会模型「如何对话」就好了。

  那么我们就需要去精心编写各式各样人们在对话中可能询问的问题,以及问题的答案。

  如果这件事从头开始做自然很难(OpenAI 确实厉害),但今天我们已经有了 ChatGPT 了,

  Instruction Tuning 中的「输入」(问题)和「输出」(答案)是训练模型的关键,

  (靠人想太累了,屏幕前的你不妨试试,看看短时间内能想出多少有价值的问题)

  Alpaca 则是使用「种子指令(seed)」,使得 ChatGPT 既生成「问题」又生成「答案」。

  由于 Alpaca 是英文项目,为了便于理解,我们使用相同思路的中文项目 [BELLE] 作为例子。

  紧接着利用 ChatGPT 的续写功能,让其不断地举一反三出新的训练数据集:

  点叫醒你或设置提醒,因为它无法执行任何操作。例如,指令不应该和音频、视频、图片、链接相关,因为

  你应该给指令生成适当的输入,输入字段应包含为指令提供的具体示例,它应该涉及现实数据,不应包含简单的占位符。输入应提供充实的内容,使指令具有挑战性。

  并非所有指令都需要输入。例如,当指令询问一些常识信息,比如“世界上最高的山峰是什么”,不需要提供具体的上下文。在这种情况下,我们只需在输入字段中放置“

  ”。当输入需要提供一些文本素材(例如文章,文章链接)时,就在输入部分直接提供一些样例。当输入需要提供音频、图片、视频或者链接时,则不是满足要求的指令。

  如果是在晚上,我通常会考虑我今天所取得的进步,如果是在早上,我会思考如何做到最好。我也会尝试练习感恩和活在当下的状态,以避免分心驾驶。

  如上述例子所示,我们先给出 2 个样例,并让 ChatGPT 进行续写:

  在这一章中,我们将梳理一些开源的 Instruction Tuning 的数据集,

  除了直接拿来用以外,我们期望通过分析这些已有数据集,从而学习如何构建一个指令数据集。

  由于数据量很大,我们无法统计出训练数据集中各任务的线条评测集] 数据分布可以推测出,训练数据集中同样包含:摘要、问答、分类等任务。

  从以下选项中选择正确的词汇填空以完整下面的句子。 他喜欢去_______看电影。A) 邮局 B)超市 C)电影院 D)音乐会

  据媒体新闻援引美国福克斯新闻网报道,美国伯克希尔哈撒韦公司首席执行官、著名投资人巴菲特近日就美国银行业危机与总统拜登的团队进行对话。

  根据提供的文本重写其中的一段,使之更加简明扼要,同时不丢失原文本的主要信息。

  纽约市,简称“纽约”,通常被称为“大苹果”,是美国最大的城市,也是全世界最大的城市之一。位于美国东海岸,东北部边界是大西洋,在新泽西州的东南部。

  小明是一个好学生,每天早上都要起得很早去上学。有一天,他迟到了,因为他的家里来了一个客人。晚上,他参加了一次班级会议,会议主题是如何提高学习效率。回到家后,他又花了一些时间复习功课。

  按照以下要求,写一个SQL查询语句:从表中查找所有性别为女性的学生的姓名和学号。

  SELECT name, id FROM students WHERE gender = 女性

  比起预训练(Pretrain)环节里相对明确的评价指标(如PPL、NLL等),

  鉴于语言生成模型的发展速度,BLEU 和 ROUGH 这样的指标已经不再客观。

  一种比较流行的方式是像 [FastChat] 中一样,利用 GPT-4 为模型的生成结果打分,

  GPT-4 会对每一条测试样本的 2 个答案分别进行打分,并给出打分理由:

  并不一定正确。如上图所示,GPT-4 为右边模型的答案打出了更高的分数,给出的理由是:

  为此,我们通过人工的 Review 的方式对每个答案进行了一次回扫,得到的结果和标准如下:

  再次重申:我们只是期望指出 GPT-4 打分可能会和实际产生偏差的问题,

  在 GPT-4 打分的结果中,已经有模型的效果甚至超过了 ChatGPT(分数为 1.02),

  但再经过人工 Review 后,ChatGPT 的答案是我们认为更合理一些的。

  因此如果只是想了解 reward model 基本概念的话可以参考这篇文章:

  我们一直都在告诉模型什么是「好」的数据,却没有给出「不好」的数据。我们更倾向于 SFT 的目的只是将 Pretrained Model 中的知识给引导出来的一种手段,EBET易博

  这将导致预训练模型中原先「错误」或「有害」的知识没能在 SFT 数据中被纠正,

  为此,一些让模型脱离昂贵标注数据,自我进行迭代的方法被提出,比如:[RLHF],[DPO],

  但无论是 RL 还是 DPO,我们都需要让告知模型什么是「好的数据」,什么是「不好的数据」。

  RL 是直接告诉模型当前样本的(好坏)得分,DPO 是同时给模型一条好的样本和一条坏的样本。

  我们使用 [llama-2-7b] 作为基座模型训练,期望模型对于 A 回答能够给尽可能高的分,B 回答则尽可能低。

  在 step 0(未训练)时,模型打出来的分差是一个近似均值为 0,方差为 0.1 的正态分布,

  随着模型训练,分布均值从 0 开始逐渐增长,这证明模型开始逐渐让「好数据」 - 「坏数据」的分差越来越大。

  ] 偏序对进行训练。从上述工作中,我们仍无法总结出一个稳定模型需要的最小量级,这取决于具体任务。

  不过,一种直觉的理解是:判分任务要比生成认为简单一些,因此可以用稍小一点的模型来作为 RM。