神经网络使用梯度下降进行训练,其中用于更新权重的误差估计是基于训练数据集的子集计算的。
用于误差梯度估计的训练数据集中的示例数量称为批量大小,是一个影响学习算法动力学的重要超参数。
探索模型的动力学以确保你充分利用它非常重要。
在本教程中,你将了解三种不同的梯度下降方法,以及如何探索和诊断批量大小对学习过程的影响。
完成本教程后,您将了解:
- 批量大小控制训练神经网络时误差梯度估计的准确性。
- 批量、随机和小型批量梯度下降是学习算法的三种主要方法。
- 批量大小与学习过程的速度和稳定性之间存在一种权衡。
用我的新书《更好的深度学习》来启动你的项目,书中包含分步教程和所有示例的 Python 源代码文件。
让我们开始吧。
- 2019 年 10 月更新:更新至 Keras 2.3 和 TensorFlow 2.0。
- **2020年1月更新**:已针对 scikit-learn v0.22 API 的变更进行更新。

如何通过梯度下降批量大小控制训练神经网络的速度和稳定性
照片由 Adrian Scottow 拍摄,保留部分权利。
教程概述
本教程分为七个部分,它们是:
- 批量大小与梯度下降
- Keras 中的随机、批量和小型批量梯度下降
- 多类别分类问题
- 批量梯度下降拟合 MLP
- 随机梯度下降拟合 MLP
- 小型批量梯度下降拟合 MLP
- 批量大小对模型行为的影响
批量大小与梯度下降
神经网络使用随机梯度下降优化算法进行训练。
这包括使用模型的当前状态进行预测,将预测与期望值进行比较,并将差异作为误差梯度的估计。此误差梯度然后用于更新模型权重,过程重复。
误差梯度是一个统计估计。估计中使用的训练示例越多,该估计就越准确,网络的权重就越有可能以改善模型性能的方式进行调整。误差梯度估计的改进是以在计算估计之前使用模型进行更多预测并进而更新权重为代价的。
使用整个训练集的优化算法被称为批量或确定性梯度方法,因为它们同时处理所有训练示例,在一个大的批量中。
— 第 278 页,深度学习,2016。
或者,使用较少的示例会导致误差梯度的估计不够准确,并且高度依赖于使用的特定训练示例。
这会导致估计值有噪声,进而导致模型权重的更新有噪声,例如许多更新可能具有相当不同的误差梯度估计。尽管如此,这些有噪声的更新可以实现更快的学习,有时还能获得更鲁棒的模型。
一次仅使用单个示例的优化算法有时被称为随机方法或在线方法。术语在线通常保留给从不断创建的示例流中抽取示例的情况,而不是来自对其中进行了几次遍历的固定大小的训练集。
— 第 278 页,深度学习,2016。
用于误差梯度估计的训练示例数量是学习算法的一个超参数,称为“批量大小”,或简称为“批量”。
批量大小为 32 意味着在更新模型权重之前,将使用 32 个训练数据集的样本来估计误差梯度。一次训练周期意味着学习算法已经遍历了一次训练数据集,其中示例被分成随机选择的“批量大小”组。
历史上,将批量大小设置为训练示例总数的训练算法称为“批量梯度下降”,将批量大小设置为 1 个训练示例的训练算法称为“随机梯度下降”或“在线梯度下降”。
介于两者之间的批量大小配置(例如,多于 1 个示例且少于训练数据集中的示例数量)称为“小型批量梯度下降”。
- 批量梯度下降。批量大小设置为训练数据集中的总示例数。
- 随机梯度下降。批量大小设置为一。
- 小型批量梯度下降。批量大小设置为多于一个且少于训练数据集中的示例总数。
为了简洁起见,该算法通常被称为随机梯度下降,无论批量大小如何。鉴于深度学习神经网络通常使用非常大的数据集进行训练,因此批量大小很少设置为训练数据集的大小。
使用较小的批量大小有两个主要原因
- 较小的批量大小会产生噪声,提供正则化效果并降低泛化误差。
- 较小的批量大小使得将一个批次的训练数据放入内存中更容易(例如,在使用 GPU 时)。
第三个原因是批量大小通常设置为较小的值,例如 32 个示例,并且不经过实践者的调整。像 32 这样的小批量大小通常效果很好。
…[批量大小]通常选择在 1 到几百之间,例如[批量大小] = 32 是一个不错的默认值
— 深度架构梯度训练的实用建议,2012。
所呈现的结果证实,在广泛的实验中,使用小批量大小在给定的计算成本下实现了最佳的训练稳定性和泛化性能。在所有情况下,使用批量大小 m = 32 或更小(通常小至 m = 2 或 m = 4)都能获得最佳结果。
— 重新审视深度神经网络的小批量训练,2018。
尽管如此,批量大小会影响模型学习的速度和学习过程的稳定性。它是一个重要的超参数,深度学习从业者应该充分理解和调整它。
想要通过深度学习获得更好的结果吗?
立即参加我为期7天的免费电子邮件速成课程(附示例代码)。
点击注册,同时获得该课程的免费PDF电子书版本。
Keras 中的随机、批量和小型批量梯度下降
Keras 允许你使用随机、批量或小型批量梯度下降来训练模型。
这可以通过在训练模型时调用fit()函数来设置 batch_size 参数来实现。
让我们逐一来看每种方法。
Keras 中的随机梯度下降
下面的示例将 batch_size 参数设置为 1 以进行随机梯度下降。
1 2 |
... model.fit(trainX, trainy, batch_size=1) |
Keras 中的批量梯度下降
下面的示例将 batch_size 参数设置为训练数据集中的样本数量,以进行批量梯度下降。
1 2 |
... model.fit(trainX, trainy, batch_size=len(trainX)) |
Keras 中的小型批量梯度下降
下面的示例使用 32 的默认 batch_size 参数,这比随机梯度下降的 1 大,并且小于批量梯度下降的训练数据集大小。
1 2 |
... model.fit(trainX, trainy) |
或者,可以将 batch_size 指定为除了 1 或训练数据集样本数量之外的其他值,例如 64。
1 2 |
... model.fit(trainX, trainy, batch_size=64) |
多类别分类问题
我们将使用一个小的多类分类问题作为基础来演示批量大小对学习的影响。
scikit-learn 类提供了make_blobs() 函数,可用于创建具有指定样本数量、输入变量、类别和类别内样本方差的多类分类问题。
该问题可以配置为具有两个输入变量(表示点的x和y坐标)以及每个组内点的标准差为 2.0。我们将使用相同的随机状态(伪随机数生成器的种子)来确保我们始终获得相同的数据点。
1 2 |
# 生成二维分类数据集 X, y = make_blobs(n_samples=1000, centers=3, n_features=2, cluster_std=2, random_state=2) |
结果是我们可以建模的数据集的输入和输出元素。
为了了解问题的复杂性,我们可以在二维散点图上绘制每个点,并根据类别值对每个点进行着色。
完整的示例如下所示。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
# blob 数据集的散点图 from sklearn.datasets import make_blobs from matplotlib import pyplot from numpy import where # 生成二维分类数据集 X, y = make_blobs(n_samples=1000, centers=3, n_features=2, cluster_std=2, random_state=2) # 每个类别值的散点图 for class_value in range(3): # 选择具有类标签的点的索引 row_ix = where(y == class_value) # 绘制不同颜色点的散点图 pyplot.scatter(X[row_ix, 0], X[row_ix, 1]) # 显示图 pyplot.show() |
运行此示例将生成整个数据集的散点图。我们可以看到,标准差为 2.0 意味着这些类不是线性可分的(不能用一条线分开),导致许多模糊的点。
这是可取的,因为它意味着问题并非微不足道,并且将允许神经网络模型找到许多不同的“足够好”的候选解决方案。

具有三个类别且点按类别值着色的 Blob 数据集散点图
批量梯度下降拟合 MLP
我们可以开发一个多层感知器模型(MLP)来解决上一节所述的多类分类问题,并使用批量梯度下降对其进行训练。
首先,我们需要对目标变量进行独热编码,将整数类值转换为二进制向量。这将使模型能够预测每个示例属于三个类别中每个类别的概率,从而在预测中提供更多细微差别,并在训练模型时提供上下文。
1 2 |
# 独热编码输出变量 y = to_categorical(y) |
接下来,我们将 1000 个示例的训练数据集划分为每个 500 个示例的训练集和测试集。
这种均等划分将使我们能够评估和比较不同批量大小配置对模型及其性能的影响。
1 2 3 4 |
# 分割成训练集和测试集 n_train = 500 trainX, testX = X[:n_train, :], X[n_train:, :] trainy, testy = y[:n_train], y[n_train:] |
我们将定义一个 MLP 模型,其中输入层期望两个输入变量,对应于数据集中使用的两个变量。
模型将具有一个隐藏层,包含 50 个节点,并采用 ReLU 激活函数和 He 随机权重初始化。最后,输出层有 3 个节点,用于预测三个类别,并采用 softmax 激活函数。
1 2 3 4 |
# 定义模型 model = Sequential() model.add(Dense(50, input_dim=2, activation='relu', kernel_initializer='he_uniform')) model.add(Dense(3, activation='softmax')) |
我们将使用随机梯度下降来优化模型,并使用分类交叉熵来计算训练期间模型的误差。
在此示例中,我们将使用“批量梯度下降”,这意味着批量大小将设置为训练数据集的大小。模型将训练 200 个训练周期,并将测试数据集用作验证集,以便在训练期间监控模型在保持集上的性能。
这将导致权重更新之间的时间更长,我们预计训练速度会比其他批量大小更快,并且梯度估计更稳定,这应该会导致模型在训练期间的性能更稳定。
1 2 3 4 5 |
# 编译模型 opt = SGD(lr=0.01, momentum=0.9) model.compile(loss='categorical_crossentropy', optimizer=opt, metrics=['accuracy']) # 拟合模型 history = model.fit(trainX, trainy, validation_data=(testX, testy), epochs=200, verbose=0, batch_size=len(trainX)) |
模型拟合完成后,将评估并在训练集和测试集上报告性能。
1 2 3 4 |
# 评估模型 _, 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)) |
创建折线图显示模型在每个训练周期在训练集和测试集上的准确率。
这些学习曲线提供了三件事的指示:模型学习问题的速度,它学习问题的程度,以及训练期间模型更新的噪声程度。
1 2 3 4 5 |
# 绘制训练历史 pyplot.plot(history.history['accuracy'], label='train') pyplot.plot(history.history['val_accuracy'], label='test') pyplot.legend() pyplot.show() |
将这些元素联系起来,完整的示例如下。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
# mlp 用于 blobs 问题,使用批量梯度下降 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 # 生成二维分类数据集 X, y = make_blobs(n_samples=1000, centers=3, n_features=2, cluster_std=2, random_state=2) # 独热编码输出变量 y = to_categorical(y) # 分割成训练集和测试集 n_train = 500 trainX, testX = X[:n_train, :], X[n_train:, :] trainy, testy = y[:n_train], y[n_train:] # 定义模型 model = Sequential() model.add(Dense(50, input_dim=2, activation='relu', kernel_initializer='he_uniform')) model.add(Dense(3, activation='softmax')) # 编译模型 opt = SGD(lr=0.01, momentum=0.9) model.compile(loss='categorical_crossentropy', optimizer=opt, metrics=['accuracy']) # 拟合模型 history = model.fit(trainX, trainy, validation_data=(testX, testy), epochs=200, verbose=0, batch_size=len(trainX)) # 评估模型 _, 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)) # 绘制训练历史 pyplot.plot(history.history['accuracy'], label='train') pyplot.plot(history.history['val_accuracy'], label='test') pyplot.legend() pyplot.show() |
运行该示例首先报告模型在训练集和测试集上的性能。
注意:您每次得到的结果可能不同,这取决于算法或评估程序的随机性,或者数值精度的差异。请考虑多次运行示例并比较平均结果。
在这种情况下,我们可以看到训练集和测试集之间的性能相似,分别为 81% 和 83%。
1 |
训练:0.816,测试:0.830 |
创建了一个模型分类准确率在训练集(蓝色)和测试集(橙色)上的折线图。我们可以看到模型学习此问题的速度相对较慢,在大约 100 个周期后收敛到解决方案,之后模型性能的变化很小。

批量梯度下降拟合 MLP 在训练集和测试集上的分类准确率折线图
随机梯度下降拟合 MLP
上一节的批量梯度下降示例可以更新为使用随机梯度下降。
这需要将批量大小从训练数据集的大小更改为 1。
1 2 |
# 拟合模型 history = model.fit(trainX, trainy, validation_data=(testX, testy), epochs=200, verbose=0, batch_size=1) |
随机梯度下降要求模型为每个训练示例进行预测并更新权重。与批量梯度下降相比,这会极大地减慢训练过程。
此更改的预期效果是模型学习速度更快,并且模型更改是嘈杂的,反过来又会导致训练周期中的性能嘈杂。
进行了此更改的完整示例如下所示。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
# mlp 用于 blobs 问题,使用随机梯度下降 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 # 生成二维分类数据集 X, y = make_blobs(n_samples=1000, centers=3, n_features=2, cluster_std=2, random_state=2) # 独热编码输出变量 y = to_categorical(y) # 分割成训练集和测试集 n_train = 500 trainX, testX = X[:n_train, :], X[n_train:, :] trainy, testy = y[:n_train], y[n_train:] # 定义模型 model = Sequential() model.add(Dense(50, input_dim=2, activation='relu', kernel_initializer='he_uniform')) model.add(Dense(3, activation='softmax')) # 编译模型 opt = SGD(lr=0.01, momentum=0.9) model.compile(loss='categorical_crossentropy', optimizer=opt, metrics=['accuracy']) # 拟合模型 history = model.fit(trainX, trainy, validation_data=(testX, testy), epochs=200, verbose=0, batch_size=1) # 评估模型 _, 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)) # 绘制训练历史 pyplot.plot(history.history['accuracy'], label='train') pyplot.plot(history.history['val_accuracy'], label='test') pyplot.legend() pyplot.show() |
运行该示例首先报告模型在训练集和测试集上的性能。
注意:您每次得到的结果可能不同,这取决于算法或评估程序的随机性,或者数值精度的差异。请考虑多次运行示例并比较平均结果。
在这种情况下,我们可以看到训练集和测试集之间的性能相似,大约为 60% 的准确率,但比使用批量梯度下降差得多(约 20 个百分点)。
至少对于这个问题以及选择的模型和模型配置,随机(在线)梯度下降是不合适的。
1 |
训练:0.612,测试:0.606 |
创建了一个模型分类准确率在训练集(蓝色)和测试集(橙色)上的折线图。
该图显示了所选配置下训练过程的不稳定性。糟糕的性能和模型剧烈的变化表明用于更新每个训练示例后权重的学习率可能过高,而较小的学习率可能会使学习过程更稳定。

随机梯度下降拟合 MLP 在训练集和测试集上的分类准确率折线图
我们可以通过重新运行随机梯度下降模型拟合和较小的学习率来测试这一点。例如,我们可以将学习率从 0.01 降低一个数量级到 0.001。
1 2 3 |
# 编译模型 opt = SGD(lr=0.001, momentum=0.9) model.compile(loss='categorical_crossentropy', optimizer=opt, metrics=['accuracy']) |
为完整性起见,下面提供了包含此更改的完整代码清单。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
# mlp 用于 blobs 问题,使用随机梯度下降 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 # 生成二维分类数据集 X, y = make_blobs(n_samples=1000, centers=3, n_features=2, cluster_std=2, random_state=2) # 独热编码输出变量 y = to_categorical(y) # 分割成训练集和测试集 n_train = 500 trainX, testX = X[:n_train, :], X[n_train:, :] trainy, testy = y[:n_train], y[n_train:] # 定义模型 model = Sequential() model.add(Dense(50, input_dim=2, activation='relu', kernel_initializer='he_uniform')) model.add(Dense(3, activation='softmax')) # 编译模型 opt = SGD(lr=0.001, momentum=0.9) model.compile(loss='categorical_crossentropy', optimizer=opt, metrics=['accuracy']) # 拟合模型 history = model.fit(trainX, trainy, validation_data=(testX, testy), epochs=200, verbose=0, batch_size=1) # 评估模型 _, 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)) # 绘制训练历史 pyplot.plot(history.history['accuracy'], label='train') pyplot.plot(history.history['val_accuracy'], label='test') pyplot.legend() pyplot.show() |
运行此示例会讲述一个截然不同的故事。
注意:您每次得到的结果可能不同,这取决于算法或评估程序的随机性,或者数值精度的差异。请考虑多次运行示例并比较平均结果。
报告的性能得到了极大提高,在训练集和测试集上的分类准确率与使用批量梯度下降拟合的性能相当。
1 |
训练:0.816,测试:0.824 |
折线图显示了预期的行为。也就是说,模型学习问题的速度比批量梯度下降快,大约在 25 个周期内跃升至约 80% 的准确率,而不是批量梯度下降的 100 个周期。由于训练速度更快,我们可以将训练停止在第 50 个周期而不是第 200 个。
这并不奇怪。使用批量梯度下降,100 个周期涉及 100 次误差估计和 100 次权重更新。在随机梯度下降中,25 个周期涉及(500 * 25)或 12,500 次权重更新,提供了超过 10 倍的反馈,尽管反馈更嘈杂,关于如何改进模型。
折线图还显示,训练和测试性能在训练过程中保持可比,与批量梯度下降的动态相比,后者在测试集上的性能略好,并在整个训练过程中保持如此。
与批量梯度下降不同,我们可以看到嘈杂的更新会导致整个训练过程中的性能嘈杂。模型中的这种方差意味着选择哪个模型作为最终模型可能很困难,而批量梯度下降由于模型已收敛,性能得到了稳定。

随机梯度下降和较小学习率的 MLP 在训练集和测试集上的分类准确率折线图
此示例突出了批量大小和学习率之间的重要关系。也就是说,对模型的更嘈杂的更新需要更小的学习率,而对模型的更新更少嘈杂、更准确的误差梯度估计可以更自由地应用。我们可以将其总结如下:
- 批量梯度下降:使用相对较大的学习率和更多的训练周期。
- 随机梯度下降:使用相对较小的学习率和更少的训练周期。
小型批量梯度下降提供了一种替代方法。
小型批量梯度下降拟合 MLP
与使用随机梯度下降和调整学习率的替代方法是保持学习率不变并更改批量大小。
实际上,这意味着我们指定了每次估算误差梯度时应用于权重的学习速率或变化量,但要通过用于估算它的样本数量来改变梯度的准确性。
将学习率保持为 0.01,就像我们在批量梯度下降中所做的那样,我们可以将批量大小设置为 32,这是一个广泛采用的默认批量大小。
1 2 |
# 拟合模型 history = model.fit(trainX, trainy, validation_data=(testX, testy), epochs=200, verbose=0, batch_size=32) |
我们期望获得随机梯度下降的一些好处,但具有更大的学习率。
此修改的完整示例列在下面。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
# mlp 用于 blobs 问题,使用小型批量梯度下降 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 # 生成二维分类数据集 X, y = make_blobs(n_samples=1000, centers=3, n_features=2, cluster_std=2, random_state=2) # 独热编码输出变量 y = to_categorical(y) # 分割成训练集和测试集 n_train = 500 trainX, testX = X[:n_train, :], X[n_train:, :] trainy, testy = y[:n_train], y[n_train:] # 定义模型 model = Sequential() model.add(Dense(50, input_dim=2, activation='relu', kernel_initializer='he_uniform')) model.add(Dense(3, activation='softmax')) # 编译模型 opt = SGD(lr=0.01, momentum=0.9) model.compile(loss='categorical_crossentropy', optimizer=opt, metrics=['accuracy']) # 拟合模型 history = model.fit(trainX, trainy, validation_data=(testX, testy), epochs=200, verbose=0, batch_size=32) # 评估模型 _, 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)) # 绘制训练历史 pyplot.plot(history.history['accuracy'], label='train') pyplot.plot(history.history['val_accuracy'], label='test') pyplot.legend() pyplot.show() |
注意:您每次得到的结果可能不同,这取决于算法或评估程序的随机性,或者数值精度的差异。请考虑多次运行示例并比较平均结果。
运行该示例报告了训练集和测试集上相似的性能,与批量梯度下降和随机梯度下降(在降低学习率后)相当。
1 |
训练:0.832,测试:0.812 |
折线图显示了随机梯度下降和批量梯度下降的动态。具体来说,模型学习速度快且更新嘈杂,但在运行结束时也趋于稳定,比随机梯度下降更稳定。
保持学习率不变并改变批量大小,可以让你获得两种方法的最佳效果。

小型批量梯度下降拟合 MLP 在训练集和测试集上的分类准确率折线图
批量大小对模型行为的影响
我们可以使用不同的批量大小重新拟合模型,并查看批量大小的变化对学习速度、学习过程中的稳定性以及最终结果的影响。
首先,我们可以清理代码并创建一个函数来准备数据集。
1 2 3 4 5 6 7 8 9 10 11 |
# 准备训练和测试数据集 def prepare_data(): # 生成 2d 分类数据集 X, y = make_blobs(n_samples=1000, centers=3, n_features=2, cluster_std=2, random_state=2) # 对输出变量进行独热编码 y = to_categorical(y) # 分割为训练集和测试集 n_train = 500 trainX, testX = X[:n_train, :], X[n_train:, :] trainy, testy = y[:n_train], y[n_train:] return trainX, trainy, testX, testy |
接下来,我们可以创建一个函数,用于在问题上拟合模型,并给定批量大小,然后绘制训练集和测试集分类准确率的学习曲线。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
# 拟合模型并绘制学习曲线 def fit_model(trainX, trainy, testX, testy, n_batch): # 定义模型 model = Sequential() model.add(Dense(50, input_dim=2, activation='relu', kernel_initializer='he_uniform')) model.add(Dense(3, activation='softmax')) # 编译模型 opt = SGD(lr=0.01, momentum=0.9) model.compile(loss='categorical_crossentropy', optimizer=opt, metrics=['accuracy']) # 拟合模型 history = model.fit(trainX, trainy, validation_data=(testX, testy), epochs=200, verbose=0, batch_size=n_batch) # 绘制学习曲线 pyplot.plot(history.history['accuracy'], label='train') pyplot.plot(history.history['val_accuracy'], label='test') pyplot.title('batch='+str(n_batch), pad=-40) |
最后,我们可以通过一系列不同的批次大小来评估模型的行为,同时保持模型的所有其他方面不变,包括学习率。
1 2 3 4 5 6 7 8 9 10 11 12 |
# 准备数据集 trainX, trainy, testX, testy = prepare_data() # 为不同批次大小创建学习曲线 batch_sizes = [4, 8, 16, 32, 64, 128, 256, 450] for i in range(len(batch_sizes)): # 确定绘图编号 plot_no = 420 + (i+1) pyplot.subplot(plot_no) # 拟合模型并绘制批次大小的学习曲线 fit_model(trainX, trainy, testX, testy, batch_sizes[i]) # 显示学习曲线 pyplot.show() |
结果将是一个包含八个图的图形,显示了使用不同批次大小的模型行为。
将这些结合起来,完整的示例列在下面。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 |
# 使用不同批次大小的小批量梯度下降进行 blob 问题 MLP 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 # 准备训练和测试数据集 def prepare_data(): # 生成 2d 分类数据集 X, y = make_blobs(n_samples=1000, centers=3, n_features=2, cluster_std=2, random_state=2) # 对输出变量进行独热编码 y = to_categorical(y) # 分割为训练集和测试集 n_train = 500 trainX, testX = X[:n_train, :], X[n_train:, :] trainy, testy = y[:n_train], y[n_train:] return trainX, trainy, testX, testy # 拟合模型并绘制学习曲线 def fit_model(trainX, trainy, testX, testy, n_batch): # 定义模型 model = Sequential() model.add(Dense(50, input_dim=2, activation='relu', kernel_initializer='he_uniform')) model.add(Dense(3, activation='softmax')) # 编译模型 opt = SGD(lr=0.01, momentum=0.9) model.compile(loss='categorical_crossentropy', optimizer=opt, metrics=['accuracy']) # 拟合模型 history = model.fit(trainX, trainy, validation_data=(testX, testy), epochs=200, verbose=0, batch_size=n_batch) # 绘制学习曲线 pyplot.plot(history.history['accuracy'], label='train') pyplot.plot(history.history['val_accuracy'], label='test') pyplot.title('batch='+str(n_batch), pad=-40) # 准备数据集 trainX, trainy, testX, testy = prepare_data() # 为不同批次大小创建学习曲线 batch_sizes = [4, 8, 16, 32, 64, 128, 256, 450] for i in range(len(batch_sizes)): # 确定绘图编号 plot_no = 420 + (i+1) pyplot.subplot(plot_no) # 拟合模型并绘制批次大小的学习曲线 fit_model(trainX, trainy, testX, testy, batch_sizes[i]) # 显示学习曲线 pyplot.show() |
运行示例将创建一个包含八个折线图的图形,显示了在mini-batch梯度下降中使用不同批次大小的模型在训练集和测试集上的分类准确率。
注意:您每次得到的结果可能不同,这取决于算法或评估程序的随机性,或者数值精度的差异。请考虑多次运行示例并比较平均结果。
图表显示,小批次通常会导致快速学习,但学习过程不稳定,分类准确率方差较大。较大的批次会减慢学习过程,但最终阶段会收敛到一个更稳定的模型,这通过分类准确率方差的降低来体现。

不同批次大小的训练集和测试集分类准确率折线图
进一步阅读
如果您想深入了解,本节提供了更多关于该主题的资源。
文章
论文
- 重新审视深度神经网络的小批量训练, 2018.
- 深度架构基于梯度的训练的实用建议, 2012.
书籍
- 8.1.3 批次和最小批次算法,《深度学习》,2016。
文章
总结
在本教程中,您学习了三种不同的梯度下降方法,以及如何探索和诊断批次大小对学习过程的影响。
具体来说,你学到了:
- 批量大小控制训练神经网络时误差梯度估计的准确性。
- 批量、随机和小型批量梯度下降是学习算法的三种主要方法。
- 批量大小与学习过程的速度和稳定性之间存在一种权衡。
你有什么问题吗?
在下面的评论中提出你的问题,我会尽力回答。
我一直感谢您的信息。
我从您的博客中学到了很多。
我有一个关于状态无关 LSTM 网络的问题,batch_size 为 1 和固定的滑动窗口。
这个 LSTM 模型优于其他经典方法,例如多项式和 MLP 模型。
在这种情况下,这个 LSTM 模型与普通的 MLP 几乎相同,因为每个批次后单元状态都会重置。
我没有利用到 LSTM 模型的任何优势。当然,每个 LSTM 层有更多的参数。但这不足以解释结果。
你能给一些直观的建议吗?
在这种情况下使用 LSTM 值吗?
有趣。我期望 MLP 的表现会优于这样的 LSTM。
也许可以试试这种方法
https://machinelearning.org.cn/how-to-develop-a-skilful-time-series-forecasting-model/
非常感谢,这是您有史以来最好的文章之一。我参加了 Andrew Ng 的全部 5 门课程,仍然没有理解这一点,所以做得很好。只花了 15 分钟就明白了 :)
谢谢 Todd!
我也是
很好的文章。我有一个关于最后一幅图的问题。我注意到这些图的 Y 轴刻度不同。这是否意味着 batch-4 和 batch-16 已经收敛到更好的整体准确率?
很好的评论!理想情况下,这些图应该具有相同的 y 轴。
在这种情况下,我不认为 y 轴会不同,只有打印标签的选择。
很好的文章。我学到了很多东西!!
谢谢,很高兴对您有帮助。
嗨,Jason,
感谢您的文章,
我有一个问题,
类别数量 (y) 与 batch_size 有关系吗?
假设我们有 150 个类别需要分类,如果我们初始化 batch_size=32,
在一个批次中,我们的过程将无法训练所有类型的类,因此学习会非常慢?
如果我错了,请纠正我
很好的问题!
我们希望批次包含各种各样的示例。如果您有 150 个类别,那么较大的批次大小可能更重复数据集。
试试看。
嗨,Jason,
正如您建议的,如果我们有更多的类别(如上面的情况 150 个),则训练批次大小更大。但大多数时候我遇到 GPU 内存挑战,如何以其他方式解决这个问题?
也许这里的一些建议
https://machinelearning.org.cn/improve-deep-learning-performance/
尊敬的 Brownlee 博士,
非常感谢您提供有用的信息。
我从您的博客中学到了很多东西。
致以亲切的问候,
Abolfazl Nejatian
谢谢,很高兴这些教程对您有帮助。
嗨,感谢您这篇非常清晰的文章,配有非常好的例子。
我有一个问题。
关于最后一幅图中的八个图,设想一个动态的批次大小是否会很有趣?
我的意思是,我们可以从小批次大小(例如 4)开始学习过程,以实现快速但粗略的收敛,然后我们可以增加批次大小(例如 256)以实现稳定性?
这是否会比批次梯度下降更快,比随机梯度下降更稳定?
此致
Romain Schuster, 博士
不客气!
你可以,试试看!
我们通常为了效率而固定批次大小——这样我们就可以快速计算准备好张量(在 TensorFlow 中)。
嗨 Schuster,
有一篇文章支持这个假设,您可能会感兴趣:https://openreview.net/pdf?id=B1Yy1BxCZ
祝好,
AG
感谢分享!
plot_no 中的 420 是什么意思?
抱歉,我没听懂你的问题。
请详细说明一下?
嗨,
根据您的帖子以及我偶然发现的其他相关帖子,我遇到了这个存储库,对归一化权重初始化的用途有疑问,您能帮忙吗?
https://github.com/PranaySPatil/ComputerVision-CSCI5561/tree/master/HW4
如果您对存储库有疑问,也许可以直接联系作者。
保持学习率恒定,增加/减少
批次大小对神经网络训练有什么影响?
可能会导致学习速度更快或更慢——但考虑到梯度估计的质量,也存在一个限度。
嗨,我有一个疑问。我有一些稀疏矩阵,我想训练一个稀疏 MLP。如果 Keras 输入层中的 sparse=True,后面跟着一个密集层,它会抛出错误。但相同的代码可以在 Colab 中工作,但在 Kaggle 内核中我遇到了这个问题。有什么想法吗?
暂时没有,抱歉,您需要调试您的代码来找出答案,或者尝试将代码和错误发布到 Stack Overflow。
谢谢!我一定会这样做的。您的帖子非常有帮助。非常感谢。
不客气。
嗨,Jason,
非常感谢您提供如此丰富的信息。
我有一个问题,可能是一个基本问题,所以提前道歉。
在模型准确率图(第一张图)中,测试集的准确率高于训练集。对此的解释是什么?我曾以为测试准确率总是会稍差一些,因为测试数据对模型来说是新的。
祝好,
Stani
不客气!
这可以帮助您解释学习曲线
https://machinelearning.org.cn/learning-curves-for-diagnosing-machine-learning-model-performance/
嗨 Jason,感谢您的教程。我有一个问题,
model.fit_generator() 怎么样?我们如何更改其中的 batch_size?
“steps_per_epoch”控制训练数据集一个 epoch 中的批次数。
非常感谢 Jason,这个页面很有用。嗯,我是 ML 界的新手,我的问题可能很傻,但我真的对此感到困惑。您提到使用小批次,学习会很快,反之亦然。但是,我实现了代码,并注意到使用小的 mini batch 数量比使用大的数量花费的时间更长。您能向我解释一下为什么会这样吗?我是否误解了这里的想法?
非常感谢您的时间
不客气。
是的,更小的批次意味着更多的计算和更多的模型权重更新,这更慢。
更大的批次完成的工作更少,执行速度更快。
你好,Jason。
谢谢,您的主题很有见地。
我有一个问题
如果它陷入局部最小值(例如,主要是因为第一次随机权重初始化)怎么办?当我们重新运行时,有时它会朝着全局最小值方向前进。但有时并非如此……有时它会朝着局部最小值方向前进。由于 NN 使用梯度作为前进方向(陷入局部最小值,梯度只是来回摆动)
我曾遇到过这种情况,即使调整批次数量也无济于事,因为不知何故
“开始时的权重在随机初始化期间”似乎真的决定了“第一个方向”
我听说过模拟退火可以尝试从局部最小值“跳出”到其他地方,但我不太确定 Keras 中是否存在这种方法。
有什么提示吗?
谢谢
Mike
一种方法是训练许多模型并平均它们的预测。
另一种方法是训练许多模型,并在保留的验证集上选择表现最好的模型。
嗨 Jason,又一篇很棒的文章。
现在,我第一次尝试 Keras 的调优器中的 BayesianOptimization() 函数进行超参数调优。
在这种情况下,我该如何纳入批次大小的优化?
您有什么好的例子吗?
嗨 Michio……感谢您的反馈!以下资源提供了关于出色的贝叶斯优化调优器的精彩介绍和示例。
https://github.com/bayesian-optimization/BayesianOptimization