【YOLOv12改进trick】超分辨率SAFM模块替换上采样模块,引入YOLOv12,实现模糊目标检测涨点,含创新点Python代码,方便发论文
🍋改进模块🍋:空间自适应特征调制(SAFM)
🍋解决问题🍋:SAFM模块将多尺度特征表示和动态调制机制,能够有效利用非局部特征交互。
🍋改进优势🍋:超分辨的SAFM模块对小目标和模糊目标涨点很明显
🍋适用场景🍋:小目标检测、模糊目标检测等
🍋思路来源🍋:ICCV2023《Spatially-Adaptive Feature Modulation for Efficient Image Super-Resolution》
目录
🔔🔔1.设计动机
🍉🍉2.空间自适应特征调制(SAFM)模块优势
👍1. 非局部特征交互能力
👍2. 动态空间调制
👍3. 多尺度特征表示
👍4. 高效的计算设计
👍5. 与局部特征的互补性
👍6. 灵活性和可扩展性
🏆🏆3.SAFM结构
🐸1. 输入特征的归一化
🐸2. 多尺度特征生成单元(MFGU)
🐸3. 特征聚合
🐸4. 动态调制
🐸5. 输出
👍👍4.将SAFM引入YOLOv12的python代码修改
🍂修改处一
🍂修改处二
🍂修改处三
🍂修改处四
👍👍5.成功训练后的网络结构截图
整理不易,欢迎一键三连!!!送你们一条美丽的--分割线--
🔔🔔1.设计动机
-
SAFM层通过独立计算学习多尺度特征表示,并将这些特征聚合用于动态空间调制。它利用多尺度特征生成单元(MFGU)提取不同尺度的特征,并通过1×1卷积进行聚合,从而生成注意力图,实现对输入特征的自适应调制。
-
该机制在不显著增加计算负担的情况下,引入了非局部特征交互能力,类似于Transformer中的多头自注意力(MHSA)机制,但更适合高效的超分辨率设计。
-
SAFM模块中使用了深度可分离卷积和自适应池化操作,减少参数量和优化计算流程,使其适合在资源受限的设备上运行。
🍉🍉2.空间自适应特征调制(SAFM)模块优势
👍1. 非局部特征交互能力
-
优势:SAFM通过多尺度特征表示和动态调制机制,能够捕捉输入特征的长距离依赖关系,类似于Transformer中的多头自注意力(MHSA)机制。这种非局部特征交互能力使得模型可以更好地利用全局信息来重建高分辨率图像。
-
效果:在图像超分辨率任务中,这种能力可以显著提升对图像细节和结构的恢复能力,尤其是在处理复杂纹理和边缘时。
👍2. 动态空间调制
-
优势:SAFM通过生成注意力图对输入特征进行动态调制,能够根据输入特征的重要性自适应地调整特征权重。这种动态调制机制使得模型能够灵活地处理不同区域的特征贡献,避免了传统卷积操作中静态权重的局限性。
-
效果:动态调制能够更好地突出重要特征,抑制冗余信息,从而提高重建图像的质量。
👍3. 多尺度特征表示
-
优势:SAFM通过多尺度特征生成单元(MFGU)提取不同尺度的特征,包括局部和全局特征。这种多尺度表示使得模型能够同时捕捉图像的细节和整体结构。
-
效果:多尺度特征的聚合能够提供更丰富的特征信息,提升模型对不同尺度细节的恢复能力。
👍4. 高效的计算设计
-
优势:尽管SAFM引入了类似Transformer的机制,但其设计注重计算效率。例如,它使用深度可分离卷积(Depth-wise Convolution)和自适应池化操作来减少计算量和参数量。
-
效果:SAFM在保持高效性的同时,实现了与Transformer类似的自适应特征处理能力,适合在资源受限的设备上运行。
👍5. 与局部特征的互补性
-
优势:SAFM模块主要处理非局部特征交互,但通过与卷积通道混合器(CCM)结合,能够补充局部上下文信息。这种设计使得模型能够同时利用全局和局部特征。
-
效果:全局和局部特征的结合能够更全面地恢复高分辨率图像的细节和结构。
👍6. 灵活性和可扩展性
-
优势:SAFM的设计基于模块化思想,可以灵活地与其他网络结构结合。例如,它可以与卷积网络、Transformer或其他轻量级模块集成,以进一步提升性能。
-
效果:这种灵活性使得SAFM能够适应不同的任务需求和网络架构。
🏆🏆3.SAFM结构
SAFM(Spatially-Adaptive Feature Modulation)模块是SAFMN网络的核心组件,其设计目标是通过动态调制输入特征,同时利用非局部特征交互和多尺度特征表示来提升图像超分辨率性能。以下是SAFM模块的详细网络结构和工作流程:
🐸1. 输入特征的归一化
-
输入:输入特征 X 首先经过 LayerNorm 层进行归一化处理。LayerNorm的作用是稳定训练过程,避免动态调制操作导致的梯度异常。
-
公式:
Xnorm=LayerNorm(X)
🐸2. 多尺度特征生成单元(MFGU)
-
功能:MFGU用于提取多尺度特征,捕捉不同范围的特征信息。
-
结构:
-
通道分割:将归一化后的输入特征 Xnorm 分割为多个组,每组分别处理不同尺度的特征。
[X0,X1,X2,X3]=Split(Xnorm) -
多尺度特征提取:
-
第一组 X0 通过一个 3×3深度可分离卷积(Depth-wise Convolution)处理局部特征。
-
其余三组 X1,X2,X3 分别通过 自适应最大池化(Adaptive Max Pooling)下采样到不同尺度,再通过3×3深度可分离卷积处理,最后上采样回原始分辨率。
其中,↓p/2i 表示下采样到 p/2i 分辨率,↑p 表示通过最近邻插值上采样回原始分辨率。
-
-
🐸3. 特征聚合
-
功能:将多尺度特征在通道维度上聚合,生成综合特征表示。
-
操作:
-
将所有尺度的特征 [X^0,X^1,X^2,X^3] 在通道维度上拼接。
-
使用 1×1卷积 进行通道压缩和特征融合。
-
🐸4. 动态调制
-
功能:通过生成的注意力图对输入特征进行动态调制,增强重要特征的权重。
-
操作:
-
使用 GELU激活函数 对聚合后的特征 X^ 进行归一化,生成注意力图。
-
将注意力图与原始输入特征 X 进行逐元素相乘,实现动态调制。
其中,⊙ 表示逐元素相乘。
-
🐸5. 输出
-
输出特征:经过动态调制后的特征 Xˉ 作为SAFM模块的输出,用于后续的特征处理。
👍👍4.将SAFM引入YOLOv12的python代码修改
🍂修改处一
在ultralytics/nn/modules/目录下添加SAFM.py,SAFM.py定义如下:
import torch
import torch.nn as nn
import torch.nn.functional as F
class SimpleSAFM(nn.Module):
def __init__(self, dim, ratio=4):
"""
初始化SimpleSAFM模块。
dim: 输入的特征图通道数。
ratio: 将通道数分为两部分的比例。
"""
super().__init__()
self.dim = dim
self.chunk_dim = dim // ratio # 将输入通道数划分为两部分
# 卷积层,用于特征映射的投影
self.proj = nn.Conv2d(dim, dim, 3, 1, 1, bias=False)
# 深度卷积,用于处理分割后的特征
self.dwconv = nn.Conv2d(self.chunk_dim, self.chunk_dim, 3, 1, 1, groups=self.chunk_dim, bias=False)
# 输出卷积层
self.out = nn.Conv2d(dim, dim, 1, 1, 0, bias=False)
# 激活函数
self.act = nn.GELU()
def forward(self, x):
"""
前向传播:进行特征提取与调制
x: 输入特征图,大小为 (batch_size, dim, H, W)
"""
h, w = x.size()[-2:] # 获取输入的高度和宽度
# 将输入分为两部分,x0 和 x1
x0, x1 = self.proj(x).split([self.chunk_dim, self.dim - self.chunk_dim], dim=1)
# 对x0进行池化,并通过深度卷积进行处理
x2 = F.adaptive_max_pool2d(x0, (h // 8, w // 8)) # 自适应池化,缩小为原图的1/8大小
x2 = self.dwconv(x2) # 深度卷积
x2 = F.interpolate(x2, size=(h, w), mode='bilinear') # 上采样恢复到原尺寸
x2 = self.act(x2) * x0 # 激活并与x0相乘,进行特征调制
# 将x1和调制后的x2合并,进行后续处理
x = torch.cat([x1, x2], dim=1)
x = self.out(self.act(x)) # 输出
return x
# Convolutional Channel Mixer 模块
class CCM(nn.Module):
def __init__(self, dim, ffn_scale, use_se=False):
"""
初始化CCM模块。
dim: 输入的特征图通道数。
ffn_scale: 用于计算隐藏层维度的比例。
use_se: 是否使用Squeeze-and-Excitation(SE)模块
"""
super().__init__()
self.use_se = use_se
hidden_dim = int(dim * ffn_scale) # 隐藏层通道数
# 卷积层1:进行通道扩展
self.conv1 = nn.Conv2d(dim, hidden_dim, 3, 1, 1, bias=False)
# 卷积层2:将通道恢复到原始维度
self.conv2 = nn.Conv2d(hidden_dim, dim, 1, 1, 0, bias=False)
self.act = nn.GELU() # 激活函数
def forward(self, x):
"""
前向传播:进行特征混合
x: 输入特征图,大小为 (batch_size, dim, H, W)
"""
x = self.act(self.conv1(x)) # 经过卷积和激活
x = self.conv2(x) # 经过第二层卷积
return x
# Attention Block 模块
class AttBlock(nn.Module):
def __init__(self, dim, ffn_scale, use_se=False):
"""
初始化Attention Block模块,该模块包含SimpleSAFM和CCM
"""
super().__init__()
# SimpleSAFM:空间自适应特征调制
self.conv1 = SimpleSAFM(dim, ratio=3)
# CCM:卷积通道混合
self.conv2 = CCM(dim, ffn_scale, use_se)
def forward(self, x):
"""
前向传播:依次经过SimpleSAFM和CCM模块
x: 输入特征图,大小为 (batch_size, dim, H, W)
"""
out = self.conv1(x) # 经过SimpleSAFM模块
out = self.conv2(out) # 经过CCM模块
return out + x # 残差连接
# SAFM与NPP(Non-Local Prior Pooling)结合的超分辨率网络
class SAFMNPP(nn.Module):
def __init__(self, input_dim, dim, n_blocks=3, ffn_scale=1.5, use_se=False, upscaling_factor=2):
"""
初始化SAFMNPP超分辨率模型。
input_dim: 输入图像的通道数。
dim: 网络中间层的通道数。
n_blocks: 注意力块的数量。
ffn_scale: 用于计算通道数的比例。
use_se: 是否使用Squeeze-and-Excitation(SE)模块。
upscaling_factor: 超分辨率放大因子。
"""
super().__init__()
self.scale = upscaling_factor # 设置上采样因子
# 输入特征图转换
self.to_feat = nn.Conv2d(input_dim, dim, 3, 1, 1, bias=False)
# 堆叠多个Attention块
self.feats = nn.Sequential(*[AttBlock(dim, ffn_scale, use_se) for _ in range(n_blocks)])
# 输出恢复图像的卷积层
self.to_img = nn.Sequential(
nn.Conv2d(dim, input_dim * upscaling_factor ** 2, 3, 1, 1, bias=False),
nn.PixelShuffle(upscaling_factor) # 用PixelShuffle进行上采样
)
def forward(self, x):
"""
前向传播:输入图像经过多个模块进行超分辨率恢复
x: 输入图像,大小为 (batch_size, input_dim, H, W)
"""
# 首先通过插值进行上采样
res = F.interpolate(x, scale_factor=self.scale, mode='bilinear', align_corners=False)
# 通过to_feat模块将输入特征转换到中间层
x = self.to_feat(x)
# 通过多个Attention块进行特征处理
x = self.feats(x)
# 通过to_img模块进行恢复图像
return self.to_img(x) + res # 最终输出图像加上残差
🍂修改处二
在 task.py文件中导入SAFMNPP类
导入代码如下:
import thop
import torch
import torch.nn as nn
#修改
from ultralytics.nn.modules.SAFM import SAFMNPP
#修改
🍂修改处三
在task.py中将SAFMNPP的使用添加修改到1000行左右位置,修改后代码如下:
if m in {
Classify,
...
#修改
SAFMNPP,
#修改
...
}
c1, c2 = ch[f], args[0]
注意:使用YOLOv12进行训练,torch版本要在2.x及以上,否则会出现scaled_dot_product_attention模块导入不成功的问题
from torch.nn.functional import scaled_dot_product_attention as sdpa
🍂修改处四
修改网络结构定义yolov12.yaml文件,在原来的模型结构基础上用SAFMNPP模块替换UpSample上采样模块。注意要根据自己的数据集修改nc,即num_class。
👍👍5.成功训练后的网络结构截图
至此就可以愉快的炼丹了。希望大家都能成果多多,paper多多~~~
整理不易,欢迎一键三连!!!
送你们一条美丽的--分割线--
🌷🌷🍀🍀🌾🌾🍓🍓🍂🍂🙋🙋🐸🐸🙋🙋💖💖🍌🍌🔔🔔🍉🍉🍭🍭🍋🍋🍇🍇🏆🏆📸📸⛵⛵⭐⭐🍎🍎👍👍🌷🌷