【python学习笔记】pytorch中的pack_padded_sequence()与pad_packed_sequence()使用

本篇博客参考:
pytorch之数据:pack_padded_sequence()与pad_packed_sequence()
Pytorch学习笔记05---- pack_padded_sequence和pad_packed_sequence理解

首先,packed是包装好的的意思;padded是填充的意思;pack有包装、压紧的意思;pad有填充的意思。

pack_padded_sequence即压紧封装填充好的句子

pad_packed_sequence即填充被压紧封装好的句子

示意图:

pack_padded_sequence
 pack_padded_sequence

pad_packed_sequence就是上边的那个过程反过来

pack_padded_sequence

#官方函数
torch.nn.utils.rnn.pack_padded_sequence(input, lengths, batch_first=False)
#↓'返回'
return PackedSequence  #一个PackedSequence对象

功能:将一个填充过的变长序列压紧。返回PackedSequence对象。

参数

  • input:要压缩的数据。当batch_first是False时候,shape的输入格式是[B,S * ],其中B是batch_size,S是seq_len(该batch中最长序列的长度)* 可以是任何维度。如果batch_first是True时候,相应的的数据格式必须是[S,B,* ]。input必须按序列长度的长短排序,长的在前面,短的在后面,第一个时间步的数据必须是最长的数据。
  • lengths:输入数据的每个序列的长度。
  • batch_first:当为True,数据格式必须[B, S, * ],反之,默认是False。

pad_packed_sequence

torch.nn.utils.rnn.pad_packed_sequence(sequence, batch_first=False) → tuple
#↓'返回'
return (sequence_pad , list) # 这个元组包含被填充后的序列 , 和batch中序列的长度列表。

功能:上面提到的函数的功能是将一个填充后的变长序列压紧。这个操作和pack_padded_sequence()是相反的。把压紧的序列再填充回来,默认按返回中list最大的数字填充。

参数

  • sequence:将要被填充的batch,是一个PackedSequence对象。
  • batch_first:作用同上pack_padded_sequence的batch_size,但是影响的是输出的数据格式。

例子

import torch

batch_size = 3   # 这个batch有3个序列
max_len = 6       # 最长序列的长度是6
embedding_size = 8 # 嵌入向量大小8
hidden_size = 16   # 隐藏向量大小16
vocab_size = 20    # 词汇表大小20

input_seq = [[3, 5, 12, 7, 2, ], [4, 11, 14, ], [18, 7, 3, 8, 5, 4]]
lengths = [5, 3, 6]   # batch中每个seq的有效长度。
# embedding
embedding = torch.nn.Embedding(vocab_size, embedding_size, padding_idx=0)
# LSTM的RNN循环神经网络
lstm = torch.nn.LSTM(embedding_size, hidden_size)

因为pack_padded_sequence中要求input必须按序列长度的长短排序,长的在前面,短的在后面,第一个时间步的数据必须是最长的数据。

所以先对数据进行排序。

zip放在补充

#由大到小排序
input_seq = sorted(input_seq, key = lambda tp: len(tp), reverse=True)
lengths = sorted(lengths, key = lambda tp: tp, reverse=True)

print(input_seq)
print(lengths)

PAD_token = 0 # 填充下标是0
def pad_seq(seq, seq_len, max_length):
    seq = seq
    seq += [PAD_token for _ in range(max_length - seq_len)]
    return seq

pad_seqs = []  # 填充后的数据
for i,j in zip(input_seq, lengths):
    pad_seqs.append(pad_seq(i, j, max_len))

print(pad_seqs)
[[18, 7, 3, 8, 5, 4], [3, 5, 12, 7, 2], [4, 11, 14]]
[6, 5, 3]
[[18, 7, 3, 8, 5, 4], [3, 5, 12, 7, 2, 0], [4, 11, 14, 0, 0, 0]]

pad过后的句子是如下格式

[[18, 7, 3, 8, 5, 4], 
 [3, 5, 12, 7, 2, 0], 
 [4, 11, 14, 0, 0, 0]]

即[batch_size,seq_len,* ],所以pack_padded_sequence中的batch_first=True

LSTM的输出维度:

其中如果LSTM是双向则num_directions=2,否则num_directions=1

参数 维度1 维度2 维度3
output seq_len batch num_directions×hidden_size
pad_seqs = torch.tensor(pad_seqs)
embeded = embedding(pad_seqs)

# 压缩,设置batch_first为true
pack = torch.nn.utils.rnn.pack_padded_sequence(embeded, lengths, batch_first=True)
#这里如果不写batch_first,你的数据必须是[s,b,e],不然会报错lenghth错误

# 利用lstm循环神经网络测试结果
state = None
pade_outputs, _ = lstm(pack, state)
# 设置batch_first为true;你可以不设置为true,为false时候只影响结构不影响结果
pade_outputs, others = torch.nn.utils.rnn.pad_packed_sequence(pade_outputs, batch_first=True)

# 查看输出的元祖
print(pade_outputs.shape)
print(others)
torch.Size([3, 6, 16])
tensor([6, 5, 3])

补充

python中zip()函数的用法

import numpy as np

a=[1,2,3,4,5]
b=(1,2,3,4,5)
c=np.arange(5)
d="zhang"

zz=zip(a,b,c,d)

print(list(zz))
[(1, 1, 0, 'z'), (2, 2, 1, 'h'), (3, 3, 2, 'a'), (4, 4, 3, 'n'), (5, 5, 4, 'g')]
posted @ 2021-04-04 21:28  ryukirin  阅读(1970)  评论(0编辑  收藏  举报