Faster Rcnn详解及代码解读

 1.backbone含义

        backbone用于特征提取,通常使用的是VGG16或者ResNet网络,其中要经过4个pooling层,且经过多层卷积后层数也发生了变化,但仍要保证在进行下一次池化之前,特征图深度为上一次池化之前深度的两倍。故第一个pooling层的strides=4,第二个的strides=2,第三个的pooling层的strides=2,第四个的pooling层的的strides=2,所以得到的特征图的shape分别为:[1, 304, 304, 256]、[1, 152, 152, 512]、[1, 76, 76, 1024]、[1, 38, 38, 2048]。由图可知此时获取到的是C2、C3、C4、C5层是经过池化得到的。C1层未经过池化。

C2,C3,C4,C5 = model.backbone(image,training=False)
#此处的model直接调用backbone()函数,返回为上述的4个特征图

2.FPN层及特征金字塔

        经过backbone获取到了4张特征图,为了更好的检测图像,引入FPN概念,由图可知,[1, 38, 38, 2048]的特征图经过两倍放大的上采样后,与[1, 76, 76, 1024]经过1层的kernel_size=1的卷积核进行卷积。  

         由上图可知,经过FPN层(自上而下的上采样然后与同层相加)后,会获得M5、M4、M3、M2特征图。

P2,P3,P4,P5 = model.neck([C2,C3,C4,C5],training=False)

        此时获得到的P2、P3、P4、P5,P6的特征图,是M2、M3、M4、M5特征图经一个3*3的卷积核得到的,且P6特征图直接由P5特征图进行下采样得到。5张特征图的shape为:[1, 304, 304, 256]、[1, 152, 152, 512]、[1, 76, 76, 1024]、[1, 38, 38, 2048]、[1, 19, 19, 256]。获得特征融合后的5张特征图

3.RPN层生成候选区域及流程详解

RPN层的主要流程:

1、生成一系列的固定参考框anchors,覆盖图像的任意位置,然后送入后续网络中进行分类和回归

2、分类分支:通过softmax分类判断anchor中是否包含目标

3、回归分支:计算目标框对于anchors的偏移量,以获得精确的候选区域

4、最后的Proposal层则负责综合含有目标的anchors和对应bbox回归偏移量获取候选区域,同时剔除太小和超出边界的候选区域。

详细流程

        (1)anchors,多尺度、多长宽比,例如:尺度为32、64、128,长宽比为:1:1,1:2,2:1的一组anchors。一般有RPN的情况下,每个特征图上生成一个尺度,三个长宽比的anchors即3个anchors。没有RPN的情况下则生成如下图的9个anchors

        故,因为使用了FPN,所以每个像素点生成3个anchors,对应于上述经FPN生成的5张特征图上生成anchors,anchors的数量为:3043043+1521523+76763+38383+19193=369303,可通过以下代码获得,其中所传参数为imagemeta是图像的元信息。此处根据generate_pyramid_anchors()函数可知,需要传递图像的元信息,通过5张特征图获取到了所有的anchors。返回的anchors为所有的anchor在原图的坐标,shape为[369303, 4]。

# 产生anchor:输入图像元信息即可,输出anchor对应于原图的坐标值
anchors,valid_flags = model.rpn_head.generator.generate_pyramid_anchors(imagemeta)

可以通过visualize模块进行图像绘制,绘制在原图上的所有anchors

visualize.draw_boxes(rgd_image[0],boxes=anchors[:10000,:4])
plt.show()

 

        (2)在5张特征图上分别都声称了anchors后,然后每张特征图再经先做一个1x1的卷积,得到[batchsize,H,W,18]的特征图,然后进行变形,将特征图转换为[batchsize,9xH,W,2]的特征图后,送入softmax中进行分类,得到分类结果(判断)后,再进行reshape最终得到[batchsize,H,W,18]大小的结果,18表示k=9个anchor是否包含目标的概率值。

        举例子:P6特征图输出后的shape是[1, 19, 19, 256],此时经过下图的1*1的卷积核后,shape变为[1,19,19,18],此时经过Reshape模块,特征图的shape变为[1,9X19,9X19,2],此时可以理解为特征图的H变为了9倍,即特征图像素变为了原来的9倍。每个像素点都对应了一个anchor。之所以第四维是2,是因为经过softmax后,判断是否存在物体,给出对应的概率。然后在经过Reshape模块,特征图又变为[1,19,19,18]。此时,特征图上9X19X19个anchors均经过softmax后给出了是否存在物体的概率,例如:存在0.6,不存在:0.4,对应的anchors的坐标值都已记录下来,后映射到真实的图像上。所以此时真实图像上的anchors中是否含有物体已经判断出来了。

 

        (3)由综合过程图可知,经过FPN后的模型,返回的5张不同尺寸的特征值,又经过下图中的1*1卷积,使得特征图的深度变为36,即为4x9的深度,其中9代表的是每个像素点有9个anchors,4代表的是经过回归后的尺寸变化,即[dx(A),dy(A),dw(A),dh(A)],其中d表示变化率。

 

        该数值进行结合,求出预测的是anchor与真实值之间的平移因子和尺度因子。其中[dx(A),dy(A),dw(A),dh(A)]分别等于下图的tx、ty、tw、th,其中xa、ya、wa、ha表示anchor框的中心点x、y、w、h的值。  

        可以通过以下代码进行获取:其中model.rpn_head()出入的是特征图金字塔,返回:rpn_class_logits.shape=[1, 369303, 2]、rpn_probs.shape=[1, 369303, 2]、rpn_deltas.shape=[1, 369303, 4]  

# RPN网络的输入:FPN网络获取的特征图
rpn_feature_maps = [P2,P3,P4,P5,P6]
# RPN网络预测,返回:logits送入softmax之前的分数,包含目标的概率,对框的修正结果
rpn_class_logits,rpn_probs,rpn_deltas = model.rpn_head(rpn_feature_maps,training = False)

         其中rpn_class_logits表示每个anchor进行分类处理后的分类之后结果,即样本标签。rpn_probs为经过softmax后输出的概率,同时也反映了anchor中存在检测物体的置信度,其中第一列为存在物体的置信度,第二列为不存在物体的置信度,rpn_deltas返回的是上述的[dx(A),dy(A),dw(A),dh(A)]回归后的结果

  

        经过回归函数,此时能够获得每个anchor的置信度,我们可以通过代码,将置信度高的anchor绘制在图像上。

# 获取分类结果中包含目标的概率值
rpn_probs_tmp = rpn_probs[0,:,1]
# 获取前100个较高的anchor
limit = 100
ix = tf.nn.top_k(rpn_probs_tmp,k=limit).indices[::-1]
# 获取对应的anchor绘制图像上,那这些anchor就有很大概率生成候选区域
visualize.draw_boxes(rgd_image[0],tf.gather(anchors,ix).numpy())

      

         (4)Proposal层,经过了RPN的分类和回归,我们获得了如下的信息:所有的anchors是否存在物体的置信度,及[dx(A),dy(A),dw(A),dh(A)]的平移因子和尺度因子。通过model.rpn_head()函数获得了上述的两个结果。然后图像及特征图要经过Proposal层,进行anchor的修正获得最终的候选框。

Proposal层的处理流程如下:model.rpn_head.get_proposals(rpn_probs,rpn_deltas,imagemeta)

  1. 利用RPN网络回归的结果对所有的anchors进行修正,得到修正后的检测框

  2. 根据RPN网络分类的softmax输出的概率值由大到小对检测框进行排序,提取前6000个结果,即提取修正位置后的检测框

  3. 限定超出图像边界的检测框为图像边界,防止后续roi pooling时候选区域超出图像边界。

  4. 对剩余的检测框进行非极大值抑制NMS,即将6000个框进行极大值抑制。由下面的代码可知此时的框的个数为1533个。
  5. Proposal层的输出是对应输入网络图像尺度归一化后的坐标值[x1, y1, x2, y2]。到此RPN网络的工作就结束。

代码表示:

# 获取候选区域
proposals_list = model.rpn_head.get_proposals(rpn_probs,rpn_deltas,imagemeta)
#结果
proposals_list
[<tf.Tensor: shape=(1533, 4), dtype=float32, numpy=
 array([[0.20729761, 0.00852748, 0.748096  , 0.46975034],
        [0.42213044, 0.5887971 , 0.7810232 , 0.9806169 ],
        [0.40125194, 0.4384725 , 0.48458642, 0.47913405],
        ...,
        [0.25977597, 0.435113  , 0.27290097, 0.4483906 ],
        [0.38884488, 0.41798416, 0.41393432, 0.4339822 ],
        [0.5885266 , 0.65331775, 0.62330776, 0.6913476 ]], dtype=float32)>]

        返回的proposals_list就是经过回归处理后的候选框坐标。但是此时的坐标是经过了归一化处理了 所以绘制图像的时候 要乘以像素值1216。

visualize.draw_boxes(rgd_image[0],boxes=proposals_list[0].numpy()[:,:4]*1216)
plt.show()

4.ROIPooling

        RoI Pooling层则负责收集RPN网络生成的候选区域,并将其映射到特征图中并固定维度,送入后续网络中进行分类和回归。

        RoI Pooling 的作用过程,如下图所示:  

        Proposal层给出了候选框,此时的候选框中存在物体,且具有1533个,且类似于抠图的操作,相当于在原图上接触1533个图片。图片的H和W各不相同。ROIPooling层的作用就是将这些不同尺寸的图片,转化为统一尺寸的pool_H和pool_W。此处的尺寸改变是通过池化的方式改变的,如下图所示,所有的候选框都转变为7*7(该参数是超参数,可以改变)的格式,且每个小格内部取最大值。  

        此时要思考一个问题,FPN层给出了多种尺寸的特征图,Proposal层得到了多种尺寸的候选框,请问不同尺寸的候选框分别映射到了哪个特征图上了呢?

        在这里,不同尺度的ROI使用不同特征层作为ROI pooling层的输入,大尺度ROI就用后面一些的金字塔层,比如P5;小尺度ROI就用前面一点的特征层,比如P3,我们使用下面的公式确定ROI所在的特征层:

        其中,224是ImageNet的标准输入,k0是基准值,设置为4,w和h是ROI区域的长和宽,假设ROI是112x112的大小,那么k = k0-1 = 4-1 = 3,意味着该ROI应该使用P3的特征层。k值会做取整处理,防止结果不是整数,而且为了保证k值在2-5之间,还会做截断处理。由此可知根据ROI候选区域的长和宽确定映射到的特征图。  

# ROI Pooling层实现:输入是候选区域,特征图,图像的元信息
pool_region_list = model.roi_align((proposals_list,rcnn_feature_maps,imagemeta),training = False)
#输出结果为:每一个候选区域都被固定为7x7大小
[<tf.Tensor: shape=(1533, 7, 7, 256), dtype=float32, numpy=
 array([[[[-6.26428795e+00,  3.55317879e+00,  3.37260556e+00, ...,
            6.22574663e+00,  3.75851846e+00, -2.49103808e+00],
          [-9.01443863e+00,  7.67611027e-01,  7.18744850e+00, ...,
            6.20492172e+00,  4.09835625e+00,  6.05924249e-01],
          [-7.43907213e+00, -3.76329374e+00,  5.01457691e+00, ...,
            6.22656918e+00,  1.19414163e+00,  3.06410480e+00],
          ...,
          [ 1.39127302e+00, -1.71078873e+00,  4.01916075e+00, ...,
            5.94641972e+00,  3.63194764e-01,  2.91014194e+00],
          [-5.21681070e+00,  2.39917469e+00,  2.49682212e+00, ...,
            5.92232943e+00,  3.01222801e+00,  1.63518691e+00],
          [-1.26697767e+00, -6.90211892e-01,  4.50919747e-01, ...,
            1.97156405e+00, -1.07467103e+00,  4.54943466e+00]]

5.目标分类和回归

        经过了ROIPooling层后,获得了统一H*W的特征图,此时经过后续的分类得到每个特征图都对应于哪个类别,该部分利用获得的候选区域的特征图,通过全连接层与softmax计算每个候选区域具体属于的类别(如人,车,电视等),输出概率值;同时再次利用回归方法获得每个候选区域的位置偏移量,用于回归更加精确的目标检测框。该部分网络结构如下所示:

从RoI Pooling层获取到固定大小的特征图后,送入后续网络,可以看到做了如下2件事:

  1. 通过全连接和softmax对候选区域进行分类

  2. 再次对候选区域进行回归修正,获取更高精度的检测框

实现流程如下:

首先获取网络分类和回归的结果:

# RCNN网络的预测:输入是ROIPooling层的特征,输出:类别的score,类别的概率值,回归结果
rcnn_class_logits,rcnn_class_probs,rcnn_deltas_list=model.bbox_head(pool_region_list,training=False)

 利用结果对候选区域进行修正:

# 获取预测结果:输入:rcnn返回的分类和回归结果,候选区域,图像元信息,输出:目标检测结果detection_list = model.bbox_head.get_bboxes(rcnn_class_probs,rcnn_deltas_list,proposals_list,imagemeta)

         结果为:一共检测出17个目标,前四个数据为每个目标的坐标位置,第五个数据为目标类别id,第六个数据为目标类别置信度。6个值构成。此处对生成的检测框做了NMS

[<tf.Tensor: shape=(17, 6), dtype=float32, numpy=
 array([[2.3262584e+02, 2.1799168e+01, 9.0194098e+02, 5.4503723e+02,
         1.0000000e+00, 9.9917287e-01],
        [1.4013255e+02, 5.5109363e+02, 3.8764392e+02, 7.5518970e+02,
         1.0000000e+00, 9.9226898e-01],
        [2.0952664e+02, 7.8792090e+02, 8.9771838e+02, 1.2104146e+03,
         1.0000000e+00, 9.9193186e-01],
        [2.0348978e+02, 4.1579453e+02, 3.3001547e+02, 5.3761450e+02,
         1.0000000e+00, 9.8929125e-01],
        [1.8087936e+02, 7.9734338e+02, 5.1281873e+02, 1.0274907e+03,
         1.0000000e+00, 9.8689401e-01],
        [1.7813437e+02, 2.3680782e+00, 5.0309012e+02, 1.1671781e+02,
         1.0000000e+00, 9.8671734e-01],
        [1.5557167e+02, 6.2398212e+02, 4.6821997e+02, 8.8862134e+02,
         1.0000000e+00, 9.8594207e-01],
        [1.6307811e+02, 2.1531593e+02, 3.3396735e+02, 3.1797446e+02,
         1.0000000e+00, 9.7716457e-01],
        [5.5404950e+02, 7.0997412e+02, 9.0215717e+02, 1.0564817e+03,
         1.0000000e+00, 9.7271395e-01],
        [3.5928052e+02, 5.3055298e+02, 4.3132263e+02, 6.3369983e+02,
         4.6000000e+01, 9.7136974e-01],
        [2.0050583e+02, 9.7621101e+01, 3.2383597e+02, 2.6199030e+02,
         1.0000000e+00, 9.6375221e-01],
        [2.9822769e+02, 5.8259045e+02, 3.4338364e+02, 6.6165851e+02,
         4.6000000e+01, 9.5854193e-01],
        [3.7460797e+02, 2.8190384e+02, 9.0596057e+02, 1.0374227e+03,
         6.1000000e+01, 9.2184818e-01],
        [5.3237848e+02, 8.8739655e+02, 6.0120386e+02, 1.0191014e+03,
         4.6000000e+01, 8.9205891e-01],
        [6.0350385e+02, 9.9131537e+02, 9.0866974e+02, 1.1663280e+03,
         5.7000000e+01, 8.5597926e-01],
        [3.3973947e+02, 6.0475940e+02, 3.7579034e+02, 6.4243842e+02,
         4.5000000e+01, 8.1343234e-01],
        [5.1774200e+02, 4.7480432e+02, 5.7942987e+02, 5.0882794e+02,
         4.0000000e+01, 7.8660023e-01]], dtype=float32)>]

可以将其绘制在图像上:

# 绘制在图像上
visualize.draw_boxes(rgd_image[0],boxes=detection_list[0][:,:4])
plt.show()

 

  • 7
    点赞
  • 43
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Faster RCNN是一种基于深度学习目标检测算法,它是RCNN、Fast RCNN的改进版,具有更快的检测速度和更高的准确率。本文将详细介绍Faster RCNN的PyTorch实现。 Faster RCNN的实现主要分为两个部分:特征提取和区域提取。特征提取使用预训练的卷积神经网络(如VGG16、ResNet等)对输入图像进行特征提取,得到一系列特征图。区域提取使用RPN(Region Proposal Network)对特征图进行处理,得到一系列候选区域,然后对每个候选区域进行分类和回归,得到最终的目标检测结果。 在PyTorch中实现Faster RCNN,可以使用torchvision中的models和transforms模块,以及torch.utils.data中的DataLoader和Dataset模块。具体实现步骤如下: 1. 加载数据集 使用torchvision中的transforms模块对数据进行预处理,然后使用Dataset模块加载数据集,最后使用DataLoader模块对数据进行批量处理。 2. 加载预训练模型 使用torchvision中的models模块加载预训练模型(如VGG16、ResNet等),然后修改模型最后一层的输出,使其适应目标检测任务。 3. 定义RPN 定义RPN网络,包括卷积层、分类层和回归层,使用预训练模型的特征图作为输入,输出候选区域。 4. 定义ROI Pooling层 定义ROI Pooling层,将候选区域映射到固定大小的特征图上,以便进行分类和回归。 5. 定义分类和回归网络 定义分类和回归网络,包括卷积层、全连接层和softmax层,使用ROI Pooling层的输出作为输入,输出目标检测结果。 6. 训练模型 使用反向传播算法和优化器对模型进行训练,调整模型参数,使其适应目标检测任务。 7. 测试模型 使用测试数据集对模型进行测试,计算模型的准确率和召回率,评估模型性能。 以上就是Faster RCNN的PyTorch实现步骤,具体实现细节可以参考PyTorch官方文档和相关论文。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值