关注微信公众号掌握更多技术动态
---------------------------------------------------------------
一、大模型原理
1.Transformer
(1)求知之路:LLM 学到了什么知识
LLM 从海量自由文本中学习了大量知识,如果把这些知识做粗略分类的话,可以分为语言类知识和世界知识两大类。
- 语言类知识指的是词法、词性、句法、语义等有助于人类或机器理解自然语言的知识。各种研究也证明了浅层语言知识比如词法、词性、句法等知识存储在 Transformer 的低层和中层,而抽象的语言知识比如语义类知识,广泛分布在 Transformer 的中层和高层结构中。
- 世界知识指的是在这个世界上发生的一些真实事件(事实型知识,Factual Knowledge),以及一些常识性知识 (Common Sense Knowledge)。于 LLM 模型能否学习世界知识的研究也有很多,结论也比较一致:LLM 确实从训练数据中吸收了大量世界知识,而这类知识主要分布在 Transformer 的中层和高层,尤其聚集在中层。而且,随着 Transformer 模型层深增加,能够学习到的知识数量逐渐以指数级增加。其实,你把 LLM 看作是一种以模型参数体现的隐式知识图谱,如果这么理解,我认为是一点问题也没有的。
从增量的训练数据中学到的更主要是世界知识。
(2)记忆之地:LLM 如何存取知识
显然,知识一定存储在 Transformer 的模型参数里。从 Transformer 的结构看,模型参数由两部分构成:多头注意力(MHA)部分占了大约参数总体的三分之一,三分之二的参数集中在 FFN 结构中。MHA 主要用于计算单词或知识间的相关强度,并对全局信息进行集成,更可能是在建立知识之间的联系,大概率不会存储具体知识点,那么很容易推论出 LLM 模型的知识主体是存储在 Transformer 的 FFN 结构里。
但这样的定位,粒度还是太粗,无法很好回答具体某条知识是如何存储与提取的,比如 “中国的首都是北京” 这条知识,以三元组表达就是 < 北京,is-capital-of,中国 >,其中 “is-capital-of” 代表实体间关系。这条知识它存储在 LLM 的哪里呢?
(3)知识涂改液:如何修正 LLM 里存储的知识
- 第一类方法从训练数据的源头来修正知识。“Towards Tracing Factual Knowledge in Language Models Back to the Training Data” 这篇文章的研究目标是:对于指定的某条知识,我们是否可以定位到是哪些训练数据导致 LLM 学会了这条知识?答案是肯定的,这意味着我们可以逆向追踪到某条知识对应的训练数据源头。如果利用这项技术,假设我们想要删除某条知识,则可首先定位到其对应的数据源头,删除数据源,然后重新预训练整个 LLM 模型,这样即可达成删除 LLM 中相关知识的目的。但是这里有个问题,如果修正一小部分知识,我们就需要重新做一次模型预训练,这样做明显成本太高。所以这种方法不会太有发展前景,可能比较适合那种对于某个特定类别数据的一次性大规模删除场合,不适合少量多次的常规知识修正场景,比如可能比较适合用来做去除偏见等去 toxic 内容的处理。
- 第二类方法是对 LLM 模型做一次 fine-tuning 来修正知识。一个直观能想到的方法是:我们可以根据要修正成的新知识来构建训练数据,然后让 LLM 模型在这个训练数据上做 fine-tuning,这样指导 LLM 记住新的知识,遗忘旧的知识。这个方法简单直观,但是也有一些问题,首先它会带来灾难遗忘问题,就是说除了忘掉该忘的知识,还忘掉了不该忘的知识,导致这么做了之后有些下游任务效果下降。另外,因为目前的 LLM 模型规模非常大,即使是做 fine-tuning,如果次数频繁,其实成本也相当高。对这种方法感兴趣的可以参考 “Modifying Memories in Transformer Models”。
- 另外一类方法直接修改 LLM 里某些知识对应的模型参数来修正知识。假设我们想要把旧知识 < 英国,现任首相,鲍里斯 >,修正到 < 英国,现任首相,苏纳克 >。首先我们想办法在 LLM 模型参数中,定位到存储旧知识的 FFN 节点,然后可以强行调整更改 FFN 中对应的模型参数,将旧知识替换成新的知识。可以看出,这种方法涉及到两项关键技术:首先是如何在 LLM 参数空间中定位某条知识的具体存储位置;其次是如何修正模型参数,来实现旧知识到新知识的修正。关于这类技术的细节,可以参考 “Locating and Editing Factual Associations in GPT” 和 “Mass-Editing Memory in a Transformer”。理解这个修正 LLM 知识的过程,其实对于更深入理解 LLM 的内部运作机制是很有帮助的。
2.规模效应
(1)当 LLM 越来越大时会发生什么
预训练模型的应用往往是两阶段的:预训练阶段,及具体场景应用阶段。在预训练阶段,其优化目标是交叉熵,对 GPT 这种自回归语言模型来说,也就是看 LLM 是否正确预测到了下一个单词;而场景应用阶段,一般要看具体场景的评价指标。一般我们的直觉是:如果 LLM 模型在预训练阶段的指标越好,自然它解决下游任务的能力就越强。然而,事实并非完全如此。现有研究已证明,预训练阶段的优化指标确实和下游任务表现出正相关关系,但是并非完全正相关。也就是说,只看预训练阶段的指标,来判断一个 LLM 模型是否够好,这是不够的。基于此,我们分头来看在这两个不同阶段,随着 LLM 模型增大,有什么影响。
首先,我们先看在预训练阶段,随着模型规模逐步增大,会发生什么。OpenAI 在 “Scaling Laws for Neural Language Models” 中专门研究了这个问题,并提出 LLM 模型所遵循的 “伸缩法则”(scaling law)。如上图所示,这个研究证明:当我们独立增加训练数据量、模型参数规模或者延长模型训练时间(比如从 1 个 Epoch 到 2 个 Epoch),预训练模型在测试集上的 Loss 都会单调降低,也就是说模型效果越来越好。
既然三个因素都重要,那么我们在实际做预训练的时候,就有一个算力如何分配的决策问题:假设用于训练 LLM 的算力总预算(比如多少 GPU 小时或者 GPU 天)给定,那么是应该多增加数据量、减少模型参数呢?还是说数据量和模型规模同时增加,减少训练步数呢?此消彼长,某个要素规模增长,就要降低其它因素的规模,以维持总算力不变,所以这里有各种可能的算力分配方案。最终 OpenAI 选择了同时增加训练数据量和模型参数,但是采用早停策略 (early stopping) 来减少训练步数的方案。因为它证明了:对于训练数据量和模型参数这两个要素,如果只单独增加其中某一个,这不是最好的选择,最好能按照一定比例同时增加两者,它的结论是优先增加模型参数,然后才是训练数据量。假设用于训练 LLM 的算力总预算增加了 10 倍,那么应该增加 5.5 倍的模型参数量,1.8 倍的训练数据量,此时模型效果最佳。
这带给我们如下启示:我们可以选择放大训练数据,并同比例地减少 LLM 模型参数,以达到在不降低模型效果的前提下,极大缩小模型规模的目的。缩小模型规模有很多好处,比如在应用的时候,推理速度会快很多等,无疑这是一个很有前途的 LLM 发展路线。
以上是从预训练阶段来看模型规模的影响,如果从 LLM 解决下游具体任务效果的角度来看,随着模型规模增大,不同类型的任务有不同的表现,具体而言,有以下三类情况。
第一类任务完美体现了 LLM 模型的 scaling law,就是说随着模型规模逐步放大,任务的表现越来越好。这类任务通常符合如下共性:它们往往都是知识密集型任务,也就是说如果 LLM 模型包含的知识量越多,这类任务表现越好。而很多研究已经证明越大的 LLM 模型学习效率越高,也就是说相同训练数据量,模型越大任务效果越好,说明面对的即使是同样的一批训练数据,更大的 LLM 模型相对规模小一些的模型,从中学到了更多的知识。更何况一般情况下,在增大 LLM 模型参数的时候,往往会同步增加训练数据量,这意味着大模型可以从更多数据中学习更多的知识点。这些研究可以很好地解释上图,为何随着模型规模增大,这些知识密集型的任务效果越来越好。大多数传统的自然语言理解类任务,其实都属于这种知识密集型任务,而很多任务在近两年获得了极大的效果提升,甚至超过了人类表现。很明显,这大概率是 LLM 模型的规模增长带来的,而非归功于某项具体的技术改进。
第二类任务展现出 LLM 具备某种 “涌现能力(Emergent Ability)”,如上图(b)所示。所谓 “涌现能力”,指的是当模型参数规模未能达到某个阀值时,模型基本不具备解决此类任务的任何能力,体现为其性能和随机选择答案效果相当,但是当模型规模跨过阀值,LLM 模型对此类任务的效果就出现突然的性能增长。也就是说,模型规模是解锁 (unlock) LLM 新能力的关键,随着模型规模越来越大,会逐渐解锁 LLM 越来越多的新能力。这是个很神奇的现象,因为它意味着如下让人对未来可报乐观预期的可能:或许很多任务,目前 LLM 还不能很好地解决,甚至站在现在这个时刻的我们看起来,LLM 完全没有能力解决这类任务,但因 LLM 具备 “涌现能力”,所以如果我们继续推大模型,也许某一天它的这项能力就被突然解锁了。LLM 模型的规模增长会给我们带来意想不到的精彩礼物。
问题是,为何 LLM 会出现这种 “涌现能力” 现象呢?上述文章以及 “Emergent Abilities of Large Language Models” 给出了几个可能的解释:
一种可能解释是有些任务的评价指标不够平滑。比如说有些生成任务的判断标准,它要求模型输出的字符串,要和标准答案完全匹配才算对,否则就是 0 分。所以,即使随着模型增大,其效果在逐步变好,体现为输出了更多的正确字符片段,但是因为没有完全对,只要有任何小错误都给 0 分,只有当模型足够大,输出片段全部正确才能得分。也就是说,因为指标不够平滑,所以不能体现 LLM 其实正在逐步改善任务效果这一现实,看起来就是 “涌现能力” 这种外在表现。
另外一种可能的解释是:有些任务由若干中间步骤构成,随着模型规模增大,解决每个步骤的能力也在逐步增强,但是只要有一个中间步骤是错的,最终答案就是错的,于是也会导致这种表面的 “涌现能力” 现象。
还有少部分任务,随着模型规模增长,任务的效果曲线展现出 U 形特性:随着模型规模逐渐变大,任务效果逐渐变差,但是当模型规模进一步增长,则效果开始越来越好,呈现出 U 形增长趋势,如上图所示的粉红色 PaLM 模型在两个任务上的指标走势。为何这些任务表现得如此特殊呢?“Inverse scaling can become U-shaped” 这篇文章给出了一种解释:这些任务,内部其实隐含了两种不同类型的子任务,一种是真正的任务,另外一种是 “干扰任务(distractor task)”。当模型规模小的时候,无法识别任意一种子任务,所以模型的表现跟随机选择答案差不多,当模型增长到中等规模的时候,主要执行的是干扰任务,所以对真正的任务效果有负面影响,体现为真正任务效果的下降,而当进一步增加模型规模,则 LLM 可以忽略干扰任务,执行真正的任务,体现为效果开始增长。
对于那些随着模型规模增大,效果一直下降的任务,如果采用思维链(CoT)Prompting,则部分任务的表现转换为遵循 Scaling law,即模型规模越大效果越好,而其它任务则转换为 U 性增长曲线。这其实侧面说明了:此类任务应属于推理类型的任务,所以加入 CoT 后任务表现会发生质的变化。
(2)模型应该多大才够?
两个数字:62B 和 175B。
- 模型至少需要 62B,使思维链的效果才能大于标准的提示词方法。
- 模型至少需要 175B(GPT3 的尺寸),思维链的效果才能大于精调小模型(T5 11B)的效果。
(3)规模是唯一的因素
规模是一个必要但不充分的因素。有些模型足够大(比如 OPT 和 BLOOM,都是 175B),但并不能做思维链。
有两种模型可以做思维链:
- GPT3 系列的模型,包括 text-davinci-002 和 code-davinci-002 (Codex)。
这是仅有的两个具有强大突现能力并可公开访问的模型。
- 除了以上两个模型,其他 GPT3 模型,包括原来的 GPT3,text-davinci-001,以及其他更小的 GPT-3 模型,都不能做思维链。
- 当说 “能做思维链” 时,我们是指使用思维链方法的效果比直接用提示词、精调 T5-11B 效果更好。
- 另外要注意的是,code-davinci-002 在
语言任务上的性能始终优于[34] text-davinci-002。这个观察非常有趣且耐人寻味。这表明基于代码数据训练的语言模型可以胜过根据语言训练的语言模型。目前为止我们还不知道是为什么。
- PaLM 系列模型,包括 PaLM、U-PaLM、Flan-PaLM 和 Minerva。这些模型目前还未开放访问。
3.人机接口:从 In Context Learning 到 Instruct 理解
一般我们经常提到的人和 LLM 的接口技术包括:zero shot prompting、few shot prompting、In Context Learning,以及 Instruct。这些其实都是表达某个具体任务的描述方式。其中 Instruct 是 ChatGPT 的接口方式,就是说人以自然语言给出任务的描述,比如 “把这个句子从中文翻译成英文”,类似这种。zero shot prompting 我理解其实就是现在的 Instruct 的早期叫法,以前大家习惯叫 zero shot,现在很多改成叫 Instruct。尽管是一个内涵,但是具体做法是两种做法。早期大家做 zero shot prompting,实际上就是不知道怎么表达一个任务才好,于是就换不同的单词或者句子,反复在尝试好的任务表达方式,这种做法目前已经被证明是在拟合训练数据的分布,其实没啥意思。目前 Instruct 的做法则是给定命令表述语句,试图让 LLM 理解它。所以尽管表面都是任务的表述,但是思路是不同的。
而 In Context Learning 和 few shot prompting 意思类似,就是给 LLM 几个示例作为范本,然后让 LLM 解决新问题。我个人认为 In Context Learning 也可以理解为某项任务的描述,只是 Instruct 是一种抽象的描述方式,In Context Learning 是一种例子示范的例子说明法。
(1)神秘的 In Context Learning
Fine-tuning 和 In Context Learning 表面看似都提供了一些例子给 LLM,但两者有质的不同(参考上图示意):Fine-tuning 拿这些例子当作训练数据,利用反向传播去修正 LLM 的模型参数,而修正模型参数这个动作,确实体现了 LLM 从这些例子学习的过程。但是,In Context Learning 只是拿出例子让 LLM 看了一眼,并没有根据例子,用反向传播去修正 LLM 模型参数的动作,就要求它去预测新例子。既然没有修正模型参数,这意味着貌似 LLM 并未经历一个学习过程,如果没有经历学习过程,那它为何能够做到仅看一眼,就能预测对新例子呢?这正是 In Context Learning 的神奇之处。
总之,这个工作证明了 In Context Learning 并未学习映射函数,但是输入和输出的分布很重要,这两个不能乱改。
(2)神奇的 Instruct 理解
我们可以把 Instruct 当作一种方便人类理解的任务表述,在这个前提下,目前关于 Instruct 的研究可以分成两种:偏学术研究的 Instruct,以及关于人类真实需求描述的 Instruct。
我们先来看第一种:偏学术研究的 Instruct。它的核心研究主题是多任务场景下,LLM 模型对 Instruct 理解的泛化能力。如上图中 FLAN 模型所示,就是说有很多 NLP 任务,对于每个任务,研究人员构造一个或者多个 Prompt 模版作为任务的 Instruct,然后用训练例子对 LLM 模型进行微调,让 LLM 以同时学习多个任务。训练好模型后,给 LLM 模型一个它没见过的全新任务的 Instruct,然后让 LLM 解决 zero shot 任务,从任务解决得是否足够好,来判断 LLM 模型是否有对 Instruct 理解的泛化能力。
如果归纳下目前的研究结论(可参考 “Scaling Instruction-Fine-tuned Language Models”/“Super-NaturalInstructions: Generalization via Declarative Instructions on 1600+ NLP Tasks”),能够有效增加 LLM 模型 Instruct 泛化能力的因素包括:增加多任务的任务数量、增加 LLM 模型大小、提供 CoT Prompting, 以及增加任务的多样性。如果采取任意一项措施,都可以增加 LLM 模型的 Instruct 理解能力。
第二种是人类真实需求下的 Instruct,这类研究以 InstructGPT 和 ChatGPT 为代表。这类工作也是基于多任务的,但是和偏向学术研究类工作最大的不同,在于它是面向人类用户真实需求的。为什么这么说呢?因为它们用于 LLM 多任务训练的任务描述 Prompt,是从大量用户提交的真实请求中抽样而来的,而不是固定好研究任务的范围,然后让研究人员来写任务描述 prompt。这里所谓的 “真实需求”,体现在两个方面:首先,因为是从用户提交的任务描述里随机抽取的,所以涵盖的任务类型更多样化,也更符合用户的真实需求;其次,某个任务的 prompt 描述,是用户提交的,体现了一般用户在表达任务需求时会怎么说,而不是你认为用户会怎么说。很明显,这类工作改出来的 LLM 模型,用户体验会更好。
InstructGPT 论文里,也拿这种方法和 FLAN 那种 Instruct based 方法做了比较。首先在 GPT3 上用 FLAN 提到的任务、数据以及 Prompt 模版进行微调,来在 GPT 3 上复现 FLAN 方法,然后和 InstructGPT 进行比较,因为 InstructGPT 的基础模型也是 GPT3,所以只有数据和方法的差别,两者可比,结果发现 FLAN 方法的效果,距离 InstructGPT 有很大的差距。那么背后的原因是什么呢?论文分析数据后认为,FLAN 方法涉及到的任务领域相对少,是 InstructGPT 涉及领域的子集,所以效果不好。也就是说,FLAN 论文里涉及到的任务和用户真实需求是不符的,而这导致在真实场景下效果不够好。而这对我们的启示是:从用户数据中收集真实需求,这事情是很重要的。
(3)In Context Learning 和 Instruct 的联系
如果我们假设 In Context Learning 是用一些例子来具象地表达任务命令,Instruct 是一种更符合人类习惯的抽象任务描述。那么,一个很自然的问题是:它们之间有什么联系吗?比如,我们是否能够提供给 LLM 完成某个任务的若干具体示例,让 LLM 找出其对应的自然语言描述的 Instruct 命令?
目前有零星的工作在探索这个问题,我认为这个方向是很有研究价值的。先说答案,答案是:Yes,LLM Can。“Large Language Models Are Human-Level Prompt Engineers” 是做这个方向很有趣的工作,如上图所示,对于某项任务,给 LLM 一些示例,让 LLM 自动生成能够描述这项任务的自然语言命令,然后它再用 LLM 生成的任务描述去测试任务效果。它使用的基础模型是 GPT 3 和 InstructGPT,经过这项技术加持后,LLM 生成的 Instruct 的效果相比未采用这项技术的 GPT 3 以及 InstuctGPT 来说,指标有极大地提升,而且在一些任务上超过人类的表现。
二、LLM推理
1.推理
LLM在对话、问答和总结等 NLP 任务中取得了显著的成功。然而,当前的LLM在复杂推理方面存在一定的局限性:
- 它们缺乏人类通过教育和经验获得的广泛的世界知识和丰富的概念表征。法学硕士仅接受文本语料库的培训。
- 他们的推理过程是含蓄且不透明的,使得理解或批评推理背后的基本原理变得困难。这种黑匣子性质降低了信任和可靠性。
- 他们的数学、逻辑和类比推理能力有限,需要结构化的符号操作。
- 他们表现出偏见、谬误,并且在许多情况下未能运用常识。他们的推理偏离了人类的规范。
- 他们无法推理自己的推理过程并识别潜在的缺陷。元认知是有限的。
相比之下,人类推理融合了多种形式的推理——演绎、归纳、溯因、类比、反事实、常识和元推理——无缝地使用结构化知识和处理能力。
(1)结构化机器可读知识的知识图
知识图有助于克服LLM等纯神经方法的知识限制。知识图(KG)以网络化、基于图的数据结构的形式表示实体及其之间的关系[4]。KG 编码三个关键元素:
- 概念本体:
领域中的实体和类及其关联方式的正式概念化。例如,本体可以将Animal指定为一个类,并将特定实体(例如Cat和Dog)作为其成员。
- 逻辑公理和规则:
编码有关该领域的事实知识的逻辑陈述,例如“所有猫都是哺乳动物”。这些支持演绎推理。
- 事实数据:
具体实体、关系和事件的实例,例如“加菲猫是一只猫”。
KG 提供了一种机器可读的语义表示,可以编码本体知识和实例数据。像 Wikidata 和 DBpedia 这样的大型知识图谱跨越了跨领域的知识。组织还构建适合其利基领域的企业知识图谱。
KG 中编码的丰富结构化知识可以帮助克服纯 LLM 的一些推理限制:
- 本体论为基础语言概念提供了可扩展的语义结构。
- 逻辑公理可以实现稳健的演绎推理。
- 现实世界的实体和事件是明确表示的,而不仅仅是从文本中统计推断出来的。
- 事实的准确性可以通过出处和管理来确保。
然而,知识图谱在灵活推理方面有其自身的局限性:
- 他们缺乏面对不确定性进行概率推理的能力。
- 他们的推理很大程度上是演绎性的,无法概括模式或进行直觉跳跃。
- 他们理解自然语言中上下文的细微差别和歧义的能力有限。
- 他们注重事实知识,但缺乏常识和社会知识。
因此,知识图谱和LLM具有互补的优势和局限性。将它们结合起来可能会导致人工智能系统具有更像人类的推理能力。这种神经符号整合是一个活跃的研究前沿。
(2)增强推理的神经符号整合
神经符号人工智能旨在将LLM等神经学习方法与符号知识图谱和逻辑相结合。这提供了多种好处:
- 结构化知识注入:知识图提供了本体论和数据库,可以向LLM“教授”背景知识,以增强他们的推理能力。
- 可解释性:与LLM的黑匣子性质不同,符号表示使逻辑推理变得可解释。
- 泛化:本体提供了一个抽象层,有利于迁移学习和泛化。
- 准确性:事实知识图通过基础和出处减少错误的推论。
- 可扩展性:知识图谱中的知识分解有助于大规模推理的计算易处理性。
2.不同推理模式
(1)演绎推理
演绎推理涉及使用有效的推理规则从公认的前提和公理中得出逻辑结论。
主要挑战:
- 处理前提中的不确定性和矛盾。LLM可以帮助产生概率并解决矛盾。KG 可以对确定性因素和来源进行编码。
- 大型推理树的计算复杂性。具有本体推理 API 的 KG 提供高效的优化实现。LLM可以帮助选择有用的推理路径。
- 当前提有缺陷时就会变得脆弱。知识图谱有助于根据精选知识验证前提。LLM可以通过语义检测不一致之处。
- 推理链的不透明性。KG 的符号表示可以实现可解释的推论。LLM可以生成自然语言解释。
(2)归纳推理
归纳推理涉及从个体实例和观察中推断一般原则和模式。
主要挑战:
- 从有限的例子中过度概括。KG 提供多样化的样本以确保稳健的概括。LLM可以根据 KG 统计数据微调推论。
- 有噪音、错误或不具代表性的数据。知识图谱中的本体约束减少了噪声数据的影响。LLM可以利用语义选择代表性样本。
- 大数据的计算复杂性。KG分区和分布式推理提高了可扩展性。LLM选择重点样本进行易于处理的推理。
- 诱导图案的不透明度。LLM生成自然语言假设。KG 能够导出假设的解释子图。
(3)归纳推理
溯因推理涉及推断能够解释观察到的事实的最可能的假设。
主要挑战:
- 大的假设搜索空间。KG 通过本体约束来限制空间。LLM使用语义一致性来修剪假设。
- 评估假设的合理性。KG 提供上下文数据来评估合理性。LLM评估假设的语义。
- 选择最佳假设。知识图谱有典型性等指标来对假设进行排名。LLM生成带有概率的排名假设。
- 具有复杂观察的组合爆炸。LLM分解问题并提出更简单的假设。KG 组成并评估模块化假设。
(4)常识推理
常识推理应用日常事实和直觉来理解情况。
主要挑战:
- 常识的范围和主观性。KG 整理了共识的常识事实。LLM使用文化/情感语义进行情境化推理。
- 将抽象概念融入现实。KG 将符号链接到真实实体。LLM通过语义推断有根据的含义。
- 检测异常和直觉失败。KG 提供了识别异常的期望。LLM通过语义不一致来感知异常。
- 不透明且无法解释的结论。LLM会产生理由。KG 通过形式语义审核常识推论。
(5)类比推理
类比推理涉及根据感知到的相似性将知识从一个领域转移到另一个领域。
主要挑战:
- 确定类比映射的显着特征。知识图谱具有加权本体来捕获特征显着性。LLM检测语义相似性。
- 在大型知识领域中寻找类比的可扩展性问题。KG 将知识划分为模块化本体。LLM专注于相关的语义空间。
- 在适当的层次上抽象关系以进行有用的类比。知识图谱具有分层本体来概括概念。LLM推断概念抽象。
- 验证类比并适当地调整知识。KG 表示验证属性以限定类比推论。LLM对转移的知识进行微调。
- 类比的识别和调整方式不透明。知识图谱跟踪源类似物和推理链的出处。LLM生成自然语言解释。
(6)元推理
元推理涉及对自己的推理过程进行反思和推理。
主要挑战:
- 精确捕捉完整的推理链。KG 使用推理追踪来解释推理轨迹。LLM用语言表达隐含的推理步骤。
- 存储完整多步骤推理轨迹的可扩展性。KG 将推理路径分解为模块化链。LLM在多个层面上总结推理。
- 如何得出结论的不透明性。KG 审核推理轨迹以解释结论。LLM生成推理的自然语言解释。
- 识别推理中的缺陷和偏见。KG 检测无效的推理模式。LLM标记语义不一致和异常。
- 逐步改进推理过程。KG 更新推理规则来解决问题。LLM微调知识表示和策略。
3.如何增强 LLM 的推理能力
当模型规模足够大的时候,LLM 本身是具备推理能力的,在简单推理问题上,LLM 已经达到了很好的能力,但是复杂推理问题上,还需要更多深入的研究。
如果梳理现有 LLM 推理相关工作的话,我把它们归到两大类,体现出挖掘或促进 LLM 推理能力不同的技术思路:第一类研究比较多,可以统称为基于 Prompt 的方法,核心思想是通过合适的提示语或提示样本,更好地激发出 LLM 本身就具备的推理能力,Google 在这个方向做了大量很有成效的工作。第二类做法是在预训练过程中引入程序代码,和文本一起参与预训练,以此进一步增强 LLM 的推理能力,这应该是 OpenAI 实践出的思路。比如 ChatGPT 肯定具备很强的推理能力,但它并不要求用户必须提供一些推理示例,所以 ChatGPT 强大的推理能力,大概率来源于使用代码参与 GPT 3.5 的预训练。
这两种思路其实大方向是迥异的:利用代码增强 LLM 推理能力,这体现出一种通过增加多样性的训练数据,来直接增强 LLM 推理能力的思路;而基于 Prompt 的方法,它并不会促进 LLM 本身的推理能力,只是让 LLM 在解决问题过程中更好地展示出这种能力的技术方法。可以看出,前者(代码方法)治本,后者治标。当然,两者其实也是互补的,但从长远看,治本的方法更重要。
(1)基于 Prompt 的方法
第一种思路是直接在问题上追加辅助推理 Prompt。这种方法简单直接,但在众多领域都很有效。这个做法是由 “Large language models are zero-shot reasoners” 提出的,也被称为 zero-shot CoT。具体而言,分为两个阶段(如上图所示),第一阶段在提问的问题上追加 “Let’s think step by step” 这句提示语,LLM 会输出具体的推理过程;第二阶段,在第一阶段的问题后,拼接 LLM 输出的具体推理过程,并再追加 Prompt=“Therefore, the answer (arabic numerals) is”,此时 LLM 会给出答案。如此简单的操作,却可以大幅增加 LLM 在各项推理任务中的效果,比如在数学推理测试集 GSM8K 上,加上提示语后,推理准确率直接从原先的 10.4% 提升到了 40.4%,可谓神奇。
为什么 LLM 会具备给一句 “Let’s think step by step” 提示语,就能列出详细的推理步骤并算出答案呢?其原因目前尚无定论,我的猜测是:很可能因为预训练数据里面存在大量的此种数据,就是以 “Let’s think step by step” 开头,然后后面是详细的推理步骤,最后给出答案,而 LLM 在预训练的时候记住了这些模式。而当我们输入这个提示语的时候,激发 LLM 模糊得 “回忆” 起某些例子的推导步骤,于是即可模仿这些例子进行步骤推理并给出答案。这侧面说明了一个道理,就是 LLM 本身是具备推理能力的,只是我们没有办法把它的这种能力激发出来而已,通过合适的提示语来进行两步提示,就在一定程度上可以释放出它的这种潜力。另外,对于中文,很可能存在另外一个黄金提示语,比如 “详细解题思路如下”,类似这种,因为中文语料在讲解推理步骤的时候,经常用的引导句和 “让我们一步一步来思考” 应该是不同的,这是明显的西方说法,而探索出这个中文黄金提示语,其实也是很有必要的。
第二种思路一般被称为基于示例的思维链(few-shot CoT,Chain of Thought)Prompting。这个方向目前是 LLM 推理研究的主方向,很多工作都是在这个思路上做的,我们简单介绍几个效果显著的代表性工作,基本能代表 CoT 的技术发展方向。
CoT 的主体思想其实很直白;为了教会 LLM 模型学会推理,给出一些人工写好的推理示例,示例里把得到最终答案前,一步步的具体推理步骤说清楚,而这些人工写的详细推理过程,就是思维链 Prompting,具体例子可参照上图中蓝色文字部分。CoT 的意思是让 LLM 模型明白一个道理;就是在推理过程中,步子不要迈得太大,否则很容易出错,改变思维模式,化大问题为小问题,步步为营,积小胜为大胜。最早明确提出 CoT 这个概念的文章是 “Chain of thought prompting elicits reasoning in large language models”,论文发布于 22 年 1 月份,虽然做法很简单,但是应用 CoT 后 LLM 模型的推理能力得到了巨大提升,GSM8K 数学推理测试集准确率提高到 60.1% 左右。
CoT 的主体思想其实很直白;为了教会 LLM 模型学会推理,给出一些人工写好的推理示例,示例里把得到最终答案前,一步步的具体推理步骤说清楚,而这些人工写的详细推理过程,就是思维链 Prompting,具体例子可参照上图中蓝色文字部分。CoT 的意思是让 LLM 模型明白一个道理;就是在推理过程中,步子不要迈得太大,否则很容易出错,改变思维模式,化大问题为小问题,步步为营,积小胜为大胜。最早明确提出 CoT 这个概念的文章是 “Chain of thought prompting elicits reasoning in large language models”,论文发布于 22 年 1 月份,虽然做法很简单,但是应用 CoT 后 LLM 模型的推理能力得到了巨大提升,GSM8K 数学推理测试集准确率提高到 60.1% 左右。
CoT 提出不久,很快在 22 年 3 月份,一项被称为 “Self-Consistency” 的改进技术就将 GSM8K 测试集准确率提高到 74.4%,提出这项改进的论文是 “Self-Consistency Improves Chain of Thought Reasoning in Language Models”。“Self-Consistency” 的思路也很直观(参考上图):首先可以利用 CoT 给出几个写了推理过程的示例,然后要求 LLM 对给定的问题进行推理,如果是 CoT,直接输出一个推理过程和答案,整个过程就结束了。“Self-Consistency” 则不然,它要求 LLM 输出多个不同的推理过程和答案,然后采用投票的方式选出最佳答案,思路非常简单直接,但是效果也确实好。“Self-Consistency” 其实是教导 LLM 学会这么一个道理:孔乙己说过茴香豆的 “茴” 字有四种写法,类似的,一个数学题的正确解法也可以有很多种,每个不同的推导过程都指向最终的答案。条条大路通罗马,虽说也有个别迷路走到北京的,但是迷路的毕竟是少数,看看大多数人走到哪里,哪里就是正确答案。简单的方法往往蕴含着深刻的哲学含义,是不是这道理?
再往后,“On the Advance of Making Language Models Better Reasoners” 这个工作在 “Self-Consistency” 基础上,进一步集成了 “从一个 Prompt 问题拓展到多个 Prompt 问题、检查推理中间步骤的正确性以及对多个输出的回答加权投票” 这三个改进点,将 GSM8K 测试集准确率提高到 83% 左右。
第三种思路体现了一种分治算法的思想。当然这个所谓 “分治” 是我归纳的,别人没这么说。这种思路的核心思想是:对于一个复杂的推理问题,我们把它分解成若干容易解决的子问题,一一解决掉子问题后,我们再从子问题的答案推导复杂问题的答案。这种思路可能才是揭示问题本质、最终解决 LLM 复杂推理问题正宗的道路。我们以 “Least-to-most prompting” 技术为例来说明这种思路的一种具体实现方式,如上图所示:它分为两个阶段,第一个阶段,从原始问题我们可以得知最终要问的问题是什么,我们假设最终问题是 Final Q,然后从原始问题填充 Prompt 模版:“如果要解决 Final Q 问题,那么我需要先解决”,然后把原始问题和这个 Prompt 交给 LLM,让 LLM 模型给出答案,等于让 LLM 给出最终问题的前置子问题 Sub Q;接下来我们进入第二个阶段,让 LLM 先回答刚才拿到的子问题 Sub Q,并拿到对应的答案,然后原始问题拼接子问题 Sub Q 及对应答案,再去问 LLM 最终那个问题 Final Q,此时 LLM 会给出最后的答案。如此这般,体现出拆解子问题,并从子问题的答案逐步找出最终答案的思路。
(2)代码预训练增强 LLM 推理能力
除了文本外,如果能够加入程序代码一起参与模型预训练,则能大幅提升 LLM 模型的推理能力。
4.关于 LLM 推理能力的思考
虽然最近一年来,关于激发 LLM 的推理能力,这方面的技术进展很快,也取得了很大的技术进步,但是总体感觉是,我们可能走在正确的方向上,但是距离接触到真正的问题本质还有一段距离,对此要有更深入的思考和探索。
首先,我比较赞同上述分治算法的主体思路,对于复杂的推理问题,我们应该把它拆解成若干简单的子问题,因为子问题对于 LLM 来说回答正确的概率就大很多,让 LLM 一一回答子问题后,再逐步推导出最终答案。受到 “Least-to-most prompting” 技术的启发,如果进一步思考,我觉得 LLM 推理本质上很可能会是如下两种可能的其中之一:不断和 LLM 进行交互的图上推理问题,抑或是不断和 LLM 进行交互的程序流程图执行问题。
先说图上推理问题,如上图所示,假设我们有办法能够把复杂问题拆解成由子问题或者子步骤构成的图结构,图中的节点是子问题或者子步骤,图中的边代表了子问题之间的依赖关系,就是说只有回答好子问题 A,才能回答子问题 B,而且图中大概率存在循环结构,就是反复做某几个子步骤。假设我们能够得到上述的子问题拆解图,那么可以根据依赖关系,引导 LLM 一步一步按照图结构,回答必须首先回答的子问题,直到推导出最终答案。
再说程序流程图问题,参考上图,假设我们有办法把复杂问题拆解成子问题或子步骤,并产生一个由子步骤构成的类似程序流程图的结构,在这个结构里,有些步骤会反复执行多次(循环结构),有些步骤的执行需要进行条件判断(条件分支)。总而言之,在执行每个子步骤的时候和 LLM 进行交互,得到子步骤的答案,然后按照流程不断执行,直到输出最终答案。类似这种模式。假设这个思路大致正确的话,也许可以从这个角度来解释为何加入代码会增强预训练模型的推理能力:大概率因为 < 文本,代码 > 的多模态预训练模型,在模型内部是通过类似这种隐含的程序流程图作为两个模态的桥梁,将两者联系起来的,即由文本描述到隐含的流程图,再映射到由流程图产生具体的代码。也就是说,这种多模态预训练,可以增强 LLM 模型从文本构建出隐含的流程图并按照流程图执行的能力,也就是加强了它的推理能力。
当然,上述思路最大的问题是,我们如何根据文本描述的问题,能够靠 LLM 模型,或者其它模型,得到图结构或者流程图结构?这个可能是其中的难点。一种可能的思路就类似继续增强文本和更高质量的代码预训练,走隐式学习内部隐含结构的方法。而目前的 CoT 技术,如果套到上述思路来思考的话,可以这么理解:标准 CoT,其实就是靠自然语言文本来描述图结构或者程序流程图的;而 “Least-to-most prompting” 技术,则是试图根据最后一个图节点,靠倒推来试图推导出其中的图结构,但是很明显,目前的方法限制了它倒推的深度,也就是说它只能推导出非常简单的图结构,这正是限制它能力的所在。
三、大模型能力与技术
1.模型的演变
- 指令微调。不会为模型注入新的能力 —— 所有的能力都已经存在了。指令微调的作用是解锁 / 激发这些能力。这主要是因为指令微调的数据量比预训练数据量少几个数量级(基础的能力是通过预训练注入的)。
- 指令微调将 GPT-3.5 的分化到不同的技能树。有些更擅长上下文学习,如text-davinci-003,有些更擅长对话,如ChatGPT。
- 指令微调通过牺牲性能换取与人类的对齐(alignment)。OpenAI 的作者在他们的指令微调论文[12] 中称其为 “对齐税” (alignment tax)。许多论文[13] 都报道了code-davinci-002在基准测试中实现了最佳性能(但模型不一定符合人类期望)。在code-davinci-002上进行指令微调后,模型可以生成更加符合人类期待的反馈(或者说模型与人类对齐),例如:零样本问答、生成安全和公正的对话回复、拒绝超出模型它知识范围的问题。
(1)code-davinci-002和text-davinci-002的进步
我们关注code-davinci-002和text-davinci-002,这两兄弟是第一版的 GPT3.5 模型,一个用于代码,另一个用于文本( Code-davinci-002 更擅长上下文学习;当没有上下文示例 / 零样本的时候, text-davinci-002 在零样本任务完成方面表现更好)。它们表现出了三种重要能力与初代 GPT-3 不同的能力:
- 响应人类指令:以前,GPT-3 的输出主要训练集中常见的句子。现在的模型会针对指令 / 提示词生成更合理的答案(而不是相关但无用的句子)。
- 泛化到没有见过的任务:当用于调整模型的指令数量超过一定的规模时,模型就可以自动在从没见过的新指令上也能生成有效的回答。 这种能力对于上线部署至关重要,因为用户总会提新的问题,模型得答得出来才行。
- 代码生成和代码理解:这个能力很显然,因为模型用代码训练过。
- 利用思维链 (chain-of-thought) 进行复杂推理:初代 GPT3 的模型思维链推理的能力很弱甚至没有。 code-davinci-002 和 text-davinci-002 是两个拥有足够强的思维链推理能力的模型。
- 思维链推理之所以重要,是因为思维链可能是解锁突现能力和超越缩放法则 (scaling laws) 的关键。
这些能力从何而来?与之前的模型相比,两个主要区别是指令微调和代码训练。具体来说
- 能够响应人类指令的能力是指令微调的直接产物。
- 对没有见过的指令做出反馈的泛化能力是在指令数量超过一定程度之后自动出现的,T0[16] 、Flan[17] 和 FlanPaLM[18] 论文进一步证明了这一点
- 使用思维链进行复杂推理的能力很可能是代码训练的一个神奇的副产物。对此,我们有以下的事实作为一些支持:
- 最初的 GPT-3 没有接受过代码训练,它不能做思维链。
- text-davinci-001 模型,虽然经过了指令微调,但第一版思维链论文 报告说,它的它思维链推理的能力非常弱 —— 所以指令微调可能不是思维链存在的原因,代码训练才是模型能做思维链推理的最可能原因。
- PaLM有 5% 的代码训练数据,可以做思维链。
- 直觉来说,面向过程的编程 (procedure-oriented programming) 跟人类逐步解决任务的过程很类似,面向对象编程 (object-oriented programming) 跟人类将复杂任务分解为多个简单任务的过程很类似。
- 以上所有观察结果都是代码与推理能力 / 思维链 之间的相关性,但不一定是因果性。这种相关性很有趣,但现在还是一个待研究的开放性问题。目前看来,我们没有非常确凿的证据证明代码就是思维链和复杂推理的原因。
- 此外, 代码训练另一个可能的副产品是长距离依赖,正如Peter Liu[25] 所指出:“语言中的下个词语预测通常是非常局部的,而代码通常需要更长的依赖关系来做一些事情,比如前后括号的匹配或引用远处的函数定义”。这里我想进一步补充的是:由于面向对象编程中的类继承,代码也可能有助于模型建立编码层次结构的能力。我们将对这一假设的检验留给未来的工作。
(2)这些能力是在预训练之后已经存在还是在之后通过微调注入
- 无论基础模型是初代的 GPT-3 还是后来训练的模型, 遵循指令和零样本泛化的能力都可能已经存在于基础模型中,后来才通过指令微调来解锁 (而不是注入)
- 这主要是因为 OpenAI 的论文[28] 报告的指令数据量大小只有 77K,比预训练数据少了几个数量级。
- 其他指令微调论文进一步证明了数据集大小对模型性能的对比,例如 Chung et al. (2022) 的工作中, Flan-PaLM 的指令微调仅为预训练计算的 0.4%。一般来说,指令数据会显著少于预训练数据。
- 然而 模型的复杂推理能力可能是在预训练阶段通过代码数据注入
- 代码数据集的规模与上述指令微调的情况不同。这里的代码数据量足够大,可以占据训练数据的重要部分(例如,PaLM 有 8% 的代码训练数据)
- 如上所述,在 code-davinci-002 之前的模型 text-davinci-001 大概没有在代码数据上面微调过,所以它的推理 / 思维链能力是非常差的,正如第一版思维链论文中所报告的那样,有时甚至比参数量更小的 code-cushman-001 还差。
(3)能力总结
- 语言生成能力 + 基础世界知识 + 上下文学习都是来自于预训练(davinci)
- 存储大量知识的能力来自 1750 亿的参数量。
- 遵循指令和泛化到新任务的能力来自于扩大指令学习中指令的数量(Davinci-instruct-beta)
- 执行复杂推理的能力很可能来自于代码训练(code-davinci-002)
- 生成中立、客观的能力、安全和翔实的答案来自与人类的对齐。具体来说:
- 如果是监督学习版,得到的模型是text-davinci-002
- 如果是强化学习版 (RLHF) ,得到的模型是text-davinci-003
- 无论是有监督还是 RLHF ,模型在很多任务的性能都无法超过 code-davinci-002 ,这种因为对齐而造成性能衰退的现象叫做对齐税。
- 对话能力也来自于 RLHF(ChatGPT),具体来说它牺牲了上下文学习的能力,来换取:
- 建模对话历史
- 增加对话信息量
- 拒绝模型知识范围之外的问题
2.关于ChatGPT技术问题的猜想
答案不可靠,无法进行实时学习(虽然本次对话可以让模型学习,但是不会真正延申到模型上,因为需要避免人为训练假的数据)
(1) 为什么面向对话的微调没有遭遇灾难性遗忘问题
灾难性遗忘问题一直是深度学习中的一个挑战,经常因为在某个任务上训练后就丧失了在其他任务上的性能。例如,一个 30 亿参数的基础模型,先在自动问答数据上进行微调,然后在多轮对话数据上进行微调,结果会发现模型的问答能力大幅度下降。ChatGPT 似乎不存在这个问题,其在基础模型 GPT-3.5 上进行了两次微调,第一次依据人工标注的对话数据进行微调,第二次根据人类反馈的强化学习进行微调,微调使用的数据很少,尤其是人类反馈的打分排序数据更少,微调后竟然仍然表现出强大的通用能力,而并没有完全过拟合到对话任务。
这是个非常有趣的现象,也是我们没有条件验证的现象。猜测可能有两方面的原因,一方面是 ChatGPT 使用的对话微调数据实际可能包含了非常全面的 NLP 各种任务,正如 InstructGPT 中对用户使用 API 的问题分类可以发现,很多都不是简单的对话,还有分类、问答、摘要、翻译、代码生成等等,因此,ChatGPT 实际是对若干任务同时进行了微调;另一方面,可能当基础模型足够大之后,在较小数据上的微调不会对模型产生很大影响,可能仅在基础模型参数空间非常小的邻域中优化,所以不会显著影响基础模型的通用能力。
(2)ChatGPT 的大范围上下文连续对话能力是如何做到的
首先,高质量的多轮对话数据是基础和关键,正如 Google 的 LaMDA,OpenAI 也采用人工标注的方式构造了大量高质量多轮对话数据,在此之上进行的微调将会激发模型的多轮对话能力。
其次,基于人类反馈的强化学习因为提升了模型回复的拟人性,也会间接增强模型多轮对话的一致性能力。最后,模型对 8192 个语言单元(Token)的显式建模能力使其几乎可以记忆普通人一整天的对话数据,在一次对话交流中很难超出这个长度,因此,所有对话历史都已经被有效记忆,从而可以显著提升连续多轮对话的能力。
(3)ChatGPT 的交互修正能力是如何炼成的
- OpenAI 人工构建的对话数据中包含一些交互修正的案例,微调后拥有了这样的能力;
- 人工反馈的强化学习使得模型输出更加符合人类偏好,从而在信息修正这类对话中表现得更加遵循人类的修正意图;
- 可能大模型达到一定规模(e.g. 60B)之后,原始训练数据中的交互修正案例就被学到了,模型交互修正的能力自然就涌现出来了。
(4)ChatGPT 的逻辑推理能力是如何学到的?
当我们询问 ChatGPT 一些逻辑推理相关的问题时,它并不是直接给出答案,而是展示出详细的逻辑推理步骤,最后给出推理结果。虽然鸡兔同笼等很多案例表明 ChatGPT 并没有学会推理本质,而仅仅学会了推理的表面逻辑,但是展示的推理步骤和框架基本是正确的。
一个语言模型能够学习到基本的逻辑推理模式已经极大超越了预期,其推理能力溯源是非常有趣的一个问题。相关对比研究发现,当模型足够大,并且程序代码与文本数据混合训练时,程序代码的完整逻辑链就会迁移泛化到语言大模型,从而大模型就拥有了一定的推理能力。
这种推理能力的习得有点神奇,但是也能理解,可能代码注释是从逻辑代码到语言大模型推理能力迁移泛化的桥梁。多语言能力应该也是类似的道理。ChatGPT 的训练数据绝大部分是英文,中文数据占比极少,然而我们发现 ChatGPT 的中文能力虽然比不上英文,但是也非常强大。训练数据中的一些中英对照的平行数据可能就是英文能力迁移到中文能力的桥梁。
(5) ChatGPT 是否针对不同下游任务采用不同的解码策略
ChatGPT 有许多惊艳的表现,其中一个是它可以针对同一个问题生成多种不同的回复,显得很睿智。比如,我们不满意 ChatGPT 的回答,可以点击 “重新生成” 按钮,它立刻会生成另一种回复,若还是不满意可以继续让其重新生成。这一点在 NLP 领域并不神秘,对于语言模型来说是它的一个基本能力,也就是采样解码。
一个文本片段的后面可能接不同的词语,语言模型会计算每个词语出现的概率,如果解码策略选择概率最大的词语输出,那么每次结果都是确定的,就无法生成多样性回复。如果按照词汇输出的概率分布进行采样,例如,“策略” 的概率是 0.5,“算法” 的概率是 0.3,然后采样解码输出 “策略” 的可能性就是 50%,输出 “算法” 的可能性就是 30%,从而保证了输出的多样性。因为采样过程是按照概率分布进行的,即使输出结果多样,但是每一次都是选择概率较大的结果,所以多种结果看起来都相对比较合理。对比不同类型的任务时,我们会发现 ChatGPT 的回复多样性针对不同下游任务差别比较大。
针对 “如何”、“为什么” 等 “How”、“Why” 型任务时,重新生成的回复与之前的回复无论是表达方式还是具体内容具有较大差异,针对机器翻译、数学应用题等 “What” 型任务时,不同回复之间的差异非常细微,有时几乎没有变化。如果都是依据概率分布的采样解码,为何不同回复之间的差异如此之小。
猜测一种理想情况可能是 “What” 型任务基础大模型学习到的概率分布非常尖锐(Sharp),例如学到的 “策略” 概率为 0.8,“算法” 概率为 0.1,所以大多数时候采样到相同的结果,也就是前面例子中 80% 的可能性都会采样到 “策略”;“How”、“Why” 型任务基础大模型学习到的概率分布比较平滑(Smooth),例如 “策略” 概率为 0.4,“算法” 概率为 0.3,所以不同时候可以采样到差异性较大的结果。
如果 ChatGPT 能够学习到任务相关的非常理想的概率分布,那确实非常厉害,基于采样的解码策略就可以适用于所有任务。通常,关于机器翻译、数学计算、事实性问答等答案比较确定或者 100% 确定的任务,一般采用基于贪婪解码,也就是每次输出概率最高的词语。如果希望输出相同语义的多样性输出,大多采用基于柱搜索的解码方法,但较少采用基于采样的解码策略。
3.关键技术
- 缩放。缩放是增加 LLMs 模型容量的关键因素,最开始 GPT-3 将模型参数增至 1750 亿,随后 PaLM 进一步将模型参数增至 5400 亿。大规模参数对于涌现能力至关重要。缩放不仅针对模型大小,还与数据大小和总计算量有关。
- 训练。由于规模巨大,成功训练一个具备强大能力的 LLMs 非常具有挑战性。因此需要分布式训练算法来学习 LLMs 的网络参数,经常联合使用各种并行策略。为了支持分布式训练,DeepSpeed 和 Megatron-LM 等优化框架被用来促进并行算法的实现和部署。此外,优化技巧对训练稳定性和模型性能也很重要,例如重新启动训练损失尖峰和混合精度训练。最近的 GPT-4 开发了特殊的基础设施和优化方法,从而利用小得多的模型来预测大模型的性能。
- 能力激发。在大规模语料库上经过预训练后,LLMs 被赋予了解决一般任务的潜在能力。然而当 LLMs 执行某个特定任务时,这些能力可能不会显式地表现出来。因此设计适合的任务指令或特定的上下文策略来激发这些能力非常有用,比如思维链 prompt 有助于通过中间推理步骤等解决复杂推理任务。此外还可以进一步对具有自然语言任务描述的 LLMs 进行指令调优,以提高对未见过任务的泛化能力。
- 对齐调优。由于 LLMs 被训练用来捕获预训练语料库的数据特征(包括高质量和低质量的数据),它们很可能生成对有毒、有偏见和有害的文本内容。为了使 LLMs 与人类价值观保持一致,InstructGPT 设计了一种利用强化学习和人类反馈的高效调优方法,使得 LLMs 能够遵循预期指令。ChatGPT 是在类似 InstructGPT 的技术上开发的,在产生高质量、无害的响应方面表现出了强大的对齐能力。
- 工具利用。LLMs 本质上是基于大规模纯文本语料库训练的文本生成器,因此在数值计算等文本表达不佳的任务上表现没那么好。此外 LLMs 的能力受限于预训练数据,无法捕获最新信息。针对这些问题,人们提出使用外部工具来弥补 LLMs 的不足,比如可以利用计算器进行精确计算,使用搜索引擎检索未知信息。ChatGPT 更是利用外部插件来联网学习新知识,这种机制可以广泛扩展 LLMs 的能力范围。
(1)预训练
预训练建立了 LLMs 的能力基础。通过对大规模语料库的预训练,LLMs 可以获得基本的语言理解和生成技能。在这个过程中,预训练语料库的规模和质量是 LLMs 获得强大能力的关键。此外,为了有效地预训练 LLMs,模型架构、加速方法和优化技术都需要精心设计。
①数据收集
要开发一个强大的 LLM,从各种数据源中收集大量的自然语言语料至关重要。现有 LLMs 主要利用各种公共文本数据集作为预训练语料库。收集大量文本数据后,必须对它们进行预训练以构建预训练语料库,包括去噪、去冗余、去除不相关和潜在有毒的数据。
②模型训练
随着模型和数据规模的增加,在有限的计算资源下有效地训练 LLMs 模型已经变得困难。特别是,需要解决两个主要技术问题,例如通过输入增加训练和将更大的模型加载到 GPU 内存中。
(2)LLMs 的适应性调优
经过预训练,LLMs 可以获得解决各种任务的通用能力。然而越来越多的研究表明,LLMs 的能力可以根据具体目标进一步调整。
①指令调优——提高或解锁 LLMs 的能力
本质上,指令调优是在自然语言形式的格式化实例集合上微调预训练 LLMs 的方法,这与监督微调和多任务提示训练高度相关。为了执行指令调优,我们首先需要收集或构建指令格式的实例。然后,我们通常使用这些格式化实例以监督学习方式微调 LLMs(例如,使用序列到序列损失进行训练)。在指令调整后,LLMs 可以展示出卓越的能力,泛化出能解决未见任务的能力,即使在多语言环境中也是如此。
- 格式化实例构建:通常,指令格式的实例由任务描述(称为指令)、输入输出对和少量演示(可选)组成。
- 指令调优策略:与预训练不同,指令调优通常更有效,因为只有适度数量的实例用于训练。虽然指令调优可以被认为是一个有监督的训练过程,但它的优化在几个方面与预训练不同,例如训练目标(即序列到序列损失)和优化配置(例如更小的批次) 大小和学习率),这在实践中需要特别注意。除了这些优化配置之外,指令调优还需要考虑两个重要方面:
- 平衡数据分布。
- 结合指令调优和预训练。
②对齐调优——使 LLMs 的行为与人类的价值观或偏好一致
③上下文学习
在预训练或适应性调整之后,使用 LLMs 的一个主要方法是为解决各种任务设计合适的 prompt 策略。一个典型的 prompt 方法是上下文学习(in-context learning),它以自然语言文本的形式制定了任务描述或演示。此外,思维链 prompting 方法可以通过将一系列中间推理步骤纳入 prompt 中来加强上下文学习
④思维链 prompt
思维链(CoT)是一种改进的 prompt 策略,可以提高 LLM 在复杂推理任务中的表现,如算术推理、常识推理和符号推理。CoT 不是像 ICL 那样简单地用输入 - 输出对来构建 prompt,而是将能够导致最终输出的中间推理步骤纳入 prompt。
四、如何训练GPT
GPT 的训练流程可粗略分为四个阶段:预训练、监督式微调、奖励建模、强化学习。这四个阶段按顺序进行。每个阶段都有各自的数据集,每个阶段也有各自用于训练神经网络的算法。第三行是所得到的模型。最后底部有一些备注信息。
在所有阶段中,预训练阶段所需的计算量是最大的,可以说 99% 的训练计算时间和浮点运算量都集中在这个阶段。因为这一阶段需要处理超大规模的互联网数据集,可能需要数千 GPU 构成的超级计算机工作几个月时间。其它三个阶段都算是微调(fine tuning)阶段,所需的 GPU 数量和训练时间都少得多。
1.预训练阶段_得到一个基础模型
预训练通常需要使用一个超大型的文本语料库,其中包含数十亿乃至数万亿 token。预训练阶段的训练任务很简单直接,就是根据前文预测下一个词。
(1)数据收集
下面给出了一个例子,这是来自 Meta 的 LLaMA 模型的数据混合(data mixture)方法:可以看到,LLaMA 的预训练数据按不同比例混用了多个不同类型的数据集,其中比例最大的是爬取自互联网的 CommonCrawl 以及基于 CommonCrawl 构建的 C4,此外还有 GitHub、维基百科等数据集。
(2)预处理
①Tokenizer Training
这一步也被称为「token 化」。简单来说,这就是一个转译过程,即把原始文本转译成某种整数序列,因为这种整数序列就是 GPT 实际工作时所操作的本地表征。
这种从文本到 token 和整数的转译过程是无损的,而具体执行这一过程的算法有好几种。举个例子,如上图所示,我们可以使用一种名为字节对编码(byte pair encoding)的技术,其工作方式是迭代式地合并短文本块并将它们分组成 token。最后实际输入 Transformer 的就是那些整数序列。
下面来看两个示例模型 GPT-3 和 LLaMA 在预训练阶段需要考虑的一些主要的超参数。Karpathy 表示由于他们还没有发布有关 GPT-4 的相关信息,因此在演讲中使用了 GPT-3 的数据。
可以看到,词汇库的大小通常是 10000 数量级的;上下文长度通常为 2000 或 4000 左右,而现在更是有长达 10 万的。上下文长度决定着 GPT 在预测序列的下一个整数时所查看的最大整数数量。
对于参数数量,可以看到 GPT-3 的为 1750 亿,而 LLaMA 的为 650 亿,但实际上 LLaMA 的性能表现远胜于 GPT-3。原因何在?因为 LLaMA 训练的 token 要长得多,达到了 1.4 万亿,而 GPT-3 仅有大约 3000 亿。因此,评价一个模型时,光看参数数量是不够的。
上图中部的表格中给出了 Transformer 神经网络中一些需要设定的超参数,比如头的数量、维度大小、学习率、层数等等。
下方则是一些训练超参数;比如为了训练 650 亿参数的 LLaMA 模型,Meta 使用 2000 个 GPU 训练了大约 21 天,资金成本大约为 500 万美元。这大概能体现出预训练阶段各项成本的数量级。
②词表扩充
为了降低模型的训练难度,人们通常会考虑在原来的词表上进行「词表扩充」,也就是将一些常见的汉字 token 手动添加到原来的 tokenizer 中,从而降低模型的训练难度。
(3)实际处理
接下来看实际的预训练过程究竟会发生什么。大致来说,首先会把 token 分批组成 data batch。这些分配数据构成数组,再被输入到 Transformer 中。这些数组的大小为 B×T;其中 B 是分批大小,即堆叠的独立样本的行数;T 是最大上下文长度。下图给出了一个示例。
在图中示例中,上下文长度 T 仅为 10,但实际模型的 T 可达到 2000 或 4000 乃至更长。也就是说,实际模型的一行数据可以非常长,比如一整个文档。我们可以将许多文档打包到各行中,并用这些特殊的文本结束 token 来分隔它们。简单来说,这些 token 是告诉 Transformer 新文档开始的位置。比如图中的 4 行文档就转换成了底部的 4×10 的数组。
现在,需要将这些数字输入到 Transformer。这里我们仅看其中一个单元格(绿色),而实际上每个单元格都会经历同样的处理流程。
这个绿色单元格会查看其之前的所有 token,即所有黄色单元格的 token。我们要将这里的全部上文输入到 Transformer 神经网络,Transformer 则需要预测出该序列的下一个 token,即图中的红色 token。
为了给出准确的预测,神经网络需要调整其上百亿个参数。每次调整后,神经网络对每个单元格 token 的预测分布就会不同。举个例子,如果词汇库的大小为 50257 个 token,那么我们就需要同样多的数字,以便得到下一个 token 的概率分布,其预测了下一个 token 的可能值及相应概率。
在图中的示例中,下一个单元格应该是 513,因此就可以将其用作监督源来更新 Transformer 的权重。我们可以并行地对每个单元格采取同样的操作。我们不断更换数据批,努力让 Transformer 有能力正确地预测序列的下一个 token。
(4)微调
预训练其实就是一个语言建模过程,这个过程的训练时间可长达一个月。之后,GPT 学到了一个非常强大的通用型语言表征。然后我们可以针对具体的下游任务高效地对其进行微调。
举个例子,如果下游任务是情绪分类。过去,你采用的方法可能是收集大量标注好「正面」或「负面」情绪的样本,然后训练一个 NLP 模型。但现在的新方法不需要预先做情绪分类了,你只需要拿一个预训练过的大型语言模型,然后只需要少量示例样本,就能非常高效地针对你的具体任务对模型进行微调。
这对实际应用来说非常有用。那么为什么预训练后的大型语言模型(LLM)只需要简单微调就能用呢?这是因为语言建模过程本身就已经涵盖了大量任务 —— 模型为了预测下一个 token,必须理解文本的结构以及其中内含的各种不同概念。
这就是 GPT-1。
现在来看 GPT-2。人们注意到 GPT-2 甚至可以不用微调就能非常有效地让这些模型执行 prompt。这些语言模型的训练目标是完成文档,因此用户实际上只需通过编排适当的虚假文档,就可以诱导模型执行具体任务。下面给出了一个例子。
其中给出了一篇文章,用户想完成的任务是做相关的问答。因此,只需要在文章后面加几个有答案的问答(这被称为 few-shot prompt),然后再提问,那么由于 Transformer 的目标是完成这个文档,也就相当于回答了问题。这个例子是用 prompt 来调教基础模型,使其相信它在模仿一个文档,结果却完成了问答任务。
Karpathy 认为,以提供 prompt 替代微调的方式昭示着大型语言模型的新时代。这让基础模型本身就足以应对许多不同类型的任务。
2.监督式微调阶段
(1)为什么要进行监督式微调
上一阶段只会产生一个基础模型,基础模型不等于助理模型。基础模型不会回答用户提问,它们只会完成文档。所以如果你对基础模型说:「写一首关于面包和奶酪的诗」,你可能不会如愿 —— 它只会把你的要求看成一个文档,然后试图完成它。
但是,你可以通过适当的 prompt 诱导基础模型写诗,如上图右侧所示。
当然,你也可以诱导模型变成助理。为此,你需要创建一些特定的少样本 prompt,使其看起来像是人类与助理交换信息的交互过程的文档。如下图所示,然后你只需要在文档结尾处附上你的提问,基础模型就能在一定程度上化身为一个有用的助理,给出某个答案。但这个过程并不非常可靠,实践效果也不好。
(2)监督式微调
在监督式微调阶段,需要收集少量但高质量的数据集。OpenAI 的方法是以人工方式收集由 prompt 和理想响应构成的数据。这些数据需要不少,一般需要几万个。
然后,继续在这些数据上执行语言建模。算法不变,只是换了训练数据集:从大量低质量的互联网文档换成了少量高质量的问答式「prompt - 响应」数据。
这个训练过程完成后,就得到了一个 SFT 模型。部署这些模型就能得到助理,它们已经能完成一定程度的工作。
监督式微调阶段涉及到另一轮对下一 token 的预测。但是,不同于之前的预训练阶段,模型现在处理的是成对的「指令 - 输出」,如上图所示。在这里,指令是指提供给模型的输入(根据任务的不同,指令中有时候会带有可选的输入文本)。输出则是模型给出的接近我们期望的响应。这里给出一个具体示例,对于下面这一对「指令 - 输出」:
指令:"Write a limerick about a pelican."输出:"There once was a pelican so fine..."
模型将指令文本(Write a limerick about a pelican)作为输入,执行下一 token 预测获得输出文本(There once was a pelican so fine...)。
尽管预测下一 token 这个训练目标是相似的,但监督式微调使用的数据集通常比预训练所用的小得多。这是因为它需要的是指令 - 输出对,而不只是原始文本。为了构建这样一个数据集,必需有一个人类(或另一个高质量 LLM)来根据给定指令写出所需输出 —— 创建这样一个数据集非常费力。
3.RLHF 奖励建模阶段
在这一阶段,需要将数据收集转变成比较的形式。这里给出了一个示例。对于同样的 prompt,即要求助理写一个能检查给定字符串是否为回文的程序或函数。再使用已经训练好的 SFT 模型生成多个结果,这里给出了三个。然后再让人类给这些结果排名。
这件事做起来可并不简单,毕竟要是让人类来完成一个 prompt,可能需要耗费几个小时时间。现在假设排名完成了,然后就需要在这些结果的所有可能配对上执行类似二元分类的操作。
如下图所示,具体的做法是这样的:将 prompt 按行排列;这里的三行 prompt 是一样的,但完成的结果不同,即图中黄色 token(来自 SFT 模型)。然后在其后添加一个特殊的奖励读出 token。这样,只需要在绿色 token 位置对 Transformer 执行监督,就能使 Transformer 预测出某个奖励,从而判断 prompt 的完成结果是否优良。
这基本上就是让 Transformer 猜测每个完成结果的质量。当其猜测完每个不同结果的质量后,开发者就可以动用已有的基本真值(ground truth)强行让某些结果的质量分数高于其它结果,从而使模型的奖励预测结果与人工给出的基本真值保持一致。这个过程可以通过一个损失函数完成。
有了奖励模型之后,GPT 依然还不能成为一个有用的助理,但奖励模型却对后面的强化学习阶段很有用,因为奖励模型可以评估任意给定 prompt 的任意完成结果的质量。
在 OpenAI 的 [Summarization] 和 [InstructGPT] 的论文中,都使用了「偏序对」来训练模型。
偏序对是指:不直接为每一个样本直接打分,而是标注这些样本的好坏顺序。
直接打分:A句子(5分),B句子(3分)偏序对标注:A > B
模型通过尝试最大化「好句子得分和坏句子得分之间的分差」,从而学会自动给每一个句子判分。
(1)执行步骤
①创建一个奖励模型
如上图所示,用上一步中创建的已微调 LLM 为每个 prompt 生成 4-9 个响应。然后再让人基于自己的偏好对这些响应进行排名。尽管这个排名过程非常耗时,但相比于创建用于监督式微调的数据集,其劳动力密集程度可能要低一些。这是因为对响应进行排名多半比编写响应更简单。
然后基于使用这些排名构建的数据集,我们可以设计一个奖励模型,其输出的是用于 RLHF 第 3 步后续优化阶段的奖励分数。这个奖励模型通常源自之前的监督式微调步骤创建的 LLM。下面将奖励模型简称为 RM,将经过监督式微调后的 LLM 简称为 SFT。为了将 RLHF 第 1 步的模型变成奖励模型,需要将其输出层(下一 token 分类层)替换成一个回归层,其具有单个输出节点。
②使用奖励模型(RM)来微调监督式微调的模型
根据 RLHF 创建的 RM 的奖励分数,使用近端策略优化(PPO)来更新 SFT 模型。
3.复刻 ChatGPT 时要注意些什么
如果希望能复刻类似 ChatGPT 这种效果令人惊艳的 LLM 模型,综合目前的各种研究结论,在做技术选型时需要重点权衡如下问题:
首先,在预训练模式上,我们有三种选择:GPT 这种自回归语言模型,Bert 这种双向语言模型,以及 T5 这种混合模式 (Encoder-Decoder 架构,在 Encoder 采取双向语言模型,Decoder 采取自回归语言模型,所以是一种混合结构,但其本质仍属于 Bert 模式)。我们应选择 GPT 这种自回归语言模型,其原因在本文范式转换部分有做分析。目前看,国内 LLM 在做这方面技术选型的时候,貌似很多都走了 Bert 双向语言模型或 T5 混合语言模型的技术路线,很可能方向走偏了。
第二,强大的推理能力是让用户认可 LLM 的重要心理基础,而如果希望 LLM 能够具备强大的推理能力,根据目前经验,最好在做预训练的时候,要引入大量代码和文本一起进行 LLM 训练。至于其中的道理,在本文前面相关部分有对应分析。
第三,如果希望模型参数规模不要那么巨大,但又希望效果仍然足够好,此时有两个技术选项可做配置:要么增强高质量数据收集、挖掘、清理等方面的工作,意思是我模型参数可以是 ChatGPT/GPT 4 的一半,但是要想达到类似的效果,那么高质量训练数据的数量就需要是 ChatGPT/GPT 4 模型的一倍(Chinchilla 的路子);另外一个可以有效减小模型规模的路线是采取文本检索(Retrieval based)模型 + LLM 的路线,这样也可以在效果相当的前提下,极大减少 LLM 模型的参数规模。这两个技术选型不互斥,反而是互补的,也即是说,可以同时采取这两个技术,在模型规模相对比较小的前提下,达到超级大模型类似的效果。
第四,超级大模型因为模型规模大,所以训练成本过高,导致很少有机构有能力去做这件事。而且由上文分析可见,继续不断推大 LLM 模型规模是肯定会发生、也应该去做的事情。于是,如何通过技术手段降低 LLM 的训练成本就很重要。LLM 的特征抽取器 Sparse 化是有效降低模型训练及推理成本的技术选择。由此可见,随着模型越来越大,LLM 模型 Sparse 化是一个应该考虑的选项。
第五,ChatGPT 是目前最接近理想 LLM 的技术方案,而理想中的 LLM 应该是以一个几乎无所不能的基础通用大模型作为依托,来支持各种各样的上层任务类型。目前看,支持越来越多的任务类型,主要是通过增加 LLM 预训练数据的多样性来达成的,数据多样性越好,LLM 能够支持的任务类型就越丰富。所以,应该重视通过增加数据多样性来增加 LLM 新能力的思路。
第六,易用的人机操作接口。人类用他们自己习惯的表达方式来描述任务,而 LLM 要能够理解这些 Instruct 的真实含义。另外,也要注意这些 Instruct 是符合人类真实需求的,就是说,要从最终用户那里收集任务表述方式,而不能靠研发人员自己的臆想或猜测。ChatGPT 给我最大的启发其实是这一点,至于是否用增强学习我倒觉得不重要,其它替代技术应该也能做类似的事情。