使用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开发提供统一的、底层APIs。
开发人员可以使用这些API与Qualcomm SoCs上的各种加速器进行交互,包括 Kryo CPU、Adreno GPU和Hexagon处理器。更多详情请参见这里。
目前,此 ExecuTorch 后端可通过 Qualcomm AI Engine Direct 接口将 AI 计算委托给 Hexagon 处理器。
前提条件(硬件和软件)¶
主机操作系统¶
QNN Backend 验证所使用的 Linux 主机操作系统是 Ubuntu 22.04 LTS x64,这是在更新本教程时的情况。通常,我们会在与 QNN 验证所使用的相同操作系统版本上验证后端。该版本在 QNN SDK 中有文档记录。
Hardware:¶
你需要一部搭载以下 Qualcomm SoC 之一并已连接 adb 的 Android 智能手机:
SM8450(骁龙 8 Gen 1)
SM8475(骁龙 8 Gen 1+)
SM8550(骁龙 8 Gen 2)
SM8650(骁龙 8 Gen 3)
此示例已在 SM8550 和 SM8450 上验证。
Software:¶
遵循 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 仓库的根目录。
设置环境变量¶
我们设置 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 (提前编译) 组件:¶
Python 在 x64 上的 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
Runtime:¶
一个示例 qnn_executor_runner 可执行文件将用于运行编译后的 pte 模型。
构建 qnn_executor_runner 的命令 for Android:
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/
第一条路径是用于 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
在搭载高通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>
The <device_serial> can be found by adb devices command.
在上述命令执行后,预处理的输入和输出将存放在 $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 提供的预编译二进制文件。
FAQ¶
如果您在复现教程时遇到任何问题,请在ExecuTorch仓库中提交一个github issue并标记使用 #qcom_aisw 标签