维度-空间注意力总结

近年来,注意力机制一直受到大家的追捧,本文总结下几篇显著性检测中的维度-空间注意力机制。

BAM

图1. BAM的整体框架图
图1. BAM的整体框架图
如图1所示,BAM分为并行的两部分:Channel Attention和Spatial Attention,Channel Attention包括一个Global avg pool(全局平均池化)和一个带隐藏层的多次感知器(MLP),为了节省开销、减小参数量,隐藏层的系数r被设置为维度C除以16,在MLP之后使用BN层来调整输出的尺度;Spatial Attention首先经过一个11卷积整合和压缩输入维度信息,然后是两个33的卷积操作来有效的获取上下文信息,最后使用1*1卷积将维度重新变为初始输入维度,同样使用BN层来收尾。经过验证,使用逐元素相加然后经过sigmoid函数最后加上原来的输入,一个并行的维度-空间注意力就完成了。代码如下:

class ChannelGate(nn.Module):
    def __init__(self, gate_channel, reduction_ratio=16, num_layers=1):
        super(ChannelGate, self).__init__()
        # self.gate_activation = gate_activation
        self.gate_c = nn.Sequential()
        self.gate_c.add_module('flatten', Flatten())
        gate_channels = [gate_channel]
        gate_channels += [gate_channel // reduction_ratio] * num_layers
        gate_channels += [gate_channel]
        for i in range(len(gate_channels) - 2):
            self.gate_c.add_module('gate_c_fc_%d' % i, nn.Linear(gate_channels[i], gate_channels[i + 1]))
            self.gate_c.add_module('gate_c_bn_%d' % (i + 1), nn.BatchNorm1d(gate_channels[i + 1]))
            self.gate_c.add_module('gate_c_relu_%d' % (i + 1), nn.ReLU())
        self.gate_c.add_module('gate_c_fc_final', nn.Linear(gate_channels[-2], gate_channels[-1]))

    def forward(self, in_tensor):
        avg_pool = F.avg_pool2d(in_tensor, in_tensor.size(2), stride=in_tensor.size(2))
        return self.gate_c(avg_pool).unsqueeze(2).unsqueeze(3).expand_as(in_tensor)
class SpatialGate(nn.Module):
    def __init__(self, gate_channel, reduction_ratio=16, dilation_conv_num=2, dilation_val=4):
        super(SpatialGate, self).__init__()
        self.gate_s = nn.Sequential()
        self.gate_s.add_module('gate_s_conv_reduce0',
                               nn.Conv2d(gate_channel, gate_channel // reduction_ratio, kernel_size=1))
        self.gate_s.add_module('gate_s_bn_reduce0', nn.BatchNorm2d(gate_channel // reduction_ratio))
        self.gate_s.add_module('gate_s_relu_reduce0', nn.ReLU())
        for i in range(dilation_conv_num):
            self.gate_s.add_module('gate_s_conv_di_%d' % i,
                                   nn.Conv2d(gate_channel // reduction_ratio, gate_channel // reduction_ratio,
                                             kernel_size=3, \
                                             padding=dilation_val, dilation=dilation_val))
            self.gate_s.add_module('gate_s_bn_di_%d' % i, nn.BatchNorm2d(gate_channel // reduction_ratio))
            self.gate_s.add_module('gate_s_relu_di_%d' % i, nn.ReLU())
        self.gate_s.add_module('gate_s_conv_final', nn.Conv2d(gate_channel // reduction_ratio, 1, kernel_size=1))

    def forward(self, in_tensor):
        return self.gate_s(in_tensor).expand_as(in_tensor)

CBAM

	图2. CBAM的整体架构
图2. CBAM的整体架构
图3. Channel Attention和Spatial Attention的细节图
图3. Channel Attention和Spatial Attention的细节图
和BAM不同的是,它采用串联的维度-空间注意力架构,而不是并行的。对Channel Attention而言,它首先经过一个并行的MaxPool和AVGPool,将结果通过一个共享的MLP模块,MLP模块同样有一个隐藏层,为了减少参数量,使用C/16来作为隐藏层的系数,然后将两个输出先相加,再进行sigmoid操作,输出经过维度注意力模块后的结果;空间注意力模块则是先沿着通道的轴分别应用最大值和平均值操作对每行取最大值、平均值,将结果进行卷积操作(卷积核大小为7),对结果进行sigmoid操作就得到了空间注意力处理后的结果。

BBS_Net

图4. DEM模块的架构图
图4. DEM模块的架构图
可以看到BBSNet的维度-空间注意力模块和CBAM模块一样都是采用串联的方式,对于Channel Attention:首先经过自适应最大池化操作,然后经过和CBAM相同的1*1卷积操作,系数同样被设置为C/16,最后经过sigmoid函数;Spatial Attention则是根据padding的不同,将卷积核大小分别设为3或7,这不同于CBAM中的固定以7为卷积核大小的方法,然后经过BatchNorm2d进行归一化操作得到空间注意力处理后的结果。代码如下:

class ChannelAttention(nn.Module):
    def __init__(self, in_planes, ratio=16):
        super(ChannelAttention, self).__init__()

        self.max_pool = nn.AdaptiveMaxPool2d(1)

        self.fc1 = nn.Conv2d(in_planes, in_planes // 16, 1, bias=False)
        self.relu1 = nn.ReLU()
        self.fc2 = nn.Conv2d(in_planes // 16, in_planes, 1, bias=False)

        self.sigmoid = nn.Sigmoid()

    def forward(self, x):
        max_out = self.fc2(self.relu1(self.fc1(self.max_pool(x))))
        out = max_out
        return self.sigmoid(out)```

class SpatialAttention(nn.Module):
def init(self, kernel_size=7):
super(SpatialAttention, self).init()

    assert kernel_size in (3, 7), 'kernel size must be 3 or 7'
    padding = 3 if kernel_size == 7 else 1

    self.conv1 = nn.Conv2d(1, 1, kernel_size, padding=padding, bias=False)
    self.sigmoid = nn.Sigmoid()

def forward(self, x):
    # 对每行取最大值,舍弃了CBAM中的平均值
    max_out, _ = torch.max(x, dim=1, keepdim=True)
    x = max_out
    x = self.conv1(x)
    return self.sigmoid(x)

``

Depth-induced Multi-scale Recurrent Attention Network for Saliency Detection

图5. DMRANet的分支:DMSW和RAM的细节
图5. DMRANet的分支:DMSW和RAM的细节
DMRA的维度注意力和LSTM结合在了一起,对于维度注意力:先经过卷积操作,然后和经过LSTM处理后的结果加在一起,再经过平均池化操作,然后按行进行softmax操作。对于空间注意力:首先进行两次卷积操作,对第二次卷积操作后的结果求sigmoid,然后和第一次的卷积结果逐行相乘(torch.mul),最终得到经过注意力机制后的结果。代码如下:

depth = self.conv_c(F_sum)
            h_c = self.conv_h(h_step)
            depth = depth + h_c
            depth = self.pool_avg(depth)
            # 按照每一行进行soft归一化
            depth = torch.mul(F.softmax(depth, dim=1), 64)
            F_sum_wt = torch.mul(depth_fw_ori, depth)

Is depth really necessary for salient object detection

图6. DASNet的维度注意力框架图
图6. DASNet的维度注意力框架图
它的维度注意力首先都输入的RGB、深度特征图做卷积+BN+ReLU的操作,然后元素相乘,再将相乘后的结果和原输入进行cat,然后进行全局平均池化操作,再卷积,通过sigmoid函数后和经过cat后的结果元素相乘,把原始的RGB和深度特征图和元素相乘后的结果分别元素相加,最后把元素相加后的结果进行cat,形成最终的输出。未提供源码

Select, supplement and focus for RGB-D saliency detection

在这里插入图片描述
图7. SSF的CAU和BSU的框架图
它的Attention模块很简单:首先是一个自适应平均池化操作、然后是两个隐藏层、加上ReLU和sigmoid操作,然后和自适应平均池化后的结果元素相乘,注意力模块就结束了。代码如下:

class AttentionLayer(nn.Module):
    def __init__(self, channel, reduction=2, multiply=True):
        super(AttentionLayer, self).__init__()
        self.avg_pool = nn.AdaptiveAvgPool2d(1)
        self.fc = nn.Sequential(
            nn.Linear(channel, channel // reduction),
            nn.ReLU(inplace=True),
            nn.Linear(channel // reduction, channel),
            nn.Sigmoid()
        )
        self.multiply = multiply

    def forward(self, x):
        b, c, _, _ = x.size()
        y = self.avg_pool(x).view(b, c)
        y = self.fc(y).view(b, c, 1, 1)
        if self.multiply == True:
            return x * y
        else:
            return y
<think>好的,我现在要帮助用户了解或实现通道-空间双路径注意力机制。首先,我需要回顾一下用户提供的引用资料,看看里面有没有相关的信息。用户提到了引用[1]、[3]、[4],这些内容都涉及计算机视觉中的注意力机制,特别是CBAM模块。 用户的问题是关于通道-空间双重注意力机制的实现方法或代码示例。根据引用[4]提到,CBAM模块通过分别处理通道和空间注意力来实现,这可能就是用户所说的双路径机制。我需要确认CBAM的结构是否属于这种双路径设计,然后给出对应的实现步骤和代码。 首先,我应该解释通道注意力空间注意力的基本概念。通道注意力关注哪些通道更重要,通常使用全局平均池化和全连接层来生成权重。空间注意力则关注图像中的哪些位置更重要,通常结合通道信息并通过卷积层生成空间权重。 接下来,我需要参考引用[4]中提到的CBAM模块的结构。CBAM依次应用通道注意力空间注意力模块,将两个模块级联起来。这符合双路径机制的设计,因此可以以CBAM为例来展示实现方法。 然后,我需要考虑如何用代码实现这两个模块。对于通道注意力,通常使用全局平均池化和最大池化,然后将结果输入共享的多层感知机(MLC),最后通过sigmoid生成权重。对于空间注意力,则合并通道维度的信息,使用卷积层生成空间权重。 在编写代码时,需要注意模块的顺序,先通道后空间,或者反过来?根据引用[4],CBAM是先通道再空间。所以代码中的顺序应该是通道注意力模块在前,空间在后。 需要检查PyTorch中的相关函数,如nn.Conv2d、nn.Sigmoid、nn.Sequential等,确保语法正确。同时,要注意张量的维度变换,比如在通道注意力中,将池化后的结果相加后通过sigmoid,再与输入相乘。 此外,用户可能希望了解如何集成到现有网络中,比如ResNet。因此,给出一个简单的示例说明如何在卷积层后添加CBAM模块会更有帮助。 最后,需要验证代码的正确性,比如输入输出的形状是否一致,权重是否正确地应用到了特征图上。同时,根据引用[3]中的综述,可以推荐用户进一步阅读相关论文或代码库,如引用[2]中的GitHub链接,以获取更多实现细节。 总结步骤:解释通道和空间注意力的原理,展示CBAM的结构,提供PyTorch代码示例,说明集成方法,并推荐相关资源。同时,生成相关问题引导用户深入学习。</think>以下为通道-空间双重注意力机制的实现详解: ### 一、通道-空间双路径注意力机制原理 通道-空间双重注意力机制通过独立分析特征图的通道维度空间维度重要性,实现精细化特征选择。其核心思想是: 1. **通道注意力**:识别不同通道的特征重要性,抑制噪声通道 $$M_c = \sigma(MLC(AvgPool(F)) + MLC(MaxPool(F)))$$[^4] 2. **空间注意力**:定位特征图中的关键区域 $$M_s = \sigma(f^{7×7}([AvgPool(F); MaxPool(F)]))$$ ### 二、PyTorch实现代码 ```python import torch import torch.nn as nn class CBAM(nn.Module): def __init__(self, channels, reduction_ratio=16): super().__init__() # 通道注意力模块 self.channel_attention = nn.Sequential( nn.AdaptiveAvgPool2d(1), nn.Conv2d(channels, channels//reduction_ratio, 1), nn.ReLU(), nn.Conv2d(channels//reduction_ratio, channels, 1), nn.Sigmoid() ) # 空间注意力模块 self.spatial_attention = nn.Sequential( nn.Conv2d(2, 1, 7, padding=3), nn.Sigmoid() ) def forward(self, x): # 通道注意力 ca = self.channel_attention(x) x = x * ca # 空间注意力 max_pool = torch.max(x, dim=1, keepdim=True)[0] avg_pool = torch.mean(x, dim=1, keepdim=True) sa_input = torch.cat([max_pool, avg_pool], dim=1) sa = self.spatial_attention(sa_input) return x * sa ``` ### 三、实现要点解析 1. **通道注意力**: - 使用全局平均池化和最大池化捕获通道统计特征 - 通过瓶颈结构(reduction_ratio=16)减少参数计算量 - Sigmoid输出0-1的权重系数 2. **空间注意力**: - 沿通道维度进行最大/平均池化,保留空间信息 - 使用7×7卷积捕获局部空间关系 - 最终生成空间权重图 3. **级联顺序**:实验表明先通道后空间效果更优 ### 四、集成到CNN的示例 ```python class ResBlockWithCBAM(nn.Module): def __init__(self, in_channels): super().__init__() self.conv = nn.Sequential( nn.Conv2d(in_channels, in_channels, 3, padding=1), nn.BatchNorm2d(in_channels), nn.ReLU(), CBAM(in_channels), # 插入CBAM模块 nn.Conv2d(in_channels, in_channels, 3, padding=1), nn.BatchNorm2d(in_channels) ) self.relu = nn.ReLU() def forward(self, x): residual = x x = self.conv(x) x += residual return self.relu(x) ``` ### 五、训练建议 1. 初始学习率降低为基准模型的1/5 2. 在ImageNet上训练时建议reduction_ratio=16 3. 可配合SE、Non-local等模块组合使用[^3]
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值