ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

YOLOv5水果检测实战:数据集训练到树莓派部署全指南

YOLOv5水果检测实战:数据集训练到树莓派部署全指南 简介这是一份面向目标检测与深度学习初学者的水果识别数据集支持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 压缩包干净第一句命令输出包内文件列表我主要看目录层级是否符合预期——顶层是否有明确的images和labels目录。第二句查找苹果系统自动生成的元数据文件。如果存在__MACOSX目录直接解压后训练脚本在递归遍历时可能会读入无效文件导致报错这时候需要解压后用find命令批量清理。这条检查约定俗成但 80% 的「解压后没标签」问题都出在这上面。解压命令本身很简单unzip fruit-detect-yolov5-5.zip -d ./datasets/参数-d指定解压到./datasets/目录方便下一步在 YOLOv5 配置中统一用相对路径引用。如果你的服务器上没有unzip用yum install -y unzip或apt-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_okTrue) 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/2和bh/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 python3.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 python3.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-python4.8.0.74 numpy1.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 进度从断点继续。这个能力非常实用我训练一次长任务时经常因为服务器重启或手动 CtrlC 中断全靠它挽回几小时的进度。要注意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.yaml中nc写了 6。YOLOv5 会把 ID 1 当成第 0 类ID 2 当成第 1 类后续 ID 全部错位等于类别和标签完全对不上。解决修改fruit.yaml的names列表使其索引和标注文件中的 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 水果检测从数据集到部署的闭环已经被我验证过三次每次都能快速定位到问题所在希望帮到你。本文还有配套的精品资源点击获取
返回列表