PaddlePaddle深度学习项目中的非极大值抑制(NMS)技术详解

PaddlePaddle深度学习项目中的非极大值抑制(NMS)技术详解

awesome-DeepLearning 深度学习入门课、资深课、特色课、学术案例、产业实践案例、深度学习知识百科及面试题库The course, case and knowledge of Deep Learning and AI awesome-DeepLearning 项目地址: https://gitcode.com/gh_mirrors/aw/awesome-DeepLearning

目标检测中的冗余框问题

在目标检测任务中,无论使用何种方法生成候选区域,都会面临一个共同的问题:模型可能会对同一个目标进行多次检测。这会导致每个物体周围出现多个重叠的预测框,严重影响检测结果的准确性。这种现象在基于深度学习的目标检测算法中尤为常见。

非极大值抑制(NMS)的基本原理

非极大值抑制(Non-Maximum Suppression, NMS)是一种后处理技术,用于消除冗余的预测框,保留最有可能代表真实目标的预测结果。其核心思想是:

  1. 对于每个检测到的物体,选择置信度(得分)最高的预测框作为候选
  2. 计算该候选框与其他所有预测框的交并比(IoU)
  3. 删除那些与候选框IoU超过预设阈值的预测框
  4. 对剩余的预测框重复上述过程,直到处理完所有预测框

NMS的具体实现步骤

让我们通过一个具体例子来理解NMS的工作流程:

  1. 输入准备:假设模型对一张图片进行预测,输出了11个预测框及其对应的置信度得分
  2. 得分排序:首先根据置信度得分对所有预测框进行降序排序
  3. 迭代处理
    • 选择得分最高的预测框作为候选
    • 计算该候选框与剩余所有预测框的IoU
    • 删除IoU超过阈值(通常设为0.5)的预测框
    • 对剩余的预测框重复上述过程

代码实现解析

在PaddlePaddle深度学习框架中,NMS的实现通常包含以下几个关键部分:

  1. IoU计算:计算两个矩形框的交并比
def box_iou_xyxy(box1, box2):
    # 计算两个矩形框的IoU
    x1min, y1min, x1max, y1max = box1[0], box1[1], box1[2], box1[3]
    x2min, y2min, x2max, y2max = box2[0], box2[1], box2[2], box2[3]
    
    # 计算交集区域
    xmin = np.maximum(x1min, x2min)
    ymin = np.maximum(y1min, y2min)
    xmax = np.minimum(x1max, x2max)
    ymax = np.minimum(y1max, y2max)
    
    # 计算交集面积
    intersection = np.maximum(xmax - xmin, 0.) * np.maximum(ymax - ymin, 0.)
    
    # 计算并集面积
    area1 = (x1max - x1min) * (y1max - y1min)
    area2 = (x2max - x2min) * (y2max - y2min)
    union = area1 + area2 - intersection
    
    # 计算IoU
    iou = intersection / union
    return iou
  1. 单类别NMS实现
def nms(bboxes, scores, score_thresh, nms_thresh):
    """
    非极大值抑制实现
    :param bboxes: 预测框列表
    :param scores: 对应的置信度得分
    :param score_thresh: 得分阈值,低于此值的预测框将被忽略
    :param nms_thresh: IoU阈值,高于此值的预测框将被抑制
    :return: 保留的预测框索引
    """
    inds = np.argsort(scores)
    inds = inds[::-1]  # 降序排列
    keep_inds = []
    
    while len(inds) > 0:
        cur_ind = inds[0]
        cur_score = scores[cur_ind]
        
        # 如果当前得分低于阈值,直接跳出循环
        if cur_score < score_thresh:
            break
            
        keep = True
        for ind in keep_inds:
            current_box = bboxes[cur_ind]
            remain_box = bboxes[ind]
            iou = box_iou_xyxy(current_box, remain_box)
            if iou > nms_thresh:
                keep = False
                break
                
        if keep:
            keep_inds.append(cur_ind)
        inds = inds[1:]
        
    return np.array(keep_inds)
  1. 多类别NMS实现:当数据集中包含多个类别的物体时,需要对每个类别分别进行NMS处理
def multiclass_nms(bboxes, scores, score_thresh=0.01, nms_thresh=0.45, 
                   pre_nms_topk=1000, pos_nms_topk=100):
    """
    多类别非极大值抑制
    :param bboxes: 预测框列表(批量)
    :param scores: 对应的置信度得分(批量)
    :param score_thresh: 得分阈值
    :param nms_thresh: IoU阈值
    :param pre_nms_topk: NMS前保留的预测框数量
    :param pos_nms_topk: NMS后保留的预测框数量
    :return: 保留的预测结果
    """
    batch_size = bboxes.shape[0]
    class_num = scores.shape[1]
    rets = []
    
    for i in range(batch_size):
        bboxes_i = bboxes[i]
        scores_i = scores[i]
        ret = []
        
        # 对每个类别分别进行NMS
        for c in range(class_num):
            scores_i_c = scores_i[c]
            keep_inds = nms(bboxes_i, scores_i_c, score_thresh, nms_thresh)
            
            if len(keep_inds) < 1:
                continue
                
            keep_bboxes = bboxes_i[keep_inds]
            keep_scores = scores_i_c[keep_inds]
            keep_results = np.zeros([keep_scores.shape[0], 6])
            keep_results[:, 0] = c  # 类别ID
            keep_results[:, 1] = keep_scores[:]  # 置信度得分
            keep_results[:, 2:6] = keep_bboxes[:, :]  # 框坐标
            ret.append(keep_results)
            
        if len(ret) < 1:
            rets.append(ret)
            continue
            
        ret_i = np.concatenate(ret, axis=0)
        scores_i = ret_i[:, 1]
        
        # 限制最终保留的预测框数量
        if len(scores_i) > pos_nms_topk:
            inds = np.argsort(scores_i)[::-1]
            inds = inds[:pos_nms_topk]
            ret_i = ret_i[inds]

        rets.append(ret_i)
        
    return rets

NMS的优化与变种

在实际应用中,标准的NMS算法可能存在一些局限性,因此研究者们提出了多种改进版本:

  1. Soft-NMS:不是直接删除IoU超过阈值的预测框,而是降低它们的得分
  2. IoU-Net:通过学习预测框的定位质量来改进NMS过程
  3. Adaptive NMS:根据目标密度动态调整NMS阈值
  4. Cluster-NMS:通过矩阵运算加速NMS过程

实际应用中的注意事项

  1. 阈值选择:IoU阈值的选择对结果影响很大,通常设置在0.3-0.7之间
  2. 性能优化:对于大规模检测任务,NMS可能成为性能瓶颈,需要考虑优化实现
  3. 多类别处理:对于多类别检测,应该对每个类别分别进行NMS
  4. 边界情况:需要考虑空输入、单个预测框等边界情况的处理

总结

非极大值抑制是目标检测任务中不可或缺的后处理步骤,它能有效消除冗余的预测框,提高检测结果的准确性。在PaddlePaddle深度学习框架中,NMS的实现既考虑了单类别场景,也支持多类别检测任务。理解NMS的原理和实现细节,对于开发和优化目标检测模型具有重要意义。

awesome-DeepLearning 深度学习入门课、资深课、特色课、学术案例、产业实践案例、深度学习知识百科及面试题库The course, case and knowledge of Deep Learning and AI awesome-DeepLearning 项目地址: https://gitcode.com/gh_mirrors/aw/awesome-DeepLearning

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

羿丹花Zea

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

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

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

打赏作者

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

抵扣说明:

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

余额充值