『计算机视觉』经典RCNN_其二:Faster-RCNN

时间:2023-01-26 13:47:13

项目源码

一、Faster-RCNN简介

『cs231n』Faster_RCNN

『计算机视觉』Faster-RCNN学习_其一:目标检测及RCNN谱系

一篇讲的非常明白的文章:一文读懂Faster RCNN

『计算机视觉』经典RCNN_其二:Faster-RCNN

(1)输入测试图像;

(2)将整张图片输入CNN,进行特征提取;

(3)用RPN生成建议窗口(proposals),每张图片保留约300个建议窗口;

(4)把建议窗口映射到CNN的最后一层卷积feature map上;

(5)通过RoI pooling层使每个RoI生成固定尺寸的feature map;

(6)利用Softmax Loss(探测分类概率) 和Smooth L1 Loss(探测边框回归)对分类概率和边框回归(Bounding box regression)联合训练.

相比FAST-RCNN,主要两处不同

(1)使用RPN(Region Proposal Network)代替原来的Selective Search方法产生建议窗口;

(2)产生建议窗口的CNN和目标检测的CNN共享

改进

快速产生建议框:FASTER-RCNN创造性地采用卷积网络自行产生建议框,并且和目标检测网络共享卷积网络,使得建议框数目从原有的约2000个减少为300个,且建议框的质量也有本质的提高.

RPN简介

放到整体网络中如下,

『计算机视觉』经典RCNN_其二:Faster-RCNN

对于共享的Feature Map,RPN使用3*3的滑窗,每个滑动窗口位置生成9个候选窗口(不同尺度、不同宽高),对应36个坐标、18个分类。

训练过程中,

1)丢弃跨越边界的anchor;

2)与样本重叠区域大于0.7的anchor标记为前景,重叠区域小于0.3的标定为背景;

总结一下:

  • 在feature map上滑动窗口
  • 建一个神经网络用于物体分类+框位置的回归
  • 滑动窗口的位置提供了物体的大体位置信息
  • 框的回归提供了框更精确的位置

这里的分类只需要区分候选框内特征为前景或者背景,这里的边框回归也是为了之后获得更精确的目标位置。

『计算机视觉』经典RCNN_其二:Faster-RCNN

损失函数

故整个网络包含四个损失函数;
  • RPN calssification(anchor good.bad),判断anchor前景背景类别
  • RPN regression(anchor->propoasal),计算anchor和gt box的偏差,利用mask仅计算前景anchor
  • Fast R-CNN classification(over classes),判断proposal分类,包含类别数C+背景
  • Fast R-CNN regression(proposal ->box),计算proposal和gt box的偏差,利用mask仅计算类别的proposal

注意到前两个损失函数目标是修正anchor,后两个损失函数目标是修正proposal,实际上产生了众多anchors后,会进行筛选(非极大值抑制并按照前景得分排序等等),选出特定比例的前景背景anchors作为proposal进行后面的运算。

『计算机视觉』经典RCNN_其二:Faster-RCNN

二、代码解读

『计算机视觉』经典RCNN_其二:Faster-RCNN

Faster-RCNN网络设计很是复杂,个人觉得但看论文或者其他材料并不能很好的理解这套流程,本篇我们从实际的代码出发,看看到底是这套网络系统到底是如何设计的。

anchor和proposal

region proposal(或者简称proposal,或者简称ROI),可以说RPN网络的目的就是为了得到proposal,这些proposal是对ground truth更好的刻画(和anchor相比,坐标更贴近ground truth,毕竟anchor的坐标都是批量地按照scale和aspect ratio复制的)。如果你还记得在系列二中关于网络结构的介绍,那么你就应该了解到RPN网络的回归支路输出的值(offset)作为smooth l1损失函数的输入之一时,其含义就是使得proposal和anchor之间的offset(RPN网络的回归支路输出)尽可能与ground truth和anchor之间的offset(RPN网络的回归支路的回归目标)接近。

调包部分

涉及了mx基础框架和一个作者自己创建的operate,

import mxnet as mx from symnet import proposal_target

特征提取器一

如开篇的图,这里是最上面一行的网络,即提取Feature Map的部分,使用了4个pooling层,意味着原始图像:Feature Map = 16:1,

『计算机视觉』经典RCNN_其二:Faster-RCNN

def get_vgg_feature(data):
# group 1
conv1_1 = mx.symbol.Convolution(
data=data, kernel=(3, 3), pad=(1, 1), num_filter=64, workspace=2048, name="conv1_1")
relu1_1 = mx.symbol.Activation(data=conv1_1, act_type="relu", name="relu1_1")
conv1_2 = mx.symbol.Convolution(
data=relu1_1, kernel=(3, 3), pad=(1, 1), num_filter=64, workspace=2048, name="conv1_2")
relu1_2 = mx.symbol.Activation(data=conv1_2, act_type="relu", name="relu1_2")
pool1 = mx.symbol.Pooling(
data=relu1_2, pool_type="max", kernel=(2, 2), stride=(2, 2), name="pool1")
# group 2
conv2_1 = mx.symbol.Convolution(
data=pool1, kernel=(3, 3), pad=(1, 1), num_filter=128, workspace=2048, name="conv2_1")
relu2_1 = mx.symbol.Activation(data=conv2_1, act_type="relu", name="relu2_1")
conv2_2 = mx.symbol.Convolution(
data=relu2_1, kernel=(3, 3), pad=(1, 1), num_filter=128, workspace=2048, name="conv2_2")
relu2_2 = mx.symbol.Activation(data=conv2_2, act_type="relu", name="relu2_2")
pool2 = mx.symbol.Pooling(
data=relu2_2, pool_type="max", kernel=(2, 2), stride=(2, 2), name="pool2")
# group 3
conv3_1 = mx.symbol.Convolution(
data=pool2, kernel=(3, 3), pad=(1, 1), num_filter=256, workspace=2048, name="conv3_1")
relu3_1 = mx.symbol.Activation(data=conv3_1, act_type="relu", name="relu3_1")
conv3_2 = mx.symbol.Convolution(
data=relu3_1, kernel=(3, 3), pad=(1, 1), num_filter=256, workspace=2048, name="conv3_2")
relu3_2 = mx.symbol.Activation(data=conv3_2, act_type="relu", name="relu3_2")
conv3_3 = mx.symbol.Convolution(
data=relu3_2, kernel=(3, 3), pad=(1, 1), num_filter=256, workspace=2048, name="conv3_3")
relu3_3 = mx.symbol.Activation(data=conv3_3, act_type="relu", name="relu3_3")
pool3 = mx.symbol.Pooling(
data=relu3_3, pool_type="max", kernel=(2, 2), stride=(2, 2), name="pool3")
# group 4
conv4_1 = mx.symbol.Convolution(
data=pool3, kernel=(3, 3), pad=(1, 1), num_filter=512, workspace=2048, name="conv4_1")
relu4_1 = mx.symbol.Activation(data=conv4_1, act_type="relu", name="relu4_1")
conv4_2 = mx.symbol.Convolution(
data=relu4_1, kernel=(3, 3), pad=(1, 1), num_filter=512, workspace=2048, name="conv4_2")
relu4_2 = mx.symbol.Activation(data=conv4_2, act_type="relu", name="relu4_2")
conv4_3 = mx.symbol.Convolution(
data=relu4_2, kernel=(3, 3), pad=(1, 1), num_filter=512, workspace=2048, name="conv4_3")
relu4_3 = mx.symbol.Activation(data=conv4_3, act_type="relu", name="relu4_3")
pool4 = mx.symbol.Pooling(
data=relu4_3, pool_type="max", kernel=(2, 2), stride=(2, 2), name="pool4")
# group 5
conv5_1 = mx.symbol.Convolution(
data=pool4, kernel=(3, 3), pad=(1, 1), num_filter=512, workspace=2048, name="conv5_1")
relu5_1 = mx.symbol.Activation(data=conv5_1, act_type="relu", name="relu5_1")
conv5_2 = mx.symbol.Convolution(
data=relu5_1, kernel=(3, 3), pad=(1, 1), num_filter=512, workspace=2048, name="conv5_2")
relu5_2 = mx.symbol.Activation(data=conv5_2, act_type="relu", name="relu5_2")
conv5_3 = mx.symbol.Convolution(
data=relu5_2, kernel=(3, 3), pad=(1, 1), num_filter=512, workspace=2048, name="conv5_3")
relu5_3 = mx.symbol.Activation(data=conv5_3, act_type="relu", name="relu5_3") return relu5_3

特征提取器二

下面是最后的一小部分网络,我们将筛选出来的proposal作用于Feature Map,得到候选区域,然后使用ROIPooling得到大小一致的候选区域,这些区域送入本部分网络,得到用于分类、回归的特征,

『计算机视觉』经典RCNN_其二:Faster-RCNN

def get_vgg_top_feature(data):
# group 6
flatten = mx.symbol.Flatten(data=data, name="flatten")
fc6 = mx.symbol.FullyConnected(data=flatten, num_hidden=4096, name="fc6")
relu6 = mx.symbol.Activation(data=fc6, act_type="relu", name="relu6")
drop6 = mx.symbol.Dropout(data=relu6, p=0.5, name="drop6")
# group 7
fc7 = mx.symbol.FullyConnected(data=drop6, num_hidden=4096, name="fc7")
relu7 = mx.symbol.Activation(data=fc7, act_type="relu", name="relu7")
drop7 = mx.symbol.Dropout(data=relu7, p=0.5, name="drop7")
return drop7

主体函数

函数接口

def get_vgg_train(anchor_scales, anchor_ratios, rpn_feature_stride,
rpn_pre_topk, rpn_post_topk, rpn_nms_thresh, rpn_min_size, rpn_batch_rois,
num_classes, rcnn_feature_stride, rcnn_pooled_size, rcnn_batch_size,
rcnn_batch_rois, rcnn_fg_fraction, rcnn_fg_overlap, rcnn_bbox_stds):

首先定义了一些用于接收数据&标签信息的占位符变量,

    num_anchors = len(anchor_scales) * len(anchor_ratios)

    data = mx.symbol.Variable(name="data")                     # 图片信息:[batch, channel, height, width]
im_info = mx.symbol.Variable(name="im_info")
gt_boxes = mx.symbol.Variable(name="gt_boxes") # 真实框信息:[obj数量, 5]
# anchor标签:-1、0、1 (无效、背景、目标)
rpn_label = mx.symbol.Variable(name='label') # [batch, 2, 中心点行数*每个位置anchors数目, 中心点列数]
# 根据初始anchor和ground truth计算出来的offset
rpn_bbox_target = mx.symbol.Variable(name='bbox_target') # [batch, 4*每个位置anchors数目, 中心点行数, 中心点列数]
# mask,如果anchor标签是1,则mask对应值为1,anchor标签是0或-1,则mask对应值为0
rpn_bbox_weight = mx.symbol.Variable(name='bbox_weight') # [batch, 4*每个位置anchors数目, 中心点行数, 中心点列数]

获取卷积特征

『计算机视觉』经典RCNN_其二:Faster-RCNN

   # shared convolutional layers
conv_feat = get_vgg_feature(data)

使用3×3的滑窗,进行卷积,

『计算机视觉』经典RCNN_其二:Faster-RCNN

  # RPN layers
rpn_conv = mx.symbol.Convolution(
data=conv_feat, kernel=(3, 3), pad=(1, 1), num_filter=512, name="rpn_conv_3x3")
rpn_relu = mx.symbol.Activation(data=rpn_conv, act_type="relu", name="rpn_relu")

每个滑动窗口位置生成9个候选窗口(不同尺度、不同宽高),对应36个坐标、18个分类,(即根据每张图片的feat map大小,生成对应数量的中心点,以及候选框体)

RPN calssification(anchor good.bad)

下面是计算全部候选窗口对应2分类的部分,生成损失函数的第一部分:全部候选窗含/不含obj的二分类损失

『计算机视觉』经典RCNN_其二:Faster-RCNN

    # rpn classification: obj / not_obj
# [batch, 2*每个位置anchors数目, 中心点行数, 中心点列数]
rpn_cls_score = mx.symbol.Convolution(
data=rpn_relu, kernel=(1, 1), pad=(0, 0), num_filter=2 * num_anchors, name="rpn_cls_score") # [batch, 2, 中心点行数*每个位置anchors数目, 中心点列数]
rpn_cls_score_reshape = mx.symbol.Reshape(
data=rpn_cls_score, shape=(0, 2, -1, 0), name="rpn_cls_score_reshape")
# 获取交叉熵回传梯度,对于出现了-1的图片梯度直接全部置为0
# 在Faster RCNN算法中,anchor一共有3种标签:-1、0、1,分别表示无效、背景、目标
rpn_cls_prob = mx.symbol.SoftmaxOutput(data=rpn_cls_score_reshape, label=rpn_label, multi_output=True,
normalization='valid', use_ignore=True, ignore_label=-1, name="rpn_cls_prob") # 切换为含/不含obj两通道,对每一个anchor是否有obj进行softmax处理
# [batch, 2, 中心点行数*每个位置anchors数目, 中心点列数]
rpn_cls_act = mx.symbol.softmax(
data=rpn_cls_score_reshape, axis=1, name="rpn_cls_act")
# [batch, 2*每个位置anchors数目, 中心点行数, 中心点列数]
# Reshpe方法不同于reshape方法,详情见此方法文档
rpn_cls_act_reshape = mx.symbol.Reshape(
data=rpn_cls_act, shape=(0, 2 * num_anchors, -1, 0), name='rpn_cls_act_reshape')

RPN regression(anchor->propoasal)

下面计算全部候选窗口对应4个坐标值的部分,生成损失函数第二部分:全部候选框坐标回归

『计算机视觉』经典RCNN_其二:Faster-RCNN

    # rpn bbox regression
# [batch, 4*每个位置anchors数目, 中心点行数, 中心点列数]
rpn_bbox_pred = mx.symbol.Convolution(
data=rpn_relu, kernel=(1, 1), pad=(0, 0), num_filter=4 * num_anchors, name="rpn_bbox_pred")
# rpn_bbox_weight: anchor的mask,如果某个anchor的标签是1,则mask对应值为1,anchor的标签是0或-1,则mask对应值为0
# rpn_bbox_target: 根据初始anchor和ground truth计算出来的offset
rpn_bbox_loss_ = rpn_bbox_weight * mx.symbol.smooth_l1(name='rpn_bbox_loss_',
scalar=3.0,
data=(rpn_bbox_pred - rpn_bbox_target))
# 获取回归梯度
# grad_scale: 表示回归损失占RPN网络总损失比,该参数相差几个量级对结果影响也不大
rpn_bbox_loss = mx.sym.MakeLoss(name='rpn_bbox_loss', data=rpn_bbox_loss_, grad_scale=1.0 / rpn_batch_rois)

候选框生成

我们会获取数量繁多的候选框(即上面得到的候选框含有obj的得分候选框坐标修正值),首先会根据框体含有obj的概率进行一次初筛,然后经由非极大值抑制算法筛选2000个候选框进入下一步的操作;在第二步中,我们会获取最终的128个候选框、它们各自对应的标签、它们坐标回归的目标、以及标定它们正负的坐标掩码,用于精确的训练候选框,生成目标边框。这个一步的操作使用了作者新建的操作节点,具体实现见源码,这里只简单介绍该操作的输入输出以及作用。

『计算机视觉』经典RCNN_其二:Faster-RCNN

另注,函数返回的候选框5个属性与后面的ROIPooling一脉相承,[候选框对应batch中图片的索引,候选框坐标×4],后面使用这个值可以直接进行ROIPooling。

    # rpn proposal
# 获取指定数目的候选框proposal
# [2000个候选框, 5个属性]
# 5个属性: batch中图片index,4个坐标
rois = mx.symbol.contrib.MultiProposal(
cls_prob=rpn_cls_act_reshape, # cls_prob: [batch, 2*每个位置anchors数目, 中心点行数, 中心点列数]
bbox_pred=rpn_bbox_pred, # bbox_pred: [batch, 4*每个位置anchors数目, 中心点行数, 中心点列数]
im_info=im_info, # mx.symbol.Variable(name="im_info")
feature_stride=rpn_feature_stride, # 16
scales=anchor_scales, ratios=anchor_ratios, # (0.5, 1, 2)
rpn_pre_nms_top_n=rpn_pre_topk, # 12000,对RPN网络输出的anchor进行NMS操作之前的proposal最大数量
# 输入proposal的数量大于12000时,对这些proposal的预测为foreground的概率(也叫score,
# 换句话说就是预测标签为1的概率)从高到低排序,然后选择前面12000个
rpn_post_nms_top_n=rpn_post_topk, # 2000,经过NMS过滤之后得到的proposal数量
threshold=rpn_nms_thresh, # 0.7,是NMS算法阈值
rpn_min_size=rpn_min_size, # 16
name = 'rois'
) # rcnn roi proposal target
# 根据上一步获取的proposal(即rois)和真实框(gt_boxes)进行筛选
# 获取128个proposal,对应的128个label,对应的128个真实坐标,128个坐标掩码(构建损失函数使用)
group = mx.symbol.Custom(rois=rois, # 2000*5的roi信息
gt_boxes=gt_boxes, # n*5的ground truth信息,n表示object数量
op_type='proposal_target',
num_classes=num_classes, # num_classes是实际要分类的类别数加上背景类
batch_images=rcnn_batch_size, # 1
batch_rois=rcnn_batch_rois, # 128
fg_fraction=rcnn_fg_fraction, # 0.25,正样本所占的比例
fg_overlap=rcnn_fg_overlap, # 0.5
box_stds=rcnn_bbox_stds # (0.1, 0.1, 0.2, 0.2)
) rois = group[0] # rois (128, 5)
label = group[1] # roi对应的标签(128)
bbox_target = group[2] # 坐标回归的目标,维度是(128,84), 其中84来自(20+1)*4
bbox_weight = group[3] # 坐标回归时候的权重,维度是(128,84),对于foreground都是1,对于backgroud都是0

在RPN网络得到proposal后还会经过一系列的过滤操作才会得到送入检测网络的proposal,节点proposal_target会将2000个proposal过滤成128个,且为这128个proposal分配标签、回归目标、定义正负样本的1:3比例等,这部分算是RPN网络和检测网络(Fast RCNN)的衔接,值得注意的是该节点不接受后面层数传递而来的梯度,且向前传递梯度强制为0,已即网络训练由其割裂为两个部分(尽管两部分仍然相连)。

ROIPooling层

将任意大小的输入层下采样为同样大小的输出层,方便后面的计算。这里我们使用候选框(128个)寻找各自对应的图片,并将各自对应的区域裁剪出来,然后pooling为同样的大小,

『计算机视觉』经典RCNN_其二:Faster-RCNN

本层的两条虚线输入中上面一条表示batch图像特征,下面一条表示候选框输入

    # rcnn roi pool
# [128个候选框, 512个通道, 7行, 7列]
roi_pool = mx.symbol.ROIPooling(
name='roi_pool',
data=conv_feat,
rois=rois,
pooled_size=rcnn_pooled_size, # (7, 7),输出大小
spatial_scale=1.0 / rcnn_feature_stride # 16, feat/raw_img
)

将对应的候选区域(注意此时抠图完成,已经不是候选框了)经由vgg的分类头部分(实际上就是对候选区域再进一步抽象提取特征)进行处理,

『计算机视觉』经典RCNN_其二:Faster-RCNN

    # rcnn top feature
# [128, 4096],对每个roi提取最终的vgg特征
top_feat = get_vgg_top_feature(roi_pool)

最后的两个损失函数生成过程,对128个候选区域的抽象特征进行分类(此时不是含/不含obj,而是直接进行21分类),并对每一个抽象特征回归出4个坐标值

两个损失函数标签均来自上面自定义节点的输出:

label = group[1]                   # roi对应的标签(128)

bbox_target = group[2]       # 坐标回归的目标,维度是(128,84), 其中84来自(20+1)*4

bbox_weight = group[3]      # 坐标回归时候的权重,维度是(128,84),对于foreground都是1,对于backgroud都是0

『计算机视觉』经典RCNN_其二:Faster-RCNN

    # rcnn classification
# 对每个roi进行分类,并构建损失函数
cls_score = mx.symbol.FullyConnected(name='cls_score', data=top_feat, num_hidden=num_classes)
cls_prob = mx.symbol.SoftmaxOutput(name='cls_prob', data=cls_score, label=label, normalization='batch') # rcnn bbox regression
# 对每个roi进行回归,并构建损失函数
bbox_pred = mx.symbol.FullyConnected(name='bbox_pred', data=top_feat, num_hidden=num_classes * 4)
bbox_loss_ = bbox_weight * mx.symbol.smooth_l1(name='bbox_loss_', scalar=1.0, data=(bbox_pred - bbox_target))
bbox_loss = mx.sym.MakeLoss(name='bbox_loss', data=bbox_loss_, grad_scale=1.0 / rcnn_batch_rois)

附、主体函数全览

def get_vgg_train(anchor_scales, anchor_ratios, rpn_feature_stride,
rpn_pre_topk, rpn_post_topk, rpn_nms_thresh, rpn_min_size, rpn_batch_rois,
num_classes, rcnn_feature_stride, rcnn_pooled_size, rcnn_batch_size,
rcnn_batch_rois, rcnn_fg_fraction, rcnn_fg_overlap, rcnn_bbox_stds):
num_anchors = len(anchor_scales) * len(anchor_ratios) data = mx.symbol.Variable(name="data") # 图片信息:[batch, channel, height, width]
im_info = mx.symbol.Variable(name="im_info")
gt_boxes = mx.symbol.Variable(name="gt_boxes") # 真实框信息:[obj数量, 5]
# anchor标签:-1、0、1 (无效、背景、目标)
rpn_label = mx.symbol.Variable(name='label') # [batch, 2, 中心点行数*每个位置anchors数目, 中心点列数]
# 根据初始anchor和ground truth计算出来的offset
rpn_bbox_target = mx.symbol.Variable(name='bbox_target') # [batch, 4*每个位置anchors数目, 中心点行数, 中心点列数]
# mask,如果anchor标签是1,则mask对应值为1,anchor标签是0或-1,则mask对应值为0
rpn_bbox_weight = mx.symbol.Variable(name='bbox_weight') # [batch, 4*每个位置anchors数目, 中心点行数, 中心点列数] # shared convolutional layers
conv_feat = get_vgg_feature(data) # RPN layers
rpn_conv = mx.symbol.Convolution(
data=conv_feat, kernel=(3, 3), pad=(1, 1), num_filter=512, name="rpn_conv_3x3")
rpn_relu = mx.symbol.Activation(data=rpn_conv, act_type="relu", name="rpn_relu") # rpn classification: obj / not_obj
# [batch, 2*每个位置anchors数目, 中心点行数, 中心点列数]
rpn_cls_score = mx.symbol.Convolution(
data=rpn_relu, kernel=(1, 1), pad=(0, 0), num_filter=2 * num_anchors, name="rpn_cls_score") # [batch, 2, 中心点行数*每个位置anchors数目, 中心点列数]
rpn_cls_score_reshape = mx.symbol.Reshape(
data=rpn_cls_score, shape=(0, 2, -1, 0), name="rpn_cls_score_reshape")
# 获取交叉熵回传梯度,对于出现了-1的图片梯度直接全部置为0
# 在Faster RCNN算法中,anchor一共有3种标签:-1、0、1,分别表示无效、背景、目标
rpn_cls_prob = mx.symbol.SoftmaxOutput(data=rpn_cls_score_reshape, label=rpn_label, multi_output=True,
normalization='valid', use_ignore=True, ignore_label=-1, name="rpn_cls_prob") # 切换为含/不含obj两通道,对每一个anchor是否有obj进行softmax处理
# [batch, 2, 中心点行数*每个位置anchors数目, 中心点列数]
rpn_cls_act = mx.symbol.softmax(
data=rpn_cls_score_reshape, axis=1, name="rpn_cls_act")
# [batch, 2*每个位置anchors数目, 中心点行数, 中心点列数]
# Reshpe方法不同于reshape方法,详情见此方法文档
rpn_cls_act_reshape = mx.symbol.Reshape(
data=rpn_cls_act, shape=(0, 2 * num_anchors, -1, 0), name='rpn_cls_act_reshape') # rpn bbox regression
# [batch, 4*每个位置anchors数目, 中心点行数, 中心点列数]
rpn_bbox_pred = mx.symbol.Convolution(
data=rpn_relu, kernel=(1, 1), pad=(0, 0), num_filter=4 * num_anchors, name="rpn_bbox_pred")
# rpn_bbox_weight: anchor的mask,如果某个anchor的标签是1,则mask对应值为1,anchor的标签是0或-1,则mask对应值为0
# rpn_bbox_target: 根据初始anchor和ground truth计算出来的offset
rpn_bbox_loss_ = rpn_bbox_weight * mx.symbol.smooth_l1(name='rpn_bbox_loss_',
scalar=3.0,
data=(rpn_bbox_pred - rpn_bbox_target))
# 获取回归梯度
# grad_scale: 表示回归损失占RPN网络总损失比,该参数相差几个量级对结果影响也不大
rpn_bbox_loss = mx.sym.MakeLoss(name='rpn_bbox_loss', data=rpn_bbox_loss_, grad_scale=1.0 / rpn_batch_rois) # rpn proposal
# 获取指定数目的候选框proposal
# [2000个候选框, 5个属性]
# 5个属性: batch中图片index,4个坐标
rois = mx.symbol.contrib.MultiProposal(
cls_prob=rpn_cls_act_reshape, # cls_prob: [batch, 2*每个位置anchors数目, 中心点行数, 中心点列数]
bbox_pred=rpn_bbox_pred, # bbox_pred: [batch, 4*每个位置anchors数目, 中心点行数, 中心点列数]
im_info=im_info, # mx.symbol.Variable(name="im_info")
feature_stride=rpn_feature_stride, # 16
scales=anchor_scales, ratios=anchor_ratios, # (0.5, 1, 2)
rpn_pre_nms_top_n=rpn_pre_topk, # 12000,对RPN网络输出的anchor进行NMS操作之前的proposal最大数量
# 输入proposal的数量大于12000时,对这些proposal的预测为foreground的概率(也叫score,
# 换句话说就是预测标签为1的概率)从高到低排序,然后选择前面12000个
rpn_post_nms_top_n=rpn_post_topk, # 2000,经过NMS过滤之后得到的proposal数量
threshold=rpn_nms_thresh, # 0.7,是NMS算法阈值
rpn_min_size=rpn_min_size, # 16
name = 'rois'
) # rcnn roi proposal target
# 根据上一步获取的proposal(即rois)和真实框(gt_boxes)进行筛选
# 获取128个proposal,对应的128个label,对应的128个真实坐标,128个坐标掩码(构建损失函数使用)
group = mx.symbol.Custom(rois=rois, # 2000*5的roi信息
gt_boxes=gt_boxes, # n*5的ground truth信息,n表示object数量
op_type='proposal_target',
num_classes=num_classes, # num_classes是实际要分类的类别数加上背景类
batch_images=rcnn_batch_size, # 1
batch_rois=rcnn_batch_rois, # 128
fg_fraction=rcnn_fg_fraction, # 0.25,正样本所占的比例
fg_overlap=rcnn_fg_overlap, # 0.5
box_stds=rcnn_bbox_stds # (0.1, 0.1, 0.2, 0.2)
) rois = group[0] # rois (128, 5)
label = group[1] # roi对应的标签(128)
bbox_target = group[2] # 坐标回归的目标,维度是(128,84), 其中84来自(20+1)*4
bbox_weight = group[3] # 坐标回归时候的权重,维度是(128,84),对于foreground都是1,对于backgroud都是0 # rcnn roi pool
# [128个候选框, 512个通道, 7行, 7列]
roi_pool = mx.symbol.ROIPooling(
name='roi_pool',
data=conv_feat,
rois=rois,
pooled_size=rcnn_pooled_size, # (7, 7),输出大小
spatial_scale=1.0 / rcnn_feature_stride # 16, feat/raw_img
) # rcnn top feature
# [128, 4096],对每个roi提取最终的vgg特征
top_feat = get_vgg_top_feature(roi_pool) # rcnn classification
# 对每个roi进行分类,并构建损失函数
cls_score = mx.symbol.FullyConnected(name='cls_score', data=top_feat, num_hidden=num_classes)
cls_prob = mx.symbol.SoftmaxOutput(name='cls_prob', data=cls_score, label=label, normalization='batch') # rcnn bbox regression
# 对每个roi进行回归,并构建损失函数
bbox_pred = mx.symbol.FullyConnected(name='bbox_pred', data=top_feat, num_hidden=num_classes * 4)
bbox_loss_ = bbox_weight * mx.symbol.smooth_l1(name='bbox_loss_', scalar=1.0, data=(bbox_pred - bbox_target))
bbox_loss = mx.sym.MakeLoss(name='bbox_loss', data=bbox_loss_, grad_scale=1.0 / rcnn_batch_rois) # reshape output
# [1, 128], [1, 128, 21], [1, 128, 84]
label = mx.symbol.Reshape(data=label, shape=(rcnn_batch_size, -1), name='label_reshape')
cls_prob = mx.symbol.Reshape(data=cls_prob, shape=(rcnn_batch_size, -1, num_classes), name='cls_prob_reshape')
bbox_loss = mx.symbol.Reshape(data=bbox_loss, shape=(rcnn_batch_size, -1, 4 * num_classes), name='bbox_loss_reshape')
print(cls_score.infer_shape(**{'data': (1, 3, 1000, 600), 'gt_boxes': (5, 5)})[1]) # group output
# mx.symbol.BlockGrad会阻止经由节点label回传的梯度
group = mx.symbol.Group([rpn_cls_prob, # anchors分类损失:[batch, 2, 中心点行数*每个位置anchors数目, 中心点列数]
rpn_bbox_loss, # anchors回归损失:[batch, 4*每个位置anchors数目, 中心点行数, 中心点列数]
cls_prob, # 候选框分类损失:[1, 128, 21]
bbox_loss, # 候选框回归损失:[1, 128, 84]
mx.symbol.BlockGrad(label) # 候选框标签:[1, 128]
])
return group if __name__=='__main__':
net = get_vgg_train(anchor_scales=(8, 16, 32),
anchor_ratios=(0.5, 1, 2),
rpn_feature_stride=16,
rpn_pre_topk=12000,
rpn_post_topk=2000,
rpn_nms_thresh=0.7,
rpn_min_size=16,
rpn_batch_rois=256,
num_classes=21,
rcnn_feature_stride=16, # 4个pooling层
rcnn_pooled_size=(7, 7),
rcnn_batch_size=1,
rcnn_batch_rois=128,
rcnn_fg_fraction=0.25,
rcnn_fg_overlap=0.5,
rcnn_bbox_stds=(0.1, 0.1, 0.2, 0.2))

『计算机视觉』经典RCNN_其二:Faster-RCNN的更多相关文章

  1. 『计算机视觉』经典RCNN_其一:从RCNN到Faster-RCNN

    RCNN介绍 目标检测-RCNN系列 一文读懂Faster RCNN 一.目标检测 1.两个任务 目标检测可以拆分成两个任务:识别和定位 图像识别(classification)输入:图片输出:物体的 ...

  2. 『计算机视觉』Mask-RCNN

    一.Mask-RCNN流程 Mask R-CNN是一个实例分割(Instance segmentation)算法,通过增加不同的分支,可以完成目标分类.目标检测.语义分割.实例分割.人体姿势识别等多种 ...

  3. 『计算机视觉』FPN:feature pyramid networks for object detection

    对用卷积神经网络进行目标检测方法的一种改进,通过提取多尺度的特征信息进行融合,进而提高目标检测的精度,特别是在小物体检测上的精度.FPN是ResNet或DenseNet等通用特征提取网络的附加组件,可 ...

  4. 『计算机视觉』Mask-RCNN_从服装关键点检测看KeyPoints分支

    下图Github地址:Mask_RCNN       Mask_RCNN_KeyPoints『计算机视觉』Mask-RCNN_论文学习『计算机视觉』Mask-RCNN_项目文档翻译『计算机视觉』Mas ...

  5. 『计算机视觉』Mask-RCNN_训练网络其二:train网络结构&损失函数

    Github地址:Mask_RCNN 『计算机视觉』Mask-RCNN_论文学习 『计算机视觉』Mask-RCNN_项目文档翻译 『计算机视觉』Mask-RCNN_推断网络其一:总览 『计算机视觉』M ...

  6. 『计算机视觉』Mask-RCNN_训练网络其一:数据集与Dataset类

    Github地址:Mask_RCNN 『计算机视觉』Mask-RCNN_论文学习 『计算机视觉』Mask-RCNN_项目文档翻译 『计算机视觉』Mask-RCNN_推断网络其一:总览 『计算机视觉』M ...

  7. 『计算机视觉』Mask-RCNN_锚框生成

    Github地址:Mask_RCNN 『计算机视觉』Mask-RCNN_论文学习 『计算机视觉』Mask-RCNN_项目文档翻译 『计算机视觉』Mask-RCNN_推断网络其一:总览 『计算机视觉』M ...

  8. 『计算机视觉』Mask-RCNN_推断网络其六:Mask生成

    一.Mask生成概览 上一节的末尾,我们已经获取了待检测图片的分类回归信息,我们将回归信息(即待检测目标的边框信息)单独提取出来,结合金字塔特征mrcnn_feature_maps,进行Mask生成工 ...

  9. 『计算机视觉』Mask-RCNN_推断网络其四:FPN和ROIAlign的耦合

    一.模块概述 上节的最后,我们进行了如下操作获取了有限的proposal, # [IMAGES_PER_GPU, num_rois, (y1, x1, y2, x2)] # IMAGES_PER_GP ...

随机推荐

  1. Sublime Text 全程指南

    摘要(Abstract) 本文系统全面的介绍了 Sublime Text,旨在成为最优秀的 Sublime Text 中文教程. 更新记录 2014/09/27:完成初稿 2014/09/28: 更正 ...

  2. xpages的comboBox能够手动输入

    在xpages使用的comboBox默认仅仅能选择.不能手动输入,怎么才干手动输入呢?经过查找资料和測试,最终能够了,请大家能够试试 假设试不行,能够再下载demo http://download.c ...

  3. ps设计资料整理

    零基础学会建立一个简单化妆品网站—前台设计篇1[PS画草图] http://xiebiji.com/2008/09/huazhuang4/?wptheme=Plainscape&ie=1 PS ...

  4. java排序算法(三):堆排序

    java排序算法(三)堆排序 堆积排序(HeapSort)是指利用堆积树这种结构所设计的排序算法,可以利用数组的特点快速定位指定索引的元素.堆排序是不稳定的排序方法.辅助空间为O(1).最坏时间复杂度 ...

  5. xml序列化和反序列化(二)

    上篇讲到关于xml入参实体序列化,下面给出出参实体反序列化,代码如下: /// <summary> /// 反序列化 /// </summary> /// <param ...

  6. ado&period;net的简单数据库操作(二)之封装SqlHelperl类

    今天我书接上回,接着昨天的ado.net的数据库操作的相关知识来讲哈! 从上篇文章给出的实例来看,你一定会发现,操作数据库其实还挺麻烦的,就连一个最简单的数据库操作语句都要包括 定义数据库连接字符串. ...

  7. NetBeans配置subli

    NetBeans主题设置: ①.去https://netbeansthemes.com/rank/网址下载喜欢的主题 ②.然后打开NetBeans-->工具->选项->外观-> ...

  8. Mysql Federated For Windows

    [1]windows环境下打开federated (1)关闭.命令:mysql> net stop mysql (2)添加federated字段.在my.ini文件中添加一个字段,注意位于[my ...

  9. Visual Basic 6&period;0(VB6&period;0)详细安装过程

    注:大家如果没有VB6.0的安装文件,可自行百度一下下载,一般文件大小在200M左右的均为完整版的软件,可以使用. 特别提示:安装此软件的时候最好退出360杀毒软件(包括360安全卫士,电脑管家等,如 ...

  10. Linux系统查看系统硬件配置信息

    1.查看CPU信息 # 查看cpu负载 uptime # cpu使用率 (没有sar 则yum -y install sysstat) sar top bn1 |grep %Cpu # 每个cpu使用 ...