点击小眼睛开启蜘蛛网特效

扔掉anchor!真正的CenterNet——Objects as Points论文解读

《扔掉anchor!真正的CenterNet——Objects as Points论文解读》

anchor-free目标检测属于anchor-free系列的目标检测,相比于CornerNet做出了改进,使得检测速度和精度相比于one-stage和two-stage的框架都有不小的提高,尤其是与YOLOv3作比较,在相同速度的条件下,CenterNet的精度比YOLOv3提高了4个左右的点。

因为文章格式原因,更新文章不方便,所以关于这篇文章的最新内容地址:

https://zhuanlan.zhihu.com/p/66048276

前言

anchor-free目标检测属于anchor-free系列的目标检测,相比于CornerNet做出了改进,使得检测速度和精度相比于one-stage和two-stage的框架都有不小的提高,尤其是与YOLOv3作比较,在相同速度的条件下,CenterNet的精度比YOLOv3提高了4个左右的点。

TIM截图20190516092134

CenterNet不仅可以用于目标检测,还可以用于其他的一些任务,如肢体识别或者3D目标检测等等,但是这篇文章我们就重点说的是其对目标检测的部分。

TIM截图20190516092437

那CenterNet相比于之前的one-stage和two-stage的目标检测有什么特点?

  • CenterNet的“anchor”仅仅会出现在当前目标的位置处而不是整张图上撒,所以也没有所谓的box overlap大于多少多少的算positive anchor这一说,也不需要区分这个anchor是物体还是背景
  • 因为每个目标只对应一个“anchor”,这个anchor是从heatmap中提取出来的,所以不需要NMS再进行来筛选
  • CenterNet的输出分辨率的下采样因子是4,比起其他的目标检测框架算是比较小的(Mask-Rcnn最小为16、SSD为最小为16)

总体来说,CenterNet结构优雅简单,直接检测目标的中心点和大小,是真anchor-free。

PS:其实本篇所说的CenterNet的真实论文名称叫做objects as points,因为也有一篇叫做CenterNet: Keypoint Triplets for Object Detection的论文与这篇文章的网络名称冲突了,所以以下所说的CenterNet是指objects as points

总之这是一篇值得一读的好文!

网络结构与前提条件

接下来说一下正式进入篇章之前的一些前提知识。

使用的网络

论文中CenterNet提到了三种用于目标检测的网络,这三种网络都是编码解码(encoder-decoder)的结构:

  • Resnet-18 with up-convolutional layers : 28.1% coco and 142 FPS
  • DLA-34 : 37.4% COCOAP and 52 FPS
  • Hourglass-104 : 45.1% COCOAP and 1.4 FPS

每个网络内部的结构不同,但是在模型的最后都是加了三个网络构造来输出预测值,默认是80个类、2个预测的中心点坐标、2个中心点的偏置。

用官方的源码(使用Pytorch)来表示一下最后三层,其中hm为heatmap、wh为对应中心点的width和height、reg为偏置量,这些值在后文中会有讲述。

(hm): Sequential(
(0): Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
(1): ReLU(inplace)
(2): Conv2d(64, 80, kernel_size=(1, 1), stride=(1, 1))
)
(wh): Sequential(
(0): Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
(1): ReLU(inplace)
(2): Conv2d(64, 2, kernel_size=(1, 1), stride=(1, 1))
)
(reg): Sequential(
(0): Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
(1): ReLU(inplace)
(2): Conv2d(64, 2, kernel_size=(1, 1), stride=(1, 1))
)

前提条件

附一张检测的效果图:

centernet_1

我们该如何检测呢?

首先假设输入图像为IRW×H×3I \in R^{W \times H \times 3},其中WWHH分别为图像的宽和高,然后在预测的时候,我们要产生出关键点的热点图(keypoint heatmap):Y^[0,1]WR×HR×C\hat{Y} \in [0,1]^ {\frac{W}{R} \times \frac{H}{R} \times C},其中RR为输出对应原图的步长,而CC是在目标检测中对应着检测点的数量,如在COCO目标检测任务中,这个CC的值为80,代表当前有80个类别。


插一端官方代码,其中RR就是self.opt.down_ratio也就是4,代表下采样的因子。

# 其中input_h和input_w为512,而self.opt.down_ratio为4,最终的output_h为128
# self.opt.down_ratio就是上述的R即输出对应原图的步长
output_h = input_h // self.opt.down_ratio
output_w = input_w // self.opt.down_ratio

这样,Y^x,y,c=1\hat{Y}_{x, y, c}=1就是一个检测到物体的预测值,对于Y^x,y,c=1\hat{Y}_{x, y, c}=1,表示对于类别cc,在当前(x,y)(x,y)坐标中检测到了这种类别的物体,而Y^x,y,c=0\hat{Y}_{x, y, c}=0则表示当前当前这个坐标点不存在类别为cc的物体。

在整个训练的流程中,CenterNet学习了CornerNet的方法。对于每个标签图(ground truth)中的某一cc类,我们要将真实关键点(true keypoint) pR2p \in \mathcal{R}^{2}计算出来用于训练,中心点的计算方式为p=(x1+x22,y1+y22)p = \left(\frac{x_{1}+x_{2}^{}}{2}, \frac{y_{1}^{}+y_{2}^{}}{2}\right),对于下采样后的坐标,我们设为p~=pR\tilde{p}=\left\lfloor\frac{p}{R}\right\rfloor,其中RR是上文中提到的下采样因子4。所以我们最终计算出来的中心点是对应低分辨率的中心点。

然后我们利用Y[0,1]WR×HR×CY \in[0,1]^{\frac{W}{R} \times \frac{H}{R} \times C}来对图像进行标记,在下采样的[128,128]图像中将ground truth pointY[0,1]WR×HR×CY \in[0,1]^{\frac{W}{R} \times \frac{H}{R} \times C}的形式,用一个高斯核Yxyc=exp((xp~x)2+(yp~y)22σp2)Y_{x y c}=\exp \left(-\frac{\left(x-\tilde{p}_{x}\right)^{2}+\left(y-\tilde{p}_{y}\right)^{2}}{2 \sigma_{p}^{2}}\right)来将关键点分布到特征图上,其中σp\sigma_{p}是一个与目标大小(也就是w和h)相关的标准差。如果某一个类的两个高斯分布发生了重叠,直接去元素间最大的就可以。

这么说可能不是很好了解,那么直接看一个官方源码中生成的一个高斯分布[9,9]:

Screenshot from 2019-05-16 20-25-09

每个点Y[0,1]WR×HR×CY \in[0,1]^{\frac{W}{R} \times \frac{H}{R} \times C}的范围是0-1,而1则代表这个目标的中心点,也就是我们要预测要学习的点。

损失函数

重点看一下中心点预测的损失函数,原始论文中因为篇幅关系将第二个otherwise的公式挤一块了,这里我们展平看一下就比较清爽:

Lk=1Nxyc{(1Y^xyc)αlog(Y^xyc) if Yxyc=1(1Yxyc)β(Y^xyc)αlog(1Y^xyc) otherwise L_{k}=\frac{-1}{N} \sum_{x y c} \left\{\begin{array}{cc}{\left(1-\hat{Y}_{x y c}\right)^{\alpha} \log \left(\hat{Y}_{x y c}\right)} & {\text { if } Y_{x y c}=1} \\ {\left(1-Y_{x y c}\right)^{\beta}\left(\hat{Y}_{x y c}\right)^{\alpha}} {\log \left(1-\hat{Y}_{x y c}\right)} & {\text { otherwise }}\end{array}\right.

其中α\alphaβ\beta是Focal Loss的超参数,NN是图像II的的关键点数量,用于将所有的positive focal loss标准化为1。在这篇论文中α\alphaβ\beta分别是2和4。这个损失函数是Focal Loss的修改版,适用于CenterNet。

这个损失也比较关键,需要重点说一下。和Focal Loss类似,对于easy example的中心点,适当减少其训练比重也就是loss值,当Yxyc=1Y_{x y c}=1的时候,(1Y^xyc)α(1-\hat{Y}_{x y c})^{\alpha}就充当了矫正的作用,假如Y^xyc\hat{Y}_{x y c}接近1的话,说明这个是一个比较容易检测出来的点,那么(1Y^xyc)α(1-\hat{Y}_{x y c})^{\alpha}就相应比较低了。而当Y^xyc\hat{Y}_{x y c}接近0的时候,说明这个中心点还没有学习到,所以要加大其训练的比重,因此(1Y^xyc)α(1-\hat{Y}_{x y c})^{\alpha}就会很大,α\alpha是超参数,这里取2。

123221.jpg_screenshot_15.05.2019

再说下另一种情况,当otherwiseotherwise的时候,这里对实际中心点的其他近邻点的训练比重(loss)也进行了调整,首先可以看到(Y^xyc)α(\hat{Y}_{x y c})^{\alpha},因为当otherwiseotherwise的时候(Y^xyc)α(\hat{Y}_{x y c})^{\alpha}的预测值理应是0,如果不为0的且越来越接近1的话,(Y^xyc)α(\hat{Y}_{x y c})^{\alpha}的值就会变大从而使这个损失的训练比重也加大;而(1Yxyc)β(1-{Y}_{x y c})^{\beta}则对中心点周围的,和中心点靠得越近的点也做出了调整(因为与实际中心点靠的越近的点可能会影响干扰到实际中心点,造成误检测),因为Yxyc{Y}_{x y c}在上文中已经提到,是一个高斯核生成的中心点,在中心点Yxyc=1{Y}_{x y c}=1但是在中心点周围扩散Yxyc{Y}_{x y c}会由1慢慢变小但是并不是直接为0,类似于上图,因此(1Yxyc)β(1-{Y}_{x y c})^{\beta},与中心点距离越近,Yxyc{Y}_{x y c}越接近1,这个值越小,相反则越大。那么(1Yxyc)β(1-{Y}_{x y c})^{\beta}(Y^xyc)α(\hat{Y}_{x y c})^{\alpha}是怎么协同工作的呢?

简单分为几种情况:

  • 对于距离实际中心点近的点,Yxyc{Y}_{x y c}值接近1,例如Yxyc=0.9{Y}_{x y c}=0.9,但是预测出来这个点的值Y^xyc\hat{Y}_{x y c}比较接近1,这个显然是不对的,它应该检测到为0,因此用(Y^xyc)α(\hat{Y}_{x y c})^{\alpha}惩罚一下,使其LOSS比重加大些;但是因为这个检测到的点距离实际的中心点很近了,检测到的Y^xyc\hat{Y}_{x y c}接近1也情有可原,那么我们就同情一下,用(1Yxyc)β(1-{Y}_{x y c})^{\beta}来安慰下,使其LOSS比重减少些。
  • 对于距离实际中心点远的点,Yxyc{Y}_{x y c}值接近0,例如Yxyc=0.1{Y}_{x y c}=0.1,如果预测出来这个点的值Y^xyc\hat{Y}_{x y c}比较接近1,肯定不对,需要用(Y^xyc)α(\hat{Y}_{x y c})^{\alpha}惩罚(原理同上),如果预测出来的接近0,那么差不多了,拿(Y^xyc)α(\hat{Y}_{x y c})^{\alpha}来安慰下,使其损失比重小一点;至于(1Yxyc)β(1-{Y}_{x y c})^{\beta}的话,因为此时预测距离中心点较远的点,所以这一项使距离中心点越远的点的损失比重占的越大,而越近的点损失比重则越小,这相当于弱化了实际中心点周围的其他负样本的损失比重,相当于处理正负样本的不平衡了。
  • 如果结合上面两种情况,那就是:(1Y^xyc)α(1-\hat{Y}_{x y c})^{\alpha}(Y^xyc)α(\hat{Y}_{x y c})^{\alpha}来限制easy example导致的gradient被easy example dominant的问题,而(1Yxyc)β(1-{Y}_{x y c})^{\beta}则用来处理正负样本的不平衡问题(因为每一个物体只有一个实际中心点,其余的都是负样本,但是负样本相较于一个中心点显得有很多)。

另外看一下官方的这张图可能有助于理解:传统的基于anchor的检测方法,通常选择与标记框IoU大于0.7的作为positive,相反,IoU小于0.3的则标记为negative,如下图a。这样设定好box之后,在训练过程中使positive和negative的box比例为1:3来减少negative box的比例(例如SSD没有使用focal loss)。

而在CenterNet中,每个中心点对应一个目标的位置,不需要进行overlap的判断。那么怎么去减少negative center pointer的比例呢?CenterNet是采用Focal Loss的思想,在实际训练中,中心点的周围其他点(negative center pointer)的损失则是经过衰减后的损失(上文提到的),而目标的长和宽是经过对应当前中心点的w和h回归得到的:

TIM截图20190514163105

目标中心的偏置损失

因为上文中对图像进行了R=4R=4的下采样,这样的特征图重新映射到原始图像上的时候会带来精度误差,因此对于每一个中心点,额外采用了一个local offsetO^RWR×HR×2\hat{O} \in \mathcal{R}^{\frac{W}{R}} \times \frac{H}{R} \times 2去补偿它。所有类cc的中心点共享同一个offset prediction,这个偏置值(offset)用L1 loss来训练:

Loff=1NpO^p~(pRp~)L_{o f f}=\frac{1}{N} \sum_{p}\left|\hat{O}_{\tilde{p}}-\left(\frac{p}{R}-\tilde{p}\right)\right|


上述公式直接看可能不是特别容易懂,其实pR\frac{p}{R}是原始图像经过下采样得到的,对于[512,512]的图像如果R=4R=4的话那么下采样后就是[128,128]的图像,下采样之后对标签图像用高斯分布来在图像上撒热点,怎么撒呢?首先将box坐标也转化为与[128,128]大小图像匹配的形式,但是因为我们原始的annotation是浮点数的形式(COCO数据集),使用转化后的box计算出来的中心点也是浮点型的,假设计算出来的中心点是[98.97667,2.3566666]。

但是在推断过程中,我们首先读入图像[640,320],然后变形成[512,512],然后下采样4倍成[128,128]。最终预测使用的图像大小是[128,128],而每个预测出来的热点中心(headmap center),假设我们预测出与实际标记的中心点[98.97667,2.3566666]对应的点是[98,2],坐标是(x,y)(x,y),对应的类别是cc,等同于这个点上Y^x,y,c=1\hat{Y}_{x, y, c}=1,有物体存在,但是我们标记出的点是[98,2],直接映射为[512,512]的形式肯定会有精度损失,为了解决这个就引入了LoffL_{o f f}偏置损失。

Loff=1NpO^p~(pRp~)L_{o f f}=\frac{1}{N} \sum_{p}\left|\hat{O}_{\tilde{p}}-\left(\frac{p}{R}-\tilde{p}\right)\right|

这个式子中O^p~\hat{O}_{\tilde{p}}是我们预测出来的偏置,而(pRp~)(\frac{p}{R}-\tilde{p})则是在训练过程中提前计算出来的数值,在官方代码中为:

# ct 即 center point reg是偏置回归数组,存放每个中心店的偏置值 k是当前图中第k个目标
reg[k] = ct - ct_int
# 实际例子为
# [98.97667 2.3566666] - [98  2] = [0.97667, 0.3566666]

reg[k]之后与预测出来的reg一并放入损失函数中进行计算。注意上述仅仅是对某一个关键点位置p~\tilde{p}来计算的,计算当前这个点的损失值的时候其余点都是被忽略掉的。

到了这里我们可以发现,这个偏置损失是可选的,我们不使用它也可以,只不过精度会下降一些。


目标大小的损失

我们假设(x1(k),y1(k),x2(k),y2(k))\left(x_{1}^{(k)}, y_{1}^{(k)}, x_{2}^{(k)}, y_{2}^{(k)}\right)为目标kk,所属类别为ckc_k,它的中心点为pk=(x1(k)+x2(k)2,y1(k)+y2(k)2)p_k = \left(\frac{x_{1}^{(k)}+x_{2}^{(k)}}{2}, \frac{y_{1}^{(k)}+y_{2}^{(k)}}{2}\right)。我们使用关键点预测Y^\hat{Y}去预测所有的中心点。然后对每个目标kksize进行回归,最终回归到sk=(x2(k)x1(k),y2(k)y1(k))s_{k}=\left(x_{2}^{(k)}-x_{1}^{(k)}, y_{2}^{(k)}-y_{1}^{(k)}\right),这个值是在训练前提前计算出来的,是进行了下采样之后的长宽值。

为了减少回归的难度,这里使用S^RWR×HR×2\hat{S} \in \mathcal{R}^{\frac{W^{\prime}}{R} \times \frac{H}{R} \times 2}作为预测值,使用L1损失函数,与之前的LoffL_{o f f}损失一样:
Lsize=1Nk=1NS^pkskL_{s i z e}=\frac{1}{N} \sum_{k=1}^{N}\left|\hat{S}_{p_{k}}-s_{k}\right|

整体的损失函数为物体损失、大小损失与偏置损失的和,每个损失都有相应的权重。

Ldet=Lk+λsizeLsize+λoffLoffL_{d e t}=L_{k}+\lambda_{s i z e} L_{s i z e}+\lambda_{o f f} L_{o f f}

在论文中λsize=0.1\lambda_{s i z e}=0.1,然后λoff=1\lambda_{o f f}=1,论文中所使用的backbone都有三个head layer,分别产生[1,80,128,128]、[1,2,128,128]、[1,2,128,128],也就是每个坐标点产生C+4C+4个数据,分别是类别以及、长宽、以及偏置。

推断阶段

在预测阶段,首先针对一张图像进行下采样,随后对下采样后的图像进行预测,对于每个类在下采样的特征图中预测中心点,然后将输出图中的每个类的热点单独地提取出来。具体怎么提取呢?就是检测当前热点的值是否比周围的八个近邻点(八方位)都大(或者等于),然后取100个这样的点,采用的方式是一个3x3的MaxPool,类似于anchor-based检测中nms的效果。

这里假设P^c\hat{\mathcal{P}}_{c}为检测到的点,P^={(x^i,y^i)}i=1n\hat{\mathcal{P}}=\left\{\left(\hat{x}_{i}, \hat{y}_{i}\right)\right\}_{i=1}^{n}代表cc类中检测到的一个点。每个关键点的位置用整型坐标表示(xi,yi)\left(x_{i}, y_{i}\right),然后使用Y^xiyic\hat{Y}_{x_{i} y_{i} c}表示当前点的confidence,随后使用坐标来产生标定框:

(x^i+δx^iw^i/2,y^i+δy^ih^i/2,x^i+δx^i+w^i/2,y^i+δy^i+h^i/2)\begin{array}{c}{\left(\hat{x}_{i}+\delta \hat{x}_{i}-\hat{w}_{i} / 2, \hat{y}_{i}+\delta \hat{y}_{i}-\hat{h}_{i} / 2\right.}, \\ {\hat{x}_{i}+\delta \hat{x}_{i}+\hat{w}_{i} / 2, \quad \hat{y}_{i}+\delta \hat{y}_{i}+\hat{h}_{i} / 2 )}\end{array}
其中(δx^i,δy^i)=O^x^i,y^i\left(\delta \hat{x}_{i}, \delta \hat{y}_{i}\right)=\hat{O}_{\hat{x}_{i}, \hat{y}_{i}}是当前点对应原始图像的偏置点,(w^i,h^i)=S^x^i,y^i\left(\hat{w}_{i}, \hat{h}_{i}\right)=\hat{S}_{\hat{x}_{i}, \hat{y}_{i}}代表预测出来当前点对应目标的长宽。

下图展示网络模型预测出来的中心点、中心点偏置以及该点对应目标的长宽:

TIM截图20190515104449

例子

运行官方源码的demo,随便挑了一张图,跑出来的结果分别对应最终图,取top=100的检测图以及预测出来的heatmap。

ctdet_screenshot_15.05.2019

out_pred_1.0_screenshot_15.05.2019

pred_hm_1.0_screenshot_15.05.2019

后记

总之这是一篇笔记,好久没有认真阅读一篇论文了。搞工程搞多了看见论文就头大,但是好的论文还是值得一读了,特别是这一篇。这篇论文厉害的地方在于:

  • 设计模型的结构比较简单,像我这么头脑愚笨的人也可以轻松看明白,不仅对于two-stage,对于one-stage的目标检测算法来说该网络的模型设计也是优雅简单的。
  • 该模型的思想不仅可以用于目标检测,还可以用于3D检测和人体姿态识别,虽然论文中没有是深入探讨这个,但是可以说明这个网络的设计还是很好的,我们可以借助这个框架去做一些其他的任务。
  • 虽然目前尚未尝试轻量级的模型(这是我接下来要做的!),但是可以猜到这个模型对于嵌入式端这种算力比较小的平台还是很有优势的,希望大家多多尝试一些新的backbone(不知道mobilenetv3+CenterNet会是什么样的效果),测试一下,欢迎和我交流呀~

当然说了一堆优点,CenterNet的缺点也是有的,那就是:

  • 如果不巧有两个物体的中心点刚好重叠,那么CenterNet只能预测其中一个物体
  • 如果图像中有些物体的位置在下采样中挤到一起,那么CenterNet对于这种情况也是无能为力的,不过CenterNet对于这种情况的处理要比faster-rcnn强一些的

好了,说了这么多,最后以这篇论文的Conclusion来结尾吧:

TIM截图20190516215704

如果文章有错误,欢迎指正,也欢迎小伙伴们与我交流~

  点赞
本篇文章采用 署名-非商业性使用-禁止演绎 4.0 国际 进行许可
转载请务必注明来源: https://oldpan.me/archives/anchor-free-ture-centernet

   关注Oldpan博客微信公众号,你最需要的及时推送给你。


  1. M
    Messi说道:

    老哥的MobileNetV3收敛了没啊 :redface: