YOLOv5果蔬识别实战:从数据标注到模型部署的完整流程

YOLOv5果蔬识别实战:从数据标注到模型部署的完整流程
简介本资源是一套基于YOLOv5的果蔬图像识别系统完整实现方案面向计算机科学与技术、人工智能等相关专业的本科生毕业设计与课程实践需求解决农业场景中常见果蔬类别的自动化检测与分类问题。资源包共717个文件涵盖546张标注JPG图像含部分JPEG、119个备份文件zbak、15个核心Python训练与推理脚本、12个PNG可视化结果图、7个XML标注文件及多个H5模型权重如cnn_fv.h5、mobilenet_fv.h5等整体压缩包大小为268.88MB结构清晰、模块分明便于按数据预处理、模型训练、评估部署等流程分阶段学习。已有55人下载学习资源经导师审核获评优秀配套详细实现指南完整覆盖YOLOv5数据集构建、标签转换、超参调优、mAP验证及轻量化适配等关键环节并提供多版本模型权重与典型测试图像显著降低复现门槛适合具备机器学习基础的学习者开展项目开发与算法优化实践。 各位做视觉检测的朋友应该都有类似的感受目标检测模型本身越来越成熟真正拉开项目差距的往往不是网络结构选得多新而是数据够不够扎实、训练流程够不够稳。最近我完整落地了一个基于YOLOv5的果蔬识别系统从数据集构建、模型训练到推理部署都走了一遍踩了不少坑也沉淀了一些可以复用的经验。这篇就围绕这个项目把YOLOv5实现果蔬识别的完整链路拆开讲清楚包括数据集怎么准备、训练参数怎么调、遇到问题怎么排查给正在做类似项目的同学一个可直接参考的路线。果蔬识别这个方向其实很有代表性。它跟通用物体检测不太一样既有类别多、外观相近的难点比如不同品种的苹果、番茄又有实际落地时对实时性和轻量化的要求比如嵌入式收银设备、分拣机器人。YOLOv5在这个场景下是很合适的选择——它不像YOLOv8那样对部署链路有较多新要求也不像Faster R-CNN那样推理速度吃亏属于成熟、稳定、资料多、踩坑成本低的方案。这篇文章的内容主要来自我实际做项目的过程记录适合正在用YOLOv5做视觉检测、尤其是果蔬农产品方向的同学参考也适合准备入坑目标检测的初学者当一份实操地图。1. 整体设计与方案选型为什么是YOLOv5果蔬识别到底在解决什么问题1.1 果蔬识别场景的核心需求拆解在做果蔬识别之前首先要搞清楚这个场景到底要解决什么。表面上看它是识别图片里有什么水果但实际落地时需求往往更具体识别画面中多个果蔬的位置和类别给出每个目标的边界框并且在嵌入式设备或普通CPU上也能跑得动。比如超市的自助结算台摄像头拍到的不是单个水果而是好几个水果堆在一起分拣流水线上果蔬随传送带移动检测速度跟不上就会漏检。所以果蔬识别本质是一个多目标、实时性优先的检测任务而不是简单的图像分类。这也是为什么我直接选了目标检测模型而不是分类模型。单纯用ResNet这类分类网络只能回答这张图里有没有苹果回答不了苹果在哪个位置、有几个。而在真实场景中位置信息和数量信息恰恰是业务最关心的。用检测模型一次推理就能同时拿到类别、坐标、置信度后续不管是触发机械臂抓取还是自动计算结算金额都有直接可用的结构化输出。1.2 为什么选YOLOv5而不是其他检测模型目标检测模型可选的范围其实不小我从三个维度做了对比精度、速度和工程成熟度。Faster R-CNN精度高但两阶段结构在推理速度上吃亏部署到边缘设备很吃力YOLOv8和YOLOv9虽然是新版本训练和推理效果也不错但当时我要集成到一套已有的视觉流水线上YOLOv5的生态最成熟转ONNX、转TensorRT、嵌入式部署的资料最全遇到问题能搜到的解决方案也最多SSD速度不错但精度相对一般小目标表现弱一些对果蔬这种尺寸不一的目标不太友好。YOLOv5真正让我放心的地方在于它自带了一整套训练和验证工具链数据集格式统一超参数配置灵活从训练到导出的路径非常清晰。尤其对于果蔬识别这种需要反复调数据、快速迭代的需求YOLOv5的工程化优势很突出。模型体积也灵活从s到x的尺寸可选后期做边缘部署时可以按算力换模型。1.3 果蔬识别系统的整体架构整个系统的结构可以分成四层数据层、训练层、推理层和应用层。数据层负责果蔬图像的采集、清洗和标注是后面所有环节的基础。训练层包括数据集划分、YOLOv5模型训练、超参数调整和效果评估。推理层做模型导出和封装把训练好的权重转成可部署的格式比如ONNX或TensorRT。应用层对接具体业务比如实时视频流检测、单张图片识别、批量图片处理等。这样的分层设计是为了让每一部分都能独立迭代。数据不够就补数据模型效果不好就调训练参数部署环境变了只改推理层接口不会牵一发动全身。实际项目里数据层往往占用最多时间——果蔬种类多、拍摄环境杂数据质量直接决定模型上限这个过程不能省。2. 数据集准备与处理果蔬识别项目的成败关键2.1 数据集来源开源数据集、自采数据和数据增强的组合策略果蔬识别第一个绕不开的问题就是数据从哪来。我当时是三种来源结合开源数据集是起点。公开的果蔬数据集有不少比如Fruit-360、Roboflow上的果蔬检测数据集还有从COCO数据集中筛选出的水果类子集。这些数据集的好处是已经标注好了省去前期最枯燥的标注工作可以作为预训练或者初步验证的素材。但直接用开源数据集做最终模型往往不够——开源数据集里的拍摄场景比较单一跟实际应用场景差异大泛化效果会打折扣。自采数据决定模型的实战能力。我拿了实际要部署场景的摄像头在不同光照、不同角度、不同堆放状态下采集了大量果蔬图像覆盖单一品种和多品种混合的情况。这个环节比较费时间但与业务最贴近是模型在真实环境里能不能用的关键。如果采集范围太窄模型换个光照条件就明显掉点后面补数据成本更高。数据增强是低成本扩充数据的手段。YOLOv5自带的增强策略已经很丰富mosaic、随机透视、HSV色域增强、随机翻转等都能有效提升模型的鲁棒性。果蔬识别里尤其受益于HSV增强——果蔬的颜色是重要特征但同一品种在不同光照下颜色差异很大通过色域增强模拟这些变化能让模型学到更本质的特征。2.2 数据标注的标准与标注工具选择数据标注是整个过程中最枯燥但最容易出错的环节。标注标准直接决定模型学习到的边界。我当时定的标准是遮挡超过50%的目标不标模糊到人眼都难分辨的目标不标只露一小角的目标不标但正常堆叠、相互遮挡不超过一半的目标必须标清楚。标注工具我用的是LabelImg轻量、免费、支持YOLO格式导出批量化操作也比较顺手。它基于Qt的图像标注工具操作方式很简单打开图片目录用矩形框框选目标选择类别保存后会生成对应的txt文件。每张图片的标注文件跟图片同名内容每一行对应一个目标格式是类别id 中心点x坐标 中心点y坐标 框宽度 框高度坐标值均做了归一化范围在0到1之间。这个格式是YOLO系列通用的后续训练时不需要额外转换直接就能喂给模型。如果标注量特别大也可以考虑Roboflow这类在线工具它支持团队协作标注并且自动做数据增强和格式转换但要注意数据上传到云端的安全问题。对一般项目来说LabelImg在本地操作已经足够。2.3 数据集格式整理与目录结构规范YOLOv5要求的数据集目录结构比较固定但也很简单。我当时的目录是这样的dataset/ ├── images/ │ ├── train/ │ ├── val/ │ └── test/ ├── labels/ │ ├── train/ │ ├── val/ │ └── test/ └── data.yamlimages和labels要严格一一对应同一张图片的jpg文件和txt标注文件必须在对应的train或val子目录下文件主名一致。data.yaml是数据集的配置文件内容包含路径信息、类别数量、类别名称列表。比如我的果蔬数据集中有apple、banana、orange、tomato、potato、carrot等类别data.yaml大概长这样train: dataset/images/train val: dataset/images/val test: dataset/images/test nc: 6 names: [apple, banana, orange, tomato, potato, carrot]这里有个细节容易被忽略train和val的路径可以写绝对路径也可以写相对于YOLOv5项目根目录的相对路径。为了项目迁移方便建议用相对路径。数据集划分比例我用了8:1:1train占八成val和test各占一成。划分的时候要注意类别平衡不能某个类别在train里很多、在val里几乎没有这样验证结果不可信。可以用脚本按照每个类别的样本数量做分层采样。2.4 数据增强策略的实际效果观察我测试过不同增强策略对果蔬识别的影响。YOLOv5在训练时默认开启mosaic增强——把4张图片随机缩放拼接成一张相当于同时增加了样本数量、目标尺度变化和上下文多样性。对果蔬识别来说mosaic增强带来的效果提升非常明显。因为实际场景中果蔬经常堆叠在一起mosaic天然模拟了这种多目标、多类别共存的情况。HSV增强是另一个需要重点关注的部分。果蔬的颜色是判别性很强的特征但同一个苹果在自然光、灯光、带阴影的环境下颜色差异不小。HSV增强可以在一定范围内随机调整色相、饱和度和亮度让模型学习对光照变化不敏感的特征。我实际测试下来把饱和度扰动范围调大一些模型在不同光照条件下的鲁棒性有明显提升。不过增强也不是越强越好。增强过猛会导致训练数据跟真实数据分布偏差过大反而让模型在真实场景上表现变差。我的经验是先按YOLOv5默认增强参数训练一版观察在验证集上的表现再针对性地调整增强强度。比如某个品种的果蔬在真实场景中经常出现高光反射就可以适当加大亮度扰动的范围去模拟这种情况。3. 环境搭建与YOLOv5安装部署从零开始跑通训练流程3.1 环境准备与依赖安装的完整步骤YOLOv5的环境搭建整体不算复杂但细节问题不少我在新机器上装过多次把踩过的坑都趟平了。首先是基础环境系统我用的Ubuntu 20.04Python版本3.8到3.10都可以PyTorch需要根据显卡驱动和CUDA版本选合适的版本。如果没有NVIDIA显卡CPU也能训练但速度会慢很多建议至少用一块入门级GPU。整个安装流程可以分成三步。第一步是克隆YOLOv5仓库并创建虚拟环境推荐用conda管理环境避免不同项目之间的依赖冲突git clone https://github.com/ultralytics/yolov5 cd yolov5 conda create -n yolov5 python3.8 conda activate yolov5第二步是安装依赖YOLOv5在requirements.txt里已经把常用的依赖都列好了直接安装即可pip install -r requirements.txt这里有个非常常见的问题requirements.txt里默认会安装最新版的torch和torchvision但最新版可能跟你的CUDA版本不匹配导致安装完发现CUDA不可用。建议先单独安装匹配的PyTorch版本再安装其他依赖。比如CUDA 11.8对应的可以这样装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如果能在runs/detect目录下看到带着检测框的输出图片说明环境基本没问题。这个验证步骤很值得做能提前暴露很多环境问题避免训练到一半才发现。3.2 常见环境问题排查从CUDA不可用到显存不足我遇到的第一个高频问题是torch.cuda.is_available()返回False。这种情况大概率是PyTorch版本和CUDA版本不匹配或者是PyTorch装成了CPU版本。排查方法是先看PyTorch编译时的CUDA版本再看系统实际的驱动版本python -c import torch; print(torch.version.cuda) nvidia-smi如果输出里cuda版本是11.8但驱动支持的是12.x通常也没问题PyTorch的CUDA版本要求的是驱动支持的下限不是精确对应。真正要注意的是PyTorch本身是不是带CUDA支持的版本如果pip list里显示的torch后面没有cu118之类的后缀很可能是CPU版本需要重装。第二个高频问题是显存不足CUDA out of memory。这通常发生在batch size设置得过大、图片分辨率太高或者模型尺寸选得太大的时候。我刚开始训练时用YOLOv5x模型、batch size设为32、图片分辨率640直接OOM。解决思路有三个降低batch size、降低图片分辨率、换小一点的模型。优先建议降batch size同时配合梯度累积来保持训练稳定性YOLOv5本身没有直接暴露梯度累积参数但可以通过脚本实现或者直接买更大显存的卡。3.3 YOLOv5权重选择从预训练权重到自训练权重训练前要选择初始权重。YOLOv5官方提供了s、m、l、x四个尺寸的预训练权重分别在COCO数据集上训练过。选择原则是算力够、追求精度就选l或x部署到边缘设备、追求速度就选s或m。对于果蔬识别我的建议是从yolov5s.pt或yolov5m.pt开始。果蔬检测不是超高难度的任务s模型在640分辨率下已经有不错的精度训练速度快迭代效率高适合做实验验证。先把流程跑通、数据验证合理再换大模型追求上限。如果一开始就用x模型训练一次要好几个小时调参效率太低。断点续训也是一个很实用的功能。在train.py里设置了resume参数后可以从上次保存的last.pt继续训练。我在调整超参数或者中途发现问题时经常用到不用从头开始。4. 模型训练与超参数调优让果蔬识别模型真正好用4.1 训练命令与核心参数的选择逻辑YOLOv5的训练命令本身不复杂但每个参数背后的含义要想清楚我重点说几个影响最大的参数。python train.py --data data.yaml --weights yolov5s.pt --img 640 --batch-size 16 --epochs 100 --name fruit_exp--data指定数据集配置文件--weights指定预训练权重--img是输入图片分辨率。分辨率这里有个权衡分辨率越高小目标检测效果越好但显存占用和推理耗时也同步增加。果蔬检测一般用640就够了如果图像中目标偏小可以试试960但训练时间会明显增加。--batch-size影响训练稳定性和显存占用。batch size太小梯度方向波动大训练不稳定太大又容易OOM。YOLOv5官方建议根据显存大小调整一般8到32之间比较合适。如果显存不够又想要大batch size的效果可以适当降低分辨率来平衡。--epochs是训练轮数。不是越大越好关键看验证集上的表现是否还在提升。我一般先训100轮看趋势如果后面几十轮mAP还在涨就继续训如果已经收敛就停下来避免过拟合。YOLOv5训练过程中会自动保存效果最好的权重best.pt和最后一轮的权重last.pt。4.2 超参数文件解读与实战调整YOLOv5的超参数在data/hyps/hyp.scratch-low.yaml这类文件里默认参数对大多数场景已经适用但理解它们能帮你针对特定数据做优化。我挑几个对果蔬识别影响比较大的说明。lr0是初始学习率默认0.01。学习率太大容易震荡不收敛太小收敛慢。YOLOv5有warmup机制训练刚开始的几个epoch会用较小的学习率预热再逐渐升到设定值这个机制能避免前期梯度爆炸。果蔬数据集如果比较小可以把初始学习率适当调低。momentum是动量默认0.937控制梯度更新的平滑程度一般不用动。weight_decay是权重衰减默认0.0005用来防止过拟合如果训练集比较小可以适当加大。box_loss、cls_loss、dfl_loss的权重参数控制不同损失项对总损失的贡献。果蔬识别的类别数少cls_loss的权重可以保持默认如果某些类别经常被混淆可以适当提高cls_loss权重。我实际调参的过程中最常用的操作是先把epochs设小跑通流程确认数据集没问题然后按默认参数完整训练观察Loss和mAP曲线最后根据曲线形态针对性地调学习率或数据增强参数。不建议一上来就大改超参数默认参数是经过大量任务验证的起点先跑出来一个baseline再优化效率最高。4.3 训练过程监控与模型评估指标解读训练过程中的输出信息很多人只看loss其实有几个指标要结合起来看。第一是box_loss反映预测边界框的回归误差应该随训练逐步下降并趋于平稳。第二是cls_loss反映分类误差如果这个值下降缓慢可能说明数据中某些类别难分或者标注有误。第三是mAP_0.5和mAP_0.5:0.95前者是IoU阈值为0.5时的平均精度后者是0.5到0.95区间内的平均精度后者更严格对边界框质量要求更高。果蔬识别场景下mAP_0.5一般更容易达标但mAP_0.5:0.95同样值得关注——它反映的是边界框定位的精细程度。如果是做智能结算台框的位置不够准或者框比实际果蔬大了一圈业务上是不能接受的。所以训练时我习惯用mAP_0.5:0.95作为主要优化目标这样能逼着模型把边界框学得更准。训练完成后可以跑一次验证看每个类别的详细表现python val.py --data data.yaml --weights runs/train/fruit_exp/weights/best.pt输出里会有一个per-class的表格列出每个类别的精确率、召回率和mAP。如果某个类别明显比其他类低就去检查这个类别的样本数量是不是太少或者样本间差异是不是太大。果蔬识别中经常出现的情况是某种水果外观差异很大比如苹果有红的有绿的如果训练数据里分布不均匀模型就容易在这个类别上掉点。5. 推理部署与效果优化从能用到好用5.1 图片与视频流的实时检测训练好模型后第一步是用detect.py做推理验证python detect.py --weights runs/train/fruit_exp/weights/best.pt --source test.jpg --conf-thres 0.25 --iou-thres 0.45--conf-thres是置信度阈值只有置信度高于这个值的目标才会被输出。0.25是默认值如果误检较多就调高一点比如0.4如果漏检较多就调低一点。果蔬识别中如果不同类别之间外观相近容易产生低置信度的误检这时候适当提高阈值是有效的。--iou-thres是NMS的IoU阈值。多个检测框重叠时NMS负责保留置信度最高的框、抑制其他框。果蔬堆叠场景下i还有附近的框可能重叠比较多IoU阈值太高容易把本应保留的不同目标框也抑制掉太低又会出现同一个目标多个框的情况。默认0.45在多数场景下够用具体可以多测几组。对实时视频流YOLOv5也支持直接读取摄像头或视频文件python detect.py --weights runs/train/fruit_exp/weights/best.pt --source 00表示读取本地默认摄像头也可以传视频文件路径。实际部署时如果追求实时性建议用TensorRT做加速YOLOv5官方提供了导出脚本python export.py --weights best.pt --include engine --device 0TensorRT优化后的模型在推理速度上提升非常明显尤其是部署到NVIDIA Jetson系列设备上几乎是必须的。5.2 模型导出与嵌入式部署经验部署到嵌入式设备是果蔬识别项目里很常见的一步。比如在RK3568这类边缘计算盒子上部署一般有两种可行方案一种是直接加载ONNX模型用RKNN-Toolkit转成RKNN格式另一种是先用TensorRT在自带GPU的设备上优化再迁移。选择方案取决于目标平台的算力架构。相比直接跑PyTorch模型把模型转成ONNX是最稳妥的中间步骤。YOLOv5的export.py支持导出ONNX格式之后用ONNXRuntime做推理速度就有明显提升。导出的过程中会遇到一些算子在转换时不兼容的问题YOLOv5在这块已经处理得相对完善但偶尔也需要固定输入尺寸、去掉不必要的动态维度这些在export脚本里都有对应参数。嵌入式部署的核心矛盾是精度和速度的平衡。我一般先在目标设备上测试YOLOv5s和YOLOv5m两个模型的推理耗时再对比它们的mAP差异选择一个在算力范围内精度尽量高的方案。有时候还需要降低输入分辨率来满足实时性要求比如从640降到480或416精度会有一定损失但速度提升明显具体取舍取决于业务场景。5.3 部署时需要注意的内存与线程问题嵌入式设备部署时内存管理和线程调度是很容易被忽视的坑。模型加载到内存后要常驻避免每次推理都重新加载——这个开销非常大。推理时的预处理图像缩放、归一化和后处理NMS也最好用线程池或者流水线的方式去优化避免线程频繁创建和销毁带来的性能损耗。另外要注意的是嵌入式设备上CPU推理时线程数的设置要合理。设太多线程会导致上下文切换开销反而变大我一般先测试单线程、双线程、四线程的性能曲线找到一个最优线程数。YOLOv5在推理时可以通过参数指定线程数而不是全由运行时决定。6. 常见问题与排查技巧实录6.1 训练不收敛或Loss上升的问题排查训练中遇到Loss不降反升是最让人头疼的情况。我排查的顺序是先看数据集有没有问题再看超参数和权重的设置。数据集问题的典型表现是标注文件与图片不对应、类别id超出范围、某些图片没有对应的标注文件但没有被过滤掉。YOLOv5在训练开始时会自动检查并丢弃一些无效样本但如果数据量大可能有部分异常数据没被识别出来。我写过一个脚本遍历所有标注文件检查每个框的坐标是否在合法范围内、类别id是否在类别列表内提前把问题数据清理掉。超参数的问题更常见。学习率设置太大是Loss不降反升的最常见原因这时候可以把lr0从0.01降到0.001试试。batch size过小也可能导致训练不稳定如果显存允许尽量保证batch size不小于8。还有一个容易忽略的情况是预训练权重没加载成功——建议每次训练前确认一下模型加载时是否有Transferred X items from...的输出如果没有说明预训练权重加载有问题从头训练的模型收敛会慢很多。6.2 样本不均衡的处理思路与效果果蔬识别中样本不均衡是非常常见的。比如苹果的样本很多杨桃的样本很少模型就会偏向学苹果的特征杨桃的检准率和召回率都上不去。我当时遇到的情况是某些品类样本数量差距接近10倍直接导致少数类别基本检不出来。处理方法有几种。最简单的是先看数据分布对样本少的类别做反复增强提高这部分样本在训练中的出现频率。YOLOv5支持每个类别单独设置采样权重但需要脚本配合。还有一种做法是调节class weights参数让少数类别的损失权重更高强制模型更重视这些类别。从效果来说提升少数类别的召回率最有效的方式还是补充数据。如果补数据不现实再用增强和权重调整去缓解。注意不要过分加大少数类别的权重否则容易过拟合到这些样本上训练集上表现很好一换场景就露馅。6.3 检测结果中误检与漏检的调试经验实际部署中最影响体验的是误检和漏检。误检表现为把背景当成果蔬或者把A果蔬错认为B果蔬漏检表现为画面中明明有果蔬但没有识别出来。误检的第一排查方向是置信度阈值——调高一点很多低置信度的误检框就没了。如果调高阈值后误检还是很多那就需要看训练数据里有没有容易混淆的负样本。我遇到过的情况是背景中跟果蔬颜色相似的物体比如红色塑料袋、圆形贴纸经常被检成苹果或番茄。解决办法是专门采集一批包含类似干扰物的负样本图片标注为空背景加入训练集让模型学会区分像苹果但不是苹果的物体。漏检的排查思路略有不同。先看漏检的目标在图上是否太小如果是小目标漏检可以尝试提高输入分辨率或者单独用小目标增强策略。再看漏检场景的光照条件是否与训练数据差异很大如果是光照问题可以通过补充对应光照条件下的数据或加大HSV增强来解决。还有一类漏检跟遮挡有关多个果蔬互相遮挡严重时模型可能只检出一部分。这种情况可以调整NMS的阈值但也可能只能靠增加遮挡样本的数据来解决。6.4 常见问题速查表问题现象可能原因排查与解决方案CUDA不可用PyTorch版本与CUDA不匹配重装匹配的PyTorch确认torch.cuda.is_available()为True显存溢出batch size过大或分辨率过高降低batch size和分辨率或换更小的模型Loss不降反升学习率过大调低lr0从0.01降到0.001某个类别效果差样本不均衡补充数据、增大该类别增强强度、调节类别损失权重误检多置信度阈值太低或负样本干扰调高conf-thres补充负样本数据小目标漏检输入分辨率不足提高--img分辨率或使用小目标增强策略部署推理慢模型过大或线程配置不当换小模型、导出TensorRT/ONNX、调整线程数写在最后的实操心得这个果蔬识别项目做下来我最大的体会是目标检测项目的难点往往不在模型本身而在于数据质量和调试的耐心。YOLOv5把训练和部署的工具链做得足够完善真正拉开效果差距的是你是否把数据准备做到位、是否能从训练日志和验证结果里读出问题所在。如果让我给正在做类似项目的朋友一个建议那就是不要急着调模型结构、换新算法先把数据集质量搞好、把训练流程的每个环节理解透效果会比你想象中提升得更快。另外每训练完一版模型记得把训练参数、数据版本、效果指标记录下来方便后续回溯对比。这个习惯能帮你少走很多弯路。本文还有配套的精品资源点击获取

最新新闻

日新闻

周新闻

月新闻