🎯 课程主题
生成器代码实现——将解码器输出转换为词概率分布。
📝 核心知识点
1. 生成器的作用
- 概念说明:Transformer 的最后一层,输出词的概率分布。
- 关键细节:
- 输入:解码器的最终输出
- 处理:线性全连接层 + Softmax 激活
- 输出:每个位置上词表的概率分布
- 取概率最大的下标 → 从词表查到对应的词
2. 代码结构
- 概念说明:生成器的实现非常简单。
- 关键细节:
- 一个线性全连接层:
nn.Linear(d_model, vocab_size) - 一个 Softmax 激活函数
- 前向传播:
softmax(linear(x))
- 一个线性全连接层:
3. 输出处理
- 概念说明:如何从概率分布得到最终词。
- 关键细节:
- 概率分布:$[batch, seq_len, vocab_size]$
- 取 argmax 得到词的 ID
- 通过 ID 从词表查找对应的词
- 拼接所有词得到最终翻译结果
🧮 核心公式与推导
生成器公式:
$$P(y) = \text{Softmax}(\text{Linear}(x))$$
其中:
- $x \in \mathbb{R}^{batch \times L \times d_{model}}$:解码器输出
- $\text{Linear}: \mathbb{R}^{d_{model}} \to \mathbb{R}^{V}$:线性变换
- $V$:词表大小
- $P(y) \in \mathbb{R}^{batch \times L \times V}$:词概率分布
预测词:
$$\hat{y}t = \arg\max{i} P(y_{t,i})$$
🏗️ 模型架构与数据流向
💻 代码实战
import torch
import torch.nn as nn
import torch.nn.functional as F
class Generator(nn.Module):
"""生成器: 将解码器输出转换为词概率分布"""
def __init__(self, d_model, vocab_size):
"""
d_model: 模型维度 (如512)
vocab_size: 词表大小 (如32000)
"""
super().__init__()
self.proj = nn.Linear(d_model, vocab_size)
def forward(self, x):
"""
x: [batch, seq_len, d_model] 解码器输出
return: [batch, seq_len, vocab_size] 词概率分布
"""
# 线性变换 + Softmax
return F.log_softmax(self.proj(x), dim=-1)
# 使用示例
if __name__ == "__main__":
d_model = 512
vocab_size = 32000
batch_size = 2
seq_len = 8
generator = Generator(d_model, vocab_size)
# 解码器输出
decoder_output = torch.randn(batch_size, seq_len, d_model)
# 生成词概率分布
log_probs = generator(decoder_output)
print(f"解码器输出: {decoder_output.shape}")
print(f"概率分布: {log_probs.shape}") # [2, 8, 32000]
# 取概率最大的词ID
predicted_ids = log_probs.argmax(dim=-1)
print(f"预测词ID: {predicted_ids.shape}") # [2, 8]
print(f"第一个样本的预测: {predicted_ids[0]}")
# 通过词表查找对应的词 (示例)
# id_to_token = {0: '<pad>', 1: '<unk>', 2: '<bos>', 3: '<eos>', ...}
# predicted_tokens = [id_to_token[id.item()] for id in predicted_ids[0]]
# print(f"翻译结果: {' '.join(predicted_tokens)}")
⚠️ 常见问题与避坑指南
- 使用
log_softmax而非softmax,便于计算交叉熵损失 - 线性层将 $d_{model}$ 映射到词表大小 $V$
- 推理时用
argmax取最大概率词,训练时用交叉熵损失 - 生成器是 Transformer 的最后一层
💡 个人总结与延伸
生成器是 Transformer 输出层,将解码器的隐藏表示映射到词表概率空间。代码实现简单但作用关键。现代大模型中,生成器通常与词嵌入共享权重(Weight Tying),减少参数量并提升性能。