deep-learning - 为什么我们在 PyTorch 中“打包”序列?

deep-learning - 为什么我们在 PyTorch 中“打包”序列?

上面的答案很好地解决了这个问题。我只是想添加一个示例以更好地理解pack_padded_sequence.

举个例子

注意:pack_padded_sequence需要批处理中的排序序列(按序列长度的降序排列)。在下面的示例中,已经对序列批次进行了排序,以减少混乱。访问此要点链接以获取完整实施。

首先,我们创建一批 2 个不同序列长度的序列,如下所示。我们批次中总共有 7 个元素。

每个序列的嵌入大小为 2。

第一个序列的长度:5

第二个序列的长度:2

import torch

seq_batch = [torch.tensor([[1, 1],

[2, 2],

[3, 3],

[4, 4],

[5, 5]]),

torch.tensor([[10, 10],

[20, 20]])]

seq_lens = [5, 2]

我们填充seq_batch以获取等长为 5 的序列批次(批次中的最大长度)。现在,新批次总共有10个元素。

# pad the seq_batch

padded_seq_batch = torch.nn.utils.rnn.pad_sequence(seq_batch, batch_first=True)

"""

>>>padded_seq_batch

tensor([[[ 1, 1],

[ 2, 2],

[ 3, 3],

[ 4, 4],

[ 5, 5]],

[[10, 10],

[20, 20],

[ 0, 0],

[ 0, 0],

[ 0, 0]]])

"""

然后,我们打包padded_seq_batch. 它返回两个张量的元组:

第一个是包含序列批次中所有元素的数据。

第二个是batch_sizes通过步骤告诉元素如何相互关联的。

# pack the padded_seq_batch

packed_seq_batch = torch.nn.utils.rnn.pack_padded_sequence(padded_seq_batch, lengths=seq_lens, batch_first=True)

"""

>>> packed_seq_batch

PackedSequence(

data=tensor([[ 1, 1],

[10, 10],

[ 2, 2],

[20, 20],

[ 3, 3],

[ 4, 4],

[ 5, 5]]),

batch_sizes=tensor([2, 2, 1, 1, 1]))

"""

现在,我们将元组传递packed_seq_batch给 Pytorch 中的循环模块,例如 RNN、LSTM。这只需要5 + 2=7在循环模块中进行计算。

lstm = nn.LSTM(input_size=2, hidden_size=3, batch_first=True)

output, (hn, cn) = lstm(packed_seq_batch.float()) # pass float tensor instead long tensor.

"""

>>> output # PackedSequence

PackedSequence(data=tensor(

[[-3.6256e-02, 1.5403e-01, 1.6556e-02],

[-6.3486e-05, 4.0227e-03, 1.2513e-01],

[-5.3134e-02, 1.6058e-01, 2.0192e-01],

[-4.3123e-05, 2.3017e-05, 1.4112e-01],

[-5.9372e-02, 1.0934e-01, 4.1991e-01],

[-6.0768e-02, 7.0689e-02, 5.9374e-01],

[-6.0125e-02, 4.6476e-02, 7.1243e-01]], grad_fn=), batch_sizes=tensor([2, 2, 1, 1, 1]))

>>>hn

tensor([[[-6.0125e-02, 4.6476e-02, 7.1243e-01],

[-4.3123e-05, 2.3017e-05, 1.4112e-01]]], grad_fn=),

>>>cn

tensor([[[-1.8826e-01, 5.8109e-02, 1.2209e+00],

[-2.2475e-04, 2.3041e-05, 1.4254e-01]]], grad_fn=)))

"""

我们需要转换output回填充的输出批次:

padded_output, output_lens = torch.nn.utils.rnn.pad_packed_sequence(output, batch_first=True, total_length=5)

"""

>>> padded_output

tensor([[[-3.6256e-02, 1.5403e-01, 1.6556e-02],

[-5.3134e-02, 1.6058e-01, 2.0192e-01],

[-5.9372e-02, 1.0934e-01, 4.1991e-01],

[-6.0768e-02, 7.0689e-02, 5.9374e-01],

[-6.0125e-02, 4.6476e-02, 7.1243e-01]],

[[-6.3486e-05, 4.0227e-03, 1.2513e-01],

[-4.3123e-05, 2.3017e-05, 1.4112e-01],

[ 0.0000e+00, 0.0000e+00, 0.0000e+00],

[ 0.0000e+00, 0.0000e+00, 0.0000e+00],

[ 0.0000e+00, 0.0000e+00, 0.0000e+00]]],

grad_fn=)

>>> output_lens

tensor([5, 2])

"""

将此努力与标准方式进行比较

在标准方式中,我们只需要传递padded_seq_batchtolstm模块。但是,它需要 10 次计算。它涉及更多关于填充元素的计算,这在计算上是低效的。

请注意,它不会导致不准确的表示,但需要更多的逻辑来提取正确的表示。

对于只有前向的 LSTM(或任何循环模块),如果我们想提取最后一步的隐藏向量作为序列的表示,我们必须从 T(th) 步中提取隐藏向量,其中 T是输入的长度。拿起最后一个表示将是不正确的。请注意,对于批次中的不同输入,T 会有所不同。

对于双向 LSTM(或任何循环模块),它更加麻烦,因为必须维护两个 RNN 模块,一个在输入开头使用填充,一个在输入结尾使用填充,并且最后提取和连接隐藏向量,如上所述。

让我们看看区别:

# The standard approach: using padding batch for recurrent modules

output, (hn, cn) = lstm(padded_seq_batch.float())

"""

>>> output

tensor([[[-3.6256e-02, 1.5403e-01, 1.6556e-02],

[-5.3134e-02, 1.6058e-01, 2.0192e-01],

[-5.9372e-02, 1.0934e-01, 4.1991e-01],

[-6.0768e-02, 7.0689e-02, 5.9374e-01],

[-6.0125e-02, 4.6476e-02, 7.1243e-01]],

[[-6.3486e-05, 4.0227e-03, 1.2513e-01],

[-4.3123e-05, 2.3017e-05, 1.4112e-01],

[-4.1217e-02, 1.0726e-01, -1.2697e-01],

[-7.7770e-02, 1.5477e-01, -2.2911e-01],

[-9.9957e-02, 1.7440e-01, -2.7972e-01]]],

grad_fn= < TransposeBackward0 >)

>>> hn

tensor([[[-0.0601, 0.0465, 0.7124],

[-0.1000, 0.1744, -0.2797]]], grad_fn= < StackBackward >),

>>> cn

tensor([[[-0.1883, 0.0581, 1.2209],

[-0.2531, 0.3600, -0.4141]]], grad_fn= < StackBackward >))

"""

上面的结果表明hn,cn有两种不同的方式,而output两种方式导致填充元素的值不同。

相关推荐

【c/c++】gcc/g++知识和常见问题解决方案
365bet新英体育

【c/c++】gcc/g++知识和常见问题解决方案

08-10 👁️ 7879
一、2017驾照要考多久
必发365app官网

一、2017驾照要考多久

07-21 👁️ 4086
dnf女圣职者转职哪个好? dnf手游女圣职者转职哪个职业厉害
多便宜才算便宜?福特蒙迪欧全国12.48万起,最高直降3.57万
法国新闻
bat365在线平台官网登录

法国新闻

07-05 👁️ 5279
王者多久开一次新区?(王者多久开一次新区比较好)
为什么移动数据开了却没网络
365bet新英体育

为什么移动数据开了却没网络

07-15 👁️ 2934
Lot0234 春秋战国 郙王太子剑
必发365app官网

Lot0234 春秋战国 郙王太子剑

07-26 👁️ 7504
髋关节检查未登录和髋关节匹配失败时,允许把交通
bat365在线平台官网登录

髋关节检查未登录和髋关节匹配失败时,允许把交通

08-23 👁️ 949