编译 UDO 包
介绍
本节提供有关为 高通 Neural Processing SDK 中所有支持的运行时编译 UDO 包的信息。
如UDO 概述中所述,一组注册和实现库统称为 UDO 包。用户可以使用兼容的工具链完全控制构建这些库,以满足其所需的运行时需求。此外,高通神经处理 SDK 提供了工具和实用程序,可轻松创建和编译 UDO。有关用于创建 UDO 包的工具的更多信息,请参阅创建 UDO 包。本节将基于包生成器提供的目录结构讲解 UDO 包的编译方法。
实现用户定义操作
从根本上讲,开发 UDO 需要使用位于 $SNPE_ROOT/include/SNPE/SnpeUdo/ 的头文件中定义的 API 集。每个运行时可能会有额外的要求,并提供自定义实现以适应运行时的选项。UDO API 的详细信息可在 高通Neural Processing SDK API 的 API 文档中找到。本节假设使用“创建 UDO 包”中描述的 UDO 包生成器工具生成了 UDO 包,该工具会根据用户配置的 UDO 规范生成部分实现框架。
制定软件包编译目标
UDO 软件包生成器工具会创建一个 makefile,用于针对特定运行时和目标平台组合编译软件包。该 makefile 旨在提供一个简单的接口,用于针对原生使用 make 或需要 ndk-build 的平台进行编译。使用提供的 makefile 还可以针对各种目标平台分别编译库。
每个 make 目标的通用格式是 <runtime>_<platform>。仅以 <runtime> 格式出现的目标包含所有可能的目标。例如,运行
make cpu
将为 x86 和 Android 平台 (arm64-v8a) 编译 CPU。下方列出了可用的 make 目标 。
注意:使用 makefile 是可选的,并不是生成库所必需的。
注意:对于以下所有示例,显示的工件均针对 arm64-v8a 目标。
为 CPU 实现 UDO
要在 CPU 运行时运行 UDO 包,需要基于核心 UDO API 的 CPU UDO 实现库。UDO 包生成器工具将创建一个包含所需格式的空白构造的框架,但创建和执行操作的核心逻辑需要由用户填写。这可以通过在 UDO 包生成器工具生成的<OpName>.cpp文件中完成finalize()
、execute()
和函数的实现来完成。free()
为了获得良好的性能和稳定性,需要在完成的execute()
函数中避免堆内存分配。堆内存分配包括但不限于调用 malloc
、构造带有默认分配器的 STL 容器对象,以及添加调用带有默认分配器的 STL 容器对象等操作。 更多信息,请查看此处。operator new
std::vector
std::vector::push_back
注意:需要注意的是,高通神经处理 SDK 并非直接提供与 UDO 所有输入和输出对应的张量数据,而是以不透明指针的形式提供。UDO 实现应在执行时使用 高通神经处理 SDK 发出的 CustomOp 操作对象中的方法获取原始张量指针的句柄。CPU 运行时仅处理浮点激活张量。因此,CPU UDO 实现应实现为仅接收和生成浮点张量,并将配置文件中的 data_type 字段设置为 FLOAT_32。所有其他数据类型将被忽略。 更多详情,请参阅定义 UDO 。
高通需要在主机上编译并运行 UDO 包 。需要使用 snpe-dlc-quantize 对模型进行量化,才能在 DSP 上运行至少具有一个非浮点输入的 UDO 层。
为主机上的 CPU 编译 UDO
在主机x86平台上编译CPU UDO实现库的步骤如下:
-
设置环境变量
$SNPE_UDO_ROOT
。export SNPE_UDO_ROOT=<absolute_path_to_SnpeUdo_headers_directory>
-
在UDO包目录中运行下面的make指令来编译UDO包:
make cpu_x86
针对主机 CPU 进行编译后预期的成果如下
-
UDO CPU 实现库:<UDO-Package>/libs/x86-64_linux_clang/libUdo<UDO-Package>ImplCpu.so
-
UDO 包注册库:<UDO-Package>/libs/x86-64_linux_clang/libUdo<UDO-Package>Reg.so
注意:该命令必须从包根目录运行。
为设备上的 CPU 编译 UDO
在Android平台上编译CPU UDO实现库的步骤如下:
-
设置环境变量
$SNPE_UDO_ROOT
。export SNPE_UDO_ROOT=<absolute_path_to_SnpeUdo_headers_directory>
-
$ANDROID_NDK_ROOT
必须为 Android NDK 构建工具链进行设置。export ANDROID_NDK_ROOT=<absolute_path_to_android_ndk_directory>
-
在UDO包目录中运行下面的make指令来编译UDO包:
make cpu_android
NDK 构建需要共享 C++ 标准库才能运行。请确保设备上存在 libc++_shared.so
LD_LIBRARY_PATH
。
针对 Android CPU 进行编译后预期的工件是
-
UDO CPU 实现库:<UDO-Package>/libs/arm64-v8a/libUdo<UDO-Package>ImplCpu.so
-
UDO包注册库:<UDO-Package>/libs/arm64-v8a/libUdo<UDO-Package>Reg.so
-
共享标准 C++ 库的副本:<UDO-Package>/libs/arm64-v8a/libc++_shared.so
为 GPU 实现 UDO
与 CPU 运行时类似,要在 GPU 运行时上运行 UDO 包,需要基于核心 UDO API 的 GPU UDO 实现库。UDO 包生成器工具将创建一个包含所需格式的空白结构的框架,但创建和执行操作的核心逻辑需要由用户填写。这可以通过完成函数的实现setKernelInfo()
, 并在UDO 包生成器工具生成的<OpName>.cpp<OpName>Operation()
文件中添加 GPU 内核实现来完成。
为了获得良好的性能和稳定性,需要在完成的<OpName>Operation()
函数中避免堆内存分配。堆内存分配包括但不限于调用malloc
、构造带有默认分配器的 STL 容器对象,以及添加调用带有默认分配器的 STL 容器对象等操作。 更多信息,请查看此处。operator new
std::vector
std::vector::push_back
高通神经处理 SDK GPU UDO 支持网络中的 16 位浮点激活。用户应预期 高通神经处理 SDK GPU UDO 的输入/输出 OpenCL 缓冲内存将采用 16 位浮点(或半精度 OpenCL)数据格式作为存储类型。为了提高准确性,用户可以选择使用 32 位浮点数据实现内核的内部数学运算,并在从 UDO 内核读取输入缓冲区或写入输出缓冲区时转换为半精度。
注: 高通 神经处理 SDK 并非直接提供与 UDO 所有输入和输出对应的张量数据,而是将其作为不透明指针提供。UDO 实现预计会将其转换为 <code>Qnn_Tensor_t</code>,该指针保存了张量的 OpenCL 内存指针。
为设备上的 GPU 编译 UDO
在Android平台上编译GPU UDO实现库的步骤如下:
-
设置环境变量
$SNPE_UDO_ROOT
。export SNPE_UDO_ROOT=<absolute_path_to_SnpeUdo_headers_directory>
-
$ANDROID_NDK_ROOT
必须为 Andorid NDK 构建工具链进行设置。export ANDROID_NDK_ROOT=<absolute_path_to_android_ndk_directory>
-
$CL_LIBRARY_PATH
必须设置 libOpenCL.so 库位置。export CL_LIBRARY_PATH=<absolute_path_to_OpenCL_library>
OpenCL 共享库不作为 高通Neural Processing SDK 的一部分分发。
-
在UDO包目录中运行下面的make指令来编译UDO包:
make gpu_android
注意:共享 OpenCL 库是特定于目标平台的。它应该可以在 中找到CL_LIBRARY_PATH
。
Android GPU 编译后预期的工件是
-
UDO GPU 实现库:<UDO-Package>/libs/arm64-v8a/libUdo<UDO-Package>ImplGpu.so
-
UDO包注册库:<UDO-Package>/libs/arm64-v8a/libUdo<UDO-Package>Reg.so
-
共享标准 C++ 库的副本:<UDO-Package>/libs/arm64-v8a/libc++_shared.so
为 DSP V65 和 V66 实现 UDO
高通神经处理 SDK 利用 高通 AI Direct SDK 在 DSP 上运行 UDO 层。因此,需要基于 高通 AI Direct SDK API 的 DSP 实现库才能在 DSP 运行时运行 UDO 包。UDO 包生成器工具将创建模板文件<OpName>.cpp,用户需要在 <OpName>_executeOp()
模板文件中的函数中实现执行逻辑。
为了获得良好的性能和稳定性,需要在完成的<OpName>_executeOp()
函数中避免堆内存分配。堆内存分配包括但不限于调用malloc
、构造带有默认分配器的 STL 容器对象,以及添加调用带有默认分配器的 STL 容器对象等操作。 更多信息,请查看此处。operator new
std::vector
std::vector::push_back
高通 Neural Processing SDK UDO 使用工作线程、六边形矢量扩展 (HVX) 代码和 VTCM 支持对操作进行多线程支持。
DSP 运行时仅在网络层之间传播无符号 8 位激活张量。但它能够根据需要将数据反量化为浮点数。因此,开发 DSP 内核的用户可以预期操作中输入和输出的激活张量是 UINT_8 还是 FLOAT_32,因此可以将配置文件中的字段 data_type 设置为这两种设置之一。有关更多详细信息,请参阅定义 UDO。
在设备上为 DSP V65 和 V66 编译 UDO
此高通 Neural Processing SDK 版本支持使用 Hexagon-SDK 3.5.x 构建 UDO DSP 实现库。
-
设置环境变量
$SNPE_UDO_ROOT
export SNPE_UDO_ROOT=<absolute_path_to_SnpeUdo_headers_directory>
-
需要安装并设置 Hexagon-SDK。有关详细信息,请按照 Hexagon-SDK 安装位置
$HEXAGON_SDK_ROOT/docs/readme.html
页面 上的设置说明进行操作。请确保设置为使用 Hexagon-SDK 构建工具链。同时设置 和$HEXAGON_SDK_ROOT
$HEXAGON_SDK_ROOT
$HEXAGON_TOOLS_ROOT
$SDK_SETUP_ENV
export HEXAGON_SDK_ROOT=<path to hexagon sdk installation> export HEXAGON_TOOLS_ROOT=$HEXAGON_SDK_ROOT/tools/HEXAGON_Tools/8.3.07 export ANDROID_NDK_ROOT=<path to Android NDK installation> export SDK_SETUP_ENV=Done
-
$ANDROID_NDK_ROOT
必须为 Andorid NDK 构建工具链进行设置。export ANDROID_NDK_ROOT=<absolute_path_to_android_ndk_directory>
-
在UDO包目录中运行下面的make指令来编译UDO DSP实现库:
make dsp
DSP 编译后的预期产物是
-
UDO DSP 实现库:<UDO-Package>/libs/dsp_<dsp_arch_type>/libUdo<UDO-Package>ImplDsp.so
-
UDO包注册库:<UDO-Package>/libs/arm64-v8a/libUdo<UDO-Package>Reg.so
注意:该命令必须从包根目录运行。为所有小于 v68 的 aarch 创建 dsp_v60 文件夹。
为 DSP V68 或更高版本实现 UDO
高通 神经处理 SDK 利用 高通 AI Direct SDK 在 DSP v68 或更高版本上运行 UDO 层。因此,需要基于 高通 AI Direct SDK API 的 DSP 实现库才能在 DSP 运行时运行 UDO 包。UDO 包生成器工具将创建模板文件 <OpName>ImplLibDsp.cpp,用户需要在<OpName>Impl()
模板文件中的函数中实现执行逻辑。
为了获得良好的性能和稳定性,需要在完成的<OpName>Impl()
函数中避免堆内存分配。堆内存分配包括但不限于调用malloc
、构造带有默认分配器的 STL 容器对象,以及添加调用带有默认分配器的 STL 容器对象等操作。 更多信息,请查看此处。operator new
std::vector
std::vector::push_back
高通 神经处理 SDK UDO 提供对六边形矢量扩展 (HVX) 代码和基于成本的调度的支持。
DSP 运行时在网络层之间传播无符号 8 位或无符号 16 位激活张量。但它能够根据需要将数据反量化为浮点数。因此,开发 DSP 内核的用户可以预期操作中传入和传出 UINT_8、UINT_16 或 FLOAT_32 类型的激活张量,因此可以将配置文件中的 data_type 字段设置为这三种类型之一。更多详情,请参阅高通AI Direct SDK。
在设备上为 DSP_V68 或更高版本编译 UDO
此高通Neural Processing SDK 版本支持使用 Hexagon-SDK 4.x 和 高通AI Direct SDK 构建 UDO DSP 实现库。
-
设置环境变量
$SNPE_UDO_ROOT
export SNPE_UDO_ROOT=<absolute_path_to_SnpeUdo_headers_directory>
-
需要安装并设置 Hexagon-SDK 4.0+。有关 Hexagon-SDK 的详细信息,请按照
$HEXAGON_SDK4_ROOT/docs/readme.html
第 页上的设置说明进行操作,其中$HEXAGON_SDK4_ROOT
是 Hexagon-SDK 的安装位置。确保$HEXAGON_SDK4_ROOT
设置为使用 Hexagon-SDK 构建工具链。此外,设置$HEXAGON_TOOLS_ROOT
和$SDK_SETUP_ENV
。此外,我们需要一个解压后的高通 AI Direct SDK(无需设置 高通 AI Direct SDK)来构建库。有关 高通 AI Direct SDK 的详细信息,请参阅第$QNN_SDK_ROOT/docs/QNN/index.html
页上的 高通AI Direct SDK 文档,其中$QNN_SDK_ROOT
是 高通 AI Direct SDK 的安装位置。将 设置$QNN_SDK_ROOT
为解压后的 高通AI Direct SDK 位置。export HEXAGON_SDK_ROOT=<path to hexagon sdk installation> export HEXAGON_SDK4_ROOT=<path to hexagon sdk 4.x installation> export HEXAGON_TOOLS_ROOT=$HEXAGON_SDK_ROOT/tools/HEXAGON_Tools/8.4.09 export QNN_SDK_ROOT=<path to QNN sdk installation> export ANDROID_NDK_ROOT=<path to Android NDK installation> export SDK_SETUP_ENV=Done
-
$ANDROID_NDK_ROOT
必须为 Andorid NDK 构建工具链进行设置。export ANDROID_NDK_ROOT=<absolute_path_to_android_ndk_directory>
-
在UDO包目录中运行下面的make指令来编译UDO DSP实现库:
make dsp
-
在 UDO 包目录中运行下面的 make 指令来生成用于离线缓存生成的库:
make dsp_x86 X86_CXX=<path_to_x86_64_clang>
-
在 UDO 包目录中运行以下 make 指令来生成适用于Android ARM 架构的库:
make dsp_aarch64
注意:此程序只能在 Linux 设备上运行,不适用于 Windows 设备。
DSP 编译后的预期产物是
-
UDO DSP 实现库:<UDO-Package>/libs/dsp_v68/libUdo<UDO-Package>ImplDsp.so
-
UDO包注册库:<UDO-Package>/libs/arm64-v8a/libUdo<UDO-Package>Reg.so
离线缓存生成编译后的预期产物是
-
UDO DSP 实现库:<UDO-Package>/libs/x86-64_linux_clang/libUdo<UDO-Package>ImplDsp.so
针对 Android ARM 架构进行编译后的预期产物是
-
UDO DSP 实现库:<UDO-Package>/libs/arm64-v8a/libUdo<UDO-Package>ImplDsp_AltPrep.so
注意:该命令必须从包根目录运行。
Make 目标表
制定目标 | 运行时 | 平台 | 杂项 |
---|---|---|---|
全部 | CPU、GPU、DSP | x86、arm64-v8a | |
全x86 | 中央处理器 | x86 | |
all_android | CPU、GPU、DSP | arm64-v8a | |
注册 | x86、arm64-v8a | ||
reg_x86 | x86 | ||
reg_android | arm64-v8a | ||
中央处理器 | 中央处理器 | x86、arm64-v8a | |
CPU_x86 | 中央处理器 | x86 | 与 all_x86 相同 |
CPU_Android | 中央处理器 | arm64-v8a | |
图形处理器 | 图形处理器 | arm64-v8a | |
gpu_android | 图形处理器 | arm64-v8a | 与 gpu 相同 |
DSP | DSP | ||
dsp_android | DSP | 与 dsp 相同 | |
DSP_x86 | DSP | ||
dsp_aarch64 | DSP |
注意:默认情况下,编译运行时还会编译相应的注册库
为 Windows 编译 UDO 包
概述
本节提供有关如何在 Linux 上准备必要的工件以及如何在 Windows 上编译 udo 包的信息。
如UDO 概述中所述,本节详细介绍了 Windows 上的 UDO 库编译流程。
在 Windows 上构建环境
CMake 版本最低要求 3.21
MSVC v143 ARM64 构建工具
基本组件
下面列出了需要在 Linux 上生成的必需组件。
对于具有 CPU 运行时实现的 UDO
UDO 包
对于使用 V68 DSP 运行时实现的 UDO
UDO 包
量化 DLC(支持 HTP),请参阅使用 UDO 准备模型
DSP 实现库,请参阅编译 UDO 包
创建 CMake UDO 包
此步骤在Linux上执行,该软件包可以在Linux和Windows中使用。使用 snpe-udo-package-generator 时添加参数\-\-gen_cmakelists 。例如:snpe-udo-package-generator --config_path <config_path> --output_path <output_path> --gen_cmakelists
有关创建 UDO 包的工具的更多信息,请参阅创建 UDO 包
为设备上的注册库和 CPU 实现库编译 Windows UDO(可选)
此步骤在 Windows 上执行,这意味着用户必须将整个包从 Linux 复制到 Windows。在arm64上编译UDO注册库的步骤如下:
将以下项目复制到主机上的所需路径
Linux 中的 UDO 包
Qualcomm® AI Direct SDK
来自 $SNPE_ROOT/share/SNPE/SnpeUdo/cmakefiles/CMakeWindows.cmake 的工具链文件
打开Visual Studio 附带的Developer Powershell
执行环境设置脚本,设置环境变量
$env:QNN_SDK_ROOT
并运行 CMake 命令& "$SNPE_ROOT\bin\envsetup.ps1" $env:QNN_SDK_ROOT = <path_to_qnn_sdk_root> cd <path_to_udo_package> cmake -S . -B <build_dir> -A arm64 -DCMAKE_TOOLCHAIN_FILE=<path_to_toolchainfile>
运行下面的 cmake 指令来编译 UDO 包:
cmake --build <build_dir> --config release --target install
编译后预期的结果如下
UDO CPU 实现库:<UDO-Package>/libs/arm64_windows/Udo<UDO-Package>ImplCpu.dll
UDO 包注册库:<UDO-Package>/libs/arm64_windows/Udo<UDO-Package>Reg.dll