ARTICLE DETAIL

资讯详情

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

YOLOv8实战PCB缺陷检测:680张小样本数据集的训练调参与避坑指南

YOLOv8实战PCB缺陷检测:680张小样本数据集的训练调参与避坑指南 简介这套PCB缺陷检测数据集以真实产线图像为基础包含680张高清JPG图片及匹配的YOLO格式标注覆盖桥接、缺失、短路、断路、偏移、极性错误六类缺陷兼顾不同光照、拍摄角度与单/双/多层板场景适合工业视觉初学者、电子质检课程及产线质检算法预研使用。压缩包为7z格式共1376个文件680张JPG图像、693个txt标签、1个yaml配置和2个cache缓存总大小仅77.85MBtxt按“类别-归一化中心坐标-归一化宽高”五元组记录边界框yaml已定义六类名称并设置训练与验证路径。数据经过严格7:2:1划分训练集476张、验证集136张、测试集68张目录结构清晰另附中文使用指南与缺陷可视化分析工具支持类别分布热力图、标注密度统计等十余项分析。已有26人学习下载。该数据已在YOLOv8n上实测mAP0.5达到86.3%mAP0.5:0.95为62.1%可作为完整体验从数据加载、模型微调到性能评估流程的高质量实训素材。1. PCB 缺陷检测数据集680 张图为什么够入门却撑不起产线落地很多做 AOI 或质检算法的人第一次看到「PCB 缺陷检测数据集6类680张图像YOLO格式」时第一反应都是“这也太小了”。680 张图放到 YOLOv8 里跑不到 50 个 epoch 就过拟合看起来根本不够看。但我实际用下来的结论是这个规模做三件事完全够——验证检测 pipline、做数据增强与超参对比实验、以及作为 YOLO 菜鸟的第一份“真数据”。它解决的不是产线精度问题而是“你想用 YOLO 做 PCB 缺陷检测但不知道从哪下手”的问题。适合谁刚接触 yolo 训练自己的数据集、在做 PCB 缺陷检测相关毕设或课题、想快速评估 6 类缺陷在 YOLO 框架下能不能检出的人。它给不了你量产级的 mAP但能让你在一天之内跑通“数据 → 训练 → 验证 → 调参”的完整闭环。真正要注意的是把 680 张当成实验基座别当成产线数据后面所有调参才有意义。2. 读懂 6 类缺陷与 YOLO 格式标签文件里藏着两个隐藏约束很多人拿到数据集之后直接扔进训练脚本结果跑到一半发现 mAP 上不去回头查才发现是标签理解错了。这一章先把 6 类缺陷是什么、YOLO 格式的 txt 怎么组织、以及 train/val 怎么划分讲透这三个点任何一个出错后面都白干。2.1 6 类缺陷的工业命名从缺孔、鼠牙洞到残铜标签 ID 背后是质检工艺PCB 缺陷检测数据集里的 6 类缺陷不是随便分的它对应的是 PCB 制程中最常见的六类外观缺陷。常见命名如下表这组标签在开源社区里基本是默认约定训练前务必核对类别顺序和你自己的 data.yaml 是否一致。类别ID常见英文标签缺陷形态YOLO 检测难点0missing_hole该有的孔没钻出来目标小容易和正常焊盘混淆1mouse_bite焊盘边缘出现鼠咬状缺口形状不规则边缘特征弱2open_circuit走线断裂线路中断细长条宽高比极端3short相邻线路桥接短路和正常走线重叠度高4spurious_copper不该有铜的位置残留铜箔形态随机边界模糊5copper_bar多余的铜条搭接在走线上和残铜相似类间差异小这里要提醒一句mouse_bite 和 spurious_copper 这两类在 640×640 分辨率下视觉特征非常接近YOLO 系列模型反复在这两类的混淆矩阵上翻车后面第 5 章会专门讲怎么处理。2.2 YOLO 格式的 txt 标签归一化坐标、类别 ID 与文件名三者的对应关系YOLO 格式的每个标注框对应 txt 文件中的一行核心是五个数值类别 ID、归一化中心点 x、归一化中心点 y、归一化宽 w、归一化高 h。下面是一个真实标注文件的例子0 0.452083 0.361111 0.048611 0.034722 1 0.713194 0.598958 0.020833 0.009028逻辑说明第一个数字 0 表示类别 ID对应 data.yaml 里 names 列表的第 0 项后面的四个小数都是除以图像原始宽高后的归一化结果。注意两点中心点和宽高全部归一化到 0~1 之间不是像素坐标类别 ID 从 0 开始计数不是从 1。这个格式有两个隐藏约束很多人踩过。第一txt 文件名必须和对应图片文件名完全一致比如img_001.jpg对应img_001.txt后缀不同没关系主名必须一致。第二data.yaml 里的 names 顺序必须和 txt 里的类别 ID 一一对应如果你把 names 写成了[mouse_bite, missing_hole, ...]那所有类别 ID 为 0 的框都会被当成鼠牙洞训练。2.3 680 张图怎么划分 train/val比例与随机种子的选择680 张图说多不多说少也不算极端少但划分方式直接决定验证集 mAP 的可信度。常见做法是 8:2 划分也就是训练集 544 张、验证集 136 张如果缺陷样本分布极不均衡可以放宽到 9:1。但无论怎么分必须做两件事按缺陷类别做分层随机抽样以及固定随机种子。下面是我常用的划分脚本python scripts/split_data.py \ --images ./dataset/images \ --labels ./dataset/labels \ --val_ratio 0.2 \ --seed 42逻辑说明--val_ratio 0.2表示验证集占 20%--seed 42固定随机种子确保每次运行划分结果一致。脚本内部会先按类别统计每张图包含的缺陷类型再在每一类内部做随机抽样避免某一类缺陷全部落在验证集里。划分完成后一定要抽查验证集里是否包含全部 6 类缺陷以及每类缺陷的框数量占比是否和总数据集大致一致。注意不要手动挑图。680 张的规模下手动挑图必然引入偏差比如你挑了缺陷明显的图做验证集训练时模型学不到相似特征mAP 就会虚低。3. 用 YOLOv8 在本地跑通这个数据集目录结构、data.yaml 与最小训练命令格式读懂了接下来就是把数据集喂给 YOLOv8。这一章给一套可以直接抄的最小配置覆盖目录组织、data.yaml 编写、训练命令和日志判读跑通之后再考虑调参。3.1 目录组织与 data.yaml图片、标签、类别名三者必须对齐YOLOv8 训练时对目录结构没有硬性要求但官方约定是 images 和 labels 分开放各自下面再分 train 和 val。整理后的标准结构如下dataset/ ├── images/ │ ├── train/ │ │ ├── img_001.jpg │ │ └── ... │ └── val/ │ ├── img_137.jpg │ └── ... └── labels/ ├── train/ │ ├── img_001.txt │ └── ... └── val/ ├── img_137.txt └── ...逻辑说明YOLOv8 会依据图片路径自动去找同名的 txt 标签文件路径规则是把images替换成labels。所以图片目录叫images、标签目录叫labels这一步不要自作聪明改名。如果你的数据集已经是这种结构直接跳过整理步骤。对应的 data.yaml 写法如下path: ./dataset train: images/train val: images/val nc: 6 names: 0: missing_hole 1: mouse_bite 2: open_circuit 3: short 4: spurious_copper 5: copper_bar参数说明path是数据集根目录建议用相对路径避免换机器后路径失效train和val都是相对于根目录的路径nc必须等于 6names的顺序必须和前面 2.2 节里 txt 文件的类别 ID 完全一致。这里最常见的错误是自己在 labels 里把类别重新排了序但 data.yaml 没同步结果训练时类别张冠李戴。3.2 最小训练命令预训练权重、图像尺寸、batch 与 epochs 的初次取值第一次跑通不要一上来就追求高精度目标是让训练流程正常走完、日志正常输出、验证集 mAP 不为 0。最小命令如下yolo detect train \ data./dataset/data.yaml \ modelyolov8n.pt \ imgsz640 \ batch16 \ epochs100 \ patience15 \ project./runs \ namepcb_6cls逻辑说明modelyolov8n.pt表示加载 COCO 预训练权重作为初始化而不是从零开始训练。680 张小数据集从零训练几乎必然发散预训练权重是第一条保命符。patience15表示验证集 mAP 连续 15 个 epoch 没有提升就提前停止训练防止后 30 个 epoch 纯粹在过拟合训练集。参数说明imgsz640是最常用的默认值但 PCB 缺陷很多是小目标640 分辨率下 20×20 像素的鼠牙洞几乎只有几个像素第一次训练先用 640 跑通流程后面再升到 1280 对比效果。batch16是 12GB 显存左右的安全值显存不够降到 8不要改 imgsz 去迁就显存。epochs100在小数据集上配合早停通常足够没必要一上来就设 300。3.3 训练日志怎么看loss 曲线、P/R 曲线与过拟合的早期信号很多人训练结束只看最后的 mAP中间日志一眼不看这在小数据集上是致命的。680 张图很容易在 20 个 epoch 后就开始过拟合而 mAP 曲线是滞后的等你看到 mAP 掉头已经晚了。训练过程中要盯这几个指标指标正常表现异常信号box_loss前 20 个 epoch 快速下降之后缓慢下降一直不降或突然反弹cls_loss同样快速下降后趋于平稳验证集 cls_loss 持续上升mAP50整体上升允许有 2~3 个点的波动大起大落或训练集和验证集差距拉大P / R 曲线P 和 R 此消彼长但 mAP 稳定R 始终低于 0.5说明漏检严重训练结束后在runs/pcb_6cls/目录下会生成results.csv里面每行对应一个 epoch 的完整指标。我一般用 pandas 直接读这个文件画出训练集和验证集的 loss 曲线叠加图两者之间的 gap 从第几个 epoch 开始拉大那个点就是早停的候选位置。注意不要只看 mAP50要同时看 mAP50-95。这个数据集的缺陷普遍是小目标mAP50-95 比 mAP50 更能反映检测框定位精度如果两者差距超过 20 个点说明框定位不准优先排查标注框质量。4. 680 张样本的 YOLO 调参实战数据增强、冻结训练与类别不平衡跑通之后进入调参阶段。小数据集调参和常规场景不太一样核心矛盾是模型容量太大、数据量太少。这一章讲三个最有效的杠杆预训练权重的使用方式、数据增强的强度控制、以及类别不平衡的处理手段。4.1 预训练权重与冻结训练小数据集的第一道保命符用yolov8n.pt做初始化只是第一步进阶做法是冻结部分网络层。冻结 backbone 前 10 层能让模型在早期训练阶段不被少量 PCB 样本带偏保留 COCO 上学到的通用纹理特征。YOLOv8 提供了 freeze 参数yolo detect train \ data./dataset/data.yaml \ modelyolov8n.pt \ imgsz640 \ batch16 \ epochs100 \ freeze10 \ project./runs \ namepcb_freeze10逻辑说明freeze10表示冻结模型前 10 层的权重训练时这些层只做前向传播不参与反向传播更新。剩余层从预训练权重继续微调。这个设置对 680 张图尤其有用因为它把模型的可学习参数数量大幅压缩变相降低了过拟合风险。参数说明freeze 的层数不是越大越好。冻结 10 层适合数据量很小的场景如果后续你补了数据到 2000 张以上可以改成freeze0做全量微调。另外要注意冻结层数过大会让模型学不到 PCB 特有的低频纹理特征表现为训练集 loss 降不下来这时候要减小 freeze 值。4.2 数据增强参数mosaic、flip、hsv 三组参数怎么开YOLOv8 默认开启的数据增强对小数据集是双刃剑。mosaic 把 4 张图拼成一张极大扩充了背景多样性但同时也可能让缺陷目标被裁掉一半。我的做法是保留 mosaic但把它的整体强度控制在默认值之下。修改方式是在超参数配置文件里改先导出现有配置yolo detect train \ data./dataset/data.yaml \ modelyolov8n.pt \ epochs1 \ imgsz640 \ cfgdefault.yaml \ project./runs \ namecfg_dump逻辑说明上面命令会在runs/cfg_dump/下生成完整的超参数文件default.yaml。打开后重点看三组参数mosaic默认 1.0、hsv_h、hsv_s、hsv_v、fliplr默认 0.5 。针对 PCB 缺陷数据集的推荐调整如下mosaic: 0.8 mixup: 0.2 fliplr: 0.5 flipud: 0.0 hsv_h: 0.015 hsv_s: 0.4 hsv_v: 0.3参数说明flipud设为 0 是因为 PCB 板的方向在检测时有工程意义上下翻转会让模型学到错误的朝向先验hsv_h调小到 0.015 是因为 PCB 板颜色以绿、蓝为主色相变化太大会把板子颜色改得不像板子mosaic从 1.0 降到 0.8 是因为 680 张图中很多小目标mosaic 拼图后目标进一步缩小检测难度更大。YOLOv8 在最后 10 个 epoch 会自动关闭 mosaic这个默认行为保留它能帮助模型在真实尺度上做最后的收敛。4.3 类别不平衡某类缺陷只有几十个实例时怎么调680 张图不是每张只有一个缺陷但类别分布依然可能极端。常见情况是 short 和 open_circuit 框较多而 copper_bar 或 missing_hole 只有二三十个框。直接训练会让模型偏向样本量大的类。先统计一下每类框的数量import os from collections import Counter label_dir ./dataset/labels/train counter Counter() for fname in os.listdir(label_dir): with open(os.path.join(label_dir, fname), r) as f: for line in f: cls_id int(line.split()[0]) counter[cls_id] 1 print(counter)逻辑说明脚本遍历训练集所有 txt 标签文件读取每行第一个数字作为类别 ID累加得到每类缺陷的实例总数。输出类似Counter({3: 480, 2: 412, 4: 156, 1: 98, 0: 64, 5: 57})这时就能看出哪几类严重偏少。如果最少的类只有几十个实例优先做三种处理第一把该类在验证集中的框全部移动到训练集单独用小验证集评估第二对该类缺陷的图片做离线复制增强常见的是对包含该类缺陷的原图做 90 度旋转和镜像生成新图片加入训练集第三提高该类在损失函数中的权重——在 data.yaml 中通过weights字段传一个 6 维数组稀疏类给 1.5~2.0稠密类给 0.8~1.0。这三种方法从简单到复杂先做第一种效果不够再加后两种。5. PCB 缺陷数据集避坑指南标注噪声、小目标与误检的 5 个血泪经验680 张图的小数据集会把所有数据层面的问题放大十倍。这一章写 5 个我实际踩过或看人踩过的坑每一条都是「现象 → 原因 → 解决」三步走适合训练前对照排查也适合训练失败后回溯。5.1 现象loss 正常下降但验证集 mAP 剧烈震荡每跑一次结果都不一样原因train/val 划分没有固定随机种子。680 张图本身样本量小验证集少 20 张、多 20 张对 mAP 的影响能到 5~10 个点。很多人的划分脚本每次运行都重新随机导致两次训练用的验证集根本不是同一批图对比实验毫无意义。解决划分脚本里显式设置random.seed(42)同时把划分后的文件列表存成train.txt和val.txt后续重新划分时先检查这两个文件是否已存在存在就跳过。这样所有实验共用同一份验证集指标才有可比性。5.2 现象漏检集中在 mouse_bite 和 spurious_copper而且 mAP50 和 mAP50-95 差距超过 20 个点原因640×640 分辨率下这两类缺陷的像素尺寸往往只有 15×15 左右加上边缘特征模糊YOLO 的深层特征图对它们不敏感。这不是模型不行是输入分辨率不够。解决把 imgsz 从 640 提升到 1280显存不够时先减 batch。对比实验表明这个数据集在 1280 分辨率下 mAP50 通常能涨 5 个点以上。如果 1280 也吃力另一个方案是把原图切成左上、右上、左下、右下四块分别训练推理时同样切块检测再合并结果等价于在 640 显存下实现 1280 的效果。5.3 现象验证集误检特别多把正常焊盘、正常走线都框出来报成缺陷原因数据集中全是“有缺陷的图”没有“正常板”的负样本。YOLO 是纯监督模型没见过的东西它不知道是背景于是在正常区域上也输出了高置信度预测。680 张全是正样本这个问题被放大了。解决补负样本。去网上或自己拍一批无缺陷的 PCB 板图片放进训练集对应 txt 标签文件写成空文件0 字节加入训练。常见的比例是负样本占总训练集的 20% 左右也就是补 130 张正常板图片。模型看到过“没有缺陷的板子长什么样”之后误检会明显下降。这不只是调参问题是数据集构成问题。5.4 现象训练 loss 正常但验证集 P 曲线和 R 曲线都很难看尤其 R 始终上不去原因标注框质量问题。680 张数据集的标注未必全是用专业标注工具做的可能存在框没包全缺陷、框比缺陷大两倍、或者中心点偏离缺陷核心的情况。YOLO 对框的 center 坐标非常敏感中心偏了模型就认为这个地方没有目标。解决写脚本扫描所有标签找出异常框。一个常见的过滤条件是框的宽高比大于 5 或小于 0.2、框面积小于整图面积的 0.001、框中心点落在图像边缘 5% 区域内。脚本如下import os def check_label(fname, img_w, img_h): with open(fname, r) as f: for line in f: parts line.split() _, cx, cy, w, h parts cx, cy, w, h float(cx), float(cy), float(w), float(h) if w/h 5 or h/w 5: print(f{fname}: extreme aspect ratio {w/h:.2f}) if w * h 0.001: print(f{fname}: tiny box {w:.4f} x {h:.4f})逻辑说明脚本遍历标签文件对每一行解析出归一化宽高检查宽高比和面积占比。输出异常样本后回到标注工具里人工复核修正。不要试图用算法自动改标注680 张图的规模人工复核一遍最多半天比任何自动修复都可靠。5.5 现象训练时类别 ID 对应错乱copper_bar 的框全部报成 spurious_copper原因data.yaml 的 names 顺序和 txt 标签里的类别 ID 对不上。常见于两类情况一是从网上下的数据集被前人重新排过类别二是你自己在标注时用了自定义类别编号导出时没映射回标准顺序。解决训练前跑一个类别对齐检查统计训练集 labels 中出现的所有类别 ID再和 data.yaml 的 names 长度对比python check_cls_ids.py --labels ./dataset/labels --num_classes 6逻辑说明这个脚本统计所有 txt 文件中的类别 ID 集合如果出现大于等于num_classes的 ID说明标签文件里有类别编号越界需要回到标注工具里修正。如果 ID 集合是 {0,1,2,3,4,5} 但你觉得某个类应该不是这个编号打开两个 txt 文件手动对照一下原始图像和框的位置即可确认。6. 用混淆矩阵和坏 case 回放把验证集变成调参后悔药训练结束后不要只看 mAP 一个数字要把验证集上的错误吃透。这个数据集的下一阶段工作就是把混淆矩阵和坏 case 回放变成每次调参后的固定动作。训完一轮之后跑一次验证集预测保存所有带框的输出图逐张看漏检和误检。命令如下yolo detect predict \ model./runs/pcb_6cls/weights/best.pt \ source./dataset/images/val \ saveTrue \ save_txtTrue \ project./runs \ namepcb_val_pred逻辑说明save_txtTrue会把预测结果连同置信度写到 txt 文件方便脚本分析saveTrue会保存标注了预测框的图片供人工逐张回放。我把这个叫“后悔药”——每次调参后把预测图存到一个按日期命名的目录里下次调参跑完对比同样的图一眼就能看出改参数到底解决了几类问题。看规则先看混淆矩阵里 copper_bar 和 spurious_copper 的交叉项这两类如果互相错认说明训练数据里这两类的形态差异不够优先补这两类的标注数据。再看 R 曲线掉头的部位R 在低置信度区间上不去基本是标注框偏大模型学到的目标边界模糊。最后挑 10 张最典型的坏 case 放进一个固定对比文件夹每轮调参后手动确认。这个数据集只有 680 张验证集 136 张全看一遍也就十几分钟但一次次积累下来你会比任何指标都清楚模型的真实边界。我的习惯是每次调完参先跑上面的 predict再花十五分钟翻一遍预测图确认是新解决了问题还是引入了新误检然后才去改下一组参数。小数据集跑得快试错成本低别浪费这个优势。希望帮到你。本文还有配套的精品资源点击获取
返回列表