使用高通 AI 引擎直连后端构建和运行 ExecuTorch¶
在本教程中,我们将引导您完成构建适用于高通 AI 引擎直连的 ExecuTorch 并在其上运行模型的过程。
高通 AI 引擎直连在源代码和文档中也称为 QNN。
在本教程中,您将学习如何为高通 AI 引擎直连降低和部署模型。
什么是高通 AI 引擎直连?¶
高通 AI 引擎直连 旨在为 AI 开发提供统一的低级 API。
开发人员可以使用这些 API 与高通 SoC 上的各种加速器进行交互,包括 Kryo CPU、Adreno GPU 和 Hexagon 处理器。更多详细信息请参见 此处。
目前,此 ExecuTorch 后端可以通过高通 AI 引擎直连 API 将 AI 计算委托给 Hexagon 处理器。
先决条件(硬件和软件)¶
主机操作系统¶
目前,QNN 后端经过验证的 Linux 主机操作系统是 Ubuntu 22.04 LTS x64(更新本教程时)。通常,我们在与 QNN 验证相同的 OS 版本上验证后端。版本记录在 QNN SDK 中。
硬件:¶
您需要一部通过 adb 连接的 Android 智能手机,并在以下 Qualcomm SoC 之一上运行
SM8450(骁龙 8 Gen 1)
SM8475(骁龙 8 Gen 1+)
SM8550(骁龙 8 Gen 2)
SM8650(骁龙 8 Gen 3)
此示例已通过 SM8550 和 SM8450 验证。
软件:¶
遵循 ExecuTorch 推荐的 Python 版本。
用于编译 AOT 部分的编译器,例如,Ubuntu LTS 附带的 GCC 编译器。
Android NDK。此示例已通过 NDK 26c 验证。
-
单击“获取软件”按钮下载 QNN SDK 版本。
但是,在更新本教程时,上述网站提供的 QNN SDK 版本不高于 2.22.6。
以下是下载各种 QNN 版本的公共链接。希望它们很快就能公开发现。
安装了高通 AI 引擎直连 SDK 的目录如下所示
├── benchmarks
├── bin
├── docs
├── examples
├── include
├── lib
├── LICENSE.pdf
├── NOTICE.txt
├── NOTICE_WINDOWS.txt
├── QNN_NOTICE.txt
├── QNN_README.txt
├── QNN_ReleaseNotes.txt
├── ReleaseNotes.txt
├── ReleaseNotesWindows.txt
├── sdk.yaml
└── share
设置您的开发环境¶
约定¶
$QNN_SDK_ROOT
指的是高通 AI 引擎直连 SDK 的根目录,即包含 QNN_README.txt
的目录。
$ANDROID_NDK_ROOT
指的是 Android NDK 的根目录。
$EXECUTORCH_ROOT
指的是 executorch git 存储库的根目录。
设置环境变量¶
我们设置 LD_LIBRARY_PATH
以确保动态链接器可以找到 QNN 库。
此外,我们设置 PYTHONPATH
,因为这更容易开发和导入 ExecuTorch Python API。
export LD_LIBRARY_PATH=$QNN_SDK_ROOT/lib/x86_64-linux-clang/:$LD_LIBRARY_PATH
export PYTHONPATH=$EXECUTORCH_ROOT/..
构建¶
以下构建说明的示例脚本在此处。我们建议使用此脚本,因为 ExecuTorch 构建命令可能会不时更改。上述脚本正在积极使用。它更新频率高于本教程。示例用法为
cd $EXECUTORCH_ROOT
./backends/qualcomm/scripts/build.sh
# or
./backends/qualcomm/scripts/build.sh --release
AOT(提前)组件:¶
需要 x64 上的 Python API 来将模型编译为高通 AI 引擎直连二进制文件。
cd $EXECUTORCH_ROOT
mkdir build-x86
cd build-x86
# Note that the below command might change.
# Please refer to the above build.sh for latest workable commands.
cmake .. \
-DCMAKE_INSTALL_PREFIX=$PWD \
-DEXECUTORCH_BUILD_QNN=ON \
-DQNN_SDK_ROOT=${QNN_SDK_ROOT} \
-DEXECUTORCH_BUILD_DEVTOOLS=ON \
-DEXECUTORCH_BUILD_EXTENSION_MODULE=ON \
-DEXECUTORCH_BUILD_EXTENSION_TENSOR=ON \
-DEXECUTORCH_ENABLE_EVENT_TRACER=ON \
-DPYTHON_EXECUTABLE=python3 \
-DEXECUTORCH_SEPARATE_FLATCC_HOST_PROJECT=OFF
# nproc is used to detect the number of available CPU.
# If it is not applicable, please feel free to use the number you want.
cmake --build $PWD --target "PyQnnManagerAdaptor" "PyQnnWrapperAdaptor" -j$(nproc)
# install Python APIs to correct import path
# The filename might vary depending on your Python and host version.
cp -f backends/qualcomm/PyQnnManagerAdaptor.cpython-310-x86_64-linux-gnu.so $EXECUTORCH_ROOT/backends/qualcomm/python
cp -f backends/qualcomm/PyQnnWrapperAdaptor.cpython-310-x86_64-linux-gnu.so $EXECUTORCH_ROOT/backends/qualcomm/python
# Workaround for fbs files in exir/_serialize
cp $EXECUTORCH_ROOT/schema/program.fbs $EXECUTORCH_ROOT/exir/_serialize/program.fbs
cp $EXECUTORCH_ROOT/schema/scalar_type.fbs $EXECUTORCH_ROOT/exir/_serialize/scalar_type.fbs
运行时:¶
示例 qnn_executor_runner
可执行文件将用于运行编译后的 pte
模型。
用于 Android 构建 qnn_executor_runner
的命令
cd $EXECUTORCH_ROOT
mkdir build-android
cd build-android
# build executorch & qnn_executorch_backend
cmake .. \
-DCMAKE_INSTALL_PREFIX=$PWD \
-DEXECUTORCH_BUILD_QNN=ON \
-DQNN_SDK_ROOT=$QNN_SDK_ROOT \
-DEXECUTORCH_BUILD_DEVTOOLS=ON \
-DEXECUTORCH_BUILD_EXTENSION_MODULE=ON \
-DEXECUTORCH_BUILD_EXTENSION_TENSOR=ON \
-DEXECUTORCH_ENABLE_EVENT_TRACER=ON \
-DPYTHON_EXECUTABLE=python3 \
-DCMAKE_TOOLCHAIN_FILE=$ANDROID_NDK_ROOT/build/cmake/android.toolchain.cmake \
-DANDROID_ABI='arm64-v8a' \
-DANDROID_NATIVE_API_LEVEL=23
# nproc is used to detect the number of available CPU.
# If it is not applicable, please feel free to use the number you want.
cmake --build $PWD --target install -j$(nproc)
cmake ../examples/qualcomm \
-DCMAKE_TOOLCHAIN_FILE=$ANDROID_NDK_ROOT/build/cmake/android.toolchain.cmake \
-DANDROID_ABI='arm64-v8a' \
-DANDROID_NATIVE_API_LEVEL=23 \
-DCMAKE_PREFIX_PATH="$PWD/lib/cmake/ExecuTorch;$PWD/third-party/gflags;" \
-DCMAKE_FIND_ROOT_PATH_MODE_PACKAGE=BOTH \
-DPYTHON_EXECUTABLE=python3 \
-Bexamples/qualcomm
cmake --build examples/qualcomm -j$(nproc)
# qnn_executor_runner can be found under examples/qualcomm
# The full path is $EXECUTORCH_ROOT/build-android/examples/qualcomm/qnn_executor_runner
ls examples/qualcomm
**注意:**如果您想构建发布版本,请将 -DCMAKE_BUILD_TYPE=Release
添加到 cmake
命令选项中。
在设备上部署和运行¶
AOT 编译模型¶
有关确切流程,请参阅 此脚本。在本教程中,我们使用 deeplab-v3-resnet101 作为示例。运行以下命令进行编译
cd $EXECUTORCH_ROOT
python -m examples.qualcomm.scripts.deeplab_v3 -b build-android -m SM8550 --compile_only --download
您可能会看到如下内容
[INFO][Qnn ExecuTorch] Destroy Qnn context
[INFO][Qnn ExecuTorch] Destroy Qnn device
[INFO][Qnn ExecuTorch] Destroy Qnn backend
opcode name target args kwargs
------------- ------------------------ --------------------------- ----------------------------- --------
placeholder arg684_1 arg684_1 () {}
get_attr lowered_module_0 lowered_module_0 () {}
call_function executorch_call_delegate executorch_call_delegate (lowered_module_0, arg684_1) {}
call_function getitem <built-in function getitem> (executorch_call_delegate, 0) {}
call_function getitem_1 <built-in function getitem> (executorch_call_delegate, 1) {}
output output output ([getitem_1, getitem],) {}
编译后的模型为 ./deeplab_v3/dlv3_qnn.pte
。
在 QNN HTP 模拟器上测试模型推理¶
在将模型部署到设备之前,我们可以通过 HTP 模拟器测试模型推理。
让我们为 x64 主机构建 qnn_executor_runner
# assuming the AOT component is built.
cd $EXECUTORCH_ROOT/build-x86
cmake ../examples/qualcomm \
-DCMAKE_PREFIX_PATH="$PWD/lib/cmake/ExecuTorch;$PWD/third-party/gflags;" \
-DCMAKE_FIND_ROOT_PATH_MODE_PACKAGE=BOTH \
-DPYTHON_EXECUTABLE=python3 \
-Bexamples/qualcomm
cmake --build examples/qualcomm -j$(nproc)
# qnn_executor_runner can be found under examples/qualcomm
# The full path is $EXECUTORCH_ROOT/build-x86/examples/qualcomm/qnn_executor_runner
ls examples/qualcomm/
要运行 HTP 模拟器,动态链接器需要访问 QNN 库和 libqnn_executorch_backend.so
。我们将以下两个路径设置为 LD_LIBRARY_PATH
环境变量
$QNN_SDK_ROOT/lib/x86_64-linux-clang/
$EXECUTORCH_ROOT/build-x86/lib/
第一个路径用于包含HTP模拟器的QNN库。它已在AOT编译部分配置。
第二个路径用于 libqnn_executorch_backend.so
。
因此,我们可以通过以下方式运行 ./deeplab_v3/dlv3_qnn.pte
cd $EXECUTORCH_ROOT/build-x86
export LD_LIBRARY_PATH=$EXECUTORCH_ROOT/build-x86/lib/:$LD_LIBRARY_PATH
examples/qualcomm/qnn_executor_runner --model_path ../deeplab_v3/dlv3_qnn.pte
我们应该看到如下一些输出。请注意,模拟器可能需要一些时间才能完成。
I 00:00:00.354662 executorch:qnn_executor_runner.cpp:213] Method loaded.
I 00:00:00.356460 executorch:qnn_executor_runner.cpp:261] ignoring error from set_output_data_ptr(): 0x2
I 00:00:00.357991 executorch:qnn_executor_runner.cpp:261] ignoring error from set_output_data_ptr(): 0x2
I 00:00:00.357996 executorch:qnn_executor_runner.cpp:265] Inputs prepared.
I 00:01:09.328144 executorch:qnn_executor_runner.cpp:414] Model executed successfully.
I 00:01:09.328159 executorch:qnn_executor_runner.cpp:421] Write etdump to etdump.etdp, Size = 424
[INFO] [Qnn ExecuTorch]: Destroy Qnn backend parameters
[INFO] [Qnn ExecuTorch]: Destroy Qnn context
[INFO] [Qnn ExecuTorch]: Destroy Qnn device
[INFO] [Qnn ExecuTorch]: Destroy Qnn backend
在搭载高通SoC的Android智能手机上运行模型推理¶
步骤1. 我们需要将所需的QNN库推送到设备。
# make sure you have write-permission on below path.
DEVICE_DIR=/data/local/tmp/executorch_qualcomm_tutorial/
adb shell "mkdir -p ${DEVICE_DIR}"
adb push ${QNN_SDK_ROOT}/lib/aarch64-android/libQnnHtp.so ${DEVICE_DIR}
adb push ${QNN_SDK_ROOT}/lib/aarch64-android/libQnnSystem.so ${DEVICE_DIR}
adb push ${QNN_SDK_ROOT}/lib/aarch64-android/libQnnHtpV69Stub.so ${DEVICE_DIR}
adb push ${QNN_SDK_ROOT}/lib/aarch64-android/libQnnHtpV73Stub.so ${DEVICE_DIR}
adb push ${QNN_SDK_ROOT}/lib/aarch64-android/libQnnHtpV75Stub.so ${DEVICE_DIR}
adb push ${QNN_SDK_ROOT}/lib/hexagon-v69/unsigned/libQnnHtpV69Skel.so ${DEVICE_DIR}
adb push ${QNN_SDK_ROOT}/lib/hexagon-v73/unsigned/libQnnHtpV73Skel.so ${DEVICE_DIR}
adb push ${QNN_SDK_ROOT}/lib/hexagon-v75/unsigned/libQnnHtpV75Skel.so ${DEVICE_DIR}
步骤2. 我们还需要通过设置 ADSP_LIBRARY_PATH
和 LD_LIBRARY_PATH
来指示Android和Hexagon上的动态链接器在哪里可以找到这些库。因此,我们可以像这样运行 qnn_executor_runner
adb push ./deeplab_v3/dlv3_qnn.pte ${DEVICE_DIR}
adb push ${EXECUTORCH_ROOT}/build-android/examples/qualcomm/executor_runner/qnn_executor_runner ${DEVICE_DIR}
adb push ${EXECUTORCH_ROOT}/build-android/lib/libqnn_executorch_backend.so ${DEVICE_DIR}
adb shell "cd ${DEVICE_DIR} \
&& export LD_LIBRARY_PATH=${DEVICE_DIR} \
&& export ADSP_LIBRARY_PATH=${DEVICE_DIR} \
&& ./qnn_executor_runner --model_path ./dlv3_qnn.pte"
您应该会看到如下内容
I 00:00:00.257354 executorch:qnn_executor_runner.cpp:213] Method loaded.
I 00:00:00.323502 executorch:qnn_executor_runner.cpp:262] ignoring error from set_output_data_ptr(): 0x2
I 00:00:00.357496 executorch:qnn_executor_runner.cpp:262] ignoring error from set_output_data_ptr(): 0x2
I 00:00:00.357555 executorch:qnn_executor_runner.cpp:265] Inputs prepared.
I 00:00:00.364824 executorch:qnn_executor_runner.cpp:414] Model executed successfully.
I 00:00:00.364875 executorch:qnn_executor_runner.cpp:425] Write etdump to etdump.etdp, Size = 424
[INFO] [Qnn ExecuTorch]: Destroy Qnn backend parameters
[INFO] [Qnn ExecuTorch]: Destroy Qnn context
[INFO] [Qnn ExecuTorch]: Destroy Qnn backend
模型仅被执行。如果我们想提供真实的输入并获取模型输出,我们可以使用
cd $EXECUTORCH_ROOT
python -m examples.qualcomm.scripts.deeplab_v3 -b build-android -m SM8550 --download -s <device_serial>
<device_serial>
可以通过 adb devices
命令找到。
执行上述命令后,预处理的输入和输出将分别放置在 $EXECUTORCH_ROOT/deeplab_v3
和 $EXECUTORCH_ROOT/deeplab_v3/outputs
文件夹中。
命令行参数在 utils.py 中编写。模型、输入和输出位置通过 --model_path
、--input_list_path
和 --output_folder_path
传递给 qnn_executorch_runner
。
支持的模型列表¶
请参考 $EXECUTORCH_ROOT/examples/qualcomm/scripts/
和 EXECUTORCH_ROOT/examples/qualcomm/oss_scripts/
以获取支持的模型列表。
常见问题解答¶
如果您在重现教程时遇到任何问题,请在ExecuTorch存储库中提交GitHub问题,并使用 #qcom_aisw
标签