在 Keras 和 LSTM/GRU 单元格中使用 Dropout

Using Dropout with Keras and LSTM/GRU cell

在 Keras 中,您可以像这样指定一个 dropout 层:

model.add(Dropout(0.5))

但是对于 GRU 单元,您可以将 dropout 指定为构造函数中的参数:

model.add(GRU(units=512,
        return_sequences=True,
        dropout=0.5,
        input_shape=(None, features_size,)))

有什么区别?一个比另一个更可取吗?

Keras' documentation 中,它将其添加为单独的丢弃层(参见 "Sequence classification with LSTM")

循环层一遍又一遍地执行相同的重复操作。

在每个时间步中,它需要两个输入:

  • 您的输入(序列的一个步骤)
  • 内部输入(例如,可以是状态和上一步的输出)

请注意,输入和输出的维度可能不匹配,这意味着 "your input" 个维度将不匹配 "the recurrent input (previous step/states)" 个维度。

然后在每个循环时间步中有两个具有两个不同内核的操作:

  • 将一个内核应用于"your inputs"以在兼容维度中对其进行处理和转换
  • 另一个(keras 称为递归内核)应用于上一步的输入。

正因为如此,keras在循环层中也使用了两个dropout操作。 (将应用于每一步的 Dropout)

  • 首次转换输入时出现丢失
  • 循环内核应用的dropout

所以,实际上RNN层中有两个dropout参数:

  • dropout,应用于输入的第一个操作
  • recurrent_dropout,应用于循环输入的其他操作(先前的输出 and/or 状态)

您可以在 GRUCellLSTMCell 中看到此描述编码,例如在 source code.


什么是正确的?

这是对创造力的开放。

你可以使用Dropout(...)层,它不是"wrong",但它也可能会掉落"timesteps"! (除非您正确设置 noise_shape 或使用 SpatialDropout1D,目前尚未记录)

也许你想要,也许你不想要。如果您在循环层中使用参数,您将只对其他维度应用 dropout,而不会丢弃任何一步。这对于循环层来说似乎是健康的,除非你想让你的网络学习如何处理包含间隙的序列(最后一句话是一个假设)。

此外,使用 dropout 参数,当操作被丢弃时,您将真正丢弃内核的一部分 "in every step",而使用单独的层将使您的 RNN 在内部执行非丢弃操作,因为您dropout 只会影响最终的输出。