由浅入深了解高通平台UDO(3):编译UDO包

编译 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 newstd::vectorstd::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实现库的步骤如下:

  1. 设置环境变量$SNPE_UDO_ROOT

    export SNPE_UDO_ROOT=<absolute_path_to_SnpeUdo_headers_directory>
    
  2. 在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实现库的步骤如下:

  1. 设置环境变量$SNPE_UDO_ROOT
    export SNPE_UDO_ROOT=<absolute_path_to_SnpeUdo_headers_directory>
    
  2. $ANDROID_NDK_ROOT必须为 Android NDK 构建工具链进行设置。

    export ANDROID_NDK_ROOT=<absolute_path_to_android_ndk_directory>
    
  3. 在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 newstd::vectorstd::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实现库的步骤如下:

  1. 设置环境变量$SNPE_UDO_ROOT
    export SNPE_UDO_ROOT=<absolute_path_to_SnpeUdo_headers_directory>
    
  2. $ANDROID_NDK_ROOT必须为 Andorid NDK 构建工具链进行设置。

    export ANDROID_NDK_ROOT=<absolute_path_to_android_ndk_directory>
    
  3. $CL_LIBRARY_PATH必须设置 libOpenCL.so 库位置。

    export CL_LIBRARY_PATH=<absolute_path_to_OpenCL_library>
    

    OpenCL 共享库不作为 高通Neural Processing SDK 的一部分分发。

  4. 在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 newstd::vectorstd::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 实现库。

  1. 设置环境变量$SNPE_UDO_ROOT

    export SNPE_UDO_ROOT=<absolute_path_to_SnpeUdo_headers_directory>
    
  2. 需要安装并设置 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
    
  3. $ANDROID_NDK_ROOT必须为 Andorid NDK 构建工具链进行设置。

    export ANDROID_NDK_ROOT=<absolute_path_to_android_ndk_directory>
    
  4. 在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 newstd::vectorstd::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 实现库。

  1. 设置环境变量$SNPE_UDO_ROOT

    export SNPE_UDO_ROOT=<absolute_path_to_SnpeUdo_headers_directory>
    
  2. 需要安装并设置 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
    
  3. $ANDROID_NDK_ROOT必须为 Andorid NDK 构建工具链进行设置。

    export ANDROID_NDK_ROOT=<absolute_path_to_android_ndk_directory>
    
  4. 在UDO包目录中运行下面的make指令来编译UDO DSP实现库:

    make dsp
    
  5. 在 UDO 包目录中运行下面的 make 指令来生成用于离线缓存生成的库:

    make dsp_x86 X86_CXX=<path_to_x86_64_clang>
    
  6. 在 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

创建 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注册库的步骤如下:
  1. 将以下项目复制到主机上的所需路径

    • Linux 中的 UDO 包

    • Qualcomm® AI Direct SDK

    • 来自 $SNPE_ROOT/share/SNPE/SnpeUdo/cmakefiles/CMakeWindows.cmake 的工具链文件

  2. 打开Visual Studio 附带的Developer Powershell

  3. 执行环境设置脚本,设置环境变量$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>
    
  4. 运行下面的 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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值