论文题目:Faster R-CNN: Towards Real-Time Object Detection with Region Proposal Networks
论文地址:https://arxiv.org/abs/1506.01497
代码地址:https://github.com/endernewton/tf-faster-rcnn 或者
https://github.com/dBeker/Faster-RCNN-TensorFlow-Python3
Faster R-CNN可以解决Fast RCNN使用第三方工具selective search提取region proposal的问题,它用RPN代替selective search,将整个目标检测功能做成一个统一的网络。Faster RCNN运用RPN,使得region proposal的计算更加elegant和efficient,RPN是一个全卷积网络,候选区域生成和目标检测共享卷积特征,并且运用了attention机制,RPN会告诉网络应该关注什么地方。
一、对论文的解读
1、RPN(region proposal network),区域生成网络
RPN是faster rcnn的核心,它的本质是基于滑窗的无类别obejct检测器,图像每个位置有多种类型的anchor boxes(region proposal),用这些region proposal 训练 faster rcnn,分类和框回归通过梯度下降反向传播调节网络参数,重新生成region proposal,再继续训练faster rcnn,不断重复这个过程。
详细内容可以参考:https://blog.csdn.net/qq_32172681/article/details/99104310
2、Faster RCNN
Faster RCNN分为3个模块:第1个模块是提取图像的公共特征网络,第2个模块是深度全卷积神经网络用来生成region proposals,第3个模块是利用这些生成的region proposals做Fast RCNN目标检测器。整个系统是一个统一的网络,并采用了attention机制,RPN模块会告诉Fast RCNN模块注意力应该在什么地方。
(1)把RPN看作一个黑盒,它输入一张任意size的图像,输出一系列矩形region proposals和每个region proposals的score。
(2)采用全卷积神经网络
(3)为了共享计算,让候选框生成网络和目标检测网络共享一系列卷积层。如VGG16,共享13个卷积层。
(4)为了生成region proposals,在卷积层的最后一个卷积层的feature map输出上,加上了一个小型网络。这个小网络输入n*n 窗口到feature map中,每个滑动窗口映射到一个低维特征,这个特征喂入到2个并行全连接层:1个框回归层reg和一个分类层cls。论文中n=3,但是输入图像的感受野很大,比如VGG是228 pixels。由于mini-network是通过滑动窗口操作的,所以对于所有的空间位置,全连接层参数也是共享的。
3、Anchors
anchor就是feature map上的一个像素,以该anchor为中心,可以生成k种anchor boxes(region proposal),每个anchor boxes有着不同的宽高比和缩放比,论文中使用的3种宽高比是(1:2,1:1,2:1),3种缩放比是(128,256,512),因此每个anchor产生9个anchor boxes。
4、Translation-Invariant anchors (平移不变性)
由于RPN采用FCN网络,参数共享,具有平移不变性。当每个anchor的anchor boxes个数为9时,输出有(4+2)*9d的输出参数,其中4为框位置的4个位置参数,2为分类分支输出参数的个数(有目标/无目标)。正是因为anchors的平移不变性,我们方法的参数比其他方法少很多。
5、multi-scale Anchors
multi-scale Anchors是特征共享的关键,多尺度预测,有以下3种方式:
(1)image:pyramids of images
(2)feature map:pyramids of filters with multiple scale/sizes
(3)anchor boxes:pyramids of reference boxes in the regression functions(论文提出的)
6、损失函数(RPN loss + Fast RCNN loss)
IoU > 0.7,=> positive proposals
IoU < 0.3,=> negative proposals
0.3 < IoU < 0.7, => 舍去,不参加训练
损失函数定义:
其中:
(1)i是anchor的index
(2)pi是anchor i 有物体的可能性
(3)pi*是真值,1表示positive,0表示negative
(4)ti是候选框的4个位置参数
(5)ti*是positive anchor的真值
(6)Lcls是分类损失
(7),其中R是Smooth L1
(8)pi*表示Lreg只在positive anchor情况下会激活,也就是pi*=1,其他情况下pi*=0
(9)是平衡两种损失Lcls和Lreg的平衡因子
(10)Ncls、Nreg是为了归一化这两个式子
(11)分类用交叉熵损失、回归用smooth L1损失
7、框回归
(1)x、y、w、h表示一个box的中心坐标和它的宽、高
(2)X、Xa、X*分别是预测值、anchor box、真值,Wa、ha分别是anchor box的宽度、高度
由上述公式可以看出,框回归的是以anchor box为基准的差值,这样比漫无目的的回归效率更高,框回归的过程就是从anchor box到真值的过程。在这个过程中,RoI可以是任意size,框回归的权重参数被所有size的region proposals共享。每个regressor负责1个宽高比和缩放比的anchor,k(k=9)个regressors不共享权重参数。
8、RPNs training
(1)随机抽取图像的256个anchor计算mini-batch的损失。positive:negative = 1:1,若positive anchor的个数小于128,将用negative anchor填充。
(2)用0均值、0.01为标准差的高斯分布初始化所有新层,其他层被ImageNet pretrained model 的参数初始化。
(3)前60k个mini-batchs的迭代,学习率为0.001;然后将学习率降低到0.0001,再继续训练20k个迭代。momentum为0.9,权重衰减率为0.0005.
(4)网络:VGG16
9、2种训练方式
RPN和Fast RCNN共享feature
(1)Alternating training
分开训练。先训练RPN,然后使用得到的候选区域训练Fast R-CNN,之后再使用得到的Fast R-CNN中的CNN去初始化RPN的CNN再次训练RPN(这里不更新CNN,仅更新RPN特有的层),最后再次训练Fast R-CNN(这里不更新CNN,仅更新Fast R-CNN特有的层)。依此迭代下去。
(2)Approximate joint training
在这个解决方案中,RPN 和 Fast R-CNN 网络在训练期间被合并到一个网络中。在每个SGD迭代中,正向的这一趟(Forward Pass)生成区域提议,在训练 Fast R-CNN检测器时则被当做固定,预先计算好的提议区 。 反向传播没有什么特别之处,只是对于共享层,来自RPN 的损失 和 Fast R-CNN的损失的向后传播的信号被组合起来的。 这个解决方案很容易实现。 但是这个解决方案忽略了 提案框的坐标也是神经网络的响应,所以是近似的。 在我们的实验中,我们经验发现,这个求解器产生了接近的结果(与下表中展示的交替训练的69.9%相比,mAP为70.0%),与交替训练相比,训练时间减少约25-50%。
10、4-step training
(1)公共特征提取网络被ImageNet-pre-trained Model vgg16初始化,并对region proposal 任务进行fine-tuning。
(2)使用step1产生的RPN proposals训练一个单独的Fast-RCNN目标检测网络,该网络也由ImageNet-pre-trained Model初始化,这两个网络不共享卷积层。
(3)用这个目标检测网络去初始化RPN训练,固定共享的卷积层参数,只微调RPN独自的层。
(4)保持RPN的卷积层参数不变,只微调单独的Fast RCNN层。
就这样,2个网络共享卷积层,而且形成了一个统一的网络,接下来只要run更多的迭代次数。
这个文章讲的不错:https://blog.csdn.net/weixin_40449426/article/details/78141635
11、NMS
为了去除大量重复的RPN proposals,采用NMS,设置IoU阈值为0.7,这样就可以减少大量冗余的proposals
12、思考:faster rcnn中的rpn和fast rcnn模块,它们的标签有什么区别?
(1) rpn输出数据:
rpn_class_logits----(1,216888,2) 代表了每个RPN box是物体和背景的类别
rpn_probs, rpn_bbox---(1,216888,4) 代表了每个RPN box相对于anchor的delta数据
(1) fast rcnn输出数据:
mrcnn_class_logits (1000,81) 结果是这1000个ROI所属物体的类别的score
mrcnn_class (1000,81) 结果是这1000个ROI所属物体的类别的概率
mrcnn_bbox (1000,81,4) 结果是1000个ROI对每个类别所产生的bbox的偏移,这里不是真正的坐标,只是针对RPN结果的delta
13、思考:rpn和rcnn输出格式
rpn分类分支输出w*h*9*2,分别表示是背景和是前景的概率。
rpn框回归分支输出w*h*9*4,分别表示框的左上角左边和宽高。
rpn的置信度就是有目标的概率。
fast rcnn的分类分支输出num*(k+1),分别表示k类目标的概率,1是背景
fast rcnn的框回归分支处处num*k*4,分别表示k类的框位置参数。
14、思考:rpn和rcnn的置信度是如何定义的?
置信度是类别概率,对于rpn来说就是前景的概率,对于rcnn来说,就是某一确定类别概率
15、思考:为啥叫近似联合训练?
因为训练rcnn的时候,proposal和特征图一起输入,此时proposal是相当于固定好的。所以这一步没有梯度反传,但其实rcnn的loss对proposals的loss也有影响,所以叫近似联合训练。
更多疑问解答:https://www.cnblogs.com/JZ-Ser/articles/7689158.html
二、对代码的解读
代码解析原文地址:https://blog.csdn.net/qq_41576083/article/details/82966489
先回忆一下网络结构图:
整个网络大体有三个部分组成,首先是公共的(1)特征提取网络,目前在看的源码中可以选择VGG16等网络来作为特征提取网络,继而在特征提取网络的最后输出的基础上,再加一个(2)RPN网络,RPN网络主要用于输出候选框(roi)的坐标修正量以及针对每一个候选框的置信度打分。最后是一个(3)fast-rcnn网络,用于生成最终的目标框坐标以及目标框内的类别信息。
主要网络结构:
使用network作为基类,又分别实现了vgg16等类,这些类的差别仅在于对于特征提取网络的不同选择,而整个网络结构的搭建主要在network.py的_build_network(self,is_training)函数中实现:
针对这个函数其实是由许多阶段性网络结构拼接而成,我们接下来逐个分析一下:
1、特征提取函数_image_to_head(is_training)
本函数可以理解为一个虚函数,在以不同网络结构作为基础的特征提取网络中,我是选择的vgg16网络,下面是其实现:
可以看到本函数输出的就是普通的一个vgg16的五层卷积后的输出特征图。
2、anchor生成
对于公共特征提取网络输出结果,stride和大概为16,即输入图片尺寸与输出特征图(也可以理解为是一个图片,反正都是一个矩阵)尺寸的比,假设最后输出特征图尺寸为60X60,那么可以理解为60X60个点,每一个点都可以作为一个窗口中心点,那么窗口的尺寸呢?这就是anchor的用处,每一个anchor即对应9个(一般是9个)窗口尺寸,再将每一个窗口应用在每一个中心点上,用来截取原图像,那么一共可以截取60X60X9约3W幅图片,即60X60X(9X4)个坐标。然后针对这些窗口,网络又需要预测窗口中是否存在目标,即对于每一个窗口还要有两个概率输出,也就是一共要有60X60X(9X2)概率得分,用于甄别对应的候选框里是否存在目标,达到候选窗筛选的功能,下面贴代码逐句分析:
可以看到,函数一开始先利用原图尺寸以及stride数值来推算经过特征提取后输出的特征图尺寸,即上文中假设的60X60。
之后有两种情况,这也是通过配置类config的对象cfg提前设置的,下面主要看一下generate_anchors_pre函数:
大概的分开看一下这个函数,首先是generate_anchors()函数,功能就是生成9个不同面积不同长宽比的窗口,接下来根据height和width,将9个尺寸的窗口应用于(height X width)个中心点上,生成height X width X 9 个具体的窗口,也就是height X width X (9X4)个具体的坐标,即上文中假设的60X60X(9X4)个坐标。
anchors为[H*W*9,4]张量,即针对每个中心点有九个窗口。
返回_anchor_componet()函数,将得到的候选窗坐标保存在类成员变量self._anchors中。
3、RPN网络(生成roi区域、构造其真值标签)
接下来,_build_network() 又通过_region_proposal()函数来生成了roi区域,即该函数实现了RPN网络的功能,看一下代码:
该函数比较复杂,因为RPN网络本身作为一个神经网络就需要训练,所以在得到结果的同时,必须还要根据样本构造其真值标签。而RPN网络又有两个输出支路(上文有提及的得分和坐标),所以可以将这一段程序看作两大部分,即(1)构造网络结构(2)构造真值样本,其中又分别针对两个输出支路,故有4小部分。
(1)构造RPN网络结构
首先是一个3X3卷积,之后通过各种reshape,softmax得到rpn_cls_prob这个张量,尺寸为[-1,W, H, 9*2],即之前假设的对于每一张图的60X60X(9X2)个得分,以及rpn_bbox_pred [-1, W, H, 9*4] 为候选框roi的修正量,结合之前得到的self._anchors即可得候选框坐标。
(2)预测候选框的分类score和位置(proposal_layer函数)
(3)构造候选框的标签(用于构造RPN的分类和回归loss,anchor_target_layer函数很长,分几部分看)
第1部分:将超出原图像尺寸范围的候选窗直接pass掉,保留剩下的窗口,并且创了一个label,用于存放相应窗口的ground truth。
第2部分:对于每个候选窗口,找到其与所有真值窗口中IOU最大的窗口索引;对于每个真值窗口,找到与其重叠比例最大的候选框
第3部分:根据IOU对当前的窗口进行标注(有目标/无目标),用于构造分类损失
标注的原则:
(1)对每个标定的真值候选区域,与其重叠比例最大的anchor记为前景样本
(2)对剩余的anchor,如果其与某个标定重叠比例大于0.7,记为前景样本
(3)如果其与任意一个标定的重叠比例都小于0.3,记为背景样本
经过这样的处理,labels就是包含如下内容:
(1)对于废弃的窗口,其对应的label为-1
(2)对于认为是目标的窗口,其对应的label为1
(3)对于认为是背景的窗口,其对应的label为0
根据标注规则,标注前景样本和背景样本,只对前景样本求框偏移的回归目标
这样就可以根据这个labels作为ground truth来使用交叉熵训练RPN网络中的得分支路(就是rpn_cls_prob)。
第4部分:构造(候选框预测值与真值的位置)差异,用于构造框回归损失
第5部分:bbox_outside_weights以及bbox_inside_weights就是简单的针对前后景样本的权值。
(4)构造用于训练Fast-RCNN的真值标签以及回归目标(_proposal_target_layer)
此处调用_sample_rois构造标签与回归框修正:
至此,最终fast-rcnn的预测标签以及回归框修正就已经构造完成,将其保存在self._proposal_targets里面,用于后续loss定义。
这样整个RPN网络就构造完成了,除了RPN网络外,在训练时还额外加了两个真值生成层(anchors_target_layer, proposal_target_layer)以及roi筛选层proposal_layer。
4、ROI pooling(_crop_pool_layer)
将这些候选区域映射至5层卷积后的特征图上,并截取相应区域,完成池化后输出第五层池化结果pool5。
5、将pool5输入两层全连接网络(_head_to_tail)
该函数也是个虚函数,具体的定义要根据选择的基础网络而定,本次选择vgg16,故可以在vgg16.py中看到此函数定义,简单的讲就是两层全连接层,输出结果fc7。
6、根据fc7完成最后的目标分类+框回归(一个全连接+softmax来分类,一个全连接来回归边框)
7、loss定义(_add_losses)
由于整个大的网络是由三个网络拼接的,最前面的vgg16只是提取特征,而RPN以及fast-RCNN均有预测输出,如图:
所以整个loss由4个部分组成:RPN分类loss、RPN框回归loss、RCNN分类loss、RCNN框回归loss