为什么我的训练损失经常出现高峰?

Ale*_*lex 11 deep-learning keras

我正在训练位于此问题底部的Keras对象检测模型,尽管我认为我的问题既与Keras无关,也不与我要训练的特定模型(SSD)有关,而是与数据方式有关在训练过程中传递给模型。

这是我的问题(请参见下图):我的训练损失总体上在减少,但显示出尖锐的定期峰值:

训练损失

x轴上的单位不是训练时期,而是数十个训练步骤。峰值每1390个训练步骤发生一次,这恰好是我的训练数据集上一次完整通过的训练步骤数。

尖峰总是在每次经过训练数据集之后始终发生的事实,使我怀疑问题不在于模型本身,而在于训练过程中正在馈送的数据。

我正在使用存储库中提供批处理生成器在培训期间生成批处理。我检查了生成器的源代码,并且在每次使用之前,它都确实洗牌了训练数据集sklearn.utils.shuffle

我感到困惑的原因有两个:

  1. 每次通过之前都要对训练数据集进行重新排序。
  2. 正如您在Jupyter笔记本中所看到的那样,我正在使用生成器的临时数据增强功能,因此,理论上数据集对于任何遍都不应该是相同的:所有增强都是随机的。

我做了一些测试预测,看看模型是否真的在学习任何东西!随着时间的推移,预测会变得更好,但是当然,该模型的学习速度非常慢,因为这些峰值似乎每1390步就会弄乱梯度。

任何关于这可能得到的提示,我们将不胜感激!我使用上面链接的完全相同的Jupyter笔记本进行培训,我更改的唯一变量是批次大小(从32到16)。除此之外,链接的笔记本包含我正在遵循的准确培训过程。

这是包含模型的存储库的链接:

https://github.com/pierluigiferrari/ssd_keras

Ale*_*lex 11

我自己弄清楚了:

TL; DR:

确保损失幅度与迷你批次的大小无关。

详细说明:

就我而言,这个问题毕竟是针对Keras的。

也许在某些时候解决这个问题对某人很有用。

事实证明,Keras将损耗除以最小批量。在这里要了解的重要一点是,不是损失函数本身对批次大小进行平均,而是在训练过程中的其他地方进行平均。

为什么这么重要?

我正在训练的模型SSD使用了一个相当复杂的多任务损失函数,该函数进行自己的平均(不是按批次大小,而是按批次中地面真相边界框的数量)。现在,如果损失函数已经将损失除以与批次大小相关的某个数字,然后Keras 第二次除以批次大小,那么突然损失值的大小开始取决于批次大小(准确地说,它与批量大小成反比)。

现在通常数据集中的样本数量不是您选择的批量大小的整数倍,因此一个时期的最后一个小批量(这里我隐含地将一个时期定义为对数据集的一次完整遍历)将最终包含样品数量少于批次大小。如果这取决于批次的大小,那么就会使损失的大小混乱,进而使梯度的大小混乱。由于我使用的是带有动量的优化器,因此,混乱的梯度也会继续影响随后几个训练步骤的梯度。

一旦我通过将损失乘以批次大小来调整损失函数(从而将Keras的后续除以批次大小),一切都很好:损失不再增加。


wpr*_*ins 5

对于在 PyTorch 中工作的任何人,解决此特定问题的一个简单解决方案是在中指定DataLoader删除最后一批:

train_loader = torch.utils.data.DataLoader(train_set, batch_size=batch_size, shuffle=False, 
                                          pin_memory=(torch.cuda.is_available()), 
                                          num_workers=num_workers, drop_last=True)
Run Code Online (Sandbox Code Playgroud)

  • 当然,这可以完成工作,但它也只是治标不治本的拐杖。关键是损失大小不应该取决于小批量大小,因为这没有意义。如果你做对了,那么就不需要放弃最后一个小批量或担心其他任何事情。 (2认同)