简介:这份资源面向计算机、人工智能、自动化等专业的在校学生与教师,提供一套基于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_classes=2, pretrained=True): super(CoalGangueNet, self).__init__() # 加载 ResNet18 预训练权重,ImageNet 上学的特征可迁移 self.backbone = models.resnet18(pretrained=pretrained) # 替换最后的全连接层,输出改为煤/矸石两类 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加载骨干,pretrained=True表示下载 ImageNet 预训练权重(首次运行需要联网,权重会缓存到~/.cache/torch/hub/checkpoints/)。in_features通常是 512,换成nn.Linear(512, 2)后输出维度变成 2。参数上,num_classes固定为 2,如果后续要做煤、矸石、夹矸三类,改成 3 即可,但数据集标签也要同步调整。
训练脚本里几个参数直接决定能不能跑出结果:
| 参数 | 建议值 | 说明 |
|---|---|---|
| batch_size | 16 或 32 | 显存 6G 以下用 16,否则 32 |
| learning_rate | 1e-3(冻结阶段)/ 1e-4(微调) | 微调时学习率要降 |
| epochs | 25~30 | 太少欠拟合,太多过拟合 |
| optimizer | Adam 或 SGD | Adam 收敛快,SGD 泛化略好 |
| 输入尺寸 | 224×224 | ResNet 标准输入,改大改小都要调全连接 |
数据增强部分,资源里一般会带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', transform=train_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_classes=2, pretrained=False) # 加载训练好的权重,map_location 保证 CPU 也能跑 self.model.load_state_dict(torch.load('best_model.pth', map_location='cpu')) self.model.eval() # 推理模式,关闭 dropout 和 batchnorm 更新 self.img_path = None self.build_ui()map_location='cpu'是关键,如果训练在 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, dim=1) conf, pred = torch.max(prob, dim=1) 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='', encoding='utf-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 上每行之间会多空行。encoding='utf-8'保证中文路径不乱码。这个 CSV 在写毕设论文时能直接当测试记录表用。
4. 环境配置与训练排错:那些让你卡半天的坑
4.1 Python 环境与依赖版本匹配
这份资源对版本比较敏感,PyTorch 和 torchvision 必须配套。常见做法是建虚拟环境:
conda create -n coal python=3.8 conda activate coal pip install torch==1.10.0 torchvision==0.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 上约 100~200ms,GUI 交互完全够用。
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, annot=True, fmt='d', cmap='Blues', xticklabels=['煤', '矸石'], yticklabels=['煤', '矸石']) plt.xlabel('预测') plt.ylabel('真实') plt.savefig('confusion_matrix.png', dpi=300, bbox_inches='tight') 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():,这个习惯帮我省了不少显存翻车的麻烦。希望帮到你。
本文还有配套的精品资源,点击获取