编辑:zero 关注 搜罗最好玩的计算机视觉论文和应用,AI算法与图像处理 微信公众号,获得第一手计算机视觉相关信息

在本教程中,您将学习在训练自己的自定义深度神经网络时,验证损失可能低于训练损失的三个主要原因。

我的验证损失低于训练损失!

怎么可能呢?

  • 我是否意外地将训练和验证loss绘图的标签切换了? 潜在地。 我没有像matplotlib这样的绘图库,因此将丢失日志通过管道传输到CSV文件,然后在Excel中进行绘图。 绝对容易发生人为错误。
  • 我的代码中有错误吗? 几乎可以确定。 我同时在自学Java和机器学习-该代码中肯定存在某种错误。
  • 我只是因为太疲倦而无法理解我的大脑吗? 也很有可能。 我一生中的睡眠时间不多,很容易错过一些明显的事情。

但是,事实证明,上述情况都不是——我的验证损失确实比我的训练损失低。

要了解您的验证loss可能低于训练loss的三个主要原因,请继续阅读!

为什么我的验证loss低于训练loss?

在本教程的第一部分中,我们将讨论神经网络中“loss”的概念,包括loss代表什么以及我们为什么对其进行测量。

在此,我们将实现一个基础的CNN和训练脚本,然后使用新近实现的CNN进行一些实验(这将使我们的验证损失低于我们的训练损失)。

根据我们的结果,我将解释您的验证loss可能低于训练loss的三个主要原因。

训练神经网络时的“loss”是什么?

[1] 机器/深度学习的中的“loss”是什么? 为什么我的验证loss低于训练loss?

在最基本的层次上,loss函数可量化给定预测变量对数据集中输入数据点进行分类的“好”或“坏”程度。

loss越小,分类器在建模输入数据和输出目标之间的关系方面的工作就越好。

就是说,在某种程度上我们可以过度拟合我们的模型-通过过于紧密地建模训练数据(modeling the training data too closely),我们的模型将失去泛化的能力。

因此,我们寻求:

  1. 尽可能降低loss,从而提高模型精度。
  2. 尽可能快地这样子做,并减少超参数的更新/实验次数。
  3. 所有这些都没有过度拟合我们的网络,也没有将训练数据建模得过于紧密。。

这是一种平衡,我们选择loss函数和模型优化器会极大地影响最终模型的质量,准确性和通用性。

典型的损失函数(也称为“目标函数”或“评分函数”)包括:

  • Binary cross-entropy
  • Categorical cross-entropy
  • Sparse categorical cross-entropy
  • Mean Squared Error (MSE)
  • Mean Absolute Error (MAE)
  • Standard Hinge
  • Squared Hinge

对loss函数的全面回顾不在本文的范围内,但就目前而言,只需了解对于大多数任务:

  • loss衡量你的模型的“好(goodness)”
  • loss越小越好
  • 但你要小心别过拟合

要了解在训练自己的自定义神经网络时loss函数的作用,请确保:

  • 阅读参数化学习和线性分类简介。https://www.pyimagesearch.com/2016/08/22/an-intro-to-linear-classification-with-python/
  • 请阅读以下有关SoftMax分类器的教程。https://www.pyimagesearch.com/2016/09/12/softmax-classifiers-explained/
  • 关于多类SVM损失,请参阅本指南。https://www.pyimagesearch.com/2016/09/05/multi-class-svm-loss/

文件结构

从那里,通过tree命令检查项目/目录结构:

  $ tree --dirsfirst.├── pyimagesearch│   ├── __init__.py│   └── minivggnet.py├── fashion_mnist.py├── plot_shift.py└── training.pickle​1 directory, 5 files

今天我们将使用一个称为MiniVGGNet的更小版本的vggnet。pyimagesearch模块包括这个CNN。

我们的fashion_mnist.py脚本在fashion MNIST数据集上训练MiniVGGNet。我在之前的一篇博文中写过关于在时尚mnist上训练MiniVGGNet,所以今天我们不会详细讨论。

https://www.pyimagesearch.com/2019/02/11/fashion-mnist-with-keras-and-deep-learning/

今天的训练脚本将生成一个training.pickle文件,其中包含训练精度/loss历史记录。在下面的原因部分中,我们将使用plot_shift.py将训练loss图移动半个epoch,以证明当验证loss低于训练loss时,测量loss的时间起作用。现在让我们深入探讨三个原因来回答这个问题:“为什么我的验证loss比训练loss低?“。

原因1:在训练中应用正则化,但在验证/测试中未应用正则化

[2] Aurélien在他的Twitter提要上回答了一个问题:“大家都想知道为什么验证loss>训练loss吗?”。 第一个原因是在训练过程中应用了正则化,但在验证/测试过程中未进行正则化。

在训练深度神经网络时,我们经常应用正则化来帮助我们的模型:

  1. 获得更高的验证/测试精度
  2. 理想情况下,为了更好地泛化验证和测试集之外的数据

正则化方法通常会牺牲训练准确性来提高验证/测试准确性——在某些情况下,可能导致您的验证loss低于训练loss。

其次,请记住,在验证/测试时不应用诸如dropout之类的正则化方法。

作为的Aurelien显示在图2中,原因验证loss应正则化(例如,在验证/测试时应用dropout)可以让你的训练/验证loss曲线看起来更相似。

原因2:训练loss是在每个epoch测量的,而验证loss是在每个epoch后测量的

[3] 验证loss的原因2有时小于训练损失,这与进行测量的时间有关

您可能会看到验证loss低于训练loss的第二个原因是由于如何测量和报告loss值:

  1. 训练loss在每个epoch过程中测量的
  2. 而验证loss是在每个epoch后测量的

在整个epoch内,您的训练loss将不断得到报告;但是,仅在当前训练epoch完成后,才根据验证集计算验证指标。

这意味着,平均而言,训练loss要提前半个epoch来衡量。

如果您将训练loss向左移动半个epoch,您会发现训练和验证loss值之间的差距要小得多。

有关此行为的示例,请阅读以下部分。

执行我们的训练脚本

我们将实现一个简单的Python脚本,以在Fashion MNIST数据集上训练类似于VGG的小型网络(称为MiniVGGNet)。在训练期间,我们会将训练和验证loss保存到磁盘中。然后,我们将创建一个单独的Python脚本,以比较未变动和变动后的loss图。

让我们开始执行loss脚本:

  # import the necessary packagesfrom pyimagesearch.minivggnet import MiniVGGNetfrom sklearn.metrics import classification_reportfrom tensorflow.keras.optimizers import SGDfrom tensorflow.keras.datasets import fashion_mnistfrom tensorflow.keras.utils import to_categoricalimport argparseimport pickle​# construct the argument parser and parse the argumentsap = argparse.ArgumentParser()ap.add_argument("-i", "--history", required=True,help="path to output training history file")args = vars(ap.parse_args())

第2-8行导入了我们所需的包,模块,类和函数。 即,我们导入MiniVGGNet(我们的CNN),fashion_mnist(我们的数据集)和pickle(确保可以序列化我们的训练历史以使用单独的脚本来处理绘图)。

命令行参数--history指向单独的.pickle文件,该文件将很快包含我们的训练历史记录(第11-14行)。

然后,我们初始化一些超参数,即我们要训练的epoch数,初始学习率和批量大小:

  # initialize the number of epochs to train for, base learning rate,# and batch sizeNUM_EPOCHS = 25INIT_LR = 1e-2BS = 32

然后,我们继续加载和预处理我们的Fashion MNIST数据:

  # grab the Fashion MNIST dataset (if this is your first time running# this the dataset will be automatically downloaded)print("[INFO] loading Fashion MNIST...")((trainX, trainY), (testX, testY)) = fashion_mnist.load_data()# we are using "channels last" ordering, so the design matrix shape# should be: num_samples x rows x columns x depthtrainX = trainX.reshape((trainX.shape[0], 28, 28, 1))testX = testX.reshape((testX.shape[0], 28, 28, 1))# scale data to the range of [0, 1]trainX = trainX.astype("float32") / 255.0testX = testX.astype("float32") / 255.0# one-hot encode the training and testing labelstrainY = to_categorical(trainY, 10)testY = to_categorical(testY, 10)# initialize the label nameslabelNames = ["top", "trouser", "pullover", "dress", "coat","sandal", "shirt", "sneaker", "bag", "ankle boot"]

第3-13行加载并预处理训练/验证数据。

第16和17行将我们的类别标签二值化,而第20和21行则列出了人类可读的类别标签名称,以供日后分类报告之用。

从这里,我们拥有编译和训练Fashion MNIST数据上的MiniVGGNet模型所需的一切:

  # initialize the optimizer and modelprint("[INFO] compiling model...")opt = SGD(lr=INIT_LR, momentum=0.9, decay=INIT_LR / NUM_EPOCHS)model = MiniVGGNet.build(width=28, height=28, depth=1, classes=10)model.compile(loss="categorical_crossentropy", optimizer=opt,metrics=["accuracy"])​# train the networkprint("[INFO] training model...")H = model.fit(trainX, trainY,validation_data=(testX, testY),batch_size=BS, epochs=NUM_EPOCHS)

第3-6行初始化并编译MiniVGGNet模型。

然后,第10-12行拟合/训练模型。

从这里我们将评估我们的模型并序列化我们的训练历史:

  # make predictions on the test set and show a nicely formatted# classification reportpreds = model.predict(testX)print("[INFO] evaluating network...")print(classification_report(testY.argmax(axis=1), preds.argmax(axis=1),target_names=labelNames))​# serialize the training history to diskprint("[INFO] serializing training history...")f = open(args["history"], "wb")f.write(pickle.dumps(H.history))f.close()

第3-6行对测试集进行预测,并将分类报告打印到终端。

10-12行将我们的训练准确性/损失历史序列化为.pickle文件。 我们将在单独的Python脚本中使用训练历史记录来绘制损耗曲线,包括一个显示二分之一epoch偏移的图。

从那里打开一个终端,然后执行以下命令:

  $ python fashion_mnist.py --history training.pickle[INFO] loading Fashion MNIST...[INFO] compiling model...[INFO] training model...Train on 60000 samples, validate on 10000 samples   Epoch 1/2560000/60000 [==============================] - 200s 3ms/sample - loss: 0.5433 - accuracy: 0.8181 - val_loss: 0.3281 - val_accuracy: 0.8815Epoch 2/2560000/60000 [==============================] - 194s 3ms/sample - loss: 0.3396 - accuracy: 0.8780 - val_loss: 0.2726 - val_accuracy: 0.9006Epoch 3/2560000/60000 [==============================] - 193s 3ms/sample - loss: 0.2941 - accuracy: 0.8943 - val_loss: 0.2722 - val_accuracy: 0.8970Epoch 4/2560000/60000 [==============================] - 193s 3ms/sample - loss: 0.2717 - accuracy: 0.9017 - val_loss: 0.2334 - val_accuracy: 0.9144Epoch 5/2560000/60000 [==============================] - 194s 3ms/sample - loss: 0.2534 - accuracy: 0.9086 - val_loss: 0.2245 - val_accuracy: 0.9194...Epoch 21/2560000/60000 [==============================] - 195s 3ms/sample - loss: 0.1797 - accuracy: 0.9340 - val_loss: 0.1879 - val_accuracy: 0.9324Epoch 22/2560000/60000 [==============================] - 194s 3ms/sample - loss: 0.1814 - accuracy: 0.9342 - val_loss: 0.1901 - val_accuracy: 0.9313Epoch 23/2560000/60000 [==============================] - 193s 3ms/sample - loss: 0.1766 - accuracy: 0.9351 - val_loss: 0.1866 - val_accuracy: 0.9320Epoch 24/2560000/60000 [==============================] - 193s 3ms/sample - loss: 0.1770 - accuracy: 0.9347 - val_loss: 0.1845 - val_accuracy: 0.9337Epoch 25/2560000/60000 [==============================] - 194s 3ms/sample - loss: 0.1734 - accuracy: 0.9372 - val_loss: 0.1871 - val_accuracy: 0.9312[INFO] evaluating network...precision    recall  f1-score   support​top       0.87      0.91      0.89      1000trouser       1.00      0.99      0.99      1000pullover       0.91      0.91      0.91      1000dress       0.93      0.93      0.93      1000coat       0.87      0.93      0.90      1000sandal       0.98      0.98      0.98      1000shirt       0.83      0.74      0.78      1000sneaker       0.95      0.98      0.97      1000bag       0.99      0.99      0.99      1000ankle boot       0.99      0.95      0.97      1000​accuracy                           0.93     10000macro avg       0.93      0.93      0.93     10000weighted avg       0.93      0.93      0.93     10000​[INFO] serializing training history...

检查工作目录的内容,您应该有一个名为training.pickle的文件-该文件包含我们的训练历史日志。

  $ ls *.pickletraining.pickle

在下一节中,我们将学习如何绘制这些值并将训练信息向左移动半个epoch,从而使我们的训练/验证loss曲线看起来更加相似。

平移我们的训练loss值

我们的plot_shift.py脚本用于绘制来自fashion_mnist.py的训练历史记录。 使用此脚本,我们可以研究将训练损失向左移动半个世纪如何使我们的训练/验证图看起来更相似。

打开plot_shift.py文件并插入以下代码:

  # import the necessary packagesimport matplotlib.pyplot as pltimport numpy as npimport argparseimport pickle# construct the argument parser and parse the argumentsap = argparse.ArgumentParser()ap.add_argument("-i", "--input", required=True,help="path to input training history file")args = vars(ap.parse_args())

第2-5行导入matplotlib(用于绘制),NumPy(用于简单的数组创建操作),argparse(命令行参数)和pickle(加载我们的序列化训练历史记录)。

第8-11行解析--input命令行参数,该参数指向磁盘上的.pickle训练历史记录文件。

让我们继续加载数据并初始化绘图:

  # load the training historyH = pickle.loads(open(args["input"], "rb").read())# determine the total number of epochs used for training, then# initialize the figureepochs = np.arange(0, len(H["loss"]))plt.style.use("ggplot")(fig, axs) = plt.subplots(2, 1)

第2行使用--input命令行参数加载序列化的训练历史记录.pickle文件。

第6行为我们的x轴腾出了空间,该空间从零到训练历史中的epoch数。

第7行和第8行将我们的绘图图设置为同一图像中的两个堆叠绘图:

  • top plot将按原样包含loss曲线。
  • 另一方面,bottom plot将包括训练loss(但不包括验证loss)的偏移。 训练loss将按照Aurélien的推文向左移动半个epoch。 然后,我们将能够观察绘图线的排列是否更加紧密。

让我们生成top plot

  # plot the *unshifted* training and validation lossplt.style.use("ggplot")axs[0].plot(epochs, H["loss"], label="train_loss")axs[0].plot(epochs, H["val_loss"], label="val_loss")axs[0].set_title("Unshifted Loss Plot")axs[0].set_xlabel("Epoch #")axs[0].set_ylabel("Loss")axs[0].legend()

然后绘制bottom plot

  # plot the *shifted* training and validation lossaxs[1].plot(epochs - 0.5, H["loss"], label="train_loss")axs[1].plot(epochs, H["val_loss"], label="val_loss")axs[1].set_title("Shifted Loss Plot")axs[1].set_xlabel("Epoch #")axs[1].set_ylabel("Loss")axs[1].legend()# show the plotsplt.tight_layout()plt.show()

请注意,在第2行上,训练损失向左移动了0.5个epoch,即本例的核心。

现在,让我们分析我们的训练/验证图。

打开一个终端并执行以下命令:

  python plot_shift.py --input training.pickle

[4] 将训练损失图向左移动1/2个epoch,可以得到更多类似的图。 显然,测量时间回答了一个问题:“为什么我的验证loss低于训练loss?”。

如您所见,将训练loss值向左(底部)移动一个半个epoch,使训练/验证曲线与未移动(顶部)图更加相似。

原因#3:验证集可能比训练集更容易(否则可能会泄漏(leaks))

[5] 考虑如何获取/生成验证集。 常见的错误可能导致验证loss少于训练loss。

验证loss低于训练loss的最终最常见原因是由于数据本身分布的问题。

考虑如何获取验证集:

  • 您可以保证验证集是从与训练集相同的分布中采样的吗?
  • 您确定验证示例与您的训练图像一样具有挑战性吗?
  • 您是否可以确保没有“数据泄漏”(即训练样本与验证/测试样本意外混入)?
  • 您是否确信自己的代码正确创建了训练集,验证集和测试集?

每位深度学习从业者在其职业中都至少犯过一次以上错误。

是的,它确实会令人尴尬-但这很重要-确实会发生,所以现在就花点时间研究您的代码。

BONUS: Are you training hard enough?

[6] 如果您想知道为什么验证损失低于训练loss,也许您没有“足够努力地训练”。

Aurélien在推文中没有提及的一个方面是“足够努力地训练(training hard enough)”的概念。

在训练深度神经网络时,我们最大的担心几乎总是过拟合——为了避免过拟合,我们引入了正则化技术(在上面的原因1中进行了讨论)。我们用以下形式应用正则化:

  • Dropout
  • L2权重衰减
  • 减少模型容量(即更浅的模型)

我们的学习率也趋于保守一些,以确保我们的模型不会在亏损形势下超越亏损较低的领域。

一切都很好,但是有时候我们最终会过度规范我们的模型 (over-regularizing our models)

如果您经历了验证loss低于上述详细说明的训练loss的所有三个原因,则可能是您的模型over-regularized了。通过以下方法开始放宽正则化约束:

  • 降低L2权重衰减强度。
  • 减少申请的dropout数量。
  • 增加模型容量(即,使其更深)。

您还应该尝试以更高的学习率进行训练,因为您可能对此过于保守。

总结

今天的教程深受作者AurélienGeron的以下推文启发。

在线程中,Aurélien简洁明了地解释了训练深度神经网络时验证损失可能低于训练损失的三个原因:

  1. 原因1:在训练期间应用正则化,但在验证/测试期间未进行正则化。如果在验证/测试期间添加正则化损失,则损失值和曲线将看起来更加相似。
  2. 原因2:训练损失是在每个epoch期间测量的,而验证损失是在每个epoch后测量的。平均而言,训练损失的测量时间是前一个时期的1/2。如果将训练损失曲线向左移动半个epoch,则损失会更好。
  3. 原因3:您的验证集可能比训练集更容易,或者代码中的数据/错误泄漏。确保您的验证集大小合理,并且是从与您的训练集相同的分布(和难度)中抽取的。
  4. 奖励:您的模型可能over-regularizing 。尝试减少正则化约束,包括增加模型容量(即通过更多参数使其更深),减少dropout,降低L2权重衰减强度等。

希望这有助于消除对为什么您的验证损失可能低于培训损失的困惑!

当我刚开始研究机器学习和神经网络时,对我来说无疑是一个摇头丸,直到中级大学才使我确切地了解了发生这种情况的原因——当时的解释都没有Aurélien的清楚和简洁。

英文原文链接:https://www.pyimagesearch.com/2019/10/14/why-is-my-validation-loss-lower-than-my-training-loss/

翻译和整理不易,希望大家能用你们发财的小手,点个赞支持哈~

关注 搜罗最好玩的计算机视觉论文和应用,AI算法与图像处理 微信公众号,获得第一手计算机视觉相关信息

坚持,不断学习进步才能不被生活打垮~

深度神经网络训练过程中为什么验证集上波动很大_一个值得深思的问题?为什么验证集的loss会小于训练集的loss...相关推荐

  1. 深度神经网络训练过程中为什么验证集上波动很大_图神经网络的新基准

    作者 | 李光明 编辑 | 贾 伟 编者注:本文解读论文与我们曾发文章<Bengio 团队力作:GNN 对比基准横空出世,图神经网络的「ImageNet」来了>所解读论文,为同一篇,不同作 ...

  2. 训练softmax分类器实例_一个值得深思的问题?为什么验证集的loss会小于训练集的loss...

    编辑:zero 关注 搜罗最好玩的计算机视觉论文和应用,AI算法与图像处理 微信公众号,获得第一手计算机视觉相关信息 在本教程中,您将学习在训练自己的自定义深度神经网络时,验证损失可能低于训练损失的三 ...

  3. 训练集山准确率高测试集上准确率很低_拒绝DNN过拟合,谷歌准确预测训练集与测试集泛化差异,还开源了数据集 | ICLR 2019...

    鱼羊 发自 凹非寺 量子位 报道 | 公众号 QbitAI 深度神经网络(DNN)如今已经无处不在,从下围棋到打星际,DNN已经渗透到图像识别.图像分割.机器翻译等各种领域,并且总是表现惊艳. 然而, ...

  4. 训练集山准确率高测试集上准确率很低_推荐算法改版前的AB测试

    编辑导语:所谓推荐算法就是利用用户的一些行为,通过一些数学算法,推测出用户可能喜欢的东西:如今很多软件都有这样的操作,对于此系统的设计也会进行测试:本文作者分享了关于推荐算法改版前的AB测试,我们一起 ...

  5. 分页携带请求参数_一个值得深思的小问题 请求中的参数值为空要不要携带该参数?...

    最近一个朋友疯狂的和我吐槽公司的后端,说很常规.很普通的一个事儿,也就是验证一下子的事儿,非要搞的那么复杂,治标不治本,技术玩来玩去不但没进步还倒退了. 这是怎么回事呢?咱们就来聊聊这件"小 ...

  6. 神经网络测试集loss不变_神经网络训练过程中不收敛或者训练失败的原因

    在面对模型不收敛的时候,首先要保证训练的次数够多.在训练过程中,loss并不是一直在下降,准确率一直在提升的,会有一些震荡存在.只要总体趋势是在收敛就行.若训练次数够多(一般上千次,上万次,或者几十个 ...

  7. 在Caffe的训练过程中打印验证集的预测结果

    起因:Caffe里的GoogLeNet Inception V1只能输出对应于三个loss的accuracy,我想计算precision,recall和F1-measure.但是调用caffe的Pyt ...

  8. 神经网络训练过程中出现loss为nan,神经元坏死

    最近在手撸Tensorflow2版本的Faster RCNN模型,稍后会进行整理.但在准备好了模型和训练数据之后的训练环节中出现了大岔子,即训练过程中loss变为nan.nan表示not a numb ...

  9. 机器深度学习的过程中盛传着7 个误解,我们来一一揭开

    https://www.toutiao.com/a6690402605824213508/ 2019-05-13 14:59:45 哥伦比亚大学计算机科学专业博士生Oscar Chang发博阐述了关於 ...

  10. 一个值得深思的问题?为什么验证集的loss会小于训练集的loss

    在本教程中,您将学习在训练自己的自定义深度神经网络时,验证损失可能低于训练损失的三个主要原因. 我的验证损失低于训练损失! 怎么可能呢? 我是否意外地将训练和验证loss绘图的标签切换了? 潜在地. ...

最新文章

  1. 皮一皮:这样的领导还有吗
  2. vlc-android配置实录
  3. SpringMVC源码解析与思考
  4. 于金刚消息引擎服务器,基于MQTT的安全通信服务器的研究与实现
  5. Windows 11 dapr 环境安装
  6. 常用正则表达式整理【总结】
  7. Linux中的shell正则表达式详解
  8. eslint 设置目录_Nuxt项目添加自定义ESLint规则
  9. HttpClient-Java-发送HTTP请求
  10. Vi 编辑器常用命令
  11. 数据挖掘实战 —— 泰坦尼克号
  12. 华为手机备份的通讯录是什么文件_华为手机的联系人在哪个文件夹里?
  13. docker deamon源码学习
  14. jar文件打不开,用什么打开
  15. 计算机语言可读性排名,计算机语言可读性强,容易记忆
  16. echarts饼图自动动画_echarts实时旋转饼图效果特效
  17. Unity 3D模型展示框架篇之自由观察(Cinemachine)
  18. 后现代婚礼机器人显神通_看机器人“各显神通”
  19. 华为立 Flag:一年超越三星做全球智能手机老大!
  20. 系统测试分析系统测试设计

热门文章

  1. JAVA中反射机制五(JavaBean的内省与BeanUtils库)
  2. JavaScript实现对象的深度克隆及typeof和instanceof【简洁】【分享】
  3. modelsim+win环境下systemverilog调用c函数
  4. eclipse import的项目报autowired cannot be resolved to a type的错误
  5. CCOMBOX下拉弹出框,因属性对话框自动隐藏而弹出框没有隐藏问题
  6. 首次体验 Live Writter
  7. [原]ActiveReport6 for net使用(一)
  8. RIP路由六大防环机制
  9. HCIE-RS-TAC-01-AR29的loopback0无法访问AR28的loopback
  10. IPv6 gre隧道、路由协议综合实验(华为设备)