对pytorch中不定长序列补齐的操作

第二种方法通常是在load一个batch数据时, 在collate_fn中进行补齐的.

以下给出两种思路:

第一种思路是比较容易想到的, 就是对一个batch的样本进行遍历, 然后使用np.pad对每一个样本进行补齐.

for unit in data:
        mask = np.zeros(max_length)
        s_len = len(unit[0])    # calculate the length of sequence in each unit
        mask[: s_len] = 1
        unit[0] = np.pad(unit[0], (0, max_length - s_len), 'constant', constant_values=(0, 0))
        mask_batch.append(mask)

但是这种方法在batch size很大的情况下会很慢, 因为使用for循环进行了遍历. 我在实际用的时候, 当batch_size=128时, 一个batch的加载时间甚至是一个batch训练时间的几倍!

因此, 我想到如何并行地对序列进行补齐. 第二种方法的思路就是使用torch中自带的pad_sequence来并行补齐.

batch_sequence = list(map(lambda x: torch.tensor(x[findex]), x_data))
batch_data[feat] = torch.nn.utils.rnn.pad_sequence(batch_sequence).T

可以看到这里使用pad_sequence一次性对整个batch进行补齐. 下面对这个函数进行详细说明.

pad_sequence详解

from torch.utils.rnn import pad_sequence
a = torch.ones(10)
b = torch.ones(6)
c = torch.ones(20)
abc = pad_sequence([a,b,c])  # shape(20, 3)

注意这个函数接收的是一个元素为tensor的列表, 而不是tensor.

最终, 这个函数会将所有tensor转换为tensor矩阵#shape(max_length, batch_size). 因此, 在使用完后通常还需要转置一下.

补充:PyTorch中用于RNN变长序列填充函数的简单使用

1、PyTorch中RNN变长序列的问题   

RNN在处理变长序列时有它的优势。在分批处理变长序列问题时,每个序列的长度往往不会完全相等,因此针对一个batch中序列长度不一的情况,需要对某些序列进行PAD(填充)操作,使得一个batch内的序列长度相等。   

PyTorch中的pack_padded_sequence和pad_packed_sequence可处理上述问题,以下用一个示例演示这两个函数的简单使用方法。

2、填充函数简介

“压缩”函数:用于将填充后的序列tensor进行压缩,方便RNN处理

pack_padded_sequence(input, lengths, batch_first=False, enforce_sorted=True)

(1)input->被“压缩”的tensor,维度一般为[batch_size,_max_seq_len[,embedding_size]]或者[max_seq_len,batch_size[,embedding_size]]

若input维度为:[batch_size,_max_seq_len[,embedding_size]]

要将batch_first设置为True,这表示input的第一个维度为batch的数量

若input维度为:[max_seq_len,batch_size[,embedding_size]]

要将batch_first设置为False(默认值),这表示input的第一个维度不是batch的数量

(2)lengths->lengths参数表示一个batch中序列真实长度,类型为列表,在例子中详细说明

(3)batch_first->表示batch的数量是否在input的第一维度,默认值为False

(4)enforce_sorted->input中的会自动按照lengths的情况进行排序,默认值为

“解压”函数:该函数与"压缩函数"相对应,经“压缩函数”处理的输入经过RNN得到的最终结果可以利用该函数进行“解压”

pad_packed_sequence(sequence, batch_first=False, padding_value=0.0, total_length=None):

(1)sequence->压缩函数处理过的input经RNN后得到的结果

(2)batch_first->与“压缩”函数中的batch_first一致

(3)padding_value->序列进行填充时使用的索引,默认为0

(4)total_length->暂略

3、PyTorch代码示例

代码如下(示例):

# Create by leslie_miao on 2020/11/1
import torch
import torch.nn as nn
d_model = 10 # 词嵌入的维度
hidden_size = 20 # lstm隐藏层单元数量
layer_num = 1 # lstm层数
# 输入inputs,维度为[batch_size,max_seq_len]=[3,4],其中0代表填充
# 该input包含3个序列,每个序列的真实长度分别为: 4 3 2
inputs = torch.tensor([[1,2,3,4],[1,2,3,0],[1,2,0,0]])
embedding = nn.Embedding(5,d_model)
# 获取词嵌入后的inputs 当前inputs的维度为[batch_size,max_seq_len,d_model]=[3,4,10]
inputs = embedding(inputs)
# 查看inputs的维度
print(inputs.size())
# print: torch.Size([3, 4, 10])
# 利用“压缩”函数对inputs进行压缩处理,[4,3,2]分别为inputs中序列的真实长度,batch_first=True表示inputs的第一维是batch_size
inputs = nn.utils.rnn.pack_padded_sequence(inputs,lengths=[4,3,2],batch_first=True)
# 查看经“压缩”函数处理过的inputs的维度
print(inputs[0].size())
# print: torch.Size([9, 10])
# 定义RNN网络
network = nn.LSTM(input_size=d_model,hidden_size=hidden_size,batch_first=True,num_layers=layer_num)
# 初始化RNN相关门参数
c_0 = torch.zeros((layer_num,3,hidden_size))
h_0 = torch.zeros((layer_num,3,hidden_size)) # [rnn层数,batch_size,hidden_size]
# inputs经过RNN网络后得到的结果outputs
output,(h_n,c_n) = network(inputs,(h_0,c_0))
#查看未经“解压函数”处理的outputs维度
print(output[0].size())
# print: torch.Size([9, 20])
# 利用“解压函数”对outputs进行解压操作,其中batch_first设置与“压缩函数相同”,padding_value为0
output = nn.utils.rnn.pad_packed_sequence(output,batch_first=True,padding_value=0)
# 查看经“解压函数”处理的outputs维度
print(output[0].size())
# print:torch.Size([3, 4, 20])

总结

介绍了PyTorch中两个应用于RNN变长序列填充的函数pack_padded_sequence和 pad_packed_sequence的简单使用方法,欢迎指正交流!

(0)

相关推荐

  • 详解PyTorch中Tensor的高阶操作

    条件选取:torch.where(condition, x, y) → Tensor 返回从 x 或 y 中选择元素的张量,取决于 condition 操作定义: 举个例子: >>> import torch >>> c = randn(2, 3) >>> c tensor([[ 0.0309, -1.5993, 0.1986], [-0.0699, -2.7813, -1.1828]]) >>> a = torch.ones(2,

  • pytorch中的nn.ZeroPad2d()零填充函数实例详解

    在卷积神经网络中,有使用设置padding的参数,配合卷积步长,可以使得卷积后的特征图尺寸大小不发生改变,那么在手动实现图片或特征图的边界零填充时,常用的函数是nn.ZeroPad2d(),可以指定tensor的四个方向上的填充,比如左边添加1dim.右边添加2dim.上边添加3dim.下边添加4dim,即指定paddin参数为(1,2,3,4),本文中代码设置的是(3,4,5,6)如下: import torch.nn as nn import cv2 import torchvision f

  • pytorch对可变长度序列的处理方法详解

    主要是用函数torch.nn.utils.rnn.PackedSequence()和torch.nn.utils.rnn.pack_padded_sequence()以及torch.nn.utils.rnn.pad_packed_sequence()来进行的,分别来看看这三个函数的用法. 1.torch.nn.utils.rnn.PackedSequence() NOTE: 这个类的实例不能手动创建.它们只能被 pack_padded_sequence() 实例化. PackedSequence

  • 对pytorch中不定长序列补齐的操作

    第二种方法通常是在load一个batch数据时, 在collate_fn中进行补齐的. 以下给出两种思路: 第一种思路是比较容易想到的, 就是对一个batch的样本进行遍历, 然后使用np.pad对每一个样本进行补齐. for unit in data: mask = np.zeros(max_length) s_len = len(unit[0]) # calculate the length of sequence in each unit mask[: s_len] = 1 unit[0]

  • java中不定长参数的实例用法

    java中不定长参数的使用方法 不定长参数方法的语法如下: 返回值 方法名(参数类型...参数名称) 在参数列表中使用"..."形式定义不定长参数,其实这个不定长参数a就是一个数组,编译器会将(int...a)这种形式看作是(int[] a)的形式. 示例:编写一个不定长参数方法. /** * 定义不定长参数方法 * * @author pan_junbiao * */ public class MyTest { public static int add(int... a) { in

  • pytorch中的上采样以及各种反操作,求逆操作详解

    import torch.nn.functional as F import torch.nn as nn F.upsample(input, size=None, scale_factor=None,mode='nearest', align_corners=None) r"""Upsamples the input to either the given :attr:`size` or the given :attr:`scale_factor` The algorith

  • 在Pytorch中使用Mask R-CNN进行实例分割操作

    在这篇文章中,我们将讨论mask R-CNN背后的一些理论,以及如何在PyTorch中使用预训练的mask R-CNN模型. 1.语义分割.目标检测和实例分割 之前已经介绍过: 1.语义分割:在语义分割中,我们分配一个类标签(例如.狗.猫.人.背景等)对图像中的每个像素. 2.目标检测:在目标检测中,我们将类标签分配给包含对象的包围框. 一个非常自然的想法是把两者结合起来.我们只想在一个对象周围识别一个包围框,并且找到包围框中的哪些像素属于对象. 换句话说,我们想要一个掩码,它指示(使用颜色或灰

  • Python函数中不定长参数的写法

    1.不定长参数的写法,用 *变量名 表示 2.不定长参数累加 3.不定长参数,使用**c接受m=23,n=56的值: 传参时,a必写,b.c可以缺省 def fun(a, b, *args): print(a) print(b) print(args) print("="*30) ret = a + b for i in args: ret += i return ret print(fun(1,2,3,4)) 结果: 1 2 (3, 4) ======================

  • 解决pytorch rnn 变长输入序列的问题

    pytorch实现变长输入的rnn分类 输入数据是长度不固定的序列数据,主要讲解两个部分 1.Data.DataLoader的collate_fn用法,以及按batch进行padding数据 2.pack_padded_sequence和pad_packed_sequence来处理变长序列 collate_fn Dataloader的collate_fn参数,定义数据处理和合并成batch的方式. 由于pack_padded_sequence用到的tensor必须按照长度从大到小排过序的,所以在

  • 对Pytorch 中的contiguous理解说明

    最近遇到这个函数,但查的中文博客里的解释貌似不是很到位,这里翻译一下stackoverflow上的回答并加上自己的理解. 在pytorch中,只有很少几个操作是不改变tensor的内容本身,而只是重新定义下标与元素的对应关系的.换句话说,这种操作不进行数据拷贝和数据的改变,变的是元数据. 这些操作是: narrow(),view(),expand()和transpose() 举个栗子,在使用transpose()进行转置操作时,pytorch并不会创建新的.转置后的tensor,而是修改了ten

  • Python中Dataframe元素为不定长list时的拆分分组

    目录 引言 解决方法 总结 引言 本文想要解决的问题是当DataFrame中某一列元素为不定长度的数组时,该如何对它们进行拆分分解为后续元素,从而进行进一步的提取操作,数据格式见下图: 解决方法  这个问题的解决思路首先是要不定长的数组填充成等长的数组,从而后续可以直接转换为元素为单一值的标准DataFrame,再和原DataFrame合并即可完成操作.填充的部分使用了map()方法来实现,实现前还需要获得数组的最大长度以确定填充数目.代码见下: a=[[['a','d'],['b'],['a'

  • oracle中创建序列及序列补零实例详解

    oracle中创建序列及序列补零实例详解 我们经常会在在DB中创建序列: -- Create sequence create sequence COMMON_SEQ minvalue 1 maxvalue 999999999 start with 1 increment by 1 cache 20 cycle; 我们的序列的最小值是从1开始,但是我们想让这种顺序取出来的序列的位数都一样,按照最大数的位数来算,我们需要8位的序列,那么我们就需要在1的前面补上7个零,只需要用下面的方法即可完成 se

  • Python函数中的不定长参数相关知识总结

    一. 不定长位置参数 # 在定义函数参数时,可以在形参的前面加*,该形参将获取所有的位置实参 # 它会将所有的实参保存在一个元组中 def fn(*args): print("args=", args) print("args type:", type(args)) # 带*形参和其他参数配合使用 def fn1(a, b, *args): print(a) print(b) print(args) # 下面这两种写法可以,但是在传实参的时候要注意 def fn2(

随机推荐