Adam 优化器在 200k 批次后失控,训练损失增加

Posted

技术标签:

【中文标题】Adam 优化器在 200k 批次后失控,训练损失增加【英文标题】:Adam optimizer goes haywire after 200k batches, training loss grows 【发布时间】:2017-07-08 17:27:57 【问题描述】:

我在训练网络时看到了一种非常奇怪的行为,在经过 10 万次迭代(8 到 10 小时)之后,一切都很好,训练损失增长

训练数据本身是随机分布的,分布在许多 .tfrecord 文件中,每个文件都包含 1000 示例,然后在输入阶段再次打乱并批处理到 200 示例。

背景

我正在设计一个同时执行四个不同回归任务的网络,例如确定对象出现在图像中的可能性并同时确定其方向。该网络从几个卷积层开始,其中一些具有残差连接,然后分支为四个全连接段。

由于第一次回归产生概率,我使用交叉熵作为损失,而其他人使用经典 L2 距离。然而,由于它们的性质,概率损失约为0..1,而方向损失可能更大,例如0..10。我已经对输入和输出值进行了规范化并使用了裁剪

normalized = tf.clip_by_average_norm(inferred.sin_cos, clip_norm=2.)

在事情可能变得非常糟糕的情况下。

我一直(成功地)使用 Adam 优化器优化包含所有不同损失的张量(而不是 reduce_suming 他们),如下所示:

reg_loss = tf.reduce_sum(tf.get_collection(tf.GraphKeys.REGULARIZATION_LOSSES))
loss = tf.pack([loss_probability, sin_cos_mse, magnitude_mse, pos_mse, reg_loss])

optimizer = tf.train.AdamOptimizer(learning_rate=learning_rate,
                                   epsilon=self.params.adam_epsilon)
op_minimize = optimizer.minimize(loss, global_step=global_step)

为了在 TensorBoard 中显示结果,我实际上是这样做的

loss_sum = tf.reduce_sum(loss)

用于标量摘要。

Adam 设置为学习率 1e-4 和 epsilon 1e-4(我看到使用 epislon 的默认值的行为相同,当我将学习率保持在 1e-3 时,它会更快地中断)。正则化对此也没有影响,它在某些时候会始终如一地这样做。

我还应该补充一点,停止训练并从最后一个检查点重新开始 - 这意味着训练输入文件也会再次打乱 - 会导致相同的行为。在那一点上,训练似乎总是表现得相似。

【问题讨论】:

快速健全性检查:您以什么顺序训练数据? 随机文件中的随机批次。将编辑。 当您的训练损失对向量的规范不敏感时,我已经看到了类似的情况。然后发生的情况是,您的数量可以无限制地变大/变小,以及浮点算术的哪些点限制起作用。避免这种情况的方法是确保所有数量都有正则化惩罚并且在相似的数值范围内 【参考方案1】:

是的。这是亚当的一个已知问题。

亚当的方程是

t <- t + 1
lr_t <- learning_rate * sqrt(1 - beta2^t) / (1 - beta1^t)

m_t <- beta1 * m_t-1 + (1 - beta1) * g
v_t <- beta2 * v_t-1 + (1 - beta2) * g * g
variable <- variable - lr_t * m_t / (sqrt(v_t) + epsilon)

其中m 是平均梯度的指数移动平均值,v 是梯度平方的指数移动平均值。问题是当你训练了很长时间并且接近最优时,v 会变得非常小。如果突然之间梯度再次开始增加,它将被一个非常小的数字除以并爆炸。

默认情况下beta1=0.9beta2=0.999。所以m 的变化比v 快得多。所以m 可以再次变大,而v 仍然很小,无法赶上。

要解决此问题,您可以增加epsilon,默认为10-8。从而停止了几乎除以 0 的问题。 根据您的网络,0.10.010.001 中的 epsilon 值可能很好。

【讨论】:

我删除了我正在使用的一个单独的损失函数并且不再看到这个问题......现在我了解到我只是让我的模型变得更糟。哦! 这是一个很好的建议。我个人使用 pytorch,默认 Adam eps 为 1e-8,我认为这太低了。 1e-4 让我训练时没有梯度爆炸,学习率高,也不需要梯度裁剪! 另一种补救措施可以是beta_1 = beta_2 还是与更改epsilon 不同? “这是亚当的一个已知问题。”您能否链接其他人讨论此行为的资源? 我已经在几个地方看到了这个建议,但我没想到在一个关于 SO 的随机问题下会找到如此合理的解释。我认为这可能是命名的问题。 epsilon 看起来只是一个无聊的稳定性常数,你应该设置得低一点,永远不要打扰它。【参考方案2】:

是的,这可能是某种超级复杂的不稳定数字/方程的情况,但可以肯定的是,你的训练率只是太高了,因为你的损失迅速下降到 25K,然后在同一水平上振荡很多。尝试将其减少 0.1 倍,看看会发生什么。您应该能够达到更低的损失值。

继续探索! :)

【讨论】:

以上是关于Adam 优化器在 200k 批次后失控,训练损失增加的主要内容,如果未能解决你的问题,请参考以下文章

SDG,ADAM,LookAhead,Lion等优化器的对比介绍

Adam优化器

Keras 中的自定义损失函数应该返回批次的单个损失值还是训练批次中每个样本的一系列损失?

使用Tensorflow后端的Keras LSTM RNN中令人费解的训练损失与纪元...行为的任何原因

TensorFlow 模型恢复(恢复训练似乎从头开始)

SGD、Adam优化器