FP4 / FP8 — Quantification en Point Flottant#
TL;DR — La quantification floating-point (FP4, FP8) est une alternative à la quantification entière (INT4, INT8) qui exploite la structure exponent/mantisse pour mieux représenter les distributions heavy-tailed des poids de LLMs. Le FP8 (E4M3, E5M2) est déjà supporté nativement sur NVIDIA Hopper H100 ; le FP4 (E2M1) arrive avec Blackwell B200. Les formats Microscaling (MX) standardisés par l'OCP ajoutent un shared scale par bloc de 32 valeurs, offrant le meilleur des deux mondes.
Floating-point vs Integer : le débat fondamental#
Niveau néophyte#
Imaginez que vous devez mesurer la taille de tous les humains sur Terre avec une règle. Une règle entière (INT) a des graduations régulières : un trait tous les centimètres, de 0 à 200 cm. Problème : la plupart des humains font entre 150 et 190 cm, là où les graduations sont très serrées et précises — mais les quelques personnes mesurant 2m20+ débordent de la règle.
Une règle flottante (FP) a des graduations non-uniformes : très précise près de la moyenne (1 mm de précision vers 170 cm), mais avec des graduations plus espacées pour les extrêmes (1 cm de précision vers 250 cm). Elle couvre une plage bien plus large avec le même nombre de graduations, en mettant la précision là où elle compte.
Les poids des LLMs sont comme la taille des humains : concentrés autour d'une moyenne, avec quelques outliers (valeurs extrêmes). Le floating-point gère mieux ces distributions.
Le problème des outliers en quantification LLM#
Les formats floating-point en détail#
Structure générale d'un nombre flottant#
(ordre de grandeur)"| note_e[" "] m -->|"précision
(digits significatifs)"| note_m["Valeur = (-1)^S × 2^(E - bias) × (1 + M/2^mant_bits)"]
L'insight clé : l'exponent gère la plage et la mantissa gère la précision. Avec peu de bits, il faut choisir son compromis :
- Plus d'exponent → plus de plage dynamique (gère les outliers)
- Plus de mantissa → plus de précision relative (moins d'erreur)
FP8 E4M3 (4 exp, 3 mant) — le format forward#
FP8 E5M2 (5 exp, 2 mant) — le format backward#
FP4 E2M1 (2 exp, 1 mant) — le format ultra-low-bit#
Comparaison visuelle des plages de valeurs#
Précision fine au centre
Sparse aux extrêmes"] end subgraph E5M2["FP8 E5M2 (120 valeurs)"] E2["Plage : -57344 à +57344
Très étalé, moins de niveaux
Très large amplitude"] end subgraph E2M1["FP4 E2M1 (6-8 valeurs)"] E3["Valeurs : -3, -2, -1.5, -1, -0.5, 0, 0.5, 1, 1.5, 2, 3
Trop peu → nécessite un SCALE partagé"] end subgraph INT8["INT8 (256 valeurs, uniformes)"] I1["Plage : -128 à +127
Espacement CONSTANT
Gaspille la résolution
Ne peut pas représenter les outliers"] end
Précision relative : FP vs INT#
La précision relative (erreur maximale relative) est ce qui compte pour les LLMs — pas l'erreur absolue.
| Format | Bits | Erreur rel. max | Notes |
|---|---|---|---|
| FP32 | 32 | ~0.00001% | Référence |
| FP16 | 16 | ~0.05% | Standard |
| BF16 | 16 | ~0.8% | Plus large dynamique |
| INT8 | 8 | ~0.2%* | *constant |
| FP8 E4M3 | 8 | ~6.25% | Près de zéro : mieux |
| FP8 E5M2 | 8 | ~25% | Très large dynamique |
| INT4 | 4 | ~3%* | *constant |
| FP4 E2M1 | 4 | ~25% | Mais meilleure dynamique |
※ L'erreur relative de INT est CONSTANTE quelle que soit la valeur. L'erreur relative de FP est CONSTANTE en % (proportionnelle à la magnitude).
→ Pour les poids près de 0 (fréquents) : FP est meilleur. Pour les outliers (rares) : FP est nettement meilleur.
FP8 est ordres de grandeur plus précis pour les petites valeurs, qui constituent la majorité des poids d'un LLM.
Formats Microscaling (MX) — le standard OCP#
Le problème du FP4 seul#
Le FP4 E2M1 n'a que 6 à 8 valeurs. Ce n'est pas assez pour représenter la diversité des poids d'un LLM sans scale adapté. La solution : Microscaling.
Principe du Microscaling#
Variantes de formats MX#
| Format | Scale | Values | Block size | Bits/value |
|---|---|---|---|---|
| MXFP8 | E8M0 | E4M3 | 32 | 8.25 |
| MXFP6 | E8M0 | E2M3 | 32 | 6.25 |
| MXFP6 alt | E8M0 | E3M2 | 32 | 6.25 |
| MXFP4 | E8M0 | E2M1 | 32 | 4.25 |
| MXINT8 | E8M0 | INT8 | 32 | 8.25 |
| MXINT4 | E8M0 | INT4 | 32 | 4.25 |
Le scale partagé (E8M0 = exponent seule, 8 bits) agit comme un « zoom » global pour le bloc de 32 valeurs, permettant une dynamique de 2^256 entre blocs différents.
Pourquoi MX est important#
→ perte totale ❌"] end subgraph MXFP4["✅ MXFP4 (scale partagé)"] M1["scale = 2^(-10) = 0.0009765625"] M2["Normalisés : [1.024, 2.048, 1.536, ...]"] M3["Quantifiés FP4 : [1.0, 2.0, 1.5, ...] ✅"] M4["Décodés : [0.00098, 0.00195, ...] ✅"] end
Le scale partagé adapte dynamiquement la grille FP4 à la magnitude locale des poids → précision préservée
Support hardware FP4 / FP8#
| Plateforme | FP8 | FP4 | MX | Disponibilité |
|---|---|---|---|---|
| NVIDIA Hopper | ✅ | ❌ | ❌ | Disponible |
| NVIDIA Blackwell | ✅ ✅ | ✅ ✅ | ✅ | 2024+ (B200) |
| AMD MI300x | ✅ | ❌ | ❌ | Disponible |
| AMD MI350 | ✅ | ❌ | ✅ | 2025+ |
| Intel Gaudi 3 | ✅ | ❌ | ❌ | Disponible |
| Google TPU v5p | ✅ | ❌ | ❌ | Cloud only |
NVIDIA Blackwell B200 : FP4 Tensor Cores avec throughput de ~9 PFLOPS (dense) / ~18 PFLOPS (sparse) — le hardware le plus puissant pour la quantification FP4 à ce jour.
FP8 Training — entraîner directement en FP8#
Le FP8 n'est pas seulement pour l'inférence — il permet aussi d'entraîner des modèles plus rapidement.
Configuration FP8 training#
(master FP32)"] -->|"E4M3"| FWD["Forward
(FP8 TC)"] FWD -->|"E4M3"| ACT["Activations
(FP8)"] ACT -->|"E5M2"| FWD FWD -->|"update"| W
| Phase | Poids | Activations | Gradients | Master weights | Optimizer |
|---|---|---|---|---|---|
| Forward | FP8 E4M3 | FP8 E4M3 | FP8 E5M2 | FP32 | FP32 |
| Backward | — | — | FP8 E5M2 | FP32 | FP32 |
Avantages : 2× throughput vs BF16 · 2× réduction mémoire poids · Batch size plus grand · Pas de perte d'accuracy si bien calibré
Comparaison FP vs INT : quand choisir quoi#
| Critère | FP8/FP4 | INT8/INT4 |
|---|---|---|
| Outliers | ✅ Excellente gestion | ⚠️ Clipping nécessaire |
| Précision près de zéro | ✅ Très bonne | ⚠️ Médiocre |
| Simplicité | ⚠️ Plus complexe | ✅ Simple |
| Hardware support | Hopper+ (FP8), Blackwell (FP4) | Volta+ (INT8), large |
| Écosystème | En développement | Mature |
| Training | ✅ FP8 training natif | ⚠️ QAT nécessaire |
| Standardisation | OCP MX (en cours) | Très standardisé |
| Edge computing | ⚠️ Limité | ✅ Très répandu |
Exemple pratique#
FP8 inference avec NVIDIA Transformer Engine#
pip install transformer_engine torch
import torch
import transformer_engine.pytorch as te
from transformer_engine.common.recipe import Format, DelayedScaling
# Définir la recette FP8
fp8_recipe = DelayedScaling(
fp8_format=Format.HYBRID, # E4M3 forward, E5M2 backward
amax_history_len=16,
amax_compute_algo="max",
)
# Remplacer nn.Linear par te.Linear (FP8 natif)
model = te.TransformerLayer(
hidden_size=4096,
ffn_hidden_size=11008,
num_attention_heads=32,
layernorm_eps=1e-5,
)
model = model.cuda()
# Forward pass avec FP8
input_ids = torch.randint(0, 32000, (4, 512, 4096)).cuda()
with te.fp8_autocast(enabled=True, fp8_recipe=fp8_recipe):
output = model(input_ids)
# Le Transformer Engine gère automatiquement :
# - La sélection E4M3/E5M2
# - Le scaling par tensor
# - L'amax tracking
print(f"Output shape: {output.shape}")
FP8 serving avec vLLM (modèles Neural Magic)#
# Utiliser un modèle pré-quantifié FP8
python -m vllm.entrypoints.openai.api_server \
--model neuralmagic/Meta-Llama-3.1-8B-Instruct-FP8 \
--quantization fp8 \
--port 8000
# Tester
curl http://localhost:8000/v1/completions \
-H "Content-Type: application/json" \
-d '{
"model": "neuralmagic/Meta-Llama-3.1-8B-Instruct-FP8",
"prompt": "Explique le FP8 :",
"max_tokens": 200
}'
Quantification FP8 statique avec TensorRT Model Optimizer#
pip install --upgrade tensorrt-model-optimizer
# Quantification FP8 avec calibration
python -m tensorrt_model_optimizer.quantize \
--model meta-llama/Meta-Llama-3-8B \
--format fp8 \
--calib-size 512 \
--calib-dataset c4 \
--output ./llama3-8b-fp8
# Résultat :
# - Taille : 16 GB → 8 GB (−50%)
# - Throughput H100 : ~1.7× vs FP16
# - PPL WikiText2 : ~6.14 (vs 6.13 FP16) → quasi-lossless
MXFP4 expérimental (Blackwell)#
# NVIDIA Blackwell B200 + PyTorch 2.5+
# Le MXFP4 est supporté via le Transformer Engine v2+
import transformer_engine.pytorch as te
# Configuration MXFP4
model = te.TransformerLayer(
hidden_size=8192,
ffn_hidden_size=28672,
num_attention_heads=32,
)
# Quantification MXFP4 pour les poids
# Le scale E8M0 partagé est calculé par bloc de 32
# lors de la conversion du modèle
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
- OCP Microscaling Formats (MX) Specification — OCP Standard, OCP-MX-v1.1
- NVIDIA Blackwell Architecture — Blackwell Technical Brief
- NVIDIA Transformer Engine — github.com/NVIDIA/TransformerEngine
- Neural Magic (modèles FP8 pré-quantifiés) — huggingface.co/neuralmagic
- Voir aussi : INT8/FP8 Hardware · INT4/INT3/INT2 Extrême · bitsandbytes NF4 · Index quantification