简介基于YOLOv5的果蔬识别系统完整项目适合计算机专业毕业设计、课程设计及深度学习实战练习者可解决从数据准备到目标检测系统落地的完整问题。项目提供果蔬图片数据集、标注文件、源码与配套教程覆盖数据清洗、划分、模型训练、评估和实时窗口识别等环节代码经过调试可直接运行也便于二次拓展。资源包共含56个文件、约94MB主要文件类型包括14个Python脚本、多张图片与XML标注、h5模型文件、txt记录和Markdown说明分别对应预处理与训练工具、训练样本、已训练模型以及测试记录和文档。目前已有54人学习/下载。教程部分着重讲解环境配置、YOLOv5训练流程与常见报错处理配合源码可快速搭建果蔬识别Demo。对于需要完成高分毕设或希望深入理解目标检测原理的学习者这份资源提供了完整的数据集、可复现的实验脚本和清晰的实践路径实用价值较高。1. YOLOv5果蔬识别系统能直接上手跑通的数据、源码与指南在毕业设计立项节点很多人会被一套YOLOv5果蔬识别系统吸引它把数据集、源码和操作指南打包成一份可以直接跑通的资产省掉从爬图到逐张标框的大半个月时间。这套资源解决的是目标检测里最典型的问题——对苹果、香蕉、番茄这类常见果蔬做分类识别同时输出类别和位置框最终落成一个可视化Demo或Web端识别工具。源码层是工程化的YOLOv5训练加推理流程数据层是已经整理成标准格式的标注集文档层负责把参数和踩坑点讲清楚。适合两类人一类是拿它做毕业设计或课程设计的计算机相关专业学生另一类是刚接触目标检测、想要一个完整闭环而不是只会改官方示例的开发者。它最大的价值不是算法新而是“数据、代码、指导”三件事同时齐了——你省下的是从零到一的定位问题时间而不是只缺模型文件。2. 代码与数据长什么样从目录结构看懂训练入口2.1 代码组织找对入口比通读源码更重要拿到资源包先别急着装环境我一般习惯先把目录树拉一遍。YOLOv5这类工程项目的代码不是靠通读理解的是靠跑通一条主链路后反向吃透的。这套资源里最常见的组织方式与官方仓库保持了一致train.py负责训练detect.py负责推理export.py负责模型导出models目录放网络结构定义utils目录放损失计算、数据增强、日志记录等工具函数data目录通常放数据集配置yaml。把train.py和detect.py先标出来就够了——训练和测试你的毕设场景只跟这两个文件强相关其他地方大多不需要深读。代码包通常会附带一个requirements.txt列出依赖版本范围还会有一个hyp文件目录存放数据增强和优化器相关的超参数配置。真正动手前建议看两眼这个目录里是否有best.pt或last.pt权重文件如果有意味着这套资源已经跑通过一轮训练你后续做增量训练或直接推理验证都会顺利很多。如果只有空项目结构和数据那就得从头训练时间预算要按数据集规模重新估算。2.2 果蔬数据集的目录与标注格式数据集部分一般按YOLO标准格式组织。根目录下分出images和labels两个主干各自再按train、val、test划分。images里是果蔬图片labels里是与图片同名的txt文件每一行对应一个目标框dataset/ ├── images/ │ ├── train/ │ ├── val/ │ └── test/ └── labels/ ├── train/ ├── val/ └── test/labels中每行文本的形式是“class_id x_center y_center width height”五个字段分别对应类别编号、归一化后的框中心点x坐标、中心点y坐标、归一化宽和高。归一化指除以图片宽高取值范围在0到1之间。比如“0 0.5123 0.4768 0.2234 0.3189”表示这个框属于类别0中心点在图片横向51.23%的位置纵向47.68%的位置宽度占图片总宽的22.34%。这里有个容易踩的细节图片集里如果混入了PNG透明背景通道或者多页TIFFYOLOv5读取后会因为通道数不一致在训练时报警第3章我会给一个数据体检脚本先用它过滤一遍比到训练中炸掉再回来排错省心得多。2.3 先跑一次侦察利用现成权重验证链路如果资源包里带了权重文件动手训练前应该先做一次推理侦察。此时环境如果是现成的直接执行python detect.py --source ./inference_demo/apple.jpg \ --weights best.pt \ --conf-thres 0.25 \ --save-txt逻辑说明这条命令把推理入口先跑通。--source指定输入的测试图片路径--weights指定用哪套权重--conf-thres控制置信度过滤阈值0.25表示低于这个置信度的检测结果不输出--save-txt要求把识别结果写到txt文件中方便自查。参数说明如果测试图片里有多类果蔬建议把--conf-thres调低到0.1看原始检测能力而不是一开始就卡高阈值否则模型明明能识别但被阈值过滤掉很容易误判成权重坏了。这一步的意义不在于测精度而在于确认“代码、权重、环境”三者的基本兼容性。跑通后再回来搭环境或改参数思路会清晰很多。如果是新机器把这条命令先记录下来第3章装好依赖后回头跑。3. 环境搭建与数据集落地先把数据可靠喂进工程3.1 虚拟环境与依赖安装环境这块我的建议永远是“独立虚拟环境优先”。不要直接装在系统的全局Python里因为你接下来很可能还要跑其他课程项目依赖版本互相打架是常态。用conda建环境最省心执行conda create -n yolov5-fruit python3.9 -y conda activate yolov5-fruit pip install -r requirements.txt逻辑说明第一行创建名为yolov5-fruit的隔离环境指定Python 3.9版本第二行激活环境第三行按requirements.txt安装项目依赖。这个顺序不要颠倒也不要先pip后建环境。参数说明YOLOv5对Python版本要求不算苛刻3.8到3.10都能跑。PyTorch版本建议1.10以上2.0也兼容但注意先装好对应CUDA版本的PyTorch再装requirements.txt否则requirements里的torch可能被降级或覆盖。显卡是NVIDIA RTX系列就装CUDA 11.8相关的版本显卡显存小或没有独显就老实装CPU版——能训练只是单张640的图在CPU上可能要跑十几秒一轮先拿它验证流程真正考研的还是时间。3.2 写个脚本先给数据集做体检这一步我在拆过几套资源后变得特别固执先校验再训练。数据集本身质量不行后面所有mAP分析都是白搭。在项目根目录下新建一个check_dataset.pyfrom pathlib import Path data_root Path(datasets/fruit) class_num 10 # 与后面 fruit.yaml 里的 nc 保持一致 def check_split(split: str): label_dir data_root / labels / split issues [] for txt in sorted(label_dir.glob(*.txt)): if txt.stat().st_size 0: issues.append(f{txt.name}: 空标签文件) continue for idx, line in enumerate(txt.read_text(encodingutf-8).strip().splitlines()): parts line.split() if len(parts) ! 5: issues.append(f{txt.name}:{idx 1} 列数不为5) continue cid int(parts[0]) if cid class_num: issues.append(f{txt.name}:{idx 1} 类别ID {cid} 超出范围) try: x, y, w, h map(float, parts[1:]) except ValueError: issues.append(f{txt.name}:{idx 1} 坐标解析失败) continue if w 0 or h 0: issues.append(f{txt.name}:{idx 1} 宽高非正) return issues for split in [train, val]: problems check_split(split) if problems: print(f[{split}] 发现 {len(problems)} 个问题:) for p in problems[:20]: print( , p) else: print(f[{split}] 校验通过)逻辑说明脚本首先检查标签文件是否为空文件空标签在训练中会导致该图片被跳过但日志不提示数据量少时影响明显。然后逐行检查标签格式列数必须是5类别ID不能超过预设的class_num宽高必须为正数。它不检查坐标是否小于0到1区间因为YOLO的归一化框超出边界虽然不报错但会在计算损失时出现怪异的表现这种可以在第2阶段再补。参数说明class_num填10只是示例务必替换成你数据集中实际的类别数与后续fruit.yaml里的nc一致。跑完后输出的问题文件列表要逐条核对最常见的结果是标注软件把类别从1开始编号而YOLO要求从0开始整体偏移一位这种问题继续往后的复现价值就是浪费显卡。3.3 fruit.yaml数据集的“说明书”YOLOv5训练时需要一份描述数据集的yaml文件写好它是训练能跑通的前提。打开data目录按如下结构写一份fruit.yaml# 数据集配置文件 path: datasets/fruit # 相对于 train.py 运行路径 train: images/train val: images/val nc: 10 names: 0: apple 1: banana 2: tomato 3: orange 4: potato 5: carrot 6: cucumber 7: pepper 8: grape 9: pear逻辑说明path定义数据集根目录train和val分别指定训练集与验证集的图片子目录YOLOv5会自动在同级目录下寻找对应的labels子目录。nc是类别总数names是类别名称列表顺序必须和标签txt里的class_id一一对应这一段如果错位模型训练的损失会奇怪地下降不了。参数说明path字段建议直接改成绝对路径比如D:/cv_projects/datasets/fruit尤其在Windows上跑的时候相对路径会因为终端工作目录不同而找不到数据。names里的名称只是给人看的不参与训练计算但导出报告和推理输出时会用到所以尽量跟标签ID的语义保持一致。有些资源包里的yaml把train写成“images/train”而val写完整的“labels/val”这种写法在部分YOLOv5版本里也能跑但我建议统一只写图片路径那层让代码自动匹配标签路径减少版本差异带来的坑。到这里数据环境的准备工作已经做完。4. 训练参数怎么调从损失曲线到mAP的取舍4.1 训练入口与关键命令数据就绪后训练命令看这一条就够了python train.py \ --data datasets/fruit.yaml \ --weights yolov5s.pt \ --img 640 \ --epochs 200 \ --batch-size 16 \ --device 0 \ --workers 4逻辑说明--data指向刚写好的数据集配置--weights指定预训练权重或基础权重。YOLOv5会先按yolov5s.pt的结构初始化模型再根据fruit.yaml里的nc调整输出层类别数。--img定义训练时输入尺寸640是精度与速度的经典平衡点--epochs定义整个训练集的遍历轮数果蔬识别这种数量不大的数据集100到200轮足够收敛--batch-size是每批样本数直接影响显存占用和梯度稳定性。参数说明预训练权重的选择有个经验值先看这个表权重文件参数量级适用场景yolov5n.pt约1.9M速度优先、边缘设备yolov5s.pt约7.2M默认首选精度速度平衡yolov5m.pt约21.2M精度优先、显存充裕果蔬识别场景我通常推荐yolov5s起步。n对小目标多或相似外观类别多的数据不够用m在普通8G显卡上勉强能跑但训练时间会明显变长。--device 0表示用第一张GPU不写则默认CPU机器有卡但忘记指定就会出现训练速度奇慢的现象。--workers是数据加载线程数Windows下建议4以内设太大会因为进程启动开销反而变慢。4.2 超参数调节果蔬场景的增强倾向YOLOv5把学习率、数据增强强度等超参放在data/hyps目录下的yaml文件里。果蔬识别有个明显特点同一类目标的光照变化、表面反光和遮挡程度差异大比一般交通标志识别更依赖数据增强。默认的hyp.scratch-low.yaml就能用但如果发现验证集上泛化不足优先调增强参数而不是无脑加训练轮数。比较推荐的调整方向是hsv增强。默认的hsv_h、hsv_s、hsv_v控制色调、饱和度和明度的随机扰动范围果蔬表面颜色是分类的重要依据扰动调太大会让苹果的红色和番茄的红色混在一起调太小又对光照变化不鲁棒。一般把hsv_s从0.7提一点到0.8hsv_v保持0.4不变让模型对同一种果蔬的颜色深浅更耐受。还有一个初学者容易忽略的参数是mosaic。默认训练前10轮会启用mosaic增强把四张图拼在一起训练能显著提升小目标的检测能力但拼接图会引入大量跨类别边缘噪音最后10轮建议关掉让模型在接近真实分布的输入上做最后的收敛。YOLOv5的hyp文件里通过mosaic参数控制启用概率想按轮数动态调整的话可以看utils/autoanchor.py中相关的逻辑或者干脆保持默认不改对果蔬识别这种类别数在十位数的任务来说默认配置已经是经验上较稳的选择。4.3 训练过程监控怎么判断模型真的在变好训练启动后不要干等进度条。看一眼训练输出目录runs/train下的新exp文件夹里面有逐轮的results.png和weights目录。results.png是训练过程的可视化包含box_loss、cls_loss、mAP0.5等曲线的总图。我判断模型状态主要看两个指标mAP0.5稳定上升且不震荡说明训练方向正确cls_loss持续下降但mAP开始平台期说明已经接近这个数据规模的上限再加大epochs也只是过拟合。实时监控用TensorBoard更直观训练过程中另开一个终端执行tensorboard --logdir runs/train逻辑说明这条命令启动TensorBoard服务读取runs/train下所有训练日志在浏览器里打开日志中提示的端口就能看到loss和mAP的实时曲线。加了--logdir指向训练输出目录能同时对比多轮实验的曲线判断调参方向。参数说明weights目录下会保存best.pt和last.ptbest是验证集mAP最高的权重last是最后一轮的权重。只评估模型质量就只看best想继续从上次状态加练就用last。注意不要直接拿last做最终部署模型它往往已经过拟合了。YOLOv5的终止条件由patience控制训练80轮后mAP无提升会自动停止这个默认值是100如果时间紧可以改成50减少无用等待。5. YOLOv5果蔬识别避坑实录五个高频翻车点与排查训练和推理环节看着顺真正动起手来翻车的点比想象中密集。下面这几个坑是我拆项目时遇到频率最高的每条都按现象、原因、解决的顺序说透。其中不少坑资源包里如果指南没写到实践时就是一眼难防的“黑匣子”。5.1 报错“class out of range”数据集全废了现象启动训练后没有进入进度条控制台直接抛AssertionError或IndexError提示标签中存在超出nc范围的类别ID。原因标注工具导出的类别编号从1开始而YOLO要求从0开始导致所有标签的class_id整体偏移一位或者数据集里混入了另一批果蔬的标注类别总数计算错误。解决跑第3章那个check_dataset.py它会精准输出哪些文件的哪些行ID超界。如果是整体偏移一位用一个简单循环把所有txt里每个ID减1即可不要手动改文件。如果只是个别几行直接删除该文件或重标这几个目标更好——数据量本身不大没必要为几个坏标注牺牲训练稳定性。5.2 GPU显存不足一调batch-size全盘重来现象训练到第几轮时突然报CUDA out of memory进程直接退出前面的训练时间全部作废。原因果蔬图片分辨率高640输入尺寸下batch-size设为16在8GB显存的显卡上基本是极限部分型号显卡还会因其他进程占用显存导致可用显存更少。解决先把batch-size降到8如果还爆就降到4。batch减半带来的梯度不稳定对果蔬这类简单场景影响很小。另一个省显存的有效手段是加--cache把数据预加载到内存减少GPU和CPU之间的数据搬运开销但内存不足时不要开会直接换一种方式爆掉。若显卡老旧只有4GB显存把--img降到416也能跑mAP会损失几个点但流程能完整走通。5.3 训练跑到半夜被中断第二天从头再来现象训练进度到了120轮突然断电或误关终端重新启动train.py后发现从第0轮开始。原因train.py默认从零开始没有加载上次断点。如果命令行里没有指定--resume它不会自动找runs/train下的last.pt继续。解决重新执行训练命令并把--weights指向上次的last.pt同时加--resumepython train.py --data datasets/fruit.yaml \ --weights runs/train/exp/weights/last.pt \ --resume逻辑说明--resume会让YOLOv5读取上次训练的完整状态包括优化器、超参数和当前轮数从断点继续跑而不是用预训练权重重新开始。参数说明--weights必须指向last.pt所在的完整路径如果上次训练中断在第100轮续跑后的训练轮数会接着100往后算不需要手动把epochs改小。我一般睡前跑长任务都会把这条命令写在终端旁边防止半夜醒来看到从0开始的惨剧。5.4 数据路径带中文图片一张都读不进来现象训练能启动但每张图片都报错“could not be read”或部分图片加载为None直接跳过最终有效训练图片数为0。原因Windows环境下OpenCV的imread不支持中文路径而数据集目录里恰好有中文文件夹名或者项目本身放在中文用户目录下。解决把整个项目和数据集移到纯英文且不含空格的路径下比如D:/cv_projects/yolov5_fruit重跑训练前确认fruit.yaml里的path也改成这个绝对路径。检查路径是否还有隐藏问题在Python里执行os.path.exists指向data路径返回True再开始训练。这个问题跟代码本身无关纯属环境问题但遇到的人比例极高尤其在高校机房机器上用户名多半是中文。5.5 验证集mAP高达0.85实拍照片一测全是漏检现象训练结束看指标很漂亮mAP0.5到了0.85但把模型拿到手机拍的果蔬照片上测试大量漏检或错分类。原因数据集划分时同角度同光线连续抽帧的图片被同时分进train和val验证集和训练集相似度过高指标虚高另一个常见原因是数据标注框太紧把果蔬边缘刚好切掉模型学到的特征太局限。解决重新划分数据集保证同一场景的不同帧不能同时出现在训练和验证里。验证时不要只看mAP单独拿一批全新的实拍图做一个快速子集跑推理统计看真实识别率。标注时每个框外扩2%到5%的边界给模型留出上下文特征空间比任何超参调整都更直接改善泛化。这个“指标好看、实际拉垮”的问题在目标检测项目里出现频率极高水份大的验证集不如不做。6. 推理验证与模型导出把识别能力真正用在图片和视频上6.1 detect.py 的实际参数细节训练结束后用测试集跑一遍完整推理确认模型在真实多样场景下的表现python detect.py --source ./test_imgs \ --weights runs/train/fruit/weights/best.pt \ --conf-thres 0.35 \ --iou-thres 0.45 \ --save-txt \ --project ./runs/detect \ --name fruit_test逻辑说明--source指向测试图片目录--weights使用验证集最优权重--conf-thres从默认的0.25调高到0.35果蔬识别场景目标明显且类别差异大阈值太低会产生一堆低置信度误检框调高反而干净。--iou-thres控制NMS去重时的IoU阈值多个重叠框超过该阈值会合并。--save-txt额外保存检测结果到txt文件方便后续做错误分析--project和--name共同决定结果输出目录。参数说明如果只想检测特定类别加--classes 0 2 5只输出apple、tomato这两类其他类别直接过滤这在后期做局部优化时省去不少噪音。对视频做推理时--source指向视频文件路径或摄像头序号0模型会自动切换到流式模式。6.2 把best.pt导出为ONNX做进一步部署毕设如果需要做一个可执行的演示程序ONNX是相对通用的部署格式。直接在项目根目录运行python export.py --weights runs/train/fruit/weights/best.pt \ --include onnx \ --opset 12逻辑说明export.py读取权重把PyTorch模型结构导出为ONNX图--include onnx表示本次只导出ONNX格式--opset 12指定ONNX算子集的版本对大多数推理框架兼容性较好。导出成功后同目录下会生成同名.onnx文件。参数说明如果后续要部署到边缘设备建议加--simplify清理冗余算子导出速度更快、体积更小。ONNX型号对动态输入尺寸支持有限导出的模型会固定为训练时的640输入部署时输入图片统一缩放到640再推理即可。这一步做顺了后面接TNN、OpenVINO甚至直接用onnxruntime写个Python推理脚本都有资料可查。6.3 用测试集做一次“错题本”检查模型导出前先做最后一步验证把测试集完整跑一遍看保存的txt结果文件逐张对照原图。我习惯关注置信度在0.3到0.5之间的检测框这些是模型的“犹豫地带”要么是标注不准确要么是模型特征没学全。从输出目录里筛选低置信度文件的方法在命令行终端里可以配合--conf-thres临时调低一档来观察那些被过滤掉的预测框这样能直观看到模型能力边界在哪里。从那以后我每次拿到新数据集都会强制走一遍全套流程先跑数据体检脚本再跑推理侦察确认环境最后才开正式训练。尤其是换机器的时候这套流程能挡掉七成以上莫名其妙的问题。希望帮到你。本文还有配套的精品资源点击获取