ARTICLE DETAIL

资讯详情

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

基于深度学习的垃圾分类系统实战:从数据到边缘部署

基于深度学习的垃圾分类系统实战:从数据到边缘部署 简介这份资源是面向深度学习入门者、课程设计或毕业设计学生的垃圾分类系统完整项目包基于YOLO目标检测算法实现垃圾图像的自动识别与分类帮助解决传统人工分拣效率低、成本高的问题。压缩包共7个文件约12KB以3个csv数据文件、2个Python脚本、1个pyc编译文件及1个md说明文档为主csv用于存放标签、历史记录与用户信息py脚本承担主程序与算法逻辑md提供项目说明。项目采用前后端分离思路包含视图与静态资源模块便于直接运行和二次开发。目前已有59人学习下载适合希望快速搭建可运行垃圾分类demo、理解YOLO在图像识别中应用流程的读者参考也可作为课程设计或毕业设计的起步模板帮助梳理数据集构建、界面交互与后端推理的整体结构。1. 垃圾分类系统遇上深度学习一个.zip背后到底藏着什么打开招聘软件搜“算法工程师”十个岗位里有六个在提“垃圾分类”或“智慧环卫”。这不是巧合。过去三年从上海到北京从社区到写字楼垃圾分类从倡导变成了硬性要求靠人工盯着垃圾桶不现实靠传统图像处理——颜色阈值、边缘检测、SVM——遇到沾了油渍的外卖盒、被压扁的塑料瓶、光线昏暗的楼道口准确率直接掉到六成以下。深度学习进来之后同样的场景一个轻量CNN就能把准确率拉到九成以上。这个标题里的“基于深度学习的垃圾分类系统.zip”本质上就是一套把摄像头画面变成“可回收/厨余/有害/其他”四分类结果的完整工程方案。它适合两类人一是想拿它当毕设或课程设计的学生二是想在社区、园区、商场落地智能垃圾桶或分拣线的工程师。接下来的内容我会按“数据怎么来、模型怎么选、训练怎么调、部署怎么跑、坑怎么避”的顺序把这条链路拆开讲清楚。2. 数据从哪来垃圾分类数据集的采集、清洗与增强2.1 公开数据集与自采数据的取舍做垃圾分类系统第一个卡点从来不是模型是数据。网上能直接下载的公开数据集常见的有TrashNet、TACO、华为云垃圾分类数据集等。TrashNet只有2527张图六个类别背景干净全是白底摆拍。拿它训出来的模型放到真实垃圾桶场景里准确率能掉三十个点。TACO更大但标注质量参差很多图是户外随手拍类别定义和国内四分类标准对不上。我的建议是公开数据集只用来做预训练或者冷启动真正要落地必须自己采。自采数据有个容易被忽略的细节不要只拍“标准投放”的图。真实场景里垃圾是混在一起的外卖盒里有剩饭纸箱上有胶带塑料瓶里有半瓶水。采集时要刻意覆盖这些“脏数据”。我一般会按下面的比例来组织数据来源占比用途公开数据集20%预训练、扩充类别社区实拍50%主训练集网络爬取20%补充长尾类别合成数据10%极端场景模拟采集设备不用一上来就上工业相机。手机就够了但要注意固定焦距和拍摄距离。我见过有人用不同手机、不同角度拍了几千张结果模型学到的全是设备差异不是垃圾特征。2.2 清洗与标注的四个硬规则数据清洗比标注更耗时间。下面这四条规则是我踩过坑之后定下来的第一剔除模糊和过曝的图。用拉普拉斯方差判断模糊阈值设在100左右低于这个值的直接删。过曝的图看直方图高光区域超过15%的也删。第二统一分辨率。不要直接resize到224×224先按短边缩放到256再中心裁剪到224。这样能保留更多细节尤其是小目标比如电池、药片。第三标注框要贴紧目标。垃圾分类里很多小目标标注框松了模型学到的就是背景。用LabelImg或CVAT标的时候框的边缘离目标不要超过5个像素。第四类别平衡。四分类里“有害垃圾”天然少电池、灯管、药品一个社区一天也收不了几件。解决办法不是硬凑而是用加权采样或者Focal Loss。我一般会把有害垃圾的采样权重调到其他类别的3到5倍。2.3 数据增强别只会翻转和旋转数据增强是提升泛化最便宜的手段。但垃圾分类场景有它的特殊性通用的翻转、旋转、裁剪不够用。下面这段代码是我常用的增强策略基于Albumentations实现import albumentations as A from albumentations.pytorch import ToTensorV2 train_transform A.Compose([ A.RandomResizedCrop(224, 224, scale(0.7, 1.0)), # 随机裁剪模拟不同距离 A.HorizontalFlip(p0.5), # 水平翻转 A.RandomBrightnessContrast(p0.3), # 亮度对比度扰动模拟光照变化 A.HueSaturationValue(p0.2), # 色相饱和度扰动模拟不同材质反光 A.MotionBlur(blur_limit5, p0.1), # 运动模糊模拟摄像头抖动 A.CoarseDropout(max_holes8, max_height16, max_width16, p0.2), # 随机遮挡模拟垃圾被部分遮盖 A.Normalize(mean[0.485, 0.456, 0.406], std[0.229, 0.224, 0.225]), ToTensorV2() ])这段代码里RandomResizedCrop的scale设成0.7到1.0是为了让模型适应垃圾在画面中不同大小。CoarseDropout模拟的是垃圾被其他物体遮挡的情况比如塑料瓶被纸箱压住一半。MotionBlur和HueSaturationValue分别对应摄像头抖动和不同材质在灯光下的色偏。参数不是固定的如果你的场景光照稳定、摄像头固定可以把亮度对比度和运动模糊的概率调低甚至去掉。注意增强策略要在验证集上验证。我见过有人加了太多增强训练集准确率很高验证集一塌糊涂原因是增强后的图和真实分布偏离太远。3. 模型选型从MobileNet到ConvNeXt垃圾分类该用哪个3.1 轻量级CNN在边缘设备上的优势垃圾分类系统最终大概率要跑在边缘设备上——树莓派、Jetson Nano、或者带NPU的国产开发板。这些设备算力有限内存通常只有几个G。所以模型选型的第一原则是参数量要小推理速度要快准确率够用就行。MobileNetV3-Small是我最常用的基线。参数量只有2.5M左右在Jetson Nano上跑224×224的图FP16推理能到30帧以上。准确率方面在自采的四分类数据集上通常能到92%到94%。如果场景简单、光照稳定这个数字还能更高。ShuffleNetV2是另一个选择参数量更小但准确率略低。EfficientNet-Lite在移动端优化得不错但部署时依赖TFLite如果你用PyTorch训练转过去会麻烦一点。下面这段代码是用PyTorch加载预训练MobileNetV3并修改分类头的标准做法import torch import torch.nn as nn from torchvision.models import mobilenet_v3_small, MobileNet_V3_Small_Weights def build_model(num_classes4, pretrainedTrue): weights MobileNet_V3_Small_Weights.IMAGENET1K_V1 if pretrained else None model mobilenet_v3_small(weightsweights) # 替换分类头原版是1000类ImageNet in_features model.classifier[3].in_features model.classifier[3] nn.Linear(in_features, num_classes) return model model build_model(num_classes4) print(f参数量: {sum(p.numel() for p in model.parameters()) / 1e6:.2f}M)这里的关键是model.classifier[3]MobileNetV3的分类头是一个Sequential最后一层是Linear。替换成4类之后前面的特征提取层用ImageNet预训练权重初始化训练时可以先冻结也可以直接微调。我一般会先冻结前几层训5个epoch再解冻全部微调。3.2 什么时候该上ConvNeXt或Swin Transformer如果你的部署环境不是边缘设备而是服务器或者云端那可以考虑更大的模型。ConvNeXt-Tiny和Swin-Tiny在垃圾分类任务上比MobileNetV3能高出3到5个点。但代价是参数量大了十倍以上推理速度慢五到八倍。判断标准很简单如果业务对延迟不敏感比如垃圾桶满了才拍一张照上传到云端识别那用大模型没问题。如果是实时分拣线传送带每秒过好几个物体那必须用轻量模型。还有一个折中方案知识蒸馏。用ConvNeXt当教师模型MobileNetV3当学生模型在自采数据上蒸馏。我做过一次对比蒸馏后的MobileNetV3比直接训练的版本高了2.3个点推理速度不变。代价是训练时间翻倍因为要同时跑两个模型。3.3 迁移学习与微调策略垃圾分类的数据集通常不大自采几千到几万张。从头训练不现实必须用迁移学习。但迁移学习不是简单地把预训练权重加载进来就完事有几个参数要调学习率方面特征提取层用1e-4到1e-5分类头用1e-3到1e-2。用PyTorch的param_groups实现optimizer torch.optim.AdamW([ {params: model.features.parameters(), lr: 1e-5}, {params: model.classifier.parameters(), lr: 1e-3} ], weight_decay1e-4)冻结策略上如果自采数据和ImageNet差异大比如全是垃圾桶内部的俯拍图那冻结层数要少甚至全部解冻。如果差异小比如白底摆拍的垃圾图那冻结前几层就够了。Batch Size在边缘设备上通常设不大8到16比较常见。如果显存不够用梯度累积。训练轮数一般20到30个epoch配合CosineAnnealingLR学习率从初始值降到1e-6。4. 训练与调参让模型在真实垃圾桶场景下不翻车4.1 损失函数选择CrossEntropy还是Focal Loss垃圾分类的类别不平衡是常态。可回收物和厨余垃圾占大多数有害垃圾可能只占1%到2%。用标准的CrossEntropyLoss模型会倾向于预测多数类有害垃圾的召回率极低。Focal Loss是解决这个问题的常用手段。它通过调节因子降低易分类样本的权重让模型聚焦在难样本上。PyTorch没有内置Focal Loss但实现起来不复杂import torch.nn.functional as F class FocalLoss(nn.Module): def __init__(self, alphaNone, gamma2.0, reductionmean): super().__init__() self.alpha alpha # 类别权重tensor self.gamma gamma self.reduction reduction def forward(self, inputs, targets): ce_loss F.cross_entropy(inputs, targets, weightself.alpha, reductionnone) pt torch.exp(-ce_loss) focal_loss ((1 - pt) ** self.gamma) * ce_loss if self.reduction mean: return focal_loss.mean() return focal_loss.sum()gamma控制难易样本的聚焦程度设2.0是常见值。alpha是类别权重可以按类别频率的倒数来设。比如四类频率分别是0.4、0.35、0.2、0.05那alpha可以设成[1.0, 1.14, 2.0, 8.0]然后归一化。我一般会先用CrossEntropy训几个epoch看看各类的召回率。如果有害垃圾的召回率低于70%就换Focal Loss。换了之后通常能提到85%以上但整体准确率可能掉0.5到1个点这是正常的取舍。4.2 学习率调度与早停学习率调度对最终精度影响很大。我试过StepLR、CosineAnnealingLR和OneCycleLR在垃圾分类任务上CosineAnnealingLR最稳。OneCycleLR收敛更快但需要调max_lr调不好容易震荡。早停的耐心值设5到7个epoch。监控指标用验证集的F1-score不要用准确率。因为类别不平衡时准确率会骗人。一个把所有样本都预测成可回收物的模型准确率也有40%。下面是一个完整的训练循环骨架from torch.optim.lr_scheduler import CosineAnnealingLR scheduler CosineAnnealingLR(optimizer, T_max30, eta_min1e-6) best_f1 0.0 patience 7 counter 0 for epoch in range(30): model.train() for images, labels in train_loader: images, labels images.cuda(), labels.cuda() optimizer.zero_grad() outputs model(images) loss criterion(outputs, labels) loss.backward() optimizer.step() scheduler.step() # 验证 model.eval() all_preds, all_labels [], [] with torch.no_grad(): for images, labels in val_loader: images images.cuda() outputs model(images) preds outputs.argmax(dim1).cpu().numpy() all_preds.extend(preds) all_labels.extend(labels.numpy()) f1 f1_score(all_labels, all_preds, averagemacro) if f1 best_f1: best_f1 f1 torch.save(model.state_dict(), best_model.pth) counter 0 else: counter 1 if counter patience: print(f早停于epoch {epoch}) break这段代码里T_max设成总epoch数eta_min是最小学习率。早停的耐心值设7意味着连续7个epoch验证F1没提升就停。保存的是最佳模型不是最后一个epoch的模型。4.3 类别不平衡的采样策略除了Focal Loss采样策略也能缓解类别不平衡。PyTorch的WeightedRandomSampler可以根据类别权重决定每个样本被采到的概率from torch.utils.data import WeightedRandomSampler class_counts [4000, 3500, 2000, 500] # 四类样本数 class_weights [1.0 / c for c in class_counts] sample_weights [class_weights[label] for _, label in dataset] sampler WeightedRandomSampler(sample_weights, num_sampleslen(dataset), replacementTrue) train_loader DataLoader(dataset, batch_size16, samplersampler)这样每个batch里有害垃圾的比例会明显提高。但要注意采样后的数据分布和真实分布不一致验证集不能用这种采样必须用原始分布否则评估结果会偏乐观。5. 部署与推理从PyTorch到ONNX再到边缘设备5.1 模型导出与量化训练完的PyTorch模型不能直接扔到边缘设备上跑。常见路径是PyTorch → ONNX → TensorRT或OpenVINO。导出ONNX的代码如下import torch.onnx model.eval() dummy_input torch.randn(1, 3, 224, 224).cuda() torch.onnx.export( model, dummy_input, garbage_classifier.onnx, input_names[input], output_names[output], dynamic_axes{input: {0: batch_size}, output: {0: batch_size}}, opset_version11 )opset_version设11比较稳设太高有些推理引擎不支持。dynamic_axes让batch维度可变方便部署时调整。量化是进一步提速的手段。PyTorch支持动态量化和静态量化。动态量化最简单一行代码quantized_model torch.quantization.quantize_dynamic( model, {nn.Linear}, dtypetorch.qint8 )但动态量化只量化Linear层对卷积层没用。静态量化需要校准数据流程复杂一些但能量化整个模型速度提升更明显。在Jetson Nano上静态量化后的MobileNetV3推理速度能从30帧提到45帧左右准确率掉1到2个点。5.2 边缘设备推理框架对比框架支持硬件优点缺点TensorRTNVIDIA GPU速度快FP16/INT8支持好只支持NVIDIAOpenVINOIntel CPU/VPUCPU上优化好不支持ARMTFLiteARM CPU/GPU移动端生态好算子支持有限ONNX Runtime多平台通用性好边缘设备上性能一般NCNNARM CPU无依赖体积小文档少如果用的是Jetson系列直接上TensorRT。如果是树莓派用NCNN或TFLite。如果是带NPU的国产开发板比如瑞芯微RK3588用RKNN工具链。5.3 推理服务的封装与并发单张图片推理和视频流推理是两回事。视频流要考虑帧率、并发和内存。我一般会用多进程队列的方式import multiprocessing as mp import cv2 def inference_worker(input_queue, output_queue, model_path): model load_model(model_path) while True: frame input_queue.get() if frame is None: break result model.predict(frame) output_queue.put(result) # 主进程读帧子进程推理 input_q mp.Queue(maxsize10) output_q mp.Queue(maxsize10) workers [mp.Process(targetinference_worker, args(input_q, output_q, model.onnx)) for _ in range(2)] for w in workers: w.start()队列的maxsize要设不然内存会爆。worker数量根据设备CPU核心数来一般设2到4个。如果设备有GPU用CUDA流做异步推理更高效。6. 避坑与排查垃圾分类系统落地时最容易翻车的五个地方6.1 现象模型在测试集上准确率95%上线后用户投诉不断原因测试集和真实场景分布不一致。测试集可能是白底摆拍真实场景是垃圾桶内部光照差、遮挡多、角度偏。解决重新采集真实场景数据至少5000张覆盖不同光照、角度、遮挡情况。用t-SNE可视化训练集和真实数据的特征分布如果差异大说明域偏移严重需要做域适应或者重新训练。6.2 现象有害垃圾召回率极低几乎全预测成其他垃圾原因类别不平衡加上标注错误。有害垃圾样本少标注时容易把电池和药片混在一起模型学不到区分特征。解决先检查标注把有害垃圾的细分类别标清楚。然后用Focal Loss加加权采样。如果还是不行考虑二阶段方案先判断是不是有害垃圾再细分具体类别。6.3 现象推理速度慢视频流卡顿原因模型太大或者预处理在CPU上做成为瓶颈。解决换轻量模型用ONNX Runtime或TensorRT加速。预处理用GPU做比如用CUDA的resize和normalize。如果还不行降低输入分辨率从224降到192或160速度能提升30%以上准确率掉1到2个点。6.4 现象模型对某些类别过拟合换一个社区就失效原因训练数据只来自一个社区垃圾的材质、品牌、包装风格单一。解决多社区采集数据至少覆盖3个以上不同区域。用风格迁移或者数据增强模拟不同社区的差异。如果做不到至少在模型里加一个域分类器做对抗训练让特征提取器学到的特征和域无关。6.5 现象ONNX导出成功但推理结果和PyTorch不一致原因算子版本不匹配或者预处理不一致。PyTorch的Normalize和ONNX的Normalize可能对均值和标准差的处理顺序不同。解决导出前把预处理也放进模型里用torch.nn.Sequential把Normalize层包进去。导出后用ONNX Runtime跑一遍和PyTorch的输出做逐元素对比误差超过1e-4就要查。7. 进阶技巧用知识蒸馏把大模型的能力塞进小模型如果你已经有一个准确率不错但跑不动的大模型比如ConvNeXt-Tiny想把它部署到边缘设备上知识蒸馏是最实用的手段。核心思路是让学生模型MobileNetV3不仅学真实标签还学教师模型的软标签。下面是一个蒸馏损失函数的实现class DistillationLoss(nn.Module): def __init__(self, alpha0.5, temperature4.0): super().__init__() self.alpha alpha self.temperature temperature self.ce nn.CrossEntropyLoss() self.kl nn.KLDivLoss(reductionbatchmean) def forward(self, student_logits, teacher_logits, labels): # 硬标签损失 hard_loss self.ce(student_logits, labels) # 软标签损失 soft_student F.log_softmax(student_logits / self.temperature, dim1) soft_teacher F.softmax(teacher_logits / self.temperature, dim1) soft_loss self.kl(soft_student, soft_teacher) * (self.temperature ** 2) return self.alpha * hard_loss (1 - self.alpha) * soft_losstemperature控制软标签的平滑程度设4.0是常见值。alpha控制硬标签和软标签的权重设0.5意味着两者各占一半。训练时教师模型冻结只更新学生模型。我做过一次对比实验直接训练MobileNetV3验证集F1是0.91用ConvNeXt-Tiny蒸馏F1到了0.936。推理速度不变模型大小不变。代价是训练时间从2小时变成5小时因为每个batch要跑两次前向。蒸馏的坑在于教师模型不能太强否则软标签太尖锐学生学不动。也不能太弱否则蒸馏没意义。一般教师模型比学生模型高3到5个点最合适。另外蒸馏时数据增强要关掉或者减弱因为教师模型对增强后的图可能给出错误的软标签。还有一个技巧是中间层蒸馏不仅学输出还学特征图。这需要教师和学生的特征维度对齐通常加一个1×1卷积做投影。实现起来复杂一些但效果比只学输出好能再提1到2个点。最后说一个我自己的习惯每次训练完我都会把模型在验证集上预测错的样本单独拎出来看。垃圾分类系统里错得最多的往往是那些“边界样本”——沾了油的纸盒、带盖的塑料瓶、混合材质的包装。这些样本不是模型的问题是分类标准本身模糊。遇到这种情况我会在系统里加一个“不确定”类别置信度低于阈值的样本不强行分类而是提示用户人工确认。这个策略在真实场景里比强行提高准确率更实用。希望帮到你。本文还有配套的精品资源点击获取
返回列表