Skip to content
Published on

Attention Is All You Need:Transformer 论文完全解析

分享
Authors

1. 论文概述

"Attention Is All You Need" 是 2017 年在 NeurIPS 上发表的论文,由 Google Brain 和 Google Research 的 Ashish Vaswani、Noam Shazeer、Niki Parmar、Jakob Uszkoreit、Llion Jones、Aidan Gomez、Lukasz Kaiser、Illia Polosukhin 共同撰写。这篇论文表明,完全摒弃传统的 Recurrence 与 Convolution,仅凭 Attention 机制就能够构建 Sequence-to-Sequence 模型,堪称深度学习史上真正的转折点。

论文提出的 Transformer 架构在 WMT 2014 English-to-German 翻译任务上取得了 28.4 BLEU,在 English-to-French 上取得了 41.8 BLEU,超越了此前所有模型。更重要的是,这一架构此后成为了 BERT、GPT、T5、ViT 等几乎所有现代 AI 主流模型的基础。


2. 论文的背景与动机:RNN/LSTM 的局限

2.1 Sequential Processing 的瓶颈

在 Transformer 出现之前,Sequence Modeling 的标准是 RNN(Recurrent Neural Network)及其变体 LSTM(Long Short-Term Memory)、GRU(Gated Recurrent Unit)。它们按 t=1,2,...,nt = 1, 2, ..., n 的顺序处理序列,同时更新 hidden state hth_t

ht=f(ht1,xt)h_t = f(h_{t-1}, x_t)

这种顺序处理特性带来了两个根本性问题。

第一,无法并行化。 由于每个时间步的计算都依赖于前一个时间步的结果,GPU 的并行处理能力无法被有效利用。序列长度越长,训练时间就呈线性增长。

第二,Long-range Dependency 问题。 理论上 LSTM 能够学习长期依赖,但实际上序列越长,捕捉远距离 token 之间关系就越困难。这是因为所有的历史信息都必须压缩进 hidden state 这样一个固定大小的向量中。

2.2 Attention 的出现与局限

Bahdanau 等人(2014)提出的 Attention 机制,让 Decoder 能够直接访问 Encoder 的全部 hidden state,从而大幅缓解了 Long-range Dependency 问题。但由于它依然是在 RNN 之上附加Attention 的形式,Sequential Processing 的瓶颈依旧存在。

论文的核心问题正是:"抛开 Recurrence,仅靠 Attention 是否足够?"

答案是肯定的,而其成果正是 Transformer。


3. Self-Attention 机制

3.1 核心概念:Query、Key、Value

Self-Attention 的核心思想是,序列中的每个 token 直接计算自己与其他所有 token 之间的关系。为此,每个输入向量被转换为三种角色。

  • Query (Q):"我在寻找什么样的信息?"
  • Key (K):"我能提供的信息的标识符是什么?"
  • Value (V):"我实际传递的信息是什么?"

对输入序列 XRn×dmodelX \in \mathbb{R}^{n \times d_{model}},通过可学习的权重矩阵生成 Q、K、V。

Q=XWQ,K=XWK,V=XWVQ = XW^Q, \quad K = XW^K, \quad V = XW^V

其中 WQ,WKRdmodel×dkW^Q, W^K \in \mathbb{R}^{d_{model} \times d_k}WVRdmodel×dvW^V \in \mathbb{R}^{d_{model} \times d_v}

3.2 直观理解

用信息检索系统来类比会更容易理解。假设在图书馆里找书,Query 就是「深度学习入门书」这样的检索词,Key 是每本书的标题或标签,Value 是书的实际内容。Self-Attention 的本质,就是让 Query 与 Key 相似度更高的书,其 Value 被更多地取用。

Self-Attention 与 RNN 的决定性区别在于,序列内任意两个 token 之间的路径长度(path length)始终为 O(1)O(1)。RNN 是 O(n)O(n),CNN 是 O(logkn)O(\log_k n)(dilated)或 O(n/k)O(n/k)(普通)。正是这一短路径长度,让模型能够有效学习 Long-range Dependency。


4. Scaled Dot-Product Attention

4.1 公式

论文提出的 Attention 函数的精确公式如下。

Attention(Q,K,V)=softmax(QKTdk)V\text{Attention}(Q, K, V) = \text{softmax}\left(\frac{QK^T}{\sqrt{d_k}}\right)V

让我们逐步拆解这个公式。

Step 1:相似度计算(QKTQK^T

计算 Query 与 Key 的 Dot Product。结果是一个 n×nn \times n 大小的 Attention Score 矩阵。其中每个元素 (i,j)(i, j) 表示第 ii 个 token 的 Query 与第 jj 个 token 的 Key 之间的相似度。

Step 2:Scaling(1dk\frac{1}{\sqrt{d_k}}

dkd_k 越大,Dot Product 值的方差就越大,从而导致 Softmax 的梯度变得极小。具体来说,若 qqkk 的每个分量都是均值为 0、方差为 1 的独立随机变量,那么 qkq \cdot k 的方差就是 dkd_k。除以 dk\sqrt{d_k} 可以将方差归一化为 1,使 Softmax 稳定运作。

论文也通过实验验证了这一 Scaling 的重要性——当 dkd_k 较小时,Additive Attention 与 Dot-Product Attention 的性能相近;但当 dkd_k 较大时,未经 Scaling 的 Dot-Product Attention 性能会大幅下降。

Step 3:Softmax

对经过 Scaling 的 Score 应用 Softmax,得到 Attention Weight。由于每一行的总和为 1,它相当于对 Value 做加权平均时的权重。

Step 4:与 Value 的加权求和

最终,将 Attention Weight 与 Value 相乘,每个 token 的输出就是所有 token 的 Value 按相关性比例合成的向量。

4.2 Masking

在 Decoder 的 Self-Attention 中,必须防止未来 token 的信息泄露给当前 token。为此,在 Softmax 之前,会使用 Masked Attention,将未来位置对应的 Score 设为 -\infty

MaskedAttention(Q,K,V)=softmax(QKT+Mdk)V\text{MaskedAttention}(Q, K, V) = \text{softmax}\left(\frac{QK^T + M}{\sqrt{d_k}}\right)V

其中 MM 是 Upper Triangular Matrix,在不被允许的位置为 -\infty,在被允许的位置为 00


5. Multi-Head Attention

5.1 单一 Attention 的局限

如果只使用一个 Attention 函数,模型就只能从单一视角把握 token 之间的关系。例如在句子 "The cat sat on the mat because it was tired" 中,「it」指代「cat」的句法关系,与「tired」描述「cat」状态的语义关系,就很难被同时捕捉到。

5.2 Multi-Head Attention 的结构

论文通过并行运行多个 Attention 来解决这一问题。

MultiHead(Q,K,V)=Concat(head1,head2,...,headh)WO\text{MultiHead}(Q, K, V) = \text{Concat}(\text{head}_1, \text{head}_2, ..., \text{head}_h) W^O

其中每个 head 定义如下。

headi=Attention(QWiQ,KWiK,VWiV)\text{head}_i = \text{Attention}(QW_i^Q, KW_i^K, VW_i^V)

各 head 的权重矩阵为 WiQRdmodel×dkW_i^Q \in \mathbb{R}^{d_{model} \times d_k}WiKRdmodel×dkW_i^K \in \mathbb{R}^{d_{model} \times d_k}WiVRdmodel×dvW_i^V \in \mathbb{R}^{d_{model} \times d_v},最终的输出投影为 WORhdv×dmodelW^O \in \mathbb{R}^{hd_v \times d_{model}}

5.3 论文中的设置

论文使用了 h=8h = 8 个 head,并设置 dk=dv=dmodel/h=64d_k = d_v = d_{model} / h = 64。由于总维度被 head 数量均分,Multi-Head Attention 的总计算成本与 Single-Head Attention 几乎相同。

根据论文的 Ablation Study,当 head 数为 1 时 BLEU 下降了 0.9 个百分点;而当 head 数过多时(例如 32 个),dkd_k 会变得过小,反而导致性能下降。

5.4 三种使用方式

在 Transformer 中,Multi-Head Attention 被用在三个地方。

  1. Encoder Self-Attention:在 Encoder 内部,输入序列的每个 token 都会参考其他所有 token。Q、K、V 全部由前一个 Encoder 层的输出生成。
  2. Decoder Self-Attention(Masked):在 Decoder 内部,通过 Masking 使其只能参考目前为止已生成的 token。
  3. Encoder-Decoder Attention(Cross-Attention):Decoder 的 Query 参考 Encoder 的 Key、Value。这一部分与传统 Seq2Seq 模型中的 Attention 最为相似。

6. Positional Encoding

6.1 必要性

Self-Attention 本质上与顺序无关(permutation invariant)。即使改变输入 token 的顺序,Attention 的输出值(除了顺序变化之外)依然相同。而在自然语言中,语序是极为重要的信息,因此必须显式地注入位置信息。

6.2 Sinusoidal Positional Encoding

论文提出了利用正弦与余弦函数的 Positional Encoding。

PE(pos,2i)=sin(pos100002i/dmodel)PE_{(pos, 2i)} = \sin\left(\frac{pos}{10000^{2i / d_{model}}}\right) PE(pos,2i+1)=cos(pos100002i/dmodel)PE_{(pos, 2i+1)} = \cos\left(\frac{pos}{10000^{2i / d_{model}}}\right)

其中 pospos 是序列内的位置,ii 是维度索引。该 Encoding 会被加到(element-wise addition)输入 Embedding 上,再传入模型。

6.3 为什么是 Sinusoidal?

选择这一函数有明确的理由。

相对位置表示:对任意固定偏移量 kkPEpos+kPE_{pos+k} 都可以表示为 PEposPE_{pos} 的线性变换。这使得模型能够更容易学习相对位置关系。

[sin(posω+kω)cos(posω+kω)]=[cos(kω)sin(kω)sin(kω)cos(kω)][sin(posω)cos(posω)]\begin{bmatrix} \sin(pos \cdot \omega + k \cdot \omega) \\ \cos(pos \cdot \omega + k \cdot \omega) \end{bmatrix} = \begin{bmatrix} \cos(k\omega) & \sin(k\omega) \\ -\sin(k\omega) & \cos(k\omega) \end{bmatrix} \begin{bmatrix} \sin(pos \cdot \omega) \\ \cos(pos \cdot \omega) \end{bmatrix}

无需学习的泛化能力:能够自然地扩展到训练数据中未出现过的更长序列。论文将其与可学习的 Positional Embedding 进行比较后,报告称两种方式的结果「几乎相同」,并出于泛化能力的考虑,最终选择了 Sinusoidal 方式。

频率谱:维度越低(ii 越小)波长越短,用于精细的位置区分;维度越高波长越长,用于编码更大范围的位置关系。


7. Encoder-Decoder 整体架构

7.1 Encoder 结构

Encoder 由 N=6N = 6 个相同的层组成。每一层包含两个 Sub-layer。

  1. Multi-Head Self-Attention
  2. Position-wise Feed-Forward Network

每个 Sub-layer 都应用了 Residual Connection 与 Layer Normalization。

output=LayerNorm(x+Sublayer(x))\text{output} = \text{LayerNorm}(x + \text{Sublayer}(x))

7.2 Decoder 结构

Decoder 同样由 N=6N = 6 个相同的层组成,但与 Encoder 不同的是,每层包含三个 Sub-layer。

  1. Masked Multi-Head Self-Attention:为保持 Auto-regressive 特性,对未来位置进行 Masking。
  2. Multi-Head Cross-Attention:以 Encoder 的输出作为 Key、Value。
  3. Position-wise Feed-Forward Network

7.3 整体流程

输入序列经过 Embedding + Positional Encoding 后进入 Encoder,经过 6 层处理后的 Encoder 输出被传递给 Decoder 的 Cross-Attention。Decoder 以此前生成的 token 作为输入,输出下一个 token 的概率分布,这一过程会一直重复,直到出现序列结束 token。所有 Sub-layer 的输出维度都统一为 dmodel=512d_{model} = 512


8. Feed-Forward Network、Layer Normalization、Residual Connection

8.1 Position-wise Feed-Forward Network(FFN)

每个 Attention Sub-layer 之后都跟着一个 Position-wise FFN。所谓「Position-wise」,是指对每个位置(token)独立地、共享同一组权重来应用。

FFN(x)=max(0,xW1+b1)W2+b2\text{FFN}(x) = \max(0, xW_1 + b_1)W_2 + b_2

这是在两个 Linear Transformation 之间插入 ReLU 激活函数的结构。输入与输出的维度为 dmodel=512d_{model} = 512,内部维度为 dff=2048d_{ff} = 2048。也就是说,这是一个先扩展 4 倍再缩回原尺寸的 Bottleneck 结构。

这个 FFN 等价于两次 1x1 Convolution,其作用是对每个 token 进行非线性变换,把 Attention 捕捉到的关系信息转化为更丰富的表示。

8.2 Residual Connection

这是一种将每个 Sub-layer 的输入加到其输出上的 Skip Connection。

output=x+Sublayer(x)\text{output} = x + \text{Sublayer}(x)

这一设计借鉴自 ResNet,能让梯度在深层网络中顺畅流动,从而稳定训练。为使 Residual Connection 正常工作,相加的两个张量维度必须相同,这正是所有 Sub-layer 与 Embedding 的输出维度统一为 dmodel=512d_{model} = 512 的原因。

8.3 Layer Normalization

每个 Sub-layer 的输出都会应用 Layer Normalization。与 Batch Normalization 不同,Layer Normalization 是在单个样本内对所有 Feature 进行归一化,因此不依赖于批大小。

LayerNorm(x)=γxμσ+ϵ+β\text{LayerNorm}(x) = \gamma \cdot \frac{x - \mu}{\sigma + \epsilon} + \beta

其中 μ\muσ\sigma 是该层所有维度上的均值与标准差,γ\gammaβ\beta 是可学习参数。论文采用了 Post-Norm(在 Sublayer 输出 + Residual 之后应用 LN)方式。


9. 训练策略

9.1 Optimizer 与 Learning Rate Schedule

论文使用了 Adam Optimizer,同时搭配了一种独特的 Learning Rate 调度方式。这一调度方式后来被广泛称为「Noam Scheduler」。

lr=dmodel0.5min(step0.5,  stepwarmup_steps1.5)lr = d_{model}^{-0.5} \cdot \min(step^{-0.5}, \; step \cdot warmup\_steps^{-1.5})

该调度方式的核心是 Warmup。在最初的 warmup_stepswarmup\_steps(论文中为 4,000 步)内,Learning Rate 线性增加,此后则按步数的平方根倒数比例递减。

之所以需要 Warmup,是因为训练初期 Adam 的二阶矩估计并不稳定。在初期保持较低的 Learning Rate,可以防止参数发生剧烈变化,等到矩估计趋于稳定后再正式展开训练。

Adam Optimizer 的超参数为 β1=0.9\beta_1 = 0.9β2=0.98\beta_2 = 0.98ϵ=109\epsilon = 10^{-9}β2\beta_2 被设置为比常见的 0.999 更小的 0.98,这一点很特别,通常被解读为是为了适应 Attention Score 分布的快速变化。

9.2 Regularization

Residual Dropout:对每个 Sub-layer 的输出应用 Dropout(rate = 0.1)后,再进行 Residual Connection。此外,在 Encoder 与 Decoder 中,Embedding + Positional Encoding 之和也会应用 Dropout。

Label Smoothing:应用了 ϵls=0.1\epsilon_{ls} = 0.1 的 Label Smoothing。这是一种将正确类别的目标概率设为 1ϵls1 - \epsilon_{ls} 而非 1、其余类别的目标概率设为 ϵls/(K1)\epsilon_{ls} / (K - 1) 的技巧。论文报告称,Label Smoothing 会使 Perplexity 恶化,但会提升 Accuracy 与 BLEU Score。这是因为它能防止模型变得过度自信,从而提升泛化性能。

9.3 训练数据与硬件

  • WMT 2014 English-German:约 450 万个句对,使用 Byte-Pair Encoding(BPE)构建的约 37,000 个共享词表
  • WMT 2014 English-French:约 3,600 万个句对,使用 32,000 个 Word-piece 词表
  • Batch:包含约 25,000 个 Source token + 25,000 个 Target token
  • Hardware:8 块 NVIDIA P100 GPU
  • 训练时间:Base 模型约 12 小时(100K steps),Big 模型约 3.5 天(300K steps)

10. 核心实验结果

10.1 机器翻译性能

ModelEN-DE BLEUEN-FR BLEUTraining Cost (FLOPs)
Transformer (Base)27.338.13.3×10183.3 \times 10^{18}
Transformer (Big)28.441.82.3×10192.3 \times 10^{19}
既有 SOTA(含 Ensemble)26.3641.29-

Transformer Big 模型在 EN-DE 上超越了此前最佳性能超过 2 个 BLEU,在 EN-FR 上也刷新了 SOTA。更令人惊讶的是,这一性能是以既有模型训练成本的一小部分达成的。

10.2 模型规模比较

ConfigNNdmodeld_{model}dffd_{ff}hhdkd_kParameters
Base6512204886465M
Big6102440961664213M

10.3 Ablation Study 核心结果

论文的 Ablation Study 清楚地展示了每个设计决策的重要性。

  • Attention Head 数量h=1h = 1 时 BLEU 下降 0.9,h=16h = 16h=32h = 32dkd_k 变得过小,导致性能下降
  • dkd_k(Key 维度):减小会导致质量下降。直接影响 Dot-Product Attention 的表达能力
  • dmodeld_{model}(模型维度):越大性能提升越一致
  • Dropout:没有 Dropout 会发生过拟合,性能大幅下降
  • Positional Encoding:可学习方式与 Sinusoidal 方式性能几乎相同

10.4 English Constituency Parsing

为了验证在翻译任务之外的泛化能力,论文还将该架构应用于 English Constituency Parsing(句法分析)任务。仅使用 WSJ 数据取得了 91.3 F1,在半监督学习设定下取得了 92.7 F1,展现出与任务专用模型相当的竞争力。这证明了 Transformer 是一种不局限于机器翻译的通用序列模型。


11. 对后续研究的影响

Transformer 架构几乎成为了现代 AI 所有重大进展的基础。

11.1 BERT(2018,Google)

仅使用 Transformer 的 Encoder 部分,进行了双向(Bidirectional)预训练。通过 Masked Language Modeling(MLM)与 Next Sentence Prediction(NSP)这两项预训练任务,在 11 个 NLP 基准测试上取得了 SOTA。BERT 确立了 NLP 领域的 Transfer Learning 范式。

11.2 GPT 系列(2018 年~,OpenAI)

仅使用 Transformer 的 Decoder 部分,进行了 Auto-regressive Language Modeling。从 GPT-1(117M)到 GPT-2(1.5B)再到 GPT-3(175B)逐步扩大规模,证明了 Scaling Law 的威力。GPT-3 展现出了 Few-shot Learning 能力,开启了 AI 的新可能性,成为后续 ChatGPT、GPT-4 所引领的大规模语言模型(LLM)革命的起点。

11.3 此后

  • T5(2019):将所有 NLP 任务统一为 Text-to-Text 格式,使用完整的 Encoder-Decoder 结构
  • ViT(2020):将 Transformer 应用于 Computer Vision,把图像切分为 patch 后作为序列处理
  • DALL-E、Stable Diffusion:在图像生成中运用 Transformer
  • AlphaFold 2:在蛋白质结构预测中运用 Attention 机制

一篇论文,超越了 NLP,变革了 Computer Vision、生物学、音乐、机器人学等几乎所有 AI 领域。


12. PyTorch 核心代码示例

12.1 Scaled Dot-Product Attention

import torch
import torch.nn as nn
import torch.nn.functional as F
import math

def scaled_dot_product_attention(
    query: torch.Tensor,
    key: torch.Tensor,
    value: torch.Tensor,
    mask: torch.Tensor = None,
    dropout: nn.Dropout = None
) -> tuple[torch.Tensor, torch.Tensor]:
    """
    Scaled Dot-Product Attention 实现。
    Args:
        query: (batch, h, seq_len, d_k)
        key:   (batch, h, seq_len, d_k)
        value: (batch, h, seq_len, d_v)
        mask:  Attention mask (optional)
    Returns:
        output: (batch, h, seq_len, d_v)
        attention_weights: (batch, h, seq_len, seq_len)
    """
    d_k = query.size(-1)

    # Step 1 & 2: QK^T / sqrt(d_k)
    scores = torch.matmul(query, key.transpose(-2, -1)) / math.sqrt(d_k)

    # Masking(Decoder Self-Attention 等场景)
    if mask is not None:
        scores = scores.masked_fill(mask == 0, float('-inf'))

    # Step 3: Softmax
    attention_weights = F.softmax(scores, dim=-1)

    if dropout is not None:
        attention_weights = dropout(attention_weights)

    # Step 4: Weighted sum of values
    output = torch.matmul(attention_weights, value)
    return output, attention_weights

12.2 Multi-Head Attention

class MultiHeadAttention(nn.Module):
    def __init__(self, d_model: int = 512, h: int = 8, dropout: float = 0.1):
        super().__init__()
        assert d_model % h == 0, "d_model must be divisible by h"

        self.d_model = d_model
        self.h = h
        self.d_k = d_model // h

        # Q, K, V, Output 各自的 Linear projection
        self.W_q = nn.Linear(d_model, d_model)
        self.W_k = nn.Linear(d_model, d_model)
        self.W_v = nn.Linear(d_model, d_model)
        self.W_o = nn.Linear(d_model, d_model)
        self.dropout = nn.Dropout(dropout)

    def forward(
        self,
        query: torch.Tensor,
        key: torch.Tensor,
        value: torch.Tensor,
        mask: torch.Tensor = None
    ) -> torch.Tensor:
        batch_size = query.size(0)

        # 1) Linear projection 后 reshape 为 (batch, h, seq_len, d_k)
        Q = self.W_q(query).view(batch_size, -1, self.h, self.d_k).transpose(1, 2)
        K = self.W_k(key).view(batch_size, -1, self.h, self.d_k).transpose(1, 2)
        V = self.W_v(value).view(batch_size, -1, self.h, self.d_k).transpose(1, 2)

        # 2) Scaled Dot-Product Attention(所有 head 并行执行)
        attn_output, attn_weights = scaled_dot_product_attention(
            Q, K, V, mask=mask, dropout=self.dropout
        )

        # 3) 将各 head 结果 Concatenate:(batch, seq_len, d_model)
        attn_output = (
            attn_output.transpose(1, 2)
            .contiguous()
            .view(batch_size, -1, self.d_model)
        )

        # 4) Final linear projection
        return self.W_o(attn_output)

12.3 Positional Encoding

class PositionalEncoding(nn.Module):
    def __init__(self, d_model: int = 512, max_len: int = 5000, dropout: float = 0.1):
        super().__init__()
        self.dropout = nn.Dropout(dropout)

        # 生成大小为 (max_len, d_model) 的 Positional Encoding 矩阵
        pe = torch.zeros(max_len, d_model)
        position = torch.arange(0, max_len, dtype=torch.float).unsqueeze(1)  # (max_len, 1)
        div_term = torch.exp(
            torch.arange(0, d_model, 2).float() * (-math.log(10000.0) / d_model)
        )  # (d_model/2,)

        pe[:, 0::2] = torch.sin(position * div_term)  # 偶数维度: sin
        pe[:, 1::2] = torch.cos(position * div_term)  # 奇数维度: cos

        pe = pe.unsqueeze(0)  # (1, max_len, d_model) - 添加 batch 维度
        self.register_buffer('pe', pe)  # 注册为 buffer 而非可学习参数

    def forward(self, x: torch.Tensor) -> torch.Tensor:
        """
        Args:
            x: (batch, seq_len, d_model) - Embedding 输出
        Returns:
            (batch, seq_len, d_model) - 加上 Positional Encoding 后的结果
        """
        x = x + self.pe[:, :x.size(1), :]
        return self.dropout(x)

12.4 Transformer Encoder Layer

class TransformerEncoderLayer(nn.Module):
    def __init__(self, d_model: int = 512, h: int = 8, d_ff: int = 2048, dropout: float = 0.1):
        super().__init__()

        # Sub-layer 1: Multi-Head Self-Attention
        self.self_attn = MultiHeadAttention(d_model, h, dropout)
        self.norm1 = nn.LayerNorm(d_model)
        self.dropout1 = nn.Dropout(dropout)

        # Sub-layer 2: Position-wise FFN
        self.ffn = nn.Sequential(
            nn.Linear(d_model, d_ff),
            nn.ReLU(),
            nn.Dropout(dropout),
            nn.Linear(d_ff, d_model),
        )
        self.norm2 = nn.LayerNorm(d_model)
        self.dropout2 = nn.Dropout(dropout)

    def forward(self, x: torch.Tensor, mask: torch.Tensor = None) -> torch.Tensor:
        # Sub-layer 1: Self-Attention + Residual + LayerNorm
        attn_output = self.self_attn(x, x, x, mask)
        x = self.norm1(x + self.dropout1(attn_output))

        # Sub-layer 2: FFN + Residual + LayerNorm
        ffn_output = self.ffn(x)
        x = self.norm2(x + self.dropout2(ffn_output))

        return x

上述代码中,self.self_attn(x, x, x, mask) 的 Q、K、V 全部来自同一个输入 x,这正是被称为「Self」-Attention 的原因。若是 Cross-Attention,则只需将 K 与 V 换成 Encoder 的输出即可。


13. 结语

"Attention Is All You Need" 并不只是提出了一个机器翻译模型。它打破了 Recurrence 这一由来已久的惯性,用实证证明了「仅靠 Attention 就足够」这一大胆主张。

这篇论文的核心贡献可以总结如下。

  1. 去除 Recurrence:以可并行处理的架构大幅提升训练速度
  2. Self-Attention:以 O(1)O(1) 路径长度直接建模序列中所有 token 之间的关系
  3. Multi-Head Attention:从多个视角同时捕捉关系
  4. Scalability:简洁而可扩展的架构设计,使后续可以扩展到数十亿乃至数万亿参数的模型

自这篇论文发表的 2017 年以来,Transformer 已经超越 NLP,扩散到 Vision、Audio、Biology、Robotics 等几乎所有 AI 领域。正如论文标题所说,Attention 确实就是 All You Need。


参考资料