使用Conv2D构建6分类图像识别模型遇形状不兼容错误求助
问题:Conv2D图像分类模型报错形状不兼容
我尝试用Conv2D构建6类图像识别模型,多次测试都出现错误:
ValueError: Shapes (None, None) and (None, 296, 296, 6) are incompatible
我的代码实现如下:
from sklearn.preprocessing import normalize im_shape = (300, 300) val_data_generator = ImageDataGenerator(preprocessing_function=normalize,validation_split=0.2) train_generator = data_generator.flow_from_directory(TRAINING_DIR, target_size=im_shape, shuffle=True, class_mode='categorical', batch_size=BATCH_SIZE, subset="training") validation_generator = val_data_generator.flow_from_directory(TRAINING_DIR, target_size=im_shape, shuffle=False, class_mode='categorical', batch_size=BATCH_SIZE, subset="validation") test_generator = ImageDataGenerator(preprocessing_function=normalize) test_generator = test_generator.flow_from_directory(TEST_DIR, target_size=im_shape, shuffle=False, class_mode='categorical', batch_size=BATCH_SIZE) nb_train_samples = train_generator.samples nb_validation_samples = validation_generator.samples nb_test_samples = test_generator.samples num_classes = 6 model = models.Sequential() model.add(layers.Conv2D(32, (3, 3),activation="elu", kernel_initializer="glorot_uniform", input_shape=(300, 300, 3))) model.add(layers.Dropout(0.2)) model.add(layers.BatchNormalization()) model.add(layers.Conv2D(64, (3, 3), activation="elu", kernel_initializer="glorot_uniform")) model.add(layers.Dropout(0.2)) model.add(layers.BatchNormalization()) model.add(layers.Dense(100, activation="elu", kernel_initializer="he_normal")) model.add(layers.Dropout(0.2)) model.add(layers.BatchNormalization()) model.add(layers.Dense(100, activation="elu", kernel_initializer="he_normal")) model.add(layers.Dropout(0.2)) model.add(layers.BatchNormalization()) model.add(layers.Dense(6, activation="softmax", kernel_initializer="glorot_uniform")) model.compile(optimizer=Adam(), loss='categorical_crossentropy',metrics=['accuracy']) history = model.fit( train_generator, steps_per_epoch=nb_train_samples // BATCH_SIZE, epochs=150, callbacks = [keras.callbacks.EarlyStopping(monitor='val_loss', patience=30,verbose=1)], validation_data=validation_generator, verbose = 1, validation_steps=nb_validation_samples // BATCH_SIZE)
错误原因分析
核心问题是Conv2D层输出的4D特征图直接连接Dense层,未做展平处理:
- Conv2D层输出的是
(批量大小, 高, 宽, 通道数)的4D张量,比如第一个Conv2D后输出(None, 296, 296, 32),第二个Conv2D后是(None, 294, 294, 64)(3x3卷积无填充时,尺寸会减2)。 - Dense层默认接收
(批量大小, 特征数)的2D张量,两者维度不匹配,导致形状冲突报错。
此外还有几个次要问题:
train_generator使用了未定义的data_generator变量;- 用
sklearn.preprocessing.normalize做图像预处理不合适,该函数默认按样本归一化,会破坏图像空间结构; - 缺少池化层,特征图尺寸过大,计算量极高且容易过拟合;
- 未导入
Adam优化器和keras相关模块。
修复方案及完整代码
关键修复点:
- 在Conv2D层和第一个Dense层之间添加
Flatten()层,将4D特征图展平为2D向量; - 每个Conv2D层后添加
MaxPooling2D()层,缩小特征图尺寸,降低计算量; - 替换图像预处理方式,改用
rescale=1./255做归一化; - 补全所有缺失的导入,修正未定义变量问题。
修改后的完整代码:
from tensorflow.keras.models import Sequential from tensorflow.keras.layers import Conv2D, Dropout, BatchNormalization, Dense, Flatten, MaxPooling2D from tensorflow.keras.optimizers import Adam from tensorflow.keras.preprocessing.image import ImageDataGenerator from tensorflow.keras.callbacks import EarlyStopping # 定义参数 im_shape = (300, 300) BATCH_SIZE = 32 # 根据硬件配置调整 TRAINING_DIR = "你的训练集路径" TEST_DIR = "你的测试集路径" # 数据生成器 data_generator = ImageDataGenerator(rescale=1./255, validation_split=0.2) train_generator = data_generator.flow_from_directory( TRAINING_DIR, target_size=im_shape, shuffle=True, class_mode='categorical', batch_size=BATCH_SIZE, subset="training" ) validation_generator = data_generator.flow_from_directory( TRAINING_DIR, target_size=im_shape, shuffle=False, class_mode='categorical', batch_size=BATCH_SIZE, subset="validation" ) test_generator = ImageDataGenerator(rescale=1./255) test_generator = test_generator.flow_from_directory( TEST_DIR, target_size=im_shape, shuffle=False, class_mode='categorical', batch_size=BATCH_SIZE ) nb_train_samples = train_generator.samples nb_validation_samples = validation_generator.samples nb_test_samples = test_generator.samples num_classes = 6 # 构建模型 model = Sequential() model.add(Conv2D(32, (3, 3), activation="elu", kernel_initializer="glorot_uniform", input_shape=(300, 300, 3))) model.add(MaxPooling2D(pool_size=(2, 2))) # 添加池化层 model.add(Dropout(0.2)) model.add(BatchNormalization()) model.add(Conv2D(64, (3, 3), activation="elu", kernel_initializer="glorot_uniform")) model.add(MaxPooling2D(pool_size=(2, 2))) # 添加池化层 model.add(Dropout(0.2)) model.add(BatchNormalization()) model.add(Flatten()) # 关键:展平4D特征图为2D向量 model.add(Dense(100, activation="elu", kernel_initializer="he_normal")) model.add(Dropout(0.2)) model.add(BatchNormalization()) model.add(Dense(100, activation="elu", kernel_initializer="he_normal")) model.add(Dropout(0.2)) model.add(BatchNormalization()) model.add(Dense(num_classes, activation="softmax", kernel_initializer="glorot_uniform")) # 编译模型 model.compile(optimizer=Adam(learning_rate=0.001), loss='categorical_crossentropy', metrics=['accuracy']) # 训练模型 history = model.fit( train_generator, steps_per_epoch=nb_train_samples // BATCH_SIZE, epochs=150, callbacks=[EarlyStopping(monitor='val_loss', patience=30, verbose=1)], validation_data=validation_generator, verbose=1, validation_steps=nb_validation_samples // BATCH_SIZE )
内容的提问来源于stack exchange,提问作者I'mStuckOnLine911
相关产品推荐
相关产品推荐

