
简介这是一套面向计算机专业本科生及深度学习初学者的YOLOv5果蔬识别实战项目资源适用于毕业设计、课程设计与期末大作业等教学实践场景解决目标检测模型从数据准备、训练部署到可视化推理的全流程落地问题。压缩包共56个文件包含14个Python脚本涵盖数据划分、图像预处理、模型训练与实时检测、12张PNG界面图与9张JPG/JPEG原始样本图、6个TXT配置与说明文档、4个XML标注文件以及MobileNet/CNN双模型H5权重和README指南整体大小为94.07MB。资源已通过导师审核并实际运行验证内含window_realtime.py等可直接调用摄像头的推理脚本、heatmap生成与结果可视化模块、异常图像清洗工具remove_wrong_image.py及多版本训练日志结构清晰、模块解耦便于理解YOLOv5与轻量模型在农业视觉任务中的适配逻辑与优化路径。1. 项目概述与核心价值最近在整理过往项目时翻出了一个我个人觉得完成度相当高的老项目一个基于YOLOv5的果蔬识别系统。这个项目最初是为了解决一个社区生鲜自助结算柜的品类识别需求而开发的后来经过多次迭代形成了一个包含高质量数据集、完整训练源码和详细部署指南的“全家桶”。之所以说它优质是因为它不仅仅是一个模型训练脚本的堆砌而是从数据准备、模型训练调优到最终轻量化部署的一整套工程化解决方案。对于想入门计算机视觉特别是目标检测实战的朋友来说这个项目能让你避开很多初期必然会踩的坑直接接触到接近生产环境的流程。这个系统的核心就是利用YOLOv5这个当下依然非常流行且高效的目标检测框架来识别图像或视频流中的各种水果和蔬菜。你可能会问现在YOLOv8、YOLOv9都出来了为什么还用v5我的体会是v5在速度、精度和易用性上达到了一个非常好的平衡点其代码结构清晰社区资源极其丰富遇到任何问题几乎都能找到解决方案。对于果蔬识别这种对实时性有一定要求比如结算柜需要快速响应但同时又需要较高识别精度的场景YOLOv5是一个非常稳妥且高效的选择。这个项目包里我不仅提供了自己清洗和标注的涵盖30种常见果蔬的数据集还包含了从环境配置、数据准备、模型训练、性能评估到模型导出的全流程代码最后还给出了在本地使用OpenCV进行实时检测的简易部署方案。无论你是学生想做一个课程设计或毕业项目还是开发者想为自己的应用增加一个视觉识别模块这套材料都能提供一个坚实的起点。2. 项目整体架构与设计思路2.1 为什么选择YOLOv5而非其他版本在项目启动时我对比了当时主流的几个YOLO版本。YOLOv3虽然经典但精度和速度已被后来者超越YOLOv4在当时表现强劲但代码依赖相对复杂对新手不够友好。而YOLOv5以其纯PyTorch实现、简洁的代码结构和出色的文档迅速吸引了我的注意。它的设计哲学非常“工程化”一个requirements.txt文件搞定环境一个train.py脚本启动训练数据格式采用通用的YOLO格式大大降低了入门门槛。更重要的是YOLOv5提供了从NanoYOLOv5n到Extra LargeYOLOv5x一系列预定义模型你可以根据你的硬件条件和性能需求灵活选择。对于果蔬识别我们通常部署在边缘设备或普通工控机上因此我主要聚焦于YOLOv5s小模型和YOLOv5m中模型。v5s速度极快在CPU上也能达到不错的帧率适合对实时性要求极高的场景v5m则在精度上有显著提升而速度代价在可接受范围内是兼顾精度与速度的“甜点”选择。这个项目源码中我会展示如何针对这两种模型进行训练和对比。2.2 数据集构建策略与核心考量一个检测模型的好坏七分靠数据三分靠调参。网络上虽然有一些公开的果蔬数据集但往往存在类别不均衡、标注质量参差不齐、背景单一或不符合实际应用场景等问题。因此我决定自己构建一个更贴近真实应用的数据集。数据采集来源我主要从三个渠道获取图像1使用手机在超市、菜市场、厨房等真实场景下拍摄2从一些开源数据集中筛选出高质量、背景复杂的果蔬图片3利用数据增强技术对已有图片进行扩充。总共收集了约5000张原始图像。类别定义我选取了30种最常见、最容易混淆的果蔬例如苹果、香蕉、橙子、西红柿、黄瓜、西兰花等。这里有一个关键点对于像“青苹果”和“红苹果”我最初考虑设为两个类别但考虑到在结算等应用中通常只关心“苹果”这个大类最终将其合并。同时将“樱桃番茄”和“普通番茄”也进行了合并。这需要在业务需求和技术实现之间做权衡。标注规范与工具采用YOLO格式的标注即每个标注文件.txt与图片同名其中每一行代表一个物体格式为class_id x_center y_center width height坐标和宽高都是相对于图片尺寸的归一化值。标注工具我选用的是labelImg它直接支持YOLO格式导出。在标注过程中我制定了详细的规范边界框要紧贴物体边缘对于部分遮挡的物体按可见部分标注对于成串的葡萄、香蕉等如果单个果实清晰可辨则单独标注如果紧密簇拥则作为一个整体标注。数据集划分按70%训练集、15%验证集、15%测试集的比例进行划分。验证集用于训练过程中的模型评估和早停测试集则是在所有训练调优完成后用于最终报告模型性能确保评估的公正性。3. 核心代码结构与模块解析3.1 环境配置与依赖管理项目的可复现性首先依赖于清晰的环境配置。我使用conda创建独立的Python环境并通过requirements.txt文件严格管理所有依赖包。核心依赖包括torch1.7.0和torchvisionPyTorch深度学习框架。ultralytics/yolov5通过git submodule或直接克隆的方式引入YOLOv5官方源码库。我选择固定某个稳定提交的哈希值以避免未来官方更新可能带来的不兼容问题。opencv-python用于图像读取、预处理和结果可视化。pillow、matplotlib、pandas、seaborn用于数据处理和可视化分析。albumentations一个强大的数据增强库我用它来实现更灵活和高效的在线增强。在requirements.txt中我会明确每个包的大版本号例如opencv-python4.5.5.64。这样可以最大程度保证其他人在不同时间、不同机器上都能成功复现环境。这也是从无数次“在我机器上好好的”的教训中总结出的经验。3.2 数据准备与配置文件详解YOLOv5的数据加载需要两个核心配置文件data.yaml和dataset.yaml名称可自定义但结构固定。data.yaml这个文件定义了数据集的元信息。# 数据集的根目录路径训练时相对于train.py的位置或绝对路径 path: ../datasets/fruits_vegetables # 训练集、验证集、测试集的图片路径列表文件相对path的路径 train: images/train val: images/val test: images/test # 类别数量 nc: 30 # 类别名称列表必须与标注文件中的class_id顺序严格对应 names: [apple, banana, orange, tomato, cucumber, broccoli, ...]关键点path的设定非常灵活。你可以设置为绝对路径也可以设置为相对于训练脚本的相对路径。在团队协作或部署时我推荐在代码中通过一个配置文件或环境变量来动态设置这个路径避免硬编码。数据增强配置YOLOv5的训练脚本train.py内部集成了一套默认的数据增强策略包括马赛克增强Mosaic、随机透视、色彩抖动等。这些默认配置对于大部分场景已经足够。但在本项目中由于果蔬图像可能存在光照不均、反光等问题我通过修改hyp.scratch.yaml超参数配置文件中的相关参数进行了微调将hsv_h色调抖动和hsv_s饱和度抖动的增益略微提高以增强模型对颜色变化的鲁棒性。适度降低mosaic的概率因为在一些特写镜头中马赛克增强可能会破坏单个果蔬的完整特征我设置为0.8。增加了mixup增强这是一种将两张图像线性混合的技术有助于提高模型对重叠物体和噪声的泛化能力设置概率为0.1。3.3 模型训练脚本的核心参数解析训练启动命令看似简单但每个参数都至关重要python train.py --img 640 --batch 16 --epochs 100 --data ./data/fruits_vegetables.yaml --cfg ./models/yolov5s.yaml --weights yolov5s.pt --name fruits_veg_exp1--img 640输入图像尺寸。YOLOv5会将所有图像统一缩放到这个尺寸进行训练。640是速度和精度的一个平衡点。如果你的目标物体通常很小可以尝试增大到832甚至1024但会显著增加显存消耗和训练时间。--batch 16批次大小。这个值首先受限于你的GPU显存。在显存允许的前提下较大的batch size有助于训练稳定。如果出现CUDA out of memory错误需要减小batch size或使用--img更小的尺寸。--epochs 100训练轮数。并非越多越好需要配合早停Early Stopping策略。YOLOv5内置了早停逻辑当验证集指标在指定轮数内不再提升时会自动停止训练并保存最佳模型。--data指向你的data.yaml配置文件。--cfg指定模型结构配置文件。这里使用yolov5s.yaml如果你想使用v5m就改为yolov5m.yaml。--weights yolov5s.pt指定预训练权重。强烈建议使用预训练权重即使是在ImageNet上预训练的权重其提取通用特征的能力也能极大加速你的收敛过程并提升最终精度。这里加载的是官方在COCO数据集上预训练的yolov5s.pt。--name fruits_veg_exp1本次实验的名称。所有输出模型权重、日志、可视化结果都会保存在runs/train/fruits_veg_exp1目录下方便管理和对比不同实验。训练过程监控训练开始后除了观察命令行输出的损失曲线更重要的是利用TensorBoard。YOLOv5会自动记录训练日志只需在另一个终端执行tensorboard --logdir runs/train即可在浏览器中查看丰富的可视化信息包括损失函数变化、验证集精度mAP、召回率Recall、以及模型对验证集图片的预测样例。通过观察这些图表你可以判断模型是否过拟合、欠拟合以及何时可以提前终止训练。4. 模型训练、调优与评估实战4.1 训练流程与关键节点把控启动训练后系统会先进行一个简短的“预热”阶段对数据加载管道和模型前向传播进行测试。之后训练循环正式开始。你需要密切关注以下几个关键节点第一个Epoch结束时查看验证集的mAP平均精度均值指标。如果此时mAP非常低例如低于0.1可能是数据标注格式错误、类别ID不匹配或者学习率设置得极其不合理。一个正常的、使用预训练权重的训练第一个epoch后的mAP通常能达到0.2-0.4取决于任务难度。损失曲线观察训练损失train/box_loss,train/obj_loss,train/cls_loss应该随着epoch增加而稳步下降并在后期趋于平缓。验证损失val/box_loss等初期会随训练损失下降但后期可能会因为模型开始过拟合训练集而有所回升。这是引入早停或调整正则化强度的信号。早停策略YOLOv5默认的早停耐心patience是100个epoch。对于我们的果蔬数据集模型通常在50-80个epoch就会收敛。我通常会设置--patience 30这意味着如果验证集mAP在连续30个epoch内没有提升训练就会停止并自动加载验证集mAP最高的那个模型权重作为最终模型。这能有效防止过拟合并节省计算资源。4.2 超参数调优实战心得YOLOv5的默认超参数在hyp.scratch.yaml中已经过大量实验优化对于新任务不建议进行大刀阔斧的修改。微调应以数据为导向。以下是我针对果蔬识别任务的一些调优经验学习率lr0这是最重要的超参数。默认值0.01对于微调使用预训练权重来说可能偏高。我通常从一个较小的值开始例如0.001并配合学习率调度器如余弦退火。如果训练初期损失下降非常缓慢再适当调高。项目代码中我提供了一个学习率范围测试LR Finder的脚本可以帮助你找到一个合适的初始学习率范围。优化器选择YOLOv5默认使用SGD优化器。对于小批量数据或希望更快收敛的场景可以尝试使用AdamW优化器通过--optimizer AdamW指定。AdamW自适应调整每个参数的学习率通常能减少一些调参工作量但最终模型泛化性能可能略逊于精心调参的SGD。我个人的习惯是先用AdamW快速得到一个baseline再用SGD进行精细调优。数据增强强度如前所述通过hyp.scratch.yaml中的hsv_h,hsv_s,hsv_v,translate,scale,mosaic等参数控制。如果你的数据集背景复杂、物体姿态多变可以增强这些参数。如果你的数据集质量很高、标注很准可以适当减弱增强避免引入过多噪声。注意超参数调优切忌同时调整多个参数。应采用“控制变量法”每次只调整一个参数观察其对验证集mAP的影响记录下最佳配置。4.3 模型评估与性能指标解读训练完成后在实验目录下如runs/train/fruits_veg_exp1会生成一系列结果文件其中最重要的是weights/best.pt最佳模型和results.png结果汇总图。使用以下命令在测试集上评估最佳模型python val.py --data ./data/fruits_vegetables.yaml --weights runs/train/fruits_veg_exp1/weights/best.pt --img 640 --task test评估报告会输出一系列关键指标mAP0.5 (mAP_0.5)在交并比IoU阈值为0.5时的平均精度均值。这是最常用的指标值越高越好达到0.85以上通常说明模型性能优秀。mAP0.5:0.95 (mAP_0.5:0.95)在IoU阈值从0.5到0.95步长0.05区间内计算的平均mAP。这是一个更严格的指标衡量模型在不同定位精度要求下的综合表现。Precision精确率模型预测为正的样本中真正为正的比例。高精确率意味着模型“错认”的情况少。Recall召回率所有真实的正样本中被模型正确预测出来的比例。高召回率意味着模型“漏检”的情况少。对于果蔬识别在结算场景下我们可能更看重精确率因为错把西红柿当成苹果计费会引起客户投诉。而在库存盘点场景下可能更看重召回率不希望漏掉任何一件商品。你需要根据业务需求来权衡。评估脚本还会生成一个混淆矩阵confusion_matrix.png它能直观地展示模型最容易混淆哪些类别。例如你可能会发现“青椒”和“黄瓜”切片状态下、“红苹果”和“西红柿”之间存在一定的误判。这为进一步的数据清洗增加难例样本或后处理规则根据形状、上下文信息提供了方向。5. 模型导出与轻量化部署方案5.1 模型格式转换与优化训练得到的.pt文件是PyTorch的模型权重包含了模型结构和参数。为了在不同平台部署我们需要将其转换为更通用的格式。导出为ONNX格式ONNX是一种开放的模型表示格式被众多推理引擎支持。python export.py --weights runs/train/fruits_veg_exp1/weights/best.pt --img 640 640 --batch 1 --include onnx--img 640 640指定了输入图片的高度和宽度必须是32的倍数。--batch 1指定了批处理大小为1这是很多边缘设备推理的常见设置。导出的ONNX模型可以方便地用OpenCV DNN、TensorRT、ONNX Runtime等库进行加载和推理。导出为TensorRT引擎如果你在NVIDIA Jetson等边缘设备上部署为了极致性能需要转换为TensorRT引擎。这个过程稍微复杂一些通常需要在部署设备上安装TensorRT然后使用export.py的--include engine选项或者使用TensorRT的Python API进行转换。转换过程会进行层融合、精度校准FP16/INT8等优化能显著提升推理速度。在项目指南中我提供了在Jetson Nano上转换和运行TensorRT引擎的详细步骤。5.2 基于OpenCV的本地实时推理Demo为了快速验证模型效果我编写了一个基于OpenCV的Python推理脚本。这个脚本不依赖PyTorch只依赖OpenCV和NumPy非常轻量。import cv2 import numpy as np # 加载模型和类别名称 net cv2.dnn.readNetFromONNX(best.onnx) with open(data/classes.names, r) as f: classes [line.strip() for line in f.readlines()] # 预处理函数 def preprocess(image, input_size(640, 640)): # 保持长宽比resize并在边缘填充灰色 h, w image.shape[:2] scale min(input_size[0] / h, input_size[1] / w) new_h, new_w int(h * scale), int(w * scale) resized cv2.resize(image, (new_w, new_h)) # 创建画布并填充 canvas np.full((input_size[0], input_size[1], 3), 114, dtypenp.uint8) canvas[:new_h, :new_w, :] resized # 归一化、BGR2RGB、HWC转CHW blob cv2.dnn.blobFromImage(canvas, 1/255.0, swapRBTrue) return blob, scale, (h, w) # 后处理函数解析YOLO输出 def postprocess(outputs, conf_thresh0.25, iou_thresh0.45): # outputs是模型输出需要根据模型结构解析出边界框、置信度、类别 # 这里是一个简化的示例实际需要根据导出的ONNX模型输出维度进行调整 # 通常包含非极大值抑制NMS步骤 # ... return boxes, scores, class_ids # 主循环 cap cv2.VideoCapture(0) # 打开摄像头 while True: ret, frame cap.read() if not ret: break blob, scale, orig_shape preprocess(frame) net.setInput(blob) outputs net.forward(net.getUnconnectedOutLayersNames()) boxes, scores, class_ids postprocess(outputs) # 在原始帧上绘制结果 for box, score, cls_id in zip(boxes, scores, class_ids): # 将归一化坐标还原为原始图像坐标 x1, y1, x2, y2 box label f{classes[cls_id]}: {score:.2f} cv2.rectangle(frame, (x1, y1), (x2, y2), (0,255,0), 2) cv2.putText(frame, label, (x1, y1-10), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0,255,0), 2) cv2.imshow(FruitVegetable Detection, frame) if cv2.waitKey(1) 0xFF ord(q): break cap.release() cv2.destroyAllWindows()这个Demo清晰地展示了部署的核心流程预处理、网络推理、后处理。后处理中的非极大值抑制NMS是关键它用于剔除冗余的重叠检测框。你需要根据模型的实际输出维度来编写解析逻辑。6. 常见问题排查与性能优化技巧6.1 训练过程中的典型问题问题1训练损失Loss不下降或者出现NaN。可能原因与排查学习率过高这是最常见的原因。过高的学习率会导致优化过程在最优解附近震荡甚至发散。解决方案立即停止训练将学习率hyp.scratch.yaml中的lr0降低一个数量级例如从0.01降到0.001重新开始。使用预训练权重时学习率通常需要设得更低。数据标注错误检查标注文件的格式是否正确特别是坐标值是否在[0,1]范围内类别ID是否从0开始连续编号。一个快速检查的方法是使用YOLOv5自带的detect.py脚本用训练好的模型哪怕是初始权重对训练集图片跑一遍看看标注框和预测框是否能大致对齐。命令python detect.py --weights yolov5s.pt --source path/to/train/images --save-txt它会将预测结果和标签一起显示。数据路径错误确保data.yaml中的path、train、val路径设置正确并且图片和对应的标签文件确实存在。我的经验遇到Loss为NaN我首先会检查数据集中是否有损坏的图片用OpenCV的imread检查是否能正常读取或者是否有标注框的坐标超出了图像边界这可能在数据增强时产生非法坐标。问题2验证集mAP很低但训练集损失正常下降过拟合。可能原因与排查数据量不足这是小数据集最常见的问题。模型记住了训练集的所有细节但无法泛化到新数据。解决方案加强数据增强增大hyp.scratch.yaml中的增强参数或者收集更多、更多样化的数据。使用albumentations库可以添加更复杂的增强如随机遮挡、模糊、天气模拟等。模型过于复杂对于只有几千张图片的数据集使用yolov5x这样的大模型很容易过拟合。解决方案换用更小的模型如yolov5s或yolov5n。或者在模型配置文件中增加Dropout层、权重衰减--weight-decay参数等正则化手段。训练轮数过多即使有早停如果耐心值设置过大模型也可能在验证集指标停止提升后继续“记忆”训练集。解决方案减少早停耐心--patience或手动监控TensorBoard在验证集mAP开始下降时提前终止训练。6.2 部署与推理阶段的性能瓶颈问题模型推理速度慢无法满足实时性要求如30 FPS。优化策略层级模型层面换用更小的模型从v5m降级到v5s甚至v5n。这是提升速度最有效的方法但会牺牲一定精度。需要进行权衡测试。输入分辨率降低--img参数例如从640降到416或320。分辨率降低会直接减少计算量但对小物体的检测能力会下降。对于果蔬识别大部分物体在320x320的输入下依然可辨。推理引擎将PyTorch模型转换为TensorRT或OpenVINO等优化后的推理引擎通常能获得1.5倍到数倍的加速。特别是在Intel CPU上OpenVINO的优化效果非常显著。后处理优化NMS是CPU上的操作可能成为瓶颈。可以尝试调整NMS的置信度阈值conf-thres和IoU阈值iou-thres。提高置信度阈值可以直接过滤掉大量低质量预测框减少NMS的计算量。使用更高效的NMS实现如Fast NMS或TorchVision的NMS如果使用PyTorch推理。硬件利用确保推理时GPU被充分利用。使用torch.cuda.synchronize()和Python的time模块精确测量前向传播时间排除图像读取、预处理、后处理和显示的时间开销。真正的模型推理时间应该远小于总时间。问题模型在真实场景下误检或漏检严重。排查与解决领域差异训练数据超市摆拍和真实部署环境厨房昏暗光线、手持抖动存在差异。解决方案进行“领域适配”。收集少量真实场景下的图片即使不标注与训练集图片一起进行在线增强让模型在训练时就看到更多样的背景和光照条件。或者使用生成对抗网络GAN进行风格迁移将真实场景图片“翻译”成类似训练集的风格。难例挖掘将模型在真实场景中识别错误的图片收集起来重新标注加入到训练集中进行第二轮训练。这个过程可能需要迭代几次。集成后处理逻辑利用业务逻辑。例如在自助结算柜中可以结合重量传感器信息如果视觉识别出一个“苹果”但重量传感器显示重量极轻则可能是一次误检可以结合其他帧的信息进行投票决策。6.3 数据集构建与管理的经验之谈数据标注的“脏活”与技巧多人标注一致性如果项目需要多人标注务必先制作详细的标注规范文档并针对边界案例如严重遮挡、部分出镜、奇异形状进行统一规定。然后让所有标注员对同一批图片进行标注计算他们之间的一致性如IoU对差异大的地方进行讨论和规范统一。主动学习初始模型训练好后用它去预测大量未标注的图片。筛选出那些模型置信度低、或者预测结果矛盾的图片例如同一类物体有的预测框置信度高有的低这些往往是“信息量”大、对模型提升有帮助的难例优先标注它们可以高效提升数据集质量。数据清洗定期检查数据集剔除模糊、过暗、过亮的低质量图片。检查标注框修正错误的类别和不准的边界框。一个干净的数据集比一个庞大但嘈杂的数据集更有价值。这个YOLOv5果蔬识别项目从数据到部署的完整链路走下来其价值远不止于识别几种水果蔬菜。它提供了一个标准的计算机视觉项目模板其中涉及的数据处理、模型训练调优、问题排查和性能优化思路可以迁移到任何其他的目标检测任务中比如工业零件检测、交通标志识别、野生动物监测等。本文还有配套的精品资源点击获取