一开始写这篇随笔的时候还没有了解到 Dateloader有一个 collate_fn 的参数,通过定义一个collate_fn 函数,其实很多batch补齐到当前batch最长的操作可以放在collate_fn 里面去,这样代码在训练和模型中就可以更加简洁。有时间再整理一下这个吧。

_________________________________________

使用的主要部分包括:Dateset、 Dateloader、MSELoss、PackedSequence、pack_padded_sequence、pad_packed_sequence

模型包含LSTM模块。

参考了下面两篇博文,总结了一下。对PackedSequence相关的理解可以先看这两篇。本文主要是把这些应用从数据准备到loss计算都串起来大致提供了一下代码思路,权当给自己的提醒备份吧。或者看完下面两篇,但是不知道具体怎么操作的朋友们一个参考。

http://www.cnblogs.com/lindaxin/p/8052043.html#commentform

https://blog.csdn.net/lssc4205/article/details/79474735

使用Dateset构建数据集的时候,在__getitem__函数中把所有数据先补齐到 全局最长序列的长度。

def __getitem__(self, index):
'''
get original data
此处省略获取原始数据的代码
input_data,output_data
数据shape是 seq_length * feature_dim
'''
# 当前seq_length小于所有数据中的最长数据长度,则补0到同一长度。
ori_length = input_data.shape[0]
if ori_length < self.max_len:
npi = np.zeros(self.input_feature_dim, dtype=np.float32)
npi = np.tile(npi, (self.max_len - ori_length,1))
input_data = np.row_stack((input_data, npi))
npo = np.zeros(self.output_feature_dim, dtype=np.float32)
npo = np.tile(npo, (self.max_len - ori_length,1))
output_data = np.row_stack((output_data, npo))
return input_data, output_data, ori_length, input_data_path

在模型中,forward的实现中,需要在LSTM之前使用pack_padded_sequence、在LSTM之后使用pad_packed_sequence,中间还涉及到顺序的还原之类的操作。

def forward(self, input_x, length_list, hidden=None):
if hidden is None:
# 这里没用 配置中的batch_size,而是直接在input_x中取batch_size是为了防止last_batch的batch_size不是配置中的那个,引发bug
h_0 = input_x.data.new(self.directional*self.layer_num, input_x.shape[0], self.hidden_dim).fill_(0).float()
c_0 = input_x.data.new(self.directional*self.layer_num, input_x.shape[0], self.hidden_dim).fill_(0).float()
else:
h_0, c_0 = hidden
'''
省略模型其他部分,直接进去LSTM前后的操作
'''
_, idx_sort = torch.sort(length_list, dim=0, descending=True)
_, idx_unsort = otrch.sort(idx_sort, dim=0) input_x = input_x.index_select(0, Variable(idx_sort))
length_list = list(length_list[idx_sort])
pack = nn_utils.rnn.pack_padded_sequence(input_x, length_list, batch_first=self.batch_first)
output, hidden = self.BiLSTM(pack, (h0, c0))
un_padded = nn_utils.rnn.pad_packed_sequence(output, batch_first=self.batch_first)
un_padded = un_padded[0].index_select(0, Variable(idx_unsort))
# 此时的un_padded已经完成了还原,并且补0完成,而且这时的补0到的序列长度是当前batch的最长长度,而不是Dateset中的全局最长长度!
# 所以在main train函数中也要对label的seq做处理
return un_padded

main train中,要对label做相应的截断处理,因为模型返回的长度已经是补齐到当前batch的最长序列长度了,而dateset返回的label是补齐到全局最长序列长度。算loss的时候,MSELoss的reduce参数要设置成false,让loss函数返回一个loss矩阵,再构造一个01掩膜矩阵mask,矩阵相乘求和得到真的loss(达到填充0的位置不参与loss的目的)

def train(**kwargs):
  train_data = my_dataset()
  train_dataloader = DataLoader(train_data, opt.batch_size, shuffle=True, num_workers=opt.num_workers)
  model = getattr(models, opt.model)(batchsize=opt.batch_size)
  criterion = torch.nn.MSELoss(reduce=False)
  lr = opt.lf
  optimizer = torch.optim.Adam(model.parameters(), lr=lr, weight_decay=opt.weight_decay)
  for epoch in range(opt.start_epoch, opt.max_epoch):
    for ii, (data, label, length_list,_) in tqdm(enumerate(train_dataloader)):
      cur_batch_max_len = length_list.max()
      data = Variable(data)
      target = Variable(label)       optimizer.zero_grad()
      score = model(data, length_list)
      loss_mat = criterion(score, target)
      list_int = list(length_list)
      mask_mat = Variable(t.ones(len(list_int),cur_batch_max_len,opt.output_feature_dim))
      num_element = 0
      for idx_sample in range(len(list_int)):
        num_element += list_int[idx_sample] * opt.output_feature_dim
        if list_int[idx_sample] != cur_batch_max_len:
          mask_mat[idx_sample, list[idx_sample]:] = 0.0       loss = (loss_mat * mask_mat).sum() / num_element
      loss.backward()
      optimizer.step()

pytorch 对变长序列的处理的更多相关文章

  1. pytorch中如何处理RNN输入变长序列padding

    一.为什么RNN需要处理变长输入 假设我们有情感分析的例子,对每句话进行一个感情级别的分类,主体流程大概是下图所示: 思路比较简单,但是当我们进行batch个训练数据一起计算的时候,我们会遇到多个训练 ...

  2. keras: 在构建LSTM模型时,使用变长序列的方法

    众所周知,LSTM的一大优势就是其能够处理变长序列.而在使用keras搭建模型时,如果直接使用LSTM层作为网络输入的第一层,需要指定输入的大小.如果需要使用变长序列,那么,只需要在LSTM层前加一个 ...

  3. 0-3为变长序列建模modeling variable length sequences

    在本节中,我们会讨论序列的长度是变化的,也是一个变量 we would like the length of sequence,n,to alse be a random variable 一个简单的 ...

  4. Python技法1:变长和定长序列拆分

    Python中的任何序列(可迭代的对象)都可以通过赋值操作进行拆分,包括但不限于元组.列表.字符串.文件.迭代器.生成器等. 元组拆分 元组拆分是最为常见的一种拆分,示例如下: p = (4, 5) ...

  5. C++中的变长参数

    新参与的项目中,为了使用共享内存和自定义内存池,我们自己定义了MemNew函数,且在函数内部对于非pod类型自动执行构造函数.在需要的地方调用自定义的MemNew函数.这样就带来一个问题,使用stl的 ...

  6. Scala 变长参数

    如果Scala定义变长参数 def sum(i Int*), 那么调用sum时,可以直接输入sum(1,2,3,4,5) 但是不可以sum(1 to 5) 必须要将1 to 5 强制为seq sum( ...

  7. 报文格式:xml 、定长报文、变长报文

    目前接触到的报文格式有三种:xml .定长报文.变长报文 . 此处只做简单介绍,日后应该会深入学习到三者之间如何解析,再继续更新.——2016.9.23 XML XML 被设计用来传输和存储数据. H ...

  8. GCC 中零长数组与变长数组

    前两天看程序,发现在某个函数中有下面这段程序: int n; //define a variable n int array[n]; //define an array with length n 在 ...

  9. 删除变长列字段后使用DBCC CLEANTABLE回收空间

    标签:SQL Server Reclaim space 收缩表 原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 .作者信息和本声明.否则将追究法律责任.http://lzf328.bl ...

随机推荐

  1. security/pam_appl.h:没有那个文件或目录

    在编译开源库时, 提示 pam.h:4:10: 致命错误:security/pam_appl.h:没有那个文件或目录 #include <security/pam_appl.h> 解决方法 ...

  2. 人工智能——Singleton模式

    上次在状态模式中的设计有一个严重的问题,就是如下: voidCTroll::ChageState(CState* pNewState) {        deletem_pCurrentState; ...

  3. Alpha冲刺&总结报告(12/12)(麻瓜制造者)

    各个成员今日完成的任务 邓弘立: 完成了上传头像的功能 符天愉: 对所有接口进行了再次测试 江郑: 完成了发布需求接口部分的进一步测试和接口文档的编写 刘双玉: 完成了商品信息接口部分的进一步测试和接 ...

  4. 【python】关于python中模块导入的总结

    precondition:比如我有如下这样的文件目录结构 说明:add和debug两个包都隶属于src目录,它们是同级目录,其中在add路径下有一个add.py的模块,里面定义了一个jiafa()的函 ...

  5. CompletionService简讲

    背景 最近在项目中看到太多后台task中使用Executor框架,提交任务后,把future都一个个加入到list,再一个个get这些future的代码. 这个的问题在于一方面没有时限,可能会被某些运 ...

  6. Django基础与组件

    第一章:Django系列之web应用与http协议 第二章:基于wsgiref模块DIY一个web框架 第三章:Django下载与简介 第四章:url控制系统 第五章:视图 第六章:Django模板语 ...

  7. Python接口自动化--requests 1

    # _*_ encoding:utf-8 _*_ import requests #请求博客园首页,无参数的get请求 r = requests.get('http://www.cnblogs.com ...

  8. 【转】jquery cookie操作

    Cookie是网站设计者放置在客户端的小文本文件.Cookie能为用户提供很多的使得,例如购物网站存储用户曾经浏览过的产品列表,或者门户网站记住用户喜欢选择浏览哪类新闻. 在用户允许的情况下,还可以存 ...

  9. git版本管理工具-git的概述

    什么是git Git是一个开源的分布式版本控制系统,用于敏捷高效地处理任何或小或大的项目的一种工具 Git 与常用的版本控制工具 CVS, Subversion 等不同,它采用了分布式版本库的方式,不 ...

  10. OpenCV——直方图计算、寻早最值位置和对比匹配(判断两幅图的相似程度)