我一直在尝试更好地了解keras
模型fit()
循环中的训练/验证序列。因此,我尝试了一个简单的训练循环,在该循环中,我尝试使用包含单个功能的输入数据来拟合简单的逻辑回归模型。
我为培训和验证输入了相同数据。在这种情况下,通过指定批大小是相同的和总数据大小,可以期望获得完全相同的损失和准确性。但这种情况并非如此。
这是我的代码:
生成具有两个类的一些随机数据:
N = 100
x = 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)
请注意,我已经为训练和x
指定了数据y
和目标validation_data
。另外,batch_size与总大小batch_size=N
相同。
培训结果为:
100/100 [==============================] - 1s 5ms/step - loss: 1.4500 - acc: 0.2300 - val_loss: 0.5439 - val_acc: 0.7200
Epoch 2/10
100/100 [==============================] - 0s 18us/step - loss: 0.5439 - acc: 0.7200 - val_loss: 0.4408 - val_acc: 0.8000
Epoch 3/10
100/100 [==============================] - 0s 16us/step - loss: 0.4408 - acc: 0.8000 - val_loss: 0.3922 - val_acc: 0.8300
Epoch 4/10
100/100 [==============================] - 0s 16us/step - loss: 0.3922 - acc: 0.8300 - val_loss: 0.3659 - val_acc: 0.8400
Epoch 5/10
100/100 [==============================] - 0s 17us/step - loss: 0.3659 - acc: 0.8400 - val_loss: 0.3483 - val_acc: 0.8500
Epoch 6/10
100/100 [==============================] - 0s 16us/step - loss: 0.3483 - acc: 0.8500 - val_loss: 0.3356 - val_acc: 0.8600
Epoch 7/10
100/100 [==============================] - 0s 17us/step - loss: 0.3356 - acc: 0.8600 - val_loss: 0.3260 - val_acc: 0.8600
Epoch 8/10
100/100 [==============================] - 0s 18us/step - loss: 0.3260 - acc: 0.8600 - val_loss: 0.3186 - val_acc: 0.8600
Epoch 9/10
100/100 [==============================] - 0s 18us/step - loss: 0.3186 - acc: 0.8600 - val_loss: 0.3127 - val_acc: 0.8700
Epoch 10/10
100/100 [==============================] - 0s 23us/step - loss: 0.3127 - acc: 0.8700 - val_loss: 0.3079 - val_acc: 0.8800
结果表明,每个时期结束时 val_loss 和 loss 都不相同, acc 和 val_acc也不同不完全相同。但是,基于此设置,可以期望它们是相同的。
我一直在研究keras中的代码,特别是这部分: https://github.com/tensorflow/tensorflow/blob/master/tensorflow/python/keras/engine/training.py#L1364
到目前为止,我只能说差异是由于通过计算图进行了一些不同的计算而引起的。
有人知道为什么会有这种区别吗?
答案 0 :(得分:1)
因此,在仔细观察结果之后,将在使用当前批次更新模型之前计算出训练步骤中的loss
和acc
值。
因此,在每个时期只有一个批次的情况下,在输入批次时会评估列车acc
和loss
,然后根据提供的优化程序更新模型参数。训练步骤完成后,我们通过输入验证数据来计算损失和准确性,该数据现在使用新的更新模型进行评估。
从训练结果输出中可以明显看出,第1阶段的验证准确性和损失等于第2阶段的训练准确性和损失,等等...
使用tensorflow进行的快速检查确认了在更新变量之前已获取值:
import tensorflow as tf
import numpy as np
np.random.seed(1)
x = tf.placeholder(dtype=tf.float32, shape=(None, 1), name="x")
y = tf.placeholder(dtype=tf.float32, shape=(None), name="y")
W = tf.get_variable(name="W", shape=(1, 1), dtype=tf.float32, initializer=tf.constant_initializer(0))
b = tf.get_variable(name="b", shape=1, dtype=tf.float32, initializer=tf.constant_initializer(0))
z = tf.matmul(x, W) + b
error = tf.square(z - y)
obj = tf.reduce_mean(error, name="obj")
opt = tf.train.MomentumOptimizer(learning_rate=0.025, momentum=0.9)
grads = opt.compute_gradients(obj)
train_step = opt.apply_gradients(grads)
N = 100
x_np = np.random.randn(N).reshape(-1, 1)
y_np = 2*x_np + 3 + np.random.randn(N)
with tf.Session() as sess:
sess.run(tf.global_variables_initializer())
for i in range(2):
res = sess.run([obj, W, b, train_step], feed_dict={x: x_np, y: y_np})
print('MSE: {}, W: {}, b: {}'.format(res[0], res[1][0, 0], res[2][0]))
输出:
MSE: 14.721437454223633, W: 0.0, b: 0.0
MSE: 13.372591018676758, W: 0.08826743811368942, b: 0.1636980175971985
由于将参数W
和b
初始化为0,所以很明显,即使使用渐变更新请求运行会话,获取的值仍为0 ...