第 16 章 · 序列与 Transformer

为什么需要注意力

从这一章起,我们正式向大模型进发。但在拆零件之前,先解决一件更要紧的事:别让知识点散成一地。 本章分两段走:先说明序列为何成为新难题、旧办法为何不够,由此引出注意力(attention); 再拿一句诗和一张贯穿第 16~22 章的总路线图,把“喂给它文本 → 它怎么训练 → 它怎么推理”从头到尾走一遍。

路线图 · 你在这一段的哪一站

这 7 章不是七个独立话题,而是一条流水线上的七段。本章先说明为何需要注意力,再给全景和一个完整例子。

读完这一章,你会明白

  • “序列”这种数据为什么对前面的网络是个难题,两种朴素做法各自的硬伤(信息瓶颈 / 传话衰减);
  • 注意力的一句话核心:让每个词直接看全局,自己决定关注谁;
  • 一眼看懂从文本到大模型的完整流水线,以及每一段分别在后面哪一章展开;
  • 跟着一句诗的例子,看模型怎么被喂进去、怎么训练、又怎么自己接下去(推理);
  • 理清一个到处出现、却各有所指的词——“上下文”到底在说什么。

1. 新挑战:句子是一串会互相影响的词

一句话由许多 token(可以先理解成“词”或“字”)按顺序组成。 它有两个让旧网络头疼的特点:长度不固定(有的句子三个词,有的三十个), 以及词之间有关系(谁修饰谁、谁指代谁)。固定大小的 MLP 一次只吃固定长度的向量, 天然不适合这种“弹性又互相纠缠”的输入。

2. 两种老办法,各有硬伤

老办法一:把整句话压成一个向量。 先把所有词的信息硬塞进一个固定大小的向量,再交给前面学的 MLP。问题是:句子越长,这个向量就越“挤”,细节被严重压缩——这叫信息瓶颈

老办法二:按顺序一个一个传,也就是上一部分的 RNN。 它用隐藏状态把“记忆”一路往后递(第 14 章)。 思路很自然,但我们已经看到它的两个硬伤:

LSTM(第 14 章)用门控缓解了“失忆”,但“串行慢”始终没解决。我们真正想要的,是一个 既能一步连接远处、又能并行的新思路。

3. 真正的难点:相关的词,可能离得很远

看这句话:

小明把放在桌子上,因为太重了。

“它”指的是“书”还是“桌子”?要判断,模型必须把“它”和前面的“书”联系起来—— 可它们之间隔了好几个词。难点不在于词多,而在于“该关联的词常常离得很远”。 按顺序传递的办法,在这种长距离依赖上特别吃力。

4. 注意力的核心想法

注意力(attention)换了个思路,简单得近乎暴力:不要再一站站传话了, 让每个词直接去看序列里所有的词,然后自己决定该重点关注谁。 “它”可以一眼扫过全句,发现自己和“书”最相关,于是把注意力大部分放在“书”上。

由此自然得到这样三步走:

  1. 都看一眼:让“它”和句子里每一个词都照个面;
  2. 打个相关分:给每次照面打个分,“它”和“书”最搭 → 高分,和“桌子”一般 → 低分;
  3. 按分数融合:分数高的词多吸收一点内容,分数低的少吸收一点,把大家的信息加权平均成“它”的新含义。

这三步就是注意力的全部骨架。此处不必追究细节——只要记住这个“先打分、再按分数加权平均”的味道, 下一章我们会把每一步都换成具体的算法和数字。

没有注意力:像传话游戏,远距离信息逐跳衰减 小明 桌子 因为 有注意力:“它”直接看全句,把注意力放在最相关的“书”上 小明 桌子 因为

上:信息沿链条逐跳衰减。下:“它”一步直达全句,粗线表示它把更多注意力分给了“书”。

两个生活类比

开会:一个人发言前,先扫一眼全场,决定主要听谁的、参考谁的,而不是只听旁边一个人耳语转述。
查资料:带着一个查询(query),扫过所有资料的标题(key),挑出最相关的几份,重点读它们的内容(value)。

一句话记住

注意力的本质,不是“更复杂的矩阵运算”,而是赋予每个词一种能力:主动地、按相关性,把注意力分配到序列里所有其他词上。

注意力只是整机里的一环

上面四节回答的是“为什么需要注意力”。接下来用一句诗,把 tokenizer → embedding → Transformer(含注意力) → 输出层 这条完整流水线走一遍——后面几章会沿这条路逐站拆开。

5. 先把整条流水线走一遍(喂它一句诗)

很多人读大模型这几章会“越读越散”:注意力、Transformer、训练、采样、并行……像一地零件,不知道怎么拼成一台机器。 前面四节已经说明为什么需要注意力;这一节把整机跑一遍:拿一个最小的例子,把“喂文本 → 训练 → 推理”从头到尾走通。 此处不必追究每一步的内部细节——只要记住顺序每一步在哪一章展开。这就是那张能把后面几章串起来的“地图”。

一段文本「床前明月」
切字·编号tokenizer
查表成向量+ 位置
互相打量注意力·Transformer
下一个字概率LM Head
挑一个字「光」

一次“前向”:一段文本进去,出来的是“下一个字该是谁”的概率。训练和推理,都建立在这条前向之上——下面逐段看。

例子:我们只教它背一句诗

把喂给模型的全部“课本”设成一句诗:「床前明月光」(《静夜思》第一句)。 模型的任务朴素到极点:看着前面几个字,猜下一个字。只要它学会了,就能自己把这句诗背出来、接下去。 真实大模型的“课本”是整个互联网,任务却一模一样,只是规模天差地别。

① 喂进去:先把文本切成字、编成号(tokenizer)

模型不认字,只认数字。第一步就是把这句诗切成一个个字,再给每个字发一个固定的号码(id):

id 号码01234

这张“字 ↔ 号码”的对照表叫词表。于是「床前明月」就变成了一串数:[0, 1, 2, 3]

这一步 = 第 19 章tokenizer;真实大模型切的是“子词”而非单字,原理一样(第 20 章 BPE)。

② 每个号码查成一串数,并标上“第几位”(embedding + 位置编码)

号码本身没有含义(2 不比 1“大”)。所以再拿号码去查一张大表,把每个字换成一串数(词向量)—— 这串数就是这个字的“意思坐标”,意思相近的字,数也相近。同时再给它标上“这是第几个字”(位置编码), 否则“明月”和“月明”在模型眼里会一模一样。

床 → [0.2, −0.5, …] · 前 → [0.9, 0.1, …] · 明 → [−0.3, 0.8, …] · 月 → [0.4, 0.4, …] (示意)每个字变成一串数,再各自加上“第 0/1/2/3 位”的位置指纹

这一步 = 第 19 章embedding 查表 + 第 18 章位置编码;这些向量为什么能带“语义”,见第 15 章第 20 章

③ 让每个字互相打量、反复加工(注意力 + Transformer)

这是整机里最核心的一步,也是第 4 节注意力思路的具体实现。每个字都回头看一眼前面所有的字, 按“和我有多相关”给它们打分,再把大家的信息加权融合进自己——这就是注意力。 比如“月”会更多地参考“明”。这样融合一轮叫一层,反复堆很多层(每层还夹着一些常规加工),字的表示就越来越“懂上下文”。

这里第一次出现“上下文”

当模型处理“月”时,它能看到的前文——“床、前、明”——就是“月”的上下文。 一个字能不能看到、能看到多远,全在这一步决定。(“上下文”这个词后面还会以别的意思出现,本章末尾专门列一张表理清。)

这一步 = 第 17 章注意力 + 第 18 章Transformer Block(堆叠、残差、归一化、前馈)。

④ 吐出“下一个字”的概率(LM Head)

第 ③ 步加工完,每个位置都得到一串新的数(向量)——这串“带着上下文的数”, 既是注意力那几层算出来的输出,又正好当作这一步输出层的输入 (就像 MLP 里,隐藏层算出的那排数,就是下一层的输入)。最上面再接一个输出层, 把最后位置那串数投影到整张词表,给每个候选字打分,过 softmax 变成概率。 假设现在喂进「床前明月」,一个刚初始化、还没训练的模型给出的概率大概是这样(乱猜,谁也不突出):

下一个字候选光(正确答案)
模型给的概率0.240.190.220.230.12

正确答案“光”只拿到 0.12——模型此刻还什么都不会。输入一串字,输出下一个字的概率:这就是“输入输出”的全部。

这一步 = 第 19 章LM Head(输出层 + softmax)。到这里,一次“前向”就走完了。

小结:前面 4 步合起来,就是模型的“输入 → 输出”

输入是一串字([床,前,明,月]),输出是“下一个字是谁”的一排概率。 模型自始至终只会这一件事。接下来的“训练”和“推理”,都只是反复使用这条前向——一个用来改参数,一个用来写下文

⑤ 怎么训练:对答案、算错、往回改一点点

模型一开始把“光”只猜到 0.12,错得离谱。怎么让它变准?关键是:正确答案根本不用人标—— 原文里“床前明月”后面本来就跟着“光”。这就是天然的答案(叫自监督)。有了答案,训练就是一个循环:

  1. 前向:走一遍上面 ①~④,拿到概率(“光”=0.12)。
  2. 算错得多离谱(损失):只看它给正确答案的概率,用交叉熵 −log(0.12) ≈ 2.1。给对的概率越低,这个数越大。
  3. 反向传播:把这个“错”从输出层一路反着传回去(第 6 章),给模型里每一个“可以被调的数”都算出一个梯度——也就是“往哪边挪、挪多少”的建议。
  4. 更新:每个数都按同一条规则挪一小步:新值 = 旧值 − 学习率 × 梯度(第 5 章)。挪完,“光”的概率就大了一点点。

把这个循环在这句诗上重复很多遍,概率就会肉眼可见地往正确答案集中、损失一路下滑:

「床前明月」→ ?给“光”的概率损失 −log(概率)
刚开始(乱猜)0.12≈ 2.1
练了一会儿0.55≈ 0.6
练久了0.90≈ 0.1

“练一次挪一点”,重复亿万次(真实大模型),那些查表向量和注意力矩阵就从随机数,长成了“懂这门语言”的样子。

这一步 = 第 4 章损失 + 第 5 章梯度下降 + 第 6 章反向传播;“答案自带”的自监督见第 19 章第 20 章

模型里有哪些参数?与 MNIST 有何异同?

“参数”就是模型里所有可以被训练调整的数。 语言模型里主要有这么几类(先有个印象即可,后面每一类都有专章):

  • 查表向量(嵌入表):每个字对应的那串数(第 ② 步)——第 19 章;
  • 注意力里的几个矩阵:决定“每个字该拿什么去问别人、给自己挂什么标签、被选中后交出什么内容”(第 ③ 步)——第 17 章;
  • 每层的小网络(前馈)和归一化的缩放系数(第 ③ 步)——第 18 章;
  • 最后的输出层:把向量投影成“下一个字的概率”(第 ④ 步)——第 19 章

关键:不管哪一类,更新方式一字不差,全是那一条 新值 = 旧值 − 学习率 × 梯度 它和 MNIST 那个手写数字网络本质完全一样——唯一的区别是:MNIST 那张网只有“权重 + 偏置”两种参数, 而语言模型多了“嵌入表、注意力矩阵、归一化系数”这些新种类;但每一种怎么算梯度、怎么挪,和 MNIST 完全相同。 (真实大模型爱用 Adam 这种更聪明的优化器,第 8 章,但那只是“挪得更讲究”,并没改变“算梯度 → 挪一步”这个套路。) 一张完整的参数清单,见第 19 章

⑥ 怎么推理:自己一个字一个字接下去(自回归)

训练好之后,怎么让它“写字”?给它一个开头(叫 prompt),让它反复走前向,每次挑出概率最高的字,接到末尾,再喂回去。 拿开头“床前”举例:

第几步喂进去的上文模型最看好的下一个字接完变成
1床前明 (0.88)床前
2床前明月 (0.86)床前明
3床前明月光 (0.90)床前明月

把“猜出来的字”接回输入、再猜下一个——这个循环叫自回归。你看到 ChatGPT “一个字一个字往外蹦”,就是它。

这一步 = 第 19 章自回归生成;至于是“死板挑最高”还是“带点随机”(temperature/top-k/top-p),也在第 19 章。

⑦ 再往上:放大成大模型、以及怎么用它

到第 ⑥ 步,一个“会背诗、会接话”的迷你语言模型就齐活了。剩下的几章,是把这台小机器往上推:

一张总表:每个环节分别在哪一章

这就是开头那句“流程里每个地方分别在哪”的答案。读后面任何一章卡住时,回到这张表对一下坐标:

流程环节在这个例子里干了啥哪一章细讲
① 切字·编号(tokenizer)「床前明月光」→ [0,1,2,3,4]19 · BPE 20
② 查表成向量 + 位置每个 id → 一串数,并标上第几位嵌入 19 · 位置 18
③ 互相打量(注意力)每个字按相关性看前文、融合17
③ 反复加工堆叠(Block)残差 / 归一化 / 前馈,堆很多层18
④ 出下一个字概率(LM Head)给词表每个字打分 → softmax19
⑤ 对答案算错(损失)和真下一个字“光”比,交叉熵4 · 19
⑤ 往回改参数(反向传播)一路更新到注意力矩阵、嵌入、输出层5 · 6
⑥ 自己接龙(自回归推理)把猜出的字接回去,再猜下一个19
⑦ 放大成大模型参数 / 数据 / 算力一起放大20 · 21
⑦ 用好它提示 / RAG / 工具 / Agent22

顺便说清:“上下文(context)”到底指什么

“上下文”这个词在后面会反复出现,但它在不同地方指的东西并不一样。下表一次性理清:

说法到底指什么在哪一章
上文 / 上下文(注意力里)当前这个字能回头看到的前面那些字(“月”的上下文 = 床、前、明)17
上下文窗口 context window / context_size一次最多能塞进去多少字/token(窗口多大)19
长上下文 long context把窗口做得很大(几十万 token),能一次读一本书20 · 21
上下文学习 in-context learning不改任何参数,只靠你在输入里给的例子/说明,让它临场学会做题(few-shot)22
KV cache 缓存的“上文”生成时把已经算过的前文的中间结果存起来复用,省得每步重算21

同一个词,五种意思。记住:前三种都在说“能看到多少前文”,第四种是“靠前文临场学”,第五种是“把前文的计算缓存起来”。

带着这张地图往下读

流水线地图到此为止。前面四节说明了为什么需要注意力;这里用一句诗把整机跑通。后面各章会沿这条路逐站展开——下一章从 Q、K、V 算起。每章开头那条路线图,会一直提醒你走到哪一站。

小结

  • 语言是序列:长度可变、词与词互相关联,固定大小的 MLP 天然不适合。
  • 把整句压成一个向量 → 信息瓶颈;按顺序逐个传递 → 传话式的远距离衰减。
  • 真正的难点是“相关的词可能离得很远”(如代词指代)。
  • 注意力让每个词直接看全局、按相关性自己分配关注,从根上解决了长距离依赖。

动手与思考

问题 1:为什么说“按顺序逐个传递”处理长句子有先天劣势?

因为信息像传话游戏一样要经过很多中间步骤,每一步都可能被改写或稀释,等传到很远的位置,最初的信息早已模糊。长距离依赖最容易在这种方式里丢失。

问题 2:用一句话概括注意力解决了什么核心问题?

让每个词都能直接“看到”序列里所有其他词,并按相关性自主决定关注谁,从而绕开了长距离信息传递的衰减问题。

先剧透下一章的“唯一重点”

如果整章你只带走一句话,请带走这句:注意力的输出,就是对所有词做一次“加权平均”。 权重代表“相关性”——越相关的词,在这次平均里占比越大。下一章那些 Q、K、V、softmax, 全都只是在回答一个问题:这组加权平均的权重,到底该怎么算? 带着这个念头去看,会顺很多。

想法很美,但“直接看全局、决定关注谁”到底怎么用数字算出来? 下一章就把这台机器拆开:Q、K、V、打分、softmax、加权求和,一个都不少。