我一直在尝试更好地理解keras
模型fit()
循环中的训练/验证序列。因此,我尝试了一个简单的训练循环,试图拟合一个简单的逻辑回归模型,输入数据仅包含一个特征。
我为训练和验证都提供了相同的数据。在这些条件下,并且通过指定批次大小与总数据大小相同,人们期望得到完全相同的损失和准确率。但事实并非如此。
这是我的代码:
生成一些两类随机数据:
N = 100x = np.concatenate([np.random.randn(N//2, 1), np.random.randn(N//2, 1)+2])y = np.concatenate([np.zeros(N//2), np.ones(N//2)])
并绘制两个类的数据分布(一个特征x):
data = pd.DataFrame({'x': x.ravel(), 'y': y})sns.violinplot(x='x', y='y', inner='point', data=data, orient='h')pyplot.tight_layout(0)pyplot.show()
构建并拟合keras模型:
model = tf.keras.Sequential([tf.keras.layers.Dense(1, activation='sigmoid', input_dim=1)])model.compile(optimizer=tf.keras.optimizers.SGD(2), loss='binary_crossentropy', metrics=['accuracy'])model.fit(x, y, epochs=10, validation_data=(x, y), batch_size=N)
请注意,我为训练和validation_data
都指定了数据x
和目标y
。此外,批次大小与总大小相同batch_size=N
。
训练结果如下:
100/100 [==============================] - 1s 5ms/step - loss: 1.4500 - acc: 0.2300 - val_loss: 0.5439 - val_acc: 0.7200Epoch 2/10100/100 [==============================] - 0s 18us/step - loss: 0.5439 - acc: 0.7200 - val_loss: 0.4408 - val_acc: 0.8000Epoch 3/10100/100 [==============================] - 0s 16us/step - loss: 0.4408 - acc: 0.8000 - val_loss: 0.3922 - val_acc: 0.8300Epoch 4/10100/100 [==============================] - 0s 16us/step - loss: 0.3922 - acc: 0.8300 - val_loss: 0.3659 - val_acc: 0.8400Epoch 5/10100/100 [==============================] - 0s 17us/step - loss: 0.3659 - acc: 0.8400 - val_loss: 0.3483 - val_acc: 0.8500Epoch 6/10100/100 [==============================] - 0s 16us/step - loss: 0.3483 - acc: 0.8500 - val_loss: 0.3356 - val_acc: 0.8600Epoch 7/10100/100 [==============================] - 0s 17us/step - loss: 0.3356 - acc: 0.8600 - val_loss: 0.3260 - val_acc: 0.8600Epoch 8/10100/100 [==============================] - 0s 18us/step - loss: 0.3260 - acc: 0.8600 - val_loss: 0.3186 - val_acc: 0.8600Epoch 9/10100/100 [==============================] - 0s 18us/step - loss: 0.3186 - acc: 0.8600 - val_loss: 0.3127 - val_acc: 0.8700Epoch 10/10100/100 [==============================] - 0s 23us/step - loss: 0.3127 - acc: 0.8700 - val_loss: 0.3079 - val_acc: 0.8800
结果显示,每个epoch结束时的val_loss和loss不同,acc和val_acc也不完全相同。然而,基于这种设置,人们期望它们是相同的。
我一直在查看keras的代码,特别是这部分:https://github.com/tensorflow/tensorflow/blob/master/tensorflow/python/keras/engine/training.py#L1364
到目前为止,我只能说差异是由于计算图中的某些不同计算引起的。
有没有人知道为什么会有这样的差异?
回答:
因此,在更仔细地查看结果后,训练步骤中的loss
和acc
值是在当前批次用于更新模型之前计算的。
因此,在每个epoch只有一个批次的情况下,训练的acc
和loss
是在批次输入时评估的,然后根据提供的优化器更新模型参数。在训练步骤完成后,我们通过输入验证数据来计算损失和准确率,这些数据现在使用的是更新后的新模型来评估。
从训练结果输出中可以明显看出,第1个epoch的验证准确率和损失等于第2个epoch的训练准确率和损失,等等…
使用tensorflow进行的快速检查确认了在变量更新之前获取了值:
输出:
MSE: 14.721437454223633, W: 0.0, b: 0.0MSE: 13.372591018676758, W: 0.08826743811368942, b: 0.1636980175971985
由于参数W
和b
被初始化为0,因此很明显,即使会话已经运行了梯度更新请求,获取的值仍然是0…