Quantization : Réduire la taille des modèles IA sans perdre en qualité

tl;dr: La quantization réduit la précision numérique des modèles (FP32→INT8→INT4) pour diviser leur taille par 4-8x avec seulement 1-5% de perte de qualité. Techniques : GPTQ, AWQ, GGUF (llama.cpp), bitsandbytes. Essentielle pour IA locale sur GPU/RAM limités.

Le problème : Llama 3.1 70B pèse 140 GB en mémoire (format FP32). Impossible à charger sur un GPU consumer (RTX 4090 = 24 GB).

La solution : La quantization réduit ce modèle à 35 GB (format INT4) avec seulement 3-5% de perte de qualité.

La quantization est la technique clé qui a démocratisé l’IA locale. Elle permet d’exécuter des modèles puissants sur hardware accessible : MacBook, PC gaming, serveurs on-premise.

💡 Définition : La quantization (quantification en français) est le processus de réduction de la précision numérique des poids et activations d’un réseau de neurones, passant par exemple de 32 bits (FP32) à 8 bits (INT8) ou 4 bits (INT4).

Pourquoi c’est crucial

Avantages :

  1. Réduction de taille : 4-8x plus petit → charge sur GPU/RAM limités
  2. Vitesse accrue : Opérations INT8/INT4 plus rapides que FP32
  3. Coûts réduits : Moins de VRAM nécessaire = GPU moins cher
  4. Économie d’énergie : Moins de calculs = moins de consommation
  5. IA locale accessible : Modèles 70B sur MacBook M2, RTX 3060

Cas d’usage :

  • Exécution locale de Llama 70B sur GPU 24GB
  • Déploiement edge (smartphones, IoT)
  • Production cloud à coût optimisé
  • Inference temps réel avec vLLM

Analogie : Compresser une photo de 16 millions de couleurs (24-bit) en 256 couleurs (8-bit). L’image reste reconnaissable, mais le fichier pèse 3x moins.

Illustration détaillée de la quantification pour optimiser les modèles d’IA

Les formats de précision

FP32 (32-bit Float)

Format standard d’entraînement (rarement utilisé en inference).

Représentation :

  • 1 bit : Signe
  • 8 bits : Exposant
  • 23 bits : Mantisse

Plage : ±3.4 × 10³⁸ Précision : ~7 décimales

Taille modèle :

  • Llama 8B : 32 GB
  • Llama 70B : 280 GB
⚠️ Warning
FP32 en inference : Rarement justifié. Gaspillage de ressources. Utilisez FP16/BF16 minimum.

FP16 (16-bit Float)

Standard actuel pour l’entraînement et inference de qualité.

Représentation :

  • 1 bit : Signe
  • 5 bits : Exposant
  • 10 bits : Mantisse

Plage : ±65,504 Précision : ~3 décimales

Caractéristiques :

  • 2x plus rapide que FP32
  • 2x moins de mémoire
  • Perte de qualité négligeable (<0.5%)
  • ❌ Risque d’underflow (nombres très petits → 0)
import torch

# Charger modèle en FP16
model = AutoModelForCausalLM.from_pretrained(
    "meta-llama/Llama-3.1-8B",
    torch_dtype=torch.float16,  # ← FP16
    device_map="auto"
)

# Taille : ~16 GB au lieu de 32 GB

BF16 (BFloat16)

Alternative à FP16, privilégiée par Google/NVIDIA.

Représentation :

  • 1 bit : Signe
  • 8 bits : Exposant (même que FP32 !)
  • 7 bits : Mantisse (réduit vs FP16)

Avantages vs FP16 :

  • Même plage que FP32 → pas d’underflow
  • Stabilité entraînement supérieure
  • ✅ Support natif GPU modernes (A100, H100, RTX 40xx)

Inconvénient :

  • ❌ Précision légèrement inférieure à FP16 (mais rarement problématique)
# BF16 recommandé pour entraînement
model = AutoModelForCausalLM.from_pretrained(
    "mistralai/Mistral-7B-v0.1",
    torch_dtype=torch.bfloat16,  # ← BF16
    device_map="auto"
)

INT8 (8-bit Integer)

Premier niveau de vraie quantization.

Représentation :

  • Entiers signés : -128 à 127
  • Ou non-signés : 0 à 255

Caractéristiques :

  • 4x plus petit que FP32
  • 2x plus petit que FP16
  • Perte minimale : 1-2% sur benchmarks
  • Support hardware : Tensor Cores INT8 (NVIDIA)
  • Bon compromis qualité/taille
# Quantization INT8 avec bitsandbytes
from transformers import AutoModelForCausalLM, BitsAndBytesConfig

quantization_config = BitsAndBytesConfig(
    load_in_8bit=True,  # ← INT8
    llm_int8_threshold=6.0  # Seuil pour quantization mixte
)

model = AutoModelForCausalLM.from_pretrained(
    "meta-llama/Llama-3.1-8B",
    quantization_config=quantization_config,
    device_map="auto"
)

# Taille : ~8 GB au lieu de 16 GB (FP16)

INT4 (4-bit Integer)

Quantization agressive, très populaire pour IA locale.

Représentation :

  • Seulement 16 valeurs possibles (-8 à 7)

Caractéristiques :

  • 8x plus petit que FP32
  • 4x plus petit que FP16
  • Perte acceptable : 3-5% sur benchmarks
  • Permet modèles 70B sur GPU 24GB
  • ⚠️ Techniques avancées requises (GPTQ, AWQ, GGUF)
# Quantization INT4 avec bitsandbytes
quantization_config = BitsAndBytesConfig(
    load_in_4bit=True,  # ← INT4
    bnb_4bit_compute_dtype=torch.bfloat16,  # Compute en BF16
    bnb_4bit_use_double_quant=True,  # Double quantization
    bnb_4bit_quant_type="nf4"  # NormalFloat 4-bit
)

model = AutoModelForCausalLM.from_pretrained(
    "meta-llama/Llama-3.1-70B",
    quantization_config=quantization_config,
    device_map="auto"
)

# Taille : ~35 GB (chargeable sur GPU 48GB ou split GPU+CPU)

INT2 (2-bit) et au-delà

Recherche expérimentale (BitNet, 1.58-bit LLMs).

État actuel :

  • 📊 Papers : Résultats prometteurs en recherche
  • ⚠️ Production : Pas encore stable/fiable
  • 🔬 Futur : Potentiel de 16x compression

Défis :

  • Perte de qualité significative (>10%)
  • Nécessite re-entraînement ou distillation
  • Hardware spécialisé requis pour gains de vitesse

Impact sur les performances

Benchmarks qualité

Llama 3.1 8B sur MMLU (connaissance générale) :

FormatTailleScore MMLUPerte vs FP16Tokens/sec (RTX 4090)
FP3232 GB68.2%-0.1%45
FP1616 GB68.3%0% (baseline)78
INT88 GB67.8%-0.5%95
INT4 (GPTQ)4.5 GB66.9%-1.4%110
INT4 (AWQ)4.5 GB67.5%-0.8%108

Observations :

  • INT8 : Négligeable (-0.5%), excellent choix
  • INT4 : Acceptable (-1-2%), double vitesse vs FP16
  • ⚠️ Q2 : Perte >5%, non recommandé production

Mistral 7B sur HumanEval (code) :

FormatScore HumanEvalPerte vs FP16
FP1640.2%0%
INT839.8%-0.4%
INT4 GPTQ38.1%-2.1%
INT4 AWQ39.2%-1.0%

Conclusion : AWQ supérieur à GPTQ pour conservation de qualité.

Benchmarks vitesse

Latence génération (tokens/seconde) :

RTX 4090 24GB :

Llama 8B :
- FP16 : 78 t/s
- INT8 : 95 t/s (+22%)
- INT4 : 110 t/s (+41%)

Llama 70B :
- FP16 : Impossible (OOM)
- INT4 : 15 t/s

Apple M2 Max 96GB (unified memory) :

Llama 13B :
- FP16 : 28 t/s
- INT8 : 35 t/s
- INT4 : 45 t/s

Llama 70B :
- INT4 : 12 t/s

CPU Intel i9-13900K, 64GB RAM :

Llama 8B INT4 (GGUF) : 6-8 t/s (utilisable)
Llama 13B INT4 (GGUF) : 3-5 t/s
💡 Gain vitesse : INT8/INT4 non seulement économisent la mémoire, mais accélèrent l’inference grâce à moins d’opérations et meilleur cache utilization.

Techniques de quantization

Post-Training Quantization (PTQ)

Principe : Quantizer un modèle déjà entraîné sans réentraînement.

Avantages :

  • ✅ Rapide (minutes à heures)
  • ✅ Pas besoin de dataset d’entraînement complet
  • ✅ Accessible (pas de GPU cluster)

Limites :

  • ⚠️ Perte de qualité plus importante que QAT
  • ⚠️ Peut nécessiter calibration dataset

Méthodes PTQ populaires :

  • GPTQ : Optimal pour GPU inference
  • AWQ : Meilleure qualité que GPTQ
  • GGUF : Optimal CPU/Apple Silicon (llama.cpp)
  • bitsandbytes : Facile, intégré Hugging Face

Quantization-Aware Training (QAT)

Principe : Entraîner le modèle en simulant la quantization.

Processus :

  1. Entraînement en FP32/FP16
  2. Simuler quantization pendant forward pass
  3. Gradient descent ajuste pour compenser perte de précision
  4. Quantization finale sans perte

Avantages :

  • Qualité maximale : ~0.1% perte vs full precision
  • ✅ Permet quantization aggressive (INT4, INT2)

Inconvénients :

  • Coûteux : Réentraînement complet requis
  • Temps : Jours/semaines sur GPU cluster
  • Accès dataset : Nécessite données d’entraînement

Usage :

  • Labs de recherche avec ressources
  • Fine-tuning pour cas critiques
  • Optimisation edge devices (smartphones)

GPTQ (GPT Quantization)

Méthode PTQ optimale pour inference GPU.

Principe :

  1. Analyser importance de chaque poids
  2. Quantizer poids moins importants plus agressivement
  3. Préserver poids critiques en haute précision
  4. Optimiser reconstruction error par couche

Implémentation :

# Installation
pip install auto-gptq optimum

from transformers import AutoTokenizer
from auto_gptq import AutoGPTQForCausalLM, BaseQuantizeConfig

# Configuration quantization
quantize_config = BaseQuantizeConfig(
    bits=4,  # INT4
    group_size=128,  # Taille groupe quantization
    desc_act=False,  # Activation ordering
    damp_percent=0.01  # Damping factor
)

# Charger modèle FP16
model = AutoGPTQForCausalLM.from_pretrained(
    "meta-llama/Llama-3.1-8B",
    quantize_config=quantize_config
)

tokenizer = AutoTokenizer.from_pretrained("meta-llama/Llama-3.1-8B")

# Dataset de calibration (petit échantillon)
from datasets import load_dataset
calibration_dataset = load_dataset("c4", split="train", streaming=True)
calibration_samples = [next(iter(calibration_dataset))["text"] for _ in range(128)]

# Quantizer (prend 10-30 min sur GPU)
model.quantize(
    calibration_samples,
    tokenizer=tokenizer,
    batch_size=1
)

# Sauvegarder modèle quantizé
model.save_quantized("Llama-3.1-8B-GPTQ")

# Utilisation
from auto_gptq import AutoGPTQForCausalLM

model = AutoGPTQForCausalLM.from_quantized(
    "Llama-3.1-8B-GPTQ",
    device="cuda:0"
)

# Inference normale
output = model.generate(**inputs, max_new_tokens=100)

Modèles GPTQ pré-quantizés : TheBloke sur Hugging Face

# Utiliser modèle pré-quantizé
model = AutoGPTQForCausalLM.from_quantized(
    "TheBloke/Llama-2-13B-chat-GPTQ",
    device="cuda:0",
    use_safetensors=True
)

AWQ (Activation-aware Weight Quantization)

Amélioration de GPTQ qui analyse aussi les activations.

Principe :

  • Certains poids ont activations fortes → impact majeur
  • Préserver précision pour ces “salient weights”
  • Résultat : Meilleure qualité que GPTQ à même taille

Performance :

  • +0.5-1% sur benchmarks vs GPTQ
  • Légèrement plus lent à quantizer
  • Vitesse inference similaire

Implémentation :

# Installation
pip install autoawq

from awq import AutoAWQForCausalLM
from transformers import AutoTokenizer

# Charger modèle
model_path = "meta-llama/Llama-3.1-8B"
quant_path = "Llama-3.1-8B-AWQ"

model = AutoAWQForCausalLM.from_pretrained(model_path)
tokenizer = AutoTokenizer.from_pretrained(model_path)

# Configuration quantization
quant_config = {
    "zero_point": True,
    "q_group_size": 128,
    "w_bit": 4,
    "version": "GEMM"
}

# Quantizer
model.quantize(
    tokenizer,
    quant_config=quant_config,
    calib_data="pileval"  # Dataset calibration
)

# Sauvegarder
model.save_quantized(quant_path)
tokenizer.save_pretrained(quant_path)

# Charger et utiliser
model = AutoAWQForCausalLM.from_quantized(
    quant_path,
    fuse_layers=True  # Fusion kernel pour vitesse
)

GGUF/GGML (llama.cpp)

Format optimal pour CPU et Apple Silicon (Metal).

Caractéristiques :

  • Optimisé CPU : AVX2, ARM NEON
  • Apple Metal : GPU Apple Silicon natif
  • Quantization variée : Q2_K à Q8_0
  • Memory mapping : Charge seulement ce qui est nécessaire
  • Compatible Ollama : Format par défaut

Variantes GGUF :

VarianteBits/weightQualitéUse case
Q2_K~2.6⭐⭐RAM/VRAM extrême limite
Q3_K_M~3.5⭐⭐⭐Compromis léger
Q4_K_M~4.5⭐⭐⭐⭐Recommandé général
Q5_K_M~5.5⭐⭐⭐⭐Qualité élevée
Q6_K~6.5⭐⭐⭐⭐⭐Presque FP16
Q8_08.0⭐⭐⭐⭐⭐Maximum qualité

Utilisation avec llama.cpp :

# Installation
git clone https://github.com/ggerganov/llama.cpp
cd llama.cpp
make

# Télécharger modèle GGUF (ou convertir depuis Hugging Face)
wget https://huggingface.co/TheBloke/Llama-2-13B-chat-GGUF/resolve/main/llama-2-13b-chat.Q4_K_M.gguf

# Inference
./main -m llama-2-13b-chat.Q4_K_M.gguf \
  -p "Explain quantum computing simply" \
  -n 256 \
  -t 8  # Threads CPU

Avec Ollama (encore plus simple) :

# Ollama utilise GGUF en interne
ollama run llama3.1  # Télécharge automatiquement Q4_K_M

# Spécifier autre quantization
ollama pull llama3.1:8b-instruct-q8_0
ollama run llama3.1:8b-instruct-q8_0

bitsandbytes (Hugging Face)

Bibliothèque intégrée à Transformers pour quantization facile.

Features :

  • INT8 : LLM.int8() method (zero degradation)
  • INT4 : NF4 (NormalFloat 4-bit) optimal
  • Double quantization : Quantizer aussi metadata
  • Mixed precision : Layers critiques en FP16

Installation :

pip install bitsandbytes accelerate

Quantization INT8 :

from transformers import AutoModelForCausalLM, BitsAndBytesConfig

model = AutoModelForCausalLM.from_pretrained(
    "meta-llama/Llama-3.1-8B",
    load_in_8bit=True,  # ← Simple !
    device_map="auto"
)

# Inference normale
output = model.generate(**inputs)

Quantization INT4 optimisée :

bnb_config = BitsAndBytesConfig(
    load_in_4bit=True,
    bnb_4bit_quant_type="nf4",  # NormalFloat 4-bit (optimal)
    bnb_4bit_use_double_quant=True,  # Double quant metadata
    bnb_4bit_compute_dtype=torch.bfloat16  # Compute en BF16
)

model = AutoModelForCausalLM.from_pretrained(
    "meta-llama/Llama-3.1-70B",
    quantization_config=bnb_config,
    device_map="auto",  # Auto split GPU/CPU si nécessaire
    max_memory={0: "22GB", "cpu": "40GB"}  # Limites explicites
)

QLoRA (Quantized LoRA) : Fine-tuning avec modèle quantizé INT4.

from peft import LoraConfig, get_peft_model, prepare_model_for_kbit_training

# Préparer modèle quantizé pour training
model = prepare_model_for_kbit_training(model)

# Configuration LoRA
lora_config = LoraConfig(
    r=16,  # Rank
    lora_alpha=32,
    target_modules=["q_proj", "v_proj"],
    lora_dropout=0.05,
    bias="none",
    task_type="CAUSAL_LM"
)

model = get_peft_model(model, lora_config)

# Fine-tuner normalement (mais 4x moins VRAM)
trainer = Trainer(
    model=model,
    args=training_args,
    train_dataset=train_dataset
)
trainer.train()

Quantization mixte

Idée : Ne pas quantizer toutes les couches uniformément.

Préserver couches critiques

Certaines couches sont plus sensibles à la quantization :

  • Attention heads : Cruciales pour compréhension
  • Première/dernière couche : Input/output encoding
  • LayerNorms : Stabilité

Approche :

# Quantization mixte avec bitsandbytes
quantization_config = BitsAndBytesConfig(
    load_in_4bit=True,
    bnb_4bit_compute_dtype=torch.bfloat16,
    llm_int8_skip_modules=["lm_head", "embed_tokens"]  # Garder FP16
)

model = AutoModelForCausalLM.from_pretrained(
    "meta-llama/Llama-3.1-70B",
    quantization_config=quantization_config,
    device_map="auto"
)

Quantization progressive

Stratégie : Quantizer plus agressivement les couches moins critiques.

# Pseudo-code conceptuel
for layer_idx, layer in enumerate(model.layers):
    if layer_idx < 5 or layer_idx > len(model.layers) - 5:
        # Premières/dernières couches : INT8
        quantize_layer(layer, bits=8)
    else:
        # Couches intermédiaires : INT4
        quantize_layer(layer, bits=4)

Résultat : Économies mémoire importantes, dégradation minimale.


Cas d’usage par contrainte hardware

16 GB VRAM (RTX 4060 Ti, RTX 3060 12GB)

Modèles chargeables :

ModèleQuantizationVRAM utiliséePerformance
Llama 8BQ4~5 GBExcellent
Llama 13BQ4~8 GBTrès bon
Mistral 7BQ8~9 GBExcellent
CodeLlama 13BQ4~8 GBTrès bon
Mixtral 8x7BQ2~14 GBAcceptable

Recommandation : Llama 13B Q4 = meilleur compromis.

# Ollama
ollama pull llama3.1:13b-instruct-q4_K_M
ollama run llama3.1:13b

# Python
model = AutoModelForCausalLM.from_pretrained(
    "meta-llama/Llama-3.1-13B",
    load_in_4bit=True,
    device_map="auto"
)

24 GB VRAM (RTX 4090, RTX 3090)

Modèles chargeables :

ModèleQuantizationVRAMPerformance
Llama 70BQ4~22 GBTrès bon
Llama 34BQ8~20 GBExcellent
Mixtral 8x7BQ4~18 GBTrès bon
Qwen 72BQ4~23 GBTrès bon

Sweet spot : Llama 70B Q4 → Qualité proche GPT-3.5 en local.

# Llama 70B sur RTX 4090
model = AutoModelForCausalLM.from_pretrained(
    "meta-llama/Llama-3.1-70B",
    load_in_4bit=True,
    device_map="auto"
)
# Génération : ~15 tokens/sec

32-64 GB RAM CPU (sans GPU)

Modèles chargeables (GGUF) :

ModèleQuantizationRAMVitesse (CPU i9)
Llama 8BQ46 GB~8 t/s
Llama 13BQ510 GB~5 t/s
Llama 13BQ48 GB~6 t/s
Mistral 7BQ89 GB~7 t/s

Recommandation : Llama 8B Q4 = utilisable, latence acceptable.

# llama.cpp
./main -m llama-3.1-8b.Q4_K_M.gguf \
  -t 16 \  # 16 threads CPU
  -n 256 \
  -p "Your prompt"

# Ollama (plus simple)
OLLAMA_NUM_GPU=0 ollama run llama3.1
# Force CPU, fonctionne bien

Apple Silicon (Unified Memory)

Avantage majeur : Unified memory = pas de limite VRAM/RAM séparée.

M1 Max 64GB :

  • Llama 70B Q4 : ~20 t/s (Metal GPU)
  • Llama 34B Q8 : ~25 t/s

M2 Ultra 192GB :

  • Llama 70B FP16 : ~40 t/s (!)
  • Llama 405B Q4 : ~8 t/s

M3 Max 128GB :

  • Llama 70B Q5 : ~25 t/s
  • Mixtral 8x7B Q8 : ~30 t/s
# Ollama détecte Metal automatiquement
ollama run llama3.1:70b

# Performances excellentes !

Tableau de correspondance complet

VRAM/RAMModèle optimalQuantizationVitesseQualité
4 GBPhi-3 MiniQ4RapideBon
8 GBLlama 8BQ4RapideTrès bon
12 GBLlama 13BQ4BonTrès bon
16 GBLlama 13BQ8BonExcellent
24 GBLlama 70BQ4MoyenExcellent
40 GBLlama 70BQ8BonExcellent
48 GBLlama 70BFP16RapideParfait
80 GBLlama 405BQ4LentExcellent

Limites et précautions

Tâches sensibles

Ne pas quantizer agressivement pour :

  • Mathématiques complexes : Précision numérique critique
  • Code safety-critical : Médical, aéronautique
  • Finance : Calculs précis requis
  • Recherche : Reproductibilité extrême

Recommandation : FP16 ou INT8 maximum pour ces cas.

Mathématiques et INT4

# Test calcul mathématique
prompts = [
    "Calculate: 45327 * 8912 = ?",
    "What is the square root of 15241578750190521?",
    "Solve: 2x^2 + 5x - 3 = 0"
]

# FP16 : Souvent correct
# INT4 : Erreurs fréquentes sur arithmétique précise

Solution : Tool calling vers calculatrice pour opérations complexes.

Tests nécessaires

Ne jamais déployer sans tester :

  1. Benchmarks standardisés (MMLU, HumanEval, etc.)
  2. Tests sur votre use case spécifique
  3. A/B test FP16 vs quantizé
  4. Monitoring qualité en production
# Exemple suite de tests
def evaluate_quantized_model(model_fp16, model_int4, test_dataset):
    results = {"fp16": [], "int4": []}

    for sample in test_dataset:
        # FP16
        output_fp16 = generate(model_fp16, sample["prompt"])
        score_fp16 = evaluate_output(output_fp16, sample["expected"])
        results["fp16"].append(score_fp16)

        # INT4
        output_int4 = generate(model_int4, sample["prompt"])
        score_int4 = evaluate_output(output_int4, sample["expected"])
        results["int4"].append(score_int4)

    print(f"FP16 average: {np.mean(results['fp16']):.2%}")
    print(f"INT4 average: {np.mean(results['int4']):.2%}")
    print(f"Degradation: {np.mean(results['fp16']) - np.mean(results['int4']):.2%}")

    return results

L’avenir de la quantization

1-bit LLMs (BitNet)

Recherche Microsoft : Modèles avec poids binaires (-1, 0, 1).

Avantages théoriques :

  • 32x compression vs FP32
  • Opérations ultra-rapides (pas de multiplication)
  • Consommation énergétique drastiquement réduite

État actuel :

  • 📄 Papers prometteurs (BitNet b1.58)
  • 🔬 Pas encore production-ready
  • 🚀 Futur probable : 2-3 ans

Quantization dynamique adaptative

Idée : Ajuster quantization en temps réel selon contexte.

  • Tâche simple → Quant agressive
  • Tâche complexe → Haute précision

Recherche en cours : Dynamic Neural Networks.

Hardware spécialisé

Tensor Cores INT4 (NVIDIA H100) :

  • Accélération native INT4
  • 2x vitesse vs INT8

Apple Neural Engine :

  • Optimisé INT8/INT4
  • On-device ML ultra-efficient

Google TPU v5 :

  • INT8 natif, FP16 optionnel
  • Inference à coût minimal

Exercices pratiques

Comparer quantizations

Objectif : Mesurer impact qualité selon quantization.

from transformers import AutoModelForCausalLM, AutoTokenizer
from datasets import load_dataset
import torch

def benchmark_quantization():
    model_name = "meta-llama/Llama-3.1-8B"
    tokenizer = AutoTokenizer.from_pretrained(model_name)

    # Charger modèles
    models = {
        "fp16": AutoModelForCausalLM.from_pretrained(model_name, torch_dtype=torch.float16),
        "int8": AutoModelForCausalLM.from_pretrained(model_name, load_in_8bit=True),
        "int4": AutoModelForCausalLM.from_pretrained(model_name, load_in_4bit=True)
    }

    # Dataset de test
    test_data = load_dataset("gsm8k", split="test[:100]")  # Maths

    # Évaluer chaque modèle
    results = {}
    for quant_type, model in models.items():
        correct = 0
        for sample in test_data:
            output = generate_answer(model, tokenizer, sample["question"])
            if check_answer(output, sample["answer"]):
                correct += 1
        results[quant_type] = correct / len(test_data)
        print(f"{quant_type}: {results[quant_type]:.2%}")

    return results

Quantizer un modèle custom

Objectif : Appliquer GPTQ à un modèle fine-tuné.

Étapes :

  1. Fine-tuner Llama 8B sur dataset custom
  2. Quantizer en INT4 avec GPTQ
  3. Comparer perplexity avant/après
  4. Tester sur cas d’usage réel

Optimiser pour hardware spécifique

Objectif : Trouver meilleur compromis pour votre GPU.

Tâche : Avec un RTX 4090 24GB, déterminer :

  • Quel modèle (13B, 34B, 70B) ?
  • Quelle quantization (Q4, Q5, Q8) ?
  • Maximiser qualité tout en maintenant >10 tokens/sec

Conclusion

La quantization est la technologie qui a rendu l’IA locale accessible. Elle permet d’exécuter des modèles 70B sur un GPU gaming, avec seulement 3-5% de perte de qualité.

Points clés :

  1. Formats : FP16 (baseline), INT8 (1-2% perte), INT4 (3-5% perte)
  2. Techniques : GPTQ (GPU), AWQ (meilleure qualité), GGUF (CPU/Apple), bitsandbytes (facile)
  3. Compromis : Q4_K_M optimal (4x compression, 95%+ qualité)
  4. Hardware : INT4 débloque Llama 70B sur GPU 24GB
  5. Futur : 1-bit LLMs, quantization adaptative, hardware spécialisé

Recommandations par usage :

  • Développement : INT4 (Q4_K_M), balance vitesse/qualité
  • Production critique : INT8 ou FP16, sécurité maximale
  • IA locale : GGUF Q4_K_M via Ollama, simplicité
  • Edge devices : Q2-Q3, compromis extrême
  • Recherche : FP16, reproductibilité

La quantization n’est pas juste une optimisation : c’est un enabler technologique qui démocratise l’accès aux modèles de pointe. Avec les bonnes techniques, vous pouvez exécuter localement des modèles rivalisant avec GPT-3.5, en toute confidentialité et sans coûts API.


Ressources

Articles liés :

Outils :

Modèles quantizés :

Papers :

  • LLM.int8() - Dettmers et al. (2022)
  • GPTQ - Frantar et al. (2022)
  • AWQ - Lin et al. (2023)
  • QLoRA - Dettmers et al. (2023)
  • BitNet b1.58 - Microsoft (2024)