GGUF (GGML Universal File Format)
GGUF est un format de fichier binaire développé par le projet llama.cpp qui embarque les poids quantifiés d’un modèle IA, son tokenizer, ses métadonnées d’architecture et ses paramètres de quantification dans un fichier unique et portable, optimisé pour l’inférence locale sur CPU, GPU et configurations hybrides.
C’est le format de référence pour faire tourner un LLM en local. Quand vous lancez un modèle via Ollama, LM Studio ou Jan, c’est un fichier GGUF qui tourne en coulisse. Un seul fichier contient tout : les poids compressés, le vocabulaire du tokenizer, la taille de contexte, l’architecture (Llama, Mistral, Qwen, Gemma, etc.), et les métadonnées de quantification. Pas de config.json séparé, pas de fichier tokenizer additionnel. Vous téléchargez un .gguf, vous le lancez.
- Type
- Format de fichier binaire pour modèles quantifiés
- Créateur
- Georgi Gerganov (projet llama.cpp / GGML)
- Date d’introduction
- Août 2023 (remplace le format GGML)
- Précisions supportées
- 1,5 à 8 bits (entier), FP16, BF16, FP32
- Schémas de quantification
- Q4_0, Q4_K_M, Q5_K_M, Q6_K, Q8_0, IQ4_XS, IQ2_XS, etc.
- Architectures supportées
- 50+ (Llama, Mistral, Qwen, Gemma, Phi, DeepSeek, etc.)
- Outils d’inférence
- llama.cpp, Ollama, LM Studio, Jan, vLLM (support expérimental)
- Point fort
- Inférence CPU/hybride, portabilité, fichier unique auto-contenu
Pourquoi GGUF a été créé
Avant GGUF, le projet llama.cpp utilisait le format GGML. Ce format avait un défaut majeur : il manquait d’extensibilité. Ajouter le support d’une nouvelle architecture de modèle ou de nouveaux types de quantification obligeait à modifier le format de manière incompatible, cassant les anciens fichiers. Les métadonnées (tokenizer, taille de contexte, etc.) étaient stockées dans des fichiers séparés, ce qui compliquait la distribution et créait des erreurs de versionnage.
GGUF résout ces problèmes avec une structure binaire extensible. Les métadonnées sont stockées sous forme de paires clé-valeur typées, ce qui permet d’ajouter de nouvelles informations sans casser la rétrocompatibilité. Le tokenizer est embarqué dans le fichier. Et chaque tenseur inclut son type de quantification dans les métadonnées, permettant d’utiliser des précisions différentes pour différentes couches du modèle.
Structure d’un fichier GGUF
Un fichier GGUF se compose de trois sections :
En-tête (Header)
L’en-tête contient le magic number (« GGUF »), la version du format, le nombre de tenseurs, et le nombre de paires clé-valeur de métadonnées. C’est la carte d’identité du fichier.
Métadonnées (Metadata)
Les métadonnées sont stockées comme des paires clé-valeur typées. Elles incluent l’architecture du modèle (general.architecture: "llama"), le nom du modèle, la taille de contexte (llama.context_length: 4096), le vocabulaire du tokenizer, le type de fichier (qui indique le niveau de quantification), et toute information nécessaire pour charger et exécuter le modèle. Cette richesse de métadonnées rend les fichiers GGUF auto-contenus : un seul fichier suffit, sans config.json ni tokenizer séparé.
Données des tenseurs (Tensor Data)
Le bloc de données contient les poids du modèle sous forme binaire compacte. Pour chaque tenseur, les métadonnées précisent le nom, les dimensions, le type de quantification (Q4_0, Q4_K, Q8_0, F16, etc.), et l’offset dans le bloc de données. Les tenseurs sont alignés sur des frontières de 32 octets pour un accès mmap (memory-mapped) efficace. C’est cette technique de mmap qui permet à llama.cpp de charger des modèles plus gros que la RAM disponible, en ne chargeant en mémoire que les parties nécessaires à la volée.
Les schémas de quantification GGUF
GGUF supporte une large gamme de schémas de quantification, organisés en trois familles.
Schémas legacy (Q4_0, Q4_1, Q5_0, Q5_1)
Les schémas originaux, avec une quantification uniforme par blocs de 32 poids. Q4_0 utilise un seul scale factor (symétrique), Q4_1 ajoute un offset (asymétrique). Ces formats sont obsolètes et ne sont plus recommandés. Ils ont été largement supplantés par les K-quants.
K-quants (Q3_K_S, Q4_K_M, Q5_K_M, Q6_K, Q8_0)
Les K-quants sont le système de quantification recommandé. Leur innovation : la précision mixte par couche. Au lieu d’appliquer le même nombre de bits à tous les tenseurs, les K-quants allouent plus de bits aux couches sensibles (typiquement les projections d’attention) et moins aux couches feedforward.
La convention de nommage encode trois informations :
Q + nombre de bits + _K + variante de taille. Exemple : Q4_K_M = 4 bits principalement, méthode K-quant, variante Medium. Les variantes sont _S (Small, plus compact, qualité moindre), _M (Medium, compromis optimal), et _L (Large, meilleure qualité, plus gros).
| Format | Bits effectifs/poids | Taille modèle 8B | Qualité vs FP16 | Recommandation |
|---|---|---|---|---|
| Q2_K | ~2,6 | ~3 Go | Dégradation notable | Compression extrême uniquement |
| Q3_K_S | ~3,4 | ~3,5 Go | Dégradation visible | Matériel très limité (6 Go VRAM) |
| Q3_K_M | ~3,9 | ~4 Go | Acceptable | Compromis si Q4_K_M ne tient pas |
| Q4_K_S | ~4,4 | ~4,5 Go | Bonne | Bonne alternative à Q4_K_M si mémoire serrée |
| Q4_K_M | ~4,6 | ~4,9 Go | Très bonne (97-99 %) | Recommandé Sweet spot communautaire |
| Q5_K_S | ~5,4 | ~5,5 Go | Très bonne | Si vous avez un peu plus de mémoire |
| Q5_K_M | ~5,7 | ~5,7 Go | Excellente | Meilleur ratio qualité/taille si Q8_0 trop gros |
| Q6_K | ~6,6 | ~6,6 Go | Quasi parfaite | Quand la qualité prime sur l’espace |
| Q8_0 | ~8,5 | ~8,5 Go | Quasi identique à FP16 | Qualité maximale en GGUF |
I-quants (IQ2_XS, IQ3_S, IQ4_XS)
Les I-quants (Importance-matrix quants) représentent l’état de l’art en compression GGUF. Ils utilisent une matrice d’importance (imatrix), calculée à partir d’un dataset de calibration, pour identifier quels poids sont les plus critiques et leur allouer une meilleure précision. IQ4_XS, par exemple, offre une qualité proche de Q4_K_M avec un fichier encore plus compact.
Pour utiliser les I-quants, il faut d’abord calculer la matrice d’importance :
# Calculer la matrice d'importance
./llama-imatrix -m model-f16.gguf
-f calibration-text.txt
--chunk 512 -o imatrix.dat -ngl 80
# Quantifier avec la matrice d'importance
./llama-quantize --imatrix imatrix.dat
model-f16.gguf model-IQ4_XS.gguf IQ4_XS
Pour les quantifications à très basse précision (2-3 bits), l’utilisation d’une imatrix est fortement recommandée, voire obligatoire. llama-quantize affiche un avertissement si vous tentez une quantification sub-4-bit sans imatrix.
Workflow de création d’un fichier GGUF
Le processus de création d’un GGUF à partir d’un modèle Hugging Face suit trois étapes :
Étape 1 : Conversion FP16/BF16
Le script convert_hf_to_gguf.py convertit un modèle Hugging Face (SafeTensors) en GGUF à pleine précision. C’est une étape obligatoire : ne sautez jamais directement à la quantification, passez d’abord par un intermédiaire FP16 ou BF16.
# Conversion vers GGUF FP16
python convert_hf_to_gguf.py ./models/Llama-3.1-8B/
--outfile Llama-3.1-8B-F16.gguf
--outtype f16
# Pour les modèles entraînés en BF16 (recommandé si supporté)
python convert_hf_to_gguf.py ./models/Qwen3-8B/
--outtype bf16
--outfile Qwen3-8B-BF16.gguf
Le convertisseur supporte plus de 50 architectures de modèles. Si un modèle est stocké avec des poids déjà quantifiés (GPTQ, FP8, BitNet), le convertisseur les déquantifie automatiquement en flottant avant l’écriture GGUF. Cela permet de re-quantifier ensuite avec les méthodes optimisées de llama.cpp.
model.merge_and_unload() de PEFT) avant la conversion. Tenter de convertir un adaptateur LoRA seul produira une erreur.
Étape 2 : Quantification
L’outil llama-quantize prend le GGUF FP16 et applique le schéma de quantification souhaité :
# Quantification Q4_K_M (le plus courant)
./llama-quantize Llama-3.1-8B-F16.gguf
Llama-3.1-8B-Q4_K_M.gguf Q4_K_M
# Avec matrice d'importance pour meilleure qualité
./llama-quantize --imatrix imatrix.dat
Llama-3.1-8B-F16.gguf
Llama-3.1-8B-Q4_K_M.gguf Q4_K_M
Options utiles : --leave-output-tensor laisse le tenseur de sortie en pleine précision (augmente la taille mais peut améliorer la qualité), --pure désactive la précision mixte K-quant et quantifie tous les tenseurs au même niveau.
Étape 3 : Inférence
Une fois le fichier GGUF créé, l’inférence est directe :
# Via llama.cpp directement
./llama-cli -m Llama-3.1-8B-Q4_K_M.gguf -cnv -p "You are a helpful assistant"
# Via Ollama (crée un Modelfile pointant vers le GGUF)
ollama run llama3.1:8b-q4_K_M
# Via le serveur OpenAI-compatible
llama-server -m Llama-3.1-8B-Q4_K_M.gguf --port 8080
Vous pouvez aussi publier votre GGUF sur le Hugging Face Hub (via huggingface-cli upload) ou utiliser l’espace GGUF-my-repo de Hugging Face pour quantifier directement depuis le navigateur, sans aucune installation locale.
GGUF vs SafeTensors (GPTQ/AWQ)
| Critère | GGUF | SafeTensors (GPTQ/AWQ) |
|---|---|---|
| Matériel cible | CPU, GPU, hybride, Apple Silicon | GPU NVIDIA (Ampere+) |
| Fichier auto-contenu | Oui (poids + tokenizer + config) | Non (nécessite config.json, tokenizer séparé) |
| Précision mixte par couche | Oui (K-quants) | Non (précision uniforme) |
| Offloading CPU+GPU | Natif (paramètre -ngl) |
Non supporté |
| Frameworks | llama.cpp, Ollama, LM Studio, Jan | vLLM, TGI, HF Transformers |
| Throughput GPU pur | Bon mais inférieur à Marlin | Excellent avec Marlin (712-741 tok/s) |
| Perplexité Q4 (Qwen2.5-32B) | 6,74 (Q4_K_M) | 6,84 (AWQ) / 6,90 (GPTQ) |
| Interconvertibilité | Non sans perte. Toujours partir du FP16 | Non sans perte. Toujours partir du FP16 |
Améliorer la qualité des modèles GGUF
La qualité d’un GGUF quantifié dépend de plusieurs facteurs que vous pouvez optimiser :
Utiliser une matrice d’importance (imatrix). C’est le levier le plus puissant. L’imatrix identifie les poids critiques via un dataset de calibration et alloue plus de précision là où ça compte. Quasi obligatoire pour les quantifications sub-4-bit, fortement recommandé pour Q4_K_M et en dessous.
Appliquer des scales AWQ avant la conversion. Un développement actif dans l’écosystème llama.cpp : appliquer les facteurs de scaling AWQ au modèle FP16 avant la conversion GGUF. Les poids sont « pré-conditionnés » pour mieux supporter la quantification, ce qui réduit l’écart de qualité entre GGUF et AWQ natif.
Choisir le bon schéma pour votre usage. Pour les assistants de code et les modèles de raisonnement, Q4_K_M est le minimum recommandé. En dessous, la précision des tokens de code et la qualité du raisonnement étape par étape se dégradent visiblement. Q5_K_M offre un meilleur compromis pour ces cas.
Laisser le tenseur de sortie en pleine précision. L’option --leave-output-tensor de llama-quantize garde le tenseur output.weight en FP16/BF16. Cela augmente la taille du fichier d’environ 5 à 10 % mais peut améliorer la qualité de la dernière couche de prédiction, surtout sur les petits modèles.
Compatibilité matérielle
GGUF via llama.cpp fonctionne sur une gamme de matériel exceptionnellement large :
CPU x86 (Intel/AMD) : optimisé via AVX, AVX2, AVX512 et AMX (les instructions de multiplication matricielle les plus récentes d’Intel). C’est le cas d’usage originel de llama.cpp.
Apple Silicon (M1-M4) : citoyen de première classe. Optimisé via ARM NEON, Accelerate et Metal (pour le GPU intégré). Un MacBook Air M2 avec 16 Go de mémoire unifiée fait tourner confortablement un modèle 8B en Q4_K_M.
GPU NVIDIA : offloading partiel ou total via CUDA. Le paramètre -ngl contrôle le nombre de couches chargées sur le GPU. Pour un modèle 8B en Q4_K_M (~5 Go), -ngl 32 (offload total) nécessite ~6 Go de VRAM.
GPU AMD : supporté via HIP (ROCm).
GPU Moore Threads : supporté via MUSA.
Configurations hybrides CPU+GPU : c’est un avantage unique de GGUF. Si votre GPU a 8 Go de VRAM mais le modèle pèse 12 Go, vous pouvez charger une partie des couches sur le GPU et le reste sur le CPU via la RAM système. L’inférence sera plus lente qu’en GPU pur mais fonctionnelle. C’est impossible avec GPTQ ou AWQ natifs.
Fonctionnalités avancées de llama.cpp avec GGUF
Au-delà de la quantification, l’écosystème GGUF/llama.cpp offre plusieurs optimisations avancées qui améliorent significativement les performances :
Décodage spéculatif. Cette technique associe un petit modèle « draft » (1B-3B paramètres) à un modèle cible plus gros (70B+). Le draft model prédit rapidement plusieurs tokens, que le modèle cible valide ou rejette en une seule passe. Résultat : un throughput effectif bien supérieur, parfois 2 à 3× plus rapide, car la majorité des tokens du draft sont acceptés. En llama.cpp : llama-server -m model-70B.gguf -md draft-3B.gguf.
Flash Attention. Activable via le flag -fa, Flash Attention optimise les patterns d’accès mémoire pendant le calcul d’attention, ce qui est critique pour les longues séquences. Sur le matériel Blackwell, où la bande passante mémoire est souvent le goulet d’étranglement plutôt que le calcul, Flash Attention est indispensable.
Quantification du cache KV. llama.cpp supporte la quantification du cache KV à la volée (via --cache-type-k q8_0 --cache-type-v q8_0), réduisant la mémoire consommée par le cache de moitié sans impact majeur sur la qualité. C’est un levier important pour les contextes longs ou les scénarios multi-utilisateurs.
Serveur OpenAI-compatible. llama-server expose des endpoints compatibles avec l’API OpenAI (/v1/chat/completions, /v1/completions), ce qui permet d’utiliser un modèle GGUF comme drop-in replacement d’un modèle cloud dans vos applications existantes.
Grammaire de sortie. llama.cpp supporte les grammaires GBNF pour contraindre la sortie du modèle (par exemple, forcer un JSON valide). Combiné à la quantification, c’est un outil puissant pour les pipelines de données structurées sur du matériel local.
Modèles très gros : sharding et split
Pour les modèles qui dépassent la taille maximale d’un fichier ou la capacité mémoire d’un seul appareil, llama.cpp fournit llama-gguf-split qui découpe un GGUF en plusieurs fragments. Chaque fragment est un fichier GGUF valide avec ses métadonnées. L’inférence charge automatiquement les fragments nécessaires. C’est utile pour les modèles 70B+ distribués sur plusieurs GPU ou pour contourner les limites de taille de fichier de certains systèmes de fichiers.
Questions fréquentes sur GGUF
Quelle variante GGUF choisir pour mon matériel ?
Règle simple : Q4_K_M si vous avez suffisamment de mémoire (environ 5 Go pour un 8B), Q3_K_M ou Q3_K_S si vous êtes très contraint. Si vous avez de la marge, Q5_K_M offre un meilleur rapport qualité/taille. Q8_0 pour la qualité maximale si la mémoire n’est pas un problème. Pour un 8B : Q4_K_M (~5 Go) tient sur un GPU de 8 Go ou un Mac de 16 Go. Pour un 70B : Q4_K_M (~40 Go) nécessite 48+ Go de RAM/VRAM ou un split multi-GPU.
Puis-je convertir un modèle GPTQ ou AWQ en GGUF ?
Techniquement oui, car le convertisseur convert_hf_to_gguf.py déquantifie automatiquement les poids GPTQ/AWQ en flottant avant la conversion. Mais c’est une mauvaise pratique : vous perdez de la qualité à chaque étape de quantification/déquantification. Partez toujours des poids FP16/BF16 originaux pour créer un GGUF de qualité. Ne convertissez depuis GPTQ/AWQ qu’en dernier recours, si les poids originaux ne sont pas disponibles.
GGUF est-il compatible avec vLLM ?
vLLM supporte les fichiers GGUF de manière expérimentale (via --quantization gguf). Les benchmarks montrent des résultats corrects mais le throughput est généralement inférieur à celui des modèles AWQ/GPTQ avec Marlin. Pour le serving haute performance sur GPU, préférez AWQ ou GPTQ via vLLM. Réservez GGUF pour l’inférence locale via llama.cpp, Ollama ou LM Studio.
Comment quantifier un modèle en GGUF sans installation locale ?
Utilisez l’espace GGUF-my-repo sur le Hub Hugging Face. Vous indiquez le modèle source, choisissez le format de quantification, et l’espace génère le fichier GGUF directement dans votre dépôt Hub. C’est synchronisé avec la branche main de llama.cpp toutes les 6 heures, donc vous bénéficiez toujours des dernières optimisations. Aucune installation locale, aucun GPU requis.
Quelle est la différence entre GGUF et GGML ?
GGML est l’ancien format utilisé par llama.cpp avant août 2023. GGUF l’a remplacé pour résoudre ses problèmes d’extensibilité et de rétrocompatibilité. GGML ne pouvait pas stocker les métadonnées (tokenizer, config) dans le fichier, nécessitait des fichiers séparés, et cassait la compatibilité à chaque ajout d’architecture. GGUF résout tout ça avec un format binaire extensible. Les anciens fichiers GGML ne sont plus supportés par les versions récentes de llama.cpp. Si vous en avez, re-convertissez depuis les poids FP16 originaux.