简介:这份数据集面向从事柑橘成熟度检测、目标检测算法实践与农业自动化采摘研究的开发者与学习者,提供橘子是否成熟的二分类标注数据,可直接用于YOLOv5训练,省去自行采集与标注的成本。资源共2000个文件,以1999个txt标签文件和1个Python可视化脚本为主,压缩包约79.14MB,按YOLOv5标准目录组织,包含训练集2313张图片及对应标签、验证集224张图片及对应标签,图像为640×640分辨率RGB格式,边界框标注清晰、图像完整。配套的show.py脚本无需修改即可运行,随机传入一张图片便能绘制并保存边界框,便于快速核验标注质量。目前已有435人学习下载,适合希望快速搭建成熟度检测基线、验证模型效果或开展自动采摘相关实验的读者使用。
1. 橘子成熟度检测数据集:2 类别、含训练集与验证集的 YOLOv5 落地包
果园里判断橘子熟没熟,靠人眼一颗颗看,效率低还容易因为光线、角度产生分歧。这份 YOLOv5 橘子成熟度检测数据集,把「成熟」和「未成熟」两个类别框出来,直接给到训练集和验证集,省掉自己拍图、标注、划分的前期投入。它适合三类人:想快速跑通 YOLOv5 目标检测全流程的新手、需要做农产品分拣或采摘机器人视觉模块的工程师、以及拿它当教学案例的老师。数据集本身不绑定具体硬件,PC 端训练完可以导出权重,后续往树莓派 5 或 Jetson 这类边缘设备上部署也顺理成章。下面按「拿到手怎么用 → 参数怎么调 → 坑在哪」的顺序拆开讲,每一步都落到能直接抄的命令和配置上。
2. 数据集结构与 YOLOv5 目录映射:从压缩包到 data.yaml
2.1 先看清目录长什么样
拿到数据集压缩包,解压后大概率是images和labels两个平行目录,各自再分train和val。这是 YOLO 系列最通用的组织方式,但不同来源的包偶尔会把验证集写成valid或test,直接跑会报找不到路径。我一般先tree一下确认层级,再决定要不要改名。
# 查看解压后的目录结构,-L 2 限制两层,避免输出太长 tree -L 2 orange_dataset/ # 典型输出 # orange_dataset/ # ├── images # │ ├── train # 训练集图片 # │ └── val # 验证集图片 # └── labels # ├── train # 训练集标签,与图片同名 .txt # └── val图片和标签必须同名,只是扩展名不同。比如images/train/001.jpg对应labels/train/001.txt。如果标签目录里出现classes.txt或notes.txt,那是标注工具留下的说明文件,训练时不会被读取,但建议移走,免得自己混淆。
2.2 标签格式与类别编号
YOLO 的标签是每行一个目标,格式为class_id x_center y_center width height,后四个值都是相对图片宽高的归一化坐标,范围 0 到 1。这份数据集是 2 类别,常见约定是0表示未成熟、1表示成熟,但不同标注者可能反过来。动手训练前一定先抽查几个标签文件,确认类别编号和你的预期一致,否则模型学出来的「成熟」可能是反的。
# 随机看一个训练标签,确认类别编号和坐标范围 head -n 5 orange_dataset/labels/train/001.txt # 统计两个类别各有多少个目标框,判断是否严重不平衡 cat orange_dataset/labels/train/*.txt | awk '{print $1}' | sort | uniq -c第二条命令输出类似320 0和410 1,说明两类目标数量接近,训练时不用额外做重采样。如果某一类只有个位数,就得考虑补数据或调损失权重,否则模型会偏向多数类。
2.3 写一份能直接用的 data.yaml
YOLOv5 靠一个 YAML 文件告诉训练脚本「图片在哪、有几类、类名是什么」。这份数据集只有 2 类,配置很短,但路径写错是最常见的翻车点。path用绝对路径最稳,train和val相对path写。
# orange.yaml path: /home/user/orange_dataset # 数据集根目录,按自己实际路径改 train: images/train # 训练集图片目录,相对 path val: images/val # 验证集图片目录,相对 path nc: 2 # 类别数,固定为 2 names: # 类别名,顺序必须和标签里的 class_id 对应 0: unripe # 0 号类别 1: ripe # 1 号类别nc和names的对应关系是硬约束:标签里写0,这里names的第 0 项就必须是它。改完 YAML 后,用一行 Python 验证路径是否都能读到文件,比训练到一半报错再回头查要省时间。
import yaml, os cfg = yaml.safe_load(open('orange.yaml')) root = cfg['path'] for split in ['train', 'val']: img_dir = os.path.join(root, cfg[split]) n = len([f for f in os.listdir(img_dir) if f.endswith(('.jpg', '.png'))]) print(split, img_dir, '图片数:', n)这段脚本只做一件事:把 YAML 里的路径拼出来,数一数图片数量。如果某个 split 输出 0,说明路径或扩展名不对,先解决再进训练。
3. YOLOv5 训练全流程:环境、命令与超参数
3.1 环境配置:conda 建环境 + 装依赖
YOLOv5 对 PyTorch 版本有要求,直接装在系统 Python 里容易和别的项目打架。我习惯用 conda 单独开一个环境,Python 选 3.9 或 3.10,兼容性最好。
# 创建并激活环境 conda create -n yolov5_orange python=3.9 -y conda activate yolov5_orange # 拉取 YOLOv5 源码(用官方仓库,别用来路不明的魔改版) git clone https://github.com/ultralytics/yolov5.git cd yolov5 # 安装依赖,requirements.txt 里已锁定兼容版本 pip install -r requirements.txt装完用python -c "import torch; print(torch.__version__, torch.cuda.is_available())"确认 GPU 是否可用。输出True才走 GPU 训练,False说明 CUDA 或驱动没配好,此时强行训练会用 CPU,速度慢到怀疑人生。显卡驱动和 CUDA 的匹配属于环境配置里的老坑,版本对不上就重装对应 PyTorch,别硬扛。
3.2 启动训练:一条命令和它的每个参数
YOLOv5 的训练入口是train.py,参数多但常用的就那几个。下面这条命令是我在 2 类别小数据集上的常用起点,显存 8G 左右能跑。
python train.py \ --data orange.yaml \ # 指向刚写好的数据配置 --weights yolov5s.pt \ # 用官方预训练权重,小数据集必须迁移学习 --img 640 \ # 输入分辨率,橘子目标不大时 640 够用 --batch 16 \ # 批大小,显存不够就降到 8 --epochs 100 \ # 训练轮数,2 类别通常 100 轮内收敛 --device 0 \ # 用第 0 号 GPU,CPU 训练去掉这行 --project runs/train \ # 结果输出根目录 --name orange_exp # 本次实验名,结果存到 runs/train/orange_exp--weights yolov5s.pt是关键。数据集规模有限时,从零训练几乎不可能收敛到可用精度,用 COCO 预训练权重做迁移学习,通常 20 轮内就能看到 mAP 明显上升。--img 640是速度和精度的折中,如果橘子在高空俯拍图里占比很小,可以提到 1280,但显存占用会翻倍,batch 要相应下调。
训练过程中终端会打印每一轮的 box_loss、obj_loss、cls_loss 和 mAP。重点看验证集的 mAP@0.5,它在runs/train/orange_exp/results.csv里也有记录。如果 loss 一直不降,先查标签格式;如果 mAP 卡在低位,多半是学习率或数据量的问题。
3.3 超参数怎么调:别一上来就动默认值
YOLOv5 的超参数集中在data/hyps/hyp.scratch-low.yaml,训练时可以用--hyp指定。新手最容易犯的错是还没跑通基线就大改超参数,结果连问题出在哪都不知道。我的做法是先跑一轮默认,拿到基线 mAP,再针对性调。
| 参数 | 默认值 | 作用 | 什么时候改 |
|---|---|---|---|
| lr0 | 0.01 | 初始学习率 | mAP 震荡大就降到 0.001 |
| lrf | 0.01 | 最终学习率系数 | 一般不动 |
| momentum | 0.937 | 优化器动量 | 一般不动 |
| weight_decay | 0.0005 | 权重衰减 | 过拟合时加到 0.001 |
| warmup_epochs | 3.0 | 预热轮数 | 小数据集可降到 1.0 |
| box | 0.05 | 框回归损失权重 | 定位不准时适当加大 |
2 类别、几千张图的规模,默认超参数基本够用。真正影响结果的是数据质量:标注框是否贴合、有没有漏标、训练集和验证集是否同分布。我见过 mAP 上不去的案例,最后查出来是验证集里混进了训练集图片,等于开卷考试,指标虚高但实际部署拉胯。
3.4 推理验证:拿图片和视频试效果
训练完权重存在runs/train/orange_exp/weights/best.pt。用detect.py跑几张验证集外的图片,看实际效果。
# 对单张图片推理,--conf 设置信度阈值 python detect.py \ --weights runs/train/orange_exp/weights/best.pt \ --source test_orange.jpg \ --conf 0.4 \ # 低于 0.4 的框不显示,减少误检 --img 640 \ --device 0结果默认存到runs/detect/exp/。--conf 0.4是经验值,漏检多就降到 0.25,误检多就提到 0.5。这个阈值没有标准答案,取决于你更怕漏检还是更怕误检——分拣线上误检一颗青橘可能只是浪费,漏检一颗熟橘混进青果筐就是品质事故,所以场景决定阈值。
4. 避坑与排查:训练不收敛、路径报错、显存爆了怎么办
4.1 报错「No labels found」或 mAP 恒为 0
现象:训练能启动,但日志里提示找不到标签,或者跑完 mAP 一直是 0。原因:九成是标签路径和图片路径没对上。YOLOv5 默认把images替换成labels来找标签,如果你的目录结构不是images/和labels/平行,就会找不到。解决:确认images/train/001.jpg对应labels/train/001.txt,且标签文件不是空的。用ls labels/train | wc -l和ls images/train | wc -l对比数量,不一致就说明有图片没标签。
4.2 显存不足「CUDA out of memory」
现象:训练几轮后突然报显存溢出,或者一开始就崩。原因:--batch或--img设太大,或者没有用--device指定单卡导致多卡分摊异常。解决:先把 batch 减半,比如 16 降到 8;还不行就把--img从 640 降到 416。另外 YOLOv5 有--cache选项,开了会把图片缓存到内存,内存不够也会崩,小内存机器别开。
4.3 类别编号反了,成熟橘子被识别成未成熟
现象:推理结果里类别名和实际对不上,熟橘标成 unripe。原因:标签里的0/1和data.yaml里names的顺序不一致,或者标注时约定就反了。解决:抽查标签文件,确认0对应哪一类,然后改names的顺序去匹配标签,而不是改标签去匹配 names——改标签要动所有文件,改 YAML 只动两行。
4.4 验证集指标虚高,实际部署一塌糊涂
现象:训练日志里 mAP@0.5 到 0.95,换真实场景图片却大量漏检。原因:训练集和验证集同分布,但和真实场景不同分布。比如数据集都是晴天顺光拍摄,真实果园有逆光、遮挡、阴天。解决:从真实场景补拍一批图,人工标注后加进验证集,重新评估。如果指标掉得厉害,说明模型泛化不够,需要扩充训练数据的场景多样性,而不是继续调超参数。
4.5 训练中断后想接着跑
现象:跑到一半断电或手动停了,不想从头再来。原因:没保存断点或不知道怎么恢复。解决:YOLOv5 每轮都会存last.pt,用--resume runs/train/orange_exp/weights/last.pt就能从断点继续。注意--resume后面跟的是权重文件路径,不是实验目录,写错会重新开始。
5. 从训练到部署:导出 ONNX 与树莓派 5 上的推理技巧
训练出best.pt只是第一步,真正落地往往要往边缘设备搬。树莓派 5 这类设备算力有限,直接跑 PyTorch 权重帧率很难看,常见做法是先导出 ONNX,再用 ONNX Runtime 推理。导出命令很短,但有几个参数决定后续能不能顺利跑起来。
# 导出 ONNX,--imgsz 必须和训练时一致 python export.py \ --weights runs/train/orange_exp/weights/best.pt \ --include onnx \ # 导出格式 --imgsz 640 640 \ # 输入尺寸,和训练保持一致 --opset 12 \ # ONNX 算子集版本,12 兼容性好 --simplify # 简化计算图,减小模型体积导出后在树莓派上装onnxruntime,用下面这段代码做推理。注意输入要做和训练时相同的预处理:缩放、归一化、通道顺序调整,任何一步不一致都会导致结果离谱。
import onnxruntime as ort import numpy as np import cv2 # 加载 ONNX 模型,树莓派上建议用 CPU 执行提供者 sess = ort.InferenceSession("best.onnx", providers=["CPUExecutionProvider"]) input_name = sess.get_inputs()[0].name img = cv2.imread("test_orange.jpg") img = cv2.resize(img, (640, 640)) img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) # YOLOv5 训练用 RGB img = img.transpose(2, 0, 1).astype(np.float32) / 255.0 # HWC 转 CHW 并归一化 img = np.expand_dims(img, axis=0) # 加 batch 维度 outputs = sess.run(None, {input_name: img}) print(outputs[0].shape) # 输出形状 (1, 25200, 7),含框坐标、置信度和类别树莓派 5 上跑 640 输入的 YOLOv5s,单帧大概几百毫秒,做静态图片分拣够用,做实时视频就得降分辨率或换更小的模型。我一般会先把--imgsz降到 416 试一版,看精度掉多少,再决定要不要为了帧率牺牲精度。另一个常被忽略的点是后处理:ONNX 输出的是原始预测,非极大值抑制(NMS)要自己写或在导出时带上,否则同一个橘子会出一堆重叠框。
从那以后我每次导出 ONNX,都会先在 PC 上用同一张图对比 PyTorch 和 ONNX 的输出,确认数值接近再往设备上搬,省得在树莓派上反复排查是模型问题还是环境问题。希望帮到你。
本文还有配套的精品资源,点击获取