我试图绘制使用批量梯度下降、随机梯度下降和小批量随机梯度下降时的不同学习结果。
我到处查阅,发现批量大小(batch_size)等于1时与普通的SGD相同,而批量大小等于训练数据长度(len(train_data))时与批量梯度下降相同。
我知道随机梯度下降是每次更新时仅使用一个数据样本,而批量梯度下降使用整个训练数据集来计算目标函数的梯度/更新。
然而,在使用Keras实现批量大小(batch_size)时,似乎发生了相反的情况。以我的代码为例,我将批量大小设置为训练数据的长度
input_size = len(train_dataset.keys())output_size = 10hidden_layer_size = 250n_epochs = 250weights_initializer = keras.initializers.GlorotUniform()#一个训练和验证模型并返回均方误差的函数def train_val_model(run_dir, hparams): model = keras.models.Sequential([ #用作网络入口点的层 keras.layers.InputLayer(input_shape=[len(train_dataset.keys())]), #密集层1 keras.layers.Dense(hidden_layer_size, activation='relu', kernel_initializer = weights_initializer, name='Layer_1'), #密集层2 keras.layers.Dense(hidden_layer_size, activation='relu', kernel_initializer = weights_initializer, name='Layer_2'), #激活函数为线性,因为我们正在进行回归 keras.layers.Dense(output_size, activation='linear', name='Output_layer') ]) #使用随机梯度下降优化器,但更改批量大小以获取BSG、SGD或MiniSGD optimizer = tf.keras.optimizers.SGD(learning_rate=0.001, momentum=0.0, nesterov=False) #编译模型 model.compile(optimizer=optimizer, loss='mean_squared_error', #计算标签和预测之间的误差平方的均值 metrics=['mean_squared_error']) #计算y_true和y_pred之间的均方误差 #初始化时间停止回调 time_stopping_callback = tfa.callbacks.TimeStopping(seconds=5*60, verbose=1) #训练网络 history = model.fit(normed_train_data, train_labels, epochs=n_epochs, batch_size=hparams['batch_size'], verbose=1, #validation_split=0.2, callbacks=[tf.keras.callbacks.TensorBoard(run_dir + "/Keras"), time_stopping_callback]) return historytrain_val_model("logs/sample", {'batch_size': len(normed_train_data)})
运行这个代码时,输出似乎显示每个epoch只有一个更新,即SGD:
可以看到每个epoch下面显示1/1,我认为这意味着单次更新迭代。另一方面,如果我将批量大小设置为1,我得到90000/90000,这是我整个数据集的大小(从训练时间上看这也是合理的)。
所以,我的疑问是,批量大小等于1实际上是批量梯度下降而不是随机梯度下降,而批量大小等于训练数据长度实际上是随机梯度下降而不是批量梯度下降?
回答:
实际上有三种情况:
batch_size = 1
确实意味着随机梯度下降(SGD)- 批量大小等于整个训练数据时是(批量)梯度下降(GD)
- 中间情况(实际上在实践中使用)通常被称为小批量梯度下降
有关更多详细信息和参考资料,请参见对小批量梯度下降和如何配置批量大小的温和介绍。事实上,在实践中,当我们说”SGD”时,我们通常是指”小批量SGD”。
这些定义实际上与您从实验中报告的内容完全一致:
-
对于
batch_size=len(train_data)
(GD情况),每个epoch确实期望有一个更新(因为只有一个批次),因此Keras输出中的1/1
指示是正确的。 -
相反,对于
batch_size = 1
(SGD情况),您期望有与训练数据中的样本一样多的更新(因为这是批次的数量),即90000,因此Keras输出中的90000/90000
指示是正确的。
即每个epoch的更新次数(Keras指示的)等于使用的批次数量(而不是批量大小)。