2018 年 6 月,Lilian Weng(当时 OpenAI 应用研究员,后任研究副总裁)在她的个人博客 Lil'Log 上写下这篇《Attention? Attention!》。它是整整一代深度学习工程师理解注意力机制的入门标准教材之一——被引用了上万次,被翻译成十几种语言。文章从一只穿西装的柴犬开始——用人类的视觉注意力做类比;接着把注意力机制的所有关键分支梳理一遍——Bahdanau 加性注意力的诞生、6 种打分函数家族、自注意力、软硬注意力、全局/局部、神经图灵机、指针网络、Transformer 的 QKV 与多头机制、SAGAN 与 SNAIL。本文是这篇综述的中文精校版,约 1.3 万字。
Lilian Weng 用一只穿男装的柴犬开篇。当人类看这张图时——会把视觉"高分辨率"焦点放在尖耳朵,把"低分辨率"留给雪地背景和外套。注意力的本质——"重要性权重向量"。在深度学习里,它就是用一个向量来描述"输出某个元素时,应该多关注输入的哪些部分"。同样的逻辑适用于自然语言——看到"吃"就预期出现食物词;颜色词描述食物,但跟"吃"本身关系不大。
2018 年 6 月,Lilian Weng——当时 OpenAI 的应用研究员(后来成为 OpenAI 研究副总裁,2024 年离开创办自己的 AI Safety 公司)——在她的个人博客 Lil'Log 上写下这篇《Attention? Attention!》。
这篇文章不是论文——但它影响力大过很多论文。它是整整一代深度学习工程师、研究生、学者第一次系统理解注意力机制的入门标准教材之一。8 年过去,它依然是 Google 搜索"attention mechanism"排名最靠前的中文/英文学习资源之一。
Lilian 用一个让人会心一笑的开头——一只穿男装的柴犬照片(来自 Instagram 上的 @mensweardog)。
她说——人类的视觉注意力让我们把"高分辨率"聚焦在某一片区域(比如照片里那对尖耳朵),同时用"低分辨率"感知周围环境(雪地背景、外套)。然后我们可以调整焦点或进行推理。
给定图像的一小块——其他位置的像素给了线索来告诉我们应该看到什么。"我们在那个黄色框里预期看到尖耳朵——是因为我们已经看到了狗鼻、右边另一个尖耳朵、柴犬神秘的眼睛——这些 doggy features 才是线索。底部的毛衣和毯子帮不上忙。"
同样的逻辑适用于自然语言——看到"吃",我们预期下一个词是食物。颜色词描述食物,但跟"吃"本身关系不大。
Lilian 用一句话总结了注意力的本质——
简而言之——
深度学习里的注意力可以广义地解释为——
一个"重要性权重"的向量。
为了预测或推理某一个元素——
比如图像里的一个像素,或句子里的一个词——
我们用注意力向量估计
它与其他元素的关联强度,
然后用注意力向量加权求和它们的值,
作为目标的近似。
Attention 不是凭空出现的——它诞生在 Sutskever 2014 年的 Seq2Seq 框架的一个具体痛点上——固定长度上下文向量记不住长句子。Encoder-Decoder 把整个源序列压成一个固定长度的"上下文向量"——结果常常等读完整个句子时,已经忘了前面一部分。Attention 的诞生(Bahdanau 2015)——不是构造单一上下文向量,而是在上下文向量和整个源输入之间架"快捷连接"。
Attention 不是凭空出现的。它诞生在一个具体的痛点上。
这个痛点叫Seq2Seq 模型(Sutskever, et al. 2014)。Seq2Seq 模型试图把一个输入序列(source)变成另一个序列(target)——两个序列可以是任意长度。典型任务——机器翻译、对话生成、句法分析。
Seq2Seq 模型通常是编码器-解码器架构——
· 编码器处理输入序列,把信息压成固定长度的"上下文向量"(也叫 sentence embedding 或 "thought" 向量)。这个表示应该是整个源序列含义的良好总结。
· 解码器用这个上下文向量初始化,产出转换后的输出。早期工作只用编码器网络的最后一个状态作为解码器初始状态。
· 编码器和解码器都是循环神经网络——LSTM 或 GRU 单元。
这个设计的关键、明显的缺陷——固定长度上下文向量记不住长句子。"常常等读完整个输入时,已经忘了前面一部分"。
这就是 attention 诞生的契机——Bahdanau et al. 2015。
Bahdanau 等人的关键创新——不构造单一上下文向量,而是在上下文向量和整个源输入之间架"快捷连接"。这些快捷连接的权重对每一个输出元素都是可定制的。上下文向量消费三部分信息——编码器隐藏状态、解码器隐藏状态、源与目标之间的对齐。对齐分数由一个带单隐层的前馈网络(tanh 激活)参数化——和模型其他部分共同训练。这就是"加性注意力"。
Bahdanau 等人的 2015 ICLR 论文《Neural Machine Translation by Jointly Learning to Align and Translate》——给神经机器翻译第一次引入了 attention。
关键创新——不是从编码器的最后一个隐藏状态构造一个单一的上下文向量,而是在上下文向量和整个源输入之间架"快捷连接"。这些快捷连接的权重对每一个输出元素都可以定制。
"上下文向量可以访问整个输入序列,所以我们不用担心遗忘"。源与目标之间的对齐由上下文向量学习并控制。
形式化定义——假设源序列 $x = [x_1, x_2, \ldots, x_n]$ 长度 $n$,输出目标序列 $y = [y_1, y_2, \ldots, y_m]$ 长度 $m$(粗体表示向量)。
编码器是双向 RNN——前向隐藏状态 $\vec{h}_i$ 和后向 $\overleftarrow{h}_i$。简单拼接两个就是编码器状态——动机是让一个词的注释同时包含前文和后文。
解码器在位置 $t$ 有隐藏状态 $\boldsymbol{s}_t = f(\boldsymbol{s}_{t-1}, y_{t-1}, \boldsymbol{c}_t)$。其中上下文向量 $\boldsymbol{c}_t$ 是输入隐藏状态的加权和——权重是对齐分数——
输出 $y_t$ 的上下文向量
$\alpha_{t,i}$ 表示"对齐"两个词 $y_t$ 和 $x_i$ 的程度——它是预定义对齐分数的 softmax。
在 Bahdanau 的论文里,对齐分数 $\alpha_{t,i}$ 由一个带单隐层的前馈网络参数化(tanh 激活)——和模型其他部分共同训练——
其中 $\boldsymbol{v}_a$ 和 $\boldsymbol{W}_a$ 是对齐模型里要学的权重矩阵。这就是"加性注意力"(additive attention)。
对齐分数矩阵是这个机制的"好副产品"——它显式地展示源词和目标词之间的相关性。Lilian 引用了 Bahdanau 论文里那张著名的图——法语 "L'accord sur l'Espace économique européen a été signé en août 1992" 与其英文翻译 "The agreement on the European Economic Area was signed in August 1992" 之间的对齐矩阵——清楚地展示了哪些词对应哪些词,是可解释性的一个早期典范。
有了 Bahdanau 的加性注意力,"源和目标之间的依赖不再被中间距离限制"——这个想法很快从机器翻译扩散到计算机视觉(Xu et al. 2015),各种打分函数相继被提出。Lilian 总结了 6 个家族——内容基础(Graves 2014)、加性(Bahdanau 2015)、位置基础(Luong 2015)、一般(Luong 2015)、点积(Luong 2015)、缩放点积(Vaswani 2017)。缩放点积就是后来 Transformer 用的——除以 $\sqrt{n}$ 是为了避免输入大时 softmax 梯度过小。
有了 Bahdanau 的加性注意力,"源和目标之间的依赖不再被中间距离限制"——这个想法很快从机器翻译扩散到计算机视觉(Xu et al. 2015),各种打分函数相继被提出(Luong 2015、Britz 2017、Vaswani 2017)。
Lilian 用一张表总结了 6 种流行的注意力机制和对应的对齐分数函数——
| 名字 | 对齐分数函数 | 引用 |
|---|---|---|
| 内容基础 Content-based | $\text{score}(\boldsymbol{s}_t, \boldsymbol{h}_i) = \cos[\boldsymbol{s}_t, \boldsymbol{h}_i]$ | Graves 2014 |
| 加性 Additive | $\text{score}(\boldsymbol{s}_t, \boldsymbol{h}_i) = \boldsymbol{v}_a^\top \tanh(\boldsymbol{W}_a [\boldsymbol{s}_{t-1}; \boldsymbol{h}_i])$ | Bahdanau 2015 |
| 位置基础 Location-base | $\alpha_{t,i} = \text{softmax}(\boldsymbol{W}_a \boldsymbol{s}_t)$ 仅依赖目标位置 | Luong 2015 |
| 一般 General | $\text{score}(\boldsymbol{s}_t, \boldsymbol{h}_i) = \boldsymbol{s}_t^\top \boldsymbol{W}_a \boldsymbol{h}_i$ $\boldsymbol{W}_a$ 是可训练权重 | Luong 2015 |
| 点积 Dot-Product | $\text{score}(\boldsymbol{s}_t, \boldsymbol{h}_i) = \boldsymbol{s}_t^\top \boldsymbol{h}_i$ | Luong 2015 |
| 缩放点积 Scaled Dot-Product | $\text{score}(\boldsymbol{s}_t, \boldsymbol{h}_i) = \dfrac{\boldsymbol{s}_t^\top \boldsymbol{h}_i}{\sqrt{n}}$ $n$ 是源隐藏状态维度 | Vaswani 2017 |
缩放点积注意力跟点积注意力几乎相同,只多了一个缩放因子 $1/\sqrt{n}$。动机——当输入向量较大时,softmax 函数的梯度会变得极小,导致训练困难。除以 $\sqrt{n}$ 把点积的方差控制住,让 softmax 落在梯度有意义的范围内。这是 Vaswani 2017 在 Transformer 里的关键工程细节——少了它,Transformer 就训练不好。
Lilian 还把更广义的"分类"列出来——按"关注什么"分——
· 自注意力(Self-Attention)——关联同一序列里不同位置(Cheng 2016)
· 全局/软(Global/Soft)——关注整个输入状态空间(Xu 2015)
· 局部/硬(Local/Hard)——只关注输入状态空间的一部分(Xu 2015、Luong 2015)
接下来三章我们逐一讲。
自注意力(self-attention,也叫 intra-attention)是一种把同一个序列的不同位置关联起来的注意力机制——目的是计算同一序列的表示。它在机器阅读、抽象摘要、图像描述生成等任务上都被证明很有用。LSTM 网络的那篇论文用了 self-attention 做机器阅读——self-attention 让模型能学到"当前词"和"句子前面部分"之间的相关性。理论上,self-attention 可以采用上面任何一个打分函数——只是把目标序列换成同一个输入序列。
自注意力——也叫 intra-attention——是一种把同一个序列的不同位置关联起来的注意力机制——目的是计算同一序列的表示。
它已经被证明在机器阅读、抽象摘要、图像描述生成等任务上非常有用。
LSTM 网络的论文(Cheng 2016)用自注意力做机器阅读——self-attention 让模型能学到"当前词"和"句子前面部分"之间的相关性。Lilian 给的图——当前词标红,蓝色阴影的大小表示激活程度。看完图你能很直观地感觉到 self-attention 在"读句子"时关注的位置。
理论上——self-attention 可以采用上面表格里任何一个打分函数。只是把目标序列换成同一个输入序列而已。
这个简单的"换成自己"就解锁了一切。后来的 Transformer、BERT、GPT、Claude——它们的核心机制都是 self-attention。
软注意力 vs 硬注意力是 Xu 2015 提出的——基于注意力是否能访问整个图像。软(Soft)——权重"软地"落在所有 patch 上,平滑可微,但大输入时贵。硬(Hard)——一次只选一个 patch关注,推理时计算少,但不可微——需要方差缩减或强化学习训练。Luong 2015 提出 全局 vs 局部——全局类似 soft;局部是软硬之间的有趣混合——先预测目标的对齐位置,然后在源端用一个窗口计算上下文向量——让 hard attention 变得可微。
在《Show, Attend and Tell》(Xu et al. 2015)里,attention 机制被应用到图像上做 caption 生成。图像先用 CNN 编码提取特征,然后LSTM 解码器消费卷积特征一个词一个词地生成描述——权重通过 attention 学习。
注意力权重的可视化清楚地展示了模型为输出某个词而关注图像的哪些区域。Xu 给的例子——"A woman is throwing a frisbee in a park"——你能清楚看到模型生成 "frisbee" 时关注圆盘,生成 "park" 时关注草地。
这篇论文第一次区分了"软" vs "硬" 注意力——基于"注意力是否能访问整个图像"——
Luong 2015 提出了"全局" vs "局部" 注意力——
全局注意力类似软注意力——关注整个源端。
局部注意力是软和硬之间的有趣混合——一种对硬注意力的改进,让它可微。
模型先预测当前目标词的单个对齐位置,然后以这个源位置为中心的窗口用来计算上下文向量。这样既保留了"只关注局部"的高效,又通过"软窗口"恢复了可微性。
1936 年 Alan Turing 提出图灵机——无限长的纸带 + 一个可读写、可左右移动的头。理论上图灵机能模拟任何计算机算法。神经图灵机(NTM)——Graves、Wayne、Danihelka 2014——是把神经网络和外部存储耦合的模型架构。内存模拟图灵机的纸带,神经网络控制读写头。NTM 的内存是有限的 $N \times M$ 矩阵——所以它"更像神经版冯诺依曼机"。读写都通过"软关注所有内存地址"实现——NTM 用混合的"内容基础 + 位置基础"寻址。
1936 年 Alan Turing 提出了一个极简的计算模型——无限长的纸带 + 一个可与纸带交互的"头"。纸带有无数格子,每格填一个符号——0、1 或空白。操作头可以读符号、改符号、向左右移动。理论上图灵机可以模拟任何计算机算法——不管多复杂。
无限内存让图灵机数学上无极限——但现实中不可行,所以我们只把图灵机当数学模型。
神经图灵机(Neural Turing Machine, NTM)——Graves、Wayne、Danihelka 2014——是把神经网络和外部存储耦合的模型架构。内存模拟图灵机的纸带,神经网络控制读写头。但 NTM 的内存是有限的,所以它"可能更像神经版冯诺依曼机"。
NTM 有两大组件——
· 控制器(Controller)——负责执行内存操作。可以是任何神经网络——前馈或循环。
· 内存库(Memory)——存储处理过的信息。是一个$N \times M$ 矩阵——$N$ 个向量行,每行 $M$ 维。
在一个更新迭代里——控制器处理输入,与内存库交互产生输出。交互通过并行的读写头实现——读写都是"模糊"的——软地关注所有内存地址。
读——时刻 $t$ 读内存时,大小为 $N$ 的注意力向量 $\boldsymbol{w}_t$ 控制对不同内存位置的关注。读出向量 $\boldsymbol{r}_t$ 是按注意力加权求和——
写——受 LSTM 的输入门和遗忘门启发——先用擦除向量 $\boldsymbol{e}_t$ 擦掉一些旧内容,再用添加向量 $\boldsymbol{a}_t$ 加上新信息——
NTM 用混合的"内容基础 + 位置基础"寻址——
· 内容寻址——基于控制器从输入提取的键向量 $\boldsymbol{k}_t$ 和内存行之间的相似度计算注意力。用余弦相似度+ softmax,加一个强度乘子 $\beta_t$ 来放大/弱化分布的聚焦。
· 插值门 $g_t$——混合"新生成的内容寻址注意力"和"上一时刻的注意力权重"。
· 位置寻址——按整数位移分布加权对注意力向量做1D 卷积。然后用锐化标量 $\gamma_t \geq 1$ 增强分布。
NTM 是"attention 作为可微计算工具"的早期范例——它告诉我们 attention 不只是对齐,还可以是读写、寻址、计算本身。
排序、旅行商问题(TSP)这类问题——输入输出都是序列,但输出元素的离散类别取决于变长输入——传统 seq2seq 解决不了。指针网络(Ptr-Net)(Vinyals 2015)——当输出元素对应输入序列里的位置时使用。它不把编码器隐藏状态混合成上下文向量,而是对输入元素施加注意力,每一步直接选一个作为输出。输出只对应位置,不对应内容——非常巧妙地把attention 改造成"指针"。
排序、旅行商问题(TSP)这类问题——输入输出都是序列,但不能被经典 seq2seq 或 NMT 模型轻易解决——因为输出元素的离散类别取决于变长输入。
指针网络(Ptr-Net)——Vinyals 2015——解决了这一类问题——当输出元素对应输入序列里的位置时使用。
它的关键创新——不用注意力把编码器隐藏单元混合成上下文向量,而是对输入元素施加注意力,每一步直接选一个作为输出。
形式化——Ptr-Net 给定输入向量序列 $\boldsymbol{x} = (x_1, \ldots, x_n)$,输出整数索引序列 $\boldsymbol{c} = (c_1, \ldots, c_m)$,其中 $1 \leq c_i \leq n$。
编码器和解码器隐藏状态分别记作 $(\boldsymbol{h}_1, \ldots, \boldsymbol{h}_n)$ 和 $(\boldsymbol{s}_1, \ldots, \boldsymbol{s}_m)$。$\boldsymbol{s}_i$ 是解码器里细胞激活后的输出门。
Ptr-Net 在状态之间用加性注意力,然后用softmax 归一化建模输出条件概率——
注意力机制被简化——因为 Ptr-Net 不把编码器状态混合到输出。这样输出只对应位置,不对应输入内容。
Ptr-Net 是 attention 的巧妙变体——它让 attention 从"给输出加权重"变成"给输出点位置"——本质上把 attention 改造成了"指针"。
"Attention is All You Need"(Vaswani 2017)——Lilian 直言"2017 年最具影响力和最有趣的论文之一"——展示了大量对软注意力的改进,让无需 RNN 也能做 seq2seq 建模。Transformer 完全建立在自注意力机制上。秘诀都在架构里——把编码后的输入看成键-值对 $(\boldsymbol{K}, \boldsymbol{V})$,解码器把上一输出压成查询 $\boldsymbol{Q}$。缩放点积注意力——$\boldsymbol{Q}$ 和 $\boldsymbol{K}$ 算点积,除以 $\sqrt{n}$,过 softmax,加权 $\boldsymbol{V}$。多头——并行跑多次,拼接,线性变换——"让模型从不同位置不同表示子空间联合关注信息"。
《Attention is All You Need》——Vaswani 2017——Lilian 直言"毫无疑问,2017 年最具影响力和最有趣的论文之一"。它带来了对软注意力的大量改进,让不用循环网络也能做 seq2seq 建模。Transformer 完全建立在自注意力机制上——没有任何序列对齐的循环架构。
秘诀都在架构里。
Transformer 的核心组件是多头自注意力机制单元。Transformer 把编码后的输入表示看作键-值对 $(\boldsymbol{K}, \boldsymbol{V})$——都是维度 $n$(输入序列长度)。在 NMT 上下文里,键和值都是编码器隐藏状态。
解码器把上一个输出压成查询 $\boldsymbol{Q}$(维度 $m$)。下一个输出由把这个查询和键-值集合映射产生。
Transformer 用缩放点积注意力——输出是值的加权和,权重由查询和所有键的点积决定——
多头自注意力——不只算一次注意力,而是并行跑多次缩放点积注意力。各自独立的注意力输出简单拼接,然后线性变换到期望的维度——
Lilian 用一句典型的 Lil'Log 幽默吐槽——"我猜动机是因为集成学习总是有用? ;)" 然后引用论文里更严肃的版本——"多头注意力让模型能从不同位置不同表示子空间联合关注信息。用单头注意力,平均会抑制这一点"。
其中 $\boldsymbol{W}^Q_i, \boldsymbol{W}^K_i, \boldsymbol{W}^V_i, \boldsymbol{W}^O$ 是要学的参数矩阵。
Lilian 还简要讲了编码器和解码器架构——
编码器——
· $N = 6$ 个相同层的堆叠
· 每层有一个多头自注意力子层+ 一个位置 feed-forward 网络
· 每个子层用残差连接 + 层归一化
· 所有子层输出维度 $d_{\text{model}} = 512$
解码器——
· $N = 6$ 个相同层
· 每层有两个多头注意力子层 + 一个 feed-forward
· 同样残差连接 + 层归一化
· 第一个多头注意力子层被修改——防止位置关注后续位置(不能看未来)
最后——源和目标序列先过嵌入层变成相同维度 $d_{\text{model}} = 512$;为保留位置信息,用正弦波位置编码加到嵌入上;最终softmax + 线性层。
Transformer 的完整架构图——是过去 8 年里被引用最多的那张神经网络图。Lilian 自己也开源了一份 TensorFlow 实现——lilianweng/transformer-tensorflow。
最后 Lilian 讲两个把 attention 扩展到不同领域的例子——SNAIL(Mishra 2017)把自注意力 + 时序卷积合起来解决 Transformer 的位置敏感问题——用于元学习(meta-learning)。Self-Attention GAN(SAGAN,Zhang 2018)把自注意力加进 GAN——让生成器和判别器更好地建模空间区域之间的关系。DCGAN 用卷积,被filter size 限制——一像素的特征只能依赖小局部。SAGAN 用自注意力显式学习一像素和所有其他位置的关系——"轻松捕捉全局依赖"。Lilian 在结尾预告了一篇关于"改进的 Transformer 模型"的后续文章。
Transformer 没有循环或卷积结构——即使加了位置编码,序列顺序仅被弱地纳入。对于对位置依赖敏感的问题——比如强化学习——这可能是大问题。
Simple Neural Attention Meta-Learner(SNAIL)——Mishra 2017——部分为解决 Transformer 的位置问题而生——把 Transformer 的自注意力机制和时序卷积结合。它在监督学习和强化学习任务上都展现良好——诞生在元学习领域("meta-learning 是另一个值得自成一篇的话题"——Lilian 后来真的写了一篇)。
简单说——元学习模型期望泛化到相似分布里没见过的新任务。
Self-Attention GAN(SAGAN)——Zhang 2018——把自注意力层加进 GAN——让生成器和判别器都能更好地建模空间区域之间的关系。
为什么需要?经典 DCGAN(深度卷积 GAN)把判别器和生成器都用多层卷积网络表示。问题——网络的表示能力被 filter size 限制——一像素的特征仅限于小局部区域。为了连接远距离区域,特征必须穿过多层卷积稀释——依赖关系不一定能维持。
"视觉上的(软)自注意力显式设计为学习一像素和所有其他位置(即使距离很远)的关系——能轻松捕捉全局依赖"。所以装了自注意力的 GAN 应该处理细节更好。
SAGAN 用非局部神经网络来计算注意力。卷积图像特征图 $\boldsymbol{x}$ 分成三个副本——对应 Transformer 里的键、值、查询——
然后应用点积注意力输出自注意力特征图——
$\alpha_{i,j}$ 是注意力图里的一个条目——表示合成第 $j$ 位置时模型应该多关注第 $i$ 位置。$\boldsymbol{W}_f, \boldsymbol{W}_g, \boldsymbol{W}_h$ 都是 $1 \times 1$ 卷积滤波器。
注意力层的输出再乘以一个缩放参数 $\gamma$,加回原始输入特征图——
训练时$\gamma$ 从 0 渐进增大——网络先依赖局部区域线索,再渐进学会给远距离区域分配更多权重。SAGAN 生成的 128×128 例子图像显著好于传统 DCGAN。
Lilian 在结尾预告了她 2020 年 4 月写的后续文章——《改进的 Transformer 模型》——继续这条线讲下去。
2018 年这篇综述结束时,
Lilian 没有想到——
5 年后她会成为 OpenAI 的研究副总裁,
"attention 机制"
会成为整个 AI 时代的底层抽象。
但她已经把所有的种子种在这一篇文章里——
Bahdanau 的对齐、自注意力、QKV、多头⋯⋯
这是互联网时代
最具教学价值的一篇综述。