Deep learning 为什么我的训练损失有规律的峰值?
我正在训练这个问题底部链接的Keras对象检测模型,尽管我相信我的问题与Keras和我试图训练的特定模型(SSD)无关,而是与训练期间数据传递到模型的方式有关 这是我的问题(见下图): 我的训练损失总体上在减少,但它显示出明显的规律性峰值: x轴上的单位不是训练时期,而是数十个训练步骤。峰值每1390个训练步骤恰好出现一次,这正是我的训练数据集上一次完整传递的训练步骤数 每次完全通过训练数据集后都会出现尖峰,这一事实让我怀疑问题不在于模型本身,而在于训练期间输入的数据 我在培训期间使用生成批次。我检查了生成器的源代码,它在每次通过前都会使用Deep learning 为什么我的训练损失有规律的峰值?,deep-learning,keras,Deep Learning,Keras,我正在训练这个问题底部链接的Keras对象检测模型,尽管我相信我的问题与Keras和我试图训练的特定模型(SSD)无关,而是与训练期间数据传递到模型的方式有关 这是我的问题(见下图): 我的训练损失总体上在减少,但它显示出明显的规律性峰值: x轴上的单位不是训练时期,而是数十个训练步骤。峰值每1390个训练步骤恰好出现一次,这正是我的训练数据集上一次完整传递的训练步骤数 每次完全通过训练数据集后都会出现尖峰,这一事实让我怀疑问题不在于模型本身,而在于训练期间输入的数据 我在培训期间使用生成批次
sklearn.utils.shuffle
洗牌训练数据集
我感到困惑的原因有两个:
我自己就想出来了: 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) 任何通常使用的小批量大小相对于整个数据集都非常小,以至于损失