You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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:
---&gt; 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的形状不匹配:

  1. 经过Conv2DTranspose(strides=(2,2), kernel_size=(4,4))和Cropping2D(cropping=(1,1))后,张量o的宽度被裁剪为4。
  2. 编码器输出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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.02 18:11:10