Bootstrap

RFBnet论文及其代码详解

RFBnet


之前学习一直是看CSDN和知识,感觉还是很多细节未能很好地了解,于是最近打算开始阅读原文,并记录自己的想法与代码解析。

可能有些错别字或者错误结论啥的哈。希望见谅。

Abstract

当前顶尖的目标检测网络(背景是在2018年)都是基于卷积神经网络作为特征提取网络(backbone),例如resnet-101与Inception,虽然这些特征提取网络有着强大的特征提取能力,但是却需要高昂的计算开销。与之相反,一些轻量化模型可以实现实时检测,但他们的精度却受到诟病。

在这篇文章中,作者探索出一个可替代的目标检测方法,通过人工特征加强这些轻量化模型的特征提取能力。作者的灵感来源于人类视觉系统的感受野(人眼关注目标物体的视野范围)结构。因此作者根据仿生学的原理提出了一个RFB模块,这个模块中以RFs的尺寸和偏心距之间的关系作为考量,以此提升网络提取特征的可变性与鲁棒性。

作者将这个模块集成与SSD网络的预测层之前,由此构成RFBnet目标检测网络的结构。为了评估作者提出网络的性能,实验在两个主要的基准线方法上(baseline)进行比较,结构表明RFBnet可以在拥有实时目标检测速度的前提下,依然有着卓越的检测性能。


Introduce

最近几年(2018年的背景喽)以RCNN,Fast-RCNN,Faster-RCNN为首的这三兄弟以及其牛逼的性能霸榜 Pascal VOC , MS COCO, and ILSVRC这三个数据集。 当然啦,他们都是二阶目标检测网络,大致思想为,一阶段进行前景与背景的区分,二阶段进行分类与回归。然后作者就扯了扯最近二阶段的一些成果什么的。

突然!一个however话锋一转,作者diss这些东东提取的特征都是来自深层次的网络,所以呐,计算机开销大,速度不太行呀。然后作者需要夸夸自己的滴工作了。

作者先介绍一阶目标检测网络速度上的优势,但是一阶目标检测网络需要牺牲性能。文中说大概比二阶目标检测网络的SOTA(最佳算法)低10% ~40%之间吧。这我一阶目标检测网络能服气,反正我是不服气。因为我就是搞一阶目标检测网络的(手动狗头)。

作者接着说最近呀,DSSD和Retinanet这两兄弟很争气,有效缓解了精度不足的问题。不幸的是,这两货使用的是resnet-101,这个backbone太慢了。

那么怎么办呢?作者提议不用这么深的特征提取网络,就用轻量化与RFB模块的特征提取网络来提取特征。而且作者说RFB模块对整个网络没什么制约,这个制约,个人猜测应该是不存在副作用吧,

随后作者列出了几点贡献

  • 提出了RFB模块
  • 将RFB模块置于检测头之前,计算开销在作者看来可以忽略不记。
  • 与MobileNet进行实验验证RFB对于轻量化backbone的有效性

Related Work

  1. Inception
  2. ASPP
  3. Deformable Conv
    在这里插入图片描述

作者将这几个结构的感受野与RFB模块的感受野进行对比,以证明RFB模块的优越性

  • Inception是利用不同大小的卷积核来获取感受野,图上的颜色更为丰富
  • ASPP是采取相同的卷积核,但是空洞数不一样,图上的颜色区域更大
  • Deformable Conv是变换卷积核中的采样点以获取不同的感受野

于是作者将Inception与ASPP二者进行结合,提出了RFB模块

RFB模块介绍

在这里插入图片描述

作者将RFB模块分为两部分 多分支的卷积与空洞卷积

多分支的卷积主要是借鉴了Googlenet的思想

空洞卷积的设置主要是借鉴了ASPP的思想

于是作者提出了两种RFB模块分别应用于目标检测网络的不同位置

在这里插入图片描述

上图是RFB模块的解释图。可以观察到每个分支得到的特征图是不一样的,这里作者用蓝色圆,绿色圆,以及红色圆来表示。可以发现他们的大小与覆盖区域也是不一样的。相加与一张图上正好可以覆盖整张图。这也是为什么作者最后需要将不同通道上的特征图进行通道堆叠。

在这里插入图片描述

知道了模块长什么样子之后我们需要知道应该放到哪里,或者说那些地方可以用到。

作者考虑到浅层感受野的缺失,主要是将模块应用于38与19两个特征图的预测之前。

之后的层也用到空洞卷积。

实验部分

消融实验
在这里插入图片描述

Pascal VOC

在这里插入图片描述

COCO

在这里插入图片描述


class BasicRFB(nn.Module):

    def __init__(self, in_planes, out_planes, stride=1, scale = 0.1, visual = 1):
        super(BasicRFB, self).__init__()
        self.scale = scale
        self.out_channels = out_planes
        inter_planes = in_planes // 8
        self.branch0 = nn.Sequential(
                BasicConv(in_planes, 2*inter_planes, kernel_size=1, stride=stride),
                BasicConv(2*inter_planes, 2*inter_planes, kernel_size=3, stride=1, padding=visual, dilation=visual, relu=False)
                )
        self.branch1 = nn.Sequential(
                BasicConv(in_planes, inter_planes, kernel_size=1, stride=1),
                BasicConv(inter_planes, 2*inter_planes, kernel_size=(3,3), stride=stride, padding=(1,1)),
                BasicConv(2*inter_planes, 2*inter_planes, kernel_size=3, stride=1, padding=visual+1, dilation=visual+1, relu=False)
                )
        self.branch2 = nn.Sequential(
                BasicConv(in_planes, inter_planes, kernel_size=1, stride=1),
                BasicConv(inter_planes, (inter_planes//2)*3, kernel_size=3, stride=1, padding=1),
                BasicConv((inter_planes//2)*3, 2*inter_planes, kernel_size=3, stride=stride, padding=1),
                BasicConv(2*inter_planes, 2*inter_planes, kernel_size=3, stride=1, padding=2*visual+1, dilation=2*visual+1, relu=False)
                )

        self.ConvLinear = BasicConv(6*inter_planes, out_planes, kernel_size=1, stride=1, relu=False)
        self.shortcut = BasicConv(in_planes, out_planes, kernel_size=1, stride=stride, relu=False)
        self.relu = nn.ReLU(inplace=False)

    def forward(self,x):
        x0 = self.branch0(x)
        x1 = self.branch1(x)
        x2 = self.branch2(x)

        out = torch.cat((x0,x1,x2),1)
        out = self.ConvLinear(out)
        short = self.shortcut(x)
        out = out*self.scale + short
        out = self.relu(out)

        return out



class BasicRFB_a(nn.Module):

    def __init__(self, in_planes, out_planes, stride=1, scale = 0.1):
        super(BasicRFB_a, self).__init__()
        self.scale = scale
        self.out_channels = out_planes
        inter_planes = in_planes //4


        self.branch0 = nn.Sequential(
                BasicConv(in_planes, inter_planes, kernel_size=1, stride=1),
                BasicConv(inter_planes, inter_planes, kernel_size=3, stride=1, padding=1,relu=False)
                )
        self.branch1 = nn.Sequential(
                BasicConv(in_planes, inter_planes, kernel_size=1, stride=1),
                BasicConv(inter_planes, inter_planes, kernel_size=(3,1), stride=1, padding=(1,0)),
                BasicConv(inter_planes, inter_planes, kernel_size=3, stride=1, padding=3, dilation=3, relu=False)
                )
        self.branch2 = nn.Sequential(
                BasicConv(in_planes, inter_planes, kernel_size=1, stride=1),
                BasicConv(inter_planes, inter_planes, kernel_size=(1,3), stride=stride, padding=(0,1)),
                BasicConv(inter_planes, inter_planes, kernel_size=3, stride=1, padding=3, dilation=3, relu=False)
                )
        self.branch3 = nn.Sequential(
                BasicConv(in_planes, inter_planes//2, kernel_size=1, stride=1),
                BasicConv(inter_planes//2, (inter_planes//4)*3, kernel_size=(1,3), stride=1, padding=(0,1)),
                BasicConv((inter_planes//4)*3, inter_planes, kernel_size=(3,1), stride=stride, padding=(1,0)),
                BasicConv(inter_planes, inter_planes, kernel_size=3, stride=1, padding=5, dilation=5, relu=False)
                )

        self.ConvLinear = BasicConv(4*inter_planes, out_planes, kernel_size=1, stride=1, relu=False)
        self.shortcut = BasicConv(in_planes, out_planes, kernel_size=1, stride=stride, relu=False)
        self.relu = nn.ReLU(inplace=False)

    def forward(self,x):
        x0 = self.branch0(x)
        x1 = self.branch1(x)
        x2 = self.branch2(x)
        x3 = self.branch3(x)

        out = torch.cat((x0,x1,x2,x3),1)
        out = self.ConvLinear(out)
        short = self.shortcut(x)
        out = out*self.scale + short
        out = self.relu(out)

        return out

Liu, Songtao, and Di Huang. “Receptive field block net for accurate and fast object detection.” Proceedings of the European Conference on Computer Vision (ECCV). 2018.

;