faster-rcnn论文连接:https://arxiv.org/pdf/1506.01497.pdf
代码地址:https://github.com/zacks417/faster-rcnn-tf
按照论文思路并参考了其他版本的源码,这版代码是我加过注释的tf版本,在我自己的电脑上能跑通。
本机实验环境:py3.6, CUDA9.0, tf1.7,GTX1070。
下面讲解一下faster-rcnn整体网络流程
以VGG16为backbone来讲解faster-rcnn整体流程
以vgg网络输入为**600x800x3**为例,网络的**conv5_3**为rpn网络的输入,就是上图中的feature Map, 大小为**1x38x50x512**
,backbone部分就不讲了,比较简单.
RPN部分:
下图为rpn的结构图,输入即为conv5_3,输出rois(128x84)128个感兴趣区域,84为21x4,即为每个类别都预测bbox。
conv5——3首先通过3x3 same卷积降维,记为rpn_conv,维度变成1x38x50x512,接下去是两个分支,都用的1x1卷积,数量分别为anchorsx2(前景后景),x4(两个点坐标)。
下面分支**rpn_bbox_pred**(1x38x50x36)为预测框的坐标和anchor的offset。
上面rpn_cls_score(1x38x50x18,这里最后为18,9x2,是包含了背景的,一会计算标签hloss会去掉背景)为分类得分图,最上面分支中通过加入地面真实框、图像高宽信息、网络总步长、总anchors数量(9)通过anchor_target_layer层生成rpn_label(1x1x38x50),这个函数在代码文件 ./layer_utils/anchor_target_layer中,该函数同时还生成rpn_bbox_targets(anchor和gt_box之间的offset回归目标)以及相对应的权重rpn_bbox_inside_weights,rpn_bbox_outside_weights,等会用于计算rpn_loss_box和rpn_cross_entropy。
然后是rpn_cls_score下面这个分支做一次reshape为rpn_cls_score_reshape(维度1x38x(50x9)x2,这个去除掉-1的标签之后与rpn_label求交叉softmax损失),便于做softmax二分类,接着reshape成[38x50x9,2]在第二个维度2上进行argmax求索引,为类别预测结果rpn_cls_pred维度为(38x50x9,);
将rpn_cls_score_reshape在最后一个维度(2)上做softmax二分类为rpn_cls_prob_reshape(维度为1x38x(50x9)x2)然后再把这个9 reshape回去为rpn_cls_prob(维度1x38x50x18)
此时加入地面真实框、图像高宽、网络步长、总anchor数(9)、之前预测的rpn_bbox_pred通过一层proposal_layer生成rois和对应的rois_scores(nms之前先按得分排序选取前12000个,nms后剩余2000个proposal)(2000x5,5是序号+两个坐标)。
然后再加入地面真实框和类别数(20+1背景也算一类而且是序号0)经过proposal_target_layer生成rois(128x84,21x4每个类别都有坐标),同时还会生成_proposal_targets字典,存放rois、labels、bbox_targets、bbox_inside_weights、bbox_outside_weights,等会用来计算RCNN的损失反过来进行修正。到此,rpn网络已经产生输出建议区域。
下面先列一下rpn网络的两个损失,之前都有提到过:
RPN分类损失:
rpn_cross_entropy = tf.reduce_mean(tf.nn.sparse_softmax_cross_entropy_with_logits(logits=rpn_cls_score,labels=rpn_label))
RPN回归损失:
这里是计算预测框的坐标和anchors的offset 和 anchors和地面真实框的offset,两个offset的差值作为回归目标,用smooth-l1损失计算
rpn_loss_box = self._smooth_l1_loss(rpn_bbox_pred,rpn_bbox_targets,rpn_bbox_inside_weights,rpn_bbox_outside_weights,sigma=sigma_rpn,dim=[1,2,3])
ROIPooling部分,如下图所示,前面rpn生成的rois感兴趣区域中有两个坐标点,将它映射到conv5-3的特征图上即为感兴趣区域,对这一部分进行池化,_crop_pool_layer函数在network.py中这版代码没有实现ROI Pooling layer 而是把ROI对应的特征图resize成相同尺寸(14x14)后再进行 max pooling(之后是7x7)生成pool5。 (后面tf直接有mask-rcnn提出的ROIAlign中采用的双线性插值的裁剪图片方法tf.image.crop_and_resize(images, boxes, batch_inds,[pooled_height, pooled_width], method='bilinear', name='Crop'))
RCNN分类和回归:
输入是之前的pool5(128x7x7x512),经过两层全连接层(后接relu)然后分别用全连接层生成目标框预测结果bbox_pred(128x4)、全连接层后接softmax生成类别预测结果cls_prob(128x21),这里可以理解为全连接层生成结果对RPN生成的结果进行修正。结构如下图所示
下面介绍一下RCNN的损失,也是两类
分类损失
这里的输入是最后全连接层的输出,没有经过softmax的(对应tf.nn.sparse_softmax_cross_entropy_with_logits这个函数),标签是RPN网络最后proposal_target_layer生成的label
cross_entropy = tf.reduce_mean(tf.nn.sparse_softmax_cross_entropy_with_logits(logits=cls_score,labels=label))
回归损失
输入一个为最后全连接层的输出,另一个为RPN最后的bbox输出,用来对RPN输出的bbox进行修正。
loss_box = self._smooth_l1_loss(bbox_pred,bbox_targets,bbox_inside_weights,bbox_outside_weights)
至此,faster-rcnn一整套流程均完结,更详细的实现可看源码,我在代码中均加入了注释便于理解。
此外论文中提到的交替训练我这里并没有实现,我采用的是end-to-end训练方法,以后有时间再把交替训练的方法加进去。