☰
基于YOLOv5的智能生活垃圾分类系统从训练到部署全解析
2026/9/26 17:24:55 网站建设 项目流程

简介:这套基于YOLOv5的智能生活垃圾分类系统源码,是面向毕业设计、期末大作业与课程设计的高分完整项目。项目由作者手动搭建并获导师认可,系统功能完善、界面美观、操作简单,代码采用YOLOv5目标检测框架,完整覆盖模型训练、推理检测、摄像头实时识别、机械控制等流程,注释细致,适合有Python基础的初学者阅读和二次开发。压缩包仅178KB,共76个文件,其中40个Python脚本承担训练、检测与控制等核心逻辑,22个YAML文件用于模型结构与训练参数配置,其余Markdown文档、Shell脚本、Dockerfile等辅助环境部署与说明,目录结构清晰,便于按模块查阅。目前已累计有165人学习下载。借助该系统,读者可快速搭建一套可演示的垃圾分类系统,理解深度学习项目从数据预处理到模型部署的完整链路,同时其控制模块便于扩展硬件联动,能为答辩展示与后续研究提供扎实基础。

1. 智能生活垃圾分类系统,为什么用YOLOv5能直接落地成毕设

先想象答辩现场最常出现的画面:摄像头对准几个饮料瓶、快递纸箱和外卖残余,屏幕上依次框出“可回收物”“厨余垃圾”,评审老师的注意力瞬间被抓住。基于YOLOv5的智能生活垃圾分类系统要交付的,恰恰是这条从一帧画面到分类结果的可运行链路,而不是论文里一张静态流程图。它适合两类人:一是准备毕业设计,想完完整整跑通一次目标检测工程的学生;二是想把YOLOv5迁移到安全帽识别、仪表读数等垂直场景的工程新手。整条路线的核心成本不在网络结构,而在数据集整理与部署调试。接下来按决策、数据、训练、部署四段展开,最后落到答辩前最容易失分的地方。

2. 先定分类体系再选型:这套系统到底分哪些垃圾,YOLOv5凭什么接得住

同样是“垃圾分类”,不同人拿到的题目差得很远。有的要求识别桌上的单件物品,有的要求对整袋垃圾做多目标检测。常见的智能生活垃圾分类系统,更接近第二类:你要在一个画面里同时框出多个物体并给出类别。如果一开始没把这个“分类体系”拍死,后面数据集、标签、训练全都会来回返工。所以动代码之前,先把类别和检测目标想清楚,这份时间花得最值。

多数地方执行的四分类标准是:可回收物、有害垃圾、厨余垃圾、其他垃圾。如果直接把这四个词当成检测类别,模型会懵:一个装着剩饭的外卖盒,到底算厨余还是其他?垃圾桶前拿着半杯奶茶的人,按常识该扔厨余,但摄像头看不透杯壁。检测任务只能依靠“外观上稳定可区分”的对象来定义类别,这也是整个方案里最需要和指导老师提前对齐的一点。

2.1 垃圾分类的类别怎么定——以四分类为基础,给出一套8类可行清单

我的习惯是,在“可回收物、有害垃圾、厨余垃圾、其他垃圾”的大框架下,把视觉上差异大、出镜率高的对象单独拆出来,剩下的全部归入“其他”。这样做的好处是模型不用去学“抽象概念”,只学“长成什么样的东西”。下面这套8类方案,是我在类似项目里常用的一版:

类别ID名称视觉判定标准
0plastic_bottle透明或半透明塑料瓶,瓶身有明显棱线
1aluminum_can金属易拉罐,有明显圆柱形金属反光
2cardboard瓦楞纸箱、快递盒,表面有波纹纹理
3glass_bottle玻璃瓶,透明且厚壁,折光明显
4paper纸张、报纸、传单,薄片状
5organic剩菜剩饭、瓜皮果核,通常装在袋子/盒子里
6hazardous电池、过期药品、带明确危险标识的小包装
7other以上都匹配不上的物品

这套清单有几个刻意为之的设计:plastic_bottle 和 glass_bottle 拆开,是因为两者形状相似但材质不同,纯视觉上容易混淆,拆开后模型能专注学“反光特征”;hazardous 只保留明确外观特征的电池和药瓶,不会强行让模型认识所有有害物。我曾经试过加一个“陶瓷类”,结果陶瓷碗和纸碗在照片里几乎无法区分,最后整个类别的召回率始终上不去。

这里有一条避坑原则:两个类别如果连人眼都经常分不清,就不要同时出现在标签表里。比如“干净纸箱”和“带胶带的纸箱”可以合并成 cardboard,胶带属于可接受干扰;“电池”和“药品包装”如果样本太少,需要合成一类 hazardous。宁可类别粗一点,也不要让模型在边界样本上反复横跳。

2.2 为什么选YOLOv5而不上YOLOv8或Faster R-CNN:算力、生态与文档三重考虑

网上随手一搜就是YOLOv8、YOLOv9的新消息,但真正落到“自己训练数据集、做毕设交付”这件事上,YOLOv5仍然是性价比最高的选择。这不是因为它结构最新,而是因为围绕它的资料密度、踩坑记录和配套工具最完整。训练一个自定义数据集,从标注、训练、看到结果文件到部署,YOLOv5的生态几乎把所有中间环节都做成了一行命令。

对比项YOLOv5YOLOv8Faster R-CNN
训练脚本完整度自带train/detect/val/export高,但接口变化快需要自己拼装
单卡显存开销低,s模型约14MB权重同级模型略高明显偏高
社区教程与问答密度极高中等高
迁移到边缘设备的案例多较少少
新手独立跑通难度低中高

对毕设场景来说,最重要的指标不是“谁mAP更高”,而是“我卡住的时候能不能在一个小时内找到答案”。YOLOv5的报错信息全网都有对应记录,连“conda yolov5环境配置”这种基础问题都能翻到完整步骤,这对时间紧的学生非常友好。Faster R-CNN虽然两阶段精度理论上更细,但训练显存和时间都不划算,用来做垃圾分类属于杀鸡用牛刀。

再从网络结构角度说一句:YOLOv5的骨干网络是CSPDarknet,负责从图像里提取不同尺度的特征;颈部用PANet把深层语义信息和浅层位置信息做融合;检测头在三个尺度上输出预测框。为什么这套结构适合垃圾场景?因为垃圾的尺度跨度太大,矿泉水瓶盖在一张640×640的图里可能只有十几个像素,旁边的纸箱又能占满整张图。YOLOv5的多尺度输出天生就是为这种情况设计的,这也是我第一次看YOLOv5网络结构图时最该记住的部分。

2.3 系统总体结构:从摄像头到分类框的数据流,落在哪几个文件

拿到一份“源码+详细文档”的项目包,先别急着点运行,先找五个东西:入口脚本、推理封装类、数据配置、权重文件、文档。按这个顺序读,能最快判断这套代码是能跑通的完整工程,还是只贴了训练脚本的半成品。一个常见可落地结构大致长这样:

  • demo.py:入口,负责加载界面、打开摄像头或选择图片;
  • detector.py:核心推理类,把模型加载、预处理、后处理封装成接口;
  • configs/data.yaml:类别名和数据集路径;
  • weights/best.pt:训练好的模型权重;
  • validate.py:用固定测试集跑一遍并输出指标。

数据流通常是:读取摄像头帧或图片 → 按letterbox方式缩放到640×640 → 模型前向推理 → NMS去重和置信度过滤 → 把坐标映射回原始画面 → 在界面上画框并记录结果。这里的letterbox不是简单resize,而是保持宽高比的同时填充灰色边,避免物体被拉伸变形。如果源码里预处理直接用了cv2.resize,后续识别框位置大概率会偏。

搞清这条主线之后,再去细读训练和文档,效率高很多。尤其注意文档里的“运行环境”段落,PyTorch版本、Python版本、依赖库缺一不可;很多项目包明明代码没毛病,却因为Python 3.11下某个依赖编译失败,第一步就卡死。后面第4章会专门给出环境配置的稳定做法。

3. 生活垃圾数据集准备:标注规范、目录结构与YOLO格式转换

数据集是这套系统里最容易被低估的部分。很多同学拿到别人提供的“免费python源码大全”式压缩包,里面往往自带一份数据集,但这份数据集很可能存在类别错乱、图片和标签对不上、标注框贴着图片边缘等问题。正确做法是:先验证数据,再写训练命令。验证数据这一步花半小时,能避免后面训练三小时白跑。

3.1 公开数据集怎么选:类别配额与边界样本的补充思路

常见的公开生活垃圾数据集,来源大体分两类:一类是高校实验室发布的四分类图片集,一类是TrashNet这类以单物品为单位的英文标注集。使用前一定要看清它的类别体系和你定的8类能不能对齐。很多数据集把“塑料瓶”和“塑料杯”分成两类,而你的方案里只有plastic_bottle,这时候要么合并,要么干脆不用那一类。

类别的样本量分配,我建议每类最少300张,最好能到500张以上。刚凑够100张训练出来的模型,在测试图片上可能挺准,一到摄像头实拍就露馅。原因是样本多样性不够:同一个饮料瓶在白色桌面、草地、垃圾桶内、夜晚灯光下的表现完全不同,模型没见过的环境就会被误判。补充数据最省钱的办法是拿手机自己拍,同一件垃圾换五六个背景,再拍几段视频抽帧,一个类别很容易凑到几百张。

边界样本指的是那些“长得像但其实是另一类”的图片。比如透明矿泉水瓶和透明玻璃瓶,正面看都是细长透明体;纸碗和纸箱表面都有瓦楞纹。这些样本要专门从训练集里抽出来检查一遍标签,把不确定的删掉或重标。忽略这一步,模型训练完的混淆矩阵里,这两类就一直是邻居。

3.2 把图片和标签整理成YOLOv5的目录结构:拆分脚本与data.yaml写法

YOLOv5官方约定,数据集目录一定要按images和labels分开,train和val再各自独立。目录结构如下:

datasets/hw_garbage/ ├── images/ │ ├── train/ │ └── val/ ├── labels/ │ ├── train/ │ └── val/ └── data.yaml

图片统一用jpg或png,标签统一用同名txt。下面这段脚本负责把收集到的原始图片按85:15拆成训练集和验证集:

import random import shutil from pathlib import Path src_img = Path("raw_images") # 你收集的所有图片 train_img = Path("datasets/hw_garbage/images/train") val_img = Path("datasets/hw_garbage/images/val") train_img.mkdir(parents=True, exist_ok=True) val_img.mkdir(parents=True, exist_ok=True) imgs = list(src_img.glob("*.jpg")) + list(src_img.glob("*.png")) random.seed(42) # 固定随机种子,保证每次拆分结果一致 random.shuffle(imgs) split = int(len(imgs) * 0.85) for idx, img in enumerate(imgs): dst = train_img if idx < split else val_img shutil.copy(img, dst / img.name)

这段脚本的逻辑很简单:先固定随机种子,再把图片列表打乱,前85%进train,后15%进val。复制图片之后,还要把同名txt标签同步复制到对应labels目录,这一步用文件操作就能完成,但要写个小校验,防止图片复制过去了标签漏掉。常见做法是遍历labels/train下的txt文件名,再回去检查images/train里有没有同名jpg。

data.yaml是连接数据集和训练脚本的桥梁,写法如下:

path: datasets/hw_garbage train: images/train val: images/val nc: 8 names: 0: plastic_bottle 1: aluminum_can 2: cardboard 3: glass_bottle 4: paper 5: organic 6: hazardous 7: other

这里最容易翻车的点是path字段。不同YOLOv5版本的相对路径解析方式有差异,如果训练时报找不到图片,直接把path改成完整绝对路径,问题通常立刻消失。names的索引顺序必须和标签txt里的类别ID严格对应,错一位整个模型就废了,这一点在第5章避坑部分会再敲一次。

3.3 从VOC标注转YOLO txt:坐标归一化与四个边界坑

公开数据集的标注格式五花八门,最常见的是VOC格式的XML,元素里存的是左上角和右下角坐标。YOLOv5训练需要的是归一化后的中心点坐标和宽高,格式是“class x_center y_center width height”,所有数值都在0到1之间。下面这个转换脚本可以直接复用:

import xml.etree.ElementTree as ET from pathlib import Path def voc2yolo(xml_path, out_txt, class_names): tree = ET.parse(xml_path) root = tree.getroot() size = root.find("size") width = int(size.find("width").text) height = int(size.find("height").text) lines = [] for obj in root.iter("object"): name = obj.find("name").text if name not in class_names: # 类别表外直接跳过,不要硬标 continue cls_id = class_names.index(name) box = obj.find("bndbox") xmin = int(box.find("xmin").text) ymin = int(box.find("ymin").text) xmax = int(box.find("xmax").text) ymax = int(box.find("ymax").text) # 坐标越界是常事,先截断再归一化 xmin = max(0, min(xmin, width - 1)) xmax = max(0, min(xmax, width - 1)) ymin = max(0, min(ymin, height - 1)) ymax = max(0, min(ymax, height - 1)) x_center = (xmin + xmax) / 2 / width y_center = (ymin + ymax) / 2 / height w = (xmax - xmin) / width h = (ymax - ymin) / height lines.append(f"{cls_id} {x_center:.6f} {y_center:.6f} {w:.6f} {h:.6f}") Path(out_txt).write_text("\n".join(lines), encoding="utf-8") if __name__ == "__main__": class_names = ["plastic_bottle", "aluminum_can", "cardboard", "glass_bottle", "paper", "organic", "hazardous", "other"] voc2yolo(Path("annotations/0001.xml"), Path("labels/0001.txt"), class_names)

这里有个我必须提醒的坐标归一化公式:x_center是xmin加xmax的一半再除以图片宽度,不是xmin加宽的一半。两种写法在矩形框完全相同时计算结果也一样,但一旦框有标注误差,结果就会差几个像素。训练初期这点误差不致命,到了小目标检测上就明显。

转换完别急着训练,还要跑一遍校验脚本,检查是否存在缺失标签、非法类别ID和中心点坐标越界。最简单的方法是用numpy把所有txt读出来扫一遍,把异常文件打印到屏幕上。这一步虽然枯燥,却是后面训练能正常收敛的前提。

4. 训练YOLOv5垃圾分类模型:命令、超参数与调参依据

数据准备好了,接下来就是“yolov5训练自己的数据集”的正题。很多新手一上来就对着超参数乱调,其实YOLOv5官方给的默认参数在大多数场景下已经能跑出不错的结果。你要做的不是“调参表演”,而是理解每个关键参数为什么被设置成这个值,以及当现象不对劲时该动哪一个。

4.1 用conda把环境一次装齐:最小训练命令和首次跑通

YOLOv5的依赖不算复杂,但Python版本和PyTorch版本要提前锁定。我一般用conda建独立环境,避免和系统Python冲突,也方便后面删掉重来。

conda create -n yolov5 python=3.9 -y conda activate yolov5 cd yolov5 pip install -r requirements.txt

PyTorch的安装这里单独说一句:最好按你自己机器的CUDA版本从对应渠道安装,使用conda默认源翻车的概率大,而且装了CUDA版本不匹配的PyTorch会出现“CUDA不可用”的隐性问题,训练时GPU占用率为0,白白浪费几个小时。

环境就绪后,启动训练的最小命令如下:

python train.py \ --data /绝对路径/hw_garbage.yaml \ --weights yolov5s.pt \ --img 640 \ --batch 16 \ --epochs 100 \ --workers 4 \ --name hw_garbage_s

说明一下几个参数:--weights yolov5s.pt表示加载在COCO上预训练好的权重,这属于迁移学习,比从零训练收敛快得多,也能用更少的数据拿到更高精度;--img 640表示训练时把输入图片统一缩放到640×640;--batch 16是显存允许情况下尽量大的值;--name是本次训练的输出目录名,后面结果都放在runs/train/hw_garbage_s里。

首次运行会自动下载预训练权重文件,这个步骤需要保持网络通畅。如果你的机器没有独立GPU,可以在命令最后加--device cpu,但100个epoch可能要跑五六个小时,建议先用小数据集验证流程没问题,再上全量数据。

4.2 五个必调超参数:epochs、img、batch、hyp、weights各自怎么动

第一个是epochs。不要机械地设成300,而是先设100个epoch跑一版,看val曲线是不是还在下降。如果最后10个epoch的mAP还在明显上升,就再加50到100个epoch;如果已经过拟合,再延长时间只会更糟。

第二个是img。640是精度和显存的平衡点。如果画面里垃圾目标普遍偏小,可以试960,但显存占用会增加到大约2.25倍,速度也明显下降。我建议第一版不要动img,用640把所有问题跑通后再试大尺寸。

第三个是batch。它直接受显存限制,6G显存用batc=8,12G显存可以到16或24。batch太小会导致batch normalization的统计量不稳定,loss曲线会像锯齿;batch太大对精度提升边际递减,还容易过拟合。

第四个是hyp,也就是超参数文件。YOLOv5自带了hyp.scratch-low.yaml、hyp.scratch-med.yaml和hyp.scratch-high.yaml。我的经验是,垃圾分类这种中等难度任务用low或med即可,重点看几个字段:

# hyp.scratch-low.yaml(节选) lr0: 0.01 # 初始学习率,模型发散时先降到0.005 lrf: 0.01 # 最终学习率 = lr0 * lrf,控制收尾震荡 momentum: 0.937 weight_decay: 0.0005 warmup_epochs: 3.0 # 前3个epoch用低学习率热身 mosaic: 1.0 # 数据增强强度,训练后期可降到0.5 fliplr: 0.5 # 水平翻转概率 hsv_h: 0.015 # 色调扰动范围

这里最值得先动的是lr0。如果训练一开始的loss就剧烈震荡,大概率是学习率偏大,把它降到0.005或0.003,前10个epoch会立刻平稳下来。warmup_epochs是预热机制,前3个epoch从很小的学习率逐步升到设定值,这是防止初始权重被大步长毁掉的关键。mosaic是拼接四张图增强,对小目标检测帮助很大,但训练后期可以改成0.5,让模型适应更接近真实分布的单图输入。

第五个是weights。迁移学习的价值在于复用底层特征,垃圾分类里的“瓶”“罐”“纸箱”特征和COCO数据集里的“瓶子”“罐子”高度重叠,所以用yolov5s.pt是正确选择。只有当你确定预训练模型来源不可靠或类别差异极大时,才该用--weights ''从零训练。

4.3 训练结果怎么看:results曲线、混淆矩阵和best权重选择

训练结束后,到runs/train/hw_garbage_s目录下看几个文件。results.png里画的是损失和mAP随epoch的变化曲线,重点关注val损失是否稳定下降、mAP50有没有在后半段大幅波动。confusion_matrix.png会直观展示每两个类别之间的混淆程度,如果plastic_bottle和glass_bottle之间出现明显深色块,说明这两类的视觉特征确实太像,要么补样本,要么考虑合并。

目录下会有best.pt和last.pt两个权重。best.pt是按验证集指标保存的最优模型,last.pt是最后一个epoch的产物。推理部署一律用best.pt,不要用last.pt。有些同学图省事用了last.pt,结果发现在测试集上mAP掉了好几个点,这就是典型的“省事翻车”。

训练过程中还会生成results.csv,里面记录了每个epoch的精确率、召回率和mAP。把这个文件导入Excel或表格工具,能更精确地对比两次训练的差异。每次改参数前,我给的建议是把当前命令、hyp改动点和结果指标完整记进笔记,这个习惯能让你调参时不会在几个变量之间反复横跳。yolov5超参数搜起来很容易,但真正有效的调参只能来自你自己的实验记录。

5. 部署与调试常见问题排查:四个最容易翻车的环节

训练完模型只是第一步,把模型接到摄像头或界面上跑起来,才算真正完成“智能生活垃圾分类系统”。这个阶段的问题往往和训练集无关,而是出在工程集成的细节上。下面四条是这套系统里最高发的故障,每一条我都按“现象、原因、解决”的顺序讲清楚。

5.1 现象:loss明明在降,mAP却卡在0.3——原因:标签类别ID映射错位

这种问题最折磨人:训练曲线正常下降,验证集mAP却始终上不去,预测结果出现了“瓶子识别成纸箱”这种离谱错乱。绝大多数情况是标签文件里的数字类别ID和你data.yaml里的names顺序不一致。比如转换脚本里class_names的索引是塑料瓶=0,但data.yaml里写着0是纸箱,模型学到的始终是错位的语义。

解决办法是写一个极简校验脚本,扫描文本标签里的ID是否都在合法范围内,并随机抽查几个框是否落在对应物体上:

from pathlib import Path import numpy as np label_dir = Path("datasets/hw_garbage/labels/train") num_classes = 8 for txt in list(label_dir.glob("*.txt"))[:20]: arr = np.loadtxt(txt, ndmin=2) cls_ids = arr[:, 0].astype(int) if set(cls_ids) - set(range(num_classes)): print(f"{txt.name} 含非法ID:{sorted(set(cls_ids))}") if arr.shape[1] != 5: print(f"{txt.name} 列数不正常:{arr.shape}")

这个脚本只做两件事:检查类别ID是否在0到7之间,检查每行是不是正好5个数值。跑完之后如果报异常文件,优先回到data.yaml和XML转换脚本里排查顺序。顺带提一句,YOLOv5的标签文件是纯文本,用记事本打开就能看,手动确认两条总比盲猜强。

5.2 现象:显存爆掉或一个epoch跑到天荒地老——原因:img/batch/workers组合不合理

训练刚启动几秒就报“CUDA out of memory”,或者CPU训练一个epoch要四十分钟,这通常不是代码问题,而是参数组合没对准机器配置。有一次我图省事把batch设成32、img设成960,结果6G显存的机器连第一个step都跑不完。后来改成batch=8、img=640,同样数据量稳稳跑完。

如果你只有普通笔记本,没有独立GPU,最稳妥的启动命令是:

python train.py \ --data hw_garbage.yaml \ --weights yolov5s.pt \ --img 640 \ --batch 8 \ --epochs 150 \ --workers 4 \ --device cpu

这里两个关键点:第一,batch从16降到8不会让结果差太多,但能救你一条命;第二,--workers不要默认拉满,物理内存8G的机器用workers=4,否则数据加载会和训练抢内存,表现为系统假死。还有一个常见坑是Windows环境下把workers设成大于0,datloader在每次epoch结束时可能报“BrokenPipeError”,这时候把workers改成0是最省事的解法。

5.3 现象:摄像头实测漏检、误检——原因:conf阈值太高和推理分辨率不匹配

测试图片上效果挺好,一接摄像头就漏检,这是部署阶段最打击人的事情。原因通常有两个:一是detect脚本里置信度阈值被调到了0.5甚至0.7,摄像头画面有运动模糊和光线变化,真实目标的置信度往往只有0.2到0.4;二是推理时把1920×1080的原始帧直接往下缩,没做letterbox,物体比例失真后检测框全歪。

建议的基础参数是conf=0.25、iou=0.45,并保持输入尺寸和训练尺寸一致,都为640。如果界面里还是抖得厉害,可以加一个简单的多帧投票策略:

from collections import Counter def vote_result(frame_results, history, max_keep=10): history.append(frame_results) if len(history) > max_keep: history.pop(0) # 统计最近10帧里出现次数最多的类别组合 cls_counter = Counter() for res in history: for cls_id in res: cls_counter[cls_id] += 1 top = cls_counter.most_common(2) return top[0][0] if top and top[0][1] >= 5 else None

这个投票逻辑不复杂,相当于把最近10帧的检测结果做一个频率统计,只有同一类别连续出现5次以上才采信。它的效果是真实稳定的:单一帧偶尔漏检不会导致界面提示乱跳,演示过程看起来就“聪明”得多。

5.4 现象:CPU推理只有2FPS——原因:整帧喂给模型,没有做缩放和跳帧

摄像头拍出来的原始帧是1080p,如果每帧都直接缩到640再推理,CPU机器上就是慢动作。优化思路有两个方向,一是降低推理输入尺寸,二是跳帧。检测不需要每帧都做,视觉上隔一帧检测一次,中间帧直接复用上一次的检测框,人眼基本感知不到延迟。

一个常见的优化片段是:

frame_idx = 0 DETECT_INTERVAL = 2 # 每2帧检测一次 while capture.isOpened(): success, frame = capture.read() if not success: break if frame_idx % DETECT_INTERVAL == 0: resized = letterbox(frame, (640, 640)) # 保持比例缩放 result = detector.predict(resized) last_result = result display_dataset(frame, last_result) # 中间帧直接复用 frame_idx += 1

这样改动之后,在CPU机器上通常能把FPS从2提升到5左右。如果再配合GPU上的half精度推理,也就是把模型切换为float16,速度还能再快一截。需要注意的是,跳帧检测在多目标快速移动场景下会丢框,但垃圾分类演示中垃圾基本是静止或缓慢移动的,影响很小。

6. 结项前最后一步:固定验证入口和权重命名,让源码在答辩现场不“翻车”

模型训练完成、检测逻辑跑通之后,最值钱的一件事是做一个永远能一键复现的固定入口。答辩现场最尴尬的情况不是模型精度低,而是评委让你再跑一次时,你临时敲命令却找不到权重文件,或者发现上次训练的结果根本不在这台机器上。我见过太多源码包本身挺好的,最后败在“演示流程不固定”上。

我的习惯是,在项目根目录保留一个极简demo脚本,只负责三件事:加载权重、读图或开摄像头、打印结果。它的价值不在于功能多,而在于路径写死、参数写死,任何一台按文档配置好的机器,双击运行就能复现。一个最小示例大概长这样:

from detector import GarbageDetector # 路径写绝对路径,避免相对路径在不同目录下失效 det = GarbageDetector( weights="weights/best_mAP50_0.902_0312.pt", conf=0.25, iou=0.45, ) results = det.predict("assets/test_demo.jpg") print(results.pandas().xyxy[0].to_string())

这里我刻意把权重文件名写成带mAP和日期的形式,比如best_mAP50_0.902_0312.pt,原因是训练过程中会反复产生best.pt,同名文件覆盖后很难追踪哪一版质量最好。与其靠记忆,不如把这个信息写进文件名。这个小小的命名习惯帮我躲过好几次“拿错旧模型”的尴尬。

如果还想再进一步,可以用YOLOv5自带的导出功能把模型转成ONNX格式,方便后面接网页服务或边缘设备。常见命令是:

python export.py --weights weights/best.pt --include onnx --img 640

转完之后最好先做一次load ONNX文件推理的测试,因为不同YOLOv5版本的导出结果有个别算子兼容问题,只要确认ONNX输出的框和pytorch输出的一致,就可以放心拿来部署。坦白说,答辩演示层面不一定非要走到ONNX这一步,但只要做到“固定入口、稳定复现、权重命名可追溯”这三件事,这套基于YOLOv5的垃圾分类源码就已经是一个合格的毕业设计交付物了。希望这篇笔记能帮你在训练和部署的路上少踩几个坑。

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

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

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

立即咨询