代码实现-pack_padded_sequence()与pad_packed_sequence()

近期实现一个基于BiGRU的项目,因为batch中的文本长短不一,如果不采取策略的话,对于短文本来说,就会有太多[pad]参与运算,使得最后的结果有太多无效信息,于是遇到了这俩标题中的函数。

下述内容有大量内容参考自:Pytorch中的RNN之pack_padded_sequence()和pad_packed_sequence() - sbj123456789 - 博客园为什么有pad和pack操作? 先看一个例子,这个batch中有5个sample 如果不用pack和pad操作会有一个问题,什么问题呢?比如上图,句子“Yes”只有一个单词,但是padding了多余的https://www.cnblogs.com/sbj123456789/p/9834018.html

目录

官方说明

详细说明


官方说明

首先贴上官方地址,有利于查看参数细节:

pack_padded_sequence():torch.nn.utils.rnn.pack_padded_sequence — PyTorch 1.10.0 documentationicon-default.png?t=LA92https://pytorch.org/docs/stable/generated/torch.nn.utils.rnn.pack_padded_sequence.htmlpad_packed_sequence():

torch.nn.utils.rnn.pad_packed_sequence — PyTorch 1.10.0 documentationicon-default.png?t=LA92https://pytorch.org/docs/stable/generated/torch.nn.utils.rnn.pad_packed_sequence.html

详细说明

pack_padded_sequence():压缩数据,简单来讲就是去除[pad],只让原本的数据参与RNN运算。具体看下图,这是一个含有5个文本的batch,在不使用该函数的情况下,以句子“Yes”为例,实际参与运算的时候,padding了多余的pad符号,从而导致RNN通过了非常多无用的字符,这样得到的句子表示就会有误差。

 那么,就会得到下图的计算方式:

理想的计算方式呢?不应该是计算完 Yes就结束了吗?是的,确实是这样,正如大家所想,所以有了下图: 

对的,于是有了 torch.nn.utils.rnn.pack_padded_sequence()

参数:

input (Tensor) – 一个待压缩的tensor,batch形式.

lengths (Tensor or list(int)) – batch元素的长度,list类型 (如果是tensor,则必须在cpu上).

batch_first (booloptional) – if True, 输入序列必须是 [B, L, dim],B - batch size,L - max_length,dim - 纬度。

enforce_sorted (booloptional) – if True, 输入序列按照长度降序排列. If False, 输入序列被随意排列. Default: True.

import torch
from torch.nn.utils.rnn import pack_padded_sequence, pad_packed_sequence
seq = torch.tensor([[1,2,0,0], [3,0,0,0], [4,5,6,0]])
lens = [2, 1, 3]
packed = pack_padded_sequence(seq, lens, batch_first=True, enforce_sorted=False)
print(packed)

会得到输出:

PackedSequence(data=tensor([4, 1, 3, 5, 2, 6]), batch_sizes=tensor([3, 2, 1]),
               sorted_indices=tensor([2, 0, 1]), unsorted_indices=tensor([1, 2, 0]))

需要注意:pack的形式不是按行压,而是按列压(上述案例可以发现,pack的时候,先对序列做了基于长度降序信息的排列,而后按列压缩,得到了 [4,1,3,5,2,6])。

压缩完以后,可以送进RNN中运算,那算完了咋办?算完了还得解压呀,于是出现了torch.nn.utils.rnn.pad_packed_sequence(sequence, batch_first=False, padding_value=0.0, total_length=None)

参数:

sequence (PackedSequence) – 添加pad的PackedSequence数据

batch_first (booloptional) – if True, 输出形式 [B, L, dim]

padding_value (floatoptional) – 指定pad的数值

total_length (intoptional) – if not None, 指定补齐后的sentence的长度为 total_length. 如果total_length小于sequence的最大长度值,那么就会报错 ValueError 

seq_unpacked, lens_unpacked = pad_packed_sequence(packed, batch_first=True)
print(seq_unpacked, lens_unpacked)

得到结果:

tensor([[1, 2, 0],
        [3, 0, 0],
        [4, 5, 6]])

tensor([2, 1, 3])

这里可以发现一个事情,就是最后的结果和我给定的输入不同,我给的是一个 3X4 的tensor,但是输出只有 3X3,这是因为在不指定 total_length 的情况下,返回结果是默认选择senquence的最大长度作为补齐长度的。

此外,我在这上面也反复遇到  ValueError ,最后说说怎么解决的吧。

主要关注pack_padded_sequence的输入input和lengths,最后锁定为:

input: [B, L, dim]、tensor

lengths: list

如果不违背上述两者,应该不会出错。

参考链接:

torch.nn.utils.rnn.pack_padded_sequence — PyTorch 1.10.0 documentation

torch.nn.utils.rnn.pad_packed_sequence — PyTorch 1.10.0 documentation

Pytorch中的RNN之pack_padded_sequence()和pad_packed_sequence() - sbj123456789 - 博客园

思考与总结是前进的基石!

  • 4
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值