骁龙神经处理引擎SDK参考指南(25)
6.5.6 量化 DLC 的 UDO DSP 教程
概述
本教程介绍了为 DSP 运行时创建 UDO 包并使用该包执行 Inception-V3 模型所需的步骤。本教程中选择了 Softmax 操作来演示使用 SNPE 实现 UDO。本教程还介绍了 DSP V68 的离线缓存生成步骤。
SNPE SDK 为这个例子提供资源
- $SNPE_ROOT/示例/NativeCpp/UdoExample/Softmax
有关 UDO 的一般信息可在UDO 概述中找到。
有关在不使用 UDO 的情况下运行 Inception-V3 网络的信息,请参阅Inception-V3 教程。
本教程将生成为 CPU、GPU 和 DSP 运行时运行 Inception-V3 网络所需的工件。此处概述了单独为 DSP 运行时编译和执行 Inception-V3 网络所需的步骤。有关为 CPU 和 GPU 运行时运行 Inception-V3 网络的信息,请访问Inception-V3 UDO 教程。
先决条件
以下教程假定已遵循一般SNPE 设置以支持 SDK 环境、TensorFlow 环境和所需的平台依赖项。此外,我们需要一个提取的 QNN-SDK(不需要 QNN-SDK 设置)来生成框架代码和构建库。有关 QNN-SDK 的详细信息,请参阅页面上的 QNN 文档 Q N N S D K R O O T / d o c s / i n d e x . h t m l ,其中 Q N N S D K R O O T 是 Q N N − S D K 安装的位置。将设置 QNN_SDK_ROOT/docs/index.html,其中QNN_SDK_ROOT是 QNN-SDK 安装的位置。将 设置 QNNSDKROOT/docs/index.html,其中QNNSDKROOT是QNN−SDK安装的位置。将设置QNN_SDK_ROOT为解压缩的 QNN-SDK 位置。本教程中列出的步骤使用 inception_v3_2016_08_28_frozen.pb 形式的 Tensorflow 模型。有关获取 Inception-V3 模型的详细信息,请访问教程设置。
介绍
以下是开发和运行 UDO 的步骤
- 1.)包生成
- 2.)框架模型转换为DLC
- 3.)包实现
- 4.)包编译
- 5.)模型执行
步骤 1-4 在 x86 主机上离线运行,并且是执行步骤 5 所必需的。步骤 5 提供有关使用 SNPE 命令行可执行文件snpe-net-run执行的信息。或者,用户可以使用提供的设置脚本自动执行步骤 1-4 。
第 1 步:包生成
生成 SoftmaxUdoPackage 需要snpe-udo-package-generator工具和提供的 UDO 插件:Softmax_Quant.json。该插件位于 $SNPE_ROOT/examples/NativeCpp/UdoExample/Softmax/config 下。可以在此处找到有关创建 UDO 插件的更多信息。
使用以下内容生成 SoftmaxUdoPackage:
export SNPE_UDO_ROOT=$SNPE_ROOT/share/SnpeUdo
snpe-udo-package-generator -p $SNPE_ROOT/examples/NativeCpp/UdoExample/Softmax/config/Softmax_Quant.json -o $SNPE_ROOT/models/inception_v3/
同样对于 DSP V68 示例,Config 位于以下位置
- $SNPE_ROOT/examples/NativeCpp/UdoExample/Softmax/config/Softmax_v68.json
此命令在 $SNPE_ROOT/models/inception_v3/SoftmaxUdoPackage 中创建基于 Softmax 的包。
有关 snpe-udo-package-generator 工具的更多信息,请访问此处。
第二步:框架模型转换为DLC
有关将模型转换为 DLC 的信息,请参阅 Inception V3 UDO 模型转换。
这将生成一个名为 inception_v3_udo.dlc 的 DLC,其中包含作为 UDO 的 Softmax,位于 $SNPE_ROOT/models/inception_v3/dlc。
第 3 步:包实现
生成的包创建了操作实现的骨架,用户必须填充该骨架才能创建功能性 UDO。与 SNPE 兼容的其余代码脚手架由snpe-udo-package-generator提供。
本教程的 UDO 实现在 $SNPE_ROOT/examples/NativeCpp/UdoExample/Softmax/src 下提供。
V65 和 V66 的 DSP 实现
在 SNPE DSP 上的具有 UDO 层的网络上运行推理需要一个注册库和一个实现库。注册库将在CPU上运行,并指定了UDO的DSP实现库。
有关为 DSP V65 和 V66运行时实现 UDO 的更多信息,请参阅为 DSP V65 和 V66 实现 UDO。
DSP V65和V66需要实现的包中的文件是
- SoftmaxUdoPackage/jni/src/DSP/Softmax.cpp
提供的示例实现位于该位置
- $SNPE_ROOT/examples/NativeCpp/UdoExample/Softmax/src/DSP/Softmax.cpp
将提供的实现复制到包中:
cp -f $SNPE_ROOT/examples/NativeCpp/UdoExample/Softmax/src/DSP/Softmax.cpp $SNPE_ROOT/models/inception_v3/SoftmaxUdoPackage/jni/src/DSP/
可选地,用户可以在包中提供他们自己的实现。
V68 或更高版本的 DSP 实现
与所有其他 SNPE 运行时类似,需要注册库和实现库才能在 SNPE DSP 上使用 UDO 层在网络上运行推理。注册库将在CPU上运行,并指定了UDO的DSP实现库。
有关为 DSP V68 或更高版本运行时实现 UDO 的更多信息,请参阅为 DSP V68 或更高版本实现 UDO。此示例中的目录路径和位置特定于 DSP V68。对于以后的运行时,请将路径中的DSP_V68替换为相应的 DSP 架构(例如DSP_V69 )。
DSP V68及以后版本需要实现的包中文件为
- SoftmaxUdoPackage/jni/src/DSP_V68/SoftmaxImplLibDsp.cpp
提供的示例实现位于该位置
- $SNPE_ROOT/examples/NativeCpp/UdoExample/Softmax/src/DSP_v68/SoftmaxImplLibDsp.cpp
将提供的实现复制到包中:
cp -f $SNPE_ROOT/examples/NativeCpp/UdoExample/Softmax/src/DSP_v68/SoftmaxImplLibDsp.cpp $SNPE_ROOT/models/inception_v3/SoftmaxUdoPackage/jni/src/DSP_V68/
可选地,用户可以在包中提供他们自己的实现。
第四步:编译包
Hexagon DSP 运行时编译
DSP 运行时的编译使用 make 系统。为了构建 DSP V65 和 V66 运行时的实现库,需要安装和设置 Hexagon-SDK。有关详细信息,请按照页面上的设置说明进行操作$HEXAGON_SDK_ROOT/docs/readme.html,HEXAGON_SDK_ROOTHexagon-SDK 的安装位置位于此处。为 DSP 编译 UDO 的信息在为 DSP 编译 UDO中可用。
为了构建 DSP V68 或更高版本运行时的实现库,需要安装和设置 Hexagon-SDK 4.0+。 H E X A G O N S D K 4 R O O T / d o c s / r e a d m e . h t m l 有关 H e x a g o n − S D K 的详细信息,请按照页面上的设置说明进行操作, H E X A G O N S D K R O O T H e x a g o n − S D K 的安装位置位于此处。此外,我们需要一个提取的 Q N N − S D K (不需要 Q N N − S D K 设置)来构建库。有关 Q N N − S D K 的详细信息,请参阅页面上的 Q N N 文档 HEXAGON_SDK4_ROOT/docs/readme.html有关 Hexagon-SDK 的详细信息,请按照页面上的设置说明进行操作, HEXAGON_SDK_ROOTHexagon-SDK 的安装位置位于此处。此外,我们需要一个提取的 QNN-SDK(不需要 QNN-SDK 设置)来构建库。有关 QNN-SDK 的详细信息,请参阅页面上的 QNN 文档 HEXAGONSDK4ROOT/docs/readme.html有关Hexagon−SDK的详细信息,请按照页面上的设置说明进行操作,HEXAGONSDKROOTHexagon−SDK的安装位置位于此处。此外,我们需要一个提取的QNN−SDK(不需要QNN−SDK设置)来构建库。有关QNN−SDK的详细信息,请参阅页面上的QNN文档QNN_SDK_ROOT/docs/index.html,其中QNN_SDK_ROOT是 QNN-SDK 安装的位置。将 设置$QNN_SDK_ROOT为解压缩的 QNN-SDK 位置。有关为 DSP V68 或更高版本编译 UDO 的信息,请参阅为 DSP_V68 或更高版本编译 UDO。
在 DSP V68 的情况下为离线缓存生成编译:
cd SoftmaxUdoPackage
make dsp_x86 X86_CXX=<path_to_x86_64_clang>
为离线缓存生成编译后的预期工件是
- UDO DSP实现库:SoftmaxUdoPackage/libs/x86-64_linux_clang/libUdoSoftmaxUdoPackageImplDsp.so
安装脚本
SNPE SDK 提供了一个选项,可以自动执行上述步骤 1-4 中概述的 UDO 的 dlc 转换、包生成、包实现和包编译步骤。该选项是Inception V3 安装脚本的扩展。要为 UDO 启用 Inception-V3 设置,请使用–udo或-u选项运行脚本。
usage: $SNPE_ROOT/models/inception_v3/scripts/setup_inceptionv3.py [-h] -a ASSETS_DIR [-d] [-r RUNTIME] [-u] [-l [HTP_SOC]]
Prepares the inception_v3 assets for tutorial examples.
required arguments:
-a ASSETS_DIR, --assets_dir ASSETS_DIR
directory containing the inception_v3 assets
optional arguments:
-d, --download Download inception_v3 assets to inception_v3 example
directory
-r RUNTIME, --runtime RUNTIME
Choose a runtime to set up tutorial for. Choices: cpu,
gpu, dsp, aip, all. 'all' option is only supported
with --udo flag
-u, --udo Generate and compile a user-defined operation package
to be used with inception_v3. Softmax is simulated as
a UDO for this script.
-l [HTP_SOC], --htp_soc [HTP_SOC]
Specify SOC target for generating HTP Offline Cache.
For example: "--htp_soc sm8450" for waipio, default
value is sm8550
–udo 扩展与 setup_inceptionv3.py 脚本通常使用的选项兼容。当启用 --udo 选项时,-r 或 --runtime 选项控制包实现和编译的运行时。此外,–udo 选项支持使用“所有”运行时选项来为 CPU、GPU 和 DSP/AIP 运行时创建和编译 SoftmaxUdo 包。选择“aip”或“dsp”运行时选项会额外编译 x86 库以量化模型。选择“cpu”运行时选项可为 x86 和 Android 目标进行编译。如果未设置 ANDROID_NDK_ROOT,将跳过 Android 目标的编译。如果未提供运行时选项,则会为 CPU 运行时编译包。
使用 UDO 设置脚本的命令是:
python3 $SNPE_ROOT/models/inception_v3/scripts/setup_inceptionv3.py -a ~/tmpdir -d -u -r <runtime_of_choice>
对于 DSP V68:
python3 $SNPE_ROOT/models/inception_v3/scripts/setup_inceptionv3.py -a ~/tmpdir -d -u -r <runtime_of_choice> -l
这将填充步骤 4中的工件。
注意:安装脚本针对 arm64-v8a 平台架构进行编译。在使用 make 时为不同的目标集 PLATFORM 进行编译。有关更多信息,请参见第 4 步。
模型执行
使用 snpe-net-run 执行
为 UDO 执行 Inception-V3 与在没有 UDO 的情况下使用snpe-net-run大致相同。
SNPE SDK 提供snpe-net-run的Linux 和 Android 二进制文件
- $SNPE_ROOT/bin/x86_64-linux-clang
- $SNPE_ROOT/bin/arm-android-clang8.0
- $SNPE_ROOT/bin/aarch64-android-clang8.0
- $SNPE_ROOT/bin/aarch64-oe-linux-gcc8.2
- $SNPE_ROOT/bin/aarch64-oe-linux-gcc9.3
- $SNPE_ROOT/bin/aarch64-ubuntu-gcc7.5
对于 UDO,snpe-net-run 通过 --udo_package_path 选项使用注册库。还必须更新 LD_LIBRARY_PATH 以包括从包编译生成的特定于运行时的工件。
安卓目标执行
在 Android 目标上执行的教程将使用 arm64-v8a 架构。
# architecture: arm64-v8a - compiler: clang - STL: libc++
export SNPE_TARGET_ARCH=aarch64-android-clang8.0
export SNPE_TARGET_STL=libc++_shared.so
然后,将 SNPE 二进制文件和库推送到目标设备:
adb shell "mkdir -p /data/local/tmp/snpeexample/$SNPE_TARGET_ARCH/bin"
adb shell "mkdir -p /data/local/tmp/snpeexample/$SNPE_TARGET_ARCH/lib"
adb push $SNPE_ROOT/lib/$SNPE_TARGET_ARCH/$SNPE_TARGET_STL \
/data/local/tmp/snpeexample/$SNPE_TARGET_ARCH/lib
adb push $SNPE_ROOT/lib/$SNPE_TARGET_ARCH/*.so \
/data/local/tmp/snpeexample/$SNPE_TARGET_ARCH/lib
adb push $SNPE_ROOT/bin/$SNPE_TARGET_ARCH/snpe-net-run \
/data/local/tmp/snpeexample/$SNPE_TARGET_ARCH/bin
接下来,更新目标设备上的环境变量以包含 SNPE 库和二进制文件:
adb shell
export SNPE_TARGET_ARCH=aarch64-android-clang8.0
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/data/local/tmp/snpeexample/$SNPE_TARGET_ARCH/lib
export PATH=$PATH:/data/local/tmp/snpeexample/$SNPE_TARGET_ARCH/bin
最后,向设备推送Inception-V3 UDO模型和输入数据:
cd $SNPE_ROOT/models/inception_v3
mkdir data/rawfiles && cp data/cropped/*.raw data/rawfiles/
adb shell "mkdir -p /data/local/tmp/inception_v3_udo"
adb push data/rawfiles /data/local/tmp/inception_v3_udo/cropped
adb push data/target_raw_list.txt /data/local/tmp/inception_v3_udo
adb push dlc/inception_v3_udo.dlc /data/local/tmp/inception_v3_udo
rm -rf data/rawfiles
Hexagon DSP 执行
DSP 在设备上的执行过程与 CPU 和 GPU 大体相同。然而,DSP 运行时需要量化的网络参数。虽然 DSP 允许未量化的 DLC,但通常建议对 DLC 进行量化以提高性能。本教程将使用量化的 DLC 作为示例。量化 DLC 需要snpe-dlc-quantize工具。
注意:在下面的命令中,应该使用在Model DLC Conversion生成的输入 dlc 。此外,在参数“udo_package_path”下提供编译 x86 主机后生成的注册库的路径。可以在此处找到有关编译 x86 的更多信息。
量化 DLC 以在 DSP 上使用:
cd $SNPE_ROOT/models/inception_v3/
snpe-dlc-quantize --input_dlc dlc/inception_v3_udo.dlc --input_list data/cropped/raw_list.txt --udo_package_path SoftmaxUdoPackage/libs/x86-64_linux_clang/libUdoSoftmaxUdoPackageReg.so --output_dlc dlc/inception_v3_udo_quantized.dlc
要使用离线缓存生成量化 DLC 以在 DSP V68 上使用:
将x86编译后生成的注册库libUdoSoftmaxUdoPackageReg.so和实现库libUdoSoftmaxUdoPackageImplCpu.so复制到SoftmaxUdoPackage/libs/x86-64_linux_clang。可以在此处找到有关编译 x86 的更多信息。
cd $SNPE_ROOT/models/inception_v3/
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:SoftmaxUdoPackage/libs/x86-64_linux_clang
snpe-dlc-quantize --input_dlc dlc/inception_v3_udo.dlc --input_list data/cropped/raw_list.txt --udo_package_path SoftmaxUdoPackage/libs/x86-64_linux_clang/libUdoSoftmaxUdoPackageReg.so --output_dlc dlc/inception_v3_udo_quantized.dlc --enable_htp
有关snpe-dlc-quantize的更多信息,请访问量化。有关 UDO 特定量化的信息,请访问使用 UDO 量化 DLC。有关 DSP/AIP 运行时的信息,请访问DSP 运行时或AIP 运行时。
现在将量化模型推送到设备:
adb push dlc/inception_v3_udo_quantized.dlc /data/local/tmp/inception_v3_udo
在 DSP 上执行之前,将 DSP 的 SNPE 库推送到设备:
adb shell "mkdir -p /data/local/tmp/snpeexample/dsp/lib"
adb push $SNPE_ROOT/lib/dsp/*.so /data/local/tmp/snpeexample/dsp/lib
现在将特定于 DSP 的 UDO 库推送到设备。根据配置中指定的 DSP 架构,dsp_v68目录可以是dsp_v60或dsp(使用较旧的 SNPE SDK)。
cd $SNPE_ROOT/models/inception_v3/
adb shell "mkdir -p /data/local/tmp/inception_v3_udo/dsp"
adb push SoftmaxUdoPackage/libs/dsp_v68/*.so /data/local/tmp/inception_v3_udo/dsp
adb push SoftmaxUdoPackage/libs/arm64-v8a/libUdoSoftmaxUdoPackageReg.so /data/local/tmp/inception_v3_udo/dsp # Pushes reg lib
然后设置所需的环境变量并在设备上运行 snpe-net-run :
adb shell
cd /data/local/tmp/inception_v3_udo/
export LD_LIBRARY_PATH=/data/local/tmp/inception_v3_udo/dsp/:$LD_LIBRARY_PATH
export ADSP_LIBRARY_PATH="/data/local/tmp/inception_v3_udo/dsp/;/data/local/tmp/snpeexample/dsp/lib;/system/lib/rfsa/adsp;/system/vendor/lib/rfsa/adsp;/dsp"
snpe-net-run --container inception_v3_udo_quantized.dlc --input_list target_raw_list.txt --udo_package_path dsp/libUdoSoftmaxUdoPackageReg.so --use_dsp
AIP执行
由于 HTA 硬件不支持 UDO,因此在 AIP 运行时执行默认为 DSP UDO 实现。HTA 硬件仅在量化模型上运行,因此与 DSP 运行时一样,将使用量化模型。
注意:在下面的命令中,应该使用在Model DLC Conversion生成的输入 dlc 。还要在参数“udo_package_path”下提供编译 x86 主机后生成的注册库的路径。可以在此处找到有关编译 x86 的更多信息。
为 AIP 量化 DLC 的命令是:
cd $SNPE_ROOT/models/inception_v3/
snpe-dlc-quantize --input_dlc dlc/inception_v3_udo.dlc --input_list data/cropped/raw_list.txt --udo_package_path SoftmaxUdoPackage/libs/x86-64_linux_clang/libUdoSoftmaxUdoPackageReg.so --output_dlc dlc/inception_v3_udo_quantized.dlc --enable_hta
现在将量化模型推送到设备:
adb push dlc/inception_v3_udo_quantized.dlc /data/local/tmp/inception_v3_udo
在使用 AIP 运行时执行之前,使用以下命令将 DSP 的 SNPE 库推送到设备:
adb shell "mkdir -p /data/local/tmp/snpeexample/dsp/lib"
adb push $SNPE_ROOT/lib/dsp/*.so /data/local/tmp/snpeexample/dsp/lib
现在将特定于 DSP 的 UDO 库推送到设备。根据配置中指定的 DSP 架构,dsp_v68目录可以是dsp_v60或dsp(使用较旧的 SNPE SDK)。
cd $SNPE_ROOT/models/inception_v3/
adb shell "mkdir -p /data/local/tmp/inception_v3_udo/dsp"
adb push SoftmaxUdoPackage/libs/dsp_v68/*.so /data/local/tmp/inception_v3_udo/dsp
adb push SoftmaxUdoPackage/libs/arm64-v8a/libUdoSoftmaxUdoPackageReg.so /data/local/tmp/inception_v3_udo/dsp # Pushes reg lib
然后设置所需的环境变量并在设备上运行 snpe-net-run :
adb shell
cd /data/local/tmp/inception_v3_udo/
export LD_LIBRARY_PATH=/data/local/tmp/inception_v3_udo/dsp/:$LD_LIBRARY_PATH
export ADSP_LIBRARY_PATH="/data/local/tmp/inception_v3_udo/dsp/;/data/local/tmp/snpeexample/dsp/lib;/system/lib/rfsa/adsp;/system/vendor/lib/rfsa/adsp;/dsp"
snpe-net-run --container inception_v3_udo_quantized.dlc --input_list target_raw_list.txt --udo_package_path dsp/libUdoSoftmaxUdoPackageReg.so --use_aip
与 Android APK 整合
本教程的这一部分概述了如何将 SNPE UDO 库和用于包注册的 Java API 集成到 Android 应用程序中。通常,要使应用程序可以发现本机共享库,它们必须放在项目中
<project>/app/src/main/jniLibs/<platform_abi>
一旦应用程序可以访问这些库,就可以使用提供的Java API注册注册库。将使用示例图像分类器应用程序复制此过程。以下假设已遵循示例应用程序设置的其余部分。本教程将为具有 arm64-v8a ABI 的平台发布说明。
首先,创建包含 UDO 库的必要目录。以下步骤将填充所有运行时实现库。
mkdir app/src/main/jniLibs/
cp -a $SNPE_ROOT/models/inception_v3/SoftmaxUdoPackage/libs/arm64-v8a/ app/src/main/jniLibs/
如果要使用 DSP 作为运行时,复制实现库如下:
cp $SNPE_ROOT/models/inception_v3/SoftmaxUdoPackage/libs/dsp/*.so app/src/main/jniLibs/arm64-v8a/
如果尚未完成,运行setup_inceptionv3.sh会将启用 UDO 的 Inception-V3 模型添加到项目中。
bash ./setup_inceptionv3.sh
现在可以注册 Java API。编辑文件 $SNPE_ROOT/examples/android/image-classifiers/app/src/main/java/com/qualcomm/qti/snpe/imageclassifiers/tasks/LoadNetworkTask.java
包含这一行
@Override
protected NeuralNetwork doInBackground(File... params) {
NeuralNetwork network = null;
try {
SNPE.addOpPackage(mApplication,"libUdoSoftmaxUdoPackageReg.so"); // Add this line to register package
final SNPE.NeuralNetworkBuilder builder = new SNPE.NeuralNetworkBuilder(mApplication)
...
现在可以构建和运行 APK
./gradlew assembleDebug