主要的注意力机制

主要的注意力机制

通道&空间注意力

SE-Net

Squeeze-and-Excitation Networks》发表于CVPR 2018,是CV领域将注意力机制应用到通道维度的代表作,后续大量基于通道域的工作均是基于此改进
在这里插入图片描述

Squeeze

F s q F_{sq} Fsq利用全局平均池化(Global Average Pooling, GAP) 操作将每个通道的二维特征(HxW)压缩为1个实数,论文是通过平均值池化的方式实现。这属于空间维度的一种特征压缩,因为这个实数是根据二维特征所有值算出来的,所以在某种程度上具有全局的感受野,通道数保持不变,所以通过squeeze操作后变为1×1×C。;

Excitation

F e x F_{ex} Fex通过参数来为每个特征通道生成一个权重值
,利用两层的多层感知机(FC-ReLU-FC-Sigmoid) 网络建模通道间的相关性,并输出和输入特征同样数目的权重值;

Scale

F s c a l e F_{scale} Fscale将前面得到的归一化权重加权到每个通道的特征上。论文中的方法是用乘法,逐通道乘以权重系数,完成再通道维度上引入attention机制。

在这里插入图片描述

class SELayer(nn.Module):
    def __init__(self, channel, reduction=16):
        super(SELayer, self).__init__()
        self.avg_pool = nn.AdaptiveAvgPool2d(1)
        self.fc = nn.Sequential(
            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()
        y = self.avg_pool(x).view(b, c)
        y = self.fc(y).view(b, c, 1, 1)
        return x * y.expand_as(x)

GE-Net

《Gather-Excite: Exploiting Feature Context in Convolutional Neural Networks》发表于NIPS 2018,从上下文建模的角度出发,提出了一种比SE-Net更一般的形式。GE-Net充分利用空间注意力来更好的挖掘特征之间的上下文信息。
在这里插入图片描述
GENet定义了Gather算子 ξ G \xi_G ξG和Excite算子 ξ E \xi_E ξE ξ G \xi_G ξG操作是用一次或多次 某size某stride的池化操作得到输出 R C × H ′ × W ′ R^{C×H^{'}×W^{'}} RC×H×W,接着将Gather的输出用 ξ E \xi_E ξE操作,变换到维度为 R C × H ′ × W ′ R^{C×H^{'}×W^{'}} RC×H×W的调控原信息流的信息,接着直接点乘上原输入 X X X

SK-Net

《Selective Kernel Networks》发表于CVPR 2018,原SE-Net的作者Momenta也参与到这篇文章中。SK-Net主要灵感来源于Inception-Net的多分支结构以及SE-Net的特征重标定策略,研究的是卷积核之间的相关性,并进一步地提出了一种选择性卷积核模块。SK-Net从多尺度特征表征的角度出发,引入多个带有不同感受野的并行卷积核分支来学习不同尺度下的特征图权重,使网络能够挑选出更加合适的多尺度特征表示,不仅解决了SE-Net中单一尺度的问题,而且也结合了多分枝结构的思想从丰富的语义信息中筛选出重要的特征。
在这里插入图片描述
Split 采用不同感受野大小的卷积核捕获多尺度的语义信息;
Fuse 融合多尺度语义信息,增强特征多样性;
Select 在不同向量空间(代表不同尺度的特征信息)中进行Softmax操作,为合适的尺度通道赋予更高的权重。

class SKConv(nn.Module):
    def __init__(self, features, M=2, G=32, r=16, stride=1, L=32):
        """ Constructor
        Args:
            features: input channel dimensionality.
            M: the number of branchs.
            G: num of convolution groups.
            r: the ratio for compute d, the length of z.
            stride: stride, default 1.
            L: the minimum dim of the vector z in paper, default 32.
        """
        super(SKConv, self).__init__()
        d = max(int(features/r), L)
        self.M = M
        self.features = features
        self.convs = nn.ModuleList([])
        for i in range(M):
            self.convs.append(nn.Sequential(
                nn.Conv2d(features, features, kernel_size=3, stride=stride, padding=1+i, dilation=1+i, groups=G, bias=False),
                nn.BatchNorm2d(features),
                nn.ReLU(inplace=False)
            ))
        self.gap = nn.AdaptiveAvgPool2d((1,1))
        self.fc = nn.Sequential(nn.Conv2d(features, d, kernel_size=1, stride=1, bias=False),
                                nn.BatchNorm2d(d),
                                nn.ReLU(inplace=False))
        self.fcs = nn.ModuleList([])
        for i in range(M):
            self.fcs.append(
                 nn.Conv2d(d, features, kernel_size=1, stride=1)
            )
        self.softmax = nn.Softmax(dim=1)
        
    def forward(self, x):
        
        batch_size = x.shape[0]
        
        feats = [conv(x) for conv in self.convs]      
        feats = torch.cat(feats, dim=1)
        feats = feats.view(batch_size, self.M, self.features, feats.shape[2], feats.shape[3])
        
        feats_U = torch.sum(feats, dim=1)
        feats_S = self.gap(feats_U)
        feats_Z = self.fc(feats_S)

        attention_vectors = [fc(feats_Z) for fc in self.fcs]
        attention_vectors = torch.cat(attention_vectors, dim=1)
        attention_vectors = attention_vectors.view(batch_size, self.M, self.features, 1, 1)
        attention_vectors = self.softmax(attention_vectors)
        
        feats_V = torch.sum(feats*attention_vectors, dim=1)
        
        return feats_V

SPA-Net

《Spatial Pyramid Attention Network for Enhanced Image Recognition》 发表于ICME 2020 并获得了最佳学生论文。考虑到 SE-Net 这种利用 GAP 去建模全局上下文的方式会导致空间信息的损失,SPA-Net另辟蹊径,利用多个自适应平均池化(Adaptive Averatge Pooling, APP) 组成的空间金字塔结构来建模局部和全局的上下文语义信息,使得空间语义信息被更加充分的利用到。
在这里插入图片描述

class CPSPPSELayer(nn.Module):
    def __init__(self,in_channel, channel, reduction=16):
        super(CPSPPSELayer, self).__init__()
        if in_channel != channel:
            self.conv1 = nn.Sequential(
                nn.Conv2d(in_channel, channel, kernel_size=1, stride=1, bias=False),
                nn.BatchNorm2d(channel),
                nn.ReLU(inplace=True)
            )
        self.avg_pool1 = nn.AdaptiveAvgPool2d(1)
        self.avg_pool2 = nn.AdaptiveAvgPool2d(2)
        self.avg_pool4 = nn.AdaptiveAvgPool2d(4)
        self.fc = nn.Sequential(
            nn.Linear(channel*21, channel*21 // reduction, bias=False),
            nn.ReLU(inplace=True),
            nn.Linear(channel*21 // reduction, channel, bias=False),
            nn.Sigmoid()
        )

    def forward(self, x):
        x = self.conv1(x) if hasattr(self, 'conv1') else x
        b, c, _, _ = x.size()
        y1 = self.avg_pool1(x).view(b, c)  # like resize() in numpy
        y2 = self.avg_pool2(x).view(b, 4 * c)
        y3 = self.avg_pool4(x).view(b, 16 * c)
        y = torch.cat((y1, y2, y3), 1)
        y = self.fc(y)
        b, out_channel = y.size()
        y = y.view(b, out_channel, 1, 1)
        return y

ECA-Net

《ECANet:Efficient Channel Attention for Deep Convolutional Neural Networks》发表于CVPR 2020,是对SE-Net中特征变换部分进行了改进。SE-Net的通道信息交互方式是通过全连接实现的,在降维和升维的过程中会损害一部分的特征表达。ECA-Net则进一步地利用一维卷积来实现通道间的信息交互,相对于全连接实现的全局通道信息交互所带来的计算开销,ECA-Net提出了一种基于自适应选择卷积核大小的方法,以实现局部交互,从而显著地降低模型复杂度且保持性能。
在这里插入图片描述

class ECALayer(nn.Module):
    """Constructs a ECA module.
    Args:
        channel: Number of channels of the input feature map
        k_size: Adaptive selection of kernel size
    """
    def __init__(self, channel, k_size=3):
        super(ECALayer, self).__init__()
        self.avg_pool = nn.AdaptiveAvgPool2d(1)
        self.conv = nn.Conv1d(1, 1, kernel_size=k_size, padding=(k_size - 1) // 2, bias=False) 
        self.sigmoid = nn.Sigmoid()

    def forward(self, x):
        # feature descriptor on the global spatial information
        y = self.avg_pool(x)
        # Two different branches of ECA module
        y = self.conv(y.squeeze(-1).transpose(-1, -2)).transpose(-1, -2).unsqueeze(-1)
        # Multi-scale information fusion
        y = self.sigmoid(y)

        return x * y.expand_as(x)

混合注意力

BAM

《BAM: Bottleneck Attention Module》发表于BMC 2018,提出了一个简单有效的注意力模型来获取空间和通道的注意力图。在这里插入图片描述
BAM形成了一种分层的注意力机制,可以有效地抑制背景特征,使模型更加聚焦于前景特征,从而加强高级语义,实现更高的性能。

CBAM

CBAM同样是使用空间注意力和通道注意力,不过与BAM不同的是,通道注意力并不是像BAM那样融合在空间注意力内再做归一化,而是先后分开进行。
在这里插入图片描述
通道注意力的生成方式:先在feature maps上进行全局最大池化和全局平均池化得到两个1维向量,再经过共享的MLP层,再进行相加,sigmoid归一化。
空间注意力的生成方式:在通道上进行最大池化和平均池化,得到两个feature map,经过7x7卷积,得到一个feature map,再BN,sigmoid归一化。
在这里插入图片描述

##Resnet-CBAM
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)
        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  # 广播机制
        out = self.sa(out) * out  # 广播机制
        if self.downsample is not None:
            residual = self.downsample(x)
        out += residual
        out = self.relu(out)
        return out
        
##直接单独加入CBAM:
class cbam(nn.Module):
 	def __init__(self, planes):
        self.ca = ChannelAttention(planes)# planes是feature map的通道个数
        self.sa = SpatialAttention()
     def forward(self, x):
        x = self.ca(out) * x  # 广播机制
        x = self.sa(out) * x  # 广播机制

scSE

《Concurrent Spatial and Channel Squeeze & Excitation in Fully Convolutional Networks》发表于MICCAI 2018,是一种更轻量化的SE-Net变体,在SE的基础上提出cSE、sSE、scSE这三个变种。cSE和sSE分别是根据通道和空间的重要性来校准采样。scSE则是同时进行两种不同采样校准,得到一个更优异的结果。
在这里插入图片描述

class SCSEModule(nn.Module):
    def __init__(self, ch, re=16):
        super().__init__()
        self.cSE = nn.Sequential(nn.AdaptiveAvgPool2d(1),
                                 nn.Conv2d(ch,ch//re,1),
                                 nn.ReLU(inplace=True),
                                 nn.Conv2d(ch//re,ch,1),
                                 nn.Sigmoid())
        self.sSE = nn.Sequential(nn.Conv2d(ch,ch,1),
                                 nn.Sigmoid())
    def forward(self, x):
        return x * self.cSE(x) + x * self.sSE(x)

A2-Nets

《A2-Nets: Double Attention Networks》发表于NIPS 2018,提出了一种双重注意力网络。该网络首先使用二阶的注意力池化(Second-order Attention Pooling, SAP) 用于将整幅图的所有关键特征归纳到一个集合当中,然后再利用另一种注意力机制将这些特征分别应用到图像中的每个区域。
在这里插入图片描述

class DoubleAtten(nn.Module):
    """
    A2-Nets: Double Attention Networks. NIPS 2018
    """
    def __init__(self,in_c):
        super(DoubleAtten,self).__init__()
        self.in_c = in_c
        """Convolve the same input feature map to produce three feature maps with the same scale, i.e., A, B, V (as shown in paper).
        """
        self.convA = nn.Conv2d(in_c,in_c,kernel_size=1)
        self.convB = nn.Conv2d(in_c,in_c,kernel_size=1)
        self.convV = nn.Conv2d(in_c,in_c,kernel_size=1)
    def forward(self,input):

        feature_maps = self.convA(input)
        atten_map = self.convB(input)
        b, _, h, w = feature_maps.shape

        feature_maps = feature_maps.view(b, 1, self.in_c, h*w) # reshape A
        atten_map = atten_map.view(b, self.in_c, 1, h*w)       # reshape B to generate attention map
        global_descriptors = torch.mean((feature_maps * F.softmax(atten_map, dim=-1)),dim=-1) # Multiply the feature map and the attention weight map to generate a global feature descriptor

        v = self.convV(input)
        atten_vectors = F.softmax(v.view(b, self.in_c, h*w), dim=-1) # 生成 attention_vectors
        out = torch.bmm(atten_vectors.permute(0,2,1), global_descriptors).permute(0,2,1)

        return out.view(b, _, h, w)

Coordinate Attention(2021)

这篇论文基于SE和CBAM改进而来,作者认为SE没有考虑空间信息,CBAM通过对每个位置的通道上进行池化,由于经过几层卷积和降采样后的feature maps的每个位置只包含原图的一个局部区域,因此这种做法只考虑了局部区域信息。为此,作者提出了一种新的attention机制–Coordinate Attention。
在这里插入图片描述

Coordinate Attention利用两个1D全局池化操作将沿垂直和水平方向的input features分别聚合为两个单独的direction-aware feature maps。 然后将具有嵌入的特定方向信息的这两个特征图分别编码为两个attention map,每个attention map都沿一个空间方向捕获输入特征图的远距离依存关系。 位置信息因此可以被保存在所生成的attention map中。 然后通过乘法将两个attention map都应用于input feature maps,以强调注意区域的表示。

import torch
from torch import nn


class CA_Block(nn.Module):
    def __init__(self, channel, h, w, reduction=16):
        super(CA_Block, self).__init__()

        self.h = h
        self.w = w

        self.avg_pool_x = nn.AdaptiveAvgPool2d((h, 1))
        self.avg_pool_y = nn.AdaptiveAvgPool2d((1, w))

        self.conv_1x1 = nn.Conv2d(in_channels=channel, out_channels=channel//reduction, kernel_size=1, stride=1, bias=False)

        self.relu = nn.ReLU()
        self.bn = nn.BatchNorm2d(channel//reduction)

        self.F_h = nn.Conv2d(in_channels=channel//reduction, out_channels=channel, kernel_size=1, stride=1, bias=False)
        self.F_w = nn.Conv2d(in_channels=channel//reduction, out_channels=channel, kernel_size=1, stride=1, bias=False)

        self.sigmoid_h = nn.Sigmoid()
        self.sigmoid_w = nn.Sigmoid()

    def forward(self, x):

        x_h = self.avg_pool_x(x).permute(0, 1, 3, 2)
        x_w = self.avg_pool_y(x)

        x_cat_conv_relu = self.relu(self.conv_1x1(torch.cat((x_h, x_w), 3)))

        x_cat_conv_split_h, x_cat_conv_split_w = x_cat_conv_relu.split([self.h, self.w], 3)

        s_h = self.sigmoid_h(self.F_h(x_cat_conv_split_h.permute(0, 1, 3, 2)))
        s_w = self.sigmoid_w(self.F_w(x_cat_conv_split_w))

        out = x * s_h.expand_as(x) * s_w.expand_as(x)

        return out


if __name__ == '__main__':
    x = torch.randn(1, 16, 128, 64)    # b, c, h, w
    ca_model = CA_Block(channel=16, h=128, w=64)
    y = ca_model(x)
    print(y.shape)

自注意力

Non-Local 位置像素注意力

《Non-local Neural Networks》发表于CVPR 2018,是第一篇将自注意力机制引入图像领域的文章。文中提出了经典的Non-Local模块,通过Self-Attention机制对全局上下午进行建模,有效地捕获长距离的特征依赖。后续许多基于自注意力的方法都是根据Non-Local来改进的。
在这里插入图片描述
自注意力流程一般是通过将原始特征图映射为三个向量分支,即Query、Key和Value。
首先,计算Q和K的相关性权重矩阵系数;
其次,通过软操作对权重矩阵进行归一化;
最后,再将权重系数叠加到V上,以实现全局上下文信息的建模。

class NonLocalBlockND(nn.Module):

    def __init__(self,
                 in_channels,
                 inter_channels=None,
                 dimension=2,
                 sub_sample=True,
                 bn_layer=True):
        super(NonLocalBlockND, self).__init__()


        assert dimension in [1, 2, 3]


        self.dimension = dimension
        self.sub_sample = sub_sample


        self.in_channels = in_channels
        self.inter_channels = inter_channels


        if self.inter_channels is None:
            self.inter_channels = in_channels // 2
            # 进行压缩得到channel个数
            if self.inter_channels == 0:
                self.inter_channels = 1


        if dimension == 3:
            conv_nd = nn.Conv3d
            max_pool_layer = nn.MaxPool3d(kernel_size=(1, 2, 2))
            bn = nn.BatchNorm3d
        elif dimension == 2:
            conv_nd = nn.Conv2d
            max_pool_layer = nn.MaxPool2d(kernel_size=(2, 2))
            bn = nn.BatchNorm2d
        else:
            conv_nd = nn.Conv1d
            max_pool_layer = nn.MaxPool1d(kernel_size=(2))
            bn = nn.BatchNorm1d


        self.g = conv_nd(in_channels=self.in_channels,
                         out_channels=self.inter_channels,
                         kernel_size=1,
                         stride=1,
                         padding=0)


        if bn_layer:
            self.W = nn.Sequential(
                conv_nd(in_channels=self.inter_channels,
                        out_channels=self.in_channels,
                        kernel_size=1,
                        stride=1,
                        padding=0), bn(self.in_channels))
            nn.init.constant_(self.W[1].weight, 0)
            nn.init.constant_(self.W[1].bias, 0)
        else:
            self.W = conv_nd(in_channels=self.inter_channels,
                             out_channels=self.in_channels,
                             kernel_size=1,
                             stride=1,
                             padding=0)
            nn.init.constant_(self.W.weight, 0)
            nn.init.constant_(self.W.bias, 0)


        self.theta = conv_nd(in_channels=self.in_channels,
                             out_channels=self.inter_channels,
                             kernel_size=1,
                             stride=1,
                             padding=0)
        self.phi = conv_nd(in_channels=self.in_channels,
                           out_channels=self.inter_channels,
                           kernel_size=1,
                           stride=1,
                           padding=0)


        if sub_sample:
            self.g = nn.Sequential(self.g, max_pool_layer)
            self.phi = nn.Sequential(self.phi, max_pool_layer)


    def forward(self, x):
        '''
        :param x: (b, c,  h, w)
        :return:
        '''


        batch_size = x.size(0)


        g_x = self.g(x).view(batch_size, self.inter_channels, -1)#[bs, c, w*h]
        g_x = g_x.permute(0, 2, 1)


        theta_x = self.theta(x).view(batch_size, self.inter_channels, -1)
        theta_x = theta_x.permute(0, 2, 1)


        phi_x = self.phi(x).view(batch_size, self.inter_channels, -1)
        
        f = torch.matmul(theta_x, phi_x)


        # print(f.shape)


        f_div_C = F.softmax(f, dim=-1)


        y = torch.matmul(f_div_C, g_x)
        y = y.permute(0, 2, 1).contiguous()
        y = y.view(batch_size, self.inter_channels, *x.size()[2:])
        W_y = self.W(y)
        z = W_y + x
        #print(z.shape)

DA-Net 位置像素注意力+通道注意力模块

《DA-Net:Dual Attention Network for Scene Segmentation》发表于CVPR 2019,该论文将Non-local的思想同时引入到了通道域和空间域,分别将空间像素点以及通道特征作为查询语句进行上下文建模,自适应地整合局部特征和全局依赖。
在这里插入图片描述

ANLNet

《ANLNet:Asymmetric Non-local Neural Networks for Semantic Segmentation》发表于ICCV 2019,是基于Non-Local的思路往轻量化方向做改进。Non-Local模块是一种效果显著的技术,但同时也受限于过大计算量而难以很好地嵌入网络中应用。为了解决以上问题,ANLNet基于Non-Local结构并融入了金字塔采样模块,在充分考虑了长距离依赖的前提下,融入了不同层次的特征,从而在保持性能的同时极大地减少计算量。
在这里插入图片描述
在这里插入图片描述
结合SPP和Non-Local,前者从不同大小区域内提取出关键点,后者对这些关键点建模长距离依赖;
Non-Local 需要计算每一个像素点,可以看作是点对点建模;ANL-Net只计算通过SPP提取出的关键点,可以看作是点对区域建模;

CC-Net

《CCNet:Criss-Cross Attention for Semantic Segmentation》发表于ICCV 2019,同样是同Non-Local轻量化的另一种尝试。
在这里插入图片描述
与Non-Local的每个查询点需要与其它所有点计算相关性的建模方式不同,CC-Net仅计算该查询点与其在水平和垂直方向上的点相关性,并且重复计算两次就可以获取该点的全局依赖,极大减少计算量。

import torch
import torch.nn as nn
import torch.nn.functional as F
from torch.nn import Softmax
print("CC Moudle")
def INF(B,H,W):
     return -torch.diag(torch.tensor(float("inf")).cuda().repeat(H),0).unsqueeze(0).repeat(B*W,1,1)
class CC_module(nn.Module):
    def __init__(self,in_dim):
        super(CC_module, self).__init__()
        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.softmax = Softmax(dim=3)
        self.INF = INF
        self.gamma = nn.Parameter(torch.zeros(1))
    def forward(self, x):
        m_batchsize, _, height, width = x.size()
        proj_query = self.query_conv(x)
        proj_query_H = proj_query.permute(0,3,1,2).contiguous().view(m_batchsize*width,-1,height).permute(0, 2, 1)
        proj_query_W = proj_query.permute(0,2,1,3).contiguous().view(m_batchsize*height,-1,width).permute(0, 2, 1)
        proj_key = self.key_conv(x)
        proj_key_H = proj_key.permute(0,3,1,2).contiguous().view(m_batchsize*width,-1,height)
        proj_key_W = proj_key.permute(0,2,1,3).contiguous().view(m_batchsize*height,-1,width)
        proj_value = self.value_conv(x)
        proj_value_H = proj_value.permute(0,3,1,2).contiguous().view(m_batchsize*width,-1,height)
        proj_value_W = proj_value.permute(0,2,1,3).contiguous().view(m_batchsize*height,-1,width)
        energy_H = (torch.bmm(proj_query_H, proj_key_H)+self.INF(m_batchsize, height, width)).view(m_batchsize,width,height,height).permute(0,2,1,3)
        energy_W = torch.bmm(proj_query_W, proj_key_W).view(m_batchsize,height,width,width)
        concate = self.softmax(torch.cat([energy_H, energy_W], 3))

        att_H = concate[:,:,:,0:height].permute(0,2,1,3).contiguous().view(m_batchsize*width,height,height)
        #print(concate)
        #print(att_H) 
        att_W = concate[:,:,:,height:height+width].contiguous().view(m_batchsize*height,width,width)
        out_H = torch.bmm(proj_value_H, att_H.permute(0, 2, 1)).view(m_batchsize,width,-1,height).permute(0,2,3,1)
        out_W = torch.bmm(proj_value_W, att_W.permute(0, 2, 1)).view(m_batchsize,height,-1,width).permute(0,2,1,3)
        #print(out_H.size(),out_W.size())
        return self.gamma*(out_H + out_W) + x

GC-Net

《GCNet: Non-local Networks Meet Squeeze-Excitation Networks and Beyond》发表于ICCV 2019,受SE-Net和Non-local思想的启发提出了一种更简化的空间自注意力模块。Non-local采用Self-attention机制来建模全局的像素对关系,建模长距离依赖,但这种基于全局像素点(pixel-to-pixel) 对的建模方式其计算量无疑是巨大的。SE-Net则利用GAP和MLP完成通道之间的特征重标定,虽然轻量,但未能充分利用到全局上下文信息。因此,作者提出了GC-Net可以高效的建模全局的上下文信息。
在这里插入图片描述

类别注意力

OCR-Net[30]

《Object-Contextual Representations for SemanticSegmentation》发表于ECCV 2020,是一种基于自注意力对类别信息进行建模的方法。与先前的自注意力对全局上下文建模的角度(通道和空间)不同,OCR-Net是从类别的角度进行建模,其利用粗分割的结果作为建模的对象,最后加权到每一个查询点,这是一种轻量并有效的方法。
在这里插入图片描述
Soft Object Regions 对Backbone倒数第二层所输出的粗分割结果进行监督;
Object Region Representations 融合粗分割和Backbone网络最后一层所输出的高级语义特征图生成对象区域语义,每一条向量代表不同的类别信息;
Pixel-Region Relations 结合最后一层的高级语义特征图以及对象区域语义信息,建模像素与对象区域之间的相关性;
Object Contextual Representations 将像素-对象区域相关性加权到对象区域信息中,完成加权目标类别信息到每一个像素上; 不难发现,这种类别信息的建模方式是完全遵循自注意力机制(Q,K,V)的。

全局注意力

RGA-Net

《Relation-Aware Global Attention for Person Re-identification》发表于CVPR 2020,作者针对行人重识别任务提出了的一种基于关系感知的全局注意力方法。作者认为,要直观地判断一个特征节点是否重要,首先要知道其全局范围的特征信息,以便在决策的过程中更好地探索每个特征节点各自的全局关系,从而学习出更鲁棒的注意力特征。
在这里插入图片描述

3D注意力模块

SimAM(2021)

本文提出一种概念简单且非常有效的注意力模块。不同于现有的通道/空域注意力模块,该模块无需额外参数为特征图推导出3D注意力权值。具体来说,本文基于著名的神经科学理论提出优化能量函数以挖掘神经元的重要性。本文进一步针对该能量函数推导出一种快速解析解并表明:该解析解仅需不超过10行代码即可实现。该模块的另一个优势在于:大部分操作均基于所定义的能量函数选择,避免了过多的结构调整。最后,本文在不同的任务上对所提注意力模块的有效性、灵活性进行验证。
在这里插入图片描述
通道注意力:1D注意力,它对不同通道区别对待,对所有位置同等对待;
空域注意力:2D注意力,它对不同位置区别对待,对所有通道同等对待。

PSA:极化自注意力(2021)

注意力机制根据施加的维度大致可以分为两类:通道注意力和空间注意力。对于通道注意力机制,代表性的工作有SENet[2]、ECANet[3];对于空间注意力机制,代表性的工作有Self-Attention[4]。随着空间和通道注意力机制的提出,很自然的,结合空间和通道两个维度的双重注意力机制也被提出,代表工作有CBAM[1],DANet[5]。

基于双重注意力机制,本文针对Pixel-wise regression的任务,提出了一种更加精细的双重注意力机制——极化自注意力(Polarized Self-Attention)。作为一个即插即用的模块,在人体姿态估计和语义分割任务上,作者将它用在了以前的SOTA模型上,并达到了新的SOTA性能,霸榜COCO人体姿态估计和Cityscapes语义分割。
在这里插入图片描述

总结

在计算机视觉领域中,注意力机制大致可分为强注意力和软注意力。由于强注意力是一种随机的预测,其强调的是动态变化,虽然效果不错,但由于不可微的性质导致其应用很受限制。与之相反的是,软注意力是处处可微的,即能够通过基于梯度下降法的神经网络训练所获得,因此其应用相对来说也比较广泛,本文所列举的注意力方法均为软注意力方式。总的来说,目前所有的注意力机制方法大都是基于各个不同的维度利用有限的资源进行信息的充分利用,本质作用是增强重要特征,抑制非重要特征。注意力机制的特点是参数少-速度快-效果好。

注意力机制深度学习中被广泛应用于各种任务和模型中。以下是一些常见的注意力机制分类: 1. 经典注意力机制(Classical Attention Mechanisms): - 点积注意力(Dot-Product Attention):通过计算查询向量和键向量之间的点积,然后进行归一化来计算权重。 - 加性注意力(Additive Attention):通过将查询向量和键向量映射到一个共享的中间表示,并计算它们之间的相似度来计算权重。 2. 缩放点积注意力(Multi-Head Attention):将输入进行多次线性变换,然后对每个变换后的结果应用点积注意力,最后将所有结果拼接起来形成最终的输出。 3. 自注意力机制(Self-Attention): - Transformer模型中的自注意力机制:将输入序列中的每个元素视为同时充当查询、键和值,并计算它们之间的相似度来计算权重。 - Long Short-Term Memory(LSTM)中的门控自注意力机制:通过计算输入序列中每个元素与自身的相似度来计算权重。 4. 全局平均池化(Global Average Pooling)注意力:对输入序列进行平均池化操作,将所有元素的特征进行平均得到一个全局特征表示。 5. 局部注意力(Local Attention):在输入序列中的每个位置上计算一个权重向量,然后将权重向量应用于值向量以获得最终的输出。 这只是一些常见的注意力机制分类,实际上还有很多其他变体和改进。注意力机制的选择取决于任务和模型的需求。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值