流水线上的AOI设备每天要过几百片PCB,暗场相机拍出来的图动不动就是几千万像素,操作员盯屏十分钟眼睛就花了,漏检全凭运气。这个项目就是干这个事的:用YOLO系列算法把PCB板的缺陷检测从"人眼盯"变成"模型扫"。我做的是某工厂产线上的一个视觉检测Demo,模型跑在工控机的GPU上,实时框出短路、开路、缺孔、划痕这些缺陷,顺带把坐标和类别通过串口发给下位机做标记。整套东西从数据采集到部署上线大概花了一个半月,本文把方案选型、数据标注、训练调优、部署踩坑全拆开讲,适合正在做工业视觉、目标检测落地,或者在实验室里被导师要求"搞一个检测系统"的同学参考。
1. 项目设计与方案选型:为什么是非YOLO不可
1.1 核心需求拆解:先搞清楚产线要什么
做工业项目第一件事不是急着下代码,而是把需求问明白。这个项目的核心需求其实就三条:第一,缺陷类型覆盖要全,短路(short circuit)、开路(open circuit)、缺孔(missing hole)、鼠咬(mouse bite)、毛刺(spur)、多余铜(spurious copper)这六类必须能识别,这是行业里最常规的分类方式;第二,检测速度要跟上产线节拍,相机拍完到结果返回不能超过几百毫秒,不然流水线就得停下来等;第三,漏检率要压到极低,误报可以稍微多一点让人工复检去兜底,但漏检意味着不良品流出,这是工厂最不能接受的。
这三条需求直接决定了算法选型方向。传统机器视觉用规则匹配、模板匹配做缺陷检测,对固定形态的缺陷有效,但PCB缺陷的形态变化太大了——同一个开路缺陷,角度不同、线条粗细不同、光照反射不同,模板匹配就崩了。深度学习目标检测天然适合这种"形态多变但有共同特征"的场景。而在目标检测算法里,YOLO系列又是最契合产线需求的:单阶段检测速度快,工业现场对实时性要求极高;端到端设计部署简单,不需要像两阶段算法那样拆出候选区域生成和分类两个网络;生态成熟,从训练到导出再到推理加速,工具链齐全。
我在这套项目里用的主力模型是YOLOv8n和YOLOv8s,后面为了对比效果还试过YOLOv5s和YOLOv6s。选v8的原因是它在C2f结构、解耦检测头、Anchor-Free设计上做了综合优化,属于"不用怎么调就能出活"的模型。工业项目最怕的不是效果不够好,而是方案太复杂导致交付不了,v8恰好平衡了效果和易用性。
1.2 算法版本选型:不同版本在PCB场景下的实际表现
很多人纠结选YOLOv5还是v8,我直接给结论:从零开始的新项目直接上v8,老项目维护不折腾就继续用v5。原因有三点:v8的Anchor-Free设计省掉了聚类Anchor的步骤,PCB缺陷长宽比差异巨大(划痕很细长,焊盘短路又是块状),聚类Anchor反而引入偏差;v8的解耦头把分类和回归分支分开,对"缺陷小、背景杂"的PCB图像更友好;v8的C2f结构梯度流更丰富,小目标特征提取能力比v5的C3强。
我在同样数据集上做过量化对比,用YOLOv8n跑640输入分辨率,mAP50能到0.93,单张推理在RTX系列显卡上大概5毫秒。YOLOv5s魔改版本能到0.91,但训练收敛速度慢一些。YOLOv6s和v8差别不大,但配套工具链没有Ultralytics生态方便。如果你是做边缘设备部署,可以考虑YOLOv8n配合TensorRT;如果对精度有苛刻要求且显卡算力充足,YOLOv8m或v8l也是可选方向,但PCB缺陷检测这种任务,n和s级别已经足够。
注意:PCB缺陷检测的难点不在模型大小,而在数据质量和推理策略。盲目上大模型只会拖慢产线节拍,收益有限。
2. 数据集构建:别让标注拖垮整个项目
2.1 数据来源与标注规范:真实缺陷图才是核心资产
这个项目的数据来源分三块:工厂AOI设备在产线上攒的实拍缺陷图(大概占70%)、实验室手工制作缺陷样板拍的图(占20%)、公开数据集补充(占10%)。这里有个关键经验:公开数据集(比如PCB_DATASET)只能用来做预训练或者冷启动,真实项目一定要以自己采集的数据为主,因为每个工厂的PCB材质、走线宽度、铜厚、阻焊层颜色都不一样,模型必须见过"自家的板子"才能在产线上稳定工作。
实拍图的标注是最大的工程量。我们用了LabelImg和X-AnyLabeling配合,前一批图用YOLOv8预训练模型做自动预标注,人工只做修正。一张图上有十几个缺陷的情况下,预标注能省掉一半时间。但是预标注有个坑:模型漏检的缺陷不会自动标出来,所以人工修正时不能只"删错框",还要"补漏框"。我让标注员在预标注基础上通读全图检查,重点看那些细小走线区域,因为漏检大多发生在这里。
标注规范方面,我定了几条硬规矩:缺陷框必须紧贴缺陷实际区域,不要为了省事拉个大框把周围正常区域也包进去;对于连在一起的多个缺陷,如果间隔超过几个像素就分开标,避免模型学出"一个框装两个缺陷"的错误模式;背景中的正常元件、孔位、丝印一律不标,避免引入噪声。标注格式统一用YOLO的txt格式,类别ID从0到5对应前面说的六类缺陷。
2.2 数据增强策略:让小目标缺陷在训练时"多露脸"
PCB缺陷检测的特点是小目标居多,很多缺陷在640分辨率的图上只有十几个像素甚至几个像素。模型训练时,小目标本身的损失贡献小,容易被大目标"淹没"。我用了几组有效的增强策略来缓解这个问题。
第一组是几何增强:随机旋转(正负30度以内)、水平翻转、垂直翻转。PCB板有方向性,但缺陷本身是任意朝向的,所以旋转角度可以放开一点。第二组是颜色增强:亮度扰动、对比度扰动、HSV色域扰动。不同光照下AOI相机拍出来的图明暗差异很大,颜色增强能让模型对光照变化更鲁棒。第三组是Mosaic和Copy-Paste混合使用。Mosaic把四张图拼成一张,变相增大batch内的小目标数量;Copy-Paste则把一张图中的缺陷区域随机贴到另一张图上,特别适合补充稀缺类别的样本。
我给这些增强设置的概率是:Mosaic 0.8(v8训练到后期会自动降为0,这个机制很好)、旋转15度概率0.3、翻转各0.5、HSV扰动0.4。实测下来,精确率提升了2到3个百分点。数据增强不是越多越好,过度增强会让模型学到"假特征",尤其是对于PCB这种纹理规则、背景接近的图像,增强幅度太猛反而有害。
2.3 类别不均衡:缺孔和鼠咬样本少怎么处理
六类缺陷的样本数量天然不均衡。短路和开路是最常见的,因为焊接和蚀刻工艺的波动主要产生这两类问题;缺孔和毛刺就比较少见,一个批次的板子里都碰不到几个。模型训练时,样本多的类别会把损失曲线压低,模型为了降低整体loss倾向于把不明确的区域预测成高频类别,这样稀缺类别就很容易漏检。
我处理类别不均衡的经验分三层。第一层:训练时给样本少的类别加大loss权重,v8里可以在数据集的yaml配置里给每个类别设置权重,缺孔和鼠咬的权重比短路高30%到50%。第二层:对稀缺类别做过采样,训练时每个epoch多回放几次这类样本,配合Copy-Paste增强补充数量。第三层:如果某个类别实在数量太少(比如少于50个实例),单纯靠过采样解决不了根本问题,那就得回产线补拍或者在样板板上人为制造缺陷来采集。另外建议给稀缺类别降低置信度阈值,推理时让模型"更愿意"框出来,反正后续还有人工复检环节。
3. 模型训练与调优实践:从基线到能用的距离
3.1 训练配置与超参数选择:照着抄也能跑
训练配置这块直接给一个可以复用的参数组合。我用的是YOLOv8n,输入分辨率640×640(后面会讲为什么不用更高),batch size 16,epochs 300,优化器SGD,初始学习率0.01,momentum 0.937,weight decay 0.0005。这些参数和Ultralytics默认值基本一致,v8的默认配置其实已经调得不错,不建议新手上来就大改。
训练数据集划分上,我按8:1:1切成训练集、验证集、测试集。这个比例对大概2000张图的数据集来说是够用的。但有个容易忽略的细节:划分前一定要检查同一块PCB的不同拍摄角度图是否被分到了不同集合里。如果训练集里有某块板子的左侧视图,验证集里恰好有同一块板子的右侧视图,数据就泄漏了,验证集分数虚高,上线后模型表现断崖式下跌。我用的是"按板子分组"的划分方式,同一块板子的所有图必须落在同一个集合,这是工业视觉项目的铁律。
训练过程要盯着几个指标:train/loss持续下降说明模型在学;val/loss先降后升说明过拟合;mAP50在最后50个epoch趋于平稳说明收敛。我用Early Stopping设了30个epoch的耐心值,v8自带这个参数,数据集不够大的时候挺实用。另外建议每个epoch结束后都跑一次测试集评估,别只在训练完跑一次,这样能早发现哪个类别在退化。
3.2 小目标检测性能优化:输入分辨率、切片推理与注意力机制
PCB缺陷一大半是小目标,这是整个项目里最难啃的骨头。第一次基线训练完,mAP50看着还行(0.93),但把漏检按目标尺寸统计后发现,小于32×32像素的缺陷漏检率高达15%,人眼都能看到的断线模型就是框不出来。这个问题的根子是:小目标在骨干网络下采样32倍后,特征图上只剩1×1甚至消失,检测头根本无从来"看"。
我做了三重优化。第一重最简单:把输入分辨率从640提到1280。分辨率提上去后,小目标在特征图上的像素数翻倍,漏检率立刻降到7%。代价是推理时间翻倍,所以这个方案要看产线算力是否够。第二重是切片推理(SAHI思路):把原图先切成若干重叠的patch,每个patch独立做检测,再把结果合并、NMS去重。切到512×512大小、重叠率20%时,小目标检测效果进一步提升,而且因为patch变小,模型看到的"背景干扰"也少了。第三重是给模型加注意力模块,我在YOLOv8n的Backbone末端接了一个轻量级SE模块,通道注意力能让模型更关注缺陷区域的通道特征,这个改动在不开大输入分辨率的情况下也有提升,而且推理时开销很小。
注意:小目标优化的核心思路永远是"让缺陷区域在特征图上占据更多像素"。提升输入分辨率、做切片推理、加注意力机制,本质上都是在做这一件事。
3.3 模型评估:不能用单一的mAP糊弄自己
工业项目评估模型,最忌只看mAP。mAP是综合了所有类别和所有阈值的平均指标,看起来体面,但掩盖了具体类别和具体场景的表现差异。我这边搭了一套评估面板:按类别分别统计mAP50、精确率、召回率、漏检率;按目标尺寸分段统计(小目标<32px、中目标32-96px、大目标>96px);再单独跑一版"极端光照图"和"不同批次板子"的测试集,看泛化能力。
实际拉出来的数据很有参考价值。短路和开路这两个类别mAP50都在0.95以上,缺孔只有0.82,鼠咬才0.76。按尺寸分段更扎心:小目标召回率只有0.71,中目标0.92,大目标0.97。这说明模型对"又小又少"的缺陷类别确实偏弱。这些数字直接指导了后续优化优先级:先补鼠咬样本、再提输入分辨率、最后才考虑改模型结构。
模型导出和部署评估也不能省。PyTorch模型导出为ONNX再转TensorRT后,FP16推理精度相比原始模型mAP掉不超过0.5个百分点,但推理速度从5毫秒提升到2毫秒。INT8量化能进一步压到1毫秒以内,但mAP会掉1.5个点左右,我用在有缺陷类型不需要特别精细分类的产线分支,FP16放在要求高的分支。
4. 推理部署与产线集成:模型效果好不是真的好
4.1 模型导出与推理加速:TensorRT和ONNX的取舍
训练完的PyTorch模型是不能直接上产线的,工控机上装PyTorch推理既笨重又慢。我的标准流程是:先导出ONNX通用格式(用固定batch和固定输入尺寸),再针对GPU用TensorRT做二次优化。这里有个经验:导出ONNX时一定把opset版本设高一点(我用17),操作符支持更全,后面TensorRT解析不容易报错。
TensorRT的部署有几个容易踩的细节。第一,工作空间大小直接影响优化效果,我设了4GB,编译出来的引擎推理速度比默认配置快15%。第二,FP16开启后要跑一遍校准,校准集选500张覆盖全部类别和不同光照的图,避免精度掉太多。第三,TensorRT引擎是跟具体GPU型号绑定的,换了显卡必须重新编译,别幻想拷一个引擎文件到处跑。
推理加速选型上,如果你用的是利旧的老工控机(没有独立显卡),那就只能走ONNX Runtime加速,CPU推理640分辨率大概每张50到80毫秒,对于产线节拍不紧的检测位也能接受。如果上了带Tensor Core的GPU,FP16推理带来的收益立竿见影,2毫秒级别完全够用。
4.2 推理管线设计:相机采集、模型推理、结果回传不能打架
工业视觉不只是"图进去、框出来"这么简单,整个推理管线要处理好几个环节的时序问题。相机采集用工业相机SDK拉流,一般是通过回调函数把帧推到队列里;模型推理线程从队列取帧,做完检测把结果打包;结果通过串口或TCP发给PLC或者下位机做不良品标记。这三个环节如果共用一个线程,中间任何一步卡住都会导致流水线停摆。
我用的是双缓冲加生产者-消费者模型:采集线程只负责往环形队列里塞原始图像,推理线程循环从队列取图,队列满就丢弃最旧的帧(产线场景优先保证实时性,不能阻塞采集)。推理结果回传单独开一个发送线程,避免串口写超时拖累推理主循环。这个架构跑下来非常稳,连续运行几天没有出现阻塞叠加的情况。
另外要处理"误检导致的次品误标"问题。模型偶尔会把正常的板子框出缺陷,如果直接触发下位机打标,好板子就被当次品扔了,产线会有意见。所以我在结果输出里加了一个"置信度阈值+最低连续帧数"逻辑:同一个位置的缺陷要连续两帧都被检出且置信度超过阈值,才判定为真阳性。这个逻辑牺牲了一点实时性,但换来了误报的大幅下降,实际产线上这个取舍非常划算。
4.3 硬件选型与性能压测:别低估工控机的散热
硬件选型方面我踩过一次坑。最开始在实验室用台式机的RTX高端显卡跑得好好的,迁移到产线工控机后推理慢了一倍。一查原因:工控机是封闭式机箱,散热跟不上,GPU温度一上去就自动降频,推理性能直线跌落。后来换成了带独立风道和散热器的工控机,才恢复正常。所以做工业部署时,测试必须在目标硬件上跑,散热、功耗、CPU竞争、内存带宽全都要考虑进去。
性能压测要模拟产线真实负载。我写了脚本模拟相机以30帧每秒的速度持续输入2小时,统计推理平均延迟、最大延迟、GPU利用率和丢帧率。压测结果在配置合理的工控机上,FP16推理平均延迟2.3毫秒,最大延迟5.8毫秒,没有丢帧。这套压测数据在项目验收时特别有说服力,也是后续定位性能问题的基线。
5. 常见问题与排查技巧实录
5.1 模型漏检率降不下去怎么办
漏检是PCB缺陷检测项目里最头疼的问题。我总结了一套排查顺序,按从低到高的成本排。
先从数据层排查:漏检的缺陷大多集中在哪个类别?哪个尺寸段?哪个位置区域?把漏检样本按类别画个分布直方图。如果全是某一类漏,说明样本数量或者标注质量有问题,回去补标注、补样本。如果全是小目标漏,按前面说的提分辨率或加切片推理。如果集中在板子边缘区域,很可能是数据标注时边缘缺陷框被切掉了,或者输入Resize时边缘信息被裁减,得改预处理逻辑。
再从模型层排查:换个更大的模型试试(比如从n换成s),如果大模型漏检率明显下降,说明小模型容量不够,要么加算力上大模型,要么优化特征提取。另外检查NMS参数,IoU阈值设太紧会压制相邻缺陷的框,设太松会把多个缺陷框合并成一个。我这边用的是默认0.7,若发现"两个靠近的缺陷只出一个框"就把阈值调到0.5。
最后从流程层排查:检查推理预处理是否和训练一致。犯过很低级的错误——训练时图是BGR顺序,部署时读图用了RGB顺序,颜色通道对调后特征全乱了,漏检率直接翻倍。这种问题通常一张图就能看出来,调试时务必先画出来看。
5.2 误检多:模型把正常焊盘和走线框出来了
误检多通常有两个来源:一是正常区域的特征和缺陷区域太像,二是模型对"背景"没有建立足够好的区分。排查时先看误检框集中的位置。如果集中在焊盘边缘,可能是焊盘的弧度、亮度变化和某些缺陷形态类似,需要补充"难负样本"——把产线上误检的图收集起来,只标出"没有缺陷"(即所有框都是红框),重新训一轮让模型学会区分这类型。
我的做法是建立了一个"误检回流"机制:每两天把产线上所有误检图从日志里捞出来,人工确认后加入训练集,作为背景或者难负样本。这个过程看起来慢,实际效果却非常显著,迭代两三轮后误检率能下降一半以上。关键是形成闭环,只靠一次性标注很难覆盖全部误检形态。
置信度阈值也是控制误检的利器。默认0.25对工业场景太低,我调到了0.45,误检立刻少了三成。代价是个别低置信度的真缺陷会给漏掉,但如果后面有复检环节,这个代价完全可以接受。阈值调整要跟现场工艺人员反复确认,找到漏检率和误检率的经济平衡点。
5.3 产线光照变化导致检测不稳定
PCB AOI设备的光照条件并非恒定的,灯管老化、零件更换、不同批次板子的反光率差异,都会导致模型输入分布漂移。最常见的情况是:模型在白天跑得好好的,到了晚上同一块板子连续报误检。原因就是光照亮度变化把正常区域的纹理"照出了"缺陷特征。
解决思路分两步走。第一步是图像预处理规范化:对输入图像做自动白平衡和亮度归一化,让模型输入尽量稳定。我在采集端做了亮度直方图匹配,以产线标准光照下的图为参考,把每帧图亮度分布对齐过去。第二步是训练时引入光照变化的增强:除了HSV扰动,再按产线实测的照度范围合成一批"模拟不同光照"的训练样本。这两步配合下来,模型对光照变化的鲁棒性明显增强。
另外提醒:定期用标准样板校正一下相机参数和光源,这属于设备和算法联合维护的范畴。模型依赖的数据分布稳定,算法层面的锦上添花才有意义。
一些数据之外的经验
做这个项目最深的体会是:工业视觉项目里,算法只占一半,另一半是数据工程和系统集成。数据标注规范、评估指标体系、推理管线的健壮性,这些看着不"性感"的工作,才是决定项目能不能真正上线跑起来的基石。我也曾在实验室里被mAP 0.95哄得开心,到了产线被漏检率0.3%的现实狠狠教育过。如果你也要做类似的检测项目,建议从第一天就把"这个模型最后要在什么环境、什么硬件、用什么方式跑"纳入思考范围,而不是等模型训完了再去想部署的事。最后分享一个小技巧:保留好每一次训练的配置文件和当时的评估结果,做成一张对比表。这个习惯在项目汇报、方案调整、复盘排查时,能帮你省下大量"我记得我上次是这么调的"的无效时间。