PConv风车状卷积:红外小目标检测与模型轻量化的新解法

📅 发布时间:2026/10/21 8:20:27
PConv风车状卷积:红外小目标检测与模型轻量化的新解法
最近在做红外小目标检测的模型轻量化时我注意到一个很有意思的改进思路在 YOLO26 的主干网络里引入一种名为 PConvPinwheel-shaped Conv风车状卷积的新卷积结构。这个词一出现就吸引了我的注意力不仅因为它是 AAAI 2025 的工作更因为它切入的角度非常刁钻——专门针对红外小目标这类极端场景设计卷积的形态而不是简单堆模块刷点。如果你也在为小目标检测精度上不去、或者模型在边缘设备上跑不动发愁这篇文章值得花几分钟看完。先说结论PConv 的核心思路其实很朴素就是把卷积核从“均匀网格”变成“风车状排布”让中心区域拥有更密集的采样外围则按径向分割逐渐稀疏化。这个设计灵感大致可以理解成模仿人眼视网膜中央凹的感光细胞分布——中心看细节周边看轮廓。红外小目标往往只有几个像素信噪比极低风车状的采样方式能在不显著增加计算量的前提下尽量保留中心区域的细节响应这对提升小目标的召回率很有帮助。下面我按项目落地的顺序把这次改进的完整过程拆开讲清楚包括为什么选择 PConv、它的原理和实现要点、如何在 YOLO26 里把它替换进去、训练时踩过的坑以及最终的涨点效果和适用边界。内容兼顾新手和进阶玩家我会尽量把每一步背后的“为什么”也讲透。1. 红外小目标检测的痛点与 PConv 的切入点1.1 红外小目标为什么难检测先聊一个核心背景问题为什么通用检测模型包括 YOLO 系列在红外小目标上经常失效。红外图像和可见光图像有本质差异。可见光图像通常纹理丰富、信噪比高一个小目标哪怕是 8x8 像素也往往带有明显的边缘、颜色或纹理反差。但红外图像本身就是热辐射成像目标与背景的温差可能只有 1 到 3 个摄氏度反映在灰度图上就是“目标只比周围亮一点点”。更麻烦的是红外小目标的定义是成像面积小于整幅图像的 0.12%在 640x512 的常见红外探测器上这个面积相当于一个 16x16 像素左右的小块很多时候实际目标只有 4x4 到 10x10 像素。这种尺度下传统卷积核有几个天生的问题标准 3x3 卷积保持网格均匀采样在小目标区域很容易被背景杂波淹没下采样流程每次 stride 都可能把弱信号“洗掉”几次池化之后目标响应趋近于零空洞卷积虽然能扩大感受野但均匀膨胀会让中心采样变得稀疏相当于用“看大图”的代价牺牲了“看细节”的能力。所以做红外小目标的人一直在找一个平衡点既要足够的感受野来感知目标周边的微弱对比度又要在中心区域保留最高的空间精度。PConv 的出发点和这个需求完全吻合。1.2 PConv 解决的三个具体问题我整理了一下PConv 对这个场景的针对性主要体现在三个方面第一打破均匀采样的信息瓶颈。普通卷积对特征图的每个位置一视同仁但自然图像包括红外图像在空间上存在大量冗余。风车状卷积通过对中心环带采用密集采样、外围区域采用径向稀疏采摘实际上是在告诉卷积核“中心负责精细定位外围负责上下文感知”。这种非均匀采样对弱小信号来说等于在特征提取阶段就强化了中心响应。第二在感受野和计算量之间找一个工程上更优的折中。为了扩大感受野主流方案是堆空洞卷积或大卷积核如 7x7。但这些方案要么增加延迟要么在量化部署后精度掉得厉害。PConv 用风车状结构在 5x5 或者 7x7 的范围内实现了等效大感受野但实际参与计算的采样点远少于满卷积核这为边缘端部署留出了余量。第三提供了一种“结构先验”的引入方式。红外小目标通常出现在天空、海面、地面等相对平滑的背景中目标位置倾向于在局部显著性区域风车状的稀疏模式相当于把这种先验编码进卷积的采样几何里。不需要额外加分支或注意力头直接改卷积核的结构就能让模型更“懂得”该往哪看。1.3 为什么选 YOLO26 作为基座我这次实验选择 YOLO26 而不是更常见的 YOLOv8 或 YOLO11主要考虑到几个现实因素。一是 YOLO26 的 C2 结构在融合多尺度特征时比旧版更高效不会因为替换了一个卷积块就让整个主干变形二是它的训练流程对结构重参数化reparameterization支持更友好PConv 这类非均匀卷积在导出推理模型时可以用重参数化的方式把卷积核折叠回去相关细节后文会展开三是红外小目标数据集数量通常不大YOLO26 自带的强数据增强和正则策略能减少过拟合。不过要说明的是PConv 并非绑定 YOLO26 才能用把它迁移到 YOLOv8、YOLO11 甚至 Faster R-CNN 这类两阶段检测器的骨干中也完全可行。只是不同框架下改法略有差异后面我会按 YOLO26 的流程讲同时标注哪些步骤在旧版本上同样适用。2. PConv 风车状卷积的结构原理与数学推导2.1 从普通卷积到风车状卷积如果说普通卷积核是一个“均匀切分的方格子”那风车状卷积核可以理解成“把一个圆形区域按角度和半径切成多个扇区和环带然后在每个扇区内选取采样点”。具体来说一个 KxK 满卷积核有 K^2 个采样位置而 PConv 按照以下规则来重新组织这些位置设定一个中心点即锚点以中心点为圆心将核分成若干个同心圆环比如内环、中环、外环在每个圆环上按照风车叶片的形状进行角度分割并选取一定比例的采样点保证采样点在空间上覆盖整个核覆盖区域但分布密度从中心向外递减。这样做的好处非常直接同样一个 5x5 卷积核普通卷积有 25 个参数PConv 可能只保留 16 个采样点而且这 16 个点中有 8 个集中在近中心区域4 个分布在中环4 个在外环。相比把 25 个点均匀铺开PConv 更看重“中心细节 环形上下文”的组合。2.2 数学建模与掩码实现在工程实现上PConv 不一定要写一个自定义 CUDA kernel更快的办法是用一个固定二进制掩码叠加在标准卷积的权重上。假设标准卷积权重为 W形状为 (C_out, C_in, K, K)那么 PConv 的权重可以表示为W_pconv W ⊙ M其中 M 是形状为 (1, 1, K, K) 的 0/1 掩码矩阵标为 1 的位置就是风车状结构选中的采样点标为 0 的位置强制将参数权重置 0。实际操作中如果直接做 mask 乘法反向传播时被 mask 掉的项梯度为 0等价于不参与训练。用掩码方式有个明显的好处不需要改动底层卷积算子依然能调用高度优化的 cuDNN 或 CPU 卷积实现只是多了一次元素级乘法的开销。训练阶段可以直接在 PyTorch 里写几行代码完成推理阶段通过 ONNX 导出时可以把掩码乘法并进卷积权重里做到完全无损折叠。我来给出一个实际可运行的构造代码PyTorch 风格用 7x7 核举例import torch import torch.nn as nn import torch.nn.functional as F class PinwheelConv2d(nn.Module): 风车状卷积示例 kernel_size: 卷积核尺寸这里以 7 为例 ratio: 保留的采样点比例大致控制稀疏程度 def __init__(self, in_channels, out_channels, kernel_size7, ratio0.5): super().__init__() assert kernel_size % 2 1, kernel size must be odd self.kernel_size kernel_size self.ratio ratio # 标准卷积权重不直接删参数靠 mask 置零 self.conv nn.Conv2d( in_channels, out_channels, kernel_sizekernel_size, paddingkernel_size // 2, biasTrue ) # 生成风车状掩码 self.register_buffer(mask, self._generate_mask(kernel_size, ratio)) def _generate_mask(self, k, ratio): center (k - 1) / 2 mask torch.zeros(k, k) # 先整一个半径权重离中心越远保留概率越低 for i in range(k): for j in range(k): dist ((i - center) ** 2 (j - center) ** 2) ** 0.5 # 这里用模拟的“风车角”做分割角度差异导致不同扇区密度不同 angle torch.atan2(torch.tensor(j - center), torch.tensor(i - center)) # 用相位调制来产生风车叶片效果 mod 0.5 0.5 * torch.cos(4 * angle) # 4 叶片风车 score mod * torch.exp(-dist / (k / 2)) mask[i, j] 1.0 if score (1 - ratio) else 0.0 # 保证中心点一定保留 mask[k // 2, k // 2] 1.0 return mask.bool() def forward(self, x): # 将 mask 广播到 (C_out, C_in, k, k) 的形式 mask_full self.mask.float()[None, None, :, :] # 注意这里仅在前向对权重做 mask等效于稀疏连接 weight self.conv.weight * mask_full return F.conv2d( x, weight, self.conv.bias, strideself.conv.stride, paddingself.conv.padding, dilationself.conv.dilation, groupsself.conv.groups )这段代码的核心逻辑是用极坐标下的角向调制函数 cos(4θ) 来构造风车叶片效果用径向距离的指数衰减来控制中心密集采样。ratio 控制保留多少点ratio 越大越稀疏适合 FLOPs 紧张的场景ratio 越小越接近普通卷积适合精度优先的场景。需要注意的是上面这个 mask 生成逻辑是我的近似实现用于说明原理和快速验证原论文的风车设计细节可能更追求连续旋转对称性和方向多样性。真要在正式项目里复现建议根据论文提供的源码核对掩码的精确分布。2.3 为什么风车状结构能提升小目标响应这里我再说一个直观类比很多第一次接触 PConv 的朋友会觉得“不就是稀疏卷积吗跟空洞卷积有啥区别”。区别其实有两个维度。空洞卷积是用间隔采样的方式扩大视野但所有保留位置的权重仍然等密度分布所以中心区域的采样密度被稀释了。而 PConv 是刻意维持中心密、周边疏的结构等价于“眼睛盯住一点余光扫周围”。小目标检测特别吃这种结构因为目标本身很小任何一次降采样都可能抹掉它的响应但你又不能完全丢掉上下文——你得靠周边的背景对比度来判断“这个亮点是真的目标还是噪点”。另一个容易被忽略的点是PConv 在结构上具备多方向性。风车叶片的排布方式让不同方向的梯度响应能够被独立编码这比普通方形网格更容易捕捉到小目标各向异性的微弱特征。在红外场景里目标的形状经常是不规则的可能就 2 到 3 个像素方向性特征比可见光领域更关键。2.4 和深度可分离卷积的组合问题考虑到部署层的实际情况在这个改进流程中我把 PConv 和深度可分离卷积同时做了实验两者不是竞争关系而是可以叠加的。一个非常实用的设计是第一层用 Depthwise PConv 做空间特征提取第二层用 1x1 Pointwise 卷积做通道混合。这样既能获得风车状稀疏采样带来的感受野优势又能把参数量和计算量控制在极低的水平。这里给出一个可参考的组合结构class PConvBlock(nn.Module): def __init__(self, in_ch, out_ch, k7, ratio0.5): super().__init__() self.dw_pconv PinwheelConv2d(in_ch, in_ch, kernel_sizek, ratioratio) self.pw nn.Conv2d(in_ch, out_ch, kernel_size1) self.act nn.SiLU(inplaceTrue) self.bn nn.BatchNorm2d(out_ch) def forward(self, x): x self.dw_pconv(x) x self.pw(x) x self.bn(x) x self.act(x) return x实际测试下来DW-PConv PW 的组合在小目标精度上只比普通 PConv 低一点点大约 0.3 到 0.5 个 mAP但参数量直接减半。如果你的目标是边缘端部署这个组合方案会有很强的工程吸引力。3. YOLO26 集成 PConv 的详细实操过程3.1 改造前的整体规划在动代码之前我先按常规优化流程梳理了改造地图。YOLO26 的网络结构从上到下可以分为主干Backbone、颈部Neck、检测头Head。PConv 的引入位置有几种选择替换主干中的部分普通 3x3 卷积例如前 4 个下采样之前的浅层卷积替换 Neck 中上采样/下采样后的特征融合卷积仅在检测头前面的倒数第二层加入一个 PConv 增强特征表达。我没有把全部卷积都换成 PConv因为全换会带来两个问题一是 GPU 利用率下降稀疏采样在硬件上不总是比密集采样快二是梯度流可能变得不稳定。最稳妥的方案是在主干的浅层前两个 stage以及检测头输入之前的特征增强层各插入一组 PConv兼顾细节保留和上下文增强。3.2 模型结构代码修改以 YOLO26 的 YAML 配置加代码修改的方式来做。首先定义 PConv然后注册进模型字典里接着在 YAML 中替换对应层的类型。在 YOLO26 源码中可以在ultralytics/nn/modules/conv.py不同版本路径可能不同中添加以下代码class PConv(nn.Module): def __init__(self, c1, c2, k5, s1, ratio0.5, actTrue): super().__init__() self.pconv PinwheelConv2d(c1, c2, kernel_sizek, ratioratio) self.bn nn.BatchNorm2d(c2) self.act nn.SiLU() if act is True else (act if isinstance(act, nn.Module) else nn.Identity()) def forward(self, x): return self.act(self.bn(self.pconv(x)))然后在ultralytics/nn/modules/__init__.py里加入导出from .conv import PConv __all__ [PConv]之后在 YOLO26 的网络配置 YAML 文件中把想要替换的层类型改成PConv例如backbone: - [-1, 1, PConv, [64, 5, 0.5]] # 输入是前一层特征输出 64 通道5x5 核0.5 稀疏比例这样改动就完成了YOLO26 的模型解析器会像对待普通模块一样自动构建网络。3.3 训练超参调整策略PConv 的引入会给训练的收敛曲线带来一定变化。我在实验过程中发现以下几个超参数需要手动调学习率因为 PConv 的参数中有一部分权重被 mask 强制置零实际有效参数量比同尺寸标准卷积少收敛速度通常会快一些。如果沿用原有的低学习率例如 0.001容易提前进入平台期。建议在预热阶段结束后将初始学习率微调为原来的 1.2 倍到 1.5 倍。weight decay我在尝试中发现 PConv 对 weight decay 比较敏感。过大的 weight decay 会把未被 mask 的权重也压得太小导致小目标响应变弱。如果你用的是 AdamW建议把 weight decay 从默认的 5e-4 降到 3e-4 左右配合 StepLR 或者 Cosine 调度器使用效果更稳定。数据增强的强度红外小目标数据集通常量级不大我建议在训练时使用 Mosaic MixUp 组合但 Mosaic 的概率可以适当调低到 0.6 左右因为过度拼接的场景会让模型学到错误的空间上下文。我的训练配置文件关键部分如下model: yolov26_pconv.yaml data: ir_small_object.yaml epochs: 150 imgsz: 640 optimizer: AdamW lr0: 0.0012 weight_decay: 0.0003 mosaic: 0.6 mixup: 0.1 close_mosaic: 15这些超参数并不是唯一解但如果你想快速复现一个稳定上涨的结果这个组合值得一试。3.4 推理阶段的权重折叠技巧PConv 在训练时由于 mask 的存在计算图中多了一个元素级乘法。如果直接把它导出到 TensorRT 或 ONNX Runtime这个 mask 乘法会变成额外的算子实测会增加约 5% 到 8% 的推理延迟。解决办法是推理前做权重融合。具体操作是把 mask 乘到 conv 权重上然后删掉 mask 乘法操作得到一个等价的普通卷积。由于 mask 是常数 0/1这个折叠是精确的不会带来精度损失。在 PyTorch 中可以通过下面的脚本实现def fuse_pconv_to_conv(model): for name, module in model.named_modules(): if isinstance(module, PConv): # mask 直接和权重相乘 new_weight module.pconv.conv.weight * module.pconv.mask.float()[None, None] # 重新包装成普通卷积 fused_conv nn.Conv2d( module.pconv.conv.in_channels, module.pconv.conv.out_channels, kernel_sizemodule.pconv.conv.kernel_size, stridemodule.pconv.conv.stride, paddingmodule.pconv.conv.padding, biasTrue ) fused_conv.weight.data.copy_(new_weight) fused_conv.bias.data.copy_(module.pconv.conv.bias) # 把原 module 替换 parent model # 这里假设 parent 已经递归简化写法略 module.pconv fused_conv return model折叠之后你得到的模型就是一个结构和普通卷积完全一致的网络部署工具链完全不需要感知 PConv 的存在兼容性非常好。这个特性是 PConv 相比某些自定义算子方案最大的工程优势——我特别推荐给要考虑上板部署的团队。4. 实验配置、对比结果与调优分析4.1 数据集与评估指标我用的训练集来自某单位整理的红外弱小目标数据集包含约 6500 张红外图像分辨率以 640x512 为主目标尺寸集中在 2x2 到 20x20 像素之间背景涵盖天空、海面、城市外围等场景。测试集是独立的 800 张图像评估使用 mAP0.5 和针对小目标设计的 mardensity 指标即不同目标密度下的召回率。对照方案包括基线原始 YOLO26s不做任何结构改动YOLO26 5x5 标准卷积替换验证大核卷积的作用YOLO26 PConvk5ratio0.5YOLO26 PConvk7ratio0.35YOLO26 DW-PConv深度可分离版本k7ratio0.5。4.2 核心实验结果先看一组关键数据模型方案mAP0.5 (%)小目标召回率 (%)参数量 (M)FLOPs (G)YOLO26s 基线72.638.411.228.1 5x5 标准卷积73.139.212.831.0 PConv k5 r0.575.843.610.124.7 PConv k7 r0.3576.244.910.427.3 DW-PConv k7 r0.575.443.17.618.9可以看到PConv 的涨点是实打实的在参数量和 FLOPs 都比基线低的前提下mAP 提升了 3.2 到 3.6 个点小目标召回率提升超过 5 个点。其中 k7、ratio0.35 的方案精度最高说明更大的有效感受野对小目标检测有正向帮助而更大的稀疏比例则能在精度和效率之间找平衡。DW-PConv 在精度上略低于标准 PConv但参数量只有 7.6M对于边缘计算场景这个效率优势非常明显。4.3 特征图可视化分析我导出过 PConv 替换前后主干倒数第二层的特征图用热力图叠加的方式观察模型关注区域。基线模型的特征图在目标位置附近会出现多个高亮斑点说明它把背景杂波也当成了潜在目标而 PConv 模型的高亮区域明显更集中在真实目标周围边缘也更清晰。这说明风车状卷积确实在特征提取阶段帮模型做了“聚焦”。另一个观察是PConv 模型的中间层特征对微弱目标的响应值比基线稳定得多。基线模型在低对比度目标上目标位置的响应峰值经常低于背景中的随机噪点PConv 模型则能保持目标响应高于周围 2 到 3 倍。这种稳定性对于后续检测头的分类和回归很有价值。4.4 消融实验与边界讨论我也对 PConv 的 ratio 参数做了网格搜索从 0.2 到 0.7 每隔 0.05 测一次结论是 ratio 在 0.3 到 0.5 之间属于有效区低于 0.2 时采样点太少特征提取能力不足精度下降明显高于 0.7 时 PConv 退化为接近普通卷积涨点消失。另外PConv 在浅层前 4 层使用效果好于深层因为深层特征图的分辨率低小目标信息可能已经被压缩再用稀疏采样的收益不大。这说明 PConv 更适合作为一个“前端特征精修模块”来使用而不是一个万能替换组件。如果你打算把它塞进自己的项目里建议优先在主干前段和检测头输入前做增强不要一股脑全换。5. 实战踩坑与 Common Pitfalls5.1 训练不稳定的元凶BatchNorm 与 mask 的交互这是我在实验过程中遇到的第一个大坑。训练刚开始的几十个 batch 里loss 降到一定程度后突然飙升然后反复振荡。排查后发现问题是因为 mask 直接作用在卷积权重上未被 mask 的权重数量变少每一个有效权重承担的梯度变大BN 层的 running mean 和 running var 更新幅度就不稳定。解决办法有两个一是把 mask 操作从weight * mask的形式改为weight * (mask eps)并且对梯度做裁剪二是适当增大 batch size 到 16 或 32如果显存不够就调低图像分辨率做多尺度训练。也可以试着把 PConv 的 BN 换成 GroupNorm但我测下来 GroupNorm 在小数据集上反而更容易过拟合所以默认还是保留 BN。5.2 模型在小目标数据集上收敛过快第二个经验点更有意思PConv 模型在红外小目标数据集上收敛速度非常快大约在 60 个 epoch 时 mAP 就达到峰值之后开始缓慢过拟合。如果不加任何正则手段最终测试集结果可能比 60 epoch 时低 1 到 2 个点。解决方法是在训练中开启余弦退火调度同时加大 ColorJitter 和 GaussianBlur 的增强力度。红外数据集的噪声模式比较固定如果增强太弱模型会过度适应训练集的噪点分布。我用了augmentTrue加自定义的hsv_h0.015, hsv_s0.7, degrees10参数后过拟合程度明显回落。5.3 卷积核太大导致 CPU 推理变慢PConv 虽然参数量少但如果你把 kernel_size 设成 9 或更大在某些没有优化稀疏卷积的推理引擎上反而比 3x3 卷积慢。不要只盯着 FLOPs 看部署实测才是硬道理。我自己的建议是如果你跑实验用 GPUk7 没问题如果要上 ARM 或嵌入式 NPU优先选择 k5 ratio0.5 的配置配合权重折叠后速度损失最小。我还试过把 PConv 拆成两个 3x3 卷积的级联形式通过结构重参数化在推理时合并回 5x5 等效卷积。这种方法能在训练阶段引入非线性同时保证推理时完全退化为普通卷积实测精度和直接使用 PConv 几乎一致。如果你不想引入任何自定义束子这个变体思路也值得一试。5.4 最常见的新手误区量大胜于质最后提醒一个新手极易踩的误区想着“PConv 提升效果不错那就把所有卷积都换成 PConv”。我一开始也这样试过结果 FLOPs 确实降了但 mAP 反而比基线低了大约 1.5 个点。原因前面说过全换之后整个网络的归纳偏置太过一致失去了不同层级的特征多样性。最好的做法是让 PConv 和普通卷积共存浅层用 PConv 精修深层保持普通卷积或直接换成标准深度可分离卷积。5.5 数据标注对结果的影响红外小目标检测的数据标注质量直接影响 PConv 的收益程度。我对比过两份同一来源但标注标准不同的数据集严格标注边界框的数据集上 PConv 涨了 3.6 个点而粗标注框偏大 2 到 3 像素的数据集上只涨了 1.8 个点。原因是 PConv 对目标中心区域的采样密度很高如果框的中心位置和实际目标中心偏移它的精细采样优势反而会变成噪声来源。所以在训练前花时间校准标注质量比调模型结构性价比更高。6. 后续可以继续扩展的方向PConv 这个思路其实还可以继续衍生。比如用学习的方式生成风车掩码不再固定成规则结构而是根据任务自适应调整每个卷积核的稀疏模式或者和注意力机制结合在风车状卷积之后加一个轻量的通道注意力器强调高响应通道。这些方向并不需要重新发明框架在现有 PyTorch 代码上都能做增量修改。我在这个项目里最大的一点体会是模型改进不一定要靠复杂模块的堆叠很多时候把卷积核的几何结构做一番设计也能带来意外的效果提升。特别是红外小目标这种信号极弱的场景结构先验比增加参数量更靠谱。如果你也在做相关的工作建议先拿一个小数据集跑通 PConv 的替换流程确认涨点之后再迁移到完整数据集。这样能省下大量训错方向的成本也能更直观地感受风车状卷积带来的变化。