YOLO11改进 - 卷积Conv | FSConv频率—空间卷积:Haar小波融合高低频与空间特征,增强红外小目标细节保留 | TGRS 2025
前言本文介绍了FSConvFrequency–Spatial Convolution频率—空间卷积模块在YOLO11中的结合应用。FSConv通过空间卷积分支与Haar小波频率分支协同提取局部细节、低频结构和多方向高频信息增强网络在降采样过程中对红外小目标与复杂背景特征的表达能力。我们使用FSConv替换YOLO11主干网络和检测头中的步长为2的下采样卷积并进行相应的模块注册和模型配置用于在尺度压缩过程中保留空间结构与频率细节。文章目录 YOLO11改进大全卷积层、轻量化、注意力机制、损失函数、Backbone、SPPF、Neck、检测头全方位优化汇总专栏链接: YOLO11改进专栏介绍由于信噪比极低红外小目标检测IRSTD仍然面临挑战。现有方法难以兼顾精度与速度尤其是在计算资源有限的情况下。为解决这些问题我们提出了一种基于YOLOv10n架构的频率—空间上下文融合网络FSCFNet。具体而言我们设计了新颖的频率—空间卷积FSConv通过Haar小波变换WT分解输入特征。高频信息聚焦局部细节以突出小目标低频信息则提供全局信息来补充空间特征。随后我们提出非对称跨域注意力ACA以增强局部中心特征的提取这反映了小目标典型的空间高斯分布模式。此外我们引入定制的多尺度感受野上下文块MRCB利用多种扩张卷积捕获长距离信息。同时采用Wasserstein距离损失WDL提高边界框质量。在IRSTD-1k、NUDT-SIRST和NUAA-SIRST三个公开数据集上的大量实验验证了FSCFNet的有效性。值得注意的是在参数量仅增加3.6%的情况下FSCFNet在IRSTD-1k上相较基线的精确率、召回率和AP50分别提高了4.7%、3.3%和3.9%。FSCFNet为资源受限环境中的实时红外监视系统提供了一种稳健的解决方案。文中还给出了更多对比结果。文章链接论文地址https://ieeexplore.ieee.org/document/11175146代码地址https://github.com/qzxwj/FSCFNet/blob/46198dfb9a4aaead11cccc704a8575c6f0cdb3f2/ultralytics/nn/modules/FSConv.py#L53基本原理1. 解决的关键问题红外小目标通常只占图像中的极少像素目标响应弱、纹理信息有限并且容易被热噪声、云层、建筑边缘和复杂地物背景淹没。普通步长卷积在完成降采样时主要在空间域聚合局部邻域可能进一步削弱小目标的高频边缘和方向细节只依赖空间特征也难以充分区分外观相似的真实目标与背景伪目标。FSConv通过引入Haar离散小波变换把空间特征拆分为全局结构相关的低频分量和局部细节相关的高频分量使降采样过程能够同时利用空间信息与互补的频率信息。2. 整体架构FSConv首先使用逐通道的1×1卷积将输入通道扩展为原来的两倍再沿通道维度拆分成空间分支和频率分支。空间分支通过步长为2的3×3卷积提取下采样空间特征频率分支使用一级Haar小波变换得到一个低频子带LL和三个高频子带HL、LH、HH。三个高频子带拼接后经过分组卷积和SE通道重标定低频子带则由另一条卷积分支独立处理。增强后的高频特征与空间分支逐元素相乘随后再与低频特征拼接并通过1×1卷积完成通道融合输出二分之一空间尺度的特征图。FSConv的输出尺寸天然对应步长为2的下采样层因此它与YOLO11中的下采样卷积具有直接的接口匹配关系而C3k2和C2PSA通常要求模块保持特征图尺寸不变。基于这一尺寸契约及用户给出的配置本文将FSConv用于主干网络P1/2至P5/32的五个尺度压缩位置以及检测头P3到P4、P4到P5的两个下采样位置而不是嵌入C3k2或C2PSA内部。3. 技术原理设输入特征为X ∈ R B × C 1 × H × W X\in\mathbb{R}^{B\times C_1\times H\times W}X∈RB×C1​×H×W。首先通过逐通道卷积扩展通道并拆分为X s X_sXs​与X f X_fXf​。空间分支使用步长为2的卷积得到F s F_sFs​频率分支对X f X_fXf​执行Haar离散小波变换得到低频近似分量A AA与水平、垂直、对角三个高频细节分量H f H_fHf​、V f V_fVf​、D f D_fDf​。高频分量先按通道拼接F h Concat ⁡ ( H f , V f , D f ) F_h\operatorname{Concat}(H_f,V_f,D_f)Fh​Concat(Hf​,Vf​,Df​)随后通过分组卷积提取高频特征并利用SE机制根据全局通道统计生成权重从而强化与小目标局部细节相关的通道。低频分量独立卷积后保留背景轮廓和大尺度上下文。代码中使用F s ⊙ F h ′ F_s\odot F_hFs​⊙Fh′​将空间响应与高频注意结果进行逐元素调制再与低频特征拼接F Concat ⁡ ( F s ⊙ F h ′ , F l ) F\operatorname{Concat}(F_s\odot F_h,F_l)FConcat(Fs​⊙Fh′​,Fl​)最后通过1×1卷积完成跨分支压缩与融合。这样既利用了空间分支的局部定位能力也保留了低频全局结构和三个方向的高频细节。适配YOLO11时空间分支和低频分支的分组数使用输入、输出通道的最大公约数以兼容首层RGB三通道输入和YOLO的宽度缩放SE中间通道设置下限为1避免极小通道配置产生零维线性层。核心代码classFSConv(nn.Module):def__init__(self,c1,c2,k3,s1,pNone,d1):super().__init__()self.c1c1 self.conv1Conv(c1,2*c1,1,gc1)self.wtDWTForward(J1,modezero,wavehaar)self.conv2Conv(c1,c2,k,2,gc1)self.conv3Conv(c1*3,c2,3,d1,gmath.gcd(c1*3,c2))self.seSEBlock(c2)self.conv4Conv(c1,c2,3,gc1)self.conv5Conv(2*c2,c2,1)defforward(self,x):x0self.conv1(x)x1,x2torch.split(x0,self.c1,dim1)conv_spatialself.conv2(x1)yL,yHself.wt(x2)# Extract the high-frequency subbandsy_HLyH[0][:,:,0,:]y_LHyH[0][:,:,1,:]y_HHyH[0][:,:,2,:]high_frequency_fusedtorch.cat([y_HL,y_LH,y_HH],dim1)high_frequency_fused_outputself.conv3(high_frequency_fused)# Apply SE attentionhigh_frequency_fused_outputself.se(high_frequency_fused_output)low_frequency_fused_outputself.conv4(yL)spatial_outputconv_spatial*high_frequency_fused_output fusedtorch.cat([spatial_output,low_frequency_fused_output],dim1)outself.conv5(fused)returnoutYOLO11引入代码在根目录下的ultralytics/nn/目录新建一个conv目录然后新建一个以FSConv.py为文件名的py文件 把代码拷贝进去。importmathimporttorchimporttorch.nnasnnfrompytorch_waveletsimportDWTForwardfromultralytics.nn.modules.convimportConvclassSEBlock(nn.Module):Squeeze-and-excitation block used by FSConv.def__init__(self,channel,reduction16):super().__init__()hiddenmax(channel//reduction,1)self.avg_poolnn.AdaptiveAvgPool2d(1)self.fcnn.Sequential(nn.Linear(channel,hidden,biasFalse),nn.ReLU(inplaceTrue),nn.Linear(hidden,channel,biasFalse),nn.Sigmoid(),)defforward(self,x):b,c,_,_x.size()yself.avg_pool(x).view(b,c)yself.fc(y).view(b,c,1,1)returnx*yclassFSConv(nn.Module):Frequency-spatial downsampling convolution using Haar wavelet decomposition.def__init__(self,c1,c2,k3,s1,pNone,d1):super().__init__()self.c1c1 self.conv1Conv(c1,2*c1,1,gc1)self.wtDWTForward(J1,modezero,wavehaar)# gcd grouping keeps the paper implementation valid for YOLOs RGB stem and width-scaled channels.self.conv2Conv(c1,c2,k,2,gmath.gcd(c1,c2))self.conv3Conv(c1*3,c2,3,d1,gmath.gcd(c1*3,c2))self.seSEBlock(c2)self.conv4Conv(c1,c2,3,gmath.gcd(c1,c2))self.conv5Conv(2*c2,c2,1)defforward(self,x):x0self.conv1(x)x1,x2torch.split(x0,self.c1,dim1)conv_spatialself.conv2(x1)yL,yHself.wt(x2)y_HLyH[0][:,:,0,:]y_LHyH[0][:,:,1,:]y_HHyH[0][:,:,2,:]high_frequency_fusedtorch.cat([y_HL,y_LH,y_HH],dim1)high_frequency_fused_outputself.conv3(high_frequency_fused)high_frequency_fused_outputself.se(high_frequency_fused_output)low_frequency_fused_outputself.conv4(yL)spatial_outputconv_spatial*high_frequency_fused_output fusedtorch.cat([spatial_output,low_frequency_fused_output],dim1)returnself.conv5(fused)注册在ultralytics/nn/tasks.py中进行如下操作步骤1:fromultralytics.nn.conv.FSConvimportFSConv步骤2修改def parse_model(d, ch, verboseTrue):ifmin{# ...已有模块...FSConv,}:c1,c2ch[f],args[0]ifc2!nc:c2make_divisible(min(c2,max_channels)*width,8)args[c1,c2,*args[1:]]配置yolo11-FSConv.yaml# Ultralytics YOLO , AGPL-3.0 license# YOLO11 object detection model with P3-P5 outputs. For Usage examples see https://docs.ultralytics.com/tasks/detect# Parametersnc:80# number of classesscales:# model compound scaling constants, i.e. modelyolo11n.yaml will call yolo11.yaml with scale n# [depth, width, max_channels]n:[0.50,0.25,1024]# summary: 319 layers, 2624080 parameters, 2624064 gradients, 6.6 GFLOPss:[0.50,0.50,1024]# summary: 319 layers, 9458752 parameters, 9458736 gradients, 21.7 GFLOPsm:[0.50,1.00,512]# summary: 409 layers, 20114688 parameters, 20114672 gradients, 68.5 GFLOPsl:[1.00,1.00,512]# summary: 631 layers, 25372160 parameters, 25372144 gradients, 87.6 GFLOPsx:[1.00,1.50,512]# summary: 631 layers, 56966176 parameters, 56966160 gradients, 196.0 GFLOPs# YOLO11n backbonebackbone:# [from, repeats, module, args]-[-1,1,FSConv,[64]]# 0-P1/2-[-1,1,FSConv,[128]]# 1-P2/4-[-1,2,C3k2,[256,False,0.25]]-[-1,1,FSConv,[256]]# 3-P3/8-[-1,2,C3k2,[512,False,0.25]]-[-1,1,FSConv,[512]]# 5-P4/16-[-1,2,C3k2,[512,True]]-[-1,1,FSConv,[1024]]# 7-P5/32-[-1,2,C3k2,[1024,True]]-[-1,1,SPPF,[1024,5]]# 9-[-1,2,C2PSA,[1024]]# 10# YOLO11n headhead:-[-1,1,nn.Upsample,[None,2,nearest]]-[[-1,6],1,Concat,[1]]# cat backbone P4-[-1,2,C3k2,[512,False]]# 13-[-1,1,nn.Upsample,[None,2,nearest]]-[[-1,4],1,Concat,[1]]# cat backbone P3-[-1,2,C3k2,[256,False]]# 16 (P3/8-small)-[-1,1,FSConv,[256]]-[[-1,13],1,Concat,[1]]# cat head P4-[-1,2,C3k2,[512,False]]# 19 (P4/16-medium)-[-1,1,FSConv,[512]]-[[-1,10],1,Concat,[1]]# cat head P5-[-1,2,C3k2,[1024,True]]# 22 (P5/32-large)-[[16,19,22],1,Detect,[nc]]# Detect(P3, P4, P5)实验脚本importwarnings warnings.filterwarnings(ignore)fromultralyticsimportYOLOif__name____main__:# 修改为自己的配置文件地址modelYOLO(./ultralytics/cfg/models/11/yolo11-FSConv.yaml)# 修改为自己的数据集地址model.train(data./ultralytics/cfg/datasets/coco8.yaml,cacheFalse,imgsz640,epochs10,single_clsFalse,# 是否是单类别检测batch8,close_mosaic10,workers0,optimizerSGD,ampTrue,projectruns/train,nameFSConv,)结果