pytorch中RNN如何处理作为压缩序列给出的填充序列?

pytorch中RNN如何处理作为压缩序列给出的填充序列?,pytorch,Pytorch,在pytorch中,我们可以将压缩序列作为RNN的输入。从中,RNN的输入可以如下所示 输入(顺序、批次、输入大小):包含输入序列特征的张量。输入也可以是压缩可变长度序列 范例 packed = torch.nn.utils.rnn.pack_padded_sequence(embedded, input_lengths) outputs, hidden = self.rnn(packed, hidden) outputs, output_lengths = torch.nn.utils.rnn

在pytorch中,我们可以将压缩序列作为RNN的输入。从中,RNN的输入可以如下所示

输入(顺序、批次、输入大小):包含输入序列特征的张量。输入也可以是压缩可变长度序列

范例

packed = torch.nn.utils.rnn.pack_padded_sequence(embedded, input_lengths)
outputs, hidden = self.rnn(packed, hidden)
outputs, output_lengths = torch.nn.utils.rnn.pad_packed_sequence(outputs)
这里,
embedded
是批输入的嵌入式表示


我的问题是,如何对RNN中的压缩序列进行计算?如何通过压缩表示为批次中的填充序列计算隐藏状态?

基于matthew_zeng的回答:填充元素不计算输出,隐藏将是最后一次有效输入后的隐藏状态。

对于第二个问题:填充序列的隐藏状态将不会被计算。

要回答这是如何发生的,让我们先看看打包填充序列对我们有什么作用:

from torch.nn.utils.rnn import pad_sequence, pad_packed_sequence, pack_padded_sequence

raw = [ torch.ones(25, 300) / 2, 
        torch.ones(22, 300) / 2.3, 
        torch.ones(15, 300) / 3.2 ]
padded = pad_sequence(raw)  # size: [25, 3, 300]

lengths = torch.as_tensor([25, 22, 15], dtype=torch.int64)
packed = pack_padded_sequence(padded, lengths)
到目前为止,我们随机创建了一个长度不同的三张量(在RNN的上下文中为timestep),我们首先将它们填充到相同的长度,然后对其进行压缩。现在如果我们跑

print(padded.size())
print(packed.data.size()) # packed.data refers to the "packed" tensor
我们将看到:

torch.Size([25, 3, 300])
torch.Size([62, 300])
显然,62不是来自25*3。因此,
pack\u padded\u sequence
所做的只是根据我们传递给
pack\u padded\u sequence
长度
张量来保持每个批次条目的有意义的时间步(即,如果我们传递[25,25,25]给它,
packed.data
的大小仍然是[75300],即使原始张量不变)。简言之,rnn甚至看不到带有pack\u padded\u序列的pad timestep

现在让我们看看将
padded
packed
传递给rnn后的区别

rnn = torch.nn.RNN(input_size=300, hidden_size=2)
padded_outp, padded_hn = rnn(padded) # size: [25, 3, 2] / [1, 3, 2]
packed_outp, packed_hn = rnn(packed) # 'PackedSequence' Obj / [1, 3, 2]
undo_packed_outp, _ = pad_packed_sequence(packed_outp)

# return "h_n"
print(padded_hn) # tensor([[[-0.2329, -0.6179], [-0.1158, -0.5430],[ 0.0998, -0.3768]]]) 
print(packed_hn) # tensor([[[-0.2329, -0.6179], [ 0.5622,  0.1288], [ 0.5683,  0.1327]]]

# the output of last timestep (the 25-th timestep)
print(padded_outp[-1]) # tensor([[[-0.2329, -0.6179], [-0.1158, -0.5430],[ 0.0998, -0.3768]]]) 
print(undo_packed_outp.data[-1]) # tensor([[-0.2329, -0.6179], [ 0.0000,  0.0000], [ 0.0000,  0.0000]]
padded_hn
packed_hn
的值不同,因为rnn确实为
padded
计算pad,但不为“PackedSequence对象”(PackedSequence对象)计算pad,从最后一个隐藏状态也可以观察到:
padded
中的所有三个批处理条目都得到了非零的最后一个隐藏状态,即使其长度小于25。但对于压缩的,不会计算较短数据的最后隐藏状态(即0)

p、 另一个观察:

print([(undo_packed_outp[:, i, :].sum(-1) != 0).sum() for i in range(3)])
将给我们
[张量(25)、张量(22)、张量(15)]
,它们与我们输入的实际长度对齐