做工业自动化项目这些年,我发现自己越来越离不开飞桨(PaddlePaddle)这套工具链。最近刚完成一个产线缺陷检测的项目,从数据标注到模型部署跑通一共用了三周,中间踩了不少坑,也整理出很多可以“抄作业”的经验。这篇文章就把整个过程拆开讲:需求怎么分析、模型怎么选、参数怎么调、线上怎么部署,以及那些文档里不会写的坑。
如果你正在做类似的工业视觉项目,或者刚接触飞桨想找实战方向,这篇内容应该能帮你少走很多弯路。文章里涉及的技术细节都以我的实际项目为准,不绕弯子,直接讲能落地的方案。
1. 项目需求与整体思路拆解
1.1 现场工况与需求还原
先说项目背景。某家电子元器件代工厂需要检测一批冲压件上的表面划痕和边缘毛刺,产线节拍是每分钟60件,也就是每件产品的检测时间不能超过1秒。人工质检的漏检率大概在3%到5%,而且长时间盯屏幕容易疲劳,经常出现批量不良品流出后才知道问题。
客户提的核心需求有三条:一是漏检率必须降到1%以下;二是不能影响现有产线节拍;三是设备成本要控制在可接受范围内。说白了就是要一个能24小时稳定运行的视觉检测系统,不是那种实验室里跑Demo的东西。
接到项目后,我第一件事不是急着找模型,而是去产线蹲了半天。发现工件表面有油污、反光不均匀,输送带还有轻微抖动,这些都会直接影响成像质量。如果连图都拍不清楚,后面模型再强也没有用。所以整个方案的第一块拼图其实是光学方案设计,包括相机、镜头、光源的选型和安装角度。
1.2 为什么选飞桨而不是其他框架
一开始团队里也有不同意见,有人提议用其他开源框架,理由是人多资料多。但我最终坚持用飞桨,核心原因有四条。
第一,飞桨拥有完整的工业落地组件。PaddleX可以做全流程开发,PaddleDetection里有预训练模型,PaddleInference做推理部署,还有模型压缩工具。对于一个人要干好几个角色的小团队来说,这套东西省了太多事。
第二,国产框架的企业支持力度确实好。遇到问题提交Issue,响应速度快,还有官方技术群可以直接问。这在项目排期紧张的时候非常重要。
第三,中文文档和社区案例贴合国内工业场景。很多案例本身就是制造业场景,比如钢板表面缺陷、布匹瑕疵、焊缝检测,直接参考就能少踩很多坑。
第四,飞桨对硬件兼容性做得不错。现场部署用的是普通工控机加显卡,不需要专用的加速卡,跑PP-YOLO这种模型完全够用。如果以后要换国产加速硬件,飞桨也原生支持,不用重新开发一套。
总结下来,选型不是看谁名气大,而是看谁能让整个项目少踩坑、快速上线、长期好维护。飞桨在这几点上确实对路。
2. 数据准备与标注细节
2.1 数据采集方案设计
工业视觉项目里,数据质量比数据量更重要。我见过很多团队拿到公网数据集训练完,一到现场准确率就崩,就是因为现场的光照、角度、背景和公开数据集差异太大。
我们这次的数据采集方式是:在产线旁搭了一个临时工位,用和正式检测相同型号的相机和光源,连续拍摄了三个班次的工件照片。总共采集了8000多张原始图,其中包含正常品6000张、有划痕的1500张、有毛刺的800张、其他异常400张。因为划痕和毛刺本身有高发区域,比如冲压边缘和表面中心区,所以初期采集时可以主动挑选有缺陷的工件,不用完全随机抓取。
采集时有一个特别重要的点:工业相机拍出来的是8位灰度图或彩色图,但很多模型预训练时用的是常规的RGB图。如果你直接用单通道图像喂给模型,会浪费预训练权重。我建议是保留三通道,即使内容一样,让模型至少能够利用统一的结构。
采集现场还要记录好对应的工艺参数,比如模具使用次数、原材料批次。这样后期如果发现模型在某个批次数据上表现异常,还能回头追踪是原料问题还是模型问题。
2.2 标注要点与踩坑记录
标注环节是用目标检测还是分割,要根据缺陷形态决定。我们的划痕是细长条,毛刺在边缘,形态差异大,用检测框就能满足客户需求,没必要做像素级分割,标注成本也能降下一大截。
但标注框的大小对训练结果影响很大。划痕本身很细,如果标注框贴着目标紧到毫米级,模型很难学到上下文特征;如果框比目标大太多,又会引入大量背景噪声。我做了个小实验:同一批数据分别用“紧框”和“宽松10%”进行标注,训练出来的模型,宽松框的召回率高了2个百分点左右。原因也很简单,工业缺陷检测中,缺陷周围的纹理变化本身就是重要的判断依据。
还有一个容易翻车的点:标注类别不平衡。如果正常品标注了6000张,缺陷品只有几十张,训练时模型会只顾着学“什么不是缺陷”,导致漏检。我们的做法是先把缺陷样本过采样,并且在线增强时让缺陷样本的增强强度更大,比如旋转角度更大、亮度变化更剧烈。
说到标注工具,我们用的是一款免费开源标注工具,支持矩形框、多边形和标签导出。导出格式直接转成飞桨推荐的数据集格式。当时最耗时间的不是画框,而是审核。我让一个资深质检员去抽查标注结果,专门标注那些连人都要思考一下的“灰色地带”样本。这一步很值得做,因为模型学的是标注的样子,而不是缺陷真实的样子。
2.3 数据增强策略与样本平衡
工业产线上的样本分布往往很不均衡,良品占了绝大多数。如果直接拿原始比例去训练,模型的误检会少,但漏检会很高。我们采用的策略是:训练集中缺陷样本不低于40%,正常样本占比约60%,让模型既学得到“正常”的分布,又能充分看到各类缺陷。
增强策略上,我按实际现场可能出现的扰动来选择操作,不能为了增强而增强。现场输送带振动会导致工件位移和轻微旋转,所以加了小角度的随机旋转;光源老化会导致亮度波动,所以加了亮度变化;还有相机噪声,所以加了高斯噪声。但像随机裁剪、随机遮挡这类增强,对于细长划痕的检测反而可能有害,我们就没开。
具体增强参数是:旋转范围±5°,亮度范围0.8到1.2,高斯噪声标准差0到0.01。这些参数看起来简单,但如果旋转角度超过10°,小目标缺陷很容易被变形到失去原样;如果噪声太大,模型会把噪声学成特征。所以做增强要针对场景去调,别直接套用公开代码里的默认值。
数据标注完成后,我们按8:1:1划分训练集、验证集和测试集。划分时按工件ID做分组,避免同一个工件被切成多张图后同时落在训练集和测试集里,否则会存在数据泄漏,评估结果虚高。
3. 模型选型与训练调参
3.1 检测模型选型:PP-YOLO还是PP-PicoDet
飞桨目标检测模型家族里,工业场景最常用的两个是PP-YOLO系列和PP-PicoDet系列。两者的定位完全不同。
PP-YOLO系列适合中大目标、对精度要求高的场景。如果工件面积在画面里占比大、缺陷尺寸也相对明显,用PP-YOLO Plus或PP-YOLOv2效果很稳。PP-PicoDet则主打轻量级,模型体积小、推理快,适合部署在低算力设备上,但对小目标缺陷的精度会略逊一筹。
我们这次综合考虑,选了PP-PicoDet S版本,原因是部署的工控机没有很强的显卡,而且检测目标相对完整,不是那种极小的针尖缺陷。先用PicoDet做基准,如果精度不够可以再切到PP-YOLO系列。实际训练下来的mAP在0.89左右,缺陷类别的召回率在0.92左右,客户要求是召回率高于0.95,所以我们后来又做了一轮优化。
这里有个经验:不要一上来就用最大的模型。工业项目有交付周期,模型太大训练慢、部署负担重。通常会先跑一个轻量模型作为baseline,看看网络结构和数据是否有明显短板,再决定要不要换大模型。我们后续通过加入一批难例样本,把召回率提到了0.96,最终没有换更大的模型。
3.2 训练参数配置经验
飞桨目标检测模型的训练参数主要通过YAML文件管理,这里面每个参数都不是摆设。
学习率我是用基础学习率0.001加线性预热策略。工业缺陷数据量不大,如果一开始就用比较大的学习率,很容易在预训练权重的基础上把特征带偏。预热让模型在前几百步保持较小的更新步伐,再逐步加大,效果会稳定很多。
Batch size方面,因为显存有限,我们设为16。如果你显存充足,可以适当加大到32或64,训练过程的噪声会变小,收敛更稳定。但注意Batch size和初始学习率需要联动,Batch size增大的同时学习率也应该适当增大,不然收敛速度会明显变慢。
训练轮数我们设了200个epoch左右。因为数据量不算特别庞大,模型大概在150个epoch后损失趋于平稳。为了选择最优权重,我用验证集mAP作为评价指标,保存验证集上表现最好的权重作为最终模型。而不是看训练集损失,训练集损失低可能是因为过拟合。
还有一个关键参数是每张图允许的目标数量上限。早期我沿用默认值,没有手动调整,发现有些图里缺陷密集的区域会产生漏检。后来把每张图的最大目标数从100调整到500,但要注意显存占用会提升。这个要根据实际情况尝试,不能想当然地改。
3.3 模型压缩与量化:把模型塞进工控机
模型训练完,体积大约在80MB左右,直接部署到工控机上虽然能跑,但检测耗时接近700毫秒,节拍要求是1秒以内,看似满足,实际还剩很多余量给其他系统调度。为了提高稳定性和留出余量,我们做了模型量化压缩。
飞桨提供模型压缩工具,我们用了离线量化方式,将权重从FP32转成INT8。量化后的模型体积压缩到26MB左右,推理速度提升到300毫秒左右,精度损失控制在0.8%以内。这个损失在可接受范围内,因为我们在训练时适当增强了模型的鲁棒性。
量化的细节要注意:不是所有层都适合量化的。飞桨工具里可以指定量化层。我们发现早期卷积层的量化敏感度较高,于是把这些层保留为FP32,只量化后面的卷积层。这样精度损失直接降到0.4%以内。如果你发现量化后漏检明显增加,可以考虑这一招。
另外在做离线量化时,需要准备一组有代表性的校准数据集,尽量覆盖所有类别的缺陷分布。我们大概是每个类别选了300张图,约1000张图来标定。校准数据的质量直接决定量化效果,偷懒不得。
4. 推理部署与系统集成
4.1 部署方案:Paddle Inference加TensorRT加速
模型跑起来容易,跑得快又稳需要认真做工程化。我们的部署平台是Windows 10工控机,显卡是入门级专业卡。软件栈选的是Paddle Inference加PaddleTensorRT。
Paddle Inference是飞桨官方的推理引擎,可以直接加载训练好的模型,不需要再把模型转成其他格式。配合TensorRT优化后,推理能进一步加速。我实际测下来,TensorRT加速后耗时大约200毫秒,相比纯Paddle Inference又减少了一百多毫秒,余量更大。
部署时要注意PaddlePaddle与TensorRT的版本兼容。这里有个容易踩的坑:如果你是在物理机上用pip安装的飞桨,需要确认是否为GPU版本,CPU版本是无法调用TensorRT的。另外TensorRT版本要和PaddlePaddle官方文档中声明的对应版本匹配,否则加载时可能直接报错。
C++部署接口的性能确实比Python接口好很多。虽然Python开发效率高,但工业现场对延迟敏感,而且C++程序没有解释器启动开销,也不用担心Python环境被搞乱。我们在现场最终用的是C++推理服务,通过一个轻量级的本地HTTP接口供上位机调用。
4.2 工业相机触发与PLC联动逻辑
工业视觉系统不是一个孤立的模型,它要跟产线信号联起来。我们采用相机硬触发模式:当工件到达检测位置时,PLC输出一个脉冲信号给相机,相机立即抓拍图像,然后通过GigE接口传到工控机。这样能保证每次抓拍时机准确,避免在工件运动模糊时拍照。
图像传入后,推理服务开始跑模型,输出结果是OK还是NG。如果NG,需要在极短时间内通知PLC踢出不良品。我们定的整个链路延迟是:从相机触发到PLC收到结果不超过800毫秒,实测稳定在650毫秒左右。
PLC通讯采用最简单的TCP协议,因为上位机和PLC都在同一局域网,环境干净,不需要复杂协议栈。发一个结构化数据包,包含工件ID、检测结果、置信度和缺陷类别,PLC解析后再决定是否触发剔除机构。这个方案实现简单,现场维护也方便。
这里有一个经验:检测结果不要只输出“好”或“坏”,最好把缺陷类型、位置坐标、置信度都存下来。这样后续可以追溯工艺问题,比如发现某个模具位置对应的缺陷特别多,就要提醒产线去检修模具。客户很看重这种追溯能力,这也是项目验收的加分项。
4.3 结果可视化与数据记录
虽然客户主要要的是自动判定,但人机界面不能省。我们给现场做了简单的结果显示界面,屏幕左侧是相机实时画面,右侧是模型检测结果的叠加框,显示缺陷类别和置信度。这样现场人员能实时看到系统在“看什么”,更容易信任系统,也方便发现异常。
数据记录方面,我把每一天的检测结果按照日期、班次、工件批次号写入数据库。并定期统计缺陷率趋势,一旦某类缺陷比例上升,就能提前预警。这些功能听起来不难,但在项目交付时往往很加分。
日志系统也要设计好。工业软件最怕跑着跑着突然崩了而不知道发生了什么。我们的程序会在检测到异常时输出完整的日志,包括图像文件路径、模型推理耗时、关键中间变量。排查问题时可以按时间和工件ID快速定位到具体样本。
5. 常见问题与排查实录
5.1 漏检和误检的调优套路
印象最深的一次漏检发生在现场:表面很浅的压痕,肉眼要仔细看才能发现,模型经常直接漏掉。后期排查发现,这种浅压痕在图像里的灰度变化非常微弱,和正常区域差异太小。增补了这类样本并提高类别权重后,漏检改善明显。
如果你的模型也有同类问题,可以这样处理:先把漏检图片整理出来,单独建一个难例集,用训练好的模型继续在难例集上微调。一般跑几百步就能见效。注意微调时学习率要调小,否则容易把之前学习到的特征破坏掉。
误检的套路则不一样。最常见的是现场环境光和训练集差异太大,比如阴影落在工件上被模型当成缺陷。解决方法是尽量让训练样本覆盖更多的光照变化,或者在图像预处理时做归一化,削弱光照影响。有一次我们排查一个持续误检的案例,最后发现是相机镜头上粘了一粒灰尘,图像上形成一个固定的暗斑,被模型识别为划痕。所以现场定期清洁镜头也很关键。
5.2 推理延迟突然升高
上线第一天,系统运行很稳定,三百毫秒左右出结果。第二天开始,推理耗时飙升到800毫秒以上,客户那边差点要求暂停。排查过程很有意思。
先看CPU和GPU占用,GPU利用率不高,但CPU占用很高。想到模型推理过程中部分算子可能跑在CPU上。查了飞桨的日志,发现一个线程池配置和系统核数不匹配,导致算子调度出现大量等待。把线程池相关环境变量重新配置后,耗时恢复正常。
另一个原因是显存碎片化。连续运行一整天,显存被反复申请和释放,TensorRT的优化效果会下降。解决办法是定期清理显存缓存或者干脆每天定时重启一次服务。听起来很土,但在现场非常有效。
5.3 工业相机与模型接口之间的坑
相机输出的图像格式是Bayer原始格式,需要经过色彩插值转换成RGB。有的工业相机SDK默认输出的是10位色深,直接转成8位会丢失信息。我们踩过这个坑,后来在采集时设置了合理的位深和格式转换参数,保证图像和训练时的数据分布一致。
还有图像尺寸问题。相机采集到的分辨率是2448乘2048,但模型训练时输入尺寸是640乘640。直接缩放到640会丢失小目标细节。我们的做法是先对原始图像做区域采样,只检测固定工件的核心区域,而不是整幅图直接缩略。这样既控制了计算量,又保住了细节。
如果必须全图检测,可以考虑切片推理,再合并结果。但要处理好切片边界处的目标截断问题,一般是增加重叠区域,重叠率设置在10%到20%之间比较合理。
最后分享几个实际操作中的心得
整个项目从需求确认到最终上线验收,大概用了六周时间。中间真正写代码的时间并不多,大部分精力都花在数据采集、标注审核和现场调优上。我个人最深的体会是:工业自动化项目不是比谁的模型结构更新颖,而是比谁能在真实环境里稳定输出。
飞桨这套工具链的好处在于,它把数据管理、模型训练、压缩和部署串成了完整链路。你不需要四处找轮子,也不需要在转换模型格式时反复踩坑。下次如果再遇到类似场景,我会更早地做光照基准测试,并且在方案设计阶段就预留更多的推理延迟余量。
最后分享一个小技巧:训练前一定要先做一次“空跑”测试,用全零数据过一遍整个流程,确认模型能正常输出、部署接口能连通。很多看起来诡异的问题,其实都出在流程早期的简单配置错误上。工业项目最怕的不是难题,而是被简单的坑拖住时间。希望这篇文章能帮你少走点弯路。