拓十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

注意力机制全解析:从SE到自注意力,选型与实战指南

注意力机制全解析:从SE到自注意力,选型与实战指南

这两年做深度学习的,不管你是搞CV还是NLP,几乎都绕不开“注意力机制”这个词。我见过不少同学,GitHub上找了个SE或者CBAM模块,往自己的网络里一插,准确率涨了就说“注意力就是牛”,不涨就说“模块没用”,然后就去换下一个。其实很多时候,问题是出在没搞清楚这些注意力机制到底在“注意”什么、用在什么位置、计算开销能不能承受。

这篇文章我把常见的注意力机制拉通梳理一遍,包括SE通道注意力、CA坐标注意力、CBAM混合注意力、自注意力、多头注意力、时序注意力,讲清楚它们各自的原理、适用场景、工程落地时的坑,最后给出一套选型和排查的思路。内容尽量用我实际项目里的经验来讲,适合刚入门想系统了解注意力的同学,也适合已经在用但想把模块选型和调参做细的工程师。我会把关键原理讲透,附带可以抄作业的代码片段,也会说清楚哪些地方容易翻车。

1. 注意力机制到底在做什么:先建立整体认知

1.1 一个视角:注意力就是信息重标定

很多讲注意力的文章一上来就搬出Transformer、QKV这些概念,但其实注意力机制最初级的形态,理解成“信息重标定”就够了。

什么叫重标定?举个例子,你在一个满是杂物的房间里找钥匙,你的视觉系统并不会对房间里所有东西一视同仁,而是会优先把目光聚焦在桌面、口袋、门框这些可能放钥匙的地方。这个“聚焦”的过程,就是对视觉信息的不同区域给予不同的权重。深度学习里的注意力机制,做的本质上也是这件事:让网络决定哪些通道、哪些位置、哪些时间步更重要,然后给它们更高的权重。

具体到实现上,注意力模块通常是一个很小的子网络,它输入是已有的特征图,输出一个权重向量或权重矩阵,然后用这个权重去乘原来的特征。权重越大,对应特征对后续任务的贡献就越大。这就是为什么注意力模块往往可以“即插即用”——它不改变原有网络的主体结构,只是对特征做了一次重标定。

这个视角对我帮助很大,因为当你把注意力理解为“重标定”时,你就能明白它为什么有时候不起作用:如果原特征本身的信息分布已经很均匀,或者任务本身不需要强调某一部分,那强行加注意力就是在给特征图做无意义的变换,甚至会干扰原有信息。

1.2 按作用维度给注意力机制分个类

我们平时看到的注意力机制版本太多了,如果不分类,记忆成本很高。我习惯按它作用的维度来分,这样选型的时候思路也清晰。

第一类是通道注意力,代表就是SE(Squeeze-and-Excitation)和ECA。这类注意力关注的是“哪些特征通道更重要”。比如一张猫的图片,有的通道可能主要响应毛发的纹理,有的通道响应背景的轮廓,通道注意力会去放大毛发的响应、抑制背景的响应。

第二类是空间注意力,关注的是“特征图哪些位置更重要”。比如检测任务中,目标所在的区域应该获得更大的权重,背景区域权重应该被压低。CBAM里的空间注意力部分,就是在做这件事。

第三类是混合注意力,典型代表是CBAM,它把通道注意力和空间注意力串联起来,先告诉网络“看哪些特征”,再告诉网络“看哪些位置”。

第四类是自注意力,它和前三类有本质区别。前几类是通过一个小网络学习一个固定的权重去重标定原特征,而自注意力是把特征内部两两之间的关系算出来,每个位置都由其他所有位置加权求和得到。这是一种动态建模,复杂度更高,表达能力也更强。

第五类是时序注意力,专门用于序列数据或时间维度的建模,比如语音帧、股票序列、传感器信号、视频帧等。它处理的是“哪个时间步更重要”的问题。

这样一分,再看那些五花八门的注意力模块,就会发现绝大多数都是在这些维度上做文章。有的在池化方式上做创新,比如用最大池化代替平均池化;有的在运算方式上做文章,比如用1D卷积代替全连接;有的则是在多个维度上做组合。理解了分类,再看具体模块就会轻松很多。

1.3 为什么会出现这么多变体

原因其实很朴素:不同任务、不同算力条件下,对注意力的需求完全不一样。

SE在图像分类上有效果,但它的全连接层会引入参数量,而且对位置信息完全无感。于是ECA提出用1D卷积替代全连接,把参数量降到极低;CA则专门针对位置信息缺失的问题,把全局池化分解成水平方向和垂直方向两个池化。CBAM觉得不光通道重要,空间位置也重要,于是把两者串起来。自注意力虽然表达能力最强,但计算复杂度和序列长度的平方成正比,输入尺寸一大就扛不住,又催生出一堆稀疏注意力、窗口注意力、线性注意力。

说白了,注意力机制的进化史,就是一张在“表达能力、参数量、计算量、适用场景”之间找平衡的权衡表。没有哪个模块在所有场景下都无敌,只有合适不合适。理解到这一层,你再看那些新出的注意力变体,就能自动去分析它的设计动机和代价,而不是被动地追新。

2. 通道注意力解析:SE与ECA的实战细节

2.1 SE模块的核心:压缩与激发

SE是通道注意力里最经典的一个,思想非常简洁。对输入特征图 (X \in R^{B,C,H,W}),先做全局平均池化,把每个通道的 (H \times W) 空间信息压缩成一个数值,得到 (z \in R^{B,C})。这个操作叫Squeeze,也就是“压缩”。然后再做Excitation,即“激发”,用两个全连接层学习每个通道的权重。

第一层全连接把通道从 (C) 压缩到 (C/r),用ReLU激活,第二层再恢复回 (C),用Sigmoid输出一个0到1之间的权重向量。最后把权重向量逐通道乘回原始特征图。这里 (r) 是压缩比例,通常在ResNet系列里设为16。

我经常被问到,为什么SE不直接用每个通道的均值来做权重,非要绕一圈全连接?原因有两个。第一,直接算出来的权重和通道之间的交互没有任何关系,而全连接的bottleneck结构允许不同通道之间共享信息,能学到通道间的关系。第二,bottleneck结构(缩再放)能限制模型复杂度,起到类似正则的作用,否则通道很多的时候参数量会爆炸。

实际使用SE的时候,我一般会把这个模块放在残差分支的最后一层卷积之后、残差相加之前,或者放在每个基础block的末尾。这样修改对原网络的破坏最小,也最容易做消融实验。还有一个细节是压缩比例 (r),它在ImageNet上实验出来的优选值是16,但如果你做的是小模型或者通道数很小的网络,16可能会把中间层压得太狠,信息丢失太严重,可以试着调成4或者8。

2.2 ECA:去掉全连接,让通道注意力更轻

ECA(Efficient Channel Attention)是继SE之后一个很讨巧的改进。它的核心观点是:全连接其实没必要,通道间的关系往往只和相邻局部通道有关。SE里用全连接建模了所有通道之间的交互,但实际有效的信息是局部的,强行全局建模反而带来了大量冗余参数。

ECA的做法很简单:全局平均池化之后,不接全连接,而是用一个一维卷积直接在通道维度上做局部交互,然后接Sigmoid得到权重。一维卷积的卷积核大小 (k) 并不是拍脑袋定的,而是根据通道数自适应计算出来的。公式是:

[ k = \left| \frac{\log_2(C)}{\gamma} + \frac{b}{\gamma} \right|_{odd} ]

其中 (\gamma) 一般取2,(b) 取1,结果取最近的奇数。这样通道越多,卷积核越大,局部交互的范围也越大。比如通道数为64时,(k) 约等于5;通道数为512时,(k) 约等于9。

ECA在效果上和SE基本持平,但参数量少得多,只有SE的几十分之一。我之前在YOLO系列检测模型里替换SE为ECA,mAP基本不掉,但模型大小和推理耗时都有下降。如果你的项目对推理速度和模型体积很敏感,比如移动端部署、边缘设备推理,我会优先推荐ECA。

用ECA的时候要注意一点:一维卷积是在“通道”这个维度上滑动的,你需要在实现时把特征从 ((B,C,1,1)) 转成适合Conv1d的 ((B,C,1)) 形状,或者直接用Conv2d处理。很多新人在这里形状对不上,报错报半天。

2.3 通道注意力注意事项

通道注意力虽然简单,但在工程里还是有几个容易踩的点。

第一,Sigmoid输出权重初始在0.5附近,这意味着刚开始训练时,注意力模块几乎对所有通道都是“打五折”。如果网络是预训练模型,这种缩放会在一开始打乱原有的特征分布,导致loss在初始阶段出现波动。解决办法是在某些实现里给最后一层全连接或Conv1d的bias做特殊初始化,让Sigmoid输出接近1,让模块在训练初期尽量保持恒等映射。

第二,通道注意力模块插入的位置很重要。我见过有人把SE插到激活函数之前,也有人插在之后,效果差异很大。我的经验是:如果前面接的是ReLU,放在ReLU之前和之后差别不大;如果前面接的是Sigmoid或者Tanh,放在之前更稳。因为Sigmoid/Tanh的输出已经是0~1或-1~1的有界值,再乘一个权重不会造成数值不稳定,而ReLU的输出如果是大范围的,先缩放再接非线性反而更平滑。

第三,不要在浅层滥用通道注意力。网络前几层的特征图尺寸大、通道数少,通道注意力的收益往往不明显,反而会拖慢训练速度。我一般建议从网络的第2或第3个stage开始再接SE/ECA,浅层保持原始卷积的较高分辨率信息。

3. 空间注意力与混合注意力:CBAM与CA

3.1 CBAM:通道和空间一起做

CBAM(Convolutional Block Attention Module)是“通道-空间协同注意力机制”的典型代表。它的结构是串联的:特征图先进通道注意力模块,得到和SE类似但稍有不同的通道权重,加权后再进空间注意力模块,得到空间权重,再加权。

CBAM的通道注意力和SE最大的区别在于:SE只用全局平均池化,CBAM则同时使用了全局平均池化和全局最大池化。最大池化捕捉的是每个通道上“最强烈的响应”,平均池化捕捉的是整体分布,两者互补。两个池化结果各自过同一个全连接共享层,输出逐元素相加后再过Sigmoid,得到通道权重。

空间注意力部分更有意思。对通道注意力加权后的特征图,在通道维度上分别做平均池化和最大池化,得到两个 (H \times W) 的二维特征,然后把它们沿着通道方向拼接起来,得到2通道的特征图,再用一个 (7 \times 7) 的卷积层将其压缩成1通道,最后过Sigmoid得到空间权重。这个权重会乘回通道加权后的特征图,最终让网络同时知道了“看什么特征”和“看哪里”。

我最早用CBAM是在一个细粒度图像分类项目上。基线模型是带SE的ResNet50,换到CBAM之后,准确率提升了大约1.2个百分点。后来我又试过颠倒CBAM里通道和空间的顺序(先空间后通道),效果稍微差一些,说明通道优先的设计在多数视觉任务里是对的:先确定哪些特征有意义,再看这些特征出现在哪里。

3.2 理解Coordinate Attention(CA):不只是又一个注意力

热词里有“ca注意力机制”,这里要明确一下,通常说的CA是指Coordinate Attention(坐标注意力),不是Channel Attention。CA的核心卖点是:在保持通道注意力低开销优势的同时,把位置信息也显式地编码进去。

SE和ECA都有一个先天不足:全局平均池化把空间信息完全压扁了,网络只知道“这个通道整体强不强”,不知道“强在哪里”。而CBAM虽然加了空间注意力,但空间注意力容易丢失长距离的依赖关系,而且空间注意力模块大多是用卷积做的,感受野有限。

CA的思路很优雅。它把全局池化分解成两个方向:一个水平方向的平均池化,一个垂直方向的平均池化。也就是说,对输入特征图 (X),分别对 (H) 维和 (W) 维做全局平均池化,得到两个特征向量,一个形状是 ((B,C,1,W)),另一个形状是 ((B,C,H,1))。这两个向量分别编码了水平方向的空间依赖和垂直方向的空间依赖。

接下来,把这两个向量在空间维度上做concat,然后通过一个 (1 \times 1) 卷积降维,再用BatchNorm和激活函数处理。之后又split成两个独立的向量,各自经过 (1 \times 1) 卷积恢复通道数,最后用Sigmoid得到两个方向的注意力权重。这两个权重会分别作用到原始特征图上,相当于告诉网络“每一行的重要程度”和“每一列的重要程度”。

CA这种设计很聪明,因为它把二维的位置信息分解成了两个一维的问题,计算量不大,但能捕捉到空间位置信息。对移动端小模型来说,CA是一个很值得尝试的模块。我用过MobileNetV3在检测任务上替换SE为CA,在相同FLOPs下mAP有小幅提升,尤其对小目标的召回率更有帮助,因为小目标的位置信息对检测太重要了。

3.3 混合注意力常见问题

关于CBAM和CA这类混合注意力,有几个问题出现过很多次。

第一个问题是CBAM的空间注意力部分计算开销。(7 \times 7) 卷积虽然不重,但如果特征图尺寸很大,比如在Encoder的第一层插入CBAM,空间注意力操作的耗时其实不可忽略。我的习惯是只在大尺寸特征图上用通道注意力,在分辨率降低到 (14 \times 14) 或更小之后才接完整CBAM。否则训练速度下降会很明显。

第二个问题是CA的坐标池化对某些任务不友好。如果你的任务里目标的形态是高度各向异性的,比如文本检测里细长的文字区域或者长条形的条形码,CA的水平方向和垂直方向分解其实会损失一些对角方向的位置关系。这种情况我试过上采样特征金字塔再插CA,效果好一些。

第三个问题是BN和注意力的协同。CA自身有BatchNorm,如果你原来的网络已经有一层BatchNorm,插入CA后等于同一个block里出现了两层BN,这在某些极端情况下会导致训练不稳定。遇到这种情况,可以把CA里的BN换成LayerNorm,或训练时适当降低学习率。

4. 自注意力与多头注意力机制

4.1 从特征交互理解Q、K、V

前面讲的SE、CBAM、CA,本质上都是通过一个小网络生成权重,然后去重标定原始特征。但自注意力是完全不同的路子:它让特征内部两两之间直接交互,输出的每个位置都带有全图的信息。

自注意力的核心概念是Query、Key、Value,也就是Q、K、V。我做个生活化的比喻:你可以把Q理解成“你要问的问题”,K是“资料库里的索引标签”,V是“标签对应的正文内容”。你在图书馆查资料时,会拿问题去和所有标签做匹配,匹配度高的就重点阅读对应的正文,匹配度低就看一眼带过。

工程实现上,对于序列输入 (X \in R^{B,N,D}),其中 (N) 是序列长度,(D) 是特征维度,分别通过三个可学习的线性变换得到 (Q = XW_Q)、(K = XW_K)、(V = XW_V)。然后计算注意力权重矩阵:

[ Attention(Q,K,V) = softmax(\frac{QK^T}{\sqrt{d_k}})V ]

这里的 (QK^T) 计算的是任意两个位置之间的相似度,除以 (\sqrt{d_k}) 是为了防止点积结果过大导致softmax的梯度消失。(d_k) 就是Key向量的维度,通常等于 (D/h),(h) 是注意力头数。softmax归一化之后,每一行权重之和为1,表示某个位置对其他所有位置的关注度分布,最后用权重去加权求和V,就得到了输出。

自注意力最大的优势是能捕捉长距离依赖。CNN靠堆叠卷积层扩大感受野,RNN靠逐步传递隐状态,都存在长距离信息衰减的问题,而自注意力一步到位,任意两个位置之间只隔了两次线性变换加一次点积。这也是Transformer为什么能碾压RNN和CNN成为主流架构的核心原因之一。

4.2 多头为什么要“多”

多头自注意力机制,就是把上面的自注意力过程并行做 (h) 次,每次用不同的 (W_Q、W_K、W_V),得到 (h) 个不同的输出,然后把它们拼接起来再过一次线性变换。

这样做的意义类比一下:你看一幅画时,可能同时关注构图、色彩、线条和细节,不同关注点看到的是不同维度的信息。多头自注意力也一样,不同的头可以在不同的子空间里学习特征之间的关系。有的头可能倾向于关注语义相关的词,有的头关注句法位置,有的头关注视觉上的空间相邻性。一个头捕捉不全,多个头互补,模型整体的表达能力就上来了。

在实际使用中,头数和每个头的维度是一个关键配置。一般经验是保持 (D = h \times d_k),比如 (D=512) 时用 (h=8),每个头 (d_k=64)。头数不是越多越好。头数太多,每个头的维度太低,能捕捉的信息就有限;头数太少,不同层面的关注点可能覆盖不全。我在文本分类任务上试过,Bert-base的 (h=12) 调成 (h=6) 之后,参数量降了,但准确率也掉了约1个百分点,效果并不划算。

还有一个经常被忽略的细节:多头注意力里不同头可能出现退化,就是某些头的输出几乎相同,没有学到差异化信息。特别是训练数据量不大的时候特别容易发生。一个缓解方案是增加attention头的dropout,或者对注意力矩阵做“DropKey”操作,随机掩盖部分key,迫使每个头学习不同的模式。

4.3 自注意力落地的尺寸与计算问题

自注意力很强,但它有个绕不开的坎:计算复杂度随序列长度 (N) 呈平方级增长,即 (O(N^2))。

原因就是注意力矩阵 (QK^T) 的形状是 (N \times N)。对于文本序列,几百个token的复杂度还能接受;但放到视觉任务里,如果输入是 (56 \times 56) 的特征图,展平成序列就有3136个位置,注意力矩阵就有约983万个元素,显存直接告急。

在CV任务里落地自注意力,目前比较可行的又比较实用的做法有几类。一类是窗口注意力,比如Swin Transformer,把特征图切成固定大小的窗口,只在窗口内做自注意力,然后通过shift窗口来交互信息;一类是局部注意力叠加全局稀疏注意力,比如对特征图每隔几个位置采样一次,做全局交互再插值回去;还有一类就是线性注意力,用核技巧把 (QK^T) 的计算近似成先算 (K^TV) 再算 (Q(K^TV)),把复杂度从 (O(N^2)) 降到 (O(N))。

我自己的习惯是:如果输入图片分辨率不大,比如224x224分类任务,直接整图自注意力问题不大;如果做的是检测、分割这种高分辨率输入的密集预测任务,第一个stage尽量别上全局自注意力,先在低分辨率的深层特征上用或者用窗口注意力。

5. 时序注意力:处理时间依赖的方向

5.1 什么时候需要时序注意力

热词里有一个“时序注意力机制”,这类注意力在NLP和时间序列预测、语音、视频任务里用得很多。它要解决的核心问题是:在一个时间序列里,哪些时间步对当前预测更重要。

举个生活化的例子,预测明天是否会下雨时,今天凌晨2点的气压读数可能和明天早上8点的降雨没有直接关系,而前天同一时段的湿度趋势参考价值更大。时序注意力的任务,就是自动学出这种“什么时间的信息权重更高”。

需要时序注意力的典型场景包括:传感器信号故障诊断,比如电机振动信号里某一小段是故障特征;股票价格走势预测,关键拐点信息更重要;语音识别,不同音素在不同时间位置的重要性不同;视频分类,动作发生在视频的某个片段里。

5.2 时序注意力的常见实现思路

理解时序注意力之前,要知道一个更早也经典的做法:Encoder-Decoder加BahdanauAttention。在机器翻译里,Encoder把源语言句子编码成一系列隐状态,Decoder在生成每个目标词时,不是只看最后一个隐状态,而是通过注意力把所有源语言隐状态加权求和,权重由当前Decoder状态和各个Encoder隐状态的匹配度算出。这本质上就是一种时序注意力,只是它应用在跨序列交互上。

在纯时间序列任务里,更常见的是把一个时间窗口的序列特征通过LSTM或者一维CNN编码,然后在时间维度上做注意力。比如先用LSTM得到每个时间步的隐状态 (h_1, h_2, ..., h_T),然后通过一个小网络计算出每个时间步的注意力权重,最后做加权求和得到序列的全局表示,再喂给分类器或回归头。

还有一个思路是把时间维度和通道维度结合起来设计,比如在通道注意力里引入时间上下文。我曾在一个电力负荷预测项目里用过类似TAM(Temporal Attention Module)的结构:序列特征先经过一维CNN提取局部时间信息,然后对时间维度做全局平均池化和最大池化,拼接后通过卷积生成时间权重,最后对每个时间步加权。相比直接用LSTM+attention,这个模块训练速度快很多,效果也没有明显下降。

5.3 时序注意力在工程中的坑

时序注意力在工程里最大的坑是信息泄漏,这是个非常严重的问题。进行时间序列预测时,你的模型只能用截止到当前时刻的数据去预测未来,绝不能使用未来信息。

很多人在实现时序注意力时,用的是全局softmax,即某个时间步会关注到所有时间步,包括它后面的未来步。这在离线训练时可能效果很好,因为网络“作弊”提前看到了未来,但线上部署时未来数据还没有出现,模型性能会暴跌。解决办法是使用带mask的注意力,保证计算某个时间步的输出时,attention只能看到当前时刻及之前的信息。PyTorch里可以用attn_mask参数,或者手动把未来位置填充为 (-\infty)。

另一个坑是序列长度的选择。时序注意力的作用范围受输入窗口长度限制,窗口太短,注意力看不到足够的历史上下文;窗口太长,计算延迟和显存占用上升。我的经验是先做简单的自相关分析,确定序列的周期性或依赖长度,再设定窗口。比如电力负荷数据有24小时周期,窗口至少得覆盖一个完整周期。

还有一个容易被忽略的点是时序特征的对齐。LSTM输出的隐状态在不同时间步的尺度可能有差异,如果直接把原始时间步特征做注意力,训练初期可能出现权重分布不均。我一般会在注意力打分之前对特征做LayerNorm,让每个时间步的特征都保持在相近的尺度上,这样注意力训练更稳定。

6. 注意力机制选型建议与问题排查技巧

6.1 选型建议:从任务和硬件出发

注意力机制这么多,最怕一上来就乱堆。我自己的选型路径是先回答三个问题:数据是什么类型的,任务对位置信息敏感吗,硬件算力限制是多少。

如果主要做图像分类或移动端小模型,通道注意力是首选,优先用ECA,其次SE。ECA参数量小,效果好,工程成熟。如果你的任务里目标位置信息很重要,比如目标检测、关键点检测、小目标分类,那在通道注意力的基础上可以加CA或切换为CBAM。CA更适合轻量网络,CBAM更适合重视精度、算力宽裕的模型。

如果处理的是序列数据,比如文本、语音、传感器信号,先判断序列长度。序列在100以内,可以直接用自注意力(Transformer Block);序列在几千或几万级别,考虑窗口注意力、稀疏注意力或线性注意力。如果对可解释性有需求,传统的Encoder-Decoder加BahdanauAttention反而更容易观察权重。

如果任务需要同时建模空间和时间信息,比如视频分类,那就不要想着用一个模块全搞定。我在做视频动作识别的时候,合理的做法是空间维度上用2D卷积处理单帧,时间维度上用时序注意力或多头自注意力跨帧交互,两个维度分开建模再融合,比塞一个重量级的3D注意力模块效果更好,训练也更容易收敛。

6.2 典型问题排查实录

我把实践中经常遇到的几个注意力相关问题和排查思路整理成了速查表,方便直接对照。

现象可能原因排查思路与建议
插入注意力后效果不升反降模块插入位置不合理,浅层特征被过度重标定只保留深层stage的注意力,浅层不放
训练初期loss剧烈波动注意力初始权重偏离1太多,破坏预训练特征分布初始化最终权重层为1,或先冻结注意力模块训练几轮再解冻
模型体积变大,推理变慢SE的全连接或CBAM的大卷积开销大换成ECA,或把CBAM空间卷积分支的7x7改成3x3
自注意力显存溢出序列长度太长,注意力矩阵过大使用窗口注意力、下采样或线性注意力
多头注意力各个头学习到相同模式训练数据不足或Dropout过高降低attention dropout,或使用DropKey
时序注意力训练表现好但线上崩注意力引入了未来信息造成泄漏检查attention mask,训练时强制mask掉未来位置
加了CA后训练速度明显变慢CA中两个方向池化+多次卷积开销被低估检查是否在高分辨率特征图上插入,移到低分辨率stage

6.3 一些实战心得

最后聊一点我自己的体会。深度学习项目里有一条很朴素的规律:加模块容易,去模块很难。尤其是注意力这种即插即用的组件,一开始谁都忍不住多塞几个,结果训练变慢、过拟合、效果还掉了。我现在的做法是先把Base模型跑到一个预期的水平,用一个固定的验证集记录指标,然后像做对照实验一样,每次只加一个注意力模块,同一个权重初始化种子,同一套超参数,跑完对比。

选择注意力模块的时候,不要只看最终精度,还要算清楚代价。我一般在消融实验里同时记录三个指标:准确率、FLOPs、推理延迟。有的模块精度涨了0.3%,但推理耗时多了15%,对于实时项目来说完全不划算。ECA之所以在很多工业项目里受欢迎,就是因为它用极小的代价换到了接近SE甚至超过SE的效果。

还有一个容易被低估的点是随机种子和初始化。注意力模块有时候对种子非常敏感,同一个模块换一个种子,效果可能从+0.8%变成-0.2%。遇到这种情况,不要急着否定模块,先跑3个不同的种子看看均值和方差。如果均值是正的、方差大,那说明模块有效但不稳定,可以考虑加一些正则或者调整初始化方法;如果均值本身就是负的,那大概率是这个模块和你的任务不匹配,不要在它身上继续浪费时间。

时序注意力也是一样,不同窗口长度对结果的影响非常大。我有一次做传感器故障诊断,窗口从128换成256,准确率掉了3个百分点,原因就是过长的窗口引入了大量无关的历史噪声。后来用滑动窗口加时间衰减权重,才把注意力重新聚焦到故障前的关键片段上。

注意力机制本质上是一种先验,它告诉你的网络“某些信息更重要”。用对了,它是放大器;用不对,它就是噪声源。希望这篇文章能帮你把这些先验放到正确的位置上。

返回列表