Visualisation de l’attention : au cœur du Transformer [vidéo]
(3blue1brown.com)- L’attention d’un Transformer est un mécanisme qui met à jour les embeddings de tokens en fonction du contexte, de sorte qu’un même mot se déplace vers un vecteur de sens différent selon les mots qui l’entourent
- Une tête d’attention crée pour chaque token des vecteurs query/key/value, puis calcule un attention pattern, c’est-à-dire des poids de pertinence entre mots, via le produit scalaire key-query et un softmax
- Un modèle autorégressif de type GPT applique un masking pour empêcher les tokens suivants d’influencer les précédents, et comme la taille de l’attention pattern croît avec le carré de la longueur du contexte, l’extension d’une grande context window devient coûteuse
- Dans l’exemple de GPT-3, les matrices key/query possèdent chacune 1 572 864 paramètres, et la value map est décomposée en une transformation de faible rang, pour arriver à environ 6,3 millions de paramètres par tête
- Un Transformer qui répète plusieurs têtes et blocs d’attention apprend différentes façons de mettre à jour le contexte, et une grande part de son succès vient de la capacité de parallélisation qui permet d’exécuter rapidement beaucoup de calculs sur GPU
Le rôle de l’attention dans un Transformer
- Un Transformer utilise le texte d’entrée pour prédire le token suivant, et l’entrée est d’abord tokenisée en mots ou fragments de mots
- Chaque token est converti en embedding, un vecteur de grande dimension
- Les directions dans cet espace d’embedding peuvent correspondre à des significations
- Par exemple, un déplacement dans une certaine direction peut transformer l’embedding d’un nom masculin en celui du nom féminin correspondant
- Le but de l’attention est d’ajuster progressivement les embeddings initiaux pour qu’ils contiennent non seulement l’information propre à chaque mot, mais aussi un sens contextuel plus riche
Pourquoi un même mot change selon le contexte
- Dans “American shrew mole”, “One mole of carbon dioxide” et “Take a biopsy of the mole”, mole a des sens différents
- À l’étape initiale d’embedding, le vecteur de mole est identique dans les trois cas, car il ressemble à une lookup table qui ne tient pas compte du contexte
- À l’étape suivante, le bloc d’attention, les embeddings voisins peuvent transmettre de l’information à l’embedding de mole pour le mettre à jour
- Un modèle bien entraîné relie les différents sens de mole à des directions distinctes dans l’espace d’embedding, puis calcule quoi ajouter à l’embedding générique selon le contexte
- Comme dans “Eiffel tower” et “miniature Eiffel tower”, l’embedding d’un mot peut être mis à jour non seulement par des mots proches, mais aussi par des tokens plus éloignés
- Comme seule la dernière représentation vectorielle sert à prédire le mot suivant, l’embedding du dernier mot d’une longue entrée doit contenir, dans une certaine mesure, l’ensemble du contexte nécessaire à la prédiction
Le déroulement du calcul dans une seule tête d’attention
- L’explication de base prend comme référence une single head of attention
- Avec la phrase d’exemple “A fluffy blue creature roamed the verdant forest.”, on suppose que les adjectifs mettent à jour l’embedding initial du nom correspondant
- Cet exemple sert à illustrer le type d’opération qu’une tête d’attention peut effectuer
- En pratique, le comportement réel d’une tête est difficile à interpréter, car il résulte de nombreux paramètres ajustés pour réduire la fonction de coût
- Les embeddings initiaux contiennent non seulement l’information sur les mots, mais aussi l’information de position, et sont notés
\vec{E} - L’objectif est de produire un nouvel embedding
\vec{E}'qui reflète le contexte à partir de l’embedding existant -
Query
- À la première étape, on multiplie l’embedding de chaque token par la matrice query
W_Qpour produire un vecteur query\vec{Q} - On peut voir cela comme un nom qui pose la question : « y a-t-il un adjectif devant moi ? »
- Les éléments de
W_Qsont des paramètres appris par le modèle, et il est difficile d’interpréter exactement ce que fait une tête donnée - Dans l’exemple, on peut imaginer qu’elle projette les embeddings de noms dans une direction « recherche d’un adjectif situé avant »
- À la première étape, on multiplie l’embedding de chaque token par la matrice query
-
Key
- En parallèle, on multiplie chaque embedding par la matrice key
W_kpour produire un vecteur key\vec{K} - La key peut être vue comme une réponse potentielle à la query, dans un espace de plus petite dimension identique à celui de la query
- Le degré d’alignement entre key et query se mesure par le produit scalaire
- Plus le produit scalaire est grand, plus les deux vecteurs sont fortement alignés
- Si les keys de fluffy et blue correspondent bien à la query de creature, elles prennent une grande valeur positive
- En calculant le produit scalaire pour toutes les paires key-query, on obtient une grille de scores qui indique dans quelle mesure un mot est pertinent pour mettre à jour le sens d’un autre mot
- En parallèle, on multiplie chaque embedding par la matrice key
Attention pattern et softmax
- Comme les scores de produit scalaire peuvent aller de
-\inftyà\infty, on applique un softmax à chaque colonne pour les normaliser entre 0 et 1 - Cette grille normalisée est appelée attention pattern
- Chaque colonne peut être vue comme un ensemble de poids indiquant à quel point le mot de gauche est pertinent pour mettre à jour le mot du haut
- L’article original sur le Transformer note cela de manière plus compacte
QetKreprésentent les tableaux complets de vecteurs query et keyK^TQreprésente la grille de tous les produits scalaires key-query possibles- Dans la notation de l’article, query et key sont placés sur les lignes et l’expression s’écrit sous la forme
QK^T, ce qui donne une version inversée en diagonale par rapport au schéma expliqué ici
- Pour la stabilité numérique, on ajoute une division par
\sqrt{d_k}, soit la racine carrée de la dimension de l’espace key-query - Le softmax entoure l’expression entière, mais conceptuellement il est appliqué colonne par colonne
Masking et contraintes de taille de contexte
- Pendant l’entraînement, le modèle ne prédit pas seulement un unique token suivant pour un texte donné, mais aussi simultanément les prochains tokens possibles après chaque sous-séquence
- Un exemple de texte agit ainsi comme plusieurs exemples d’entraînement, ce qui améliore l’efficacité
- Dans l’exemple GPT, si les tokens ultérieurs pouvaient influencer les précédents, cela révélerait la bonne réponse pour la prédiction du token suivant, d’où l’usage du masking
- Avant le softmax, les valeurs de ces positions sont fixées à l’infini négatif
- Après le softmax, ces positions deviennent 0 et la colonne reste correctement normalisée
- Toute l’attention n’utilise pas forcément un masking permanent, mais dans l’exemple GPT il est toujours appliqué pour empêcher les tokens suivants d’influencer les précédents
- La taille de l’attention pattern est égale au carré de la taille du contexte
- C’est pourquoi la taille du contexte peut devenir une limite importante des grands modèles de langage
- Des variantes ont été proposées pour rendre le mécanisme d’attention plus scalable avec de plus grandes context windows, mais ici on ne traite que de la forme de base
Comment les embeddings sont réellement mis à jour via Value
- L’attention pattern fournit les poids indiquant quels mots doivent mettre à jour quels autres, et l’étape suivante consiste à produire la variation effective de l’embedding
- On multiplie chaque embedding par la matrice value
W_Vpour produire un vecteur value- Les vecteurs value vivent dans le même espace de grande dimension que les embeddings
- Ils représentent la modification concrète à ajouter quand un mot pertinent ajuste le sens d’un autre mot
- Dans chaque colonne, on multiplie les vecteurs value par les poids correspondants de l’attention pattern, puis on les additionne pour obtenir la variation
\Delta \vec{E} - En ajoutant cette variation à l’embedding d’origine, on obtient un nouvel embedding
\vec{E}'qui reflète le contexte- Dans l’exemple, creature absorbe l’information de fluffy et blue pour porter un sens plus proche de “fluffy blue creature”
- En appliquant le même processus à toutes les colonnes, on obtient en sortie du bloc d’attention des embeddings raffinés pour toute la séquence de tokens
- Une seule tête d’attention est paramétrée par trois types de matrices de paramètres appris : matrice key, matrice query et matrice value
Calcul des paramètres dans le cas de GPT-3
- Dans l’exemple GPT-3, les matrices key et query ont chacune 12 288 colonnes, correspondant à la dimension d’embedding, et 128 lignes, correspondant à la dimension de l’espace key-query
- Chaque matrice contient 1 572 864 paramètres
- Si la matrice value était une matrice carrée 12 288×12 288, cela ajouterait 150 994 944 paramètres, soit bien plus que key/query
- En pratique, il est plus efficace de décomposer la value map en deux matrices plus petites afin d’obtenir un nombre de paramètres comparable à celui de key/query
- La première matrice projette le grand espace d’embedding vers un espace plus petit, par exemple de dimension 128
- La seconde remonte ensuite de ce petit espace vers l’espace d’embedding
- Du point de vue de l’algèbre linéaire, cela revient à restreindre la value map globale à une transformation de faible rang
- Dans cette explication, ces deux matrices sont appelées
Value_\downarrowetValue_\uparrow, mais ce ne sont pas des noms conventionnels - En additionnant les quatre matrices, une tête d’attention totalise environ 6,3 millions de paramètres
Self-attention et cross-attention
- La structure décrite jusqu’ici correspond plus précisément à une tête de self-attention
- Une tête de cross-attention apparaît dans les modèles qui traitent deux ensembles de données différents
- Par exemple, dans un modèle de traduction, les keys peuvent venir d’une langue et les queries d’une autre
- L’attention pattern peut alors représenter la façon dont les mots d’une langue correspondent à ceux de l’autre
- En cross-attention, la différence avec la self-attention est que les projections key et query s’appliquent à des jeux de données différents
- Dans une configuration comme la traduction, il n’y a généralement pas de notion selon laquelle les tokens suivants influencent les précédents, donc il n’y a en général pas de masking
Multi-headed attention et répétition des blocs
- En pratique, un bloc d’attention est composé de plusieurs têtes exécutées en parallèle : c’est la multi-headed attention
- GPT-3 utilise 96 têtes d’attention dans chaque bloc
- 96 matrices key/query différentes produisent 96 attention patterns différents
- Chaque tête génère sa propre séquence de vecteurs value via sa propre matrice value
- À chaque position de token, on additionne les variations
\Delta \vec{E}proposées par toutes les têtes puis on les ajoute à l’embedding d’origine
- L’exécution parallèle de plusieurs têtes donne au modèle la capacité d’apprendre plusieurs façons dont le contexte peut modifier le sens
- Dans le cas de GPT-3, un bloc de multi-headed attention comportant 96 têtes contient environ 600 millions de paramètres
- Dans les articles et les implémentations réelles, les matrices correspondant au
Value_\uparrowde chaque tête sont regroupées en une grande output matrix reliée à l’ensemble du bloc de multi-headed attention- Quand on parle habituellement de la matrice value d’une tête donnée, on désigne souvent ici la première étape de projection appelée
Value_\downarrow
- Quand on parle habituellement de la matrice value d’une tête donnée, on désigne souvent ici la première étape de projection appelée
Comment le sens s’accumule dans un Transformer plus profond
- Les données à l’intérieur d’un Transformer ne traversent pas un seul bloc d’attention, mais plusieurs blocs d’attention ainsi que des multi-layer perceptron
- Même après qu’un embedding de mot a déjà absorbé une partie du contexte, il continue d’avoir des occasions d’être influencé par des embeddings voisins devenus plus raffinés
- À mesure que le réseau gagne en profondeur, chaque embedding peut intégrer davantage de sens provenant d’autres embeddings, avec la capacité d’encoder des caractéristiques abstraites de plus haut niveau comme le sentiment, le ton ou le fait qu’un texte soit cynique
- GPT-3 comprend 96 couches, et les paramètres liés à key/query/value sont décrits comme étant au total inférieurs à 58 milliards
- Cela représente environ un tiers des paramètres du réseau entier, le reste provenant majoritairement des blocs situés entre les mécanismes d’attention
- Une grande partie du succès du mécanisme d’attention ne vient pas d’un comportement particulier, mais de sa forte capacité de parallélisation, qui permet d’exécuter de nombreux calculs en peu de temps sur GPU
- Comme, en deep learning, l’augmentation d’échelle peut apporter des améliorations qualitatives importantes des performances, une architecture parallélisable qui permet cette montée en charge bénéficie d’un avantage majeur
1 commentaires
Avis sur Hacker News
Ayant travaillé en chimie quantique et un peu en machine learning, j’ai trouvé en regardant cette vidéo que les similarités entre les modèles Transformer et la mécanique quantique sautaient assez aux yeux
En mécanique quantique, l’état d’un système physique complet est encodé comme un vecteur normalisé de très grande dimension, c’est-à-dire une demi-droite de l’espace de Hilbert, et son évolution dans le temps est assurée par un opérateur de décalage temporel qu’on peut voir grossièrement comme une matrice unitaire U = exp(-iHt)
Dans la vidéo, on explique que la prédiction du token suivant est déterminée en calculant le vecteur d’embedding contextuel suivant à partir du seul dernier vecteur d’embedding contextuel, ce qui ressemble au résultat de l’application d’une fonction d’état linéaire à un vecteur de grande dimension
Cela donne l’impression de générer hors ligne le Hamiltonien du système complet à partir des données d’entraînement, puis de reparamétrer un sous-système particulier, la fenêtre de contexte, dans une base adaptée à ce Hamiltonien, d’appliquer un pas d’évolution temporelle, puis de revenir à la base d’origine
Cela dit, quand on travaille dans un domaine particulier, on a tendance à voir tous les problèmes comme des clous pour le marteau de ce domaine ; je me demande donc si cette similarité parle aussi à d’autres, ou si c’est vraiment tiré par les cheveux
Si une application de l’opérateur faisait avancer l’état de l’univers d’un temps de Planck, je me demande si on pourrait observer une différence entre un tel univers et un univers où le temps est continu
Le lien avec ce qui se passait alors en physique ne m’est venu à l’esprit que maintenant
La vidéo YouTube de CodeEmporium était plus facile à suivre : https://www.youtube.com/watch?v=Nw_PJdmydZY
Les transformers sont difficiles à expliquer par analogie et, en réalité, il n’existe pas vraiment de bonne explication de pourquoi ils marchent ; il vaut peut-être mieux simplement montrer le mécanisme et laisser l’interprétation au spectateur
De plus, il est plus simple d’expliquer le produit scalaire comme la projection de vecteurs les uns sur les autres
Si « the cat sat on the ... » est suivi de « mat », c’est parce que c’est le mot qui apparaît le plus souvent ensuite dans le jeu de données, et le réseau de neurones est un modèle de ces fréquences
Si le modèle semble connaître « London in UK » mais pas « London in France », c’est aussi parce que « UK » apparaît bien plus souvent dans le jeu de données
L’algorithme lui-même ne fait rien de particulièrement intéressant en dehors du fait d’aligner le calcul sur le matériel. La valeur vient de la structure de probabilité conditionnelle contenue dans les données, structure qui résulte du fait que les humains arrangent les mots de manière utile pour se transmettre de l’information
C’est une explication incomplète, mais je pense que c’est mieux que rien
Il existe une visualisation convaincante de la manière dont un LLM fonctionne pour traiter des requêtes simples : https://bbycroft.net/llm
Cela complète bien l’explication détaillée de 3blue1brown
Excellente vidéo. Elle montre bien pourquoi la multiplication matricielle Q*K est le goulet d’étranglement. Si la longueur de la séquence, c’est-à-dire de la fenêtre de contexte, est S, il faut stocker en mémoire une matrice SxS contenant le résultat de toutes les query contre toutes les key
Il existe une idée relativement récente pour améliorer ce goulet d’étranglement, Ring Attention, et cet article l’explique bien : https://learnandburn.ai/p/how-to-build-a-10m-token-context
J’ai édité cet article
Chez Unsloth, grâce à Flash Attention, l’usage mémoire croît linéairement au lieu d’être quadratique, le fine-tuning est 2 fois plus rapide, l’usage de VRAM baisse de 80 % et l’inférence est aussi 2 fois plus rapide. En revanche, la quantité de calcul reste en O(N^2)
Pour les contextes longs, la dernière release d’Unsloth peut gérer des contextes 4 fois plus longs que HF+FA2 avec seulement +1,9 % d’overhead, jusqu’à 228K de contexte sur H100
L’article précédent, « But what is a GPT? », est lui aussi vraiment excellent : https://www.3blue1brown.com/lessons/gpt
Grâce à cette vidéo, j’ai compris que le mécanisme d’attention est moins une fonction précise qu’une sorte de méta-fonction.
Si j’ai bien compris, l’attention + les poids appris permettent au transformeur d’apprendre une fonction en partie arbitraire, qui inclut un mécanisme d’appariement comme le scaled dot-product.
C’est pourquoi je pense que l’attention linéaire aura du mal à s’approcher des capacités de l’attention standard. Le terme quadratique, qui explore toutes les paires entrée-sortie, en est une caractéristique essentielle.
Si cette vidéo était facile à assimiler, c’est en grande partie grâce aux animations. La façon dont elles se déploient, se contractent et s’étendent au rythme des explications est vraiment très réussie.
Je travaille dans un domaine étroitement lié, et cette vidéo a été ajoutée immédiatement à la documentation d’onboarding de notre équipe.
Le fait qu’une bonne partie du code de visualisation soit disponible sur GitHub est aussi important : https://github.com/3b1b/videos/tree/master/_2024/transformers
J’ai enfin compris. Je ne sais pas pourquoi les autres vidéos rendaient ça si confus.
Ça me fait penser que les aptitudes pédagogiques et les aptitudes de recherche sont, en général, presque des compétences mutuellement exclusives.
Premièrement, la terminologie standard n’est pas bonne. “attention” est à peine intuitif, “self-attention” est encore pire, et ne parlons même pas de “key” et “value”.
Deuxièmement, les articles fondamentaux comme Attention is All You Need, l’article sur BERT, etc., ne sont pas particulièrement bien écrits. Ce n’est pas pour minimiser leurs résultats, mais un article influent qui contient une percée majeure peut malgré tout très mal expliquer les choses, et je pense que c’était le cas ici.
Troisièmement, ces architectures ont globalement été découvertes en essayant diverses choses et en voyant ce qui marchait bien ensemble. Il n’y a pas d’abord eu un processus de réflexion menant à la prédiction qu’une telle architecture fonctionnerait bien, ensuite validé par l’expérience ; le processus a été empirique du début à la fin.
Du coup, on ne comprend pas complètement pourquoi cela fonctionne si bien, toutes les explications relèvent un peu de la rationalisation a posteriori, et des travaux récents suggèrent aussi qu’avec suffisamment d’ajustements, d’autres architectures pourraient fonctionner presque aussi bien. Il est difficile d’expliquer clairement quelque chose qu’on ne comprend pas entièrement.
Je me demande s’il existe une ressource qui explique comment l’architecture actuelle a évolué. J’aimerais voir le cheminement depuis une idée centrale très simple jusqu’au célèbre article “all you need”.
Sinon, beaucoup d’éléments donnent l’impression d’apparaître de nulle part, avec beaucoup de calcul mais peu d’intuition.
Jeremy Howard a dit sur Twitter qu’il avait vu de nombreuses variantes de cette idée à plusieurs reprises, ce qui donne l’impression qu’elle était assez naturelle. Voir des exemples de la manière dont cette idée est apparue ailleurs aiderait sans doute à construire l’intuition.
Cette approche RNN/LSTM avait deux faiblesses : la représentation de taille fixe, et la difficulté à décider quelles parties de la séquence d’entrée utiliser lors de la génération d’une partie donnée de la sortie. Bahdanau et d’autres ont résolu cela avec une architecture RNN encodeur-décodeur couplée à un mécanisme d’attention, permettant d’accéder non seulement à l’état final, mais à tous les états passés du RNN.
Les RNN étaient inefficaces à entraîner, donc Jakob Uszkoreit a cherché un moyen de mieux exploiter le matériel massivement parallèle, tout en remarquant que le langage n’est pas seulement séquentiel, mais aussi hiérarchique. Il a proposé une architecture en couches où, à chaque niveau, les tokens d’une sous-séquence sont traités en parallèle, tout en conservant une attention de type Bahdanau pour prédire la couche suivante via une self-attention où les tokens se réfèrent les uns aux autres.
Les premières implémentations fonctionnaient, mais n’étaient pas meilleures que d’autres approches de l’époque, comme les convolutions. Ensuite, Noam Shazeer a fait évoluer l’idée vers une architecture bien plus efficace et, après des expériences visant à retirer les composants inutiles, on est arrivé au transformeur d’origine. Je ne sais pas exactement qui a conçu la forme finale de l’attention fondée sur les key.
Le transformeur original de l’article Attention is All You Need reprenait l’approche RNN antérieure avec un encodeur et un décodeur séparés, et il a aussi été utilisé dans les premiers modèles comme BERT de Google. Mais pour les modèles de langage, ce n’est pas indispensable, donc le GPT d’OpenAI n’a utilisé que la partie décodeur, et aujourd’hui c’est globalement cette approche que tout le monde suit. Dans un transformeur décodeur-only, la phrase d’entrée entre dans la couche la plus basse, puis elle est transformée étape par étape en traversant les couches successives pour ressortir en haut. Un token de fin est ajouté à la fin de la séquence d’entrée, et il est transformé en le token suivant de la séquence de sortie, c’est-à-dire le dernier token.