GCNet

GCNet 论文详解

GCNet:Non-local Networks Meet Squeeze-Excitation Networks and Beyond,cvpr,2019.

链接:paper

代码:github

摘要

背景:Non-local Network 提供了一种捕获远程依赖关系的开创性方法,通过将特定于查询的全局上下文聚合得到每个查询位置。但是,本文发现,对于图中不同的查询位置,non-local network 网络建模的上下文信息几乎是相同的。

贡献:基于上述问题,文中建立了一个简化的基于查询无关的网络(snl),保持了NLNet的精度,大大减少了计算量。设计了一个轻量级GC block模块,和snet 都属于一种“三步骤”通用框架:1、全局上下文建模;2、channel-wise 依赖关系转换;3、特征融合。可以有效的建模全局上下文。可以将其应用于主干网络的多层中。

引言

​ 无论是non-local还是本文所提出的gcnet都属于"long-range dependency “。它们的目的都是尽可能从"global"的角度来理解图像。使用传统的卷积效率低,且很难达到这一点,因为一个卷积操作是对一个“local neighborhood "的pixel 关系进行建模。虽然可以通过不断的加深网络,来达到网络后半部分的神经元的感受野变大,达到一种不太”local“的效果,但这种粗暴的加深网络的做法:有三个缺点:(1)不够精巧,参数量计、算量大;(2)网络越深,优化难度越大;(3)不太”local"并不代表全局,有最大距离的限制。

对上面第三点的理解可以为:在网络的后半部分,feature map右下角的cell,感受野可能扩大了,但可能还是始终无法获得原图片上左上角的信息(因为卷积操作最大距离的限制)。与之对应的,一个理想的神经网络应该是:不要那么深,让用户优化的太困难;网络涉及的精巧一点,最好较少的参数量达到原始网络结构的性能;真正的做到全局,没有最大距离的限制。

为了解决这个问题,我们提出了non-local network,通过自我注意机制来建模远程依赖关系。对于每一个query position,计算该query position与图中其他点之间的关系来提取该点的特征。

然而,作者对non-local 的attention map进行可视化后发现不同的query point 对应的attention map 几乎是一样的。如下图所示:

img

基于此,文中提出了简化版的NL(SNL)。该简化模块的计算量明显少于NL。其准确率几乎没有下降。此外,我们发现这个简化块与SENet 网络具有相似的结构。它们都是通过从各个位置聚合的相同特征来强化原有特征,但在聚合策略、转化和强化功能上的选择又相互区别。通过对这些函数的抽象,我们得到了统一简化的NL块和SE块的三步通用框架:(a)上下文建模模块,它将所有位置的特征聚合在一起,形成全局上下文特征;(b)特征转换模块,以捕获渠道间的相互依赖;和©融合模块,将全局上下文特征合并为所有位置特征。简化的NL块和SE块是这个通用框架的两个实例。文中还提出了GC 模块,在上下文建模(使用全局注意力池)和融合(使用添加)步骤上,GC 模块与简化的NL块共享相同的实现,而与SE块共享相同的转换步骤(使用两层瓶颈)。GC块在多个视觉识别任务中的表现优于简化的NL块和SE块。

Method

1、Simplifying the Non-local Block

​ 既然attention map 与具体的点的位置无关,那就不要每一个点单独算一个attention map.用另外一种能过获取全局信息,但一个feature map 上的点可以共用attention 。基于此,我们简化了NL模块,提出了SNL模块,结构如下图(b):

img

Non-local 定义公式:

img

SNL定义公式:

img

一个直观的感觉是block结构确实简化了。在实际运算的变化中,可以看公式,公式中关键部分在于+号后面的变化。Non-local+号后面的内容与xi有关,因此每一个点i,需要计算一次。而snl的表达公式+号后面的内容已与xi无关,也即计算一次,然后大家公用,也映证了上文所讲的query-independent。

2、global context block

GCNet在上下文信息建模这个地方使用了Simplified NL block中的机制,可以充分利用全局上下文信息,同时在Transform阶段借鉴了SE block。

img

实验

Ablation

  • a. 看出Simplified NL与NL几乎一直,但是参数量要小一些。且每个阶段都使用GC block性能更好。
  • b. 在residual block中GC添加在add操作之后效果最好。
  • c. 添加在residual 的所有阶段效果最优,能比baseline高1-3%。
  • d. 使用简化版的NLNet并使用1×1卷积作为transform的时候效果最好,但是其计算量太大。
  • e. ratio=1/4的时候效果最好。
  • f. attention pooling+add的的组合用作池化和特征融合设计方法效果最好。

img

pytorch 代码

import torch
import torch.nn as nn
import torchvision
classs GlobalContextBlock(nn.Module):
    def __init__(slef,inplanes,ratio,pooling_type='att',fusion_types=('channel_add',)):
        super(GlobalContextBlock,self).__init__()
        assert pooling_type in ['avg', 'att']
        assert isinstance(fusion_types, (list, tuple))
        valid_fusion_types = ['channel_add', 'channel_mul']
        assert all([f in valid_fusion_types for f in fusion_types])
        assert len(fusion_types) > 0, 'at least one fusion should be used'
        self.inplanes = inplanes
        self.ratio = ratio
        self.planes = int(inplanes * ratio)
        self.pooling_type = pooling_type
        self.fusion_types = fusion_types
        if pooling_type == 'att':
            slef.conv_mask = nn.Conv2d(inplanes,1,kernel_size = 1)
            slef.softmax = nn.Softmax(dim=2)
         else:
            slef.avg_pool = self.avg_pool = nn.AdaptiveAvgPool2d(1)
          if 'channel_add' in fusion_types:
            self.channel_add_conv = nn.Sequential(
                nn.Conv2d(self.inplanes, self.planes, kernel_size=1),
                nn.LayerNorm([self.planes, 1, 1]),
                nn.ReLU(inplace=True),  # yapf: disable
                nn.Conv2d(self.planes, self.inplanes, kernel_size=1))
         else:
            self.channel_add_conv = None
         if 'channel_mul' in fusion_types:
            self.channel_mul_conv = nn.Sequential(
                nn.Conv2d(self.inplanes, self.planes, kernel_size=1),
                nn.LayerNorm([self.planes, 1, 1]),
                nn.ReLU(inplace=True),  # yapf: disable
                nn.Conv2d(self.planes, self.inplanes, kernel_size=1))
        else:
            self.channel_mul_conv = None
            
    def spatial_pool(self, x):
        batch, channel, height, width = x.size()
        if self.pooling_type == 'att':
            input_x = x
            # [N, C, H * W]
            input_x = input_x.view(batch, channel, height * width)
            # [N, 1, C, H * W]
            input_x = input_x.unsqueeze(1)
            # [N, 1, H, W]
            context_mask = self.conv_mask(x)
            # [N, 1, H * W]
            context_mask = context_mask.view(batch, 1, height * width)
            # [N, 1, H * W]
            context_mask = self.softmax(context_mask)
            # [N, 1, H * W, 1]
            context_mask = context_mask.unsqueeze(-1)
            # [N, 1, C, 1]
            context = torch.matmul(input_x, context_mask)
            # [N, C, 1, 1]
            context = context.view(batch, channel, 1, 1)
        else:
            # [N, C, 1, 1]
            context = self.avg_pool(x)

        return context

    def forward(self, x):
        # [N, C, 1, 1]
        context = self.spatial_pool(x)

        out = x
        if self.channel_mul_conv is not None:
            # [N, C, 1, 1]
            channel_mul_term = torch.sigmoid(self.channel_mul_conv(context))
            out = out * channel_mul_term
        if self.channel_add_conv is not None:
            # [N, C, 1, 1]
            channel_add_term = self.channel_add_conv(context)
            out = out + channel_add_term

        return out

### 优化 GCNet 模型的性能与结构改进方法 GCNet 是一种结合了非局部注意力机制和 SE Block 的全局上下文建模模块,其核心思想是通过动态调整注意力权重来增强网络对关键信息的关注。为了进一步提升 GCNet 的性能和结构效率,可以从以下几个方面进行优化和改进。 --- #### 1. **轻量化设计** 在保持性能的同时降低模型复杂度是提高推理效率的关键。 - **通道压缩与降维**:在 GC 块中引入更高效的通道压缩策略,例如使用深度可分离卷积或线性瓶颈结构减少计算量。 - **简化注意力机制**:可以借鉴 SENet 或 ECA-Net 的轻量级通道注意力机制,在保证全局建模能力的前提下降低参数量[^4]。 ```python # 示例:ECA 注意力机制简化实现 class ECAAttention(nn.Module): def __init__(self, kernel_size=3): super().__init__() self.avg_pool = nn.AdaptiveAvgPool2d(1) self.conv = nn.Conv1d(1, 1, kernel_size=kernel_size, padding=(kernel_size - 1) // 2, bias=False) self.sigmoid = nn.Sigmoid() def forward(self, x): y = self.avg_pool(x) y = self.conv(y.squeeze(-1).transpose(-1, -2)).transpose(-1, -2).unsqueeze(-1) return x * self.sigmoid(y) ``` --- #### 2. **多尺度融合与上下文建模** 增强模型对多尺度特征的感知能力,有助于提升检测、分割等任务的精度。 - **多尺度 GC 模块集成**:在不同层级(如 c3、c4、c5)中分别引入具有不同感受野的 GC 模块,以捕捉多层次语义信息。 - **结合非局部操作与空洞卷积**:将 GCNet 中的注意力机制与空洞卷积相结合,扩大有效感受野而不增加下采样次数[^2]。 --- #### 3. **结构重排与模块化重构** 通过重新设计模块结构提升训练稳定性与泛化能力。 - **采用 Bottleneck 结构优化 GC 模块**:将 GC 模块嵌入 ResNet 的 Bottleneck 中,并调整其插入位置(如 stage3-stage5),可显著提升性能[^4]。 - **引入残差连接与归一化层**:确保 GC 模块内部具备良好的梯度流动,推荐使用 LayerNorm 或 BatchNorm 配合残差连接[^1]。 ```python # 示例:带残差连接的 GC 模块 class ResidualGCBlock(nn.Module): def __init__(self, in_channels): super().__init__() self.gc = GlobalContextBlock(in_channels) self.norm = nn.BatchNorm2d(in_channels) self.relu = nn.ReLU(inplace=True) def forward(self, x): residual = x x = self.gc(x) x += residual x = self.norm(x) return self.relu(x) ``` --- #### 4. **训练策略优化** 合理的训练策略可以显著提升最终性能。 - **学习率调度与数据增强**:使用 Cosine Annealing 或 StepLR 调整学习率,并结合 CutMix、Mosaic 等高级数据增强技术提升泛化能力。 - **知识蒸馏**:使用更大模型(如 ResNeXt-101)作为教师模型,指导小模型训练,从而提升其性能而无需增加推理开销[^2]。 --- #### 5. **结合可变形卷积与级联策略** 针对目标检测等任务,可以通过以下方式增强特征提取能力: - **添加可变形卷积模块**:在 GCNet 的骨干网络中引入 DCN(Deformable Convolution Network),使其适应目标形状变化。 - **级联检测头设计**:采用 Cascade R-CNN 思路,在多个阶段逐步优化检测结果,提升 AP 指标[^2]。 --- #### 6. **部署优化与硬件加速** 为实际部署场景考虑,还需对模型进行工程层面的优化。 - **量化与剪枝**:对训练完成的 GCNet 模型进行通道剪枝或权重量化,减小模型体积并提升推理速度。 - **ONNX 导出与推理引擎适配**:将模型导出为 ONNX 格式,并使用 TensorRT、OpenVINO 等推理引擎进行加速部署。 --- ###
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值