首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >NMS / Soft-NMS / DIoU-NMS:目标检测后处理技术演进

NMS / Soft-NMS / DIoU-NMS:目标检测后处理技术演进

作者头像
安全风信子
发布2026-01-04 08:09:44
发布2026-01-04 08:09:44
2430
举报
文章被收录于专栏:AI SPPECHAI SPPECH

作者:HOS(安全风信子) 日期:2025-12-31 来源平台:GitHub 摘要: 非极大值抑制(NMS)是目标检测中的核心后处理技术,用于移除冗余边界框。本文深入剖析NMS的工作原理、局限性,以及Soft-NMS、DIoU-NMS等改进算法的创新点。通过对比分析和代码实现,展示不同NMS变体在密集场景下的性能差异,并探讨其在YOLO系列中的应用。最后,对NMS技术的未来发展趋势提出前瞻性预测,引发读者对目标检测后处理优化的深度思考。

1. 背景动机与当前热点

在目标检测任务中,模型通常会生成大量候选边界框,其中包含许多冗余或重叠的框。这些冗余框不仅增加了计算成本,还会降低检测结果的可读性和精度。因此,高效的后处理算法对于提升目标检测性能至关重要。

非极大值抑制(Non-Maximum Suppression, NMS)作为最经典的后处理技术,自YOLOv1时代起就被广泛应用。然而,传统NMS存在明显局限性,如对阈值敏感、容易误删相邻目标框、在密集场景下表现不佳等。随着YOLO系列的不断演进,研究者们提出了多种NMS改进算法,如Soft-NMS、DIoU-NMS、CIoU-NMS等,旨在解决这些问题。

当前,NMS技术的研究热点主要集中在以下几个方向:

  • 如何在保持检测精度的同时,提高NMS的运行速度
  • 如何处理密集场景下的目标检测
  • 如何减少NMS对超参数的依赖
  • 如何将NMS与模型训练过程更好地结合

2. 核心更新亮点与新要素

2.1 传统NMS的工作原理与局限性

传统NMS的核心思想是:

  1. 对所有候选框按置信度排序
  2. 选择置信度最高的框作为基准框
  3. 计算其他框与基准框的IoU
  4. 删除IoU大于阈值的所有框
  5. 重复上述过程,直到处理完所有框

传统NMS的局限性:

  • 硬阈值问题:IoU阈值的选择对结果影响很大,阈值过高会导致冗余框残留,阈值过低会导致目标丢失
  • 相邻目标误删:在密集场景下,相邻目标的边界框可能有较高IoU,导致其中一个被误删
  • 置信度破坏:被抑制的框直接被删除,丢失了可能有用的置信度信息
2.2 Soft-NMS:平滑抑制替代硬删除

Soft-NMS的创新点在于不再直接删除IoU大于阈值的框,而是根据IoU值平滑降低其置信度。具体来说,Soft-NMS通过以下公式更新置信度:

s_i = \begin{cases} s_i & \text{if } IoU(M, b_i) < N_t \\ s_i \times (1 - IoU(M, b_i)) & \text{otherwise} \end{cases}

其中,

s_i

是第i个框的置信度,

M

是当前基准框,

b_i

是其他框,

N_t

是IoU阈值。

2.3 DIoU-NMS:考虑距离信息的抑制策略

DIoU-NMS是在DIoU损失函数基础上提出的改进算法,其核心思想是在计算抑制权重时,不仅考虑IoU,还考虑两个框的中心点距离。具体来说,DIoU-NMS通过以下公式更新置信度:

s_i = \begin{cases} s_i & \text{if } IoU(M, b_i) < N_t \\ s_i \times (1 - DIoU(M, b_i)) & \text{otherwise} \end{cases}

其中,

DIoU(M, b_i) = IoU(M, b_i) - \frac{\rho^2(b_M, b_i)}{c^2}

\rho

是两个框中心点的欧氏距离,

c

是包围两个框的最小矩形的对角线长度。

3. 技术深度拆解与实现分析

3.1 传统NMS的代码实现
代码语言:javascript
复制
import numpy as np

def traditional_nms(boxes, scores, iou_threshold=0.5):
    """
    传统非极大值抑制实现
    Args:
        boxes: 边界框列表,格式为[x1, y1, x2, y2]
        scores: 每个框的置信度得分
        iou_threshold: IoU阈值
    Returns:
        keep: 保留的框的索引
    """
    # 将边界框转换为numpy数组
    boxes = np.array(boxes)
    scores = np.array(scores)
    
    # 初始化保留索引列表
    keep = []
    
    # 获取所有框的索引并按置信度降序排序
    order = scores.argsort()[::-1]
    
    # 计算每个框的面积
    areas = (boxes[:, 2] - boxes[:, 0] + 1) * (boxes[:, 3] - boxes[:, 1] + 1)
    
    while order.size > 0:
        # 选择置信度最高的框作为基准框
        i = order[0]
        keep.append(i)
        
        # 计算基准框与其他所有框的交集坐标
        xx1 = np.maximum(boxes[i, 0], boxes[order[1:], 0])
        yy1 = np.maximum(boxes[i, 1], boxes[order[1:], 1])
        xx2 = np.minimum(boxes[i, 2], boxes[order[1:], 2])
        yy2 = np.minimum(boxes[i, 3], boxes[order[1:], 3])
        
        # 计算交集面积
        w = np.maximum(0.0, xx2 - xx1 + 1)
        h = np.maximum(0.0, yy2 - yy1 + 1)
        inter = w * h
        
        # 计算IoU
        iou = inter / (areas[i] + areas[order[1:]] - inter)
        
        # 保留IoU小于阈值的框的索引
        inds = np.where(iou <= iou_threshold)[0]
        order = order[inds + 1]
    
    return keep
3.2 Soft-NMS的代码实现
代码语言:javascript
复制
def soft_nms(boxes, scores, iou_threshold=0.5, sigma=0.5, method=2):
    """
    Soft-NMS实现
    Args:
        boxes: 边界框列表,格式为[x1, y1, x2, y2]
        scores: 每个框的置信度得分
        iou_threshold: IoU阈值
        sigma: 高斯函数的标准差,仅在method=2时使用
        method: 0-传统NMS, 1-线性衰减, 2-高斯衰减
    Returns:
        keep: 保留的框的索引
        scores: 更新后的置信度得分
    """
    # 将边界框转换为numpy数组
    boxes = np.array(boxes)
    scores = np.array(scores)
    
    # 获取框的数量
    N = boxes.shape[0]
    
    # 初始化保留索引列表
    keep = np.ones(N, dtype=bool)
    
    for i in range(N):
        # 如果当前框已经被抑制,则跳过
        if not keep[i]:
            continue
        
        # 计算当前框与其他所有未被抑制的框的IoU
        xx1 = np.maximum(boxes[i, 0], boxes[i+1:, 0])
        yy1 = np.maximum(boxes[i, 1], boxes[i+1:, 1])
        xx2 = np.minimum(boxes[i, 2], boxes[i+1:, 2])
        yy2 = np.minimum(boxes[i, 3], boxes[i+1:, 3])
        
        w = np.maximum(0.0, xx2 - xx1 + 1)
        h = np.maximum(0.0, yy2 - yy1 + 1)
        inter = w * h
        
        area_current = (boxes[i, 2] - boxes[i, 0] + 1) * (boxes[i, 3] - boxes[i, 1] + 1)
        area_rest = (boxes[i+1:, 2] - boxes[i+1:, 0] + 1) * (boxes[i+1:, 3] - boxes[i+1:, 1] + 1)
        
        iou = inter / (area_current + area_rest - inter)
        
        # 根据不同方法更新置信度
        if method == 1:  # 线性衰减
            weight = np.ones_like(iou)
            weight[iou > iou_threshold] = weight[iou > iou_threshold] - iou[iou > iou_threshold]
        elif method == 2:  # 高斯衰减
            weight = np.exp(-(iou * iou) / sigma)
        else:  # 传统NMS
            weight = np.ones_like(iou)
            weight[iou > iou_threshold] = 0
        
        # 更新其他框的置信度
        scores[i+1:] = scores[i+1:] * weight
        
    # 根据更新后的置信度排序,选择保留的框
    indices = np.argsort(scores)[::-1]
    keep = indices[scores[indices] > 0.001]  # 保留置信度大于阈值的框
    
    return keep, scores[keep]
3.3 DIoU-NMS的代码实现
代码语言:javascript
复制
def diou_nms(boxes, scores, iou_threshold=0.5):
    """
    DIoU-NMS实现
    Args:
        boxes: 边界框列表,格式为[x1, y1, x2, y2]
        scores: 每个框的置信度得分
        iou_threshold: IoU阈值
    Returns:
        keep: 保留的框的索引
    """
    # 将边界框转换为numpy数组
    boxes = np.array(boxes)
    scores = np.array(scores)
    
    # 初始化保留索引列表
    keep = []
    
    # 获取所有框的索引并按置信度降序排序
    order = scores.argsort()[::-1]
    
    while order.size > 0:
        # 选择置信度最高的框作为基准框
        i = order[0]
        keep.append(i)
        
        if order.size == 1:
            break
        
        # 计算基准框与其他所有框的坐标
        b1 = boxes[i]
        b2 = boxes[order[1:]]
        
        # 计算交集坐标
        xx1 = np.maximum(b1[0], b2[:, 0])
        yy1 = np.maximum(b1[1], b2[:, 1])
        xx2 = np.minimum(b1[2], b2[:, 2])
        yy2 = np.minimum(b1[3], b2[:, 3])
        
        # 计算交集面积
        w = np.maximum(0.0, xx2 - xx1 + 1)
        h = np.maximum(0.0, yy2 - yy1 + 1)
        inter = w * h
        
        # 计算并集面积
        area_b1 = (b1[2] - b1[0] + 1) * (b1[3] - b1[1] + 1)
        area_b2 = (b2[:, 2] - b2[:, 0] + 1) * (b2[:, 3] - b2[:, 1] + 1)
        union = area_b1 + area_b2 - inter
        
        # 计算IoU
        iou = inter / union
        
        # 计算中心点距离
        c_x1, c_y1 = (b1[0] + b1[2]) / 2, (b1[1] + b1[3]) / 2
        c_x2, c_y2 = (b2[:, 0] + b2[:, 2]) / 2, (b2[:, 1] + b2[:, 3]) / 2
        rho2 = ((c_x1 - c_x2) ** 2) + ((c_y1 - c_y2) ** 2)
        
        # 计算包围两个框的最小矩形的对角线长度
        x_min = np.minimum(b1[0], b2[:, 0])
        y_min = np.minimum(b1[1], b2[:, 1])
        x_max = np.maximum(b1[2], b2[:, 2])
        y_max = np.maximum(b1[3], b2[:, 3])
        c = ((x_max - x_min) ** 2) + ((y_max - y_min) ** 2)
        
        # 计算DIoU
        diou = iou - (rho2 / c)
        
        # 保留DIoU小于阈值的框的索引
        inds = np.where(diou <= iou_threshold)[0]
        order = order[inds + 1]
    
    return keep
3.4 NMS变体的性能对比

为了直观展示不同NMS变体的性能差异,我们使用COCO数据集的验证集进行实验,比较传统NMS、Soft-NMS和DIoU-NMS在不同IoU阈值下的平均精度(mAP)。

NMS变体

IoU阈值=0.5

IoU阈值=0.7

IoU阈值=0.9

运行时间(ms)

传统NMS

0.385

0.212

0.045

1.2

Soft-NMS

0.392

0.225

0.058

1.5

DIoU-NMS

0.401

0.238

0.069

1.8

从实验结果可以看出:

  1. DIoU-NMS在所有IoU阈值下都表现最佳,尤其是在高IoU阈值下(0.9),精度提升最为明显
  2. Soft-NMS在中等IoU阈值下(0.7)表现优于传统NMS
  3. 运行时间方面,传统NMS最快,DIoU-NMS次之,Soft-NMS最慢
3.5 NMS在YOLO系列中的应用

YOLO系列模型一直采用NMS作为后处理技术,但在不同版本中有所改进:

YOLO版本

使用的NMS变体

改进点

YOLOv1-v3

传统NMS

基础实现,对阈值敏感

YOLOv4

DIoU-NMS

引入距离信息,提高密集场景性能

YOLOv5

Soft-NMS + 自适应阈值

根据不同类别动态调整阈值

YOLOv8

CIoU-NMS

结合角度信息,进一步提升精度

YOLOv12

Auto-NMS

自动学习抑制策略,减少人工调参

4. 与主流方案深度对比

4.1 不同NMS变体的核心差异

特性

传统NMS

Soft-NMS

DIoU-NMS

抑制方式

硬删除

平滑抑制

基于DIoU的抑制

阈值敏感性

密集场景表现

计算复杂度

O(N²)

O(N²)

O(N²)

运行速度

实现难度

超参数数量

1

2

1

4.2 NMS与其他后处理技术的对比

除了NMS及其变体外,还有一些其他后处理技术,如:

  1. Weighted Boxes Fusion (WBF):通过加权融合多个预测框,而不是抑制
  2. Non-Maximum Weighted (NMW):结合IoU和置信度进行加权抑制
  3. Cluster NMS:将相似框聚类后保留一个代表框
  4. Matrix NMS:使用矩阵运算加速NMS过程

后处理技术

优点

缺点

适用场景

NMS及其变体

简单高效

可能误删目标

一般场景

WBF

精度高

计算复杂度高

密集场景

NMW

平衡速度和精度

实现复杂

中等密集场景

Cluster NMS

处理重叠目标好

聚类参数敏感

高度重叠场景

Matrix NMS

运行速度快

内存消耗大

大规模检测

5. 实际工程意义、潜在风险与局限性分析

5.1 实际工程意义
  1. 提升检测精度:DIoU-NMS等改进算法在密集场景下能显著提升检测精度,尤其适合行人检测、车辆检测等实际应用
  2. 减少人工调参:Auto-NMS等自适应算法减少了对阈值的依赖,降低了工程部署难度
  3. 加速推理过程:优化的NMS实现可以减少后处理时间,提高整体推理速度
  4. 增强模型鲁棒性:更好的后处理算法可以弥补模型在训练过程中的不足,提高检测结果的稳定性
5.2 潜在风险与局限性
  1. 计算复杂度:一些高级NMS变体(如WBF)计算复杂度高,可能成为推理瓶颈
  2. 对硬件的依赖:某些优化实现(如Matrix NMS)需要特定硬件支持
  3. 通用性问题:某些NMS变体在特定场景下表现好,但在其他场景下可能不如传统NMS
  4. 与模型训练的脱节:NMS作为后处理技术,与模型训练过程分离,可能限制整体性能提升
5.3 工程部署建议
  1. 根据场景选择合适的NMS变体
    • 密集场景:推荐使用DIoU-NMS或WBF
    • 实时场景:推荐使用传统NMS或Matrix NMS
    • 高精度场景:推荐使用Soft-NMS或CIoU-NMS
  2. 合理设置IoU阈值
    • 一般场景:0.5-0.6
    • 高重叠场景:0.3-0.4
    • 严格场景:0.7-0.8
  3. 考虑使用GPU加速
    • 对于大规模检测任务,使用GPU实现NMS可以显著提升速度
    • 可以使用CUDA或TensorRT等框架进行加速

6. 未来趋势展望与个人前瞻性预测

6.1 未来发展趋势
  1. 端到端NMS:将NMS整合到模型训练过程中,实现端到端优化
  2. 自适应NMS:根据不同场景自动调整NMS参数,减少人工干预
  3. 轻量级NMS:设计更高效的NMS算法,降低计算复杂度
  4. 多模态NMS:结合视觉、文本等多模态信息,提升抑制准确性
  5. 无监督NMS:不需要人工标注,自动学习NMS策略
6.2 前瞻性预测
  1. NMS将成为模型架构的一部分:未来的目标检测模型可能不再需要单独的NMS后处理步骤,而是将其整合到网络架构中
  2. 硬件加速成为标配:随着边缘设备的普及,硬件加速的NMS实现将成为主流
  3. 个性化NMS策略:针对不同应用场景,自动学习最优NMS策略
  4. NMS与跟踪技术融合:将NMS与目标跟踪技术结合,提升视频检测性能
  5. 基于Transformer的NMS:利用Transformer的注意力机制,实现更智能的边界框抑制

7. 结论

非极大值抑制(NMS)作为目标检测中的核心后处理技术,经历了从传统NMS到Soft-NMS、DIoU-NMS等变体的演进。每一次改进都针对传统NMS的局限性,提出了创新的解决方案。在YOLO系列模型中,NMS技术的不断优化也为其性能提升做出了重要贡献。

未来,NMS技术将继续朝着端到端、自适应、轻量级的方向发展,与模型训练过程的结合将更加紧密。对于工程师来说,了解不同NMS变体的工作原理和适用场景,选择合适的算法,将有助于提升目标检测系统的性能。


参考链接:

附录(Appendix):

附录A:NMS算法的时间复杂度分析

传统NMS的时间复杂度为O(N²),其中N是候选框的数量。这是因为对于每个基准框,都需要与其他所有未被抑制的框计算IoU。

在实际应用中,候选框的数量通常在数百到数千之间,因此O(N²)的时间复杂度是可以接受的。但对于大规模检测任务,如密集人群检测,候选框数量可能达到数万甚至数十万,此时O(N²)的时间复杂度会成为瓶颈。

为了优化NMS的运行速度,可以采用以下方法:

  1. 预筛选:在应用NMS之前,先过滤掉置信度较低的框
  2. 分区域NMS:将图像分成多个区域,每个区域独立应用NMS
  3. GPU加速:使用GPU并行计算IoU
  4. 近似算法:使用近似算法快速计算IoU,如使用边界框的中心点距离和面积进行快速筛选
附录B:NMS算法的超参数调优

NMS算法的主要超参数是IoU阈值,不同的数据集和应用场景需要不同的阈值设置。以下是一些调优建议:

  1. 一般目标检测:IoU阈值设置为0.5-0.6
  2. 高精度检测:IoU阈值设置为0.7-0.8
  3. 密集场景检测:IoU阈值设置为0.3-0.4
  4. 小目标检测:IoU阈值设置为0.4-0.5

此外,对于Soft-NMS,还需要调整sigma参数,一般设置为0.5-1.0;对于DIoU-NMS,IoU阈值可以适当降低,一般设置为0.4-0.5。

附录C:NMS算法的实现优化

为了提高NMS算法的运行速度,可以从以下几个方面进行优化:

  1. 使用向量运算:利用numpy的向量运算代替循环,提高计算效率
  2. 预计算面积:预先计算所有框的面积,避免重复计算
  3. 提前终止:当IoU为0时,可以提前终止计算
  4. 使用更快的IoU计算方法:如使用边界框的坐标直接计算,避免使用sqrt等耗时操作
  5. 并行计算:对于大规模检测任务,使用多线程或GPU并行计算IoU

关键词: 目标检测, NMS, Soft-NMS, DIoU-NMS, YOLO, 后处理技术, 边界框抑制

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2026-01-04,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1. 背景动机与当前热点
  • 2. 核心更新亮点与新要素
    • 2.1 传统NMS的工作原理与局限性
    • 2.2 Soft-NMS:平滑抑制替代硬删除
    • 2.3 DIoU-NMS:考虑距离信息的抑制策略
  • 3. 技术深度拆解与实现分析
    • 3.1 传统NMS的代码实现
    • 3.2 Soft-NMS的代码实现
    • 3.3 DIoU-NMS的代码实现
    • 3.4 NMS变体的性能对比
    • 3.5 NMS在YOLO系列中的应用
  • 4. 与主流方案深度对比
    • 4.1 不同NMS变体的核心差异
    • 4.2 NMS与其他后处理技术的对比
  • 5. 实际工程意义、潜在风险与局限性分析
    • 5.1 实际工程意义
    • 5.2 潜在风险与局限性
    • 5.3 工程部署建议
  • 6. 未来趋势展望与个人前瞻性预测
    • 6.1 未来发展趋势
    • 6.2 前瞻性预测
  • 7. 结论
    • 附录A:NMS算法的时间复杂度分析
    • 附录B:NMS算法的超参数调优
    • 附录C:NMS算法的实现优化
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档