You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何训练最后一轮val_accuracy与fit后eval acc结果不一致?

训练验证准确率与后续评估准确率不一致的问题
Epoch 19/20
1/1 [==============================] - 0s 473ms/step - loss: 1.4018 - accuracy: 0.8750 - val_loss: 1.8656 - val_accuracy: 0.8900
Epoch 20/20
1/1 [==============================] - 0s 444ms/step - loss: 0.5904 - accuracy: 0.8750 - val_loss: 2.1255 - val_accuracy: 0.8700
get_dataset: validation
Found 1000 files belonging to 2 classes.
Using 100 files for validation.
4/4 [==============================] - 1s 81ms/step
eval acc: 0.81

问题

为何训练最后一轮的val_accuracy(0.87)与fit完成后的eval acc(0.81)结果不一致?我尝试让fit过程中每一轮的验证以及后续额外验证使用同一数据集。

更新记录

2022-07-19 更新1

  • 显然两次准确率计算并未实际使用相同数据,如何调试实际使用的数据?
    • 2022-07-20 更新3:已追踪数据到TensorFlow内部,确认Model.evaluate(fit过程中)和Model.predict中的x.filenames是相同的,但后续在quick_execute中的__inference_test_function_248219和__inference_predict_function_231438在Python外执行,参数为dtype=resource的张量,无法查看内容。
  • 为简化示例特意移除了类别平衡代码,知晓这会降低准确率实用性,但目前暂不关注此点。
  • get_dataset('validation')仅在fit开始时调用一次,并非每一轮都调用。
  • 已设置max_queue_size=0, use_multiprocessing=False, workers=0,但准确率仍不一致。

2022-07-19 更新2

使用已弃用的ImageDataGenerator也能复现该现象,相关代码如下:

from tensorflow.keras.applications.resnet50 import preprocess_input
from keras_preprocessing.image import ImageDataGenerator

datagen = ImageDataGenerator(
    preprocessing_function=preprocess_input,
    validation_split=0.1,
)

def get_dataset(subset):
    print('get_dataset:', subset)
    return datagen.flow_from_directory(
        'data-nodup-1000',
        class_mode='binary',
        target_size=(224, 224),
        shuffle=True,
        seed=1,
        subset=subset,
    )

同时将真实标签的获取代码改为:

true_class = val_dataset.labels

2022-07-21 更新4

将验证数据的shuffle设置为shuffle=(subset == 'training')可使两个验证准确率一致,但这并非可行方案——因为flow_from_directory不做分层,此时验证集仅包含类别1。

核心代码

import tensorflow as tf
from sklearn.metrics import accuracy_score
from tensorflow.keras.models import Model
from tensorflow.keras.layers import Dense, Flatten
from tensorflow.keras.preprocessing import image_dataset_from_directory
    
inputs = tf.keras.Input(shape=(224, 224, 3))
base_model = tf.keras.applications.ResNet50(weights='imagenet', include_top=False)
base_output = base_model(inputs)
base_model.trainable = False
out = Flatten(name='flat')(base_output)
out = Dense(1, activation='sigmoid')(out)
model = Model(inputs=inputs, outputs=out)
model.compile(optimizer='adam', loss='binary_crossentropy', metrics=['accuracy'])

def get_dataset(subset):
    print('get_dataset:', subset)
    return image_dataset_from_directory(
        'data-nodup-1000',
        labels="inferred",
        label_mode='binary',
        color_mode="rgb",
        image_size=(224, 224),
        shuffle=True,
        seed=1,
        validation_split=0.1,
        subset=subset,
        crop_to_aspect_ratio=False,
    )

model.fit(
    get_dataset('training'),
    steps_per_epoch=1,
    epochs=20,
    validation_data=get_dataset('validation'),
    max_queue_size=0,
    use_multiprocessing=False,
    workers=0,
)

val_dataset = get_dataset('validation')
true_class = tf.concat([y for x, y in val_dataset], axis=0)
pred = model.predict(val_dataset)
pred_class = pred >= .5
print('eval acc:', accuracy_score(true_class, pred_class))

环境说明

  • 使用最新版本库,如tensorflow 2.9.1和sklearn 1.1.1(通过pip-compile -U安装)。
  • 文件夹data-nodup-1000包含两个子文件夹:一个有113个类别0文件,另一个有887个类别1文件。

内容的提问来源于stack exchange,提问作者Robert Pollak

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.26 02:36:20