位置: IT常识 - 正文

【注意力机制集锦】Channel Attention通道注意力网络结构、源码解读系列一(注意力机制cbam)

编辑:rootadmin
【注意力机制集锦】Channel Attention通道注意力网络结构、源码解读系列一

推荐整理分享【注意力机制集锦】Channel Attention通道注意力网络结构、源码解读系列一(注意力机制cbam),希望有所帮助,仅作参考,欢迎阅读内容。

文章相关热门搜索词:注意力机制senet,注意力机制有什么作用,注意力机制有什么作用,注意力机制工作原理,注意力机制有什么作用,注意力机制 q k v,注意力机制工作原理,注意力机制cbam,内容如对您有帮助,希望把文章链接给更多的朋友!

Channel Attention网络结构、源码解读系列一

SE-Net、SK-Net与CBAM

1 SENet

原文链接:SENet原文 源码链接:SENet源码

Squeeze-and-Excitation Networks(SENet)是由自动驾驶公司Momenta在2017年公布的一种全新的图像识别结构,它通过对特征通道间的相关性进行建模,把重要的特征进行强化来提升准确率。这个结构是2017 ILSVR竞赛的冠军,作者在原文中提到,SENet将top5的错误率达到了2.251%,比2016年的第一名还要低25%,在当年也是很有成就的一件事。

1.1 Squeeze-and-Excitation Blocks

SE Block模块主要由Squeeze操作和Excitation操作组成:Squeeze操作负责将spatial维度进行全局池化(比如7 x 7 -->1 x 1);Excitation操作则学习池化后的通道依赖关系,并进行通道权重的赋权。上图网络结构其实很好地概括了SENet的主题思想,下面我将会从Squeeze和Excitation两个方面具体讲解。

1.1.1 Squeeze: Global Information Embedding

网络结构最开始的部分Ftr:X->U是以往的经典卷积结构,U之后的部分才是SENet的创新部分:使用全局平均池化在H和W两个维度对U进行Squeeze,将一个channel上整个空间特征编码为一个全局特征,得到1x1xC的中间输出。说得通俗点,这里其实就是使用一个二维的池化核对特征图进行降维,由原来的H、W、C上的3个维度降到了C这1个维度上,使得后续的通道赋权操作可行,其公式如下图所示:

1.1.2 Excitation: Adaptive Recalibration

为了更好的学习到Squeeze操作得到的特征信息,作者使用Excitation操作获取通道之间的依赖关系。为了实现这一目标,作者分析到该函数必须满足两个标准:(1)它必须是灵活的(特别是能够学习通道之间的非线性交互作用);(2)它必须能够学习一种非互斥的关系(因为我们希望确保允许强调多个通道)。所以作者使用两个全连接层FC学习通道之间的依赖关系,最后再通过sigmoid函数对权重进行归一(将各通道的权重值限制在0-1,权重和限定为1),其公式如下:

1.1.3 举个栗子:SE-ResNet Module

上图是SE-ResNet的网络结构。对于Residual阶段,SE-Block会通过一次全局池化进行降维(说降维可能不规范)得到通道C这一维度的特征,而后经过两层FC。第一层FC会继续降低C的维度,主要通过超参数r来实现(r是指压缩的比例,作者尝试了r在各种取值下的性能 ,最后得出结论r=16时整体性能和计算量最平衡);经过激活后,第二层FC则将压缩后的通道映射回原来的维度,最后利用Sigmoid函数对每个通道赋予不同的权重。 Scale代表将权重与待加权的特征相乘的操作,经过Scale操作后,channel维度上权重就完美地添加到特征中了。

1.2 代码实现1.2.1 SE module

SE的实现如下代码所示,具体每一步我都做了详细的注释。如果前面的公式看不明白,对应这里的函数操作可能会帮助理解公式。

class SELayer(nn.Module): def __init__(self, channel, reduction=16): super(SELayer, self).__init__() self.avg_pool = nn.AdaptiveAvgPool2d(1)# Squeeze操作的定义 self.fc = nn.Sequential(# Excitation操作的定义 nn.Linear(channel, channel // reduction, bias=False),# 压缩 nn.ReLU(inplace=True), nn.Linear(channel // reduction, channel, bias=False),# 恢复 nn.Sigmoid()# 定义归一化操作 ) def forward(self, x): b, c, _, _ = x.size()# 得到H和W的维度,在这两个维度上进行全局池化 y = self.avg_pool(x).view(b, c)# Squeeze操作的实现 y = self.fc(y).view(b, c, 1, 1)# Excitation操作的实现 # 将y扩展到x相同大小的维度后进行赋权 return x * y.expand_as(x)1.2.2 SE-ResNet

下列代码展示了将SENet中加入到Resnet中残差链接前的操作,其实理论上来说SENet可以在浅层Block中添加(如添加在conv1前),也可以在深层中添加(bn2后),具体的添加位置要根据自身任务确定。 如果你的网络更关注浅层特征,如纹理特征,那么就可以加在浅层;相反,如果你的网络更关注深层特征,如轮廓特征、结构特征,那就应该加在深层, 具体问题具体分析。

class SEBasicBlock(nn.Module): expansion = 1 def __init__(self, inplanes, planes, stride=1, downsample=None, groups=1, base_width=64, dilation=1, norm_layer=None, *, reduction=16): super(SEBasicBlock, self).__init__() self.conv1 = conv3x3(inplanes, planes, stride) self.bn1 = nn.BatchNorm2d(planes) self.relu = nn.ReLU(inplace=True) self.conv2 = conv3x3(planes, planes, 1) self.bn2 = nn.BatchNorm2d(planes) self.se = SELayer(planes, reduction) self.downsample = downsample self.stride = stride def forward(self, x): residual = x out = self.conv1(x) out = self.bn1(out) out = self.relu(out) out = self.conv2(out) out = self.bn2(out) out = self.se(out)# 加入通道注意力机制 if self.downsample is not None: residual = self.downsample(x) out += residual out = self.relu(out) return out2 SKNet

原文链接:SKNet原文 源码链接:SKNet源码

CVPR2019的文章Selective Kernel Networks,这篇文章也是致敬了SENet的思想。 SENet提出了Sequeeze and Excitation block,而SKNet提出了Selective Kernel Convolution. 二者都可以很方便的嵌入到现在的网络结构,比如ResNet、Inception、ShuffleNet,实现精度的提升。

2.1 Selective Kernel Convolution【注意力机制集锦】Channel Attention通道注意力网络结构、源码解读系列一(注意力机制cbam)

文章关注点主要是不同大小的感受野对于不同尺度的目标有不同的效果,而我们又应该采取什么方法使得网络可以自动地利用对分类有效的感受野呢?为了解决这个问题,作者在文章中提出了一种对卷积核的动态选择机制,该机制允许每个神经元根据输入信息的多尺度自适应地调整其感受野(卷积核)的大小。 上图就是select kernel convolution模块,网络中主要包括Split、Fuse、Select三个操作。Split通过多条不同大小的kernel产生不同特征图,上图中的模型只设计了两个不同大小的卷积核,实际上可以设计多个分支的多个卷积核;Fuse运算结合并聚合来自多个路径的信息,以获得用于选择权重的全局和综合表示;select操作根据选择权重聚合不同大小内核的特征图。

2.1.1 Split

对输入X使用不同的卷积核生成不同的特征输出,上图所示的是使用3x3和5x5的卷积核进行的卷积操作,为了提高运算效率,5x5的卷积操作是用空洞率为2、卷积核为3x3的空洞卷积实现的,并且使用了分组卷积、深度可分离卷积、BatchNorm和ReLU。

2.1.2 Fuze

将得到的多个特征输出进行信息融合,即pytorch中的sum操作,得到新的特征图U,即下图中的公式(1);然后利用Squeeze相同的操作生成通道这个维度的信息,即下图中的公式(2);最后利用1层全连接层FC学习通道之间的依赖关系,最后使用ReLU和BatchNorm进行归一,即下图中的公式(3)。相关公式如下:

2.1.3 Select

在通道这个维度对多个分支得到的最终特征图进行赋权,使用sigmoid函数。最后将所有分支加权后的特征图相加,得到最终的输出。

2.2 代码实现

结合上述的讲解,代码其实很明了,具体的定义及操作我都作了注释,可以参看注释进行理解。

class SKConv(nn.Module): def __init__(self, features, WH, M, G, r, stride=1 ,L=32): super(SKConv, self).__init__() d = max(int(features/r), L) self.M = M self.features = features self.convs = nn.ModuleList([]) # 生成M个分支,将其添加到convs中,每个分支采用不同的卷积核和不同规模的padding,保证最终得到的特征图大小一致 for i in range(M): self.convs.append(nn.Sequential( nn.Conv2d(features, features, kernel_size=3+i*2, stride=stride, padding=1+i, groups=G), nn.BatchNorm2d(features), nn.ReLU(inplace=False) )) # 学习通道间依赖的全连接层 self.fc = nn.Linear(features, d) self.fcs = nn.ModuleList([]) for i in range(M): self.fcs.append( nn.Linear(d, features) ) self.softmax = nn.Softmax(dim=1) def forward(self, x): for i, conv in enumerate(self.convs): fea = conv(x).unsqueeze_(dim=1) if i == 0: feas = fea else: feas = torch.cat([feas, fea], dim=1) fea_U = torch.sum(feas, dim=1)# 将多个分支得到的特征图进行融合 fea_s = fea_U.mean(-1).mean(-1)# 在channel这个维度进行特征抽取 fea_z = self.fc(fea_s)# 学习通道间的依赖关系 # 赋权操作,由于是对多维数组赋权,所以看起来比SENet麻烦一些 for i, fc in enumerate(self.fcs): vector = fc(fea_z).unsqueeze_(dim=1) if i == 0: attention_vectors = vector else: attention_vectors = torch.cat([attention_vectors, vector], dim=1) attention_vectors = self.softmax(attention_vectors) attention_vectors = attention_vectors.unsqueeze(-1).unsqueeze(-1) fea_v = (feas * attention_vectors).sum(dim=1) return fea_v3 CBAM

原文链接:CBAM原文 源码链接:CBAM源码

CBAM( Convolutional Block Attention Module )是一种轻量化的通道注意力机制,也是目前应用比较广泛的一种视觉注意力机制,在2018年的ECCV中提出。文章同时使用了Channel Attention和Spatial Attention,发现将两种attention串联在一起效果较好。

3.1 Convolutional Block Attention Module

下图是CBAM的网络结构图。

可以看到CBAM包含2个独立的子模块, 通道注意力模块(Channel Attention Module,CAM) 和空间注意力模块(Spartial Attention Module,SAM) ,分别进行通道与空间上的赋权。这样不只能够节约参数和计算力,并且保证了其能够做为即插即用的模块集成到现有的网络架构中去。

3.1.1 Channel attention module

通道注意力机制的基本思想与SENet相同,但是具体操作与SENet略有不同,不同部分我用红色进行了标记。 首先,将输入的特征图F(H×W×C)分别经过基于H和W两个维度的 全局最大池化(MaxPool)和全局平均池化(AvgPool),得到两个1×1×C的特征图; 然后,将两个特征图送入一个 共享权值的双层神经网络(MLP)进行通道间依赖关系的学习,两层神经层之间通过压缩比r实现降维。 最后,将MLP输出的特征进行基于element-wise的加和操作,再经过sigmoid激活操作,生成最终的通道加权,即M_c。其公式如下图:

3.1.2 Spatial attention module

本来本篇专题主要对通道注意力机制进行讨论,想着下一篇空间注意力机制的时候再说CBAM的后续,但按照我懿姐的说法就是,算法都送到嘴边了,那我干脆一块解决了。

空间注意力机制将通道注意力模块输出的特征图F‘作为本模块的输入特征图。 首先,基于channel这个维度进行最大池化(MaxPool)和平均池化(AvgPool)操作,得到两个H×W×1 的特征图; 然后,将两个特征图基于通道维度进行拼接,即concat操作; 再然后,使用7×7卷积核(作者通过实验验证了7x7效果好于其他维度卷积核)进行通道降维,降维为单通道的特征图,即H×W×1; 最后,经过sigmoid学习空间元素之间的依赖关系,生成空间维度的权重,即M_s。其公式如下:

3.2 代码实现3.2.1 CA&SA

具体的网络定义及操作实现参见我的代码注释。

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)# 定义全局最大池化 # 定义CBAM中的通道依赖关系学习层,注意这里是使用1x1的卷积实现的,而不是全连接层 self.fc = nn.Sequential(nn.Conv2d(in_planes, in_planes // 16, 1, bias=False), nn.ReLU(), nn.Conv2d(in_planes // 16, in_planes, 1, bias=False)) self.sigmoid = nn.Sigmoid() def forward(self, x): avg_out = self.fc(self.avg_pool(x))# 实现全局平均池化 max_out = self.fc(self.max_pool(x))# 实现全局最大池化 out = avg_out + max_out# 两种信息融合 # 最后利用sigmoid进行赋权 return self.sigmoid(out)class SpatialAttention(nn.Module): def __init__(self, kernel_size=7): super(SpatialAttention, self).__init__() # 定义7*7的空间依赖关系学习层 self.conv1 = nn.Conv2d(2, 1, kernel_size, padding=kernel_size//2, bias=False) self.sigmoid = nn.Sigmoid() def forward(self, x): avg_out = torch.mean(x, dim=1, keepdim=True)# 实现channel维度的平均池化 max_out, _ = torch.max(x, dim=1, keepdim=True)# 实现channel维度的最大池化 x = torch.cat([avg_out, max_out], dim=1)# 拼接上述两种操作的到的两个特征图 x = self.conv1(x)# 学习空间上的依赖关系 # 对空间元素进行赋权 return self.sigmoid(x)3.2.2 CBAM_ResNet

篇幅限制,这里仅展示BasicBlock的CA&SA的添加

class BasicBlock(nn.Module): expansion = 1 def __init__(self, inplanes, planes, stride=1, downsample=None): super(BasicBlock, self).__init__() self.conv1 = conv3x3(inplanes, planes, stride) self.bn1 = nn.BatchNorm2d(planes) self.relu = nn.ReLU(inplace=True) self.conv2 = conv3x3(planes, planes) self.bn2 = nn.BatchNorm2d(planes)# 定义ca和sa,注意CA与channel num有关,需要指定这个超参!!! self.ca = ChannelAttention(planes) self.sa = SpatialAttention() self.downsample = downsample self.stride = stride def forward(self, x): residual = x out = self.conv1(x) out = self.bn1(out) out = self.relu(out) out = self.conv2(out) out = self.bn2(out) out = self.ca(out) * out# 对channel赋权 out = self.sa(out) * out# 对spatial赋权 if self.downsample is not None: residual = self.downsample(x) out += residual out = self.relu(out) return out

系列一到这里就结束了,点赞越多更新越快哦!

本文链接地址:https://www.jiuchutong.com/zhishi/297309.html 转载请保留说明!

上一篇:Ai实现FPS游戏自动瞄准 yolov5fps自瞄(游戏ai模式是什么意思)

下一篇:JS 异步编程方法:6种方案(js异步解决方案)

  • 如何注销滴滴车主车辆和账号(如何注销滴滴车主账号)

    如何注销滴滴车主车辆和账号(如何注销滴滴车主账号)

  • oppo手机卸载的软件怎么找回来(oppo手机卸载的软件在哪里)

    oppo手机卸载的软件怎么找回来(oppo手机卸载的软件在哪里)

  • 联想笔记本电脑亮度调节失灵怎么办(联想笔记本电脑黑屏打不开怎么办)

    联想笔记本电脑亮度调节失灵怎么办(联想笔记本电脑黑屏打不开怎么办)

  • 天猫品牌兑换卡什么意思(天猫品牌兑换卡在哪)

    天猫品牌兑换卡什么意思(天猫品牌兑换卡在哪)

  • 支付宝语音播报怎么设置(支付宝语音播报收款怎么设置)

    支付宝语音播报怎么设置(支付宝语音播报收款怎么设置)

  • 荣耀30防水防尘级别(荣耀30s 防水)

    荣耀30防水防尘级别(荣耀30s 防水)

  • 华为nova7为什么没有智能遥控(华为nova7为什么指纹不能用了)

    华为nova7为什么没有智能遥控(华为nova7为什么指纹不能用了)

  • 芒果视频弹幕在哪里设置(芒果视频弹幕在哪里关闭)

    芒果视频弹幕在哪里设置(芒果视频弹幕在哪里关闭)

  • ipadmini4什么时候上市的		(ipadmini4什么时候上市的多少钱)

    ipadmini4什么时候上市的 (ipadmini4什么时候上市的多少钱)

  • ldn-al10是什么型号的手机(ldn一al10)

    ldn-al10是什么型号的手机(ldn一al10)

  • 200兆的网速快吗(200兆的网速算快吗)

    200兆的网速快吗(200兆的网速算快吗)

  • matebookd14和15的区别(matebook14和matebookd15)

    matebookd14和15的区别(matebook14和matebookd15)

  • 手机丢失能不能通过手机号定位(手机丢失能不能用手机卡定位)

    手机丢失能不能通过手机号定位(手机丢失能不能用手机卡定位)

  • 苹果5s手机怎么开机(苹果5s手机怎么打开手机镜像)

    苹果5s手机怎么开机(苹果5s手机怎么打开手机镜像)

  • 接码平台能注册微信号吗(接码平台能注册软件吗)

    接码平台能注册微信号吗(接码平台能注册软件吗)

  • 小米9透明版和透明尊享版有什么区别(小米9透明版和探索版一样吗)

    小米9透明版和透明尊享版有什么区别(小米9透明版和探索版一样吗)

  • eⅹcel怎么制做表格(6×3的制作)

    eⅹcel怎么制做表格(6×3的制作)

  • cpu的基本功能包括(cpu的基本功能是什么)

    cpu的基本功能包括(cpu的基本功能是什么)

  • 什么是五g时代(5g时代是什么意思)

    什么是五g时代(5g时代是什么意思)

  • 荣耀10如何设置返回键(荣耀10如何设置24小时显示)

    荣耀10如何设置返回键(荣耀10如何设置24小时显示)

  • 什么手机可以放两张电信卡(什么手机可以放两张卡)

    什么手机可以放两张电信卡(什么手机可以放两张卡)

  • 天猫魔筒和360安全路由器哪个好 360安全路由器和天猫魔筒配置区别对比(天猫魔投安装教程)

    天猫魔筒和360安全路由器哪个好 360安全路由器和天猫魔筒配置区别对比(天猫魔投安装教程)

  • 超详细的VSCode下载和安装教程以及解决VSCode下载速度特别慢的问题(vscode2010下载)

    超详细的VSCode下载和安装教程以及解决VSCode下载速度特别慢的问题(vscode2010下载)

  • JavaScript-扫盲(javascriptz)

    JavaScript-扫盲(javascriptz)

  • 一般税收协定是多少
  • 资产减值损失影响利润吗
  • 未抵扣的进项发票是什么意思
  • 公司注销投资款退回给股东,附言写什么
  • 企业所得税研发费用100%扣除的有哪些企业
  • 不动产在建工程是什么意思
  • 房子免租期
  • 房地产企业所得税预缴
  • 高管培训费不能税前列支
  • 交通运输业安全心得体会范文
  • 外贸出口退税是退出口金额的多少
  • 一般纳税人外经证预缴怎样缴费
  • 网上申报时纳税人怎么填
  • 小规模纳税人应交增值税科目设置
  • 出售废旧物资可以开专票吗
  • 未按规定安装使用税控装置
  • 个人网银测试要点
  • 属于留存收益的是
  • 普票需要缴纳印花税吗
  • 借主营业务成本贷应付账款
  • 员工离职再入职要重新签订合同吗
  • 9个点的税率有哪些
  • 对公账户一直没有流水怎么办
  • PHP:Memcached::addServers()的用法_Memcached类
  • 委托境外研发费用加计扣除比例
  • kazaalite.exe是什么进程 kazaalite进程有什么用
  • cuda completed with errors
  • 利息补偿金怎么算
  • 外企采购回扣普遍吗
  • 财政返还土地奖金的规定
  • 小企业会计准则财务报表至少包括
  • php无限级分类
  • AttributeError: ‘bytes‘ object has no attribute ‘encode‘异常解决方案
  • centos php7.4
  • 文件上传模板怎么弄
  • sysctl命令配置主机名
  • 销售商品怎么做好宣传
  • 土地使用权的使用方式
  • 分配现金股利的分录
  • 企业转让无形资产取得的收益应计入营业外收入
  • 织梦cms怎么样
  • sqlite时间戳转时间语句(时间转时间戳)
  • 融资租赁业务应包括哪些
  • 利润表中本期金额是什么意思
  • 非金融企业之间的借款合同要交印花税吗
  • 发放职工薪酬计入什么科目
  • 存货计划成本法的优点
  • 建安企业用什么会计制度
  • 持有至到期投资减值准备
  • 发票红字怎么弄
  • 逐步测试法计算内含报酬率
  • 研发阶段的产品质检要参与
  • 固定资产的税法处理与会计处理的差异50字
  • 预缴税款的会计处理
  • 会计账簿按账页不同可以分为
  • 会计调账是什么意思
  • 事业单位会计制度
  • mysql锁表的sql
  • FreeBSD su Sorry问题解决办法
  • win8无法安装其它软件
  • linux中find命令基本使用方法
  • linux系统怎么安装
  • win7系统回收站不见了怎么办
  • 装win8.1
  • 电脑系统win8
  • 安装linux系统步骤图解
  • win7系统安装不了软件怎么办
  • linux的web服务器
  • python中对文件操作的一般步骤
  • wordpress单页面店铺
  • nodejs+ts
  • AndroidAnnotations框架Eclipse下的配置
  • unity导入设置在哪里
  • js uridecode
  • 国家税务总局是正部级还是副部级
  • 云南地税局官网
  • 进境邮件补充申请
  • 查询发票号码
  • 经营工作会议
  • 免责声明:网站部分图片文字素材来源于网络,如有侵权,请及时告知,我们会第一时间删除,谢谢! 邮箱:opceo@qq.com

    鄂ICP备2023003026号

    网站地图: 企业信息 工商信息 财税知识 网络常识 编程技术

    友情链接: 武汉网站建设