一开始写这篇随笔的时候还没有了解到 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. 最短路径Dijkstra matlab

    Dijkstra: function [dist,pre, full_path]=MinRoad_Dijkstra(G,v0) n=0; if isfield(G,'w') && ~i ...

  2. Arcgis创建SDE_Geometry、SDO_Geometry的区别

    先初略的了解下SDE_Geometry和SDO_Geometry的区别: 1. SDO_GEOMETRY Oracle Spatial在MDSYS模式下定义了一系列几何类型.函数来支持空间数据的存储和 ...

  3. 谁对EXTJS熟悉,有关关闭panel的问题?

    谁对EXTJS熟悉,有关关闭panel的问题?比如:我在A.js 中写了一个  var  win  =   new  Ext.Window( { b.js });   win.show(); 打开了一 ...

  4. CF700E:Cool Slogans(SAM,线段树合并)

    Description 给你一个字符串,如果一个串包含两个可有交集的相同子串,那么这个串的价值就是子串的价值+1.问你给定字符串的最大价值子串的价值. Input 第一行读入字符串长度$n$,第二行是 ...

  5. 【转】 [置顶] Android 通知栏Notification的整合 全面学习 (一个DEMO让你完全了解它)

    在Android的应用层中,涉及到很多应用框架,例如:Service框架,Activity管理机制,Broadcast机制,对话框框架,标题栏框架,状态栏框架,通知机制,ActionBar框架等等. ...

  6. mac apache的使用

    因为apache的安装目录/private/etc是默认隐藏的,所以我们需要通过文件夹前往/命令行的方法去找. 或命令行中输入: userdeMBP:~ user$ open /etc 然后都会打开相 ...

  7. day4-课堂笔记

    变量 成员变量-构造方法里定义 self.xxx 使用:类内部: self.xxx 类外部: 先创建实例 实例.xxx 类变量 类定义下面直接定义 使用:类方法内 cls.xxx 类名.xxx sel ...

  8. Drool实战系列(二)之eclipse安装drools插件

    这里演示是drools7.5.0,大家可以根据自己需要安装不同的drools版本 drools安装地址: http://download.jboss.org/drools/release/ 一. 二. ...

  9. 【LeeCode23】Merge k Sorted Lists★★★

    1.题目描述: 2.解题思路: 题意:将K个已经排序的链表合并成一个排序的链表,分析并描述所用算法的复杂度. 方法一:基于“二分”思想的归并排序.本文用非递归和递归两种方法实现. (1)非递归:归并排 ...

  10. Wpf(Storyboard)动画简单实例

    原文:Wpf(Storyboard)动画简单实例 动画的三种变换方式 RotateTransform:旋转变换变化值:CenterX围绕转的圆心横坐标 CenterY纵坐标 Angle旋转角度(角度正 ...