引用:Woo S, Park J, Lee J Y, et al. Cbam: Convolutional block attention module[C]//Proceedings of the European conference on computer vision (ECCV). 2018: 3-19.
论文题目:CBAM: Convolutional Block Attention Module
论文链接:下载地址(不用看)
论文代码:下载地址(不用看)
直接Copy!! 试
1、作用
是为了提升前馈卷积神经网络性能而提出的一种简单而有效的注意力模块。CBAM通过顺序地推断两个维度上的注意力图(通道和空间),然后将这些注意力图乘以输入特征图进行自适应特征精炼。
2、机制
1、通道注意力模块(Channel Attention Module):
通过利用特征之间的通道关系来生成通道注意力图。每个通道的特征图被视为一个特征探测器,通道注意力关注于给定输入图像中“什么”是有意义的。为了有效地计算通道注意力,CBAM首先对输入特征图的空间维度进行压缩,同时使用平均池化和最大池化操作来捕获不同的空间上下文描述符,这些被送入共享的多层感知机(MLP)以产生通道注意力图。
2、空间注意力模块(Spatial Attention Module):
利用特征之间的空间关系来生成空间注意力图。与通道注意力不同,空间注意力关注于“在哪里”是一个有信息的部分,这与通道注意力是互补的。为了计算空间注意力,CBAM首先沿着通道轴应用平均池化和最大池化操作,然后将它们连接起来生成一个高效的特征描述符。在该描述符上应用一个卷积层来生成空间注意力图。
3、独特优势
1、双重注意力机制:
CBAM首次将通道注意力(Channel Attention)和空间注意力(Spatial Attention)顺序结合起来,对输入特征进行两阶段的精炼。这种设计让模型先关注于“哪些通道是重要的”,然后再关注于“空间上哪些位置是重要的”,从而更加全面地捕获特征中的关键信息。
2、自适应特征重标定:
通过通道注意力和空间注意力的逐步应用,CBAM能够自适应地调整输入特征图中每个通道和空间位置的重要性。这种自适应重标定机制允许模型根据任务需求和内容上下文动态地关注于最有用的特征,从而提高模型的表征能力和决策准确性。
3、灵活性和通用性:
CBAM模块设计简洁,可轻松集成到各种现有的CNN架构中,如ResNet、Inception等,而不需要对原始架构进行大的修改。这种灵活性和通用性使CBAM成为一种有效的插件,可以广泛应用于各种视觉识别任务,包括图像分类、目标检测和语义分割等。
4、计算效率高:
尽管CBAM为模型引入了额外的计算,但其设计考虑了计算效率,如通过全局平均池化和最大池化来简化通道注意力的计算,通过简单的卷积操作来实现空间注意力。这些设计使得CBAM能够在带来性能提升的同时,保持较低的额外计算成本。
5、逐步精炼策略:
CBAM中通道和空间注意力的顺序应用,形成了一种逐步精炼输入特征的策略。这种从通道到空间的逐步细化过程,有助于模型更有效地利用注意力机制,逐渐提取并强调更加有意义的特征,而不是一次性地处理所有信息。
4、代码
import torch
from torch import nn
# 通道注意力模块
class ChannelAttention(nn.Module):
def __init__(self, in_planes, ratio=16):
super(ChannelAttention, self).__init__()
self.avg_pool = nn.AdaptiveAvgPool2d(1) # 自适应平均池化
self.max_pool = nn.AdaptiveMaxPool2d(1) # 自适应最大池化
# 两个卷积层用于从池化后的特征中学习注意力权重
self.fc1 = nn.Conv2d(in_planes, in_planes // ratio, 1, bias=False) # 第一个卷积层,降维
self.relu1 = nn.ReLU() # ReLU激活函数
self.fc2 = nn.Conv2d(in_planes // ratio, in_planes, 1, bias=False) # 第二个卷积层,升维
self.sigmoid = nn.Sigmoid() # Sigmoid函数生成最终的注意力权重
def forward(self, x):
avg_out = self.fc2(self.relu1(self.fc1(self.avg_pool(x)))) # 对平均池化的特征进行处理
max_out = self.fc2(self.relu1(self.fc1(self.max_pool(x)))) # 对最大池化的特征进行处理
out = avg_out + max_out # 将两种池化的特征加权和作为输出
return self.sigmoid(out) # 使用sigmoid激活函数计算注意力权重
# 空间注意力模块
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' # 核心大小只能是3或7
padding = 3 if kernel_size == 7 else 1 # 根据核心大小设置填充
# 卷积层用于从连接的平均池化和最大池化特征图中学习空间注意力权重
self.conv1 = nn.Conv2d(2, 1, kernel_size, padding=padding, bias=False)
self.sigmoid = nn.Sigmoid() # Sigmoid函数生成最终的注意力权重
def forward(self, x):
avg_out = torch.mean(x, dim=1, keepdim=True) # 对输入特征图执行平均池化
max_out, _ = torch.max(x, dim=1, keepdim=True) # 对输入特征图执行最大池化
x = torch.cat([avg_out, max_out], dim=1) # 将两种池化的特征图连接起来
x = self.conv1(x) # 通过卷积层处理连接后的特征图
return self.sigmoid(x) # 使用sigmoid激活函数计算注意力权重
# CBAM模块
class CBAM(nn.Module):
def __init__(self, in_planes, ratio=16, kernel_size=7):
super(CBAM, self).__init__()
self.ca = ChannelAttention(in_planes, ratio) # 通道注意力实例
self.sa = SpatialAttention(kernel_size) # 空间注意力实例
def forward(self, x):
out = x * self.ca(x) # 使用通道注意力加权输入特征图
result = out * self.sa(out) # 使用空间注意力进一步加权特征图
return result # 返回最终的特征图
# 示例使用
if __name__ == '__main__':
block = CBAM(64) # 创建一个CBAM模块,输入通道为64
input = torch.rand(1, 64, 64, 64) # 随机生成一个输入特征图
output = block(input) # 通过CBAM模块处理输入特征图
print(input.size(), output.size()) # 打印输入和输出的