AQLM (Additive Quantization for LLMs)#
TL;DR — AQLM adapte l'additive quantization (issue de l'information retrieval) à la compression de LLMs. Au lieu de quantifier chaque poids indépendamment, AQLM approxime chaque vecteur de poids par une somme de vecteurs sélectionnés dans plusieurs codebooks appris. Cette approche par vector quantization exploite les corrélations entre poids et atteint une qualité Pareto-optimale en régime sub-3-bit, surpassant GPTQ et AWQ à 2 bits.
Le problème fondamental (expliqué pour un néophyte)#
Les méthodes de quantification classiques (GPTQ, AWQ) traitent chaque poids individuellement : on prend un nombre FP16 et on le remplace par son plus proche niveau dans une grille fixe. À 2 bits, on n'a que 4 niveaux — c'est trop peu pour représenter la diversité des poids d'un grand modèle.
L'idée d'AQLM : au lieu de quantifier chaque poids séparément, on groupe les poids par petits vecteurs et on approxime chaque vecteur comme une combinaison additive de motifs appris (les codebooks).
Quantification classique (scalaire) : Chaque poids individuellement → w = 0.037 → q = 0, w = 0.142 → q = 1, etc. ❌ 4 niveaux seulement en 2-bit → beaucoup d'erreur.
Additive Quantization (AQLM) : Un VECTEUR de 8 poids à la fois :
8 poids FP16"] --> APPROX CB1["codebook₁[42]
vecteur dim 8"] --> APPROX CB2["codebook₂[17]
vecteur dim 8"] --> APPROX CB3["codebook₃[5]
vecteur dim 8"] --> APPROX APPROX["≈ Somme additive
3 indices seulement"] --> OUT["✅ 65 536 combinaisons possibles
en 2-bit/poids"]
C'est comme la différence entre peindre pixel par pixel (quantification scalaire) et utiliser une palette de motifs pré-calculés qu'on superpose (additive quantization).
Papier source#
| Élément | Détail |
|---|---|
| Titre | Extreme Compression of Large Language Models via Additive Quantization |
| Auteurs | Vage Egiazarian, Andrei Panferov, Denis Kuznedelev, Elias Frantar, Artem Babenko, Dan Alistarh (IST Austria / Yandex Research) |
| Date | Janvier 2024 |
| Publication | ICML 2024 |
| arXiv | 2401.06118 |
| Code | github.com/Vahe1994/AQLM |
Mécanisme#
Niveau néophyte#
Imagine que tu veux compresser une longue liste de nombres. Au lieu de stocker chaque nombre individuellement (avec ses décimales), tu crées plusieurs petits « dictionnaires » de motifs typiques. Pour reconstituer un groupe de nombres, tu additionnes un motif de chaque dictionnaire. C'est comme décomposer une couleur complexe en mélangeant quelques couleurs de base (RGB) — sauf qu'ici on a plusieurs couches de « couleurs de base » (les codebooks) et on les additionne.
Niveau intermédiaire#
AQLM utilise la vector quantization additive. Pour chaque ligne de la matrice de poids, on approxime le vecteur original par :
w ≈ codebook₁[i₁] + codebook₂[i₂] + ... + codebook_K[iK]
Chaque codebook est une petite matrice de taille n_groups × group_size contenant des vecteurs de référence. Le nombre de codebooks K et leur taille n_groups contrôlent le bitrate effectif :
Bitrate par poids = K × log₂(n_groups) / group_size
Exemple : K=2 codebooks, n_groups=65536 (16-bit index), group_size=8
→ bitrate = 2 × 16 / 8 = 4 bits par poids
Exemple extrême : K=2, n_groups=256 (8-bit), group_size=8
→ bitrate = 2 × 8 / 8 = 2 bits par poids
Les codebooks sont appris pendant la quantification : un algorithme d'optimisation ajuste conjointement les vecteurs de codebook et les indices pour minimiser l'erreur d'approximation, en utilisant les données de calibration.
Niveau tech avancé#
AQLM formule la compression comme un problème d'optimisation conjointe :
Minimiser : Σ_layers || W - Σ_{k=1}^{K} C_k[i_k] ||²_H
où :
- W = matrice de poids originale (par couche)
- C_k = k-ème codebook (matrice de vecteurs)
- i_k = indice sélectionné dans le codebook k
- ||·||²_H = norme pondérée par la Hessienne H = 2XᵀX
(information de second ordre des activations de calibration)
Trois caractéristiques distinguent AQLM :
-
Joint optimization across blocks : contrairement à GPTQ qui traite chaque couche indépendamment, AQLM optimise les codebooks conjointement à travers plusieurs blocs du transformer, capturant les dépendances inter-couches.
-
Beam search pour l'index assignment : l'attribution des indices de codebook n'est pas greedy — AQLM utilise une beam search pour explorer l'espace des combinaisons d'indices et trouver la meilleure approximation additive.
-
Input-adaptive codebooks : les codebooks sont optimisés en utilisant la Hessienne des activations réelles (pas seulement la magnitude des poids), ce qui rend la compression sensible au comportement fonctionnel du modèle.
Le coût : l'apprentissage des codebooks est itératif et coûteux — compter des heures à des dizaines d'heures pour un modèle de 7B-70B.
Illustration : AQLM vs quantification classique#
[0.037, 0.142, 0.091, 0.218, ...]"] --> SQ["Quantification scalaire
(chaque poids séparément)"] SQ --> Q1["2-bit: [0, 1, 1, 2, ...]
Codebook scalaire: {-0.3, -0.1, +0.1, +0.3}
❌ Perte d'information massive"] end subgraph AQLM["AQLM (multi-codebook)"] W2["Poids FP16"] --> SPLIT["Découpage en vecteurs
group_size = 8 poids"] SPLIT --> OPT["Optimisation conjointe des codebooks
Codebook 1: 256 vecteurs dim 8
Codebook 2: 256 vecteurs dim 8
Sélection: w ≈ CB₁[42] + CB₂[17]
(beam search optimale)"] OPT --> STORE["Stockage: 2 indices 8-bit pour 8 poids
= 2 bits/poids
✅ 65 536 combinaisons additives possibles"] end
Détail du process AQLM#
(ex: Llama-2-7B)"] --> S1 S1["1. Calibration
Passer 128-512 échantillons
→ Calculer Hessienne H = 2XᵀX par couche"] --> S2 S2["2. Initialisation des codebooks
K codebooks via K-means sur les vecteurs de poids"] --> S3 S3["3. Optimisation itérative"] --> S3A S3A["a) Beam search: trouver meilleurs indices
(i₁, i₂, ..., i_K) pour chaque vecteur"] --> S3B S3B["b) Mise à jour: ajuster vecteurs des codebooks
pour minimiser ||W - ΣCB||²_H"] --> S3C S3C["c) Block-wise: optimiser conjointement
à travers les blocs du transformer"] --> S3D{"Convergé ?"} S3D -- Non --> S3A S3D -- Oui --> S4 S4["4. Modèle quantifié AQLM
K codebooks + indices par vecteur
Taille: ~2 bits/poids
Kernels GPU/CPU optimisés"]
Bits / Formats supportés#
| Configuration | Codebooks | Taille de codebook | Bits/poids | Supporté | Notes |
|---|---|---|---|---|---|
| 2-bit (1×16) | 1 | 65 536 | ~2.0 | ✅ | Configuration de base |
| 2-bit (2×8) | 2 | 256 | ~2.0 | ✅ | Configuration recommandée |
| 3-bit (2×12) | 2 | 4 096 | ~3.0 | ✅ | Bon ratio qualité/taille |
| 3-bit (1×8) | 1 | 256 | ~1.0 | ⚠️ | Trop extrême, dégradation |
| 4-bit | — | — | ~4.0 | ⚠️ | GPTQ/AWQ plus adaptés à ce niveau |
AQLM est conçu pour le régime sub-3-bit. À 4 bits et plus, les méthodes scalaires (GPTQ, AWQ) sont plus rapides et suffisent.
Résultats de perplexité#
AQLM est Pareto-optimal en accuracy-vs-model-size pour moins de 3 bits par poids.
Llama-2 (perplexité sur WikiText2 — plus bas = mieux)#
| Bits/poids | FP16 (ref) | AQLM | GPTQ | AWQ | QuIP# |
|---|---|---|---|---|---|
| 16 (ref) | 5.47 | — | — | — | — |
| ~2 | — | ~7.5–8.0 | 11.36 | 8.48 | 7.27 |
QuIP# et AQLM sont les seules options vraiment viables en 2-bit.
À mémoire équivalente#
À empreinte mémoire IDENTIQUE (~2 GB pour un 7B) :
AQLM 2-bit offre le meilleur qualité/taille. GPTQ 2-bit est cassé.
Avantages et inconvénients#
| ✅ Avantages | ❌ Inconvénients |
|---|---|
| Pareto-optimal en sub-3-bit (accuracy vs taille) | Temps de quantification très long (heures → jours) |
| Surpasse significativement GPTQ/AWQ à 2 bits | Complexité de mise en œuvre (apprentissage de codebooks) |
| Vitesse d'inférence ≥ FP16 optimisé | Support limité dans les frameworks mainstream |
| Memory footprint très réduit (~2 bpw) | Moins utile pour ≥ 4 bits (GPTQ/AWQ suffisent) |
| Kernels GPU et CPU optimisés | Sensibilité aux hyperparamètres (K, group_size) |
| Joint optimization inter-blocs | Calibration requise (données d'entrée) |
Outils et implémentations#
auto-aqlm (outil principal)#
auto-aqlm est le pipeline automatisé pour quantifier n'importe quel modèle Hugging Face avec AQLM.
# Installation
pip install auto-aqlm
# Quantification 2-bit (configuration recommandée : 2 codebooks × 8-bit)
python -m auto_aqlm \
--model meta-llama/Llama-2-7b-hf \
--output_dir ./llama-7b-aqlm-2bit \
--num_codebooks 2 \
--num_indices = 256 \
--in_group_size 8 \
--calibration_dataset redpajama \
--num_calibration_samples 128
# Résultat attendu :
# - Taille : 13.5 GB → ~2.5 GB (−81%)
# - Temps : 2–6 heures sur A100
# - PPL WikiText2 : ~7.5–8.0
Hugging Face Transformers#
from transformers import AutoModelForCausalLM, AutoTokenizer
# Charger un modèle AQLM pré-quantifié
model = AutoModelForCausalLM.from_pretrained(
"BlackSamorez/Llama-2-7b-AQLM-2Bit-1x16-hf",
device_map="auto",
trust_remote_code=True,
)
tokenizer = AutoTokenizer.from_pretrained(
"BlackSamorez/Llama-2-7b-AQLM-2Bit-1x16-hf"
)
# Inférence
inputs = tokenizer("Explique l'additive quantization :", return_tensors="pt")
outputs = model.generate(**inputs.to(model.device), max_new_tokens=200)
print(tokenizer.decode(outputs[0]))
Exemple pratique#
Quantifier Llama-2-7B avec auto-aqlm#
# 1. Installer auto-aqlm
pip install auto-aqlm transformers accelerate
# 2. Lancer la quantification (2-bit, 2 codebooks × 8-bit indices)
python -m auto_aqlm \
--model meta-llama/Llama-2-7b-hf \
--output_dir ./llama-2-7b-aqlm \
--num_codebooks 2 \
--in_group_size 8 \
--num_indices 256 \
--calibration_dataset c4 \
--num_calibration_samples 128
# 3. Résultat attendu
# ┌──────────────────────────────────────────┐
# │ Llama-2-7b FP16 : 13.5 GB │
# │ Llama-2-7b AQLM : ~2.5 GB (−81%) │
# │ Temps de quantif. : 2–6h sur A100 │
# │ PPL WikiText2 : ~7.5 │
# └──────────────────────────────────────────┘
Inférence avec vLLM (support AQLM)#
# vLLM supporte les modèles AQLM
pip install vllm
# Servir un modèle AQLM
python -m vllm.entrypoints.openai.api_server \
--model BlackSamorez/Llama-2-7b-AQLM-2Bit-1x16-hf \
--trust-remote-code
Comparaison avec les alternatives#
| Méthode | Régime optimal | 2-bit viable ? | Temps de quantif. | Calibration | Support frameworks |
|---|---|---|---|---|---|
| AQLM | ≤ 3 bit | ✅ (compétitif) | Très long (heures–jours) | ✅ Requise | Partiel (HF, vLLM) |
| QuIP# | ≤ 3 bit | ✅ ✅ (SOTA) | Long | ✅ Requise | Partiel |
| GPTQ | 4 bit | ❌ (cassé) | Rapide (minutes) | ✅ Requise | Excellent |
| AWQ | 3–4 bit | ⚠️ (dégradé) | Rapide | ✅ Requise | Excellent |
| HQQ | 3–4 bit | ⚠️ (dégradé) | Très rapide | ❌ Non | Bon |
AQLM et QuIP# se disputent le SOTA en sub-3-bit. QuIP# est généralement légèrement plus précis ; AQLM offre des kernels d'inférence plus matures.
Références#
- Papier AQLM — Egiazarian et al., "Extreme Compression of Large Language Models via Additive Quantization", ICML 2024 — arXiv:2401.06118
- Code officiel — github.com/Vahe1994/AQLM
- auto-aqlm — github.com/BlackSamorez/auto-aqlm — Pipeline automatisé
- Modèles pré-quantifiés — huggingface.co/BlackSamorez — Modèles AQLM prêts à l'emploi
- Intégration Hugging Face — huggingface.co/docs/transformers/aqlm
- Page de référence — Voir aussi Quantification LLM pour le panorama complet
- Méthode comparable — Voir QuIP# pour l'alternative en régime sub-3-bit