pytorch实现seq2seq时对loss进行mask的方式

如何对loss进行mask

pytorch官方教程中有一个Chatbot教程,就是利用seq2seq和注意力机制实现的,感觉和机器翻译没什么不同啊,如果对话中一句话有下一句,那么就把这一对句子加入模型进行训练。其中在训练阶段,损失函数通常需要进行mask操作,因为一个batch中句子的长度通常是不一样的,一个batch中不足长度的位置需要进行填充(pad)补0,最后生成句子计算loss时需要忽略那些原本是pad的位置的值,即只保留mask中值为1位置的值,忽略值为0位置的值,具体演示如下:

import torch
import torch.nn as nn
import torch.nn.functional as F
import itertools

DEVICE = torch.device("cuda" if torch.cuda.is_available() else "cpu")

PAD_token = 0

首先是pad函数和建立mask矩阵,矩阵的维度应该和目标一致。

def zeroPadding(l, fillvalue=PAD_token):
 # 输入:[[1, 1, 1], [2, 2], [3]]
 # 返回:[(1, 2, 3), (1, 2, 0), (1, 0, 0)] 返回已经是转置后的 [L, B]
 return list(itertools.zip_longest(*l, fillvalue=fillvalue))

def binaryMatrix(l):
 # 将targets里非pad部分标记为1,pad部分标记为0
 m = []
 for i, seq in enumerate(l):
 m.append([])
 for token in seq:
  if token == PAD_token:
  m[i].append(0)
  else:
  m[i].append(1)
 return m

假设现在输入一个batch中有三个句子,我们按照长度从大到小排好序,LSTM或是GRU的输入和输出我们需要利用pack_padded_sequence和pad_packed_sequence进行打包和解包,感觉也是在进行mask操作。

inputs = [[1, 2, 3], [4, 5], [6]] # 输入句,一个batch,需要按照长度从大到小排好序
inputs_lengths = [3, 2, 1]
targets = [[1, 2], [1, 2, 3], [1]] # 目标句,这里的长度是不确定的,mask是针对targets的
inputs_batch = torch.LongTensor(zeroPadding(inputs))
inputs_lengths = torch.LongTensor(inputs_lengths)
targets_batch = torch.LongTensor(zeroPadding(targets))
targets_mask = torch.ByteTensor(binaryMatrix(zeroPadding(targets))) # 注意这里是ByteTensor
print(inputs_batch)
print(targets_batch)
print(targets_mask)

打印后结果如下,可见维度统一变成了[L, B],并且mask和target长得一样。另外,seq2seq模型处理时for循环每次读取一行,预测下一行的值(即[B, L]时的一列预测下一列)。

tensor([[ 1, 4, 6],
 [ 2, 5, 0],
 [ 3, 0, 0]])
tensor([[ 1, 1, 1],
 [ 2, 2, 0],
 [ 0, 3, 0]])
tensor([[ 1, 1, 1],
 [ 1, 1, 0],
 [ 0, 1, 0]], dtype=torch.uint8)

现在假设我们将inputs输入模型后,模型读入sos后预测的第一行为outputs1, 维度为[B, vocab_size],即每个词在词汇表中的概率,模型输出之前需要softmax。

outputs1 = torch.FloatTensor([[0.2, 0.1, 0.7], [0.3, 0.6, 0.1], [0.4, 0.5, 0.1]])
print(outputs1)
tensor([[ 0.2000, 0.1000, 0.7000],
 [ 0.3000, 0.6000, 0.1000],
 [ 0.4000, 0.5000, 0.1000]])

先看看两个函数

torch.gather(input, dim, index, out=None)->Tensor

沿着某个轴,按照指定维度采集数据,对于3维数据,相当于进行如下操作:

out[i][j][k] = input[index[i][j][k]][j][k] # if dim == 0
out[i][j][k] = input[i][index[i][j][k]][k] # if dim == 1
out[i][j][k] = input[i][j][index[i][j][k]] # if dim == 2

比如在这里,在第1维,选第二个元素。

# 收集每行的第2个元素
temp = torch.gather(outputs1, 1, torch.LongTensor([[1], [1], [1]]))
print(temp)
tensor([[ 0.1000],
 [ 0.6000],
 [ 0.5000]])

torch.masked_select(input, mask, out=None)->Tensor

根据mask(ByteTensor)选取对应位置的值,返回一维张量。

例如在这里我们选取temp大于等于0.5的值。

mask = temp.ge(0.5) # 大于等于0.5
print(mask)
print(torch.masked_select(temp, temp.ge(0.5)))
tensor([[ 0],
 [ 1],
 [ 1]], dtype=torch.uint8)
tensor([ 0.6000, 0.5000])

然后我们就可以计算loss了,这里是负对数损失函数,之前模型的输出要进行softmax。

# 计算一个batch内的平均负对数似然损失,即只考虑mask为1的元素
def maskNLLLoss(inp, target, mask):
 nTotal = mask.sum()
 # 收集目标词的概率,并取负对数
 crossEntropy = -torch.log(torch.gather(inp, 1, target.view(-1, 1)))
 # 只保留mask中值为1的部分,并求均值
 loss = crossEntropy.masked_select(mask).mean()
 loss = loss.to(DEVICE)
 return loss, nTotal.item()

这里我们计算第一行的平均损失。

# 计算预测的第一行和targets的第一行的loss
maskNLLLoss(outputs1, targets_batch[0], targets_mask[0])

(tensor(1.1689, device='cuda:0'), 3)

最后进行最后把所有行的loss累加起来变为total_loss.backward()进行反向传播就可以了。

以上这篇pytorch实现seq2seq时对loss进行mask的方式就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持我们。

(0)

相关推荐

  • python实现根据给定坐标点生成多边形mask的例子

    处理数据集的过程中用到了mask 但是源数据集中只给了mask顶点的坐标值,那么在python中怎么实现生成只有0.1表示的mask区域呢? 主要借鉴cv2中的方法: (我使用的数据情况是将顶点坐标分别存储在roi.mat中的x和y元素) matfn = 'roi.mat' data = sio.loadmat(matfn) x_cor = data['x'] y_cor = data['y'] im = np.zeros(图像对应尺寸, dtype="uint8") cor_xy =

  • python_mask_array的用法

    掩码数组 数据很大形况下是凌乱的,并且含有空白的或者无法处理的字符,掩码式数组可以很好的忽略残缺的或者是无效的数据点.掩码式数组由一个正常数组与一个布尔式数组组成,若布尔数组中为Ture,则表示正常数组中对应下标的值无效,反之False表示对应正常数组的值有效. numpy.ma模块中提供掩码数组的处理,这个模块中几乎完整复制了numpy中的所有函数,并提供掩码数组的功能: >>>import numpy.ma as ma >>>x = np.array([1,2,3,

  • Pytorch mask_select 函数的用法详解

    非常简单的函数,但是官网的介绍令人(令我)迷惑,所以稍加解释. mask_select会将满足mask(掩码.遮罩等等,随便翻译)的指示,将满足条件的点选出来. 根据掩码张量mask中的二元值,取输入张量中的指定项( mask为一个 ByteTensor),将取值返回到一个新的1D张量, 张量 mask须跟input张量有相同数量的元素数目,但形状或维度不需要相同 x = torch.randn(3, 4) x 1.2045 2.4084 0.4001 1.1372 0.5596 1.5677

  • pytorch实现seq2seq时对loss进行mask的方式

    如何对loss进行mask pytorch官方教程中有一个Chatbot教程,就是利用seq2seq和注意力机制实现的,感觉和机器翻译没什么不同啊,如果对话中一句话有下一句,那么就把这一对句子加入模型进行训练.其中在训练阶段,损失函数通常需要进行mask操作,因为一个batch中句子的长度通常是不一样的,一个batch中不足长度的位置需要进行填充(pad)补0,最后生成句子计算loss时需要忽略那些原本是pad的位置的值,即只保留mask中值为1位置的值,忽略值为0位置的值,具体演示如下: im

  • pytorch在fintune时将sequential中的层输出方法,以vgg为例

    有时候我们在fintune时发现pytorch把许多层都集合在一个sequential里,但是我们希望能把中间层的结果引出来做下一步操作,于是我自己琢磨了一个方法,以vgg为例,有点僵硬哈! 首先pytorch自带的vgg16模型的网络结构如下: VGG( (features): Sequential( (0): Conv2d (3, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1)) (1): ReLU(inplace) (2): Co

  • pytorch实现focal loss的两种方式小结

    我就废话不多说了,直接上代码吧! import torch import torch.nn.functional as F import numpy as np from torch.autograd import Variable ''' pytorch实现focal loss的两种方式(现在讨论的是基于分割任务) 在计算损失函数的过程中考虑到类别不平衡的问题,假设加上背景类别共有6个类别 ''' def compute_class_weights(histogram): classWeigh

  • Pytorch训练网络过程中loss突然变为0的解决方案

    问题 // loss 突然变成0 python train.py -b=8 INFO: Using device cpu INFO: Network: 1 input channels 7 output channels (classes) Bilinear upscaling INFO: Creating dataset with 868 examples INFO: Starting training: Epochs: 5 Batch size: 8 Learning rate: 0.001

  • 解决Numpy与Pytorch彼此转换时的坑

    前言 ​   最近使用 Numpy包与Pytorch写神经网络时,经常需要两者彼此转换,故用此笔记记录码代码时踩(菜)过的坑,网上有人说: Pytorch 又被称为 GPU 版的 Numpy,二者的许多功能都有良好的一一对应. ​但在使用时还是得多多注意,一个不留神就陷入到了 一根烟一杯酒,一个Bug找一宿 的地步. 1.1.numpy --> torch ​   使用 torch.from_numpy() 转换,需要注意,两者共享内存.例子如下: import torch import num

  • Pytorch测试神经网络时出现 RuntimeError:的解决方案

    Pytorch测试神经网络时出现"RuntimeError: Error(s) in loading state_dict for Net" 解决方法: load_state_dict(torch.load('net.pth') 在前,增加 model = nn.DataParallel(model) 就可以了. 比如 net = NET() net.cuda() net = nn.DataParallel(net) net.load_state_dict(torch.load('ne

  • Pytorch 多维数组运算过程的索引处理方式

    背景:对 python 不熟悉,能看懂代码,也能实现一些简单的功能,但是对 python 的核心思想和编程技巧不熟,所以使 Pytorch 写 loss 的时候遇到很多麻烦,尤其是在 batch_size > 1 的时候,做矩阵乘法之类的运算会觉得特别不顺手. 所幸,在边查边写的过程中,理解了 python 中多维运算的实现规则. 1.python 的基本索引规则 从 0 开始 对于给定的范围,如 b = a[m:n], 那么 b 为由 (n-m)个数据组成的新数组,由 a[m],a[m+1],

  • pytorch 实现模型不同层设置不同的学习率方式

    在目标检测的模型训练中, 我们通常都会有一个特征提取网络backbone, 例如YOLO使用的darknet SSD使用的VGG-16. 为了达到比较好的训练效果, 往往会加载预训练的backbone模型参数, 然后在此基础上训练检测网络, 并对backbone进行微调, 这时候就需要为backbone设置一个较小的lr. class net(torch.nn.Module): def __init__(self): super(net, self).__init__() # backbone

  • pytorch实现用CNN和LSTM对文本进行分类方式

    model.py: #!/usr/bin/python # -*- coding: utf-8 -*- import torch from torch import nn import numpy as np from torch.autograd import Variable import torch.nn.functional as F class TextRNN(nn.Module): """文本分类,RNN模型""" def __ini

  • 使用 PyTorch 实现 MLP 并在 MNIST 数据集上验证方式

    简介 这是深度学习课程的第一个实验,主要目的就是熟悉 Pytorch 框架.MLP 是多层感知器,我这次实现的是四层感知器,代码和思路参考了网上的很多文章.个人认为,感知器的代码大同小异,尤其是用 Pytorch 实现,除了层数和参数外,代码都很相似. Pytorch 写神经网络的主要步骤主要有以下几步: 1 构建网络结构 2 加载数据集 3 训练神经网络(包括优化器的选择和 Loss 的计算) 4 测试神经网络 下面将从这四个方面介绍 Pytorch 搭建 MLP 的过程. 项目代码地址:la

随机推荐