目录
3.2 Coordinate Attention Block
摘要
最近对移动网络设计的研究已经证明了通道注意力(例如,Squeeze-and-Excitation attention)对于提升模型性能的显着有效性,但他们通常忽略了位置信息,这对于生成空间选择性注意力图很重要。在本文中,我们通过将位置信息嵌入到通道注意力中来为移动网络提出一种新的注意力机制,我们称之为“坐标注意力”。与通过 2D 全局池化将特征张量转换为单个特征向量的通道注意力不同,坐标注意力将通道注意力分解为两个一维特征编码过程,分别沿两个空间方向聚合特征。通过这种方式,可以沿一个空间方向捕获远程依赖关系,同时可以沿另一个空间方向保留精确的位置信息。然后将得到的特征图单独编码成一对方向感知和位置敏感的注意力图,这些图可以互补地应用于输入特征图以增强感兴趣对象的表示。我们的坐标注意力很简单,可以灵活地插入到经典的移动网络中,例如 MobileNetV2、MobileNeXt 和 EfficientNet,几乎没有计算开销。大量实验表明,我们的坐标注意力不仅有利于 ImageNet 分类,而且更有趣的是,在下游任务中表现更好,例如对象检测和语义分割。代码地址为: https://github.com/Andrew- Qibin/CoordAttention 。
1 介绍
注意力机制用于告诉模型“what”和“where”,已被广泛研究和广泛部署,以提高现代深度神经网络的性能。 然而,它们在移动网络(模型大小有限)上的应用明显落后于大型网络,这主要是因为大多数注意力机制带来的计算开销对于移动网络来说是负担不起的。
考虑到移动网络计算能力的限制,迄今为止,移动网络最流行的注意力机制仍然是 Squeeze-andExcitation (SE) attention。 它在2D全局池化的帮助下计算通道注意力,并以相当低的计算成本提供显着的性能提升。 然而,SE注意力只考虑编码通道间信息而忽略了位置信息的重要性,这对于在视觉任务中捕获对象结构至关重要。 后来的工作,如BAM和CBAM,试图通过减少输入张量的通道维度,然后使用卷积计算空间注意力来利用位置信息,如图 2(b) 所示。 然而,卷积只能捕获局部关系,而无法对视觉任务必不可少的远程依赖进行建模。
在本文中,除了第一项工作之外,我们通过将位置信息嵌入到通道注意力中来提出一种新颖有效的注意力机制,使移动网络能够参与大区域,同时避免产生大量计算开销。为了减轻由 2D 全局池化引起的位置信息丢失,我们将通道注意力分解为两个并行的一维特征编码过程,以有效地将空间坐标信息整合到生成的注意力图中。具体来说,我们的方法利用两个一维全局池化操作分别将垂直和水平方向的输入特征聚合成两个独立的方向感知特征图。这两个嵌入了方向特定信息的特征图然后被分别编码成两个注意力图,每个图都捕获输入特征图沿一个空间方向的长程依赖关系。位置信息因此可以保留在生成的注意力图中。然后通过乘法将两个注意力图应用于输入特征图以强调感兴趣的表示。我们将所提出的注意力方法命名为坐标注意力,因为它的操作区分空间方向(即坐标)并生成坐标感知注意力图。
我们的坐标注意力具有以下优点。 首先,它不仅捕获跨通道信息,还捕获方向感知和位置敏感信息,这有助于模型更准确地定位和识别感兴趣的对象。 其次,我们的方法灵活且轻量级,可以轻松插入移动网络的经典构建块,例如 MobileNetV2 中提出的倒置残差块和 MobileNeXt 中提出的沙漏块,以通过强调信息表示来增强特征。 第三,作为预训练模型,我们的协调注意力可以为移动网络的下游任务带来显着的性能提升,特别是对于那些具有密集预测(例如语义分割)的任务,我们将在实验部分展示。
为了证明所提出的方法相对于以前的移动网络注意力方法的优势,我们在 ImageNet 分类和流行的下游任务(包括对象检测和语义分割)中进行了大量实验。 有了相当数量的可学习参数和计算,我们的网络在 ImageNet 上的 top-1 分类精度上实现了 0.8% 的性能提升。 在对象检测和语义分割中,与图1中显示的其他注意力机制的模型相比,我们也观察到了显着的改进。我们希望我们简单有效的设计能够促进未来移动网络注意力机制的发展。
2 相关工作
2.1 Mobile Network
最近的很多关于Mobile Network的工作,大多数都是基于深度可分离卷积和inverted残差模块:
-
HBONet:在每个inverted残差模块中引入下采样操作,用于建模具有代表性的空间信息。
-
ShuffleNetV2:在inverted残差模块之前和之后使用通道分割模块和通道shuffle模块。
-
MobileNetV3:结合神经网络结构搜索算法,寻找最优激活函数和不同深度的inverted残差块的扩展比。
-
MixNet、EfficientNet和ProxylessNAS:也采用不同的搜索策略来搜索深度可分卷积的最优核大小或标量,从而从扩展比、输入分辨率、网络深度和宽度等方面控制网络权值。
-
最近,有学者重新思考了基于深度可分离卷积的方法,专门设计了基于Mobile Network的bottleneck结构,并基于此设计 MobileNeXt。
2.2 注意力机制
想必大家都已经知道注意力机制在各种计算机视觉任务中都是有帮助,如图像分类和图像分割。其中最为经典和被熟知的便是SENet,它通过简单地squeeze每个2维特征图,进而有效地构建通道之间的相互依赖关系。
CBAM进一步推进了这一思想,通过大尺度核卷积引入空间信息编码。后来的研究如GENet、GALA、AA、TA,通过采用不同的空间注意力机制或设计高级注意力块,扩展了这一理念。
Non-local/self-attention Network则着重于构建spatial或channel注意力。典型的例子包括NLNet、GCNet、A2Net、SCNet、gsopnet和CCNet,它们都利用Non-local机制来捕获不同类型的空间信息。然而,由于self-attention模块内部计算量大,常被用于大型模型中,不适用于Mobile Network。
与Non-local/self-attention的方法不同,CA方法考虑了一种更有效的方法来捕获位置信息和通道关系,以增强Mobile Network的特征表示。通过将二维全局池操作分解为两个一维编码过程,本文方法比其他具有轻量级属性的注意力方法(如SENet、CBAM和TA)运行得更好。
3 Coordinate Attention
一个coordinate attention块可以被看作是一个计算单元,旨在增强Mobile Network中特征的表达能力。它可以将任何中间特征张量作为输入并通过转换输出了与 张量具有相同size同时具有增强表征的
。为了更加清晰的描述CA注意力,这里先对SE block进行讨论。
3.1 Revisit SE Block
在结构上,SE block可分解为Squeeze和Excitation 2步,分别用于全局信息嵌入和通道关系的自适应Re-weight。
3.1.1 Squeeze
在输入X的条件下,第c通道的squeeze步长可表示为:
式中, 是与第c通道相关的输出。
输入X来自一个固定核大小的卷积层,因此可以看作是局部描述符的集合。Sqeeze操作使模型收集全局信息成为可能。
3.1.2 Excitation
Excitation的目的是完全捕获通道之间的依赖,它可以被表述为:
其中为通道乘法,
为sigmoid激活函数,z为变换函数生成的结果,公式如下:
这里, T1和T2是2个线性变换,可以通过学习来捕捉每个通道的重要性。
3.1.3 为什么SE Block不好?
SE Block虽然近2年来被广泛使用;然而,它只考虑通过建模通道关系来重新衡量每个通道的重要性,而忽略了位置信息,但是位置信息对于生成空间选择性attention maps是很重要的。因此作者引入了一种新的注意块,它不仅仅考虑了通道间的关系还考虑了特征空间的位置信息。
3.2 Coordinate Attention Block
Coordinate Attention通过精确的位置信息对通道关系和长期依赖性进行编码,具体操作分为Coordinate信息嵌入和Coordinate Attention生成2个步骤。
3.2.1 Coordinate信息嵌入
全局池化方法通常用于通道注意编码空间信息的全局编码,但由于它将全局空间信息压缩到通道描述符中,导致难以保存位置信息。为了促使注意力模块能够捕捉具有精确位置信息的远程空间交互,本文按照以下公式分解了全局池化,转化为一对一维特征编码操作:
具体来说,给定输入X ,首先使用尺寸为(H,1)或(1,W)的pooling kernel分别沿着水平坐标和垂直坐标对每个通道进行编码。因此,高度为h的第c通道的输出可以表示为:
同样,宽度为w的第c通道的输出可以写成:
上述2种变换分别沿两个空间方向聚合特征,得到一对方向感知的特征图。这与在通道注意力方法中产生单一的特征向量的SE Block非常不同。这2种转换也允许注意力模块捕捉到沿着一个空间方向的长期依赖关系,并保存沿着另一个空间方向的精确位置信息,这有助于网络更准确地定位感兴趣的目标。
3.2.2 Coordinate Attention生成
通过3.2.1所述,本文方法可以通过上述的变换可以很好的获得全局感受野并编码精确的位置信息。为了利用由此产生的表征,作者提出了第2个转换,称为Coordinate Attention生成。这里作者的设计主要参考了以下3个标准:
-
首先,对于Mobile环境中的应用来说,新的转换应该尽可能地简单;
-
其次,它可以充分利用捕获到的位置信息,使感兴趣的区域能够被准确地捕获;
-
最后,它还应该能够有效地捕捉通道间的关系。
通过信息嵌入中的变换后,该部分将上面的变换进行concatenate操作,然后使用 卷积变换函数 对其进行变换操作:
最后,Coordinate Attention Block的输出Y可以写成:
4. 实验
4.1 消融实验
当水平注意力和垂直注意力结合时得到了最好的结果,如表1所示。实验结果表明,Coordinate Information Embedding在图像分类中,可以在保证参数量的情况下提升精度。
4.2 与其他Attention进行比较
可以看出,添加SE attention已经使分类性能提高了1%以上。对于CBAM与SE注意相比,似乎在Mobile Network中没有提升。然而,当使用本文所提出的CA注意力时,取得了最好的结果。
在下图中,作者还将使用不同注意力方法的模型生成的特征图进行了可视化。显然,CA注意力比SE和CBAM更有助于目标的定位。
4.3 Stronger Baseline
为了检验所提CA注意力在EfficientNet上的表现,作者简单地用CA注意力代替SE。对于其他设置遵循原始文件。结果如表5。与原有的含SE的EfficientNet-b0方法以及其他与EfficientNet-b0的方法相比,CA注意力络获得了最好的结果。这也所提出的CA注意力在强大的Mobile Network中仍然具有良好的性能。
4.4 目标检测实验
作者通过实验观察到SE和CBAM并不能改善Baseline的性能。然而,增加CA注意力可以很大程度上提高平均AP从71.7%到73.1%。在COCO和Pascal VOC数据集上的检测实验都表明,与其他注意力方法相比,具有CA注意力的分类模型具有更好的迁移能力。
4.5 语义分割实验
从表8可以看出,具有CA注意力的模型比vanilla MobileNetV2使用其他注意力的模型的表现要好得多。
5 CA Block的PyTorch实现
import torch
import torch.nn as nn
import math
import torch.nn.functional as F
class h_sigmoid(nn.Module):
def __init__(self, inplace=True):
super(h_sigmoid, self).__init__()
self.relu = nn.ReLU6(inplace=inplace)
def forward(self, x):
return self.relu(x + 3) / 6
class h_swish(nn.Module):
def __init__(self, inplace=True):
super(h_swish, self).__init__()
self.sigmoid = h_sigmoid(inplace=inplace)
def forward(self, x):
return x * self.sigmoid(x)
class CoordAtt(nn.Module):
def __init__(self, inp, oup, reduction=32):
super(CoordAtt, self).__init__()
self.pool_h = nn.AdaptiveAvgPool2d((None, 1))
self.pool_w = nn.AdaptiveAvgPool2d((1, None))
mip = max(8, inp // reduction)
self.conv1 = nn.Conv2d(inp, mip, kernel_size=1, stride=1, padding=0)
self.bn1 = nn.BatchNorm2d(mip)
self.act = h_swish()
self.conv_h = nn.Conv2d(mip, oup, kernel_size=1, stride=1, padding=0)
self.conv_w = nn.Conv2d(mip, oup, kernel_size=1, stride=1, padding=0)
def forward(self, x):
identity = x
n,c,h,w = x.size()
x_h = self.pool_h(x)
x_w = self.pool_w(x).permute(0, 1, 3, 2)
y = torch.cat([x_h, x_w], dim=2)
y = self.conv1(y)
y = self.bn1(y)
y = self.act(y)
x_h, x_w = torch.split(y, [h, w], dim=2)
x_w = x_w.permute(0, 1, 3, 2)
a_h = self.conv_h(x_h).sigmoid()
a_w = self.conv_w(x_w).sigmoid()
out = identity * a_w * a_h
return out