目标检测常用的方法是将对象标识为图像中轴向对齐的框,大多数的较好的检测方法稠密的列举了目标可能出现的位置,并对每个位置进行分类,这是浪费、低效的,且需要很多额外的后处理。
本文提出了一种不同的方法,我们将目标建模为一个点——b-box的中心点。
本文检测方法使用关键点估计来寻找中心点,并回归框的其他特性,如尺度、3D 位置、方向、姿态等。
本文的基于中心点的方法——CenterNet,是一个端到端可微、简单、快速且准确度较高的方法。
CenterNet 在 MS COCO 数据集上达到了最好的速度和精度的平衡,AP 为28.1%时达到142FPS,AP为37.4%时达到52FPS,多尺度测试时AP 为45.1%时达到1.4FPS。
同时,我们使用了相同的方法在 KITTI 中来估计3D b-box。
本文提出了简单且高效的目标检测方法,我们使用b-box的单个中心点来表示目标(图2),之后可以从中心位置的图像特征来回归得到目标大小、维度、3d 扩展、方向和姿态等。
基于此,我们的目标检测问题就变成了一个标准的关键点估计问题。
我们将图像输入全卷积网络,得到热力图,热力图的峰值对应目标的中心。
每个峰值上的图像特征可以预测目标框的宽和高,网络使用稠密的有监督学习进行训练,推理阶段是一个单一的前向传播网络,没有NMS的后处理。
本文方法可以通过预测每个中心点的额外的输出,来扩展到其他应用方面,如3D目标检测和多人姿态估计。
对于3D 目标检测,我们回归目标的绝对深度、3D b-box 维度、目标方向。
对于人类姿态估计,我们将关节点(2D joint)位置作为中心点的偏移量,直接在中心点位置回归出这些偏移量的值。
本文简单的方法使得具有较快的速度,如图1,实验在三个网络上进行:
本文的方法接近于 anchor-based 单阶段方法,中心点可以被看成一个形状未知的anchor(如图3),但也有很多不同。
利用关键点进行目标检测:
本文不是第一个使用关键点进行目标检测的方法,CornerNet 使用两个关键点来检测边界框。ExtremNet 检测所有目标的左、右、上、下和中心点。
这些方法同样能够建立鲁棒性的关键点估计网络,但是,他们在关键点检测之后需要组合的步骤,会显著的降低网络速度。
CenterNet 网络仅仅抽取目标的中心点,无需进行关键点组合的后处理。
单目3D目标检测:
3D 边界框估计在自动驾驶领域有很重要的作用[17]。
I ∈ R W × H × 3 I\in R^{W\times H \times 3} I∈RW×H×3 是大小为 W 和 H 的三维输入图像
我们的目标是产生一个关键点的热力图 Y ^ ∈ [ 0 , 1 ] W R × H R × C \hat{Y}\in[0,1]^{\frac{W}{R}\times\frac{H}{R}\times C} Y^∈[0,1]RW×RH×C,其中,R 是输出的特征图的步长,C 是关键点类型个数。
关键点类型的个数:
输出步长:本文使用 R=4,输出的步长对输出的估计用 R 进行下采样
预测结果:
本文使用多个不同的全卷积编码解码网络来估计 Y ^ \hat{Y} Y^:
关键点预测网络的训练:
对类别 c 中的每个真实关键点 p ∈ R 2 p \in R^2 p∈R2,计算一个低分辨率的对应点 p ˇ = ⌊ p R ⌋ \check{p}=\lfloor \frac{p}{R} \rfloor pˇ=⌊Rp⌋。
之后将所有真实关键点使用高斯核 Y x y c = e x p ( − ( x − p ˇ x ) 2 + ( y − p ˇ y ) 2 2 σ p 2 ) Y_{xyc}=exp(-\frac{(x-\check{p}_x)^2+(y-\check{p}_y)^2}{2\sigma_p^2}) Yxyc=exp(−2σp2(x−pˇx)2+(y−pˇy)2) 投射到热力图上,其中 σ p \sigma_p σp 为与目标大小相关的标准差。
如果同一类别的两个高斯分布重合了,我们使用逐个像素点取最大值的方法来处理。
训练的目标函数是一个像素级逻辑回归的focal loss:
其中:
该 Focal loss 函数是针对 CenterNet 修正而来的损失函数,和 Focal Loss类似,对于easy example的中心点,适当减少其训练比重也就是loss值.
( 1 − Y ^ x y z ) α (1-\hat{Y}_{xyz})^{\alpha} (1−Y^xyz)α 和 ( Y ^ x y z ) α (\hat{Y}_{xyz})^{\alpha} (Y^xyz)α 的作用:
限制 easy example 导致的梯度更新被易区分的点所主导的问题
当 Y x y z = 1 Y_{xyz}=1 Yxyz=1 的时候, 假如 Y ^ x y z \hat{Y}_{xyz} Y^xyz 接近1的话,说明这个是一个比较容易检测出来的点,那么 ( 1 − Y ^ x y z ) α (1-\hat{Y}_{xyz})^{\alpha} (1−Y^xyz)α 就相应比较低了。
当 Y x y z = 1 Y_{xyz}=1 Yxyz=1 的时候,而 Y ^ x y z \hat{Y}_{xyz} Y^xyz 接近0的时候,说明这个中心点还没有学习到,所以要加大其训练的比重,因此 ( 1 − Y ^ x y z ) α (1-\hat{Y}_{xyz})^{\alpha} (1−Y^xyz)α 就会很大, α \alpha α是超参数,这里取2。
当 Y x y z = 0 Y_{xyz}=0 Yxyz=0 的时候,预测的 Y ^ x y z \hat{Y}_{xyz} Y^xyz 理论上也要接近于0,但如果其预测的值 Y ^ x y z \hat{Y}_{xyz} Y^xyz 接近于1的话, ( Y ^ x y z ) α (\hat{Y}_{xyz})^{\alpha} (Y^xyz)α 的值就会比较大,加大损失,即增加这个未被正确预测的样本的损失。
( 1 − Y x y z ) β (1-Y_{xyz})^{\beta} (1−Yxyz)β 的作用:
为了弥补输出步长所造成的离散化损失,我们对每个中心点都额外的预测了 local offset O ^ ∈ R W R × H R × 2 \hat{O}\in R^{\frac{W}{R}\times\frac{H}{R}\times 2} O^∈RRW×RH×2。
所有的类别都共享相同的预测 offset,该offset是用L1 loss训练的:
仅仅在关键点位置 p ˇ \check{p} pˇ 上实行有监督行为,其他位置被忽略。
令 ( x 1 ( k ) , y 1 ( k ) , x 2 ( k ) , y 2 ( k ) ) (x_1^{(k)},y_1^{(k)},x_2^{(k)},y_2^{(k)}) (x1(k),y1(k),x2(k),y2(k)) 表示有 c k c_k ck个类别的目标 k k k 的b-box,其中心点在 p k = ( x 1 ( k ) + x 2 ( k ) 2 , y 1 ( k ) + y 2 ( k ) 2 ) p_k=(\frac{x_1^{(k)}+x_2^{(k)}}{2},\frac{y_1^{(k)}+y_2^{(k)}}{2}) pk=(2x1(k)+x2(k),2y1(k)+y2(k))。
我们使用关键点估计 Y ^ \hat{Y} Y^ 来预测所有中心点,另外,对每个目标 k 都回归其目标大小 s k = ( x 2 ( k ) − x 1 ( k ) , y 2 ( k ) − y 1 ( k ) ) s_k=(x_2^{(k)}-x_1^{(k)}, y_2^{(k)}-y_1^{(k)}) sk=(x2(k)−x1(k),y2(k)−y1(k))。
为了限制计算量,我们对所有目标类别都使用单个尺度的预测 S ^ ∈ R W R × H R × 2 \hat{S}\in R^{\frac{W}{R}\times\frac{H}{R}\times 2} S^∈RRW×RH×2。
我们对中心点使用和(2)相同的 L1 loss :
我们没有规范化尺度,且直接使用原始的像素坐标,直接使用常量 λ s i z e \lambda_{size} λsize 来平衡 loss:
设定:
从点到b-box:
推理阶段,首先给每个类别独立抽取热力图的峰值,检测所有其值大于或等于其相邻8个邻域的响应,保留前100个峰值。
令 P ^ c \hat{P}_c P^c 表示类别 c 中 n 个检测到的中心点 P ^ = ( x ^ i , y ^ i ) i = 1 n \hat{P}={(\hat{x}_i, \hat{y}_i)}_{i=1}^n P^=(x^i,y^i)i=1n 。
每个关键点是由整数坐标 ( x i , y i ) (x_i,y_i) (xi,yi) 给出的,我们将关键点值 Y ^ x i y i c \hat{Y}_{x_iy_ic} Y^xiyic 作为检测置信度的衡量,并且在位置上产生一个b-box:
3D 检测是估计一个三维的b-box,并且每个关键点都需要额外的参数:深度、3D 维度、方向。
我们给其添加一些额外的输出来预测这些值。
深度:
深度(depth) d 是一个单独的,但是深度难以直接回归,我们使用[13]中的输出变换,且 d = 1 / δ ( d ^ ) − 1 d=1/\delta(\hat{d})-1 d=1/δ(d^)−1,其中 δ \delta δ 是sigmoid函数。我们将深度的计算单独输出一个通道 D ^ ∈ [ 0 , 1 ] W R × H R \hat{D}\in [0,1]^{\frac{W}{R}\times \frac{H}{R}} D^∈[0,1]RW×RH。
不同于之前的形式,在输出层使用反向sigmoid变换,变换之后使用 L1 loss 来训练深度估计的网络。
3D dimensions
目标的3D dimensions 是三个标量,我们直接使用分离的head F ^ ∈ R W R × H R × 3 \hat{F}\in R^{\frac{W}{R}\times \frac{H}{R}\times 3} F^∈RRW×RH×3 和 L1 loss 来回归其绝对值,
方向
方向是一个默认的单个标量,但也较难回归。我们使用 [38] 中的方法,将方向表示成两个 bins,且用 in-bins 回归。详细来说就是使用 8 个标量scalars 来编码,每个bin有4个标量,每个bin中,两个标量被用来进行 softmax 分离,其余两个被用来会个每个bin中的角度。详见附录。
使用 Resnet-18,Resnet-101,DLA-34 和 Hourglass-104 backbone分别实验
对Resnet 和 DLA-34都使用可变性卷积进行了修正,Hourglass-104使用原来的网络。
CenterNet的优点如下:
设计模型的结构比较简单,一般人也可以轻松看明白,不仅对于two-stage,对于one-stage的目标检测算法来说该网络的模型设计也是优雅简单的。
该模型的思想不仅可以用于目标检测,还可以用于3D检测和人体姿态识别,虽然论文中没有是深入探讨这个,但是可以说明这个网络的设计还是很好的,我们可以借助这个框架去做一些其他的任务。
虽然目前尚未尝试轻量级的模型,但是可以猜到这个模型对于嵌入式端这种算力比较小的平台还是很有优势的。
CenterNet的缺点也是有的:
在实际训练中,如果在图像中,同一个类别中的某些物体的GT中心点,在下采样时会挤到一块,也就是两个物体在GT中的中心点重叠了,CenterNet对于这种情况也是无能为力的,也就是将这两个物体的当成一个物体来训练(因为只有一个中心点)。同理,在预测过程中,如果两个同类的物体在下采样后的中心点也重叠了,那么CenterNet也是只能检测出一个中心点,不过CenterNet对于这种情况的处理要比faster-rcnn强一些的,具体指标可以查看论文相关部分。
有一个需要注意的点,CenterNet在训练过程中,如果同一个类的不同物体的高斯分布点互相有重叠,那么则在重叠的范围内选取较大的高斯点。
代码已开源:https://github.com/xingyizhou/CenterNet
把需要的模型和数据下载,安装,之后运行。
所有的训练脚本都在 :https://github.com/xingyizhou/CenterNet/tree/master/experiments
本文的训练都是在 8 个GPU 上进行的,可以依据该论文来将学习率和 batch size 调整。
例如,在 2 个 gpu 上训练 coco 数据集:
python main.py ctdet --exp_id coco_dla --batch_size 32 --master_batch 15 --lr 1.25e-4 --gpus 0,1
--master batch
允许给最好的 GPU 使用不同的batch_size。--resume
来中段训练,也可以在 exp_id
中找到最后的那个模型cd src
# train
python main.py ctdet --exp_id coco_hg --arch hourglass --batch_size 24 --master_batch 4 --lr 2.5e-4 --load_model ../models/ExtremeNet_500000.pth --gpus 0,1,2,3,4
# test
python test.py ctdet --exp_id coco_hg --arch hourglass --keep_res --resume
# flip test
python test.py ctdet --exp_id coco_hg --arch hourglass --keep_res --resume --flip_test
# multi scale test
python test.py ctdet --exp_id coco_hg --arch hourglass --keep_res --resume --flip_test --test_scales 0.5,0.75,1,1.25,1.5
cd ..
test.py
增加 --trainval
1x
表示训练迭代 140 个 epoch,在 90 次和 120 次的时候学习率分别下降 10倍;2x
表示训练迭代 230 个 epoch,在 180 次和 210 次的时候学习率分别下降 10倍;batch_size、iteration、epoch 的区别:
batchsize:中文翻译为批大小(批尺寸)。在深度学习中,一般采用SGD训练,即每次训练在训练集中取batchsize个样本训练;
iteration:中文翻译为迭代,1个iteration等于使用batchsize个样本训练一次;一个迭代 = 一个正向通过+一个反向通过
epoch:迭代次数,1个epoch等于使用训练集中的全部样本训练一次;一个epoch = 所有训练样本的一个正向传递和一个反向传递
举个例子,训练集有1000个样本,batchsize=10,那么:训练完整个样本集需要:100次iteration,1次epoch。
KITTI 上进行 3D 目标检测的细节:
ddd_3dop.sh:
cd src
# train
python main.py ddd --exp_id 3dop --dataset kitti --kitti_split 3dop --batch_size 16 --master_batch 7 --num_epochs 70 --lr_step 45,60 --gpus 0,1
# test
python test.py ddd --exp_id 3dop --dataset kitti --kitti_split 3dop --resume
cd ..
cd src
# train
python main.py ddd --exp_id sub --dataset kitti --kitti_split subcnn --batch_size 16 --master_batch 7 --num_epochs 70 --lr_step 45,60 --gpus 0,1
# test
python test.py ddd --exp_id sub --dataset kitti --kitti_split subcnn --resume
cd ..
例如:
1、使用 DLA 作为backbone,来评估 COCO 数据集上的效果:
python test.py ctdet --exp_id coco_dla --keep_res --load_model ../models/ctdet_coco_dla_2x.pth
如果所有的安装正确,那么会获得AP=37.4的结果
--keep_res
:使用原始分辨率的图像,如果没有设定这项的话,将会把图像resize为 512x512 大小--flip_test --test_scales 0.5,0.75,1,1.25,1.5
:分别实现 flip_test 和 muiti-scale test2、使用 hourglass 作为backbone,来评估 COCO 数据集上的效果:
python test.py ctdet --exp_id coco_hg --arch hourglass --fix_res --load_model ../models/ctdet_coco_hg.pth
3、测试 KITTI 的效果::
首先编码工具:
cd CenterNet_ROOT/src/tools/kitti_eval
g++ -o evaluate_object_3d_offline evaluate_object_3d_offline.cpp -O3
之后运行:
python test.py ddd --exp_id 3dop --dataset kitti --kitti_split 3dop --load_model ../models/ddd_3dop.th
ddd
是3D 的模型--exp_id 3dop
:使用 3dop 数据划分,也可以使用 --kitti_split subcnn
来划分