Keras中output_shape与实际形状差异:ResNet50层调用异常
解决ResNet50预训练层输出形状不匹配的问题
哈哈,这个坑我之前踩过!本质上是你忽略了ResNet50预训练模型里第一个卷积层前置的padding操作,导致单独调用层的时候形状计算跑偏了。
为什么会出现这种差异?
你看,ResNet50的预训练模型结构里,第一个卷积层(通常叫conv1_conv)前面其实还有个ZeroPadding2D((3,3))层。在model.summary()里,显示的是经过padding后的输入再走卷积层的输出形状——输入(224,224,3)先padding成(230,230,3),再经过kernel_size=(7,7)、strides=(2,2)的卷积,计算出来的输出就是(112,112,64),和你看到的summary结果一致。
但如果你直接把(224,224,3)的输入张量传给那个卷积层,没有前置的padding,那计算方式就变成了:(224 -7)/2 +1 = 109.5,Keras会向下取整得到109,于是输出形状就变成了(?,109,109,64),自然和预期不符。
两种快速解决方法
方法1:直接构建包含前置层的子模型
不用单独提取卷积层,直接把从输入到目标层的整个路径打包成子模型,这样就能保留原模型的所有前置操作:
from tensorflow.keras.applications import ResNet50 from tensorflow.keras.models import Model import numpy as np # 加载预训练ResNet50,注意指定输入形状 base_model = ResNet50(include_top=False, input_shape=(224,224,3), weights='imagenet') # 获取到你要的firstconv层,比如ResNet50里的conv1_conv target_layer = base_model.get_layer('conv1_conv') # 构建子模型,自动包含所有前置层 sub_model = Model(inputs=base_model.input, outputs=target_layer.output) # 测试输入 test_input = np.random.rand(1,224,224,3) output = sub_model.predict(test_input) print(output.shape) # 输出 (1, 112, 112, 64),和summary一致
方法2:手动添加前置padding层
如果你非要单独调用那个卷积层,记得手动补上它原本依赖的padding操作:
from tensorflow.keras.layers import Input, ZeroPadding2D from tensorflow.keras.applications import ResNet50 base_model = ResNet50(include_top=False, input_shape=(224,224,3), weights='imagenet') target_layer = base_model.get_layer('conv1_conv') target_layer.trainable = False # 不想训练预训练层的话加上这句 # 定义输入并添加padding input_tensor = Input(shape=(224,224,3)) x = ZeroPadding2D(padding=(3,3), name='conv1_pad')(input_tensor) # 再经过目标卷积层 x = target_layer(x) print(x.shape) # 输出 (None, 112, 112, 64),符合预期
额外注意点
- 确保你的输入张量尺寸是
(224,224,3),这是ResNet50预训练模型的默认输入尺寸; - 别忘了用
preprocess_input处理输入,虽然这不会直接影响形状,但能保证输入符合预训练模型的要求:from tensorflow.keras.applications.resnet50 import preprocess_input test_input = preprocess_input(test_input)
内容的提问来源于stack exchange,提问作者RolandDeschain
相关产品推荐
相关产品推荐

