恒美微站
首页
关于我们
建站服务
主题模板
案例展示
资讯中心
联系我们
Python机器学习课设:TensorFlow MobileNet垃圾分类系统实战解析
首页
资讯中心
/
Python机器学习课设:TensorFlow MobileNet垃圾分类系统实战解析
Python机器学习课设:TensorFlow MobileNet垃圾分类系统实战解析
发布时间:2026/10/14 1:27:47
简介面向机器学习课程设计或毕业设计的完整Python垃圾分类系统源码包适合掌握Python基础、希望将理论用于图像分类实战的高校学生和开发者能够解决从数据集处理、模型训练到结果展示全流程的参考需求。压缩包共32个文件、约2.26MB包含4个Python脚本分别对应模型训练、测试评估与矩阵分析另有9张jpg与8张jpeg原始图像、4个xml标注文件、4张png结果图以及一份Excel评估表同时兼顾代码、数据与可视化输出。目前已有772人学习在同类课程设计资源中具有较高参考热度。项目基于TensorFlow 2.3与MobileNet迁移学习覆盖图像预处理、特征提取、监督学习模型训练、召回率与F1分数评估、混淆矩阵可视化等关键步骤并附带可运行的图形界面演示方便直接体验分类结果。通过源码可直观掌握sklearn主成分分析、交叉验证与超参数调整的落地方式为完成课程设计报告、答辩演示或进一步扩展至深度学习提供直接支撑。1. 开箱Python机器学习课设包垃圾分类系统的构成与复现前提拿到《机器学习课程设计Python垃圾分类系统源码》这份压缩包时我习惯先列一遍文件再解压因为这类课设包最大的变数往往不在算法而在能不能一次跑通。它是一套基于 TensorFlow 2.3 和 MobileNet 的图像分类工程训练脚本、评估脚本、桌面窗口三条线都在非常适合作为机器学习课程设计的对标项目或入门练手。但想真正复现得先把迁移学习选型、数据目录约定、混淆矩阵验收这三件事串起来。下面按我拆包时的顺序从文件结构一路讲到参数、踩坑和界面接入。2. 看清源码包结构从文件命名反推完整流水线2.1 顶层文件命名先拆出训练、评估、界面三条主线解压后通常能看到两个目录一个是machine-learning-master另一个是trash_classification_tf2.3-master。前者是常见仓库下载时的外层壳后者才是真正的工程目录名字里的tf2.3直接点明了框架版本。我一般先把后者完整列一遍trash_classification_tf2.3-master ├── train_mobilenet.py # 训练入口MobileNet 迁移学习50轮 ├── test_model.py # 单张图片预测脚本 ├── window_trash.py # 桌面窗口程序PyQt5 ├── matrix.py # 混淆矩阵生成 matrix.xls 导出 ├── results_epoch50.png # 训练50轮的结果图loss/acc曲线 ├── matrix.xls # 混淆矩阵表格 ├── images/ # 图片数据集或测试图目录 ├── .keep # git空目录占位文件从这几个文件名就能反推完整流程train_mobilenet.py负责训练并在最后输出模型test_model.py负责拿单张图片验证模型matrix.py对全部测试图片做批量预测并生成混淆矩阵window_trash.py把模型封装成桌面窗口。results_epoch50.png和matrix.xls都是训练与评估的产物说明这个包默认跑完过 50 轮并且保留了一份可视化结果。提示这类压缩包通常不附带requirements.txt环境要自己补。建议先建虚拟环境再锁版本具体版本写在第 5 章避坑清单里。2.2 images 目录垃圾分类数据集的摆放约定图像分类项目里数据目录按类别分子文件夹是最常见的约定。训练代码通过子目录名得到标签所以images/下一般是这样组织的images/ paper/ # 纸张 plastic/ # 塑料 glass/ # 玻璃 metal/ # 金属 kitchen/ # 厨余垃圾 other/ # 其他train_mobilenet.py里通常用flow_from_directory或image_dataset_from_directory读取这个目录类名由子文件夹名自动生成。也就是说你的images/放错层级类别映射就会整个错位。我看这个包的时候发现它带有.keep占位文件说明images/原本很可能只有目录骨架或少量样板图真实数据集需要自己按上面的结构补进去。这一点不处理好后面所有精度数字都是假的后面避坑章会详细讲。2.3 两个 master 目录怎么取舍版本差异与占位文件碰到双层目录时先看哪一层有train_mobilenet.py真正能跑的是这一层。machine-learning-master如果只有 README 或空壳就把它当作下载残留直接忽略即可。还有一点容易忽略.keep是 git 里的空目录占位文件说明原工程上images/或某个输出目录在仓库里是空的模型保存目录通常也要自己建。把这份源码包迁移到自己课程设计里时我一般这样做把trash_classification_tf2.3-master整体复制到新工程根目录建一个干净的虚拟环境然后把代码里写死的图片路径和输出路径统一改成相对路径。注意检查一个坑matrix.py里如果写死了images/test/这种路径而你只放了images/运行时会直接找不到文件。3. 训练MobileNet分类器数据摆放、关键参数与50轮调参思路3.1 为什么选 MobileNet 而不是从零训练 CNN课程设计的数据量通常不大垃圾图片可能每类只有几百张。从零训练一个 CNN 在这种情况下非常容易过拟合训练集准确率很快冲到 0.98验证集却在 0.7 附近震荡。MobileNet 是 ImageNet 预训练的特征提取器它在通用图像特征上已经有了很强的先验垃圾的纹理、边缘、颜色这些中低层特征可以直接复用我们只需要在它后面接一个小的分类头用少量数据和较少轮数就能拿到可接受的精度。TF2.3 中直接调用tensorflow.keras.applications.MobileNet即可include_topFalse表示去掉原有 1000 类分类头只保留卷积特征部分。相比 SVM、KNN 这类传统方法迁移学习对图像这类高维非结构化数据的拟合能力更强而相比自己写 ResNetMobileNet 参数少CPU 也能勉强跑完 50 轮训练。3.2 train_mobilenet.py 的代码走读与参数表这个脚本的核心逻辑可以归纳成下面这段典型写法from tensorflow.keras.applications import MobileNet from tensorflow.keras import layers, models from tensorflow.keras.preprocessing.image import ImageDataGenerator IMG_SIZE (224, 224) BATCH_SIZE 32 train_datagen ImageDataGenerator( rescale1.0 / 255.0, rotation_range20, width_shift_range0.2, height_shift_range0.2, horizontal_flipTrue, validation_split0.2, ) train_gen train_datagen.flow_from_directory( images/, target_sizeIMG_SIZE, batch_sizeBATCH_SIZE, subsettraining, shuffleTrue, ) base_model MobileNet( input_shape(IMG_SIZE[0], IMG_SIZE[1], 3), include_topFalse, weightsimagenet, ) base_model.trainable False model models.Sequential([ base_model, layers.GlobalAveragePooling2D(), layers.Dropout(0.5), layers.Dense(len(train_gen.class_indices), activationsoftmax), ]) model.compile(optimizeradam, losscategorical_crossentropy, metrics[accuracy])这个片段里几个参数值得注意。rescale1.0/255.0把像素归一化到 0~1MobileNet 的预训练权重就是在这个量级下学的rotation_range、width_shift_range、horizontal_flip是数据增强目的是减少过拟合。validation_split0.2表示从数据里切出 20% 做验证集两个subsettraining和验证集的 generator 要配对使用漏掉subsetvalidation就会报ValueError。最关键的一行是base_model.trainable False。迁移学习第一阶段只训练后面新增的Dense分类头卷积部分权重冻结不动。如果训练完精度不满意再把base_model.trainable True解冻最后几十层做微调学习率要降到 1e-4 左右。参数约定可以整理成下面这张表参数值影响IMG_SIZE(224, 224)MobileNet 标准输入尺寸太大显存吃紧太小丢纹理BATCH_SIZE32常规值数据量小时建议降到 16epochs50迁移学习第一阶段默认轮数optimizeradam默认 lr1e-3微调阶段改 1e-4/1e-5Dropout0.5分类头防过拟合validation_split0.2没有独立 val 目录时的切分比例results_epoch50.png的存在说明这份源码按默认参数跑过完整 50 轮。如果你机器比较慢先用 10~15 轮确认流程全通再续跑 50 轮别一上来就全量训练。3.3 训练过程监控从结果图里看三点跑完 50 轮后results_epoch50.png会包含训练/验证的 loss 和 accuracy 两组曲线。看这个图我一般只盯三点验证精度是否还在上升、验证 loss 有没有从某个 epoch 开始掉头向上、训练精度是不是已经贴到 1.0。前两点是过拟合信号最后一点说明模型容量已经足够大再训也不会有实质提升。常见做法是给训练脚本补两个回调from tensorflow.keras.callbacks import EarlyStopping, ReduceLROnPlateau early EarlyStopping(monitorval_loss, patience5, restore_best_weightsTrue) lr_sched ReduceLROnPlateau(monitorval_loss, factor0.5, patience3, min_lr1e-6) model.fit( train_gen, validation_datavalid_gen, epochs50, callbacks[early, lr_sched], )EarlyStopping的patience5表示验证 loss 连续 5 轮不改善就停restore_best_weightsTrue会自动回滚到验证集上最好的那版权重相当于买了后悔药。ReduceLROnPlateau在 loss 停滞时把学习率减半避免后期在原地打转。加上这两个回调50 轮可能实际 30 轮就停了效果通常比硬跑满 50 轮更好。4. 评估与验收混淆矩阵读出四类典型误判4.1 matrix.py 在做什么批量预测并生成 matrix.xlsmatrix.py做的事情可以理解为遍历测试图片对每张图调用训练好的模型做预测收集真实标签和预测标签然后用sklearn.metrics.confusion_matrix生成混淆矩阵。核心逻辑是这样的import numpy as np import pandas as pd from sklearn.metrics import confusion_matrix, classification_report cm confusion_matrix(y_true, y_pred, labelsclass_names) report classification_report(y_true, y_pred, labelsclass_names, output_dictTrue) pd.DataFrame(cm, indexclass_names, columnsclass_names).to_excel(matrix.xls) pd.DataFrame(report).T.to_excel(matrix_report.xls)这里有两个容易被忽略的参数。labelsclass_names必须显式传入否则confusion_matrix会按字母顺序排类和训练时的类别顺序对不上output_dictTrue则让分类报告变成结构化字典方便直接写进 Excel。为什么要把结果落到matrix.xls里课程设计答辩时给老师看一张彩色混淆矩阵图加一张 Excel 表比只报一个准确率数字有说服力得多出问题时也更容易定位到具体类别。4.2 混淆矩阵里最常出现的四类误判垃圾图像分类的混淆矩阵里误判通常集中在视觉相似的类型上。第一类是塑料瓶和玻璃瓶两者都是透明或半透明圆柱体颜色直方图和形状特征高度重合模型经常把玻璃瓶判成塑料瓶。第二类是纸类内部的细分比如报纸和纸板纹理和颜色都接近边界基本靠揉搓后的褶皱形态区分二维图像里很难抓住。第三类是厨余垃圾和沾油污的一次性餐具真实场景中塑料餐盒混着剩菜标签本身都可能标错。第四类是高反光的金属罐与银色包装袋反光区域让卷积特征出现类似的强边缘。看混淆矩阵时不要只看整体准确率而要看矩阵的off-diagonal值也就是预测错的格子集中在哪个类别。如果某两类互相混淆严重先回去检查images/下这两类图片的标签质量而不是急着改网络结构。标签噪声在爬虫数据里非常常见这个问题比模型容量更隐蔽。4.3 三个指标准确率、召回率、F1 怎么对照验收课程设计评估阶段常用的三个指标各有用途。准确率是全部预测里正确的占比适合整体概览召回率是某类真实样本里被正确找出来的比例数据不均衡时靠它发现问题F1 是精确率和召回率的调和平均对某类综合表现给一个分数。整理成表更直观指标含义在垃圾分类里的意义准确率全部预测中正确的比例整体是否可用召回率该类实际样本中被正确识别的比例某类是否被系统性漏掉F1精确率与召回率的调和平均对低召回率类给出综合评价我拿到matrix.xls后习惯先按行找召回率最低的类别。如果某一类召回率比其他类低 15 个百分点以上第一件事是回去数一下该类的样本量。样本少于 50 张的类别训练时很难学到稳定特征这时候不是调模型而是补数据。另一个常见做法是把classification_report输出到另一张表每类一行方便写进课程设计报告。5. 避坑排查TensorFlow 2.3 环境与界面调用的五个高频问题这个包要完整复现我的建议顺序是环境 -train_mobilenet.py-test_model.py-matrix.py-window_trash.py。五个环节最容易翻车每条都按现象、原因、解决来写。5.1 现象1TensorFlow 装好后 import 直接报错现象按代码里的import tensorflow.keras运行提示module tensorflow has no attribute keras或类似错误。原因pip默认装的是比 2.3 新得多的版本新版 TensorFlow 把 Keras 接口拆到了独立的tf_keras包里老代码不再直接兼容。解决锁版本安装固定成 TF2.3python -m venv venv_trash source venv_trash/bin/activate # Windows: venv_trash\Scripts\activate pip install tensorflow2.3.0 numpy pandas matplotlib opencv-python scikit-learn xlwt PyQt5这个包基于 tf2.3 写的锁版本最省事。注意一点如果你机器没有 NVIDIA 显卡或不想配 CUDA就装tensorflow-cpu2.3.0否则 TF2.3 的 GPU 版会对 CUDA 10.1 和 cuDNN 7.6 严格匹配版本不对会在训练第一行就报底层库错误。5.2 现象2训练时报 labels 维度不匹配现象model.fit刚开始报错内容是labels的形状与categorical_crossentropy不匹配或者在Dense层输出维度上直接对不上。原因最常见的是Dense(num_classes)里的num_classes写死了而实际images/下的子目录数量和类别数与写死的值不一致。解决训练脚本里用代码动态获取类别数并在编译前打出来确认num_classes len(train_gen.class_indices) print(classes:, train_gen.class_indices) assert num_classes 1, images/ 下至少需要两个类别子目录class_indices这个字典就是训练时类别名到数字编号的映射务必在训练时打印并保存下来后面测试和界面都要复用它。5.3 现象3验证精度挺高但window_trash.py一张图都测不对现象训练阶段明明显示验证精度 0.9但把同一张图丢进窗口程序预测结果完全不对而且是固定的某个类。原因类别映射不一致。训练时class_indices是按flow_from_directory遍历目录顺序生成的而测试脚本里往往硬编码了一个class_names [glass, metal, ...]两者顺序一旦错位所有预测结果都偏到别的类上。解决训练完把类别顺序落盘成一个 JSON训练、评估、界面通用同一个文件import json with open(classes.json, w, encodingutf-8) as f: json.dump(list(train_gen.class_indices.keys()), f, ensure_asciiFalse)测试脚本里读取这个文件而不是手写列表。这一步能避免大量错位问题属于课设工程里最容易忽略的隐性问题。5.4 现象4中文路径和中文标签导致读图失败现象images/下用了中文子目录名OpenCV的imread返回None或者matplotlib画混淆矩阵时中文标签显示成方块。原因OpenCV 在 Windows 下对中文路径支持差cv2.imread拿到中文路径直接失败matplotlib 默认字体不含中文字符。解决一是目录和标签统一用英文二是界面代码里绕开原生imread改用numpy读字节再解码import cv2 import numpy as np data np.fromfile(img_path, dtypenp.uint8) img cv2.imdecode(data, cv2.IMREAD_COLOR)np.fromfile按二进制读入文件cv2.imdecode再从内存解码中文路径问题就绕过去了。这个技巧在 PyQt5 界面里几乎必用。5.5 现象5点击“识别”按钮后界面卡死或白屏现象窗口能打开但点按钮后整个窗口无响应过一会儿弹“未响应”或者图片不显示。原因PyQt5 的主线程里直接跑了model.predict()推理阻塞了事件循环还有一种情况是按钮回调里load_model路径写错模型没加载成功但异常被吞了。解决先用test_model.py单独验证模型路径和推理结果确认没问题再接界面。界面侧把推理放到子线程from PyQt5.QtCore import QThread, pyqtSignal class PredictThread(QThread): done pyqtSignal(str) def __init__(self, model, img_path): super().__init__() self.model model self.img_path img_path def run(self): prob predict(self.model, self.img_path) self.done.emit(f类别{prob[label]}置信度{prob[score]:.2f})注意一个细节模型实例在创建线程时传进去不要在run()里再load_model加载模型本身也很耗时放在子线程里会让“点按钮”和“出结果”之间出现很长时间的假死感。6. 进阶自测把模型接进 PyQt5 界面做端到端验证6.1 先从一条命令行开始test_model.py 改出 top3 输出拿到这份源码我建议第一件事不是打开窗口程序而是先把test_model.py改成能输出 Top3 置信度的版本。这样能从命令行快速确认模型是否真的可用def predict_top3(model, img_path, class_names, top_k3): img load_img(img_path, target_size(224, 224)) arr img_to_array(img) / 255.0 arr np.expand_dims(arr, axis0) pred model.predict(arr, verbose0)[0] idx pred.argsort()[::-1][:top_k] for i in idx: print(f{class_names[i]:12s} {pred[i]:.4f})看输出时重点观察最高置信度。如果某张图的最高分只有 0.35模型实际上是在“猜”这时候就算界面显示了一个类别结果也不可信。我在课设里习惯把 0.5 作为阈值低于这个值就显示“无法判断”这个细节在答辩时很加分。6.2 界面接入的三个固定动作window_trash.py的改造就三步第一步按钮回调里用QFileDialog.getOpenFileName拿到图片路径第二步把路径交给predict_top3函数第三步用 QLabel 显示结果文本用小一点的 QLabel 显示原图缩略图。注意 OpenCV 读出来是 BGR 通道顺序显示到 QLabel 前要先转成 RGB 再转成 QImage否则颜色会整体偏蓝。这个通道顺序问题不解决界面显示出来的垃圾图片颜色会失真影响判断。6.3 留一个冒烟测试脚本最后我建议在这个包里补一个smoke_test.py把“加载模型 - 读测试图 - top3 输出 - 断言最高置信度大于阈值”串起来跑一遍。每次改完代码后执行一次就能确认流水线还通着不用反复开窗口点按钮。这套源码包做课程设计足够扎实训练、评估、界面三条线完整需要时直接下载后按上面的顺序对照复现。从那以后我每次拿到课设包都强制走一遍“单测脚本 - 界面回调 - 真实图片验证”的顺序再回去调参数白屏和错标签的返工确实少了很多。希望帮到你。本文还有配套的精品资源点击获取