Deep learning 为什么我的训练损失有规律的峰值?

Deep learning 为什么我的训练损失有规律的峰值?,deep-learning,keras,Deep Learning,Keras,我正在训练这个问题底部链接的Keras对象检测模型,尽管我相信我的问题与Keras和我试图训练的特定模型(SSD)无关,而是与训练期间数据传递到模型的方式有关 这是我的问题(见下图): 我的训练损失总体上在减少,但它显示出明显的规律性峰值: x轴上的单位不是训练时期,而是数十个训练步骤。峰值每1390个训练步骤恰好出现一次,这正是我的训练数据集上一次完整传递的训练步骤数 每次完全通过训练数据集后都会出现尖峰,这一事实让我怀疑问题不在于模型本身,而在于训练期间输入的数据 我在培训期间使用生成批次

我正在训练这个问题底部链接的Keras对象检测模型,尽管我相信我的问题与Keras和我试图训练的特定模型(SSD)无关,而是与训练期间数据传递到模型的方式有关

这是我的问题(见下图): 我的训练损失总体上在减少,但它显示出明显的规律性峰值:

x轴上的单位不是训练时期,而是数十个训练步骤。峰值每1390个训练步骤恰好出现一次,这正是我的训练数据集上一次完整传递的训练步骤数

每次完全通过训练数据集后都会出现尖峰,这一事实让我怀疑问题不在于模型本身,而在于训练期间输入的数据

我在培训期间使用生成批次。我检查了生成器的源代码,它在每次通过前都会使用
sklearn.utils.shuffle
洗牌训练数据集

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

  • 每次传球前都会对训练数据集进行洗牌
  • 正如您在中所看到的,我正在使用生成器的特殊数据增强功能,因此从理论上讲,任何过程的数据集都不应该相同:所有的增强都是随机的
  • 我做了一些测试预测,看看这个模型是否真的学到了什么,而且确实如此!随着时间的推移,预测会变得更好,但当然,模型的学习速度非常慢,因为这些尖峰似乎每1390步就会弄乱梯度

    任何关于这可能是什么的提示都将不胜感激!我在使用上面链接的Jupyter笔记本进行培训,唯一的变量是批量大小从32变为16。除此之外,链接的笔记本包含我正在遵循的确切培训过程

    以下是指向包含模型的存储库的链接:


    我自己就想出来了:

    TL;医生:

    确保损失量与最小批量无关

    详细解释:

    就我而言,问题毕竟是具体的

    也许这个问题的解决方案在某个时候会对某些人有用

    结果表明,Keras将损失除以最小批量。这里需要理解的重要一点是,不是损失函数本身对批量大小进行平均,而是平均发生在培训过程中的其他地方

    为什么这很重要

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

    现在,数据集中的样本数通常不是所选批次大小的整数倍,因此历元的最后一个小批次(这里我隐式地将历元定义为数据集中的一个完整过程)最终包含的样本数将少于批次大小。如果损失的大小取决于批量大小,那么这就是造成损失大小混乱的原因,反过来又会造成梯度大小混乱。因为我使用的是一个带有动量的优化器,所以混乱的梯度也会继续影响后续几个训练步骤的梯度


    一旦我通过将损失乘以批量大小(从而恢复Keras随后除以批量大小)来调整损失函数,一切都很好:损失中不再出现尖峰。

    我会添加梯度剪辑,因为这样可以防止梯度中的尖峰在训练期间扰乱参数

    梯度剪裁是一种在非常深的网络(通常是递归神经网络)中防止梯度爆炸的技术


    大多数程序允许您向基于GD的优化器添加渐变剪裁参数

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

    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)
    

    这几乎不是一个,我认为这个问题可以很好地解决,这将增加获得答案的概率:)@djk47463我同意这几乎不是一个紧凑的示例,但是如果你有一个复杂的对象检测模型,并且问题可能出在模型的任何部分,你如何创建一个紧凑的示例?不管怎样,我自己解决了,毕竟这是一个克拉斯特有的问题。也许这在某个时候对某些人有用。梯度剪裁可能会完成工作,但我认为在这种情况下这不是一个好主意,因为它可以治疗症状而不是原因(损失本来就不应该爆炸)。此外,已经提供了解决方案:在大多数情况下,如上文所述,问题在于损失大小取决于批量大小,而这本不应该。在这种情况下,通常只丢弃最后一批比较安全。即使损失与批次大小无关,但很小的批次更有可能包含不具代表性的数据,从而扰乱梯度。当使用小批量梯度下降时,损失情况不是固定的,但随着每个批次的变化而变化。如果批量太小,这可能会导致损失的典型波动。只有当批量大小足够大,能够代表整个数据集时,损失才会稳定下来。因此,在新纪元结束时的一小批(呃)也会产生类似的负面影响。@A_客人,我不确定我是否同意,原因有三。1) 任何通常使用的小批量大小相对于整个数据集都非常小,以至于损失