R-CNN可以说是利用深度学习进行目标检测的开山之作,作者Ross Girshick多次在PASCAL VOC的目标检测竞赛中折桂,曾在2010年带领团队获得终身成就奖。R-CNN这篇论文是在2014年提出的,在2014年之前,主流都是一些传统的目标检测算法,使用人为定义特征的方式进行检测,但那些年经典的目标检测算法已经进入了瓶颈期,其发展也非常的缓慢。在2014年,随着R-CNN的提出,将目标检测领域的准确度至少提高了30%,传统的的目标检测算法准确率大概是在30%左右,R-CNN一来直接跳到了50%,可以说是一个非常大的进步。
利用Selective Search算法通过图像分割的方法得到一些原始区域,然后使用一些合并策略将这些区域合并,得到一个层次化的区域结构,而这些结构就包含着可能需要检测的目标。
将Selective Search算法生成的约2000个候选区域缩放到227×227pixel,即无论候选框是什么形状,输入到CNN之前都需要对其进行resize处理 ,将缩放后的候选区域输入到网络就能得到对应的特征向量,其实这里的CNN就是图像分类网络,只不过将其后面的全连接层去掉,只进行了展平处理。原论文中一个候选框从AlexNet CNN输出得到一个4096维特征向量,2000个候选区域就得到了2000×4096维矩阵。(4096是AlexNet 规定的)
SVM分类器是一个二分类的分类器,所以针对每一个类别都有一个专门的分类器。这里是以PASCAL VOC数据集为例,在PASCAL VOC数据集中有20个类别,所以这里就有20个SVM分类器。将2000×4096维特征与20个SVM组成的权值矩阵4096×20相乘,获得2000×20维的评分矩阵,表示每个建议框是某个目标类别的得分。
为了方便理解请看下图:最左边是特征矩阵,每一行就是一个候选框通过CNN网络得到的特征向量,2000个候选框对应2000个特征向量,中间是SVM权值矩阵,每一列代表一个类别的权值向量,假设第一列代表猫,第二列代表狗,将候选框1所对应的特征向量与分类器1进行矩阵相乘,得到2000×20矩阵的第一行第一个元素,代表第一个候选框为猫的概率,以此类推,与第二个判断是否为狗的分类器相乘得到第一行第二个元素,代表第一个候选框为狗的概率,······就有20个概率。接下来分别对2000×20维矩阵中的每一列(对应同一个类别的概率)即每一类进行非极大值抑制剔除重叠建议框,得到该列即该类中得分最高的一些建议框,如下面2000×20概率矩阵的第一列代表所有候选框为猫的概率。
引入概念IoU(Intersection over Union):两个目标框的交并比,数学表达形式如下图所示,对每个类别寻找得分最高的目标,计算其他目标与该目标的IoU值,再对每一个边界框与最高得分边界框的IoU值进行判断,如果该IoU值大于所给定的阈值就删除它,将最高得分的目标存起来,再在剩下的边界框中继续寻找得分最高的目标,按照上述流程再次计算、删除,直到将所有的边界框遍历完。下图是便于理解的一个示例:向日葵图像中通过SS算法得到了一系列的边界框,这些边界框通过SVM后中评分最高的一个是0.98,仅次的一个是0.86,通过计算这两个边界框的交并比大于所给的阈值,认为这两个目标是同一个目标,就把概率低的删除掉,保留概率高的,最后所期望的是通过检测网络得到一个最完美的边界框,而不是其他残缺的边界框。
通过SS算法得到的目标候选框位置并不是特别的准确,所有需要通过一系列的回归器去修正候选框的位置,即对非极大值抑制后剩余的建议框进一步筛选。分别用20个回归器对上述20个类别中剩余的建议框进行回归操作,最终得到每个类别的修正后的得分最高的bounding box。这一步的实现依旧是和训练SVM分类器一样,针对每一个边界框通过CNN输出的特征向量进行预测。下图中橙黄色的边界框是通过SS算法所得到的目标建议框,绿色的是真实的目标边界框,使用回归分类器后会得到四个参数,分别对应着目标建议框中心点的x/y偏移量和边界框高度/宽度的缩放因子,通过这四个参数对目标建议框进行调整,得到红色的边界框。 关于如何训练回归器在下面的Faster R-CNN中进行说明。
R-CNN存在的问题:
Fast R-CNN是作者Ross Girshick继R-CNN后的又一力作,原论文是在2015年发表的,同样使用VGG16作为网络的backbone,与R-CNN相比训练时间快9倍,测试推理时间快213倍,准确率从62%提升至66%(PASCAL VOC数据集)。
左边是R-CNN生成特征的方式:对每一个候选区域resize,输入进网络得到对应的特征,所以在R-CNN中,通过SS算法得到2000个候选框,就需要两千次正向传播。但这样的做法会存在大量的冗余,很多重叠的部分只需要计算一次就可以,但在R-CNN中不停的反复计算。
右图是Fast R-CNN生成特征的方式:将整幅图像输入到CNN网络之中得到了特征图,紧接着通过每个候选区域原图与特征图的映射关系,就可以直接在特征图中直接获取候选区域的特征矩阵,这样,这些候选区域的特征就不需要重新计算了。通过这种简单的操作,能够大幅提高Fast R-CNN的计算过程。
在训练过程中,并不是使用SS算法得到的所有候选区域,通过SS算法得到2000个候选框,但训练过程中只需要一小部分就足够了。而且对于采样的数据分为正样本和负样本,正样本就是候选框种确实存在所需检测目标的样本,负样本是背景,没有我们想要检测的目标。为什么要分正样本和负样本呢?比如要去训练一个猫狗分类器,如果猫的样本数量远大于狗的样本数量,也就是说如果数据不平衡的话,那么网络在预测的过程中就会更偏向于猫,这样明显是不对的(极端一点的情况,只有猫,则网络只认识猫,不认识狗)。 同样,如果都是正样本的话,网络就会以很大的概率认为候选区域是我们所需要检测的目标,如果明明是个背景但也认成了目标。在原论文中,作者说明了对每张图从2000个候选框中采集64个,64个候选框中一部分是正样本,一部分是负样本。正样本定义在候选框与真实目标框的IoU大于0.5,负样本定义在IoU为0.1~0.5之间。
有了训练样本之后,将训练样本通过RoI pooling层将其缩放到统一的尺寸,中间的过程是如下实现的:对之前几步所得到的训练样本(通过映射裁剪得到的feature map)化分为7×7即49等份,对每一个区域执行最大池化下采样,这样最终就得到了一个7×7的特征矩阵,其他的channel也是以此类推。因此无论特征区域是什么样的尺寸,都统一缩放到了7×7大小,这样就可以不限制输入图像的尺寸。在R-CNN中,必须要求输入图像的尺寸大小为227×227,但在Fast R-CNN中就不对输入图像尺寸进行限制了。接下来再对下采样后的特征展平处理,接着通过两个全连接层,得到RoI feature vector,在其上并联两个全连接层,其中一个全连接层用于目标概率的预测,另外一个全连接层用于边界框回归参数的预测。
该分类器会输出N+1个类别的概率,N为检测目标的种类,1为背景。以PASCAL VOC数据集为例,其有20个类别,就应该输出21个类别概率,第一个概率为当前候选框为背景的概率,剩下20个对应着所需检测的每个目标的概率,这个概率是经过softmax处理之后的,所以其满足概率分布。既然需要输出N+1个类别概率,那么这里的全连接层就需要N+1个节点。
边界框回归器会输出对于N+1个类别的候选边界框回归参数(dx,dy,dw,dh),共(N+1)×4个参数,对应(N+1)×4个节点,如上图所示的一维向量,每四个分为一组,一组对应一个类别的边界框回归参数。
下面这个公式是在R-CNN中给出的:dx和dy分别是用来调整候选边界框中心坐标的回归参数,
由于需要预测候选框的类别概率以及边界框的回归参数,因此就需要两个损失,一个是分类损失,一个是边界框回归损失,下图的公式是直接从Mask R-CNN中提取过来的:
假设有k个目标种类,p0就代表候选区域为背景的概率,u就代表目标真实的标签类别。在Fast R-CNN中作者是通过log损失计算分类损失的,其实这里的log损失就是交叉熵损失,计算公式如下,pu代表分类器预测当前候选区域为u的概率
顺带着回顾一下交叉熵损失, oi星代表真实标签值,其只有在正确的标签索引位置是等于1的,其他位置是等于0的,因为0乘任何数都等于0,索引就可以将0的部分全部省去,最后只剩下为真实标签索引的那一项,假设当i=u的时候对应正确的标签值,那么ou星=1,下面的公式1就对应上面的公式。
边界框回归损失:除了Llocation这个损失是由四部分组成的,另外还有两项:λ(平衡系数,用于平衡分类损失和交叉熵损失)和[u≥1]是艾弗森括号,u代表目标的真实标签,当u≥1时这一项就等于1,当u=1就是等于0的,u≥1就说明候选区域确实属于需要检测的某一个类别,对应着正样本,这个时候才有边界框损失,当u=0时对应负样本,即当前区域为背景,就不需要边界框回归损失这一项。将边界框损失和分类损失相加即得到Fast R-CNN的总损失,再对其进行反向传播就可以训练整个网络了。
第一部分是通过SS算法获取候选框,第二部分是特征提取、分类、边界框回归,这三个部分已经融合在一个CNN网络里,而R-CNN还要再单独训练SVM和边界框回归器,需要四个部分。接下来的Faster R-CNN网络需要把Fast R-CNN的两个部分融合在一起,形成一个端到端的训练过程。
Fast R-CNN网络的瓶颈在SS算法上,SS算法在CPU需要2s的时间,而第二部分总体才需要零点几秒就能完成,为了解决这个问题,Faster R-CNN引入了RPN。
Faster R-CNN是作者Ross Girshick继Fast R-CNN后的又一力作,同样使用VGG-16作为网络的backbone,推理速度在GPU上达到5fps(包括候选区域的生成),即每秒钟能检测五张图片,准确率也有进一步的提升,在2015年的ILSVRC以及COCO竞赛中获得多个项目的第一名。
Faster R-CNN的算法流程可分为3个部分:
其实Faster R-CNN = RPN + Fast R-CNN,RPN即Region Proposal Network,用RPN替代SS算法。
上图中右半部分是原论文给的RPN网络结构,首先是一个feature map,使用一个滑动窗口在其上进行滑动,每滑动到一个位置上,就生成一个一维的向量,在这个向量的基础上,再通过两个全连接层,分别去输出目标概率以及边界框回归参数,图中的2k个scores是针对k个anchor boxes,每一个anchor生成两个概率,一个是其为背景的概率,一个是其为前景的概率,同时每个anchor生成4个边界框回归参数。
这个256是怎么来的?:将ZF网络作为Faster R-CNN的backbone,其说生成的特征图的深度是256,如果使用VGG16的话,这里就应该是512了,所以这里生成的一维向量元素的个数是根据所使用的backbone输出特征矩阵的深度所确定的。
什么是anchor?:对于feature map上每一个3×3的滑动窗口,首先计算中心点在原图所对应的位置,如何去找这个位置呢?将原图除以特征图的宽度再取整就得到一个倍数,用feature map上的x,y坐标乘以倍数就得到了原图中的位置,接下来以得到的映射点为坐标生成一系列anchor box,这里的每个anchor box都是给定的大小及长宽比例,如上图中左边的三个不同颜色的框,anchor可能包含了需要检测的目标,也可能没有包含。
2k个scores和4k个coordinate是如何影响anchor的?:k个anchor会生成2k个scores,下图的黄色框是生成的2k个scores,红色框为coordinate,每两个scores,四个coordinate对应一个anchor。假设第一个anchor对应图中的黄框,第一组scores中0.1为背景的概率,0.9为目标的概率,这里只是预测前景和背景,并没有对其进行分类,同样第一组coordinate中dx,dy对应anchor的中心坐标偏移量,dw,dh是对宽度和高度的调整,通过边界框回归参数调整之后,尽可能准确的框选出目标。
**为什么要给出这么多不同比例的anchor?**因为所要检测的目标大小是不一样的,而且每个目标的长宽比也是不一样的,所以需要一系列的anchor去预测目标的位置。
原论文中给了三个尺度和三种比例:128²、256²、512²(这些对应着anchor的面积),1:1、1:2、2:1,因此每个滑动窗口在原图上都对应有3×3=9个anchor,这些数据在论文中说都是根据经验所得,没什么值得深究的地方。如对于128²的三个比例,其分别对应右图最中心的三个小框。9个anchor一共会生成18个类别分数,36个边界框回归参数。
对于ZF网络,滑动窗口的感受野是171,对于VGG网络,其感受野是228。 如果使用VGG网络,3×3的滑动窗口在原图上的感受野是228×228,但为什么还能预测比它大的如256,512的目标的边界框呢?原论文中作者是这样说的:通过一个小的感受野去预测一个比它大的目标边界框是有可能的,比如通过经验去看物体的一部分,就能大概的猜出这个目标完整的位置区域了。而且在实际使用过程中,这个方法也确实是有效的。 下图给出了如何计算ZF网络的感受野:
滑动窗口其实就是3×3的卷积层来进行处理的,stride=1,padding=1,这样,其滑动窗口就能把feature map的每一个点都覆盖到,通过卷积之后生成的是一个高度‘宽度、深度都和feature map一样的特征矩阵,紧接着并联两个1×1的卷积层实现对于类别的预测和边界框回归参数的预测。
因为每个位置上都会有9个anchor,如果对于一个1000×600×3的图像,通过特征提取网络之后,大概是60×40的大小,生成的anchor大约有60×4×9=20k个,忽略跨越边界的anchor,剩下约6k个,对于剩下6k个anchor再使用RPN生成的边界框回归参数将这6k个anchor调整为6k个候选框(anchor经过RPN的回归参数调整后,生成的才叫候选框),但生成的候选框存在大量的重叠,就根据评分采取非极大值抑制的方法,IoU设为0.7,这样每张图片大概只剩下2k个候选框。
通过滑动窗口在特征图上进行滑动,在原图上大概会生成上万个anchor,但并不是每个都用来训练我们的RPN网络,原论文中这样说:从上万个anchor随机采样256个anchor,分别由正样本和负样本组成,比例大概为1:1,如果正样本的个数不足128,那就用负样本来进行填充。有两种定义正样本的方式:1.只要anchor于ground-truth box(标注的准确的边界框)IoU超过0.7,那么这个anchor就是正样本。2.anchor与某一个ground-truth box有最大的IoU,那么也将其指定成正样本。其实第二个条件是对第一个条件的补充,通常情况下使用第一个条件就能生成足够的正样本,但在极少数的情况下,使用第一个条件是找不到正样本的,即没有IoU大于0.7,那么这个时候就需要采用第二个条件。定义负样本的方式:与所有的ground-truth box的IoU都小于0.3。对于正样本和负样本之外的anchor就全部丢弃掉。
包含两部分:分类损失和边界框回归损失。这个公式是原论文中给出的,原论文中指出,后面一项的系数可以替换为前面一项的系数,这里和Fast R-CNN的计算类似不再赘述。
直接采用RPN loss + Fast R-CNN Loss的联合训练方法。
原论文中采用分别训练RPN以及Fast R-CNN的方法