利用高通跃龙IQ-9100平台部署工业异常检测模型PaDiM(1): 环境准备与模型导出

发布时间:2026/5/16 14:33:04

利用高通跃龙IQ-9100平台部署工业异常检测模型PaDiM(1): 环境准备与模型导出 前言做工业视觉的朋友都知道产线上的表面缺陷检测是个头疼事儿——划痕、污点、色差人工盯久了眼睛累漏检率还高。这几年用深度学习做异常检测越来越火其中PaDiM模型特别适合工业场景只用正常样本训练其实不算传统训练后面会讲不需要标注缺陷部署起来也相对轻量。高通跃龙IQ-9100平台作为高通跃龙系列的旗舰平台100 TOPS的 AI 算力、-40~115℃的工业级温宽天生就是为工厂车间、户外检测这类场景设计的。把 PaDiM 部署上去摄像头拍一张、板子算一下、几毫秒出结果断网也能跑数据也不用上传云端挺香。这里我们使用的硬件是Thundercomm的基于高通跃龙IQ-9100 平台 Linux OS的AI边缘盒子这个系列将分两篇介绍1讲环境和模型导出在 PC 上把该准备的准备好2讲 QNN 转换和板端部署真正跑到 高通跃龙IQ-9100平台上。先别急着上板子环境搞对了后面能省不少事。1. 整体部署架构先把大致的流程捋清楚后面每一步就知道自己在干嘛了。流程总结训练阶段在PC端完成PaDiM模型训练导出ONNX骨干网络和统计参数。转换阶段利用QNN Converter将ONNX模型转换为端侧可执行格式。推理阶段IQ-9100板端NPU加速特征提取CPU完成后处理最终输出异常检测结果。核心思路特征提取交给 QNN 在 NPU 上跑占大头统计比较在 CPU 上算就行计算量小。这样既能吃到硬件加速又不用把 PaDiM 的整套逻辑都塞进 QNN协方差、马氏距离那些算子支持不好搞。2. PaDiM 到底是个啥用一句话概括用预训练 CNN 提特征用多元高斯分布描述正常长啥样测试时算个马氏距离离得远就是异常。训练阶段只用正常样本前向传播提特征拟合每个 patch 的均值和协方差不做反向传播。推理阶段新图进来提特征 → 跟训练好的分布算马氏距离 → 得到异常分数和定位热力图。所以训练其实是统计拟合非常快十几二十分钟搞定一个类别。而且模型主体就是 ResNet18 这类成熟 backbone导出 ONNX、转 QNN 都比较顺。3. 环境准备PC 端下面这些是在你电脑上要装的用来跑 Anomalib、导出 ONNX。建议用 Linux 或 WSL2避免 Windows 上各种路径和依赖的坑。3.1 创建虚拟环境**建议 Python 3.9 或 3.10** conda create -n padim_qcs9100 python3.10 -y conda activate padim_qcs91003.2 安装 Anomalib 及依赖如果你有 NVIDIA 显卡可以装 GPU 版这里先按 CPU 来pip install anomalib[full,cpu]如果只做推理和导出可以精简一点pip install anomalib torch torchvision pip install onnx onnxruntime3.3 验证安装python -c from anomalib.models.image.padim import Padim model Padim(backboneresnet18, layers[layer1,layer2,layer3], n_features100) print(PaDiM 加载成功)能打印 “PaDiM 加载成功” 就说明环境 OK。4. 用 MVTec AD 跑一版 PaDiMMVTec AD 是工业异常检测的经典数据集各种材质、纹理、缺陷类型都有。先拿它过一遍流程后面换你自己的数据照葫芦画瓢就行。4.1 下载数据集# 创建目录 mkdir -p data cd data # MVTec AD 官网https://www.mvtec.com/company/research/datasets/mvtec-ad # 或用 anomalib 自带的自动下载部分类别 # 这里以 bottle 为例手动下载后解压到 data/MVTec/bottle/如果使用 Anomalib 自带的数据加载它会按需下载。我们直接用命令行训练一版anomalib train --model padim --data MVTec --data.category bottle训练完成后模型和结果一般在 results 目录下。4.2 用 Python 脚本训练并保存如果不想用 CLI可以写个脚本方便后面改参数和导出# train_padim.py from anomalib.data import MVTec from anomalib.models.image.padim import Padim from anomalib.engine import Engine # 数据 datamodule MVTec( rootdata, categorybottle, image_size256, train_batch_size32, eval_batch_size32, ) # 模型ResNet18 适合边缘部署想更准可以换 wide_resnet50_2 model Padim( backboneresnet18, layers[layer1, layer2, layer3], n_features100, pre_trainedTrue, ) # 训练 engine Engine( max_epochs1, # PaDiM 一个 epoch 就够了 acceleratorauto, default_root_dirresults/padim_bottle, ) engine.fit(modelmodel, datamoduledatamodule)跑完会得到results/padim_bottle下的 checkpoint里面包含 backbone 权重和统计参数均值、协方差等。5. 导出 ONNX把 backbone 单独摘出来PaDiM 推理时真正占时间的部分是 backbone 前向。我们先把 backbone 导出成 ONNX后面用 QNN 工具转成板端可跑的格式。统计那部分均值、协方差、马氏距离保留在 Python/C 里推理时先调 QNN 跑 backbone再在 CPU 上算分数。# export_backbone_onnx.py import torch from anomalib.models.image.padim import Padim from anomalib.models.components import AnomalyModule # 加载训练好的模型 model Padim.load_from_checkpoint(results/padim_bottle/lightning_logs/version_0/checkpoints/last.ckpt) model.eval() # 获取 backboneResNet18 backbone model.model.backbone # 示例输入[1, 3, 256, 256] dummy_input torch.randn(1, 3, 256, 256) torch.onnx.export( backbone, dummy_input, padim_resnet18_backbone.onnx, input_names[image], output_names[layer1, layer2, layer3], opset_version13, dynamic_axes{ image: {0: batch}, layer1: {0: batch}, layer2: {0: batch}, layer3: {0: batch}, }, ) print(Backbone ONNX 导出成功: padim_resnet18_backbone.onnx)注意不同版本的 AnomalibPaDiM 的model结构可能略有差异有的需要从model.model.backbone取有的可能多一层封装。遇到报错就print(model)看一下结构把 backbone 抠出来就行。5.1 保存统计参数推理时除了 backbone还需要均值向量和协方差矩阵或逆矩阵。训练完后把这些保存下来# save_stats.py import numpy as np from anomalib.models.image.padim import Padim model Padim.load_from_checkpoint(results/padim_bottle/lightning_logs/version_0/checkpoints/last.ckpt) padim_model model.model # 提取并保存 np.save(padim_mean.npy, padim_model.mean.cpu().numpy()) np.save(padim_cov_inv.npy, padim_model.inv_covariance.cpu().numpy()) print(统计参数已保存: padim_mean.npy, padim_cov_inv.npy)这些.npy文件后面一起拷到板子上推理时加载用。6. 用 ONNX Runtime 快速验证导出 ONNX 后先在 PC 上用 ONNX Runtime 跑一版确保输出和 PyTorch 一致# verify_onnx.py import onnxruntime as ort import numpy as np sess ort.InferenceSession(padim_resnet18_backbone.onnx) x np.random.randn(1, 3, 256, 256).astype(np.float32) out sess.run(None, {image: x}) print(输出层 shape:, [o.shape for o in out])能看到layer1/2/3的 shape 就说明 backbone 导出没问题。7. 小结与本篇踩坑记录本篇完成了.环境搭建Anomalib PyTorch ONNX.MVTec AD 训练用 bottle 类别跑了一版 PaDiM.Backbone 导出 ONNXpadim_resnet18_backbone.onnx.统计参数保存padim_mean.npy、padim_cov_inv.npy这边踩过的坑Anomalib 版本不同Padim的model.model结构不一样导出前先dir(model.model)看一下。输入尺寸要固定训练时用的 256导出和板端推理都要保持一致。MVTec AD 下载有时会很慢可以提前从官网下好解压到data/MVTec/。下一篇会写用 QNN 工具把 ONNX 转成 IQ-9100 可执行的格式以及在板子上接摄像头跑实时的完整 C/Python 推理流程。有问题的朋友可以评论区留言一起琢磨。

相关新闻