基于MobileNetV2的CNN添加自定义层时出现维度错误,求解决方案
问题原因分析
你遇到的错误核心是MobileNetV2输出的特征图尺寸太小,无法适配后续的5x5卷积层:
当输入为96x96x3时,include_top=False的MobileNetV2会经过多次下采样,最终输出的特征图尺寸是3x3x1280。而你添加的Conv2D层默认使用padding='valid'(无填充),此时输出尺寸计算公式为:输出尺寸 = (输入尺寸 - 卷积核尺寸 + 2*padding)/步长 + 1
代入3x3输入和5x5卷积核后,得到(3-5+0)/1 +1 = -1,直接出现负维度,触发报错。
另外,你在Conv2D层手动指定的input_shape=(96,96,3)完全无效——Sequential模型中后续层会自动继承上一层的输出形状,这个参数只会造成混淆,建议直接删除。
修复方案
以下三种方案任选其一即可:
方案1:给卷积层添加填充
通过padding='same'让卷积层自动填充输入,保证输出尺寸与输入一致,避免维度异常:
base_model = tf.keras.applications.MobileNetV2(input_shape=(96,96,3), include_top=False, weights='imagenet') model = tf.keras.Sequential() model.add(base_model) # 添加padding='same',删除无效的input_shape参数 model.add(layers.Conv2D(60, kernel_size=(5, 5), strides=(1, 1), activation='relu', padding='same')) model.add(layers.MaxPooling2D(pool_size=(2, 2), strides=(2, 2))) # 后续卷积层同样需要添加padding,否则1x1特征图用5x5卷积仍会报错 model.add(layers.Conv2D(64, kernel_size=(5, 5), strides=(1, 1), activation='relu', padding='same')) model.add(layers.Flatten()) model.add(layers.Dense(500, activation='relu')) model.add(layers.Dense(10, activation='softmax'))
方案2:缩小卷积核尺寸
把5x5卷积换成更小的尺寸(比如3x3或1x1),适配3x3的特征图:
base_model = tf.keras.applications.MobileNetV2(input_shape=(96,96,3), include_top=False, weights='imagenet') model = tf.keras.Sequential() model.add(base_model) # 换成3x3卷积核,无需填充也能得到1x1的输出 model.add(layers.Conv2D(60, kernel_size=(3, 3), strides=(1, 1), activation='relu')) # 用1x1卷积做通道转换,避免尺寸问题 model.add(layers.Conv2D(64, kernel_size=(1, 1), strides=(1, 1), activation='relu')) model.add(layers.Flatten()) model.add(layers.Dense(500, activation='relu')) model.add(layers.Dense(10, activation='softmax'))
方案3:增大输入图像尺寸
如果坚持使用5x5卷积且不添加填充,可以把输入尺寸调整为更大的值(比如224x224),让MobileNetV2输出的特征图尺寸足够大:
# 修改输入尺寸为224x224,此时MobileNetV2输出7x7x1280的特征图 base_model = tf.keras.applications.MobileNetV2(input_shape=(224,224,3), include_top=False, weights='imagenet') model = tf.keras.Sequential() model.add(base_model) model.add(layers.Conv2D(60, kernel_size=(5, 5), strides=(1, 1), activation='relu')) model.add(layers.MaxPooling2D(pool_size=(2, 2), strides=(2, 2))) model.add(layers.Conv2D(64, kernel_size=(5, 5), strides=(1, 1), activation='relu')) model.add(layers.MaxPooling2D(pool_size=(2, 2), strides=(2, 2))) model.add(layers.Flatten()) model.add(layers.Dense(500, activation='relu')) model.add(layers.Dense(10, activation='softmax'))
内容的提问来源于stack exchange,提问作者tmiwetmiwtwete
相关产品推荐
相关产品推荐

