当前位置: 首页 > 后端技术 > Python

非极大值抑制HardNMS和Soft-NMS的两种方式

时间:2023-03-26 17:16:55 Python

非极大值抑制算法NMS非极大值抑制(Non-MaximumSuppression,NMS)是目标检测任务中重要的后处理步骤。只要是Anchor-based的检测方式,都需要经过NMS的后处理。一张图片被目标检测到后,会得到大量重复的anchors,NMS就是去除这些重复的anchors。如下图,左边是NMS处理前,右边是NMS处理后。NMS主要有两种处理方式,分别是HardNMS和SoftNMS,下面分别介绍。HardNMSHardNMS的步骤是根据anchor的评分从高到低对anchor进行排序。取出anchor列表中的第一个anchor(假设有100个anchor),计算剩下的所有anchor(99个anchor)和该anchor的iou,将该anchor添加到一个列表中。放弃iou大于iou阈值的anchor(认为是检测同一个物体)重复2和3,直到anchor列表为空代码如下defbbox_iou(anchors1,anchors2):lt=np.minimum(anchors1[:,np.newaxis,:2],anchors2[:,:2])rb=np.maximum(anchors2[:,np.newaxis,2:],anchors2[:,2:])inter_area=np.prod(rb-lt,axis=1)*np.all(rb>lt,axis=1)area1=np.prod(anchors1[2:]-anchors1[:2],axis=1)area2=np.prod(anchors2[2:]-anchors2[:2],axis=1)returninter_area/(area1[:,np.newaxis]+area2-inter_area)defhard_nms(anchors,scores,iou_thresh=0.7,condidates_num=200):“”"Params:anchors(numpy.array):nms之前的检测anchors,withshape(N,4)scores(numpy.array):anchorscoresbeforenms,withshape(N,)iou_thresh(float):iouthresholdReturn:keeps(num.array):keepedanchorindexes"""#ifanchors.size==0:return#按分数排序idxs=scores.argsort(0)[::-1]keeps=[]whilelen(idxs)>0:current=idxs[0]keep.append(current)#ifkeepnumequalwithcondidates_numoronlyananchorleftiflen(idxs)==1orlen(keeps)==condidates_num:打破idxs=idxs[1:]iou=bbox_iou(anchors[current][np.newaxis,:],anchors[idxs]).flaten()mask=ious<=iou_threshidxs=idxs[mask]返回np.array(keeps)SoftNMS通常我们选择HardNMS作为目标检测的后处理,但是在物体密集的情况下,HardNMS会丢弃一些置信度高的anchor周围的anchor。比如下图中的两匹马,红框的置信度最高,会被保留。假设HardNMS的iou阈值为0.5,下面红框和绿框的iou有可能大于阈值。这时,绿框将被丢弃。但在我们看来,绿框和红框其实是在检测两匹不同的马,绿框不应该被丢弃。所以这就是HardNMS的问题。有没有办法解决这个问题?首先,我们可能会想到修改iou阈值来缓解这个问题。欠条阈值应该设置多少?如果设置的高,会出现误检;如果设置低,召回率会降低,所以这是一个糟糕的选择。而SoftNMS正是为了解决这个问题。SoftNMS的流程可以用下图表示。从上图可以看出,NMS(HardNMS)和SoftNMS唯一的区别是对大于阈值的iou对应的anchor的处理方式。在HardNMS中,直接丢弃iou大于阈值的anchor$$s_i=\begin{cases}&s_i,\quadIou(M,b_i)0:#获取最大分数索引max_idx=np.argmax(scores)keep.append(max_idx)#ifkeepednum如果len(scores)==1或len(keeps)==condidates_num等于condidates_num或只剩下一个锚:break#获取左边的分数索引mask=np.arange(len(scores))!=max_idxscores=scores[mask]#计算iouiou=bbox_iou(anchors[max_idx][np.newaxis,:],anchors[mask]).flaten()#重新赋值,scoresdecayscores=scores*np.exp(-ious*ious/sigma)scores=scores[scores>iou_thresh]returnnp.array(keeps)总结Soft-NMS是非最大抑制的广义版本。传统的NMS是具有不连续二进制加权的特例。从下图可以看出,在VOC和Coco数据上,SoftNMS优于HardNMS。在集合上有一定的提升,SoftNMS不会增加过多的计算量和超参数,推荐使用。参考NMS和soft-NMSImprovingObjectDetectionWithOneLineCode