基于双视图与批量数据集,用Keras构建CNN分类模型报错解决
双视图CNN图像分类模型维度错误修复
问题概述
使用Keras构建双视图图像分类CNN时,训练阶段出现维度不兼容错误:
ValueError: Input 0 of layer is incompatible with the layer: expected shape=(None, 80, 80, 3), found shape=(32, 32, 80, 80, 3)
核心问题是数据加载和训练循环中出现了重复批次打包,导致多了一个不必要的维度。
错误原因
- 重复批次化:
image_dataset_from_directory已经通过batch_size=32参数生成了批次数据,后续调用combined_dataset.batch(batch_size)会再次对批次进行打包,导致维度变成(32, 32, 80, 80, 3)(第一个32是新批次大小,内部每个元素是原32张图像的批次)。 - 数据集解构错误:
tf.data.Dataset.zip((data_train_1, data_train_2))后的数据集元素结构是((view1_imgs, view1_labels), (view2_imgs, view2_labels)),原代码的循环解构(view1_batch, view2_batch), labels无法正确提取数据。 - 未定义变量:
class_names未从数据集中获取,直接调用len(class_names)会报错。 - 损失函数不匹配:对比损失(contrastive loss)用于孪生网络的相似性判断任务,而当前是分类任务,应该使用分类专用损失函数。
修复步骤
- 移除
combined_dataset.batch(batch_size)调用,直接使用原始批次化数据集。 - 修正训练循环的数据集解构逻辑,正确提取两个视图的图像和统一标签(确保双视图对应同一样本的标签一致)。
- 从数据集中获取
class_names变量。 - 替换损失函数为适合分类任务的
SparseCategoricalCrossentropy(因标签为整数类型),输出层激活改为softmax(多分类场景)。
完整修正代码
import keras import tensorflow as tf import keras.layers as layers from keras.models import Sequential # 图像尺寸 img_width, img_height = 80, 80 batch_size = 32 # 加载视图1数据集 data_train_1 = tf.keras.preprocessing.image_dataset_from_directory( '_view_1', labels='inferred', label_mode='int', color_mode='rgb', batch_size=batch_size, image_size=(img_width, img_height), shuffle=True, seed=123, validation_split=0.2, subset="training" ) data_validation_1 = tf.keras.preprocessing.image_dataset_from_directory( '_view_1', labels='inferred', label_mode='int', color_mode='rgb', batch_size=batch_size, image_size=(img_width, img_height), shuffle=True, seed=123, validation_split=0.2, subset="validation" ) # 加载视图2数据集 data_train_2 = tf.keras.preprocessing.image_dataset_from_directory( '_view_2', labels='inferred', label_mode='int', color_mode='rgb', batch_size=batch_size, image_size=(img_width, img_height), shuffle=True, seed=123, validation_split=0.2, subset="training" ) data_validation_2 = tf.keras.preprocessing.image_dataset_from_directory( '_view_2', labels='inferred', label_mode='int', color_mode='rgb', batch_size=batch_size, image_size=(img_width, img_height), shuffle=True, seed=123, validation_split=0.2, subset="validation" ) # 获取分类数量(从任意一个数据集提取) class_names = data_train_1.class_names num_classes = len(class_names) # 定义共享CNN特征提取器 shared_cnn = keras.Sequential([ layers.Rescaling(1./255), layers.Conv2D(16, 3, activation='relu'), layers.MaxPooling2D(), layers.Conv2D(32, 3, activation='relu'), layers.MaxPooling2D(), layers.Conv2D(64, 3, activation='relu'), layers.MaxPooling2D(), layers.Flatten(), layers.Dense(128, activation='relu'), ]) # 定义双视图输入 view1_input = keras.Input(shape=(img_height, img_width, 3)) view2_input = keras.Input(shape=(img_height, img_width, 3)) # 提取双视图特征 view1_features = shared_cnn(view1_input) view2_features = shared_cnn(view2_input) # 融合特征 merged_features = layers.concatenate([view1_features, view2_features], axis=1) # 分类输出层(多分类用softmax) predictions = layers.Dense(num_classes, activation='softmax')(merged_features) # 创建模型 model = keras.Model(inputs=[view1_input, view2_input], outputs=predictions) # 编译模型:分类任务用稀疏交叉熵损失 model.compile( optimizer=keras.optimizers.Adam(), loss=keras.losses.SparseCategoricalCrossentropy(), metrics=['accuracy'] ) # 合并双视图训练数据集(确保样本对应) train_dataset = tf.data.Dataset.zip((data_train_1, data_train_2)).map( lambda x, y: ((x[0], y[0]), x[1]) # 提取两个视图的图像,取第一个视图的标签(双视图标签一致) ) val_dataset = tf.data.Dataset.zip((data_validation_1, data_validation_2)).map( lambda x, y: ((x[0], y[0]), x[1]) ) # 训练模型(直接用fit更简洁,无需手动梯度带) epochs = 10 model.fit( train_dataset, validation_data=val_dataset, epochs=epochs )
额外说明
- 如果确实需要使用对比损失(比如双视图相似性匹配任务),需调整标签为二元相似/不相似标签,并将输出层改为单神经元
sigmoid激活。 - 使用
model.fit()代替手动梯度带循环,代码更简洁且自动处理批次、验证等逻辑。
内容的提问来源于stack exchange,提问作者Yassine
相关产品推荐
相关产品推荐

