英译法案例 - 模型预测代码实现
1 课程概览
本课讲解模型评估函数 evaluate。流程:①关闭梯度计算(torch.no_grad())节省内存加速推理;②编码阶段将英文句子转为隐藏状态;③解码阶段参数准备(构建固定长度编码器输出张量);④解码循环生成法语单词,遇到 EOS 停止。
2 核心概念与定义
- evaluate:模型评估函数,进行翻译。
- torch.no_grad():关闭梯度计算,节省内存加速推理。
- max_length:固定长度(10),统一编码器输出。
- EOS(End of Sequence):终止符,遇到则停止生成。
3 模型与算法详解
评估流程
第一步:关闭梯度计算
with torch.no_grad():
# 推理过程
- 节省内存
- 加速推理
- 只适用于模型预测,不适用于训练
第二步:编码阶段
encoder_hidden = my_encoder.initHidden()
encoder_output, encoder_hidden = my_encoder(x, encoder_hidden)
- 将英文句子转为隐藏状态
- 得到中间语义张量 C
第三步:解码参数准备
encoder_outputs = torch.zeros(max_length, hidden_size, device=device)
for index in range(input_length):
encoder_outputs[index] = encoder_output[0, 0]
- 构建固定长度(10)的编码器输出张量
- 无论输入长度多少,都统一为 10
第四步:解码循环
decoder_input = torch.tensor([[SOS]], device=device) # 开始标志
decoder_hidden = encoder_hidden
for di in range(max_length):
decoder_output, decoder_hidden, attn = my_decoder(
decoder_input, decoder_hidden, encoder_outputs
)
# 获取预测结果
topv, topi = decoder_output.topk(1)
# 遇到 EOS 停止
if topi.item() == EOS:
break
# 用预测结果作为下一步输入
decoder_input = topi
关键点
| 步骤 | 说明 |
|---|---|
| 关闭梯度 | torch.no_grad() 节省内存 |
| 编码 | 英文句子 → 隐藏状态 |
| 固定长度 | 统一为 max_length(10) |
| 解码循环 | 生成法语单词,遇到 EOS 停止 |
| 预测输入 | 用预测结果作为下一步输入(不用 Teacher Forcing) |
4 数学原理与推导
编码
$$\text{output}, h_t = \text{Encoder}(x_t, h_{t-1})$$
注意力
$$\alpha_t = \text{softmax}(Q_t K^T)$$ $$C_t = \alpha_t V$$
解码
$$\text{output}, h_t = \text{Decoder}(C_t, h_{t-1})$$ $$\hat{y}_t = \arg\max \text{output}$$
5 代码示例
import torch
def evaluate(x, my_encoder, my_attn_decoder, max_length=10):
"""
模型评估函数
:param x: 英文句子
:param my_encoder: 编码器模型
:param my_attn_decoder: 带注意力机制的解码器模型
:param max_length: 最大长度
:return: decoder_words, decoder_attns
"""
# 第一步:关闭梯度计算
with torch.no_grad():
# 第二步:编码阶段
# 将英文句子转为隐藏状态
encoder_hidden = my_encoder.initHidden()
# 编码每个单词
for ei in range(x.size(0)):
encoder_output, encoder_hidden = my_encoder(x[ei], encoder_hidden)
# 第三步:解码参数准备
# 构建固定长度的编码器输出张量
encoder_outputs = torch.zeros(
max_length,
my_encoder.hidden_size,
device=device
)
for index in range(x.size(0)):
encoder_outputs[index] = encoder_output[0, 0]
# 第四步:解码循环
decoder_input = torch.tensor([[SOS]], device=device) # 开始标志
decoder_hidden = encoder_hidden # 用编码器的隐藏状态初始化
decoder_words = [] # 记录生成的法语单词
decoder_attns = [] # 记录注意力权重
for di in range(max_length):
decoder_output, decoder_hidden, attn = my_attn_decoder(
decoder_input, decoder_hidden, encoder_outputs
)
# 获取预测结果
topv, topi = decoder_output.data.topk(1)
# 遇到 EOS 停止
if topi.item() == EOS:
decoder_words.append('<EOS>')
break
else:
# 将索引转为单词
decoder_words.append(output_lang.index2word[topi.item()])
# 用预测结果作为下一步输入
decoder_input = topi.squeeze().detach()
# 记录注意力权重
decoder_attns.append(attn)
return decoder_words, decoder_attns
# 测试
if __name__ == "__main__":
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
# 加载模型(假设已加载)
# my_encoder = ...
# my_attn_decoder = ...
# 测试句子
test_sentence = "i am a student"
x = tensorFromSentence(test_sentence)
# 评估
words, attns = evaluate(x, my_encoder, my_attn_decoder)
print("翻译结果:", ' '.join(words))
6 重难点与易错提醒
- ❗重点:
torch.no_grad()关闭梯度计算,节省内存加速推理。 - ❗重点:编码器输出统一为固定长度(max_length=10)。
- ⚠️易错:预测时不能用 Teacher Forcing,用预测结果作为输入。
- ⚠️易错:遇到 EOS 要停止生成。
- 💡深入理解:
torch.no_grad()只适用于模型预测,不适用于训练。
7 课堂问答精选
Q1:为什么要关闭梯度计算?
A:模型已经训练完毕,预测时不需要更新参数。关闭梯度计算可以节省内存并加速推理。使用 torch.no_grad(),只适用于模型预测,不适用于训练。
Q2:为什么要构建固定长度的编码器输出张量?
A:因为每个句子的长度不同,但解码器需要固定长度的输入。所以统一为 max_length(10),不足的部分用 0 填充。
Q3:解码循环什么时候停止?
A:遇到 EOS(终止符)停止生成,或者达到最大长度 max_length 停止。
Q4:预测时用 Teacher Forcing 吗?
A:不用。预测时没有真实值,只能用预测结果作为下一步输入。
8 本课小结
- 关闭梯度:
torch.no_grad()节省内存加速推理。 - 编码阶段:英文句子 → 隐藏状态。
- 固定长度:统一为 max_length(10)。
- 解码循环:生成法语单词,遇到 EOS 停止。
- 预测输入:用预测结果作为下一步输入(不用 Teacher Forcing)。
9 延伸思考
- 如何加载训练好的模型?
- 如何评估翻译效果?