论文链接
https://arxiv.org/abs/1808.01244
动机
在目标检测中使用anchor box的两个缺点:(1)在检测过程中会生成大量anchor box并计算每个anchor box和ground truth box的IoU。其中大部分的anchor box都是负样本而被丢弃。这个机制减慢了训练速度,增加了计算开销。 (2)anchor机制引入了更多的超参数,比如anchor box的大小、长宽比等,这增加了系统设计的复杂度。
贡献
提出一个新的one-stage但不需要anchor box的目标检测算法,通过预测bbox的左上角点坐标和右下角点坐标,得到目标的bbox定位。同时提出一个新的corner pooling操作,帮助卷积网络更好地定位bbox的角点。
算法
将hourglass network的最后一个卷积层的输出分别输入到两个分支,分别用于预测左上角点和右上角点的heatmaps,embeddings,offsets。
角点的检测
使用heatmap去检测定位角点。heatmaps有C个通道,对应C个类别(不包含背景类),本质上第k个通道都是一个针对第k类的二值掩码,在该通道上的每个位置的值可以理解为是第k类的bbox的左上(右下)角点的概率。
在训练时,考虑到角点在真值角点的附近时,依然可以形成一个和真值bbox的IoU接近1的bbox,所以当预测的角点在真值角点的某个半径的范围内时,可以适当减少损失。
半径的确定:处于真值(左上、右下)角点的半径范围内的预测(左上、右下)角点构成的bbox和真值bbox的IoU至少为t(论文中为0.3)
# 根据预测到的bbox计算半径
def gaussian_radius(det_size, min_overlap):
height, width = det_size
a1 = 1
b1 = (height + width)
c1 = width * height * (1 - min_overlap) / (1 + min_overlap)
sq1 = np.sqrt(b1 ** 2 - 4 * a1 * c1)
r1 = (b1 - sq1) / (2 * a1)
a2 = 4
b2 = 2 * (height + width)
c2 = (1 - min_overlap) * width * height
sq2 = np.sqrt(b2 ** 2 - 4 * a2 * c2)
r2 = (b2 - sq2) / (2 * a2)
a3 = 4 * min_overlap
b3 = -2 * min_overlap * (height + width)
c3 = (min_overlap - 1) * width * height
sq3 = np.sqrt(b3 ** 2 - 4 * a3 * c3)
r3 = (b3 + sq3) / (2 * a3)
return min(r1, r2, r3)
def gaussian2D(shape, sigma=1):
m, n = [(ss - 1.) / 2. for ss in shape]
y, x = np.ogrid[-m:m+1,-n:n+1]
h = np.exp(-(x * x + y * y) / (2 * sigma * sigma))
h[h < np.finfo(h.dtype).eps * h.max()] = 0
return h
def draw_gaussian(heatmap, center, radius, k=1):
diameter = 2 * radius + 1
gaussian = gaussian2D((diameter, diameter), sigma=diameter / 6)
x, y = center
height, width = heatmap.shape[0:2]
left, right = min(x, radius), min(width - x, radius + 1)
top, bottom = min(y, radius), min(height - y, radius + 1)
masked_heatmap = heatmap[y - top:y + bottom, x - left:x + right]
masked_gaussian = gaussian[radius - top:radius + bottom, radius - left:radius + right]
np.maximum(masked_heatmap, masked_gaussian * k, out=masked_heatmap)
角点位置预测的损失函数:
N为图片中真值bbox的个数。pcij为第c个通道的位置(i, j)处为角点的概率。ycij为标签,表示第c个通道的位置(i, j)处为角点的概率值,以ycij=1的(i, j)位置为中心点,形成一个概率的高斯分布,预测的角点越靠近ycij=1的(i, j)点,其损失越小。
许多网络对输入进行下采样获取全局信息并减少显存占用,输出时的规格比输入的原始图片要小。所以在预测bbox时,角点从原始图像映射到更小规格的heatmap上,在按比例缩小的过程中,导致了坐标精度的损失,影响定位效果。为了解决这个问题,增加一个位置偏移预测,通过预测偏移矫正角点的定位。
n是下采样系数。损失函数:
使用了smoothL1损失函数,增强对噪声的鲁棒性。
角点分组
在一副图片上检测到多个左上角点和右下角点后,需要将属于同一个bbox的左上角点和右下角点进行配对,忽略多余的角点。神经网络为每一个被检测的角点预测一个embedding vector。属于同一个bbox的左上角点和右下角点的embedding vector的欧式距离应该尽可能小,不属于同一个bbox的左上角点和右下角点的embedding vector的欧式距离要尽量大。在预测时就可以通过计算各个角点的embedding vector的距离进行配对。
损失函数:
etk为左上角点的embedding vector,ebk是右下角点的embedding vector。ek为etk和ebk的平均值
角点池化
由于角点的位置没有视觉上的显示,所以为了定位左上角点,需要在特征图的水平方向上从左向右找到bbox的上边界,在特征图的垂直方向从上向下找到bbox的左边界,通过两条边界确定左上角点(右下角点同理)。所以提出了corner pooling的新池化方法用于更好地定位角点。
垂直方向上corner pooling的公式:
t(i+1)j表示在第j列上,第i+1行到第H行的值中最大的值,实际上就是一个动态规划。
水平方向上corner pooling公式(同理):
Corner pooling在网络中的使用:
虚线框中的两个灰块分别是对水平方向和垂直方向的corner pooling
沙漏网络
沙漏网络首先通过max pooling进行多次下采样,然后多次上采样后恢复到原始分辨率,并通过跳跃连接恢复丢失的细节。多个沙漏网络能够堆叠构成一个更大的网络,适合目标检测。本文网络由两个沙漏网络堆叠而成,并对网络结构做了一些修改,比如把max pooling改为stride=2的卷积层、将特征分辨率减小5倍并增加了特征通道数、添加中间监督训练等等(具体看原文)。
实验
数据集
MS COCO
评价指标
结果
以上实验结果说明了corner pooling的有效性,根据bbox的大小确定损失减小半径的有效性以及沙漏网络的有效性。
优缺点
优点:
- 不使用anchor box,而是通过预测bbox的左上角点和右下角点的位置来定位目标bbox,并针对这个预测方式提出corner pooling,彻底摆脱了anchor box,减少了超参数量
缺点:
- 文中没有和yolov3进行比较,感觉是故意不进行比较的
- 在Titan X GPU上yolov3可以达到50ms一帧,而cornerNet需要244ms一帧,而他们的AP50结果差不多,这说明cornerNet和yolov3相比还是有一定差距
反思
CornerNet输入输出流程梳理:
- 输入一张RGB图片到hourglassNet中,通过两个串联的hourglassNet提取特征图。
2.将第二个hourglassNet最后一个卷积层输出的特征图分别输出到两个分支,分别进行左上角点和右下角点的定位。
3.在每个分支中特征图经过corner pooling等特征提取后输出3个特征图:(1)Heatmaps,有C(C为目标类别数量)个通道,每个通道上的值表示该像素位置为属于该类的bbox的角点的概率。(2)embeddings,两个分支的embeddings进行L1距离计算对左上角点和右下角点进行配对,获得属于同一个bbox的左上角点和右下角点的位置,从而定位bbox。(3)offsets,由于从高分辨率到低分辨率的映射使得角点的位置精度下降,通过使用offsets对损失的精度进行补偿校准,提高定位准确性。
4.在heatmap上使用3x3map pooling层进行NMS操作,再选择概率最大的前100个左上角点和前100个右下角点。然后使用L1距离计算两个分支的embedding各个点的距离,距离小于0.5或者两个角点属于不同的类的bbox被排除。再使用soft-nms进一步排除多余的bbox
corner pooling
对于corner pooling仍然有点不明白为什么要这样做。为什么这样的pooling能够对角点的定位有效果?如果把corner pooling换成其他的操作,比如卷积层,是否效果会变差?