You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用迁移学习处理多标签图像分类的严重不平衡数据并优化模型?

针对维也纳分类多标签图像任务的优化方案

一、处理类别不平衡的核心手段

类别不平衡是导致模型效果拉胯的关键原因,尤其是多标签场景下,常规accuracy指标完全失真,以下是可落地的解决方法:

1. 损失函数加权

给少数类别赋予更高的损失权重,强迫模型关注这些难学的类别:

  • 先统计每个类别的样本量,计算权重(示例用总样本数/(类别数*该类样本数)的公式):
    # 假设train_data里每个元素包含labels字段,统计每个类别的样本数
    class_counts = []
    for label in labels:
        count = 0
        for item in train_data:
            if label in item['labels']:
                count +=1
        class_counts.append(count)
    total_samples = len(train_data)
    class_weights = {i: total_samples/(len(labels)*count) for i, count in enumerate(class_counts)}
    
  • 在训练时传入权重:
    history = model.fit(train_generator, epochs=EPOCHS, shuffle=True, 
                        validation_data=valid_generator,
                        callbacks=[early_stopping], 
                        class_weight=class_weights,  # 加入这行
                        verbose=1)
    

2. 数据层面调整

  • 过采样少数类:对样本极少的类别,复制现有图像或用数据增强生成新样本(比如翻转、旋转、随机裁剪),可以在自定义DataGenerator里针对少数类做额外增强。
  • 欠采样多数类:对样本量极大的类别,随机丢弃部分样本,但别丢太多,最好配合交叉验证避免浪费数据。
  • 针对性增强:给少数类图像加更多增强操作(比如随机亮度调整、高斯噪声),缩小和多数类的数据分布差距。

3. 替换评价指标

多标签不平衡场景下,accuracy完全没参考价值,必须换用更合适的指标:

model.compile(
    loss=tf.keras.losses.BinaryCrossentropy(), 
    optimizer=tf.keras.optimizers.Adam(learning_rate=0.00002), 
    metrics=[
        tf.keras.metrics.Precision(name='precision'),
        tf.keras.metrics.Recall(name='recall'),
        tf.keras.metrics.F1Score(average='macro', name='f1_score')  # 多标签选macro或weighted
    ]
)

同时把EarlyStopping的监控指标换成val_f1_score,别再被accuracy误导:

early_stopping = tf.keras.callbacks.EarlyStopping(
    monitor='val_f1_score', min_delta=0.001, patience=5, verbose=1,
    mode='max', baseline=None, restore_best_weights=True
)

二、迁移学习中添加层的建议

现有模型结构可以优化,加层是可行的,但要避免过拟合:

1. 简化冗余层,加Dropout防过拟合

当前模型里GlobalAveragePooling2D已经输出了扁平化的特征,不需要再用Flatten,这一步是冗余的。同时建议在全连接层后加Dropout:

def load_network(labels):
    cnn = EfficientNetB0(include_top=False, input_shape=(224, 224, 3), weights="imagenet")
    # Rebuild top
    x = layers.GlobalAveragePooling2D(name="avg_pool")(cnn.output)
    x = layers.BatchNormalization()(x)
    # 删掉冗余的Flatten层
    fcn = tf.keras.layers.Dense(2048, activation='relu')(x)
    fcn = tf.keras.layers.Dropout(0.5)(fcn)  # 添加Dropout
    fcn_1 = tf.keras.layers.Dense(1024, activation='relu')(fcn)
    fcn_1 = tf.keras.layers.Dropout(0.3)(fcn_1)  # 可选的第二层Dropout
    fcn_classification = tf.keras.layers.Dense(len(labels), activation='sigmoid')(fcn_1)
    model = tf.keras.Model(inputs=cnn.inputs, outputs=fcn_classification)

    # 先冻结全部预训练层,训练完顶部再解冻微调
    for layer in cnn.layers:
        layer.trainable = False
    return model

2. 分阶段微调

别一开始就解冻大量层,建议分两步训练:

  1. 先冻结所有EfficientNet预训练层,只训练你加的全连接层,学习率设为1e-4。
  2. 训练3-5轮后,解冻EfficientNet的后10-20层,把学习率降到1e-5,继续训练让预训练层适配你的数据集。

3. 别加太多全连接层

过多全连接层会导致参数爆炸,容易过拟合。要加的话控制在2-3层以内,神经元数量逐步减少(比如2048→1024→512),同时配合Dropout和BatchNormalization。

额外检查点

  • 确认DataGenerator输出的标签是正确的多标签格式:每个样本对应一个长度为类别数的向量,有标签的位置为1,其余为0。
  • 显存足够的话可以试试更大的EfficientNet模型(比如B1-B4),但学习率要再调低些。

内容的提问来源于stack exchange,提问作者NHT_99

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.16 05:35:23