验证误差小于训练误差?


57

我在这里这里都发现了两个关于这个问题的问题,但是还没有明显的答案或解释。在我的卷积神经网络中,验证错误小于训练错误时,我仍然执行相同的问题。这意味着什么?


我认为在不知道训练(cv)和测试用例的绝对数量以及针对交叉验证和测试的MSE所观察到的差异的情况下,无法回答这个问题。
cbeleites 2015年

随机播放数据
user0

我们从中得出什么呢?是的,它是由具有辍学和batchnorm层的密集网络生成的。![在此处输入图片描述 ](i.stack.imgur.com/KX1Fz.png
Srinath

Answers:


69

不知道您的实际方法(例如交叉验证方法,性能指标,数据拆分方法等)很难确定。

一般来说,训练错误几乎总是会低估您的验证错误。但是,验证误差有可能小于训练误差。您可以通过两种方式来考虑:

  1. 您的训练集有很多“难”的案例需要学习
  2. 您的验证集大部分具有“容易”的情况可以预测

这就是为什么真正评估模型训练方法很重要的原因。如果您不对数据进行适当的培训,那么结果将导致令人困惑的结论,即使不是简单的错误。

我认为模型评估分为四个不同的类别:

  1. 拟合不足-验证和培训错误高

  2. 过拟合–验证误差高,训练误差低

  3. 适合度高–验证误差低,略高于训练误差

  4. 未知拟合度-验证错误低,训练错误“高”

我说“未知”适合,因为结果与机器学习的工作原理相反。机器学习的本质是预测未知数。如果您比“学习”的知识更能预测未知数,则AFAIK训练和验证之间的数据必须有所不同。这可能意味着您要么需要重新评估数据拆分方法,添加更多数据,要么可能需要更改性能指标(您实际上是在测量所需的性能吗?)。

编辑

为了解决OP对先前的python 千层面问题的引用。

这表明您有足够的数据,不需要交叉验证,而只需训练,验证和测试数据子集。现在,如果您查看烤宽面条教程,您会发现在页面顶部看到了相同的行为。我很难相信如果奇怪的话作者会发布这样的结果,但我们不只是假设它们是正确的,而是让我们进一步看。我们最感兴趣的部分是训练循环部分,在底部的正上方,您将看到如何计算损耗参数。

培训的损失是在计算出整个训练数据集。同样,在整个验证数据集上计算验证损失。训练集通常至少是验证(80-20)的4倍。假设误差是在所有样本上计算得出的,则可以预期损失约为验证集损失度量的4倍。但是,您会注意到,随着培训的继续,培训损失和验证损失正在接近。这是有意的,好像您的训练错误开始变得低于验证错误一样,您将开始过拟合模型!!!

我希望这可以澄清这些错误。


2
好答案。代码中也可能存在错误,这可能导致训练尚未收敛到训练集上的最佳解决方案。或者,如果训练目标不是凸的,并且训练算法收敛到恰好对验证集有利的局部最小值。
索比2015年

@cdeterman谢谢。我使用RMSE作为性能指标。我将数据分为20%用于测试,而80%用于训练和验证(20%的训练数据经过交叉验证以计算验证误差)。实际上,验证误差很低,略低于训练误差。测试错误高于训练和验证错误。我们可以在MNISTdataset中找到类似的手写识别状态stats.stackexchange.com/questions/178371/…–
Bido

@Bido请问您我最近的编辑地址吗?
cdeterman

@cdeterman谢谢。我刚刚注意到您已经编辑了答案。这很清楚而且很有帮助。
2015年

很好的解释,如果您可以添加一些图表-这将是可能的最好图表
Taras Matsyk

109

一种可能性:如果您在网络中使用辍学正则化层,则验证错误小于训练错误是合理的。因为通常在训练时退出会被激活,而在验证集上进行评估时会被取消激活。在后一种情况下,您可以获得更流畅的功能(通常意味着更好)。


12
一个简单,明智的答案!
rajb245 '17

4
是的,确实应该将其标记为正确答案。
Simanas

2
我删除了辍学层,但仍然看到验证损失比起初的训练损失低!(我也没有在层上指定任何正则化!)
Josiah Yoder '18

适合我的情况。使用大量辍学。
安德烈·克里斯托弗·安徒生

@JosiahYoder-您还有什么要分享的吗?我有1650个输入功能。当我保持网络较小(1650、50、1)丢失或没有丢失时,初始时期的训练错误高于验证错误。当我使用大型网络(具有selu激活的1650、1200、800、100 ....大约10层100层)时,较高验证准确性的怪异模式会有所缓解。
MiloMinderbinder

19

我没有足够的观点来评论@DK的答案,但是现在作为Keras文档的常见问题解答来回答:

“为什么培训损失比测试损失高得多?

Keras模型具有两种模式:训练和测试。在测试时会关闭诸如Dropout和L1 / L2权重正则化等正则化机制。

此外,训练损失是每批训练数据损失的平均值。由于您的模型会随着时间而变化,因此,前几个时期的损失通常高于最后几个时期的损失。另一方面,一个时期的测试损失是使用模型计算的,因为它处于该时期的末尾,因此损失较低。”


1
这也不能完全回答问题。禁用辍学功能后,我仍然看到连续几个时期的验证损失大约是训练损失的一半!
Josiah Yoder '18

您的培训数据代表开发数据吗?
dter

我将数据集随机分为训练和测试。从视觉上看,它是一个很好的样本。我正在研究一个回归问题,其中最好的分类器仅比总是预测平均值好一点。
乔希亚·约德

您的答案没有说培训损失大于验证损失,这是所提出的问题。你是更侧重于培训损失和测试损失
enjal

6

我的2美分:即使没有辍学层,我也遇到了同样的问题。就我而言-批处理规范层是罪魁祸首。当我删除它们时,训练损失变得类似于验证损失。之所以发生这种情况,可能是因为在训练期间,批次范数使用给定输入批次的均值和方差,这在批次之间可能会有所不同。但是在评估过程中,批次规范使用运行均值和方差,这两者都反映了整个训练集的属性,比训练期间单个批次的均值和方差要好得多。至少,这就是在pytorch中实现批处理规范的方式


1
谢谢@ Mans007,这发生在我身上,我正在使用Keras。批次规范层是原因。
Roei Bahumi

4

通过某种方式组合@cdeterman@DK的答案的另一种可能性是,如果您使用某种数据增强机制。事实数据的增强通常仅对训练集而不是对验证集进行(对于辍学正则化),这可能导致验证集包含比训练集中的情况更容易预测的案例。


2

我得到了类似的结果(测试损失明显低于训练损失)。一旦我删除了辍学正规化,两者的损失几乎相等。


0

@cdeterman和@DK有很好的解释。我还要再说一个理由- data leakage。训练数据的某些部分与测试数据“密切相关”。

潜在的例子:假设您有1000只狗和1000只猫,每只宠物有500张相似的照片(有些主人喜欢以非常相似的姿势拍摄他们的宠物的照片)。因此,如果您随机进行70/30分割,则会使火车数据泄漏到测试数据中。


0

简而言之,如果正确计算出训练损失和验证损失,则训练损失不可能高于验证损失。这是因为反向传播直接减少了在训练集上计算出的误差,而仅间接(甚至不能保证!)减少了在验证集上计算出的误差。

培训和验证时必须有一些其他因素是不同的。辍学是一个好人,但也可以有其他人。确保检查使用的任何库的文档。模型和图层通常可以具有我们通常不关注的默认设置。


0

与辍学或其他相关的波动可能会导致验证低于培训错误,但如果长期持续下去,则可能表明培训和验证数据集实际上并非来自相同的统计集合。如果您的示例来自一个系列,并且您没有正确地随机分配训练和验证数据集,则可能会发生这种情况。


0

目前,基于随机梯度的方法几乎始终是深度学习的首选算法。这意味着数据将成批输入,计算梯度并更新参数。这意味着您还可以在选择每个批次时计算数据损失。在此框架下,有两种方式如何损失的计算,我能想到的可能会导致这种现象的训练误差大于验证错误更大。在下面,我表明Keras实际上似乎是通过这些方式计算样本内误差的。

1.)训练误差是在整个时期内平均的,而不是在时期末一次平均,但是验证误差仅在时期末。请注意,验证错误具有完全更新的优势,而训练错误包括更新次数较少的错误计算。当然,渐近地,这种效果通常应该消失。

2.)批量更新之前计算训练误差。在基于随机梯度的方法中,梯度会有些噪声。当人们在爬山时,很有可能减少所有训练样本计算得出的整体损失。但是,当一个模式非常接近该模式时,相对于批次中的样本更新方向将为负。但是,由于我们围绕某个模式反弹,这意味着平均而言,我们必须选择一个相对于样本输出为正的方向批次。现在,如果我们要针对给定批次中的样本进行更新,则意味着它们已经被潜在的许多未包含在其中的批次更新所推动,通过计算更新前的损失,这就是随机的方法已将参数推向最有利于数据集中其他样本的位置,从而使我们在预期损失上的偏差较小。

请注意,虽然渐近,但(1)的效果消失了,(2)的效果没有消失!下面我显示Keras似乎同时执行(1)和(2)。

(1)表明指标是每个时期的平均批次,而不是最后一次全部。请注意,在第一个时期,样本内准确性与val_accuracy的巨大差异有利于val_accuracy。这是因为一些样本内错误是通过很少的批处理更新来计算的。

>>> model.fit(Xtrn, Xtrn, epochs = 3, batch_size = 100, 
...                 validation_data = (Xtst, Xtst))
Train on 46580 samples, validate on 1000 samples
Epoch 1/3
46580/46580 [==============================] - 8s 176us/sample 
- loss: 0.2320 - accuracy: 0.9216 
- val_loss: 0.1581 - val_accuracy: 0.9636
Epoch 2/3
46580/46580 [==============================] - 8s 165us/sample 
- loss: 0.1487 - accuracy: 0.9662 
- val_loss: 0.1545 - val_accuracy: 0.9677
Epoch 3/3
46580/46580 [==============================] - 8s 165us/sample 
- loss: 0.1471 - accuracy: 0.9687 
- val_loss: 0.1424 - val_accuracy: 0.9699
<tensorflow.python.keras.callbacks.History object at 0x17070d080>

(2)显示错误是更新每个批次之前计算的。请注意,对于时代1,当我们使用batch_size = nRows(即一批中的所有数据)时,对于时代1,样本内误差约为0.5(随机猜测),但验证误差为0.82。因此,样本内误差是批量更新之前计算的,而验证误差是批量更新之后计算的。

>>> model.fit(Xtrn, Xtrn, epochs = 3, batch_size = nRows, 
...                 validation_data = (Xtst, Xtst))
Train on 46580 samples, validate on 1000 samples
Epoch 1/3
46580/46580 [==============================] - 9s 201us/sample 
- loss: 0.7126 - accuracy: 0.5088 
- val_loss: 0.5779 - val_accuracy: 0.8191
Epoch 2/3
46580/46580 [==============================] - 6s 136us/sample 
- loss: 0.5770 - accuracy: 0.8211 
- val_loss: 0.4940 - val_accuracy: 0.8249
Epoch 3/3
46580/46580 [==============================] - 6s 120us/sample 
- loss: 0.4921 - accuracy: 0.8268 
- val_loss: 0.4502 - val_accuracy: 0.8249
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.