【问题标题】:How can I make TensorFlow RNN training more robust?如何让 TensorFlow RNN 训练更加健壮?
【发布时间】:2018-01-28 08:52:29
【问题描述】:

我正在训练一个时间序列的 RNN。我将RNNCell 子类化并在dynamic_rnn 中使用它。 RNNCell的拓扑如下:

  1. 输入(形状[15, 100, 3]
  2. 1x3 卷积(5 个内核),ReLu(形状 [15, 98, 5]
  3. 1x(剩余)卷积(20 个内核),ReLu(形状[15, 1, 20]
  4. 连接上一个输出(形状[15, 1, 21]
  5. 压缩和 1x1 卷积(1 个内核)、ReLu(形状 [15, 1]
  6. 挤压和softmax(形状[15]

dynamic_rnn 的批量大小约为 100(与上面描述的 100 不同,这是数据窗口中的时间段数)。 Epoch 由大约 200 个批次组成。 我想尝试超参数和正则化,但我经常尝试完全停止学习,我不明白为什么。这些是发生的一些奇怪的事情:

  • Adagrad 有效,但如果我使用 Adam 或 Nadam,则梯度全为零。

  • 我不得不设置一个巨大的学习率 (~1.0) 来查看从一个时期到另一个时期的学习情况。

  • 如果我尝试在任何卷积之后添加 dropout,即使我将 keep_prob 设置为 1.0,它也会停止学习。

  • 如果我调整卷积中的内核数量,对于一些看起来同样好的选择(例如 5、25、1 与 5、20、1),网络会再次完全停止学习。

为什么这个模型如此脆弱?是RNNCell的拓扑吗?

编辑: 这是RNNCell的代码:

class RNNCell(tf.nn.rnn_cell.RNNCell):
    def __init__(self):
        super(RNNCell, self).__init__()
        self._output_size = 15
        self._state_size = 15

    def __call__(self, X, prev_state):

        network = X
        # ------ 2 convolutional layers ------
        network = tflearn.layers.conv_2d(network, 5, [1, 3], activation='relu', weights_init=tflearn.initializations.variance_scaling(), padding="valid", regularizer=None)
        width = network.get_shape()[2]
        network = tflearn.layers.conv_2d(network, 20, [1, width], [1, 1], activation='relu', weights_init=tflearn.initializations.variance_scaling(), padding="valid", regularizer=None)

        # ------ concatenate the previous state ------
        _, height, width, features = network.get_shape()
        network = tf.reshape(network, [-1, int(height), 1, int(width * features)])
        network = tf.concat([network, prev_state[..., None, None]], axis=3)

        # ------ last convolution and softmax ------
        network = tflearn.layers.conv_2d(network, 1, [1, 1], activation='relu', weights_init=tflearn.initializations.variance_scaling(), padding="valid", regularizer=None)
        network = network[:, :, 0, 0]
        predictions = tflearn.layers.core.activation(network, activation="softmax")

        return predictions, predictions

    @property
    def output_size(self):
        return self._output_size
    @property
    def state_size(self):
        return self._state_size

【问题讨论】:

  • 序列长度为100?
  • 正确,窗口有 100 个时间段。我也在试验这些,但它们似乎并没有破坏一切。
  • 如果您提供完整的代码和一些数据以使其可重现,那就太好了
  • 我很乐意,但是完整的代码太长(它包括直接在 TF 中预处理数据和另一个完整的对象来管道数据)。我可以给你看RNNCell,够紧凑了。

标签: python tensorflow machine-learning recurrent-neural-network


【解决方案1】:

您很可能正面临渐变消失的问题。

不稳定性可能是由于将 ReLU 与少量要调整的参数结合使用而引起的。据我从描述中了解到,例如,第一层中只有1x3x5 = 15 可训练参数。如果假设初始化大约为零,那么平均 50% 的参数的梯度将始终保持为零。一般而言,ReLU 在小型网络上的表现不佳,尤其是在 RNN 的情况下。

  1. 尝试使用 Leaky ReLU(但您可能会面临梯度爆炸)
  2. 尝试使用 tanh,但检查参数的初始值,确保它们确实在零附近,否则梯度也会很快消失。
  3. 在第 0 步检索未经训练但刚刚初始化的网络的结果。通过正确的初始化和 NN 构造,您应该得到大约 0.5 的正态分布值.所有严格的值 0.5 也是不好的。
  4. 考虑更稳健的方法,例如 LSTM

【讨论】:

  • 我似乎有以零为中心的高斯,而不是 0.5。你认为这是问题所在吗?见tflearn.org/initializations/#variance-scaling:分布是一个以零为中心的截断正态truncated_normal(shape, 0.0, stddev=sqrt(factor / n))
  • 这是否解释了为什么 Adam 不起作用而 Adagrad 起作用?
  • 你的输出应该在0.5左右,因为在softmax之前的初始化值应该在0左右。很难判断你的初始化是否正确。最简单的测试:在没有训练的情况下运行模型并检查输出?严格 1/0 - 使用太大的值初始化,0.5 - 使用太小的值初始化。它可以解释为什么某些优化器不起作用。有些对梯度消失问题可能更稳健,但这取决于实现。它还解释了为什么你需要大步走,你的梯度很小,没有大步你就不能收敛。
  • 所以事实证明 tflearn variance_scaling() 正在用负值初始化大部分权重。我将在 github 上打开一个问题,因为它在我看来像是一个错误。