news 2026/10/2 18:18:14

yolov5果蔬识别数据集实战:从标注到产线部署避坑指南

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
yolov5果蔬识别数据集实战:从标注到产线部署避坑指南

简介:这是一套面向计算机视觉初学者与深度学习实践者的YOLOv5果蔬识别完整项目资源,围绕土豆、圣女果、大白菜、大葱、梨、胡萝卜、芒果、苹果、西红柿、韭菜、香蕉、黄瓜等十余类常见果蔬的检测任务展开,可用于课程设计、毕业设计或算法入门练手。压缩包共56个文件,约94.07MB,包含14个Python脚本、12个PNG与9个JPG及6个JPEG图像、6个TXT说明、4个XML标注、2个H5权重文件,以及Markdown文档和工程配置,覆盖数据读取、图像预处理、模型训练与实时检测等环节。资源中提供了CNN与MobileNet两套训练流程、热力图与训练过程记录、测试记录及模型权重,便于读者对照复现训练曲线、分析检测效果并理解迁移学习思路。目前已有3769人学习下载,适合希望快速跑通YOLOv5果蔬识别全流程、积累数据集处理与模型调优经验的读者参考。

1. 果蔬识别为什么总在产线翻车:从 yolov5 数据集到落地的第一道坎

做过分拣线视觉项目的人都有个共识:模型在实验室里 mAP 跑到 0.9 不难,难的是到了现场,光照一变、果子一叠、品种一换,识别率直接掉到六成。果蔬识别这个场景看着简单——不就是把苹果、橘子、西红柿分出来吗——但真正卡住工程进度的,往往不是网络结构,而是数据集的质量和标注的一致性。yolov5 果蔬识别数据集系统这套东西,核心价值就在于把「数据采集、标注规范、训练配置、推理部署」串成一条能复现的链路,而不是丢给你一个裸模型让你自己猜怎么用。

这套方案适合谁?一是做农业分拣、冷链质检、智能称重这类项目的工程师,需要快速搭一个能识别常见果蔬的基线;二是学生或转行者,想拿一个完整的数据集加代码加教程跑通目标检测全流程,作为 yolov5 训练自己数据集的练手项目。它解决的不是「从零发明算法」的问题,而是「让你在两天内拥有一套可用的果蔬检测基线,并且知道每一步为什么这么设」的问题。下面按数据、训练、调参、部署、避坑的顺序,把这条链路拆开讲。

2. 果蔬数据集怎么建:从采集到 YOLO 格式的完整链路

2.1 果蔬数据集的类别设计与采集边界

很多人拿到「果蔬识别数据集」第一反应是类别越多越好,恨不得把菜市场所有品类都塞进去。这是典型的翻车起点。类别一多,类间差异变小(比如青椒和尖椒、红富士和黄元帅),标注难度和模型混淆率同时飙升。我一般建议第一版控制在 8 到 15 类,选类间外观差异明显的品种,比如苹果、香蕉、橙子、西红柿、黄瓜、胡萝卜、土豆、洋葱这种。

采集时要盯住三个边界条件。第一是光照:产线常见的是顶部条形光源和侧向补光,数据集里必须包含这两种光照下的样本,否则模型会把「阴影方向」当成类别特征。第二是遮挡与堆叠:果蔬在传送带上经常互相压着,标注时对遮挡超过 50% 的目标要么标要么弃,但规则必须全数据集统一。第三是背景:纯色背景训练出来的模型换到木框、塑料筐、金属台面上会崩,采集时背景要覆盖实际工位的主要材质。

一个常被忽略的点是负样本。传送带空转、包装箱、人手入镜这些画面要单独收集一批,作为背景图参与训练,能显著降低误检。常见做法是负样本占总量 5% 到 10%。

2.2 标注规范:YOLO 格式的四个硬性约定

yolov5 用的是 YOLO 格式标注,每张图对应一个同名 txt 文件,每行一个目标,格式是:

<class_id> <x_center> <y_center> <width> <height>

四个坐标都是归一化到 0 到 1 的相对值,不是像素。这一点新手最容易搞错,直接把像素坐标写进去,训练时 loss 不降,排查半天才发现是格式问题。

标注工具有 LabelImg、CVAT、Roboflow 等,选哪个不影响结果,关键是导出时选 YOLO 格式。标注规范我一般定四条:框要贴紧目标外轮廓,不留大边距;被遮挡目标按可见部分标注,不脑补完整轮廓;同类目标框的大小风格要一致,避免有人标大有人标小;每标完 200 张做一次交叉复核,抽检 10%。

下面是一个把 LabelImg 的 VOC 格式转成 YOLO 格式的脚本,实际项目里经常遇到标注同学导出错格式的情况:

import os import xml.etree.ElementTree as ET # 类别映射,必须和 data.yaml 里的 names 顺序一致 classes = ["apple", "banana", "orange", "tomato", "cucumber"] def convert(size, box): # size: (w, h) 图像宽高; box: (xmin, xmax, ymin, ymax) dw, dh = 1.0 / size[0], 1.0 / size[1] x = (box[0] + box[1]) / 2.0 y = (box[2] + box[3]) / 2.0 w = box[1] - box[0] h = box[3] - box[2] return x * dw, y * dh, w * dw, h * dh def convert_annotation(xml_path, out_dir, img_w, img_h): tree = ET.parse(xml_path) root = tree.getroot() base = os.path.splitext(os.path.basename(xml_path))[0] with open(os.path.join(out_dir, base + ".txt"), "w") as f: for obj in root.iter("object"): cls = obj.find("name").text if cls not in classes: continue # 跳过未定义类别,避免训练时报 index 越界 cls_id = classes.index(cls) bnd = obj.find("bndbox") box = (float(bnd.find("xmin").text), float(bnd.find("xmax").text), float(bnd.find("ymin").text), float(bnd.find("ymax").text)) bb = convert((img_w, img_h), box) f.write(f"{cls_id} {' '.join([f'{v:.6f}' for v in bb])}\n")

逻辑说明:convert函数把像素坐标转成归一化中心点加宽高,这是 YOLO 格式的核心。classes列表的顺序决定了 class_id,必须和训练时 data.yaml 的 names 完全对应,顺序错一位整个模型就废了。参数上img_w、img_h要从对应图片读取,不能写死,因为数据集里图片尺寸往往不统一。

2.3 数据集划分与 data.yaml 配置

划分比例常规是训练集 70%、验证集 20%、测试集 10%。但果蔬场景有个坑:如果同一批采集的图片(同一时间段、同一光照)被随机打散到训练和验证集,验证指标会虚高,因为验证集和训练集太像了。正确做法是按采集批次划分,让验证集来自不同批次,这样指标才反映真实泛化能力。

目录结构建议:

dataset/ images/ train/ val/ test/ labels/ train/ val/ test/ data.yaml

data.yaml 内容:

path: ./dataset train: images/train val: images/val test: images/test nc: 5 names: ["apple", "banana", "orange", "tomato", "cucumber"]

nc是类别数,必须和 names 长度一致。path用相对路径时,训练命令要在 dataset 同级目录执行,否则 yolov5 找不到图片。这个路径问题在 yolov5 环境配置阶段坑了无数人,报错通常是「No labels found」或者「Dataset not found」。

3. yolov5 训练果蔬数据集的参数怎么设

3.1 环境配置与最小可跑命令

环境这块,conda 建虚拟环境是最稳的。Python 版本选 3.8 到 3.10,torch 版本跟 CUDA 对齐。常见做法是:

conda create -n yolo python=3.9 conda activate yolo pip install torch torchvision --index-url https://download.pytorch.org/whl/cu118 pip install -r requirements.txt

cu118对应 CUDA 11.8,具体选哪个看你的显卡驱动支持的 CUDA 版本,用nvidia-smi查。装完验证:

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

输出 True 才算环境通了。这一步不过,后面训练全是 CPU 在跑,一个 epoch 能等到你怀疑人生。

最小训练命令:

python train.py --data dataset/data.yaml --weights yolov5s.pt --epochs 100 --batch-size 16 --img 640

--weights yolov5s.pt是加载预训练权重做迁移学习,果蔬数据集通常几千张图,从零训练收敛慢且容易过拟合,用预训练权重是标配。--img 640是输入分辨率,果蔬目标如果比较小(比如樱桃、小番茄),可以提到 960 或 1280,但显存占用会翻倍。

3.2 关键超参数:学习率、batch size 与 anchor

yolov5 的超参数默认值对通用数据集调得不错,但果蔬场景有两三个参数值得动。

学习率--lr0默认 0.01,配合 SGD 优化器。如果数据集小于 2000 张,建议降到 0.001 到 0.005,避免早期震荡。batch size 受显存限制,16 是 8G 显存的稳妥值,显存够就往上加,batch 大梯度稳,但太大泛化会略降。

anchor 这块,yolov5 训练时会自动用 k-means 重新聚类 anchor,所以一般不用手动设。但如果你的果蔬目标尺寸特别集中(比如全是直径 5 到 8 厘米的果子),可以跑一次python utils/autoanchor.py看聚类结果,确认默认 anchor 是否匹配。

数据增强参数里,--mosaic默认开启,把四张图拼一张,对小目标检测帮助大。但果蔬堆叠场景下,mosaic 可能把遮挡关系搞得更乱,如果发现验证集掉点,可以试--mosaic 0关掉对比。--degrees旋转增强默认 0,果蔬在传送带上方向随机的话,可以开到 10 到 15 度。

3.3 训练过程监控与早停判断

训练启动后看runs/train/exp/下的结果。重点盯三个指标:metrics/mAP_0.5、train/box_loss、val/box_loss。

正常情况 mAP 在前 20 个 epoch 快速上升,之后放缓。如果 train loss 降但 val loss 升,是过拟合,加数据或加--dropout。如果两个 loss 都不降,检查学习率是不是太大,或者标注格式是不是错了。

yolov5 自带早停,--patience默认 100,意思是 100 个 epoch 没提升就停。实际项目里我一般设 30 到 50,省时间。训练完最好的权重是best.pt,不是last.pt,部署时别拿错。

验证命令:

python val.py --data dataset/data.yaml --weights runs/train/exp/weights/best.pt --img 640

会输出每类的 P、R、mAP。如果某一类特别低,回去看那一类的标注量和标注质量,八成是样本太少或框得不准。

4. 推理部署:从 PyTorch 权重到产线可用

4.1 本地推理与批量测试

训练完先本地跑推理确认效果:

python detect.py --weights runs/train/exp/weights/best.pt --source test_images/ --img 640 --conf 0.4

--conf 0.4是置信度阈值,低于这个值的框不输出。果蔬分拣场景对误检容忍度低(把好果子判成坏的损失大),阈值可以提到 0.5 到 0.6;对漏检容忍度低(坏果子漏过去)则降到 0.3。这个值要拿实际产线图片调,没有万能值。

--source可以是单张图、文件夹、视频,甚至摄像头编号。批量测试时输出在runs/detect/exp/。

4.2 导出 ONNX 与推理加速

产线部署很少直接用 PyTorch,一般导出 ONNX 或 TensorRT。ONNX 通用性好:

python export.py --weights best.pt --include onnx --img 640 --batch 1

--batch 1是推理时的 batch,产线通常单张流式处理。导出后可以用 onnxruntime 验证:

import onnxruntime as ort import numpy as np sess = ort.InferenceSession("best.onnx") # yolov5 输入是 1x3x640x640,归一化到 0-1 img = np.random.rand(1, 3, 640, 640).astype(np.float32) outputs = sess.run(None, {sess.get_inputs()[0].name: img}) print(outputs[0].shape) # 应为 (1, 25200, 5+nc)

输出维度里 25200 是三个检测层的 anchor 总数,5+nc是 xywh 加置信度加类别概率。后处理要做 NMS,这部分 yolov5 的utils/general.py里有现成实现,移植时直接抄。

如果产线用树莓派 5 这类边缘设备,ONNX 加 onnxruntime 是可行路线,但帧率有限,640 输入大概几帧到十几帧,具体看模型大小。要提速就换 yolov5n 或 yolov5s,或者降输入到 416。

4.3 部署时的预处理一致性

这是血泪经验:训练时的预处理和推理时的预处理必须完全一致。yolov5 训练时做了 letterbox 缩放(保持长宽比,短边补灰),推理时如果直接 resize 拉伸,长宽比变了,框会偏。很多人本地测好好的,部署后框全歪,就是栽在这。

letterbox 的核心是算缩放比例取 min,然后补边到目标尺寸。移植到 C++ 或其他语言时,这段逻辑要一比一复刻,包括补边的灰度值 114。差一点,精度就掉。

5. 果蔬识别避坑清单:五个真实踩过的坑

5.1 坑一:验证集 mAP 很高,上线就崩

现象:本地 val mAP 0.92,产线实测识别率不到 70%。

原因:验证集和训练集来自同一批采集,光照、背景、角度高度相似,模型记住了这批数据的「风格」而不是果蔬特征。

解决:按采集批次划分数据集,验证集必须包含训练时没见过的光照和背景。有条件的话,留一批现场实拍图做最终测试,不参与任何训练调参。

5.2 坑二:某一类识别率奇低

现象:苹果、香蕉都 0.9 以上,西红柿只有 0.4。

原因:要么西红柿样本量远少于其他类,要么标注时把西红柿和红苹果混标了,要么这一类的外观差异本身就小(比如不同成熟度的西红柿)。

解决:先统计各类样本数,少于 300 张的类补采。再看混淆矩阵,如果西红柿大量被预测成苹果,说明类间差异不够,考虑合并类别或加更多区分性样本。成熟度差异大的话,可以拆成「青西红柿」「红西红柿」两类。

5.3 坑三:训练 loss 不降,一直震荡

现象:box_loss 在 0.1 上下跳,mAP 卡在 0.1 不动。

原因:九成是标注格式问题。常见的是坐标没归一化、class_id 从 1 开始(YOLO 要求从 0)、txt 文件和图片没对应上。

解决:写个校验脚本,遍历所有 label 文件,检查每行是否 5 个值、坐标是否在 0 到 1 之间、class_id 是否小于 nc。跑一遍就能揪出问题文件。

5.4 坑四:显存溢出(CUDA out of memory)

现象:训练几个 batch 后报 OOM。

原因:batch size 太大、img 分辨率太高、或者 dataloader 的 workers 太多导致内存泄漏。

解决:先降 batch size 到 8 试,再降 img 到 416。--workers设 4 到 8 就行,设太大反而抢内存。如果还不行,用--accumulate梯度累积,小 batch 模拟大 batch 效果。

5.5 坑五:导出 ONNX 后精度掉点

现象:PyTorch 权重 mAP 0.9,ONNX 推理结果明显变差。

原因:导出时的 opset 版本不兼容,或者后处理 NMS 的参数和训练时不一致。

解决:导出加--opset 12,别用太新的 opset。NMS 的 iou 阈值和 conf 阈值要和 PyTorch 推理时对齐。导出后用同一批图分别跑 PyTorch 和 ONNX,逐张对比框,定位差异。

6. 把果蔬识别做到产线级:一个提精度的小技巧

前面讲的都是标准流程,最后说一个我在实际项目里反复验证有效的技巧:用测试集反推标注质量,而不是只看 mAP。

具体做法是,训练完后拿测试集跑推理,把预测框和标注框叠在原图上可视化,人工过一遍。你会看到两类问题:一是标注框本身歪了或松了,模型学了个错的;二是模型预测的框比标注框更贴合目标,说明标注拖了模型后腿。这个动作做一轮,回去修 50 到 100 张标注,再训练,mAP 通常能涨 2 到 5 个点,比调超参数见效快。

可视化脚本核心逻辑:

import cv2 def draw_boxes(img_path, label_path, pred_path=None): img = cv2.imread(img_path) h, w = img.shape[:2] with open(label_path) as f: for line in f: cid, xc, yc, bw, bh = map(float, line.split()) # 归一化坐标还原成像素 x1 = int((xc - bw / 2) * w) y1 = int((yc - bh / 2) * h) x2 = int((xc + bw / 2) * w) y2 = int((yc + bh / 2) * h) cv2.rectangle(img, (x1, y1), (x2, y2), (0, 255, 0), 2) # 绿框为标注 cv2.imwrite("vis_" + img_path.split("/")[-1], img)

参数说明:xc, yc, bw, bh是 YOLO 格式的归一化值,还原时分别乘宽高。绿框画标注,如果要对比预测,用红框画预测结果,叠一起看偏差。这个脚本不依赖 yolov5 框架,纯 OpenCV,方便集成到标注复核流程里。

我自己的习惯是,每完成一轮训练,必做一次可视化抽检,抽 30 张,不看完不调参。这个习惯帮我省了无数次「调了半天参数发现是标注错了」的后悔药。果蔬识别这行,数据质量的天花板就是模型精度的天花板,算法能补的很有限。希望帮到你。

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

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/2 18:16:56

AI视觉防尾随方案:从目标检测到门禁联动的落地指南

很多物业团队在防尾随这件事上&#xff0c;踩过同一个坑&#xff1a;门口已经装了高清摄像头&#xff0c;刷卡门禁也正常&#xff0c;AI人脸识别盒子也上了&#xff0c;可尾随事件依然屡禁不止。问题并不出在“看得清不清”&#xff0c;而在于摄像头只负责“看见画面”&#xf…

作者头像 李华
网站建设 2026/10/2 18:16:46

火焰烟雾数据集YOLO训练全流程指南:从解压到部署避坑

简介&#xff1a;一份面向火焰烟雾检测的YOLO数据集资源&#xff0c;图片经过人工挑选与标注&#xff0c;场景覆盖广泛&#xff0c;可直接作为通用模板数据集用于模型训练&#xff0c;也可按需加入特定场景样本&#xff0c;适合深度学习与人工智能方向的开发者及研究人员。压缩…

作者头像 李华
网站建设 2026/10/2 18:16:37

Claude Code上下文工程化:从CLAUDE.md到@引用,根治AI答非所问

用Claude Code最常遇到的尴尬&#xff0c;不是它不会写代码&#xff0c;而是你让它改登录接口&#xff0c;它反问你"登录接口在哪个文件里"。这不是模型笨&#xff0c;是它真的对你的项目一无所知。ClaudeCode实战系列走到第4篇&#xff0c;我越来越确认一件事&#…

作者头像 李华
网站建设 2026/10/2 18:14:50

基于CNN的KDD99入侵检测实战:99.5%准确率源码拆解与避坑指南

简介&#xff1a;这份资源面向计算机、网络安全方向的本科生与研究生&#xff0c;以及正在准备毕业设计或课程项目的开发者&#xff0c;提供一套基于卷积神经网络的网络入侵检测完整实现方案。项目以KDD Cup 99流量数据为基础&#xff0c;通过CNN自动提取流量中的局部特征与空间…

作者头像 李华
网站建设 2026/10/2 18:14:46

VASP与QE双引擎Python脚本:应力应变计算与弹性常数拟合实战

简介&#xff1a;这份资源面向材料科学计算方向的研究生与科研人员&#xff0c;聚焦如何用Python驱动VASP与Quantum Espresso完成应力—应变关系计算&#xff0c;解决第一性原理力学性质模拟中数据提取、处理与可视化的问题。压缩包共16个文件&#xff0c;约30KB&#xff0c;以…

作者头像 李华
网站建设 2026/10/2 18:14:22

2026年必看:七款热门AI编程工具权威横评,TaoToken统一Key接入实测

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华