想象一下,你是一家公司的产品经理,要召集一场“需求评审会”。会议分两半:前半场,大家先充分理解用户到底想要什么;后半场,再针对需求讨论怎么实现。参会的人很多,但你没有让每个人轮流发言——而是让所有人同时说话,你竖起耳朵,重点听那些和你当前问题最相关的人。谁专业、谁靠谱,你就多听谁的;关系不大的,就少听或不听。听完之后,你把所有人的观点按重要程度加权融合,形成自己的判断,再在初稿上批注修改,控制好音量,进入下一轮讨论。 这,就是 Transformer 的工作方式。 Transformer 是当今几乎所有大语言模型(GPT、BERT、Llama)的底层架构。它把“开会”这件事拆成了几个清晰的机制:自注意力决定该听谁、多头注意力从多个角度反复讨论、位置编码给每个人发座位号、残差连接确保不丢掉初稿、LayerNorm 维持讨论的秩序。这篇文章就用这场“会议”作为主线,把 Transformer 的原理、公式、面试高频追问一次讲透——让你从完全不懂,到能从容应对面试官的层层深挖。

岗位关联

对 AI 从业者来说,Transformer 是面试必考、工作必用的地基。能把这套机制讲清楚,不仅意味着你懂模型,更说明你有结构化理解复杂系统的能力——这是算法岗、大模型岗面试最看重的素质。

目录
  1. 可视化演示
  2. 整体架构:一场“先听后说”的高效会议
  3. 自注意力机制:谁靠谱,就多听谁的
  4. 多头注意力:开六个小组会再汇总
  5. 位置编码:给每个座位贴号牌
  6. 残差连接与 LayerNorm:改稿而不是重写
  7. 对比循环网络:并行会议 vs 排队发言
  8. 面试高频追问:怎么答才不翻车
  9. AI 应用场景
  10. Python 演示
  11. 常见误区
  12. 面试题

可视化演示

动态演示Transformer原理的核心机制,通过源头/管道/节点/终端四种模式展示关键概念与交互流程。

本节配有交互动效(进入视口后自动加载,约 3KB)。

Transformer原理:自注意力 自注意力机制原理详解 多头注意力机制设计 核心机制可视化 Transformer原理整体架构与关键组件

整体架构:一场“先听后说”的高效会议

假设你要把一句中文“我爱你”翻译成英文。你召集两场会:第一场是“理解会”,所有参会者把这句话从各个角度读懂——谁在说、对谁说、什么语气。第二场是“生成会”,基于理解会的结论,一个词一个词地把英文说出来。Transformer 正是这样:编码器(Encoder)负责理解,解码器(Decoder)负责生成。

在模型内部,输入的每个词先通过嵌入层(Embedding)变成向量——相当于给每位参会者发一张工牌,上面写着他们的身份。然后,这些向量进入编码器的 6 层堆叠结构。每一层都在做同一件事:先让所有人互相交换信息(自注意力),再对每个人的发言做一轮独立加工(前馈网络)。6 层不是简单重复,而是逐层提炼,像会议从发散讨论慢慢收敛成清晰结论。

解码器这边同样有 6 层,但多了一个关键动作:它每生成一个词,都要回头“问”编码器要信息(交叉注意力),同时还要保证自己只看到已生成的词,不能偷看未来的答案(掩码机制)。整场会议就在这种“先听后说”的节奏中完成翻译。一个 Transformer 编码器层的完整变换可以写成:

回到会议场景:每一层就是一轮“小组讨论 + 个人思考 + 记录归档”,记录员永远不会扔掉你的原稿,只在上面批注。6 轮下来,理解会开完了,解码器再拿着这份纪要生成目标语言。

z=LayerNorm(x+MultiHead(x)),h=LayerNorm(z+FFN(z))\displaystyle z=\text{LayerNorm}(x+\text{MultiHead}(x)),\qquad h=\text{LayerNorm}(z+\text{FFN}(z))
这个式子描述了一个 Transformer 层内部的两次“加工-修正”:一次针对注意力结果,一次针对前馈网络结果,每次都在原信息上做改进而不是推倒重来。
  1. 输入向量 $x$表示上一层传入的向量,可能是词嵌入,也可能是上一层加工后的结果。
    x∈Rdmodel\displaystyle x \in \mathbb{R}^{d_{\text{model}}}
  2. 多头注意力 $\text{MultiHead}(x)$让每个词综合全局信息,得到一份“开会共识”。
    MultiHead(x)\displaystyle \text{MultiHead}(x)
  3. 残差加法 $x+\text{MultiHead}(x)$把原信息和注意力结果相加,保留原始内容,只做增量修改。
    x+MultiHead(x)\displaystyle x+\text{MultiHead}(x)
  4. 层归一化 $\text{LayerNorm}$把相加结果的数值分布拉回稳定区间,防止训练时数值爆炸。
    LayerNorm(⋅)\displaystyle \text{LayerNorm}(\cdot)
  5. 前馈网络 $\text{FFN}(z)$对每个词独立做一次非线性变换,相当于个人独立思考时间。
    FFN(z)\displaystyle \text{FFN}(z)
  6. 第二次残差与归一化同样保留 $z$ 的信息,再对新结果做一次修正。
    h=LayerNorm(z+FFN(z))\displaystyle h=\text{LayerNorm}(z+\text{FFN}(z))

自注意力机制:谁靠谱,就多听谁的

现在我们把镜头推进到会议室里那一刻。你坐在桌边,心里有个问题:“这个季度的预算怎么花?”这就是你的 Query(查询向量 Q)。对面每位同事胸前都挂着名牌,写着他们的专长,比如“财务-预算”“市场-投放”“技术-研发”——这些名牌就是 Key(键向量 K)。你快速扫一眼名牌,和你的问题比对:财务的名牌和“预算”最匹配,于是你竖起耳朵认真听;市场和技术也有相关性,你分出一部分注意力听;跟预算无关的同事,你礼貌性地点头即可。

这个“比对”在数学上就是 点积:两个向量方向越一致、数值越大,相似度越高。把 Query 与所有 Key 做点积,得到一组分数,再经过 Softmax 归一化 变成“注意力权重”——权重高的多听,权重低的少听。最后,每位同事的完整发言内容存在 Value(值向量 V) 里,你把所有人的 V 按权重加权求和,就得到了你听完会后形成的新观点。整个过程写成公式:

这场“听会”有个神奇之处:所有词是同时进行的。你不需要等别人开完口你再想——每个人都同时拿着自己的 Q,去匹配所有人的 K,再各自加权汇总 V。这就是自注意力(Self-Attention)名字的由来:序列中每个元素都在“自己看自己所在的整个序列”。

Attention(Q,K,V)=softmax(QK⊤dk)V\displaystyle \text{Attention}(Q,K,V)=\text{softmax}\left(\frac{QK^\top}{\sqrt{d_k}}\right)V
这个公式是 Transformer 的灵魂:它让每个词都能“看向”序列中的所有其他词,并按相关程度汲取信息。缩放因子 $\sqrt{d_k}$ 是防止分数过大导致 Softmax 饱和的关键细节。
  1. 查询矩阵 $Q$由输入向量乘以权重矩阵 $W^Q$ 得到,代表“我关心什么”。
    Q=XWQ\displaystyle Q=XW^Q
  2. 键矩阵 $K$由输入向量乘以权重矩阵 $W^K$ 得到,代表“我擅长什么、可以被什么匹配上”。
    K=XWK\displaystyle K=XW^K
  3. 点积 $QK^\top$拿每个查询去和所有键做内积,得到相似度分数矩阵,分数越高越相关。
    QK⊤=∑i=1dkQiKi\displaystyle QK^\top=\sum_{i=1}^{d_k} Q_i K_i
  4. 缩放 $\frac{1}{\sqrt{d_k}}$当维度 $d_k$ 很大时,点积数值会很大,Softmax 会掉进饱和区、梯度消失;除以 $\sqrt{d_k}$ 把数值拉回合理范围。
    QK⊤dk\displaystyle \frac{QK^\top}{\sqrt{d_k}}
  5. Softmax 归一化把每行分数转成概率分布,保证权重非负且和为 1。
    softmax(zi)=ezi∑jezj\displaystyle \text{softmax}(z_i)=\frac{e^{z_i}}{\sum_j e^{z_j}}
  6. 加权求和 $(\cdot)V$用概率权重对所有 Value 做加权平均,得到注意力输出。
    ∑jsoftmaxj Vj\displaystyle \sum_j \text{softmax}_j\, V_j

多头注意力:开六个小组会再汇总

只用一种角度开大会,容易看偏问题。比如讨论预算,你只听财务的,就可能忽略市场部的投放计划。Transformer 的解决方法是:同时开多个小组会,每组从不同角度切分和匹配信息——这就是“多头”(Multi-Head)。

具体做法是:把查询、键、值和输入特征的维度平均切成 $h$ 份(论文里 $h=8$),每份都是一个“头”。每个头用自己独立的一组投影矩阵 $W_i^Q, W_i^K, W_i^V$,在低维子空间里做一次自注意力。有的头可能学会了捕捉主谓关系,有的头学会了关注指代关系,有的头学会了捕捉位置邻近关系——它们各管一个子空间,互不干扰。最后,把所有头的输出拼接起来,再经过一个输出投影矩阵 $W^O$ 融合成最终结果:

回到会议:6 个小组同时开会——技术组、市场组、成本组、用户组……每组独立形成结论,最后各组长碰头,把大家的意见汇总成一份总方案。这就是为什么多头注意力让 Transformer 能从多个子空间捕捉关系,而不是只盯着一个角度。面试时如果说“多头就是多个注意力串行”,会被一眼看穿——它们是并行的。

MultiHead(Q,K,V)=Concat(head1,…,headh)WO,headi=Attention(QWiQ,KWiK,VWiV)\displaystyle \text{MultiHead}(Q,K,V)=\text{Concat}(\text{head}_1,\ldots,\text{head}_h)W^O,\qquad \text{head}_i=\text{Attention}(QW_i^Q,KW_i^K,VW_i^V)
多头不是多个注意力串联,而是把一个大注意力“切开”并行的多头再合并——总计算量和单头注意力基本持平,但表达能力大幅提升。
  1. 头的定义 $\text{head}_i$第 $i$ 个头,注意力计算时使用该头专属的三组矩阵。
    headi=Attention(QWiQ,KWiK,VWiV)\displaystyle \text{head}_i=\text{Attention}(QW_i^Q,KW_i^K,VW_i^V)
  2. 输入投影 $QW_i^Q$每个头的 Q 都由原始输入乘上该头的查询投影矩阵得到,实现“换个角度看待问题”。
    QWiQ,KWiK,VWiV\displaystyle QW_i^Q,\quad KW_i^K,\quad VW_i^V
  3. 拼接 $\text{Concat}$把 $h$ 个头的输出按特征维拼接,形成更高维的综合意见。
    Concat(head1,…,headh)∈Rdmodel\displaystyle \text{Concat}(\text{head}_1,\ldots,\text{head}_h)\in\mathbb{R}^{d_{\text{model}}}
  4. 输出投影 $W^O$拼接结果再乘一个输出矩阵,把多头信息混合并还原到模型维度。
    MultiHead(⋅)=Concat(⋅)WO\displaystyle \text{MultiHead}(\cdot)=\text{Concat}(\cdot)W^O

位置编码:给每个座位贴号牌

自注意力有个致命弱点:它天生不感知顺序。在注意力眼里,序列就像一屋子无序站着的人,没有“谁先发言”的概念。如果把“猫咬了我”和“我咬了猫”的四个词分别输入,词向量完全相同,注意力计算出的结果也会完全一样——模型根本分不清谁是受害者、谁是施害者。

开会必须有人知道发言顺序。Transformer 的做法是给每个位置的词向量注入一个“座位号”,这就是位置编码(Positional Encoding)。它不是学出来的,而是用固定公式生成的,叠加在词嵌入上一起进入模型:

回到会议:每个人进会场时领一个“号牌”,号牌上刻着正弦波相位。即便所有同事的工牌内容一样,号牌也决定了“谁是第几个发言”。位置编码正是这样一个号牌——它让原本无序的集合操作,重新获得了序列顺序信息。

PE(pos,2i)=sin⁡(pos100002i/dmodel),PE(pos,2i+1)=cos⁡(pos100002i/dmodel)\displaystyle PE_{(pos,2i)}=\sin\left(\frac{pos}{10000^{2i/d_{\text{model}}}}\right),\qquad PE_{(pos,2i+1)}=\cos\left(\frac{pos}{10000^{2i/d_{\text{model}}}}\right)
位置编码用一组不同频率的正弦和余弦波,给序列中每个位置打上独一无二的“相位标记”。位置越靠后,相位变化越平缓。
  1. 位置下标 $pos$词在句子里的位置,从 0 开始计数。
    pos=0,1,2,…\displaystyle pos=0,1,2,\ldots
  2. 维度下标 $i$表示向量的第 $i$ 维,决定使用正弦还是余弦、以及使用哪种频率。
    i=0,1,2,…,dmodel2−1\displaystyle i=0,1,2,\ldots,\frac{d_{\text{model}}}{2}-1
  3. 偶数维度用正弦、奇数维度用余弦用一对正余弦同时编码,让模型能通过三角函数关系推测相对位置。
    PE(pos,2i)=sin⁡(⋅),PE(pos,2i+1)=cos⁡(⋅)\displaystyle PE_{(pos,2i)}=\sin(\cdot),\quad PE_{(pos,2i+1)}=\cos(\cdot)
  4. 频率指数 $10000^{2i/d}$随着 $i$ 增大,分母指数变大,频率从快到慢变化,形成多尺度编码。
    100002i/dmodel\displaystyle 10000^{2i/d_{\text{model}}}
  5. 叠加方式位置编码直接与词嵌入相加,不改变维度。
    x′=x+PE\displaystyle x' = x + PE

残差连接与 LayerNorm:改稿而不是重写

开一场漫长的会,最怕什么?聊到第三轮,大家把第一轮聊的精华全忘了。Transformer 用残差连接解决这件事:每一层的输出不是把输入完全改写成新内容,而是在原输入上“加”一个增量。就像写会议纪要,你不会每次从头重写,而是在初稿上做批注修改。这样,原始信息可以从第一层一路畅通流到最后一层,梯度反向传播时也能跳过中间层直达浅层——这就是为什么 Transformer 可以堆到几十上百层而不退化。

但光有残差还不够。会上如果一个人声音特别大、一个人声音特别小,讨论就会失衡。层归一化(LayerNorm) 就像会议主持人,随时控制每个人的“音量”:对每个词向量,先算出这一维向量内部所有特征的均值和方差,再把它标准化成均值为 0、方差为 1 的分布,最后用可学习参数 $\gamma$ 和 $\beta$ 重新缩放和平移,保留模型需要的表达能力:

回到会议场景:残差连接保证每轮讨论的初稿都还在桌上,LayerNorm 保证每个人发言都清清楚楚、音量均衡。两者配合,让 Transformer 既能堆得很深、又能训得很稳——这是面试中“为什么 Transformer 这么好训练”的核心答案。

LayerNorm(x)=γ⊙x−μσ2+ϵ+β\displaystyle \text{LayerNorm}(x)=\gamma\odot\frac{x-\mu}{\sqrt{\sigma^2+\epsilon}}+\beta
层归一化对每个样本单独做归一化,不依赖 batch 大小和序列长度,因此特别适合自然语言这种变长输入的场景。
  1. 均值 $\mu$ 与方差 $\sigma^2$对单个词向量在所有特征维度上计算,衡量这一层数值的整体水平和波动程度。
    μ=1d∑j=1dxj,σ2=1d∑j=1d(xj−μ)2\displaystyle \mu=\frac{1}{d}\sum_{j=1}^{d}x_j,\qquad \sigma^2=\frac{1}{d}\sum_{j=1}^{d}(x_j-\mu)^2
  2. 标准化每个特征减去均值、除以标准差(加小常数 $\epsilon$ 防止除零),把分布拉回标准正态。
    x−μσ2+ϵ\displaystyle \frac{x-\mu}{\sqrt{\sigma^2+\epsilon}}
  3. 缩放平移 $\gamma$ 和 $\beta$两个可学习参数,允许模型在归一化后重新调整“音量大小”和“偏移”,避免信息被过度规整。
    γ⊙(⋅)+β\displaystyle \gamma\odot(\cdot)+\beta

对比循环网络:并行会议 vs 排队发言

老一代的循环神经网络(RNN)是怎么开会的?会议室规定:只能按工号顺序发言。第一个人说完,第二个人才能开口;第二个人听到的信息里,第一个人的原话已经“转述”了一遍,打了折扣。等到第 100 个人发言时,第 1 个人的信息已经衰减到几乎听不见了——这就是 RNN 的“长距离依赖问题”和“无法并行”的痛点。

Transformer 直接把这条规则掀了:全员同时发言,所有人都能实时听到彼此。每个词都直接和序列中所有其他词做注意力计算,没有中间转述环节。这意味着:

  • 并行计算:整句话一起算,不再一个词一个词排队,GPU 吞吐量大幅提升;
  • 任意两词直接互联:无论相隔多远,注意力权重都是“一步直达”,长距离依赖不随距离衰减;
  • 代价是平方复杂度:每个词都要和所有词算匹配度,因此要维护一个 $n\times n$ 的注意力矩阵:

回到会议:RNN 是“排队发言”,信息传得越远越失真;Transformer 是“圆桌讨论”,任何两个人之间没有中间人。代价就是场地成本变高——人越多,需要摆放的“两两对话连线”越多。明白了这一点,面试官再问“Transformer 和 RNN 本质区别”,你就能直击要害:并行 VS 串行,直达 VS 衰减。

自注意力复杂度=O(n2×d)\displaystyle \text{自注意力复杂度}=O(n^2\times d)
其中 $n$ 是序列长度,$d$ 是特征维度。序列翻倍,计算量翻四倍,这是 Transformer 面对超长文本时的主要瓶颈。
  1. 复杂度来源有 $n$ 个查询,每个查询要跟 $n$ 个键做点积。
    n×n=n2\displaystyle n \times n = n^2
  2. 点积开销每个点积在 $d$ 维空间计算,因此总复杂度为 $O(n^2 d)$。
    O(n2×d)\displaystyle O(n^2\times d)
  3. 对比 RNNRNN 每步只做 $O(d^2)$ 的矩阵运算,但必须串行 $n$ 步,总时间 $O(n\,d^2)$ 且无法并行。
    RNN 串行步数=n\displaystyle \text{RNN 串行步数}=n

面试高频追问:怎么答才不翻车

最后,我们把面试官最爱追着问的几个“坑”提前踩一遍。每一个都是基于前面概念的深挖。

追问一:为什么要除以 $\sqrt{d_k}$? 如果不缩放,两个 $d_k$ 维向量的点积数值会随着维度增大而迅速变大。大数值送进 Softmax 后,概率分布会变得极不均匀——最大的一项接近 1,其他项接近 0,梯度几乎为 0,模型就学不动了。除以 $\sqrt{d_k}$ 相当于把所有分数拉回到方差为 1 的水平,Softmax 才能工作在敏感区。这可以用 Softmax 的导数形式看出:

追问二:解码器的掩码是怎么回事? 解码器生成“我”时,绝不能偷看到后面的“爱”和“你”。所以训练时会给注意力矩阵加一个上三角掩码:把未来位置全部设成负无穷,Softmax 后权重为 0。另外还有 Padding Mask,用来屏蔽无效的填充位。

追问三:为什么用 LayerNorm 而不用 BatchNorm? 句子有长有短,batch 内的统计量不稳定;而且推理时序列长度可能变化,BatchNorm 依赖的 batch 统计会失效。LayerNorm 只看当前词向量自己的特征维,和 batch、序列长度都无关,所以成为 NLP 的首选。这正好呼应了残差与归一化一节里“主持人控制音量”的比喻——只调当前人的音量,不看全场平均。

∂ softmax(zi)∂zj=softmax(zi)(δij−softmax(zj))\displaystyle \frac{\partial\,\text{softmax}(z_i)}{\partial z_j}=\text{softmax}(z_i)\left(\delta_{ij}-\text{softmax}(z_j)\right)
  1. Kronecker 函数 $\delta_{ij}$当 $i=j$ 时为 1,否则为 0,用于区分“对自己的偏导”和“对其他项的偏导”。
    δij={1i=j0i≠j\displaystyle \delta_{ij}=\begin{cases}1 & i=j\\0 & i\neq j\end{cases}
  2. 导数结构Softmax 对输入的导数等于“当前概率乘上一个修正项”。
    softmax(zi)(δij−softmax(zj))\displaystyle \text{softmax}(z_i)\left(\delta_{ij}-\text{softmax}(z_j)\right)
  3. 饱和现象当 $z$ 很大时,某个 $\text{softmax}(z_j)\to1$,括号内修正项 $\to0$,整体梯度趋近 0——模型停止学习。
    softmax(zi)(1−1)→0\displaystyle \text{softmax}(z_i)(1-1)\to0

AI 应用场景

机器翻译:从“理解会”到“生成会”的完整闭环

阶段:模型架构设计与训练

解决的问题:传统统计机器翻译需要大量人工特征工程,且难以捕捉长距离语义依赖。Transformer 的编码器-解码器结构让“理解”与“生成”彻底解耦:编码器把整个源语言句子压缩成语义向量,解码器再逐词生成目标语言,整个过程可以端到端训练。

具体案例:Google 翻译从 2016 年起用 Transformer 替换 RNN,翻译质量和速度双双大幅提升。你在网页上输入一段中文,后台的编码器先召开“理解会”读懂全句,解码器再按英文习惯一个词一个词生成,同时通过交叉注意力随时回看中文原文。

大语言模型的文本生成:解码器里的“逐词预测会”

阶段:模型推理与生成

解决的问题:GPT 系列大模型本质上是一个巨大的“解码器”。它只用掩码自注意力,每生成一个词,都回头对前面所有词重新计算注意力权重——就像会议讨论每得出一个新结论,大家都要重新评估哪些旧观点更重要。这让模型能根据上下文动态调整重点,生成连贯的长文本。

具体案例:ChatGPT 回答问题时,每个 token 的输出都依赖前面所有 token 的注意力结果。你追问“再详细一点”,新的 Query 会让模型把注意力重新分配到更相关的细节上,从而给出更具体的补充回答。

语义检索与文本表征:编码器的“向量化名片”

阶段:特征提取与语义匹配

解决的问题:传统关键词搜索无法理解“苹果手机”和“iPhone“是同一回事。用 Transformer 编码器把句子编码成一个向量,语义相似的句子在向量空间里距离近。自注意力让每个词都能吸收整句的语境信息,所以”苹果很好吃“和”苹果发布了新手机”会被编码到不同方向。

具体案例:企业知识库问答系统中,用户提问“今年报销流程有变化吗”,系统用编码器把问题编码成向量,和知识库中所有文档向量做余弦相似度匹配,召回最相关的制度文档,再交给生成模型组织回答。

Python 演示

python52 行
import numpy as np  def softmax(x, axis=-1):    """数值稳定的 softmax 实现"""    e_x = np.exp(x - np.max(x, axis=axis, keepdims=True))    return e_x / np.sum(e_x, axis=axis, keepdims=True)  def attention(Q, K, V):    """缩放点积注意力"""    d_k = K.shape[-1]    scores = np.dot(Q, K.T) / np.sqrt(d_k)    weights = softmax(scores, axis=-1)    return np.dot(weights, V), weights  def multi_head_attention(X, num_heads=2, d_model=8):    """简化版多头注意力"""    d_k = d_model // num_heads    rng = np.random.default_rng(42)    W_Q = rng.normal(0, 0.1, (d_model, d_model))    W_K = rng.normal(0, 0.1, (d_model, d_model))    W_V = rng.normal(0, 0.1, (d_model, d_model))    W_O = rng.normal(0, 0.1, (d_model, d_model))     Q = np.dot(X, W_Q)    K = np.dot(X, W_K)    V = np.dot(X, W_V)     heads = []    for i in range(num_heads):        q = Q[:, i * d_k:(i + 1) * d_k]        k = K[:, i * d_k:(i + 1) * d_k]        v = V[:, i * d_k:(i + 1) * d_k]        head, _ = attention(q, k, v)        heads.append(head)     concat = np.concatenate(heads, axis=-1)    return np.dot(concat, W_O)  if __name__ == "__main__":    # 三个词的输入向量, 模拟 "我 爱 猫"    X = np.array([        [1.0, 0.0, 0.0, 1.0, 0.5, 0.2, 0.1, 0.0],        [0.0, 1.0, 0.5, 0.0, 0.2, 0.8, 0.0, 0.1],        [0.5, 0.0, 1.0, 0.5, 0.0, 0.1, 0.9, 0.2],    ])    out = multi_head_attention(X, num_heads=2, d_model=8)    print("多头注意力输出形状:", out.shape)    print(out)
目的:用 NumPy 从零实现缩放点积注意力和多头注意力,演示 Transformer 最核心的计算流程。
  1. scores = np.dot(Q, K.T) / np.sqrt(d_k)计算每个 Query 与所有 Key 的点积相似度,再除以 $\sqrt{d_k}$ 防止 Softmax 饱和。
  2. weights = softmax(scores, axis=-1)对每一行做 Softmax,把分数变成非负且和为 1 的注意力权重。
  3. return np.dot(weights, V), weights按权重对所有 Value 加权求和,得到注意力输出。
  4. q = Q[:, i * d_k:(i + 1) * d_k]把 Q 按特征维切成多份,每个头只在自己的子空间里计算。
  5. concat = np.concatenate(heads, axis=-1)把所有头的输出沿特征维拼接,模拟“开完小组会再汇总”。

常见误区

误区我一开始以为注意力的 Q、K、V 三个矩阵就是输入向量 X,它们只是换个名字重复用。

正解Q、K、V 分别是输入 X 乘以三组不同的权重矩阵得到的。就像同一个参会者,他的“名牌(K)”“关注的问题(Q)”和“完整发言(V)”是从同一身份(X)加工出来的三个不同侧面,各有各的专业分工,绝不是同一个东西。

为何常见:公式里 Q、K、V 都由 X 变换而来,符号上容易让人误以为“它们就是 X”,忽略了中间的线性投影。

误区面试时被问残差连接的作用,我张口就答“为了防止梯度消失”。

正解防梯度消失确实是一方面,但残差更核心的价值是让信息从浅层直通深层——每层只在原输入上做增量修改,原始特征不会随着层数增加而完全被改写。这相当于写会议纪要在初稿上批注,而不是每轮都重写一遍,信息保真度大幅提高,模型也因此可以堆到几十上百层。

为何常见:因为残差在 ResNet 里最著名的效果就是解决梯度消失,很多人就把这个原理解释直接搬过来了,忽略了 Transformer 里“信息直通”的另一层意义。

误区反正都是归一化,LayerNorm 和 BatchNorm 只是名字不同,效果应该差不多。

正解两者归一化的维度完全不同。BatchNorm 对一个 batch 里所有样本的同一个特征通道做归一化,依赖 batch 统计量;LayerNorm 对单个样本的所有特征维度做归一化,跟 batch、序列长度都无关。NLP 里句子长短不一、batch 通常较小,BatchNorm 的统计量不稳定,所以 Transformer 清一色用 LayerNorm。

为何常见:二者都叫“归一化”,公式外形也像(减均值除方差),初学者很容易只在名字层面理解,忽略了归一化轴这个关键差异。

误区我以为多头注意力就是先把注意力算一遍,把结果再传给下一个头,一个接一个地算。

正解多头是并行切分维度:把 Q、K、V 的特征维平均切成 h 份,每个头在低维子空间同时计算,最后拼接再投影。因为维度被切小了,所有头加在一起的计算量和单头注意力几乎一样,只是通过多组投影矩阵学习不同子空间的模式。

为何常见:代码里看到 for 循环遍历每个 head 就误以为串行,其实循环里每个头处理的是切分后的不同维度块,彼此互不依赖。

误区自注意力已经能看到整句话所有词了,位置信息应该没那么重要,去掉试试也无妨。

正解注意力是“集合操作”,本身不感知顺序。把“猫咬了我”和“我咬了猫”的词向量打乱顺序输入,注意力输出完全一样,模型根本无法区分主宾关系。位置编码是 Transformer 唯一的顺序信息来源,去掉它模型就退化成“词袋模型”。

为何常见:注意力“一步直达全局”的能力太抢眼,让人忽略了它无序的本质——看得全不等于看得有顺序。

面试题

Q1. 自注意力中的 Query(查询向量)是如何得到的?

单选题 · easy

  • A.输入 X 直接就是 Query
  • B.输入 X 乘以 W_Q 得到← 正确答案
  • C.上一层的输出直接复制
  • D.随机初始化后固定不变

答案:B。Query 由输入向量与查询投影矩阵 $W^Q$ 相乘得到。就像你参会时关心的“问题”是从你的身份(输入)结合会议议题加工出来的,不是直接复制身份本身。A 忽略了线性投影,C 和 D 都不符合自注意力的参数化方式。

Q2. 注意力分数为什么要除以 $\sqrt{d_k}$?

单选题 · easy

  • A.降低矩阵乘法的总开销
  • B.防止 Softmax 饱和梯度消失← 正确答案
  • C.保证 Q 和 K 的维度匹配
  • D.让矩阵乘法运行速度更快

答案:B。当维度 $d_k$ 较大时,向量点积的数值会很大,Softmax 会进入饱和区,概率趋于 one-hot,梯度趋于 0,模型无法学习。除以 $\sqrt{d_k}$ 把分数拉回方差为 1 的合理范围。这跟开会时控制音量防止讨论失控是一个道理。

Q3. 关于多头注意力中各个头的关系,下列说法正确的是?

单选题 · mid

  • A.串联执行,前一个头的输出喂给下一个
  • B.在一份 Q/K/V 上并行切分计算再拼接← 正确答案
  • C.每个头都使用完全相同的权重矩阵
  • D.只有一个主头真正参与计算过程

答案:B。多头注意力把 Q/K/V 的特征维切分成 h 份,每个头在自己的子空间内并行计算注意力,最后拼接并投影。相当于同时开多个小组会再汇总。A 是串行误解,C 会导致所有头输出相同失去意义,D 完全不符合多头设计。

Q4. Transformer 中添加位置编码的主要作用是什么?

单选题 · mid

  • A.提供词在句子中的顺序信息← 正确答案
  • B.增加词向量的维度
  • C.让注意力权重更稀疏
  • D.防止过拟合训练数据

答案:A。自注意力是集合操作,本身无序,不感知词的前后关系。位置编码用正余弦函数给每个位置打上标记,让模型知道“谁先谁后”。它不改变词向量维度,也不影响注意力稀疏性或过拟合问题。

Q5. 关于残差连接和 LayerNorm,下列说法正确的有?

多选题 · mid

  • A.残差连接让信息从浅层直通深层← 正确答案
  • B.LayerNorm 对一个样本的特征做归一化← 正确答案
  • C.残差连接可以完全取代 LayerNorm
  • D.两者都用于提升训练稳定性← 正确答案

答案:ABD。残差连接保留原始信息,让梯度可以跳过中间层直达浅层;LayerNorm 对单个样本的所有特征维归一化,两者都让训练更稳定。C 错误——残差解决信息直通,LayerNorm 解决数值分布失衡,功能不同,不能相互替代。

Q6. Transformer 相比 RNN 的核心优势是什么?

单选题 · hard

  • A.能并行处理整个输入序列← 正确答案
  • B.模型的参数量显著更少
  • C.完全不需要位置信息
  • D.时间复杂度总是更低

答案:A。自注意力对所有词同时计算,天然支持并行,而 RNN 必须逐词串行。Transformer 参数量不一定更少、位置信息必须显式注入、时间复杂度 $O(n^2)$ 通常比 RNN 的串行 $O(n)$ 更高,所以其余选项都不对。

Q7. 序列长度为 $n$ 时,标准自注意力的时间复杂度是?

单选题 · hard

  • A.O(n)
  • B.O(n log n)
  • C.O(n²)← 正确答案
  • D.O(n³)

答案:C。每个 Query 要和所有 Key 计算点积,所以需要构建 $n\times n$ 的注意力矩阵。这是 Transformer 处理长文本的主要瓶颈,也催生了各种稀疏注意力优化方案。

Q8. 关于解码器中的掩码(Mask)机制,下列说法正确的有?

多选题 · mid

  • A.防止生成时看到未来位置的词← 正确答案
  • B.让训练和推理行为保持一致← 正确答案
  • C.提升注意力分数的数值精度
  • D.屏蔽 padding 位置的无效信息← 正确答案

答案:ABD。解码器用上三角掩码遮住未来位置,保证预测第 t 个词时只能看到前 t-1 个词,这使训练(teacher forcing)和推理(逐步生成)行为一致。Padding Mask 则用于屏蔽填充位。C 与掩码作用无关,掩码并不会提升数值精度。

Q9. 在公式 $\text{softmax}(\frac{QK^\top}{\sqrt{d_k}})V$ 中,$QK^\top$ 的计算结果代表什么?

单选题 · mid

  • A.Query 与 Key 的点积相似度← 正确答案
  • B.Value 与 Key 的乘积结果
  • C.Query 与 Value 的加权和
  • D.Key 矩阵的逆再乘 Query

答案:A。$QK^\top$ 对每个查询和键做内积,数值越大代表两者越匹配。就像你拿着自己的问题去比对每位同事的名牌,匹不匹配一目了然。之后才进入 Softmax 和加权求和阶段。

Q10. 关于多头注意力的“切分”机制,下列说法正确的有?

多选题 · extreme

  • A.维度切成 h 份分别计算← 正确答案
  • B.每个头关注不同子空间模式← 正确答案
  • C.多个头结果拼接后线性投影← 正确答案
  • D.每次只用多头中的最大头

答案:ABC。多头把 Q/K/V 的特征维切分成 h 份,每份独立计算注意力,从而学习到不同子空间的模式(主谓、指代、位置邻近等),最后拼接后经 $W^O$ 投影融合。D 完全错误——所有头都会参与,没有“最大头”一说。