Attention linéaire et mémoire matricielle fixe

Passer d’un carnet de tokens croissant à une matrice d’état fixe, puis mesurer la lecture et les interférences.

Applied AI · advanced · Session 13

Carte du mécanisme

ÉCRITURE (token t)                    LECTURE (requête)
 k=[1,0]  v=[2,3]                        q=[1,0]
     │                                      │
     ▼                                      │
┌──────────────┐                            │
│ produit ext. │                            │
│    k vᵀ      │                            │
└──────┬───────┘                            │
       │ S ← S + k vᵀ                       ▼
       ▼                            ┌──────────────┐
┌──────────────────────┐    qᵀS     │   lecture    │
│  S  = [[2,3],        │ ─────────▶ │  y = qᵀS     │
│        [0,0]]        │            │  y = [2,3]   │
│  TAILLE FIXE d_k×d_v │            └──────────────┘
└──────────────────────┘
  toutes les écritures et lectures passent par S ;
  S ne grandit pas avec la séquence

Le problème — Fondations matricielles

Vous allez manipuler des mémoires faites de vecteurs et de matrices. Une erreur de forme — multiplier un vecteur de 3 par une matrice 2×2 — ne produit pas un résultat faux : elle n’a aucun sens. Et avec le broadcasting de NumPy, certaines formes fausses s’exécutent quand même et corrompent tout l’aval en silence.

L’idée — Fondations matricielles

Un vecteur est une liste ordonnée de d nombres ; une matrice organise lignes et colonnes (d_k × d_v). Les dimensions dictent les multiplications valides : ici k(2) et v(2) fabriquent S(2×2), et une clé [1;0;2] de dimension 3 est refusée avant tout calcul.

Pourquoi / à quel prix — Fondations matricielles

Le contrôle de forme coûte une ligne et se fait avant le calcul : il transforme une corruption silencieuse en refus immédiat. Le prix de l’ignorer : les sessions 14 à 18 empilent ces objets — une forme fausse au départ y devient introuvable.

Contrôle : S mesure 2×2 et l’on vous donne k=[1,0,2]. Quelle multiplication échoue exactement, quelle dimension devez-vous corriger en premier, et pourquoi ce contrôle doit-il précéder tout calcul plutôt que le suivre ?

Le problème — Produit scalaire

Une mémoire a besoin d’adresses : à quelle écriture une requête doit-elle s’apparier ? Comparer des vecteurs « à l’œil » ne donne aucun nombre exploitable, et sans mesure d’alignement chiffrée, chaque lecture devrait tout relire.

L’idée — Produit scalaire

Le produit scalaire résume l’alignement en un nombre : q·k = Σqᵢkᵢ. Ici q=[1,0] contre k=[1,0] donne 1 (aligné) ; contre k=[0,1] il donne 0 (orthogonal). C’est le mécanisme d’adressage : fort = concerné, nul = ignoré.

q·k=Σqᵢkᵢ

Pourquoi / à quel prix — Produit scalaire

Pourquoi ça marche : le zéro d’orthogonalité isole les adresses — sans lui, chaque requête lirait toutes les écritures. Le prix : l’alignement est continu ; deux clés proches (q·k = 0,9) partagent partiellement leur adresse, et ce partage deviendra l’interférence du dernier beat.

Contrôle : Pour k=[0,1] et q=[1,0], le produit scalaire q·k vaut 0. Que lira la requête à cette adresse, pourquoi ce zéro est-il recherché plutôt que subi, et que se passerait-il si toutes les clés étaient identiques ?

Support visuel — Produit scalaire

        k=[0,1]
          ▲
          │
          │
          └──────────▶ k=[1,0]   (aussi la direction de q)

q=[1,0]·k=[1,0] = 1   → adresse sélectionnée
q=[1,0]·k=[0,1] = 0   → adresse ignorée
q=[1,1]·k=[1,0] = 1   → sélection partielle : q touche les DEUX lignes

Le problème — Produit extérieur

Le produit scalaire compare, mais n’écrit rien. Comment ranger la valeur v=[2,3] « à l’adresse » k=[1,0] dans une structure de taille fixe — de façon que la bonne requête la retrouve plus tard ?

L’idée — Produit extérieur

Le produit extérieur k vᵀ fabrique une matrice : la ligne est sélectionnée par k, le contenu est porté par v. Pour k=[1,0] et v=[2,3] : k vᵀ = [[2,3],[0,0]] — la valeur est rangée sur la ligne 1, la ligne 2 reste vierge. L’écriture s’accumule : S ← S + k vᵀ.

S←S+k vᵀ

Pourquoi / à quel prix — Produit extérieur

Une écriture associative en une opération O(1), locale à la direction de k : c’est ce qui rend l’état fixe possible. Le prix : l’addition est aveugle — elle ne vérifie jamais si l’adresse est déjà occupée. Écrire deux fois sur k=[1,0] additionne les valeurs au lieu de remplacer.

Contrôle : Écrivez k vᵀ pour k=[0,1] et v=[5,1], puis donnez S complet. Quelle ligne de S change, laquelle reste intacte, et quelle propriété de k explique cette localisation de l’écriture ?

Support visuel — Produit extérieur

            v = [ 2   3 ]

k = [1]     ┌─────────┐
    [0]     │  2   3  │  ← ligne allumée par k₁ = 1
            │  0   0  │  ← ligne éteinte par k₂ = 0
            └─────────┘

k vᵀ : chaque case (i,j) = kᵢ × vⱼ

Le problème — Lecture de l’état

La mémoire contient maintenant plusieurs écritures superposées dans une seule matrice. Comment une requête récupère-t-elle LA valeur qui la concerne sans parcourir de liste — puisqu’il n’y a plus de liste du tout ?

L’idée — Lecture de l’état

La lecture est une multiplication : y = qᵀS. La requête q=[1,0] sélectionne la ligne 1 et lit [2,3] exactement ; q=[0,1] lit [5,1]. Rien n’est parcouru : une seule opération, quelle que soit la longueur du passé.

y=qᵀS

Pourquoi / à quel prix — Lecture de l’état

Lecture O(1) contre O(n) pour le cache KV : le gain est structurel. Le prix : y est toujours une combinaison de tout ce qui a été écrit, pondérée par q·k. Elle n’est exacte que si les clés sont orthogonales — la lecture ne distingue pas « valeur stockée » et « mélange ».

Contrôle : Après les deux écritures orthogonales, prédisez y pour q=[1,1] AVANT de calculer, puis vérifiez. Le résultat correspond-il à une valeur réellement stockée, et qu’est-ce que cela vous apprend sur ce que « lire » veut dire ici ?

Le problème — Mémoire fixe

Un cache KV à 100 000 tokens explose la facture mémoire d’un service — et il croît encore au token suivant. Peut-on servir un long contexte avec une mémoire dont la taille ne dépend pas de la longueur ?

L’idée — Mémoire fixe

S mesure d_k × d_v, point : 1 000 ou 100 000 tokens écrits, la matrice garde la même taille. La croissance O(n) du cache devient une constante — au prix d’un résumé superposé à la place d’une trace exacte.

Pourquoi / à quel prix — Mémoire fixe

Le budget mémoire devient prévisible — précisément ce qui se facture en production. Le prix : la capacité informationnelle est constante elle aussi ; au-delà d’environ d_k directions de clés distinctes, les écritures se superposent. « Taille fixe » signifie aussi « capacité fixe », jamais contexte infini.

Contrôle : La séquence passe de 1 000 à 100 000 tokens. Qu’arrive-t-il à la taille de S, qu’arrive-t-il à celle d’un cache KV, et laquelle des deux quantités apparaît dans la facture mémoire d’un service en production ?

Support visuel — Mémoire fixe

une couche, une tête, d = 128, BF16

              cache KV (2·d·2 o/token)      état S (d×d×2 o)
  1 000 t     500 Kio   ██                  32 Kio  ▏
100 000 t     ≈ 49 Mio  ████████████        32 Kio  ▏  (inchangé)

le cache paie chaque token ; S ne paie qu’une fois

Le problème — Interférence

Troisième écriture : k=[1,0] resservi avec v=[9,9]. La lecture q=[1,0] rend [11,12] — ni l’ancienne valeur ni la nouvelle. Qui a écrasé quoi ? Personne : les deux écritures cohabitent, fusionnées. Que faire d’une mémoire qui ne sait plus distinguer ?

L’idée — Interférence

L’interférence est arithmétique, pas aléatoire : la ligne 1 de S contient [2,3] + [9,9] = [11,12], et la lecture restitue exactement cette somme. Des clés proches écrivent dans des directions partagées ; leurs valeurs se mélangent au prorata de l’alignement.

Pourquoi / à quel prix — Interférence

La voir comme une somme la rend prévisible et mesurable — un test de rappel contrôlé suffit à la détecter. Le prix demeure : sans correction ni oubli, une mémoire additive dérive avec la longueur. C’est exactement le problème que la règle delta de la session 14 attaque.

Contrôle : La troisième écriture réutilise k=[1,0] et la lecture rend [11,12] au lieu de [2,3] ou [9,9]. Nommez précisément la quantité perdue, puis proposez une mesure qui détecterait cette interférence en production sans inspecter S.

Cas guidé — trace complète

Avec S nul, k=[1,0] et v=[2,3], l’écriture donne [[2,3],[0,0]]. Une requête q=[1,0] lit [2,3]. Tenter d’ajouter une clé [1,0,2] de dimension 3 révèle aussi pourquoi les contrôles de forme sont obligatoires.

S = [[0,0],      état initial (2×2), vide
     [0,0]]

écriture 1 : k=[1,0]  v=[2,3]
  k vᵀ = [[1*2, 1*3],   = [[2,3],
          [0*2, 0*3]]      [0,0]]
  S    = [[2,3],[0,0]]

écriture 2 : k=[0,1]  v=[5,1]      clé ORTHOGONALE
  S    = [[2,3],[5,1]]

lecture q=[1,0] :  y = qᵀS = [2,3]   ✅ valeur 1 récupérée exactement
lecture q=[0,1] :  y = qᵀS = [5,1]   ✅ valeur 2 récupérée exactement

écriture 3 : k=[1,0]  v=[9,9]      clé RÉUTILISÉE → collision
  S    = [[11,12],[5,1]]
lecture q=[1,0] :  y = [11,12]       ❌ ni [2,3] ni [9,9] : superposition

CONTRÔLE DE FORME : k(2) vᵀ(2) → S(2×2). Une clé [1,0,2] (3) est refusée.

Cache KV exact contre état matriciel fixe

Critère Cache KV État S (attention linéaire)
Mémoire pour n tokens croît en O(n) constante, d_k × d_v
Rappel d’un token isolé exact approché, sujet à interférence
Coût par nouveau token O(n) (relit tout) O(1) (une mise à jour)
Point de rupture mémoire saturée en long contexte clés proches → valeurs mélangées

Laboratoire causal

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

/interactives/curriculum/linear-delta-memory.html?lang=fr

Erreurs fréquentes

« Mémoire de taille fixe = contexte infini. »

La taille de S est constante, donc sa capacité informationnelle l’est aussi : au-delà, les écritures se superposent au lieu de s’ajouter proprement. La trace le montre dès la troisième écriture, où [2,3] et [9,9] fusionnent en [11,12]. Un contexte long n’est pas un contexte conservé : S accepte toujours d’écrire, même quand il ne peut plus distinguer.

« La lecture qᵀS rend la valeur qui a été écrite. »

Seulement si les clés sont orthogonales — c’est le cas des deux premières écritures, et c’est pour cela qu’elles se relisent exactement. Avec des clés proches ou réutilisées, la lecture rend une combinaison pondérée : c’est la définition même de l’interférence, pas un bug d’implémentation. La question utile n’est donc jamais « la valeur est-elle là ? » mais « les clés sont-elles assez séparées ? ».

Frontière, preuve et sources

Mémoire fixe ne signifie ni mémoire parfaite ni contexte infini : capacité et interférence restent bornées.

Statut de preuve : Mécanismes établis ; les simplifications numériques sont pédagogiques.

  • Dossier de cours bilingue fourni par le propriétaire, chapitre 8.
  • Katharopoulos et al., “Transformers are RNNs: Fast Autoregressive Transformers with Linear Attention”, ICML (2020).
  • 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

Reprenez la trace en dimension 3 : k₁=[1;0;0], v₁=[2,3], k₂=[0;1;0], v₂=[5,1], puis une troisième écriture k₃=[0,7;0,7;0], v₃=[4,0].

  1. Donnez la nouvelle forme de S et justifiez-la.
  2. Prédisez quelle lecture (q=k₁ ou q=k₂) se dégrade, puis calculez les deux.
  3. Énoncez la règle générale : quand une écriture supplémentaire est-elle « gratuite » ?

Synthèse et ticket de sortie

  • Fondations matricielles
  • Produit scalaire
  • Produit extérieur
  • Lecture de l’état
  • Mémoire fixe
  • Interférence

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 l’anecdote du broadcasting silencieux : un (3,) contre une (2,2) refuse, mais certaines formes fausses « marchent » et font n’importe quoi. Demander qui a déjà perdu une heure là-dessus — les mains levées installent le réflexe mieux qu’une règle.

Notes formateur: Faire écrire les dimensions au tableau avant toute opération. Refuser explicitement une multiplication incompatible devant le groupe : c’est le réflexe qui sauve les séances 14 à 18, où les formes deviennent plus difficiles à suivre de tête. Demander systématiquement « quelle forme entre, quelle forme sort ? ».

Notes formateur: Réponse : k vᵀ (et qᵀS) échoue — k a 3 composantes contre 2 lignes de S ; on corrige d’abord d_k, la projection qui produit k. Le contrôle précède le calcul parce qu’une forme fausse peut s’exécuter par broadcasting et corrompre l’aval sans erreur. Erreur attendue : « on tronque k à deux composantes ».

Notes formateur: Question d’accroche : « une mémoire sans adresses, à quoi ça ressemble ? ». Réponse visée : à une pile où tout se mélange. Garder cette image au tableau — l’interférence du dernier beat la recyclera telle quelle.

Notes formateur: Demander le signe du produit scalaire avant tout calcul. Deux vecteurs orthogonaux donnent zéro, et c’est ce zéro qui rend l’adressage possible : sans lui, chaque requête lirait toutes les écritures. Faire formuler cette conséquence par un apprenant plutôt que l’annoncer.

Notes formateur: Réponse : l’écriture posée sur k=[0,1] est invisible pour q=[1,0] — contribution nulle. Ce zéro est recherché : il isole les adresses. Si toutes les clés étaient identiques, chaque lecture rendrait la somme de toutes les valeurs — une mémoire à une seule case. Erreur attendue : « q·k = 0 est un bug ».

Notes formateur: Faire placer q=[1,1] sur le dessin : il est à 45° des deux axes, donc il lit les deux lignes à parts égales. La géométrie annonce le résultat [7,4] du contrôle suivant avant tout calcul.

Notes formateur: Faire dessiner une matrice vide 2×2 et demander : « où ranger [2,3] pour que q=[1,0] la retrouve ? ». Les propositions spontanées (case (1,1) ? diagonale ?) font sentir le besoin d’une règle — k vᵀ EST cette règle.

Notes formateur: Beaucoup confondent produit scalaire et produit extérieur. Faire nommer la forme de sortie de chacun — un scalaire contre une matrice — avant de continuer, et écrire les deux côte à côte au tableau. La confusion non traitée ici réapparaît systématiquement en session 14 sur la règle delta.

Notes formateur: Réponse : k vᵀ = [[0,0],[5,1]] ; la ligne 2 change (k₂ = 1), la ligne 1 reste intacte (k₁ = 0) — la localisation vient des zéros de k. Erreur attendue : transposer et poser [5,1] en colonne ; faire vérifier la forme 2×2 au tableau.

Notes formateur: Faire remplir les quatre cases une par une avec la règle kᵢ × vⱼ avant de montrer le résultat. La ligne de zéros doit venir d’eux : c’est elle qui rend l’écriture « adressée ».

Notes formateur: Demander d’abord : « combien d’opérations pour lire dans une liste de 100 000 entrées ? » puis « et dans une matrice ? ». Le contraste O(n)/O(1) doit précéder la formule, pas l’illustrer après coup.

Notes formateur: Masquer le résultat et faire prédire y à main levée. L’erreur classique consiste à attendre la dernière valeur écrite plutôt que la somme que la requête reconstruit. Recueillir une prédiction fausse et la réparer publiquement vaut mieux que dérouler le calcul juste.

Notes formateur: Réponse : y = [7,4] = [2,3] + [5,1] — aucune des valeurs stockées. « Lire » signifie combiner au prorata de q·k, pas retrouver. Erreur attendue : prédire [5,1], la dernière écriture — c’est exactement l’erreur que la prédiction à main levée doit faire émerger.

Notes formateur: Faire estimer la mémoire d’un cache KV à 100 000 tokens avant d’afficher le support visuel. Les estimations s’étalent typiquement sur trois ordres de grandeur — c’est précisément le symptôme que cette session soigne.

Notes formateur: Relier au coût produit : faire calculer la mémoire d’un cache KV à 100 000 tokens, puis la comparer à celle de S, inchangée. Le contraste chiffré porte toute la séance et prépare la session 18. Ne pas donner le résultat : le faire produire.

Notes formateur: Réponse : S reste à d_k × d_v ; le cache KV est multiplié par 100 (O(n)) ; c’est le cache qui apparaît sur la facture — voir le support visuel : 500 Kio → ≈ 49 Mio par tête et par couche, quand S reste à 32 Kio. Erreur attendue : « S grandit aussi, un peu ».

Notes formateur: Faire refaire les deux multiplications à la calculatrice : 2×128×2×100 000 contre 128×128×2. Puis annoncer que la session 18 refera ce calcul à l’échelle d’un vrai modèle (32 couches, 8 têtes) — mêmes formules, facteurs en plus.

Notes formateur: Rejouer la lecture [11,12] et demander : « qui a bugué ? ». Réponse visée : personne — l’addition a fait exactement son travail. Le malaise de cette réponse est le point d’entrée du beat ; ne pas le désamorcer trop vite.

Notes formateur: Faire construire un cas d’interférence par les apprenants eux-mêmes, en choisissant leurs propres clés proches. Une collision qu’ils ont fabriquée se retient bien mieux qu’une collision montrée, et rend la notion de « clés assez séparées » concrète avant les portes de la session 16.

Notes formateur: Réponse : la quantité perdue est la distinction entre les deux écritures — la somme est exacte, l’attribution est perdue. Mesure de production : un test de rappel contrôlé (insérer des paires clé→valeur connues, mesurer le taux de restitution exacte selon longueur et similarité des clés). Erreur attendue : proposer d’inspecter S, illisible en pratique.

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 : S devient 3×2 (d_k = 3, d_v = 2). Les DEUX lectures se dégradent — q=k₁ lit [4,8 ; 3] au lieu de [2,3] et q=k₂ lit [7,8 ; 1] au lieu de [5,1] : k₃ chevauche les deux adresses et y dépose 0,7 × [4,0] = [2,8 ; 0]. Règle : une écriture est gratuite si et seulement si sa clé est orthogonale à toutes les clés qu’on voudra encore relire. Idée fausse attendue : « seule la lecture la plus proche est touchée ». 10 minutes, binômes.

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é.