尧图网络 高端网站定制 · 原创设计
免费咨询热线
400-888-6620
免费获取方案
货架空置检测实战:FCOS_HRNetV2P调优与部署全记录
1. 为什么货架空置检测我选FCOS_HRNetV2P而不是YOLO做零售数字化项目的人应该都有同感门店里真正让运营头疼的往往不是大促时的爆单而是货架悄悄空了没人发现。货架空置状态检测这个任务说白了就是让摄像头代替理货员的眼睛自动找出货架上哪些位置出现了空档然后触发补货提醒。我在这类场景里先后试过好几个主流检测方案最后真正落地的是基于FCOS_HRNetV2P的高精度检测算法。这篇文章就把整个项目的技术思路、训练细节和踩坑经历完整记录下来给正在做同类型感知业务的人一个可以直接参考的样本。先说结论这个任务选型阶段最大的坑是容易被YOLO系列跑得快带偏。我最初也用YOLOv8做过一轮实验速度和部署都很舒服但货架空置这个目标有一个天然特点——它不是完整物体而是物体之间的缺失区域——导致框的长宽比极度不稳定小目标占比又高YOLO的anchor设计在这种目标上非常吃力。FCOS以逐像素方式直接回归目标框天然规避了anchor形状匹配的问题配上HRNetV2P这种能保留高分辨率细节的骨干网络之后细小的缝隙、阴影边缘、层板交界处的空档都能被稳定感知到。1.1 货架空置到底该怎么定义缝隙检测的场景特殊性很多第一次接触这个需求的人会问货架空置不就是该有商品的地方没有商品吗直接检测商品不就行了这个思路听起来对实际操作会发现非常难收敛。超市货架上的商品种类成千上万包装颜色千差万别想要训练一个能识别这里缺了什么的模型等于让模型先做货架实景分割、再和标准陈列图做差异比对数据成本和推理复杂度都翻了几倍。我采用的路线是把空置缝隙本身当作检测目标。也就是说标注员框出来的不是一个商品而是货架层板上那块明显的空缺区域——它的左右是商品上下是层板边缘或者背板中间是暴露出来的空隙。这样做最大的好处是把任务从理解货架内容降维成寻找连续空白区域类内一致性高得多模型需要学习的信息量也小得多。这个目标有两个视觉上的关键特征。第一是边缘结构复杂缝隙两侧通常是瓶罐、包装盒的不规则边缘而不是平滑的几何边界这对特征金字塔的浅层细节要求很高。第二是尺度分布极广有的空置缝隙是整层货架全空动辄占几百个像素有的只是两瓶饮料之间被拿走的那个坑可能只有三十几个像素宽这两个极端都出现在同一张图里。FCOS的FPN多尺度输出配合逐像素预测对这种尺度跨度大的目标有天然的适应能力。1.2 FCOS的anchor-free机制为什么贴合这个场景FCOS的全称是Fully Convolutional One-Stage Object Detection核心思路是放弃anchor对特征图上的每个位置直接回归该位置到目标框四条边的距离同时预测类别得分和一个centerness分数。这个机制放到货架空置检测里有几个别人不一定能立刻体会到的优势。一是无需调anchor参数。货架缝隙的长宽比完全取决于商品摆放方式。竖放的瓶装饮料之间形成的缝隙可能是1:6的细长条而层板上被清空的区域可能又是接近1:1.2的方框。用anchor-based方法得先统计数据里的长宽比分布再设计一组合适的先验框这组参数换一个门店品类分布就会失效。FCOS不做这个事每个像素直接学习离四条边的距离目标多窄多扁都能回退到统一范式里。二是正样本丰富。FCOS把所有落在目标框内部的像素都算作正样本候选再结合center sampling做取舍不像anchor方法只有少量与GT框IoU达标的预设框才参与训练。货架缝隙这类目标边缘信息强、中心语义弱像素级的稠密监督正好能把这些边缘特征充分利用起来模型收敛速度明显更快。1.3 HRNetV2P给检测头供了什么样的特征骨干网络这块标准FCOS通常配ResNet50或者ResNet101但在我这个项目里效果不够理想。原因在于货架场景里存在大量低对比度目标白色层板与白色墙面的缝隙、透明玻璃瓶之间的空隙、灯光直射下的浅色包装之间的空档。这些目标需要的是高分辨率的空间细节而不是靠深层语义来分辨。ResNet系列的串行下采样结构到P5层时小目标的边缘信息已经损失得很厉害。HRNetV2P走的是另一条路。它从头到尾维护一条高分辨率分支同时并行加入中分辨率、低分辨率分支各分支之间反复交换信息全程不丢失细粒度空间特征。V2P这个后缀代表的是它在最后会输出多分辨率的金字塔特征对应四个分支最后一层正好可以直接喂给FPN做后续融合。实测下来在只换backbone不动其他配置的情况下小尺寸缝隙的召回率就从61%左右提了接近7个百分点这个提升幅度在检测项目里算是相当可观的。1.4 三个候选方案的对比表格选型阶段我认真对比了三个方案做成表格给团队评审这里也放出来供参考方案小目标/细长目标能力训练速度部署体积实测结论YOLOv8中受anchor形状限制明显快轻量常规目标好货架空置这种非刚性目标精度不够Faster R-CNN ResNet50中上但两阶段开销大慢较重精度有保障但性价比低边缘设备跑不动FCOS HRNetV2P强逐像素回归对形状无偏好中中等本次选定方案精度/速度平衡最好这里多说一句我并不是否定YOLO系列它在通用目标检测领域完全够用只是货架空置这个细分场景真的不对它的胃口。如果你手头的场景是检测人、车、商品这类边界清晰的目标YOLO依然是首选。2. 数据准备空置缝隙标注的边界约定与采集坑模型选型做得再漂亮数据质量不行也是白搭。货架空置检测的数据准备阶段我踩过不少坑最大的感受是这个项目的成败有一半以上在标注规则里就决定了。下面把实操层面的关键点展开说。2.1 采集设备和角度如何影响最终效果数据采集这一步设备不需要太高端普通枪机摄像头或者分辨率不低于1080p的安防相机就够了。真正影响效果的是安装角度。货架层板会产生强烈的透视遮挡如果相机位置过低、几乎平视货架下层货架的空隙会被上层层板挡住大半标注和检测都会很难受。我最终定的方案是相机安装高度在货架正前方2.2米左右轻微俯视15到30度保证每层货架在画面里有一个清晰的开口视角。另一个容易忽略的问题是光照。超市的照明一般在白天比较稳定但夜间的应急照明模式、灯管老化导致的频闪、甚至货架顶部的广告灯箱都会让同一位置的空隙在不同时段呈现出完全不同的明暗关系。我的建议是数据采集至少覆盖三个时段早班补货前、午间客流高峰后、晚班闭店前。闭店后的数据尤其重要因为那段时间货架空置率最高恰好是算法最需要发威的时刻。2.2 标注规则一个空置框哪里开始哪里结束标注这块我最早直接拿标注工具让人凭感觉框结果同一张图三个人能框出三个完全不同的位置。后来写了一份标注规范核心就三条垂直方向以层板边缘为上下边界如果缝隙被层板阴影遮挡了一部分则以可见部分为准不脑补遮挡区域。水平方向以左右相邻商品的最外边缘为边界商品本身不能被框进目标内但允许与目标框有1到2像素的交叠。单个空置缝隙的宽度小于15像素时放弃标注因为这类目标在检测下采样后已经不可分辨标了只会增加低质量正样本。数据集规模方面我总共标注了约4200张图片其中包含空置缝隙的图像大概2900张其余是完全没有空隙的干净货架负样本这部分非常关键它们负责压制误检。标注格式直接用COCO的JSON格式空置这一类定义为一个类别empty_gap。类别名无所谓关键是框的边界必须统一。2.3 负样本与增强策略负样本为什么重要用数字说话门店日常运营中80%以上的货架处于基本满货状态空置缝隙是小概率事件。如果训练集里全是正样本模型学到的先验就是看到货架就输出框误检率会高到完全没法用。负样本的来源主要有三类。一类是完全满货的整洁货架这类数据用来教会模型没有缝隙时闭嘴。第二类是带干扰物的场景比如顾客的手在货架前拿商品、购物车停在货架旁边、员工在补货时身体挡住层板这些场景如果不进训练集模型上线后会把人体轮廓、购物车边框当空隙报。第三类是暗光条件下的正常货架因为层板阴影本身就容易形成假缝隙。增强策略上我不仅用了常规的随机翻转、随机缩放和多尺度训练还专门加了几组针对货架结构的增强。一个是随机改变亮度和对比度模拟不同灯管照度另一个是随机遮挡模拟商品被顾客手部或价签遮挡时缝隙不完整的情况。马赛克增强我没怎么用因为货架场景本身结构规整拼接后会产生大量跨货架的伪边界反而干扰模型学习层板结构。3. 模型搭建与训练配置拆解数据准备妥当之后就是模型搭建和训练。这个部分我直接用MMDetection这套开源检测工具箱来做因为它对FCOS和HRNetV2P都有现成的高质量实现不用自己造轮子。整个训练工程的核心是搭好配置文件下面把关键部分拆开讲。3.1 基于MMDetection的模型配置细节模型定义这块backbone选用HRNetV2P-W32neck用FPNhead用FCOSHead。之所以选W32而不是更大的W48是因为货架检测最终要跑到边缘端侧设备上W48带来的精度提升大约只有1个点左右但显存占用和推理延迟都明显上涨不划算。model dict( typeFCOS, backbonedict( typeHRNet, extradict( stage1dict( num_modules1, num_branches1, blockBOTTLENECK, num_blocks(4,), num_channels(64,)), stage2dict( num_modules1, num_branches2, blockBASIC, num_blocks(4, 4), num_channels(32, 64)), stage3dict( num_modules4, num_branches3, blockBASIC, num_blocks(4, 4, 4), num_channels(32, 64, 128)), stage4dict( num_modules3, num_branches4, blockBASIC, num_blocks(4, 4, 4, 4), num_channels(32, 64, 128, 256))), pretrainedhrnetv2p_w32_imagenet_pretrained.pth), neckdict( typeFPN, in_channels[32, 64, 128, 256], out_channels256, num_outs5), bbox_headdict( typeFCOSHead, num_classes1, in_channels256, stacked_convs4, feat_channels256, strides[8, 16, 32, 64, 128], loss_clsdict( typeFocalLoss, use_sigmoidTrue, loss_weight1.0), loss_bboxdict(typeGIoULoss, loss_weight1.0), loss_centernessdict( typeCrossEntropyLoss, use_sigmoidTrue, loss_weight1.0)))这里有个容易被忽略的细节HRNet的FPN输入通道数必须按照四个分支的通道数写也就是[32, 64, 128, 256]而不是ResNet系列的[256, 512, 1024, 2048]。我在第一次搭配置时惯性思维写错了In-Channels结果训练loss一直不降排查了半天才发现是这里的问题。特征金字塔的五个输出层默认对应下采样倍数8到128倍基本覆盖了货架缝隙从30像素到600像素的尺度范围。3.2 训练参数与资源训练参数我用了相对稳健的一组配置这批参数在同类单类目标检测任务上表现都比较稳定可以作为起步值参数设置说明输入尺寸1333×800多尺度训练区间为短边640到1024长边按比例缩放优化器SGDlr0.01momentum0.9weight_decay0.0001batch size164卡×4单卡batch过小会导致BN统计量不稳定总epoch36使用了2x训练计划学习率调整第24、32个epoch衰减10倍warmup前500步正样本分配center_samplingTrueradius1.5只取目标中心附近像素做正样本训练全部跑完大概耗时一天半用的四块消费级显卡。Loss从初始的2.1左右下降到0.3附近就不再明显下降了这时候看验证集mAP已经达到71.8%。需要说明的是mAP这个数字在不同的数据划分下会有浮动我这里用的是我自己划分的验证集主要价值在于横向对比不同配置的优劣。3.3 训练曲线和踩坑记录训练过程中的两个现象值得记录一下。第一个是类别数只有1的时候Focal Loss的类别不平衡特性反而成了一个干扰源在训练早期loss下降非常快但GIoU Loss下降明显滞后。这是因为单类检测里每个像素的分类任务过于简单分类loss很快就饱和了模型的优化重心需要靠调整loss权重来向回归任务倾斜。我把loss_cls的权重从1.0降到0.75回归loss和centerness保持不变最终的框定位精度提升了一个多百分点。第二个坑是数据加载阶段的预算。HRNet骨干网络参数量不大但特征交互的显存开销比ResNet高不少如果把batch size和输入分辨率同时拉满很容易爆显存。我的做法是先固定输入分辨率再往下调batch size直到显存占用稳定在预留余量的70%左右。千万别一上来就追求大batch训练中OOM中断的挫败感会严重影响项目节奏。4. 实测调优把mAP从61%拉到72%的几个关键改动模型能从65%左右的初始版本一路调到72%靠的并不是什么花哨的网络结构改造而是一系列针对货架空置这个特殊目标的调优细节。这些改动单独看都不大但叠加起来效果非常明显。4.1 细长目标与centerness的矛盾FCOS的centerness分支输出的是每个像素作为目标中心的程度原文设计里最终置信度分数等于分类分数和centerness分数的乘积。这个设计对常规目标没什么问题但货架缝隙的很多实例是极细长的高度只有20像素宽度却有150像素。这类目标的中心区域在整个框里占比太小centerness的标签值下降非常快模型学出来的centerness响应会整体偏低导致大量原本中心对齐良好的细长缝隙框被压低分数而漏检。解决思路是在推理阶段削弱centerness对最终分数的压制把最终分数从cls_score * centerness改成cls_score * sqrt(centerness)。这是一个只有几行代码的改动但细长目标的召回率在验证集上提高了3个点。如果你用的是MMDetection的现成推理流程需要改一下FCOSHead中get_bboxes函数关于score的计算部分。4.2 特征层的选择与输入分辨率前面提到FPN默认输出5个尺度特征下采样8、16、32、64、128倍。货架里的小缝隙在1080p原始图上大约是30到50像素见方落到下采样32倍的特征层上只剩下1个多像素几乎不可能检测出来。我把输入分辨率从1333×800提升到1600×1000同时给FPN多加了一层stride4的P2特征输出小目标检测能力立刻见效。代价是训练时间增加了约25%但这个代价换来了4个点的mAP提升完全值得。这里有个务实建议不要只看mAP高不高要看不同尺寸区间上的AP。货架空置检测里小于32×32像素的目标占比接近40%这些目标的AP才是决定业务体验的北极星指标解决了它们mAP的上升只是副产品。4.3 误检来源暗影、玻璃反光、购物车如果把模型的输出可视化到门店实时画面上误检的来源非常有规律。排前三位的分别是层板暗影、玻璃柜门反光、购物车轮廓。层板暗影这类误检本质上是数据问题你在采集数据时避开正午强光时段多收夜景暗光样本就能明显改善。购物车误检比较有意思。购物车的铁丝网格结构会产生大量密集的横向和纵向边缘和层板上商品间空隙的低级特征很相似。我的处理方式是在训练负样本里专门增加一个子类别的数据横向摆放的、空置的、满载的购物车各来一批并配合随机旋转增强。模型很快就学会了购物车的网状结构不是货架空置这个误检源的占比直接下降了80%。说到底误检问题的本质是训练分布和真实分布不匹配更多数据比调参有效得多。5. 把模型接到真实货架推理后处理与部署模型训练完项目其实才走完一半。货架空置检测要真正在门店里跑起来还要解决推理后处理和部署落地这一大堆工程问题。这一节完全是我在项目实际落地中摸出来的经验文档里基本不会写。5.1 单帧检测为何不能直接当告警刚开始上线的时候我对检测结果的处理非常简单每帧画面跑一次模型只要有置信度大于0.5的空置框就立刻发补货告警。结果上线第一天就被运营同事冲了。原因很简单摄像头存在轻微抖动光线变化会引起画面噪点波动同一个缝隙可能这一帧检出来了下一帧又没了。更麻烦的是顾客的手在货架前停留两秒模型把胳膊和肩膀当成空隙报了三次警。正确的做法是在时间维度上做确认。我对同一个货架分区维护一个检测框队列只有连续N帧检测到与既有框IoU超过0.5的空置区域并且该区域在最近一段时间内没有被补货动作覆盖才真正触发告警。实际工程里N设成5帧比较合适配合15fps左右的拉流帧率意味着一个候选空置区域需要连续出现约1/3秒才会确认误报率能降低一个数量级。def confirm_gap(history, current_box, iou_thresh0.5, min_hits5): matched False for record in history: if compute_iou(record.box, current_box) iou_thresh: record.hits 1 record.box current_box matched True break if not matched: history.append(TrackBox(current_box, hits1)) return [r for r in history if r.hits min_hits]5.2 ONNX、TensorRT的导出与量化PyTorch模型直接部署到门店的工控机或者边缘盒子上速度是不达标的。我实测过一个HRNetV2P-W32的模型输入1600×1000的单帧推理延迟在普通CPU机器上要800毫秒以上GPU机器上也要150毫秒左右远远达不到实时监测的要求。我的导出路径是先转成ONNX中间格式再做TensorRT的FP16推理。ONNX导出时一定要固定输入尺寸虽然动态尺寸更灵活但TensorRT对动态尺寸的优化会差很多。我用1600×1000作为固定尺寸导出再转成TensorRT引擎在边缘盒子上的单帧延迟降到了35毫秒左右稳定跑30fps没有任何压力。推理方式延迟(ms)说明PyTorch GPU推理150未做任何优化ONNX Runtime GPU72框架级优化TensorRT FP1635精度几乎没有损失5.3 业务指标映射从检测框到货架编号模型输出的是像素坐标系里的检测框但门店运营关心的是第几号货架第几层缺货了。这一步需要在部署时做坐标映射。最省事的方案是提前人工标定每个货架的感兴趣区域ROI在图像上画好多边形区域每个区域对应一个货架编号和层号。推理的时候把检测框中心点拿来做点在多边形内的判断落在哪个ROI就能定位到具体的货架位置。如果你有门店的平面图也可以通过货架排布计算透视变换把每一个检测框的中心点投影到平面图上。从操作成本来看直接在画面上画前后期ROI最高效支持新开门店时整个映射配置在半小时内完成。这部分在技术含量上不高但直接被运营同事使用的就是这些结果值得认真打磨。6. 一些没有写进代码的体会最后说点偏经验和感受层面的东西不一定每个技术方案都适用但大概率能帮你少走弯路。第一个体会是像货架空置这样的细分场景模型结构成熟度远远大于创新空间真正的瓶颈在数据分布和标注质量。我前前后后换过不少训练策略但从61%到72%的mAP提升里有接近一半来自更合理的数据采集和标注规则而不是模型改动。想到这一点之后我在项目初期就把大量精力放在规范和流程上后程才变得顺遂。第二个体会是单帧检测在真实业务里毫无价值时序上下文才是降误报的关键。最开始报告审阅我用的是采帧模式被各种瞬间误检折磨得不行。后来改成连续视频流确认、再加上补货动作的消隐期之后整个告警通道的可用性才真正达到运营侧接纳的水平。第三个体会是小技巧层面的如果你手头的门店场景里包含大量开架冷柜记得在训练集里混入一批玻璃门起雾、有水汽的样本不然玻璃反光造成的误检会让你排查一个礼拜都找不到原因。这个项目的基础功能上线后我还在往两个方向扩展一个是把空置缝隙钻进一个补货优先级的业务规则里按空置面积、历史销量和库存天数做加权排序另一个是尝试用视频时序信息替代单帧检测让模型直接学习商品被拿走这个动作模式。老实说单帧检测下一步的成长空间已经比较有限动态语义理解才是更值得投入的方向。如果你正在做类似项目希望这篇记录能给你省下几晚上的调试时间。
RELATED

相关推荐

机器学习分类任务全流程指南:从数据准备到模型评估

机器学习分类任务全流程指南:从数据准备到模型评估

拿到“第五章:如何处理分类任务(预习)”这个标题,我第一反应是:这不就是大多数人在机器学习入门阶段都会卡住的那一章吗?前面还在学回归、学损失函数、学梯度下降,突然进入分类任务,…

📅 2026/10/18 18:03:55
C#彻底删除PDF数字签名:字段、外观与残留清理全攻略

C#彻底删除PDF数字签名:字段、外观与残留清理全攻略

收到需求“用 C# 删除 PDF 里的数字签名”,大部分人以为这是件小事,打开文件、删个字段、保存,三行代码搞定。实际上我第一次接到类似需求就栽了跟头:用 RemoveField 删掉字段后,页面上的签名图片还赖着不走&#xff1…

📅 2026/10/18 18:03:55
R语言提取GEO数据全流程:从getGEO下载到探针注释与差异分析

R语言提取GEO数据全流程:从getGEO下载到探针注释与差异分析

简介:GEO数据库是全球规模最大的公共基因表达数据仓库,R语言GEOquery包是获取这些数据的标准工具。然而,直接调用getGEO常因网络超时、平台注释差异或探针ID映射问题而失败。理解GEO数据的GSE、GDS与GPL结构,掌握超时设置与缓存机…

📅 2026/10/18 18:03:55
MORE NEWS

更多资讯

📰

STM32步进电机T型加速实战:从丢步到平稳启停的代码解析

简介:这份资源面向嵌入式开发初学者与电机控制方向的工程师,提供在STM32平台上实现步进电机T型加速算法的完整项目代码。T型加速将运动过程划分为匀加速、匀速与匀减速三个阶段,轨迹呈等腰梯形,可有效降低启停冲击与振动&#xff…

📰

FPGA图像直方图均衡化:从算法原理到Verilog工程落地的完整攻略

简介:面向FPGA开发者和数字图像处理学习者的Verilog直方图均衡化实现,解决硬件平台上图像对比度调节的实时处理问题。算法围绕原始直方图计算、归一化、累积分布函数和灰度值映射四个环节展开,工程代码主要分为RGB转YUV、直方图统计、均衡化和…

📰

socket常用API函数:TCP连接生命周期与状态机实战解析

1. 这不是API列表,而是一张网络通信的“操作地图”刚入行那会儿,我翻过不下十本网络编程教材,每本都把socket()、bind()、listen()、accept()、connect()、send()、recv()这几个函数列成表格,配上参数说明和返回值定义。看得头大&…

📰

集成学习回归实战:从评估到调参的完整指南

1. 集成学习在回归场景的整体设计思路1.1 单模型容易“翻车”,问题到底出在哪先说一个我经常见到的现象:很多初学者拿着一棵决策树直接做回归,训练集上R高得离谱,一到测试集就崩。换成线性回归,预测值甚至可能出现负数…

📰

DecEx-RAG:过程监督与智能剪枝如何将多跳检索提速近6倍

1. 为什么拖着不做多跳检索:延迟痛点比想象中更致命我在做检索增强生成相关项目时,最早遇到的一个尴尬局面是:单跳问答的效果已经不错了,但业务方提的需求几乎都是多跳的——"这个产品线在华东区的季度增长率,和竞…

📰

用真实界面做30秒AI演示视频:UI保真度驱动的产品信任构建

1. 项目概述:为什么“用真实界面做30秒演示”正在成为AI视频工具的分水岭最近在帮几个做ToB SaaS产品的团队做产品演示优化,发现一个特别有意思的现象:几乎所有团队都试过用主流AI视频工具生成App功能介绍视频——输入一段文字描述&#xff0…

TODAY

今日更新

THIS WEEK

本周精选

THIS MONTH

本月热门

读完文章,想聊聊您的网站?

告诉我们您的行业与需求,资深顾问一对一梳理方案与报价,全程免费。

📞 💬