简介面向毕业设计与课程作业的深度学习工业缺陷检测Python项目源码适合具备一定Python基础、希望快速搭建可演示系统的本科及高职学生。项目包含完整的模型训练、数据预处理、评估与预测流程采用ResNet/SE-ResNet等卷积网络结构并配有清晰代码注释和说明文档便于理解与二次开发。压缩包共12个文件以7个Python脚本为核心涵盖训练、配置、数据加载和模型定义等模块另含3个文本文件用于数据列表管理1个Shell脚本辅助数据准备以及1份Markdown说明文档整体仅556KB部署轻量。该资源已有193人学习下载属于导师认可的高分毕业设计项目。下载后可获得整套可运行代码、数据集划分脚本与使用文档界面完善、功能齐全能直接用于结题演示或功能验证尤其适合作为期末大作业和答辩展示的参考范本。1. 毕业设计做工业缺陷检测为什么值得从深度学习切入毕业设计选“基于深度学习的工业产品缺陷检测”这个方向很多同学第一反应是去 GitHub 找个现成源码包直接跑。这个方向真正值得做的地方在于它不是一道算法题而是一条从数据标注、模型训练到指标评估的完整闭环恰好复刻了工业视觉领域落地项目的标准流程。我用 PyTorch 做过轴承表面缺陷检测从整理数据集到跑通检测模型再补上文档和实验对比前后用了一周。这篇文章不打算给你贴一个“完美源码”而是顺着这条闭环拆开讲清楚数据怎么组织、VOC 标注怎么转 YOLO 格式、模型怎么选、训练参数怎么设、mAP 怎么算以及最容易劝退新手的几个坑。目标是让你看完能自己搭出一套可复现的缺陷检测工程论文、答辩、演示都能拿得出手。2. 数据是第一步构建工业缺陷数据集与标注格式转换的完整流程2.1 缺陷检测数据长什么样类别、尺寸、光照与标注准则工业缺陷图像和自然场景图像有三个明显区别先认清这三点后面所有决策才有依据。背景单一但反光严重。金属、塑料、玻璃表面的反光会让模型学到“亮斑即缺陷”这种错误映射所以后文会专门强调光照增强和验证集划分。缺陷目标占比极小。一条划痕可能只占整张 640 × 640 图像的 0.5%属于典型的小目标检测。用 Faster R-CNN 这类两阶段模型时候选框生成能兜住小目标用 YOLO 系模型时则需要关注 anchor 设置和多尺度特征融合。类别极不平衡。正常产品占绝大多数缺陷样本可能只有几十张。没有数据增强和类别权重模型会快速收敛到“永远输出正常”的捷径解。标注策略上我建议核心类别控制在 35 类。比如轴承缺陷数据常见的划分方式是类别名称典型形态备注scratch划痕线性方向性明显bubble气泡/麻点圆形或椭圆stain污渍/氧化皮块状边缘模糊crack裂纹细长常带分支pitting点蚀密集小坑这个分类粒度对毕业设计足够。太细会导致每类样本数少到没法训练太粗则论文里的混淆矩阵没有区分度。标注工具用 LabelImg 画矩形框就行输出是 VOC 格式的 XML。分割标注不是不行但目标检测已经足够撑起毕设的算法对比和指标分析割标注徒增工作量。注意一个容易被忽略的细节同一张图里多个同类缺陷可以合并成一个框也可以拆开标——我的习惯是间距小于目标直径的合并否则分开标这样模型学到的“实例感”更强。2.2 把 VOC 标注转成 YOLO 格式转换脚本与四个边界坑LabelImg 默认导出 VOC 格式 XMLYOLO 系模型训练需要 txt 标注格式不互通这一步几乎是所有人都会卡一下的地方。我自己写过一个转换脚本去掉项目特定部分后核心如下import os import xml.etree.ElementTree as ET from pathlib import Path # 类别顺序要固定之后 train.txt 里出现的就是这个索引 CLASSES [scratch, bubble, stain, crack, pitting] def voc_to_yolo(xml_path, out_txt_path, img_w, img_h): tree ET.parse(xml_path) root tree.getroot() lines [] for obj in root.iter(object): name obj.find(name).text if name not in CLASSES: print(f[警告] 未知类别 {name}跳过 {xml_path}) continue cls_id CLASSES.index(name) box obj.find(bndbox) xmin float(box.find(xmin).text) ymin float(box.find(ymin).text) xmax float(box.find(xmax).text) ymax float(box.find(ymax).text) # 边界框到图像边缘会导致损失计算出现负值直接裁掉 xmin max(0, xmin) ymin max(0, ymin) xmax min(img_w, xmax) ymax min(img_h, ymax) if xmax xmin or ymax ymin: print(f[跳过] 无效框: {xml_path}) continue # VOC: xmin,ymin,xmax,ymax - YOLO: x_center,y_center,w,h全部归一化 x_center (xmin xmax) / 2.0 / img_w y_center (ymin ymax) / 2.0 / img_h w (xmax - xmin) / img_w h (ymax - ymin) / img_h lines.append(f{cls_id} {x_center:.6f} {y_center:.6f} {w:.6f} {h:.6f}) with open(out_txt_path, w, encodingutf-8) as f: f.write(\n.join(lines)) if __name__ __main__: xml_dir Path(annotations/voc) out_dir Path(annotations/yolo) out_dir.mkdir(exist_okTrue) # 图片尺寸表dict[文件名] (width, height) sizes {} # 由你自己从 image 元数据读取 for xml_path in xml_dir.glob(*.xml): stem xml_path.stem img_w, img_h sizes[stem] voc_to_yolo(str(xml_path), str(out_dir / f{stem}.txt), img_w, img_h) print(VOC 转 YOLO 完成)这段代码的逻辑很直白遍历 XML 里每个 object把坐标从左上右下角格式转换成中心点加宽高的归一化格式最后拼出 YOLO 需要的“类别 中心x 中心y 宽 高”一行。注意我在转换前做了越界裁剪这是必须的否则后续匹配 anchor 阶段会出现中心点在图像外的野框损失曲线看起来像过山车。实际项目里有四个边界坑值得单独记一下。第一图片宽高必须来自图像本身而不是 XML 里的 size 节点。某些标注工具的 size 记录的是标注时窗口的分辨率和原图不同归一化后坐标整体偏移训练时模型永远对不齐。第二类名和类别索引要锁死。训练脚本里读 classes.txt 的第一行对应索引 0如果转换脚本里 CLASSES 和 classes.txt 顺序不一致模型学到的语义就全错了。最笨但最有效的办法转换完随机抽几张图把 txt 里的归一化坐标乘回宽高画框核对。第三Windows 上跑脚本要注意路径分隔符。Path 对象在 Windows 和 Linux 下行为一致但如果你直接 open() 拼接字符串路径反斜杠转义问题会让你排查半小时。第四背景类不要写进 CLASSES。YOLO 不需要背景类标签写了反而额外增加输出维度检测头会混乱。2.3 数据增强产线样本量不够时怎么把一张图变成十张工业缺陷检测的数据量一般都不大几十张到几百张原始图很常见。数据增强不是可选项是必需品。我的首选是 Albumentations因为它的目标是把图像和标注同步变换不需要你手动维护两张图之间的对齐关系。下面是一套适合反光金属表面的增强管线import albumentations as A train_transform A.Compose([ A.RandomBrightnessContrast( brightness_limit0.2, contrast_limit0.2, p0.5 ), A.HueSaturationValue( hue_shift_limit10, sat_shift_limit20, val_shift_limit10, p0.3 ), A.HorizontalFlip(p0.5), A.VerticalFlip(p0.2), # 轴承上下对称翻转不会改变语义 A.RandomRotate90(p0.3), # 90度旋转适合圆形零件 A.GaussNoise(var_limit(10.0, 50.0), p0.2), A.CLAHE(clip_limit2.0, tile_grid_size(8, 8), p0.3), A.CoarseDropout(max_holes4, max_height16, max_width16, p0.1), ], bbox_paramsA.BboxParams( formatyolo, min_visibility0.3, # 被遮挡超过 70% 的框丢弃避免语义残废 label_fields[class_labels], )) # 使用时保持图像和标注同步变换 augmented train_transform( imageimage_np, bboxesbbox_np, # 格式为 yolocx,cy,w,h class_labelsclass_id_np, )参数说明里重点看两处。RandomBrightnessContrast 的亮度范围设 0.2是针对金属反光场景调的光照变化超过这个幅度会把“反光区域”和“真实缺陷”混淆模型反而学会把亮度突变当特征。CoarseDropout 是模拟零件表面被夹具遮挡的情况但 max_holes 不要超过 4否则缺陷区域大量消失模型被迫去猜。min_visibility 属性必须开它决定增强后标注框被裁剪到多少比例以下直接丢弃避免出现“一个框只有 2 个像素还硬学”的噪声标签。增强的规模和原始数据的比例我控制在 1:10 以内。也就是说原始图 100 张增强后 1000 张左右就有了。超过这个比例增强之间的重叠度太高验证集里会出现训练时的增强变体指标虚高。3. 模型选型与最小训练工程用 PyTorch 搭起可复现的检测基线3.1 迁移学习还是从零训练ResNet、YOLO、Faster R-CNN 怎么挑工业缺陷检测的模型选型核心矛盾是“小数据 高精度要求”。在几十到几百张样本量下从零训练一个深度卷积神经网络几乎不可行收敛慢不说还会严重过拟合。标准做法是使用在 ImageNet 或 COCO 上预训练的权重在其基础上微调能把需要的有效样本量降低一个数量级。具体架构选型取决于任务难度任务复杂度推荐模型理由分类有无缺陷ResNet18 / ResNet50结构简单训练快论文好写检测缺陷位置Faster R-CNN FPN两阶段对小目标召回率更好检测速度优先演示YOLOv8 / YOLOv5推理快可视化效果好毕业设计里最怕“性能不够就堆模型复杂度”。Faster R-CNN 在小目标缺陷上的平均精度通常比同配置 YOLO 高 3~5 个点原因是两阶段方法先用 RPN 生成候选区域再做二次分类和回归对小目标更友好。YOLO 则是单阶段直接回归结构简单、推理快现场演示时 GPU 占用小、响应快答神环节更有底气。我的建议是论文主线用 Faster R-CNN 做精度指标另外跑一个 YOLO 做对比和速度验证这样实验对比表至少有两列不至于单薄。3.2 最小可训练工程DataLoader、模型、损失函数、优化器四件套很多网上源码包的问题是“工程重逻辑散”一个大仓库跑起来后新手根本不知道哪里改类别数、哪里换数据集。我更喜欢从最小可训练代码起步理解每一行在干什么再逐步加功能。下面是一个简化但完整可跑的检测训练循环骨架import torch import torch.nn as nn from torch.utils.data import DataLoader, Dataset from torchvision import models, transforms from torchvision.models.detection import fasterrcnn_resnet50_fpn_v2, FasterRCNN_ResNet50_FPN_V2_Weights class SurfaceDefectDataset(Dataset): 实现三个方法 __len__ 返回样本数__getitem__ 返回 (图像, 检测目标字典) def __init__(self, image_dir, label_dir): self.image_paths sorted(image_dir.glob(*.jpg)) self.label_dir label_dir self.transforms transforms.Compose([ transforms.ToTensor(), transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225]), ]) self.classes [scratch, bubble, stain, crack, pitting] def __len__(self): return len(self.image_paths) def __getitem__(self, idx): img Image.open(self.image_paths[idx]).convert(RGB) img_tensor self.transforms(img) # 读取同名的 YOLO 标注文件转换成 tensor label_path self.label_dir / (self.image_paths[idx].stem .txt) boxes, labels [], [] for line in open(label_path): cls_id, cx, cy, w, h map(float, line.strip().split()) # 从 (cx, cy, w, h) 换算回 (x_min, y_min, x_max, y_max) x_min (cx - w / 2) * img.width y_min (cy - h / 2) * img.height x_max (cx w / 2) * img.width y_max (cy h / 2) * img.height if x_max x_min or y_max y_min: continue boxes.append([x_min, y_min, x_max, y_max]) labels.append(int(cls_id)) if not boxes: # 空标注样本提供一个空 tensortorchvision 里允许 boxes torch.zeros((0, 4), dtypetorch.float32) labels torch.zeros((0,), dtypetorch.int64) else: boxes torch.tensor(boxes, dtypetorch.float32) labels torch.tensor(labels, dtypetorch.int64) return img_tensor, {boxes: boxes, labels: labels} # 使用预训练权重只替换类别数 model fasterrcnn_resnet50_fpn_v2(weightsFasterRCNN_ResNet50_FPN_V2_Weights.COCO_V1) in_features model.roi_heads.box_predictor.cls_score.in_features model.roi_heads.box_predictor models.detection.faster_rcnn.FastRCNNPredictor( in_features, num_classes6 # 5 类缺陷 1 类背景 ) train_loader DataLoader( train_dataset, batch_size4, shuffleTrue, num_workers2, collate_fnlambda batch: tuple(zip(*batch)), # 检测任务 dict 不能自动堆叠 ) device torch.device(cuda if torch.cuda.is_available() else cpu) model.to(device) params [p for p in model.parameters() if p.requires_grad] optimizer torch.optim.SGD(params, lr0.005, momentum0.9, weight_decay0.0005) lr_scheduler torch.optim.lr_scheduler.StepLR(optimizer, step_size3, gamma0.1) for epoch in range(num_epochs): model.train() total_loss 0.0 for images, targets in train_loader: images [img.to(device) for img in images] targets [{k: v.to(device) for k, v in t.items()} for t in targets] loss_dict model(images, targets) loss sum(loss for loss in loss_dict.values()) optimizer.zero_grad() loss.backward() optimizer.step() total_loss loss.item() lr_scheduler.step() print(fEpoch {epoch1}: loss {total_loss / len(train_loader):.4f}) torch.save(model.state_dict(), fcheckpoints/detector_ep{epoch1}.pth)这段代码有几个关键点要展开说明一下。DataLoader 的 collate_fn 参数在目标检测任务里必须自定义。Faster R-CNN 的 targets 是可变长度 dictPyTorch 默认的 collate 会把它们堆成 tensor 报错所以需要一个简单的 zip 封装让 batch 变成“图像列表 目标字典列表”。损失函数不用自己写。torchvision 的 Faster R-CNN 内部已经包含了分类损失和回归损失model(images, targets) 返回的 dict 里有 loss_classifier、loss_box_reg 等分量。直接求和反馈梯度即可这也是用 torchvision 这类封装库比纯手写模型更不容易翻车的原因。你只需要保证 targets 里的每个键格式正确缺一个就会在损失计算时报错。优化器选择 SGD 而不是 Adam是做过对比的。目标检测任务里 SGD momentum 在 5 个 epoch 后 loss 的下降曲线更平滑Adam 初期收敛快但后期精度容易抖动。不过如果你只是想快速看效果AdamW 的下限也够用不会差太多。学习率和 batch size 的匹配关系是毕设答辩最常见的问题。4 张 batch 配 0.005 的初始 lr显存占用大约 3.5G1050 Ti 级别的卡可以跑。如果你只能凑 batch size2把 lr 降到 0.002 左右否则梯度过大loss 会出现峰值。3.3 训练超参数初始化lr、batch size、anchor 与 epoch 的经验区间超参数的“经验值”主要来自工业检测场景反复跑出来的规律不是一个标准答案。我给出一组经过多次验证的区间照着设不会大翻车。参数经验区间说明初始学习率1e-3 ~ 5e-3SGD迁移学习时用 1e-3从零训练降到 1e-4batch size2 ~ 8Faster R-CNN主要受显存限制10G 以上可到 8epoch 数25 ~ 60缺陷样本少30 轮足够收敛灵活使用早停输入图像尺寸640 × 640 ~ 1333 × 800小缺陷务必不要过度下采样锚框anchor默认配置即可YOLO 系可用 k-means 重聚类收益和代价都有关于 epoch超过 60 轮基本就是过拟合曲线。把每个 epoch 的模型权重都保存下来最后用验证集 mAP 选最优权重不要只看最后一个 epoch。这是很多人会忽略的细节——best model 往往不是最后一个 checkpoint而是中间某个特定 epoch 的版本。输入尺寸对缺陷检测的影响很大。原图是 3000 × 3000 像素的零件图直接送到检测器会把缺陷缩到几个像素特征完全丢失。常见的做法是做一个滑动窗口切割把大图切成 512 × 512 或 640 × 640 的小块再训练这样缺陷的像素占比能保持在可学习范围。切割时的重叠率设 20%~30%避免漏掉边缘缺陷。4. 训练与评估mAP 怎么算、损失曲线怎么盯、预测结果怎么看4.1 损失下降但 mAP 不动先检查正负样本与 IoU 阈值训练中常见的一个现象是loss 曲线稳步下降但验证集 mAP 一直趴着不动。大多数情况下不是模型坏了而是评估阶段的匹配逻辑有问题。mAP 计算分三步预测框按置信度从高到低排序逐个和真实框计算 IoUIoU 超过阈值一般取 0.5且类别一致算 True Positive否则算 False Positive。然后根据所有图片的统计结果画出 PR 曲线计算曲线下面积得到 AP再对每个类别取平均得到 mAP。如果你的 mAP 用的是 COCO 标准还要在 0.5:0.95 的 IoU 区间取平均值这对小缺陷来说很残忍——缺陷框本身可能只有几十像素IoU 稍微偏差一点就从 0.5 跌到 0.3AP 直接变零。所以工业缺陷检测论文里我建议守规矩写 mAP0.5另外把 mAP0.5:0.95 作为附加指标两个都报既诚实又有层次感。如果训练集上有很高的 mAP验证集上却几乎为零先检查是不是 IoU 匹配逻辑里类别索引错位。打印一下预测的 class id 和真实标签的 class id 映射关系确认没有整体偏移一位。4.2 TensorBoard 盯训练loss、mAP、PR 曲线一起记录训练时可以同时记录 loss 曲线、验证 mAP、PR 曲线、学习率变化和几张典型预测图这些材料在论文和答辩 PPT 里全是素材。用 torch.utils.tensorboard 摘要写法如下from torch.utils.tensorboard import SummaryWriter writer SummaryWriter(runs/surface_defect) # 每个 epoch 或每个 batch 记录一次 for epoch in range(num_epochs): avg_loss train_one_epoch(...) val_mAP evaluate(model, val_loader) writer.add_scalar(Loss/train, avg_loss, epoch) writer.add_scalar(Metrics/mAP0.5, val_mAP, epoch) writer.add_scalar(LR, optimizer.param_groups[0][lr], epoch) # 把预测可视化的图像写进 TensorBoard方便直观判断 vis_img draw_predictions(model, val_loader) writer.add_image(Prediction/val, vis_img, epoch) writer.close()训练日志路径加一个时间戳后缀否则多次训练的数据会写进同一个目录TensorBoard 界面上曲线混在一起染色。常见做法是tensorboard --logdirruns --port6006浏览器打开 localhost:6006 就能看到所有训练记录。答辩前截几张 loss 下降和 PR 曲线的图放进文档比空口说“效果不错”有说服力得多。4.3 用测试集做可视化验证画框、算置信度、区分漏检与误检验证阶段最容易忽略的是“置信度阈值”的选择。模型输出每个框带 0~1 的置信度默认取 0.5但工业场景里阈值应该是可调参数。阈值调低召回率上升误检也上升调高则相反。实践中我会按类别分别做一次阈值扫描找出每个类别在验证集上 mAP 最高的工作点固定下来用于测试集评估这样写进论文的时候指标的选取有依据不容易被答辩老师挑毛病。可视化验证的代码很简单import cv2 import torch model.eval() with torch.no_grad(): pred model([img_tensor])[0] boxes pred[boxes].cpu().numpy() scores pred[scores].cpu().numpy() labels pred[labels].cpu().numpy() img_show cv2.cvtColor(raw_img_np, cv2.COLOR_RGB2BGR) for box, score, label in zip(boxes, scores, labels): if score 0.5: continue # 跳过低置信度框 x_min, y_min, x_max, y_max [int(v) for v in box] color (0, 0, 255) if label 0 else (0, 255, 0) cv2.rectangle(img_show, (x_min, y_min), (x_max, y_max), color, 2) cv2.putText(img_show, fcls{label} {score:.2f}, (x_min, y_min - 8), cv2.FONT_HERSHEY_SIMPLEX, 0.6, color, 2) cv2.imwrite(val_prediction.jpg, img_show)把每张验证图的预测结果存下来后人工过一遍重点看漏检真实框没有对应预测框和误检预测框没有对应真实框。这两种错误在工业现场是完全不同的处置方式漏检意味着缺陷流出产线误检意味着停线检查浪费产能。论文里如果能把这两种错误分开统计是很加分的细节。5. 缺陷检测避坑指南工业场景下最常翻车的 5 个问题5.1 反光表面的误检与漏检光照条件是第一变量现象验证集上大量把零件表面的高光区域预测成 scratch 或 stain真实缺陷反而漏检。原因训练数据里光照单一模型学到的是“亮度突变”这个特征而不是“缺陷纹理”这个本质。金属反光区域和缺陷在灰度分布上高度相似。解决数据采集阶段就引入多个角度、多个时段的光照变化。增强阶段把 brightness_limit 提高到 0.3~0.4并加入 CLAHE 局部对比度增强。如果项目允许加一张偏振镜照片会明显拉低反光误检。验证集必须包含与训练集不同批次的采样照片否则光照干扰不会暴露出来。5.2 样本不平衡严重把背景当缺陷缺陷却当成噪声现象训练后模型对正常产品误检率极高几乎每张图都画一大堆框。原因增强后缺陷类样本虽然有上千张但“无缺陷”区域在每张图里占绝对多数。分类器只需要输出背景类就能获得很低的损失值缺陷框的数量占比太小损失主导权全在背景上。解决两阶段模型可以在训练时提高正样本框的采样比例更简单的方案是给损失函数加了类别权重尤其是背景类和缺陷类的权重差异调整。另外可以主动截取仅包含正常表面的负样本图片加入训练集让模型见过足够多“没有缺陷但反光”的背景。以我的经验负样本和正样本的比例 1:1 是底线。5.3 DataLoader 慢到怀疑人生num_workers 与预载的取舍现象GPU 利用率徘徊在 20% 以下训练一个 epoch 要半小时但模型本身并不复杂。原因数据增强和图像解码全在 CPU 上串行执行DataLoader 的 num_workers 设成了 0等于每次迭代都卡在图像加载上。解决Linux 下把 num_workers 设成 4~8配合 pin_memoryTrue让 CUDA 直接访问锁页内存。Windows 下多进程需要考虑 spawn 机制先设成 2 验证流程再逐步调高。另外把增强较重的操作缓存到磁盘可以避免每个 epoch 都重复计算。一个 epoch 前把增强后的样本数量归档成新的数据集文件后续训练直接读取速度翻倍。5.4 验证集指标虚高训练集与验证集发生了数据泄漏现象训练 loss 没收敛好但验证集 mAP 高达 0.9 以上明显不正常。原因同一产品的多张照片被拆分到训练集和验证集里两张图之间只是轻微平移或旋转模型在训练时“见过”了验证图像的内容评估结果就不可信了。解决按“产品批次”而不是按“单张图片”划分数据集。比如同一批次拍摄的 100 张图全部进训练集或全部进验证集绝不混切。工业检测里产品个体差异、批次差异、时间光照差异都是真实分布的一部分数据划分要模拟这种分布。这个是答辩时老师最爱问的点答好了非常加分。5.5 交论文时的可复现问题路径写死、随机种子没固定、环境描述不清现象项目换到另一台电脑上就报错找不到文件或者每次训练结果差异巨大。原因代码里出现了绝对路径、随机初始化没有固定种子、依赖库版本没有锁定。解决固定随机种子的函数写在所有初始化之前import random import numpy as np import torch def seed_everything(seed42): random.seed(seed) np.random.seed(seed) torch.manual_seed(seed) torch.cuda.manual_seed_all(seed) torch.backends.cudnn.deterministic True # 关闭 cudnn 自动调优 torch.backends.cudnn.benchmark False # 保证每次卷积计算结果一致 seed_everything(42)cudnn 自动调优是“随机性”的主要来源之一。deterministicTrue 会让训练稍微慢一点但换来的是可复现的结果毕设完全值得。路径处理上用相对路径项目文件夹名不要带中文也不要用一个写着某某某台式机的绝对路径。环境描述写清楚 Python 版本、CUDA 版本、torch 和 torchvision 版本即可不要一股脑全贴 requirements.txt 让读者自己猜。6. 把项目做成能过关的交付物文档结构、实验对比与复现细节6.1 项目目录怎么组织毕设项目交付时代码、文档、数据要分清楚让评审老师能在十分钟内找到想看的东西。我常用的项目结构是这样的surface_defect_detection/ ├── README.md # 项目简介 快速开始命令 ├── requirements.txt # Python 依赖锁版本 ├── configs/ # 模型和训练的超参数配置 ├── data/ │ ├── raw/ # 原始图像只读不改 │ ├── annotations/ # 标注文件 │ ├── train/ # 划分后的训练集 │ └── val/ # 验证集按批次划分 ├── scripts/ # 数据转换、训练、评估脚本 ├── checkpoints/ # 训练产物保存 best 权重 ├── docs/ │ ├── 数据集说明.md │ ├── 实验报告.md │ └── 答辩PPT.md └── results/ ├── tensorboard/ # 训练日志 └── predictions/ # 验证集可视化结果RAEDME.md 里至少要写清楚三件事环境怎么装、数据放哪里、训练命令是什么。每个命令复制粘贴就能跑通不要留“请自行修改路径”这种话。数据文件如果太大把原始数据单独压缩成一个 zip 或放在网盘代码里只保留一份最小示例数据用于快速验证流程。6.2 实验对比表怎么写基线、改进项、消融实验缺一不可论文里的对比实验决定了最终成绩的上限。只报一个最终模型 mAP 是不够的要能证明“你每一步改进都在起作用”。常用的方法是一张主对比表加两张补充表。主对比表结构如下方法训练数据规模mAP0.5mAP0.5:0.95推理耗时Faster R-CNN论文基线原始 200 张0.620.3576 msFaster R-CNN 数据增强增强 2000 张0.740.4676 msFaster R-CNN FPN 多尺度训练增强 2000 张0.790.5282 msYOLOv8 基线速度对比增强 2000 张0.710.4112 ms这个表的逻辑是从“基线”到“改进项”到“复杂度结余”每加一个点都对应一块工程或算法改动。消融实验则针对模型内部结构做减法和替换比如去掉 FPN 层、冻结 backbone 前三层、换损失函数等每一行的差异只保留一个变量。答辩老师问“为什么你的 mAP 不是最高的”时答案的底气就来自这张表——你诚实地报告了基线、明确了自己的改进并说明了哪些模块有效、哪些模块性价比低。6.3 别人复现时环境、随机种子和 README 要做到什么程度一个项目能不能“复现”核心在于别人能不能只看 README 一步不差地跑通。我会在 README 里放三个命令pip install -r requirements.txt python scripts/prepare_data.py # 处理原始图 标注划分数据集 python scripts/train.py --config configs/faster_rcnn.yaml每个脚本都做成可以独立执行不依赖编辑器环境变量或 IDE 的 Run 按钮。requirements.txt 把主要库版本锁住torch2.0.1 torchvision0.15.2 albumentations1.3.1 opencv-python4.8.0.74 numpy1.24.3 tensorboard2.14.0版本号必须对应自己实际运行环境不要用 “latest” 或注释掉。到这一步项目交付的完整度和可复现性才真正够格交到评审老师手上。回头再看我做第一个缺陷检测毕设时的过程最耗时的并不是模型调参而是那些“你以为不是事的事”标注格式转换、数据划分泄漏、随机种子不固定、文档里少写了一条 pip 命令。这些坑每一个都能让后续步骤多折腾一下午。后来我养成一个习惯任何脚本跑通后先把 README 写好把完整的运行命令记录进去再继续下一步。这次的经验救了我好多次希望帮到你。本文还有配套的精品资源点击获取
阅读完成 · 觉得有帮助?