Transformer架构深度解析:从注意力机制到现代应用

引言

在深度学习的发展历程中,序列建模一直是一个核心挑战。传统的循环神经网络(RNN)和长短期记忆网络(LSTM)在处理长序列时面临着梯度消失和并行化困难的问题。2017年,Google的研究团队在论文《Attention Is All You Need》中提出了Transformer架构,彻底改变了自然语言处理领域的格局。

Transformer的核心创新在于完全摒弃了循环结构,转而使用自注意力机制(Self-Attention)来捕捉序列中的依赖关系。这一设计不仅解决了长距离依赖问题,还实现了高度并行化,为大规模预训练模型(如BERT、GPT系列)奠定了基础。

技术原理详解

1. 自注意力机制

自注意力机制是Transformer的核心组件,它允许模型在处理每个词元时,同时关注输入序列中的所有其他词元。

注意力计算公式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
import torch
import torch.nn as nn
import math

def scaled_dot_product_attention(Q, K, V, mask=None):
"""
Q: 查询矩阵 [batch_size, seq_len, d_k]
K: 键矩阵 [batch_size, seq_len, d_k]
V: 值矩阵 [batch_size, seq_len, d_v]
mask: 可选的掩码矩阵
"""
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)

# 应用softmax获取注意力权重
attention_weights = torch.softmax(scores, dim=-1)

# 计算加权和
output = torch.matmul(attention_weights, V)

return output, attention_weights

技术术语解释

  • 查询(Query):当前需要计算表示的词元
  • 键(Key):用于与查询计算相似度的词元
  • 值(Value):用于生成最终表示的词元
  • 缩放因子:√d_k,防止点积过大导致softmax梯度消失

2. 多头注意力

多头注意力通过并行运行多个注意力头,使模型能够同时关注不同表示子空间的信息。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
class MultiHeadAttention(nn.Module):
def __init__(self, d_model, num_heads):
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 split_heads(self, x):
"""将输入分割为多个头"""
batch_size, seq_len, d_model = x.size()
return x.view(batch_size, seq_len, self.num_heads, self.d_k).transpose(1, 2)

def combine_heads(self, x):
"""合并多个头的输出"""
batch_size, _, seq_len, d_k = x.size()
return x.transpose(1, 2).contiguous().view(batch_size, seq_len, self.d_model)

def forward(self, Q, K, V, mask=None):
batch_size = Q.size(0)

# 线性变换并分割头
Q = self.split_heads(self.W_q(Q))
K = self.split_heads(self.W_k(K))
V = self.split_heads(self.W_v(V))

# 计算缩放点积注意力
attention_output, attention_weights = scaled_dot_product_attention(Q, K, V, mask)

# 合并头并应用输出线性变换
output = self.W_o(self.combine_heads(attention_output))

return output, attention_weights

3. Transformer编码器层

每个Transformer编码器层包含两个主要子层:多头自注意力和前馈神经网络。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
class TransformerEncoderLayer(nn.Module):
def __init__(self, d_model, num_heads, d_ff, dropout=0.1):
super().__init__()

# 自注意力子层
self.self_attention = MultiHeadAttention(d_model, num_heads)
self.norm1 = nn.LayerNorm(d_model)
self.dropout1 = nn.Dropout(dropout)

# 前馈神经网络子层
self.feed_forward = nn.Sequential(
nn.Linear(d_model, d_ff),
nn.ReLU(),
nn.Linear(d_ff, d_model)
)
self.norm2 = nn.LayerNorm(d_model)
self.dropout2 = nn.Dropout(dropout)

def forward(self, x, mask=None):
# 自注意力子层(带残差连接和层归一化)
attn_output, _ = self.self_attention(x, x, x, mask)
x = x + self.dropout1(attn_output)
x = self.norm1(x)

# 前馈子层(带残差连接和层归一化)
ff_output = self.feed_forward(x)
x = x + self.dropout2(ff_output)
x = self.norm2(x)

return x

技术术语解释

  • 层归一化(LayerNorm):对每个样本的特征进行归一化,稳定训练过程
  • 残差连接(Residual Connection):将输入直接加到输出上,缓解梯度消失问题
  • 前馈神经网络(Feed-Forward Network):两层全连接网络,增加模型表达能力

4. 位置编码

由于Transformer没有循环结构,需要显式地添加位置信息。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
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, 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: [batch_size, seq_len, d_model]
return x + self.pe[:, :x.size(1)]

实战代码示例

完整的Transformer编码器实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
class TransformerEncoder(nn.Module):
def __init__(self, vocab_size, d_model, num_layers, num_heads,
d_ff, max_len, dropout=0.1):
super().__init__()

# 词嵌入层
self.embedding = nn.Embedding(vocab_size, d_model)

# 位置编码
self.positional_encoding = PositionalEncoding(d_model, max_len)

# 编码器层堆叠
self.layers = nn.ModuleList([
TransformerEncoderLayer(d_model, num_heads, d_ff, dropout)
for _ in range(num_layers)
])

self.dropout = nn.Dropout(dropout)

def forward(self, x, mask=None):
# 词嵌入 + 位置编码
x = self.embedding(x)
x = self.positional_encoding(x)
x = self.dropout(x)

# 通过所有编码器层
for layer in self.layers:
x = layer(x, mask)

return x

# 使用示例
if __name__ == "__main__":
# 配置参数
vocab_size = 10000
d_model = 512
num_layers = 6
num_heads = 8
d_ff = 2048
max_len = 100
batch_size = 32
seq_len = 50

# 创建模型
encoder = TransformerEncoder(vocab_size, d_model, num_layers,
num_heads, d_ff, max_len)

# 模拟输入
input_ids = torch.randint(0, vocab_size, (batch_size, seq_len))

# 前向传播
output = encoder(input_ids)
print(f"输入形状: {input_ids.shape}")
print(f"输出形状: {output.shape}")

最佳实践建议

1. 超参数