Python 如何使TensorFlow RNN训练更健壮?

Python 如何使TensorFlow RNN训练更健壮?,python,tensorflow,machine-learning,recurrent-neural-network,Python,Tensorflow,Machine Learning,Recurrent Neural Network,我在时间序列上训练RNN。我将其子类化为RNNCell,并在dynamic\u rnn中使用它。RNNCell的拓扑结构如下: 输入(形状[15100,3]) 1x3卷积(5个内核),ReLu(形状[15,98,5]) 1x(剩余)卷积(20个内核),ReLu(形状[15,1,20]) 连接以前的输出(形状[15,1,21]) 压缩和1x1卷积(1个内核),ReLu(形状[15,1]) 挤压和softmax(形状[15]) dynamic\u rnn的批大小约为100(与上面描述的100不同,这

我在时间序列上训练RNN。我将其子类化为
RNNCell
,并在
dynamic\u rnn
中使用它。
RNNCell
的拓扑结构如下:

  • 输入(形状
    [15100,3]
  • 1x3卷积(5个内核),ReLu(形状
    [15,98,5]
  • 1x(剩余)卷积(20个内核),ReLu(形状
    [15,1,20]
  • 连接以前的输出(形状
    [15,1,21]
  • 压缩和1x1卷积(1个内核),ReLu(形状
    [15,1]
  • 挤压和softmax(形状
    [15]
  • dynamic\u rnn
    的批大小约为100(与上面描述的100不同,这是数据窗口中的时间段数)。纪元由大约200批组成。 我想尝试超参数和正则化,但我尝试的太多了,完全停止了学习,我不明白为什么。以下是发生的一些奇怪的事情:

    • Adagrad可以工作,但如果我使用Adam或Nadam,梯度都是零

    • 我被迫设定一个巨大的学习率(~1.0),以观察各个时代的学习情况

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

    • 如果我调整卷积中的核数,对于一些看起来同样好的选择(例如5,25,1 vs 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
    

    最可能的情况是,您正面临“消失的梯度”问题

    潜在的不稳定性可能是由于将ReLU与少量参数结合使用而导致的。据我从描述中了解,例如,第一层中只有
    1x3x5=15
    可训练参数。如果假设初始化值在零附近,则平均50%的参数的梯度将始终保持零。一般来说,在一个邪恶的小网络上,特别是在RNN的情况下

  • 尝试使用泄漏的ReLU(但你可能会面临爆炸性的渐变)
  • 尝试使用tanh,但检查参数的初始值,确保它们确实在零附近,否则渐变也会很快消失
  • 在步骤0检索未经培训但刚刚初始化的网络的结果。有了正确的初始化和NN构造,你应该得到正态分布的值。5如果你有严格的1、0或它们的混合,你的NN架构是错误的。严格来说,所有的值。5也是不好的
  • 考虑更稳健的方法,如LSTM

  • 序列长度为100?正确,窗口有100个时间段。我也在尝试这些,但它们似乎并没有破坏一切。如果您提供完整的代码和一些数据以使其重现,那就太好了。我很乐意,但完整的代码太长了(它包括直接在TF中预处理数据和另一个完整的对象来传输数据)。我可以给你看
    RNNCell
    ,它足够紧凑了。我的高斯分布中心是0,而不是0.5。你认为这就是问题所在吗?请参阅:分布是以零为中心的截断正态分布
    截断正态(shape,0.0,stddev=sqrt(factor/n))
    这是否解释了Adam不工作而Adagrad工作的原因?您的输出应该在.5左右,因为初始化后softmax之前的值应该在0左右。很难判断您的初始化是否正确。最简单的测试:在没有培训的情况下运行模型并检查输出?严格来说,1/0-初始化值太大,.5-初始化值太小。它可以解释为什么一些优化器不工作。有些方法对消失梯度问题更具鲁棒性,但这取决于实现。这也解释了为什么你需要走大步,因为你的梯度很小,没有大步你就无法收敛。因此,事实证明,tflearn
    variance\u scaling()
    用负值初始化了大多数Weights。我将在github上打开一个问题,因为我觉得它像一个bug。