简介:这是一份面向电子制造质检与计算机视觉方向的PCB表面元器件缺陷检测数据集,适合从事目标检测算法训练、工业缺陷识别研究的学生与工程师使用。数据集包含超过600张标注图像,已统一处理为YOLO格式并完成数据增强,可直接用于YOLO全系列网络训练,覆盖Miss、mask defect、defect等7类缺陷,配套class类别文件便于核对标签体系。资源包共1219个文件,以608张jpg图像、609个txt标注文件为主,另含1个py可视化脚本与1个png说明图,压缩包约57.41MB,训练集、验证集与标签划分清晰。其中show脚本可将预测或标注的边界框绘制在图像上,方便直观检查缺陷位置与标注质量,辅助调试模型与评估检测效果。目前已有391人学习下载,适合需要快速搭建缺陷检测基线、验证数据增强策略或开展工业质检实验的读者参考使用。
1. 产线质检的“找茬”利器:PCD表面元器件缺陷检测数据集上手记
上周帮一个做SMT贴片的朋友看他们产线的AOI误报问题,发现他们卡在同一个地方:模型对“Miss”和“mask defect”两类缺陷的边界框总是画不准,漏检率压不下去。聊下来才知道,他们手头只有几百张产线随手拍的图,标注格式五花八门,连训练集和验证集都是混着用的。这其实是很多做工业质检的团队都会遇到的坎——算法选型不难,难的是没有一份干净、格式统一、带可视化工具的数据集来快速验证想法。今天要拆的这个PCD表面元器件缺陷检测数据集,就是冲着这个痛点来的:超过600张经过标注的电路板表面元器件图像,已经处理成YOLO格式,自带训练集/验证集划分、class类别文件和show可视化脚本,可以直接喂给YOLO系列网络跑训练。如果你正在做目标检测落地、尤其是电子制造相关的缺陷检测,这份资源能帮你省掉最耗时的数据清洗环节。
2. 拆开数据集看门道:YOLO格式的目录结构与类别定义
2.1 目录布局与文件命名逻辑
拿到一个数据集,我习惯先看目录结构,因为目录布局直接决定了你后面写DataLoader时会不会踩坑。这个数据集的组织方式是比较典型的YOLO训练目录,根目录下分images和labels两个大文件夹,各自再按train和val切分。图片文件命名保留了原始采集时的前缀,比如6_PNG_jpg.rf.e9eafa26558f3ce2defce65e40498238.jpg这种,中间那串rf.后面跟的哈希值是数据增强时生成的唯一标识,用来避免同名文件覆盖。标签文件与图片文件同名,只是扩展名换成.txt,这是YOLO格式的标准做法——一张图对应一个txt,txt里每一行代表一个目标框,格式是class_id x_center y_center width height,坐标都做了归一化处理。
class文件单独放在根目录,里面按行列出了7个类别。从摘要描述看,类别包括Miss、mask defect、defect等,具体顺序需要打开class文件确认,因为class_id是跟这个文件的行号绑定的。我一般会先跑一行命令把类别和数量打出来,确认没有编码问题:
# 查看class文件内容,确认类别顺序和数量 cat class.txt | nl -ba # 统计train和val的图片数量,核对是否与描述一致 find images/train -name "*.jpg" | wc -l find images/val -name "*.jpg" | wc -l这里有个细节:文件名里带_PNG_和_JPG_的混在一起,说明原始图片格式不统一,但都被转成了jpg。转换过程中如果压缩率设得不对,小缺陷的纹理可能被抹掉,所以后面训练前最好抽样看几张图,确认缺陷区域还清晰可辨。
2.2 七个类别的实际含义与标注边界
类别定义是缺陷检测里最容易扯皮的地方。这个数据集给了7个类,从名称看,Miss通常指元器件缺失,mask defect指焊盘或阻焊层缺陷,defect是个兜底类,可能涵盖划痕、异物等。但具体每个类的标注标准是什么,数据集本身不会写,需要你自己从标注框的分布去反推。我一般会写个小脚本统计每个类的框数量和平均面积,判断是否存在长尾分布:
import os from collections import defaultdict label_dir = "labels/train" class_count = defaultdict(int) class_area = defaultdict(list) for txt_file in os.listdir(label_dir): if not txt_file.endswith(".txt"): continue with open(os.path.join(label_dir, txt_file), "r") as f: for line in f: parts = line.strip().split() if len(parts) != 5: continue cls_id = int(parts[0]) w, h = float(parts[3]), float(parts[4]) class_count[cls_id] += 1 class_area[cls_id].append(w * h) for cls_id in sorted(class_count.keys()): avg_area = sum(class_area[cls_id]) / len(class_area[cls_id]) print(f"class {cls_id}: {class_count[cls_id]} boxes, avg area {avg_area:.4f}")跑完这个统计,你就能知道哪个类样本最多、哪个类框最小。小目标检测在这类数据集上特别容易翻车,因为PCB上的元器件本身就不大,如果某个缺陷类的平均框面积低于0.01,训练时就要考虑加anchor或者用更高分辨率的输入。
2.3 数据增强留下的痕迹与使用建议
文件名里的rf.哈希值说明这批图是经过Roboflow类工具增强过的,常见的增强手段包括旋转、裁剪、亮度调整、加噪声等。增强的好处是泛化能力上去了,但坏处是验证集可能也被增强过,导致验证指标虚高。我的习惯是先把val集里的图抽样看一遍,如果发现同一块板子的不同增强版本同时出现在train和val里,那验证结果就不可信了。处理办法很简单:按原始文件名前缀分组,确保同一前缀的图只出现在一个split里。这个操作在训练前花十分钟做掉,比训练完发现过拟合再回头查要省事得多。
3. 从零跑通YOLO训练:环境配置与show脚本可视化
3.1 环境准备与依赖安装
这个数据集标称支持YOLO所有系列,实际测试下来,YOLOv5、YOLOv8、YOLOv11的目录结构都能直接兼容。我一般用conda建个干净环境,避免和系统里的包打架:
conda create -n pcb_defect python=3.9 -y conda activate pcb_defect pip install torch torchvision --index-url https://download.pytorch.org/whl/cu118 pip install ultralytics opencv-python matplotlibultralytics这个包把YOLOv8和YOLOv11的接口统一了,训练脚本写起来很省事。如果你用的是YOLOv5的老代码,需要单独clone仓库,但数据配置文件yaml的写法是一样的。装完之后先跑个yolo checks确认CUDA和cuDNN都认到了,不然训练时跑到一半报显存错误更浪费时间。
3.2 编写数据配置文件
YOLO训练需要一个yaml文件告诉它去哪里找图和标签。这个数据集已经分好了train和val,所以配置写起来很直接:
# pcb_defect.yaml path: /data/pcb_defect # 数据集根目录 train: images/train val: images/val nc: 7 # 类别数,与class文件行数一致 names: 0: Miss 1: mask_defect 2: defect 3: class_3 4: class_4 5: class_5 6: class_6names这里我只写了前三个确定的名字,后面几个需要你打开class文件对照着填。注意类别名里不要有空格,mask defect要写成mask_defect,否则yaml解析会报错。路径用绝对路径最稳,相对路径在不同工作目录下跑容易找不到文件。
3.3 启动训练与关键参数设置
配置写好之后,训练命令就一行:
yolo detect train data=pcb_defect.yaml model=yolov8n.pt epochs=100 imgsz=640 batch=16 patience=20这里几个参数值得展开说。model=yolov8n.pt用的是nano版本,参数量小,适合先跑通流程看效果;如果显存够,换成yolov8s.pt或yolov8m.pt精度会更好。imgsz=640是输入分辨率,PCB缺陷通常比较小,如果显存允许,可以提到imgsz=1024,对小目标检测帮助明显。patience=20是早停耐心值,验证集loss连续20轮不降就停,避免过拟合。batch=16是批大小,显存不够就往下调,调到8或4都行,但太小了BN层统计量不准,训练会不稳定。
训练过程中重点看两个指标:mAP50和mAP50-95。前者是IoU阈值0.5时的平均精度,后者是0.5到0.95取平均,更严格。如果mAP50还行但mAP50-95很低,说明框的位置不够准,可能需要调anchor或加更多位置回归的loss权重。
3.4 用show脚本把预测框画出来
数据集自带的show脚本是可视化利器,但不同版本的脚本接口可能不一样。我一般会自己写一个简单的可视化函数,确保能同时画GT框和预测框:
import cv2 import random def visualize_boxes(img_path, label_path, pred_path=None): img = cv2.imread(img_path) h, w = img.shape[:2] colors = [(random.randint(0,255), random.randint(0,255), random.randint(0,255)) for _ in range(7)] # 画GT框 with open(label_path, "r") as f: for line in f: cls_id, xc, yc, bw, bh = map(float, line.strip().split()) x1 = int((xc - bw/2) * w) y1 = int((yc - bh/2) * h) x2 = int((xc + bw/2) * w) y2 = int((yc + bh/2) * h) cv2.rectangle(img, (x1, y1), (x2, y2), colors[int(cls_id)], 2) cv2.putText(img, str(int(cls_id)), (x1, y1-5), cv2.FONT_HERSHEY_SIMPLEX, 0.5, colors[int(cls_id)], 1) cv2.imwrite("vis_output.jpg", img) print(f"saved to vis_output.jpg, image size {w}x{h}") visualize_boxes("images/val/6_PNG_jpg.rf.e9eafa26558f3ce2defce65e40498238.jpg", "labels/val/6_PNG_jpg.rf.e9eafa26558f3ce2defce65e40498238.txt")这个脚本跑完会生成一张带框的图,你可以直观看到标注是否准确。如果发现框明显偏了或者漏标,那训练前就得先修数据,不然模型学到的就是错的。我一般会随机抽20张val图跑一遍,确认标注质量过关再开始训练。
4. 避坑指南:数据增强、类别不平衡与验证集陷阱
4.1 增强后的图混入验证集导致指标虚高
现象:训练完看验证集mAP50到了0.9以上,但拿产线新拍的图一测,漏检率还是很高。原因:数据增强时同一张原图生成了多个版本,这些版本被随机分到了train和val里,模型在验证集上看到的是“见过的图”,指标自然好看。解决:按原始文件名前缀分组,用GroupShuffleSplit代替随机划分,确保同一前缀的图只出现在一个split里。具体做法是提取文件名里rf.之前的部分作为group id,然后按group划分。
4.2 小目标缺陷在640分辨率下几乎消失
现象:训练loss降不下去,mAP50卡在0.3左右,可视化发现小缺陷的框根本没预测出来。原因:PCB上的元器件缺陷本身可能只有十几个像素,缩放到640后信息量更少,YOLO的stride=32那层特征图根本感受不到。解决:把imgsz提到1024或1280,同时在数据配置里开启mosaic=0(最后几轮关掉mosaic,让模型在原始尺度上微调)。如果显存不够,用yolov8n加imgsz=1024比yolov8m加imgsz=640对小目标更友好。
4.3 类别不平衡导致少数类被模型忽略
现象:Miss类召回率很高,但mask defect类的召回率不到0.2。原因:统计一下框数量就会发现,mask defect的样本可能只有Miss的十分之一,模型倾向于把不确定的框都预测成多数类。解决:在训练配置里加cls=1.5提高分类loss权重,或者用focal_loss替代默认的BCE。更直接的办法是对少数类做过采样,在数据配置文件里给train路径多指向几个包含少数类的子目录。
4.4 标签文件里的坐标越界导致训练崩溃
现象:训练到第几个epoch突然报AssertionError: invalid bbox。原因:增强过程中旋转或裁剪后,部分框的坐标超出了0到1的范围,YOLO的DataLoader会直接断言失败。解决:训练前跑一遍清洗脚本,把坐标裁到[0,1]区间,同时过滤掉宽或高小于0.001的框。这个脚本很简单,但能省掉半夜起来重启训练的麻烦。
import os def clean_labels(label_dir): for txt_file in os.listdir(label_dir): if not txt_file.endswith(".txt"): continue path = os.path.join(label_dir, txt_file) valid_lines = [] with open(path, "r") as f: for line in f: parts = line.strip().split() if len(parts) != 5: continue cls_id = int(parts[0]) xc, yc, bw, bh = map(float, parts[1:]) xc = min(max(xc, 0.0), 1.0) yc = min(max(yc, 0.0), 1.0) bw = min(max(bw, 0.001), 1.0) bh = min(max(bh, 0.001), 1.0) valid_lines.append(f"{cls_id} {xc:.6f} {yc:.6f} {bw:.6f} {bh:.6f}\n") with open(path, "w") as f: f.writelines(valid_lines) clean_labels("labels/train") clean_labels("labels/val")4.5 验证集指标波动大,不知道选哪个权重
现象:每个epoch的mAP50上下跳动超过0.1,不知道哪个权重最好。原因:验证集样本太少,600张图按8:2分,val可能只有100多张,统计噪声大。解决:用k-fold交叉验证,把train和val合并后重新分5折,每折训一个模型取平均。或者至少把val的batch调大,让验证指标更稳定。我一般会在训练命令里加save_period=10,每10轮存一个权重,最后拿几个候选权重在产线实拍图上测,而不是只看验证集数字。
5. 进阶技巧:用混淆矩阵和PR曲线定位模型短板
训练跑通只是第一步,真正要落地到产线,得知道模型在哪个类别上弱、在哪个尺度上漏。YOLO训练完会在runs/detect/train/目录下生成混淆矩阵和PR曲线,但很多人直接跳过不看。我一般会重点看混淆矩阵的非对角线元素——如果mask defect被大量预测成defect,说明这两个类的特征区分度不够,要么合并类别,要么在标注时把边界定得更清楚。PR曲线则能告诉你每个类的置信度阈值该设多少:如果Miss类的曲线在recall=0.8时precision还有0.9,那阈值可以设高一点减少误报;如果曲线很早就掉下来,说明这个类本身就难分,阈值得放低。
还有一个容易被忽略的点是推理速度。产线质检对节拍有要求,YOLOv8n在640分辨率下用TensorRT加速后单帧大概2到3毫秒,但如果你为了小目标把imgsz提到1280,速度会掉到8到10毫秒。这时候要么换更小的模型,要么把检测区域裁出来单独跑。我一般会先用yolo export format=engine half=True导出TensorRT引擎,然后在实际产线图上测端到端延迟,包括预处理和后处理的时间,而不是只看模型前向的benchmark数字。
从那以后我每次拿到新数据集,都强制走一遍“统计类别分布→抽样看标注→清洗越界框→按group划分验证集”的流程,哪怕数据集标称已经处理好了也不跳过。这套习惯帮我省掉了至少三次训练到一半发现数据有问题的情况。希望这份拆解能帮你在PCB缺陷检测的项目上少走点弯路。
本文还有配套的精品资源,点击获取