Skip to content

[Android demo] Decouple pte file from assets and remove unused #8906

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Mar 5, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion build/build_android_library.sh
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,9 @@ collect_artifacts_to_be_uploaded() {
}

main() {
BUILD_AAR_DIR="$(mktemp -d)"
if [[ -z "${BUILD_AAR_DIR:-}" ]]; then
BUILD_AAR_DIR="$(mktemp -d)"
fi
export BUILD_AAR_DIR
if [ -z "$ANDROID_ABIS" ]; then
ANDROID_ABIS=("arm64-v8a" "x86_64")
Expand Down
139 changes: 36 additions & 103 deletions examples/demo-apps/android/ExecuTorchDemo/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,9 +39,14 @@ We generate the model file for the ExecuTorch runtime in Android Demo App.
For delegating DeepLab v3 to XNNPACK backend, please do the following to export the model:

```bash
cd executorch # go to executorch root
python3 -m examples.xnnpack.aot_compiler --model_name="dl3" --delegate
mkdir -p examples/demo-apps/android/ExecuTorchDemo/app/src/main/assets/
cp dl3_xnnpack_fp32.pte examples/demo-apps/android/ExecuTorchDemo/app/src/main/assets/
```

Then push the pte file to Android device:

```bash
adb push dl3_xnnpack_fp32.pte /data/local/tmp/dl3_xnnpack_fp32.pte
```

For more detailed tutorial of lowering to XNNPACK, please see [XNNPACK backend](backends-xnnpack.md).
Expand All @@ -50,135 +55,63 @@ For more detailed tutorial of lowering to XNNPACK, please see [XNNPACK backend](

For delegating to Qualcomm Hexagon NPU, please follow the tutorial [here](backends-qualcomm.md).

After generating the model, copy the model to `assets` directory.

```bash
python -m examples.qualcomm.scripts.deeplab_v3 -b build-android -m SM8450 -s <adb_connected_device_serial>
cp deeplab_v3/dlv3_qnn.pte examples/demo-apps/android/ExecuTorchDemo/app/src/main/assets/
```

Then push the pte file to Android device:

```bash
adb push deeplab_v3/dlv3_qnn.pte /data/local/tmp/dlv3_qnn.pte
```

### Runtime

We build the required ExecuTorch runtime library to run the model.
We build the required ExecuTorch runtime library (AAR) to run the model.

#### XNNPACK

1. Build the CMake target for the library with XNNPACK backend:

```bash
# go to ExecuTorch repo root
export ANDROID_NDK=<path-to-android-ndk>
export ANDROID_ABI=arm64-v8a
export ANDROID_ABIS=arm64-v8a

# Run the following lines from the `executorch/` folder
./install_executorch.sh --clean
mkdir cmake-android-out

# Build the core executorch library
cmake . -DCMAKE_INSTALL_PREFIX=cmake-android-out \
-DCMAKE_TOOLCHAIN_FILE="${ANDROID_NDK}/build/cmake/android.toolchain.cmake" \
-DANDROID_ABI="${ANDROID_ABI}" \
-DEXECUTORCH_BUILD_XNNPACK=ON \
-DEXECUTORCH_BUILD_EXTENSION_DATA_LOADER=ON \
-DEXECUTORCH_BUILD_EXTENSION_MODULE=ON \
-DEXECUTORCH_BUILD_EXTENSION_RUNNER_UTIL=ON \
-DEXECUTORCH_BUILD_EXTENSION_TENSOR=ON \
-Bcmake-android-out

cmake --build cmake-android-out -j16 --target install
```

When we set `EXECUTORCH_BUILD_XNNPACK=ON`, we will build the target [`xnnpack_backend`](https://github.com/pytorch/executorch/blob/main/backends/xnnpack/CMakeLists.txt) which in turn is linked into libexecutorch_jni via [CMake](https://github.com/pytorch/executorch/blob/main/examples/demo-apps/android/jni/CMakeLists.txt).

2. Build the Android extension:

```bash

# Build the android extension
cmake extension/android \
-DCMAKE_TOOLCHAIN_FILE="${ANDROID_NDK}"/build/cmake/android.toolchain.cmake \
-DANDROID_ABI="${ANDROID_ABI}" \
-DCMAKE_INSTALL_PREFIX=cmake-android-out \
-Bcmake-android-out/extension/android
# Create a new directory `app/libs` for the AAR to live
pushd examples/demo-apps/android/ExecuTorchDemo
mkdir -p app/libs
popd

cmake --build cmake-android-out/extension/android -j16
# Build the AAR. It will include XNNPACK backend by default.
export BUILD_AAR_DIR=$(realpath examples/demo-apps/android/ExecuTorchDemo/app/libs)
sh build/build_android_library.sh
```

`libexecutorch_jni.so` wraps up the required XNNPACK Backend runtime library from `xnnpack_backend`, and adds an additional JNI layer using fbjni. This is later exposed to Java app.

#### Qualcomm Hexagon NPU

1. Build the CMake target for the library with Qualcomm Hexagon NPU (HTP) backend (XNNPACK also included):

```bash
# go to ExecuTorch repo root
export ANDROID_NDK=<path-to-android-ndk>
export ANDROID_ABI=arm64-v8a
export QNN_SDK_ROOT=<path-to-qnn-sdk>
export ANDROID_ABIS=arm64-v8a
export QNN_SDK_ROOT=<path-to-qnn-sdk-root>

# Run the following lines from the `executorch/` folder
./install_executorch.sh --clean
mkdir cmake-android-out
cmake . -DCMAKE_INSTALL_PREFIX=cmake-android-out \
-DCMAKE_TOOLCHAIN_FILE="${ANDROID_NDK}/build/cmake/android.toolchain.cmake" \
-DANDROID_ABI="${ANDROID_ABI}" \
-DEXECUTORCH_BUILD_XNNPACK=ON \
-DEXECUTORCH_BUILD_QNN=ON \
-DQNN_SDK_ROOT="${QNN_SDK_ROOT}" \
-DEXECUTORCH_BUILD_EXTENSION_DATA_LOADER=ON \
-DEXECUTORCH_BUILD_EXTENSION_MODULE=ON \
-DEXECUTORCH_BUILD_EXTENSION_RUNNER_UTIL=ON \
-DEXECUTORCH_BUILD_EXTENSION_TENSOR=ON \
-Bcmake-android-out

cmake --build cmake-android-out -j16 --target install
```
Similar to the XNNPACK library, with this setup, we compile `libexecutorch_jni.so` but it adds an additional static library `qnn_executorch_backend` which wraps up Qualcomm HTP runtime library and registers the Qualcomm HTP backend. This is later exposed to Java app.

`qnn_executorch_backend` is built when we turn on CMake option `EXECUTORCH_BUILD_QNN`. It will include the [CMakeLists.txt](https://github.com/pytorch/executorch/blob/main/backends/qualcomm/CMakeLists.txt) from backends/qualcomm where we `add_library(qnn_executorch_backend STATIC)`.

2. Build the Android extension:
# Create a new directory `app/libs` for the AAR to live
pushd examples/demo-apps/android/ExecuTorchDemo
mkdir -p app/libs
popd

```bash
cmake extension/android \
-DCMAKE_TOOLCHAIN_FILE="${ANDROID_NDK}"/build/cmake/android.toolchain.cmake \
-DANDROID_ABI="${ANDROID_ABI}" \
-DCMAKE_INSTALL_PREFIX=cmake-android-out \
-Bcmake-android-out/extension/android

cmake --build cmake-android-out/extension/android -j16
```

## Deploying on Device via Demo App

### Steps for Deploying Model via XNNPACK

```bash
mkdir -p examples/demo-apps/android/ExecuTorchDemo/app/src/main/jniLibs/arm64-v8a
cp cmake-android-out/extension/android/libexecutorch_jni.so \
examples/demo-apps/android/ExecuTorchDemo/app/src/main/jniLibs/arm64-v8a/libexecutorch.so
# Build the AAR. It will include XNNPACK backend by default.
export BUILD_AAR_DIR=$(realpath examples/demo-apps/android/ExecuTorchDemo/app/libs)
sh build/build_android_library.sh
```

This allows the Android app to load ExecuTorch runtime with XNNPACK backend as a JNI library. Later, this shared library will be loaded by `NativePeer.java` in Java code.

### Steps for Deploying Model via Qualcomm's AI Engine Direct

```bash
mkdir -p ../examples/demo-apps/android/ExecuTorchDemo/app/src/main/jniLibs/arm64-v8a
```

We need to push some additional Qualcomm HTP backend libraries to the app. Please refer to [Qualcomm docs](backends-qualcomm.md) here.

```bash
cp ${QNN_SDK_ROOT}/lib/aarch64-android/libQnnHtp.so ${QNN_SDK_ROOT}/lib/hexagon-v69/unsigned/libQnnHtpV69Skel.so ${QNN_SDK_ROOT}/lib/aarch64-android/libQnnHtpV69Stub.so ${QNN_SDK_ROOT}/lib/aarch64-android/libQnnSystem.so \
examples/demo-apps/android/ExecuTorchDemo/app/src/main/jniLibs/arm64-v8a
```

Copy the core libraries:

```bash
cp cmake-android-out/extension/android/libexecutorch_jni.so \
examples/demo-apps/android/ExecuTorchDemo/app/src/main/jniLibs/arm64-v8a/libexecutorch.so
cp cmake-android-out/lib/libqnn_executorch_backend.so \
examples/demo-apps/android/ExecuTorchDemo/app/src/main/jniLibs/arm64-v8a/libqnn_executorch_backend.so
```
This is very similar to XNNPACK setup, but users now needs to define `QNN_SDK_ROOT` so that
QNN backend is built into the AAR.

## Running the App

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,9 +57,7 @@ dependencies {
implementation("androidx.constraintlayout:constraintlayout:2.2.0-alpha12")
implementation("com.facebook.soloader:soloader:0.10.5")
implementation("com.facebook.fbjni:fbjni:0.5.1")
implementation("org.pytorch.executorch:executorch") {
exclude("com.facebook.fbjni", "fbjni-java-only")
}
implementation(files("libs/executorch.aar"))
testImplementation("junit:junit:4.13.2")
androidTestImplementation("androidx.test.ext:junit:1.1.5")
androidTestImplementation("androidx.test.espresso:espresso-core:3.5.1")
Expand All @@ -72,8 +70,8 @@ dependencies {
tasks.register("setup") {
doFirst {
exec {
commandLine("sh", "examples/demo-apps/android/LlamaDemo/setup.sh")
workingDir("../../../../../")
commandLine("sh", "setup.sh")
workingDir("../")
}
}
}
2 changes: 0 additions & 2 deletions examples/demo-apps/android/ExecuTorchDemo/app/src/main/BUCK
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,6 @@ fb_android_resource(
fb_android_library(
name = "app_lib",
srcs = [
"java/com/example/executorchdemo/ClassificationActivity.java",
"java/com/example/executorchdemo/ImageNetClasses.java",
"java/com/example/executorchdemo/MainActivity.java",
"java/com/example/executorchdemo/TensorImageUtils.java",
],
Expand Down
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.

This file was deleted.

Loading
Loading