139 lines
5.3 KiB
Markdown
139 lines
5.3 KiB
Markdown
# Déploiement ExecuTorch + QNN NPU — OnePlus Pad 3
|
|
|
|
*Procédure validée le 28 mars 2026*
|
|
|
|
## Prérequis
|
|
|
|
- Tablette rootée (Magisk)
|
|
- SELinux permissive (`su -c 'setenforce 0'`)
|
|
- DSP permissions ouvertes (boot script `/data/adb/service.d/kazeia_dsp.sh`)
|
|
- QNN SDK 2.42 installé sur le PC : `/opt/Kazeia/qnn_sdk_242/qairt/2.42.0.251225/`
|
|
- ExecuTorch compilé pour Android ARM64 : `/opt/Kazeia/executorch/build-android/`
|
|
|
|
## Fichiers requis (TOUS obligatoires)
|
|
|
|
| Fichier | Source | Rôle |
|
|
|---------|--------|------|
|
|
| `qnn_llama_runner` | `executorch/build-android/examples/qualcomm/oss_scripts/llama/` | Runner LLM |
|
|
| `libqnn_executorch_backend.so` | `executorch/build-android/backends/qualcomm/` | Backend ExecuTorch ↔ QNN |
|
|
| `libQnnHtp.so` | `qnn_sdk_242/.../lib/aarch64-android/` | QNN HTP runtime |
|
|
| `libQnnHtpV79Stub.so` | `qnn_sdk_242/.../lib/aarch64-android/` | Stub CPU → DSP |
|
|
| `libQnnHtpV79Skel.so` | `qnn_sdk_242/.../lib/hexagon-v79/unsigned/` | Skel DSP (hexagon) |
|
|
| `libQnnHtpPrepare.so` | `qnn_sdk_242/.../lib/aarch64-android/` | Préparation graphe HTP |
|
|
| `libQnnSystem.so` | `qnn_sdk_242/.../lib/aarch64-android/` | Système QNN |
|
|
| `libQnnModelDlc.so` | `qnn_sdk_242/.../lib/aarch64-android/` | Chargement modèles DLC |
|
|
| `libQnnHtpNetRunExtensions.so` | `qnn_sdk_242/.../lib/aarch64-android/` | Extensions réseau HTP |
|
|
| `hybrid_llama_qnn.pte` | `models_qnn/qwen3-*-executorch/` | Modèle ExecuTorch |
|
|
| `tokenizer.json` | `models_qnn/qwen3-*-executorch/` | Tokenizer HuggingFace |
|
|
|
|
**IMPORTANT** : Les libs Skel DOIVENT venir du même SDK que celui utilisé pour compiler le .pte. Ne PAS utiliser les libs vendor de la tablette (`/vendor/lib64/hw/audio/`).
|
|
|
|
## Script de déploiement
|
|
|
|
```bash
|
|
#!/bin/bash
|
|
QNN="/opt/Kazeia/qnn_sdk_242/qairt/2.42.0.251225"
|
|
ET="/opt/Kazeia/executorch"
|
|
DIR="/data/local/tmp/kazeia-et"
|
|
MODEL_DIR="/opt/Kazeia/models_qnn/qwen3-0_6b-executorch" # ou qwen3-1_7b-executorch
|
|
|
|
# Créer répertoire
|
|
adb shell "rm -rf $DIR && mkdir -p $DIR/outputs"
|
|
|
|
# Libs QNN SDK 2.42
|
|
adb push $QNN/lib/aarch64-android/libQnnHtp.so $DIR/
|
|
adb push $QNN/lib/aarch64-android/libQnnHtpV79Stub.so $DIR/
|
|
adb push $QNN/lib/hexagon-v79/unsigned/libQnnHtpV79Skel.so $DIR/
|
|
adb push $QNN/lib/aarch64-android/libQnnHtpPrepare.so $DIR/
|
|
adb push $QNN/lib/aarch64-android/libQnnSystem.so $DIR/
|
|
adb push $QNN/lib/aarch64-android/libQnnModelDlc.so $DIR/
|
|
adb push $QNN/lib/aarch64-android/libQnnHtpNetRunExtensions.so $DIR/
|
|
|
|
# ExecuTorch
|
|
adb push $ET/build-android/backends/qualcomm/libqnn_executorch_backend.so $DIR/
|
|
adb push $ET/build-android/examples/qualcomm/oss_scripts/llama/qnn_llama_runner $DIR/
|
|
|
|
# Modèle + Tokenizer
|
|
adb push $MODEL_DIR/hybrid_llama_qnn.pte $DIR/
|
|
adb push $MODEL_DIR/tokenizer.json $DIR/
|
|
|
|
# Permissions
|
|
adb shell "chmod +x $DIR/qnn_llama_runner"
|
|
```
|
|
|
|
## Exécution
|
|
|
|
```bash
|
|
adb shell "su -c 'cd /data/local/tmp/kazeia-et && \
|
|
export LD_LIBRARY_PATH=/data/local/tmp/kazeia-et && \
|
|
export ADSP_LIBRARY_PATH=/data/local/tmp/kazeia-et && \
|
|
./qnn_llama_runner \
|
|
--model_path hybrid_llama_qnn.pte \
|
|
--tokenizer_path tokenizer.json \
|
|
--decoder_model_version qwen3 \
|
|
--output_path outputs/outputs.txt \
|
|
--performance_output_path outputs/perf.txt \
|
|
--shared_buffer \
|
|
--prompt \"Votre prompt ici\" \
|
|
--system_prompt \"Tu es Kazeia, compagnon écoute émotionnelle.\" \
|
|
--temperature 0.7 \
|
|
--seq_len 256 \
|
|
--eval_mode 1'"
|
|
```
|
|
|
|
### Paramètres clés
|
|
|
|
| Paramètre | Valeur | Description |
|
|
|-----------|--------|-------------|
|
|
| `--decoder_model_version` | `qwen3` | Template de chat Qwen3 |
|
|
| `--eval_mode` | `1` | Mode hybride (prefill + KV cache) |
|
|
| `--shared_buffer` | (flag) | **OBLIGATOIRE** — mémoire partagée CPU↔DSP |
|
|
| `--output_path` | chemin | Fichier de sortie texte |
|
|
| `--temperature` | 0.0-1.0 | 0 = déterministe, 0.7 = créatif |
|
|
| `--seq_len` | 128-4096 | Longueur max (prompt + réponse) |
|
|
|
|
## Performances mesurées
|
|
|
|
### Qwen3-0.6B (660 MB)
|
|
- **Chargement** : 0.86s
|
|
- **Prefill** : 31ms (451 tok/s)
|
|
- **Génération** : 93.15 tok/s
|
|
- **Temps au premier token** : 31ms
|
|
- **RAM** : ~698 MB
|
|
|
|
### Qwen3-1.7B (1.7 GB)
|
|
- **Génération** : ~25.7 tok/s (benchmark mars 2026)
|
|
|
|
### Mistral-Nemo 12B (7.4 GB)
|
|
- **Génération** : ~5.1 tok/s (benchmark mars 2026)
|
|
|
|
## Modèles disponibles
|
|
|
|
| Modèle | Fichier .pte | Taille | Qualité FR |
|
|
|--------|-------------|--------|------------|
|
|
| Qwen3-0.6B | `qwen3-0_6b-executorch/hybrid_llama_qnn.pte` | 660 MB | Basique |
|
|
| Qwen3-1.7B | `qwen3-1_7b-executorch/hybrid_llama_qnn.pte` | 1.7 GB | Bonne |
|
|
| Mistral-Nemo 12B | `mistral-nemo-executorch/hybrid_llama_qnn.pte` | 7.4 GB | Excellente |
|
|
|
|
## Erreurs courantes
|
|
|
|
### `loadRemoteSymbols failed with err 4000`
|
|
- **Cause** : Libs Skel manquantes ou incompatibles
|
|
- **Fix** : Vérifier que `libQnnHtpV79Skel.so` vient du SDK 2.42 (hexagon-v79/unsigned/), pas du vendor
|
|
|
|
### `SoC model (SnapdragonModel) is unknown`
|
|
- **Cause** : Utilisation des libs vendor au lieu des libs SDK
|
|
- **Fix** : Ne PAS utiliser `/vendor/lib64/hw/audio/libQnn*.so`
|
|
|
|
### Runner se termine sans générer de texte
|
|
- **Cause** : `--shared_buffer` et `--output_path` manquants
|
|
- **Fix** : Ajouter les deux paramètres
|
|
|
|
### `Failed to create transport for device`
|
|
- **Cause** : `libQnnModelDlc.so` manquant
|
|
- **Fix** : Copier depuis `qnn_sdk_242/.../lib/aarch64-android/`
|
|
|
|
---
|
|
|
|
*Projet Kazeia — Damien Micottis & Richard Loyer*
|