赞
踩
https://arxiv.org/pdf/1807.06514.pdf
近期深度神经网络的进展主要通过架构搜索来增强其表示能力。在这项工作中,我们专注于注意力在一般深度神经网络中的作用。我们提出了一种简单而有效的注意力模块,名为瓶颈注意力模块(BAM),可以与任何前馈卷积神经网络集成。我们的模块沿两个独立的通道和空间路径推断注意力图。我们将模块放置在模型中的每个瓶颈处,其中特征图进行了下采样。我们的模块在具有大量参数的瓶颈处构建了分层注意力,并且可以与任何前馈模型进行端到端的训练。我们在CIFAR-100、ImageNet-1K、VOC 2007和MS COCO基准上进行了广泛的实验来验证我们的BAM。实验结果表明,我们的BAM在不同模型中都实现了分类和检测性能的持续提高,这表明BAM具有广泛的适用性。代码和模型将公开可用。
深度学习已经成为一系列模式识别应用的有力工具,包括分类、检测、分割和控制问题。由于其数据驱动的本质和大规模并行计算的可获得性,深度神经网络在大多数领域都取得了最先进的结果。研究人员已经通过多种方式来提高性能,例如设计优化器[28,48],提出对抗训练方案[11],或针对特定任务的元架构,如两阶段架构[37]进行检测。
提高性能的基本方法是设计一个好的主干网络架构。自从第一个大规模深度神经网络AlexNet [30]以来,已经提出了各种主干网络架构,如VGGNet [40]、GoogLeNet [41]、ResNet [16]、DenseNet [20]。所有主干网络架构都有自己的设计选择,并且相对于先前的架构显示出显著的性能提升。
提高网络性能的最直观方法是堆叠更多的层。然后,深度神经网络能够使用其深层来近似高维函数。VGGNet [40]和ResNet [15]的哲学正是遵循这一原则。与AlexNet [30]相比,VGGNet的层数增加了两倍。此外,通过采用残差连接改进了梯度流,ResNet的层数比VGGNet多了22倍。GoogLeNet [41]也非常深,它在每个卷积块中使用具有不同滤波器大小的特征的串联。在同一层中使用多种特征显示了性能的提高,从而实现了强大的表示。DenseNet [20]也使用不同层中的特征图的串联。换句话说,卷积层的输出在输入特征图上被迭代串联。WideResNet [47]表明,使用更多的通道和更宽的卷积可以比简单地加深网络获得更高的性能。同样,PyramidNet [13]表明,在更深层增加通道可以有效地提高性能。最近的分组卷积方法,如ResNeXt [43]或Xception [7],作为主干架构显示出最先进的性能。ResNeXt和Xception的成功来自于具有更高基数的高性能卷积。此外,一条实用的研究路线是寻找面向移动设备的、计算有效的架构。MobileNet [18]与ResNeXt和Xception有着相似的哲学思想,它使用具有高基数的深度卷积。
除了之前的方法,我们研究了注意力在深度神经网络中的作用,并提出了一个简单、轻量级的模块,适用于一般的深度神经网络。也就是说,提出的模块设计为易于与现有卷积神经网络架构集成。深度神经网络中的注意力机制在许多先前的工作中已经得到了研究[2, 3, 12, 25, 35, 44]。虽然大多数先前的工作使用注意力是为了特定的任务目的,但我们明确地探讨了使用注意力作为提高网络表示能力的一种极其有效的方法。因此,我们提出了“瓶颈注意力模块”(BAM),这是一个简单而高效的注意力模块,可以用于任何卷积神经网络。给定一个3D特征图,BAM产生一个3D注意力图来强调重要的元素。在BAM中,我们将推断3D注意力图的过程分解为两个流(图2),从而显著减少了计算和参数开销。由于特征图的通道可以被视为特征检测器,因此两个分支(空间和通道)明确地学习“关注什么”和“关注哪里”。
我们使用各种基准架构在各种任务上测试了BAM的疗效。在CIFAR-100和ImageNet分类任务上,我们通过放置BAM观察到了比基准网络更好的性能。有趣的是,我们观察到多个位于不同瓶颈处的BAM构建了一个层次化的注意力,如图1所示。最后,我们在VOC 2007和MS COCO数据集上验证了目标检测的性能提升,证明了BAM的广泛应用性。由于我们精心设计了轻量级的模块,因此参数和计算开销可以忽略不计。
贡献。我们的主要贡献有三点:
许多研究[8,24,38]已经表明,注意力在人类感知中起着重要作用。例如,人眼中央凹中心的分辨率高于周围区域[17]。为了高效地、自适应地处理视觉信息,人类视觉系统会迭代处理空间一瞥并关注显著的区域[31]。
跨模态注意力。注意力机制在多模态设置中是广泛使用的技术,尤其是在某些模态应该根据其他模态进行处理的场景中。视觉问答任务是此类任务的典型例子。给定一张图片和自然语言问题,任务是预测答案,例如计数、推断目标的位置或属性。视觉问答任务可以被视为一系列动态变化的任务,其中提供的图像应根据给定的问题进行处理。注意力机制软选择与任务(问题)相关的图像特征方面。如[45]所示,根据给定的问题生成图像特征的注意力图,并用作查询来检索与问题相关的特征。最终答案通过堆叠的图像特征进行分类。另一种方法是使用双向推理,为文本和图像生成注意力图,如[36]所示。在这些文献中,注意力图被用作解决有条件任务的有效方法,但它们是为特定任务目的分阶段训练的。
自注意力。已经有了多种将注意力集成到DNNs中的方法,以端到端的方式联合训练特征提取和注意力生成。一些尝试[19,42]已经将注意力视为一般分类任务的有效解决方案。Wang等人提出了残差注意力网络,使用沙漏模块为中间特征生成3D注意力图。由于生成的注意力图,该架构对噪声标签具有抵抗力,但由于3D地图生成过程繁重,计算/参数开销很大。Hu等人提出了一个紧凑的“挤压和激励”模块,用于利用通道间的关系。虽然论文中没有明确指出,但可以将它视为应用于通道轴的注意力机制。然而,他们错过了空间轴,这也是推断准确注意力图的重要因素。
自适应模块。一些早期的工作使用自适应模块,这些模块可以根据其输入动态地改变其输出。动态滤波网络[27]提出根据输入特征生成卷积特征,以实现灵活性。空间变换网络[26]使用输入特征自适应地生成仿射变换的超参数,以便最终对齐目标区域特征图。这可以被视为对特征图的硬注意力。可变形卷积网络[9]使用可变形卷积,其中从输入特征动态生成池化偏移,以便仅对相关特征进行池化以进行卷积。与上述方法类似,BAM也是一个独立的自适应模块,通过注意力机制动态抑制或强调特征图。
在这项工作中,我们使用简单且轻量级的设计利用通道和空间轴的注意力。此外,我们找到了放置我们的模块的有效位置 - 网络的瓶颈。
BAM 的详细结构如图 2 所示。对于给定的输入特征图
F
∈
R
C
×
H
×
W
\mathbf{F} \in \mathbb{R}^{C \times H \times W}
F∈RC×H×W,BAM 推断出一个 3D 注意力图
M
(
F
)
∈
R
C
×
H
×
W
\mathbf{M}(\mathbf{F}) \in \mathbb{R}^{C \times H \times W}
M(F)∈RC×H×W。经过细化后的特征图
F
′
\mathbf{F}^{\prime}
F′ 的计算方式如下:
F
′
=
F
+
F
⊗
M
(
F
)
\mathbf{F}^{\prime}=\mathbf{F}+\mathbf{F} \otimes \mathbf{M}(\mathbf{F})
F′=F+F⊗M(F)
其中
⊗
\otimes
⊗ 表示逐元素乘法。我们采用带有注意力机制的残差学习方案以促进梯度流动。为了设计一个高效且强大的模块,我们首先在两个独立的分支上计算通道注意力
M
c
(
F
)
∈
R
C
\mathbf{M}_{\mathbf{c}}(\mathbf{F}) \in \mathbb{R}^{C}
Mc(F)∈RC 和空间注意力
M
s
(
F
)
∈
R
H
×
W
\mathbf{M}_{\mathbf{s}}(\mathbf{F}) \in \mathbb{R}^{H \times W}
Ms(F)∈RH×W,然后计算注意力图
M
(
F
)
\mathbf{M}(\mathbf{F})
M(F):
M
(
F
)
=
σ
(
M
c
(
F
)
+
M
s
(
F
)
)
,
\mathbf{M}(\mathbf{F})=\sigma\left(\mathbf{M}_{\mathbf{c}}(\mathbf{F})+\mathbf{M}_{\mathbf{s}}(\mathbf{F})\right),
M(F)=σ(Mc(F)+Ms(F)),
其中
σ
\sigma
σ 是一个 sigmoid 函数。两个分支的输出在相加之前都调整为
R
C
×
H
×
W
\mathbb{R}^{C \times H \times W}
RC×H×W。
通道注意力分支。由于每个通道包含特定的特征响应,我们利用通道分支中的通道间关系。为了聚合每个通道的特征图,我们在特征图
F
\mathbf{F}
F 上进行全局平均池化,并生成一个通道向量
F
c
∈
R
C
×
1
×
1
\mathbf{F}_{\mathbf{c}} \in \mathbb{R}^{C \times 1 \times 1}
Fc∈RC×1×1。这个向量软编码了每个通道中的全局信息。为了从通道向量
F
c
\mathbf{F}_{\mathbf{c}}
Fc 中估计跨通道的注意力,我们使用一个具有一个隐藏层的多层感知器 (MLP)。为了节省参数开销,隐藏层的激活大小设置为
R
C
/
r
×
1
×
1
\mathbb{R}^{C / r \times 1 \times 1}
RC/r×1×1,其中 r 是降低比率。在MLP之后,我们添加批量归一化层 [23] 来调整与空间分支输出相同的规模。简而言之,通道注意力计算如下:
M
c
(
F
)
=
B
N
(
MLP
(
Avg
Pool
(
F
)
)
)
=
B
N
(
W
1
(
W
0
Avg
Pool
(
F
)
+
b
0
)
+
b
1
)
,
其中
W
0
∈
R
C
/
r
×
C
,
b
0
∈
R
C
/
r
,
W
1
∈
R
C
×
C
/
r
,
b
1
∈
R
C
\mathbf{W}_{\mathbf{0}} \in \mathbb{R}^{C / r \times C}, \mathbf{b}_{\mathbf{0}} \in \mathbb{R}^{C / r}, \mathbf{W}_{\mathbf{1}} \in \mathbb{R}^{C \times C / r}, \mathbf{b}_{\mathbf{1}} \in \mathbb{R}^{C}
W0∈RC/r×C,b0∈RC/r,W1∈RC×C/r,b1∈RC。
空间注意力分支。空间分支生成一个空间注意力
M
s
(
F
)
∈
R
H
×
W
\mathbf{M}_{\mathbf{s}}(\mathbf{F}) \in \mathbb{R}^{H \times W}
Ms(F)∈RH×W,用于强调或抑制不同空间位置的特征。众所周知,利用上下文信息对于知道应该关注哪些空间位置至关重要。拥有一个大的接收场来有效地利用上下文信息是重要的。我们采用膨胀卷积来高效地扩大接收场。我们观察到,与标准卷积相比,膨胀卷积有助于构建更有效的空间图(参见第4.1节)。我们采用了ResNet [15]中建议的“瓶颈结构”作为我们的空间分支,这既节省了参数数量又减少了计算开销。具体来说,特征
F
∈
R
C
×
H
×
W
\mathbf{F} \in \mathbb{R}^{C \times H \times W}
F∈RC×H×W 通过
1
×
1
1 \times 1
1×1 的卷积投影到降低的维度
R
C
/
r
×
H
×
W
\mathbb{R}^{C / r \times H \times W}
RC/r×H×W,以跨通道维度整合和压缩特征图。为了简化,我们使用与通道分支相同的降低比率 r。在降低维度后,应用两个
3
×
3
3 \times 3
3×3 的膨胀卷积来有效地利用上下文信息。最后,通过
1
×
1
1 \times 1
1×1 的卷积将特征再次降低到
R
1
×
H
×
W
\mathbb{R}^{1 \times H \times W}
R1×H×W 的空间注意力图。为了进行尺度调整,我们在空间分支的末尾应用批量归一化层。简而言之,空间注意力计算如下:
M
s
(
F
)
=
B
N
(
f
3
1
×
1
(
f
2
3
×
3
(
f
1
3
×
3
(
f
0
1
×
1
(
F
)
)
)
)
)
,
\mathbf{M}_{\mathbf{s}}(\mathbf{F})=B N\left(f_{3}^{1 \times 1}\left(f_{2}^{3 \times 3}\left(f_{1}^{3 \times 3}\left(f_{0}^{1 \times 1}(\mathbf{F})\right)\right)\right)\right),
Ms(F)=BN(f31×1(f23×3(f13×3(f01×1(F))))),
其中
f
f
f 表示卷积操作,
B
N
B N
BN 表示批量归一化操作,上标表示卷积滤波器的尺寸。有两个
1
×
1
1 \times 1
1×1 的卷积用于通道数目的减少,而中间的
3
×
3
3 \times 3
3×3 的膨胀卷积则用于通过较大的接收场来聚合上下文信息。
在获得两个注意力分支的通道注意力 M c ( F ) \mathbf{M}_{\mathbf{c}}(\mathbf{F}) Mc(F) 和空间注意力 M s ( F ) \mathbf{M}_{\mathbf{s}}(\mathbf{F}) Ms(F) 后,我们将它们组合起来以生成最终的3D注意力图 M ( F ) \mathbf{M}(\mathbf{F}) M(F)。由于两个注意力图具有不同的形状,我们在组合之前将它们扩展到 R C × H × W \mathbb{R}^{C \times H \times W} RC×H×W。在各种组合方法中,如元素加法、乘法或最大值操作,我们选择元素加法以实现有效的梯度流 [15]。我们通过实验验证,元素加法在三种选项中获得了最佳性能(参见第4节)。在求和之后,我们使用sigmoid函数来获得范围在0到1之间的最终3D注意力图 M ( F ) \mathbf{M}(\mathbf{F}) M(F)。然后,这个3D注意力图会逐元素地与输入特征图 F \mathbf{F} F 相乘,并与原始输入特征图相加,以获得精炼的特征图 F ′ \mathbf{F}^{\prime} F′,如式(1)所示。
我们在标准基准上进行评估:用于图像分类的CIFAR-100和ImageNet-1K,以及用于目标检测的VOC 2007和MS COCO。为了进行更好的appleto-apple比较,我们首先在PyTorch框架中复现了所有报告的性能,并将其设置为我们的基线[15, 20, 43, 47]。然后,我们进行了大量实验,以全面评估我们最终模块的有效性。最后,我们验证了BAM在没有任何花哨功能的情况下优于所有基线,证明了BAM在各种架构和不同任务中的通用性。表5、表6、表7、表8、表9可在补充材料中找到。
CIFAR-100数据集[29]由来自100个类别的60,000张32x32彩色图像组成。训练集和测试集分别包含50,000和10,000张图像。对于这个数据集,我们采用随机裁剪的常规数据增强方法,并在图像周围添加4像素的填充并进行水平翻转。对于预处理,我们使用RGB均值和标准差对数据进行归一化。
扩放值和降低率。在表1中,我们进行了一项实验,以确定我们模块中的两个主要超参数,即扩放值和降低率,基于ResNet50架构。扩放值决定了空间注意力分支的感受野大小。表1显示了四个不同扩放值的比较结果。我们可以清楚地看到,随着扩放值的增加,性能有所提高,尽管在扩放值为4时已经趋于饱和。这一现象可以从上下文推理的角度来解释,这在密集预测任务中被广泛利用[4,5,34,46,49]。由于扩放卷积的序列允许感受野的指数级扩展,它使我们的模块能够无缝地聚合上下文信息。请注意,标准卷积(即扩放值为1)产生的准确度最低,这表明用于推断空间注意力图的上下文先验的有效性。降低率与两个注意力分支中的通道数直接相关,这使我们能够控制模块的容量和开销。在表1中,我们比较了四个不同降低率的性能。有趣的是,降低率为16时达到了最高的准确度,尽管降低率为4和8时的容量更高。我们推测这一结果是由于过度拟合导致的,因为在两种情况下训练损失都收敛了。基于表1中的结果,我们在以下实验中将扩放值设置为4,将降低率设置为16。
分支独立或合并。在表1中,我们进行了一项消融研究,以验证我们在模块中的设计选择。我们首先分别移除每个分支,以验证同时利用通道和空间注意力分支的有效性。如表1所示,尽管每个注意力分支都可以提高性能超过基线,但我们观察到当同时使用两个分支时,性能有显著的提升。这表明将通道和空间分支结合起来在推断最终注意力图方面起着至关重要的作用。事实上,这种设计遵循人类视觉系统的类似方面,该系统具有“what”(通道)和“where”(空间)路径,并且这两个路径都有助于处理视觉信息[6,31]。
组合方法。我们还探索了三种不同的组合策略:元素最大值、元素乘积和元素求和。表1总结了三种不同实现方式的比较结果。我们通过经验证实,元素求和实现获得了最佳性能。从信息流的角度来看,元素求和是一种有效的方式来整合和保护来自前一层的的信息。在正向传播阶段,它使网络能够利用来自两个互补分支(通道和空间)的信息,而不会丢失任何信息。在反向传播阶段,梯度均匀地分配给所有输入,从而实现高效的训练。元素乘积可以使网络对小的输入分配较大的梯度,从而使网络难以收敛,导致性能较差。元素最大值仅将梯度路由到较高的输入,在一定程度上提供正则化效果,但由于我们的模块参数较少,导致训练不稳定。请注意,所有三种不同的实现都优于基线,这表明利用每个分支至关重要,而最佳组合策略可以进一步提高性能。
与在瓶颈处放置原始卷积块的比较。在本实验中,我们通过经验验证,显著的性能提升并非来自通过简单地在瓶颈处添加额外层来增加网络的深度。我们添加了具有与基准卷积块相同拓扑的辅助卷积块,然后将其与表1中的BAM进行比较。我们可以明显地注意到,插入BAM不仅产生了优越的性能,而且相对于简单地在瓶颈处放置额外的层而言,减少了开销。这表明BAM的改进不仅仅是由于深度的增加,而是因为有效的特征细化。
瓶颈:放置BAM的有效点。我们通过经验验证,网络的瓶颈是放置我们的模块BAM的有效点。最近关于注意力机制的研究[19,42]主要关注的是对“卷积块”而不是“瓶颈”的修改。我们通过在CIFAR-100上使用各种模型来比较这两种不同的位置。在表2中,我们可以清楚地观察到,将模块放置在瓶颈处,在开销与准确度之间的权衡上是有效的。在大多数情况下,它减少了开销并提高了准确度,除了PreResNet 110 [16]之外。
在表3中,我们将BAM放置在包括[15, 16, 20, 43, 47]在内的最先进模型瓶颈处的性能与CIFAR-100进行比较。请注意,ResNet101和ResNeXt29 16x64d网络分别实现了20.00%和17.25%的错误率,而ResNet50与BAM和ResNeXt29 8x64d与BAM仅使用一半的参数就分别实现了20.00%和16.71%的错误率。这表明我们的模块BAM可以有效地提高网络的容量,同时减少网络参数的数量。由于我们的轻量级设计,整体参数和计算开销微不足道。
ILSVRC 2012分类数据集[10]由120万张训练图像和5万张验证图像组成,共有1000个目标类别。我们采用与[15,16]相同的训练数据增强方案,并在测试时应用大小为224×224的单次裁剪评估。根据[15,16,21],我们在验证集上报告分类错误。ImageNet分类基准是最大和最复杂的图像分类基准之一,我们展示了BAM在如此通用和复杂的任务中的有效性。我们使用用于ImageNet分类任务的ResNet [15]、WideResNet [47]和ResNeXt [43]的基准网络。更多细节请参见补充材料。
如表3所示,具有BAM的网络再次优于所有基准,这表明BAM可以在大型数据集上的各种模型中很好地泛化。请注意,参数和计算的开销微不足道,这表明所提出的模块BAM可以有效地显著提高网络容量。另一件值得注意的是,性能的提升仅来自整个网络中放置的三个模块。由于空间限制,BAM成功和失败案例的进一步分析和可视化参见补充材料。
我们模块的主要优势在于,它在提高性能的同时,对模型/计算复杂性几乎没有开销。为了在更实际的设置中展示这一优势,我们将模块与紧凑型网络相结合[18,22],这些网络具有严格的资源限制。紧凑型网络专为移动和嵌入式系统而设计,因此设计选项具有计算和参数限制。
如表3所示,BAM以较小的开销提高了所有模型的准确度。由于我们在模块上不采用任何挤压操作[18,22],因此我们认为在效率方面还有更多改进的空间。
我们在Microsoft COCO数据集[32]上进行目标检测。根据[4, 33],我们使用所有训练图像以及验证图像的子集训练模型,保留5000个示例用于验证。我们采用Faster-RCNN [37]作为我们的检测方法,并采用ImageNet预训练的ResNet101 [15]作为基准网络。在这里,我们感兴趣的是通过将BAM插入基准来提高性能。由于我们使用两种模型的相同检测方法,因此只能将增益归因于我们的模块BAM。如表4所示,我们观察到相对于基线的显著改进,这表明BAM在其他识别任务上的泛化性能。
我们进一步在PASCAL VOC 2007检测任务上对BAM进行实验。在这个实验中,我们将BAM应用于检测器。我们采用StairNet [39]框架,这是基于SSD [33]的最强大的多尺度方法之一。我们在每个分类器之前放置BAM,在预测之前对最终特征进行细化,强制模型仅选择有意义的特征。实验结果总结在表4中。我们可以清楚地看到,BAM提高了所有使用两个主干网络的强基准的准确性。请注意,BAM的准确度提升具有可忽略的参数开销,这表明增强效果不是由于简单的容量增加,而是由于我们有效的特征细化。此外,使用轻量级主干网络的结果再次表明,BAM可以成为低端设备的有趣方法。
为了与Squeeze-and-Excitation (SE)进行比较,我们在CIFAR-100分类任务上进行了额外实验。表5总结了所有结果,显示在大多数情况下,BAM使用更少的参数,性能优于SE。我们的模块需要稍微更多的GFLOPS,但参数比SE少得多,因为我们只在网络的瓶颈处放置模块,而不是每个卷积块。
我们提出了瓶颈注意力模块(BAM),这是一种增强网络表示能力的新方法。我们的模块通过两个独立的路径高效地学习关注或抑制的内容,并有效地细化中间特征。受人类视觉系统的启发,我们建议在网络瓶颈处放置一个注意力模块,这是信息流最关键的点。为了验证其效果,我们在各种最先进的模型上进行了大量实验,并确认BAM在三个不同的基准数据集上优于所有基线:CIFAR-100、ImageNet 1 \mathrm{~K}、VOC2007和MS COCO。此外,我们还可视化了该模块如何在中间特征图上起作用,以更清楚地了解其作用。有趣的是,我们观察到了类似于人类感知过程的分层推理过程。我们相信,我们在瓶颈处发现的自适应特征细化对其他视觉任务也有所帮助。
YOLOv8l summary (fused): 268 layers, 43631280 parameters, 0 gradients, 165.0 GFLOPs Class Images Instances Box(P R mAP50 mAP50-95): 100%|██████████| 29/29 [ all 230 1412 0.922 0.957 0.986 0.737 c17 230 131 0.973 0.992 0.995 0.825 c5 230 68 0.945 1 0.995 0.836 helicopter 230 43 0.96 0.907 0.951 0.607 c130 230 85 0.984 1 0.995 0.655 f16 230 57 0.955 0.965 0.985 0.669 b2 230 2 0.704 1 0.995 0.722 other 230 86 0.903 0.942 0.963 0.534 b52 230 70 0.96 0.971 0.978 0.831 kc10 230 62 0.999 0.984 0.99 0.847 command 230 40 0.97 1 0.995 0.811 f15 230 123 0.891 1 0.992 0.701 kc135 230 91 0.971 0.989 0.986 0.712 a10 230 27 1 0.555 0.899 0.456 b1 230 20 0.972 1 0.995 0.793 aew 230 25 0.945 1 0.99 0.784 f22 230 17 0.913 1 0.995 0.725 p3 230 105 0.99 1 0.995 0.801 p8 230 1 0.637 1 0.995 0.597 f35 230 32 0.939 0.938 0.978 0.574 f18 230 125 0.985 0.992 0.987 0.817 v22 230 41 0.983 1 0.995 0.69 su-27 230 31 0.925 1 0.995 0.859 il-38 230 27 0.972 1 0.995 0.811 tu-134 230 1 0.663 1 0.995 0.895 su-33 230 2 1 0.611 0.995 0.796 an-70 230 2 0.766 1 0.995 0.73 tu-22 230 98 0.984 1 0.995 0.831 Speed: 0.2ms preprocess, 3.8ms inference, 0.0ms loss, 0.8ms postprocess per image
ChannelGate模块,首先使用自适应平均池化将输入特征图的空间维度压缩到1x1,然后通过一个多层感知机(MLP)来学习通道之间的依赖关系。MLP包含两个线性层,中间使用ReLU激活函数。学习到的权重向量再经过批量归一化后,被重新整形为与输入特征图相同的空间维度(通过广播机制),以便后续与输入特征图进行逐通道相乘或其他操作。这种通道注意力机制可以让模型更加关注重要的通道,并抑制不重要的通道。注意,这里的代码只计算了权重向量,并没有显示地与输入特征图进行相乘操作,这通常是在更大的网络结构中完成的。
SpatialGate模块,首先通过第一个卷积层对输入特征图进行压缩。然后通过一个包含两个全连接层的序列来学习空间依赖关系,中间使用了批标准化和ReLU激活函数。最后通过第三个卷积层和批标准化层得到权重向量,并将其形状扩展为与输入特征图相同,以便后续与输入特征图进行逐元素相乘或其他操作。这种空间注意力机制可以让模型更加关注重要的空间位置,并抑制不重要的区域。
该模块结合了通道注意力(Channel Attention)和空间注意力(Spatial Attention)。在BAM的前向传播函数中,首先通过ChannelGate和SpatialGate分别得到通道注意力和空间注意力的结果,然后将两者相加并应用sigmoid激活函数得到最终的注意力权重。
最后,将注意力权重与输入特征图相乘,并加上原始特征图,实现注意力机制的效果。这种机制可以使模型在处理图像或序列数据时更加关注重要的部分。
代码以及注释如下:
import torch from torch import nn import torch.nn.functional as F # ChannelGate类是一个自定义的通道注意力模块,它通过压缩空间维度来学习通道之间的依赖关系。 class ChannelGate(nn.Module): # 构造函数 def __init__(self, channel, reduction=16): super().__init__() # 调用父类nn.Module的初始化函数 # 定义一个自适应平均池化层,将输入特征图的空间维度压缩到1x1 self.avgpool = nn.AdaptiveAvgPool2d(1) # 定义一个多层感知机(MLP),包含两个线性层和一个ReLU激活函数 # 第一个线性层将通道数减少到原来的1/reduction,第二个线性层恢复到原来的通道数 self.mlp = nn.Sequential( nn.Linear(channel, channel // reduction), nn.ReLU(inplace=True), # 使用原地激活,节省存储空间 nn.Linear(channel // reduction, channel) ) # 定义一个批量归一化层,作用于通道维度 self.bn = nn.BatchNorm1d(channel) # 前向传播函数 def forward(self, x): b, c, h, w = x.shape # 获取输入特征图的形状:批大小、通道数、高度、宽度 # 使用自适应平均池化将特征图的空间维度压缩到1x1,然后展平为[b, c]的形状 y = self.avgpool(x).view(b, c) # 通过MLP学习通道之间的依赖关系,并输出与输入相同通道数的权重向量 y = self.mlp(y) # 对权重向量进行批量归一化,并重新整形为[b, c, 1, 1],以便后续与输入特征图进行广播操作 y = self.bn(y).view(b, c, 1, 1) # 使用expand_as方法将权重向量广播到与输入特征图相同的形状,并返回结果 return y.expand_as(x) import torch.nn as nn # SpatialGate类是一个自定义的空间注意力模块,它通过卷积操作来学习空间依赖关系。 class SpatialGate(nn.Module): # 构造函数 def __init__(self, channel, reduction=16, kernel_size=3, dilation_val=4): super().__init__() # 调用父类nn.Module的初始化函数 # 定义第一个卷积层,输入通道数和输出通道数都是channel // reduction self.conv1 = nn.Conv2d(channel, channel // reduction, kernel_size=1) # 定义一个卷积序列,包含两个卷积层,批标准化和ReLU激活函数 self.conv2 = nn.Sequential( nn.Conv2d(channel // reduction, channel // reduction, kernel_size, padding=dilation_val, dilation=dilation_val), nn.BatchNorm2d(channel // reduction), # 批标准化层 nn.ReLU(inplace=True), # ReLU激活函数 nn.Conv2d(channel // reduction, channel // reduction, kernel_size, padding=dilation_val, dilation=dilation_val), nn.BatchNorm2d(channel // reduction), # 批标准化层 nn.ReLU(inplace=True) # ReLU激活函数 ) # 定义第三个卷积层,输出通道数为1 self.conv3 = nn.Conv2d(channel // reduction, 1, kernel_size=1) # 定义批标准化层,作用于通道维度 self.bn = nn.BatchNorm2d(1) # 前向传播函数 def forward(self, x): b, c, h, w = x.shape # 获取输入特征图的形状:批大小、通道数、高度、宽度 y = self.conv1(x) # 通过第一个卷积层 y = self.conv2(y) # 通过第二个卷积序列 y = self.conv3(y) # 通过第三个卷积层 y = self.bn(y) # 通过批标准化层 return y.expand_as(x) # 将输出形状扩展为与输入相同,并返回结果 # 定义BAM类,继承自nn.Module class BAM(nn.Module): def __init__(self, channel): # 初始化函数,接收通道数作为参数 super(BAM, self).__init__() # 调用父类nn.Module的初始化函数 # 定义通道注意力模块 self.channel_attn = ChannelGate(channel) # 定义空间注意力模块 self.spatial_attn = SpatialGate(channel) # 前向传播函数 def forward(self, x): # 接收输入特征图x # 计算通道注意力和空间注意力的加权和,并应用sigmoid激活函数得到注意力权重 attn = torch.sigmoid(self.channel_attn(x) + self.spatial_attn(x)) # 将注意力权重与输入特征图相乘,并加上原始特征图,实现注意力机制的效果 return x + x * attn
将上面的代码复制到block.py脚本中,如下图:
将BAM注意力加入到C2f模块中,代码如下:
class C2f(nn.Module): """Faster Implementation of CSP Bottleneck with 2 convolutions.""" def __init__(self, c1, c2, n=1, shortcut=False, g=1, e=0.5): """Initialize CSP bottleneck layer with two convolutions with arguments ch_in, ch_out, number, shortcut, groups, expansion. """ super().__init__() self.c = int(c2 * e) # hidden channels self.cv1 = Conv(c1, 2 * self.c, 1, 1) self.cv2 = Conv((2 + n) * self.c, c2, 1) # optional act=FReLU(c2) self.m = nn.ModuleList(Bottleneck(self.c, self.c, shortcut, g, k=((3, 3), (3, 3)), e=1.0) for _ in range(n)) self.BAM=BAM(c2) def forward(self, x): """Forward pass through C2f layer.""" y = list(self.cv1(x).chunk(2, 1)) y.extend(m(y[-1]) for m in self.m) return self.BAM(self.cv2(torch.cat(y, 1))) def forward_split(self, x): """Forward pass using split() instead of chunk().""" y = list(self.cv1(x).split((self.c, self.c), 1)) y.extend(m(y[-1]) for m in self.m) return self.BAM(self.cv2(torch.cat(y, 1)))
在项目的根目录添加train.py脚本,代码如下:
from ultralytics import YOLO
import os
if __name__ == '__main__':
# 加载模型
model = YOLO(model="ultralytics/cfg/models/v8/yolov8l.yaml") # 从头开始构建新模型
# Use the model
results = model.train(data="VOC.yaml", epochs=300, device='0', batch=8, seed=42,) # 训练模
训练完成后,就可以看到测试结果!
在项目的根目录添加val.py脚本,代码如下:
from ultralytics import YOLO
if __name__ == '__main__':
# Load a model
# model = YOLO('yolov8m.pt') # load an official model
model = YOLO('runs/detect/train/weights/best.pt') # load a custom model
# Validate the model
metrics = model.val(split='val') # no arguments needed, dataset and settings remembered
split='val’代表使用验证集做测试,如果改为split=‘test’,则使用测试集做测试!
在项目的根目录添加test.py脚本,代码如下:
from ultralytics import YOLO
if __name__ == '__main__':
# Load a model
# model = YOLO('yolov8m.pt') # load an official model
model = YOLO('runs/detect/train/weights/best.pt') # load a custom model
results = model.predict(source="ultralytics/assets", device='0',save=True) # predict on an image
print(results)
test脚本测试assets文件夹下面的图片,save设置为true,则保存图片的测试结果!
YOLOv8l summary: 420 layers, 44018640 parameters, 0 gradients, 165.9 GFLOPs Class Images Instances Box(P R mAP50 mAP50-95): 100%|██████████| 15/15 [00:02<00:00, 7.06it/s] all 230 1412 0.975 0.965 0.987 0.748 c17 230 131 0.99 0.992 0.995 0.826 c5 230 68 0.995 1 0.995 0.832 helicopter 230 43 0.973 0.953 0.983 0.613 c130 230 85 0.988 0.97 0.994 0.659 f16 230 57 1 0.954 0.986 0.688 b2 230 2 0.932 1 0.995 0.651 other 230 86 0.998 0.895 0.975 0.545 b52 230 70 0.967 0.971 0.979 0.822 kc10 230 62 0.998 0.984 0.989 0.838 command 230 40 1 0.989 0.995 0.827 f15 230 123 0.96 0.98 0.992 0.691 kc135 230 91 0.992 0.978 0.99 0.703 a10 230 27 1 0.523 0.858 0.472 b1 230 20 0.991 0.95 0.99 0.743 aew 230 25 0.952 1 0.987 0.797 f22 230 17 0.957 1 0.995 0.749 p3 230 105 0.997 0.981 0.995 0.81 p8 230 1 0.88 1 0.995 0.796 f35 230 32 1 0.93 0.994 0.558 f18 230 125 0.991 0.992 0.99 0.806 v22 230 41 0.995 1 0.995 0.695 su-27 230 31 0.993 1 0.995 0.852 il-38 230 27 0.992 1 0.995 0.857 tu-134 230 1 0.856 1 0.995 0.895 su-33 230 2 1 1 0.995 0.858 an-70 230 2 0.921 1 0.995 0.796 tu-22 230 98 0.999 1 0.995 0.824
将上面的代码复制到block.py脚本中,如下图:
在__init__.py脚本中导入BAM,如下图:
在task.py中导入BAM,如下图:
在task.py中的parse_model函数增加BAM模块,如下图:
elif m is BAM:
args = [ch[f]]
修改ultralytics/cfg/models/v8/yolov8l.yaml配置文件,代码如下:
# YOLOv8.0n backbone backbone: # [from, repeats, module, args] - [-1, 1, Conv, [64, 3, 2]] # 0-P1/2 - [-1, 1, Conv, [128, 3, 2]] # 1-P2/4 - [-1, 3, C2f, [128, True]] - [-1, 1, Conv, [256, 3, 2]] # 3-P3/8 - [-1, 6, C2f, [256, True]] - [-1, 1, Conv, [512, 3, 2]] # 5-P4/16 - [-1, 6, C2f, [512, True]] - [-1, 1, Conv, [1024, 3, 2]] # 7-P5/32 - [-1, 3, C2f, [1024, True]] - [-1, 1, SPPF, [1024, 5]] # 9 - [-1, 1, BAM, []] # YOLOv8.0n head head: - [-1, 1, nn.Upsample, [None, 2, 'nearest']] - [[-1, 6], 1, Concat, [1]] # cat backbone P4 - [-1, 3, C2f, [512]] # 12 - [-1, 1, nn.Upsample, [None, 2, 'nearest']] - [[-1, 4], 1, Concat, [1]] # cat backbone P3 - [-1, 3, C2f, [256]] # 15 (P3/8-small) - [-1, 1, Conv, [256, 3, 2]] - [[-1, 13], 1, Concat, [1]] # cat head P4 - [-1, 3, C2f, [512]] # 18 (P4/16-medium) - [-1, 1, Conv, [512, 3, 2]] - [[-1, 10], 1, Concat, [1]] # cat head P5 - [-1, 3, C2f, [1024]] # 21 (P5/32-large) - [[16, 19, 22], 1, Detect, [nc]] # Detect(P3, P4, P5)
在项目的根目录添加train.py脚本,代码如下:
from ultralytics import YOLO
import os
if __name__ == '__main__':
# 加载模型
model = YOLO(model="ultralytics/cfg/models/v8/yolov8l.yaml") # 从头开始构建新模型
# Use the model
results = model.train(data="VOC.yaml", epochs=300, device='0', batch=8, seed=42,) # 训练模
训练完成后,就可以看到测试结果!
在项目的根目录添加val.py脚本,代码如下:
from ultralytics import YOLO
if __name__ == '__main__':
# Load a model
# model = YOLO('yolov8m.pt') # load an official model
model = YOLO('runs/detect/train/weights/best.pt') # load a custom model
# Validate the model
metrics = model.val(split='val') # no arguments needed, dataset and settings remembered
split='val’代表使用验证集做测试,如果改为split=‘test’,则使用测试集做测试!
在项目的根目录添加test.py脚本,代码如下:
from ultralytics import YOLO
if __name__ == '__main__':
# Load a model
# model = YOLO('yolov8m.pt') # load an official model
model = YOLO('runs/detect/train/weights/best.pt') # load a custom model
results = model.predict(source="ultralytics/assets", device='0',save=True) # predict on an image
print(results)
test脚本测试assets文件夹下面的图片,save设置为true,则保存图片的测试结果!
YOLOv8l summary (fused): 287 layers, 43700691 parameters, 0 gradients, 165.0 GFLOPs Class Images Instances Box(P R mAP50 mAP50-95): 100%|██████████| 15/15 [00:01<00:00, 9.76it/s] all 230 1412 0.955 0.974 0.991 0.744 c17 230 131 0.984 0.992 0.995 0.831 c5 230 68 0.975 0.985 0.995 0.846 helicopter 230 43 0.948 1 0.979 0.617 c130 230 85 0.977 0.985 0.995 0.661 f16 230 57 0.994 0.965 0.986 0.667 b2 230 2 0.883 1 0.995 0.75 other 230 86 0.954 0.965 0.969 0.55 b52 230 70 0.967 0.971 0.979 0.838 kc10 230 62 0.995 0.984 0.989 0.837 command 230 40 0.995 1 0.995 0.826 f15 230 123 0.999 1 0.995 0.7 kc135 230 91 0.967 0.979 0.987 0.715 a10 230 27 1 0.583 0.976 0.479 b1 230 20 0.985 1 0.995 0.732 aew 230 25 0.918 1 0.995 0.788 f22 230 17 0.911 1 0.995 0.764 p3 230 105 1 0.966 0.995 0.804 p8 230 1 0.806 1 0.995 0.597 f35 230 32 0.983 0.938 0.993 0.595 f18 230 125 0.992 0.989 0.994 0.839 v22 230 41 0.976 1 0.995 0.7 su-27 230 31 0.985 1 0.995 0.876 il-38 230 27 0.982 1 0.995 0.841 tu-134 230 1 0.798 1 0.995 0.895 su-33 230 2 0.93 1 0.995 0.728 an-70 230 2 0.873 1 0.995 0.796 tu-22 230 98 0.997 1 0.995 0.82
链接:https://pan.baidu.com/s/1ZFdO3osb6UtkN353acKn6A?pwd=v3zr
提取码:v3zr
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。