aidqnn 高层 Python SDK 开发者指南
本指南旨在帮助开发者快速上手使用 aidqnn 高层 Python SDK。该 SDK 对底层的 aidlite C++ 接口进行了深度封装,提供了极其简化的 API 来加载和运行各种 AI 模型(ONNX、TFLite、QNN),并自动处理了设备调度、输入输出形状推导以及张量轴(Axis)转换等繁琐工作。
1. 核心特性
- 极简加载:支持通过单行代码直接从模型文件或 aimo(模型优化平台)下载的文件夹中加载模型。
- 多框架支持:无缝支持 ONNX (
cpu)、TFLite (cpu,gpu) 和 QNN (cpu,gpu,npu)。 - 智能排布修正:QNN 优化模型时可能会改变张量的轴顺序(例如 NCHW 变成 NHWC),SDK 能够根据配置文件自动在后台完成转置(Transpose),开发者无需修改预处理/后处理代码。
- 环境自适应:自动识别 AidLux 社区版(normal)与企业版,智能切换 QNN 的 Remote 与 Local 推理模式。
2. 快速入门:懒人加载模式 (from_path)
对于大部分从 aimo 平台 导出的 QNN 模型,最推荐、也是最简单的使用方式是使用 AutoModel.from_path。
⚠️注意:传给 from_path 的文件夹必须是直接从 aimo 平台下载并解压后的原始文件夹,切勿随意重命名或删除其中的任何文件。SDK 会依赖文件夹内的文件结构(如 ctx.bin、.so、_net.json 等)自动推断最佳配置。
import numpy as np
from aidqnn import AutoModel
model = AutoModel.from_path("./model_save_path")
# 2. 准备输入数据
# 注意:ONNX 和 TFLite 均不支持动态形状(Dynamic Shapes),必须严格匹配模型要求的固定尺寸。
# QNN 模型强制要求输入数据格式为 np.float32,无论是否量化。
input_data = np.random.randn(1, 3, 224, 224).astype(np.float32)
# 3. 运行推理
output = model(input_data)
print("推理成功,输出形状:", output.shape)
3. 进阶使用:常规加载模式 (AutoModel)
如果你手上只有单独的模型文件(比如单个 .tflite 或 .onnx 文件),可以直接使用 AutoModel 类来进行实例化。SDK 会根据文件后缀名自动判断框架类型。
from aidqnn import AutoModel
import numpy as np
# -------- 加载 TFLite 模型 --------
# 默认情况下,TFLite 会尝试使用 GPU
tflite_model = AutoModel("model.tflite", device="gpu")
output = tflite_model(np.random.randn(1, 224, 224, 3).astype(np.float32))
# -------- 加载 ONNX 模型 --------
# ONNX 目前仅支持 CPU 设备
onnx_model = AutoModel("model.onnx", device="cpu")
output = onnx_model(np.random.randn(1, 3, 224, 224).astype(np.float32))
3.1 手动加载 QNN 模型时的注意事项
如果是手动指定 QNN 模型文件(.so 或 .bin),强烈建议同时传入 model_config 参数(即 _net.json 文件的路径)。config 文件可以在 aimo 导出的文件夹中找到,通常是文件大小最大的那个 .json 文件。
为什么? QNN 框架在优化时经常会做通道排布的转换(Channel Last 优化,例如把 NCHW 转换为 NHWC,NCF 转换为 NFC)。如果不传 Config 文件,你需要自己手动做 np.transpose;如果传入了 Config 文件,SDK 的 AidModel 会自动解析 axis_format,并在推理前后为你自动完成输入数据的转置和输出数据的复原。
# 手动加载 QNN 并在参数中补充 config 路径,确保轴顺序自动纠正
qnn_model = AutoModel(
model_path="model_aarch64.ndk.so",
model_config="model_net.json", # 强烈建议传入!
device="gpu"
)
4. 推理传参方式
SDK 提供了非常灵活的调用方式,支持多输入模型的灵活传参。重载的 __call__ 方法允许你以位置、字典或关键字参数的形式输入数据。
假设你的模型有两个输入,名字分别为 "input_1" 和 "input_2":
input1_data = np.random.randn(1, 3, 224, 224).astype(np.float32)
input2_data = np.random.randn(1, 3, 224, 224).astype(np.float32)
# 方式一:位置传参 (需确保顺序与模型要求的输入顺序一致)
out = model(input1_data, input2_data)
# 方式二:字典传参(名字需要和模型输入名字一直,可在aimo转换时手动指定)
out = model({"input_1": input1_data, "input_2": input2_data})
# 方式三:关键字传参 (Kwargs)
out = model(input_1=input1_data, input_2=input2_data)
关于多输出:
- 如果模型只有 1 个输出,返回值直接是
np.ndarray。 - 如果模型有多个输出,返回值是一个包含多个
np.ndarray的元组Tuple[np.ndarray, ...]。
out = single_output_model(input_data) # 单输出模型直接返回一个 np.ndarray
out1, out2 = multi_output_model(input_data) # 多输出模型返回一个元组
5. 开发者必读须知
- 静态形状限制 (Static Shapes Only)
无论是 ONNX、TFLite 还是 QNN,当前均不支持动态形状。你喂给模型的数据
shape必须与模型导出时固化的shape完全一致,否则 SDK 会抛出ValueError。 - 社区版 vs 企业版 QNN (Local/Remote 模式) AidLux 的 QNN 推理分为 Remote 模式和 Local 模式:
- 社区版:手机上下载的 AidLux 版本为社区版。受限于系统架构和权限问题,仅支持以 Remote 模式运行 QNN。手动指定非量化模型需选中 aimo 中带有
ndk关键词的.so文件。 - 企业版:支持 Local 和 Remote 两种模式。推荐使用 Local 模式以获得更低的延迟和更高的性能,手动指定模型时需选中 aimo 中带有
gcc9_4关键词的.so文件。 - 量化模型:无论 Local 和 Remote 模式,量化模型手动指定模型时都只用选中带有
ctx.bin关键词的文件。 - SDK 处理逻辑:通常 SDK 会自动试图确定是否为社区版,开发者通常不需要操心这一点后端实现,只用确保正确选择模型文件即可。
- 数据类型安全
在处理 QNN 模型时,底层 API 严格要求输入数据为 32 位浮点数,请确保使用
.astype(np.float32)进行预处理。对于量化模型,虽然模型内部是量化的,但输入数据仍需为float32,SDK 会在底层自动进行量化处理。
最终的输出数据类型也是 float32。
在使用 aimo 转换模型到 qnn 格式的时候,注意尽量确保模型输入输出的数据类型为 float32,以避免在 SDK 层出现不可预料的结果和潜在的精度损失。