做工业视觉这行久了,你会发现一个规律:越是看起来“简单”的任务,落地时越会暴露出各种意想不到的问题。“基于YOLO系列算法的PCB板缺陷检测”就是这类典型项目。很多人以为拿个开源权重往伺服线上挂就行,真正搞过才知道,从数据集构建到模型收敛再到产线稳定运行,每一步都在考验工程经验,而非单纯的算法调参能力。
这篇东西,我基于自己在这类项目里的实际经验,把从数据准备、模型选型、训练调优到最终部署上线的完整链路拆开讲一遍。里面不会有天花乱坠的理论,更多是那些“文档里不会写、但现场一定会遇到”的事。
1. 项目整体思路拆解:缺陷检测到底在检测什么
先把这个项目的核心搞清楚。PCB缺陷检测,本质上是一个小目标、高精度、多类别的视觉定位问题。它跟通用物体检测不一样的地方在于:缺陷区域在整块板子上的占比往往极小,比如线路缺口、锡珠、短路、缺件,可能只有几十乘几十像素,而整张图像可能是几千乘几千的工业相机原图。这意味着你不能拿一张完整的板图直接丢给YOLO去训,后面要说的切图策略几乎是必选项。
这个项目的价值,在于它可以替代传统基于规则算法的检测方案。以前用模板匹配、灰度差、边缘提取做AOI检测,换产品型号就要重新调参,开发周期长,兼容性差。YOLO方案的逻辑完全不同:标注一批缺陷图,训练出权重,换型号时只需要补充标注再微调,甚至可以直接复用。产线维护成本、算法迭代成本都会明显降下来。
从整体架构上,一个可落地的系统至少包含这几个环节:
- 图像采集与预处理:工业相机、光源方案、图像格式统一处理。
- 缺陷数据集构建:采集、清洗、标注、数据增强、训练集划分。
- 模型训练:YOLO系列版本选型、超参配置、训练策略。
- 推理与服务化部署:模型转换、封装推理接口、缺陷可视化、结果输出。
- 产线联动与异常上报:将检测结果通过IO或Modbus协议传给PLC分拣机构。
这篇文章重点讲第2到第4环节,因为数据是模型的上限,部署是稳定性的保障,这两块最容易踩坑。
2. 数据集构建:决定模型上限的“脏活累活”
2.1 图像采集的细节注意:别让光源坑了你
工业相机的成像质量能直接影响模型能力。你采集图像时用的光源角度、颜色、亮度,最终都会成为模型“看到的特征”。假设采集时用荧光灯照明、板面反光严重,模型学到的边界特征里就混杂了反光干扰;到了现场用了环形低角度光源,图像整体对比度完全不同,模型精度会直接掉下来。
根据我的实操经验,采集环节要锁定的几个参数:
- 相机固定:用定焦工业相机+远心镜头或低畸变镜头,安装高度固定。
- 光源一致:推荐用白色或蓝色的低角度环形光源,可以有效突出铜箔线路边缘和焊盘区域。
- 图像格式:统一保存为无损格式(png或bmp),不要用jpg,因为压缩会直接丢失小缺陷的纹理细节。
另外,采集的板卡应该包含多批次、不同工艺状态的样本。只采良品或单一批次,模型在跨批次上的泛化能力几乎没有。最理想的做法是:连续跟踪产线一周左右,累积不同批次的板卡图像,每个批次图像编号做好记录,这对后面分析漏检非常有帮助。
2.2 缺陷类别定义:不是越多越好
缺陷类别的划分,要兼顾“产线需要区分”和“模型容易学习”两个维度。分太细,类别间特征相似度过高,比如“少锡”和“锡珠”在图像上可能只是形态差异,模型会反复打架;分太粗,很多不良混在一起,现场又难以定位工艺问题。
我见到的比较合理的分类方案是:
| 类别 | 特征描述 | 检测难度 |
|---|---|---|
| 缺件 | 元件本体缺失,露出焊盘 | 较易 |
| 偏移 | 元件偏移,超出焊盘范围 | 中等 |
| 桥连 | 相邻焊点粘连 | 中等 |
| 锡珠 | 焊点旁多余锡球 | 较难 |
| 线路缺口 | 铜箔走线断裂或缺口 | 最难(小目标) |
| 虚焊 | 焊点灰度异常 | 较难 |
实际项目中,可以先定这6类,跑基线实验,再依据混淆矩阵合并或拆分类别。比如线路缺口和铜渣经常被分为两类,但特征高度相似,模型很容易混,这时候果断合并成“线路异常”反而效果更好。
2.3 标注规范与质量审查
打标签是决定模型精度的第一步。YOLO格式的标注框必须贴合目标边缘,宁可略紧也不要过松。尤其是PCB这类高密度场景,框稍微大一点,就会把相邻焊盘包进去,模型学到的特征就是错的。
我做一个项目时,标注由两名标注员分别做,然后做交叉审查,计算每个人标注框的IoU一致性,低于0.85的样本打回重标。整个过程非常枯燥,但正是这种死磕,帮助模型在开局就赢在起跑线上。建议每个类别至少1500个实例,并确保不同光照条件、不同板卡批次的样本均衡。
数据增强这块,我的经验是:
- 随机水平翻转:可以稳定提升指标,PCB板面属性允许。
- 随机HSV微调:轻微调整亮度/饱和度,增强对光照波动的抗性,幅度控制在±20%以内。
- Mosaic增强:对PCB缺陷检测有很大的正面作用。它能让模型在小目标上学习到跨样本的上下文信息。
- 不要用随机旋转90度:PCB的横竖形态与线路走向有强相关性,旋转后语义混乱,实测会掉点。
2.4 切图策略:大图切小图的主要参数
PCB原图经常是5000x4000这种量级,直接放入YOLO训练不现实。切图策略就是核心工作。
我常用的切图方案是:
- 切片尺寸:640x640。
- 重叠率:10%到15%。切图时必须带重叠。原因很简单,缺陷如果恰好落在切图边缘,不重叠的话目标就被切碎,标注框被截断,等于废样本。
- 过滤规则:切出的子图中如果某个目标被边缘截断超过20%,直接丢弃该子图;如果包含的缺陷实例数低于1个,除保留少量纯背景作负样本外,大部分过滤掉,避免冗余计算。
- 推理端重叠率:推理时重叠率可以高一些,比如20%,配合NMS后处理,有效降低目标被切断的风险。
3. YOLO模型选型与训练调优
3.1 YOLO系列版本怎么选:v5、v8还是v11
YOLO系列这几年版本迭代快,不少初学者容易盲目追新。就PCB缺陷检测这个场景,我对比使用过多个版本,结论比较清晰:
| 版本 | 推理速度 | 小目标能力 | 工程成熟度 | 推荐指数 |
|---|---|---|---|---|
| YOLOv5s | 快 | 中等 | 高,资料多 | 3星 |
| YOLOv8s | 较快 | 较好 | 高,架构完备 | 5星 |
| YOLO v11s | 快 | 较好 | 较新,社区积累中等 | 4星 |
| YOLOX-s | 中等 | 中等 | 中等 | 2星 |
首推YOLOv8。它的C2f结构在特征提取上比v5的C3更高效,在PCB这种小目标场景收益明显;同时它提供了成熟的分割、姿态、分类全套生态,后期如果要做缺陷分割,可以直接切到同一套代码体系。v11在速度上有提升,但社区基数和第三方工具链成熟度不如v8稳定。
规模选择上,从s起步,而不是一上来就考虑l或x。用s跑通整个数据闭环,然后如果精度不达标,再用m或l做对比实验,观察mAP提升幅度。PCB缺陷场景下,s到m提升明显,m再往上提升就比较有限了。
3.2 训练细节:从预训练权重到超参数调优
应用预训练权重非常关键。PCB缺陷在结构特征上跟自然图像差异很大,但从ImageNet或COCO预训练权重开始,迁移学习的收敛速度和最终精度,依然比从头训练好得多。具体做法是:加载YOLOv8s.pt,冻结前10层骨干网络,先训练20个epoch让检测头收敛,再解冻全部层,用较低学习率微调。
核心超参配置我直接给出可用的起点:
# 以YOLOv8官方仓库为例 yolo detect train \ model=yolov8s.pt \ data=pcb.yaml \ epochs=150 \ imgsz=640 \ batch=32 \ lr0=0.01 \ lrf=0.01 \ mosaic=0.8 \ close_mosaic=10 \ hsv_h=0.015 \ hsv_s=0.25 \ hsv_v=0.25 \ patience=30几个参数的详细解释:
- close_mosaic=10:训练最后10个epoch关闭Mosaic增强,让模型在接近真实分布的图像上精调。这个是YOLOv8从v5后期就有的通用策略,对收敛稳定性帮助很大。
- lr0=0.01:迁移学习场景下这个值合适,过大会在开局就破坏预训练特征,过小会收敛极慢。
- imgsz=640:如果用GPU显存充裕(例如24G),可以考虑768,但需要测试模型实际推理耗时。PCB切图本来就是640,这个参数不需要额外放大。
- batch=32:如果显存不支持32,降到16;YOLOv8对batch的敏感度不算太高,但batch过小会影响BN层的稳定性,建议别低于8。
评估时不能只看mAP50。PCB缺陷场景,P(精确率)和R(召回率)的平衡点才是最该关心的。产线缺检(漏检)会造成不良品流出,误检(过检)则浪费人工复判成本。训练时就应当根据产线能容忍的成本定义优化目标:比如更偏向召回率,就在utils中把损失权重向分类损失倾斜,或者在推理时调低置信度阈值。
3.3 小目标缺陷的专项优化
小目标在YOLO里是个经典难题。PCB上的线路缺口、锡珠,尺寸可能只有20x20甚至更小。除了切图策略,还有几个有效手段:
- 提高输入分辨率:把imgsz从640提到960,对整体mAP提升显著,代价是推理时间变长。如果产线节拍允许,这个方法的效果立竿见影。
- 增加浅层检测头:ultralytics的YOLOv8在P3层有检测头,但仍可加入P2层(更大分辨率特征图),对小目标召回率有提升,但同时会带来推理耗时和显存增加,需要平衡。
- Anchor优化:YOLOv8是无Anchor的,但本质仍是基于中心点的回归方式,模型需要训练足够多的样本才容易定位小目标。因此保证小目标样本在数据增强中不被过滤掉很重要。
实操中我踩过一个很深的坑:切图时简单用640窗口切片,每个子板包含的缺陷数量太少,模型泛化性差。后来改为按缺陷中心做“缺陷居中切法”,即确保每个切图中心区域包含至少一个缺陷实例,训练集的有效样本直接翻倍,效果非常明显。
3.4 训练过程中的监控与诊断
训练不能只看loss曲线,建议同时盯住这几项:
- 验证集每个类别的召回率。某个类别的召回率如果始终上不去,多半是样本数量不足或标注质量差,去做针对性补样比盲目加训练轮数有效。
- 过拟合迹象:训练loss持续下降而验证loss在波动上升时,果断做早停。PCB场景样本有限,强撑轮数只会让模型记住训练集的噪声。
- 激活特征图可视化:挑几张典型缺陷图,观察模型关注的区域。如果激活位置不在缺陷本体而总在板卡边缘或丝印上,说明模型学到的是“位置特征”而非“缺陷特征”,需要通过增加负样本、扩充同类样本等手段纠正。
4. 模型部署与模块化实现
4.1 ONNX导出与推理优化
训练结束只是完成了一半工作,部署阶段才是真正考验工程能力的地方。我们通常先转为ONNX再做TensorRT加速,尤其在产线环境,模型推理耗时直接跟产线节拍挂钩。
导出与加速的核心步骤:
# 导出ONNX model = YOLO("runs/detect/train/weights/best.pt") model.export(format="onnx", dynamic=False, imgsz=640, half=True)导出后用onnxruntime或TensorRT再跑一遍验证集,确认数值精度对齐。这一步很重要,转换过程中的算子精度丢失可能导致个位数的精度波动。实测YOLOv8s在TensorRT FP16下,单次推理可以在5到10ms级别完成(取决于显卡),完全能跟上产线节拍。
生产环境中如果算力紧张,还有几个备选方案:
- 改用YOLOv8n版,精度下降有限,速度可以再提一个量级。
- 减少输入分辨率,但PCB小目标往往不允许你大幅压缩。
- 使用批量推理:同时处理4到8张子图,一次性走GPU推理,整体吞吐量更高。
4.2 推理逻辑与缺陷可视化
推理端代码不复杂,但几个细节值得注意:
def detect_pcb_subimages(full_img, model, slice_size=640, overlap=0.1): h, w = full_img.shape[:2] step = int(slice_size * (1 - overlap)) detections = [] for y in range(0, h, step): for x in range(0, w, step): # 边界处理 x_end = min(x + slice_size, w) y_end = min(y + slice_size, h) sub_img = full_img[y:y_end, x:x_end] results = model.predict( sub_img, conf=0.25, iou=0.45, imgsz=640, verbose=False ) for box in results[0].boxes: x1, y1, x2, y2 = [int(v) for v in box.xyxy[0].tolist()] # 映射回原图坐标 detections.append({ "cls": int(box.cls[0]), "conf": float(box.conf[0]), "bbox": [x + x1, y + y1, x + x2, y + y2] }) return detections推理时的置信度阈值建议保守一点。训练时mAP曲线拐点如果出现在0.3附近,推理时间就定0.25甚至0.15。多漏掉一个真缺陷的代价,远大于多处理几个误检框。反正现场都会有复判工位,没必要在算法侧硬砍误检。
切图重叠推理时,一个缺陷可能被多个子图同时检出,通过NMS做全局去重:
- 把所有子图的检测框映射回原图坐标系。
- 按类别执行全局NMS。类间不抑制,因为不同类别在物理上天然互斥。
- 输出统一的可视化叠加图和JSON结果,方便后续与MES系统对接。
4.3 与产线联动、结果上报
检测结果要落在产线上才创造价值。一般的交互链路是:拍照触发信号由PLC给出,GPU服务器收到触发指令后,通过RTSP或GigE接口读取图像帧,完成推理后把结果通过ModbusTCP写回PLC寄存器,PLC根据结果控制分拣气缸动作。
这里有两个实操建议:
- 接口逻辑要做好超时保护。相机信号触发后,如果推理服务因异常卡住了,必须30ms内返回超时结论并置为“疑似缺陷”,走人工复判通道,而不是让产线停机或让板子直接漏过去。
- 热备份机制。推理服务挂掉再重启,需要3到5秒的恢复时间。产线连续运行不能接受这种空窗,所以要么做双显卡双模型实例热备,要么做CPU软备。极速恢复能力比模型本身的几个点精度更重要。
4.4 模型上线的灰度验证
灰度验证很容易被忽略。如果直接全量上线,遇到模型对某一批次误检爆发的情况,产线会陷入混乱。我推荐的做法是:
- 第一个阶段,模型与人工检测并行运行一两天,只记录结果不下发分拣。
- 统计模型与人工判定的一致性,尤其是误检率和漏检率两个指标。
- 达到预设阈值(例如漏检率低于0.5%,误检率低于5%)后,切换为“模型初判+人工复判”模式。
- 运行一周,持续追踪指标,再用正常结果反哺训练数据做下一轮迭代。
5. 常见问题与现场排查技巧
5.1 漏检集中出现在某一类缺陷上
第一反应去看该类别的样本数量与标注质量。如果样本量偏少,优先做补充采集,特别是多样性样本:不同板卡批次、不同工艺参数的板子。如果样本量充足,考虑网络容量不足,升级到m或l版本。如果仅仅在特定光照条件下漏检,大概率是光源差异问题,回到数据采集环节找原因,别盲目调模型。
5.2 误检多但漏检很少
说明模型偏向于“宁可错杀”的策略,这在缺陷检测里其实可以接受。比较有效的调整手段是在推理端把conf阈值从0.25上调到0.35到0.4之间。PCB场景中的很多误检框,置信度都不会太高,这个操作能显著降低过检率。如果误检依然大量存在,检查负样本是否足够;在训练集中加入大量合格板图像,并明确标注背景区域,能有效抑制误检。
5.3 切图推理导致重复检测
重叠推理产生重复框是正常的,NMS全局去重即可。但要注意NMS的IoU阈值不宜过大,0.4到0.5比较合适。阈值太小会导致同一缺陷的多个邻近框无法被合并,输出坐标也不稳定;阈值太大,缺陷距离较近时会把不同目标合并成一个。
5.4 模型在验证集精度高、现场精度骤降
这几乎可以断定是数据分布不一致。常见原因有三个:
- 现场图像与训练图像的光照环境不一致。解决思路:在采集环节就考虑现场条件,或做在线图像归一化预处理。
- 相机安装角度或板卡固定方式不同,导致目标尺度分布变化。这时候可以用自动检测板卡位置做透视校正,让输入图像与训练数据保持相同几何形态。
- 新批次板卡出现工艺更新,看起来像新型缺陷。这种情况最头疼,需要建立线上难例回流机制:现场自动保存模型置信度低或分类置信度较低的图像,定期人工复核并补充标注。
5.5 推理速度不达标
优先优化方向是TensorRT下的FP16推理,并关闭动态shape,用固定shape做工程化。其次可将预处理(resize、归一化、letterbox)放入GPU执行,而不要放在CPU端串行处理。一次性把多路相机采集的图集齐,合并成batch做推理,效果也很明显。如果还在用CPU推理,尽早换GPU服务器,这是性价比最高的提升。
6. 项目迭代方向与经验总结
做完一套YOLO的PCB检测系统,我最大的感受是:模型训练只占整个项目工作量的三成,数据和部署占了七成。光有好的算法不够,要让算法在真实产线上长期稳定运行,更需要一套围绕数据闭环和灰度发布的完整工程体系。
后续迭代可以考虑两个方向:
一个方向是缺陷分割。检测框只能告诉你有缺陷,但维修工位要精确知道缺陷位置,如果能在检测框基础上做像素级分割,甚至用YOLOv8的seg系列实现缺陷轮廓提取,能大幅提高人工复判的效率和准确性。
另一个方向是自动光学参数回归。将检测到的缺陷类别、坐标、面积等特征与PCB工艺参数(温度曲线、锡膏厚度、贴装压力等)做关联分析,长期积累后能形成“缺陷预测”能力,提前预警工艺偏移,而不只是被动检测。这已经超出视觉检测的范畴,但行业价值更高。
如果你准备在这个课题上动手,我的建议是不要纠结用YOLOv5还是v8,先拿YOLOv8s基于公开数据集把完整流程跑通,再针对你自己的板卡数据做采集和标注。流程通了,版本迁移只是改配置的事。真正的突破点永远在数据质量和现场协同上,这是我在多个项目中反复验证下的结论。