英译法案例 - 测试基于 GRU 的无 Attention 解码器
1 课程概览
本课讲解英译法案例中基于 GRU 的无 Attention 解码器的测试代码。需要先初始化编码器(vocab_size=28036, hidden_size=256)生成中间语义张量 C,再初始化解码器(output_size=4345, hidden_size=256)进行测试。
2 核心概念与定义
- 测试流程:先初始化编码器,再初始化解码器。
- 编码器参数:vocab_size=28036(英文),hidden_size=256。
- 解码器参数:output_size=4345(法文),hidden_size=256。
- 中间语义张量 C:编码器的输出,作为解码器的初始隐藏状态。
3 模型与算法详解
测试流程
1. 获取数据加载器对象
2. 初始化编码器模型并移动到 GPU
3. 初始化解码器模型并移动到 GPU
4. 遍历数据加载器进行测试
5. 打印编码器和解码器结构
编码器和解码器参数
| 模型 | 参数 | 值 | 说明 |
|---|---|---|---|
| 编码器 | vocab_size | 28036 | 英文词汇表大小 |
| 编码器 | hidden_size | 256 | 隐藏层维度 |
| 解码器 | output_size | 4345 | 法文词汇表大小 |
| 解码器 | hidden_size | 256 | 隐藏层维度 |
解码器结构
DecoderGRU(
(embedding): Embedding(4345, 256)
(gru): GRU(256, 256)
(out): Linear(in_features=256, out_features=4345, bias=True)
(softmax): LogSoftmax(dim=1)
)
4 数学原理与推导
编码器
$$\text{output}, \text{hidden} = \text{EncoderGRU}(\text{input})$$
解码器
$$\text{output}, \text{hidden} = \text{DecoderGRU}(\text{input}, \text{hidden})$$
5 代码示例
import torch
import torch.nn as nn
import torch.nn.functional as F
class EncoderGRU(nn.Module):
"""基于 GRU 的编码器"""
def __init__(self, vocab_size, hidden_size):
super(EncoderGRU, self).__init__()
self.hidden_size = hidden_size
self.embedding = nn.Embedding(vocab_size, hidden_size)
self.gru = nn.GRU(hidden_size, hidden_size)
def forward(self, input, hidden):
embedded = self.embedding(input).view(1, 1, -1)
output, hidden = self.gru(embedded, hidden)
return output, hidden
def initHidden(self):
return torch.zeros(1, 1, self.hidden_size)
class DecoderGRU(nn.Module):
"""基于 GRU 的无 Attention 解码器"""
def __init__(self, hidden_size, output_size):
super(DecoderGRU, self).__init__()
self.hidden_size = hidden_size
# 1. 词嵌入层:4345 → 256
self.embedding = nn.Embedding(output_size, hidden_size)
# 2. GRU 层:256 → 256
self.gru = nn.GRU(hidden_size, hidden_size)
# 3. 线性层:256 → 4345
self.out = nn.Linear(hidden_size, output_size)
# 4. LogSoftmax
self.softmax = nn.LogSoftmax(dim=1)
def forward(self, input, hidden):
embedded = self.embedding(input).view(1, 1, -1)
embedded = F.relu(embedded)
output, hidden = self.gru(embedded, hidden)
output = self.softmax(self.out(output[0]))
return output, hidden
def initHidden(self):
return torch.zeros(1, 1, self.hidden_size)
def test_decoder_gru():
"""测试基于 GRU 的无 Attention 解码器"""
print("=== 英译法案例 - 测试基于 GRU 的无 Attention 解码器 ===")
# 1. 获取数据加载器对象
# my_data_loader = get_data_loader()
# 2. 初始化编码器模型并移动到 GPU
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
my_encoder_gru = EncoderGRU(vocab_size=28036, hidden_size=256).to(device)
# 3. 初始化解码器模型并移动到 GPU
my_decoder_gru = DecoderGRU(hidden_size=256, output_size=4345).to(device)
print(f"设备: {device}")
print(f"\n编码器:\n{my_encoder_gru}")
print(f"\n解码器:\n{my_decoder_gru}")
# 4. 测试
input_tensor = torch.tensor([[1]]).to(device) # [1, 1]
# 编码器
encoder_hidden = my_encoder_gru.initHidden().to(device)
encoder_output, encoder_hidden = my_encoder_gru(input_tensor, encoder_hidden)
# 解码器
decoder_input = torch.tensor([[1]]).to(device) # SOS
decoder_hidden = encoder_hidden # 编码器的隐藏状态作为解码器的初始隐藏状态
decoder_output, decoder_hidden = my_decoder_gru(decoder_input, decoder_hidden)
print(f"\n编码器输出形状: {encoder_output.shape}")
print(f"解码器输出形状: {decoder_output.shape}") # [1, 4345]
print(f"概率最高的词索引: {decoder_output.topk(1).indices.item()}")
# 测试
if __name__ == "__main__":
test_decoder_gru()
代码说明
| 代码 | 说明 |
|---|---|
EncoderGRU(vocab_size=28036, hidden_size=256) | 编码器 |
DecoderGRU(hidden_size=256, output_size=4345) | 解码器 |
.to(device) | 移动到 GPU |
encoder_hidden | 编码器的隐藏状态 |
decoder_hidden = encoder_hidden | 编码器隐藏状态作为解码器初始隐藏状态 |
6 重难点与易错提醒
- ❗重点:测试解码器前需要先初始化编码器。
- ❗重点:编码器的隐藏状态作为解码器的初始隐藏状态。
- ❗重点:编码器 vocab_size=28036(英文),解码器 output_size=4345(法文)。
- 💡技巧:使用 GPU 时需要将模型移动到 device。
7 课堂问答精选
Q1:为什么测试解码器前需要先初始化编码器?
A:解码器需要中间语义张量 C,而中间语义张量 C 是基于编码器生成的。
Q2:编码器和解码器的参数有什么区别?
A:编码器 vocab_size=28036(英文词汇表大小),解码器 output_size=4345(法文词汇表大小),两者 hidden_size=256 一致。
Q3:如何将模型移动到 GPU?
A:使用 .to(device),其中 device 是 torch.device("cuda" if torch.cuda.is_available() else "cpu")。
8 本课小结
- 测试流程:获取数据加载器 → 初始化编码器 → 初始化解码器 → 遍历测试。
- 编码器 vocab_size=28036,解码器 output_size=4345,hidden_size=256。
- 编码器的隐藏状态作为解码器的初始隐藏状态。
9 延伸思考
- 如何构建带 Attention 的解码器?
- Attention 机制如何提升解码器性能?