AidLite Python 接口文档
使用 AutoModel
以下步骤适用于 Linux Python SDK。 AutoModel 已合入当前维护源码。 安装包需要包含配套的核心、Python 扩展和后端。 已发布的旧安装包不一定包含此接口。 AutoModel 为本地后端和 Android 推理服务提供统一入口。 枚举成员和模型格式识别不代表该后端可以运行。 安装匹配的后端插件和 SDK。 后端需要提供相应张量 API。 入口统一不代表每个模型都已通过设备兼容性验证。 AutoModel 和 InferenceSession 支持显式选择 LOCAL 或 REMOTE。 以下 REMOTE 用法需要包含此功能的配套源码构建。 旧发布包不一定包含此功能。 使用前,阅读 REMOTE 模式排查。
准备模型
- 使用已转换的本地模型。
- 确认模型后端与设备上的 SDK 版本匹配。
- 按原模型的要求准备输入。
新版 AIMO 可在 .aidem 中保存输入输出元数据。 原生 QNN context 使用配套的 <模型文件名>.io.json。 保留模型与配套文件。 不要把所有输入统一转换为 FP32。 元数据需要配套的新版 AIMO 转换器和模型打包服务。 已有模型文件不会自动更新。
“原模型”指 AIMO 转换入口的 ONNX 模型。 元数据不能恢复此前导出器已经改变的接口。 图像归一化、分词和其他模型预处理仍由调用方完成。
调用单输入模型
- 从文件读取原模型的输入数组。
- 加载模型。
- 调用模型。
import numpy as np
from aidlite import AutoModel
inputs = np.load("input.npy", allow_pickle=False)
with AutoModel.from_pretrained("model.aidem") as model:
outputs = model(inputs)输入数组保留原模型要求的类型和形状。 例如,FP16 输入使用 numpy.float16。 ID 和掩码也使用各自声明的数据类型。 单输出模型返回数组。 多输出模型按原模型顺序返回元组。 输出在模型关闭后仍然可用。
调用多输入模型
将各输入数组保存到同一个 .npz 文件。 使用原模型的输入名称作为键。 保留每个数组自身的数据类型。
import numpy as np
from aidlite import AutoModel
with np.load("inputs.npz", allow_pickle=False) as archive:
inputs = {name: archive[name] for name in archive.files}
with AutoModel.from_pretrained("model.aidem", return_dict=True) as model:
outputs = model(inputs)返回字典使用原模型的输出名称。 位置参数也按原模型输入顺序处理。 不要按转换后的张量顺序重排输入。
检查接口
加载模型后,检查 model.inputs 和 model.outputs。 每个 TensorSpec 提供名称、形状和数据类型。 model_shape 和 runtime_dtype 描述适配后的运行时接口。
| 参数 | 行为 |
|---|---|
interface="auto" | 优先使用可用的 AIMO 元数据;缺少或无法使用时回退到后端张量 API。 |
interface="original" | 要求模型包含可验证的原接口元数据。 |
interface="runtime" | 使用内部接口,由调用方管理转换。 |
新版 AIMO QNN 模型会自动匹配已验证的名称、顺序和维度排列。 包装层只执行普通 SDK 接口需要的类型转换。 后端已有的量化和反量化不会再执行一次。 恢复数据类型不能恢复量化时损失的数值精度。
整数或布尔值无法通过接口转换保留时,调用会报错。 严格原接口模式下,名称、形状或布局无法确认时,加载会报错。 自动模式会在元数据无法使用时发出 ModelMetadataWarning。 随后使用后端的名称、形状和数据类型。 加载后检查 model.metadata_source、model.metadata_warning、model.inputs 和 model.outputs。 需要原接口时,请修正模型元数据。 不要通过随意转换类型来绕过错误。
支持范围
原接口适配当前支持单产物 QNN 模型的 graph 0。 需要版本为 1 的 aplux.model_io 元数据。 QNN context 仍使用转换后确定的形状。 元数据不会让固定形状模型自动支持动态输入。
没有元数据的 .bin 或旧 .aidem 可能需要显式指定 framework。 from_pretrained() 只读取已转换的本地模型。 它不下载模型,也不直接转换任意 Transformers 权重。
ONNX 输入类型
安装配套的新版 ONNX 插件。 该插件可直接绑定 float32、float16、bool、int8、int16、int32、int64、uint8、uint16、uint32 和 uint64 输入。 按 model.inputs 中的数据类型准备数组。 例如,FP16 模型输入使用 numpy.float16。 不要先转换成 FP32。 float64、字符串和压缩位宽类型不在当前支持范围内。 类型不受支持时,修正模型或选择支持该类型的后端。
选择 LOCAL 或 REMOTE
默认使用 LOCAL。 设置 implementation="remote",通过进程间通信调用 Android 推理服务。 model(x) 的调用方式保持相同。 device 选择执行设备;implementation 选择执行位置。 例如,device="dsp" 与 implementation="remote" 可同时使用。
import numpy as np
from aidlite import AutoModel
with AutoModel.from_pretrained(
"model.qnn240.ctx.bin", implementation="remote"
) as model:
print(model.implementation) # remote
# 本例使用一个固定形状的输入。按原模型要求准备真实输入。
x = np.zeros(model.inputs[0].shape, dtype=model.inputs[0].dtype)
y = model(x)多输入模型仍可按名字传入字典。 return_dict=True、输出选择和输出缓冲区复用也可使用。 有有效 AIMO 元数据时,AutoModel 继续适配原模型的 dtype 和布局。 没有该元数据时,使用服务返回的运行时接口。 检查 model.inputs 和 model.outputs。 不要假定所有模型都使用 FP32。
InferenceSession 提供相同的执行位置选项:
from aidlite import InferenceSession
with InferenceSession(
"model.qnn240.ctx.bin", framework="qnn240", device="dsp",
implementation="remote",
) as session:
# x 必须符合运行时接口。InferenceSession 不执行原接口适配。
y = session.run(x)已有代码也可设置 config.implement_type = ImplementType.TYPE_REMOTE。 显式 implementation 覆盖配置副本中的值,不修改原 config。 None 使用配置中的值;TYPE_DEFAULT 按 LOCAL 执行。 会话的 implementation 属性显示所选位置。
请检查以下条件:
- 安装相互匹配的 Python 扩展、核心、REMOTE 插件和 Android 服务。
- 确认服务支持所选后端和模型版本。只更新客户端不会更新 QNN。
- 确认服务可在加载后返回实际张量信息。高层入口不要求手填模型形状。
- 用
close()或with释放会话。输出视图的生命周期规则保持相同。
缺少服务或模型信息时,调用报告错误,不自动切换到 LOCAL。 旧 2.3.2 适配器不支持高层 REMOTE;使用配套的维护版构建。 当前动态 ONNX 输入能力限于 LOCAL CPU;此选项不会扩展服务的动态形状能力。 IPC 延迟取决于服务、模型和设备,不能保证与 LOCAL 相同。
QNN REMOTE 调用优化
固定形状、单图的 QNN REMOTE 模型可使用完整调用路径。 AutoModel 自动选择此路径。继续使用 model(x)。 此路径将输入、执行和所选输出合并为一次底层调用。 配套服务支持时,它可减少 IPC 往返次数。 输入输出的名字、原始 dtype 和布局规则保持相同。 输出选择、预分配输出和 copy=False 也可使用。
安装配套的 Python 扩展、核心和 REMOTE 插件。 插件在执行前检查服务能力和控制消息长度。 旧服务或过长的控制消息使用原有的逐步调用路径。 执行失败或超时后,不自动重试推理。 按错误信息重新建立会话。
其他后端、动态图和多图模型继续使用原有高层调用路径。 InferenceSession.run() 保留逐步绑定输入的行为。 例如,可先绑定输入 B,再传入输入 X 并执行。
REMOTE 插件将各 QNN 版本标识转换为服务协议中的 QNN 后端标识。 此转换不安装或升级 Android 上的 QNN。 服务仍须支持模型所用的 QNN 版本。
默认输出为独立副本。 copy=False 返回只读视图,并保留 Python 会话所有者。 下一次执行或显式关闭会话后,不再使用旧视图。 用实际模型测量延迟。此优化不保证 REMOTE 与 LOCAL 具有相同延迟。
复用远程输入缓冲区
配套服务在完整推理路径中复用输入长度头、校验标记和字节缓冲区。 model(x) 和 InferenceSession.run() 的调用方式相同。 每个输入保留独立的准备区和已提交数据区,最多使用两个字节数组。 准备下一次输入时,服务不会改写后端当前持有的数组。 输入载荷读取失败时,不会设置部分输入或执行推理。 后端调用或输出写入失败后,后续请求使用新的缓存存储。
缓存属于当前模型上下文。 输入字节数变化时,服务替换对应的存储。 模型所有者释放后,Java 可以回收缓存。 共享内存中的输入仍会复制到 Java 数组;JNI 和后端的数据传递接口保持相同。 原生输入的包装对象也会复用。 此优化主要减少临时对象分配。
在 QCS8550、Android 13 和配套 QNN 2.48 的限定测试中,原生 UINT8 路径的 ART 进程分配量下降约 29% 至 39%。 大输入的 P50 延迟下降约 12% 至 17%。 这些数据只适用于所测模型和环境。 小输入 FP32 默认路径的三轮 P50 变化为 +3.47%、+4.34% 和 +1.54%。 尾延迟也有波动;不能据此保证延迟相同。 每个字节输入最多保留两个载荷数组。 部署前,用实际模型检查内存占用和延迟。
构建和检查步骤见服务输入缓冲说明。
检查 QNN 原生接口的缓冲区
配套 JNI 在模型加载后读取并缓存实际的输入和输出规格。 它使用 SDK 返回的元数据,不使用调用者声明的形状来放宽检查。 每次推理不再查询这些规格。 此接口使用默认图;它不提供图切换操作。
普通输入和输出继续使用 FP32 数据表示。 原生模式使用模型实际的数据表示。 FloatArray 在原生模式下要求模型张量为 FP32。 字节数组保存原生数据的完整字节表示,可包含 FP16 或更宽的类型。 原有字节入口名称和 JNI 方法签名保持相同。 这些底层入口不会推断字节内容的数值类型,也不会安装新的后端能力。
输入数组必须与实际张量所需的长度完全相同。 带 size 参数时,该值还必须等于数组的字节数。 空引用、错误长度、负索引或越界索引会产生 IllegalArgumentException。 JNI 在取得数组数据和调用 SDK 之前执行检查。 错误输入不会替换已提交的输入。 使用正确数据后,可继续使用当前已加载的会话。
模型元数据缺失、无效或尺寸溢出时,模型加载失败。 释放该模型所有者,然后修正模型或 SDK 配套关系。 后端输出为空或返回错误长度时,JNI 会在复制到 Java 数组前报错。 后端异常也会释放本次取得的输入数组。 调用者仍须按顺序使用同一模型所有者,并在使用后释放它。
Python 调用者继续使用 AutoModel 或 InferenceSession。 这些检查位于配套 Android QNN JNI,不增加新的 Python 参数。 AutoModel 继续按有效 AIMO 元数据适配原模型的 dtype 和布局。 构建和测试步骤见QNN JNI 缓冲区说明。
使用 QNN 2.48 远程服务
QNN 2.48 模型需要配套的 Android 服务、Java 原生接口(JNI)库和 QNN 运行库。 AutoModel 和 InferenceSession 使用相同的 implementation="remote" 选项。 例如,加载为 QNN 2.48 转换的模型:
from aidlite import AutoModel
with AutoModel.from_pretrained(
"model.qnn248.ctx.bin", implementation="remote"
) as model:
outputs = model(inputs)按原模型要求准备 inputs。 不要把所有输入转换为 FP32。 有有效 AIMO 元数据时,AutoModel 继续适配原始 dtype 和布局。 服务仍需支持模型版本和数据模式。 客户端中的 QNN 版本标识不会升级 Android 运行库。
如果你自行构建服务,使用同一次 SDK 构建导出的头文件和静态库。 维护版 SDK 会导出 sdk-package/Release/manifest.json。 这是 SDK 配套清单,与模型输入输出元数据不同。 新版 SDK 的参数结构和清理接口已改变,不能只替换静态库。 将整个 SDK 配套目录交给 JNI 构建,通过 QNN_JNI_SDK_MANIFEST 选择它。 构建会检查文件哈希、应用二进制接口(ABI)、Android API 等级和 C++ 运行库。 省略此选项时,继续使用原来的 SDK 配对。 步骤见 SDK 构建指南 和 JNI 构建指南。
排查自定义 Android 服务时,在 AidQNN.init() 成功后调用 getInferenceFrameworkVersion()。 该方法返回已加载后端的 QNN 核心 API 版本,并缓存结果。 旧 JNI 或旧 SDK 无法查询时,返回 unknown,不再返回写死的 2.36.0。 核心 API 版本与 QAIRT 发行版本不同。 本次验证中,QAIRT 2.40.0.251030 返回 2.30.0,2.48.0.260626 返回 2.37.0。 保留 SDK 构建清单和库文件哈希,以确认具体安装包。 此方法不增加每次推理的查询开销,也不会自动升级远程服务。
QCS8550 的隔离服务已验证匹配的 QNN 2.40 和 2.48 运行库。 检查包括双输入、三输出、命名输入、输出复用和只读视图。 两个不同数据模式的会话也通过了并发检查。 受控元数据检查了原始输入类型和布局适配。 这不代表新的 AIMO 转换、加密模型或所有平台均已验证。 源码更新也不代表已安装的服务包已经更新。
用实际模型测量延迟。 本次配对测试中,2.48 的六组 P50 变化约为 −4.96% 到 +3.18%。 FP32 默认输出的 P99 约增加 8.8%。 这些结果不证明尾延迟等价,也不证明 REMOTE 与原生推理具有相同延迟。
可选推理控制
保留默认的 model(inputs) 用法。 需要选择输出或复用输出数组时,使用 predict()。
选择输出
使用 model.output_names 中的输出名称。 返回结果按所选顺序排列。
import numpy as np
from aidlite import AutoModel
inputs = np.load("input.npy", allow_pickle=False)
with AutoModel.from_pretrained("model.aidem") as model:
name = model.output_names[0]
result = model.predict(inputs, outputs=[name])框架只读取和适配所选输出。 这可以减少输出复制和转换。 这不承诺减少模型内部的计算。 使用 return_dict=True 时,返回字典以所选输出名称作为键。
复用输出数组
分配可写、C 连续的 NumPy 数组。 使用输出声明的数据类型和确定形状。 动态输出需要先获取实际形状,再分配数组。
import numpy as np
from aidlite import AutoModel
inputs = np.load("input.npy", allow_pickle=False)
with AutoModel.from_pretrained("model.aidem") as model:
name = model.output_names[0]
first = model.predict(inputs, outputs=[name])
buffer = np.empty_like(first)
result = model.predict(inputs, outputs=[name], out=buffer)返回数组就是传入的缓冲区。 复用缓冲区会覆盖上一次的结果。 多个输出使用 out={name: array},键必须与所选输出完全一致。 输出缓冲区不能与输入重叠,也不能彼此重叠。 输出缓冲区要求 return_tensors="np"。 后端到缓冲区仍可能复制数据。 必要的数据类型或布局转换仍可能分配临时数组。
选择原生输入和输出模式
这些选项适用于已经管理后端张量格式的 QNN 和 SNPE 流程。 加载模型时,分别设置 native_input 和 native_output。 两者默认均为 False。
from aidlite import AutoModel
with AutoModel.from_pretrained(
"model.qnn248.ctx.bin",
native_input=True,
native_output=False,
) as model:
print(model.inputs, model.outputs)开启任一选项时,整个模型使用内部接口。 按 model.inputs 和 model.outputs 准备每个张量。 原生一侧使用物理张量类型。 普通一侧使用后端普通接口。 调用方需要确认量化参数和张量含义。 包装层不会额外执行量化。 原生模式在模型生命周期内保持不变。 原生模式不能与 interface="original" 合用。
设置图优先级
通过 config 传入后端配置。 框架在加载时复制配置,不修改调用方对象。
from aidlite import AutoModel, Config
config = Config.create_instance()
if config is None:
raise RuntimeError("Cannot create AidLite config")
config.graph_priority = "high"
with AutoModel.from_pretrained("model.qnn248.ctx.bin", config=config) as model:
print(model.inputs)graph_priority 默认为空字符串,保留后端默认优先级。 QNN DSP 支持 low、normal_low、normal、normal_high、high、high_plus、critical 和 critical_plus。 QNN 2.40 只提供四档原生优先级。 该版本将 normal_low 映射为 low。 high_plus、critical 和 critical_plus 映射为 high。 QNN 2.48 使用对应的原生档位。 优先级是否生效取决于后端和设备支持。 加载后修改原 config 不会改变已加载的模型。
控制 Python 并发
release_gil 默认为 False。 默认调用保留原来的 Python 调度行为。 在 AutoModel.from_pretrained() 或 InferenceSession() 中设置 release_gil=True,可在原生推理期间允许其他 Python 线程运行。 该选项需要配套的新版本原生扩展和拥有完整生命周期的会话。 旧版借用 Model/Context 的适配器不支持此选项。
每个工作线程使用独立会话。 同一个会话仍按顺序调用。 推理期间不要修改输入,不要切换图,也不要关闭会话。 AutoModel 会按顺序执行同一模型的调用。 InferenceSession 在原生推理期间拒绝同一会话的其他原生操作。
先测量实际工作负载,再启用此选项。 短 CPU 模型可能因线程竞争而变慢。 释放 GIL 不保证同一 NPU 上的请求可以并行执行。 按设备和工作负载设置 config.number_of_threads。 多个会话同时使用大量 CPU 线程可能增加延迟。
查看量化参数
TensorSpec.dtype 是调用接口要求的数据类型。 TensorSpec.native_dtype 是后端报告的物理数据类型。 两者可以不同。 例如,普通 QNN 接口可使用浮点数组,而物理张量使用 uint8。
from aidlite import AutoModel
with AutoModel.from_pretrained("model.qnn248.ctx.bin") as model:
for spec in model.inputs + model.outputs:
print(spec.name, spec.dtype, spec.native_dtype)
print(spec.quantization, spec.quantize_scale, spec.quantize_offset)可用的 QNN 逐张量参数通过 spec.quantization 返回。 参数对象提供 scale、zero_point、dtype 和 offset。 offset 使用 QNN 约定:zero_point = -offset。 spec.quantize_scale 和 spec.quantize_offset 提供相同参数的快捷读取方式。 参数来自已加载模型的后端张量信息。 AIMO 元数据继续提供原接口映射和经核对的形状。 缺失、无效或已知不支持的量化编码返回 None。 不要将 None 当成缩放值 1 或零点 0。 当前标量参数对象不表示逐通道、分块或压缩低位宽编码。 旧后端 API 不能报告完整编码类型时,调用方仍需核对模型的量化方式。 其他后端的量化约定未确认时,也返回 None。
手动量化和反量化
quantize() 和 dequantize() 是可选工具。 它们不会被 model(inputs) 自动调用。 默认原接口的数据类型规则不变。
以下示例要求一个输入、一个输出的逐张量量化 QNN 模型。 输入文件必须使用后端要求的维度排列。
import numpy as np
from aidlite import AutoModel, quantize, dequantize
inputs = np.load("input-runtime-layout.npy", allow_pickle=False)
with AutoModel.from_pretrained(
"model.qnn248.ctx.bin", native_input=True, native_output=True,
) as model:
input_params = model.inputs[0].quantization
output_params = model.outputs[0].quantization
if input_params is None or output_params is None:
raise ValueError("This model needs explicit supported quantization parameters")
quantized = quantize(inputs, input_params)
result = model.predict(quantized, copy=False)
restored = dequantize(result, output_params, dtype=inputs.dtype)quantize() 计算 round_to_even(x / scale) + zero_point,然后截断到整数类型范围。 dequantize() 计算 (q - zero_point) * scale。 QNN offset 与 zero point 符号相反。 不要直接把 QNN offset 作为 zero_point 传入。 工具不重排维度,不推断量化参数,也不恢复量化损失的精度。 整数类型支持原生字节序的 int8、uint8、int16、uint16、int32 和 uint32。 缩放值必须为正且有限。 非有限输入、无效零点、参数冲突和不匹配的数据类型会报错。 反量化默认返回 float32;可显式选择 float16 或 float64。 这个默认值只属于工具函数,不改变原模型的接口类型。
已知参数时,也可以直接传入数值。
import numpy as np
from aidlite import QuantizationParams, quantize, dequantize
params = QuantizationParams(scale=0.5, zero_point=10, dtype=np.uint8)
quantized = quantize(np.array([1.0], dtype=np.float16), params)
restored = dequantize(quantized, params, dtype=np.float16)
assert quantized[0] == 12
assert restored[0] == 1.0
same = quantize([1.0], scale=0.5, zero_point=10, dtype=np.uint8)使用参数对象时,不要同时传入 scale、zero_point 或量化目标 dtype。 多输入和多输出模型应分别使用每个张量自己的参数。 普通 QNN 或 SNPE 输入输出已由后端转换时,不要再手动量化或反量化。
借用后端输出视图
默认 copy=True,输出独立于后续推理和模型关闭。 需要减少输出复制时,显式使用 predict(copy=False)。
import numpy as np
from aidlite import AutoModel
inputs = np.load("input-runtime-layout.npy", allow_pickle=False)
with AutoModel.from_pretrained("model.onnx", interface="runtime") as model:
view = model.predict(inputs, copy=False)
saved = view.copy()借用结果是只读 NumPy 视图。 框架不会复制该输出的数据。 后端本身仍可能复制或转换数据。 布局置换可以返回不连续的视图。 需要转换输出数据类型时,copy=False 会在推理前报错。 此时使用默认复制,或显式选择满足所需数据类型的内部接口。 copy=False 不能与 out 或 return_tensors="pt" 合用。 输出选择和 return_dict=True 仍可使用。
保持模型存活,并在下一次调用或关闭模型前处理完视图。 下一次调用可能覆盖或重新分配后端输出内存。 关闭模型后,不要访问借用的数组。 其他线程也不能在视图使用期间调用或关闭同一个模型。 需要保留结果时,在有效期内调用 view.copy()。
使用 QNN 2.40 和 2.48 后端
以下行为需要包含原生张量修复的 QNN 2.40 或 2.48 插件。 源码合并不代表安装包已经发布。 QNN 2.40 和 2.48 使用相同的高层调用方式。 示例使用 QNN 2.48 模型。 使用 QNN 2.40 时,选择为该版本转换的模型。 例如,加载 model.qnn240.ctx.bin。 模型必须与插件和运行库版本匹配。 升级时,请确认插件包含本节所述修复。
import numpy as np
from aidlite import AutoModel, Config
config = Config.create_instance()
if config is None:
raise RuntimeError("Cannot create AidLite config")
config.qnn_shared_buffer = True
with AutoModel.from_pretrained(
"model.qnn248.ctx.bin", device="npu", config=config,
) as model:
inputs = np.load("input.npy", allow_pickle=False)
result = model(inputs)先确认模型输入要求,再准备 input.npy。 有效的 AIMO 元数据仍决定原模型的数据类型和布局。 本节不要求所有原模型都使用 FP32。
qnn_shared_buffer=True 使用插件持有的 RPC 共享缓冲区。 它不表示任意 NumPy 数组都能直接注册为 NPU 内存。 输入仍可能需要复制、量化或布局转换。 不要把共享缓冲区等同于端到端零复制。
使用 native_input=True 和 native_output=True,可以传递内部数据。 数据类型必须与 native_dtype 一致。 FP16、布尔、整数及定点数据按实际字节数传递。 原生输出直接借用后端缓冲区。 普通 FP32 输出的转换缓冲区按需分配,并在后续调用中复用。 标量量化转换要求有效的 scale/offset 参数。 其他编码应使用原生模式,并由调用方执行对应转换。
量化标量输入按一个元素处理。 转换失败时,调用会报告错误。 普通输入转换复用张量尺寸检查结果。 它不再为维度列表分配临时存储。 量化算法和舍入方式保持不变。
如果加载 .so 模型或 QNN 2.48 的 .dlc 模型失败,请查看后端日志。 QNN model buffer must contain data 表示模型数据为空。 Create QNN model 或 Write QNN model file 表示内部模型文件准备失败。 重试前,先检查消息中的系统错误。 模型对象拥有内部模型文件。 释放模型对象时,也会释放该文件;初始化失败后同样适用。
如需使用可选的后端扩展,请在加载模型前设置其 JSON 路径:
config.backend_extension_config = "/absolute/path/backend-config.json"调用 AutoModel.from_pretrained 时,传入 config=config。 扩展库和 JSON 设置必须与 QNN SDK 版本一致。 普通 JSON 配置不需要 DLC 资源管理器。 加载失败时,请查看后端日志中的库、接口或配置错误。 构造失败或关闭模型时,SDK 会释放扩展对象和库。
多图模型使用 graph 选择运行的图。 例如,graph=1, interface="runtime" 选择第二个图。 一次调用只执行所选图。 推理失败后,不要读取上一次的输出。 先修复错误,再重新执行推理。
关闭失败时,保留模型及其输入缓冲区。 检查错误日志并处理运行库错误。 然后重试 model.close()。 成功释放的电源配置不会再次释放。 关闭完成前,不要继续推理。
如果单独设置运行库路径,请保留配套的 DSP 文件路径。 AIDLUX_QNN_LIB_DIR_PATH 指定运行库目录。 ADSP_LIBRARY_PATH 可指定额外的 DSP 搜索目录。 使用同一版本的运行库、stub 和 skel。 一个进程内不要混用多个 QNN 运行时版本。
可选的 QNN 2.48 内存绑定
维护中的 QNN 2.48 后端提供 QNN_BIND_MEM_HANDLES 构建选项。 默认关闭。只有包含此选项的配套构建才会检查绑定能力。 启用 config.qnn_shared_buffer 后,后端仍需报告支持该能力。 不支持时,继续使用普通共享缓冲区路径。 此选项不改变 AutoModel 或 model(x) 的调用方式。 它不等同于任意输入数组的零复制。
启用绑定后,每个图分别持有绑定信息。 加载模型时建立绑定。推理时不重复建立绑定。 销毁模型时,先解除绑定,再释放该图的内存。 如果销毁失败,保留模型对象。解决原因后重试 close()。 C++ SDK 使用 destroy()。 清理完成前,不要继续推理或替换模型。
当前 QCS8550 测试环境中的 QNN 2.48 运行库不支持该能力。 真实 NPU 测试验证了正常回退路径。 绑定和故障处理已通过主机受控测试;尚未在支持绑定的 NPU 上验证。 按实际模型测量延迟。不要假定启用此选项一定更快。 构建步骤和验证工具见 QNN 构建指南。
选择其他后端
创建模型时,SDK 向当前核心查询本地后端支持情况。 导入 Python 包时,不扫描系统中的后端插件。 模型格式规则由 Python 和核心共用。 自动识别采用当前原生核心提供的格式提示。 文件名只提供提示。 参数或 aidlite.json 中的显式 framework 优先于文件名。 .dlc 默认选择通用 QNN,不再默认选择 SNPE2。 显式 framework 或有效 AIMO 元数据可指定后端。 未明确选择具体版本时,.qnn248.dlc 等文件名可提供版本提示。 .tnnmodel、.mnn、.nb 和 .ms 可以识别格式。 识别格式不代表当前核心已实现对应后端。 当前维护的核心使用 QNN 2.40 和 QNN 2.48。 它已停用 QNN 2.36 及更早版本,也已停用 SNPE 后端。 相关枚举和旧示例保留用于迁移旧项目。 .rknn 文件选择 RKNN,默认设备为 NPU。 对 QNN 和 SNPE,device="npu" 映射到 DSP。 其他后端保留 NPU 选择。 后端要求独立权重文件时,使用 model_weight_path。
区分模型声明与运行支持
aidlite.json 中的 framework 声明模型所属后端。 SDK 只检查此字段的字符串类型和标识符语法。 名称按小写处理,并且只能包含字母、数字和下划线,以字母开头。 例如,未来的后端名可以保存在模型资产中。 这不表示当前 SDK 可以运行该后端。 即使文件名以 .onnx 结尾,也先保留显式后端声明。 实际运行仍由核心和插件验证。
显式参数、aidlite.json 和真实 AIMO 元数据中的后端声明必须一致。 它们之间的冲突仍会报错。
通用 qnn 声明可以细化为 qnn248 等具体版本。 例如,配套元数据声明 qnn 时,可以指定 framework="qnn248"。 这些声明中的两个具体版本必须一致。 例如,AIMO 元数据中的 qnn240 与显式 qnn248 冲突时,SDK 会报错。 元数据回退不会忽略真实的框架冲突。
需要检查当前核心的派发能力时,使用配套新版 SDK 的查询接口:
import aidlite
framework = aidlite.infer_framework_type("model.dlc")
backend = aidlite.get_local_backend_key(framework)
print(framework, backend)infer_framework_type() 只根据文件名推导类型。 它不读取模型,也不检查插件文件。 无法识别格式时,返回 FrameworkType.TYPE_DEFAULT。 get_local_backend_key() 返回当前核心实现的本地后端键;未实现时返回 None。 通用 QNN 返回 "qnn",具体版本在模型创建时选择。 非空结果不表示插件已安装、依赖可加载或设备兼容。 实际加载仍需匹配的插件、SDK 和设备。
模型创建错误分为以下情况:
| 情况 | 处理方法 |
|---|---|
| 当前原生绑定不认识后端名 | 核对名称,并使用配套的核心和 Python 绑定。不要仅因当前安装包较旧而改写正确的模型声明。 |
| 核心没有实现该本地后端 | 选择当前支持的后端,或重新转换模型。保留枚举不会启用已停用的后端。 |
| 插件加载、依赖或版本校验失败 | 根据初始化错误中的后端路径和原因,检查插件及其依赖和版本。 |
get_last_backend_error() 可读取当前线程最近一次初始化的后端错误。 下一次 init() 会清空该信息。 在需要手动检查低层返回码时,立即读取此信息。
检查元数据回退
有效的 AIMO 元数据优先提供输入输出形状。 加载时,框架通过后端张量 API 核对一次。 这项检查用于保护本地代码使用的缓冲区尺寸。 推理时复用已验证的处理计划。 无法使用时,自动模式查询 get_input_tensor_info() 和 get_output_tensor_info()。 后端信息描述转换后的模型。 它不能重建缺失的原模型名称、布局或数据类型。 使用 interface="original",可以要求严格原接口并禁止回退。 后端查询或模型加载失败时仍会报错。 SDK 错误会提供可用的操作、状态信息和建议检查项。
REMOTE 模式排查
本节适用于通过进程间通信(IPC)调用 Android 服务的模式。 检查 Android 服务支持的后端版本、输入数量和数据类型。 原生后端与 REMOTE 模式的支持范围可能不同。
检查服务和后端版本
先确认 Android 推理服务正常运行。 再确认模型与该服务的 QNN SDK 版本兼容。 单独更新 Linux 侧 AidLite,不会更新 Android 侧 QNN 后端。 模型需要较新的 QNN SDK 时,请更新配套服务或重新转换模型。
自定义 Android 服务的共享内存
自行构建 Android 推理服务时,请使用配套的 AidLuxIPC Java 类和 Java 本地接口(JNI)库。 包含此修复的构建支持用 Java try-with-resources 释放共享内存对象。 已有 destroy_ashmem() 调用也可继续使用。 关闭对象前,先结束使用其借用文件描述符的操作。 参见 Java 资源管理和数组边界说明。
包含区间写入优化的 JNI 构建只复制请求的输入区间。 可继续复用较大的 Java 输入数组。 字节写入和对齐的浮点写入使用一次区间复制。 未对齐的浮点字节偏移仍可使用原有兼容路径。 复制出错时,保留异常,不切换路径重试。 出错前已写入的数据不会自动还原。 用实际模型测量延迟;区间写入优化不保证整次推理更快。
Python 调用者继续用 with 管理 AutoModel 或 InferenceSession。 这会释放会话;无需手动管理 Android 共享内存。
检查服务崩溃日志
推理超时也可能由 Android 服务崩溃引起。 先连接测试设备的 Android 调试桥(ADB)。 用 adb devices 确认设备序列号。 将 DEVICE_SERIAL 替换为该序列号。
adb -s DEVICE_SERIAL logcat -d -b crash检查日志中的进程名和错误信息。 如果同时出现 ai.onnxruntime 和 JNI DETECTED ERROR,请提供完整日志。 如果还出现 mid == null,请由设备维护人员检查 ONNX 发布包配置。 该问题可能需要重新构建并发布 Android 服务。 服务更新后,重新检查正常推理和错误返回。
低层接口参考
以下接口用于手动管理模型、配置和解释器。 其中的数据类型规则由所选后端接口决定。 这些规则与 AutoModel 的原接口适配不同。
模型数据类型 class DataType
对于 AidliteSDK 而言,会用来处理不同框架的不同模型,每个模型也会有不同的输入数据类型和不同的输出数据类型。调用某些接口时,需要设置模型的输入输出数据类型,就需要用到此数据类型的枚举。
| 成员变量名 | 类型 | 值 | 描述 |
|---|---|---|---|
| TYPE_DEFAULT | int | 0 | 无效数据类型 |
| TYPE_UINT8 | int | 1 | Unsigned char 数据 |
| TYPE_INT8 | int | 2 | Char 数据 |
| TYPE_UINT32 | int | 3 | Unsigned int32 数据 |
| TYPE_FLOAT32 | int | 4 | float 数据 |
| TYPE_INT32 | int | 5 | int32 数据 |
| TYPE_INT64 | int | 6 | int64 数据 |
| TYPE_UINT64 | int | 7 | Unsigned int64 数据 |
| TYPE_INT16 | int | 8 | Int16 数据 |
| TYPE_UINT16 | int | 9 | Unsigned int16 数据 |
| TYPE_FLOAT16 | int | 10 | Float16 数据 |
| TYPE_BOOL | int | 11 | Bool 数据 |
推理实现类型 class ImplementType
| 成员变量名 | 类型 | 值 | 描述 |
|---|---|---|---|
| TYPE_DEFAULT | int | 0 | 无效 ImplementType 类型 |
| TYPE_MMKV | int | 1 | C++ 接口中保留该枚举;当前 Python 绑定未导出,不能直接使用 |
| TYPE_REMOTE | int | 2 | 远程推理实现 |
| TYPE_FAST | int | 2 | TYPE_REMOTE 的兼容别名,已废弃,不建议继续使用 |
| TYPE_LOCAL | int | 3 | 本地推理实现 |
💡注意
特别说明:
TYPE_LOCAL 与 TYPE_REMOTE 的区别在于:对于 Aplux 融合系统而言,前者的推理实现过程是在 Linux 环境本地完成的,无需数据的传输。而后者则是通过 IPC(进程间通信)的方式与 Android 环境实现数据交互,推理实现过程在 Android 环境完成的,故而会涉及到数据的传输。综上所述,TYPE_LOCAL 方式是用来完成推理过程的优选项。
模型框架类型 class FrameworkType
由于 AidliteSDK 整合了多种深度学习推理框架,所以在使用过程中,需要设置当前使用哪个框架的模型,就需要设置所需推理框架的类型枚举。
| 成员变量名 | 类型 | 值 | 描述 |
|---|---|---|---|
| TYPE_DEFAULT | int | 0 | 无效 FrameworkType 类型 |
| TYPE_SNPE | int | 1 | SNPE 1.x (DLC) 模型 |
| TYPE_TFLITE | int | 2 | TFLite 模型 |
| TYPE_RKNN | int | 3 | RKNN 模型 |
| TYPE_QNN | int | 4 | QNN 模型 |
| TYPE_SNPE2 | int | 5 | SNPE 2.x (DLC) 模型 |
| TYPE_NCNN | int | 6 | NCNN 模型 |
| TYPE_MNN | int | 7 | MNN 模型 |
| TYPE_TNN | int | 8 | TNN 模型 |
| TYPE_PADDLE | int | 9 | Paddle 模型 |
| TYPE_MS | int | 10 | MindSpore 模型 |
| TYPE_ONNX | int | 11 | onnx 模型 |
| TYPE_QNN216 | int | 101 | QNN2.16 模型 |
| TYPE_SNPE216 | int | 102 | SNPE2.16 模型 |
| TYPE_QNN223 | int | 103 | QNN2.23 模型 |
| TYPE_SNPE223 | int | 104 | SNPE2.23 模型 |
| TYPE_QNN229 | int | 105 | QNN2.29 模型 |
| TYPE_SNPE229 | int | 106 | SNPE2.29 模型 |
| TYPE_QNN231 | int | 107 | QNN2.31 模型 |
| TYPE_QNN236 | int | 108 | QNN2.36 模型 |
| TYPE_QNN240 | int | 109 | QNN2.40 模型 |
| TYPE_QNN248 | int | 110 | QNN2.48 模型 |
💡注意
特别说明:
- 枚举保留历史值,不表示当前核心实现全部列出的后端。使用
get_local_backend_key()查询本地派发支持情况。 TYPE_QNN在当前核心实现的具体 QNN 后端中,优先选择版本较新的已安装插件。当前维护版本为 QNN 2.40 和 QNN 2.48。旧 QNN 和 SNPE 后端仍已停用。- 一个进程内不要混用多个 QNN 运行时版本。
推理加速硬件类型 class AccelerateType
对于每个深度学习推理框架而言,可能会支持运行在不同的加速设备上(如 SNPE/QNN 模型运行在 DSP 设备,RKNN 模型运行在 NPU 设备),所以在使用过程中,需要设置当前模型期望运行在哪个设备,就需要使用此加速硬件枚举。
| 成员变量名 | 类型 | 值 | 描述 |
|---|---|---|---|
| TYPE_DEFAULT | int | 0 | 无效 AccelerateType 类型 |
| TYPE_CPU | int | 1 | CPU 加速运行 |
| TYPE_GPU | int | 2 | GPU 加速运行 |
| TYPE_DSP | int | 3 | DSP 加速运行 |
| TYPE_NPU | int | 4 | NPU 加速运行 |
日志级别 class LogLevel
AidliteSDK 提供有设置日志相关信息的接口(后续会介绍),如果需要指定 AidliteSDK 当前使用哪个日志级别,就需要使用此日志级别枚举。
| 成员变量名 | 类型 | 值 | 描述 |
|---|---|---|---|
| INFO | int | 0 | 消息 |
| WARNING | int | 1 | 警告 |
| ERROR | int | 2 | 错误 |
| FATAL | int | 3 | 致命错误 |
设备信息类.class DeviceInfo
从 2.3.1 开始,Python 绑定也提供了 DeviceInfo 类型,用于描述底层可用推理设备的信息,目前主要用于 QNN DSP 场景下的设备查询与自定义设备配置。
成员变量列表
| 成员变量名 | 类型 | 默认值 | 描述 |
|---|---|---|---|
| id | int | 0 | 设备 ID |
| type | int | 0 | 设备类型编号,由后端解释 |
| cores_num | int | 1 | 设备包含的核心数量 |
| cores_id | list | 空 | 设备核心 ID 列表 |
💡注意
C++ 结构体中的 version 字段当前没有在 Python 绑定层导出,Python 侧可直接使用其余四个公开字段。
输入输出信息类.class TensorInfo
每个模型都会有各自的输入输出,对于开发者不那么熟悉的模型而言,开发过程中可能需要查询该模型的输入输出 Tensor 信息,以方便开发者做模型推理的前后处理操作。Aidlite 为开发者提供了查询模型输入输出详细信息的接口,以及用于存储输入输出详细信息的 TensorInfo 数据类型。
成员变量列表
TensorInfo 对象用于存储模型输入输出 Tensor 的详细信息,其中就包含如下的这些参数:
| 成员 | version |
| 类型 | int |
| 默认 | 0X00020205 |
| 描述 | 此成员用于标识 TensorInfo 版本,如果以后需要扩展更多信息时,会更新版本号 |
| 成员 | index |
| 类型 | int |
| 默认 | 无默认值 |
| 描述 | Tensor 的索引值 |
| 成员 | name |
| 类型 | str |
| 默认 | 无默认值 |
| 描述 | Tensor 的名称字符串 |
| 成员 | element_count |
| 类型 | int |
| 默认 | 0 |
| 描述 | Tensor 中数据元素的数量(非字节数量) |
| 成员 | element_type |
| 类型 | enum DataType |
| 默认 | DataType::TYPE_DEFAULT |
| 描述 | Tensor 中数据元素的类型 |
| 成员 | dimensions |
| 类型 | int |
| 默认 | 0 |
| 描述 | Tensor 中数据元素的维度值 |
| 成员 | shape |
| 类型 | list[int] |
| 默认 | 无默认值 |
| 描述 | Tensor 中数据元素的 shape 描述 |
模型类 class Model
在创建推理解释器之前,需要设置具体模型的相关详细参数。Model 类主要用于记录模型的文件信息、结构信息、运行过程中模型相关内容。
创建空实例对象 create_instance()
当前 Python 绑定也提供了无参重载,可先创建一个空的 Model 实例,再由调用方在后续流程中补充模型路径或属性信息。
| API | create_instance |
| 描述 | 构造一个不携带模型文件路径的 Model 实例对象 |
| 参数 | 无 |
| 返回 | 正常:Model 实例对象 |
| 异常:None |
创建实例对象 create_instance()
想要设置模型相关的详细信息,当然就需要先有模型实例对象,此函数用于创建 Model 实例对象。如果模型框架(如 snpe、tflite 等)只需一个模型文件,则调用此接口。
| API | create_instance |
| 描述 | 通过传递模型文件的路径名称,构造 Model 类型的实例对象 |
| 参数 | model_path:模型文件的路径名称 |
| 返回 | 正常:Model 实例对象 |
| 异常:None |
# 使用当前路径下 inceptionv3_float32.dlc 文件创建模型对象,返回值为空则报错
model = aidlite.Model.create_instance(model_path=r"./inceptionv3.dlc")
if model is None:
print("Create model failed.")
return False创建实例对象 create_instance()
想要设置模型相关的详细信息,当然就需要先有模型实例对象,此函数用于创建 Model 实例对象。如果模型框架(如 ncnn、tnn 等)涉及两个模型文件,则调用此接口。
| API | create_instance |
| 描述 | 通过传递模型文件的路径名称,构造 Model 类型的实例对象 |
| 参数 | model_struct_path:模型结构文件的路径名称 |
| model_weight_path:模型权重参数文件的路径名称 | |
| 返回 | 正常:Model 实例对象;异常:None |
# 使用当前路径下 ncnn 的两个模型文件创建模型对象,返回值为空则报错
model = aidlite.Model.create_instance(
model_struct_path=r"./mobilenet_ssd_voc_ncnn.param",
model_weight_path=r"./mobilenet_ssd_voc_ncnn.bin")
if model is None:
print("Create model failed.")
return False设置模型属性 set_model_properties()
模型实例对象创建成功之后,需要设置模型的输入输出数据类型和输入输出 tensor 数据的 shape 信息。
| API | set_model_properties |
| 描述 | 设置模型的属性,设置模型的输入/输出数据 shape 和数据类型。 |
| 参数 | input_shapes:输入 tensor 的 shape 数组,二维数组结构。 |
| input_data_type:输入 tensor 的数据类型,DataType 枚举类型。 | |
| output_shapes:输出 tensor 的 shape 数组,二维数组结构。 | |
| output_data_type:输出 tensor 的数据类型,DataType 枚举类型。 | |
| 返回 | 正常:0;异常:非 0 |
| 注意 | 使用 REMOTE 时,按后端要求设置输入输出信息。 QNN 和 SNPE 的普通低层接口默认使用 aidlite.DataType.TYPE_FLOAT32。 原生数据模式以张量信息和当前 REMOTE 服务的支持范围为准。 其他后端按所用接口声明的数据类型准备数组。 |
# 数据类型使用前述 DataType,输入输出 shape 是二维数组
input_shapes=[[1,640,640,3]]
output_shapes=[[1,10,10,255], [1,20,20,255], [1,40,40,255]]
model.set_model_properties( input_shapes=input_shapes,
input_data_type=aidlite.DataType.TYPE_FLOAT32,
output_shapes=output_shapes,
output_data_type=aidlite.DataType.TYPE_FLOAT32)获取模型路径 get_model_absolute_path()
如果模型框架(如 SNPE、TFLite 等)只涉及一个模型文件,在构建 Model 对象没有异常的情况下,会将传入的模型文件参数转换为绝对路径形式的文件路径。
| API | get_model_absolute_path |
| 描述 | 用于获取模型文件的绝对路径 |
| 参数 | 无 |
| 返回 | Model 对象所对应的模型文件路径字符串 |
获取模型路径 get_model_struct_absolute_path()
如果模型框架(如 NCNN、TNN 等)涉及两个模型文件,在构建 Model 对象没有异常的情况下,会将传入的模型结构文件参数转换为绝对路径形式的文件路径。
| API | get_model_struct_absolute_path |
| 描述 | 用于获取模型结构文件的绝对路径 |
| 参数 | 无 |
| 返回 | Model 对象所对应的模型结构文件路径字符串 |
获取模型路径 get_model_weight_absolute_path()
如果模型框架(如 NCNN、TNN 等)涉及两个模型文件,在构建 Model 对象没有异常的情况下,会将传入的模型权重参数文件参数转换为绝对路径形式的文件路径。
| API | get_model_weight_absolute_path |
| 描述 | 用于获取模型权重参数文件的绝对路径 |
| 参数 | 无 |
| 返回 | Model 对象所对应的模型权重参数文件路径字符串 |
配置类 class Config
在创建推理解释器之前,除了需要设置 Model 具体信息之外,还需要设置一些推理时的配置信息。Config 类用于记录需要预先设置的配置选项,这些配置项在运行时会被用到。
创建实例对象 create_instance()
想要设置运行时的配置信息,当然就需要先有配置实例对象,此函数用于创建 Config 实例对象。
| API | create_instance |
| 描述 | 用于构造 Config 类的实例对象 |
| 参数 | 无 |
| 返回 | 正常:Config 实例对象 |
| 异常:None |
# 创建配置实例对象,返回值为 None 则报错
config = aidlite.Config.create_instance()
if config is None:
print("Create config failed.")
return False成员变量列表
Config 对象用于设置运行时的配置信息,其中就包含如下的这些参数:
| 成员 | accelerate_type |
| 类型 | class AccelerateType |
| 默认 | AccelerateType.TYPE_CPU |
| 描述 | 加速硬件的类型 |
| 成员 | implement_type |
| 类型 | class ImplementType |
| 默认 | ImplementType.TYPE_DEFAULT |
| 描述 | 用于区分后端实现推理功能的不同环境 |
| 注意 | 开发者可以不用显式设置此配置项, AidliteSDK 会根据当前的系统环境、模型框架等因素,适配得出更优的 ImplementType 类型 |
| 成员 | framework_type |
| 类型 | class FrameworkType |
| 默认 | FrameworkType.TYPE_DEFAULT |
| 描述 | 底层推理框架的类型 |
| 成员 | number_of_threads |
| 类型 | int |
| 默认 | -1 |
| 描述 | 线程数,大于 0 有效 |
| 注意 | 当且仅当 framework_type 为 TFLITE 时,可以选择性设置此配置项 |
| 成员 | snpe_out_names |
| 类型 | list |
| 默认 | 无 |
| 描述 | 模型输出节点的名称列表 |
| 注意 | 当且仅当 framework_type 为 SNPE 时,需要设置此配置项 |
| 成员 | is_quantify_model |
| 类型 | int |
| 默认 | 0 |
| 描述 | 是否为量化模型,1 表示量化模型 |
| 注意 | 当且仅当 implement_type 为 REMOTE 时,需要设置此配置项 |
| 成员 | remote_timeout |
| 类型 | int |
| 默认 | -1 |
| 描述 | 接口超时时间(毫秒,大于 0 有效) |
| 注意 | 当且仅当 implement_type 为 REMOTE 时,可以选择性设置此配置项 |
| 成员 | fast_timeout |
| 类型 | int |
| 默认 | -1 |
| 描述 | `remote_timeout` 的历史兼容字段;当前 Python 绑定仍可访问,但不建议继续使用 |
| 成员 | qnn_shared_buffer |
| 类型 | int |
| 默认 | 0 |
| 描述 | 是否启用 QNN shared buffer,目前主要用于 QNN DSP 场景 |
| 成员 | batch_invoke_size |
| 类型 | int |
| 默认 | 1 |
| 描述 | 后端 batch 推理配置参数,目前主要用于 QNN DSP 场景 |
| 成员 | backend_extension_config |
| 类型 | str |
| 默认 | 空字符串 |
| 描述 | 后端推理框架扩展配置文件,目前主要用于 QNN DSP 场景 |
| 成员 | custom_device_info |
| 类型 | list[DeviceInfo] |
| 默认 | 空 |
| 描述 | 自定义设备信息列表,用于指定后端实际使用的设备集合 |
| 成员 | reserved1 |
| 类型 | int |
| 默认 | 0 |
| 描述 | 预留字段,当前无业务语义,调用方无需主动设置 |
💡注意
remote_timeout 与 fast_timeout 对应同一组超时配置;其中 fast_timeout 仅为历史兼容字段,新代码应统一使用 remote_timeout。
config.framework_type = aidlite.FrameworkType.TYPE_QNN
config.accelerate_type = aidlite.AccelerateType.TYPE_DSP
# 按需设置其他配置项
# ... ...上下文类 class Context
用于存储执行过程中所涉及的运行时上下文,就包括 Model 对象和 Config 对象,后续可能会扩展运行时的上下文数据。
构造函数 Context()
| API | Context |
| 描述 | 构造 Context 实例对象 |
| 参数 | model:Model 实例对象 |
| config:Config 实例对象 | |
| 返回 | 正常:Context 实例对象 |
| 异常:None |
context = aidlite.Context(model=model, config=config)获取 Model 成员变量 get_model()
| API | get_model |
| 描述 | 获取 context 管理的 Model 对象 |
| 参数 | 无 |
| 返回 | Model 对象 |
model = context.get_model()获取 Config 成员变量 get_config()
| API | get_config |
| 描述 | 获取 context 管理的 Config 对象 |
| 参数 | 无 |
| 返回 | Config 对象 |
config = context.get_config()解释器类 class Interpreter
Interpreter 类型的对象实例是执行推理操作的主体,用于执行具体的推理过程。创建解释器对象之后,所有的操作都是基于解释器对象来完成的,所以它是 AidliteSDK 绝对的核心内容。
创建实例对象 create_instance
想要执行推理相关的操作,推理解释器肯定必不可少,此函数就用于构建推理解释器的实例对象。
| API | create_instance |
| 描述 | 利用 Context 对象所管理的各种数据,构造 Interpreter 类型的对象 |
| 参数 | context:Context 实例对象 |
| 返回 | 正常:Interpreter 实例对象 |
| 异常:None |
# 创建解释器对象,返回值为 None 则报错
interpreter = aidlite.Interpreter.create_instance(context=context)
if interpreter is None:
print("Create Interpreter failed.")
return False初始化 init()
解释器对象创建之后,需要执行一些初始化操作(比如环境检查、资源构建等)。
| API | init |
| 描述 | 完成推理所需的相关的初始化工作 |
| 参数 | 无 |
| 返回 | 正常:0 |
| 异常:非 0 |
# 解释器初始化,返回值非0则报错
result = interpreter.init()
if result != 0:
print("sample : interpreter.init() failed.")
return False获取设备信息 get_device_info()
当前 Python 绑定新增了 get_device_info(),用于查询后端实际可见的设备信息。该接口从 2.3.1 起支持,目前主要用于 QNN DSP 场景。
| API | get_device_info |
| 描述 | 获取后端设备详情列表 |
| 返回 | 正常:DeviceInfo 对象列表 |
| 异常:抛出异常 |
device_info_list = interpreter.get_device_info()
for device in device_info_list:
print(device.id, device.type, device.cores_num, device.cores_id)加载模型 load_model()
解释器对象完成初始化操作之后,就可以为解释器加载所需的模型文件,完成模型加载工作。后续的推理过程就使用加载的模型资源。
| API | load_model |
| 描述 | 完成模型加载相关的工作。 因为前述在 Model 对象中已经设置模型文件的路径,所以直接执行模型加载操作即可 |
| 参数 | 无 |
| 返回 | 正常:0 |
| 异常:非 0 |
# 解释器加载模型,返回值非 0 则报错
result = interpreter.load_model()
if result != 0:
print("sample : interpreter.load_model() failed.")
return False获取输入Tensor详情 get_input_tensor_info()
如果想要获取模型的输入 Tensor 的详细信息,可以使用此接口获取。
| API | get_input_tensor_info |
| 描述 | 获取模型中输入 Tensor 的详细信息 |
| 返回 | 正常:TensorInfo 类型数据的二维数组 |
| 异常:None | |
| 说明 | 此接口从 AidliteSDK 版本号 2.2.5 开始支持 |
# 获取模型的输入 Tensor 详细信息
input_tensor_info = aidlite_interpreter.get_input_tensor_info()
if len(input_tensor_info) == 0 :
print("interpreter get_input_tensor_info() failed.")
return False
for gi, graph_tensor_info in enumerate(input_tensor_info):
for ti, tensor_info in enumerate(graph_tensor_info):
print( f"Input tensor : Graph[{gi}]-Tensor[{ti}]-name[{tensor_info.name}]"
f"-element_count[{tensor_info.element_count}]-element_type[{tensor_info.element_type}]"
f"-dimensions[{tensor_info.dimensions}]-shape{tensor_info.shape}")获取输出Tensor详情 get_output_tensor_info()
如果想要获取模型的输出 Tensor 的详细信息,可以使用此接口获取。
| API | get_output_tensor_info |
| 描述 | 获取模型中输出 Tensor 的详细信息 |
| 返回 | 正常:TensorInfo 类型数据的二维数组 |
| 异常:None | |
| 说明 | 此接口从 AidliteSDK 版本号 2.2.5 开始支持 |
# 获取模型的输出 Tensor 详细信息
output_tensor_info = aidlite_interpreter.get_output_tensor_info()
if len(output_tensor_info) == 0 :
print("interpreter get_output_tensor_info() failed.")
return False
for gi, graph_tensor_info in enumerate(output_tensor_info):
for ti, tensor_info in enumerate(graph_tensor_info):
print( f"Output tensor : Graph[{gi}]-Tensor[{ti}]-name[{tensor_info.name}]"
f"-element_count[{tensor_info.element_count}]-element_type[{tensor_info.element_type}]"
f"-dimensions[{tensor_info.dimensions}]-shape{tensor_info.shape}")设置输入数据 set_input_tensor()
执行推理操作之前,需要传入模型所需的输入 Tensor 数据。设置输入数据之前,对于不同的模型,需要完成不同的前处理操作以适配具体模型。
| API | set_input_tensor |
| 描述 | 设置推理所需的输入 tensor 的数据 |
| 参数 | in_tensor_tag:输入 tensor 的索引值或者名称字符串,类型为 int 或者 str |
| input_data:支持 buffer protocol 的输入数据,如 numpy.ndarray、memoryview 或 bytes | |
| 可选参数 | is_native:是否将传入数据视为原生后端数据格式;为 `false` 时按 SDK 默认逻辑处理量化/反量化,为 `true` 时直接按原始格式传入;默认值为 False |
| 返回 | 正常:0 |
| 异常:非 0 | |
| 说明 | 1. 参数 in_tensor_tag 从 AidliteSDK 版本号 2.2.5 开始支持 tensor 名字字符串 2. 对于 numpy.ndarray 和 memoryview,要求使用 C 连续内存布局;非连续数组/视图会触发 RuntimeWarning 并自动转化为连续内存副本,可能引起额外的数据拷贝开销 3. 对于 SNPE/QNN 两个推理框架来说,默认输入通常按 float32 处理;若调用原生格式接口,则需要用户自行保证数据格式与后端要求一致。 |
# 设置推理的输入数据,返回值非 0 则报错
result = interpreter.set_input_tensor(in_tensor_tag=1, input_data=obj)
# result = interpreter.set_input_tensor(in_tensor_tag="input_tensor_name", input_data=obj)
# result = interpreter.set_input_tensor(in_tensor_tag=1, input_data=obj, is_native=True)
if result != 0:
print("interpreter->set_input_tensor() failed.")
return False执行推理 invoke()
设置输入数据之后,接下来的步骤自然就是对输入数据执行推理运行过程。
| API | invoke |
| 描述 | 执行推理运算过程 |
| 参数 | 无 |
| 返回 | 正常:0 |
| 异常:非 0 |
# 执行推理运行操作,返回值非 0 则报错
result = interpreter.invoke()
if result != 0:
print("sample : interpreter->invoke() failed.")
return False获取输出数据 get_output_tensor()
推理完成之后,就需要将推理得到的结果数据取出来。之前介绍流程时提到,取出结果数据之后,就可以对这些结果数据进行处理,判断结果是否正确。
| API | get_output_tensor |
| 描述 | 推理成功之后,获取推理结果数据 |
| 参数 | out_tensor_tag:结果输出 tensor 的索引值或者名称字符串,类型为 int 或者 str |
| output_type:结果输出的目标数据类型,可选参数,不传默认为 aidlite.DataType.TYPE_FLOAT32 | |
| 可选参数 | is_native:是否直接按后端原生的数据类型格式返回底层输出字节视图;默认值为 False |
| 返回 | 正常:numpy.ndarray 结果数据。 |
| 异常:None。 | |
| 说明 | 1. 参数 out_tensor_tag 从 AidliteSDK 版本号 2.2.5 开始支持字符串 2. `output_type` 用于将底层 `uint8` 结果按目标数据类型重新解释,不会额外拷贝数据 3. 对于 SNPE/QNN,默认接口通常返回 float32 语义的数据;如果使用原生格式接口,则需要按后端真实输出格式自行解析数据类型。 |
# 获取推理结果数据,返回值为 numpy.ndarray
out_data = interpreter.get_output_tensor(out_tensor_tag=1, output_type=aidlite.DataType.TYPE_INT32)
# out_data = interpreter.get_output_tensor(out_tensor_tag="output_tensor_name", output_type=aidlite.DataType.TYPE_INT32)
# out_data = interpreter.get_output_tensor(out_tensor_tag=1, is_native=True)
if out_data is None:
print("interpreter->get_output_tensor() failed.")
return False资源释放 destroy()
前面提到解释器对象需要执行 init() 初始化操作和 load_model() 加载模型的操作,相应的,解释器也需要执行一些释放操作,将之前创建的资源予以销毁。
| API | destroy |
| 描述 | 完成必要的释放操作 |
| 参数 | 无 |
| 返回 | 正常:0 |
| 异常:非 0 |
# 执行解释器释放过程,返回值非 0 则报错
result = interpreter.destroy()
if result != 0:
print("sample : interpreter-> destroy() failed.")
return False解释器创建类 class InterpreterBuilder
统一的解释器 Interpreter 对象的创建函数,通过此类来创建所需的解释器对象。
构建解释器 build_interpreter_from_path()
构建推理解释器对象,可以提供不同的参数,最简单的就是只提供模型文件的路径和名称。如果模型框架(如 SNPE、TFLite 等)只需一个模型文件,则调用此接口。
| API | build_interpreter_from_path |
| 描述 | 通过模型文件的路径名称,直接创建对应的解释器对象 |
| 参数 | model_path:模型文件的路径名称 |
| 返回 | 正常:Interpreter 对象实例 |
| 异常:None |
# 传入 Model 文件路径来构建解释器,返回值为 None 则报错
interpreter = aidlite.InterpreterBuilder.build_interpreter_from_path(model_path=r"./640.dlc")
if interpreter is None:
print("Create Interpreter failed !")
return False构建解释器 build_interpreter_from_path()
构建推理解释器对象,可以提供不同的参数,最简单的就是只提供模型文件的路径和名称。如果模型框架(如 NCNN、TNN 等)涉及两个模型文件,则调用此接口。
| API | build_interpreter_from_path |
| 描述 | 通过模型文件的路径名称,直接创建对应的解释器对象 |
| 参数 | model_struct_path:模型结构文件的路径名称 |
| model_weight_path:模型权重参数文件的路径名称 | |
| 返回 | 正常:Interpreter 对象实例 |
| 异常:None |
构建解释器 build_interpreter_from_model()
构建推理解释器对象,除了提供模型文件路径之外,也可以提供 Model 对象,这样不仅可以设置模型文件的路径名称,还可以设置模型的输入输出数据类型和输入输出数据的 shape 信息。
| API | build_interpreter_from_model |
| 描述 | 通过传入 Model 对象来创建对应的解释器对象。而 Config 相关涉及的参数都使用默认值 |
| 参数 | model:Model 类型的对象,包含模型相关的数据 |
| 返回 | 正常:Interpreter 对象实例 |
| 异常:None |
# 传入 Model 对象来构建解释器,返回值为 None 则报错
interpreter = aidlite.InterpreterBuilder.build_interpreter_from_model(model=model)
if interpreter is None:
print("Create Interpreter failed !")
return False构建解释器 build_interpreter_from_model_and_config()
构建推理解释器对象,除了前述的两种方式,也可以同时提供 Model 对象和 Config 对象,这样不仅可以提供模型相关信息,还可以提供更多的运行时配置参数。
| API | build_interpreter_from_model_and_config |
| 描述 | 通过传入 Model 对象和 Config 来创建对应的解释器对象。 |
| 参数 | model:Model 类型的对象,包含模型相关的数据 |
| config:Config 类型的对象,包含一些配置参数 | |
| 返回 | 正常:Interpreter 对象实例 |
| 异常:None |
# 传入 Model 和 Config 对象来构建解释器,返回值为 None 则报错
interpreter = aidlite.InterpreterBuilder.build_interpreter_from_model_and_config(model=model, config=config)
if interpreter is None:
print("Create Interpreter failed.")
return False其他方法
获取 SDK 版本信息 get_library_version()
| API | get_library_version |
| 描述 | 用于获取当前 Aidlite-SDK 的版本相关信息 |
| 参数 | 无 |
| 返回 | 返回值为当前 Aidlite-SDK 的版本信息字符串 |
获取 Python SDK 版本信息 get_py_library_version()
| API | get_py_library_version |
| 描述 | 用于获取当前 Py-Aidlite-SDK 的版本相关信息 |
| 参数 | 无 |
| 返回 | 返回值为当前 Py-Aidlite-SDK 的版本信息字符串 |
设置日志级别 set_log_level()
| API | set_log_level |
| 描述 | 设置当前的最低日志级别,输出大于等于该日志级别的日志数据。默认打印输出 WARNING 及以上级别的日志。 |
| 参数 | log_level:类型 LogLevel 的取值 |
| 返回 | 默认返回 0 值 |
日志输出到标准终端 log_to_stderr()
| API | log_to_stderr |
| 描述 | 设置日志信息输出到标准错误终端 |
| 参数 | 无 |
| 返回 | 默认返回 0 值 |
日志输出到文本文件 log_to_file()
| API | log_to_file |
| 描述 | 设置日志信息输出到指定的文本文件 |
| 参数 | path_and_prefix:日志文件的存放路径与名称前缀 |
| also_to_stderr:标识是否同时输出日志到 stderr 终端,默认值为 False | |
| 返回 | 正常:0 |
| 异常:非 0 |
获取最近日志信息 last_log_msg()
| API | last_log_msg |
| 描述 | 获取当前某个日志级别的最新日志信息,通常获取最新的错误信息 |
| 参数 | log_level:类型 LogLevel 的取值 |
| 返回 | 最新日志信息 |
AidLite Python 示例程序
💡注意
使用 Aidlite-SDK 开发需要了解如下事项:
Aidlite 的功能实现分为两个部分,软件包 Aidlite-SDK 是为开发者提供接口的,而不同框架的推理功能则是由不同的后端软件包(如Aidlite-QNN236等)提供。
示例程序由后端推理软件包提供,示例程序随软件包安装,如 Aidlite-QNN236 的示例程序路径如下:
- cpp 示例程序路径:/usr/local/share/aidlite/examples/aidlite_qnn236/cpp/
- Python 示例程序路径:/usr/local/share/aidlite/examples/aidlite_qnn236/python/
以后端程序 Aidlite-QNN236 为例,其 Python 示例程序大致包含如下几个部分:
初始化配置与模型加载
如果开发者对模型推理有所了解,或者是看过 Aidlite API 接口文档,那么必然会知道,在真正实现推理操作之后,通常都需要设置一些关键信息,然后再为推理框架加载所需的模型文件。
# 此处可以使用不同数据精度的模型文件
resource_dir = "../data/qnn_yolov5_multi"
model_name = "cutoff_yolov5s_640_sigmoid_w8a8.qnn236.ctx.bin"
# 创建 Model 对象实例,可以设置模型相关的信息
model_path = os.path.join(resource_dir, model_name)
model = aidlite.Model.create_instance(model_path)
if model is None:
print("Create model failed.")
return False
# 创建 Model 对象实例
config = aidlite.Config.create_instance()
if config is None:
print("Create config failed.")
return False
# 配置一些运行时所需要的参数
config.framework_type = aidlite.FrameworkType.TYPE_QNN236
if acc_type == 1:
config.accelerate_type = aidlite.AccelerateType.TYPE_CPU
elif acc_type == 2:
config.accelerate_type = aidlite.AccelerateType.TYPE_GPU
elif acc_type == 3:
config.accelerate_type = aidlite.AccelerateType.TYPE_DSP
else:
return show_help_prompt()
# 创建推理所需的解释器对象
interpreter = aidlite.InterpreterBuilder.build_interpreter_from_model_and_config(model, config)
if interpreter is None:
print("build_interpreter_from_model_and_config failed.")
return None
# 完成资源初始化的操作
result = interpreter.init()
if result != 0:
print("interpreter init failed.")
return False
# 完成模型的加载操作
result = interpreter.load_model()
if result != 0:
print("interpreter load model failed.")
return False在上述示例代码中,开发者可以提供 不同精度的模型文件(包括非量化的 float32 模型、量化的 int8 模型等) 来创建 Model 对象。相应的,开发者也需要为此指定不同的加速硬件,也就是需要设置 Config 对象的 accelerate_type 成员变量的值。利用 Model 对象和 Config 对象创建推理所需的解释器,然后即可完成所需的初始化、模型加载的操作。
输入数据的前处理
一般来讲,模型推理所需的输入数据需要满足一定的要求,所以就需要对已有的输入数据做一些处理,使其可以被模型利用。
# 使用 Opencv 读取图片数据
frame = cv2.imread(image_path)
# 输入图像的前处理操作
# ... ...
# 取得 Opencv Mat 对象所含的图像数据。
input_tensor_data = frame.data前处理部分的内容究竟怎么实现,完全取决于开发者使用的模型需要什么样的输入数据。 示例程序中的前处理操作,就是针对我们示例程序提供的模型文件所适配的。
完成推理操作
前处理操作完成之后,就可以将得到的数据传入给解释器,解释器就可以利用这些数据来完成推理任务,而在推理完成之后,开发者需要取出推理操作的结果数据。
# 将前处理完成后的数据传递给解释器对象
# result = interpreter.set_input_tensor(0, input_tensor_data)
result = interpreter.set_input_tensor("images", input_tensor_data)
if result != 0:
print("interpreter set_input_tensor() failed.")
return False
# 执行推理过程
result = interpreter.invoke()
if result != 0:
print("interpreter set_input_tensor() failed.")
return False
# 模型有三个输出 Tensor ,所以需要获取三个 Tensor 的输出数据。
# stride8 = interpreter.get_output_tensor(0)
stride8 = interpreter.get_output_tensor("_326")
if stride8 is None:
print("sample : interpreter->get_output_tensor() 0 failed.")
return False
# stride16 = interpreter.get_output_tensor(1)
stride16 = interpreter.get_output_tensor("_364")
if stride16 is None:
print("sample : interpreter->get_output_tensor() 1 failed.")
return False
# stride32 = interpreter.get_output_tensor(2)
stride32 = interpreter.get_output_tensor("_402")
if stride32 is None:
print("sample : interpreter->get_output_tensor() 2 failed.")
return False前处理完成之后,就可以将输入数据给到解释器,由解释器完成推理任务,进而返回结果数据。
💡注意
QNN 和 SNPE 的普通低层接口默认使用 FP32 数组。 支持原生数据模式的后端,可按张量信息使用原生数组。 使用 REMOTE 时,先确认 Android 服务支持该数据模式。 使用 AutoModel 时,保留原模型要求的数据类型。 包装层按已验证的模型接口处理必要的转换。
输出数据的后处理
一般来讲,模型推理结束之后,输出的结果数据不会是我们最终想要的数据,还需要做进一步的加工才是开发者所需要的,这就是后处理操作。
# 输出数据的后处理操作
# ... ...与前处理操作同理,后处理部分的内容究竟怎么实现,完全取决于开发者需要对推理结果数据做什么样的分析处理。 示例程序中的后处理操作,就是针对我们示例程序提供的模型文件所适配的。
资源释放
当开发者不再需要 Aidlite 解释器来完成推理任务时,可以显示地完成资源释放操作。
result = interpreter.destroy()
if result != 0:
print("interpreter set_input_tensor() failed.")
return False至此,已经展示了使用 Aidlite 做模型推理的全部流程,开发者只需要根据自己的模型做对应的修改,即可完成推理任务。