CBAM注意力机制与自注意力机制的区别与实现详解

1次阅读
没有评论

共计 2502 个字符,预计需要花费 7 分钟才能阅读完成。

image.webp

初识注意力机制

刚接触深度学习时,总会被各种注意力机制绕晕。今天我们就来聊聊两个容易混淆的概念:CBAM 和 Self-Attention。先说结论:它们虽然都叫 ” 注意力 ”,但完全是不同的设计思路和应用场景。

CBAM 注意力机制与自注意力机制的区别与实现详解

  • CBAM:全称 Convolutional Block Attention Module,是专门为卷积网络设计的轻量级注意力模块
  • Self-Attention:Transformer 的核心组件,主要处理序列数据的长距离依赖关系

举个形象的例子:CBAM 像是给 CNN 配了个智能聚光灯,告诉网络 ” 看这里重要 ”;而 Self-Attention 更像是让序列中的每个元素都能互相 ” 对话 ”。

原理对比

CBAM 的双分支结构

CBAM 包含两个串联的子模块:

  1. 通道注意力 (Channel Attention)
  2. 公式:$M_c(F) = \sigma(MLP(AvgPool(F)) + MLP(MaxPool(F)))$
  3. 通过全局池化 +MLP 学习每个通道的重要性

  4. 空间注意力 (Spatial Attention)

  5. 公式:$M_s(F) = \sigma(f^{7×7}([AvgPool(F); MaxPool(F)]))$
  6. 通过池化拼接 + 卷积学习空间位置的重要性

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%

避坑指南

  1. 特征图尺寸问题
  2. 空间注意力中的 7 ×7 卷积要求特征图尺寸≥7
  3. 对于小尺寸输入 (如 CIFAR 的 32×32),建议减小卷积核尺寸

  4. 1×1 卷积的特殊作用

  5. 在通道注意力中,1×1 卷积相当于全连接层
  6. 通过 reduction_ratio 控制计算量,通常设为 16 或 32

延伸思考

在实际项目中我们可以考虑:

  1. 如何将 CBAM 与 Transformer 结合?比如在 CNN 提取特征后接 Transformer 时,先用 CBAM 强化重要特征
  2. 对于目标检测任务,CBAM 可能更适合处理局部特征,而 Self-Attention 擅长建模全局关系

注意力机制就像给模型装上 ” 智能眼镜 ”,关键是要根据任务特点选择合适的设计。希望这篇笔记能帮你理清这两个重要概念的区别与应用场景。

正文完
 0
评论(没有评论)