长期以来,优化YOLO
框架的网络架构一直是提升目标检测性能的关键,而以往的研究大多聚焦于基于卷积神经网络(CNN
)的改进。这是因为基于注意力机制的模型通常难以达到与基于CNN
的模型相媲美的速度。然而,YOLOv12
却打破了这一桎梏,该框架不仅充分利用了注意力机制在性能上的优势,还在推理速度上与之前基于CNN
的YOLO
框架相当,从而在实时性与精度之间实现了更好的平衡。
其中,其提出了A2C2f模块便是基于Transformer
注意力构建的,其结构如下:
A2C2f(
(cv1): Conv(
(conv): Conv2d(256, 128, kernel_size=(1, 1), stride=(1, 1), bias=False)
(bn): BatchNorm2d(128, eps=0.001, momentum=0.03, affine=True, track_running_stats=True)
(act): SiLU(inplace=True)
)
(cv2): Conv(
(conv): Conv2d(256, 256, kernel_size=(1, 1), stride=(1, 1), bias=False)
(bn): BatchNorm2d(256, eps=0.001, momentum=0.03, affine=True, track_running_stats=True)
(act): SiLU(inplace=True)
)
(m): ModuleList(
(0): Sequential(
(0): ABlock(
(attn): AAttn(
(qkv): Conv(
(conv): Conv2d(128, 384, kernel_size=(1, 1), stride=(1, 1), bias=False)
(bn): BatchNorm2d(384, eps=0.001, momentum=0.03, affine=True, track_running_stats=True)
(act): Identity()
)
(proj): Conv(
(conv): Conv2d(128, 128, kernel_size=(1, 1), stride=(1, 1), bias=False)
(bn): BatchNorm2d(128, eps=0.001, momentum=0.03, affine=True, track_running_stats=True)
(act): Identity()
)
(pe): Conv(
(conv): Conv2d(128, 128, kernel_size=(7, 7), stride=(1, 1), padding=(3, 3), groups=128, bias=False)
(bn): BatchNorm2d(128, eps=0.001, momentum=0.03, affine=True, track_running_stats=True)
(act): Identity()
)
)
(mlp): Sequential(
(0): Conv(
(conv): Conv2d(128, 256, kernel_size=(1, 1), stride=(1, 1), bias=False)
(bn): BatchNorm2d(256, eps=0.001, momentum=0.03, affine=True, track_running_stats=True)
(act): SiLU(inplace=True)
)
(1): Conv(
(conv): Conv2d(256, 128, kernel_size=(1, 1), stride=(1, 1), bias=False)
(bn): BatchNorm2d(128, eps=0.001, momentum=0.03, affine=True, track_running_stats=True)
(act): Identity()
)
)
)
(1): ABlock(
(attn): AAttn(
(qkv): Conv(
(conv): Conv2d(128, 384, kernel_size=(1, 1), stride=(1, 1), bias=False)
(bn): BatchNorm2d(384, eps=0.001, momentum=0.03, affine=True, track_running_stats=True)
(act): Identity()
)
(proj): Conv(
(conv): Conv2d(128, 128, kernel_size=(1, 1), stride=(1, 1), bias=False)
(bn): BatchNorm2d(128, eps=0.001, momentum=0.03, affine=True, track_running_stats=True)
(act): Identity()
)
(pe): Conv(
(conv): Conv2d(128, 128, kernel_size=(7, 7), stride=(1, 1), padding=(3, 3), groups=128, bias=False)
(bn): BatchNorm2d(128, eps=0.001, momentum=0.03, affine=True, track_running_stats=True)
(act): Identity()
)
)
(mlp): Sequential(
(0): Conv(
(conv): Conv2d(128, 256, kernel_size=(1, 1), stride=(1, 1), bias=False)
(bn): BatchNorm2d(256, eps=0.001, momentum=0.03, affine=True, track_running_stats=True)
(act): SiLU(inplace=True)
)
(1): Conv(
(conv): Conv2d(256, 128, kernel_size=(1, 1), stride=(1, 1), bias=False)
(bn): BatchNorm2d(128, eps=0.001, momentum=0.03, affine=True, track_running_stats=True)
(act): Identity()
)
)
)
)
)
)
A2C2f 结构功能详解
-
cv1 和 cv2:
这两个部分是卷积层(Conv),分别将输入通道数从 256 转换到 128 (cv1) 和保持在 256 (cv2)。
每个 Conv 都由一个 Conv2d 层、一个 BatchNorm2d 层以及一个激活函数(SiLU 或 Identity)组成。 -
m (ModuleList):
包含了一个或多个 Sequential 模块,每个模块中有一个或多个 ABlock。
在你的例子中有两个 ABlock 实例。 -
ABlock:
每个 ABlock 包含一个注意力机制模块 AAttn 和一个多层感知机(MLP)模块。
AAttn (Attention Block):
qkv: 一个卷积层,用于生成查询(query)、键(key)和值(value)向量。输出通道数为输入的三倍(在这个例子中,输入是 128,输出是 384)。
proj: 另一个卷积层,用于将注意力结果投影回原始维度。
pe: 位置编码(Position Encoding),通过一个深度可分离卷积(groups=128)实现,其核大小为 7x7,并带有适当的填充以确保输入和输出尺寸相同。 -
MLP (多层感知机):
MLP 由两层卷积层构成,其中第一层扩展了特征维度(例如从 128 到 256),而第二层则将其压缩回到原来的维度(如从 256 回到 128)。每层之间使用 SiLU 作为激活函数,除了最后一层使用 Identity(即没有激活函数)。
A2C2f
├── cv1
│ ├── Conv2d(256, 128)
│ ├── BatchNorm2d(128)
│ └── SiLU()
├── cv2
│ ├── Conv2d(256, 256)
│ ├── BatchNorm2d(256)
│ └── SiLU()
└── m (ModuleList)
└── Sequential
├── ABlock
│ ├── AAttn
│ │ ├── qkv(Conv2d(128, 384))
│ │ ├── proj(Conv2d(128, 128))
│ │ └── pe(Conv2d(128, 128))
│ └── MLP
│ ├── Conv2d(128, 256)
│ └── Conv2d(256, 128)
└── ABlock
├── AAttn
│ ├── qkv(Conv2d(128, 384))
│ ├── proj(Conv2d(128, 128))
│ └── pe(Conv2d(128, 128))
└── MLP
├── Conv2d(128, 256)
└── Conv2d(256, 128)