垃圾分类这件事,我在几个不同规模的场景里都折腾过一轮,从最早用传统图像处理做颜色阈值分割,到后来上深度学习模型,再到把识别能力塞进微信小程序里给普通用户用,中间踩的坑比想象中多得多。这个项目标题里堆了不少东西——微信小程序、YOLOv5、训练数据集,还有开题报告、中期检查、论文这一整套学术交付物,本质上它是一个典型的"算法+工程+文档"三位一体的毕业设计型项目。我打算把它拆开揉碎讲清楚:模型怎么选、数据怎么造、小程序怎么接、文档怎么写才不空洞,以及那些只有真正跑过一遍的人才会知道的细节。不管你是刚接触目标检测的新手,还是已经能训模型但卡在工程落地环节的老手,下面这些内容应该都能直接拿去用。
1. 为什么这个题目值得认真做,而不是随便套个模板
1.1 垃圾分类识别的真实难点在哪
很多人第一反应是"不就是个图像分类吗,ResNet 一把梭"。真上手就会发现没那么简单。生活垃圾的类别边界极其模糊:一个捏扁的塑料瓶和一段透明塑料管,在像素层面高度相似;湿垃圾里的果皮和可回收物里的某些包装纸,颜色纹理都接近。更麻烦的是同一类物体在不同状态下外观差异巨大——完整的纸箱、撕碎的纸板、被油浸过的纸片,模型要能统一归到"可回收物"。
这就决定了纯分类网络(把整张图缩成一个类别)不够用,因为用户拍一张照片里往往有好几件垃圾。你需要检测能力,也就是不仅要知道"有什么",还要知道"在哪、有几个"。YOLOv5 在这个场景里是个务实的选择:单阶段检测、推理速度快、对小目标有一定容忍度,而且社区生态成熟,改起来方便。相比之下,两阶段检测器精度可能略高,但部署到小程序后端时延和资源占用都不划算。
还有一个容易被忽略的点:类别体系本身要跟实际投放规则对齐。国内主流是四分类(可回收物、有害垃圾、厨余垃圾、其他垃圾),但每个城市细则不同。项目里如果直接硬编码四类,后期换城市就得重训。我的做法是把类别定义抽成配置文件,模型输出索引,映射表单独维护,这样换规则只改映射不改模型。
1.2 学术交付物和工程交付物的双重属性
这个标题里"开题报告+中期检查+论文"不是凑数的。它意味着你不仅要跑通代码,还要能讲清楚为什么这么做。我见过太多项目,模型训出来了、小程序也能跑,但论文里全是"本文采用了 YOLOv5 模型,取得了较好效果"这种空话,答辩时被问"为什么不用 YOLOv8""数据增强具体怎么做的""mAP 提升了几个点、为什么"就答不上来。
所以从第一天起就要有意识地记录实验:每次改超参、换增强策略、调 anchor,都留一份对比结果。这些记录最后直接变成论文里的实验章节和中期检查的支撑材料。开题阶段重点写清楚"问题定义"和"技术路线选型理由",中期检查重点展示"已完成模块+阶段性指标+遇到的问题及解决思路",论文则是完整闭环。三者是递进关系,不是三份独立文档。
2. 数据集这道坎:自己造数据的完整方法论
2.1 数据来源与采集策略
公开数据集能用的不少,但直接拿来训往往水土不服——很多是实验室摆拍,背景干净、光照均匀,跟用户随手拍的真实场景差距大。我的建议是公开数据打底 + 自采数据补真实分布。
自采这块,别指望一个人拍几千张。实际操作中可以这样分工:找几个同学在不同时间段(早晨、中午、傍晚)、不同光照(室内灯光、窗边自然光、阴天)、不同背景(桌面、地面、垃圾桶旁)各拍一批,每张图里刻意放 1 到 4 件垃圾,模拟真实拍摄。手机拍就行,但要注意保持和最终用户拍摄习惯一致——小程序里用户是举着手机俯拍或斜拍,那采集时也这么拍,别全用平视特写。
采集量上,四分类每类至少 500 张有效图起步,稀有类别(比如有害垃圾里的电池、灯管)可以少一些但要保证每类不低于 200 张,否则模型对这类基本没感觉。总量控制在 3000 到 5000 张是比较现实的区间,再多标注成本吃不消。
2.2 标注规范:比标注工具更重要的是规则
用 LabelImg 或 Labelme 都行,格式统一成 YOLO 的 txt(每行类别索引 中心x 中心y 宽 高,全部归一化到 0-1)。真正决定质量的是标注规则,必须在动手前写死:
- 遮挡处理:物体被遮挡超过 50% 不标;遮挡但主体可辨的,按可见部分框,框尽量贴合可见轮廓。
- 边界情况:一个物体被另一个完全挡住只露一角,不标;两个同类物体紧挨着,分别框,不合并。
- 模糊图:严重失焦、无法判断类别的直接剔除,不要硬标,否则等于给模型喂噪声。
- 类别歧义:制定一份"疑难清单",比如"沾油的纸餐盒"归其他垃圾还是厨余,提前定好,全组统一,避免同一物体不同人标成不同类。
我踩过的最大的坑是标注不一致:同一批数据两个人标,一个人把奶茶杯连盖子带吸管框成一个大框,另一个人分开标三个框,模型学出来框的大小飘忽不定,mAP 死活上不去。后来统一规则重标了一遍才解决。所以标注前开个短会、定规则、标 50 张做交叉校验,比事后返工省太多时间。
2.3 数据增强与划分的实操细节
YOLOv5 自带 Mosaic、随机缩放、色彩抖动等增强,默认配置对通用场景够用,但垃圾分类有几个特殊需求:
- 色彩抖动要克制。垃圾识别很大程度依赖颜色(比如绿色厨余、蓝色可回收的容器),HSV 增强幅度过大会让模型对颜色不敏感。我的经验是把
hsv_h调到 0.015 左右,hsv_s0.5,hsv_v0.3,比默认略保守。 - Mosaic 对小目标友好但要防过拟合。Mosaic 把四张图拼一张,能增加小目标和背景多样性,但如果你的数据本身背景单一,过度 Mosaic 会让模型学到拼接伪影。训练后期可以关掉 Mosaic(YOLOv5 有
close_mosaic参数),让模型在真实分布上收尾。 - 划分比例:训练/验证/测试按 8:1:1。注意按场景划分而不是随机划分——如果同一场景的图既在训练集又在测试集,测试指标会虚高。正确做法是把"某次采集的一批图"整体分到同一侧,保证测试集是模型没见过的场景。
3. YOLOv5 训练:从环境到收敛的完整链路
3.1 环境搭建与版本选择
YOLOv5 对 PyTorch 版本比较敏感,我一般锁一套稳定组合:Python 3.8 到 3.9、PyTorch 1.10 到 1.13、CUDA 11.x。装的时候先按官方 requirements 走,但不要无脑pip install -r,因为里面有些包版本会互相打架。我的习惯是手动装核心三件套(torch、torchvision、opencv-python),再补 numpy、pyyaml、tqdm 这些,最后跑一遍python detect.py --source data/images验证推理链路通不通。
模型规模上,yolov5s是性价比首选——参数量小、推理快,适合部署到后端服务。如果精度不够再考虑yolov5m,但别一上来就上 l/x,训练慢且容易过拟合小数据集。实测在 3000 到 5000 张的数据量上,s 和 m 的 mAP 差距往往在 1 到 2 个点,但推理速度差一倍,工程上不划算。
3.2 配置文件与超参调整
数据配置文件data/garbage.yaml长这样:
path: ../datasets/garbage train: images/train val: images/val test: images/test nc: 4 names: ['recyclable', 'hazardous', 'kitchen', 'other']训练命令我常用这套:
python train.py --img 640 --batch 16 --epochs 100 \ --data data/garbage.yaml --weights yolov5s.pt \ --hyp data/hyps/hyp.scratch-low.yaml --cache几个关键点解释一下。--img 640是输入分辨率,垃圾目标通常占画面比例不小,640 够用,再大显存吃不消。--batch 16看显存,8G 显存跑 640 大概能到 16,不够就降到 8。--cache把图片缓存到内存,加速数据加载,但数据集大(超过 1 万张)时慎用,容易爆内存。--hyp选 low 增强配置,配合前面说的克制色彩抖动。
学习率方面,默认lr0=0.01对从头训一般合适,但如果你用预训练权重微调,可以降到 0.001 到 0.005,避免把预训练学到的通用特征冲掉。我一般先跑 20 个 epoch 看 loss 曲线,如果 val loss 早早开始震荡上升,就是学习率偏大或过拟合,及时调。
3.3 训练过程监控与收敛判断
训练时盯着三个东西:box_loss、obj_loss、cls_loss和对应的 mAP。正常情况下 box 和 cls 应该稳步下降,mAP@0.5 稳步上升。如果出现下面几种情况要警惕:
| 现象 | 可能原因 | 处理方式 |
|---|---|---|
| train loss 降但 val loss 升 | 过拟合 | 加数据、加增强、减模型规模、加 dropout |
| 两个 loss 都不降 | 学习率太小或数据有问题 | 查标注、调大 lr、检查类别平衡 |
| mAP 卡在低位不动 | 类别严重不平衡或 anchor 不匹配 | 重算 anchor、对稀有类过采样 |
| loss 出现 NaN | 学习率过大或数据有脏样本 | 降 lr、清洗数据、开梯度裁剪 |
我遇到过最诡异的一次是 mAP 一直上不去,查了半天发现是验证集里混进了几张标注错误的图(框标到了背景上),模型在验证时被这些脏样本拖累。所以训之前一定要抽查验证集标注,别只查训练集。
4. 微信小程序端:把检测能力真正送到用户手里
4.1 整体架构:为什么不在小程序里直接跑模型
小程序运行环境对本地推理支持有限,直接塞 YOLOv5 模型进去不现实(体积、算力、兼容性都是问题)。标准做法是前后端分离:小程序负责拍照/选图、上传、展示结果;后端服务加载模型做推理,返回 JSON。这样模型更新不用重新发版小程序,也方便做多端复用。
后端我用 Flask 或 FastAPI 起一个轻量服务,加载训练好的best.pt,暴露一个/predict接口,接收图片、返回检测框和类别。FastAPI 更推荐,异步处理并发请求更稳,而且自带接口文档,调试方便。
4.2 小程序端的关键实现
小程序这边核心是三个动作:选图、上传、渲染结果。选图用wx.chooseMedia,上传用wx.uploadFile,拿到后端返回的坐标后,用 canvas 在原图上画框。
这里有个坐标系换算的坑:后端返回的框是基于原图尺寸的归一化坐标,而小程序展示时图片被缩放适配了屏幕,必须按展示尺寸重新换算,否则框会画偏。我的做法是拿到图片的原始宽高和展示宽高,算一个缩放比,再乘到框坐标上。
// 假设后端返回 boxes: [{x, y, w, h, cls, conf}],均为归一化值 const scaleX = displayWidth / originalWidth; const scaleY = displayHeight / originalHeight; boxes.forEach(b => { const left = b.x * originalWidth * scaleX; const top = b.y * originalHeight * scaleY; // 用 canvas 绘制矩形和类别文字 });还有一个体验细节:上传前压缩图片。手机原图动辄几 MB,直接传慢且费流量。用wx.compressImage压到 80% 质量、长边 1280 以内,既保证检测精度又提速。实测压缩后单张上传时间从两三秒降到一秒内,用户体验差别很大。
4.3 结果展示与交互设计
检测结果别只画个框就完事。用户真正关心的是"这垃圾该扔哪个桶"。所以框旁边要标类别和置信度,下方再给一段投放提示文字(比如"可回收物:请清空瓶内液体后投入蓝色桶")。置信度低于阈值(比如 0.4)的框可以不显示或标灰,避免误导。
另外要考虑多目标场景:一张图里检测出多个物体时,按置信度排序展示,或者用不同颜色区分类别。我做过一个版本是点击某个框高亮对应的投放提示,用户反馈比一次性列一堆文字清楚得多。
5. 文档三件套:开题、中期、论文怎么写才不空
5.1 开题报告的核心是"讲清楚为什么"
开题报告最忌讳写成"技术堆砌"。评审想看到的是:你为什么选这个题、为什么用这套技术、预期解决什么问题。结构上我建议按"背景与意义—国内外现状—研究内容—技术路线—进度安排"来,但每一块都要有具体内容支撑。
技术路线那块,别只写"采用 YOLOv5",要写清楚:为什么检测而非分类(多目标场景)、为什么选 YOLOv5 而非其他(速度精度平衡、部署友好)、数据从哪来(公开+自采)、怎么评估(mAP、推理时延、小程序端到端体验)。这些理由在论文里还会再用一次,开题时想清楚,后面省事。
5.2 中期检查:用数据说话
中期检查的重点是"做到哪了、效果如何、遇到什么问题"。这时候模型应该已经能跑出初步结果,把阶段性指标摆出来:当前 mAP@0.5 多少、各类别召回率如何、小程序 demo 能不能跑通。遇到问题不可怕,写清楚"问题—分析—解决思路"反而加分。比如"初期 mAP 偏低,排查发现标注不一致,统一规则重标后提升 X 个点",这种叙述比"进展顺利"有说服力得多。
5.3 论文:实验章节是拉开差距的地方
论文的骨架一般是绪论、相关技术、系统设计、实验与结果分析、总结。真正体现水平的是实验章节。这里要有:数据集统计(各类别数量、场景分布)、训练配置(超参表)、对比实验(不同模型规模、不同增强策略的 mAP 对比)、消融实验(去掉某个模块指标掉多少)、端到端性能(小程序上传到返回结果的时延)。
对比实验的表格一定要有,比如:
| 模型 | 输入尺寸 | mAP@0.5 | 单张推理时延(ms) | 模型体积(MB) |
|---|---|---|---|---|
| yolov5s | 640 | 0.82 | 25 | 14 |
| yolov5m | 640 | 0.85 | 48 | 40 |
| yolov5s(无Mosaic) | 640 | 0.79 | 25 | 14 |
这种表格一摆,选型理由不言自明。注意数据要真实,别编,答辩时被追问细节露馅就麻烦了。
6. 那些只有跑过一遍才知道的坑
6.1 类别不平衡的隐蔽影响
四分类里"有害垃圾"样本天然少,模型很容易对它"视而不见"——预测时几乎不输出这个类。表面看整体 mAP 还行,但拆开看有害垃圾的召回率可能只有 0.3。解决办法:训练时给稀有类更高的损失权重,或者对稀有类做针对性过采样(复制+不同增强)。我一般先看各类别召回率,低于 0.5 的类重点补数据。
6.2 小程序真机与模拟器的差异
开发者工具里跑得好好的,真机上可能出问题。最常见的是图片方向:手机拍的照片带 EXIF 旋转信息,小程序某些 API 读出来是横的,导致检测框全错位。处理办法是上传前用 canvas 重绘一遍图片,强制摆正方向。还有网络问题,真机弱网下上传超时要做好重试和 loading 提示,别让用户干等。
6.3 模型更新与后端兼容
模型迭代后,输出格式如果变了(比如类别顺序调整),后端和小程序都要同步改。我的做法是接口返回里带上类别名称而非索引,小程序只负责展示,不关心索引映射,这样换模型只要后端改映射表,小程序不用动。这个设计在后期迭代时省了大量联调时间。
6.4 推理服务的资源管理
后端加载模型常驻内存,如果服务长时间不用会被系统回收,下次请求冷启动很慢。可以加个定时保活,或者用 gunicorn 多 worker 时注意每个 worker 都会加载一份模型,显存/内存要算够。小规模场景单 worker 足够,别盲目开多进程。
7. 从 demo 到可用:还能往哪些方向打磨
如果这个项目只是交作业,跑通上面这些就够了。但如果想做得更扎实,有几个方向值得投入。一是引入分割能力,检测框只能告诉你"大概在这",实例分割能给出精确轮廓,对堆叠垃圾的区分更准,不过标注成本会翻倍。二是做投放引导的闭环,检测出类别后结合本地垃圾分类规则库给出具体投放建议,甚至做成语音播报,对老人更友好。三是模型轻量化,用剪枝或量化把模型压到能在端侧跑的规模,彻底摆脱对后端服务的依赖,当然这需要额外的工程投入。
我自己在实际操作中的体会是,这类项目真正的价值不在于模型多先进,而在于整条链路是否顺畅——数据标注规范、训练可复现、接口稳定、前端体验过得去、文档能自圆其说。把这几件事做扎实,比盲目追新模型有用得多。最后分享一个小技巧:每次训练完把results.csv、confusion_matrix.png和几个典型预测样例图存到一个带日期的文件夹里,几个月后写论文翻出来,实验章节的素材基本就齐了,不用再回头重跑。