PolarQuant (Google Research) : compression du cache KV par transformation polaire

En bref

PolarQuant est une méthode de compression du cache KV publiée par Google Research. Elle permet de diviser par 4× la mémoire occupée par le cache clés-valeurs à l'inférence, sans réentraîner le modèle et avec une perte de qualité minime.

Son approche est différente de la quantification classique (int8/int4 avec scale + zero_point) : au lieu de stocker des valeurs numériques arrondies avec des paramètres de calibration par bloc, PolarQuant convertit les vecteurs en angles + rayons (coordonnées polaires), puis quantifie les angles — qui se trouvent être très prévisibles après un pré-traitement adapté. Résultat : pas besoin de stocker des constantes de quantification coûteuses en mémoire.

PolarQuant fait partie d'une suite plus large (TurboQuant, QJL) que Google Research a présentée en 2026, ciblant la compression "extrême" du cache KV pour les contextes longs.

Le problème que cela résout

Dans un Transformer auto-régressif, chaque nouveau token généré nécessite de recalculer l'attention sur tous les tokens précédents. Pour éviter de tout recalculer à chaque pas, on stocke les clés (K) et valeurs (V) dans un cache. Ce cache grossit linéairement avec la longueur du contexte et devient rapidement le principal goulet d'étranglement mémoire quand on travaille avec des contextes longs (32K, 128K tokens…).

La quantification classique (type int4/int8) réduit bien la taille du cache, mais elle introduit un surcoût souvent sous-estimé : pour chaque bloc de données quantifiées, il faut stocker un scale et parfois un zero_point en pleine précision. Google Research estime que ce surcoût peut ajouter 1 à 2 bits par valeur quantifiée selon les schémas — ce qui réduit le gain réel de compression.

Comment ça marche

PolarQuant se décompose en trois étapes, qui s'appliquent aux vecteurs K et V avant leur stockage dans le cache :

1. Préconditionnement (rotation aléatoire)

On multiplie chaque vecteur par une matrice de rotation orthogonale partagée (la même pour toutes les couches et têtes d'attention). L'effet : les coordonnées du vecteur sont "mélangées" de façon à ce qu'aucune dimension ne concentre toute l'énergie. Les produits scalaires sont préservés exactement.

2. Transformation polaire récursive

Le vecteur préconditionné est converti en coordonnées polaires de façon récursive : on prend les coordonnées par paires, on calcule un angle et un rayon pour chaque paire, puis on recommence avec les rayons. Après 4 niveaux (le réglage retenu), on obtient beaucoup d'angles et très peu de rayons (15/16 d'angles, 1/16 de rayons).

L'astuce centrale : après le préconditionnement, ces angles sont très concentrés autour de valeurs prévisibles (typiquement autour de 45°). Plus la dimension est grande, plus cette concentration est forte. On peut donc les encoder avec très peu de bits.

3. Quantification des angles via codebooks

Les angles sont quantifiés indépendamment via des codebooks (tables de correspondance), construits soit "en ligne" pendant le prefill, soit "hors ligne" (pré-calculés une fois pour toutes). En pratique, l'implémentation utilise 4 bits pour le premier niveau d'angles et 2 bits pour les suivants, soit environ 3,875 bits par coordonnée — contre 16 bits en FP16.

À la lecture (quand l'attention a besoin des K/V), on reconstruit les vecteurs en sens inverse : codebook → angles → cos/sin → rayons → rotation inverse.

Implémentation pratique

L'implémentation décrite dans l'article repose sur PyTorch avec des kernels CUDA custom pour les opérations critiques (déquantification pendant le calcul d'attention). Les valeurs sont empaquetées dans des torch.uint8. Les expériences sont réalisées sur un seul GPU RTX A6000 (48 GB).

Codebooks en ligne vs hors ligne — c'est le choix pratique le plus important :

Le mode en ligne construit les codebooks par k-means sur les angles observés pendant le prefill de chaque prompt. Qualité légèrement meilleure, mais prefill 3 à 4× plus lent.

Le mode hors ligne utilise des codebooks pré-calculés et réutilisables. Le prefill retrouve une vitesse normale, avec une perte de qualité négligeable — parce que la distribution des angles est très stable après préconditionnement.

Benchmarks

Qualité — LongBench (Llama-3.1-8B-Instruct)

Méthode Moyenne SQA MQA Résumé Few-shot Synthétique Code
Exact (16 bits) 45.71 45.32 26.69 68.62 59.25 46.17 48.63
SnapKV 38.23 42.61 19.07 64.65 59.60 43.28 44.57
HeadKV 39.45 42.69 19.77 68.07 59.48 42.60 45.34
PyramidKV 36.80 41.54 18.91 64.88 59.68 42.38 44.03
StreamingLLM 25.68 35.79 20.90 56.91 58.81 32.07 38.36
KIVI 43.38 37.81 27.44 68.60 58.67 44.29 46.70
PolarQuant 44.03 44.34 27.32 68.68 59.82 44.46 48.11
PolarQuant-R (offline) 44.71 44.72 26.43 68.58 60.08 45.20 48.29
PolarQuant-R (online) 45.45 45.13 26.42 68.54 59.57 45.13 48.37

Ce qu'il faut retenir : PolarQuant-R (online) est quasiment au niveau du FP16 (45.45 vs 45.71). Les méthodes par éviction de tokens (SnapKV, PyramidKV, StreamingLLM) perdent nettement plus en qualité. KIVI (quantification 2 bits) fait un bon score moyen mais chute sur certaines tâches (SQA).

Latence — prefill + génération (entrée 16K tokens, génération 1K tokens)

Méthode Prefill (s) Génération (s)
Exact (16 bits) 2.934 38.374
SnapKV 3.438 34.053
PyramidKV 3.428 32.732
HeadKV 3.300 34.401
KIVI 3.590 49.564
PolarQuant (online) 11.633 44.448
PolarQuant-R (offline) 3.364 44.097

Ce qu'il faut retenir : le mode online a un prefill très lent (~4× le FP16) à cause du clustering. Le mode offline ramène le prefill au niveau du FP16. En génération, PolarQuant est ~14% plus rapide que KIVI. Les méthodes par éviction restent les plus rapides en génération (elles gardent moins de tokens en cache).

PolarQuant vs les alternatives

Approche Principe Compression Points forts Points faibles
PolarQuant Rotation + polaire + codebooks >4,2× Proche du FP16 en qualité, pas de paramètres par bloc Kernels CUDA custom, pas de repo public, prefill coûteux en mode online
KIVI Quantification 2 bits asymétrique ~2,6× Implémentation "hardware-friendly", simple Qualité variable selon les tâches
SnapKV / PyramidKV / HeadKV Éviction/sélection de tokens ~4× Rapide en génération Perte de qualité notable, surtout sur tâches multi-docs
StreamingLLM Fenêtre glissante + tokens initiaux Variable Très simple Forte dégradation sur tâches longues
Quantification affine standard scale + zero_point par bloc Variable (int8/int4) Très compatible matériel Surcoût des paramètres de quantification

Limites et points d'attention

Côté pratique :

Le prefill en mode codebook online est un vrai problème de latence (11.6s vs 2.9s en FP16). Le mode offline le résout, mais avec un léger compromis qualité. La dimension des têtes d'attention doit être une puissance de 2 (ce qui est le cas de la plupart des architectures courantes, mais pas toutes). Pas de repo public, pas d'intégration framework — pour l'instant c'est un résultat de recherche, pas un outil prêt à l'emploi.

Côté robustesse :

La méthode fonctionne d'autant mieux que la dimension est grande (les angles se concentrent davantage). Sur de petites dimensions de tête, les codebooks fixes pourraient être moins efficaces. Si les vecteurs K/V ont une distribution très inhabituelle, le préconditionnement aide mais ne garantit rien.