news 2026/10/5 12:30:36

基于深度学习的垃圾分类项目实战:从解压到部署全流程

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
基于深度学习的垃圾分类项目实战:从解压到部署全流程

简介:一份基于深度学习的垃圾分类项目压缩包,面向毕业设计、期末大作业及机器学习入门者,提供从数据处理、模型定义到应用部署的完整参考方案。项目以 Python 为主要开发语言,可配合 TensorFlow 或 PyTorch 等框架复现训练与推理流程。压缩包内含 43 个文件,主要由 Python 脚本、PyCharm 配置、Jupyter Notebook 和说明文档组成,其中模型脚本覆盖 SqueezeNet、ResNet 等常用网络结构,预处理模块负责图像缩放与归一化,工具函数则用于日志、评估和 JSON 解析,便于二次开发与调试。包体仅 55KB,轻量精炼,适合快速查阅代码结构。目前已有 45 人学习下载。通过该资源可以了解垃圾分类数据集的标注格式、模型训练流程、界面交互逻辑及推理输出方式,同时也能参考 .gitignore、readme 等文件学习项目规范化管理。对于准备课程设计或入门深度学习图像分类的读者,是一份实用且易上手的参考资料。

1. 基于深度学习的垃圾分类:先拆开这个zip看它到底值不值

拿到“基于深度学习的垃圾分类.zip”这类压缩包,第一反应别急着双击解压。这个标题背后是一个典型的图像分类落地项目:训练脚本、数据集组织、模型文件和推理入口全塞在一个压缩包里。它的核心价值在“分类”两个字——输入一张垃圾照片,输出它属于可回收、厨余、有害还是其他垃圾。适合有 PyTorch 基础、想把深度学习模型跑通并部署到边缘设备的工程师和学生。前提是你能把 zip 里的环境依赖、数据路径和类别映射理顺,否则大概率会在训练环节翻车。

2. 解压与项目结构梳理:先复现demo再碰训练

2.1 两步解压,先给文件体检

拿到 zip 后,我一般会先在 Linux 或 macOS 下用unzip解压,而不是直接双击。因为项目里常带 shell 脚本和 Python 代码,文件名可能包含中文或特殊字符,图形化解压工具容易把编码弄坏,导致后续 import 路径报错。

mkdir -p garbage_classify && cd garbage_classify unzip ../基于深度学习的垃圾分类.zip -d . find . -maxdepth 2 -type d | head -20

逻辑说明:先把 zip 解压到独立的项目目录,再用find看两层以内的目录结构。这样能快速确认压缩包是不是套了一层同名文件夹。如果是“垃圾分类/垃圾分类/...”这种嵌套,训练脚本里写死的相对路径会全部失效。

参数说明:-d .指定解压目标目录;maxdepth 2限制find的递归深度,避免把模型权重文件全列出来刷屏。解压后如果看到.py文件和data/目录平级,说明包结构正常。

解压后先看依赖文件。常见做法是项目根目录放一个requirements.txt或environment.yml,里面锁定了 numpy、torch、torchvision、opencv-python 这些版本。我建议用虚拟环境安装,不要直接装进系统 Python,避免和别的项目互相污染。

python -m venv venv source venv/bin/activate pip install --upgrade pip pip install -r requirements.txt

逻辑说明:创建虚拟环境后,所有依赖都装进venv/。后续即使项目里某个包版本号和本机已有包冲突,也不会影响其他工作目录。

参数说明:venv是虚拟环境目录名,可改成.venv以便在 shell 提示符中隐藏;--upgrade pip先把 pip 升到较新版本,因为老版本 pip 解析复杂依赖时容易报怪错。Windows 上source venv/bin/activate要换成venv\Scripts\activate。

2.2 项目目录里每类文件是干什么的

一个规范的垃圾分类项目,解压后大致是这种结构:

路径作用
data/train/训练集图片,按类别分子目录
data/val/验证集图片,目录名与训练集一致
train.py训练入口,包含模型构建、loss、优化器
model.py模型定义,通常是 resnet/mobilenet 的封装
infer.py推理脚本,输入单张图片输出类别
config.py超参数和路径配置,集中管理
models/训练产出的权重文件目录

这里最值得先看的是config.py和train.py头部。很多项目把类别列表、图片尺寸、epoch 数、学习率都散落在各个文件里,集中配置的话改起来省事。如果压缩包里直接带着.pth权重,先跑python infer.py --image 测试图.jpg把 demo 复现出来,再决定要不要重新训练。

# config.py 典型内容 NUM_CLASSES = 4 IMG_SIZE = 224 BATCH_SIZE = 32 EPOCHS = 30 LR = 1e-4 CLASS_NAMES = ["可回收", "厨余", "有害", "其他"] DEVICE = "cuda" if torch.cuda.is_available() else "cpu"

逻辑说明:把类别名、图片尺寸、批大小、学习率集中定义,训练和推理两个脚本同时引用这份配置,避免出现训练用 224、推理用 256 这种隐蔽的不一致。

参数说明:IMG_SIZE=224是 ImageNet 预训练模型惯用输入尺寸;BATCH_SIZE=32在 8GB 显存下跑 mobilenet 比较稳,resnet50 的话可能要降到 16;NUM_CLASSES必须和data/train/下的子目录数量一致,这是新手最容易栽的地方。

3. 数据组织与标签映射:垃圾分类数据集的坑比模型更大

3.1 从“可回收/厨余/有害/其他”到 one-hot 标签

垃圾分类本质是图像分类任务,模型输出的是一个 4 维概率向量。但实际拿到的数据往往是“某张图片对应某个中文类别名”,中间需要一次映射。常见做法是手写一个字典:

# label_map.py label_map = { "可回收": 0, "厨余": 1, "有害": 2, "其他": 3, } id_to_label = {v: k for k, v in label_map.items()}

逻辑说明:训练时图片目录名是中文或英文标签,通过label_map转成 0/1/2/3 的整数;推理时把模型输出概率最大的下标,通过id_to_label再翻译回中文。

参数说明:这个映射必须和config.py里的CLASS_NAMES顺序完全一致。如果训练脚本里写的是["其他", "有害", "可回收", "厨余"],而label_map里是另一套顺序,模型会一直学错,准确率还看不出明显异常——这类错位是垃圾分类项目里最难受的隐性 bug。

我见过不少项目直接拿 ImageFolder 按字母序生成标签。中文目录名在 Windows 上按 Unicode 排序,在 Linux 上按字节排序,两套顺序可能都不一样。所以不要依赖自动排序,必须显式指定映射。

垃圾分类数据集另一个特点是“图片质量参差”。用手机拍的厨余垃圾往往有大量背景干扰、光线不均,有的类别样本只有几百张,有的上万张。数据层面的坑,比模型选型的坑更容易决定最终效果。

3.2 用 PyTorch Dataset 加载本地图片:路径和缓存都别偷懒

如果项目没有直接给 Dataset 实现,我习惯自己写一份。核心要做两件事:把图片路径和标签配对,再在__getitem__里做解码和增广。

import torch from torch.utils.data import Dataset from PIL import Image import os class GarbageDataset(Dataset): def __init__(self, root_dir, transform=None): self.samples = [] for label_name, label_id in label_map.items(): class_dir = os.path.join(root_dir, label_name) for fname in os.listdir(class_dir): if fname.lower().endswith(('.jpg', '.jpeg', '.png')): self.samples.append((os.path.join(class_dir, fname), label_id)) self.transform = transform def __len__(self): return len(self.samples) def __getitem__(self, idx): path, label = self.samples[idx] image = Image.open(path).convert("RGB") if self.transform: image = self.transform(image) return image, label

逻辑说明:__init__阶段扫描整个目录,把每张图片的绝对路径和整数标签存进列表,一次扫完,训练时不再访问文件系统目录。__getitem__按索引读取图片、转成 RGB、做增广变换。

参数说明:convert("RGB")强制统一成三通道,避免出现灰度图或带透明通道的 PNG 导致 tensor 形状不一致;endswith过滤只保留常见图片格式,避免.txt或系统隐藏文件混进来。transform参数由训练脚本构造,一般包含 Resize、RandomCrop、RandomHorizontalFlip。

随机增广要谨慎。垃圾分类图片里,有些类别方向敏感度很低(比如电池),有些类别其实敏感(比如按形状辨认的玻璃瓶,倒过来后语义没有变化,但训练分布变了)。我一般只用RandomHorizontalFlip和ColorJitter,不做RandomRotation,避免把“有害”标志的朝向搞乱,导致模型特征学习偏移。

4. 训练脚本拆解:mobilenet 还是 resnet,参数怎么设

4.1 模型选型理由:先看算力再看准确率

如果 zip 里的项目默认用 resnet,通常是因为在 GPU 上跑很顺手。resnet50 在 ImageNet 上预训练充分,作为迁移学习起点非常稳。但如果目标是落地到 Jetson 或树莓派这种边缘设备,mobilenet v3 或 mobilenet v2 才是合理选择。参数量差距很直观:

模型参数量单张 224×224 推理相对耗时适合场景
resnet50约 25.6M中服务器训练,追求准确率
mobilenet v2约 3.5M快边缘设备部署
mobilenet v3 small约 2.5M更快低功耗设备

选型不是越大的模型越好。垃圾分类总共 4 类或几十类,类别数是固定的,输入图是日常照片,不需要像 ImageNet 1000 类那样大的容量。我做实际项目时,先用 mobilenet 做 baseline,如果验证集准确率不达标,再换 resnet 看增益。反过来先跑 resnet 再压缩,往往费时费力。

4.2 训练主循环与 5 个必调参数

# train.py 核心片段 from torchvision import models from torch.utils.data import DataLoader model = models.mobilenet_v2(pretrained=True) model.classifier[1] = torch.nn.Linear(model.last_channel, NUM_CLASSES) model = model.to(DEVICE) criterion = torch.nn.CrossEntropyLoss() optimizer = torch.optim.AdamW(model.parameters(), lr=LR, weight_decay=1e-4) scheduler = torch.optim.lr_scheduler.CosineAnnealingLR(optimizer, T_max=EPOCHS) for epoch in range(EPOCHS): model.train() for images, labels in train_loader: images, labels = images.to(DEVICE), labels.to(DEVICE) outputs = model(images) loss = criterion(outputs, labels) optimizer.zero_grad() loss.backward() optimizer.step() scheduler.step()

逻辑说明:用 torchvision 加载在 ImageNet 上预训练过的 mobilenet_v2,把最后分类层替换成自己类别数的输出。训练循环是标准模式:前向、算损失、清空梯度、反向、更新参数。scheduler 每轮调整学习率,让后期训练更稳。

参数说明:

  • pretrained=True用 ImageNet 权重做初始化,收敛速度远快于随机初始化。
  • model.last_channel是 mobilenet_v2 的倒数第二层输出维度,替换分类头时必须用它,不能写成 1280 这种魔法数字,否则换模型时忘记同步改就报维度错。
  • AdamW比 Adam 多了正确的权重衰减实现,配合weight_decay=1e-4能减少过拟合。
  • CosineAnnealingLR在训练后期自动降低学习率,比固定学习率更容易收到一个平缓收敛的尾巴。
  • BATCH_SIZE设为 32 在 8GB 显存下跑 mobilenet 比较稳,如果报 CUDA out of memory,降到 16 或 8。

训练时我习惯每跑完一个 epoch 打印一次 train loss 和 val acc,不要等到全部训完才看。loss 一直在降但验证集准确率不动,十有八九是过拟合,早停比换模型更有效。

4.3 类别不均衡:loss 里加一个权重就够了

真实垃圾分类数据集中,“其他垃圾”往往样本特别多,“有害垃圾”特别少。如果不处理,模型会学成“全都预测其他垃圾”,整体准确率还挺高,但有害垃圾的实际召回率几乎为 0。解决手段很简单:统计每类样本数,给少数类更大的 loss 权重。

from sklearn.utils.class_weight import compute_class_weight import numpy as np labels = [label for _, label in train_dataset.samples] class_weights = compute_class_weight( class_weight="balanced", classes=np.unique(labels), y=np.array(labels) ) class_weights = torch.tensor(class_weights, dtype=torch.float32, device=DEVICE) criterion = torch.nn.CrossEntropyLoss(weight=class_weights)

逻辑说明:compute_class_weight按样本数反比计算出每类权重,样本少的类别权重高,样本多的权重低。CrossEntropyLoss 在算梯度时乘以该权重,相当于把少数类的每个样本重要性放大。

参数说明:balanced模式的计算公式是总样本数除以(类别数乘以该类样本数),不需要手写;classes参数必须传唯一的标签数组,不能传原始列表。权重最终要搬到与模型相同的设备上,否则 loss 计算时 tensor 跨设备会报错。

加了类别权重之后,整体准确率可能略有下降,但有害垃圾的召回率会明显上来。做垃圾分类项目要看的核心指标不是总 acc,而是每个类别的精确率和召回率,尤其是有害垃圾。只看总分,容易被数据分布骗了。

5. 垃圾分类项目落地的常见坑与排查:解压到推理全流程

5.1 zip 解压后中文目录名导致 ImageFolder 读取失败

现象:Windows 上解压后,data/train/可回收/下面图片一读取就报FileNotFoundError,或者图片找到了但路径显示乱码。

原因:zip 压缩包里的中文文件名编码通常由打包机器的系统编码决定(常见 GBK 或 UTF-8),Windows 自带解压工具和 Python 的zipfile模块对非 UTF-8 文件名处理不一致,导致解压出来的目录名看着正常,实际字节已经损坏。

解决:在 Python 里重新解压并显式指定编码,或者干脆把数据集目录全部改成拼音或英文名,只保留label_map里的中文显示名。我一般选后者,一劳永逸:

cd data/train mv 可回收 recyclable mv 厨余 kitchen_waste mv 有害 hazardous mv 其他 other

这样目录名全是 ASCII,无论在哪台机器解压都不会再出现编码问题。对应地,把label_map和CLASS_NAMES同步改成英文 key,推理展示时再转回中文。

5.2 类别目录名与代码硬编码不一致:报错 KeyError

现象:train.py一跑起来就KeyError: '可回收',或者label_map定义的键不在目录列表里。

原因:数据目录是后来补的图片,目录名和代码里写死的类别名有一个字对不上(比如“厨余”和“厨余垃圾”),或者打包时把类别目录嵌套了一层,os.listdir拿到的是子文件夹名而不是图片文件。

解决:优先让数据迁就代码。写一段校验脚本,打印出label_map和实际目录之间的差集:

import os for label_name in label_map.keys(): path = os.path.join("data/train", label_name) if not os.path.isdir(path): print("缺失目录:", label_name)

逻辑说明:脚本遍历映射字典中的每个类别名,检查训练目录下是否存在同名子目录。如果少了某个类别,说明数据目录和代码不一致。

参数说明:os.path.isdir只能判断目录,不能用文件路径替代。检查完目录后,还要确认每个类别目录里至少有一张图片,否则DataLoader在某个 epoch 采样时仍会报空。

5.3 训练时内存/显存不足:batch_size、workers、混合精度

现象:训练开始没几个 step 就报CUDA out of memory,或者 CPU 直接卡死、内存被吃满。

原因:显存不足通常是 batch_size 太大或输入图片尺寸超出了IMG_SIZE设定;内存吃满多半是DataLoader的num_workers开太高,或者有缓存机制一次性把全部图片读进内存。

解决:先减小 batch_size 到 8 或 16,把IMG_SIZE从 224 降到 192 实测一次,确认能跑通再加回去。num_workers一般从 4 开始调,显存和内存都不宽裕的机器设成 2。

train_loader = DataLoader( train_dataset, batch_size=BATCH_SIZE, shuffle=True, num_workers=2, pin_memory=True, persistent_workers=True, )

逻辑说明:pin_memory=True让数据加载到锁页内存,能加快 GPU 拷贝;persistent_workers=True避免每个 epoch 重复创建 worker 进程,但该参数在 Windows 上偶尔会引发多进程报错,遇到就删掉。

参数说明:num_workers=2在双核机器和主流服务器上都是比较稳的起点,开太高会让数据加载变成瓶颈反而不快。shuffle=True只能用于训练集,验证集必须设False。

如果换了 mobilenet 还爆显存,检查代码里是不是把验证集也放进了训练流程,或者模型输出了所有中间层激活(比如为了可视化 Grad-CAM 把 hook 一直挂着),这类代码问题比硬件问题更常见。

5.4 部署到低算力设备时模型转换失败

现象:用torch.jit.trace或onnx.export导出模型时,报Unsupported operator或推理结果全错。

原因:训练脚本里用了动态控制流(比如if batch_size > 1分支),trace 阶段没法正确跟踪;或者模型里有 Resize、插值操作与导出格式不兼容。

解决:导出前把模型切到 eval 模式,用固定尺寸的 dummy input 做 trace。更稳妥的做法是先导出 ONNX,再用 ONNX Runtime 推理,整体流程更清晰:

import torch.onnx model.eval() dummy = torch.randn(1, 3, 224, 224).to(DEVICE) torch.onnx.export( model, dummy, "garbage_classify.onnx", input_names=["input"], output_names=["output"], opset_version=11, dynamic_axes={"input": {0: "batch"}, "output": {0: "batch"}}, )

逻辑说明:model.eval()关闭 dropout 和 batch norm 的训练行为,保证导出的图是推理时真正执行的路径。dynamic_axes允许推理时 batch 维不固定,方便单张图片按 1 传入。

参数说明:opset_version=11兼容性较好;动态 batch 设置后,推理端要按[N, 3, 224, 224]的输入形状组装 tensor。如果目标设备只支持静态输入,就删掉dynamic_axes,固定成[1, 3, 224, 224]。

6. 进阶:把模型导出成 ONNX 再量化,让垃圾分拣跑在边缘盒子上

训练完权重只是第一步。如果最终要部署到 Jetson Nano、RK3588 或树莓派这类边缘设备,我一般会把模型先转成 ONNX,再做 INT8 量化,体积能压到原来的四分之一,推理速度提升明显。这里有一个特别实用的技巧:不是导出之后才量化,而是先做 Post-Training Quantization 校准。

校准需要一小批有代表性的真实图片,不能随便拿几十张高斯噪声凑数。垃圾分类场景下,校准集最好覆盖四个类别,每类挑 5 到 10 张,确保缩放因子覆盖到各种亮度。用 onnxruntime 的量化工具包时,特别留意opset_version和量化算子是否被目标设备的推理引擎支持。

我踩过的最深一个坑,是把量化后的模型发到设备上,发现输出概率全是同一个值,排查半天才发现是校准图片没有做和训练时一致的归一化,亮度分布偏移导致激活值全部落入量化的死区。

现在我做这套项目,会先把transform里的Normalize(mean, std)参数原封不动带到推理前处理脚本,再设计一个“端到端一致性检查”:拿同一张图,原始 PyTorch 模型的 top-1 类别和 ONNX 量化模型的 top-1 类别必须一致,不一致就回退到 FP16 或找算子的兼容性问题,不强行压 INT8。

按这个套路,从 zip 解压到部署,我基本能在半天内把一个垃圾分类 demo 跑起来。早期我也犯过只盯着训练集准确率、拿到压缩包不先看数据分布就开训的毛病,后来被验证集准确率狠狠教育了一回。实践下来,这类项目的成败关键,七成在数据组织,三成在模型参数。希望这份拆解能帮你少走几趟弯路,把时间花在真正影响结果的地方。

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

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/5 12:30:09

大模型从会聊天到会干活:提示词与工具调用实战指南

1. 从“会聊天”到“会干活”的分水岭到底在哪很多人第一次接触大模型,都是从聊天开始的。你问它一句“帮我写个周报”,它噼里啪啦给你输出一大段,看着挺像那么回事。但真到了要它去查数据库、调接口、发邮件、改代码、跑脚本的时候&#xff…

作者头像 李华
网站建设 2026/10/5 12:27:15

OpenRIG开源模拟赛车座舱搭建指南:铝型材DIY完整避坑

最近我在模拟赛车圈子里关注到一套很有意思的开源方案,叫 OpenRIG。它不是某个品牌出的成品支架,也不是那种看起来很唬人的广告图,而是一整套基于开源图纸、通用铝型材和标准紧固件拼装起来的赛车模拟器座舱。简单说,就是你可以用…

作者头像 李华
网站建设 2026/10/5 12:26:26

生成式AI服务管理实战:从模型层到交互层的落地要点

一个生成式人工智能服务从“跑通 Demo”到“稳定可用”,中间差的往往不是模型选得多强,而是管理得有没有章法。最近不少人都在聊“生成式人工智能服务管理”这个话题,各家文章大多围绕宏观框架展开,真正到团队执行层面的实践经验反…

作者头像 李华
网站建设 2026/10/5 12:26:25

高频功率放大器设计全攻略:从指标定义到调试避坑指南

1. 立项之前,先想清楚指标之间的“三角债”高频功率放大器的设计,很多人一上来就翻管子型号、画原理图,觉得把管子焊上去就能出功率。我在这个行当里做过不少项目,实事求是讲,功放是射频链路里最容易被“一票否决”的模…

作者头像 李华
网站建设 2026/10/5 12:26:24

继电保护整定计算全流程解析:从短路电流到定值单实战指南

咱们搞继电保护的人,电脑里谁没存过几十套整定计算书、方案模板?但真到要出计算书、做定值单、应付审查的时候,往往还是觉得心里没底。这阵子我整理了一套完整的继电保护整定值计算软件配套资料,总共69份,从原理说明到…

作者头像 李华