W4A8 / W8A8 — Quantification en précision mixte#
TL;DR — La notation WxAy décrit une quantification en précision mixte où les poids (Weights) sont codés sur x bits et les activations sur y bits. Les poids étant statiques et réguliers, on peut les compresser agressivement (4-bit). Les activations, sujettes à des outliers dynamiques, nécessitent plus de précision (8 ou 16-bit). W8A8 est la configuration la plus robuste (support natif Tensor Cores INT8/FP8). W4A8 est plus agressive et optimale pour le cloud serving à grand batch.
Le concept : pourquoi quantifier différemment poids et activations ?#
Dans un Transformer, une couche linéaire calcule Y = X × W où :
- W (poids) — fixe après entraînement, distributions lisses et régulières
- X (activations) — changent à chaque token, contiennent des outliers (valeurs extrêmes)
L'analogie pour néophyte#
Imagine un restaurant. Les poids sont le livre de recettes : il ne change jamais, tu peux le photocopier en version condensée (4 mots-clés par recette). Les activations, ce sont les ingrédients qui arrivent en temps réel — chaque plat est différent, parfois un ingrédient sort du lot (une dose 20× trop forte). Tu ne peux pas condenser les ingrédients autant que les recettes, sinon tu ruines le plat. Donc : recettes en 4-bit, ingrédients en 8-bit.
Les trois configurations principales#
| Schéma | Poids | Activ. | Cas d'usage optimal |
|---|---|---|---|
| W4A16 | INT4 | FP16 | Edge / single-user : préserve la qualité, réduit la mémoire poids → GPTQ, AWQ, GGUF |
| W4A8 | INT4 | INT8 | Cloud serving (large batch) : compression poids + accél. compute via INT8 Tensor Cores → QoQ/QServe, OmniQuant, QQQ |
| W8A8 | INT8 | INT8 | Production robuste : perte d'accuracy minimale, support hardware natif maximal → SmoothQuant, LLM.int8() |
| W4A4 | INT4 | INT4 | Régime extrême (QAT souvent nécessaire) → LLM-QAT |
| W6A6 | INT6 | INT6 | Compromis doux (peu commun) |
W8A8 : la configuration de référence#
Principe#
Poids et activations tous deux en 8-bit. C'est le standard de l'industrie pour la quantification production-ready.
Migration des outliers :
X' = X · diag(1/s)
W' = diag(s) · W
→ Activations « lissées »"] SQ --> Q["**Quantification INT8**
W → INT8 (per-channel)
X → INT8 (per-token)"] Q --> GEMM["**GEMM INT8 × INT8**
Tensor Cores INT8 natifs
Débit 2× supérieur au FP16 sur Ampere/Hopper"]
Pourquoi W8A8 est le plus stable#
- Pas de déquantification coûteuse : tout le pipeline reste en INT8
- Support hardware natif : Tensor Cores INT8 depuis NVIDIA Volta (V100)
- Outliers gérables : SmoothQuant + INT8 suffit à contenir les valeurs extrêmes
- Perte d'accuracy < 1% sur la plupart des benchmarks
Outils principaux pour W8A8#
| Outil | Mécanisme | Notes |
|---|---|---|
| SmoothQuant | Migration outliers activation → poids | PTQ pur, α ≈ 0.5, ICML 2023 |
| LLM.int8() | Décomposition mixed-precision pour outliers | Zéro dégradation, léger overhead |
| TensorRT-LLM | Quantification INT8/FP8 native NVIDIA | Standard de production |
| FP8 (Hopper) | W8A8 en floating-point (E4M3) | Meilleure dynamique que INT8 |
W4A8 : le meilleur des deux mondes pour le cloud serving#
Principe#
Poids en INT4 (compression agressive), activations en INT8 (stabilité + accélération compute). C'est la configuration qui a émergé comme optimale pour le large-batch cloud serving.
Lisser les activations
Migration outliers → poids"] S1 --> S2["**Étape 2 : Quantification différenciée**
W → INT4 (group quant, g=128)
X → INT8 (per-token)"] S2 --> S3["**Étape 3 : GEMM en précision mixte**"] S3 --> DQ["W_int4 → [déquant 4→8 bit] → W_int8"] DQ --> GEMM["GEMM INT8×INT8 (Tensor Cores)"] S3 --> X8["X_int8"] X8 --> GEMM
W4A8 vs W4A16 : quand utiliser quoi ?#
| Aspect | W4A16 (poids INT4 + act FP16) | W4A8 (poids INT4 + act INT8) |
|---|---|---|
| Bottleneck | Mémoire poids (weight loading) | Compute + mémoire poids |
| Compute | FP16 × déquant (pas accéléré) | INT8 GEMM (Tensor Cores, 2× plus rapide) |
| Qualité | Maximale pour l'INT4 | Légèrement inférieure (act quantifiées) |
| Optimal pour | Edge, single-user, CPU inference | Cloud serving, large batch, datacenter |
| Outils | GPTQ, AWQ, GGUF, HQQ | QServe/QoQ, QQQ, OmniQuant |
La nuance critique : la déquantification progressive#
Le défi du W4A8 est le GEMM : comment multiplier du INT4 par du INT8 ? Il faut déquantifier les poids. Deux approches :
⚠️ Pas d'accélération hardware
⚠️ Overhead de déquant lourd"] XFN --> GN end subgraph OPT["✅ Approche W4A8 optimisée (rapide)"] direction TB W4O["W_int4"] --> DQO["[déquant INT4 → INT8]"] --> W8O["W_int8"] X8O["X_int8"] W8O --> GO["GEMM INT8 × INT8
✅ Tensor Cores INT8 (2× FP16)
✅ Déquant peu coûteuse"] X8O --> GO end
C'est exactement l'innovation du progressive quantization dans QoQ/QServe.
Diagramme unifié : W8A8 vs W4A8 vs W4A16#
GEMM INT8×INT8 Tensor Cores
Accuracy: ★★★★ · Mémoire: ★★ · Vitesse: ★★★★
(large batch)"] end subgraph W4A8_box["W4A8"] W4A8D["W: INT4 · A: INT8
Déquant 4→8 · GEMM INT8×INT8 Tensor Cores
Accuracy: ★★★ · Mémoire: ★★★★ · Vitesse: ★★★★★
(large batch)"] end subgraph W4A16_box["W4A16"] W4A16D["W: INT4 · A: FP16
Déquant 4→16 · GEMM FP16
Accuracy: ★★★★ · Mémoire: ★★★★ · Vitesse: ★★★
(single user)"] end
Le rôle de SmoothQuant dans W8A8 et W4A8#
SmoothQuant est le prérequis pour toute quantification W8A8 ou W4A8 réussie. Sans lui, les outliers d'activation rendent l'INT8 catastrophique.
Outlier (20×)
INT8 = saturé ou clip
→ erreurs massives"] SA2["Poids inchangés
→ INT8 propre"] end subgraph AVEC["Avec SmoothQuant"] direction TB AV1["Activations lissées :
Toutes les valeurs
dans une plage gérable
→ INT8 propre"] AV2["Poids légèrement modifiés
(multipliés par s)
→ INT8/INT4 propre"] end
La transformation est mathématiquement équivalente (même sortie) :
Y = X · W (original)
Y = (X · diag(1/s)) · (diag(s) · W) (équivalent, mais X lissé)
Y = X' · W' (W' = poids modifiés)
Méthodes et outils de quantification W4A8 / W8A8#
Vue d'ensemble#
| Méthode | Schéma | Type | Outlier Handling | Source |
|---|---|---|---|---|
| SmoothQuant | W8A8 | PTQ | Migration α=0.5 | arXiv:2211.10438 |
| LLM.int8() | W8A8 (mixed) | PTQ | Décomposition FP16 pour outliers | arXiv:2208.07339 |
| QoQ / QServe | W4A8KV4 | PTQ+ | SmoothQuant + SmoothAttention | arXiv:2405.04532 |
| QQQ | W4A8 | PTQ | INT4 poids + INT8 act optimisés | arXiv:2406.09904 |
| OmniQuant | W4A8, W8A8, W6A6, W4A4 | PTQ+ | Learnable clipping + transform | arXiv:2308.13137 |
| TensorRT-LLM | W8A8, FP8 | PTQ | Native NVIDIA INT8/FP8 | — |
Le combo SmoothQuant + GPTQ (W4A8 pratique)#
Une approche pratique de W4A8 combine SmoothQuant (pour les activations INT8) avec GPTQ (pour les poids INT4) :
→ Activations lissées, quantifiables en INT8
→ Poids légèrement modifiés"] S1 --> S2["**2. GPTQ sur les poids lissés**
→ Poids compressés en INT4 (group_size=128)"] S2 --> S3["**3. Inférence**
→ Déquant INT4 → INT8 à la volée
→ GEMM INT8 × INT8 sur Tensor Cores"]
Exemple pratique#
W8A8 avec TensorRT-LLM#
# 1. Installer TensorRT-LLM
pip install tensorrt-llm
# 2. Quantification W8A8 (SmoothQuant + INT8)
python tensorrt_llm/examples/llama/quantize.py \
--model_dir ./llama-3-8b \
--dtype float16 \
--qformat int8_smoothquant \ # W8A8 avec SmoothQuant
--calib_size 512 \ # 512 échantillons de calibration
--output_dir ./llama-3-8b-w8a8
# 3. Build du moteur TensorRT
trtllm-build \
--checkpoint_dir ./llama-3-8b-w8a8 \
--output_dir ./trt-engine-w8a8 \
--gemm_plugin int8 # Utiliser les Tensor Cores INT8
# 4. Inférence
python -m tensorrt_llm.run \
--engine_dir ./trt-engine-w8a8 \
--tokenizer_dir ./llama-3-8b
W4A8 avec QServe/QoQ#
# Cloner QServe
git clone https://github.com/mit-han-lab/omniserve.git
cd omniserve
pip install -e .
# Serving W4A8KV4
python -m qserve.entrypoints.openai.api_server \
--model meta-llama/Meta-Llama-3-8B \
--quantization qoq \
--w-bits 4 \
--a-bits 8 \
--kv-bits 4 \
--port 8000
W8A8 avec SmoothQuant (standalone)#
from smoothquant import SmoothQuant, Calibration
# 1. Calibration
calib = Calibration(model, dataset="redpajama", n_samples=512)
activation_stats = calib.collect_stats()
# 2. Migration des outliers
sq = SmoothQuant(alpha=0.5) # α contrôle la migration
model_smoothed = sq.migrate(model, activation_stats)
# 3. Quantification INT8 (W8A8)
model_int8 = quantize_int8(model_smoothed)
# → GEMM INT8 × INT8 sur Tensor Cores
Tableau de décision#
| Ton scénario | Schéma recommandé | Outil |
|---|---|---|
| Edge / mobile / single-user | W4A16 | GPTQ, AWQ, GGUF |
| Cloud serving petit batch (< 8) | W4A16 + Marlin | GPTQ-Marlin (vLLM) |
| Cloud serving large batch (32+) | W4A8 | QServe/QoQ |
| Production robuste, accuracy max | W8A8 | TensorRT-LLM, SmoothQuant |
| Hardware Hopper+ disponible | FP8 (W8A8) | vLLM FP8, TensorRT FP8 |
| Fine-tuning basse précision | W4A4 | LLM-QAT |
Avantages et inconvénients#
| ✅ Avantages | ❌ Inconvénients |
|---|---|
| Flexibilité : choisir le meilleur compromis accuracy/perf | Complexité accrue (gérer multiples précisions) |
| W4A8 optimal pour cloud serving (compute + mémoire) | Nécessite des kernels spécialisés (Marlin, QServe) |
| W8A8 : support hardware natif maximal | Pas toujours supporté par tous les frameworks |
| W4A16 : qualité maximale pour l'edge | W4A16 : pas d'accélération du compute |
| SmoothQuant rend W8A8/W4A8 viables | SmoothQuant requiert calibration + tuning de α |
| FP8 : meilleur que INT8 sur Hopper+ | FP8 : hardware récent uniquement |
Références#
- SmoothQuant — Xiao et al., "SmoothQuant: Accurate and Efficient Post-Training Quantization for Large Language Models", ICML 2023 — arXiv:2211.10438
- LLM.int8() — Dettmers et al., "LLM.int8(): 8-bit Matrix Multiplication for Transformers at Scale", NeurIPS 2022 — arXiv:2208.07339
- QoQ / QServe — Lin et al., "QServe: W4A8KV4 Quantization and System Co-design for Efficient LLM Serving", 2024 — arXiv:2405.04532
- QQQ — "QQQ: Quality Quattuor-Bit Quantization for Large Language Models", 2024 — arXiv:2406.09904
- OmniQuant — Shao et al., "OmniQuant: Omnidirectionally Calibrated Quantization for Large Language Models", 2023 — arXiv:2308.13137
- FP8 Formats — Micikevicius et al., "FP8 Formats for Deep Learning", 2022 — arXiv:2209.05433
- Voir aussi : SmoothQuant · QoQ / QServe · GPTQ · LLM.int8() · Marlin · Index quantification