Les poids d'un modèle sont des nombres à virgule flottante, stockés d'ordinaire sur 16 bits (FP16 ou BF16), soit 2 octets chacun. Un modèle de 7 milliards de paramètres occupe donc ~14 Go rien que pour ses poids — avant même le cache KV et les activations. Quantifier le modèle, c'est ré-encoder ces poids sur moins de bits : 8, 4, parfois moins. À 4 bits, les mêmes 7 milliards de paramètres tiennent dans ~3,5 Go.
La question intéressante n'est pas « comment » — c'est mécanique — mais « pourquoi ça ne détruit pas le modèle ». Diviser par quatre la précision numérique de milliards de coefficients devrait être catastrophique. En pratique, une quantification 4 bits bien faite reste à quelques dixièmes de point de perplexité du modèle d'origine. Comprendre pourquoi éclaire aussi les cas où ça casse.
Un poids, c'est un nombre — avec plus ou moins de chiffres
Quantifier, c'est projeter un intervalle continu de valeurs réelles sur une grille de quelques niveaux entiers. Pour un bloc de poids, on retient une échelle s (et parfois un décalage), puis chaque poids devient : q = round(w / s), stocké comme un petit entier. À l'inférence, on reconstruit une approximation : w ≈ s × q. L'écart entre w et sa reconstruction est l'erreur de quantification — au plus une demi-marche de grille.
Tout l'enjeu est la granularité de l'échelle. Une seule échelle pour toute une matrice (per-tensor) est grossière : un poids aberrant lointain étire la grille et dégrade tous les autres. Une échelle par colonne (per-channel), ou par petit groupe de 32 à 128 poids (per-group), colle beaucoup mieux à la distribution locale — c'est le réglage standard en 4 bits, pour un surcoût mémoire négligeable.
s × q retombe à côté de la valeur d'origine, d'un peu.Pourquoi ça ne détruit pas le modèle
Trois raisons se cumulent :
- Les réseaux sont robustes au bruit sur les poids. Ils ont été entraînés avec du dropout, du bruit de gradient, une précision déjà limitée. Une perturbation aléatoire de faible amplitude sur chaque poids se comporte comme un bruit de plus, que les couches suivantes absorbent.
- L'erreur se moyenne. Une sortie de couche est une somme de milliers de produits
poids × activation. Si les erreurs de quantification sont à peu près centrées et indépendantes, elles se compensent partiellement dans la somme — le résultat dévie bien moins que chaque terme pris isolément. - La distribution des poids s'y prête. L'immense majorité des poids est concentrée près de zéro, sur une plage étroite qu'une grille fine couvre bien. Ce sont les rares valeurs extrêmes qui posent problème.
D'où les méthodes modernes, qui ne quantifient pas aveuglément. LLM.int8() détecte les colonnes d'activations à fortes valeurs aberrantes et les garde en 16 bits, le reste en int8. GPTQ quantifie les poids couche par couche en ajustant les poids restants pour compenser l'erreur déjà commise, colonne après colonne. AWQ repère les canaux de poids les plus « saillants » (ceux dont l'activation associée est grande) et les met à l'échelle avant l'arrondi pour les protéger. Toutes utilisent un petit jeu de données de calibration pour mesurer où l'erreur fait mal.
Où le compromis se paie
| Format | Poids d'un 7B | Débit relatif* | Perte de qualité | Usage |
|---|---|---|---|---|
| FP16 / BF16 | ~14 Go | 1× | référence | entraînement, inférence sans contrainte mémoire |
| int8 (LLM.int8, per-channel) | ~7 Go | ~1,3× | quasi nulle | défaut sûr pour servir un modèle |
| int4 (GPTQ / AWQ, per-group) | ~3,5–4 Go | ~1,5–2× | faible (< ~0,5 pt de perplexité) | faire tenir un gros modèle sur un GPU modeste |
| int4 naïf (per-tensor) | ~3,5 Go | ~1,5× | notable, parfois cassante | à éviter |
| int2 / int3 | < 3 Go | ~2× | forte en dessous de ~13B | expérimental, gros modèles seulement |
Quantifier pour entraîner : QLoRA
La quantification ne sert pas qu'à servir un modèle : elle rend aussi le finetuning accessible. QLoRA gèle le modèle de base en 4 bits (dans un format dédié, NF4, calé sur la distribution normale des poids), et n'entraîne que des adaptateurs LoRA en BF16 par-dessus. Les gradients ne traversent que les adaptateurs ; le modèle gelé sert seulement de fonction fixe. Résultat : un modèle qui demanderait 60 Go pour un finetuning classique tient sur un seul GPU de 24 Go. Le modèle de base ne bouge pas — sa quantification n'est jamais réapprise, seulement lue.
Ce que la quantification ne fait pas
- Elle n'accélère pas magiquement tout. Le gain est net en decode (memory-bound), faible en prefill (compute-bound), et nul si les noyaux de calcul du runtime ne savent pas exploiter le format choisi.
- Quantifier les activations est plus dur que les poids. Les activations varient selon l'entrée et contiennent des valeurs aberrantes marquées ; la plupart des schémas 4 bits ne quantifient que les poids et gardent les activations en 16 bits.
- Les petits modèles encaissent mal. En dessous de ~3B paramètres, la marge de redondance est plus faible : une quantification 4 bits agressive y fait plus de dégâts que sur un 70B.
- Ce n'est pas de la compression sans perte. L'erreur est réelle ; elle est juste, en général, sous le seuil qui changerait la réponse. À valider avec une évaluation sur ta tâche, pas sur la foi d'un benchmark générique.
FAQ
Quantifier un modèle le rend-il moins bon ?
Un peu, et souvent de façon imperceptible. En int8 la perte est quasi nulle ; en int4 avec une méthode moderne (GPTQ, AWQ, per-group), elle reste sous le demi-point de perplexité sur les modèles de 7B et plus. En dessous de 4 bits ou sur de petits modèles, la dégradation devient visible.
int8 ou int4 ?
int8 est le choix sûr pour servir un modèle sans presque rien perdre. int4 se justifie quand il faut faire tenir un modèle plus gros sur un GPU donné, ou gagner en débit sur la phase decode. En dessous de int4, réservé aux très gros modèles et à l'expérimentation.
La quantification accélère-t-elle l'inférence ?
Surtout la génération token par token, qui est limitée par la lecture mémoire : moins de bits par poids, moins de mémoire à lire, plus de tokens par seconde. Le traitement du prompt, limité par le calcul, en profite beaucoup moins.