
简介这份资源面向计算机、人工智能、自动化等专业的在校学生与教师提供一套基于ResNet卷积神经网络的煤矸石识别分类系统完整Python实现可用于毕业设计、课程设计或项目立项演示。压缩包共45个文件约4.37MB包含11个py源码、10个csv数据文件、7张jpg样本图、4个ipynb实验笔记及若干模型与缓存文件覆盖图像预处理、GLCM特征提取、图像分割、CNN与VGG16对比实验等模块并配有GUI界面与训练好的模型。资源已通过测试运行附带数据集与操作教程已有182人学习下载。读者可据此掌握从数据增强、特征工程到ResNet分类的完整流程理解煤矸石识别的建模思路与调参方法也可在现有代码基础上修改扩展快速完成自己的课题或作业。1. 煤矸石识别分类系统一份能跑通的 ResNet GUI 毕设资源选煤厂里分拣煤和矸石过去靠老师傅看颜色、听声音、掂重量一个班下来眼睛都花了误判率还不稳定。这份资源干的事很直接用 ResNet 卷积神经网络做煤矸石图像二分类配一个能点按钮的 GUI 界面把数据集、训练好的模型权重、操作教程一起打包。对正在做深度学习方向毕业设计的人来说它解决的是从零搭环境到出可视化结果这条链路上最耗时的部分——不用自己找煤矸石图片、不用从零写训练脚本、不用纠结 PyTorch 还是 TensorFlow。适合有 Python 基础、学过卷积神经网络原理但没完整跑过一个图像分类项目的人也适合想快速验证 ResNet 在自己数据上表现的熟手。下面按资源是什么、怎么用、坑在哪的顺序拆开讲。2. ResNet 做煤矸石分类为什么选它、网络怎么改2.1 煤矸石图像分类的任务特点与 ResNet 的适配理由煤矸石识别本质是图像二分类问题输入是传送带或现场拍摄的矿石图像输出是煤或矸石两个类别。这个任务有几个特点类间差异主要体现在颜色深浅、纹理粗糙度、反光程度上类内差异反而可能更大——同一类煤块状和粉末状在图像上差别不小。传统 CNN 堆到十几层就会出现梯度消失训练集准确率上不去而 ResNet 的残差连接让梯度能跨层回传这是它比普通卷积网络更适合这类任务的核心原因。常见做法是用 ResNet18 或 ResNet34 做骨干把最后的全连接层输出改成 2 类。ResNet18 参数量约 1100 万在几千张煤矸石图像上训练不容易过拟合推理速度也够 GUI 实时调用。如果数据集上万张、类别更细可以换 ResNet50但毕设场景下 ResNet18 的性价比最高。资源里给的预训练权重是基于 ImageNet 的迁移学习能显著减少训练轮数——我一般会先冻结骨干只训分类头 5 个 epoch再解冻全部微调 20 个 epoch这样比从头训收敛快得多。2.2 网络结构改造与训练脚本关键参数拿到源码后第一件事是确认骨干网络和分类头的衔接方式。资源里的模型定义通常长这样import torch import torch.nn as nn from torchvision import models class CoalGangueNet(nn.Module): def __init__(self, num_classes2, pretrainedTrue): super(CoalGangueNet, self).__init__() # 加载 ResNet18 预训练权重ImageNet 上学的特征可迁移 self.backbone models.resnet18(pretrainedpretrained) # 替换最后的全连接层输出改为煤/矸石两类 in_features self.backbone.fc.in_features self.backbone.fc nn.Linear(in_features, num_classes) def forward(self, x): return self.backbone(x)这段代码的逻辑是用models.resnet18加载骨干pretrainedTrue表示下载 ImageNet 预训练权重首次运行需要联网权重会缓存到~/.cache/torch/hub/checkpoints/。in_features通常是 512换成nn.Linear(512, 2)后输出维度变成 2。参数上num_classes固定为 2如果后续要做煤、矸石、夹矸三类改成 3 即可但数据集标签也要同步调整。训练脚本里几个参数直接决定能不能跑出结果参数建议值说明batch_size16 或 32显存 6G 以下用 16否则 32learning_rate1e-3冻结阶段/ 1e-4微调微调时学习率要降epochs2530太少欠拟合太多过拟合optimizerAdam 或 SGDAdam 收敛快SGD 泛化略好输入尺寸224×224ResNet 标准输入改大改小都要调全连接数据增强部分资源里一般会带RandomHorizontalFlip、RandomRotation(10)、ColorJitter。煤矸石图像里颜色是重要特征ColorJitter的亮度、对比度扰动幅度别开太大否则会把煤和矸石的颜色差异抹掉反而掉点。我一般把brightness和contrast控制在 0.2 以内。2.3 数据集组织与标签映射数据集目录结构通常是train/coal、train/gangue、val/coal、val/gangue这种 ImageFolder 格式。加载时用from torchvision import datasets, transforms train_transform transforms.Compose([ transforms.Resize((224, 224)), transforms.RandomHorizontalFlip(), transforms.RandomRotation(10), transforms.ToTensor(), transforms.Normalize(mean[0.485, 0.456, 0.406], std[0.229, 0.224, 0.225]) ]) train_dataset datasets.ImageFolder(data/train, transformtrain_transform) # 类别到索引的映射{coal: 0, gangue: 1}顺序按文件夹名字母序 print(train_dataset.class_to_idx)Normalize里的均值和方差是 ImageNet 的统计值用预训练权重时保持一致不要自己算。class_to_idx打印出来确认标签顺序GUI 里显示结果时要按这个映射反查否则会出现模型说 0界面显示矸石这种低级错误。验证集和测试集的 transform 只保留Resize、ToTensor、Normalize不要加随机增强。3. GUI 界面与推理流程从模型文件到可点击按钮3.1 GUI 框架选型与界面布局资源里的 GUI 大概率用 Tkinter 或 PyQt5。Tkinter 是 Python 自带不用额外装包适合毕设演示PyQt5 界面更现代但打包时体积大。判断方法很简单看源码开头import tkinter还是from PyQt5.QtWidgets import。Tkinter 版本的典型布局是左边一个选择图片按钮加图片预览区右边显示识别结果和置信度底部一个开始识别按钮。界面初始化时要加载模型不要每次点识别都重新加载import tkinter as tk from tkinter import filedialog from PIL import Image, ImageTk import torch class App: def __init__(self, root): self.root root self.root.title(煤矸石识别系统) self.model CoalGangueNet(num_classes2, pretrainedFalse) # 加载训练好的权重map_location 保证 CPU 也能跑 self.model.load_state_dict(torch.load(best_model.pth, map_locationcpu)) self.model.eval() # 推理模式关闭 dropout 和 batchnorm 更新 self.img_path None self.build_ui()map_locationcpu是关键如果训练在 GPU 上、演示机器没显卡不加这个参数会报RuntimeError: Attempting to deserialize object on a CUDA device。model.eval()也必须调否则 BatchNorm 层会用当前 batch 的统计量单张图片推理时结果会飘。3.2 图片预处理与推理函数GUI 里选完图片后要做的预处理必须和验证集完全一致def predict(self, img_path): transform transforms.Compose([ transforms.Resize((224, 224)), transforms.ToTensor(), transforms.Normalize(mean[0.485, 0.456, 0.406], std[0.229, 0.224, 0.225]) ]) img Image.open(img_path).convert(RGB) # 防止灰度图或 RGBA 报错 tensor transform(img).unsqueeze(0) # 增加 batch 维度 with torch.no_grad(): # 关闭梯度计算省显存 output self.model(tensor) prob torch.softmax(output, dim1) conf, pred torch.max(prob, dim1) label 煤 if pred.item() 0 else 矸石 return label, conf.item()convert(RGB)这行血泪经验现场拍的图可能是灰度图或带透明通道的 PNG直接ToTensor会得到 1 通道或 4 通道送进 ResNet 第一层就报维度错误。unsqueeze(0)把[3,224,224]变成[1,3,224,224]因为模型 forward 要求有 batch 维度。torch.no_grad()在 GUI 推理时必加不然每次点按钮都建计算图内存越用越多。3.3 置信度显示与结果落盘界面上除了显示煤/矸石建议把置信度也打出来比如矸石 97.3%。置信度低于 70% 时可以标黄提示结果存疑这在答辩演示时是个加分项。结果落盘用 CSV 追加import csv, datetime def save_result(self, img_path, label, conf): with open(results.csv, a, newline, encodingutf-8) as f: writer csv.writer(f) writer.writerow([datetime.datetime.now().strftime(%Y-%m-%d %H:%M:%S), img_path, label, f{conf:.4f}])newline不加的话 Windows 上每行之间会多空行。encodingutf-8保证中文路径不乱码。这个 CSV 在写毕设论文时能直接当测试记录表用。4. 环境配置与训练排错那些让你卡半天的坑4.1 Python 环境与依赖版本匹配这份资源对版本比较敏感PyTorch 和 torchvision 必须配套。常见做法是建虚拟环境conda create -n coal python3.8 conda activate coal pip install torch1.10.0 torchvision0.11.0 -f https://download.pytorch.org/whl/torch_stable.html pip install pillow numpy matplotlib opencv-pythonPython 3.8 是兼容性最好的版本3.10 以上有些旧版 torchvision 装不上。-f后面跟的地址指定 CUDA 版本对应的 wheel如果机器没显卡就装 CPU 版。装完用python -c import torch; print(torch.__version__, torch.cuda.is_available())验证输出True说明 GPU 可用。VSCode 里配置解释器时选这个虚拟环境的python.exe别选系统默认的。4.2 训练不收敛的排查顺序训练 loss 不降或准确率卡在 50%按这个顺序查先看数据标签有没有错——用ImageFolder时文件夹名字就是标签如果coal文件夹里混了矸石图模型学出来就是随机猜。再看学习率1e-2 以上容易震荡1e-5 以下收敛极慢。然后确认Normalize的均值和预训练权重是否匹配用错统计值会让输入分布偏移。最后查model.train()和model.eval()有没有在正确的位置调用验证时忘了eval()会导致 BatchNorm 用错统计量准确率虚低。4.3 显存不足与 CPU 推理降级报CUDA out of memory时先把batch_size减半再把输入尺寸从 224 降到 192但全连接层不用改ResNet 的自适应池化会处理。如果还是不够在训练脚本里加torch.cuda.empty_cache()或者用梯度累积模拟大 batch。演示机器没显卡时把模型和输入都.to(cpu)ResNet18 单张推理在 CPU 上约 100200msGUI 交互完全够用。5. 避坑与常见问题五条真实翻车记录现象训练准确率 99%测试准确率 60%。原因训练集和测试集图片来自同一批连续拍摄相似度太高模型记住了背景而不是煤矸石特征。 解决按拍摄批次或时间段划分数据集确保测试集里有训练时没见过的背景和光照条件。现象GUI 点识别没反应控制台也不报错。原因按钮的command绑定的函数忘了加self或者图片路径是中文导致Image.open静默失败。 解决检查函数定义def predict(self):路径用os.path.abspath转一下中文路径在 Windows 上建议先复制到临时英文目录。现象torch.load报UnpicklingError或KeyError。原因保存模型时用了torch.save(model, path)保存整个对象加载环境类定义变了就失败。 解决统一用torch.save(model.state_dict(), path)只存权重加载时先实例化模型再load_state_dict。现象验证集 loss 比训练集还低。原因验证集没加数据增强且 BatchNorm 在eval()模式下用滑动平均统计量而训练初期滑动平均还没稳定。 解决这是正常现象继续训几个 epoch 会回归如果一直如此检查验证集是不是太小。现象打包成 exe 后闪退。原因PyInstaller 没把 torchvision 的权重文件或 PIL 的依赖打进去。 解决用--add-data把模型文件和必要资源加进去或者改用--onedir模式方便看报错。6. 进阶技巧用混淆矩阵和置信度阈值把毕设做扎实基础流程跑通后想让毕设答辩更有说服力加两样东西混淆矩阵和置信度阈值分析。混淆矩阵能直观看出模型把多少煤误判成矸石、多少矸石误判成煤这比一个总准确率有说服力得多。用 sklearn 几行就能出from sklearn.metrics import confusion_matrix, classification_report import seaborn as sns import matplotlib.pyplot as plt # y_true 和 y_pred 是验证集上的真实标签和预测标签列表 cm confusion_matrix(y_true, y_pred) sns.heatmap(cm, annotTrue, fmtd, cmapBlues, xticklabels[煤, 矸石], yticklabels[煤, 矸石]) plt.xlabel(预测) plt.ylabel(真实) plt.savefig(confusion_matrix.png, dpi300, bbox_inchestight) print(classification_report(y_true, y_pred, target_names[煤, 矸石]))classification_report会输出每类的 precision、recall、f1-score。煤矸石分选场景里recall 比 precision 更重要——漏判一个矸石混进煤里后续燃烧效率下降把煤误判成矸石只是浪费一点好煤。所以看报告时重点盯矸石类的 recall如果低于 0.9就调低判为矸石的置信度阈值。置信度阈值怎么调在验证集上跑一遍把每张图的矸石概率和真实标签存下来画一条阈值-召回率曲线。我一般会写个小脚本遍历 0.3 到 0.9 的阈值找矸石 recall 达到 0.95 时对应的最低阈值把这个值写进 GUI 的判定逻辑里。这样模型输出概率后不是简单取 argmax而是矸石概率 阈值就判矸石否则判煤。这个改动很小但在答辩时能讲出针对分选场景做了代价敏感决策的亮点。还有一个容易被忽略的点测试时用torch.no_grad()包住整个验证循环别只在单张推理时加。验证集几百张图不关梯度会白白占显存batch_size 被迫调小评估速度也慢。从那以后我每次写验证循环第一行就是with torch.no_grad():这个习惯帮我省了不少显存翻车的麻烦。希望帮到你。本文还有配套的精品资源点击获取