如何让 TensorFlow RNN 训练更稳健?
How can I make TensorFlow RNN training more robust?
我正在用时间序列训练 RNN。我将 RNNCell
子类化并在 dynamic_rnn
中使用它。 RNNCell
的拓扑结构如下:
- 输入(形状
[15, 100, 3]
)
- 1x3 卷积(5 个内核),ReLu(形状
[15, 98, 5]
)
- 1x(剩余)卷积(20 个内核),ReLu(形状
[15, 1, 20]
)
- 连接上一个输出(形状
[15, 1, 21]
)
- 挤压和 1x1 卷积(1 个内核),ReLu(形状
[15, 1]
)
- 挤压和 softmax(形状
[15]
)
dynamic_rnn
的批量大小约为 100(与上面描述的 100 不同,那是 window 数据中的时间段数)。时代由大约 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
很可能你正面临梯度消失的问题。
不稳定的原因可能是将 ReLU 与少量要调整的参数结合使用。据我从描述中了解到,例如,第一层中只有 1x3x5 = 15
个可训练参数。如果假设初始化大约为零,那么平均 50% 的参数的梯度将始终保持为零。一般来说,ReLU 在小型网络上是一种邪恶,尤其是在 RNNs 的情况下。
- 尝试使用 Leaky ReLU(但你可能会面临梯度爆炸)
- 尝试使用 tanh,但检查参数的初始值,它们确实在零附近,否则你的梯度也会很快消失。
- 检索未经训练但刚刚在第 0 步初始化的网络的结果。通过正确的初始化和 NN 构造,您应该获得大约 .5 的正态分布值。是错的。所有值都严格为 .5 也是不好的。
- 考虑更稳健的方法,例如 LSTM
我正在用时间序列训练 RNN。我将 RNNCell
子类化并在 dynamic_rnn
中使用它。 RNNCell
的拓扑结构如下:
- 输入(形状
[15, 100, 3]
) - 1x3 卷积(5 个内核),ReLu(形状
[15, 98, 5]
) - 1x(剩余)卷积(20 个内核),ReLu(形状
[15, 1, 20]
) - 连接上一个输出(形状
[15, 1, 21]
) - 挤压和 1x1 卷积(1 个内核),ReLu(形状
[15, 1]
) - 挤压和 softmax(形状
[15]
)
dynamic_rnn
的批量大小约为 100(与上面描述的 100 不同,那是 window 数据中的时间段数)。时代由大约 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
很可能你正面临梯度消失的问题。
不稳定的原因可能是将 ReLU 与少量要调整的参数结合使用。据我从描述中了解到,例如,第一层中只有 1x3x5 = 15
个可训练参数。如果假设初始化大约为零,那么平均 50% 的参数的梯度将始终保持为零。一般来说,ReLU 在小型网络上是一种邪恶,尤其是在 RNNs 的情况下。
- 尝试使用 Leaky ReLU(但你可能会面临梯度爆炸)
- 尝试使用 tanh,但检查参数的初始值,它们确实在零附近,否则你的梯度也会很快消失。
- 检索未经训练但刚刚在第 0 步初始化的网络的结果。通过正确的初始化和 NN 构造,您应该获得大约 .5 的正态分布值。是错的。所有值都严格为 .5 也是不好的。
- 考虑更稳健的方法,例如 LSTM