Cache KV, mémoire récurrente, MLA et bas rang

Comparer trois budgets mémoire et distinguer compression par token, état fixe et factorisation bas rang.

Applied AI · advanced · Session 18

Carte du mécanisme

TOKEN t : h_t (d_model = 4096)
      │
      ▼
┌──────────────────┐
│  W_DKV : d → c   │  compression latente (c = 512)
└────────┬─────────┘
         ▼
      c_t  (512 valeurs)   ◀── SEULE CHOSE MISE EN CACHE
         │
   ┌─────┴─────┐
   ▼           ▼
┌───────┐  ┌───────┐
│ W_UK  │  │ W_UV  │  reconstruction c → têtes
└───┬───┘  └───┬───┘
    ▼          ▼
   K_t        V_t  ──▶ attention exacte sur t tokens
───────────────────────────────────────────────────────
CACHE  = t × couches × c × 2 o     ← TOUJOURS LINÉAIRE EN t
ÉTAT S = couches × d_k × d_v × 2 o ← constant, ne voit pas t

Le problème — Cache KV standard

Votre service vise 131 072 tokens de contexte. Avant toute optimisation, il faut le chiffre brut : à 32 couches, 8 têtes KV, d_head=128 et BF16, chaque token coûte 128 Kio de cache — 16 Gio par requête à pleine longueur. Et cette facture revient à chaque requête.

L’idée — Cache KV standard

Le cache conserve clés et valeurs de chaque token passé, par couche : bytes ≈ tokens × couches × 2 × têtes × d_head × octets. La lecture est fidèle — attention exacte sur tout le passé — et le calcul se refait facteur par facteur, sans calculatrice.

bytes≈tokens×layers×2×heads×d_head×bytes/value

Pourquoi / à quel prix — Cache KV standard

La fidélité est totale : rappel exact de n’importe quel token. Le prix est structurel : croissance strictement linéaire — ×32 tokens = ×32 mémoire — et une bande passante de relecture qui suit. Aucun réglage ne change la pente, seulement le coefficient.

Contrôle : Avec couches=32, têtes_KV=8, d_head=128 et BF16, le cache vaut 128 Kio par token. Recalculez ce 131 072 facteur par facteur, puis dites lequel disparaît si l’on passe en INT8.

Le problème — État récurrent fixe

16 Gio par requête interdit la plupart des déploiements. Les sessions 13 à 16 ont construit l’alternative radicale : et si le passé tenait dans une matrice de taille fixe, quel que soit le nombre de tokens ?

L’idée — État récurrent fixe

L’état S — 32 couches × 128 × 128 × BF16 = 1 Mio — résume tout le passé : 4 096 ou 524 288 tokens, toujours 1 Mio. La croissance disparaît ; c’est l’aboutissement des mémoires des sessions précédentes.

Pourquoi / à quel prix — État récurrent fixe

Un budget constant et dérisoire — 16 000 fois moins que le cache à 131 072 tokens. Le prix, connu des sessions 13-16 : compression et interférence — le rappel n’est plus exact et se dégrade avec la longueur, même si la mémoire, elle, ne bouge pas.

Contrôle : L’état fixe de 1 Mio ne bouge pas entre 4 096 et 524 288 tokens. Quelle quantité, elle, se dégrade sur cet intervalle, et à quel moment le remarqueriez-vous dans une sortie ?

Le problème — MLA

Entre 16 Gio exacts et 1 Mio approximatif, l’écart est brutal. Existe-t-il un milieu : garder une entrée PAR token — la fidélité structurée — mais payer moins par entrée ?

L’idée — MLA

Multi-head Latent Attention compresse chaque token en un vecteur latent c_t (512 valeurs) — la seule chose mise en cache — puis reconstruit K et V via W_UK et W_UV au moment de lire. Largeur ÷ 4 ⇒ 32 Kio/token, 4 Gio à 131 072 tokens.

Pourquoi / à quel prix — MLA

Le cache garde sa structure par token et la facture est divisée par 4. Le prix : une reconstruction à chaque lecture — de la mémoire troquée contre du calcul, surtout au décodage — et la croissance reste O(n) : le gain est un coefficient, pas un changement d’asymptote.

Contrôle : MLA met en cache c_t (512 valeurs) et reconstruit K_t et V_t via W_UK et W_UV. Quel coût déplace-t-on de la mémoire vers le calcul, et à quel pas — préfill ou décodage ?

Le problème — Factorisation bas rang

La compression de MLA repose sur une question d’algèbre pure : quand remplacer une grande matrice W par un produit de deux petites fait-il vraiment économiser ? Mal choisi, le goulot r ne gagne rien du tout.

L’idée — Factorisation bas rang

W (d×m) ≈ A(d×r)·B(r×m) coûte r(d+m) paramètres au lieu de d·m. Pour 4096×4096 : r=512 divise par 4 ; r=2048 donne 16 777 216 — exactement le coût d’origine. Le seuil d’équilibre est r = d·m/(d+m) = 2048 ici.

W≈AB, A∈R^{d×r}, B∈R^{r×m}

Pourquoi / à quel prix — Factorisation bas rang

Sous le seuil, l’économie est réelle et le calcul plus rapide. Le prix : la capacité de la projection est plafonnée au rang r — toute transformation qui exigerait un rang supérieur est structurellement hors de portée, quel que soit l’entraînement.

Contrôle : Pour W ∈ R^{4096×4096}, r=512 divise les paramètres par 4 mais r=2048 n’économise rien. Retrouvez le seuil r = d·m/(d+m) et expliquez pourquoi il vaut exactement 2048 ici.

Support visuel — Factorisation bas rang

W : 4096 × 4096 = 16 777 216 paramètres

r =  512 : 4096·512 + 512·4096   =  4 194 304   ✅ ÷ 4
r = 1024 : 4096·1024 + 1024·4096 =  8 388 608   ✅ ÷ 2
r = 2048 : 4096·2048 + 2048·4096 = 16 777 216   ❌ = W entier

seuil : r* = d·m/(d+m) = 4096·4096/8192 = 2048
au-delà du goulot d’équilibre, la « compression » coûte plus cher

Le problème — MLA n’est pas mémoire fixe

Deux annonces se ressemblent : « cache compressé 4× » et « mémoire constante ». Une équipe budgète 4 Gio « pour toujours » avec MLA — et découvre 16 Gio à 524 288 tokens. Où est passée la promesse ?

L’idée — MLA n’est pas mémoire fixe

Il n’y en avait pas : MLA compresse chaque entrée, il ne fusionne pas les tokens. Une entrée par token ⇒ croissance linéaire à coefficient réduit. Seul un état récurrent fusionne le passé en un objet de taille fixe.

Pourquoi / à quel prix — MLA n’est pas mémoire fixe

Distinguer les deux évite l’erreur de capacité en production : MLA borne le coefficient, l’état borne la croissance. Le prix de la confusion se lit dans la trace : le gain ×4 de MLA est ravalé par ×4 tokens — la longueur continue de commander.

Contrôle : Passer de 131 072 à 524 288 tokens ramène MLA à 16 Gio, soit le budget du cache standard de départ. Quel type de gain la compression par token offre-t-elle donc — constant ou asymptotique ?

Support visuel — MLA n’est pas mémoire fixe

                 4 096 t     131 072 t     524 288 t
cache standard   512 Mio     16 Gio        64 Gio      droite, 128 Kio/t
MLA (c ÷ 4)      128 Mio      4 Gio        16 Gio      droite, 32 Kio/t
état fixe          1 Mio      1 Mio         1 Mio      plate
                              ▲
     MLA à 524 288 t = cache standard à 131 072 t :
     un coefficient se rattrape, une pente ne se rattrape pas

Le problème — Bas rang n’est pas LoRA

Même formule W ≈ AB dans deux contextes : la factorisation architecturale de MLA et l’adaptation LoRA. Un lecteur pressé conclut « MLA, c’est du LoRA intégré » — et propose de « retirer l’adaptateur » d’un modèle qui n’en a pas.

L’idée — Bas rang n’est pas LoRA

Rôles opposés : dans MLA, A et B SONT le chemin normal, entraînés depuis zéro, inamovibles. LoRA ajoute un delta bas rang À CÔTÉ de poids gelés, pour adapter après coup — fusionnable ou désactivable à volonté.

Pourquoi / à quel prix — Bas rang n’est pas LoRA

Le discernement évite des décisions absurdes — geler « l’adaptateur » de MLA, ou croire LoRA indispensable à l’inférence. Le prix : une vigilance permanente ; la même algèbre sert des architectures et des procédés d’adaptation, et seul le contexte décide du sens.

Contrôle : W_DKV et W_UK sont dans le chemin avant du modèle et entraînés avec lui ; une adaptation LoRA ajoute A et B à côté de poids gelés. Sur les deux, laquelle peut être retirée après coup sans casser le modèle ?

Support visuel — Bas rang n’est pas LoRA

même algèbre W ≈ A·B       MLA (architecture)     LoRA (adaptation)

entraîné…                  depuis zéro            après coup
à côté de…                 rien : c’est W         poids gelés
retirable ?                jamais                 fusion ou retrait
objectif                   cache plus étroit      spécialiser à bas coût

Cas guidé — trace complète

Avec 32 couches, 8 têtes KV, d_head=128, BF16 et 4 096 tokens, le cache brut simplifié vaut 4 096×32×2×8×128×2 octets = 536 870 912 octets = 512 Mio (0,5 Gio). Diviser la largeur latente par quatre réduit le terme par token, pas sa croissance linéaire.

CONFIG : couches=32, têtes_KV=8, d_head=128, BF16 (2 o/valeur)

bytes ≈ tokens × couches × 2 × têtes × d_head × 2

par token = 32 × 2 × 8 × 128 × 2 = 131 072 o = 128 Kio/token

t = 4 096    → 4 096 × 131 072 = 536 870 912 o = 512 Mio  ✅
t = 131 072  → 131 072 × 131 072 = 17 179 869 184 o = 16 Gio ✅
               (×32 tokens ⇒ ×32 mémoire : strictement linéaire)

MLA, largeur latente ÷ 4 → 32 Kio/token
t = 131 072  → 4 Gio        ✅ 4× moins… mais toujours linéaire
t = 524 288  → 16 Gio       ❌ le gain constant est ravalé par ×4 tokens

ÉTAT FIXE (d_k=d_v=128) : 32 × 128 × 128 × 2 = 1 Mio
t = 4 096 → 1 Mio ; t = 524 288 → 1 Mio   ← indépendant de t

BAS RANG : W (4096×4096) = 16 777 216 param.
  r = 512  → 2 × 4096 × 512  =  4 194 304   ✅ ÷4
  r = 2048 → 2 × 4096 × 2048 = 16 777 216   ❌ zéro gain (seuil r = d·m/(d+m))

CONTRÔLE D’UNITÉS : 512 Mio ≠ 512 Mo. 1 Gio = 1 024 Mio = 2³⁰ o.

Trois budgets mémoire à 131 072 tokens (32 couches, BF16)

Mécanisme Mémoire à 131 072 tokens Ce que l’on paie
Cache KV standard 16 Gio, croissance O(n) rien en fidélité : rappel exact
MLA (c ÷ 4) 4 Gio, croissance O(n) reconstruction K/V à chaque lecture
État récurrent fixe 1 Mio, constant compression et interférence entre tokens
Bas rang r=512 sur W n’affecte pas le cache capacité de la projection plafonnée à r

Laboratoire causal

Prédire → modifier une variable → exécuter → expliquer l’écart

/interactives/curriculum/cache-mla-comparison.html?lang=fr

Erreurs fréquentes

« MLA transforme le cache en mémoire de taille fixe. »

MLA compresse chaque entrée du cache, il ne fusionne pas les tokens. Le cache reste une entrée par token : 4 Gio à 131 072 tokens, 16 Gio à 524 288. Seul un état récurrent (1 Mio ici) est réellement indépendant de la longueur.

« La factorisation bas rang du modèle, c’est du LoRA intégré. »

Même algèbre (W ≈ AB), rôles opposés. Ici A et B sont le chemin normal du modèle, entraînés depuis zéro et jamais retirables. LoRA ajoute un delta bas rang entraînable à côté de poids gelés, pour adapter après coup et se fusionner ou se désactiver à volonté.

Frontière, preuve et sources

Les formules simplifiées omettent alignement, quantification, buffers et détails de partage. Elles servent à comparer des tendances, pas à promettre une empreinte réelle.

Statut de preuve : Mixte : mécanismes établis + choix de type Kimi K3 rapportés par la source.

  • Dossier de cours bilingue fourni par le propriétaire, chapitre 13.
  • DeepSeek-AI, “DeepSeek-V2: A Strong, Economical, and Efficient Mixture-of-Experts Language Model” (introduces Multi-head Latent Attention), arXiv:2405.04434 (2024).
  • Hu et al., “LoRA: Low-Rank Adaptation of Large Language Models”, ICLR (2022).
  • Dossier source fourni par le propriétaire; les détails sur des produits nommés restent attribués à cette source jusqu’à vérification primaire.

Défi de transfert

Choisissez UNE hypothèse de la trace — d_head, largeur latente c, ou longueur servie — et modifiez-la d’un facteur 2.

  1. Pré-enregistrez l’effet attendu sur le coût par token ET sur la mémoire à 131 072 tokens.
  2. Recalculez les deux chiffres et comparez à votre prédiction.
  3. Laquelle des trois modifications changerait aussi la qualité, et pourquoi les deux autres pas directement ?

Synthèse et ticket de sortie

  • Cache KV standard
  • État récurrent fixe
  • MLA
  • Factorisation bas rang
  • MLA n’est pas mémoire fixe
  • Bas rang n’est pas LoRA

Ticket : mécanisme · trace · observation · frontière · preuve · prochaine expérience

Notes formateur: Poser le problème avant de nommer le mécanisme. Recueillir une prédiction initiale et la conserver pour le ticket de sortie.

Notes formateur: Faire relier chaque étape à la suivante par un verbe causal. Signaler toute flèche purement décorative.

Notes formateur: Ouvrir par la facture : « votre PM veut 131 072 tokens de contexte — combien de mémoire par requête ? ». Recueillir trois estimations avant tout calcul ; l’écart entre les réponses et 16 Gio structure toute la séance.

Notes formateur: Faire poser le calcul au tableau facteur par facteur, sans calculatrice, jusqu’à 128 Kio/token. Puis demander de doubler d_head à voix haute : le réflexe « quel facteur bouge » est l’objectif de la diapositive.

Notes formateur: Réponse : 32 × 2 × 8 × 128 × 2 = 131 072 o — couches × (K et V) × têtes × d_head × octets/valeur. En INT8, le dernier facteur passe de 2 à 1 : 64 Kio/token. Erreur attendue : « INT8 supprime un facteur » — non, il le divise par deux ; aucun facteur ne disparaît.

Notes formateur: Rappel éclair des sessions 13-16 en une question : « quelle taille fait S après un million de tokens ? ». La réponse « la même » doit fuser de la salle — sinon, refaire soixante secondes de session 13 avant d’avancer.

Notes formateur: Demander avant tout commentaire : « à 524 288 tokens, combien pèse l’état ? » La réponse « toujours 1 Mio » doit venir de la salle, pas de l’instructeur — c’est ce qui rend le compromis crédible ensuite.

Notes formateur: Réponse : la qualité du rappel se dégrade (interférence accumulée), pas la mémoire ; on le remarque quand une lecture ancienne revient mélangée — d’où un test de rappel contrôlé, pas un moniteur de RAM. Erreur attendue : « rien ne se dégrade puisque la taille est constante ».

Notes formateur: Question d’accroche : « peut-on payer moins par token sans renoncer au par-token ? ». Laisser la salle formuler l’espace du compromis — fidélité structurée contre coefficient — avant de prononcer « MLA ».

Notes formateur: Faire tracer la flèche du schéma au feutre : qu’est-ce qui est stocké, qu’est-ce qui est recalculé ? Tant que la salle n’a pas désigné c_t seul, ne pas avancer.

Notes formateur: Réponse : on déplace de la mémoire (cache 4× plus étroit) vers du calcul (reconstruction via W_UK/W_UV à chaque lecture) ; le surcoût pèse surtout au décodage, où chaque nouveau token relit tout le cache. Erreur attendue : « au préfill » — le préfill est déjà dominé par le calcul.

Notes formateur: Écrire 16 777 216 au tableau et demander : « couper W en deux matrices, ça gagne toujours ? ». Faire voter oui/non ; le vote prépare la découverte du seuil r = 2048 dans le beat.

Notes formateur: Donner r = 2048 sans le commenter et laisser le groupe découvrir le zéro gain. L’échec calculé vaut mieux que la règle énoncée ; ensuite seulement, faire dériver le seuil.

Notes formateur: Réponse : coût factorisé r(d+m) < d·m ⇔ r < d·m/(d+m) ; avec d = m = 4096, r* = 4096/2 = 2048, et à r = 2048 l’égalité est exacte : zéro gain. Erreur attendue : croire le seuil à d/2 « par hasard » — faire refaire avec d = 4096, m = 1024 (r* ≈ 819).

Notes formateur: Faire calculer la ligne r = 1024 par la salle avant de l’afficher, puis demander r* pour d = 4096, m = 1024 (≈ 819) : le seuil dépend des DEUX dimensions, pas d’une règle « moitié ».

Notes formateur: Relire les deux annonces côte à côte : « cache compressé 4× » et « mémoire constante ». Demander qui budgète quoi à 524 288 tokens — les erreurs de budget récoltées sont le contenu du beat.

Notes formateur: Provoquer explicitement l’erreur : demander un vote à main levée sur « MLA est-il à mémoire fixe ? » avant de montrer les 4 Gio → 16 Gio. Le vote rend la correction mémorable.

Notes formateur: Réponse : un gain constant — un facteur ÷4 sur une croissance qui reste linéaire ; l’ordre O(n) est inchangé. Erreur attendue : « asymptotique, puisque 4× moins à toute longueur » — c’est précisément la définition d’un gain constant. Renvoyer au support visuel : deux droites, coefficients différents.

Notes formateur: Faire lire la table en diagonale : la case MLA à 524 288 égale la case standard à 131 072. Demander ensuite : « quelle ligne changerait si on passait c ÷ 8 ? » — seules les deux droites bougent, jamais la plate.

Notes formateur: Afficher W ≈ AB seul, sans contexte, et demander : « architecture ou adaptation ? ». L’impossibilité de répondre sans contexte EST la leçon du beat — la formuler explicitement à la fin.

Notes formateur: Écrire W ≈ AB une seule fois au tableau et faire annoter deux colonnes : « entraîné depuis zéro / greffé sur gelé », « inamovible / fusionnable ». La même algèbre, deux colonnes : c’est tout le message.

Notes formateur: Réponse : l’adaptation LoRA est retirable — un delta posé à côté de poids gelés ; W_DKV et W_UK sont le chemin avant du modèle, les retirer le casse. Erreur attendue : confondre « LoRA peut être fusionné » (choix) avec « LoRA est indispensable » (faux), et l’inverse pour MLA.

Notes formateur: Masquer les en-têtes de colonnes et faire deviner, ligne par ligne, de quel côté chaque case appartient. Les hésitations sur « retirable ? » sont le vrai diagnostic de compréhension.

Notes formateur: Dérouler ligne par ligne. Une incohérence se localise à la première étape fautive, pas seulement sur la dernière ligne.

Notes formateur: Faire remplir la dernière ligne par les apprenants avant de la révéler : c’est le compromis qui décide en production.

Notes formateur: Conserver les valeurs initiales et finales. Interdire les changements simultanés qui rendent l’écart impossible à attribuer.

Notes formateur: Pour chaque affirmation, faire produire le contre-exemple minimal par le groupe avant de donner la correction.

Notes formateur: Séparer mécanisme vérifiable, choix d’implémentation rapporté et résultat expérimental. La précision de la preuve doit suivre celle de l’affirmation.

Notes formateur: Réponses : d_head ×2 → 256 Kio/token et 32 Gio (qualité potentiellement touchée : têtes plus larges) ; c ÷2 → 16 Kio/token et 2 Gio (qualité touchée : reconstruction plus contrainte) ; longueur ÷2 → coût par token INCHANGÉ, mémoire 8 Gio (qualité touchée seulement si le contenu utile dépasse la fenêtre). Erreur à récolter : « diviser la longueur divise le coût par token ». Vérifier que chaque binôme a pré-enregistré avant de calculer. 10 minutes.

Notes formateur: Faire reconstruire la chaîne sans regarder les slides, puis remplir le ticket en six lignes maximum. Comparer à la prédiction initiale du premier slide et nommer ce qui a réellement changé.