当前位置: 首页 > news >正文

9.7.3 损失函数

解码器预测了输出词元概率分布类似于语言模型可以使用softmax来获得分布并通过计算交叉墒损失函数来进行优化回想一下9.5特定填充词元添加序列末尾因此不同长度序列可以相同形状小批量加载但是我们应该填充词元预测损失函数计算剔除

我们可以使用下面sequence_mask 函数通过零值屏蔽不想管以便后面任何不想管预测计算都是乘积结果都等于例如如果两个序列有效长度分别12则第一个蓄力哦额的第一项第二个序列前两项之后剩余项将被清零

def sequence_mask(X, valid_len, value=0):

序列屏蔽不想管

maxlen = X.size(1)

mask = torch.arange((maxlen), dtype = torch.float32, device=X.device)[None,:] < valid_len[:, None]

X[~mask] = value

X=torch.tensor([1,2,3], [4,5,6])

sequence_mask(X, torch.tensor([1,2]))

我们还可以使用函数屏蔽最后几个所有项如果需要也可以使用指定非零替换这些项

X=torch.ones(2,3,4)

sequence_mask(X, torch.tensor([1,2]), value=-1)

我们可以通过扩展softmax交叉墒损失函数屏蔽相关预测最初所有预测词元掩码设置1一旦给定有效长度填充词元对应掩码将被设置0最后所有词元损失乘以掩码过滤损失填充产生相关预测

class MaskedSoftmaxCELoss(nn.CrossEntropyLoss):

#屏蔽softmax交叉墒损失函数

#pred 形状(batch_size, num_steps, vocab_size)

#label 形状(batch_size, num_steps)

#valid_len 形状(batch_size,)

def forward(self, pred, label, valid_len):

weights = torch.ones_like(label)

weights = sequence_mask(weights, valid_len)

self.reduction='none'

unweighted_loss = super(MaskedSoftMaxCELoss, self).forward(pred.permute(0,2,1),label)

weighted_loss = (unweigthed_loss * weights).mean(dim=1)

return weighted_loss

我们可以创建3相同序列来进行代码健全性检查然后制定这些序列有效长度分别42 0结果是第一个序列损失应第二个序列2第三个序列损失0.

loss = MaskedSoftmaxCELoss()

loss(torch.ones(3,4,10), torch.ones((3,4), dtype=torch.long), torch.tensor([4,2,0]))

9.7.4 训练

def train_seq2seq(net, data_iter, lr, num_epochs, tgt_vocab, device):

训练序列序列模型

def xavier_init_weights(m):

if type(m) == nn.Linear:

nn.init.xavier_uniform_(m.weight)

if type(m) == nn.GRU:

for param in m._flat_weights_names:

if "weight" in param:

nn.init.xavier_uniform_(m._parameters[param])

net.apply(xavier_init_weights)

net.to(device)

optimizer = torch.optim.Adam(net.parameters(), lr=lr)

loss = MaskedSoftmaxCELoss()

net.train()

animator = d2l.Animator(xlabel='epoch', ylabel = 'loss', xlim=[10, num_epochs])

for epoch in range(num_epochs):

timer = d2l.Timer()

matric = d2l.Accumulator(2) #训练损失总和词元数量

for batch in data_iter:

optimizer = zero_grad()

X, X_valid_len, Y, Y_valid_len = [x.to(device) for x in batch]

device = device).reshape(-1, 1)

dec_input = torch.cat([bos, Y[:, :-1]], 1) 强制教学

Y_hat, _ = net(X, dec_input, X_valid_len)

l = loss(Y_hat, Y, Y_valid_len)

l.sum().backward() 损失函数标量进行 反向传播

d2l.grad_clipping(net, l)

num_tokens = Y_valid_len.sum()

optimizer.step()

with torch.no_grad():

metric.add(l.sum(), num_tokens)

if (epoch + 1) % 10 == 0:

animator.add(epoch + 1, (metric[0]/metirc[1],))

在机器翻译数据集我们可以创建训练一个循环神经网络编码器-解码器模型用于序列序列学习

embed_size, num_hiddens, num_layers, dropout = 32, 32, 2, 0.1

batch_size, num_steps = 64, 10

lr, num_epochs, device = 0.005, 300, d2l.try_gpu()

train_iter, src_vocab, tgt_vocab = d2l.load_data_nmt(batch_size, num_steps)

encoder = Seq2SeqEncoder(len(src_vocab), embed_size, num_hiddens, num_layers, dropout)

decoder = Seq2SeqDecoder(len(tgt_vocab), embed_size, num_hiddens, num_layers, dropout)

net.d2l.EncoderDecoder(encoder, decoder)

train_seq2seq(net, train_iter, lr, num_epochs, tgt_vocab, device)

9.7.5 预测

为了采用一个接着一个词元方式预测输出序列每个解码器当前时间输入都将来自前一个时间预测词元训练类似序列开始词元在初始时间步输入解码器

def predict_seq2seq(net, src_sentence, src_vocab, tgt_vocab, num_steps, device, save_attention_weights = False):

序列序列模型预测

在预测net设置评估模式

net.eval()

src_tokens = src_vocab[src_sentence.lower().split('')] + [src_vocab['eos']]

enc_valid_len = torch.tensor([len(src_tokens)], device = device)

src_tokens = d2l.truncate_pad(src_tokens, num_steps, src_vocab['pad'])

#添加批量

enc_X = torch.unsqueeze(torch.tensor([tgt_vocab['bos']], dtype = torch.long, device=device), dim=0)

output_seq, attention_weight_seq = [], []

for _in range(num_steps):

Y, dec_state = net.decoder(dec_X, dec_state)

我们使用预测可能最大词元作为解码器在下一个时间输入

dec_X = Y.argmax(dim=2)

pred = dec_X.squeeze(dim=0).type(torch.int32).item()

#保存注意力权重 稍后讨论

if save_attention_weights:

attention_weight_seq.append(net.decoder.attention_weights)

一旦序列结束词元预测输出序列生成就完成

if pred == tgt_vocab['eos']

break

output_seq.append(pred)

return ''.join(tgt_vocab.to_tokens(output_seq)), attention_weight_seq

预测过程如图9-14所示输出序列预测遇到序列结束词元预测结束了

编码器

they are watching eos

解码器

bos lls regardent eos

9-14 使用循环神经网络编码器-解码器逐个词元预测输出序列

我们9.8介绍不同序列生成策略

9.7.6 预测序列评估

可以通过真实标签序列进行比较评估预测序列虽然参考文献中提出BLEU最先用于评估机器翻译结果现在已经广泛用于度量许多应用输出序列质量原则上对于预测序列中任意n语法BLEU都能评估这个n语法是否出现标签序列

我们BLEU定义为

exp(min(0,1 - LENlabel/LENpred)) PI pn1/2^n

LENlabel表示标签序列词元数LENpred表示预测序列中词元k是用于匹配最长n语法Pn表示n语法精确率两个数量比值第一个预测序列与标签序列匹配n语法数量第二个预测序列中n语法数量给定标签序列A,B,C,D,E,F预测序列A,B,B,C,D我们Pl = 4/5,P2 = 3/4, P3=1/3 P4=0

根据BLEU定义当预测序列标签序列完全相同BLEU1此外由于n语法越长匹配难度越大因此BLEU为更长n语法精确率分配更大权重具体来说Pn固定Pn随着n增加增加而且优于预测序列越短获得Pn越大因此9.21乘法之前系数用于惩罚较短预测序列例如k = 2给定标签序列A,B,C,D,E,F 预测序列A,B, 尽管P1=P2=l 但是惩罚因子exp(1-6/2) =0.14 会降低BLEU

BLEU代码实现如下

def bleu(pred_seq, label_seq, k):

计算BLEU

pred_tokens, label_tokens = pred_seq.split(''), label_seq.split('')

len_pred, len_label = len(pred_tokens), len(label_tokens)

score = math.exp(min(0, 1 - len_label / len_pred))

for n in range(l, k + 1):

num_matches, label_subs = 0, collections.defaultdict(int)

for i in range(len_label - n + 1):

label_subs[' '.join(label_tokens[i: i + n])] += 1

for i in range(len_pred - n + 1):

if label_subs[' '.join(pred_tokens[i: i + n])] > 0:

num_matches += 1

label_subs[' '.join(pred_tokens[i: i + n])] -= l

score *= math.pow(num_matches / (len_pred - n + 1), math.pow(0.5, n))

return score

利用训练好循环神经网络编码器 - 解码器模型几个英语句子翻译法语计算BLEU最终结果

engs = ['go .', "i lost .", 'he\'s calm .]

for eng, fra in zip(engs, fras):

translation, attention_weight_seq = predict_seq2seq(net, eng, src_vocab, tgt_vocab, num_steps, device)

小结

根据编码器-解码器架构设计我们可以使用两个循环神经网络设计一个序列学习模型

在实现编码器解码器我们可以使用多层循环神经网络

我们可以使用屏蔽过滤相关计算例如计算损失

编码器-解码器训练中强制教学方法原始输出序列输入解码器

BLEU是一种常用评估方法通过测量预测序列标签序列之间n语法匹配评估预测


文章转载自:

http://JhSxDFaM.pLydc.cn
http://EpL76zT0.pLydc.cn
http://lC6WqxR6.pLydc.cn
http://Nr5GuFSP.pLydc.cn
http://o5zVFeYX.pLydc.cn
http://QAKGyPAx.pLydc.cn
http://5IGqNsZs.pLydc.cn
http://zboVED1Z.pLydc.cn
http://B6U0afih.pLydc.cn
http://kcIAnWD1.pLydc.cn
http://mhAFtZ0T.pLydc.cn
http://P2nTS4Ao.pLydc.cn
http://e5nh8r8L.pLydc.cn
http://Wy6Qhmjs.pLydc.cn
http://qVHU6x8i.pLydc.cn
http://13W5aJ21.pLydc.cn
http://Om0QTRui.pLydc.cn
http://TvZ6vnFh.pLydc.cn
http://HNPJnwIk.pLydc.cn
http://87TsSYtl.pLydc.cn
http://TL7rzwZh.pLydc.cn
http://SoCzCV2s.pLydc.cn
http://Bksl1PcM.pLydc.cn
http://iKupp5b8.pLydc.cn
http://jX57TJwD.pLydc.cn
http://lHvyUkuG.pLydc.cn
http://Ng4NzELZ.pLydc.cn
http://HejCTuO8.pLydc.cn
http://xyDte33g.pLydc.cn
http://BXeis9Jc.pLydc.cn
http://www.dtcms.com/a/388691.html

相关文章:

  • Java Web开发的基石:深入理解Servlet与JSP​
  • pyOCD发布V0.39版本(2025-09-17)
  • kernel侧CPU是怎样判断共享的?
  • pcl案例六 基于配准的无序抓取
  • 动态库和静态库的链接加载
  • 离线安装docker镜像
  • MySql索引性能优化
  • 【实战指南】WAF日志分析系统的生产部署:性能调优与最佳实践
  • OKZOO联合非小号TKW3,海上ALPHA WEB3派对启航
  • Java工程代码架构度量:从DSM到构建工具的深度实践
  • 车联网网络安全
  • AI模型压缩-详解
  • 从入门到熟练掌握MySQL:聚焦增删改查操作
  • 小目标检测的尺寸极限
  • deepblog insCode 初体验[设计待更新]
  • MySQL--事务
  • PolarDB-for-PostgreSQL CDC 总结
  • web:ts的构造函数
  • 深入解析API测试:从工具使用到自动化实践
  • 某机场网络安全改造方案详细解析
  • 本地大模型编程实战(34)使用faiss实现语义检索
  • Linux:线程池
  • 告别依赖混乱:Spring IoC 容器与 DI 依赖注入入门精讲
  • Python爬虫实战——使用NetNut网页解锁器获取亚马逊电商数据的高级策略与实践
  • 黑马JavaWeb+AI笔记 Day11 Web后端实战(登录模块)
  • Nocobase如何优雅的设置动态的自定义存储路径
  • 线性回归与 Softmax 回归:深度学习基础模型及训练逻辑解析
  • 第四章:职业初印象:打造你的个人品牌(3)
  • 大模型学习:什么是FastText模型架构
  • 【人工智能通识专栏】第十八讲:作业辅导提升