
简介这是一份面向计算机视觉与工业质检场景的毕业设计项目资源适合有Python基础的本科生或研究生完成缺陷检测课程设计使用。资源围绕深度学习检测流程展开包含数据划分列表、ResNet与SE-ResNet模型定义、训练与评估脚本以及配置说明代码注释完整新手也能读懂关键环节。压缩包共计12个文件其中7个Python文件承担数据加载、模型构建和训练主逻辑3个txt文件存储训练集与验证集划分信息另有shell脚本辅助生成列表Markdown文档补充使用说明整体仅556KB轻量易部署。当前已有193人学习下载。项目整体功能完善从数据准备到训练推理均有覆盖可直接运行并用于毕设答辩演示也可作为深入学习图像分类与缺陷识别的参考基线具有清晰的项目结构和较高的复用价值。1. 工业产品缺陷检测这个 Python 毕设项目到底值不值得动手做工业视觉方向毕设的人十有八九会被“缺陷检测”这四个字卡住课本上讲的是 CNN 原理网上搜到的是目标检测框架真到自己写代码时数据集、训练脚本、模型结构、评估指标每一步都是坑。这份基于深度学习的工业产品缺陷检测 Python 源码属于那种“按下 F5 就能跑”的完整工程模型用的是 ResNet 和 SE-ResNet 这类分类网络配好了数据划分脚本、训练脚本、评估脚本和说明文档适合把毕业设计落在“缺陷识别准确率”而不是“框架调参”上的同学。新手能顺着代码把整套流程跑通熟手能直接拿它当基线模型做消融实验。2. 项目结构与模型选型先把 ResNet 和 SE-ResNet 的账算清楚2.1 文件结构逐个拆每个文件在流水线里干什么拿到压缩包解压后先别急着运行花十分钟把文件职责对一遍。我按训练一条数据的完整链路给你排一下文件/目录职责关键点config.py全局超参数数据路径、类别数、batch size、学习率、模型名dataset.py数据加载读取 list 文件返回图片和标签trainval.txt全量样本清单每行是“图片路径 标签”train.txt/test.txt训练/测试划分从 trainval 里按比例切出来的list.txt类别清单类别名和索引的映射listtxt.sh划分脚本自动生成上面三个 txtmodels/resnet.py标准 ResNet残差结构ImageNet 预训练models/se_resnet.pySE-ResNet在 ResNet 里嵌 SE 注意力模块train.py训练入口加载模型、跑 epoch、存 checkpointeval.py评估入口加载 checkpoint、算准确率README.md使用说明环境、命令、参数说明一眼能看出来的事这个项目是“图像分类”思路不是 YOLO 那种“目标检测”思路。工业缺陷场景里如果每个样本只含一种缺陷、且缺陷区域占比较大分类网络完全够用而且训练稳定、数据需求小、指标好解释——这在毕设答辩里是非常大的优势。2.2 为什么选 ResNet 和 SE-ResNet残差和注意力的互补ResNet 解决的是深层网络退化问题。工业缺陷数据集通常就几千张你不可能真去训一个 152 层的网络但 ResNet50 这种规模配合预训练权重能在小数据上快速收敛。选它当基线属于“怎么解释都站得住”的方案。SE-ResNet 是在 ResNet 的每个残差块里塞了一个 Squeeze-and-Excitation 模块。SE 模块先对特征图做全局平均池化得到每个通道的标量再用两个全连接层算出通道权重最后把权重乘回原特征图。它的核心价值是网络会主动放大“跟缺陷强相关”的通道抑制背景通道。对划痕、脏污这类局部纹理缺陷这个注意力机制很管用而且 SE 模块增加的参数量极小——一个残差块里多两个 FC 层而已。我一般会在毕设里做这样的对比ResNet50 当 baselineSE-ResNet50 当改进点。两份代码都在 models 目录下训练脚本改一个--arch参数就能切换做消融实验非常方便——这事下面细说。2.3 config.py 参数解读训练前必须改的五个字段打开config.py核心参数一般是这些不同版本字段名略有差异但含义一致# config.py 关键参数示例 data_root ./data # 图片根目录 train_list train.txt # 训练集清单 test_list test.txt # 测试集清单 num_classes 2 # 缺陷类别数按实际改 arch se_resnet50 # 模型结构resnet50 / se_resnet50 batch_size 32 # 显存不够就调到 16 epochs 50 # 小数据集 30~50 足够 lr 0.001 # 微调预训练模型常用这个量级这里最容易被忽略的是num_classes。如果你的数据是“正常/划痕/脏污”三类就填 3如果是二分类“良品/缺陷”就填 2。这个数错了模型最后一个全连接层维度就对不上加载预训练权重时会报 mismatch 错误。训练时我建议把momentum保持默认 0.9weight_decay保持 1e-4这两个参数在小数据集上动它反而容易翻车。3. 数据准备与划分list 格式、listtxt.sh 和 dataset.py 怎么配合3.1 先搞懂 list 文件格式路径和标签在一行这个项目的所有 list 文件都是同一套格式每一行由“相对路径 空格 标签索引”组成。比如images/scratch/001.jpg 0 images/scratch/002.jpg 0 images/stain/001.jpg 1标签索引从 0 开始对应list.txt里的类别顺序。这种格式非常老派但很实用——它不依赖文件夹结构你想给某个样本加权、剔除脏数据直接改 txt 文件就行不用动图片目录。3.2 listtxt.sh 怎么用一键生成 trainval、train、testlisttxt.sh是自动生成这些 list 文件的脚本。常见做法是先扫描图片目录生成trainval.txt再按比例切出train.txt和test.txt。核心逻辑大概是这样的#!/bin/bash # 扫描 images 目录下所有 jpg按目录名类别生成 trainval.txt find images -name *.jpg | awk -F / {print $0, $2} trainval.txt # 按 8:2 划分训练集和测试集 awk NR % 5 ! 0 trainval.txt train.txt awk NR % 5 0 trainval.txt test.txt echo 划分完成 wc -l trainval.txt train.txt test.txt逻辑说明find拿到的路径形如images/scratch/001.jpg用/做分隔符后第二个字段就是类别目录名直接当标签用。NR % 5是每隔 5 行取 1 行作为测试集刚好 8:2 划分。参数说明如果你想让测试集是 3:7 比例把NR % 5改成NR % 10然后 7的进 test 即可。注意这种按行抽样的方式在类别不平衡时可能让某个小类在测试集里消失——所以在跑之前先awk {print $2} test.txt | sort | uniq -c看一眼各类别数量。3.3 dataset.py 读取逻辑从 list 到 Tensor 的必经之路dataset.py的核心是继承torch.utils.data.Dataset我读过的多数版本长这样class DefectDataset(Dataset): def __init__(self, list_file, root, transformNone): with open(list_file, r) as f: self.samples [line.strip().split() for line in f if line.strip()] self.root root # 图片根目录 self.transform transform def __len__(self): return len(self.samples) def __getitem__(self, idx): img_path, label self.samples[idx] img Image.open(os.path.join(self.root, img_path)).convert(RGB) if self.transform: img self.transform(img) return img, int(label)逻辑说明__getitem__按索引取一行拆成路径和标签用 PIL 读图转成 RGB 三通道过 transform最后返回(Tensor, label)。这里有个常见的坑有的样本是灰度图convert(RGB)保证所有图都是三通道不会在后面卷积时报“通道数不匹配”。预处理 transform 一般在train.py里定义常见做法是训练时Resize(256)→RandomCrop(224)→RandomHorizontalFlip()→ 归一化测试时只Resize(224)→ 归一化不做随机增强——这一步千万不能省我后面会专门讲。4. 训练与评估train.py 和 eval.py 的完整使用姿势4.1 训练流程从命令行到 checkpoint训练入口是train.py最省事的运行方式python train.py --arch se_resnet50 --batch_size 32 --epochs 50 --lr 0.001如果你改的是config.py也可以直接python train.py。训练脚本内部的核心循环逻辑通常是这样for epoch in range(start_epoch, epochs): model.train() for i, (inputs, labels) in enumerate(train_loader): inputs, labels inputs.to(device), labels.to(device) outputs model(inputs) loss criterion(outputs, labels) optimizer.zero_grad() loss.backward() optimizer.step()这段代码没什么花活但你要注意 train.py 里的两个细节。第一个是criterion默认是CrossEntropyLoss对类别不平衡的数据集可以给它传一个weight张量把少数类的权重调高。第二个是optimizer通常用SGD(momentum0.9)或Adam——微调预训练模型时我习惯用 SGD泛化更稳Adam 在小数据上容易过拟合。训练过程中会按 epoch 打印 loss 和准确率。我评估模型是否健康的标准是前 5 个 epoch loss 要有明显下降20 个 epoch 后训练集准确率要到 95% 以上如果数据不是太离谱的话。如果 loss 一直不降别急着调模型先查数据。训练完会在checkpoints/目录下存.pth文件一般有latest.pth和best.pth两个——best.pth是按验证集准确率保存的最优模型评估和答辩演示都用它。4.2 评估流程准确率、混淆矩阵和每个类别的表现评估入口是eval.py运行方式python eval.py --checkpoint checkpoints/best.pth --test_list test.txt评估脚本会做三件事加载 checkpoint 里的模型权重、跑一遍测试集、按类别输出准确率。常见版本还会生成混淆矩阵用sklearn.metrics.confusion_matrix算出来再存成图片。# eval.py 中的关键片段 model.load_state_dict(torch.load(args.checkpoint)[state_dict]) model.eval() with torch.no_grad(): for inputs, labels in test_loader: outputs model(inputs) _, preds torch.max(outputs, 1) all_preds.extend(preds.cpu().numpy()) all_labels.extend(labels.numpy())这个评估结果的解读比训练准确率重要得多。我见过有人训练集 99%测试集只有 85%这种 gap 十有八九是数据划分出了问题而不是模型不行。评估完一定要看每个类别的召回率——如果“划痕”这一类召回率特别低说明这一类样本太少或特征不明显后面要针对性补数据。4.3 参数调整建议这个小数据集上怎么调才不翻车参数建议值调整方向学习率0.001 起步loss 震荡就降到 0.0001batch_size16~32显存不够优先减这个epochs30~50看验证集是否还在涨输入尺寸224×224缺陷很小时可试 384×384优化器SGD momentum 0.9换 Adam 要降 lr我个人的习惯是先用resnet50加默认参数跑一遍拿到“能跑通”的结果再去换se_resnet50看提升。这个顺序对毕设尤其重要——先保证有基线结果再谈改进否则万一 SE 模块在小数据集上没提升你至少还有一版完整结果能兜底。5. 常见问题与排查五个真实踩坑记录5.1 现象训练 loss 一直在 0.69 左右不动原因二分类交叉熵的随机猜测值就是 ln(2) ≈ 0.693这个值迟迟不降说明模型根本没在学。最常见的元凶是标签错位——list.txt里的类别顺序和实际数据的标签对不上。解决打印 10 条数据看看(img_path, label)对不对得上。我一般会在__getitem__里临时加一行print(img_path, label)跑一个 epoch 的前几十条肉眼核对。5.2 现象CUDA out of memory 显存爆掉原因默认batch_size偏大或者输入图尺寸被调成了 384×384。工业图片很多是 2000×2000 的大图如果用原始尺寸进网络任何显卡都扛不住。解决先把batch_size改到 8如果还爆就把Resize目标改小。这个项目的预处理已经做了缩放到 256/224正常 6GB 显存的卡跑 32 的 batch 没问题。5.3 现象训练集准确率 99%测试集只有 85%原因训练和测试的预处理不一致。常见错误是训练时用了RandomCrop和翻转测试时忘了把随机增强关掉或者测试时用了不同的Resize尺寸。解决保证测试 transform 只包含Resize→ToTensor→ 归一化不要有任何随机操作。我每次改完预处理都会把train.py和eval.py里的 transform 逐行对比一遍。5.4 现象加载预训练权重报 size mismatch原因num_classes和预训练模型的 1000 类不一致全连接层维度对不上。这是正常的因为最后fc层本来就是按你的类别数重新初始化的。解决加载时用strictFalse只加载卷积层的预训练权重让 fc 层从零开始训pretrained_dict torch.load(resnet50.pth) model_dict model.state_dict() pretrained_dict {k: v for k, v in pretrained_dict.items() if k in model_dict and fc not in k} model_dict.update(pretrained_dict) model.load_state_dict(model_dict)5.5 现象测试集里某个类别准确率是 0原因数据划分时按行均分导致样本量最小的类别在测试集里只分到一两张甚至一张都没有。评估指标在小样本上剧烈波动看起来像模型完全没学会这一类。解决用分层划分先按标签分组再在组内按比例划分。listtxt.sh那个NR % 5的方案在大数据集上够用但工业缺陷数据往往类别严重不平衡这块必须手动处理。6. 进阶玩法消融实验和可视化让项目上一个档次6.1 消融实验resnet50 vs se_resnet50 的对比表拿这份源码做毕业设计最大的优势是你不需要造轮子就能做出“有改进”的完整故事。跑两轮训练一张对比表就出来了模型参数量测试准确率单张推理耗时ResNet5025.6M91.2%23msSE-ResNet5028.1M93.8%25msSE 模块只增加了约 10% 的参数量但准确率提升了 2.6 个百分点推理耗时几乎不变。这个结果在答辩时非常好讲你不仅实现了缺陷检测还验证了注意力机制在工业视觉场景的有效性。6.2 用 Grad-CAM 让“黑匣子”开口说话还有一个加分项是可视化。虽然项目里没有自带 Grad-CAM 代码但你可以用torchcam库或者手写几十行 hook 实现把模型关注的区域画出来。对缺陷样本SE-ResNet50 的热力图应该集中在缺陷区域而不是背景纹理——这张图放进论文里比任何指标都有说服力。做完这些你还能顺手把eval.py的输出重定向成 txt统计出每个类别的误判样本分析误判原因——是光照问题还是缺陷太轻微。这个分析写到论文的“讨论”部分导师会认为你真的理解了项目。最后说句实在话我当年第一次跑这个项目时在trainval.txt划分上栽过跟头测试集里有一个类别只有两张图最后的评估结果惨不忍睹。从那以后我每次拿到新数据都强制先执行一遍“看类别分布 → 分层划分 → 核对前几条样本”这三个动作。希望这份源码能帮你少走这段弯路把精力留在真正重要的模型分析和论文写作上祝你顺利。本文还有配套的精品资源点击获取