如何通过添加噪声来提高深度学习模型的鲁棒性

向一个欠约束的、具有小型训练数据集的神经网络模型添加噪声可以起到正则化的作用,并减少过拟合。

Keras通过一个名为GaussianNoise的独立层支持添加高斯噪声。此层可用于向现有模型添加噪声。

在本教程中,您将发现如何在Keras中向深度学习模型添加噪声,以减少过拟合并提高模型泛化能力

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

  • 可以通过GaussianNoise层向神经网络模型添加噪声。
  • GaussianNoise可用于为输入值或隐藏层之间的噪声添加噪声。
  • 如何添加GaussianNoise层以减少多层感知机分类模型中的过拟合。

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

让我们开始吧。

  • 2019 年 10 月更新:更新至 Keras 2.3 和 TensorFlow 2.0。
How to Improve Deep Learning Model Robustness by Adding Noise

如何通过添加噪声来提高深度学习模型的鲁棒性
照片由Michael Mueller拍摄,保留部分权利。

教程概述

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

  1. Keras中的噪声正则化
  2. 模型中的噪声正则化
  3. 噪声正则化案例研究

Keras中的噪声正则化

Keras通过GaussianNoise层支持向模型添加噪声。

这是一个将噪声添加到给定形状的输入中的层。噪声的均值为零,并要求将噪声的标准差作为参数指定。例如

该层的输出形状将与输入相同,唯一的修改是为值添加噪声。

模型中的噪声正则化

GaussianNoise可以在神经网络模型中以几种不同的方式使用。

首先,它可以作为输入层直接为输入变量添加噪声。这是噪声作为神经网络中正则化方法的传统用法。

下面是一个将GaussianNoise层定义为接受2个输入变量的模型的输入层的示例。

也可以在模型中的隐藏层之间添加噪声。鉴于Keras的灵活性,可以在激活函数使用之前或之后添加噪声。在激活之前添加噪声可能更有意义;尽管如此,这两种选择都是可行的。

下面是一个GaussianNoise层将噪声添加到Dense层线性输出之后,再应用修正线性激活函数(ReLU)的示例,这可能是在隐藏层之间使用噪声的更恰当方式。

也可以在激活函数之后添加噪声,这类似于使用带噪声的激活函数。这种用法的一个缺点是,结果值可能超出激活函数通常提供的范围。例如,带噪声的值可能小于零,而ReLU激活函数只会输出大于或等于零的值。

让我们来看看噪声正则化如何与一些常见的网络类型一起使用。

MLP噪声正则化

下面的示例在两个全连接层之间添加噪声。

CNN噪声正则化

下面的示例在卷积网络中的池化层之后添加噪声。

RNN Dropout正则化

下面的示例在LSTM循环层和Dense全连接层之间添加噪声。

现在我们已经了解了如何向神经网络模型添加噪声,接下来让我们看一个将噪声添加到过拟合模型以减少泛化误差的案例研究。

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

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

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

噪声正则化案例研究

在本节中,我们将演示如何使用噪声正则化来减少MLP在简单二分类问题上的过拟合。

这个例子提供了一个将噪声正则化应用于您自己的神经网络进行分类和回归问题的模板。

二分类问题

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

每个观测值都有两个具有相同比例的输入变量和一个类别输出值 0 或 1。由于绘制时每个类别中观测值的形状,此数据集称为“*circles*”数据集。

我们可以使用make_circles()函数来生成该问题的数据。我们将向数据添加噪声并设置随机数生成器的种子,以便每次运行代码时都能生成相同的样本。

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

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

运行该示例将生成一个散点图,显示每个类别中观测值的同心圆形状。我们可以看到散布点中的噪声使得圆圈不那么明显。

Scatter Plot of Circles Dataset with Color Showing the Class Value of Each Sample

带有颜色显示每个样本类别值的圆数据集散点图

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

我们只生成了100个样本,这对于神经网络来说太少了,这为过拟合训练数据集并导致测试数据集错误率较高提供了机会,这很适合使用正则化。此外,样本带有噪声,这为模型学习样本中不能泛化的方面提供了机会。

过拟合多层感知器

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

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

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

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

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

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

我们还将测试数据集用作验证数据集。

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

最后,我们将绘制每个 epoch 模型在训练集和测试集上的性能。

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

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

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

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

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

创建了一个图,显示模型在训练集和测试集上的准确度线图。

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

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

训练期间训练集和测试集准确度线图,显示过拟合

MLP输入层噪声

数据集由具有受控统计噪声的点定义。

尽管如此,由于数据集很小,我们可以为输入值添加更多噪声。这将起到创建更多样本或重新采样域的作用,使输入空间的结构人为地更平滑。这可能会使学习问题更容易,并提高泛化性能。

我们可以添加一个GaussianNoise层作为输入层。噪声量必须很小。鉴于输入值在[0, 1]范围内,我们将添加均值为0.0、标准差为0.01的高斯噪声,该值是任意选择的。

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

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

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

在这种情况下,我们可能会在测试数据集上看到模型性能的小幅提升,而对训练数据集没有负面影响。

我们可以在训练期间的评估中清晰地看到添加噪声的影响,如下图所示。噪声导致模型在训练期间的准确性出现波动,这可能是由于噪声引入了与训练数据集中的真实点相冲突的点。

也许较低的输入噪声标准差会更合适。

模型仍然显示出过拟合的模式,在训练周期中测试准确性出现先上升后下降的情况。

Line Plot of Train and Test Accuracy With Input Layer Noise

具有输入层噪声的训练和测试准确性折线图

MLP隐藏层噪声

与向输入值添加噪声的替代方法是,在隐藏层之间添加噪声。

这可以通过在激活函数(在本例中为修正线性激活函数)应用之前,向层的线性输出(加权和)添加噪声来实现。我们还可以使用更大的噪声标准差,因为模型在这一级别对噪声的敏感度较低,这可能归因于过拟合的权重更大。我们将使用0.1的标准差,同样是任意选择的。

下面列出了在隐藏层之间添加高斯噪声的完整示例。

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

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

在这种情况下,我们可以看到模型在保留的测试集上的性能有了显著提高。

我们还可以从准确性随训练周期变化的折线图可以看出,模型不再显示出过拟合的特性。

Line Plot of Train and Test Accuracy With Hidden Layer Noise

具有隐藏层噪声的训练和测试准确性折线图

我们还可以进行实验,将噪声添加到第一个隐藏层通过激活函数之后的输出。

完整的示例如下所示。

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

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

出乎意料的是,我们发现模型性能几乎没有差异。

同样,从准确性随训练周期变化的折线图可以看出,模型不再显示出过拟合的迹象。

Line Plot of Train and Test Accuracy With Hidden Layer Noise (alternate)

具有隐藏层噪声(替代方案)的训练和测试准确性折线图

扩展

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

  • 重复评估。更新示例以使用对模型(有噪声和无噪声)进行重复评估,并将性能报告为重复次数的平均值和标准差。
  • 网格搜索标准差。开发一个网格搜索,以发现能够可靠地产生最佳性能模型的噪声量。
  • 输入和隐藏噪声。更新示例,在模型的输入层和隐藏层引入噪声。

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

进一步阅读

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

总结

在本教程中,您了解了如何在Keras中向深度学习模型添加噪声,以减少过拟合并提高模型泛化能力。

具体来说,你学到了:

  • 可以通过GaussianNoise层向神经网络模型添加噪声。
  • GaussianNoise可用于为输入值或隐藏层之间的噪声添加噪声。
  • 如何添加GaussianNoise层以减少多层感知机分类模型中的过拟合。

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

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

Better Deep Learning

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

...只需几行python代码

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

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

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

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

查看内容

25条回复“如何通过添加噪声提高深度学习模型的鲁棒性”

  1. Nitin Panwar 2018年12月14日晚上6:10 #

    谢谢Jason,讲解得很棒。非常喜欢。

  2. maedeh 2019年2月22日晚上1:34 #

    谢谢,但我认为我们只有高斯噪声层。如果我想应用一些攻击,比如裁剪,Keras中有任何层可以做到吗?你有什么建议吗?我期待您的回复。

    • Jason Brownlee 2019年2月22日晚上2:48 #

      好问题,通常没有,您可以使用自定义数据生成器,并在将图像馈送到模型之前对其进行随机裁剪。

  3. Michael 2019年4月12日早上5:23 #

    嗨Jason,当你向权重或激活添加噪声时,你对反向传播有什么看法?例如,当向激活(它们作为层输入)添加噪声时,要计算该层的权重梯度,您需要将传入的梯度乘以这些激活。您会使用原始激活还是失真的激活?或者当反向传播误差时,我们将其乘以每个层的转置权重矩阵,同样,您会使用原始权重还是失真的权重?

    • Jason Brownlee 2019年4月12日早上7:56 #

      嗯。

      我没怎么见过,除了像GAN和随机标签平滑这样的模型——因为训练GAN非常不稳定才需要。

      如果您有想法,就去尝试吧。有了如此出色的工具,这从未如此容易!

      • Michael 2019年4月12日早上8:48 #

        事实上,这对我来说并不容易。例如,假设我们想向激活(第二个层的输入)添加噪声,然后更新第二个层的权重。TF或Pytorch中的标准自动微分会将上游梯度直接传递给噪声添加操作,以乘以第二个层的原始输入。但是,我如何改变它,使它们乘以失真的输入?我认为失真的输入并没有保留用于反向传播。

        在这种情况下,我认为这些工具实际上使实验变得更加困难。

        • Michael 2019年4月12日早上8:51 #

          或者,如果自动微分保留的是失真的输入,那么我如何跳过它们并将梯度传递给原始输入?

          • Jason Brownlee 2019年4月12日晚上2:40 #

            模型看不到失真的输入,它看到的是输入/输出/激活。恰好您用噪声使它们失真了。更新照常进行。

            也许我不理解您试图实现的细微差别。

  4. Borja 2019年5月4日晚上10:47 #

    你好 Jason,

    我想知道,如果模型结构中添加了噪声层,它是否也会将噪声应用于每个测试输入?您将如何进行模型的噪声训练,然后用干净的输入进行训练?

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

      这取决于。输入或输出噪声通常会关闭,有时会在测试时保留。模型内的噪声有时会保留。也许在测试时用/不用进行评估并进行比较。

      如果需要,您可以重新构建最终模型而不使用噪声层。

  5. Robert 2019年5月8日早上11:14 #

    嗨,Jason,

    很棒的文章,我有一个关于在先前填充(例如用0填充)的输入上使用高斯噪声的问题。您认为在这种情况下训练中的损失会变差吗?一个例子可能是填充不同长度的输入,如语音频谱图,以便它们具有相同的形状。

    • Jason Brownlee 2019年5月8日晚上2:12 #

      嗯,好问题。

      是的,噪声覆盖填充听起来是个坏主意。

      有很多方法可以将噪声引入系统,发挥创意并测试一系列方法。

  6. Nestak 2019年8月6日早上1:01 #

    你好!有办法调整/增强对比度吗?类似 model.add(Contrast(0.1)) 吗?

  7. Nestak 2019年8月8日早上4:20 #

    我想为用于分类JPG图像的神经网络添加一些噪声。所以,我的神经网络的输入是像素数组,我已经将它们归一化到0到1的范围内。我想按照你的建议做

    model.add(MaxPooling2D())
    model.add(GaussianNoise(x))

    但我担心GaussianNoise可能会使我的数据超出0到1的范围并破坏训练。这是一个有效的问题,还是我安全了?它是否取决于x的值,我应该使用什么x值?谢谢。

    • Jason Brownlee 2019年8月8日早上6:36 #

      应该可以,也许可以测试一下并评估效果?

      或者,您可以创建自己的自定义层来实现您想要的功能。

  8. JG 2019年8月14日早上4:36 #

    嗨,Jason,

    感谢您的教程!

    我一直在使用这个教程,添加其他选项到脚本中,以便以某种“网格搜索”的方式进行实验。这是我的报告。

    - 我使用Keras模型类API而不是Sequential来定义我的模型:但我不期望结果有任何影响!

    - 我设置了模型(和您一样),但也使用了其他“高级”模型构造函数,如Sklearn库中的‘KerasClassifier’和‘cross_val_score’(用于Kfold统计分析)。总的来说,‘cross_val_score’获得的平均准确率较低(平均准确率69%),而模型在测试输入上的准确率为85.7%。我明白这一点。
    但奇怪的是,当我使用KerasClassiffier时,我的结果通常更好(例如84.3%)。

    我不明白为什么我在 KerasClassifier 上能获得比我的“手动”API 类模型更好的结果,尽管我在两种情况下都使用了相同的“validation_split”(70% 用于测试,30% 用于输入训练)。

    – 我在验证训练中获得了某种“正弦损失曲线”(先下降后上升,但长期趋势是上升的,即使我训练了 8000 个 epoch)。在验证准确率上也有相同的影响,但趋势是轻微下降的)。所有这些情况都应用了没有添加高斯噪声。

    – 我观察到来自“sklearn 的 make_circles”的 X 输入数据在 -1.06… 和 +1.06 … 之间,所以我决定对输入数据进行归一化或标准化(使用 sklearn 的 MinMaxScaler 和 StandardScaler 以及您的教程。总的来说,我在“cross-val-score”上获得了稍好的性能。(平均准确率提高了高达 72%),但我的 KerasClassifier 表现更好(准确率高达 88.6%),而我的“手动模型”在测试上的准确率稍差,约为 77%。

    - 当我将 70% 的测试和 30% 的训练输入置换为 30% 的测试和 70% 的训练(更自然的数据利用)时,Bing 的结果很敏感。在这种情况下,cross_val_score 的平均准确率为 83%,sigma 为 10.7%,KerasClassifier 的准确率为 96.7%,我的手动模型的准确率为 90%。在这个场景中原因很清楚。

    - 我还应用了 Dropout 层和权重约束正则化(取自您的教程),但结果没有太大区别。

    – 我当然应用了高斯噪声层(在输入层之后或输出层之前),并且清楚地在验证损失训练曲线方面获得了正确的趋势(在训练 epoch 增加期间消失了损失增加),但我的手动模型的准确率相似,scross-val-score 构造函数的准确率稍好。我观察到它们对应用于高斯噪声层的 sigma(标准差)非常敏感。

    – 即使我将所有正则化技术结合起来,以一种“混乱”的方式使用(Dropout 层 + 高斯噪声 + 权重约束正则化)加上输入数据缩放器…我的准确率约为 50%(根本没有学习),所以很明显我需要更好地控制这些工具…:-)

    – 总结一下,当使用高斯噪声层时,我对准确率结果没有太大影响(但当然在损失和准确率训练曲线方面有更好的行为),即使同时使用输入层之后和输出层之前的高斯噪声层…可能是因为 sigma 噪声(标准差)需要更好地拟合…

    谢谢你的教程 Jason

    • Jason Brownlee 2019 年 8 月 14 日上午 6:50 #

      精彩的实验,感谢分享。

      如果您写下来并分享,这将是非常有价值的——有价值的,因为它表明一个人必须多么系统和好奇才能真正深入研究这些技术。

      在 90 年代,添加噪声非常流行,现在由于我们有了 dropout,它不那么流行了。然而,我在大型现代 GAN 模型中看到了它,所以它仍然存在且有用。

  9. Sean Reynolds 2020 年 1 月 24 日下午 2:16 #

    嘿 Jason,文章写得很好。
    如何在预训练模型中添加输入噪声,例如
    from tensorflow.keras.applications.resnet50 import ResNet50

    我只想做输入噪声,但我不知道如何插入它。

    • Jason Brownlee 2020 年 1 月 25 日上午 8:31 #

      将噪声层添加为模型的第一个层——例如,使用函数式 API。

      也许我没理解问题所在?

  10. Amir 2020 年 3 月 4 日上午 7:51 #

    嗨 Jason
    感谢您精彩的讲解
    您是否有关于研究 LSTM 对训练噪声鲁棒性的文档?
    谢谢

    • Jason Brownlee 2020 年 3 月 4 日下午 1:32 #

      暂时没有,也许可以对您的数据集运行敏感性分析?

  11. Alex 2024 年 2 月 15 日凌晨 1:11 #

    我为我的模型添加了噪声层,我得到了与添加噪声层之前相同的结果?这是否意味着我的模型很好或过拟合?

Leave a Reply

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