simple Faster RCNN 实现(转自陈云https://zhuanlan.zhihu.com/p/32404424)
faster rcnn 流程
从编程角度来说,Faster RCNN分为四部(图中四个绿框):
Dataset:数据,提供符合要求的数据格式
Extractor:利用CNN提取图片特征,features
RPN:负责提供候选区域rois
RoIHead:负责对rois分类和微调。
2详细实现**
2.1.数据
对每张图片,进行如下处理:
图片缩放,使得长边小于等于1000,短边小于等于600(至少有一个等于)。
对相应的bounding boxes 也进行同等尺度的缩放。
对于Caffe的VGG16预训练模型,需要图片位于0-255,BGR格式,并减去一个 均值,使得图片像素均值为0。
最后返回四个值供模型训练:
images:3×H×W ,BGR三通道,宽W,高H
bboxes: 4×K , K个bounding boxes,每个bounding box的左上角和右下角的座标,形如(Y_min,X_min, Y_max,X_max),第Y行,第X列。
labels:K, 对应K个bounding boxes的label(对于VOC取值范围为[0-19])
scale: 缩放的倍数, 原图H’ ×W’被resize到了HxW(scale=H/H’ )
需要注意的是,目前大多数Faster R-CNN实现都只支持batch-size=1的训练
2.2Extractor
Extractor使用的是预训练好的模型提取图片的特征。论文中主要使用的是Caffe的预训练模型VGG16。修改如下:为了节省内存,前四层卷积的学习率设为0。Conv5_3的输出作为图片 特征(feature)。conv5-3的输出作为图片特征(feature)。conv5-3相比于输入,下采样了16倍,也就是说输入的图片尺寸为3xHxW,那么feature的尺寸就是Cx(H/16)x(W/16)。VGG最后的三层全连接层的前两层,一般用来初始化RoIHead的部分参数。
2.3,RPN
Faster RCNN最突出的贡献在于提出RPN代替selectiveSearch,从而将候选区域提取的时间开销几乎将为0(2s->0.01s)
2.31
九种anchor在特征图左右上下移动,每一个特征图上的点都有九个anchor,最终生成(H/16)x(W/16)x9个anchor。对于一个512×62×37的feature map,有 62×37×9~ 20000个anchor。 也就是对一张图片,有20000个左右的anchor。这种做法很像是暴力穷举,20000多个anchor,哪怕是蒙也能够把绝大多数的ground truth bounding boxes蒙中。
2.32训练RPN
RPN框架:
anchor的数量和feature map相关,不同的feature map对应的anchor数量也不一样。RPN在Extractor输出的feature maps的基础之上,先增加了一个卷积(用来语义空间转换?),然后利用两个1x1的卷积分别进行二分类(是否为正样本)和位置回归。进行分类的卷积核通道数为9×2(9个anchor,每个anchor二分类,使用交叉熵损失),进行回归的卷积核通道数为9×4(9个anchor,每个anchor有4个位置参数)。RPN是一个全卷积网络(fully convolutional network),这样对输入图片的尺寸就没有要求了。
对于每一个ground truth bounding box (gt_bbox),选择和它重叠度(IoU)最高的一个anchor作为正样本对于剩下的anchor,从中选择和任意一个gt_bbox重叠度超过0.7的anchor,作为正样本,正样本的数目不超过128个。随机选择和gt_bbox重叠度小于0.3的anchor作为负样本。负样本和正样本的总数为256。对于每个anchor, gt_label 要么为1(前景),要么为0(背景),而gt_loc则是由4个位置参数(tx,ty,tw,th)组成,这样比直接回归座标更好。 计算分类损失用的是交叉熵损失,而计算回归损失用的是Smooth_l1_loss. 在计算回归损失的时候,只计算正样本(前景)的损失,不计算负样本的位置损失。
2.3.3RPN生成Rols
RPN在自身训练的同时,还会提供RoIs(region of interests)给Fast RCNN(RoIHead)作为训练样本。RPN生成RoIs的过程(ProposalCreator)如下:对于每张图片,利用它的feature map, 计算 (H/16)× (W/16)×9(大概20000)个anchor属于前景的概率,以及对应的位置参数。选取概率较大的12000个anchor利用回归的位置参数,修正这12000个anchor的位置,得到RoIs利用非极大值((Non-maximum suppression, NMS)抑制,选出概率最大的2000个RoIs
注意:在inference的时候,为了提高处理速度,12000和2000分别变为6000和300.
注意:这部分的操作不需要进行反向传播,因此可以利用numpy/tensor实现。RPN的输出:RoIs(形如2000×4或者300×4的tensor)
2.4 RoIHead/Fast R-CNN
RPN只是给出了2000个候选框,RoI Head在给出的2000候选框之上继续进行分类和位置参数的回归。
2.4.1网络结构
由于RoIs给出的2000个候选框,分别对应feature map不同大小的区域。首先利用ProposalTargetCreator 挑选出128个sample_rois, 然后使用了RoIPooling 将这些不同尺寸的区域全部pooling到同一个尺度(7×7)上。下图就是一个例子,对于feature map上两个不同尺度的RoI,经过RoIPooling之后,最后得到了3×3的feature map.
Rol Pooling是一种特殊的Pooling操作,给定一张图片的Feature map(512xH/16xW/16),和128个候选区域的坐标(128x4),Rol Pooling将这些区域统一采样到(512x7x7),就得到了128x512x7x7的向量。可以看成是一个batch-size=128,通道数为512,7x7的feature map。
为什么要pooling成7x7的尺度?是为了能够共享权重。在之前讲过,除了用到VGG前几层的卷积之外,最后的全连接层也可以继续利用。当所有的Rols都被pooling成(512x7x7)的feature map后,将它reshape成一个一维的向量,就可以利用VGG16预训练的权重,初始化前两层全连接。最后再接两个全连接层,分别是:
FC21用来分类,预测Rols属于哪个类别(20个类+背景)
FC84用来回归位置(21个类,每个类都有4个位置参数)
2.4.2训练
前面讲过,RPN会产生大约2000个RoIs,这2000个RoIs不是都拿去训练,而是利用ProposalTargetCreator 选择128个RoIs用以训练。选择的规则如下:
RoIs和gt_bboxes 的IoU大于0.5的,选择一些(比如32个)
选择 RoIs和gt_bboxes的IoU小于等于0(或者0.1)的选择一些(比如 128-32=96个)作为负样本
为了便于训练,对选择出的128个RoIs,还对他们的gt_roi_loc 进行标准化处理(减去均值除以标准差)
对于分类问题,直接利用交叉熵损失. 而对于位置的回归损失,一样采用Smooth_L1Loss, 只不过只对正样本计算损失.而且是只对正样本中的这个类别4个参数计算损失。举例来说:
一个RoI在经过FC 84后会输出一个84维的loc 向量. 如果这个RoI是负样本,则这84维向量不参与计算 L1_Loss
如果这个RoI是正样本,属于label K,那么它的第 K×4, K×4+1 ,K×4+2, K×4+3 这4个数参与计算损失,其余的不参与计算损失。
2.4.3生成预测结果
测试的时候对所有的RoIs(大概300个左右) 计算概率,并利用位置参数调整预测候选框的位置。然后再用一遍极大值抑制(之前在RPN的ProposalCreator用过)。
注意:
在RPN的时候,已经对anchor做了一遍NMS,在RCNN测试的时候,还要再做一遍
在RPN的时候,已经对anchor的位置做了回归调整,在RCNN阶段还要对RoI再做一遍
在RPN阶段分类是二分类,而Fast RCNN阶段是21分类
2.5模型架构图:
需要注意的是: 蓝色箭头的线代表着计算图,梯度反向传播会经过。而红色部分的线不需要进行反向传播(论文了中提到了ProposalCreator生成RoIs的过程也能进行反向传播,但需要专门的算法)。