番外篇2.4:图像处理与深度学习:图像检测(R-CNN, Fast Rcnn, Faster Rcnn, R-FCN, SSD, Yolo)

所谓图像检测(目标检测 whatever)就是在一幅图像中,找到我们所希望检测到的东西(可能是多目标),并把它圈出来。

1.1 R-CNN

这个问题的思路有很多,先说最直接的一种:取到图像中所有的框,不同大小,不同位置(遍历),对每一个框进行识别,(对应一种目标)选择若干个极大值点(当然也要大于阈值)对应的框作为这种目标的大小和位置。
当然,一幅图像大大小小的框加起来过于多,靠暴力试错是没有前途的。所以要先得到一些可能是目标的候选区域,方法有比如Selective Search和Edge Boxes什么的,这里暂时不仔细总结。
然后我们就可以把得到的这些候选框框修正一下大小,直接加到设计好的神经网络架构中进行学习了。
这里写图片描述
不过这个也有一个问题,就是框和框之间会有很多重叠,对应的卷积计算我们就要重复做很多次,大大拖慢了我们的学习效率。那怎么办呢?为了解决这个问题,SPP-Net的概念就被使用了。

1.2 SPP-Net/Fast R-CNN

SPP-Net(空间金字塔池化)本来不是用在这里的,不过在这里使用的spp-net有一个很重要的核心思想,就是输入的时候我们输入整个图像,在最后得到整张图像的feature map。然后我们找到候选框框之后,可以直接在feature map上找到对应的patch,然后我们再用这个方法来把得到的patch中的数据池化成我们需要的统一大小再输出。我们可以很简单的猜测到,这个spp-net(我们成之为ROI pooling)直接放在最后一个卷积层和全连接层之间。(这就是Fast R-CNN)
这里写图片描述

1.3 RPN/Faster R-CNN

不过显然,找候选框也需要大量的计算,约几秒钟吧,完全没办法实现实时分类的要求。为了解决这个问题,RBG与何恺明设计了新的方法提取候选框框,这种方法就是RPN网络。
这种方法就是让候选框也通过CNN来得到,我们可以看到,候选框的选择也是需要把图像作为输入的。那干脆把图像输入到一个cnn网络中,只是输出的时候分别对两个全连接层(打比方,用卷积层也ok)分别输入,分别得到输出不就ok了吗!(Faster R-CNN)
这里写图片描述
候选区域生成网络(Region Proposal Network, RPN)工作方式如下:
先通过对输入图像的数层卷积得到一个特征图像,然后在特征图像上生成候选区域。它使用一个n*n(n=3)的滑动窗口,将局部的特征图像转换成一个低维特征, 预测k个的区域(cls层,2k个输出)是否为候选区域和对应的k个边框(reg层,4k个输出)。这里的K个区域被称为锚(anchor), 对应着与滑动窗口具有相同的中心的不同大小和不同长宽比的矩形框。假设卷积后的特征图像大小为W*H,那么一共有WHk个锚。这种特征提取和候选区域生成的方法具有位移不变性。
总体的步骤分如下四部:1,单独训练RPN;2,使用步骤中1得到的区域生成方法单独训练Fast R-CNN; 3, 使用步骤2得到的网络作为初始网络训练RPN;4, 再次训练Fast R-CNN, 微调参数。

1.4 R-FCN

对于region-based的检测方法,以Faster R-CNN为例,实际上是分成了几个子网络,第一个用来在整张图上做比较耗时的卷积,这些操作与region无关,是计算共享的。第二个是用来产生候选框(如RPN),第三个用来分类或进一步对候选框进行regression(如Fast RCNN),这个子网络和region是有关系的,必须每个region单独跑网络,衔接在这个子网络和前两个子网络中间的就是ROI pooling。为个进一步提升速度,我们最好把第三个子网络也可以在前面共同使用。
和使用残差网络ResNet 101 的Faster R-CNN相比,(前91层为共享子网络,中间插入ROI pooling,后十层是不共享的)R-FCN 同样使用了ResNet 101,用来预测的卷积只有1层,其他全部都是共享的,提升了速度。
这里写图片描述

2.1 YOLOv1

无论怎么简化优化,实质上这些方法(R-CNN,Fast R-CNN,Faster R-CNN, R-FCN)都是分两步解决问题,先找到候选区域,再对候选区域进行识别。
那有没有办法一次性(one-stage)实现检测呢?有的,那就是yolo。
yolo的创新点在于,他把全图划分为X*X的格子,每个格子负责中心在这个格子中目标的检测。预测目标,所以每个格子需要得到(x,y,w,h)(图片四维),以及一个置信概率,共五个值。还要考虑到每个格子中可能有多个目标,我们设一个上限也就是I,再考虑到检测J种类的情况,每个格子需要输出5*I+J个值,整个系统的输出就是S*S*(5*I+J)。
如果我们有一个100*100像素大小的输入,我们拆分成100*10*10作为输入来输入进网络,选择每个格子中输入4个目标,10个种类,那我们输出的就应该是10*10*30。
然后滤掉置信概率不够高的输出,(每个格子只能最多产生一个),保留的目标进行NMS处理(非极大值抑制),得到最后的结果。
yolo模型精度比faster R-CNN要差,而且由于原理限制,对目标占画面比例较小,但数量高的情况不适用。
而且我们知道yolo输出的参数很多,计算损失函数的时候不能完全平均计算损失,因为有的参数代表位置,而有的参数代表种类,而且当格子中没有目标时,种类参数置信概率也没有意义。
我们给前面代表目标位置的参数更高的损失权重,对没有目标时的种类参数、置信概率赋更低的损失权重;当目标小时,代表偏移的损失的权重要比大目标偏移的损失权重高。
这种方法模型要用imageNet预训练。(YOLO fast原理相同,卷积层从24层降低为9层)
这里写图片描述

2.2 SSD

SSD 使用 VGG19 网络作为特征提取器。我们在该网络之后添加自定义卷积层,并使用卷积核执行预测。
这里写图片描述
然而,卷积层降低了空间维度和分辨率。因此上述模型仅可以检测较大的目标。为了解决该问题,我们从多个特征图上执行独立的目标检测。(R-SSD)(有些类似高斯金字塔)
这里写图片描述
SSD算法的原理有点类似R-FCN,它产生一系列的固定大小的boxes(形状不同),以及每一个box中包含目标的可能性。最后进行NMS处理后得到最终的预测。
这里写图片描述
既然boxes的大小是固定的,那我们如何预测不同大小的目标呢?就是通过上面所说的,我们后面有很多的卷积层,如果对卷积层有足够的了解,你会知道不同的卷积层对应原图像上的感受野是不一样大的。所以在不同的卷积层上计算置信概率,对应的也是不同大小的目标。
对应每一个box,我们要计算出多少个类,每个类的置信概率,还有相对于默认box的偏移值。
最后得到若干个盒子,我们直接对置信概率做NMS,就可以得到目标了。
提高SSD算法的精度,有几种方法:
1. 数据增强。原文中就用了数据增强的方法,算法性能明显提高。
2. 控制正负样本比例。一般情况下negative default boxes数量是远大于positive default boxes数量,如果随机选取样本训练会导致网络过于重视负样本(因为抽取到负样本的概率值更大一些),这会使得loss不稳定。因此需要平衡正负样本的个数,我们常用的方法就是Hard Negative Mining,即依据confidience score对default box进行排序,挑选其中confidience高的box进行训练,将正负样本的比例控制在positive:negative=1:3,这样会取得更好的效果。如果我们不加控制的话,很可能会出现Sample到的所有样本都是负样本(即让网络从这些负样本中找正确目标,这显然是不可以的),这样就会使得网络的性能变差。
3. 匹配策略。首先,寻找与每一个ground truth有最大的IoU的default box,这样就能保证ground truth至少有default box匹配;SSD之后又将剩余还没有配对的default box与任意一个ground truth尝试配对,只要两者之间的IoU大于阈值(SSD 300 阈值为0.5),就认为match;配对到ground truth的default box就是positive,没有配对的default box就是negative。这样,一个ground truth可能会对应多个positive default box。
这里写图片描述
4. Atrous Algothrim。 这个方法就是使用hole算法,目的是在提高feature map大小的同时提高接受场的大小,这样可以获得更加密集的score map。
总之,SSD算法是在YOLO的基础上改进的单阶段方法,通过融合多个feature map上的BB,在提高速度的同时提高了检测的精度,性能超过了YOLO和Faster-RCNN。不过灵感还是有部分来自于Faster的。。

2.3 YOLO9000(YOLOv2)

yolov2是在yolov1的基础上改变的(废话),直接说改进的手段:
这里写图片描述
1、Batch Normalization(批标准化)
可以提升模型收敛速度,而且可以起到一定正则化效果,降低模型的过拟合。在YOLOv2中,每个卷积层后面都添加了Batch Normalization层,并且不再使用dropout。使用Batch Normalization后,YOLOv2的mAP提升了2.4%。
2、采用高分辨率的分类器
由于历史原因,ImageNet分类模型基本采用大小为224*224的图片作为输入,分辨率相对较低,不利于检测模型。所以YOLOv1在采用224*224分类模型预训练后,将分辨率增加至448*448,并使用这个高分辨率在检测数据集上finetune(微调)。但是直接切换分辨率,检测模型可能难以快速适应高分辨率。所以YOLOv2增加了在ImageNet数据集上使用448*448来finetune分类网络这一中间过程(10 epochs),这可以使得模型在检测数据集上finetune之前已经适用高分辨率输入。使用高分辨率分类器后,YOLOv2的mAP提升了约4%。
3、先验框
其实就是RPN与SSD都用过的东西,YOLOv2把v1中的全连接层去掉,改用卷积和先验框来预测边界框。虽然mAP有些许下降,不过召回率提高了7%(从81到88)
4、对先验框做聚类分析
YOLOv2用k-means聚类方法,对训练集中的边界框做了聚类分析,IOU更高,更容易训练。
5、换了基础模型
YOLOv1的基础模型是VGG16,而v2直接换成了Darknet-19,包括19个卷积层和5个maxpooling层。与NIN(Network in Network)类似,Darknet-19最终采用global avgpooling做预测,并且在3*3卷积之间使用1*1卷积来压缩特征图channles以降低模型计算量和参数。Darknet-19每个卷积层后面同样使用了batch norm层以加快收敛速度,降低模型过拟合。改了基础模型之后,YOLOv2的计算量减少了33%。
6、约束了边界框的偏移值
YOLOv2与v1类似,用sigmoid函数来处理偏移值,这样不会产生在a点算到的边界框中心点跑到b点去的问题。结合聚类分析,先验框,和这种约束,mAP提升了5%。
7、更精细的特征图
把倒数第二层的输出额外加了一个passthrough层,直接塞进了最后一层的输出中,直接把维度*3。这算是一个小trick,把v2的性能提升了1%。
8、多尺度训练
YOLOv2的输入不限制大小。YOLOv2采用了多尺度输入训练策略,具体来说就是在训练过程中每间隔一定的iterations之后改变模型的输入图片大小。由于YOLOv2的下采样总步长为32,输入图片大小选择一系列为32倍数的值:640?wx_fmt=png输入图片最小为320*320,此时对应的特征图大小为10*10(不是奇数了,确实有点尴尬),而输入图片最大为608*608,对应的特征图大小为19*19,在训练过程,每隔10个iterations随机选择一种输入图片大小,然后只需要修改对最后检测层的处理就可以重新训练。
YOLOv2的改进基本都是借鉴别人的一些思路,但是整合出来的效果却还不错,有一些新的思路也给了后人启发,比如聚类、多尺度训练等。
而YOLO9000则是以YOLOv2为基础,加上了Wordtree思想,分类有9000种,还是很酷炫的,总体mAP值为19.7%,算是开创之举了。

2.4 YOLOv3

YOLOv3可以说出来直接吊打一切图像检测算法。比同期的DSSD(反卷积SSD), FPN(feature pyramid networks)准确率更高或相仿,速度是其1/3.。
YOLOv3的改动主要有如下几点:
1、增加了top down的多级预测,直接解决了YOLO对小目标很难识别的顽疾。
v2 只有一个 detection,v3 增加到了3个detection,分别是一个下采样的,feature map 为 13*13,还有 2 个上采样的 eltwise sum,feature map 为 26*26,52*52,也就是说 v3 的 416 版本已经用到了 52 的 feature map,而 v2 把多尺度考虑到训练的 data 采样上,最后也只是用到了 13 的 feature map,这可以说在对小目标的识别上,是一个突破。
论文中,一共是9个聚类中心,按照大小分给三个detection,单层只预测三种boundingbox。
2、loss不同。 v3 替换了 v2 的 softmax loss 变成 logistic loss,由于每个点所对应的 bounding box 少并且差异大,每个 bounding 与 ground truth 的 matching 策略变成了 1 对 1。当目标类别很复杂的时候,通常logistic loss更有效,也方便使用多标签分类。
3、加深了网络。使用简化的残差网络代替了1*1,3*3的卷积层(加了短路),基础模型也从Darknet-19变成了Darknet-53,在网络中也有一连串的1*1(用来压缩特征表示),3*3(用于增加信道)卷积。
YOLOv3也不是毫无缺点,由于最根本原理的原因(每个网格固定目标数量),召回率并不很高。对于位置并没有很好优化,精准度比较差。而且模型泛化能力太强,有时候容易跑偏。
当然优点更明显,简单,速度快,精度高,可以识别小物体,泛化能力强(语义识别能力)
以后还会有更多优秀的算法,以后再总结吧,就先到这里 溜啦!

猜你喜欢

转载自blog.csdn.net/dimei0938/article/details/82262444