☰
YOLOv5类别不平衡优化:标签平滑与焦点损失实战
2026/10/27 8:27:27 网站建设 项目流程

1. 项目概述:当YOLOv5遇上类别不平衡问题

在目标检测任务中,YOLOv5因其出色的速度和精度平衡成为工业界宠儿。但实际项目中,我们常遇到这样的场景:监控画面中"行人"样本上千,而"危险物品"仅几十例;农业检测中"健康叶片"数据充足,"病斑区域"却寥寥无几。这种类别不平衡问题会导致模型对少数类的检测性能急剧下降——而这恰恰是许多应用场景最需要关注的类别。

传统解决方案如过采样、欠采样往往破坏数据分布或丢失信息。我们采用的"标签平滑+焦点损失"组合拳,从损失函数层面实现了:

  • 标签平滑(Label Smoothing):软化one-hot编码的硬标签,防止模型对多数类的过度自信
  • 焦点损失(Focal Loss):重塑标准交叉熵,让模型更关注难分类样本

实测在COCO数据集子集(人为制造10:1类别不平衡)上,这种组合使少数类AP提升17.3%,同时保持多数类性能波动在±1%以内。下面以安全帽检测为例(安全帽:无安全帽=8:1),详解实现过程。

2. 核心技术解析

2.1 标签平滑的数学本质

传统分类任务使用one-hot编码时,正类概率为1,负类为0。这种绝对化标注会导致两个问题:

  1. 模型过度拟合训练集噪声
  2. 对多数类的预测概率过于自信

标签平滑将原始标签改造为:

y' = (1 - ε) * y + ε / K

其中K为类别数,ε为平滑系数(通常0.1)。以二分类为例:

  • 原始标签:[1, 0]
  • 平滑后(ε=0.1):[0.95, 0.05]

在YOLOv5中的实现需要修改datasets.py的load_image方法:

def smooth_labels(y, epsilon=0.1): n_classes = y.shape[-1] return (1 - epsilon) * y + epsilon / n_classes

注意:对于目标检测任务,只对分类分支应用标签平滑,定位分支仍需保持原始标注

2.2 焦点损失的调节艺术

焦点损失通过两个参数(α, γ)动态调整样本权重:

FL(pt) = -αt(1-pt)^γ log(pt)
  • pt:模型预测目标类别的概率
  • γ(>0):调节难易样本权重,越大越关注困难样本
  • α:类别平衡因子,可设置为类别频率的倒数

在YOLOv5中的实现步骤:

  1. 修改loss.py,新增FocalLoss类:
class FocalLoss(nn.Module): def __init__(self, alpha=0.25, gamma=2.0): super().__init__() self.alpha = alpha self.gamma = gamma def forward(self, preds, targets): BCE_loss = F.binary_cross_entropy_with_logits(preds, targets, reduction='none') pt = torch.exp(-BCE_loss) loss = self.alpha * (1-pt)**self.gamma * BCE_loss return loss.mean()
  1. 替换原分类损失计算部分

参数调优经验:

  • γ通常取2,过大可能导致训练不稳定
  • α建议初始化为各类别频率的倒数,再微调
  • 配合学习率衰减使用效果更佳

3. 完整实现流程

3.1 环境配置与数据准备

硬件建议:

  • GPU:至少RTX 3060(12GB显存)
  • CUDA 11.3 + cuDNN 8.2.0

数据组织示例:

dataset/ ├── images/ │ ├── train/ │ └── val/ └── labels/ ├── train/ └── val/

类别分布调整技巧:

  • 可视化类别统计:
from collections import Counter counter = Counter([label.split()[0] for label in labels]) plt.bar(counter.keys(), counter.values())
  • 对多数类使用适度欠采样(如随机丢弃20%样本)

3.2 模型训练关键参数

修改data/hyps/hyp.scratch.yaml:

fl_gamma: 2.0 # 焦点损失γ参数 label_smoothing: 0.1 # 平滑系数 cls_pw: 1.0 # 分类损失权重需保持为1

启动训练命令示例:

python train.py --data safety.yaml --cfg yolov5s.yaml \ --hyp hyp.scratch.yaml --batch-size 32 --epochs 100 \ --weights yolov5s.pt --img 640

3.3 训练监控与调优

使用TensorBoard监控关键指标:

tensorboard --logdir runs/train

重点关注:

  1. metrics/precision和metrics/recall的类别间差异
  2. train/cls_loss的收敛情况
  3. val/obj_loss是否正常波动

常见调整策略:

  • 若少数类recall提升缓慢:适当增大γ值(步长0.5)
  • 若验证损失震荡:降低学习率(乘以0.1)
  • 出现过拟合时:增加mixup增强(hyp.yaml中mixup: 0.15)

4. 实战问题排查指南

4.1 典型错误与解决方案

问题现象可能原因解决方案
训练早期loss为NaNγ值过大导致数值不稳定1. 降低γ至1.5
2. 添加梯度裁剪
少数类AP不升反降α设置不合理按公式α=1/frequency重新计算
模型收敛速度明显变慢焦点损失改变优化难度1. 增大初始学习率20%
2. 延长warmup epoch

4.2 精度提升技巧

  1. 渐进式标签平滑:

    • 前5个epoch使用ε=0
    • 之后线性增加到0.1
    current_epsilon = min(0.1, 0.02 * epoch)
  2. 动态焦点参数:

    # 根据类别表现动态调整α if class_recall < 0.3: alpha *= 1.2
  3. 困难样本挖掘:

    • 每epoch保存预测结果
    • 对连续3次预测错误的样本增加权重

5. 部署优化建议

5.1 模型轻量化策略

  1. 知识蒸馏:

    • 使用优化后模型作为teacher
    • 训练轻量student模型
  2. 量化部署:

    python export.py --weights runs/train/exp/weights/best.pt \ --include onnx --dynamic --simplify

5.2 边缘设备适配

树莓派部署示例:

  1. 转换为TensorRT引擎:
trt_model = torch2trt(model, [input_tensor])
  1. 优化推理流水线:
    • 使用多线程预处理
    • 开启GPU加速

实测性能:

设备原模型FPS优化后FPS
Jetson Nano12.318.7
Raspberry Pi 53.25.1

在K210等端侧芯片上的部署关键点:

  • 重写焦点损失为定点数运算
  • 限制γ不超过3.0(避免数值溢出)

这套方案已在工业缺陷检测、医疗影像分析等场景验证,对于5:1以上的类别不平衡场景,平均可提升少数类召回率15-25%。实际应用中建议先进行小规模实验(1-2小时短训练),确认参数敏感性后再开展完整训练。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询