共计 2465 个字符,预计需要花费 7 分钟才能阅读完成。
CBAM 注意力机制与自注意力机制的本质区别及实战应用
概念区分与数学原理
CBAM(Convolutional Block Attention Module)和自注意力机制(Self-Attention)是两种完全不同的注意力机制:
- CBAM:
- 由通道注意力(Channel Attention)和空间注意力(Spatial Attention)两个子模块组成
- 通道注意力公式(基于全局平均 / 最大池化):
M_c(F) = \sigma(MLP(AvgPool(F)) + MLP(MaxPool(F))) -
空间注意力公式(基于卷积操作):
M_s(F) = \sigma(f^{7×7}([AvgPool(F); MaxPool(F)])) -
自注意力机制 :
- Transformer 架构的核心组件
- 计算过程(Q/K/ V 变换):
Attention(Q,K,V) = softmax(\frac{QK^T}{\sqrt{d_k}})V
常见误用与性能影响
- 计算资源浪费案例 :
-
在 CNN 架构中误用自注意力会导致:
- 计算复杂度从 O(n) 飙升到 O(n²)
- 小分辨率特征图上出现过度平滑现象
-
模型性能下降实例 :
- 在 ImageNet 分类任务中测试表明:
- 错误替换 CBAM 为自注意力会使 top- 1 准确率下降 3 -5%
- 推理速度降低 40% 以上
PyTorch 实现详解
通道注意力模块
class ChannelAttention(nn.Module):
def __init__(self, in_planes, ratio=8):
super().__init__()
# [B,C,H,W] -> [B,C,1,1] 两种池化方式
self.avg_pool = nn.AdaptiveAvgPool2d(1)
self.max_pool = nn.AdaptiveMaxPool2d(1)
# 共享参数的 MLP(实际用 1x1 卷积实现)self.fc1 = nn.Conv2d(in_planes, in_planes//ratio, 1, bias=False)
self.relu = nn.ReLU()
self.fc2 = nn.Conv2d(in_planes//ratio, in_planes, 1, bias=False)
def forward(self, x):
avg_out = self.fc2(self.relu(self.fc1(self.avg_pool(x))))
max_out = self.fc2(self.relu(self.fc1(self.max_pool(x))))
return torch.sigmoid(avg_out + max_out) # [B,C,1,1]
空间注意力模块
class SpatialAttention(nn.Module):
def __init__(self, kernel_size=7):
super().__init__()
# 经验表明 7x7 卷积在多数场景效果最佳
self.conv = nn.Conv2d(2, 1, kernel_size, padding=kernel_size//2, bias=False)
def forward(self, x):
# 沿通道维度做平均 / 最大池化 [B,C,H,W]->[B,1,H,W]
avg_out = torch.mean(x, dim=1, keepdim=True)
max_out = torch.max(x, dim=1, keepdim=True)[0]
concat = torch.cat([avg_out, max_out], dim=1) # [B,2,H,W]
return torch.sigmoid(self.conv(concat)) # [B,1,H,W]
ResNet 集成示例
class CBAM_ResBlock(nn.Module):
def __init__(self, in_channels, out_channels, stride=1):
super().__init__()
self.conv1 = nn.Conv2d(in_channels, out_channels, 3, stride, 1)
self.bn1 = nn.BatchNorm2d(out_channels)
self.conv2 = nn.Conv2d(out_channels, out_channels, 3, 1, 1)
self.bn2 = nn.BatchNorm2d(out_channels)
self.channel_att = ChannelAttention(out_channels)
self.spatial_att = SpatialAttention()
def forward(self, x):
residual = x
out = F.relu(self.bn1(self.conv1(x)))
out = self.bn2(self.conv2(out))
# CBAM 处理(注意顺序:先通道后空间)out = self.channel_att(out) * out
out = self.spatial_att(out) * out
return F.relu(out + residual)
实验对比分析
CIFAR-10 测试结果
| 模型类型 | 参数量 (M) | FLOPs(G) | 准确率 (%) |
|---|---|---|---|
| ResNet-18 | 11.2 | 0.56 | 93.5 |
| +CBAM | 11.3 | 0.57 | 94.8 |
| +Self-Attention | 12.1 | 1.02 | 92.3 |
注意力热图可视化

– CBAM 能同时增强关键通道和空间区域
– 自注意力在低分辨率特征上出现过度聚焦
工程实践指南
- BN 层协同技巧 :
- 应将 CBAM 模块放在 BN 层之后
-
避免在注意力权重应用前做 ReLU 激活
-
多分辨率适配方案 :
- 空间注意力卷积核应随输入尺寸调整:
kernel_size = min(7, input_size//2) # 保证感受野合理 -
通道注意力不受分辨率影响
-
初始化策略 :
- 将最终 sigmoid 前的卷积层权重初始化为 0
- 可使训练初期等效于原始网络
延伸思考
在视频理解任务中,可以考虑:
1. 增加时间维度的 3D 卷积注意力
2. 在 LSTM 单元中嵌入 CBAM 机制
3. 跨帧的特征通道相关性分析
期待读者在实践中探索更多可能性,也欢迎分享您的改进方案。
正文完
