Colab调用flow_from_directory报listdir传参为BatchDataset错误求解
报错核心原因
代码混用了两套互不兼容的Keras数据加载API,同时存在多处参数配置错误:
ImageDataGenerator.flow_from_directory()的第一个入参必须是字符串格式的数据集本地路径,你传入的train_ds、val_ds是tf.keras.utils.image_dataset_from_directory()返回的BatchDataset类型的数据集对象,不是路径,底层调用os.listdir()读取路径时直接触发类型错误。- 两套数据加载逻辑不能拼接使用:要么全程用
image_dataset_from_directory加载数据集,要么全程用ImageDataGenerator+flow_from_directory传入路径生成迭代器,不能把前者生成的数据集对象传给后者的接口。 - 代码还存在其他会导致运行失败的逻辑错误:
- 重复定义
img_width、img_height,先赋值150又被覆盖为32,分辨率设置混乱 - 模型输出层配置和损失、分类模式不匹配:最后一层用1个神经元+sigmoid激活是二分类配置,却搭配了多分类用的
categorical_crossentropy损失和categorical分类模式 model.fit()传入了未定义的变量nb_train_samples、nb_validation_samples、epochs,且验证集参数名错误写成了val_ds,正确参数名是validation_data
- 重复定义
可直接运行的修正代码
以下方案统一用更简洁、不易出错的image_dataset_from_directoryAPI,不需要手动统计样本数,修正了所有配置冲突,直接替换原代码即可:
from tensorflow.keras.models import Sequential from tensorflow.keras.layers import Activation, Dropout, Flatten, Dense, Conv2D, MaxPooling2D, Rescaling from tensorflow.keras.losses import sparse_categorical_crossentropy from tensorflow.keras.optimizers import Adam import matplotlib.pyplot as plt import tensorflow as tf import os # -------------------------- 可根据实际需求调整的配置项 -------------------------- batch_size = 32 # 32*32分辨率过低容易丢失图像特征,统一用150*150 img_width, img_height, img_num_channels = 150, 150, 3 no_epochs = 30 # 自动读取数据集下的分类文件夹数量,不需要手动硬编码 data_path = '/content/drive/MyDrive/Colab Notebooks/Training_Data' no_classes = len([x for x in os.listdir(data_path) if os.path.isdir(os.path.join(data_path,x))]) # ----------------------------------------------------------------------------- # 拆分训练、验证集 train_ds = tf.keras.utils.image_dataset_from_directory( data_path, validation_split=0.2, subset="training", seed=123, image_size=(img_height, img_width), batch_size=batch_size) val_ds = tf.keras.utils.image_dataset_from_directory( data_path, validation_split=0.2, subset="validation", seed=123, image_size=(img_height, img_width), batch_size=batch_size) # 在线数据增强 data_augmentation = Sequential([ tf.keras.layers.RandomFlip('horizontal'), tf.keras.layers.RandomRotation(0.2), tf.keras.layers.RandomZoom(0.2), ]) # 像素值归一化到0-1区间 rescale = Rescaling(1./255) # 优化数据集加载速度 AUTOTUNE = tf.data.AUTOTUNE train_ds = train_ds.map(lambda x,y: (rescale(data_augmentation(x, training=True)), y)).cache().shuffle(1000).prefetch(buffer_size=AUTOTUNE) val_ds = val_ds.map(lambda x,y: (rescale(x), y)).cache().prefetch(buffer_size=AUTOTUNE) # 搭建CNN模型 input_shape = (img_width, img_height, img_num_channels) model = Sequential() model.add(Conv2D(32, (3, 3), input_shape=input_shape)) model.add(Activation('relu')) model.add(MaxPooling2D(pool_size=(2, 2))) model.add(Conv2D(32, (3, 3))) model.add(Activation('relu')) model.add(MaxPooling2D(pool_size=(2, 2))) model.add(Conv2D(64, (3, 3))) model.add(Activation('relu')) model.add(MaxPooling2D(pool_size=(2, 2))) model.add(Flatten()) model.add(Dense(64)) model.add(Activation('relu')) model.add(Dropout(0.5)) # 输出层匹配分类数,多分类用softmax激活 model.add(Dense(no_classes)) model.add(Activation('softmax')) # 编译模型,损失函数匹配整数格式标签(不需要手动转独热编码) model.compile(loss=sparse_categorical_crossentropy, optimizer=Adam(learning_rate=1e-4), metrics=['accuracy']) # 启动训练 history = model.fit( train_ds, validation_data=val_ds, epochs=no_epochs ) # 绘制训练/验证的准确率、损失曲线 acc = history.history['accuracy'] val_acc = history.history['val_accuracy'] loss = history.history['loss'] val_loss = history.history['val_loss'] epochs_range = range(no_epochs) plt.figure(figsize=(12,4)) plt.subplot(1,2,1) plt.plot(epochs_range, acc, label='Training Accuracy') plt.plot(epochs_range, val_acc, label='Validation Accuracy') plt.legend(loc='lower right') plt.title('Training and Validation Accuracy') plt.subplot(1,2,2) plt.plot(epochs_range, loss, label='Training Loss') plt.plot(epochs_range, val_loss, label='Validation Loss') plt.legend(loc='upper right') plt.title('Training and Validation Loss') plt.show()
注意事项
- 如果你的数据集是二分类(只有2个分类文件夹),把模型最后输出部分改成
model.add(Dense(1))、model.add(Activation('sigmoid')),损失函数替换为tf.keras.losses.BinaryCrossentropy()即可。 - 训练前确认数据集目录结构符合要求:
Training_Data文件夹下直接存放以分类名命名的子文件夹,每个子文件夹内存放对应类别的图片,不要嵌套多余层级。 - 如果训练时触发显存不足报错,把
batch_size调小到16或者8即可。 - 初始学习率设为1e-4比Adam默认的1e-3更稳定,不容易出现训练不收敛、验证集精度震荡的问题。
- 如果你更习惯用
ImageDataGenerator的写法,需要删掉所有image_dataset_from_directory相关代码,直接把数据集路径字符串作为第一个参数传给flow_from_directory(),同时手动统计训练、验证集样本数给对应变量赋值,配置复杂度更高,优先使用上面给出的修正方案。
内容的提问来源于stack exchange,提问作者อิม อัฐวงศ์
相关产品推荐
相关产品推荐

