搭建自定义ResNet模型时出现Input has undefined rank错误如何解决?
错误原因
- 核心错误出在ConvBlock的捷径分支实现:你定义了Conv2D层后没有把输入张量
X_shortcut传入层实例做前向计算,直接将Conv2D层对象传给了后续的BatchNormalization层。BN层拿到的不是具备shape属性的张量,无法推断输入维度,因此抛出undefined rank错误。 - 次要错误1:你自定义的模型函数命名为
ResNet,但调用时使用了ResNet50,函数名不匹配无法调用。 - 次要错误2:构建Model实例时参数应为
inputs和outputs,你写的input和output在高版本Keras/TensorFlow中会触发参数错误。 - 潜在错误:恒等块要求主路径输出和捷径分支的shape、通道数完全一致,你主路径第一个Conv2D使用了
padding='valid'会导致特征图尺寸缩小,和捷径分支的原始输入尺寸不匹配,调用Add层时会触发维度不兼容错误。
修复方案
1. 修正ConvBlock的捷径分支代码
给Conv2D层传入输入张量X_shortcut,同时根据主路径的降采样情况配置卷积步长,保证输出维度和主路径匹配。
2. 修正恒等块的padding配置、函数名、Model参数等问题
修正后的完整代码如下:
修正后的恒等块(Identity Block)
def IdentityBlock(X, f, filters): F1, F2, F3 = filters X_shortcut = X # padding改为same,避免特征图尺寸缩小和shortcut不匹配 X = Conv2D(filters = F1, kernel_size = (3, 3), padding = 'same')(X) X = BatchNormalization()(X) X = Activation('relu')(X) X = Conv2D(filters = F2, kernel_size = (f, f), padding = 'same')(X) X = BatchNormalization()(X) X = Activation('relu')(X) X = Conv2D(filters = F3, kernel_size = (3, 3), padding = 'same')(X) X = BatchNormalization()(X) X = Add()([X, X_shortcut]) X = Activation('relu')(X) return X
修正后的卷积块(Conv Block)
def ConvBlock(X, f, filters, s=2): F1, F2, F3 = filters X_shortcut = X X = Conv2D(filters = F1, kernel_size = (3, 3), strides=(s,s), padding = 'same')(X) X = BatchNormalization()(X) X = Activation('relu')(X) X = Conv2D(filters = F2, kernel_size = (f, f), padding = 'same')(X) X = BatchNormalization()(X) X = Activation('relu')(X) X = Conv2D(filters = F3, kernel_size = (3, 3), padding = 'same')(X) X = BatchNormalization()(X) # 修正:给shortcut的Conv2D传入输入张量,同时配置步长和主路径对齐 X_shortcut = Conv2D(filters = F3, kernel_size = (3, 3), strides=(s,s), padding = 'same')(X_shortcut) X_shortcut = BatchNormalization()(X_shortcut) X = Add()([X, X_shortcut]) X = Activation('relu')(X) return X
修正后的ResNet模型定义
def ResNet50(input_shape = (224, 224, 3)): X_input = Input(input_shape) X = Conv2D(64, (7, 7), strides=(2,2), padding='same')(X_input) X = BatchNormalization()(X) X = Activation('relu')(X) X = MaxPooling2D((3, 3), strides=(2,2), padding='same')(X) X = ConvBlock(X, f = 3, filters = [64, 64, 256], s=1) X = IdentityBlock(X, 3, filters = [64, 64, 256]) X = IdentityBlock(X, 3, filters = [64, 64, 256]) X = ConvBlock(X, f = 3, filters = [128, 128, 512]) X = IdentityBlock(X, 3, filters = [128, 128, 512]) X = IdentityBlock(X, 3, filters = [128, 128, 512]) X = IdentityBlock(X, 3, filters = [128, 128, 512]) X = GlobalAveragePooling2D()(X) # 替换原MaxPooling2D,符合ResNet标准实现 model = Model(inputs = X_input, outputs = X) return model
调用代码保持不变即可正常运行:
base_model = ResNet50(input_shape=(224, 224, 3))
内容的提问来源于stack exchange,提问作者Sticky
相关产品推荐
相关产品推荐

