news 2026/9/27 3:38:15

橘子成熟度检测数据集:YOLOv5二分类训练与验证全流程

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
橘子成熟度检测数据集:YOLOv5二分类训练与验证全流程

简介:这份数据集面向从事柑橘采摘自动化、农业视觉检测的开发者与研究者,提供橘子成熟度二分类目标检测所需的完整标注数据,可直接接入YOLOv5训练流程,省去自行采集与标注的成本。包内共约2000个文件,以txt标注文件为主,另附一个可视化脚本,压缩包整体约79MB,按YOLOv5标准目录组织,训练集含2313张图片及对应标签,验证集含224张图片及对应标签,图像为640×640分辨率RGB格式,边界框标注清晰、图像完整。类别仅成熟与未成熟两类,标签文本简洁明确。附带的Python可视化脚本无需修改,随机传入一张图片即可绘制边界框并保存到当前目录,便于快速核验标注质量。目前已有435人学习下载,适合需要快速验证成熟度检测模型或搭建自动采摘原型的读者参考使用。

1. 橘子成熟度检测数据集:2 类别、训练集与验证集到底怎么用

果园里最怕的不是没橘子,而是摘早了酸、摘晚了烂。我去年帮一个做分拣设备的朋友看模型,他拿网上随便凑的橘子图训了一版 YOLOv5,验证集 mAP 看着有 0.8,拉到产线上一照,青皮橘子全被判成成熟,原因很简单——他的数据集里“未成熟”这一类几乎全是远景小目标,模型根本没学到青绿果皮在近景下的纹理。这就是标题里“橘子是否成熟检测(2 类别,包含训练集、验证集)”真正要解决的问题:它不是让你跑通一个 demo,而是让你拿到一份能直接喂给 YOLOv5、类别定义清晰、训练验证划分合理的数据集,把“成熟 / 未成熟”这个二分类检测任务做扎实。

这份数据集的核心价值在于两点。第一,类别只有两个,标注边界清楚,不像多类别数据集那样容易在相似类别间反复横跳,适合刚接触 YOLOv5 训练自己数据集的人快速建立完整链路。第二,它自带训练集和验证集,意味着你不需要自己从零划分,省掉了“按 8:2 随机切分”这种看似简单、实则容易切出分布偏差的步骤。适合谁用?做农业视觉分拣的、做采摘机器人感知模块的、以及想拿一个真实二分类检测任务练手 YOLOv5 环境配置和超参数调整的工程师。下面我按“数据怎么读 → 环境怎么搭 → 训练怎么跑 → 坑在哪 → 怎么验证”这条线,把能抄作业的部分写清楚。

2. 橘子成熟度数据集的目录结构与标注格式:先看懂再动手

2.1 训练集、验证集、标注文件三者的对应关系

拿到一份目标检测数据集,第一件事不是急着写训练脚本,而是把目录结构摸清楚。常见做法是根目录下分images和labels,再各自分train和val。但不同来源的数据集组织方式有差异,有的把训练集和验证集直接放在两个大文件夹里,有的用train.txt/val.txt列出图片路径。你拿到手之后,先跑一条命令把结构打出来:

# 查看数据集目录树,只看两层,避免图片太多刷屏 find ./orange_ripeness_dataset -maxdepth 2 -type d | sort

这条命令只列目录不列文件,目的是确认images/train、images/val、labels/train、labels/val这四个关键路径是否存在。如果发现只有train和val两个文件夹,里面混着图片和 txt,那说明它用的是“图片与标注同目录”的组织方式,YOLOv5 也能读,但需要在 data.yaml 里把路径写对。

标注格式方面,YOLOv5 用的是 YOLO 格式 txt:每行一个目标,格式为class_id x_center y_center width height,后四个值都是相对图片宽高的归一化值,范围 0 到 1。二分类任务里,class_id只有 0 和 1。我一般会先抽查几个标注文件,确认没有越界值:

# 抽查标注文件,检查归一化坐标是否在 0~1 之间 import os label_dir = "./orange_ripeness_dataset/labels/train" bad_files = [] for fname in os.listdir(label_dir): if not fname.endswith(".txt"): continue with open(os.path.join(label_dir, fname)) as f: for line_no, line in enumerate(f, 1): parts = line.strip().split() if len(parts) != 5: bad_files.append((fname, line_no, "字段数不对")) continue cls_id = int(parts[0]) coords = [float(x) for x in parts[1:]] if cls_id not in (0, 1): bad_files.append((fname, line_no, f"类别ID异常: {cls_id}")) if any(c < 0 or c > 1 for c in coords): bad_files.append((fname, line_no, f"坐标越界: {coords}")) print(f"异常标注条数: {len(bad_files)}") for item in bad_files[:10]: print(item)

这段脚本做三件事:检查每行是否恰好 5 个字段、类别 ID 是否只在 0 和 1 之间、归一化坐标是否越界。参数上不需要调,直接跑即可。如果异常条数不为零,先别急着训练,把对应文件挑出来人工看一眼,常见的是标注工具导出时把像素坐标直接写进去了,这种必须转回归一化坐标,否则模型学到的框会全部偏到图片角落。

2.2 data.yaml 的写法与两个类别的命名约定

YOLOv5 训练时靠一个 yaml 文件告诉它去哪里找数据、有几个类别、类别叫什么。这个文件我一般命名为orange.yaml,放在项目根目录或data目录下。写法如下:

# orange.yaml path: ./orange_ripeness_dataset # 数据集根目录 train: images/train # 训练集图片相对路径 val: images/val # 验证集图片相对路径 nc: 2 # 类别数 names: ['unripe', 'ripe'] # 类别名,顺序必须与标注里的 class_id 对应

这里有几个参数值得说清楚。path是根目录,train和val是相对于path的路径,YOLOv5 会自动把images替换成labels去找标注,所以你的目录里必须有同级的labels/train和labels/val。nc是类别数,二分类就写 2。names的顺序至关重要:如果你的标注里 0 代表未成熟、1 代表成熟,那 names 就必须是['unripe', 'ripe'],写反了模型训练不会报错,但推理时标签会全部颠倒,这种坑我见过不止一次。

提示:改完 yaml 后,用 YOLOv5 自带的检查脚本跑一遍,确认图片和标注能一一对应上,比训练到一半才发现缺标注要省事得多。

2.3 用一条命令确认图片与标注数量是否对齐

图片和标注必须一一对应,缺一个都会在训练时被跳过或报错。我习惯用下面这条命令快速核对:

# 分别统计训练集图片数和标注数,两者应相等 echo "train images: $(ls ./orange_ripeness_dataset/images/train | wc -l)" echo "train labels: $(ls ./orange_ripeness_dataset/labels/train | wc -l)" echo "val images: $(ls ./orange_ripeness_dataset/images/val | wc -l)" echo "val labels: $(ls ./orange_ripeness_dataset/labels/val | wc -l)"

四个数字里,前两个应该相等,后两个应该相等。如果标注数少于图片数,说明有图片没有对应标注,YOLOv5 默认会把这些图片当负样本处理,但如果你确定每张图里都有橘子,那就是标注漏了。如果标注数多于图片数,多出来的标注文件会被忽略。这一步花不了一分钟,但能避免训练日志里出现大量“missing labels”警告。

3. 用 YOLOv5 跑通橘子成熟度训练:环境、命令与参数

3.1 环境配置与依赖安装的稳定路径

YOLOv5 的环境配置说简单也简单,说玄学也玄学,主要坑在 PyTorch 版本和 CUDA 的匹配上。我一般用 conda 建一个干净环境,避免和系统里的其他包打架:

# 创建并激活 conda 环境 conda create -n orange_yolo python=3.9 -y conda activate orange_yolo # 安装 PyTorch,这里以 CUDA 11.8 为例,具体按你的显卡驱动选 pip install torch torchvision --index-url https://download.pytorch.org/whl/cu118 # 克隆 YOLOv5 源码并安装依赖 git clone https://github.com/ultralytics/yolov5.git cd yolov5 pip install -r requirements.txt

参数说明:Python 选 3.9 是因为它在 YOLOv5 各版本上兼容性最稳;CUDA 版本要和你nvidia-smi右上角显示的版本匹配,不要超过驱动支持的上限。装完之后跑一句python -c "import torch; print(torch.cuda.is_available())",输出 True 才算环境通了。如果输出 False,先别往下走,检查驱动和 CUDA 版本,这一步翻车后面全白搭。

3.2 训练命令与关键超参数怎么设

环境通了之后,训练命令本身不复杂,但参数设不对,二分类任务很容易过拟合或欠拟合。我常用的起手命令:

python train.py \ --data orange.yaml \ --weights yolov5s.pt \ --img 640 \ --batch 16 \ --epochs 100 \ --workers 4 \ --project runs/train \ --name orange_exp1

逐项说:--data指向你写好的 yaml;--weights用预训练的yolov5s.pt,小模型在二分类任务上够用且训练快,如果你数据量很大再考虑yolov5m;--img 640是输入分辨率,橘子检测一般 640 足够,如果果实占画面比例很小可以提到 1280,但显存要跟上;--batch 16是批大小,显存不够就降到 8 或 4;--epochs 100对二分类通常够收敛,但要看验证集 mAP 曲线,如果 80 轮还在涨就加到 150;--workers是数据加载线程,设成 CPU 核心数的一半左右比较稳。

训练开始后,重点盯三个指标:box_loss、obj_loss、mAP@0.5。二分类任务里,如果obj_loss一直不降,多半是标注框有问题;如果mAP@0.5在训练集上很高但验证集上很低,那就是过拟合,需要加数据增强或减模型复杂度。

3.3 训练过程中该看什么、不该频繁动什么

YOLOv5 训练日志会实时打印每轮的损失和 mAP,我一般不会频繁中断训练去调参,而是等一轮完整跑完再看趋势。真正需要中途干预的情况只有两种:一是显存溢出(CUDA out of memory),这时候停掉,把 batch 减半再重启;二是损失变成 NaN,通常是学习率太大或标注里有非法值,先查标注再降学习率。

不该做的事:不要因为前 10 轮 mAP 低就急着换模型或改数据,YOLOv5 在前 20 轮通常还在预热阶段,mAP 波动很正常。另外,不要一边训练一边改 yaml 或标注文件,YOLOv5 会在启动时缓存标签,中途改文件不会生效,反而让你误以为改动没用。

注意:如果你用的是自己划分的训练集和验证集,而不是数据集自带的,务必确认验证集里的橘子成熟度分布和训练集接近,否则 mAP 会虚高或虚低,参考价值大打折扣。

4. 橘子成熟度检测的避坑与排查:5 个血泪教训

4.1 验证集 mAP 很高但实际推理全错

现象:训练日志里验证集 mAP@0.5 到了 0.9 以上,但拿几张新拍的橘子图去推理,成熟和未成熟几乎全判反。原因:最常见的是names顺序和标注class_id反了,模型学到的“0 号类别”其实是成熟,但你在 yaml 里写成了未成熟。解决:回头核对标注文件里 0 和 1 分别对应什么,把 names 改对,重新训练。如果 names 没错,那就检查验证集图片是否和训练集来自同一批拍摄条件,分布差异过大会导致验证集指标失真。

4.2 训练到一半报“missing labels”大量警告

现象:日志里刷屏missing labels,训练能继续但 mAP 很低。原因:图片路径和标注路径没有对应上,YOLOv5 按images替换成labels去找,如果你的目录结构是train/images和train/labels,但 yaml 里写的是images/train,路径就错了。解决:用第 2.3 节的命令核对数量,再检查 yaml 里的train和val路径是否相对于path正确。路径里不要用绝对路径,除非你确定换机器后路径不变。

4.3 显存溢出导致训练中断

现象:跑了几轮之后突然CUDA out of memory。原因:YOLOv5 在训练初期显存占用会波动,如果 batch 设得刚好卡在显存上限,后期数据增强或缓存就可能撑爆。解决:把--batch降到 8 或 4,同时把--img从 640 降到 512 试试。如果还不行,加--nosave减少 checkpoint 占用,或者换更小的yolov5n模型。不要盲目加--device 0指定显卡,多卡环境下指定错卡反而更糟。

4.4 标注框大量重叠或超出边界

现象:训练损失震荡不收敛,推理时框乱飞。原因:标注时框画得太大或太小,或者多个框严重重叠,YOLOv5 的 anchor 匹配会混乱。解决:用第 2.1 节的脚本查坐标越界,再抽查几个标注文件,把明显不合理的框重新标。二分类任务里,一个橘子只应该有一个框,如果同一颗橘子被标了两次,删掉重复的。

4.5 验证集指标虚高但实际分拣误判多

现象:验证集 mAP 好看,但产线上青橘子和黄橘子分不清。原因:验证集和训练集可能来自同一段视频的相邻帧,画面高度相似,模型只是记住了背景而不是果皮颜色。解决:如果数据集自带的验证集和训练集同源,建议自己从不同时间段、不同光照条件下另切一份验证集,重新评估。这一步能暴露真实泛化能力,比盯着虚高的 mAP 有用得多。

5. 验证橘子成熟度模型是否真的可用:三个进阶技巧

训练跑完、mAP 看着不错,不代表模型能上产线。我一般会用下面三个方法做最终验证,顺序从简到繁。

第一个技巧是混淆矩阵细看。YOLOv5 训练结束后会在runs/train/orange_exp1下生成confusion_matrix.png,不要只看 mAP 数字,打开这张图看“未成熟”被误判成“成熟”的比例。如果这个比例超过 10%,说明模型对青绿果皮的敏感度不够,需要补充更多未成熟橘子的近景样本,或者把--img提高到 1280 让果皮纹理更清晰。

第二个技巧是拿视频流做连续推理。单张图片的指标有偶然性,用一段果园实拍视频跑detect.py,观察同一颗橘子在连续帧里的类别是否稳定。如果类别频繁跳变,说明模型置信度阈值设得太低,可以在推理时加--conf 0.5过滤掉低置信度框。下面这条命令把结果保存成带框视频:

python detect.py \ --weights runs/train/orange_exp1/weights/best.pt \ --source ./test_videos/orchard.mp4 \ --conf 0.5 \ --img 640 \ --project runs/detect \ --name orange_test

参数上,--conf 0.5是置信度阈值,二分类任务里可以设到 0.5 到 0.6,太低会引入大量误检;--img要和训练时一致,否则精度会掉。跑完之后逐帧看,重点看遮挡、逆光、果实重叠这三种情况下的表现。

第三个技巧是做一个最小分拣逻辑验证。检测框出来之后,真正决定“摘不摘”的是业务逻辑。我一般会写一个简单脚本,统计画面里成熟橘子的数量和位置,模拟分拣信号:

# 模拟分拣逻辑:统计成熟橘子数量并输出信号 import cv2 import torch model = torch.hub.load('ultralytics/yolov5', 'custom', path='runs/train/orange_exp1/weights/best.pt') model.conf = 0.5 img = cv2.imread('./test_images/sample.jpg') results = model(img) df = results.pandas().xyxy[0] # 列:xmin, ymin, xmax, ymax, confidence, class, name ripe_count = len(df[df['name'] == 'ripe']) unripe_count = len(df[df['name'] == 'unripe']) if ripe_count > 0 and unripe_count == 0: print("信号:可采摘") elif unripe_count > 0: print(f"信号:暂缓,未成熟 {unripe_count} 个") else: print("信号:无目标")

这段代码把检测结果转成业务信号,model.conf控制置信度阈值,df['name']对应 yaml 里的类别名。跑几张不同场景的图,看信号是否符合预期。如果“可采摘”信号在青橘子画面上也触发,说明模型还没过关,回去补数据或调阈值。

我自己的习惯是,任何检测模型上线前,至少用 20 张完全没参与训练的新图跑一遍这个逻辑,人工核对每一张的信号。这一步没有捷径,但能让你在产线翻车之前先在自己电脑上翻一次。希望帮到你。

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

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

智慧商城整体解决方案:从PPT到可落地技术架构与避坑指南

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

作者头像 李华
网站建设 2026/9/27 3:37:22

基于FFmpeg与FFprobe的视频去重实战:从原理到跨平台流水线

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

作者头像 李华
网站建设 2026/9/27 3:35:48

配电变压器检测数据集:VOC+YOLO双格式工程实践指南

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

作者头像 李华
网站建设 2026/9/27 3:35:11

408计算机组成原理:中断系统与程序中断方式核心考点全解析

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

作者头像 李华
网站建设 2026/9/27 3:34:31

FPGA I/O Bank与GT Bank物理约束全解析

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

作者头像 李华
网站建设 2026/9/27 3:24:29

Milvus可视化客户端Attu实战:从部署到排错全记录

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

作者头像 李华