ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

垃圾分类系统源码解析:基于PyTorch和迁移学习的图像分类实战

垃圾分类系统源码解析:基于PyTorch和迁移学习的图像分类实战 简介一套基于 Python 的垃圾分类系统完整源码包面向计算机、数学、电子信息等专业学生的课程设计、期末大作业与毕业设计场景适合有一定 Python 基础、希望参考完整项目来理解分类算法与系统搭建的读者。源码可直接导入运行覆盖数据预处理、分类识别、结果展示与前端交互等环节配套项目说明文档有助于快速理清模块结构与关键流程。资源共 2000 个文件打包体积约 16.29MB以 1457 个 Python 脚本为核心辅以 139 个 HTML 页面、96 个 JavaScript 脚本和 20 个 CSS 样式文件构成可视化界面另有 234 个 pyc 缓存、少量 exe 可执行文件及 Markdown 说明文档便于直接部署与对照学习。目前已有 431 人浏览学习适合作为毕设或课程设计的参考资料。下载后可直接运行使用既能查看完整目录结构与关键注释也能借助项目说明理解算法选择与参数配置若想扩展功能在读懂代码的基础上可自行修改调试节省从零搭建的时间成本。1. 一套能直接跑的垃圾分类系统源码毕设流程里最容易被拖垮的一环已经铺平做毕设的人常以为模型是最难的部分实际上多数人先死在数据集不均衡、中文路径和类别顺序这些工程细节上。这套基于 Python 的垃圾分类系统源码项目说明把“图片进来—模型推理—中文类别出去”的完整闭环已经搭好解压后按说明跑通再往里面换自己的数据集即可。它不是帮你代写论文的捷径而是一个能看懂的工程底座源码注释和目录划分都比较清楚适合拿来学习再改造。适合谁课程设计、期末大作业、毕业设计三种场景都覆盖也适合刚接触图像分类、想把 torchvision 的 ImageFolder 到 Web 展示整条链路走一遍的从业者。对新手跟着第 3 章的步骤操作能落地对熟手重点看第 2 章的选型理由和第 4 章的坑避免重复造轮子。下面的内容按“先看懂设计再动手复现最后避坑和验证”展开。2. 系统设计与模型选型迁移学习凭什么比从零训练省一半时间先给一个判断这份源码解决的是图像分类任务不是目标检测任务。很多同学拿到“垃圾分类”四个字一上来就认为要做 YOLO 框出垃圾位置。实际上课程设计和毕业设计里最常见的验收材料是能选一张图程序告诉你是哪类垃圾附上训练曲线和混淆矩阵。图像分类已经覆盖这个需求。目标检测需要标注框、类别、置信度三份标签数据准备成本翻几倍训练也慢没有特别要求“识别画面里多个垃圾目标”时不值得碰。所以这份资源的核心是一条分类链路数据集按类别目录组织模型输出每个类别的概率取最大概率对应的中文标签最后在 Web 页面上展示。理解这一点后面所有参数调整都不会跑偏。2.1 功能边界训练端、推理端与 Web 展示端的职责划分训练端负责三件事读图、更新权重、保存 checkpoint。常见实现里 data 目录下每个类一个子文件夹torchvision.datasets.ImageFolder会按文件夹名字排序后自动生成class_to_idx映射这个映射就是后面所有环节的顺序基准。你不需要手写 label encoder但要非常清楚它是按文件夹名排序的不是按你期望的顺序。推理端负责加载训练好的权重用和训练完全相同的预处理把图片变成张量前向一次得到 logits再做 softmax。这里最容易翻车的地方有两个一是忘了model.eval()导致 BatchNorm 和 Dropout 行为异常预测结果漂移二是用了一套和训练不同的图片尺寸或归一化参数输入分布不一致准确率直接下滑。展示端是一个薄薄的 Flask 层接收上传图片存到临时目录调用推理函数返回结果。这个分层最大的价值不是“看起来高级”而是换数据集时训练脚本不用动只需要把数据目录换掉、改类别数如果你要改识别逻辑也不必在 Flask 视图函数里改模型结构。拿到源码后先确认这三层是否解耦如果发现app.py里混着训练代码那就是个坏味道尽早拆开。2.2 模型选型ResNet 与 MobileNet 之间怎么选迁移学习改哪里垃圾分类数据集通常是几千张到几万张的规模和 ImageNet 这种百万级数据集差几个数量级。从零训练一个 CNN前几十轮 loss 常常降不下去即使收敛了验证集泛化也不行。迁移学习的做法是加载 ImageNet 预训练权重把最后一层全连接换成本项目的类别数低层特征保留只让高层针对垃圾图像微调。实践里第一个 epoch 就可能跑到 60% 以上的准确率这是从零训练很难做到的。常见基座是 ResNet50如果你的机器只有 CPU没有独立显卡我一般建议换成 MobileNetV2。ResNet50 在 CPU 上前向加反向一轮可能要几十分钟MobileNetV2 会明显更快精度损失在垃圾分类这类颜色纹理相对明显的任务上并不大。改造点只有一处import torch.nn as nn from torchvision import models model models.resnet50(pretrainedTrue) num_classes len(class_names) # 垃圾类别数 model.fc nn.Linear(model.fc.in_features, num_classes)逻辑说明resnet50(pretrainedTrue)会先尝试从 torchvision 的权重缓存里加载预训练参数第一次运行需要联网下载通常会花几分钟model.fc原本输出 1000 类这里替换成输出num_classes的全连接层。只要类别数改了这一行必须跟着变否则加载 checkpoint 会报size mismatch。如果你换用 MobileNetV2对应改model.classifier[1]而不是fc这是新手最容易照着网上的 ResNet 教程抄错的地方。微调策略上有人把整个主干冻结只训练最后的全连接训练很快但如果发现验证集精度上不去再解冻最后两层也不迟。我一般上来就让全部参数参与训练但把学习率压到 1e-4 这个量级防止大步长破坏预训练特征。这里没有绝对正确答案看验证集表现再调。2.3 关键参数图像尺寸、batch size 和训练轮数的取值逻辑拿到了源码第一步不是直接python train.py而是先把参数表过一遍。多数项目会把参数放在train.py的 argparse 里或者config.py里参数背后有明确的取舍。参数常见取值调参方向与原因图像尺寸224×224ResNet 和 MobileNet 的标准输入兼容性最好。改成 256 不会等比提升精度计算量却涨了不少batch sizeGPU 16/32CPU 8显存不够先降到 8数据量少时 batch 太大容易让梯度方向过于确定反而难泛化epochs30~50 微调10~15 演示不要只看训练 loss看验证集脚本里应该保存验证集最优权重而不是最后一轮学习率1e-3 新头部1e-4 预训练部分Adam 下这个区间比较稳微调阶段学习率过大会把预训练权重冲坏优化器Adam默认 beta 参数即可不需要额外调参归一化ImageNet mean/std预训练模型依赖这套标准化参数自己随意改会破坏输入分布数据处理上训练集和验证集按 8:2 或 8:1:1 划分验证集只在每个 epoch 结束后评估不能参与训练。源码里的ImageFolder会按文件夹名自动生成类别索引所以目录层级必须是data/train/类别名/图片.jpg这种结构如果套了一层data/train/images/...分类数会变成 1。这些细节后面第 4 章还会反复提到。3. 跑通源码的完整动作环境、目录、训练与单图预测接下来是可抄作业的部分。无论你是课程设计还是毕设先保证能复现出一次完整训练和预测再谈改模型。3.1 环境准备虚拟环境、依赖与 PyTorch 硬件识别先创建虚拟环境避免 pip 包污染系统 Pythonpython -m venv venv source venv/bin/activate # Windows 下用 venv\Scripts\activate pip install -r requirements.txt逻辑说明-m venv创建独立解释器环境source是激活 Linux/macOS 环境Windows 下激活脚本路径不同。requirements.txt里一般包含 torch、torchvision、flask、pillow、numpy、scikit-learn。装完后先确认 PyTorch 能否识别显卡python -c import torch; print(torch.__version__, torch.cuda.is_available())逻辑说明这行命令打印 PyTorch 版本和 CUDA 是否可用。输出True说明后续训练走 GPU输出False也没关系代码会落到 CPU但训练会慢很多这时建议参考 3.3 节把 batch size 调小或者换成 MobileNetV2。如果你是在 PyCharm 里配置 python 环境记得把项目解释器也指向这个 venv否则 pip 装到系统 PythonIDE 却用另一个解释器跑代码会报 ModuleNotFoundError。3.2 目录结构每个目录在流程里负责什么下载解压后先读一遍项目说明再看目录。这类工程最常见的组织方式如下文件/目录在流程里的作用改动时注意data/train训练图片每个类别一个子文件夹文件夹名排序会决定类别索引别随意改data/val验证集用于选择最优 epoch不要参与训练否则选出来的权重是虚高的models/训练产生的权重文件预测和 Web 端都要指向同一条路径utils/数据加载、预处理、通用函数改动模型后这里要同步train.py训练入口参数优先级高于 config 文件predict.py单张图片预测入口类别映射必须来自训练输出app.pyFlask 展示端端口被占用时改端口即可requirements.txt依赖清单不建议手动逐个升级版本拿到源码后我一般按这个顺序检查先看config.py里的路径是否写死再看data/train下是不是每个类别一个文件夹最后用 3.4 节的预测脚本跑一张图片验证权重能加载。这个流程走通之前不要急着训练。3.3 训练入口ImageFolder 与参数传递训练脚本核心逻辑简化下来是这个样子# train.py 核心流程完整逻辑以源码为准 import argparse import torch import torch.nn as nn from torch.utils.data import DataLoader from torchvision import datasets, transforms, models parser argparse.ArgumentParser() parser.add_argument(--data_dir, typestr, defaultdata/train) parser.add_argument(--epochs, typeint, default30) parser.add_argument(--batch_size, typeint, default16) parser.add_argument(--img_size, typeint, default224) parser.add_argument(--lr, typefloat, default1e-3) args parser.parse_args() transform transforms.Compose([ transforms.Resize((args.img_size, args.img_size)), transforms.RandomHorizontalFlip(p0.5), transforms.ToTensor(), transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225]) ]) dataset datasets.ImageFolder(args.data_dir, transformtransform) loader DataLoader(dataset, batch_sizeargs.batch_size, shuffleTrue, num_workers4, drop_lastTrue) num_classes len(dataset.classes) model models.resnet50(pretrainedTrue) model.fc nn.Linear(model.fc.in_features, num_classes)逻辑说明ImageFolder通过子文件夹自动生成类别标签dataset.classes保存类别名列表class_to_idx保存名称到索引的映射。Resize((224, 224))是直接拉伸比保持长宽比裁剪更简单但会改变物体形状所以在第 5 章验证阶段要特别留意那些非正方形图片。RandomHorizontalFlip是数据增强对左右翻转不变类有效但它解决不了类别不均衡。drop_lastTrue表示最后不足一个 batch 的数据被丢弃为了避免 BatchNorm 在小批量上统计不稳定但如果数据集本身很小这会白白丢样本。启动训练python train.py --data_dir data/train --epochs 30 --batch_size 16 --img_size 224 --lr 1e-3参数说明第一次跑建议把--epochs降到 10 验证流程能走通再正式跑满。Windows 下num_workers4有时会报RuntimeError: An attempt has been made to start a new process before the current process has finished its bootstrapping这个坑我踩过不止一次解决方式是把它设成 0或者把整个训练逻辑放进if __name__ __main__:里。3.4 单张图片预测类别映射与模型状态的坑预测脚本是验收时最常被现场执行的代码要足够稳# predict.py 核心函数 import torch from PIL import Image from torchvision import transforms def predict(img_path, model, class_names, devicecpu, img_size224): tf transforms.Compose([ transforms.Resize((img_size, img_size)), transforms.ToTensor(), transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225]) ]) img Image.open(img_path).convert(RGB) x tf(img).unsqueeze(0).to(device) model.eval() with torch.no_grad(): out model(x) probs torch.softmax(out, dim1) top1 int(probs.argmax(dim1)) return class_names[top1], float(probs[0][top1])逻辑说明convert(RGB)是为了去掉可能存在的透明通道统一成三通道输入model.eval()必须放在预测函数里否则模型里的 BatchNorm 会继续计算统计量torch.no_grad()关闭梯度计算省显存、更快。class_names应该从训练时保存的 JSON 文件加载不要在代码里手写类别中文名列表这是第 4 章要重点讲的坑。命令行调用方式通常长这样python predict.py --image test_images/glass.jpg --weights models/best_model.pth参数说明--image是待测图片路径--weights指向训练保存的权重。如果脚本里要求传入--data_dir才能构建类别映射说明这个工程把训练和预测耦合得比较紧建议改成读取 JSON 映射的方式预测就不需要依赖训练数据目录了。3.5 Web 展示Flask 上传接口训练和预测跑通后再把 Web 展示补上python app.py --port 8080 # 浏览器访问 http://127.0.0.1:8080/逻辑说明Flask 启动后监听127.0.0.1浏览器通过上传页提交图片后端保存到临时目录调用上一步的predict()函数把中文类别名和置信度渲染到页面。这里最常见的坑是上传接口没有限制文件类型和大小毕设演示现场有人传一张几 MB 的大图预处理直接把内存吃满。我一般会在上传代码里加一个MAX_CONTENT_LENGTH限制图片超过 5MB 直接返回提示。另外要注意手机拍的照片带有 EXIF 旋转信息PIL.Image.open读进来后方向可能不对推荐用ImageOps.exif_transpose(img)处理一下再进模型否则有些类别会稳定地识别错。4. 避坑笔记数据集、编码、路径和显存的五个翻车现场我在复现这类项目时踩过最多的坑不在模型而在数据。下面五条是初跑时最容易碰到的按现象、原因、解决列出顺序基本就是我的排查顺序。4.1 类别不均衡准确率 0.9 是假象现象训练 loss 降得很快验证集准确率到 0.9 以上但你随手拍一张“有害垃圾”的图模型却输出“其他垃圾”反复测都一样。原因垃圾图片天然不均衡某个大类样本量可能是小类的几倍。模型学到的是“全猜大类”也能得到高准确率整体 accuracy 被大头类别拉高了。解决训练前先统计data/train下每类图片数量如果差距超过 3 倍用torch.utils.data.WeightedRandomSampler做加权采样或者给大类限流。同时不要只看整体准确率要看每个类别的 Recall用一个分类报告把类别列出来。注意删减大类样本前先备份原始数据避免后悔药都没得吃。4.2 中文标签在 Windows 下编码报错现象Windows 控制台跑predict.py打印中文类别名时报UnicodeEncodeError: gbk codec cant encode character或者浏览器页面上中文全是乱码。原因源码里用中文作为文件夹名或者显示名训练脚本写文件时按 UTF-8 保存控制台默认按 GBK 输出两边对不上。Python 入门阶段在这块浪费半天很正常。解决内部目录名统一用英文或数字 ID中文显示名单独放到一个 JSON 映射表文件保存时指定encodingutf-8。临时救急可以在运行前执行chcp 65001或者在代码里加sys.stdout.reconfigure(encodingutf-8)但这不是长久之计换一台机器还会翻车。4.3 绝对路径写死换机器第一件事就崩现象解压后不修改任何代码直接跑训练报FileNotFoundError错误信息里的路径带着上一个作者的桌面用户名比如C:/Users/admin/Desktop/...。原因源码作者在本地开发时把数据集路径写死了train.py、predict.py、app.py里各写了一份绝对路径换机器后当然找不到。解决在config.py开头用base_dir os.path.dirname(os.path.abspath(__file__))拿到项目根目录所有数据、权重、临时目录都用os.path.join(base_dir, ...)拼接。下载后先在项目范围内搜索一下常见的盘符路径把所有写死的绝对路径全部替换成相对路径。这一步不做后面改什么都白搭。4.4 显存不足或 CPU 训练慢到怀疑人生现象8G 显存的显卡跑 ResNet50前几个 epoch 正常某一步突然报CUDA out of memory没有显卡机器上跑一个 epoch 要一个多小时。原因默认batch_size32、img_size224、ResNet50 三件套对显存是压力组合CPU 上跑预训练 ResNet50 的前向加反向本身就很吃力。解决先把batch_size降到 8如果还爆再把img_size降到 160但必须同步修改预测脚本里的尺寸否则输入不一致。CPU-only 环境下把特征提取网络换成 MobileNetV2num_workers设为 0通常能从一小时降到十分钟左右。训练结束后执行torch.cuda.empty_cache()释放缓存。4.5 训练和推理的类别顺序不一致结果整体错位现象训练时准确率正常但用predict.py测一张“塑料瓶”图片输出“玻璃瓶”而且不是个别现象是某一类整体被识别成另一类。原因训练时ImageFolder按文件夹名排序生成索引比如按 ASCII 排序得到[glass, metal, paper, plastic]索引 0、1、2、3而predict.py里手写了classes [可回收物, 厨余垃圾, 有害垃圾, 其他垃圾]默认顺序和训练索引对不上。解决训练完把dataset.class_to_idx保存成 JSON预测时从 JSON 加载类别名绝不手写import json with open(class_names.json, w, encodingutf-8) as f: json.dump(dataset.class_to_idx, f, ensure_asciiFalse, indent2)逻辑说明ensure_asciiFalse保证中文名不被转成\uXXXX转义查看时更直观。class_to_idx记录的是文件夹名到索引的映射这个顺序就是模型输出的顺序预测脚本必须完全复用。注意如果展示端显示的是中文名而训练文件夹是英文名需要再做一层“英文内部名 → 中文显示名”的映射中间任何一环断了前端都会显示乱码。5. 进阶验证混淆矩阵和回归清单给模型做体检训练完成、能跑通预测只能说明程序没崩不能说明模型合格。我会给这份源码补两道检查混淆矩阵和单张图回归清单。第一道用测试集跑一遍所有图片输出混淆矩阵。重点不是看整体准确率而是看对角线之外哪些类别互相混。垃圾分类里“玻璃瓶”和“陶瓷”互混是合理的因为纹理颜色接近“塑料瓶”和“纸张”互混就不太正常可能是数据增强太弱或者训练不充分。代码上借用 sklearn 就能出结果import torch from sklearn.metrics import confusion_matrix, classification_report for img_path, label in test_samples: pred predict(img_path, model, class_names) y_true.append(label) y_pred.append(pred) print(classification_report(y_true, y_pred, target_namesclass_names)) cm confusion_matrix(y_true, y_pred)逻辑说明classification_report会输出每个类别的精确率、召回率和 F1比单个 accuracy 更能暴露不均衡问题混淆矩阵则是给答辩评委看的最佳可视化素材配合热力图就是“数据分析与可视化”这一环的加分项。第二道回归清单是我的保留动作每个类别单独挑 5 张以上图片故意选训练集里没出现过的拍摄角度、光线和背景用上面predict()一张张过。只要某张图的 top1 置信度低于 0.6或者输出类别和实际不符就放进错题集重点分析是数据没覆盖还是模型漏了。这个清单以后改数据集、调参数时反复使用能避免“这次改完到底有没有变好”的玄学判断。从那以后我每次拿到下载来的模型工程都会先跑一遍混淆矩阵和回归清单再动训练参数改完任何东西也强制把清单重新过一遍。这个习惯帮我挡掉了至少三次答辩现场的翻车。希望帮到你。本文还有配套的精品资源点击获取
返回列表