本文改进:感受野注意力卷积运算(RFAConv),解决卷积块注意力模块(CBAM)和协调注意力模块(CA)只关注空间特征,不能完全解决卷积核参数共享的问题
RFAConv| 亲测在多个数据集能够实现大幅涨点,有的数据集达到3个点以上
论文:https://arxiv.org/pdf/2304.03198.pdf
摘要:空间注意力已被广泛用于提高卷积神经网络的性能。 然而,它有一定的局限性。 在本文中,我们提出了空间注意力有效性的新视角,即空间注意力机制本质上解决了卷积核参数共享的问题。 然而,空间注意力生成的注意力图中包含的信息对于大尺寸的卷积核来说是不够的。 因此,我们提出了一种新颖的注意力机制,称为感受野注意力(RFA)。 现有的空间注意力,例如卷积块注意力模块(CBAM)和协调注意力(CA)仅关注空间特征,并没有完全解决卷积核参数共享的问题。 相比之下,RFA 不仅关注感受野空间特征,还为大尺寸卷积核提供有效的注意力权重。 RFA 开发的感受野注意力卷积运算(RFAConv)代表了一种替代标准卷积运算的新方法。 它提供的计算成本和参数增量几乎可以忽略不计,同时显着提高了网络性能。 我们在 ImageNet-1k、COCO 和 VOC 数据集上进行了一系列实验,以证明我们方法的优越性。 特别重要的是,我们认为现在是时候将当前空间注意机制的焦点从空间特征转移到感受野空间特征了。 这样,我们就可以进一步提升网络性能,取得更好的效果。
关于感受野空间特征,我们提出感受野注意(RFA)。 这种方法不仅强调感受野滑块内不同特征的重要性,而且优先考虑感受野空间特征。 通过这种方法,彻底解决了卷积核参数共享的问题。 感受野空间特征是根据卷积核的大小动态生成的,因此,RFA是卷积的固定组合,离不开卷积运算的帮助,同时依靠RFA来提高性能,所以我们 提出感受野注意卷积(RFAConv)。 具有3×3尺寸卷积核的RFAConv的整体结构如图2所示。
作者设计了一种新的CBAM和CA,称为RFACBAM和RFACA,它专注于感受野的空间特征。与RFA类似,使用stride为k的k×k的最终卷积运算来提取特征信息,具体结构如图4和图5所示,将这2种新的卷积方法称为RFCBAMConv和RFCAConv。比较原始的CBAM,使用SE注意力来代替RFCBAM中的CAM。因为这样可以减少计算开销。
实验结果
分类
目标检测
核心代码:
class DyCAConv(nn.Module):
def __init__(self, inp, oup, kernel_size, stride, reduction=32):
super(DyCAConv, 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, inp, kernel_size=1, stride=1, padding=0)
self.conv_w = nn.Conv2d(mip, inp, kernel_size=1, stride=1, padding=0)
self.conv = nn.Sequential(nn.Conv2d(inp, oup, kernel_size, padding=kernel_size // 2, stride=stride),
nn.BatchNorm2d(oup),
nn.SiLU())
self.dynamic_weight_fc = nn.Sequential(
nn.Linear(inp, 2),
nn.Softmax(dim=1)
)
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()
# Compute dynamic weights
x_avg_pool = nn.AdaptiveAvgPool2d(1)(x)
x_avg_pool = x_avg_pool.view(x.size(0), -1)
dynamic_weights = self.dynamic_weight_fc(x_avg_pool)
out = identity * (dynamic_weights[:, 0].view(-1, 1, 1, 1) * a_w +
dynamic_weights[:, 1].view(-1, 1, 1, 1) * a_h)
return self.conv(out)
详见:
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。