ARTICLE DETAIL

资讯详情

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

带钢表面缺陷数据集与YOLO训练全流程:从标注到部署

带钢表面缺陷数据集与YOLO训练全流程:从标注到部署 简介一份面向目标检测实践与课程设计的带钢表面缺陷数据集包含1800张已标注图像及对应的XML标注文件标注框质量高可直接用于YOLO系列模型训练与验证。资源包内文件约2000个主要由JPG图像、XML标注和BMP格式存档组成压缩包大小约78.62MB既适合计算机、电子信息工程、数学等专业学生完成期末大作业或毕业设计也适合初学者快速上手目标检测全流程。图像覆盖多种典型带钢表面缺陷场景标注信息完整省去手动采集与标注的时间成本配套的标注文件可帮助理解XML标注与YOLO训练所需的标签组织方式。目前已有1028人学习对于需要高质量数据集支撑算法实验的读者而言是一份即下即用的实践资源。1. 带钢表面缺陷数据集给 YOLO 直接喂标注好的 1800 张图省掉最耗时的环节做工业视觉检测的人都知道带钢表面缺陷检测是 YOLO 系列落地最频繁的场景之一——氧化皮、夹杂、斑块这些缺陷在热轧产线上每秒都在产生人工目检根本盯不过来。但真正动手训练时最卡脖子的不是模型选型而是数据带钢表面缺陷的公开数据集本来就少能找到的又多半是未标注的原图每张图需要自己用 LabelImg 框缺陷、分类别、生成 XML1800 张图光标注就得干一两个星期标完还得检查框准不准。这份资源解决的就是这个问题1800 张已标注图像直接打包XML 标注文件齐全下载解压后就能跑通 YOLO 的训练全流程。如果你是做课程设计、毕业设计或者刚接触目标检测想找个干净数据集练手它可以直接省掉数据准备这个最没技术含量却又最耗时的环节把精力留给模型训练和调参本身。2. 数据集解剖从文件名反推标注逻辑看缺陷类型分布与标注质量拿到数据集压缩包解压后第一件事不是急着训练而是先弄清楚里面的图像长什么样、标注文件的结构是什么。这决定了你在 YOLO 训练参数里怎么设置类别数、怎么划分训练集和验证集。2.1 图像尺寸与缺陷类型的对应关系格式统一的底层保障先看文件名。压缩包里的图像是 BMP 格式文件名本身带着类别信息Sc_109.bmp、PS_186.bmp、In_145.bmp这种前缀是缺陷类别的缩写——Sc 对应氧化皮Scale、In 对应夹杂Inclusion、PS 对应斑块Patching等常见带钢表面缺陷。每个类别后面跟的数字是图像编号同类缺陷的图片连号排列说明原始数据采集时是按缺陷类型分批次拍摄的。一位经验丰富的算法工程师分析这类数据集时习惯先抽几张图用cv2.imread读一下尺寸和通道数因为带钢表面缺陷图像的尺寸并不统一有的数据集是 512×512有的采集自 CCD 相机分辨率更高。我一般会写一个脚本批量统计所有图像的宽高确认数据集的统一性然后再决定用哪个 YOLO 模型的输入尺寸。import cv2 import os from collections import Counter image_dir ./images # 换成实际解压路径 size_counter Counter() for fname in os.listdir(image_dir): if not fname.endswith(.bmp): continue img cv2.imread(os.path.join(image_dir, fname)) if img is None: print(f读取失败: {fname}) continue h, w img.shape[:2] size_counter[(w, h)] 1 for k, v in size_counter.items(): print(f尺寸 {k[0]}x{k[1]}: {v} 张)这个脚本跑完后能立刻看到数据集是不是统一尺寸。如果是统一的比如全都是 512×512后面 YOLO 训练时的图像缩放参数就很好设如果尺寸不一致则需要在data.yaml里设置合理的imgsz让 YOLO 在训练时自动做 letterbox 填充而不变形。同时统计尺寸分布也能提前发现异常图——比如某张图分辨率特别小那它在缩放后缺陷会变得极不明显容易被模型漏检需要考虑是否直接剔除。2.2 XML 标注文件的内部结构读一次就知道框的质量项目说明里强调“标注框质量高”这个不能光听作者说得自己验证。XML 标注文件通常是 Pascal VOC 格式结构很清晰annotation根节点下是size记录图像宽高object节点记录每个缺陷框的类别名和bndbox边界框坐标。用一个简单的 Python 脚本随机抽 5 个 XML 文件打印object里的所有字段就能判断标注是否符合预期。import xml.etree.ElementTree as ET xml_files [Sc_109.xml, PS_186.xml, In_145.xml] base_path ./annotations # 换成实际路径 for f in xml_files: tree ET.parse(os.path.join(base_path, f)) root tree.getroot() print(f文件: {f}, 图像尺寸: {root.findtext(size/width)}x{root.findtext(size/height)}) for obj in root.findall(object): name obj.findtext(name) bbox obj.find(bndbox) xmin float(bbox.findtext(xmin)) ymin float(bbox.findtext(ymin)) xmax float(bbox.findtext(xmax)) ymax float(bbox.findtext(ymax)) w xmax - xmin h ymax - ymin print(f 类别: {name}, 坐标: ({xmin:.1f}, {ymin:.1f}) - ({xmax:.1f}, {ymax:.1f}), 宽: {w:.1f}, 高: {h:.1f})正常情况下打印出来的边界框横纵比会集中在某个合理区间比如氧化皮通常是被拉长的条状宽度明显大于高度夹杂则是小而圆的点状。如果发现大量框的宽度或高度小于 5 个像素说明该数据集的标注框有小目标偏多的特点训练时需要重点处理小目标检测层。如果发现有些 XML 里xmin比xmax还大或者坐标超出图像边界说明标注有脏数据后面需要清理。2.3 缺陷检测场景的标注特点为什么工业缺陷框和通用目标框不一样带钢表面缺陷标注和 COCO 数据集里的自然图像标注有本质区别。自然图像里的人物、车辆、猫狗通常边缘清晰、形状完整标注框套得松松垮垮不影响训练但带钢缺陷是连续的纹理异常比如氧化皮在灰度图上是一片灰度值比较低的不规则区域夹杂则是一条细长的线状结构标注框稍微偏一点框内就会混入大量正常背景模型学到的特征就不纯。所以查看这份数据集的标注框时我会额外关注两个指标一是框的面积占比是不是普遍偏小说明小目标多二是框和缺陷实际形状的贴合度——理想情况下标注框应该是缺陷的最小外接矩形。用上面脚本算出的宽高比如果大量接近于 1说明是正方形小框对应的是点状夹杂类缺陷这部分目标在 YOLO 下采样时很容易丢失特征训练时得靠数据增强里的随机裁剪来补偿。3. 把 VOC 格式转成 YOLO 格式转换脚本与四个边界坑YOLO 训练时读取的不是 XML而是每个图像对应一个同名 TXT 文件里面每行是class_id cx cy w h且都是相对于图像宽高的归一化数值。所以拿到这份数据集后第一步不是急着配环境而是写一个转换脚本把 XML 全部转成 YOLO 要的 TXT。3.1 转换脚本核心逻辑与逐行拆解转换逻辑分四步读取 XML → 解析所有object→ 将绝对像素坐标归一化 → 写入同名 TXT。看起来简单但写起来有几个必须注意的细节尤其分母用的是图像真实宽高不是 416 或 640。import xml.etree.ElementTree as ET import os voc_xml_dir ./annotations # XML 文件目录 yolo_label_dir ./labels # 转换后输出的 TXT 目录 class_list [] # 用于记录类别名到 id 的映射 if not os.path.exists(yolo_label_dir): os.makedirs(yolo_label_dir) for xml_name in os.listdir(voc_xml_dir): if not xml_name.endswith(.xml): continue xml_path os.path.join(voc_xml_dir, xml_name) tree ET.parse(xml_path) root tree.getroot() img_w int(root.findtext(size/width)) img_h int(root.findtext(size/height)) lines [] for obj in root.findall(object): name obj.findtext(name) if name not in class_list: class_list.append(name) class_id class_list.index(name) bbox obj.find(bndbox) xmin float(bbox.findtext(xmin)) ymin float(bbox.findtext(ymin)) xmax float(bbox.findtext(xmax)) ymax float(bbox.findtext(ymax)) # 转成 YOLO 格式中心点坐标 宽高全部除以图像宽高做归一化 cx (xmin xmax) / 2.0 / img_w cy (ymin ymax) / 2.0 / img_h w (xmax - xmin) / img_w h (ymax - ymin) / img_h # 防止归一化后出现 0 或超过 1 的异常值 cx max(0.0, min(1.0, cx)) cy max(0.0, min(1.0, cy)) w max(0.0, min(1.0, w)) h max(0.0, min(1.0, h)) lines.append(f{class_id} {cx:.6f} {cy:.6f} {w:.6f} {h:.6f}) txt_name xml_name.replace(.xml, .txt) with open(os.path.join(yolo_label_dir, txt_name), w) as f: f.write(\n.join(lines)) print(f类别映射: {class_list}) print(f转换完成共处理 {len(os.listdir(voc_xml_dir))} 个 XML 文件)逻辑上有个容易被忽略的点class_list是在遍历过程中动态增长的这意味着类别 id 不是按字母序提前固定的而是按 XML 文件被os.listdir遍历到的顺序分配的。如果后续要加新类别或者换机器重跑id 顺序可能会变所以在训练前应该把这个映射表单独存下来用于后续推理时把模型输出的类别 id 映射回类别名。另一个要注意的是坐标归一化时统一除以img_w和img_h而不是除以 416 或 640。YOLO 的 label 文件要求的是相对比例模型训练时不管输入图像被缩放到多大预测出的框回算到原始分辨率时依赖的就是归一化坐标。如果这里用了固定尺寸做分母小图和大图的框比例会错乱训练直接翻车。3.2 数据划分训练集、验证集、测试集的生成策略转换完成后还要把 1800 张图按比例划分出训练集和验证集。一般我会按 8:1:1 划分训练、验证、测试而且必须随机打乱不能按文件名顺序前 80% 做训练——因为文件名是按缺陷类别连号排列的顺序切分会导致某个缺陷类别只出现在验证集里训练时模型完全没见过这个类别。import os import random import shutil image_dir ./images label_dir ./labels output_base ./dataset train_img_dir os.path.join(output_base, images/train) val_img_dir os.path.join(output_base, images/val) train_lbl_dir os.path.join(output_base, labels/train) val_lbl_dir os.path.join(output_base, labels/val) for d in [train_img_dir, val_img_dir, train_lbl_dir, val_lbl_dir]: os.makedirs(d, exist_okTrue) all_images [f for f in os.listdir(image_dir) if f.endswith(.bmp)] random.seed(42) random.shuffle(all_images) train_count int(len(all_images) * 0.8) val_count int(len(all_images) * 0.1) train_list all_images[:train_count] val_list all_images[train_count:train_count val_count] test_list all_images[train_count val_count:] for img_name in train_list: base os.path.splitext(img_name)[0] shutil.copy(os.path.join(image_dir, img_name), train_img_dir) shutil.copy(os.path.join(label_dir, base .txt), train_lbl_dir) for img_name in val_list: base os.path.splitext(img_name)[0] shutil.copy(os.path.join(image_dir, img_name), val_img_dir) shutil.copy(os.path.join(label_dir, base .txt), val_lbl_dir) print(f训练集: {len(train_list)} 张) print(f验证集: {len(val_list)} 张) print(f测试集: {len(test_list)} 张)这里random.seed(42)很重要没有固定随机种子的话每次跑脚本划分结果都不同如果读者复现你的实验并对比 mAP划分不一致会导致结果完全不可比。固定种子后训练集和验证集内容稳定后续调参时才有基准参照。shutil.copy而不是shutil.move是因为原始 XML 可能还有别的用途保留一份原档不破坏小文件总没错。3.3 验证转换结果可视化检查框与图的对应关系转换脚本跑完不能直接开训练还要可视化抽查一批结果即使最简单的办法也能发现明显问题。用 OpenCV 把 TXT 里的坐标反算回像素坐标然后画在图上能直观看出框有没有偏移、有没有错位。import cv2 import random def visualize_one(img_path, txt_path, class_names): img cv2.imread(img_path) h, w img.shape[:2] with open(txt_path, r) as f: for line in f.readlines(): parts line.strip().split() if len(parts) ! 5: continue cls_id int(parts[0]) cx float(parts[1]) * w cy float(parts[2]) * h bw float(parts[3]) * w bh float(parts[4]) * h xmin int(cx - bw / 2) ymin int(cy - bh / 2) xmax int(cx bw / 2) ymax int(cy bh / 2) color (0, 255, 0) cv2.rectangle(img, (xmin, ymin), (xmax, ymax), color, 2) cv2.putText(img, str(cls_id), (xmin, max(0, ymin - 5)), cv2.FONT_HERSHEY_SIMPLEX, 0.6, color, 2) cv2.imshow(check, img) cv2.waitKey(0) cv2.destroyAllWindows() # 随机抽一张验证集图片看一眼 vis_img random.choice(os.listdir(val_img_dir)) base os.path.splitext(vis_img)[0] visualize_one(os.path.join(val_img_dir, vis_img), os.path.join(val_lbl_dir, base .txt), class_namesNone)画出来的效果应该是每个缺陷区域被一个绿色矩形框住且框的四边紧贴缺陷边缘。如果框整体向左偏了半个身位大概率是 XML 解析时xmin和xmax对应错了如果框是整张图的大小说明归一化公式里分母用错了变量。这步可视化检查很多人嫌麻烦直接跳过但遇到训练后 mAP 奇低的情况再回头找原因就费劲了花两分钟提前验证是性价比最高的操作。4. YOLO 训练配置类别映射、模型选择与关键超参数设置XML 转 YOLO 格式并划分好数据集之后才能进入真正意义上的模型训练。YOLO 发展至今有 v5、v8、v11 等版本选哪个版本、类别映射怎么配置、训练参数怎么设直接决定训练效率和最终精度。4.1 数据集配置文件的编写告诉 YOLO“去哪里读数据、有几类”YOLO 系列训练前都要读一个数据集描述文件标准 YAML 结构。路径使用相对路径或绝对路径并把绝对路径写清晰避免换机器时反复改配置。# data.yaml path: ./dataset # 数据集根目录相对于当前工作目录 train: images/train # 训练集图片目录 val: images/val # 验证集图片目录 test: images/test # 测试集图片目录可用可不用 nc: 3 # 类别数根据实际标注的缺陷类型数量修改 names: 0: scale 1: inclusion 2: patchingpath这一项要注意区分相对路径和绝对路径。用相对路径时启动训练的终端工作目录需要与data.yaml中path的相对基准一致否则会报路径找不到的错。我的习惯是用绝对路径虽然不够优雅但不会错。nc必须和names里的条目数一致类别名最好用有意义的语义名后续推理输出和可视化时会直接显示这些名字排查问题方便。4.2 模型选择数据规模决定是选 YOLOv8n 还是 YOLOv8m1800 张图像的数据规模限制了模型容量的选择空间。这个数据量放在深度学习中不算大直接上 YOLOv8x 这种大模型很容易过拟合训练时 mAP 看似很高换到新产线上的图像就大幅下跌。我一般会从 YOLOv8n轻量版或 YOLOv8s小版起手这两种参数量适中在 1800 张图上能稳定收敛。从实操角度看YOLOv8n 权重文件大约 6MBYOLOv8s 大约 22MB在显存有限的笔记本上也能跑。课程设计或毕业设计场景通常不需要极限精度YOLOv8n 训练一个 epoch 一分钟左右20 个 epoch 跑完也就半小时能快速看到整体流程走通。如果时间充裕再用 YOLOv8s 跑一轮对比 mAP 提升幅度结论写进报告已经很有说服力。4.3 训练脚本与超参数说明以 YOLOv8 为例训练命令封装成脚本比手敲更不容易错也让后续调参变得可回溯。以下代码块中的每行参数都有它自己的说法盲目照抄会踩不少暗坑。yolo train taskdetect \ modelyolov8n.pt \ datadata.yaml \ epochs50 \ imgsz640 \ batch16 \ lr00.01 \ patience10 \ project./runs \ namesteel_surface_defecttaskdetect显式指定检测任务有些 YOLO 版本都支持taskyolo11-detection或taskobb对于当前场景写detect最稳避免因任务类型不匹配导致配置报错。modelyolov8n.pt传的是预训练权重不是从头初始化一个模型。带钢表面缺陷和自然图像虽然特征不同但预训练模型在 ImageNet 上学会的纹理、边缘、形状基础特征能迁移过来训练过程会明显加速。第一次跑没有该文件时yolo 命令会自动下载如果下载失败会直接报错后续排查会专门说这块。epochs50对于 1800 张图已经足够这类工业缺陷检测任务往往在 30 轮后 mAP 增速明显放缓50 轮属于舒适区既不会欠拟合也不会过度训练。imgsz640是训练时统一缩放到 640×640。如果原图是 512×512经过 640 的输入尺寸会有轻微的放大拉伸效果能保留更多细节。如果原图像素分布范围很大建议直接设置成数据集中最常见的分辨率否则太多图被强行缩放会引入变形伪影。batch16在 8GB 显存上能跑通理论上 batch 越大收敛越平稳但如果显存不足而强行加大训练过程中会报 CUDA out of memory直接中断。笔记本显卡先从batch8开始稳定跑起来后再加。lr00.01是初始学习率YOLOv8 默认值就是 0.01初学者不建议改动。如果训练时发现 loss 震荡明显可以降到 0.005但多数场景保持默认即可。patience10是早停参数验证集 mAP 连续 10 个 epoch 没有提升就自动停止训练。这个机制在 1800 张小数据集上特别有用因为小数据集模型很容易在 20 轮左右就收敛后续继续跑只是浪费时间早停能自动帮你把实验时间砍半。训练结束后模型保存在./runs/steel_surface_defect/weights/best.pt这就是最后需要保留的成果文件。验证集 mAP 指标会在训练日志里按 epoch 输出判断模型表现不应该只看最后的 loss而是关注mAP50和mAP50-95两组数字的走势。5. 训练避坑指南五个高频翻车点及排查思路数据集本身质量不错但这不代表训练过程一帆风顺。目标检测项目在工业缺陷数据上翻车的点不少是数据格式、环境依赖和训练设置层面的问题。以下按现象到原因再到解决的方式来写。5.1 换 xml 格式后训练直接出错解读“标签不匹配”现象运行训练命令后马上弹出类似Label image.jpeg not exist或AssertionError: class number not match的错误甚至直接报IndexError: list index out of range。原因最常见的两个来源。一是图片目录和标签目录的文件名对不上比如 XML 转换脚本里使用了xml_name.replace(.xml, .txt)但原始文件名可能还有大小写不一致的情况.BMP和.bmp导致部分 TXT 文件没生成YOLO 在读取到对应图像时找不到同名标签二是data.yaml里nc设为 4但实际转换脚本生成的类别 id 只有 0、1、2 三类或者反过来nc比实际类别数小YOLO 在预检时会做一个标签内容校验发现某个标签文件的 class id 越界就报错。解决先在命令行跑一段快速预检脚本统计所有 TXT 文件里的 class id 最大值再和data.yaml里的nc对比二者必须满足最大值 nc。同时检查 labels 目录下 TXT 文件数量与 images 目录下图像数量是否一致不一致的部分用for f in os.listdir(labels_dir)反向比对出缺少了谁再回去补转换。提示换机器或换项目文件夹后先检查转换目录有没有被复制完整有时候只拷了 images 目录、遗漏了 labels 目录YOLO 会自动跳过这些没有标签的图像最终导致训练集数量比预期少几百张。5.2 mAP 极高但检测效果差问题出在数据划分还是可视化现象训练完成后验证集 mAP50 高达 0.98但用同一张验证图跑predict模型画出的框和实际缺陷完全对不上甚至把无缺陷区域也框出来。原因这种“训练指标好看、推理效果拉胯”的矛盾几乎可以断定是数据泄露造成的。例如在划分数据集前没有做类别均衡验证集里全是某一类缺陷训练集以其他类别居多模型对验证集区域的“测试”实际上是靠记忆完成的还有一种可能是训练命令里rect参数默认被改了YOLOv8x 支持矩形训练如果输入尺寸设置不合理会把整张图按 batch 内最长边长对齐标签虽然没变但图像自身被 padding 改变了特征分布推理时按 letterbox 回算坐标出错。解决重新划分数据集并用random.seed固定划分逻辑。检查方式是对比训练集和验证集的类别数量绘制一个简单的类别直方图感受趋势是否偏差过大。如果发现某一类在验证集里数量为 0这就是数据划分的锅重新划分并强制每类按比例抽样即可。5.3 训练时 loss 为 NaN不是数据的问题是环境或参数的问题现象训练到第 5 个 epoch 左右loss 输出变成nan进度条还在继续走但每个 batch 的 loss 都是 nan训练日志输出的 mAP 始终是 0。原因int 型除零或 log 求值异常是 loss 变成 nan 的根本原因。具体到这种场景float 类型的边界框坐标除以了 0 宽高——即训练脚本读入的标签中出现了宽或高为 0 的框。来自转换脚本的早期版本没有对xmax - xmin做最小值保护某个标注框因为标注人员手滑xmax xmin归一化后宽度为 0损失函数里的 log 项直接崩溃。解决在转换脚本里加上最小宽度高度限制例如w max(1.0, xmax - xmin)再统一确保每个 TXT 内不会出现宽度为 0 的行。加了这层保护后重新转换再跑训练NaN 现象就会消失。同时建议把 batch size 适当调小防止梯度累计时某一步的异常值被放大传播。5.4 下载预训练权重时卡死或失败tp 配置不合理现象执行yolo train时模型不可用提示AutoDownload失败或一直停在下载进度条不动。原因YOLO 在启动训练时如果本地没有预训练权重则会访问远程权重仓库下载。国内网络环境访问部分境外服务器可能不稳定下载就会卡住或超时。这不是代码或者配置的错误而是网络层面的问题。解决先手动从公开镜像或国内可用源下载对应的权重文件如yolov8n.pt放到当前工作目录再执行训练命令时带上model./yolov8n.pt使用本地权重。下载完成后可以通过ls -lh确认文件大小是否与官方公布的一致比如yolov8n.pt应该约 6MB如果只有几十 KB 说明下载不完整需要重新下载。5.5 显存不足导致训练中断换小模型还是换小尺寸现象训练跑到一半报CUDA out of memory训练停掉之前跑的 epoch 全部作废。原因batch size、模型规格、输入图像尺寸三者共同决定了显存峰值。1800 张带钢图像如果是 512×512 的原图用imgsz640训练会让显存占用翻倍6GB 显存的显卡很容易被打爆。解决三个调整手段按优先级排先降 batch 到 8若仍超显存则降模型规格从yolov8m.pt换成yolov8n.pt最后实在不够就把imgsz512尽量保持原图分辨率而不要强行拉高。如果模型降级后 mAP 下降明显可以再考虑用混合精度训练参数开启后显存占用能减少 30% 左右。6. 模型评估与工业级部署用混淆矩阵挑毛病再导出成 ONNX/RKNN 跑推理模型跑完 50 个 epochbest.pt 已经生成但课程设计报告或产线试用还没结束。要评估模型到底行不行不能只看 mAP 曲线还需要具体分析它容易把哪两类缺陷搞混因为不同缺陷的产线处理策略完全不一样——氧化皮可能吹扫就能解决夹杂则需要停车检修。6.1 混淆矩阵的读取方法类别混淆背后的物理含义YOLO 训练输出目录下会生成confusion_matrix.png每行代表真实类别每列代表预测类别。矩阵里的非对角线数值高的位置就是模型系统性出错的地方。对于带钢表面缺陷最典型的一对高混淆组合是氧化皮Sc和斑块PS。这两类缺陷在灰度图中亮度分布相似形状也都有聚集趋势容易互相误判。如果混淆矩阵显示这两个类别间的数值超过 0.2可以针对性提纯这两类的训练图像或者单独增加这两类的数据增强概率用翻转、旋转、光照扰动让模型更多看到它们的区分特征。6.2 测试集推理与置信度阈值调节重新认识置信度的意义用best.pt在测试集上跑推理最初看到的结果不一定满意但不要急着给模型下结论。YOLO 默认的置信度阈值是 0.25这个值对带钢这种小目标数据集偏高大量真实缺陷被当背景过滤掉了得到的结果看起来就像模型漏检严重。我把测试集推理脚本封装成一个函数不设阈值把模型的原始输出全部保留逐个框地看置信度分数分布再统一决定切在哪。from ultralytics import YOLO model YOLO(./runs/steel_surface_defect/weights/best.pt) results model.predict( source./dataset/images/test, imgsz640, conf0.05, # 临时调低置信度保证低分框也被保留 save_txtTrue, save_confTrue )跑完后统计所有 predicted 框的置信度分布观察多少框落在 0.05 到 0.25 区间如果这部分框里有大量真实缺陷用文件名索引回原始图像人工核对就说明当前模型的置信度阈值不合适后续部署时调低到 0.15 即可。如果低置信度区间内噪声框极多超过一半都框在无缺陷区域说明模型训练还没收敛需要回到第 4 章调整 epochs 或学习率。6.3 导出 ONNX 推理格式脱离 PyTorch 环境的部署路径课程设计交付时老师或甲方可能要求在纯 CPU 环境运行。YOLO 的.pt权重是 PyTorch 格式依赖环境较重导出成 ONNX 后可以直接用 ONNX Runtime 加载推理不需要安装 PyTorch 全家桶推理速度也快不少。yolo export model./runs/steel_surface_defect/weights/best.pt \ formatonnx \ imgsz640 \ opset12导出后在同目录下生成best.onnx文件大小约比.pt小三分之一。使用 ONNX Runtime 推理时需要自己处理输入图像的预处理包括 BGR 转 RGB、归一化到 0-1、letterbox 填充到 640×640这些步骤和 YOLO 训练时的预处理保持一致模型输出也要做 NMS 后处理才能得到最终的检测框。如果这些步骤不熟建议先用onnxruntime配合 OpenCV 写一个简单的单图推理脚本跑通后再考虑其他硬件平台的部署。6.4 从固定缺陷类别扩展到新缺陷迁移学习的关键带钢表面的缺陷类型远不止这 3 到 6 种实际产线上可能还有裂纹、压痕、辊印等新类别。使用这份数据集训练出的模型在迁移到新缺陷时有一个明显的优势模型已经学会了带钢表面纹理的通用特征预训练权重本身就包含了自然图像的基础特征再加上这次训练的工业表面特征迁移起点比从零开始高得多。扩展新类别时只需要在原有数据集上追加几十张新缺陷的标注图重新生成 XML、转换 TXT、更新data.yaml中的nc和names然后像之前一样训练注意在data.yaml中把nc改成新总数不需要重头训整个模型。新类别样本数量少是正常现象通常 50 到 100 张足够让模型学会新类别的基本特征因为底层的特征提取器已经被调过了新增的只是分类头的最后一层。这个过程可以反复叠加新类别每轮训练时间比首次训练短得多。从那以后我每次做带钢缺陷数据集训练都会先跑一遍 2 章的统计脚本和可视化抽检再进入转换和训练流程这已经成了肌肉记忆。数据集的先天质量再好缺失这一步后面各种玄学问题会让你怀疑人生。希望这份数据集加这套流程能帮你在课程设计或毕业设计里少走几段弯路。本文还有配套的精品资源点击获取
返回列表