Tensorflow 2.0:当输出是连续的时如何计算指标?

Tensorflow 2.0: How are metrics computed when the ouput is sequential?

我一直在使用 Tensorflow 2.0 处理二进制顺序输入和输出,我一直想知道 Tensorflow 使用哪种方法来计算这些场景中训练期间的召回率或准确率等指标。

我网络的每个样本都包含 60 个时间步长,每个时间步长有 300 个特征,因此我的预期输出是一个 (60, 1) 1 和 0 的数组。假设我有 2000 个验证样本。在评估每个时期的验证集时,tensorflow 是将 2000 个样本的 所有 连接成一个 (2000*60=120000, 1) 数组,然后与连接的真实标签进行比较,还是评估每个(60, 1) 单独,然后 returns 这些值的平均值?有什么方法可以修改此行为吗?

默认情况下,

Tensorflow/Keras 为训练数据分批计算指标,同时它对 fit 方法中 validation_data 参数中传递的所有数据计算相同的指标。

这意味着在拟合训练数据期间打印的指标是在所有批次上计算的分数的平均值。换句话说,对于训练集,keras 单独评估每个 bach,然后 returns 这些值的平均值。对于验证数据不同,keras获取所有验证样本,然后将它们与"concatenated" groundtruth标签进行比较。

为了用代码证明这种行为,我提出了一个虚拟示例。我提供了一个自定义回调,用于计算在纪元结束时传递的所有数据的准确度分数(用于训练和可选验证)。这对我们理解训练过程中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')

正如我们所看到的,默认方法和我们的回调在训练数据(第一个图)上的准确性是不同的。这意味着火车数据的准确性是分批计算的。 我们的回调和默认方法计算的验证准确度(第二个图)是一样的!这意味着验证数据的分数是一次性计算的