FPN改装faster-RCNN
利用FPN构建Faster R-CNN检测器步骤
首先,选择一张需要处理的图片,然后对该图片进行预处理操作;
然后,将处理过的图片送入预训练的特征网络中(如ResNet等),即构建所谓的bottom-up网络;
接着,如图5所示,构建对应的top-down网络(即对层4进行上采样操作,先用1x1的卷积对层2进行降维处理,然后将两者相加(对应元素相加),最后进行3x3的卷积操作,最后);
接着,在图中的4、5、6层上面分别进行RPN操作,即一个3x3的卷积后面分两路,分别连接一个1x1的卷积用来进行分类和回归操作;
接着,将上一步获得的候选ROI分别输入到4、5、6层上面分别进行ROI Pool操作(固定为7x7的特征);
最后,在上一步的基础上面连接两个1024层的全连接网络层,然后分两个支路,连接对应的分类层和回归层;
reference:
RPN详解
目的是筛选出图片中有可能存在物体的坐标,供后面的分类使用
首先anchor是人为定义的,不是体现在网络里的具体结构,每个feature的像素在3x3卷积后的数据就包含k个anchor的信息在里面了
经过backbone输出一个512维向量(featuremap是例如vgg这类特征提取网络出来的,所以是512),再分别喂给两个网络class(cls)和regression(reg)网络,前者输出2-d的数据,代表是前景、背景的概率,也就是单纯判断是否存在物体(逻辑回归),后者输出4-d的数据,其代表物体的具体位置(x,y,h,w)(线性回归输出数值);
如果这个anchor有k个,那么cls就会产生2k个分类值和reg的4k个位置信息
其中cls决定了k个anchor中哪些是有物体的,reg则是决定了所有的anchor的具体大小
进一步理解RPN的操作(这里我的理解和网上的大都不一样,毕竟没有去看caffe写的源码((( ):
当backbone为VGG-16时,去掉FC和最后一层池化输出的strides为16,当输入的图为800x600,则到featuremap中的大小为$512*50*37$,那么经过3x3滑动窗口后会产生$512*50*37$的featuremap输出给后面的cls和reg
当k=9时
在cls中:
利用1x1卷积输出$18*50*37$的数据,reshape成$2*9*50*37$,这里相当于有$50*37$个点的判断,通过softmax判断0轴,即9个anchor中,哪个置信度最大,输出$9*50*37$
reg中:
同上先利用1x1转换为$36*50*37$的数据,reshape成$4*9*50*37$(4代表w,h,x,y),在proposal中输出上面cls中各自对应的置信度最大的anchor对应通道的值(也就是前面的9里选1个),输出为$4*50*37$,这里相当于输出了$50*37$个某类anchor的坐标
于是最后经过proposal处理后,RPN对应每个feature上的点,输出一个5维向量(p,w,h,x,y)(p是cls输出的置信度),即最后输出的shape为$5*50*37$,也就是$50*37$个候选框,在这里才会通过例如NMS这样的算法合并或者舍弃保留候选框。
经过Proposal Layer的时候,其loss为
i为被选中的anchor框,$ p^*_i$是anchor是否是有效的意思,取值为(0,1),$t^*_i$是维度为4的(w,h,x,y)标签位置向量,$t_i$是偏移量,下面解释。
$N$为归一化项
$N_{cls}$可以简单定义为输入图片的Size(比如输入图片为256x256($H*W$),那么经过vgg16输出后为16x16,那么$N_{cls}=\frac{H*W}{Stride^2}=16*16=256$就可以了),
$N_{reg}$为被定位的anchor的数量,当feature的每个像素有9个anchor,输入图片的size=256时,$N_{reg}=9*16*16=2304$,文中取了个大约值2400
$L_{cls}$用的是L1范数
$L_{reg}$是bounding box regression的拟合方法(在这篇2.4节讲的很透彻
$\lambda$是分类和位置的权重,默认为10
$t_i$是偏移量,里面有4个参数,用来平移、缩放预测框,以此与groundtruth的$t^*_i$衡量。
如果只使用坐标之间的平移量就是复杂线性问题,需要通过$t_i$中的变换成为可以用cnn解决的简单线性问题
细说$L_{reg}$
这个loss主要解决的,是如何将复杂的线性关系(如真实值与预测值直接的差值)转变为可以计算的y=wx 可以被cnn计算的方法
变换的原理bounding box regression原理(在这篇2.4节讲的很透彻),这里讨论只实现的方法:
首先,$L_{reg}(t_i,t^*_i)=R(t_i-t^*_i)$,R代表L1范数,$t$是偏移量,$i$是被选中的anchor序列;
$t_i$代表预测偏移量,里面包含4个变量数:$t_x,t_y,t_w,t_h$代表anchor的$x_a,y_a,w_a,h_a$相对于预测值$x,y,z,w$的偏移量,
$t^*_i$代表ground truth,同理里面也有四个变量,代表$x^*,y^*,w^*,h^*$对应相对于anchor的偏移量,实现的方法如下:
$$ t_x = (x − x_a)/w_a, \ t_y = (y − y_a)/h_a, \\ t_w = log(w/w_a), t_h = log(h/h_a), \\ t^∗_x = (x^∗ − x_a)/w_a, t^∗_y = (y^∗ − y_a)/h_a, \\ t^∗_w = log(w^∗/w_a), t^∗_h = log(h^∗/h_a), $$
这个loss的意义,就在于让预测值和真实值相对于anchor的偏差量最小化,因此,我们可以让reg网络直接输出预测偏差值$t_x,t_y,t_w,t_h$,然后基于anchor的坐标算出$t^*_x,t^*_y,t^*_w,t^*_h$再进行loss计算,这样可以使得每个侦测到物体的预测框都能学习到物体特征。
那么anchor的思想体现在哪呢?
体现在训练网络的时候,先确定每个点的anchor大小,
当图像中对某点的物体与anchor的IOU大于一定值时(这个值应该设置为接近1),将该点的对应的anchor置信度label标记为1,小于某个接近0的值时标记为0,这样就可以使得网络中的对应anchor只有当尺寸合适时置信度才会高,所以这就是一开始说的anchor大小是人为定制的,它并不体现在网络结构上
PS:RPN利用了CNN的平移不变性来决定区域
ROIpooling
输入通过RPN网络输出建议的区域坐标,映射在featuremap对应位置上
类似于spp根据输入图片的大小来改变池化层大小和步长,产生固定大小的输出
举个例子,假设我现在有一个8x8的featuremap,我的RPN给出了一个对应下图的5x7的区域:
我要输出的大小为2x2,那么根据类似sppnet的想法,roi中bin大小的计算方法:
上面这句注释的意思是RoI Pooling结果的每个bin在RoI中起始和结束的index。
比如对于上图来说最终RoI Pooling的结果的第0个bin,其实际计算应该是:
$start_{0h}=floor(0*5/2)=0 $
$end_{0h}=ceil(1*5/2)=3 $
$start_{0w}=floor(0*7/2)=0 $
$end_{0w}=ceil(1*7/2)=4 $
所以
$Pool[0,0]=Max(Roi[0:3,0:4])$
同理可得
$Pool[0,1]=Max(Roi[0:3,3:7])$
$Pool[1,0]=Max(Roi[2:5,0:4])$
$Pool[1,1]=Max(Roi[2:5,3:7])$
也就是实际上应该如下图划分bin:
最后输出的结果为:
- reference:
https://zhuanlan.zhihu.com/p/66124459
但是这种ROIpooling有两个量化误差的问题
只会在训练的时候出现的问题
1.图片缩放时,标记位置取整造成的误差
训练的时候原图Size为800x800,标记的区域为600*600,经过backbon(假设是上面的VGG16)后原图尺寸缩小为25x25,而标记区域则变为18.75x18.75,根据c++源码中取整的操作,会变成18x18,这就会0.75的偏差,放大了就是24像素的偏差。
2.Roi池化时,为输出对应尺寸造成的误差
拿上面的结果来说,假设我现在要把这个18x18的proposal区域经过ROi变成7x7,根据源码可知会通过
$ ksize=math.floor(\frac{20}{7})=2$
$ stride=math.ceil(\frac{20}{7})=3$
来构造池化核。
这个ksize中的尺寸本应为2.857,但是为了池化核的构造而向下取整,并且因为stride比ksize还大就造成再一次的量化误差。
为了解决这两个问题,何凯明提出了
ROI Align(论文地址)
不是使用普通池化的方法滑动池化核,而是一种直接按对应位置给出池化值的方法
1.图片标记位置时,保留其小数点,并在featuremap上映射出带小数点的对应位置,这就是proposal区域
2.根据pool后要输出的尺寸定义bin的个数(如要输出7x7那就是7x7个bins)
3.把proposal区域用上面的bin等比例划分区域
4.每个bin再等分为4个dots,每个dot的取值根据featuremap中的像素点双线性插值确定
5.每个bin的值取其dot的极值(Roi中是取极值),起到池化的作用
6.得到7x7后的池化值。