INT8 / FP8 Quantization — Support Hardware Native#
TL;DR — La quantification n'a d'intérêt pratique que si le matériel sait calculer directement dans le format compressé. Les GPU modernes (NVIDIA Hopper H100, Blackwell B200), les CPU (Intel AMX) et les accélérateurs (Apple ANE) intègrent désormais des unités de calcul dédiées pour INT8 et FP8. Ce support natif se traduit par un throughput jusqu'à 2× à 4× supérieur au FP16, sans perte d'accuracy notable. Comprendre la correspondance format ↔ hardware est le levier pour déployer des LLMs en production à grande échelle.
Pourquoi le support hardware matters#
Niveau néophyte#
Imaginez que vous deviez traduire un texte du chinois vers le français, mais que votre machine à traduire ne comprend que l'anglais. Vous devez faire une étape intermédiaire (chinois → anglais → français), ce qui prend deux fois plus de temps et introduit des erreurs.
Avec le support hardware natif, la machine traduit directement du chinois au français — pas d'étape intermédiaire, pas de surcoût. Pour les LLMs, le GPU peut multiplier des matrices en INT8 ou FP8 sans jamais repasser par le FP16, ce qui double voire quadruple la vitesse.
Le problème de la déquantification à la volée#
La plupart des méthodes de quantification (GPTQ INT4, AWQ, etc.) stockent les poids compressés mais doivent les déquantifier vers FP16 à chaque calcul :
juste moins de mémoire"] end
Tensor Cores INT8 natifs"] X8B["X_int8"] --> GEB GEB -. "Calcul DIRECTEMENT en INT8" .-> NOTE2["2× à 4× de speedup réel
Accumulation en INT32/FP32"] end
La différence est fondamentale : sans support hardware natif, la quantification ne fait que réduire la mémoire (utile pour l'edge) mais n'accélère pas le calcul. Avec le support natif, elle accélère tout — mémoire ET compute.
Les formats : FP8 E4M3 vs FP8 E5M2 vs INT8#
Diagramme bit-level#
Comparaison détaillée#
| Caractéristique | INT8 | FP8 E4M3 | FP8 E5M2 |
|---|---|---|---|
| Bits | 8 | 8 | 8 |
| Plage dynamique | 256 niveaux (fixe) | ±448 | ±57 344 |
| Précision relative | Constante | ~1.6% | ~6.25% |
| Niveaux représentables | -128…+127 | 240 valeurs finies | 120 valeurs finies |
| Gestion des outliers | ❌ Mauvaise (saturation) | ✅ Bonne | ✅ Excellente |
| Usage optimal | Activations, poids réguliers | Poids + activations forward | Gradients backward |
| Hardware | Volta+, AMX, ANE | Hopper H100+ | Hopper H100+ |
| Maturité | ★★★★★ (très mature) | ★★★☆☆ (2023+) | ★★★☆☆ (2023+) |
Pourquoi le FP8 gère mieux les outliers#
Les poids de LLMs suivent une distribution heavy-tailed (queue épaisse) avec quelques valeurs extrêmes :
Le FP8, grâce à son exponent, alloue dynamiquement la précision là où c'est nécessaire — plus de niveaux près de zéro, moins pour les grandes valeurs. L'INT8, lui, distribue ses niveaux uniformément, ce qui gaspille de la résolution sur les zones peu peuplées et sature sur les outliers.
Support hardware par plateforme#
Vue d'ensemble#
| Plateforme | INT8 | FP8 | Architecture |
|---|---|---|---|
| NVIDIA Volta | ✅ (V100) | ❌ | Tensor Cores |
| NVIDIA Ampere | ✅ (A100) | ❌ | Tensor Cores |
| NVIDIA Hopper | ✅ (H100) | ✅ ✅ | FP8 TC + TMA |
| NVIDIA Blackwell | ✅ (B200) | ✅ ✅ | FP8 + FP4 TC |
| AMD MI300x | ✅ | ✅ | Matrix Cores |
| Intel Xeon (AMX) | ✅ ✅ | ❌ | AMX tiles |
| Apple Silicon | ✅ (ANE) | ❌ | Neural Engine |
| Google TPU v5 | ✅ | ✅ (v5e+) | MXU |
NVIDIA Hopper (H100) — le game-changer FP8#
L'architecture Hopper a introduit le FP8 natif dans les Tensor Cores :
| Format | Dense | Sparse 2:4 |
|---|---|---|
| FP64 | 67 TFLOPS | — |
| FP32 | 67 TFLOPS | — |
| TF32 | 495 TFLOPS | 990 TFLOPS |
| BF16 | 989 TFLOPS | 1979 TFLOPS |
| FP8 | 1979 TFLOPS | 3958 TFLOPS 🚀 |
| INT8 | 1979 TOPS | 3958 TOPS |
FP8 = 2× la vitesse du BF16 en dense · 4× en sparse
Transformer Engine : gestion automatique du FP8 (E4M3 forward / E5M2 backward)
Le Transformer Engine (bibliothèque logicielle NVIDIA) gère automatiquement :
- La sélection du format FP8 (E4M3 pour forward, E5M2 pour backward)
- Le scaling dynamique par tile/tensor
- L'amax tracking (suivi de la valeur max d'activation)
- Le fallback vers BF16 si nécessaire
Intel AMX — INT8 sur CPU#
L'Advanced Matrix Extensions (AMX) d'Intel apporte des instructions matricielles INT8/BF16 directement sur CPU Xeon (Sapphire Rapids et ultérieurs) :
Apple Neural Engine (ANE)#
L'ANE des puces Apple Silicon (M1, M2, M3, M4) supporte nativement l'INT8 via le Apple Neural Engine :
| Puce | ANE TOPS | INT8 natif |
|---|---|---|
| M1 | 11 TOPS | ✅ |
| M2 | 15.8 TOPS | ✅ |
| M3 | 18 TOPS | ✅ |
| M4 | 38 TOPS | ✅ ✅ (amélioré) |
Framework : CoreML, MLX → inférence locale INT8 sur Mac/iPad
Pas de FP8 natif sur ANE (mais GPU Apple supporte FP16/BF16)
Niveau tech avancé : le pipeline FP8 complet#
Quantification FP8 statique (PTQ)#
amax = max(|activation|)
scale = max_fp8 / amax
FP8_max = 448 (E4M3)"] CAL --> WQ["**2. Quantification poids**
W_fp8 = round(W_fp16 × scale_w) → E4M3"] CAL --> XQ["**3. Quantification activations**
X_fp8 = round(X_fp16 × scale_x) → E4M3"] WQ --> GEMM["**4. Inférence native**
FP8 GEMM (Tensor Cores)
→ acc_fp32 → Y"] XQ --> GEMM GEMM -. "Scaling par-tensor ou par-token" .-> NOTE[""]
Granularités de quantification#
| Granularité | Description | Précision | Overhead mémoire | Usage |
|---|---|---|---|---|
| Per-tensor | 1 scale pour toute la matrice | Bas | Minimal (1 float) | Hopper Tensor Cores |
| Per-channel | 1 scale par colonne de poids | Bon | Modéré (N floats) | Standard INT8 |
| Per-token | 1 scale par token d'activation | Très bon | Modéré | Activations dynamiques |
| Per-block (MX) | 1 scale par bloc de 32 | Excellent | Non négligeable | Format Microscaling |
| Per-group | 1 scale par groupe de N | Variable | Selon N | INT4/INT8 custom |
Benchmarks throughput vs FP16#
Throughput théorique (Tensor Cores)#
FP8 dense = 2× le throughput du BF16 dense · INT8 dense = 2× · FP8/INT8 sparse = 4×
Benchmarks réels (vLLM, Llama-2-7B)#
| Configuration | GPU | Throughput (tok/s) | Speedup vs FP16 |
|---|---|---|---|
| FP16 (ref) | H100 | ~2 500 | 1.0× |
| INT8 W8A8 | H100 | ~3 800 | 1.5× |
| FP8 W8A8 | H100 | ~4 200 | 1.7× |
| INT8 W8A8 | A100 | ~1 800 | 1.2× |
| FP16 (ref) | A100 | ~1 500 | 1.0× |
Note : le speedup réel est inférieur au speedup théorique car le GEMM n'est qu'une partie du pipeline complet (attention, sampling, KV cache management).
Accuracy : INT8 / FP8 vs FP16#
| Modèle | Format | WikiText2 PPL | Δ vs FP16 | Évaluation |
|---|---|---|---|---|
| Llama-2-7B | FP16 | 5.47 | — | Référence |
| Llama-2-7B | INT8 (LLM.int8) | 5.49 | +0.02 | Quasi-lossless ✅ |
| Llama-2-7B | FP8 E4M3 | 5.48 | +0.01 | Quasi-lossless ✅ |
| Llama-2-70B | FP16 | 3.32 | — | Référence |
| Llama-2-70B | INT8 | 3.35 | +0.03 | Quasi-lossless ✅ |
| Llama-2-70B | FP8 E4M3 | 3.33 | +0.01 | Quasi-lossless ✅ |
À 8 bits, INT8 et FP8 sont essentiellement lossless pour la plupart des modèles ≥ 7B. C'est le régime « safe » de la quantification.
Outils principaux#
NVIDIA TensorRT-LLM — le standard production#
# Installation
pip install tensorrt-llm
# Quantification FP8 d'un modèle Hugging Face
python tensorrt_llm/quantization/quantize.py \
--model_dir meta-llama/Llama-2-7b-hf \
--dtype float16 \
--qformat fp8 \
--output_dir ./llama-7b-fp8 \
--calib_size 512
# Build du moteur TensorRT optimisé
trtllm-build \
--checkpoint_dir ./llama-7b-fp8 \
--output_dir ./llama-7b-fp8-engine \
--gemm_plugin fp8
# Inférence via l'API Python ou le serveur Triton
vLLM — le plus simple pour FP8#
# Servir un modèle en FP8 sur H100
python -m vllm.entrypoints.openai.api_server \
--model neuralmagic/Meta-Llama-3.1-8B-Instruct-FP8 \
--quantization fp8 \
--dtype auto \
--port 8000
# vLLM détecte le FP8 et utilise les Tensor Cores nativement
Intel OpenVINO — INT8 sur CPU#
from optimum.intel import OVQuantizer, OVModelForCausalLM
# Quantification INT8 avec calibration
model = OVModelForCausalLM.from_pretrained("meta-llama/Llama-2-7b-hf")
quantizer = OVQuantizer.from_pretrained(model)
# Calibration + quantification INT8
quantizer.quantize(
calibration_dataset=dataset,
save_directory="./llama-7b-int8-ov",
)
# Inférence sur CPU Xeon avec AMX
model_int8 = OVModelForCausalLM.from_pretrained("./llama-7b-int8-ov")
torch.compile — PyTorch natif#
import torch
# Quantification INT8 dynamique avec PyTorch 2+
model_fp16 = ... # votre modèle
# Quantization dynamique INT8 (activations)
model_int8 = torch.ao.quantization.quantize_dynamic(
model_fp16,
{torch.nn.Linear},
dtype=torch.qint8
)
# torch.compile avec backend optimisé
model_int8 = torch.compile(model_int8, mode="max-autotune")
# Pour FP8 (nécessite PyTorch 2.2+ + H100)
# Utiliser le Transformer Engine de NVIDIA :
import transformer_engine.pytorch as te
# Remplacer les Linear par des te.Linear (FP8 natif)
NVIDIA Transformer Engine — FP8 natif#
import transformer_engine.pytorch as te
import torch
# Modèle avec FP8 natif
model = te.TransformerLayer(
hidden_size=4096,
ffn_hidden_size=11008,
num_attention_heads=32,
)
# Le FP8 est géré automatiquement par le Transformer Engine
# Sélection E4M3 (forward) / E5M2 (backward) transparente
with te.fp8_autocast():
output = model(input_ids)
loss = loss_fn(output, labels)
loss.backward() # gradients en E5M2
Quand utiliser INT8 vs FP8#
(Hopper/Blackwell)"] Q --> A100["A100 / V100
(Ampere/Volta)"] Q --> AMD["AMD MI300x"] Q --> Intel["Intel Xeon (AMX)"] Q --> Apple["Apple Silicon"] Q --> CPU["CPU générique"] H100 --> FP8["**FP8 E4M3**
(meilleur accuracy + throughput)"] A100 --> INT8a["**INT8**
(FP8 non supporté nativement)"] AMD --> BOTH["**FP8 ou INT8**
(les deux supportés)"] Intel --> INT8b["**INT8 via OpenVINO**"] Apple --> INT8c["**INT8 via CoreML/MLX**"] CPU --> INT8d["**INT8 dynamique (PyTorch)**
ou FP16"]
Références#
- Papier FP8 Formats — Micikevicius et al., "FP8 Formats for Deep Learning", 2022 — arXiv:2209.05433
- Papier FP8 PTQ — "Efficient Post-training Quantization with FP8 Formats", MLSys 2024 — arXiv:2310.18313
- NVIDIA H100 Whitepaper — NVIDIA Hopper Architecture In-Depth
- NVIDIA Transformer Engine — docs.nvidia.com/deeplearning/transformer-engine
- Intel AMX — Intel Advanced Matrix Extensions
- NVIDIA TensorRT-LLM — github.com/NVIDIA/TensorRT-LLM
- OpenVINO — docs.openvino.ai
- Voir aussi : LLM.int8() · SmoothQuant · Index quantification