资讯动态

YOLOv5钢材表面缺陷检测:数据集制作、模型训练与部署避坑指南

发布时间:2026/10/1 1:44:22 来源:尧图企业网站定制
简介面向钢材表面缺陷检测与YOLOv5目标检测的开发者这份源码包集成了完整的数据集与检测系统适用于工业质检场景下的缺陷识别、模型训练与算法验证也适合深度学习初学者通过真实数据动手实践。压缩包共5528个文件约28.28MB内含1800张钢材表面jpg图像、1800份xml标注文件与1806个txt标签文件完整覆盖图像、标注与类别信息同时提供33个Python脚本、26个YAML参数配置以及CMake等工程构建文件可直接用于YOLOv5环境搭建与训练调参。目前已有2514人学习浏览说明该资源具备一定参考热度。拿到后可获得端到端的数据处理与训练方案包括标签含义说明、模型配置文件、辅助脚本与跨平台编译支持目录结构按图像、标注、配置与代码分层存放便于检索省去从零采集和整理数据的耗时可快速开展缺陷检测实验或二次开发。1. YOLOv5钢材表面缺陷数据集检测系统源码先回答它解决什么问题再谈怎么跑钢材表面缺陷检测就是在产线上找出裂纹、夹杂、麻点、划伤这类瑕疵并把它们在图像里框出来。YOLOv5钢材表面缺陷数据集检测系统源码.zip 这类压缩包通常把 YOLOv5 模型、已标注的缺陷数据集、训练和推理脚本放在一起目标是让你不用从零搭环境直接用上真实工业数据。这个方向适合三类人刚入门 YOLOv5 想拿真实数据集练手的做机器视觉需要快速验证缺陷识别方案的还有准备毕业设计的学生。但“源码.zip”和“能跑起来的工程”之间往往还隔着数据格式、环境版本和训练参数三座大山。2. 钢材表面缺陷数据集怎么转成 YOLO 格式XML 解析、归一化标签与划分边界2.1 长条热轧钢板上的六类缺陷公开数据集怎么选做钢材缺陷识别最常被拿来当基线的是东北大学发布的 NEU-DET也就是在标题里说“钢材表面缺陷数据集”时九成资料指的是它。这组数据来自热轧带钢表面图像尺寸固定为 200x200共 1800 张每类缺陷 300 张。六类分别是 crazing网状裂纹、inclusion夹杂、patches斑块、pitted_surface麻点、rolled-in_scale氧化铁皮压入、scratches划伤。类别看着少但每类外观差异非常大crazing 是分散的细线pitted_surface 是密集小坑rolled-in_scale 是大块暗色斑块。同一个类别里缺陷大小跨度也大有的框只有几十个像素宽有的几乎占满整张图。这组数据的特点是“数量不大、目标偏小、背景纹理杂乱”。如果直接套通用目标检测的思路很容易遇到训练正常、到了产线场景就漏检的情况。最常用的做法是把 200x200 原图放大到 512 或 640 再喂给模型。放大到 640 意味着缺陷相对尺寸变大检测更友好代价是放大带来的插值锯齿和显存占用增加放大到 512 相对折中我在自己的实验里先跑 512因为工业现场往往还要叠加低分辨率相机512 更接近真实退化程度。另外NEU-DET 的标注是 VOC 风格 XML每个 XML 文件对应一张图像。YOLOv5 训练需要的是每张图一个同名 txt 文件每个框占一行格式为“类别索引 x_center y_center width height”四个坐标全部除以图像宽高归一化到 0 和 1 之间。如果是从零开始标注自己的钢材数据也需要转成这种格式。很多新人会把 xmin、ymin、xmax、ymax 直接写进 txtYOLO 读不了这是常见的第一道坎。2.2 编写 XML 转 YOLO 脚本处理空框与越界框常见做法是写一个一次性转换脚本扫描 XML 目录逐个把 bndbox 四坐标换算成中心点坐标和宽高。注意必须用归一化坐标否则训练读出来是超过 1 的数loss 直接飙升而且看起来像学习率问题实际是标注问题。# xml2yolo.py import os import xml.etree.ElementTree as ET CLASSES [crazing, inclusion, patches, pitted_surface, rolled-in_scale, scratches] IMG_W, IMG_H 200, 200 def convert_xml_to_yolo(xml_path, txt_path): tree ET.parse(xml_path) root tree.getroot() lines [] for obj in root.findall(object): name obj.find(name).text.strip() if name not in CLASSES: 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.0, min(xmin, IMG_W - 1)) xmax max(0.0, min(xmax, IMG_W - 1)) ymin max(0.0, min(ymin, IMG_H - 1)) ymax max(0.0, min(ymax, IMG_H - 1)) 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(txt_path, w, encodingutf-8) as f: f.write(\n.join(lines)) if __name__ __main__: xml_dir NEU-DET/ANNOTATIONS label_dir NEU-DET/labels os.makedirs(label_dir, exist_okTrue) for xml_name in os.listdir(xml_dir): if not xml_name.endswith(.xml): continue stem os.path.splitext(xml_name)[0] convert_xml_to_yolo(os.path.join(xml_dir, xml_name), os.path.join(label_dir, stem .txt))参数说明CLASSES 的顺序就是类别索引顺序。YOLO txt 里的数字 0 对应 CLASSES[0]也就是 crazing这个顺序必须和后面 data.yaml 里的 names 完全一致否则训练时类别标签是错位的。IMG_W 和 IMG_H 这里写死成 200因为 NEU-DET 固定尺寸如果是自己的产线数据集改成实际图像宽高。裁剪那四行是加的一段防御VOC XML 偶尔会出现 xmax 略大于图宽的情况不裁剪会让归一化坐标超过 1YOLO 判定为无效目标还会污染输出。转换完抽查一下。我一般会随机挑三五张图把同名的 txt 打印到控制台人工对一下数字是否落在 0 到 1 区间再用 OpenCV 画一次框确认。很多问题都出在序号对应错位上单独看 txt 看不出画出来就露馅。2.3 训练集、验证集的划分直接决定 mAP 可信度数据划分看起来是小事在钢材缺陷上需要注意的地方不少。第一种划分是随机划分1800 张图直接按 8:1:1 拆成 train、val、test。缺点如果同一卷钢带截出的连续图像同时被分进训练和验证模型因为“看见过邻居”而得分虚高实测 mAP 可能比换带生产时高出好几个点。第二种更严谨的是按批次划分。按钢带编号分组后再切分 train 和 val让验证集里不出现同一卷钢带下的相邻图像。钢材表面纹理连续性很强我推荐按批次划分这样验证结果更接近真实产线不会出现评估很漂亮、上机就翻车的尴尬。划分时还需要保证每个类别在 train 和 val 里都出现。NEU-DET 各类别均匀问题不大但自己去现场标数据时可能有 patched 类只有几十张随机划分就要做分层抽样。划分脚本参考下面这段# split_data.py import os import random from shutil import copy images sorted(os.listdir(NEU-DET/IMAGES)) random.seed(2024) random.shuffle(images) n len(images) train_imgs images[:int(n * 0.8)] val_imgs images[int(n * 0.8):int(n * 0.9)] test_imgs images[int(n * 0.9):] for split, imgs in [(train, train_imgs), (val, val_imgs), (test, test_imgs)]: for img in imgs: stem os.path.splitext(img)[0] copy(os.path.join(NEU-DET/IMAGES, img), os.path.join(NEU-DET/images, split, img)) copy(os.path.join(NEU-DET/labels, stem .txt), os.path.join(NEU-DET/labels, split, stem .txt))这段代码会在 images 和 labels 两侧同时把同一份文件分配到对应 split 目录避免出现“图像有、标签没有”的漏配。如果你不复制而是用软链接也必须在两个目录同时建链接。YOLOv5 读 label 是拿图像路径替换后缀、替换目录名来定位 txt 的一个缺失就会在训练时提示找不到标签文件连带影响整个训练集统计。划分完之后再看一眼三个 split 目录里的文件数量train 约 1440 张val 约 180 张test 约 180 张。数量对不对不重要重要的是没有空目录也没有某类只在 train 里出现的情况。3. YOLOv5 环境配置与源码目录关系conda 安装、requirements 顺序、data.yaml 别写错3.1 用 conda 建独立 Python 环境PyTorch 和 torchvision 必须成对出现拿到这类源码第一件事不是急着开 train.py而是把 Python 环境搭干净。我习惯用 conda因为它能隔离同一台机器上不同项目的依赖避免“装好新项目炸掉老项目”的常见事故。conda create -n yolo5 python3.9 -y conda activate yolo5 pip install torch1.13.1 torchvision0.14.1 cd yolov5 pip install -r requirements.txtPython 3.9 对 YOLOv5 比较友好太高或太低都可能遇到 numpy 和 opencv 的二进制兼容问题。torch 和 torchvision 的版本必须一前一后对齐torch1.13.1 对应 torchvision0.14.1这是 PyTorch 官方约定。错开一位就容易出现cannot import name functional_pauli from torchvision.transforms这类表面上跟算子无关、实际上版本错乱的报错而且往往在跑数据增强那段才崩排查起来特别费时间。如果本机已经装好 CUDA 11.7也可以用pip install torch1.13.1cu117 torchvision0.14.1cu117指定带后缀的版本。没有特殊需求时直接用默认版本即可。装完验一下python -c import torch, torchvision; print(torch.__version__, torchvision.__version__) python -c print(torch.cuda.is_available())第一行打印的版本要匹配第二行返回 True 再继续否则后面训练会在设备分配时报错。3.2 requirements 安装顺序为什么先装 torch 再装其它依赖YOLOv5 的 requirements.txt 会列一堆包opencv-python、numpy、matplotlib、seaborn、pandas、pyyaml、tqdm、requests、scipy 等。直接pip install -r requirements.txt在多数情况下也能成功但遇到问题时会非常难定位。先装 PyTorch 再装其余依赖能让 torchvision 里绑定的 numpy 扩展按正确版本生成。如果先装好 numpy再装 torch 把 numpy 版本顶掉OpenCV 和 matplotlib 就可能因为 C 扩展链接关系出现段错误。pip install numpy1.23.5 pip install opencv-python4.8.0.74 pip install -r requirements.txt很多排查现场里更常见的是ImportError: libGL.so.1: cannot open shared object file。这是 opencv 缺少系统图形库和 pip 无关发生在纯容器或精简 Linux 系统上。解决方法是安装系统库apt-get install -y libgl1 libglib2.0-0。这条在部署阶段几乎是必踩的坑值得提前装掉。3.3 源码目录与自建数据集的位置data.yaml 怎么写不会迷路下载的 YOLOv5 源码解压后标准目录骨架大概是yolov5/ ├── train.py ├── detect.py ├── val.py ├── export.py ├── data/ # 数据集配置模板 ├── models/ # 模型结构 yaml ├── utils/ # 训练与推理工具 ├── runs/ # 训练结果输出目录 └── requirements.txt这是通用组织方式不要把自建数据直接丢进yolov5/data下面它容易和官方模板混在一起更不要在 data 下放图像和标签混合的目录。惯常做法是让数据集独立放在和yolov5/平级的NEU-DET/目录下再写一个data.yaml指过去。# NEU-DET/data.yaml path: ./NEU-DET train: images/train val: images/val test: images/test nc: 6 names: - crazing - inclusion - patches - pitted_surface - rolled-in_scale - scratchespath是数据根目录train、val、test 写相对 path 的相对路径。YOLOv5 部分版本支持path字段如果报路径解析错误可以去掉 path直接写train: ./NEU-DET/images/train。nc必须和 names 长度一致多一个少一个都会在训练启动时被断言拦下。这个断言信息写得比较简短新手常看不出原因其实只要数一下 names 数量就好。检查标签路径是否命中YOLOv5 读标签时会用训目标图像目录去推导同级 labels 目录。例如图像在NEU-DET/images/train/crazing_003.jpg它就会去NEU-DET/labels/train/crazing_003.txt找标注。这就要求 images 和 labels 的二级目录结构完全并列一个叫 train 另一个也叫 train不能一个叫 train 一个叫 train_txt后缀不同直接找不到。4. 训练钢材缺陷检测模型train.py 参数选择、超参数调整和结果解读4.1 用预训练权重做迁移学习batch 和 imgsz 的基本设定直接从零训练在小数据集上划不来。NEU-DET 只有 1800 张从随机初始化开始至少要跑几百轮才能收敛而 YOLOv5 官方在 COCO 上预训练好的yolov5s.pt已经具备通用特征提取能力在工业缺陷数据上做 100 轮微调就能达到不错的 mAP。所以训练一个实用的检测系统标准做法是python train.py \ --data NEU-DET/data.yaml \ --weights yolov5s.pt \ --img 512 \ --batch-size 16 \ --epochs 100 \ --workers 4 \ --project runs/train_steel \ --name exp01 \ --cache--img是训练输入尺寸默认值 640。这里故意调到 512因为原始图只有 200x200放大到 512 相当于 2.5 倍既能保住缺陷纹理又不至于让显存像用 640 那样紧张。如果显卡是 8GBbatch 从 16 降到 8 也还能跑。batch-size 不是越大越好这批数据类别少、目标小batch 加大会让梯度方向更平滑但显存空间也吃得更紧无法再同时把--img调大。--cache在数据量小的时候值得开着。它会把图像以内存或磁盘缓存方式加载减少每次 epoch 的 I/O。钢材图像是灰度单通道缓存占用不大开了之后每次训练能省不少时间。--project和--name是输出目录的定制。默认输出在runs/train/exp第二次跑会变成exp2非常混乱。改成train_steel加exp01递增后面翻混淆矩阵和 PR 曲线时一眼能认出哪轮用了什么参数。4.2 针对钢材场景调超参数关闭颜色增强降低 mosaic 概率YOLOv5 的默认超参数写在data/hyps/hyp.scratch-low.yaml。更可控的做法是复制一份命名为hyp.steel.yaml用--hyp hyp.steel.yaml指定。下面是一份我在钢材缺陷上常用的改法# hyp.steel.yaml lr0: 0.01 lrf: 0.2 momentum: 0.937 weight_decay: 0.0005 warmup_epochs: 3.0 warmup_momentum: 0.8 box: 0.05 cls: 0.5 obj: 1.0 mosaic: 0.3 hsv_h: 0.0 hsv_s: 0.0 hsv_v: 0.0 translate: 0.1 scale: 0.5 fliplr: 0.0 flipud: 0.0为什么要这样改钢材表面缺陷通常在灰度域上表现明显色彩空间没有可学信息关闭 hsv 三个通道能减少增强带来的随机噪声让模型更关注形状和纹理。fliplr 和 flipud 对方向性缺陷有风险crazing 一般是沿轧制方向的微小裂纹如果左右翻转模型会把“裂纹方向”和“背景条状纹理”混淆所以全部关掉。mosaic 从默认 1.0 降成 0.3是因为 mosaic 会把任意四张图拼在一起在自然图像上有效但钢板背景高度相似拼接产生的大量伪边界会让模型额外学习“背景过渡线”南辕北辙。超参数不是越多改越好。只拿训练损失来评估调参也片面要同时看 val 损失。如果 train loss 一直在降、val loss 从某个 epoch 开始反弹那先理解为过拟合信号而不是超参数没调好。1800 张图跑到 120 轮左右mAP50 基本走平。也有人对钢材数据把 cls 调到 0.7 来强调分类但这对外观相近的 crazing 和 scratches 反而有副作用除非确认混淆矩阵里分类错误占主导保守起见用 0.5。4.3 训练输出怎么看results.csv、混淆矩阵与 PR 曲线训练结束后runs/train_steel/exp01/下会出现一批文件weights/best.pt、weights/last.pt、results.csv、results.png、confusion_matrix.png、PR_curve.png等。results.csv每一行代表一个 epoch列包含metrics/mAP_0.5、metrics/mAP_0.5:0.95、val/box_loss等。先盯着 mAP50 和 mAP50-95mAP50 衡量框和类别是否大致命中mAP50-95 对框定位精度更严格。钢材缺陷里小目标多如果 mAP50 高但 mAP50-95 偏低说明预测框定位精度没到“精准”级别运行时需要调整 NMS或者重新考虑训练尺寸。混淆矩阵能指出哪两类缺陷互相“认错”。我见过 crazing 和 scratches 的混淆最多因为它们都是线状缺陷区别只是纹理深度和连续性。如果这两类互相串只调 NMS 上限不会好应该回查标注看是不是部分框画得太宽松把背景纹理也包进去了。PR_curve.png里每个类的曲线会不同。rolled-in_scale 是大块目标曲线通常很漂亮crazing 的曲线会掉得快说明它夹带的背景像素多误报也多。这些图表不是用来“看个结果”的是决定要不要回去改标注、改数据增强的依据。5. 钢材缺陷检测项目避坑指南五个最容易翻车的地方和现场解决记录5.1 现象PyTorch 装好后一 import torchvision 就报模块找不到原因torchvision 版本和 torch 没有对齐。很多人先pip install torch装成 2.x再装 torchvision 选了 1.x两者在底层张量实现上有差异导入到functional_pauli这类模块时直接抛异常看起来像代码问题实际是环境问题。解决在独立 conda 环境里固定 torch 和 torchvision 版本。先卸载再成对安装pip uninstall torch torchvision -y pip install torch1.13.1 torchvision0.14.1 python -c import torch, torchvision; print(torch.__version__, torchvision.__version__)如果 pip 解析时又互相顶掉用conda install pytorch1.13.1 torchvision0.14.1让 conda 做依赖解析。装完必须再验一次 import确认打印的两个版本成对。5.2 现象训练启动后 loss 一直不降前 20 个 epoch 横在 7 左右原因九成是标签问题不是学习率。YOLO 的 loss 在标签异常时会把目标置信度计算成远大于正常范围的值。常见原因有三个txt 里的坐标没有归一化出现 x_center170 这种数图像和标签没有对应上label 文件是空文件或缺失class_id 超过 nc-1。解决先抽查一批标签import os label_dir NEU-DET/labels/train for name in os.listdir(label_dir)[:10]: p os.path.join(label_dir, name) print(name, open(p).read())看打印的坐标是否都在 0 到 1 之间。如果看到class 6就说明索引越界把 data.yaml 的 names 列表和 XML 转换脚本的 CLASSES 顺序对齐即可。空文件说明 XML 解析失败回头检查name字段是否被识别。5.3 现象训练 mAP0.5 到了 0.9但拿 detect.py 检测同一批图时漏了很多小缺陷原因mAP 评估的是预测框和真实框在某个阈值下的匹配结果而 detect.py 默认的--conf-thres 0.25会把大量低置信度的小目标框过滤掉。钢材表面缺陷密集且尺寸小一个缺陷周围可能产生十几个候选框NMS 在 IOU 阈值 0.45 时把相邻的真缺陷框合并掉导致漏检。解决跑推理时把置信度阈值调低IOU 阈值也调低python detect.py \ --weights runs/train_steel/exp01/weights/best.pt \ --source NEU-DET/images/test \ --img 512 \ --conf-thres 0.08 \ --iou-thres 0.35 \ --save-txt参数说明--conf-thres从默认 0.25 降到 0.08模型会保留更多低分框适合小目标密集场景。--iou-thres从 0.45 调到 0.35NMS 对重叠框更严格能把紧邻的两个真实缺陷框都保留下来。代价是会多一些重复框和误检框需要根据产线要求的精确率和召回率再平衡。5.4 现象对图像做过 CLAHE 预处理之后检测率反而骤降原因训练集和测试集上的预处理不一致。CLAHE也就是对比度受限自适应直方图均衡化对低对比度钢板很有效但如果在训练时用了某一组 clipLimit推理时用了另一组或者只对验证集做、没对训练集做模型的输入分布就不一致mAP 可能出现明显下跌。这个坑特别隐蔽因为两张图肉眼看起来差别不大。解决把 CLAHE 抽成一个复用函数训练和推理共用同一份代码# preprocess.py import cv2 def to_model_input(img, clip2.0, grid(8, 8)): clahe cv2.createCLAHE(clipLimitclip, tileGridSizegrid) # img 必须是单通道灰度图 return clahe.apply(img)参数说明clipLimit 调得越大对比度增强越强但背景噪声也会被放大。钢材表面轻微划伤时我用 2.0tileGridSize 用 8x8在 512x512 输入下足够细。如果做训练增强把它放在数据加载流程的同一位置如果做离线预处理训练和推理都要先跑一遍。5.5 现象train.py 运行时报 No labels found 或者类别数断言失败原因最常见是 images 和 labels 的路径不匹配。YOLOv5 从train字段找到图像目录然后换算到同级 labels 目录。只要一个在NEU-DET/images/train/另一个在NEU-DET/labels/train_txt/就会因为缺标签直接报错。另一个低频原因是图像后缀不统一有 jpg 也有 png脚本只处理了 jpg。解决先核对文件名和目录名再用一条命令批量检查for f in NEU-DET/images/train/*.jpg; do b$(basename $f); b${b%.jpg} [ -f NEU-DET/labels/train/$b.txt ] || echo missing: $b done如果还有 png把*.jpg换成*.jpg *.png再跑一遍。跨平台搬项目时最容易遇到Windows 下大小写不敏感目录叫Images也能读到一到 Linux 上就爆所以 data.yaml 里的路径要严格区分大小写。6. 部署验证技巧批量推理与 ONNX 导出先用一张“认得的图”把关训练完成后不要只看 mAP 数字。我习惯的做法是拿一张自己亲手标过、知道每个缺陷在哪里的原图跑一遍 detect.py再人工数一遍图上真实缺陷有多少个模型框出了几个多框的和漏框的各是什么类别。如果真实缺陷 20 个模型只出 15 个优先怀疑漏检如果多出 5 个框优先怀疑误检。这个步骤永远最先做因为它是成本最低的“模型有没有学歪”体检。推理命令保持和训练一致的图像尺寸python detect.py \ --weights runs/train_steel/exp01/weights/best.pt \ --source NEU-DET/images/test \ --data NEU-DET/data.yaml \ --img 512 \ --conf-thres 0.08 \ --iou-thres 0.35 \ --save-txt--save-txt会同时把检测结果写成一个 txt方便和标注文件做逐行对比而不只是看图。输出在runs/detect/exp下第一轮是 exp第二轮是 exp2按需改名。如果要嵌入现有质检系统建议把 best.pt 导出成 ONNX用 ONNX Runtime 做后续推理不必在产线机器上再搭一套 Python 训练环境。python export.py \ --weights runs/train_steel/exp01/weights/best.pt \ --include onnx \ --img 512导出后先确认输出的 shape 和置信度格式再用 ONNX Runtime 跑一遍上面那张“认得”的图看结果和 PyTorch 推理是否一致。不一致时基本都是预处理差异尤其是灰度图转三通道的方式。我现在的习惯是每次拿到一份钢材缺陷检测源码不管对方声称训练效果多好第一件事永远是找一张自己标过、知道答案的图跑完一遍对比框再谈其它。这个动作帮我挡掉过不少次“mAP 很高、现场不认”的返工。检测系统的短板经常在数据和阈值匹配上模型只是其中一环先盯住这一环后面的事就顺了。希望帮到你。本文还有配套的精品资源点击获取

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑