大语言模型的基本原理

大语言模型(Large Language Models, LLMs)的训练主要分为预训练(pre-training)和后训练(post-training)两个部分。

预训练(Pre-Training)

获取预训练数据集

为了让模型学会语言,首先需要收集大量人类语言的数据。以ChatGPT为例,人们首先在互联网上(用爬虫等方式)获取大量公开文本数据。这样得到的原始数据包含很多低质量语料、重复语料、不良信息等,必须经过过滤(可以设计算法以更加自动化地完成过滤)。FineWeb就是这样一个经过处理的公开的互联网语料数据集,包含十几亿个高质量的网页文本(如维基百科、新闻稿、书籍等等)。

Tokenization

接下来的问题是,我们应当把文本以什么形式作为模型的输入(如何编码)?自然的思路有,以文本字符本身作为编码,把文本展开为二进制编码,以单词为单位编码等等。不同编码方式对文本的模式(pattern)的刻画效果是不同的,例如二进制编码会把文本展开得特别长,以单词为单位编码又会把文本压缩得比较短。经过实验,人们发现把一个单词划分成一到三个(平均)部分,并按每个部分分别编码的方式,在大语言模型的训练上比较有效。每一个被编码的单词子串称为一个token,把文本转化为token序列的过程称为tokenization。GPT4共编码了100277个不同的token。

训练模型

把互联网语料数据集转化为token序列以后,我们训练一个神经网络,使得它在输入一个token序列时,能够“模仿”训练数据集来预测下一个token。通常的做法是,随机选取训练数据集中的一段连续的token(量级约为几千到几十万),让模型给出输出。模型的输出是每个token作为下一个token的概率(也即100277个\([0,1]\)中的数),用这一概率分布匹配训练数据集中的下一个token,优化模型的参数(对应于神经网络中根据loss function反向传播)。关于如何设计该模型的具体架构,可以参见“Transformer架构”一文。如果不关心模型的具体架构,则我们只需将模型看作一个关于token序列和参数(截至2024年,参数量级约为7000亿左右)的一个确定性的函数,一旦输入的token序列和模型参数取定,模型会输出一个确定的概率分布。

由于训练数据集庞大以及参数众多,该训练过程通常需要在数千台机器上训练好几个月才能完成。

生成文本

有了训练好的模型以后,我们可以输入给模型一个token序列。此时模型会给出next token的一个概率分布,我们按照概率分布采样一个token,接着再把这一token接到输入的最后,再把新的token序列输入模型。如此反复,模型就能持续生成token序列。如果模型训练效果足够好,那么它已经能够实现依据输入的提示词生成接下来的连贯有意义的自然语言文本了。

注意,我们并不总是选取概率分布中概率最大的next token,而是依据概率分布采样。这就让模型输出带有了随机性。哪怕提示词相同,只要采样过程中有一个token和上一轮不同,就会链式效应产生一个不同的回答。


至此,我们已经结束了对预训练的讨论。经过了预训练的模型和我们日常使用的成品模型还有很大的区别。回顾该训练过程容易发现,预训练模型只是一个模拟互联网文本数据的next token预测器。例如,如果给预训练模型输入提示词“1+1=2吗?”它可能会这样接下去,如果它恰好在一篇类似的“哲学论文”上训练过:“1+1=2吗?这是个问题,它可以等于2,也可以不等于2。谁知道呢?……”预训练过程让模型“掌握”了人类语言的语法,能够“背诵”或“模仿”人类的写作。它只是用来拟合大规模互联网文本的函数,并不具有回答问题、推理与思考等能力。

后训练(Post-Training)

我们通常把经过预训练的模型称为一个base model(基础模型)。后训练的任务就是以base model为基础继续训练模型,来让模型满足各类应用的需求,而不只是next token预测器。

上下文学习(In Context Learning, ICL)

最简单的让模型学会现实中的任务的方法是让模型直接从输入的提示词中学习。以翻译任务为例,我们可以设计下面的提示词来让base model做中文词语到日文词语的翻译:“苹果,りんご;狗,いぬ;猫,ねこ;面包,”。Base model会把这一提示词当作互联网文本中的某一段话,预测接下来的token。典型地,它会输出:“パン;学校,がっこう;...”它不仅会正确完成“面包”的翻译,还会预测你下一个想让它翻译的中文词汇。这是因为base model的训练数据中通常包含互联网上的中日单词对照表,在模型读到提示词时,会把它当成单词表,预测接下来的token。不过,通过截取模型输出的第一个单词,我们已经能够实现AI翻译单词的任务了。把单词替换为句子,AI就能实现句子翻译;把中文单词和日文单词替换为英文段落和中文总结,模型就可以实现写中文摘要的能力;等等。

注意到,模型的能力(知识)蕴藏在我们通过训练得到的参数里。然而,我们并不能保证模型总是准确地完成任务。如果模型恰好没有见过某一单词,它并不会回答不知道,而是尽可能去预测符合互联网文本的next token。这称为模型的幻觉(hallucination)问题,我们之后会详细讨论。

通过ICL,我们也能把base model改造成一个聊天机器人或回答问题的agent。只需在用户提问前,首先插入这样的提示词:“User: 你好!Agent: 你好,有什么我可以帮助你的吗?User: 1+1等于几?Agent: 1+1=2。... User: ”这时,base model就能够发现输入提示词的pattern,而表现得像一个乐于助人的agent。

监督微调(Supervised Fine-Tuning, SFT)

Data Conversations

对于实现对话和回答问题agent,相比于ICL,一个更直接的方式是在base model的基础上用大量继续训练模型的参数,让模型从一个互联网文本的next token预测器转变为一个对话文本的next token预测器,而后者实际上就是一个回答问题的agent。具体做法是:收集问题以及解答(以我们期望agent输出的形式),把训练数据集替换为这些问答文本的token串(数据集中不再保留原先的互联网文本),这些token串中增添了新的token用作分隔符:<start>,<sep>,<end>等(新token是base model没有见过的)。问答的训练数据形式如下:“<start>你好!<sep>你好,有什么我可以帮助你的吗?<end><start>1+1等于几?<sep>1+1=2。<end>”。训练的方式还是和预训练相同,随机抽取token串,根据数据集中的next token和模型输出的概率分布计算loss,用反向传播更新参数。由于对话数据通常需要人工构造,其规模远小于预训练时的互联网文本。通常,这一训练只需几小时就能完成,也即它们并不对base model的参数做太大的调整,所以称为微调(fine-tuning)。尽管只是“微调”,但模型在输出对话的能力上却相比于base model有巨大提升。由于我们是用事先构造的数据做微调,所以是监督学习,所以这一过程称为监督微调(SFT)。

在上面的对话agent的SFT中,对话数据一般是这样构造的:大的公司(比如OpenAI)编写回答的书写规范(比如表现出热忱),然后招募各个领域(物理、生物、医学)的专家来写回答。专家通常会查阅资料、网络来确保回答准确完善。在收集了足够多的人工回答以后,可以用已有的语言模型帮助生成回答再由人工检查来降低工作量。

Hallucination(幻觉)

以GPT4为例的大语言模型就是预训练+对话agent SFT训练完成的。所以在和这样的大模型对话时,我们可以把大模型想象成那些书写对话的员工。大模型在模仿这些员工书写对话的方式和我们对话。所谓“模仿”,就是对知识的有损压缩(lossy compression)和推广。

尽管互联网文本和SFT数据集覆盖了大部分人类的知识,但显然无法保证它们能够覆盖全部的人类知识。所以在和这样的大模型对话时,大模型会容易出现幻觉,编造出不符合事实的“知识”。这并不令人惊讶,因为机器学习的本质是用数学模型拟合训练数据,从而让模型具有训练数据的统计特征(statistical characteristics)。而正确的事实和错误的事实有时具有相同的统计特征。

为了减轻大模型的幻觉现象,一个合理的设计是要求大模型在没有把握时输出“我不知道”或“我不确定”。显然,如果SFT数据集中所有数据的形式都是问题与其正确答案,那么由于大模型会学习统计特征,它总是会捏造事实。所以我们需要往SFT数据集中加入一些回答“我不知道”的问题。问题是,如何确定大模型究竟知不知道某一事实呢?我们通常会对大模型进行审问(interrogate),对于一个我们确定了答案的问题,我们询问大模型多次,如果大模型大概率答不对这个问题,就说明大模型缺乏这一知识。更有意思的是,我们可以基于有幻觉的大模型来自动化审问的过程。方法是,在网上搜寻一段事实文本,以提示词的方式输入大模型,并要求大模型基于这段文本生成若干问题和对应的回答。由于大模型是从提示词出发生成的问题的答案,这些答案不存在幻觉的问题。于是我们就可以拿着这些问题和答案去审问大模型(判读大模型的输出是否符合答案也可以用大模型自动完成)。这样在训练过程中我们意识到,上述方法蕴含了一个重要的观察:“存储在大模型参数中的知识是模糊的,而作为输入给大模型的上下文的知识是清晰的。这与人类其实也是相似的,存储在人的记忆中的知识是模糊的,而摆在人面前正在被人阅读的文字中的知识是清晰的。前者是vague recollection,后者是working memory”。然后,对于大模型不知道的知识,我们添加“我不知道”的回答到训练数据集里。这样,大模型在训练过程中就会“学习”哪些是自己知道的知识,哪些是自己不知道的知识。

为了缓解幻觉问题,还可以让大模型联网搜索。具体方法是,当用户提出一个问题时,大模型首先在互联网上搜索该问题的答案(只需把用户的问题放到搜索框里),然后获取相关网页的文本。接下来只需要把这些文本放入提示词内(context),然后加一句类似这样的提示词:“总结以上文本内容,回答问题:...”。再一次,上下文中是清晰的知识,所以不再有幻觉问题。如果大模型已经训练出了较好的自我知识的认知,那么也可以让大模型自己判断是否需要联网搜索。

用户自己也可以通过提示词缓解幻觉现象。在实践中人们发现,LLM并不擅长对人来说非常简单的问题。例如,counting对AI来说是一个困难的任务,著名的例子是“单词strawberry中有几个r?”以及“.............是多少个点?”这是因为单词是以token的形式被大模型“理解”的,而从token到counting的映射相比于文本到counting的映射自然复杂许多。再例如,“9.11和9.9哪个大?”,LLM可能混淆了作为数字的9.11和作为书的章节编号的9.11(第9章第11节自然大于第9章第9节)。对于诸如这样的简单任务,用户只需要增加提示词Use Code,大模型就会编写相关的程序。在写程序时大模型只需对用户的token做复制粘贴,这是不会出错的。之后只需要运行大模型的程序就可以得到正确的解答,避免了LLM的幻觉。

LLM的计算推理能力

实践表明,用以上方法训练得到的大模型能解决一些需要推理和数学计算的问题。然而实践也表明,诸如大整数运算、需要复杂推理步骤的问题并不是大模型的强项。这也不令人惊讶,因为我们相信问题的计算复杂性是确定的,解决不同难度的问题所需的计算步骤(能量)是不同的。而LLM的架构中next token的预测总是经过一个完全固定的函数,所以我们可以认为每个next token所能经历的计算步骤是非常有限的。

举一个非常有启发性的例子。当LLM回答一道计算题时,下面两种回答方式哪种更容易出错?第一种:答案是3,因为...;第二种,因为...,所以答案是3。显然第一种更容易出错,因为在预测“答案是”的下一token时,我们要求模型完成整道题的计算量,在计算量不足时就LLM只能先“乱猜”一个答案;而在第二种回答中,模型可以把整道题的计算量分摊到推导过程的各个token上。用户可以在提示词中写“Let's think step by step”来提高模型的推理计算能力。

因此人们意识到,LLM的思考能力其实就在其输出的token序列上。这其实与人类也是类似的,复杂的问题人类需要思考很久,而简单的问题人类很快就能给出答案,甚至可以口算。只不过,人类可以打草稿,也可以在脑海里想象。而LLM能做的只有输出token。对于越复杂的问题,LLM越需要长的token序列来铺垫。这一发现称为LLM的思维链(Chain of Thought, CoT)。事实上,我们可以相信理性思考本就应该是符号化的,也就是语言化、形式化的。“费曼学习法”中通过教别人、写讲义的方式来学习,实际上就是发现了把模糊的思维过程清晰表达出来的学习方法。现在人们发现,这一方法也恰好适用于LLM。

多模态大语言模型(Multimodal LLMs)

监督微调的方法也可以让大语言模型跳出“语言文本”这一限制,也能够处理音频、图片、视频等多种形态的信息格式。能同时处理多种信息格式并能在信息格式之间转换的大语言模型被称为多模态大语言模型。

实现多模态的方法很简单——只需要把各种形式的信息格式编码为token序列!例如,如果我们想实现一个能把音频转换为文字的AI,可以这样做:设计一种有效的算法把音频转换为一串token(不同于base model中用于表示文字的token),这一编码方式需要能够足够好的保存音频的信息。接着,只需收集音频token串到音频对应的文本的SFT数据集,在base model上做监督微调即可。图片、视频也是类似,只需设计图片、视频到token序列的编解码算法(这些算法本身也可以是LLM或其它AI模型),然后做SFT。

强化学习(Reinforcement Learning, RL)

如果把训练大模型的过程比作学一门课的学生,那么预训练阶段就可以看作让学生阅读课本上的知识,监督微调的过程可以看作学习课本上的例题。通常,学生还必须完成老师布置的(或书后的)课后习题。做习题的过程和看例题不一样,看例题的时候学生必须被动地遵循答案的解题思路,而做题的学生必须主动构造一个解答,在这个过程中学生必须做各种尝试、猜想、计算、验证。如果学生足够聪明,还可以发现比例题中的答案更简单的方法。

在大模型的后训练阶段,我们也希望能增加让模型主动学习回答问题、解决问题的训练阶段,而不只是让模型一味模仿互联网文本以及SFT数据集中的回答问题的方式。这事实上比学生做课后习题更重要,因为通常情况下例题会选择最适合学生理解的方法,而作为人类我们并不知道什么样的解法最适合大模型。以小学数学为例, 我们并不知道是列算式更适合大模型,还是解方程更适合大模型,是用文字说明更适合大模型,还是转化为抽象数学问题更适合大模型。最适合大模型的解题方式必须由大模型自己发现!

Verifiable Tasks

让我们先来考虑人们能给出一个明确答案的任务,比如数学题、化学题等等。这样的任务很容易评估结果,所以我们可以通过大模型的解答来调整大模型的参数。例如,对于一个问题,我们让大模型回答15次,假如大模型只回答对了4次,那么这首先说明大模型在这个任务上表现不好,但也同时说明回答对的那4次的回答方式相比于其它11次回答的方式更适合大模型解题。所以我们选择大模型回答对的(中的一些)回答,和问题本身一起加入训练数据集。在众多不同问题上重复以上过程,大模型的回答会越来越接近那些更容易答对的范式,也就是更适合大模型的范式。实验表明,这样做确实能稳步提高大模型的解题能力。(以上过程并不需要人工的参与,因为判断模型回答是否正确的任务可以由SFT的大模型很好的完成)

事实上,这样通过监督、奖惩、调参的训练方法有广泛的应用,称为强化学习(RL)。AlphaGo就用了强化学习的方法最终超过了人类棋手。在AlphaGo中,人们设计函数来奖励好棋、惩罚坏棋,从而让模型自己发现最优的棋步,而不是一味模仿人类的棋谱。模型甚至可以在不参考任何人类棋谱的情况下,只是通过强化学习训练最终超越人类。这是拟合人类棋谱的模型从未能做到的。

在用强化学习训练大模型的解题、推理能力时,大模型找到了这样一种范式:“让我一步一步分析问题,...,等等,我想我找到答案了,让我再一步步验证一下,...,确实没问题,让我再用另一种方法检验一下,...,没错,我想这就是正确答案。”大模型通过分步的看似“冗长”推理,并且反复以各种方法加以验证,可以以最高概率答对问题。这其实和人类完全相符,越是仔细推敲仔细验证,越能取得正确答案。人们在这一强化学习过程中的重要发现是,越是允许大模型给出越长的回答,大模型就能以更高的准确率回答更多的问题。这与思维链的发现是一致的,LLM的推理能力蕴含在token序列中。

Unverifiable Tasks

对于解题,我们有一个明确的答案可以验证。对于证明,已经有些困难了,可以把AI的输出配合上形式化验证的工具,人们正在做这方面研究。而对于“写一首诗”,“总结一下这段文字”这类完全开放的任务,我们无法设计一个好的奖励函数来做强化学习。而这对大语言模型其实是一个重要的任务,我们希望他能够有比SFT模型有更好的表现。

一个直接的思路是,既然无法用公式打分,那就用人工来打分。这样的训练方式称为带人工反馈的强化学习(Reinforcement Learning with Human Feedback, RLHF)。听上去很愚蠢, 但我们可以用各种方法来压缩人的工作量。首先注意到,在强化学习中我们并不需要人工来构造一个具体的样本,而只需要在AI构造的诸个回答中判断哪些好哪些不好。判断是一个比直接构造轻松地多的任务(类比\(\text{P}\neq \text{NP}\))。我们还可以通过人工给AI的诸个回答的排名,训练一个用来打分的大模型。这个大模型会模仿人类给AI的诸个回答排名,间接地起到了奖励函数的作用。然而,这样的方法的问题在于,由于大模型模仿人类打分难免有疏漏,假如它给一些不好的回答打了极高的高分,强化学习就倾向于让AI生成这些不好的回答。这样的样本称为对抗样本(adversarial examples)。对抗样本是无法消除的,因为我们找不到一个完美的打分模型。在实践中,对于unverifiable tasks我们通常不能做太久的强化学习训练,短期的强化学习能提高一定的质量,而一旦超过某一阈值模型产生的答案质量会大幅下跌(陷入了对抗样本的模式)。

Reference

Andrej Karpathy, Deep dive into LLMs like ChatGPT

posted @ 2025-02-17 01:40  行而上  阅读(804)  评论(0)    收藏  举报