©PaperWeekly 原创 · 作者|海晨威
学校|同济大学硕士生
研究方向|自然语言处理
在 NLP 中,文本数据大都是变长的,为了能够做 batch 的训练,需要 padding 到相同的长度,并在实际训练中忽略 padding 部分的影响。
在不同的深度学习框架中,对变长序列的处理,本质思想都是一致的,但具体的实现方式有较大差异,下面针对 Pytorch、Keras 和 TensorFlow 三大框架,以 LSTM 模型为例,说明各框架对 NLP 中变长序列的处理方式和注意事项。
PyTorch
在 pytorch 中,是用的 torch.nn.utils.rnn 中的 pack_padded_sequence 和 pad_packed_sequence 来处理变长序列,前者可以理解为对 padded 后的 sequence 做 pack(打包/压紧),也就是去掉 padding 位,但会记录每个样本的有效长度信息;后者是逆操作,对 packed 后的 sequence 做 pad,恢复到相同的长度。
def pack_padded_sequence(input, lengths, batch_first=False, enforce_sorted=True):
...
if enforce_sorted:
sorted_indices = None
else:
lengths, sorted_indices = torch.sort(lengths, descending=True)
sorted_indices = sorted_indices.to(input.device)
batch_dim = 0 if batch_first else 1
input = input.index_select(batch_dim, sorted_indices)
...
不过在使用过程中,要格外注意 pack_padded_sequence 的 enforce_sorted 参数和 pad_packed_sequence 的 total_length 参数。
1.1 pack_padded_sequence
下面是 pack_padded_sequence 函数的部分 Pytorch 源码,input 就是输入的一个 batch 的 tensor,lengths 是这个 batch 中每个样本的有效长度。
在 pack_padded_sequence 处理之后,会得到一个 PackedSequence 的数据,其除了记录 Tensor data 之外,还会记录 batch_sizes, sorted_indices 和 unsorted_indices,其中 batch_sizes 是将输入按照有效长度排序之后,每个时间步对应的 batch 大小,后面会有例子;sorted_indices 就是对输入 lengths 排序后的索引,unsorted_indices 是用来将排序数据恢复到原始顺序的索引。
在 pack_padded_sequence 中,enforce_sorted 默认设置为 True,也就是说输入的 batch 数据要事先按照长度排序,才能输入,实际上,更简单的方式是,将其设置为 False,从上面的代码中也可以看出,Pytorch 会自动给我们做排序。
注:torch1.1 及之后才有 enforce_sorted 参数,因此 torch1.1 之后才有自动排序功能。
一个简单的例子:
# input_tensor shape:batch_size=2,time_step=3,dim=1
input_tensor = torch.FloatTensor([[4, 0, 0], [5, 6, 0]]).resize_(2, 3, 1)
seq_lens = torch.IntTensor([1, 2])
x_packed = nn_utils.rnn.pack_padded_sequence(input_tensor, seq_lens, batch_first=True, enforce_sorted=False)