在计算机视觉中,目标检测是一个难题。在大型项目中,首先须要先进行目标检测,获得对应类别和坐标后,才进行以后的各类分析。如人脸识别,一般是首先人脸检测,获得人脸的目标框,再对此目标框进行人脸识别。若是该物体都不能检测获得,则后续的分析就无从入手。所以,目标检测占据着十分重要的地位。在目标检测算法中,一般能够分红One-Stage单阶段和Two-Stage双阶段。而在实际中,我常常接触到的是One-Stage算法,如YOLO,SSD等。接下来,对常接触到的这部分One-stage单阶段目标检测算法进行小结。本文one stage检测算法包括有YOLO系列,SSD,FSSD,DSOD,Tiny DSOD,RefineNet,FCOS。html
YOLO能够说是最先的One-stage目标检测算法之一,通过做者的优化,存在3个版本。git
Yolo v1在《You Only Look Once: Unified, Real-Time Object Detection》中提出。在Yolo以前的目标检测算法,如R-CNN系列,其网络相对比较复杂,耗时大,难以优化(由于每一个单独的部分是独立训练的)。所以,做者将目标检测认为是一个独立的回归任务,回归每一个分离的预测框坐标及其对应的类别几率,使其具备如下的优势:github
介绍完Yolo的优势后,咱们来看看其思想,以下图所示。首先,Yolo将一张输入图片分红S*S格。若是GT框的中心落在某格(grid cell)上,则该格负责预测这个目标。每格会预测B个预测框及B个置信度得分。该置信度得分反映的是该格包含物体的置信度和这个预测框有多准。所以,对于该置信度得分,其定义为$Pr(Object)*IOU^{truth}_{pred}$。若是没有物体的中心在该格上,则该置信度得分为0;若是有物体的中心在该格上,则咱们但愿置信度得分等于IOU。所以,对于每一个预测框而言,都会预测5个值,分别是中心点$(x,y)$,宽高$(w,h)$,和上述的置信度得分。算法
对于每格而言,除了预测B个预测框及其置信度外,还会预测C个类别的条件几率$Pr(Class_i|Object)$。以VOC0712为例,就会预测$C=20$个类别的几率。这个几率是条件几率,在存在目标的前提下,其为第i类的几率。每格会共用这样的几率,与B个预测框无关。在测试阶段,每格类别的置信度得分等于类别的条件几率乘以每格预测框的置信度得分:网络
$$Pr(Class_i|Object)*Pr(Object)*IOU^{truth}_{pred}=Pr(Class_i)*IOU^{truth}_{pred}$$框架
能够看出,每格类别的置信度不只表示了这个类别出现的几率,并且也反映了预测框是否拟合GT框。ide
在该论文中,$S=7,B=2$,因此最后输出的是$7*7*30$的张量,能够当作是49个30维的向量,这30维的向量包含了以下图的信息。函数
值得留意的是,Yolo并无预设不一样大小的anchor。网络进行前向运算后,每格会输出2个预测框,将该预测框与GT框进行匹对和计算IOU,此时才能肯定使用IOU大的那个预测框来负责预测该对象。所以,Yolo的损失函数是各项偏差平方和的一个加权:性能
其中,$1^{obj}_i$表示物体的中心是否位于第i格,$1^{obj}_{ij}$表示第i个格子的第j个预测框中存在对象,$1^{noobj}_{ij}$表示第i格子的第j个预测框中不存在对象。损失函数的第一项表示当第i个格子的第j个预测框中存在对象时,其中心点偏移的偏差;第二项表示当第i个格子的第j个预测框中存在对象时,宽高的偏差;第三项表示当第i个格子的第j个预测框中存在对象时,其置信度得分偏差,真实的$C_i$应该等于IOU;第四项表示当第i格子的第j个预测框中不存在对象时,其置信度得分偏差,真实的$C_i$应该等于0;第五项表示当物体中心在第i格时,其类别偏差。其中,还有$\lambda _{coord}$调整预测框位置偏差的权重,$\lambda _{noobject}$调整不存在目标的预测框的置信度权重,通常是调低不存在对象的预测框的置信度偏差的权重。学习
Yolo v1的不足:
参考资料:
Yolo v2在《YOLO9000: Better, Faster, Stronger》中提出。为了解决Yolo v1的不足,做者使用了融合了多种思路来提升了网络的性能,使得mAP获得大幅度提高;为了加快推理速度,使用新的模型结构;为了能检测出更多的对象,提出了新的联合训练机制,结合分类数据集(如ImageNet)和检测数据集(如COCO和VOC),使得YOLO V2能检测出更多的类别。
在提升网络性能上,做者使用了如下的思路:
将上述的思想融合起来,最终的实验效果以下图所示。实验效果的增幅仍是挺明显的,将v2提升了近15个点的mAP。
做者不只想让Yolo v2的mAP更高,并且还想让其更快。在v1中,使用的网络结构是基于Inception的,其速度比VGG快,但性能略逊色于VGG。所以,做者提出了新的分类网络,Darknet-19,做为Yolo v2的主干网络,以下图所示。该网络中含有19个卷积层和5个池化层。
YOLO v2的训练主要包括三个阶段。第一阶段就是先在ImageNet分类数据集上预训练Darknet-19,此时模型输入为224*224 ,共训练160个epochs。而后第二阶段将网络的输入调整为448*448 ,继续在ImageNet数据集上finetune分类模型,训练10个epochs,此时分类模型的top-1准确度为76.5%,而top-5准确度为93.3%。第三个阶段就是修改Darknet-19分类模型为检测模型,移除最后一个卷积层、global avgpooling层以及softmax层,而且新增了三个 3*3*1024卷积层,同时增长了一个pass through层,最后使用 1*1 卷积层输出预测结果,输出的channels数为:num_anchors*(5+num_classes) ,和训练采用的数据集有关系。因为anchors数为5,对于VOC数据集(20种分类对象)输出的channels数就是125,最终的预测矩阵T的shape为 (batch_size, 13, 13, 125),能够先将其reshape为 (batch_size, 13, 13, 5, 25) ,其中 T[:, :, :, :, 0:4] 为边界框的位置和大小$(t_x,t_y,t_w,t_y)$,T[:, :, :, :, 4] 为边界框的置信度,而 T[:, :, :, :, 5:] 为类别预测值。
在VOC数据集中,只有20类物体能够进行检测。但实际生活中,物体的类别数是远远大于20种的。所以做者想结合分类数据集和检测数据集来进行联合训练,使得检测的类别数能大幅度提升。这种联合训练方式的基本思想是,若是是检测样本,其loss就包含分类偏差和定位偏差;若是是分类样本,其loss就只包含分类偏差。
因为我没有对这一块作过多研究,了解不深。但该方法最主要的是构建Word Tree。由于数据集的不一样,致使每一个标签之间不是互斥的,存在包含关系,例如在COCO数据集中的一个类别是“狗”,而在ImageNet中包含了多种狗的标签。因此,经过构建word tree来将全部标签信息串联起来,相似于“树”的结构,父节点包含了不一样类别的子结构。
参考资料:
Yolo v3提出于《YOLOv3: An Incremental Improvement》中,在v2版本上,进一步进行了改进,整体来讲,改进力度有限,下面来分别看看这些改进措施。
首先,在预测类别时,不使用softmax,而是使用logistic进行预测。由于这样有利于多标签预测。当使用复杂领域的数据集时,可能会出现标签不互斥的状况(如woman和person),使用多标签的方法会更加有利于模型,即便用logistic
第二,使用了新的网络Darknet-53,以下图所示。在v2中,使用的backbone是Darknet-19,而在v3中,不只网络层数增长了,并且还借鉴了ResNet的思想,使用多个连续的3*3和1*1卷积层,而且带有shortcut链接。根据做者提供的实验比较,在ImageNet中,Darknet-53具备与ResNet-152类似的准确率,但速度是其两倍。
第三,利用多尺度信息来进行预测。这里借用一下这位博主的图,其总体的网络结构,以下图所示。在v3中,利用了不一样尺度的信息进行预测,我认为做者的这种方式,其应该是借鉴了FPN的思想。使用3个尺度的特征图进行预测,如图上黄色方块表示的同样,在第79层后,进行上采样,上采样获得的特征图与第61层的特征图进行融合,再进行上采样,与第36层的特征图融合。
第四,使用K-means聚类获得锚点框的尺寸。和v2版本采用方法一致,v3这里使用了3个不一样尺寸的特征图进行预测,在每层特征图中使用3种不一样尺寸的锚点框,如下图所示。为小尺寸的特征图分配大尺寸的锚点框,适合检测大目标;为大尺寸的特征图分配小尺寸的锚点框,适合检测小目标。
以COCO为例,v3使用3个特征图来进行预测,每一个特征图会对应3种锚点框,所以,对于每层特征图,其输出的tensor为$N*N*[3*(4+1+80)]$,其中,$N$表示特征图的尺寸,$3$表示3个锚点框,$4$表示4个坐标值,$1$表示是否包含物体的置信度(v3的置信度貌似与v1中的置信度不同),$80$表示COCO数据集的类别总数。
参考资料:
SSD算法提出于《SSD:Single Shot MultiBox Detector》 中,一样是一篇很是经典的one stage目标检测算法,其框架也衍生出了不少系列。以前,我曾经对SSD进行过总结和代码复现,想仔细了解的能够参考来阅读如下,这里主要是归纳性回顾如下。
以下图所示,是SSD的框架网络,其使用了6个不一样尺寸的特征图来进行预测,分别是$(38*38),(19*19),(10*10),(5*5),(3*3),(1*1)$。这6个特征层会分别通过3*3的卷积后分红分类头和检测头,分别用于预测坐标误差值和类别置信度(包含背景)。相比于YOLO V1和YOLO V2,SSD使用了多个特征层,更适合检测多种不一样尺度的目标。
其次,在这6个不一样尺寸的特征图中,还使用了不一样大小和宽高比的锚点框。每一个特征图使用不一样于其余层的锚点框尺寸,而在该尺寸上又设置4种或者6种不一样的宽高比。在大尺寸特征图是同小尺寸的锚点框,来检测小目标;在小尺寸的特征图使用大尺寸的锚点框,来检测大目标。这样的设置方式,日后不少SSD系列都采起这种方式。所以,整个SSD中,会检测8732个锚点框的坐标误差值和类别置信度。
第三,使用了OHEM进行难例挖掘,来缓解正负样本的不平衡。在SSD中,并无使用全部的负样本,而是将这些匹配上背景的样本根据置信度损失进行降序排列,将损失较大的样本认为是难例(hard negative),须要模型重点学习。选取损失最大的前N个样本做为负样本,正样本与负样本的比例控制在1:3左右,对于那些没有选上的样本,label设置成-1,不参与训练当中。
做者还强调了数据加强对网络性能有着明显提高。能够这么理解,经过数据加强,间接提升了数据量和样本之间的多样性,从而提升了模型的鲁棒性。另外,空洞卷积一样能够提升了SSD的mAP,经过空洞卷积,是能在参数量不变的前提下感觉野变大,使网络能“看”到的东西更多。
FSSD提出于《FSSD: Feature Fusion Single Shot Multibox Detector》中,使用了轻量化的FPN结构,来提升SSD的小目标检测效果。
在SSD中,对小目标的检测效果不佳,召回率低。由于小目标一般是浅层网络来进行预测的,特征抽象能力不足,缺少语义信息;其次,小目标检测一般严重依赖于上下文信息。所以,FPN的提出是为了使浅层特征和深层特征进行融合,更好的辅助浅层特征来进行目标检测,进而提升小目标的检测效果。FPN的结构以下图的(c)所示。(b)是YOLO v1和v2系列的结构示意图;(d)是SSD系列的结构示意图。
在FPN结构中,右边的特征层是只由上一层的右边特征层和同一层的左边特征层进行融合的,缺少不一样层特征层之间的融合;其次,上一层的右边特征层和同一层的左边特征层的融合是十分耗时的。所以,在FPN的基础上,做者提出了一种轻量化的FPN结构,与SSD进行结合,构成了FSSD,如上图的(e)所示。FSSD的主要思想是,以合适的方式一次性融合全部不一样层级的特征层,而后基于此特征层来生成特征金字塔。
FSSD的网络结构以下图所示。做者认为当特征图的尺寸小于$10*10$时,信息特征太少,对特征融合增益不大,所以,使用了conv3_3,conv4_3,fc_7和conv7_2四个特征层来进行融合(图中只画了3个)。首先对这4个特征层进行$1*1$卷积来下降通道数,下降到256维。而后以conv4_3的特征图尺寸$38*38$为基础,其它特征层进行下采样或者上采样来是特征图的尺寸变成$38*38$,至此,全部图中黄色的特征图都有了相同的特征图空间尺寸了。
而后对这4个黄色特征图进行融合,融合方式有两种:concat或者ele-sum。经过实验发现,concat的效果更好。所以,将这4个黄色特征图进行concat起来,构成了$38*38*1024$的tensor。因为不一样层的特征图的分布是不一致的,所以,对这$38*38*1024$的tensor进行BN操做。最后对融合后的特征层进行下采样(论文中使用bottlenet结构来进行下采样),产生绿色的特征层,使用这些不一样尺寸的绿色特征层来进行目标检测。
最终实验代表在牺牲少许速度的前提下,FSSD的mAP比原版的SSD要高,特别是对小目标的召回率提升了不少。
DSOD提出于《DSOD: Learning Deeply Supervised Object Detectors from Scratch》中。目前,大部分目标检测算法都须要使用预训练模型来提升检测效果。可是因为分类任务和检测任务的损失函数的类别分布不一样,使用预训练模型会引入学习误差;同时当分类场景和检测场景具备很大差别时,使用预训练模型的效果也不佳。所以,最好的办法是对检测网络进行从头训练,不使用预训练模型。为此,做者提出了DSOD模型来解决从头开始训练的问题。
DSOD的结构以下图的右边所示,左边是SSD的网络结构,右边是DSOD的网络结构。能够看出,DSOD的结构与SSD十分相似,但其主干网络是DenseNet。前面两个特征层是DenseNet主干网络生成的,第1个特征层一路直接送到预测中,另一路通过pool和conv层后,与第2个特征成concat后再送入预测。随后,会分红2条支路,一路流经pool和conv来进行dowm-sample,另一路输入到$1*1$和$3*3$的卷积中;两路进行concat后再送入预测。
最后,做者总结了下,解决从头训练问题的几条原则:
综上所述,做者利用DenseNet做为主干网络,提出了DSOD算法,解决了从头训练的问题。
Tiny DSOD提出于《Tiny-DSOD: Lightweight Object Detection for Resource-Restricted Usages》。目前不少目标检测算法对计算资源有限的硬件设备都不太有友好,所以,做者在DSOD的基础上,提出了轻量化的目标检测网络Tiny DSOD。该Tiny DSOD引入了两个创新且高效的结构:depthwise dense block (DDB)和depthwise feature-pyramid-network (D-FPN)。
首先,在DSOD中,使用的主干网络是DenseNet,其结构以下图所示。输入分红两路,通过$1*1*C$和$3*3*C/4$的卷积后,输出C/4个通道的tensor,而后与输入进行concat。这样作的计算成本大。
受到MobileNet的启发,做者将深度可分离卷积融合进DenseNet中,并命名为DDB结构。该DDB结构有两种形式,以下图所示。其中,DDB-a中含有倒残差结构的思想,先将有n个通道的输入扩大至$w*n$个通道,$w$表示人为设置的超参,用于控制扩张倍数;而后进行$3*3$的卷积;接着进行$1*1$的卷积,但通道数降至$g$;最后将二者进行concat,造成$n+g$个通道的特征图。能够认为$g$表示DDB-a的增加率。可是,这种结构DDB-a的复杂度是$O(L^3g^2)$,随着网络层数$L$的增长,计算资源消耗也会快速增长,因此要控制增加率$g$,将$g$约束在较小的值。然而,增加率$g$较小,又会使模型的泛化能力变差。
基于上述的考虑,又提出了DDB-b这种结构。输入首先会压缩成$g$维,而后进行$3*3$的卷积,最后将二者进行concat起来,造成$n+g$维的输出。所以,总体的复杂度为$O(L^2g^2)$。在实验中发现,DDB-b这种结构不只更加高效,并且在资源有限的状况下准确率更高。所以,在Tiny DSOD中,使用了DDB-b这种结构。
所以,Tiny DSOD的网络结构以下图所示。对于增加率$g$值而言,做者采用了浅层网络使用小$g$值、深层网络采用大$g$值得策略。由于浅层网络的特征图尺寸大,须要消耗更多的计算资源,而$g$值比较小时,能节省部分计算计算。
Tiny DSOD的另一个结构是D-FPN,以下图所示。结合了FPN的思想,设计了一种轻量化的D-FPN结构,来使深层次的语义信息与浅层特征进行融合。这里的downsample结构与DSOD的结构相似,利用多分枝思想,融合不一样感觉野的信息,可是与DSOD不一样的是,输出的通道维数变小了和使用了深度可分离卷积。
综上所示,在DSOD基础上,Tiny DSOD融合了DDB结构和FPN结构,下降计算资源的前提下,同时也提升检测效果。
RefineDet提出于《Single-Shot Refinement Neural Network for Object Detection》中。总所周知,two stage目标检测器能实现较高的精度,而FPS较慢;one stage目标检测器的FPS很高,但却牺牲必定精度。two stage能取得较高的精度,是由于:
所以,做者对one stage和two stage目标检测器进行取长补短,提出了RefineDet,结构以下图所示,能实现比two stage检测器更高的精度,且能保持较好的运行效率。其中,主要由两个模块组成:anchor refiement module (ARM)和object detection module (ODM)。
ARM模块主要负责:
ARM模块会先对锚点框进行判断,判断锚点框内是否含有物体,属于二分类;而后再粗调锚点框的位置,来传递给ODM来进一步二次回归。其实这ARM的做用,有点相似Faster R-CNN中的RPN模块。若是ARM中预测出该锚点框属于背景的置信度大于必定阈值时,就会忽略这个锚点框。也就是ARM模块只会给ODM模块传递粗调过的难负例锚点框和粗调过的正锚点框。
而ODM模块主要负责将粗调过的锚点框来对其进行二次坐标回归和类别预测。如图中绿色带星星的方块图,星星表示粗调后的锚点框,传递给ODM,ODM在这基础上来进一步预测。
同时,做者还借鉴了FPN的思想,设计了transfer connection block (TCB)来将ARM中的特征传递给ODM,能够看到,其将深层语义与浅层语义进行融合,这样应该会进一步提升模型的性能。
FCOS提出于《FCOS: Fully Convolutional One-Stage Object Detection》中,是一种anchor-free的检测模型。目前,大部分检测模型都是基于预设的锚点框,如SSD系列,做者就思考:目标检测算法是否必定须要锚点框才能取得较好的性能?而基于锚点框的目标检测算法,具备如下的不足:
所以,做者基于全卷积网络,提出FOCS检测模型。该FCOS会在每层特征图的每一个特征点上预测四维向量和类别,以下图的左边所示。这四维向量是$(l,t,r,b)$,分别表示该点到检测框四条边的相对距离。同时,当该像素点远离GT框的中心点位置时,会产生不少低质量的预测框。为了抑制这些低质量的预测框,在网络中引入了一个分支“center-ness”,来预测像素点到目标框中心的偏移程度,以此来下降低质量预测框的权重。
所以,FCOS的网络结构,以下图所示。FCOS结合了FPN模块,并对FPN模块进行了相应的修改,$(P6,P7)$是经过$P5$下采样获得的。而后会分红分类头和回归头,分别是4组卷积。最后在分类头处,还有一个Center-ness的分支。
对于特征图$F_i$的每一个位置$(x,y)$,会映射回原图的$\left (\left \lfloor \frac{s}{2} \right \rfloor +xs,\left \lfloor \frac{s}{2} \right \rfloor +ys\right )$,其中$s$表示该特征层的下采样率。当映射回去后,若是该点位于GT框内,则认为其是正样本,与GT框的标签一致,直接进行回归与预测。若是改变位于多个GT框的交集区域,就将该点指定给面积最小的那个GT框。因为回归的值老是正值,所以在回归头处采用了$e^x$对坐标值进行映射。使用anchor-free这种方式,使负样本的数量减小,有利于正负样本之间的平衡。同时,对于anchor-based的方式,每一个特征点有6个或者9个锚点框须要预测,而anchor-free则只需回归一次,总体输出少了9倍左右。
在FCOS中的FPN起到了很重要的做用,主要解决了如下两个大问题:
使用了FPN的FCOS,须要在不一样特征层处预测不一样大小的物体。不像anchor-based那样,为每层特征层指定不一样大小的锚点框。FCOS则是首先为每一个特征图的位置点计算须要回归的距离$(l^*,t^*,r^*,b^*)$。当$m_{i-1}<max(l^*,t^*,r^*,b^*)<m_i$时,才会认为该点是正样本,送入回归。其中,$m_i$表示第$i$层特征图的最大回归距离。即回归的4个值中的最大值须要位于两个特征层的最大回归距离之间。也能够理解成该特征层只对大小为$[m_{i-1},m_i]$的物体进行回归。当这个最大值超出最大回归距离范围之间时,就认为是负样本,不进行训练。这样作是由于应该对回归进行限制,不可能无限制的回归,进行大值回归可能效果很差,与锚点框的思想一致。
在最后进行预测和回归的时候,FPN中不一样特征层共享同一个head(即那4组卷积),这样作不只节省了参数,并且还提升了检测性能。可是,不一样特征层用来回归不一样尺寸的目标,让全部特征层共享一个head彷佛不太合理。所以,做者使用了一组能够训练的变量$s_i$来为每层特征层自动调整指数函数的底,因此,在回归头处使用的指数函数再也不是$e^x$,而是$e^{s_ix}$。
即便使用了FPN,FCOS的性能依然与anchor-based的检测器有差距,缘由是远离目标中的为位置会产生大量低质量的预测框,就是离目标中心越远,预测框的效果反而更差。所以,做者想要在不引入超参的状况下,抑制这些低质量的检测框,其作法就是引入了一条分支Center-ness。这条Center-ness分支输出一个$H\times W\times 1$的tensor,表示该点到目标中心点的“距离权重”,以下图所示,“距离权重”的值在$[0,1]$之间。在测试的时候,最终输出的分数应该是Center-ness与分类置信度的得分进行相乘。因此,Center-ness能起到下降远离目标中心的得分权重的做用。而Center-ness的另外一种替代形式是只使用真实框中心的附近点做为正样本,人为引入一个超参来抑制远距离的特征点的影响。做者发现,将这两种方式进行结合起来使用,能取得更佳的效果。
$$centerness^*=\sqrt{\frac{min(l^*,r^*)}{max(l^*,r^*)}\times \frac{min(t^*,b^*)}{max(t^*,b^*)}}$$
最终损失函数的组成应该有3部分,分别是置信度损失、回归损失和centerness损失(二值交叉熵损失)。其中,$\lambda $和$\alpha $分别平衡二者的权重。能够看出,损失函数中都是只是用正样本参与计算。在源码中计算损失函数时,centerness层的值除了计算二值交叉熵损失外,还会与回归损失进行结合,下降远离中心点的特征点的回归损失。而在测试时,centerness层的值直接与置信度相乘,使用相乘后的置信度来进行后处理。
$$Loss=\frac{1}{N_{pos}}\sum_{x,y}L_{cls}(p_{x,y},c^*_{x,y})+\frac{\lambda }{N_{pos}}\sum_{x,y}\mathbb{I}_{c^*_{x,y}}L_{reg}(t_{x,y},t^*_{x,y})+\alpha L_{center-ness}(d,d^*)$$
下图是FCOS算法的性能,能够看出,在不采起改进措施的前提下,FCOS已经能和RetinaNet媲美了。在使用了(a)center-ness层放在回归头处、(b)只在目标框的中心附近采样、(c)使用GIOU做为回归损失函数、(d)标准化目标回归函数,等改进措施后,性能更是进一步提升。
参考资料:
以上我是在以为在one stage目标检测中比较经典的算法,为此特地准备回顾了一下。欢迎批评指教。