Vous savez pourquoi quantifier un modèle. Ce guide montre comment le faire, et surtout ce que ça change vraiment, mesures à l'appui. Vous allez quantifier un modèle de bout en bout en GGUF pour l'inférence locale, servir des variantes AWQ, GPTQ et FP8 sur GPU, et lire le compromis réel entre taille, vitesse et qualité. Tous les chiffres de ce guide ont été relevés en lab — sur CPU pour la partie GGUF, sur un GPU H100 pour la partie serveur. Public visé : développeur ou ingénieur plateforme à l'aise avec Docker et la ligne de commande.
Ce que vous allez apprendre
Section intitulée « Ce que vous allez apprendre »- Convertir un modèle Hugging Face en GGUF puis le quantifier vous-même.
- Mesurer le compromis taille / débit / perplexité d'une quantification.
- Servir un modèle déjà quantifié en AWQ, GPTQ ou FP8 avec vLLM.
- Lire le gain VRAM et débit réel de chaque format sur GPU.
- Choisir le bon format selon votre matériel et votre priorité.
Prérequis
Section intitulée « Prérequis »Ce guide suppose acquis le vocabulaire de la quantification — précision, bits par paramètre, formats. Si ces notions sont floues, lisez d'abord Comprendre la quantification des LLM. Il vous faut également :
- Docker et le plugin Compose.
- Python 3.12 et
gitpour la partie conversion GGUF. - Un GPU NVIDIA pour la partie serveur (sinon, cette partie reste instructive en lecture).
La partie GGUF se reproduit entièrement sur un poste CPU. La partie GPU a été réalisée sur un H100, mais le principe vaut pour tout GPU récent.
Le pipeline GGUF : convertir et quantifier soi-même
Section intitulée « Le pipeline GGUF : convertir et quantifier soi-même »Le format GGUF est celui de l'écosystème llama.cpp et Ollama. Le quantifier soi-même se fait en deux temps : convertir le modèle Hugging Face en un GGUF non quantifié (16 bits), puis quantifier ce GGUF vers un format compact. Le modèle de démonstration est Qwen2.5-1.5B-Instruct, assez petit pour que tout le pipeline tienne en quelques minutes.
-
Récupérer le modèle Hugging Face.
Téléchargez les fichiers du modèle (poids
.safetensors, tokenizer, configs) dans un dossiermodels/Qwen2.5-1.5B-Instruct/. Le dépôtQwen/Qwen2.5-1.5B-Instructest public, aucun compte n'est requis. Vérifiez quemodel.safetensorspèse bien environ 3,1 Go — un fichier tronqué fera échouer la conversion. -
Convertir en GGUF 16 bits.
La conversion utilise le script
convert_hf_to_gguf.pyde llama.cpp. Ce script a besoin de dépendances Python (torch, transformers) et de son module interne — clonez donc le dépôt et travaillez dans un environnement virtuel.Fenêtre de terminal git clone --depth 1 https://github.com/ggml-org/llama.cppcd llama.cpppython3 -m venv .venv./.venv/bin/pip install --only-binary=:all: \-r requirements/requirements-convert_hf_to_gguf.txt./.venv/bin/python convert_hf_to_gguf.py ../models/Qwen2.5-1.5B-Instruct \--outtype f16 --outfile ../models/qwen2.5-1.5b-f16.ggufLe fichier
qwen2.5-1.5b-f16.ggufobtenu pèse environ 2,9 Gio. C'est la base non quantifiée, qui servira aussi de référence de qualité. -
Quantifier vers Q4_K_M, Q5_K_M et Q8_0.
L'outil
llama-quantizetransforme le GGUF 16 bits en variantes compactes. Il est inclus dans l'image Docker officielleghcr.io/ggml-org/llama.cpp:full.Fenêtre de terminal for Q in Q4_K_M Q5_K_M Q8_0; dodocker run --rm -v "$PWD/models:/models" \--entrypoint /app/llama-quantize \ghcr.io/ggml-org/llama.cpp:full \/models/qwen2.5-1.5b-f16.gguf /models/qwen2.5-1.5b-$Q.gguf $QdoneEn sortie, trois fichiers : le Q8_0 (8 bits), le Q5_K_M (~5,5 bits) et le Q4_K_M (~4,5 bits).
Mesurer le compromis taille / vitesse / qualité
Section intitulée « Mesurer le compromis taille / vitesse / qualité »Quantifier sans mesurer n'a pas de sens. Trois outils de llama.cpp suffisent : llama-bench pour le débit, llama-perplexity pour la qualité, et un simple ls -lh pour la taille.
La perplexité mérite un mot. C'est une mesure de la qualité d'un modèle de langage : elle évalue à quel point le modèle est « surpris » par un texte de référence. Plus elle est basse, mieux c'est. Quantifier dégrade légèrement le modèle, donc augmente un peu la perplexité — l'enjeu est de savoir de combien.
Voici les mesures relevées sur Qwen2.5-1.5B, CPU, avec un échantillon du corpus wikitext.
| Format | Taille | Génération | Perplexité | Écart de qualité |
|---|---|---|---|---|
| F16 | 2,88 Gio | 10,5 tok/s | 9,44 | référence |
| Q8_0 | 1,53 Gio | 16,9 tok/s | 9,46 | +0,2 % |
| Q5_K_M | 1,04 Gio | 24,2 tok/s | 9,62 | +1,9 % |
| Q4_K_M | 935 Mio | 30,8 tok/s | 10,01 | +6,0 % |
Trois enseignements ressortent. La taille chute fortement : le Q4_K_M divise le modèle par 3,2. La génération accélère à mesure qu'on quantifie — de 10,5 à 30,8 tokens/seconde, soit trois fois plus vite, parce que moins de bits signifie moins de données à déplacer en mémoire. Et la qualité se dégrade peu : le Q8_0 est imperceptible, le Q5_K_M très discret, le Q4_K_M visible mais modéré.
Servir un modèle quantifié sur GPU
Section intitulée « Servir un modèle quantifié sur GPU »Sur GPU, on quantifie rarement soi-même : on sert un modèle déjà quantifié, publié sur Hugging Face. Trois formats dominent — AWQ et GPTQ (4 bits), FP8 (8 bits) — et vLLM les charge tous. Le modèle de démonstration passe à Qwen2.5-14B-Instruct, une taille où la quantification a un vrai intérêt.
Les variantes AWQ et GPTQ sont des dépôts Hugging Face distincts. vLLM détecte automatiquement la quantification depuis la configuration du modèle.
docker run -d --name vllm-quant --runtime nvidia --gpus all --ipc host \ -p 8000:8000 -v hf-cache:/root/.cache/huggingface \ vllm/vllm-openai:latest \ --model Qwen/Qwen2.5-14B-Instruct-AWQ \ --max-model-len 8192 --gpu-memory-utilization 0.90Remplacez le suffixe -AWQ par -GPTQ-Int4 pour servir la variante GPTQ.
Le FP8 ne nécessite pas de dépôt dédié : vLLM peut quantifier le modèle à la volée au chargement, à partir des poids 16 bits, via l'option --quantization fp8.
docker run -d --name vllm-quant --runtime nvidia --gpus all --ipc host \ -p 8000:8000 -v hf-cache:/root/.cache/huggingface \ vllm/vllm-openai:latest \ --model Qwen/Qwen2.5-14B-Instruct --quantization fp8 \ --max-model-len 8192 --gpu-memory-utilization 0.90Pour connaître la mémoire réellement occupée par les poids, lisez les logs au démarrage : vLLM affiche une ligne Model loading took X GiB. C'est ce chiffre — et non la VRAM totale, qui inclut le cache — qui mesure le gain de la quantification.
Le gain mesuré sur GPU
Section intitulée « Le gain mesuré sur GPU »Les quatre variantes ont été servies sur le même H100, avec le même modèle Qwen2.5-14B et le même bench (200 requêtes, débit plafond).
| Variante | VRAM des poids | Débit total | Latence (TPOT) |
|---|---|---|---|
| bf16 (référence) | 27,6 Gio | 8 354 tok/s | 74,6 ms |
| AWQ 4 bits | 9,5 Gio | 9 474 tok/s | 70,1 ms |
| GPTQ-Int4 4 bits | 9,4 Gio | 9 604 tok/s | 69,4 ms |
| FP8 8 bits | 16,1 Gio | 12 417 tok/s | 55,8 ms |
Le résultat va à l'encontre d'une idée reçue : toutes les variantes quantifiées sont plus rapides que le bf16, pas seulement plus légères. Les formats 4 bits divisent la VRAM des poids par 2,9 et gagnent ~13 à 15 % de débit. Le FP8, lui, est spectaculaire : +49 % de débit par rapport au bf16.
Quel format choisir
Section intitulée « Quel format choisir »Aucun format n'est universellement supérieur. Le bon choix dépend de votre contrainte principale.
| Votre situation | Format conseillé |
|---|---|
| Inférence locale CPU, usage mono-utilisateur | GGUF Q4_K_M — compacité maximale, génération rapide |
| Inférence locale, la qualité prime | GGUF Q5_K_M ou Q8_0 |
| GPU, faire tenir un gros modèle sur peu de VRAM | AWQ ou GPTQ — compression par ~3 |
| GPU récent (Tensor Cores FP8), priorité au débit | FP8 — débit imbattable |
| Qualité de référence, VRAM suffisante | bf16 — pas de quantification |
La règle pratique : commencez par une quantification 4 bits (Q4_K_M en local, AWQ/GPTQ sur GPU). C'est un excellent point de départ. Vous ne reviendrez à une précision supérieure que si vous mesurez une dégradation gênante sur votre cas d'usage.
Dépannage
Section intitulée « Dépannage »Les incidents de quantification se résument à quelques causes connues.
| Symptôme | Cause probable | Solution |
|---|---|---|
model.safetensors rejeté à la conversion | Fichier tronqué au téléchargement | Re-télécharger ; vérifier la taille avec ls -lh |
ModuleNotFoundError au lancement de convert_hf_to_gguf.py | Script lancé hors du dépôt cloné | Travailler depuis le dépôt llama.cpp cloné, pas un script isolé |
CUDA out of memory en servant le modèle quantifié | --max-model-len trop élevé | Réduire la longueur de contexte, ou baisser --gpu-memory-utilization |
| Le FP8 n'accélère pas | GPU sans Tensor Cores FP8 | Utiliser AWQ/GPTQ sur un GPU antérieur à l'architecture Hopper/Ada |
| Qualité visiblement dégradée | Quantification trop agressive sur un petit modèle | Monter en Q5/Q8, ou prendre un modèle plus gros |
À retenir
Section intitulée « À retenir »- Le pipeline GGUF se fait en deux temps : convertir en 16 bits, puis quantifier vers Q4/Q5/Q8.
- Quantifier réduit la taille et accélère la génération — ce n'est pas qu'un compromis, c'est souvent un double gain.
- La perte de qualité reste faible jusqu'à 4 bits ; elle est plus marquée sur les petits modèles.
- Sur GPU, AWQ et GPTQ compressent le plus (÷2,9 de VRAM) ; le FP8 privilégie le débit.
- Le FP8 sur H100 gagne +49 % de débit grâce aux Tensor Cores FP8 natifs — un résultat lié au matériel.
- Choisir un format, c'est choisir sa contrainte prioritaire : VRAM, débit ou qualité.
pip installexécute du code : auditer ses sources fait partie du pipeline.