共计 2502 个字符,预计需要花费 7 分钟才能阅读完成。
初识注意力机制
刚接触深度学习时,总会被各种注意力机制绕晕。今天我们就来聊聊两个容易混淆的概念:CBAM 和 Self-Attention。先说结论:它们虽然都叫 ” 注意力 ”,但完全是不同的设计思路和应用场景。

- CBAM:全称 Convolutional Block Attention Module,是专门为卷积网络设计的轻量级注意力模块
- Self-Attention:Transformer 的核心组件,主要处理序列数据的长距离依赖关系
举个形象的例子:CBAM 像是给 CNN 配了个智能聚光灯,告诉网络 ” 看这里重要 ”;而 Self-Attention 更像是让序列中的每个元素都能互相 ” 对话 ”。
原理对比
CBAM 的双分支结构
CBAM 包含两个串联的子模块:
- 通道注意力 (Channel Attention)
- 公式:$M_c(F) = \sigma(MLP(AvgPool(F)) + MLP(MaxPool(F)))$
-
通过全局池化 +MLP 学习每个通道的重要性
-
空间注意力 (Spatial Attention)
- 公式:$M_s(F) = \sigma(f^{7×7}([AvgPool(F); MaxPool(F)]))$
- 通过池化拼接 + 卷积学习空间位置的重要性
Self-Attention 的核心计算
对比下经典的自注意力公式:
$Attention(Q,K,V) = softmax(\frac{QK^T}{\sqrt{d_k}})V$
可以看到:
- CBAM 操作对象是 feature map 的通道和空间维度
- Self-Attention 计算的是序列元素间的相似度
PyTorch 实现详解
CBAM 模块完整代码
import torch
import torch.nn as nn
class CBAM(nn.Module):
def __init__(self, channels, reduction_ratio=16):
super().__init__()
# 通道注意力分支
self.channel_attention = nn.Sequential(nn.AdaptiveAvgPool2d(1), # 全局平均池化
nn.Conv2d(channels, channels//reduction_ratio, 1),
nn.ReLU(),
nn.Conv2d(channels//reduction_ratio, channels, 1),
nn.Sigmoid())
# 空间注意力分支
self.spatial_attention = nn.Sequential(nn.Conv2d(2, 1, 7, padding=3), # 7x7 卷积
nn.Sigmoid())
def forward(self, x):
# 通道注意力
ca = self.channel_attention(x)
x = x * ca # 广播机制自动扩展维度
# 空间注意力
max_pool = torch.max(x, dim=1, keepdim=True)[0]
avg_pool = torch.mean(x, dim=1, keepdim=True)
sa = self.spatial_attention(torch.cat([max_pool, avg_pool], dim=1))
return x * sa
嵌入 ResNet 示例
def conv3x3(in_planes, out_planes, stride=1):
return nn.Conv2d(in_planes, out_planes, kernel_size=3, stride=stride, padding=1, bias=False)
class BasicBlock(nn.Module):
expansion = 1
def __init__(self, inplanes, planes, stride=1, downsample=None):
super().__init__()
self.conv1 = conv3x3(inplanes, planes, stride)
self.bn1 = nn.BatchNorm2d(planes)
self.relu = nn.ReLU(inplace=True)
self.conv2 = conv3x3(planes, planes)
self.bn2 = nn.BatchNorm2d(planes)
self.downsample = downsample
self.stride = stride
# 在残差连接前添加 CBAM
self.cbam = CBAM(planes)
def forward(self, x):
residual = x
out = self.conv1(x)
out = self.bn1(out)
out = self.relu(out)
out = self.conv2(out)
out = self.bn2(out)
# 应用注意力
out = self.cbam(out)
if self.downsample is not None:
residual = self.downsample(x)
out += residual
return self.relu(out)
实验对比
计算开销对比 (输入尺寸 =224×224)
| 机制类型 | 参数量 | FLOPs |
|---|---|---|
| CBAM | ~1.2K | 0.01G |
| Self-Attention | ~590K | 0.56G |
CIFAR-10 分类准确率
| 模型 | 基础准确率 | +CBAM | +Self-Attention |
|---|---|---|---|
| ResNet18 | 93.2% | 94.7% | 93.5% |
| MobileNetV2 | 91.8% | 93.1% | 92.0% |
避坑指南
- 特征图尺寸问题
- 空间注意力中的 7 ×7 卷积要求特征图尺寸≥7
-
对于小尺寸输入 (如 CIFAR 的 32×32),建议减小卷积核尺寸
-
1×1 卷积的特殊作用
- 在通道注意力中,1×1 卷积相当于全连接层
- 通过 reduction_ratio 控制计算量,通常设为 16 或 32
延伸思考
在实际项目中我们可以考虑:
- 如何将 CBAM 与 Transformer 结合?比如在 CNN 提取特征后接 Transformer 时,先用 CBAM 强化重要特征
- 对于目标检测任务,CBAM 可能更适合处理局部特征,而 Self-Attention 擅长建模全局关系
注意力机制就像给模型装上 ” 智能眼镜 ”,关键是要根据任务特点选择合适的设计。希望这篇笔记能帮你理清这两个重要概念的区别与应用场景。
正文完
