(1)RCNN(2014)
Object Detection任务主要包含两个内容:识别物体,确定位置。在识别物体这一块,传统的做法是利用特征点来表征物体的类,例如:SIFT,SURF等;在CNN方法出现之后,普遍采用“卷积+池化+全连接”的方式来完成。而对于确定物体的位置,最流行的就是莫过于Region Proposal Regression,在图像中产生一系列的候选框,然后利用回归/分类的方式找到最合适的那个box。基于目标检测中的“识别+定位”任务,RCNN提出了下图所示的方法。
总体而言,RCNN的流程分为三步:
详细来说,在第一步会产生大约2000个左右的 Region Proposal,所使用的方法是 Selective Search(SS,选择性搜索)。在第二步中对 proposal 进行 crop/warp 操作将其处理到固定大小 227*227,以此作为 CNN 的输入;CNN 模型包括5个卷积、2个全连接,由此得到每一个 proposal 的特征,其大小为 4096 维。第三步中分类采取 SVM 方法,将 proposal feature 送入每一类的 SVM 判断它是否属于该类别,它会对该区域所属类别进行打分,利用 NMS 找到那些最有可能的 proposal;起初 proposal 的位置跟 Groundtruth 会有区别,在每一次迭代学习过程中使用 Bounding Box Regression 的方法对其进行修正:构建一个线性回归器,将 region feature 作为输入,计算得到 proposal 在当前位置上的缩放和偏移尺寸,然后进行更新。
Selective Search 是产生Region Proposal的一种方法,和它相同地位的还有:穷举搜索、sliding window等。
SS方法先是通过图像分割的方法得到一个区域集R,该集合中的每一个元素都是原图像在像素级别上的一个segmentation,看起来就跟油画一样是不能够作为Regina Proposal的(有部位上的重叠、包含、遮挡等)。
SS给R的每一个元素套上一个Box,然后计算相邻区域的相似度(基于颜色、纹理、尺寸、形状)得到一个相似度集S,根据S挑选出相似度最高的两个区域 r i 、 r j r_i、r_j ri、rj;二者合并得到 r t r_t rt 后,将 r t r_t rt 加入集合R,然后把S中与 r i 、 r j r_i、r_j ri、rj 相关联的部分全部去掉,重新计算 r t r_t rt 与相邻区域的相似度、并加入S;反复迭代,直到S为空。
RCNN的问题在于:
之后的SPP-Net(Spatial Pyramid Pooling,作者:何凯明)针对RCNN的第二、三点问题进行改进,它把提取到的 Region Proposal 的位置信息放在CNN卷积之后,让CNN先针对整体图像计算特征,然后将位置信息通过比例映射到整张图的 feature map上提取出候选区域的特征图,这样就不用针对每一个候选区域计算特征图了;其次,取消对 proposal 的 crop/warp 操作,这样 proposal 的大小就各不相同,所以要在全连接之前加入 SPP 层,保证全连接层接收到的特征尺寸不变。
(1)一般我们要求输入CNN的图像尺寸保持一致,实际上这种硬性需求与卷积层无关,而是全连接层的需求。因为卷积层只要指定卷积核大小、步长后,图像多大都无所谓,但是全连接层它要把特征拼接成一个特定维度的向量,如果输入特征尺寸不同那么所需要的参数量也不相同。
(2)SPP全称是Spatial Pyramid Pooling(空间金字塔池化),它加在全连接层之前。具体来说,对于任意一个维度的特征,它将对其做三种分割:4*4、2*2、1*1,依次可以得到16、4、1个网格,然后在这21(在RCNN中,有20个目标类别,外加一个背景类)个网格中分别进行最大池化得到一个一维的值,将这21个值拼接成一个21维向量最为最终输入全连接层的特征。
(2)Fast RCNN(2015)
Fast RCNN借鉴了SPP的思想,在 RCNN 的基础上做出以下改进:
Fast RCNN的整体框架如下图所示,相比较于RCNN而言它弥补了RCNN的很多缺陷,但是仍然采用 selective search 的方法来提取 Region Proposal,这也成为它在速度方面的最大限制。
(3)Faster RCNN(2015)
相比于 Fast RCNN,Faster RCNN 的改变主要在以下两点:
下图给出了 Faster RCNN 的整体框架,其主要改进点落在 RPN,而 RPN 中最富新意的就是锚框Anchor。
Faster RCNN 网络接受任意尺寸的图像作为输入,通过卷积操作计算得到该图像的feature map,随后将 feature map 输送给 RoI 的同时共享给 RPN。RPN 会先在 feature map 的每一个像素点上产生 9 个固定尺寸大小的锚框 anchor,如上图右上角所示;对于每一个锚框,RPN 会进行两个操作:(1) 利用 softmax 判断锚框所选区域是前景还是背景;(2) 对锚框所选区域内的特征进行边框回归。softmax 给出二分类概率值,边框回归对锚框进行位置偏移得到预测框 x y w h xywh xywh。接着对预测框进行筛选:先利用前景分类概率 foreground score 进行排序,根据 top-k 输出一定数量的预测框;然后将预测框对应的 anchor 在特征图中的位置映射回原始图像,剔除掉那些严重越界的预测框;最后用非极大值抑制 NMS 再次筛选,输出最终的Region Proposal。得到 proposal 以后,后续操作就跟 Fast RCNN 一样了。
RPN 在 Faster RCNN 中独立完成训练,它的训练方法、训练数据、训练过程都是独立的,训练好了之后直接把它嵌入在Faster RCNN中。
Mask RCNN 是何凯明基于 Faster RCNN 模型提出来的一种 Instance Segmentation(实例分割)方法。
Object Detection:目标检测,输出图像中个体的bounding box。
Semantic Segmentation:语义分割,输出像素级别的类归属。
Instance Segmentation:实例分割,输出像素级别的类归属以及类的实体ID,就是给出每一个实例的轮廓。
上图左边给出了 Mask RCNN 的模型结构,大体上沿袭了 Faster RCNN 的框架思路,不同之处在于:
(1)RoI Align 代替 ROI Pooling
之前 Fast/Faster RCNN 在全连接层之前都采用 RoI Pooling,这可以使得模型能够接受任意尺寸大小的图像作为输入。但是,该方法有两个量化问题:(1) RPN 方法得到的锚框 anchor 需要进行边框回归,回归结果是一个浮点数,在映射到 feature map 上时需要做舍入;(2) 网格的划分直接采用 w / W 、 h / H w/W、h/H w/W、h/H,也需要进行舍入。
这两次量化会直接影响 proposal 的准确性。RoI Align的做法是:回归和网格划分还是照做,但是不再进行舍入,而是在网格(位置大小均是浮点数)内找四个位置固定的虚拟坐标点,这四个点的特征值由网格内的真实特征点根据双线性插值计算得到,然后对这四个虚拟特征点做 max pooling 操作。当然了,不一定非要是4个虚拟特征点,实际上只用网格中心点的双线性插值也可以达到相类似的效果。
(2)加入 mask 分支
Faster RCNN 在全连接之后通过两个分支分别输出 proposal 的类别和预测位置,Mask RCNN 在此基础上增加一个 mask 分支,该分支利用 FCN 对 proposal 特征图中的每一个像素进行分类。原始的 FCN 中用的是 softmax 和交叉熵,Mask RCNN 为了避免同类间的竞争,采用了 sigmoid,并对每个 proposal 区域输出 k ∗ m ∗ m k*m*m k∗m∗m 维度的mask, k k k 是类别数量, m m m 就是 proposal 经过 RoI Align 得到的特征图的尺寸,将特征图的点映射回原始图像,就能得到原始图每个像素点的类别。因为该分支输出了针对每一类的 mask,这样就不涉及像素之间的类别竞争。要注意的是, L m a s k L_{mask} Lmask 在计算时只针对 proposal 所属的第 k k k 类,其他类 mask 不参与损失函数计算。
关于FCN:
(1)FCN是Semantic Segmentation的里程碑之作,它对图像进行像素级的分类,解决了语义级别的图像分割。
(2)FCN不包含全连接层,只有卷积层,在最后一个卷积层的后面接一个反卷积层,将feature map还原到原始图像尺寸大小,对每一个像素进行预测,最后逐像素求softmax损失,这就相当于每一个像素就是一个样本。
Mask RCNN 的特征提取网络使用的是 ResNet101,同时文章也给出 FPN 的同等对比方案,因为 FPN 能融合不同尺度上的特征,所以它能提炼更加丰富的上下文信息。
关于FPN:
一般的特征预测可以有三种形式:(1)采用网络最后一层的特征预测,典型的有SPP、Fast/er RCNN;(2)图像金字塔,每一种图像尺寸进行一次特征预测;(3)多尺度融合,每一层特征进行一次预测,不同层之间没有联系,典型的有SSD。
FPN(Feature Pyramid Network),特征金字塔网络,顶层特征通过上采样和底层特征进行融合,层与层之间有相互联系。
Mask RCNN的Tensorflow版本开源下载地址。
代码写的很清晰、很整洁,不管能不能理解原理,先让它跑起来再说,看一下结果。
此项目依赖于COCO,其配置方式为:
Mask RCNN的官方源码在Detectron,Detectron是Facebook的开源物体检测平台,它基于Caffe2、用Python写成。除了Mask RCNN的实现之外,Detectron还包含了ICCV 2017最佳学生论文RetinaNet,Ross Girshick 此前的研究Faster R-CNN和RPN、Fast R-CNN、以及R-FCN的实现。
Mask RCNN的出世时间是2017年,到目前为止它依然是相当强悍的目标检测方法之一,当然也不乏超越它的作品。
RCNN 系列属于目标检测中 2-stage 方法的代表作品,之所以称为 2-stage 是因为它们需要先通过一类算法找到图像中的候选区域 Region Proposal,然后再利用另外一类算法对这些区域进行分类、回归,完成目标检测问题中的识别与定位。该方法的 pipeline 需要多个独立的部分,每一部分需要单独数据集、单独训练,过程较为繁琐且无法实现端到端的训练。
针对 2-stage 的问题,YOLO 提出 1-stage 的目标检测方法:Fast RCNN 主要的改进不是将 proposal 进行网格划分嘛,YOLO 将这种思想直接应用到原始图像上,那就不需要做生成 proposal 的工作了呀!所以,YOLO 将 proposal生成、分类、回归放到一个模型中统一完成,在速度上有相当的优势,虽然精度有所降低,但是随着版本的进化也相应的有所改善。
(1)Yolo(2015)
Yolo使用最直观的求解思路,对于输入的完整图像,经过一个网络直接给出每一个目标物体的位置bbox、所属类别,它的思路设计可以概括为以下几步:
下图是Yolo的流程图:
为什么可以直接在原始图像上划分网格?Faster RCNN 在特征图的每个特征点上生成 anchor,如果把这些特征点映射回原始图像其实也就是一个个的网格,YOLO 相当于直接把特征点映射回去了,希望通过原始图像上的网格直接产生对目标物体的预测。
在开始训练之前,要为图像的每个网格打上标签,生成标签的做法是:根据真实的目标框所在位置,判断它落在哪个网格内,包含目标框中心点的网格会被赋予有效的 label(真实类别,真实边框)。 对于需要网络预测的 bbox,它的表达形式为 ( x , y , w , h ) (x,y,w,h) (x,y,w,h),前两个参数给出 bbox 的中心相对于该网格左上角的所在位置,后两个参数给出了 bbox 相对于全图的大小尺寸,它们的值都被归一化到 0~1。网络最终的输出形式是 ( 7 , 7 , 30 ) (7,7,30) (7,7,30),因为原始图像被划分成 S ∗ S = 7 ∗ 7 S*S=7*7 S∗S=7∗7 个网格,每一个网格有 B = 2 B=2 B=2 个 bbox 预测,每个预测框有5个位置参数 、 C = 20 C=20 C=20 个类别参数,所以最终特征正尺寸是 7*7,通道数量是 5*2+20=30。根据此输出值,计算 bbox 的所属类概率 c o n f i d e n c e ∗ P r ( C l a s s i ∣ O b j e c t ) confidence * Pr(Class_i|Object) confidence∗Pr(Classi∣Object) 也就是 bbox 的置信度乘以它所在网格类概率。虽然每个网格都能计算这样一个值,但是只有在前面的 label 标签中包含目标框中心点的网格才有资格作为预测值,参与到后续loss计算。具体来看看损失函数: λ coord ∑ i = 0 S 2 ∑ j = 0 B I i j obj [ ( x i − x ^ i ) 2 + ( y i − y ^ i ) 2 ] + λ coord ∑ i = 0 S 2 ∑ j = 0 B I i j obj [ ( w i − w ^ i ) 2 + ( h i − h ^ i ) 2 ] + ∑ i = 0 S 2 ∑ j = 0 B I i j o b j ( C i − C ^ i ) 2 + λ n o o b j ∑ i = 0 S 2 ∑ j = 0 B I i j n o o b j ( C i − C ^ i ) 2 + ∑ i = 0 S 2 I i o b j ∑ c ∈ classes ( p i ( c ) − p ^ i ( c ) ) 2 \begin{array}{l} {\lambda_{\text { coord }} \displaystyle\sum_{i=0}^{S^{2}} \sum_{j=0}^{B} \mathbb{I}_{i j}^{\text { obj }}\left[\left(x_{i}-\hat{x}_{i}\right)^{2}+\left(y_{i}-\hat{y}_{i}\right)^{2}\right]} \\ +\lambda_{\text { coord }} \displaystyle\sum_{i=0}^{S^{2}} \sum_{j=0}^{B} \mathbb{I}_{i j}^{\text {obj}} \left[\left(\sqrt{w_i}-\sqrt{\hat{w}_{i}}\right)^{2}+ \left(\sqrt{h_i}-\sqrt{\hat{h}_{i}}\right)^{2} \right]\\ +\displaystyle\sum_{i=0}^{S^{2}} \sum_{j=0}^{B} \mathbb{I}_{i j}^{\mathrm{obj}}\left(C_{i}-\hat{C}_{i}\right)^{2} \\ +\lambda_{\mathrm{noob} j} \displaystyle \sum_{i=0}^{S^{2}} \sum_{j=0}^{B} \mathbb{I}_{i j}^{\mathrm{noobj}}\left(C_{i}-\hat{C}_{i}\right)^{2} \\ +\displaystyle\sum_{i=0}^{S^{2}} \mathbb{I}_{i}^{\mathrm{obj}} \sum_{c\in\text {classes}}\left({p_{i}(c)-\hat{p}_{i}(c)}\right)^{2} \end{array} λ coord i=0∑S2j=0∑BIij obj [(xi−x^i)2+(yi−y^i)2]+λ coord i=0∑S2j=0∑BIijobj[(wi−w^i)2+(hi−h^i)2]+i=0∑S2j=0∑BIijobj(Ci−C^i)2+λnoobji=0∑S2j=0∑BIijnoobj(Ci−C^i)2+i=0∑S2Iiobjc∈classes∑(pi(c)−p^i(c))2第一部分计算的是包含物体中心的网格的 bbox 中心位置损失,这里只会计算与 GroundTruth 交并比最大的那个 bbox,虽然给的 j j j 值是0~B,但是后面的计算只与 i i i 有关,说明只有一个bbox参与计算。具体是哪一个 bbox,由 I i j obj \mathbb{I}_{i j}^{\text {obj}} Iijobj 计算得到,它给出了根据 I O U IOU IOU 选择 bbox 的数学表示。
第二部分计算的是尺寸损失,大物体与小物体同时偏离一个尺寸带来的误差是不同的,这里为了减小这种尺度大小带来的影响,将 w / h w/h w/h 进行开方然后计算损失。
第三部分计算的是置信度损失,与前两部分相比这一部分没有系数 λ coord \lambda_{\text {coord}} λcoord,原因是 bbox 位置信息与置信度信息维度不同、重要性不同,如果将它们同等对待处理显然不合理,为了突出 bbox 损失故在其前面加入系数 λ coord = 5 {\lambda_{\text{coord}}}=5 λcoord=5。
第四部分计算的是不包含物体中心的网格置信度损失, I i j noobj \mathbb{I}_{i j}^{\text {noobj}} Iijnoobj 负责教会模型判断哪些网格不包含物体中心,系数 λ noobj = 0.5 {\lambda_{\text{noobj}}}=0.5 λnoobj=0.5 弱化这类网格的影响。
第五部分计算的是分类损失,它与bbox是无关的,所以判别参数是 I i obj \mathbb{I}_{i}^{\text {obj}} Iiobj,且与置信度同等重要。
(1)包含物体中心的网格:需要计算分类loss,两个predictor都要计算置信度loss(系数不同),预测的bbox与ground truth IOU比较大的那个predictor需要计算位置、尺寸loss。
(2)不包含物体中心的网格:只需要计算置信度loss。
上图是Yolo的网络结构,对于卷积层的参数先用 ImageNet 做分类预训练,预训练输入图像尺寸为 224*224,之后进行检测训练时将输入图像尺寸改为 448*448(为什么要这样做?)。
RCNN 系列的边框回归是在 proposal/anchor 上进行的,而 YOLO 没有做边框回归,它直接输出 bbox 的中心位置、尺寸大小,中心点针对网格左上角,尺寸大小是相对于全图而言,如果要类比的话可以认为这里的网格就相当于 RCNN 系列中 的 anchor,不准确哈!YOLO 的不足在于:一个网格最终只有一个目标物体的输出,这导致它对那些尺寸较小或者比较拥挤的目标的检测不是很准确。
(2)Yolo v2(2017)
Yolo-v2对Yolo进行了多方面的改进。
对于两个数据集,5个先验框的width和height如下:
COCO: (0.57273, 0.677385), (1.87446, 2.06253), (3.33843, 5.47434), (7.88282, 3.52778), (9.77052, 9.16828)
VOC: (1.3221, 1.73145), (3.19275, 4.00944), (5.05587, 8.09892), (9.47112, 4.84053), (11.2364, 10.0071)
Yolo 使用 GoogLeNet 作为basebone,Yolo-v2 则提出自己的网络结构Darknet-19:
为什么第一层卷积的输出是224*224?实际上,这并不是最终的检测模型的输入尺寸,整个Yolo-v2的训练分三个阶段:
前两个阶段其实都是分类预训练,为的是让 Darknet-19 拥有较好的分辨能力;第三阶段才是目标检测,使用的数据集也改成了COCO、VOC-2007。
Yolo-v2 中每个网格有5个 bbox,每个 bbox 有4个坐标值、1个置信度值、20个类别概率值,因此一个网格需要5*(4+1+20)=125个 filters。Yolo中一个网格有2个bbox,这两个bbox共享一个类别概率,Yolo-v2中则是每一个bbox都有一个属于自己的类别概率。
Yolo-v2的细节很多,论文中只给了最为突出的部分,要了解所有的细节还是需要对源码进行剖析。Yolo-v2的损失函数可以参考这里。
这里所说的网格其实是最后特征图上的一个点,但是映射回原图可以看做是一个网格
(Yolo9000的部分有待补充!)
Yolo-v3 论文比 Yolo-v2 还要随意,具体优化内容主要有:
(10×13)、(16×30)、(33×23)、(30×61)、(62×45)、(59×119)、(116 × 90)、(156 × 198)、(373 × 326)
作为工程项目来说,Yolo-v3的检测效果应该是相当不错的,这里我们不去讨论mAP、COCO数据集上的表现等刷分用的参数,就仅仅看它在实际应用中的performance,速度、精度都很令人满意。重要的是,Yolo-v3开源代码的使用极其简单,即便是看源码、根据自己的需求修改源码都很方便(主要是代码写得很清晰)。参考Tensorflow版本的项目,得到下图结果。
Tiny Yolo
Yolo Nano
Gaussian YOLOv3
YOLO-v4
SSD(Single Shot MultiBox Detector)发表于2015年,Faster RCNN 和 Yolo 之后的作品,它也属于目标检测的 1-stage 范畴,同时借鉴了OverFeat、SPP、Fast RCNN、Yolo、Faster RCNN 的一些思想。SSD 由一个 base network 和6个卷积特征层构成,base network 是自VGG-16改造来的,6个卷积特征层分别输出不同尺寸的特征。
SSD 的网络结构图还是很清晰的,它和 YOLO 的区别就在于:YOLO 只利用到最后一层特征层的信息,而 SSD 则利用了不同尺度上的特征信息,其精度可想而知比 YOLO 要好。在卷积神经网络中,低层卷积更关心特征在哪里,它更多的是提取一些具体的细节信息,其分类准确性并不高;而高层卷积则更关心特征是什么,它提取的是与整体相关的抽象信息,可能丢失了类似物体在哪里的位置信息。SSD 将二者结合,在不同尺度的特征图上设置初始框,对于那些和真实目标交并比较大的初始框,网络对它做分类预测和位置偏移,并从中产生预测值。
SSD 的三个创新点:
TODO
TODO
参考
anchor的前世今生(上)
anchor的前世今生(下)
知乎1:物体检测的轮回: anchor-based 与 anchor-free
知乎2:目标检测:Anchor-Free时代
anchor based与anchor free对比
anchor free相关论文解析
Anchor-free之SAPD