pytorch dropout_Pytorch 是如何处理变长序列的

8c39da903d676d8961ac175b76cc2b0a.png

前言

最近在由 TensorFlow 迁移至 Pytorch, 不得不说,真的香啊。 在写模型的时候发现 Pytorch 中处理变长序列与 TensorFlow 有很大的不同, 因此此处谈谈我自己的理解。

此外, 我对 LSTM, GRU 进行了二次加工, 将对变长序列的处理封装到内部细节中,感兴趣的可以看看:NLP-Pytorch

从 LSTM 谈起[1]

首先, 注意到这里LSTM的计算公式与我们常见的LSTM有所区别,虽然区别不大,但还是要提一下,因为后面的参数初始化会有所不同:

class torch.nn.LSTM(*args, **kwargs)

-- 参数列表:
   -- input_size: x 的特征维度
   -- hidden_size: 隐层的特征维度
   -- num_layers: LSTM 层数,默认为1
   -- bias: 是否采用 bias, 如果为False,则不采用。默认为True
   -- batch_first: True, 则输入输出的数据格式为 [batch_size, seq_len, feature_dim],默认为False
   -- dropout: dropout会在除最后一层外都进行dropout, 默认为0
   -- bidirectional: 是否采用双向,默认为False

 -- 输入数据:
   -- input: [seq_len, batch_size, input_size], 输入的特征矩阵
   -- h_0: [num_layers * num_directions, batch_size, hidden_size], 初始时 h 状态, 默认为0
   -- c_0: [num_layers * num_directions, batch_size, hidden_size], 初始时 cell 状态, 默认为0

 -- 输出数据:
   -- output: [seq_len, batch_size, num_directions * hidden_size], 最后一层的所有隐层输出
   -- h_n : [num_layers * num_directions, batch, hidden_size], 所有层的最后一个时刻隐层状态
   -- c_n : [num_layers * num_directions, batch, hidden_size], 所有层的最后一格时刻的 cell 状态

-- W,b参数:
  -- weight_ih_l[k]: 与输入x相关的第k层权重 W 参数, W_ii, W_if, W_ig, W_io
  -- weight_hh_l[k]: 与上一时刻 h 相关的第k层权重参数, W_hi, W_hf, W_hg, W_ho
  -- bias_ih_l[k]: 与输入x相关的第k层 b 参数, b_ii, b_if, b_ig, b_io
  -- bias_hh_l[k]: 与上一时刻 h 相关的第k层 b 参数, b_hi, b_hf, b_hg, b_ho

需要注意的一点是, LSTM中所有的W,b 参数默认采用均匀分布 :

, 有一些初始化方法能够加速收敛过程, 因此,很多情况下我们需要自己初始化这些参数,我在 NLP-Pytorch: LSTM 对LSTM 进行了简要封装。

对比 GRU [1]

同样为了更鲜明的表明参数的初始化, 这里将 GRU 搬过来:

class torch.nn.GRU(*args, **kwargs)

-- 参数列表:与 LSTM 的一致, 不赘述了
-- 输入序列:input, h_0; 与 LSTM 差不多,只是省略了 cell 状态
-- 输出序列:output, h_n; 与 LSTM 差不多,只是省略了 cell 状态
-- W,b参数:
  -- weight_ih_l[k]: 与输入x相关的第k层权重 W 参数, W_ir, W_iz, W_in
  -- weight_hh_l[k]: 与上一时刻 h 相关的第k层权重参数, W_hr, W_hz, W_hn
  -- bias_ih_l[k]: 与输入x相关的第k层 b 参数, b_ir, b_iz, b_in
  -- bias_hh_l[k]: 与上一时刻 h 相关的第k层 b 参数, b_hr, b_hz, b_hn

与LSTM 一样, W,b参数的初始化默认采用均匀分布 :

如何处理变长序列?[2]

我们知道,在文本的处理过程中,句子的长度是不一的,对于这种数据,我们往往采用<PAD> 将每个句子扩充到一样的长度, 然后我们就可以使用LSTM或GRU来处理了。

但仔细一想, 又有些不对,我们将句子扩充,那么扩充的信息必然会对我们的结果产生影响,这与我们正常的思路完全不同,虽然我自己做比较实验表明,二者之间差距并不明显,但我个人认为这是数据集与<PAD>初始化的关系。

那么,Pytorch 中如何处理这种变长的情况,去掉<PAD> 呢,答案就是 torch.nn.utils.rnn.pack_padded_sequence()以及 torch.nn.utils.rnn.pad_packed_sequence()

压缩序列

压缩序列所使用的API为torch.nn.utils.rnn.pack_padded_sequence(), 其目的是将多余的 <PAD> 去除,获得一个干净的,最初的序列。

pack_padded_sequence(...)
-- 参数列表:
  -- input: 有 <PAD> 的 batch 序列
  -- lengths: input 中每个序列的长度
  -- batch_first: 如果为True, input 必须是 [batch_size, seq_len, input_size], 参见LSTM
  -- enforce_sorted: 如果为True, 那么 input 中的序列需要按照 长度递减排列

-- 返回值:
    一个 PackedSequence 对象

我们获得干净的序列之后,就可以将其放入 LSTM 中了, 具体可参见我的实现:NLP-Pytorch: LSTM

解压序列

我们通过 LSTM 对压缩后的序列处理后,还需要将压缩后的信息解压缩,本质上是将数据从PackedSequence 类型转化为Tensor ,此部分主要是做 Attention 的时候会用到。

pad_packed_sequence(...)

-- 参数列表:
  -- sequence: 一个PackedSequence 对象
  -- batch_first: 
  -- padding_value: padding 该序列的values
  -- total_length: Padding 到多长, 一般为None

-- Returns:
  -- output: 有 padding 信息的序列输出
  -- output_lengths: 每个序列没有Padding之前的长度

最后

最后,知乎上有一个很有趣的问题:你在训练RNN的时候有哪些特殊的trick, 十分值得一看,感兴趣的可以自己做一做相关的实验,ok, 就酱。

Reference

[1][Pytorch 官方文档]](https://pytorch.org/docs/stable/nn.html)

[2]pytorch中如何处理RNN输入变长序列padding

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值