FCN8解码器报错ValueError:输入形状不兼容,求问题排查
FCN8解码器运行报错:输入形状不兼容
我编写了如下FCN8解码器代码:
def fcn8_decoder(convs, n_classes): # features from the encoder stage f3, f4, f5 = convs # number of filters n = 512 # add convolutional layers on top of the CNN extractor. o = tf.keras.layers.Conv2D(n , (7 , 7) , activation='relu' , padding='same', name="conv6", data_format=IMAGE_ORDERING)(f5) o = tf.keras.layers.Dropout(0.5)(o) o = tf.keras.layers.Conv2D(n , (1 , 1) , activation='relu' , padding='same', name="conv7", data_format=IMAGE_ORDERING)(o) o = tf.keras.layers.Dropout(0.5)(o) o = tf.keras.layers.Conv2D(n_classes, (1, 1), activation='relu' , padding='same', data_format=IMAGE_ORDERING)(o) ### START CODE HERE ### # Upsample `o` above and crop any extra pixels introduced o = tf.keras.layers.Conv2DTranspose(n_classes , kernel_size=(4,4) , strides=(2,2) , use_bias=False)(o) o = tf.keras.layers.Cropping2D(cropping=(1,1))(o) # load the pool 4 prediction and do a 1x1 convolution to reshape it to the same shape of `o` above o2 = f4 o2 = ( tf.keras.layers.Conv2D(n_classes , ( 1 , 1 ) , activation='relu' , padding='same', data_format=IMAGE_ORDERING))(o2) # add the results of the upsampling and pool 4 prediction o = tf.keras.layers.Add()([o, o2]) # upsample the resulting tensor of the operation you just did o = (tf.keras.layers.Conv2DTranspose( n_classes , kernel_size=(4,4) , strides=(2,2) , use_bias=False))(o) o = tf.keras.layers.Cropping2D(cropping=(1, 1))(o) # load the pool 3 prediction and do a 1x1 convolution to reshape it to the same shape of `o` above o2 = f3 o2 = tf.keras.layers.Conv2D(n_classes , ( 1 , 1 ) , activation='relu' , padding='same', data_format=IMAGE_ORDERING)(o2) # add the results of the upsampling and pool 3 prediction o = tf.keras.layers.Add()([o, o2]) # upsample up to the size of the original image o = tf.keras.layers.Conv2DTranspose(n_classes , kernel_size=(8,8) , strides=(8,8) , use_bias=False )(o) o = tf.keras.layers.Cropping2D(((0, 0), (0, 96-84)))(o) # append a sigmoid activation o = (tf.keras.layers.Activation('sigmoid'))(o) ### END CODE HERE ### return o # TEST CODE test_convs, test_img_input = FCN8() test_fcn8_decoder = fcn8_decoder(test_convs, 11) print(test_fcn8_decoder.shape) del test_convs, test_img_input, test_fcn8_decoder
运行时出现如下错误:
--------------------------------------------------------------------------- ValueError Traceback (most recent call last) <ipython-input-14-cff468b82c6a> in <module> 2 3 test_convs, test_img_input = FCN8() ----> 4 test_fcn8_decoder = fcn8_decoder(test_convs, 11) 5 6 print(test_fcn8_decoder.shape) 2 frames /usr/local/lib/python3.8/dist-packages/keras/layers/merging/base_merge.py in _compute_elemwise_op_output_shape(self, shape1, shape2) 71 else: 72 if i != j: ---> 73 raise ValueError( 74 'Inputs have incompatible shapes. ' 75 f'Received shapes {shape1} and {shape2}') ValueError:输入形状不兼容。接收到的形状为(4, 4, 11)和(4, 5, 11)
请问我哪里出错了?
错误原因分析
报错提示在Add层中两个张量形状不兼容:(4, 4, 11)和(4, 5, 11),说明高度一致但宽度差1。问题出在第一次上采样后的裁剪操作与编码器输出f4的形状不匹配:
- 经过
Conv2DTranspose(strides=(2,2), kernel_size=(4,4))和Cropping2D(cropping=(1,1))后,张量o的宽度被裁剪为4。 - 编码器输出
f4经过1x1卷积后宽度为5,两者无法直接相加。
这种差异通常是因为输入图像的尺寸不是偶数,或者编码器阶段的padding/步长导致特征图尺寸出现奇数,固定裁剪参数无法适配。
解决方案
方案1:动态裁剪匹配形状
在Add层之前,对o2(即f4的处理结果)进行裁剪,使其宽度与o一致:
# 替换原Add层前的代码 o2 = f4 o2 = tf.keras.layers.Conv2D(n_classes , (1,1), activation='relu', padding='same', data_format=IMAGE_ORDERING)(o2) # 动态裁剪o2的宽度,匹配o的宽度 o2 = tf.keras.layers.Cropping2D(cropping=((0,0), (0, o2.shape[2] - o.shape[2])))(o2) o = tf.keras.layers.Add()([o, o2])
方案2:调整固定裁剪参数
如果已知f4的宽度比o大1,直接修改第一次Cropping2D的参数,只裁剪右侧1个像素,保留宽度为5:
# 替换原第一次Cropping2D代码 o = tf.keras.layers.Cropping2D(cropping=((1,1), (0,1)))(o)
方案3:使用Resize层适配形状
更灵活的方式是用Resize层将其中一个张量的尺寸统一到另一个的大小,避免依赖固定裁剪:
# 替换原Add层前的代码 o2 = f4 o2 = tf.keras.layers.Conv2D(n_classes , (1,1), activation='relu', padding='same', data_format=IMAGE_ORDERING)(o2) # 将o2 resize到o的形状 o2 = tf.keras.layers.Resizing(height=o.shape[1], width=o.shape[2])(o2) o = tf.keras.layers.Add()([o, o2])
另外,注意最后一步的Cropping2D(((0,0),(0,96-84)))是针对特定输入宽度(84)的固定裁剪,若输入尺寸变化,这里也可能引发后续形状问题,建议改为动态计算裁剪量。
内容的提问来源于stack exchange,提问作者Paul Reiners
相关产品推荐
相关产品推荐

