Machine Learning Mastery 深度学习表现教程(六)

原文:Machine Learning Mastery

协议:CC BY-NC-SA 4.0

适时使用提前停止来停止神经网络的训练

原文:https://machinelearningmastery.com/how-to-stop-training-deep-neural-networks-at-the-right-time-using-early-stopping/

最后更新于 2020 年 8 月 25 日

训练神经网络的一个问题是选择要使用的训练时期的数量。

过多的时期会导致训练数据集的过拟合,而过少的时期会导致模型的欠拟合。提前停止是一种方法,它允许您指定任意数量的训练时期,并在模型表现停止在等待验证数据集上改善时停止训练。

在本教程中,您将发现 Keras API,用于将早期停止添加到过度深度学习神经网络模型中。

完成本教程后,您将知道:

  • 如何使用 Keras API 在训练过程中监控模型的表现。
  • 如何使用 Keras API 创建和配置早期停止和模型检查点回调。
  • 如何通过在现有模型中增加提前停止来减少过拟合?

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

我们开始吧。

  • 2019 年 10 月更新:针对 Keras 2.3 和 TensorFlow 2.0 更新。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

如何在正确的时间停止训练深层神经网络使用提前停止
图片由伊恩·d·基廷提供,保留部分权利。

教程概述

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

  1. 在 Keras 中使用回调
  2. 评估验证数据集
  3. 监控模型表现
  4. 在 Keras 的早期停留
  5. Keras 的检查点
  6. 早期停止案例研究

在 Keras 中使用回调

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

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

首先,回调必须被实例化。

...
cb = Callback(...)

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

...
cb_list = [cb, ...]

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

...
model.fit(..., callbacks=cb_list)

在 Keras 中评估验证数据集

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

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

这样做有两种方法。

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

...
model.fit(train_X, train_y, validation_data=(val_x, val_y))

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

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

...
model.fit(train_X, train_y, validation_split=0.3)

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

监控模型表现

为您的模型选择优化的损失函数在每个时期结束时计算。

对于回调,这可以通过名称“ loss 获得。”

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

在模型的训练过程中,可以监控额外的度量。

它们可以在编译模型时通过编译函数的“度量”参数来指定。该参数采用已知度量函数的 Python 列表,例如均方误差为“ mse ,准确率为“准确率”。例如:

...
model.compile(..., metrics=['accuracy'])

如果在训练过程中监控了额外的指标,它们也可以通过相同的名称用于回调,例如训练数据集中的准确率为“准确率”,验证数据集中的准确率为“ val_accuracy ”。或者,训练数据集中的均方误差为“ mse ”,验证数据集中的 val_mse 。

在 Keras 的早期停留

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

该回调允许您指定要监视的表现度量、触发器,一旦触发,它将停止训练过程。

通过参数实例化时,配置预警回调。

监视器”允许您指定要监视的表现度量,以便结束培训。回想一下上一节,验证数据集上的度量计算将具有“ val_ 前缀,例如验证数据集上的损失的“ val_loss ”。

es = EarlyStopping(monitor='val_loss')

根据绩效衡量标准的选择,需要指定“模式”参数,即所选指标的目标是增加(最大化或“最大值”)还是减少(最小化或“最小值”)。

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

es = EarlyStopping(monitor='val_loss', mode='min')

默认情况下,模式设置为“自动”,并且知道您想要最小化损失或最大化准确率。

这就是最简单的提前停止所需要的。当所选的绩效指标停止改善时,培训将停止。要发现停止训练的训练时期,可以将“ verbose ”参数设置为 1。一旦停止,回调将打印纪元号。

es = EarlyStopping(monitor='val_loss', mode='min', verbose=1)

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

我们可以通过在我们不希望看到改进的时期数量方面增加触发器的延迟来说明这一点。这可以通过设置“耐心”参数来完成。

es = EarlyStopping(monitor='val_loss', mode='min', verbose=1, patience=50)

确切的耐心程度会因模型和问题而异。查看表现度量图对于了解数据模型的优化过程可能有多嘈杂非常有用。

默认情况下,绩效指标的任何变化,无论多小,都将被视为改进。您可能需要考虑特定增量的改进,例如均方误差为 1 个单位,准确率为 1%。这可以通过“ min_delta ”参数来指定。

es = EarlyStopping(monitor='val_accuracy', mode='max', min_delta=1)

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

这在微调模型时可能更有用,因为在训练新模型的早期阶段所看到的表现度量的初始剧烈波动已经过去。

es = EarlyStopping(monitor='val_loss', mode='min', baseline=0.4)

Keras 的检查点

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

需要一个额外的回调,以保存在培训期间观察到的最佳模型,供以后使用。这是模型检查点回调。

模型检查点回调的使用方式很灵活,但在这种情况下,我们将只使用它来保存训练期间观察到的最佳模型,该模型由验证数据集上选择的表现度量来定义。

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

sudo pip install h5py

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

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

mc = ModelCheckpoint('best_model.h5')

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

mc = ModelCheckpoint('best_model.h5', monitor='val_loss')

此外,与早期预测回调一样,我们必须将“模式指定为最小化或最大化表现度量。同样,默认为“汽车”,它知道标准的表现指标。

mc = ModelCheckpoint('best_model.h5', monitor='val_loss', mode='min')

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

mc = ModelCheckpoint('best_model.h5', monitor='val_loss', mode='min', save_best_only=True)

这是所有需要的,以确保当使用早期停止时,或一般情况下,具有最佳表现的模型被保存。

了解表现度量的价值以及模型是在哪个时期保存的可能会很有趣。通过将“ verbose ”参数设置为“ 1 ,回调就可以打印出来。

mc = ModelCheckpoint('best_model.h5', monitor='val_loss', mode='min', verbose=1)

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

# load a saved model
from keras.models import load_model
saved_model = load_model('best_model.h5')

既然我们知道了如何使用早期停止和模型检查点 API,让我们来看一个成功的例子。

早期停止案例研究

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

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

二分类问题

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

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

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

# generate 2d classification dataset
X, y = make_moons(n_samples=100, noise=0.2, random_state=1)

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

下面列出了生成数据集并绘制它的完整示例。

# generate two moons dataset
from sklearn.datasets import make_moons
from matplotlib import pyplot
from pandas import DataFrame
# generate 2d classification dataset
X, y = make_moons(n_samples=100, noise=0.2, random_state=1)
# scatter plot, dots colored by class value
df = DataFrame(dict(x=X[:,0], y=X[:,1], label=y))
colors = {0:'red', 1:'blue'}
fig, ax = pyplot.subplots()
grouped = df.groupby('label')
for key, group in grouped:
    group.plot(ax=ax, kind='scatter', x='x', y='y', label=key, color=colors[key])
pyplot.show()

运行该示例会创建一个散点图,显示每个类别中观测值的半圆或月亮形状。我们可以看到点扩散的噪音使得卫星不那么明显。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

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

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

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

过采样多层感知器

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

该模型将有一个隐藏层,该隐藏层的节点可能比解决该问题所需的节点更多,这为过度填充提供了机会。我们还将对模型进行比要求更长时间的训练,以确保模型溢出。

在定义模型之前,我们将把数据集分成训练集和测试集,用 30 个例子训练模型,用 70 个例子评估拟合模型的表现。

# generate 2d classification dataset
X, y = make_moons(n_samples=100, noise=0.2, random_state=1)
# split into train and test
n_train = 30
trainX, testX = X[:n_train, :], X[n_train:, :]
trainy, testy = y[:n_train], y[n_train:]

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

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

# define model
model = Sequential()
model.add(Dense(500, input_dim=2, activation='relu'))
model.add(Dense(1, activation='sigmoid'))
model.compile(loss='binary_crossentropy', optimizer='adam', metrics=['accuracy'])

然后,定义的模型适用于 4000 个时期的训练数据,默认批量为 32。

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

# fit model
history = model.fit(trainX, trainy, validation_data=(testX, testy), epochs=4000, verbose=0)

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

# evaluate the model
_, train_acc = model.evaluate(trainX, trainy, verbose=0)
_, test_acc = model.evaluate(testX, testy, verbose=0)
print('Train: %.3f, Test: %.3f' % (train_acc, test_acc))

最后,我们将绘制每个时期模型在列车和测试集上的损失。

如果模型确实过度训练了训练数据集,那么随着模型学习训练数据集中的统计噪声,我们将期望训练集上的损失(和准确率)的线图继续增加,并且测试集上升,然后再次下降。

# plot training history
pyplot.plot(history.history['loss'], label='train')
pyplot.plot(history.history['val_loss'], label='test')
pyplot.legend()
pyplot.show()

我们可以把所有这些部分绑在一起;下面列出了完整的示例。

# mlp overfit on the moons dataset
from sklearn.datasets import make_moons
from keras.layers import Dense
from keras.models import Sequential
from matplotlib import pyplot
# generate 2d classification dataset
X, y = make_moons(n_samples=100, noise=0.2, random_state=1)
# split into train and test
n_train = 30
trainX, testX = X[:n_train, :], X[n_train:, :]
trainy, testy = y[:n_train], y[n_train:]
# define model
model = Sequential()
model.add(Dense(500, input_dim=2, activation='relu'))
model.add(Dense(1, activation='sigmoid'))
model.compile(loss='binary_crossentropy', optimizer='adam', metrics=['accuracy'])
# fit model
history = model.fit(trainX, trainy, validation_data=(testX, testy), epochs=4000, verbose=0)
# evaluate the model
_, train_acc = model.evaluate(trainX, trainy, verbose=0)
_, test_acc = model.evaluate(testX, testy, verbose=0)
print('Train: %.3f, Test: %.3f' % (train_acc, test_acc))
# plot training history
pyplot.plot(history.history['loss'], label='train')
pyplot.plot(history.history['val_loss'], label='test')
pyplot.legend()
pyplot.show()

运行该示例会报告列车和测试数据集上的模型表现。

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

:考虑到算法或评估程序的随机性,或数值准确率的差异,您的结果可能会有所不同。考虑运行该示例几次,并比较平均结果。

因为模型被严重过拟合,我们通常不会期望模型在同一数据集上重复运行时的准确率有太大差异。

Train: 1.000, Test: 0.914

创建一个图形,显示列车和测试集上模型损失的线图。

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

回顾图,我们还可以看到验证损失起伏中的平点。任何提前停止都必须考虑到这些行为。我们还预计,停止训练的好时机可能是在 800 年前后。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

训练时训练和测试数据集上的损失线图显示过拟合模型

提前停止过度捕捞 MLP

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

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

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

# simple early stopping
es = EarlyStopping(monitor='val_loss', mode='min', verbose=1)

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

# fit model
history = model.fit(trainX, trainy, validation_data=(testX, testy), epochs=4000, verbose=0, callbacks=[es])

下面列出了添加简单提前停止的完整示例。

# mlp overfit on the moons dataset with simple early stopping
from sklearn.datasets import make_moons
from keras.models import Sequential
from keras.layers import Dense
from keras.callbacks import EarlyStopping
from matplotlib import pyplot
# generate 2d classification dataset
X, y = make_moons(n_samples=100, noise=0.2, random_state=1)
# split into train and test
n_train = 30
trainX, testX = X[:n_train, :], X[n_train:, :]
trainy, testy = y[:n_train], y[n_train:]
# define model
model = Sequential()
model.add(Dense(500, input_dim=2, activation='relu'))
model.add(Dense(1, activation='sigmoid'))
model.compile(loss='binary_crossentropy', optimizer='adam', metrics=['accuracy'])
# simple early stopping
es = EarlyStopping(monitor='val_loss', mode='min', verbose=1)
# fit model
history = model.fit(trainX, trainy, validation_data=(testX, testy), epochs=4000, verbose=0, callbacks=[es])
# evaluate the model
_, train_acc = model.evaluate(trainX, trainy, verbose=0)
_, test_acc = model.evaluate(testX, testy, verbose=0)
print('Train: %.3f, Test: %.3f' % (train_acc, test_acc))
# plot training history
pyplot.plot(history.history['loss'], label='train')
pyplot.plot(history.history['val_loss'], label='test')
pyplot.legend()
pyplot.show()

运行该示例会报告列车和测试数据集上的模型表现。

:考虑到算法或评估程序的随机性,或数值准确率的差异,您的结果可能会有所不同。考虑运行该示例几次,并比较平均结果。

我们还可以看到回调在 epoch 200 停止了训练。这还为时过早,因为我们预计早停会在 800 年前后。列车和测试集上的分类准确率也凸显了这一点,这比不提前停止更糟糕。

Epoch 00219: early stopping
Train: 0.967, Test: 0.814

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

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

简单提前停止训练中列车和试验损失的线图

我们可以通过在停止前等待一段时间来提高提前停止的触发条件。

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

在这种情况下,我们将等待 200 个纪元,然后停止训练。具体来说,这意味着在验证损失开始下降后,我们将允许培训再持续 200 个时期,从而使培训过程有机会跨越平坦点或发现一些额外的改进。

# patient early stopping
es = EarlyStopping(monitor='val_loss', mode='min', verbose=1, patience=200)

下面列出了此更改的完整示例。

# mlp overfit on the moons dataset with patient early stopping
from sklearn.datasets import make_moons
from keras.models import Sequential
from keras.layers import Dense
from keras.callbacks import EarlyStopping
from matplotlib import pyplot
# generate 2d classification dataset
X, y = make_moons(n_samples=100, noise=0.2, random_state=1)
# split into train and test
n_train = 30
trainX, testX = X[:n_train, :], X[n_train:, :]
trainy, testy = y[:n_train], y[n_train:]
# define model
model = Sequential()
model.add(Dense(500, input_dim=2, activation='relu'))
model.add(Dense(1, activation='sigmoid'))
model.compile(loss='binary_crossentropy', optimizer='adam', metrics=['accuracy'])
# patient early stopping
es = EarlyStopping(monitor='val_loss', mode='min', verbose=1, patience=200)
# fit model
history = model.fit(trainX, trainy, validation_data=(testX, testy), epochs=4000, verbose=0, callbacks=[es])
# evaluate the model
_, train_acc = model.evaluate(trainX, trainy, verbose=0)
_, test_acc = model.evaluate(testX, testy, verbose=0)
print('Train: %.3f, Test: %.3f' % (train_acc, test_acc))
# plot training history
pyplot.plot(history.history['loss'], label='train')
pyplot.plot(history.history['val_loss'], label='test')
pyplot.legend()
pyplot.show()

运行该示例,我们可以看到训练停止得很晚,在本例中是在纪元 1000 之后。

:考虑到算法或评估程序的随机性,或数值准确率的差异,您的结果可能会有所不同。考虑运行该示例几次,并比较平均结果。

我们还可以看到,测试数据集上的表现比不使用任何提前停止要好。

Epoch 01033: early stopping
Train: 1.000, Test: 0.943

回顾一下训练中的损失线图,我们可以看到耐心让训练越过了一些小平面和坏点。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

患者提前停止时训练和测试损失的线图

我们还可以看到,在过去大约 100 个时代,测试损失开始再次增加。

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

在这种情况下,我们有兴趣在测试数据集上以最佳准确率保存模型。我们也可以在测试数据集中寻找具有最佳损失的模型,但是这可能对应于也可能不对应于具有最佳准确率的模型。

这突出了模型选择中的一个重要概念。当使用不同的绩效衡量标准进行评估时,培训期间“最佳”模型的概念可能会发生冲突。试着根据在领域中评估和呈现模型的标准来选择模型。在平衡二进制分类问题中,这很可能是分类准确率。因此,我们将在模型检查点回调中使用准确性进行验证,以保存训练期间观察到的最佳模型。

mc = ModelCheckpoint('best_model.h5', monitor='val_accuracy', mode='max', verbose=1, save_best_only=True)

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

当调用 fit() 函数时,这个新的附加回调可以被添加到回调列表中。

history = model.fit(trainX, trainy, validation_data=(testX, testy), epochs=4000, verbose=0, callbacks=[es, mc])

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

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

# load the saved model
saved_model = load_model('best_model.h5')
# evaluate the model
_, train_acc = saved_model.evaluate(trainX, trainy, verbose=0)
_, test_acc = saved_model.evaluate(testX, testy, verbose=0)
print('Train: %.3f, Test: %.3f' % (train_acc, test_acc))

下面列出了这些更改的完整示例。

# mlp overfit on the moons dataset with patient early stopping and model checkpointing
from sklearn.datasets import make_moons
from keras.models import Sequential
from keras.layers import Dense
from keras.callbacks import EarlyStopping
from keras.callbacks import ModelCheckpoint
from matplotlib import pyplot
from keras.models import load_model
# generate 2d classification dataset
X, y = make_moons(n_samples=100, noise=0.2, random_state=1)
# split into train and test
n_train = 30
trainX, testX = X[:n_train, :], X[n_train:, :]
trainy, testy = y[:n_train], y[n_train:]
# define model
model = Sequential()
model.add(Dense(500, input_dim=2, activation='relu'))
model.add(Dense(1, activation='sigmoid'))
model.compile(loss='binary_crossentropy', optimizer='adam', metrics=['accuracy'])
# simple early stopping
es = EarlyStopping(monitor='val_loss', mode='min', verbose=1, patience=200)
mc = ModelCheckpoint('best_model.h5', monitor='val_accuracy', mode='max', verbose=1, save_best_only=True)
# fit model
history = model.fit(trainX, trainy, validation_data=(testX, testy), epochs=4000, verbose=0, callbacks=[es, mc])
# load the saved model
saved_model = load_model('best_model.h5')
# evaluate the model
_, train_acc = saved_model.evaluate(trainX, trainy, verbose=0)
_, test_acc = saved_model.evaluate(testX, testy, verbose=0)
print('Train: %.3f, Test: %.3f' % (train_acc, test_acc))

运行这个例子,我们可以看到来自模型检查点回调的详细输出,包括保存新的最佳模型和没有观察到改进。

我们可以看到,在这次运行中,最好的模型出现在纪元 879。

:考虑到算法或评估程序的随机性,或数值准确率的差异,您的结果可能会有所不同。考虑运行该示例几次,并比较平均结果。

同样,我们可以看到早期停止耐心地持续到纪元 1000 年之后。注意历元 880 +耐心 200 不是历元 1044。回想一下,早期停止是监控验证数据集的损失,模型检查点是基于准确性保存模型。因此,早停的耐心始于 880 年以外的时代。

...
Epoch 00878: val_acc did not improve from 0.92857
Epoch 00879: val_acc improved from 0.92857 to 0.94286, saving model to best_model.h5
Epoch 00880: val_acc did not improve from 0.94286
...
Epoch 01042: val_acc did not improve from 0.94286
Epoch 01043: val_acc did not improve from 0.94286
Epoch 01044: val_acc did not improve from 0.94286
Epoch 01044: early stopping
Train: 1.000, Test: 0.943

在这种情况下,我们在测试数据集上看不到模型准确率有任何进一步的提高。然而,我们遵循了一个良好的做法。

为什么不监控验证准确性以提前停止?

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

扩展ˌ扩张

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

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

如果你探索这些扩展,我很想知道。

进一步阅读

如果您想更深入地了解这个主题,本节将提供更多资源。

邮件

应用程序接口

摘要

在本教程中,您发现了 Keras API,用于将早期停止添加到过度深度学习神经网络模型中。

具体来说,您了解到:

  • 如何使用 Keras API 在训练过程中监控模型的表现。
  • 如何使用 Keras API 创建和配置早期停止和模型检查点回调。
  • 如何通过在现有模型中增加提前停止来减少过拟合?

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

数据集大小对深度学习模型技巧和表现评估的影响

原文:https://machinelearningmastery.com/impact-of-dataset-size-on-deep-learning-model-skill-and-performance-estimates/

最后更新于 2020 年 8 月 25 日

监督学习是具有挑战性的,尽管这种挑战的深度经常被学习,然后被遗忘或故意忽略。

情况肯定是这样的,因为在这个挑战上停留太久可能会导致悲观的前景。尽管面临挑战,我们仍继续使用监督学习算法,它们在实践中表现良好。

监督学习挑战的基础是以下问题:

  • 从输入到输出合理地逼近未知的底层映射函数需要多少数据?
  • 需要多少数据来合理地估计映射函数的近似值的表现?

一般来说,众所周知,训练数据太少会导致近似性差。过度约束的模型会使小的训练数据集不足,而欠约束的模型反过来可能会使训练数据过多,两者都会导致较差的表现。太少的测试数据将导致对模型表现的乐观和高方差估计。

关键是要用工作实例将这个“常识”具体化。

在这篇文章中,我们将通过一个详细的案例研究来开发一个关于简单的两类分类问题的多层感知器神经网络。你会发现,在实践中,我们没有足够的数据来学习映射函数或评估模型,然而像神经网络这样的监督学习算法仍然非常有效。

  • 如何分析两个圆的分类问题并测量神经网络学习算法引入的方差?
  • 训练数据集大小的变化如何直接影响由神经网络近似的映射函数的质量。
  • 测试数据集大小的变化如何直接影响拟合神经网络模型表现的估计质量。

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

我们开始吧。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

数据集大小对深度学习模型技能和表现评估的影响
图片由 Eneas De Troya 提供,保留部分权利。

教程概述

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

  1. 监督学习的挑战
  2. 圆问题导论
  3. 神经网络模型方差
  4. 研究测试准确率与训练集大小的关系
  5. 研究测试集大小与测试集准确性

圆问题导论

作为我们探索的基础,我们将使用一个非常简单的两类或二分类问题。

Sklearn 库提供了 make_circles()函数,该函数可用于创建具有规定样本数和统计噪声的二进制分类问题。

每个示例都有两个输入变量,用于定义点在二维平面上的 xy 坐标。这两个类的点排列成两个同心圆(它们有相同的中心)。

数据集中的点数由参数指定,其中一半将从每个圆中绘制。通过定义噪声标准偏差的“噪声”参数对点进行采样时,可以添加高斯噪声,其中 0.0 表示没有噪声或从圆圈中精确绘制的点。伪随机数发生器的种子可以通过“随机状态参数指定,该参数允许每次调用函数时对完全相同的点进行采样。

下面的示例从两个没有噪声且值为 1 的圆生成 100 个示例来播种伪随机数发生器。

# example of generating circles dataset
from sklearn.datasets import make_circles
# generate circles
X, y = make_circles(n_samples=100, noise=0.0, random_state=1)
# show size of the dataset
print(X.shape, y.shape)
# show first few examples
for i in range(5):
	print(X[i], y[i])

运行该示例会生成点,并打印样本的输入( X )和输出( y )组件的形状。我们可以看到,对于 xy 坐标,有 100 个输入示例,每个示例有两个特征,输出变量或类值的 100 个匹配示例有 1 个变量。

显示了数据集的前五个示例。我们可以看到输入变量的 xy 分量以 0.0 为中心,并且有边界[-1,1]。我们还可以看到,类值是 0 或 1 的整数,并且示例在类之间进行了混合。

(100, 2) (100,)
[-0.6472136 -0.4702282] 1
[-0.34062343 -0.72386164] 1
[-0.53582679 -0.84432793] 0
[-0.5831749  -0.54763768] 1
[ 0.50993919 -0.61641059] 1

绘制数据集

我们可以重新运行该示例,并在给定相同伪随机数发生器种子的情况下,始终获得相同的“随机生成的”点。

下面的示例生成相同的点,并使用散点图绘制样本的输入变量。我们可以使用散点()matplotlib 函数来创建图,并将第一个变量用于 x 坐标,第二个变量用于图中的 y 坐标传递到 X 数组的所有行中。

# example of creating a scatter plot of the circles dataset
from sklearn.datasets import make_circles
from matplotlib import pyplot
# generate circles
X, y = make_circles(n_samples=100, noise=0.0, random_state=1)
# scatter plot of generated dataset
pyplot.scatter(X[:, 0], X[:, 1])
pyplot.show()

运行该示例会创建一个散点图,清晰显示数据集的同心圆。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

圆形数据集输入变量的散点图

我们可以重新创建散点图,而是绘制 0 类蓝色的所有输入样本和 1 类红色的所有点。

我们可以使用 where() NumPy 函数选择 y 数组中具有给定值的样本的索引,然后使用这些索引选择 X 数组中的行。完整的例子如下。

#  scatter plot of the circles dataset with points colored by class
from sklearn.datasets import make_circles
from numpy import where
from matplotlib import pyplot
# generate circles
X, y = make_circles(n_samples=100, noise=0.0, random_state=1)
# select indices of points with each class label
zero_ix, one_ix = where(y == 0), where(y == 1)
# points for class zero
pyplot.scatter(X[zero_ix, 0], X[zero_ix, 1], color='red')
# points for class one
pyplot.scatter(X[one_ix, 0], X[one_ix, 1], color='blue')
pyplot.show()

运行该示例,我们可以看到类 0 的样本是蓝色的内圆,类的样本属于红色的外圆。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

按类别值着色的圆形数据集的输入变量散点图

具有不同噪声的图

所有真实数据都有统计噪声。更多的统计噪声意味着学习算法将输入变量映射到输出或目标变量的问题更具挑战性。

圆形数据集允许我们通过“噪声”参数模拟噪声对样本的添加。

我们可以创建一个名为*散点图 _ 圆 _ 问题()*的新函数,该函数创建一个具有给定噪声量的数据集,并创建一个散点图,其中的点按其类值着色。

# create a scatter plot of the circles dataset with the given amount of noise
def scatter_plot_circles_problem(noise_value):
	# generate circles
	X, y = make_circles(n_samples=100, noise=noise_value, random_state=1)
	# select indices of points with each class label
	zero_ix, one_ix = where(y == 0), where(y == 1)
	# points for class zero
	pyplot.scatter(X[zero_ix, 0], X[zero_ix, 1], color='red')
	# points for class one
	pyplot.scatter(X[one_ix, 0], X[one_ix, 1], color='blue')

我们可以用不同数量的噪声多次调用这个函数,看看对问题复杂性的影响。

我们将通过 4 乘 4 矩阵中的子图()matplotlib 函数创建四个散点图作为子图,噪声值为[0.0,0.1,0.2,0.3]。下面列出了完整的示例。

# scatter plots of the circles dataset with varied amounts of noise
from sklearn.datasets import make_circles
from numpy import where
from matplotlib import pyplot

# create a scatter plot of the circles dataset with the given amount of noise
def scatter_plot_circles_problem(noise_value):
	# generate circles
	X, y = make_circles(n_samples=100, noise=noise_value, random_state=1)
	# select indices of points with each class label
	zero_ix, one_ix = where(y == 0), where(y == 1)
	# points for class zero
	pyplot.scatter(X[zero_ix, 0], X[zero_ix, 1], color='red')
	# points for class one
	pyplot.scatter(X[one_ix, 0], X[one_ix, 1], color='blue')

# vary noise and plot
values = [0.0, 0.1, 0.2, 0.3]
for i in range(len(values)):
	value = 220 + (i+1)
	pyplot.subplot(value)
	scatter_plot_circles_problem(values[i])
pyplot.show()

运行该示例,创建了一个具有四个子情节的绘图,分别针对左上角、右上角、左下角和右下角的四个不同噪声值[0.0、0.1、0.2、0.3]中的每一个。

我们可以看到,少量的噪声 0.1 使问题具有挑战性,但仍然可以区分。0.0 的噪声值是不现实的,如此完美的数据集不需要机器学习。0.2 的噪声值会使问题变得非常有挑战性,而 0.3 的值可能会使问题变得太有挑战性而无法学习。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

根据统计噪声量变化的圆形数据集的四个散点图

不同样本量的图

我们可以用不同数量的样本创建一个类似的问题图。

更多的样本给了学习算法更多的机会去理解输入到输出的潜在映射,进而得到一个更好的模型。

我们可以更新*散点图圆问题()*函数,把要生成的样本数作为自变量,也可以把噪声量作为自变量,将噪声设置为默认值 0.1,这样会让问题有噪声,但不会太吵。

# create a scatter plot of the circles problem
def scatter_plot_circles_problem(n_samples, noise_value=0.1):
	# generate circles
	X, y = make_circles(n_samples=n_samples, noise=noise_value, random_state=1)
	# select indices of points with each class label
	zero_ix, one_ix = where(y == 0), where(y == 1)
	# points for class zero
	pyplot.scatter(X[zero_ix, 0], X[zero_ix, 1], color='red')
	# points for class one
	pyplot.scatter(X[one_ix, 0], X[one_ix, 1], color='blue')

我们可以调用这个函数来创建多个具有不同点数的散点图,在两个圆或类之间均匀分布。

我们将使用以下大小的样本[50,100,500,1000]来尝试问题的版本。下面列出了完整的示例。

# scatter plots of the circles dataset with varied sample sizes
from sklearn.datasets import make_circles
from numpy import where
from matplotlib import pyplot

# create a scatter plot of the circles problem
def scatter_plot_circles_problem(n_samples, noise_value=0.1):
	# generate circles
	X, y = make_circles(n_samples=n_samples, noise=noise_value, random_state=1)
	# select indices of points with each class label
	zero_ix, one_ix = where(y == 0), where(y == 1)
	# points for class zero
	pyplot.scatter(X[zero_ix, 0], X[zero_ix, 1], color='red')
	# points for class one
	pyplot.scatter(X[one_ix, 0], X[one_ix, 1], color='blue')

# vary sample size and plot
values = [50, 100, 500, 1000]
for i in range(len(values)):
	value = 220 + (i+1)
	pyplot.subplot(value)
	scatter_plot_circles_problem(values[i])
pyplot.show()

运行该示例会创建一个包含四个子情节的绘图,分别针对左上角、右上角、左下角和右下角不同大小的样本[50、100、500、1000]各一个。

我们可以看到,50 个例子可能太少,甚至 100 分看起来也不足以真正学会这个问题。这些图表明,500 个和 1000 个例子可能更容易学习,尽管隐藏了许多“异常值”导致两个圆圈重叠的事实。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

圆形数据集的四个散点图因样本量而异

神经网络模型方差

我们可以用神经网络来模拟圆的问题。

具体来说,我们可以训练一个多层感知器模型,简称 MLP,为模型提供从圆问题生成的输入和输出示例。一旦学会,我们可以通过使用模型对新的例子进行预测并评估其准确性来评估模型对问题的学习程度。

我们可以使用 Keras 深度学习库为该问题开发一个小 MLP,该库有两个输入、隐藏层中的 25 个节点和一个输出。修正的线性激活函数可以用于隐藏层中的节点。由于该问题是一个二分类问题,因此该模型可以使用输出层上的 sigmoid 激活函数来预测样本属于类别 0 或 1 的概率。

可以使用称为 Adam 的小批量随机梯度下降的有效版本来训练模型,其中模型中的每个权重都有其自己的自适应学习率。二元交叉熵损失函数可以用作优化的基础,其中较小的损失值表示更好的模型拟合。

# define model
model = Sequential()
model.add(Dense(25, input_dim=2, activation='relu'))
model.add(Dense(1, activation='sigmoid'))
model.compile(loss='binary_crossentropy', optimizer='adam', metrics=['accuracy'])

我们需要从圆问题生成的样本来训练模型,并且需要一个单独的测试集来训练模型,该测试集可用于估计模型在对新数据进行预测时的平均表现。

下面的 create_dataset() 函数将创建这些给定大小的训练和测试集,并使用 0.1 的默认噪声。

# create a test dataset
def create_dataset(n_train, n_test, noise=0.1):
	# generate samples
	n_samples = n_train + n_test
	X, y = make_circles(n_samples=n_samples, noise=noise, random_state=1)
	# split into train and test
	trainX, testX = X[:n_train, :], X[n_train:, :]
	trainy, testy = y[:n_train], y[n_train:]
	# return samples
	return trainX, trainy, testX, testy

我们可以调用这个函数来准备分成输入和输出组件的训练和测试集。

# create dataset
trainX, trainy, testX, testy = create_dataset(500, 500)

一旦我们定义了数据集和模型,我们就可以训练模型了。我们将在训练数据集上训练模型 500 个时期。

# fit model
history = model.fit(trainX, trainy, epochs=500, verbose=0)

一旦拟合,我们使用模型对测试集的输入示例进行预测,并将它们与测试集的真实输出值进行比较,然后计算准确性分数。

evaluate() 函数执行此操作,返回测试数据集上模型的损失和准确率。我们可以忽略损失并显示准确率,以了解模型在将随机示例从圆形域映射到 0 类或 1 类方面的表现。

# evaluate the model
_, test_acc = model.evaluate(testX, testy, verbose=0)
print('Test Accuracy: %.3f' % (test_acc*100))

将所有这些结合在一起,下面列出了完整的示例。

# mlp evaluated on the circles dataset
from sklearn.datasets import make_circles
from keras.layers import Dense
from keras.models import Sequential

# create a test dataset
def create_dataset(n_train, n_test, noise=0.1):
	# generate samples
	n_samples = n_train + n_test
	X, y = make_circles(n_samples=n_samples, noise=noise, random_state=1)
	# split into train and test
	trainX, testX = X[:n_train, :], X[n_train:, :]
	trainy, testy = y[:n_train], y[n_train:]
	# return samples
	return trainX, trainy, testX, testy

# create dataset
trainX, trainy, testX, testy = create_dataset(500, 500)
# define model
model = Sequential()
model.add(Dense(25, input_dim=2, activation='relu'))
model.add(Dense(1, activation='sigmoid'))
model.compile(loss='binary_crossentropy', optimizer='adam', metrics=['accuracy'])
# fit model
history = model.fit(trainX, trainy, epochs=500, verbose=0)
# evaluate the model
_, test_acc = model.evaluate(testX, testy, verbose=0)
print('Test Accuracy: %.3f' % (test_acc*100))

运行该示例会生成数据集,在训练数据集上拟合模型,并在测试数据集上评估模型。

:考虑到算法或评估程序的随机性,或数值准确率的差异,您的结果可能会有所不同。考虑运行该示例几次,并比较平均结果。

在这种情况下,模型达到了大约 84.4%的估计准确率。

Test Accuracy: 84.400

随机学习算法

这个例子的一个问题是你的结果可能会有所不同。

每次运行示例时,您可能会看到不同的估计准确率。

再次运行该示例,我看到估计准确率约为 84.8%。同样,您的具体结果可能会有所不同。

Test Accuracy: 84.800

每次运行示例时,数据集中的示例都是相同的。这是因为我们在创建样本时修复了伪随机数发生器。样本确实有噪音,但我们每次都收到相同的噪音。

神经网络是一种非线性学习算法,意味着它们可以学习输入变量和输出变量之间复杂的非线性关系。它们可以逼近具有挑战性的非线性函数。

因此,我们称神经网络模型具有低偏差和高方差。它们的偏差很小,因为该方法对映射函数的数学函数形式几乎不做假设。它们具有很高的方差,因为它们对用于训练模型的具体例子很敏感。训练示例中的差异可能意味着非常不同的结果模型,进而具有不同的技能。

尽管神经网络是一种高方差低偏差的方法,但这并不是在相同生成的数据点上运行相同算法时估计表现差异的原因。

相反,由于学习算法是随机的,我们在多次运行中看到了表现的差异。

学习算法使用随机性元素来帮助模型平均学习如何在训练数据集中将输入变量映射到输出变量。随机性的示例包括用于初始化模型权重的小随机值,以及在每个训练时期之前对训练数据集中的示例进行随机排序。

这是有用的随机性,因为它允许模型自动“”发现”映射函数的好解。

这可能会令人沮丧,因为每次运行学习算法时,它经常会找到不同的解决方案,有时解决方案之间的差异很大,导致在对新数据进行预测时模型的估计表现存在差异。

平均模型表现

我们可以通过总结该方法在多次运行中的表现来抵消特定神经网络发现的解决方案中的差异。

这包括在同一数据集上多次拟合同一算法,但允许每次运行算法时,学习算法中使用的随机性发生变化。每次运行时,在相同的测试集上评估模型,并记录分数。在所有重复结束时,使用平均值和标准偏差总结分数的分布。

模型在多次运行中的平均表现给出了特定数据集上特定模型的平均表现。分数的分布或标准差给出了学习算法引入的方差的概念。

我们可以将单个 MLP 的评估转移到一个获取数据集并返回测试集准确率的函数。下面的 evaluate_model() 函数实现了这个行为。

# evaluate an mlp model
def evaluate_model(trainX, trainy, testX, testy):
	# define model
	model = Sequential()
	model.add(Dense(25, input_dim=2, activation='relu'))
	model.add(Dense(1, activation='sigmoid'))
	model.compile(loss='binary_crossentropy', optimizer='adam', metrics=['accuracy'])
	# fit model
	model.fit(trainX, trainy, epochs=500, verbose=0)
	# evaluate the model
	_, test_acc = model.evaluate(testX, testy, verbose=0)
	return test_acc

然后我们可以多次调用这个函数,比如 10 次、30 次或更多次。

考虑到大数定律,更多的运行将意味着更精确的估计。为了保持跑步时间适中,我们将重复跑步 10 次。

# evaluate model
n_repeats = 10
scores = list()
for i in range(n_repeats):
	# evaluate model
	score = evaluate_model(trainX, trainy, testX, testy)
	# store score
	scores.append(score)
	# summarize score for this run
	print('>%d: %.3f' % (i+1, score*100))

然后,在这些运行结束时,将报告分数的平均值和标准偏差。我们也可以通过箱线图()matplotlib 函数使用箱线图和触须图来总结分布。

# report distribution of scores
mean_score, std_score = mean(scores)*100, std(scores)*100
print('Score Over %d Runs: %.3f (%.3f)' % (n_repeats, mean_score, std_score))
# plot distribution
pyplot.boxplot(scores)
pyplot.show()

将所有这些元素结合在一起,下面列出了在圆形数据集上重复评估 MLP 模型的示例。

# repeated evaluation of mlp on the circles dataset
from sklearn.datasets import make_circles
from keras.layers import Dense
from keras.models import Sequential
from numpy import mean
from numpy import std
from matplotlib import pyplot

# create a test dataset
def create_dataset(n_train, n_test, noise=0.1):
	# generate samples
	n_samples = n_train + n_test
	X, y = make_circles(n_samples=n_samples, noise=noise, random_state=1)
	# split into train and test
	trainX, testX = X[:n_train, :], X[n_train:, :]
	trainy, testy = y[:n_train], y[n_train:]
	# return samples
	return trainX, trainy, testX, testy

# evaluate an mlp model
def evaluate_model(trainX, trainy, testX, testy):
	# define model
	model = Sequential()
	model.add(Dense(25, input_dim=2, activation='relu'))
	model.add(Dense(1, activation='sigmoid'))
	model.compile(loss='binary_crossentropy', optimizer='adam', metrics=['accuracy'])
	# fit model
	model.fit(trainX, trainy, epochs=500, verbose=0)
	# evaluate the model
	_, test_acc = model.evaluate(testX, testy, verbose=0)
	return test_acc

# create dataset
trainX, trainy, testX, testy = create_dataset(500, 500)
# evaluate model
n_repeats = 10
scores = list()
for i in range(n_repeats):
	# evaluate model
	score = evaluate_model(trainX, trainy, testX, testy)
	# store score
	scores.append(score)
	# summarize score for this run
	print('>%d: %.3f' % (i+1, score*100))
# report distribution of scores
mean_score, std_score = mean(scores)*100, std(scores)*100
print('Score Over %d Runs: %.3f (%.3f)' % (n_repeats, mean_score, std_score))
# plot distribution
pyplot.boxplot(scores)
pyplot.show()

运行示例首先报告模型在每次重复评估中的得分。

:考虑到算法或评估程序的随机性,或数值准确率的差异,您的结果可能会有所不同。考虑运行该示例几次,并比较平均结果。

重复结束时,平均分数约为 84.7%,标准偏差约为 0.5%。这意味着,对于在特定训练集上训练并在特定测试集上评估的特定模型,99%的运行将导致 83.2%到 86.2%之间的测试准确率,给定与平均值的三个标准偏差。

毫无疑问,10 的小样本量导致了这些估计的一些误差。

>1: 84.600
>2: 84.800
>3: 85.400
>4: 85.000
>5: 83.600
>6: 85.600
>7: 84.400
>8: 84.600
>9: 84.600
>10: 84.400
Score Over 10 Runs: 84.700 (0.531)

创建了测试准确度分数的方框图,显示了由方框表示的分数的中间 50%(称为四分位数范围),范围从略低于 84.5%到略低于 85%。

我们还可以看到,观察到的 83%的值可能是一个异常值,因为它被表示为一个点。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

MLP 圆问题测试准确率的盒须图

研究测试准确率与训练集大小的关系

给定固定数量的统计噪声和固定但合理配置的模型,学习圆问题需要多少个例子?

我们可以通过评估适合不同大小训练数据集的 MLP 模型的表现来研究这个问题。

作为一个基础,我们可以定义大量的例子,我们认为这些例子足以学习这个问题,比如 10 万个。我们可以将此作为训练示例数量的上限,并在测试集中使用这许多示例。我们将定义一个在这个数据集上表现良好的模型,作为有效地学习了两个圆问题的模型。

然后,我们可以通过用不同大小的训练数据集拟合模型来进行实验,并在测试集上评估它们的表现。

太少的例子将导致低的测试准确率,可能是因为所选择的模型超过了训练集或者训练集不足以代表问题。

太多的例子会导致好的,但可能比理想的测试准确率稍低,可能是因为所选的模型没有能力学习如此大的训练数据集的细微差别,或者数据集过度代表了问题。

训练数据集大小对模型测试准确性的线形图应该显示收益递减点的增长趋势,甚至可能是表现的最终轻微下降。

我们可以使用上一节中定义的 create_dataset() 函数来创建训练和测试数据集,并将测试集参数的大小设置为默认值 100,000 个示例,同时允许指定训练集的大小,并随每次调用而变化。重要的是,我们希望对每个不同大小的训练数据集使用相同的测试集。

# create train and test datasets
def create_dataset(n_train, n_test=100000, noise=0.1):
	# generate samples
	n_samples = n_train + n_test
	X, y = make_circles(n_samples=n_samples, noise=noise, random_state=1)
	# split into train and test, first n for test
	trainX, testX = X[n_test:, :], X[:n_test, :]
	trainy, testy = y[n_test:], y[:n_test]
	# return samples
	return trainX, trainy, testX, testy

我们可以直接使用上一节中相同的 evaluate_model() 函数来拟合和评估给定列车和测试集上的 MLP 模型。

# evaluate an mlp model
def evaluate_model(trainX, trainy, testX, testy):
	# define model
	model = Sequential()
	model.add(Dense(25, input_dim=2, activation='relu'))
	model.add(Dense(1, activation='sigmoid'))
	model.compile(loss='binary_crossentropy', optimizer='adam', metrics=['accuracy'])
	# fit model
	model.fit(trainX, trainy, epochs=500, verbose=0)
	# evaluate the model
	_, test_acc = model.evaluate(testX, testy, verbose=0)
	return test_acc

我们可以创建一个新的函数来执行给定模型的重复评估,以解释随机学习算法。

下面的 evaluate_size() 函数将训练集的大小以及重复次数作为参数,默认为 5 次,以保持运行时间下降。创建 create_dataset() 函数来创建训练集和测试集,然后重复调用 evaluate_model() 函数来评估模型。然后,该函数返回重复得分列表。

# repeated evaluation of mlp model with dataset of a given size
def evaluate_size(n_train, n_repeats=5):
	# create dataset
	trainX, trainy, testX, testy = create_dataset(n_train)
	# repeat evaluation of model with dataset
	scores = list()
	for _ in range(n_repeats):
		# evaluate model for size
		score = evaluate_model(trainX, trainy, testX, testy)
		scores.append(score)
	return scores

然后可以重复调用这个函数。我猜想,在 1000 到 10000 个问题的例子之间的某个地方就足以学会这个问题,其中足够意味着测试准确率只有很小的分数差异。

因此,我们将调查 100、1,000、5,000 和 10,000 个示例的训练集大小。将报告每种测试规模的平均测试准确率,以便了解进展情况。

# define dataset sizes to evaluate
sizes = [100, 1000, 5000, 10000]
score_sets, means = list(), list()
for n_train in sizes:
	# repeated evaluate model with training set size
	scores = evaluate_size(n_train)
	score_sets.append(scores)
	# summarize score for size
	mean_score = mean(scores)
	means.append(mean_score)
	print('Train Size=%d, Test Accuracy %.3f' % (n_train, mean_score*100))

在运行结束时,将创建一个线图来显示列车组大小和模型测试组准确率之间的关系。我们预计会看到一个指数曲线,从低准确率到收益递减点。

还创建了每个测试集大小的分数分布的方框图和触须图。随着训练集大小的增加,我们预计测试准确率的分布会缩小。

下面列出了完整的示例。

# study of training set size for an mlp on the circles problem
from sklearn.datasets import make_circles
from keras.layers import Dense
from keras.models import Sequential
from numpy import mean
from matplotlib import pyplot

# create train and test datasets
def create_dataset(n_train, n_test=100000, noise=0.1):
	# generate samples
	n_samples = n_train + n_test
	X, y = make_circles(n_samples=n_samples, noise=noise, random_state=1)
	# split into train and test, first n for test
	trainX, testX = X[n_test:, :], X[:n_test, :]
	trainy, testy = y[n_test:], y[:n_test]
	# return samples
	return trainX, trainy, testX, testy

# evaluate an mlp model
def evaluate_model(trainX, trainy, testX, testy):
	# define model
	model = Sequential()
	model.add(Dense(25, input_dim=2, activation='relu'))
	model.add(Dense(1, activation='sigmoid'))
	model.compile(loss='binary_crossentropy', optimizer='adam', metrics=['accuracy'])
	# fit model
	model.fit(trainX, trainy, epochs=500, verbose=0)
	# evaluate the model
	_, test_acc = model.evaluate(testX, testy, verbose=0)
	return test_acc

# repeated evaluation of mlp model with dataset of a given size
def evaluate_size(n_train, n_repeats=5):
	# create dataset
	trainX, trainy, testX, testy = create_dataset(n_train)
	# repeat evaluation of model with dataset
	scores = list()
	for _ in range(n_repeats):
		# evaluate model for size
		score = evaluate_model(trainX, trainy, testX, testy)
		scores.append(score)
	return scores

# define dataset sizes to evaluate
sizes = [100, 1000, 5000, 10000]
score_sets, means = list(), list()
for n_train in sizes:
	# repeated evaluate model with training set size
	scores = evaluate_size(n_train)
	score_sets.append(scores)
	# summarize score for size
	mean_score = mean(scores)
	means.append(mean_score)
	print('Train Size=%d, Test Accuracy %.3f' % (n_train, mean_score*100))
# summarize relationship of train size to test accuracy
pyplot.plot(sizes, means, marker='o')
pyplot.show()
# plot distributions of test accuracy for train size
pyplot.boxplot(score_sets, labels=sizes)
pyplot.show()

在现代硬件上运行该示例可能需要几分钟时间。

:考虑到算法或评估程序的随机性,或数值准确率的差异,您的结果可能会有所不同。考虑运行该示例几次,并比较平均结果。

报告了每个训练集大小的平均模型表现,如我们所料,随着训练集的增加,测试准确率稳步提高。我们还看到平均模型表现从 5,000 个示例下降到 10,000 个示例,这很可能突出了数据样本中的差异已经超过了所选模型配置的容量(层数和节点数)。

Train Size=100, Test Accuracy 72.041
Train Size=1000, Test Accuracy 83.719
Train Size=5000, Test Accuracy 84.062
Train Size=10000, Test Accuracy 84.025

创建测试准确率与训练集大小的线图。

我们可以看到测试准确率从 100 个示例急剧增加到 1000 个示例,之后表现似乎趋于平稳。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

圆问题上 MLP 模型的训练集大小与测试集准确率的线图

创建了一个方框和触须图,显示了每个大小的训练数据集的测试准确度分数的分布。正如预期的那样,我们可以看到,随着训练集大小的增加,测试集准确性分数的分布急剧缩小,尽管在给定所选比例的情况下,在图中仍然很小。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

用不同大小的训练集训练的多层线性规划在圆问题上的测试集准确率的盒须图

结果表明,所选的 MLP 模型配置可以通过 1,000 个示例很好地学习问题,通过 5,000 个和 10,000 个示例可以看到相当适度的改进。也许有一个 2500 个例子的最佳点,用不到 5000 个例子就能得到 84%的测试集准确率。

随着越来越多的数据被提供给模型,神经网络的表现可以不断提高,但是模型的容量必须被调整以支持数据的增加。最终,会有一个收益递减点,在这个点上,更多的数据将无法提供更多关于如何最好地建模映射问题的洞察。对于更简单的问题,比如两个圆,这个点会比更复杂的问题更快达到,比如对象的照片分类。

这项研究强调了应用机器学习的一个基本方面,具体来说,你需要足够多的问题示例来学习未知底层映射函数的有用近似。

我们几乎从来没有丰富或过多的训练数据。因此,我们的重点通常是如何最经济地使用可用数据,以及如何避免过拟合训练数据集中存在的统计噪声。

研究测试集大小与测试集准确性

给定一个固定的模型和一个固定的训练数据集,需要多少测试数据来实现模型表现的准确估计?

我们可以通过用固定大小的训练集拟合 MLP,并用不同大小的测试集评估模型来研究这个问题。

我们可以使用与上一节中的研究大致相同的策略。我们将把训练集的大小固定为 1000 个例子,因为当对 100000 个例子进行评估时,它产生了一个估计准确率约为 83.7%的合理有效的模型。我们希望有一个更小的测试集大小可以合理地接近这个值。

可以更新 create_dataset() 函数来指定测试集大小,并使用默认的 1000 个示例作为训练集大小。重要的是,每次测试集的大小发生变化时,训练集都会使用相同的 1000 个示例。

# create dataset
def create_dataset(n_test, n_train=1000, noise=0.1):
	# generate samples
	n_samples = n_train + n_test
	X, y = make_circles(n_samples=n_samples, noise=noise, random_state=1)
	# split into train and test, first n for test
	trainX, testX = X[:n_train, :], X[n_train:, :]
	trainy, testy = y[:n_train], y[n_train:]
	# return samples
	return trainX, trainy, testX, testy

我们可以使用同样的 fit_model() 函数来拟合模型。因为我们使用相同的训练数据集和不同的测试数据集,我们可以创建和拟合模型一次,并为每个不同大小的测试集重用它们。在这种情况下,我们将在同一训练数据集上拟合 10 个模型来模拟 10 次重复。

# create fixed training dataset
trainX, trainy, _, _ = create_dataset(10)
# fit one model for each repeat
n_repeats = 10
models = [fit_model(trainX, trainy) for _ in range(n_repeats)]
print('Fit %d models' % n_repeats)

一旦适合,我们就可以使用给定大小的测试数据集来评估每个模型。下面的 evaluate_test_set_size() 函数实现了这一行为,返回拟合模型列表和给定测试集大小的测试集准确度分数列表。

# evaluate a test set of a given size on the fit models
def evaluate_test_set_size(models, n_test):
	# create dataset
	_, _, testX, testy = create_dataset(n_test)
	scores = list()
	for model in models:
		# evaluate the model
		_, test_acc = model.evaluate(testX, testy, verbose=0)
		scores.append(test_acc)
	return scores

我们将用 100、1,000、5,000 和 10,000 个例子来评估四个不同大小的测试集。然后,我们可以报告每个大小的测试集的平均分数,并创建相同的直线、方框和触须图。

# define test set sizes to evaluate
sizes = [100, 1000, 5000, 10000]
score_sets, means = list(), list()
for n_test in sizes:
	# evaluate a test set of a given size on the models
	scores = evaluate_test_set_size(models, n_test)
	score_sets.append(scores)
	# summarize score for size
	mean_score = mean(scores)
	means.append(mean_score)
	print('Test Size=%d, Test Accuracy %.3f' % (n_test, mean_score*100))
# summarize relationship of test size to test accuracy
pyplot.plot(sizes, means, marker='o')
pyplot.show()
# plot distributions of test size to test accuracy
pyplot.boxplot(score_sets, labels=sizes)
pyplot.show()

将这些元素结合在一起,下面列出了完整的示例。

# study of test set size for an mlp on the circles problem
from sklearn.datasets import make_circles
from keras.layers import Dense
from keras.models import Sequential
from numpy import mean
from matplotlib import pyplot

# create dataset
def create_dataset(n_test, n_train=1000, noise=0.1):
	# generate samples
	n_samples = n_train + n_test
	X, y = make_circles(n_samples=n_samples, noise=noise, random_state=1)
	# split into train and test, first n for test
	trainX, testX = X[:n_train, :], X[n_train:, :]
	trainy, testy = y[:n_train], y[n_train:]
	# return samples
	return trainX, trainy, testX, testy

# fit an mlp model
def fit_model(trainX, trainy):
	# define model
	model = Sequential()
	model.add(Dense(25, input_dim=2, activation='relu'))
	model.add(Dense(1, activation='sigmoid'))
	model.compile(loss='binary_crossentropy', optimizer='adam', metrics=['accuracy'])
	# fit model
	model.fit(trainX, trainy, epochs=500, verbose=0)
	return model

# evaluate a test set of a given size on the fit models
def evaluate_test_set_size(models, n_test):
	# create dataset
	_, _, testX, testy = create_dataset(n_test)
	scores = list()
	for model in models:
		# evaluate the model
		_, test_acc = model.evaluate(testX, testy, verbose=0)
		scores.append(test_acc)
	return scores

# create fixed training dataset
trainX, trainy, _, _ = create_dataset(10)
# fit one model for each repeat
n_repeats = 10
models = [fit_model(trainX, trainy) for _ in range(n_repeats)]
print('Fit %d models' % n_repeats)
# define test set sizes to evaluate
sizes = [100, 1000, 5000, 10000]
score_sets, means = list(), list()
for n_test in sizes:
	# evaluate a test set of a given size on the models
	scores = evaluate_test_set_size(models, n_test)
	score_sets.append(scores)
	# summarize score for size
	mean_score = mean(scores)
	means.append(mean_score)
	print('Test Size=%d, Test Accuracy %.3f' % (n_test, mean_score*100))
# summarize relationship of test size to test accuracy
pyplot.plot(sizes, means, marker='o')
pyplot.show()
# plot distributions of test size to test accuracy
pyplot.boxplot(score_sets, labels=sizes)
pyplot.show()

运行该示例会报告每个不同大小测试集的测试集准确率,在同一数据集上训练的 10 个模型之间取平均值。

:考虑到算法或评估程序的随机性,或数值准确率的差异,您的结果可能会有所不同。考虑运行该示例几次,并比较平均结果。

如果我们将前一部分的 83.7%的结果作为对 100,000 个例子的评估,那么我们可以看到较小规模的测试集在这个评估的上下变化。

Fit 10 models
Test Size=100, Test Accuracy 86.100
Test Size=1000, Test Accuracy 82.410
Test Size=5000, Test Accuracy 84.228
Test Size=10000, Test Accuracy 83.760

创建测试集大小与测试集准确率的线图。

该图显示,100 个和 1000 个示例的较小测试集大小分别高估和低估了模型的准确性。测试集 5000 和 10000 的结果更接近,后者可能显示出最佳匹配。

这令人惊讶,因为天真的预期可能是,与训练集大小相同的测试集将是模型准确率的合理近似值,例如,就好像我们对 2000 个示例数据集执行了 50%/50%的分割。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

MLP 圆问题中测试集大小与测试集准确率的线图

方框图和触须图显示,较小的测试集显示了较大的分数分布,所有这些都是乐观的。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

圆问题上不同测试集尺寸的测试集准确率分布的盒须图

应该指出的是,我们并没有报告所选模型在从领域中随机抽取的示例上的平均表现。模型和例子是固定的,唯一的变化来源是学习算法。

该研究证明了模型的估计准确率对测试数据集的大小有多敏感。这是一个重要的考虑因素,因为通常很少考虑测试集的大小,使用 70%/30%或 80%/20%的常见分割进行训练/测试分割。

正如上一节所指出的,我们通常很少拥有足够的数据,并且在测试甚至验证数据集上花费宝贵的一部分数据通常很少被深入考虑。结果强调了交叉验证方法的重要性,例如省略交叉验证,允许模型对数据集中的每个示例进行测试预测,但计算成本如此之高,需要为数据集中的每个示例训练几乎一个模型。

在实践中,我们必须与太小而无法学习未知底层映射函数的训练数据集和太小而无法合理逼近模型在问题上的表现的测试数据集作斗争。

进一步阅读

如果您想更深入地了解这个主题,本节将提供更多资源。

摘要

在本教程中,您发现在实践中,我们没有足够的数据来学习映射函数或评估模型,然而像神经网络这样的监督学习算法仍然非常有效。

具体来说,您了解到:

  • 如何分析两个圆的分类问题并测量神经网络学习算法引入的方差?
  • 训练数据集大小的变化如何直接影响由神经网络近似的映射函数的质量。
  • 测试数据集大小的变化如何直接影响拟合神经网络模型表现的估计质量。

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

如何提高深度学习表现

原文:https://machinelearningmastery.com/improve-deep-learning-performance/

最后更新于 2019 年 8 月 6 日

*20 个技巧、窍门和技巧,你可以用来

对抗过度训练,获得更好的概括*

如何从深度学习模式中获得更好的表现?

这是我被问到的最常见的问题之一。

可以这样问:

如何提高准确率?

…也可以反过来说:

神经网络表现不好怎么办?

我经常用“回复,不太清楚,但是有很多想法。

然后我会列出我能想到的所有可能提升表现的想法。

我决定把我所有的想法都写在这篇文章里,而不是再写一遍那个列表。

这些想法不仅能帮助你进行深度学习,还能真正帮助任何机器学习算法。

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

这是一个很大的帖子,你可能想把它做成书签。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

如何提高深度学习表现
佩德罗·里贝罗·西莫斯摄,版权所有。

提高算法表现的思路

这个想法列表并不完整,但它是一个很好的开始。

我的目标是给你很多想法去尝试,希望是一两个你没有想到的想法。

你通常只需要一个好主意就能成功。

如果你从其中一个想法中得到结果,请在评论中告诉我。
我很想听听!

如果你还有一个想法或其中一个想法的延伸,让我知道,我和所有读者都会受益!这可能只是帮助其他人获得突破的一个想法。

我将列表分为 4 个子主题:

  1. ***用数据提升表现。*T3】
  2. ***通过算法提高表现。*T3】
  3. ***通过算法调整提高表现。*T3】
  4. ***通过集成提高表现。*T3】

收益往往越低越小。例如,一个新的问题框架或更多的数据通常会给你更多的回报,而不是调整你的最佳算法的参数。不一定,但总的来说。

我在博客中加入了许多教程的链接,相关网站的问题以及经典的神经网络常见问题解答上的问题。

有些想法是针对人工神经网络的,但许多是非常笼统的。足够一般,你可以用它们来激发用其他技术提高你的表现的想法。

让我们开始吧。

1.利用数据提高表现

通过更改您的培训数据和问题定义,您可以获得巨大的成功。也许即使是最大的赢家。

以下是我们将要介绍的内容的简短列表:

  1. 获取更多数据。
  2. 发明更多数据。
  3. 重新缩放您的数据。
  4. 转换您的数据。
  5. 特征选择。

1)获取更多数据

你能得到更多的训练数据吗?

模型的质量通常受到训练数据质量的限制。你想要你能为你的问题得到的最好的数据。

你也想要很多。

深度学习和其他现代非线性机器学习技术随着数据的增加而变得更好。特别是深度学习。这是让深度学习如此令人兴奋的要点之一。

看看下面这幅漫画:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

为什么是深度学习?
幻灯片由吴恩达制作,版权所有。

更多的数据并不总是有帮助,但它可以。如果给我选择的机会,我将获得更多关于它提供的可选性的数据。

相关:

2)发明更多数据

深度学习算法通常在有更多数据的情况下表现更好。

我们在最后一节提到了这一点。

如果你不能合理地获得更多的数据,你可以发明更多的数据。

  • 如果你的数据是数字向量,创建现有向量的随机修改版本。
  • 如果您的数据是图像,请创建现有图像的随机修改版本。
  • 如果你的数据是文本,你就明白了…

这通常被称为数据扩充或数据生成。

您可以使用生成模型。你也可以使用简单的技巧。

例如,使用照片图像数据,您可以通过随机移动和旋转现有图像来获得巨大的收益。如果在新数据中预期会有这种转换,那么它将提高模型对数据中这种转换的泛化能力。

这也与添加噪声有关,我们过去称之为添加抖动。它可以像正则化方法一样抑制训练数据集的过拟合。

相关:

3)重新缩放您的数据

这是速战速决。

使用神经网络时,传统的经验法则是:

将您的数据重新缩放到激活函数的范围内。

如果您正在使用 sigmoid 激活函数,请将您的数据重新缩放到 0 到-1 之间的值。如果使用双曲正切(tanh),请重新缩放至-1 到 1 之间的值。

这适用于输入(x)和输出(y)。例如,如果输出层上有一个 sigmoid 来预测二进制值,则将 y 值规范化为二进制。如果你正在使用 softmax,你仍然可以从 y 值正常化中获益。

这仍然是一个很好的经验法则,但我会更进一步。

我建议您创建几个不同版本的训练数据集,如下所示:

  • 归一化为 0 到 1。
  • 重新调整为-1 比 1。
  • 标准化。

然后评估你的模型在每个方面的表现。挑一个,然后加倍。

如果你改变激活功能,重复这个小实验。

在你的网络中积累的大价值并不好。此外,还有其他方法可以让网络中的数字保持较小,例如标准化激活和权重,但我们将在稍后查看这些技术。

相关:

4)转换您的数据

与上面建议的重新缩放相关,但工作更多。

你必须真正了解你的数据。想象一下。寻找异常值。

猜测每列的单变量分布。

  • 如果一个列看起来像一个偏斜的高斯,考虑用 Box-Cox 变换来调整偏斜。
  • 一列看起来像指数分布吗,考虑一个对数变换。
  • 一个专栏看起来有一些特色吗,但是它们被一些明显的东西打败了,试着平方,或者平方根。
  • 你能使一个特征离散或以某种方式装仓以更好地强调某个特征吗?

依靠你的直觉。尝试一下。

  • 你能用像 PCA 这样的投影方法对数据进行预处理吗?
  • 可以将多个属性聚合成一个值吗?
  • 你能用一个新的布尔标志揭示这个问题的一些有趣的方面吗?
  • 你能以其他方式探索时间或其他结构吗?

神经网络执行特征学习。他们可以做这些事情。

但是,如果你能更好地将问题的结构暴露给网络学习,他们也会更快地学习一个问题。

抽查数据或特定属性的许多不同转换,看看哪些有效,哪些无效。

相关:

5)特征选择

神经网络通常对不相关的数据具有鲁棒性。

他们将使用一个接近于零的权重,将非预测属性的贡献排除在外。

尽管如此,数据、权重和训练周期并不需要用来做出好的预测。

您能从数据中删除一些属性吗?

有很多特征选择方法和特征重要性方法可以让你知道要保留的特征和要引导的特征。

尝尝。全部试试。想法就是得到想法。

同样,如果你有时间,我会建议你用相同的网络评估几个不同的“观点”,看看它们是如何表现的。

  • 也许你可以用更少的功能做得同样好或更好。耶,快点!
  • 也许所有的特征选择方法都引导相同的特定特征子集。耶,关于无用功能的共识。
  • 也许一个选定的子集给了你一些关于你可以执行的进一步特征工程的想法。耶,更多的想法。

相关:

6)重构你的问题

远离你的问题。

你收集的观察结果是你提出问题的唯一方法吗?

也许还有别的办法。也许这个问题的其他框架能够更好地向学习器展示你的问题结构。

我真的很喜欢这个练习,因为它迫使你敞开心扉。这很难。尤其是如果你被投资了(自负!!!,时间,金钱)。

即使你只是列出 3 到 5 个备选框架并对它们进行折扣,至少你正在建立对所选方法的信心。

  • 也许你可以在一个窗口或者一个允许时间步长的方法中加入时间元素。
  • 也许你的分类问题可以变成回归问题,或者反过来。
  • 也许你的二进制输出可以变成 softmax 输出?
  • 也许你可以用一个子问题来代替。

在拿起工具之前仔细考虑问题是一个好主意,也是可能的,因为你对解决方案的投资较少。

然而,如果你被卡住了,这一个简单的练习可以提供一个思路。

此外,你不必扔掉你以前的任何作品。稍后参见集成部分。

相关:

2.通过算法提高表现

机器学习是关于算法的。

所有的理论和数学描述了从数据中学习决策过程的不同方法(如果我们把自己局限于预测建模的话)。

你为你的问题选择了深度学习。这真的是你能选择的最好的技术吗?

在这一节中,我们将在下一步深入探讨如何从您选择的深度学习方法中获得最大收益之前,仅涉及一些关于算法选择的想法。

这是一份简短的清单

  1. 抽查算法。
  2. 从文学中窃取。
  3. 重采样方法。

我们开始吧。

1)抽查算法

振作起来。

你不能事先知道哪种算法在你的问题上表现最好。

如果你知道,你可能不需要机器学习。

你收集了什么证据证明你选择的方法是一个好的选择?

让我们把这个难题翻过来。

当对所有可能的问题进行平均时,没有任何一种算法的表现比其他算法更好。所有算法都是平等的。这是对无免费午餐定理的发现的总结。

可能你选择的算法对你的问题不是最好的。

现在,我们并没有试图解决所有可能的问题,但是算法领域的新热点可能不是您特定数据集上的最佳选择。

我的建议是收集证据。想象有其他好的算法,并给他们一个公平的机会来解决你的问题。

抽查一套最好的方法,看看哪个好,哪个不好。

  • 评估一些线性方法,如逻辑回归和线性判别分析。
  • 评估一些树的方法,如 CART,随机森林和梯度提升。
  • 评估一些实例方法,如 SVM 和 kNN。
  • 评估其他一些神经网络方法,如 LVQ、MLP、美国有线电视新闻网、LSTM、混血儿等。

加倍关注表现最好的人,并通过进一步调整或数据准备来提高他们的机会。

根据您选择的深度学习方法对结果进行排名,它们如何比较?

也许你可以放弃深度学习模式,用简单得多、速度快得多的东西去训练,甚至是容易理解的东西。

相关:

2)从文学中窃取

挑选好方法的一个很好的捷径,就是从文学中窃取思想。

还有谁研究过像你这样的问题,他们用了什么方法。

查看论文、书籍、博客文章、问答网站、教程,谷歌扔给你的所有东西。

写下所有的想法,然后一路走来。

这不是关于复制研究,而是关于你没有想到的可能提升你表现的新想法。

发表的研究高度优化

有很多聪明人写了很多有趣的东西。为你需要的掘金挖掘这个伟大的图书馆。

相关:

3)重采样方法

你必须知道你的模型有多好。

你对模型表现的估计可靠吗?

深度学习方法训练缓慢。

这通常意味着我们不能使用黄金标准方法来估计模型的表现,例如 k 倍交叉验证。

  • 也许你正在使用一个简单的训练/测试分割,这是非常常见的。如果是这样,您需要确保分割代表问题。单变量统计和可视化是一个好的开始。
  • 也许你可以利用硬件来提高估计值。例如,如果您有一个集群或亚马逊网络服务帐户,我们可以并行训练n-模型,然后取结果的平均值和标准差,以获得更稳健的估计。
  • 也许您可以使用一个验证等待集来了解模型训练时的表现(对于提前停止很有用,请参见后面的内容)。
  • 也许您可以保留一个完全盲目的验证集,只有在执行了模型选择之后才使用它。

反过来,也许你可以缩小数据集,使用更强的重采样方法。

  • 与在整个数据集上训练的模型相比,在训练数据集的样本上训练的模型的表现可能有很强的相关性。也许您可以使用较小的数据集来执行模型选择和优化,然后在最后将最终技术扩展到整个数据集。
  • 也许你可以约束数据集,获取一个样本,并将其用于所有的模型开发。

你必须对你的模型的表现评估有完全的信心。

相关:

3.通过算法调整提高表现

肉在这里。

您通常可以通过抽查快速发现一两个表现良好的算法。从这些算法中获得最大收益可能需要几天、几周或几个月的时间。

这里有一些关于调整你的神经网络算法的想法,以便从中获得更多。

  1. 诊断。
  2. 重量初始化。
  3. 学习率。
  4. 激活功能。
  5. 网络拓扑。
  6. 批次和时代。
  7. 正规化。
  8. 优化和损失。
  9. 提前停止。

您可能需要多次(3-10 次或更多次)训练网络的给定“配置”,以获得对配置表现的良好估计。这可能适用于本节中您可以调整的所有方面。

关于超参数优化的好文章,请参阅:

1)诊断

如果你知道为什么表现不再提高,你会得到更好的表现。

你的模型是适配过度还是适配不足?

永远记住这个问题。一直都是。

它会做这样或那样的事情,只是程度不同。

深入了解模型学习行为的一个快速方法是在每个时期的训练和验证数据集上对其进行评估,并绘制结果。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

训练和验证数据集上的模型准确率图

  • 如果训练比验证集好得多,那么你可能是过拟合了,你可以使用正则化之类的技术。
  • 如果训练和验证都很低,你可能是适应不足,你可能会增加你的网络容量,训练更多或更长时间。
  • 如果当训练超过验证时出现拐点,你可以使用提前停止。

经常创建这些图,并研究它们,以便深入了解可以用来提高表现的不同技术。

这些图可能是你能创建的最有价值的诊断。

另一个有用的诊断是研究网络对与错的观察。

在一些问题上,这可以给你一些尝试的想法。

  • 也许你需要更多或更多的难以训练的例子。
  • 也许您可以移除训练数据集中易于建模的大样本。
  • 也许你可以使用专门的模型,专注于输入空间的不同清晰区域。

有关系的

2)权重初始化

经验法则曾经是:

使用小随机数初始化。

实际上,这可能还是足够好的。但是这对你的网络来说是最好的吗?

对于不同的激活函数也有启发式,但我不记得在实践中看到过多少不同。

保持网络固定,尝试每种初始化方案。

请记住,权重是您试图找到的模型的实际参数。有许多组权重可以提供良好的表现,但是您想要更好的表现。

  • 尝试所有不同的初始化方法,看看在所有其他方法保持不变的情况下,一种方法是否更好。
  • 尝试使用自动编码器等无监督方法进行预学习。
  • 试着采用一个现有的模型,为你的问题重新训练一个新的输入输出层(转移学习)。

请记住,改变权重初始化方法与激活函数甚至优化函数密切相关。

有关系的

3)学习率

调整学习率通常是有回报的。

以下是一些值得探索的想法:

  • 用非常大和非常小的学习率进行实验。
  • 网格从文献中搜索常见的学习率值,看看你能把网络推多远。
  • 尝试一种随着时代而降低的学习速度。
  • 尝试一种学习率,将每个固定数量的时代降低一个百分比。
  • 尝试添加动量项,然后将网格搜索学习率和动量结合起来。

更大的网络需要更多的训练,反之亦然。如果你增加更多的神经元或更多的层,增加你的学习率。

学习率与训练时期的数量、批量和优化方法相耦合。

相关:

4)激活功能

你可能应该使用整流器激活功能。

他们只是工作得更好。

在此之前,它是 sigmoid 和 tanh,然后是输出层的 softmax、linear 或 sigmoid。除非你知道自己在做什么,否则我不建议你尝试更多。

尝试这三种方法,重新调整数据以满足函数的限制。

显然,您希望为输出形式选择正确的传递函数,但请考虑探索不同的表示形式。

例如,对于回归问题,将二分类的 sigmoid 切换为线性,然后对输出进行后处理。这可能还需要将损失函数更改为更合适的值。有关这些方面的更多想法,请参见数据转换部分。
相关:

  • 为什么要使用激活功能?

5)网络拓扑

网络结构的改变会有回报。

你需要多少层和多少个神经元?

没人知道。没有人。别问了。

你必须为你的问题找到一个好的配置。实验。

  • 尝试一个有很多神经元的隐藏层(宽)。
  • 尝试每层神经元很少的深层网络(深层)。
  • 尝试以上的组合。
  • 尝试最近关于类似问题的论文中的架构。
  • 从书籍和论文中尝试拓扑模式(先扇出后进入)和经验法则(见下面的链接)。

这很难。更大的网络有更强的代表性,也许你需要它。

更多的层为从数据中学习到的抽象特征的分层重组提供了更多的机会。也许你需要这个。

后来的网络需要更多的训练,无论是在时代还是在学习速度上。相应调整。
相关:

这些链接会给你很多尝试的想法,它们确实适合我。

  • 我应该使用多少隐藏层?
  • 我应该使用多少隐藏单位?

6)批次和时代

批次大小定义了梯度和更新权重的频率。一个纪元就是将整个训练数据逐批暴露给网络。

你试验过不同的批量和时代数量吗?

以上,我们已经评论了学习率、网络规模和时代之间的关系。

在现代深度学习实现中,具有大时期大小和大量训练时期的小批量是常见的。

这可能会也可能不会解决你的问题。收集证据看看。

  • 尝试批处理大小等于训练数据大小,内存取决于(批处理学习)。
  • 尝试一个批量(在线学习)。
  • 尝试不同小批量(8、16、32、…)的网格搜索。
  • 试着为几个时代和很多个时代进行训练。

考虑几乎无限数量的时期和设置检查点,以获取迄今为止表现最好的模型,请进一步查看。

一些网络体系结构比其他网络体系结构对批量更敏感。我认为多层感知器通常对批量很敏感,而 LSTM 和 CNN 相当敏感,但这只是传闻。

有关系的

7)正规化

正则化是抑制训练数据过拟合的一个很好的方法。

热门的新正则化技术是,你试过吗?

drop 在训练过程中随机跳过神经元,迫使层中的其他人捡起松弛部分。简单有效。从丢弃开始。

  • 网格搜索不同的丢弃率。
  • 实验输入层、隐藏层和输出层的压降。

丢弃的想法也有延伸,你也可以玩像下降连接

还要考虑其他更传统的神经网络正则化技术,例如:

  • 重量衰减惩罚大重量。
  • 激活约束,惩罚大量激活。

尝试可以处罚的不同方面和可以适用的不同类型的处罚(L1、L2,两者都有)。

相关:

8)优化和损失

以前是随机梯度下降,现在有很多优化器。

你试验过不同的优化程序吗?

默认为随机梯度下降。先充分利用它,有不同的学习率、动力和学习率时间表。

许多更高级的优化方法提供了更多的参数、更多的复杂性和更快的收敛速度。这是好是坏,取决于你的问题。

为了最大限度地利用给定的方法,您确实需要深入了解每个参数的含义,然后网格搜索不同的值来解决您的问题。辛苦了。耗时。可能会有回报。

我发现较新/流行的方法可以更快地收敛,并快速了解给定网络拓扑的功能,例如:

您还可以探索其他优化算法,例如更传统的(Levenberg-Marquardt)和不太传统的(遗传算法)。其他方法可以为 SGD 和朋友提供很好的提炼起点。

要优化的损失函数可能与您试图解决的问题密切相关。

尽管如此,你经常有一些回旋余地(MSE 和 MAE 用于回归等)。)你可能会因为换出问题上的损失函数而受到小小的冲击。这也可能与您的输入数据的规模和正在使用的激活功能有关。

相关:

9)提前停止

一旦表现开始下降,您就可以停止学习。

这可以节省大量时间,甚至可以让您使用更复杂的重采样方法来评估模型的表现。

提前停止是一种抑制训练数据过拟合的正则化类型,要求您在每个时期监控模型在训练和持有的验证数据集上的表现。

一旦验证数据集的表现开始下降,就可以停止训练。

如果满足此条件(测量准确率损失),您也可以设置检查点来保存模型,并允许模型继续学习。

Checkpointing 允许你在不停止的情况下提前停止,让你在跑步结束时有几个模型可以选择。

相关:

4.使用集成提高表现

您可以组合来自多个模型的预测。

算法调优后,这是下一个大的改进领域。

事实上,您通常可以通过组合来自多个“足够好”的模型的预测来获得良好的表现,而不是来自多个高度调优(和脆弱)的模型。

我们将介绍三个您可能需要考虑的总体领域:

  1. 组合模型。
  2. 组合视图。
  3. 堆叠。

1)组合模型

不要选择一个模型,把它们结合起来。

如果您有多个不同的深度学习模型,每个模型在问题上都表现良好,请通过取平均值来组合它们的预测。

型号越不同越好。例如,您可以使用非常不同的网络拓扑或不同的技术。

如果每个模型都很有技巧,但方式不同,集成预测将更加稳健。

或者,你可以尝试相反的姿势。

每次训练网络时,用不同的权重初始化它,它就会收敛到一组不同的最终权重。多次重复这个过程来创建许多网络,然后组合这些网络的预测。

他们的预测将高度相关,但它可能会让你对那些更难预测的模式有一个小小的冲击。

相关:

2)组合视图

如上所述,但是针对您的问题的不同观点或框架来训练每个网络。

同样,目标是要有技巧性的模型,但方式不同(例如,不相关的预测)。

您可以依靠上面数据部分中列出的非常不同的缩放和转换技术来获得想法。

用于训练不同模型的问题的变换和框架越不同,你的结果就越有可能得到改善。

使用简单的预测手段将是一个良好的开端。

3)堆叠

您还可以学习如何最好地组合来自多个模型的预测。

这就是所谓的堆叠概括或简称堆叠。

通常,使用简单的线性方法,比如学习如何加权不同模型的预测的正则化回归,可以得到比平均预测更好的结果。

基线重用使用子模型预测的平均值,但使用模型的已知权重提升表现。

结论

你成功了。

额外资源

有很多好的资源,但很少有人把所有的想法联系在一起。

我将列出一些资源和相关的帖子,如果你想更深入地探讨,你可能会觉得有趣。

知道好的资源吗?让我知道,留下评论。

处理压倒性优势

这是一个很大的帖子,我们已经覆盖了很多领域。

你不需要做所有的事情。你只需要一个好主意就能提升表现。

下面是如何处理压倒性的:

  1. 选择一组
    1. 数据。
    2. 算法。
    3. 调谐。
    4. 全体
  2. 从组中选择一种方法。
  3. 从选择的方法中选择一个来尝试。
  4. 比较结果,如果有改进就保留。
  5. 重复一遍。

分享你的成果

你觉得这个帖子有用吗?

你有没有想到一个有所不同的想法或方法?

让我知道,留言评论!我很想听听这件事。

如何避免深度学习神经网络中的过拟合

原文:https://machinelearningmastery.com/introduction-to-regularization-to-reduce-overfitting-and-improve-generalization-error/

最后更新于 2019 年 8 月 6 日

训练一个能够很好地推广到新数据的深度神经网络是一个具有挑战性的问题。

容量太小的模型无法学习问题,而容量太大的模型可以学习得太好,过度训练训练数据集。这两种情况都导致模型不能很好地推广。

减少泛化误差的现代方法是使用更大的模型,这可能需要在训练期间使用正则化来保持模型的权重小。这些技术不仅可以减少过拟合,还可以加快模型的优化速度,提高整体表现。

在这篇文章中,你将发现训练神经网络时过拟合的问题,以及如何用正则化方法解决这个问题。

看完这篇文章,你会知道:

  • 通过增加网络容量可以很容易地解决适配不足的问题,但是过度适配需要使用专门的技术。
  • 像权重衰减这样的正则化方法为控制大型神经网络模型的过拟合提供了一种简单的方法。
  • 一个现代的正则化建议是使用提前停止和权重约束。

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

我们开始吧。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

减少过拟合和改善泛化误差的正则化的温和介绍jaimelie . beale摄,保留部分权利。

概观

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

  1. 模型泛化和过拟合问题
  2. 通过约束模型复杂性减少过拟合
  3. 正则化方法
  4. 正规化建议

模型泛化和过拟合问题

神经网络的目标是拥有一个最终模型,该模型在我们用来训练它的数据(例如训练数据集)和模型将用来进行预测的新数据上表现良好。

机器学习的核心挑战是,我们必须在新的、以前看不到的输入上表现良好——而不仅仅是那些训练我们模型的输入。在以前没有观察到的输入上表现良好的能力被称为概括。

—第 110 页,深度学习,2016。

我们要求模型从已知的例子中学习,并在将来从那些已知的例子中归纳出新的例子。我们使用类似训练/测试分割或 k-fold 交叉验证的方法来评估模型推广到新数据的能力。

学习和推广新的案例是很难的。

学习太少,模型在训练数据集和新数据上将表现不佳。这个模型会解决这个问题。过多的学习和模型将在训练数据集上表现良好,而在新数据上表现不佳,模型将过拟合问题。在这两种情况下,模型都没有一般化。

  • 下钻模型。未能充分了解问题的模型,在训练数据集上表现不佳,在保持样本上表现不佳。
  • 过冲模型。学习训练数据集太好的模型,在训练数据集上表现良好,但在等待样本上表现不佳。
  • 良好拟合模型。适合学习训练数据集并很好地推广到旧数据集的模型。

可以在偏差-方差权衡的背景下考虑模型拟合。

欠信息模型具有高偏差和低方差。不管训练数据中的具体样本如何,它都无法学习问题。过拟合模型具有低偏差和高方差。该模型学习训练数据太好了,并且随着训练数据集中新的未见过的例子或者甚至统计噪声被添加到例子中,表现变化很大。

为了很好地概括,系统需要足够强大以逼近目标函数。如果过于简单,甚至无法拟合训练数据,那么对新数据的泛化能力也很可能很差。[……]然而,一个过于复杂的系统可能能够以许多不同的方式近似数据,从而产生类似的误差,并且不太可能选择最能概括的那一个…

—第 241 页,神经锻造:前馈人工神经网络中的监督学习,1999。

我们可以通过增加模型的容量来解决装配不足的问题。能力是指模型适应各种功能的能力;更大的容量意味着一个模型可以适合更多类型的函数,用于将输入映射到输出。增加模型的容量很容易通过改变模型的结构来实现,例如添加更多的层和/或向层添加更多的节点。

因为欠比特模型很容易解决,所以过比特模型更常见。

通过在训练数据集和保持验证数据集上评估模型,在训练期间监控模型的表现,可以很容易地诊断过度训练模型。在训练期间绘制模型表现的线图,称为学习曲线,将显示熟悉的模式。

例如,模型在训练和验证数据集上的损失(我们寻求最小化)的线图将显示训练数据集的下降和可能平稳的线,以及验证数据集的先下降,然后在某个点开始再次上升的线。

随着训练的进行,当网络适应训练数据的特性时,泛化误差可以减小到最小,然后再次增加。

—第 250 页,神经锻造:前馈人工神经网络中的监督学习,1999。

学习曲线图讲述了模型学习问题的故事,直到它开始过拟合,并且它推广到看不见的验证数据集的能力开始变差。

通过约束模型复杂性减少过拟合

有两种方法可以接近 overfit 模型:

  1. 通过在更多的例子上训练网络来减少过拟合。
  2. 通过改变网络的复杂性来减少过拟合。

深度神经网络的一个好处是,当它们被输入越来越大的数据集时,它们的表现会不断提高。一个拥有几乎无限数量例子的模型最终会在网络的学习能力方面趋于平稳。

模型可以过度训练训练数据集,因为它有足够的能力这样做。降低模型的容量会降低模型过拟合训练数据集的可能性,达到不再过拟合的程度。

一个神经网络模型的容量,它的复杂性,是由它的节点和层的结构和它的权重的参数定义的。因此,我们可以通过以下两种方式之一来降低神经网络的复杂性,以减少过拟合:

  1. 通过改变网络结构(权重数)来改变网络复杂性。
  2. 通过更改网络参数(权重值)来更改网络复杂性。

在神经网络的情况下,复杂性可以通过改变网络中自适应参数的数量来改变。这叫做结构稳定。[……]控制模型复杂性的第二种主要方法是通过使用正则化,这涉及到在误差函数中添加惩罚项。

—第 332 页,用于模式识别的神经网络,1995。

例如,可以例如通过网格搜索来调整该结构,直到找到合适数量的节点和/或层来减少或消除该问题的过拟合。或者,可以通过移除节点对模型进行过拟合和修剪,直到它在验证数据集上获得合适的表现。

更常见的是通过确保模型的参数(权重)保持较小来约束模型的复杂性。小的参数意味着不太复杂,反过来,更稳定的模型,对输入数据的统计波动不太敏感。

较大的权重往往会导致[激活]功能的急剧转变,因此输入的小变化会导致输出的大变化。

—第 269 页,神经锻造:前馈人工神经网络中的监督学习,1999。

更常见的是关注约束神经网络中权重大小的方法,因为单个网络结构可以被定义为约束不足,例如具有比问题所需大得多的容量,并且在训练期间可以使用正则化来确保模型不会过拟合。在这种情况下,表现甚至可以更好,因为额外的能力可以集中在更好地学习问题中的可推广概念上。

寻求通过保持网络权重小来减少过拟合(减少泛化误差)的技术被称为正则化方法。更具体地说,正则化指的是一类添加额外信息以将不适定问题转化为更稳定的适定问题的方法。

如果给定信息中的小变化导致解决方案中的大变化,则称问题是不适定的。这种数据的不稳定性使得解决方案不可靠,因为微小的测量误差或参数的不确定性可能会被极大地放大,并导致截然不同的响应。[……]正则化背后的思想是使用补充信息以稳定的形式重述不适定问题。

—第 266 页,神经锻造:前馈人工神经网络中的监督学习,1999。

正则化方法被如此广泛地用于减少过拟合,以至于术语“正则化”可以用于改善神经网络模型的泛化误差的任何方法。

正则化是我们对学习算法所做的任何修改,目的是减少其泛化误差,而不是训练误差。正则化是机器学习领域关注的焦点之一,其重要性仅次于优化。

—第 120 页,深度学习,2016。

神经网络的正则化方法

最简单也可能是最常见的正则化方法是根据模型中权重的大小,在损失函数中加入一个惩罚。

  1. 【权重正则化(权重衰减) :在训练过程中根据权重的大小对模型进行惩罚。

这将鼓励模型将输入映射到训练数据集的输出,使得模型的权重保持较小。这种方法被称为权重正则化或权重衰减,并且几十年来被证明对于更简单的线性模型和神经网络都非常有效。

收集更多数据的一个简单的替代方法是通过调整权重衰减系数等超参数来减小模型的大小或改进正则化…

—第 427 页,深度学习,2016。

下面列出了五种最常见的附加正则化方法。

  1. 【活动规则化】 :在训练过程中根据激活的大小惩罚模型。
  2. 【权重约束】 :将权重的大小约束在一个范围内或低于一个限制。
  3. :在训练过程中可能会移除输入。
    *** 噪声 :训练时给输入增加统计噪声。* 【提前停止】 :监控验证集上的模型表现,当表现下降时停止训练。**

**这些方法中的大部分已经被证明(或证明)近似了在损失函数中加入惩罚的效果。

每种方法处理问题的方式都不同,在泛化表现、可配置性和/或计算复杂性方面都有优势。

正规化建议

本节概述了一些使用正则化方法进行深度学习神经网络的建议。

您应该始终考虑使用正则化,除非您有非常大的数据集,例如大数据规模。

除非你的训练集包含数千万或更多的例子,否则你应该从一开始就包含一些温和的正则化形式。

—第 426 页,深度学习,2016。

一个很好的总体建议是设计一个约束不足的神经网络结构,并使用正则化来减少过拟合的可能性。

……控制模型的复杂性不是一件简单的事情,需要找到大小合适、参数数量合适的模型。相反,……在实际的深度学习场景中,我们几乎总是会发现——最佳拟合模型(在最小化泛化误差的意义上)是已经适当正则化的大型模型。

—第 229 页,深度学习,2016。

除了在训练中保持小重量的方法之外,几乎应该普遍使用提前停止。

早停应该几乎普遍使用。

—第 426 页,深度学习,2016。

一些更具体的建议包括:

  • 经典:使用提前停止和权重衰减(L2 权重正则化)。
  • 替代:使用提前停止和带有重量限制的附加噪音。
  • 现代:除了重量限制外,使用提前停止和脱扣。

这些建议将适合多层感知器和卷积神经网络。

对递归神经网络的一些建议包括:

  • 经典:使用增加了权重噪声的提前停止和最大范数等权重约束。
  • 现代:使用提前停止,通过时间感知的退圈和重量限制反向传播。

在正规化方面没有万灵药,强烈鼓励系统的实验。

进一步阅读

如果您想更深入地了解这个主题,本节将提供更多资源。

文章

摘要

在这篇文章中,你发现了训练神经网络时过拟合的问题,以及如何用正则化方法解决这个问题。

具体来说,您了解到:

  • 通过增加网络容量可以很容易地解决适配不足的问题,但是过度适配需要使用专门的技术。
  • 像权重衰减这样的正则化方法为控制大型神经网络模型的过拟合提供了一种简单的方法。
  • 一个现代的正则化建议是使用提前停止和权重约束。

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

深度学习中权重限制的温和介绍

原文:https://machinelearningmastery.com/introduction-to-weight-constraints-to-reduce-generalization-error-in-deep-learning/

最后更新于 2019 年 8 月 6 日

当训练神经网络以鼓励网络使用小权重时,权重正则化方法(如权重衰减)会对损失函数引入惩罚。

神经网络中较小的权重可以导致模型更加稳定,并且不太可能过拟合训练数据集,从而在对新数据进行预测时具有更好的表现。

与权重正则化不同,权重约束是一个触发器,它检查权重的大小或大小,并对它们进行缩放,使它们都低于预定义的阈值。该约束迫使权重变小,可以代替权重衰减,并与更积极的网络配置结合使用,例如非常大的学习率

在这篇文章中,您将发现使用权重约束正则化作为权重惩罚的替代,以减少深度神经网络中的过拟合。

看完这篇文章,你会知道:

  • 权重惩罚鼓励但不要求神经网络具有小的权重。
  • 权重约束,例如 L2 范数和最大范数,可以用来迫使神经网络在训练期间具有小的权重。
  • 当与其他正则化方法(如 dropout)结合使用时,权重约束可以提高泛化能力。

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

我们开始吧。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

轻度介绍权重约束以减少深度学习中的泛化错误
图片由黎明·埃尔纳提供,保留部分权利。

概观

  • 大重量处罚的替代方案
  • 强制小重量
  • 如何使用权重约束
  • 权重约束的使用示例
  • 使用重量限制的提示

大重量处罚的替代方案

神经网络中的大权重是过拟合的标志。

具有大权重的网络很可能已经学会了训练数据中的统计噪声。这导致模型不稳定,并且对输入变量的变化非常敏感。反过来,当对新的未知数据进行预测时,overfit 网络的表现很差。

解决该问题的一种流行且有效的技术是更新在训练期间优化的损失函数,以考虑权重的大小。

这被称为惩罚,因为网络的权重越大,网络受到的惩罚就越多,从而导致更大的损失,进而导致更大的更新。其效果是,惩罚鼓励重量变小,或不超过训练过程中所需的重量,从而减少过度训练。

使用惩罚的一个问题是,尽管它确实鼓励网络朝着更小的权重发展,但它并没有强制更小的权重。

用权重正则化惩罚训练的神经网络可能仍然允许大的权重,在某些情况下是非常大的权重。

强制小重量

使用网络权重大小惩罚的另一种解决方案是使用权重约束。

权重约束是对检查权重大小的网络的更新,如果大小超过预定义的限制,权重将被重新缩放,以使其大小低于限制或介于范围之间。

您可以将权重约束看作是一个 if-then 规则,它在网络被训练时检查权重的大小,并且只在需要时生效并使权重变小。注意,为了提高效率,它不一定要作为一个“如果-那么”规则来实现,而且通常不是。

与在损失函数中增加惩罚不同,权重约束确保网络的权重很小,而不是鼓励它们很小。

它可以用于解决这些问题,或者用于抵制其他正则化方法(如权重惩罚)的网络。

当您将网络配置为使用替代正则化方法对正则化进行加权,但仍然希望网络具有较小的权重以减少过拟合时,权重约束证明特别有用。一个经常被引用的例子是权重约束正则化与缺失正则化的使用。

虽然仅丢弃就能带来显著的改善,但使用丢弃和[权重约束]正则化,[……]比仅使用丢弃提供了显著的提升。

——丢弃:防止神经网络过拟合的简单方法,2014。

如何使用权重约束

对层中的每个节点强制实现约束。

该层中的所有节点使用相同的约束,并且同一网络中的多个隐藏层通常会使用相同的约束。

回想一下,当我们一般讨论向量范数时,这是节点中权重向量的大小,默认情况下计算为 L2 范数,例如向量中平方值之和的平方根。

可以使用的一些约束示例包括:

  • 强制向量范数为 1.0(例如单位范数)。
  • 限制向量范数的最大大小(例如最大范数)。
  • 限制向量范数的最小和最大大小(例如,min_max 范数)。

最大范数,也称为 max-norm 或 maxnorm,是一种流行的约束,因为它比其他规范(如单位范数)不那么激进,只需设置一个上限。

最大范数正则化以前已经被使用过……它典型地改善了深度神经网络的随机梯度下降训练的表现…

——丢弃:防止神经网络过拟合的简单方法,2014。

使用极限或范围时,必须指定超参数。假设权重很小,超参数通常也是一个小的整数值,例如 1 到 4 之间的值。

…我们可以使用最大范数正则化。这将每个隐藏单元的输入权重向量的范数约束为常数 c。c 的典型值范围为 3 到 4。

——丢弃:防止神经网络过拟合的简单方法,2014。

如果范数超过指定的范围或限制,权重将被重新缩放或归一化,以使其大小低于指定的参数或在指定的范围内。

如果权重更新违反了这个约束,我们通过除法来重整隐藏单元的权重。使用约束而不是惩罚可以防止权重变得非常大,不管建议的权重更新有多大。

——通过防止特征检测器的共同适应来改进神经网络,2012。

该约束可以在每次更新权重之后应用,例如在每个小批量的末尾。

权重约束的使用示例

本节提供了一些从最近的研究论文中精选的例子,其中使用了重量约束。

Geoffrey Hinton 等人在他们 2012 年发表的题为“通过防止特征检测器的共同适应来改进神经网络”的论文中,对应用于 MNIST 手写数字分类任务和 ImageNet 照片分类任务的 CNN 模型使用了 maxnorm 约束。

所有层对每个隐藏单元的输入权重都有 L2 权重约束。

Nitish Srivastava 等人在 2014 年发表的题为“T0 丢弃:防止神经网络过拟合的简单方法”的论文中,在 MNIST 手写数字分类任务中使用了带有 MLP 的 maxnorm 约束,在街景门牌号数据集上使用了 CNNs,该数据集的参数是通过保持验证集配置的。

最大范数正则化用于卷积层和全连接层的权重。

Jan Chorowski 等人在 2015 年发表的题为“基于注意力的语音识别模型”的论文中使用 LSTM 和注意力模型进行语音识别,最大范数约束设置为 1。

我们首先用最大范数为 1 的列范数约束训练我们的模型…

使用重量限制的提示

本节提供了一些在神经网络中使用权重约束的技巧。

适用于所有网络类型

权重约束是一种通用方法。

它们可以用于大多数,也许是所有类型的神经网络模型,尤其是最常见的多层感知器、卷积神经网络和长短期记忆递归神经网络。

在 LSTMs 的情况下,可能希望对输入和循环连接使用不同的约束或约束配置。

标准化输入数据

将输入变量重新缩放到相同的比例是一种很好的通用做法。

当输入变量具有不同的标度时,网络权重的标度将相应地变化。这在使用权重约束时引入了一个问题,因为较大的权重将导致约束更频繁地触发。

这个问题可以通过输入变量的规范化或标准化来解决。

使用更高的学习率

使用重量限制可以让你在网络训练中更加积极。

具体来说,可以使用更大的学习率,从而允许网络在每次更新时对权重进行更大的更新。

这被认为是使用权重限制的一个重要好处。例如使用约束结合退出:

使用约束而不是惩罚可以防止权重变得非常大,不管建议的权重更新有多大。这使得以非常大的学习率开始成为可能,该学习率在学习期间衰减,因此允许比以小权重开始并使用小学习率的方法更彻底地搜索权重空间。

——通过防止特征检测器的共同适应来改进神经网络,2012。

尝试其他约束

探索其他权重约束的使用,例如最小和最大范围、非负权重等。

您也可以选择在某些权重上使用约束,而不在其他权重上使用约束,例如在 MLP 中不对偏置权重使用约束,或者在 LSTM 中不对循环连接使用约束。

进一步阅读

如果您想更深入地了解这个主题,本节将提供更多资源。

报纸

文章

摘要

在这篇文章中,您发现了使用权重约束正则化作为权重惩罚的替代方法来减少深度神经网络中的过拟合。

具体来说,您了解到:

  • 权重惩罚鼓励但不要求神经网络具有小的权重。
  • 诸如 L2 范数和最大范数之类的权重约束可以用于在训练期间强制神经网络具有小的权重。
  • 当与其他正则化方法(如 dropout)结合使用时,权重约束可以提高泛化能力。

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值