具身智能论文伴读 | 第一期 | 精读 05|Attention Is All You Need | 把“注意力“拆解成 query-key-value,以及√dk
精读 Transformer|3.2 Attention:把"注意力"拆解成 query-key-value,以及那个 √dk 到底在防什么


本节的阅读地图
3.2 这一节作者采用的是**“先给通用定义,再给自己的具体实现,最后论证为什么这样实现”** 的三段式:
先用一个高度抽象的定义说清"注意力函数"到底是什么(不绑定任何具体算法);然后进入 3.2.1,给出自己采用的具体版本——Scaled Dot-Product Attention,把抽象定义落成一个矩阵公式;最后花两整段做对比论证:先和另一种主流注意力(加性注意力)比效率,再解释自己为什么要多加一个 √dk 的缩放因子。
读的时候,请把注意力放在最后那个 √dk 上。它是全节唯一一处"我们做了一个别人没做的小改动",而作者用了将近一段篇幅去论证它——论文里被反复论证的小细节,往往才是真正的贡献点。
逐句拆解
An attention function can be described as mapping a query and a set of key-value pairs to an output, where the query, keys, values, and output are all vectors.
这是全节的地基句,给注意力下了一个不依赖任何具体实现的抽象定义。请务必先建立起 query(查询)、key(键)、value(值) 这三个角色的直觉,后面所有公式都是它们的变奏。
一个流传很广、也确实好用的类比是图书馆检索:你带着一个查询(query)去找书,书架上每本书贴着一个标签(key),书的内容(value) 才是你真正想要的东西。你拿 query 去和每个 key 比对,看哪本书的标签跟你的需求最匹配,匹配度高的书,它的内容就在最终结果里占更大比重。注意这里的关键设计:key 和 value 是成对的(key-value pairs)——标签用来"被匹配",内容用来"被取出",两者分工不同但一一对应。
句末的 all vectors :query、key、value、output 全都是向量。这意味着"匹配"和"取出"都将是向量运算,为下文的点积和加权求和铺好了路。
The output is computed as a weighted sum of the values, where the weight assigned to each value is computed by a compatibility function of the query with the corresponding key.
这句把抽象定义再往前推一步,点明输出的计算方式,拆成两个动作:
其一,输出是值的加权和(weighted sum of the values)。weighted sum是加权求和:有的值更重要,分配的权重就大;不重要的,权重就小。结果=(值1×权重1)+(值2×权重2)+(值3×权重3)\text{结果} = (\text{值}_1 \times \text{权重}_1) + (\text{值}_2 \times \text{权重}_2) + (\text{值}_3 \times \text{权重}_3)结果=(值1×权重1)+(值2×权重2)+(值3×权重3)回到图书馆的类比——最终结果不是只取最匹配那一本书,而是把所有书的内容按匹配度加权混合。这一点很重要:注意力是"软"的,它不做非黑即白的选择,而是给每个 value 分配一个权重,再全部加起来。
其二,每个 value 的权重(the weight assigned to each value),由 query 与其对应 key 的 compatibility function(相容性函数/兼容性函数) 算出。
需要注意的是,compatibility function 并不是一个像 convolution、attention 本身那样有固定实现的专业术语,它更像是作者临时造的一个"统称"或者"接口名"。在注意力机制的相关文献里,这一类计算通常被称为 similarity function(相似度函数) 或 affinity function(亲和性函数)——本质上就是在衡量 query 和 key 之间"有多接近、多匹配"。作者选择用 compatibility(相容性) 这个词,某种程度上是在有意地"抽象化":不直接告诉你底层用什么公式去算这个"匹配程度",而是先把它当成一个可以往里塞任何具体实现的接口/占位符,就像定义一个抽象方法一样,先声明"这里存在一个函数,用来产出权重",但具体是加性也好、点积也好,暂不指定。
这样处理有它的巧妙之处:先把整体框架搭起来,把可替换的部件留成一个接口式的"占位符",再在后面具体小节里逐一填入实现细节(比如后文对比的点积 vs 加性两种版本)。这提示我们,作者在这里是先做了一层抽象封装,用 compatibility function 这个通用说法把"如何衡量匹配程度"这件事包起来,具体实现留给下文展开。
你自己写方法论的时候,也可以借鉴这种写法:面对一族相似的方法,先抽象出共同的框架和接口(哪怕临时起一个不那么"标准"的名字),再在细节部分突出自己填的是哪一块具体实现。
We call our particular attention “Scaled Dot-Product Attention” (Figure 2).
从这里开始,占位符要被填上了。注意 our particular attention——“我们这一种特定的注意力”。前面定义的是通用框架,现在作者要给出自己的具体实现。这个名字本身就是一份浓缩的说明书:Dot-Product(点积) 交代了相容性函数怎么算(用点积),Scaled(缩放的) 交代了那个即将成为重点的改动(要除以一个东西)。读到一个方法的命名时,不妨先拆开它的每个词,往往能预判整个机制。
The input consists of queries and keys of dimension dk, and values of dimension dv.
给出维度设定。query 和 key 的维度都是 dkd_kdk,value 的维度是 dvd_vdv。
这里有个值得停顿的细节:query 和 key 的维度必须相同(都是 dkd_kdk),而 value 的维度可以不同(是 dvd_vdv)。为什么?因为 query 和 key 之间要做点积,而点积要求两个向量维度一致——你无法对两个长度不同的向量做点积。value 则不参与这个匹配运算,它只是被加权取出,所以维度可以独立设定。下标 kkk 对应 key、ddd 对应 value 的 dimension,这套记号一看就能对上角色。
We compute the dot products of the query with all keys, divide each by √dk, and apply a softmax function to obtain the weights on the values.
这是用文字完整走了一遍算法流程,三步:
第一步,拿 query 和所有 key 做点积——这就是前面那个"相容性函数"的具体填充:用点积来衡量匹配度。两个向量越"同向",点积越大,匹配度越高。
第二步,每个点积结果都除以 dk\sqrt{d_k}dk——这就是名字里"Scaled"的来源,先记住有这么一步,原因留到本节末尾专门论证。
第三步,套一个 softmax。softmax 的作用是把一组任意实数转成一组"非负且加起来等于 1"的权重,正好符合"加权和里权重"的要求。经过 softmax,原本较大的点积会得到较大的权重,较小的得到较小的权重,而且所有权重构成一个概率分布。这组权重,就是要施加在 value 上的。
In practice, we compute the attention function on a set of queries simultaneously, packed together into a matrix Q. The keys and values are also packed together into matrices K and V.
从"逐个"到"批量"的工程化表述。
前面是按单个 query 描述的,但实际计算时不会一个一个 query 地算——那太慢。作者把一批 query 打包(packed) 成一个矩阵 QQQ,同样把所有 key、value 分别打包成 KKK、VVV。这样一来,原本需要循环处理的一堆向量运算,就变成了几次矩阵乘法。
留意 In practice(在实践中) 这个信号词。它标志着叙述从"数学上是什么"切换到"工程上怎么高效实现"。这个从"逐元素定义"到"矩阵批处理"的跳转,正是 Transformer 能在 GPU 上高速并行的根源——也呼应了上一节它彻底摆脱 RNN 那种"必须一步接一步"的串行计算。
Attention(Q,K,V)=softmax(QKTdk)V(1)\text{Attention}(Q, K, V) = \text{softmax}\left(\frac{QK^T}{\sqrt{d_k}}\right)V \quad (1)Attention(Q,K,V)=softmax(dkQKT)V(1)
这就是整节的核心公式,把前面文字描述的三步压缩成一行。逐块对照着读:
QKTQK^TQKT 一次性算出了所有 query 与所有 key 的两两点积。若 QQQ 有 nnn 个 query、KKK 有 mmm 个 key,那么 QKTQK^TQKT 是一个 n×mn \times mn×m 的矩阵,第 (i,j)(i,j)(i,j) 个元素正是"第 iii 个 query 和第 jjj 个 key 的匹配分数"。这就是文字里"query 和所有 key 做点积"的矩阵化。
dk\frac{}{\sqrt{d_k}}dk 是那步缩放,对整个分数矩阵逐元素除以 dk\sqrt{d_k}dk。
softmax(⋅)\text{softmax}(\cdot)softmax(⋅) 对矩阵的每一行做归一化——每一行对应一个 query 对所有 key 的注意力分布,行内加起来为 1。
最后右乘 VVV,就是拿这组权重去对 value 做加权求和,得到最终输出。整个公式读下来,和前面的文字流程严丝合缝——先用文字讲清逻辑、再用一个公式收拢,这是本论文一贯的节奏(上一节的 LayerNorm 公式也是如此)。
The two most commonly used attention functions are additive attention [2], and dot-product (multiplicative) attention. Dot-product attention is identical to our algorithm, except for the scaling factor of √(1/dk).
进入对比论证。
作者开始把自己的方法放到已有方法的坐标系里。当时最常用的注意力有两种:additive attention(加性注意力) 和 dot-product / multiplicative attention(点积/乘性注意力)。注意 multiplicative(乘性) 是 dot-product 的别名——因为点积本质是逐元素相乘再相加,故称"乘性",与"加性"正好构成一对命名上的对照。
这里作者明说自己的算法除了那个 1dk\frac{1}{\sqrt{d_k}}dk1 的缩放因子之外,和标准点积注意力完全相同(identical … except for)。也就是说,点积注意力本身不是作者的发明,作者唯一动的地方就是加了个缩放。这种坦白划清了"继承"与"贡献"的界线,等于在说:真正值得我论证的,就这一处。 学术写作中,主动、清晰地说明"我和前人只差在哪里",是基本的规范要求。
Additive attention computes the compatibility function using a feed-forward network with a single hidden layer.
这句填上了加性注意力的"相容性函数"是什么:它不用点积,而是用一个带单隐层的前馈网络来计算 query 和 key 的匹配度。你可以回想本节开头那个故意留白的"compatibility function"——现在两种注意力的差异,恰恰就体现在它们各自用什么函数来填这个空:一个用简单的点积,一个用一个小神经网络。前面埋的框架,在这里显出了它的好处:两种方法的对比,被清楚地定位到了同一个部件上。
While the two are similar in theoretical complexity, dot-product attention is much faster and more space-efficient in practice, since it can be implemented using highly optimized matrix multiplication code.
这是作者选择点积而非加性注意力的理由。两者在理论复杂度(theoretical complexity) 上相近,但在实践中(in practice),点积注意力快得多、也更省内存。
原因说得很实在:点积注意力可以直接用高度优化的矩阵乘法代码(highly optimized matrix multiplication code) 来实现。这是一个非常"接地气"的工程论点——矩阵乘法是数值计算中被优化到极致的操作,GPU、专用库(如 BLAS)对它有大量针对性加速。加性注意力那个前馈网络反而享受不到这种红利。请注意这里"理论 vs 实践"的对照修辞:理论上打平,实践中却因为能复用成熟的高效算子而胜出。 这提醒我们,方法的优劣不只看渐进复杂度,能否落到高效实现上同样关键——这是一个很有价值的科研判断视角。
While for small values of dk the two mechanisms perform similarly, additive attention outperforms dot product attention without scaling for larger values of dk [3].
位置:引出问题——为缩放因子做铺垫。
前面说点积快,但这句话锋一转,抛出一个"效果上"的隐患。在 dkd_kdk 较小时,两种机制表现相当;可一旦 dkd_kdk 较大,不带缩放的点积注意力就打不过加性注意力了 [3]。
注意 without scaling(不加缩放) 这个限定词——它是整段论证的枢纽。作者是在说:点积注意力有个短板,但这个短板是"不缩放时"才有的。这句话摆出问题(点积在高维时会退化),下一句给出对问题的诊断,再下一句给出解药。"摆问题—诊断原因—给出对策"这个三拍子,是论证一个设计决策最标准的结构,值得记住并模仿。
We suspect that for large values of dk, the dot products grow large in magnitude, pushing the softmax function into regions where it has extremely small gradients.
这是诊断:作者推测,当 dkd_kdk 很大时,点积的数值会变得很大,从而把 softmax 推入梯度极小的区域。
值得留意作者的措辞是 We suspect(我们推测),而非"我们证明"。这是科研写作里恰当的谦抑表达——对于一个基于直觉、未经严格证明的机理解释,用 suspect、we hypothesize 之类的词,既传达了自己的判断,又不越界宣称已经证实。这是一种学术诚实,也是自我保护。
至于机理本身,可以这样理解。假设 query 和 key 的每个分量都是均值 0、方差 1 的独立随机变量,那么它们的点积 q⋅k=∑i=1dkqikiq \cdot k = \sum_{i=1}^{d_k} q_i k_iq⋅k=∑i=1dkqiki 是 dkd_kdk 个项的和,其方差会随 dkd_kdk 线性增长到 dkd_kdk(标准差约为 dk\sqrt{d_k}dk)。也就是说,维度越高,点积的取值范围就越被拉大。而 softmax 有一个特性:当输入里某个值远远大于其他值时,它会近乎饱和——输出几乎变成一个 one-hot 向量(某一项接近 1,其余接近 0)。函数一旦饱和,它在这些点上的梯度就趋近于 0。梯度接近 0,反向传播时几乎学不动,训练就会停滞。这就是"较大 dkd_kdk 拖累不缩放点积"的根源。
To counteract this effect, we scale the dot products by √(1/dk).
对策——收束全节。
对策登场:为了抵消(counteract) 这个效应,把点积乘以 1dk\frac{1}{\sqrt{d_k}}dk1(即除以 dk\sqrt{d_k}dk)。
现在回头看这一步的巧妙之处。前面推断出点积的标准差大约是 dk\sqrt{d_k}dk,那么除以 dk\sqrt{d_k}dk,恰好能把点积的方差重新拉回到 1 附近,与维度无关。这样一来,无论 dkd_kdk 取多大,进入 softmax 的数值都被控制在一个合理范围内,softmax 就不会被推入饱和区,梯度也就得以保持健康。名字里那个 Scaled 的全部意义,到这里才彻底揭晓——它不是随手加的装饰,而是一个针对"高维点积导致 softmax 梯度消失"这一具体问题、且量纲上恰好对症的补丁。
至此,本节的三拍子完整闭环:摆问题(高维时不缩放的点积会退化)→ 诊断(点积变大 → softmax 饱和 → 梯度消失)→ 对策(除以 dk\sqrt{d_k}dk,把方差压回来)。
今日知识点
英文表达
- An attention function can be described as mapping A to B:给一个机制下抽象定义的经典句式,
be described as比is更留有余地,暗示这是一种"可以这样理解"的刻画。 - compatibility function:相容性/兼容性函数,衡量 query 与 key 匹配程度的函数;在下定义时可用它作"占位符",把具体实现留到后文。
- our particular attention:“我们所采用的这一种特定的……”,用于从通用框架切入自己的具体实现。
- is identical to … except for …:“除了……之外,与……完全相同”,精准划清"继承"与"改动"边界的高频表达,能让读者一眼锁定你的贡献点。
- In practice, …:实践信号词,标志叙述从"数学定义"切换到"工程实现"。
- While the two are similar in … , X is much faster in practice:"理论上相当,但实践中 X 更优"的对照句式,用于论证方法选择。
- We suspect that …:谦抑表达,用于陈述基于直觉、尚未严格证明的机理推测;同类还有 we hypothesize、we conjecture。
- To counteract this effect, we …:“为抵消这一效应,我们……”,给出对策、收束"问题—诊断—对策"论证链的收尾句。
顺手攒个小词
本节反复出现表"效率高"的两个词值得分辨。faster 指"速度快、耗时短",衡量的是时间;space-efficient 指"省空间、省内存",衡量的是存储。作者说点积注意力 “much faster and more space-efficient”,是从时间和空间两个正交维度同时夸它——这也是评价一个算法开销时的标准双维度。写作中若想全面说明效率优势,记得时间与空间两头都提;只说"efficient"一词则含糊,不如拆开来讲清是快还是省。
科研知识
- 面对一族相似的方法,先抽象出共同框架、把可替换部件留成"占位符"(如本节的 compatibility function),再在具体小节填入自己的选择,是清晰且专业的写法。
- 方法的优劣不能只看理论复杂度;能否落到"高度优化的成熟算子"(如矩阵乘法)上,往往决定实践中的真实效率。这是一个重要的工程—科研结合视角。
- 论证一个设计决策的标准结构是"摆问题 → 诊断原因 → 给出对策"三拍子。本节对 dk\sqrt{d_k}dk 的论证是教科书式范例。
- 对未经严格证明的机理解释,应使用 we suspect / we hypothesize 等谦抑措辞,既表达判断又不越界宣称已证实,这是学术诚实的体现。
- 缩放因子 1dk\frac{1}{\sqrt{d_k}}dk1 的选择有量纲依据:高维点积的标准差约为 dk\sqrt{d_k}dk,除以它可将方差归一化到 1 附近,防止 softmax 进入梯度趋零的饱和区。设计"补丁"时,让它在量纲/统计意义上恰好对症,比拍脑袋取值更可信。
- 论文中被反复、细致论证的小细节(哪怕只是一个缩放因子),往往正是作者真正的用心与贡献所在,阅读时应重点对待。
一句话带走:注意力的本质是"用 query 与各 key 的匹配度作权重,对 value 做加权求和";Transformer 采用点积形式是为了复用高效的矩阵乘法,又因高维点积会使 softmax 饱和、梯度消失,故额外除以 dk\sqrt{d_k}dk 把数值方差压回可控范围——这便是 “Scaled Dot-Product Attention” 名字里每个词的由来。
DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。
更多推荐



所有评论(0)