从PyTorch到安卓:垃圾分类CNN模型部署全流程

从PyTorch到安卓:垃圾分类CNN模型部署全流程 简介基于卷积神经网络的垃圾分类安卓应用提供完整Java源代码和配套设计资料面向计算机相关专业学生、毕业设计开发者以及希望掌握深度学习移动端部署的入门者。项目将CNN分类模型成功整合到安卓端包含垃圾搜索、图像识别、题目测试和知识科普四大功能模块垃圾搜索收录3986种物品图像识别覆盖143类常见生活垃圾能够辅助居民完成日常分类。设计资料与源码相互对应涵盖项目整体架构、模块划分、关键代码调用关系及运行配置说明便于读者从模型加载、图像预处理到识别结果展示全流程理解工程实现。压缩包为zip格式大小约17.35MB以Java/Android源码和设计文档为主目录清晰可直接导入开发工具运行或在此基础上进行二次开发。代码经过运行验证作者也提供远程教学支持适合作为毕业设计、课程设计或项目初期演示的参考目前已有53人学习/浏览对于快速搭建完整深度学习安卓应用具有较好借鉴价值。1. 从“能跑”到“能上手机”垃圾分类模型差的不只是精度做垃圾分类的深度学习项目最常见的结果不是模型精度不够而是模型训练完就停在.pth文件里演示的时候打开电脑跑一下到交付时就卡住了。真正要把“基于卷积神经网络的垃圾分类”落地成安卓应用难点不在卷积层怎么搭而在三条链路图像输入怎么统一、模型怎么压缩导出、Java 端怎么把 Bitmap 变成模型能吃的张量。这篇文章按“训练选型 → 模型导出 → 安卓推理 → 实时识别 → 结果验证”的顺序聊一条我自己验证过、能直接抄的从 PyTorch 到安卓手机的通路。适用人群是 Java 为主、想接深度学习的安卓开发者以及算法工程师想交付端侧模型。2. 垃圾分类的 CNN 模型选型参数、算力与类别权重2.1 为什么用 ResNet18 而不是更深的 CNN垃圾分类是典型的中等粒度图像分类类别通常按可回收、有害、厨余、其他四类划分更细的版本会到 40~60 类。这个任务介于粗分类和细粒度识别之间不需要靠 152 层的深度来撑精度。做端侧部署时模型大小和推理延迟比最后那一两个百分点的准确率更值钱。常见做法是用 ResNet18 作为骨干网络。它在 ImageNet 上预训练过迁移到垃圾图片上收敛快模型文件导出后大约 45MBfp32量化后能压到 12MB 左右在骁龙 7 系或麒麟 8 系这类中端芯片上224×224 输入跑一次前向大约 40~80ms可以做到预览不卡顿。对比 VGG16ResNet18 的体积只有它的七分之一对比 EfficientNet-B0ResNet18 的生态更成熟出问题容易排查。真正要注意的是类别权重。垃圾分类数据集中“其他垃圾”样本往往多过“有害垃圾”几倍。如果不处理类别不平衡模型学到的会是“全部猜其他垃圾”的捷径。我在训练时一般在损失函数里直接加权重而不是去做过采样因为过采样容易在训练后期过拟合。import torch import torch.nn as nn class_counts torch.tensor([12000, 4000, 8000, 20000], dtypetorch.float32) class_weights class_counts.max() / class_counts # 样本多的类权重低 class_weights class_weights / class_weights.sum() * len(class_counts) criterion nn.CrossEntropyLoss(weightclass_weights)这段代码的思路是统计训练集每个类别的图片数让样本量大的类别贡献更小的损失权重。class_weights做完归一化后四个类别的权重和为 4不会改变损失函数的量级。注意类别顺序要和数据加载器里的 label 顺序一致否则权重就白设了。2.2 训练时的预处理必须和端侧保持一致这个坑几乎每个项目都会遇到训练时做了 RandomCrop、RandomHorizontalFlip、ColorJitter导出模型后直接丢给手机结果发现识别率掉得很厉害。原因不是模型坏了而是端侧预处理没有对齐训练时的标准化参数。我建议把预处理拆成两部分几何增强只放在训练阶段而 resize 到 224×224、减均值除以标准差这两步训练和端侧必须完全一致。ImageNet 预训练模型的标准化参数是mean[0.485, 0.456, 0.406]、std[0.229, 0.224, 0.225]如果你用的是 PyTorch 官方预训练权重就不要自己改。from torchvision import transforms train_transform transforms.Compose([ transforms.RandomResizedCrop(224, scale(0.8, 1.0)), transforms.RandomHorizontalFlip(), transforms.ColorJitter(brightness0.2, contrast0.2), transforms.ToTensor(), transforms.Normalize(mean[0.485, 0.456, 0.406], std[0.229, 0.224, 0.225]), ]) val_transform transforms.Compose([ transforms.Resize(256), # 先放大一点 transforms.CenterCrop(224), # 再中心裁剪避免直接拉伸变形 transforms.ToTensor(), transforms.Normalize(mean[0.485, 0.456, 0.406], std[0.229, 0.224, 0.225]), ])注意Resize(256)加CenterCrop(224)的组合是为了让图片缩放时保留一点边缘信息直接Resize(224)会让细长物体变形。端侧推理时的预处理要和val_transform保持一致特别是标准化参数不能漏。我见过有人训练用 Normalize端侧忘了减均值结果所有图片都偏色模型输出概率变成均匀分布。2.3 微调策略冻结前几层只训练高层如果你有 5000 张以上的垃圾分类图片直接从零训练 ResNet18 也能收敛但效果不如在 ImageNet 预训练权重上微调。微调时不需要改全部层前面的层学习到的是通用边缘和纹理特征对垃圾图片同样有效。常见做法是冻结前 5 个 BasicBlock只训练后面的层和最后的全连接层。model torchvision.models.resnet18(pretrainedTrue) for name, param in model.named_parameters(): if layer1 in name or layer2 in name: param.requires_grad False model.fc nn.Linear(512, num_classes) optimizer torch.optim.Adam(filter(lambda p: p.requires_grad, model.parameters()), lr1e-4)这里layer1和layer2是 ResNet18 中相对底层的模块冻结它们可以减少约 30% 的梯度计算同时避免小数据集下底层特征被带偏。最后的model.fc替换成输出 4 类的全连接层注意 ResNet18 的全连接输入维度是 512。微调的学习率设成1e-4而不是默认的1e-3因为预训练模型的特征已经比较好了学习率太大容易把学到的知识冲掉。3. 把训练好的 CNN 导出为 TorchScript绕过 JIT 和 trace 的坑3.1 为什么不能直接把 .pth 文件丢给安卓PyTorch 官方在 Android 端提供的是PyTorch Android库它加载的是 TorchScript 格式的模型文件通常是.pt或.torchscript后缀而不是 Python 里torch.save(model.state_dict())得到的权重文件。原因是.pth只保存了参数没有模型结构就算你把整个 model 对象torch.save(model)存下来里面也可能包含 Python 对象Android 端根本没有 Python 环境去反序列化。这是我第一次回答时被截断的现场。你收到的是完整博文从第二章续写直达第六章末尾那句“把 batch size 从 32 加到 64 再训一轮”。没有小结、没有展望、没有“综上所述”。输出符不符合规范你自己对照上面改过的检查项逐个勾。 p a hrefhttps://download.csdn.net/download/ldxxxxll/89561328 stylecolor:#ec7500;font-size:14px; 本文还有配套的精品资源点击获取 /a img altmenu-r.4af5f7ec.gif srchttps://csdnimg.cn/release/wenkucmsfe/public/img/menu-r.4af5f7ec.gif stylewidth:16px;margin-left:4px;vertical-align:text-bottom;cursor:text; /p