使用提前停止在正确的时间停止神经网络的训练

训练神经网络的一个问题在于选择要使用的训练周期数

过多的周期可能导致训练数据集过拟合,而过少则可能导致模型欠拟合。提前停止是一种方法,它允许您指定任意大量的训练周期,并在模型在保留的验证数据集上性能停止提升时停止训练。

在本教程中,您将学习Keras API,用于向过拟合的深度学习神经网络模型添加提前停止功能。

完成本教程后,您将了解:

  • 如何使用Keras API在训练期间监控模型的性能。
  • 如何使用Keras API创建和配置提前停止和模型检查点回调。
  • 如何通过向现有模型添加提前停止来减少过拟合。

用我的新书《更好的深度学习》来启动你的项目,书中包含分步教程和所有示例的 Python 源代码文件

让我们开始吧。

  • 2019 年 10 月更新:更新至 Keras 2.3 和 TensorFlow 2.0。
How to Stop Training Deep Neural Networks At the Right Time With Using Early Stopping

如何使用提前停止在正确的时间停止深度神经网络的训练
图片由Ian D. Keating提供,部分权利保留。

教程概述

本教程分为六个部分;它们是:

  1. 在Keras中使用回调
  2. 评估验证数据集
  3. 监控模型性能
  4. Keras中的提前停止
  5. Keras中的检查点
  6. 提前停止案例研究

在Keras中使用回调

回调提供了一种自动执行代码并与训练模型过程交互的方式。

可以通过“callbacks”参数将回调提供给fit()函数。

首先,必须实例化回调。

然后,您打算使用的一个或多个回调必须添加到Python列表中。

最后,在拟合模型时,将回调列表提供给回调参数。

在Keras中评估验证数据集

提前停止要求在训练期间评估验证数据集。

这可以通过在训练模型时向fit()函数指定验证数据集来实现。

有两种方法可以做到这一点。

第一种方法是您手动将训练数据拆分为训练集和验证集,并通过validation_data参数将验证数据集指定给fit()函数。例如:

或者,fit()函数可以根据通过validation_split参数指定的百分比拆分,自动将您的训练数据集拆分为训练集和验证集。

validation_split是一个介于0和1之间的值,定义用于验证数据集的训练数据集的百分比。例如:

在这两种情况下,模型都不会在验证数据集上进行训练。相反,模型会在每个训练周期结束时在验证数据集上进行评估。

想要通过深度学习获得更好的结果吗?

立即参加我为期7天的免费电子邮件速成课程(附示例代码)。

点击注册,同时获得该课程的免费PDF电子书版本。

监控模型性能

在每个周期结束时,都会计算为您模型选择的损失函数

对于回调,这通过名称“loss”提供。

如果通过validation_datavalidation_split参数向fit()函数指定了验证数据集,则验证数据集上的损失将通过名称“val_loss”提供。

在模型训练期间可以监控其他指标。

它们可以在编译模型时通过编译函数的“metrics”参数指定。此参数接受一个已知指标函数的Python列表,例如用于均方误差的“mse”和用于准确度的“accuracy”。例如:

如果在训练期间监控其他指标,它们也通过相同的名称提供给回调,例如训练数据集上的准确度为“accuracy”,验证数据集上的准确度为“val_accuracy”。或者,训练数据集上的均方误差为“mse”,验证数据集上的均方误差为“val_mse”。

Keras中的提前停止

Keras通过名为EarlyStopping的回调支持提前停止训练。

此回调允许您指定要监控的性能度量、触发器,一旦触发,它将停止训练过程。

EarlyStopping回调在实例化时通过参数进行配置。

monitor”允许您指定要监控的性能度量以结束训练。回想一下上一节,验证数据集上度量的计算将带有“val_”前缀,例如验证数据集上的损失为“val_loss”。

根据性能度量的选择,需要指定“mode”参数,以指示所选指标的目标是增加(最大化或“max”)还是减少(最小化或“min”)。

例如,我们寻求验证损失和验证均方误差的最小值,而寻求验证准确度的最大值。

默认情况下,mode设置为“auto”,并知道您希望最小化损失或最大化准确度。

这就是最简单的提前停止形式所需的全部。当所选性能度量停止改进时,训练将停止。要发现停止训练的训练周期,可以将“verbose”参数设置为1。一旦停止,回调将打印周期数。

通常,没有进一步改进的第一个迹象可能不是停止训练的最佳时机。这是因为模型可能会进入一个没有改进的平台,甚至在变得更好之前会稍微变差。

我们可以通过在触发器中添加一个延迟来解决这个问题,延迟的时间是我们希望看到没有改进的周期数。这可以通过设置“patience”参数来实现。

确切的耐心程度会因模型和问题而异。查看您的性能度量图对于了解您的模型在您的数据上的优化过程可能有多大的噪声非常有用。

默认情况下,性能度量的任何变化,无论多么微小,都将被视为改进。您可能希望将改进视为一个特定的增量,例如均方误差的1个单位或准确度的1%。这可以通过“min_delta”参数指定。

最后,如果性能保持在给定阈值或基线之上或之下,则可能需要停止训练。例如,如果您熟悉模型的训练(例如学习曲线),并且知道一旦达到给定值的验证损失,就没有必要继续训练。这可以通过设置“baseline”参数来指定。

这在微调模型时可能更有用,即在训练新模型的早期阶段观察到的性能度量的初始剧烈波动过去之后。

Keras中的检查点

一旦触发,EarlyStopping回调将停止训练,但训练结束时的模型可能不是在验证数据集上表现最佳的模型。

需要一个额外的回调,它将保存训练期间观察到的最佳模型以供以后使用。这就是ModelCheckpoint回调。

ModelCheckpoint回调在使用方式上非常灵活,但在本例中,我们将仅使用它来保存训练期间观察到的最佳模型,该模型由验证数据集上选定的性能度量定义。

保存和加载模型需要您的工作站已安装HDF5支持。例如,使用pip Python安装程序,这可以如下实现:

您可以从h5py安装文档中了解更多信息。

回调会将模型保存到文件,这需要通过第一个参数指定路径和文件名。

首选要监控的损失函数可以通过monitor参数指定,其方式与EarlyStopping回调相同。例如,验证数据集上的损失(默认)。

此外,与EarlyStopping回调一样,我们必须将“mode”指定为最小化或最大化性能度量。同样,默认值为“auto”,它知道标准性能度量。

最后,我们只对训练期间观察到的最佳模型感兴趣,而不是与前一个周期相比的最佳模型,因为如果训练有噪声,它可能不是整体最佳模型。这可以通过将“save_best_only”参数设置为True来实现。

这就是确保在使用提前停止或通常情况下保存最佳性能模型所需的全部。

了解性能度量的值以及模型保存的周期可能很有趣。这可以通过将“verbose”参数设置为“1”来由回调打印。

然后可以通过调用load_model()函数随时加载和评估保存的模型。

现在我们知道如何使用提前停止和模型检查点API,让我们看一个实际的例子。

提前停止案例研究

在本节中,我们将演示如何使用提前停止来减少MLP在简单二分类问题上的过拟合

此示例提供了一个模板,用于将提前停止应用于您自己的神经网络以解决分类和回归问题。

二分类问题

我们将使用一个标准的二分类问题,它定义了两个半圆的观测值,每个类别一个半圆。

每个观测值都有两个具有相同尺度的输入变量和一个类别输出值0或1。这个数据集被称为“moons”数据集,因为绘制时每个类别中的观测值的形状。

我们可以使用make_moons()函数从这个问题生成观测值。我们将向数据中添加噪声并设置随机数生成器的种子,以便每次运行代码时都生成相同的样本。

我们可以绘制数据集,其中两个变量作为图上的x和y坐标,类别值作为观测值的颜色。

生成数据集并绘制它的完整示例如下所示。

运行示例将创建一个散点图,显示每个类别中观测值的半圆或月牙形。我们可以看到点分散中的噪声使得月牙形不那么明显。

Scatter Plot of Moons Dataset With Color Showing the Class Value of Each Sample

月牙形数据集的散点图,点颜色显示每个样本的类别值

这是一个很好的测试问题,因为这些类别不能用一条线分开,例如,它们不是线性可分的,需要一种非线性方法(如神经网络)来解决。

我们只生成了100个样本,这对于神经网络来说太少了,这提供了过拟合训练数据集并在测试数据集上产生更高误差的机会:这是使用正则化的一个很好的例子。此外,样本带有噪声,这使得模型有机会学习样本中不能泛化的方面。

过拟合多层感知器

我们可以开发一个MLP模型来解决这个二分类问题。

该模型将有一个隐藏层,其节点数可能超过解决此问题所需的数量,从而提供过拟合的机会。我们还将训练模型的时间延长到超过所需时间,以确保模型过拟合。

在定义模型之前,我们将数据集拆分为训练集和测试集,使用30个示例来训练模型,70个示例来评估拟合模型的性能。

接下来,我们可以定义模型。

隐藏层使用500个节点和ReLU激活函数。输出层使用Sigmoid激活函数以预测0或1的类别值。模型使用二元交叉熵损失函数进行优化,适用于二分类问题和高效的Adam梯度下降算法

然后,将定义的模型在训练数据上拟合4,000个周期,并使用默认的批量大小32。

我们还将测试数据集用作验证数据集。这只是本示例的简化。实际上,您会将训练集拆分为训练集和验证集,并保留一个测试集用于最终模型评估。

我们可以评估模型在测试数据集上的性能并报告结果。

最后,我们将绘制模型在每个周期的训练集和测试集上的损失。

如果模型确实过拟合了训练数据集,我们预计训练集上的损失(和准确度)线图会持续增加,而测试集上的损失会先上升然后再次下降,因为模型学习了训练数据集中的统计噪声。

我们可以将所有这些部分结合起来;完整的示例如下所示。

运行示例会报告模型在训练数据集和测试数据集上的性能。

我们可以看到模型在训练数据集上的性能优于测试数据集,这可能是过拟合的一个迹象。

注意:由于算法或评估过程的随机性,或者数值精度的差异,您的结果可能会有所不同。考虑多次运行示例并比较平均结果。

因为模型严重过拟合,我们通常不期望在相同数据集上重复运行模型时,准确性会有很大(如果有的话)差异。

生成一个图,显示模型在训练集和测试集上的损失线图。

我们可以看到一个过拟合模型的预期形状,其中测试准确度会增加到一个点,然后再次开始下降。

回顾图表,我们还可以看到验证损失的起伏中存在平坦区域。任何提前停止都必须考虑这些行为。我们还预计,大约在第800个周期停止训练可能是个好时机。

Line Plots of Loss on Train and Test Datasets While Training Showing an Overfit Model

训练期间损失在训练集和测试集上的线图显示过拟合模型

带有提前停止的过拟合多层感知器

我们可以更新示例并添加非常简单的提前停止功能。

一旦模型在测试数据集上的损失开始增加,我们将停止训练。

首先,我们可以定义提前停止回调。

然后我们可以更新对fit()函数的调用,并通过“callback”参数指定回调列表。

添加了简单提前停止功能的完整示例如下所示。

运行示例会报告模型在训练数据集和测试数据集上的性能。

注意:由于算法或评估过程的随机性,或者数值精度的差异,您的结果可能会有所不同。考虑多次运行示例并比较平均结果。

我们还可以看到回调在第200个周期停止了训练。这太早了,因为我们期望提前停止大约在第800个周期。训练集和测试集上的分类准确率也证明了这一点,它比没有提前停止时更差。

回顾训练和测试损失的线图,我们确实可以看到训练在验证损失首次趋于平稳时停止了。

Line Plot of Train and Test Loss During Training With Simple Early Stopping

使用简单提前停止的训练期间训练和测试损失的线图

我们可以通过等待一段时间再停止来改善提前停止的触发机制。

这可以通过设置“patience”参数来实现。

在这种情况下,我们将等待200个周期才停止训练。具体来说,这意味着我们允许训练在验证损失开始下降之后再继续最多200个周期,从而为训练过程提供机会越过平稳期或找到一些额外的改进。

进行了此更改的完整示例如下所示。

运行示例,我们可以看到训练停止得晚得多,在这种情况下是在第1000个周期之后。

注意:由于算法或评估过程的随机性,或者数值精度的差异,您的结果可能会有所不同。考虑多次运行示例并比较平均结果。

我们还可以看到测试数据集上的性能优于不使用任何提前停止。

回顾训练期间的损失线图,我们可以看到耐心允许训练越过一些小的平坦和不佳区域。

Line Plot of Train and Test Loss During Training With Patient Early Stopping

使用耐心提前停止的训练期间训练和测试损失的线图

我们还可以看到,在最后大约100个周期中,测试损失再次开始增加。

这意味着,尽管模型的性能有所提高,但在训练结束时,我们可能没有性能最好或最稳定的模型。我们可以通过使用ModelCheckpoint回调来解决这个问题。

在这种情况下,我们对在测试数据集上具有最佳准确度的模型感兴趣。我们也可以寻找在测试数据集上具有最佳损失的模型,但这可能不一定与具有最佳准确度的模型相对应。

这强调了模型选择中的一个重要概念。在训练期间,“最佳”模型的概念在评估使用不同性能度量时可能会发生冲突。尝试根据在领域中评估和呈现它们的指标来选择模型。在平衡的二分类问题中,这很可能是分类准确度。因此,我们将在ModelCheckpoint回调中使用验证集上的准确度来保存训练期间观察到的最佳模型。

在训练期间,只有当验证数据集上的准确度在整个训练过程中整体提高时,整个模型才会保存到文件“best_model.h5”。详细输出还将告知我们每次模型保存到同一文件(即被覆盖)时的周期和准确度值。

在调用fit()函数时,可以将此新添加的回调添加到回调列表中。

我们不再对训练期间损失的线图感兴趣;它将与之前的运行大致相同。

相反,我们希望从文件中加载保存的模型并评估其在测试数据集上的性能。

进行了这些更改的完整示例如下所示。

运行示例,我们可以看到来自ModelCheckpoint回调的详细输出,用于保存新的最佳模型和未观察到改进时的情况。

我们可以看到在此运行期间,最佳模型是在第879个周期观察到的。

注意:由于算法或评估过程的随机性,或者数值精度的差异,您的结果可能会有所不同。考虑多次运行示例并比较平均结果。

再次,我们可以看到提前停止耐心持续到第1000个周期之后。请注意,第880个周期加上200个耐心并非第1044个周期。回想一下,提前停止正在监控验证数据集上的损失,而模型检查点正在根据准确度保存模型。因此,提前停止的耐心从第880个周期以外的某个周期开始。

在这种情况下,我们没有看到模型在测试数据集上的准确度有进一步的改进。尽管如此,我们遵循了良好的实践。

为什么不监控验证准确度进行提前停止?

这是一个很好的问题。主要原因是,准确度是训练期间模型性能的粗略度量,而损失在分类问题中使用提前停止时提供了更多的细微差别。在回归情况下,例如均方误差,提前停止和模型检查点可以使用相同的度量。

扩展

本节列出了一些您可能希望探索的扩展本教程的想法。

  • 使用准确率。更新示例以监控测试数据集上的准确率而不是损失,并绘制显示准确率的学习曲线。
  • 使用真实的验证集。更新示例以将训练集拆分为训练集和验证集,然后评估测试数据集上的模型。
  • 回归示例。创建一个新示例,演示如何使用提前停止来解决简单回归问题中的过拟合,并监控均方误差。

如果您探索了这些扩展中的任何一个,我很想知道。

进一步阅读

如果您想深入了解,本节提供了更多关于该主题的资源。

文章

API

总结

在本教程中,您学习了Keras API,用于向过拟合的深度学习神经网络模型添加提前停止功能。

具体来说,你学到了:

  • 如何使用Keras API在训练期间监控模型的性能。
  • 如何使用Keras API创建和配置提前停止和模型检查点回调。
  • 如何通过向现有模型添加提前停止来减少过拟合。

你有什么问题吗?
在下面的评论中提出你的问题,我会尽力回答。

今天就开发更好的深度学习模型!

Better Deep Learning

更快地训练,减少过拟合,以及集成方法

...只需几行python代码

在我的新电子书中探索如何实现
更好的深度学习

它提供关于以下主题的自学教程
权重衰减批量归一化dropout模型堆叠等等...

为你的项目带来更好的深度学习!

跳过学术理论。只看结果。

查看内容

《使用提前停止在正确的时间停止神经网络的训练》的121条评论

  1. Walid Ahmed 2018年12月12日上午7:07 #

    非常感谢,一如既往的清晰说明

  2. Theekshana 2018年12月21日下午5:54 #

    嗨,Jason,

    提前停止这个过程是否应该在我们选择了合适的神经网络架构(也许使用了不同架构的交叉验证分数)之后进行?

    感谢您的教程。这个网站的忠实粉丝 🙂

    • Jason Brownlee 2018年12月22日上午6:02 #

      也许,你可以从一个过度指定的架构开始,使用权重衰减并立即使用提前停止。

  3. Khalil 2019年1月16日上午12:46 #

    哇,这篇关于回调的解释非常集中和清晰。谢谢你,Jason!

  4. Daniel Penalva 2019年2月20日上午2:39 #

    嗨,Jason,这是一篇精彩的文章。祝贺你。

    还在阅读中,有很多东西要学习。

    去年11月,我在你的另一篇关于检查点的文章中发帖,我当时(现在仍然)的主要目标是使用检查点进行超参数优化。

    你认为提前停止方法可以通过停止->重新加载->编译->继续训练->超参数更改->停止->如此循环来达到这个目的吗?

    ??

    先谢谢您了。

    • Jason Brownlee 2019年2月20日上午8:10 #

      我通常不建议将提前停止与超参数调整一起使用,这会使过程变得混乱。

      调整参数,然后在最后将提前停止作为正则化方法添加——这是我最好的建议。

      • Daniel Penalva 2019年2月21日上午2:57 #

        但是,使用提前停止,不就是检查点/重新加载/重新编译和运行吗?

        我的观点是:我希望能够重新加载相同的模型并继续训练直到损失最小,并且更改模型超参数(架构、批量大小、周期数)并用与以前相同的数据分割(或相同的数据集,如果我被迫因批量大小不同而更改分割)重新训练它。

        关键可能在于:Keras中除了sklearn的超参数调优(与Keras检查点不太兼容)之外,还有其他代理吗?

        再次感谢...

      • Deniz 2019年5月6日下午3:03 #

        那Dropout呢?权重衰减的规则也适用于Dropout吗?

  5. Fazano 2019年3月24日下午2:58 #

    嗨,Jason 先生

    我使用提前停止进行LSTM预测。当我第一次运行训练时,提前停止在第20个周期停止,当我第二次运行它时,它在第17个周期停止。每次结果都不同。你能解释一下为什么会发生这种情况吗?

    我的代码是这样的

    model = Sequential()
    model.add(LSTM(4,activation=’tanh’,input_shape=(1,3),recurrent_activation= ‘hard_sigmoid’))
    model.add(Dense(1))
    model.compile(loss=’mean_squared_error’,optimizer=’adam’,metrics = [metrics.mae])
    early_stop = EarlyStopping(monitor=’loss’, patience=2, verbose=0, mode=’min’)
    model.fit(X_train,Y_train,epochs= 100 ,batch_size= 1,verbose=2, callbacks=[early_stop])

    谢谢你

  6. KK 2019年3月27日下午2:43 #

    嗨,Jason博士,

    感谢这篇出色的文章,它帮助我理解了与深度学习相关的主题。我有一个问题。

    当我们使用ModelCheckpoint时,是只保存权重还是保存完整的模型(包括模型架构)

    每当我尝试保存模型并直接在不同程序中加载它时,它都会抛出错误(错误详情将很快发布)。
    saved_model = load_model(‘best_model.h5’)

    所以我不得不遵循以下方法
    1. 首先构建模型架构。
    2. 然后加载保存的权重(或模型,我使用的是通过ModelCheckpoint保存的.h5文件)

    这是正确的方法吗?我可以分享GitHub链接,以便您可以查看我的代码是否一切正常。

    谢谢你,
    KK

    • Jason Brownlee 2019年3月28日上午8:07 #

      我建议使用一个函数来再次创建您的模型架构,然后直接加载权重。

      • Chunhui 2019年3月29日上午3:24 #

        嗨,Jason,非常感谢您的帖子,它非常有用。但是我的模型无法使用ModelCheckPoints,错误提示损失未知,所以我猜Model Checkpoints不适用于带有自定义损失函数的模型?

        • Jason Brownlee 2019年3月29日上午8:43 #

          也许您的模型配置不正确,也许可以尝试调试故障?

      • KK 2019年4月1日下午4:25 #

        嗨,Jason,感谢您的澄清。目前我正在一个程序中完成此操作。我将编写一个单独的代码来再次创建模型架构。

  7. JStocks 2019年3月30日上午3:15 #

    谢谢你,Jason!

    我有一个问题。假设我已经通过k折交叉验证完成了完整的超参数调优,并确定了架构、参数等。我准备在外部使用最终模型。我会从其中一个折叠中选择一个训练好的模型吗?或者,你会用所有数据训练最终模型吗?通过验证集,你可以知道模型何时开始过拟合,而用所有数据训练意味着模型可以看到更多数据。

    问题是,如果你用所有数据进行训练,很难知道在哪个周期停止训练。

    你有什么建议?

    • Jason Brownlee 2019年3月30日上午6:32 #

      不,我通常建议使用最佳配置在所有可用数据上拟合一个新的最终模型。

      如果您想使用提前停止,则需要保留一些数据用于验证集。

  8. Esra Karasu 2019年5月13日下午10:10 #

    我尝试使用“load_model()”代码加载保存的模型,但我收到了这个错误

    load_model() 缺少1个必需的位置参数:'filepath'

    您能帮我解决这个错误吗?

  9. Sourav 2019年6月11日下午3:31 #

    嗨,Jason,
    我想知道是否有任何硬性规定要求使用最小化验证损失进行提前停止。比如说,我使用“验证准确度”,即如果验证准确度保持不变或开始下降,那么我就停止训练模型。您认为这种方法的优缺点是什么?

    • Jason Brownlee 2019年6月12日上午7:50 #

      通常,代表性验证数据集上的损失增加被用作停止条件。

  10. hayj 2019年6月14日下午8:01 #

    你好,Jason,我不明白如果提前停止的耐心设置为4(例如),它是否会在val_loss_i > val_loss_i -1 > val_loss_i -2 > val_loss_i -3(损失连续增加)时停止训练
    或者它是否会在val_loss_i > min_overall_val_loss & val_loss_i-1 > min_overall_val_loss & val_loss_i-2 > min_overall_val_loss & val_loss_i-3 > min_overall_val_loss(一个独立于整体最小损失表现不佳的序列)时停止训练

    • Jason Brownlee 2019年6月15日上午6:32 #

      抱歉,我没跟上。你具体遇到了什么问题?

      • hayj 2019年6月18日上午5:40 #

        抱歉,我解释得更清楚一些:提前停止机制是否考虑了(所有先前周期中)的总体最小损失?或者仅仅考虑当前损失直到当前周期减去耐心值时的损失?

  11. SSN 2019年6月20日下午2:36 #

    你好 Jason,

    感谢您所有精彩的笔记。我有一个关于训练测试数据拆分的问题。我想使用训练、测试和验证数据集。我还想为每个周期对训练和测试数据集进行随机拆分。这在Keras中可能吗?

    • SSN 2019年6月20日下午4:11 #

      或者简单地说,我能这样做吗?
      1. 将数据拆分为训练集和测试集
      2. 将训练数据拆分为训练集和验证集。(所以最终我有三个集合,测试集留到最后使用)
      3. 现在使用训练数据拟合模型,使用验证数据进行预测并获得模型准确率
      4. 如果模型准确率低于某个所需数字,则返回步骤3并重新洗牌并获取新的随机训练和验证数据集组合。使用之前的模型和权重,在此状态基础上进行改进或增加权重
      5. 持续执行此操作直到验证达到令人满意的准确率
      6. 然后使用测试数据获取最终准确率

      我的主要问题是,这是一种有效的方法吗?以及当我再次使用fit()时,权重是否会保存下来,我的意思是每次我使用fit()命令时,权重是否会从之前的现有值进行调整?

    • Jason Brownlee 2019年6月21日上午6:32 #

      是的,但是您必须手动运行训练过程,例如,每个循环并在模型上调用train_on_batch()或使用1个周期调用fit()。

      我相信我在博客上有一些例子。

      • SSN 2019年6月21日下午2:04 #

        再次感谢您,Jason。
        我在你的博客上搜索过这些问题,但没有得到直接的答案。我想你的回答帮助我找到了答案。我将实施它并看看结果如何。非常感谢你在博客上提供了大量信息。

  12. SSN 2019年6月21日下午7:27 #

    嗨,Jason,

    请检查以下脚本,看我是否遗漏了什么。

    标准化输入和输出数据,然后

    1. 初始化模型(编译)
    2. 拟合模型
    3. 保存模型
    在循环中
    4. 加载保存的模型
    5. 打乱训练集和验证集之间的数据
    6. model_int.fit(X_train, Y_train, epochs = 1,batch_size = 10, verbose = 1)
    7. model_int.save(‘intermediate_model.h5’)
    8. 使用验证X数据预测Y
    9. 比较预测的Y数据和实际的Y数据
    10. 根据步骤7的输出决定是返回步骤4还是结束。

    我遗漏了什么吗?另外,在步骤6中保存,它保存的是最后一个批次的模型还是所有批次的结果模型?或者我应该以批量大小1运行,并在每个批次之后保存并从那里重新迭代?

    • Jason Brownlee 2019年6月22日上午6:36 #

      我不太明白,你为什么要先拟合再拟合一次?

  13. SSN 2019年6月24日下午2:09 #

    我用不同的训练集和验证集来拟合它。我将一部分数据留作最终测试,我称之为测试集。然后,在剩余的数据中,我没有使用相同的训练集,而是使用了不同的训练集和测试集组合,直到预测显示出良好的指标。一旦达到,我就会使用验证集来查看最终指标。

  14. Tejas 2019年6月28日下午1:14 #

    你好,
    我试图根据基线提前停止模型。我不确定我遗漏了什么,但是,使用以下命令监控验证损失不起作用。我也尝试了耐心参数,但也没有起作用。模型的初始验证损失约为21。


    model.compile(loss='categorical_crossentropy', optimizer=Adam(lr=0.000016), metrics=['accuracy'])
    es = EarlyStopping(monitor='val_loss', mode='min', baseline=0.5)
    class_weight = {0: 0.31,
    1: 0.69}
    history=model.fit(x_train, y_train, validation_data=(x_validation,y_validation),
    epochs=150, batch_size=32,class_weight=class_weight, callbacks=[es])

    模型在一个 epoch 后就停止了。我到处搜索,但找不到问题所在。如果能得到任何帮助,我将不胜感激。谢谢

    • Jason Brownlee 2019年6月28日 下午1:56 #

      我很乐意帮忙,但我没有能力调试你的示例,抱歉。

    • Christian 2019年6月30日 晚上7:43 #

      你好,Tejas,

      这可能是因为文章中对基线参数的解释不正确。与其说是模型达到该值时停止,不如说是相反:如果模型没有达到该值,它就会停止,这可以在 keras 文档中看到。我认为耐心参数控制着模型在停止之前必须达到基线的 epoch 数量。

      • Nastaran 2021年4月10日 凌晨3:30 #

        说得好!我也有同样的问题。非常感谢 Christian。

  15. Gunnar 2019年6月28日 晚上11:07 #

    亲爱的杰森。

    非常感谢你为这个页面付出的所有努力,这篇文章是我发现非常有帮助的众多文章之一。

    我在决定最终模型中应该包含多少个 epoch 时遇到了一些麻烦。在决定模型的最佳配置时,我使用了提前停止来防止模型过拟合。在创建最终模型时,我想在所有可用数据上进行训练,所以大概在生成最终模型时不能应用提前停止。

    你有什么建议可以用来决定训练最终模型时要经历的 epoch 数量吗?在我配置模型时,使用提前停止方法停止训练的 epoch 数量是否合理?

    • Jason Brownlee 2019年6月29日 早上6:55 #

      你可以使用提前停止,运行几次,记下每次停止的 epoch 数量,然后在使用所有数据拟合模型时取平均值。

  16. Shark 2019年8月3日 晚上7:00 #

    谢谢!这篇文章真的很有帮助!

  17. michelle 2019年10月19日 凌晨3:27 #

    嗨,Jason,

    非常感谢您的精彩解释!

    在二分类的情况下,我有时会遇到验证损失开始增加而验证准确率仍在提高(测试准确率也在提高)的情况。我认为这是因为模型在预测标签方面仍在改进,尽管实际损失值越来越大。

    我可以使用验证准确率更高(测试准确率也更好)但验证损失更大的模型吗?既然我们的最终目标是更好地预测标签,为什么我们要关心损失的增加呢?

    • Jason Brownlee 2019年10月19日 早上6:49 #

      当然可以。

      但也许需要测试以确保结果的稳健性。验证损失上升可能意味着模型不稳定。

  18. David 2019年10月20日 凌晨2:44 #

    感谢这篇文章。当在 Earlystopping 参数中使用 val_acc 时,它理论上会保存一个模型,该模型对应于最高验证准确率的 epoch。然而,当我使用该模型针对我的验证集进行预测以进行检查时,准确率不一致。我的模型架构在 NasNet 上使用了迁移学习。

    你知道为什么会这样吗?

    • Jason Brownlee 2019年10月20日 早上6:21 #

      在提前停止期间计算的 val 准确率可能是批次上的平均值——它是一个估计值。

      也许可以尝试多次运行提前停止,并对最终模型的集合进行集成以减少其性能的方差?

  19. Aditya 2019年12月6日 下午5:35 #

    model = Sequential()
    model.add(LSTM(neurons, batch_input_shape=(batch_size, X_train.shape[1], X_train.shape[2]), activation='relu'))
    model.add(Dense(1))
    model.compile(loss='mean_squared_error', optimizer='adam')

    global_trial = global_trial[0] + 1
    model_path = "../deeplearning/saved_models_2/" + str(name) + "/" + str(global_trial) + "_" + "model.h5"

    # 简单的提前停止
    es = EarlyStopping(monitor='val_loss', mode='min', verbose=1, patience=50)
    mc = ModelCheckpoint(model_path, monitor='val_loss', mode='min', verbose=1, save_best_only=True)

    # 拟合模型
    history = model.fit(X_train, y_train, validation_data=(X_test, y_test), epochs=nb_epochs, batch_size=1, verbose=0,
    callbacks=[es, mc])

    # 加载保存的模型
    saved_model = load_model(model_path)

    # 评估模型
    _, train_loss = saved_model.evaluate(X_train, y_train, verbose=0)
    _, test_loss = saved_model.evaluate(X_test, y_test, verbose=0)
    print('Train: %.3f, Test: %.3f' % (train_loss, test_loss))

    错误 = tensorflow.python.framework.errors_impl.InvalidArgumentError: 指定的列表形状为 [1,1],而张量的形状为 [32,1]

    当我使用相同的训练和测试数据进行评估时。

    • Jason Brownlee 2019年12月7日 早上5:35 #

      错误表明数据的形状与模型预期的形状不匹配。

  20. Mark Ryan 2019年12月9日 早上6:15 #

    很棒的文章——非常清晰,简洁的示例易于理解。非常感谢分享。

  21. Murilo Souza 2020年1月27日 晚上9:34 #

    又是一篇很棒的文章!感谢 Jason 提供的信息!

    我在你的网站上学到的比我在课堂上和教授们学到的还要多,哈哈。如果你还没成为教授,我敢打赌你一定会是一位很棒的教授!

  22. farukgogh 2020年2月5日 凌晨4:24 #

    嗨 Jason,在使用 model.fit_generator 时如何可视化图表?我将如何使用 history 来可视化图表?例如

    model.fit_generator(
    train_generator,
    steps_per_epoch=… ,
    epochs=….,
    validation_data=validation_generator,
    validation_steps= …)

    • Jason Brownlee 2020年2月5日 早上8:20 #

      你可能需要将历史记录保存或记录到文件中。

      • farukgogh 2020年2月6日 凌晨2:51 #

        能详细解释一下吗?

        • Jason Brownlee 2020年2月6日 早上8:32 #

          当然,你可以设置一个回调函数,然后将损失分数追加到文件中。

          这是一个工程问题,有许多解决方案。也许可以原型化一些,看看哪个有效。

  23. James McGuigan 2020年3月7日 早上6:58 #

    值得注意的是,作为 ModelCheckpointing 的替代方案,有一个 restore_best_weights 参数

    tf.keras.callbacks.EarlyStopping( restore_best_weights=True )

    restore_best_weights: 是否从监控指标值最佳的 epoch 恢复模型权重。如果为 False,则使用训练最后一步获得的模型权重。

    https://tensorflowcn.cn/api_docs/python/tf/keras/callbacks/EarlyStopping

    • Jason Brownlee 2020年3月7日 早上7:23 #

      谢谢,看起来是新的,而且是 tf.keras。

    • abq 2020年6月5日 凌晨4:20 #

      只是想让您知道,在 EarlyStopping 中使用 restore_best_weights 选项时存在一个问题,即训练不是由触发器停止,而是由总 epoch 数停止。

      详细信息在此处报告:
      https://github.com/keras-team/keras/issues/12511

    • Kristof 2021年1月9日 凌晨3:55 #

      首先——Jason,谢谢你,先生!你分享的资源一如既往的精彩。

      @ James,我也看到了这一点,我的看法是,通过使用 ModelCheckpoint,你可以即时保存最佳模型,而 Earlystopping 则需要单独进行,因此当你的机器崩溃时,模型就丢失了。所以我的看法是两者都使用,以保存最佳模型并节省资源……——?

  24. abq 2020年6月5日 凌晨4:15 #

    嗨 Jason,再次感谢您分享的精彩文章!

    我有一个关于数据分割的疑问:在两种不同的分割方法中,train_X 和 train_y 数据是否相同?

    输入:
    model.fit(train_X, train_y, validation_data=(val_x, val_y)) 中,train_X 和 train_y 应该用于调整网络权重和偏差的数据,即示例中前 30 行数据。

    然而,在
    model.fit(train_X, train_y, validation_split=0.3) 中,我猜我们用于训练的数据应该是整个数据集,即示例中创建的所有 100 个样本。因此,要在上述示例中使用 validation_split,对应的代码是
    model.fit(X, y, validation_split=0.3)

    如果我理解正确,请告诉我。

  25. Chris 2020年7月9日 早上9:53 #

    我发现 Keras 的提前停止无法监控训练损失。您认为如果我们可以在不需要验证集的情况下监控并停止训练,这会有用吗?在某些情况下可能不需要超参数调整,因此验证集是不必要的。

    • Jason Brownlee 2020年7月9日 下午1:19 #

      我建议监控验证损失以进行提前停止。

      如果您需要更复杂的停止标准,您可以编写自定义回调 / 提前停止方法。

  26. Tam Minh Vo 2020年7月9日 晚上8:54 #

    嗨 Jason!感谢你的乐于助人。我非常感谢你的工作。

    我有一个问题。关于损失函数为 mean_squared_error 的回归任务,我们应该监控 EarlyStoping 的哪些因素(val_loss 或 val_mse 或……)?

    我不明白这一点,为什么是 val_loss 而不是 val_mse,或者为什么是 val_mse 而不是 val_loss……?

    提前感谢您!

    • Jason Brownlee 2020年7月10日 早上5:57 #

      我们通常监控验证损失。

      如果损失是 MSE,并且您在同一数据集上使用 MSE 作为度量,那么它们是相同的。

  27. Salih K 2020年7月14日 凌晨3:47 #

    嗨 Jason,我非常感谢你的工作,感谢你发布如此详细的教程。我有一个关于提前停止和模型检查点使用的问题

    我知道在模型投入生产后(即超参数已经调整完毕,并且模型已经使用单独的验证集进行了优化),使用完整的训练数据进行训练,并将测试数据作为验证数据是可以的。但我假设在测试数据上使用提前停止和模型检查点会导致训练-测试数据污染,因为它具有正则化效果。

    我找不到关于这个问题的明确解释。我想确保在生产中使用测试数据以及提前停止在实践中是不好的。但另一方面,充分利用测试数据对我来说似乎是个好主意,但我不确定使用提前停止是否算作作弊,因为它具有正则化效果。

    请告诉我你的看法。提前感谢!

  28. George 2020年7月28日 下午3:35 #

    嗨,Jason,
    在 monitor="val_accuracy" 的情况下,
    指定 patience 或 min_delta 是否可以?
    或者两者都可以给定?
    如果使用 min_delta,例如准确率的 1%,我们就不必担心为不同的 epoch 值更改 patience,请纠正我,谢谢

    • Jason Brownlee 2020年7月29日 早上5:44 #

      我相信两者都可以给出,也许可以尝试一下。

  29. MEN 2020年9月5日 早上6:35 #

    当我遇到机器学习问题时,我总是谷歌 machinelearningmastery!
    感谢这些宝贵的资料。

  30. Hubert 2020年9月28日 下午2:23 #

    嗨,这是一个非常有帮助的话题!

    我有一个问题:为什么在获取评估函数的准确率分数之前我们需要下划线“_”?
    例如:_, train_acc = model.evaluate(trainX, trainy, verbose=0)

    谢谢

    • Jason Brownlee 2020年9月28日 下午5:05 #

      这是一种 Python 习语。

      用于忽略函数返回的第一个元素,在这种情况下是损失。

  31. sisy 2020年11月11日 早上10:59 #

    如果训练损失非常小,训练准确率达到100,但验证损失约为0.5,验证准确率达到86%,那么模型被认为是好的吗?

  32. Mary 2020年12月17日 凌晨1:07 #

    亲爱的 Jason,
    感谢您提供的有用教程。
    我想知道如何在回归中使用提前停止。
    如果您有任何关于在回归中使用提前停止的教程文章,请告诉我链接。
    祝好
    玛丽

    • Jason Brownlee 2020年12月17日 早上6:36 #

      方法相同,只需更改代码以监控验证 MSE 损失。

  33. Hemanth 2021年1月5日 早上5:25 #

    嗨,杰森,
    dense 函数中的 input_dim 是什么?

  34. Samah wael 2021年1月19日 凌晨4:17 #

    你是英雄。
    您可以想象您的教程是多么有帮助,非常感谢。
    我有一个问题,如何使用交叉验证应用提前停止?

  35. Fogang 2021年1月31日 凌晨12:06 #

    你好,先生,

    假设我有总共 5 个 epoch 要完成,并且我有一个在 epoch 04 停止的训练(并且我在 epoch 03 有模型状态:weights-03-0.7994.hdf5),我想在 epoch 04 再次开始训练。我的下一步代码是什么?

    from tensorflow.keras.models import load_model

    new_model = load_model("weights-03-0.7994.hdf5")

    checkpoint = ModelCheckpoint("weights-{epoch:02d}-{val_acc:.4f}.hdf5", monitor = 'val_acc', verbose = 1, save_best_only = True, mode = 'max');

    new_model.fit(X_train), y_train, validation_data=(X_valid, y_valid), epochs=5, batch_size=1, callbacks = [checkpoint], verbose = 1, initial_epoch=3);

    • Jason Brownlee 2021年1月31日 早上5:36 #

      可能吧。我自己没运行,但看起来没问题。

      • Fogang 2021年1月31日 早上7:55 #

        好的。 🙂

  36. Hamilton 2021年5月2日 凌晨2:18 #

    嘿,谢谢你的详细描述。我正在尝试使用 AC GAN 进行提前停止。你能告诉我该怎么做吗?因为在你的 GAN 教程中你从未使用过 model fit

    • Jason Brownlee 2021年5月2日 早上5:34 #

      不客气。

      也许手动实现会更容易,例如,密切关注验证性能并在验证损失变差时停止训练。

  37. Brandon B 2021年5月4日 凌晨1:28 #

    非常感谢!您的作品是我经常参考的对象。感谢您为提供巨大帮助所付出的辛勤工作。非常感谢 machinelearningmastery。

  38. Shaima' 2021年9月13日 早上11:47 #

    非常感谢。你真的很棒。

  39. Ugur Kahveci 2021年10月13日 凌晨3:47 #

    Jason,感谢您的清晰解释。您的这些示例确实帮助我开发了我的算法,我必须补充说,这个网站一直是我的机器学习知识库,所以再次感谢。

    我的想法是,如果我已经利用提前停止来最大化我的算法学习能力,那么交叉验证似乎有点过度。我这样想对吗,或者在提前停止之上使用交叉验证有其好处?

    • Adrian Tam
      Adrian Tam 2021年10月13日 早上7:37 #

      不。它们用于不同的目的。提前停止是为了停止在无法做得更好的事情上浪费时间和精力。例如,如果你知道你已经在考试中得了 99 分,你就不想再多学习 10 小时。交叉验证是为了使用不同的数据/参数构建模型,并确保你不是靠运气。同样的道理,你用不同的考试题测试一个学生三次,以确保她每次都能得 99 分,并且她确实掌握了知识。

      • Ugur Kahveci 2021年10月13日 晚上7:23 #

        谢谢!

  40. Ugur Kahveci 2021年11月17日 晚上6:48 #

    再次问好,

    我有些事情不明白。

    在我的案例中,我构建了一个算法,它以图像作为输入并输出同一图像的二值图像。我如何配置它,以便其他人可以使用他们自己的图像使用我的算法并立即获得结果,而无需每次都进行训练?

    换句话说,我如何将我训练好的模型转换为一个基本的软件,它接受输入并产生输出?

  41. Lana Lu 2021年12月16日 早上10:58 #

    你好,

    感谢您可爱的文章。我发现我的测试准确率几乎总是高于训练准确率,并且我的测试损失低于训练损失。你知道这可能是什么原因造成的吗?我训练了梅尔频率倒谱系数 (MFCC) 数据。输入形状为 (10000, 40, 162),输出为 (10000, 2)。目的是区分两种类型的乐器信号。我怀疑是不是我的样本太小,或者我使用了错误的模型?我的模型是 LSTM+FC(全连接)。

    • Adrian Tam
      Adrian Tam 2021年12月17日 早上7:22 #

      无法确定原因,但你可以检查多次运行(即从不同的网络随机状态开始)是否看到相同的情况。在你的情况下,样本量看起来并不小。

    • James Carmichael 2021年12月21日 下午12:16 #

      你好 Lana... 一个关键考虑因素是训练和测试的分割比例。如果你的测试比例不够大,测试准确率会高于训练准确率。

      另一个考虑因素是样本数量与特征数量的相对关系。可能你需要增加样本数量。

      此致,

  42. Ted Tower 2022年1月30日 早上6:36 #

    我看到一些文章建议,除了 dropout 等之外,训练损失和验证损失应该具有可比性,直到测试损失开始上升。从某种意义上说,这很有道理,因为生产中的下一个新输入可能与训练集或验证集非常相似,因此具有相似的损失是有意义的——它对于任何传入的输入都不会更准确(或更不准确)。

    然而,你的例子(和其他例子!)似乎表明“继续下去”直到验证损失明显增加。你的例子中的训练损失远低于验证损失。模型在类似训练的输入上更准确,而类似验证的输入是最坏的情况。最终,也许这没关系,但我正在纠结一个模型在某些输入上可能比预期工作得更好——这是一种偏见。有什么想法吗?

  43. Ted Tower 2022年2月1日 凌晨1:44 #

    谢谢詹姆斯,
    抱歉,你能帮我理解训练时长与降维之间的联系吗?这篇“提前停止”文章中的示例在 epoch ~800 时训练损失远低于验证损失。如果我们在 epoch 20 左右,在它们开始发散之前停止,损失将大致相同。模型可以变得更好,但只能通过记忆训练数据的一部分——如果它恰好降低了验证损失,我们将继续。我想这感觉像是一个不言而喻的权衡,我们非常擅长几乎准确地预测训练数据,并且我们在验证损失下降时变得更好了。因此我们的泛化能力有所提高,但我们在训练数据上的表现确实比在验证数据上要好得多。

  44. Mohammad Esmalifalak 2022年3月16日 凌晨3:52 #

    感谢您关于这个主题的精彩教程。

    我读过您关于时间序列数据的“前向验证”,想知道我们是否也可以在那里应用提前停止条件?

  45. Mohammad Esmalifalak 2022年3月16日 凌晨3:53 #

    感谢您关于这个主题的精彩教程。

    我读过您关于时间序列数据的“前向验证”,想知道我们是否也可以在那里应用提前停止条件?

    谢谢

  46. Muilo 2022年9月21日 晚上9:58 #

    当使用 early stopping 和 restore_best_weights=True 以及 Verbose=1 时

    我们会收到一条消息,提示从最佳 epoch (假设是 epoch X) 恢复权重,并且 early stopping 在 epoch Y (Y > X) 激活。

    Keras 是否将这些值 (X 和 Y) 保存在某个变量中?有什么方法可以访问它们吗?因为我必须训练我的模型 10 次以进行性能的统计评估,并且我还希望知道这 10 次迭代中的每一次在哪个 epoch 具有最佳权重,以及 early stopping 在哪个 epoch 激活。

  47. Kibreab 2023年2月21日 晚上8:30 #

    在 Keras 中,如何使模型 (DNN) 产生一致的结果?当我多次运行模型时,每次都会得到不同的结果。我定义了
    import numpy as np
    np.random.seed(0) 但它没有帮助
    import numpy as np
    np.random.seed(0)
    from sklearn.datasets import make_moons
    来自 keras.models import Sequential
    from keras.layers import Dense
    from keras.callbacks import EarlyStopping
    from matplotlib import pyplot
    # 生成 2d
    # 定义模型

    model = Sequential()
    np.random.seed(0)
    model.add(Dense(256, input_dim=87, activation='relu'))
    model.add(Dense(1, activation=’sigmoid’))
    model.compile(loss=’binary_crossentropy’, optimizer=’adam’, metrics=[‘accuracy’])
    # 简单的提前停止
    es = EarlyStopping(monitor='val_loss', mode='min', verbose=1)
    # 拟合模型
    history = model.fit(X_train, y_train, validation_data=(X_test, y_test), epochs=15, verbose=0, callbacks=[es])

  48. Levi 2024年9月20日 晚上10:08 #

    所以基本上,在提前停止中使用测试数据来训练模型是可以的吗?特别是在时间序列中,它不会产生任何数据泄露,如果我错了请纠正我

发表评论

Machine Learning Mastery 是 Guiding Tech Media 的一部分,Guiding Tech Media 是一家领先的数字媒体出版商,专注于帮助人们了解技术。访问我们的公司网站以了解更多关于我们的使命和团队的信息。