三、FPN论文总结

三、FPN论文总结

论文导读

主要作用:对金字塔特征的网络集成;用于解决小目标问题;

意义:结合了浅层的高分辨率和深层的丰富语义,FPN不是独立的目标检测算法,而是一个backbone;

论文概要

摘要

1、特征金字塔是识别不同大小物体的基本组成部分;

2、我们利用深度卷积网络固有的多尺度金字塔层次结构来构建特征金字塔;

3、开发了具有横向连接的自上而下的体系结构,以构建各种规模的高级语义特征图;

4、该方法可以在GPU上以6FPS的速度运行,是一种实用且准确的多尺度目标检测解 决方案;

设计理念

FPN包含两个部分:第一部分是自底向上的过程,第二部分是自顶向下和侧向连接的融合过程;

在这里插入图片描述

自底向上:就是一系列的卷积操作;

自顶向下:通过上采样的方式将顶层的小特征图放大到上一个stage的特征图一样的大小,即利用了顶层较强的语义信息(利于分类),有利用了底层的高分辨率信息(利于定位);

具体实现如下图所示:

在这里插入图片描述

从上图可知,FPN用到了ResNet中的跳连结构,为了保证通道数一致,使用1x1卷积进行升/降维;

上采样方法采用的是简单的最近邻插值

使用场景

1、最适合小目标的检测;

2、不适用于行人检测等浅层表征能力较差的任务;(大目标)

论文总结

关键点

1、金字塔特征;

2、自底向上,自顶向下;

3、在Fast RCNN中的应用;

创新点

1、利用浅层的高分辨率;

2、兼顾顶层的语义信息;

3、适合小目标检测;

论文代码

class FPN(nn.Module):
    def __init__(self, block, num_blocks):
        super(FPN, self).__init__()
        self.in_planes = 64
        
        # 第一层的conv的结果并不会作为一个多尺度特征输出,对文中的解释是`due to its large memory footprint`
        # 此时的channel数为64
        self.conv1 = nn.Conv2d(3, 64, kernel_size=7, stride=2, padding=3, bias=False)
        self.bn1 = nn.BatchNorm2d(64)

        # Bottom-up layers
        # 以下建立的每一层在文中分别对应conv2,conv3,conv4,conv5
        # Bottom-up layers 其中的64,128,256,512代表BottleNeck瓶颈的channel数,每一个layer的输出为瓶颈channel数的4倍
        self.layer1 = self._make_layer(block,  64, num_blocks[0], stride=1)
        self.layer2 = self._make_layer(block, 128, num_blocks[1], stride=2)
        self.layer3 = self._make_layer(block, 256, num_blocks[2], stride=2)
        self.layer4 = self._make_layer(block, 512, num_blocks[3], stride=2)

        # Top layer
        # 用于conv5,因为没有更上一层的特征了
        self.toplayer = nn.Conv2d(2048, 256, kernel_size=1, stride=1, padding=0)  # Reduce channels

        # Smooth layers
        # 分别用于conv4,conv3,conv2(按顺序)
        self.smooth1 = nn.Conv2d(256, 256, kernel_size=3, stride=1, padding=1)
        self.smooth2 = nn.Conv2d(256, 256, kernel_size=3, stride=1, padding=1)
        self.smooth3 = nn.Conv2d(256, 256, kernel_size=3, stride=1, padding=1)

        # Lateral layers
        # 分别用于conv4,conv3,conv2(按顺序)
        self.latlayer1 = nn.Conv2d(1024, 256, kernel_size=1, stride=1, padding=0)
        self.latlayer2 = nn.Conv2d( 512, 256, kernel_size=1, stride=1, padding=0)
        self.latlayer3 = nn.Conv2d( 256, 256, kernel_size=1, stride=1, padding=0)

    def _make_layer(self, block, planes, num_blocks, stride):
        strides = [stride] + [1]*(num_blocks-1)
        layers = []
        for stride in strides:
            layers.append(block(self.in_planes, planes, stride))
            self.in_planes = planes * block.expansion  # planes是瓶颈的大小,每次输出都是瓶颈大小的四倍
        return nn.Sequential(*layers)

    def _upsample_add(self, x, y):
        _,_,H,W = y.size()
        return F.upsample(x, size=(H,W), mode='bilinear') + y

    def forward(self, x):
        # Bottom-up
        # 对应图中左边一列
        c1 = F.relu(self.bn1(self.conv1(x)))
        c1 = F.max_pool2d(c1, kernel_size=3, stride=2, padding=1)
        c2 = self.layer1(c1)
        c3 = self.layer2(c2)
        c4 = self.layer3(c3)
        c5 = self.layer4(c4)
        # Top-down
        # 对应图中中间一列
        p5 = self.toplayer(c5)
        p4 = self._upsample_add(p5, self.latlayer1(c4))
        p3 = self._upsample_add(p4, self.latlayer2(c3))
        p2 = self._upsample_add(p3, self.latlayer3(c2))
        # Smooth
        # 对应图中右边一列
        p4 = self.smooth1(p4)
        p3 = self.smooth2(p3)
        p2 = self.smooth3(p2)
        return p2, p3, p4, p5
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值