近期实现一个基于BiGRU的项目,因为batch中的文本长短不一,如果不采取策略的话,对于短文本来说,就会有太多[pad]参与运算,使得最后的结果有太多无效信息,于是遇到了这俩标题中的函数。
目录
官方说明
首先贴上官方地址,有利于查看参数细节:
pack_padded_sequence():torch.nn.utils.rnn.pack_padded_sequence — PyTorch 1.10.0 documentationhttps://pytorch.org/docs/stable/generated/torch.nn.utils.rnn.pack_padded_sequence.htmlpad_packed_sequence():
详细说明
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 (bool, optional) – if True
, 输入序列必须是 [B, L, dim],B - batch size,L - max_length,dim - 纬度。
enforce_sorted (bool, optional) – 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 (bool, optional) – if True
, 输出形式 [B, L, dim]
padding_value (float, optional) – 指定pad的数值
total_length (int, optional) – 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 - 博客园
思考与总结是前进的基石!