做工业视觉这些年,被问得最多的问题就是:深度学习做缺陷检测到底行不行?说实话,这个问题跟项目绑得太死,很难一句话回答。但PCB板缺陷检测恰好是一个特别典型的例子——它是那种“用传统机器视觉能磨出来、但用深度学习会舒服得多”的case。我去年完整落地过一套基于深度学习的PCB缺陷检测系统,从数据采集、模型训练、到产线部署都走了一遍,踩了不少坑也积累了不少心得,这篇就把它掰开揉碎讲讲。
这套系统解决的是电子制造里最实际的问题:PCB裸板或贴片后板卡上出现短路、断路、缺孔、划痕、余铜这类缺陷时,靠人工目检效率低、漏检率高,传统AOI设备(自动光学检测)则依赖人工设计的特征和阈值,换一种板材、换一道工艺就得重新调参。深度学习方案通过卷积网络自动学习缺陷特征,端到端输出缺陷位置和类别,既提升了检测准确率,也大幅降低了产线维护成本。对刚接触这个方向的工程师、研究生,或者正在评估工业质检智能化改造的同行来说,这篇内容可以直接当项目参考用。
1. 项目到底在解决什么问题
1.1 PCB质检的行业痛点
PCB是所有电子产品的物理底座,上面密密麻麻的走线、焊盘、过孔,任何一处缺陷都可能导致整板功能失效。常见的缺陷类型包括短路(两条不该相连的线路搭在一起)、断路(线路中断)、缺孔(过孔漏钻)、鼠咬(线路边缘缺损)、余铜(板面残留铜箔)、锡珠(贴片后焊锡球残留)等。这些缺陷有的肉眼可见,有的只有零点几毫米,全靠人工目检不仅费眼费力,而且检测标准很难统一——不同检验员的标准松紧不一样,同一块板上午检和下午检也可能给出不同结论。
传统AOI设备通过高分辨率相机采集板卡图像,然后依赖人工设计的图像处理算法来检测缺陷,比如用模板匹配对比标准版图、用阈值分割突出异常区域、用形态学运算过滤噪声。这类算法在一类固定产品上可以稳定运行,但一旦产品换型,或者产线工艺参数微调导致图像背景变化,误报率就会急剧上升,现场的工程师常常陷入“调整阈值—跑测—再调整”的循环里。更头疼的是,规则算法很难覆盖所有缺陷形态,很多缺陷在彼时的打光条件下呈现出的灰度变化极其微妙,传统方法根本抓不住。
1.2 为什么深度学习是当下的最优解
深度学习切入这个问题的核心优势在于:不需要人去定义“缺陷长什么样”,只需要提供足够多的缺陷样本,网络自己会学出一组鲁棒的特征表达。用目标检测框架来做,模型一次性输出缺陷的类别、置信度和位置框,检测流程从“多阶段规则串联”压缩成“单阶段端到端”,逻辑简单了很多。
我见过不少同行在讨论阶段纠结“是不是上深度学习有点大材小用”,但实际跑完数据后,结论都比较一致:对于PCB这种背景相对规整、缺陷形态相对固定的场景,CNN的特征提取能力远优于手工特征。尤其是面对轻微短路、细小缺口这类小目标缺陷,深度模型在召回率上的优势是传统算法难以企及的。而且,深度学习方案的维护成本曲线更平滑——新产品上线只需要补充少量数据、微调模型,而不是重新写一轮图像处理规则。
当然,深度学习方案也不是把图扔进网络就完事,它真正难的点在数据、标注和部署这几个环节。下面按项目推进的顺序展开。
2. 数据是这类项目的命门
2.1 数据集怎么来
做缺陷检测,很多人第一步会想到开源数据集。确实,开源界流传较广的PCB_DATASET数据集是预研阶段很好的练手材料,它包含了短路、断路、缺孔、鼠咬、余铜、毛刺等常见缺陷类别,图像尺寸较小但缺陷类别覆盖比较全,用来验证模型选型是否合理完全够用。我建议所有刚开始接触这个方向的人先用这类公开数据跑通一个完整流程,再做真实产线的数据采集,能节省大量调试时间。
但真实项目里,公开数据集远远不够。产线工况和开源数据的差异很大:板材颜色不同、铜厚不同、打光方式不同、相机分辨率不同,都会导致图像分布变化。实际项目的数据来源主要是客户产线部署的工业相机。常见配置是500万到1200万像素的面阵相机,配合环形光或同轴光照明,采集到的图像分辨率在2448×2048甚至更高。这类图像比公开数据集大得多,不能直接整图送入网络,通常先切分成Patch,再筛选包含缺陷的Patch进入训练集。切分尺寸一般在640×640或512×512,具体取决于检测目标的最小尺寸和显存大小。
2.2 标注规范与质量控制
标注是数据环节里最容易被低估的一步。PCB缺陷往往很小,一个短路点在500万像素的图里可能只有几十个像素,标注时稍微手抖,框中心偏了,训练出来的模型边界就会不稳。所以我强烈建议在标注阶段定三条硬规则:
- 所有缺陷采用矩形框标注,尽量减少框的冗余边距,保证缺陷目标占满框的70%以上。
- 同一缺陷跨Patch切割时,在各个Patch中都要完整标注,不能漏标。
- 模糊的、无法确认的区域宁可先不标,也不要标出“似是而非”的框,否则会直接污染训练样本。
标注工具方面,LabelImg或Labelme都可以,但这俩工具在缺陷数量多的图像上效率偏低。我实际用下来,XAnyLabeling这类工具更顺手,支持交互式分割辅助标注,对PCB这种小目标标注场景提升很明显。标注完成后,一定要安排第二个人复检一遍,重点检查小目标的框是否贴合、是否有漏标,这一步能把“脏标注”带来的训练噪声降到最低。
2.3 数据增强策略
PCB缺陷数据天然存在类不平衡问题,比如短路的样本可能比缺孔多一个数量级。如果直接拿原始数据训练,模型会把大多数注意力放在高频类别上,稀有小类别几乎学不到。数据增强是缓解这个问题最直接的手段之一。
我用的增强组合是:随机翻转(水平+垂直)、随机旋转90度、HSV颜色抖动、随机亮度和对比度调整、马赛克增强。其中马赛克增强(Mosaic)特别适合PCB场景,它把四张图随机裁剪拼接成一张,既增加了单张图像中的目标多样性,又让小目标更密集地出现,对PCB这种小目标密集场景效果非常明显。但要注意,在线增强会增加每个epoch的训练时间,建议在GPU资源允许的情况下使用,否则可以换成离线增强打样本。
有一点要特别注意:测试和验证阶段绝对不能做几何增强,只能做保持语义不变的预处理(如归一化),否则评估指标会虚高,上线后模型真实表现会对不上。
提示:PCB缺陷识别的本质是“小目标检测”,如果数据增强只做全局缩放而不关注小目标密度,模型对小缺陷的召回率很难提上去。Mosaic、Copy-Paste这类能让小目标在训练图中“多出现几次”的方法,优先级是最高的。
3. 模型选型:精度和速度的博弈
3.1 主流方案对比
PCB缺陷检测可以用目标检测、图像分类、语义分割三种技术路线来做,目的各不相同。图像分类只能判断“板子有没有问题”,给不出具体位置,适合粗筛;语义分割能输出像素级缺陷轮廓,但标注成本高、推理速度慢,一般用于特殊缺陷的精修定位;目标检测输出缺陷类别加位置框,是当前工业落地的绝对主流。
目标检测框架里,两阶段代表是Faster R-CNN,一阶段代表是YOLO系列和SSD。Faster R-CNN精度高,但推理速度通常在50ms以上,在GPU上还好,部署到边缘设备就吃力了。YOLO系列经过多个版本迭代,速度和精度的平衡做得很成熟,尤其是v5、v8两个版本在工程界应用极广,训练生态、部署工具链都相对完善。SSD目前使用率已经明显下降,工程化支持不如YOLO系。从项目落地角度,我不太建议在“哪个框架更强”上花太多时间,关键是看团队熟不熟、部署道路顺不顺。
3.2 我选型的具体理由
我这个项目最终选了YOLOv5s作为基础模型,理由有三点。第一,PCB缺陷检测对实时性有硬要求,产线节拍一般要求在几十毫秒内完成单板检测,YOLOv5s在单张GPU上跑640×640输入、batch为1时,耗时普遍在5到10ms左右,余量很充足。第二,YOLOv5对中小目标的检测能力经过广泛验证,配合PANet特征融合结构,底层特征和高层语义能有效融合,这对捕捉细微的断路缺陷非常关键。第三,工程生态好,从训练到导出再到TensorRT部署,都有现成路径可参考,项目交付周期能压下来。
当然,如果项目对精度要求更极端、又允许推理时间放宽,可以考虑YOLOv8m或YOLOv8l;如果部署平台是Jetson这类边缘设备,可以进一步压缩成YOLOv5n或使用MobileNet主干。这里没有“最好的模型”,只有“最匹配产线约束的模型”。
输入分辨率方面,我最终用了640×640。理论上分辨率越高小目标信息越完整,但训练和推理成本也随之上升。PCB缺陷很多是极小的连通区域,如果原始图像本身分辨率就不够,硬拉高输入分辨率也不会凭空增加信息。更合理的做法是保证原始采集图像的分辨率足够大,切块后的小Patch输入网络,而不是整张大图缩放。
3.3 损失函数与训练技巧
YOLO系的默认损失函数在PCB场景下基本够用,分类分支用BCE,回归分支用CIoU或SIoU,目标置信度分支也是BCE。但有一个常见的坑:PCB缺陷样本里难例(比如与走线纹理高度相似的鼠咬缺陷)很多,默认的BCE分类损失会让模型在难例上反复震荡。解决方法是引入Focal Loss思想,给难例分配更高的损失权重,让模型把注意力集中在那些“看起来像却又不是噪声”的缺陷上。
Anchor设置也值得调一下。YOLOv5默认的Anchor是针对COCO数据集尺寸聚类的,直接用在PCB小目标上不是最优解。我建议训练前用K-Means在自有数据集上重新聚类Anchor,聚类中心数量可以在默认基础上微调。这一步很多教程不会写,但对小目标检测的召回率提升非常明显。亲测效果:聚类后mAP@0.5提升了2个百分点左右,完全值得花这十分钟。
4. 训练与验证的完整流程
4.1 环境配置与数据划分
训练环境我用的是单张消费级GPU,显存16GB,对于YOLOv5s这个规模完全够用。软件栈是标准的PyTorch框架,训练脚本基于开源框架改造,数据集格式按YOLO格式组织:每张图像对应一个同名的txt文件,每行内容为“类别id 中心点x 中心点y 宽 高”,坐标值归一化到0到1之间。
数据划分这里有个容易犯的错误:直接按图像随机划分训练集和验证集。PCB图像往往来自同一批次板卡的连续拍摄,相邻图像高度相似,如果按图像随机划分,验证集里会出现大量和训练集几乎重复的图像,评估指标会虚高。正确的做法是按“板卡”或“批次”划分,一个批次出去的图像要么全在训练集,要么全在验证集,这样验证集才能真正反映模型面对新板卡时的泛化能力。训练集、验证集、测试集我按7:2:1分配。
4.2 训练参数细节
超参数方面,我记录一套实测下来效果不错的配置,可以直接作为起点:
- 输入尺寸:640×640
- 训练轮数:200个epoch(包含预训练模型的热身轮数)
- Batch大小:16
- 优化器:SGD,初始学习率0.01,配合warmup(前3个epoch从0.001线性升到0.01)
- 学习率调度:余弦退火
- 混合精度训练(AMP):开启,训练速度提升明显且精度不掉
- EMA(指数移动平均):开启,会让模型更稳,尤其是小目标场景
开启AMP之前,我拿同一份数据做了对比实验。不开AMP时收敛曲线更平滑,但每个epoch耗时高出约30%;开AMP后精度几乎没有差异,所以我直接锁定了AMP方案。EMA则是稳定精度的“性价比之王”,几乎不需要额外代价,推荐所有人训练检测模型时都开着。迁移学习是必须做的,用ImageNet预训练权重初始化主干网络,然后冻结主干前几层跑5个epoch热身,再解冻全模型训练。这样收敛速度快,最终精度也比随机初始化高不少。
4.3 评估指标怎么定才靠谱
缺陷检测项目不能只看一个mAP就交付,产线更关心两类指标:漏检率(缺陷没检出来,会导致不良品流出)和误报率(良品被误判为不良,会导致产线停线复判)。我建议在项目验收时同时盯这几个指标:
- mAP@0.5:衡量整体检测精度,用于模型选型对比
- Recall(召回率):漏检越少越好,这是质检场景的第一优先
- Precision(精确率):误报越少越好,降低人工复判负担
- F1 Score:召回率和精确率的综合,用于调阈值
- 单帧推理时间:验证是否满足产线节拍
实际中,“漏检”和“误报”往往此消彼长,调节置信度阈值可以在这两者之间滑动。比如把置信度阈值从0.25下调到0.1,召回率可能上升,但误报也会明显增多。上线前一定要结合客户能接受的人工复判成本,确定一个最优阈值。我最终定在0.18,配合人工复判环节,那个项目的漏检率压在千分之三以下,误报率控制在百分之二以内。
5. 部署落地:从实验室到产线
5.1 模型转换与加速
模型训完只是万里长征走了一半,落地部署才是真正见真章的地方。PyTorch模型直接上线推理效率不行,我的标准流程是:PyTorch模型先导出成ONNX,再转成TensorRT引擎,最后用TensorRT推理。转换过程中有几个关键点:
- 导出ONNX时固定输入尺寸,不要设动态尺寸,TensorRT对固定尺寸的优化更激进。
- 如果是TensorRT INT8量化,需要准备一个校准数据集,我用了验证集中的1000张图像,跑完后精度掉点可以接受,在1%以内。
- fp16和INT8的耗时差异并不大,但INT8精度有损,如果产线允许,优先用fp16,省心很多。
转换后我在同一种GPU上对比过耗时:PyTorch原模(未优化)约18ms,ONNX Runtime约12ms,TensorRT fp16约4ms。对于产线节拍50ms以内的场景,TensorRT方案优势非常明显。如果部署在无GPU的工业主机上,也可以考虑用ONNX Runtime在CPU上跑,但推理时间会长很多,一般只适合抽检用途。
5.2 推理服务怎么设计
部署形态我建议做成独立的检测服务,而不是把模型代码直接嵌到产线控制系统里。我用的方案是FastAPI封装一个HTTP服务,输入是图像(base64编码),输出是缺陷列表(类别、置信度、坐标框)。产线MES系统或者上位机通过HTTP调用这个服务,逻辑清晰、耦合度低。后来为了降低通信开销,也加了gRPC接口做备选,实测在局域网内两者延迟差距不明显,HTTP足够用。
服务内部处理逻辑有几步细节值得注意。第一,图像切块:工业相机拍出的大分辨率图先切分成多个小Patch,分别送入模型,再把结果合并回原图坐标系。这里要注意Patch之间留出重叠区域,我一般留20像素重叠,否则跨块的缺陷会被截断漏检。第二,后处理NMS:每个Patch内部的检测结果合并后,要在整个图像维度再做一次NMS,去除跨Patch的重复框。第三,可疑结果标记:置信度落在阈值附近(比如0.1到0.18之间)的目标,统一标记为“待人工复判”,而不是直接判NG或OK。
5.3 与产线联动的注意事项
部署完模型只是第一步,和产线配合才是日常运维的重头。当检测系统判NG时,板卡会被送到人工复判台,现场人员会看模型圈出的区域,确认是真实缺陷还是误报。误报数据如果被人工纠正,应该定期回收,回填到训练集里做增量训练。我特别强调这个闭环流程,因为它能让系统越用越准,而不是越跑越“僵”。
产线环境还有一个容易忽略的变数:光照漂移。工业现场灯管老化、车间光线变化都会让图像灰度分布缓慢偏移,导致模型检测性能下滑。解决办法是每隔一段时间用一组固定的样本图做“体检”,计算检测指标,如果掉点超过阈值就触发重新标定或增量训练。另一个是定期清理服务日志和缓存,避免长期运行导致内存泄漏。
6. 常见问题与排查技巧实录
6.1 小缺陷漏检怎么破
最常见的现象是:大缺陷一切正常,只有零点几毫米的短路点、微小缺口老是不出框。排查方向有三个。第一,检查输入分辨率,是否缩得太小导致小目标信息丢失,解决方法是提高相机分辨率或放大Patch,让缺陷在输入图像中至少占16×16像素。第二,检查Anchor是否匹配目标尺寸,用K-Means重新聚类后通常有明显改善。第三,在特征融合上做文章,换用带更高分辨率特征层的版本,让浅层细节信息参与到最终预测。我实测下来,这三个方向按顺序排查,九成漏检问题能解决。
另一个实战技巧是“多尺度推理”:推理时同时跑原始尺寸和放大后的尺寸,合并结果。但这会牺牲速度,通常只在小批量复检场景使用。产线实时检测还是优先把数据端的分辨率问题解决好,而不是靠推理阶段硬补。
6.2 背景纹理导致的误报
PCB走线密集,铜箔纹理本身就有很强的边缘和对比度,模型经常会把正常的走线边缘、焊盘轮廓误判成鼠咬或余铜。这类误报单纯调阈值压不下去,因为它在特征上确实和真实缺陷高度相似。我处理这类问题时做了两件事。第一,在训练集中主动加入大量“难负样本”,也就是没有缺陷但纹理极其复杂的背景图块,让模型在训练时明确看到一个完整图像的负样本长什么样,而不是只把有缺陷的Patch作为负样本来源。第二,检查打光配置,把同轴光角度稍微调整,减少铜箔表面反光带来的伪纹理。
这个问题的本质是“训练分布和测试分布不一致”。如果产线的光照、相机参数和采集训练数据时不一样,模型性能一定打折。所以采集训练数据时最好直接沿用产线最终的光照方案和相机参数,不要用实验室搭的一套,换一套。
6.3 类别不平衡怎么处理
当数据里短路类样本3000张、缺孔类样本只有200张时,模型会严重偏向高频类别,缺失孔类的召回率基本没法看。我先做过采样复制少数类样本,效果有限;后来改用“类别加权损失”配合马赛克增强,在训练时动态保证每个batch里各类别出现的频次相近,效果明显更好。另外一个思路是单独为少数类训练一个专用检测模型,然后把多个模型的输出做融合。这个方案精度确实高,但维护成本高,通常只在缺孔这类关键缺陷的召回率死活提不上去时使用。
数据生成也是一个可行的补充手段。比如对已有的缺孔样本做小范围位置偏移、旋转、缩放,加上背景融合,可以生成大量“新”样本。但是要非常小心生成样本的边界,如果生成的缺陷形态和真实缺陷差异过大,反而会把模型带偏。我一般只做像素级的轻微扰动,不做结构上的创造。
6.4 标注问题导致的训练异常
如果训练时发现loss降不下去、或者验证集上某些类别的精度突然波动很大,先别急着调参,回头查标注。我遇到过好几次“模型越训越差”的情况,最后都是标注数据里有框类别标错、或者框明显偏大偏小的问题。排查方法很简单:把训练图像和对应的标注框画出来,肉眼扫一遍,重点看每一类的框是否贴合目标、有没有混入其他类别。这项工作枯燥,但效率特别高,比在炼丹参数上折腾半天靠谱得多。
另一个容易被忽视的问题:同一缺陷类别在不同批次数据里的标注风格不一致。比如第一批数据里鼠咬的框都贴着缺陷边缘,第二批数据里鼠咬的框却框住了一大片邻域。这种风格不一致会直接干扰回归分支的学习。严格来说,标注规范和复核是数据环节最关键的投资,越早重视越省钱。
关于这个项目的补充体会
如果重新做一遍这个系统,我会在立项第一天就把“数据闭环”设计好,而不是先把模型跑起来再回头补数据。产线上每一张被判NG的板卡图、每一次人工复判结果,都自动存下来并标记好是否存在缺陷,这套机制带来的数据积累速度远高于人工单独整理。模型每两周做一次增量训练,系统性能会像滚雪球一样越滚越好。这一点建议所有准备做类似系统的同行重视起来。
另外,人员配置上,这个项目只靠算法工程师是跑不动的,至少需要一个懂产线工艺的现场工程师配合。因为很多图像上“看起来像缺陷”的东西,实际是工艺过程造成的正常现象,只有懂工艺的人能准确判断到底该不该判NG。算法工程师和工艺工程师拧成一股绳,项目才能顺利验收。