非最大抑制(NMS)主要用于基于深度学习的目标检测模型输出的后处理,从而去除冗余的检测框,获得正确的检测结果。示意图如下:
算法流程:
通过分析可以发现 N M S NMS NMS 存在以下几个缺陷:
import numpy as np
def nms(dets, Nt):
x1 = dets[:,0]
y1 = dets[:,1]
x2 = dets[:,2]
y2 = dets[:,3]
scores = dets[:,4]
order = scores.argsort()[::-1]
#计算面积
areas = (x2 - x1 + 1)*(y2 - y1 + 1)
#保留最后需要保留的边框的索引
keep = []
while order.size > 0:
# order[0]是目前置信度最大的,肯定保留
i = order[0]
keep.append(i)
#计算窗口i与其他窗口的交叠的面积
xx1 = np.maximum(x1[i], x1[order[1:]])
yy1 = np.maximum(y1[i], y1[order[1:]])
xx2 = np.minimum(x2[i], x2[order[1:]])
yy2 = np.minimum(y2[i], y2[order[1:]])
#计算相交框的面积,不相交时用0代替
w = np.maximum(0.0, xx2 - xx1 + 1)
h = np.maximum(0.0, yy2 - yy1 + 1)
inter = w * h
#计算IOU:相交的面积/相并的面积
ovr = inter / (areas[i] + areas[order[1:]] - inter)
inds = np.where(ovr < thresh)[0]
order = order[inds + 1]
return keep
# test
if __name__ == "__main__":
dets = np.array([[30, 20, 230, 200, 1],
[50, 50, 260, 220, 0.9],
[210, 30, 420, 5, 0.8],
[430, 280, 460, 360, 0.7]])
thresh = 0.35
keep_dets = nms(dets, thresh)
print(keep_dets)
print(dets[keep_dets])
时间复杂度: O ( n 2 ) O(n^2) O(n2),其中 n n n 为待筛选检测框数量
针对 N M S NMS NMS 存在的第一个问题,通过分析发现主要是因为在 N M S NMS NMS 算法中每次直接将与 m m m 的 i o u iou iou 大于等于 N t N_t Nt 的检测框直接删除导致的。 因此基于 N M S NMS NMS 算法, S o f t − N M S Soft-NMS Soft−NMS 进行了如下改进:
将于 m m m 重叠的检测框置信度降低,而不是直接删除。
这样可能存在另一个问题,同一目标的其他检测框也可能被保留下来。因此需要设计合适的策略,既保留相近的其他目标,又删除重复检测的目标。直觉上可以发现通常重复的检测框具有更高的重叠,因此可以根据 i o u iou iou 大小来设计置信度分数下降的程度。置信度修正策略如下:
s i = { s i , iou ( M , b i ) < N t s i ( 1 − iou ( M , b i ) ) , iou ( M , b i ) ≥ N t s_{i}=\left\{\begin{array}{ll}{s_{i},} & {\operatorname{iou}\left(\mathcal{M}, b_{i}\right)<N_{t}} \\ {s_{i}\left(1-\operatorname{iou}\left(\mathcal{M}, b_{i}\right)\right),} & {\operatorname{iou}\left(\mathcal{M}, b_{i}\right) \geq N_{t}}\end{array}\right. si={si,si(1−iou(M,bi)),iou(M,bi)<Ntiou(M,bi)≥Nt
该策略为 i o u iou iou 的线性函数,同样可以使用高斯惩罚函数
s i = s i ∗ e − i ou ( M , b i ) 2 σ , ∀ b i ∉ D s_{i}=s_{i}*e^{-\frac{\mathrm{i} \text { ou }\left(\mathcal{M}, b_{i}\right)^{2}}{\sigma}}, \forall b_{i} \notin \mathcal{D} si=si∗e−σi ou (M,bi)2,∀bi∈/D
算法流程如下图所示:
代码:
# -*- coding:utf-8 -*-
import numpy as np
def py_cpu_softnms(dets, Nt=0.3, sigma=0.5, thresh=0.5, method=2):
"""
py_cpu_softnms
:param dets: boexs 坐标矩阵 format [x1, y1, x2, y2, score]
:param Nt: iou 交叠阈值
:param sigma: 使用 gaussian 函数的方差
:param thresh: 最后的分数阈值
:param method: 使用的方法,1:线性惩罚;2:高斯惩罚;3:原始 NMS
:return: 留下的 boxes 的 index
"""
N = dets.shape[0]
# the order of boxes coordinate is [x1,y1,x2,y2]
x1 = dets[:, 0]
y1 = dets[:, 1]
x2 = dets[:, 2]
y2 = dets[:, 3]
areas = (x2 - x1 + 1) * (y2 - y1 + 1)
for i in range(N):
# intermediate parameters for later parameters exchange
tB = dets[i, :4]
ts = dets[i, 4]
ta = areas[i]
pos = i + 1
if i != N-1:
maxscore = np.max(dets[:, 4][pos:])
maxpos = np.argmax(dets[:, 4][pos:])
else:
maxscore = dets[:, 4][-1]
maxpos = -1
if ts < maxscore:
dets[i, :] = dets[maxpos + i + 1, :]
dets[maxpos + i + 1, :4] = tB
dets[:, 4][i] = dets[:, 4][maxpos + i + 1]
dets[:, 4][maxpos + i + 1] = ts
areas[i] = areas[maxpos + i + 1]
areas[maxpos + i + 1] = ta
# IoU calculate
xx1 = np.maximum(dets[i, 0], dets[pos:, 0])
yy1 = np.maximum(dets[i, 1], dets[pos:, 1])
xx2 = np.minimum(dets[i, 2], dets[pos:, 2])
yy2 = np.minimum(dets[i, 3], dets[pos:, 3])
w = np.maximum(0.0, xx2 - xx1 + 1)
h = np.maximum(0.0, yy2 - yy1 + 1)
inter = w * h
ovr = inter / (areas[i] + areas[pos:] - inter)
# Three methods: 1.linear 2.gaussian 3.original NMS
if method == 1: # linear
weight = np.ones(ovr.shape)
weight[ovr > Nt] = weight[ovr > Nt] - ovr[ovr > Nt]
elif method == 2: # gaussian
weight = np.exp(-(ovr * ovr) / sigma)
else: # original NMS
weight = np.ones(ovr.shape)
weight[ovr > Nt] = 0
dets[:, 4][pos:] = weight * dets[:, 4][pos:]
# select the boxes and keep the corresponding indexes
inds = np.argwhere(dets[:, 4] > thresh)
keep = inds.astype(int).T[0]
return keep
算法时间复杂度: O ( n 2 ) O(n^2) O(n2),其中 n n n 为待筛选检测框数量
注意:
通过对比可以看出,原始 N M S NMS NMS 与 S o f t − N M S Soft-NMS Soft−NMS 算法中的模式 3 3 3 等价,也就是说,删除 i o u iou iou 过高的重叠框等价于将该重叠框置信度分数置 0 0 0 。
S o f t − N M S Soft-NMS Soft−NMS 只解决了三个问题中的第一个问题。对于第二个问题,分类置信度分数和框的 i o u iou iou 不是强相关,因此需要一种新的方法来衡量框的位置置信度
。
作者假设边界框的 4 4 4 个坐标值之间相互独立,并使用单变量高斯分布来预测位置置信度。
P Θ ( x ) = 1 2 π σ 2 e − ( x − x e ) 2 2 σ 2 P_{\Theta}(x)=\frac{1}{\sqrt{2 \pi \sigma^{2}}} e^{-\frac{\left(x-x_{e}\right)^{2}}{2 \sigma^{2}}} PΘ(x)=2πσ21e−2σ2(x−xe)2
其中 Θ \Theta Θ 为可学习参数的集合, x e x_e xe 为被估计的边界框位置。标准差 σ \sigma σ 衡量预测的不确定性,当 σ → 0 \sigma \rightarrow0 σ→0 时,表示网络对预测的位置的置信度很高。
G T GT GT 边界框置信度也可以使用高斯分布来表示,当 σ → 0 \sigma \rightarrow0 σ→0 时,变成 D i r a c d e l t a Dirac~delta Dirac delta 函数:
P D ( x ) = δ ( x − x g ) P_{D}(x)=\delta\left(x-x_{g}\right) PD(x)=δ(x−xg)
其中, x g x_g xg 为 G T GT GT 边界框位置。
KL 损失函数
目标定位的目标是估计参数 Θ ^ \hat{\Theta} Θ^,使 N N N 个样本的 P Θ ( x ) P_{\Theta}(x) PΘ(x) 和 P D ( x ) P_{D}(x) PD(x) 之间的 K L KL KL 散度最小。
Θ ^ = arg min Θ 1 N ∑ D K L ( P D ( x ) ∥ P Θ ( x ) ) \hat{\Theta}=\underset{\Theta}{\arg \min } \frac{1}{N} \sum D_{K L}\left(P_{D}(x) \| P_{\Theta}(x)\right) Θ^=ΘargminN1∑DKL(PD(x)∥PΘ(x))
使用 K L KL KL 散度作为回归损失函数,对于单个样本:
L r e g = D K L ( P D ( x ) ∥ P Θ ( x ) ) = ∫ P D ( x ) log P D ( x ) d x − ∫ P D ( x ) log P Θ ( x ) d x = ( x g − x e ) 2 2 σ 2 + log ( σ 2 ) 2 + log ( 2 π ) 2 − H ( P D ( x ) ) \begin{aligned} L_{r e g} &=D_{K L}\left(P_{D}(x) \| P_{\Theta}(x)\right) \\ &=\int P_{D}(x) \log P_{D}(x) \mathrm{d} x-\int P_{D}(x) \log P_{\Theta}(x) \mathrm{d} x \\ &=\frac{\left(x_{g}-x_{e}\right)^{2}}{2 \sigma^{2}}+\frac{\log \left(\sigma^{2}\right)}{2}+\frac{\log (2 \pi)}{2}-H\left(P_{D}(x)\right) \end{aligned} Lreg=DKL(PD(x)∥PΘ(x))=∫PD(x)logPD(x)dx−∫PD(x)logPΘ(x)dx=2σ2(xg−xe)2+2log(σ2)+2log(2π)−H(PD(x))
分析可知,当 x e x_e xe 预测不准确时,网络预测更大的 σ 2 \sigma^2 σ2 使 L r e g L_{reg} Lreg 更小。 l o g ( 2 π ) 2 \frac{log(2\pi)}{2} 2log(2π) 和 H ( P D ( x ) ) H(P_D(x)) H(PD(x)) 与估计参数 Θ \Theta Θ 无关,因此
L r e g ∝ ( x g − x e ) 2 2 σ 2 + 1 2 log ( σ 2 ) L_{r e g} \propto \frac{\left(x_{g}-x_{e}\right)^{2}}{2 \sigma^{2}}+\frac{1}{2} \log \left(\sigma^{2}\right) Lreg∝2σ2(xg−xe)2+21log(σ2)
由于 σ \sigma σ 位于分母,为了防止梯度爆炸,网络预测 α = l o g ( σ 2 ) \alpha=log(\sigma^2) α=log(σ2) 代替直接预测 σ \sigma σ。
L r e g ∝ e − α 2 ( x g − x e ) 2 + 1 2 α L_{r e g} \propto \frac{e^{-\alpha}}{2}\left(x_{g}-x_{e}\right)^{2}+\frac{1}{2} \alpha Lreg∝2e−α(xg−xe)2+21α
对于 ∣ x g − x e ∣ > 1 |x_g-x_e|>1 ∣xg−xe∣>1 使用类似于 s m o o t h L 1 smooth~L_1 smooth L1 损失。
L r e g = e − α ( ∣ x g − x e ∣ − 1 2 ) + 1 2 α L_{r e g}=e^{-\alpha}\left(\left|x_{g}-x_{e}\right|-\frac{1}{2}\right)+\frac{1}{2} \alpha Lreg=e−α(∣xg−xe∣−21)+21α
方差投票
获取预测框位置方差后,根据相邻边界框位置方差来对候选框投票。 s o f t e r − N M S softer-NMS softer−NMS 算法如下。
通过分析发现,有两类邻近框权重较低:
由于分类分数较低的框可能有较高的位置置信度,因此分类置信度不参与位置投票。
本文主要介绍了 N M S NMS NMS、 S o f t − N M S Soft-NMS Soft−NMS 和 S o f t e r − N M S Softer-NMS Softer−NMS 算法,及其主要改进的方向。