猫狗分类CNN模型输入层尺寸不兼容错误排查求助
问题:CNN猫狗图片分类时的输入形状不兼容错误
我正在编写简单CNN模型对本地train目录中的猫狗图片分类,当前代码如下:
import numpy as np import cv2 as cv import tensorflow.keras as keras import os from sklearn.preprocessing import LabelEncoder from tensorflow.keras.utils import to_categorical from tensorflow.keras import layers , models from sklearn.model_selection import train_test_split images_vector =[] images_label =[] fileNames = os.listdir('train') for i , f_name in enumerate(fileNames) : image = cv.imread('train/' + f_name) image = cv.resize(image , (50,50)) image = image/255.0 image = image.flatten() # 这里把图片展平成一维了 images_vector.append(image) images_label.append(f_name.split('.')[0]) if i%10000 == 0 : print(f" [INFO ] : {i} images are processed...") labelEncoder = LabelEncoder() images_label = labelEncoder.fit_transform(images_label) images_label = to_categorical(images_label) # 补全原代码的语法错误 X_train , X_test , y_train , y_test = train_test_split(images_vector ,images_label , random_state=40 , train_size=0.8) print('X_train: ' + str(np.array(X_train).shape)) print('Y_train: ' + str(y_train.shape)) print('X_test: ' + str(np.array(X_test).shape)) print('Y_test: ' + str(y_test.shape))
运行以下模型构建代码后:
net = models.Sequential([ layers.Conv2D(32 , (3,3) , activation='relu' , input_shape = (1,7500)) , layers.MaxPooling2D(2,2), layers.Conv2D(64 , (3,3) , activation='relu'), layers.Flatten(), layers.Dense(2 , activation='softmax') ]) net.summary()
出现错误:
ValueError: Input 0 of layer "conv2d_96" is incompatible with the layer: expected min_ndim=4, found ndim=3. Full shape received: (None, 1, 7500)
解决方案
错误核心是你把图片展平成了一维数组,而CNN需要保留图片的空间维度(高度、宽度、通道数),同时输入形状定义不符合Conv2D层要求。具体修正步骤如下:
1. 保留图片空间维度,取消展平
CNN的Conv2D层需要处理4D张量(批量大小, 高度, 宽度, 通道数),因此读取图片后不要用flatten(),保留(50,50,3)的形状(cv.imread读取的是3通道彩色图):
image = cv.imread('train/' + f_name) # 跳过损坏图片 if image is None: print(f"跳过损坏图片: {f_name}") continue image = cv.resize(image , (50,50)) image = image/255.0 # 仅做归一化,不展平 images_vector.append(image)
2. 将列表转换为numpy数组
原代码中images_vector是Python列表,无shape属性,需转为numpy数组才能被Keras正确识别:
images_vector = np.array(images_vector)
3. 修正模型输入形状
Conv2D的input_shape需对应单张图片的维度:(高度, 宽度, 通道数),即(50,50,3),批量维度由Keras自动添加:
net = models.Sequential([ layers.Conv2D(32 , (3,3) , activation='relu' , input_shape = (50,50,3)) , layers.MaxPooling2D(2,2), layers.Conv2D(64 , (3,3) , activation='relu'), layers.MaxPooling2D(2,2), # 添加池化层压缩特征图尺寸 layers.Flatten(), layers.Dense(128, activation='relu'), # 新增全连接层提升模型能力 layers.Dense(2 , activation='softmax') ])
4. 修正数据划分后的形状打印
X_train和X_test需转为numpy数组才能正确打印形状:
X_train = np.array(X_train) X_test = np.array(X_test) print('X_train: ' + str(X_train.shape)) # 输出应为 (样本数,50,50,3) print('Y_train: ' + str(y_train.shape)) print('X_test: ' + str(X_test.shape)) print('Y_test: ' + str(y_test.shape))
修改后的完整代码
import numpy as np import cv2 as cv import tensorflow.keras as keras import os from sklearn.preprocessing import LabelEncoder from tensorflow.keras.utils import to_categorical from tensorflow.keras import layers , models from sklearn.model_selection import train_test_split images_vector =[] images_label =[] fileNames = os.listdir('train') for i , f_name in enumerate(fileNames) : image = cv.imread('train/' + f_name) if image is None: print(f"跳过损坏图片: {f_name}") continue image = cv.resize(image , (50,50)) image = image/255.0 images_vector.append(image) images_label.append(f_name.split('.')[0]) if i%10000 == 0 : print(f" [INFO ] : {i} images are processed...") images_vector = np.array(images_vector) labelEncoder = LabelEncoder() images_label = labelEncoder.fit_transform(images_label) images_label = to_categorical(images_label) X_train , X_test , y_train , y_test = train_test_split(images_vector ,images_label , random_state=40 , train_size=0.8) print('X_train: ' + str(X_train.shape)) print('Y_train: ' + str(y_train.shape)) print('X_test: ' + str(X_test.shape)) print('Y_test: ' + str(y_test.shape)) net = models.Sequential([ layers.Conv2D(32 , (3,3) , activation='relu' , input_shape = (50,50,3)) , layers.MaxPooling2D(2,2), layers.Conv2D(64 , (3,3) , activation='relu'), layers.MaxPooling2D(2,2), layers.Flatten(), layers.Dense(128, activation='relu'), layers.Dense(2 , activation='softmax') ]) net.summary()
修改后输入数据形状为(样本数,50,50,3),符合Conv2D层要求的4D张量,模型可正常构建。
内容的提问来源于stack exchange,提问作者Ahmad Badpey
相关产品推荐
相关产品推荐

