Machine-Learning-Mastery-深度学习表现教程-三-

55 阅读1小时+

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

原文:Machine Learning Mastery

协议:CC BY-NC-SA 4.0

训练深度学习神经网络时如何选择损失函数

原文:machinelearningmastery.com/how-to-choo…

最后更新于 2020 年 8 月 25 日

使用随机梯度下降优化算法训练深度学习神经网络

作为优化算法的一部分,必须重复估计模型当前状态的误差。这需要选择一个误差函数,通常称为损失函数,该函数可用于估计模型的损失,以便更新权重来减少下一次评估的损失。

神经网络模型从示例中学习从输入到输出的映射,损失函数的选择必须与特定预测建模问题的框架相匹配,例如分类或回归。此外,输出层的配置也必须适合所选的损耗函数。

在本教程中,您将发现如何为给定预测建模问题的深度学习神经网络选择损失函数。

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

  • 如何配置回归问题的均方误差和变量模型?
  • 如何为二分类配置交叉熵和铰链损失函数模型。
  • 如何为多类分类配置交叉熵和 KL 散度损失函数模型。

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

我们开始吧。

  • 2019 年 10 月更新:针对 Keras 2.3 和 TensorFlow 2.0 更新。
  • 2020 年 1 月更新:针对 Sklearn v0.22 API 的变化进行了更新

How to Choose Loss Functions When Training Deep Learning Neural Networks

训练深度学习神经网络时如何选择损失函数 图片由glacierenps提供,保留部分权利。

教程概述

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

  1. 回归损失函数
    1. 均方误差损失
    2. 均方对数误差损失
    3. 平均绝对误差损失
  2. 二分类损失函数
    1. 二元交叉熵
    2. 铰链损失
    3. 方形铰链损失
  3. 多类分类损失函数
    1. 多类交叉熵损失
    2. 稀疏多类交叉熵损失
    3. 库尔巴克·莱布勒发散损失

我们将重点讨论如何选择和实现不同的损失函数。

有关损失函数的更多理论,请参见文章:

回归损失函数

回归预测建模问题涉及预测实值量。

在本节中,我们将研究适用于回归预测建模问题的损失函数。

作为本次调查的背景,我们将使用由 Sklearn 库在make _ revolution()函数中提供的标准回归问题生成器。该函数将从具有给定数量的输入变量、统计噪声和其他属性的简单回归问题中生成示例。

我们将使用这个函数来定义一个有 20 个输入特征的问题;其中 10 个功能将是有意义的,10 个将不相关。总共将随机生成 1000 个示例。伪随机数发生器将是固定的,以确保我们每次运行代码时都会得到相同的 1000 个例子。

# generate regression dataset
X, y = make_regression(n_samples=1000, n_features=20, noise=0.1, random_state=1)

当实值输入和输出变量被缩放到合理的范围时,神经网络通常表现得更好。对于这个问题,每个输入变量和目标变量都具有高斯分布;因此,在这种情况下标准化数据是可取的。

我们可以使用 Sklearn 库中的标准转换器类来实现这一点。在一个实际问题上,我们将在训练数据集上准备定标器,并将其应用于训练集和测试集,但是为了简单起见,我们将在分割成训练集和测试集之前将所有数据一起定标。

# standardize dataset
X = StandardScaler().fit_transform(X)
y = StandardScaler().fit_transform(y.reshape(len(y),1))[:,0]

一旦缩放,数据将被平均分成训练集和测试集。

# split into train and test
n_train = 500
trainX, testX = X[:n_train, :], X[n_train:, :]
trainy, testy = y[:n_train], y[n_train:]

将定义一个小型多层感知器(MLP)模型来解决这个问题,并为探索不同的损失函数提供基础。

该模型将预期 20 个特征作为问题定义的输入。该模型将有一个包含 25 个节点的隐藏层,并将使用校正线性激活函数(ReLU) 。给定一个要预测的真实值,输出层将有 1 个节点,并将使用线性激活函数。

# define model
model = Sequential()
model.add(Dense(25, input_dim=20, activation='relu', kernel_initializer='he_uniform'))
model.add(Dense(1, activation='linear'))

该模型将适合随机梯度下降,学习率为 0.01,动量为 0.9,两者都是合理的默认值。

训练将进行 100 个时期,测试集将在每个时期结束时进行评估,以便我们可以在运行结束时绘制学习曲线

opt = SGD(lr=0.01, momentum=0.9)
model.compile(loss='...', optimizer=opt)
# fit model
history = model.fit(trainX, trainy, validation_data=(testX, testy), epochs=100, verbose=0)

现在我们已经有了问题和模型的基础,我们可以看一下评估三个适用于回归预测建模问题的常见损失函数。

虽然在这些例子中使用了 MLP,但是当训练 CNN 和 RNN 模型进行回归时,可以使用相同的损失函数。

均方误差损失

均方误差损失是用于回归问题的默认损失。

数学上,如果目标变量的分布是高斯分布,则是最大似然推理框架下的优选损失函数。首先要评估的是损失函数,只有在你有充分理由的情况下才能改变。

均方误差计算为预测值和实际值之间的平方差的平均值。无论预测值和实际值的符号如何,结果总是正的,理想值为 0.0。平方意味着较大的错误比较小的错误导致更多的错误,这意味着模型因犯较大的错误而受到惩罚。

在 Keras 中,均方误差损失函数可以通过在编译模型时指定“ mse 或“均方误差作为损失函数来使用。

model.compile(loss='mean_squared_error')

建议输出层有一个目标变量节点,并使用线性激活函数。

model.add(Dense(1, activation='linear'))

下面列出了在所描述的回归问题上演示 MLP 的完整示例。

# mlp for regression with mse loss function
from sklearn.datasets import make_regression
from sklearn.preprocessing import StandardScaler
from keras.models import Sequential
from keras.layers import Dense
from keras.optimizers import SGD
from matplotlib import pyplot
# generate regression dataset
X, y = make_regression(n_samples=1000, n_features=20, noise=0.1, random_state=1)
# standardize dataset
X = StandardScaler().fit_transform(X)
y = StandardScaler().fit_transform(y.reshape(len(y),1))[:,0]
# split into train and test
n_train = 500
trainX, testX = X[:n_train, :], X[n_train:, :]
trainy, testy = y[:n_train], y[n_train:]
# define model
model = Sequential()
model.add(Dense(25, input_dim=20, activation='relu', kernel_initializer='he_uniform'))
model.add(Dense(1, activation='linear'))
opt = SGD(lr=0.01, momentum=0.9)
model.compile(loss='mean_squared_error', optimizer=opt)
# fit model
history = model.fit(trainX, trainy, validation_data=(testX, testy), epochs=100, verbose=0)
# evaluate the model
train_mse = model.evaluate(trainX, trainy, verbose=0)
test_mse = model.evaluate(testX, testy, verbose=0)
print('Train: %.3f, Test: %.3f' % (train_mse, test_mse))
# plot loss during training
pyplot.title('Loss / Mean Squared Error')
pyplot.plot(history.history['loss'], label='train')
pyplot.plot(history.history['val_loss'], label='test')
pyplot.legend()
pyplot.show()

运行该示例首先在训练和测试数据集上打印模型的均方误差。

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

在这种情况下,我们可以看到模型学会了实现零误差的问题,至少达到小数点后三位。

Train: 0.000, Test: 0.001

还创建了一个线图,显示了训练集(蓝色)和测试集(橙色)在训练时期的均方误差损失。

我们可以看到,模型收敛得相当快,训练和测试表现保持相当。模型的表现和收敛行为表明均方误差是学习该问题的神经网络的良好匹配。

Line plot of Mean Squared Error Loss over Training Epochs When Optimizing the Mean Squared Error Loss Function

优化均方误差损失函数时训练时段的均方误差损失线图

均方对数误差损失

可能存在回归问题,其中目标值有一个值的范围,当预测一个大值时,您可能不想像均方误差那样严重地惩罚模型。

相反,您可以首先计算每个预测值的自然对数,然后计算均方误差。这被称为对数均方误差损失,简称 MSLE。

它具有放松大预测值中的大差异的惩罚效果的效果。

作为一种损失度量,当模型直接预测未缩放的数量时,它可能更合适。然而,我们可以用简单的回归问题来证明这个损失函数。

模型可以更新为使用“均方对数误差损失函数,并保持输出层的相同配置。在拟合模型时,我们还将跟踪均方误差作为一个指标,以便我们可以将其用作表现的衡量标准,并绘制学习曲线。

model.compile(loss='mean_squared_logarithmic_error', optimizer=opt, metrics=['mse'])

下面列出了使用 MSLE 损失函数的完整示例。

# mlp for regression with msle loss function
from sklearn.datasets import make_regression
from sklearn.preprocessing import StandardScaler
from keras.models import Sequential
from keras.layers import Dense
from keras.optimizers import SGD
from matplotlib import pyplot
# generate regression dataset
X, y = make_regression(n_samples=1000, n_features=20, noise=0.1, random_state=1)
# standardize dataset
X = StandardScaler().fit_transform(X)
y = StandardScaler().fit_transform(y.reshape(len(y),1))[:,0]
# split into train and test
n_train = 500
trainX, testX = X[:n_train, :], X[n_train:, :]
trainy, testy = y[:n_train], y[n_train:]
# define model
model = Sequential()
model.add(Dense(25, input_dim=20, activation='relu', kernel_initializer='he_uniform'))
model.add(Dense(1, activation='linear'))
opt = SGD(lr=0.01, momentum=0.9)
model.compile(loss='mean_squared_logarithmic_error', optimizer=opt, metrics=['mse'])
# fit model
history = model.fit(trainX, trainy, validation_data=(testX, testy), epochs=100, verbose=0)
# evaluate the model
_, train_mse = model.evaluate(trainX, trainy, verbose=0)
_, test_mse = model.evaluate(testX, testy, verbose=0)
print('Train: %.3f, Test: %.3f' % (train_mse, test_mse))
# plot loss during training
pyplot.subplot(211)
pyplot.title('Loss')
pyplot.plot(history.history['loss'], label='train')
pyplot.plot(history.history['val_loss'], label='test')
pyplot.legend()
# plot mse during training
pyplot.subplot(212)
pyplot.title('Mean Squared Error')
pyplot.plot(history.history['mean_squared_error'], label='train')
pyplot.plot(history.history['val_mean_squared_error'], label='test')
pyplot.legend()
pyplot.show()

运行该示例首先打印训练和测试数据集中模型的均方误差。

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

在这种情况下,我们可以看到该模型在训练和测试数据集上都导致了稍差的均方误差。因为目标变量的分布是标准的高斯分布,所以它可能不太适合这个问题。

Train: 0.165, Test: 0.184

还创建了一个线图,显示了训练(蓝色)和测试(橙色)集合(顶部)在训练时期的对数误差的均方损失,以及一个类似的均方误差图(底部)。

我们可以看到,在 100 个时代的算法中,MSLE 收敛得很好;从 20 世纪开始,MSE 似乎显示出过度适应问题的迹象,快速下降并开始上升。

Line Plots of Mean Squared Logistic Error Loss and Mean Squared Error Over Training Epochs

训练时期的均方对数误差损失和均方误差的线图

平均绝对误差损失

在一些回归问题中,目标变量的分布可能大部分是高斯分布,但是可能有异常值,例如远离平均值的大值或小值。

在这种情况下,平均绝对误差损失是一个合适的损失函数,因为它对异常值更稳健。它被计算为实际值和预测值之间的绝对差值的平均值。

模型可以更新为使用“ mean_absolute_error ”损失函数,并为输出层保持相同的配置。

model.compile(loss='mean_absolute_error', optimizer=opt, metrics=['mse'])

下面列出了使用平均绝对误差作为回归测试问题损失函数的完整示例。

# mlp for regression with mae loss function
from sklearn.datasets import make_regression
from sklearn.preprocessing import StandardScaler
from keras.models import Sequential
from keras.layers import Dense
from keras.optimizers import SGD
from matplotlib import pyplot
# generate regression dataset
X, y = make_regression(n_samples=1000, n_features=20, noise=0.1, random_state=1)
# standardize dataset
X = StandardScaler().fit_transform(X)
y = StandardScaler().fit_transform(y.reshape(len(y),1))[:,0]
# split into train and test
n_train = 500
trainX, testX = X[:n_train, :], X[n_train:, :]
trainy, testy = y[:n_train], y[n_train:]
# define model
model = Sequential()
model.add(Dense(25, input_dim=20, activation='relu', kernel_initializer='he_uniform'))
model.add(Dense(1, activation='linear'))
opt = SGD(lr=0.01, momentum=0.9)
model.compile(loss='mean_absolute_error', optimizer=opt, metrics=['mse'])
# fit model
history = model.fit(trainX, trainy, validation_data=(testX, testy), epochs=100, verbose=0)
# evaluate the model
_, train_mse = model.evaluate(trainX, trainy, verbose=0)
_, test_mse = model.evaluate(testX, testy, verbose=0)
print('Train: %.3f, Test: %.3f' % (train_mse, test_mse))
# plot loss during training
pyplot.subplot(211)
pyplot.title('Loss')
pyplot.plot(history.history['loss'], label='train')
pyplot.plot(history.history['val_loss'], label='test')
pyplot.legend()
# plot mse during training
pyplot.subplot(212)
pyplot.title('Mean Squared Error')
pyplot.plot(history.history['mean_squared_error'], label='train')
pyplot.plot(history.history['val_mean_squared_error'], label='test')
pyplot.legend()
pyplot.show()

运行该示例首先打印训练和测试数据集中模型的均方误差。

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

在这种情况下,我们可以看到模型学会了这个问题,实现了接近零的误差,至少到小数点后三位。

Train: 0.002, Test: 0.002

还创建了一个线形图,显示了训练时段中训练集(蓝色)和测试集(橙色)的平均绝对误差损失(上图),以及一个类似的均方误差图(下图)。

在这种情况下,我们可以看到 MAE 确实收敛了,但显示出一个颠簸的过程,尽管 MSE 的动力学似乎没有受到很大影响。我们知道目标变量是标准高斯,没有大的异常值,所以在这种情况下,MAE 不是一个很好的拟合。

如果我们不先缩放目标变量,可能会更适合这个问题。

Line plots of Mean Absolute Error Loss and Mean Squared Error over Training Epochs

训练时期平均绝对误差损失和均方误差的线图

二分类损失函数

二进制分类是那些预测建模问题,其中例子被分配两个标签中的一个。

该问题通常被设计为预测第一类或第二类的值 0 或 1,并且通常被实现为预测该示例属于类值 1 的概率。

在本节中,我们将研究适用于二分类预测建模问题的损失函数。

我们将从 Sklearn 中的循环测试问题中生成示例,作为本次调查的基础。圆问题涉及从二维平面上的两个同心圆中抽取的样本,其中外圆上的点属于 0 类,内圆上的点属于 1 类。统计噪声被添加到样本中,以增加模糊性,并使问题更难学习。

我们将生成 1000 个示例,并添加 10%的统计噪声。伪随机数发生器将被植入相同的值,以确保我们总是得到相同的 1000 个例子。

# generate circles
X, y = make_circles(n_samples=1000, noise=0.1, random_state=1)

我们可以创建数据集的散点图来了解我们正在建模的问题。下面列出了完整的示例。

# 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=1000, noise=0.1, random_state=1)
# select indices of points with each class label
for i in range(2):
	samples_ix = where(y == i)
	pyplot.scatter(X[samples_ix, 0], X[samples_ix, 1], label=str(i))
pyplot.legend()
pyplot.show()

运行该示例会创建示例的散点图,其中输入变量定义点的位置,类值定义颜色,类 0 为蓝色,类 1 为橙色。

Scatter Plot of Dataset for the Circles Binary Classification Problem

圆形二分类问题的数据集散点图

这些点已经合理地缩放到 0 左右,几乎在[-1,1]中。在这种情况下,我们不会重新缩放它们。

对于训练集和测试集,数据集被平均分割。

# split into train and test
n_train = 500
trainX, testX = X[:n_train, :], X[n_train:, :]
trainy, testy = y[:n_train], y[n_train:]

可以定义一个简单的 MLP 模型来解决这个问题,该模型要求数据集中的两个要素有两个输入,一个具有 50 个节点的隐藏层,一个经过校正的线性激活函数,以及一个需要针对损失函数的选择进行配置的输出层。

# define model
model = Sequential()
model.add(Dense(50, input_dim=2, activation='relu', kernel_initializer='he_uniform'))
model.add(Dense(1, activation='...'))

模型将使用随机梯度下降进行拟合,合理默认学习率为 0.01,动量为 0.9。

opt = SGD(lr=0.01, momentum=0.9)
model.compile(loss='...', optimizer=opt, metrics=['accuracy'])

我们将为 200 个训练时期拟合模型,并针对每个时期结束时的损失和准确性评估模型的表现,以便绘制学习曲线。

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

现在我们已经有了问题和模型的基础,我们可以看一下评估三个适用于二分类预测建模问题的常见损失函数。

虽然在这些例子中使用了 MLP,但是当训练 CNN 和 RNN 模型进行二进制分类时,可以使用相同的损失函数。

二元交叉熵损失

交叉熵是用于二进制分类问题的默认损失函数。

它适用于目标值在集合{0,1}中的二进制分类。

数学上,它是最大似然推理框架下的优选损失函数。首先要评估的是损失函数,只有在你有充分理由的情况下才能改变。

交叉熵将计算一个分数,该分数总结了预测类别 1 的实际和预测概率分布之间的平均差异。分数被最小化,完美的交叉熵值为 0。

通过在编译模型时指定“binary _ cross 熵”,可以将交叉熵指定为 Keras 中的损失函数。

model.compile(loss='binary_crossentropy', optimizer=opt, metrics=['accuracy'])

该函数要求输出层配置单个节点和一个“ sigmoid ”激活,以便预测类别 1 的概率。

model.add(Dense(1, activation='sigmoid'))

下面列出了两个圆的二分类问题的交叉熵损失 MLP 的完整例子。

# mlp for the circles problem with cross entropy loss
from sklearn.datasets import make_circles
from keras.models import Sequential
from keras.layers import Dense
from keras.optimizers import SGD
from matplotlib import pyplot
# generate 2d classification dataset
X, y = make_circles(n_samples=1000, noise=0.1, random_state=1)
# split into train and test
n_train = 500
trainX, testX = X[:n_train, :], X[n_train:, :]
trainy, testy = y[:n_train], y[n_train:]
# define model
model = Sequential()
model.add(Dense(50, input_dim=2, activation='relu', kernel_initializer='he_uniform'))
model.add(Dense(1, activation='sigmoid'))
opt = SGD(lr=0.01, momentum=0.9)
model.compile(loss='binary_crossentropy', optimizer=opt, metrics=['accuracy'])
# fit model
history = model.fit(trainX, trainy, validation_data=(testX, testy), epochs=200, 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 loss during training
pyplot.subplot(211)
pyplot.title('Loss')
pyplot.plot(history.history['loss'], label='train')
pyplot.plot(history.history['val_loss'], label='test')
pyplot.legend()
# plot accuracy during training
pyplot.subplot(212)
pyplot.title('Accuracy')
pyplot.plot(history.history['accuracy'], label='train')
pyplot.plot(history.history['val_accuracy'], label='test')
pyplot.legend()
pyplot.show()

运行该示例首先打印模型在训练和测试数据集上的分类准确率。

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

在这种情况下,我们可以看到模型相当好地学习了问题,在训练数据集上达到了大约 83%的准确率,在测试数据集上达到了大约 85%。分数相当接近,表明该模型可能没有结束或不足。

Train: 0.836, Test: 0.852

还创建了一个图形,显示了两条线图,顶部显示了列车(蓝色)和测试(橙色)数据集在不同时期的交叉熵损失,底部显示了不同时期的分类准确率。

该图显示训练过程收敛良好。给定概率分布之间误差的连续性质,损失的曲线是平滑的,而准确率的直线曲线显示颠簸,在列车和测试集中给出的例子最终只能被预测为正确或不正确,从而对表现提供不太精细的反馈。

Line Plots of Cross Entropy Loss and Classification Accuracy over Training Epochs on the Two Circles Binary Classification Problem

两圆二分类问题的交叉熵损失和训练时段分类准确率的线图

铰链损失

二分类问题中交叉熵的另一种选择是铰链损失函数,主要是为支持向量机(SVM)模型开发的。

它适用于目标值在集合{-1,1}中的二进制分类。

铰链损失函数鼓励示例使用正确的符号,当实际类别值和预测类别值之间的符号存在差异时,会分配更多的误差。

铰链损失的表现报告是混合的,有时在二分类问题上产生比交叉熵更好的表现。

首先,目标变量必须修改为具有集合{-1,1}中的值。

# change y from {0,1} to {-1,1}
y[where(y == 0)] = -1

然后,可以在编译函数中将铰链损失函数指定为“铰链”。

model.compile(loss='hinge', optimizer=opt, metrics=['accuracy'])

最后,网络的输出层必须配置为具有单个节点,该节点具有双曲正切激活函数,能够输出[-1,1]范围内的单个值。

model.add(Dense(1, activation='tanh'))

下面列出了两个圆的二分类问题的具有铰链损失函数的 MLP 的完整例子。

# mlp for the circles problem with hinge loss
from sklearn.datasets import make_circles
from keras.models import Sequential
from keras.layers import Dense
from keras.optimizers import SGD
from matplotlib import pyplot
from numpy import where
# generate 2d classification dataset
X, y = make_circles(n_samples=1000, noise=0.1, random_state=1)
# change y from {0,1} to {-1,1}
y[where(y == 0)] = -1
# split into train and test
n_train = 500
trainX, testX = X[:n_train, :], X[n_train:, :]
trainy, testy = y[:n_train], y[n_train:]
# define model
model = Sequential()
model.add(Dense(50, input_dim=2, activation='relu', kernel_initializer='he_uniform'))
model.add(Dense(1, activation='tanh'))
opt = SGD(lr=0.01, momentum=0.9)
model.compile(loss='hinge', optimizer=opt, metrics=['accuracy'])
# fit model
history = model.fit(trainX, trainy, validation_data=(testX, testy), epochs=200, 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 loss during training
pyplot.subplot(211)
pyplot.title('Loss')
pyplot.plot(history.history['loss'], label='train')
pyplot.plot(history.history['val_loss'], label='test')
pyplot.legend()
# plot accuracy during training
pyplot.subplot(212)
pyplot.title('Accuracy')
pyplot.plot(history.history['accuracy'], label='train')
pyplot.plot(history.history['val_accuracy'], label='test')
pyplot.legend()
pyplot.show()

运行该示例首先打印模型在训练和测试数据集上的分类准确率。

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

在这种情况下,我们可以看到比使用交叉熵稍差的表现,所选择的模型配置在列车和测试集上的准确率低于 80%。

Train: 0.792, Test: 0.740

还创建了一个图形,显示了两条线图,顶部显示了列车(蓝色)和测试(橙色)数据集在不同时期的铰链损耗,底部显示了不同时期的分类准确率。

铰链损失图表明模型已经收敛,并且在两个数据集上都有合理的损失。分类准确率图也显示了趋同的迹象,尽管在这个问题上,技术水平可能低于理想水平。

Line Plots of Hinge Loss and Classification Accuracy over Training Epochs on the Two Circles Binary Classification Problem

两圆二分类问题的铰链损失和训练时期分类准确率的线图

方形铰链损失

铰链损失函数有许多扩展,通常是 SVM 模型的研究对象。

一种流行的扩展称为平方铰链损失,它简单地计算分数铰链损失的平方。它具有平滑误差函数表面的效果,并使其在数值上更容易处理。

如果在给定的二分类问题上使用铰链损失确实导致更好的表现,那么平方铰链损失可能是合适的。

与使用铰链损失函数一样,必须修改目标变量,使其值在集合{-1,1}中。

# change y from {0,1} to {-1,1}
y[where(y == 0)] = -1

在定义模型时,平方铰链损失可以在*编译()*函数中指定为“平方铰链”。

model.compile(loss='squared_hinge', optimizer=opt, metrics=['accuracy'])

最后,输出层必须使用具有双曲正切激活函数的单个节点,该函数能够输出[-1,1]范围内的连续值。

model.add(Dense(1, activation='tanh'))

下面列出了在两个圆的二分类问题上具有平方铰链损失函数的 MLP 的完整例子。

# mlp for the circles problem with squared hinge loss
from sklearn.datasets import make_circles
from keras.models import Sequential
from keras.layers import Dense
from keras.optimizers import SGD
from matplotlib import pyplot
from numpy import where
# generate 2d classification dataset
X, y = make_circles(n_samples=1000, noise=0.1, random_state=1)
# change y from {0,1} to {-1,1}
y[where(y == 0)] = -1
# split into train and test
n_train = 500
trainX, testX = X[:n_train, :], X[n_train:, :]
trainy, testy = y[:n_train], y[n_train:]
# define model
model = Sequential()
model.add(Dense(50, input_dim=2, activation='relu', kernel_initializer='he_uniform'))
model.add(Dense(1, activation='tanh'))
opt = SGD(lr=0.01, momentum=0.9)
model.compile(loss='squared_hinge', optimizer=opt, metrics=['accuracy'])
# fit model
history = model.fit(trainX, trainy, validation_data=(testX, testy), epochs=200, 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 loss during training
pyplot.subplot(211)
pyplot.title('Loss')
pyplot.plot(history.history['loss'], label='train')
pyplot.plot(history.history['val_loss'], label='test')
pyplot.legend()
# plot accuracy during training
pyplot.subplot(212)
pyplot.title('Accuracy')
pyplot.plot(history.history['accuracy'], label='train')
pyplot.plot(history.history['val_accuracy'], label='test')
pyplot.legend()
pyplot.show()

运行该示例首先在训练和测试数据集上打印模型的分类准确率。

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

在这种情况下,我们可以看到,对于这个问题和所选的模型配置,铰链平方损失可能不合适,导致列车和测试集上的分类准确率低于 70%。

Train: 0.682, Test: 0.646

还创建了一个图形,显示了两条线图,顶部显示了列车(蓝色)和测试(橙色)数据集在各个时期的平方铰链损耗,底部显示了各个时期的分类准确率。

损失图显示,确实,模型收敛了,但是误差表面的形状不像其他损失函数那样平滑,在其他损失函数中,权重的微小变化导致损失的巨大变化。

Line Plots of Squared Hinge Loss and Classification Accuracy over Training Epochs on the Two Circles Binary Classification Problem

两圆二分类问题的平方铰链损失和训练时期分类准确率的线图

多类分类损失函数

多类分类是那些预测建模问题,其中例子被分配到两个以上的类之一。

这个问题通常被描述为预测一个整数值,其中每个类被分配一个从 0 到(num _ class–1)的唯一整数值。该问题通常被实现为预测该示例属于每个已知类的概率。

在本节中,我们将研究适用于多类分类预测建模问题的损失函数。

我们将使用斑点问题作为调查的基础。Sklearn 提供的 make_blobs()函数提供了一种在给定指定数量的类和输入特征的情况下生成示例的方法。我们将使用这个函数为一个有 2 个输入变量的 3 类分类问题生成 1000 个例子。伪随机数发生器将被一致地播种,以便每次运行代码时生成相同的 1000 个例子。

# generate dataset
X, y = make_blobs(n_samples=1000, centers=3, n_features=2, cluster_std=2, random_state=2)

两个输入变量可以作为二维平面上点的 xy 坐标。

下面的示例按照类别成员关系创建了整个数据集着色点的散点图。

# scatter plot of blobs dataset
from sklearn.datasets import make_blobs
from numpy import where
from matplotlib import pyplot
# generate dataset
X, y = make_blobs(n_samples=1000, centers=3, n_features=2, cluster_std=2, random_state=2)
# select indices of points with each class label
for i in range(3):
	samples_ix = where(y == i)
	pyplot.scatter(X[samples_ix, 0], X[samples_ix, 1])
pyplot.show()

运行该示例会创建一个散点图,显示数据集中的 1,000 个示例,这些示例分别属于 0、1 和 2 类颜色蓝色、橙色和绿色。

Scatter Plot of Examples Generated from the Blobs Multi-Class Classification Problem

由斑点多类分类问题生成的示例散点图

输入特征是高斯型的,可以从标准化中受益;尽管如此,为了简洁起见,我们将在本例中保持这些值不变。

数据集将在训练集和测试集之间平均分割。

# split into train and test
n_train = 500
trainX, testX = X[:n_train, :], X[n_train:, :]
trainy, testy = y[:n_train], y[n_train:]

一个小的 MLP 模型将被用作探索损失函数的基础。

该模型需要两个输入变量,在隐藏层和校正线性激活函数中有 50 个节点,输出层必须根据损失函数的选择进行定制。

# define model
model = Sequential()
model.add(Dense(50, input_dim=2, activation='relu', kernel_initializer='he_uniform'))
model.add(Dense(..., activation='...'))

该模型使用随机梯度下降进行拟合,合理的默认学习率为 0.01,动量为 0.9。

# compile model
opt = SGD(lr=0.01, momentum=0.9)
model.compile(loss='...', optimizer=opt, metrics=['accuracy'])

该模型将适用于训练数据集上的 100 个时期,测试数据集将用作验证数据集,允许我们在每个训练时期结束时评估训练集和测试集的损失和分类准确率,并绘制学习曲线。

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

现在我们已经有了问题和模型的基础,我们可以看一下评估三个适用于多类分类预测建模问题的常见损失函数。

虽然在这些例子中使用了 MLP,但是当训练 CNN 和 RNN 模型进行多类分类时,可以使用相同的损失函数。

多类交叉熵损失

交叉熵是用于多类分类问题的默认损失函数。

在这种情况下,它旨在用于多类分类,其中目标值在集合{0,1,3,…,n}中,每个类都被分配一个唯一的整数值。

数学上,它是最大似然推理框架下的优选损失函数。首先要评估的是损失函数,只有在你有充分理由的情况下才能改变。

交叉熵将计算一个分数,该分数总结了问题中所有类别的实际和预测概率分布之间的平均差异。分数被最小化,完美的交叉熵值为 0。

在编译模型时,通过指定“分类 _ 交叉熵”,可以将交叉熵指定为 Keras 中的损失函数。

model.compile(loss='categorical_crossentropy', optimizer=opt, metrics=['accuracy'])

该功能要求输出层配置有一个 n 节点(每个类一个),在这种情况下为三个节点,以及一个“ softmax 激活,以便预测每个类的概率。

model.add(Dense(3, activation='softmax'))

反过来,这意味着目标变量必须是一个热编码的。

这是为了确保每个示例的实际类值的预期概率为 1.0,所有其他类值的预期概率为 0.0。这可以使用到 _ classic()Keras 函数来实现。

# one hot encode output variable
y = to_categorical(y)

下面列出了用于多类斑点分类问题的具有交叉熵损失的 MLP 的完整例子。

# mlp for the blobs multi-class classification problem with cross-entropy loss
from sklearn.datasets import make_blobs
from keras.layers import Dense
from keras.models import Sequential
from keras.optimizers import SGD
from keras.utils import to_categorical
from matplotlib import pyplot
# generate 2d classification dataset
X, y = make_blobs(n_samples=1000, centers=3, n_features=2, cluster_std=2, random_state=2)
# one hot encode output variable
y = to_categorical(y)
# split into train and test
n_train = 500
trainX, testX = X[:n_train, :], X[n_train:, :]
trainy, testy = y[:n_train], y[n_train:]
# define model
model = Sequential()
model.add(Dense(50, input_dim=2, activation='relu', kernel_initializer='he_uniform'))
model.add(Dense(3, activation='softmax'))
# compile model
opt = SGD(lr=0.01, momentum=0.9)
model.compile(loss='categorical_crossentropy', optimizer=opt, metrics=['accuracy'])
# fit model
history = model.fit(trainX, trainy, validation_data=(testX, testy), epochs=100, 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 loss during training
pyplot.subplot(211)
pyplot.title('Loss')
pyplot.plot(history.history['loss'], label='train')
pyplot.plot(history.history['val_loss'], label='test')
pyplot.legend()
# plot accuracy during training
pyplot.subplot(212)
pyplot.title('Accuracy')
pyplot.plot(history.history['accuracy'], label='train')
pyplot.plot(history.history['val_accuracy'], label='test')
pyplot.legend()
pyplot.show()

运行该示例首先打印模型在训练和测试数据集上的分类准确率。

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

在这种情况下,我们可以看到模型表现良好,在训练数据集上实现了大约 84%的分类准确率,在测试数据集上实现了大约 82%的分类准确率。

Train: 0.840, Test: 0.822

还创建了一个图形,显示了两条线图,顶部显示了列车(蓝色)和测试(橙色)数据集在不同时期的交叉熵损失,底部显示了不同时期的分类准确率。

在这种情况下,图表显示模型似乎已经收敛。交叉熵和准确度的线图都显示了良好的收敛行为,尽管有些颠簸。如果没有过拟合或拟合不足的迹象,模型可能配置良好。在这种情况下,可以调整学习率或批处理大小来平衡收敛的平滑度。

Line Plots of Cross Entropy Loss and Classification Accuracy over Training Epochs on the Blobs Multi-Class Classification Problem

斑点多类分类问题的交叉熵损失和训练时段分类准确率的线图

稀疏多类交叉熵损失

当对具有大量标签的分类问题使用交叉熵时,令人沮丧的一个可能原因是一个热门的编码过程。

例如,预测词汇中的单词可能有数万或数十万个类别,每个标签对应一个类别。这可能意味着每个训练示例的目标元素可能需要一个具有数万或数十万个零值的热编码向量,这需要大量内存。

稀疏交叉熵通过对误差执行相同的交叉熵计算来解决这个问题,而不需要目标变量在训练之前被热编码。

调用*编译()*函数时,使用“稀疏 _ 分类 _ 交叉熵,可以在 keras 中使用稀疏交叉熵进行多类分类。

model.compile(loss='sparse_categorical_crossentropy', optimizer=opt, metrics=['accuracy'])

该功能要求输出层配置有一个 n 节点(每个类一个),在这种情况下为三个节点,以及一个“ softmax 激活,以便预测每个类的概率。

model.add(Dense(3, activation='softmax'))

不需要对目标变量进行热编码,这是损失函数的一个好处。

下面列出了在斑点多类分类问题上用稀疏交叉熵训练 MLP 的完整例子。

# mlp for the blobs multi-class classification problem with sparse cross-entropy loss
from sklearn.datasets import make_blobs
from keras.layers import Dense
from keras.models import Sequential
from keras.optimizers import SGD
from matplotlib import pyplot
# generate 2d classification dataset
X, y = make_blobs(n_samples=1000, centers=3, n_features=2, cluster_std=2, random_state=2)
# split into train and test
n_train = 500
trainX, testX = X[:n_train, :], X[n_train:, :]
trainy, testy = y[:n_train], y[n_train:]
# define model
model = Sequential()
model.add(Dense(50, input_dim=2, activation='relu', kernel_initializer='he_uniform'))
model.add(Dense(3, activation='softmax'))
# compile model
opt = SGD(lr=0.01, momentum=0.9)
model.compile(loss='sparse_categorical_crossentropy', optimizer=opt, metrics=['accuracy'])
# fit model
history = model.fit(trainX, trainy, validation_data=(testX, testy), epochs=100, 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 loss during training
pyplot.subplot(211)
pyplot.title('Loss')
pyplot.plot(history.history['loss'], label='train')
pyplot.plot(history.history['val_loss'], label='test')
pyplot.legend()
# plot accuracy during training
pyplot.subplot(212)
pyplot.title('Accuracy')
pyplot.plot(history.history['accuracy'], label='train')
pyplot.plot(history.history['val_accuracy'], label='test')
pyplot.legend()
pyplot.show()

运行该示例首先打印模型在训练和测试数据集上的分类准确率。

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

在这种情况下,我们可以看到模型在问题上取得了良好的表现。事实上,如果多次重复实验,稀疏和非稀疏交叉熵的平均表现应该是相当的。

Train: 0.832, Test: 0.818

还创建了一个图形,显示了两条线图,顶部显示了列车(蓝色)和测试(橙色)数据集在不同时期的稀疏交叉熵损失,底部显示了不同时期的分类准确率。

在这种情况下,该图显示了模型在损失和分类准确率方面相对于训练的良好收敛性。

Line Plots of Sparse Cross Entropy Loss and Classification Accuracy over Training Epochs on the Blobs Multi-Class Classification Problem

斑点多类分类问题的稀疏交叉熵损失线图和训练时期的分类准确率

库尔巴克·莱布勒发散损失

库尔巴克·莱布勒散度,简称 KL 散度,是一个概率分布与基线分布差异的度量。

KL 散度损失为 0 表明分布是相同的。实际上,KL 散度的行为与交叉熵非常相似。如果使用预测的概率分布来近似期望的目标概率分布,它会计算丢失了多少信息(以比特为单位)。

因此,当使用学习逼近比简单的多类分类更复杂的函数的模型时,例如在用于在必须重建原始输入的模型下学习密集特征表示的自动编码器的情况下,KL 发散损失函数更常用。在这种情况下,KL 发散损失将是优选的。然而,它可以用于多类分类,在这种情况下,它在功能上等同于多类交叉熵。

通过在*编译()*函数中指定“kull back _ leibler _ diffusion”可以在 Keras 中使用 KL 散度损失。

model.compile(loss='kullback_leibler_divergence', optimizer=opt, metrics=['accuracy'])

与交叉熵一样,输出层配置有一个 n 节点(每个类一个),在这种情况下是三个节点,以及一个“ softmax 激活,以便预测每个类的概率。

此外,与分类交叉熵一样,我们必须对目标变量进行热编码,以使类值的预期概率为 1.0,所有其他类值的预期概率为 0.0。

# one hot encode output variable
y = to_categorical(y)

下面列出了为 blobs 多类分类问题训练具有 KL 散度损失的 MLP 的完整例子。

# mlp for the blobs multi-class classification problem with kl divergence loss
from sklearn.datasets import make_blobs
from keras.layers import Dense
from keras.models import Sequential
from keras.optimizers import SGD
from keras.utils import to_categorical
from matplotlib import pyplot
# generate 2d classification dataset
X, y = make_blobs(n_samples=1000, centers=3, n_features=2, cluster_std=2, random_state=2)
# one hot encode output variable
y = to_categorical(y)
# split into train and test
n_train = 500
trainX, testX = X[:n_train, :], X[n_train:, :]
trainy, testy = y[:n_train], y[n_train:]
# define model
model = Sequential()
model.add(Dense(50, input_dim=2, activation='relu', kernel_initializer='he_uniform'))
model.add(Dense(3, activation='softmax'))
# compile model
opt = SGD(lr=0.01, momentum=0.9)
model.compile(loss='kullback_leibler_divergence', optimizer=opt, metrics=['accuracy'])
# fit model
history = model.fit(trainX, trainy, validation_data=(testX, testy), epochs=100, 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 loss during training
pyplot.subplot(211)
pyplot.title('Loss')
pyplot.plot(history.history['loss'], label='train')
pyplot.plot(history.history['val_loss'], label='test')
pyplot.legend()
# plot accuracy during training
pyplot.subplot(212)
pyplot.title('Accuracy')
pyplot.plot(history.history['accuracy'], label='train')
pyplot.plot(history.history['val_accuracy'], label='test')
pyplot.legend()
pyplot.show()

运行该示例首先打印模型在训练和测试数据集上的分类准确率。

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

在这种情况下,我们看到的表现类似于交叉熵损失的结果,在这种情况下,训练和测试数据集的准确率约为 82%。

Train: 0.822, Test: 0.822

还创建了一个图形,显示了两条线图,顶部显示了列车(蓝色)和测试(橙色)数据集在不同时期的 KL 散度损失,底部显示了不同时期的分类准确率。

在这种情况下,该图显示了损失和分类准确率的良好收敛行为。考虑到度量的相似性,交叉熵的评估很可能导致几乎相同的行为。

Line Plots of KL Divergence Loss and Classification Accuracy over Training Epochs on the Blobs Multi-Class Classification Problem

斑点多类分类问题的 KL 散度损失和训练时期分类准确率的线图

进一步阅读

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

邮件

报纸

应用程序接口

文章

摘要

在本教程中,您发现了如何为给定预测建模问题的深度学习神经网络选择损失函数。

具体来说,您了解到:

  • 如何配置回归问题的均方误差和变量模型?
  • 如何为二分类配置交叉熵和铰链损失函数模型。
  • 如何为多类分类配置交叉熵和 KL 散度损失函数模型。

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

如何配置神经网络的层数和节点数

原文:machinelearningmastery.com/how-to-conf…

最后更新于 2019 年 8 月 6 日

人工神经网络有两个控制网络架构或拓扑的主要超参数:层数和每个隐藏层中的节点数。

配置网络时,必须指定这些参数的值。

为您的特定预测建模问题配置这些超参数的最可靠方法是通过使用强大的测试工具进行系统实验。

对于机器学习领域的初学者来说,这可能是一颗难以吞下的药丸,他们正在寻找一种计算最佳层数和节点数的分析方法,或者简单的经验法则。

在这篇文章中,你将发现层和节点的作用,以及如何为你的预测建模问题接近多层感知器神经网络的配置。

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

  • 单层和多层感知器网络的区别。
  • 网络中有一个和多个隐藏层的价值。
  • 配置网络层数和节点数的五种方法。

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

我们开始吧。

How to Configure the Number of Layers and Nodes in a Neural Network

如何配置神经网络中的层数和节点数 图片由瑞安提供,版权所有。

概观

该员额分为四个科;它们是:

  1. 多层感知器
  2. 如何计算层数?
  3. 为什么有多层?
  4. 要使用多少层和节点?

多层感知器

节点,也称为神经元或感知器,是一个具有一个或多个加权输入连接、以某种方式组合输入的传递函数和输出连接的计算单元。

节点随后被组织成层以构成网络。

单层人工神经网络,也叫单层,顾名思义,就是有单层的节点。单层中的每个节点都直接连接到一个输入变量,并贡献给一个输出变量。

单层网络只有一层活动单元。输入通过单层权重直接连接到输出。输出不相互作用,因此具有 N 个输出的网络可以被视为 N 个独立的单输出网络。

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

单层网络可以扩展到多层网络,称为多层感知器。多层感知器,简称 MLP,是一种具有多个单层的人工神经网络。

它有一个连接到输入变量的输入层,一个或多个隐藏层,以及一个产生输出变量的输出层。

标准多层感知器(MLP)是单层感知器的级联。有一层输入节点、一层输出节点和一个或多个中间层。内部层有时被称为“隐藏层”,因为它们不能从系统的输入和输出直接观察到。

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

我们可以将 MLP 的层类型总结如下:

  • 输入层:输入变量,有时称为可见层。
  • 隐藏层:输入和输出层之间的节点层。这些层可能有一层或多层。
  • 输出层:产生输出变量的节点层。

最后,有一些术语用来描述神经网络的形状和能力;例如:

  • 大小:模型中的节点数。
  • 宽度:特定层中的节点数。
  • 深度:神经网络中的层数。
  • 容量:网络配置可以学习的功能类型或结构。有时被称为“代表能力”。
  • 架构:网络中各层和节点的具体安排。

如何计算层数?

传统上,对于如何计算层数有一些分歧。

分歧集中在输入层是否被计算。有一种观点认为,它不应该被计算在内,因为输入不活跃;它们只是输入变量。我们将使用这个惯例;这也是《神经锻造*》一书中推荐的惯例。*

*因此,具有一个输入层、一个隐藏层和一个输出层的 MLP 是一个 2 层 MLP。

MLP 的结构可以用一个简单的符号来概括。

这种方便的表示法总结了层数和每层中的节点数。每层中的节点数被指定为一个整数,从输入层到输出层依次排列,每层的大小由正斜杠字符(“/”)分隔。

例如,输入层有两个变量,一个隐藏层有八个节点,一个输出层有一个节点的网络将使用符号 2/8/1 来描述。

我建议在描述多层感知器神经网络的层及其大小时使用这种符号。

为什么有多层?

在我们考虑要指定多少层之前,重要的是要考虑为什么我们要有多个层。

单层神经网络只能用于表示线性可分函数。这意味着非常简单的问题,比如,分类问题中的两个类可以用一条线整齐地分开。如果你的问题相对简单,也许单层网络就足够了。

我们感兴趣解决的大多数问题都不是线性可分的。

多层感知器可用于表示凸区域。这意味着,实际上,他们可以学习在一些高维空间中围绕例子绘制形状,这些形状可以对它们进行分离和分类,从而克服线性可分性的限制。

事实上,李普曼在 1987 年的论文《神经网络计算导论》中有一个理论发现,表明具有两个隐藏层的 MLP 足以创建任何期望形状的分类区域。这是有指导意义的,尽管应该注意的是,没有给出在每个层中使用多少节点或者如何学习权重的指示。

进一步的理论发现和证明表明,MLPs 是通用逼近器。有了一个隐藏层,MLP 可以逼近我们需要的任何函数。

具体而言,通用近似定理指出,具有线性输出层和至少一个具有任何“挤压”激活函数(例如逻辑 sigmoid 激活函数)的隐藏层的前馈网络可以以任何期望的非零误差量近似从一个有限维空间到另一个有限维空间的任何 Borel 可测函数,只要网络被给予足够的隐藏单元。

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

这是一个经常被引用的理论发现,并且有大量关于它的文献。在实践中,我们同样不知道对于给定的问题,在单个隐藏层中使用多少节点,也不知道如何有效地学习或设置它们的权重。此外,已经提出了许多反例,说明不能通过单个一隐层 MLP 直接学习的函数,或者需要无穷多个节点的函数。

即使对于那些可以通过足够大的一个隐藏层 MLP 来学习的函数,使用两个(或更多)隐藏层来学习也会更有效。

既然一个足够大的隐藏层足以逼近大多数函数,为什么会有人使用更多呢?一个原因在于“足够大”这几个字。虽然单个隐藏层对于某些功能来说是最佳的,但是对于其他功能,单个隐藏层解决方案与具有更多层的解决方案相比效率非常低。

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

要使用多少层和节点?

随着 MLPs 序言的结束,让我们进入你真正的问题。

您应该在多层感知器中使用多少层,每层有多少节点?

在这一节中,我们将列举解决这个问题的五种方法。

1)实验

一般来说,当我被问及 MLP 要使用多少层和节点时,我通常会回答:

我不知道。使用系统实验来发现什么最适合您的特定数据集。

我还是袖手旁观这个答案。

一般来说,您无法通过分析计算人工神经网络中的层数或每层使用的节点数来解决特定的现实预测建模问题。

层数和每层中的节点数是您必须指定的模型超参数。

你可能是第一个试图用神经网络解决你的特定问题的人。在你之前没人解决过。因此,没有人能告诉你如何配置网络的答案。

您必须使用强大的测试工具和受控实验来发现答案。例如,查看帖子:

不管你可能会遇到什么样的试探法,所有的答案都会回到仔细实验的需要,看看什么最适合你的特定数据集。

2)直觉

网络可以通过直觉进行配置。

例如,您可能有一种直觉,即需要深度网络来解决特定的预测建模问题。

深度模型提供了一个层次结构,从输入变量到输出变量,这些层次结构建立了越来越多的抽象层次。

给定对问题域的理解,我们可能认为需要深度层次模型来充分解决预测问题。在这种情况下,我们可以选择具有多层深度的网络配置。

选择深度模型编码了一个非常普遍的信念,即我们想要学习的函数应该包含几个更简单的函数的组合。这可以从表征学习的角度解释为,我们认为学习问题包括发现一组潜在的变异因素,这些因素又可以用其他更简单的潜在变异因素来描述。

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

这种直觉可以来自对领域的经验,对神经网络建模问题的经验,或者两者的某种混合。

以我的经验来看,直觉往往会因为实验而失效。

3)追求深度

古德费勒、本吉奥和库维尔在他们关于深度学习的重要教科书中强调,根据经验,在感兴趣的问题上,深度神经网络似乎表现得更好。

具体来说,他们陈述了在深度可能对直觉有益的情况下,使用深度神经网络作为统计参数的选择。

从经验来看,更大的深度似乎确实会导致更好地概括各种各样的任务。[……]这表明使用深度架构确实表达了模型所学习的功能空间的有用先验。

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

我们可以用这个论点来建议,使用深层网络,即具有许多层的网络,可能是一种启发式的方法来配置网络,以应对具有挑战性的预测建模问题。

这类似于从表格数据预测建模问题的随机森林随机梯度提升开始的建议,以在测试其他方法之前快速获得模型技能的上限。

4)借用想法

一个简单但可能耗时的方法是利用文献中报道的发现。

找一些研究论文,描述 MLPs 在预测问题上的应用,这些问题在某些方面与你的问题相似。记下这些论文中使用的网络配置,并将其作为测试问题配置的起点。

模型超参数的可转移性导致熟练的模型从一个问题到另一个问题是一个具有挑战性的开放问题,也是为什么模型超参数配置更像艺术而不是科学的原因。

然而,用于相关问题的网络层和节点数量是测试想法的良好起点。

5)搜索

设计自动搜索来测试不同的网络配置。

你可以从文学和直觉中寻找灵感。

一些流行的搜索策略包括:

  • 随机:尝试层和每层节点的随机配置。
  • 网格:尝试跨层数和每层节点数进行系统搜索。
  • 启发式:尝试跨配置的定向搜索,如遗传算法或贝叶斯优化。
  • 穷举:尝试所有的层组合和节点数;这对于小型网络和数据集可能是可行的。

对于大型模型、大型数据集以及两者的组合,这可能是一个挑战。减少或管理计算负担的一些想法包括:

  • 在训练数据集的较小子集上拟合模型,以加快搜索速度。
  • 积极地限制搜索空间的大小。
  • 跨多个服务器实例并行化搜索(例如,使用亚马逊 EC2 服务)。

如果时间和资源允许,我建议系统化。

更大的

我见过无数的试探法,如何估计层数,或者神经元总数,或者每层神经元数。

我不想一一列举;我怀疑它们除了被证明的特殊情况之外,还能增加实际价值。

如果你对这个领域感兴趣,也许可以从“神经锻造一书中的“第 4.4 节容量与尺寸”开始。它总结了这方面的大量发现。这本书是从 1999 年开始的,所以如果你愿意的话,在这一领域还有将近 20 年的想法要走。

此外,参见进一步阅读部分(如下)中链接的一些讨论。

我错过了你最喜欢的配置神经网络的方法了吗?或者你知道一个关于这个话题的好的参考资料吗? 在下面的评论里告诉我。

进一步阅读

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

报纸

文章

讨论

摘要

在这篇文章中,你发现了层和节点的作用,以及如何配置多层感知器神经网络。

具体来说,您了解到:

  • 单层和多层感知器网络的区别。
  • 网络中有一个和多个隐藏层的价值。
  • 配置网络层数和节点数的五种方法。

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

如何使用节点和层控制神经网络模型容量

原文:machinelearningmastery.com/how-to-cont…

最后更新于 2020 年 8 月 25 日

深度学习神经网络模型的能力控制它能够学习的映射函数类型的范围。

容量太小的模型无法学习训练数据集,这意味着它会欠载,而容量太大的模型可能会记住训练数据集,这意味着它会过载,或者可能会在优化过程中卡住或丢失。

神经网络模型的容量是通过配置节点数和层数来定义的。

在本教程中,您将发现如何控制神经网络模型的容量,以及容量如何影响模型的学习能力。

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

  • 神经网络模型容量由模型中的节点数和层数控制。
  • 具有单个隐藏层和足够数量的节点的模型具有学习任何映射函数的能力,但是所选择的学习算法可能能够或者不能够实现这种能力。
  • 增加层数提供了用更少的资源增加模型容量的捷径,现代技术允许学习算法成功地训练深度模型。

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

我们开始吧。

  • 2020 年 1 月更新:针对 Sklearn v0.22 API 的变化进行了更新。

How to Control Neural Network Model Capacity With Nodes and Layers

如何用节点和层控制神经网络模型容量 图片由伯纳德·斯拉格提供。新西兰,保留部分权利。

教程概述

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

  1. 控制神经网络模型容量
  2. 在 Keras 中配置节点和层
  3. 多类分类问题
  4. 使用节点更改模型容量
  5. 改变模型容量和层数

控制神经网络模型容量

神经网络的目标是学习如何将输入示例映射到输出示例。

神经网络学习映射函数。网络的容量是指模型可以近似的功能类型的范围或范围。

非正式地说,模型的能力是它适应各种功能的能力。

—第 111-112 页,深度学习,2016。

容量较小的模型可能无法充分学习训练数据集。容量更大的模型可以对更多不同类型的函数进行建模,并且可能能够学习一个函数来将输入充分映射到训练数据集中的输出。然而,容量太大的模型可能会记住训练数据集,并且不能概括或迷失或陷入对合适的映射函数的搜索中。

一般来说,我们可以将模型容量视为对模型是否可能对训练数据集进行欠填充或过填充的控制。

我们可以通过改变一个模型的容量来控制它是更有可能超载还是超载。

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

神经网络的容量可以通过模型的两个方面来控制:

  • 节点数。
  • 层数。

具有更多节点或更多层的模型具有更大的容量,进而有可能学习更大的映射函数集。

具有更多层和每层更多隐藏单元的模型具有更高的表示能力——它能够表示更复杂的功能。

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

一层中的节点数称为宽度

开发一层多节点的广域网相对简单。理论上,在单个隐藏层中具有足够节点的网络可以学习逼近任何映射函数,尽管在实践中,我们不知道有多少节点是足够的,也不知道如何训练这样的模型。

模型中的层数被称为其深度

增加深度会增加模型的容量。训练深层模型,例如具有许多隐藏层的模型,比训练具有大量节点的单层网络在计算上更有效率。

现代深度学习为监督学习提供了一个非常强大的框架。通过在一个层中添加更多的层和更多的单元,深度网络可以代表越来越复杂的功能。

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

传统上,由于梯度消失等问题,训练具有多个层的神经网络模型具有挑战性。最近,现代方法已经允许深度网络模型的训练,允许开发令人惊讶的深度的模型,其能够在广泛领域的挑战性问题上实现令人印象深刻的表现。

在 Keras 中配置节点和层

Keras 允许您轻松地将节点和层添加到模型中。

配置模型节点

层的第一个参数指定层中使用的节点数。

多层感知器或 MLP 模型的完全连接层是通过密集层添加的。

例如,我们可以创建一个具有 32 个节点的全连接层,如下所示:

...
layer = Dense(32)

类似地,可以以相同的方式为递归神经网络层指定节点的数量。

例如,我们可以创建一个具有 32 个节点(或单元)的 LSTM 层,如下所示:

...
layer = LSTM(32)

卷积神经网络,或 CNN,没有节点,而是指定过滤器映射的数量和它们的形状。过滤图的数量和大小决定了层的容量。

我们可以用 32 个过滤图定义一个二维 CNN,每个过滤图的大小为 3 乘 3,如下所示:

...
layer = Conv2D(32, (3,3))

配置模型层

通过调用 add()函数并传入层,层被添加到顺序模型中。

MLP 的全连接层可以通过重复调用来添加,以在已配置的密集层中添加通道;例如:

...
model = Sequential()
model.add(Dense(32))
model.add(Dense(64))

类似地,循环网络的层数可以以相同的方式添加,以给出堆叠的循环模型。

一个重要的区别是递归层期望三维输入,因此先前的递归层必须返回完整的输出序列,而不是输入序列末尾每个节点的单个输出。

这可以通过将“return _ sequence”参数设置为“ True 来实现。例如:

...
model = Sequential()
model.add(LSTM(32, return_sequences=True))
model.add(LSTM(32))

卷积层可以直接堆叠,通常是将一两个卷积层堆叠在一起,然后是一个池化层,然后重复这种层的模式;例如:

...
model = Sequential()
model.add(Conv2D(16, (3,3)))
model.add(Conv2D(16, (3,3)))
model.add(MaxPooling2D((2,2)))
model.add(Conv2D(32, (3,3)))
model.add(Conv2D(32, (3,3)))
model.add(MaxPooling2D((2,2)))

现在我们知道了如何在 Keras 中为模型配置节点和层的数量,我们可以看看容量如何影响多类分类问题上的模型表现。

多类分类问题

我们将使用一个标准的多类分类问题作为基础来演示模型容量对模型表现的影响。

Sklearn 类提供了 make_blobs()函数,该函数可用于创建具有规定数量的样本、输入变量、类和类内样本方差的多类分类问题。

我们可以通过“ n_features ”参数将问题配置为具有特定数量的输入变量,并通过“ centers ”参数配置特定数量的类或中心。“ random_state ”可用于给伪随机数发生器播种,以确保每次调用函数时我们总是获得相同的样本。

例如,下面的调用为一个有两个输入变量的三类问题生成了 1000 个例子。

...
# generate 2d classification dataset
X, y = make_blobs(n_samples=1000, centers=3, n_features=2, cluster_std=2, random_state=2)

结果是我们可以建模的数据集的输入和输出元素。

为了了解问题的复杂性,我们可以在二维散点图上绘制每个点,并按类值给每个点着色。

下面列出了完整的示例。

# scatter plot of blobs dataset
from sklearn.datasets import make_blobs
from matplotlib import pyplot
from numpy import where
# generate 2d classification dataset
X, y = make_blobs(n_samples=1000, centers=3, n_features=2, cluster_std=2, random_state=2)
# scatter plot for each class value
for class_value in range(3):
	# select indices of points with the class label
	row_ix = where(y == class_value)
	# scatter plot for points with a different color
	pyplot.scatter(X[row_ix, 0], X[row_ix, 1])
# show plot
pyplot.show()

运行该示例会创建整个数据集的散点图。我们可以看到,选择的标准偏差为 2.0 意味着类不是线性可分的(用一条线可分),导致很多不明确的点。

这是可取的,因为这意味着问题不是微不足道的,并将允许神经网络模型找到许多不同的“T0”足够好的“T1”候选解决方案。

Scatter Plot of Blobs Dataset With Three Classes and Points Colored by Class Value

具有三个类和按类值着色的点的斑点数据集的散点图

为了探索模型容量,我们需要比三个类和两个变量更复杂的问题。

为了以下实验的目的,我们将使用 100 个输入特征和 20 个类;例如:

...
# generate 2d classification dataset
X, y = make_blobs(n_samples=1000, centers=20, n_features=100, cluster_std=2, random_state=2)

使用节点更改模型容量

在本节中,我们将开发一个多层感知器模型,或 MLP,用于 blobs 多类分类问题,并演示节点数量对模型学习能力的影响。

我们可以从开发一个函数来准备数据集开始。

数据集的输入和输出元素可以使用上一节中描述的 make_blobs() 函数来创建。

接下来,目标变量必须是一个热编码的。这是为了使模型能够学习预测输入示例属于 20 个类中的每一个的概率。

我们可以使用to _ classic()Keras 效用函数来实现,例如:

# one hot encode output variable
y = to_categorical(y)

接下来,我们可以将 1,000 个示例分成两半,使用 500 个示例作为训练数据集,使用 500 个示例来评估模型。

# split into train and test
n_train = 500
trainX, testX = X[:n_train, :], X[n_train:, :]
trainy, testy = y[:n_train], y[n_train:]
return trainX, trainy, testX, testy

下面的 create_dataset() 函数将这些元素联系在一起,并根据输入和输出元素返回训练和测试集。

# prepare multi-class classification dataset
def create_dataset():
	# generate 2d classification dataset
	X, y = make_blobs(n_samples=1000, centers=20, n_features=100, cluster_std=2, random_state=2)
	# one hot encode output variable
	y = to_categorical(y)
	# split into train and test
	n_train = 500
	trainX, testX = X[:n_train, :], X[n_train:, :]
	trainy, testy = y[:n_train], y[n_train:]
	return trainX, trainy, testX, testy

我们可以调用这个函数来准备数据集。

# prepare dataset
trainX, trainy, testX, testy = create_dataset()

接下来,我们可以定义一个函数来创建模型,使其适合训练数据集,然后在测试数据集上对其进行评估。

模型需要知道输入变量的数量以便配置输入层,并且需要知道目标类的数量以便配置输出层。这些属性可以直接从训练数据集中提取。

# configure the model based on the data
n_input, n_classes = trainX.shape[1], testy.shape[1]

我们将定义一个具有单个隐藏层的模型,该模型使用校正的线性激活函数和 he 随机权重初始化方法。

输出层将使用 softmax 激活函数来预测每个目标类的概率。隐藏层中的节点数量将通过名为“ n_nodes ”的参数提供。

# define model
model = Sequential()
model.add(Dense(n_nodes, input_dim=n_input, activation='relu', kernel_initializer='he_uniform'))
model.add(Dense(n_classes, activation='softmax'))

该模型将使用随机梯度下降进行优化,学习率为 0.01,高动量为 0.9,并将使用分类交叉熵损失函数,适用于多类分类。

# compile model
opt = SGD(lr=0.01, momentum=0.9)
model.compile(loss='categorical_crossentropy', optimizer=opt, metrics=['accuracy'])

该模型将适合 100 个训练时期,然后将在测试数据集上评估该模型。

# fit model on train set
history = model.fit(trainX, trainy, epochs=100, verbose=0)
# evaluate model on test set
_, test_acc = model.evaluate(testX, testy, verbose=0)

将这些元素联系在一起,下面的 evaluate_model() 函数将节点数和数据集作为参数,并返回每个时期结束时的训练损失历史以及最终模型在测试数据集上的准确性。

# fit model with given number of nodes, returns test set accuracy
def evaluate_model(n_nodes, trainX, trainy, testX, testy):
	# configure the model based on the data
	n_input, n_classes = trainX.shape[1], testy.shape[1]
	# define model
	model = Sequential()
	model.add(Dense(n_nodes, input_dim=n_input, activation='relu', kernel_initializer='he_uniform'))
	model.add(Dense(n_classes, activation='softmax'))
	# compile model
	opt = SGD(lr=0.01, momentum=0.9)
	model.compile(loss='categorical_crossentropy', optimizer=opt, metrics=['accuracy'])
	# fit model on train set
	history = model.fit(trainX, trainy, epochs=100, verbose=0)
	# evaluate model on test set
	_, test_acc = model.evaluate(testX, testy, verbose=0)
	return history, test_acc

我们可以用不同数量的节点来调用这个函数,以便在隐藏层中使用。

问题相对简单;因此,我们将回顾具有 1 到 7 个节点的模型的表现。

我们预计,随着节点数量的增加,这将增加模型的容量,并允许模型更好地学习训练数据集,至少在学习算法的所选配置(例如,学习率、批次大小和时期)所限制的点上。

将打印每个配置的测试准确率,并绘制每个配置的训练准确率的学习曲线。

# evaluate model and plot learning curve with given number of nodes
num_nodes = [1, 2, 3, 4, 5, 6, 7]
for n_nodes in num_nodes:
	# evaluate model with a given number of nodes
	history, result = evaluate_model(n_nodes, trainX, trainy, testX, testy)
	# summarize final test set accuracy
	print('nodes=%d: %.3f' % (n_nodes, result))
	# plot learning curve
	pyplot.plot(history.history['loss'], label=str(n_nodes))
# show the plot
pyplot.legend()
pyplot.show()

为了完整起见,下面提供了完整的代码列表。

# study of mlp learning curves given different number of nodes for multi-class classification
from sklearn.datasets import make_blobs
from keras.layers import Dense
from keras.models import Sequential
from keras.optimizers import SGD
from keras.utils import to_categorical
from matplotlib import pyplot

# prepare multi-class classification dataset
def create_dataset():
	# generate 2d classification dataset
	X, y = make_blobs(n_samples=1000, centers=20, n_features=100, cluster_std=2, random_state=2)
	# one hot encode output variable
	y = to_categorical(y)
	# split into train and test
	n_train = 500
	trainX, testX = X[:n_train, :], X[n_train:, :]
	trainy, testy = y[:n_train], y[n_train:]
	return trainX, trainy, testX, testy

# fit model with given number of nodes, returns test set accuracy
def evaluate_model(n_nodes, trainX, trainy, testX, testy):
	# configure the model based on the data
	n_input, n_classes = trainX.shape[1], testy.shape[1]
	# define model
	model = Sequential()
	model.add(Dense(n_nodes, input_dim=n_input, activation='relu', kernel_initializer='he_uniform'))
	model.add(Dense(n_classes, activation='softmax'))
	# compile model
	opt = SGD(lr=0.01, momentum=0.9)
	model.compile(loss='categorical_crossentropy', optimizer=opt, metrics=['accuracy'])
	# fit model on train set
	history = model.fit(trainX, trainy, epochs=100, verbose=0)
	# evaluate model on test set
	_, test_acc = model.evaluate(testX, testy, verbose=0)
	return history, test_acc

# prepare dataset
trainX, trainy, testX, testy = create_dataset()
# evaluate model and plot learning curve with given number of nodes
num_nodes = [1, 2, 3, 4, 5, 6, 7]
for n_nodes in num_nodes:
	# evaluate model with a given number of nodes
	history, result = evaluate_model(n_nodes, trainX, trainy, testX, testy)
	# summarize final test set accuracy
	print('nodes=%d: %.3f' % (n_nodes, result))
	# plot learning curve
	pyplot.plot(history.history['loss'], label=str(n_nodes))
# show the plot
pyplot.legend()
pyplot.show()

运行示例首先打印每个模型配置的测试准确率。

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

在这种情况下,我们可以看到,随着节点数量的增加,模型学习问题的能力也会增加。这导致模型在测试数据集上的泛化误差逐渐降低,直到模型完美地学习问题的 6 和 7 个节点。

nodes=1: 0.138
nodes=2: 0.380
nodes=3: 0.582
nodes=4: 0.890
nodes=5: 0.844
nodes=6: 1.000
nodes=7: 1.000

还创建了一个线图,显示了 100 个训练时期内每个模型配置(隐藏层中的 1 到 7 个节点)的训练数据集中的交叉熵损失。

我们可以看到,随着节点数量的增加,模型能够更好地减少损失,例如更好地学习训练数据集。该图显示了模型容量与模型学习能力之间的直接关系,模型容量由隐藏层中的节点数量定义。

Line Plot of Cross Entropy Loss Over Training Epochs for an MLP on the Training Dataset for the Blobs Multi-Class Classification Problem When Varying Model Nodes

当改变模型节点时,斑点多类分类问题训练数据集中 MLP 在训练时期的交叉熵损失线图

节点的数量可以增加到学习算法不再能够充分学习映射函数的程度(例如 1000 个节点)。

改变模型容量和层数

我们可以执行类似的分析,并评估层数如何影响模型学习映射函数的能力。

增加层数通常可以大大增加模型的容量,就像建模问题的计算和学习捷径。例如,一个包含 10 个节点的隐藏层的模型不等同于两个包含 5 个节点的隐藏层的模型。后者的容量要大得多。

危险在于,容量超过要求的模型可能会过度训练训练数据,并且与具有太多节点的模型一样,具有太多层的模型可能无法学习训练数据集,从而在优化过程中迷失或停滞。

首先,我们可以更新 evaluate_model() 函数来拟合具有给定层数的 MLP 模型。

从上一节中我们知道,一个大约有七个或更多节点的 MLP 适合 100 个时代,它将完美地学习这个问题。因此,我们将在每一层中使用 10 个节点,以确保模型在一层中有足够的容量来学习问题。

下面列出了更新后的函数,以层数和数据集为参数,返回模型的训练历史和测试准确率。

# fit model with given number of layers, returns test set accuracy
def evaluate_model(n_layers, trainX, trainy, testX, testy):
	# configure the model based on the data
	n_input, n_classes = trainX.shape[1], testy.shape[1]
	# define model
	model = Sequential()
	model.add(Dense(10, input_dim=n_input, activation='relu', kernel_initializer='he_uniform'))
	for _ in range(1, n_layers):
		model.add(Dense(10, activation='relu', kernel_initializer='he_uniform'))
	model.add(Dense(n_classes, activation='softmax'))
	# compile model
	opt = SGD(lr=0.01, momentum=0.9)
	model.compile(loss='categorical_crossentropy', optimizer=opt, metrics=['accuracy'])
	# fit model
	history = model.fit(trainX, trainy, epochs=100, verbose=0)
	# evaluate model on test set
	_, test_acc = model.evaluate(testX, testy, verbose=0)
	return history, test_acc

假设单个隐藏层模型有足够的能力学习这个问题,我们将探索增加层数,使学习算法变得不稳定,无法再学习这个问题。

如果选择的建模问题更复杂,我们可以探索增加层次,并回顾模型表现的改进,直到收益递减。

在这种情况下,我们将评估具有 1 到 5 层的模型,期望在某一点上,层数将导致所选择的学习算法不能适应训练数据的模型。

# evaluate model and plot learning curve of model with given number of layers
all_history = list()
num_layers = [1, 2, 3, 4, 5]
for n_layers in num_layers:
	# evaluate model with a given number of layers
	history, result = evaluate_model(n_layers, trainX, trainy, testX, testy)
	print('layers=%d: %.3f' % (n_layers, result))
	# plot learning curve
	pyplot.plot(history.history['loss'], label=str(n_layers))
pyplot.legend()
pyplot.show()

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

# study of mlp learning curves given different number of layers for multi-class classification
from sklearn.datasets import make_blobs
from keras.models import Sequential
from keras.layers import Dense
from keras.optimizers import SGD
from keras.utils import to_categorical
from matplotlib import pyplot

# prepare multi-class classification dataset
def create_dataset():
	# generate 2d classification dataset
	X, y = make_blobs(n_samples=1000, centers=20, n_features=100, cluster_std=2, random_state=2)
	# one hot encode output variable
	y = to_categorical(y)
	# split into train and test
	n_train = 500
	trainX, testX = X[:n_train, :], X[n_train:, :]
	trainy, testy = y[:n_train], y[n_train:]
	return trainX, trainy, testX, testy

# fit model with given number of layers, returns test set accuracy
def evaluate_model(n_layers, trainX, trainy, testX, testy):
	# configure the model based on the data
	n_input, n_classes = trainX.shape[1], testy.shape[1]
	# define model
	model = Sequential()
	model.add(Dense(10, input_dim=n_input, activation='relu', kernel_initializer='he_uniform'))
	for _ in range(1, n_layers):
		model.add(Dense(10, activation='relu', kernel_initializer='he_uniform'))
	model.add(Dense(n_classes, activation='softmax'))
	# compile model
	opt = SGD(lr=0.01, momentum=0.9)
	model.compile(loss='categorical_crossentropy', optimizer=opt, metrics=['accuracy'])
	# fit model
	history = model.fit(trainX, trainy, epochs=100, verbose=0)
	# evaluate model on test set
	_, test_acc = model.evaluate(testX, testy, verbose=0)
	return history, test_acc

# get dataset
trainX, trainy, testX, testy = create_dataset()
# evaluate model and plot learning curve of model with given number of layers
all_history = list()
num_layers = [1, 2, 3, 4, 5]
for n_layers in num_layers:
	# evaluate model with a given number of layers
	history, result = evaluate_model(n_layers, trainX, trainy, testX, testy)
	print('layers=%d: %.3f' % (n_layers, result))
	# plot learning curve
	pyplot.plot(history.history['loss'], label=str(n_layers))
pyplot.legend()
pyplot.show()

运行示例首先打印每个模型配置的测试准确率。

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

在这种情况下,我们可以看到模型能够很好地学习问题,最多有三层,然后开始动摇。我们可以看到,五层的表现确实下降了,如果层数进一步增加,预计还会继续下降。

layers=1: 1.000
layers=2: 1.000
layers=3: 1.000
layers=4: 0.948
layers=5: 0.794

还创建了一个线图,显示了 100 个训练时期内每个模型配置(1 至 5 层)在训练数据集上的交叉熵损失。

我们可以看到,1、2 和 3 个模型(蓝色、橙色和绿色)的模型动力学非常相似,学习问题很快。

令人惊讶的是,四层和五层的训练损失显示出最初表现良好的迹象,然后跳跃上升,这表明模型可能停留在次优的权重集,而不是过拟合训练数据集。

Line Plot of Cross Entropy Loss Over Training Epochs for an MLP on the Training Dataset for the Blobs Multi-Class Classification Problem When Varying Model Layers

当改变模型层时,斑点多类分类问题的训练数据集中 MLP 在训练时期的交叉熵损失的线图

分析表明,通过增加深度来增加模型的容量是一个非常有效的工具,必须谨慎使用,因为它可能会很快导致模型具有较大的容量,而这可能无法轻松学习训练数据集。

扩展ˌ扩张

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

  • 节点太多。更新增加节点的实验,找到学习算法不再能够学习问题的点。
  • 重复评估。更新一个实验,使用每个配置的重复评估来对抗学习算法的随机性质。
  • 更难的问题。对一个需要通过增加深度来增加容量的问题重复增加层数的实验,以获得良好的表现。

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

进一步阅读

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

邮件

应用程序接口

文章

摘要

在本教程中,您发现了如何控制神经网络模型的容量,以及容量如何影响模型的学习能力。

具体来说,您了解到:

  • 神经网络模型容量由模型中的节点数和层数控制。
  • 具有单个隐藏层和足够数量的节点的模型具有学习任何映射函数的能力,但是所选择的学习算法可能能够或者不能够实现这种能力。
  • 增加层数提供了用更少的资源增加模型容量的捷径,现代技术允许学习算法成功地训练深度模型。

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

如何使用批量大小控制神经网络训练的稳定性

原文:machinelearningmastery.com/how-to-cont…

最后更新于 2020 年 8 月 28 日

使用梯度下降来训练神经网络,其中基于训练数据集的子集来计算用于更新权重的误差估计。

误差梯度估计中使用的训练数据集中的样本数称为批量,是影响学习算法动态性的重要超参数。

探索模型的动态性是很重要的,以确保您能从中获得最大收益。

在本教程中,您将发现三种不同风格的梯度下降,以及如何探索和诊断批次大小对学习过程的影响。

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

  • 当训练神经网络时,批量控制误差梯度估计的准确率。
  • 批处理、随机和迷你批处理梯度下降是学习算法的三种主要风格。
  • 批量大小与学习过程的速度和稳定性之间存在紧张关系。

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

我们开始吧。

  • 2019 年 10 月更新:针对 Keras 2.3 和 TensorFlow 2.0 更新。
  • 2020 年 1 月更新:针对 Sklearn v0.22 API 的变化进行了更新。

How to Control the Speed and Stability of Training Neural Networks With Gradient Descent Batch Size

如何控制梯度下降批量训练神经网络的速度和稳定性阿德里安·斯科托摄,版权所有。

教程概述

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

  1. 批量和梯度下降
  2. Keras 的随机、批量和小批量梯度下降
  3. 多类分类问题
  4. 批量梯度下降的 MLP 拟合
  5. 随机梯度下降的 MLP 拟合
  6. MLP 适合迷你批次梯度下降
  7. 批量对模型行为的影响

批量和梯度下降

使用随机梯度下降优化算法训练神经网络。

这包括使用模型的当前状态进行预测,将预测与期望值进行比较,并将差值用作误差梯度的估计。该误差梯度然后被用于更新模型权重,并且该过程被重复。

误差梯度是一种统计估计。估计中使用的训练示例越多,该估计就越准确,网络的权重就越有可能以提高模型表现的方式进行调整。误差梯度的改进估计值的代价是,在计算估计值之前,必须使用模型进行更多的预测,进而更新权重。

使用整个训练集的优化算法被称为批量或确定性梯度方法,因为它们在大批量中同时处理所有训练示例。

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

或者,使用较少的示例会导致误差梯度的估计不太准确,这高度依赖于所使用的特定训练示例。

这导致了噪声估计,而噪声估计又导致模型权重的噪声更新,例如,许多更新可能具有非常不同的误差梯度估计。尽管如此,这些有噪声的更新可以导致更快的学习,有时会导致更健壮的模型。

一次只使用一个例子的优化算法有时被称为随机方法,有时被称为在线方法。“在线”一词通常用于从连续创建的示例流中提取示例的情况,而不是从固定大小的训练集中提取示例,在训练集中要进行多次遍历。

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

误差梯度估计中使用的训练示例的数量是学习算法的超参数,称为“批次大小,或简称为“批次

批量为 32 意味着在更新模型权重之前,将使用训练数据集中的 32 个样本来估计误差梯度。一个训练时期意味着学习算法已经一次通过训练数据集,其中示例被分成随机选择的“批量组。

历史上,将批量设置为训练示例总数的训练算法称为“批量梯度下降”,将批量设置为 1 个训练示例的训练算法称为“随机梯度下降或“在线梯度下降

介于两者之间的批处理大小的配置(例如,多于 1 个示例且少于训练数据集中的示例数量)称为“小批处理梯度下降

  • 批量梯度下降。批处理大小设置为训练数据集中的示例总数。
  • 随机梯度下降。批量设置为 1。
  • 迷你批次梯度下降。批处理大小被设置为大于 1 且小于训练数据集中的示例总数。

简而言之,该算法通常被称为随机梯度下降,与批量大小无关。考虑到非常大的数据集通常用于训练深度学习神经网络,批量大小很少被设置为训练数据集的大小。

使用较小批量有两个主要原因:

  • 较小的批次尺寸会产生噪声,从而提供正则化效果和较低的泛化误差。
  • 较小的批处理大小使得在内存中容纳一批训练数据变得更容易(即使用图形处理器时)。

第三个原因是批量大小通常被设置为较小的值,例如 32 个例子,并且不是由从业者调整的。像 32 这样的小批量通常效果很好。

…[批量大小]通常选择在 1 到几百之间,例如[批量大小] = 32 是一个很好的默认值

——深度架构基于梯度训练的实用建议,2012。

所呈现的结果证实,在广泛的实验中,对于给定的计算成本,使用小批量实现了最佳的训练稳定性和泛化表现。在所有情况下,批次大小 m = 32 或更小,通常小至 m = 2 或 m = 4,就能获得最佳结果。

——重温深度神经网络小批量训练,2018。

然而,批量大小影响模型学习的速度和学习过程的稳定性。这是一个重要的超参数,深度学习实践者应该很好地理解和调整它。

Keras 的随机、批量和小批量梯度下降

Keras 允许您使用随机、批量或小批量梯度下降来训练模型。

这可以通过在训练模型时调用 fit() 函数时设置 batch_size 参数来实现。

让我们依次看看每种方法。

Keras 随机梯度下降

下面的示例将随机梯度下降的 batch_size 参数设置为 1。

...
model.fit(trainX, trainy, batch_size=1)

Keras 批量梯度下降

下面的示例将 batch_size 参数设置为批处理梯度下降训练数据集中的样本数。

...
model.fit(trainX, trainy, batch_size=len(trainX))

Keras 的迷你批次梯度下降

以下示例对 batch_size 参数使用默认的批处理大小 32,对于随机梯度下降,该值大于 1,对于批处理梯度下降,该值小于训练数据集的大小。

...
model.fit(trainX, trainy)

或者,可以将 batch_size 指定为 1 或训练数据集中的样本数之外的值,例如 64。

...
model.fit(trainX, trainy, batch_size=64)

多类分类问题

我们将使用一个小的多类分类问题作为基础来演示批量大小对学习的影响。

Sklearn 类提供了 make_blobs()函数,该函数可用于创建具有规定数量的样本、输入变量、类和类内样本方差的多类分类问题。

该问题可以配置为具有两个输入变量(表示点的 xy 坐标)和每组内点的标准偏差 2.0。我们将使用相同的随机状态(伪随机数发生器的种子)来确保我们总是获得相同的数据点。

# generate 2d classification dataset
X, y = make_blobs(n_samples=1000, centers=3, n_features=2, cluster_std=2, random_state=2)

结果是我们可以建模的数据集的输入和输出元素。

为了了解问题的复杂性,我们可以在二维散点图上绘制每个点,并按类值给每个点着色。

下面列出了完整的示例。

# scatter plot of blobs dataset
from sklearn.datasets import make_blobs
from matplotlib import pyplot
from numpy import where
# generate 2d classification dataset
X, y = make_blobs(n_samples=1000, centers=3, n_features=2, cluster_std=2, random_state=2)
# scatter plot for each class value
for class_value in range(3):
	# select indices of points with the class label
	row_ix = where(y == class_value)
	# scatter plot for points with a different color
	pyplot.scatter(X[row_ix, 0], X[row_ix, 1])
# show plot
pyplot.show()

运行该示例会创建整个数据集的散点图。我们可以看到,2.0 的标准偏差意味着类不是线性可分的(用一条线可分的),导致了很多不明确的点。

这是可取的,因为这意味着问题不是微不足道的,并将允许神经网络模型找到许多不同的“T0”足够好的“T1”候选解决方案。

Scatter Plot of Blobs Dataset With Three Classes and Points Colored by Class Value

具有三个类和按类值着色的点的斑点数据集的散点图

批量梯度下降的 MLP 拟合

我们可以开发一个多层感知器模型(MLP)来解决前一节中描述的多类分类问题,并使用批处理梯度下降来训练它。

首先,我们需要对目标变量进行热编码,将整数类值转换为二进制向量。这将允许模型预测每个例子属于三个类别中的每一个的概率,在训练模型时在预测和上下文中提供更多的细微差别。

# one hot encode output variable
y = to_categorical(y)

接下来,我们将把 1000 个例子的训练数据集分割成一个训练和测试数据集,每个数据集有 500 个例子。

这种均匀分割将允许我们评估和比较模型上不同批量配置的表现及其表现。

# split into train and test
n_train = 500
trainX, testX = X[:n_train, :], X[n_train:, :]
trainy, testy = y[:n_train], y[n_train:]

对于数据集中的两个变量,我们将定义一个带有输入层的 MLP 模型,该模型需要两个输入变量。

该模型将有一个单一的 50 个节点的隐藏层和一个校正的线性激活函数和何随机权重初始化。最后,输出层有 3 个节点,以便对三个类和一个 softmax 激活函数进行预测。

# define model
model = Sequential()
model.add(Dense(50, input_dim=2, activation='relu', kernel_initializer='he_uniform'))
model.add(Dense(3, activation='softmax'))

我们将使用随机梯度下降优化模型,并在训练过程中使用分类交叉熵来计算模型的误差。

在这个例子中,我们将使用“批次梯度下降,这意味着批次大小将被设置为训练数据集的大小。该模型将适用于 200 个训练时期,测试数据集将用作验证集,以便在训练期间监控模型在保持集上的表现。

效果将是权重更新之间的时间更长,并且我们期望比其他批量更快的训练,以及更稳定的梯度估计,这将导致模型在训练期间更稳定的表现。

# compile model
opt = SGD(lr=0.01, momentum=0.9)
model.compile(loss='categorical_crossentropy', optimizer=opt, metrics=['accuracy'])
# fit model
history = model.fit(trainX, trainy, validation_data=(testX, testy), epochs=200, verbose=0, batch_size=len(trainX))

一旦模型合适,就在训练和测试数据集上评估和报告表现。

# 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['accuracy'], label='train')
pyplot.plot(history.history['val_accuracy'], label='test')
pyplot.legend()
pyplot.show()

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

# mlp for the blobs problem with batch gradient descent
from sklearn.datasets import make_blobs
from keras.layers import Dense
from keras.models import Sequential
from keras.optimizers import SGD
from keras.utils import to_categorical
from matplotlib import pyplot
# generate 2d classification dataset
X, y = make_blobs(n_samples=1000, centers=3, n_features=2, cluster_std=2, random_state=2)
# one hot encode output variable
y = to_categorical(y)
# split into train and test
n_train = 500
trainX, testX = X[:n_train, :], X[n_train:, :]
trainy, testy = y[:n_train], y[n_train:]
# define model
model = Sequential()
model.add(Dense(50, input_dim=2, activation='relu', kernel_initializer='he_uniform'))
model.add(Dense(3, activation='softmax'))
# compile model
opt = SGD(lr=0.01, momentum=0.9)
model.compile(loss='categorical_crossentropy', optimizer=opt, metrics=['accuracy'])
# fit model
history = model.fit(trainX, trainy, validation_data=(testX, testy), epochs=200, verbose=0, batch_size=len(trainX))
# 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['accuracy'], label='train')
pyplot.plot(history.history['val_accuracy'], label='test')
pyplot.legend()
pyplot.show()

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

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

在这种情况下,我们可以看到训练集和测试集的表现相似,分别为 81%和 83%。

Train: 0.816, Test: 0.830

创建列车(蓝色)和测试(橙色)数据集上模型分类准确率的线图。我们可以看到,模型学习这个问题的速度相对较慢,大约 100 个时代后就收敛到一个解决方案上,之后模型表现的变化很小。

Line Plot of Classification Accuracy on Train and Tests Sets of an MLP Fit With Batch Gradient Descent

列车分类准确率线图和批量梯度下降的 MLP 拟合检验集

随机梯度下降的 MLP 拟合

上一节中的批量梯度下降示例可以更新为使用随机梯度下降。

这需要将批处理大小从训练数据集的大小更改为 1。

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

随机梯度下降要求模型进行预测,并为每个训练示例更新权重。与批量梯度下降相比,这具有显著减慢训练过程的效果。

这种变化的预期是模型学习得更快,并且模型的变化是有噪声的,这反过来导致训练时期的噪声表现。

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

# mlp for the blobs problem with stochastic gradient descent
from sklearn.datasets import make_blobs
from keras.layers import Dense
from keras.models import Sequential
from keras.optimizers import SGD
from keras.utils import to_categorical
from matplotlib import pyplot
# generate 2d classification dataset
X, y = make_blobs(n_samples=1000, centers=3, n_features=2, cluster_std=2, random_state=2)
# one hot encode output variable
y = to_categorical(y)
# split into train and test
n_train = 500
trainX, testX = X[:n_train, :], X[n_train:, :]
trainy, testy = y[:n_train], y[n_train:]
# define model
model = Sequential()
model.add(Dense(50, input_dim=2, activation='relu', kernel_initializer='he_uniform'))
model.add(Dense(3, activation='softmax'))
# compile model
opt = SGD(lr=0.01, momentum=0.9)
model.compile(loss='categorical_crossentropy', optimizer=opt, metrics=['accuracy'])
# fit model
history = model.fit(trainX, trainy, validation_data=(testX, testy), epochs=200, verbose=0, batch_size=1)
# 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['accuracy'], label='train')
pyplot.plot(history.history['val_accuracy'], label='test')
pyplot.legend()
pyplot.show()

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

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

在这种情况下,我们可以看到训练集和测试集之间的表现是相似的,大约 60%的准确率,但是比使用批量梯度下降的表现差得多(大约 20 个百分点)。

至少对于这个问题和所选择的模型和模型配置,随机(在线)梯度下降是不合适的。

Train: 0.612, Test: 0.606

创建列车(蓝色)和测试(橙色)数据集上模型分类准确率的线图。

该图显示了所选配置的训练过程的不稳定性。表现不佳,模型变化剧烈,说明每次训练示例后用于更新权重的学习率可能过大,较小的学习率可能会使学习过程更加稳定。

Line Plot of Classification Accuracy on Train and Tests Sets of an MLP Fit With Stochastic Gradient Descent

列车分类准确率线图及随机梯度下降 MLP 拟合检验集

我们可以通过用随机梯度下降和较小的学习率重新运行模型拟合来测试这一点。例如,我们可以将学习率降低一个数量级,从 0.01 到 0.001。

# compile model
opt = SGD(lr=0.001, momentum=0.9)
model.compile(loss='categorical_crossentropy', optimizer=opt, metrics=['accuracy'])

为了完整起见,下面提供了包含此更改的完整代码列表。

# mlp for the blobs problem with stochastic gradient descent
from sklearn.datasets import make_blobs
from keras.layers import Dense
from keras.models import Sequential
from keras.optimizers import SGD
from keras.utils import to_categorical
from matplotlib import pyplot
# generate 2d classification dataset
X, y = make_blobs(n_samples=1000, centers=3, n_features=2, cluster_std=2, random_state=2)
# one hot encode output variable
y = to_categorical(y)
# split into train and test
n_train = 500
trainX, testX = X[:n_train, :], X[n_train:, :]
trainy, testy = y[:n_train], y[n_train:]
# define model
model = Sequential()
model.add(Dense(50, input_dim=2, activation='relu', kernel_initializer='he_uniform'))
model.add(Dense(3, activation='softmax'))
# compile model
opt = SGD(lr=0.001, momentum=0.9)
model.compile(loss='categorical_crossentropy', optimizer=opt, metrics=['accuracy'])
# fit model
history = model.fit(trainX, trainy, validation_data=(testX, testy), epochs=200, verbose=0, batch_size=1)
# 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['accuracy'], label='train')
pyplot.plot(history.history['val_accuracy'], label='test')
pyplot.legend()
pyplot.show()

运行这个例子讲述了一个非常不同的故事。

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

报告的表现大大提高,在列车和测试集上实现了与使用批量梯度下降的拟合相当的分类准确率。

Train: 0.816, Test: 0.824

线形图显示了预期的行为。也就是说,与分批梯度下降相比,该模型快速学习问题,在大约 25 个时期内跳跃到大约 80%的准确率,而不是使用分批梯度下降时看到的 100 个时期。由于训练速度更快,我们本可以在第 50 期而不是第 200 期停止训练。

这并不奇怪。使用批量梯度下降,100 个时期涉及 100 个误差估计和 100 个权重更新。在随机梯度下降中,涉及 25 个时期(500 * 25)或 12,500 个权重更新,为如何改进模型提供了超过 10 倍的反馈,尽管反馈噪声更大。

线图还显示,与批次梯度下降的动力学相比,训练和测试表现在训练期间保持相当,批次梯度下降的动力学在测试集上的表现稍好,并且在整个训练期间保持相当。

与批量梯度下降不同,我们可以看到,在整个训练期间,有噪声的更新会导致有噪声的表现。模型中的这种差异意味着,选择哪种模型作为最终模型可能具有挑战性,这与批量梯度下降相反,在批量梯度下降中,表现是稳定的,因为模型已经收敛。

Line Plot of Classification Accuracy on Train and Tests Sets of an MLP Fit With Stochastic Gradient Descent and Smaller Learning Rate

列车上分类准确率的线图和具有随机梯度下降和较小学习率的 MLP 拟合的测试集

这个例子强调了批量和学习率之间的重要关系。也就是说,对模型的噪声更大的更新需要更小的学习率,而噪声更小的误差梯度的更精确的估计可以更自由地应用于模型。我们可以总结如下:

  • 批量梯度下降:使用相对较大的学习率和较多的训练时期。
  • 随机梯度下降:使用相对较小的学习率和较少的训练时期。

小批量梯度下降提供了一种替代方法。

MLP 适合迷你批次梯度下降

使用随机梯度下降和调整学习率的另一种方法是保持学习率不变并改变批量大小。

实际上,这意味着我们指定每次估计误差梯度时应用于权重的学习率或变化量,但根据用于估计的样本数量来改变梯度的准确率。

将学习率保持在 0.01,就像我们使用批处理梯度下降一样,我们可以将批处理大小设置为 32,这是一个广泛采用的默认批处理大小。

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

我们期望以更大的学习率获得随机梯度下降的一些好处。

下面列出了这种修改的完整示例。

# mlp for the blobs problem with minibatch gradient descent
from sklearn.datasets import make_blobs
from keras.layers import Dense
from keras.models import Sequential
from keras.optimizers import SGD
from keras.utils import to_categorical
from matplotlib import pyplot
# generate 2d classification dataset
X, y = make_blobs(n_samples=1000, centers=3, n_features=2, cluster_std=2, random_state=2)
# one hot encode output variable
y = to_categorical(y)
# split into train and test
n_train = 500
trainX, testX = X[:n_train, :], X[n_train:, :]
trainy, testy = y[:n_train], y[n_train:]
# define model
model = Sequential()
model.add(Dense(50, input_dim=2, activation='relu', kernel_initializer='he_uniform'))
model.add(Dense(3, activation='softmax'))
# compile model
opt = SGD(lr=0.01, momentum=0.9)
model.compile(loss='categorical_crossentropy', optimizer=opt, metrics=['accuracy'])
# fit model
history = model.fit(trainX, trainy, validation_data=(testX, testy), epochs=200, verbose=0, batch_size=32)
# 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['accuracy'], label='train')
pyplot.plot(history.history['val_accuracy'], label='test')
pyplot.legend()
pyplot.show()

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

运行该示例在训练集和测试集上都报告了相似的表现,在我们降低学习率之后,可以与批处理梯度下降和随机梯度下降相媲美。

Train: 0.832, Test: 0.812

线形图显示了随机和分批梯度下降的动力学。具体来说,该模型学习速度快,有噪声更新,但在接近运行结束时更稳定,比随机梯度下降更稳定。

保持学习率不变并改变批量大小,可以让您在两种方法中选择最佳方法。

Line Plot of Classification Accuracy on Train and Tests Sets of an MLP Fit With Minibatch Gradient Descent

列车分类准确率线图和具有小批量梯度下降的 MLP 拟合测试集

批量对模型行为的影响

我们可以用不同的批次大小重新调整模型,并回顾批次大小的变化对学习速度、学习过程中的稳定性以及最终结果的影响。

首先,我们可以清理代码并创建一个函数来准备数据集。

# prepare train and test dataset
def prepare_data():
	# generate 2d classification dataset
	X, y = make_blobs(n_samples=1000, centers=3, n_features=2, cluster_std=2, random_state=2)
	# one hot encode output variable
	y = to_categorical(y)
	# split into train and test
	n_train = 500
	trainX, testX = X[:n_train, :], X[n_train:, :]
	trainy, testy = y[:n_train], y[n_train:]
	return trainX, trainy, testX, testy

接下来,我们可以创建一个函数来拟合给定批量的问题模型,并在训练和测试数据集上绘制分类准确率的学习曲线。

# fit a model and plot learning curve
def fit_model(trainX, trainy, testX, testy, n_batch):
	# define model
	model = Sequential()
	model.add(Dense(50, input_dim=2, activation='relu', kernel_initializer='he_uniform'))
	model.add(Dense(3, activation='softmax'))
	# compile model
	opt = SGD(lr=0.01, momentum=0.9)
	model.compile(loss='categorical_crossentropy', optimizer=opt, metrics=['accuracy'])
	# fit model
	history = model.fit(trainX, trainy, validation_data=(testX, testy), epochs=200, verbose=0, batch_size=n_batch)
	# plot learning curves
	pyplot.plot(history.history['accuracy'], label='train')
	pyplot.plot(history.history['val_accuracy'], label='test')
	pyplot.title('batch='+str(n_batch), pad=-40)

最后,我们可以用一组不同的批处理大小来评估模型行为,同时保持模型的其他一切不变,包括学习率。

# prepare dataset
trainX, trainy, testX, testy = prepare_data()
# create learning curves for different batch sizes
batch_sizes = [4, 8, 16, 32, 64, 128, 256, 450]
for i in range(len(batch_sizes)):
	# determine the plot number
	plot_no = 420 + (i+1)
	pyplot.subplot(plot_no)
	# fit model and plot learning curves for a batch size
	fit_model(trainX, trainy, testX, testy, batch_sizes[i])
# show learning curves
pyplot.show()

结果将是一个具有八个不同批次大小的八个模型行为图的图形。

将这些联系在一起,完整的示例如下所示。

# mlp for the blobs problem with minibatch gradient descent with varied batch size
from sklearn.datasets import make_blobs
from keras.layers import Dense
from keras.models import Sequential
from keras.optimizers import SGD
from keras.utils import to_categorical
from matplotlib import pyplot

# prepare train and test dataset
def prepare_data():
	# generate 2d classification dataset
	X, y = make_blobs(n_samples=1000, centers=3, n_features=2, cluster_std=2, random_state=2)
	# one hot encode output variable
	y = to_categorical(y)
	# split into train and test
	n_train = 500
	trainX, testX = X[:n_train, :], X[n_train:, :]
	trainy, testy = y[:n_train], y[n_train:]
	return trainX, trainy, testX, testy

# fit a model and plot learning curve
def fit_model(trainX, trainy, testX, testy, n_batch):
	# define model
	model = Sequential()
	model.add(Dense(50, input_dim=2, activation='relu', kernel_initializer='he_uniform'))
	model.add(Dense(3, activation='softmax'))
	# compile model
	opt = SGD(lr=0.01, momentum=0.9)
	model.compile(loss='categorical_crossentropy', optimizer=opt, metrics=['accuracy'])
	# fit model
	history = model.fit(trainX, trainy, validation_data=(testX, testy), epochs=200, verbose=0, batch_size=n_batch)
	# plot learning curves
	pyplot.plot(history.history['accuracy'], label='train')
	pyplot.plot(history.history['val_accuracy'], label='test')
	pyplot.title('batch='+str(n_batch), pad=-40)

# prepare dataset
trainX, trainy, testX, testy = prepare_data()
# create learning curves for different batch sizes
batch_sizes = [4, 8, 16, 32, 64, 128, 256, 450]
for i in range(len(batch_sizes)):
	# determine the plot number
	plot_no = 420 + (i+1)
	pyplot.subplot(plot_no)
	# fit model and plot learning curves for a batch size
	fit_model(trainX, trainy, testX, testy, batch_sizes[i])
# show learning curves
pyplot.show()

运行该示例创建了一个带有八条线图的图形,显示了使用小批量梯度下降时列车和不同批量模型测试集的分类准确率。

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

这些图显示,小批量通常导致快速学习,但学习过程不稳定,分类准确率差异较大。较大的批量会减慢学习过程,但最终阶段会收敛到更稳定的模型,例如分类准确率的较低方差。

Line Plots of Classification Accuracy on Train and Test Datasets With Different Batch Sizes

不同批量的训练和测试数据集上分类准确率的线图

进一步阅读

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

邮件

报纸

文章

摘要

在本教程中,您发现了三种不同风格的梯度下降,以及如何探索和诊断批次大小对学习过程的影响。

具体来说,您了解到:

  • 当训练神经网络时,批量控制误差梯度估计的准确率。
  • 批处理、随机和迷你批处理梯度下降是学习算法的三种主要风格。
  • 批量大小与学习过程的速度和稳定性之间存在紧张关系。

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