Transformer 架构测试(上)
1 课程概览
本课讲解 Transformer 架构的测试(上)。使用 make_model 函数构建 Transformer 模型,定义深拷贝工具函数 c = copy.deepcopy,依次创建编码器层、解码器层、词嵌入层、位置编码层、多头注意力机制、前馈全连接层等组件。
2 核心概念与定义
- make_model 函数:构建 Transformer 模型的工厂函数。
- 深拷贝工具函数:
c = copy.deepcopy,用于复制模块。 - nn.Sequential:处理链,将多个层按顺序组合。
- 组件:词嵌入层、位置编码层、多头注意力机制、前馈全连接层等。
3 模型与算法详解
make_model 函数流程
1. 定义深拷贝工具函数 c = copy.deepcopy
2. 创建词嵌入层(Embedding)
3. 创建位置编码层(PositionalEncoding)
4. 创建多头注意力机制(MultiHeadAttention)
5. 创建前馈全连接层(FeedForward)
6. 创建编码器层(EncoderLayer)
7. 创建解码器层(DecoderLayer)
8. 创建编码器(Encoder)
9. 创建解码器(Decoder)
10. 创建源输入嵌入层(source_embed)
11. 创建目标输入嵌入层(target_embed)
12. 创建输出生成器(Generator)
13. 创建 Transformer 模型(EncoderDecoder)
14. 参数初始化(Xavier)
组件参数
| 组件 | 参数 | 值 |
|---|---|---|
| 词嵌入层 | vocab_size, d_model | 1000, 512 |
| 位置编码层 | d_model, dropout | 512, 0.1 |
| 多头注意力机制 | d_model, num_heads | 512, 8 |
| 前馈全连接层 | d_model, d_ff | 512, 2048 |
| 编码器/解码器层数 | N | 6 |
深拷贝工具函数
c = copy.deepcopy,用于复制模块。
import copy
c = copy.deepcopy # 不加小括号是赋值,加小括号是调用
# 使用
attn = MultiHeadAttention(d_model, num_heads)
self_attn = c(attn) # 等价于 copy.deepcopy(attn)
4 数学原理与推导
词嵌入
$$\text{embedded} = \text{Embedding}(\text{x})$$
位置编码
$$\text{pe} = \text{PositionalEncoding}(\text{embedded})$$
多头注意力
$$\text{output} = \text{MultiHeadAttention}(\text{Q}, \text{K}, \text{V})$$
前馈全连接
$$\text{output} = \text{FeedForward}(\text{x})$$
5 代码示例
import torch
import torch.nn as nn
import copy
class MultiHeadAttention(nn.Module):
"""多头注意力机制"""
def __init__(self, d_model, num_heads, dropout=0.1):
super(MultiHeadAttention, self).__init__()
self.d_model = d_model
self.num_heads = num_heads
self.head_dim = 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.fc = nn.Linear(d_model, d_model)
self.dropout = nn.Dropout(dropout)
def forward(self, Q, K, V, mask=None):
batch_size = Q.size(0)
Q = self.w_q(Q).view(batch_size, -1, self.num_heads, self.head_dim).transpose(1, 2)
K = self.w_k(K).view(batch_size, -1, self.num_heads, self.head_dim).transpose(1, 2)
V = self.w_v(V).view(batch_size, -1, self.num_heads, self.head_dim).transpose(1, 2)
scores = torch.matmul(Q, K.transpose(-2, -1)) / (self.head_dim ** 0.5)
if mask is not None:
scores = scores.masked_fill(mask == 0, -1e9)
attn_weights = torch.softmax(scores, dim=-1)
attn_weights = self.dropout(attn_weights)
output = torch.matmul(attn_weights, V)
output = output.transpose(1, 2).contiguous().view(batch_size, -1, self.d_model)
output = self.fc(output)
return output
class PositionalEncoding(nn.Module):
"""位置编码层"""
def __init__(self, d_model, dropout, max_len=5000):
super(PositionalEncoding, self).__init__()
self.dropout = nn.Dropout(dropout)
pe = torch.zeros(max_len, d_model)
position = torch.arange(0, max_len).unsqueeze(1).float()
div_term = torch.exp(torch.arange(0, d_model, 2).float() * (-torch.log(torch.tensor(10000.0)) / d_model))
pe[:, 0::2] = torch.sin(position * div_term)
pe[:, 1::2] = torch.cos(position * div_term)
pe = pe.unsqueeze(0)
self.register_buffer('pe', pe)
def forward(self, x):
x = x + self.pe[:, :x.size(1)]
return self.dropout(x)
class FeedForward(nn.Module):
"""前馈全连接层"""
def __init__(self, d_model, d_ff, dropout=0.1):
super(FeedForward, self).__init__()
self.fc1 = nn.Linear(d_model, d_ff)
self.fc2 = nn.Linear(d_ff, d_model)
self.dropout = nn.Dropout(dropout)
def forward(self, x):
return self.fc2(self.dropout(torch.relu(self.fc1(x))))
def make_model(source_vocab, target_vocab, N=6, d_model=512, d_ff=2048, num_heads=8, dropout=0.1):
"""
构建 Transformer 模型
Args:
source_vocab: 源词汇表大小
target_vocab: 目标词汇表大小
N: 编码器/解码器层数(默认 6)
d_model: 词向量维度(默认 512)
d_ff: 前馈全连接层维度(默认 2048)
num_heads: 多头注意力头数(默认 8)
dropout: 随机失活概率(默认 0.1)
Returns:
model: Transformer 模型
"""
# 1. 定义深拷贝工具函数
c = copy.deepcopy
# 2. 创建词嵌入层
source_embed = nn.Embedding(source_vocab, d_model)
target_embed = nn.Embedding(target_vocab, d_model)
# 3. 创建位置编码层
position = PositionalEncoding(d_model, dropout)
# 4. 创建多头注意力机制
attn = MultiHeadAttention(d_model, num_heads, dropout)
# 5. 创建前馈全连接层
ff = FeedForward(d_model, d_ff, dropout)
# 6. 创建编码器(使用 PyTorch 内置)
encoder = nn.TransformerEncoder(
nn.TransformerEncoderLayer(d_model, num_heads, d_ff, dropout, batch_first=True),
N
)
# 7. 创建解码器(使用 PyTorch 内置)
decoder = nn.TransformerDecoder(
nn.TransformerDecoderLayer(d_model, num_heads, d_ff, dropout, batch_first=True),
N
)
# 8. 创建源输入嵌入层(处理链:词嵌入 + 位置编码)
source_embed_seq = nn.Sequential(c(source_embed), c(position))
# 9. 创建目标输入嵌入层(处理链:词嵌入 + 位置编码)
target_embed_seq = nn.Sequential(c(target_embed), c(position))
# 10. 创建输出生成器
generator = nn.Linear(d_model, target_vocab)
# 11. 创建 Transformer 模型
class EncoderDecoder(nn.Module):
def __init__(self, encoder, decoder, source_embed, target_embed, generator):
super(EncoderDecoder, self).__init__()
self.encoder = encoder
self.decoder = decoder
self.source_embed = source_embed
self.target_embed = target_embed
self.generator = generator
def forward(self, source_x, target_y, source_mask, target_mask):
encoder_output = self.encode(source_x, source_mask)
output = self.decode(target_y, encoder_output, source_mask, target_mask)
return self.generator(output)
def encode(self, source_x, source_mask):
return self.encoder(self.source_embed(source_x), source_mask)
def decode(self, target_y, encoder_output, source_mask, target_mask):
return self.decoder(self.target_embed(target_y), encoder_output, source_mask, target_mask)
model = EncoderDecoder(encoder, decoder, source_embed_seq, target_embed_seq, generator)
# 12. 参数初始化(Xavier)
for p in model.parameters():
if p.dim() > 1:
nn.init.xavier_uniform_(p)
return model
# 测试
if __name__ == "__main__":
print("=== Transformer 架构测试(上)===")
source_vocab = 1000
target_vocab = 1000
# 构建 Transformer 模型
model = make_model(source_vocab, target_vocab, N=6, d_model=512, num_heads=8)
print(f"Transformer 模型创建成功")
print(f"模型参数数量: {sum(p.numel() for p in model.parameters()):,}")
代码说明
| 代码 | 说明 |
|---|---|
c = copy.deepcopy | 深拷贝工具函数 |
nn.Embedding(source_vocab, d_model) | 词嵌入层 |
PositionalEncoding(d_model, dropout) | 位置编码层 |
MultiHeadAttention(d_model, num_heads, dropout) | 多头注意力机制 |
FeedForward(d_model, d_ff, dropout) | 前馈全连接层 |
nn.Sequential(c(source_embed), c(position)) | 处理链 |
nn.init.xavier_uniform_(p) | Xavier 参数初始化 |
6 重难点与易错提醒
- ❗重点:使用
c = copy.deepcopy定义深拷贝工具函数。 - ❗重点:source_embed 和 target_embed 是处理链(nn.Sequential)。
- ❗重点:参数初始化使用 Xavier。
- 💡技巧:
c = copy.deepcopy不加小括号是赋值,加小括号是调用。
7 课堂问答精选
Q1:为什么使用深拷贝?
A:深拷贝确保模块参数不共享,各模块独立。
Q2:source_embed 包含什么?
A:source_embed 是处理链(nn.Sequential),包含词嵌入层和位置编码层。
Q3:参数初始化使用什么方法?
A:使用 Xavier 初始化(nn.init.xavier_uniform_)。
8 本课小结
- 使用
make_model函数构建 Transformer 模型。 - 定义深拷贝工具函数
c = copy.deepcopy。 - source_embed 和 target_embed 是处理链(nn.Sequential)。
- 参数初始化使用 Xavier。
9 延伸思考
- 如何测试 Transformer 模型?
- 如何使用 Transformer 进行机器翻译?