一、什么是 Transformer?
Transformer 是一种基于**自注意力机制(Self-Attention)**的深度学习模型架构,彻底改变了自然语言处理(NLP)乃至计算机视觉(CV)、语音识别等多个领域。
在 Transformer 出现之前,序列建模的主流是 RNN(循环神经网络) 和 LSTM/GRU。这些模型存在根本性缺陷:
- 串行计算:必须按时间步顺序处理,无法并行
- 长距离依赖:信息随时间步传播会衰减,难以捕捉远距离 token 之间的关系
- 梯度消失/爆炸:长序列训练困难
Transformer 的核心主张是:完全抛弃循环和卷积结构,仅依靠注意力机制来建模序列中任意两个位置之间的依赖关系。
二、核心创新点
1. 自注意力机制(Self-Attention)⭐
这是 Transformer 的灵魂。它允许模型在处理每个 token 时,同时关注输入序列中的所有位置,并自动学习不同位置之间的关联权重。
关键突破:
- 任意两个 token 的距离都变为 O(1)(直接计算注意力权重)
- 彻底解决了 RNN 的长距离依赖问题
- 全局视野,每个位置都能"看到"整个序列
2. 完全并行化(Parallelization)⭐
RNN 必须按顺序计算:h_t = f(h_{t-1}, x_t)
Transformer 的 Self-Attention 可以同时计算所有位置的表示,训练速度大幅提升,且易于在 GPU/TPU 上扩展。
3. 多头注意力(Multi-Head Attention)
将注意力机制复制多份(heads),每份学习不同的"关注点"(子空间):
- 有的 head 关注语法关系
- 有的 head 关注语义关系
- 有的 head 关注指代消解
最终拼接所有 head 的结果,获得更丰富的表示。
4. 位置编码(Positional Encoding)
由于 Self-Attention 本身没有位置概念(对输入顺序不敏感),Transformer 通过正弦/余弦函数将位置信息注入模型:
PE(pos, 2i) = sin(pos / 10000^(2i/d_model))
PE(pos, 2i+1) = cos(pos / 10000^(2i/d_model))
这种编码方式允许模型学习相对位置关系,且能外推到训练时未见过的更长序列。
5. 残差连接与层归一化(Residual Connection & Layer Normalization)
- 残差连接:Output = LayerNorm(x + Sublayer(x)),缓解梯度消失,支持深层网络
- 层归一化:对每个样本的所有特征做归一化,稳定训练
6. Encoder-Decoder 架构的解耦
- Encoder:通过 Self-Attention 编码输入序列的上下文表示
- Decoder:通过 Masked Self-Attention + Cross-Attention 自回归生成输出
三、Transformer 如何工作?(架构详解)
3.1 整体架构
┌─────────────────────────────────────────────────────────────┐
│ Transformer │
├─────────────────────────────┬───────────────────────────────┤
│ Encoder Stack │ Decoder Stack │
│ ┌───────────────────────┐ │ ┌─────────────────────────┐ │
│ │ Input Embedding │ │ │ Output Embedding │ │
│ │ + Positional Encoding│ │ │ + Positional Encoding │ │
│ └───────────┬───────────┘ │ └───────────┬─────────────┘ │
│ ▼ │ ▼ │
│ ┌───────────────────────┐ │ ┌─────────────────────────┐ │
│ │ Multi-Head Attention │ │ │ Masked Multi-Head Attn │ │
│ │ + Add & Norm │ │ │ + Add & Norm │ │
│ └───────────┬───────────┘ │ └───────────┬─────────────┘ │
│ ▼ │ ▼ │
│ ┌───────────────────────┐ │ ┌─────────────────────────┐ │
│ │ Feed Forward Network │ │ │ Multi-Head Cross-Attn │ │
│ │ + Add & Norm │ │ │ + Add & Norm │ │
│ └───────────┬───────────┘ │ └───────────┬─────────────┘ │
│ ▼ │ ▼ │
│ ┌───────────────────────┐ │ ┌─────────────────────────┐ │
│ │ … (N layers) │ │ │ Feed Forward Network │ │
│ └───────────┬───────────┘ │ │ + Add & Norm │ │
│ ▼ │ └───────────┬─────────────┘ │
│ ┌───────────────────────┐ │ ▼ │
│ │ Output to Decoder │──┼──▶│ … (N layers) │ │
│ └───────────────────────┘ │ └───────────┬─────────────┘ │
│ │ ▼ │
│ │ ┌─────────────────────────┐ │
│ │ │ Linear + Softmax │ │
│ │ │ → Probability Dist. │ │
│ │ └─────────────────────────┘ │
└─────────────────────────────┴───────────────────────────────┘
3.2 Self-Attention 的数学原理
Step 1: 生成 Q, K, V
对每个输入 token 的嵌入向量 x,通过三个不同的权重矩阵映射为:
- Query (Q): 当前 token "想要查询什么"
- Key (K): 当前 token "包含什么信息"
- Value (V): 当前 token "实际传递什么内容"
Q = X · W_Q
K = X · W_K
V = X · W_V
其中 W_Q, W_K, W_V ∈ R^(d_model × d_k) 是可学习的参数矩阵。
Step 2: 计算注意力分数
Attention(Q, K, V) = softmax(QK^T / √d_k) · V
分步拆解:
QK^T: 计算每对 token 之间的相似度(点积),得到注意力分数矩阵
- 形状: (seq_len, seq_len) —— 每个位置关注所有位置的分数
/ √d_k: 缩放因子(Scaling)
- 当 d_k 很大时,点积的数值会非常大,导致 softmax 进入梯度极小的饱和区
- 除以 √d_k 将方差控制在合理范围,保证梯度稳定
softmax: 将分数归一化为概率分布(每行之和为 1)
· V: 用注意力权重对 Value 做加权求和,得到输出表示
Step 3: 多头拼接
MultiHead(Q, K, V) = Concat(head_1, …, head_h) · W_O
where head_i = Attention(QW_i^Q, KW_i^K, VW_i^V)
- 原始论文: h = 8 个头, d_k = d_v = d_model / h = 64
- 每个 head 独立学习不同的注意力模式
- 最终通过 W_O 投影回 d_model 维度
3.3 Masked Self-Attention(Decoder 专用)
Decoder 在训练时需要防止看到未来的 token(保持自回归特性)。
实现方式:在 softmax 之前,将未来位置的注意力分数设为 -∞:
Mask = [[0, -∞, -∞, …],
[0, 0, -∞, …],
[0, 0, 0, …],
…]
Attention_scores = QK^T / √d_k + Mask
这样每个位置只能关注到它及之前的位置。
3.4 Cross-Attention(Encoder-Decoder Attention)
Decoder 中的第二层注意力:
- Q 来自 Decoder 上一层的输出(当前已生成的序列)
- K, V 来自 Encoder 的最终输出(源序列的编码表示)
这实现了源语言 → 目标语言的信息传递,是机器翻译等任务的核心。
3.5 前馈神经网络(Feed-Forward Network, FFN)
每个 Encoder/Decoder 层都包含一个全连接前馈网络:
FFN(x) = max(0, xW_1 + b_1)W_2 + b_2
即:Linear → ReLU → Linear
- 中间维度: d_ff = 2048(原始论文)
- 对每个位置独立应用(不共享信息,信息交互由 Attention 完成)
- 增加模型的非线性表达能力
3.6 层归一化(Layer Normalization)
LayerNorm(x) = γ ⊙ (x – μ) / √(σ² + ε) + β
- 对单个样本的所有特征做归一化(区别于 BatchNorm)
- 适用于序列长度变化的场景
- Pre-Norm vs Post-Norm:原始论文用 Post-Norm,现代变体多用 Pre-Norm(更稳定)
四、训练细节
4.1 输入嵌入(Input Embedding)
- 使用可学习的词嵌入矩阵将 token ID 映射为 d_model 维向量
- 原始论文: d_model = 512
- 嵌入权重与输出层 softmax 前的线性层共享权重(减少参数量,提升性能)
4.2 输出层
Decoder 最终输出经过:
4.3 损失函数
标准交叉熵损失(Cross-Entropy Loss):
L = -Σ log P(y_t | y_<t, x)
4.4 优化器与正则化
- Adam 优化器: β1=0.9, β2=0.98, ε=10⁻⁹
- 学习率调度(Warmup + 衰减):
lrate = d_model^(-0.5) · min(step^(-0.5), step · warmup_steps^(-1.5))
- Warmup: 前 4000 步线性增长
- 之后按 step^(-0.5) 衰减
- Dropout: P_drop = 0.1(嵌入、注意力、FFN、残差连接后)
- Label Smoothing: ε_ls = 0.1(防止模型过度自信)
五、为什么 Transformer 如此强大?
| 并行性 | ❌ 串行 | ✅ 完全并行 |
| 长距离依赖 | ❌ 随距离衰减 | ✅ 直接连接 |
| 计算复杂度(每步) | O(1) | O(1)(但总体 O(n²)) |
| 训练速度 | 慢 | 快(可大规模并行) |
| 位置感知 | 天然有序 | 需位置编码 |
| 可解释性 | 低 | 高(注意力权重可视化) |
5.1 注意力可视化
通过观察注意力权重矩阵,可以直观理解模型在关注什么:
- 句法关系: 代词指向其指代的名词
- 语义关系: 同义词/反义词之间的关联
- 跨语言对齐: 翻译任务中源语言和目标语言的词对齐
5.2 从 Transformer 到现代大模型
Transformer 架构是以下所有模型的基础:
| BERT | Encoder-only | 双向编码,预训练 + 微调范式 |
| GPT 系列 | Decoder-only | 自回归生成,Scaling Law |
| T5 | Encoder-Decoder | Text-to-Text 统一框架 |
| Vision Transformer (ViT) | Encoder | 将图像分块作为序列处理 |
| CLIP | Dual Encoder | 图文对齐,多模态理解 |
| LLaMA, ChatGPT, Claude | Decoder-only | 大规模预训练 + RLHF |
六、PyTorch 核心实现
import math
import torch
import torch.nn as nn
import torch.nn.functional as F
class MultiHeadAttention(nn.Module):
"""多头自注意力机制"""
def __init__(self, d_model=512, num_heads=8):
super().__init__()
assert d_model % num_heads == 0
self.d_model = d_model
self.num_heads = num_heads
self.d_k = d_model // num_heads # 每个头的维度
# 线性投影层
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):
"""计算缩放点积注意力"""
scores = torch.matmul(Q, K.transpose(-2, -1)) / math.sqrt(self.d_k)
if mask is not None:
scores = scores.masked_fill(mask == 0, -1e9)
attn_weights = F.softmax(scores, dim=-1)
output = torch.matmul(attn_weights, V)
return output, attn_weights
def forward(self, query, key, value, mask=None):
batch_size = query.size(0)
# 1. 线性投影并分头
# (batch, seq, d_model) -> (batch, seq, num_heads, d_k) -> (batch, num_heads, seq, d_k)
Q = self.W_q(query).view(batch_size, -1, self.num_heads, self.d_k).transpose(1, 2)
K = self.W_k(key).view(batch_size, -1, self.num_heads, self.d_k).transpose(1, 2)
V = self.W_v(value).view(batch_size, -1, self.num_heads, self.d_k).transpose(1, 2)
# 2. 计算注意力
attn_output, attn_weights = self.scaled_dot_product_attention(Q, K, V, mask)
# 3. 拼接多头并输出投影
# (batch, num_heads, seq, d_k) -> (batch, seq, d_model)
attn_output = attn_output.transpose(1, 2).contiguous().view(
batch_size, -1, self.d_model
)
return self.W_o(attn_output)
class PositionwiseFeedForward(nn.Module):
"""前馈神经网络"""
def __init__(self, d_model=512, d_ff=2048, dropout=0.1):
super().__init__()
self.linear1 = nn.Linear(d_model, d_ff)
self.linear2 = nn.Linear(d_ff, d_model)
self.dropout = nn.Dropout(dropout)
def forward(self, x):
return self.linear2(self.dropout(F.relu(self.linear1(x))))
class PositionalEncoding(nn.Module):
"""正弦位置编码"""
def __init__(self, d_model=512, max_len=5000, dropout=0.1):
super().__init__()
self.dropout = nn.Dropout(dropout)
# 预计算位置编码矩阵
pe = torch.zeros(max_len, d_model)
position = torch.arange(0, max_len, dtype=torch.float).unsqueeze(1)
div_term = torch.exp(
torch.arange(0, d_model, 2).float() *
(-math.log(10000.0) / d_model)
)
pe[:, 0::2] = torch.sin(position * div_term)
pe[:, 1::2] = torch.cos(position * div_term)
pe = pe.unsqueeze(0) # (1, max_len, d_model)
self.register_buffer('pe', pe)
def forward(self, x):
x = x + self.pe[:, :x.size(1), :]
return self.dropout(x)
class EncoderLayer(nn.Module):
"""单个 Encoder 层"""
def __init__(self, d_model=512, num_heads=8, d_ff=2048, dropout=0.1):
super().__init__()
self.self_attn = MultiHeadAttention(d_model, num_heads)
self.feed_forward = PositionwiseFeedForward(d_model, d_ff, dropout)
self.norm1 = nn.LayerNorm(d_model)
self.norm2 = nn.LayerNorm(d_model)
self.dropout = nn.Dropout(dropout)
def forward(self, x, mask=None):
# 子层1: Multi-Head Self-Attention + Add & Norm
attn_output = self.self_attn(x, x, x, mask)
x = self.norm1(x + self.dropout(attn_output))
# 子层2: FFN + Add & Norm
ff_output = self.feed_forward(x)
x = self.norm2(x + self.dropout(ff_output))
return x
class TransformerEncoder(nn.Module):
"""Transformer Encoder 堆叠"""
def __init__(self, vocab_size, d_model=512, num_heads=8,
num_layers=6, d_ff=2048, dropout=0.1, max_len=5000):
super().__init__()
self.embedding = nn.Embedding(vocab_size, d_model)
self.pos_encoding = PositionalEncoding(d_model, max_len, dropout)
self.layers = nn.ModuleList([
EncoderLayer(d_model, num_heads, d_ff, dropout)
for _ in range(num_layers)
])
self.dropout = nn.Dropout(dropout)
self.scale = math.sqrt(d_model)
def forward(self, x, mask=None):
x = self.embedding(x) * self.scale
x = self.pos_encoding(x)
for layer in self.layers:
x = layer(x, mask)
return x
七、总结
核心公式回顾
| Scaled Dot-Product Attention | softmax(QK^T / √d_k)V |
| Multi-Head Attention | Concat(head₁,…,headₕ)W^O |
| FFN | max(0, xW₁+b₁)W₂+b₂ |
| Positional Encoding | sin/cos(pos/10000^(2i/d_model)) |
| Layer Normalization | γ(x-μ)/√(σ²+ε) + β |
设计哲学
历史意义
Transformer 不仅是 NLP 的里程碑,更是现代人工智能的基石。从 BERT 到 GPT-4,从 ChatGPT 到 Sora,几乎所有当前最先进的 AI 系统都建立在 Transformer 或其变体之上。它证明了:一个简洁而优雅的架构设计,可以引发整个领域的范式革命。

