为何TensorFlow预训练MobileNetV2缺少全连接层与分类输出层?
问题成因
你实例化tf.keras.applications.MobileNetV2时设置了include_top=False,该参数的作用就是裁剪掉模型顶层用于ImageNet 1000类分类的全连接层模块,仅保留卷积特征提取部分,因此只能输出特征嵌入,这是问题的根本原因。
解决方法
方案1:直接加载带预训练全连接层的完整模型
如果你的需求是直接使用预训练权重做ImageNet 1000类分类,直接修改include_top参数为True即可,修改后的代码如下:
import numpy as np import PIL import tensorflow as tf image = np.array(PIL.Image.open("amsterdam.jpg")) image = np.expand_dims(image,0) IMG_SIZE = image.shape[1:3] IMG_SHAPE = IMG_SIZE + (3,) # 仅修改include_top参数为True即可保留全连接层 base_model = tf.keras.applications.MobileNetV2(input_shape=IMG_SHAPE, include_top=True, weights='imagenet') # 配套MobileNetV2的输入预处理逻辑 preprocess_input = tf.keras.applications.mobilenet_v2.preprocess_input processed_img = preprocess_input(image) # 输出1000维分类概率 preds = base_model.predict(processed_img) # 解码得到分类标签 print("预测结果Top3:", tf.keras.applications.mobilenet_v2.decode_predictions(preds, top=3)[0])
此时模型会自动加载与全连接层匹配的预训练权重,输出维度为1000。
方案2:在特征提取器后手动追加预训练全连接层
如果你需要保留include_top=False的特征提取结构,同时额外添加匹配预训练权重的全连接层,可以按以下逻辑实现:
import numpy as np import PIL import tensorflow as tf image = np.array(PIL.Image.open("amsterdam.jpg")) image = np.expand_dims(image,0) IMG_SIZE = image.shape[1:3] IMG_SHAPE = IMG_SIZE + (3,) # 加载无顶层的特征提取器 base_model = tf.keras.applications.MobileNetV2(input_shape=IMG_SHAPE, include_top=False, weights='imagenet') # 加载完整模型提取全连接层权重 full_pretrained_model = tf.keras.applications.MobileNetV2(input_shape=IMG_SHAPE, include_top=True, weights='imagenet') fc_weights = full_pretrained_model.get_layer('predictions').get_weights() # 拼接自定义模型 inputs = tf.keras.Input(shape=IMG_SHAPE) x = base_model(inputs, training=False) x = tf.keras.layers.GlobalAveragePooling2D()(x) # 全连接层结构和预训练结构保持一致 outputs = tf.keras.layers.Dense(1000, activation='softmax', name='predictions')(x) custom_model = tf.keras.Model(inputs, outputs) # 加载预训练全连接层权重 custom_model.get_layer('predictions').set_weights(fc_weights)
该方式适合需要在特征提取层和分类层之间插入自定义逻辑的场景。
内容的提问来源于stack exchange,提问作者fstab
相关产品推荐
相关产品推荐

