kazeia/DEPLOY_EXECUTORCH_NPU.md

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*