如何为TensorFlow的Inception模型添加新类别并保留原有1000类?
当然有可行的方案!给TensorFlow的Inception模型扩展类别,本质上是迁移学习的经典应用——我们不需要从头训练整个庞大的模型,只需要微调最后几层来适配新增的类别,同时保留原模型对1000类的识别能力。下面是一步步的实现指南:
核心思路
Inception模型(比如InceptionV3)的前几层是通用的特征提取器,已经在ImageNet的1000类数据上学到了强大的视觉特征。我们只需要替换掉模型最顶层的分类层,将其扩展为1000 + 新类别数的输出维度,然后训练这个新的分类层(甚至微调部分底层),让模型学会把提取到的特征映射到包含新类别的所有类别上。
具体实现步骤
1. 准备数据集
- 整理你的新类别数据:每个新类别单独放在一个文件夹中(和ImageNet的目录结构一致),每个类别建议至少准备50-100张图片(样本越多,效果越好)。如果想保留原1000类的识别能力,最好能准备原ImageNet中每类的少量样本(比如每类10-20张),防止模型“遗忘”原有知识。
- 使用TensorFlow的工具加载并预处理数据:
import tensorflow as tf # 加载数据集,调整尺寸到InceptionV3要求的299x299 train_ds = tf.keras.utils.image_dataset_from_directory( '你的数据集路径', image_size=(299, 299), batch_size=32, label_mode='int' # 标签用整数编码,新类别从1000开始编号 ) # 归一化到InceptionV3要求的[-1, 1]范围 preprocess_input = tf.keras.applications.inception_v3.preprocess_input train_ds = train_ds.map(lambda x, y: (preprocess_input(x), y)) - 可选:添加数据增强,提升模型泛化能力:
data_augmentation = tf.keras.Sequential([ tf.keras.layers.RandomFlip('horizontal'), tf.keras.layers.RandomRotation(0.1), tf.keras.layers.RandomZoom(0.1) ]) train_ds = train_ds.map(lambda x, y: (data_augmentation(x, training=True), y))
2. 加载预训练的Inception模型
加载去掉顶层分类层的InceptionV3,并冻结基础层的权重,避免训练时破坏已学到的特征:
base_model = tf.keras.applications.InceptionV3( weights='imagenet', # 加载ImageNet预训练权重 include_top=False, # 不包含顶层的分类层 input_shape=(299, 299, 3) ) base_model.trainable = False # 冻结基础模型
3. 构建新的分类头
在基础模型的输出上搭建适配新类别的分类层:
# 获取基础模型的输出 x = base_model.output # 全局平均池化,把特征图转为一维向量 x = tf.keras.layers.GlobalAveragePooling2D()(x) # 可选:添加全连接层,学习特征到新类别的映射 x = tf.keras.layers.Dense(1024, activation='relu')(x) x = tf.keras.layers.Dropout(0.5)(x) # Dropout防止过拟合 # 输出层:神经元数量 = 原1000类 + 你的新类别数 num_new_classes = 5 # 替换成你的新类别数量 predictions = tf.keras.layers.Dense(1000 + num_new_classes, activation='softmax')(x)
4. 组装并编译模型
把基础模型和新分类头组合起来,然后编译:
model = tf.keras.models.Model(inputs=base_model.input, outputs=predictions) # 编译模型,选择合适的优化器和损失函数 model.compile( optimizer=tf.keras.optimizers.Adam(learning_rate=1e-3), loss=tf.keras.losses.SparseCategoricalCrossentropy(), metrics=['accuracy'] )
5. 训练模型
阶段1:训练新分类头
先只训练我们新增的分类层,让模型学会用已有的特征识别新类别:
model.fit(train_ds, epochs=10)
阶段2:微调基础模型(可选)
如果想让模型效果更好,可以解冻基础模型的最后几层,用更小的学习率继续训练,让底层特征也适配新类别:
# 解冻基础模型的最后20层 base_model.trainable = True fine_tune_at = len(base_model.layers) - 20 for layer in base_model.layers[:fine_tune_at]: layer.trainable = False # 重新编译,用更小的学习率 model.compile( optimizer=tf.keras.optimizers.Adam(learning_rate=1e-5), loss=tf.keras.losses.SparseCategoricalCrossentropy(), metrics=['accuracy'] ) # 继续训练 model.fit(train_ds, epochs=20, initial_epoch=model.epoch)
6. 标签映射与推理
- 准备一个包含原1000类和新类别的标签字典:原ImageNet的标签可以参考
tf.keras.applications.inception_v3.decode_predictions对应的类别,然后把新类别从1000开始追加进去。 - 推理时,预测结果的索引对应到这个字典即可:
# 示例:预测一张图片 img = tf.keras.utils.load_img('测试图片路径', target_size=(299, 299)) img_array = tf.keras.utils.img_to_array(img) img_array = preprocess_input(img_array) img_array = tf.expand_dims(img_array, 0) predictions = model.predict(img_array) predicted_class_idx = tf.argmax(predictions[0]).numpy() # 用你的标签字典获取类别名称 predicted_class = your_label_dict[predicted_class_idx]
关键注意事项
- 样本数量:新类别样本越多,模型效果越稳定。如果样本少,优先用数据增强和过采样。
- 防止遗忘:如果要保留原1000类的识别能力,训练时最好加入少量原ImageNet样本,或者用知识蒸馏的方式让新模型继承原模型的输出。
- 学习率控制:微调基础层时一定要用极小的学习率,否则容易破坏预训练的特征。
内容的提问来源于stack exchange,提问作者kanishka chandra
相关产品推荐
相关产品推荐

