铝片表面缺陷检测实战:YOLOv5数据集结构与训练避坑指南

发布时间:2026/10/5 0:39:08
铝片表面缺陷检测实战:YOLOv5数据集结构与训练避坑指南 简介一份面向铝片表面缺陷检测的目标检测数据集采用YOLOv5标准目录结构图像为640×480的RGB图片覆盖针孔、擦伤、脏污、褶皱四个常见缺陷类别。数据已按训练集与验证集划分训练集含1120张图片及对应标签验证集含280张图片及对应标签分别存放在独立子目录中标签文件与图像一一对应可直接用于目标检测模型训练与评估。压缩包共2000个文件以txt标注文件、jpg图像和Python可视化脚本为主要类型整体约82MB标注文件为YOLO格式边界框Python脚本无需修改即可随机读图并绘制检测框便于快速检查标注质量。作为工业表面缺陷识别方向的现成数据资源免去了自行采集、清洗与格式转换的环节既适合初学者快速跑通YOLOv5流程也方便工程师直接开展铝材质检模型实验。已有195人学习下载。1. 铝片缺陷检测数据集YOLOv5 目录格式解压后直接当训练数据用做铝材表面质检的同行应该都有体会目标检测项目里最耗时的不是调模型而是整理数据。这套数据集就是冲着这个痛点来的——铝片表面 4 类缺陷针孔、擦伤、脏污、褶皱640×480 分辨率训练集 1120 张、验证集 280 张标签全部转成了 YOLOv5 的 txt 格式压缩包 82MB解压就能用。对刚接触 YOLOv5 的入门者来说尤其友好不用自己装 LabelImg 重新标一遍也不用写格式转换脚本。本文会拆目录结构、讲标签含义、跑可视化脚本、给训练命令最后把最容易翻车的几个坑列出来。2. 数据集内部结构与 YOLOv5 标签约定先看清目录再决定怎么训2.1 目录树images 与 labels 同级文件名一一对应YOLOv5 官方仓库对数据集目录有固定约定这套数据严格按这个约定组织。解压后第一层是 datasets 文件夹里面分成 images 和 labels 两个大区再往下按 train / val 划分。图片是 640×480 的 RGB JPG标签是同名的 .txt 纯文本文件。这意味着训练和验证时YOLOv5 的 dataloader 不需要做任何路径映射直接就能找到对应标签。路径内容数量datasets/images/train/训练集图片.jpg1120datasets/images/val/验证集图片.jpg280datasets/labels/train/训练集标签.txt与图片同名1120datasets/labels/val/验证集标签.txt与图片同名280文件命名是一一对应的比如训练集里有一张1310.jpg那么在 labels/train 下就必然有一个1310.txt。我拿到数据集后的习惯是先随机抽 5 对同名文件核对一下防止出现“图片有但标签缺失”这类低级问题。如果你解压后看到的目录层级比这深一两层比如datasets/images/train外面还套了日期文件夹原理是一样的只要改 data.yaml 里的路径就行。2.2 标签 txt 每行五个数类别 id、中心点坐标、宽高YOLO 格式的标签不是给人看的是给模型看的。每一行对应图上的一个目标框五个数字分别是类别 id、归一化后的中心点 x、中心点 y、框宽度 w、框高度 h。注意这里全部是比例值范围在 0 到 1 之间而不是像素值。拿一张图举例假设 1310.jpg 上有两处缺陷一个针孔和一个褶皱打开对应的 1310.txt 会看到类似下面两行0 0.523438 0.615625 0.078125 0.120833 3 0.730469 0.352083 0.046875 0.089583第一行的0代表类别 id 为 0对应针孔后面四个数是框的中心和大小。这个格式训练时不需要再转换但手工核对时容易懵0.523438 到底是什么位置换算回去才知道中心点 x 乘以图片宽度 640得到约 335 像素中心点 y 乘以高度 480得到约 295 像素。这套归一化坐标的好处是分辨率无关同样的标注在 640×480 下训完换成 1280×960 的图也不会错位。如果你手头有别的工具标出来的像素坐标想转成这种格式公式其实很简单import cv2 img cv2.imread(1310.jpg) h, w img.shape[:2] # 假设你在图上标了一个像素框左上角(320,180)右下角(370,238) x1, y1, x2, y2 320, 180, 370, 238 x_center ((x1 x2) / 2) / w y_center ((y1 y2) / 2) / h box_w (x2 - x1) / w box_h (y2 - y1) / h # 最后写进txt的一行类别id 上述四个值参数说明分母一定是图片的实际宽高不是网络输入尺寸。比如训练时你设--img 640原图 640×480 可能被 letterbox 成 640×640但标签已经是归一化坐标了模型内部会自己处理缩放不需要你改。这也是为什么 YOLO 格式能成为事实标准的原因之一——标签与输入分辨率解耦。2.3 类别 txt 文本文件顺序决定 data.yaml 的 names数据集里附带 4 个类别 txt 文本文件分别对应四个缺陷类别。这个细节容易忽略但它直接决定了训练时 data.yaml 里names的书写顺序。我按描述顺序推断类别 id 的约定是0-针孔、1-擦伤、2-脏污、3-褶皱。你训练前一定要打开一个标签 txt 确认一下看 id 为 0 的那行对应的到底是不是针孔。方法很简单抽一张只含单类缺陷的图可视化后看框上标注的名字和第 3.1 节的脚本逻辑一致即可。顺序一旦搞错训练不会报错但预测出来的类别名全是错位的这种问题最隐蔽。顺带提醒一句yaml 里的names建议直接用英文或拼音不要写中文。OpenCV 画框时中文会显示成乱码方块排查起来很麻烦我一般习惯在 yaml 里用pinhole, scratch, dirty, wrinkle展示的时候再映射成中文。3. 可视化脚本实测下载后先画几张图别急着开训3.1 脚本逻辑读 txt、解析坐标、按比例还原像素并画框这套数据带一个可视化 py 脚本官方描述是“随机传入一张图片即可绘制边界框并且保存在当前目录脚本无需更改可以直接运行”。我拆数据时习惯先看脚本逻辑再动手它的核心流程其实很固定读取图片尺寸、加载同名 txt、把归一化坐标乘回像素值、用 OpenCV 画矩形框和类别名、最后保存到当前目录。我按常见实现还原一下核心逻辑帮助你理解脚本内部做了什么# visualize.py 的核心逻辑从txt读取目标框并绘制到原图 import cv2 import sys # 注意类别顺序必须和 data.yaml 里的 names 保持一致 label_names [pinhole, scratch, dirty, wrinkle] def draw_boxes(img_path, label_path, save_nameoutput.jpg): img cv2.imread(img_path) h, w img.shape[:2] with open(label_path, r, encodingutf-8) as f: for line in f: parts line.strip().split() if len(parts) 5: # 跳过空行和格式异常的行 continue cls_id int(parts[0]) cx, cy, bw, bh map(float, parts[1:5]) # 归一化坐标还原成像素坐标 x1 int((cx - bw / 2) * w) y1 int((cy - bh / 2) * h) x2 int((cx bw / 2) * w) y2 int((cy bh / 2) * h) cv2.rectangle(img, (x1, y1), (x2, y2), (0, 0, 255), 2) cv2.putText(img, label_names[cls_id], (x1, y1 - 5), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 0, 255), 1) cv2.imwrite(save_name, img) print(saved to, save_name) if __name__ __main__: img_path sys.argv[1] label_path img_path.replace(images, labels).replace(.jpg, .txt) draw_boxes(img_path, label_path)逻辑说明label_path的替换逻辑依赖目录结构即images/train/xxx.jpg对应labels/train/xxx.txt这也是为什么前面强调目录结构不能乱动。归一化还原时先算中心点再加减宽高的一半得到左上角和右下角坐标OpenCV 画框需要的是这两个点。参数说明cv2.rectangle的第三、第四个参数是框的起点和终点(0,0,255) 是 BGR 颜色红色框在工业缺陷图上更醒目putText里的字体大小 0.5 适合 640×480 的图如果你把图放大到 1280字会显得偏小可以调到 0.8。另外注意replace(images, labels)只适用于该字符串第一次出现的位置如果你的路径里其他位置也含 “images” 字样会替换错这就是为什么我建议数据集路径里不要出现同名目录。3.2 运行方式命令行传图片路径结果输出在当前目录脚本是命令行运行的不需要图形界面Windows 和 Linux 都兼容。你的用法是python visualize.py datasets/images/train/1310.jpg运行结束后当前目录下会生成output.jpg用看图工具打开就能看到原图上叠加的红色框和类别名。我一般会连续跑三张以上的图而不是只看一张因为单张图可能只覆盖一两类缺陷看不出整体标注质量。3.3 依赖不齐怎么办缺 cv2 和 numpy 的常见处理最容易遇到的报错是ModuleNotFoundError: No module named cv2。原因很简单你的 Python 环境里没装 OpenCV。解决方式是用 pip 安装依赖包一般我建议一次性装全pip install opencv-python numpy注意这里只需要opencv-python就够了不需要装opencv-contrib-python那个大包。装完后再跑一次可视化脚本如果还报错大概率是路径写错了检查sys.argv[1]传进去的图片路径是否真实存在。如果报错信息是UnicodeDecodeError则是 txt 编码问题这套数据用的是 UTF-8一般不会触发万一出现用codecs.open(label_path, r, utf-8)替代内置open即可。4. 训练 YOLOv5data.yaml 配置、训练命令与验证输出4.1 data.yaml路径、类别数与 names 顺序缺一不可要用 YOLOv5 训练这套数据第一步是写一个 data.yaml。这份文件告诉训练脚本数据在哪、有几个类别、类别叫什么。你可以在项目目录下新建aluminum.yaml内容如下# 铝片表面缺陷数据集配置 train: /your/absolute/path/datasets/images/train val: /your/absolute/path/datasets/images/val nc: 4 names: [pinhole, scratch, dirty, wrinkle]参数说明train和val指向的是图片目录而不是标签目录YOLOv5 会自动去同级的labels目录找同名 txt。路径建议写绝对路径写相对路径时要注意你的当前工作目录必须是 YOLOv5 仓库根目录否则会报does not exist。nc是类别数量这里是 4names的顺序必须和前面说的类别 txt 顺序一致这里再强调一遍因为这个错不报异常只会在验证时让你抓狂。这套标签格式不只适用于 YOLOv5YOLOv8、YOLOv11 的 ultralytics 仓库也用同样的五列 txt区别只是 yaml 写法稍有不同。如果你同时装了 ultralytics直接用yolo detect train dataaluminum.yaml modelyolov8s.pt也能训数据不需要二次处理。4.2 训练命令迁移学习优先cache 对小数据集提速明显我通常用官方仓库训练自己的数据集命令如下python train.py --data aluminum.yaml --weights yolov5s.pt --img 640 --batch 16 --epochs 100 --cache参数说明--weights yolov5s.pt是 COCO 预训练权重用迁移学习而不是从头训练。铝片缺陷虽然在 COCO 类别里没有但预训练模型已经学到了基础纹理和边缘特征迁移过来收敛速度快得多最终精度也更高。--img 640和原图分辨率一致不需要额外缩放。--batch 16是单卡 8GB 显存的安全值如果你只有 6GB 显存降到 8如果是 24GB 的企业卡可以开到 32 以上。--epochs 100对 1120 张训练图来说是比较合理的中等规模设置数据增强做得好的情况下不会明显欠拟合。--cache这个参数值得单独说一下。它的作用是把训练集图片一次性加载进内存减少训练时的磁盘 IO。1120 张 640×480 图片全部缓存后约占用几百 MB 内存对现在的机器毫无压力但训练速度提升非常明显尤其是机械硬盘环境下。第一次运行时会看到 caching 的进度条这是在读图不是卡住了。4.3 验证与推理val.py 看指标detect.py 直接出图训练结束后runs/train/exp/weights/下会生成best.pt和last.pt前者是在验证集上 mAP 最高的权重后者是最后一轮的权重。正式评估用best.ptpython val.py --data aluminum.yaml --weights runs/train/exp/weights/best.pt --img 640 --conf-thres 0.25运行结果会打印每个类别的精确率、召回率和 mAP同时在runs/val/exp/下生成 PR 曲线和混淆矩阵图片。重点看针孔类别的 AP通常这个类目标小数值会明显低于其他三类如果低到 0.5 以下参考第 5.3 节的处理方法。要看实际检测效果用 detect 脚本对单张图片推理python detect.py --weights runs/train/exp/weights/best.pt --source datasets/images/val/663.jpg --save-txt --save-conf--save-txt会把每个检测框的类别和置信度写成 txt--save-conf在框上额外显示置信度数值。标注后的图片保存在runs/detect/exp/下。我习惯把训练集、验证集各抽一张对比看如果验证集上的检测框贴合度高说明模型泛化正常如果只有训练集效果好验证集一塌糊涂那就是过拟合回到第 5.4 节排查。5. 铝片缺陷实测避坑指南从类别 id 到小目标漏检的血泪经验5.1 用看图软件打开标签文件误以为标注全部丢失现象把1310.txt拖进图片查看器显示“无法打开文件”或一片乱码第一反应是数据作者没给标签差点把整个数据集删了重新标注。原因YOLO 标签是纯文本文件系统默认的图片查看器根本不认识它。这不是数据问题是打开方式不对。解决用 VS Code 或 Notepad 打开 txt看到每行五个数就正常。更靠谱的验证方式是跑第 3 章的可视化脚本直接在图上画框一眼就能判断标注到底在不在。从那以后我再也不用手工打开标签了一律脚本说话。5.2 类别 id 与 yaml 顺序不一致训练不报错但验证全错位现象训练时 loss 正常下降mAP 数值也不低但打开推理结果一看图上是褶皱的区域框上标的确是“pinhole”字样四个类别的名字整体错位。原因txt 里的类别 id 是数据集作者按自己的顺序定义的而我写 data.yaml 时只盯着一张某类缺陷的图确认了 id没有全局核对。比如作者定义的 id 1 是擦伤我以为 id 1 是脏污后续所有类别全部偏移。解决训练前写一个 10 行的小脚本统计训练集 labels 目录下所有 txt 里每个类别 id 出现的次数再和 4 个类别 txt 文件名逐一比对。如果 id 0 到 3 的数量分布明显不均结合可视化脚本对单类图片抽样验证。我自己现在每换一个数据集都强制先跑这一步5 分钟能省下后面一整天的返工。5.3 针孔类目标太小训练完 mAP 比其他类低一大截现象训练 100 轮后擦伤、脏污、褶皱的 mAP 都在 0.85 以上针孔只有 0.5 左右。查看检测结果针孔要么没框上要么框的位置偏了半个孔位。原因针孔在 640×480 的图里往往只有 10 到 20 个像素宽经过 YOLOv5 的 5 次下采样后在特征图上只剩两三个像素信息几乎丢失了。这属于小目标检测的固有问题不是数据集标错了。解决我一般分三步走。第一步训练时把--img从 640 提到 960代价是显存占用增加但小目标特征更完整第二步如果显存不够用 SAHI 这类切图工具把原图切成几块分别推理再合并结果针孔这种极小目标非常吃这套第三步在数据增强配置里关闭或调低mosaic的缩放幅度因为 mosaic 随机缩放过狠时针孔会缩到 3 像素以内相当于被增强策略抹掉了。这套组合拳下来针孔的 mAP 通常能拉回来 10 到 15 个点。5.4 训练集只有 1120 张直接从头训练必过拟合现象前 30 轮 train loss 一直在降val loss 也跟上去了但 40 轮以后 train loss 还在降val loss 开始在 0.02 附近反复震荡、不再下降说明模型开始背训练集了。原因1120 张图对目标检测来说属于小规模数据集尤其缺陷类别的形态变化有限模型很快就把训练样本的细节记死了。解决用 COCO 预训练权重第 4.2 节命令默认就是这么做的做迁移学习同时把学习率适当降低YOLOv5 默认 lr 是 0.01数据量小时我会改成 0.005 或 0.001。另外把训练轮数从 100 调到 150配合更强的增强策略比如开启--augment让模型看到更多样本变体。如果你有同类的无标注铝片图可以先用训练好的模型跑一批伪标注人工挑出置信度高的补充进训练集这是工业缺陷检测很常见的数据扩充手段。6. 十分钟验证数据集可视化、短训练、单图推理三步走拿到这套数据后建议你先别急着跑 100 轮。十分钟以内做三件事就能判断数据能不能用、训练链路通不通、模型有没有基本效果。第一步可视化抽样。从训练集和验证集各随机抽两张图跑第 3 章的 visualize 脚本确认每张图上的框贴合缺陷位置、类别名正确。这一步能剔除最大的隐患标注错位和路径错误。python visualize.py datasets/images/train/1310.jpg python visualize.py datasets/images/val/663.jpg第二步短训练验证链路。只跑 5 个 epoch用 COCO 预训练权重python train.py --data aluminum.yaml --weights yolov5s.pt --img 640 --batch 16 --epochs 5这里不看精度只看 loss 曲线。如果 5 轮内 loss 从初始值明显下降说明数据读取、标签解析、类别映射全是通的如果 loss 纹丝不动多半是标签内容和 yaml 配置对不上回到第 5.2 节排查。第三步单图推理。用刚才短训练产出的 last.pt 跑 detectpython detect.py --weights runs/train/exp/weights/last.pt --source datasets/images/val/663.jpg --save-conf哪怕模型只训了 5 轮COCO 预训练权重带来的先验能力也足以让它在缺陷图上画出一些合理的候选框。打开runs/detect/exp/里的输出图如果图上能找到框、框的位置基本在缺陷区域附近整个链路就算通了接下来再启动 100 轮正式训练。从那以后我每次拿到陌生的目标检测数据集都强制走一遍“可视化 → 短训练 → 单图推理”这个十分钟流程它已经成了我判断数据可用性的默认动作。这套流程筛掉了不少看起来正常、实际标签错乱的数据集也帮我省下了大量盲目训练浪费的 GPU 时间。这套铝片缺陷数据是少见的开箱即用型你拿到后按这个流程验证一遍心里就有底了。希望帮到你。本文还有配套的精品资源点击获取