代码之家  ›  专栏  ›  技术社区  ›  kylerthecreator

在TensorFlow dynamic\u rnn中使用sequence\u length参数时如何处理填充

  •  3
  • kylerthecreator  · 技术社区  · 6 年前

    我正在尝试使用 dynamic_rnn 在Tensorflow中起到加速训练的作用。在阅读了一些内容后,我的理解是,加快培训的一种方法是显式地将值传递给 sequence_length 此函数中的参数。再多读一点,发现 this 所以解释一下,我需要传递的似乎是一个向量(可能由 tf.placeholder )包含批次中每个序列的长度。

    这就是我困惑的地方:为了利用这一点,我是否应该将每个批次填充到批次中最长的序列,而不是训练集中最长的序列?Tensorflow如何处理任何较短序列中剩余的零/填充标记?此外,这里的主要优势是真正的速度,还是只是额外的保证,我们在训练期间屏蔽了pad标记?如有任何帮助/背景,将不胜感激。

    1 回复  |  直到 6 年前
        1
  •  7
  •   Maxim    6 年前

    我是否应该将每个批次填充到批次中的最长长度序列,而不是训练集中的最长长度序列?

    序列 批次内 必须对齐,即必须具有相同的长度。所以对你的问题的一般回答是“是”。但是 不同批次 不必具有相同的长度,因此可以将输入序列分为大小大致相同的组,并相应地填充它们。这种技术被称为 扣合 你可以在 this tutorial .

    Tensorflow如何处理任何较短序列中剩余的零/填充标记?

    非常直观。 tf.nn.dynamic_rnn 返回两个张量: output states . 假设实际序列长度为 t 填充序列长度为 T .

    然后 输出 之后将包含零 i > t 各州 将包含 t型 -第个单元格状态,忽略后续单元格的状态。

    下面是一个示例:

    import numpy as np
    import tensorflow as tf
    
    n_steps = 2
    n_inputs = 3
    n_neurons = 5
    
    X = tf.placeholder(dtype=tf.float32, shape=[None, n_steps, n_inputs])
    seq_length = tf.placeholder(tf.int32, [None])
    
    basic_cell = tf.nn.rnn_cell.BasicRNNCell(num_units=n_neurons)
    outputs, states = tf.nn.dynamic_rnn(basic_cell, X, 
                                        sequence_length=seq_length, dtype=tf.float32)
    
    X_batch = np.array([
      # t = 0      t = 1
      [[0, 1, 2], [9, 8, 7]], # instance 0
      [[3, 4, 5], [0, 0, 0]], # instance 1
      [[6, 7, 8], [6, 5, 4]], # instance 2
    ])
    seq_length_batch = np.array([2, 1, 2])
    
    with tf.Session() as sess:
      sess.run(tf.global_variables_initializer())
      outputs_val, states_val = sess.run([outputs, states], feed_dict={
        X: X_batch, 
        seq_length: seq_length_batch
      })
      print(outputs_val)
      print()
      print(states_val)
    

    请注意,实例1已填充,因此 outputs_val[1,1] 是零向量,并且 states_val[1] == outputs_val[1,0] :

    [[[ 0.76686853  0.8707901  -0.79509073  0.7430128   0.63775384]
      [ 1.          0.7427926  -0.9452815  -0.93113345 -0.94975543]]
    
     [[ 0.9998851   0.98436266 -0.9620067   0.61259484  0.43135557]
      [ 0.          0.          0.          0.          0.        ]]
    
     [[ 0.99999994  0.9982034  -0.9934515   0.43735617  0.1671598 ]
      [ 0.99999785 -0.5612586  -0.57177305 -0.9255771  -0.83750355]]]
    
    [[ 1.          0.7427926  -0.9452815  -0.93113345 -0.94975543]
     [ 0.9998851   0.98436266 -0.9620067   0.61259484  0.43135557]
     [ 0.99999785 -0.5612586  -0.57177305 -0.9255771  -0.83750355]]
    

    此外,这里的主要优势是真正的速度,还是只是额外的保证,我们在训练期间屏蔽了pad标记?

    当然,批处理比逐个输入序列更有效。但指定长度的主要优点是,您可以从RNN中获得合理的状态,即填充项不会影响结果张量。如果不设置长度,但手动选择正确的状态,则会得到完全相同的结果(和相同的速度)。