我正在训练这个问题底部链接的 Keras 对象检测模型,尽管我相信我的问题与 Keras 和我尝试训练的特定模型 (SSD) 无关,而是与数据的方式有关在训练期间传递给模型。
这是我的问题(见下图):
我的训练损失总体上正在减少,但它显示出明显的规律性峰值:
x 轴上的单位不是训练 epoch,而是几十个训练步骤。尖峰每 1390 个训练步骤精确出现一次,这正是我的训练数据集一次完整通过的训练步骤数。
每次完全通过训练数据集后总是会出现尖峰,这让我怀疑问题不在于模型本身,而在于训练期间输入的数据。
我正在使用 batch generator provided in the repository在训练期间生成批处理。我检查了生成器的源代码,它确实在每次通过之前使用 sklearn.utils.shuffle
对训练数据集进行了洗牌。 .
我很困惑有两个原因:
我做了一些测试预测,看看模型是否真的在学习任何东西,而且确实如此!随着时间的推移,预测会变得更好,但当然模型的学习速度非常慢,因为这些尖峰似乎每 1390 步就会扰乱梯度。
非常感谢任何关于这可能是什么的提示!我使用与上面链接的完全相同的 Jupyter 笔记本进行培训,我更改的唯一变量是从 32 到 16 的批量大小。除此之外,链接的笔记本包含我正在遵循的确切培训过程。
这是包含模型的存储库的链接:
https://github.com/pierluigiferrari/ssd_keras
最佳答案
我自己想通了:
TL;DR:
确保您的损失幅度与您的小批量大小无关。
长解释:
就我而言,这个问题毕竟是 Keras 特有的。
也许这个问题的解决方案在某些时候会对某人有用。
事实证明,Keras 将损失除以小批量大小。这里要理解的重要一点是,对批量大小进行平均的不是损失函数本身,而是在训练过程中的其他地方进行平均。
为什么这很重要?
我正在训练的模型 SSD 使用了一个相当复杂的多任务损失函数,它自己进行平均(不是按批处理大小,而是按批处理中地面实况边界框的数量)。现在,如果损失函数已经将损失除以与批量大小相关的某个数字,然后 Keras 除以批量大小 第二次 ,然后损失值的大小突然开始取决于批量大小(准确地说,它与批量大小成反比)。
现在通常数据集中的样本数量不是您选择的批量大小的整数倍,因此一个时期的最后一个小批量(这里我隐式地将一个时期定义为对数据集的一次完整传递)最终将包含样本数量少于批量大小。如果它取决于批量大小,这就是破坏损失幅度的原因,进而破坏了梯度的幅度。由于我使用的是具有动量的优化器,因此困惑的梯度也会继续影响一些后续训练步骤的梯度。
一旦我通过将损失乘以批量大小来调整损失函数(从而恢复 Keras 的后续除以批量大小),一切都很好:损失不再出现峰值。
关于deep-learning - 为什么我的训练损失有规律的峰值?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47824598/