Soft-NMS:Improving Object Detection With One Line of Code

发布于 2019-09-26 作者 风铃 418次 浏览 版块 前端

论文地址:https://arxiv.org/pdf/1704.04503.pdf

Github项目:https://github.com/bharatsingh430/soft-nms

论文摘要

非最大抑制(Non-maximum suppression, NMS)是物体检测流程中重要的组成部分。它首先基于物体检测分数产生检测框,分数最高的检测框M被选中,其他与被选中检测框有明显重叠的检测框被抑制。该过程被不断递归的应用于其余检测框。根据算法的设计,如果一个物体处于预设的重叠阈值之内,可能会导致检测不到该待检测物体。因此,我们提出了Soft-NMS算法,该连续函数对非最大检测框的检测分数进行衰减而非彻底移除。它仅需要对传统的NMS算法进行简单的改动且不增额外的参数。该Soft-NMS算法在标准数据集PASCAL VOC2007(较R-FCN和Faster-RCNN提升1.7%)和MS-COCO(较R-FCN提升1.3%,较Faster-RCNN提升1.1%)上均有提升。此外,Soft-NMS具有与传统NMS相同的算法复杂度,使用高效。Soft-NMS也不需要额外的训练,并易于实现,它可以轻松的被集成到任何物体检测流程中。

NMS处理流程

传统的NMS处理方法可以通过以下的分数重置函数(Rescoring Function)来表达:

在这个公式中, NMS采用了硬阈值来判断相邻检测框是否保留。但是,换一种方法,假设我们对一个与M高度重叠的检测框bi的检测分数进行衰减,而非全部抑制。如果检测框bi中包含不同于M中的物体,那么在检测阈值比较低的情况下,该物体并不会错过检测。但是,如果bi中并不包含任何物体,即使在衰减过后,bi的分数仍然较高,它还是会产生一个假阳性的结果。因此,在使用NMS做物体检测处理的时候,需要注意以下几点:

  • 相邻检测框的检测分数应该被降低,从而减少假阳性结果,但是,衰减后的分数仍然应该比明显的假阳性结果要高。
  • 通过较低的NMS重叠阈值来移除所有相邻检测框并不是最优解,并且很容易导致错过被检测物体,特别是在物体高度重叠的地方
  • 当NMS采用一个较高的重叠阈值时,平均准确率可能会相应降低。

Motivation

绝大部分目标检测方法,最后都要用到 NMS-非极大值抑制进行后处理。 通常的做法是将检测框按得分排序,然后保留得分最高的框,同时删除与该框重叠面积大于一定比例的其它框。

这种贪心式方法存在如下图所示的问题: 红色框和绿色框是当前的检测结果,二者的得分分别是0.95和0.80。如果按照传统的NMS进行处理,首先选中得分最高的红色框,然后绿色框就会因为与之重叠面积过大而被删掉。

另一方面,NMS的阈值也不太容易确定,设小了会出现下图的情况(绿色框因为和红色框重叠面积较大而被删掉),设置过高又容易增大误检。

float

思路:不要粗鲁地删除所有IOU大于阈值的框,而是降低其置信度。

Method

如下图:如文章题目而言,就是用一行代码来替换掉原来的NMS。按照下图整个处理一遍之后,指定一个置信度阈值,然后最后得分大于该阈值的检测框得以保留


原来的NMS可以描述如下:将IOU大于阈值的窗口的得分全部置为0。


文章的改进有两种形式,一种是线性加权的:


一种是高斯加权的:

float

分析上面的两种改进形式,思想都是:M为当前得分最高框,bi为待处理框,bi和M的IOU越大,bi的得分si就下降的越厉害。

值得注意的是,soft-NMS也是一种贪心算法,并不能保证找到全局最优的检测框分数重置。但是,soft-NMS算法是一种更加通用的非最大抑制算法,传统的NMS算法可以看做是它的一个采用不连续二值权重函数的特例。除了以上这两种分数重置函数,我们也可以考虑开发其他包含更多参数的分数重置函数,比如Gompertz函数等。但是它们在完成分数重置的过程中增加了额外的参数。

NMS代码:

%% NMS:non maximum suppression

function pick = nms(boxes,threshold,type)
% boxes: m x 5,表示有m个框,5列分别是[x1 y1 x2 y2 score]
% threshold: IOU阈值
% type:IOU阈值的定义类型

% 输入为空,则直接返回
if isempty(boxes)
  pick = [];
  return;
end

% 依次取出左上角和右下角坐标以及分类器得分(置信度)
x1 = boxes(:,1);
y1 = boxes(:,2);
x2 = boxes(:,3);
y2 = boxes(:,4);
s = boxes(:,5);

% 计算每一个框的面积
area = (x2-x1+1) .* (y2-y1+1);

%将得分升序排列
[vals, I] = sort(s);

%初始化
pick = s*0;
counter = 1;

% 循环直至所有框处理完成
while ~isempty(I)
    last = length(I); %当前剩余框的数量
    i = I(last);%选中最后一个,即得分最高的框
    pick(counter) = i;
    counter = counter + 1;  

    %计算相交面积
    xx1 = max(x1(i), x1(I(1:last-1)));
    yy1 = max(y1(i), y1(I(1:last-1)));
    xx2 = min(x2(i), x2(I(1:last-1)));
    yy2 = min(y2(i), y2(I(1:last-1)));  
    w = max(0.0, xx2-xx1+1);
    h = max(0.0, yy2-yy1+1); 
    inter = w.*h;

    %不同定义下的IOU
    if strcmp(type,'Min')
        %重叠面积与最小框面积的比值
        o = inter ./ min(area(i),area(I(1:last-1)));
    else
        %交集/并集
        o = inter ./ (area(i) + area(I(1:last-1)) - inter);
    end

    %保留所有重叠面积小于阈值的框,留作下次处理
    I = I(find(o<=threshold));
end
pick = pick(1:(counter-1));

end

Soft-NMS代码:

def cpu_soft_nms(np.ndarray[float, ndim=2] boxes, float sigma=0.5, float Nt=0.3, float threshold=0.001, unsigned int method=0):
cdef unsigned int N = boxes.shape[0]
cdef float iw, ih, box_area
cdef float ua
cdef int pos = 0
cdef float maxscore = 0
cdef int maxpos = 0
cdef float x1,x2,y1,y2,tx1,tx2,ty1,ty2,ts,area,weight,ov

for i in range(N):
    maxscore = boxes[i, 4]
    maxpos = i

    tx1 = boxes[i,0]
    ty1 = boxes[i,1]
    tx2 = boxes[i,2]
    ty2 = boxes[i,3]
    ts = boxes[i,4]

    pos = i + 1
# get max box
    while pos < N:
        if maxscore < boxes[pos, 4]:
            maxscore = boxes[pos, 4]
            maxpos = pos
        pos = pos + 1

# add max box as a detection 
    boxes[i,0] = boxes[maxpos,0]
    boxes[i,1] = boxes[maxpos,1]
    boxes[i,2] = boxes[maxpos,2]
    boxes[i,3] = boxes[maxpos,3]
    boxes[i,4] = boxes[maxpos,4]

# swap ith box with position of max box
    boxes[maxpos,0] = tx1
    boxes[maxpos,1] = ty1
    boxes[maxpos,2] = tx2
    boxes[maxpos,3] = ty2
    boxes[maxpos,4] = ts

    tx1 = boxes[i,0]
    ty1 = boxes[i,1]
    tx2 = boxes[i,2]
    ty2 = boxes[i,3]
    ts = boxes[i,4]

    pos = i + 1
# NMS iterations, note that N changes if detection boxes fall below threshold
    while pos < N:
        x1 = boxes[pos, 0]
        y1 = boxes[pos, 1]
        x2 = boxes[pos, 2]
        y2 = boxes[pos, 3]
        s = boxes[pos, 4]

        area = (x2 - x1 + 1) * (y2 - y1 + 1)
        iw = (min(tx2, x2) - max(tx1, x1) + 1)
        if iw > 0:
            ih = (min(ty2, y2) - max(ty1, y1) + 1)
            if ih > 0:
                ua = float((tx2 - tx1 + 1) * (ty2 - ty1 + 1) + area - iw * ih)
                ov = iw * ih / ua #iou between max box and detection box

                if method == 1: # linear
                    if ov > Nt: 
                        weight = 1 - ov
                    else:
                        weight = 1
                elif method == 2: # gaussian
                    weight = np.exp(-(ov * ov)/sigma)
                else: # original NMS
                    if ov > Nt: 
                        weight = 0
                    else:
                        weight = 1

                boxes[pos, 4] = weight*boxes[pos, 4]

        # if box score falls below threshold, discard the box by swapping with last box
        # update N
                if boxes[pos, 4] < threshold:
                    boxes[pos,0] = boxes[N-1, 0]
                    boxes[pos,1] = boxes[N-1, 1]
                    boxes[pos,2] = boxes[N-1, 2]
                    boxes[pos,3] = boxes[N-1, 3]
                    boxes[pos,4] = boxes[N-1, 4]
                    N = N - 1
                    pos = pos - 1

        pos = pos + 1

keep = [i for i in range(N)]
return keep</code></pre><br/><h2 style="font-family:&#39;-apple-system&#39;, &#39;SF UI Text&#39;, Arial, &#39;PingFang SC&#39;, &#39;Hiragino Sans GB&#39;, &#39;Microsoft YaHei&#39;, &#39;WenQuanYi Micro Hei&#39;, sans-serif, SimHei, SimSun;background-color:rgb(255,255,255);"><a></a><span style="color:#0000FF;">Experiments</span></h2><p style="font-size:14px;font-family:&#39;-apple-system&#39;, &#39;SF UI Text&#39;, Arial, &#39;PingFang SC&#39;, &#39;Hiragino Sans GB&#39;, &#39;Microsoft YaHei&#39;, &#39;WenQuanYi Micro Hei&#39;, sans-serif, SimHei, SimSun;background-color:rgb(255,255,255);">下图可以看出,基本可以获得平均1%的提升,且不增加额外的训练和计算负担。</p><p style="text-align:center;font-size:14px;font-family:&#39;-apple-system&#39;, &#39;SF UI Text&#39;, Arial, &#39;PingFang SC&#39;, &#39;Hiragino Sans GB&#39;, &#39;Microsoft YaHei&#39;, &#39;WenQuanYi Micro Hei&#39;, sans-serif, SimHei, SimSun;background-color:rgb(255,255,255);"><img src="https://img-blog.csdn.net/20170430193152979?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvc2h1emZhbg==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="float"/></p><p style="font-size:14px;font-family:&#39;-apple-system&#39;, &#39;SF UI Text&#39;, Arial, &#39;PingFang SC&#39;, &#39;Hiragino Sans GB&#39;, &#39;Microsoft YaHei&#39;, &#39;WenQuanYi Micro Hei&#39;, sans-serif, SimHei, SimSun;background-color:rgb(255,255,255);">高斯方差以及NMS的IOU阈值的敏感性测试:</p><p style="text-align:center;font-size:14px;font-family:&#39;-apple-system&#39;, &#39;SF UI Text&#39;, Arial, &#39;PingFang SC&#39;, &#39;Hiragino Sans GB&#39;, &#39;Microsoft YaHei&#39;, &#39;WenQuanYi Micro Hei&#39;, sans-serif, SimHei, SimSun;background-color:rgb(255,255,255);"><img src="https://img-blog.csdn.net/20170430194501090?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvc2h1emZhbg==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="float"/></p>            
收藏
暂无回复