YOLOv11 改进策略 | Soft-NMS 与 IoU 家族损失,提升密集遮挡场景检测精度

YOLOv11 改进策略 | Soft-NMS 与 IoU 家族损失,提升密集遮挡场景检测精度

介绍

在目标检测任务中,模型通常会为图像中的许多区域生成大量的候选边界框。非极大值抑制(Non-Maximum Suppression, NMS)是一种标准的后处理算法,用于去除冗余的边界框,保留最终的检测结果。然而,传统的 NMS 算法采用“硬阈值”的策略,当两个真实目标距离很近或发生严重遮挡时,得分较低的真实目标的边界框可能会被得分较高的目标的边界框误删,导致漏检。Soft-NMS 是一种对传统 NMS 的改进,它不直接移除与高得分框重叠的低得分框,而是降低其置信度得分,从而减轻误删问题。同时,为了让模型在训练阶段就预测出更精确、更符合实际目标的边界框,研究人员提出了多种基于 IoU(Intersection over Union)的边界框回归损失函数,如 GIoU、DIoU、CIoU、SIoU 和 EIou。将 Soft-NMS 应用于 YOLOv11 的后处理阶段,并结合先进的 IoU-based 损失函数进行模型训练,是提升模型在密集遮挡场景下检测精度的有效策略。

引言

在现实世界的许多场景中,目标往往会紧密排列或相互遮挡,例如拥挤的人群、繁忙的交通、堆叠的货物等。这些场景对目标检测算法提出了严峻的挑战。传统的 NMS 算法在处理这些情况时,容易将本属于不同目标的重叠边界框误判为同一目标的冗余检测,从而错误地抑制了得分较低但属于真实目标的边界框。Soft-NMS 通过引入一种平滑的得分衰减机制,使得被抑制的边界框仍有机会在最终结果中保留,有效缓解了传统 NMS 的“硬抑制”问题。另一方面,模型预测边界框的质量直接影响到 NMS 的效果。基于 IoU 的损失函数家族,通过直接优化预测框与真实框之间的 IoU 或其相关的几何特性,能够引导模型预测出更准确、更鲁棒的边界框,为 Soft-NMS 提供高质量的输入,从而共同提升在密集遮挡场景下的检测精度。

技术背景

NMS (Non-Maximum Suppression)

传统 NMS 的工作流程如下:

  1. 根据模型的置信度得分对所有预测边界框进行排序。
  2. 选择得分最高的边界框作为当前最优框。
  3. 计算当前最优框与所有其他边界框的 IoU。
  4. 移除所有与当前最优框 IoU 大于某个阈值(例如 0.5)的边界框。
  5. 重复步骤 2-4,直到所有边界框都被处理。

这种“赢者通吃”的策略在目标重叠较少时工作良好,但在密集场景下容易导致误删。

Soft-NMS

Soft-NMS 对传统 NMS 的步骤 4 进行了修改:

  1. 根据模型的置信度得分对所有预测边界框进行排序。
  2. 选择得分最高的边界框作为当前最优框。
  3. 计算当前最优框与所有其他边界框的 IoU。
  4. 对于与当前最优框 IoU 大于某个阈值的其他边界框,不是直接移除它们,而是根据 IoU 值降低它们的置信度得分。常用的得分衰减函数有两种:
    • 线性衰减:
      s i = s i × { 1 if IoU ( M , b i ) < IoU t h r e s h 1 − IoU ( M , b i ) if IoU ( M , b i ) ≥ IoU t h r e s h s_i = s_i \times \begin{cases} 1 & \text{if IoU}(M, b_i) < \text{IoU}_{thresh} \\ 1 - \text{IoU}(M, b_i) & \text{if IoU}(M, b_i) \ge \text{IoU}_{thresh} \end{cases} si=si×{ 11IoU(M,bi)if IoU(M,bi)<IoUthreshif IoU(M,bi)IoUthresh
    • 高斯衰减:
      s i = s i × e − IoU ( M , b i ) 2 σ s_i = s_i \times e^{-\frac{\text{IoU}(M, b_i)^2}{\sigma}} si=si×eσIoU(M,bi)2
      其中, s i s_i si 是边界框 b i b_i bi 的原始得分, M M M 是当前得分最高的边界框, IoU ( M , b i ) \text{IoU}(M, b_i) IoU(M,bi) M M M b i b_i bi 之间的 IoU, IoU t h r e s h \text{IoU}_{thresh} IoUthresh 是 IoU 阈值, σ \sigma σ 是高斯衰减的参数。
  5. 将当前最优框添加到最终检测结果列表中。
  6. 将当前最优框从待处理的边界框列表中移除。
  7. 重复步骤 2-6,直到所有边界框的得分都低于某个最终置信度阈值。

通过得分衰减,Soft-NMS 允许与高得分框重叠的边界框在得分降低后仍有机会被选中,从而减少了对密集目标的误删。

Bounding Box Regression Loss

边界框回归损失用于衡量模型预测的边界框与真实边界框之间的差异,并指导模型参数的优化。传统的回归损失函数(如 L1 或 L2 损失)是基于预测框和真实框的坐标差计算的,它们与 IoU 之间的相关性不强,且对尺度的变化敏感。

IoU (Intersection over Union)

IoU 是衡量两个边界框重叠程度的常用指标,定义为两个边界框交集面积与并集面积之比:

IoU = Area ( B p ∩ B g t ) Area ( B p ∪ B g t ) \text{IoU} = \frac{\text{Area}(B_p \cap B_{gt})}{\text{Area}(B_p \cup B_{gt})} IoU=Area(BpBgt)Area(BpBgt)

其中 B p B_p Bp 是预测边界框, B g t B_{gt} Bgt 是真实边界框。IoU 值介于 0 到 1 之间,1 表示完全重合,0 表示完全不重合。

IoU-based Losses (GIoU, DIoU, CIoU, SIoU, EIou)

IoU-based 损失函数直接以 IoU 或其改进形式作为损失项,能够更好地反映边界框的重叠程度,从而引导模型预测出更精确的边界框。

  • GIoU Loss (Generalized IoU): 解决了 IoU 在预测框与真实框不重叠时梯度为 0 的问题。GIoU 考虑了预测框和真实框的最小外接矩形 C C C,并引入了惩罚项:
    GIoU = IoU − Area ( C ∖ ( B p ∪ B g t ) ) Area ( C ) \text{GIoU} = \text{IoU} - \frac{\text{Area}(C \setminus (B_p \cup B_{gt}))}{\text{Area}(C)} GIoU=IoUArea(C)Area(C(BpBgt))

### 实现YOLOv8中的Soft-NMS及其不同类型IOU结合 在目标检测领域,尤其是面对密集遮挡场景时,改进后的NMS算法能够显著提升模型的表现。对于YOLOv8而言,在原有基础上引入Soft-NMS并结合多种类型的交并比(IOU),可以有效改善此类复杂环境下的检测效果。 #### Soft-NMS简介 传统NMS通过设定阈值来过滤重叠框,而Soft-NMS则采用更灵活的方式调整候选框得分,从而保留更多潜在的有效预测[^2]。具体来说,当两个边界框存在较大程度上的重合时,不是简单地丢弃其中一个,而是降低其置信度分数,使得最终输出更加合理。 #### 结合不同类型的IOU 为了进一步增强YOLOv8应对密集物体的能力,可以在Soft-NMS过程中融入GIOU、DIOU、CIOU、EIOU和SIOU改进IOU计算方法: - **Generalized IOU (GIoU)**:不仅考虑了两矩形之间的相交区域,还加入了包围这两个矩形最小外接矩形的影响因子。 - **Distance IOU (DIoU)**:除了上述因素之外,额外考量中心点距离对相似性的贡献。 - **Complete IOU (CIoU)**:综合了尺度差异、形状匹配等多个方面的影响。 - **Enhanced IOU (EIou)**:在此基础上增加了角度偏差惩罚项。 - **Symmetric IOU (SIoU)**:强调两侧边界的相对位置关系。 这些变体形式能够在不同程度上弥补标准IOU存在的局限性,特别是在处理高度拥挤或部分被遮挡的对象时表现出色[^1]。 #### Python代码示例 以下是基于PyTorch框架下实现带有各种IOU版本的Soft-NMS函数的一个简化版例子: ```python import torch def soft_nms_with_iou_types(boxes, scores, iou_type='giou', sigma=0.5, thresh=0.4): """ :param boxes: Tensor of shape [num_boxes, 4], each row is [x_min, y_min, x_max, y_max]. :param scores: Tensor of shape [num_boxes]. Confidence score for each box. :param iou_type: Type of IoU to use ('giou', 'diou', 'ciou', 'eiou', or 'siou'). :return: Indices of the selected boxes after applying Soft-NMS. """ indices = [] while scores.numel() > 0: max_idx = torch.argmax(scores) indices.append(max_idx.item()) keep_mask = compute_iou_matrix(boxes[max_idx:max_idx+1], boxes)[0] <= thresh weights = torch.exp(-(compute_iou_matrix( boxes[max_idx:max_idx+1], boxes, type=iou_type) ** 2)/sigma) scores *= weights * keep_mask.float() mask = scores >= thresh boxes = boxes[mask] scores = scores[mask] return torch.tensor(indices).long() def compute_iou_matrix(box_a, box_b, type="iou"): """Compute pairwise IoUs between two sets of bounding boxes.""" area_a = (box_a[:, 2]-box_a[:, 0])*(box_a[:, 3]-box_a[:, 1]) area_b = (box_b[:, 2]-box_b[:, 0])*(box_b[:, 3]-box_b[:, 1]) inter_xmin = torch.max(box_a[:, None, 0], box_b[:, 0]) inter_ymin = torch.max(box_a[:, None, 1], box_b[:, 1]) inter_xmax = torch.min(box_a[:, None, 2], box_b[:, 2]) inter_ymax = torch.min(box_a[:, None, 3], box_b[:, 3]) w_inter = torch.clamp(inter_xmax-inter_xmin, min=0.) h_inter = torch.clamp(inter_ymax-inter_ymin, min=0.) intersection = w_inter*h_inter union = area_a[:,None]+area_b-intersection if type=="iou": ious = intersection / union elif type=="giou": # Generalized Intersection over Union enclosing_box = ( torch.min(box_a[:, None, :2], box_b[:,:2]), torch.max(box_a[:, None, 2:], box_b[:,2:]) ) c_area = ((enclosing_box[1][:,:,0]-enclosing_box[0][:, :, 0])* (enclosing_box[1][:,:,1]-enclosing_box[0][:, :, 1])) giou_term = (c_area - union)/(union+c_area) ious = ious-giou_term elif type=="diou": # Distance-IoU Loss center_dist_sqrd = ((box_a[:, None, 0]+box_a[:, None, 2])/2-(box_b[:, 0]+box_b[:, 2])/2)**2 \ +((box_a[:, None, 1]+box_a[:, None, 3])/2-(box_b[:, 1]+box_b[:, 3])/2)**2 diag_enclose_sqrd = ((enclosing_box[1][:,:,0]-enclosing_box[0][:, :, 0])**2+ (enclosing_box[1][:,:,1]-enclosing_box[0][:, :, 1])**2) diou_term=center_dist_sqrd/(diag_enclose_sqrd+1e-7) ious = ious-diou_term elif type=="ciou": # Complete IoU loss v=(torch.atan(((box_b[:, 2]-box_b[:, 0])/(box_b[:, 3]-box_b[:, 1])+1e-7))- torch.atan(((box_a[:, None, 2]-box_a[:, None, 0])/ (box_a[:, None, 3]-box_a[:, None, 1])))).pow_(2)*(4/math.pi**2) alpha=v/(ious+(1-ious)*v) ciou_term=alpha*v ious = ious-ciou_term-diou_term elif type=="eiou": # Enhanced IoU e_w=torch.abs((box_a[:, None, 2]-box_a[:, None, 0])-\ (box_b[:, 2]-box_b[:, 0])) e_h=torch.abs((box_a[:, None, 3]-box_a[:, None, 1])-\ (box_b[:, 3]-box_b[:, 1])) eiou_term=e_w/e_h ious = ious-eiou_term elif type=="siou": # Symmetric IoU s_w=torch.abs((box_a[:, None, 2]+box_a[:, None, 0])-(box_b[:, 2]+box_b[:, 0]))/2 s_h=torch.abs((box_a[:, None, 3]+box_a[:, None, 1])-(box_b[:, 3]+box_b[:, 1]))/2 siou_term=s_w+s_h ious = ious-siou_term else: raise ValueError(f'Unknown IoU type {type}') return ious.squeeze_() ``` 此段代码展示了如何定义一个支持多类IOU计算方式的`soft_nms_with_iou_types()` 函数,并提供了相应的辅助函数 `compute_iou_matrix()` 来完成具体的IOU运算逻辑。用户可以根据实际需求选择合适的参数组合来进行实验测试。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

鱼弦

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值