🔄 Transformer 架构深度拆解

从 Self-Attention 到 Multi-Head Attention,从位置编码到完整架构——
理解现代 AI 最核心的技术基石

PAGE 03 · 中级 · 预计阅读 25 分钟

📜 一、Transformer 诞生的背景

🔁 RNN/LSTM 的瓶颈

在 Transformer 出现之前,循环神经网络(RNN)及其变体 LSTM(Long Short-Term Memory)是序列建模的主流方法。但它们存在几个根本性的局限:

问题 1:串行计算 — RNN 必须逐步处理序列:先处理第 1 个词,再处理第 2 个词……无法并行化。在 GPU 上,这意味着大量计算资源被浪费。

问题 2:长期依赖衰减 — 当序列很长时,早期信息在反复传递中逐渐"遗忘"。虽然 LSTM 引入了门控机制缓解了这个问题,但在处理超长序列(如整篇文章)时仍然力不从心。

问题 3:梯度消失/爆炸 — 反向传播时梯度在时间步上连乘,容易导致训练不稳定。

RNN 的处理方式(串行)

词₁ → [RNN] → 词₂ → [RNN] → 词₃ → [RNN] → …
⏱️ 必须等上一步完成才能处理下一步

Transformer 的处理方式(并行)

词₁ ──┐
词₂ ──┼──→ [Self-Attention] → 全部同时处理
词₃ ──┘
⚡ 所有词同时处理,充分利用 GPU

🔗 Seq2Seq 模型的局限

Seq2Seq(Sequence-to-Sequence)模型使用编码器将输入序列压缩成一个固定长度的向量,再用解码器生成输出序列。这个架构虽然突破了定长输入的限制,但固定长度的上下文向量成为信息瓶颈——无论输入多长,都被压缩进同一个向量中,信息不可避免地丢失。

2015 年引入的注意力机制(Bahdanau Attention)允许解码器在生成每个词时"回头看"编码器的不同位置,缓解了信息瓶颈。这为 Transformer 的诞生埋下了伏笔。

出处:Bahdanau, D., Cho, K. & Bengio, Y. (2015). "Neural Machine Translation by Jointly Learning to Align and Translate." ICLR 2015. arXiv:1409.0473

💡 "Attention Is All You Need" 的核心思想

2017 年 6 月,Google Brain 团队的 8 位研究者发表了论文 "Attention Is All You Need",提出了 Transformer 架构。其核心思想极其大胆:

完全抛弃 RNN 和 CNN,仅用注意力机制来建模序列关系。

论文认为:既然注意力机制已经能解决 RNN 的信息瓶颈问题,为什么不干脆去掉 RNN,让注意力机制独立承担全部工作?实验证明,这样做不仅在翻译任务上达到了当时的最优水平(BLEU 28.4),而且训练速度大幅提升(比当时最优模型快 8 倍)。

为什么叫 "Attention Is All You Need"?

标题本身就是一个宣言:我们之前用 RNN、CNN、各种复杂的门控机制来做序列建模,但实际上,注意力机制就已经足够了。你需要的全部(All You Need),就是注意力。这个标题既简洁又充满自信,后来也成为了 AI 领域最著名的论文标题之一。

出处:Vaswani, A. et al. (2017). "Attention Is All You Need." NeurIPS 2017. arXiv:1706.03762

🏗️ 二、Transformer 整体架构

📐 编码器-解码器架构

原始 Transformer 采用经典的 Encoder-Decoder 架构。编码器负责理解输入,解码器负责生成输出。两者都由 N 个相同结构的层堆叠而成(论文中 N=6)。

▼ 输出(逐词生成)
Output: "Je suis étudiant"
解码器 Decoder(×N 层)
Masked
Multi-Head
Attention
Multi-Head
Attention
(交叉)
Feed
Forward
▲ 交叉注意力
编码器 Encoder(×N 层)
Multi-Head
Self-Attention
Feed
Forward
输入嵌入 + 位置编码
Input Embedding + Positional Encoding
▼ 输入文本
"I am a student"

🔄 完整数据流

数据从输入到输出的完整路径如下:

1

输入嵌入(Input Embedding)

将每个 token(词/子词)转换为 d_model 维的向量(论文中 d_model=512)。类似词向量(Word Embedding),但维度更高。

2

位置编码(Positional Encoding)

在嵌入向量上叠加位置信息。因为自注意力机制本身没有顺序概念,需要显式告诉模型每个词的位置。

3

编码器(Encoder)

输入序列经过 N 层编码器,每层包含:Multi-Head Self-Attention → Add & Norm → Feed-Forward → Add & Norm。输出是编码后的"上下文表示"。

4

解码器(Decoder)

已生成的输出序列经过 N 层解码器,每层额外包含"交叉注意力"——让解码器关注编码器的输出。最后通过线性层 + Softmax 输出概率分布。

⚡ 与 RNN 的关键区别:并行计算

维度 RNN / LSTM Transformer
计算方式 串行(逐步处理) 并行(同时处理所有位置)
长距离依赖 信息随距离衰减 任意两个位置直接交互
训练速度 慢(无法充分并行) 快(充分利用 GPU 并行)
位置信息 隐含在处理顺序中 需要额外添加位置编码
最大路径长度 O(n),序列越长路径越长 O(1),任意两个词之间直接连接
出处:Vaswani, A. et al. (2017). "Attention Is All You Need." NeurIPS 2017. Table 1 & Section 3.2.

🎯 三、自注意力机制(Self-Attention)深度拆解

📚 Q、K、V 的直觉理解——图书馆检索类比

自注意力机制的核心是三个矩阵:Query(查询)Key(键)Value(值)。一个绝佳的类比是图书馆检索系统:

📖 想象你走进图书馆:

Query(查询) = 你心中的问题——"我想找一本关于量子力学的书"

Key(键) = 每本书的标签/标题——"《量子力学导论》《红楼梦》《Python编程》……"

Value(值) = 书的内容本身

你用 Query 去匹配所有 Key,找到最相关的书,然后取出对应的 Value(内容)。

在 Transformer 中,每个词都会生成自己的 Q、K、V:

  • Q:这个词"想知道"什么信息
  • K:这个词"能提供"什么信息(给其他词参考)
  • V:这个词的"实际内容"(被选中后传递给其他词)

📐 数学公式

Attention(Q, K, V) = softmax(QKT / √dk) V

让我们逐项拆解:

QKT — 查询与所有键的点积,衡量"相关性"。点积越大 = 两个词越相关。
每个词的 Q 与所有词的 K 做点积,得到一个 n×n 的"注意力分数矩阵"。
√dk — 缩放因子。dk 是 Key 向量的维度。
为什么要除以 √dk?因为当维度很大时,点积的值会很大,导致 softmax 函数进入梯度非常小的饱和区域。除以 √dk 可以保持数值稳定。
softmax — 将分数转换为概率分布(所有权重之和 = 1)。
作用:决定每个词应该"关注"其他词的程度。权重高的词,其 Value 会被更多采用。
× V — 用注意力权重加权求和所有 Value。
最终结果:每个位置获得一个"融合了其他位置信息"的新表示。

🔢 数值示例:逐步计算

假设句子 "The cat sat on the mat",我们只取前 3 个词来演示。设 dk = 4:

Step 1:输入嵌入矩阵 X(3×4)经过三个线性变换得到 Q、K、V:

Q = X · WQK = X · WKV = X · WV
其中 WQ、WK、WV 是可学习的权重矩阵(维度 4×4)

Step 2:计算注意力分数(以 "cat" 的 Q 为例):

Qcat · Kthe1T = 2.1,Qcat · KcatT = 4.8,Qcat · KsatT = 1.3

除以 √dk = √4 = 2:
→ 1.05,2.4,0.65

Step 3:Softmax 归一化:

e1.05 = 2.86, e2.4 = 11.02, e0.65 = 1.92
softmax = [2.86, 11.02, 1.92] / (2.86+11.02+1.92) = [0.181, 0.696, 0.123]

→ "cat" 关注 "The" 18.1%,关注 "cat" 自身 69.6%,关注 "sat" 12.3%

Step 4:加权求和 Value:

Outputcat = 0.181 × Vthe1 + 0.696 × Vcat + 0.123 × Vsat
→ 得到一个融合了上下文信息的 4 维向量

👁️ 可视化:注意力矩阵

注意力矩阵展示了每个词对其他词的"关注程度"。以 "The cat sat on the mat" 为例:

注意力权重矩阵(颜色越深 = 关注越多)

The
cat
sat
on
The
0.10
0.55
0.25
0.10
cat
0.18
0.70
0.12
0.00
sat
0.05
0.15
0.60
0.20
on
0.00
0.05
0.30
0.65

解读:"cat" 最关注自身(70%)和 "The"(18%),因为它需要确定自己是主语。
"sat" 既关注 "cat"(15%,主语)也关注 "on"(20%,介词),因为动词需要搭配。
这是一个简化示意——实际训练后的注意力模式会更加复杂和有意义。

🧩 四、多头注意力(Multi-Head Attention)

🤔 为什么要多头?

单个注意力头只能从"一个角度"看待词与词之间的关系。但语言中的关系是多种多样的:

Head 1
🔗

关注语法关系
主语 → 谓语

Head 2
📐

关注指代消解
it → 前面的名词

Head 3
🌈

关注语义相似性
近义词、同义表达

Head 4
📍

关注位置关系
相邻词、远距离词

直觉:就像人看一幅画——一个人从色彩角度欣赏,另一个人从构图角度分析,第三个人关注画中的故事。多个"视角"合在一起,才能得到更全面的理解。多头注意力让模型同时从多个子空间学习不同类型的注意力关系。

📐 计算过程

MultiHead(Q, K, V) = Concat(head₁, head₂, ..., headh) WO

其中 headi = Attention(Q WiQ, K WiK, V WiV)
1

线性投影

将 Q、K、V 分别通过 h 组不同的权重矩阵投影到 h 个低维子空间。每个头的维度 dk = dmodel / h(如 512/8=64)。

2

并行计算

在 h 个子空间中分别独立计算缩放点积注意力。每个头关注不同方面的关系。

3

拼接(Concat)

将 h 个头的输出拼接起来,得到 dmodel 维的向量。

4

线性变换

通过输出权重矩阵 WO 将拼接结果映射回 dmodel 维,得到最终的 Multi-Head Attention 输出。

论文使用了 h = 8 个注意力头。由于每个头的维度是 dmodel/h = 64,总的计算量与单头注意力(dk = dmodel = 512)几乎相同,但能捕获更丰富的关系模式。

出处:Vaswani, A. et al. (2017). "Attention Is All You Need." NeurIPS 2017. Section 3.2.2.

🔄 三种注意力使用场景

类型Q 来源K,V 来源作用
Self-Attention 同一序列 同一序列 编码器内部 / 解码器内部
Masked Self-Attention 同一序列 同一序列(掩码) 解码器:防止"看到未来"
Cross-Attention 解码器 编码器输出 解码器关注输入信息

📍 五、位置编码(Positional Encoding)

❓ 为什么需要位置编码?

自注意力机制有一个"致命弱点":它本身是排列不变的(Permutation Invariant)。也就是说,把 "猫 吃 鱼" 和 "鱼 吃 猫" 输入自注意力层,如果没有额外的位置信息,模型认为它们的含义完全一样!

RNN 天然通过处理顺序来编码位置信息(先处理的词 = 位置靠前),但 Transformer 的自注意力是并行处理所有词的,丢失了顺序信息。因此需要显式地注入位置信息

📐 正弦-余弦位置编码

原始 Transformer 使用的是固定的正弦-余弦编码,其优雅之处在于不需要学习参数:

PE(pos, 2i) = sin(pos / 100002i/dmodel)
PE(pos, 2i+1) = cos(pos / 100002i/dmodel)

其中:

  • pos = 词在序列中的位置(0, 1, 2, 3, ...)
  • i = 维度索引(0, 1, 2, ..., dmodel/2 - 1)
  • dmodel = 模型维度(论文中 = 512)

设计原理:

低频维度(i 较小):波长长,变化慢 → 编码"粗粒度"的位置信息
高频维度(i 较大):波长短,变化快 → 编码"细粒度"的位置信息
线性关系:对于任意固定偏移 k,存在一个线性变换 M 使得 PEpos+k = M · PEpos
这意味着模型可以轻松学习相对位置关系!

位置编码可视化(简化示意)

sin
cos
sin
cos
sin
cos
sin
cos
sin
cos
sin
cos
sin
cos
sin
cos
sin
cos
sin
cos
sin
cos
sin
cos

行 = 位置(pos 0, 1, 2),列 = 维度。
左侧(低频维度)颜色变化明显,能区分不同位置;
右侧(高频维度)颜色相近,提供细微的位置差异。

🔄 可学习的位置编码 vs 固定位置编码

类型说明代表模型
固定正弦-余弦 使用三角函数,无需学习参数,天然支持外推到更长序列 原始 Transformer (2017)
可学习绝对编码 位置编码作为可训练参数,模型自己学习最优的位置表示 BERT、GPT-2、ViT
相对位置编码 编码两个位置之间的"距离"而非绝对位置,泛化能力更强 T5、Transformer-XL
旋转位置编码 (RoPE) 通过旋转变换编码相对位置,兼具绝对和相对位置信息 LLaMA、Qwen、PaLM
出处:Shaw, P. et al. (2018). "Self-Attention with Relative Position Representations." NAACL 2018; Su, J. et al. (2021). "RoFormer: Enhanced Transformer with Rotary Position Embedding." arXiv:2104.09864

⚙️ 六、其他关键组件

📐

Feed-Forward Network

每个注意力层之后都有一个前馈网络(FFN),由两个线性变换 + ReLU 激活组成。作用是"非线性特征变换"——在注意力提取了词与词的关系后,FFN 进一步加工这些信息。

FFN(x) = max(0, xW₁ + b₁)W₂ + b₂

FFN 的隐藏维度通常为 4 × dmodel(如 2048),比输入维度大很多。这相当于在每个位置上独立做了一次"特征扩展→压缩",类似于两个 1×1 卷积。

📊

Layer Normalization

对每个样本的特征维度做归一化,使其均值为 0、方差为 1。作用:

  • 稳定训练过程,加速收敛
  • 缓解梯度消失/爆炸
  • 减少对初始化的敏感性

Transformer 使用了 Pre-LN(先归一化再进入注意力层),这比原始论文的 Post-LN 训练更稳定。

🔀

残差连接(Residual Connection)

将子层的输入直接加到输出上:output = LayerNorm(x + SubLayer(x))。这是 ResNet 的核心思想:

  • 让梯度可以直接流过残差路径
  • 使深层网络可训练(避免退化问题)
  • 相当于每个子层学习的是"增量"而非"全新表示"

论文中每层有 2 个残差连接:一个围绕 Multi-Head Attention,一个围绕 FFN。

🎭

Masking(掩码机制)

掩码在 Transformer 中扮演关键角色,主要有两种:

  • Padding Mask:将填充(pad)位置的注意力分数设为 -∞,使 softmax 后权重为 0
  • Look-ahead Mask(因果掩码):在解码器中,将未来位置的注意力分数设为 -∞,防止"作弊"(看到自己还没生成的词)

因果掩码使解码器具有自回归特性:生成第 t 个词时只能看到前 t-1 个词。

🔬 编码器层的完整结构

输入:x
Multi-Head
Self-Attention
+ x(残差)
Add & LayerNorm
Feed-Forward
Network
+ 上一步输出(残差)
Add & LayerNorm
输出:编码表示
出处:Vaswani, A. et al. (2017). "Attention Is All You Need." NeurIPS 2017. Section 3.1, Figure 1.

🚀 七、Transformer 的影响与演进

Transformer 的发布彻底改变了 AI 的格局。以下是基于它的几个里程碑式的工作:

2018

BERT — 双向编码器的崛起

Google 发布 BERT(Bidirectional Encoder Representations from Transformers),只使用 Transformer 的编码器部分。核心创新:

  • 双向注意力:同时考虑上下文(不像 GPT 只能看左侧)
  • MLM 预训练:随机遮盖 15% 的词让模型预测,迫使模型理解完整上下文
  • NSP:下一句预测任务,学习句子间关系

BERT 在 11 项 NLP 基准任务上刷新了记录,奠定了"预训练-微调"范式。

出处:Devlin, J. et al. (2019). "BERT: Pre-training of Deep Bidirectional Transformers for Language Understanding." NAACL 2019. arXiv:1810.04805
2018-2024

GPT 系列 — 自回归解码器的进化

OpenAI 的 GPT(Generative Pre-trained Transformer)系列只使用 Transformer 的解码器部分,采用"从左到右"的自回归方式生成文本:

  • GPT-1(2018):1.17 亿参数,验证了"预训练 + 微调"的生成式方法
  • GPT-2(2019):15 亿参数,展示了强大的零样本生成能力
  • GPT-3(2020):1750 亿参数,展示了 few-shot 学习的惊人能力
  • GPT-4(2023):多模态,推理能力飞跃,+ RLHF 对齐
  • GPT-4o / o1 / o3(2024-2025):推理链优化,突破复杂推理瓶颈
出处:Radford, A. et al. (2018). "Improving Language Understanding by Generative Pre-Training." OpenAI; Brown, T. et al. (2020). "Language Models are Few-Shot Learners." NeurIPS 2020.
2019-2020

T5 — 编码器-解码器的复兴

Google 的 T5(Text-to-Text Transfer Transformer)将所有 NLP 任务统一为"文本到文本"格式:输入一段文本,输出一段文本。翻译、摘要、问答、分类……全部用相同的编码器-解码器架构处理。

  • T5-Small: 60M 参数 → T5-11B: 110 亿参数
  • 首次在大规模上系统性对比了不同的预训练目标
  • 证明了编码器-解码器架构在某些任务上仍具优势
出处:Raffel, C. et al. (2020). "Exploring the Limits of Transfer Learning with a Unified Text-to-Text Transformer." JMLR, 21(140), 1-67. arXiv:1910.10683
2020

Vision Transformer (ViT) — 从 NLP 到 CV

ViT 证明了 Transformer 不仅适用于文本,也能在图像识别上达到或超越 CNN 的水平。核心方法极其简单:

  • 将图像切分为 16×16 的小块(Patch),类似文本中的 token
  • 每个 Patch 经过线性投影变为向量
  • 加上位置编码后直接输入标准 Transformer 编码器
  • 在 ImageNet 上达到 SOTA(在海量数据预训练后)

ViT 的论文标题 "An Image is Worth 16x16 Words" 是对 "A picture is worth a thousand words" 的巧妙致敬——一张图片 ≈ 16×16 个词。

出处:Dosovitskiy, A. et al. (2021). "An Image is Worth 16x16 Words: Transformers for Image Recognition at Scale." ICLR 2021. arXiv:2010.11929

🌳 Transformer 家族树

Transformer
(Vaswani 2017)
├──────────────┼──────────────┤
仅编码器
(Encoder-Only)

BERT、RoBERTa、ALBERT、DeBERTa
适用:分类、NER、语义理解

仅解码器
(Decoder-Only)

GPT 系列、LLaMA、Qwen、DeepSeek
适用:文本生成、对话、推理

编码器-解码器
(Encoder-Decoder)

T5、BART、mBART、Whisper
适用:翻译、摘要、语音识别

💻 八、Python 代码示例

🔧 用 PyTorch 从零实现 Self-Attention

以下代码展示了自注意力机制的完整实现过程,包含详细的数学注释:

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

class SelfAttention(nn.Module):
    """
    自注意力机制的 PyTorch 实现

    数学公式: Attention(Q, K, V) = softmax(QK^T / √d_k) V

    参数:
        d_model (int): 模型维度,即每个 token 向量的长度
        n_heads  (int): 注意力头的数量
    """

    def __init__(self, d_model=512, n_heads=8):
        super().__init__()
        assert d_model % n_heads == 0, "d_model 必须能被 n_heads 整除"

        self.d_model = d_model
        self.n_heads = n_heads
        self.d_k = d_model // n_heads  # 每个头的维度: 512/8 = 64

        # Q, K, V 的线性投影层 (可学习参数)
        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)

    def scaled_dot_product_attention(self, Q, K, V, mask=None):
        """
        缩放点积注意力

        Step 1: QK^T — 查询与键的点积,得到注意力分数
        Step 2: / √d_k — 缩放,防止梯度消失
        Step 3: softmax — 归一化为概率分布
        Step 4: × V — 加权求和 Value
        """
        # Step 1 & 2: 计算注意力分数并缩放
        # Q: (batch, n_heads, seq_len, d_k)
        # K^T: (batch, n_heads, d_k, seq_len)
        # scores: (batch, n_heads, seq_len, seq_len)
        scores = torch.matmul(Q, K.transpose(-2, -1)) / math.sqrt(self.d_k)

        # 应用掩码(如因果掩码): 将需要屏蔽的位置设为 -∞
        if mask is not None:
            scores = scores.masked_fill(mask == 0, float('-inf'))

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

        # Step 4: 用注意力权重加权 Value
        # output: (batch, n_heads, seq_len, d_k)
        output = torch.matmul(attention_weights, V)

        return output, attention_weights

    def forward(self, x, mask=None):
        """
        前向传播

        输入 x: (batch_size, seq_len, d_model)
        """
        batch_size, seq_len, _ = x.size()

        # Step 1: 线性投影得到 Q, K, V
        Q = self.W_q(x)  # (batch, seq_len, d_model)
        K = self.W_k(x)
        V = self.W_v(x)

        # Step 2: 拆分为多头
        # reshape 为 (batch, n_heads, seq_len, d_k)
        Q = Q.view(batch_size, seq_len, self.n_heads, self.d_k).transpose(1, 2)
        K = K.view(batch_size, seq_len, self.n_heads, self.d_k).transpose(1, 2)
        V = V.view(batch_size, seq_len, self.n_heads, self.d_k).transpose(1, 2)

        # Step 3: 计算缩放点积注意力
        attn_output, attn_weights = self.scaled_dot_product_attention(Q, K, V, mask)

        # Step 4: 拼接多头
        # (batch, n_heads, seq_len, d_k) → (batch, seq_len, d_model)
        attn_output = attn_output.transpose(1, 2).contiguous()
        attn_output = attn_output.view(batch_size, seq_len, self.d_model)

        # Step 5: 输出线性变换
        output = self.W_o(attn_output)

        return output, attn_weights


# ===== 使用示例 =====
if __name__ == "__main__":
    # 模型参数
    d_model = 512    # 模型维度
    n_heads = 8      # 注意力头数
    seq_len = 10     # 序列长度(如 10 个词)
    batch_size = 4  # 批量大小

    # 创建模型
    self_attn = SelfAttention(d_model=d_model, n_heads=n_heads)

    # 模拟输入: 4 个句子,每句 10 个词,每个词 512 维
    x = torch.randn(batch_size, seq_len, d_model)

    # 创建因果掩码(下三角矩阵,防止看到未来)
    mask = torch.tril(torch.ones(seq_len, seq_len))

    # 前向传播
    output, weights = self_attn(x, mask)

    print(f"输入形状:  {x.shape}")          # (4, 10, 512)
    print(f"输出形状:  {output.shape}")      # (4, 10, 512)
    print(f"注意力权重: {weights.shape}")    # (4, 8, 10, 10)
    print(f"每个样本有 {n_heads} 个头, 每个头是 {seq_len}×{seq_len} 的注意力矩阵")

代码结构说明:

1. W_q, W_k, W_v — 三个线性层,将输入投影为 Q、K、V(可学习参数)

2. scaled_dot_product_attention — 核心注意力计算:QK^T → 缩放 → softmax → ×V

3. 多头拆分/拼接 — 将 d_model 维度拆为 n_heads × d_k,分别计算后拼接

4. W_o — 输出投影,将拼接后的多头结果映射回 d_model 维

5. 因果掩码 — 下三角矩阵,确保解码器只能看到已生成的内容

出处:基于 Vaswani, A. et al. (2017). "Attention Is All You Need." NeurIPS 2017 的算法描述实现; PyTorch 官方文档。