
作为深度学习领域的奠基之作,《Attention Is All You Need》在深度学习和自然语言处理的交叉领域提出了一种名为 Transformer 的全新(针对 2017 年)网络架构。它旨在解决主流序列转换模型(如机器翻译)中广泛使用的循环神经网络(RNN)和卷积神经网络(CNN)所固有的序列计算限制问题。传统模型由于其顺序处理的特性,难以并行化,并且在捕捉长距离依赖关系方面存在显著挑战。
该文章的核心亮点在于完全摒弃了传统且常见的二循环和卷积机制,而是仅仅依赖于注意力机制(Attention Machanism),尤其是 多头注意力机制(Multi-Head Self Attention) 来捕捉序列间的全局依赖关系。这种架构可以实现高度的并行化,因而显著缩短了模型的训练时间。实际上它也是当时在 WMT 机器翻译任务上的 SOTA 模型,有效证明了其模型架构的优越性。
整个文章的细节主要在第三部分Model Architecture(废话),这一部分详细叙述了 Transformer 的基本组成和关键思路
编码/解码器
与常规的 RNN 相同, Transformer 同样采用经典的 编码 – 解码(Encoder – Decoder) 机制 。所谓 编码/解码,论文是这么表述的:
“Here, the encoder maps an input sequence of symbol representations $(x_1,x_2,…,x_n)$ to a sequence of continuous representations $\mathbb{z} = (z_1,z_2,…,z_n)$. Given $\mathbb{z}$, the decoder then generates an output sequence $(y_1,y_2,…,y_m)$ of symbols one element at a time.”
也就是将输入序列 $x$ 通过某种变换映射到新的、连续的序列 $z$ 上,进而通过 $z$ 我们逐元素的得出输出序列 $y$ 对应的元素。
嗯… 一如既往的不讲人话
我们来想一个问题 – “The cat sat on the mat” 这句话应该怎么翻译?
你当然可以 “The cat – 这只猫” “sat – 坐” “on the mat – 在垫子上” 然后就有”The cat sat on the mat – 这只猫坐在垫子上”,这看上去是听一个词翻译一个(实际上也不完全是,比如你会认为”on the mat “才是一个完整的词元,这也是一种信息处理),这似乎是可行的,那么这句呢:
“To put it simply , Prime Minister , certain informal discussions took place, involving a full and exchange of views , out of which there arose a series of proposals which proved to indicate certain promising lines of inquiry , which , when pursued , led to the realisation that the alternative courses of action , might , in fact , in certain circumstances , be susceptible of discreet modification , leading to a reappraisal of the areas of difference and pointing the way to encouraging possibilities of compromise and cooperation , which ,if bilaterally implemented with appropriate give and take on both sides , might , if the climate were right , have a possibility , at the end of the day , of leading , rightly or wrongly , to a mutually satisfactory resolution.”
—— “Yes Prime Minister” S2P5
采用和上面相同的策略,我们得到了这么个结果:
“简单地说,首相,某些非正式讨论发生了涉及全面和交换意见,从中产生了一系列提案.这些提案被证明指示某些有希望的研究方向,这些方向,当被追求时,导致认识到替代行动方案,可能,事实上,在某些情况下,容易进行谨慎修改,导致对分歧领域的重新评估并指出妥协和合作的令人鼓舞的可能性,这些可能性,如果双边实施并双方适当让步,可能,如果气候合适,有机会,最终,无论对错,导致一个相互满意的解决方案。”
这或许看得懂但很显然很扯淡。我们需要捕捉整句话的语法、实体、时态以及它们之间的关系,最终形成一个抽象的、不依赖于任何特定语言的“意义”表示,而不是一堆似是而非的词语堆砌。这同样也是编码器需要做的。它的唯一任务就是接收完整的输入序列,并将其“编码”成一个富含信息的中间表示。这个中间表示,我们通常称之为上下文向量(Context Vector)或“思想向量”。
对应到技术实现上,编码器需要接受一个完整的原序列,并通过其内部的网络神经层对整个输入序列进行抽象处理,这在Transformer以前通常由 RNN 和 LSTM 实现,而 Transformer 中则是自注意力层(见下文)进行实现。
但 RNN 和 LSTM 的实现有一个问题。通常这时的 Encoder 最后只会输出一个固定大小的向量,这个向量是 RNN 最后一个时间步的隐藏状态.虽然理论上它压缩了整个输入序列的精华,但因为其长度固定,就必然会存在信息瓶颈。上面的例子可以视为固定向量长度为 1 的情况,显然对于长句,很多早期的信息会丢失,造成翻译质量的明显下降。
Transformer 下的 Encoder 的输出则不只是一个向量,而是一系列向量(和输入词一样多)。每个向量都富含了对应位置单词以及通过自注意力机制融合了上下文后的信息。这就比单个向量信息量大得多。而在解码的每一步,虽然和 RNN 或者 LSTM 的解码器一样是一个一个 输出,但 Transformer 的解码器因为可选空间更多,会计算一个注意力分布,来决定“回头看”输入的哪个部分。
而在整个编码 – 解码架构中,最重要的就是编码器如何将信息传递给解码器。这座“桥梁”的设计,同样也是不同模型间最核心的区别。
如上文提及,传统的 Seq2seq 是通过一个固定大小的上下文向量进行传递,解码器在每个时间步都只使用这样一个完全相同的向量。这很显然会造成信息损失
在 Transformer 架构下,桥梁则是编码器-解码器注意力层(Encoder-Decoder Attention Layer),这样的注意力子层遍布解码器的每一个层。
- 它的查询(Query) 来自于解码器自身(前一个子层的输出,代表了“我现在想知道什么信息”)。
- 它的键(Key) 和 值(Value) 全部来自于编码器的最终输出(那一整套向量,代表了源句子的所有信息)。
这就使得解码器的每一步、每一层都能直接、并行地访问到输入序列的所有信息,并根据需要动态地提取最相关的信息,极其强大和灵活。
注意力/注意力机制
前面说 Transformer 的特色是注意力,那么在深度学习中,“注意力”到底是什么?注意力是一种机制(或者就叫“注意力机制”),旨在让模型处理输入数据时能够聚焦于当前的关键部分,忽略无关信息。与心理学上的注意力不同,此处注意力的本质是一种数学上的加权策略:通过计算不同部分的重要性分数,动态分配更多计算资源到相关元素上。
点积缩放注意力(Scaled Dot-Product Attention, SDPA)
Paper 在 3.2.1 节对 SDPA 做出了一个很好的抽象:
We call our particular attention “Scaled Dot-Product Attention” . The input consists of queries and keys of dimension $d_k$, and values of dimension $d_v$ . We compute the dot products of the query with all keys, divide each by $\sqrt{d_k}$, and apply a softmax function to obtain the weights on the values.
大意是输出由维度为 $k$ 的查询 $Q$ 和键值对($K-V$)组成,输出则通过计算 查询 和 键的点积( $Q\cdot K$ )并使用 Softmax 筛选最佳 Logits。也就是说,我们将一个查询(Query)和一系列键值对(Key-Value pairs)映射到一个输出。输出是值的加权和,权重由查询与对应键的“兼容性函数”计算得出。
点积操作在这是相当合理的,因为考虑点积几何意义,两个向量的点积本身就是其方向的接近程度的体现。点积越大,意味着两个向量在方向上越接近,关联性越强。
值得注意的是这块还有一个 trick ,点积通过除以维度的根号值进行缩放,防止 Softmax 不稳定。
最后将上一步得到的注意力权重矩阵与值矩阵 $V$ 相乘。其效果是相当于每个位置的输出加权和。注意力权重越高的值向量,对最终输出的贡献越大。
多头注意力 (Multi-Head Attention, MHA)
这是 Paper 在 3.2.2 节提及的另一种注意力(或者说是对 SDPA 的另一种计算形式?)。他的计算方式与 SDPA 完全一致,不同的是计算时的维度。换而言之,我们同样可以视 MHA 为一个更高层次的结构,它并行地运行了多个 SDPA 实例。而 SDPA(Scaled Dot-Product Attention)则抽象为实现注意力计算的那个具体、核心的数学函数。
具体而言,与其在 $d_{model}$ (例如512) 的高维度上进行一次 SDPA 计算,MHA 将这个高维度分解成 h 个 $d_k$ (例如 512/8 = 64) 的低维度空间。每个头都在这个更小的、独立的子空间内进行 SDPA 计算。论文中给出的数学表述为:
$$\text{MultiHead}(Q, K, V) = \text{Concat}(\text{head}_1, …, \text{head}_h)W^O \\\text{where head}_i = \text{Attention}(QW_i^Q, KW_i^K, VW_i^V)$$
详细拆解一下:
- $W_i^Q, W_i^K, W_i^V$: 这些是线性投影矩阵,是模型需要学习的参数。对于 h 个“头”中的第 i 个头,原始的 Q, K, V 矩阵分别与这三个矩阵相乘,被投影到更低的维度。
- $\text{head}_i$: 每个头独立地执行一次缩放点积注意力计算。由于投影矩阵不同,每个头可以学习关注输入序列的不同方面的特征。例如,一个头可能关注语法关系,另一个可能关注语义关联。
- $\text{Concat}(…)$: 将 h 个头的输出结果在特征维度上拼接起来。
- $W^O$: 另一个需要学习的线性投影矩阵,将拼接后的高维向量重新投影回模型期望的维度 $d_{model}$。
为什么要这么做?
除了并行化提高效率外,MHA 有一个更重要的作用。它将“注意力”这个单一的任务分解了。一个单一的注意力头必须学会在一种模式下关注所有类型的信息(比如,既要关注语法结构,又要关注语义关联)。这可能会导致不同类型的信息相互干扰。MHA 允许不同的头成为“专家”,每个头可以学习关注输入序列中不同方面的关系。
所以和卷积核的输出通道类似,与其说是纯粹的“分解运算”,我更倾向于将 MHA 描述为“多视角”或“多通道”的集成学习(Ensemble Learning)。模型在这不是把一个大问题拆开算,而是从 h 个不同的视角(子空间)同时观察同一个问题,然后综合所有视角的观察结果,得出最终结论。
实际上,这点在论文中也有提及:
“With a single attention head, averaging inhibits this.”
如果只有一个注意力头,那么它计算出的权重是对所有信息的一种“妥协”或“平均”。比如,在 “The animal didn’t cross the street because it was too tired” 这句话中,单个注意力头在处理”it”时,可能既要关注”animal”(语义指代),又要关注句法上的其他词。最终的注意力权重可能是多种需求的混合,导致对”animal”的关注强度被削弱。而 MHA 可以让一个头专门负责指代消解,另一个头关注动词关系等,每个头都可以产生非常“尖锐”和明确的注意力分布,从而捕捉到更清晰、更细节的特征。
同时, MHA 通过将输入投影到 h 个不同的表示子空间(由 $W_i^Q, W_i^K, W_i^V$ 决定),模型有机会学习到输入序列的多样化特征。就像我们看一张图片,可以同时关注它的颜色、纹理、轮廓等不同方面。每个头捕捉到的一方面信息,在最终拼接后,就形成了一个比单一表示更丰富、更全面的特征向量。这也正是 Transformer 设计的绝妙之处!
位置前馈网络(Position-wise Feed-Forward Networks)
这是 Paper 3.3 节提出的另一个结构,同时也是 Encoder 和 Decoder 中每层的另一个子层,它对每个位置的向量进行独立且相同的变换。
我们可以这么理解:MHA 对输入进行了拆解和思考,得到的中间结果需要整理后才能输出,那么前馈网络就是干“思考后整理“这活的。
从结构上看, FFN 其实非常简单,就是一个包含两层线性变换和一个 ReLU 激活函数的全连接网络。
$$\text{FFN}(x) = \text{max}(0, xW_1 + b_1)W_2 + b_2$$
- 第一层线性变换 ($xW_1 + b_1$): 将输入向量 x 从 d_model 维度(例如 512)扩展到一个更高的维度 d_ff(例如 2048)。
- ReLU 激活函数 ($\text{max}(0, …)$): 对扩展后的向量进行非线性变换。这是至关重要的一步。
- 第二层线性变换 ($…W_2 + b_2$): 将向量从 d_ff 维度压缩回原始的 d_model 维度(例如 512)。
这个“先扩展,后压缩”的模式在深度学习中非常常见,我习惯性称它为 “瓶颈”
FFN 本身很常见,这里的关键在于 Position-wise(逐位置)。
逐位置本身是独立性的一种体现,FFN 对序列中的每个位置(每个词的向量)进行这个完全相同的变换的时候,只会使用第 i
个词的输入向量,完全不考虑其他位置的词。这就实现了对每个位置的信息的独立深加工。
但 FFN 同时也由关联性,虽然对每个位置的操作是独立的,但它们共享同一套 $W_1, b_1, W_2, b_2$ 参数
是不是想到了什么?对,卷积的平移不变性!
实际上,FFN 的操作在实现上等价于使用两个核大小为 1×1 的卷积层。也就是 Conv1D(filters=d_ff, kernel_size=1)
和 Conv1D(filters=d_model, kernel_size=1)
。
但此时还有一个问题,思考后整理的模块有很多,为什么偏偏选择 FFN ?
首先是引入非线性能力,我们知道非线性是神经元学习能力的重要实现途径,Transformer 架构中,除了激活函数,大部分操作(矩阵乘法、加法)都是线性的。如果去掉 FFN,那么多层注意力堆叠在一起,其效果近似于一个线性模型。FFN 中的 ReLU 激活函数是模型非线性能力的主要来源。没有非线性,模型就无法学习输入和输出之间更复杂的映射关系,表达能力会大打折扣。
其次是前文提及的信息整合和提炼,通过两层网络(尤其是非线性网络) FFN 能够识别出混合信息中有价值的模式。而通过最后的压缩操作, FFN 强制模型将高维空间中发现的有用特征转换为原始的、更紧凑的编码并传入下一个 Encoder/Decoder 层。
位置编码 (Positional Encoding)
这是 Paper 在 3.5 节提到的一个类似于位置处理的 Tirck,因为序列的位置本身也是有有价值的信息的,但 Transformer 本身不包括循环和卷积,所以必须有某种方式注入序列的顺序信息。
Paper 在这采用的是缩放在一个周期的 $\sin$ 和 $\cos$ 进行位置标注:
$$PE_{(pos, 2i)} = \sin(\text{pos} / 10000^{2i/d_{\text{model}}}) \\PE_{(pos, 2i+1)} = \cos(\text{pos} / 10000^{2i/d_{\text{model}}})$$
- $pos$ 是词在序列中的位置(从 0 开始)。
- $i$ 是向量的维度索引(从 0 开始)。
这个公式为每个位置 $pos$ 生成一个 $d_{model}$ 维度的位置编码向量。向量的每个维度对应一个不同频率的正弦或余弦波。
这种设计还是挺巧妙的,对于任意固定的偏移量 $k$,$PE_{pos+k}$ 可以表示为 $PE_{pos}$ 的线性函数。这使得模型能轻易地学习到相对位置关系。
不过这是一种硬编码而非自适应,虽然原文的实验证明其有效,但我们能不能提出了更多,更柔和的替代方案?
Some Questions
Transform 作为注意力机制的经典之作毫无疑问其架构是非常精妙的,但模型本身不可能处处完美,实际上,距离论文发表也已过了 8 年之久。综合注意力机制的后续发展,我们在此对模型的部分可能的不足做一些讨论:
- 二次方计算复杂度:自注意力机制需要计算序列中每两个词之间的关系,导致其计算复杂度和内存消耗都是序列长度 n 的二次方($O(n^2)$)。这使得 Transformer 难以处理非常长的序列(如长文档、高分辨率图像、音频等)。
- 缺乏归纳偏置:与 RNN 的时序偏置或 CNN 的局部性偏置不同,Transformer 的结构性假设较少。虽然这赋予了它极大的灵活性,但也意味着它在数据量较少时可能比 RNN 或 CNN 更难训练,需要更多数据来学习序列的结构信息。
- 位置编码的有效性:在上文业已提及
- 模型的可解释性:这是 DL 领域老生常谈的问题了,虽然论文在附录中展示了注意力权重的可视化,并声称其有助于理解模型行为(如解决指代消解),但注意力权重是否真的等同于模型的“解释”?
以上
2025 . 10
发表回复