为什么训练期间损失/准确率会波动?(Keras,LSTM)

机器算法验证 lstm 循环神经网络 喀拉斯
2022-02-06 17:50:47

我在 Keras 中使用 LSTM 网络。在训练期间,损失波动很大,我不明白为什么会发生这种情况。

这是我最初使用的 NN: 在此处输入图像描述

以下是训练期间的损失和准确性: 在此处输入图像描述

(请注意,准确度实际上最终确实达到了 100%,但需要大约 800 个 epoch。)

我认为这些波动的发生是因为 Dropout 层/学习率的变化(我使用了 rmsprop/adam),所以我做了一个更简单的模型: 在此处输入图像描述

我还使用了没有动量和衰减的 SGD。我尝试了不同的值,lr但仍然得到相同的结果。

sgd = optimizers.SGD(lr=0.001, momentum=0.0, decay=0.0, nesterov=False)

但我仍然遇到同样的问题:损失在波动而不是在减少。我一直认为损失只是假设逐渐下降,但在这里它似乎没有这样的行为。

所以:

  1. 训练过程中loss出现这样的波动是正常的吗?为什么会发生?

  2. 如果不是,为什么对于lr参数设置为某个非常小的值的简单 LSTM 模型会发生这种情况?

谢谢。(请注意,我在这里检查了类似的问题,但它并没有帮助我解决我的问题。)

更新: 1000+ epochs 的损失(没有 BatchNormalization 层,Keras 的 unmodifier RmsProp): 在此处输入图像描述

更新。2: 对于最终图:

model.compile(loss='categorical_crossentropy', optimizer='rmsprop', metrics=['accuracy'])
history = model.fit(train_x, train_y, epochs = 1500)

数据:电流值序列(来自机器人的传感器)。

目标变量:机器人正在运行的表面(作为单热向量,6 个不同类别)。

预处理:

  1. 更改了采样频率,因此序列不会太长(LSTM 似乎没有学习其他方法);
  2. 将序列切割成较小的序列(所有较小序列的长度相同:每个 100 个时间步长);
  3. 检查 6 个类中的每一个在训练集中具有大致相同数量的示例。

没有填充。

训练集的形状(#sequences、#timesteps in a sequence、#features):

(98, 100, 1) 

对应标签的形状(作为 6 个类别的 one-hot 向量):

(98, 6)

层数:

在此处输入图像描述

其余参数(学习率、批量大小)与 Keras 中的默认值相同:

keras.optimizers.RMSprop(lr=0.001, rho=0.9, epsilon=None, decay=0.0)

batch_size:整数或无。每次梯度更新的样本数。如果未指定,则默认为 32。

更新。3: 损失batch_size=4

在此处输入图像描述

因为batch_size=2LSTM 似乎没有正确学习(损​​失在相同的值附近波动并且没有减少)。

更新。4:看问题是否不只是代码的bug:我做了一个人工例子(2个不难分类的类:cos vs arccos)。这些示例在训练期间的损失和准确性: 在此处输入图像描述

3个回答

有几个原因会导致训练损失在不同时期内出现波动。主要的一个事实是几乎所有的神经网络都是用不同形式的随机梯度下降训练的。这就是为什么存在 batch_size 参数的原因,它决定了要使用多少样本来对模型参数进行一次更新。如果您每次更新都使用所有样本,您应该会看到它在减少并最终达到限制。请注意,具有一些随机行为的损失还有其他原因。

这就解释了为什么我们会看到振荡。但在你的情况下,我会说这更正常。查看您的代码,我看到两个可能的来源。

  1. 大型网络,小型数据集:您似乎正在训练一个相对较大的网络,该网络具有 200K+ 参数,样本数量非常少,~100。从这个角度来看,您想学习 200K 参数或仅使用 100 个样本在 200K-D 空间中找到良好的局部最小值。因此,您最终可能只是四处游荡,而不是锁定一个好的局部最小值。(徘徊也是因为下面的第二个原因)。

  2. 非常小的batch_size。你使用非常小的batch_size。因此,就像您信任数据点的每一小部分一样。假设在您的数据点中,您有一个错误标记的样本。该样本与 2-3 个甚至正确标记的样本组合时,可能会导致更新不会减少全局损失,但会增加它,或者将其从局部最小值中丢弃。当batch_size 较大时,这种影响会降低。除了其他原因,batch_size 最好高于某个最小值。它太大也会使训练变慢。因此,batch_size 应该被视为一个超参数。

你的损失曲线在我看来还不错。只要总体趋势是下跌,它肯定应该上下“波动”一点 - 这是有道理的。

批量大小也会影响网络的学习方式,因此您可能希望与学习率一起优化它。另外,我会绘制整个曲线(直到它达到 100% 的准确度/最小损失)。听起来你训练了 800 个 epoch 并且只显示了前 50 个 epoch - 整个曲线可能会给出一个非常不同的故事。

波动在一定限度内是正常的,并且取决于您使用启发式方法的事实,但在您的情况下它们是过度的。尽管所有性能都有一个明确的方向,因此该系统可以正常工作。从您发布的图表来看,问题取决于您的数据,因此这是一项困难的培训。如果您已经尝试更改学习率,请尝试更改训练算法。您会同意测试您的数据:首先使用 KNN 计算贝叶斯错误率(在需要时使用技巧回归),这样您可以检查输入数据是否包含您需要的所有信息。然后在没有验证或 dropout 的情况下尝试 LSTM,以验证它是否有能力为您实现必要的结果。如果训练算法不合适,即使没有验证或 dropout,您也应该遇到相同的问题。只是在最后调整训练和验证大小以获得测试集中的最佳结果。统计学习理论不是一次可以谈的话题,必须循序渐进。