十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

航拍小目标检测:YOLOv8配合热力图嵌入与蛇形卷积的实践

航拍小目标检测:YOLOv8配合热力图嵌入与蛇形卷积的实践 最近在做一个无人机航拍场景的小目标检测项目场景其实很朴素3000x3000的大图里车辆和行人往往只占十几个到几十个像素。YOLOv8跑起来以后漏检率高得吓人那种只有10像素左右的小目标置信度永远卡在0.3上下加了再多的数据增强也救不回来。后来我把CenterNet那套热力图位置感知的思路和一种方向自适应的蛇形卷积采样方式同时塞进检测头里mAP才实打实地涨了一截。这篇文章把完整的技术方案、模块设计逻辑、训练调参细节以及我在实际迭代里踩过的坑都写出来给同样在做小目标检测的朋友一个可以直接参照的工程样本。这个方案比较适合航拍遥感、无人机视角、工业质检、医学影像中带有小目标或细长目标特征的场景。不同数据集的涨点幅度会有波动但核心设计思路是可以复用的。1. 先搞清楚小目标检测卡住的三个物理瓶颈1.1 多少像素算小背后的定义陷阱MS COCO里定义小目标是面积小于32x32像素的目标但这个定义放到实际项目里经常引发误判。我做航拍数据时一辆车在3000x3000的大图中往往只有15x35像素按COCO标准算小目标但同一辆车如果裁切到640x640的小图上就能占到32x64像素不再算小。问题在于很多检测模型在训练时会把整张大图缩放到固定尺寸缩放之后原本就小的目标变得更小信息几乎被压没了。所以与其纠结定义不如先看你输入网络的图像尺寸和目标实际像素数的比例关系。一般来说目标短边小于输入尺寸的5%时就是典型的强小目标场景需要专门设计。1.2 特征稀缺与语义被平均掉的原理小目标在特征图上的响应非常弱。以YOLOv8的backbone为例输入640x640的图像经过5次下采样后P5层特征图只有20x20。一个原本10x10像素的行人在P5层可能只占据不到1个像素点即使到了P3层80x80也只有4x4个像素左右。问题是CNN里每个特征点都对应原图的一个局部区域感受野小目标占的区域里有大量背景像素卷积核在提取特征时会把前景和背景的信息混合在一起。打个比方你想在一张满是噪点的照片里找一根头发丝模型看到的却是头发丝周围大量灰白噪点的平均值这个平均结果很容易被背景主导响应自然弱下去。这就是为什么很多模型在训练初期小目标的loss一直降不下去——不是拟合能力不够而是网络从特征图里得到的正样本信号本身就弱。1.3 定位精度要求与被放大的回归误差小目标的定位问题更苛刻。大目标即使预测框偏移二三十个像素IoU依然可能很高但一个10x10的小目标预测框只要偏移3个像素IoU就可能掉到0.5以下直接变成负样本。换句话说小目标对边界框回归的精度要求是像素级的但特征图下采样倍率决定了网络天然存在量化误差。YOLOv8在80x80的P3层做预测时每个特征点对应的原图步长是8像素这意味着仅靠P3层的离散化误差就有8像素。用这样的输出去贴合一个10x10的目标难度和用粗笔芯画一条细线差不多。热力图位置嵌入的价值恰恰体现在这里——把连续的空间位置信息以监督信号的形式注入到网络里而不是只依赖离散的边界框回归。2. 热力图位置嵌入给检测头一份补救空间先验的思路2.1 从CenterNet借来的启示热力图为什么比直接回归中心点更稳CenterNet那套方法我很早就接触过它不预测anchor框而是直接预测每个目标中心点的高斯热力图峰值位置就是目标中心。当时没细想直到这次做小目标才发现热力图有个天然优势它把目标中心在哪这个问题从回归任务变成了分割/分类任务。对于10x10的小目标直接在特征图上回归中心点坐标误差稍微一抖就可能偏移好几个像素但如果生成一个以真值中心为核心、标准差为几个像素的高斯热力图网络要做的只是在80x80的特征图上尽量逼近这个小山包。这个任务的收敛难度显著更低因为相邻位置之间有连续梯度网络知道离中心越近分数越高这种软标签缓解了小目标正样本过少的问题。我用一个具体数字说明在P3层80x80上一个10x10像素的小目标如果采用标准的中心点宽高回归方式正样本可能只有目标中心附近的1到2个锚点而采用高斯热力图后以目标中心为均值、半径约3像素的高斯核会覆盖周围约30个特征点正样本量直接扩大一个量级。训练时的梯度信号充足模型就能更快学会这里有个东西。2.2 位置嵌入的具体实现不是把热力图拼到特征图上就完事很多人以为热力图位置嵌入就是把热力图通道拼接到特征图后面我一开始也这么试过效果有提升但有限。后来我把方案改成了坐标调制的方式效果才明显起来。具体做法是生成一个与P3层分辨率一致的高斯热力图每个目标的中心点生成一个2D高斯峰背景区域为0将热力图通过一个1x1卷积压缩到与特征图通道数一致的维度得到位置权重图将权重图与特征图逐通道相乘再加上特征图本身形成残差式的位置增强。这样做的好处是网络可以自己学习热力图的哪些区域值得信任而不是由我硬性决定热力图通道应该被怎么解读。相乘操作相当于给特征图的每个位置乘上一个空间注意力权重中心区域权重高背景区域权重低小目标的特征响应被突出背景干扰被压低。# 伪代码热力图位置嵌入模块 class HeatmapEmbed(nn.Module): def __init__(self, in_channels): super().__init__() self.conv1 nn.Conv2d(1, in_channels, 1) self.sigmoid nn.Sigmoid() def forward(self, x, heatmap): # x: [B, C, H, W] # heatmap: [B, 1, H, W] weight self.sigmoid(self.conv1(heatmap)) return x * weight x这个模块的参数量非常小只增加了一个1x1卷积可以插入到检测头的任意位置几乎不带来推理延迟。2.3 为什么选择嵌入而不是额外分支我最初也试过把热力图分支作为独立的辅助监督只在训练时计算loss推理时丢弃。这种做法能让训练更稳定但对推理阶段的预测没有任何帮助。后来我改成训练时和推理时都使用热力图的嵌入方案前提是推理时能实时生成假的预测热力图。这里需要澄清一个重要设计在推理阶段模型没有真值热力图于是我让模型的主干在forward过程中额外输出一个预测热力图分支这个分支在训练时用高斯真值监督在推理时直接输出预测结果。也就是说热力图不是外部输入而是模型自己预测出来的内部表征然后通过HeatmapEmbed模块嵌入到检测特征中。这样既保持了训练和推理的一致性又让模型具备了先找热点位置、再细看特征的能力本质上是给检测头增加了一个显式的空间位置注意力通道。3. 线性蛇形卷积为细长小目标设计的采样方式3.1 标准3x3卷积在细小目标上的失效模式在航拍场景里很多目标不是简单的小方块比如桥梁、道路、电线、长条形车辆。标准3x3卷积的采样区域是方方正正的对于细长结构大部分采样点落在目标外真正有效的采样位置可能只有2到3个。这导致卷积输出里的目标信号和背景信号严重混叠。可变形卷积DCN理论上能解决这个问题它通过额外分支预测每个采样点的偏移量让卷积核自由变形。但DCN在小目标上有两个问题一是偏移量分支本身的训练不稳定小目标特征弱偏移量很容易被预测成随机方向二是DCN的自由度过高对细长目标来说偏移后的采样点可能会扭曲成无规律的形状反而丢失线性结构。我需要的是一种既具备DCN的自适应能力、又能约束采样点沿某个连续方向排列的卷积方式。3.2 蛇形路径采样的核心思想先走一条线再沿着线取点线性蛇形卷积的思路可以拆成两步第一步预测一组方向偏移量确定一条经过目标区域的蛇形路径第二步沿着这条路径顺序采样用一维卷积的方式聚合路径上的特征。具体实现上我参考了血管分割任务里的一些做法把采样点组织成一条首尾相接的折线。对于每个中心位置首先生成N个初始采样点这些点均匀分布在一个局部邻域内然后通过一个轻量级的offset预测网络迭代地调整每个采样点的位置调整过程中加上一个平滑约束即相邻采样点之间的偏移量不能突变过大这就让采样点序列具备线性连续性。对于小目标检测场景我把蛇形路径设计成局部扫描线以当前特征点为中心先在地平面方向上预测一条主方向线然后在这条主方向线的两侧各取若干采样点。这样既能覆盖细长的小目标又不会像DCN那样把采样点散得到处都是。# 伪代码线性蛇形卷积采样 def snake_conv(feature, offset, kernel_size5): # feature: [B, C, H, W] # offset: [B, 2*N, H, W]预测的N个采样点偏移量 # 先在中心点周围生成初始一维采样网格 base_grid make_line_kernel(kernel_size) # 一维线性排列 # 叠加预测偏移量 sample_grid base_grid offset # 双线性采样并卷积 sampled bilinear_sample(feature, sample_grid) return conv1d_feature(sampled)3.3 平滑约束与offset预测网络的轻量化设计offset预测网络不能太重否则参数量涨得没法看。我用的是一个3x3卷积两个1x1卷积的组合输入是当前特征层的特征输出是N个采样点的x、y偏移量通道数为2N。为了让偏移量具备平滑性我在loss里加了相邻offset之间的差分惩罚L_offset mean(|offset[:, i, :, :] - offset[:, i-1, :, :]|)这个约束非常关键没有它蛇形卷积很容易退化成DCN采样点杂乱无章。我测试过不加平滑约束的版本训练到后期offset的方差会变得很大部分采样点直接飞到目标外部精度不升反降。加了约束后offset逐渐收敛成相对一致的线性方向对小目标的细长结构拟合得明显更好。4. 把两个模块塞进YOLOv8整体结构设计与参数量控制4.1 颈部与检测头的轻量化改造在YOLOv8的基础上我没有改动backbone和颈部的主体结构因为YOLOv8本身已经足够成熟改动主结构容易引入回归问题。我只做了两处修改一是在检测头之前增加一个低维的语义分支专门输出预测热力图二是在P3层80x80的检测头前插入线性蛇形卷积模块。P3层是小目标的主要预测层P4、P5层保持原样这样能控制计算量。改造后的完整流程输入图像经过backbone提取多尺度特征P3层特征进入热力图预测分支输出与P3等分辨率的热力图热力图通过HeatmapEmbed模块嵌入P3特征得到位置增强后的特征增强后的特征经过线性蛇形卷积模块提取细长结构信息送入YOLOv8的检测头完成分类和回归。4.2 热力图位置嵌入模块的插入位置我试过把HeatmapEmbed插在backbone输出后和检测头前两种方式的差异是插在backbone输出后热力图能影响整个颈部多尺度特征的融合但计算开销稍大插在检测头前影响范围更聚焦于最终预测开销更小。最终我选择了后者因为P4、P5层的目标尺寸更大对热力图嵌入的需求不迫切只在P3层做增强就能解决小目标的主要矛盾。还有一个小细节热力图分支的预测也需要梯度回传所以它的loss不能省。我按0.5的权重加入总loss让模型在训练早期就学会哪里有小目标。4.3 线性蛇形卷积的替换位置与参数量对比原始YOLOv8的P3检测头前是一个标准3x3卷积层负责特征变换。我把这个3x3卷积保留在线性蛇形卷积后额外接了一个1x1卷积做通道融合。线性蛇形卷积的N设为7个采样点参数量大约等于两个3x3卷积的量级对整模型的影响很小。我统计过改造前后模型的参数量和GFLOPs变化原始YOLOv8s大约11.2M参数、28.6GFLOPs加入热力嵌入蛇形卷积后参数约增加到12.8MGFLOPs约31.4。参数量增加约14%推理速度在A30上从大约3.2ms降到3.6ms这个损耗相对来说是值得的因为整体mAP提升了3-5个点。5. 训练配置、损失权重与收敛经验5.1 数据增强策略对小目标的作用与限度小目标检测里很多人第一反应是堆数据增强尤其是马赛克增强和随机裁剪。但我在这个项目里发现对小目标而言增强是把双刃剑。Mosaic增强用四张图拼接的方式增加数据多样性但拼接时小目标会被进一步缩小且容易和背景混在一起导致模型学到的是缩小遮挡的伪样本。我最后用了如下策略保留Mosaic但把随机缩放的边界从0.5改为0.8避免把小目标压到5像素以下增加Copy-Paste增强的比例把小目标从原图中抠出来随机粘贴到大图的多个位置相当于扩充小目标的数量关闭随机擦除Random Erase因为它很容易直接抹掉小目标导致标注和图像不匹配。5.2 损失项让热力图分支真正起作用实验中发现如果热力图分支的loss权重过大模型会把精力都放在预测热力图上导致分类分支的训练不足权重过小热力图分支学不出来位置嵌入模块就形同虚设。我最后采用了分阶段调整策略前20个epoch热力图loss权重设为1.0让分支快速收敛到可以使用的水平20到50个epoch权重降到0.5让检测主任务开始主导训练50个epoch之后权重固定在0.3只做微调。最终训练曲线显示热力图分支在15个epoch左右就能达到较高的精度之后对主任务的提升逐步稳定。5.3 调参实测batch、学习率和EMA的影响我在这个项目里的base lr设为0.001batch size为64使用AdamW优化器。换成SGD后收敛速度明显变慢尤其热力图分支在SGD下20个epoch时还处于不稳定的状态。EMA我仍然保留但把衰减系数从默认的0.9999调到0.999因为小目标检测的场景里目标数量多且分布复杂EMA窗口太长反而会让权重的变化跟不上数据分布的变化。更微妙的一点是学习率warmup。原始YOLOv8默认有3个epoch的warmup但在这个方案里热力图分支是一个新增的、随机初始化的分支如果warmup太短它会在训练初期产生很大的梯度噪声干扰已经预训练好的主干特征。我把warmup延长到8个epoch并让热力图分支在warmup阶段单独使用较高的学习率主干的5倍这样分支能快速站稳脚跟又不牵动主干。6. 对比实验与踩坑记录6.1 三个关键对比结果我选了一组1500张无人机航拍车辆数据集做对比实验测试集500张目标平均大小为18x22像素。消融结果如下配置mAP0.5mAP0.5:0.95参数增减原始YOLOv8s71.236.8基准热力图位置嵌入73.839.10.9M线性蛇形卷积72.938.40.7M两者同时加入75.641.21.6M单独加线性蛇形卷积的涨幅不如热力图位置嵌入说明这个数据集上模型的首要矛盾是小目标位置响应弱而不是细长结构特征提取不足。两者结合时能互补因为热力图先让模型大致知道目标在哪里蛇形卷积再在局部区域更精准地提取方向特征。6.2 踩坑一热力图分辨率与下采样倍率的矛盾最初我把热力图分支放在P2层160x160上生成因为分辨率越高小目标的位置定位越精细。但P2层的计算开销非常大而且YOLOv8没有原生的P2检测层需要额外上采样特征导致训练显存直接不够用。后来我把热力图降到P3层生成位置精度有所损失但通过把高斯核的标准差适当调大从2到3让热力图覆盖范围更广反而让模型学到了更稳定的位置分布。算力受限的情况下不一定要追求最高分辨率的热力图通过调节高斯核尺度也可以达到类似效果。6.3 踩坑二线性蛇形卷积offset不收敛第一次跑线性蛇形卷积时offset分支的输出没有任何约束结果训到第10个epoch看到训练集上一部分BBox的置信度只有0.1。排查后发现问题出在offset的初始化上。我把offset层的最终输出初始化成0也就是初始状态下等价于一个标准的1D卷积核然后再让它在训练过程中逐渐学习偏移。简单加了一行零初始化offset就正常收敛了。更麻烦的问题是offset的数值范围不可控有时会偏移出特征图边界。我在输出端加了一个tanh激活函数把偏移量限制在[-1, 1]再乘以一个缩放系数默认0.5确保采样点不会跑到有效区域之外。6.4 踩坑三热力嵌入与NMS的交互位置嵌入增强了中心区域的响应模型的置信度整体升高这让NMS阈值需要重新调整。原始YOLOv8用NMS IoU阈值0.7加了热力嵌入后同一个目标会同时出现多个高分预测框密集排列且置信度都在0.8以上0.7的IoU阈值压不住。我最后把NMS的IoU阈值降到0.6同时引入了soft-NMS策略以置信度为中心的衰减方式保留最强的预测框。这一步让mAP0.5:0.95又涨了大概0.8个百分点。最后再分享一个经验在真实落地时不能只看mAP一个指标。我用这个方案在嵌入式设备上做过压测热力图嵌入的1x1卷积几乎不耗时但线性蛇形卷积的双线性采样在有些显卡上会触发额外的内存读写开销。如果部署环境对延迟特别敏感建议把蛇形卷积放在仅P3层或者直接用NVIDIA TensorRT的plugin自定义算子否则双线性采样的循环部分会成为新的瓶颈。别看这只是一次具体的项目实践其中的设计思路——把空间先验和方向先验分别以热力图和蛇形偏移的形式补充给检测头——即使换到其他数据上也值得先跑一轮消融再决定去留。
返回列表