HQQ (Half-Quadratic Quantization)#
TL;DR — HQQ formule la quantification comme un problème d'optimisation half-quadratic résolu par alternance. Résultat : une quantification ultra-rapide (Llama-2-70B en < 5 minutes) et sans calibration (aucune donnée d'entrée nécessaire) qui rivalise avec GPTQ en qualité. La seule méthode majeure qui opère exclusivement sur les poids, sans jamais avoir besoin de passer des données dans le modèle.
Le problème fondamental (expliqué pour un néophyte)#
La plupart des méthodes de quantification (GPTQ, AWQ, SmoothQuant) ont besoin de données de calibration : on passe 128 à 1024 échantillons de texte à travers le modèle pour observer comment les activations se comportent, puis on utilise cette information pour guider la quantification des poids. C'est efficace mais ça prend du temps et pose des problèmes de généralisation (le modèle peut surajuster aux données de calibration).
L'insight de HQQ : et si on pouvait quantifier les poids uniquement à partir de leur distribution statistique, sans jamais passer de données à travers le modèle ? HQQ reformule la quantification comme un problème d'optimisation mathématique pur et le résout avec un algorithme itératif qui converge rapidement.
(variables auxiliaires)"] OPT --> Q2["Poids quantifiés"] end
❌ GPTQ/AWQ : lent, nécessite des données, peut surajuster — ✅ HQQ : rapide, data-free, généralise bien.
Papier source#
| Élément | Détail |
|---|---|
| Titre | Half-Quadratic Quantization of Large Machine Learning Models |
| Auteurs | Hicham Badri, Mohammad Emad (Dropbox) |
| Date | Novembre 2023 |
| Publication | Pas un papier arXiv formel à l'origine — publié comme blog technique Dropbox et code open-source |
| Code | github.com/dropbox/hqq |
⚠️ HQQ n'a pas de papier académique peer-reviewed formel à l'origine. La méthode est décrite dans un blog technique et le code open-source. Son adoption rapide par la communauté (intégration Hugging Face, vLLM) témoigne de sa qualité pratique.
Mécanisme#
Niveau néophyte#
Quand on quantifie des poids, on essaie de trouver les meilleurs paramètres (scale, zero-point) pour minimiser l'erreur entre les poids originaux et leurs versions quantifiées. C'est un problème d'optimisation, mais il est difficile car la quantification n'est pas différentiable (on ne peut pas calculer de gradient proprement).
HQQ contourne ce problème en introduisant des variables auxiliaires qui rendent le problème résoluble de manière itérative : on alterne entre optimiser les variables auxiliaires et optimiser les paramètres de quantification, jusqu'à converger vers une bonne solution. C'est comme résoudre un puzzle en fixant d'abord certaines pièces, puis les autres, puis en revenant aux premières avec les nouvelles informations.
Niveau intermédiaire#
HQQ formule la quantification comme la minimisation d'une fonction objectif half-quadratic :
min_{Q,s,z} || W - Q(W; s, z) ||² + λ · g(v)
où :
- W = matrice de poids originale
- Q(W; s, z) = version quantifiée avec scale s et zero-point z
- g(v) = terme de régularisation half-quadratic
- λ = paramètre de régularisation
- v = variable auxiliaire introduite pour rendre le problème tractable
La résolution se fait par optimisation alternée (alternating minimization) :
Répéter jusqu'à convergence :
Étape 1 : Fixer Q, optimiser v
→ Problème proximal : v = prox_{λg}(W - Q)
(mise à jour des variables auxiliaires)
Étape 2 : Fixer v, optimiser s, z
→ Optimiser les paramètres de quantification (scale, zero-point)
sachant les variables auxiliaires actuelles
Cette alternance converge rapidement (quelques itérations) et ne nécessite aucune forward pass dans le modèle — tout se passe au niveau de la matrice de poids.
Niveau tech avancé#
La formulation half-quadratic repose sur le théorème de Geman & Yang (1995) : pour certaines fonctions de coût robustes, il existe une représentation équivalente avec une variable auxiliaire qui transforme un problème non-convexe en une suite de sous-problèmes convexes.
Théorème half-quadratic (demimodule) :
Pour f(x) = φ(x²) où φ est convexe et décroissante :
f(x) = min_v { v·x² + ψ(v) }
où ψ(v) est le conjugué de Fenchel de φ.
→ Le problème original à une variable devient
un problème à deux variables résoluble par alternance.
Dans HQQ, cela s'applique au problème de quantification :
-
Variables auxiliaires
v: agissent comme un masque de pondération adaptatif qui accorde plus d'importance aux poids difficiles à quantifier (près des frontières de bins). -
Optimisation des paramètres
s(scale) etz(zero-point) : devient un problème de moindres carrés pondéré, soluble analytiquement. -
Convergence : typiquement 5–20 itérations suffisent, rendant la quantification extrêmement rapide.
Le résultat : une quantification per-channel ou per-group optimisée pour chaque canal/groupe de poids, sans aucune information d'activation.
Illustration : le process HQQ#
Distribution statistique seule
🔴 Pas de données ! Pas de forward pass !"] --> INIT INIT["Initialisation: scale s₀, zp z₀
(estimation statistique de W)"] --> LOOP subgraph LOOP["Boucle d'optimisation alternée"] S1["Étape 1: Mise à jour de v
v = prox_{λg}(W − Q(W;s,z))
→ Variables auxiliaires"] --> S2 S2["Étape 2: Mise à jour de s, z
min_{s,z} || W − Q(W;s,z) ||²_v
→ Scale et zero-point optimaux"] --> CONV{"Convergé ?"} CONV -- "Non (5–20 itérations)" --> S1 end CONV -- Oui --> OUT OUT["Poids quantifiés Q(W; s*, z*)
+ paramètres optimaux s*, z*
⏱ Temps total: < 2 min pour 7B, < 5 min pour 70B"]
Bits / Formats supportés#
| Bits | Format | Supporté | Notes |
|---|---|---|---|
| 1-bit | int1 | ✅ | Régime extrême, qualité dégradée mais fonctionnelle |
| 2-bit | int2 | ✅ | Utilisable pour les grands modèles (≥ 70B) |
| 3-bit | int3 | ✅ | Bonne qualité, sweet spot pour grands modèles |
| 4-bit | int4 | ✅ | Configuration recommandée — compétitif avec GPTQ |
| 8-bit | int8 | ✅ | Excellent, perte négligeable |
| 16-bit | fp16 | ✅ | Pas de quantification, référence |
HQQ est l'une des rares méthodes qui supporte nativement n'importe quel nombre de bits, y compris 1-bit.
Pourquoi c'est calibration-free ?#
→ X = activations → nécessite des données de calibration
→ La Hessienne guide l'erreur selon l'importance fonctionnelle"] AH["AWQ utilise max(|X|) des activations
→ Nécessite des données de calibration
→ Identifie les poids 'saillants' via les activations"] end subgraph HQQ_BOX["HQQ"] HH["HQQ optimise || W − Q(W) ||²
→ N'utilise QUE les poids W
→ Aucune information d'activation nécessaire
→ Les variables auxiliaires v compensent l'absence
d'information fonctionnelle"] end TRADE["Trade-off: HQQ ne sait pas quels poids sont
'fonctionnellement importants', mais l'optimisation HQ
minimise si bien l'erreur statistique que ça suffit
pour atteindre une qualité compétitive."] HQQ_BOX --> TRADE
Résultats de perplexité#
Llama-2 (perplexité sur WikiText2 — plus bas = mieux)#
| Bits/poids | FP16 (ref) | HQQ | GPTQ | AWQ |
|---|---|---|---|---|
| 16 (ref) | 5.47 | — | — | — |
| 4 | — | 5.73 | 5.69 | 5.63 |
| 3 | — | 6.55 | 6.62 | 6.40 |
| 2 | — | 9.62 | 11.36 | 8.48 |
En 3-bit, HQQ surpasse même GPTQ (6.55 vs 6.62) — sans avoir utilisé la moindre donnée de calibration !
Le résultat contre-intuitif : grand modèle + bas bitrate#
Llama-2-70B 3-bit HQQ vs Llama-2-13B FP16 — Empreinte mémoire IDENTIQUE (~25 GB) :
- Llama-2-13B FP16 : PPL 5.74 (référence)
- Llama-2-70B HQQ 3-bit : PPL ~5.6 (MEILLEUR !)→ Un modèle 70B en 3-bit bat un modèle 13B full-precision À MÉMOIRE ÉQUIVALENTE. Conclusion : préférer un grand modèle quantifié plutôt qu'un petit modèle en pleine précision.
Avantages et inconvénients#
| ✅ Avantages | ❌ Inconvénients |
|---|---|
| Data-free : aucune calibration nécessaire | Moins précis que GPTQ/AWQ (qui utilisent les activations) |
| Ultra-rapide : 70B en < 5 minutes | Pas de papier académique formel (peer review limité) |
| Flexible : supporte 1-bit à 8-bit | Support dans les frameworks moins universel que bitsandbytes |
| Qualité compétitive en INT4/INT3 | Sans calibration, ignore l'importance fonctionnelle des poids |
| Grand modèle 3-bit > petit modèle FP16 à mémoire équivalente | Régime 2-bit moins bon qu'AQLM/QuIP# |
| Intégration Hugging Face native | Overhead de déquantification à l'inférence |
Outils et implémentations#
HQQ (Dropbox)#
# Installation
pip install hqq
# Quantification
python -c "
from hqq.engine.hf import HQQModelForCausalLM
from hqq.core.quantize import HQQLinear, HQQDefaultConfig
# Charger le modèle
model = HQQModelForCausalLM.from_pretrained('meta-llama/Llama-2-7b-hf')
# Configuration quantification (8-bit par défaut)
quant_config = HQQDefaultConfig(nbits=4, group_size=64)
# Quantifier
HQQModelForCausalLM.quantize_model(model, quant_config=quant_config)
# Sauvegarder
model.save_quantized('./llama-7b-hqq-4bit')
"
Hugging Face Transformers#
from transformers import AutoModelForCausalLM, AutoTokenizer
# Charger directement un modèle HQQ quantifié
model = AutoModelForCausalLM.from_pretrained(
"mobiuslabsgmbh/Llama-2-7b-hf-2bit_hqq",
device_map="auto",
)
tokenizer = AutoTokenizer.from_pretrained(
"mobiuslabsgmbh/Llama-2-7b-hf-2bit_hqq"
)
# Inférence
inputs = tokenizer("Explique la quantification half-quadratic :", 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 HQQ#
# 1. Installer HQQ
pip install hqq transformers accelerate
# 2. Quantification 4-bit (rapide, data-free)
python -c "
from hqq.engine.hf import HQQModelForCausalLM
from hqq.core.quantize import HQQDefaultConfig
model_id = 'meta-llama/Llama-2-7b-hf'
# Charger et quantifier
model = HQQModelForCausalLM.from_pretrained(model_id)
HQQModelForCausalLM.quantize_model(
model,
quant_config=HQQDefaultConfig(nbits=4, group_size=64)
)
model.save_quantized('./llama-2-7b-hqq-4bit')
# 3. Résultat attendu :
# ┌──────────────────────────────────────────────┐
# │ Llama-2-7b FP16 : 13.5 GB │
# │ Llama-2-7b HQQ 4bit : ~3.8 GB (−72%) │
# │ Temps de quantif. : < 2 minutes ! │
# │ PPL WikiText2 : ~5.73 │
# │ Calibration : AUCUNE │
# └──────────────────────────────────────────────┘
"
Quantification extrême : 2-bit#
# 2-bit (pour les très grands modèles)
python -c "
from hqq.engine.hf import HQQModelForCausalLM
from hqq.core.quantize import HQQDefaultConfig
model = HQQModelForCausalLM.from_pretrained('meta-llama/Llama-2-70b-hf')
HQQModelForCausalLM.quantize_model(
model,
quant_config=HQQDefaultConfig(nbits=2, group_size=64)
)
model.save_quantized('./llama-2-70b-hqq-2bit')
# Résultat :
# Llama-2-70B FP16 : 140 GB → HQQ 2-bit : ~18 GB
# Temps : < 5 minutes sur A100
# Pas de calibration !
"
Comparaison avec les alternatives#
| Méthode | Calibration | Vitesse quantif. | PPL 4-bit | PPL 2-bit | Simplicité |
|---|---|---|---|---|---|
| HQQ | ❌ Aucune | ⚡ Très rapide (< 5 min) | 5.73 | 9.62 | ⭐⭐⭐⭐⭐ |
| GPTQ | ✅ Requise | Rapide (minutes) | 5.69 | 11.36 | ⭐⭐⭐⭐ |
| AWQ | ✅ Requise | Rapide | 5.63 | 8.48 | ⭐⭐⭐⭐ |
| AQLM | ✅ Requise | Très lente (heures) | N/A | ~7.5 | ⭐⭐ |
| QuIP# | ✅ Requise | Lente | 5.55 | 7.27 | ⭐⭐ |
HQQ brille par sa simplicité et sa vitesse : c'est la méthode de référence quand on veut quantifier rapidement sans se soucier de données de calibration. En qualité pure, GPTQ/AWQ (avec calibration) sont légèrement meilleurs en 4-bit, et AQLM/QuIP# dominent en 2-bit.
Références#
- Blog HQQ — Badri & Emad, "Half-Quadratic Quantization of Large Machine Learning Models", Dropbox, 2023 — dropbox.github.io/hqq_blog
- Code officiel — github.com/dropbox/hqq
- Modèles pré-quantifiés — huggingface.co/mobiuslabsgmbh — Modèles HQQ prêts à l'emploi
- Intégration Hugging Face — huggingface.co/docs/transformers/hqq
- Théorie half-quadratic — Geman & Yang, "Nonlinear image recovery with half-quadratic regularization", 1995 — base théorique de la formulation HQ
- Page de référence — Voir aussi Quantification LLM pour le panorama complet