CNN最大池化层引发负维度尺寸错误求助
嗨,我看了你的代码和错误信息,这个问题其实是两个常见的小bug导致的,咱们一步步来解决:
首先看错误核心:Negative dimension size caused by subtracting 2 from 1,意思是你的特征图某个维度已经缩小到1了,再用2x2的最大池化窗口去处理,就会算出负数维度,直接报错。
第一个问题:卷积层堆叠错误
你的conv_block函数里,第二个Conv2D层的输入写的是inputs而不是上一层的输出x!这就导致两个卷积层是并行作用在同一个输入上,第一个卷积层的结果直接被覆盖了,完全没起到堆叠提取特征的作用,还可能让特征图的维度变化不符合预期。
修复这个很简单,把第二个Conv2D的输入改成x就行:
def conv_block(inputs, n_filter, regularizer, common_args): x = tf.keras.layers.Conv2D(filters=n_filter, kernel_size=3, strides=1, padding='same', activation='relu', kernel_regularizer=regularizer, **common_args)(inputs) # 这里把inputs改成x,让第二个卷积层接在第一个的输出后面 x = tf.keras.layers.Conv2D(filters=n_filter, kernel_size=3, strides=1, padding='same', activation='relu', kernel_regularizer=regularizer, **common_args)(x) x = tf.keras.layers.MaxPooling2D((2, 2))(x) return x
第二个问题:输入数据的维度可能不对
从错误信息里的输入形状[?,128,10,1](NCHW格式,对应NHWC的(None,10,1,128))来看,你的特征图宽度已经变成1了,这说明你的输入数据可能没按照预期的(40,40,7)格式传入。比如可能不小心把通道维度放在了中间,变成了(40,7,40),这样经过两次池化后,宽度维度就会从7→3→1,第三次池化就炸了。
你可以先验证一下输入数据的形状:
# 取一个训练样本看看形状 for sample in train_dataset.take(1): print("样本形状:", sample.shape)
正常应该输出(40,40,7)(未batch的情况)或者(64,40,40,7)(已batch的情况)。如果维度不对,用tf.transpose调整:
# 比如如果当前是(7,40,40),转成(40,40,7) adjusted_sample = tf.transpose(sample, perm=[1,2,0])
如果你的数据是channels_first格式,也可以在模型里统一指定:在Conv2D和MaxPooling2D层里加上data_format="channels_first",同时输入层改成Input(shape=(n_bands, img_size, img_size))。
修复后验证维度变化
修复完上面两个问题,咱们算一下特征图的尺寸变化:
- 初始输入:40x40x7
- 第一次conv_block:两次卷积后还是40x40x32,池化后变成20x20x32
- 第二次conv_block:两次卷积后20x20x64,池化后10x10x64
- 第三次conv_block:两次卷积后10x10x128,池化后5x5x128
- Flatten后是55128=3200,完全没问题,不会出现负维度。
按照上面的步骤改完,应该就能顺利训练了!
备注:内容来源于stack exchange,提问作者riskiem

