YOLO26改进 – C3k2 C3k2融合SFS-Conv空间 – 频率选择卷积,在单卷积层中提取空间和频率维度特征,降低通道冗余

# 前言

本文介绍了高效卷积模块SFS - Conv及其在YOLO26中的结合应用。传统深度卷积神经网络在合成孔径雷达(SAR)目标检测中存在特征冗余、信息单一问题,现有轻量模型或压缩方法会导致性能下降。SFS - Conv采用“分流 - 感知 - 选择”策略,将输入特征图分流为空间和频率维度,分别通过空间感知单元(SPU)和频率感知单元(FPU)提取特征,再由通道选择单元(CSU)自适应融合。基于此模块构建了轻量级SAR目标检测网络SFS - CNet。我们将相关组件集成进YOLO26,实验表明其在SAR目标检测基准数据集上优于当前先进模型,且减少了模型规模和计算成本。

文章目录: YOLO26改进大全:卷积层、轻量化、注意力机制、损失函数、Backbone、SPPF、Neck、检测头全方位优化汇总

专栏链接: YOLO26改进专栏

介绍

image-20251125223811534

摘要

深度卷积神经网络(DCNNs)在合成孔径雷达(SAR)目标检测中取得了显著性能,但这需要巨大的计算资源作为代价,部分原因是单个卷积层内会提取冗余特征。近年来的研究要么致力于模型压缩方法,要么专注于精心设计的轻量级模型,这两种方式都会导致性能下降。本文提出一种适用于SAR目标检测的高效卷积模块SFS-Conv,通过“分流-感知-选择”策略提升每个卷积层内的特征多样性。具体而言,我们将输入特征图分流为空间和频率两个维度:前者通过动态调整感受野感知各类目标的上下文信息,后者借助分数伽柏变换捕捉丰富的频率变化和纹理特征。为自适应融合空间与频率维度的特征,我们设计了无参数特征选择模块,确保保留最具代表性和辨识度的信息。基于SFS-Conv,我们构建了轻量级SAR目标检测网络SFS-CNet。实验结果表明,SFS-CNet在一系列SAR目标检测基准数据集上优于当前最先进(SoTA)模型,同时减少了模型规模和计算成本。

文章链接

论文地址:论文地址

代码地址:代码地址

基本原理

SFS-Conv是针对SAR(合成孔径雷达)目标检测设计的高效轻量卷积模块,核心目标是解决传统卷积特征冗余、依赖单一空间维度信息的问题,通过“分流-感知-选择”(shunt-perceive-select)策略,在单卷积层内同时提取空间与频率特征,实现“高辨识度特征+低计算成本”的平衡,是SFS-CNet网络的核心组件。

一、核心设计定位

  • 解决痛点:传统DCNN在SAR检测中存在两大问题——特征冗余(单卷积层提取相似特征)、信息单一(仅依赖空间特征,难以应对SAR图像的相干斑噪声和复杂背景);现有轻量模型或压缩方法会导致性能下降。
  • 设计目标:在不增加通道数的前提下,提升特征多样性与辨识度,同时减少模型参数和计算量(FLOPs),适配资源受限场景部署。

二、整体工作流程

SFS-Conv的输入为特征图 $X \in \mathbb{R}^{C × H × W}$(C为通道数,H/W为空间尺寸),输出为融合后的高辨识度特征 $Y$,完整流程分三步:

  1. 分流(Shunt):按比例α将输入特征拆分为空间分支 $X^s \in \mathbb{R}^{(1-\alpha)C × H × W}$ 和频率分支 $X^f \in \mathbb{R}^{\alpha C × H × W}$,再通过1×1逐点卷积(PWC)分别调整通道适配性。
  2. 感知(Perceive):空间分支由SPU提取多尺度上下文特征,频率分支由FPU提取高频纹理与散射特征。
  3. 选择(Select):由CSU无参数自适应融合双分支特征,保留最具代表性的信息。

三、关键组件详解

1. 分流策略(Shunt Strategy)

  • 核心逻辑:按比例分配通道资源,同时覆盖空间与频率信息,避免单一维度信息缺失。
  • 关键参数:分流比例α,实验验证最优值为1/4(此时AP50达95.73%);α=1/2时可实现“性能-效率”平衡(AP50仅降0.02%,模型参数减少0.11M)。
  • 作用:为后续双分支感知提供针对性输入,避免通道资源浪费。

2. 空间感知单元(SPU:Spatial Perception Unit)

  • 核心目标:动态适配SAR目标的多尺度特性(小目标、尺度差异大),捕捉目标与周围环境的上下文关系。
  • 实现原理
    • 通道分组:将 $X^s$ 均匀拆分为n组 $X_g^s$(每组通道数为 $C/n$),每组对应不同尺寸的卷积核 $K_g$。
    • 动态感受野扩展:通过层级残差连接扩大感受野,核尺寸与感受野满足公式: $$ k_{g+1}=k_g+2\ (k1=3),\quad RF{g+1}=RFg+(k{g+1}-1) $$ 即后一组卷积核会接收前所有组的特征,感受野逐层扩大,适配不同尺度目标。
    • 特征融合:将n组输出沿通道拼接,通过1×1卷积整合为空间精炼特征 $Y^s$。
  • 优势:无需额外注意力模块,通过分组+残差实现多尺度建模,参数开销低。

3. 频率感知单元(FPU:Frequency Perception Unit)

  • 核心目标:提取SAR图像的高频纹理与电磁散射特征,抑制相干斑噪声,弥补空间特征的局限性。
  • 核心技术:分数伽柏变换(FrGT:Fractional Gabor Transform),融合伽柏变换(GT)的多方向/多尺度优势与分数傅里叶变换(FrFT)的多普勒频移抑制能力。
  • 实现原理
    • 2D离散FrGT扩展:将1D连续FrGT适配图像场景,公式为: $$ Gf^\alpha(x,y,u,v) = \sum{i=0}^{H-1}\sum_{m=0}^{U-1} B(i,\frac{m}{UT1},\alpha)\bar{g}(i-m) \left[ \sum{j=0}^{W-1}\sum_{n=0}^{V-1} f(i,j) B(j,\frac{n}{VT_2},\alpha)\bar{g}(j-n) \right] $$ 其中 $B(\cdot)$ 为变换核,α为变换角度,U/V为分数域采样数,可捕捉多尺度/多方向高频特征。
    • 卷积核调制:用FrGT滤波器调制普通卷积核,生成分数伽柏核(FrGK),公式为 $K{i,u}^v = K{i,o} * G(u,v)$($G(u,v)$ 为不同方向/尺度的FrGT滤波器)。
    • 特征输出:将 $X^f$ 分组后与对应FrGK卷积,拼接所有组输出得到频率精炼特征 $Y^f$。
  • 优势:天生抑制相干斑噪声,对目标旋转、尺度变化鲁棒,无需额外去噪模块。

4. 通道选择单元(CSU:Channel Selection Unit)

  • 核心目标:自适应融合 $Y^s$ 与 $Y^f$,保留最具辨识度的特征,且不增加额外参数。
  • 实现原理
    1. 全局信息聚合:通过全局平均池化(GAP)提取双分支的通道级统计信息 $S^s = GAP(Y^s)$、$S^f = GAP(Y^f)$(维度均为 $C×1×1$)。
    2. 自适应权重生成:用通道级soft attention计算融合权重,公式为: $$ \gamma = \frac{e^{S^s}}{e^{S^s}+e^{S^f}},\quad \beta = \frac{e^{S^f}}{e^{S^s}+e^{S^f}} $$ 其中γ、β分别为空间与频率特征的权重,动态适配不同场景下的特征重要性。
    3. 特征融合:按权重加权求和得到最终输出 $Y = \gamma \cdot Y^s + \beta \cdot Y^f$。
  • 优势:无参数设计(避免增加计算量),自适应选择最优特征组合,比简单相加(AP50=94.68%)提升1.03%。

核心代码

class SFS_Conv(nn.Module):
    def __init__(
        self, in_channels, out_channels, order=0.25, filter="FrGT"):
        super().__init__()
        self.PWC0 = Conv(in_channels, in_channels // 2, 1)
        self.PWC1 = Conv(in_channels, in_channels // 2, 1)
        self.SPU = SPU(in_channels // 2, out_channels)

        assert filter in (
            "FrFT",
            "FrGT",
        ), "The filter type must be either Fractional Fourier Transform(FrFT) or Fractional Gabor Transform(FrGT)."
        if filter == "FrFT":
            self.FPU = FourierFPU(in_channels // 2, out_channels, order)
        elif filter == "FrGT":
            self.FPU = GaborFPU(in_channels // 2, out_channels, order)

        self.PWC_o = Conv(out_channels, out_channels, 1)
        self.advavg = nn.AdaptiveAvgPool2d(1)

    def forward(self, x):
        x_spa = self.SPU(self.PWC0(x))
        x_fre = self.FPU(self.PWC1(x))
        out = torch.cat([x_spa, x_fre], dim=1)
        out = F.softmax(self.advavg(out), dim=1) * out
        out1, out2 = torch.split(out, out.size(1) // 2, dim=1)

        return self.PWC_o(out1 + out2)

实验

脚本

# Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license

# Ultralytics YOLO26 object detection model with P3/8 - P5/32 outputs
# Model docs: https://docs.ultralytics.com/models/yolo26
# Task docs: https://docs.ultralytics.com/tasks/detect

# Parameters
nc: 80 # number of classes
end2end: True # whether to use end-to-end mode
reg_max: 1 # DFL bins
scales: # model compound scaling constants, i.e. 'model=yolo26n.yaml' will call yolo26.yaml with scale 'n'
  # [depth, width, max_channels]
  n: [0.50, 0.25, 1024] # summary: 260 layers, 2,572,280 parameters, 2,572,280 gradients, 6.1 GFLOPs
  s: [0.50, 0.50, 1024] # summary: 260 layers, 10,009,784 parameters, 10,009,784 gradients, 22.8 GFLOPs
  m: [0.50, 1.00, 512] # summary: 280 layers, 21,896,248 parameters, 21,896,248 gradients, 75.4 GFLOPs
  l: [1.00, 1.00, 512] # summary: 392 layers, 26,299,704 parameters, 26,299,704 gradients, 93.8 GFLOPs
  x: [1.00, 1.50, 512] # summary: 392 layers, 58,993,368 parameters, 58,993,368 gradients, 209.5 GFLOPs

# YOLO26n 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_SFSConv, [256, False, 0.25]]
  - [-1, 1, Conv, [256, 3, 2]] # 3-P3/8
  - [-1, 2, C3k2_SFSConv, [512, False, 0.25]]
  - [-1, 1, Conv, [512, 3, 2]] # 5-P4/16
  - [-1, 2, C3k2_SFSConv, [512, True]]
  - [-1, 1, Conv, [1024, 3, 2]] # 7-P5/32
  - [-1, 2, C3k2_SFSConv, [1024, True]]
  - [-1, 1, SPPF, [1024, 5, 3, True]] # 9
  - [-1, 2, C2PSA, [1024]] # 10

# YOLO26n head
head:
  - [-1, 1, nn.Upsample, [None, 2, "nearest"]]
  - [[-1, 6], 1, Concat, [1]] # cat backbone P4
  - [-1, 2, C3k2_SFSConv, [512, True]] # 13

  - [-1, 1, nn.Upsample, [None, 2, "nearest"]]
  - [[-1, 4], 1, Concat, [1]] # cat backbone P3
  - [-1, 2, C3k2_SFSConv, [256, True]] # 16 (P3/8-small)

  - [-1, 1, Conv, [256, 3, 2]]
  - [[-1, 13], 1, Concat, [1]] # cat head P4
  - [-1, 2, C3k2_SFSConv, [512, True]] # 19 (P4/16-medium)

  - [-1, 1, Conv, [512, 3, 2]]
  - [[-1, 10], 1, Concat, [1]] # cat head P5
  - [-1, 1, C3k2_SFSConv, [1024, True, 0.5, True]] # 22 (P5/32-large)

  - [[16, 19, 22], 1, Detect, [nc]] # Detect(P3, P4, P5)

结果

image-20260124211141325

THE END