使用image_dataset_from_directory生成的验证集仅含单一类别问题排查求助
这个问题我之前也碰到过,根源在于数据集的存储顺序和TensorFlow拆分验证集的逻辑配合出了问题,我来给你拆解一下并解决它:
问题到底出在哪?
微软的猫狗数据集默认是按类别分文件夹存储的——train/cat/下全是猫的图片,train/dog/下全是狗的图片。而tf.keras.preprocessing.image_dataset_from_directory在shuffle=False时,会严格按照文件夹的顺序遍历所有图片:先把猫的图片全部加载完,再加载狗的图片。
当你设置validation_split(比如0.2)且训练集shuffle=False时,TensorFlow会直接按原始顺序拆分:前80%的样本(全是猫+部分狗)作为训练集,剩下的20%全是狗,自然就导致验证集只有单一类别。
而当训练集设置shuffle=True时,TensorFlow会先基于你指定的SEED把整个数据集打乱,再拆分训练和验证集,这时候验证集就会包含两类样本了。
怎么解决?
核心思路是:让数据集在拆分前先被全局打乱,同时保证训练集和验证集基于同一个随机种子拆分,验证集本身可以不用打乱(不影响评估结果)。修改你的load_from_directory函数如下:
def load_from_directory(path, shuffle_train=True): train_ds = tfk.preprocessing.image_dataset_from_directory( directory=path, image_size=IMAGE_SIZE, validation_split=VALIDATION_SPLIT, batch_size=BATCH_SIZE, seed=SEED, subset='training', label_mode='binary', shuffle=shuffle_train ) val_ds = tfk.preprocessing.image_dataset_from_directory( directory=path, image_size=IMAGE_SIZE, validation_split=VALIDATION_SPLIT, batch_size=BATCH_SIZE, seed=SEED, # 必须和训练集用同一个seed! subset='validation', label_mode='binary', shuffle=False # 验证集不需要打乱,不影响类别分布 ) return train_ds, val_ds # 调用时开启训练集的打乱,确保拆分前数据被全局洗牌 train_ds, val_ds = load_from_directory(path=TRAINING_PATH, shuffle_train=True)
为什么这样改就有效?
当训练集和验证集使用相同的SEED,且训练集shuffle=True时,TensorFlow会先基于这个种子对整个数据集做一次全局打乱,再按照validation_split的比例拆分出训练和验证子集。哪怕验证集设置shuffle=False,它只是在迭代时保持顺序不变,但子集本身已经是从打乱后的全量数据中拆分出来的,类别自然是均衡的。
额外的验证小技巧
如果你想确认数据集的原始顺序问题,可以跑这段代码看看前几批样本的标签:
# 查看原始顺序下的标签分布 temp_ds = tfk.preprocessing.image_dataset_from_directory( directory=TRAINING_PATH, image_size=IMAGE_SIZE, batch_size=BATCH_SIZE, label_mode='binary', shuffle=False ) for x, y in temp_ds.take(5): print(y.numpy())
你会看到前几批的标签全是同一类,这就坐实了数据集是按类别连续存储的问题。
内容的提问来源于stack exchange,提问作者user12205212

