Pytorch模型(1)——Dynamic RNN

RNN基本公式

在普通神经网络中引入了隐藏状态
h t = t a n h ( w i h x t + b i h + w h h h t − 1 + b h h ) h_t=tanh(w_{ih}x_t+b_{ih}+w_{hh}h_{t-1}+b_{hh}) ht=tanh(wihxt+bih+whhht1+bhh)

什么是Dynamic RNN

静态RNN:由于静态RNN需要预先指定seq_len,所以所有数据都必须使用同一个seq_len,即每一个batch的seq_len是一致的
动态RNN:由于利用循环次数实现了seq_len的作用,所以不同的batch可以有不同的seq_len,但是同一个batch内的seq_len还是保持一致的
在这里插入图片描述
注:左图和右图等价,但是右图等于把左图展开了,右图即static rnn,左图为更紧凑的dynamic rnn


为什么要用batch呢?

  • 因为batch size可以加速训练
  • 而且可以根据一个batch内的样本来更新参数,防止梯度下降的随机性,易于收敛
  • 但是更大的batch会陷入局部最优值

为什么要用Dynamic RNN

dynamic RNN可以让不同迭代传入的batch可以是长度不同的数据,但同一次迭代一个batch内部的所有数据长度仍然是固定的。例如,第一时刻传入的数据shape=[batch_size, 10],第二时刻传入的数据shape=[batch_size, 12],第三时刻传入的数据shape=[batch_size, 8]等等;一般通过为batch内不同长度的sequence进行补零操作至相同长度后,与真实seq_len一同输入模型实现。

如何在pytorch中实现Dynamic RNN

  • 输入数据处理
    每次取数据时,要求先将不同长度的原始sequence补零至同一长度(max_seq_len),注意这里要返回seq_len
# 在dataset的定义中
def __getitem__(self, idx):
    # data: seq_len * input_size
    data, label, seq_len = self.train_data[idx]
    # pad_data: max_seq_len * input_size
    pad_data = np.zeros(shape=(self.max_seq_len, data.shape[1]))
    pad_data[0:data.shape[0]] = data
    # 这里可以在batch迭代时使用sample["data"]即可返回batch后的数据
    sample = {'data': pad_data, 'label': label, 'seq_len': seq_len}
    return sample
  • pack_padded_sequence & pad_packed_sequence

将补零后的数据重新打包整理,给出在RNN循环中每一步有几个数据同时进行运算

tensor([[[ 1.],
         [ 2.],
         [ 3.]],

        [[ 1.],
         [ 0.],
         [ 0.]]])

————>

PackedSequence(data=tensor([[ 1.],
        [ 1.],
        [ 2.],
        [ 3.]]), batch_sizes=tensor([ 2,  1,  1]))

PackedSequence对象可以直接输入RNN模型中,其中Pytorch在内部循环时如果发现是补的零,将不会添加进最终结果,对于h_n我们可以直接使用,对于output我们需要将其从PackedSequence对象还原成原始补零的Tensor

PackedSequence(data=tensor([[ -0.3207, -0.4567],
        [ 0.6665,  0.0530],
        [ 0.4456,  0.1340],
        [ 0.3373, -0.3268]]), batch_sizes=tensor([ 2,  1,  1]))

————>

tensor([[[ -0.3207, -0.4567],
         [ 0.6665,  0.0530]],

        [[ 0.4456,  0.1340],
         [ 0.0000,  0.0000]],

        [[ 0.3373, -0.3268],
         [ 0.0000,  0.0000]]]) tensor([ 3,  1])

官网api
官网Example演示pack和pad操作;注意这里enforce_sorted=False

>>> from torch.nn.utils.rnn import pack_padded_sequence, pad_packed_sequence
>>> seq = torch.tensor([[1,2,0], [3,0,0], [4,5,6]])
>>> lens = [2, 1, 3]
>>> packed = pack_padded_sequence(seq, lens, batch_first=True, enforce_sorted=False)
>>> packed
PackedSequence(data=tensor([4, 1, 3, 5, 2, 6]), batch_sizes=tensor([3, 2, 1]),
               sorted_indices=tensor([2, 0, 1]), unsorted_indices=tensor([1, 2, 0]))
>>> seq_unpacked, lens_unpacked = pad_packed_sequence(packed, batch_first=True)
>>> seq_unpacked
tensor([[1, 2, 0],
        [3, 0, 0],
        [4, 5, 6]])
>>> lens_unpacked
tensor([2, 1, 3])

参考来源:

动态RNN和静态RNN区别
如何理解RNN中的Batch_size?
tensor flow dynamic_rnn 与rnn有啥区别?
[莫烦 PyTorch 系列教程] 5.1 – 为什么 Torch 是动态的
训练神经网络时如何确定batch size?
Pytorch实现RNN

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值