似乎 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_rnn 的 sequence_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 来适应可变序列长度的更多信息。另外,如果我使用嵌入层只是为了添加掩码,我该如何防止嵌入改变我的输入和接受训练?
类似这个问题RNN in Tensorflow vs Keras, depreciation of tf.nn.dynamic_rnn()但我想知道如何使用掩码替换 sequence_length
请您参考如下方法:
我也需要这个问题的答案,并通过您问题底部的链接弄清楚了我需要什么。
简而言之,您可以按照链接中的答案进行操作,但如果您对使用嵌入层不感兴趣,则可以“简单地”省去嵌入层。我强烈建议您阅读并理解 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 个序列长度进行训练,然后是 20 秒,然后是 30 秒。或者,如果您说有很多 100 个序列长度,还有很多 3、4、5 个序列长度,您可能希望将较小的序列长度填充到所有 5 个长度,并使用 100s 和填充/掩码 5s 训练两次。您可能会提高训练速度,但代价是准确性会降低,因为您将无法在不同序列长度的批处理之间进行混洗。
