ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

YOLOv8钢材表面缺陷检测实战:NEU-DET数据集与训练全流程

YOLOv8钢材表面缺陷检测实战:NEU-DET数据集与训练全流程 简介基于YOLOv8的钢材表面缺陷检测系统面向深度学习初学者、毕业设计及课程设计开发者解决工业场景中钢材划痕、凹坑、氧化皮和腐蚀等缺陷的自动识别问题。压缩包共2000个文件大小60.81MB其中包含1800余个txt标注文件、187张钢材表面图像、5个Python训练脚本、3个不同阶段的PyTorch模型权重以及YAML配置文件和环境依赖清单覆盖从数据准备、模型训练到结果输出的完整流程。随包提供的多档模型权重可适应不同精度与速度需求配套训练脚本支持灵活调整参数配置文件清晰定义了路径、标签和训练策略。系统能自动化完成缺陷检测并直观显示位置与类别有助于提升检测效率。目前已有75人学习下载适合需要快速搭建工业视觉检测方案、深入理解YOLOv8工程化实践的开发者。1. 钢材表面缺陷检测为什么值得用 YOLOv8从 NEU-DET 数据集到可落地的毕业设计钢材表面的裂纹、夹杂、麻点、氧化铁皮这类缺陷靠人工肉眼抽检漏检率一直压不下来而且每个班次的判断标准还不一样。用深度学习做钢材表面缺陷检测最稳的切入点就是 YOLOv8——它有现成的预训练权重、完善的训练链路CPU 环境也能跑通整个流程对毕业设计和课程设计来说是性价比最高的目标检测方案。这套资源把数据集处理、环境搭建、模型训练到缺陷识别预测的完整链路打包好了适合正在做基于 YOLOv8 的毕业设计、想快速复现钢材缺陷检测项目的同学。下面按我实际拆过的流程把每一步怎么走、参数怎么设、坑在哪写清楚。2. 环境搭建Ubuntu 20.04 CPU 版跑 YOLOv8 的完整流程与预训练权重准备2.1 CPU 版本环境为什么够用以及依赖选型很多人一听说做深度学习第一反应就是必须要有 GPU。但实际上钢材表面缺陷检测这个任务NEU-DET 数据集单张图片只有 200×200 像素类别是六类模型用 YOLOv8n 这种 nano 级别的结构CPU 推理一张图也就几十毫秒。训练阶段 CPU 确实慢但毕业设计验证模型性能跑 50 到 100 轮是能接受的。我一般在 Ubuntu 20.04 上搭 CPU 环境核心思路是装 CPU 版 PyTorch 而不是 CUDA 版避免显卡驱动和 CUDA 版本不匹配导致的环境翻车。选型上Python 用 3.8 或 3.10 都行ultralytics 库对版本要求不苛刻。最关键的是 PyTorch 必须用 CPU 版本安装否则你在没有 NVIDIA 显卡的机器上会直接报 CUDA 不可用的错。这里给出一套我反复装过多次的命令conda create -n steel python3.10 -y conda activate steel pip install torch torchvision --index-url https://download.pytorch.org/whl/cpu pip install ultralytics参数说明--index-url https://download.pytorch.org/whl/cpu是指定从 PyTorch 官方 CPU 轮子源下载这样装出来的 torch 不依赖 CUDA 库文件体积小一半以上。ultralytics是 YOLOv8 的官方库安装后会自动带上 opencv-python、numpy、pandas 这些依赖。装完以后用python -c import torch; print(torch.__version__)验证能输出版本号就说明环境基本通了。2.2 预训练权重的下载与存放位置YOLOv8 的预训练权重分几个档位yolov8n.pt 是 nano 版参数量最低CPU 上跑得最快yolov8s.pt、yolov8m.pt 精度更高但推理耗时明显上升。对我这套钢材缺陷检测来说nano 和 small 就够用没必要上 large。第一次运行训练命令时 ultralytics 会自动下载权重但国内网络环境经常卡在下载这一步我一般手动把权重文件放到项目目录下再在训练脚本里直接引用本地路径。权重文件放到weights/目录下训练时通过modelyolov8n.pt指定。如果你下载的是 yolov8s.pt就把参数改成对应文件名。这里要注意预训练权重是 COCO 数据集上训出来的 80 类模型我们的任务是 6 类钢材缺陷所以加载权重后训练时 ultralytics 会自动替换检测头你不用手动改网络结构。2.3 验证环境是否跑通的最小测试环境配好之后先别急着训练跑一遍官方自带的推理测试确认整条链路没有问题。这一步看起来多余但能帮你把环境问题和代码问题分开排查。yolo predict modelyolov8n.pt sourcehttps://ultralytics.com/images/bus.jpg如果图片能正常识别出 person、bus 这些类别说明 PyTorch、opencv、ultralytics 的配合是正常的。之后我们做钢材缺陷检测的所有代码都是在这个基础上替换数据集和模型参数。CPU 环境下推理免不了风扇狂转这是正常现象不要觉得是机器坏了。3. 数据集处理NEU-DET 格式转换与 labelme 标注转 YOLO 的实用脚本3.1 先搞清数据集的原始格式再决定写什么脚本钢材表面缺陷检测最常用的公开数据集是东北大学的 NEU-DET里面包含六类缺陷crazed裂纹、inclusion夹杂、patches麻点、painted氧化铁皮、rolled-in轧制氧化皮、scratches划痕。原始标注格式是每张图片对应一个 XML 文件标注框坐标是xmin, ymin, xmax, ymax这种形式而 YOLOv8 训练需要的是 txt 格式每行内容是class_id x_center y_center width height坐标全部归一化到 0 到 1 之间。你拿到的这套资源里可能有两种情况一种是下载的原始 NEU-DET 数据集带着 XML 标注另一种是已经处理成 YOLO 格式的 txt 标注。我建议你先打开目录看一眼如果是 XML就跑下面的转换脚本如果已经是 txt直接用第 4 章的 data.yaml 组织训练就行。这里把 XML 转 YOLO 的脚本写出来这是整个数据集预处理里最容易出错的一环。import xml.etree.ElementTree as ET import os class_mapping { crazed: 0, inclusion: 1, patches: 2, painted: 3, rolled-in: 4, scratches: 5 } def convert_xml_to_txt(xml_path, txt_path, img_width, img_height): tree ET.parse(xml_path) root tree.getroot() lines [] for obj in root.iter(object): name obj.find(name).text if name not in class_mapping: continue class_id class_mapping[name] bbox obj.find(bndbox) xmin float(bbox.find(xmin).text) ymin float(bbox.find(ymin).text) xmax float(bbox.find(xmax).text) ymax float(bbox.find(ymax).text) x_center (xmin xmax) / 2.0 / img_width y_center (ymin ymax) / 2.0 / img_height width (xmax - xmin) / img_width height (ymax - ymin) / img_height lines.append(f{class_id} {x_center:.6f} {y_center:.6f} {width:.6f} {height:.6f}) with open(txt_path, w) as f: f.write(\n.join(lines)) # 遍历图片目录批量转换 for img_name in os.listdir(images): if not img_name.endswith(.jpg): continue img_width, img_height 200, 200 # NEU-DET 是固定尺寸 xml_path os.path.join(annotations, img_name.replace(.jpg, .xml)) txt_path os.path.join(labels, img_name.replace(.jpg, .txt)) convert_xml_to_txt(xml_path, txt_path, img_width, img_height)逻辑说明脚本遍历 images 目录下的 jpg 文件找到对应的 XML解析出类别名和边界框坐标再换算成 YOLO 格式的归一化中心点坐标和宽高。这里class_mapping把六类缺陷映射成 0 到 5 的数字顺序必须和第 4 章 data.yaml 里的names列表完全一致否则训练出来的类别标签就是乱的。注意点有三个一是 NEU-DET 图片固定 200×200所以宽高直接写死如果你用的是其他数据集要从 XML 的 size 节点读取实际宽高二是归一化的坐标如果出现大于 1 的值说明边界框越界了需要做 clip 限制三是 txt 文件和图片要同名YOLOv8 是按文件名匹配标注和图片的。3.2 用 labelme 标注自己的钢材缺陷数据矩形框标注转 YOLO 格式如果你不是用公开数据集而是要标注自己拍的钢材表面图片那就要用到 labelme 工具。labelme 默认生成的是 JSON 文件里面保存的是多边形或多边形矩形框的坐标不能直接喂给 YOLOv8。标注的时候我一般只画矩形框因为钢材缺陷的形状不规则用多边形标注反而会引入更多标注噪声。pip install labelme labelme打开 labelme 后左侧选择打开图片目录用Create Rectangle工具画框每个框选择一个类别标签类别名称建议直接用英文比如 scratch、inclusion避免中文路径和编码问题。标完每张图保存后会生成一个同名的 JSON 文件。接下里的转换脚本是把 JSON 转成 YOLO txt 格式关键点是 labelme 存的坐标是绝对像素值需要结合图片宽高归一化。import json import os def labelme_json_to_yolo(json_path, txt_path, class_list): with open(json_path, r, encodingutf-8) as f: data json.load(f) img_width data[imageWidth] img_height data[imageHeight] lines [] for shape in data[shapes]: label shape[label] if label not in class_list: continue class_id class_list.index(label) points shape[points] xmin min(points[0][0], points[1][0]) ymin min(points[0][1], points[1][1]) xmax max(points[0][0], points[1][0]) ymax max(points[0][1], points[1][1]) x_center (xmin xmax) / 2 / img_width y_center (ymin ymax) / 2 / img_height w (xmax - xmin) / img_width h (ymax - ymin) / img_height x_center min(max(x_center, 0), 1) y_center min(max(y_center, 0), 1) w min(max(w, 0), 1) h min(max(h, 0), 1) lines.append(f{class_id} {x_center:.6f} {y_center:.6f} {w:.6f} {h:.6f}) with open(txt_path, w) as f: f.write(\n.join(lines)) class_list [crazed, inclusion, patches, painted, rolled-in, scratches] labelme_json_to_yolo(annotations/1.json, labels/1.txt, class_list)这段脚本里给归一化坐标加了min(max())的边界限制就是防止手滑标注时把矩形框拖到图片外面去。参数说明class_list的顺序就是最终的类别编号顺序你在 labelme 里标注用的标签名必须和这个列表里的字符串完全一致包括大小写否则会被continue跳过导致漏标。3.3 数据集目录结构YOLOv8 训练前必须长这样处理完标注文件后数据集目录要按照 YOLOv8 的约定组织。常见做法是分成 train 和 val 两个子集各自包含 images 和 labels 目录。这里有个容易忽略的点训练集里每张图片的 txt 标注文件要保证存在哪怕这张图里没有任何缺陷也要放一个空 txt 文件否则训练时报错找不到标注。steel_dataset/ ├── images/ │ ├── train/ │ └── val/ ├── labels/ │ ├── train/ │ └── val/ └── steel.yamltrain 和 val 的划分比例我一般按 8:2如果样本量小就按 7:3。划分时要确保每个类别在两个集合里都有分布别让某个缺陷只在训练集出现而验证集里完全没有这样验证结果会虚高。4. 模型训练YOLOv8 网络结构认知与训练参数调优4.1 data.yaml 的写法与关键字段含义YOLOv8 训练前需要一个 data.yaml 文件告诉模型训练数据在哪、有几类、类别名是什么。这是整个训练流程里最简单但也最容易写错的文件。路径建议用绝对路径或者用相对路径时保证当前工作目录在项目根目录。path: /home/user/steel_dataset train: images/train val: images/val nc: 6 names: [crazed, inclusion, patches, painted, rolled-in, scratches]特别强调nc必须和names的长度一致。如果你在 3.1 节的转换脚本里class_mapping把 influxion 这类拼写错误的类别也算进去这里就对不上了。我在实践中碰到过nc: 5但names里写了 6 个名字训练直接崩的情况报错信息很迷惑检查这里就对了。4.2 YOLOv8 网络结构图CNN 骨干、颈部与检测头的关系YOLOv8 的网络结构大致分成三块主干网络负责提取图像特征颈部网络负责融合多尺度特征检测头负责输出预测框和类别概率。很多人调参时喜欢直接改网络结构但对钢材缺陷检测来说缺陷尺度本身不大200×200 的输入已经足够改结构不如调训练参数来得快。YOLOv8 默认会把输入图片缩放到 640×640如果你的数据集图片本身就是 200×200建议把 imgsz 设成 640让模型在较小的缺陷目标上有更好的特征表达。yolo detect train datasteel.yaml modelyolov8n.pt epochs100 imgsz640 batch8 devicecpu参数说明epochs100是训练轮数CPU 环境下 100 轮可能要跑几个到十几个小时batch8是每次送入模型的图片数量CPU 内存不够就降到 4devicecpu明确指定用 CPU。训练过程中终端会实时打印 loss 和 mAP 指标不用等全部训练完再判断好坏。4.3 训练参数含义lr0、optimizer、patience 怎么调YOLOv8 的训练参数集中在hyp超参配置里但命令行也能直接覆盖。我用得最多的几个参数是lr0初始学习率默认 0.01、optimizer优化器默认 auto 自动选择、patience提前停止训练。钢材缺陷数据集比较小学习率太大容易震荡我一般把 lr0 从 0.01 降到 0.005让损失曲线更平滑。yolo detect train datasteel.yaml modelyolov8n.pt epochs150 imgsz640 batch8 optimizerAdamW lr00.005 patience20这里说明一下patience20表示如果连续 20 轮验证集 mAP 没有提升就自动停止训练防止 CPU 上浪费时间跑无效轮次。优化器AdamW对这个小数据集比较友好SGD 收敛慢一些但泛化不一定差可以两个都试看验证集结果说话。4.4 训练过程的监控损失函数曲线图怎么看训练结束后ultralytics 会在runs/detect/train/目录生成results.png这张图里包含训练损失、验证损失、精确率、召回率和 mAP 的变化曲线。很多人只看最终的 mAP不看曲线形态这是一个很大的误区。正常情况是train/box_loss和val/box_loss都稳步下降并趋于平缓如果训练损失持续下降但验证损失在第 50 轮开始上升那就是过拟合了需要提前停止或者加数据增强。我习惯自己画一张损失函数曲线图用训练过程自动保存的 results.csv做更细致的判读。下面这段脚本读取 CSV 并画出 box_loss 和 cls_loss 的对比曲线import pandas as pd import matplotlib.pyplot as plt df pd.read_csv(runs/detect/train/results.csv) df.columns [c.strip() for c in df.columns] plt.figure(figsize(10, 6)) plt.plot(df[epoch], df[train/box_loss], labeltrain box loss) plt.plot(df[epoch], df[val/box_loss], labelval box loss) plt.plot(df[epoch], df[train/cls_loss], labeltrain cls loss) plt.xlabel(epoch) plt.ylabel(loss) plt.legend() plt.title(YOLOv8 Loss Curves) plt.savefig(steel_loss_curve.png, dpi300)逻辑说明results.csv 里每一行是一个 epoch 的汇总指标列名带空格所以先用列表推导式把列名清理掉。画出来的曲线如果 train 和 val 的 gap 不断拉大就要考虑降低学习率或减少模型容量。这里dpi300是为了让曲线图放到论文里足够清晰。5. 踩坑排查从数据标注到模型推理的五个高频问题5.1 现象CPU 训练速度慢到怀疑人生甚至中途卡死原因没有指定 CPU 线程数PyTorch 默认占满所有核或者装错了 CUDA 版 torch 导致运行时反复尝试加载显卡驱动。解决确认 torch 是 CPU 版然后给训练命令加上workers2限制数据加载线程batch降到 4 或 2。我在 8 核 16G 内存的机器上用 yolov8n、imgsz416、batch4100 轮能控制在 6 小时以内。另一个技巧是先用fraction0.5参数用 50% 的数据跑 10 轮验证流程等确认没报错再跑全量。5.2 现象训练不报错但所有缺陷都被识别成同一个类别原因类别映射顺序错乱。最常见的是 XML 转 txt 时class_mapping的 key 顺序和 data.yaml 的names顺序不一致比如转换脚本里patches是 2yaml 里names列表第二位是painted模型就会把 patches 学成 painted。解决把class_mapping和names做成同一份配置不要在两个地方手写两次。训练前随机抽三张训练图片打印出 txt 标注内容和对应原图人工核对框和类别是否匹配这一步能筛掉大部分低级错误。5.3 现象验证集 mAP 很高但一到实际预测就漏检原因大概率是训练集和验证集划分不当或者数据增强过强导致模型只记住了训练集的纹理分布。钢材缺陷的类内差异非常大rolled-in 和 painted 在灰度图上可能只差一点纹理方向。解决划分数据集时用sklearn的train_test_split按类别分层抽样确保每个类别在训练集占比一致。预测时不要直接拿默认置信度阈值把conf降到 0.15 试试缺陷检测场景漏检比误检代价更高。5.4 现象模型导出 ONNX 后推理结果和 PyTorch 预测完全不一致原因ONNX 导出时的输入尺寸和训练时不一致或者导出的图没有做预处理对齐。YOLOv8 的 predict 内部会自动做 letterbox 缩放但 ONNX 推理需要用同样方式预处理。解决如果只是毕业设计演示直接用yolo detect predict modelbest.pt sourceimage.jpg就够了不需要折腾 ONNX。如果确实要导出固定imgsz640并且在推理代码里用 ultralytics 自带的预处理函数保证输入分布一致。5.5 现象训练内存不足进程直接被系统杀掉原因CPU 模式下 batch 设置过大或者同时打开了很多其他程序。解决先看free -h确认剩余内存把 batch 降到 2imgsz 从 640 降到 480workers设为 0减少数据加载占用的内存。这个场景下优先保证训练能完整跑完而不是追求单次迭代处理更多图片。6. 进阶技巧让钢材缺陷检测系统再往上走一档训练收敛之后别急着收工。先用best.pt对验证集做一次批量预测把预测结果拼接成网格图逐张看误检集中在哪类缺陷上。我之前跑完第一版mAP 看着有 0.86结果可视化之后发现误检全部集中在 patches 和 painted 两种纹理相似的类别上单看指标完全发现不了。做法是把预测输出的图片写到一个目录用代码拼接成马赛克图花半小时人工核对。针对纹理相似导致误检的问题可以考虑给 YOLOv8 加入注意力机制。比较成熟的方案是在主干网络的输出位置加入 CBAM或者尝试yolov8-协调注意力的改进网上有现成的网络结构修改代码改造后训练轮数适当增加 20 轮。另一个更实用的方向是数据增强的精细化关闭 Mosaic 增强只保留轻微 HSV 扰动因为钢材表面的真实缺陷不会像日常图片那样发生大面积仿射变换过强的增强反而会掩盖缺陷纹理特征。验证方法上除了 mAP我还会统计每个类别单独的分类精确率和召回率做成一张表格。钢材缺陷检测的最终评价标准不是平均 mAP而是最差的那个类别的检出率——硫化铁皮这个类别在光照不均匀时最容易丢单独拎出来看召回率比看整体指标有价值得多。从那以后我每次做这类检测项目都强制走一遍可视化核对、类别分组指标计算和增强策略复验这三步宁可多花两小时也不直接交一版黑盒模型。希望帮到你。本文还有配套的精品资源点击获取
返回列表