为何flow_from_directory与image_dataset_from_directory验证结果差异巨大?
你遇到的两种数据加载方式的差异,核心原因在于数据预处理不匹配和tf.data与旧API的行为差异,具体分析和解决办法如下:
1. 核心问题:数据归一化缺失
你的ImageDataGenerator显式做了rescale=1./255,将图片像素值缩放到[0,1]区间,但image_dataset_from_directory加载的数据是原始的0-255像素值——而预训练MobileNet的权重是基于归一化后的图片训练的,输入数据范围不匹配会导致模型输出完全异常,比如所有样本被预测为同一类别。
解决办法:给image_dataset_from_directory的数据集添加归一化
有两种常用方式:
- 方式一:在数据集加载后通过
map处理
# 如果你用[0,1]归一化 train_ds = train_ds.map(lambda x, y: (x / 255.0, y)) validation_ds = validation_ds.map(lambda x, y: (x / 255.0, y)) # 或者用MobileNet官方的预处理(缩放到[-1,1],更贴合预训练权重) from tensorflow.keras.applications.mobilenet import preprocess_input train_ds = train_ds.map(lambda x, y: (preprocess_input(x), y)) validation_ds = validation_ds.map(lambda x, y: (preprocess_input(x), y))
- 方式二:将归一化层加入模型
from tensorflow.keras.layers import Rescaling model = tf.keras.Sequential([ Rescaling(1./255, input_shape=(128, 128, 3)), # 或者用对应预训练模型的预处理逻辑 MobileNet(...) # 你的MobileNet模型结构 ])
2. 其他可能的影响因素
(1)类不平衡问题
如果训练集本身存在严重的类不平衡(比如某类样本占比超过90%),模型会倾向于预测占比高的类别。可以通过以下代码统计各类样本数量:
import os train_dir = '/home/kun/knee/train/' for cls in os.listdir(train_dir): print(f"{cls}: {len(os.listdir(os.path.join(train_dir, cls)))}")
若存在不平衡,可在训练时设置class_weight参数,或对数据集做过采样/欠采样处理。
(2)数据集打乱设置
image_dataset_from_directory默认shuffle=True,和ImageDataGenerator的flow_from_directory默认行为一致,但验证集不需要打乱,可给validation_ds加上shuffle=False,和之前的test_generator保持一致,避免评估时的不必要干扰。
(3)训练参数一致性
确保两种加载方式下,模型的训练参数(学习率、损失函数、优化器、epochs数等)完全一致,否则无法准确对比差异。比如ImageDataGenerator训练时用的是categorical_crossentropy,image_dataset_from_directory训练时也要保持相同的损失函数。
3. 关于速度差异
image_dataset_from_directory基于tf.data.Dataset构建,相比旧的ImageDataGenerator(基于生成器),它支持更高效的多线程数据预处理、预取和缓存,所以epoch耗时更短是正常的,这也是它的核心优势之一。
内容的提问来源于stack exchange,提问作者Wayne Dan

