FasterRCNN

论文:“Faster R-CNN: Towards Real-Time Object Detection with Region Proposal Networks”

FasterRCNN主要包括 backbone、RPN、ROI Pooling、Classifier几个部分。总体上相当于RPN+FastRCNN。

图源:https://github.com/WZMIAOMIAO/deep-learning-for-image-processing

Backbone

Backbone是整个目标检测网络的主干,用于特征提取,通常使用VGG、ResNet等网络。将原图输入进backbone之后会得到一系列特征图。

RPN

RPN(Region Proposal Network)用于生成备选区域。输入的是backbone输出的特征图。

主要步骤:

  1. 通过RPNHead部分预测得到每个Anchors到GT bbox的偏移量box_pred以及它们包含物体的概率cls_logits。
  2. 通过AnchorGenerator在backbone的特征图上产生不同尺度大小的Anchors,并投影回到原始图像上。
  3. Proposals将RPNHead输出的分类参数和回归参数与AnchorGenerator产生的Anchors相结合,得到最终预测的bbox坐标。
  4. FilterProposals过滤掉小面积的Proposal,之后根据预测概率筛选出每层特征图上的前pre_nms_top_n个bbox(2000),最后进行NMS,得到总共的post_nms_top_n个bbox(2000)。
  5. 如果是在训练阶段,则还要在第3步得到的Anchors的基础上分正负样本,计算损失。

RPNHead

该部分使用一个滑动窗口在输入的特征图上进行滑动,滑动的输出成为后面两个并行层(cls 层和 reg 层) 的输入。

在具体实现上,首先是一个 3×33 \times 33×3 卷积作为滑动窗口融合每个点周围的信息。之后通过 1×11\times11×1 卷积分成了并行的两层。上面的reg层回归每个Anchor到GT bbox的偏移参数。下面的cls层做一个二分类:前景(包含目标)、背景(不包含目标)。

举例:

假设通过backbone只输出一层特征图,形状为 [C,H,W][C,H,W][C,H,W],3×33\times33×3 卷积不改变特征图的数量,则reg层的 1×11\times11×1 卷积的输出形状为 [4k,H,W][4k,H,W][4k,H,W]。kkk 表示在特征图的每个像素点上生成 kkk 个Anchor。每个Anchor的偏移参数为 (dx,dy,dh,dw)(d_x,d_y,d_h,d_w)(dx​,dy​,dh​,dw​),因此是 4k4k4k。

下面cls层的 1×11\times11×1 卷积输出形状为 [2k,H,W][2k,H,W][2k,H,W]。表示每个Anchor是前景和背景的概率(pytorch官方实现中输出为 [k,H,W][k,H,W][k,H,W],表示positive的概率),之后进行softmax(pytorch官方实现中并没有进行softmax)。

class RPNHead(nn.Module):"""add a RPN head with classification and regression通过滑动窗口计算预测目标概率与bbox regression参数Arguments:in_channels: number of channels of the input featurenum_anchors: number of anchors to be predicted"""def __init__(self, in_channels, num_anchors):super(RPNHead, self).__init__()# 3x3 滑动窗口self.conv = nn.Conv2d(in_channels, in_channels, kernel_size=3, stride=1, padding=1)# 计算预测的目标分数(这里的目标只是指前景或者背景)self.cls_logits = nn.Conv2d(in_channels, num_anchors, kernel_size=1, stride=1)# 计算预测的目标bbox regression参数self.bbox_pred = nn.Conv2d(in_channels, num_anchors * 4, kernel_size=1, stride=1)for layer in self.children():if isinstance(layer, nn.Conv2d):torch.nn.init.normal_(layer.weight, std=0.01)torch.nn.init.constant_(layer.bias, 0)def forward(self, x):# type: (List[Tensor]) -> Tuple[List[Tensor], List[Tensor]]logits = []bbox_reg = []for i, feature in enumerate(x):t = F.relu(self.conv(feature))logits.append(self.cls_logits(t))bbox_reg.append(self.bbox_pred(t))return logits, bbox_reg

AnchorGenerator

该模块用于在原始图像上产生不同尺度大小的Anchor。

Proposals

Proposals将RPNHead回归到的Anchor偏移参数应用到AnchorGenerator生成的一系列Anchor之上。具体方法为:

如图,红色框是positive anchor,绿色的框是GT bbox,而我们需要找到就是一个变换,将红色的框映射到蓝色的框,使得蓝色的框尽量接近绿色的GT bbox。变换方法可以使用平移+缩放的组合。

假设红色框的坐标参数为 (Ax,Ay,Aw,Ah)(A_x,A_y,A_w,A_h)(Ax​,Ay​,Aw​,Ah​),分别为红色框的中心点坐标、和宽、高。蓝色框的坐标参数为 (Gx′,Gy′,Gw′,Gh′)(G'_x,G'_y,G'_w,G'_h)(Gx′​,Gy′​,Gw′​,Gh′​)。则变换过程为
Gx′=Aw∗dx+AxGy′=Ah∗dy+AyGw′=Aw∗edwGh′=Ah∗edhsG'_x=A_w*d_x+A_x\\ G'_y=A_h*d_y+A_y\\ G'_w=A_w*e^{d_w}\\ G'_h=A_h*e^{d_h}s Gx′​=Aw​∗dx​+Ax​Gy′​=Ah​∗dy​+Ay​Gw′​=Aw​∗edw​Gh′​=Ah​∗edh​s
则我们需要回归的偏移参数即为 (dx,dy,dw,dh)(d_x,d_y,d_w,d_h)(dx​,dy​,dw​,dh​)。在训练阶段,GT bbox坐标信息已知,则 (dx,dy,dw,dh)(d_x,d_y,d_w,d_h)(dx​,dy​,dw​,dh​) 学习的目标值为 (tx,ty,tw,th)(t_x,t_y,t_w,t_h)(tx​,ty​,tw​,th​):
tx=Gx−AxAwty=Gy−AyAhtw=log(GwAw)th=log(GhAh)t_x=\frac{G_x-A_x}{A_w}\\ t_y=\frac{G_y-A_y}{A_h}\\ t_w=log(\frac{G_w}{A_w})\\ t_h=log(\frac{G_h}{A_h}) tx​=Aw​Gx​−Ax​​ty​=Ah​Gy​−Ay​​tw​=log(Aw​Gw​​)th​=log(Ah​Gh​​)

FilterProposal

def filter_proposals(self, proposals, objectness, image_shapes, num_anchors_per_level):# type: (Tensor, Tensor, List[Tuple[int, int]], List[int]) -> Tuple[List[Tensor], List[Tensor]]"""筛除小boxes框,nms处理,根据预测概率获取前post_nms_top_n个目标Args:proposals: 预测的bbox坐标objectness: 预测的目标概率image_shapes: batch中每张图片的size信息num_anchors_per_level: 每个预测特征层上预测anchors的数目Returns:"""num_images = proposals.shape[0]device = proposals.device# do not backprop throught objectnessobjectness = objectness.detach()objectness = objectness.reshape(num_images, -1)# Returns a tensor of size size filled with fill_value# levels负责记录分隔不同预测特征层上的anchors索引信息levels = [torch.full((n, ), idx, dtype=torch.int64, device=device)for idx, n in enumerate(num_anchors_per_level)]levels = torch.cat(levels, 0)# Expand this tensor to the same size as objectnesslevels = levels.reshape(1, -1).expand_as(objectness)# select top_n boxes independently per level before applying nms# 获取每张预测特征图上预测概率排前pre_nms_top_n的anchors索引值top_n_idx = self._get_top_n_idx(objectness, num_anchors_per_level)image_range = torch.arange(num_images, device=device)batch_idx = image_range[:, None]  # [batch_size, 1]# 根据每个预测特征层预测概率排前pre_nms_top_n的anchors索引值获取相应概率信息objectness = objectness[batch_idx, top_n_idx]levels = levels[batch_idx, top_n_idx]# 预测概率排前pre_nms_top_n的anchors索引值获取相应bbox坐标信息proposals = proposals[batch_idx, top_n_idx]objectness_prob = torch.sigmoid(objectness)final_boxes = []final_scores = []# 遍历每张图像的相关预测信息for boxes, scores, lvl, img_shape in zip(proposals, objectness_prob, levels, image_shapes):# 调整预测的boxes信息,将越界的坐标调整到图片边界上boxes = box_ops.clip_boxes_to_image(boxes, img_shape)# 返回boxes满足宽,高都大于min_size的索引keep = box_ops.remove_small_boxes(boxes, self.min_size)boxes, scores, lvl = boxes[keep], scores[keep], lvl[keep]# 移除小概率boxes,参考下面这个链接# https://github.com/pytorch/vision/pull/3205keep = torch.where(torch.ge(scores, self.score_thresh))[0]  # ge: >=boxes, scores, lvl = boxes[keep], scores[keep], lvl[keep]# non-maximum suppression, independently done per levelkeep = box_ops.batched_nms(boxes, scores, lvl, self.nms_thresh)# keep only topk scoring predictionskeep = keep[: self.post_nms_top_n()]boxes, scores = boxes[keep], scores[keep]final_boxes.append(boxes)final_scores.append(scores)return final_boxes, final_scores

Loss Function

在训练阶段,需要区分正负样本。在所有得到的anchors中,下面两种anchor被认为是正样本

  • 与GT bbox 拥有最大的IOU的anchor
  • 与GT bbox的IOU在0.7以上的anchor

一个GT bbox可能对应多个 positive anchor

如果一个anchor与所有的GT bbox的IOU都小于0.3,那么标记其为负样本。剩下的anchor被丢弃掉。

区分完正负样本之后,还需要再次从中选取真正用于训练的样本mini-batch=256,其中正负样本的比例为1:1,如果正样本不足128个,那么剩下的用负样本来填充。

损失函数为分类损失和回归损失的加权和。分类损失使用二值交叉熵损失函数,bbox的回归损失使用smooth L1损失函数。

ROI Head

RPN网络会输出为形状为 [2000,4][2000,4][2000,4] 的tensor表示每张图像上的2000个proposals作为ROI Head模块的输入。但是在训练时并没有使用2000个proposal,而是采样了其中的512个。ROI Head部分包括了两个全连接层、FastRCNN Preditor、postprocess。

图源:https://github.com/WZMIAOMIAO/deep-learning-for-image-processing

划分正负样本

训练阶段,需要划分出正负样本。首先对每个proposal与每个GT bbox计算IOU,将每个proposal和与其IOU最大的GT bbox对应。接着划分正负样本,划分方法:

  • proposal与GT box的IOU大于0.5为正样本
  • proposal与GT box的IOU小于0.5为负样本

负样本类别的target设为0代表是背景

之后是数据采样,在输入的2000个proposal的基础上采样512个proposal,正样本占25%(可调),负样本占75%,如果正样本不够就用负样本填充。

如果是在测试阶段,那么只会生成1000个proposal。

ROI Pooling

ROI Pooling根据每张图像上的proposals得到固定大小(如 7×77\times77×7 )的特征图。ROI Pooling将每个proposal分成 7×77\times77×7 个部分,取每个部分的最大值作为输出。为了解决在此过程中多次取整的问题,可以用ROI Align代替。ROI Align通过双线性插值解决不断取整的问题。通过该部分得到每个图像的特征图的形状为 [N,out_channels,7,7]。其中N是整个batch的proposal的个数,如果batch_size=2,则N=1024。out_channels是backbone输出特征图的通道数

Two MLP Head

该模块包含了两个全连接层,首先将ROI Pooling的输出特征图展平成 [N, out_channels ×\times× 7 ×\times× 7],经过两个全连接层 FC1: [N ×\times× out_channels ×\times× 7 ×\times× 7, 1024], FC2: [1024,1024]。最后输出为[N, 1024] 的tensor。

FastRCNN Predictor

该模块的输入是Two MLP Head部分的输出。通过两个全连接层并行地预测类别和bbox参数。FC3: [1024, num_classes] 预测类别,输出为 [N, num_classes] 的tensor。FC4: [1024, num_classes ×\times× 4] 预测bbox的参数,对每个proposal的每个类别都预测一个bbox。在训练阶段还会计算该部分的损失,同样由分类损失bbox回归损失两部分组成。

PostProcess

该模块是后处理。

FasterRCNN相关推荐

  1. RCNN系列、Fast-RCNN、Faster-RCNN、R-FCN检测模型对比

    RCNN系列.Fast-RCNN.Faster-RCNN.R-FCN检测模型对比 一.RCNN 问题一:速度 经典的目标检测算法使用滑动窗法依次判断所有可能的区域.本文则预先提取一系列较可能是物体的候 ...

  2. 基于CNN目标检测方法(RCNN,Fast-RCNN,Faster-RCNN,Mask-RCNN,YOLO,SSD)行人检测,目标追踪,卷积神经网络

    一.研究意义 卷积神经网络(CNN)由于其强大的特征提取能力,近年来被广泛用于计算机视觉领域.1998年Yann LeCun等提出的LeNet-5网络结构,该结构使得卷积神经网络可以端到端的训练,并应 ...

  3. python脚本——图片重命名、图片合成视频、faster-rcnn画P-R曲线

    调试faster rcnn算法实用的python脚本 目录 调试faster rcnn算法实用的python脚本 一.前言 二.常用python脚本 三.后记 一.前言 最近在做关于目标检测算法的研究 ...

  4. 目标检测之Faster-RCNN的pytorch代码详解(数据预处理篇)

    首先贴上代码原作者的github:https://github.com/chenyuntc/simple-faster-rcnn-pytorch(非代码作者,博文只解释代码) 今天看完了simple- ...

  5. fasterrcnn深度学习口罩检测

    fasterrcnn深度学习口罩检测 前言 FasterRCNN原理详解 训练我们自己的FasterRCNN 使用labelimg制作我们自己的VOC数据集 FasterRCNN训练详解 源码地址与小 ...

  6. FasterRCNN代码解读

    之前的文章简要介绍了Faster-RCNN等物体检测的算法,本文将从代码角度详细分析介绍Faster-RCNN的实现.本文使用的代码参考了chenyuntc的实现,代码的位置看这里.需要注意的是,本文 ...

  7. windows下faster-rcnn遇到的检测框重复很多问题 nms

    最近在做目标检测.于是就采用了RBG大神的faster rcnn进行切入.从RCNN开始,一直到Faster rcnn,先把理论过了一遍.接下来就是实践了,准备跑下代码.faster rcnn看了大体 ...

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

    RCNN介绍 目标检测-RCNN系列 一.目标检测 1.两个任务 目标检测可以拆分成两个任务:识别和定位 图像识别(classification) 输入:图片 输出:物体的类别 评估方法:准确率 定位 ...

  9. Faster-RCNN 自己的数据训练

    参考网址:https://blog.csdn.net/l297969586/article/category/7178545(一呆飞仙)Faster-RCNN_TF代码解读, 参考网址:https:/ ...

  10. 图像理解之物体检测object detection,模型rcnn/fastrcnn/fasterrcnn原理及概念

    A,https://www.cnblogs.com/zhengzhe/p/7783270.html RCNN选择性搜索(Selective Search) RCNN选择性搜索(Selective Se ...

最新文章

  1. STM8S103 解决Rom空间不足 Map文件分析
  2. linux7.4 配置yum,Centos7.4重装yum
  3. 安卓7.0拍照遇到 Uri暴露错误
  4. 【ES9(2018)】Object Rest Spread
  5. thymeleaf 获取yml中的值_Thymeleaf模板引擎学习
  6. 30分钟彻底弄懂flex布局
  7. elastic-job和xxl-job实践对比
  8. CentOS下查看电脑硬件设备属性命令
  9. 【GZH逸佳君】:科技感膨爆,观赏性极强:送你PS粒子飞溅特效插件,1秒瞬间爆开
  10. 云原生系列六:容器和Docker
  11. 【深度】被加班,狼性文化面纱下的奴性文化
  12. log4j2 日期换天后,今天的日志打印到了昨天的日志文件里面,rollover混乱
  13. ClockGen,旧电脑的超频利器
  14. ChatGPT:chatGPT本地部署、运行和接口调用
  15. Knewton适应性学习
  16. 一个整数拆分为连续自然数之和
  17. [python3教程]第七章.输入输出(Input and Output)
  18. 将PDF论文转换成Word格式
  19. Equals与==的区别
  20. Qt之opengl画钻石

热门文章

  1. Android 签名板
  2. yalmip实用操作(1)
  3. 基于JSP实现的作业管理系统
  4. 达梦数据库html管理,达梦数据库的管理 - osc_nbqoh20k的个人空间 - OSCHINA - 中文开源技术交流社区...
  5. 服务器SSH 22端口关闭
  6. ubuntu18.04 端口转发工具 Rinetd
  7. 【在线仿真】Arduino WS2812b环形24颗霓虹灯动态效果显示
  8. 微信小程序播放器实战开发教程
  9. IDEA2019安装及PJ
  10. idea导入项目框架的方法