基于Hugging Face的稀疏多标签文本分类类不平衡损失选型
问题解答
一、损失函数更换是否能提升召回/精确率
可以,你当前使用的默认BCEWithLogitsLoss没有适配稀疏多标签、类别不平衡的场景,默认所有类别、所有样本的损失权重相等,高频簇的损失会主导梯度更新,导致模型倾向于只预测高频簇、漏识别稀有簇,更换适配不平衡场景的损失函数能大幅提升效果,可选择的损失函数如下:
- 加权
BCEWithLogitsLoss
给每个类别设置差异化权重,稀有簇权重更高,权重计算规则为类别权重 = 总样本数/(类别数 * 该类别正样本数),代码示例:# 提前统计训练集中每个簇的正样本数量,得到长度为60的pos_counts数组 total_samples = len(train_dataset) pos_weight = torch.tensor([(total_samples - cnt) / cnt for cnt in pos_counts]).to(device) loss_func = BCEWithLogitsLoss(pos_weight=pos_weight) - 多标签版Focal Loss
在加权BCE的基础上,进一步降低易分类样本(大部分高频簇样本属于易分类样本)的损失权重,让模型更关注难分类的稀有簇样本,代码示例:import torch.nn as nn import torch.nn.functional as F class MultiLabelFocalLoss(nn.Module): def __init__(self, alpha=None, gamma=2, logits=True, reduce=True): super(MultiLabelFocalLoss, self).__init__() self.alpha = alpha # 传入计算好的类别权重数组 self.gamma = gamma # 一般取值为2 self.logits = logits self.reduce = reduce def forward(self, inputs, targets): if self.logits: BCE_loss = F.binary_cross_entropy_with_logits(inputs, targets, reduction='none') else: BCE_loss = F.binary_cross_entropy(inputs, targets, reduction='none') pt = torch.exp(-BCE_loss) F_loss = self.alpha * (1-pt)**self.gamma * BCE_loss return torch.mean(F_loss) if self.reduce else F_loss # 初始化损失函数 loss_func = MultiLabelFocalLoss(alpha=class_weights, gamma=2) - 非对称损失(ASL Loss)
更适配极端稀疏的多标签分类场景,会分别调整正、负样本的梯度权重,进一步降低稀有簇漏检的概率,效果优于Focal Loss。
二、多标签场景下类别不平衡的其他解决方案
1. 训练策略优化
- 你当前代码中设置的学习率
lr=0.05过高,BERT类预训练模型微调的学习率建议设置在2e-5到5e-5区间,过高的学习率会导致模型快速拟合高频簇特征,完全学不到稀有簇的特征,这是你当前模型效果差的核心问题之一。 - 训练时加入早停策略,监控验证集上稀有簇的F1值,而非整体损失或整体准确率,避免模型过拟合高频簇。
- 推理阶段调整分类阈值:默认阈值为0.5,可以给稀有簇设置更低的阈值提升召回,给高频簇设置更高的阈值提升精度。
2. 数据层面优化
- 对稀有簇样本做文本增强:采用回译、同义词替换、上下文扰动等方法扩充稀有簇的训练样本,避免直接复制样本导致的过拟合。
- 自定义采样逻辑:重写dataloader的采样器,保证每个训练批次中包含一定比例的稀有簇样本,避免批次中全是高频簇样本。
3. 模型层面优化
- 可以在BERT输出层后加入类别注意力层,针对性学习不同簇对应的文本特征,提升稀有簇的特征识别能力。
- 可尝试采用Prompt Tuning的微调方式,给每个簇设计对应的提示模板,更好地迁移预训练模型的通用知识到稀有簇上。
内容的提问来源于stack exchange,提问作者MAC
相关产品推荐
相关产品推荐

