如何通俗理解 Transformer 架构
以 GPT-3 为量化基准,逐层拆解 Decoder-only 大语言模型
第1章 从序列模型到 Transformer 的演进
在深入 Transformer 的内部结构之前,有必要先回答一个问题:在这套架构出现之前,人们用什么方法来处理文本序列?又遇到了什么根本性的困难?
答案是 RNN,也就是循环神经网络,以及它的改进版本 LSTM 和 GRU。RNN 的设计思路看起来非常自然:它像人读书一样,从左到右逐字阅读,同时用一个隐藏状态来记住前面读过的内容。每读到一个新词,就把这个词的信息和之前的记忆合并,更新隐藏状态。这个设计在直觉上毫无问题,甚至可以说是对人类阅读过程的直接模拟。但恰恰是这种"像人一样顺序处理"的思路,埋下了两个致命的结构性缺陷。
1.1 缺陷一:长距离依赖失效
考虑下面这个句子:
小明告诉小李,他很开心。
当 RNN 读到句末的"他"时,它必须判断这个"他"指的是谁。是"小明"还是"小李"?对人类读者来说,结合常识和语境,我们通常能做出判断。但对 RNN 来说,当它处理到"他"这个字时,"小明"这个信息已经经过了多个时间步的传递。
RNN 的每一步都在做同一件事:把当前输入和上一个隐藏状态压缩成一个新的隐藏状态。这个隐藏状态的维度是固定的,比如 256 维或 512 维。这意味着,无论句子已经有多长,前面所有的历史信息都必须被挤压进同一个固定大小的向量里。当句子从 5 个词变成 50 个词,再变成 500 个词时,这个向量并不会变大——它始终只有 256 维。早期信息被逐步覆盖、稀释,最终变得模糊不清。
这不是一个可以通过调参或增加网络深度来解决的工程问题。这是结构层面的限制:RNN 用固定维度的容器去装载无限增长的历史,容器满了,信息必然溢出。句子越长,模型对早期内容的记忆就越差。指代消解、长距离因果推理、跨段落的信息关联,这些任务对 RNN 来说都极为困难。
在 2014 年前后,研究者尝试用注意力机制来补救:让解码端在生成每个词时,都能回头去"看"编码端的所有隐藏状态,并动态决定关注哪些位置。这确实缓解了长距离依赖的问题,但 RNN 本身的顺序结构没有变,信息仍然需要一步一步地传递。
1.2 缺陷二:无法并行计算
RNN 的第二个缺陷与第一个同样根本,但性质不同。RNN 的第 t 步隐藏状态 h_t 必须依赖第 t-1 步的隐藏状态 h_{t-1} 才能计算:
h_t = f(h_{t-1}, x_t)
这个公式意味着严格的顺序依赖。处理一个包含 1000 个 token 的句子时,1000 个时间步必须一个接一个地串行执行。第 2 步必须等第 1 步算完,第 3 步必须等第 2 步算完,以此类推。
哪怕你有一块拥有上万个 CUDA 核心的 GPU,RNN 也无法让它们同时工作。batch 并行只能做到同时处理多个不同的句子,但句子内部的 1000 个位置始终无法并行。这使得 RNN 在大规模语料上的训练效率极低。当数据量达到数十亿甚至数万亿 token 时,RNN 的训练时间会变得不可接受。
1.3 Transformer 的解决方案
2017 年,Google 的研究团队发表了《Attention Is All You Need》,提出了 Transformer 架构。它对待序列问题的方式与 RNN 完全不同。
Transformer 不再按顺序传递信息。它让序列中的任意两个位置直接建立关联,关联的强度通过一次矩阵乘法计算得出。位置 1 和位置 1000 之间的关系,与位置 1 和位置 2 之间的关系,在计算复杂度上没有本质区别——都是一次矩阵运算。这从根本上解决了长距离依赖的问题。
同时,由于所有位置之间的关联计算互不依赖,它们可以同时在 GPU 上执行。一个 1000 个 token 的句子,其内部的所有位置可以在同一个计算批次中并行处理。这彻底解决了并行计算的问题。
实现这一切的核心机制叫做自注意力(Self-Attention)。它的基本思想是:序列中的每个词都生成三个向量——Query(查询)、Key(键)和 Value(值)。每个词用自己的 Query 去和所有词的 Key 做比较,得到一个关联分数,再用这个分数对所有词的 Value 做加权求和。这样一来,每个位置的输出都同时聚合了全序列的信息,而且整个过程完全由矩阵运算实现,天然适合 GPU 并行。
RNN 的设计者试图让机器"像人一样阅读",结果受制于顺序结构。Transformer 的设计者放弃了这种拟人化的思路,转而让机器用矩阵运算直接计算所有位置之间的关系,反而同时解决了长距离依赖和并行计算两个难题。
1.4 为什么必须理解 RNN 的失败
Transformer 的注意力机制不是凭空发明出来的炫技。它是对 RNN 两个结构性缺陷的直接回应:
- RNN 的长距离依赖失效,是因为信息必须逐步传递、逐步压缩。注意力机制的回应是:任意两个位置直接相连,无需中间步骤。
- RNN 的无法并行,是因为时间步之间存在严格的顺序依赖。注意力机制的回应是:所有位置的计算互不依赖,天然可并行。
如果不理解 RNN 为什么在这两个维度上失败,就很难真正理解 Transformer 为什么设计成现在这个样子。注意力、残差连接、层归一化、前馈网络——每一个组件的设计动机,都可以追溯到对某个具体问题的回应。
接下来的章节,我们将不再回顾 RNN,而是沿着数据在模型中流动的真实路径,一个组件一个组件地拆解现代大模型的通用骨架:Decoder-only Transformer。
图1:RNN 串行 vs Transformer 并行对比图

第2章 为什么大模型都长成了"GPT 的样子"?
2017 年 Transformer 论文问世时,作者提出的原始架构是 Encoder-Decoder,用于机器翻译任务。编码端把源语言句子压缩成上下文表示,解码端再把这个表示逐步解码成目标语言。这个设计在翻译任务上表现优异,但它并没有预见到此后几年大模型领域的走向。
从 2018 年到 2026 年,Transformer 架构分化出了三条路线。令人意外的是,最终一统江湖的并不是原版的 Encoder-Decoder,而是看起来最简单的 Decoder-only。今天,无论是 GPT-4、Llama、Qwen、DeepSeek 还是 Kimi,它们共享着同一个底层骨架:Decoder-only。理解这个选择,是理解后续每一层技术决策的前提。
2.1 三条路线的分化
Transformer 发布后的几年里,研究者围绕"如何处理输入序列"和"如何生成输出"这两个问题,探索出了三种不同的架构选择。
Encoder-Decoder(编码器-解码器)
这是 Transformer 论文的原始设计,后来被 T5、BART 等模型继承。它的核心特征是有两个独立的模块:编码器负责双向理解输入序列,解码器负责自左向右生成输出序列。这种架构天然适合输入和输出成对出现的任务,比如机器翻译(中英文对照)、文本摘要(原文→摘要)。但它的局限也很明显:训练需要成对的标注数据,而高质量成对数据的获取成本极高,规模受限。
Encoder-only(仅编码器)
以 BERT(2018)为代表。它去掉了解码器,只保留编码器,并且用双向注意力同时看一个词的左右两边上下文。BERT 的预训练任务是在句子中随机挖掉一些词,让模型根据上下文预测被挖掉的词是什么。这种设计让 BERT 在文本理解任务上表现极强——情感分类、命名实体识别、问答抽取等。但 BERT 本身不会生成文本,它的输出是理解后的表示,必须再接入其他任务层才能使用。
Decoder-only(仅解码器)
以 GPT 系列为代表。它去掉了编码器,只保留解码器,并且用因果掩码强制模型只能从左到右看序列。它的训练目标极其简单:给定前面的词,预测下一个词。这个任务叫做"自回归语言建模"。
2.2 Decoder-only 胜出的三个维度
三条路线各有优劣,但 Decoder-only 在 2020 年之后迅速成为绝对主流。这不是偶然,而是三个维度上的系统性胜利。
维度一:训练数据利用率
Encoder-Decoder 需要成对的输入-输出数据。机器翻译需要中英对照的平行语料,摘要需要原文和人工撰写的摘要对。这类数据的采集、清洗、标注成本极高,天然限制了训练规模的上限。
BERT 虽然可以用任意无标注文本,但它的掩码预测任务(挖掉一些词让模型猜)在训练效率上不如直接预测下一个词直观。模型需要学习"被挖掉的词是什么",这个中间目标与最终的应用目标之间存在差距。
Decoder-only 的"预测下一个词"目标函数意味着:互联网上的任何文本——书籍、网页、论文、代码、对话记录——都可以直接用于训练,无需任何人工标注。一个句子自身就是监督信号:用"我今天去"预测"公园"。数据获取的边际成本接近于零,这决定了 Decoder-only 可以使用的训练数据规模没有理论上限。
维度二:工程实现简洁性
Decoder-only 架构的工程复杂度远低于 Encoder-Decoder。
首先,它只有一个目标函数:交叉熵预测下一个词。Encoder-Decoder 需要同时优化编码端和解码端,两者的梯度相互影响,调参更复杂。
其次,Decoder-only 与 KV Cache 天然兼容。在推理阶段,模型需要反复生成 token,KV Cache 可以避免重复计算历史 token 的 Key 和 Value。这个优化在 Decoder-only 中实现得非常直接,而在 Encoder-Decoder 中则需要分别处理编码端和解码端的缓存策略。
最后,分布式训练时的数据并行策略也更简单。所有参数都在同一个目标函数下更新,不需要像 Encoder-Decoder 那样处理两个模块之间的梯度同步问题。
维度三:Scaling Law 表现
2020 年,OpenAI 发表了 GPT-3 论文《Language Models are Few-Shot Learners》,展示了一个令人震惊的结果:一个 1750 亿参数的 Decoder-only 模型,仅仅通过"预测下一个词"这个任务训练后,不需要针对任何下游任务微调,就能在零样本或少样本设置下完成翻译、问答、算术、代码生成等任务。
同年,Kaplan 等人的论文《Scaling Laws for Neural Language Models》进一步量化了这一规律:Decoder-only 模型的性能随参数规模、训练数据量和计算量的增长呈现出可预测的提升曲线。当规模突破某个阈值后,模型会"涌现"出训练时并未明确教授的新能力。
Decoder-only 架构在规模化后的能力涌现最为明显。这不是说其他架构不能扩展,而是 Decoder-only 在"简单目标 + 海量数据 + 巨大规模"这个组合下的表现最为优异,而且工程上最容易实现。
2.3 一个关键认知:Decoder-only 不是"简化版"
有人可能会认为,Decoder-only 去掉了编码器,是一种"偷工减料"的简化。这种观点是错的。
Decoder-only 的因果掩码(只能看前面,不能看后面)赋予了它一个 Encoder-only 和 Encoder-Decoder 都不具备的核心特性:自回归生成能力。它可以逐 token 地生成无限长的文本,而这种生成能力是通用人工智能最自然的接口形式——对话、写作、编程、推理,本质上都是序列生成。
Encoder-only 模型擅长理解,但不会生成。Encoder-Decoder 模型可以生成,但受限于成对数据。Decoder-only 模型用极简的训练目标(预测下一个词)和极简的架构(单一模块),解锁了最广的应用场景和最大的数据规模。
2.4 小结
从本章开始,本书将 exclusively 聚焦于 Decoder-only 架构。读者日常接触的所有大模型——无论是闭源的 GPT-4、Kimi,还是开源的 Llama、Qwen、DeepSeek——都是这个架构的变体。理解了这个选择之后,我们就可以进入架构内部,沿着数据流动的真实路径,一个组件一个组件地拆解它。
图2:进化时间线图谱

图3:三大家族谱系图

第3章 Decoder-only 架构全景:从输入到输出的五阶段
在拆解任何一个零件之前,先看整机。这一章的目标是给读者一张完整的地图,展示数据从进入模型到生成下一个词的完整旅程。后续的章节将沿着这张地图,一站一站地深入。
3.1 五阶段数据流
一个 Decoder-only 模型的工作流程可以概括为五个阶段。我们用 GPT-3 的参数规模作为贯穿全书的量化基准:seq_len = 2048,d_model = 12288,vocab_size = 50257,num_layers = 96。
阶段一:输入表示
原始输入是一段文本,经过分词器(Tokenizer)后被切分成一系列 token,每个 token 用一个整数 ID 表示。输入张量的形状是 (seq_len,),即 (2048,)——一个包含 2048 个整数的向量。
这个整数序列首先经过 Embedding 层,每个整数 ID 被映射为一个 d_model 维的连续向量。以 GPT-3 为例,每个 token 变成 12288 维的浮点向量,2048 个 token 组成一个 (2048, 12288) 的浮点矩阵。
随后,位置编码被逐元素加到这个矩阵上,给每个位置打上"这是第几个词"的标记。位置编码的输出形状仍然是 (2048, 12288)。
阶段二:多层语义提炼
输入表示完成后,数据进入模型最核心的部分:一个由 num_layers 个相同结构的 Block 堆叠而成的高塔。以 GPT-3 为例,这个高塔有 96 层。
每个 Block 内部包含四个组件(按数据流顺序):
- 掩码多头自注意力(Masked Multi-Head Self-Attention)
- 残差连接与层归一化(Residual Connection & LayerNorm)
- 前馈网络(FFN)
- 残差连接与层归一化(Residual Connection & LayerNorm)
关键的事实是:每个 Block 的输入形状和输出形状完全相同,都是 (2048, 12288)。数据进入时是一个 (2048, 12288) 的张量,经过 96 层 Block 后,出来的仍然是一个 (2048, 12288) 的张量。
这意味着 Block 不是在改变数据的形状,而是在改变数据的语义内容。每一层都在对同一个空间中的向量进行重新编码,逐步注入上下文信息、提炼语义关系。
阶段三:输出生成
96 层 Block 处理完成后,模型得到了一个富含上下文语义的 (2048, 12288) 张量。输出层的任务是把最后一个位置的语义向量——一个 (1, 12288) 的向量——映射回词表空间。
这个映射通过 LM Head 完成。LM Head 本质上是一个形状为 (12288, 50257) 的线性变换,输出一个 (50257,) 的向量,叫做 logits。每个元素对应词表中一个词的"原始得分"。
值得注意的是,LM Head 的权重矩阵通常与输入 Embedding 共享(Weight Tying)。这意味着输出层不增加额外的可学习参数。
阶段四:概率归一化
logits 是未经归一化的原始得分,不能直接解释为概率。Softmax 函数把这个 (50257,) 的 logits 向量转换为一个概率分布:所有元素变为正数,且加和为 1。每个元素代表词表中对应词作为"下一个词"的概率。
阶段五:自回归循环
模型从概率分布中采样出一个 token,把它拼接到已有序列的末尾,然后整个五阶段流程再次运行,生成下一个 token。这个过程持续进行,直到遇到结束标记或达到最大长度限制。
这就是 Decoder-only 模型被称为"自回归"的原因:它一步一步地生成序列,每一步的输出都作为下一步的输入。
图4:五阶段全景数据流图

3.2 参数总量视角:1750 亿参数花在哪了?
GPT-3 的总参数量约为 1750 亿。这个数字听起来抽象,但如果把它拆解到五个阶段的具体组件上,就会变得清晰。理解参数的分布,是理解模型"容量在哪里"的关键。
FFN(前馈网络)——1160 亿,占 66.4%
这是最容易被低估的部分。每一层 Block 内的 FFN 包含两个线性变换:一个把 12288 维扩展到 4*12288 = 49152 维,另一个再压缩回 12288 维。每层 FFN 的参数量约为 12.08 亿。96 层累计约 1160 亿参数,占总参数的三分之二。
自注意力——580 亿,占 33.2%
每一层 Block 内的自注意力包含四个参数矩阵:W_Q、W_K、W_V 和 W_O,每个的形状都是 (12288, 12288)。每层注意力参数量约为 6.04 亿。96 层累计约 580 亿参数。
Embedding + 位置编码——约 6.43 亿,占 0.37%
Embedding 矩阵的形状是 (50257, 12288),参数量约 6.18 亿。GPT-3 采用可学习位置编码,形状是 (2048, 12288),参数量约 0.25 亿。两者合计不到总参数的 0.4%。
LayerNorm——约 474 万,占比不足 0.003%
每个 LayerNorm 只有两个很小的参数向量:缩放系数 γ 和偏移量 β,形状均为 (12288,)。每层 Block 内有 2 个 LayerNorm(注意力前和 FFN 前),96 层加上最终输出前的 1 个,全部 LayerNorm 合计约 474 万参数。数量极小,但没有它,深层网络的训练会立刻发散。
残差连接与因果掩码——0 参数
残差连接只是加法操作,因果掩码只是把一个矩阵的上三角置为负无穷。它们不占用任何参数,但与千亿参数的组件同等重要。
一个反直觉的事实
整个模型三分之二的参数不在注意力层,而在看似"简单"的 FFN 中。注意力负责建立词与词之间的关联(信息路由),FFN 负责在关联建立之后做深度的语义加工(非线性判断)。参数量分配揭示了一个深层事实:"判断说什么内容"比"决定和谁说话"需要更多的参数容量。
3.3 最简骨架视角:理论上只需要两层就可以训练
在深入拆解 96 层 Block 之前,有一个关键认知值得先建立。它能帮助你在后续面对复杂结构时,始终记得每个组件存在的根本目的。
理论上,一个模型只需要 Embedding + LM Head 就可以端到端训练:
- Embedding 把词表上 50257 个离散 token 映射到 12288 维语义空间。
- LM Head 把 12288 维语义向量映射回 50257 个词的概率分布。
- 训练目标仍然是"预测下一个词"。
这相当于一个巨大的"查表系统":看到某个 token,就直接输出下一个 token 的概率。比如看到"猫",模型可能输出"抓"的概率最高;看到"我",模型可能输出"是"的概率最高。
但这个最简系统有一个致命的缺陷:每个 token 都是孤立处理的。模型在预测"抓"的概率时,看不到前面的"猫",也看不到后面的"鼠"。它只能根据单个 token 做出判断,完全丧失了上下文理解能力。
从这个最简骨架出发,Decoder-only 架构中所有中间层的使命可以概括为一句话:让模型在预测下一个词时,能看到并理解前面所有的词。
- 位置编码:告诉模型"每个词在第几个位置"。
- 自注意力:让每个词直接获取前面所有词的语义信息。
- 残差连接:让深层网络的梯度可以传到浅层。
- 层归一化:让数值在深层网络中保持稳定。
- FFN:在获取上下文后,对每个词做深度非线性语义加工。
- 多层堆叠:让信息反复提炼,从词法到句法再到语义和推理。
96 层 Block 不是 96 个不同的东西,而是同一个核心操作——"看上下文并重新编码"——重复执行 96 次。浅层先解决词法层面的问题,中层解决句法,深层解决语义和推理。层数就是模型的"思考深度"。
图5:最简骨架视角示意图

3.4 小结:你即将看到的拆解顺序
本书后续章节的顺序,严格遵循数据在模型中流动的真实路径:
- Embedding(第4章):离散 token → 连续向量
- 位置编码(第5章):给顺序打上标记
- 掩码多头自注意力(第6章):建立词与词的动态关联
- 残差连接与层归一化(第7章):让深层网络可训练
- 前馈网络 FFN(第8章):注入非线性表达能力
- 输出层 LM Head(第9章):从语义向量回到词表概率
所有组件讲完之后,我们再进入训练和推理(第10-11章),然后从多个视角回顾整个架构(第12-15章),最后看看 2020 年以来每个组件的前沿改进(第16章)。
接下来,我们从数据进入模型的第一站开始:Embedding。
第4章 Token Embedding:离散符号到连续向量
神经网络只能处理数字,不能直接理解"猫""狗""开心"这样的文字符号。Embedding 是整个系统的入口,负责把人类语言的离散符号转换为模型能够计算的连续向量。这个转换看似简单,却是所有后续语义操作的前提。
4.1 上帝视角:入口处的维度跃迁
从人类视角看,输入给模型的是一句话。从模型视角看,它收到的是一串整数。分词器(Tokenizer)预先把文本切分成词片段(token),每个片段对应词表中的一个唯一整数 ID。以 GPT-3 为例,词表大小 vocab_size = 50257,所以每个 token 用一个 0 到 50256 之间的整数表示。
输入张量的形状是 (seq_len,),即 (2048,)——一个包含 2048 个整数的向量。这些整数本身没有任何语义:"猫"可能被编码为 12345,"狗"被编码为 67890,这些数字的大小关系与词义完全无关。如果直接把整数输入神经网络,模型会把"12345"和"12346"当成相近的输入,这是荒谬的。
Embedding 层的工作是:为词表中的每一个 token 学习一个独特的向量表示,把它从 1 维的整数 ID 映射到 d_model 维的连续向量空间。以 GPT-3 为例,这个映射把每个 token 从 1 个整数扩展为 12288 个浮点数。2048 个 token 就变成了一个 (2048, 12288) 的浮点矩阵。
这是数据在模型内部的第一次维度跃迁。输入是离散的、符号化的、不可微的;输出是连续的、几何化的、可微的。
4.2 输入、输出与参数
输入:input_ids,形状 (seq_len,),即 (2048,)。每个元素是一个整数 token ID,取值范围 0 到 50256。
输出:embedded,形状 (seq_len, d_model),即 (2048, 12288)。每个 token 变成了一个 12288 维的浮点向量。
参数:W_embedding,形状 (vocab_size, d_model),即 (50257, 12288)。
这个参数矩阵就是 Embedding 层的全部内容。它的每一行对应词表中的一个 token,行号等于 token ID,行内容就是这个 token 的向量表示。当输入是 token ID = 12345 时,Embedding 层做的事情本质上就是矩阵索引:取出 W_embedding 的第 12345 行。
参数量计算:
50257 × 12288 = 617,558,016
约 6.18 亿 参数。在 GPT-3 约 1750 亿的总参数中,Embedding 仅占 0.35%。
这个比例看起来很小,但需要意识到:Embedding 矩阵的参数量是固定的,不随层数增加而变化。无论模型是 12 层还是 96 层,Embedding 始终是 50257 × 12288 = 6.18 亿。
4.3 为什么 Embedding 必须是可学习的
一种朴素的想法是:既然 Embedding 只是查表,为什么不直接固定它?比如用 one-hot 编码——"猫"对应一个只有第 12345 位为 1、其余全为 0 的 50257 维向量。这样不需要任何可学习参数,直接把 one-hot 向量输入下一层不就行了吗?
问题在于 one-hot 向量之间彼此正交,任意两个词的语义相似度都是 0。"皇帝"和"国王"在 one-hot 表示中没有任何关联,"苹果"(水果)和"苹果"(公司)也完全相同。
可学习的 Embedding 让模型有机会从数据中发现语义结构。训练开始时,W_embedding 随机初始化,所有词向量在空间中均匀散布。随着训练进行,模型通过损失函数的反馈自动调整向量几何:
- "皇帝"和"国王"的向量被拉近,因为它们在训练数据中经常出现在相似的上下文中。
- "苹果"(水果)和"香蕉"被拉近,因为它们属于同一语义类别。
- "苹果"(水果)和"苹果"(公司)的向量可能保持分离,因为它们的上下文模式截然不同。
这种从数据中学到的向量几何,是语言模型所有语义理解能力的基础。没有可学习的 Embedding,后续无论堆多少层注意力,模型都无法获得真正的语义表示。
4.4 Weight Tying:输入与输出共享同一张表
在 GPT-3 中,Embedding 层的 W_embedding 矩阵与输出层的 LM Head 共享同一个权重矩阵。这叫做 Weight Tying(权重共享)。
从数学上看,输入 Embedding 做的是把 token ID 映射到语义空间:token_id → 语义向量,形状变化是 (50257,) → (12288,),对应的矩阵形状是 (50257, 12288)。
输出 LM Head 做的是把语义向量映射回词表空间:语义向量 → 词表得分,形状变化是 (12288,) → (50257,),对应的矩阵形状是 (12288, 50257)。
注意到这两个矩阵互为转置。如果强制它们共享同一个矩阵 W,输入时查第 i 行得到语义向量,输出时用同一个 W 做线性变换得到 logits。这样做有两个好处:
第一,节省参数。 如果不共享,LM Head 需要额外增加约 6.18 亿参数(12288 × 50257)。Weight Tying 为 GPT-3 节省了约 6.18 亿参数,占总参数的 0.35%。在大模型时代,0.35% 也是不可忽视的数字。
第二,强制语义空间对齐。 输入端和输出端被约束在同一个向量空间中。这意味着模型学到的语义表示必须同时满足两个条件:既能被前面的层高效处理,又能被最后的输出层高效解码回词表概率。这种双向约束通常会让表示质量更好。
4.5 必要性:没有 Embedding,就没有入口
Embedding 的必要性几乎是自明的:神经网络只能接收浮点数张量作为输入。如果没有 Embedding,模型无法接受离散文本。
但 Embedding 的意义不止于此。它是整个模型语义理解的根基:
- 它决定了模型最初如何"看待"每个词。
- 它把 50257 个孤立的符号组织成一个 12288 维的几何空间。
- 它让语义相似性可以被距离度量(如余弦相似度)捕捉。
- 它为后续所有层——注意力、FFN、输出层——提供了可操作的表示。
如果把整个 Decoder-only 模型比作一座工厂,Embedding 就是工厂的原料处理车间。它本身不做复杂的加工,但没有它,后续的精加工车间连原材料都收不到。
在理解 Embedding 的本质之后,下一个问题是:模型如何知道"第几个词"这个信息?Transformer 不像 RNN 那样按顺序处理,如果不额外注入位置信息,"我爱你"和"你爱我"对它将完全一样。这就是下一章的主题:位置编码。
图6:Embedding 输入输出框图

第5章 位置编码:给顺序打上标记
Embedding 把每个词映射成了向量,但它有一个根本性的遗漏:信息被丢失了。具体地说,Embedding 在处理"猫抓老鼠"中的"猫"和在"老鼠抓猫"中的"猫"时,输出的向量是完全相同的。因为 Embedding 只关心"这个词是什么",不关心"这个词在第几个位置"。
对人类来说,顺序是语义的核心组成部分。"我爱你"和"你爱我"由完全相同的三个字组成,顺序一变,含义截然相反。对 Transformer 来说,如果不额外注入位置信息,这两句话确实没有任何区别——因为自注意力机制本身是完全位置无关的。
位置编码的功能,就是给每个位置的向量打上"这是第几个词"的标记。
5.1 上帝视角:补全 Transformer 的盲点
RNN 天然具有顺序感知能力,因为它按时间步依次处理,第 t 步自动知道自己是第 t 个词。但 Transformer 的所有位置是同时计算的,自注意力机制在计算两个词的关联时,完全不考虑它们之间的距离或先后顺序。
位置编码不是对模型结构的修改,而是对输入数据的补充。它在 Embedding 输出之后,通过一个逐元素相加的操作,把位置信息注入到每个词的向量中。输入和输出形状完全相同:(seq_len, d_model),即 (2048, 12288)。
这个加法操作的直觉是:在 d_model = 12288 维的向量空间中,为每个位置分配一个独特的"位置指纹",把这个指纹加到对应位置的词向量上。模型在处理向量时,就能同时感知到"这个词是什么"和"这个词在第几个位置"。
5.2 三种位置编码方案
自 Transformer 诞生以来,位置编码经历了三代主要方案。
| 方案 | 参数量 | 是否可学习 | 原理 | 优缺点 |
|---|---|---|---|---|
| 正弦/余弦 | 0 | 否 | 不同频率的正弦波,固定公式 | 零参数,泛化好,但不能根据数据调整 |
| 可学习 | (2048, 12288) ≈ 0.25 亿 | 是 | 每个位置学一个向量 | 灵活自适应,但外推能力弱,需额外参数 |
| RoPE | 0 | 否 | 旋转向量,相对位置信息内积自然体现 | 零参数,外推和内插最自然,当前主流 |
理解它们的差异,有助于把握这个位置信息注入问题的本质。
方案一:正弦/余弦位置编码
这是 2017 年原始 Transformer 论文提出的方案。它不为位置编码设置任何可学习参数,而是用一个固定的数学公式直接计算每个位置的编码向量。
公式如下。对于位置 pos 和维度索引 i:
PE(pos, 2i) = sin(pos / 10000^(2i/d_model))
PE(pos, 2i+1) = cos(pos / 10000^(2i/d_model))
其中 d_model = 12288。这个公式的设计有几个巧妙之处:
- 不同维度使用不同频率的正弦波。低维度(i 较小)的波长很长,编码粗略的位置信息;高维度(i 较大)的波长很短,编码精细的位置差异。
- 正弦函数的值域在 [-1, 1] 之间,不会破坏 Embedding 向量的数值尺度。
- 由于正弦和余弦的数学性质,模型可以通过学习来推导相对位置:
PE(pos+k)可以表示为PE(pos)的线性函数。
优点:零参数,不增加模型容量负担;泛化到训练时未见过的序列长度相对容易。
缺点:位置信息以固定模式注入,模型不能根据数据调整编码方式。
方案二:可学习位置编码
这是 GPT-3 采用的方案。它把位置编码当作一个与 Embedding 一样的可学习参数矩阵。
具体来说,模型维护一个形状为 (max_seq_len, d_model) 的参数矩阵。以 GPT-3 为例,最大序列长度 max_seq_len = 2048,d_model = 12288,所以位置编码矩阵的形状是 (2048, 12288)。
参数量:2048 × 12288 = 25,165,824,约 0.25 亿 参数。仅占 GPT-3 总参数的 0.014%。
训练时,这个矩阵随机初始化,与 Embedding 矩阵一样通过反向传播自动调整。模型可以自己决定如何编码位置信息——某些维度可能编码绝对位置,某些维度可能编码相对距离,模型从数据中学习最优的编码策略。
优点:灵活性高,模型可以根据任务和数据自适应地调整位置表示。
缺点:训练时未见过的位置(超出 2048)没有对应的编码向量,外推能力较弱;需要额外的 0.25 亿参数。
方案三:旋转位置编码(RoPE)
RoPE(Rotary Position Embedding)是 2021 年提出的方案,现已成为 Llama、Qwen 等主流模型的标准选择。
RoPE 的核心思想是:不单独维护一个位置编码向量,而是把位置信息直接"旋转"进 Query 和 Key 向量中。具体来说,它用复数旋转矩阵对 Q 和 K 向量进行逐维旋转,旋转角度与位置索引成正比。两个向量做内积时,旋转角度的差值自然体现在结果中——这意味着相对位置信息被直接编码到了注意力分数的计算中。
优点:零参数;相对位置信息内建于注意力机制本身,外推和内插更加自然;与注意力机制无缝融合。
缺点:数学实现比前两种方案复杂。
图7:三种位置编码方案对比图

图8:正弦/余弦位置编码可视化热力图

5.3 参数对比与选择逻辑
| 方案 | 参数量 | 是否可学习 | 相对位置支持 | 当前主流采用 |
|---|---|---|---|---|
| 正弦/余弦 | 0 | 否 | 间接支持 | 原始 Transformer |
| 可学习 | 0.25亿 | 是 | 较弱 | GPT-3 |
| RoPE | 0 | 否 | 原生支持 | Llama、Qwen、DeepSeek |
三种方案的选择取决于模型的设计目标。GPT-3 选择了可学习位置编码,因为当时研究者相信数据驱动的自适应编码会优于固定公式。后来的实践表明,RoPE 在相对位置建模和长上下文外推方面表现更优,因此成为新模型的主流选择。
但无论采用哪种方案,位置编码的本质功能不变:补全 Transformer 对顺序信息的缺失。
5.4 必要性:没有位置编码,模型是顺序盲的
假设完全去掉位置编码,会发生什么?
自注意力机制计算任意两个位置的关联时,只看它们的内容向量,不看它们的位置。这意味着:
- "我爱你"和"你爱我"的注意力分数矩阵完全相同。
- "猫抓老鼠"和"老鼠抓猫"对模型来说没有区别。
- 诗歌的押韵、对联的对仗、代码的缩进结构——所有依赖位置关系的模式都无法被捕捉。
模型将退化为一个"词袋"(Bag of Words)系统:只关心句子里有哪些词,完全无视它们的排列顺序。这显然是不可接受的。
位置编码的必要性因此非常明确:它用极小的代价(0 参数或 0.25 亿参数,占总参数不足 0.014%),修复了 Transformer 架构的一个结构性盲点。
5.5 小结
Embedding 回答了"每个词是什么",位置编码回答了"每个词在第几个位置"。两者相加之后,模型才获得了对输入序列的完整初始表示:(2048, 12288) 的矩阵,其中每一行既携带了语义信息,又携带了位置信息。
这个矩阵随后进入模型的核心加工车间:Decoder Block。在每个 Block 中,数据将经历注意力机制的全局重组、残差连接的梯度保护、层归一化的数值稳定,以及 FFN 的非线性深加工。我们从注意力机制开始——它是 Transformer 最具标志性的组件,也是理解整个架构的关键。
第6章 掩码多头自注意力:建立词与词的动态关联
这是 Transformer 最核心的组件,也是整个架构得名的原因。自注意力的功能是让序列中的每个 token 都能动态地计算与所有其他 token(在因果约束下)的关联强度,并按这个强度聚合信息。多头机制则让不同类型的关系在不同的子空间中独立学习。
理解这一层,就理解了 Transformer 为什么能同时解决长距离依赖和并行计算两个问题。
6.1 为什么需要自注意力——回到 RNN 的失败
第1章说过,RNN 的长距离依赖失效是因为信息必须逐步传递。当 RNN 读到句子末尾时,开头的信息已经经过了多步隐藏状态的压缩和稀释。位置 1000 的信息要到达位置 1,需要经过 999 步接力,每步都伴随噪声和丢失。
自注意力的设计是对这个问题的直接回应:任意两个位置之间的关联不再依赖中间步骤的接力,而是通过一次矩阵乘法直接计算。位置 1 和位置 1000 之间的距离,与位置 1 和位置 2 之间的距离在计算复杂度上没有区别——都是一次矩阵运算。
同时,这一步彻底解决了并行问题。所有位置的 Query、Key、Value 矩阵乘法互不依赖,可以同时在 GPU 上执行。RNN 的顺序依赖被彻底消除。
6.2 自注意力的计算流程
输入与输出
输入:X,形状 (seq_len, d_model),即 (2048, 12288)。这是 Embedding 加位置编码后的结果。
输出:AttentionOut,形状 (seq_len, d_model),即 (2048, 12288)。每个位置的输出向量都聚合了全序列(在因果约束下)的上下文信息。
参数
自注意力层包含四个可学习的参数矩阵:
W_Q、W_K、W_V:形状均为(d_model, d_model),即(12288, 12288)W_O:形状(d_model, d_model),即(12288, 12288)
工程实现上,W_Q、W_K、W_V 各被逻辑切分成 num_heads = 96 个竖条,每个竖条的形状是 (d_model, d_k),其中 d_k = d_model / num_heads = 12288 / 96 = 128。
参数量计算:
每层注意力总参数量 = 4 × d_model × d_model = 4 × 12288 × 12288 = 603,979,776
约 6.04 亿 参数。GPT-3 共 96 层,注意力累计约 580 亿 参数,占总参数 33.2%。
计算过程(严格按数据流)
第1步:生成 Q、K、V
Q = X @ W_Q → 形状 (2048, 12288)
K = X @ W_V → 形状 (2048, 12288)
V = X @ W_V → 形状 (2048, 12288)
同一个输入 X 分别与三个不同的权重矩阵相乘,得到三个不同的表示。这里就引出了 Q/K/V 各自的物理意义(详见本章专栏)。
第2步:切成多头
Q、K、V 各被重塑为 (96, 2048, 128)。逻辑上,这是把 12288 维切成 96 个 128 维的片段,每个片段由一个独立的"头"处理。
第3步:计算注意力分数
对每个头分别计算:
scores = Q_h @ K_h^T / sqrt(d_k) → 形状 (96, 2048, 2048)
Q_h @ K_h^T 得到一个 2048×2048 的矩阵,其中第 i 行第 j 列的元素表示:在第 h 个头中,位置 i 的 Query 与位置 j 的 Key 的相似度。除以 sqrt(d_k) = sqrt(128) 是为了防止内积值过大导致 Softmax 梯度消失。
第4步:加因果掩码
把分数矩阵的上三角(不含对角线)置为负无穷。这样经过 Softmax 后,上三角的值会变成 0——位置 i 只能关注位置 0 到 i(含自己)。这是 Decoder-only 的因果特性核心。
第5步:Softmax 与加权求和
weights = Softmax(scores) → 形状 (96, 2048, 2048)
output_h = weights @ V_h → 形状 (96, 2048, 128)
Softmax 把分数转换为概率分布(每行之和为 1),然后用这个分布对 V_h 做加权求和。每个位置的输出是它前面所有位置(含自己)的 Value 向量的加权平均。
第6步:拼接与输出投影
concat = Concat(output_h for h in 1..96) → 形状 (2048, 12288)
AttentionOut = concat @ W_O → 形状 (2048, 12288)
96 个头的输出拼接回 (2048, 12288),再通过 W_O 做线性变换,得到最终输出。
图9:掩码多头注意力完整计算流程框图

6.3 为什么需要多头——单头的局限
如果只用一个注意力头,W_Q、W_K、W_V 各只有一个 (12288, 12288) 矩阵。语法关系、指代关系、语义相似性、局部搭配等多种不同类型的关系被迫挤在同一个 12288 维的空间中互相干扰。
训练后的观察表明:
- 某些头专门追踪代词与先行词的指代关系。
- 某些头专门处理局部语法结构(如介词短语搭配)。
- 某些头捕捉远距离的语义关联(如主题与评论)。
- 某些头关注相邻位置的局部模式。
数学上的非等价性。有人可能会问:96 个 (12288, 128) 的矩阵拼接起来,不就等于一个 (12288, 12288) 的大矩阵吗?为什么非要切成多头?
关键区别在于 W_O。多头机制中,96 个头的输出拼接后还要经过一个 (12288, 12288) 的 W_O 投影。这个拼接+投影的操作,与直接使用一个 (12288, 12288) 的注意力矩阵在数学上不等价。多头引入了一种强归纳偏置,强制模型在不同的低维子空间中学习不同类型的关系,最后由 W_O 综合各头的发现。
如果没有多头机制,单个大矩阵虽然容量相同,但没有结构性的约束来推动它分化出专门化的子功能。这类似于:给一个团队 96 个任务,让每个人同时做所有任务, versus 把 96 个人分成 96 个小组,每组专注一类任务,最后汇总——后者通常更高效。
图10:多头分解与拼接示意图

图13:单头 vs 多头注意力对比图

6.4 为什么需要因果掩码——防止偷看
训练时,模型的目标是"预测下一个词"。给定序列中的前 i 个词,模型应该预测第 i+1 个词是什么。
如果不加任何限制,自注意力在计算位置 5 的输出时,可以直接看到位置 6、7、8 的真实答案。这意味着模型不需要真正"预测",只需要从未来的词中复制答案即可。这样的模型在训练集上会表现完美,但它从未学会过真正的因果推理。
因果掩码把这个漏洞堵住了。它把注意力分数矩阵的上三角(严格上三角,不含对角线)置为负无穷。经过 Softmax 后,这些位置的概率变为 0。结果是:位置 i 只能关注位置 0 到 i(含自己),绝不能看到位置 i+1 及之后的内容。
这不是推理时的限制,而是训练时的教学设计。它强制模型在每一步都只能基于已有信息推断未知信息。只有在这样的约束下训练出来的模型,才能在推理时具备自回归生成能力:看到一个词,预测下一个;把预测结果拼回去,再预测下下一个——这个过程能够持续进行,正是因为模型在训练时就被要求只做"向前看"的预测。
图12:因果掩码矩阵可视化

【专栏】Q、K、V 的物理意义与手算示例
Q/K/V 的抽象定义经常让读者困惑。这里用一个手算级别的小数字示例,讲清各自的物理意义和计算全流程。
物理意义
- Query(查询):"我现在在这个位置,我想知道什么?"——当前 token 主动发出的询问信号。
- Key(键):"我是什么?如果有人在找我,这就是我的名片。"——每个 token 的被动身份标签。
- Value(值):"我实际携带了什么信息?"——每个 token 的语义内容本身。
注意力机制的本质是:用 Query 去匹配 Key,找到"谁和我相关",然后把相关者的 Value 加权聚合过来。
一个直观的比喻:图书馆。 你想找一本书,于是对管理员说:"我想找一本关于猫的书。"——这句话就是你的 Query(查询)。管理员手边有一排书的索引标签——"狗""猫""鸟"——这些标签就是每本书的 Key(键)。管理员把你的查询和所有标签比对,发现"猫"匹配度最高,于是从书架上取出对应的书递给你——书里的内容就是 Value(值)。
在自注意力中,每个 token 同时扮演三个角色:
- Q:它在当前上下文中"想问的问题"。比如"抓"这个 token 可能会问:"前面是什么名词?"
- K:它的"身份标签",用来回答别人的查询。比如"猫"的 K 表明"我是名词,可以做主语"。
- V:它的"实际语义内容",是真正被搬运和聚合的信息。
Q @ K.T 计算的是"我的问题"和"你的身份"之间的匹配度。Softmax 把匹配度转化为"关注度比例"。比例 @ V 就是"按关注度聚合所有人的实际内容"。
为什么需要三套矩阵,而不是一套?
因为"我想问什么""我是什么身份""我携带什么信息"是三种不同的语义功能。如果只用一套矩阵,模型被迫用同一个向量同时回答三个问题,表达能力受限。W_Q、W_K、W_V 分别是三个独立的学习目标,让模型学会如何提问、如何标识身份、如何表达内容。
手算示例
考虑一个极简场景:3 个 token,4 维向量,2 个头,每头 2 维。
输入:
X = [[1, 0, 0, 0], # token 0:"猫"
[0, 1, 0, 0], # token 1:"抓"
[0, 0, 1, 0]] # token 2:"鼠"
权重矩阵(为手算方便,设为简单形式):
W_Q = I(4×4) # 单位矩阵
W_K = 交换前两维矩阵 # 第一维↔第二维互换
W_V = 2×I(4×4) # 2倍单位矩阵
第1步:计算 Q、K、V
Q = X @ W_Q = X = [[1,0,0,0], [0,1,0,0], [0,0,1,0]]
K = X @ W_K = [[0,1,0,0], [1,0,0,0], [0,0,1,0]]
# "猫"的 Key 变成 [0,1,0,0](和"抓"的原始向量一样)
# "抓"的 Key 变成 [1,0,0,0](和"猫"的原始向量一样)
V = X @ W_V = [[2,0,0,0], [0,2,0,0], [0,0,2,0]]
第2步:切成 2 个头
Q_h1 = [[1,0], [0,1], [0,0]] # 每行取前2维
Q_h2 = [[0,0], [0,0], [1,0]] # 每行取后2维
K_h1 = [[0,1], [1,0], [0,0]]
K_h2 = [[0,0], [0,0], [1,0]]
V_h1 = [[2,0], [0,2], [0,0]]
V_h2 = [[0,0], [0,0], [2,0]]
第3步:头1 计算注意力
scores_h1 = Q_h1 @ K_h1^T / sqrt(2)
Q_h1 @ K_h1^T:
[[1,0] [[0,1,0] [[0, 1, 0]
[0,1] @ [1,0,0] = [1, 0, 0]
[0,0]] [0,0,0]] [0, 0, 0]]
d_k = 2, sqrt(2) ≈ 1.414
scores_h1 = [[0, 0.707, 0],
[0.707, 0, 0],
[0, 0, 0]]
第4步:加因果掩码
把上三角置为 -∞:
scores_h1 = [[0, -∞, -∞],
[0.707, 0, -∞],
[0, 0, 0]]
第5步:Softmax
位置0: Softmax([0, -∞, -∞]) = [1, 0, 0]
位置1: Softmax([0.707, 0, -∞]) = [0.675, 0.325, 0]
位置2: Softmax([0, 0, 0]) = [0.333, 0.333, 0.333]
第6步:加权求 V
output_h1[0] = 1.0×[2,0] + 0×[0,2] + 0×[0,0] = [2, 0]
output_h1[1] = 0.675×[2,0] + 0.325×[0,2] + 0×[0,0] = [1.35, 0.65]
output_h1[2] = 0.333×[2,0] + 0.333×[0,2] + 0.333×[0,0] = [0.67, 0.67]
头2 的计算过程类似。最终两头的输出拼接后过 W_O,得到 (3, 4) 的最终输出。
这个例子虽然极小,但完整展示了从输入到输出的全部流程。关键 takeaway 是:
- Q 决定"我要找什么"。
- K 决定"我是什么,能被谁找到"。
- V 决定"被找到后,我传递什么信息"。
- 因果掩码决定"我只能找谁"。
图11:Q/K/V 手算级小数字示例图

必要性总结
自注意力层为什么必须有?
如果没有自注意力,模型中没有任何机制能让不同位置的 token 交换信息。FFN 对每个位置独立运算,Embedding 和位置编码只是初始表示。没有自注意力,每个 token 将始终孤立地处理,模型退化为一个"每个词单独判断"的系统,完全丧失上下文理解能力。
如果没有多头,所有类型的关系挤在同一个空间中互相干扰,模型难以分化出专门化的关联模式。
如果没有因果掩码,训练时模型可以直接偷看未来信息,永远无法学会真正的自回归生成。
自注意力、多头、因果掩码三者缺一不可,共同构成了 Transformer 核心的信息重组机制。
第7章 残差连接与层归一化:让深层网络可训练
当神经网络的层数从几层增加到几十层甚至上百层时,两个致命问题会浮现:梯度消失和数值不稳定。前者让深层参数几乎无法更新,后者让前向传播的数值指数级爆炸或衰减。残差连接和层归一化是解决这两个问题的标准工程手段。它们不直接参与语义计算,但没有它们,GPT-3 的 96 层深度将完全不可行。
7.1 残差连接:梯度高速公路
上帝视角
深层网络训练困难的根本原因在于梯度传播。反向传播时,损失函数对每一层参数的梯度,都需要从输出层逐层传递回输入层。每一层的梯度计算都涉及链式法则中的连乘,当网络很深时,这些小于 1 的数连乘起来会迅速趋近于零。结果是:靠近输入端的浅层参数获得的梯度信号极其微弱,几乎不更新。这叫做梯度消失。
残差连接的设计极其简洁,但效果深远。它的数学形式是:
output = input + F(input)
其中 F(input) 是当前层的变换(比如注意力层或 FFN 层)。注意这里的 + 是逐元素相加,不是拼接。
这个公式创造了两条并行路径:一条经过当前层的复杂变换 F,另一条是直接抄近路的恒等映射 input。无论 F 有多少层内部运算,输入信号总可以通过那条"近路"直接传到输出端。
反向传播时,这条近路变成了梯度高速公路。损失对输入的梯度可以直接沿着恒等路径传回,不需要经过 F 的内部层层衰减。这意味着即使网络有 96 层,最底层的 Embedding 参数也能接收到来自顶层 Loss 的直接梯度信号。
为什么超过 10 层的网络必须用它
在 ResNet(2015)引入残差连接之前,训练超过 10-20 层的神经网络非常困难。研究者的普遍经验是:层数增加到某个点后,训练损失不再下降,验证性能反而变差。这不是过拟合——训练集上的表现也不好。问题的根源就是梯度消失。
残差连接的发现是深度学习历史上的一个转折点。它让 ResNet 可以训练 152 层甚至 1000 层的卷积网络。Transformer 直接继承了这个设计,并把它从计算机视觉带到了自然语言处理。GPT-3 的 96 层如果没有残差连接,训练根本无法收敛。
图14:残差连接与梯度流动示意图

7.2 层归一化:数值稳定器
上帝视角
即使有了残差连接,深层网络仍然面临另一个问题:数值不稳定。在前向传播中,每一层的输出都会经过矩阵乘法、激活函数等变换。当层数很多时,这些变换的累积效应会导致数值要么指数级爆炸(变成天文数字),要么指数级衰减(变成几乎为零)。无论哪种情况,训练都会发散。
层归一化(LayerNorm)的功能是对每个样本的特征维度做归一化,使得每一层输出的均值接近 0、方差接近 1。它把数值的尺度拉回到一个稳定的范围内,防止深层网络中的数值雪崩。
输入、输出与参数
输入:(seq_len, d_model),即 (2048, 12288)。
输出:(seq_len, d_model),即 (2048, 12288)。形状不变。
参数:每个 LayerNorm 有两个可学习参数:
γ(缩放系数),形状(d_model,),即(12288,)β(偏移量),形状(d_model,),即(12288,)
参数量计算:
每个 LayerNorm 有 2 × d_model = 2 × 12288 = 24576 个参数。
GPT-3 采用 Pre-Norm 结构(在残差分支之前做归一化),每个 Block 内有 2 个 LayerNorm:一个在自注意力之前,一个在 FFN 之前。每层 Block 的 LayerNorm 参数量为 4 × d_model = 4 × 12288 = 49152,约 5 万 参数。
96 层 Block 加上最终输出层前的 1 个 LayerNorm,全部 LayerNorm 合计:
96 × 49152 + 24576 = 4,943,616 + 24,576 = 4,968,192
约 474 万 参数。占总参数 1750 亿的 0.003%。
这个比例小到可以忽略不计,但没有 LayerNorm,训练在几步之内就会发散。
Pre-Norm vs Post-Norm
原始 Transformer 论文采用的是 Post-Norm(在残差分支之后做归一化):
Post-Norm: output = LayerNorm(input + F(input))
GPT-3 及之后几乎所有大模型改用 Pre-Norm(在残差分支之前做归一化):
Pre-Norm: output = input + F(LayerNorm(input))
Pre-Norm 把归一化放在当前层变换之前,使得 F 接收到的输入在训练初期就已经是均值 0、方差 1 的分布。这显著提升了深层网络的训练稳定性。在 Post-Norm 下,随着层数增加到 50 层以上,数值爆炸或衰减的概率急剧上升;Pre-Norm 把这个稳定阈值推到了 100 层以上。
图15:有无残差连接对比图

7.3 必要性:结构约束与容量缺一不可
残差连接和层归一化共同构成了深层 Transformer 训练的结构约束。
如果没有残差连接,96 层的梯度信号会衰减到几乎为零。浅层参数无法更新,模型退化为"只有顶层在工作"的浅层网络。
如果没有层归一化,前向传播的数值会在几层之内就溢出浮点数表示范围或衰减到机器精度以下。无论参数量多大,训练都无法进行。
值得强调的是,残差连接和层归一化是工程手段,不是"让模型更聪明"的组件,而是"让模型能活着训练完"的组件。它们没有创造新的表达能力,但解除了深度对可训练性的诅咒。它们占用的参数几乎为零(残差连接是加法,0 参数;LayerNorm 仅占 0.003%),但与 FFN 的 1160 亿参数、注意力的 580 亿参数同等重要。模型的可行性等于结构约束与容量的乘积:
可行性 = 结构约束(残差、归一化、掩码) × 容量(FFN、注意力)
去掉结构约束,容量再大连训练都无法完成。这就是为什么在后续的多视角回顾中,我们会反复看到:零参数组件的价值绝不亚于千亿参数组件。
7.4 小结
残差连接和层归一化不直接参与语义内容的计算,但它们为语义计算提供了物理上可行的环境。残差连接确保梯度能从第 96 层直达第 1 层,层归一化确保数值在 96 次变换后仍然稳定。
在自注意力完成上下文重组之后,每个位置的向量已经聚合了前面的语义信息。接下来,这些信息需要被深度加工——每个 token 要在自己的语义空间中做出复杂的非线性判断。这就是下一章的主题:前馈网络(FFN)。
第8章 前馈网络(FFN):注入非线性表达能力
自注意力的本质是对 Value 向量的线性加权求和。无论权重多复杂,这个操作仍然是线性的:输出是输入的线性组合。如果整个模型只有自注意力、残差连接和层归一化,无论堆叠多少层,最终都等价于一个大型线性变换。FFN 的存在,打破了这种线性,让整个模型拥有了逼近复杂非线性函数的能力。
8.1 上帝视角:为什么注意力不够
注意力机制解决了"信息从哪来"的问题——它让每个 token 知道应该关注谁。但它没有解决"来了之后怎么处理"的问题。假设注意力把"猫"的相关信息传递给了"抓","抓"的向量现在包含了上下文信息,但这个向量仍然是输入向量的线性组合。如果没有非线性变换,模型只能做线性分类和线性回归,无法表达复杂的判断逻辑。
FFN 在每个位置独立施加非线性变换,把"聚合了上下文信息的向量"送入一个高维空间进行深度加工,再压缩回原始维度。这个"扩张-加工-收缩"的过程是整个模型表达能力的主要来源。
8.2 输入、输出与结构
输入:(seq_len, d_model),即 (2048, 12288)。这是经过自注意力和残差&归一化后的输出。
输出:(seq_len, d_model),即 (2048, 12288)。形状不变。
结构:两个线性变换夹一个非线性激活函数:
FFN(x) = W_2 @ Activation(W_1 @ x)
具体维度变化:
(2048, 12288) --W_1--> (2048, 4*12288) --GELU--> (2048, 4*12288) --W_2--> (2048, 12288)
W_1:形状(d_model, 4*d_model),即(12288, 49152)W_2:形状(4*d_model, d_model),即(49152, 12288)
注意到中间维度被扩展到了 4*12288 = 49152,是输入维度的 4 倍。这是原始 Transformer 论文确定的标准比例,后续几乎被所有大模型沿用。
为什么是 4 倍扩展?
这个比例不是随意定的。扩展维度为 FFN 提供了更大的"加工空间"——在更高维的空间中,模型可以学习更复杂的特征组合。4 倍是在表达能力与参数量之间的权衡点:更低(如 2 倍)会显著损失能力,更高(如 8 倍)参数量爆炸而边际收益递减。
图16:FFN 结构框图

8.3 参数
W_1 参数量:d_model × 4*d_model = 12288 × 49152 = 603,979,776,约 6.04 亿。
W_2 参数量:4*d_model × d_model = 49152 × 12288 = 603,979,776,约 6.04 亿。
每层 FFN 总参数量:8 × d_model² = 8 × 12288 × 12288 = 1,207,959,552,约 12.08 亿。
GPT-3 共 96 层,FFN 累计参数量:
96 × 12.08亿 = 1160亿
占总参数 1750 亿的 66.4%。FFN 是整个模型参数量最大的组件。
8.4 GELU:为什么必须有一个非线性激活函数
FFN 中的激活函数(GPT-3 使用 GELU,后续模型多用 SwiGLU)是打破线性的关键。如果没有它,FFN 将变成两个线性变换的串联:
W_2 @ (W_1 @ x) = (W_2 @ W_1) @ x = W_combined @ x
两个线性矩阵的乘积仍然是一个线性矩阵。这意味着无论 W_1 和 W_2 怎么设计,FFN 的整体效果等同于一个 (12288, 12288) 的线性变换——与注意力层的线性本质没有区别。整个模型仍然是纯线性的。
纯线性模型的问题在于:无论多少层,它只能学习线性分类边界,无法逼近任何非线性函数。而语言中的语义判断——比如根据上下文判断一个词是名词还是动词、是褒义还是贬义、是字面意思还是隐喻——本质上都是高度非线性的决策。
GELU(Gaussian Error Linear Unit)的定义是:
GELU(x) = x × Φ(x)
其中 Φ(x) 是标准正态分布的累积分布函数。GELU 的行为介于 ReLU(硬截断)和线性函数之间:对于大的正数它几乎保持原值,对于负数它平滑地衰减到接近零,在零附近有一个平滑的过渡区。
这个平滑的非线性"褶皱"把向量空间"揉皱"了——原本平坦的线性空间被扭曲成复杂的形状,使得 FFN 无法被简化为单层矩阵乘法。这个"揉皱"的能力,就是模型能逼近任意复杂函数的数学根源。
8.5 FFN 与注意力的分工
把注意力和 FFN 放在一起看,它们构成了一个完整的信息处理节拍:
注意力:负责"横向"信息传播。它让序列中不同位置的 token 交换信息,建立全局关联。注意力的输出是每个位置聚合了上下文后的表示。
FFN:负责"纵向"深度加工。它对每个位置独立运算,在聚合了上下文信息的基础上,做复杂的非线性语义判断。FFN 的输出是经过了深度语义加工后的表示。
二者交替进行:注意力先广播信息,FFN 再深化理解;下一层注意力在新的理解基础上重新广播,FFN 再进一步加工。96 层 Block 就是 96 个这样的"广播-加工"节拍。
8.6 必要性:没有 FFN,模型退化为纯线性系统
如果没有 FFN,整个 Decoder-only 模型将变成什么?
- Embedding:线性映射(查表)
- 自注意力:线性加权求和
- 残差连接:加法(线性)
- 层归一化:缩放和平移(线性)
所有操作都是线性的。多层线性操作的复合仍然是线性的。无论堆多少层,整个模型等价于一个单一的线性变换:
output = W_big @ input
这样的模型只能做最简单的线性分类,无法表达语言中复杂的非线性模式。
FFN 的存在打破了这种线性。通过 4*12288 维的中间扩张和 GELU 非线性激活,FFN 让每个 token 在获取上下文后,能够进行深度、复杂的语义判断。这是模型拥有强大表达能力的根本原因。
8.7 小结
FFN 占据了 GPT-3 三分之二的参数(1160 亿),但它的作用常常被忽视。人们更关注" glamorous "的注意力机制,而忽略了默默承担大部分"脑力劳动"的 FFN。
注意力回答"和谁有关",FFN 回答"这意味着什么"。前者是信息路由,后者是语义判断。1160 亿 vs 580 亿的参数分配告诉我们:在大型语言模型中,基于上下文的深度判断,比建立词间关联本身,需要多得多的参数容量。
FFN 处理完成后,每个位置的向量已经完成了在本层 Block 内的全部语义加工。接下来,这些向量要么进入下一层 Block 继续提炼,要么——如果这是最后一层——被送往输出层,映射回词表概率。下一章我们讲输出层。
第9章 输出层(LM Head):从语义向量回到词表概率
96 层 Block 处理完成后,模型手里是一个 (2048, 12288) 的语义表示张量。这个张量中的每一行都承载了对应位置 token 在完整上下文中的深层语义。但模型最终需要回答的问题仍然是:给定前面的所有词,下一个词应该是什么?
输出层的任务,就是把最后一个位置的语义向量映射回词表上每个词的"得分",再把这些得分变成一个合法的概率分布。
9.1 上帝视角:从连续空间回到离散选择
整个 Decoder-only 模型的内部运算都在一个连续的、高维的向量空间中进行。Embedding 把离散的 token 带进了这个空间,后续的 96 层 Block 在这个空间里反复重组和加工语义信息。输出层则是这个空间的"出口"——它必须把连续的语义向量重新映射回离散的、可解释的选择:词表中的 50257 个词,哪一个应该作为下一个词?
这个映射分为两步:先通过线性变换得到原始得分(logits),再通过 Softmax 把得分转换为概率。
9.2 输入、输出与参数
输入:(seq_len, d_model),即 (2048, 12288)。这是最后一个 Decoder Block 的输出。
在实际生成时,模型只关心最后一个位置——因为它要预测的是"下一个"词。所以实际参与计算的是最后一行的向量:(1, 12288)。
输出:(vocab_size,),即 (50257,) 的概率分布。每个元素是词表中对应词作为下一个词的概率,所有元素之和为 1。
参数:W_lm,形状 (d_model, vocab_size),即 (12288, 50257)。
如果不使用 Weight Tying,这个矩阵的参数量为:
12288 × 50257 = 617,558,016
约 6.18 亿 参数,与 Embedding 矩阵的参数量完全相同。
但在 GPT-3 中,LM Head 与输入 Embedding 共享权重(Weight Tying)。W_lm 就是 W_embedding 的转置。因此输出层不增加任何额外的可学习参数。
9.3 计算过程
第1步:线性投影得到 logits
logits = last_hidden @ W_lm → 形状 (50257,)
last_hidden 是最后一个位置的语义向量,形状 (1, 12288)。W_lm 的形状是 (12288, 50257)。矩阵乘法的结果是一个 (50257,) 的向量,每个元素对应词表中一个词的非归一化得分。
这个得分可以是正数、负数或零。得分越高,表示模型认为这个词越适合作为下一个词。
第2步:Softmax 转换为概率
probs = Softmax(logits) → 形状 (50257,)
Softmax 的定义是:
probs[i] = exp(logits[i]) / sum(exp(logits[j]) for j in 0..50256)
Softmax 做三件事:
- 用指数函数把所有 logits 变成正数。
- 把所有正数归一化,使它们之和为 1。
- 保持相对大小关系:logits 中得分高的词,在概率分布中的概率也高。
第3步:采样
从 (50257,) 的概率分布中采样一个 token。最简单的策略是贪婪采样:直接选择概率最高的词。更常用的策略是温度采样或 top-p 采样:在概率最高的若干个词中按概率加权随机选择,以增加生成文本的多样性。
9.4 为什么使用 Softmax 而不是 argmax
一个自然的问题是:既然我们最终只想选概率最高的那个词,为什么不直接取 logits 的最大值(argmax),而要先经过 Softmax?
答案在训练阶段。
argmax 操作是不可导的。它的输出是一个离散的类别索引(比如"第 12345 号词"),这个输出对输入 logits 的梯度几乎处处为零。在反向传播中,argmax 就像一个断路器,梯度无法通过它传递回去。
Softmax 是光滑可导的。它的输出是连续的概率分布,输入 logits 的微小变化会导致输出概率的微小变化。这让 Softmax 可以参与梯度反向传播,告诉模型"正确答案的概率应该提高,错误答案的概率应该降低"。
此外,Softmax 与交叉熵损失函数配合时,梯度形式极其简洁(详见第10章)。这种数学上的简洁性大大提升了训练效率和数值稳定性。
在推理阶段,理论上可以直接对 logits 做 argmax。但由于训练时使用的是 Softmax + 交叉熵,模型已经学会了在 logits 空间中产生适合 Softmax 的得分分布。保持这个流程的一致性是最稳妥的做法。
9.5 Weight Tying 的深层意义
输出层与输入层共享同一个权重矩阵,这在数学上意味着什么?
Embedding 的操作是:token_id → 语义向量。LM Head 的操作是:语义向量 → 词表得分。这两个操作互为逆方向。
当它们共享同一个矩阵 W(互为转置)时,模型被强制要求:输入端学到的语义表示,必须同时满足输出端的解码需求。语义向量不能只被前面的层"看懂",还必须能被最后的输出层高效地翻译回词表概率。
这种双向约束通常会产生更高质量的语义表示。如果 Embedding 和 LM Head 使用独立的矩阵,输入端可能学到一些对输出端"不友好"的表示——这些表示对中间层有用,但输出层难以把它们映射回正确的词。Weight Tying 杜绝了这种可能性。
9.6 必要性:从语义到选择的唯一桥梁
如果没有输出层,96 层 Block 加工出来的 (2048, 12288) 语义张量再精致,也无法被解释为"下一个词应该是什么"。
输出层是整个模型与外部世界交互的接口。训练时,它把内部语义转换为概率分布,让交叉熵损失可以衡量预测的好坏。推理时,它把概率分布交给采样策略,生成具体的 token。
从数据流的角度看,输出层完成了最后一次形状剧变:从 (1, 12288) 的连续语义向量,到 (50257,) 的离散概率分布。这是模型内部连续空间与外部离散语言之间的最后一道桥梁。
图17:输出层框图

9.7 小结
到这一章为止,我们已经沿着 数据在模型中流动的真实路径,完整走完了 Decoder-only 的所有组件:
- Embedding:把离散 token 映射为连续向量。
- 位置编码:给每个位置打上顺序标记。
- 掩码多头自注意力:建立词与词的动态关联,聚合上下文信息。
- 残差连接与层归一化:让深层网络可训练、数值稳定。
- FFN:在聚合上下文后做深度非线性语义加工。
- 输出层:把语义向量映射回词表概率。
每个组件的输入、输出、参数和必要性都已经讲清楚。但知道零件是什么还不够——我们还需要知道整个机器如何运转。接下来两章将分别回答:训练时所有参数如何更新(第10章),推理时数据如何流动(第11章)。
第10章 训练:端到端的参数学习
到第9章为止,我们已经知道了模型在推理时如何工作:输入一段文本,经过 96 层 Block,输出下一个词的概率分布。但模型并非天生就知道这些参数应该是什么。训练阶段的目标,就是让模型通过海量的文本数据,自动学会预测下一个词的能力。
训练的核心思想极其简单:给模型看一段文本的前半部分,让它预测下一个词;如果预测错了,就调整参数让它下次预测得更准。重复这个过程数万亿次,参数就会收敛到能较好预测下一个词的状态。
10.1 数据流:错位一位的自监督
Decoder-only 的训练不需要人工标注。它利用文本自身的结构作为监督信号,这叫做自监督学习。
具体做法如下。假设训练数据中有这样一个句子:
"我今天去了公园"
分词后得到 token 序列:
["我", "今天", "去", "了", "公园", "<end>"]
训练时,模型接收输入序列:
input_ids = ["我", "今天", "去", "了", "公园"]
而目标序列是输入序列错位一位的版本:
labels = ["今天", "去", "了", "公园", "<end>"]
也就是说,位置 0 的目标是位置 1 的真实词,位置 1 的目标是位置 2 的真实词,以此类推。模型在每个位置都需要预测"下一个词是什么"。
以 GPT-3 为例,一个训练样本的 seq_len = 2048。模型一次性接收 2048 个 token 作为输入,同时有 2048 个错位一位的 token 作为目标。前向传播一次,模型输出 2048 组 logits,每组形状 (50257,)。
这 2048 个位置中,前面的位置目标较短(比如位置 0 只需预测 1 个词),后面的位置目标较长(比如位置 2047 需要预测 2048 个词的历史上下文)。但所有位置都在同一次前向传播中并行计算,这是注意力机制的并行性带来的训练效率优势。
图18:训练数据流框图

10.2 损失函数:交叉熵
模型输出的是概率分布,目标是离散的类别(正确词的索引)。衡量"预测的概率分布与真实答案之间的差距"的标准工具是交叉熵损失(Cross-Entropy Loss)。
对于单个位置,交叉熵损失定义为:
loss_i = -log(probs[正确答案])
其中 probs 是 Softmax 后的概率分布,正确答案 是目标 token 的索引。如果模型给正确答案分配的概率接近 1,损失接近 0;如果模型给正确答案分配的概率很低,损失会变得很大。
总损失是所有位置的平均:
Loss = mean(loss_0, loss_1, ..., loss_2047)
为什么交叉熵是合适的
交叉熵损失有一个对训练极其友好的性质:当它与 Softmax 配合时,对 logits 的梯度形式极其简洁。
具体地,设 logits 是输出层的原始得分向量(形状 (50257,)),probs = Softmax(logits)。则损失对 logits 的梯度为:
∂Loss/∂logits = probs - one_hot(正确答案)
这个公式非常直观:probs 是模型当前预测的概率分布,one_hot(正确答案) 是一个只在正确答案位置为 1、其余为 0 的向量。它们的差告诉模型:
- 正确答案位置:概率应该提高(梯度为负,参数向增加概率方向更新)。
- 错误答案位置:概率应该降低(梯度为正,参数向降低概率方向更新)。
这个梯度形式没有复杂的二次项或指数运算,计算高效且数值稳定。它是大规模语言模型训练可行的重要数学基础之一。
图19:Softmax + 交叉熵梯度示意图

10.3 反向传播:1750 亿参数同时更新
前向传播完成后,损失值从输出层反向传播,经过所有 96 个 Decoder Block,一直传回 Embedding 层。在这个过程中,每一个带有可学习参数的组件都会计算出自己的梯度。
以 GPT-3 为例,总参数量约 1750 亿。这些参数在每次反向传播中全部获得梯度,并通过优化器(通常是 Adam 的变体)同时更新。这个过程的参数量级是惊人的:
- FFN 贡献 1160 亿参数的梯度,计算量最大。
- 自注意力贡献 580 亿参数的梯度。
- Embedding、位置编码、LayerNorm 合计不足 7 亿参数的梯度。
优化器的状态。Adam 优化器为每个参数维护两个额外的状态变量:一阶动量(梯度的指数移动平均)和二阶动量(梯度平方的指数移动平均)。这意味着在训练过程中,GPU 显存中不仅需要存储 1750 亿的参数,还需要存储 1750 亿的一阶动量和 1750 亿的二阶动量——总显存占用是参数量的 3 倍左右。
学习率调度。训练初期使用较小的学习率预热(warmup),逐步增加到峰值,然后在训练后期逐渐衰减。这种调度策略帮助模型在训练初期稳定收敛,在后期精细调整参数。
10.4 并行训练的效率
Decoder-only 的训练效率远高于 RNN,核心原因在于注意力的并行性。
在 RNN 中,即使采用 teacher forcing(把真实目标作为下一步的输入),序列内部的 2048 个位置仍然必须串行计算。RNN 处理一个 2048 长度的序列需要 2048 个串行时间步。
在 Transformer 中,2048 个位置的前向传播是一次性完成的。注意力机制的 Q @ K^T 矩阵乘法天然可并行——2048×2048 的注意力分数矩阵在一个 CUDA kernel 中就能计算完毕。FFN 对每个位置独立运算,同样可以完全并行。
这种并行性使得 Transformer 可以在现代 GPU 上以极高的吞吐量处理训练 数据。GPT-3 的训练使用了数千块 V100 GPU,在数十天内完成了对数千亿 token 的训练。如果用 RNN,同样的训练量可能需要数月甚至更久。
10.5 小结
训练阶段可以概括为一句话:所有可学习参数在同一个反向传播过程中一并更新,目标只有一个——让模型预测下一个词的能力尽可能准确。
- 数据组织:输入与目标错位一位,自监督无需人工标注。
- 损失函数:交叉熵,简洁的梯度形式推动参数向正确答案靠拢。
- 反向传播:从输出层到 Embedding 层,1750 亿参数同时获得梯度。
- 并行性:2048 个位置一次性前向传播,训练效率远超 RNN。
训练完成后,模型的参数固定下来。接下来,我们看看这些固定参数如何在推理时驱动自回归生成——以及 KV Cache 为什么是解决推理效率的关键。
第11章 推理:自回归生成与 KV Cache
训练完成后,模型的所有参数被固定下来,不再更新。但推理时的运行方式与训练截然不同。理解这种差异,以及 KV Cache 这个关键工程优化,是理解大模型实际部署的核心。
11.1 推理与训练的本质差异
训练时,模型一次接收 2048 个 token,一次性并行输出 2048 组预测,计算 2048 个位置的损失,反向传播更新所有参数。
推理时,模型没有目标序列可以参考,必须一步一步地生成。生成过程是自回归的:每生成一个新 token,就把它拼接到已有序列的末尾,然后继续生成下一个。这个循环直到遇到结束标记或达到最大长度限制。
这种差异导致了推理时的两个关键特征:
- 无法并行生成:第 t+1 个 token 必须在第 t 个 token 生成之后才能计算,因为第 t+1 个 token 的输入依赖于第 t 个 token 的输出。
- 重复计算的历史:在生成第 t+1 个 token 时,模型仍然需要计算第 1 到第 t 个 token 的注意力——因为它们都是第 t+1 个 token 的"前文"。如果不做优化,每个新 token 的生成都需要重新计算所有历史 token 的 Key 和 Value,造成巨大的计算浪费。
11.2 两个阶段:Prefill 与 Decoding
推理过程分为两个截然不同的阶段。
Prefill 阶段(并行处理 Prompt)
当用户输入一段 prompt(比如"请解释量子力学",假设分词后为 10 个 token)时,这 10 个 token 被一次性送入模型,并行处理。这个阶段的计算模式与训练时的前向传播几乎相同:所有位置同时计算 Q、K、V,生成注意力分数,经过 FFN,输出 logits。
Prefill 阶段完成后,模型产出了第一个新 token(比如"量子")。同时,这一阶段计算出的所有历史 token 的 Key 和 Value 被保存下来,存入缓存。
Decoding 阶段(逐个生成新 Token)
从第二个新 token 开始,进入 Decoding 阶段。每次只输入 1 个新 token(上一步生成的结果)。
对于这个新 token:
- 计算它的 Query(Q)。
- 它的 Key(K)和 Value(V)计算出来后,追加进缓存。
- 用这个新 token 的 Q 查询缓存中所有历史 K,计算注意力分数。
- 用注意力权重对缓存中所有历史 V 做加权求和。
- 经过 FFN,输出 logits,采样得到下一个 token。
关键点:历史 token 的 K 和 V 永不重新计算,直接从缓存读取。
为什么只缓存 K 和 V,不缓存 Q? Q 只代表"当前 token 在问什么问题"——每个新生成的 token 要问的问题都不同,缓存了也没有意义。而 K 和 V 代表"历史 token 能提供什么信息",这部分一旦计算出来就固定不变,所以值得存起来复用。
图20:KV Cache 工作原理图

11.3 KV Cache:推理效率的生命线
KV Cache 的核心思想是:在 Decoding 阶段,每个新 token 的注意力计算只涉及两个新向量(当前 token 的 Q、K、V)和大量历史向量(缓存中的 K、V)。既然历史 token 的 K 和 V 不会变,为什么不把它们存起来,下次直接读?
KV Cache 的显存占用
KV Cache 需要存储每一层、每个历史位置的 K 和 V 向量。以 GPT-3 为例:
num_layers= 96 层- 每层存储 2 个矩阵:K 和 V
- 每个矩阵的形状:
(seq_len, d_model),即(当前长度, 12288) - 数据精度:推理通常用 FP16(2 字节/元素)
每 token 的 KV Cache 占用:
2(K+V) × 96(层) × 12288(d_model) × 2(FP16字节) = 4,718,592 字节
约 4.5 MB。
当上下文长度为 2048 时:
4.5 MB × 2048 = 约 9.0 GB
当上下文长度为 100,000 时:
4.5 MB × 100,000 = 约 450 GB
瓶颈在显存,不在算力
100k 上下文需要 450 GB 的 KV Cache,这已经超出了单块 GPU 的显存容量(目前主流 GPU 显存为 40-80 GB)。处理长上下文时,KV Cache 的存储和访问成为主要瓶颈,而非计算量本身。
注意力的计算复杂度随序列长度呈平方增长(O(seq_len²)),但 Decoding 阶段每次只处理 1 个新 token,所以实际计算量是 O(seq_len)。相比之下,KV Cache 的显存占用是 O(seq_len),但系数很大(每 token 4.5 MB)。因此,当上下文很长时,显存容量和带宽成为限制因素,而不是算力。
这也解释了为什么 2023 年以来大模型领域如此多的研究工作集中在 KV Cache 的压缩上——MQA、GQA、MLA 等改进的核心目标都是减少 KV Cache 的显存占用(详见第16章)。
11.4 两个阶段的数据量变化
在 Prefill 阶段,FFN 需要处理全部 prompt 长度(比如 1000 个 token)的并行计算,计算量较大。进入 Decoding 阶段后,FFN 每次都只处理 1 个 token,计算量骤减为 O(1)。
但注意力的 K/V 缓存长度从 prompt 长度逐渐增长到总长度。生成第 1001 个 token 时,注意力需要查询 1000 个历史 K;生成第 10000 个 token 时,需要查询 9999 个历史 K。这就是为什么长文本生成的速度会随着长度增加而变慢——不是因为 FFN 变重了,而是因为注意力需要处理越来越长的 KV Cache。
11.5 小结
推理阶段的 Decoder-only 模型是一个自回归生成器:
- Prefill:用户 prompt 一次性并行处理,产出第一个新 token,同时初始化 KV Cache。
- Decoding:每次只输入 1 个新 token,历史 K/V 从 Cache 读取,永不重新计算。
- KV Cache 瓶颈:每 token 约 4.5 MB(GPT-3),100k 上下文约 450 GB。长上下文推理的瓶颈在显存,不在算力。
理解训练和推理的差异,是理解大模型工程部署的关键。训练追求高吞吐量(一次处理尽可能多的 token),推理追求低延迟(尽快生成下一个 token)。这两个目标对硬件和软件优化的要求截然不同。
到这一章为止,我们已经完整讲清了模型的所有组件(第4-9章)、训练过程(第10章)和推理过程(第11章)。但知道零件是什么还不够——我们还需要知道整个机器如何运转。接下来,我们将从四个不同视角重新审视整个架构,建立更立体的认知框架。
第12章 参数视角:1750 亿参数都花在哪了?
到第11章为止,我们已经逐个认识了模型的所有组件。但把这些组件拼在一起后,一个更宏观的问题浮现出来:GPT-3 的 1750 亿参数,在各个组件之间是如何分配的?这种分配揭示了什么深层规律?
12.1 参数全景
下表列出 GPT-3 各组件的参数量及占比:
| 组件 | 每层参数量 | 总参数量 | 占总参数比例 |
|---|---|---|---|
| FFN(前馈网络) | 12.08 亿 | 1160 亿 | 66.4% |
| 自注意力 | 6.04 亿 | 580 亿 | 33.2% |
| Embedding | 6.18 亿 | 6.18 亿 | 0.35% |
| 位置编码(可学习) | 0.25 亿 | 0.25 亿 | 0.014% |
| LayerNorm | 约 5 万 | 474 万 | ~0.003% |
| 残差连接 | 0 | 0 | 0% |
| 因果掩码 | 0 | 0 | 0% |
| 总计 | — | ~1750 亿 | 100% |
三个数字值得特别关注:
- FFN 独占 66.4%,是注意力的两倍。
- Embedding 仅占 0.35%,却承担了所有输入和输出的语义映射。
- 残差连接和因果掩码占 0 参数,但没有它们,训练完全不可能。
12.2 为什么 FFN 占了三分之二?
从数学公式看,FFN 的参数量天然大于注意力。每层 FFN 的参数量是 8 × d_model²,而每层注意力是 4 × d_model²。FFN 的参数量是注意力的整整两倍。
但这个数学事实背后有更深层的解释。注意力和 FFN 在模型中承担的是两种截然不同的功能:
注意力 = 信息路由。它的工作是"找谁说话"——确定当前 token 应该关注哪些其他 token,按什么强度聚合它们的信息。注意力的输出是当前 token 的"上下文增强版"表示。
FFN = 语义判断。它的工作是"说什么内容"——在获取了上下文信息之后,对每个 token 独立做复杂的非线性语义加工。FFN 的输出是经过了深度理解和判断后的表示。
"判断"比"路由"需要更多的参数容量。确定"猫抓老鼠"中"抓"的语义(是物理动作还是抽象概念),需要基于上下文做复杂的非线性推理;而确定"抓"应该关注"猫"和"老鼠",相对来说是更直接的相似度计算。
参数量分配揭示了一个深层事实:模型的大部分"脑力"花在基于上下文做复杂决策上,而不是花在建立词间关联上。
12.3 零参数组件的隐性价值
残差连接和因果掩码不占用任何参数,但它们与千亿参数组件同等重要。这个观点值得反复强调。
模型的可行性公式可以写成:
可行性 = 结构约束 × 容量
其中:
- 结构约束 = 残差连接 + 层归一化 + 因果掩码
- 容量 = FFN + 自注意力 + Embedding
结构约束为零时,无论容量多大,可行性都是零。没有残差连接,96 层的梯度消失会让训练在第一轮就崩溃。没有层归一化,数值会在几层之内溢出。没有因果掩码,模型永远学不会自回归生成。
这就像建造摩天大楼:钢筋水泥(容量)再贵,如果没有地基和承重结构(约束),楼盖不起来。在 Transformer 中,"地基"的成本几乎为零,但没有它,上面的"大楼"无从谈起。
12.4 参数占比的启示
66.4% 的参数集中在 FFN,33.2% 在注意力,0.37% 在输入表示。这不是设计者的浪费,而是揭示了模型能力的分配逻辑:
- 理解上下文相对"便宜"(33.2%)。注意力机制通过矩阵乘法高效地建立了全局关联。
- 基于理解做判断相对"昂贵"(66.4%)。FFN 的高维非线性加工是模型"智力"的主要来源。
- 把离散符号接入连续空间几乎"免费"(0.37%)。Embedding 只占总参数的很小一部分,但它是整个系统的入口。
这个分配比例对模型压缩和优化有重要指导意义。如果要在不显著损失能力的前提下压缩模型,FFN 是首选目标——因为它参数最多,且研究表明 FFN 中存在大量冗余(第16章将讨论 MoE 等基于这一观察的改进)。
图21:组件必要性对照表

12.5 小结
参数视角回答的问题是:模型的"容量"在哪里?
答案是:三分之二的容量在 FFN,三分之一在注意力,几乎可以忽略的部分在 Embedding 和归一化。零参数的残差连接和掩码虽然没有容量,但它们决定了整个系统是否可训练。
这个视角帮助我们从"工程师分配资源"的角度理解架构设计。下一章,我们将换一个角度:不再问"参数在哪",而是问"数据进入模型后经历了什么"——从数据流的视角重新审视整个系统。
第13章 数据流视角:数据在系统中的三次变形
参数视角回答"容量在哪"。数据流视角回答另一个问题:数据进入模型后,到底经历了什么?它的形状如何变化?内容如何变化?这个视角关注的是"数据的旅程"。
13.1 第一阶段:输入表示(离散 → 连续)
数据旅程的起点是一段原始文本。经过分词器后,文本变成一串整数:
("我今天去了公园") → [2345, 8912, 456, 7890, 1234]
这些整数是离散的、符号化的、不可微的。Embedding 层把它们映射为连续向量:
(2048,) → (2048, 12288)
这是 数据在模型内部的第一次维度跃迁。输入从 1 维的整数序列膨胀为 12288 维的浮点矩阵。每个整数从"一个符号"变成了高维空间中的一个点。
位置编码随后加入,但形状不变。第一阶段结束时,数据是一个 (2048, 12288) 的浮点矩阵,每一行既携带语义信息,又携带位置信息。
13.2 第二阶段:上下文重组(形状不变,语义剧变)
第二阶段是 数据在 96 个 Decoder Block 中的旅程。这是最容易让读者困惑的阶段,因为输入输出形状完全一致:
(2048, 12288) → Block 1 → (2048, 12288)
(2048, 12288) → Block 2 → (2048, 12288)
...
(2048, 12288) → Block 96 → (2048, 12288)
形状不变不代表内容不变。恰恰相反,这是语义变化最剧烈的阶段。每一步都在对同一个空间中的向量进行重新编码。
以"苹果"为例:
- Embedding 之后:"苹果"的向量是孤立的水果概念,与"香蕉""橘子"接近,与"公司""股票"无关。
- 经过若干层注意力之后:在"我吃了苹果"中,"苹果"的向量被"吃""我"等上下文词拉向"食物"语义方向;在"苹果公司上市"中,"苹果"的向量被"公司""上市"拉向"企业"语义方向。
- 经过 FFN 加工之后:这些上下文信息被深度非线性加工,"苹果"的向量最终携带了它在当前句子中的精确角色。
形状不变的设计是一种刻意的选择。它让模型可以在同一个语义空间中反复提炼,而不需要在不同维度之间来回转换。注意力负责"横向"广播信息(位置之间交换内容),FFN 负责"纵向"深化理解(每个位置独立加工)。两者交替进行 96 次,语义被层层提炼。
13.3 第三阶段:预测输出(连续 → 离散)
96 层 Block 处理完成后,数据进入输出阶段。这个阶段完成了第二次形状剧变:
(2048, 12288) → LM Head → (50257,) logits → Softmax → (50257,) 概率
FFN 先做深度非线性加工(形状不变),LM Head 再把语义向量映射回词表概率(维度剧变)。从 12288 维的连续语义空间,回到 50257 个离散选择的概率分布。
随后,采样策略从概率分布中选出一个具体的 token(比如"很开心"),这个 token 被拼回输入序列,整个流程再次循环。
13.4 一个贯穿始终的反直觉事实
回顾整个数据旅程,最剧烈的形状变化发生在两个端点:
- 入口处:
(2048,)整数 →(2048, 12288)浮点。维度膨胀了 12288 倍。 - 出口处:
(1, 12288)浮点 →(50257,)概率。从连续空间回到离散选择。
中间的 96 个 Block 像是一条笔直的隧道——(2048, 12288) 进去,(2048, 12288) 出来。但隧道内部发生了 96 次语义提炼。每次提炼都不改变数据的"体积"(形状),但剧烈改变数据的"成分"(语义内容)。
这个设计与很多其他神经网络形成对比。在卷积神经网络中,数据通常从高分辨率逐渐被下采样到低分辨率;在编码器-解码器架构中,数据先被压缩到瓶颈向量,再被扩展回来。Decoder-only 的独特之处在于:它在最核心的处理阶段保持形状完全不变,让所有语义操作都在同一个高维空间中进行。
13.5 小结
数据流视角把模型看作一个管道:
- 第一阶段(输入表示):把离散符号翻译成连续语言。
- 第二阶段(上下文重组):在同一个空间中反复提炼语义,不改变形状但剧烈改变内容。
- 第三阶段(预测输出):把连续语义翻译回离散选择。
三个阶段的分工清晰:翻译、提炼、再翻译。中间 96 层的"形状守恒"是 Decoder-only 架构的核心设计特征——它把所有复杂的语义操作都约束在一个统一的几何空间中,避免了维度转换带来的信息损失。
下一章,我们将从信息如何在空间中传播的视角,进一步理解这个系统的动力学。
第14章 信息传播视角:梯度、信号与语义如何在 96 层中流动
参数视角看"静态分布",数据流视角看"形状变化"。信息传播视角则进一步追问:信息在模型内部如何运动?它在层与层之间怎么传?在位置与位置之间怎么传?理解这种传播动力学,是理解"为什么 96 层"和"每层在干什么"的关键。
14.1 纵向传播:残差高速公路
残差连接 output = input + F(input) 不仅解决了梯度消失问题,还深刻地塑造了信息在层间的传播方式。
它创造了两条并行路径:一条经过当前层的复杂变换 F,一条是直接抄近路的恒等映射。这意味着每一层的输出都包含两个部分:原始输入的保留,和当前层新增的变换。用数学语言表达:
Layer_1_output = x + F_1(x)
Layer_2_output = Layer_1_output + F_2(Layer_1_output)
= x + F_1(x) + F_2(x + F_1(x))
展开后可以看到,第 N 层的输出包含了原始输入 x,加上各层增量修正的叠加。深层不是"重写"浅层的表示,而是在浅层表示的基础上做增量修正。
这解释了为什么浅层、中层、深层的分工不同:
- 浅层(1-20 层):处理词法层面的问题。词性标注、词形变化、基本搭配。这些是大粒度、低层次的规律,浅层的增量修正就能解决大部分。
- 中层(21-60 层):处理句法层面的问题。短语结构、依存关系、局部语义组合。需要多轮注意力和 FFN 的反复提炼。
- 深层(61-96 层):处理语义和推理层面的问题。指代消解、逻辑推断、世界知识、长距离因果关系。这些是细粒度、高层次的判断,需要很深的"思考空间"才能解决。
如果没有残差连接,深层网络就像一个没有通风口的深井——信号下去就再也上不来了。减少层数会直接损害复杂推理能力,因为深层是模型"想得更深"的物理空间。
14.2 横向传播:注意力的全局广播
自注意力是横向信息传播的唯一机制。它让任意两个位置直接交换信息,距离为 1 的邻居和距离为 1000 的远端在传播延迟上没有区别——都是一次矩阵乘法。
这对比 RNN 是本质性的突破:
- RNN 中,位置 1000 的信息到达位置 1 需要 999 步接力。每步都伴随压缩和噪声,信息逐步衰减。
- 注意力中,位置 1000 的信息到达位置 1 只需一步
Q @ K^T。信息不衰减、不扭曲,完整地传递过去。
这种全局广播能力让模型可以同时捕捉多种距离的关系:
- 局部关系(相邻词的修饰关系)由某些注意力头处理。
- 中长距离关系(句子内的指代)由另一些头处理。
- 超长距离关系(段落间的主题呼应)同样可以在一步内完成。
注意力没有"记忆长度"的限制——它的有效上下文只受 seq_len 的物理上限约束,而不是像 RNN 那样受梯度传播路径长度的约束。
14.3 FFN 的局部加工:信息不扩散
与注意力的全局广播形成鲜明对比,FFN 对序列中每个位置独立运算,位置之间没有交互。
FFN 对每个位置 i 独立计算:output[i] = FFN(input[i])
这形成了一种精妙的节奏:
- 注意力负责"横向广播":让信息在位置之间流动,建立全局关联。
- FFN 负责"纵向深化":在获取了上下文信息后,对每个位置独立做深度语义判断。
二者交替进行:先广播,再加工;再广播,再加工。96 个 Block 就是 96 轮"广播-加工"循环。每一轮都在前一轮的理解基础上,进一步提炼语义。
如果把注意力比作"开会议"(让大家交换信息),FFN 就是"独立思考"(每个人基于会议内容做出自己的判断)。没有会议,思考缺乏素材;没有思考,会议结果无法转化为决策。
14.4 层数的意义:从物理空间到抽象层级
96 层不是随意定的数字。它直接决定了模型能够处理的抽象层级数量。
在浅层,模型主要学习局部模式:哪些词经常相邻出现,哪些词性搭配合理。在中层,模型开始学习组合规则:名词短语如何构造,从句如何嵌套,主谓宾如何匹配。在深层,模型开始处理真正复杂的语义和推理:一个代词指代的是谁,一段话的论证结构是什么,一个问题需要调用哪些世界知识来回答。
每一层都为下一层提供更精炼的表示。这种层级化的表示学习不是人为设计的,而是训练过程中自然涌现的。模型被强制预测下一个词,为了做好这个任务,它必须自动发现语言中的层级结构——从字符到词,从词到短语,从短语到句子,从句子到段落。
14.5 小结
信息传播视角揭示了 Decoder-only 架构中三种互补的信息运动方式:
- 纵向:残差高速公路让信息和梯度在 96 层之间畅通无阻,每层做增量修正而非重写。
- 横向:注意力在一步之内完成全局广播,彻底消除了距离衰减。
- 局部:FFN 对每个位置独立加工,把广播来的信息转化为深度判断。
三种运动方式的协同,让模型既能看到远方的信息(注意力),又能做复杂的局部决策(FFN),还能在深层逐步提炼抽象表示(残差+层数)。
下一章,我们将从最后一个视角——工程权衡——来审视那些关键数字背后的设计哲学。
第15章 工程权衡视角:为什么是这些数字?
前三个视角分别从"参数分布""数据变形""信息流动"的角度审视了模型。本章换一个更工程化的角度:为什么是 d_model=12288?为什么是 FFN 4 倍扩展?为什么是 96 层?为什么用 Pre-Norm 而不是 Post-Norm?
每一个数字背后都不是拍脑袋,而是能力、成本、稳定性三者之间的精确权衡。理解这些权衡,是理解大模型工程哲学的关键。
15.1 为什么是 d_model=12288?
d_model 决定了模型内部语义空间的维度。每个 token 被表示为一个 12288 维的向量,这意味着模型同时能编码 12288 种不同的"概念维度"。
如果 d_model 太小(比如 512),向量空间装不下丰富的语义结构。"皇帝"和"国王"可能被迫共享几乎相同的向量,"苹果"(水果)和"苹果"(公司)无法有效分离。模型的表示能力会受到严重限制。
如果 d_model 太大(比如 65536),训练成本和推理成本会急剧上升。参数量与 d_model² 成正比,每增大一倍,FFN 和注意力的参数量都变成四倍。同时,矩阵乘法的计算量也与 d_model² 成正比。
12288 是 GPT-3 时代在算力、显存和模型能力之间找到的一个权衡点。它不是理论上的最优值,而是在当时硬件条件下(V100 GPU,32GB 显存)能够高效训练、同时又不至于损失太多表达能力的经验值。后续模型如 GPT-4 的 d_model 更大(传闻为 16384 或更高),反映了硬件进步后权衡点的移动。
15.2 为什么是 FFN 4×扩展?
原始 Transformer 论文选择了 4 倍扩展。这个比例在后续模型中被广泛沿用,但原因不仅仅是"传统"。
从数学上看,FFN 的参数量公式是 8 × d_model²。如果扩展比例从 4 降到 2,参数量减半(变为 4 × d_model²),但表达能力显著下降——中间空间太小,模型无法学习足够的非线性特征组合。如果扩展到 8,参数量翻倍(变为 16 × d_model²),但实验表明,从 4× 到 8× 的能力提升有限,边际收益递减。
4× 接近"参数量-能力"曲线的拐点:再小则损失明显,再大则浪费严重。后续研究(如 SwiGLU 的引入)在保持 4× 中间维度的同时,通过门控机制进一步提升了表达能力,而不是简单地增加扩展比例。
15.3 为什么是 96 层?
层数直接决定模型的"思考深度"。每一层都在前一层的基础上做增量修正,层数越多,模型能处理的抽象层级就越多。
但层数不能无限增加。超过一定深度后,训练稳定性会急剧恶化。在 Pre-Norm 出现之前(原始 Transformer 使用 Post-Norm),超过 20 层的模型训练就已经非常困难。Pre-Norm 把稳定训练的上限推到了大约 100 层。
GPT-3 的 96 层是 Pre-Norm 结构下能够稳定训练的一个接近极限的值。再深(如 200 层)需要 DeepNorm 等更新的技术来保证梯度不爆炸也不消失(详见第16章)。
层数与 d_model 之间也存在权衡。在总参数量固定的情况下,可以做一个"宽而浅"的模型(大 d_model,少层数),或者一个"窄而深"的模型(小 d_model,多层数)。实践表明,在总参数相近的情况下,"深"模型通常比"宽"模型在复杂推理任务上表现更好,因为深层提供了更多的抽象层级。
15.4 为什么是 Pre-Norm?
原始 Transformer 论文使用的是 Post-Norm:先加残差,再做归一化。公式是 LayerNorm(x + F(x))。
Post-Norm 的问题在于,当网络很深时,x + F(x) 的数值尺度在训练初期非常不稳定。如果 F(x) 的输出碰巧很大,加上 x 后数值就会爆炸;如果 F(x) 的输出碰巧很小,数值就会衰减。LayerNorm 虽然能归一化,但它是在加法之后做归一化,问题已经产生了。
Pre-Norm 把归一化放在前面:x + F(LayerNorm(x))。F 接收到的输入在训练初期就已经是均值 0、方差 1 的分布,输出的尺度更可预测。这让深层网络的训练稳定性大幅提升。
GPT-3 及之后几乎所有大模型都采用 Pre-Norm。这不是因为它是"更好的归一化",而是因为它让 100 层级别的模型训练从"几乎不可能"变成了"可行"。
15.5 为什么保留 Softmax 而不是 argmax?
在第9章提到过,argmax 不可导,无法参与反向传播。但还有另一个原因:Softmax 提供了平滑的概率输出,让模型在训练时能感知到"错误答案之间的差距"。
假设正确答案的词 A 获得了 logits 的最高分,但词 B 只比词 A 低一点点。如果用 argmax,模型只知道"A 是对的",完全不知道 B 也很接近。用 Softmax,B 会获得较高的概率(比如 45%),损失函数会告诉模型"A 和 B 很接近,你需要进一步拉开差距"。这种细粒度的反馈让模型学得更好。
此外,Softmax 与交叉熵配合时梯度形式简洁(probs - one_hot),计算高效。这种数学上的优雅性在千亿参数规模下具有实际工程价值。
15.6 核心洞察:没有免费午餐
总结以上每一个设计选择,它们都遵循同一个原则:
每个数字 = 能力 ↑ × 成本 ↓ × 稳定性 ↑ 的权衡最优解
- d_model=12288:能力足够大,成本和训练稳定性可控。
- FFN 4×:能力接近拐点,参数量不浪费。
- 96 层:Pre-Norm 下稳定训练的深度极限。
- Pre-Norm:用略微减少的表达能力换取大幅提升的训练稳定性。
- Softmax:用可导性和平滑反馈换取不能硬截断的微小代价。
理解这些权衡,意味着你不再把模型的每个数字当作"别人规定的魔法常数",而是把它们看作工程师在特定约束条件下做出的理性选择。当硬件进步(GPU 显存更大、计算更快)或算法突破(新的归一化方法、更高效的注意力)出现时,这些最优解会随之移动——这就是为什么架构演进是一个持续进行的过程。
图22:关键设计选择权衡矩阵

15.7 小结
工程权衡视角回答的问题是:为什么是这些具体的数字?
答案是:每个数字都是能力、成本、稳定性三者之间的精确权衡,不是理论推导的唯一解,而是在特定历史条件下的经验最优解。理解这些权衡的底层逻辑,比记住数字本身更有价值——因为当条件变化时,你会知道如何重新评估和调整。
到这一章为止,多视角回顾已经完成。接下来,我们将跳出 GPT-3 的静态架构,看看 2020 年以来每个组件经历了怎样的现代化改进。
第16章 前沿演进:GPT-3 之后 Decoder-only 架构的持续改进(2020—2026)
GPT-3 在 2020 年确立了 Decoder-only 架构的基本框架,但它远非终点。从 2020 年到 2026 年,架构的每一个组件都被反复重新审视、优化和替换。这些改进不是推翻重来,而是在保持核心机制不变的前提下,用更高效的实现、更优的数学形式或更聪明的条件激活来突破瓶颈。
本章按照第三部分"逐层拆解"的数据流顺序,系统梳理每个组件的研究进展。核心围绕三个目标:支持更长上下文、降低推理成本、提升训练稳定性与表达能力。
16.1 Token Embedding 的演进
更大词表。GPT-3 的词表大小是 50257。此后,词表持续扩大:Llama 2 用 32000,Llama 3 用 128256,一些模型甚至使用 256k。扩大词表的目的不是增加参数量(Embedding 在总参数中占比很小),而是让每个 token 能编码更多信息。一个更大的词表意味着更少的 token 就能表达同样的内容,序列长度缩短,推理速度提升。
多模态统一 Embedding。GPT-4o、Gemini 等模型将图像、音频的离散 token 与文本共享同一个 Embedding 空间。图像被切分为视觉 patch,每个 patch 像单词一样被编码为向量,与文本 token 并排输入同一个 Decoder-only 骨架。这使得单一架构能够处理多种模态,而不需要为每种模态单独设计编码器。
16.2 位置编码的演进
RoPE 成为绝对主流。旋转位置编码(Rotary Position Embedding)在 2021 年提出后,迅速取代可学习位置编码,成为 GPT-NeoX、Llama、Qwen 等模型的标准选择。RoPE 用旋转矩阵替代可学习位置向量,相对位置信息直接体现在 Query 和 Key 的内积中,外推和内插更加自然。
长上下文外推技术。模型训练时的上下文长度有限(通常是 2k-4k),但用户希望模型能处理 128k 甚至 1M 的长文档。直接在这个长度上训练成本极高。研究者发现,可以通过调整 RoPE 的旋转频率或插值比例,让模型"以为"位置编号没有超出训练范围:
- PI(Positional Interpolation):把长距离的位置编号按比例缩小,塞回训练时的范围。
- YaRN:根据注意力头的不同动态调整插值比例,某些头处理局部信息不需要插值,某些头处理全局信息需要更多插值。
- NTK-aware scaling:从神经正切核(NTK)理论出发,非线性地调整不同维度的旋转频率。
这些技术让模型在不重新训练的情况下,把上下文窗口扩展到 128k 甚至 1M。
16.3 掩码多头自注意力的演进
注意力机制是自注意力的核心,但它的计算和显存开销也最大。2020 年以来的改进主要集中在让它更快、更省显存、更适合长上下文。
FlashAttention 系列(1/2/3)。标准注意力的实现需要显式构造 seq_len × seq_len 的注意力分数矩阵,显存复杂度是 O(seq_len²)。FlashAttention 不改动注意力的数学公式,而是重排 GPU 内存访问模式,利用 tiling 和重计算(recomputation)把显存复杂度降到 O(seq_len)。这使得百 k 级上下文在工程上可行。
MQA / GQA(Multi-Query / Grouped-Query Attention)。标准多头注意力中,每个头都有自己独立的 K 和 V。MQA 让所有头共享同一组 K 和 V;GQA 是折中方案,把 96 个头分成若干组,每组共享 K 和 V。以 Llama 2/3 为例,采用 GQA 后,KV Cache 显存占用降为原来的 1/8 ~ 1/2,推理速度显著提升,而能力损失控制在可接受范围内。
MLA(Multi-head Latent Attention)。DeepSeek-V2/V3 提出的 MLA 用低秩压缩把 K/V 投影到更小的 latent 空间。KV Cache 占用比 GQA 进一步降低一个数量级,是长上下文推理的极致优化方向。
线性注意力 / 状态空间模型。Mamba、RWKV 等架构试图用 O(seq_len) 的序列建模替代 O(seq_len²) 的自注意力,彻底摆脱长上下文的二次复杂度诅咒。这些架构在特定任务上展现优势,但在通用能力上尚未全面超越标准注意力。
16.4 残差连接与归一化的演进
Pre-Norm 成为绝对标准。GPT-3 及之后几乎所有大模型均采用 Pre-Norm,相比原始 Transformer 的 Post-Norm 显著提升了深层网络的训练稳定性。
RMSNorm 替代 LayerNorm。Llama、Mistral、DeepSeek 等模型用 RMSNorm 取代了 LayerNorm。RMSNorm 去掉 LayerNorm 的均值中心化步骤,只保留标准差缩放:
RMSNorm(x) = x / RMS(x) × γ
计算更简单、训练速度更快,效果与 LayerNorm 相当。
DeepNorm。微软在 2022 年提出的 DeepNorm 为超深层网络(100+ 层)设计特殊的残差缩放系数。标准残差是 output = x + F(x),DeepNorm 改为 output = x + α·F(x),其中 α 是一个与层数相关的理论最优常数。DeepNorm 从数学上保证深层网络梯度不爆炸也不消失,让 100+ 层的模型可训练。
16.5 前馈网络(FFN)的演进
SwiGLU / GeGLU 替代 GELU。PaLM、Llama、Mistral、DeepSeek 等模型在 FFN 中引入门控机制:
SwiGLU(x) = (W_1 @ x ⊗ SiLU(W_2 @ x)) @ W_3
两个并行线性分支,一个过激活函数后与另一个逐元素相乘(⊗ 表示逐元素乘法)。表达能力显著强于单路 GELU,已成为当前最主流的 FFN 变体。
MoE(Mixture of Experts)。GPT-4、Mixtral、DeepSeek-V2/V3、Kimi 等模型不再使用单一 FFN,而是维护 8-256 个并行的"专家" FFN,每个 token 通过一个轻量路由网络选择 1-8 个专家进行计算。
以 DeepSeek-V3 为例:总参数量 671B,但每次前向传播只激活约 37B 参数。目的是在不增加推理计算量的前提下,指数级扩展模型的参数容量和知识存储能力。MoE 的核心洞察是:模型不需要在每个 token 上激活全部参数,只需要激活与当前 token 最相关的专家即可。
并行注意力+FFN。PaLM 将原本串行的"注意力 → FFN"改为并行执行:
output = x + Attention(LayerNorm(x)) + FFN(LayerNorm(x))
注意力分支和 FFN 分支同时计算,减少层间流水依赖,加速大规模分布式训练。
16.6 输出层(LM Head)的演进
超大词表输出。配合 128k-256k 词表,LM Head 的投影矩阵增大。如果不使用 Weight Tying,输出层单独占用的参数量会变得很大(d_model × 128256 约 15.7 亿)。这进一步凸显了 Weight Tying 的重要性。
多模态输出投影。GPT-4o、FLUX 等模型在文本词表之外增加图像/音频解码头,共享底层语义表示但各自解码回不同模态。Decoder-only 骨架从"文本生成器"扩展为"多模态生成器"。
16.7 架构级新探索
混合架构。Jamba、Zamba 等模型把 Mamba 层与标准 Attention 层交替堆叠。前几层用 O(seq_len) 的 Mamba 做局部建模,后几层用 Attention 做全局关联,取长补短的折中方案。
去归一化探索。部分研究尝试减少或去掉 LayerNorm/RMSNorm,通过更精细的初始化策略维持数值稳定,进一步简化架构、降低计算开销。目前仍在实验阶段。
16.8 核心洞察:改进的两条主线
回顾 2020-2026 年的演进,可以清晰地看到两条主线:
2020-2023:工程效率改进(蓝色节点)
这一阶段的核心目标是在保持能力的前提下降低成本:
- FlashAttention 降低显存占用。
- MQA/GQA 降低 KV Cache。
- 更大词表缩短序列长度。
- RMSNorm 简化计算。
2023-2026:能力扩展与成本解耦(橙色节点)
这一阶段的核心目标是在控制成本的同时扩展能力边界:
- MoE 用条件激活实现万亿参数规模的模型,但每次推理只激活一小部分。
- MLA 把 KV Cache 压缩到极致,支撑百万级上下文。
- 长上下文外推技术让模型无需重新训练就能处理超长文档。
- 多模态统一让 Decoder-only 骨架超越文本,成为通用智能的底座。
所有改进都遵循一个原则:核心机制(自注意力 + FFN + 残差 + 归一化)未被推翻,而是被更高效地实现、更聪明地激活、更稳定地训练。Decoder-only 的基本框架在 2020 年被 GPT-3 确立后,至今仍是所有大模型的通用骨架。变化的是每个组件的具体实现形式,而不是架构的根本逻辑。
图23:各组件演进时间线(2020-2026)

16.9 小结
从 2020 到 2026 年,Decoder-only 架构经历了快速而持续的进化。Embedding 更大更多模态,位置编码更灵活,注意力更快更省显存,归一化更简单更稳定,FFN 更强更聪明,输出层更多模态。这些改进共同推动了大模型从"能生成流畅文本"走向"能理解超长文档、能处理多模态输入、能进行复杂推理"的通用人工智能底座。
但所有这些改进,都是建立在本书前 15 章所描述的坚实基础之上的。如果你已经理解了 Embedding、位置编码、注意力、残差、归一化、FFN 和输出层各自的功能和必要性,那么前沿演进中的每一项改进对你来说都不再是黑箱——你会知道它改的是什么、为什么能改、以及改进的边界在哪里。
本书的技术内容到此结束。最后一章是后记,我想以作者的视角,补充一些写作背后的思考和感悟。
后记
写这本书的时候,我常常想起十几年前在实验室里调模型的日子。那时用的还是 RNN,训练一个情感分类任务要跑一整晚,看着终端上跳动的 loss 曲线,心里既焦灼又充满期待。后来我去做了金融,穿上了西装,每天打交道的是报表和市场,但夜里偶尔还是会打开 arXiv 翻翻新论文,像是一个从未彻底离开的老朋友。
2022 年底 ChatGPT 问世时,我正坐在出差的飞机上。降落后打开手机,满屏都是它的截图。我试了几个问题,然后意识到:这个世界要变了。不是因为它能写诗——早年的模型也能写诗——而是因为它展现出了近乎通用的推理能力。这种能力不是某个团队用某个特定数据集训练出来的,而是从一个极简的目标函数(预测下一个词)和一套极简的架构(Decoder-only Transformer)中自然涌现的。
这之后的几年里,大模型成了全世界最热闹的话题。我见过太多人谈论它,有人惊叹它的聪明,有人担忧它的危险,也有人急着用它赚钱。可当我真正沉下心去读那些论文时,我发现很多讨论都绕过了最基础的一个问题——它到底是怎么工作的?不是那种"注意力机制很神奇"的笼统说法,而是每一层具体在干什么,数据从哪来、经过什么、变成什么。这个问题不搞清楚,所有的惊叹和担忧都像是站在沙滩上看浪,看起来汹涌,其实脚下是空的。
所以我决定写这本书。我无意把它写成一本百科全书——Transformer 的 Encoder-Decoder 架构固然经典,BERT 和 T5 也曾经是时代的主角,但今天的大语言模型无一例外都是 Decoder-only。与其面面俱到,不如把这一个架构讲透。这是当代大模型的通用骨架,理解了它,你就理解了几乎所有你日常接触到的 AI。
我既不想堆砌公式,也不想滥用比喻——比喻听多了容易让人误以为自己懂了,实际上脑子里还是一团浆糊。我更愿意带着你站在一个足够高的地方,先看清整台机器的全貌,然后再一个零件一个零件地拆下来看。每一个零件,我都会说清楚它的输入是什么、输出是什么、参数有多少、为什么必须有它。数据在系统里流动的路径,就像一条河,你顺着它走,自然就能看懂每个闸口的作用。
关于这本书的方法论
在写作过程中,我始终坚持三个原则。
第一个原则是"上帝视角优先"。 每一章在讲细节之前,先告诉读者"这一层在全局中承担什么角色"。人在面对复杂系统时,如果没有整体框架,细节只会变成杂乱无章的信息碎片。只有先看到地图,再去走每一条街道,才能记住路。
第二个原则是"按数据流顺序拆解"。 很多技术书按"作者觉得重要的顺序"来讲,而不是按"数据实际流动的顺序"来讲。这本书严格遵循后者:Embedding → 位置编码 → 注意力 → 残差&归一化 → FFN → 输出层。读者沿着"数据从哪来、经过什么、变成什么"的线性路径阅读,符合认知习惯。
第三个原则是"每个组件回答四个问题"。 输入是什么?输出是什么?参数是什么?为什么必须有它?如果回答不了第四个问题,说明我自己也没真正理解这个组件。这个标准逼着我反复推敲,删掉了很多看似正确但实际上经不起追问的内容。
关于量化与具体性
全书以 GPT-3 作为量化基准,这不是因为我特别推崇 GPT-3——事实上,它已经被后续模型全面超越——而是因为它的参数规模(1750 亿)和架构选择(96 层、12288 维、50257 词表)在 Transformer 发展史中具有标志性意义。用一套具体的数字贯穿全书,读者可以在阅读每一章时都建立一个清晰的尺度感,而不是在抽象符号中迷失。
当我说"每层注意力有 6.04 亿参数"时,这不是为了炫耀数字,而是为了让读者在心中形成具体的认知。6.04 亿是什么概念?大约相当于 1000 本《红楼梦》的文字量。把这些数字内化后,当你再听说某个模型有"万亿参数"时,你会知道那意味着什么。
关于 Decoder-only 的未来
写这本书的时候,有人问我:Decoder-only 会一统江湖多久?我的回答是:核心机制(自注意力 + FFN + 残差 + 归一化)至少在未来五年内不会被推翻,因为它们是数学上有效、工程上可行、规模上可扩展的最小充分集。
但每个组件的具体形式会持续演进。注意力的二次复杂度终将被某种线性近似补充或替代——不是完全取代,而是在特定场景下分担负载。FFN 的门控化和条件激活(MoE)会成为标配。多模态统一会让 Decoder-only 从"文本模型"进化为"世界模型"的通用骨架。
最重要的趋势可能是"推理时计算"的崛起。现在的模型在推理时只做一次前向传播就输出答案。未来的模型可能会在推理时进行多步内部思考——让模型在生成最终答案之前,先在内部生成并评估多个候选思路。这相当于把训练时的"梯度下降"搬到推理时的"搜索空间探索"中。如果这条路走通,模型的能力边界将被再次大幅推高。
写在最后
我不是一个全职的研究者,也不是一个全职的工程师。我是一个对技术有执念的金融从业者,一个在深夜读论文时还会心跳加速的前 AI PhD。我写这本书,是因为我相信理解是敬畏的前提。当你真正理解了一个 1750 亿参数的模型内部是如何一块一块拼起来的,你对它的惊叹会从"魔法"变成"工程"。而后者,在我看来,是更深刻、更持久的敬意。
如果这本书能让你下次打开 ChatGPT 时,脑子里浮现出 Embedding、注意力、FFN 和 LM Head 接力运行的画面,那它就完成了使命。技术的普及不是让每个人都成为专家,而是让每个人都有能力理解专家在说什么。技术的终极意义,从来不只是让人惊叹,而是让人理解。