Tensorflow dynamic_rnn弃用

时间:2019-03-20 15:39:31

标签: python tensorflow keras recurrent-neural-network embedding

tf.nn.dynamic_rnn似乎已被弃用:

  

警告:不建议使用此功能。它将在将来的版本中删除。更新说明:请使用keras.layers.RNN(cell),它等效于此API

我已经检查了keras.layers.RNN(cell),它说它可以使用掩膜,我认为它可以代替dynamic_rnn的{​​{1}}参数吗?

  

该层支持对具有可变时间步长的输入数据进行屏蔽。要将掩码引入数据,请使用embedding层,其mask_zero参数设置为True。

但是,即使在嵌入文档中也没有关于如何使用sequence_length来容纳可变序列长度的更多信息。另外,如果我只是使用嵌入层添加蒙版,那么如何防止嵌入更改输入内容并接受训练?

类似于此问题RNN in Tensorflow vs Keras, depreciation of tf.nn.dynamic_rnn(),但我想知道如何使用掩码替换mask_zero=True

1 个答案:

答案 0 :(得分:1)

我也需要一个答案,并通过问题底部的链接找出了我需要的东西。

简而言之,您可以按照链接中的答案进行操作,但是如果您不愿意使用嵌入层,则可以“简单地”省去嵌入层。我强烈建议您阅读和理解linked answer,并进一步阅读Masking上的文档,但这是经过修改的版本,它在序列输入上使用掩蔽层来替换“ sequence_length” :

import numpy as np
import tensorflow as tf

pad_value = 0.37
# This is our input to the RNN, in [batch_size, max_sequence_length, num_features] shape
test_input = np.array(
[[[1.,   1.  ],
  [2,    2.  ],
  [1.,   1.  ],
  [pad_value, pad_value], # <- a row/time step which contains all pad_values will be masked through the masking layer
  [pad_value, pad_value]],

 [[pad_value, pad_value],
  [1.,   1.  ],
  [2,    2.  ],
  [1.,   1.  ],
  [pad_value, pad_value]]])

# Define the mask layer, telling it to mask all time steps that contain all pad_value values
mask = tf.keras.layers.Masking(mask_value=pad_value)
rnn = tf.keras.layers.GRU(
    1,
    return_sequences=True,
    activation=None, # <- these values and below are just used to initialise the RNN in a repeatable way for this example
    recurrent_activation=None,
    kernel_initializer='ones',
    recurrent_initializer='zeros',
    use_bias=True,
    bias_initializer='ones'
)

x = tf.keras.layers.Input(shape=test_input.shape[1:])
m0 = tf.keras.Model(inputs=x, outputs=rnn(x))
m1 = tf.keras.Model(inputs=x, outputs=mask(x))
m2 = tf.keras.Model(inputs=x, outputs=rnn(mask(x)))

print('raw inputs\n', test_input)
print('raw rnn output (no mask)\n', m0.predict(test_input).squeeze())
print('masked inputs\n', m1.predict(test_input).squeeze())
print('masked rnn output\n', m2.predict(test_input).squeeze())

退出:

raw inputs
 [[[1.   1.  ]
  [2.   2.  ]
  [1.   1.  ]
  [0.37 0.37]
  [0.37 0.37]]

 [[0.37 0.37]
  [1.   1.  ]
  [2.   2.  ]
  [1.   1.  ]
  [0.37 0.37]]]
raw rnn output (no mask)
 [[  -6.        -50.       -156.       -272.7276   -475.83362 ]
 [  -1.2876     -9.862801  -69.314    -213.94202  -373.54672 ]]
masked inputs
 [[[1. 1.]
  [2. 2.]
  [1. 1.]
  [0. 0.]
  [0. 0.]]

 [[0. 0.]
  [1. 1.]
  [2. 2.]
  [1. 1.]
  [0. 0.]]]
masked rnn output
 [[  -6.  -50. -156. -156. -156.]
 [   0.   -6.  -50. -156. -156.]]

请注意,在应用遮罩的情况下,如何在激活遮罩的时间步长(即填充序列的时间步)上不执行计算。取而代之的是,将前一个时间步骤的状态继续进行。

需要注意的其他几点:

  • 在链接的(和本例)示例中,使用各种激活和初始化参数创建RNN。我假设这是为了示例的可重复性,将RNN初始化为已知状态。实际上,您可以按照自己的意愿初始化RNN。
  • 填充值可以是您指定的任何值。通常,使用零填充。在链接的(和此)示例中,使用的值为0.37。我只能假定它是一个任意值,以显示原始和掩蔽的RNN输出中的差异,因为在此示例中,输入值为零,RNN初始化在输出中几乎没有差异,因此“某个”值(即0.37)说明了遮罩的效果。
  • Masking文档指出,只有当该时间步长的所有 值包含掩码值时,行/时间步长才被屏蔽。例如,在上面,[0.37, 2]的时间步长仍将与这些值一起馈送到网络,但是,[0.37, 0.37]的时间步长将被跳过。
  • 替代掩盖此问题的一种替代方法是通过将不同的序列长度分批在一起进行几次训练。例如,如果您混合使用10、20和30的序列长度,而不是将它们全部填充为30并进行掩蔽,则使用所有10个序列长度进行训练,然后依次使用20s和30s。或者,如果您说100个序列长度很多,还有3、4、5个序列长度很多,您可能希望将较小的序列长度填充到全部5个长度,并使用100s和填充/蒙版5s训练两次。您可能会获得训练速度,但是要以较低的精度为代价,因为您将无法在序列长度不同的批次之间进行混洗。