一、接龙大师的疑问:白板那么长,该听谁的?
第 01、02 篇连起来看,是这样一个过程:模型手上只有一块白板,这一轮要用的东西全写在上面;每生成一个字,它都要把白板上已经写下的内容重新过一遍,才猜得出下一个 token。
这里藏着一个没拆的问题:白板上可能有几万个 token------你三小时前的开场白、贴的文档、刚才的追问,全都还在。模型生成当前这个字时,这些 token 的影响力都一样大吗?
当然不是。"今天天气真"接"好",主要靠最近的几个字;回答"你刚才说的第二个方案",就得从几万字外把那个方案精准捞回来。白板上这些 token,影响大小不看远近,只看能不能对上当前这个字。
这套机制叫 Attention,中文译作"注意力"。一句话版本:
每个 token 都会算出前面每一个 token 跟它有多相关,得到一个分数;再把这些分数当比例,把前面 token 的内容加起来,结果就是这个 token 的新内容。
Transformer 之所以能记住几万字之前说过的话,靠的就是这个动作:一个词的意思不全是它自带的,是把一圈上下文都算进去之后得出的。
二、Q/K/V:图书馆三件套
怎么让每个 token 算出"该听谁的多一点"?换成图书馆的场景:你手上有一张检索卡,书架上是一排书,每本书的书脊上贴着标签。查一次,三样东西各管一件事:
- Q(Query,查询):你手上的检索卡------写着"我要找什么"。这张卡只代表这一趟的需求,换个问题就得重写。
- K(Key,键):书脊上贴的标签------写着"我这儿讲什么"。它贴在书外面,专门用来被比对,不用翻开书。
- V(Value,值):书的正文------书里真正写了什么。只有被挑中的书,你才会去翻它。
标签和正文为什么要分成两样?因为"好不好找"和"值不值得读"是两件事。书名起得响,内容可能没用;内容扎实,书名也可能不起眼。分开之后,比对只看标签,取内容才翻正文,两件事互不干扰。
Attention 把这三样东西发给了每个 token------模型里每个 token 都同时备着检索卡、标签和正文。
一轮"找资料"是这么走完的:当前 token 用自己的检索卡(Q),去比对前面每一个 token 的标签(K),得到一组匹配分;再把分数换算成比例,按比例把每个 token 的正文(V)各取一份,混在一起------这就是它的新内容。
三个细节:
- 三样东西出自同一个 token,只是乘了三个不同的矩阵。 每个 token 原本只有一串数字(正式名字叫向量),按三套规则各换算一次,得到三串新向量------同一份资料按三种用途各算了一遍。三套规则就是模型里的三个矩阵,都是训练时学出来的,不是人写的。
- 匹配分是 Q 和 K 的点积。 点积是两串同样长的数字按位相乘、再把结果加总,得到一个数。两串数字越对得上,这个数越大------分数高,就说明这两个 token 的内容对得上。
- 比例是全部 token 一起分完的,每个都分到一点。 匹配分先换算成一组加起来等于 1 的比例(就是把分数变成百分比,和 01 篇讲 softmax 是同一个动作),再按比例把每个 token 的 V 取一份加总。最相关的那几个占大头,其余每个也掺一点,只是很少------新内容里,前面每个 token 都留了一点痕迹。
整条流水线一张图:
#mermaid-svg-K0bhjCk1HpHsOavY{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-K0bhjCk1HpHsOavY .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-K0bhjCk1HpHsOavY .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-K0bhjCk1HpHsOavY .error-icon{fill:#552222;}#mermaid-svg-K0bhjCk1HpHsOavY .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-K0bhjCk1HpHsOavY .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-K0bhjCk1HpHsOavY .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-K0bhjCk1HpHsOavY .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-K0bhjCk1HpHsOavY .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-K0bhjCk1HpHsOavY .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-K0bhjCk1HpHsOavY .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-K0bhjCk1HpHsOavY .marker{fill:#333333;stroke:#333333;}#mermaid-svg-K0bhjCk1HpHsOavY .marker.cross{stroke:#333333;}#mermaid-svg-K0bhjCk1HpHsOavY svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-K0bhjCk1HpHsOavY p{margin:0;}#mermaid-svg-K0bhjCk1HpHsOavY .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-K0bhjCk1HpHsOavY .cluster-label text{fill:#333;}#mermaid-svg-K0bhjCk1HpHsOavY .cluster-label span{color:#333;}#mermaid-svg-K0bhjCk1HpHsOavY .cluster-label span p{background-color:transparent;}#mermaid-svg-K0bhjCk1HpHsOavY .label text,#mermaid-svg-K0bhjCk1HpHsOavY span{fill:#333;color:#333;}#mermaid-svg-K0bhjCk1HpHsOavY .node rect,#mermaid-svg-K0bhjCk1HpHsOavY .node circle,#mermaid-svg-K0bhjCk1HpHsOavY .node ellipse,#mermaid-svg-K0bhjCk1HpHsOavY .node polygon,#mermaid-svg-K0bhjCk1HpHsOavY .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-K0bhjCk1HpHsOavY .rough-node .label text,#mermaid-svg-K0bhjCk1HpHsOavY .node .label text,#mermaid-svg-K0bhjCk1HpHsOavY .image-shape .label,#mermaid-svg-K0bhjCk1HpHsOavY .icon-shape .label{text-anchor:middle;}#mermaid-svg-K0bhjCk1HpHsOavY .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-K0bhjCk1HpHsOavY .rough-node .label,#mermaid-svg-K0bhjCk1HpHsOavY .node .label,#mermaid-svg-K0bhjCk1HpHsOavY .image-shape .label,#mermaid-svg-K0bhjCk1HpHsOavY .icon-shape .label{text-align:center;}#mermaid-svg-K0bhjCk1HpHsOavY .node.clickable{cursor:pointer;}#mermaid-svg-K0bhjCk1HpHsOavY .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-K0bhjCk1HpHsOavY .arrowheadPath{fill:#333333;}#mermaid-svg-K0bhjCk1HpHsOavY .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-K0bhjCk1HpHsOavY .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-K0bhjCk1HpHsOavY .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-K0bhjCk1HpHsOavY .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-K0bhjCk1HpHsOavY .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-K0bhjCk1HpHsOavY .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-K0bhjCk1HpHsOavY .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-K0bhjCk1HpHsOavY .cluster text{fill:#333;}#mermaid-svg-K0bhjCk1HpHsOavY .cluster span{color:#333;}#mermaid-svg-K0bhjCk1HpHsOavY div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-K0bhjCk1HpHsOavY .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-K0bhjCk1HpHsOavY rect.text{fill:none;stroke-width:0;}#mermaid-svg-K0bhjCk1HpHsOavY .icon-shape,#mermaid-svg-K0bhjCk1HpHsOavY .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-K0bhjCk1HpHsOavY .icon-shape p,#mermaid-svg-K0bhjCk1HpHsOavY .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-K0bhjCk1HpHsOavY .icon-shape .label rect,#mermaid-svg-K0bhjCk1HpHsOavY .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-K0bhjCk1HpHsOavY .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-K0bhjCk1HpHsOavY .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-K0bhjCk1HpHsOavY :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 当前 token 的 Q
(检索卡)
和前面每个 K 比一遍
得到一个匹配分
前面所有 token 的 K
(书脊标签)
匹配分换成比例
(加起来等于 1)
按比例取 V
混在一起
前面所有 token 的 V
(书的正文)
当前 token 的新内容
(带上了上下文)
三、一个最小数值例子:计算一遍
类比讲完了,拿三个 token 算一遍。假设序列里只有三个 token:猫、追、老鼠,现在算"追"这一轮。为了便于计算,匹配分直接用 0 到 1 之间的数;真实模型里分数出来后还要先除以一个固定的数(分数太大算不稳,除一下让它落回合理范围),这一步只影响数值、不影响机制,这里略去。
第一步,"追"的 Q 和三个 K 的匹配分:
| token | 匹配分 |
|---|---|
| 猫 | 0.2 |
| 追(自己) | 0.3 |
| 老鼠 | 0.5 |
第二步,把分数变成一组加起来等于 1 的比例(真实模型里这一步由 softmax 完成,它的效果是把分数之间的差距拉得更开,再换算成比例:分高的占得多,分低的占得少):
- 猫 → 0.2,追 → 0.3,老鼠 → 0.5
第三步,按比例把三个 token 的 V 各取一份,加在一起。设每个 V 是一串只有两个数的数:
- V(猫) = 1, 0,V(追) = 0, 1,V(老鼠) = 1, 1
按比例取 V 加起来的结果:0.2×1,0 + 0.3×0,1 + 0.5×1,1 = 0.7, 0.8
看这个结果是什么意思:"追"原本只有 0, 1,只代表"追"这个动作,看不出谁追谁;算完之后它变成 0.7, 0.8,一个"半猫半老鼠"的动作节点------老鼠占的比例大,因为匹配分高(0.5)。这就是第一节那个定义落到数值上的样子。真实的 Attention 只是把每串数从 2 个换成几千个、把匹配分换成打分更细的点积,再乘一个缩放系数------骨架一模一样。
至于那组"把差距拉得更开,再换算成比例"的动作,就是 softmax 干的事。第 01 篇的采样概率表用的是它,这里用的也是它------同一个工具,一个把"分数"变成"抽签概率",一个把"匹配分"变成"分配比例"。本篇不展开它的数学,留下一个直觉就够:softmax 是一台把任意一堆分数转换成'总和为一的分配方案'的机器。
四、Multi-Head:几个头同时查
一次比对只回答一个问题。可读一句话的时候,往往要同时弄清好几件事:这个"它"指谁?动词的主语在哪?"苹果发布新品"里的苹果是水果还是公司?只查一遍,只能顾上其中一件。
Transformer 的办法很直接:同一批 token,并行做多次第二节那套"查资料"。每次查都用一套自己的检索卡、标签和正文,也就是自己的 Q/K/V,各自取回一份内容,最后把几份拼在一起。这样一套独立的 Q/K/V,就叫一个 Head(头)。
各个头大致在查什么,看几个例子:
- 有的头偏向指代:"它""他""上述方案",往回翻,指的是前面哪个词
- 有的头偏向语法:动词和主语对不对得上------"苹果发布了新手机",发布的是公司,不是水果
- 有的头偏向词义:同一个"苹果",这里是水果还是公司
- 还有些头,研究者也说不清它们在查什么------学到的关联,人类没给起过名字
这段分工是打比方。真实的头不是各管一摊、互不干扰:训练出来的头常常几件事都沾一点,研究者只能看到"倾向于"某种模式。能确定的是同一层里同时在算好几种相关性,具体怎么分由数据自己长出来,没人指定。
代价算一笔账就清楚。用来描述一个 token 的数字本来是 4096 个,一个头全用上;拆成 32 个头,每个头只分到 128 个。32 × 128 还是 4096,总计算量基本没变------多视角是拿"每个头看得更窄"换来的。反过来,如果每个头都保留完整的 4096 个数字,头数翻倍计算量就翻倍,这个成本根本扛不住。
五、Attention 凭什么取代 RNN
在 Transformer(2017)之前,处理序列的主流是 RNN/LSTM:像人读串珠一样,一个 token 读完了再读下一个,用一条"隐藏状态"从头传到尾。它有两个致命伤,恰好被 Attention 一步治好:
第一,长程依赖 。RNN 里第 1 个词的信息要传到第 500 步,得经过 499 次中转,每转一次丢一点------传到后面早面目全非。Attention 里任何两个 token 都直接相连:第 500 步的 Q 直接和第 1 步的 K 算匹配分,一步到位,无论隔多远。距离在 Attention 面前不再是信息衰减的理由------但注意,第 02 篇讲过 lost in the middle:一步到位不代表比例一定给够,"能直接看"和"一定看准"是两回事。
第二,训练无法并行 。RNN 必须按顺序算:第 t 步依赖第 t-1 步的输出,GPU 的上万核心干瞪眼。Attention 对整个序列的 Q×K 计算是矩阵乘法,全序列一次算完------这正是大模型能吃下万亿级 token 的前提:没有并行训练,就没有现代 LLM 的规模。
代价也有,就是第 02 篇提过的老朋友:任意两点相连意味着两两都要算匹配分,n 个 token 就是 n² 个分数------长上下文贵的数学根源,在这里就已经埋下了。
六、一句话收束,外加一份"面试浓缩"
如果整篇只带走一句话,带走这句:
Attention = 每个 token 用 Q 去和所有 K 比对得到匹配分,softmax 把分数换成总和为 1 的比例,再按比例把所有 V 混在一起------输出的新内容由整个上下文按比例混出来。
剩下的都挂在这句话上:匹配分换比例靠 softmax;一个视角不够就并行多个 Head;任意两点直接连线所以长程依赖一步到位;全序列矩阵化所以训练能并行;连线是两两全连所以计算 O(n²)。第 02 篇的白板之所以"中间容易被划水",本质也是这套按比例分配的机制在超长序列上失衡。
还有个常见追问值得预先拆掉:"Attention 就是模型在'理解'语义吗?"------严谨地说,Attention 只是一种可学习的加权信息聚合机制,权重由训练自动学出。它产出的表征确实支撑了模型表现出的语义能力,但"注意力权重 = 人类意义上的理解"这个等式,学界并不承认。它是手段,不是意识。
小结
- Attention 一句话:每个 token 算出前面每个 token 的匹配分,把分数当比例取对方的内容加起来,得到自己的新内容
- Q/K/V 三件套:查询卡找什么、书脊标签被什么找到、正文是实际交付的信息;比对 → 换比例 → 按比例取 V 加起来
- 输出是按比例混出来的,不是复制:softmax 把匹配分变成总和为 1 的比例(第 01 篇采样用的同一台机器)
- Multi-Head 是并行做多次查询(指代/语法/词义各查一件),但"分工明确"是简化说法,职能由数据学出且常重叠
- 取代 RNN 的两个理由:任意两 token 直接相连(长程依赖一步到位)+ 全序列矩阵并行(训练可扩展);代价是 O(n²)------第 02 篇"长上下文贵"的根源
思考题
- 如果序列里两个 token 的 K 向量完全相同,当前 token 分给它们的比例会怎样?这对"模型区分同形异义(同一个词不同意思)"意味着什么?(提示:想想 softmax 对相同分数的分配,再想想 K 是从 token 原始向量变换来的------同形 token 的输入真的一样吗?)
- Attention 是 O(n²),序列长度翻倍、计算量翻四倍。工业界都在从哪些方向把这个平方压下去?(提示:搜索"稀疏注意力、滑动窗口注意力、线性注意力"这三个词,看看它们各自砍掉了哪部分配对。)
高频面试题
Q1:用一句话讲清 self-attention 的工作机制。
A:序列中每个 token 生成 Query,与包括自身在内的所有 token 的 Key 计算匹配分,匹配分经 softmax 归一化为总和为 1 的注意力权重,再按权重对全部 token 的 Value 加权求和,得到融合了全局上下文的新表征。self 指的是 Q、K、V 都来自同一序列,即序列内部自己做信息聚合。
Q2:Q、K、V 为什么要用三个矩阵?一个向量直接算不行吗?
A:三个矩阵让同一个 token 的"我要找什么(Q)""我能被什么匹配(K)""我实际携带的信息(V)"解耦到三个子空间。若不做变换直接用原始向量,token 会被迫用同一种表达既当查询又当内容------"一个词"和"这个词对别人的价值"以及"它贡献给别人的信息"是三种不同角色,混合表达会互相干扰。实证上,Q/K/V 变换显著优于无变换版本,这是消融实验支持的结论。
Q3:为什么 Attention 能取代 RNN 处理长序列?
A:两点。其一,RNN 的信息沿隐藏状态逐步传递,长距离依赖经过多步中转持续衰减;Attention 中任意两个位置直接计算关联,路径长度 O(1)。其二,RNN 的时序依赖迫使训练串行;Attention 的匹配分计算是全序列矩阵运算,可在 GPU 上完全并行,这是模型规模能扩展到万亿 token 数据的前提。代价是 O(n²) 的配对计算,由此衍生出各类高效注意力变体。
Q4:Multi-Head Attention 的作用是什么?头数是不是越多越好?
A:多头让模型在同一层并行算好几套不同的相关性(如句法、语义、指代等模式),单头只能算一套。头数增加通常在中小规模时提升效果,但存在收益递减:每份维度变小、单个头的表达力下降;且若保持每个头的维度不变而增加头数,计算与显存开销会线性增长。某些头会被证明冗余可剪。实践中头数是随模型宽度调的超参数,不是越大越好。
系列导航:上一篇 02《上下文窗口与遗忘》 → 下一篇 04《知识是从哪来的》:预训练、微调、对齐各在练什么,幻觉从哪来