Ultralytics:解读CBAM模块

前言
- 由于本人水平有限,难免出现错漏,敬请批评改正。
- 更多精彩内容,可点击进入Python日常小操作专栏、OpenCV-Python小应用专栏、YOLO系列专栏、自然语言处理专栏、人工智能混合编程实践专栏或我的个人主页查看
- YOLOs-CPP:一个免费开源的YOLO全系列C++推理库(以YOLO26为例)
- PaddleOCR:Win10上安装使用PPOCRLabel标注工具
- 目标检测:使用自己的数据集微调DEIMv2进行物体检测
- 图像分割:PyTorch从零开始实现SegFormer语义分割
- 图像超分:使用自己的数据集微调Real-ESRGAN-x4plus进行超分重建
- 图像生成:PyTorch从零开始实现一个简单的扩散模型
- Stable Diffusion:使用自己的数据集微调 Stable Diffusion 3.5 LoRA 文生图模型
- 图像超分:使用自己的数据集微调Real-ESRGAN-x2plus进行超分重建
- Anomalib:使用Anomalib 2.1.0训练自己的数据集进行异常检测
- Anomalib:在Linux服务器上安装使用Anomalib 2.1.0
- 人工智能混合编程实践:C++调用封装好的DLL进行异常检测推理
- 人工智能混合编程实践:C++调用封装好的DLL进行FP16图像超分重建(v3.0)
- 隔离系统Python:源码编译3.11.8到自定义目录(含PGO性能优化)
- 在线机的Python环境迁移到离线机上
- Nuitka 将 Python 脚本封装为 .pyd 或 .so 文件
- Ultralytics:使用 YOLO11 进行速度估计
- Ultralytics:使用 YOLO11 进行物体追踪
- Ultralytics:使用 YOLO11 进行物体计数
- Ultralytics:使用 YOLO11 进行目标打码
- 人工智能混合编程实践:C++调用Python ONNX进行YOLOv8推理
- 人工智能混合编程实践:C++调用封装好的DLL进行YOLOv8实例分割
- 人工智能混合编程实践:C++调用Python ONNX进行图像超分重建
- 人工智能混合编程实践:C++调用Python AgentOCR进行文本识别
- 通过计算实例简单地理解PatchCore异常检测
- Python将YOLO格式实例分割数据集转换为COCO格式实例分割数据集
- YOLOv8 Ultralytics:使用Ultralytics框架训练RT-DETR实时目标检测模型
- 基于DETR的人脸伪装检测
- YOLOv7训练自己的数据集(口罩检测)
- YOLOv8训练自己的数据集(足球检测)
- YOLOv5:TensorRT加速YOLOv5模型推理
- YOLOv5:IoU、GIoU、DIoU、CIoU、EIoU
- 玩转Jetson Nano(五):TensorRT加速YOLOv5目标检测
- YOLOv5:添加SE、CBAM、CoordAtt、ECA注意力机制
- YOLOv5:yolov5s.yaml配置文件解读、增加小目标检测层
- Python将COCO格式实例分割数据集转换为YOLO格式实例分割数据集
- YOLOv5:使用7.0版本训练自己的实例分割模型(车辆、行人、路标、车道线等实例分割)
- 使用Kaggle GPU资源免费体验Stable Diffusion开源项目
- Stable Diffusion:在服务器上部署使用Stable Diffusion WebUI进行AI绘图(v2.0)
- Stable Diffusion:使用自己的数据集微调训练LoRA模型(v2.0)
相关介绍
Ultralytics 简介
Ultralytics 基于多年的计算机视觉和人工智能基础研究,创建了最先进的 (SOTA) YOLO 模型。我们的模型不断更新性能和灵活性,快速、准确且易于使用。他们擅长对象检测、跟踪、实例分割、语义分割、图像分类和姿势估计任务。
前提条件
- 熟悉Python、Pytorch
实验环境
bash
Package Version
------------------------ ------------
Python 3.11.8
absl-py 2.4.0
accelerate 1.13.0
annotated-doc 0.0.4
anyio 4.13.0
calflops 0.3.2
certifi 2026.4.22
charset-normalizer 3.4.7
click 8.3.3
colorama 0.4.6
contourpy 1.3.3
cycler 0.12.1
filelock 3.29.0
flatbuffers 25.12.19
fonttools 4.62.1
fsspec 2026.4.0
grpcio 1.80.0
h11 0.16.0
hf-xet 1.5.0
httpcore 1.0.9
httpx 0.28.1
huggingface_hub 1.14.0
idna 3.15
Jinja2 3.1.6
kiwisolver 1.5.0
Markdown 3.10.2
markdown-it-py 4.2.0
MarkupSafe 3.0.3
matplotlib 3.10.9
mdurl 0.1.2
ml_dtypes 0.5.0
mpmath 1.3.0
networkx 3.6.1
numpy 1.26.4
nvidia-cublas-cu12 12.8.3.14
nvidia-cuda-cupti-cu12 12.8.57
nvidia-cuda-nvrtc-cu12 12.8.61
nvidia-cuda-runtime-cu12 12.8.57
nvidia-cudnn-cu12 9.7.1.26
nvidia-cufft-cu12 11.3.3.41
nvidia-cufile-cu12 1.13.0.11
nvidia-curand-cu12 10.3.9.55
nvidia-cusolver-cu12 11.7.2.55
nvidia-cusparse-cu12 12.5.7.53
nvidia-cusparselt-cu12 0.6.3
nvidia-nccl-cu12 2.26.2
nvidia-nvjitlink-cu12 12.8.61
nvidia-nvtx-cu12 12.8.55
onnx 1.19.0
onnxruntime-gpu 1.26.0
onnxslim 0.1.94
opencv-python 4.6.0.66
packaging 26.2
pillow 12.2.0
pip 24.0
polars 1.40.1
polars-runtime-32 1.40.1
protobuf 7.34.1
psutil 7.2.2
pycocotools 2.0.11
Pygments 2.20.0
pyparsing 3.3.2
python-dateutil 2.9.0.post0
PyYAML 6.0.3
regex 2026.5.9
requests 2.34.1
rich 15.0.0
safetensors 0.7.0
scipy 1.16.0
setuptools 65.5.0
shellingham 1.5.4
six 1.17.0
sympy 1.14.0
tabulate 0.10.0
tensorboard 2.20.0
tensorboard-data-server 0.7.2
tokenizers 0.22.2
torch 2.7.1+cu128
torchaudio 2.7.1+cu128
torchvision 0.22.1+cu128
tqdm 4.67.3
transformers 5.8.1
triton 3.3.1
typer 0.25.1
typing_extensions 4.15.0
ultralytics 8.4.58
ultralytics-thop 2.0.19
urllib3 2.7.0
Werkzeug 3.1.8
CBAM(卷积块注意力模块)
CBAM(Convolutional Block Attention Module)是一种轻量级的注意力模块,它将 通道注意力 (Channel Attention)和 空间注意力 (Spatial Attention)以 串行 的方式组合在一起,对特征图进行自适应细化。该模块在 ECCV 2018 中被提出,现已成为许多视觉任务的标配组件。
代码实现
python
import cv2
import math
import torch
import numpy as np
import matplotlib.pyplot as plt
from torch import nn
class ChannelAttention(nn.Module):
"""Channel-attention module for feature recalibration.
Applies attention weights to channels based on global average pooling.
Attributes:
pool (nn.AdaptiveAvgPool2d): Global average pooling.
fc (nn.Conv2d): Fully connected layer implemented as 1x1 convolution.
act (nn.Sigmoid): Sigmoid activation for attention weights.
References:
https://github.com/open-mmlab/mmdetection/tree/v3.0.0rc1/configs/rtmdet
"""
def __init__(self, channels: int) -> None:
"""Initialize Channel-attention module.
Args:
channels (int): Number of input channels.
"""
super().__init__()
self.pool = nn.AdaptiveAvgPool2d(1)
self.fc = nn.Conv2d(channels, channels, 1, 1, 0, bias=True)
self.act = nn.Sigmoid()
def forward(self, x: torch.Tensor) -> torch.Tensor:
"""Apply channel attention to input tensor.
Args:
x (torch.Tensor): Input tensor.
Returns:
(torch.Tensor): Channel-attended output tensor.
"""
return x * self.act(self.fc(self.pool(x)))
class SpatialAttention(nn.Module):
"""Spatial-attention module for feature recalibration.
Applies attention weights to spatial dimensions based on channel statistics.
Attributes:
cv1 (nn.Conv2d): Convolution layer for spatial attention.
act (nn.Sigmoid): Sigmoid activation for attention weights.
"""
def __init__(self, kernel_size=7):
"""Initialize Spatial-attention module.
Args:
kernel_size (int): Size of the convolutional kernel (3 or 7).
"""
super().__init__()
assert kernel_size in {3, 7}, "kernel size must be 3 or 7"
padding = 3 if kernel_size == 7 else 1
self.cv1 = nn.Conv2d(2, 1, kernel_size, padding=padding, bias=False)
self.act = nn.Sigmoid()
def forward(self, x):
"""Apply spatial attention to input tensor.
Args:
x (torch.Tensor): Input tensor.
Returns:
(torch.Tensor): Spatial-attended output tensor.
"""
return x * self.act(self.cv1(torch.cat([torch.mean(x, 1, keepdim=True), torch.max(x, 1, keepdim=True)[0]], 1)))
class CBAM(nn.Module):
"""Convolutional Block Attention Module.
Combines channel and spatial attention mechanisms for comprehensive feature refinement.
Attributes:
channel_attention (ChannelAttention): Channel attention module.
spatial_attention (SpatialAttention): Spatial attention module.
"""
def __init__(self, c1, kernel_size=7):
"""Initialize CBAM with given parameters.
Args:
c1 (int): Number of input channels.
kernel_size (int): Size of the convolutional kernel for spatial attention.
"""
super().__init__()
self.channel_attention = ChannelAttention(c1)
self.spatial_attention = SpatialAttention(kernel_size)
def forward(self, x):
"""Apply channel and spatial attention sequentially to input tensor.
Args:
x (torch.Tensor): Input tensor.
Returns:
(torch.Tensor): Attended output tensor.
"""
return self.spatial_attention(self.channel_attention(x))
功能
- 串行注意力机制 :先通过 通道注意力 对输入特征图的各个通道进行重标定,再通过 空间注意力 对空间位置进行重标定。
- 全面的特征精炼:通道注意力关注"什么(what)"是重要的,空间注意力关注"哪里(where)"是重要的,两者互补,使模型更聚焦于关键信息。
- 即插即用:可嵌入任意 CNN 网络中,提升性能而仅增加少量计算开销。
初始化参数
| 参数 | 类型 | 说明 |
|---|---|---|
c1 |
int | 输入特征图的通道数(即 ChannelAttention 的 channels 参数) |
kernel_size |
int | 空间注意力卷积核大小(默认 7,可选 3 或 7) |
该模块不改变输入特征图的形状(通道数和空间尺寸均不变)。
前向方法
forward(x):x→ 通道注意力 → 空间注意力 → 输出,形状保持不变。
使用示例

python
if __name__ == '__main__':
torch.manual_seed(42) # 固定种子,确保每次运行初始化相同
# 1. 读取图像
img_path = "cat_640x640.png"
img_bgr = cv2.imread(img_path)
if img_bgr is None:
raise FileNotFoundError(f"图片 {img_path} 不存在!")
# 2. 转为张量 (1,3,640,640)
img_rgb = cv2.cvtColor(img_bgr, cv2.COLOR_BGR2RGB)
img_tensor = torch.from_numpy(img_rgb).float().permute(2, 0, 1).unsqueeze(0)
# 3. 创建 CBAM 模块(输入通道 3,空间注意力核大小 7)
cbam = CBAM(c1=3, kernel_size=7)
# 4. 前向传播,并分别提取通道注意力和空间注意力权重(便于可视化)
with torch.no_grad():
# 通道注意力输出(中间特征)
ca_out = cbam.channel_attention(img_tensor) # 形状 [1,3,640,640]
# 通道注意力权重(即 sigmoid(fc(pool(x))))
ca_weight = cbam.channel_attention.act(
cbam.channel_attention.fc(
cbam.channel_attention.pool(img_tensor)
)
) # [1,3,1,1]
# 最终 CBAM 输出
out = cbam(img_tensor) # [1,3,640,640]
# 空间注意力权重(从 CBAM 的空间注意力模块提取)
# 输入是 ca_out,计算 mean + max,再卷积+Sigmoid
pooled = torch.cat([
torch.mean(ca_out, 1, keepdim=True),
torch.max(ca_out, 1, keepdim=True)[0]
], 1)
sa_weight = cbam.spatial_attention.act(
cbam.spatial_attention.cv1(pooled)
) # [1,1,640,640]
print("CBAM 输出形状:", out.shape) # [1,3,640,640]
print("通道注意力权重形状:", ca_weight.shape) # [1,3,1,1]
print("空间注意力权重形状:", sa_weight.shape) # [1,1,640,640]
# 5. 可视化:原图、通道注意力权重(热力图)、空间注意力图、最终输出(取第一通道)
# 归一化通道权重(虽为标量,但扩展成全图用于显示)
ca_weights_np = ca_weight.squeeze().cpu().numpy() # (3,)
# 选择权重最大的通道显示(或固定显示第0通道)
max_ca_ch = np.argmax(ca_weights_np)
ca_heatmap = np.full((640, 640), ca_weights_np[max_ca_ch], dtype=np.float32)
# 空间注意力图归一化
sa_map = sa_weight[0, 0, :, :].cpu().numpy()
sa_map = (sa_map - sa_map.min()) / (sa_map.max() - sa_map.min() + 1e-8)
# 最终输出的第一个通道
final_feat = out[0, 0, :, :].cpu().numpy()
final_feat = (final_feat - final_feat.min()) / (final_feat.max() - final_feat.min() + 1e-8)
plt.figure(figsize=(16, 5), constrained_layout=True)
plt.subplot(1, 4, 1)
plt.imshow(cv2.cvtColor(img_bgr, cv2.COLOR_BGR2RGB))
plt.title("Original")
plt.axis("off")
plt.subplot(1, 4, 2)
plt.imshow(ca_heatmap, cmap='hot', vmin=0, vmax=1)
plt.title(f"Channel Attn (Ch{max_ca_ch}, {ca_weights_np[max_ca_ch]:.3f})")
plt.axis("off")
plt.subplot(1, 4, 3)
plt.imshow(sa_map, cmap='hot')
plt.title("Spatial Attention")
plt.axis("off")
plt.subplot(1, 4, 4)
plt.imshow(final_feat, cmap='gray')
plt.title("CBAM Output (Ch0)")
plt.axis("off")
plt.savefig("cbam_output.png", dpi=150)
# plt.show()
print("可视化已保存为 cbam_output.png")

输出示例:
CBAM 输出形状: torch.Size([1, 3, 640, 640])
通道注意力权重形状: torch.Size([1, 3, 1, 1])
空间注意力权重形状: torch.Size([1, 1, 640, 640])
可视化已保存为 cbam_output.png
流程示意图

代码解读
__init__ 方法
- 先创建
ChannelAttention实例,输入通道数为c1。 - 再创建
SpatialAttention实例,指定kernel_size(默认 7)。 - 两个子模块将串联使用。
forward 方法
- 输入
x先通过self.channel_attention,得到通道细化后的特征。 - 然后通过
self.spatial_attention,得到最终输出。 - 顺序为 通道 → 空间,与 CBAM 原论文一致(论文实验表明该顺序优于空间→通道)。
注意事项
- 顺序固定:CBAM 采用"通道先、空间后"的顺序,若需交换顺序可自行修改,但原论文推荐此方式。
- 中间特征:通道注意力输出会作为空间注意力的输入,因此空间注意力的统计量(均值和最大值)是在通道增强后的特征上计算的,这能更好反映通道注意力筛选后的信息。
- 参数共享 :
ChannelAttention和SpatialAttention内部无 BN,因此不同批次间可共享统计量,不影响训练。 - 计算开销:相比单独使用通道或空间注意力,CBAM 增加了约一倍的注意力计算量,但仍远小于主干网络本身,适合多数模型。
- 适用场景:可用于分类、检测、分割等任务,通常放置在残差块之后或特征金字塔的每个层级上。
优缺点
优点
- 性能提升显著:结合了通道和空间注意力,可同时关注"什么"和"哪里",通常比单独使用一种注意力效果更好。
- 轻量化:参数量小,仅增加了几个卷积层,计算开销可控。
- 即插即用:可无缝嵌入现有 CNN,无需改动网络结构。
- 可解释性强:两个注意力图均可可视化,便于分析模型的关注区域。
缺点
- 计算量略高于单一注意力:需串行执行两个注意力模块,推理速度稍有下降。
- 空间注意力核大小限制:仅支持 3 或 7,可能无法适应所有尺度变化。
- 顺序固定:虽然原论文认为通道→空间最优,但在某些任务中可能需要调整,灵活性不足。
- 在极轻量级网络中可能冗余:如果网络本身很浅或通道数很少,额外增加注意力可能收益有限,反而增加开销。
在 YOLO 中的应用
在 YOLOv8 或 RT-DETR 等检测模型中,CBAM 可放置在 C2f 模块的输出后,或 特征金字塔(FPN) 的每个层上,用于增强特征表达。通常,在深层特征图使用 kernel_size=7 以获取更大感受野,浅层使用 kernel_size=3 关注细节。
通过 CBAM,您可以轻松提升模型性能,同时保持较低的计算成本。建议在实际训练中尝试将 CBAM 插入不同位置,通过消融实验确定最佳部署方案。
参考文献
1 https://docs.ultralytics.com/
2 https://github.com/ultralytics/ultralytics.git
- 由于本人水平有限,难免出现错漏,敬请批评改正。
- 更多精彩内容,可点击进入Python日常小操作专栏、OpenCV-Python小应用专栏、YOLO系列专栏、自然语言处理专栏、人工智能混合编程实践专栏或我的个人主页查看
- YOLOs-CPP:一个免费开源的YOLO全系列C++推理库(以YOLO26为例)
- PaddleOCR:Win10上安装使用PPOCRLabel标注工具
- 目标检测:使用自己的数据集微调DEIMv2进行物体检测
- 图像分割:PyTorch从零开始实现SegFormer语义分割
- 图像超分:使用自己的数据集微调Real-ESRGAN-x4plus进行超分重建
- 图像生成:PyTorch从零开始实现一个简单的扩散模型
- Stable Diffusion:使用自己的数据集微调 Stable Diffusion 3.5 LoRA 文生图模型
- 图像超分:使用自己的数据集微调Real-ESRGAN-x2plus进行超分重建
- Anomalib:使用Anomalib 2.1.0训练自己的数据集进行异常检测
- Anomalib:在Linux服务器上安装使用Anomalib 2.1.0
- 人工智能混合编程实践:C++调用封装好的DLL进行异常检测推理
- 人工智能混合编程实践:C++调用封装好的DLL进行FP16图像超分重建(v3.0)
- 隔离系统Python:源码编译3.11.8到自定义目录(含PGO性能优化)
- 在线机的Python环境迁移到离线机上
- Nuitka 将 Python 脚本封装为 .pyd 或 .so 文件
- Ultralytics:使用 YOLO11 进行速度估计
- Ultralytics:使用 YOLO11 进行物体追踪
- Ultralytics:使用 YOLO11 进行物体计数
- Ultralytics:使用 YOLO11 进行目标打码
- 人工智能混合编程实践:C++调用Python ONNX进行YOLOv8推理
- 人工智能混合编程实践:C++调用封装好的DLL进行YOLOv8实例分割
- 人工智能混合编程实践:C++调用Python ONNX进行图像超分重建
- 人工智能混合编程实践:C++调用Python AgentOCR进行文本识别
- 通过计算实例简单地理解PatchCore异常检测
- Python将YOLO格式实例分割数据集转换为COCO格式实例分割数据集
- YOLOv8 Ultralytics:使用Ultralytics框架训练RT-DETR实时目标检测模型
- 基于DETR的人脸伪装检测
- YOLOv7训练自己的数据集(口罩检测)
- YOLOv8训练自己的数据集(足球检测)
- YOLOv5:TensorRT加速YOLOv5模型推理
- YOLOv5:IoU、GIoU、DIoU、CIoU、EIoU
- 玩转Jetson Nano(五):TensorRT加速YOLOv5目标检测
- YOLOv5:添加SE、CBAM、CoordAtt、ECA注意力机制
- YOLOv5:yolov5s.yaml配置文件解读、增加小目标检测层
- Python将COCO格式实例分割数据集转换为YOLO格式实例分割数据集
- YOLOv5:使用7.0版本训练自己的实例分割模型(车辆、行人、路标、车道线等实例分割)
- 使用Kaggle GPU资源免费体验Stable Diffusion开源项目
- Stable Diffusion:在服务器上部署使用Stable Diffusion WebUI进行AI绘图(v2.0)
- Stable Diffusion:使用自己的数据集微调训练LoRA模型(v2.0)