Appearance
原文:第 8 章 说明:忠实翻译原网页内容,并补入与经典文献、业界系统的对照。术语首次出现给出英文锚点。
第 8 章 Transformer 基础
本章在体系中的位置
前 7 章一直在讲「算力底座」:GPU 为什么赢(第 2 章)、它内部长什么样(第 3 章)、怎么给它的执行单元写程序(第 4–5 章)、编译器怎么把内核榨到极致(第 7 章)。从本章开始,课程进入大模型系统部分——被优化、被并行、被服务的对象,从抽象的张量变成了 Transformer 架构本身。
第 8 章是这部分的入口,做两件事。第一,把 Transformer 从输入到输出完整拆开,让你拿到后半门课的「算力账本」:每个组件(嵌入、注意力、前馈、生成)各占多少计算、多少内存、多少参数。第二,用这份账本回答一个前置问题:为什么大模型训练必须在成百上千块加速器上分布式进行。 第 9 章的数据并行、第 10 章的模型并行,都得先清楚「单个 Transformer 层有多少 FLOPs、多少字节」,才知道怎么切;第 11 章的推理系统,则在「自回归逐 token 生成」这个机制上展开。第 7 章优化的是内核;从本章起,课程优化的对象变成了架构本身。
训练一个能对话、会推理、能写代码的模型,早已不只是算法问题,而是系统工程问题。而这一切的起点,是一个具体的架构:Transformer。
这一章把它从输入到输出完整拆开:一句话怎么变成数字,注意力怎么计算,最后一个词怎么被生成。过程中我们会一直记账——每一步要多少算力、多少内存、多少参数。这些账,就是第 9 章之后所有分布式与推理技术的算术基础。如果你想在这 2 万字的行程里只带走一句话,那是这句:Transformer 是一个计算上可并行、规模上单机不可承受的架构——前半句是它能统治这个时代的原因,后半句是整门课后半段存在的理由。
8.1 Transformer 生态:鸟瞰
当代人工智能已经进入由大语言模型(Large Language Model,LLM)定义的时代。这类系统规模惊人、能力空前,正在重塑人与机器交互的方式。但要训练它们,我们既需要深入理解底层架构,更需要掌握系统工程——如何把海量的计算负载分布到成百上千块加速器(GPU 或 NPU)上。
在钻进机制之前,值得先感受一下 Transformer 的渗透程度。今天,一个库——Hugging Face 的 transformers——就用统一接口覆盖了海量任务,这些任务背后的模型几乎全部由 Transformer 架构驱动,横跨多种模态:
- 文本: 文本生成、文本分类、摘要、翻译、特征提取
- 视觉: 图像转文本、图像分类、目标检测
- 音频: 自动语音识别、文本转语音、音频分类
这不是一份野心宣言,而是生态现实。在 transformers 配套的模型仓库(Model Hub)里,托管着几十万个预训练检查点(checkpoint),从几亿参数的小模型到几千亿参数的旗舰模型都有;「换个任务」在库的层面常常只是换一行 pipeline() 的参数。这个库的关键抽象正是 pipeline() 函数:它把一个预训练模型和它所需的全部预处理、后处理步骤打包成一个即用管道。下面这个情感分析的最小示例直接来自 Hugging Face 的官方书籍:
python
from transformers import pipeline
classifier = pipeline("sentiment-analysis")
classifier("I've been waiting for a machine learning systems course my whole life.")
# 输出:POSITIVE(0.96)这行简单得骗人的代码,底下藏着惊人的复杂度。管道会自动执行三个截然不同的阶段:
- 预处理(preprocessing): 原始文本被分词,转成模型能处理的数值表示。
- 模型推理(model inference): 数值输入穿过 Transformer 网络,执行数以百万甚至十亿计的浮点运算。
- 后处理(post-processing): 原始数值输出被解码,映射回人类可读的标签和分数。
默认情况下,pipeline() 会在本地没有缓存时自动挑选并下载一个预训练模型。这背后是现代 NLP 的一条核心哲学:把在海量数据上预训练的巨额投入拿来复用,再针对特定任务做最小化的适配。
对这个课程来说,示例还有另一层提醒:情感分析只是 Transformer 的外壳,真正值得系统工程师盯着的,是第二个阶段——几百万到几十亿次浮点运算,如何在单张卡上高效执行。这正是第 3、7 章(GPU、编译器)已经打下的地基,也是本章接下来要拆开的架构。8.3–8.7 节的内容,就是在把第二个阶段这层「外壳」剖开给人看。
8.2 Transformer 模型简史
要理解分布式训练为什么如此关键,先得回顾模型规模膨胀得有多快。现代 NLP 的血统可以追溯到 2017 年 Vaswani 等人的论文 Attention Is All You Need:它引入了基础的 Transformer 架构,并证明了仅凭注意力机制就足以在机器翻译上达到当时最先进的水平。
这篇论文的划时代意义不止于此:它彻底摆脱了循环神经网络(RNN)逐时间步串行的依赖结构,序列建模第一次可以大规模并行计算——「可并行」这个属性,直接埋下了后来分布式训练的种子,也是第 7 章编译器能对 Transformer 内核做深度优化的前提。
之后的年份,能力更强的模型接连爆发,大致可以排成这样:
| 时期 | 关键进展 |
|---|---|
| 2017 | 原始 Transformer(Attention Is All You Need) |
| 2018–2019 | 奠基模型:GPT、BERT、GPT-2、T5 |
| 2020 | GPT-3——真正大的语言模型出现(175B 参数) |
| 2021–2022 | InstructGPT、FLAN、ChatGPT——对齐与指令遵循 |
| 2023–2024 | GPT-4、LLaMA、LLaMA-3.1(405B)、GPT-4o——开源与闭源前沿模型 |
| 2025 | 高级推理模型:OpenAI-o1、DeepSeek-V3、DeepSeek-R1 |
这张时间线里最重要的洞察只有一个词:规模(scale)。从左到右,模型参数量从几千万增长到几千亿,个别场景已经到了万亿级。GPT-3 有 1750 亿参数;LLaMA-3.1 达到 4050 亿。没有任何一张现存的 GPU 能把这些模型装进显存,更别说训练它们了。 这不是「等下一代更快的芯片」能解决的问题——单芯片扩展早就撞上了功耗墙(第 1 章),出路是把问题拆开、摊到很多台机器上。这正是分布式训练技术存在的意义,也是本章——乃至整门课后半段——的核心工程挑战。
如果你想把 Transformer 亲手从零实现一遍,强烈推荐 Harvard NLP 小组的 The Annotated Transformer:它把 PyTorch 实现逐行注释,配合原文读,是教科书之外最好的阅读指引。
8.3 Transformer 的预处理
现代 LLM 落在两种训练范式里,它们在使用上下文的方式上差别很大。先分清这两个范式,后面 8.6 节谈架构家族时你就能自己推出「什么架构配什么任务」。
8.3.1 因果语言模型
因果语言模型(causal language model)尊重时间箭头:预测下一个 token 时,它只能看见过去的 token,不能偷看未来。训练目标简单得优雅——给定一串词,预测下一个词:
训练时,这个过程在数十亿甚至数万亿个 token 上重复。每一步,模型做一个预测、与训练数据里的真实标签对比、通过反向传播更新权重。预测的差距用交叉熵(cross-entropy)衡量——交叉熵越小,模型对「下一个词」的概率估计越准。别被这简单的目标骗了:GPT-3、GPT-4、LLaMA 都属于这个家族,当今大多数生成式 AI 系统几乎全在这里——包括你正在用的每个聊天模型。目标越简单,掩盖的计算代价越巨大:要在现代 LLM 要求的规模上完成这些操作,需要非同寻常的基础设施。
8.3.2 非因果语言模型
非因果语言模型(non-causal language model)换了一条路:它同时读完整条序列,左侧和右侧的上下文都能看见。它不预测下一个词,而是用掩码语言建模(Masked Language Modeling)训练:随机把输入里的一个词替换成特殊的 [MASK] token,让模型用周围的上下文把它猜回来:
这种双向阅读理解,让非因果模型在处理需要理解完整输入的任务上格外强——搜索、语义嵌入、文本分类都是。这个家族的经典代表是 BERT(它的训练任务严格说是两个:掩码词预测 + 下一句预测)。双向性的代价也很直接:它天生做不了自回归生成——它擅长「补全」,不擅长「续写」。这解释了为什么理解类任务看 BERT,生成类任务看 GPT。但无论采用哪种训练范式,底层矩阵运算的规模都同样庞大,对分布式基础设施的需求一模一样。
8.3.3 从文本到 token:分词
上面说的是 Transformer 学什么,接下来看它怎么学——追踪数据如何流过完整的架构栈:从输入的原始文本,到输出的概率分布。神经网络读不懂英文,它们只操作数字。流水线的第一步因此是把原始文本转成一串整数 ID,这个过程叫分词(tokenization)。
关键在于:token 并不总等于完整单词。分词器用一张子词单元(subword unit)的词汇表,常见词映射成单个 token,生僻或复杂的词拆成多个子词片段。例如:
"bought"→ 单个 token"indivisible"→ 两个 token:"indiv"+"isible""."(标点)→ 自己的 token
词汇表里每个唯一 token 都对应一个整数 ID。一张 50,000 词的词汇表,意味着任何文本都能表示成取值于 的整数序列。此外,分词器还会预留几个特殊 token:句首 [BOS]、句末 [EOS]、未知词 [UNK]、以及训练掩码用的 [MASK]——它们在词表里各占一个 ID。
主流的子词切分算法包括字节对编码(Byte-Pair Encoding,BPE)、WordPiece 与 Unigram——GPT 系多用 BPE,BERT 用 WordPiece。BPE 的思路一句话就能说清:统计词频,不断合并最高频的字节对,直到词表达到目标大小。它让模型不必记住每个生僻词的完整拼写,而是复用常见子词——这也是为什么模型认识「indivisible」,哪怕训练语料里这个词没出现过几次。
8.3.4 独热编码
分词器给出的整数 ID 还不能直接做数学运算。下一步是独热编码(one-hot encoding):每个整数 ID 变成一个长度为 (词汇表大小)的稀疏向量,除了第 位是 1,其余全是 0。词汇表 50,000、token ID 是 3687 的话:
概念上干净,工程上极其低效:一个 50,000 维的向量,49,999 个位置都是零。把这种稀疏、高维的向量直接喂进神经网络,计算代价不可接受。记住这个「一热一冷」的中间形态——它是理解下一步嵌入层为什么要存在的最好铺垫。
8.3.5 token 嵌入
稀疏问题的解法是嵌入层(embedding layer)。定义一个可学习的嵌入矩阵(embedding matrix) , 是词汇表大小, 是(小得多的)嵌入维度。把独热向量乘上 ,等价于一次索引查找——它直接选中矩阵的某一行:
结果是稠密的 维浮点向量——嵌入后的 token(embedded token)。几千个零换成一个丰富、紧凑的向量,这才是流经 Transformer 其余部分的形式。换个角度,嵌入矩阵就是一张可学习的查找表:查表(索引)+ 取行。训练中这张表的每一行都被梯度更新,所以「dog 靠近 cat」不是写进去的规则,而是海量文本共现统计的产物。
嵌入空间是模型学习语义关系的地方。通过训练,这个空间的几何会逐渐反映意义:"dog" 的向量会离 "cat" 比离 "car" 更近。序列里的每个 token 都独立地做这种嵌入。这里还藏着一个工程细节:输出层那个把隐藏向量映射回词表的大投影矩阵 (8.7 节会用到),常常直接复用嵌入矩阵 ——这叫权重绑定(weight tying),既省了 个参数,又让「输入侧」和「输出侧」共享同一套语义几何。
8.3.6 位置编码
嵌入之后,一个微妙但致命的问题浮出来:注意力机制天然是置换不变(permutation invariant)的——它本质上在做集合运算,根本不关心 token 的顺序。同一句话打乱 token 顺序,注意力分数矩阵的元素组合几乎不变。对「词序即语义」的语言来说,这是不可接受的。
解法是位置编码(positional encoding):把随位置变化的信号加到嵌入向量上。这些编码是固定的数学函数(或可学习参数),让模型能区分 "Tom likes Jerry" 和 "Jerry likes Tom"。原始论文用的是固定的正弦/余弦函数:
其中 是位置, 是维度下标。不同频率的三角函数让模型既能区分相邻位置,又能在长序列上保持周期结构。今天的主流大模型大多改用 RoPE(Rotary Position Embedding,旋转位置编码,Su et al. 2021):它不把位置信息加在向量上,而是对 query 和 key 做按维度旋转——把向量按维度两两分成一对,在二维平面上旋转一个与位置成正比的角度。于是两个 token 的注意力分数只依赖它们的相对位置差,而非绝对位置,长度外推能力因此更好——LLaMA、GPT-NeoX 等都用它。位置编码从「加法」到「旋转」的演化,是模型架构仍在快速演进的一个缩影。
8.4 自注意力机制
Transformer 的心脏——也是它强大和昂贵的原因——是自注意力(self-attention)。这个机制让序列里的每个 token 直接关注所有其他 token,捕获 RNN 这类顺序模型难以学到的长程依赖。8.3 节把数据送进了模型,从本节开始,真正的「算力账本」要开张了。
8.4.1 查询、键与值
要计算注意力,每个嵌入后的 token 先通过三个独立的学习权重矩阵,被投影成三种角色:
其中 ,, 是查询/键维度, 是值维度。三种角色的直觉,用检索系统来理解最顺手——「查询-键-值」这三个名字本来就借自信息检索与数据库:
- 查询(query,): 这个 token 在找什么。比如 "watch" 这个查询,想知道自己是什么样的 watch。
- 键(key,): 这个 token 有什么。"apple" 带着一把键,表明它可能是个品牌,也可能是一种水果。
- 值(value,): 当查询和键匹配时,真正被传递出去的含义。
想象你在图书馆找书:query 是「我要找讲 transformer 的书」,key 是每本书的索引卡,value 是书架上的实体书。注意力分数回答「这本索引卡匹配我的问题吗」,输出则是所有书按匹配度加权取回。注意 是三个不同的矩阵——同一个 token 能以三种身份参与匹配,这正是后面多头机制的前奏。
实践中,所有 token 的投影是同时算的。把 token 向量堆成序列矩阵 ,一次算完:
这是稠密矩阵乘法——正是 GPU 为之优化的那类工作负载,也是第 7 章编译器最想优化的对象。
8.4.2 缩放点积注意力
给定 、、 三个矩阵,注意力输出是:
公式名字里有两样东西:「点积」——相似度由内积衡量;「缩放」——除以 的用意,下面逐步拆开看:
- : 查询和键做矩阵乘法,产生一个 的原始相似度矩阵, 是序列长度(即单个请求的输入 token 数)。元素 度量 token 应该多大程度地关注 token ;当 时,那是 token 关注自己——自注意力里完全合法,而且往往强度很高。
- 除以 缩放: 不缩放的话,点积会随 增大而变得非常大,把 softmax 推进梯度极小的区域。直观原因:若 、 的各分量是均值为 0、方差为 1 的独立随机变量,点积 的方差就是 ;除以 把方差拉回 1,softmax 不会过早饱和。
- Softmax: 把每行的原始分数转成概率分布,每个 token 的注意力权重之和为 1。注意 softmax 是按行作用的——第 行的归一化只看第 行,各行独立成分布。
- 乘以 : 最终输出是值向量的加权和,权重就是注意力概率——注意力分数高的 token 对输出贡献更大。
二次方内存:注意力的阿喀琉斯之踵
产生的是 矩阵。对长度为 的序列,这需要 内存。现代 LLM 把上下文窗口推到 100,000 甚至 200,000 个 token 时,这个二次方内存成为严重瓶颈。今天的训练和推理框架不会一次性算出完整的注意力矩阵——FlashAttention(Dao et al., NeurIPS 2022)通过 IO 感知的切块,把注意力分块计算、避免实例化 矩阵,是这类「注意力系统优化」的代表作,第 11 章会回到这个话题。
8.4.3 多头注意力
一次注意力计算只能同时寻找一种关系。但自然语言里同时并存着大量彼此重叠的结构:语法一致、指代、语义相似、时间顺序,等等。
多头注意力(multi-head attention)让 个注意力计算并行进行,每个头都有自己的投影矩阵。若完整隐藏维度是 ,每个头在截断后的维度 上工作:
每个头独立地专门化,它们的输出被拼接起来、经 线性投影,把多样化的上下文信息合成一个统一的表示。以 为例,不同头可能分别学会关注句法角色、语义关联、位置邻近等不同的模式——2017 年原文用的就是 、。有一个容易误会的点:多头并不改变总的计算量级—— 个头、每个维度 ,加起来的矩阵运算规模和不分头大致相同;它改变的是表达。但正因为每个头都要维护自己的投影矩阵,这一部分成为模型内存足迹的主要来源之一——记忆和表达的双重代价,都在这里。
8.4.4 解码器中的因果掩码
自回归生成(一次一个 token 地预测下一个)要求模型不能关注未来的 token。这靠一个加到 softmax 前注意力分数上的掩码矩阵(masking matrix) 来强制执行:
的构造规则:
- 下三角(过去和当前位置)是 ——分数不受影响;
- 上三角(未来位置)是 ——因为 ,softmax 对未来 token 恰好分配零权重。
这一个优雅操作,把 Transformer 从双向阅读器变成严格的单向生成器——计算行为彻底不同,架构却没改一个字,只加了一个掩码。还要强调一句:掩码只在训练和自回归生成时出现;8.6 节三种架构家族的差别,本质就是「这个掩码加不加、加在哪」——编码器不掩码,解码器才掩码。
8.5 前馈网络
自注意力子层之后,每个 token 的表示还要过一个逐位置前馈网络(position-wise Feed-Forward Network,FFN)。注意力在序列上全局作用;FFN 则独立地、逐 token 相同地施加:
它的标志性特征是隐藏维度扩张。输入维度是 的话,第一个投影 把它扩到 ;经过非线性的 ReLU 激活后,第二个投影 再映射回 。
这个 扩张因子对参数量有惊人的影响。账可以算得很清楚:注意力子层的四块矩阵 各是 ,共 个参数;FFN 的两块矩阵 和 ,共 。于是 ——在标准稠密 Transformer 里,大约三分之二的模型参数住在 FFN 块里。对一个 700 亿参数的模型,其中数百亿权重就在 和 这两块矩阵里。这个「注意力贵在内存、FFN 贵在参数」的失衡,正是第 9、10 章各种并行切分策略的重要线索——切参数,主要就是在切 FFN。
现代模型给这个子层换了几样零件,但骨架没变。激活函数从 ReLU 换成 GELU(高斯误差线性单元,GPT 系)或 SwiGLU(LLaMA 系),后者把单一线性层换成「门控 + 两路投影」的组合,本质仍是两层夹一个非线性。也有模型把隐藏维度扩张比例从 调到 (如 GPT-3 的 )——扩张比例是架构设计的自由旋钮。不管怎么拧,FFN 都是逐 token、与序列内其他 token 无关的,这一属性让它在并行策略里特别好切。
8.6 层堆叠与架构家族
单个 Transformer 块 = 多头自注意力子层 + 前馈子层,每层外面都包着残差连接(residual connection)和层归一化(layer normalization)。残差连接让梯度能绕过子层直接回传,几十上百层的堆叠才不至于梯度消失;层归一化则稳定每层的数值分布。两者合起来,是「堆得深」的前提。原始论文把归一化放在残差之后(post-norm),现代大模型(GPT-2 之后、LLaMA)多把归一化放到残差分支之前(pre-norm)——位置不同,训练稳定性差异显著,这也是一个至今仍在被精细调节的设计点。完整模型就是把许多这样的块顺序堆叠起来:
现代 LLM 堆叠几十到上百个块。粗略估算:一个块约 10 亿参数,80 层就有约 800 亿参数。经验上的深度在 30–100+ 层之间,宽度 从 768(BERT-base)到上万(千亿级模型)——深度与宽度是架构设计里最经典的一对旋钮。
前面讲的基本组件——嵌入、注意力(带不带掩码)、FFN——能组装成三种架构家族,各自服务不同的目的。
8.6.1 仅编码器模型
这类模型堆叠无掩码的自注意力块。每个 token 都能双向关注所有其他 token,编码器因此为完整输入构建了极其丰富的表示。这让仅编码器模型非常适合需要深度理解的任务:情感分析、文本分类、语义搜索。原型代表是 BERT。如果你已经读懂了 8.3.2 节,这里会觉得很熟悉——掩码语言建模的「双向理解」,配的正是「无掩码注意力」的编码器。
8.6.2 仅解码器模型
这类模型只用掩码自注意力。每个 token 只能关注它的前驱,由此实现自回归文本生成。顶部的线性投影加 Softmax 层,把最终隐藏状态转成词汇表上的概率分布,再从中采样出下一个 token。原型代表是 GPT-3、GPT-4 和 LLaMA 家族。今天,这是大规模生成式 AI 的主导架构——你平时用到的每个聊天模型,几乎都属于这一类,对应 8.3.1 节的因果语言模型范式。
8.6.3 编码器-解码器模型
这是 2017 年原始论文里 Transformer 的本尊设计,面向机器翻译、摘要这类序列到序列(sequence-to-sequence)任务。编码器堆栈读完整条输入序列,产出一组丰富的上下文表示 ;解码器堆栈通过交叉注意力(cross-attention)利用这些编码器表示,再配合自身的掩码自注意力,一次一个 token 地生成输出序列。原型代表是 T5。交叉注意力与自注意力的区别就在键和值的来源:自注意力的 、 来自自己,交叉注意力的 、 来自编码器。
8.7 生成输出
穿过所有 Transformer 层后,最后一个块吐出一个稠密隐藏向量 。这个向量编码了模型已经算出的全部上下文,但还得转回人类可读的词。这一步包含三步。
步骤 1:线性投影到 logits
隐藏向量乘一个大投影矩阵 (常常与嵌入矩阵 权重绑定,见 8.3.5 节):
结果是 个原始分数(logits),词汇表里每个词一个。logit 是 150,说明模型认为这个词极可能;logit 是 ,说明极不可能。logits 是「未归一化的概率」——数值越大越可能,但还不能直接当概率用。
步骤 2:Softmax 到概率分布
原始 logits 用 Softmax 转成正式的概率分布:
这保证所有概率非负、总和恰好为 1,给出一个覆盖整个词汇表的干净分布。指数函数还把 logits 之间的差距放大了——这正是模型「自信」的来源。
步骤 3:解码 / 采样
有了概率分布,就要选下一个 token。两种主流策略:
- 贪心解码(greedy decoding): 永远选概率最高的词。简单、确定,但容易产出重复、机械的文本。
- 采样(sampling): 把概率当成加权骰子,从排名靠前的候选中抽样。引入变数与创造力,产出我们期待现代 LLM 给出的那种更自然、更多样的输出。
采样在实践中很少直接对着裸概率分布:温度(temperature)缩放 logits 的陡峭程度,top-k / top-p 先砍掉低概率候选再归一化。这些旋钮直接控制生成文本的「胆子」——贪心像照本宣科,高温采样像放飞自我。对系统工程师还有一个基本事实:整个生成过程逐 token 串行,每个 token 都要走一遍完整网络——这正是第 11 章推理系统要面对的基本现实。
先埋一个伏笔:KV cache
自回归生成是逐 token 的:要生成第 个词,模型理论上要重算前 个词的注意力。聪明的工程师立刻会发现浪费——第 步明明已经算过第 个 token 的键和值了,为什么不留着复用?这正是 KV cache 的由来:推理时把每一步算出的 、 缓存下来,后续步骤只算新 token 的 query,拿缓存里的 、 做注意力。代价是缓存随序列长度线性增长、持续吃显存。它是第 11 章推理系统的核心议题,这里先打个照面。
8.8 分布式训练为什么是必然的
把 Transformer 的完整计算图走完——从分词、嵌入,经自注意力与 FFN 层,到 logit 投影和采样——现在可以精确回答:为什么在当代规模下训练这些模型,必须靠分布式基础设施。
先给单个 Transformer 层的显存记账:
- 模型权重必须存进 GPU 显存;
- 梯度和权重一样大,反向传播要维护一份;
- 优化器状态(比如 Adam 的一阶、二阶矩估计)再叠加好几个权重的倍数;
- 中间激活(forward pass 的中间结果)要为梯度计算保留。
拿 800 亿参数粗算一笔:权重用 FP16 存是 160 GB,梯度再来 160 GB,Adam 优化器状态(每个参数 12 字节的 FP32 一阶/二阶矩)约 960 GB——光这几项就超过 1 TB,还没算激活值。单张 H100 的 80 GB 显存连零头都装不下。这不是「加一张卡就完事」的问题,而是一个结构性约束:单设备的算术再多,内存也装不下;分布式不是可选项,是前提。
好在 Transformer 的结构也给了分布式一条出路:它的计算高度规整(稠密矩阵乘法主导),层与层、头与头之间又有清晰的边界——不像随便一个递归网络那样拧成一团。怎么把这块大饼切开、分到成百上千块 GPU 上、再让它们步调一致地同步,是第 9 章(数据并行)与第 10 章(模型并行与专家并行)要回答的工程问题,配套的还有集合通信库和各类内存优化手段。这里只算了训练;推理(第 11 章)又是另一本账——而且这本账里,8.7 节埋下的 KV cache 会一跃成为主角。
这一章把账本交到了你手里。接下来的章节,教你如何把它摊到整个机房。
延伸阅读
- Transformer 原始论文:Ashish Vaswani 等, Attention Is All You Need, NeurIPS 2017(arXiv:1706.03762)。本章的缩放点积注意力、多头、掩码、位置编码正弦公式都出自这里。
- 阅读指引:Harvard NLP, The Annotated Transformer——逐行注释的 PyTorch 实现,配合原文阅读。
- 官方文档:Hugging Face, transformers 文档(
pipeline()、模型仓库 Model Hub;pipeline的预处理/推理/后处理三阶段设计见官方教程与《NLP with Transformers》一书)。 - 子词分词:Rico Sennrich 等, Neural Machine Translation of Rare Words with Subword Units, ACL 2016(BPE 的原始出处);BERT 的 WordPiece 见 Jacob Devlin 等的 BERT 论文。
- RoPE:Jianlin Su 等, RoFormer: Enhanced Transformer with Rotary Position Embedding, 2021(旋转位置编码的原始出处,LLaMA 等主流模型的默认位置编码)。
- FlashAttention:Tri Dao 等, FlashAttention: Fast and Memory-Efficient Exact Attention with IO-Awareness, NeurIPS 2022(第 11 章推理系统会展开的注意力系统优化代表作)。
- KV cache 前置参考:自回归推理的 KV 缓存机制见第 11 章;通俗讲解可参考 Hugging Face 博客 What Is a KV Cache?。