简介这份资源是面向高校Python课程大作业场景的完整项目包主题为基于深度学习的垃圾分类系统适合正在准备课程设计、需要可运行参考项目的本科生或自学者。压缩包共134个文件约75.59MB包含20个py源码、13个ipynb实验笔记、12个vue前端页面、14个js脚本、19张png效果图以及pptx汇报演示、docx参考报告、pdf文档、onnx模型、sqlite3数据库和Dockerfile部署配置等覆盖从模型训练、图像预处理到前端展示与部署的完整链路。资源中源码均经本地编译调试可直接运行并附有部署指南与全部文档方便对照理解数据采集、特征提取、分类输出等模块的实现思路。目前已有89人学习下载评审分达到95分以上难度适中适合作为课程实践与深度学习入门的参考方案。1. 从一份课程大作业说起垃圾分类系统到底要交付什么每年到了期末问得最多的一类问题就是「基于深度学习的垃圾分类系统」这个 Python 课程大作业到底该怎么做、做成什么样才算过关。我见过太多同学卡在同一个地方模型训练脚本跑通了准确率也刷到了 90% 以上但一到验收环节就翻车——老师问「你怎么部署的」「换个摄像头还能不能识别」「报告里的数据是怎么来的」答不上来。这个标题背后其实是一套完整的工程交付物源码、部署指南、报告 PPT、全部文档四样东西缺一不可而真正拉开差距的不是模型本身是你能不能把「训练好的权重」变成一个别人能跑起来、能看懂、能复现的系统。这篇文章面向两类人一类是正在做这个课程大作业、需要一份能照着落地的完整路径的同学另一类是想拿垃圾分类当深度学习入门实战项目、但不想只停留在跑通 demo 的从业者。我会按「数据怎么准备 → 模型怎么选和训 → 服务怎么部署 → 文档和 PPT 怎么写 → 坑在哪」的顺序讲中间给到能直接抄的命令和代码参数也会说清楚为什么这么设。垃圾分类这个场景看着简单实际上类别不均衡、背景干扰、部署环境差异这几个问题一个都不少把它做扎实比刷十个 MNIST 变体有用得多。2. 数据集准备与增强从原始图片到能喂给模型的数据2.1 垃圾分类的数据集从哪来、怎么划分常见做法有两种一是用公开数据集比如 TrashNet 这类按纸板、玻璃、金属、纸张、塑料、其他分成 6 类的数据集图片量在几千张级别二是自己用手机拍按可回收物、厨余垃圾、有害垃圾、其他垃圾这四分类去采集。课程大作业我更推荐第二种因为四分类和国内实际垃圾桶对应答辩时好讲而且自己拍的数据能体现工作量。采集时注意每类至少 300 张拍摄角度、光照、背景尽量多样否则模型学到的只是「白色桌面」这种无关特征。划分比例用 7:1.5:1.5 比较稳也就是训练集 70%、验证集 15%、测试集 15%。这里有个血泪经验不要用随机划分就完事如果同一张图的不同角度被分到了训练和测试两边测试准确率会虚高。正确做法是按「拍摄批次」或「物体实例」划分同一个物体的所有照片只能出现在一个集合里。下面这段脚本按文件名前缀分组划分能避免这个问题。import os import random import shutil from collections import defaultdict # 原始数据目录结构: raw_data/类别名/xxx.jpg RAW_DIR raw_data OUT_DIR dataset SPLIT {train: 0.7, val: 0.15, test: 0.15} random.seed(42) # 按文件名前缀(视为同一物体)分组, 保证同组不跨集合 def group_by_prefix(files): groups defaultdict(list) for f in files: prefix f.split(_)[0] # 约定命名: 物体ID_角度.jpg groups[prefix].append(f) return list(groups.values()) for cls in os.listdir(RAW_DIR): cls_dir os.path.join(RAW_DIR, cls) if not os.path.isdir(cls_dir): continue files [f for f in os.listdir(cls_dir) if f.lower().endswith((.jpg, .png))] groups group_by_prefix(files) random.shuffle(groups) n len(groups) n_train int(n * SPLIT[train]) n_val int(n * SPLIT[val]) split_map { train: groups[:n_train], val: groups[n_train:n_train n_val], test: groups[n_train n_val:], } for split, grps in split_map.items(): dst os.path.join(OUT_DIR, split, cls) os.makedirs(dst, exist_okTrue) for g in grps: for f in g: shutil.copy(os.path.join(cls_dir, f), os.path.join(dst, f)) print(f{cls}: train{n_train} val{n_val} test{n - n_train - n_val} 组)逻辑说明先按前缀把同一物体的多张照片聚成组再以「组」为单位随机打散后切分这样同一个物体的照片不会同时出现在训练集和测试集。参数上SPLIT可以按数据量调整数据少于 2000 张时验证集比例可以降到 0.1把更多数据留给训练。random.seed(42)固定随机种子保证每次划分结果一致方便复现。2.2 数据增强的度怎么把握垃圾分类的增强不能乱来。水平翻转、随机裁剪、颜色抖动这三样是安全且有效的但垂直翻转要慎用因为垃圾桶和垃圾的上下关系是有语义的倒过来的塑料瓶在现实中几乎不存在强行翻转会让模型学到错误特征。旋转角度控制在 ±15 度以内太大容易把物体转出画面。用 torchvision 的 transforms 组合起来大概是这样from torchvision import transforms train_tf transforms.Compose([ transforms.Resize((256, 256)), transforms.RandomResizedCrop(224, scale(0.7, 1.0)), # 随机裁剪, 保留70%-100%面积 transforms.RandomHorizontalFlip(p0.5), transforms.RandomRotation(15), # 小角度旋转 transforms.ColorJitter(brightness0.2, contrast0.2, saturation0.2), transforms.ToTensor(), transforms.Normalize(mean[0.485, 0.456, 0.406], # ImageNet 统计值 std[0.229, 0.224, 0.225]), ]) val_tf transforms.Compose([ transforms.Resize((224, 224)), transforms.ToTensor(), transforms.Normalize(mean[0.485, 0.456, 0.406], std[0.229, 0.224, 0.225]), ])参数说明RandomResizedCrop的scale(0.7, 1.0)表示裁剪面积占原图的 70% 到 100%这个范围对垃圾分类够用再小会把物体裁没。Normalize用的是 ImageNet 的均值和方差因为后面要用预训练权重输入分布必须对齐这一步漏了准确率会掉好几个点。验证集只做 Resize 和归一化不能加任何随机增强否则验证指标会抖动没法判断模型好坏。提示如果某一类样本特别少比如有害垃圾只有 100 张优先用「过采样 强增强」而不是直接复制图片复制会导致过拟合。也可以在损失函数里加类别权重这个后面训练部分会讲。3. 模型选型与训练迁移学习为什么是课程大作业的最优解3.1 从零训练还是迁移学习算一笔账课程大作业的数据量通常在一两千到一万张之间这个规模从零训练一个 CNN 基本等于自杀——收敛慢、准确率低、还容易过拟合。迁移学习是标准答案拿 ImageNet 上预训练好的骨干网络换掉最后的分类头用垃圾分类数据微调。骨干网络的选择上ResNet18 和 MobileNetV3 是两个最常被推荐的。ResNet18 参数量约 1100 万准确率稳适合追求指标的场合MobileNetV3-Small 参数量只有 250 万左右推理快适合后面要部署到边缘设备或者做成 Web 服务的场景。课程大作业我一般推荐 MobileNetV3因为部署环节会轻松很多答辩时「能在普通笔记本上实时识别」是个加分项。选型对比可以看这张表骨干网络参数量输入尺寸适合场景训练显存(bs32)ResNet18~11M224追求准确率、有 GPU~4GBMobileNetV3-Small~2.5M224要部署、要实时~2GBEfficientNet-B0~5.3M224折中方案~3GB3.2 训练脚本与关键参数下面是一个完整的训练脚本骨架用 PyTorch 写包含类别权重处理不均衡、学习率调度、验证和保存最优权重。import torch import torch.nn as nn from torch.utils.data import DataLoader from torchvision import datasets, models from torch.optim import Adam from torch.optim.lr_scheduler import CosineAnnealingLR DEVICE torch.device(cuda if torch.cuda.is_available() else cpu) BATCH_SIZE 32 EPOCHS 30 LR 1e-3 NUM_CLASSES 4 # 可回收、厨余、有害、其他 train_ds datasets.ImageFolder(dataset/train, transformtrain_tf) val_ds datasets.ImageFolder(dataset/val, transformval_tf) train_loader DataLoader(train_ds, batch_sizeBATCH_SIZE, shuffleTrue, num_workers4) val_loader DataLoader(val_ds, batch_sizeBATCH_SIZE, shuffleFalse, num_workers4) # 计算类别权重, 缓解不均衡 counts [0] * NUM_CLASSES for _, label in train_ds.samples: counts[label] 1 weights torch.tensor([sum(counts) / (NUM_CLASSES * c) for c in counts], dtypetorch.float).to(DEVICE) model models.mobilenet_v3_small(weightsmodels.MobileNet_V3_Small_Weights.IMAGENET1K_V1) model.classifier[3] nn.Linear(model.classifier[3].in_features, NUM_CLASSES) # 换分类头 model model.to(DEVICE) criterion nn.CrossEntropyLoss(weightweights) optimizer Adam(model.parameters(), lrLR) scheduler CosineAnnealingLR(optimizer, T_maxEPOCHS) best_acc 0.0 for epoch in range(EPOCHS): model.train() for imgs, labels in train_loader: imgs, labels imgs.to(DEVICE), labels.to(DEVICE) optimizer.zero_grad() loss criterion(model(imgs), labels) loss.backward() optimizer.step() scheduler.step() model.eval() correct total 0 with torch.no_grad(): for imgs, labels in val_loader: imgs, labels imgs.to(DEVICE), labels.to(DEVICE) pred model(imgs).argmax(1) correct (pred labels).sum().item() total labels.size(0) acc correct / total print(fepoch {epoch1} val_acc{acc:.4f}) if acc best_acc: best_acc acc torch.save(model.state_dict(), best_model.pth)逻辑说明weights按类别样本数的倒数计算样本少的类权重高让损失函数更关注它们。CosineAnnealingLR让学习率从 1e-3 余弦下降到接近 0比固定学习率收敛更稳。每轮验证后只在准确率提升时保存权重避免保存到过拟合的模型。参数说明BATCH_SIZE32是显存和稳定性的折中显存不够就降到 16同时把学习率按比例降到 5e-4。EPOCHS30对迁移学习足够通常 15 轮左右验证准确率就趋于平稳。LR1e-3是 Adam 微调的常用起点如果发现 loss 震荡降到 3e-4。num_workers4在 Windows 上如果报错就改成 0这是 Windows 下多进程的经典坑。注意换分类头时model.classifier[3]这个索引是 MobileNetV3 的结构决定的换成 ResNet 就是model.fc换 EfficientNet 是model.classifier[1]写之前先 print 一下模型结构确认别照抄。4. 部署落地把权重变成能用的服务4.1 三种部署形态怎么选课程大作业的部署常见有三种命令行脚本、Flask Web 服务、打包成 exe。命令行脚本最简单适合演示Flask Web 服务能上传图片返回结果答辩时用浏览器演示最直观打包 exe 适合交给完全不懂技术的老师双击就能跑。我一般推荐 Flask 方案工作量适中效果好看而且部署指南写起来清晰。Flask 服务的核心代码from flask import Flask, request, jsonify from PIL import Image import torch from torchvision import transforms, models import torch.nn as nn import io app Flask(__name__) DEVICE torch.device(cpu) # 部署环境通常没 GPU CLASSES [可回收物, 厨余垃圾, 有害垃圾, 其他垃圾] model models.mobilenet_v3_small() model.classifier[3] nn.Linear(model.classifier[3].in_features, len(CLASSES)) model.load_state_dict(torch.load(best_model.pth, map_locationcpu)) model.eval().to(DEVICE) tf transforms.Compose([ transforms.Resize((224, 224)), transforms.ToTensor(), transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225]), ]) app.route(/predict, methods[POST]) def predict(): file request.files[image] img Image.open(io.BytesIO(file.read())).convert(RGB) tensor tf(img).unsqueeze(0).to(DEVICE) with torch.no_grad(): prob torch.softmax(model(tensor), dim1)[0] idx prob.argmax().item() return jsonify({class: CLASSES[idx], confidence: round(prob[idx].item(), 4)}) if __name__ __main__: app.run(host0.0.0.0, port5000)逻辑说明加载权重时map_locationcpu保证在没有 GPU 的机器上也能加载。unsqueeze(0)给单张图补上 batch 维度。返回结果里带上置信度前端可以据此决定是否提示「识别不确定」。参数说明host0.0.0.0让局域网内其他设备也能访问答辩时用手机拍一张传上去演示效果很好。port5000是 Flask 默认端口被占用就换 5001。生产环境不要用app.run但课程大作业够用。4.2 部署指南文档该写哪些内容部署指南不是把命令堆上去就完事要按「一个没接触过你项目的人」的视角写。必备内容Python 版本要求建议 3.8 到 3.103.11 以上有些包会出问题、依赖安装命令、模型权重文件放哪、启动命令、访问方式、常见报错。依赖建议导出成 requirements.txtpip freeze requirements.txt # 别人拿到后 pip install -r requirements.txtrequirements.txt 里 torch 的版本要写清楚比如torch2.0.1不写版本号别人装到最新版可能 API 变了跑不起来。这是部署指南里最容易被忽略、又最容易导致「在我电脑上能跑」的一条。5. 避坑与排查那些让答辩翻车的细节5.1 准确率虚高测试集一跑就露馅现象训练时验证准确率 95%老师拿自己的照片一测错得离谱。原因通常是数据泄漏——同一物体的多角度照片被分到了训练和验证两边模型记住了物体而不是类别特征。解决按第 2 章的按组划分重做数据集并且留一批完全没参与训练的「外部测试图」做最终验证。5.2 部署时报 No module named torch现象在自己电脑上跑得好好的换台机器就报找不到 torch。原因requirements.txt 没写版本或者对方 Python 版本不兼容。解决明确写死版本号并在部署指南里注明 Python 版本范围。如果对方是 Windows 且装 torch 失败多半是没装对应 CUDA 版本CPU 版用pip install torch --index-url https://download.pytorch.org/whl/cpu更稳。5.3 上传图片后服务卡死或报错现象Flask 服务收到某些图片就 500。原因图片是 CMYK 模式或带透明通道Image.open后直接转 tensor 会出错。解决打开后统一.convert(RGB)这一步在第 4 章代码里已经加了但很多人会漏。另外限制上传大小app.config[MAX_CONTENT_LENGTH] 5 * 1024 * 1024防止超大图拖垮服务。5.4 报告 PPT 里数据对不上现象PPT 写的准确率和代码跑出来的不一致。原因PPT 用的是某次训练的中间结果后来重训了没更新。解决所有指标从最终保存的best_model.pth重新在测试集上跑一遍把混淆矩阵、每类准确率都导出来PPT 直接引用这份结果。混淆矩阵用 sklearn 的confusion_matrix几行就能出。5.5 打包 exe 后模型加载失败现象用 PyInstaller 打包后运行报找不到模型文件。原因打包后的路径和开发时不一样相对路径失效。解决用sys._MEIPASS处理资源路径或者干脆把模型文件放在 exe 同目录下用绝对路径读取。这个坑在答辩现场演示 exe 时特别致命提前测。6. 让这个项目更值钱的两个进阶技巧第一个技巧是把单张图片识别升级成视频流实时识别。思路很简单用 OpenCV 读摄像头帧每隔几帧送一次模型把结果画在画面上。这样答辩演示时对着垃圾桶一扫就出结果比上传图片震撼得多。核心代码就是在第 4 章 predict 逻辑外面套一层cv2.VideoCapture循环注意控制推理频率每 5 帧推理一次就够否则 CPU 扛不住。这里有个参数值得调置信度阈值设 0.6低于这个值显示「不确定」避免模型瞎猜导致演示尴尬。第二个技巧是给报告加一个「错误分析」章节。把测试集里预测错的图片挑出来按类别归类分析是背景干扰、光照问题还是类别本身容易混比如纸杯到底算可回收还是其他。这一章能体现你对数据的理解是拉开报告分数的关键。用几行代码就能导出错误样本import torch from torchvision import datasets from torch.utils.data import DataLoader test_ds datasets.ImageFolder(dataset/test, transformval_tf) loader DataLoader(test_ds, batch_size1, shuffleFalse) model.eval() wrong [] with torch.no_grad(): for i, (img, label) in enumerate(loader): pred model(img).argmax(1).item() if pred ! label.item(): path, _ test_ds.samples[i] wrong.append((path, test_ds.classes[label.item()], test_ds.classes[pred])) for w in wrong[:20]: print(f真实{w[1]} 预测{w[2]} 文件{w[0]})把这份错误清单整理进报告配上几张典型错图比单纯堆准确率数字有说服力得多。我自己做这类项目养成的习惯是模型跑完先不看准确率先看错误样本因为错误样本告诉你的信息永远比一个数字多。这两个技巧加上前面完整的训练部署流程一份课程大作业的源码、部署指南、报告 PPT 和文档就都有扎实的内容支撑了剩下的就是按部就班填进去。希望帮到你。本文还有配套的精品资源点击获取
企业数字化 ERP 产品动态
相关推荐
FCS 2.0文件解析:流式细胞术数据格式与Python读取实践 简介:流式细胞文件(FCS)2.0标准协议文档是一份面向流式细胞术数据分析人员、软件开发者和生物信息学研究者的经典规范PDF。该版本由分析细胞学学会数据文件标准委员会在1990年提出,至今虽已更新至3.2版,但2.0版确立的H… · 2026/9/23 1:43:31
ExpertNet + Resnet50:医疗图像无监督自适应多任务学习实战 简介:这是一份面向医疗图像分析场景的Python深度学习项目源码,基于ExpertNet与Resnet50构建多任务学习网络,并在无监督自适应策略下实现模型训练与评估,适合具备一定深度学习基础、希望研究多任务学习或医疗影像识别的研究者与开发… · 2026/9/23 1:43:06
博彦科技怎么样?3个版本升级API全变坑与完整示例 博彦科技怎么样?3个版本升级API全变坑与完整示例 版本升级后 API 全变了,项目直接崩盘?我在博彦科技驻场三年,见过太多因框架迭代导致接口对不上、报错满天飞的场景。这篇避坑指南不吹嘘公司福利,只讲真实踩过的技术深坑,附上 完整示例… · 2026/9/23 1:43:06
3分钟搞懂系统截图快捷键原理,面试不再挂科 3分钟搞懂系统截图快捷键原理,面试不再挂科 面试时被问“系统截图快捷键底层是怎么实现的”,你脑子里是不是只剩“Ctrl+Shift+S”?别慌,这题卡住很多人。今天这篇文章带你一文搞懂,从用户按下按键到图片存盘,全链路拆解,让你下次回答能直… · 2026/9/23 4:15:40
科技内容为何在短视频平台爆发?从1.4万亿次观看看全民科技热潮 你有没有在深夜刷抖音时,点进一个标题叫“为什么AI画手多了一根手指”的视频,结果一路刷完了评论区几百条吵架式讨论?这不是你的错觉,而是科技内容正式从小众爱好走向大众茶余饭桌的标志。2025年,抖音上科技类内容的观… · 2026/9/23 4:15:40
Biome Markdown 格式化器有序列表编号重排机制深度解析 开发工具Lint格式化静态分析代码质量前端 【免费下载链接】biome A toolchain for web projects, aimed to provide functionalities to maintain them. Biome offers formatter and linter, usable via CLI and LSP. 项目地址: https://gitcode.com/gh_mirrors/bi/… · 2026/9/23 4:15:40
存在主义视角下的焦虑本质与转化方法 1. 焦虑的本质与哲学解读焦虑(Angst)这个词在德语中有着特殊的哲学含义,它不同于普通的恐惧或担忧。我第一次深入理解这个概念是在研读存在主义哲学著作时,那种醍醐灌顶的感觉至今难忘。焦虑不是简单的负面情绪,而是人… · 2026/9/23 4:15:40
n76备考保姆级教程:告别配置地狱,5天搞定证书 n76备考保姆级教程:告别配置地狱,5天搞定证书 配置环境就卡半天,代码跑不通,报错日志看得人眼瞎。这种痛苦每个想考n76的朋友都经历过。 别慌,这篇保姆级教程带你避开90%的坑。 坑的现象:为什么你总是卡在环境配置上 现象描述:… · 2026/9/23 4:15:40
纯前端3D时空渲染引擎:浏览器内实现60帧高性能可视化 1. 从标题拆解这个项目的真实面貌1.1 这个标题到底在说什么“在浏览器里开间谍卫星”这个说法听起来很唬人,但拆开来看,它描述的其实是一类非常具体的技术产品形态:一个完全跑在浏览器里的三维时空数据可视化引擎。所谓“间谍卫星”是一种比喻… · 2026/9/23 4:15:34
3招搞定手机怎么下载微信面试难题实战项目解析 3招搞定手机怎么下载微信面试难题实战项目解析 面试被问“手机怎么下载微信”背后的原理,90%的人答不上来。别笑,这看似弱智的问题,实则是考察你对移动应用分发机制、安全校验及网络协议理解的试金石。我带过不少校招新人,他们背了八股文,却连一个A… · 2026/9/23 0:00:03
你有新短消息请注意查收:3个新手避坑指南搞定消息系统选型 你有新短消息请注意查收:3个新手避坑指南搞定消息系统选型 面试被问“高并发下如何保证消息不丢失”,你张口就是“用Redis”,结果面试官追问“如果Redis宕机了怎么办”,你瞬间卡壳。这种场景太常见了,很多新手在背八股文时,只记住了技术名词… · 2026/9/23 0:00:29