zoukankan      html  css  js  c++  java
  • rcnn ->fast rcnn->faster rcnn物体检测论文

    faster rcnn中的rpn网络:

    特征可以看做一个尺度51*39的256通道图像,对于该图像的每一个位置,考虑9个可能的候选窗口:三种面积{1282,2562,5122}×三种比例{1:1,1:2,2:1}。这些候选窗口称为anchors。下图示出51*39个anchor中心,以及9种anchor示例。 

    讲解RPN网络比较好的博客:https://blog.csdn.net/sloanqin/article/details/51545125

    RCNN的缺点:

    1、图像wrap的问题

    2、计算量大

    FAST RCNN

    1、ROI pooling就是不同大小feature resize到一个固定大小

    2、Train end to end,multi task loss

    梯度如何从唯一大小回传到任意大小,如果有影响,相当于y=x,如果有影响就累加

    FASTER RCNN

    1、test的时候要做NMS,RPN

    2、Joint trainning

    首先rcnn,和fast rcnn都比较好理解

    fast rcnn其实就是roi+clc+bbox regression

    faster rcnn是rpn(region proposal network)+ fast rcnn,最后两个网络是迭代训练

    本弱找到一篇讲解faster rcnn比较好都博文,所以就速速搬过来了:

    缩进经过RCNN和Fast RCNN的积淀,Ross B. Girshick在2016年提出了新的Faster RCNN,在结构上,Faster RCN已经将特征抽取(feature extraction),proposal提取,bounding box regression(rect refine),classification都整合在了一个网络中,使得综合性能有较大提高,在检测速度方面尤为明显。

    图1 Faster CNN基本结构(来自原论文)

    缩进依作者看来,如图1,Faster RCNN其实可以分为4个主要内容:

    1. Conv layers。作为一种CNN网络目标检测方法,Faster RCNN首先使用一组基础的conv+relu+pooling层提取image的feature maps。该feature maps被共享用于后续RPN层和全连接层。
    2. Region Proposal Networks。RPN网络用于生成region proposals。该层通过softmax判断anchors属于foreground或者background,再利用bounding box regression修正anchors获得精确的proposals。
    3. Roi Pooling。该层收集输入的feature maps和proposals,综合这些信息后提取proposal feature maps,送入后续全连接层判定目标类别。
    4. Classification。利用proposal feature maps计算proposal的类别,同时再次bounding box regression获得检测框最终的精确位置。

    所以本文以上述4个内容作为切入点介绍Faster RCNN网络。

    缩进图2展示了Python版本中的VGG16模型中的faster_rcnn_test.pt的网络结构,可以清晰的看到该网络对于一副任意大小PxQ的图像,首先缩放至固定大小MxN,然后将MxN图像送入网络;而Conv layers中包含了13个conv层+13个relu层+4个pooling层;RPN网络首先经过3x3卷积,再分别生成foreground anchors与bounding box regression偏移量,然后计算出proposals;而Roi Pooling层则利用proposals从feature maps中提取proposal feature送入后续全连接和softmax网络作classification(即分类proposal到底是什么object)。

    path:${py-faster-rcnn-root}/models/pascal_voc/VGG16/faster_rcnn_alt_opt/faster_rcnn_test.pt

    图2 faster_rcnn_test.pt网络结构(放大网页看大图)

    1 Conv layers

    缩进Conv layers包含了conv,pooling,relu三种层。以python版本中的VGG16模型中的faster_rcnn_test.pt的网络结构为例,如图2,Conv layers部分共有13个conv层,13个relu层,4个pooling层。这里有一个非常容易被忽略但是又无比重要的信息,在Conv layers中:

    1. 所有的conv层都是:kernel_size=3,pad=1
    2. 所有的pooling层都是:kernel_size=2,stride=2

    为何重要?在Faster RCNN Conv layers中对所有的卷积都做了扩边处理(pad=1,即填充一圈0),导致原图变为(M+2)x(N+2)大小,再做3x3卷积后输出MxN。正是这种设置,导致Conv layers中的conv层不改变输入和输出矩阵大小。如图3:

    图3

    类似的是,Conv layers中的pooling层kernel_size=2,stride=2。这样每个经过pooling层的MxN矩阵,都会变为(M/2)*(N/2)大小。综上所述,在整个Conv layers中,conv和relu层不改变输入输出大小,只有pooling层使输出长宽都变为输入的1/2。

    缩进那么,一个MxN大小的矩阵经过Conv layers固定变为(M/16)x(N/16)!这样Conv layers生成的featuure map中都可以和原图对应起来。

    2 Region Proposal Networks(RPN)

    缩进经典的检测方法生成检测框都非常耗时,如OpenCV adaboost使用滑动窗口+图像金字塔生成检测框;或如RCNN使用SS(Selective Search)方法生成检测框。而Faster RCNN则抛弃了传统的滑动窗口和SS方法,直接使用RPN生成检测框,这也是Faster RCNN的巨大优势,能极大提升检测框的生成速度。

    图4 RPN网络结构

    上图4展示了RPN网络的具体结构。可以看到RPN网络实际分为2条线,上面一条通过softmax分类anchors获得foreground和background(检测目标是foreground),下面一条用于计算对于anchors的bounding box regression偏移量,以获得精确的proposal。而最后的Proposal层则负责综合foreground anchors和bounding box regression偏移量获取proposals,同时剔除太小和超出边界的proposals。其实整个网络到了Proposal Layer这里,就完成了相当于目标定位的功能。

    2.1 多通道图像卷积基础知识介绍

    缩进在介绍RPN前,还要多解释几句基础知识,已经懂的看官老爷跳过就好。
    1. 对于单通道图像+单卷积核做卷积,第一章中的图3已经展示了;
    2. 对于多通道图像+多卷积核做卷积,计算方式如下:
    图5 多通道+多卷积核做卷积示意图(摘自Theano教程)
    缩进如图5,输入图像layer m-1有4个通道,同时有2个卷积核w1和w2。对于卷积核w1,先在输入图像4个通道分别作卷积,再将4个通道结果加起来得到w1的卷积输出;卷积核w2类似。所以对于某个卷积层,无论输入图像有多少个通道,输出图像通道数总是等于卷积核数量!
    缩进对多通道图像做1x1卷积,其实就是将输入图像于每个通道乘以卷积系数后加在一起,即相当于把原图像中本来各个独立的通道“联通”在了一起。

    2.2 anchors

    缩进提到RPN网络,就不能不说anchors。所谓anchors,实际上就是一组由rpn/generate_anchors.py生成的矩形。直接运行作者demo中的generate_anchors.py可以得到以下输出:

    [python] view plain copy
     
    1. [[ -84.  -40.   99.   55.]  
    2.  [-176.  -88.  191.  103.]  
    3.  [-360. -184.  375.  199.]  
    4.  [ -56.  -56.   71.   71.]  
    5.  [-120. -120.  135.  135.]  
    6.  [-248. -248.  263.  263.]  
    7.  [ -36.  -80.   51.   95.]  
    8.  [ -80. -168.   95.  183.]  
    9.  [-168. -344.  183.  359.]]  

    其中每行的4个值[x1,y1,x2,y2]代表矩形左上和右下角点坐标。9个矩形共有3种形状,长宽比为大约为:height = [1:1, 1:2, 2:1]三种,如图6。实际上通过anchors就引入了检测中常用到的多尺度方法。

    图6 anchors示意图

    注:关于上面的anchors size,其实是根据检测图像设置的。在python demo中,会把任意大小的输入图像reshape成800x600(即图2中的M=800,N=600)。再回头来看anchors的大小,anchors中长宽1:2中最大为352x704,长宽2:1中最大736x384,基本是cover了800x600的各个尺度和形状。

    那么这9个anchors是做什么的呢?借用Faster RCNN论文中的原图,如图7,遍历Conv layers计算获得的feature maps,为每一个点都配备这9种anchors作为初始的检测框。这样做获得检测框很不准确,不用担心,后面还有2次bounding box regression可以修正检测框位置。

    图7

    解释一下上面这张图的数字。

    1. 在原文中使用的是ZF model中,其Conv Layers中最后的conv5层num_output=256,对应生成256张特征图,所以相当于feature map每个点都是256-d
    2. 在conv5之后,做了rpn_conv/3x3卷积且num_output=256,相当于每个点又融合了周围3x3的空间信息(猜测这样做也许更鲁棒?反正我没测试),同时256-d不变(如图4和图7中的红框)
    3. 假设一共有k个anchor,而每个anhcor要分foreground和background,所以cls=2k scores;而每个anchor都有[x, y, w, h]对应4个偏移量,所以reg=4k coordinates
    4. 补充一点,这k个anchor全部拿去训练太多了,训练程序会随机选取k中256个合适的anchors进行训练,这个256与上面的256-d不同(什么是合适的anchors下文5.1有解释)

    注意,在本文讲解中使用的VGG conv5 num_output=512,所以是512d,其他类似.....

    2.3 softmax判定foreground与background

    缩进一副MxN大小的矩阵送入Faster RCNN网络后,到RPN网络变为(M/16)x(N/16),不妨设W=M/16,H=N/16。在进入reshape与softmax之前,先做了1x1卷积,如图8:
    图8 RPN中判定fg/bg网络结构
    该1x1卷积的caffe prototxt定义如下:
    [cpp] view plain copy
     
    1. layer {  
    2.   name: "rpn_cls_score"  
    3.   type: "Convolution"  
    4.   bottom: "rpn/output"  
    5.   top: "rpn_cls_score"  
    6.   convolution_param {  
    7.     num_output: 18   # 2(bg/fg) * 9(anchors)  
    8.     kernel_size: 1 pad: 0 stride: 1  
    9.   }  
    10. }  
    可以看到其num_output=18,也就是经过该卷积的输出图像为WxHx18大小(注意第二章开头提到的卷积计算方式)。这也就刚好对应了feature maps每一个点都有9个anchors,同时每个anchors又有可能是foreground和background,所有这些信息都保存WxHx(9x2)大小的矩阵。为何这样做?后面接softmax分类获得foreground anchors,也就相当于初步提取了检测目标候选区域box(一般认为目标在foreground anchors中)。
    缩进那么为何要在softmax前后都接一个reshape layer?其实只是为了便于softmax分类,至于具体原因这就要从caffe的实现形式说起了。在caffe基本数据结构blob中以如下形式保存数据:
    blob=[batch_size, channel,height,width]
    对应至上面的保存bg/fg anchors的矩阵,其在caffe blob中的存储形式为[1, 2*9, H, W]。而在softmax分类时需要进行fg/bg二分类,所以reshape layer会将其变为[1, 2, 9*H, W]大小,即单独“腾空”出来一个维度以便softmax分类,之后再reshape回复原状。贴一段caffe softmax_loss_layer.cpp的reshape函数的解释,非常精辟:
    [cpp] view plain copy
     
    1. "Number of labels must match number of predictions; "  
    2. "e.g., if softmax axis == 1 and prediction shape is (N, C, H, W), "  
    3. "label count (number of labels) must be N*H*W, "  
    4. "with integer values in {0, 1, ..., C-1}.";  
    综上所述,RPN网络中利用anchors和softmax初步提取出foreground anchors作为候选区域。

    2.4 bounding box regression原理

    缩进介绍bounding box regression数学模型及原理。如图9所示绿色框为飞机的Ground Truth(GT),红色为提取的foreground anchors,那么即便红色的框被分类器识别为飞机,但是由于红色的框定位不准,这张图相当于没有正确的检测出飞机。所以我们希望采用一种方法对红色的框进行微调,使得foreground anchors和GT更加接近。

    图9

    缩进对于窗口一般使用四维向量(x, y, w, h)表示,分别表示窗口的中心点坐标和宽高。对于图 10,红色的框A代表原始的Foreground Anchors,绿色的框G代表目标的GT,我们的目标是寻找一种关系,使得输入原始的anchor A经过映射得到一个跟真实窗口G更接近的回归窗口G',即:给定A=(Ax, Ay, Aw, Ah),寻找一种映射f,使得f(Ax, Ay, Aw, Ah)=(G'x, G'y, G'w, G'h),其中(G'x, G'y, G'w, G'h)≈(Gx, Gy, Gw, Gh)。

    图10

    那么经过何种变换才能从图6中的A变为G'呢? 比较简单的思路就是:

    缩进 1. 先做平移

    缩进 2. 再做缩放

    缩进观察上面4个公式发现,需要学习的是dx(A),dy(A),dw(A),dh(A)这四个变换。当输入的anchor与GT相差较小时,可以认为这种变换是一种线性变换, 那么就可以用线性回归来建模对窗口进行微调(注意,只有当anchors和GT比较接近时,才能使用线性回归模型,否则就是复杂的非线性问题了)。对应于Faster RCNN原文,平移量(tx, ty)与尺度因子(tw, th)如下:

    缩进接下来的问题就是如何通过线性回归获得dx(A),dy(A),dw(A),dh(A)了。线性回归就是给定输入的特征向量X, 学习一组参数W, 使得经过线性回归后的值跟真实值Y(即GT)非常接近,即Y=WX。对于该问题,输入X是一张经过num_output=1的1x1卷积获得的feature map,定义为Φ;同时还有训练传入的GT,即(tx, ty, tw, th)。输出是dx(A),dy(A),dw(A),dh(A)四个变换。那么目标函数可以表示为:

    其中Φ(A)是对应anchor的feature map组成的特征向量,w是需要学习的参数,d(A)是得到的预测值(*表示 x,y,w,h,也就是每一个变换对应一个上述目标函数)。为了让预测值(tx, ty, tw, th)与真实值最小,得到损失函数:

    函数优化目标为:

    2.5 对proposals进行bounding box regression

    缩进在了解bounding box regression后,再回头来看RPN网络第二条线路,如图11。

    图11 RPN中的bbox reg

    先来看一看上图11中1x1卷积的caffe prototxt定义:

    [cpp] view plain copy
     
    1. layer {  
    2.   name: "rpn_bbox_pred"  
    3.   type: "Convolution"  
    4.   bottom: "rpn/output"  
    5.   top: "rpn_bbox_pred"  
    6.   convolution_param {  
    7.     num_output: 36   # 4 * 9(anchors)  
    8.     kernel_size: 1 pad: 0 stride: 1  
    9.   }  
    10. }  

    可以看到其num_output=36,即经过该卷积输出图像为WxHx36,在caffe blob存储为[1, 36, H, W]。与上文中fg/bg anchors存储为[1, 18, H, W]类似,这里相当于feature maps每个点都有9个anchors,每个anchors又都有4个用于回归的[dx(A),dy(A),dw(A),dh(A)]变换量。利用上面的的计算公式即可从foreground anchors回归出proposals。

    2.6 Proposal Layer

    缩进Proposal Layer负责综合所有[dx(A),dy(A),dw(A),dh(A)]变换量和foreground anchors,计算出精准的proposal,送入后续RoI Pooling Layer。还是先来看看Proposal Layer的caffe prototxt定义:
    [cpp] view plain copy
     
    1. layer {  
    2.   name: 'proposal'  
    3.   type: 'Python'  
    4.   bottom: 'rpn_cls_prob_reshape'  
    5.   bottom: 'rpn_bbox_pred'  
    6.   bottom: 'im_info'  
    7.   top: 'rois'  
    8.   python_param {  
    9.     module: 'rpn.proposal_layer'  
    10.     layer: 'ProposalLayer'  
    11.     param_str: "'feat_stride': 16"  
    12.   }  
    13. }  
    Proposal Layer有3个输入:fg/bg anchors分类器结果rpn_cls_prob_reshape,对应的bbox reg的[dx(A),dy(A),dw(A),dh(A)]变换量rpn_bbox_pred,以及im_info;另外还有参数feat_stride=16,这和图4是对应的。
    缩进首先解释im_info。对于一副任意大小PxQ图像,传入Faster RCNN前首先reshape到固定MxN,im_info=[M, N, scale_factor]则保存了此次缩放的所有信息。然后经过Conv Layers,经过4次pooling变为WxH=(M/16)x(N/16)大小,其中feature_stride=16则保存了该信息。所有这些数值都是为了将proposal映射回原图而设置的,如图12,毕竟检测就是为了在原图上画一个框而已~
    图12
    缩进Proposal Layer forward(caffe layer的前传函数)按照以下顺序依次处理:
    1. 再次生成anchors,并对所有的anchors做bbox reg位置回归(注意这里的anchors生成顺序和之前是即完全一致的)
    2. 按照输入的foreground softmax scores由大到小排序anchors,提取前pre_nms_topN(e.g. 6000)个anchors。即提取修正位置后的foreground anchors
    3. 利用feat_stride和im_info将anchors映射回原图,判断fg anchors是否大范围超过边界,剔除严重超出边界fg anchors。
    4. 进行nms(nonmaximum suppression,非极大值抑制)
    5. 再次按照nms后的foreground softmax scores由大到小排序fg anchors,提取前post_nms_topN(e.g. 300)结果作为proposal输出。
    之后输出proposal=[x1, y1, x2, y2],注意,由于在第三步中将anchors映射回原图判断是否超出边界,所以这里输出的proposal是对应MxN输入图像尺度的,这点在后续网络中有用。另外我认为,严格意义上的检测应该到此就结束了,后续部分应该属于识别了~
     
    RPN网络结构就介绍到这里,总结起来就是:
    生成anchors -> softmax分类器提取fg anchors -> bbox reg回归fg anchors -> Proposal Layer生成proposals
     

    3 RoI pooling

    缩进而RoI Pooling层则负责收集proposal,并计算出proposal feature maps,送入后续网络。从图3中可以看到Rol pooling层有2个输入:

    1. 原始的feature maps
    2. RPN输出的proposal boxes(大小各不相同)

    3.1 为何需要RoI Pooling

    缩进先来看一个问题:对于传统的CNN(如AlexNet,VGG),当网络训练好后输入的图像尺寸必须是固定值,同时网络输出也是固定大小的vector or matrix。如果输入图像大小不定,这个问题就变得比较麻烦。有2种解决办法:

    1. 从图像中crop一部分传入网络
    2. 将图像warp成需要的大小后传入网络

    图13 crop与warp破坏图像原有结构信息

    两种办法的示意图如图13,可以看到无论采取那种办法都不好,要么crop后破坏了图像的完整结构,要么warp破坏了图像原始形状信息。回忆RPN网络生成的proposals的方法:对foreground anchors进行bound box regression,那么这样获得的proposals也是大小形状各不相同,即也存在上述问题。所以Faster RCNN中提出了RoI Pooling解决这个问题(需要说明,RoI Pooling确实是从SPP发展而来,但是限于篇幅这里略去不讲,有兴趣的读者可以自行查阅相关论文)。

    3.2 RoI Pooling原理

    缩进分析之前先来看看RoI Pooling Layer的caffe prototxt的定义:

    [cpp] view plain copy
     
    1. layer {  
    2.   name: "roi_pool5"  
    3.   type: "ROIPooling"  
    4.   bottom: "conv5_3"  
    5.   bottom: "rois"  
    6.   top: "pool5"  
    7.   roi_pooling_param {  
    8.     pooled_w: 7  
    9.     pooled_h: 7  
    10.     spatial_scale: 0.0625 # 1/16  
    11.   }  
    12. }  

    其中有新参数pooled_w=pooled_h=7,另外一个参数spatial_scale=1/16应该能够猜出大概吧。

    缩进RoI Pooling layer forward过程:在之前有明确提到:proposal=[x1, y1, x2, y2]是对应MxN尺度的,所以首先使用spatial_scale参数将其映射回MxN大小的feature maps尺度(这里来回多次映射,是有点绕);之后将每个proposal水平和竖直都分为7份,对每一份都进行max pooling处理。这样处理后,即使大小不同的proposal,输出结果都是7x7大小,实现了fixed-length output。

     

    图14 proposal示意图

    4 Classification

    缩进Classification部分利用已经获得的proposal feature maps,通过full connect层与softmax计算每个proposal具体属于那个类别(如人,车,电视等),输出cls_prob概率向量;同时再次利用bounding box regression获得每个proposal的位置偏移量bbox_pred,用于回归更加精确的目标检测框。Classification部分网络结构如图15。
    图15 Classification部分网络结构图
     

    从PoI Pooling获取到7x7=49大小的proposal feature maps后,送入后续网络,可以看到做了如下2件事:

    1. 通过全连接和softmax对proposals进行分类,这实际上已经是识别的范畴了
    2. 再次对proposals进行bounding box regression,获取更高精度的rect box
    这里来看看全连接层InnerProduct layer,如图16,

    图16 全连接层示意图

    其计算公式如下:

    其中W和bias B都是预先训练好的,即大小是固定的,当然输入X和输出Y也就是固定大小。所以,这也就印证了之前Poi Pooling的必要性。到这里,我想其他内容已经很容易理解,不在赘述了。

     
     

    5 Faster RCNN训练

    缩进Faster CNN的训练,是在已经训练好的model(如VGG_CNN_M_1024,VGG,ZF)的基础上继续进行训练。实际中训练过程分为6个步骤:
    1. 在已经训练好的model上,训练RPN网络,对应stage1_rpn_train.pt
    2. 利用步骤1中训练好的RPN网络,收集proposals,对应rpn_test.pt
    3. 第一次训练Fast RCNN网络,对应stage1_fast_rcnn_train.pt
    4. 第二训练RPN网络,对应stage2_rpn_train.pt
    5. 再次利用步骤4中训练好的RPN网络,收集proposals,对应rpn_test.pt
    6. 第二次训练Fast RCNN网络,对应stage2_fast_rcnn_train.pt

    可以看到训练过程类似于一种“迭代”的过程,不过只循环了2次。至于只循环了2次的原因是应为作者提到:"A similar alternating training can be run for more iterations, but we have observed negligible improvements",即循环更多次没有提升了。接下来本章以上述6个步骤讲解训练过程。

    5.1 训练RPN网络

    缩进在该步骤中,首先读取RBG提供的预训练好的model(本文使用VGG),开始迭代训练。来看看stage1_rpn_train.pt网络结构,如图17。

    图17 stage1_rpn_train.pt

    (考虑图片大小,Conv Layers中所有的层都画在一起了,如红圈所示,后续图都如此处理)

    与检测网络类似的是,依然使用Conv Layers提取feature maps。整个网络使用的Loss如下:

    上述公式中,i表示anchors index,pi表示foreground softmax predict概率,pi*代表对应的GT predict概率(即当第i个anchor与GT间IoU>0.7,认为是该anchor是foreground,pi*=1;反之IoU<0.3时,认为是该anchor是background,pi*=0;至于那些0.3<IoU<0.7的anchor则不参与训练);t代表predict bounding box,t*代表对应foreground anchor对应的GT box。可以看到,整个Loss分为2部分:

    1. cls loss,即rpn_cls_loss层计算的softmax loss,用于分类anchors为forground与background的网络训练
    2. reg loss,即rpn_loss_bbox层计算的soomth L1 loss,用于bounding box regression网络训练。注意在该loss中乘了pi*,相当于只关心foreground anchors的回归(其实在回归中也完全没必要去关心background)。

    缩进由于在实际过程中,Ncls和Nreg差距过大,用参数λ平衡二者(如Ncls=256,Nreg=2400时设置λ=10),使总的网络Loss计算过程中能够均匀考虑2种Loss。这里比较重要是Lreg使用的soomth L1 loss,计算公式如下:

    缩进了解数学原理后,反过来看图17:

    1. 对于rpn_loss_cls,输入的rpn_cls_scors_reshape和rpn_labels分别对应p与p*,Ncls参数隐含在p与p*的blob的大小中
    2. 对于rpn_loss_bbox,输入的rpn_bbox_pred和rpn_bbox_targets分别对应t于t*,rpn_bbox_inside_weigths对应p*,rpn_bbox_outside_weights对应λ,Nreg同样隐含在blob大小中

    这样,公式与代码就完全对应了。

    5.2 通过训练好的RPN网络收集proposals

    缩进在该步骤中,利用之前的RPN网络,获取proposal rois,同时获取foreground softmax probability,如图18,然后将获取的信息保存在python pickle文件中。该网络本质上和检测中的RPN网络一样,没有什么区别。

    图18 rpn_test.pt

    5.3 训练Fast RCNN网络

    缩进读取之前保存的pickle文件,获取proposals与foreground probability。从data层输入网络。然后:

    1. 将提取的proposals作为rois传入网络,如图19蓝框
    2. 将foreground probability作为bbox_inside_weights传入网络,如图19绿框
    3. 通过caffe blob大小对比,计算出bbox_outside_weights(即λ),如图19绿框

    这样就可以训练最后的识别softmax与最终的bounding regression了,如图19。

    图19 stage1_fast_rcnn_train.pt

    之后的训练都是大同小异,不再赘述了。

    RPN网络:

      name: 'input-data' #这一层就是最开始数据输入
      type: 'Python'
      top: 'data' # top表示该层的输出,所以可以看到这一层输出三组数据,data,真值框gt_boxes,和相关信息im_info
      top: 'im_info' # 这些都是存储在矩阵中的
      top: 'gt_boxes'
      python_param {
        module: 'roi_data_layer.layer'
        layer: 'RoIDataLayer'
        param_str: "'num_classes': 21"
      }
    }
     
    #========= conv1-conv5 ============
     
    layer {
    	name: "conv1"
    	type: "Convolution"
    	bottom: "data" # 输入data
    	top: "conv1" # 输出conv1,这里conv1就代表了这一层输出数据的名称,存储在对应的矩阵中
    	param { lr_mult: 1.0 }
    	param { lr_mult: 2.0 }
    	convolution_param {
    		num_output: 96
    		kernel_size: 7
    		pad: 3  # 这里可以看到卷积1层 填充了3个像素
    		stride: 2
    	}
    }
    layer {
    	name: "relu1"
    	type: "ReLU"
    	bottom: "conv1"
    	top: "conv1"
    }
    layer {
    	name: "norm1"
    	type: "LRN"
    	bottom: "conv1"
    	top: "norm1" # 做归一化操作,通俗点说就是做个除法
    	lrn_param {
    		local_size: 3
    		alpha: 0.00005
    		beta: 0.75
    		norm_region: WITHIN_CHANNEL
        engine: CAFFE
    	}
    }
    layer {
    	name: "pool1"
    	type: "Pooling"
    	bottom: "norm1"
    	top: "pool1"
    	pooling_param {
    		kernel_size: 3
    		stride: 2
    		pad: 1 # 池化的时候,又做了填充
    		pool: MAX
    	}
    }
    layer {
    	name: "conv2"
    	type: "Convolution"
    	bottom: "pool1"
    	top: "conv2"
    	param { lr_mult: 1.0 }
    	param { lr_mult: 2.0 }
    	convolution_param {
    		num_output: 256
    		kernel_size: 5
    		pad: 2
    		stride: 2
    	}
    }
    layer {
    	name: "relu2"
    	type: "ReLU"
    	bottom: "conv2"
    	top: "conv2"
    }
    layer {
    	name: "norm2"
    	type: "LRN"
    	bottom: "conv2"
    	top: "norm2"
    	lrn_param {
    		local_size: 3
    		alpha: 0.00005
    		beta: 0.75
    		norm_region: WITHIN_CHANNEL
        engine: CAFFE
    	}
    }
    layer {
    	name: "pool2"
    	type: "Pooling"
    	bottom: "norm2"
    	top: "pool2"
    	pooling_param {
    		kernel_size: 3
    		stride: 2
    		pad: 1
    		pool: MAX
    	}
    }
    layer {
    	name: "conv3"
    	type: "Convolution"
    	bottom: "pool2"
    	top: "conv3"
    	param { lr_mult: 1.0 }
    	param { lr_mult: 2.0 }
    	convolution_param {
    		num_output: 384
    		kernel_size: 3
    		pad: 1
    		stride: 1
    	}
    }
    layer {
    	name: "relu3"
    	type: "ReLU"
    	bottom: "conv3"
    	top: "conv3"
    }
    layer {
    	name: "conv4"
    	type: "Convolution"
    	bottom: "conv3"
    	top: "conv4"
    	param { lr_mult: 1.0 }
    	param { lr_mult: 2.0 }
    	convolution_param {
    		num_output: 384
    		kernel_size: 3
    		pad: 1
    		stride: 1
    	}
    }
    layer {
    	name: "relu4"
    	type: "ReLU"
    	bottom: "conv4"
    	top: "conv4"
    }
    layer {
    	name: "conv5"
    	type: "Convolution"
    	bottom: "conv4"
    	top: "conv5"
    	param { lr_mult: 1.0 }
    	param { lr_mult: 2.0 }
    	convolution_param {
    		num_output: 256
    		kernel_size: 3
    		pad: 1
    		stride: 1
    	}
    }
    layer {
    	name: "relu5"
    	type: "ReLU"
    	bottom: "conv5"
    	top: "conv5"
    }
     
    #========= RPN ============
    # 到我们的RPN网络部分了,前面的都是共享的5层卷积层的部分
    layer {
      name: "rpn_conv1"
      type: "Convolution"
      bottom: "conv5"
      top: "rpn_conv1"
      param { lr_mult: 1.0 }
      param { lr_mult: 2.0 }
      convolution_param {
        num_output: 256
        kernel_size: 3 pad: 1 stride: 1 #这里作者把每个滑窗3*3,通过3*3*256*256的卷积核输出256维,完整的输出其实是12*12*256,
        weight_filler { type: "gaussian" std: 0.01 }
        bias_filler { type: "constant" value: 0 }
      }
    }
    layer {
      name: "rpn_relu1"
      type: "ReLU"
      bottom: "rpn_conv1"
      top: "rpn_conv1"
    }
    layer {
      name: "rpn_cls_score"
      type: "Convolution"
      bottom: "rpn_conv1"
      top: "rpn_cls_score"
      param { lr_mult: 1.0 }
      param { lr_mult: 2.0 }
      convolution_param {
        num_output: 18   # 2(bg/fg) * 9(anchors)
        kernel_size: 1 pad: 0 stride: 1 #这里看的很清楚,作者通过1*1*256*18的卷积核,将前面的256维数据转换成了18个输出
        weight_filler { type: "gaussian" std: 0.01 }
        bias_filler { type: "constant" value: 0 }
      }
    }
    layer {
      name: "rpn_bbox_pred"
      type: "Convolution"
      bottom: "rpn_conv1"
      top: "rpn_bbox_pred"
      param { lr_mult: 1.0 }
      param { lr_mult: 2.0 }
      convolution_param {
        num_output: 36   # 4 * 9(anchors)
        kernel_size: 1 pad: 0 stride: 1 <span style="font-family: Arial, Helvetica, sans-serif;">#这里看的很清楚,作者通过1*1*256*36的卷积核,将前面的256维数据转换成了36个输出</span>
        weight_filler { type: "gaussian" std: 0.01 }
        bias_filler { type: "constant" value: 0 }
      }
    }
    layer {
       bottom: "rpn_cls_score"
       top: "rpn_cls_score_reshape" # 我们之前说过,其实这一层是12*12*256的,所以后面我们要送给损失函数,需要将这个矩阵reshape一下,我们需要的是144个滑窗,每个对应的256的向量
       name: "rpn_cls_score_reshape"
       type: "Reshape"
       reshape_param { shape { dim: 0 dim: 2 dim: -1 dim: 0 } }
    }
    layer {
      name: 'rpn-data'
      type: 'Python'
      bottom: 'rpn_cls_score'
      bottom: 'gt_boxes'
      bottom: 'im_info'
      bottom: 'data'
      top: 'rpn_labels'
      top: 'rpn_bbox_targets'
      top: 'rpn_bbox_inside_weights'
      top: 'rpn_bbox_outside_weights'
      python_param {
        module: 'rpn.anchor_target_layer'
        layer: 'AnchorTargetLayer'
        param_str: "'feat_stride': 16"
      }
    }
    layer {
      name: "rpn_loss_cls"
      type: "SoftmaxWithLoss" # 很明显这里是计算softmax的损失,输入labels和cls layer的18个输出(中间reshape了一下),输出损失函数的具体值
      bottom: "rpn_cls_score_reshape"
      bottom: "rpn_labels"
      propagate_down: 1
      propagate_down: 0
      top: "rpn_cls_loss"
      loss_weight: 1
      loss_param {
        ignore_label: -1
        normalize: true
      }
    }
    layer {
      name: "rpn_loss_bbox"
      type: "SmoothL1Loss" # 这里计算的框回归损失函数具体的值
      bottom: "rpn_bbox_pred"
      bottom: "rpn_bbox_targets"
      bottom: "rpn_bbox_inside_weights"
      bottom: "rpn_bbox_outside_weights"
      top: "rpn_loss_bbox"
      loss_weight: 1
      smooth_l1_loss_param { sigma: 3.0 }
    }
     
    #========= RCNN ============
    # Dummy layers so that initial parameters are saved into the output net
     
    layer {
      name: "dummy_roi_pool_conv5"
      type: "DummyData"
      top: "dummy_roi_pool_conv5"
      dummy_data_param {
        shape { dim: 1 dim: 9216 }
        data_filler { type: "gaussian" std: 0.01 }
      }
    }
    layer {
      name: "fc6"
      type: "InnerProduct"
      bottom: "dummy_roi_pool_conv5"
      top: "fc6"
      param { lr_mult: 0 decay_mult: 0 }
      param { lr_mult: 0 decay_mult: 0 }
      inner_product_param {
        num_output: 4096
      }
    }
    layer {
      name: "relu6"
      type: "ReLU"
      bottom: "fc6"
      top: "fc6"
    }
    layer {
      name: "fc7"
      type: "InnerProduct"
      bottom: "fc6"
      top: "fc7"
      param { lr_mult: 0 decay_mult: 0 }
      param { lr_mult: 0 decay_mult: 0 }
      inner_product_param {
        num_output: 4096
      }
    }
    layer {
      name: "silence_fc7"
      type: "Silence"
      bottom: "fc7"
    

      

    对于每个3x3的窗口,作者就计算这个滑动窗口的中心点所对应的原始图片的中心点。然后作者假定,这个3x3窗口,是从原始图片上通过SPP池化得到的,而这个池化的区域的面积以及比例,就是一个个的anchor。换句话说,对于每个3x3窗口,作者假定它来自9种不同原始区域的池化,但是这些池化在原始图片中的中心点,都完全一样。这个中心点,就是刚才提到的,3x3窗口中心点所对应的原始图片中的中心点。如此一来,在每个窗口位置,我们都可以根据9个不同长宽比例、不同面积的anchor,逆向推导出它所对应的原始图片中的一个区域,这个区域的尺寸以及坐标,都是已知的。而这个区域,就是我们想要的 proposal。所以我们通过滑动窗口和anchor,成功得到了 51x39x9 个原始图片的proposal。接下来,每个proposal我们只输出6个参数:每个 proposal 和 ground truth 进行比较得到的前景概率和背景概率(2个参数)(对应图上的 cls_score);由于每个 proposal 和 ground truth 位置及尺寸上的差异,从 proposal 通过平移放缩得到 ground truth 需要的4个平移放缩参数(对应图上的 bbox_pred)。

    所以根据我们刚才的计算,我们一共得到了多少个anchor box呢?

    51 x 39 x 9 = 17900

    约等于 20 k

  • 相关阅读:
    AIMS 2013中的性能报告工具不能运行的解决办法
    读懂AIMS 2013中的性能分析报告
    在线研讨会网络视频讲座 方案设计利器Autodesk Infrastructure Modeler 2013
    Using New Profiling API to Analyze Performance of AIMS 2013
    Map 3D 2013 新功能和新API WebCast视频下载
    为Autodesk Infrastructure Map Server(AIMS) Mobile Viewer创建自定义控件
    ADN新开了云计算Cloud和移动计算Mobile相关技术的博客
    JavaScript修改css样式style
    文本编辑神器awk
    jquery 开发总结1
  • 原文地址:https://www.cnblogs.com/wuxiangli/p/7066707.html
Copyright © 2011-2022 走看看