拓冰建站拓冰建站
首页 / 资讯中心 / 正文

YOLOv5实战:冬虫夏草小目标检测从训练到部署全流程

简介目标检测是计算机视觉领域的核心任务之一其本质是在图像中定位并识别感兴趣的目标。在实际工程中针对小目标、复杂背景的检测场景模型的选择与训练策略往往比网络结构本身更关键。YOLOv5作为成熟稳定的检测框架凭借其轻量级设计、灵活的配置和丰富的生态资源在诸多垂直领域中得到广泛应用。本文以冬虫夏草生长检测为实践案例系统介绍从数据集构建、标注规范、数据增强到模型训练、超参调整、权重选择再到推理优化与边缘设备部署的完整链路。通过合理调整置信度阈值、输入分辨率与锚框参数可有效提升小目标的召回率。该技术路线同样适用于农作物监测、野生资源调查、工业缺陷检测等场景为开发者提供了一套可复用的工程化解决方案。 这个项目其实挺有意思的。冬虫夏草这玩意儿跟工业质检里那些规规矩矩的螺丝钉完全不一样它长在高原草甸上背景是枯草、泥土、碎石混在一起的复杂环境子座从土里冒出来个头小、颜色跟周围环境还特别接近人眼找起来都得眯着眼睛仔细看。用YOLOv5来做单类别检测听起来不算复杂但真正跑通“数据准备→标注→训练→权重部署”这条链路里头的坑一点不少。这篇就把整个实战过程掰开揉碎从数据集怎么来、标注要注意什么到训练参数怎么调、权重文件怎么选再到推理和常见问题排查一次性讲清楚。1. 项目核心思路与方案选型1.1 为什么选YOLOv5而不是YOLOv8或者更重的框架先说结论单类别目标检测YOLOv5目前依然是性价比最高的选择没有之一。虽然YOLOv8、YOLOv9这些新版本在COCO这类通用数据集上刷榜刷得很欢但放到“冬虫夏草生长检测”这种垂直场景里YOLOv5的生态成熟度、踩坑资料数量、部署资料完整度都远超新版本。具体原因有三点。第一YOLOv5对硬件的要求足够友善。虫草检测这套任务目标是小尺寸、低对比度通常需要在实地设备上跑可能是Jetson Nano可能是RK3568也可能是工厂或者实验室里一台普通的老GPU。YOLOv5s和YOLOv5n这两个轻量级版本在GTX 1660这种入门级显卡上就能训练推理时甚至CPU都能跑只不过速度慢一些。而YOLOv8虽然也有n/s版本但很多老设备上的推理库和工具链对它的支持还没有完全跟上。第二YOLOv5的代码结构清晰配置文件简单适合做二次改动。比如后面要讲的anchor尺寸调整、数据增强策略开关都是几行配置的事。而且国内外关于YOLOv5的教程、踩坑记录、社区问答简直是海量遇到问题搜一下基本都有答案。对这类偏应用型的项目来说框架的“可救性”比“先进性”重要得多。第三YOLOv5的输出权重格式对后续部署非常友好。不管是转成onnx、TorchScript还是TensorRT都有成熟稳定的转换脚本这在后面做边缘设备部署时会省掉大量时间。单类别任务尤其适合YOLOv5还有一个隐藏优势它的Neck和Head设计本身是按通用物体检测优化的在处理单类别、小目标、复杂背景这类场景时可控的调节空间很大不需要做网络结构层面的改动只需要在数据增强、锚框、超参上做文章。1.2 单类别“生长检测”的任务定位这里需要先把“检测”和“分类”的概念理清楚。这个项目做的是“冬虫夏草生长检测”本质上是在图像中回答两个问题图中有没有冬虫夏草如果有它在哪里这类需求在实际业务中对应很多场景。比如高原产区做虫草资源的动态监测通过无人机或地面巡拍采集图像用模型自动框出每个虫草的位置统计分布密度再比如药材企业做收购分级前的初筛把大量历史照片里的虫草快速标记出来替代人工一张张翻找还有科研单位做生长周期观测通过连续图像中的虫草位置变化来分析出土时间、生长速度等指标。“1类别”意味着不需要区分虫草的种类、等级、生长阶段只要能找到“目标在哪”就行。这看起来比多类别任务简单但实际做下来会发现单类别任务的难点不在“区分度”而在“查全率”也就是漏检率。虫草的颜色和周围枯草接近早期出土的子座非常小几十像素到一百像素都很常见如果不专门优化小目标检测能力模型很容易漏掉大量真实目标。所以这个项目的数据集设计和训练策略一切都是围绕“少漏检、少误检”来做的而不是追求把某个类别的AP刷到99%。2. 数据集构建与预处理2.1 数据来源与采集策略冬虫夏草的数据集不像车牌、行人那么烂大街公开的现成数据集很少所以很大概率需要自己动手攒。根据我做类似农作物检测项目的经验数据来源可以分三条路按优先级排列。第一条路是实地采集也就是带着相机或手机到种植基地、产区草甸去拍。这是最理想的方式因为拍到的图像和实际部署场景完全一致没有域偏移问题。拍摄时要注意几个细节尽量覆盖不同时间段因为早晨和傍晚的光线角度、色温完全不一样要拍不同天气条件晴天、阴天、雨后虫草出土后带着水珠的样子和干燥时差别很大还要覆盖不同背景纯草地、碎石地、枯草密集地都要有。拍摄高度和角度也要模拟实际使用场景如果最终打算用无人机俯拍那训练数据就不要大量使用平视角度拍摄的图。第二条路是整理历史照片。很多产区的研究者、收购商手里都有大量历史照片虽然可能没有针对检测任务做过标注但作为检测任务的原始素材非常合适。我建议在动手标注之前先建一个简单的素材池把同角度、同光线、同背景的相似照片去重避免模型过拟合到重复背景。第三条路是网络公开图片。这个只能作为补充因为公开图片的版权、分辨率、拍摄角度差异太大而且能搜到的虫草特写图大多是大目标、清晰背景跟实际野外场景差距很大。如果非要用只能作为增加背景多样性的辅助不能作为主力数据。我以自己做的这套数据为例总共1080张图其中实地采集约700张历史资料整理300张网络补充80张。数量不算多但单类别检测本身数据需求就不像多类别那么高关键是质量。2.2 标注工具与YOLO格式要点标注工具我用的是LabelImg开源免费操作简单安装后直接就能用。用pip安装就行pip install labelImg然后命令行启动labelImg在工具里把图片文件夹和预定义的类别文件路径配置好类别文件就是一个txt每一行写一个类别名。单类别项目就一行dongchongxiacao标注界面里用矩形框把虫草的子座框出来。这里有个非常关键的实操经验框的范围宁小勿大。冬虫夏草的检测重点通常放在子座也就是露出地面的那一段真菌结构上不要把周围的泥土、小草、杂物包进框里。因为框得太大会让模型学到“虫草一堆背景区域一个小目标”的错误映射推理时误检率会直线上升。标注完成后LabelImg默认会生成VOC格式的XML文件需要转成YOLO格式的txt。YOLO格式的核心是每张图对应一个txt文件每一行代表一个目标格式是class_id center_x center_y width height注意这里的四个坐标值全部是归一化到0-1之间的用像素值除以图像宽高得到。举个例子一张1920x1080的图中一个目标框左上角在(500, 300)右下角在(800, 700)那么img_w, img_h 1920, 1080 x1, y1, x2, y2 500, 300, 800, 700 cx ((x1 x2) / 2) / img_w cy ((y1 y2) / 2) / img_h w (x2 - x1) / img_w h (y2 - y1) / img_h如果自己写转换脚本这段逻辑是核心。还要注意YOLO格式的txt文件名必须和图片文件名完全一致包括扩展名前面的部分且放在对应的labels目录下否则训练时数据加载会报错。2.3 数据增强策略与样本平衡数据增强对于虫草这类小目标、复杂背景的任务极其重要。YOLOv5内置了Mosaic增强、随机翻转、HSV色域增强、随机仿射变换等这些在训练时默认会启用。但对于虫草场景我建议做几个针对性调整。首先是Mosaic增强的拼图策略。Mosaic会把4张图缩放到小尺寸再拼接好处是增加了小目标的数量坏处是如果原图本身分辨率不高缩放后目标会变得更加模糊。所以我建议在数据准备阶段就不要把原图压得太小YOLOv5在训练时会把图resize到输入尺寸比如640x640如果原图本身分辨率不足目标信噪比会急剧下降。我自己的经验是原图分辨率至少保持1280以上训练时imgsz可以设成640让模型在缩放过程中学到更多细节。其次是翻转增强。YOLOv5默认的翻转参数是随机水平翻转0.5也就是一半概率左右翻转。虫草的生长方向虽然天然随机的但如果你在实际部署时对方向有明确要求比如明确要检测“从土里向上生长”的状态翻转过狠会让模型对方向不敏感。我在这个项目里把水平翻转概率降到0.25垂直翻转直接关闭因为垂直翻转会让虫草变成“倒挂”状态实际场景不会出现学了反而干扰。第三是HSV色域增强。虫草和背景的颜色差异很微妙过度调整饱和度、色相会让模型学到错误的颜色特征。YOLOv5默认的hsv_h、hsv_s、hsv_v参数是0.015、0.7、0.4对通用任务合适但对虫草这种低对比度目标我建议把hsv_s降到0.3左右把hsv_v保持0.4让模型更关注形状和纹理特征而不是死记颜色。数据集规模不够时还可以用离线增强的方式扩充样本比如旋转90度、180度、270度对虫草这种无方向性目标其实没毛病以及加入高斯噪声、轻微模糊模拟不同天气条件下拍摄的效果。但要记住一个原则增强是为了模拟真实分布不是为了编造不存在的场景。2.4 数据集目录结构标准的YOLOv5数据集目录结构如下dataset/ ├── images/ │ ├── train/ │ ├── val/ │ └── test/ ├── labels/ │ ├── train/ │ ├── val/ │ └── test/ └── dongchongxiacao.yaml其中images和labels必须严格对应train、val的比例按8:1:1或9:1来分都可以。单类别任务数据量本身不大我建议验证集比例稍微高一些比如15%这样评估指标更可信。划分的时候一定注意同一次拍摄的连续帧照片不要同时出现在训练集和验证集里不然验证集结果会虚高。我习惯按文件名前缀或目录来划分而不是随机抽这样更贴近真实场景。yaml配置文件内容大概是这样的train: dataset/images/train val: dataset/images/val test: dataset/images/test nc: 1 names: [dongchongxiacao]路径建议用相对路径这样整个项目目录拷到别的机器上不用改配置。yaml文件里的换行、空格缩进要严格按YAML语法一个空格错位都会报错。3. 环境配置与训练关键步骤3.1 YOLOv5环境安装环境安装这块网上教程五花八门我直接说一套最稳的流程。先创建Python虚拟环境推荐用condaconda create -n yolov5 python3.8 conda activate yolov5然后克隆YOLOv5仓库并安装依赖git clone https://github.com/ultralytics/yolov5.git cd yolov5 pip install -r requirements.txtrequirements.txt会装torch、torchvision、opencv-python、numpy、matplotlib等一堆依赖。需要注意这里默认装的是CPU版torch如果你有NVIDIA GPU需要先装对应CUDA版本的torch再跑requirements。建议先单独装pip install torch torchvision --index-url https://download.pytorch.org/whl/cu118再执行pip install -r requirements.txt这样能避免依赖顺序问题。装完之后先跑一个最简单的测试python detect.py --weights yolov5s.pt --source data/images/bus.jpg如果顺利输出结果图说明环境通了。如果卡在下载权重文件那一步就手动去下载yolov5s.pt放到项目根目录。权重文件名必须严格匹配大小写都不能错。3.2 数据配置文件与训练启动环境就绪后把前面准备好的dataset目录和yaml配置文件放到YOLOv5项目同级目录下。训练命令是python train.py --img 640 --batch 16 --epochs 200 --data dongchongxiacao.yaml --weights yolov5s.pt --name dongchong_test逐项解释一下--img是输入图像尺寸640是默认值如果你的显存够比如12G以上可以调成960小目标检测效果会明显提升--batch是批大小16在8G显存下是安全的如果爆显存就降到8--epochs是训练轮数单类别任务200轮完全够再多了容易过拟合--weights是预训练权重这里用yolov5s.pt如果你显存很小可以用yolov5n.pt更轻量但精度会掉一点--name是训练输出的文件夹名YOLOv5会保存到runs/train/下。训练过程中要盯几个东西。第一个是loss曲线YOLOv5的输出里box_loss、obj_loss、cls_loss三条曲线单类别任务主要关注box_loss和obj_loss。正常情况是前50轮快速下降之后缓慢收敛如果曲线一路走平或者反弹说明有问题下面排查章节详细说。第二个是mAP曲线每10轮会自动在验证集上评估一次mAP0.5一般到0.85以上就算能用虫草这种难检测的小目标0.8以上已经算不错了。3.3 超参数调整与实战心得YOLOv5自带一个超参数文件data/hyps/hyp.scratch-low.yaml默认值对通用任务比较稳。但虫草检测有几个参数值得动一动。一个是锚框anchor。YOLOv5默认的anchor是在COCO数据集聚类出来的对虫草这种小目标来说偏大。如果你在训练日志里看到某些anchor匹配率很低YOLOv5会自动重聚类所以一般不用手动改但为了保险可以在训练前用YOLOv5自带的聚类脚本对标注框做一次分析。方法不复杂本质是用K-means统计所有标注框的长宽分布。虫草的目标框特点是细长、瘦高子座是长的跟COCO里那些方形目标差异很大。建议训练时开启--multi-scale参数让模型适应不同尺度的目标。另一个是正负样本匹配的iou阈值。YOLOv5低版本用的是single anchor匹配策略新版本改成动态分配。如果想调可以在模型配置文件里改anchor_t默认4.0这个值越大允许预测框偏离真实框的程度越大对召回率有帮助但会牺牲一些精度。单类别任务我建议适度调高比如设成4.5因为虫草目标小、形状细长太严格的正样本匹配会让模型学不到东西。还有一个非常容易被忽略的参数--workers。这个参数控制数据加载的线程数Windows下默认0Linux下可以设成4或8。数据加载速度跟不上GPU时训练会一直等数据GPU利用率上不去看起来像模型坏了一样实际是IO瓶颈。3.4 权重文件解读与版本管理训练结束后runs/train/dongchong_test/weights/目录下会有两个文件best.pt和last.pt。这两个文件看似差不多实际用途完全不同。best.pt是整个训练过程中在验证集上表现最好的权重也是我们日常推理、部署要用的那个。last.pt是最后一个epoch的权重主要用于中断后恢复训练或者你想继续在前一次训练结果的基础上接着跑。千万别把它们搞混了很多人图省事直接用last.pt部署结果精度明显偏低。权重文件用起来有几个细节要注意。第一best.pt是包含完整的模型结构、优化器状态和训练配置的文件比较大yolov5s大约15M如果只是做推理可以在detect.py里正常加载但如果是部署到生产环境建议用export.py先转成onnx或TorchScript格式体积更小、加载更快。第二权重文件的版本和代码版本必须匹配。用YOLOv6.0的代码跑出来的权重拿到YOLOv5v5.0的代码里直接推理大概率报错或者结果异常。我在本地会用一个简单的脚本管理多个项目的权重文件目录结构按项目分weights/ ├── dongchong/ │ ├── best.pt │ ├── last.pt │ └── onnx/ │ └── best.onnx这样每次训练成果不会互相覆盖也能快速回溯。4. 模型评估与推理部署实践4.1 评估指标怎么看训练完之后runs/train/dongchong_test/下会有results.png里面画了所有指标曲线。单类别任务重点看四个Precision精确率、Recall召回率、mAP0.5、mAP0.5:0.95。在虫草检测场景里Recall比Precision重要。这个逻辑跟工业质检刚好相反质检里把良品误判成次品会增加人工复检成本但虫草检测如果漏检Recall低意味着实际有虫草的地方没检测出来统计密度或计数就会偏低这直接导致数据失真。所以训练阶段如果发现Precision和Recall有矛盾优先照顾Recall。YOLOv5在验证时输出的PR曲线图会显示置信度阈值与Precision/Recall的平衡关系。默认置信度阈值是0.25如果你发现推理时漏检多可以把这个值降到0.15甚至0.1如果误检多就往上调到0.4。这个调参逻辑后面推理部分还会详细说。一个容易踩的坑mAP0.5:0.95这个指标在虫草这种小目标、细长形状的任务上通常不会好看可能只有0.3-0.4这是正常的。因为这个IoU阈值范围太严格虫草的框稍微偏一点IoU就掉得厉害。不要单纯因为mAP0.5:0.95不高就认为模型不行还是要看实际推理效果。4.2 推理参数优化推理用detect.py基本命令python detect.py --weights runs/train/dongchong_test/weights/best.pt --source test_images/ --conf 0.25 --iou 0.45 --img 640--conf是置信度阈值--iou是NMS的IoU阈值。实际调参经验是虫草检测的置信度阈值不要设太高因为小目标、低对比度目标的置信度天然偏低。我实测下来0.15-0.2这个区间的置信度阈值能在漏检和误检之间找到比较好的平衡点。NMS的iou阈值保持在0.45-0.5就行虫草目标之间基本不会互相重叠。如果检测的是视频或实时摄像头流还要注意--vid-stride参数默认是1也就是逐帧检测。野外拍摄的视频如果帧率很高比如30fps相邻帧内容几乎不变可以调成2或3省一半算力还不漏目标。代码层面如果想在推理时顺便输出目标的数量可以在detect.py的输出循环里加几行判断统计每个检测结果里框的数量。这个功能在虫草密度统计场景特别实用。4.3 边缘设备部署的思路如果最终要部署在Jetson、RK3588这类边缘设备上做实时检测建议提前把权重转成TensorRT或RKNN格式。YOLOv5自带的export.py支持onnx导出python export.py --weights best.pt --include onnx --opset 11转出来的onnx可以接着用TensorRT的trtexec工具优化或者转成RKNN。这里有个重要提醒边缘设备上的量化对细长小目标不友好。虫草目标本身的像素面积小INT8量化后特征丢失严重很多目标就检测不到了。如果边缘设备推理精度掉得厉害优先考虑FP16而不是INT8或者干脆用FP32虽然慢一点但保精度。部署时还有一个很容易忽略的点输入分辨率要和训练时保持一致。如果训练用640推理时为了提高速度改成320小目标会大量漏检。如果确实需要提速建议改batch size或换轻量主干而不是降低输入分辨率。5. 常见问题与排查技巧实录5.1 训练不收敛或loss震荡这个现象在虫草项目里很常见因为目标小、正负样本极度不平衡。首先要确认一个关键点是不是数据标注出了问题。我遇到过好几次训练loss一直降不下去打开标注文件一看坐标归一化做错了有一半目标框的cx、cy超过1模型根本学不到正确位置。如果确认标注没问题再检查训练集和验证集是不是有重复。前面说过连续帧照片如果同时进训练集和验证集验证集的loss会很低但推理时表现差这是典型的“假收敛”。另外数据太少也会导致loss震荡单类别任务至少要有500张有效图再多就稳很多。超参数方面如果前50轮loss完全没有下降趋势尝试把--lr0初始学习率从默认的0.01降到0.001。虫草这种难分类任务学习率太大容易在loss曲面震荡小一点反而收敛更稳。5.2 CUDA显存不足显存不足是新手遇到最多的报错英文提示通常是CUDA out of memory。最直接的解决办法是降低--batch从16降到8再降到4直到能跑起来。但要注意batch太小导致梯度估计不准训练会不稳定。我建议优先降低--img尺寸从640降到512或480这样显存占用下降非常明显同时小目标性能损失不算太大。如果batch和img都不想动就开梯度累积可以通过在训练脚本里设置--accumulate参数YOLOv5新版没有直接暴露的CLI参数需要改代码或在hyp里调相当于每多步积累一次梯度再更新效果近似于变相扩大batch。5.3 过拟合特征虫草数据集如果采集场景单一模型很容易过拟合。表现形式是训练集loss很低但验证集loss反弹或者验证集mAP迟迟上不去。解决办法有两个方向。一是严格划分数据集保证训练集和验证集的拍摄场景不重叠二是加大数据增强强度把Mosaic的缩放范围调大、开启copy_paste增强YOLOv5新版支持让模型见过更多样的输入。5.4 推理误检、漏检调整思路把常见问题整理成一张速查表方便直接对着排查。现象可能原因解决方式漏检多该框的没框置信度阈值偏高把--conf从0.25降到0.15漏检多且小目标完全看不见输入分辨率太低把--img从640提高到960误检多把草、石头框出来置信度阈值偏低把--conf从0.15升到0.35误检多且框偏大标注框画得太大重新检查并修改部分标注后重训验证集AP高但新图效果差训练集和部署场景差异大补充部署场景的数据或做迁移微调输出结果闪烁视频检测帧间置信度波动结合跟踪逻辑或提高帧推理稳定性5.5 几个容易忽视的细节这些细节是做完整个项目之后回头看最想让当初的自己提前知道的。第一不要迷信训练轮数多。单类别虫草检测150-200轮足够再多就是浪费算力和显存。如果发现100轮以后mAP已经开始走平可以直接提前停YOLOv5自带早停机制默认patience是100也可以手动设小一点。第二权重文件损坏问题。从网上下载预训练权重时如果文件下载不全训练时可能不报错但loss乱跳。遇到训练异常先把权重文件删掉重新下载排除这个最简单的可能性。第三配置文件的YAML格式陷阱。YOLOv5的data yaml里冒号后面一定要有空格train: dataset/images/train这种写法如果写成train:dataset/images/train会直接报错而且报错信息还很不直观新人容易在这里卡一个小时。第四标签文件和图片数量必须一一对应。有些图是没有目标的正确的做法是保留一个内容的txt文件0字节千万不要把没有目标的图直接删掉或者不生成空txt。YOLOv5在加载数据时会校验数量对不上训练就会中断。第五多尺度训练与推理分辨率的关系。如果训练时用了--multi-scale模型在各尺度下都能工作但推理时最好还是用训练时最常用的主尺度通常是640这样效果最稳定。最后再分享一个小技巧当我对一个权重文件的效果不确定时会专门挑几张最难的图比如目标极小、背景极乱、光线很差的单独做测试而不是只看验证集mAP。因为验证集是数据集划分出来的跟训练集同分布在这个数据集上效果好不代表真实现场效果好。用最难样本做一个“压力测试”这个权重能不能用心里马上就有数了。这个项目做完最大的感受是目标检测项目的重心往往不在模型本身而在数据和细节上。YOLOv5的代码和权重都是现成的真正决定虫草检测效果好坏的是有没有一张干净的、标注合理的、分布贴近真实场景的数据集以及遇到了loss不降、显存爆掉、识别不准这些问题时能不能快速定位到症结。把这套流程完整跑一遍后续再换其他单类别检测项目基本就是复制粘贴再微调的事。本文还有配套的精品资源点击获取
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门