software-mansion / software-mansion/react-native-executorch
Experiment with Qualcomm (QNN) backend export
Nobody has claimed this yet.
- 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
pipexecutorchwheel 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 aQcomChipsetmember (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_BACKENDSin
src/exporter/spec.py(the harness hard-rejects unknown backends). - New model
exporter_models/mobilenet_v2/:-
model.json—backendsincludes"qnn". -
qnn/config.json— local spec (no HF repo ships a QNN config). Variants:
int8(8a8w PTQ,quantized: true) andfp16.forward:
input[1,3,224,224]float32 → output[1,1000]float32. -
qnn/export.py— implementsexport(config, out_dir); lowers inline via
the QNN HTP path (make_quantizer8a8w →prepare_pt2e→ calibrate →
convert_pt2e→to_edge_transform_and_lower_to_qnnwith 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_runnerfor android (done bybuild.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
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- 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