Backbone 之 DetNet:为检测而生(Pytorch实现及代码解析)

 背景:

前面几节的网络骨架,如VGGNet和ResNet等,虽从各个角度出发提升了物体检测性能,但究其根本是为ImageNet的图像分类任务而设计的。而图像分类与物体检测两个任务天然存在着落差,分类任务侧重于全图的特征提取深层的特征图分辨率很低而物体检测需要定位出物体位置,特征图分辨率不宜过小,因此造成了以下两种缺陷:

  • 大物体难以定位对于FPN等网络,大物体对应在较深的特征图上检测,由于网络较深时下采样率较大,物体的边缘难以精确预测,增加了回归边界的难度。

  • 小物体难以检测对于传统网络,由于下采样率大造成小物体在较深的特征图上几乎不可见;FPN虽从较浅的特征图来检测小物体,但浅层的语义信息较弱,且融合深层特征时使用的上采样操作也会增加物体检测的难度。

DetNet应运而生:

针对以上问题,旷视科技提出了专为物体检测设计的DetNet结构,引入了空洞卷积使得模型兼具较大感受野与较高分辨率,同时避免了3.6节中FPN的多次上采样,实现了较好的检测效果。

了解网络结构之前有必要了解以下空洞卷积:

DetNet的网络结构:

img

如图所示,仍然选择性能优越的ResNet-50作为基础结构,并保持前4个stage与ResNet-50相同,具体的结构细节有以下3点:

  • 引入了一个新的Stage 6,用于物体检测Stage 5与Stage 6使用了DetNet提出的Bottleneck结构,最大的特点是利用空洞数为2的3×3卷积取代了步长为2的3×3卷积。(具体什么是空洞卷积见上)

  • Stage 5与Stage 6的每一个Bottleneck输出的特征图尺寸都为原图的,通道数都为256,而传统的Backbone通常是特征图尺寸递减,通道数递增。

  • 在组成特征金字塔时,由于特征图大小完全相同,因此可以直接从右向左传递相加避免了上一节的上采样操作为了进一步融合各通道的特征,需要对每一个阶段的输出进行1×1卷积后再与后一Stage传回的特征相加。

DetNet这种精心设计的结构作用:

  • 在增加感受野的同时,获得了较大的特征图尺寸,有利于物体的定位。

  • 与此同时,由于各Stage的特征图尺寸相同,避免了上一节的上采样,既一定程度上降低了计算量,又有利于小物体的检测。

DetNet网络结构与残差ResNet网络结果对比:

img

这样设计的区别及作用:本图中左侧的两个Bottleneck ABottleneck B分别对应DetNet网络结构图中的A与B,右侧的为原始的ResNet残差结构。DetNet与ResNet两者的基本思想都是卷积堆叠层与恒等映射的相加,区别在于DetNet使用了空洞数为2的3×3卷积,这样使得特征图尺寸保持不变,而ResNet是使用了步长为2的3×3卷积。B相比于A,在恒等映射部分增加了一个1×1卷积,这样做可以区分开不同的Stage,并且实验发现这种做法对于特征金字塔式的检测非常重要。

具体代码如下

from torch import nn
​
###这个类只是表示的DetNet的小砖块的定义
class DetBottleneck(nn.Module):
###初始化参数extra为False时,代表BottleneckA,反之代表BottleneckB
    def __init__(self, inplanes, planes, stride=1, extra=False):
        super(DetBottleneck, self).__init__()
        ###构造连续3*3个卷积层的Bottleneck
        self.bottleneck = nn.Sequential(
                nn.Conv2d(inplanes, planes, 1, bias=False), 
                nn.BatchNorm2d(planes),
                nn.ReLU(inplace=True),
            ##表示空洞数为2的空洞卷积,dilation表示空洞数
                nn.Conv2d(planes, planes, kernel_size=3, stride=1, padding=2, 
                               dilation=2, bias=False),
                nn.BatchNorm2d(planes),
                nn.ReLU(inplace=True),
                nn.Conv2d(planes, planes, 1, bias=False),
                nn.BatchNorm2d(planes),
        )
        self.relu = nn.ReLU(inplace=True)
        self.extra = extra
        if self.extra:
            ###表示Bottleneck B的1*1卷积
            self.extra_conv = nn.Sequential(
                nn.Conv2d(inplanes, planes, 1, bias=False),
                nn.BatchNorm2d(planes)
            )
​
    def forward(self, x):
        if self.extra:
            ###对于Bottleneck B来讲,粗腰对恒等变换增加额外卷积操作,此处与ResNet类似
            identity = self.extra_conv(x)
        else:
            identity = x
        out = self.bottleneck(x)
        out += identity
        out = self.relu(out)
        return out
​
​

点个赞再走呗!!

熊猫头嘻嘻嘻(拖头)_拖头_熊猫_嘻嘻表情

 

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
THE END
分享
二维码
< <上一篇

)">
下一篇>>