当前位置:   article > 正文

ECA-Net: Efficient Channel Attention for Deep Convolutional Neural Networks论文详解_eca_resnet50 expand_as

eca_resnet50 expand_as

论文链接:https://arxiv.org/abs/1910.03151

代码地址:https://github.com/BangguWu/ECANet

摘要

现有的注意力方法开发更复杂的注意力模块来提升性能,增加了计算负担。本文提出了一个有效的通道注意(ECA)模块,它只涉及少量的(k<=9)参数,但带来了明显的性能增益。

通过对SENet通道注意力模块的分析,证明了避免降维和适当的跨通道信息交互对于学习有效的通道注意非常重要。文中提出了一种不降维的局部交叉通道交互策略,该策略可以通过一维卷积有效地实现。此外,我们提出了一个通道维数的函数来自适应地确定一维卷积的核大小,它代表了局域交叉通道相互作用的覆盖范围。我们以ResNets和MobileNetV2为骨干,对ECA模块在图像分类、目标检测和实例分割方面进行了广泛的评估。实验结果表明,该模块在性能上优于其他模块,具有较高的效率。

相关工作

注意机制已被证明是增强深度CNNs的潜在手段。SE-Net首次提出了一种有效的通道注意学习机制,取得了良好的效果。随后,注意模块的开发大致可以分为两个方向:(1)增强特征聚合;(2)通道与空间注意相结合。具体来说,CBAM使用平均池化和最大池化来聚合特性。GSoP引入了一个二阶池化来实现更有效的特性聚合。GE利用深度卷积来对特征进行空间扩展。scSE和CBAM利用核大小为k×k的二维卷积计算空间注意,然后将其与通道注意结合起来。双注意网络与非局部神经网络有着相似的思想,它引入了一种新的图像或视频识别关系函数,而双注意网络(DAN)和交叉网络(CCNet)同时考虑非局部通道和非局部空间注意进行语义分割。类似地,Li等人提出了一个期望最大化注意(EMA)模块用于语义分割。

方法简介

具体来说,在给定输入特征的情况下,SE块首先对每个通道单独使用全局平均池化,然后使用两个具有非线性的完全连接(FC)层,然后使用一个Sigmoid函数来生成通道权值。两个FC层的设计是为了捕捉非线性的跨通道交互,其中包括降维来控制模型的复杂性。虽然该策略在后续的通道注意模块中得到了广泛的应用,但作者的实验研究表明,降维对通道注意预测带来了副作用,捕获所有通道之间的依赖是低效且不必要的。

ECANet主要对SENet模块进行了一些改进,提出了一种不降维的局部跨信道交互策略(ECA模块)和自适应选择一维卷积核大小的方法,从而实现了性能上的提优。最近已经有很多文章在通道和空间注意力上做改进并取得了性能提升。例如SKNet,SANet,ResNeSt等等,不得不说,注意力机制真的香!

文中提出了一种不降维的局部跨信道交互策略,该策略可以通过一维卷积有效地实现。进一步,作者又提出了一种自适应选择一维卷积核大小的方法,以确定局部跨信道交互的覆盖率。

图1示:各种注意力模块SENet、CBAM的比较,以ResNets为骨干模型,在准确率、网络参数、FLOPs方面。圆的大小表示模型计算(FLOPs)。显然,我们的ECA-Net在模型复杂度较低的同时,获得了较高的精度。

图2示:SE块和(b)我们的有效通道注意力(ECA)模块的比较。给定使用全局平均池(GAP)的聚合特性,SE块使用两个FC层计算权重。与之不同的是,ECA通过执行大小为k的快速一维卷积来生成通道权值,其中k通过通道维C的函数自适应地确定。

如图 (b)所示,在不降低维数的通道级全局平均池化之后,通过考虑每个通道及其k近邻来捕获局部跨通道交互信息。通过大小为k的快速一维卷积来捕获了跨通道交互信息

ECA可以通过大小为k的快速一维卷积来有效实现,其中卷积核大小k代表了局部跨信道交互的覆盖率,即,该通道附近有多少邻居参与了这个通道的注意力预测,为了避免通过交叉验证对k进行手动调优,本文提出了一种方法来自适应地确定k,其中交互的覆盖率(即卷积核大小 k)与通道维数成正比。

如图1和表2所示,与主干模型相反,使用ECA模块的深层CNNs(称为ECA- Net)引入很少的额外参数和可忽略的计算,同时带来显著的性能提升。

 

本文贡献:

1、避免降维和适当的跨通道交互对于学习有效的深度CNNs通道注意是重要的。
2、提出了一种新型的高效通道注意(ECA),尝试为深度CNNs开发一种非常轻量级的通道注意模块,该模块增加的模型复杂度很小,但带来了明显的改进。
3、在ImageNet-1K和MS COCO上的实验结果表明,我们的方法比最先进的方法具有更低的模型复杂性,同时获得了非常有竞争力的性能。

表1:以ResNet-50为骨干的ImageNet各通道注意模块对比参数。表示每个通道注意模块所涉及的参数数。O意味着点乘。GC和C1D分别表示群卷积和1D卷积。k是C1D的核大小。

核大小k的自适应选择 

k决定了交互的覆盖范围,不同的通道数和不同的CNN架构的卷积块可能会有所不同。

k与通道维数c有关,一般认为,通道尺寸越大,长期交互作用越强,而通道尺寸越小,短期交互作用越强。换句话说,之间可能存在某种映射φk和C:

在这里插入图片描述

最优映射φ通常是未知的。基于上述分析,k与C成非线性比例,因此参数化指数函数是一个可行的选择。同时,在经典的核技巧中,作为核函数的指数族函数(如高斯)被广泛用于处理未知映射问题。因此,我们使用一个指数函数近似映射φ,如下:
在这里插入图片描述

 

此外,由于通道维C通常设置为2的整数次幂,所以我们用 在这里插入图片描述 代替在这里插入图片描述
然后,给定通道维C,自适应确定内核大小k:
在这里插入图片描述
这里 在这里插入图片描述 表示最近的奇数t。本文中将γ设置为2,b设置为1。显然,通过映射,高维通道具有较长的相互作用,而低维通道通过非线性映射具有较短的相互作用

 

代码

如下为ECA模块的代码

  1. import torch
  2. from torch import nn
  3. from torch.nn.parameter import Parameter
  4. class eca_layer(nn.Module):
  5. """Constructs a ECA module.
  6. Args:
  7. channel: Number of channels of the input feature map
  8. k_size: Adaptive selection of kernel size
  9. """
  10. def __init__(self, channel, k_size=3):
  11. super(eca_layer, self).__init__()
  12. self.avg_pool = nn.AdaptiveAvgPool2d(1)
  13. self.conv = nn.Conv1d(1, 1, kernel_size=k_size, padding=(k_size - 1) // 2, bias=False)
  14. self.sigmoid = nn.Sigmoid()
  15. def forward(self, x):
  16. # x: input features with shape [b, c, h, w]
  17. b, c, h, w = x.size()
  18. # feature descriptor on the global spatial information
  19. y = self.avg_pool(x)
  20. # Two different branches of ECA module
  21. y = self.conv(y.squeeze(-1).transpose(-1, -2)).transpose(-1, -2).unsqueeze(-1)
  22. # Multi-scale information fusion
  23. y = self.sigmoid(y)
  24. return x * y.expand_as(x)

mobilenetv2 ECA模块

  1. from torch import nn
  2. from .eca_module import eca_layer
  3. __all__ = ['ECA_MobileNetV2', 'eca_mobilenet_v2']
  4. model_urls = {
  5. 'mobilenet_v2': 'https://download.pytorch.org/models/mobilenet_v2-b0353104.pth',
  6. }
  7. class ConvBNReLU(nn.Sequential):
  8. def __init__(self, in_planes, out_planes, kernel_size=3, stride=1, groups=1):
  9. padding = (kernel_size - 1) // 2
  10. super(ConvBNReLU, self).__init__(
  11. nn.Conv2d(in_planes, out_planes, kernel_size, stride, padding, groups=groups, bias=False),
  12. nn.BatchNorm2d(out_planes),
  13. nn.ReLU6(inplace=True)
  14. )
  15. class InvertedResidual(nn.Module):
  16. def __init__(self, inp, oup, stride, expand_ratio, k_size):
  17. super(InvertedResidual, self).__init__()
  18. self.stride = stride
  19. assert stride in [1, 2]
  20. hidden_dim = int(round(inp * expand_ratio))
  21. self.use_res_connect = self.stride == 1 and inp == oup
  22. layers = []
  23. if expand_ratio != 1:
  24. # pw
  25. layers.append(ConvBNReLU(inp, hidden_dim, kernel_size=1))
  26. layers.extend([
  27. # dw
  28. ConvBNReLU(hidden_dim, hidden_dim, stride=stride, groups=hidden_dim),
  29. # pw-linear
  30. nn.Conv2d(hidden_dim, oup, 1, 1, 0, bias=False),
  31. nn.BatchNorm2d(oup),
  32. ])
  33. layers.append(eca_layer(oup, k_size))
  34. self.conv = nn.Sequential(*layers)
  35. def forward(self, x):
  36. if self.use_res_connect:
  37. return x + self.conv(x)
  38. else:
  39. return self.conv(x)
  40. class ECA_MobileNetV2(nn.Module):
  41. def __init__(self, num_classes=1000, width_mult=1.0):
  42. super(ECA_MobileNetV2, self).__init__()
  43. block = InvertedResidual
  44. input_channel = 32
  45. last_channel = 1280
  46. inverted_residual_setting = [
  47. # t, c, n, s
  48. [1, 16, 1, 1],
  49. [6, 24, 2, 2],
  50. [6, 32, 3, 2],
  51. [6, 64, 4, 2],
  52. [6, 96, 3, 1],
  53. [6, 160, 3, 2],
  54. [6, 320, 1, 1],
  55. ]
  56. # building first layer
  57. input_channel = int(input_channel * width_mult)
  58. self.last_channel = int(last_channel * max(1.0, width_mult))
  59. features = [ConvBNReLU(3, input_channel, stride=2)]
  60. # building inverted residual blocks
  61. for t, c, n, s in inverted_residual_setting:
  62. output_channel = int(c * width_mult)
  63. for i in range(n):
  64. if c <= 96:
  65. ksize = 1
  66. else:
  67. ksize = 3
  68. stride = s if i == 0 else 1
  69. features.append(block(input_channel, output_channel, stride, expand_ratio=t, k_size=ksize))
  70. input_channel = output_channel
  71. # building last several layers
  72. features.append(ConvBNReLU(input_channel, self.last_channel, kernel_size=1))
  73. # make it nn.Sequential
  74. self.features = nn.Sequential(*features)
  75. # building classifier
  76. self.classifier = nn.Sequential(
  77. nn.Dropout(0.25),
  78. nn.Linear(self.last_channel, num_classes),
  79. )
  80. # weight initialization
  81. for m in self.modules():
  82. if isinstance(m, nn.Conv2d):
  83. nn.init.kaiming_normal_(m.weight, mode='fan_out')
  84. if m.bias is not None:
  85. nn.init.zeros_(m.bias)
  86. elif isinstance(m, nn.BatchNorm2d):
  87. nn.init.ones_(m.weight)
  88. nn.init.zeros_(m.bias)
  89. elif isinstance(m, nn.Linear):
  90. nn.init.normal_(m.weight, 0, 0.01)
  91. if m.bias is not None:
  92. nn.init.zeros_(m.bias)
  93. def forward(self, x):
  94. x = self.features(x)
  95. x = x.mean(-1).mean(-1)
  96. x = self.classifier(x)
  97. return x
  98. def eca_mobilenet_v2(pretrained=False, progress=True, **kwargs):
  99. """
  100. Constructs a ECA_MobileNetV2 architecture from
  101. Args:
  102. pretrained (bool): If True, returns a model pre-trained on ImageNet
  103. progress (bool): If True, displays a progress bar of the download to stderr
  104. """
  105. model = ECA_MobileNetV2(**kwargs)
  106. # if pretrained:
  107. # state_dict = load_state_dict_from_url(model_urls['mobilenet_v2'],
  108. # progress=progress)
  109. # model.load_state_dict(state_dict)
  110. return model

 

参考:

https://blog.csdn.net/tjut_zdd/article/details/102600401

 

 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/很楠不爱3/article/detail/307166
推荐阅读
相关标签
  

闽ICP备14008679号