QNN 执行提供程序
用于 ONNX Runtime 的 QNN 执行提供程序支持在 Qualcomm 芯片组上进行硬件加速执行。它使用 Qualcomm AI Engine Direct SDK (QNN SDK) 从 ONNX 模型构建 QNN 图,该图可以由受支持的加速器后端库执行。OnnxRuntime QNN 执行提供程序可用于搭载 Qualcomm Snapdragon SOC 的 Android 和 Windows 设备。
目录
- 安装先决条件(仅限从源代码构建)
- 构建(Android 和 Windows)
- 预构建包(仅限 Windows)
- Qualcomm AI Hub
- 配置选项
- 支持的 ONNX 运算符
- 使用 QNN EP 的 HTP 后端运行模型(Python)
- QNN 上下文二进制缓存功能
- QNN EP 权重共享
- 用法
- 错误处理
- 在 QNN EP 中添加新的运算符支持
- 混合精度支持
安装先决条件(仅限从源代码构建)
如果您从源代码构建 QNN 执行提供程序,则应首先从 https://qpm.qualcomm.com/main/tools/details/qualcomm_ai_engine_direct 下载 Qualcomm AI Engine Direct SDK (QNN SDK)
QNN 版本要求
ONNX Runtime QNN 执行提供程序已使用 QNN 2.22.x 和 Qualcomm SC8280、SM8350、Snapdragon X SOC 在 Android 和 Windows 上构建和测试
构建(Android 和 Windows)
有关构建说明,请参阅 BUILD 页面。
预构建包(仅限 Windows)
注意:从 1.18.0 版本开始,您无需单独下载和安装 QNN SDK。所需的 QNN 依赖库已包含在 OnnxRuntime 包中。
- NuGet 包
- Microsoft.ML.OnnxRuntime.QNN 的每夜构建包的 Feed 可在 此处 找到
- Python 包
- 要求
- Windows ARM64(用于在搭载 Qualcomm NPU 的本地设备上进行推理)
- Windows X64(用于量化模型。请参阅 生成量化模型)
- Python 3.11.x
- Numpy 1.25.2 或 >= 1.26.4
- 安装:
pip install onnxruntime-qnn
- 安装每夜构建包
python -m pip install --pre --extra-index-url https://aiinfra.pkgs.visualstudio.com/PublicPackages/_packaging/ORT-Nightly/pypi/simple onnxruntime-qnn
- 要求
Qualcomm AI Hub
Qualcomm AI Hub 可用于优化和运行在 Qualcomm 托管设备上的模型。OnnxRuntime QNN 执行提供程序是 Qualcomm AI Hub 中受支持的运行时
配置选项
QNN 执行提供程序支持许多配置选项。这些提供程序选项以键值字符串对的形式指定。
“backend_path” | 描述 |
---|---|
‘libQnnCpu.so’ 或 ‘QnnCpu.dll’ | 启用 CPU 后端。用于集成测试。CPU 后端是 QNN 运算符的参考实现 |
‘libQnnHtp.so’ 或 ‘QnnHtp.dll’ | 启用 HTP 后端。将计算卸载到 NPU。 |
“profiling_level” | 描述 |
---|---|
‘off’ | |
‘basic’ | |
‘detailed’ |
“profiling_file_path” | 描述 |
---|---|
‘your_qnn_profile_path.csv’ | 指定 CSV 文件路径以转储 QNN 性能分析事件 |
有关性能分析的更多信息,请参阅 性能分析工具
除了在编译时设置 profiling_level 之外,还可以使用 ETW (Windows) 动态启用性能分析。有关更多详细信息,请参阅 跟踪
“rpc_control_latency” | 描述 |
---|---|
微秒(字符串) | 允许客户端设置 RPC 控制延迟(以微秒为单位) |
“vtcm_mb” | 描述 |
---|---|
MB 为单位的大小(字符串) | QNN VTCM 大小(MB),默认为 0(未设置) |
“htp_performance_mode” | 描述 |
---|---|
‘burst’ | |
‘balanced’ | |
‘default’ | |
‘high_performance’ | |
‘high_power_saver’ | |
‘low_balanced’ | |
‘low_power_saver’ | |
‘power_saver’ | |
‘sustained_high_performance’ |
“qnn_saver_path” | 描述 |
---|---|
‘QnnSaver.dll’ 或 ‘libQnnSaver.so’ 的文件路径 | QNN Saver 后端库的文件路径。将 QNN API 调用转储到磁盘以进行重放/调试。 |
“qnn_context_priority” | 描述 |
---|---|
‘low’ | |
‘normal’ | 默认值。 |
‘normal_high’ | |
‘high’ |
“htp_graph_finalization_optimization_mode” | 描述 |
---|---|
‘0’ | 默认值。 |
‘1’ | 准备时间更快,但图不是最优的。 |
‘2’ | 准备时间更长,图更优。 |
‘3’ | 准备时间最长,图很可能更优。 |
“soc_model” | 描述 |
---|---|
型号(字符串) | SoC 型号。有关有效值,请参阅 QNN SDK 文档。默认为“0”(未知)。 |
“htp_arch” | 描述 |
---|---|
硬件架构 | HTP 架构编号。有关有效值,请参阅 QNN SDK 文档。默认值(无) |
“device_id” | 描述 |
---|---|
设备 ID(字符串) | 设置 htp_arch 时要使用的设备 ID。默认为“0”(用于单个设备)。 |
“enable_htp_fp16_precision” | 描述 示例 |
---|---|
‘0’ | 已禁用。如果是 fp32 模型,则以 fp32 精度进行推理。 |
‘1’ | 默认值。启用以 fp16 精度推理 float32 模型。 |
“offload_graph_io_quantization” | 描述 |
---|---|
‘0’ | 已禁用。QNN EP 将处理图 I/O 的量化和反量化。 |
‘1’ | 默认值。已启用。将图 I/O 的量化和反量化卸载到 CPU EP。 |
“enable_htp_shared_memory_allocator” | 描述 |
---|---|
‘0’ | 默认值。已禁用。 |
‘1’ | 启用 QNN HTP 共享内存分配器。需要 libcdsprpc.so/dll 可用。 代码示例 |
支持的 ONNX 运算符
运算符 | 注释 |
---|---|
ai.onnx:Abs | |
ai.onnx:Add | |
ai.onnx:And | |
ai.onnx:ArgMax | |
ai.onnx:ArgMin | |
ai.onnx:Asin | |
ai.onnx:Atan | |
ai.onnx:AveragePool | |
ai.onnx:BatchNormalization | 自 1.18.0 起支持 fp16 |
ai.onnx:Cast | |
ai.onnx:Clip | 自 1.18.0 起支持 fp16 |
ai.onnx:Concat | |
ai.onnx:Conv | 自 1.18.0 起支持 3d |
ai.onnx:ConvTranspose | 自 1.18.0 起支持 3d |
ai.onnx:Cos | |
ai.onnx:DepthToSpace | |
ai.onnx:DequantizeLinear | |
ai.onnx:Div | |
ai.onnx:Elu | |
ai.onnx:Equal | |
ai.onnx:Exp | |
ai.onnx:Expand | |
ai.onnx:Flatten | |
ai.onnx:Floor | |
ai.onnx:Gather | 仅支持正索引 |
ai.onnx:Gelu | |
ai.onnx:Gemm | |
ai.onnx:GlobalAveragePool | |
ai.onnx:Greater | |
ai.onnx:GreaterOrEqual | |
ai.onnx:GridSample | |
ai.onnx:HardSwish | |
ai.onnx:InstanceNormalization | |
ai.onnx:LRN | |
ai.onnx:LayerNormalization | |
ai.onnx:LeakyRelu | |
ai.onnx:Less | |
ai.onnx:LessOrEqual | |
ai.onnx:Log | |
ai.onnx:LogSoftmax | |
ai.onnx:LpNormalization | p == 2 |
ai.onnx:MatMul | HTP 后端上支持的输入数据类型:(uint8、uint8)、(uint8、uint16)、(uint16、uint8) |
ai.onnx:Max | |
ai.onnx:MaxPool | |
ai.onnx:Min | |
ai.onnx:Mul | |
ai.onnx:Neg | |
ai.onnx:Not | |
ai.onnx:Or | |
ai.onnx:Prelu | 自 1.18.0 起支持 fp16、int32 |
ai.onnx:Pad | |
ai.onnx:Pow | |
ai.onnx:QuantizeLinear | |
ai.onnx:ReduceMax | |
ai.onnx:ReduceMean | |
ai.onnx:ReduceMin | |
ai.onnx:ReduceProd | |
ai.onnx:ReduceSum | |
ai.onnx:Relu | |
ai.onnx:Resize | |
ai.onnx:Round | |
ai.onnx:Sigmoid | |
ai.onnx:Sign | |
ai.onnx:Sin | |
ai.onnx:Slice | |
ai.onnx:Softmax | |
ai.onnx:SpaceToDepth | |
ai.onnx:Split | |
ai.onnx:Sqrt | |
ai.onnx:Squeeze | |
ai.onnx:Sub | |
ai.onnx:Tanh | |
ai.onnx:Tile | |
ai.onnx:TopK | |
ai.onnx:Transpose | |
ai.onnx:Unsqueeze | |
ai.onnx:Where | |
com.microsoft:DequantizeLinear | 提供 16 位整数反量化支持 |
com.microsoft:Gelu | |
com.microsoft:QuantizeLinear | 提供 16 位整数量化支持 |
支持的数据类型因运算符和 QNN 后端而异。有关更多信息,请参阅 QNN SDK 文档。
使用 QNN EP 的 HTP 后端运行模型(Python)
QNN HTP 后端仅支持量化模型。具有 32 位浮点激活和权重的模型必须首先量化为较低的整数精度(例如,8 位或 16 位整数)。
本节提供有关量化模型以及随后使用 Python API 在 QNN EP 的 HTP 后端上运行量化模型的说明。有关量化概念的更广泛概述,请参阅 量化页面。
模型要求
QNN EP 不支持具有动态形状的模型(例如,动态批大小)。动态形状必须固定为特定值。有关更多信息,请参阅有关 使动态输入形状固定 的文档。
此外,QNN EP 支持 ONNX 运算符的子集(例如,不支持 Loops 和 Ifs)。请参阅 支持的 ONNX 运算符列表。
生成量化模型(仅限 x64)
ONNX Runtime python 包通过 onnxruntime.quantization
导入提供用于量化 ONNX 模型的实用程序。由于在 ARM64 上安装 onnx
包时遇到问题,因此量化实用程序目前仅在 x86_64 上受支持。因此,建议使用 x64 机器来量化模型,或者在 Windows ARM64 机器上使用单独的 x64 python 安装。
安装 ONNX Runtime x64 python 包。(请注意,您必须使用 x64 包来量化模型。使用 arm64 包进行推理和利用 HTP/NPU)
python -m pip install onnxruntime-qnn
QNN EP 的量化需要使用校准输入数据。使用代表典型模型输入的校准数据集对于生成准确的量化模型至关重要。
以下代码片段定义了一个示例 DataReader
类,该类生成随机 float32 输入数据。请注意,使用随机输入数据很可能会生成不准确的量化模型。有关如何创建从磁盘上的图像文件提供输入的 CalibrationDataReader
的示例,请参阅 Resnet 数据读取器的实现。
# data_reader.py
import numpy as np
import onnxruntime
from onnxruntime.quantization import CalibrationDataReader
class DataReader(CalibrationDataReader):
def __init__(self, model_path: str):
self.enum_data = None
# Use inference session to get input shape.
session = onnxruntime.InferenceSession(model_path, providers=['CPUExecutionProvider'])
inputs = session.get_inputs()
self.data_list = []
# Generate 10 random float32 inputs
# TODO: Load valid calibration input data for your model
for _ in range(10):
input_data = {inp.name : np.random.random(inp.shape).astype(np.float32) for inp in inputs}
self.data_list.append(input_data)
self.datasize = len(self.data_list)
def get_next(self):
if self.enum_data is None:
self.enum_data = iter(
self.data_list
)
return next(self.enum_data, None)
def rewind(self):
self.enum_data = None
以下代码片段预处理原始模型,然后量化预处理后的模型以使用 uint16
激活和 uint8
权重。尽管量化实用程序公开了 uint8
、int8
、uint16
和 int16
量化数据类型,但 QNN 运算符通常支持 uint8
和 uint16
数据类型。有关每个 QNN 运算符的数据类型要求,请参阅 QNN SDK 运算符文档。
# quantize_model.py
import data_reader
import numpy as np
import onnx
from onnxruntime.quantization import QuantType, quantize
from onnxruntime.quantization.execution_providers.qnn import get_qnn_qdq_config, qnn_preprocess_model
if __name__ == "__main__":
input_model_path = "model.onnx" # TODO: Replace with your actual model
output_model_path = "model.qdq.onnx" # Name of final quantized model
my_data_reader = data_reader.DataReader(input_model_path)
# Pre-process the original float32 model.
preproc_model_path = "model.preproc.onnx"
model_changed = qnn_preprocess_model(input_model_path, preproc_model_path)
model_to_quantize = preproc_model_path if model_changed else input_model_path
# Generate a suitable quantization configuration for this model.
# Note that we're choosing to use uint16 activations and uint8 weights.
qnn_config = get_qnn_qdq_config(model_to_quantize,
my_data_reader,
activation_type=QuantType.QUInt16, # uint16 activations
weight_type=QuantType.QUInt8) # uint8 weights
# Quantize the model.
quantize(model_to_quantize, output_model_path, qnn_config)
运行 python quantize_model.py
将生成一个名为 model.qdq.onnx
的量化模型,该模型可以通过 ONNX Runtime 的 QNN EP 在 Windows ARM64 设备上运行。
有关量化实用程序用法的更多信息,请参阅以下页面
- CPU EP 上 mobilenet 的量化示例
- quantization/execution_providers/qnn/preprocess.py
- quantization/execution_providers/qnn/quant_config.py
在 Windows ARM64 上运行量化模型(onnxruntime-qnn 版本 >= 1.18.0)
安装用于 QNN EP 的 ONNX Runtime ARM64 python 包(需要 Python 3.11.x 和 Numpy 1.25.2 或 >= 1.26.4)
python -m pip install onnxruntime-qnn
以下 Python 代码片段创建了一个带有 QNN EP 的 ONNX Runtime 会话,并在 HTP 后端上运行量化模型 model.qdq.onnx
。
# run_qdq_model.py
import onnxruntime
import numpy as np
options = onnxruntime.SessionOptions()
# (Optional) Enable configuration that raises an exception if the model can't be
# run entirely on the QNN HTP backend.
options.add_session_config_entry("session.disable_cpu_ep_fallback", "1")
# Create an ONNX Runtime session.
# TODO: Provide the path to your ONNX model
session = onnxruntime.InferenceSession("model.qdq.onnx",
sess_options=options,
providers=["QNNExecutionProvider"],
provider_options=[{"backend_path": "QnnHtp.dll"}]) # Provide path to Htp dll in QNN SDK
# Run the model with your input.
# TODO: Use numpy to load your actual input from a file or generate random input.
input0 = np.ones((1,3,224,224), dtype=np.float32)
result = session.run(None, {"input": input0})
# Print output.
print(result)
运行 python run_qdq_model.py
将在 QNN HTP 后端上执行量化的 model.qdq.onnx
模型。
请注意,会话已可选配置为:如果整个模型无法在 QNN HTP 后端上执行,则引发异常。这对于验证量化模型是否完全受 QNN EP 支持非常有用。可用的会话配置包括
- session.disable_cpu_ep_fallback:禁用将不受支持的运算符回退到 CPU EP。
- ep.context_enable:启用 QNN 上下文缓存 功能以转储模型的缓存版本,从而缩短会话创建时间。
上面的代码片段仅指定了 backend_path
提供程序选项。有关所有可用的 QNN EP 提供程序选项的列表,请参阅 配置选项部分。
QNN 上下文二进制缓存功能
存在一个 QNN 上下文,其中包含在转换、编译、最终确定模型后的 QNN 图。QNN 可以将上下文序列化为二进制文件,以便用户可以直接将其用于进一步的推理(无需 QDQ 模型),从而降低模型加载成本。QNN 执行提供程序支持许多会话选项来配置此功能。
转储 QNN 上下文二进制文件
- 创建会话选项,将“ep.context_enable”设置为“1”以启用 QNN 上下文转储。键“ep.context_enable”在 onnxruntime_session_options_config_keys.h 中定义为 kOrtSessionOptionEpContextEnable。
- 使用步骤 1 中创建的会话选项和 HTP 后端 A 创建带有 QDQ 模型的会话。一旦创建/初始化会话,将创建一个带有 QNN 上下文二进制文件的 Onnx 模型。无需运行会话。QNN 上下文二进制文件的生成可以在具有 HTP 的 QualComm 设备上使用 Arm64 构建完成。它也可以在使用 x64 构建的 x64 机器上完成(由于没有 HTP 设备,因此无法运行)。
生成的具有 QNN 上下文二进制文件的 Onnx 模型可以部署到生产/真实设备以运行推理。此 Onnx 模型被 QNN 执行提供程序视为普通模型。推理代码与 HTP 后端上使用 QDQ 模型进行推理的代码保持一致。
#include "onnxruntime_session_options_config_keys.h"
// C++
Ort::SessionOptions so;
so.AddConfigEntry(kOrtSessionOptionEpContextEnable, "1");
// C
const OrtApi* g_ort = OrtGetApiBase()->GetApi(ORT_API_VERSION);
OrtSessionOptions* session_options;
CheckStatus(g_ort, g_ort->CreateSessionOptions(&session_options));
g_ort->AddSessionConfigEntry(session_options, kOrtSessionOptionEpContextEnable, "1");
# Python
import onnxruntime
options = onnxruntime.SessionOptions()
options.add_session_config_entry("ep.context_enable", "1")
配置上下文二进制文件路径
在用户未指定路径的情况下,带有 QNN 上下文二进制文件的生成的 Onnx 模型默认为 [input_QDQ_model_name]_ctx.onnx。用户可以使用键“ep.context_file_path”在会话选项中设置路径。以下是示例代码
// C++
so.AddConfigEntry(kOrtSessionOptionEpContextFilePath, "./model_a_ctx.onnx");
// C
g_ort->AddSessionConfigEntry(session_options, kOrtSessionOptionEpContextFilePath, "./model_a_ctx.onnx");
# Python
options.add_session_config_entry("ep.context_file_path", "./model_a_ctx.onnx")
启用嵌入模式
默认情况下,QNN 上下文二进制文件内容未嵌入到生成的 Onnx 模型中。将单独生成一个 bin 文件。文件名类似于 [input_model_file_name]QNNExecutionProvider_QNN[hash_id]_x_x.bin。该名称由 Ort 提供,并在生成的 Onnx 模型中跟踪。如果对 bin 文件进行任何更改,都将导致问题。此 bin 文件需要与生成的 Onnx 文件放在一起。用户可以通过将“ep.context_embed_mode”设置为“1”来启用它。在这种情况下,上下文二进制文件的内容将嵌入到 Onnx 模型内部。
// C++
so.AddConfigEntry(kOrtSessionOptionEpContextEmbedMode, "1");
// C
g_ort->AddSessionConfigEntry(session_options, kOrtSessionOptionEpContextEmbedMode, "1");
# Python
options.add_session_config_entry("ep.context_embed_mode", "1")
QNN EP 权重共享
Onnx 域中的权重共享
Onnx 中的权重共享意味着具有外部权重的多个 Onnx 模型指向同一个外部权重文件。Onnx 模型共享相同的张量名称,以便它们引用相同的张量数据。
QNN 域中的权重共享
QNN 权重共享通过 QNN 预生成的 QNN 上下文二进制文件启用。它要求用户在 Linux x86_64 或 Windows x86_64 机器上离线生成上下文二进制文件(Windows 支持自 QNN 2.26 起)。QNN 上下文二进制文件包含多个共享相同张量的图。
QNN 域中的权重共享
OnnxRuntime 将具有权重共享的 Onnx 模型转换为具有权重共享的 QNN 上下文二进制文件的方式。
- 创建启用权重共享配置的 QNN 上下文。
- 将 model1.onnx 转换并编译到 QNN 上下文中(获取 Qnn graph1)。
- 将 model2.onnx 转换并编译到 QNN 上下文中(获取 Qnn graph2)。
- 如果模型更多,请重复步骤 2。
- 生成 QNN 上下文二进制文件,生成带有 EPContext 节点的包装 Onnx 模型。OnnxRuntime QNN EP 提供了 OnnxRuntime_qnn_ctx_gen 工具来完成这些步骤。示例命令行
./ep_weight_sharing_ctx_gen -e qnn -i "soc_model|60 htp_graph_finalization_optimization_mode|3" ./model1.onnx,./model2.onnx
它创建了 2 个 Onnx 模型(model1_ctx.onnx、model2_ctx.onnx)和一个 QNN 上下文二进制文件(model2_xxx.bin)。
如果用户从 QNN 工具链 (qnn-context-binary-generator) 创建 QNN 上下文二进制 .bin 文件权重共享。上下文二进制 .bin 文件看起来相同。用户需要创建 model1.onnx 和 model2.onnx,其中 EPContext 节点指向此 .bin 文件。每个 EPContext 节点应引用(节点名称和 partition_name)来自 QNN 上下文的不同 Qnn 图名称。以下是供参考的示例脚本 gen_qnn_ctx_onnx_model.py,它将单个 QNN 图包装到 EPContext 节点中。
使用 QNN 资源共享工作流程进行推理
OnnxRuntime 推理会话需要启用资源共享(将会话选项 ep.share_ep_contexts 设置为 1)才能使用启用了权重共享的转储 Qnn 上下文模型。
- 创建 OnnxRuntime 推理会话,其中 ep.share_ep_contexts=1,加载 model1_ctx.onnx 模型。
- 会话加载 model1_ctx.onnx 模型。
- 共享位置为空。
- model1_ctx.onnx 中的 EPContext 节点 1 指定它使用 Qnn_graph1
- QNN EP 加载 qnn_ctx.bin 并反序列化二进制文件以获取 Qnn 图(Qnn_graph1、Qnn_graph2)。
- 为此 OnnxRuntime 会话使用 Qnn_graph1。
- 将 Qnn_graph2 放入共享位置。
- 创建 OnnxRuntime 推理会话,其中 ep.share_ep_contexts=1,加载 model2_ctx.onnx 模型。
- 会话加载 model2_ctx.onnx 模型。
- model2_ctx.onnx 中的 EPContext 节点 2 指定它使用 Qnn_graph2。
- 共享位置具有 Qnn_graph2。
- QNN EP 跳过加载 qnn_ctx.bin,因为它从共享位置获得了它想要的内容。
- 为此会话使用共享位置中的 Qnn_graph2。
- 为避免现有执行时出现问题,用户需要先销毁第二个会话,然后再销毁第一个会话。
代码示例.
用法
C++
C API 详细信息请参阅 此处。
Ort::Env env = Ort::Env{ORT_LOGGING_LEVEL_ERROR, "Default"};
std::unordered_map<std::string, std::string> qnn_options;
qnn_options["backend_path"] = "QnnHtp.dll";
Ort::SessionOptions session_options;
session_options.AppendExecutionProvider("QNN", qnn_options);
Ort::Session session(env, model_path, session_options);
Python
import onnxruntime as ort
# Create a session with QNN EP using HTP (NPU) backend.
sess = ort.InferenceSession(model_path, providers=['QNNExecutionProvider'], provider_options=[{'backend_path':'QnnHtp.dll'}])`
推理示例
在 CPP 中使用 QNN 执行提供程序以及 QNN CPU 和 HTP 后端进行 Mobilenetv2 图像分类
错误处理
HTP 子系统重启 - SSR
QNN EP 返回关于 QNN HTP SSR 问题的 StatusCode::ENGINE_ERROR。如果在会话运行时检测到此错误,则上层框架/应用程序应重新创建 Onnxruntime 会话。
在 QNN EP 中添加新的运算符支持
要在 EP 中启用新的运算符支持,需要访问以下区域
- QDQ 脚本是否支持此 Op? 代码示例
- Onnxruntime QDQ 节点单元是否支持此 Op? 代码示例
- 它是布局敏感型运算符吗?
- 是否在 LayoutTransformer 中注册? 代码示例
- 是否注册了 NHWC op 架构? 示例错误消息
::operator ()] 模型 face_det_qdq 加载失败:致命错误:com.ms.internal.nhwc:BatchNormalization(9) 不是已注册的函数/op [示例 PR](https://github.com/microsoft/onnxruntime/pull/15278)
启用新运算符的示例 PR
-
非布局敏感型运算符。 使用 SDK 支持直接支持为 QNN EP 启用 Hardsigmoid
-
布局敏感型运算符。 向 QNN EP 添加 InstanceNormalization 运算符
混合精度支持
下图演示了混合精度模型的示例。
混合精度 QDQ 模型由具有不同激活/权重化数据类型的区域组成。区域之间的边界使用 DQ 到 Q 序列在激活量化数据类型之间转换(例如,uint8 到 uint16)。
指定具有不同量化数据类型的区域的能力使得可以探索精度和延迟之间的权衡。更高的整数精度可能会提高精度,但会牺牲延迟,因此有选择地将某些区域提升到更高的精度可以帮助在关键指标中实现理想的平衡。
下图显示了一个模型,其中一个区域已从默认的 8 位激活类型提升到 16 位。
此模型量化为 uint8 精度,但张量“Op4_out”量化为 16 位。这可以通过指定以下初始张量量化覆盖来实现
# Op4_out could be an inaccurate tensor that should be upgraded to 16bit
initial_overrides = {"Op4_out": [{"quant_type": QuantType.QUInt16}]}
qnn_config = get_qnn_qdq_config(
float_model_path,
data_reader,
activation_type=QuantType.QUInt8,
weight_type=QuantType.QUInt8,
init_overrides=initial_overrides, # These initial overrides will be "fixed"
)
上面的代码片段生成以下“固定”覆盖(通过 qnn_config.extra_options[“TensorQuantOverrides”] 获取)
overrides = {
“Op2_out”: [{“quant_type”: QUInt8, “convert”: {“quant_type”: QUInt16, “recv_nodes”: {“Op4”}}}],
“Op3_out”: [{“quant_type”: QUInt8, “convert”: {“quant_type”: QUInt16, “recv_nodes”: {“Op5”}}}],
“Op4_out”: [{“quant_type”: QUInt16}],
“Op5_out”: [{“quant_type”: QUInt16, “convert”: {“quant_type”: QUInt8, “recv_nodes”: {“Op6”}}}]
}
覆盖后,模型的工作方式如下
- Op2 的输出由 Op4、Op7 和 Op8 使用。Op4 使用转换后的 u16 类型,而 Op7 和 Op8 使用原始 u8 类型。
- Op3 的输出从 u8 转换为 u16。Op5 使用转换后的 u16 类型。
- Op4 的输出只是 u16(未转换)。
- Op5 的输出从 u16 转换为 u8。Op6 使用 u8 类型。