计算机视觉之RCNN, Fast RCNN, Faster RCNN, Mask RCNN目标检测
一、目标检测
1.1 概念
- 定位和分类:对于仅有一个目标的图片,检测出该目标所处的位置及该目标的类别;
- 目标检测:对于有多个目标的图片,检测出所有目标所处的位置及类别;
- 下图左侧为定位和分类任务,右侧为目标检测任务;
1.2 定位+分类
- 对于输入图片,定位任务需要返回图片中目标的外界矩阵框,即目标的 ( x , y , w , h ) (x, y, w, h) (x,y,w,h)四元组,四元组的预测可看做回归任务;
- 分类任务要识别目标的类别;
- 定位+分类的具体步骤如下:
1)训练或下载一个分类模型,例如Alexnet、VGGNet,Resnet;
2)在分类网络最后一个卷积层的特征层(feature map)上添加"Regression head";
3)同时训练"Classification head"和"Regression head",为了同事训练分类和回归问题,最终损失函数是分类和定位两个"head"产生的损失的加权和;
4)最终使用分类和回归的两个"head"得到分类+定位的结果,分类预测的结果是 C C C个类别,回归预测结果分两种:一种与类别无关,输出4个值;一种是类别相关,输出 4 ∗ C 4*C 4∗C个值。
1.3 目标检测
- 目标检测需要获取图片中所有目标的位置及类别,当图片中只有一个目标时,"Regression head"预测4个值,当图片中有三个目标时,"Regression head"预测12个值,当图片中有多个目标时,"Regression head"要预测较多的值;
- 基于上述问题,提出两种解决方案:
1)使用滑窗的方法解决,需要设计大量的不同尺度和长宽比的“滑窗”来使它们通过CNN,此方法计算量巨大,暂不采纳;
2)使用一种从图片中选出潜在物体候选框(Region of Interest,ROI)的方法selective search,基于此方法提出了RCNN。
1.4 R-CNN(Region-CNN)
- RCNN训练过程如图所示:
- 训练步骤如下:
1)选出潜在目标候选框ROI:基于selective search方法生成2000个潜在物体候选框ROI,然后对每个候选框Resize成固定大小;
2)训练一个特征提取器:采用AlexNet、VGGNet、GoolgeNet、ResNet等CNN模型提取一个4096维的特征向量,得到最后一个特征向量;
为了获得一个较好的特征提取器,一般在模型上做微调,唯一的改动就是将模型的1000个类别输出改为 ( C + 1 ) (C+1) (C+1)个输出,其中 C C C为真实预测的类别数, 1 1 1是背景的类别,新的特征训练方法采用随机梯度下降法SGD进行训练,提取训练好的模型的最后一个特征层;
衡量正负样本的指标IOU(Intersection Over Union),就是两个矩形面积的交集除以并集,假定两个矩阵框中,1个矩形表示ROI,两一个矩形表示真实的矩形框,当 R O I ≥ 0.5 ROI\ge 0.5 ROI≥0.5时,认为两个矩形基本相交,认为是正样本;其余为负样本;
至此RCNN的特征提取器就开始训练了,训练过程中要对正负样本进行采样,训练中正样本太少会导致正负样本不平衡,最终提取一个4096维的特征向量;
3)训练最终分类器:将特征向量送入SVM分类器中,预测出框选区域中多含物体属于每个类的概率值(每个类别单独训练一个SVM,判断是否属于这个类别,属于是positive,反之nagative),RCNN提出者最终选择真实值的矩阵框作为正样本;
4)训练回归模型:对于每一个类,训练一个线性回归模型,来微调ROI与真实矩形框位置和大小的偏差;
- 计算IOU代码如下所示:
def cal_IOU(boxA, boxB):
A_xmin = boxA[0]
A_ymin = boxA[1]
A_xmax = boxA[2]
A_ymax = boxA[3]
A_width = A_xmax - A_xmin
A_height = A_ymax - A_ymin
B_xmin = boxB[0]
B_ymin = boxB[1]
B_xmax = boxB[2]
B_ymax = boxB[3]
B_width = B_xmax - B_xmin
B_height = B_ymax - B_ymin
xmin = min(A_xmin, B_xmin)
ymin = min(A_ymin, B_ymin)
xmax = max(A_xmax, B_xmax)
ymax = max(A_ymax, B_ymax)
A_B_width_and = (A_width + B_width) - (xmax - xmin) # 宽的交集
A_B_height_and = (A_height + B_height) - (ymax - ymin) # 高的交集
if A_B_width_and <= 0.0001 or A_B_height_and <= 0.0001:
return 0
area_and = A_B_width_and * A_B_height_and
area_or = A_width * A_height + B_width * B_height
IOU = area_and / (area_or - area_and)
return IOU
if __name__ == '__main__':
rect1 = (661, 27, 679, 47)
rect2 = (662, 27, 682, 47)
iou = cal_IOU(rect1, rect2)
print("IOU={:.4f}".format(iou))
#结果
IOU=0.8095
- 预测步骤如下:
1)使用selective search方法生成2000个ROI;
2)所有ROI调整为特征提取网络所需的输入大小并进行特征提取,得到与2000个ROI对应的2000个4096维的特征向量;
3)将2000个特征向量分别输入到SVM中,得到每个ROI预测类别;
4)通过回归网络微调ROI的位置;
5)最终使用极大值抑制(Non-MaximumSuppression, NMS)方法对同一类别的ROI进行合并得到最终检测结果。NMS的原理是得到每个矩形框的分数(置信度),如果两个矩形框的IOU超过指定阈值,则仅保留分数大的那个矩形框。
1.5 Fast R-CNN
1.5.1 R-CNN缺点
- 2000个ROI的CNN特征提取占用大量时间;
- CNN特征不会因为SVM和回归的调整而更新;
- R-CNN训练流程复杂,并不是端到端的训练过程(因为R-CNN首先进行2000个ROI的提取,将提取的结果再放进CNN中进行特征提取和后续训练,是2个步骤,并不是端到端的训练);
1.5.2 SPP Net (Spatial Pyramid Pooling空间金字塔池化)
- 要解决的问题:
1)一般CNN后接全连接层或者分类器,他们都需要固定的输入尺寸,因此不得不对输入数据进行裁剪,这些预处理会造成数据的丢失或几何的失真。SPP Net的第一个贡献就是将金字塔思想加入到CNN,在卷积层和全连接层之间加入了SPP layer。此时网络的输入可以是任意尺度的,不需要在特征提取前对图像做resize操作,在SPP layer中每一个pooling的filter会根据输入调整大小,而SPP的输出尺度始终是固定的;
假设原图输入是224x224,对于conv5出来后的输出是13x13x256的,可以理解成有256个这样的filter,每个filter对应一张13x13的reponse map。如果像上图那样将reponse map分成1x1(金字塔底座),2x2(金字塔中间),4x4(金字塔顶座)三张子图,分别做max pooling后,出来的特征就是(16+4+1)x256 维度。如果原图的输入不是224x224,出来的特征依然是(16+4+1)x256维度。这样就实现了不管图像尺寸如何 池化n 的输出永远是 (16+4+1)x256 维度。 - 单层sppnet的网络层,叫做ROI Pooling。
1.5.3 Fast R-CNN原理
- 训练过程如上图所示,步骤如下:
1)将整张图片及划分好的ROI直接输入到全卷积的CNN中,此时整张图片进行全卷积操作,不需要对ROI进行全卷积操作,卷积后得到特征层和对应在特征层上的ROI(此时ROI可以根据其集合位置加卷积公式推导得出);
2)为了保证FCs(全连接层)输入尺寸一致,而特征层上的ROI尺寸大小不一,所以要经过ROI Pooling层处理,经过ROI Pooling层后转换为尺寸一致的特征向量(及调整为 M ∗ N M*N M∗N);
3)经过ROI Pooling层后,全部的2000个 M ∗ N M*N M∗N个训练数据通过全连接层并分别经过2个head:Softmax分类及L2回归,最终损失函数是分类和回归损失函数的加权和。 - 测试过程如下图所示。
重点:
1)R-CNN一大缺点:由于每一个候选框都要独自经过CNN,这使得花费的时间非常多。
解决:共享卷积层,现在不是每一个候选框都当做输入进入CNN了,而是输入一张完整的图片,在第五个卷积层再得到每个候选框的特征
2)原来的方法:许多候选框(比如两千个)–>CNN–>得到每个候选框的特征–>分类+回归
现在的方法:一张完整图片–>CNN–>得到每张候选框的特征–>分类+回归
3)所以容易看见,Fast RCNN相对于RCNN的提速原因就在于:不像RCNN把每个候选区域给深度网络提特征,而是整张图提一次特征,再把候选框映射到conv5上,而SPP只需要计算一次特征,剩下的只需要在conv5层上操作就可以了。
在性能上提升也是相当明显的:
1.6 Faster R-CNN
1.6.1 Fast R-CNN缺点
- 选择性搜索selective search,找出所有的候选框,这个也非常耗时。
解决:加入一个提取边缘的神经网络,即选择候选框ROI的工作也交给神经网络来做了。做这样的任务的神经网络叫做Region Proposal Network(RPN)。
1.6.2 RPN网络原理
- RPN网络具体做法:
• 将RPN放在最后一个卷积层的后面;
• RPN直接训练得到候选区域; - RPN的核心思想是:构建一个小的全卷积网络,对于任意大小的图片,输出ROI的具体位置及该ROI是否为目标,RPN网络在卷积神经网络的最后一个特征上滑动。
- 如下图a)所示,最下面灰色的网络为卷积神经网络的特征层,红框表示RPN的输入,大小是 3 ∗ 3 3*3 3∗3,而后连接到256维的向量上。这个 3 ∗ 3 3*3 3∗3的窗口滑动经过整个特征层,并且每次计算都经过256维的向量并最终输出2个结果:该 3 ∗ 3 3*3 3∗3滑动窗口中是否有物体,以及该滑动窗口对应物体的矩阵框位置对应的4个值;
- b)图为将网络转化为正向立面进行计算的过程表示;
- 为了适应更多形状的物体,RPN定义了 K K K种不同尺度的滑窗,统一用 3 ∗ 3 3*3 3∗3的滑窗难以满足多种情况,此时定义一个专业名词anchor(anchor:译为锚点,位于 n ∗ n n*n n∗n窗口的中心处),每个anchor都以特征层(feature map)上的像素点为中心并且根据其尺寸大小进行后续计算的。在Faster R-CNN论文中,滑窗在特征层的每个位置使用3种大小和3种比例,共有 3 ∗ 3 = 9 3*3=9 3∗3=9个anchor,如上图中 n = 9 n=9 n=9。
- 针对分类任务,对于滑窗产生的每一个anchor都计算该anchor与真实标记矩阵框的IOU,当 I O U ≥ 0.7 IOU\ge0.7 IOU≥0.7时,便认为该anchor包含目标;当 I O U ≤ 0.3 IOU\le0.3 IOU≤0.3时,便认为该anchor不包含目标;当IOU介于0.3~0.7时,则不参与网络训练的迭代过程。
- 针对回归任务,需要预测anchor中心点的横、纵坐标以及anchor的宽、高,学习目标为anchor与真实box在四个值上的偏移,RPN为一个全卷机网络,可以用随机梯度下降SGD的方式进行端到端的训练。
- 需要注意的是,训练过程中与真实目标矩阵框相交的 I O U ≥ 0.7 IOU\ge 0.7 IOU≥0.7的anchor并不多,绝大多数都是负样本,因此会导致正负样本比例严重失衡。因此在RPN训练过程中,对每个batch进行随机采样(若每个batch样本数为256)并保持正负样本比例为1:1,而当正样本数量小于128时,去全部正样本,其余的则随机使用负样本进行补全。
1.6.3 Faster R-CNN原理
- Faster R-CNN训练过程如下图所示,训练步骤为:
1)使用对整张图片输进CNN,得到feature map;
2)卷积特征输入到RPN,得到候选框的特征信息;
3)对候选框中提取出的特征,输入ROI Pooling层变换为尺寸大小一致的候选特征;
4)将变换后的特征使用分类器判别是否属于一个特定类;
5)对于属于某一特征的候选框,用回归器进一步调整其位置。
1.7 总结各大算法步骤
参考网址:https://www.cnblogs.com/skyfsm/p/6806246.html
RCNN:
1. 在图像中确定约2000个候选框 (使用选择性搜索);
2. 每个候选框内图像块缩放至相同大小,并输入到CNN内进行特征提取 ;
3. 对候选框中提取出的特征,使用分类器判别是否属于一个特定类;
4. 对于属于某一特征的候选框,用回归器进一步调整其位置。
Fast RCNN:
1. 在图像中确定约2000个候选框 (使用选择性搜索);
2. 对整张图片输进CNN,得到feature map;
3. 找到每个候选框在feature map(即经过conv5后的特征层称为feature map)上的映射候选框,将此候选框作为每个候选框的卷积特征输入到SPP layer和之后的层;
4. 对候选框中提取出的特征,使用分类器判别是否属于一个特定类;
5. 对于属于某一特征的候选框,用回归器进一步调整其位置。
Faster RCNN:
1. 对整张图片输进CNN,得到feature map;
2. 卷积特征输入到RPN,得到候选框的特征信息;
3. 对候选框中提取出的特征,使用分类器判别是否属于一个特定类;
4. 对于属于某一特征的候选框,用回归器进一步调整其位置。
1.8 Mask RCNN
- Mask R-CNN是在Faster R-CNN的基础上进行2处修改,如下图其中黑色部分为原来的Faster-RCNN,红色部分为在Faster-RCNN网络上的修改:
1)增加预测mask的分支,即添加了并列的FCN层(mask层);
2)将RoI Pooling 层替换成了RoIAlign层;
1.8.1 RoIAlign
- RoIPooling是从RPN网络输出的ROI中输出较小的特征图(a small feature map,eg 7x7),ROI的大小各不相同,但是RoIPool后都变成了7x7大小。RPN网络会提出若干RoI的坐标以[x,y,w,h]表示,然后输入RoI Pooling,输出7x7大小的特征图供分类和定位使用。
- 问题就出在RoI Pooling的输出大小是7x7上,如果ROI网络输出的RoI大小是8*8的,那么无法保证输入像素和输出像素是一一对应,首先他们包含的信息量不同(有的是1对1,有的是1对2),其次他们的坐标无法和输入对应起来(1对2的那个RoI输出像素该对应哪个输入像素的坐标?)。这对分类没什么影响,但是对分割却影响很大。
- 如上图所示,在使用ROI Pooling时,原始图像是 800 ∗ 800 800*800 800∗800,狗的边框是 665 ∗ 665 665*665 665∗665,在经过VGG16特征提取后,使用了5个 2 ∗ 2 2*2 2∗2的池化,所以图像变为原始的 1 32 \frac{1}{32} 321,对于原始图像变为 ( 800 / 32 ) ∗ ( 800 / 32 ) = 25 ∗ 25 (800/32)*(800/32)=25*25 (800/32)∗(800/32)=25∗25,对于边框变为 ( 665 / 32 ) ∗ ( 665 / 32 ) = 20.78 ∗ 20.78 (665/32)*(665/32)=20.78*20.78 (665/32)∗(665/32)=20.78∗20.78,结果为浮点数,但像素点是整数,所以做了第一次量化操作(即取整操作)变为 20 ∗ 20 20*20 20∗20,这一次的量化操作引入了误差;
- 在feature map层,对于 20 ∗ 20 20*20 20∗20的ROI输入ROI Pooling层后输出固定尺寸 7 ∗ 7 7*7 7∗7ROI Feature,此时相当于 20 / 7 ∗ 20 / 7 = 2.86 ∗ 2.86 20/7*20/7=2.86*2.86 20/7∗20/7=2.86∗2.86,同样是浮点数,我们进行第二次量化操作,量化为2,这样引入了第二次的量化误差。
- RoIAlign采用==双线性差值法(ROI crop resize)==规避2次量化误差:
1)为了计算 P P P点像素值,可分别采用2次线性插值法计算出 R 1 R_1 R1和 R 2 R_2 R2的像素点,再使用一次线性插值法计算出 P P P点的像素值;
x
2
−
x
x
2
−
x
1
=
Q
21
−
R
1
Q
21
−
Q
11
\frac{x_2-x}{x_2-x_1}=\frac{Q_{21}-R_1}{Q_{21}-Q_{11}}
x2−x1x2−x=Q21−Q11Q21−R1
可得到
R
1
R_1
R1的像素点为:
R
1
=
x
2
−
x
x
2
−
x
1
Q
11
+
x
−
x
1
x
2
−
x
1
Q
21
R_1=\frac{x_2-x}{x_2-x_1}Q_{11}+\frac{x-x_1}{x_2-x_1}Q_{21}
R1=x2−x1x2−xQ11+x2−x1x−x1Q21
同理可得到
R
2
R_2
R2的像素点为:
R
2
=
x
2
−
x
x
2
−
x
1
Q
12
+
x
−
x
1
x
2
−
x
1
Q
22
R_2=\frac{x_2-x}{x_2-x_1}Q_{12}+\frac{x-x_1}{x_2-x_1}Q_{22}
R2=x2−x1x2−xQ12+x2−x1x−x1Q22
最终在y方向上进行线性差值,得到
P
P
P点像素值为:
P
=
y
2
−
y
y
2
−
y
1
R
1
+
y
−
y
1
y
2
−
y
1
R
2
P=\frac{y_2-y}{y_2-y_1}R_1+\frac{y-y_1}{y_2-y_1}R_2
P=y2−y1y2−yR1+y2−y1y−y1R2
- 讲解ROI Align操作:
1)黑色部分为feature map,红色边框表示ROI,为了输出 7 ∗ 7 7*7 7∗7的矩阵框,所以将ROI切分成 7 ∗ 7 7*7 7∗7的单元格,在每个单元格中均匀采样4个点(作者发现将采样点设为4会获得最佳性能),针对单元格中的4个点(将单元格划分为 2 ∗ 2 2*2 2∗2的小单元格),针对每个点及周围已知像素点值为位置,采用双线性差值法得出该点像素点值,最后对4个点的像素点值进行maxpooling,就得到 7 ∗ 7 7*7 7∗7像素点矩阵图,最终得到ROIAlign结果。
1.8.2 Mask分支
- Mask RCNN模型损失函数为:
L o s s = L c l s + L b o x + L m a s k Loss=L_{cls}+L_{box}+L_{mask} Loss=Lcls+Lbox+Lmask - 训练网络时输入Mask分支的目标是有RPN提供的,即Proposals(正样本);预测的时候输入Mask分支的目标是有Faster RCNN提供;
- 训练时:经过RPN得到的Proposal,通过RoIAlign后得到对应的特征信息(shape为14x14xC),进入Mask分支,计算每个类别的logits,通过Faster R-CNN分支正负样本匹配过程我们能够知道该Proposal的GT类别为猫(cat),所以将logits中对应类别猫的预测mask(shape为28x28)提取出来。然后根据Proposal在原图对应的GT上裁剪并缩放到28x28大小,得到图中的GT mask(对应目标区域为1,背景区域为0)。最后计算logits中预测类别为猫的mask与GT mask的BCELoss(BinaryCrossEntropyLoss)即可。
- 预测时:通过Faster R-CNN分支,我们能够得到最终预测的目标边界框信息以及类别信息。接着将目标边界框信息提供给Mask分支就能预测得到该目标的logits信息,再根据Faster R-CNN分支提供的类别信息将logits中对应该类别的Mask信息提取出来,即针对该目标预测的Mask信息(shape为28x28,由于通过sigmoid激活函数,数值都在0到1之间)。然后利用双线性插值将Mask缩放到预测目标边界框大小,并放到原图对应区域。接着通过设置的阈值(默认为0.5)将Mask转换成一张二值图,比如预测值大于0.5的区域设置为前景剩下区域都为背景。现在对于预测的每个目标我们就可以在原图中绘制出边界框信息,类别信息以及目标Mask信息。
最终,Mask RCNN预测的是目标的边界框、目标的类别和目标的阴影区域。
Mask RCNN参考网址:https://blog.csdn.net/qq_37541097/article/details/123754766