使用ImageDataGenerator训练ResNet50时遇NoneType无items属性错误
问题解决:ResNet50迁移训练报错AttributeError: 'NoneType' object has no attribute 'items'
问题场景
用迁移学习训练ResNet50模型,数据集包含40000张图片,使用ImageDataGenerator预处理数据,通过flow_from_directory按validation_split=0.2划分训练/验证集,采用Adam优化器。训练时触发错误:AttributeError: 'NoneType' object has no attribute 'items',尝试过设置shuffle=True、使用repeat函数、手动过滤数据、切换rmsprop优化器,均无法解决。
错误根源
核心问题是**model变量从未定义**:你导入了ResNet50模块,但没有构建迁移学习模型的具体结构,直接调用model.compile(),此时model为None,调用其方法必然触发该错误。此外还有几个次要问题:
num_epochs未定义,训练阶段会触发未定义变量错误print (train_data.shape) and (validation_data.shape)语法错误,无法正确打印数据集信息- 混用
keras和tensorflow.keras的API,可能引发兼容性问题
解决方案
- 构建ResNet50迁移学习模型:加载预训练的ResNet50(去掉顶层分类层),添加自定义的全连接分类头
- 修复语法与变量问题:修正print语句格式,定义训练轮数
num_epochs - 统一API规范:全部使用
tensorflow.keras的模块,避免混用不同版本的Keras
修正后的完整代码
# Import Library import numpy as np import pandas as pd import matplotlib.pyplot as plt from glob import glob import tensorflow as tf from tensorflow.keras.preprocessing.image import ImageDataGenerator, img_to_array, load_img from tensorflow.keras.models import save_model, Sequential, Model from tensorflow.keras.layers import Dense, Flatten import os import cv2 from tensorflow.keras.applications import ResNet50 from tensorflow.keras.applications.imagenet_utils import preprocess_input from tensorflow.keras.optimizers import Adam from tensorflow.keras.losses import categorical_crossentropy from tensorflow.keras.callbacks import EarlyStopping # Define the path to the dataset and batch size path = r"C:\Users\Rajarshi\Downloads\Compressed\Concrete Crack Images for Classification" batch_size = 32 num_epochs = 10 # 定义训练轮数 # Step 1: Set up data generators image_generator = ImageDataGenerator(horizontal_flip=True, rescale=1./255, zoom_range=0.2, validation_split=0.2) try: train_data = image_generator.flow_from_directory(batch_size=batch_size, directory=path, shuffle=True, target_size=(224, 224), subset="training", class_mode="categorical") validation_data = image_generator.flow_from_directory(batch_size=batch_size, directory=path, shuffle=True, target_size=(224, 224), subset="validation", class_mode="categorical") except OSError as e: print(f"生成数据时出错: {e}") print("请检查数据目录路径和结构是否正确。") # 修正print语句,打印数据集信息 print(f"训练集样本数: {train_data.samples}, 批次大小: {train_data.batch_size}") print(f"验证集样本数: {validation_data.samples}, 批次大小: {validation_data.batch_size}") # Step 2: 构建ResNet50迁移学习模型 # 加载预训练的ResNet50,不含顶层分类层 base_model = ResNet50(weights='imagenet', include_top=False, input_shape=(224, 224, 3)) # 冻结预训练层(可选,若想微调可部分解冻) for layer in base_model.layers: layer.trainable = False # 添加自定义分类头 x = base_model.output x = Flatten()(x) x = Dense(256, activation='relu')(x) predictions = Dense(train_data.num_classes, activation='softmax')(x) # 定义完整模型 model = Model(inputs=base_model.input, outputs=predictions) # model compile model.compile(loss='categorical_crossentropy', optimizer=Adam(learning_rate=1e-4), # 建议设置学习率,避免破坏预训练权重 metrics=['accuracy']) # Training Model model.fit( train_data, steps_per_epoch=train_data.samples // train_data.batch_size, epochs=num_epochs, validation_data=validation_data, validation_steps=validation_data.samples // validation_data.batch_size )
额外说明
- 如果需要微调预训练层,可以在模型构建后解冻部分顶层的预训练层,再重新编译(注意调低学习率)
- 需确保数据集目录结构符合
flow_from_directory要求:每个类别对应一个独立子文件夹,结构示例如下:Concrete Crack Images for Classification/ 类别1/ 图片1.jpg 图片2.jpg ... 类别2/ 图片1.jpg 图片2.jpg ...
内容的提问来源于stack exchange,提问作者Ray
相关产品推荐
相关产品推荐

