Tensorflow dynamic_rnn 弃用

Tensorflow dynamic_rnn deprecation

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

Warning: THIS FUNCTION IS DEPRECATED. It will be removed in a future version. Instructions for updating: Please use keras.layers.RNN(cell), which is equivalent to this API

我查看了 keras.layers.RNN(cell),它说它可以使用掩码,我认为它可以替代 dynamic_rnnsequence_length 参数?

This layer supports masking for input data with a variable number of timesteps. To introduce masks to your data, use an Embedding layer with the mask_zero parameter set to True.

但即使在嵌入文档中也没有关于如何使用 mask_zero=True 来适应可变序列长度的更多信息。另外,如果我使用嵌入层只是为了添加掩码,我该如何防止嵌入改变我的输入和接受训练?

类似这个问题但是我想知道如何使用mask来代替sequence_length

我也需要这个问题的答案,并通过你问题底部的 link 弄清楚了我需要什么。

简而言之,您可以按照 link 中的答案进行操作,但是如果您对使用嵌入层不感兴趣,则 'simply' 可以省略嵌入层。我强烈建议阅读和理解 as it goes into more detail, and the docs on 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.]]

请注意如何应用掩码,计算不会在掩码处于活动状态(即序列被填充的位置)的时间步长上执行。取而代之的是,前一个时间步的状态被向前推进。

其他几点注意事项:

  • 在 linked(和这个)示例中,RNN 是使用各种激活和初始化参数创建的。我假设这是为了将 RNN 初始化为已知状态,以实现示例的可重复性。实际上,您可以按照自己的意愿初始化 RNN。
  • 填充值可以是您指定的任何值。通常,使用使用零的填充。在 linked(和这个)示例中,使用了值 0.37。我只能假设它是一个任意值来显示原始和掩码 RNN 输出的差异,因为此示例 RNN 初始化的零输入值给出 little/no 输出差异,因此 'some' 值(即0.37) 演示了掩蔽的效果。
  • Masking 文档指出,仅当 所有 时间步的值包含掩码值时,rows/time 步才会被掩码。例如,在上面,[0.37, 2] 的时间步长仍将使用这些值馈送到网络,但是,[0.37, 0.37] 的时间步长将被跳过。
  • 解决此问题的替代方法是通过将不同的序列长度批处理在一起来训练多次。例如,如果您混合使用 10、20 和 30 的序列长度,而不是将它们全部填充到 30 和掩码,而是使用所有 10 个序列长度进行训练,然后是 20 秒,然后是 30 秒。或者,如果您说有很多 100 个序列长度,还有很多 3、4、5 个序列长度,您可能希望将较小的序列长度填充到所有 5 个长度,并使用 100s 和 padded/masked 5s 训练两次。您可能会提高训练速度,但准确度会降低 trade-off,因为您将无法在不同序列长度的批次之间洗牌。