各种CV领域 Attention (原理+代码大全)

发布时间:2025-12-09 18:50:15 浏览次数:3

人类在处理信息时,天然会过滤掉不太关注的信息,着重于感兴趣信息,于是将这种处理信息的机制称为注意力机制。

注意力机制分类:软注意力机制(全局注意)、硬注意力机制(局部注意)、和自注意力机制(内注意)

软注意力机制:根据每个区域被关注程度的高低,用0~1之间的概率值来表示;与硬注意力相比,软注意力是一个可微的过程,可以通过训练过程的前向和后向反馈学习得到;因为对每部分信息都有考虑,所以相对于硬注意机制,计算量比较大。

硬注意力机制:又称强注意力机制,即哪些区域是被关注的,哪些区域是不被关注的,是一个是或不是的问题,会直接舍弃掉一些不相关项,如在图像领域的图像裁剪,裁剪后留下的部分即被关注的区域;优势在于会节省一定的时间和计算成本,但是有可能会丢失一部分信息。值得注意的是,因其是一个不可微的过程,所以在cv领域,一般用在强化学习中;如在视频领域中,因为有时序性关系,每张图片即为某个时间点下的采样,强注意力机制则可以看成是否对该时间点的采样关注,可以通过强化学习来训练。

自注意力机制:自注意力是对每个输入赋予的权重取决于输入数据之间的关系,即通过输入项内部之间的相互博弈决定每个输入项的权重。与前两项机制相比,自注意力在计算时,具有并行计算的优势。

CV领域注意力分类

在CV领域,按照注意力关注的域,可以将其分成:

  • 空间域注意力
  • 通道域注意力
  • 时间域注意力
  • 混合域注意力
  • 自注意力


    • CV领域注意力分类
    • 1.通道注意力机制Channel Attention
        • SENet
        • GSoP-Net
        • FcaNet
        • ECA-Net
        • SRM
        • GCT
    • 2.空间注意力机制Spatial Attention
        • RAM
        • DRAW
        • STN-Net
        • DCN v1/v2
        • GENet
        • Non-local Neural Networks
        • CCNet
        • EMANet
        • SASA
        • SAN
        • ViT/DETR
    • 3.时间注意力机制Temporal Attention
        • TAM
        • GLTR
    • 4.通道和空间注意力机制
        • CBAM
        • BAM
        • scSE
        • Triplet Attention
        • RGA
        • Residual attention
        • SimAM
        • SCNet
    • 5.时域和空间注意力机制
        • RSTAN
        • STA
        • STGCN

1.通道注意力机制Channel Attention

通道注意力机制在计算机视觉中,更关注特征图中channel之间的关系,而普通的卷积会对通道做通道融合,这个开山鼻祖是SENet,后面有GSoP-Net,FcaNet 对SENet中的squeeze部分改进,EACNet对SENet中的excitation部分改进,SRM,GCT等对SENet中的scale部分改进。

SENet

paper:https://arxiv.org/abs/1709.01507
github: pytorch:https://github.com/moskomule/senet.pytorch

SENet《Squeeze-and-Excitation Networks》是CVPR17年的一篇文章,提出SE module。在卷积神经网络中,卷积操作更多的是关注感受野,在通道上默认为是所有通道的融合,而SENet提出SE模块,将注意力放到通道之间,希望模型可以学习到不同通道之间的权重:

输入特征图h* w* c,先分别通过一个全局最大池化和全局平均池化,分别得到一个1* 1* c的特征图,将两个特征图分别送进两个全连接层,得到两个1* 1* c的特征图,将两个特征图相加,通过sigmoid激活到[0,1]范围内的权重,与输入的特征图在通道层相乘,得到输出特征图。这里的思路基本与SENet相同,除了增加一个池化,增加通道注意力的语义丰富性。作者也实验证明了同时使用两个池化比单独使用其中一种效果要好,可以理解最大池化关注图片的显著信息,平均池化关注图片的全局信息,都是有可用性,同理后面的空间注意力机制也使用了两种池化方式。

空间注意力实现如下:

输入特征图为 H x W x C,分别通过一个通道维度的最大池化和平均池化得到两个H x W x 1的特征图,然后将这两个特征图在通道维度拼接起来,得到一个H x W x 2的特征图,然后再经过一个卷积层,降为1个通道,保持H W 不变,输出feature map为H x W x 1,然后再通过Sigmoid函数生成空间权重系数,与输入feature map相乘得到最终feature map。

同时作者实验证明通道注意力放在空间注意力前面效果更好。

class ChannelAttention(nn.Module):def __init__(self,channel,reduction=16):super().__init__()self.maxpool=nn.AdaptiveMaxPool2d(1)self.avgpool=nn.AdaptiveAvgPool2d(1)self.se=nn.Sequential(nn.Conv2d(channel,channel//reduction,1,bias=False),nn.ReLU(),nn.Conv2d(channel//reduction,channel,1,bias=False))self.sigmoid=nn.Sigmoid()def forward(self, x) :max_result=self.maxpool(x)avg_result=self.avgpool(x)max_out=self.se(max_result)avg_out=self.se(avg_result)output=self.sigmoid(max_out+avg_out)return outputclass SpatialAttention(nn.Module):def __init__(self,kernel_size=7):super().__init__()self.conv=nn.Conv2d(2,1,kernel_size=kernel_size,padding=kernel_size//2)self.sigmoid=nn.Sigmoid()def forward(self, x) :max_result,_=torch.max(x,dim=1,keepdim=True)avg_result=torch.mean(x,dim=1,keepdim=True)result=torch.cat([max_result,avg_result],1)output=self.conv(result)output=self.sigmoid(output)return outputclass CBAMBlock(nn.Module):def __init__(self, channel=512,reduction=16,kernel_size=49):super().__init__()self.ca=ChannelAttention(channel=channel,reduction=reduction)self.sa=SpatialAttention(kernel_size=kernel_size)def init_weights(self):for m in self.modules():if isinstance(m, nn.Conv2d):init.kaiming_normal_(m.weight, mode='fan_out')if m.bias is not None:init.constant_(m.bias, 0)elif isinstance(m, nn.BatchNorm2d):init.constant_(m.weight, 1)init.constant_(m.bias, 0)elif isinstance(m, nn.Linear):init.normal_(m.weight, std=0.001)if m.bias is not None:init.constant_(m.bias, 0)def forward(self, x):b, c, _, _ = x.size()residual=xout=x*self.ca(x)out=out*self.sa(out)return out+residual

BAM

paper:https://arxiv.org/abs/1807.06514v2
github:https://github.com/Jongchan/attention-module


BAM和CBAM几乎相同时间提出,称为瓶颈注意力机制,主要有两个分支。
上面那个分支和SENet基本上相同,相当于通道注意力机制;
下面的分支为空间注意力,先将特征层通过11的卷积将通道压缩到C/r,再经过两个33的空洞卷积,做特征融合,通道数不变,最后通过一个1*1的卷积将通道数变成1。再将通道注意力机制与空间注意力机制生成的特征图融合成和输入相同大小的特征图,再与输入做跳层连接。

class Flatten(nn.Module):def forward(self,x):return x.view(x.shape[0],-1)class ChannelAttention(nn.Module):def __init__(self,channel,reduction=16,num_layers=3):super().__init__()self.avgpool=nn.AdaptiveAvgPool2d(1)gate_channels=[channel]gate_channels+=[channel//reduction]*num_layersgate_channels+=[channel]self.ca=nn.Sequential()self.ca.add_module('flatten',Flatten())for i in range(len(gate_channels)-2):self.ca.add_module('fc%d'%i,nn.Linear(gate_channels[i],gate_channels[i+1]))self.ca.add_module('bn%d'%i,nn.BatchNorm1d(gate_channels[i+1]))self.ca.add_module('relu%d'%i,nn.ReLU())self.ca.add_module('last_fc',nn.Linear(gate_channels[-2],gate_channels[-1]))def forward(self, x) :res=self.avgpool(x)res=self.ca(res)res=res.unsqueeze(-1).unsqueeze(-1).expand_as(x)return resclass SpatialAttention(nn.Module):def __init__(self,channel,reduction=16,num_layers=3,dia_val=2):super().__init__()self.sa=nn.Sequential()self.sa.add_module('conv_reduce1',nn.Conv2d(kernel_size=1,in_channels=channel,out_channels=channel//reduction))self.sa.add_module('bn_reduce1',nn.BatchNorm2d(channel//reduction))self.sa.add_module('relu_reduce1',nn.ReLU())for i in range(num_layers):self.sa.add_module('conv_%d'%i,nn.Conv2d(kernel_size=3,in_channels=channel//reduction,out_channels=channel//reduction,padding=1,dilation=dia_val))self.sa.add_module('bn_%d'%i,nn.BatchNorm2d(channel//reduction))self.sa.add_module('relu_%d'%i,nn.ReLU())self.sa.add_module('last_conv',nn.Conv2d(channel//reduction,1,kernel_size=1))def forward(self, x) :res=self.sa(x)res=res.expand_as(x)return resclass BAMBlock(nn.Module):def __init__(self, channel=512,reduction=16,dia_val=2):super().__init__()self.ca=ChannelAttention(channel=channel,reduction=reduction)self.sa=SpatialAttention(channel=channel,reduction=reduction,dia_val=dia_val)self.sigmoid=nn.Sigmoid()def init_weights(self):for m in self.modules():if isinstance(m, nn.Conv2d):init.kaiming_normal_(m.weight, mode='fan_out')if m.bias is not None:init.constant_(m.bias, 0)elif isinstance(m, nn.BatchNorm2d):init.constant_(m.weight, 1)init.constant_(m.bias, 0)elif isinstance(m, nn.Linear):init.normal_(m.weight, std=0.001)if m.bias is not None:init.constant_(m.bias, 0)def forward(self, x):b, c, _, _ = x.size()sa_out=self.sa(x)ca_out=self.ca(x)weight=self.sigmoid(sa_out+ca_out)out=(1+weight)*xreturn out

scSE

paper:https://arxiv.org/abs/1808.08127
github:https://github.com/pprp/SimpleCVReproduction/tree/master/Plug-and-play%20module/attention/scSE(unofficial)

这篇文章主要用于语义分割上,对SE模块进行了改进,提出了SE模块的三个变体cSE、sSE、scSE,并通过实验证明了了这样的模块可以增强有意义的特征,抑制无用特征。一开始作者提出了两个模块:sSE模块和cSE模块,分别为通道注意力和空间注意力:

scSE则是将两者并联起来,有点类似于BAM结构:

Triplet Attention

paper:https://arxiv.org/abs/2010.03045
github:https://github.com/landskape-ai/triplet-attention

triplet Attention 也是在CNN中加入进spatial attention和channel attention的一个即插即用模块,文章认为CBAM建立Channel Attention和Spatial Attention的操作是分别进行的,而二者之间可能有联系,应该同时建模Channel Attention和Spatial Attention。

于是文章中的Triplet其实就是从三个角度去建模attention关系:以输入的feature map大小为(b, c, h, w)为例,围绕channel,height,width可以建模三组关系:
channel to height(c,h)
channel to width(c,w)
height to width(h,w)

相对其他Attention Module而言,Triplet Attention近乎无参,效果提升不是很明显。

class BasicConv(nn.Module):def __init__(self, in_planes, out_planes, kernel_size, stride=1, padding=0, dilation=1, groups=1, relu=True, bn=True, bias=False):super(BasicConv, self).__init__()self.out_channels = out_planesself.conv = nn.Conv2d(in_planes, out_planes, kernel_size=kernel_size, stride=stride, padding=padding, dilation=dilation, groups=groups, bias=bias)self.bn = nn.BatchNorm2d(out_planes,eps=1e-5, momentum=0.01, affine=True) if bn else Noneself.relu = nn.ReLU() if relu else Nonedef forward(self, x):x = self.conv(x)if self.bn is not None:x = self.bn(x)if self.relu is not None:x = self.relu(x)return xclass ZPool(nn.Module):def forward(self, x):return torch.cat( (torch.max(x,1)[0].unsqueeze(1), torch.mean(x,1).unsqueeze(1)), dim=1)class AttentionGate(nn.Module):def __init__(self):super(AttentionGate, self).__init__()kernel_size = 7self.compress = ZPool()self.conv = BasicConv(2, 1, kernel_size, stride=1, padding=(kernel_size-1) // 2, relu=False)def forward(self, x):x_compress = self.compress(x)x_out = self.conv(x_compress)scale = torch.sigmoid_(x_out) return x * scaleclass TripletAttention(nn.Module):def __init__(self, no_spatial=False):super(TripletAttention, self).__init__()self.cw = AttentionGate()self.hc = AttentionGate()self.no_spatial=no_spatialif not no_spatial:self.hw = AttentionGate()def forward(self, x):x_perm1 = x.permute(0,2,1,3).contiguous()x_out1 = self.cw(x_perm1)x_out11 = x_out1.permute(0,2,1,3).contiguous()x_perm2 = x.permute(0,3,2,1).contiguous()x_out2 = self.hc(x_perm2)x_out21 = x_out2.permute(0,3,2,1).contiguous()if not self.no_spatial:x_out = self.hw(x)x_out = 1/3 * (x_out + x_out11 + x_out21)else:x_out = 1/2 * (x_out11 + x_out21)return x_out

RGA

paper:https://arxiv.org/abs/1904.02998
github:https://github.com/microsoft/Relation-Aware-Global-Attention-Networks

这是一篇cvpr2020由微软提出的关系感知全局注意力机制,用于捕获全局信息。区别于常用的获取注意力的方法,作者将特征图中的每个位置上的feature看作一个node,通过强调node间的对称关系来挖掘全局范围的相关性和语义信息,提出了即插即用在残差块后的注意力模块Relation-aware global attention module(RGA),该模块将注意力同时应用与spatial及channel上。

Residual attention

paper:https://arxiv.org/abs/1704.06904
github:https://github.com/fwang91/residual-attention-network

作者提出了Residual Attention Network,主要通过堆叠多个Attention Modules来构造Residual Attention Network。堆叠结构是混合注意力机制的基本应用。因此,不同类型的注意力能够被不同的注意力模块捕获,而直接叠加注意力模块会导致明显的学习性能下降。因此,提出了attention residual learning mechanism来优化几百层的非常深层的Residual Attention Network。

class ResidualAttention(nn.Module):def __init__(self, channel=512 , num_class=1000,la=0.2):super().__init__()self.la=laself.fc=nn.Conv2d(in_channels=channel,out_channels=num_class,kernel_size=1,stride=1,bias=False)def forward(self, x):b,c,h,w=x.shapey_raw=self.fc(x).flatten(2) #b,num_class,hxwy_avg=torch.mean(y_raw,dim=2) #b,num_classy_max=torch.max(y_raw,dim=2)[0] #b,num_classscore=y_avg+self.la*y_maxreturn score

SimAM

paper:http://proceedings.mlr.press/v139/yang21o/yang21o.pdf
github:https://github.com/ZjjConan/SimAM

作者提出一种概念简单且非常有效的注意力模块。不同于现有的通道/空域注意力模块,该模块无需额外参数为特征图推导出3D注意力权值。同时推导出了能量函数的解析解加速了注意力权值的计算并得到了一种轻量型注意力模块;

class SimAM(torch.nn.Module):def __init__(self, channels = None, e_lambda = 1e-4):super(SimAM, self).__init__()self.activaton = nn.Sigmoid()self.e_lambda = e_lambdadef __repr__(self):s = self.__class__.__name__ + '('s += ('lambda=%f)' % self.e_lambda)return s@staticmethoddef get_module_name():return "simam"def forward(self, x):b, c, h, w = x.size()n = w * h - 1x_minus_mu_square = (x - x.mean(dim=[2,3], keepdim=True)).pow(2)y = x_minus_mu_square / (4 * (x_minus_mu_square.sum(dim=[2,3], keepdim=True) / n + self.e_lambda)) + 0.5return x * self.activaton(y)

SCNet

paper:http://mftp.mmcheng.net/Papers/20cvprSCNet.pdf
github:https://github.com/MCG-NKU/SCNet

在本文中,没有设计复杂的网络体系结构来增强特征表示,而是引入了自校正卷积作为一种有效的方法来帮助卷积网络通过增加每层的基本卷积变换来学习判别表示。类似于分组卷积,它将特定层的卷积核分为多个部分,但不均匀地每个部分中的卷积核以异构方式被利用。具体而言,自校正卷积不是通过均匀地对原始空间中的输入执行所有卷积,而是首先通过下采样将输入转换为低维嵌入, 采用由一个卷积核变换的低维嵌入来校准另一部分中卷积核的卷积变换。得益于这种异构卷积和卷积核间通信,可以有效地扩大每个空间位置的感受野.

5.时域和空间注意力机制

时域和空间注意力是基于时域注意力和空间注意力机制,综合考虑两者一起提出的注意力机制,也称混合注意力机制,主要用于视频领域,如动作识别或者行人ReID中,主要包括区分时域和空间的注意力:RSTAN;联合产生的时域和空间注意力机制:STA;基于成对关系的注意力:STGCN。

RSTAN

paper:https://ieeexplore.ieee.org/document/8123939
github: https://github.com/PancakeAwesome/ran_two_stream_to_recognize_drives(unofficial)

对视频中的动作识别增加软注意力机制,使用多层循环神经网络 (RNN) 和长短期记忆 (LSTM) 单元。

STA

paper: https://ojs.aaai.org//index.php/AAAI/article/view/4841
github: https://github.com/justchenhao/STANet(unofficial)

STA在空间和时间维度上充分利用了一个目标的那些判别部分,从而通过帧间正则化生成一个二维注意力得分矩阵,以测量不同帧中空间部分的重要性。因此,可以根据挖掘的二维注意力得分矩阵引导的加权求和运算生成更稳健的剪辑级特征表示。

class BAM(nn.Module):""" Basic self-attention module"""def __init__(self, in_dim, ds=8, activation=nn.ReLU):super(BAM, self).__init__()self.chanel_in = in_dimself.key_channel = self.chanel_in //8self.activation = activationself.ds = ds #self.pool = nn.AvgPool2d(self.ds)print('ds: ',ds)self.query_conv = nn.Conv2d(in_channels=in_dim, out_channels=in_dim // 8, kernel_size=1)self.key_conv = nn.Conv2d(in_channels=in_dim, out_channels=in_dim // 8, kernel_size=1)self.value_conv = nn.Conv2d(in_channels=in_dim, out_channels=in_dim, kernel_size=1)self.gamma = nn.Parameter(torch.zeros(1))self.softmax = nn.Softmax(dim=-1) #def forward(self, input):"""inputs :x : input feature maps( B X C X W X H)returns :out : self attention value + input featureattention: B X N X N (N is Width*Height)"""x = self.pool(input)m_batchsize, C, width, height = x.size()proj_query = self.query_conv(x).view(m_batchsize, -1, width * height).permute(0, 2, 1) # B X C X (N)/(ds*ds)proj_key = self.key_conv(x).view(m_batchsize, -1, width * height) # B X C x (*W*H)/(ds*ds)energy = torch.bmm(proj_query, proj_key) # transpose checkenergy = (self.key_channel**-.5) * energyattention = self.softmax(energy) # BX (N) X (N)/(ds*ds)/(ds*ds)proj_value = self.value_conv(x).view(m_batchsize, -1, width * height) # B X C X Nout = torch.bmm(proj_value, attention.permute(0, 2, 1))out = out.view(m_batchsize, C, width, height)out = F.interpolate(out, [width*self.ds,height*self.ds])out = out + inputreturn out

STGCN

paper: https://ieeexplore.ieee.org/document/9156954/
github: https://github.com/justchenhao/STANet(unofficial)

该论文将GCN运用到Person ReID上面来,将图像信息分块作为节点信息;作者提出一个新的时空图卷积网络(STGCN)。STGCN包括两个GCN分支:空间分支、时间分支。空间分支提取人体的结构信息,时间分支从相邻帧中挖掘判别线索。通过联合优化这些分支,模型提取了与外观信息互补的鲁棒时空信息。

参考文章:http://www.360doc6.net/wxarticlenew/1053604427.html

需要做网站?需要网络推广?欢迎咨询客户经理 13272073477