拓十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Halcon深度学习分类模型实战:从数据准备到产线部署全流程

Halcon深度学习分类模型实战:从数据准备到产线部署全流程

1. Halcon深度学习分类模型到底是个什么东西

1.1 从产线质检的痛点说起

我在做机器视觉项目这些年,被问得最多的一类问题就是:“这个划痕算不算不良?”“这个字符有没有印歪?”“这颗螺丝有没有装反?”——这些问题用传统的Halcon算子,比如find_shape_model、measure_pos、threshold,能做,但做得非常痛苦。因为传统算子本质上是靠边缘、灰度、几何特征去卡阈值,一旦产品换批次、光照飘一点、来料表面有油污,阈值就得重新调,调到最后工程师自己都崩溃。

Halcon的深度学习分类模型,就是来解决这类“人一眼能看出来,但写规则写到吐”的问题的。它属于Halcon Deep Learning系列里最基础、最容易上手的一类模型,官方叫Deep Learning Classification,底层是一个卷积神经网络(CNN)分类器。你给它一批已经分好类的图片,比如“OK”和“NG”两个文件夹,它自己学特征,最后输出一个类别标签加一个置信度分数。

这里要先把概念理清楚,很多人一上来就搞混:

模型类型解决什么问题典型算子输出
分类 Classification这张图属于哪一类classify_image类别 + 置信度
检测 Detection图里有没有目标、在哪detect系列框 + 类别
分割 Segmentation每个像素属于哪一类segment_image像素级掩膜
异常检测 Anomaly没见过的不良长啥样apply_dl_model异常分数

分类模型是这四类里数据标注成本最低的——你不需要画框,不需要标像素,只要把图片按文件夹分好类就行。这也是为什么我一般建议新手从分类模型入门,跑通一遍整个流程,再去碰检测和分割。

1.2 它和OpenCV、YOLO那套有什么区别

经常有人问我:“Halcon深度学习和OpenCV、YOLO有啥区别?我直接用YOLOv8分类不香吗?”

这个问题得分开看。YOLO系列(包括v8、v11、v13这些)本质是通用目标检测框架,分类只是它的一个附带能力,生态活跃、社区模型多、预训练权重丰富,训练一般跑在Python + PyTorch上。而Halcon的深度学习是深度集成在Halcon自己的算子体系里的,它的优势不在模型本身有多先进,而在于:

  • 部署链路极短:训练完的模型直接就是.hdl文件,read_dl_model读进来就能在Halcon里推理,不需要Python环境、不需要ONNX转换、不需要TensorRT折腾。
  • 和传统算子无缝混用:你可以先用threshold粗定位,再reduce_domain裁出ROI,然后送进分类模型,整个流程在一个.hdev里跑完。
  • 工业现场稳定性:Halcon的推理对CPU/GPU的兼容性做得比较扎实,产线上工控机没有独显也能跑(慢一点而已)。

反过来说,如果你追求SOTA精度、要做超大模型、要用LoRA微调、要玩多模态,那Halcon确实不是首选,该上PyTorch还是得上。工具没有优劣,只有合不合适。产线单机部署、要求快速落地、工程师是Halcon背景的,选Halcon分类模型基本不会错。

1.3 适合谁来学,需要什么前置基础

这篇内容我假设你满足以下条件:

  • 装好了Halcon(20.11之后的版本对深度学习支持比较完整,建议23.11或更新),有可用的License(深度学习模块需要单独的授权,这点后面会专门讲)。
  • 会基本的Halcon操作:读图、开窗口、显示、写个简单的for循环。
  • 对“训练集/验证集/测试集”这三个词不陌生,哪怕只是听说过。

如果你连Halcon的界面都没打开过,建议先去把read_image、dev_display、dev_open_window这几个算子跑一遍再回来。分类模型的代码量其实不大,难的是数据准备和参数调优的思路,这两块我会重点展开。


2. 训练之前必须想清楚的几件事

2.1 你的问题真的适合用分类模型吗

这是我最想先泼的一盆冷水。分类模型的隐含前提是:一张图(或一个ROI)里只有一个主体,且这个主体整体属于某一类。

举几个适合和不适合的例子,你对号入座:

  • 适合:整块PCB板判断“良品/不良品”;一个瓶盖判断“正/反”;一颗药片判断“完整/破损”。
  • 不适合:一张图里要同时找出3个缺陷并分别定位(这是检测的活);要判断缺陷的具体形状轮廓(这是分割的活);不良样本极少、根本凑不齐第二类(这是异常检测的活)。

我见过太多人拿分类模型硬做检测的活,最后精度上不去,回头骂Halcon不行。不是模型不行,是问题选错了工具。判断标准很简单:如果你标注的时候只需要给整张图打一个标签,那就是分类;如果需要画框或涂像素,那就换模型。

2.2 数据集的三个硬指标

Halcon分类模型对数据的要求,我总结成三个硬指标,缺一个都容易翻车。

第一,类别要平衡。假设你做OK/NG二分类,OK有2000张,NG只有50张,模型会学出一个“无脑判OK”的偷懒策略,准确率照样95%以上,但NG一个都抓不到。经验值是每类至少100张起步,类间数量比控制在1:3以内。NG样本实在少,就靠数据增强(旋转、亮度扰动、加噪声)硬凑,或者用gen_dl_samples配合增强参数。

第二,图像要一致。训练图和现场推理图必须来自同一套成像系统——同样的相机、镜头、光源、曝光、工作距离。我踩过最深的坑就是:实验室用环形光拍的训练集,现场换成条形光,模型直接废掉。如果现场光照会波动,训练集里就要主动把不同光照条件下的图都放进去,让模型学会忽略光照差异。

第三,标注要干净。分类的“标注”就是文件夹分类,听起来简单,但错标一张图的代价比检测里错画一个框大得多。我一般会做两轮复核:第一轮按文件夹抽查,第二轮把模型训出来之后,专门看置信度在0.5到0.7之间的那些图,这些是模型“犹豫”的样本,十有八九是标错了或者本身就是模棱两可的边界样本。

2.3 网络选型:pretrained_dl_classifier 那几档怎么选

Halcon提供了几个预训练的分类网络骨干,常见的有:

网络名称输入尺寸特点适用场景
pretrained_dl_classifier_compact.hdl224x224最轻量,速度快类别少、特征明显、算力紧张
pretrained_dl_classifier_enhanced.hdl224x224中等容量大多数工业场景的默认选择
pretrained_dl_classifier_resnet50.hdl224x224容量大,精度高类别多、类间差异细微

选型的逻辑是:先用compact跑一版baseline,如果验证集精度不够,再往上升级。不要一上来就上ResNet50,训练慢、显存吃得多,而且在小数据集上反而容易过拟合。我做过一个药片缺陷分类的项目,compact就能到98.5%,换enhanced只涨了0.3%,但训练时间翻倍,完全不划算。

另外要注意,这些预训练模型是在ImageNet上训出来的,输入尺寸固定224x224。你的原始图如果不是这个比例,Halcon会做缩放,缩放会丢细节。如果缺陷本身很小,比如一个2像素的针孔,缩到224之后可能就没了。这种情况要么把ROI裁得更紧,要么考虑用检测模型。


3. 从零到一:完整训练流程拆解

3.1 数据准备与目录结构

Halcon读数据有两种方式:一种是用read_dl_classifier_data从文件夹读,另一种是用read_dl_samples从.hdict文件读。新手我强烈建议用文件夹方式,直观、好排查。

目录结构长这样:

dataset/ ├── train/ │ ├── ok/ │ │ ├── 001.png │ │ ├── 002.png │ │ └── ... │ └── ng/ │ ├── 001.png │ └── ... └── validation/ ├── ok/ └── ng/

几个实操细节:

  • 图片格式统一,别混着png、bmp、jpg。jpg有压缩伪影,工业场景尽量用png或bmp。
  • 文件名别用中文和空格,Halcon某些版本对路径编码处理不友好,容易读图失败。
  • train和validation的划分比例,我一般用8:2。如果数据量少于500张,用7:3,验证集多一点更能反映真实泛化能力。
  • 划分要随机但可复现。别按文件名顺序切,否则可能train全是上午拍的、validation全是下午拍的,光照一变就露馅。用shuffle打乱后再切。

3.2 核心算子逐个讲透

整个训练流程的核心算子其实就十来个,我按执行顺序列出来,每个都说说它到底在干嘛。

第一步,读数据。

read_dl_classifier_data ('dataset/train', 'class_name', TrainData, TrainLabels)

这个算子会扫描目录,把每个子文件夹名当作类别名,返回图像路径元组和对应的标签元组。注意它返回的是路径不是图像本身,真正读图是在后面生成batch的时候。

第二步,创建分类器。

create_dl_classifier ('pretrained_dl_classifier_enhanced.hdl', 2, \ 'softmax', DLClassifierHandle)

第二个参数2是类别数,这个必须和你文件夹里的类别数严格一致,多一个少一个都会报错。softmax是输出层,分类任务基本都用它。

第三步,设置超参数。

set_dl_classifier_param (DLClassifierHandle, 'batch_size', 8) set_dl_classifier_param (DLClassifierHandle, 'learning_rate', 0.001) set_dl_classifier_param (DLClassifierHandle, 'momentum', 0.9) set_dl_classifier_param (DLClassifierHandle, 'weight_prior', 0.0001)

这几个参数是调优的重灾区,我后面单独开一节讲。

第四步,预处理参数。

set_dl_classifier_param (DLClassifierHandle, 'image_width', 224) set_dl_classifier_param (DLClassifierHandle, 'image_height', 224) set_dl_classifier_param (DLClassifierHandle, 'image_num_channels', 3)

如果你用的是灰度图,image_num_channels设1,但预训练模型是按3通道训的,设1会丢掉预训练权重的第一层,精度可能受影响。我的做法是灰度图也复制成3通道,保持和预训练一致。

第五步,训练。

train_dl_classifier_batch (TrainData, TrainLabels, DLClassifierHandle)

这个算子内部会自动做数据增强(旋转、翻转、亮度扰动),你不需要自己写增强代码。训练轮数通过set_dl_classifier_param的epochs控制,或者用train_dl_classifier_batch的循环次数控制。

第六步,评估。

evaluate_dl_classifier (ValidationData, DLClassifierHandle, EvaluationResult)

返回的结果里包含混淆矩阵、各类精度、总体精度。重点看混淆矩阵,它能告诉你模型到底把哪一类错判成了哪一类。

第七步,保存。

write_dl_classifier (DLClassifierHandle, 'my_classifier.hdl')

保存下来的.hdl文件就是最终产物,部署时read_dl_classifier读进来即可。

3.3 一个能直接跑的最小示例

下面这段代码是我平时做baseline用的模板,改改路径就能跑:

* 读训练数据 read_dl_classifier_data ('dataset/train', 'class_name', TrainData, TrainLabels) read_dl_classifier_data ('dataset/validation', 'class_name', ValData, ValLabels) * 创建分类器,2类 create_dl_classifier ('pretrained_dl_classifier_enhanced.hdl', 2, 'softmax', DLHandle) * 设置参数 set_dl_classifier_param (DLHandle, 'image_width', 224) set_dl_classifier_param (DLHandle, 'image_height', 224) set_dl_classifier_param (DLHandle, 'image_num_channels', 3) set_dl_classifier_param (DLHandle, 'batch_size', 8) set_dl_classifier_param (DLHandle, 'learning_rate', 0.001) set_dl_classifier_param (DLHandle, 'epochs', 30) * 训练 train_dl_classifier_batch (TrainData, TrainLabels, DLHandle) * 评估 evaluate_dl_classifier (ValData, ValLabels, DLHandle, EvalResult) * 保存 write_dl_classifier (DLHandle, 'pill_classifier.hdl')

这段代码跑通,你就完成了80%的工作。剩下的20%是调参和排查问题,那才是真正拉开差距的地方。


4. 参数调优与避坑实战

4.1 学习率、batch_size、epochs 怎么配

这三个参数是训练的核心,我用一个表格把经验值列出来,再说背后的逻辑。

参数常用范围我的默认值调整方向
learning_rate0.0001 ~ 0.010.001精度不涨就降,震荡就再降
batch_size4 ~ 328显存够就加大,小数据集用4
epochs20 ~ 10030看验证集精度曲线,不再涨就停

学习率是最关键的。太大,loss来回震荡不收敛;太小,训练慢到怀疑人生。我的经验是从0.001起步,如果训练loss在前5个epoch就掉到很低但验证精度上不去,说明过拟合了,降学习率没用,得加数据或加正则。如果loss一直居高不下,先检查数据标注是不是有问题。

batch_size影响的是梯度估计的稳定性。batch太小(比如2),梯度噪声大,训练不稳定;batch太大,泛化可能变差。工业场景数据量通常不大,8是个比较稳的中间值。显存不够就降到4,别硬撑。

epochs不是越多越好。我一般会设一个较大的值(比如100),然后每5个epoch评估一次验证集精度,连续3次不涨就提前停。Halcon本身没有内置的early stopping,得自己在循环里写判断。

4.2 数据增强:Halcon帮你做了多少

Halcon的train_dl_classifier_batch内部默认会做这些增强:

  • 随机旋转(小角度)
  • 随机缩放
  • 随机亮度/对比度扰动
  • 随机裁剪

这些对工业场景基本够用。但如果你有特殊需求,比如产品会360度旋转,那默认的小角度旋转就不够了,得自己在预处理阶段用rotate_image把图转一圈生成多个副本。

注意:增强不是越多越好。过度增强会让模型学到“旋转不变性”这种在产线上根本不存在的特性,反而降低精度。增强策略要贴合实际工况——产线上产品怎么摆放,训练集就怎么增强。

4.3 常见报错与排查速查表

我把这些年踩过的坑整理成一张表,遇到问题先对号入座:

现象可能原因排查方法
训练loss不下降学习率过大/数据标注错乱降到0.0001重试,抽查标注
验证精度远低于训练精度过拟合加数据、加weight_prior、减epochs
某一类精度特别低类间不平衡补充该类样本或调class_weights
读图报错路径含中文/格式不支持改英文路径,统一png
License报错深度学习模块未授权检查License是否含DL模块
推理速度慢用了大网络/CPU推理换compact,或启用GPU
置信度普遍偏低训练不充分/域差异大加epochs,检查训练与现场成像一致性

关于License我要多说一句。Halcon的深度学习模块是需要单独授权的,普通License跑不了create_dl_classifier。很多人下载安装完发现算子报错,第一反应是版本问题,其实是License没覆盖DL模块。这个在项目启动前就要确认,别等到训练到一半才发现。

4.4 推理部署:训练完怎么用起来

训练只是上半场,部署才是见真章的地方。推理的核心算子就两个:

read_dl_classifier ('pill_classifier.hdl', DLHandle) classify_image (Image, DLHandle, ClassName, Confidence)

classify_image返回预测类别和置信度。实际产线上,我一般会加一个置信度阈值判断:置信度高于0.9直接判,低于0.9的图单独存下来人工复核。这样既保证了产线节拍,又不会漏掉边界样本。

如果要在C++或C#里调用,思路是一样的:ReadDlClassifier读模型,ClassifyImage推理。Halcon的深度学习模型跨语言调用非常干净,不像PyTorch模型还得转ONNX、装运行时,这点在工业部署上是实打实的优势。


5. 几个容易被忽略的进阶细节

5.1 类别不平衡的补救手段

前面提过类间数量比控制在1:3以内,但现实中NG样本就是少,怎么办?三个办法:

  • 加权损失:Halcon支持通过class_weights给不同类别设权重,让少样本类的loss贡献更大。这个参数在set_dl_classifier_param里设。
  • 过采样:把NG样本复制多份,配合不同的增强参数,让每轮训练都能见到足够多的NG。
  • 合成样本:用gen_dl_samples配合增强算子,程序化生成变体。

我一般优先用加权损失,简单直接。过采样容易导致过拟合,合成样本则要小心生成得太假。

5.2 训练集和现场不一致怎么办

这是工业视觉最头疼的问题。实验室训得好好的,现场一上就拉胯。我的处理流程是:

  1. 先量化差异:拿现场图跑一遍模型,看置信度分布。如果普遍在0.6以下,说明域差异很大。
  2. 小样本微调:从现场采几十张图,混进训练集重新训。不需要全部重训,在已有模型基础上继续train_dl_classifier_batch即可。
  3. 在线迭代:产线跑起来之后,把置信度低的图定期回收,人工标好再喂回去。这是个持续迭代的过程,不是一锤子买卖。

5.3 模型评估不能只看准确率

准确率这个指标在类别不平衡时会骗人。OK占95%,模型全判OK也有95%准确率,但NG一个没抓到。所以我评估时必看三个东西:

  • 混淆矩阵:看清楚错判的方向。
  • 每类召回率:NG的召回率才是产线真正关心的。
  • 置信度分布:正常样本和异常样本的置信度是否分得开。

如果NG召回率上不去,宁可牺牲一点OK的准确率,把判定阈值往NG方向偏。产线上漏检的代价远大于误检。


6. 我个人的一些实操体会

最后分享几个文档里不会写、但实际项目里特别管用的经验。

第一,先跑通再优化。别一上来就纠结网络选型、参数调优。用compact网络、默认参数、30个epoch先跑一版,看看baseline在哪。有了baseline,后面每一步调整才知道是涨了还是跌了。

第二,数据质量决定上限,模型和参数只决定你能不能摸到上限。我见过太多人把时间花在调参上,结果回头一看训练集里混了十几张标错的图。花半天时间把数据清洗干净,比调三天参数管用。

第三,训练日志一定要存。每次训练的配置、精度、混淆矩阵都记下来,最好连模型文件一起归档。产线上出问题回溯的时候,你会感谢当时留了日志的自己。

第四,别迷信端到端。Halcon分类模型和传统算子结合使用,效果往往比纯深度学习好。比如先用threshold把ROI裁出来再分类,比整图直接分类精度高得多,因为模型不用去学“忽略背景”这件事。

第五,模型是要养的。上线不是终点,是起点。产线换料、换批次、换季节,成像都会变。建立一个定期回收低置信度样本、人工复核、增量训练的闭环,模型才能长期稳定。

这套流程我在好几个项目上跑过,从药片缺陷到瓶盖正反,从PCB良品判定到字符印刷质量,基本都能落地。Halcon的深度学习分类模型不是什么黑科技,它就是一个把CNN封装成工业算子的工具,用好它的关键不在模型本身,而在你对问题的理解和对数据的把控。

返回列表