简介这份资源面向从事PCB表面缺陷检测的算法工程师、高校研究者与深度学习学习者提供一套可直接用于目标检测训练与验证的标注数据集帮助解决工业质检场景中样本获取难、标注成本高的问题。压缩包共1386个文件由693张jpg图像与693个xml标注文件组成整体约907.52MB标签同时提供VOC的xml格式与YOLO的txt格式便于在Faster R-CNN、YOLO等主流框架间灵活切换。缺陷覆盖Missing_hole、Mouse_bite、Open_circuit、Short、Spur、Spurious_copper六类标注精确、类别分布均匀可支撑较稳定的模型拟合效果。目前已有2904人学习下载适合作为PCB缺陷识别项目的训练底库或算法对比基准也可用于数据增强、类别均衡与检测精度调优等实验。1. 从一批spurious_copper文件名说起这份 PCB 缺陷数据集到底能干什么如果你手头正好有一批04_spurious_copper_12.jpg、04_spurious_copper_16.jpg这样的文件名大概率你拿到的就是一份按缺陷类别前缀命名的 PCB 缺陷数据集。这份资源的核心是 2700 余张 PCB 板面图像覆盖 6 类典型缺陷Missing_hole缺孔、Mouse_bite鼠咬、Open_circuit开路、Short短路、Spur毛刺、Spurious_copper余铜。每张图同时提供 YOLO 格式的 txt 标签和 Pascal VOC 格式的 xml 标签意味着你既可以直接喂给 YOLO 系列做检测训练也能走 VOC 路线接 Faster R-CNN、SSD 这类框架。它解决的是「手头没有工业缺陷样本、自己标注成本高、类别不均衡」这三个最现实的问题适合做 PCB 质检方向的学生、做工业视觉落地的算法工程师以及需要快速搭一个缺陷检测 baseline 的从业者。需要提前说明的是受上传体积限制公开部分约 693 张剩余部分作者通过邮箱补发这一点在动手前要心里有数。2. 数据集结构与两种标签格式先看懂目录再谈训练拿到压缩包后别急着解压完就丢进训练脚本先把目录结构和标签格式吃透否则后面报错你连是哪一层出的问题都定位不到。这一章把「文件怎么摆、两种标签怎么读、怎么互相转」讲清楚这是后面所有训练动作的地基。2.1 目录组织与文件命名规律这类数据集常见的组织方式是按缺陷类别分文件夹或者图像和标签平铺在同一目录靠文件名前缀区分。从给出的文件名看命名规则是「编号_类别名_序号.jpg」比如04_spurious_copper_12.jpg表示第 4 组、余铜缺陷、第 12 张。这种命名有个好处即使标签文件丢了你也能从文件名反推类别做数据校验时非常省事。我一般拿到手先跑一遍统计确认每类数量、有没有空标签、有没有图像和标签对不上的情况。下面这段脚本就是干这个的放在数据集根目录执行即可。import os from collections import Counter root ./PCB_DATASET # 换成你的实际路径 img_dir os.path.join(root, images) lbl_dir os.path.join(root, labels) # 统计每类图像数量按文件名前缀里的类别名 classes [Missing_hole, Mouse_bite, Open_circuit, Short, Spur, Spurious_copper] counter Counter() for f in os.listdir(img_dir): if not f.lower().endswith((.jpg, .png)): continue for c in classes: if c in f: counter[c] 1 break print(每类图像数量:, dict(counter)) # 检查图像与标签是否一一对应 imgs {os.path.splitext(f)[0] for f in os.listdir(img_dir)} lbls {os.path.splitext(f)[0] for f in os.listdir(lbl_dir)} print(有图无标签:, imgs - lbls) print(有标签无图:, lbls - imgs)逻辑说明第一段按类别名做子串匹配统计分布能快速看出六类是否均衡第二段用集合差集找出配对异常。参数上root要改成你解压后的真实路径classes列表必须和文件名里的类别拼写完全一致大小写敏感。如果输出里「有图无标签」不是空集说明这批数据需要先清洗别硬着头皮训练否则 YOLO 会直接跳过这些图你以为训了 2700 张实际可能只用了 2000 张。2.2 YOLO txt 与 VOC xml 的字段对照两种格式描述的是同一件事——目标框位置和类别但坐标系和存储方式完全不同。YOLO 的 txt 每行一个目标格式是class_id x_center y_center width height全部归一化到 0~1VOC 的 xml 用绝对像素坐标存xmin ymin xmax ymax。搞混这两个是新手最常见的翻车点训练时 loss 不降、框全跑到角落八成就是坐标系用错了。维度YOLO txtVOC xml坐标类型归一化中心点宽高绝对像素左上右下类别表示数字 id0~5字符串 name单文件目标数多行每行一个多个object节点常用框架YOLOv5/v8/v11Faster R-CNN、SSD是否需要类别映射文件需要classes.txt不需要name 直接写类别 id 的映射顺序必须固定建议按这个顺序建classes.txtMissing_hole、Mouse_bite、Open_circuit、Short、Spur、Spurious_copper对应 0 到 5。一旦训练中途改了顺序之前训的权重就废了这是血泪经验。2.3 两种格式互转的脚本实际项目里经常遇到「只有 VOC 但要训 YOLO」或者反过来。下面这个转换脚本覆盖两个方向读图尺寸拿真实宽高做归一化避免用错基准。import os import xml.etree.ElementTree as ET from PIL import Image classes [Missing_hole, Mouse_bite, Open_circuit, Short, Spur, Spurious_copper] cls2id {c: i for i, c in enumerate(classes)} def voc2yolo(xml_path, img_path, out_txt): tree ET.parse(xml_path) root tree.getroot() w int(root.find(size/width).text) h int(root.find(size/height).text) lines [] for obj in root.findall(object): name obj.find(name).text if name not in cls2id: continue bb obj.find(bndbox) xmin float(bb.find(xmin).text) ymin float(bb.find(ymin).text) xmax float(bb.find(xmax).text) ymax float(bb.find(ymax).text) # 转成归一化中心点宽高 xc (xmin xmax) / 2 / w yc (ymin ymax) / 2 / h bw (xmax - xmin) / w bh (ymax - ymin) / h lines.append(f{cls2id[name]} {xc:.6f} {yc:.6f} {bw:.6f} {bh:.6f}) with open(out_txt, w) as f: f.write(\n.join(lines)) def yolo2voc(txt_path, img_path, out_xml): img Image.open(img_path) w, h img.size root ET.Element(annotation) ET.SubElement(root, filename).text os.path.basename(img_path) size ET.SubElement(root, size) ET.SubElement(size, width).text str(w) ET.SubElement(size, height).text str(h) with open(txt_path) as f: for line in f: if not line.strip(): continue cid, xc, yc, bw, bh map(float, line.split()) xmin int((xc - bw / 2) * w) ymin int((yc - bh / 2) * h) xmax int((xc bw / 2) * w) ymax int((yc bh / 2) * h) obj ET.SubElement(root, object) ET.SubElement(obj, name).text classes[int(cid)] bb ET.SubElement(obj, bndbox) for k, v in zip([xmin, ymin, xmax, ymax], [xmin, ymin, xmax, ymax]): ET.SubElement(bb, k).text str(v) ET.ElementTree(root).write(out_xml)逻辑说明voc2yolo从 xml 读绝对坐标除以图像宽高做归一化中心点用(xminxmax)/2算yolo2voc反过来先乘回像素再取整。参数上要注意两点一是cls2id的顺序必须和训练时的classes.txt一致二是yolo2voc里int()截断可能让框比原图小一像素对精度要求高的场景建议用round()。转换完务必抽查几张用可视化脚本画框确认别信脚本不验证。3. 用这份数据训一个 YOLO 检测模型从环境到出权重数据看懂了接下来就是把它跑起来。这一章按「装环境 → 配数据 → 改配置 → 开训 → 看结果」的顺序走每一步都给出可抄的命令和参数含义新手照着能出权重熟手可以对照检查自己的配置有没有埋雷。3.1 环境搭建与依赖版本YOLO 系列对 PyTorch 和 CUDA 版本比较敏感版本对不上轻则警告重则直接崩。我一般用 conda 建独立环境避免污染主环境。conda create -n pcb_yolo python3.10 -y conda activate pcb_yolo # 按你的 CUDA 版本装 torch下面以 cu118 为例 pip install torch torchvision --index-url https://download.pytorch.org/whl/cu118 pip install ultralytics opencv-python pillow lxml逻辑说明python3.10是当前 YOLOv8/v11 兼容性最好的版本torch 的 index-url 要和你显卡驱动支持的 CUDA 版本匹配用nvidia-smi看右上角 CUDA Version。ultralytics一个包就把 YOLOv8/v11 的训练、验证、导出全带了比早年克隆仓库改代码省事得多。装完跑一句yolo checks确认环境它会打印 torch、CUDA、设备信息这一步别省。3.2 数据集配置文件与目录规范YOLO 训练要求固定的目录结构图像和标签分开放且路径要在 yaml 里声明。建议整理成这样pcb_dataset/ ├── images/ │ ├── train/ │ └── val/ ├── labels/ │ ├── train/ │ └── val/ └── pcb.yamlpcb.yaml内容如下path: ./pcb_dataset train: images/train val: images/val nc: 6 names: [Missing_hole, Mouse_bite, Open_circuit, Short, Spur, Spurious_copper]逻辑说明path是数据集根目录train/val是相对路径nc是类别数必须和names长度一致写错了训练时类别索引会越界。划分比例常见做法是 8:2但 PCB 缺陷样本少建议按类别分层抽样保证 val 里六类都有否则验证指标会失真。划分脚本用sklearn.model_selection.train_test_split加stratify参数即可这里不展开。3.3 训练命令与关键参数配置齐了就能开训。下面这条命令是我在 8G 显存上跑通的最小可用配置yolo detect train \ data./pcb_dataset/pcb.yaml \ modelyolov8n.pt \ epochs100 \ imgsz640 \ batch16 \ lr00.01 \ patience20 \ projectruns/pcb \ nameexp1逻辑说明modelyolov8n.pt用 nano 版先跑通流程显存不够就降到batch8imgsz640是默认输入尺寸PCB 缺陷目标偏小可以试imgsz1024但显存翻倍lr00.01是初始学习率小数据集别调太大否则 loss 震荡patience20表示 20 轮没提升就早停省时间。训练日志里重点看box_loss和mAP50前者持续不降说明标签有问题后者上不去可能是类别不均衡或学习率不对。3.4 推理与结果验证训完在runs/pcb/exp1/weights/下会有best.pt和last.pt用 best 做推理yolo detect predict \ modelruns/pcb/exp1/weights/best.pt \ source./pcb_dataset/images/val \ conf0.25 \ saveTrue逻辑说明conf0.25是置信度阈值低于它的框不显示工业场景漏检代价高可以降到 0.1 再人工复核saveTrue把画框结果存到runs/detect/predict。验证时别只看 mAP一定要肉眼看几张漏检和误检的图PCB 的 Short 和 Spurious_copper 在低分辨率下容易混这是数据本身的难点不是模型的问题。4. 避坑与排查这份数据集最容易翻车的五个地方数据、代码、环境都摆好了真正让人卡住的往往是些不起眼的细节。这一章把我在类似 PCB 缺陷数据集上踩过的坑按「现象 → 原因 → 解决」列出来遇到问题先对照排查能省下大量瞎试的时间。4.1 训练 loss 不降框全堆在图像中心现象开训几轮后box_loss卡在高位不动可视化预测框全挤在图像中央。原因YOLO 标签坐标系用错把 VOC 的绝对像素坐标直接当归一化坐标喂进去了数值远大于 1模型学不到有效位置。解决确认 txt 里每个数值都在 0~1 之间用 2.3 的转换脚本重新生成标签转换后抽查数值范围。4.2 类别索引错位预测全标成同一类现象模型能框出目标但类别几乎全是Missing_hole。原因classes.txt或 yaml 里names的顺序和生成标签时的cls2id不一致比如生成时 Short 是 3配置里写成了 2。解决全流程统一一份类别顺序文件生成标签、训练配置、推理后处理都读同一个来源别手写多份。4.3 显存溢出 CUDA out of memory现象训练刚开始就报 OOM。原因batch或imgsz超过显存容量PCB 图分辨率高时尤其明显。解决先把batch降到 8 或 4再考虑降imgsz也可以用yolo detect train ... ampTrue开混合精度显存能省三成左右。4.4 验证集 mAP 虚高但实际漏检严重现象mAP50到 0.9 以上实际推理却漏掉很多小缺陷。原因训练集和验证集划分时没分层验证集里恰好都是大目标或简单样本。解决按类别分层抽样重划数据集确保 val 里六类都有且包含小目标样本重新评估。4.5 图像与标签数量对不上训练悄悄丢样本现象明明有 2700 张图训练日志显示的样本数却少了几百。原因部分图像没有对应标签文件YOLO 默认跳过。解决用 2.1 的配对检查脚本找出缺失项要么补标签要么把这些图移出训练集别让它们静默消失。5. 进阶技巧把这份数据用到极致的两三个动作跑通 baseline 只是起点真正决定模型能不能落地的是后面这些细节。这一章讲几个我常用的进阶动作包括数据增强策略、小目标处理和模型导出都是能直接提升实际效果的。5.1 针对 PCB 缺陷的数据增强配置PCB 缺陷里 Spur 和 Spurious_copper 目标很小默认增强可能不够。YOLO 支持在训练命令里直接调增强参数yolo detect train \ data./pcb_dataset/pcb.yaml \ modelyolov8s.pt \ epochs150 \ imgsz1024 \ batch8 \ mosaic1.0 \ scale0.5 \ fliplr0.5 \ hsv_h0.015 \ hsv_s0.7逻辑说明mosaic1.0开启马赛克增强对小目标检测帮助明显scale0.5允许缩放模拟不同拍摄距离fliplr0.5水平翻转PCB 缺陷方向不敏感可以放心用hsv_h和hsv_s调色调饱和度应对不同光照的工业相机。注意imgsz1024时batch要相应降否则 OOM。5.2 小目标检测的切片推理PCB 整板图里缺陷占比很小直接缩到 640 会丢细节。常见做法是切片推理SAHI 思路把大图切成带重叠的小块分别检测再合并。核心参数是切片尺寸和重叠比例参数建议值说明slice_size640与训练输入一致overlap0.2切片间重叠避免边缘目标被切断conf0.1切片后置信度可调低靠 NMS 合并切片推理的代价是速度变慢一张整板图可能切成几十块推理时间线性增长。如果产线节拍要求高得在精度和速度之间权衡我一般先测切片方案的召回提升幅度提升不明显就不上。5.3 模型导出与部署前验证训练完的 pt 权重不能直接上产线通常要导出成 ONNX 或 TensorRT。导出命令yolo export modelruns/pcb/exp1/weights/best.pt formatonnx opset12 simplifyTrue逻辑说明opset12兼容性较好simplifyTrue会做图优化去掉冗余节点。导出后务必用同一批验证图对比 pt 和 onnx 的推理结果确认精度没有明显下降再部署。我见过导出后框偏移的案例原因是预处理里的归一化参数没对齐所以这一步的验证不能省。从那以后我每次拿到新数据集都强制先跑一遍配对检查和类别分布统计再动手训练。这份 PCB 缺陷数据集的价值在于它把六类典型缺陷和两种标签格式都备齐了省掉了最耗时的标注环节剩下的就是你怎么把它用好。希望帮到你。本文还有配套的精品资源点击获取
阅读完成 · 觉得有帮助?