R-FCN解读

2024-08-24 18:08
文章标签 解读 fcn

本文主要是介绍R-FCN解读,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

最近一直做检测,发现检测领域好多好玩的东西啊,R-FCN是msra dai老师和kaiming做的,insight很赞,这次翻出来再学习一下。最近旷视科技又发了light RCNN,检测这领域真是日新月异。

Motivation

虽然fast rcnn共享了每个roi的feature map, faster rcnn利用rpn也使proposal的生成共享了feature map,已经比之前的rcnn减少了大量计算方法,快了很多。但是roi pooling后面的多个fc,每个roi之间是没有共享计算的,而且fc的参数巨多,在之前的faster rcnn源码解析中也都讲过,train时有128个送到后面,test时有300个送到后面,大量的重复计算浪费了很多时间。

观察到ResNet和GoogLeNet,他们只在最后一层f是全连接的,不像vgg有隐层fc6 fc7,所以很自然的方法,我们能不能把roi pooling后面的隐层fc去掉,rpn共享前面所有的卷积,roi pooling后直接跟一个fc,但是效果是不行的,所以kaiming的ResNet附录里A. Object Detection Baselines的做法是共享前91个卷积(相当于vgg的前13个卷积),后面10个卷积依然不共享(相当于vgg的隐层fc)。kaiming为什么这样做呢?因为分类是要求translation invariance,而检测要求translation variance,这就矛盾了,所以需要通过roi pooling这种与位置相关的层打破translation invariance,roi后面的卷积就有了translation-invariance性,但是这样还是降低了速度。(后来的faster rcnn v3时是仅仅把vgg的特征换成resnet的,roi 后面还是fc6 fc7 fc8)

所以这篇论文就想能不能共享所有的计算,并提出了Region-based Fully Convolutional Network (R-FCN)

这里写图片描述
(以RoIpooling为分界线,分为两部分)

# ResNet101 prototxt
layer {bottom: "res5c"top: "pool5"name: "pool5"type: "Pooling"pooling_param {kernel_size: 7stride: 1pool: AVE}
}
layer {bottom: "pool5"top: "fc1000"name: "fc1000"type: "InnerProduct"inner_product_param {num_output: 1000}
}
layer {bottom: "fc1000"top: "prob"name: "prob"type: "Softmax"
}

Approach

这里写图片描述

在最后一个卷积res5c后,添加一个1*1的卷积生成k^2(C+1)个channel的位置敏感的分类feature和k^2(C+1)个channel的回归feature。以分类为例,这k^2个score map对应k^2个格子的位置。以k=3,左上角为例,黄色是C+1个channel,每个channel对应一个类别在左上角的score map,经过经过这个pool之后得到(C+1)*k*k,然后vote(avg or max pool),得到(C+1)*1*1,直接softmax,没有fc或者卷积等计算,所有roi都贡献了计算。注意还有个

# conv_new_1
# relu1是C1-C5后加了relu后的feature。
# ResNet-101 has 100 convolutional layers followed by global average pooling and a 1000-class fc layer
# R-FCN把global pool和fc都去掉,加了个1*1的卷积降维,然后这101个卷积都贡献参数和计算
conv_new_1 = mx.sym.Convolution(data=relu1, kernel=(1, 1), num_filter=1024, name="conv_new_1", lr_mult=3.0)
relu_new_1 = mx.sym.Activation(data=conv_new_1, act_type='relu', name='relu1')# rfcn_cls/rfcn_bbox
# rfcn_cls: k*k(C+1)个channel rfcn_bbox: k*k*4(C+1)个channe
rfcn_cls = mx.sym.Convolution(data=relu_new_1, kernel=(1, 1), num_filter=7*7*num_classes, name="rfcn_cls")rfcn_bbox = mx.sym.Convolution(data=relu_new_1, kernel=(1, 1), num_filter=7*7*4*num_reg_classes, name="rfcn_bbox")psroipooled_cls_rois = mx.contrib.sym.PSROIPooling(name='psroipooled_cls_rois', data=rfcn_cls, rois=rois, group_size=7, pooled_size=7,output_dim=num_classes, spatial_scale=0.0625)psroipooled_loc_rois = mx.contrib.sym.PSROIPooling(name='psroipooled_loc_rois', data=rfcn_bbox, rois=rois, group_size=7, pooled_size=7, output_dim=8, spatial_scale=0.0625)
# vote
cls_score = mx.sym.Pooling(name='ave_cls_scors_rois', data=psroipooled_cls_rois, pool_type='avg', global_pool=True, kernel=(7, 7))bbox_pred = mx.sym.Pooling(name='ave_bbox_pred_rois', data=psroipooled_loc_rois, pool_type='avg', global_pool=True, kernel=(7, 7))cls_score = mx.sym.Reshape(name='cls_score_reshape', data=cls_score, shape=(-1, num_classes))bbox_pred = mx.sym.Reshape(name='bbox_pred_reshape', data=bbox_pred, shape=(-1, 4 * num_reg_classes))# softmax计算loss
cls_prob = mx.sym.SoftmaxOutput(name='cls_prob', data=cls_score, label=label, normalization='valid', grad_scale=1.0)bbox_loss_ = bbox_weight * mx.sym.smooth_l1(name='bbox_loss_', scalar=1.0, data=(bbox_pred - bbox_target))

Position-sensitive RoI pooling

rpn生成的每个proposal对应到这k^2(C+1)个channel的score map上得到每个roi,然后将每个roi划分为k*k个bin,每个bin是位置相关的,比如左上角的bin,只在黄色层(C+1个channel)对应位置做average或max pooling,注意是对应位置,只在黄色层的左上角做,不是在黄色层整个roi上做。比如下面这个只看person这个channel,第一个图是左上角的bin,只在第一个图roi的左上角红色框做pool,不是在这个图的整个roi绿色框做pool。
这里的k相当于roi pooling的pool height/width
这里写图片描述

//使用CUDA多线程计算  
CUDA_KERNEL_LOOP(index, nthreads) {   //index为最终score map上所有,共有(C+1)*k*k个值  
// The output is in order (n, ctop, ph, pw),类似于图像的BIL逐行扫描  
int pw = index % pooled_width;   //score map上第i=[0,k-1]列  
int ph = (index / pooled_width) % pooled_height;   //score map上第j=[0,k-1]行  
int ctop = (index / pooled_width / pooled_height) % output_dim;   //score map上第ctop个层(class)  
int n = index / pooled_width / pooled_height / output_dim;   //第n个roi  
// ......
int gw = pw;  
int gh = ph;  
//ctop*group_size*group_size+gh*gh*group_size+gw,计算得到的是第ctop类的(ph,pw)位置索引  
//例如,score map上第ctop=1类的第(i,j)=(1,1)位置,c=1*49+1*7+1,对于feature map上第c个颜色层中(实际包含C=21层)的第2(ctop+1)层  
int c = (ctop*group_size + gh)*group_size + gw;    
// 移动到该层做average pool
// 这是cuda代码,每次计算score map上一个值,如左上角

其他细节

  1. ResNet101的res5c是2048channel,为了减少计算量,先用了个1*1的卷积降维到了1024,然后才有position-sensitive的score map
  2. 加了洞算法,调整了步长,使最户的feature map为1/16
  3. 经过position-sensitive pooling后得到了k^2(C+1)的feature(类似于roipooling后的7*7*512的feature),后面两个分支,一个是分支首先average/max pooling到1*1*(C+1),然后softmax得到分类,另一个是坐标回归,生成4k^2-d的向量,然后做average/max pooling到4-d。此处为了简便,做的是类别无关的回归,但是类别相关的回归(生成4k^2C-d的向量)也是适用的

实验

这里写图片描述

  • Naive Faster R-CNN 就是开始说的直接ResNet拿过来,roi pooling后无隐层fc,区别于kaiming的roi pooling后有10个卷积(76.4% mAP)
  • Class-specific RPN,之前的rpn只分为是否是物体,这里直把proposal分为具体哪一个类别
  • R-FCN without position-sensitivity,即k设置为1,类似于分割直接产生C+1个channel,每个channel代表一个类别的score map。这是最直接的做法了

    根据表可知R-FCN和标准的faster rcnn(76.4% mAP)差不多了,在roi后没有用任何带参数的层,证明
    ps-RoIpooling可以编码到有用的用于定位的空间信息,ps: Class-specific RPN近似于fast rcnn中sliding window的特殊形式

这里写图片描述

这两个表说明,R-FCN节省了很多训练和测试时间,且和标准的faster rcnn相比精度还要高一点点

这里写图片描述

这两个表说明这个策略泛化性很强,无论是不同深度的网络还是不同的proposal的提取方式,该论文的策略都适用。


参考:
msracver/Deformable-ConvNets

这篇关于R-FCN解读的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1103214

相关文章

java之Objects.nonNull用法代码解读

《java之Objects.nonNull用法代码解读》:本文主要介绍java之Objects.nonNull用法代码,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐... 目录Java之Objects.nonwww.chinasem.cnNull用法代码Objects.nonN

SpringCloud负载均衡spring-cloud-starter-loadbalancer解读

《SpringCloud负载均衡spring-cloud-starter-loadbalancer解读》:本文主要介绍SpringCloud负载均衡spring-cloud-starter-loa... 目录简述主要特点使用负载均衡算法1. 轮询负载均衡策略(Round Robin)2. 随机负载均衡策略(

解读spring.factories文件配置详情

《解读spring.factories文件配置详情》:本文主要介绍解读spring.factories文件配置详情,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录使用场景作用内部原理机制SPI机制Spring Factories 实现原理用法及配置spring.f

Spring MVC使用视图解析的问题解读

《SpringMVC使用视图解析的问题解读》:本文主要介绍SpringMVC使用视图解析的问题解读,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录Spring MVC使用视图解析1. 会使用视图解析的情况2. 不会使用视图解析的情况总结Spring MVC使用视图

Linux中的进程间通信之匿名管道解读

《Linux中的进程间通信之匿名管道解读》:本文主要介绍Linux中的进程间通信之匿名管道解读,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、基本概念二、管道1、温故知新2、实现方式3、匿名管道(一)管道中的四种情况(二)管道的特性总结一、基本概念我们知道多

Linux系统之authconfig命令的使用解读

《Linux系统之authconfig命令的使用解读》authconfig是一个用于配置Linux系统身份验证和账户管理设置的命令行工具,主要用于RedHat系列的Linux发行版,它提供了一系列选项... 目录linux authconfig命令的使用基本语法常用选项示例总结Linux authconfi

解读docker运行时-itd参数是什么意思

《解读docker运行时-itd参数是什么意思》在Docker中,-itd参数组合用于在后台运行一个交互式容器,同时保持标准输入和分配伪终端,这种方式适合需要在后台运行容器并保持交互能力的场景... 目录docker运行时-itd参数是什么意思1. -i(或 --interactive)2. -t(或 --

解读为什么@Autowired在属性上被警告,在setter方法上不被警告问题

《解读为什么@Autowired在属性上被警告,在setter方法上不被警告问题》在Spring开发中,@Autowired注解常用于实现依赖注入,它可以应用于类的属性、构造器或setter方法上,然... 目录1. 为什么 @Autowired 在属性上被警告?1.1 隐式依赖注入1.2 IDE 的警告:

Rust中的注释使用解读

《Rust中的注释使用解读》本文介绍了Rust中的行注释、块注释和文档注释的使用方法,通过示例展示了如何在实际代码中应用这些注释,以提高代码的可读性和可维护性... 目录Rust 中的注释使用指南1. 行注释示例:行注释2. 块注释示例:块注释3. 文档注释示例:文档注释4. 综合示例总结Rust 中的注释

解读Pandas和Polars的区别及说明

《解读Pandas和Polars的区别及说明》Pandas和Polars是Python中用于数据处理的两个库,Pandas适用于中小规模数据的快速原型开发和复杂数据操作,而Polars则专注于高效数据... 目录Pandas vs Polars 对比表使用场景对比Pandas 的使用场景Polars 的使用