Quantification des modèles : précision numérique, taille et vitesse
La quantification approxime des valeurs numériques avec moins de bits. Son gain direct est de réduire les données à stocker et à déplacer. Vitesse et qualité dépendent du modèle, de la méthode, des opérateurs de calcul et du matériel. Partir d'un budget mémoire, puis identifier les éléments à comprimer, est plus utile que le seul libellé « 4-bit ».
Avant de choisir une compression, Nombres flottants et calcul stable aide à distinguer précision de représentation, étendue des valeurs et erreur de calcul.
Approximer un groupe de valeurs
Dans une quantification uniforme symétrique, on choisit une échelle s, on encode le poids w par q = round(w / s) dans un intervalle entier fini, puis on le reconstruit par s × q. Les valeurs hors plage sont écrêtées. La variante asymétrique ajoute un point zéro pour représenter une plage non centrée sur zéro.
Cet exemple fictif utilise une convention symétrique simplifiée sur 4 bits, de -7 à 7, avec un code inutilisé. Les formats réels peuvent différer.
weights = [-1.0, -0.2, 0.3, 1.0]
scale = max(abs(w) for w in weights) / 7
quantized = [max(-7, min(7, round(w / scale))) for w in weights]
restored = [round(q * scale, 3) for q in quantized]
print(quantized) # [-7, -1, 2, 7]
print(restored) # [-1.0, -0.143, 0.286, 1.0]
Les deux poids centraux changent : -0,2 devient -0,143, soit une erreur de 0,057 ; 0,3 devient 0,286, soit une erreur de 0,014.
Avec une seule échelle pour toute une couche, une valeur extrême rend les petits poids ordinaires grossiers. Gardons les mêmes nombres, mais remplaçons 1,0 par 3,5. L'échelle passe de 1 / 7 ≈ 0,143 à 3,5 / 7 = 0,5. Alors -0,2 / 0,5 = -0,4 s'arrondit à 0, et 0,3 / 0,5 = 0,6 s'arrondit à 1, reconstruit en 0,5. Les deux poids ordinaires portent désormais une erreur de 0,2, plus de trois fois et quatorze fois leurs erreurs précédentes. C'est pourquoi des échelles par canal ou par petit groupe épousent mieux les plages locales, mais ajoutent des métadonnées et modifient le coût des noyaux.
Faites glisser un poids, ou sélectionnez-le et utilisez ↑ ↓ (← → passe au voisin). Chaque groupe a une seule échelle, et chaque poids se cale sur le niveau le plus proche de la grille de son groupe.
Poids 7, groupe 2q = round(w / s) = round(0.08 / 0.101) = 1 → ŵ = s × q = 0.101 (erreur +0.021)
| Groupe | min … max | échelle s |
|---|---|---|
| 1 | −1.00 … 1.00 | max|w| / 7 = 1.00 / 7 = 0.143 |
| 2 | −0.55 … 0.71 | max|w| / 7 = 0.71 / 7 = 0.101 |
| 3 | −0.86 … 0.50 | max|w| / 7 = 0.86 / 7 = 0.123 |
| 4 | −0.47 … 0.64 | max|w| / 7 = 0.64 / 7 = 0.0914 |
- Erreur quadratique moyenne
- 0.028
- max 0.057
- Bits par poids
- 8
- 4 + 16 / 4 · groupes de 128 : 4,125
- 8 milliards de poids
- 8 Go
- 16 Go en 16 bits · 50 %
Poids inventés. Les bits par poids supposent une échelle de 16 bits par groupe et, en asymétrique, un point zéro stocké sur autant de bits que les codes ; les formats réels rangent leurs métadonnées autrement.
Quelles valeurs sont quantifiées ?
La présentation de Transformers détaille méthodes et compatibilités. Il faut distinguer trois objets :
Des poids sur 4 bits peuvent coexister avec des activations et un cache sur 16 bits. Le calcul peut déquantifier localement les poids avant une opération flottante. W4A16 signifie poids sur 4 bits et activations sur 16 bits, pas que tout le processus utilise quatre bits. Conteneur de fichier, algorithme et noyau d'exécution sont également distincts : télécharger un format ne garantit pas son efficacité sur le moteur et le matériel choisis.
Estimer la capacité avec ses frais annexes
Un modèle dense fictif d'exactement 8 milliards de poids demande 8 × 10^9 × 2 = 16 GB pour ses poids bruts sur 16 bits, et 8 × 10^9 × 0.5 = 4 GB sur 4 bits. Il s'agit ici de GB décimaux ; en GiB, cela fait environ 14,9 GiB et 3,7 GiB.
Le fichier contient aussi échelles, points zéro, tenseurs non quantifiés et métadonnées. L'exécution ajoute cache KV, tampons temporaires, moteur et requêtes simultanées. Quatre gigaoctets de poids ne garantissent donc pas une exécution dans quatre gigaoctets de VRAM avec n'importe quel contexte. Pour un mélange d'experts, distinguer paramètres activés par token et poids stockés ou chargés : l'activation parcimonieuse ne supprime pas le stockage du modèle complet.
Le suffixe d'un téléchargement indique le format et le nombre de bits
Quand on télécharge un modèle en local, un même modèle apparaît souvent sous forme d'une colonne de fichiers ; le suffixe de chaque nom est sa quantification. La documentation de quantize de llama.cpp donne les tailles réelles de Llama 3.1 8B à chaque niveau :
Le chiffre du suffixe est le nombre de bits principal ; la moyenne réelle est toujours un peu plus haute, car les facteurs d'échelle prennent aussi de la place. Selon les notes GGUF de Hugging Face, K désigne un k-quant : les poids sont regroupés en super-blocs de 256, redécoupés en petits blocs qui ont chacun leur facteur d'échelle. Q4_K fait donc environ 4,5 bits en pratique. Les lettres finales S, M et L sont des niveaux d'un mélange qui garde certains tenseurs à plus haute précision ; c'est pourquoi Q4_K_M porte environ 0,2 bit de plus que Q4_K_S. Les i-quants IQ s'appuient sur une matrice d'importance (imatrix) pour choisir l'approximation, et la documentation de llama.cpp indique qu'une imatrix adaptée réduit la perte en perplexité et en divergence de Kullback-Leibler. Comparons avec le calcul de la section précédente : 8 milliards de poids à 4 bits font 4 Go, mais le fichier Q4_K_M pèse 4,58 Gio, soit environ 4,9 Go ; l'écart, ce sont ces métadonnées et les tenseurs gardés à plus haute précision.
Hors GGUF, quelques autres formats sont courants :
- MLX : le format qu'utilise MLX sur Apple Silicon. mlx-lm convertit des poids Hugging Face en version quantifiée avec
mlx_lm.convert -q; l'exemple de la documentation produit un modèle 4 bits. Les fichiers MLX et GGUF ne sont pas interchangeables. - AWQ, GPTQ : des poids quantifiés pour GPU au format safetensors, surtout destinés à des serveurs comme vLLM et Transformers. La documentation de quantification de vLLM indique le matériel pris en charge pour chacun. Depuis vLLM 0.30.0, le
g_idxde l'ordre d'activation GPTQ est ignoré : vérifiez les anciens fichiers qui en dépendent. - MXFP4 : un format 4 bits à virgule flottante par blocs avec micro-mise à l'échelle, qui existe aussi comme type GGUF. gpt-oss-20b a quantifié ses poids MoE en MXFP4 pendant le post-entraînement, et sa fiche indique qu'il fonctionne dans 16 Go de mémoire.
- Fichiers QAT publiés par l'éditeur : Google publie un GGUF
qat-q4_0officiel pour Gemma 4 31B, un fichier de 17,7 Go. La fiche indique que l'entraînement conscient de la quantification préserve une qualité proche du bfloat16. C'est un exemple concret de la QAT décrite à la section suivante.
La précision du cache KV ne figure pas dans le nom du fichier ; elle se règle dans le runtime. Ollama utilise OLLAMA_KV_CACHE_TYPE, llama.cpp -ctk et -ctv, vLLM kv_cache_dtype. Ce que chaque niveau économise et ce qu'il coûte se trouve dans la note sur le cache KV.
PTQ, QAT et données de calibration
La quantification après entraînement, ou PTQ, approxime des poids existants. L'entraînement conscient de la quantification, ou QAT, tient compte de ses effets durant l'apprentissage. L'arrondi explique le principe ; des méthodes plus élaborées réduisent les erreurs importantes grâce aux distributions de poids et d'activations. GPTQ utilise des informations approximatives du second ordre pour quantifier les poids après entraînement ; AWQ utilise les statistiques d'activation pour identifier et protéger les canaux de poids importants.
Une autre voie est SmoothQuant : déplacer une partie des valeurs extrêmes des activations vers les poids, pour que les deux deviennent plus faciles à quantifier. Elle sert les accélérateurs serveur qui quantifient poids et activations ensemble, à la différence d'AWQ, qui ne quantifie que les poids.
La calibration estime ici plages ou erreurs d'approximation ; elle diffère de la calibration des probabilités, qui ajuste les probabilités de sortie. Code, longs contextes et tâches multilingues peuvent produire des distributions d'activation différentes. Un texte de calibration peu représentatif peut donner de bons résultats généraux tout en pénalisant la tâche visée.
LoRA adapte un petit ensemble de paramètres ; la distillation transmet le comportement d'un enseignant à un élève. Ces techniques ne sont pas une quantification numérique, même si elles se combinent. Voir transfert, LoRA et distillation.
Plus petit ne signifie pas toujours plus rapide
Quand une personne génère token après token, chaque nouveau token relit une fois tous les poids depuis la mémoire du GPU, et la lecture prend bien plus de temps que le calcul ; la note sur la performance d'inférence chiffre cette étape. Pour le modèle de 8 milliards de poids ci-dessus, 4 Go en 4 bits lisent trois quarts de moins par token que 16 Go en 16 bits : le décodage accélère. Mais si un noyau basse précision redécompresse d'abord les poids en 16 bits avant de calculer, convient mal au matériel ou se rabat sur une opération lente, le temps gagné est reperdu.
Le préremplissage d'un long prompt calcule beaucoup de tokens à la fois : son goulot est le calcul, et lire moins d'octets de poids aide peu. Le décodage token par token et les différentes tailles de lot ont chacun leurs contraintes ; un seul chiffre de vitesse ne résume donc pas un format de quantification.
Comparer les formats à modèle initial, moteur, matériel, prompts et budget de sortie constants. Mesurer pic mémoire, délai du premier token, débit de génération, exactitude et échecs concrets. Inclure longs textes, termes rares, sorties structurées et arguments d'outils, plutôt que seulement perplexité ou conversation. Des tentatives répétées dues à une précision trop basse peuvent absorber l'économie par inférence. La performance d'inférence précise les frontières de mesure.