ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

YOLO目标检测PCB缺陷数据集:三种标签格式与训练全流程解析

YOLO目标检测PCB缺陷数据集:三种标签格式与训练全流程解析 简介面向YOLO目标检测学习与研究者的PCB缺陷数据集共含1000张真实场景图片已用LabelImg完成高质量标注并提供VOC(xml)、COCO(json)与YOLO(txt)三种格式标签分别存放于独立文件夹可直接接入YOLO系列模型训练。压缩包内共2000个文件以xml与txt标签文件为主另有yaml配置、Python划分脚本及6份环境搭建/训练教程文档整体约275.87MB能满足从数据准备到训练的全流程需求。配套资源还包含Linux与Windows双平台的YOLO环境搭建教程、训练案例教程以及训练集/验证集/测试集划分脚本用户可按需调整划分比例将数据集无缝迁移到自己的检测任务中。目前已有713人学习适合刚接触目标检测或需要PCB缺陷数据支撑课题、比赛与课程项目的读者。1. YOLO目标检测PCB缺陷数据集三种标签格式一次配齐的落地资源PCB板缺陷检测是工业视觉里最典型的落地场景之一但真正卡住新手的地方往往不是模型选型而是数据准备。这份YOLO目标检测PCB缺陷数据集包含1000张真实场景的PCB图片用LabelImg标注配套提供VOCxml、COCOjson、YOLOtxt三种格式标签分别存放在不同文件夹下可以直接用于YOLO系列的目标检测压缩包里还附带三个数据集划分脚本、Linux与Windows双平台的环境搭建教程和训练案例教程。做工业质检的人最清楚PCB缺陷样本的采集和标注成本有多高所以这份资源对想快速跑通完整训练流程、又不想从零标数据的新手来说非常友好。我拆完以后最大的感受是它把从原始图片到可训练数据集之间最繁琐的环节全部替你处理好了这套流程走明白之后后面换任何数据集都顺。2. 数据集结构拆解图片、标签与目录组织的对应关系2.1 目录结构与文件名匹配设计解压后先别急着跑脚本把顶层目录扫一遍。这份资源的组织方式是图片一个文件夹VOC、COCO、YOLO三种标注各一个子文件夹脚本和教程文档单独放。这种“图片目录、标注目录、工具目录”分离的布局在工业项目里最常见目的就一个划分数据集时只需要按文件名前缀把图片和对应标注一起搬动不需要再按扩展名做二次处理。这里最关键的约定是文件名一一对应。VOC的xml和YOLO的txt都按图片同名命名例如图片是pcb_0001.jpg标注就是pcb_0001.xml和pcb_0001.txtCOCO格式则把所有标注汇总到一个json里靠images和annotations两个数组里的id字段建立关联。理解这个对应关系是后面所有操作的前提如果文件名对不上再好的划分脚本也搬不动数据。我拿到任何数据集都会先做三个检查第一对比图片目录和标签目录的文件数量是否一致第二随机抽几个xml和txt看类别名拼写是否统一第三把标注画回图片上肉眼确认框的位置对不对。这三件事花不到十分钟却能避免后面训练时出现类别错乱、mAP虚高之类的问题。2.2 VOC、COCO、YOLO三种格式的核心差异与选型理由不少刚接触目标检测的人会问为什么一份数据集要同时给三种格式直接给一种不就行了原因很简单不同训练框架和工具链对标签格式的要求不一样而格式转换恰恰是数据准备里最耗时间的一环。VOC格式本质是xml文件逐图记录每个目标的像素坐标xmin、ymin、xmax、ymax打开文件就能看到框在图片的哪个位置适合人工检查和调试。缺点也很明显每个目标占一段xml节点信息冗余度高解析速度偏慢。COCO格式把整个数据集的标注汇总成一个json结构上是图片列表、标注列表、类别列表三部分。它的优点是存储紧凑自带area、iscrowd这些字段很多检测框架原生支持COCO评估方式。缺点是单个文件体量大结构层级深改错一个括号整份标注就失效了。YOLO格式最精简每个txt文件一行一个目标记录类别id、归一化中心点坐标和宽高。坐标全部落在[0,1]区间与输入图片尺寸解耦训练时不管resize到640还是1280标签都不需要重新算。缺点是纯小数坐标肉眼排查不方便人工修改容易看花眼。三种格式的横向对比见下表格式文件组织坐标表达典型适用场景VOC每张图一个xml像素绝对坐标(xmin, ymin, xmax, ymax)人工检视、调试、VOC系列工具链COCO整个数据集一个json像素绝对坐标(x, y, w, h)COCO API、mmdetection、实例分割任务YOLO每张图一个txt归一化相对坐标(class, cx, cy, w, h)YOLOv5/v8官方训练脚本PCB缺陷常见类型一般包括缺孔、短路、划痕、污染等具体类别以这份数据集里的标注为准训练前先打开标签文件把类别清单列出来。这份数据集把三种格式的标签都按文件夹分开放好省掉了最麻烦的转换步骤。我自己做项目时最重视的就是这一点数据格式的处理时间越短留给模型调参的时间就越充足。2.3 标注质量验证十分钟快速画框检查摘要里说标注框质量高但实际拿到手不能全凭描述自己验证一遍心里才有底。我一般用下面这段Python脚本把VOC的xml标注画回图片上随机抽十张快速翻看。import os import cv2 import xml.etree.ElementTree as ET import random image_dir images xml_dir annotations/voc_xml img_files [f for f in os.listdir(image_dir) if f.endswith(.jpg)] random.seed(0) samples random.sample(img_files, min(10, len(img_files))) for img_name in samples: xml_path os.path.join(xml_dir, img_name.replace(.jpg, .xml)) if not os.path.exists(xml_path): print(f[缺失] {img_name} 没有对应xml) continue img cv2.imread(os.path.join(image_dir, img_name)) tree ET.parse(xml_path) root tree.getroot() for obj in root.findall(object): name obj.find(name).text box obj.find(bndbox) xmin int(box.find(xmin).text) ymin int(box.find(ymin).text) xmax int(box.find(xmax).text) ymax int(box.find(ymax).text) cv2.rectangle(img, (xmin, ymin), (xmax, ymax), (0, 0, 255), 2) cv2.putText(img, name, (xmin, max(ymin - 5, 15)), cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0, 0, 255), 2) out_path fcheck_{img_name} cv2.imwrite(out_path, img) print(f[已生成] {out_path})这段脚本逻辑很简单把每张图对应的xml解析出来拿到目标类别和边界框坐标用OpenCV在原图上画出红框和类别名。参数上需要注意两点第一是文件名的替换方式replace(.jpg, .xml)的前提是图片必须是jpg后缀如果资源里是png就需要改成.png第二是random.seed(0)固定抽样顺序方便不同批次检查时看到同样的十张图。检查时重点看三类问题标注框是否明显偏离缺陷区域、同一类缺陷的框是否大小差异过大、有没有整块缺陷区域没被框住。这三类问题直接决定训练出的模型是能用的还是只能看的。3. 划分脚本实战训练集、验证集、测试集是怎么切出来的3.1 三个脚本的分工与适用场景压缩包里给了三个划分脚本对应两种不同的数据组织方式。split_train_val生成ImageSets下txt文件划分脚本.py走的是Pascal VOC那套老路只生成包含图片路径的txt列表文件不做实际文件复制类似压缩包里的train_list.txt就是这种列表的产物另外两个脚本的命名里带“划分写入新文件夹”说明它们会把图片和对应标签一起复制到训练、验证、测试的新目录里。两种方式各有各的用途。txt列表方式适合数据量大的场景例如数万张图片复制文件浪费磁盘空间和时间训练框架直接读列表路径就行写入新文件夹的方式适合中小型项目好处是训练集、验证集、测试集目录清清楚楚别人接手项目时一目了然。对于1000张PCB缺陷图片这个量级我一般直接用写入新文件夹的方式目录结构清晰后续排查问题方便。第二个和第三个脚本的区别在于多了一个测试集。只划分训练集和验证集的脚本适合调试阶段尽快跑通流程带测试集的脚本适合正式实验最终报告里的精确率、召回率必须用独立测试集来算才不会被数据泄漏误导。3.2 划分比例与随机种子参数怎么调这类划分脚本的顶部通常有一段参数区我改脚本的习惯是先看参数区不动核心逻辑。以训练集、验证集、测试集划分脚本为例需要关注的参数无非这么几个源图片目录、源标签目录、输出根目录、三集比例、随机种子。PCB缺陷场景有一个和通用目标检测不同的地方缺陷类别分布通常很不均匀比如缺孔、短路样本多划痕、污染样本少。如果直接按全局比例随机划分可能出现某一类缺陷全跑到训练集、验证集里恰好没有的情况模型验证时就漏掉了这类缺陷。常见做法是先把样本按类别分组在每个组内分别按比例划分保证三个集合的类别分布接近一致。在动手改脚本前先理清自己的需求# 以提供的“训练集、验证集、测试集划分脚本”为例我会在参数区这样调整 image_src images # 原始图片目录 label_src annotations/yolo_txt # 源标签目录可选voc_xml或coco_json output_root dataset_splitted # 划分结果输出目录 train_ratio 0.8 # 训练集比例 val_ratio 0.1 # 验证集比例 test_ratio 0.1 # 测试集比例 random_seed 42 # 固定随机种子保证划分结果可复现固定随机种子这件事很多新手会忽略。随机种子不固定每次运行脚本划分结果都不一样意味着你换了一次划分之前跑出来的实验结果就丧失了可比性。random_seed 42只是习惯设置关键不是42这个数字而是每次实验保持同一个值让数据集划分可复现。还有一个容易被忽略的参数是标签目录的选择。这份数据集给了三种格式划分脚本里要明确指出输入的是voc_xml还是yolo_txt不要直接把整个annotations目录丢进去否则脚本会把xml、json、txt混在一起处理出来的划分结果一团乱。我通常只用YOLO格式的txt做划分因为后面训练YOLO直接能用。3.3 划分结果完整性校验划分完不要直接开训先验证图片和标签是不是都完整搬过去了。我习惯在划分脚本之后跟一段校验逻辑import os def count_file_pairs(img_dir, label_dir, ext.txt): imgs set(f[:-4] for f in os.listdir(img_dir) if f.endswith(.jpg)) labels set(f[:-4] for f in os.listdir(label_dir) if f.endswith(ext)) # 取差集看哪些名字只存在于一侧 missing_label imgs - labels missing_img labels - imgs print(f图片总数: {len(imgs)}, 标签总数: {len(labels)}) if missing_label: print(f缺少标签的图片: {missing_label}) if missing_img: print(f缺少图片的标签: {missing_img}) return len(imgs) len(labels) for split in [train, val, test]: count_file_pairs( fdataset_splitted/{split}/images, fdataset_splitted/{split}/labels )这段脚本的核心是取文件名前缀做集合差图片前缀集合和标签前缀集合做减法哪一侧多出来就说明哪一侧有文件没配对。参数上要注意f[:-4]这个切片它是从文件名末尾去掉4个字符恰好去掉.jpg或.txt的后缀。如果图片是png后缀长度也是4不用改但如果是jpeg后缀长度是5切片就得改成f[:-5]。校验脚本输出“图片总数”和“标签总数”一致时并不代表所有文件一定匹配成功还需要确认差集为空。如果缺失标签的集合不为空多半是划分脚本处理时漏掉了部分文件或者原始标注文件本来就缺这时候回到源头补文件比在训练时硬顶要节省时间得多。4. 把这套数据集跑进YOLO训练环境搭建与训练脚本修改4.1 Windows与Linux双平台环境搭建要点数据集自带的教程里分别给了Linux和Windows两套环境搭建方案这一点很务实。Ubuntu环境是深度学习服务器的主流选择环境干净、依赖好装Windows则适合个人笔记本调试和小数据量训练。两套方案的核心步骤一致差异主要在驱动安装路径和命令语法上。Linux这边YOLO的环境搭建本质就是三件事装显卡驱动、装CUDA和cuDNN、装Python依赖。最稳妥的路线是用Anaconda建一个独立虚拟环境避免和系统Python打架。常见做法是Python版本选3.8或3.9PyTorch版本要和CUDA版本匹配。torch.cuda.is_available()一定要跑到输出True很多新手在这步翻车都是因为装成CPU版本或CUDA版本不匹配。验证命令很简单python -c import torch; print(torch.__version__, torch.cuda.is_available())如果输出True说明GPU环境基本没问题如果输出False先检查驱动和CUDA版本是否对应不要急着重装PyTorch。显卡驱动的版本决定CUDA能不能用这是最常见的环境搭建翻车点。Windows这边逻辑一样只是驱动和CUDA的安装全部走图形界面。有个容易忽略的坑是Windows下路径不要出现中文数据集解压路径如果带中文文件夹名脚本很可能在读取数据阶段直接报错。另外建议把Anaconda的虚拟环境激活后再跑训练命令不要用系统自带的Python依赖版本容易乱。提示Windows下训练时数据集路径里不要出现中文和空格否则脚本大概率读到一半直接退出。4.2 数据配置和训练参数怎么改把数据集喂给YOLO训练前要先写一个数据配置文件告诉训练脚本数据在哪里、类别有几种、各自叫什么名字。以常见的YOLOv5和YOLOv8配置为例这个文件是一个yaml# 数据配置文件路径建议写成绝对路径避免相对路径踩坑 # 下面的类别名只是示例实际以数据集标注为准 path: /home/user/pcb_defect_dataset/dataset_splitted # 划分后的数据根目录 train: train/images val: val/images test: test/images nc: 4 # 类别数量按实际标注类别修改 names: 0: missing_hole 1: short_circuit 2: scratch 3: pollution这里的nc必须和names的数量保持一致写错一个数训练过程不会报错但预测结果会错得离谱。类别名建议用英文小写加下划线中文名在部分可视化工具里会乱码纯英文最省事。训练命令里值得关注的参数主要是这几个--batch-size、--epochs、--imgsz、--weights。1000张图片属于小数据集batch size不要贪大显存不够就减半。epochs根据验证集mAP曲线早停来定不是越大越好。预训练权重建议从yolov5s.pt或yolov8s.pt开始小模型在没有大规模数据时收敛更快不容易过拟合。如果本地网络下载慢可以事先把预训练模型下载好放到项目目录下训练命令里直接指定权重路径。python train.py --data pcb_data.yaml --weights yolov5s.pt \ --batch-size 16 --epochs 100 --imgsz 640 --patience 20patience 20表示验证集指标连续20个epoch没有提升就自动停止这个参数对时间紧张的项目特别实用。跑起来后重点盯三张图损失曲线是不是在下降、验证集mAP是不是在涨、类别分布图里每个类别是否都有一定数量的样本。损失曲线下降但mAP不动说明模型在过拟合边缘mAP在涨但某个类别一直检不出就需要回看数据划分是否均匀。5. 避坑指南训练自己的数据集时最常见的五个雷区5.1 高频踩坑记录现象、原因与解决坑一训练正常跑完但val mAP一直为0。现象是loss正常下降验证集精确率和召回率却始终是0。原因多半是数据配置文件里nc和标注txt里的类别id不匹配或者类别id从1开始写而YOLO要求从0开始。解决方法是先检查数据集里所有txt文件的第一个数字确认类别id最大值为nc - 1。我遇到过一个项目标注工具有个默认设置把类别从1开始编号数据里出现了id为5的目标而配置只写了0到4模型自然什么都学不会。坑二loss值爆炸或出现NaN。现象是训练到中间某个epochloss突然变成NaN。原因可能是batch size过大导致显存溢出也可能是学习率设置过高。解决方法是把batch size减半或把初始学习率从0.01降到0.001。PCB数据本身的缺陷区域较小模型容易在早期被大量背景干扰用小学习率起步更稳。坑三同一种缺陷有的图片有标签有的图片没有。现象是同一个类别的目标在部分图片完全没被检测到。原因多半是划分脚本处理时漏掉了一部分标签文件或者原始标注文件名和图片名不一致。解决方法是回到第三章的配对校验脚本跑一遍看差集在哪。还有一个隐蔽情况原始标注里一张图有多个缺陷框划分脚本只复制了其中一个txt导致训练样本不完整这类问题也要靠配对校验才能发现。坑四用验证集当测试集导致指标虚高。现象是训练时验证集mAP有0.9到了现场部署实际检测效果却很差。原因是项目为了省事只划分了训练集和验证集调参过程反复在验证集上看效果本质上已经泄漏了。解决方式是正式实验必须切出独立测试集哪怕数量少了点至少能说明模型没在考场上看过答案。坑五Windows训练时报“No such file or directory”。现象是训练脚本读不到图片或标签文件。原因通常是路径分隔符或编码问题Windows的\和Linux的/在某些脚本里不能被兼容也可能路径里有中文。解决方法是把数据集挪到纯英文目录下并在脚本里统一用os.path.join拼接路径不要手写死斜杠。5.2 从根源上规避训练前十分钟检查清单上面这些坑其实都能在训练开始前用十分钟检查完。我现在每次训练前都会顺手把这几件事走一遍数据配置文件的路径是否真实存在、nc是否等于文件夹里标注类别的总数、每张图片是否都有对应标签、类别id是否从0开始、训练命令里的--data指向的yaml有没有写错中文路径。这些看起来琐碎但每一条都是在过往项目里真实消耗过半天以上时间的血泪经验。提示如果训练跑得特别慢先别怀疑机器性能检查一下是不是数据读取成了瓶颈也就是GPU利用率很低但CPU占用拉满。小数据集完全可以先做个缓存提速YOLOv5里开启--cache参数把图片缓存进内存训练速度会有明显提升。6. 模型验证与进阶mAP曲线、混淆矩阵和误检分析训练结束后不能只看val mAP一个数值还得做两件事看混淆矩阵看预测结果图。YOLO训练日志里会生成混淆矩阵图它告诉你哪些类别之间容易互相弄混。PCB缺陷里短路和污染在视觉上有时确实接近如果混淆矩阵显示这两个类别预测时经常纠缠不要先急着加数据先把标注样本翻出来对比一遍确认到底是模型问题还是当初标注问题。验证集的最后一批预测结果图也值得仔细翻。我一般会把预测结果里置信度低于0.5的检测框单独筛出来看看这些低置信度检测是真缺陷还是背景误检。如果是背景误检需要在数据配置里适当提高置信度阈值如果是真缺陷说明该类别欠样本需要补充数据或做数据增强。这个流程比盲目调参有效得多。PCB小缺陷还有一个经典问题马赛克增强时小目标容易被切碎如果用了Mosaic增强且缺陷区域很小可以在增强参数里关掉或降低马赛克比例避免模型学到一堆残缺样本。这套数据集的价值在于它把格式转换、目录划分这些脏活累活都做完了但它仍然是一个通用数据资源具体效果还取决于你如何划分、如何设参、如何筛结果。从那以后我每次拿到新数据集都会把校验脚本、划分脚本、训练脚本像工序一样固定走一遍顺序从来不敢乱。希望帮到你。本文还有配套的精品资源点击获取
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进