ARTICLE DETAIL

资讯详情

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

轻量型目标检测算法全解析:从骨干网络到端侧部署实践

轻量型目标检测算法全解析:从骨干网络到端侧部署实践 轻量型目标检测算法这几年被行业里聊得非常多。我早期做端侧视觉项目时最先跑的模型是YOLOv2和SSD在手机上跑一帧要几百毫秒模型文件动辄几十MB后来逐步接触MobileNet系列、NanoDet、PP-PicoDet再到YOLOv5n、YOLOv8n能明显感觉到这条路在设计思路和工程落地上已经非常成熟。现在一个5MB左右的目标检测模型跑实时视频流已经不是什么新鲜事。这篇文章想把这些年“摸过”的轻量型目标检测算法做个系统梳理聊聊背后的设计逻辑、常见算法选型、训练部署流程以及我实际踩过的坑适合正在做模型选型或者准备在手机、嵌入式设备上落地检测功能的朋友参考。1. 为什么说轻量型目标检测算法是端侧项目的第一道坎1.1 端侧算力不是堆出来的“轻量型目标检测”之所以成为一门重要的研究方向根本原因在于真实世界的算力环境非常不均匀。服务器上跑一个几百MB的大模型用A100显卡当然没问题但换到手机、摄像头、无人机、门禁设备上内存和功耗都是硬约束。端侧项目面对的往往不是“准不准”这一个指标还有“跑不跑得动”“会不会发烫”“功耗能不能撑住一整天”这些更接地气的问题。我见过太多项目在前期选型时直接拿GPU服务器上的大模型做实验精度确实不错一到样机阶段就翻车。芯片厂商的SDK不支持某些算子板子内存不够模型文件塞不进固件这些都是常见事故。轻量型目标检测算法解决的就是这类问题在尽量少的参数和计算量下把目标检测这事做对。它不是把大模型“缩小一点”而是从结构设计、压缩方法到部署细节的一整套工程方法。1.2 轻量化不等于“牺牲精度”很多人一听到“轻量型算法”就下意识觉得精度一定差很多这个印象需要修正。近几年轻量型算法的精度在公共数据集上的表现已经相当能打。比如YOLOv8n这样量级的模型参数只有几百万在COCO数据集上的mAP能到37上下很多垂直场景只要数据足够好效果完全够用。更关键的是轻量化带给业务的价值不只是“跑得动”还包括更低的服务器成本、更快的响应速度以及更好的隐私保护。视频流不需要上传云端在设备本地就能完成检测这对很多行业来说是刚需。我的经验是选轻量型目标检测算法不要只盯着精度排序要先把“设备、分辨率、帧率、模型大小”这几个约束写清楚。只要约束明确很多模型其实差别不大真正决定项目成败的往往是后续的数据清洗、标注质量、训练调参和算子兼容这些内容后面会详细展开。2. 轻量型目标检测算法的四条设计主线2.1 轻量骨干网络是地基目标检测模型可以粗略拆成“骨干网络”和“检测头”两部分。骨干网络负责提取图像特征特征提得好不好直接决定检测上限。轻量型算法的第一条主线就是把骨干网络做轻。目前用得最多的思路有深度可分离卷积、通道混洗、结构重参数化以及靠神经架构搜索搜出来的高效结构。以MobileNet系列为代表核心操作是深度可分离卷积。它把标准3×3卷积拆成两步先用一个3×3卷积对每个输入通道单独做卷积再用一个1×1卷积在通道之间做线性组合。在输入通道和输出通道都是C的情况下标准3×3卷积的参数量是9×C×C而深度可分离卷积的参数量是9×CC×C当C比较大时计算量和参数大概能降到原来的九分之一左右。这样换来的代价是某些任务上精度略微下降但换到端侧设备上就是帧率几倍的提升。ShuffleNet系列走的是另一条路用分组卷积配合通道混洗让各组特征之间能够“串门”同样能有效减少计算量。EfficientNet-Lite则通过自动搜索找到兼顾精度和效率的缩放系数在移动端也经常能看到。实际选骨干网络时不必非得看懂每篇论文的细节但需要清楚一件事深度可分离卷积几乎成了轻量检测模型的默认配置如果项目里遇到一个模型计算量奇高、参数量还大大概率是因为骨干网络用到了太多普通卷积。2.2 检测头也要“减重”很多研究者在做轻量化时会把大量精力花在骨干网络上但检测头同样不能忽略。早期SSD、Faster R-CNN这类模型检测头通常是一组普通卷积堆叠通道数动辄256、512算下来占整个模型的比重不小。轻量型目标检测算法在检测头上一般做三件事缩小通道数、用深度可分离卷积替换普通卷积、从anchor-based改成anchor-free来简化回归目标。举个例子YOLOv8n的检测头就是anchor-free风格不再需要设计一堆先验框也省去了和anchor匹配相关的计算与调参。NanoDet在检测头上做了更激进的设计砍掉很多冗余分支并引入轻量化的特征金字塔结构所以模型可以做到不到1M参数还能保持不错的精度。这里我的经验是检测头越小训练时需要花更多时间让特征对齐但换来的是部署时非常舒服的模型体积和推理速度。2.3 训练后的压缩手段结构上的轻量化是“天生瘦”训练后的压缩则是“后天减脂”。常见手段有三板斧剪枝、量化、知识蒸馏。剪枝是去掉权重里贡献比较小的一部分。非结构化剪枝会得到稀疏的网络需要特殊库和硬件支持在移动端并不常见结构化剪枝直接剪掉某些输出通道或卷积核对部署框架比较友好。实操中我一般用torch_pruning这类库给模型做一个按通道的稀疏化训练再设一个保留比例剪完后微调几个epoch。需要注意剪枝不是越狠越好剪到20%可能损失很小超过50%往往要花很长时间才能把精度拉回来。量化指的是把模型权重从FP32变成INT8最关键的是减少计算和内存占用。INT8量化后模型体积能变成原来的四分之一推理速度在某些端侧芯片上能提升两到三倍。知识蒸馏则是让轻量模型去学习大模型的“软标签”用大模型作为teacher小模型作为student通常能补回不少精度。我的建议是先训练好一个大模型作为基准再用蒸馏的方式去带小模型比直接硬训一个小模型要稳定得多。2.4 自动搜索与结构重参数化近两年越来越多轻量模型开始借助神经架构搜索来自动决定网络的深度、宽度、卷积类型。EfficientNet-Lite和MobileNetV3都依赖这种思路。这类模型的内部结构看起来并不“手工”但工程效果往往比手工调出来的更好。结构重参数化则是另一种思路训练时用多分支结构部署前把多分支合并成一个普通卷积典型代表是RepVGG。目标检测模型里也能看到类似思想训练和部署用两套结构换来的是推理阶段几乎没有额外开销。不过自动搜索出来的模型虽然精度不错偶尔会碰到部署框架不支持的算子。在实际项目里我一般会优先看这个模型有没有现成的端侧部署案例算子兼容性比一点精度更影响上线进度。3. 主流轻量型目标检测算法一次盘点3.1 先分清参数量、FLOPs、MACs这三个指标盘点算法之前必须把几个容易混淆的指标说清楚。参数量指的是模型里有多少个可学习的权重单位通常是M百万或K模型文件大小主要由参数量和存储精度决定。比如一个FP32的权重每个参数要占4字节模型文件换算下来大约是“参数量×4”如果是INT8则大约是“参数量×1”。FLOPs是浮点运算次数MACs是乘加运算次数二者经常一起出现且1次MAC约等于2次FLOP。热搜里如果看到“MACs仅5MB的目标检测模型”其实这里把“计算量”和“模型文件大小”混在一起说了。MACs的单位是G、M指的是推理时要做的运算次数MB是存储体积两者没有直接换算关系。一个模型可能文件很小但计算量很大也可能文件不小但计算量并不高。看模型是否轻量两个指标都要看。3.2 经典组合SSD MobileNetSSD-MobileNet是很多端侧项目的启蒙模型。它用MobileNet作骨干在多个尺度的特征图上直接预测边界框和类别。相比Faster R-CNNSSD没有RPN阶段结构简单、计算量低在2017年前后几乎是移动端检测的默认选项。这套组合现在依然有意义一是历史代码存量很大很多老设备上的工程都是基于它改的二是因为训练和部署资料非常全。缺点也很明显backbone和检测头都是浅层设计对遮挡严重、目标密集的场景表现一般。如果你今天从零开始一个新项目我不会首推它但理解SSD的多尺度特征图预测逻辑对理解后来的YOLO系列很有帮助。3.3 YOLO轻量版从YOLOv5n到YOLOv8nYOLO系列是目标检测领域绕不开的名字。YOLOv5n和YOLOv5s是较早一批把轻量化和生态做好的模型尤其是YOLOv5n参数量约1.9M、模型文件3.8MB左右一度是中低端设备上最稳妥的选择。YOLOv6n、YOLOv7-tiny也都是同一思路只是不同公司或作者维护。YOLOv8n是我最近用得更多的模型参数量约3.2M输入640分辨率时FLOPs约8.7G精度相比YOLOv5n有明显提升。它自带很完整的训练框架和导出工具链从数据标注到ONNX导出再到TensorRT、NCNN部署整个流程很顺。YOLOX-Nano则是在anchor-free这条路上的一家代表参数约0.9M设计上更强调工业部署的简洁性适合对模型大小极其敏感的项目。这类轻量YOLO模型的标准用法是用公开权重做迁移学习在自己的数据集上微调一般不推荐从头训练。3.4 专门为移动端设计的NanoDet和PP-PicoDet除了YOLO系还有一批从设计之初就面向移动端的检测框架。NanoDet系列由开源社区推动主打“小到极致”。NanoDet-Plus在不到1M参数的情况下精度能接近早期的YOLOv5s部署代码也很干净很适合MCU级别的设备研究。PP-PicoDet是百度飞桨推出的轻量型目标检测模型它在移动端优化上做得非常细除了使用深度可分离卷积还引入了更强的数据增强策略、更好的标签分配和蒸馏方案。PP-PicoDet的模型体积和FLOPs控制得都很低在ARM CPU上的帧率表现通常不错这也是我近几年在端侧项目中最常推荐给团队测试的模型之一。需要注意的是PicoDet的官方仓库基于PaddleDetection如果你想用PyTorch复现社区版本很多需要自己甄别实现是否严格对齐原始配置文件。3.5 轻量型目标检测算法对比表下面这张表格是我根据公开项目里常看到的数据整理的不同实现、不同输入分辨率会有差异选型时建议以项目官方README为准。模型参数量FLOPs640输入附近模型大小参考适合场景SSD-MobileNetV2约6M视检测头配置约1G左右约14MB老项目迁移入门教学YOLOv5n约1.9M约4.5G约4MB通用轻量端侧检测YOLOX-Nano约0.91M约1.1G约2MB对体积极度敏感的设备YOLOv8n约3.2M约8.7G约6MB精度和生态兼顾NanoDet-Plus约0.9M约1G级别约2MB移动端、低功耗设备PP-PicoDet-S约1.2M约1G级别约5MBARM CPU、端侧摄像头从这张表能看出模型大小和FLOPs没有必然正比关系。有些模型文件很小但推理运算量并不一定最低因为文件大小还受存储格式影响。选型时不要只看单一指标最好拿同一个部署环境跑一遍用帧率和实际精度说话。4. 从零训练一个轻量检测模型完整实操流程4.1 环境准备与数据集组织实操部分我用YOLOv8n做例子因为它的工具链最完整适合大多数人快速上手。先准备Python环境建议Python 3.8到3.11之间安装ultralyticspip install ultralytics然后在本地准备好数据集。这里以一个简单的安全帽检测项目为例数据集按如下目录组织datasets/myhelmet/ ├── images/ │ ├── train/ │ └── val/ └── labels/ ├── train/ └── val/标签文件是YOLO格式的txt每行代表一个目标类别id 归一化中心x 归一化中心y 归一化宽 归一化高。如果你手头只有VOC或者COCO格式的数据可以用ultralytics内置的转换脚本也可以自己写脚本转一下。数据做好后创建一个YAML文件path: datasets/myhelmet train: images/train val: images/val names: 0: helmet 1: person4.2 第一次训练参数怎么调才不踩坑轻量型模型训练在小数据集上很容易过拟合所以我的习惯是先用公开权重做微调而不是从头训练。执行下面这条命令yolo detect train datamyhelmet.yaml modelyolov8n.pt epochs100 imgsz640 batch16 device0几个关键参数需要解释。imgsz控制输入分辨率默认640但如果目标普遍偏小可以适当提升到960或1280代价是训练和推理变慢。batch受显存限制如果显存不够可以先降batch同时可以考虑开启混合精度训练。epochs不要一上来就设个500先用100个epoch看收敛趋势再决定是否加长。训练时我会额外关心两类日志一是loss曲线二是验证集上的PR曲线。如果loss持续下降但mAP不动大概率是数据标注问题或类别不均衡如果loss下降很慢可以试试把学习率调到0.001或者0.01。轻量模型尤其容易出现“瓶颈在网络结构容量而不是训练程度”的情况这时再堆epoch也意义不大。训练结束后别急着用last.pt最好使用best.pt它是根据验证集mAP自动挑选出来的最优权重。4.3 模型导出与剪枝量化训练完成后把PyTorch模型导出成ONNX方便后续部署yolo export modelruns/detect/train/weights/best.pt formatonnx opset12 simplifyTrue如果是要部署到移动端常用NCNN或MNN。以NCNN为例拿到ONNX后执行onnx2ncnn helmet.onnx helmet.param helmet.bin ncnnoptimize helmet.param helmet.bin helmet.opt.param helmet.opt.bin 1这里能看出模型在PyTorch里表现很好只是第一步很多算子转换后才暴露出兼容性问题。如果某个算子不支持需要回到模型结构里替换成更基本的卷积、激活函数组合。量化可以在这条链路里做一般用PTQ训练后量化就够了。用一部分验证图片作为校准集工具会统计每个激活值的分布再决定INT8的量化参数。量化后一定要在目标硬件上重新跑一遍精度测试不能只看文件变小了就宣布胜利。剪枝我一般放在量化之前先剪枝微调再量化否则精确度损失容易叠加。4.4 部署到边缘设备并验证帧率部署到边缘设备时有两个指标必须实测单帧推理时间和峰值内存。只凭开发者电脑上的测速没有任何参考价值因为不同芯片的算子库差异巨大。比如同一个模型在带GPU的Jetson上表现不错到纯ARM CPU上可能慢得离谱原因可能是模型里某些算子对内存访问不友好或者卷积实现没有针对芯片优化。我习惯在真机上写一个简单的循环测试连续跑100帧取平均时间再统计模型加载后的内存占用。如果某一块算子明显耗时可以用NCNN的profiling工具定位也可以考虑把输入分辨率降一档看看。这里切忌为一个模型反复调优而不回到业务目标如果产品本身只需要5帧每秒那就画一条“帧率与精度”的取舍线超过需求的部分没必要硬扛。5. 真实项目里最容易踩的坑及排查思路5.1 小目标检测效果差轻量型模型为了速度往往会把输入图像缩小到320或416这样一来小目标在特征图上只剩下几个像素漏检很正常。解决思路有几个。第一适当提高输入分辨率从416提升到640通常能立刻看到小目标召回率上升。第二训练时使用多尺度训练让模型适应不同尺寸的目标。第三如果设备性能允许使用“切图”策略把大图切成几块分别检测再合并结果。我做一个鸟群监测项目时用YOLOv8n在640分辨率下小目标漏检很严重后来改成1280分辨率训练模型FLOPs直接翻倍但精度明显提升。注意轻量模型在大分辨率输入下帧率下降幅度往往比大模型更明显因为高分辨率下的特征图计算量也上来了。所以最好先量一下自己场景里的目标尺寸分布再决定要不要为小目标牺牲速度。5.2 训练精度不高但模型又小轻量模型参数少理论上更容易过拟合但实际中经常出现的是另一个问题模型容量不够训练集精度已经很高验证集上不去。遇到这种情况我建议先检查训练数据是不是有“信息泄露”或者类别不均衡。比如安全帽数据集里绝大多数图片只有一种角度模型没有见过别的角度哪怕换大模型也未必能解决。数据增强对轻量模型尤其重要。ultralytics默认会有马赛克增强对小数据集很有帮助。如果试了增强还很差可以尝试用知识蒸馏。用一个大一些的模型作为teacher把中间特征或输出分布一起约束轻量模型往往能把mAP提升3到5个点。这里的“大模型”不一定要很大YOLOv8m就够用了。5.3 模型转换后算子不支持或精度掉点模型在PyTorch里跑得好导出ONNX后推理结果完全不对或者出现NaN是部署常见的头疼问题。最常见的原因有ONNX版本和部署框架版本不匹配、某些动态尺寸没有固定、归一化方式不一样。我的习惯是导出ONNX后在本地先用onnxruntime跑一遍对比PyTorch输出确认无误后再做下一步。量化后精度掉点也很常见尤其是小目标。如果校准集选得不好或者模型里有些层对量化特别敏感损失会更明显。我的排查思路是“二分定位”逐个尝试跳过某些层的量化找到掉点最严重的层手动保持FP32或改用16位浮点。有些框架也支持混合量化允许一部分层INT8、一部分层FP16这样能换来精度和速度的平衡。5.4 模型体积与推理速度的误区前面提到过“模型大小5MB”和“推理快”并不是同一件事。一个模型可能权重文件很小但里面每层计算量都很大原因是参数量少但输入尺寸大反之一个模型参数很多但经过深度可分离卷积设计速度可能比参数少的还快。所以我在团队里定了规矩评估轻量模型时至少列出参数量、FLOPs、内存占用、实测帧率四个指标缺一不可。部署端还有一个很容易忽略的点模型加载时间和预热。有些模型在真机上第一次推理特别慢因为算子库在初始化时做了很多内存分配。测试时必须跑足够多次拿到稳定后的平均值不能直接把第一次推理的时间当作性能结论。6. 关于轻量型目标检测我最后想说的几句6.1 新手怎么选型如果你刚接触轻量型目标检测我的建议是先别急着研究所有算法找一个生态完整的库把流程跑通一遍。YOLOv8n是一个非常好的起点文档全、坑少训练导出部署一整套路径都通。跑通之后再换到PP-PicoDet或者NanoDet体会不同设计带来的差异这时你对“轻量化”的感受会具体很多。选型时把四个问题写清楚设备CPU还是GPU、内存上限多少、目标帧率多少、检测的最小目标大概多大。答案一旦确定很多泛泛而谈的模型对比其实可以直接跳过。6.2 我踩过几次坑之后的体会我曾经花了一周时间试图把一个模型剪枝到极致最后文件是小了但推理速度几乎没有提升原因在于剪枝后产生了很多不规则稀疏算子在目标芯片上支持并不好。后来我改成了整通道剪枝配合微调和量化效果才明显改善。做轻量化不要只盯着“剪多少”要看“在目标部署环境里能省多少”。另外轻量模型最终是给业务用的不是用来刷指标的。我见过团队为了追求mAP涨零点几把模型输入分辨率从416提到1280结果设备端帧率掉了四倍客户上线首发当天就崩了。根据我个人经验最稳的路径是先锁定部署设备和使用场景再反推模型选型和训练策略。轻量型目标检测算法更新很快但想让它真正服务业务还是离不开从数据、训练、压缩到部署的完整闭环。这套功夫没有捷径但只要认真走一遍后面的项目会越做越顺。
返回列表