
简介面向YOLOV5目标检测应用的数据集包聚焦铝片表面缺陷识别包含针孔、擦伤、脏污、褶皱4个类别适合工业质检、缺陷检测模型训练的开发者直接使用。数据已按照YOLOV5目录规范整理无需额外格式转换其中训练集提供1120张图像及对应txt标签验证集提供280张图像及对应txt标签图像为640×480的RGB图片可有效支撑模型训练与验证评估。压缩包共含2000个文件主要由598张jpg图片、1401个txt标注文件及1个可视化py脚本构成包体大小约81.92MB结构清晰便于取用。附带的可视化脚本支持随机传入图片自动绘制边界框并保存结果可快速核对标注质量。目前已有195人学习下载适合作为铝片表面缺陷检测项目的直接数据基础。1. 铝片表面缺陷目标检测打包好的YOLOv5目录数据集能省多少事铝片表面缺陷检测卡人的往往不是模型结构而是数据。从产线拍回来的图片命名混乱、标注标准不统一、训练集验证集划分随手一拉模型在实验室 PR 曲线上漂亮一到现场就漏检。这套铝片表面缺陷目标检测数据集已经按 YOLOv5 目录格式整理完毕——4 个类别训练集、验证集分开归置拿到手就能直接喂给 train.py省掉的是图片清洗、格式转换和目录组织这一大段脏活。这篇文章写给两类人准备用 YOLOv5 训练自己铝片数据的算法工程师以及做机器视觉质检方案选型的现场工程师。标题里“YOLOV5目录格式”这几个字对应着一套具体的落地约定images 和 labels 分目录存放标签用 txt 记录归一化坐标data.yaml 声明类别。中间你会看到完整的落地路径——先做目录与标签校验再从 YOLOv5s 起步跑通训练调学习率、分辨率、锚框和样本平衡最后是五个真实踩坑记录和部署验证方法。工业表面缺陷数据和公开数据集有几个最阴间的区别正文里会一个个点出来。2. 拿到YOLOv5格式数据集后的第一件事目录结构校验与标签体检训练铝片缺陷模型第一步不是选网络而是确认你手上这套 YOLOv5 格式数据是否真的“格式正确”。工业数据集和 COCO、VOC 这类公开数据不一样标注通常来自外包团队或现场质检员类别编号错位、坐标越界、空标签文件是家常便饭。格式问题不解决训练过程会以各种诡异方式翻车轻则 loss 不降重则训练到一半直接崩掉。见过太多人拿到数据集就先 train.py跑了两天发现标签读取有错回头重来白白烧掉显卡和时间。YOLOv5 的目录约定其实非常死板images 和 labels 平行放置训练集、验证集各一份标签文件与图片文件同名同前缀扩展名改为 .txt。只要有一张图找不到对应标签训练时那批数据就会被静默跳过或引发断言错误。所以我的习惯是任何数据到手先用脚本把整份数据体检一遍再决定要不要继续往下走。2.1 标准YOLOv5目录长什么样三个目录加一个yaml一套标准的 YOLOv5 数据目录通常长这样datasets/ └── aluminum_surface/ ├── data.yaml ├── images/ │ ├── train/ │ │ ├── 0001.jpg │ │ └── ... │ └── val/ │ ├── 0801.jpg │ └── ... └── labels/ ├── train/ │ ├── 0001.txt │ └── ... └── val/ ├── 0801.txt └── ...每个 txt 文件与同名图片一一对应文件名是唯一关联键。标签文件内部是纯文本每一行描述一个目标格式固定为“类别序号 x_center y_center width height”。注意这五个值里x_center、y_center、width、height 全部是归一化到 0~1 区间的浮点数不是像素坐标。类别序号从 0 开始计数对应 data.yaml 里 names 列表的下标。data.yaml 是 YOLOv5 读取数据集的入口内容包含 train 路径、val 路径、类别数和类别名。一个容易忽略的点是路径可以是绝对路径也可以是相对路径相对路径相对于你执行训练命令的当前工作目录。如果换机器跑路径写死绝对路径会直接报 FileNotFoundError这一项在团队协作时最容易出问题。我的习惯是统一用相对路径并在训练命令里 cd 到项目根目录再执行省得反复改 yaml。2.2 标签体检脚本类别序号、坐标范围、空文件三项硬指标校验脚本不需要多复杂但必须覆盖三个硬指标类别序号是否越界、坐标是否在 0~1 区间、是否有空标签文件。另外还要检查一个软指标标签文件是否都能找到对应的图片文件。下面这段脚本是每次拿到数据后我会跑的第一段代码。# check_labels.py from pathlib import Path NUM_CLASSES 4 # 与 data.yaml 中的 nc 保持一致 def check_dataset(labels_dir: str, img_dir: str): label_files sorted(Path(labels_dir).glob(*.txt)) issues [] for lf in label_files: img_candidates [ Path(img_dir) / (lf.stem ext) for ext in (.jpg, .jpeg, .png, .bmp) ] if not any(p.exists() for p in img_candidates): issues.append(f{lf.name}: 标签存在但找不到同名图片) continue raw lf.read_text().strip() if not raw: issues.append(f{lf.name}: 空标签文件(0个目标)) continue for line in raw.splitlines(): parts line.split() if len(parts) ! 5: issues.append(f{lf.name}: {line!r} 字段数不是5) continue cls int(parts[0]) coords [float(v) for v in parts[1:]] if not (0 cls NUM_CLASSES): issues.append(f{lf.name}: 类别序号 {cls} 越界) if any(c 0.0 or c 1.0 for c in coords): issues.append(f{lf.name}: 归一化坐标越界 {coords}) return issues if __name__ __main__: problems check_dataset( datasets/aluminum_surface/labels/val, datasets/aluminum_surface/images/val ) if problems: print(f发现 {len(problems)} 个问题前 30 条) print(\n.join(problems[:30])) else: print(标签校验通过)这段脚本的核心逻辑很直接遍历 labels 目录下所有 txt一行一行拆字段。cls int(parts[0])取第一个字段作为类别序号coords [float(v) for v in parts[1:]]把后四个字段转成浮点数并检查是否落在 0~1 闭区间。这里要注意文件夹中可能同时存在 .jpg 和 .png所以图片匹配用了多种扩展名逐一尝试避免因为扩展名不一致误报“找不到图片”。空标签文件单独判一次因为read_text().strip()得到的空字符串如果直接进入循环split()会得到空列表干扰后续判断。跑这个脚本时你会立刻看清这批数据的真实状态。如果发现某张图有 6 个字段、某个标签的类别序号写成 4、或者坐标出现负数不要心存侥幸——YOLOv5 的 dataloader 在加载时不会对这些做严格校验错误标签会在训练时静默产生错误 loss最后表现为验证集指标虚高、现场表现拉胯。2.3 训练集与验证集的划分逻辑按图片随机分是最大隐患很多数据集在打包时train/val 的划分方式是全局随机抽样比如把所有图片 shuffle 后按 8:2 切。这在公开数据集上没问题但在铝片缺陷场景里会埋下一个大坑同一卷铝带、同一块铝板在连续采集时相邻帧的背景纹理、光照条件几乎一样缺陷形态也高度相似。如果这些高度相似的图片被同时分进训练集和验证集验证集就会变成“开卷考试”测出来的 mAP 虚高现场一换产线立刻原形毕露。更稳妥的划分方式是按生产批次、料卷或拍摄时段分组一个批次的图片要么全部进训练集要么全部进验证集。拿到这份数据集时可以先看一眼图片文件命名如果文件名前缀带着批次号或拍摄时间建议重新按批次维度做一次划分。另外验证集规模不要太小工业场景 4 个类别每个类别至少要保证 100 个以上的实例否则混淆矩阵会稀疏到看不出问题。铝片缺陷的类别分布天然不均衡划伤可能占 60%麻点可能只有 10%划分后最好统计一下各类别在 train 和 val 中的占比偏差过大时再做一次分层抽样。3. 用YOLOv5训练自己的铝片数据集从weights选型到第一条命令数据校验完下一步才是真正启动训练。这一章讲怎么用 YOLOv5 官方仓库把这份铝片数据集的训练跑通。很多文章默认你已经把环境装好、仓库拉下来了但实际遇到的坑大多不在网络结构上而在启动命令的细节里——预训练权重选哪个、yaml 里的路径怎么填、batch 设多大才不会爆显存。3.1 为什么从YOLOv5s起步而不是直接上YOLOv5xYOLOv5 的 s/m/l/x 四个版本本质是同一套网络结构的深度和宽度缩放。对照 yolov5 网络结构图来看s 版本的参数量约为 7Mx 版本约为 86M推理耗时相差约 5~8 倍。铝片表面缺陷检测只有 4 个类别背景相对单一就是铝片的金属纹理和光照变化缺陷形态虽然多样但类别边界清晰。这种任务复杂度下YOLOv5s 的容量已经足够m 和 l 的提升主要在极端小目标和密集场景代价是训练时间和部署成本成倍增加。另一个务实的理由是迭代速度。工业项目的瓶颈经常不在模型精度而在试错轮次YOLOv5s 在单张 2080Ti 上训练 100 epoch 大约只要 4~6 小时x 版本直接翻到 20 小时以上。快速拿到一个 baseline确认数据、标签、增强策略没问题再考虑加大模型也不迟。不要一上来就追求“大模型更准”铝片这种简单背景任务s 版本跑不出来的问题换成 x 版本大概率也跑不出来。3.2 数据配置yaml与训练命令跑通第一个epoch在 YOLOv5 仓库目录下新建或修改 data/aluminum.yaml内容如下# data/aluminum.yaml train: datasets/aluminum_surface/images/train val: datasets/aluminum_surface/images/val nc: 4 names: 0: scratch 1: dent 2: pit 3: staintrain 和 val 路径写的是相对路径相对于你执行训练命令时的目录。nc 必须与标签文件里的最大类别序号 1 相等。names 里的名称只是给人看的不影响训练结果但名称顺序必须和标签 txt 里的第一列编号一一对应——如果 labels 里类别 0 实际是划伤这里的 names[0] 就必须是 scratch。启动训练的标准命令python train.py \ --data data/aluminum.yaml \ --weights yolov5s.pt \ --img 640 \ --batch 16 \ --epochs 100 \ --name aluminum_run1--weights yolov5s.pt用的是 COCO 预训练权重首次运行会自动下载。建议保留预训练权重而不是从零训练因为预训练模型已经学到了通用特征在中小数据集上收敛更快、最终精度更高。--img 640是输入分辨率工业缺陷常涉及小目标后面会讨论是否该加高。--batch 16是单卡 batch size如果显存报 OOM优先降到 8 而不是调小图片尺寸调小图片尺寸会直接丢失缺陷细节。--name决定训练日志和权重的输出目录YOLOv5 默认输出在 runs/train/ 下用 --name 区分不同实验别偷懒省略。训练跑起来之后重点看两个曲线train loss 是否稳定下降、val mAP 是否逐步抬升。如果前 10 个 epoch mAP 还是 0不要慌YOLOv5 的 mAP 计算在早期 epoch 会偏低因为置信度阈值还没被充分校准。跑到 30~50 epoch 再看趋势才有意义。3.3 数据增强参数工业表面缺陷场景最该开和最该关的开关YOLOv5 的增强参数都集中在 hyp.scratch-low.yaml 这个文件里不修改也能训但工业表面缺陷有它自己的脾气。铝片表面是金属材质缺陷和背景的区分主要靠纹理突变和灰度差异色彩信息贡献很小而光照变化影响极大。所以 HSV 增强参数里hsv_h色相偏移和 hsv_s饱和度偏移对铝片检测的帮助非常有限金属表面本来就没有丰富色彩改了反而制造无意义的颜色变体真正有用的是 hsv_v明度偏移它能模拟现场不同角度、不同亮度的光源对提升泛化性有直接帮助。如果现场光源是暗场低角度照射划伤类缺陷常用打光方式可以把 hsv_v 从默认的 0.4 适当调到 0.5~0.6。fliplr水平翻转可以放心开铝片左右对称flipud垂直翻转要谨慎如果产线拍摄方向固定、铝带运动方向固定垂直翻转会让模型学到错误的纹理方向。mosaic 增强默认是开的它把 4 张图拼成一张好处是大幅增加单张图的目标数量坏处是会把小缺陷裁掉一半。如果数据集里缺陷尺寸本身很小mosaic 概率可以从 1.0 降到 0.5同时把 mixup 关掉避免小目标被进一步“混”没。4. 让模型在铝片数据上收敛的四个调参点把玄学变成可控训练跑通只是开始铝片缺陷检测模型的精度上限取决于后面对学习率、分辨率、锚框和样本平衡的处理。这四处是铝片这种工业表面缺陷数据上最常出问题的点也是我踩过最多坑的地方。4.1 学习率与批次大小小数据集上最怕什么YOLOv5 默认的初始学习率是 0.01配套 warmup 机制前几个 epoch 从 0.001 线性升到 0.01。这个设置在 COCO 这种大规模数据集上没问题但铝片数据集通常只有几千张图batch 也就 16 左右0.01 的初始学习率对这么小的数据量来说偏大了。最典型的症状是训练刚开始的 loss 剧烈震荡甚至前几个 epoch 就冲到 NaN。遇到这种情况直接把--lr0调低一个数量级比如--lr0 0.001。用命令行参数覆盖默认超参比改 hyp 文件更直观。batch 大小要和学习率联动batch 减半学习率最好也减半因为大 batch 的梯度更平滑可以撑住更大的学习率。如果只有单张 8G 显存的卡batch 设 8 比较稳配--lr0 0.001训练过程会安静很多。另外一个常被忽视的点是 warmup epoch 数。小数据集上模型收敛快3 个 epoch 的 warmup 有点浪费可以减到 2 甚至 1。判断标准很简单看前 10 个 epoch 的 loss 曲线如果在 0.01 学习率下 loss 还在正常下降说明没问题如果第一个 epoch loss 就飙升优先怀疑学习率。4.2 图像分辨率与锚框自适应小缺陷的命门铝片表面缺陷里划伤的宽度常常只有 2~3 个像素麻点直径更是小得可怜。在 640x640 分辨率下这些缺陷的像素面积占比可能小于 0.1%属于典型的小目标检测场景。处理方式有两种一是把--img提高到 1280二是修改锚框。前者最直接但也最费显存和时间——1280 分辨率下 batch 8 至少需要 12G 显存训练时间是 640 分辨率的 4 倍。后者更优雅。YOLOv5 训练时会自动运行 autoanchor根据你数据集的标签重新聚类锚框尺寸默认是开启的。如果你用的是 COCO 预训练权重初始锚框是 COCO 上聚类出来的针对的一般是中等偏大的目标铝片小缺陷用不上。autoanchor 会在前几个 epoch 重算锚框但不同版本对重算的时机处理有差异保险起见在训练前手动执行python train.py \ --data data/aluminum.yaml \ --weights yolov5s.pt \ --img 640 \ --batch 16 \ --epochs 1 \ --name anchor_check \ --noautoanchor这个命令只跑 1 个 epoch同时关闭 autoanchor启动日志里会打印当前锚框对训练集的召回率和最佳召回率。如果召回率低于 0.9说明锚框和缺陷尺寸不匹配。不用这个命令的话YOLOv5 训练第一轮也会自动重算但“让 autoanchor 自动跑”和“你看着它重算”是完全不同的体验——你看到聚类后的锚框尺寸分布才会理解你的数据到底长什么样。4.3 类别样本不平衡少样本缺陷类别怎么保4 个类别的样本量天然不均衡划伤类可能占一半以上麻点、脏斑类可能只有几百个实例。模型在多轮迭代后会越来越偏向常见类表现为混淆矩阵里少数类那几列全是 FN漏检而常见类的查准率很高。不要只看整体 mAP在 val 窗口里找到每一类的 AP 单独看少数类 AP 比多数类低 20 个点以上就属于明显不平衡。最简单的处理是调整损失权重也就是在 hyp 文件里把cls_pw从默认的 1.0 调高到 2.0~3.0。这个参数控制类别损失的加权系数调高后模型会在少数类上多分一些注意力。如果权重调整后效果不明显再做数据增强层面的补偿对少数类目标做复制粘贴增强把缺陷小图裁剪下来随机贴到其他铝片图片的空白区域同时生成对应的标签。注意过采样要克制。少数类样本太少时直接重复训练会让模型过拟合到那几个样本的具体形态而不是缺陷的通用特征。更推荐的做法是先训练一个 baseline把少数类漏检的样本抽出来用缩放、旋转、亮度扰动做离线增强扩充到原来的 2~3 倍就停。工业质检的场景复杂度就那么几种盲目扩到几十倍只会增加训练时长精度不再上升。5. 铝片缺陷训练的五个避坑记录现象、原因、解决一条龙这章是血泪经验集。铝片数据集本身整理得再好训练过程还是有一堆问题等你。下面五个坑按我实际遇到的频率排序每一条都有“现象 → 原因 → 解决”的完整链路。5.1 训练一启动就报错标签类别序号越界现象训练刚跑第一个 step终端抛出一串 traceback指向 dataloader 或 loss 计算的位置错误信息里有类似 “Assertion 0 n n num_classes” 的字样或者 CUDA 报非法内存访问。原因标签 txt 里的类别序号超出了 names 的数量范围。最常见的是标注工具默认从 1 开始编号而 YOLOv5 要求从 0 开始。如果数据集的 4 个类别被标成 1、2、3、4而 data.yaml 里 nc4那么类别 4 就必然越界。解决用第 2 章的校验脚本把所有标签跑一遍定位所有越界行的文件名和值。然后批量处理把标签里所有类别序号整体减 1前提是确实从 1 开始或者修改 data.yaml 的 names 列表让序号从对应位置开始。前者更合理因为序号语义应该和数据集的标注约定一致而不是反过来迁就数据。5.2 loss一路狂奔变NaN先查学习率再查标签现象训练到某个 epochtrain loss 突然变成 nan之后所有指标全部失效训练日志里 mAP 也变成 0。原因第一嫌疑是学习率过大梯度爆炸小数据集上尤其容易触发。第二嫌疑是标签里有脏数据比如某个标签的坐标值极端异常宽或高大到让边界框计算出现除零、负数。第三嫌疑是某张图片本身损坏解码失败后产出无效张量。解决先用第 2 章脚本查标签坐标排除脏数据。再把加载器里损坏图片删掉重下。如果这两步都没问题就把学习率从 0.01 降到 0.001损失函数为 NaN 的概率会显著下降。另一个治本的办法是开启梯度裁剪YOLOv5 的 train.py 里不支持直接传这个参数但可以改代码在 loss.backward() 之后加一行torch.nn.utils.clip_grad_norm_(model.parameters(), max_norm10.0)能兜住大部分梯度爆炸场景。5.3 验证集mAP逼近0.95现场还是漏检数据划分泄漏现象模型在验证集上 mAP 高得惊人接近 0.95你觉得可以上线了。然而到现场一跑漏检率比实验室高了 10 个百分点不止尤其是零散的小缺陷。原因这是工业缺陷检测里最阴间的问题——数据泄漏。如果训练集和验证集的图片来自同一批次、同一光源、同一角度验证集等于“开卷考试”模型学到的其实是背景和光照的特征而不是缺陷本身的特征。第 2 章里我特别强调按批次划分就是为了避免这个坑。解决回到数据划分这一步按批次或按拍摄时段重新划分验证集确保验证集里的铝片和训练集在物理来源上完全隔离。更稳妥的做法是额外保留一组“现场实测集”找一批没有参与过训练的现场图片单独跑一轮 val.py用实测集的结果作为是否上线的依据。5.4 训练中期loss走平学习率策略和mosaic的锅现象训练跑到 40~50 epochtrain loss 和 val loss 都走平不再下降。mAP 卡在 0.8 左右上不去。原因YOLOv5 的默认学习率调度是 cosine 衰减跑到中期学习率已经降到一个相对低位模型进入平台期。另一个隐藏原因是 mosaic 增强它在后期可能造成负面影响——拼图时人为制造了大量截断目标模型反复看到这些畸形样本泛化能力被拖住。解决如果 loss 曲线在最后 20 个 epoch 完全没有下降趋势可以手动降低--lr0再重启一轮训练用上一次的 best.pt 作为--weights。这种方法相当于手动做一次学习率重启往往能把 mAP 再推 2~3 个点。如果怀疑 mosaic把--mosaic 0.5甚至 0.3看 val mAP 是否立刻有反应。注意 mosaic 对训练影响是滞后的——你改的是之后每个 epoch 的增强方式已经跑过的 epoch 不会返工。5.5 推理时一个缺陷被重复框十几次NMS阈值没有重调现象用训练好的模型跑现场图片同一个划伤区域出现十几个重叠框画出来跟开花一样后处理模块统计缺陷数量直接爆表。原因YOLOv5 默认的 NMS 参数是--conf 0.25 --iou 0.45。在铝片这种大批量缺陷同时出现的场景中模型对同一个物理缺陷会产生多个候选框confidence 都挤在 0.3~0.5 这个区间。如果置信度阈值设低了NMS 又因为框之间重叠度不够高而没能合并就会留下大量重复检测。解决第一步把置信度阈值提到 0.4 再看通常能砍掉一半以上误检。第二步把 NMS 的 IoU 阈值从 0.45 调到 0.5 或 0.55让更宽的框被合并。第三步是固定推理时的输入尺寸推理和训练时--img不一致会直接改变缺陷框的尺度分布NMS 参数在这种不匹配下基本失灵。这三步做完重复框的问题基本能消失。6. 交付前的验证与轻量化部署把模型从实验室搬到产线训练完成不是结束模型要在现场设备上稳定跑起来才算真的交付。这一章是整条链路里最后也是最容易敷衍的部分——很多项目死在“实验室精度高产线跑不动”这条鸿沟上。6.1 混淆矩阵怎么读哪两类缺陷最容易混淆先跑验证集得到混淆矩阵python val.py \ --data data/aluminum.yaml \ --weights runs/train/aluminum_run1/weights/best.pt \ --img 640 \ --conf 0.25 \ --iou 0.45 \ --save-jsonYOLOv5 会输出 confusion_matrix.png 和一张 F1 曲线图。重点看混淆矩阵里的非对角块哪两个类别互相误判最多你就知道现场最该防的混淆组合是什么。铝片场景里划伤和压痕在低角度光下形态相似最容易互相串脏斑和被氧化色斑也经常被模型当成同一类。这两个混淆方向如果你知道现场哪类缺陷更致命漏检一次损失更大就可以针对性调整置信度阈值——对高风险类别调低 conf模型会更敏感代价是误检上升需要后处理来兜底。另外用 val.py 的--save-json导出的 COCO 格式结果文件可以画出每一类的 PR 曲线。AP 差异最大的类别就是下一轮迭代的优化对象。6.2 从pt到onnx再到INT8轻量部署的落地路径产线部署通常是边缘设备Jetson、RK3588 这类小卡是主力。pt 权重不能直接在这些设备上运行需要先导出为中间格式再转换或直接推理。第一步导出 ONNXpython export.py \ --weights runs/train/aluminum_run1/weights/best.pt \ --include onnx \ --dynamic --simplify导出完成后用 onnxruntime 在 CPU 上先跑一遍确认输入输出 shape 正确。--dynamic让 ONNX 支持动态输入尺寸但动态尺寸在 TensorRT 里会牺牲一部分优化空间。如果现场固定了相机分辨率和裁剪区域建议导出时用固定尺寸性能能再提一截。INT8 量化在这类任务里收益极大——TensorRT INT8 对比 FP16在 Jetson 上能同时提升吞吐和降低延迟代价是精度会有些许回退。量化后必须用现场图片重新测一次 mAP我见过某个项目量化后精度掉了 4 个点换了校准集重做才压回 1.5 个点。这套流程走完模型才算真正能交付。我自己的习惯是固定验证集绝不动上线前测一组现场实测集上线后再调 threshold改完记录在训练日志里。这样做过三个项目踩坑比例明显下降。希望帮到你。本文还有配套的精品资源点击获取