Python CNN模型出现ValueError及负维度尺寸问题求助
CNN模型训练时出现ValueError负维度错误
错误详情
File "C:\Users\Ayeh\AppData\Local\Programs\Python\Python310\lib\site-packages\keras\utils\traceback_utils.py", line 70, in error_handler raise e.with_traceback(filtered_tb) from None File "C:\Users\Ayeh\AppData\Local\Programs\Python\Python310\lib\site-packages\tensorflow\python\framework\ops.py", line 1969, in _create_c_op raise ValueError(e.message) ValueError: Exception encountered when calling layer "conv2d_2" (type Conv2D).在执行
{{node conv2d_2/Conv2D}} = Conv2D[T=DT_FLOAT, data_format="NHWC", dilations=[1, 1, 1, 1], explicit_paddings=[], padding="VALID", strides=[1, 3, 3, 1], use_cudnn_on_gpu=true](Placeholder, conv2d_2/Conv2D/ReadVariableOp)时,因从1中减去3导致负维度尺寸,输入形状为:[?,1,1,32], [3,3,32,64]。
conv2d_2层(Conv2D类型)接收的调用参数:inputs=tf.Tensor(shape=(None, 1, 1, 32), dtype=float32)
模型代码
# Part 1 - Building the CNN #importing the Keras libraries and packages from keras.models import Sequential from keras.layers import Convolution2D from keras.layers import MaxPooling2D from keras.layers import Flatten from keras.layers import Dense, Dropout from keras import optimizers # Initialing the CNN classifier = Sequential() # Step 1 - Convolutio Layer classifier.add(Convolution2D(32, 3, 3, input_shape = (64, 64, 3), activation = 'relu')) #step 2 - Pooling classifier.add(MaxPooling2D(pool_size =(2,2))) # Adding second convolution layer classifier.add(Convolution2D(32, 3, 3, activation = 'relu')) classifier.add(MaxPooling2D(pool_size =(2,2))) #Adding 3rd Concolution Layer classifier.add(Convolution2D(64, 3, 3, activation = 'relu')) classifier.add(MaxPooling2D(pool_size =(2,2))) #Step 3 - Flattening classifier.add(Flatten()) #Step 4 - Full Connection classifier.add(Dense(256, activation = 'relu')) classifier.add(Dropout(0.5)) classifier.add(Dense(26, activation = 'softmax')) #Compiling The CNN classifier.compile( optimizer = optimizers.SGD(lr = 0.01), loss = 'categorical_crossentropy', metrics = ['accuracy']) #Part 2 Fittting the CNN to the image from keras.preprocessing.image import ImageDataGenerator train_datagen = ImageDataGenerator( rescale=1./255, shear_range=0.2, zoom_range=0.2, horizontal_flip=True) test_datagen = ImageDataGenerator(rescale=1./255) training_set = train_datagen.flow_from_directory( 'mydata/training_set', target_size=(64, 64), batch_size=32, class_mode='categorical') test_set = test_datagen.flow_from_directory( 'mydata/test_set', target_size=(64, 64), batch_size=32, class_mode='categorical') model = classifier.fit_generator( training_set, steps_per_epoch=800, epochs=25, validation_data = test_set, validation_steps = 6500) '''#Saving the model import h5py classifier.save('Trained_model.h5')''' print(model.history.keys()) import matplotlib.pyplot as plt # summarize history for accuracy plt.plot(model.history['acc']) plt.plot(model.history['val_acc']) plt.title('model accuracy') plt.ylabel('accuracy') plt.xlabel('epoch') plt.legend(['train', 'test'], loc='upper left') plt.show() # summarize history for loss plt.plot(model.history['loss']) plt.plot(model.history['val_loss']) plt.title('model loss') plt.ylabel('loss') plt.xlabel('epoch') plt.legend(['train', 'test'], loc='upper left') plt.show()
问题原因与解决方法
核心原因
错误本质是第三层卷积层的输入特征图尺寸仅为1x1,无法适配3x3的卷积核(默认padding='valid'时,要求输入尺寸≥卷积核尺寸,否则会计算出负维度)。
可能的触发因素:
- 连续池化操作过度压缩特征图尺寸(理论上64x64输入经两次卷积池化后仍有14x14特征图,但实际运行中可能因数据生成器异常、图像未正确resize或框架版本兼容问题导致尺寸异常)
- 卷积层步长被意外设置为3(错误信息显示strides=[1,3,3,1],与代码默认步长1不符,可能是框架版本的参数解析问题)
修复方案
方案1:给卷积层添加padding
在所有卷积层中设置padding='same',让框架自动填充边缘,保证卷积后特征图尺寸与输入一致,避免负维度问题:
# 修改后的卷积层代码 classifier.add(Convolution2D(32, 3, 3, input_shape=(64, 64, 3), activation='relu', padding='same')) classifier.add(MaxPooling2D(pool_size=(2,2))) classifier.add(Convolution2D(32, 3, 3, activation='relu', padding='same')) classifier.add(MaxPooling2D(pool_size=(2,2))) classifier.add(Convolution2D(64, 3, 3, activation='relu', padding='same')) classifier.add(MaxPooling2D(pool_size=(2,2)))
方案2:调整模型结构,减少池化/卷积层数
如果不需要三层卷积,可去掉第三组卷积和池化,避免特征图被过度压缩:
# 注释掉第三层卷积和池化 # classifier.add(Convolution2D(64, 3, 3, activation = 'relu')) # classifier.add(MaxPooling2D(pool_size =(2,2)))
方案3:增大输入图像尺寸
将target_size从(64,64)改为更大的尺寸(如(128,128)),让特征图经过多次池化后仍保留足够尺寸:
training_set = train_datagen.flow_from_directory( 'mydata/training_set', target_size=(128, 128), # 增大输入尺寸 batch_size=32, class_mode='categorical') test_set = test_datagen.flow_from_directory( 'mydata/test_set', target_size=(128, 128), # 同步修改测试集尺寸 batch_size=32, class_mode='categorical')
方案4:更新代码适配新版本框架
代码中使用了部分已弃用的API,替换为现代版本可避免版本兼容问题:
- 将
Convolution2D替换为Conv2D(功能一致,后者是更现代的命名) - 将
fit_generator替换为fit(fit_generator在TensorFlow 2.1+已被弃用) - 将
optimizers.SGD(lr=0.01)改为optimizers.SGD(learning_rate=0.01)(lr参数已被弃用)
修改后的示例代码片段:
from keras.layers import Conv2D # 替换Convolution2D # ... classifier.add(Conv2D(32, (3, 3), input_shape=(64, 64, 3), activation='relu', padding='same')) # ... classifier.compile( optimizer = optimizers.SGD(learning_rate=0.01), # 替换lr为learning_rate loss = 'categorical_crossentropy', metrics = ['accuracy']) # ... model = classifier.fit( # 替换fit_generator为fit training_set, steps_per_epoch=800, epochs=25, validation_data = test_set, validation_steps = 6500)
内容的提问来源于stack exchange,提问作者Harris Irman
相关产品推荐
相关产品推荐

