ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

果蔬识别系统从零落地:YOLOv5训练链路与数据集选型实战

果蔬识别系统从零落地:YOLOv5训练链路与数据集选型实战 简介这份资源面向计算机科学与技术等相关专业的毕业设计、课程实践与综合作业场景提供一套基于YOLOv5架构的果蔬图像识别系统完整实现方案适合具备机器学习基础、希望深入理解目标检测算法落地流程的学习者。压缩包共717个文件约268.88MB以546张jpg与jpeg图像构成训练与测试数据集辅以15个py源码文件、4个h5模型权重、4个xml标注文件及若干txt说明与png可视化结果另含zbak备份文件覆盖数据预处理、模型训练到性能优化的完整链路。目前已有56人学习下载。资源在导师严格审核下获得优秀评价所有组件均经多轮验证测试运行稳定可靠读者可据此掌握果蔬类别自动化检测的实现思路并作为项目开发与研究参考。资源来源于网络分享仅用于学习交流请勿用于商业用途如有侵权请联系删除。1. 果蔬识别系统从零落地YOLOv5 训练链路与数据集选型果蔬识别这个题目每年毕业设计和课程设计都有人做但真正能跑通、能演示、能写进论文的不到三成。大部分卡在同一个地方数据集和训练链路没打通。你拿到一份标注好的果蔬数据集以为直接丢进 YOLOv5 就能出结果结果要么类别对不上要么 mAP 低得没法看要么训练到一半显存炸了。这套资源解决的就是这条链路——从数据集结构、YOLOv5 配置、训练参数到推理部署给出一套可复现的完整流程。适合正在做果蔬识别方向毕业设计的学生也适合想把 YOLOv5 目标检测落到具体场景的工程师。下面按「资源是什么 → 怎么用 → 坑在哪」的顺序拆开讲每一步都落到可执行的命令和参数上。2. 数据集结构与 YOLOv5 格式转换从原始标注到可训练目录2.1 果蔬数据集的目录组织与类别映射拿到一份果蔬数据集第一件事不是急着训练而是看清楚它的原始结构。常见做法是数据集分两类一类是已经切好 train/val 的图片文件夹加对应 txt 标注另一类是原始图片加一个总的标注文件比如 COCO json 或 csv。果蔬识别场景下类别通常包括苹果、香蕉、橙子、番茄、黄瓜、胡萝卜等类别数一般在 10 到 30 之间。你需要先确认三件事图片总数、类别列表、标注格式。YOLOv5 要求的数据集结构是固定的dataset/ ├── images/ │ ├── train/ │ └── val/ ├── labels/ │ ├── train/ │ └── val/ └── data.yaml每张图片对应一个同名 txt 文件txt 里每行格式是class_id x_center y_center width height坐标全部归一化到 0 到 1 之间。这里最容易翻车的是类别 id 从 0 开始还是从 1 开始。YOLOv5 内部从 0 开始如果你原始标注从 1 开始训练时不会报错但类别会整体偏移一位最后推理出来的标签全是错的。我一般会先写个脚本统计一遍类别分布确认 id 范围。import os from collections import Counter label_dir dataset/labels/train counter Counter() for f in os.listdir(label_dir): if f.endswith(.txt): with open(os.path.join(label_dir, f)) as fp: for line in fp: cls_id int(line.strip().split()[0]) counter[cls_id] 1 print(类别 id 分布:, dict(sorted(counter.items()))) print(最小 id:, min(counter), 最大 id:, max(counter))这段脚本遍历训练集所有标注文件统计每个类别 id 出现的次数。如果最小 id 是 1说明标注从 1 开始需要统一减 1如果出现 id 大于等于类别总数说明有脏标注得回去查。参数上只需要改label_dir指向你的标注目录即可。统计完类别分布还能顺带看出有没有严重的长尾问题——某个类别只有几十个样本训练时基本学不出来后面要在数据增强上补。2.2 标注格式转换脚本与 data.yaml 配置如果原始标注是 COCO json 或 xml需要转成 YOLO txt。以 COCO json 为例核心逻辑是读 images 和 annotations按 image_id 分组把 bbox 的[x, y, w, h]转成归一化的[x_center, y_center, w, h]。import json import os def coco2yolo(json_path, save_dir, img_dir): with open(json_path) as f: data json.load(f) # 建立 image_id 到文件名的映射 img_map {img[id]: img[file_name] for img in data[images]} # 建立 category_id 到连续 id 的映射 cat_map {c[id]: i for i, c in enumerate(data[categories])} os.makedirs(save_dir, exist_okTrue) for ann in data[annotations]: img_id ann[image_id] img_name img_map[img_id] img_w next(i[width] for i in data[images] if i[id] img_id) img_h next(i[height] for i in data[images] if i[id] img_id) x, y, w, h ann[bbox] x_center (x w / 2) / img_w y_center (y h / 2) / img_h norm_w w / img_w norm_h h / img_h cls_id cat_map[ann[category_id]] txt_name os.path.splitext(img_name)[0] .txt with open(os.path.join(save_dir, txt_name), a) as fp: fp.write(f{cls_id} {x_center:.6f} {y_center:.6f} {norm_w:.6f} {norm_h:.6f}\n) coco2yolo(annotations.json, dataset/labels/train, dataset/images/train)这段代码的关键点有三个cat_map把原始 category_id 重映射成从 0 开始的连续整数避免 id 跳号导致类别数虚高坐标归一化用图片实际宽高不能用固定值写入用追加模式因为一张图可能有多个目标。参数上json_path是 COCO 标注文件路径save_dir是输出 txt 目录img_dir用于校验图片是否存在。转换完一定要抽查几张用可视化脚本画框确认坐标没偏。data.yaml 是 YOLOv5 训练时的数据入口内容如下path: ./dataset train: images/train val: images/val nc: 12 names: [apple, banana, orange, tomato, cucumber, carrot, pepper, grape, strawberry, pear, peach, lemon]nc是类别数必须和 names 长度一致也必须和标注里最大 id 加 1 一致。这三个地方对不上训练不报错但结果全乱。我见过有人 names 写了 12 个但 nc 写的 10训练完模型只能识别前 10 类后两类永远预测不出来。3. YOLOv5 训练配置与超参数调优从环境到收敛3.1 环境配置与依赖版本锁定YOLOv5 的环境配置本身不复杂但版本兼容性是血泪经验。PyTorch 版本和 CUDA 版本必须匹配YOLOv5 不同版本对 PyTorch 最低版本要求不同。常见做法是用 conda 建一个独立环境然后按官方 requirements.txt 装依赖。conda create -n yolo5 python3.8 -y conda activate yolo5 # 安装 PyTorch根据你的 CUDA 版本选对应命令 pip install torch1.12.1cu113 torchvision0.13.1cu113 --extra-index-url https://download.pytorch.org/whl/cu113 # 克隆 YOLOv5 源码并安装依赖 git clone https://github.com/ultralytics/yolov5 cd yolov5 pip install -r requirements.txt这里有几个参数要盯住Python 用 3.8 是因为 YOLOv5 部分依赖在 3.9 以上有兼容问题PyTorch 1.12.1 配 cu113 是经过验证的稳定组合--extra-index-url指定 PyTorch 官方源避免装到 CPU 版本。装完用python -c import torch; print(torch.cuda.is_available())验证输出 True 才算环境通了。如果输出 False要么 CUDA 没装要么 PyTorch 装成了 CPU 版回去重装。3.2 训练命令与关键超参数含义YOLOv5 的训练入口是 train.py果蔬识别场景下我一般用 yolov5s 作为基线因为数据集规模通常不大s 模型在精度和速度之间平衡最好。python train.py \ --data dataset/data.yaml \ --weights yolov5s.pt \ --img 640 \ --batch 16 \ --epochs 100 \ --device 0 \ --workers 4 \ --project runs/train \ --name fruit_veggie \ --patience 20 \ --lr0 0.01 \ --lrf 0.01 \ --cos-lr逐个说参数--img 640是输入分辨率果蔬图片如果目标较小可以提到 1280但显存占用翻倍--batch 16是批大小显存不够就降到 8 或 4但太小会影响 BN 层效果--epochs 100配合--patience 20表示 20 轮没提升就早停避免过拟合--lr0 0.01是初始学习率--lrf 0.01是最终学习率比例配合--cos-lr余弦退火收敛更平滑--workers 4是数据加载线程数Windows 下建议设 0 避免多进程报错。训练过程中重点看三个指标box_loss和obj_loss是否稳定下降mAP0.5是否在上升precision和recall是否平衡。如果 loss 震荡厉害先把 batch 调大或学习率调小如果 mAP 卡在低位不动检查标注质量和类别是否混淆。果蔬识别里番茄和苹果、橙子和橘子容易混如果这两类 mAP 明显低说明特征区分度不够要么加数据要么在数据增强里加颜色抖动。3.3 数据增强策略与果蔬场景适配YOLOv5 默认开启 Mosaic、HSV 增强、随机翻转等。果蔬识别场景下Mosaic 增强对小目标友好但如果你的图片里果蔬都是大目标居中Mosaic 拼接后反而引入大量背景噪声。常见做法是训练前期开 Mosaic后期关掉让模型在真实分布上微调。# 前 80 轮开 Mosaic后 20 轮关闭 python train.py --data dataset/data.yaml --weights yolov5s.pt --img 640 --batch 16 --epochs 100 --close-mosaic 80--close-mosaic 80表示第 80 轮开始关闭 Mosaic。HSV 增强里hsv_h、hsv_s、hsv_v分别控制色调、饱和度、亮度扰动果蔬颜色是重要特征hsv_h不宜过大默认 0.015 够用调太大会让苹果变绿、香蕉变红反而干扰学习。翻转增强flipud和fliplr默认 0.5 和 0.5果蔬识别里上下翻转一般关掉因为现实中不会倒着拿水果。4. 推理部署与模型导出从权重到可用接口4.1 推理脚本与置信度阈值调节训练完得到best.pt推理用 detect.py 或自己写脚本。果蔬识别系统通常需要返回类别和位置所以直接调模型接口更灵活。import torch from PIL import Image model torch.hub.load(ultralytics/yolov5, custom, pathruns/train/fruit_veggie/weights/best.pt) model.conf 0.4 # 置信度阈值 model.iou 0.45 # NMS IoU 阈值 img Image.open(test.jpg) results model(img) results.print() results.save(output/)model.conf控制置信度阈值果蔬识别里如果漏检多就降到 0.25误检多就提到 0.5。model.iou控制 NMS 的 IoU 阈值同一类果蔬堆叠时调低到 0.4 能减少重复框。results.print()输出检测到的类别、置信度和坐标results.save()保存带框图片。参数上path指向训练好的权重test.jpg换成你的测试图。4.2 模型导出 ONNX 与推理加速如果部署到边缘设备或需要跨平台导出 ONNX 是常见做法。python export.py --weights runs/train/fruit_veggie/weights/best.pt --include onnx --img 640 --batch 1导出后得到best.onnx可以用 onnxruntime 推理。--img 640必须和训练时一致--batch 1是推理批大小。导出后建议用onnxsim简化模型去掉冗余算子。注意导出 ONNX 时如果模型里有自定义算子会失败YOLOv5 标准结构一般没问题。导出后拿一张测试图对比 PyTorch 和 ONNX 的输出如果框位置差太多检查预处理是否一致——归一化方式、通道顺序、resize 插值都要对齐。5. 避坑与常见问题排查果蔬识别训练中的五个翻车点5.1 现象训练 loss 正常下降但 mAP 始终为 0原因标注文件里的类别 id 和 data.yaml 的 names 顺序对不上或者标注坐标没有归一化。YOLOv5 不会校验这些loss 照样降但模型学的是错误映射。解决用 2.1 的统计脚本检查 id 范围用可视化脚本画框确认坐标在图片范围内。归一化坐标必须在 0 到 1 之间如果出现大于 1 的值说明转换时没除宽高。5.2 现象训练到一半显存溢出CUDA out of memory原因--img或--batch设太大或者--workers太多导致数据加载占用显存。果蔬图片分辨率高时尤其明显。解决先把 batch 降到 8 或 4再把 img 从 1280 降到 640。如果还炸用--workers 0关掉多进程加载。另外检查有没有其他进程占着 GPUnvidia-smi看一眼。5.3 现象推理时同一目标出现多个重叠框原因NMS 的 IoU 阈值设太高或者模型对同一类果蔬输出了多个高置信度框。果蔬堆叠场景下常见。解决把model.iou从 0.45 降到 0.35 到 0.4 之间增大 NMS 的抑制力度。如果还不行检查训练数据里有没有重复标注——同一目标标了两次模型会学出两个框。5.4 现象验证集 mAP 高但实际测试图效果差原因验证集和训练集分布太接近模型过拟合。果蔬识别里常见于数据集来源单一比如全是白底商品图测试时换成自然场景就崩。解决训练时留一部分不同来源的图片做验证或者在数据增强里加随机裁剪、背景替换。如果已经训完用测试图做一轮微调学习率调小到 0.001。5.5 现象ONNX 导出成功但推理结果和 PyTorch 不一致原因预处理不一致。PyTorch 推理时 YOLOv5 自动做了 letterbox resize 和归一化ONNX 推理时如果自己写预处理容易漏掉 letterbox 的 padding 或归一化系数。解决对比两边输入张量的数值确保 resize 后的尺寸、padding 值、归一化方式完全一致。常见做法是直接复用 YOLOv5 的datasets.py里的 letterbox 函数不要自己重写。6. 进阶技巧用 TensorBoard 盯住训练过程与权重选择训练不是跑完 100 轮就完事关键是知道哪一轮的权重最好。YOLOv5 默认把训练日志写到runs/train/fruit_veggie/用 TensorBoard 可以实时看曲线。tensorboard --logdir runs/train打开浏览器看mAP0.5、precision、recall三条曲线。我一般会重点看mAP0.5的峰值出现在哪一轮然后去weights/目录找对应的best.pt和last.pt。best.pt是验证集 mAP 最高的权重last.pt是最后一轮的权重。如果best.pt出现在第 60 轮而训练跑到 100 轮说明后 40 轮过拟合了下次把--patience调到 15 更早停。还有一个技巧是看val/box_loss和val/obj_loss如果训练 loss 还在降但验证 loss 开始升就是过拟合信号。果蔬识别里过拟合通常因为数据量不够解决办法不是加轮数而是加数据增强或换更小的模型yolov5n。另外如果precision高但recall低说明模型保守调低model.conf能找回一些漏检反过来recall高但precision低调高model.conf过滤误检。从那以后我每次训练完都强制走一遍 TensorBoard 看曲线确认 best.pt 的轮次和验证 loss 的拐点再决定要不要重新训。希望帮到你。本文还有配套的精品资源点击获取
返回列表