目标检测可以理解为是物体识别和物体定位的综合,不仅仅要识别出物体属于哪个分类,更重要的是得到物体在图片中的具体位置。在自然图像中,基于深度学习的目标检测技术包括anchor-based和anchor-free两大类。基于anchor-based的技术包括一个阶段和两个阶段的检测。其中一阶段的检测技术包括SSD,DSSD,RetinaNet,RefineDet,YOLOV3等,二阶段技术包括Faster-RCNN,R-FCN,FPN,Cascade R-CNN,SNIP等。一般的,两个阶段的目标检测会比一个阶段的精度要高,但一个阶段的算法速度会更快。
two-stage: two-stage检测算法将检测问题划分为两个阶段,首先产生候选区域(region proposals),然后对候选区域分类(一般还需要对位置精修),这一类的典型代表是R-CNN, Fast R-CNN, Faster R-CNN,Mask R-CNN家族。他们识别错误率低,漏识别率也较低,但速度较慢,不能满足实时检测场景。
one-stage: 其不需要region proposal阶段,直接产生物体的类别概率和位置坐标值,经过单次检测即可直接得到最终的检测结果,因此有着更快的检测速度,比较典型的算法如YOLO,SSD,YOLOv2,YOLOv3,Retina-Net德等。
二者的共同点就是anchor-based,在检测过程中都需要先生成anchor,基于这些先验区域分别做分类和位置回归。
anchor-free的技术包括基于Keypoint与Segmentation两类。其中基于Keypoint技术包括CornerNet,CenterNet,CornerNet-Lite等,基于Segmentation的技术包括FSAF,FCOS,FoveaBox等。
通常来说,图像分类只能产生一个输出结果,这个结果会告诉你这张图像归属于哪种类别,比如下面这张图:
图像分类可以告诉你这是一张关于猫的图像或者这是一张关于狗的图像,但是无法区分到底是猫还是狗,只能告诉你是哪个类别的可能性更高(其实这张图里面既有猫又含有狗)。而对于一个目标检测器来说,它能准确的把这两种类别区分开,并能告诉你每个类别的物体具体位置在哪里:
因为目标检测的分类器只要专注于对目标框内部的东西做分类,而不需要关心目标框的外部干扰信息,通常可以给出每个目标非常准确的分类信息。因此,模型现在能够产生两个输出结果:
⒈ bounding box的回归结果
⒉ 可能的类别分布结果
真棒啊,又到了知识盲区bounding box,只能接着补充了。
什么是边框回归? 拆开来看一为边框一为回归,什么边框,就是下图的各种颜色的框;回归理解为逼近,如此什么是边框回归就清晰明了–目标检测过程中对产生的候选框以标注好的真实框为目标进行逼近的过程。
为什么要做边框回归? 通过对候选框做边框回归,可以使最终检测到的目标定位更加接近真实值,提高定位准确率。那么它的准确率拿什么衡量?IoU:Intersection over Union,通过这个名称我们大概可以猜到 IoU 的计算方法。IoU 计算的是 “预测的边框” 和 “真实的边框” 的交集和并集的比值。这就是衡量的标准。如下所示:
既然最终有俩个结果,损失函数自然也应该由俩部分组成:分类损失部分和回归损失部分,最后通过SGD进行优化。使用回归框进行单个目标预测结果较好,但是如果图中含有多个检测目标就会出现问题,如下:
这张图里面有两匹马,如果你的网络只能输出一个bounding box结果,那很有可能会是中间的那个黄色框,为什么会这样呢?因为你的网络只能输出一个目标框,但是图像中含有两个目标,这样网络就会非常为难,因为他不知道应该检测左边的马还是右边的马,这样网络经过训练后很有可能会采取一个折中的办法,得到中间黄色框的检测结果。可能你会说,那为什么不会得出一个大的检测框包含这两匹马,因为事实上我们的ground truth在标注的时候都是针对于单个物体的,那么网络经过训练后,输出的结果自然就会倾向于单个物体的bounding box而不是N多物体的。
有一种解决办法就是让网络多输出几个bounding boxes,每个bounding box对应着一个目标,那也许问题就解决了。然而,现实并不是这样的…比如下面这张图:
得到的检测结果又像黄色框那样,他们全在中间。这样也很合理,因为网络并不知道应该将哪个框对应到哪个物体上,没有我们想象的那么智能,于是就得到了上面的这个结果。所以说如果不采取一定的策略,即使输出再多的bounding boxes也没有什么用,他们最终的位置可能都会像黄色框那样,而不是想要的结果。
one-stage目标检测中有一种常用的方法,利用网格(grid)把图像分区域,每个区域内的bounding box只检测这个区域内的物体,Grid是one-stage目标检测中非常重要的部分之一了,他的功能有点类似于R-CNN里的region proposal,目的都是提供一定的候选区域,使得bounding box不会乱跑。使用固定网格上的检测器是one-stage检测算法的主要思想。
和大多数网络一样,我们会选取一个骨干网络提取特征,因为目标检测的特殊性,骨干网络会在某个图像分类的数据集上做训练,用于特征提取,比如ImageNet。像YOLO用416416的图像作为网络输入(SSD可能是300300),其实这些输入比传统的图像分类网络输入要大(图像分类的网络输入通常为224224),这样做是因为目标检测中有可能会含有比较小的物体,提高网络输入也是为了提取到更多小目标的特征。那可以剔除一个这样的网络:
前Layer1~Layer6都是你的骨干网络,骨干网络可以是很多种类:ResNet、Inception或者是YOLO的Darknet都可以,这些网络用于特征的提取。有时候为了追寻网络小型化和速度的提升,比如SqueezeNet和MobileNet。而LayerA ~ LayerC是目标检测部分,经过训练后用来预测边框和框内分类概率的。上图的模型已经可以用来构建快速且相当精确的目标检测模型。
假定我们就用上面的这个网络来做目标检测,经过网络的卷积等操作后,最终的输出结果可能是一个131325的feature map,就像下面这样:
我们称这1313的特征图的每一个点都是一个grid cell(也就是先前提到的grid)。而每一个grid有125个通道,这125个通道被分成了5个detector。那每个grid的作用就是:限定这每个detector只负责检测目标中心点坐标落在grid上的目标。这样就解决了之前我们提到的每个bounding box不知道应该负责检测哪个物体的问题。网格中每个单元格有5个独立的单元检测器,每个检测器都预测一个边界框。每个检测器产生25个值,分别是20个类别值,4个是边界框的值,还有一个置信度,525=125,这就是为什么有125个通道的原因。
通常分类器可能用softmax,但是值得注意的是像YOLOV3和SSD,将每个类别看做一个单独的任务,变成了多标签分类,用sigmoid取代了softmax。所谓的confidence score是detector是否包含目标的一个衡量值,这个值通常在0~1之间,表征了边界框包含了真实物体的可能性。这个分数只能说明边界框内有物体并没有说明是什么物体具体的分类需要后边确定。在yolo中这个值为0表明当前detector不含目标(或者说为背景),而在SSD中则是否包含目标归为了了classification中的一个类,即背景类。
至此,一共1313个grid,每个grid含有5个detector,共13135=845个detector,也就是说对于一个输入图像,将会有845个输出结果,这是一个固定的值也就是说该模型固定有845个输出结果,这些结果中可能大部分都是无用的,毕竟一张图片包含的目标是有限的。可以通过confidence score去除那些无用的输出结果,最终你的检测结果可能是这样的:
有一些检测框可能产生了重叠,这也是正常的,因为相邻的grid cell可能检测到了同一个物体而产生了两个结果。标准的后处理结果是非最大抑制处理(NMS),即通过设置一个NMS阈值,就能去除重叠的检测框。简而言之,NMS保留具有最大的置信度的预测框,并删除任何与之重叠超过一定阈值的预测框。这就是grid机制来限制检测结果不要“乱跑”,但是为什么这样做会有效呢?grid起到了约束的作用使得你的检测框不会“乱跑”,每个检测器各司其职。这样的策略在机器学习(尤其指深度学习)里是非常有效的技巧。
Grid的这种机制迫使网络的detector专注于检测图像中某些空间位置上的某些目标。在坐标回归的机制上(后面会讲到),detector只会检测中心坐标位于对应grid cell内的目标而永远不会原理当前的grid cell(当然这是通过训练得到的结果)。就像先前我们没用grid的机制的时候,检测框的结果就不会那么的准确(黄色框)。
anchor(也被称为anchor box)是在训练之前,在训练集上利用k-means等方法聚类出来的一组矩形框,代表数据集中目标主要分布的长宽尺度。在推理时生成的特征图上由这些anchor滑动提取n个候选矩形框再做进一步的分类和回归(详细叙述请参考提出anchor思想的fasterRCNN一文)。也就是传统目标检测算法中,在图像金字塔上使用的那个mn的滑窗。只不过传统方法中特征图是不同尺度的,滑窗一般是固定大小的;而类似于fasterRCNN算法中特征图是固定的,anchor是多尺度的。
除了grid之外,另一个能有效提升detector检测效率的就是Anchor。Grid相当于在空间位置上对detector增加了约束,而anchor则在每个detector所检测目标的形状大小上增加了一定的约束。anchor是在原图上的区域,而不是在特征图上(也就是特征图上一个点可以对应到原图上一个nn的区域)
前面的例子中我们的网络输出了13*13的grid,每个grid含有5个detector,但是为什么要输出5个detector而不是一个detector呢?事实上待检测目标可能位于图像的任意位置,同样的目标也会存在各种不同的大小,而对于每个detecotor来讲,每个grid中的目标大小是随机变化的,这种变化是很难通过训练来学习到。所以我们用anchor做一个类似于proposal的功能,尽量用anchor涵盖不同的物体大小,然后最终的检测结果针对于anchor做一个回归就可以了。
这五种形状的框就是anchor,以列表的形式记录:
anchors = [1.19, 1.99, # width, height for anchor 1
2.79, 4.60, # width, height for anchor 2
4.54, 8.93, # etc.
8.06, 5.29,
10.33, 10.65]
每个anchor含有两个值,分别代表anchor的宽和高。上面的5个anchor,最小的负责检测小而细长型的目标,最大的负责检测大而方正的目标。当然这不是绝对,实际上每个anchor检测的目标都是尺寸和形状上与之相似就行了。
这个地方要再说明一下,这个宽和高是相对于grid来讲的,或者说相对于你的最终feature map的大小,比如1.19对于1313的feature map,在原输入图像中其实对应的是1.1932=38这么大的一个框。另外,在YOLOv2中的anchor还是采用这种相对于grid的大小形式,在YOLOv3中,anchor的大小已经转换成了相对于实际输入图像的大小。在SSD中,则是将anchor的大小归一化到(0,1)的区间上,这样anchor的大小和grid的大小就无关了。
了解这些anchor是预先选择的,这一点很重要。它们是常数,在训练过程中不会改变。由于锚点只是宽度和高度,它们是预先选择的,因此YOLO论文也称它们为“尺寸先验”。(YOLO的官方源代码Darknet称它们为“偏见”,我认为是正确的-检测器偏向于预测某种形状的物体-但重载该术语会造成混淆。)
这一部分讲我们的网络是如何跟gird、anchor关联上以及如何通过网络的最终输出得到目标的位置及分类结果。
13*13对应着每一个grid,每个grid含有125个通道,并且被分成了5个detector,这5个detector,每个detector针对不同的anchor大小去做回归。每个detector含有25个通道即25个数值,这25个数值对应着4个位置坐标、1个confidence score置信度以及20个分类类别(对应VOC)。
我们从4个坐标开始说,对于目标的位置,通常可以采用两个坐标点比如:xmin,ymin,xmax,ymax的这种形式;也可以采用坐标点+宽高的表示形式比如:center x,center y,width,height。这两种形式都可以,但是本文会用到坐标点+宽高的这种表示形式。
模型预测的不是每个边界框的绝对位置而是四个偏移值。为什么是偏移值而不直接得出坐标呢?这其实和anchor有关系,前面说到anchor限定了每个detector负责检测目标的大小和形状,但是anchor并不是最终输出的目标框结果,真实的结果是在anchor的基础上加了一些“偏移”得到的。
结合anchor和偏移得到实际的目标框宽高,需要经过如下计算:
i, j是对应的grid序号,b是对应的5个detector序号 (index 0~4)。其中exp的作用是将坐标的偏移限定在大于0的范围内,可以假定有下面两种情况:
⒈ 当delta_w<0,0< exp(delta_w)<1,这样会使得实际的目标框结果小于anchor box;
⒉ 当delta_w>0,exp(delta_w)>1,实际目标框结果大于anchor box。
网络输入为416416,最终的输为1313,所以计算出来的结果还要乘以32才是最终相对于网络输入的目标框的宽高。因为在计算结果的时候用到了exp(),所以在计算loss的时候相对应的用到了log()。
注意这里用sigmoid把中心坐标的偏移限定在了0~1的范围内,这个偏移值其实是检测框中心坐标相对于每个grid cell左上角坐标序号的偏移。这也就是我们之前提到的,为什么每个grid只负责检测中心点落在grid范围内的目标。
SSD的计算方式:
可以注意到因为没有对delta_x和delta_y做sigmoid限制,这意味着目标框的坐标位置可以脱离grid cell的限制。并且还有一点不同的是,SSD中的中心坐标偏移值相对的是anchor的中心坐标(x,y)而不是grid cell的中心坐标。
以我们的网络为例,共有845个detector,但实际上绝大多数的detector都不会包含目标。在训练的过程中,我们会引导网络的每一个detector检测一个单独的目标,而confidence score则是表示该detector是否包含目标的置信度。因此最终你会发现,绝大多数detector的confidence score都比较小,只有个别的detector的confidence score会比较高。这样通过设置confidence的阈值可以剔除那些不包含目标的detector,我们只对检测到目标的detector做分析就可以了。
然后对于那些包含目标的detector的输出结果,通过softmax对类别进行判定即可:
最后根据confidence score和calssifacation的结果,我们可以得到某个detector中包含某种特定类别物体的概率,通常叫做confidence_in_class:
FPN是一种利用常规CNN模型来高效提取图片中各维度特征的方法。在计算机视觉学科中,多维度的目标检测一直以来都是通过将缩小或扩大后的不同维度图片作为输入来生成出反映不同维度信息的特征组合。这种办法确实也能有效地表达出图片之上的各种维度特征,但却对硬件计算能力及内存大小有较高要求,因此只能在有限的领域内部使用。
FPN通过利用常规CNN模型内部从底至上各个层对同一scale图片不同维度的特征表达结构,提出了一种可有效在单一图片视图下生成对其的多维度特征表达的方法。它可以有效地赋能常规CNN模型,从而可以生成出表达能力更强的feature maps以供下一阶段计算机视觉任务像object detection/semantic segmentation等来使用。本质上说它是一种加强主干网络CNN特征表达的方法。
上图(a)中的方法即为常规的生成一张图片的多维度特征组合的经典方法。即对某一输入图片我们通过压缩或放大从而形成不同维度的图片作为模型输入,使用同一模型对这些不同维度的图片分别处理后,最终再将这些分别得到的特征(feature maps)组合起来就得到了我们想要的可反映多维度信息的特征集。此种方法缺点在于需要对同一图片在更改维度后输入处理多次,因此对计算机的算力及内存大小都有较高要求。
图(b)中的方法则只拿单一维度的图片做为输入,然后经CNN模型处理后,拿最终一层的feature maps作为最终的特征集。显然此种方法只能得到单一维度的信息。优点是计算简单,对计算机算力及内存大小都无过高需求。此方法为大多数R-CNN系列目标检测方法所用像R-CNN/Fast-RCNN/Faster-RCNN等。因此最终这些模型对小维度的目标检测性能不是很好。
图©中的方法同样是拿单一维度的图片做为输入,不过最终选取用于接下来分类或检测任务时的特征组合时,此方法不只选用了最后一层的high level feature maps,同样也会选用稍靠下的反映图片low level 信息的feature maps。然后将这些不同层次(反映不同level的图片信息)的特征简单合并起来(一般为concat处理),用于最终的特征组合输出。此方法可见于SSD当中。不过SSD在选取层特征时都选用了较高层次的网络。比如在它以VGG16作为主干网络的检测模型里面所选用的最低的Convolution的层为Conv4,这样一些具有更低级别信息的层特征像Conv2/Conv3就被它给漏掉了,于是它对更小维度的目标检测效果就不大好。
图(d)中的方法同图©中的方法有些类似,也是拿单一维度的图片作为输入,然后它会选取所有层的特征来处理然后再联合起来做为最终的特征输出组合。(作者在论文中拿Resnet为实例时并没选用Conv1层,那是为了算力及内存上的考虑,毕竟Conv1层的size还是比较大的,所包含的特征跟直接的图片像素信息也过于接近)。另外还对这些反映不同级别图片信息的各层自上向下进行了再处理以能更好地组合从而形成较好的特征表达(详细过程会在下面章节中进一步介绍)。而此方法正是我们本文中要讲的FPN CNN特征提取方法。
FPN会使用CNN网络中每一层的信息来生成最后的表达特征组合。下图是它的基本架构。从中我们能看到FPN会模型每个CNN层的特征输出进行处理以生成反映此维度信息的特征。而自上至下处理后所生成出的特征之间也有个关联关系,即上层high level的特征会影响下一层次的low level特征表达。最终所有的特征一起用来作为下一步的目标检测或类别分析等任务的输入。
FPN是传统CNN网络对图片信息进行表达输出的一种增强。它目的是为了改进CNN网络的特征提取方式,从而可以使最终输出的特征更好地表示出输入图片各个维度的信息。它的基本过程有三个分别为:自下至上的通路即自下至上的不同维度特征生成;自上至下的通路即自上至下的特征补充增强;CNN网络层特征与最终输出的各维度特征之间的关联表达。
我们在下图中能看出这三个过程的细粒度表示。
自下至上的通路(Bottom-top pathway):这个没啥奇怪就是指的普通CNN特征自底至上逐层浓缩表达特征的一个过程。此过程很早即被认识到了即较底的层反映较浅层次的图片信息特征像边缘等;较高的层则反映较深层次的图片特征像物体轮廓、乃至类别等;
自上至下的通路(Top-bottome pathway):上层的特征输出一般其feature map size比较小,但却能表示更大维度(同时也是更加high level)的图片信息。此类high level信息经实验证明能够对后续的目标检测、物体分类等任务发挥关键作用。因此我们在处理每一层信息时会参考上一层的high level信息做为其输入(这里只是在将上层feature map等比例放大后再与本层的feature maps做element wise相加);
CNN层特征与每一级别输出之间的表达关联:在这里作者实验表明使用1x1的Conv即可生成较好的输出特征,它可有效地降低中间层次的channels 数目。最终这些1x1的Convs使得我们输出不同维度的各个feature maps有着相同的channels数目(本文用到的Resnet-101主干网络中,各个层次特征的最终输出channels数目为256)。
参考文献:
1.《关于one-stage目标检测方法的详细解析(一)》
2.《边框回归(Bounding Box Regression)详解》
3.《FPN: 一种高效的CNN特征提取方法》
4.《目标检测 1 : 目标检测中的Anchor详解》
5.RPN(区域生成网络)