YOLOv5实战:冬虫夏草生长检测的完整工程链路解析
2026/9/1 1:01:17 网站建设 项目流程

简介:本资源是一套面向计算机视觉初学者与农业AI应用开发者的YOLOv5目标检测实战项目,聚焦冬虫夏草生长早期识别这一细分农业场景,解决高分辨率田间图像中单类别微小目标精准定位难题。压缩包共1552个文件(含748张640×482分辨率RGB训练/验证图像、615个YOLO格式标签txt、52个配置yaml、51个核心py脚本及训练好的.pt权重),总大小189.89MB,结构完整覆盖数据准备、模型训练、可视化分析全流程。已有273人学习下载,资源内置20epoch训练结果(mAP@0.5达0.96)、混淆矩阵、PR/F1曲线等评估产物,并保留未收敛潜力,便于用户继续优化。所有代码经实测可直接运行,配套数据标注规范、目录层级清晰,显著降低农业视觉项目复现门槛。 项目里最珍贵的不只是那套训练好的权重,还有从零到一跑通整个流程的工程经验。这篇文章我会按“为什么做、数据怎么搞、模型怎么训、权重怎么用、坑怎么避”的顺序,把YOLOv5做单类别冬虫夏草生长检测这件事的完整链路拆开讲清楚。整个过程没有玄学,每一步都能落地。


1. 项目拆解:冬虫夏草生长检测到底在检测什么

1.1 场景痛点与项目价值

冬虫夏草是蝙蝠蛾幼虫被虫草菌侵染后形成的复合体,野外状态下,能被人眼直接观察到的是露出地表的那截子座。实际业务里,不管你是做产区资源调查、人工抚育效果评估,还是辅助采挖定位,第一步都是同一个问题:把草地里的冬虫夏草找出来。

这事放在人眼面前不难,但放到规模化场景里就麻烦了。一个调查样方可能几百平方米,靠人蹲在地上逐块排查,效率低且费腰;如果用无人机或者全景相机采集图像回来人工数,那更是灾难,一张高分辨率影像里草、土、石头、枯枝和虫草子座混在一起,人看一小时就视觉疲劳了。目标检测模型干的就是这个活:把图像里属于虫草目标的区域框出来,并且告诉你置信度有多高。

这个项目最终确定“1类别”,原因是核心业务只需要区分“虫草”和“背景”二分类语义。不需要区分产地、不用鉴别品级、也不需要识别子座和虫体的连接关系,那么把模型复杂度降下来,把单类别的精度做上去,就是性价比最高的路线。1类别模型有一个天然优势:类别间混淆的风险完全不存在,模型只需要专注学习“虫草目标”相对背景的视觉差异性,收敛难度比多类别模型小很多,所需的标注量和训练轮次都更友好。

另外,你需要知道“生长检测”在这里有两层含义。第一层是静态检测,即从单张图像里定位出虫草目标;第二层是动态监测,即通过不同时间点的检测结果对比,判断虫草出土、生长、成熟甚至腐烂的阶段变化。本次项目交付的模型和权重,核心覆盖第一层,但按固定点位周期拍摄的思路来使用,就能平滑支撑第二层应用。

1.2 为什么选YOLOv5而不是更高版本或其他模型

目标检测领域现在可选方案很多,YOLOv8、YOLOX、SSD、Faster R-CNN摆在一起,难免选择困难。我从项目实际角度说说为什么仍然选YOLOv5。

第一,生态成熟度高。YOLOv5从2020年发布到现在,社区积累了海量的教程、调参经验、部署方案和踩坑记录。你遇到一个问题,搜出来的答案很可能就是针对YOLOv5的,这能极大缩短排查时间。模型选型不能只看性能指标,还要看“出了事你有没有人可问”。

第二,工程化最顺手。数据格式、训练命令、权重管理、推理接口都封装得很干净。一个训练好的weights/best.pt,配一个detect.py就能跑图片、视频、摄像头,部署到服务端或者边缘设备都有成熟的导出路径。

第三,单类别场景下精度足够。冬虫夏草目标不算极端微小,形态上子座呈细长棒状,直立破土,和背景有明确边界。YOLOv5s级别的模型在640分辨率下就能有很好的表现,往上换m或l模型收益有限,反而推理变慢。如果盲目用更重的模型,在嵌入式设备上的部署成本会翻倍,这是实际项目的隐性代价。

做个简单对比可能会更直观:

方案优点在本项目中的劣势
YOLOv5生态好、部署方便、单类别精度够结构相对经典,新特性少
YOLOv8结构更新、训练更方便部分老设备部署资料少,改动成本高
YOLOX精度不错、无锚框工程资料相对少,调试门槛高
Faster R-CNN精度上限高推理太慢,不适合批量和实时巡检

YOLOv5的推理速度在单类别任务上让我放心很多。实测一张1280x1280的野外巡检图,用yolov5s的FP16模式在RTX 3060上推理时间大约在15到20毫秒,即使只跑CPU也能做到每秒几张图,这个效率是两阶段检测器给不了的。


2. 动手之前:环境搭建与数据工程

2.1 运行环境配置与依赖安装

拿到项目代码后,第一步不是急着训练,而是把环境铺好。这个项目基于YOLOv5官方框架改造,依赖项集中在requirements.txt里。我建议用 conda 建一个独立环境,避免把系统Python搞乱。

conda create -n yolo-cordyceps python=3.9 conda activate yolo-cordyceps cd yolov5 # 项目根目录 pip install -r requirements.txt

requirements.txt 里核心的包无非就是 torch、torchvision、opencv-python、numpy、matplotlib、pyyaml、tqdm 这些。需要特别注意PyTorch版本和你的CUDA版本匹配。直接用官方默认的requirements安装,会自动装CPU版还是GPU版不一定,最好根据显卡驱动手动安装对应版本的PyTorch。

我遇到过不少人在这一步卡住,训练时报“Torch not compiled with CUDA enabled”,就是因为装成了CPU版。建议先跑一行命令验证环境:

python -c "import torch; print(torch.__version__, torch.cuda.is_available())"

输出里True才是GPU环境,False的话就算能训练也是龟速。还有一点,如果显存紧张,可以适当降低batch size,这个后面训练参数部分细说。

2.2 数据采集与标注规范

数据是检测项目的粮食,冬虫夏草这种垂直场景没有现成公开数据集,只能自己拍或者合作方提供。我先说采集环节的几条经验:

采集时尽量覆盖不同生长阶段、不同光照条件、不同背景复杂度。清晨和傍晚的光线、阴天和晴天的色温差异非常大,如果只在晴天中午拍,模型很容易把光线特征当成目标特征,泛化能力会很差。我建议一个简单的配比:晴天60%、阴天30%、弱光10%,多角度(俯视为主、侧视为辅)拍摄。

拍摄设备不必追求高端,像样的手机就行,但要注意分辨率不能太低,建议不低于1080p。因为虫草子座相对细小,图像太小的话目标在图中可能只有几十个像素,标注和检测都困难。

标注工具推荐LabelImg或者X-AnyLabeling,都是开源免费工具。这个项目是单类别检测,标注时统一打一个标签,比如cordyceps,不需要细分。但有个关键点:边界框怎么画直接影响训练效果。

冬虫夏草的子座是细长型的,如果严格按照外接矩形框,框大多数情况下都是扁长条,长宽比可能到5:1甚至8:1。YOLO的锚框机制对极长宽比目标不算友好,训练时容易出现定位偏差。我的实践做法是:子座外露部分紧密框住,但不要把虫体部分(地下部分)算进去,同时允许上下各留2%左右的边距,避免截断子座尖端。这么做可以稍微降低长宽比的极端程度,让模型收敛更稳定。

标注完成后,每个txt文件里是归一化后的坐标:class_id x_center y_center width height。建议写个小脚本检查数据:

import os for label_file in os.listdir('labels/train'): with open(os.path.join('labels/train', label_file), 'r') as f: for line in f: parts = line.strip().split() assert len(parts) == 5, f'{label_file} 格式错误' x, y, w, h = map(float, parts[1:]) assert 0 < x < 1 and 0 < y < 1, f'{label_file} 坐标越界' assert 0 < w < 1 and 0 < h < 1, f'{label_file} 宽高越界'

坐标越界这类问题很隐蔽,训练时不一定会报错,但会严重污染loss,导致模型不收敛。

2.3 dataset.yaml 配置与数据划分

YOLOv5框架通过yaml文件告诉训练脚本三件事:训练集路径、验证集路径、类别数量。这个项目的配置文件大概长这样:

train: data/cordyceps/images/train val: data/cordyceps/images/val nc: 1 names: ['cordyceps']

数据目录结构按YOLOv5要求组织:

data/cordyceps/ ├── images/ │ ├── train/ │ └── val/ └── labels/ ├── train/ └── val/

数据和标签必须严格同名,比如img_001.jpg对应img_001.txt,否则训练时这张图会因为没有标签而被自动忽略。训练集和验证集的划分我习惯按9:1来,如果样本量特别少(少于500张),可以试8:2,但不要低于7:3,否则训练数据不够,很容易过拟合。

划分图片时建议用脚本随机拆,而不是手动拖文件夹。顺手生成一个train.txtval.txt的路径列表也可以,不过YOLOv5按目录方式读取已经足够,不必额外生成。

提示:验证集要保证“没被模型见过”,千万别把训练集里同一张图的不同裁剪也放进去,否则验证指标虚高,换真实场景立刻打回原形。我自己就吃过这个亏,数据增强后的图片混进了验证集,mAP从0.95掉到0.72,排查了半天。


3. 模型训练与权重使用全解析

3.1 迁移学习与预训练权重选型

训练YOLOv5时最忌讳的就是从零开始训。随机初始化的模型在几千张图上要同时学习特征提取、目标定位和类别判别,收敛慢且容易过拟合。这个项目我强烈建议用COCO预训练权重做迁移学习。

yolov5s.pt、yolov5m.pt这些预训练权重,是在COCO数据集上训练好的,已经能提取比较通用的视觉特征,比如边缘、纹理、颜色分布、局部形状。冬虫夏草虽然不在COCO的80类里,但作为视觉目标,它同样由基本的边缘和纹理组合而成。迁移学习相当于让模型带着“已经会看东西”的基础来学新任务,只需要微调后面几层就能适配新类别。

选哪个规模的预训练权重,看你的算力和目标大小。yolov5s最轻量,显存占用小,适合快速迭代;yolov5m更重但特征提取能力更强。对于单类别检测,yolov5s是首选,yolov5m只是备选。如果训练中发现小目标漏检严重,优先调整分辨率和锚框,而不是盲目上大模型。

下载好的权重放到项目根目录,命名保持yolov5s.pt即可,训练命令中会自动识别。如果因为网络原因下载不下来,可以用你本地已有的任意YOLOv5权重文件,只要结构是对应的,都能作为预训练起点。

3.2 训练命令与关键超参数解释

训练入口是train.py,项目的核心训练命令如下:

python train.py --data data/cordyceps.yaml --weights yolov5s.pt --img 640 --batch 16 --epochs 150 --name cordyceps_run1

每个参数背后都有讲究,我逐个说:

--img 640表示输入图像分辨率。YOLOv5会等比缩放输入图像到640x640,不足部分补灰边。冬虫夏草子座是细小目标,如果用640明显感觉漏检多,就上1280,但显存占用会变成原来的4倍,实测RTX 3060 12G显存下,yolov5s + batch 8能跑1280,再大就悬了。冬虫夏草目标大概占图像面积的0.5%到5%,我个人建议如果硬件允许,直接上1280,小目标检测效果提升非常明显。

--batch 16是每个batch的图像数量。显存是硬约束,batch太大直接OOM。与其纠结理论最优值,不如用“能跑最大batch的70%”作为一个稳键起点。batch太小(小于8)会让BN层统计不稳定,训练震荡明显。

--epochs 150是最大训练轮数。单类别模型收敛比较快,一般80到120轮就能达到稳定状态,150轮是给足余量。YOLOv5自带早停机制,如果连续50轮验证集指标没有提升,会自动停止,你不需要一直守着。开启方式是在train.py里指定--patience 50

可以用一批关键超参数体验一下:

参数默认值本项目推荐原因
--img640640或1280目标较小,分辨率优先
--batch1616或8看显存
--epochs300150单类别收敛快
--patience10050避免无效等待
--cacheFalseTrue小数据集加载更快
--cos-lrFalseTrue余弦退火更稳

--cache True是让数据预加载到内存里,对几千张图的数据集来说,能显著减少训练过程中读盘的等待时间。

3.3 训练好的权重加载与推理

训练结束后,runs/train/cordyceps_run1/weights/下会出现两个文件:best.ptlast.ptbest.pt是验证集上表现最好的权重,last.pt是最后一轮的权重。日常使用必须选best.pt,这基本是共识。

单张图片推理用detect.py:

python detect.py --weights runs/train/cordyceps_run1/weights/best.pt --source data/test/images/img_001.jpg --conf 0.5 --img 640

输出结果会保存到runs/detect/exp目录。--conf 0.5是置信度阈值,低于该值的预测框会被过滤。野外场景的稀疏目标建议阈值设0.4到0.5,宁缺毋滥,减少误报。

如果你的系统里没有detect.py或者想集成到自己的程序里,可以用torch.hub加载:

import torch model = torch.hub.load('ultralytics/yolov5', 'custom', path='weights/best.pt', force_reload=True) model.conf = 0.5 model.iou = 0.45 results = model('test_img.jpg') results.show() results.print()

用torch.hub方式加载的训练权重,不需要重新安装YOLOv5就能直接运行,对生产环境接入比较友好。需要注意,hub加载会自动联网检查仓库版本,离线环境可能有问题,需要提前把库clone到本地并设置source='local'

摄像头实时推理也简单:

python detect.py --weights weights/best.pt --source 0 --conf 0.5

这会打开电脑摄像头,对每一帧实时做检测。如果落地到野外巡检,这个模式配合USB摄像头或者网络摄像头(RTSP流)都能用,RTSP流的source填rtsp://ip:port/stream即可。


4. 结果怎么看:评估指标与模型调优

4.1 训练日志里的关键指标解读

训练跑完后,打开runs/train/cordyceps_run1/results.png,会看到一整套训练曲线,包括loss曲线、Precision曲线、Recall曲线、mAP@0.5曲线、mAP@0.5:0.95曲线。我逐一看这些指标。

loss曲线分三部分:box_loss(框回归损失)、obj_loss(目标置信度损失)、cls_loss(分类损失)。对于单类别模型,cls_loss本来就趋近于0,重点看box_loss和obj_loss是否稳定下降并收敛。

Precision(精确率)表示所有被模型预测为“虫草”的框中,真正是虫草的占比。Recall(召回率)表示所有真正的虫草中,被模型成功找出来的占比。这两个指标天然互斥,调阈值时只能二选一权衡。在冬虫夏草巡检场景,我个人倾向于保Recall,因为漏掉一株虫草,可能意味着漏掉一个样本点,后期人工补采成本太高;多框几个非目标,后期人工复核成本相对低。

mAP@0.5是IoU阈值0.5下的平均精度,这是最常用的综合指标。单类别任务中,mAP@0.5能达到0.9以上就算非常优秀了。mAP@0.5:0.95是更严格的指标,IoU从0.5到0.95每隔0.05取一次平均值,它更关注边界框定位的精细程度。如果你做的是科研任务,mAP@0.5:0.95是论文里绕不开的指标;如果只是业务部署,mAP@0.5够用了。

4.2 单类别模型的调优方向

训练完发现指标不行,先别急着调参,用几个方向排查:

第一,先看验证集效果图。运行detect.py后打开标注了预测框的图片,观察错误类型。如果目标被漏检得很均匀,说明模型泛化不足,可能是数据不够或者数据分布太单一,需要补充更多样性的数据。如果目标被框出来了,但框的位置偏移明显,说明回归损失还没收敛,可以增加训练轮次或调低学习率。

第二,针对小目标优化。冬虫夏草子座细长,直接提高--img到1280往往最简单有效。但随之而来的显存压力,可以配合降低batch size解决。还有一种思路是给模型单独计算自适应锚框,YOLOv5默认会从数据里自动重新聚类锚框,不用担心手动配置。如果想手动开启,训练时加--noautoanchor会禁用这个功能,不建议新手动。

第三,调整置信度阈值。训练后的权重默认conf阈值是0.25。如果推理时假阳性太多(把草叶、枯枝当成虫草),把--conf提到0.5甚至0.6。反之如果漏检太多,就降到0.2以下。这个参数只需推理时调整,不需要重新训练,性价比极高。

第四,数据增强已经是YOLOv5默认配置里的一部分(Mosaic、仿射变换、HSV扰动等),不需要额外设置。但如果数据量很少(少于300张),建议把Mosaic增强关掉或降低比例,因为数据太少时,大比例拼接反而会让模型学到不真实的特征。

调优并不是越复杂越好。这个项目的数据和任务规模下,20到30组有效图片配合yolov5s,已经可以训练出能实际使用的模型。高手和新手的差距,往往体现在对数据的理解上,而不是模型结构上的花活。


5. 实战踩坑:常见问题与排查技巧

5.1 训练阶段的高频问题

不夸张地说,训练阶段80%的报错集中在这几类,先把这些整明白,能省非常多的时间。

CUDA out of memory

这是最经典的一个。YOLOv5默认会自动开启Mosaic增强,并且训练时图像是带上下文的,显存占用比推理时高不少。解决优先级:先降低batch到8或4,还不行就降低imgsz到480或512,再不行换yolov5n(更轻量)。不建议一开始就关闭Mosaic,它对你的训练效果帮助很大。

Dataset not found / 路径错误

YOLOv5用的是相对路径还是绝对路径,取决于你的yaml文件怎么写。如果你的项目从A目录拷贝到B目录,yml里的相对路径就失效了。我的建议是在data/cordyceps.yaml里直接写绝对路径,虽然不够优雅,但绝对不出错。

labels格式不对导致训练时所有图都没有目标

YOLOv5要求标签文件是YOLO格式的txt,每行对应一个目标。如果你用VOC格式的xml标注,直接用脚本转换时容易把坐标算错(像素坐标和归一化坐标搞混)。转换后务必用可视化脚本画一遍框检查,不要只管“能训练”。

训练速度极慢

如果不是GPU版本没装对,那就是数据读取成了瓶颈。建议加--cache True,把数据一次性缓存到内存。另外确认你的数据是jpg,不要用png,png解码更慢且占用内存更大。

5.2 推理与部署阶段的隐藏坑

训练完成后,权重的使用阶段也有几个容易翻车的地方。

模型加载报KeyError

这通常是因为用不同版本YOLOv5训练的权重,加载到另一个版本的代码里。YOLOv5的模型状态字典在不同commit间会有字段差异。解决办法很简单:用训练时的那个项目代码做推理,别混版本。

推理结果为空,但训练指标正常

这是置信度阈值和NMS阈值设定不合理。检测时默认--conf 0.25,但野外低对比度图像上,模型输出的置信度普遍偏低,建议批量测试时用一个动态阈值脚本,找到适合你场景的最优值。我通常的做法是,拿50张已经人工标注好的图跑一遍,记录每个预测框的置信度分布,再选取精确率和召回率平衡的那个点。

批量推理内存溢出

用大分辨率图像做批量推理时,如果一次把上千张图塞进一个list再推理,内存会先爆。推荐写个简单的生成器,逐批读取、逐批推理、逐批释放。虽然多几行代码,但可以省去频繁重启的麻烦。

下面是一个排查速查表,可以直接收藏使用:

症状直接原因优先处理方案
CUDA OOMbatch太大 / 分辨率太高降低batch,降低imgsz
训练loss降不下去标注坐标错误 / 学习率过高检查标签,调低lr到0.001
无检测结果conf阈值过高 / 训练过拟合调低conf,检查epochs是否过多
有误检但漏检少背景复杂、假阳性多调高conf,补充负样本
验证集mAP高,实测差过拟合、数据分布单一增加数据多样性,降低epochs
显存够但训练慢数据增强耗时 / 缓存未开加cache,检查CPU核心数

再补充一个非常容易忽略的问题:YOLOv5的Mosaic增强在最后10个epoch会默认关闭,这是官方行为,为了让模型在接近真实分布的数据上稳定收敛。如果你发现训练末期mAP有小幅波动,不用紧张,那是正常现象。

在推理时,还有个很容易被忽略的小决定:权重文件是FP32还是FP16。best.pt默认是FP32,推理速度够用。如果你需要部署到边缘设备或追求极速,可以把weight转成TensorRT的engine格式或ONNX格式,yolov5自带export.py脚本: python export.py --weights weights/best.pt --include onnx --opset 12 转ONNX后,可以用onnxruntime或TensorRT做推理,速度快不少。但要注意,ONNX导出后如果遇到动态输入尺寸的问题,多半是你之前训练时固定了imgsz,导出时也指定相同尺寸即可解决。

6. 项目复盘:数据、代码、权重之外的收益

做这个项目时我踩过最大的坑,其实不在技术上。第一次训练时我拿到的数据只有200多张,而且全部是晴天正午拍摄的。模型训练完,验证集mAP到了0.91,看着很漂亮。结果拿到阴天场景一试,漏检率直接飙升到30%以上。后来补充了不同光照、不同背景的图片,重新训练后才真正可用。

这个教训让我意识到,单类别检测项目里,数据的“覆盖度”远比数量重要。200张覆盖完整的图,效果胜过500张单一场景的图。你不需要一口气把数据集弄到几千张,但一定要保证场景的多样性。

代码层面,这份项目代码最好的地方在于“改得动”。YOLOv5官方仓库本身就是模块化设计,无论是改数据加载逻辑、加回调函数,还是替换骨干网络,都有清晰的接口。我后来在部署时把detect.py的批量推理逻辑抽出来,写成了一个简单的API服务,前后只花了两小时,这也是基于YOLOv5生态做二次开发的优势。

权重文件是整个项目的最终资产。拿到权重之后,如果你想长期运营这个检测服务,要养成记录训练超参数、数据版本和指标的习惯。给每个权重文件命名时带上日期和数据版本,比如best_20240612_v2.pt,不要直接保留last.pt,否则半年后回来看,你根本不知道这个权重是从哪批数据训出来的。这个习惯在团队协作时尤其重要。

最后分享一个后续扩展方向:在单类别检测的基础上,如果业务上需要区分冬虫夏草的生长阶段(如刚出土、子座成熟、开始腐烂),可以在数据标注阶段增加类别标签,把单类别检测升级为多类别检测任务。你不需要换模型框架,把nc: 1改成nc: 3nc: 4,调整标注类别,重新训练即可。前期的数据采集、环境搭建、训练流程全部可以复用,这也是选择一套成熟框架来做项目最舒服的地方——它给你留了足够多的升级空间。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询