💡💡💡 本文目的:通过利用一个新颖的双注意力块实现了更好的去雾性能,同时大幅降低了模型复杂度。这个双注意力块串联了两个模块:通道-空间注意力和并行注意力。我们提出了一种新的并行注意力架构,通过并行连接三种不同的注意力机制(全局通道注意力、局部通道注意力和空间注意力),实现了更好的去雾效果。
💡💡💡如何使用:1)结合A2C2f、C3k2二次创新使用;
论文:[2502.12524] YOLOv12: Attention-Centric Real-Time Object Detectors
摘要:
长期以来,提升YOLO框架的网络架构至关重要,但相关改进主要聚焦于基于CNN的优化,尽管注意力机制已被证实具备更卓越的建模能力。这种现状源于注意力模型在速度上始终无法与CNN模型相媲美。本研究提出了一种以注意力机制为核心的YOLO框架——YOLOv12,在保持与先前CNN模型相当速度的同时,充分释放了注意力机制的性能优势。
YOLOv12在保持具有竞争力的推理速度下,其准确率超越了所有主流实时目标检测器。具体而言,YOLOv12-N在T4 GPU上以1.64ms的推理延迟实现了40.6%的mAP,相较先进的YOLOv10-N/YOLOv11-N分别提升2.1%/1.2%的mAP,同时保持相近速度。该优势在其他模型规模上同样显著。相较于改进DETR的端到端实时检测器,YOLOv12也展现出优越性:例如YOLOv12-S以42%的速度优势超越RT-DETR-R18/RT-DETRv2-R18,仅需36%的计算量和45%的参数量。更多对比详见图1。
结构图如下:
本文旨在解决这些挑战,并进一步构建了一个以注意力为中心的YOLO框架,即YOLOv12。我们引入了三项关键改进。首先,我们提出了一个简单高效的区域注意力模块(A²),它以一种非常简单的方式在保持较大感受野的同时减少了注意力的计算复杂度,从而提高了速度。其次,我们引入了残差高效层聚合网络(R-ELAN),以应对注意力机制(尤其是大规模模型)引入的优化挑战。R-ELAN在原始ELAN的基础上引入了两项改进:(i)基于块的残差设计与缩放技术;(ii)重新设计的特征聚合方法。第三,我们在传统注意力机制的基础上进行了一些架构改进,以适应YOLO系统。我们升级了传统的注意力中心架构,包括:引入FlashAttention以解决注意力的内存访问问题,移除位置编码等设计以使模型更快速、更简洁,将MLP比率从4调整为1.2以平衡注意力机制和前馈网络之间的计算量,从而获得更好的性能,减少堆叠块的深度以促进优化,以及尽可能多地利用卷积操作来发挥其计算效率。
总之,YOLOv12的贡献可以概括为以下两点:1)它建立了一个以注意力为中心的、简单而高效的YOLO框架,通过方法创新和架构改进,打破了CNN模型在YOLO系列中的主导地位。2)YOLOv12在不依赖预训练等额外技术的情况下,实现了快速推理速度和更高的检测精度的最新成果,展现了其潜力。
YOLOv12设计了区域注意力模块(A2),将特征图划分为简单的垂直或水平区域,减少了注意力机制的计算复杂度,同时保持了较大的感受野。
核心源码如下:
代码位置ultralytics/nn/modules/block.py
A2C2f模块全称为“Area-Attention Enhanced Cross-Feature module”,是YOLOv12中提出的一种改进型特征提取模块,结合了区域注意力(Area-Attention)和残差连接,主要用于提升特征提取的效率和精度
A2C2f模块由以下关键部分组成:
代码位置ultralytics/nn/modules/block.py
论文:https://ieeexplore.ieee.org/stamp/stamp.jsp?tp=&arnumber=10679105
摘要:在遥感图像中去除雾霾对于天气预报、监测、矿产勘探和灾害管理等各个领域的实际应用至关重要。之前的深度学习模型利用大卷积核和注意力机制来高效去雾。然而,这些方法存在一些缺点,比如图像细节丢失和性能低下。本文将介绍一种新的双注意力网络,称为DA-Net,用于去雾遥感图像。该网络通过利用一个新颖的双注意力块实现了更好的去雾性能,同时大幅降低了模型复杂度。这个双注意力块串联了两个模块:通道-空间注意力和并行注意力。我们提出了一种新的并行注意力架构,通过并行连接三种不同的注意力机制(全局通道注意力、局部通道注意力和空间注意力),实现了更好的去雾效果。此外,我们将展示,通过把通道-空间注意力与并行注意力模块串联起来,可以更准确地检测出雾霾成分信息,同时通过结合两个不同的通道和空间分支分别生成的通道和空间信息,成比例地减少了模型复杂度。我们的实验结果表明,无论是在合成数据还是真实图像数据集上,DA-Net在定量和定性评估方面都比其他去雾模型表现得更好。
在这部分中,我们将详细描述DA-Net用于遥感图像(RSI)去雾的架构。如图1所示,DA-Net包含五个阶段,每个阶段都有一个双注意力块(DAB)。与之前的结果相比,DA-Net通过DAB的新颖结构设计显著提高了整体去雾性能,这种设计通过利用两个注意力模块而不是一个注意力模块,高效地结合了通道和空间信息。下采样用于减小特征图的大小,同时增加通道数量以捕获上下文信息;而上采样则用于减少通道数量,同时增加特征图大小以找到详细信息。此外,选择性核特征融合(SKFF)被用来通过合并两种不同的特征图来提取有用的特征[67]。使用重建过程从观测图像中获得去雾后的图像。在接下来的部分中,我们将更详细地解释DAB。
DAB由两个模块串联而成:通道-空间注意力模块(CSAM)和并行注意力模块(PAM),如图2所示。从理论上讲,DAB的结构设计可以减少模型的复杂度。现有的基于深度学习的模型通常需要大量的参数来准确捕捉雾霾成分,从而增加了模型的复杂性。相比之下,DAB中的CSAM和PAM基于注意力机制,可以在保持较少参数的情况下高效检测雾霾成分。此外,将CSAM与PAM串联起来可以互补,增强DAB的有效性。因此,DAB通过利用一种结构设计——即两个模块CSAM和PAM串联连接,能够更精确地检测雾霾成分,同时按比例减少模型的复杂度。
核心代码:
######################################## DA_Net IEEE Access 2024 by AI Little monster start ########################################
import torch
import torch.nn as nn
import torch.nn.functional as F
from torch.nn.init import _calculate_fan_in_and_fan_out
from timm.models.layers import trunc_normal_
import math
# https://blog.csdn.net/m0_63774211?type=lately
from ultralytics.nn.modules.conv import Conv, autopad
from ultralytics.nn.modules.block import Bottleneck, C2f,C3k,ABlock,C3k2,A2C2f
# This is the official code of DA-Net for haze removal in remote sensing images (RSI).
# DA-Net: Dual Attention Network for Haze Removal in Remote Sensing Image
# IEEE Access
# 09/12/2024
# Namwon Kim (namwon@korea.ac.kr)
class ChannelBranch(nn.Module):
# Channel Branch
def __init__(self, in_channels, reduction_ratio=16):
super(ChannelBranch, self).__init__()
self.fc = nn.Sequential(
nn.Linear(in_channels, in_channels // reduction_ratio),
nn.GELU(),
nn.Linear(in_channels // reduction_ratio, in_channels)
)
self.avg_pool = nn.AdaptiveAvgPool2d((1, 1))
def forward(self, x):
avg_pool = self.avg_pool(x).view(x.size(0), -1)
channel_att_raw = self.fc(avg_pool)
channel_att = torch.sigmoid(channel_att_raw).unsqueeze(-1).unsqueeze(-1)
return x * channel_att
class SpatialBranch(nn.Module):
# Spatial Branch
def __init__(self, in_channels):
super(SpatialBranch, self).__init__()
self.spatial = nn.Sequential(
nn.Conv2d(in_channels, 1, kernel_size=7, padding=3, padding_mode='reflect'),
nn.Sigmoid()
)
def forward(self, x):
scale = self.spatial(x)
return x * scale
# Channel Spatial Attention Module
class ChannelSpatialAttentionModule(nn.Module):
def __init__(self, in_channels):
super(ChannelSpatialAttentionModule, self).__init__()
self.channel_attention = ChannelBranch(in_channels)
self.spatial_attention = SpatialBranch(in_channels)
def forward(self, x):
out = self.channel_attention(x) + self.spatial_attention(x)
return out
class LocalChannelAttention(nn.Module):
def __init__(self, dim):
super(LocalChannelAttention, self).__init__()
self.conv = nn.Conv1d(1, 1, kernel_size=3, padding=1, padding_mode='reflect')
self.GAP = nn.AdaptiveAvgPool2d(1)
self.local = nn.Sequential(
nn.Conv2d(dim, dim, kernel_size=3, padding=1, groups=dim, padding_mode='reflect'),
nn.Sigmoid()
)
def forward(self, x):
N, C, H, W = x.shape
att = self.GAP(x).reshape(N, 1, C)
att = self.conv(att).sigmoid()
att = att.reshape(N, C, 1, 1)
out = ((x * att) + x) + (self.local(x) * x)
return out
class Mlp(nn.Module):
def __init__(self, network_depth, in_features, hidden_features=None, out_features=None):
super().__init__()
out_features = out_features or in_features
hidden_features = hidden_features or in_features
self.network_depth = network_depth
self.mlp = nn.Sequential(
nn.Conv2d(in_features, hidden_features, 1),
nn.Mish(True),
nn.Conv2d(hidden_features, out_features, 1)
)
self.apply(self._init_weights)
def _init_weights(self, m):
if isinstance(m, nn.Conv2d):
gain = (8 * self.network_depth) ** (-1 / 4)
fan_in, fan_out = _calculate_fan_in_and_fan_out(m.weight)
std = gain * math.sqrt(2.0 / float(fan_in + fan_out))
trunc_normal_(m.weight, std=std)
if m.bias is not None:
nn.init.constant_(m.bias, 0)
def forward(self, x):
return self.mlp(x)
class DualAttentionBlock(nn.Module):
def __init__(self, dim, network_depth=1):
super().__init__()
self.norm1 = nn.BatchNorm2d(dim)
self.norm2 = nn.BatchNorm2d(dim)
self.dim = dim
# shallow feature extraction layer
self.conv1 = nn.Conv2d(dim, dim, kernel_size=1) # main
self.conv2 = nn.Conv2d(dim, dim, kernel_size=5, padding=2, groups=dim, padding_mode='reflect') # main
self.attn = ChannelSpatialAttentionModule(dim)
# Local Channel Attention
self.gp = LocalChannelAttention(dim)
# Global Channel Attention
self.cam = GlobalChannelAttention(dim)
# Spatial Attention
self.pam = SpatialAttention(dim)
self.mlp = Mlp(network_depth, dim, hidden_features=int(dim * 4.), out_features=dim)
self.mlp2 = Mlp(network_depth, dim * 3, hidden_features=int(dim * 4.), out_features=dim)
def forward(self, x):
# Channel Spatial Attention Module
identity = x
x = self.norm1(x)
x = self.attn(x)
x = self.mlp(x)
x = identity + x
# Parallel Attention Module
identity = x
x = self.norm2(x)
x = self.conv1(x)
x = self.conv2(x)
x = torch.cat([self.gp(x), self.cam(x), self.pam(x)], dim=1)
x = self.mlp2(x)
x = identity + x
return x
# YOLOv12 🚀, AGPL-3.0 license
# YOLOv12 object detection model with P3-P5 outputs. For Usage examples see https://docs.ultralytics.com/tasks/detect
# Parameters
nc: 80 # number of classes
scales: # model compound scaling constants, i.e. 'model=yolov12n.yaml' will call yolov12.yaml with scale 'n'
# [depth, width, max_channels]
n: [0.50, 0.25, 1024] # summary: 465 layers, 2,603,056 parameters, 2,603,040 gradients, 6.7 GFLOPs
s: [0.50, 0.50, 1024] # summary: 465 layers, 9,285,632 parameters, 9,285,616 gradients, 21.7 GFLOPs
m: [0.50, 1.00, 512] # summary: 501 layers, 20,201,216 parameters, 20,201,200 gradients, 68.1 GFLOPs
l: [1.00, 1.00, 512] # summary: 831 layers, 26,454,880 parameters, 26,454,864 gradients, 89.7 GFLOPs
x: [1.00, 1.50, 512] # summary: 831 layers, 59,216,928 parameters, 59,216,912 gradients, 200.3 GFLOPs
# YOLO12n backbone
backbone:
# [from, repeats, module, args]
- [-1, 1, Conv, [64, 3, 2]] # 0-P1/2
- [-1, 1, Conv, [128, 3, 2]] # 1-P2/4
- [-1, 2, C3k2_DAB, [256, False, 0.25]]
- [-1, 1, Conv, [256, 3, 2]] # 3-P3/8
- [-1, 2, C3k2_DAB, [512, False, 0.25]]
- [-1, 1, Conv, [512, 3, 2]] # 5-P4/16
- [-1, 4, A2C2f_DAB, [512, True, 4]]
- [-1, 1, Conv, [1024, 3, 2]] # 7-P5/32
- [-1, 4, A2C2f_DAB, [1024, True, 1]] # 8
# YOLO12n head
head:
- [-1, 1, nn.Upsample, [None, 2, "nearest"]]
- [[-1, 6], 1, Concat, [1]] # cat backbone P4
- [-1, 2, A2C2f_DAB, [512, False, -1]] # 11
- [-1, 1, nn.Upsample, [None, 2, "nearest"]]
- [[-1, 4], 1, Concat, [1]] # cat backbone P3
- [-1, 2, A2C2f_DAB, [256, False, -1]] # 14
- [-1, 1, Conv, [256, 3, 2]]
- [[-1, 11], 1, Concat, [1]] # cat head P4
- [-1, 2, A2C2f_DAB, [512, False, -1]] # 17
- [-1, 1, Conv, [512, 3, 2]]
- [[-1, 8], 1, Concat, [1]] # cat head P5
- [-1, 2, C3k2_DAB, [1024, True]] # 20 (P5/32-large)
- [[14, 17, 20], 1, Detect, [nc]] # Detect(P3, P4, P5)
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。