当前位置: 首页 > news >正文

利用高通跃龙QCS9100平台部署工业异常检测模型PaDiM(2): QNN转换与板端部署

前言

上一篇我们把PaDiM模型的 backbone 导出成了 ONNX,统计参数也存好了。接下来就是把 ONNX 转成 高通QCS9100平台上跑的格式,再在板子上把完整推理链路跑通。

说实话,QNN 这套工具链第一次用会觉得有点绕,但只要按步骤来,问题不大。这篇会尽量把命令和路径写清楚,你照着做能少踩点坑。

1. QNN SDK 安装与路径说明

1.1 下载 QNN SDK

去高通开发者官网下 QNN SDK,选和你 QCS9100 系统匹配的版本(比如 2.18、2.20 等)。解压后目录大概长这样:

qnn-v2.18.0/ ├── bin/ │ ├── x86_64-linux-clang/ # x86 Linux 工具 │ └── aarch64-android/ # Android 目标 ├── lib/ ├── include/ └── ...

我们主要用qnn-onnx-converterqnn-model-lib-generator,这两个在 bin 下面。

1.2 设置环境变量

export QNN_SDK_ROOT=/path/to/qnn-v2.18.0 export PATH=$QNN_SDK_ROOT/bin/x86_64-linux-clang:$PATH export LD_LIBRARY_PATH=$QNN_SDK_ROOT/lib/x86_64-linux-clang:$LD_LIBRARY_PATH

建议写进~/.bashrc,每次开终端自动生效。

1.3 检查工具是否可用

qnn-onnx-converter --help qnn-model-lib-generator --help

能打出帮助信息说明环境 OK。

2. ONNX 转 QNN 模型

2.1 准备 ONNX 模型

上一篇导出的padim_resnet18_backbone.onnx直接拿来用。如果输入是动态 batch,建议先固定成 1,避免板端一些奇奇怪怪的问题:

# fix_onnx_batch.py import onnx from onnx import shape_inference model = onnx.load("padim_resnet18_backbone.onnx") # 固定 batch=1 for inp in model.graph.input: for d in inp.type.tensor_type.shape.dim: if d.dim_param == "batch": d.ClearField("dim_param") d.dim_value = 1 onnx.save(model, "padim_resnet18_backbone_fixed.onnx")

2.2 运行转换

qnn-onnx-converter \ --input_network padim_resnet18_backbone.onnx \ --output_path padim_qnn \ --input_list input_names.txt

input_names.txt内容(根据你 ONNX 的实际输入名调整):

image 1 3 256 256

格式是:输入名 batch channel height width

2.3 量化

QCS9100 的 NPU 跑 INT8 比 FP32 快很多,建议做量化。准备一些校准图片(正常样本裁成 256×256),列个清单:

# calibration_list.txt /path/to/img1.png /path/to/img2.png ...

然后:

qnn-onnx-converter \ --input_network padim_resnet18_backbone.onnx \ --output_path padim_qnn_quant \ --input_list input_names.txt \ --quantization_overrides quantization_overrides.json

quantization_overrides.json示例(按需调整):

{ "ConvertFp16ToFp32": ["Conv", "Gemm"], "Quantization": { "image": { "quantization_scheme": "quantization_scheme_range_unsigned_symmetric", "bit_width": 8, "calibration_method": "calibration_method_per_channel" } } }

量化这块不同版本 QNN 参数可能不一样,以官方文档为准。转完之后会得到.bin.cpp等文件,这些就是板端要用的。

3. 生成可执行库

qnn-model-lib-generator \ --model padim_qnn/padim_resnet18_backbone.cpp \ --model padim_qnn/padim_resnet18_backbone.bin \ --output_dir padim_lib

生成完会有一坨.so或静态库,这就是在 QCS9100 上要链接的推理库。

4. 板端部署思路

4.1 文件准备

把下面这些拷到板子:

  • padim_lib/下的库文件
  • padim_mean.npypadim_cov_inv.npy
  • QNN 的 runtime 库(在 QNN SDK 的lib里,按目标架构选)

4.2 推理流程伪代码

  1. 初始化QNN context,加载 backbone 模型
  2. 加载padim_mean.npypadim_cov_inv.npy
  3. 循环:
    a. 从摄像头/文件读一帧图像
    b. 预处理:resize 到 256×256,减均值除方差(和训练时一致)
    c. 调用 QNN 执行 backbone 前向 → 得到 layer1/2/3 特征
    d. 按 PaDiM 论文把多层特征拼接、reshape
    e. 用马氏距离公式算异常分数
    f. 大于阈值判异常,可选画热力图

4.3 Python 板端示例(有 QNN Python 绑定时)

# 伪代码,具体 API 以 QNN Python 包为准 from qnn import QNNRuntime import numpy as np rt = QNNRuntime(model_path="padim_backbone.qnn") mean = np.load("padim_mean.npy") cov_inv = np.load("padim_cov_inv.npy") def infer(image): # image: 256x256x3, 预处理后 feat = rt.execute(image) # 按 PaDiM 公式算马氏距离 score = mahalanobis(feat, mean, cov_inv) return score

4.4 C++ 板端

高通一般推荐用 C++ 调 QNN,性能更好。流程就是:

  1. QnnContext加载模型
  2. QnnInterface::graphExecute()跑推理
  3. 取输出 buffer,在 CPU 上做马氏距离和热力图

这部分代码量不少,建议直接参考 QNN SDK 里的 sample,把输入输出改成 PaDiM 的就行。

5. 性能与阈值 tuning

  • 时延:backbone 在 NPU 上大概几毫秒到十几毫秒(看量没量化、输入尺寸),马氏距离在 CPU 上很快,整体可以做到几十毫秒一帧。
  • 阈值:用验证集或测试集正常/异常样本算一遍分数,画个分布,挑个合适的阈值,让召回率和误报率平衡一下。

6. 小结

这篇把 ONNX → QNN → 板端推理的主线走通了,重点是:

  1. QNN SDK装好,环境变量设对
  2. qnn-onnx-converter把 backbone 转成 QNN 格式,能做量化尽量做
  3. 板端:QNN 跑 backbone,CPU 算统计部分,两者结合就是完整的 PaDiM 推理

该系列完

http://www.jsqmd.com/news/462092/

相关文章:

  • 重构个人数字记忆:WeChatMsg如何赋能用户掌控聊天记录主权
  • RTX 4090高算力适配典范:Qwen-Turbo-BF16开源镜像部署与性能调优指南
  • FireRedASR-AED-L与卷积神经网络(CNN)前端结合:提升噪声环境识别率
  • 文脉定序系统Docker镜像使用详解与Compose编排
  • Python tkinter.filedialog实战:文件与文件夹交互操作全解析
  • 2026年用户口碑优选常州全屋定制品牌:五大品牌服务案例与工艺对比 - 品牌推荐
  • YOLOv11视觉感知+Qwen3-ASR-0.6B语音感知的多模态交互demo
  • 国产AI Agent大逃杀:谁在裸泳一目了然!!!
  • 自由获取数字内容:如何通过开源下载工具掌控你的阅读体验
  • 雪女-斗罗大陆-造相Z-Turbo技术解析:其内部神经网络架构与LSTM模块的应用
  • 高端家居定制趋势洞察:2026年常州全屋定制品牌市场格局与竞争力解析 - 品牌推荐
  • Qwen3-Reranker-0.6B应用场景:汽车维修手册多版本文档变更敏感性重排序
  • Android崩溃日志全解析:adb logcat与DropBox实战指南
  • Python项目改成绝对路径导入后,只能从项目根目录运行了吗?(否,可将项目根目录加入PYTHONPATH环境变量,也可用pip install -e .把项目装成包)没有包名补全功能、绝对路径导包
  • 轻松构建LLM微调数据集:Easy-Dataset实战指南
  • 效果炸裂!Local SDXL-Turbo赛博朋克风格生成实测
  • 解决Pycharm调试时Gevent兼容性问题:变量显示超时的终极方案
  • 解决Ubuntu20.04虚拟网卡配置后重启失效的问题:netplan实战技巧
  • 麦橘超然Flux图像生成控制台:5分钟本地部署,低显存也能玩转AI绘画
  • 华为云OBS存储桶创建报错解析:如何解决区域约束不兼容问题
  • 基于Chatbot Arena Leaderboard论文的AI辅助开发实战:如何构建高效对话系统
  • 机械臂关节空间轨迹规划之 B 样条算法探索
  • vLLM+Chainlit强强联合:GLM-4-9B-Chat-1M镜像部署与使用全解析
  • Qwen3-4B Instruct-2507部署教程:支持A10/A100/V100多卡自适应分配
  • ANIMATEDIFF PRO实战体验:从文字到电影级动画的完整流程
  • 从零开始:InternLM2-Chat-1.8B模型在Windows系统下的部署教程
  • 手把手教你将AW88195音频驱动从MTK移植到RK平台(附完整配置流程)
  • VSCode离线插件安装全攻略:从.vsix下载到成功部署
  • FUTURE POLICE模型在计算机组成原理教学中的应用演示
  • Python uiautomation 实现微信自动化消息处理