Tensorflow dynamic_rnn 废弃警告

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

警告:此函数已弃用,在将来的版本中将会被移除。更新说明:请使用 keras.layers.RNN(cell),它等同于这个 API。

我查看了 keras.layers.RNN(cell),并且发现它可以使用 masking ,我假设可以作为 dynamic_rnnsequence_length 参数的替代品。

该层支持对具有可变时间步数的输入数据进行屏蔽。要向数据引入 mask,请使用一个 mask_zero 参数设置为 True 的嵌入层。

但是即使在 Embedding 文档中也没有更多关于如何使用 mask_zero=True 调整变量序列长度的信息。另外,如果我只是使用嵌入层添加掩码,那么我如何防止嵌入层改变我的输入和进行训练?
与此问题类似:RNN in Tensorflow vs Keras, depreciation of tf.nn.dynamic_rnn(),不过我想知道如何使用掩码替换 sequence_length
1个回答

3
我也需要这个答案,通过你问题底部的链接找到了所需信息。
简而言之,按照链接中的回答操作,但是如果你不想使用嵌入层,则“简单地”省略它。强烈建议阅读和理解链接的答案,因为它详细介绍了此过程,并且在遮蔽文档中有更多信息,但是这里是一个修改后的版本,它在序列输入上使用了遮蔽层来替换“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个长度并使用100个和填充/掩码的5个长度进行两次训练。您可能会获得更快的训练速度,但代价是精度较低,因为您无法在不同序列长度的批次之间进行洗牌。

你有关于你上一个方法的例子吗?我无法理解为什么没有填充会起作用。model.fit()有一个固定的批量大小,对吧?如果不同长度的序列形成不同的批量大小怎么办? - ARAT
@ARAT 批量大小是网络每次更新时看到的示例数量 -(您也可以使用train_on_batch)。最后一个维度 - 每个批次中每个项目的特征序列长度 - 对于RNN非常重要。每次调用fit()都需要具有相同序列长度的批次。因此,您将把数据分成data_seq_len_1data_seq_len_2,例如,并调用fit(data_seq_len_1)fit(data_seq_len_2)(或者无论您如何向模型提供数据)。但是,正如您所看到的,数据不能在序列长度之间进行洗牌... - parrowdice

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接