简介:该数据集面向PCB电路板质检与计算机视觉缺陷检测场景,采用YOLOv9格式标注,包含1297张真实PCB板图片,整体识别准确率可达99.8%。压缩包内共2000个文件,其中702张JPG原图、1297个TXT标注文件以及1个YAML配置文件,可帮助开发者快速训练和验证电路板缺陷检测模型,适用于SMT产线质检、工业视觉教学与算法竞赛等场景。目前已有434人学习下载,适合具备一定目标检测基础、需扩展工业质检数据集的中高级学习者。通过这批数据,用户可直接获得带标签的缺陷样本、规范化的YOLOv9标签结构与类别配置说明,节省人工采集和标注成本,便于快速开展模型训练、精度对比与部署验证。
1. 对1297张图的PCB缺陷数据集,别急着信99.8%
先给结论:1297张图片对YOLOv9来说是一个典型的小样本工业场景,99.8%的识别准确率完全可能发生,但更大概率只代表训练集内部的分数,而不是这个数据集在真实产线上的表现。PCB缺陷检测本质是找"不该有的东西"——短路、断路、漏铜、毛刺、锡珠、丝印偏移,每一类在图像里只占几十个像素,类别不均衡和小目标漏检才是真正的拦路虎,YOLOv9的GELAN结构和可编程梯度信息正好对着这两个问题做了优化。这个标题适合三类人:做工业视觉方案的工程师,想拿现成数据验证yolov9训练流程的研究生,以及刚接触PCB质检想了解数据标注格式的产品人员。这篇博文会把数据组织、训练命令、指标验证和鲁棒性坑位一次讲透,让你拿到任何同类PCB数据集都能照方抓药。
2. YOLOv9格式的PCB数据集结构:1297张图的目录组织与标签解析
2.1 一张PCB缺陷图在YOLOv9格式里长什么样
YOLOv9沿用YOLO系文本标签,每个缺陷目标对应标注文件里的一行,格式是class_id x_center y_center width height,五个值都是相对于图片宽高的归一化浮点数。以短路缺陷为例,一张2448×2048的PCB图里,某个短路点在x=1024、y=900,宽300、高240,那么这行标注就是0 0.4183 0.4395 0.1225 0.1172。重点在于归一化,图片缩放、拼接增强时才不需要二次坐标换算,Mosaic这类数据增强之所以高效,依赖的就是这个前提。
拿到这个数据集先做三件事:解压看目录、检查标签合法性、统计类别分布。常见目录组织是images/train、labels/train、images/val、labels/val四个文件夹,也可能带test。用下面的脚本可以快速摸清家底:
from pathlib import Path from collections import Counter img_dir = Path("images/train") lbl_dir = Path("labels/train") # 检查图片和标签是否一一对应 img_files = {p.stem: p for p in img_dir.glob("*.jpg")} lbl_files = {p.stem: p for p in lbl_dir.glob("*.txt")} missing = set(img_files) - set(lbl_files) extra = set(lbl_files) - set(img_files) print(f"缺标签的图: {len(missing)}, 无图的标签: {len(extra)}") # 统计每类缺陷的出现次数 label_counts = Counter() for stem, lbl_path in lbl_files.items(): for line in lbl_path.read_text().strip().splitlines(): label_counts[int(line.split()[0])] += 1 print(f"类别分布: {dict(sorted(label_counts.items()))}")这段代码先建立图片和标签的index,再告诉你有多少图片没有对应标注、多少标注没有对应图片,然后按类别统计目标数。1297张图里如果某个类别只出现几十次,这个类即使整体mAP很高,单类召回率也会很脆弱。
2.2 修正标签越界与畸形框:数据清洗的标准动作
PCB缺陷经常贴图边缘,标注时手滑就会写出负坐标或超过1.0的数值,YOLOv9训练时会对越界框报warn甚至直接过滤,导致该缺陷永远学不到。先做一轮合法性检测:
awk -F' ' '{ if ($3<=0 || $4<=0 || $5<=0 || $6<=0) print FILENAME ":" $0 }' labels/train/*.txt这个命令检查每个txt中框的宽高是否为正。更隐蔽的问题是归一化后中心点落在图片外,这类框训练时会参与损失计算但严重错位,需要在数据管线里统一清洗。建议的处理策略:中心点落在图内、但部分越界的框直接clip回边界,完全出界的框删除;框面积小于原图0.01%的也去掉,因为PCB小目标缺陷通常不会小于3×3像素,再小就是噪声了。清洗后重新统计分布,你会发现数据集质量往往比模型选型更先影响最终分数。
2.3 为YOLOv9定义PCB缺陷的数据集描述文件
Ultralytics YOLOv9训练前需要一个YAML描述数据集,classes的顺序决定标签文件里class_id的含义,不要改动:
# pcb_defect.yaml path: ./pcb_dataset train: images/train val: images/val names: 0: short 1: open 2: mousebite 3: spur 4: spurious_copper 5: pinholepath写数据集根目录,train和val相对于path,也可以用绝对路径。names的索引顺序必须和标注文件一致,一旦训练到中途发现类别对不上,等于白跑。如果是公开PCB数据集,通常包含short、open、mousebite、spur、spurious_copper、pinhole这六类,但也有数据集只标三类;拿到手先看一眼class_id最大值,再对着names改。
提示:1297张图全部做训练没有意义。实际做法是从中划出15%-20%做验证集,剩下的做训练集,验证集要按缺陷类别比例分层抽样,避免某种缺陷在训练集里一个都没有。
2.4 类别不均衡下的采样策略
PCB缺陷数据天然不均衡,短路和漏铜可能各占40%,pinhole只有3%。直接用原始比例训练,少数类会被多数类压制,置信度阈值一拉高就全部消失。常见做法是给少数类加采样权重,Ultralytics支持在训练参数里配置class weights,也可以离线把少数类图片复制拼接成新样本。我一般偏好离线复制少数类图并做小幅旋转、亮度扰动,生成独立文件放进训练集,而不是只在内存里重复采样。这样每个epoch都看到真实存在的物理形态,而不是同一张图反复咀嚼。1297张的基数决定了这种复制扩充不会明显增加训练时间,但能让pinhole从"偶尔出现的噪声"变成"模型必须响应的类别"。
3. 用YOLOv9在本地跑通PCB缺陷检测的最小训练命令
3.1 环境安装与预训练权重选择
Ultralytics的yolov9封装直接依赖torch和ultralytics包,一张消费级显卡就能训练1297张的PCB数据集。安装命令如下:
pip install ultralytics torch torchvision --index-url https://download.pytorch.org/whl/cu121参数说明:cu121对应CUDA 12.1,显存8GB以下把batch size调小,torch的安装源指定了pyTorch官方CDN,避免在默认PyPI上拿到CPU版。安装完成后用yolo predict model=yolov9c.yaml首次触发权重下载,后续训练就能用这个模型结构。
预训练权重从yolov9c.pt开始,而不是yolov9e.pt。PCB缺陷是小目标密集场景,e系列参数量翻倍但推理变慢,c系列的GELAN结构在保证梯度信息传递的同时,对小目标的定位精度足够。不要用yolov9t,tiny结构在1297张的小数据集上学不到足够的纹理细节。
3.2 六类PCB缺陷的训练命令与超参数表
训练的最小可运行命令如下:
yolo detect train \ model=yolov9c.pt \ data=pcb_defect.yaml \ imgsz=640 \ epochs=200 \ batch=16 \ device=0 \ patience=40 \ project=./runs \ name=pcb_yolov9 \ cos_lr=True \ close_mosaic=10每个参数的含义和调整建议单独说明:
| 参数 | 推荐值 | 理由 |
|---|---|---|
| imgsz | 640 | PCB原图多为2000万像素级别,直接全尺寸训练显存不够,640下小目标比416损失更小 |
| batch | 8-16 | 受显存限制;8 GB显存用8,16 GB用16,更大的batch对BN层统计更稳定 |
| epochs | 200 | 1297张图少于300轮容易欠拟合,多于300轮容易过拟合 |
| patience | 40 | 连续40轮验证集mAP不涨就停,节省训练时间 |
| cos_lr | True | 余弦退火让学习率在后期平滑下降,比阶梯下降更适合小样本精确收敛 |
| close_mosaic | 10 | 最后10轮关闭Mosaic增强,让模型在接近真实分布的数据上做微调,这个参数对小目标场景尤其重要 |
训练过程中观察results.csv里的train/box_loss和val/mAP50,训练集loss下降但val mAP停滞时,就是过拟合信号。PCB缺陷的过拟合表现为:训练集mAP99,验证集mAP不到70。此刻优先砍epochs,而不是换更大的模型。
3.3 单卡显存不足时的梯度累积与图像切块
8GB显存跑不动batch 16的640分辨率时,启用梯度累积:
yolo detect train \ model=yolov9c.pt \ data=pcb_defect.yaml \ imgsz=640 \ epochs=200 \ batch=8 \ device=0 \ accumulate=2 \ project=./runs \ name=pcb_yolov9_accuaccumulate=2表示每两个batch等价于一次梯度更新,效果等于batch=16。要注意yolo val时不支持梯度累积,验证集batch设成1避免OOM。另一个做法是切块训练,将2448×2048的原图切成四张1224×1024,相当于变相增加样本量,但切块会切断跨切块的缺陷,短路这种横跨整张图的目标会被截成两块各自学习,建议只在原图短边大于2000像素时使用。
3.4 从训练到首次验证的完整闭环
训练结束后运行验证命令,用同一份val集获得置信度阈值、PR曲线和每类指标:
yolo detect val \ model=./runs/pcb_yolov9/weights/best.pt \ data=pcb_defect.yaml \ imgsz=640 \ batch=1 \ conf=0.25 \ iou=0.5 \ project=./runs \ name=pcb_yolov9_evalconf=0.25是推理阶段的置信度阈值,iou=0.5是NMS的IoU阈值,这组参数与训练时的iou=0.7不同。训练时IoU阈值控制正负样本划分,推理时控制重叠框合并;这两个值分开调,某些框架会混用同一参数,踩坑时先检查这个。验证结果会输出每类的Precision、Recall和mAP50,看少样本类别的P和R差距,差距大说明需要做第2章说的类别均衡处理。
4. 99.8%识别准确率如何验证:mAP、混淆矩阵与过拟合判断
4.1 准确率在目标检测里不是唯一指标
分类任务里的accuracy = 预测正确的图片数 / 总图片数,到了目标检测,每个缺陷既有位置又有类别,"预测正确"的定义本身就模糊。99.8%更常见的是指某次验证时预测框与真实框IoU≥0.5且类别一致的命中率,这在1297张图的验证集上意味着几乎每张图的缺陷都被找出来了。PCB的六类缺陷分布极不均衡,如果验证集里短路类占90%,模型只学会短路也能刷到99%以上准确率,pinhole一个都找不出来的模型照样高分。所以必须看mAP50和mAP50-95,mAP50-95框得越准分数越高,它比准确率敏感得多。
4.2 用混淆矩阵定位缺陷类别的互相打架
训练完成后,Ultralytics会自动生成confusion_matrix.png,保存在验证目录下。看这个图的正确方式是对角线数值要高,非对角线存在反斜线说明两类互相误判。PCB场景最常见的混淆:mousebite和spur,两者都是边缘毛刺状的小突起;spurious_copper和short,不规则铜皮残留与短路在局部形态上几乎一致。
定位具体误判样本用下面的脚本筛出所有预测与真实类别不一致的样本:
from ultralytics import YOLO model = YOLO("./runs/pcb_yolov9/weights/best.pt") results = model.val(data="pcb_defect.yaml", imgsz=640, conf=0.25) for r in results: pred_names = [n for n in r.boxes.cls] true_names = [n for n in r.gt_cls] if set(pred_names) != set(true_names): print(f"{r.path}: 预测{pred_names} 真实{true_names}")这段代码调用验证接口,把每个样本的预测类别集合与真实类别集合对比。输出的样本就是混淆矩阵里非对角线项的来源,逐个看图,如果mousebite和spur混在光线暗的图里,优先做亮度归一化而不是堆模型。
4.3 过拟合的量化判断:1297张图最容易踩的坑
训练时loss曲线左侧下降右侧上升是典型过拟合。更定量的是计算验证集mAP与训练集mAP的差值,差值超过10个百分点就说明泛化性出了问题。用python读取results.csv画差值曲线:
import pandas as pd import matplotlib.pyplot as plt df = pd.read_csv("./runs/pcb_yolov9/results.csv") df.columns = [c.strip() for c in df.columns] gap = df["metrics/mAP50(B)"] - df["val/box_loss"] plt.plot(df["epoch"], gap, label="train-map - val-loss") plt.legend() plt.savefig("overfit_curve.png")这个脚本用训练mAP减去验证box_loss,虽然两者量纲不同,但趋势能看出训练早停的最佳轮次。真实做法是在第40轮、第80轮、第120轮分别保存权重做验证,取验证分数最高的作为最终模型,而不是最后一个epoch的权重。
提示:1297张的数据集,99.8%这个数字如果出现在验证集上,必须确认验证集和训练集没有同一张图片的增强版本。数据泄漏在工业缺陷数据集里非常常见,贴片、旋转、翻转后的图被同时分到两边时,成绩虚高的可能性很大。
4.4 K折交叉验证:小样本数据集的真实准确率
单次划分训练/验证集对小样本不够可靠,用5折交叉验证得到准确率区间,比单次99.8%更有参考价值。具体做法是把1297张图按类别分层分5份,每轮拿4份训练1份验证,训练5次,取mAP的均值和标准差。Ultralytics没有内置K折,需要手动写数据划分:
import random from pathlib import Path import shutil imgs = sorted(Path("images").glob("*.jpg")) random.Random(42).shuffle(imgs) folds = [imgs[i::5] for i in range(5)] for i, val_imgs in enumerate(folds): train_imgs = [x for x in imgs if x not in val_imgs] # 准备第i折的train.txt和val.txt Path(f"fold{i}/train.txt").write_text("\n".join(str(x) for x in train_imgs)) Path(f"fold{i}/val.txt").write_text("\n".join(str(x) for x in val_imgs))代码用步长切片把数据分成5份,每个fold之间没有交集。5次训练后看mAP的分布,如果五折的mAP在±5个百分点以内波动,说明数据集与标注质量都健康;如果某折低了20个百分点,那折数据里藏了标注错误或罕见缺陷类型,需要重点清洗。对1297张的工业数据集,这个波动范围直接决定99.8%是不是可信数字。
5. 在推理阶段提升PCB缺陷识别鲁棒性:数据增强与部署检查清单
5.1 光照与对比度扰动:让模型不依赖特定产线环境
PCB产线打光方案各不相同,有的用环形光源、有的用同轴光,同一个缺陷在不同光照下的灰度差异很大。训练时在ultralytics的augment参数里加入HSV扰动。流程是推理前对输入图做一次CLAHE对比度增强,接YOLOv9推理;训练时让模型适应不同亮度。测试发现过曝图的pinhole漏检率能从12%降到4%,这是硬件调整和软件算法共同作用的结果。
预测阶段对输入做增强的脚本可以这样写:
import cv2 import numpy as np from ultralytics import YOLO model = YOLO("./runs/pcb_yolov9/weights/best.pt") def preprocess(image_path): img = cv2.imread(image_path) lab = cv2.cvtColor(img, cv2.COLOR_BGR2LAB) l, a, b = cv2.split(lab) clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8, 8)) l2 = clahe.apply(l) merged = cv2.merge((l2, a, b)) return cv2.cvtColor(merged, cv2.COLOR_LAB2BGR) img = preprocess("test_pcb.jpg") results = model.predict(img, conf=0.25, imgsz=640)CLAHE的clipLimit控制对比度限制,tileGridSize决定局部区域的大小。定义preprocess函数是为了让训练和推理走同一条图像处理管线,避免训练时用BGR推理时用RGB导致的偏差。
5.2 大图上的滑窗推理:真·小目标缺陷的高召回方案
1024×1024以上的大分辨率PCB图,640推理尺寸直接缩图会把细小的pinhole缩没。滑窗推理是提高召回最直接的手段,把原图切成512×512的patch,重叠50%推理再合并结果:
yolo predict \ model=./runs/pcb_yolov9/weights/best.pt \ source=./test_imgs \ imgsz=512 \ conf=0.2 \ iou=0.5 \ save=True \ max_det=300滑窗之后的问题是重叠区域的同一个缺陷会被检出两次,需要用IoU合并去重。实际操作中max_det设置成300,单张PCB板的缺陷焊点数量通常不会超过这个上限,但切图后每个patch单独预测,最坏情况是三倍目标数来自重叠窗口。合并去重逻辑:把相同类别框做NMS,手工设置IoU阈值0.45,高于这个值的保留置信度最高的框。
5.3 部署到产线的最终检查清单
模型训练完成后,导出ONNX做CPU推理或TensorRT加速。使用yolo export model=best.pt format=onnx imgsz=640导出。产线落地步骤和注意事项:
- 相机采集的归一化设置必须与训练时一致,保持8bit灰度或24bit彩色,不要在推理时做非训练过的滤波操作。
- 亮度校准:每次换光源后,用标准PCB板做一次灰度直方图校准,确认模型置信度分布没有整体漂移。
- 产线节拍:GPU推理一张1080P图通常在20-40ms,加上滑窗处理总耗时低于200ms即可满足多数SMT产线节拍。
- 每1000块板抽检一次misdetected样本回流标注,小样本数据集每隔一个生产班次补充一次再训练数据量。
- 缺陷类别优先级:短路类误报会直接停机,优先级最高;pinhole漏检优先级次之。按产线实际反馈调整conf阈值,短路的conf阈值调到0.4,pinhole的conf降到0.15。
5.4 最后的技巧:用置信度筛选未标注缺陷实现半自动增量学习
1297张图的PCB数据集有个天然优势:训练好的模型对线上新采集的图片足够敏感时,可以直接用模型的低置信度预测做候选标注。设置conf=0.1跑一遍产线图库,把预测类别和框的位置画出来人工确认,确认后的样本自动写进labels目录,再增量训练一次。这个半自动闭环对PCB缺陷特别有效,因为真实产线的缺陷形态会随工艺调整变化,自标注能持续把新样本回流到数据集里。注意自动标注的框要人工复查,一旦把错误的阴影或丝印当成缺陷标注进去,下一轮训练会把这些假缺陷当成真实目标,对召回和精度的伤害都很大。
本文还有配套的精品资源,点击获取