使用tf.keras.utils.image_dataset_from_directory自定义CSV标签报错求助
问题分析与解决方案
错误根源
你遇到的问题核心在于tf.keras.utils.image_dataset_from_directory的labels参数与validation_split配合时的底层逻辑冲突:
- 当传入自定义标签(非
'inferred'/None)时,要求标签长度必须与目录内图片数量严格匹配,且格式需为numpy数组或普通列表(而非Tensor)。 - 使用
validation_split时,函数会自动划分数据集,但如果传入的是Tensor类型的标签,内部切片转换时会触发类型不兼容错误。
此外,直接传入整数列表作为标签报错,大概率是因为顺序与函数默认的文件名排序不匹配,或者未转为numpy数组导致处理异常。
推荐解决方案:手动构建tf.data.Dataset
由于你的图片未按类别拆分,用tf.data.Dataset手动构建数据集更灵活可控,完全避免image_dataset_from_directory的限制。
步骤1:准备图片路径与标签
首先确保图片路径顺序与你的label_int完全对应:
import os import numpy as np import tensorflow as tf # 配置参数 train_dir = "你的训练图片目录路径" batch_size = 32 img_height = 224 img_width = 224 cat_count = 120 # 获取所有图片路径(按文件名排序,与label_int顺序对齐) image_paths = sorted([ os.path.join(train_dir, fname) for fname in os.listdir(train_dir) if fname.endswith(('.jpg', '.jpeg', '.png')) ]) # 验证路径数量与标签数量匹配 assert len(image_paths) == len(label_int), "图片数量与标签数量不匹配!"
步骤2:定义图片加载预处理函数
def load_and_preprocess_image(path): # 读取图片 img = tf.io.read_file(path) # 解码为RGB格式 img = tf.image.decode_jpeg(img, channels=3) # 调整尺寸 img = tf.image.resize(img, (img_height, img_width)) # 可选:根据模型需求添加预处理(比如归一化) img = tf.keras.applications.resnet50.preprocess_input(img) return img
情况1:标签编码(用于SparseCategoricalCrossentropy)
# 构建图片数据集 img_ds = tf.data.Dataset.from_tensor_slices(image_paths)\ .map(load_and_preprocess_image, num_parallel_calls=tf.data.AUTOTUNE) # 构建整数标签数据集 label_ds = tf.data.Dataset.from_tensor_slices(np.array(label_int)) # 合并图片与标签 full_ds = tf.data.Dataset.zip((img_ds, label_ds)) # 划分训练/验证集 val_size = int(0.2 * len(image_paths)) train_ds = full_ds.skip(val_size)\ .shuffle(buffer_size=1000)\ .batch(batch_size)\ .prefetch(tf.data.AUTOTUNE) val_ds = full_ds.take(val_size)\ .batch(batch_size)\ .prefetch(tf.data.AUTOTUNE)
情况2:独热编码(用于CategoricalCrossentropy)
# 生成独热编码的numpy数组 oh_labels = tf.one_hot(np.array(label_int), cat_count).numpy() # 构建独热标签数据集 label_ds = tf.data.Dataset.from_tensor_slices(oh_labels) # 合并图片与标签 full_ds = tf.data.Dataset.zip((img_ds, label_ds)) # 划分训练/验证集(同标签编码逻辑) val_size = int(0.2 * len(image_paths)) train_ds = full_ds.skip(val_size)\ .shuffle(buffer_size=1000)\ .batch(batch_size)\ .prefetch(tf.data.AUTOTUNE) val_ds = full_ds.take(val_size)\ .batch(batch_size)\ .prefetch(tf.data.AUTOTUNE)
关于labels=None的补充说明
如果设置labels=None,数据集只会返回图片张量,此时你可以在model.fit()中手动传入标签,但必须严格保证:
- 训练数据的batch顺序与标签数组的顺序完全一致
- 标签数组的长度与训练数据的样本数完全匹配
这种方式容易出现对齐错误,不推荐使用。
内容的提问来源于stack exchange,提问作者John G.
相关产品推荐
相关产品推荐

