第三部 · 语言第 8 章 / 14

每个词都能看见其他词

注意力机制是整门课的心脏。这一章把 Transformer 拆开,看它怎样让一个词根据上下文改变自己的含义,以及它怎样一个 token 一个 token 地写出文字。

主线 7 分钟 · 深入 6 段 · 实验 2 个
一个词回头看其他词。
一个词回头看其他词。

「我早上吃了一个苹果。」「苹果昨晚发布了新手机。」两句话里的「苹果」是同一个 token,上一章讲的嵌入层会给它同一个向量。但它们的意思显然不同。模型要怎样知道该把哪个「苹果」理解成水果?

答案是看周围的词。第一句有「吃」,第二句有「发布」和「手机」。一个好的语言模型必须让每个词的表示根据上下文改变:进入模型时「苹果」是一个固定的向量,几层之后它应该变成「水果的苹果」或者「公司的苹果」。做这件事的机制叫注意力,2017 年的 Transformer 架构把它变成了一切的核心。这一章的目标是让你看懂它,不需要线性代数,只需要跟着一个比喻走。

注意力:每个词发出一个问题

想象一个班级,每个词是一个学生,坐成一排。现在轮到「苹果」发言,它想弄清自己在这句话里是什么意思。它做了三件事。

它先发出一个查询(query):「谁能告诉我,我是水果还是公司?」

每个同学,包括它自己,都举着一张(key),写着自己能回答什么类型的问题:「吃」举的牌子上写着「我和食物有关」,「发布」写着「我和商业行为有关」,「一个」写着「我是量词」。

「苹果」拿自己的查询和每张键比对,算出一个相关度。「吃」的键和它的查询很匹配,得分高;「一个」的键不太相关,得分低。把所有得分用 softmax 变成一组加起来等于 1 的权重,就是「苹果」对每个词的注意力

最后,每个同学还准备了一份(value),是它愿意贡献的信息。「苹果」按注意力权重把所有同学的值加权求和,得到一个新向量。因为「吃」的权重大,新向量里混入了大量「食物」的信息。经过这一步,「苹果」的表示已经偏向了水果。

每个词同时做这件事:每个词都发出查询,都提供键和值,都从所有词那里加权收集信息。这就是自注意力:序列里的每个位置都在看序列里的所有位置,包括自己。一层之后,每个词的向量都吸收了上下文;再来一层,它们吸收的是已经吸收过上下文的向量,关系越来越复杂。

早上 吃了 一个 苹果 0.050.080.620.100.15 「苹果」发出查询:我是水果还是公司? 每个词举着键:「吃了」:我和食物有关 相关度 → 权重:加起来等于 1 新的「苹果」= 0.05·值(我) + 0.08·值(早上) + 0.62·值(吃了) + 0.10·值(一个) + 0.15·值(苹果) 按权重把所有词的「值」加起来:「食物」的信息占了大头,表示偏向水果 每个词同时做这件事,一层之后每个词都吸收了上下文;叠几十层,关系越来越复杂。 Attention(Q,K,V) = softmax(QKᵀ/√d)·V
「苹果」的查询与每个词的键比对得到权重,再按权重把所有词的值加起来。

注意力的数学形式是一行:

$$\text{Attention}(Q, K, V) = \text{softmax}!\left(\frac{QK^\top}{\sqrt{d_k}}\right)V$$

把上面的比喻对上去。输入是一串向量 $X$(每个词一行)。三个矩阵 $W_Q, W_K, W_V$ 是可训练的参数,把每个词的向量分别变换成它的查询 $Q = XW_Q$、键 $K = XW_K$、值 $V = XW_V$。$QK^\top$ 一次算出所有词对所有词的查询与键的点积,也就是相关度打分。除以 $\sqrt{d_k}$ 是为了让分数的尺度不随向量维度膨胀,否则 softmax 会把权重挤到极端。softmax 逐行把分数变成加起来为 1 的权重。最后乘以 $V$,就是按权重对所有词的值加权求和。

注意这里面没有任何「语法规则」,也没有任何关于「代词该看名词」的先验。三个矩阵一开始是随机的,模型为了预测下一个词、在训练中逐渐学到了让注意力落在有用位置上的变换。语法关系是被逼出来的副产品。

另一个值得注意的性质:这个计算对序列里的每个词是并行的。以前的循环网络必须一个词一个词地顺序处理,处理第一千个词要等前九百九十九个算完;注意力一次矩阵乘法算完全部,这是 Transformer 能用几万块 GPU 并行训练、从而能做到今天这个规模的直接原因。代价是计算量随序列长度的平方增长,长上下文的技术难题多半来自这里。

在 Transformer 之前,处理序列的主流是循环神经网络(RNN)及其改进版 LSTM。它们的思路很自然:一个词一个词地读,每读一个词就更新一个「记忆」向量,读完整句话,记忆里应该装着句子的含义。

它输在两个地方。第一是记忆的瓶颈:不管句子多长,所有信息都要挤进一个固定大小的向量,读到第一百个词时,第一个词的信息已经被冲淡到几乎不剩。人们加了各种「门」来控制记忆的写入和遗忘,改善了,但没有根除。第二是无法并行:第一百个词的处理必须等前九十九个算完,训练时几万块 GPU 只能排队。

注意力最初是作为 RNN 的补丁出现的(2014 年,用于翻译):让解码器在生成每个词时回头「看」输入句子的所有位置,而不是只依赖那个被压缩的记忆。2017 年的论文做了一个大胆的删减:既然注意力这么好用,干脆把循环去掉,只留注意力。标题里的「你所需要的一切」说的就是这个。

结果是记忆瓶颈消失了(每个词都能直接看到每个词,不经过压缩),并行也有了。代价是计算量随长度平方增长,以及需要位置编码来补回顺序。近几年出现了一些试图兼得两者的新架构(状态空间模型等),在长序列上有优势,但截至本书写作,Transformer 仍是主流。

多头与位置

两个补充让这个机制真正好用。

多头。一个词和其他词的关系不止一种:语法关系、语义关系、指代关系、位置关系。让一组查询键值同时表达所有这些关系太勉强,所以 Transformer 用多组,每组叫一个「头」,各自学习关注不同的东西,最后把各头的输出拼起来。事后观察训练好的模型,确实能看到有的头专门看前一个词,有的头专门看句首,有的头专门追踪指代。

位置。上面的机制有一个问题:它对词的顺序完全无感。「猫追狗」和「狗追猫」,每个词的查询、键、值都相同,注意力的结果也相同。解决办法是在每个词的向量上加一个表示位置的向量,让「第一个位置的猫」和「第三个位置的猫」在进入注意力之前就已经不同。位置编码有好几种做法,但目的都一样:把顺序信息塞回一个本身不在乎顺序的机制。

注意力对序列里每一对词都要算一次相关度。一千个词是一百万对,一万个词是一亿对,十万个词是一百亿对。计算量和显存都随长度平方增长。这就是为什么早期模型的窗口只有几千 token,也是为什么「上下文窗口」曾经是各家竞争的焦点。

缓解它的办法大致三类。算得更聪明:不改变数学结果,但重新安排计算顺序以减少显存读写,这一类方法让同样的硬件能处理几倍长的序列。算得更少:只让每个词看附近的词、或者看少数「摘要」位置,牺牲一点精度换长度。换架构:用状态空间模型等不依赖两两比较的结构,计算量随长度线性增长,在超长序列上有优势,但在语言任务上还没有全面取代注意力。

生成时还有另一笔账。每写一个新 token 都要把整个序列重新算一遍吗?不用:前面的词的键和值在上一步已经算过了,把它们缓存起来,新 token 只需要算自己的,再和缓存比对。这叫 KV 缓存,是长对话能实时响应的关键。它的代价是显存:一个长上下文的缓存可能有几十 GB,这也是长上下文的调用更贵的直接原因。

以一个典型的几十亿参数模型为例,参数大致分布在四处。

嵌入层:词表大小乘以向量维度。十万词表、四千维,就是四亿参数。它把 token 变成向量,最后的输出层常常复用同一张表把向量变回 token。

注意力:每层四个矩阵(查询、键、值、输出),每个是维度的平方。四千维时每层约六千万参数,乘以层数。

前馈网络:每层两个矩阵,中间维度通常是向量维度的四倍,所以每层约一亿三千万参数,是注意力的两倍。这是模型参数最多的地方,也被认为是「知识」主要储存的地方。混合专家把这一部分复制成多份,让总参数暴涨而每次只用几份。

归一化和位置:几乎可以忽略。

这个分布解释了几件事:为什么扩大词表会显著增加参数;为什么混合专家只改前馈网络;为什么「知识编辑」的研究主要盯着前馈层。它也提醒我们,「参数」不是均匀分布的智慧,而是几种功能不同的矩阵。

一个 Transformer 模块

注意力层之后还有几个部件,合起来是一个「模块」,整个模型就是几十上百个模块叠起来。

一根线穿过几十个一模一样的模块。
一根线穿过几十个一模一样的模块。

前馈网络:注意力负责在词与词之间搬运信息,前馈网络负责对每个词单独做一次非线性变换,可以理解为「注意力收集了上下文,前馈网络消化它」。它是第六章的多层感知机,模型的大部分参数在这里,研究者认为模型的很多「知识」也存在这里。

残差连接:每个子层的输出加上它的输入,再传给下一层。这让信息可以绕过某一层直接往下走,深度网络因此可以训练到上百层,第六章「深入」里提过它。

层归一化:把每一层的向量重新缩放到一个稳定的范围,防止数值在几十层之后失控。

一个模块就是:注意力,加残差,归一化;前馈,加残差,归一化。把这个模块复制几十份叠起来,前面接嵌入层,后面接一个把向量变回词表概率的输出层,这就是一个完整的语言模型。GPT 系列、Llama、Qwen、DeepSeek、Claude,架构上都是这个东西的变体。

一个模块 · 复制几十份叠起来就是整个模型 自注意力 相加 + 层归一化 前馈网络 相加 + 层归一化 ↑ 下一个模块 残差:绕过去直达 残差:绕过去直达 词与词之间搬运信息 每个词单独「消化」;大部分参数和知识在这里 让数值不失控 GPT、Llama、Qwen、DeepSeek、Claude,架构上都是它的变体。
一个 Transformer 模块的四个部件,以及绕过它们的残差连接。

2017 年的原始 Transformer 是为翻译设计的,有两半:编码器读入源语言句子,让每个词看到全句;解码器生成目标语言,每个词只能看到自己前面的词(不能偷看后面),同时可以看编码器的输出。

后来出现了三条路线。只用编码器(如 2018 年的 BERT):每个词看到全句,擅长理解和分类,但不擅长生成。编码器加解码器(如 T5):保留原始结构。只用解码器(如 GPT 系列):每个词只看前面,天然就是「预测下一个词」的语言模型。

只用解码器的路线最终成为主流,有几个原因。它的训练目标最简单,和「语言模型」的定义完全一致,不需要设计特殊任务。它天然适合生成,而生成能覆盖理解(要分类,就让它生成「正面」或「负面」)。它的规模扩展得最顺,规模定律在它身上最干净。还有一个工程原因:只看前面的词意味着生成时可以缓存已经算过的键和值,每写一个新词只需要为它计算一次,这叫 KV 缓存,是长对话能实时响应的关键。

所以当你听到「GPT」,那三个字母是「生成式预训练 Transformer」,「生成式」指的就是这条只用解码器的路线。

生成:一次一个 token

理解了模型的内部,最后看它怎样写出一段回答。

过程是自回归的:把提示词切成 token 送进模型,模型输出一个对「下一个 token」的概率分布;从分布里选一个,接在后面,再把整个序列送进去,得到再下一个的分布;如此重复,直到选中一个表示「结束」的特殊 token。模型每次只产生一个 token,一段五百字的回答意味着几百次完整的前向计算。你在聊天界面看到文字一个个蹦出来,不是打字效果,是它真的在一个一个算。

「从分布里选一个」这一步有几种做法。贪心:永远选概率最大的,结果稳定但容易重复、单调。采样:按概率随机抽,越可能的越容易被抽中,结果有变化但也可能抽到低概率的怪词。中间的调节旋钮叫温度:温度低,分布被压得更尖,接近贪心;温度高,分布被压平,更随机。写代码用低温度,写诗用高温度。此外还有只在前 K 个候选里抽(top-k)、只在累积概率达到 P 的候选里抽(top-p)这些限制随机性的办法。

「从分布里选一个」的方式有好几种,它们各有用途。

策略 做法 优点 缺点 适合
贪心 每步取概率最大 稳定、可复现 单调、易重复、会错过整体更好的句子 短答案、事实性回答
束搜索 同时保留最好的几条候选序列 整体更优 更单调,长文本会「安全得无聊」 翻译、摘要
温度采样 按调整过的概率随机抽 多样 温度高时会离谱 创作、头脑风暴
Top-k 只在前 k 个候选里抽 去掉长尾的怪词 k 固定,分布尖时仍可能抽到差的 通用
Top-p(核采样) 只在累积概率达到 p 的候选里抽 自适应候选数 需要调 p 今天最常用的默认

实际产品通常组合使用:温度 0.7 加 top-p 0.9 是常见默认。当你在 API 里看到 temperaturetop_p 两个参数,它们对应的就是这张表。

这一步有一个重要的推论:模型没有「计划」。它不会先想好整段回答再写,而是每一步只决定下一个 token。回答的结构感、逻辑性,全部来自它在训练中见过太多有结构、有逻辑的文本,以至于「按概率续写」自然就带出了结构。这既是它惊人能力的来源,也是第十章要讲的「幻觉」的根源:它在每一步选的都是「最像会出现在这里的词」,而不是「最真实的词」。

带走一句话

Transformer 让每个词根据与所有其他词的相关度加权吸收信息,一层层叠加,把固定的词向量变成随上下文变化的表示。生成时,它一次只预测一个 token,靠温度和采样在「稳定」与「多样」之间取舍。

自测先自己想,再点开答案
  1. 用查询、键、值的比喻解释:模型怎样知道「苹果」在「苹果发布了新手机」里指公司?

    答案

    「苹果」发出查询,「发布」和「手机」的键与它高度相关,注意力权重集中在它们身上,于是「苹果」的新向量混入了大量「商业」「电子产品」的信息,表示偏向公司。这个判断来自上下文,不来自「苹果」这个词本身。

  2. 注意力机制本身不在乎词的顺序,那模型怎么区分「猫追狗」和「狗追猫」?

    答案

    靠位置编码:在每个词的向量上加一个表示位置的向量,让同一个词在不同位置进入注意力之前就已经不同。

  3. 为什么 Transformer 比之前的循环网络更容易训练到超大规模?

    答案

    注意力对整个序列的计算是并行的一次矩阵运算,而循环网络必须逐词顺序处理。并行意味着可以把计算摊到成千上万块 GPU 上,这是规模扩展的前提。

  4. 温度调到 0 和调到 2,模型的行为各会怎样?分别适合什么场景?

    答案

    温度趋近 0 时接近贪心,每次输出几乎相同,稳定但可能单调重复,适合代码、事实性回答;温度高时分布被压平,低概率的词也常被抽中,输出多样但可能离谱,适合创意写作、头脑风暴。

本章术语

自注意力Self-attention

序列里每个位置都根据与所有位置的相关度加权收集信息,从而让一个词的表示随上下文改变(「苹果」在「吃」旁边偏向水果)。对整个序列可并行计算,这是 Transformer 能扩展到超大规模的原因;代价是计算量随长度平方增长。

查询键值Query, Key, Value

注意力的三个角色:每个词发出查询(我想知道什么),提供键(我能回答什么)和值(我愿意贡献的信息)。查询与各键比对得到权重,按权重对各值加权求和。三者由三个可训练矩阵从词向量变换而来。

多头注意力Multi-head attention

同时用多组查询键值,每组(一个「头」)学习关注不同类型的关系(语法、指代、位置),最后把各头输出拼接。事后观察可见有的头专看前一个词、有的专追踪代词。

位置编码Positional encoding

注意力机制本身不在乎词序,「猫追狗」与「狗追猫」无法区分。位置编码在每个词的向量上加入表示位置的信息,把顺序塞回一个本身与顺序无关的机制。

TransformerTransformer

2017 年提出的架构,由多个模块叠成,每个模块是「自注意力 + 残差与归一化 + 前馈网络 + 残差与归一化」。前接嵌入层,后接输出层。GPT、Llama、Qwen、DeepSeek、Claude 在架构上都是它的变体。

前馈网络Feed-forward network, FFN

Transformer 模块里对每个位置单独做非线性变换的多层感知机。注意力在词间搬运信息,前馈网络消化它。模型的大部分参数在这里,研究者认为许多「知识」也存在这里;混合专家架构替换的就是它。

残差连接Residual connection

让每个子层的输出加上它的输入再往下传,信息可以绕过某层直行。2015 年提出,解决了深网络梯度消失的问题,使网络从几十层到上千层成为可能。Transformer 每个模块都带着它。

自回归生成Autoregressive generation

模型每次只预测一个 token,接在序列后再预测下一个,直到产生结束标记。一段五百字的回答意味着几百次完整计算;文字逐个蹦出来不是打字效果。模型没有「计划」,结构感来自训练语料。

采样与温度Sampling & temperature

从下一个 token 的概率分布里选词的方式。贪心永远选最大者,稳定但单调;采样按概率随机抽。温度是调节旋钮:低温压尖分布、接近贪心,高温压平分布、更随机。top-k、top-p 限制候选范围。