
简介这是一套面向深度学习入门者与计算机视觉方向学生的YOLOv5果蔬识别完整项目包围绕土豆、圣女果、大白菜、大葱、梨、胡萝卜、芒果、苹果、西红柿、韭菜、香蕉、黄瓜等十余类常见果蔬的检测任务展开可用于课程设计、毕业设计或算法练手。压缩包共56个文件约94.07MB包含14个Python脚本、12个PNG与9个JPG及6个JPEG图像、6个TXT说明、4个XML标注、2个H5权重文件以及Markdown文档和工程配置覆盖数据读取、训练、测试与实时摄像头推理等环节。资源中提供了CNN与MobileNet两套训练流程、训练过程记录、测试记录、热力图与结果图以及数据划分、错误样本清理等工具脚本便于读者对照复现模型训练与评估。目前已有3770人学习下载适合希望快速跑通果蔬检测全流程、理解数据集组织与模型调参的读者参考。1. 果蔬识别为什么总在分拣线上翻车从 yolov5 数据集到可复现训练做过果蔬分拣线视觉项目的人大多有过类似经历模型在实验室的验证集上 mAP 跑到 0.9一上产线就频繁把青椒认成黄瓜、把带疤的苹果漏检。问题往往不在网络结构而在数据集和训练配置这两块被忽视的地方。yolov5 果蔬识别数据集系统代码教程这套组合本质上是把「数据采集标注 → 格式转换 → 训练调参 → 推理部署」这条链路打包成可复现的工程模板解决的是从零搭一套果蔬检测系统时反复踩坑、反复返工的问题。它适合两类人一类是想用 yolov5 训练自己数据集、但卡在标注格式和超参数上的算法新手另一类是要把果蔬识别落到分拣、称重、质检环节的一线工程师。下面按我实际做过的顺序把数据集怎么建、代码怎么跑、参数怎么调、坑在哪讲清楚。2. 果蔬数据集怎么建从采集到 YOLO 格式的完整链路2.1 果蔬识别的类别划分与采集策略果蔬识别和通用目标检测最大的区别在于类间差异小、类内差异大。同一个苹果红富士和黄元帅在颜色上差异明显但青苹果和青椒在低分辨率下几乎同色同一颗西红柿成熟度不同颜色从青到红连续变化。所以类别划分不能只按物种要按业务需要的粒度来定。我一般会先问三个问题分拣线要区分的是品种、成熟度还是缺陷误检和漏检哪个代价更高单帧图像里同类目标最多几个这三个答案直接决定类别数和采集方式。比如做苹果分拣如果只分「好果/坏果」那就是二分类检测数据集压力小很多如果要分「红富士/黄元帅/嘎啦」再叠加缺陷类别数会到 6 到 10 类每类至少需要 800 到 1500 个实例才能稳住。采集时注意几点血泪经验一是光照要覆盖产线实际工况顶光、侧光、背光都拍否则模型在逆光工位直接翻车二是遮挡要真实果蔬堆叠、传送带边缘遮挡、机械臂抓取瞬间的遮挡都要有三是负样本要够空传送带、只有包装箱、只有标签的画面都要采不然模型会把背景纹理当目标。常见做法是每个类别先采 300 到 500 张原始图再通过旋转、亮度扰动、随机裁剪扩到 1500 张左右但增强不能替代真实采集尤其是缺陷类。2.2 标注规范与 LabelImg 实操标注质量决定上限。果蔬标注最容易出的问题是边界框贴太紧或太松。贴太紧会把果蔬边缘的阴影切掉模型学不到完整轮廓贴太松会把相邻果蔬框进来导致一个框里两个目标。我的习惯是框到果蔬可见轮廓外扩 2 到 3 个像素遮挡目标只标可见部分严重遮挡可见面积小于 30%的直接不标避免引入噪声。用 LabelImg 标注时类别名建议用英文小写加下划线比如apple_red、apple_defect、tomato_green不要用中文或空格否则后续转换和训练容易出编码问题。标注文件是 PASCAL VOC 格式的 XML每张图对应一个 XML里面记录了 filename、size 和每个 object 的 bndbox。# 安装 LabelImg常见做法Python 环境 pip install labelImg # 启动指定图片目录和类别文件 labelImg ./images ./classes.txtclasses.txt每行一个类别名顺序要和后续 data.yaml 里的 names 一致。标注完成后目录结构通常是images/放原图annotations/放 XML。这里有个容易忽略的点图片文件名不要有中文和空格否则 XML 里的 filename 和实际文件对不上转换脚本会报找不到文件。2.3 VOC 转 YOLO 格式转换脚本与四个边界坑yolov5 训练需要的是 YOLO 格式的 txt 标签每行class_id x_center y_center width height全部归一化到 0 到 1。VOC 的 XML 是绝对坐标必须转换。下面是我常用的转换脚本处理了果蔬数据集里常见的几个边界情况。import os import xml.etree.ElementTree as ET # 类别映射顺序必须和 data.yaml 的 names 一致 classes [apple_red, apple_green, apple_defect, tomato_red, tomato_green] def convert_bbox(size, box): VOC 绝对坐标转 YOLO 归一化坐标 dw 1.0 / size[0] dh 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(xml_dir, out_dir): if not os.path.exists(out_dir): os.makedirs(out_dir) for f in os.listdir(xml_dir): if not f.endswith(.xml): continue tree ET.parse(os.path.join(xml_dir, f)) root tree.getroot() size root.find(size) w int(size.find(width).text) h int(size.find(height).text) lines [] for obj in root.iter(object): cls obj.find(name).text if cls not in classes: continue # 跳过未定义类别避免训练时报 index 越界 cls_id classes.index(cls) bndbox obj.find(bndbox) box (float(bndbox.find(xmin).text), float(bndbox.find(xmax).text), float(bndbox.find(ymin).text), float(bndbox.find(ymax).text)) bb convert_bbox((w, h), box) # 过滤宽高为 0 的异常框 if bb[2] 0 or bb[3] 0: continue lines.append(f{cls_id} .join([f{x:.6f} for x in bb])) out_name os.path.splitext(f)[0] .txt with open(os.path.join(out_dir, out_name), w) as out: out.write(\n.join(lines)) convert(./annotations, ./labels)逻辑说明convert_bbox把 VOC 的左上右下坐标转成中心点加宽高的归一化值这是 YOLO 的标准格式。参数上classes列表的顺序就是类别 id必须和训练配置里的 names 完全一致否则模型学到的类别会错位。四个边界坑分别是类别名不在 classes 里要跳过而不是报错宽高为 0 的异常框要过滤图片尺寸以 XML 里的 size 为准而不是实际文件因为有些标注工具会写错输出文件名要和图片同名yolov5 靠文件名配对图片和标签。转换完成后建议抽查几张用脚本把归一化坐标还原画框肉眼确认框位置正确。这一步花十分钟能省掉训练几小时才发现标签错位的后悔药。3. yolov5 训练果蔬数据集环境、配置与超参数怎么定3.1 环境搭建与目录组织yolov5 对环境不算挑剔但版本错配是新手翻车重灾区。我一般用 Python 3.8 到 3.10PyTorch 1.10 以上CUDA 版本和显卡驱动匹配即可。不建议一上来就追最新版果蔬数据集规模通常不大稳定比新特性重要。# 克隆 yolov5用官方仓库不要用来路不明的 fork git clone https://github.com/ultralytics/yolov5 cd yolov5 # 安装依赖建议用虚拟环境 pip install -r requirements.txt # 验证环境 python -c import torch; print(torch.__version__, torch.cuda.is_available())目录组织我习惯这样数据集根目录下分images/train、images/val、labels/train、labels/valtrain 和 val 按 8:2 或 7:3 划分。划分时注意同一批次、同一光照条件的图不要跨 train 和 val否则验证集指标虚高上线就露馅。果蔬数据集尤其要注意这点因为同一颗果蔬连拍的多张图如果一半在训练一半在验证模型等于见过验证集。3.2 data.yaml 与模型配置的关键字段data.yaml 是数据集和训练的桥梁字段不多但每个都关键。# data.yaml path: ../datasets/fruit_veg # 数据集根目录 train: images/train val: images/val nc: 5 # 类别数必须和 classes 长度一致 names: [apple_red, apple_green, apple_defect, tomato_red, tomato_green]nc写错是最常见的报错来源写成 5 但 names 有 6 个训练直接崩。path用相对路径时要注意是相对于 yolov5 根目录还是 yaml 文件所在目录不同版本行为有差异稳妥做法是用绝对路径。模型配置选yolov5s.yaml起步果蔬识别通常不需要大模型。如果产线要求实时s 版本在主流显卡上能到 60 FPS 以上如果精度不够再换 m 或 l。改模型配置时只需要改nc其他结构参数不要动除非你清楚每个参数的含义。3.3 训练命令与超参数调整# 单卡训练果蔬数据集常用配置 python train.py \ --data data/fruit_veg.yaml \ --cfg models/yolov5s.yaml \ --weights yolov5s.pt \ --epochs 150 \ --batch-size 16 \ --img-size 640 \ --hyp data/hyp.fruit.yaml \ --name fruit_veg_v1参数说明--weights yolov5s.pt用预训练权重果蔬数据集样本量通常不够从零训迁移学习能省一半以上 epoch--epochs 150是经验值果蔬类别少时 100 到 200 之间看验证集 mAP 曲线早停--batch-size 16受显存限制显存不够就降到 8 并配合--accumulate梯度累积--img-size 640是默认值如果果蔬在图中占比很小比如传送带远景可以提到 1280但显存和速度代价明显。超参数文件hyp.fruit.yaml我一般基于默认 hyp.scratch-low.yaml 改三处lr0从 0.01 降到 0.005果蔬数据集小学习率太大会震荡mosaic保持 1.0 但mixup降到 0.1mixup 对果蔬这种需要精确边界的任务有时会引入噪声hsv_h和hsv_s适当调大增强对光照和成熟度变化的鲁棒性。这些不是玄学是果蔬颜色敏感特性决定的。训练过程中重点看三个指标mAP0.5看整体精度mAP0.5:0.95看框的紧致程度val/box_loss看定位是否收敛。如果 mAP 涨但 box_loss 不降多半是标注框松紧不一致如果训练 loss 降验证 loss 涨是过拟合加数据或加增强。4. 果蔬识别落地避坑五条产线踩出来的经验4.1 现象验证集 mAP 高产线漏检严重原因通常是验证集和产线分布不一致。果蔬数据集如果验证集全是清晰、正面、光照均匀的图产线上的侧拍、逆光、遮挡样本模型没见过。解决方法是把产线实际采集的难样本按比例混进验证集或者单独建一个「产线测试集」评估不要只看验证集指标。4.2 现象同类果蔬不同批次识别率波动大原因是颜色分布漂移。不同季节、不同产地的果蔬颜色差异明显模型对颜色过拟合。解决方法是训练时加强 HSV 增强并在推理前做白平衡校正把输入图像的色温拉到训练集相近的分布。这个坑在跨批次分拣时特别常见。4.3 现象小目标果蔬检测不到原因是下采样丢特征。传送带远景拍摄时单个果蔬可能只有 20 到 30 像素。解决方法是提高输入分辨率到 1280或者在模型配置里增加 P2 检测层小目标层代价是速度下降。如果速度不能降就调整相机安装距离让果蔬在画面里占更大比例这比改模型更划算。4.4 现象训练报 CUDA out of memory原因是 batch size 或 img-size 超过显存。解决方法是先降 batch size 到 8 或 4配合--accumulate 2保持等效 batch还不行就降 img-size 到 416。另外检查是否有其他进程占显存nvidia-smi看一眼就清楚。4.5 现象推理结果框重叠、同一果蔬多个框原因是 NMS 阈值不合适或模型没收敛。果蔬堆叠场景下目标挨得近NMS IoU 阈值默认 0.45 可能把相邻果蔬的框合并或保留重复框。解决方法是推理时调--conf-thres 0.4 --iou-thres 0.5并在训练时确保标注没有重复框。如果模型没收敛先看训练 loss 曲线别急着调 NMS。5. 从训练到部署果蔬识别模型的量化与产线验证技巧训练完拿到 best.pt 只是开始真正上产线还要过部署这一关。果蔬识别对延迟敏感分拣线传送带速度通常 0.5 到 2 米每秒留给单帧推理的时间可能只有 30 到 50 毫秒。这时候 PyTorch 原生推理往往不够快需要做模型导出和量化。我一般先导出 ONNX 验证精度损失再用 TensorRT 或 OpenVINO 做推理加速。导出命令很简单python export.py --weights runs/train/fruit_veg_v1/weights/best.pt --include onnx --img-size 640导出后务必用同一批测试图对比 PyTorch 和 ONNX 的输出确认框位置和类别一致。常见问题是动态轴设置不对导致 batch 推理出错或者 opset 版本和推理引擎不匹配。如果目标平台是边缘设备比如瑞芯微或树莓派这类量化到 INT8 能再提速 2 到 3 倍但果蔬识别对颜色敏感INT8 量化后要重点验证颜色相近类别的区分度青苹果和青椒这类容易在量化后混淆。产线验证我习惯分三步第一步离线跑 500 张产线实拍图统计每类召回率和误检率第二步半在线用视频流跑但不控制分拣人工核对结果第三步在线小批量试运行设置置信度阈值偏高比如 0.6先保准确稳定后再逐步降低阈值提召回。这个过程中记录每个误检案例反哺数据集迭代通常两到三轮就能把产线指标做到可用。一个具体技巧是给模型加一个「拒识」机制当最高置信度低于阈值且第二类别置信度接近时输出「不确定」交给人工复核而不是强行分类。果蔬分拣里错分一个缺陷果的代价远高于人工复核几个可疑果。这个逻辑在推理后处理里加十几行代码就能实现比一味调模型性价比高得多。我自己做果蔬项目最大的教训是别在模型结构上反复折腾把时间花在数据集清洗和产线难样本回流上收益大得多。每次上线后我都会留一个「错题本」把误检漏检的图存下来下一轮训练直接加进去。希望帮到你。本文还有配套的精品资源点击获取