LESSON 19 · 卷 大语言模型

注意力机制

「它太累了」——「它」指谁?让每个词自己决定该看向哪里

第 1 站

「它」指谁?

先读两句几乎一样的话:

小猫没有过马路,因为了。
小猫没有过马路,因为了。

两个「它」,指的东西完全不同:第一句指小猫,第二句指马路。 你几乎是无意识就分辨出来了。但请注意你是怎么做到的—— 读到「它」时,你的目光回头扫了一眼前文,并且只在「小猫」和「马路」之间挑了一个, 其余的字几乎被忽略。

这个「回头看、且看得有轻有重」的动作,就是人类的注意力。 问题是:怎么让一个神经网络也学会这个动作?

第 2 站

旧方案的局限:一条太窄的门缝

卷三的终点站还记得吗?RNN / LSTM 处理句子的方式,是从左到右逐词读入, 把读过的一切不断压缩进一个固定大小的向量里,像滚雪球:

小猫没有马路h₁h₂h₃h₄h₅最终向量整句话的全部信息,必须挤进右边那个固定大小的「行李箱」。句子越长,越早装进去的东西,越容易被压变形。
图 19-1RNN 的「行李箱」:无论句子多长,都要塞进同一个固定大小的向量。
方案的局限

等网络读到「它」时,「小猫」已经是五步之前的记忆,在行李箱里被反复挤压。 句子再长一点——比如一整段话——开头的信息几乎荡然无存。 LSTM 的「阀门」缓解了遗忘,却没有解决根本问题:所有历史共用一条固定宽度的门缝。

激进一点:如果根本不压缩呢?所有词的向量都原样留在桌面上, 「它」需要谁就直接去看谁。这个方案缺什么?
第 3 站

新想法:不压缩,回头看,按分配

新方案只有三步,每一步都用的是你已经会的东西:

第一步,打分。「它」想知道每个词和自己的相关度。 卷一第 2 课说过:两个向量的点积越大,方向越一致,越「相关」。 那就让「它」的向量和每个词的向量分别做点积,得到一排分数。

第二步,变成权重。这排分数有大有小、有正有负,不好直接用。 卷二第 11 课的 Softmax 正是干这个的:把任意一排分数变成一排加起来等于 1 的比例。 比如「小猫 62%、马路 9%、累 13%、其他词分剩下的」。

第三步,按比例混合。用这些百分比对所有词的向量做加权求和, 得到一个新向量——它代表的不再是孤零零的「它」, 而是「一个主要由小猫构成、掺了一点累的它」。指代问题,就这样被算出来了。

小猫没有马路因为62%9%13%线越粗 = 分到的注意力越多
图 19-2处理「它」时的注意力分布:大头给了「小猫」,一小份给「累」——正是消解指代所需的两块信息。
第 4 站

一个问题,三个角色:Q、K、V

上一站的方案直接拿词向量互相点积,藏着一个微妙的毛病:一个词「想找什么」和「能提供什么」根本是两回事。「它」作为代词,想找的是「前文里某个具体事物」; 而「它」能提供给别的词的信息,只是「这里有个代词」。一个向量身兼两职,会互相打架。

修补的办法依然是最小的:别用原始向量直接对话, 让每个词先通过三个线性变换(卷一第 3 课的矩阵,参数可学习)生成三个分身—— 就像在图书馆里:

词向量x× W_Q× W_K× W_VQ · 查询单「我在找:前文里一个具体事物」K · 书脊标签「我这里有:一只动物,名词,主语」V · 书的内容「真正被取走混合的信息本体」
图 19-3查询单(Query)拿去和每本书的书脊标签(Key)对分数,分数高的书,取出内容(Value)来读。

于是打分规则修正为:用「它」的 Q,去点积每个词的 K; 权重算好后,混合的是每个词的 V。 三个矩阵 WQ、WK、WV 都是训练中学出来的—— 也就是说,「该注意什么」这件事本身,是模型自己学会的。

第 5 站

从「它」一个词,到整句话

第 4 站收尾时,我们已经为「它」配齐了一整套动作:用它的 Q 去点积每个词的 K 打分、用 softmax 把分数变成权重、 再照权重混合每个词的 V。漂亮——可这套动作只照顾了「它」一个词。 真实的句子里,每个词都得这样回头看一遍:「累」要找它修饰谁,「过」要找它的宾语…… 与其一个词一个词地循环,不如把「对所有词各做一遍」用矩阵一次写完

而当我们把它写到最紧凑,整套流程会坍缩成一个式子——这个式子不是我们生造的, 它正是 2017 年 Google 论文《Attention Is All You Need》的核心(3.2.1 节,Scaled Dot-Product Attention,缩放点积注意力)。 那篇论文提出了 Transformer 架构,甩开了统治十年的 RNN / LSTM;今天的 GPT、BERT、几乎所有大模型,骨架都从这里长出来:

Attention Is All You NeedAshish Vaswani · Noam Shazeer · Niki Parmar · Jakob UszkoreitLlion Jones · Aidan N. Gomez · Łukasz Kaiser · Illia PolosukhinGoogle Brain · Google Research · University of Toronto | NeurIPS 2017Abstract3.2.1 Scaled Dot-Product AttentionAttention(Q, K, V) = softmax(QKᵀ / √d̲ₖ) V(1)↑ 整篇论文的核心,就这一行这一站,我们就用前几站亲手造的零件,把它拼出来
图 19-4《Attention Is All You Need》(Vaswani 等,2017)示意。论文最有名的,除了那句口号般的标题,就是框里这个公式——它如今是所有大模型的地基。下面我们就一步步把它拼出来。

别被一堆大写字母唬住——这一行里的每个零件,你在前三站都已经亲手造过了。 下面就把上面说的「用矩阵一次写完」摊开,看这一行到底是怎么拼出来的。

关键的一步,是把所有词的零件摞成矩阵。把每个词的查询单 q 当成一行,从上到下摞起来, 就得到一个矩阵 个词就是 行);同理把所有 k 摞成 、所有 v 摞成 大写的 Q、K、V,就是上一站那些小写分身「摞起来」的整捆版本——内容半点没变,只是排好了队,好让一次矩阵乘法把全句都算了。

于是上一站那套动作,原封不动地升级成四步矩阵运算:

第一步 打分 
第二步 降温 
第三步 归一 
第四步 混合 

一步一步看,每一步到底在搬动什么:

第一步 :一次把所有词对所有词的分数都打出来。上一站「它」的 q 点积每个词的 k,得到一行分数。现在 里有 行查询、 里有 行标签,两者一乘,就同时打出 张分数表: 第 行第 格,就是「第 个词该看第 个词多少」。 (那个转置 只是把 立起来,让维度对得上、能做点积,不必深究。) 上一站图 19-2 算的,正是下面这张表里「它」那一行——现在我们一口气把每一行都算了出来:

小猫没有马路因为被看的词(K)→发出查询的词(Q)↓小猫没有马路因为629713为看得清,只点亮了「它」这一行;其余每个词也各有这样一行权重
图 19-5 一次算出整张 的分数表:每一行是「某个词该看全句各词多少」。「它」那一行的大头落在「小猫」(62),正是图 19-2 的内容——只不过现在每一行都被同时算了出来。

第二步 :给分数「降温」。这一步上一站没提,因为单看一行不明显,可一上规模就必须有。问题出在维度:论文里每个 q、k 是 维, 点积是 64 个乘积相加,数值很容易累积得很大——粗算下来分数常在 上下晃。 把 这种悬殊的分数喂进 softmax,结果几乎是 ——softmax「饱和」了,注意力变成非黑即白,只死盯一个词、其余一律不看,梯度也几乎为零、学不动。 解法很省事:整张表统一除以 ,分数缩回 的温和范围,softmax 重新变得「有轻有重」而不极端。

第三步 :把每一行变成一组百分比。降温后的分数还是有正有负的实数,不能直接当权重。对分数表的每一行各做一次 softmax(第 11 课那一套), 这一行就变成一组加起来正好等于 1 的比例——也就是图 19-5 里「它」那行的 62%、9%、13%…… 行各归一一次,整张表就成了一张干净的权重表

第四步 :照权重把内容混合出来。拿权重表去乘 (每行是一个词的内容分身)。具体到「它」这一行:用 62% 取「小猫」的 V、13% 取「累」的 V……加权相加, 得到「它」的新向量——一个主要由小猫、掺了点累构成的「它」。每一行都这么混一次, 输出就是 个被全句上下文重新润色过的新词向量。 注意:前三步只是算出「该看谁」的计划,这一步才把计划真正执行成「信息搬进了词里」; 这些新向量会顶替掉原来的词向量继续往上走。下一站把它代成具体数字,你就会看清这个「搬运」到底有什么用。

把这四步接成一条流水线,写成一行,就是 2017 年那篇论文里的原式:

从里到外读: 打分 → 降温 → 归一成权重 → 乘 混合。四步,正好对应上面四行。

值得停下来欣赏一下这个设计的两个「免费赠品」: 其一,所有词的回头看是同时发生的——矩阵一乘全算完,不像 RNN 必须逐词排队; 其二,「小猫」距离「它」是 5 个词还是 500 个词,都是一次直达,不存在传着传着丢了的问题。 行李箱被彻底扔掉了。

第 6 站

把公式代进数字:一个 2 维的小例子

公式拼好了,可一行符号终究还是抽象。这一站我们把它彻底落地: 用一个小到能用纸笔验算的例子,把 从头到尾算一遍。 为了算得清爽,每个向量只取 2 维(真实模型是 64 维)——但每一步的动作,和真实 Transformer 里发生的一模一样,只是数字小。

取句子里最要紧的三个词:小猫、累、它。回忆第 4 站——每个词过 三个矩阵, 生成 q、k、v 三个分身。为了把注意力都集中在公式本身,这里直接把算好的 2 维分身列出来 (真实模型里,这些数字是训练学出来的):

小猫  q = [0.3, 0.3]  k = [1.2, 0.0]  v = [1.0, 0.0]
累   q = [0.2, 1.5]  k = [0.0, 1.0]  v = [0.0, 1.0]
它   q = [2.0, 0.2]  k = [0.1, 0.0]  v = [0.5, 0.5]

一个小约定:这里把 v 的两个维度设计成可以「读」的——第 1 维代表「动物味」,第 2 维代表「疲惫味」。 所以小猫的 v=[1,0] 是纯动物味,累的 v=[0,1] 是纯疲惫味。等会儿看「它」最后混出的 v 落在哪, 就知道模型把「它」理解成了什么。下面我们只算「它」这一行(它该看谁、看多少),其余两行同理。

第一步 · 打分 拿「它」的查询 ,分别和三个词的 k 做点积:

它 · 小猫 = 2.0×1.2 + 0.2×0.0 = 2.4
它 · 累  = 2.0×0.0 + 0.2×1.0 = 0.2
它 · 它  = 2.0×0.1 + 0.2×0.0 = 0.2

对「小猫」的分数 2.4,把另外两个 0.2 远远甩开。为什么差这么多? 因为点积衡量的是两个向量方向有多一致——而「它」的查询,几乎和「小猫」的 key 指向同一个方向。 把这四个向量画在 2 维平面上,一眼就能看明白:

121「动物 / 主语」方向「疲惫 / 状态」方向q(它)k(小猫)k(累)k(它)·很短q 与 k(小猫) 几乎同向,夹角最小 → 点积最大 →分到的注意力最多。
图 19-6把 q、k 画成 2 维平面上的箭头:点积大 = 方向一致。「它」的查询箭头几乎压在「小猫」的 key 上,所以打分远高于另外两个——这就是第一步分数悬殊的几何原因。

第二步 · 降温 这里维度 ,所以除以 。整行分数同除这个数:

2.4 ÷ 1.41 = 1.70
0.2 ÷ 1.41 = 0.14
0.2 ÷ 1.41 = 0.14

(真实模型 、除以 8,原理完全一样,只是这里维度小、缩放也小,效果不明显——但流程一步不少。)

第三步 · 归一 把降温后的 喂进 softmax:先取 e 的幂,再各自除以总和。

e^1.70 ≈ 5.46  e^0.14 ≈ 1.15  e^0.14 ≈ 1.15
总和 = 5.46 + 1.15 + 1.15 = 7.76
小猫:5.46 ÷ 7.76 = 0.703
累 :1.15 ÷ 7.76 = 0.148
它 :1.15 ÷ 7.76 = 0.148
小猫70.3%
14.8%
14.8%

三个数加起来正好 100%——这就是「它」分配给全句的目光:七成给了小猫。

第四步 · 混合 拿这组权重去加权混合三个词的 v,逐维相加:

out = 0.703×[1.0, 0.0] + 0.148×[0.0, 1.0] + 0.148×[0.5, 0.5]
第 1 维:0.703×1.0 + 0.148×0.0 + 0.148×0.5 = 0.78
第 2 维:0.703×0.0 + 0.148×1.0 + 0.148×0.5 = 0.22
→ 「它」的新向量 = [0.78, 0.22]

还记得 v 的两维是「动物味 / 疲惫味」吗?「它」原本是个意思模糊的代词, 经过这一轮注意力,它的新向量变成了 [0.78, 0.22]——0.78 的动物味 + 0.22 的疲惫味。换句话说,模型已经算出:这个「它」≈ 一只(有点累的)小猫。 第 1 站那个「它指谁」的悬念,到这里被四步算术实实在在地解决了

可是——费这么大劲混出这个新向量,到底有什么用?这才是整套机制的落点,值得说透。

前面三步(打分、降温、softmax)算出来的,只是一张「该看谁、看多少」的计划表: 70% 小猫、15% 累……可计划表本身并不会让模型变聪明——它只是「知道该看小猫」,还没「真的看到」。第四步 ×V,才是把计划付诸执行:照这组比例,把小猫的内容(V)真的取过来,装进「它」自己的向量里。少了这一步,前面辛苦算出的权重就只是一份没人读的报告, 「它」的向量纹丝不动,整层等于白忙。混合 V,就是注意力真正「搬运信息」的那一下。

而这个装好了料的新向量,会顶替掉原来那个空洞的「它」,继续往上走—— 送进下一层注意力去抓更多关系,最终送到输出层去预测下一个词。 关键在于:因为现在「它」的向量里真的写着「小猫」,模型后面所有的判断, 都是在对「一只小猫」做,而不再是对一个谁也不知道指什么的空代词做。

原始「它」查词表得到 · 空洞与上下文无关,每句都一样注意力层混合 V新「它」= [0.78, 0.22]0.78 动物味 + 0.22 疲惫味装进了小猫的信息,随上下文而变下一层/预测下一词
图 19-7混合 V 的产物是一个「装好了上下文」的新向量:它顶替原来空洞的「它」,带着小猫的信息继续往上走,喂给下一层、最终喂给预测。注意力的价值,全在这次「搬运」里。

这也正好回扣第 1 站:原始的「它」是从词表里查出来的固定向量,与上下文无关—— 在哪句话里都长一个样。经过这一层注意力,它变成了随上下文而变的向量: 在「小猫累了」里偏向小猫,换成「马路堵了」就会偏向马路。 「同一个词,不同语境,得到不同向量」——这正是注意力存在的全部理由, 也是 GPT 们能「读懂上下文」的底层机制。

把维度放大回去

把这里的 2 维换回 64 维、把「只算它一行」换成「n 行一起算」, 就是真实 Transformer 每一层每时每刻在做的事——同样的四步:打分、降温、归一、混合, 只是更大、更并行。你刚刚用纸笔走完的,正是大模型内部最核心的那个动作。

第 7 站

亲手点一点

回到开头那对句子。下面是一个迷你注意力面板:点击任意一个词, 看它的注意力都分给了谁;再切换句子,观察同一个「它」的目光如何移动。

动手实验「它」的目光 —— 点击词语,查看注意力分布

」的目光主要落在「小猫」上(60%)

百分比 = softmax 后的注意力权重(演示用的手工数据)。注意切换句子时,「它」的最大权重从「小猫」跳到「马路」——决定目光去向的,是「累 / 堵」这一个字的差别。

这个面板里的注意力似乎只关心「指代」。可一句话里还有语法搭配、修饰关系、情感色彩…… 一套 Q/K/V 打出来的一种分数,照顾得过来吗?
第 8 站

总结

本课核心 · TAKEAWAY

注意力机制,就是让每个词带着自己的问题(Q)去查所有词的标签(K), 按匹配程度分配目光,再把对应的内容(V)按比例混合成自己的新含义—— 从此,理解一个词不再依赖一条会遗忘的传话链。

这一课你亲手发明了

  • 注意力权重:点积打分 + softmax 归一,得到「该看谁多少」的百分比。
  • Q / K / V:查询单、书脊标签、书的内容——一个词的三个分身,由三个可学习的矩阵生成。
  • 缩放因子 √d_k:给高维点积「降温」,防止 softmax 饱和。
  • 两个免费赠品:全句并行计算;任意距离一步直达。
小测验

学习小测验

做完这一课,来检测一下核心知识点。选出你的答案后点击「提交」,即可看到正确选项与讲解。

Q1注意力机制要解决「它太累了——『它』指谁?」这类问题。它的核心做法是?
Q2自注意力中的 Query、Key、Value 分别大致扮演什么角色?
NEXT · 第 20 课

多头注意力

一句话里不止一种关系——指代、语法、情感各派一个「头」去看,再把所见拼成全貌。

0 人点赞,0 人看过