CBAM注意⼒机制及pytorch实现
简述
本⽂提出了卷积注意⼒模块,这是⼀种⽤于前馈卷积神经⽹络的简单⽽有效的注意⼒模块.Convolutional Block Attention Module (CBAM)表⽰卷积模块的注意⼒机制模块,是⼀种结合了空间(spatial)和通道(channel)的注意⼒机制模块。相⽐于net只关注通道(channel)的注意⼒机制可以取得更好的效果。
实现过程
上图给出了添加CBAM模块之后的整体结构。可以看到的是,卷积层输出的结果,会先通过⼀个通道注意⼒模块,得到加权结果之后,会再经过⼀个空间注意⼒模块,最终进⾏加权得到结果。
通道注意⼒模块如上图图⼀所⽰.将输⼊的特征图,分别经过基于width和height的global max pooling和global average pooling,然后分别经过MLP.将MLP输出的特征进⾏基于element-wi的加和操作,再经过sigmoid激活操作,⽣成最终的channel attention
featuremap。将该channel attention featuremap和input featuremap做elementwi乘法操作,⽣成Spatial attention模块需要的输⼊特征。以上是通道注意⼒机制的步骤。如何美白皮肤小妙招
换⼀个⾓度考虑,通道注意⼒机制(Channel Attention Module)是将特征图在空间维度上进⾏压缩,得到⼀个⼀维⽮量后再进⾏操作。在空间维度上进⾏压缩时,不仅考虑到了平均值池化(Average Pooling)还考虑了最⼤值池化(Max Pooling)。平均池化和最⼤池化可⽤来聚合特征映射的空间信息,送到⼀个共享⽹络,压缩输⼊特征图的空间维数,逐元素求和合并,以产⽣通道注意⼒图。单就⼀张图来说,通道注意⼒,关注的是这张图上哪些内容是有重要作⽤的。平均值池化对特征图上的每⼀个像素点都有反馈,⽽最⼤值池化在进⾏梯度反向传播计算时,只有特征图中响应最⼤的地⽅有梯度的反馈。通道注意⼒机制可以表达为:
空间注意⼒模块如上图⼦图2所⽰。将Channel attention模块输出的特征图作为本模块的输⼊特征图。⾸先做⼀个基于channel的global max pooling 和global average pooling,然后将这2个结果基于channel 做concat操作。然后经过⼀个卷积操作,降维为1个channel。再经过sigmoid⽣成spatial attention feature。最后将该feature和该模块的输⼊feature做乘法,得到最终⽣成的特征。
同样,空间注意⼒机制(Spatial Attention Module)是对通道进⾏压缩,在通道维度分别进⾏了平均值池化和最⼤值池化。MaxPool的操作就是在通道上提取最⼤值,提取的次数是⾼乘以宽;AvgPool
的操作就是在通道上提取平均值,提取的次数也是是⾼乘以宽;接着将前⾯所提取到的特征图(通道数都为1)合并得到⼀个2通道的特征图。
对于输⼊的特征图,CBAM模块会沿着两个独⽴的维度(通道和空间)依次推断注意⼒图,然后将将注意⼒图与输⼊的特征图相乘以进⾏⾃适应特征优化.
优势:
由于CBAM是轻量级的通⽤模块,因此可以忽略该模块的开销,且⽆缝集成到任何CNN架构中,并可以与基础CNN⼀起进⾏端到段的训练.
代码实现
"""
Author: yida
苏教版四年级上册
Time is:2021/11/2111:40
this Code:实现CBAM模块
"""
import os
import torch
as nn
class CBAM(nn.Module):
def __init__(lf, in_channel):
super(CBAM, lf).__init__()
lf.Cam =ChannelAttentionModul(in_channel=in_channel) # 通道注意⼒模块
lf.Sam =SpatialAttentionModul(in_channel=in_channel) # 空间注意⼒模块
def forward(lf, x):
x = lf.Cam(x)
x = lf.Sam(x)
return x
class ChannelAttentionModul(nn.Module): # 通道注意⼒模块
def __init__(lf, in_channel, r=0.5): # channel为输⼊的维度, r为全连接层缩放⽐例->控制中间层个数
super(ChannelAttentionModul, lf).__init__()
# 全局最⼤池化
lf.MaxPool = nn.AdaptiveMaxPool2d(1)
lf.fc_MaxPool = nn.Sequential(
nn.Linear(in_channel,int(in_channel * r)), # int(channel * r)取整数,中间层神经元数⾄少为1,如有必要可设为向上取整
nn.Linear(in_channel,int(in_channel * r)), # int(channel * r)取整数,中间层神经元数⾄少为1,如有必要可设为向上取整 nn.ReLU(),
nn.Linear(int(in_channel * r), in_channel),
nn.Sigmoid(),
)
# 全局均值池化
lf.AvgPool = nn.AdaptiveAvgPool2d(1)
lf.fc_AvgPool = nn.Sequential(
nn.Linear(in_channel,int(in_channel * r)), # int(channel * r)取整数,中间层神经元数⾄少为1,如有必要可设为向上取整 nn.ReLU(),
nn.Linear(int(in_channel * r), in_channel),
nn.Sigmoid(),
)
# 激活函数
张京 翻译lf.sigmoid = nn.Sigmoid()
def forward(lf, x):
# 1.最⼤池化分⽀
komax_branch = lf.MaxPool(x)
# 送⼊MLP全连接神经⽹络,得到权重
max_in = max_branch.view(max_branch.size(0),-1)
max_weight = lf.fc_MaxPool(max_in)
# 2.全局池化分⽀契据
avg_branch = lf.AvgPool(x)
# 送⼊MLP全连接神经⽹络,得到权重
avg_in = avg_branch.view(avg_branch.size(0),-1)生命在于运动英语
avg_weight = lf.fc_AvgPool(avg_in)
# MaxPool + AvgPool 激活后得到权重weight
weight = max_weight + avg_weight
weight = lf.sigmoid(weight)
# 将维度为b, c的weight, reshape成b, c,1,1与输⼊x 相乘
h, w = weight.shape
# 通道注意⼒Mc
Mc = shape(weight,(h, w,1,1))
# 乘积获得结果
x = Mc * x
return x
class SpatialAttentionModul(nn.Module): # 空间注意⼒模块
def __init__(lf, in_channel):
super(SpatialAttentionModul, lf).__init__()
raison
lf.sigmoid = nn.Sigmoid()
def forward(lf, x):
# x维度为[N, C, H, W]沿着维度C进⾏操作,所以dim=1,结果为[N, H, W]
上海高考英语
MaxPool = torch.max(x, dim=1).values # torch.max 返回的是索引和value,要⽤.values去访问值才⾏!
AvgPool = an(x, dim=1)
amenable# 增加维度,变成[N,1, H, W]
MaxPool = torch.unsqueeze(MaxPool, dim=1)
AvgPool = torch.unsqueeze(AvgPool, dim=1)
# 维度拼接[N,2, H, W]
x_cat = torch.cat((MaxPool, AvgPool), dim=1) # 获得特征图
# 卷积操作得到空间注意⼒结果
批量下载# 卷积操作得到空间注意⼒结果
x_out = lf.conv(x_cat)
Ms = lf.sigmoid(x_out)
# 与原图通道进⾏乘积
x = Ms * x
return x
if __name__ =='__main__':
inputs = torch.randn(10,100,224,224)
model =CBAM(in_channel=100) # CBAM模块,可以插⼊CNN及任意⽹络中,输⼊特征图in_channel的维度
print(model)
outputs =model(inputs)
print("输⼊维度:", inputs.shape)
print("输出维度:", outputs.shape)
验证
通过在ImageNet-1k,MS COCO检测和VOC 2007检测数据集上进⾏的⼴泛实验来验证CBAM。 实验表明,使⽤该模块在各种模型上,并在分类和检测性能⽅⾯的持续改进,证明了CBAM的⼴泛适⽤性。