《Strip Pooling: Rethinking Spatial Pooling for Scene Parsing》论文笔记

文章地址https://arxiv.org/pdf/2003.13328v1.pdf
源码地址https://github.com/Andrew-Qibin/SPNet

问题的引出

在某些情况下,目标对象可能具有远距离的带状结构或离散分布(如下图所示)。 使用方形不能很好地解决问题,因为它不可避免地会合并来自无关区域的信息。普通的空间池化,不可避免的会加入一些无关紧要的像素区域。尤其是在利用池化扩大感受野时,这一缺点将更加明显。所以作者提出了 条纹池化。

在这里插入图片描述
在本文中,为了更有效地捕获远程依赖关系,进一步研究使用池化来扩大CNN的接收域并收集信息上下文,并提出了条形池化的概念。 作为全局池的替代方法,条形池化具有两个优点。 首先,它沿一个空间维度部署了长条的核,因此可以捕获孤立区域的长期关系。 其次,它沿其他空间维保持窄的内核形状,这有助于捕获本地上下文并防止无关区域干扰标签预测。 集成了如此长而狭窄的内核,使得场景解析网络可以同时聚合全局和局部上下文。 这与传统的从固定的正方形区域收集上下文的池化本质上是不同的。
基于条形池化操作,我们提出了两个场景解析网络模块。 首先,文中设计一个条形池化模块(SPM),以有效地扩大主干的接收范围。其次,文中提出了一种新颖的附加残差构建模块,称为混合池化模块(MPM),以进一步在高语义级别上对远程依赖性进行建模。

方法

为了更有效地捕获长依赖关系,本文在空间池化层扩大卷积神经网络感受野和捕获上下文信息的基础上,提出了条形池化(strip pooling)的概念。条形池有两个优点:
1、它沿一个空间维度部署一个长条的池化形状,能够捕获孤立区域的远程关系。
2、它沿其他空间维度保持一个狭窄的池化形状,有利于捕获上下文,并防止无关区域的污染信息干扰预测。
这种条形池化可以使语义分割网络能够同时聚合全局和局部上下文信息。

在这里插入图片描述
令输出张量x∈RCxHxW,C为通道数量,首先将x输入两个平行的路径,每个路径包含一个水平或垂直的条形池化层,然后是一维卷积层,其内核大小为3,用于整合当前位置及其相邻特征。这部分给出了yh∈RCxH和了yv∈RCxW,为了获得含有更多全局先验信息的输出z∈RCxWxH,首先通过下式获得y∈RCxHxW:
在这里插入图片描述
然后输出z由下式计算:
在这里插入图片描述

其中Scale(,)表示逐元素乘法,σ表示sigmoid函数,f是1*1卷积。应当注意,存在多种方式来组合由两个条形池化层提取的特征,例如计算两个提取的一维特征向量之间的内积。 但是,考虑到效率,我们采用了上述操作。
在以上过程中,输出张量中的每个位置允许建立与输入张量中其他位置的关系。例如,上图,输出张量中黑框的位置与和其有相同水平和垂直位置的点(用红色和紫色框围起来)构建连接。通过重复上述过程多次,可以在整个场景上建立远程依赖关系。 此外,得益于基本的乘法运算,建议的SPM还可以被视为一种注意力机制,并且可以直接应用于任何经过预训练的骨干网,而无需从头开始进行训练。

Mixed Pooling Module(MPM)

在这里插入图片描述

Code

class StripPooling(nn.Module):
    """
    Reference:
    """
    def __init__(self, in_channels, pool_size, norm_layer, up_kwargs):
        super(StripPooling, self).__init__()
        self.pool1 = nn.AdaptiveAvgPool2d(pool_size[0])
        self.pool2 = nn.AdaptiveAvgPool2d(pool_size[1])
        self.pool3 = nn.AdaptiveAvgPool2d((1, None))
        self.pool4 = nn.AdaptiveAvgPool2d((None, 1))

        inter_channels = int(in_channels/4)
        self.conv1_1 = nn.Sequential(nn.Conv2d(in_channels, inter_channels, 1, bias=False),
                                norm_layer(inter_channels),
                                nn.ReLU(True))
        self.conv1_2 = nn.Sequential(nn.Conv2d(in_channels, inter_channels, 1, bias=False),
                                norm_layer(inter_channels),
                                nn.ReLU(True))
        self.conv2_0 = nn.Sequential(nn.Conv2d(inter_channels, inter_channels, 3, 1, 1, bias=False),
                                norm_layer(inter_channels))
        self.conv2_1 = nn.Sequential(nn.Conv2d(inter_channels, inter_channels, 3, 1, 1, bias=False),
                                norm_layer(inter_channels))
        self.conv2_2 = nn.Sequential(nn.Conv2d(inter_channels, inter_channels, 3, 1, 1, bias=False),
                                norm_layer(inter_channels))
        self.conv2_3 = nn.Sequential(nn.Conv2d(inter_channels, inter_channels, (1, 3), 1, (0, 1), bias=False),
                                norm_layer(inter_channels))
        self.conv2_4 = nn.Sequential(nn.Conv2d(inter_channels, inter_channels, (3, 1), 1, (1, 0), bias=False),
                                norm_layer(inter_channels))
        self.conv2_5 = nn.Sequential(nn.Conv2d(inter_channels, inter_channels, 3, 1, 1, bias=False),
                                norm_layer(inter_channels),
                                nn.ReLU(True))
        self.conv2_6 = nn.Sequential(nn.Conv2d(inter_channels, inter_channels, 3, 1, 1, bias=False),
                                norm_layer(inter_channels),
                                nn.ReLU(True))
        self.conv3 = nn.Sequential(nn.Conv2d(inter_channels*2, in_channels, 1, bias=False),
                                norm_layer(in_channels))
        # bilinear interpolate options
        self._up_kwargs = up_kwargs

    def forward(self, x):
        _, _, h, w = x.size()
        x1 = self.conv1_1(x)
        x2 = self.conv1_2(x)
        x2_1 = self.conv2_0(x1)
        x2_2 = F.interpolate(self.conv2_1(self.pool1(x1)), (h, w), **self._up_kwargs)
        x2_3 = F.interpolate(self.conv2_2(self.pool2(x1)), (h, w), **self._up_kwargs)
        x2_4 = F.interpolate(self.conv2_3(self.pool3(x2)), (h, w), **self._up_kwargs)
        x2_5 = F.interpolate(self.conv2_4(self.pool4(x2)), (h, w), **self._up_kwargs)
        x1 = self.conv2_5(F.relu_(x2_1 + x2_2 + x2_3))
        x2 = self.conv2_6(F.relu_(x2_5 + x2_4))
        out = self.conv3(torch.cat([x1, x2], dim=1))
        return F.relu_(x + out)

数据集评估

在Cityscapes数据集上的评估:
在这里插入图片描述

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

CV无名之辈

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值