Polydesk-logotype
Polydesk.ai — Header

INT8 (Integer 8-bit)

INT8 est un type de donnée entier signé codé sur 8 bits (1 octet), capable de représenter des valeurs de -128 à 127, utilisé en quantization pour réduire de moitié l’empreinte mémoire des modèles d’IA par rapport au format FP16, tout en conservant une qualité quasi identique à l’original.

C’est le format de quantification le plus sûr et le plus éprouvé pour déployer un LLM en production. Un modèle de 7 milliards de paramètres en FP16 occupe environ 14 Go de VRAM. En INT8, il passe à ~7 Go. Et sur la majorité des benchmarks, la perte de qualité se mesure à moins de 0,5 %. C’est le choix par défaut quand vous voulez optimiser sans prendre de risque.

INT8 en bref
Type
Entier signé 8 bits
Plage de valeurs
-128 à 127 (signé) / 0 à 255 (non signé)
Taille
1 octet par valeur
Gain mémoire
~50 % vs FP16, ~75 % vs FP32
Perte de qualité
< 0,5 % sur les benchmarks standards (MMLU, HellaSwag)
Méthodes associées
LLM.int8(), SmoothQuant (W8A8), GPTQ-INT8, bitsandbytes
Outils compatibles
vLLM, TensorRT-LLM, TGI, bitsandbytes, ONNX Runtime
GPU supportés
NVIDIA Turing (RTX 20xx) et suivants, jusqu’à Hopper (H100). Attention : limitation sur Blackwell (SM ≥ 10.0)

Comment fonctionne la représentation INT8

Comprendre INT8 nécessite de saisir la différence fondamentale entre les formats à virgule flottante (FP16, BF16, FP32) et les formats entiers.

Virgule flottante vs entier

Les formats flottants (FP16, BF16, FP32) utilisent un système signe + exposant + mantisse qui leur permet de représenter une très large gamme de valeurs, des très petits nombres aux très grands, avec une précision variable. C’est flexible mais coûteux en bits. FP16 utilise 16 bits : 1 de signe, 5 d’exposant, 10 de mantisse.

INT8, en revanche, est un format fixe et linéaire. 8 bits, dont 1 pour le signe, représentent directement un entier. Pas d’exposant, pas de mantisse. Les 256 valeurs possibles sont réparties uniformément sur l’intervalle [-128, 127]. C’est moins flexible, mais les opérations arithmétiques en entier sont nettement plus rapides et plus efficaces en énergie sur la quasi-totalité du matériel, des CPU x86 aux Tensor Cores NVIDIA.

Le processus de quantification vers INT8

Pour convertir un poids FP16 en INT8, on utilise un facteur d’échelle (scale factor) qui mappe la plage de valeurs flottantes vers la plage entière [-128, 127]. Voici le calcul concret :

Prenez un poids FP16 de valeur 0.15625, dans un groupe où la valeur maximale absolue est 1.0. Le scale factor est 127 / 1.0 = 127. On multiplie : 0.15625 × 127 = 19.84. On arrondit à l’entier le plus proche : 20. Ce 20 est stocké sur 8 bits (soit 00010100 en binaire). À l’inférence, pour déquantifier, on divise : 20 / 127 = 0.15748. L’erreur est d’environ 0,7 % sur cette valeur individuelle.

En pratique, cette quantification ne se fait pas sur l’ensemble du modèle avec un seul scale factor (ce qui serait désastreux). Elle opère par groupes de poids (typiquement 64 à 128 éléments), chaque groupe ayant son propre scale factor. Plus les groupes sont petits, meilleure est la précision, au prix de quelques octets supplémentaires pour stocker les facteurs d’échelle.

Quantification symétrique vs asymétrique

Deux variantes existent pour le mapping :

Quantification symétrique : la plage [-max_abs, +max_abs] est mappée sur [-127, 127]. Le zéro FP16 correspond exactement au zéro INT8. C’est la méthode la plus courante pour les poids de LLM, car ils sont généralement centrés autour de zéro. Elle est aussi plus rapide sur le matériel, car il n’y a pas de décalage (zero-point) à gérer.

Quantification asymétrique : la plage [min, max] des valeurs est mappée sur [0, 255] (unsigned) ou [-128, 127] avec un zero-point non nul. Plus précise quand la distribution n’est pas centrée, elle est surtout utilisée pour les activations, qui peuvent être asymétriques (par exemple après une fonction ReLU).

Poids vs Activations Les poids d’un modèle sont statiques (connus avant l’inférence) et faciles à quantifier : on peut analyser leur distribution à l’avance. Les activations, en revanche, sont dynamiques (elles changent à chaque entrée) et peuvent contenir des outliers difficiles à représenter en 8 bits. C’est pourquoi quantifier les activations en INT8 nécessite des techniques spécifiques comme SmoothQuant.

Impact concret sur la mémoire

L’arithmétique est directe : chaque paramètre passe de 2 octets (FP16) à 1 octet (INT8). Voici ce que ça donne en pratique pour les modèles courants :

Modèle Paramètres Poids FP16 Poids INT8 Économie
Llama 3.1 8B 8 milliards ~16 Go ~8,5 Go ~47 %
Mistral 7B 7 milliards ~14 Go ~7,5 Go ~47 %
Llama 3.1 70B 70 milliards ~140 Go ~70 Go ~50 %
Qwen3 32B 32 milliards ~64 Go ~32 Go ~50 %

Les chiffres réels sont légèrement supérieurs aux 50 % théoriques car il faut stocker les scale factors de chaque groupe. Pour un Llama 3.1 8B, la version FP16 pèse environ 16 Go, et la version Q8_0 (GGUF) environ 8,5 Go. Ces valeurs ne couvrent que les poids : en inférence, il faut ajouter le cache KV, les activations, et l’overhead du framework.

Mémoire totale en inférence Pour un modèle 8B en INT8 avec un contexte de 4096 tokens et un seul utilisateur, comptez environ 8,5 Go pour les poids + 1 à 2 Go pour le cache KV et l’overhead. Un GPU de 12 Go (RTX 3060/4060) gère ça confortablement. Pour 70B en INT8, il faut environ 70 Go pour les poids seuls, ce qui nécessite un GPU serveur (A100 80 Go, H100 80 Go) ou un split multi-GPU.

Impact sur la qualité du modèle

C’est la question cruciale, et la réponse est rassurante : INT8 est le format de quantification le plus sûr en termes de préservation de la qualité.

Ce que disent les benchmarks

Les mesures récentes sont convergentes. Sur un Qwen3 32B, la dégradation mesurée entre BF16 et INT8 est de seulement 0,04 % sur MMLU-Pro. C’est statistiquement du bruit. Sur des modèles 8B type Llama 3.1, les formats Q8_0 (GGUF) et EXL2 à 8 bpw (bits per weight) montrent moins de 1 % de dégradation par rapport à FP16 sur les métriques MMLU et HellaSwag.

Cette stabilité s’explique par le fait que 256 niveaux de quantification (ce que permet INT8) capturent la quasi-totalité de la plage dynamique des poids d’un LLM. La distribution des poids dans un Transformer suit approximativement une courbe normale centrée autour de zéro, et 8 bits suffisent largement pour la représenter fidèlement.

Les cas où INT8 peut poser problème

INT8 n’est pas parfait dans tous les scénarios. Les tâches de raisonnement mathématique très poussé ou de code complexe sont les plus sensibles à la perte de précision. Les modèles plus petits (sous 3B de paramètres) supportent moins bien la quantification que les gros modèles, car chaque poids individuel a plus d’importance relative. Et si vous quantifiez à la fois les poids ET les activations (W8A8), la qualité dépend fortement de la méthode utilisée pour gérer les outliers dans les activations.

En résumé : pour 99 % des cas d’usage courants (conversation, rédaction, résumé, Q&A, code standard), INT8 est imperceptiblement différent de FP16.

Les méthodes de quantification INT8

Plusieurs approches permettent de quantifier un modèle en INT8, chacune avec ses compromis.

LLM.int8() (bitsandbytes)

Publiée par Tim Dettmers en 2022, LLM.int8() est la méthode qui a démocratisé la quantification 8 bits pour les LLM. Son innovation clé : une décomposition en précision mixte. Les poids « normaux » sont quantifiés en INT8 classique, tandis que les outliers (les colonnes d’activation dont au moins une valeur dépasse un seuil) sont traités séparément en FP16. Ce traitement spécial des outliers permet de conserver la qualité complète du modèle original, même sur des modèles de 175 milliards de paramètres.

L’utilisation est triviale avec Hugging Face Transformers :

from transformers import AutoModelForCausalLM model = AutoModelForCausalLM.from_pretrained( "meta-llama/Llama-3.1-8B-Instruct", load_in_8bit=True, device_map="auto" )

Le seuil par défaut pour détecter les outliers est 6.0. Si une valeur d’activation dépasse ce seuil dans une colonne, toute la colonne est calculée en FP16. Vous pouvez ajuster ce seuil via llm_int8_threshold, mais la valeur par défaut convient à la grande majorité des modèles.

LLM.int8() ne fournit pas d’accélération Contrairement à ce qu’on pourrait penser, LLM.int8() ne rend pas l’inférence plus rapide. La décomposition mixte (INT8 + FP16 pour les outliers) introduit un overhead qui compense le gain de la quantification. L’intérêt est purement la réduction mémoire. Pour obtenir une vraie accélération en INT8, il faut se tourner vers SmoothQuant + vLLM ou TensorRT-LLM.

SmoothQuant (W8A8)

SmoothQuant, développé par le MIT Han Lab, résout le problème fondamental de la quantification d’activations : les outliers. L’idée est élégante. Les poids sont faciles à quantifier (distribution stable, connue à l’avance). Les activations sont difficiles (distribution variable, outliers imprévisibles). SmoothQuant applique une transformation mathématiquement équivalente qui « transfère » une partie de la difficulté des activations vers les poids, en lissant les distributions d’activation avant la quantification.

Le résultat est un modèle W8A8 : poids en INT8, activations en INT8. Contrairement à LLM.int8() qui ne quantifie que les poids, SmoothQuant quantifie les deux, ce qui permet une vraie accélération matérielle. Les benchmarks montrent jusqu’à 2× de réduction mémoire et jusqu’à 1,56× d’accélération par rapport à FP16. C’est la méthode de référence pour le déploiement production haute performance en INT8.

GPTQ en mode INT8

GPTQ est surtout connu pour la quantification 4 bits, mais il supporte aussi INT8. En mode INT8, GPTQ quantifie les poids couche par couche en utilisant un dataset de calibration et une approximation de second ordre (basée sur la matrice Hessienne) pour minimiser l’erreur de reconstruction. Les résultats en INT8 sont excellents, comparables à SmoothQuant pour les poids, mais GPTQ ne quantifie pas les activations.

W8A8 avec vLLM + LLM Compressor

La combinaison la plus puissante pour la production : vLLM supporte nativement les modèles W8A8 (poids et activations en INT8). Le workflow typique combine SmoothQuant (pour lisser les activations) puis GPTQ (pour optimiser les poids), produisant un modèle INT8 complet. Le calcul INT8 est supporté sur les GPU NVIDIA de compute capability > 7.5 (Turing, Ampere, Ada Lovelace, Hopper).

from llmcompressor import oneshot from llmcompressor.modifiers.quantization import GPTQModifier from llmcompressor.modifiers.smoothquant import SmoothQuantModifier recipe = [ SmoothQuantModifier(smoothing_strength=0.8), GPTQModifier(targets="Linear", scheme="W8A8", ignore=["lm_head"]), ] oneshot( model=model, dataset=ds, recipe=recipe, max_seq_length=2048, num_calibration_samples=512, )

Des checkpoints W8A8 pré-quantifiés sont disponibles sur le Hugging Face Hub pour les modèles les plus populaires, prêts à charger directement dans vLLM.

Q8_0 via GGUF (llama.cpp)

Dans l’écosystème GGUF / llama.cpp, le format Q8_0 est l’équivalent de l’INT8 « poids seuls ». C’est la quantification la plus fidèle disponible en GGUF (la plus haute qualité avant le FP16 natif). Q8_0 quantifie chaque bloc de 32 poids avec un seul scale factor en FP16, ce qui donne environ 8,5 bits effectifs par poids (8 bits pour le poids + l’overhead du scale factor). Pour l’utiliser avec Ollama :

ollama run llama3.1:8b-q8_0

Q8_0 est parfait quand vous avez assez de mémoire pour vous le permettre et que vous voulez la meilleure qualité possible avec un format GGUF. Pour la plupart des gens qui font de l’inférence locale avec un bon GPU, c’est un choix solide.

Comparaison des méthodes INT8

Méthode Quantifie les poids Quantifie les activations Accélération Complexité Cas d’usage
LLM.int8() (bitsandbytes) Oui Non (FP16 pour outliers) Non (parfois plus lent) Très faible (2 lignes de code) Prototypage, fine-tuning
SmoothQuant + GPTQ (W8A8) Oui Oui Oui (1,5× à 2×) Moyenne (calibration requise) Production GPU haute performance
GPTQ-INT8 (poids seuls) Oui Non Limitée Moyenne (calibration requise) Serving avec vLLM/AutoGPTQ
Q8_0 (GGUF) Oui Non Selon le backend Très faible (prêt à l’emploi) Inférence locale (Ollama, LM Studio)
TensorRT-LLM INT8 Oui Oui (optionnel) Oui (maximale sur NVIDIA) Élevée (compilation requise) Production NVIDIA max performance

INT8 vs INT4 : comment choisir

Le débat INT8 vs INT4 est le plus fréquent en matière de quantification. Voici un cadre de décision clair.

Choisissez INT8 quand : la qualité est votre priorité absolue, vous avez suffisamment de VRAM, vous travaillez sur des tâches sensibles à la précision (raisonnement, code, mathématiques), ou vous débutez en quantification et voulez un choix sûr.

Choisissez INT4 quand : vous êtes contraint par la VRAM (GPU de 8 Go ou moins), vous voulez maximiser le throughput (plus de requêtes concurrentes), vos tâches sont tolérantes (conversation, rédaction, Q&A), ou vous déployez sur du matériel edge/mobile.

Critère INT8 INT4
Bits par poids 8 4
Taille modèle 7B ~7 Go ~3,5-5 Go
Perte qualité typique < 0,5 % 1-3 % (selon méthode)
Sensibilité au raisonnement Quasi nulle Perceptible sur tâches complexes
GPU 8 Go (ex. RTX 4060) 7B serré, 13B impossible 7B confortable, 13B possible
GPU 12 Go (ex. RTX 4060 Ti) 7B confortable 13B possible
GPU 24 Go (ex. RTX 4090) 13B confortable 32B-70B (selon modèle)
Concurrence en production (H100) ~18 users (4K context) ~47 users (4K context)
La règle pragmatique Commencez par INT8. Mesurez la qualité sur vos données. Mesurez la mémoire et le throughput sur votre matériel. Ne passez à INT4 que si les chiffres le justifient. Dans bien des cas, INT8 est « juste assez petit » pour vos besoins, et la tranquillité d’esprit sur la qualité vaut les Go supplémentaires.

INT8 vs FP8 : le successeur arrive

FP8 est un format 8 bits qui utilise une représentation à virgule flottante (signe + exposant + mantisse) au lieu de la représentation entière d’INT8. Il offre une plage dynamique plus large et nécessite moins de calibration. Sur les GPU NVIDIA Hopper (H100, H200) et suivants, FP8 est supporté nativement via le Transformer Engine, qui bascule dynamiquement entre FP8 et FP16 couche par couche.

En termes de mémoire, FP8 et INT8 sont équivalents : 1 octet par paramètre, soit ~50 % d’économie vs FP16. La différence est dans la qualité et la facilité d’utilisation :

FP8 tend à offrir une qualité légèrement supérieure à INT8 pour le même nombre de bits, grâce à sa capacité à mieux représenter les valeurs éloignées de zéro. En revanche, INT8 bénéficie d’un support matériel bien plus large (tous les GPU depuis Turing/RTX 20xx) et d’un écosystème logiciel plus mature.

Limitation Blackwell (RTX 50xx, B200) Point important : sur les GPU NVIDIA Blackwell (compute capability ≥ 10.0, comme la RTX 5090 ou la B200), les kernels GEMM INT8 ne sont pas supportés nativement dans vLLM et d’autres frameworks. NVIDIA pousse FP8 comme le format 8 bits de référence sur cette architecture. Si vous utilisez du matériel Blackwell, utilisez FP8 au lieu d’INT8. Sur Hopper (H100) et antérieur, INT8 reste pleinement supporté.

Compatibilité matérielle

Le support INT8 varie selon les générations de GPU. Voici l’état des lieux :

Architecture NVIDIA Compute Capability Exemples Support INT8 Notes
Volta 7.0 V100 Limité Support basique via certains frameworks
Turing 7.5 RTX 2080, T4 Oui Tensor Cores avec support INT8 natif
Ampere 8.0 / 8.6 A100, RTX 3090 Oui Excellentes performances INT8
Ada Lovelace 8.9 RTX 4090, L40 Oui Performances INT8 optimales
Hopper 9.0 H100, H200 Oui INT8 + FP8 natif via Transformer Engine
Blackwell 10.0 / 12.0 B200, RTX 5090 Non (GEMM) Utiliser FP8 à la place. INT8 TOPS listés dans les specs mais GEMM non supporté dans vLLM

Côté CPU, l’inférence INT8 est supportée par llama.cpp (via GGUF Q8_0), ONNX Runtime, et d’autres frameworks. Les CPU modernes x86 (Intel et AMD) disposent d’instructions VNNI (Vector Neural Network Instructions) qui accélèrent les multiplications matricielles INT8. Les processeurs Apple Silicon (M1 et suivants) supportent aussi l’inférence INT8 via le Neural Engine et l’ANE (Apple Neural Engine).

INT8 en production : bonnes pratiques

Choisir la bonne méthode selon votre stack

Si vous servez un modèle via vLLM, la voie royale est W8A8 (SmoothQuant + GPTQ via LLM Compressor). Vous obtenez une vraie accélération et une réduction mémoire. Utilisez 512 échantillons de calibration représentatifs de vos données de production, avec une longueur de séquence de 2048 tokens.

Si vous utilisez TGI (Hugging Face), les modèles GPTQ-INT8 fonctionnent directement. TGI les détecte automatiquement au chargement.

Si vous faites de l’inférence locale avec Ollama, téléchargez simplement la variante Q8_0 du modèle. C’est le format le plus fidèle en GGUF.

L’importance de la calibration

Pour les méthodes qui requièrent une calibration (SmoothQuant, GPTQ), le choix du dataset de calibration impacte la qualité finale. Quelques règles :

Utilisez des données qui ressemblent à votre cas d’usage réel. Si vous servez un chatbot, utilisez des conversations. Si c’est du code, utilisez du code. 512 échantillons est un bon point de départ. Augmentez si la qualité baisse. Appliquez le template de chat du modèle lors de la tokenisation des échantillons. Et surtout, évaluez la qualité du modèle quantifié sur vos propres métriques, pas seulement sur la perplexité WikiText-2.

Quantification du cache KV

Au-delà des poids, le cache KV peut lui aussi être quantifié en INT8 (ou FP8), indépendamment de la quantification des poids. Cela divise par deux la mémoire consommée par le cache, ce qui est particulièrement impactant pour les longs contextes et les scénarios à forte concurrence. vLLM supporte cette option nativement. Pour un modèle 8B avec un contexte de 32K tokens, le cache KV en FP16 peut consommer jusqu’à 4-5 Go. En INT8, il tombe à 2-2,5 Go.

Limites et considérations

INT8 n’est pas la solution universelle. Voici ses limites :

Pas toujours plus rapide. La quantification INT8 « poids seuls » (comme LLM.int8()) ne fournit pas nécessairement d’accélération, car la déquantification à FP16 se fait à la volée. Pour obtenir un vrai gain de vitesse, il faut une quantification W8A8 complète (poids + activations) avec des kernels optimisés.

Le « unpacking tax ». Sur certains matériels et à petit batch size, le coût de décompression des poids INT8 vers FP16 pour le calcul peut annuler une partie du gain de bande passante. Le bénéfice de vitesse est surtout visible à haute concurrence (batch size élevé).

Modèles anciens moins bien supportés. Les modèles qui n’ont pas été conçus avec la quantification en tête (architectures pré-2023) peuvent montrer des dégradations plus marquées en INT8, car leurs distributions de poids et activations ne sont pas optimisées pour ça.

FP8 le remplace sur Blackwell. Comme mentionné plus haut, NVIDIA oriente clairement l’écosystème vers FP8 pour les GPU de dernière génération. INT8 reste pertinent sur Hopper et antérieur, mais planifiez une migration vers FP8 si vous investissez dans du matériel Blackwell.


Questions fréquentes sur INT8

INT8 divise-t-il vraiment la mémoire par deux ?

Pour les poids du modèle, oui, quasiment. Chaque paramètre passe de 2 octets (FP16) à 1 octet (INT8), avec un léger overhead pour les scale factors (quelques pourcents supplémentaires). En pratique, pour un modèle 7B, vous passez de ~14 Go à ~7,5 Go pour les poids. Attention : la mémoire totale en inférence inclut aussi le cache KV et l’overhead du framework, qui restent en précision supérieure sauf si vous les quantifiez aussi séparément.

Quelle est la différence entre INT8 et FP8 ?

Les deux utilisent 8 bits (1 octet), mais la représentation diffère. INT8 code un entier sur une plage fixe [-128, 127]. FP8 utilise un format à virgule flottante (signe + exposant + mantisse) qui offre une plage dynamique plus large. En pratique, FP8 nécessite moins de calibration et offre souvent une qualité légèrement meilleure. Son inconvénient : il requiert un GPU Hopper (H100) ou plus récent pour les kernels natifs. INT8 fonctionne sur tout GPU depuis les RTX 20xx (Turing), ce qui le rend beaucoup plus accessible.

Comment quantifier un modèle en INT8 le plus simplement possible ?

La méthode la plus simple est bitsandbytes avec Hugging Face Transformers : ajoutez load_in_8bit=True au chargement du modèle. Zéro calibration, zéro configuration. Pour l’inférence locale, utilisez Ollama avec un modèle au format Q8_0 : ollama run llama3.1:8b-q8_0. Pour la production, téléchargez un checkpoint W8A8 pré-quantifié depuis le Hugging Face Hub et chargez-le dans vLLM.

INT8 est-il compatible avec le fine-tuning ?

Oui, grâce à QLoRA et bitsandbytes. Vous pouvez charger un modèle en INT8 (ou même en 4 bits NF4) et ajouter des adaptateurs LoRA entraînables en FP16. C’est la technique standard pour fine-tuner un gros modèle sur un seul GPU. Le modèle de base reste gelé en INT8, seuls les adaptateurs sont entraînés en pleine précision. Les résultats sont proches d’un fine-tuning FP16 complet pour la plupart des tâches.

Dois-je utiliser INT8 ou Q4_K_M pour mon LLM local ?

Si vous avez suffisamment de VRAM/RAM, Q8_0 (GGUF) offre la meilleure qualité. Pour un modèle 8B, comptez ~8,5 Go vs ~4,5-6 Go pour Q4_K_M. Si votre matériel est limité (8 Go de VRAM), Q4_K_M est le meilleur compromis : il conserve 97-99 % de la qualité originale avec une empreinte nettement plus compacte. La recommandation de la communauté llama.cpp est claire : Q4_K_M si vous êtes contraint, Q8_0 si vous pouvez vous le permettre. Les formats intermédiaires (Q5_K_M, Q6_K) offrent des compromis entre les deux.

Polydesk.ai — Footer