Day 50 CBAM 注意力机制

  1. CBAM 注意力机制概述
    1.1 什么是 CBAM?

CBAM (Convolutional Block Attention Module) 是一种能够集成到任何卷积神经网络架构中的注意力模块。

1.2 核心目标

通过学习的方式,自动获取特征图在通道和空间维度上的重要性

对特征图进行自适应调整,增强重要特征,抑制不重要特征

提升模型的特征表达能力和性能

简单来说,CBAM 就像是给模型装上了"智能眼镜",让模型能够更精准地看到图像中关键的部分。

1.3 CBAM 的组成

CBAM 由两个主要部分组成:

  • 通道注意力模块 (Channel Attention):分析"哪些通道的特征更关键"
  • 空间注意力模块 (Spatial Attention):定位"关键特征在图像中的具体位置"
1.4 CBAM vs SE 注意力
  • SE 通道注意力的局限:仅关注"哪些通道重要",未考虑"重要信息在空间中的位置"
  • CBAM 的突破:二者结合,让模型同时学会"关注什么"和"关注哪里"
1. 第一步:通道注意力(Channel Attention Module, CAM)

核心目标:判断「哪些通道的特征更重要」。比如在识别猫的任务中,「猫耳朵」「猫爪子」对应的通道特征比「背景纹理」对应的通道特征更重要。

工作流程(超简化版)

  1. 对特征图 [C, H, W]全局池化 ,把每个通道的 H×W 大小的特征,压缩成 1 个数值 ,得到一个 [C, 1, 1] 的向量(这个向量代表了每个通道的「全局重要性」)。
    • 这里用了两种池化:全局平均池化(GAP)和全局最大池化(GMP),目的是获取更全面的信息。
  2. 把这两个池化后的向量,输入一个简单的两层神经网络 (MLP),分别得到两个 [C, 1, 1] 的权重向量。
  3. 把两个权重向量相加 ,再经过一个 sigmoid 函数(把数值压缩到 0~1 之间),得到最终的通道注意力权重
  4. 把这个权重和原来的特征图 相乘 ------ 重要通道的特征会被放大,不重要的会被削弱。
2. 第二步:空间注意力(Spatial Attention Module, SAM)

核心目标:判断「特征图的哪些空间位置更重要」。还是识别猫的任务,特征图里「猫所在的位置」比「背景位置」更重要。

工作流程(超简化版)

  1. 把第一步通道注意力处理后的特征图 [C, H, W],在通道维度 做池化:计算每个空间位置(每个 H×W 点)的平均值和最大值,得到两个 [1, H, W] 的特征图。
  2. 把这两个特征图 拼接 在一起,变成 [2, H, W]
  3. 用一个 3×3 的卷积层 对拼接后的特征图降维,把通道数从 2 变回 1,得到 [1, H, W] 的特征图。
  4. 经过 sigmoid 函数得到空间注意力权重(0~1 之间)。
  5. 把这个权重和第一步处理后的特征图 相乘 ------ 重要空间位置的特征会被放大,不重要的会被削弱。
3. 最终输出

经过「通道注意力 → 空间注意力」两步处理后,得到的特征图就是被注意力机制增强后的特征,可以直接传入下一个卷积块继续训练。

三、CBAM 的优势:为啥大家都爱用?

  1. 轻量级:参数量极少,几乎不会增加模型的计算负担,适合嵌入各种 CNN 模型(比如 ResNet、MobileNet)。
  2. 即插即用:不需要修改原网络的主体结构,直接加在卷积块的末尾或开头就行。
  3. 双维度注意力:同时关注「通道」和「空间」两个维度,比只做单维度注意力的效果更好。

四、小白友好的总结

CBAM 就像一个「特征筛选器」:

  • 先筛选有用的特征种类 (通道注意力),再筛选有用的特征位置(空间注意力);

  • 让模型把精力集中在关键信息上,从而提升识别、分类等任务的准确率。

    import torch
    import torch.nn as nn
    import torch.nn.functional as F

    第一步:实现通道注意力模块(CAM)

    class ChannelAttention(nn.Module):
    def init(self, in_channels, reduction_ratio=16):
    """
    参数说明(小白版):
    - in_channels: 输入特征图的通道数(比如ResNet的卷积块输出通道数是64/128等)
    - reduction_ratio: 压缩系数(默认16,目的是减少MLP的参数量,不用改)
    """
    super(ChannelAttention, self).init()

    复制代码
          # 全局平均池化:[B, C, H, W] → [B, C, 1, 1]
          self.avg_pool = nn.AdaptiveAvgPool2d(1)
          # 全局最大池化:[B, C, H, W] → [B, C, 1, 1]
          self.max_pool = nn.AdaptiveMaxPool2d(1)
          
          # 两层MLP(全连接层):压缩通道数再还原,减少计算量
          self.fc = nn.Sequential(
              # 第一层:把通道数从 C 压缩到 C//reduction_ratio
              nn.Linear(in_channels, in_channels // reduction_ratio, bias=False),
              nn.ReLU(inplace=True),  # 激活函数,增加非线性
              # 第二层:把通道数还原回 C
              nn.Linear(in_channels // reduction_ratio, in_channels, bias=False)
          )
          # sigmoid函数:把数值压缩到0~1之间,作为注意力权重
          self.sigmoid = nn.Sigmoid()
    
      def forward(self, x):
          """
          前向传播(核心逻辑):
          x: 输入特征图,形状 [B, C, H, W]
          """
          # 平均池化 + MLP
          avg_out = self.fc(self.avg_pool(x).view(x.size(0), -1))  # [B, C]
          # 最大池化 + MLP
          max_out = self.fc(self.max_pool(x).view(x.size(0), -1))  # [B, C]
          
          # 两个结果相加 → [B, C] → 变形为 [B, C, 1, 1]
          out = avg_out + max_out
          out = self.sigmoid(out).view(x.size(0), x.size(1), 1, 1)
          
          # 注意力权重 × 原特征图(逐通道相乘)
          return x * out

    第二步:实现空间注意力模块(SAM)

    class SpatialAttention(nn.Module):
    def init(self, kernel_size=3):
    """
    参数说明:
    - kernel_size: 卷积核大小(默认3,必须是奇数,不用改)
    """
    super(SpatialAttention, self).init()

    复制代码
          # 卷积层:把通道数从2(平均+最大池化)降为1
          self.conv = nn.Conv2d(2, 1, kernel_size, padding=kernel_size//2, bias=False)
          self.sigmoid = nn.Sigmoid()
    
      def forward(self, x):
          """
          前向传播:
          x: 通道注意力处理后的特征图,形状 [B, C, H, W]
          """
          # 在通道维度做平均池化:[B, C, H, W] → [B, 1, H, W]
          avg_out = torch.mean(x, dim=1, keepdim=True)
          # 在通道维度做最大池化:[B, C, H, W] → [B, 1, H, W]
          max_out, _ = torch.max(x, dim=1, keepdim=True)
          
          # 拼接两个池化结果:[B, 2, H, W]
          out = torch.cat([avg_out, max_out], dim=1)
          # 卷积降维 + sigmoid → [B, 1, H, W](空间注意力权重)
          out = self.sigmoid(self.conv(out))
          
          # 注意力权重 × 原特征图(逐空间位置相乘)
          return x * out

    第三步:组合通道+空间注意力,实现完整的CBAM

    class CBAM(nn.Module):
    def init(self, in_channels, reduction_ratio=16, kernel_size=3):
    super(CBAM, self).init()
    self.channel_att = ChannelAttention(in_channels, reduction_ratio) # 通道注意力
    self.spatial_att = SpatialAttention(kernel_size) # 空间注意力

    复制代码
      def forward(self, x):
          """
          完整CBAM前向传播:先通道注意力,再空间注意力
          x: 输入特征图 [B, C, H, W]
          return: 增强后的特征图 [B, C, H, W]
          """
          x = self.channel_att(x)  # 第一步:通道注意力
          x = self.spatial_att(x)  # 第二步:空间注意力
          return x

    --------------- 测试代码:小白可以直接运行看效果 ---------------

    if name == "main":
    # 模拟一个CNN的特征图:批量大小=2,通道数=64,高=32,宽=32
    # (这个形状是CNN中很常见的,比如ResNet18的第一层卷积输出)
    fake_feature = torch.randn(2, 64, 32, 32)

    复制代码
      # 创建CBAM模块:输入通道数=64(和特征图通道数一致)
      cbam = CBAM(in_channels=64)
      
      # 用CBAM处理特征图
      enhanced_feature = cbam(fake_feature)
      
      # 打印输入/输出形状(验证:形状不变,只是特征被增强)
      print(f"输入特征图形状: {fake_feature.shape}")
      print(f"输出特征图形状: {enhanced_feature.shape}")

@浙大疏锦行

相关推荐
deephub2 小时前
大规模向量检索优化:Binary Quantization 让 RAG 系统内存占用降低 32 倍
人工智能·大语言模型·向量检索·rag
人工智能培训2 小时前
深度学习—卷积神经网络(1)
人工智能·深度学习·神经网络·机器学习·cnn·知识图谱·dnn
ㄣ知冷煖★2 小时前
【Google系列】AI智能体技术白皮书
人工智能·agent
新加坡内哥谈技术2 小时前
阿尔茨海默症的成因与风险因素到模型与干预分析
人工智能
张张张三丰2 小时前
【文献】金融市场发展与企业风险管理:来自上海原油期货上市的证据
人工智能·# 相关知识
阿里云大数据AI技术2 小时前
真实案例复盘:从“三套烟囱”到 All in ES,这家企业如何砍掉 40%运维成本?
人工智能·elasticsearch·搜索引擎
电商API_180079052472 小时前
深度解析以图搜索商品API:技术原理、接口设计与实践优化
人工智能·计算机视觉·目标跟踪
audyxiao0012 小时前
前沿观点|智慧教育的“四个未来”是什么?
人工智能·智慧教育·未来课堂·未来学校
啊巴矲2 小时前
小白从零开始勇闯人工智能:机器学习初级篇(贝叶斯算法与SVM算法)
人工智能·机器学习·支持向量机