英译法案例 - 基于 GRU 有 Attention 的解码器代码实现(上)
1 课程概览
本课讲解英译法案例中基于 GRU 的有 Attention 解码器的 __init__ 方法实现。初始化参数包括 output_size(4345)、hidden_size(256)、dropout_p(随机失活概率)、max_length(句子最大长度)。创建词嵌入层、随机失活层、注意力权重计算层、注意力应用层、GRU、线性层、LogSoftmax。
2 核心概念与定义
- DecoderGRUWithAttention 类:基于 GRU 的有 Attention 解码器。
- output_size:法语词汇表大小(4345)。
- hidden_size:隐藏层维度(256),需与编码器一致。
- dropout_p:随机失活概率。
- max_length:句子最大长度(10)。
3 模型与算法详解
__init__ 方法
初始化参数和创建网络层。
1. 初始化父类成员
2. 保存输入参数
3. 创建词嵌入层(4345 → 256)
4. 创建随机失活层
5. 创建注意力权重计算层(512 → 10)
6. 创建注意力应用层(512 → 256)
7. 创建 GRU 层(256 → 256)
8. 创建线性层(256 → 4345)
9. 创建 LogSoftmax
各层说明
| 层 | 输入维度 | 输出维度 | 说明 |
|---|---|---|---|
| Embedding | 4345 | 256 | 词嵌入层 |
| Dropout | - | - | 随机失活 |
| attn (Linear) | 512 | 10 | 注意力权重计算 |
| attn_combine (Linear) | 512 | 256 | 注意力应用 |
| GRU | 256 | 256 | GRU 层 |
| out (Linear) | 256 | 4345 | 线性层 |
| LogSoftmax | 4345 | 4345 | 转概率 |
参数说明
| 参数 | 说明 |
|---|---|
| output_size | 法语词汇表大小(4345) |
| hidden_size | 隐藏层维度(256),需与编码器一致 |
| dropout_p | 随机失活概率 |
| max_length | 句子最大长度(10) |
4 数学原理与推导
注意力权重计算
$$\text{attn_weights} = \text{softmax}(\text{Linear}(\text{Q} \oplus \text{K}))$$
其中:
- $\text{Q} \oplus \text{K}$ 拼接后维度为 $2 \times \text{hidden_size} = 512$
- $\text{Linear}$ 将 512 维映射到 $\text{max_length} = 10$ 维
注意力应用
$$\text{output} = \text{Linear}(\text{attn_applied} \oplus \text{Q})$$
其中:
- $\text{attn_applied} \oplus \text{Q}$ 拼接后维度为 $2 \times \text{hidden_size} = 512$
- $\text{Linear}$ 将 512 维映射到 $\text{hidden_size} = 256$ 维
5 代码示例
import torch
import torch.nn as nn
import torch.nn.functional as F
class DecoderGRUWithAttention(nn.Module):
"""基于 GRU 的有 Attention 解码器"""
def __init__(self, hidden_size, output_size, dropout_p=0.1, max_length=10):
"""
初始化函数
Args:
hidden_size: 隐藏层维度(256),需与编码器一致
output_size: 输出维度(4345,法语词汇表大小)
dropout_p: 随机失活概率
max_length: 句子最大长度(10)
"""
# 1. 初始化父类成员
super(DecoderGRUWithAttention, self).__init__()
# 2. 保存输入参数
self.hidden_size = hidden_size
self.output_size = output_size
self.dropout_p = dropout_p
self.max_length = max_length
# 3. 创建词嵌入层:4345 → 256
self.embedding = nn.Embedding(output_size, hidden_size)
# 4. 创建随机失活层
self.dropout = nn.Dropout(dropout_p)
# 5. 创建注意力权重计算层:512 → 10
# 输入是 Q 和 K 拼接后的 512 维
self.attn = nn.Linear(hidden_size * 2, max_length)
# 6. 创建注意力应用层:512 → 256
# 输入是 attn_applied 和 Q 拼接后的 512 维
self.attn_combine = nn.Linear(hidden_size * 2, hidden_size)
# 7. 创建 GRU 层:256 → 256
self.gru = nn.GRU(hidden_size, hidden_size)
# 8. 创建线性层:256 → 4345
self.out = nn.Linear(hidden_size, output_size)
# 9. 创建 LogSoftmax
self.softmax = nn.LogSoftmax(dim=1)
def forward(self, input, prev_hidden, encoder_outputs):
"""前向传播(下节课实现)"""
pass
# 测试
if __name__ == "__main__":
print("=== 英译法案例 - 基于 GRU 有 Attention 的解码器代码实现(上)===")
hidden_size = 256
output_size = 4345
max_length = 10
# 创建解码器
decoder = DecoderGRUWithAttention(
hidden_size=hidden_size,
output_size=output_size,
dropout_p=0.1,
max_length=max_length
)
print(f"解码器:\n{decoder}")
# 查看各层参数
print(f"\n词嵌入层: {decoder.embedding}")
print(f"随机失活层: {decoder.dropout}")
print(f"注意力权重计算层: {decoder.attn}")
print(f"注意力应用层: {decoder.attn_combine}")
print(f"GRU 层: {decoder.gru}")
print(f"线性层: {decoder.out}")
print(f"LogSoftmax: {decoder.softmax}")
代码说明
| 代码 | 说明 |
|---|---|
nn.Embedding(output_size, hidden_size) | 词嵌入层(4345 → 256) |
nn.Dropout(dropout_p) | 随机失活层 |
nn.Linear(hidden_size * 2, max_length) | 注意力权重计算层(512 → 10) |
nn.Linear(hidden_size * 2, hidden_size) | 注意力应用层(512 → 256) |
nn.GRU(hidden_size, hidden_size) | GRU 层(256 → 256) |
nn.Linear(hidden_size, output_size) | 线性层(256 → 4345) |
nn.LogSoftmax(dim=1) | LogSoftmax |
6 重难点与易错提醒
- ❗重点:hidden_size 需与编码器一致(256)。
- ❗重点:注意力权重计算层输入是 512 维(Q 和 K 拼接)。
- ❗重点:注意力应用层输入是 512 维(attn_applied 和 Q 拼接)。
- ❗重点:max_length=10 是句子最大长度。
- ⚠️易错:Linear 层只能处理二维张量。
7 课堂问答精选
Q1:解码器的初始化参数有哪些?
A:output_size(4345)、hidden_size(256)、dropout_p(随机失活概率)、max_length(句子最大长度 10)。
Q2:为什么 hidden_size 需与编码器一致?
A:在 Seq2Seq 架构中,编码器的最终隐藏状态作为解码器的初始隐藏状态,所以两者需要一致。
Q3:注意力权重计算层的输入维度是多少?
A:512 维,是 Q 和 K 拼接后的维度(256 + 256 = 512)。
8 本课小结
__init__方法创建 7 个网络层:Embedding、Dropout、attn、attn_combine、GRU、out、LogSoftmax。- 关键参数:output_size=4345,hidden_size=256,max_length=10。
- 注意力权重计算层输入 512 维,输出 10 维。
- 注意力应用层输入 512 维,输出 256 维。
9 延伸思考
- 如何实现 forward 方法?
- 如何测试有 Attention 的解码器?