重新训练Mobilenet_v1新增synsets:保留原1000类的实现疑问
嘿,这个问题我太熟悉了!之前做迁移学习扩展预训练模型类别时,也踩过一模一样的坑,给你梳理清楚怎么解决:
问题根源
你碰到的情况是因为官方默认的迁移学习脚本(比如早期TensorFlow的retrain.py),默认逻辑是直接替换预训练模型的最后一层全连接层,把输出维度从1000改成你的自定义类别数10——这相当于完全丢弃了原模型对1000类的分类能力,只保留前面的特征提取部分来适配你的新类别。
解决方案:当然可以保留原1000类+新增10类!
核心思路是不替换原最后一层,而是在原层的基础上扩展输出维度,把原1000类的权重保留,同时新增10类的权重进行训练。具体分两种框架来操作:
一、TensorFlow 1.x(基于图模式)
- 加载预训练模型,找到特征提取层的输出节点(比如MobileNet的
MobilenetV1/Logits/Conv2d_1c_1x1/BiasAdd,这是最后一层卷积的输出,还没做全连接分类)。 - 获取原分类层的权重:原模型最后一层全连接层的权重是1024×1000(MobileNet的特征维度是1024),偏置是1000维,你可以通过
tf.get_default_graph().get_tensor_by_name()获取这些预训练好的权重。 - 构建新的分类层:
- 新建一个1024×1010的权重矩阵,前1000列直接用原模型的权重,后10列用随机初始化的权重(比如
tf.random.normal)。 - 新建一个1010维的偏置向量,前1000个用原模型的偏置,后10个随机初始化。
- 用特征提取层的输出和新权重做矩阵乘法,加新偏置得到1010维的logits,再接Softmax层。
- 新建一个1024×1010的权重矩阵,前1000列直接用原模型的权重,后10列用随机初始化的权重(比如
- 训练设置:
- 如果你想快速训练,可以冻结特征提取层的所有参数,只训练新分类层的后10列权重和偏置。
- 如果追求更好的效果,可以微调特征提取层的部分参数(比如最后几个卷积块),但需要更多算力和数据。
- 自定义数据的标签要设为1000~1009(避免和原1000类标签冲突),训练时模型会学习这些新标签的特征,而原1000类的权重因为保留了预训练结果,依然能正常分类。
二、TensorFlow 2.x(Keras接口,更简单)
用Keras的话,代码会更直观,示例如下:
import tensorflow as tf from tensorflow.keras.applications import MobileNet from tensorflow.keras.models import Model # 1. 加载预训练MobileNet,去掉顶层分类层 base_model = MobileNet(weights='imagenet', include_top=False, input_shape=(224, 224, 3)) # 2. 添加全局平均池化层,把特征转为1024维向量 x = base_model.output x = tf.keras.layers.GlobalAveragePooling2D()(x) # 3. 获取原模型的顶层分类层权重 original_top_layer = MobileNet(weights='imagenet', include_top=True).layers[-1] original_weights, original_biases = original_top_layer.get_weights() # 4. 构建新的顶层分类层:1010类 # 扩展权重矩阵:原1024×1000 + 新增1024×10 new_weights = tf.concat([original_weights, tf.Variable(tf.random.normal((1024, 10)))], axis=1) # 扩展偏置向量:原1000维 + 新增10维 new_biases = tf.concat([original_biases, tf.Variable(tf.random.normal((10,)))], axis=0) # 5. 创建新的输出层并设置权重 new_output = tf.keras.layers.Dense(1010, activation='softmax')(x) new_output.set_weights([new_weights, new_biases]) # 6. 构建完整模型 model = Model(inputs=base_model.input, outputs=new_output) # 7. 训练设置:冻结特征层,只训练新顶层 for layer in base_model.layers: layer.trainable = False # 8. 编译并训练 model.compile(optimizer='adam', loss='categorical_crossentropy', metrics=['accuracy']) model.fit(your_custom_dataset, epochs=20, batch_size=32)
关键注意事项
- 标签唯一性:确保你的10个自定义类标签(10001009)和ImageNet原1000类的标签(0999)没有重叠。
- 原类性能维护:如果担心原1000类的分类性能下降,可以加入少量ImageNet样本一起训练,或者选择微调特征层的部分参数。
- 模型保存:训练完成后保存的
.pb文件(或者Keras的.h5/.keras文件)会包含完整的1010类分类能力,预测时直接输入图片就能得到1010个类别的概率。
内容的提问来源于stack exchange,提问作者Hao Xi
相关产品推荐
相关产品推荐

