Skip to content

Commit 3f9b39e

Browse files
authored
Qualcomm AI Engine Direct -- update documents
Differential Revision: D61026763 Pull Request resolved: #4590
1 parent e4897dd commit 3f9b39e

File tree

8 files changed

+203
-262
lines changed

8 files changed

+203
-262
lines changed

backends/qualcomm/README.md

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
11
# Qualcomm AI Engine Direct Backend
22

33
Disclaimer: At present, we do not offer any backward compatibility guarantees
4-
for any APIs. We are currently in a pre-alpha development phase, and as such,
4+
for any APIs. We are currently in a development phase, and as such,
55
we reserve the right to modify interfaces and implementations.
66

77
This backend is implemented on the top of
88
[Qualcomm AI Engine Direct SDK](https://developer.qualcomm.com/software/qualcomm-ai-engine-direct-sdk).
9-
Please follow [tutorial](https://pytorch.org/executorch/stable/build-run-qualcomm-ai-engine-direct-backend.html) to setup environment, build, and run executorch models by this backend (Qualcomm AI Engine Direct is also referred to as QNN in the source and documentation).
9+
Please follow [tutorial](../../docs/source/build-run-qualcomm-ai-engine-direct-backend.md) to setup environment, build, and run executorch models by this backend (Qualcomm AI Engine Direct is also referred to as QNN in the source and documentation).
10+
11+
A website version of the tutorial is [here](https://pytorch.org/executorch/stable/build-run-qualcomm-ai-engine-direct-backend.html).
1012

1113
## Delegate Options
1214

@@ -29,7 +31,7 @@ Add SoC model into QcomChipset enum in [schema](./serialization/schema.fbs) and
2931
Insert new SoC information into _soc_info_table in [qnn_compile_spec_schema](./serialization/qnn_compile_spec_schema.py).
3032

3133
#### Step 3: Recompile the .pte file
32-
Follow [setup](setup.md) to setup environment and build runtime with new schema header.
34+
Follow [setup](../../docs/source/build-run-qualcomm-ai-engine-direct-backend.md) to setup environment and build runtime with new schema header.
3335

3436
### Supported Inference Type
3537
- Quantized
@@ -46,6 +48,7 @@ backends/qualcomm
4648
├── partition # QNN Partitioner (AoT Part).
4749
├── passes # Various passes helping lower models to QNN backend (AoT Part).
4850
├── python # Places to put pybind artifacts for accessing QNN APIs, structures, etc (AoT Part).
51+
├── quantizer # QNN Quantizer
4952
├── runtime # Here is QNN runtime responsbile for compiling a model on x64.
5053
| | # Meanwhile, this is also the runtime responsbile for executing compiled
5154
| | # models on a device.

backends/qualcomm/scripts/build.sh

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ usage() {
1616
echo "Usage: Build the aarch64 version of executor runner or the python interface of Qnn Manager"
1717
echo "First, you need to set the environment variable for QNN_SDK_ROOT"
1818
echo ", and if you want to build the aarch64 version of executor runner"
19-
echo ", you need to set ANDROID_NDK_ROOT"
19+
echo ", you need to export ANDROID_NDK_ROOT=/path/to/android_ndkXX"
2020
echo "e.g.: executorch$ ./backends/qualcomm/scripts/build.sh --skip_x86_64"
2121
exit 1
2222
}
@@ -25,9 +25,9 @@ usage() {
2525
[ "$1" = -h ] && usage
2626

2727
BUILD_X86_64="true"
28-
CMAKE_X86_64="build_x86_64"
28+
CMAKE_X86_64="cmake-out"
2929
BUILD_AARCH64="true"
30-
CMAKE_AARCH64="build_android"
30+
CMAKE_AARCH64="cmake-out-android"
3131
CLEAN="true"
3232
BUILD_TYPE="Debug"
3333
BUILD_JOB_NUMBER="16"
@@ -61,7 +61,7 @@ PRJ_ROOT="$( cd "$(dirname "$0")/../../.." ; pwd -P)"
6161

6262
if [ "$BUILD_AARCH64" = true ]; then
6363
if [[ -z ${ANDROID_NDK_ROOT} ]]; then
64-
echo "Please export ANDROID_NDK_ROOT=/path/to/android_ndk"
64+
echo "Please export ANDROID_NDK_ROOT=/path/to/android_ndkXX"
6565
exit -1
6666
fi
6767
BUILD_ROOT=$PRJ_ROOT/$CMAKE_AARCH64

backends/qualcomm/setup.md

Lines changed: 3 additions & 185 deletions
Original file line numberDiff line numberDiff line change
@@ -1,189 +1,7 @@
11
# Setting up QNN Backend
22

3-
This is a tutorial for building and running Qualcomm AI Engine Direct backend,
3+
Please refer to [Building and Running ExecuTorch with Qualcomm AI Engine Direct Backend](../../docs/source/build-run-qualcomm-ai-engine-direct-backend.md).
4+
5+
That is a tutorial for building and running Qualcomm AI Engine Direct backend,
46
including compiling a model on a x64 host and running the inference
57
on a Android device.
6-
7-
8-
## Prerequisite
9-
10-
Please finish tutorial [Setting up executorch](../../docs/source/getting-started-setup.md).
11-
12-
13-
## Conventions
14-
15-
`$QNN_SDK_ROOT` refers to the root of Qualcomm AI Engine Direct SDK,
16-
i.e., the directory containing `QNN_README.txt`.
17-
18-
`$ANDROID_NDK_ROOT` refers to the root of Android NDK.
19-
20-
`$EXECUTORCH_ROOT` refers to the root of executorch git repository.
21-
22-
23-
## Environment Setup
24-
25-
### Download Qualcomm AI Engine Direct SDK
26-
27-
Navigate to [Qualcomm AI Engine Direct SDK](https://developer.qualcomm.com/software/qualcomm-ai-engine-direct-sdk) and follow the download button.
28-
29-
You might need to apply for a Qualcomm account to download the SDK.
30-
31-
After logging in, search Qualcomm AI Stack at the *Tool* panel.
32-
You can find Qualcomm AI Engine Direct SDK under the AI Stack group.
33-
34-
Please download the Linux version, and follow instructions on the page to
35-
extract the file.
36-
37-
The SDK should be installed to somewhere `/opt/qcom/aistack/qnn` by default.
38-
39-
### Download Android NDK
40-
41-
Please navigate to [Android NDK](https://developer.android.com/ndk) and download
42-
a version of NDK. We recommend LTS version, currently r25c.
43-
44-
### Setup environment variables
45-
46-
We need to make sure Qualcomm AI Engine Direct libraries can be found by
47-
the dynamic linker on x64. Hence we set `LD_LIBRARY_PATH`. In production,
48-
we recommend users to put libraries in default search path or use `rpath`
49-
to indicate the location of libraries.
50-
51-
Further, we set up `$PYTHONPATH` because it's easier to develop and import executorch Python APIs. Users might also build and install executorch package as usual python package.
52-
53-
```bash
54-
export LD_LIBRARY_PATH=$QNN_SDK_ROOT/lib/x86_64-linux-clang/:$LD_LIBRARY_PATH
55-
export PYTHONPATH=$EXECUTORCH_ROOT/..
56-
```
57-
58-
Note: Since we set `PYTHONPATH`, we may have issue with finding `program.fbs`
59-
and `scalar_type.fbs` when we export a model, because they are installed into
60-
`pip-out` directory with the same package name pattern. A workaround is that
61-
we copy `$EXECUTORCH_ROOT/pip-out/lib.linux-x86_64-cpython-310/executorch/exir/_serialize/program.fbs`
62-
and `$EXECUTORCH_ROOT/pip-out/lib.linux-x86_64-cpython-310/executorch/exir/_serialize/scalar_type.fbs`
63-
to `$EXECUTORCH_ROOT/exir/_serialize/`.
64-
65-
66-
## End to End Inference
67-
68-
### Step 1: Build Python APIs for AOT compilation on x64
69-
70-
Python APIs on x64 are required to compile models to Qualcomm AI Engine Direct binary.
71-
Make sure `buck2` is under a directory in `PATH`.
72-
73-
```bash
74-
cd $EXECUTORCH_ROOT
75-
mkdir build_x86_64
76-
cd build_x86_64
77-
cmake .. -DEXECUTORCH_BUILD_QNN=ON -DQNN_SDK_ROOT=${QNN_SDK_ROOT}
78-
cmake --build . -t "PyQnnManagerAdaptor" "PyQnnWrapperAdaptor" -j8
79-
80-
# install Python APIs to correct import path
81-
# The filename might vary depending on your Python and host version.
82-
cp -f backends/qualcomm/PyQnnManagerAdaptor.cpython-310-x86_64-linux-gnu.so $EXECUTORCH_ROOT/backends/qualcomm/python
83-
cp -f backends/qualcomm/PyQnnWrapperAdaptor.cpython-310-x86_64-linux-gnu.so $EXECUTORCH_ROOT/backends/qualcomm/python
84-
```
85-
86-
87-
### Step 2: Build `qnn_executor_runner` for Android
88-
89-
`qnn_executor_runner` is an executable running the compiled model.
90-
91-
You might want to ensure the correct `flatc`. `flatc` can be built along with the above step. For example, we can find `flatc` in `build_x86_64/third-party/flatbuffers/`.
92-
93-
We can prepend `$EXECUTORCH_ROOT/build_x86_64/third-party/flatbuffers` to `PATH`. Then below cross-compiling can find the correct flatbuffer compiler.
94-
95-
Commands to build `qnn_executor_runner` for Android:
96-
97-
```bash
98-
cd $EXECUTORCH_ROOT
99-
mkdir build_android
100-
cd build_android
101-
# build executorch & qnn_executorch_backend
102-
cmake .. \
103-
-DCMAKE_INSTALL_PREFIX=$PWD \
104-
-DEXECUTORCH_BUILD_QNN=ON \
105-
-DEXECUTORCH_BUILD_SDK=ON \
106-
-DEXECUTORCH_ENABLE_EVENT_TRACER=ON \
107-
-DQNN_SDK_ROOT=$QNN_SDK_ROOT \
108-
-DCMAKE_TOOLCHAIN_FILE=$ANDROID_NDK_ROOT/build/cmake/android.toolchain.cmake \
109-
-DANDROID_ABI='arm64-v8a' \
110-
-DANDROID_NATIVE_API_LEVEL=23 \
111-
-B$PWD
112-
113-
cmake --build $PWD -j16 --target install
114-
115-
cmake ../examples/qualcomm \
116-
-DCMAKE_TOOLCHAIN_FILE=$ANDROID_NDK_ROOT/build/cmake/android.toolchain.cmake \
117-
-DANDROID_ABI='arm64-v8a' \
118-
-DANDROID_NATIVE_API_LEVEL=23 \
119-
-DCMAKE_PREFIX_PATH="$PWD/lib/cmake/ExecuTorch;$PWD/third-party/gflags;" \
120-
-DCMAKE_FIND_ROOT_PATH_MODE_PACKAGE=BOTH \
121-
-Bexamples/qualcomm
122-
123-
cmake --build examples/qualcomm -j16
124-
```
125-
**Note:** If you want to build for release, add `-DCMAKE_BUILD_TYPE=Release` to the `cmake` command options.
126-
127-
You can find `qnn_executor_runner` under `build_android/examples/qualcomm/`.
128-
129-
130-
### Step 3: Compile a model
131-
132-
```
133-
python -m examples.qualcomm.scripts.export_example --model_name mv2
134-
```
135-
136-
Then the generated `mv2.pte` can be run on the device by
137-
`build_android/backends/qualcomm/qnn_executor_runner` with Qualcomm AI Engine
138-
Direct backend.
139-
140-
[**Note**] To get proper accuracy, please apply calibrations with representative
141-
dataset, which could be learnt more from examples under `examples/qualcomm/`.
142-
143-
144-
### Step 4: Model Inference
145-
146-
The backend rely on Qualcomm AI Engine Direct SDK libraries.
147-
148-
You might want to follow docs in Qualcomm AI Engine Direct SDK to setup the device environment.
149-
Or see below for a quick setup for testing:
150-
151-
```bash
152-
# make sure you have write-permission on below path.
153-
DEVICE_DIR=/data/local/tmp/executorch_test/
154-
adb shell "mkdir -p ${DEVICE_DIR}"
155-
adb push ${QNN_SDK_ROOT}/lib/aarch64-android/libQnnHtp.so ${DEVICE_DIR}
156-
adb push ${QNN_SDK_ROOT}/lib/aarch64-android/libQnnHtpV69Stub.so ${DEVICE_DIR}
157-
adb push ${QNN_SDK_ROOT}/lib/aarch64-android/libQnnHtpV73Stub.so ${DEVICE_DIR}
158-
adb push ${QNN_SDK_ROOT}/lib/aarch64-android/libQnnHtpV75Stub.so ${DEVICE_DIR}
159-
adb push ${QNN_SDK_ROOT}/lib/aarch64-android/libQnnSystem.so ${DEVICE_DIR}
160-
adb push ${QNN_SDK_ROOT}/lib/hexagon-v69/unsigned/libQnnHtpV69Skel.so ${DEVICE_DIR}
161-
adb push ${QNN_SDK_ROOT}/lib/hexagon-v73/unsigned/libQnnHtpV73Skel.so ${DEVICE_DIR}
162-
adb push ${QNN_SDK_ROOT}/lib/hexagon-v75/unsigned/libQnnHtpV75Skel.so ${DEVICE_DIR}
163-
```
164-
165-
We also need to indicate dynamic linkers on Android and Hexagon where to find these libraries
166-
by setting `ADSP_LIBRARY_PATH` and `LD_LIBRARY_PATH`.
167-
168-
So, we can run `qnn_executor_runner` like
169-
```bash
170-
adb push mv2.pte ${DEVICE_DIR}
171-
adb push ${EXECUTORCH_ROOT}/build_android/examples/qualcomm/qnn_executor_runner ${DEVICE_DIR}
172-
adb shell "cd ${DEVICE_DIR} \
173-
&& export LD_LIBRARY_PATH=${DEVICE_DIR} \
174-
&& export ADSP_LIBRARY_PATH=${DEVICE_DIR} \
175-
&& ./qnn_executor_runner --model_path ./mv2_qnn.pte"
176-
```
177-
178-
You should see the following result.
179-
Note that no output file will be generated in this example.
180-
```
181-
I 00:00:00.133366 executorch:qnn_executor_runner.cpp:156] Method loaded.
182-
I 00:00:00.133590 executorch:util.h:104] input already initialized, refilling.
183-
I 00:00:00.135162 executorch:qnn_executor_runner.cpp:161] Inputs prepared.
184-
I 00:00:00.136768 executorch:qnn_executor_runner.cpp:278] Model executed successfully.
185-
[INFO][Qnn ExecuTorch] Destroy Qnn backend parameters
186-
[INFO][Qnn ExecuTorch] Destroy Qnn context
187-
[INFO][Qnn ExecuTorch] Destroy Qnn device
188-
[INFO][Qnn ExecuTorch] Destroy Qnn backend
189-
```

backends/qualcomm/tests/utils.py

Lines changed: 31 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -231,25 +231,43 @@ def validate_profile():
231231
qnn_sdk = os.environ.get("QNN_SDK_ROOT", None)
232232
assert qnn_sdk, "QNN_SDK_ROOT was not found in environment variable"
233233

234-
build_path = "build_x86_64"
235-
cmds = [
236-
# export LD_LIBRARY_PATH to QNN_SDK_ROOT
237-
f"export LD_LIBRARY_PATH={qnn_sdk}/lib/{target}/:{self.executorch_root}/{build_path}/lib && "
234+
build_folder = self.build_folder
235+
if os.path.isabs(self.build_folder):
236+
# obey user's opinion
237+
pass
238+
else:
239+
# ok, assuming the user give a relative path to cwd
240+
build_folder = os.path.join(os.getcwd(), self.build_folder)
241+
242+
cmd = [
238243
# qnn_executor_runner
239-
f"{self.executorch_root}/{build_path}/examples/qualcomm/qnn_executor_runner",
240-
f"--model_path {pte_fname}",
241-
f"--input_list_path {tmp_dir}/input_list.txt",
242-
f"--output_folder_path {output_dir}",
244+
f"{build_folder}/examples/qualcomm/qnn_executor_runner",
245+
"--model_path",
246+
f"{pte_fname}",
247+
"--input_list_path",
248+
f"{tmp_dir}/input_list.txt",
249+
"--output_folder_path",
250+
f"{output_dir}",
243251
]
244252

245-
subprocess.run(
246-
" ".join(cmds),
247-
shell=True,
248-
executable="/bin/bash",
249-
capture_output=True,
253+
env = dict(os.environ)
254+
env["LD_LIBRARY_PATH"] = f"{qnn_sdk}/lib/{target}/:{build_folder}/lib"
255+
proc = subprocess.run(
256+
cmd,
257+
stdout=subprocess.PIPE,
258+
stderr=subprocess.STDOUT,
259+
env=env,
250260
cwd=tmp_dir,
251261
)
252262

263+
self.assertEqual(
264+
proc.returncode,
265+
0,
266+
f"The process running qnn_executorch_runner return {proc.returncode}, "
267+
"STDOUT=\n"
268+
f"{proc.stdout.decode('utf-8')}",
269+
)
270+
253271
# Verify the outputs
254272
post_process()
255273
self._assert_outputs_equal(outputs, ref_outputs)

0 commit comments

Comments
 (0)