使用 Qualcomm AI Engine Direct 后端构建和运行 ExecuTorch¶
在本教程中,我们将引导您完成入门过程 为 Qualcomm AI Engine Direct 构建 ExecuTorch 并在其上运行模型。
Qualcomm AI Engine Direct 在源代码和文档中也称为 QNN。
在本教程中,您将学习如何降低和部署 Qualcomm AI Engine Direct 的模型。
什么是 Qualcomm AI Engine Direct?¶
Qualcomm AI Engine Direct 旨在为 AI 开发提供统一的低级 API。
开发人员可以使用这组 API 与 Qualcomm SoC 上的各种加速器进行交互,包括 Kryo CPU、Adreno GPU 和 Hexagon 处理器。更多详情可在此处找到。
目前,此 ExecuTorch 后端可以通过 Qualcomm AI Engine Direct API 将 AI 计算委托给 Hexagon 处理器。
先决条件 (硬件和软件)¶
主机操作系统¶
QNN 后端验证的 Linux 主机操作系统为 Ubuntu 22.04 LTS x64 在更新本教程时。 通常,我们会在验证 QNN 的同一操作系统版本上验证后端。 该版本记录在 QNN SDK 中。
硬件:¶
您需要一部连接了 adb 的 Android 智能手机,在以下 Qualcomm SoC 之一上运行:
SM8450(骁龙 8 第 1 代)
SM8475 (骁龙 8 Gen 1+)
SM8550(骁龙 8 第 2 代)
SM8650(骁龙 8 第 3 代)
此示例使用 SM8550 和 SM8450 进行了验证。
软件:¶
遵循 ExecuTorch 推荐的 Python 版本。
用于编译 AOT 部分的编译器,例如 GCC 编译器附带 Ubuntu LTS。
Android NDK 的此示例已通过 NDK 26c 进行验证。
-
单击“获取软件”按钮下载 QNN SDK 版本。
但在更新本教程时,上述网站不提供高于 2.22.6 的 QNN SDK。
以下是下载各种 QNN 版本的公共链接。希望他们很快就能被公开发现。
已安装 Qualcomm AI Engine Direct 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
指 Qualcomm AI Engine Direct SDK 的根,
即包含 .QNN_README.txt
$ANDROID_NDK_ROOT
是指 Android NDK 的根。
$EXECUTORCH_ROOT
引用 executorch git 仓库的根目录。
设置环境变量¶
我们设置以确保动态链接器可以找到 QNN 库。LD_LIBRARY_PATH
此外,我们设置了 因为开发和导入 ExecuTorch 更容易
Python API 的 API 中。PYTHONPATH
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 才能将模型编译为 Qualcomm AI Engine Direct 二进制文件。
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 库和 .
我们将以下两个路径设置为 environment variable:libqnn_executorch_backend.so
LD_LIBRARY_PATH
$QNN_SDK_ROOT/lib/x86_64-linux-clang/
$EXECUTORCH_ROOT/build-x86/lib/
第一个路径适用于 QNN 库,包括 HTP 仿真器。已在 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
在配备 Qualcomm 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。我们还需要在 Android 和 Hexagon 上指示动态链接器
通过设置 和 在何处查找这些库。
所以,我们可以像ADSP_LIBRARY_PATH
LD_LIBRARY_PATH
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 编写的。
模型、输入和输出位置由 、 和 传递给 。qnn_executorch_runner
--model_path
--input_list_path
--output_folder_path
支持的型号列表¶
请参阅和参阅支持的型号列表。$EXECUTORCH_ROOT/examples/qualcomm/scripts/
EXECUTORCH_ROOT/examples/qualcomm/oss_scripts/
即将发生的事情¶
提高 llama3-8B-Instruct 的性能并支持批量预填充。
我们将支持来自 Qualcomm AI Hub 的预编译二进制文件。
常见问题¶
如果您在复制本教程时遇到任何问题,请提交 github
ExecuTorch 存储库和标签 use 标签上的问题#qcom_aisw