Aller au contenu principal

Module 5 — Formats d'exécution efficaces

Un modèle compressé n'est utile que si un moteur d'inférence sait le lire vite sur le matériel cible. Les poids Hugging Face en format safetensors conviennent pour l'entraînement et l'expérimentation, mais pèsent lourd à charger et n'exploitent pas les instructions vectorielles des CPU récents. Trois formats spécialisés se sont imposés pour l'inférence de petits modèles : GGUF, ONNX et MLX. Chacun a un terrain d'élection, et confondre les trois coûte du temps.

GGUF : le format de llama.cpp

GGUF est le format binaire du projet llama.cpp, moteur d'inférence en C++ pur qui a rendu possible l'exécution de modèles de langage sur un simple portable. Le fichier .gguf contient les poids quantifiés, le tokenizer, les métadonnées d'architecture et le gabarit de discussion, le tout dans un seul artefact autonome.

Ses points forts sont son universalité et sa simplicité. GGUF fonctionne sur CPU x86 avec AVX2 ou AVX-512, sur ARM (Apple Silicon, Snapdragon X Elite, Ampere Altra), sur GPU NVIDIA via CUDA, sur GPU AMD via ROCm, et sur GPU Apple via Metal. Le même fichier tourne partout, ce qui est précieux pour livrer un assistant sur des postes hétérogènes.

Ses limites tiennent au champ d'application. GGUF cible l'inférence ; l'affinage se fait ailleurs, généralement en safetensors, puis convertit en GGUF avant déploiement. Le format est également le lieu privilégié des quantifications exotiques — Q4_K_M, Q5_K_S, Q6_K, IQ4_XS — qui affinent le compromis taille-qualité mieux que le duo classique GPTQ/AWQ, mais dont la documentation reste éparpillée dans les tickets du dépôt.

Un GGUF de notre modèle 3B en Q4_K_M pèse environ 2,1 Go, se charge en moins de trois secondes et tourne sur un portable de milieu de gamme avec 8 Go de RAM libres. C'est le format par défaut de notre projet.

ONNX Runtime : l'inférence portable industrielle

ONNX est un format standard décrit par un graphe de calcul. ONNX Runtime, le moteur maintenu par Microsoft, est optimisé pour l'inférence sur des environnements industriels : Windows Server, conteneurs Linux, embarqué ARM, navigateur via WebAssembly.

Ses points forts sont l'intégration serveur et l'écosystème d'accélérateurs : DirectML sur Windows, CUDA sur NVIDIA, OpenVINO sur Intel, TensorRT pour l'inférence à très basse latence. Un modèle exporté proprement en ONNX peut tourner en production avec des SLA serrés, avec un profileur intégré qui identifie l'opérateur coûteux.

Ses limites tiennent à la conversion. Un modèle de langage moderne utilise des opérateurs — attention à fenêtre glissante, cache KV, groupes d'attention multi-requête — qui ne s'exportent pas toujours sans intervention manuelle. Une conversion réussie sur Llama 3 peut échouer sur une variante affinée à cause d'un module personnalisé. Compter une à deux journées d'ingénierie pour un premier export propre, ensuite reproductible.

ONNX Runtime brille dans un scénario que GGUF couvre mal : service web multi-utilisateurs derrière une API, avec continuous batching et compilation graphe. Pour l'inférence sur poste isolé, GGUF reste plus simple.

MLX : la voie Apple Silicon

MLX est le cadriciel d'inférence d'Apple, taillé pour la mémoire unifiée des puces M1 à M4. Contrairement à Metal utilisé indirectement par llama.cpp, MLX est conçu de bout en bout autour de cette architecture : les poids résident dans la RAM partagée entre CPU et GPU, sans copie, ce qui accélère significativement l'inférence sur ces machines.

Sur un MacBook Air M3 avec 16 Go, un modèle 3B en 4 bits sous MLX répond au premier jeton en 60 à 80 ms, contre 90 à 120 ms sous llama.cpp Metal. Le gain est réel mais ne se manifeste que sur Apple Silicon ; le format ne se déploie pas ailleurs. Sa niche est claire : produits vendus à un public d'utilisateurs Mac (rédacteurs, designers, développeurs indépendants) où la mémoire unifiée d'un M3 ou M4 offre un rapport qualité-latence-prix imbattable.

Comment convertir sans se tromper

Le point commun aux trois formats est qu'ils dérivent tous de poids Hugging Face en safetensors. La chaîne canonique est donc :

  1. Récupérer le modèle affiné (module 7) en safetensors.
  2. Convertir vers le format cible avec l'outil du moteur (convert_hf_to_gguf.py pour GGUF, optimum-cli export onnx pour ONNX, mlx_lm.convert pour MLX).
  3. Quantifier au niveau demandé (llama-quantize model.gguf model.Q4_K_M.gguf Q4_K_M pour un GGUF).
  4. Vérifier : rejouer les 200 tickets d'évaluation et comparer le résultat à celui du modèle d'origine.

L'étape 4 est celle qu'on oublie. Une conversion silencieuse peut introduire une perte de 3 ou 4 points sans lever d'exception, à cause d'un tokenizer mal exporté ou d'un gabarit de discussion défaillant. Sans mesure de contrôle systématique, on découvre le problème en production.

Choix rapide selon le matériel

Poste Windows ou Linux avec ou sans GPU : GGUF via llama.cpp ou Ollama. Serveur d'entreprise avec batching : ONNX Runtime. Poste Apple Silicon comme cible principale : MLX si vous cherchez la latence, GGUF si vous voulez déployer partout avec un seul artefact.

En résumé

  • GGUF est le format universel de llama.cpp : un fichier autonome, quantifications riches, tourne sur CPU, GPU NVIDIA, AMD et Apple.
  • ONNX Runtime vise l'inférence industrielle avec batching et compilation graphe ; la conversion demande une à deux journées la première fois, ensuite reproductible.
  • MLX exploite la mémoire unifiée d'Apple Silicon et gagne 30 à 50 ms sur le premier jeton, au prix d'un déploiement limité aux Mac.
  • La conversion doit systématiquement se valider sur le jeu de 200 tickets, sinon une perte silencieuse s'installe en production.

Module suivant : mesurer proprement latence et débit, avec un protocole reproductible qui survit à un changement de fournisseur ou de matériel.