software-mansion / software-mansion/react-native-executorch

Experiment with Qualcomm (QNN) backend export

Open
#1,333 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

idea performance platform: android
Dominant language
TypeScript
Stars
1.7k
Forks
96
Avg merge
20h 51m
Merged PRs (30d)
59

Description

Goal

Experiment with the ExecuTorch Qualcomm (QNN) backend: export a few easy
models and get them running correctly on-device on Qualcomm hardware (HTP /
Hexagon). Start with MobileNetV2 (small image classifier, quantizes cleanly
to int8 on HTP) as the proof-of-concept, then generalize.

Export scripts land in the GitLab export-scripts repo (universal-exporter
harness); RNE runtime integration is a separate follow-up (see below).

Key constraint: AOT compile needs x86_64 Linux (not macOS)

The QNN ahead-of-time (AOT) compiler is only shipped/verified for Ubuntu
22.04 x86_64
(or WSL). The QNN SDK ships no macOS host library — its host
libs are x86_64-linux-clang / x86_64-windows-msvc only. So the export flow
cannot run on an Apple Silicon Mac; only the device runtime libs are
cross-platform. Everything below runs on a Linux x86_64 box; only the phone is
shared.

Setup required

  • x86_64 Linux host — Ubuntu 22.04 (or WSL on Windows), g++ ≥ 13.

  • QNN SDK 2.37.0 (Qualcomm AI Engine Direct) from the Qualcomm developer
    portal, unpacked to e.g. ~/qnn-sdk/qairt/2.37.0.250724. 2.37 is the
    version ExecuTorch currently recommends for stability.

  • Android NDK (for building the on-device qnn_executor_runner).

  • ExecuTorch built from source with the Qualcomm backend enabled — the
    pip executorch wheel does not ship the QNN AOT libraries.
    bash git clone https://github.com/software-mansion-labs/executorch.git cd executorch && git submodule sync && git submodule update --init export QNN_SDK_ROOT=$HOME/qnn-sdk/qairt/2.37.0.250724 export ANDROID_NDK_ROOT=$HOME/Android/Sdk/ndk/<version> ./install_executorch.sh ./backends/qualcomm/scripts/build.sh # QNN AOT libs + android runtime

  • Env vars in every export shell:
    bash export QNN_SDK_ROOT=$HOME/qnn-sdk/qairt/2.37.0.250724 export EXECUTORCH_ROOT=$HOME/executorch source $QNN_SDK_ROOT/bin/envsetup.sh # sets LD_LIBRARY_PATH for QNN export PYTHONPATH=$EXECUTORCH_ROOT/..:$PYTHONPATH

  • A Qualcomm SoC device connected over adb. Read the chip and map it
    to a QcomChipset member (needed for --soc):
    bash adb shell getprop ro.soc.model # e.g. SM8650
    | ro.soc.model | QcomChipset | Marketing | Hexagon |
    |----------------|---------------|----------------------|---------|
    | SM8450 | SM8450 | Snapdragon 8 Gen 1 | v69 |
    | SM8550 | SM8550 | Snapdragon 8 Gen 2 | v73 |
    | SM8650 | SM8650 | Snapdragon 8 Gen 3 | v75 |
    | SM8750 | SM8750 | Snapdragon 8 Elite | v79 |

    Full list: `backends/qualcomm/serialization/qc_schema.py` (`QcomChipset`).
    

Export-scripts (universal-exporter) integration

Add QNN to the @nk/universal-exporter harness. QNN is a new backend axis — no
qnn/qualcomm reference exists there yet (inspect_pte.py's KNOWN_BACKENDS
already lists QnnBackend/HtpBackend, but there is no export path).

  • Register the backend — add "qnn" to _BACKENDS in
    src/exporter/spec.py (the harness hard-rejects unknown backends).
  • New model exporter_models/mobilenet_v2/:
    • model.jsonbackends includes "qnn".
    • qnn/config.json — local spec (no HF repo ships a QNN config). Variants:
      int8 (8a8w PTQ, quantized: true) and fp16. forward:
      input [1,3,224,224] float32 → output [1,1000] float32.
    • qnn/export.py — implements export(config, out_dir); lowers inline via
      the QNN HTP path (make_quantizer 8a8w → prepare_pt2e → calibrate →
      convert_pt2eto_edge_transform_and_lower_to_qnn with an HTP
      compiler spec for the target SoC). ExecuTorch imports stay inside
      export() per the harness contract. Calibrate on a small ImageNet-mini
      split for usable int8 accuracy.
  • skills/backends/qnn/SKILL.md — document the Linux-x86_64 + QNN-SDK
    requirement and the lowering recipe, mirroring the existing backend skills.

On-device validation

  • Build qnn_executor_runner for android (done by build.sh), push the
    .pte + inputs, run on the HTP, and sanity-check top-1/top-5. Fastest path
    is ExecuTorch's upstream one-shot example:
    bash python -m examples.qualcomm.scripts.mobilenet_v2 \ -b build-android -m SM8650 -s <serial> --dataset ./imagenet-mini/val # expect roughly top_1 ~70%, top_5 ~90%
    A healthy top-k proves the QNN compile + Hexagon execution path works on
    the target SoC.

Follow-up: react-native-executorch runtime integration (rne-rewrite)

Running a QNN-delegated .pte inside the RNE app is a separate, larger task
and is out of scope for the first milestone:

  • RNE's native ExecuTorch build must include the QNN delegate (stock RNE
    libs are XNNPACK/CoreML only).
  • Ship the QNN runtime .sos + Hexagon skels in the APK.
  • Wire the classification model path to load the QNN .pte.

Milestone

Milestone 1 = a validated on-device MobileNetV2 QNN .pte (top-k sane via the
runner). RNE app integration follows once the toolchain is proven.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with src/exporter/spec.py and the existing exporter_models and skills/backends directories in the GitLab export-scripts repository, then review backends/qualcomm/serialization/qc_schema.py and the upstream MobileNetV2 example. Verify the Ubuntu x86_64, QNN SDK, Android NDK, and Qualcomm device prerequisites before implementing the export path. Done means a MobileNetV2 QNN .pte runs through qnn_executor_runner with sane top-1/top-5 results on the target SoC.

Written by the indexing model from the issue text.

Assessment

Tech stack
android, python, pytorch, react-native
Domain
backend, machine-learning, mobile
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
32/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.