默认情况下,Tensorflow/Keras 会为训练数据分批计算指标,同时它会在 fit 方法中的 validation_data 参数中传递的所有数据上计算相同的指标。
这意味着在拟合训练数据期间打印的指标是对所有批次计算的分数的平均值。换句话说,对于 trainset,keras 会单独评估每个 bach,然后返回这些值的平均值。由于验证数据不同,keras 获取所有验证样本,然后将它们与“连接的”groundtruth 标签进行比较。
为了用代码证明这种行为,我提出了一个虚拟示例。我提供了一个自定义回调,它可以确定在 epoch 结束时传递的所有数据的准确度得分(用于训练和可选的验证)。这对于我们了解训练期间 tensorflow 的行为很有用。
import numpy as np
from sklearn.metrics import accuracy_score
import tensorflow as tf
from tensorflow.keras.layers import *
from tensorflow.keras.models import *
from tensorflow.keras.callbacks import *
class ACC_custom(tf.keras.callbacks.Callback):
def __init__(self, train, validation=None):
super(ACC_custom, self).__init__()
self.validation = validation
self.train = train
def on_epoch_end(self, epoch, logs={}):
logs['ACC_score_train'] = float('-inf')
X_train, y_train = self.train[0], self.train[1]
y_pred = (self.model.predict(X_train).ravel()>0.5)+0
score = accuracy_score(y_train.ravel(), y_pred)
if (self.validation):
logs['ACC_score_val'] = float('-inf')
X_valid, y_valid = self.validation[0], self.validation[1]
y_val_pred = (self.model.predict(X_valid).ravel()>0.5)+0
val_score = accuracy_score(y_valid.ravel(), y_val_pred)
logs['ACC_score_train'] = np.round(score, 5)
logs['ACC_score_val'] = np.round(val_score, 5)
else:
logs['ACC_score_train'] = np.round(score, 5)
创建虚拟数据
x_train = np.random.uniform(0,1, (1000,60,10))
y_train = np.random.randint(0,2, (1000,60,1))
x_val = np.random.uniform(0,1, (500,60,10))
y_val = np.random.randint(0,2, (500,60,1))
拟合模型
inp = Input(shape=((60,10)), dtype='float32')
x = Dense(32, activation='relu')(inp)
out = Dense(1, activation='sigmoid')(x)
model = Model(inp, out)
es = EarlyStopping(patience=10, verbose=1, min_delta=0.001,
monitor='ACC_score_val', mode='max', restore_best_weights=True)
model.compile(loss='binary_crossentropy', optimizer='adam', metrics=['accuracy'])
history = model.fit(x_train,y_train, epochs=10, verbose=2,
callbacks=[ACC_custom(train=(x_train,y_train),validation=(x_val,y_val)),es],
validation_data=(x_val,y_val))
在下图中,我比较了我们的回调计算的准确度和 keras 计算的准确度
plt.plot(history.history['ACC_score_train'], label='accuracy_callback_train')
plt.plot(history.history['accuracy'], label='accuracy_default_train')
plt.legend(); plt.title('train accuracy')
plt.plot(history.history['ACC_score_val'], label='accuracy_callback_valid')
plt.plot(history.history['val_accuracy'], label='accuracy_default_valid')
plt.legend(); plt.title('validation accuracy')
我们可以看到训练数据(第一个图)的准确性在默认方法和我们的回调之间是不同的。这意味着训练数据的准确性是分批计算的。
我们的回调计算的验证准确率(第二个图)和默认方法是一样的!这意味着验证数据的分数是一次性计算的