尧图建网站 尧图建网站 YAOTU WEB BUILD 免费咨询
ARTICLE DETAIL

资讯详情

深耕网站建设与建站编程的一线实战洞察。

PCB缺陷检测实战:基于YOLOv8的小数据集训练全流程解析

PCB缺陷检测实战:基于YOLOv8的小数据集训练全流程解析 简介在工业视觉领域PCB缺陷检测是保障电子产品质量的关键环节常见缺陷包括开路、短路、鼠咬等。目标检测技术特别是YOLOv8以其高效准确的特点成为AOI系统的核心算法之一。面对真实产线中缺陷样本稀缺的困境利用小数据集进行模型训练成为实现快速落地的可行路径。通过迁移学习加载预训练权重、合理应用数据增强策略即使仅有几百张标注图像也能训练出可用的缺陷检测模型。本文以680张YOLO格式的PCB缺陷数据为例完整演示了从数据集解析、标签校验到YOLOv8训练配置与结果评估的全流程并总结了小样本训练中的过拟合、类别不平衡和小目标漏检等实用对策为相关项目开发和学术研究提供参考。 做视觉检测项目的人应该都有这种体会算法可以现学模型可以调参最让人头疼的其实是数据。尤其是PCB缺陷检测工厂里想拿到大量真实缺陷图片比训练一个模型难多了。所以我前段时间拿到这份6类、680张图像的YOLO格式PCB缺陷检测数据集时第一反应不是“终于有数据了”而是“这么点数据够干嘛”。结果一轮训练跑下来结论和我预想的完全不一样。这篇文章就把我从拿到数据到出模型的全过程完整记录下来数据集里到底有什么、680张图为什么够用、YOLO标签怎么读、如何在YOLOv8上把模型训练起来以及小数据集训练中那些容易翻车的点。如果你正在做PCB光板缺陷检测、SMT贴片后的AOI复判或者毕业论文刚好选了PCB缺陷检测这个方向这篇应该能帮你少走不少弯路。1. 先弄清楚数据集里装了什么6类缺陷的来龙去脉1.1 六类缺陷的成因、特征与检测难点网上流传的PCB缺陷检测数据集版本不少最常见的划分就是6类缺陷加正常背景。我手里这份680张的YOLO格式数据集label文件里类ID对应的缺陷类型是下面这六种类ID缺陷名称典型成因视觉特征0missing_hole 缺孔钻孔工序漏钻、钻头断裂或磨损该有孔的位置没有孔焊盘上出现空白1mouse_bite 鼠咬蚀刻过度铜箔边缘被咬出弧形凹口线路边缘出现半圆形缺口像老鼠啃过2open_circuit 开路蚀刻过度、机械划伤、电镀空洞导线中间断裂两侧铜箔不连通3short_circuit 短路蚀刻不足、残留铜屑、阻焊层破损两条不该相连的线路中间出现异常连接4spur 多余铜刺蚀刻不充分线边缘残留尖刺导线边缘凸出细小的铜尖5spurious_copper 残铜显影或蚀刻后清洗不干净板面零散分布的小铜块、铜点你可能会问为什么偏偏是这6类因为PCB制程里内层线路图形转移和蚀刻阶段最容易出这几类问题而它们又恰好是肉眼检查最耗时、最容易漏掉的部分。缺孔影响元件插装和过孔连接开路直接导致信号不通短路轻则功能异常、重则烧板鼠咬、铜刺和残铜虽然不一定立刻让板子报废但会诱发后续制程的可靠性问题。AOI设备要干的活就是把这6类问题从成千上万个焊盘和走线中捞出来。每一类的检测难度差很多。开路和短路这类缺陷通常尺寸相对大一点模型相对好学鼠咬和铜刺是很细小的边缘异常可能只有几个像素宽很容易被当作正常走线噪声残铜则形态自由度很高有大有小、有圆有尖位置也随机这类框的边界往往标得很碎一个大的残铜区域经常被拆成好几个框训练时会让模型有点晕。1.2 目录结构、图像尺寸与标注分布拿到这份数据集后第一步不是急着训练而是把文件结构摸清楚。常见的组织方式是pcb_dataset/ ├── images/ │ ├── train/ │ └── val/ └── labels/ ├── train/ └── val/每个和图像同名的txt文件就是YOLO格式标签。我这份680张图里train和val比例并不是固定的有些版本是7:3有些版本是8:2。我习惯自己重新划分一遍因为要保证测试集和训练集完全隔离防止同类缺陷的相似样本泄漏进训练集导致mAP虚高。图像尺寸方面不同放出来的版本差异挺大。有512x512的有586x589的还有800x800左右的多数是灰度图或伪彩色图。分辨率不一样其实影响训练策略——分辨率越高小缺陷越容易被保留但训练显存占用也越大。我以前在低分辨率版本上跑过鼠咬和铜刺这两类的AP明显偏低后来换成高分辨率版本mAP涨了差不多5个点。这个在后面训练章节会细说。标注框总量和每张图的分布也要心里有数。我对自己的实验版本统计过680张图里大约有1800多个标注框平均每张图2到3个缺陷。但是分布极不均匀有的板上密集出现几十个缺陷框有的图一个缺陷都没有。那些没有缺陷的纯背景图在训练里同样重要能让模型学会“不误报”但如果你发现整份数据集里背景图比例过高就要留意模型会不会把干净板子也判成有缺陷。2. 680张图到底够不够用先算账再训练2.1 从数据量角度看这份数据集的边界很多人一看680张图就觉得“太少没法训”这是拿分类任务的标准在衡量检测任务。你想想一个缺陷框就是一个有效样本单位1800多个标注框再乘上训练时的Mosaic、仿射、色彩等增强一个epoch实际能喂给模型的有效缺陷样本就远不止680个。检测模型学的是“局部区域的缺陷特征”不像分类任务那样需要整张图级别的海量样本。当然680张确实不算多。和工业界动辄几万张的私有数据集比它的边界很明显数据规模适合做什么不适合做什么几百张算法验证、课题研究、Demo演示、预研原型多工艺线切换的稳定量产模型几千张单条产线AOI复判模型、细分品类专用模型覆盖所有板型和工艺参数的通用模型几万张以上跨产线、跨板型的通用缺陷检测大部分项目其实到不了这个阶段这680张图的定位是让你把整条pipeline跑通、验证算法可行性以及拿到一个能参加中期答辩或客户演示的初版模型。配合迁移学习效果会好到出乎意料。我在训练时直接加载了COCO预训练权重虽然COCO里的“PCB板”样本极少但骨干网络学会的底层纹理、边缘、形状特征是可以直接迁移到电路板缺陷上的这就相当于把ImageNet级别的知识搬运过来大幅降低了对目标域样本量的需求。2.2 用Python统计缺陷类别和标签框数量在对数据量做出判断之前我建议你先把自己手里的标签分布跑出来看一遍。不要相信别人说的“一共1800多个框”那份数据可能和你拿到的不一样。这里有一段很简单的统计脚本直接遍历labels目录就能看到类别分布和框尺寸分布import os from collections import Counter label_dir pcb_dataset/labels/train class_counter Counter() box_size_list [] for fname in os.listdir(label_dir): if not fname.endswith(.txt): continue with open(os.path.join(label_dir, fname), r) as f: for line in f: parts line.strip().split() if len(parts) ! 5: continue cls_id int(parts[0]) w float(parts[3]) h float(parts[4]) class_counter[cls_id] 1 box_size_list.append((w, h)) print(类别分布:, class_counter) print(框数:, sum(class_counter.values())) print(平均框宽:, sum(b[0] for b in box_size_list) / len(box_size_list)) print(平均框高:, sum(b[1] for b in box_size_list) / len(box_size_list))这段代码不需要装额外的库纯标准库就能跑。跑完之后重点看两个东西第一类别数量是不是均衡。如果某类只有几十个框训练时你就要手动上调它的权重或者考虑复制增强。第二框的平均尺寸。归一化之后假设图像是512x512平均框宽0.05就是约25个像素这类小框在YOLO里天然是弱势类别后面调参时要特别照顾。我自己的习惯是训练前先打印出这个分布然后对照训练结果里的每类AP基本能提前判断哪类会崩。不是玄学是小目标和大目标在特征金字塔里的“待遇”本来就不一样。3. YOLO标签格式逐行拆解从txt到可视化3.1 归一化坐标的换算YOLO格式的标签看起来很简单每行5个数字类别ID、归一化中心x、归一化中心y、归一化宽度w、归一化高度h。但不少人第一次看到会犯迷糊比如这个2 0.513672 0.436523 0.048828 0.031250别急着往上套先理解“归一化”这三个字。归一化的意思是把像素坐标除以图像宽高得到0到1之间的小数这样不管图像是512x512还是1024x1024同样的物体在标签里数值是相同的。转换公式非常简单x_center_norm x_center_pixel / image_width y_center_norm y_center_pixel / image_height w_norm box_width_pixel / image_width h_norm box_height_pixel / image_height反过来推理的时候想还原像素坐标把归一化值乘以图像宽高就行。上面那行标签的意思就是类别ID为2如果是上面表格里的定义就是open_circuit开路中心点在图像水平51.37%、垂直43.65%的位置框宽占整张图宽度的4.88%框高占整张图高度的3.13%。放在512x512图上就是大约25x16像素的一个小缺陷框很小所以这类目标对特征金字塔的浅层特征要求很高。3.2 常见标签格式转换与验证虽然这份数据集已经是YOLO格式但实际项目中你经常会拿到VOC XML格式或COCO JSON格式的数据还是要掌握一次转换的思路。VOC XML里存的是左上角和右下角的绝对像素坐标转YOLO时需要算中心坐标再归一化# VOC XML中拿到的坐标 xmin, ymin, xmax, ymax 10, 20, 50, 80 img_w, img_h 512, 512 x_center (xmin xmax) / 2.0 y_center (ymin ymax) / 2.0 w xmax - xmin h ymax - ymin yolo_line f{class_id} {x_center/img_w:.6f} {y_center/img_h:.6f} {w/img_w:.6f} {h/img_h:.6f}转完之后一定要做一次合法性检查。最常见的坑是标签越界也就是某一行里的x_center w/2 1或者y_center - h/2 0。原因通常是原始标注框边缘超出了图像边界或者转换时四舍五入精度问题。YOLO训练时遇到越界标签轻则该框被裁掉重则导致loss异常波动。我用下面这段代码快速筛查def validate_yolo_label(txt_path): with open(txt_path, r) as f: for line_no, line in enumerate(f, 1): parts line.strip().split() if len(parts) ! 5: print(f{txt_path}:{line_no} 列数不对) continue _, x, y, w, h map(float, parts) if not (0 x 1 and 0 y 1): print(f{txt_path}:{line_no} 中心点越界) if w 0 or h 0: print(f{txt_path}:{line_no} 宽高非正) if x w/2 1 or x - w/2 0 or y h/2 1 or y - h/2 0: print(f{txt_path}:{line_no} 框边界越界)另一个非常推荐的做法是可视化标签。直接用cv2把标签画在原图上肉眼检查最直观五十张图翻下来基本就能发现标注错位、类别搞混、框没贴住目标这些问题。画框代码很简单把归一化坐标乘回图像宽高再用rectangle画出来就行。这一步千万别偷懒我在公开数据集里就发现过好几处标签中心点偏移了半个身位的情况如果不检查直接训模型会被这些脏标签带偏。4. YOLOv8完整训练流程用680张图训出可用模型4.1 环境准备与数据集组织训练之前先把环境安排好。YOLOv8是Ultralytics团队维护的项目安装只需要一条命令pip install ultralytics如果你需要CUDA加速确保PyTorch版本和你本机的CUDA版本匹配否则训练时会掉到CPU上680张图倒不是不能训但速度会让你怀疑人生。我通常建议先建一个干净的conda环境Python 3.9或3.10都行避免和其他深度学习项目的依赖打架。目录结构建议按Ultralytics的习惯整理pcb_dataset/ ├── images/ │ ├── train/ # 476张 │ └── val/ # 204张 ├── labels/ │ ├── train/ │ └── val/ └── pcb.yaml数据划分的比例我建议是7:3。680张里训练集用476张验证集用204张。这里有一个很多人忽略的点如果数据集中有“同一块板子的多个角度拍摄图”一定要保证这些图都划分到同一个集里不要让同一块板子的图一半进了训练集、一半进了验证集否则验证集指标虚高部署时立刻现原形。检查方法就是看图名PCB数据集里经常有board_01_front、board_01_back这种命名要小心。pcb.yaml的内容如下path: /your/absolute/path/pcb_dataset train: images/train val: images/val names: 0: missing_hole 1: mouse_bite 2: open_circuit 3: short_circuit 4: spur 5: spurious_copper4.2 训练配置与命令环境准备好后直接开训。我会用一条相对保守的训练命令yolo detect train \ datapcb.yaml \ modelyolov8n.pt \ imgsz640 \ batch16 \ epochs300 \ patience40 \ lr00.0005 \ optimizerAdamW \ augmentTrue \ seed42 \ device0逐项说说我为什么这么选。模型用yolov8n.pt而不是凭空初始化这是680张图能训好的关键。n是YOLOv8系列里最小的模型参数量最少最不容易在小数据集上过拟合。如果你显存够、想提升精度可以换yolov8s.pt但别一上来就上l或x小数据上大模型基本必过拟合。imgsz用640这是默认值。但我得说如果你的显卡允许把imgsz拉到1280会极大改善小目标检测。代价是训练时间成倍增加训练到一半显存还不够反而拖慢进度。我的建议是先用640跑通流程后面专门做一次1280的对照实验看看mAP提升幅度值不值得你为它买单。epochs设300配合patience40的早停机制。意思是最多训300轮但如果连续40轮验证集指标没有上升就自动停下来不用傻傻等完。这是小数据集训练的必备策略因为模型一般在几十个epoch之后就开始在训练集上“背题”继续训只会在验证集上越走越偏。lr0设0.0005比默认值低一点。迁移学习场景下预训练权重已经在一个很大的分布上收敛过到了新数据集上不需要大步长乱撞。我做过对比用默认lr00.01在小数据集上训前几轮loss直接飞掉降到0.0005之后loss曲线平稳得多。这是“为什么”层面的东西你亲手跑一次就明白了。除了命令行Ultralytics也支持Python脚本方式方便在Jupyter里跑和后续做消融实验from ultralytics import YOLO model YOLO(yolov8n.pt) results model.train( datapcb.yaml, epochs300, imgsz640, batch16, lr00.0005, optimizerAdamW, patience40, seed42, device0 )4.3 结果评估与指标解读训练结束后结果保存在runs/detect/train目录下里面包括weights/best.pt、weights/last.pt、confusion_matrix.png、results.png等。优先用best.pt这是验证集上表现最好的权重不要用last.pt。第一个要看的指标是训练集和验证集loss曲线。如果训练loss持续下降、验证loss先降后升典型过拟合曲线说明模型开始背训练集了。但不要一看到过拟合就慌。对于680张数据训练出来的模型训练loss远低于验证loss其实是常态只要验证mAP还在可接受范围内模型就是能用的。第二个是mAP。YOLOv8默认输出mAP50和mAP50-95。mAP50是IoU阈值0.5时每类AP的均值工业场景一般更看重这个指标。PCB缺陷检测里0.85以上的mAP50算及格0.9以上算不错。mAP50-95是更严格的综合指标对框的精准度要求更高小目标数据上通常会比mAP50低不少这是正常的。第三个看混淆矩阵尤其是被误检成背景的那一类。PCB板正常走线密集模型很容易把线宽变化、过孔边缘误判为开路或铜刺这类误报在工业落地时比漏检还让人头疼。如果混淆矩阵里假阳性很多优先考虑提高置信度阈值或者补一些背景图做负样本。顺带说一句如果你在做本科毕业论文想让“消融实验”部分更有说服力不要只做“加不加预训练”这种必崩的对比。没有预训练权重680张图上的随机初始化模型基本不收敛答辩时容易被追问。更合理的消融变量是数据增强的开关、图像分辨率、不同模型尺寸这三个变量在小数据集上差异明显也更能体现你对训练策略的思考。5. 小数据集训练最容易踩的四个坑5.1 过拟合loss降了验证集却乱套这是680张图训练时最典型的现象。具体表现为training loss一路降到0.1以下验证集mAP却卡在0.8上不去或者validation loss在第100轮之后开始反弹。过拟合的根源是模型容量相对于数据量“过剩”了。我这里给你三个亲测有效的对策一是增强拉满。YOLOv8默认开了Mosaic、平移、缩放、翻转、亮度扰动但你可以再激进一点调高hsv_h、hsv_s、hsv_v扰动幅度让模型对颜色变化更鲁棒。PCB数据以灰度图为主色彩增强作用有限但几何增强绝对有效——把缺陷旋转、镜像、缩放相当于白嫖更多训练样本。二是换小模型。yolov8n还过拟合就换个更轻量的Backbone或者减小输入分辨率。虽然这样做会牺牲一点上限但小数据集的上限本身不高换小模型求的是“能收敛、能用”。三是加早停和正则。patience设小一点比如30轮。训练时如果发现val loss连续不上涨果断停。硬拖下去不仅浪费时间还会把挑出来的best权重反倒留在更早的位置。5.2 类别不平衡模型对某些缺陷“视而不见”统计完标签分布你可能会发现open_circuit有400多个框spur只有100多个框。这种不均衡会导致模型把更多注意力放在样本量大的类别上样本少的类别学习不充分AP往往明显偏低。最简单的办法是复制少样本类的图像让每类框的数量大致相当。不要复制同一张图——那样模型会记住这张图的像素级细节而是对少样本类的图随机做旋转翻转再复制一份本质上是一种离线增强。另一个办法是调loss权重。Ultralytics本身没有直接暴露per-class loss weight的入口但你可以通过重采样实现类似效果在构建数据加载器时让少样本类的图像被采样到的概率更高。不过这涉及到改源码对初学者不太友好。更推荐的做法是如果某个类只有几十个框训练时损失曲线的回调直接把它忽略靠其他样本先学个大概最后针对这一类单独微调。5.3 小目标漏检细小的框根本没人看得到鼠咬、铜刺这类缺陷框可能只有20x20像素甚至更小在YOLOv8的骨干网络里经过几次下采样后特征图上只剩一个点甚至小于一个点特征金字塔的浅层特征虽然大但语义信息不够很容易漏检。我实测下来的有效方案有三个第一个是增大输入分辨率。imgsz1280对比imgsz640小目标AP能提升6到8个点代价是显存和训练时间翻倍。如果你的显卡只有8G显存可以用小batch或梯度累积硬扛。第二个是开启YOLOv8的SAHISlicing Aided Hyper Inference切图推理。训练可以维持640推理时把原图切成320或512的小块分别检测再合并结果。PCB图像是静态的切图不会引入速度上的严重负担适合离线检测场景。这个思路对鼠咬这类极小的边缘缺陷特别管用。第三个是做预处理裁剪。如果图像里就是单个板子先用传统图像处理找到板子边缘把背景裁掉再放大送进模型。相当于变相提高分辨率而且不依赖模型学出“板子在哪”。5.4 公开数据集的标签质量隐患别以为公开数据集就一定是干净的。我在训练这个数据集时就踩过一次标签错位的问题某个缺失孔缺陷的框中心点偏了半个孔位模型怎么学也学不稳训练曲线抖动得厉害。后来把可疑样本可视化出来一眼就看出来是标签标偏了。所以动手训练前建议你做一次全量标签可视化抽查每类至少看20张。重点检查三点框是不是紧贴缺陷边缘类别ID有没有标错有没有同一目标标了两个框、一个框里装了两个目标的情况。如果你发现确实有错标别犹豫直接修改txt文件。6. 如果不想用现成数据集从零自制一份PCB缺陷数据集6.1 图像采集AOI实拍与人工模拟自己做数据集首要问题是图像从哪来。最理想的是工厂AOI设备实测采样从生产线上截取带缺陷的板卡图像。但很多人没这个条件尤其是学生实验室里也许连一块缺陷PCB板都没有。退而求其次的做法是人工模拟。找几块正常PCB板用高频微振、刀片划伤、焊锡粘连等方式人为制造开路、短路、铜刺、残铜等缺陷再用微距镜头或工业相机补光拍摄。模拟样本和真实产线样本有一定分布差异但对于验证算法可行性、跑通流程来说完全够用。还有一种思路是仿真渲染。从PCB设计工具导出Gerber文件在图像处理软件里叠加噪声、覆盖缺陷形状批量生成带标注数据。这种合成数据的优势是标注精度极高缺点是和真实拍摄图像的纹理差异较大一般建议作为训练数据的补充而不是唯一来源。6.2 标注规范与工具选择标注工具我用过不少简单排个序LabelImg老牌工具支持Pascal VOC格式转YOLO格式时用内置脚本或者自己写个小转换都行。胜在轻量缺点是不支持在线协作。Label Studio现代浏览器端标注工具支持多人协作标注语义分割、矩形框、多边形都可以还能直接导出YOLO格式。适合需要连续标注几百张图的场景。Roboflow功能最全面支持在线标注、自动增强、版本管理导出YOLO格式只需要点几下。但免费版有图片数量限制大批量标注需要付费。标注时最忌讳的是标准前后不一致。我踩过的坑是标注员A习惯把缺陷框收得很紧标注员B习惯留一圈背景结果同一个缺陷在两个标注员手里视觉框大小差异巨大模型学出来的框又小又偏。所以开工前务必定好规则紧贴缺陷可见边缘留1到2个像素的余量不多不少多个紧邻目标各自标框不要合并背景板和缺缺陷板分开目录管理。6.3 导出YOLO格式与数据划分标注完成后整理目录结构。LabelImg导出的VOC XML可以用labelimg.exe自带的转换脚本也可以在命令行下用ultralytics提供的脚本转git clone https://github.com/ultralytics/ultralytics cd ultralytics python ultralytics/data/converter.py \ --voc-dir /path/to/voc \ --yolo-dir /path/to/yolo无论用什么工具转换最后一定用第二节里的校验脚本过一遍再可视化抽几十张图确认。数据划分你要特别留意先按板子把图像分组再整体划分到train/val/test防止同一板子的相似图泄漏。我的建议是train:val:test 7:2:1训练集负责喂给模型验证集用来选权重测试集只在全部训练结束后跑一次这个测试集的结果才是你对外宣传的模型指标。如果你自制的数据也是小量级比如只有两三百张那前面的迁移学习策略依然适用甚至更应该用预训练权重。小数据集加预训练权重是这类工件检测项目的安全牌。我个人经验是数据集的制作永远是花时间最多、回报也最稳定的一环。很多人喜欢在模型结构上折腾但真正让检测效果脱胎换骨的往往是多花一周时间把标签做干净、把增强配好、把场景覆盖全。一开始觉得680张图太少训完才意识到只要策略用得对小数据集也能撑起一个具备落地价值的基线模型。本文还有配套的精品资源点击获取
返回列表