大语言模型是怎么工作的?浅析 Transformer 架构
浅析 Transformer 架构
前言
不知道从什么时候起,我已经用 AI 帮我做了很多事情了 大多数是用 AI 糊弄学校的作业。彼时的我和大多数人一样,完全不理解 AI 到底是怎么工作的,觉得这个东西是一个玄而又玄的技术。
就在这几天,我决定要对 AI Agent 方向进行学习探索,于是第一个接触的内容就是 Transformer 架构。网络上很多深入浅出的教程给了我很大的启发,其实 LLM 的基本原理没有那么高端复杂。
所以本文从一个刚刚接触 AI Agent 方向的小白的角度,阐述 Transformer 的主要基本原理。一方面供自己温习,一方面也可能可以帮助其他想要入门的人。
万字长文警告。
正文
从 LLM 开始
LLM 是大型语言模型(英语:large language model)的缩写,简称大模型。其中,“大型”代表其具有庞大的参数量;“语言模型”代表其专为自然语言处理任务而设计,尤其适用于语言生成。平日我们对话的大部分聊天 AI 都属于 LLM。
LLM 的一大用处就是补全文本。譬如你给一个 LLM 丢一份只写了开头的句子,它可以顺利地补全句子,甚至可以不断继续生成下去,组成一篇文章。你可能会好奇它到底是怎么工作的,其实 LLM 的核心思想非常简单:LLM 通过已有的文字,预测下一个词(准确来说是 token)的概率分布,来实现生成补全。
例如,你输入“今天天气真”,LLM 会计算所有可能的下一个词的概率。可能的概率分布长这样:
| 词 | 概率 |
|---|---|
| 好 | 30% |
| 不错 | 20% |
| 热 | 10% |
| … | … |
LLM 会根据概率和一定的策略选择一个词,补充在句子后面。然后根据补充的句子继续预测下一个词,如此循环,一个词一个词地生成完整的内容。这个机制叫做自回归生成(Autoregressive Generation)。
听起来好像很简单,实际上也确实是很容易理解。但是困难的点在于,LLM 如何计算下一个词的概率?如何才能保证 LLM 计算的概率分布符合我们所知的语法、事实、推理甚至世界知识?这就是我们接下来要介绍的东西。
概念:词嵌入
词嵌入(Word Embedding) 是 LLM 的一个核心基础。
想一想,如果是人类来补全“今天天气真”这句话,人类会怎么思考?显然,我们也会补充出例如“好”、“不错”、“糟糕”、“热”、“凉爽”之类的词语。我们之所以会认为这些填法都是合理的,是因为这些词都有一些相似之处:都是形容词,且都能形容天气。
人类能理解这种词语间关系,是不断学习应用的结果。但计算机本身读不懂文字,它只读得懂数字。所以,如果我们要让“模型”也能理解词语间的关系,就需要量化每个词语。
词嵌入的本质就是将文字转化为「数字坐标」,所有的词都放置在一个巨大的语义地图上,每个词都是地图上的一个点。语义相近的词在数学空间上的距离也相近。
例如:
- 「狗」和「狼」在地图上的距离就很近,因为都是犬科动物
- 「狗」和「斑马」在地图上的距离也比较近,因为都是动物,但肯定没有「狗」和「狼」的距离近。
- 「狗」和「飞天意大利面」的距离就很远了,这俩基本没什么关联。
所以,词嵌入本质就是在给每个词一个精确的坐标,让模型看得懂这些关系。
为了更精确的表示这些关系,地图的维度不会只是简单的二维或三维,而是用更多更大的维度,比如 768 维、4096 维,这样一个词语的坐标可以用一个向量来表示。
每个维度代表了不同的含义,有不同的偏向,你可以粗略地类比为:每个维度就相当于提了一个问题,词语在这个维度上的坐标值就是其相关度。
例如:“这个词和水果的相关度?” 可能的结果:
- 「香蕉」:在这个维度的坐标值为 100,显然是水果。
- 「番茄」:在这个维度坐标值为 70,部分人认为是水果,但也有一部分人认为是蔬菜,姑且还是相关。
- 「沃尔玛购物袋」:在这个维度的坐标值为 40,不是水果,但起码可以装水果。
- 「武装直升机」:在这个维度坐标值为 5,基本没啥关联。
通过上述方法,赋予每个词语在每个维度上的值,也就是构造合适的向量,让语义关系体现在数学关系上,模型就能知道词之间的关联,在什么语境下应当填写哪类词语。
值得一提的是,词嵌入还有一些神奇的特性。最著名的例子就是:其向量可以做「语义算术」。例如:
- 国王 - 男人 + 女人 ≈ 女王
用数学来解释,就是:
- 「国王」向量 ≈ [皇室, 男性, 权力, …]
- 减去「男性」的性别特征
- 加上「女性」的性别特征
- 得到 [皇室, 女性, 权力, …] ≈ 女王
类似地,也有:巴黎 - 法国 + 意大利 ≈ 罗马。
事实上,我们可以用更加“数学”的方式去阐述这个现象。我们可以让一个向量
- 「国王」向量 +
\vec V ≈ 「女王」向量 - 「父亲」向量 +
\vec V ≈ 「母亲」向量 - 「兄弟」向量 +
\vec V ≈ 「姐妹」向量
这说明了,词嵌入不仅记住了词的含义,还很好地编码了词之间的关系。
词嵌入是如何训练的
我们刚刚提到,词嵌入其实就是把每个词用一个向量表示,向量上不同维度的值大致代表了与某个问题的相关性。
那每个词语的向量是怎么构造出来的?世界上的词语浩如烟海,一个词语又有如此多的维度信息需要填写,总不可能人为去设置每个维度的问题,然后去筛选填写吧!所以,我们需要一个合理的训练方式,给每个词赋予合适的向量。
对于词嵌入训练,核心思想是上下文预测,也就是:一个词的意思,由它周围的词决定。
我们以 Word2Vec(词语转向量)为例,训练过程如下:
- 准备大量的文本,例如可以从维基百科、新闻中选材,做一遍文本清洗(去噪、规范化、分词)。
- 使用滑动窗口:取一个句子,遮住中间的一个词,让模型选词。例如:
我 喜欢 [?] 因为 它 很 可爱模型需要根据上下文「喜欢」「因为」「可爱」来预测中间是「猫」。
- 调整向量:如果模型猜错了,就调整这个词的向量坐标,让其更接近正确答案。
- 反复迭代:经过海量文本的训练,每个词的坐标就稳定下来了。
上面是大概的流程,具体而言,模型会把「我」「喜欢」「因为」「它」「很」「可爱」的向量取平均,输入一个简单的神经网络,然后输出一个巨大的词语概率分布。调整向量与迭代的目的是为了让「猫」的概率尽量大。
这种训练模式叫做 CBOW(Continuous Bag of Words),也就是用上下文预测中心词。
在数据集比较大的情况下,有一种更常用的方法叫做 Skip-gram,也就是用中心词预测上下文。和 CBOW 反过来,通过给模型输入「猫」的向量,经过神经网络,目标是让窗口内的词(我、喜欢、因为...)概率高,窗口外的词概率低。
上面描述的只是很粗略的步骤,实际上词嵌入训练还有很多细节。
另外,训练的技术也是在不断更新迭代的。现如今的 LLM(如 GPT、Claude)已经不再单独训练词嵌入,而是把一个词拆成词元(Token),例如把 "unhappiness" -> "un" + "happi" + "ness"。然后将词嵌入作为模型的第一层,和后续层一起端到端训练。其训练出来的维度更大(4096D、8192D),表达能力也更强。
Transformer 架构的引入
经过词嵌入后,对于一个词而言,其对应且仅对应了一个向量坐标。
但这又引入了另外一个问题,同一个词在不同语境下可能是具有不同含义的,举例来说:
- “今天我吃了一个苹果” 与 “苹果公司推出了新产品”:显然,前者的苹果指的就是一种水果,而后者的苹果指的是科技公司的品牌名。
再比如:
- “张三把书送给了李四,因为他很喜欢阅读”:这里的他大概率指代的是李四。
那对于同一个词,其词嵌入向量相同的情况下,怎么才能让模型知道这个“他”指代的不是张三而是李四呢?这就引入了 Transformer 架构的一个重要概念:自注意力(Self-Attention) 机制。
只需要注意力就够了!
现代的 Transformer 架构首次在 2017 年谷歌发布的一篇论文《Attention Is All You Need》中被提出,其中自注意力机制是最引人注目的部分。在此之前,注意力机制虽已广泛用于辅助循环神经网络(RNN),但几乎没人相信仅靠注意力本身就能支撑整个架构。
:::info[论文趣事一则]{open} Attention Is All You Need 这个标题致敬了披头士乐队的歌曲《All You Need Is Love》,“Transformer”这一名称由论文作者之一雅各布·乌什科雷特(Jakob Uszkoreit)选定,因其喜欢该词的发音。
早期设计文档曾命名为《Transformers:面向多任务的迭代式自注意力与处理》,并包含《变形金刚》(Transformers)系列六个角色的插图,团队亦命名为“Team Transformer”。 :::
回想一下之前的例子,一个词在不同语境下拥有了不同的含义,本质上是上下文对其产生了影响。
对于「苹果」这个词,如果在前面发现了「吃」这样的词,说明其代表的是水果;而如果在后面发现了「公司」的字样,说明其代表的是品牌名;同样的,要清楚句子中的「他」指代的是谁,则需要综合上下文的语义及逻辑关系来进行分析。
这说明,一个词的含义会被上下文所影响。有时候这种影响可能会来自很远的地方,词的含义也有可能会受到大量而非少量上下文的影响。例如,给模型输入一整本推理小说,最后一句“真正的罪犯是”让模型补全,那么模型就需要具备综合分析大量上下文的能力。
自注意力机制的作用就是,让模型在处理一个词时,让其能够关注上下文中的其他位置。当模型在处理「他」这个词时,自注意力机制让其与「李四」联系起来。
为了达成这个目的,我们需要让所有输入的初始向量之间可以相互交流更新,让每个词向量停留在更具体更精准的含义上。让「吃」这个词去更新「苹果」,使「苹果」向量的含义更精准地停留在“一种水果”的含义上;让「书」「喜欢」「阅读」等词去更新「他」,使「他」向量的含义更精准的停留在指代「李四」的含义上。
那么,自注意力具体是如何实现的呢?
自注意力机制如何工作?
让我们通过这句话来分析:
这 有 只 毛茸茸 的 棕色 动物
最初,每个词都会初始嵌入一个向量(通过词嵌入),此时,每个词的向量只编码了其初始含义,和上下文是没有关联的。然后,通过位置编码(Positional Encoding) 将每个词的位置编码进向量中。这里不介绍其具体是如何工作的,你只需要知道在编码后,所有向量足以说明这个词是什么,以及在哪个位置。我们记词的初始向量为
我们的最终目标是通过一系列计算,更新原来的向量
为此,我们需要引入三个角色:Q、K、V,分别代表查询、键、值。更详细地说:
- Q:代表 Query,指“我在找什么信息?”
- K:代表 Key,指“我能提供什么?”
- V:代表 Value,指“我的实际内容是什么?”
其中,Q, K, V 都以矩阵的方式进行编码。
这样讲还是太抽象了,我们回到刚刚的例子上来。现在我们要更新「动物」这个词的向量,你可以想象这个词发出了一个提问:“我前面存在形容词吗?”,而「毛茸茸」和「棕色」这两个词想回答:“有的!我就是形容词”。
从数学上的实现来讲,像“查询前面是否有形容词”这样的询问都被编码为了一个“查询矩阵”,记作
同样的,像“我是形容词”这样的回答都被编码为了一个“键矩阵”,记作
需要指出的是,
对于一个词得到的
从数学意义上来讲,假设各向量长度相近时,两个向量
所以可以通过计算
现在我们有了「查询」与「键」之间的相关度,但光有相关度还不够——相关度只回答了"该关注谁",还没有回答"关注到了什么内容"。这就是第三个角色 V 要干的事情。
回到例子上,「动物」发出了询问,「毛茸茸」和「棕色」回答了“我就是形容词”。那么接下来,「动物」真正想从它们那里拿走的,是它们各自的实际内容,也就是“毛茸茸的特征”和“棕色的特征”本身。这些内容,正是通过「值」来传递的。
词的实际内容也被编码为一个"值矩阵",记作
有了
其中权重
当然,实际运算上,我们不会把每个词的向量分开进行分别计算,所有上下文的词嵌入向量都被打包成了一个矩阵,然后整体进行矩阵乘法运算。上面所有的描述,在《Attention Is All You Need》中被描述为一个优雅的公式:
你可能对其中的
如果你对
至此,我们最初的目标就达成了:更新后的
如果你能理解上面的内容,你就已经理解了自注意力机制的核心。
很多很多头的注意力
回顾一下我们刚才做的事情,「动物」发出了一个查询:“我前面存在形容词吗?”,然后根据回答更新了自己。整个过程看起来很完美,但仔细想想会发现一个问题:一个词需要关心的关系,往往不止一种。
还是以「动物」为例。它可能想同时发出好几个不同的查询:
- "我前面有形容词吗?"(关注「毛茸茸」「棕色」——修饰关系)
- "我是被哪个量词修饰的?"(关注「只」——数量关系)
- "我前面有动词吗?动作是谁发出的?"(关注「有」——句法结构)
如果只有一套
于是,论文中引入了一种名为 “多头注意力”(Multi-Head Attention) 机制的改进,进一步提升了自注意力层的性能。它的核心思路也很简单粗暴:既然一套注意力不够用,那就同时用很多套。
从数学的含义上讲,我们准备 h 组彼此独立的矩阵。这里取 h=8 组,于是我们有了:
其中,每一组称为一个「头」,每个头都完整地执行一遍我们之前讲过的自注意力全流程。
你可以想象有 8 个人同时读这句话,每个人只从自己关心的角度去理解:第一个人专门盯形容词,第二个人专门盯量词,第三个人专门盯句子的主干结构...第一个人理解出的「动物」是“毛茸茸的、棕色的”,第二个人理解出的是“数量为一只的”,第三个人理解出的是“被拥有着的”。
当然,这里再提一嘴,我们其实很难用语言去解释一个矩阵它到底干了什么,在运算起了什么作用。上面只是一种形式化的比喻,让其过程更容易理解。实际上,没有人告诉第一个头“你要去关注形容词”。每个头的矩阵是从大量数据中训练出来的,模型在学习过程中自发地让不同的头分化出了不同的关注点。研究人员在分析训练好的模型时,确实发现了有的头偏好相邻的词、有的头偏好指代关系、有的头偏好标点结构,这种现象再次印证了多头设计的合理性。
好了,现在 8 个头各自给出了一个更新后的向量,每个向量都只说对了一部分,怎么把它们合并成一个最终结果呢?
做法很简单:我们先将每个向量拼接在一起,然后再将它们与一个额外的权重矩阵
这里的
用公式总结整个过程就是:
至此,每个词的新向量就真正融合了来自多个视角的上下文信息。
残差连接
到目前为止,我们已经讲完了一个注意力模块的内部结构。但一个完整的模型并不会只做一次注意力计算,注意力计算后还会经过一个前馈网络(FFN) 模块,这两个模块最后会打包成一组,进行反复的堆叠,堆上几十层甚至上百层,每一层都在上一层的基础上继续加工向量。
这意味着,某个词在吸收一些上下文信息后,产生的含义更丰富细致的向量,还有更多的机会被周围含义更细致的向量所影响。其经过越多的模块,其向量本身的含义就会越来越丰富,理想的话,对于输入的内容,能提炼出更高级、更抽象的概念,而不仅仅是修饰和语法结构。也许还包括情感、语气、诗意以及科学原理等等。
但事不遂人愿,实际上,向量在不断的加工后,会出现一个问题:信息传得越久,就越容易走样。
你可以想象一个“传话游戏”:一句话经过几十个人依次转述,传到最后一句话时往往面目全非——每转述一次都会丢失一点细节、混入一点偏差。向量在层间传递也是同样的道理:每一层的注意力计算都会重新混合所有词的信息,「动物」原始的词义在一层层加工中被不断稀释。传到几十层之后,它可能早就“忘记”自己最初是什么词了。
更要命的是训练层面的困难。如果你了解基本的机器学习就会知道,训练模型靠的是从输出端反向传播误差信号,来逐层调整参数。但是如果层数太深,这个信号在层层回传的过程中会不断衰减(即梯度消失),导致靠前的几十层几乎接收不到任何有效的调整指令,那这些层就“学不动”了。
如何解决这个问题呢?出乎意料的是,解决方法异常地简单:每一层算出新向量后,不急着把旧向量扔掉,而是把它原封不动地加回来。这个方法就叫做残差连接(Residual Connection)。
从数学上的实现来讲,就是:
也就是说,每一层的工作不再是“重写”向量,而是“修改”向量,只负责在原有内容的基础上补充增量。
回到我们的例子:「动物」向量经过注意力层后,新向量 = 原来的「动物」+ 刚学到的“毛茸茸、棕色”等增量信息。这样一来,无论堆多少层,「动物」的原始词义始终完好地保存在向量里,每一层只是在它之上做加法,而不是把它覆盖掉。这类似于我们修订一篇文稿:原稿始终都是不变可见的,而每个人只是在旁边添加批注和修改,不会把原稿翻新重写。
对于训练来说,残差连接还带来了一个额外的好处:它为误差信号修了一条“高速公路”。由于每一层都有一条绕过注意力计算的直达通路,误差信号可以顺着这些通路几乎无损地传回最靠前的层,让深层网络也能被有效地训练。可以这么说:没有残差连接,现在动辄上百层的大模型根本无从训练。
:::info[残差连接的发展]{open} 残差连接是继承了 ResNet(残差网络) 这一思想得来的。其核心论文《Deep Residual Learning for Image Recognition》发表于 2015 年(CVPR 2016,获最佳论文奖),该论文作者均是华人研究者,第一作者是何恺明,当时任职于微软亚洲研究院(MSRA),论文的共同作者张祥雨、任少庆、孙剑也都是华人研究者。
残差的思想在 ResNet 之前已有雏形,但运用的工作上产生的影响极其有限。是 ResNet 首次把“输入直接加回输出”这种简洁形式做到极深的网络上,以压倒性优势拿下 ImageNet 冠军,让全世界认识到残差连接是训练深层网络的关键。何恺明也因此成为深度学习领域被引用最多的研究者之一。Transformer 论文(2017)沿用的正是 ResNet 验证过的这套做法。
何恺明后来加入 Facebook AI Research(FAIR),又主导了 Mask R-CNN 等重要工作,2024 年起在 MIT 任教。 :::
需要指出的是,实际的模型中通常还会搭配一个层归一化(LayerNorm) 操作,在每一层计算前把向量的数值调整到稳定的范围内,防止数值在层层累加中越滚越大。残差连接配合层归一化共同保证了深层网络的稳定。
概念:前馈网络
在前面,我们提到了前馈网络(Feed-Forward Network,FFN) 这一概念,这同样是 Transformer 架构的重要组成之一。实际上,相较注意力模块,FFN 才是模型参数量的“大头”。在一个典型的 Transformer 层里,大约三分之二的参数都集中在 FFN 中。
那为什么我们需要 FFN,它起到了什么作用呢?
简单来说,自注意力层让词与词之间相互交换信息,使一个词向量嵌入了更丰富更精确的含义。但要注意,注意力本质上只做了一件事:搬运。它只是将别的词的信息按权重混合进指定词的向量,但信息的总量并没有被“消化”。
类比一下,就像是一个团队开完了一场会议,每个人都收到了同事的各种资料。那么接下来,每个人都需要回到自己工位上,把这些资料好好读一遍、提炼消化,形成自己的结论。这个“回到工位独立思考”的环节,就是前馈网络。
我们再来举一个更具体的例子。例如我们给模型输入“法国的首都”,那么经过自注意力模块后,「首都」这个词理应嵌入了「法国」这个词的相关含义,但是没有进行总结提炼。那么在经过 FFN 后,「首都」这个词就应该自行总结出「巴黎」这样的含义,再通过残差连接把这个含义包含进原来的词。
听起来很厉害吧!那要实现这样的效果该怎么做呢?实际上,其本质还是在通过一些训练过的矩阵进行数学计算。这部分概念可能比较抽象,好在对于每个词,其在 FFN 中的过程是并行的,它不像自注意力模块中,词与词之间会相互交流。所以我们只需要弄清楚一个词向量在 FFN 中是怎么进行计算的,就能推广到全体向量了。
前馈网络如何工作?
从结构上看,FFN 简单得有些出人意料——它只有三步:升维、筛选以及降维。我们来分开解析每一步的作用。
第一步:升维
首先,经过自注意力模块的词语向量
升维矩阵做了什么?我们可以把矩阵的每一列拆开来,视作很多不同的向量,回想一下自注意力机制中
- “你包含一个国家名吗?”
- “你是在描述一个地理概念吗?”
- “你和运动有关吗?”
- …
维度越高,能同时问的问题就越多,向量的特征就被剖析得越细致。这同时回答了“为什么要升维”这一问题:低维空间里挤在一起、难以区分的信息,到了高维空间里就有了足够的“地方”被分门别类地展开,方便模型进行更细致的处理。
整个升维矩阵和原词语向量相乘,得到的新高维向量在高维空间中的每个坐标,就是它对每个问题的回答得分。
然后,我们还需要引入一个偏置项
偏置项起的作用类似于划定了每个问题的“及格线”,当两向量相加后,值为正的坐标说明词语与问题相关,值越大则相关度越大。反之,值为负则一般说明不相关。例如偏置项中的某一坐标是 -5,那么词向量回答该坐标的问题值必须超过 5 才被视作“合格”。
在这里,值的正负很重要,0 被视作一个分界线,这也是为什么需要引入偏置项,你会在后面的步骤理解其为什么重要。
我们用“法国的首都”来举一个例子。也许存在这样一个“提问”,其偏置项中对应的坐标值是 -5。当其检测到「法国」会产生 3 的贡献,而检测到「首都」又会产生 3 的贡献。所以当完整地检测到一个词包含「法国」和「首都」的信息,就会得到 3+3-5=1,算作合格了。但如果只包含「法国」或「首都」其一,比如进入模型的是“法国的名菜”或“英国的首都”,这个问题就不会被视作合格,从而被后面的过程筛选掉。
第二步:筛选
这一步非常易于理解:把第一步得出的向量取出,然后将每个坐标值送进一个激活函数(Activation Function)。论文中使用的是 ReLU,它的规则十分简单粗暴:负数一律归零,正数原样保留。也就是:
经过这一步,绝大多数“问题”都被筛掉了,只有少数真正匹配的特征被保留下来。
这下,你应该可以稍微理解为什么前面要引入“偏置项”,是因为后续的计算环节,我们天生就把 0 当作分水岭来用。这个分界线的源头可以追溯到最早的感知机(Perceptron,1958),它直接模仿生物神经元“要么放电、要么静默”的特性,用的激活函数是阶跃函数:
在这个模型里,“大于 0 激活、小于 0 不激活”是字面意义上完全成立的。而现代网络大量使用的 ReLU 是阶跃函数的“软化版”,体现为:当值大于 0,则神经元激活,且激活强度线性增长;否则神经元完全不激活,特征被丢弃。
当下的大模型大多不用 ReLU,而是用 GELU 或 SwiGLU 这类函数,但起到的作用是类似的。
第三步:降维
接下来,经过 ReLU 筛选后的向量会与一个降维矩阵
如果说
回到之前的例子:在“法国的首都”这句话里,「首都」的向量经过注意力后已经带上了「法国」的信息。进入 FFN 后,某个神经元恰好负责检测“前面有国家名 + 当前词是首都”这个模式,经过升维和筛选后,它被成功激活。
而把
至此,经过 FFN 的三步骤,向量完成了一次从“收集资料”到“得出结论并记录”的完整过程。上面的过程同样可以总结为一个优雅的公式:
毫不意外的是,
:::info[FFN 是模型的“记忆库”吗?]{open}
研究人员发现,FFN 的行为很像一个“键-值”数据库(参见 2021 年的论文《Transformer Feed-Forward Layers Are Key-Value Memories》):
换言之,模型在训练中记住的大量事实知识,很可能主要就存储在 FFN 的矩阵里。这也解释了为什么 FFN 占据了模型约三分之二的参数,因为它不仅是模型的“消化器官”,还是一个整合了世界知识的“图书馆”。 :::
从向量回到文本
于是,经过几十层加工后,我们最后还是会得到每个词的最终向量。但还记得我们最初的内容吗?模型的使命是预测下一个词,向量毕竟只是数学对象,我们最终想要的,还是文章开头那样的概率分布表。这一步该怎么办呢?
首先我们要明确,虽然我们得到了全部词的最终向量,但我们其实只需要最后一个位置的向量。它站在句子的末尾,综合了全部上下文信息的位置,是最适合用于预测下一个词的向量。我们记它为
回想一下词嵌入:我们训练的模型把每个词都对应上了一个向量,这相当于模型手里有了一本“词典”,负责把词变成向量。而实际上,模型还有“第二本词典”,叫做输出嵌入矩阵(Output Embedding,也称 Unembedding),记作
然后,我们来进行一个打分操作。操作的方式你应该很熟悉了:把
直觉上,这相当于回到了语义地图:加工后的
但现在,我们有大量的词对应大量的分数,每个分数的值有大有小、可正可负,还不是概率。这个时候就要请出我们的老朋友
至此,文章开头那张概率分布表就算是真正地算出来了:「好」30%、「不错」20%、「热」10%……每一个概率数字的背后,都是几十层注意力与前馈网络联手加工的结果。
后记
到这里,我们已经讲解了一遍 Transformer 架构的主要结构原理。
让我们回到开头提出的那个问题:LLM 究竟是如何计算下一个词的概率的?现在我们可以给出一个虽然粗略、但不再神秘的回答了:每个词先通过词嵌入变成一个向量坐标,然后在一层又一层的模块里,先靠自注意力机制与上下文交换信息,再靠前馈网络独立思考、消化提炼,全程通过残差连接与层归一化保证稳定性。经过几十上百层这样的加工,最初那个只代表“孤立词义”的向量,已经被塑造成蕴含上下文、语法、逻辑乃至世界知识的丰富表示。最后,模型再根据这个向量换算出词表中每个词的得分,得到一个词语的概率分布表。
当然,正如文中反复强调的,本文只是一次入门级的“浅析”。还有太多重要的东西没有展开:模型具体是怎么训练的、生成时为什么不能“偷看”后面的词、编码器与解码器又有什么区别……这些就留给各位继续探索吧!文末的推荐阅读都是我学习时深受启发的资料,有不同视角下对 Transformer 架构的解读,强烈推荐。
另外,坦白说,我自己也只是一个刚入门的小白,写作本文的过程其实是我“以教促学”的尝试。文中难免存在疏漏甚至错误,如果你发现了,请务必指正,非常感谢。
最后,Transformer 的原理固然精妙,但我希望各位在读完这篇文章后能知道:它并不是什么高深的魔法,它只是一群聪明人把线性代数与矩阵乘法玩到极致的产物。希望大家以后再用 AI 的时候,心里能多一份“我知道你大概在干什么”的踏实感。
推荐阅读:
- 论文 - Attention Is All You Need
- 中文维基百科 - Transformer 架构
- Jay Alammar 的图解 Transformer - The Illustrated Transformer
- Bilibili: 3Blue1Brown - 直观解释 Transformer、直观解释注意力机制 与 直观解释大语言模型如何储存事实