1. Transformer模型概述:自然语言处理的革命性突破
2017年,Google研究团队在《Attention Is All You Need》论文中提出的Transformer架构,彻底改变了自然语言处理(NLP)领域的技术格局。这个创新模型摒弃了传统RNN和CNN的序列处理方式,完全基于自注意力机制来建模序列数据中的长距离依赖关系。Transformer的出现不仅在当时刷新了机器翻译等任务的性能记录,更重要的是为后续BERT、GPT等大规模预训练语言模型奠定了基础。
1.1 传统序列模型的局限性
在Transformer出现之前,NLP领域主要依赖两种神经网络架构:
-
循环神经网络(RNN):通过隐藏状态传递历史信息,理论上可以处理任意长度的序列。但实际应用中存在梯度消失/爆炸问题,难以有效建模长距离依赖。LSTM和GRU虽然有所改善,但本质问题仍未解决。
-
卷积神经网络(CNN):通过卷积核捕捉局部特征,堆叠多层可获得更大的感受野。但需要精心设计网络深度和卷积核大小,且难以建立全局依赖关系。
这两种架构的共同缺陷是:
- 顺序计算特性导致训练效率低下
- 难以直接建模序列中任意两个位置的关系
- 信息传递路径随距离增长而衰减
1.2 Transformer的核心创新
Transformer通过以下设计解决了上述问题:
- 完全基于注意力机制:使用自注意力直接计算序列中所有位置的关系权重,不受距离限制
- 并行计算架构:所有位置的注意力计算可同时进行,极大提升训练效率
- 位置编码替代递归:通过显式的位置编码保留序列顺序信息,摆脱递归计算的束缚
这种架构在WMT 2014英德翻译任务上取得了28.4 BLEU的成绩,比当时最好的递归模型高出2个BLEU,同时训练成本仅为1/4。
2. Transformer架构深度解析
2.1 整体架构设计
Transformer采用经典的编码器-解码器结构,但每个组件都经过重新设计:
code复制输入序列 → [编码器] → 中间表示 → [解码器] → 输出序列
编码器堆栈
- 由N个(原论文N=6)相同层堆叠而成
- 每层包含两个子层:
- 多头自注意力机制
- 前馈神经网络
- 每个子层采用残差连接和层归一化
解码器堆栈
- 同样由N个相同层堆叠
- 每层包含三个子层:
- 带掩码的多头自注意力
- 编码器-解码器注意力
- 前馈神经网络
- 同样使用残差连接和层归一化
2.2 核心组件实现细节
位置编码(Positional Encoding)
由于Transformer不包含递归或卷积操作,必须显式注入位置信息。原论文使用正弦/余弦函数生成固定位置编码:
python复制PE(pos,2i) = sin(pos/10000^(2i/d_model))
PE(pos,2i+1) = cos(pos/10000^(2i/d_model))
其中:
pos:词元在序列中的位置i:维度索引(0 ≤ i < d_model/2)d_model:模型维度(通常512)
这种编码方式的优势:
- 可以表示绝对位置
- 可以线性表示相对位置关系
- 对长序列有良好的外推性
实际实现时,位置编码与词嵌入相加作为模型输入:
python复制class PositionalEncoding(nn.Module):
def __init__(self, d_model, max_len=5000):
super().__init__()
pe = torch.zeros(max_len, d_model)
position = torch.arange(0, max_len).unsqueeze(1)
div_term = torch.exp(torch.arange(0, d_model, 2) * (-math.log(10000.0)/d_model))
pe[:, 0::2] = torch.sin(position * div_term)
pe[:, 1::2] = torch.cos(position * div_term)
self.register_buffer('pe', pe)
def forward(self, x):
return x + self.pe[:x.size(1)]
自注意力机制
自注意力的核心是计算查询(Q)、键(K)、值(V)三个矩阵:
- 计算注意力分数:
QK^T / sqrt(d_k) - 应用softmax得到注意力权重
- 加权求和:
Attention = softmax(QK^T/√d_k)V
代码实现:
python复制def scaled_dot_product_attention(q, k, v, mask=None):
d_k = q.size(-1)
scores = torch.matmul(q, k.transpose(-2, -1)) / math.sqrt(d_k)
if mask is not None:
scores = scores.masked_fill(mask == 0, -1e9)
p_attn = F.softmax(scores, dim=-1)
return torch.matmul(p_attn, v), p_attn
多头注意力
将注意力机制并行化,使用多组Q/K/V投影:
python复制class MultiHeadAttention(nn.Module):
def __init__(self, d_model, n_heads):
super().__init__()
self.d_k = d_model // n_heads
self.n_heads = n_heads
self.linears = clones(nn.Linear(d_model, d_model), 4)
def forward(self, query, key, value, mask=None):
batch_size = query.size(0)
# 1) 线性投影并分头
query, key, value = [
lin(x).view(batch_size, -1, self.n_heads, self.d_k).transpose(1, 2)
for lin, x in zip(self.linears, (query, key, value))
]
# 2) 计算注意力
x, attn = scaled_dot_product_attention(query, key, value, mask)
# 3) 拼接多头结果
x = x.transpose(1, 2).contiguous().view(batch_size, -1, self.n_heads * self.d_k)
return self.linears[-1](x)
前馈神经网络
编码器和解码器中的全连接层:
python复制class PositionwiseFeedForward(nn.Module):
def __init__(self, d_model, d_ff):
super().__init__()
self.w1 = nn.Linear(d_model, d_ff)
self.w2 = nn.Linear(d_ff, d_model)
def forward(self, x):
return self.w2(F.relu(self.w1(x)))
3. 编码器实现详解
3.1 编码器层结构
单个编码器层的完整实现:
python复制class EncoderLayer(nn.Module):
def __init__(self, d_model, n_heads, d_ff, dropout=0.1):
super().__init__()
self.self_attn = MultiHeadAttention(d_model, n_heads)
self.feed_forward = PositionwiseFeedForward(d_model, d_ff)
self.norm1 = nn.LayerNorm(d_model)
self.norm2 = nn.LayerNorm(d_model)
self.dropout = nn.Dropout(dropout)
def forward(self, x, mask):
# 1) 自注意力子层
attn_output = self.self_attn(x, x, x, mask)
x = x + self.dropout(attn_output)
x = self.norm1(x)
# 2) 前馈子层
ff_output = self.feed_forward(x)
x = x + self.dropout(ff_output)
x = self.norm2(x)
return x
3.2 编码器堆栈
将多个编码器层堆叠:
python复制class Encoder(nn.Module):
def __init__(self, vocab_size, d_model, n_layers, n_heads, d_ff, dropout=0.1):
super().__init__()
self.embedding = nn.Embedding(vocab_size, d_model)
self.pos_encoding = PositionalEncoding(d_model)
self.layers = nn.ModuleList([
EncoderLayer(d_model, n_heads, d_ff, dropout)
for _ in range(n_layers)
])
def forward(self, src, src_mask):
x = self.embedding(src)
x = self.pos_encoding(x)
for layer in self.layers:
x = layer(x, src_mask)
return x
3.3 掩码处理
编码器需要处理两种掩码:
- 填充掩码(Padding Mask):忽略填充token的影响
- 序列掩码(Sequence Mask):防止解码器看到未来信息
python复制def create_padding_mask(seq, pad_idx=0):
return (seq != pad_idx).unsqueeze(1).unsqueeze(2)
def create_seq_mask(seq_len):
return torch.triu(torch.ones(seq_len, seq_len), diagonal=1).bool()
4. 解码器实现详解
4.1 解码器层结构
解码器层比编码器多一个编码器-解码器注意力子层:
python复制class DecoderLayer(nn.Module):
def __init__(self, d_model, n_heads, d_ff, dropout=0.1):
super().__init__()
self.self_attn = MultiHeadAttention(d_model, n_heads)
self.src_attn = MultiHeadAttention(d_model, n_heads)
self.feed_forward = PositionwiseFeedForward(d_model, d_ff)
self.norm1 = nn.LayerNorm(d_model)
self.norm2 = nn.LayerNorm(d_model)
self.norm3 = nn.LayerNorm(d_model)
self.dropout = nn.Dropout(dropout)
def forward(self, x, memory, src_mask, tgt_mask):
# 1) 自注意力子层(带掩码)
attn_output = self.self_attn(x, x, x, tgt_mask)
x = x + self.dropout(attn_output)
x = self.norm1(x)
# 2) 编码器-解码器注意力
attn_output = self.src_attn(x, memory, memory, src_mask)
x = x + self.dropout(attn_output)
x = self.norm2(x)
# 3) 前馈子层
ff_output = self.feed_forward(x)
x = x + self.dropout(ff_output)
x = self.norm3(x)
return x
4.2 解码器堆栈
python复制class Decoder(nn.Module):
def __init__(self, vocab_size, d_model, n_layers, n_heads, d_ff, dropout=0.1):
super().__init__()
self.embedding = nn.Embedding(vocab_size, d_model)
self.pos_encoding = PositionalEncoding(d_model)
self.layers = nn.ModuleList([
DecoderLayer(d_model, n_heads, d_ff, dropout)
for _ in range(n_layers)
])
def forward(self, tgt, memory, src_mask, tgt_mask):
x = self.embedding(tgt)
x = self.pos_encoding(x)
for layer in self.layers:
x = layer(x, memory, src_mask, tgt_mask)
return x
5. 完整Transformer实现
将编码器和解码器组合成完整模型:
python复制class Transformer(nn.Module):
def __init__(self, src_vocab_size, tgt_vocab_size, d_model=512, n_layers=6,
n_heads=8, d_ff=2048, dropout=0.1):
super().__init__()
self.encoder = Encoder(src_vocab_size, d_model, n_layers, n_heads, d_ff, dropout)
self.decoder = Decoder(tgt_vocab_size, d_model, n_layers, n_heads, d_ff, dropout)
self.generator = nn.Linear(d_model, tgt_vocab_size)
def forward(self, src, tgt, src_mask, tgt_mask):
memory = self.encoder(src, src_mask)
output = self.decoder(tgt, memory, src_mask, tgt_mask)
return self.generator(output)
6. 训练技巧与优化
6.1 学习率调度
Transformer使用特殊的学习率预热策略:
python复制class WarmupScheduler:
def __init__(self, d_model, warmup_steps=4000):
self.d_model = d_model
self.warmup_steps = warmup_steps
self.step_num = 0
def __call__(self):
self.step_num += 1
return (self.d_model ** -0.5) * min(
self.step_num ** -0.5,
self.step_num * (self.warmup_steps ** -1.5)
)
6.2 标签平滑
减轻模型过度自信的问题:
python复制class LabelSmoothing(nn.Module):
def __init__(self, smoothing=0.1):
super().__init__()
self.confidence = 1.0 - smoothing
self.smoothing = smoothing
def forward(self, x, target):
logprobs = F.log_softmax(x, dim=-1)
nll_loss = -logprobs.gather(dim=-1, index=target.unsqueeze(1))
smooth_loss = -logprobs.mean(dim=-1)
loss = self.confidence * nll_loss + self.smoothing * smooth_loss
return loss.mean()
7. 关键问题与解决方案
7.1 长序列处理
原始Transformer的复杂度是O(n²),处理长序列时:
- 使用局部注意力(如Longformer)
- 稀疏注意力模式(如Reformer)
- 分块处理(如Blockwise Transformer)
7.2 位置编码改进
固定位置编码的替代方案:
- 可学习的位置嵌入
- 相对位置编码(如Transformer-XL)
- 旋转位置编码(RoPE)
7.3 模型压缩
减小模型尺寸的方法:
- 知识蒸馏(如DistilBERT)
- 参数共享(如ALBERT)
- 量化与剪枝
8. Transformer的演进与影响
8.1 主要变体
- BERT:双向Transformer编码器,通过掩码语言建模预训练
- GPT:自回归Transformer解码器,通过语言建模预训练
- T5:统一的文本到文本Transformer框架
8.2 跨领域应用
- 计算机视觉:Vision Transformer将图像分块处理
- 语音处理:Conformer结合CNN和Transformer
- 多模态:CLIP等模型处理图文跨模态任务
Transformer架构的成功证明了注意力机制作为通用计算范式的强大能力,其设计思想将持续影响深度学习的发展方向。