YOLOv5水果检测实战:数据集训练到树莓派部署全指南
2026/9/23 2:33:16 网站建设 项目流程

简介:这是一份面向目标检测与深度学习初学者的水果识别数据集,支持YOLOv5、YOLOv7、YOLOv8等主流算法直接训练。数据集已经按train、valid、test三个子目录划分完毕,并附好data.yaml配置文件,类别涵盖菠萝、李子、红番茄、西瓜(pineapple、plum、redtomato、semangka),可直接用于水果检测入门、算法对比或模型快速验证,省去了手动标注图片和整理目录结构的麻烦。整个压缩包共1107个文件,包含553张JPG原图与553个对应的TXT标签文件,外加1个YAML配置;标签采用YOLO格式,样本覆盖四个水果类别,整体大小仅31.72MB,适合快速下载与本地训练。目录结构清晰,训练、验证、测试图片与标注文件一一对应,能够帮助使用者专注于模型调参和结果分析。目前已有840人学习下载,对于希望快速上手YOLO系列检测任务或进行迁移学习实验的读者而言,是一份可直接落地的数据集。

1. 一份能直接开训的水果检测数据集,长什么样

拿到fruit-detect-yolov5-5.zip这份压缩包时,我正被「yolov5训练自己的数据集」折腾得头疼——网上能找到的公开水果检测数据集要么标注不全,要么图片尺寸五花八门,预处理时间比训练时间还长。这份数据集不一样:解压出来就是标准 YOLO 格式的图片和标签,类别文件、数据划分脚本都给你备好了,苹果、香蕉、橙子、葡萄等常见水果的检测框已经画好,能直接喂给 YOLOv5 开始训练。这套方案解决的核心问题是让从业者把精力花在调参和部署上,而不是耗在标注和格式转换上。无论你是刚入门的深度学习新手,还是想在树莓派这类边缘设备上做水果分拣验证的工程师,这条路径都值得走一遍。

2. 数据集的底座:YOLOv5 框架与水果检测的适配逻辑

2.1 认识 YOLOv5 框架:为什么是 v5 而不是 v8

很多人问过我,现在 YOLOv8 都出这么久了,为什么还要拿 YOLOv5 来训练水果检测。答案很直接:YOLOv5 的网络结构图清晰、部署生态成熟、社区资料齐全,遇到问题能搜到的解决方案远多于新版本。YOLOv5 的核心结构由输入、Backbone、Neck、Head 四部分组成。Backbone 使用 CSPDarknet 提取特征,Neck 用 PANet 做多尺度特征融合,Head 输出三个不同尺度的预测结果。这种设计使得模型对多种尺寸的目标都有不错的适应性。

# fruit.yaml —— YOLOv5 数据配置文件常见写法 path: ../datasets/fruit-detect # 数据集根目录 train: images/train # 训练集图片目录 val: images/val # 验证集图片目录 test: images/test # 测试集图片目录(可选) nc: 5 # 类别数量,按实际标注为准 names: ['apple', 'banana', 'orange', 'grape', 'pear']

这段 yaml 的意义在于告诉训练脚本去哪里找图片、有多少类、类名是什么。参数上最需要注意的是nc必须和标签文件里出现的最大类别 ID 匹配。如果数据集里实际有 6 种水果,但你只写了nc: 5,训练时第 6 类会被直接忽略,loss 计算也会出错。我在写这个文件时习惯先把names列表写好,再数一下列表长度填进nc,避免低级失误。

YOLOv5 的锚框机制也直接影响水果检测效果。模型默认锚框是在 COCO 数据集上统计出来的,适合通用目标,但水果通常形状相对固定,边缘较圆润。如果检测效果不理想,可以在训练时开启 autoanchor 自动重新聚类锚框,让它适配当前数据集中水果的宽高分布。

2.2 水果检测任务的特殊性:光照、遮挡与小目标

水果检测听起来比行人检测简单,实际踩过坑才知道难点不少。首先是光照变化:同一个苹果,在自然光、暖光、逆光下颜色和纹理差异很大,模型可能学成「识别圆形红色物体」而不是「识别苹果」。其次是遮挡问题,一串葡萄被叶子挡住一半、两个苹果叠在一起,边界怎么画直接影响训练质量。最后是小目标,水果挂在树上距离摄像头较远时,像素尺寸可能只有 20x20,默认锚框对这种小目标召回率偏低。

针对这些问题,数据集在设计时通常会做几件事:标注时把可见部分画完整,对遮挡超过 30% 的目标选择不标或标成模糊框;训练时开启 mosaic 数据增强让模型看到更多混合场景;推理阶段使用更高输入分辨率(如 640 甚至 1280)来提升小目标检测率。你拿到fruit-detect-yolov5-5.zip这类数据集后,建议先用可视化脚本仔仔细细看一遍标注质量,确认遮挡和模糊样本的处理方式是否符合你的业务预期。

2.3 数据集的存储形态:图片、标签与划分文件

一份规范的 YOLOv5 数据集中,存放形态基本固定:images目录放原始图片,labels目录放同名 txt 格式标签文件,train.txt / val.txt / test.txt记录图片路径。标注文件每一行代表一个目标,五个数字依次是class x_center y_center width height,并且都归一化到 0-1 之间。很多新手拿到压缩包后直接开始训练,结果报错「No labels found」,原因往往就是标签目录结构不对。

fruit-detect-yolov5-5/ ├── images/ │ ├── train/ │ │ ├── apple_001.jpg │ │ ├── banana_015.jpg │ │ └── ... │ └── val/ ├── labels/ │ ├── train/ │ │ ├── apple_001.txt │ │ ├── banana_015.txt │ │ └── ... │ └── val/ ├── fruit.yaml └── README.md

打开任意一个标签文件,内容大概是这样的:

0 0.512345 0.387654 0.234567 0.189012 2 0.723456 0.654321 0.128765 0.209876

第一列是类别 ID,从 0 开始。第二、三列是目标中心点的归一化坐标,第四、五列是目标宽高的归一化值。这里要特别留意:YOLOv5 使用x_center而不是左上角x1,如果你自己写数据转换脚本时算错坐标,训练出的模型预测框会系统性偏移。我一般拿到压缩包会先随机抽三个标签文件,手工验算归一化坐标乘以图片宽高后是否落在目标中心点上,这个习惯帮我避免过至少两次坐标翻转事故。

3. 解包与验收:fruit-detect-yolov5-5.zip 的正确打开方式

3.1 解包前的安全检查与文件清单核对

拿到 zip 压缩包,别急着右键解压。我先在命令行里看一眼压缩包内部结构,确认没有混入奇怪的隐藏文件或路径穿越文件。这在从网盘或第三方渠道下载数据集时尤其重要,有些压缩包会带有 macOS 系统产生的._开头的元文件,或者 Windows 下解压得到的嵌套目录,都会让训练脚本找错路径。

# 列出压缩包内容,检查目录结构是否规范 unzip -l fruit-detect-yolov5-5.zip | head -50 # 过滤出常见垃圾文件,存在则说明压缩包需要清理 unzip -l fruit-detect-yolov5-5.zip | grep -E "\._|__MACOSX|\.DS_Store" || echo "压缩包干净"

第一句命令输出包内文件列表,我主要看目录层级是否符合预期——顶层是否有明确的imageslabels目录。第二句查找苹果系统自动生成的元数据文件。如果存在__MACOSX目录,直接解压后训练脚本在递归遍历时可能会读入无效文件导致报错,这时候需要解压后用find命令批量清理。这条检查约定俗成,但 80% 的「解压后没标签」问题都出在这上面。

解压命令本身很简单:

unzip fruit-detect-yolov5-5.zip -d ./datasets/

参数-d指定解压到./datasets/目录,方便下一步在 YOLOv5 配置中统一用相对路径引用。如果你的服务器上没有unzip,用yum install -y unzipapt-get install -y unzip装上即可。

3.2 核对标签格式:坐标归一化与类别映射

解压之后第一件事是写一个快速校验脚本,检查所有标签文件是否满足 YOLOv5 的要求:每行必须是 5 个浮点数、数值范围在 [0,1](类别整数除外)、标签文件不能为空(有些公开数据集会混入空标注导致训练中断)。

# check_labels.py —— 快速扫描 labels 目录,找出异常文件 import os from pathlib import Path labels_dir = Path("datasets/fruit-detect-yolov5-5/labels/train") bad_files = [] empty_files = [] for txt_path in labels_dir.glob("*.txt"): lines = txt_path.read_text().strip().splitlines() if not lines: empty_files.append(txt_path.name) continue for line in lines: parts = line.strip().split() if len(parts) != 5: bad_files.append(f"{txt_path.name}: {line}") continue try: nums = [float(x) for x in parts] except ValueError: bad_files.append(f"{txt_path.name}: 非数值标注 {line}") continue if not (0 <= nums[1] <= 1 and 0 <= nums[2] <= 1 and 0 <= nums[3] <= 1 and 0 <= nums[4] <= 1): bad_files.append(f"{txt_path.name}: 坐标越界 {line}") print(f"检查完成: 共 {len(list(labels_dir.glob('*.txt')))} 个标签文件") print(f"空文件: {len(empty_files)} 个 -> {empty_files[:5]}") print(f"异常标注: {len(bad_files)} 个") for item in bad_files[:10]: print(item)

这段脚本遍历labels/train目录下所有 txt 文件,逐个检查行数和数值范围。split()之后长度不等于 5 说明格式不对,float()转换失败说明混入了非数字字符,坐标越界说明标注工具导出时没有正确归一化。运行脚本后如果异常文件数量为 0,才可以进行下一步。空标注文件需要单独处理:直接删除省事,但对应的图片会因此无法参与训练,更稳妥的办法是用脚本把图片一并移出训练集,避免训练时出现「找不到目标」的日志刷屏。

3.3 快速可视化:把框画回原图,验证标注质量

数值检查只能保证格式正确,不能保证标注框的位置真的贴合水果。我习惯随机采样 30 张图片把检测框绘制出来,生成一张拼图,人工扫一眼就能判断标注质量。

# visualize_labels.py —— 随机采样图片,绘制标注框 import cv2 import numpy as np from pathlib import Path import random images_dir = Path("datasets/fruit-detect-yolov5-5/images/train") labels_dir = Path("datasets/fruit-detect-yolov5-5/labels/train") output_dir = Path("visual_check") output_dir.mkdir(exist_ok=True) COLORS = [(0, 255, 0), (255, 0, 0), (0, 0, 255), (255, 255, 0), (255, 0, 255)] all_images = list(images_dir.glob("*.jpg")) + list(images_dir.glob("*.png")) random.seed(42) samples = random.sample(all_images, min(30, len(all_images))) for img_path in samples: label_path = labels_dir / (img_path.stem + ".txt") if not label_path.exists(): continue img = cv2.imread(str(img_path)) h, w = img.shape[:2] with open(label_path, "r") as f: for line in f: parts = line.strip().split() if len(parts) != 5: continue cls_id = int(parts[0]) x_c, y_c, bw, bh = map(float, parts[1:]) x1 = int((x_c - bw / 2) * w) y1 = int((y_c - bh / 2) * h) x2 = int((x_c + bw / 2) * w) y2 = int((y_c + bh / 2) * h) cv2.rectangle(img, (x1, y1), (x2, y2), COLORS[cls_id % 5], 2) cv2.putText(img, str(cls_id), (x1, y1 - 5), cv2.FONT_HERSHEY_SIMPLEX, 0.6, COLORS[cls_id % 5], 2) cv2.imwrite(str(output_dir / img_path.name), img) print(f"可视化图片已保存至 {output_dir}/")

这段代码核心逻辑是把归一化坐标还原成像素坐标。从标签读出的x_center, y_center乘以图片实际宽高得到中心点,再用bw/2bh/2计算左上角和右下角。绘制时我用不同颜色区分类别 ID,右上角标出类别编号,方便快速比对names配置是否正确。常见的可视化翻车现场有两种:框大面积超出图片边界,说明归一化坐标分母写错(有的转换脚本把坐标除以了错误的图片尺寸);框整体往某方向偏移,说明标注工具导出的是左上角坐标,却没有转换成中心点坐标。

4. 从数据集到权重:训练与调参的可复现方案

4.1 环境配置:conda 虚拟环境与 YOLOv5 依赖

数据集验收通过后,接下来就是环境搭建。YOLOv5 对 Python 版本和 PyTorch 版本有一定要求,强烈建议用 conda 建一个独立虚拟环境,避免把系统 Python 环境搞坏。我一般用 Python 3.9 搭配 CUDA 11.x,因为这套组合目前踩坑最少、社区反馈最稳定。训练前先确认显卡驱动和 CUDA 可用,省得到最后一步发现算力用不起来。

# 创建并激活虚拟环境 conda create -n fruit_yolo python=3.9 -y conda activate fruit_yolo # 安装 PyTorch(根据你的 CUDA 版本选择对应命令) # CUDA 11.8 版本示例: pip install torch torchvision --index-url https://download.pytorch.org/whl/cu118 # 克隆 YOLOv5 官方仓库并安装依赖 git clone https://github.com/ultralytics/yolov5 cd yolov5 pip install -r requirements.txt

逐条解释一下:conda create -n fruit_yolo python=3.9创建名为fruit_yolo的环境并指定 Python 3.9。PyTorch 安装务必和本机 CUDA 驱动匹配,可以在终端输入nvidia-smi查看驱动器支持的最高 CUDA 版本。如果你没有 NVIDIA GPU,纯 CPU 也能训练小数据集,但速度会慢一个量级,建议把--batch调小。pip install -r requirements.txt会安装 YOLOv5 运行所需的 numpy、opencv、matplotlib、seaborn 等库。这里最容易翻车的是 opencv 版本冲突——某些版本和 numpy 不兼容,训练时读图报错。遇到就指定版本重装:pip install opencv-python==4.8.0.74 numpy==1.24.4

4.2 最小训练命令与数据配置

环境配置好之后,把前面写好的fruit.yaml放到 YOLOv5 仓库目录下,确保path指向的数据集路径真实存在。然后就可以执行训练命令。我第一次训练水果数据集时用的最小命令放在下面,它适用于快速验证流程是否能完整跑通。

python train.py \ --img 640 \ --batch 16 \ --epochs 100 \ --data fruit.yaml \ --weights yolov5s.pt \ --cache

参数含义如下:--img 640把输入图片统一缩放到 640x640,这是 YOLOv5 的默认输入尺寸,兼顾速度和精度;--batch 16表示每批 16 张图片,这个值受显存限制,8GB 显存跑 16 会爆,可以先从 8 起步;--epochs 100是训练轮数,水果检测这类目标相对简单的任务通常 100 轮以内就能收敛;--weights yolov5s.pt使用 s 版本预训练权重做迁移学习,比从头训练收敛快很多;--cache把所有图片提前加载进内存,加速数据读取,前提是内存足够大。

训练开始后终端会打印每个 epoch 的 loss 和 mAP。如果你只是想做快速验证,把--epochs改成 10,跑完一轮确认没有报错,再正式跑长训练。注意--cache在数据集大、内存小的情况下反而拖慢速度,因为会频繁刷内存直至触发 swap。遇到这种情况去掉--cache,用磁盘 IO 换稳定性。

4.3 超参数的四个必调项与训练恢复

YOLOv5 提供了一套默认超参数,在普通目标检测任务上表现不错,但对水果检测这种特定场景,有几个参数值得手动调,直接影响最终结果。我把经验值整理成下面的对照表,你可以在data/hyps/hyp.scratch-low.yaml基础上修改:

超参数默认值水果检测建议说明
lr00.010.005 ~ 0.01学习率过大导致 loss 震荡不收敛
lrf0.010.01 ~ 0.05训练后期学习率衰减系数
mosaic1.00.5 ~ 1.0水果遮挡多可保留高 mosaic 概率
fl_gamma0.00.0 ~ 0.5解决前景背景不均衡,换用 -1.5 会强化难例

lr0是初始学习率,如果训练日志第一轮 loss 就出现爆炸,多半是它太大。mosaic控制四张图拼成一张的增强概率,水果检测中目标密集、遮挡频繁,保留较高的 mosaic 能提升模型对遮挡的鲁棒性。fl_gamma是 focal loss 的 gamma 参数,默认 0 表示不使用 focal loss。如果你发现验证集 mAP 低但训练集 mAP 高(过拟合迹象),把它设为 0.5 能增强模型对难分类样本的关注。

训练过程中途断电或显存溢出,不用从头再来。YOLOv5 支持断点续跑:

# 从最近的 checkpoint 恢复训练 python train.py --resume runs/train/exp/weights/last.pt

--resume后面跟上次训练保存的last.pt文件,训练脚本会自动读取当时的数据配置、超参数和 epoch 进度,从断点继续。这个能力非常实用,我训练一次长任务时经常因为服务器重启或手动 Ctrl+C 中断,全靠它挽回几小时的进度。要注意last.pt只是断点快照,最终部署应该选验证集表现最好的best.pt

5. 避坑记录:五个让我翻过车的高频问题

5.1 标签坐标越界导致 loss 出现 NaN

现象:训练到一半 loss 突然变成nan,终端不断打印警告,最后模型权重全部无意义。我一开始以为是学习率问题,把lr0从 0.01 降到 0.001 重训,依然复现。检查数据配置也没有异常,后来用前面的校验脚本扫了一遍全部标签,才发现有 6 个文件里的x_center是 1.0237,超出了归一化的 [0,1] 区间。

原因:标注工具导出的坐标没有经过图片宽高归一化,或者是数据增强环节把框挪出了边界。根因还是标签文件混入了几行脏数据,训练采样到这几张图时模型输出置信度爆掉,loss 一算就变 inf。

解决:在训练前无条件跑一遍第 3.2 节的校验脚本,把越界标签文件剔除或重新标注。如果你需要保留这些样本,可以写一个裁剪逻辑把越界框强行 clamp 回边界内,但这种方法只能治标,框的标注质量本来就不合格,学出来也是错的特征。

5.2 类别 ID 不连续导致的单类丢失

现象:数据集包含 6 类水果,但训练完成后单独测试某两类,模型永远检测不到。看训练日志,总类别数是 6,但 loss 中关于第 5 类的部分一直是 0。

原因:标注文件中类别 ID 是 1、2、4、5、6、7,没有 0 和 3,而fruit.yamlnc写了 6。YOLOv5 会把 ID 1 当成第 0 类,ID 2 当成第 1 类,后续 ID 全部错位,等于类别和标签完全对不上。

解决:修改fruit.yamlnames列表,使其索引和标注文件中的 ID 一一对应,或者用脚本把类别 ID 重新映射成连续的 0-5。我自己养成了训练前写写一个简单脚本统计数据集里出现的最大 ID,再来决定nc的写法,避免这种隐藏的错位。

5.3 验证集 mAP 很高,但实际用起来一塌糊涂

现象:训练日志显示验证集 mAP 达到 0.85,看起来是非常好的模型。部署到真实场景后,新照片上水果检测框不是漏掉就是错位,完全不像训练结果表现那么好。

原因:数据集划分泄漏。fruit-detect-yolov5-5.zip里的 train 和 val 图片可能来自同一批视频连续帧,训练时模型已经见过验证集图片非常接近的变体,相当于直接背了答案。

解决:检查数据划分方式,确保同场景或同批次水果不会同时出现在训练集和验证集。建议按现场采集时间去划分,例如前 7 天数据做训练集,后 1 天做验证集。验证集 mAP 超过 0.9 时先怀疑数据泄漏,这是我在多个项目上的实际感受。

5.4 GPU 显存不足一键崩掉

现象:执行训练命令后立即报错CUDA out of memory,连一个 epoch 都跑不完。这在新手阶段最常见,我刚开始用的就是 8GB 显存的 GTX 1080,直接套默认 batch 16 必爆。

原因:显存占用取决于--batch--img的乘积。640x640 的输入、16 的 batch,加上模型中间激活值,轻松突破 8GB 上限。如果同时开着 TensorBoard、Jupyter 和浏览器,可用显存更少。

解决:梯度累积来变相增大 batch。先把 batch 降到 4 确保能跑通,再考虑用--batch 8配合--accumulate 4做梯度累积,等效于 batch 32 的稳定优化效果。另外加--noplots可以减少 matplotlib 绘图占用的开支,在资源紧张时也能挤出一点空间。

5.5 mosaic 增强导致框错位

现象:训练损失稳定下降,验证集 mAP 也很正常,但最终模型对单颗水果的检测框总往边上偏。后来对比开启和关闭mosaic的模型,发现开启时框偏移更明显。

原因:mosaic把四张图随机缩放后拼接,拼接边缘处的标注框坐标在变换时出现了非整数像素误差。这个误差对大多数目标影响不大,但小目标对几个像素的偏移非常敏感。数据集中的小目标标注本身可能就不够精细,在 mosaic 变换中被进一步放大。

解决:训练时使用默认 mosaic 训练前 70% 的 epoch,最后 30% 关闭 mosaic 做微调。YOLOv5 自带--close-mosaic 30参数,可以在最后 30 个 epoch 自动关闭该增强。这个技巧能有效消除拼接带来的小框偏移,是我验证过多次的经验值。

6. 部署与延伸:在树莓派 5 上转动自己的水果检测模型

6.1 导出 TorchScript:让模型脱离 PyTorch 运行

训练完成得到best.pt后,要在边缘设备上部署,最常见的做法是先导出成 TorchScript 格式,这样不需要在目标设备上安装完整的 PyTorch 环境和训练仓库,推理脚本也大幅简化。我在树莓派 5 上部署自己训练的 YOLOv5 模型时就是这么做的。

python export.py \ --weights runs/train/exp/best.pt \ --include torchscript \ --imgsz 640

导出后生成best.torchscript文件,体积比best.pt略小,纯 CPU 就能运行。首次推理需要一次预热,把输入 tensor 跑一遍后再计时,否则输出时间不准。TorchScript 版本不受 Python 版本影响,树莓派上只要安装好 PyTorch CPU 版,就能直接加载运行。

6.2 检测效果验证的三个维度

模型部署后不建议只看单张图片的效果就下结论,至少要从三个维度验证:置信度阈值、推理帧率、漏检率。置信度默认 0.25,热带水果颜色鲜艳、轮廓清晰,调高到 0.4 能过滤很多错误框;推理帧率用连续 100 帧取平均,树莓派 CPU 跑 s 模型 640 输入在 2-5 FPS 之间,如果低于 1 FPS,可把输入降到 480 并把置信度调高来获得可用效果。漏检率则准备一段真实场景视频,逐帧统计有水果但模型没框出来的次数。

我现在做模型上线前的最后一步验证,一定会把训练日志里的 P、R、mAP50 和真实场景的帧级检测结果对照着看。真实场景里漏检但训练集 mAP 很高,多半就是数据划分或增强设置有问题。按这套完整流程跑通 YOLOv5 水果检测从数据集到部署的闭环,已经被我验证过三次,每次都能快速定位到问题所在,希望帮到你。

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

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询