Projet que j’ai créé moi-même.
- Bibliothèque qui réimplémente en C pur le runtime de FastEnhancer-Medium (modèle d’amélioration vocale en streaming à 48 kHz)
- Modèle original : https://github.com/aask1357/fastenhancer (Ahn et al., 2025)
- Utilise telles quelles les pondérations 48 kHz publiées en supplément par le dépôt original après l’article (16 kHz). Aucun réentraînement, fine-tuning ni calibration set
- Le modèle et les pondérations appartiennent aux auteurs originaux ; l’optimisation porte sur le runtime
■ Performances
- Real-time factor de 0,069 sur un seul cœur Apple M2. Sur la même machine, exécuter le même graphe avec ONNX Runtime donne 0,230, soit 3,3×
- 0,096 sur Galaxy S23+ (Snapdragon 8 Gen 2)
- La dégradation de qualité est presque inexistante. Sur 824 énoncés VoiceBank-DEMAND, seulement -0,006 PESQ par rapport au modèle fp32. Pas un niveau discernable à l’écoute
■ Optimisations appliquées
Le gain de 3× ne vient pas d’une seule technique : plusieurs couches ont été retravaillées séparément.
- Quantification : la plage des activations est recalculée à chaque frame. Il n’est donc pas du tout nécessaire d’ajuster ni de distribuer un calibration set, et cela ne casse pas lorsque la distribution d’entrée change
- Convolutions : application de Winograd F(2,3) aux conv k=3, avec l’épilogue qui suit (dequant + bias + SiLU + écriture fp16) intégré dans la même passe afin d’éliminer les buffers intermédiaires
- Récurrence : le GRU est entièrement fusionné en un seul kernel par tier. Le produit matriciel côté entrée, le produit matriciel côté caché, les trois portes r/z/n et la mise à jour du hidden sont terminés dans un même kernel, de sorte que l’accumulateur int32 ne déborde pas vers la mémoire
- Attention : softmax traite directement les scores int32. Comme aucune matrice de scores fp32 n’est créée, les allers-retours mémoire correspondants disparaissent
- Mémoire : les états cross-stage (GRU hidden, encoder skip) sont conservés en fp16, réduisant de moitié la bande passante entre frames
- Kernels : 6 kernels GEMM int8 spécifiques aux ISA ont été écrits à la main et sont sélectionnés automatiquement à l’initialisation (ARM NEON/DOTPROD/I8MM, x86 AVX2/AVX-VNNI/AVX-512)
- Le reste de la liste des optimisations est disponible sur le GitHub du projet
■ Stabilité en temps réel
- La vérification ne s’est pas arrêtée à un benchmark unique de 37 secondes : le système a tourné 30 minutes en continu au rythme réel des callbacks audio
- Le M2 est resté dans le budget de frame pendant toute la durée des 30 minutes (p99 0,56)
■ Divers
- Zéro dépendance externe. Se compile avec cmake + make, et la bibliothèque statique fait 162 KiB
- L’API publique compte 4 fonctions (fe_init / fe_run / fe_reset / fe_free)
- Blob de pondérations de 565 KB, 511 754 paramètres
- Licence MIT
Aucun commentaire pour le moment.