YOLOv5改进 | NMS | 将NMS修改为soft-NMS【完整代码】

秋招面试专栏推荐 :深度学习算法工程师面试问题总结【百面算法工程师】——点击即可跳转


💡💡💡本专栏所有程序均经过测试,可成功执行💡💡💡


专栏目录: 《YOLOv5入门 + 改进涨点》专栏介绍 & 专栏目录 |目前已有80+篇内容,内含各种Head检测头、损失函数Loss、Backbone、Neck、NMS等创新点改进


本文给大家介绍的是Soft-NMS,Soft-NMS (Soft Non-Maximum Suppression) 是目标检测算法中用来筛选边界框的一个技术,它是对传统 NMS(Non-Maximum Suppression)的改进。文章在介绍主要的原理后,将手把手教学如何进行模块的代码添加和修改,并将修改后的完整代码放在文章的最后,方便大家一键运行,小白也可轻松上手实践。以帮助您更好地学习深度学习目标检测YOLO系列的挑战。 

专栏地址 YOLOv5改进+入门——持续更新各种有效涨点方法 点击即可跳转          

目录

1. 原理

2. NMS 和 soft- nms的对比

3. Soft-nms替换nms

4. 完整代码

5.进阶

6. 总结 


1. 原理

论文地址:Improving Object Detection With One Line of Code——点击即可跳转 

官方代码:官方代码仓库——点击即可跳转 

Soft-NMS 是一种改进的非极大值抑制 (NMS) 算法,用于目标检测任务中减少误检并提高平均精度。传统的 NMS 算法会将与当前最高得分框重叠程度超过阈值的框的得分置为 0,从而消除误检。然而,这种方法也容易导致漏检,因为一些实际存在的目标可能由于得分略低而被错误地抑制。 Soft-NMS 的主要原理是通过降低重叠框的得分,而不是将其完全抑制,来避免漏检。具体来说,Soft-NMS 根据框与最高得分框的重叠程度,将其得分按线性或高斯函数进行衰减。这样,重叠框仍然保留在检测结果中,但得分更低,从而降低了误检的可能性,同时避免了漏检。 Soft-NMS 的优势在于:

  • 减少漏检: 通过降低重叠框的得分,而不是将其完全抑制,Soft-NMS 能够保留一些实际存在的目标,从而提高检测的召回率。

  • 提高平均精度: Soft-NMS 能够在多个重叠阈值下提高平均精度,因为它避免了传统 NMS 在低阈值下漏检和高阈值下误检的问题。

  • 易于实现: Soft-NMS 的实现非常简单,只需修改传统 NMS 算法中的一行代码即可。

  • 无需额外训练: Soft-NMS 无需对模型进行额外的训练,可以直接应用于现有的目标检测模型。

Soft-NMS 的工作原理

Soft-NMS 的工作流程与传统的 NMS 类似,主要区别在于对重叠框的得分进行衰减,而不是将其置为 0。具体步骤如下:

  1. 排序: 将所有检测框按照得分进行排序。

  2. 选择最高得分框: 选择得分最高的检测框作为当前框。

  3. 更新重叠框的得分: 对于与当前框重叠程度超过阈值的检测框,将其得分按照线性或高斯函数进行衰减。

  4. 重复步骤 2-3: 重复选择得分最高的检测框并更新重叠框的得分,直到所有检测框都被处理完毕。

Soft-NMS 的参数

Soft-NMS 有两个主要参数:

  • 重叠阈值 (Nt): 与传统 NMS 中的重叠阈值相同,用于确定哪些框被认为是重叠框。

  • 衰减参数 (σ): 用于控制得分衰减的程度,σ 越大,衰减程度越大。

Soft-NMS 的应用

Soft-NMS 可以应用于任何基于 NMS 的目标检测模型,例如 Faster R-CNN、R-FCN 等。实验结果表明,Soft-NMS 能够在各种目标检测任务中提高平均精度,并减少漏检。

2. NMS 和 soft- nms的对比

特性NMS (Non-Maximum Suppression)Soft-NMS (Soft Non-Maximum Suppression)
抑制方式硬阈值抑制:直接删除重叠度高的框软抑制:逐渐降低重叠框的得分
边界框得分处理保留最高得分的框,删除其他根据重叠程度调整边界框得分
误杀问题容易误删正确的边界框减少误删,有助于保留正确的边界框
适应性对密集目标表现较差对密集和重叠目标更为鲁棒
算法复杂度较低略高,但仍然接近 NMS
检测精度在某些情况下可能精度下降提高了检测精度,尤其是在多目标密集场景中
通用性普遍使用,直接应用可以无缝替换传统 NMS,适配性强
使用场景适用于目标分布较分散的情况适用于目标分布密集或边界模糊的情况

3. Soft-nms替换nms

步骤一:

复制下面的代码,粘贴到\yolov5\utils\general.py的non_max_suppression函数上面【在1000行附近】

def nms_iou(box1, box2, GIoU=False, DIoU=False, CIoU=False, SIoU=False, EIou=False, eps=1e-7):
    # Returns Intersection over Union (IoU) of box1(1,4) to box2(n,4)

    b1_x1, b1_y1, b1_x2, b1_y2 = box1.chunk(4, -1)
    b2_x1, b2_y1, b2_x2, b2_y2 = box2.chunk(4, -1)
    w1, h1 = b1_x2 - b1_x1, (b1_y2 - b1_y1).clamp(eps)
    w2, h2 = b2_x2 - b2_x1, (b2_y2 - b2_y1).clamp(eps)

    # Intersection area
    inter = (b1_x2.minimum(b2_x2) - b1_x1.maximum(b2_x1)).clamp(0) * \
            (b1_y2.minimum(b2_y2) - b1_y1.maximum(b2_y1)).clamp(0)

    # Union Area
    union = w1 * h1 + w2 * h2 - inter + eps

    # IoU
    iou = inter / union
    if CIoU or DIoU or GIoU or EIou:
        cw = b1_x2.maximum(b2_x2) - b1_x1.minimum(b2_x1)  # convex (smallest enclosing box) width
        ch = b1_y2.maximum(b2_y2) - b1_y1.minimum(b2_y1)  # convex height
        if CIoU or DIoU or EIou:  # Distance or Complete IoU https://arxiv.org/abs/1911.08287v1
            c2 = cw ** 2 + ch ** 2 + eps  # convex diagonal squared
            rho2 = ((b2_x1 + b2_x2 - b1_x1 - b1_x2) ** 2 + (b2_y1 + b2_y2 - b1_y1 - b1_y2) ** 2) / 4  # center dist ** 2
            if CIoU:  # https://github.com/Zzh-tju/DIoU-SSD-pytorch/blob/master/utils/box/box_utils.py#L47
                v = (4 / math.pi ** 2) * (torch.atan(w2 / h2) - torch.atan(w1 / h1)).pow(2)
                with torch.no_grad():
                    alpha = v / (v - iou + (1 + eps))
                return iou - (rho2 / c2 + v * alpha)  # CIoU
            elif EIou:
                rho_w2 = ((b2_x2 - b2_x1) - (b1_x2 - b1_x1)) ** 2
                rho_h2 = ((b2_y2 - b2_y1) - (b1_y2 - b1_y1)) ** 2
                cw2 = cw ** 2 + eps
                ch2 = ch ** 2 + eps
                return iou - (rho2 / c2 + rho_w2 / cw2 + rho_h2 / ch2)
            return iou - rho2 / c2  # DIoU
        c_area = cw * ch + eps  # convex area
        return iou - (c_area - union) / c_area  # GIoU https://arxiv.org/pdf/1902.09630.pdf
    elif SIoU:
        # SIoU Loss https://arxiv.org/pdf/2205.12740.pdf
        s_cw = (b2_x1 + b2_x2 - b1_x1 - b1_x2) * 0.5 + eps
        s_ch = (b2_y1 + b2_y2 - b1_y1 - b1_y2) * 0.5 + eps
        sigma = torch.pow(s_cw ** 2 + s_ch ** 2, 0.5)
        sin_alpha_1 = torch.abs(s_cw) / sigma
        sin_alpha_2 = torch.abs(s_ch) / sigma
        threshold = pow(2, 0.5) / 2
        sin_alpha = torch.where(sin_alpha_1 > threshold, sin_alpha_2, sin_alpha_1)
        angle_cost = torch.cos(torch.arcsin(sin_alpha) * 2 - math.pi / 2)
        rho_x = (s_cw / cw) ** 2
        rho_y = (s_ch / ch) ** 2
        gamma = angle_cost - 2
        distance_cost = 2 - torch.exp(gamma * rho_x) - torch.exp(gamma * rho_y)
        omiga_w = torch.abs(w1 - w2) / torch.max(w1, w2)
        omiga_h = torch.abs(h1 - h2) / torch.max(h1, h2)
        shape_cost = torch.pow(1 - torch.exp(-1 * omiga_w), 4) + torch.pow(1 - torch.exp(-1 * omiga_h), 4)
        return iou - 0.5 * (distance_cost + shape_cost)
    return iou  # IoU


def soft_nms(bboxes, scores, iou_thresh=0.5, sigma=0.5, score_threshold=0.25):
    order = torch.arange(0, scores.size(0)).to(bboxes.device)
    keep = []

    while order.numel() > 1:
        if order.numel() == 1:
            keep.append(order[0])
            break
        else:
            i = order[0]
            keep.append(i)

        iou = nms_iou(bboxes[i], bboxes[order[1:]], CIoU=True).squeeze()

        idx = (iou > iou_thresh).nonzero().squeeze()
        if idx.numel() > 0:
            iou = iou[idx]
            newScores = torch.exp(-torch.pow(iou, 2) / sigma)
            scores[order[idx + 1]] *= newScores

        newOrder = (scores[order[1:]] > score_threshold).nonzero().squeeze()
        if newOrder.numel() == 0:
            break
        else:
            maxScoreIndex = torch.argmax(scores[order[newOrder + 1]])
            if maxScoreIndex != 0:
                newOrder[[0, maxScoreIndex],] = newOrder[[maxScoreIndex, 0],]
            order = order[newOrder + 1]

    return torch.LongTensor(keep)

步骤二:

将non_max_suppression函数中 i = torchvision.ops.nms(boxes, scores, iou_thres)  # NMS 这句代码替换为   i = soft_nms(boxes, scores, iou_thres)

i = torchvision.ops.nms(boxes, scores, iou_thres)  # NMS

替换为 

 i = soft_nms(boxes, scores, iou_thres)

4. 完整代码

https://pan.baidu.com/s/1XRLupL_qDsnyogbIzXzgPQ?pwd=hy91

 提取码: hy91 

5.进阶

可以结合损失函数或者卷积模块进行多重改进

YOLOv5改进 | 损失函数 | EIoU、SIoU、WIoU、DIoU、FocuSIoU等多种损失函数——点击即可跳转

6. 总结 

Soft-NMS 的主要原理是在进行边界框抑制时,不是直接删除与最高得分框重叠度(IoU)超过阈值的其他边界框,而是根据这些边界框与最高得分框的重叠程度逐渐降低它们的得分。具体来说,Soft-NMS 会对每个候选框根据其与最高得分框的 IoU 计算一个新的得分,该得分会随 IoU 的增加而衰减,而不是一刀切地将得分较高的框保留、将得分较低的框完全删除。通过这种方式,Soft-NMS 保留了更多潜在的正确边界框,尤其是在多个目标靠近或边界模糊的情况下,从而减少了误杀(删除正确边界框)的情况,最终提高了目标检测的整体精度和鲁棒性。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

kay_545

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

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

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

打赏作者

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

抵扣说明:

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

余额充值