首页 / 资讯中心 / 文章详情

基于P2层与HSFF融合的YOLOv26超小目标检测改进

基于P2层与HSFF融合的YOLOv26超小目标检测改进 ★ FEATURED ARTICLE
1. 为什么超小目标需要单独的P2层1.1 小目标在特征金字塔里的困境做目标检测的人应该都体会过那种感觉一个目标明明就在图像里肉眼看得清清楚楚模型就是检测不到。尤其是无人机视角下的人、遥感图像里的车辆、工厂产线上的细小划痕这些目标往往只有十几个像素甚至几个像素。它们有一个共同的称呼——超小目标通常指绝对尺寸小于等于16x16像素、在特征图中仅占1到2个格子的目标。为什么这么难核心原因在于特征金字塔本身的工作原理。以YOLOv26这种典型的卷积检测器为例输入一张640x640的图像主干网络会不断下采样生成多尺度的特征层stride为8、16、32的P3、P4、P5。常规检测头只在这三个尺度上做预测。问题是一个16x16像素的超小目标映射到stride为8的P3特征图上只剩下2x2个像素点映射到P5上直接就不到1个像素了。目标的空间信息在逐层卷积和池化中被稀释边界和纹理细节早已丢失你让检测头从一堆语义模糊的像素里找回这个目标基本等于大海捞针。更麻烦的是特征金字塔自上而下的融合路径是单向的语义传导。P5的语义信息会传到P4、P3但P3自身分辨率不够高P2——即stride为4的高分辨率特征层——根本没有被利用起来。这个层在传统设计里被视为噪声之源分辨率高、计算量大、语义信息弱加入后容易产生大量误检。所以很多YOLO系列的默认配置都把它砍掉了。但对于超小目标检测这个特定场景P2恰恰是空间信息最完整的层砍掉它等于丢掉了一张最重要的底牌。1.2 YOLOv26基线方案的两处短板我对YOLOv26基线做了完整的实验摸底发现它在超小目标上表现不佳问题集中在两个方面。第一个短板是感受野与目标尺度严重不匹配。YOLOv26的CSP结构在深层有较大的感受野适合捕捉中大型目标的全局语义但超小目标根本用不了那么大的感受野。一个8x8像素的缺陷区域在深层特征图里对应的感受野可能涵盖了图像的大部分区域大量无关背景特征参与了分类判断目标本身的特征占比极低。简单说就是看得越广越看不清小东西。第二个短板是正样本分配机制对超小目标不友好。基于中心距离和IoU的标签分配策略在小目标场景下会导致正样本数量极少。一个目标在P3层只有2x2个格子bias和anchor的匹配概率天然很低训练时正样本稀疏梯度信号微弱模型很难学到有效的特征响应。我做了一组统计在一个无人机视角的数据集上基线中参与训练的超小目标正样本数量仅为中大型目标的十分之一左右这种样本不均衡直接拉低了小目标的AP值。1.3 四尺度与融合这条改进路线的总体思路我这次做的改进方向很明确把特征金字塔从三尺度扩展到四尺度增加P2超小目标检测层同时引入高分辨率特征融合机制解决P2层语义信息不足的先天缺陷。用一句话概括就是——P2管空间细节高层特征管语义信息两者融合后一起喂给检测头。为什么强调双重而不是单独加一个P2层因为我在调研中发现很多人在YOLO系列上强加P2层效果并不理想。单独引入P2会导致两个问题一是浅层特征包含大量边缘、纹理等底层信息缺少物体类别的语义判别能力误检率飙升二是P2特征图尺寸大参与训练后计算量和显存占用显著增加训练时间成倍拉长。如果不做融合优化P2层带来的噪声抵消了它带来的分辨率增益最终mAP甚至可能不升反降。所以完整方案需要两条腿走路第一构建P2-P5四尺度特征金字塔让超小目标有更高的空间分辨率可用第二设计一个轻量级的高分辨率特征融合模块把深层语义信息注入P2层提升它对目标类别的判别能力。这个模块在YOLOv26整体架构里相当于一个语义增强器让浅层特征既有细节又有语义是整条改进链路里最关键的一块拼图。在动手之前我也明确了一下这套方案适用的场景无人机航拍、遥感图像、工业表面缺陷检测、医学影像中的小病灶识别总之就是目标尺寸普遍较小、对漏检率要求高的任务。普通日常场景下的目标检测没必要上这套毕竟成本摆在那里后面我会把代价和收益的权衡讲清楚。2. 方案设计四尺度特征金字塔与高分辨率语义融合2.1 P2层从哪来Backbone路径的取舍搭建四尺度特征金字塔首先要回答一个问题P2层从哪里取特征这个问题看似简单实际上决定了后续所有融合路径的走向。在YOLOv26的Backbone里网络对输入图像连续进行多个阶段的卷积和下采样每个阶段输出的特征图尺寸依次减半。我选取了stage2的输出作为P2的来源这一层特征图尺寸恰好是输入图像的1/4也就是stride4。举例来说640x640的输入对应的P2特征图大小为160x160。和我上面提到的P380x80相比它在每个维度的分辨率直接翻倍总像素数量是P3的四倍超小目标在这层特征图上能保留更完整的轮廓信息。为什么不选更浅的stage1输出也就是stride2虽然它的分辨率更高但语义信息过于原始几乎就是边缘和颜色块而且通道数太少直接做检测头输入会导致模型的判别能力严重不足。经过实际测试从stage2引出P2兼顾了分辨率和基本的语义抽象是最平衡的选择。我自己也试过直接从stage1引特征做融合训练时loss收敛很慢验证集上的误检框大幅增加最终放弃。确定P2的来源之后特征金字塔就变成了四层stride4、8、16、32的P2、P3、P4、P5。其中P3、P4、P5沿用YOLOv26原有的FPN路径自上而下的特征传递链路扩展为P5到P2的完整路径。这里有一个关键决策新增的P2检测层是独立分支原有P3到P5的检测头全部保留不做任何替换。这样做的最大好处是兼容预训练权重原有的三层检测能力不会被破坏模型可以从一个稳定的起点开始增量学习。2.2 HSFF高分辨率特征融合模块拆解有了P2层还远远不够接下来要面对的是它语义弱、噪声多的先天问题。我设计了一个轻量级的高分辨率特征融合模块命名为HSFF全称是High-resolution Semantic-aware Feature Fusion。HSFF做的事情可以拆成三个步骤通道对齐、跨尺度融合、注意力增强。通道对齐的目的是把不同尺度的特征拉到同一个维度。P2特征图的通道数通常是128或256而P5深层特征的通道数可能是512甚至1024直接用这些特征做融合计算量是灾难性的。我在每个输入分支前面加了一个1x1卷积把P3、P4、P5的特征通道统一降到一个较小的值比如128。这样后续融合操作的计算成本可控不会因为多路特征叠加把算力拖垮。跨尺度融合是整个模块的核心。高层特征需要上采样到与P2相同的分辨率然后与P2特征加权融合。这里我用的是类似加权双向特征金字塔的快速归一化方式每个输入分支学习一个可训练的标量权重归一化后进行加权求和。为什么不用简单相加因为不同尺度的特征重要性不同在超小目标场景下空间细节的权重应该大于语义信息但具体比例应该让网络自己学而不是人为设定一个固定值。训练完成后我发现学到的高层语义权重占比大约在0.2到0.3之间低于P2特征的权重这和我的预判一致。注意力增强放在融合之后。我选用了一个轻量的空间注意力模块对融合后的特征图做响应增强让模型更关注目标可能存在的区域。为了避免额外参数过多我用了基于全局平均池化和最大池化的经典结构只在关键位置配置少量卷积整个HSFF模块的参数量控制在几百万以内对整体模型的参数量影响很小。值得强调的是P5特征上采样到P2分辨率会带来可观的显存开销所以我在HSFF内部放弃了传统的最近邻上采样改用双线性插值并且在特征降维之后再上采样。先降维再上采样的顺序可以避免在高分辨率上处理高通道数特征这一步能省下大约三分之一的相关显存占用。2.3 标签分配与损失函数的配套调整一个容易被忽视的问题是仅仅在模型结构里加入P2层训练逻辑如果不跟着改效果会大打折扣。P2层的特征图分辨率高每个目标在特征图上占据的格子更多但原有的标签分配方法还是按P3的尺度逻辑来匹配这会浪费掉P2层丰富的正样本信息。我做的第一个调整是扩大每个目标的正样本匹配范围。YOLOv26原有的标签分配策略倾向于围绕目标中心选取若干个格子作为正样本这个数量对中大型目标足够对超小目标不够。我把top-k的候选数量从默认值往上调了大约三分之一同时放宽了中心距离的约束阈值。这样一来一个在P2层上占据4x4格子的超小目标能匹配到的正样本数量从原来的一两个增加到四到六个训练信号显著增强。这个改动在验证集上带来的AP_small提升非常明显是我整个实验中最奏效的单一改动之一。第二个调整是损失函数。常规的IoU损失在小目标上有一个致命缺陷当预测框与真实框只有几个像素的偏移时IoU可能骤降到接近0梯度变得极不稳定。我引入了归一化高斯距离NWD损失来替代一部分IoU损失把边界框建模为二维高斯分布用Wasserstein距离衡量两个分布之间的差异。NWD对微小目标的位置偏差更敏感但梯度曲线更平滑不会像IoU那样一跌到底。实际操作中我没有完全替换CIoU而是把两者按权重加权CIoU保留对边界框尺寸的约束能力NWD负责小目标的定位稳定性。标签分配和损失函数的调整是配合结构改进的最后一公里。结构和损失都改完之后整套方案才算真正闭环。3. 代码落地配置改动与关键实现3.1 模型配置文件改造示例YOLO系列检测器的模型定义通常使用YAML配置文件YOLOv26也不例外。当我准备加入P2层时第一件事就是修改配置文件中关于特征层和检测头的定义。最核心的改动有两处一是指定P2层的来源Backbone节点二是增加stride为4的检测头输出。这里给出一个简化版的配置示意读者可以对照自己使用的具体框架进行调整# 原基线三尺度 # stride: [8, 16, 32] # channels: [256, 512, 1024] # 改进后四尺度 stride: [4, 8, 16, 32] channels: [128, 256, 512, 1024] backbone: p2_from: stage2 # stride4高分辨率浅层特征 p3_from: stage3 p4_from: stage4 p5_from: stage5 head: num_detectors: 4 feat_dims: [128, 256, 512, 1024] fpn: enable_p2: true fusion_module: HSFF hsff_in_channels: [128, 256, 512, 1024] hsff_out_channels: 128需要注意的一个细节stride列表的顺序必须和特征图的尺度顺序完全一致检测头会按照这个顺序把预测结果映射回输入图像。一旦顺序写错推理时的框位置会全部错位这类错误在工程调试中很折磨人我建议改完配置后先跑一张单图的前向推断检查特征图尺寸。还有一个容易被忽略的点预训练权重。当新增P2检测头后模型输出的通道数变了原有检测头的权重形状不匹配如果你直接加载预训练权重会因为通道数不一致而报错或者被随机初始化。我采用的做法是手动加载Backbone部分的权重只对新增加的P2检测头和HSFF模块做随机初始化其他部分保持预训练状态。这样模型既获得了预训练特征的先验知识又不会因为结构变动而崩溃。3.2 HSFF模块的PyTorch实现要点下面这个代码片段是我实际项目中的HSFF模块的简化版本省去了很多和具体训练框架耦合的部分保留了核心逻辑方便读者理解整个数据流import torch import torch.nn as nn import torch.nn.functional as F class Conv(nn.Module): def __init__(self, in_c, out_c, k1, s1): super().__init__() self.conv nn.Conv2d(in_c, out_c, k, s, k // 2) self.bn nn.BatchNorm2d(out_c) self.act nn.SiLU() def forward(self, x): return self.act(self.bn(self.conv(x))) class SpatialAttn(nn.Module): def __init__(self): super().__init__() self.conv nn.Conv2d(2, 1, kernel_size7, padding3) self.sigmoid nn.Sigmoid() def forward(self, x): avg x.mean(dim1, keepdimTrue) mx x.max(dim1, keepdimTrue).values attn torch.cat([avg, mx], dim1) attn self.sigmoid(self.conv(attn)) return x * attn class HSFF(nn.Module): def __init__(self, c2128, c3256, c51024, out128): super().__init__() self.proj2 Conv(c2, out) self.proj3 Conv(c3, out) self.proj5 Conv(c5, out) # 可学习的融合权重初始为等权 self.w nn.Parameter(torch.ones(3, 1, 1, 1)) self.attn SpatialAttn() self.out_conv Conv(out, out, k3) def forward(self, p2, p3, p5): p2 self.proj2(p2) p3 self.proj3(p3) p5 F.interpolate(self.proj5(p5), sizep2.shape[-2:], modebilinear, align_cornersFalse) w self.w / (self.w.sum() 1e-5) fused w[0] * p2 w[1] * p3 w[2] * p5 fused self.attn(fused) return self.out_conv(fused)几个实现层面的注意点。融合权重初始化为什么全部设为1而不是随机数因为训练初期模型还没有稳定的特征表示如果权重随机且差异过大融合输出会被某个分支主导P2层的梯度信号会被压缩。等权初始化配合分母求和做归一化可以保证训练初期各分支贡献一致模型逐步学习到合理的权重比例。residual连接我刻意在示例中省略了。实际项目中我在模块的末尾保留了输入特征与融合输出之间的残差连接fused p2 self.out_conv(fused)。原因是P2层的原始空间细节经过多层卷积和注意力之后仍有可能丢失残差连接相当于一条高速公路让浅层细节直达检测头。这个设计在验证集上带来了一定提升而且几乎不增加额外参数属于性价比很高的操作。BN层的初始化也很关键。我建议对HSFF内部所有的BN层gamma参数初始化为1但对融合输出端的BN初始化为0。这样模块在训练初始阶段相当于一个恒等映射不会因为新增模块的随机初始化而剧烈扰动原有的特征分布训练稳定性会好很多这个技巧在迁移学习场景下尤其有效。3.3 训练策略冻结、渐进式与混合精度P2层加入之后我面临的第一个实际问题是模型该怎么训练按照以往的经验直接全量微调容易出问题尤其是新增模块的随机初始化权重会在前几个epoch产生较大的梯度震荡。我采用的策略是分两阶段训练。第一阶段冻结原有Backbone和P3-P5三个已有检测头的参数只训练新增的P2检测头、HSFF模块以及相关的特征融合路径大约跑30个epoch。冻结操作让新模块只能在原有特征的基础上做适配不能反向修改主干网络的参数从根本上限制了训练初期的破坏性。30个epoch之后新模块基本具备稳定的特征表达能力这时再解冻全部参数进行全量微调大约200到300个epoch。这种两阶段策略在收敛速度和最终精度上都有明显优势。直接全量训练P2增强模型时前50个epoch的loss波动较大收敛到最优解需要更长时间而两阶段训练的前期loss曲线平滑得多最终的AP_small约高出1到1.5个点。训练过程中我还启用了混合精度训练AMP。P2层的特征图尺寸大前向计算的内存开销本来就高用FP16计算可以在显存占用上省出约30%的空间。不过AMP在小目标检测上有一个隐藏风险超小目标的梯度值通常很小FP16的表示范围有限可能出现梯度下溢导致极小目标的空间位置学习不到。我的解决方案是在损失后乘上一个放大系数或者对梯度的裁剪阈值做调整这些都可以在框架里通过配置实现。如果发现小目标的AP没有随训练轮次上升优先检查这一步。4. 实验验证消融结果与效率分析4.1 评价指标与实验数据我做实验使用的数据集是一个无人机航拍视角的小目标检测数据集图像分辨率集中在800到1200像素区间目标类别包含车辆、行人、船只等。这个数据集的特点是目标整体偏小绝大多数目标的绝对尺寸在8到32像素之间正好覆盖超小目标的核心区间。评价指标上我没有只看mAP还额外关注了几个专用于小目标的指标AP_small小目标的平均精度、AR100和AR300不同候选框数量下的平均召回率。在超小目标检测任务中召回率往往比精度更值得关注因为很多应用场景宁可有误检也不希望漏检关键目标。所以我在实验记录里会同时保留这些指标而不是在一个mAP数字上做简单结论。所有实验都在同一台设备上完成为了控制变量我固定了训练轮次、优化器配置和数据增强策略每个模型做三次平均避免单次训练随机性影响结论。4.2 消融实验与结果解读我做了三组对比实验基线模型、基线加P2层、基线加P2层再加HSFF融合模块。关键结果如下配置P2层HSFFmAP0.5mAP0.5:0.95AP_smallAR100参数量计算量(GFLOPs)基线无无42.324.112.851.226.8M82.4P2有无45.126.716.259.728.2M96.7P2HSFF有有46.927.917.663.428.9M99.8从数据里可以读出几个非常有意思的结论。单独加入P2层对AP_small的提升非常显著从12.8直接涨到16.2AR100也涨了8.5个点这说明超小目标确实从高分辨率特征层中获得了巨大的空间信息收益。但细节隐藏在mAP0.5和AP_small之间的差距里整体mAP的涨幅远不如AP_small明显说明P2层在改善小目标的同时也引入了一些噪声拖累了一部分中大型目标的检测表现。加入HSFF之后AP_small又从16.2涨到17.6mAP0.5也涨了约1.8个点但更重要的是误检率有了明显下降。我在验证集上统计了平均每张图像的误检框数量单独加P2时比基线增加了将近一倍经过HSFF融合后回落到比基线略高的水平。这说明HSFF的主要贡献不是看得见小目标而是知道什么才是小目标。融合进来的语义信息帮助浅层特征区分了真实目标和背景噪声这正是设计时预期的效果。4.3 计算代价与性能权衡结构改进不可能只涨精度不涨成本关键是搞清楚成本花在哪里、值不值。从上表的GFLOPs可以看出单独加P2层增加了约14.3的算力开销这个占比约17%主要来自160x160特征图上的检测头计算。HSFF模块本身增加的算力并不大约3个GFLOPs可以说是一个非常轻量的组件。但实际运行时的显存开销比FLOPs显示得更严峻。P2特征图在训练时需要保存足够的梯度信息160x160的分辨率意味着与前层特征相比其激活值存储量大幅上升。我测试的结果是基线模型在batch size为16时显存占用约11GB加上P2层后约14GB再叠加HSFF后约14.5GB。也就是说P2层是显存增长的主要来源HSFF的边际成本很小。推理速度的变化也需要注意。在同样的输入分辨率下基线单张推理约14毫秒加入P2和HSFF后约18到19毫秒延迟增加接近30%。如果项目对实时性要求苛刻这个代价需要仔细权衡。我的建议是如果你的输入分辨率可以从640提升到960或更高P2层的分辨率优势会被部分抵消此时可以先用高分辨率输入加三尺度基线测试如果AP_small已经满足需求就不一定需要上P2。在算力资源有限的情况下增大输入分辨率往往比增加P2层性价比更高。5. 常见问题与排查记录5.1 P2层训练不稳定与NaN处理P2层训练不稳定的情况我遇到过非常多次最典型的就是训练过程中loss突然变成NaN。前几次遇到这个问题我一度以为是学习率设置过大调低之后发现依旧会出现后来逐步排查才定位到几个真正的原因。第一个原因是融合权重分母计算问题。在HSFF模块中融合权重需要通过除以其和来归一化如果训练初期权重出现极端值极端情况下分母会接近0导致梯度过大。我的解决方法是在分母上加了一个极小值1e-5做兜底同时将权重初始化限制在一个合理的区间内避免极端情况。第二个原因是BN在P2层上的统计不稳定高分辨率特征图上的batch统计波动比低分辨率层更剧烈。我采用了先冻结BN统计量预热若干轮之后再恢复统计更新的策略配合BN gamma初始化为0的做法NaN问题基本绝迹。还有一个容易踩的坑是混合精度训练下的低精度梯度。超小目标的损失贡献在整个batch中占比很小在FP16下很容易被下溢为0表现在训练曲线上就是AP_small长时间不动。如果你开了AMP且发现小目标指标不涨第一步不是改结构而是关掉AMP跑一次对比试验排除精度下溢的干扰。5.2 显存不足与训练时间过长P2层带来的显存压力是所有使用者都绕不开的问题。我第一次跑完整配置时batch size设为16输入分辨率960显存直接爆掉被迫逐步降低batch size才算跑起来。这里分享几个我实测有效的降显存手段。梯度检查点是最直接的手段之一把P2层相关的计算量大的模块标记为需要重算前向传播时不保存这部分激活值反向传播时再重新计算一次。这个方案能省下不少显存代价是训练时间增加大约10%到15%。另外可以对P2检测输入的特征通道做裁剪毕竟P2层主要提供空间位置信息通道数不需要像深层特征那么宽我把P2相关路径的通道数从256降到128显存节省明显AP_small几乎没有损失。训练时间方面P2层前向和反向的计算开销都不小同样的epoch数量下训练时长比基线增加三成以上。如果只是想验证方案可行性我的建议是先用小输入尺度比如512或640做一个短周期的训练确认指标趋势正确后再切到目标分辨率做完整训练。这种先小后大的验证策略能省下大量排队等GPU的时间。5.3 小目标漏检不降反升的诊断流程这个情况在论坛上经常被问到明明加了P2层小目标效果为什么反而变差我自己也经历过在这里梳理一个排查顺序希望对大家有帮助。第一步查标签分配。先确认小目标在所有尺度上的正样本是否真的增多了如果只是加了P2层而标签分配逻辑没有改动新增的正样本几乎没有P2层的收益自然体现不出来。第二步查NMS配置。P2层输出的框数量远多于三尺度版本默认的NMS阈值可能过于激进大量小目标置信度稍低的框被抑制掉了。先降低conf_thres观察召回率是否回升再决定是否调整NMS的IoU阈值。第三步查数据增强。如果启用了高概率的马赛克增强超小目标被切割成更小的碎片P2层也弥补不了信息丢失。这一步排查往往能解释为什么验证集不如预期。排查的原则很简单先确认模型有没有可能学到再确认预测出来了但被后续处理丢掉最后再确认数据本身有没有提供足够的样本。按这个顺序走下来大多数问题都能定位到具体的环节而不是盲目调参。6. 一些个人经验和建议整套方案从设计到落地我个人的最大体会是P2层不是面向所有任务的神器它是针对特定问题的精准工具。如果你的数据集目标尺寸普遍在30像素以上加P2层纯粹是增加计算量收益非常有限但如果你面对的是无人机视角、遥感图斑、工业微缺陷这类目标普遍在10到20像素的任务P2层的空间分辨率优势是其他优化手段难以替代的。给打算复现这套方案的朋友一个建议不要一上来就全套加上先跑通P2加标签分配的改动确认AP_small的提升在预期范围再用HSFF去消除噪声。分步验证的好处是每一步的收益和代价都清晰可见不会在混合变量里迷失方向。我最初就是直接把四尺度和融合一起加上结果出了问题都说不清楚是哪个环节带来的。最后再分享一个小技巧。如果显存实在不够又不想放弃P2层的收益可以尝试只在高分辨率输入下启用P2分支推理阶段根据输入尺寸动态决定是否走P2路径。这个思路相当于把分辨率作为P2层的开关灵活性高很多。后续如果条件允许我打算在这个方向上继续探索基于尺度感知的动态路由方案争取在算力开销和精度收益之间找到更优的平衡点。
阅读完成 · 觉得有帮助?
咨询建站