6.2 KiB
Compiling Whisper for Qualcomm NPU (AI Hub)
Guide pour compiler les modèles Whisper (Base/Small/Medium) via Qualcomm AI Hub pour déploiement NPU sur Snapdragon 8 Elite (SM8750).
Prérequis
Environnement Python
# Créer un venv dédié (Python 3.10 recommandé)
python3 -m venv /opt/Kazeia/qnn_venv
source /opt/Kazeia/qnn_venv/bin/activate
# Installer qai-hub et les modèles
pip install qai-hub qai-hub-models
Compte Qualcomm AI Hub
- Créer un compte sur https://aihub.qualcomm.com
- Générer un API token dans les paramètres du compte
- Configurer le token :
qai-hub configure --api_token <VOTRE_TOKEN>
La configuration est sauvée dans ~/.qai_hub/client.ini.
Compilation
Commande générale
source /opt/Kazeia/qnn_venv/bin/activate
python3 -m qai_hub_models.models.<MODEL_NAME>.export \
--device "Snapdragon 8 Elite QRD" \
--target-runtime precompiled_qnn_onnx \
--precision float \
--skip-profiling \
--skip-inferencing \
--output-dir /opt/Kazeia/models_qnn/<OUTPUT_DIR>
Modèles disponibles
| Modèle | Module | Paramètres | Layers | Heads |
|---|---|---|---|---|
| Whisper-Base | whisper_base |
77M | 6 | 8 |
| Whisper-Small | whisper_small |
244M | 12 | 12 |
| Whisper-Medium | whisper_medium |
769M | 24 | 16 |
Exemple : Whisper-Small
python3 -m qai_hub_models.models.whisper_small.export \
--device "Snapdragon 8 Elite QRD" \
--target-runtime precompiled_qnn_onnx \
--precision float \
--skip-profiling \
--skip-inferencing \
--output-dir /opt/Kazeia/models_qnn/whisper-small-sm8750
Temps de compilation : ~5-10 minutes (upload modèle + compilation cloud).
Exemple : Whisper-Base
python3 -m qai_hub_models.models.whisper_base.export \
--device "Snapdragon 8 Elite QRD" \
--target-runtime precompiled_qnn_onnx \
--precision float \
--skip-profiling \
--skip-inferencing \
--output-dir /opt/Kazeia/models_qnn/whisper-base-sm8750
Options de device
# Lister les devices disponibles
qai-hub list-devices | grep -i "8 elite\|sm8750"
# Devices SM8750 (Snapdragon 8 Elite) :
# "Snapdragon 8 Elite QRD" → chipset: qualcomm-snapdragon-8-elite, sm8750
# "Samsung Galaxy S25 (Family)" → chipset: qualcomm-snapdragon-8-elite-for-galaxy, sm8750-ac
#
# Note: OnePlus Pad 2/3 utilise sm8750 standard (pas "for-galaxy")
Fichiers générés
La compilation produit un sous-dossier avec :
whisper_small-precompiled_qnn_onnx-float-qualcomm_snapdragon_8_elite/
├── HfWhisperEncoder.onnx # Stub ONNX (~3KB)
├── HfWhisperEncoder_qairt_context.bin # Context binaire QNN (encoder)
├── HfWhisperDecoder.onnx # Stub ONNX (~8KB)
├── HfWhisperDecoder_qairt_context.bin # Context binaire QNN (decoder)
├── metadata.yaml # Métadonnées de compilation
└── vocab.bin # Vocabulaire (non utilisé)
Architecture des modèles
Encoder (HfWhisperEncoder) :
- Input :
input_features[1, 80, 3000] fp16 - Output : Cross-attention KV caches (N layers × k,v)
k_cache_cross_N: [num_heads, 1, 64, 1500] fp16v_cache_cross_N: [num_heads, 1, 1500, 64] fp16
Decoder (HfWhisperDecoder) — KV-cache autorégressif :
- Inputs :
input_ids: [1, 1] int32 (un token à la fois)attention_mask: [1, 1, 1, 200] fp16 (right-aligned, -100 pour masqué)k_cache_self_N_in/v_cache_self_N_in: Self KV caches (199 slots, init zeros)k_cache_cross_N/v_cache_cross_N: Cross KV caches (depuis encoder)position_ids: [1] int32
- Outputs :
logits: [1, 51865, 1, 1] fp16k_cache_self_N_out/v_cache_self_N_out: Self KV caches mis à jour
Déploiement sur tablette
1. Copier les modèles
MODEL_DIR="/data/local/tmp/kazeia/models/whisper-small-sm8750"
SRC="<chemin_local>/whisper_small-precompiled_qnn_onnx-float-qualcomm_snapdragon_8_elite"
adb shell "mkdir -p $MODEL_DIR"
adb push $SRC/HfWhisperEncoder.onnx $MODEL_DIR/
adb push $SRC/HfWhisperEncoder_qairt_context.bin $MODEL_DIR/
adb push $SRC/HfWhisperDecoder.onnx $MODEL_DIR/
adb push $SRC/HfWhisperDecoder_qairt_context.bin $MODEL_DIR/
2. Copier les assets partagés
Les fichiers mel_filters.json et vocab.json sont communs à toutes les variantes Whisper :
# Si déjà présents depuis une autre variante :
adb shell "cp /data/local/tmp/kazeia/models/whisper-sm8750/mel_filters.json $MODEL_DIR/"
adb shell "cp /data/local/tmp/kazeia/models/whisper-sm8750/vocab.json $MODEL_DIR/"
3. Configurer le chemin dans KazeiaService.kt
npuStt.load("$modelsDir/whisper-small-sm8750")
Tailles des modèles compilés
| Modèle | Encoder (bin) | Decoder (bin) | Total |
|---|---|---|---|
| Whisper-Base | 47 MB | 145 MB | ~192 MB |
| Whisper-Small | 201 MB | 345 MB | ~546 MB |
Performances sur OnePlus Pad (SM8750)
| Étape | Whisper-Base | Whisper-Small |
|---|---|---|
| Mel (C++ natif) | ~220ms | ~220ms |
| Encoder NPU | ~140ms | ~270ms* |
| Decoder NPU (par step) | ~13ms | TBD |
| Load encoder | ~150ms | ~270ms |
| Load decoder | ~150ms | ~250ms |
*À confirmer avec des benchmarks réels sur audio.
Dépannage
"resource failed to call close"
Warnings bénins de l'ONNX Runtime. Les sessions ORT non fermées proprement génèrent ces messages lors du GC.
Modèle ne se charge pas
- Vérifier que
HfWhisperEncoder_qairt_context.binest dans le MÊME répertoire queHfWhisperEncoder.onnx - Vérifier que
libQnnHtp.soest accessible vianativeLibDir - Le modèle doit être compilé pour le bon chipset (sm8750, pas sm8750-ac ni sm8850)
Mauvaise détection de langue
Whisper-Base est peu fiable pour la détection de langue sur segments courts. Whisper-Small est nettement meilleur. Si besoin, on peut forcer le token de langue après SOT.
Référence
- Qualcomm AI Hub : https://aihub.qualcomm.com
- Code de référence :
qai_hub_models/models/_shared/hf_whisper/app.py - HuggingFace Whisper-Base : https://huggingface.co/qualcomm/Whisper-Base
- HuggingFace Whisper-Small : https://huggingface.co/qualcomm/Whisper-Small