Le calcul qui permet à chaque mot d'une phrase de regarder tous les autres et de décider lesquels comptent pour le comprendre. Dans « le colis est arrivé mais il était abîmé », c'est lui qui relie « il » à « colis ». C'est la brique centrale des Transformers, donc de la quasi-totalité des LLM actuels.
Dans une réunion, chaque participant écoute tout le monde mais retient surtout ceux qui parlent de son sujet. Chaque mot fait pareil avec les autres mots de la phrase.
Chaque mot est un vecteur. Le modèle en tire trois versions : une requête (ce que je cherche), une clé (ce que je contiens) et une valeur (ce que je transmets).
On compare la requête d'un mot à la clé de tous les autres par produit scalaire, divisé par la racine de la dimension. Une fonction softmax transforme ces scores en poids positifs qui somment à 1.
Le nouveau vecteur d'un mot est la moyenne des valeurs de tous les mots, lui compris, pondérée par ces poids. « il » absorbe ainsi une bonne part du sens de « colis ».
« Le colis est arrivé mais il était abîmé. » Huit mots, chacun représenté par un vecteur de 32 nombres. Les vecteurs sont simulés : celui de « il » est placé près de celui de « colis », comme le ferait un modèle entraîné.
Une ligne par mot, une colonne par mot regardé, chaque ligne somme à 1. Dans la sortie Python, « il » répartit son attention entre lui-même (0,52) et « colis » (0,39), presque rien ailleurs. C'est ce qui permet à un LLM de savoir que c'est le colis qui est abîmé.
Il n'y a pas de métrique propre à l'attention : on juge le modèle complet sur sa tâche (classement, résumé, extraction). Les poids d'attention servent à inspecter, pas à prouver. Plusieurs travaux montrent qu'ils ne suffisent pas à expliquer une décision.
L'attention se paramètre au sein d'une architecture. Noms donnés pour PyTorch (nn.MultiheadAttention) et Keras (MultiHeadAttention).
Plusieurs attentions en parallèle, chacune avec ses propres projections : une tête peut suivre la syntaxe, une autre les références. 8 à 16 têtes sont courantes.
La taille des vecteurs de requête et de clé. Plus grande, plus expressive, plus coûteuse. D'où la division par la racine de la dimension, qui évite des softmax trop tranchés.
Pour générer du texte, chaque mot ne doit voir que les mots précédents. Un masque met à zéro l'attention vers le futur. C'est la différence entre un modèle de type GPT et un modèle de type BERT.
Le nombre de jetons que le modèle regarde à la fois. Doubler la longueur multiplie environ par quatre le coût de l'attention.
# Lecture d'une réclamation : mécanisme d'attention en R
set.seed(42)
mots <- c("le", "colis", "est", "arrivé", "mais", "il", "était", "abîmé")
d <- 32
# Vecteurs de mots simulés ; « il » est placé près de « colis », comme après entraînement
X <- matrix(rnorm(length(mots) * d), nrow = length(mots), dimnames = list(mots, NULL))
X["il", ] <- X["colis", ] + 0.3 * rnorm(d)
# Requêtes, clés, valeurs : projections apprises dans un vrai modèle, identité ici
Q <- X
K <- X
V <- X
# Score de chaque paire de mots, divisé par racine de d, puis softmax ligne par ligne
scores <- Q %*% t(K) / sqrt(d)
poids <- exp(scores - apply(scores, 1, max))
poids <- poids / rowSums(poids)
sortie <- poids %*% V # chaque mot devient un mélange pondéré de tous les mots
print(round(poids, 2))
print(sort(round(poids["il", ], 2), decreasing = TRUE)[1:3])
cat("Dimension de la sortie :", dim(sortie), "\n")
# Lecture d'une réclamation : mécanisme d'attention en Python
import numpy as np
import pandas as pd
rng = np.random.default_rng(42)
mots = ["le", "colis", "est", "arrivé", "mais", "il", "était", "abîmé"]
d = 32
# Vecteurs de mots simulés ; « il » est placé près de « colis », comme après entraînement
X = rng.normal(size=(len(mots), d))
X[5] = X[1] + 0.3 * rng.normal(size=d)
# Requêtes, clés, valeurs : projections apprises dans un vrai modèle, identité ici pour la lisibilité
Q, K, V = X, X, X
# Score de chaque paire de mots, divisé par racine de d, puis softmax ligne par ligne
scores = Q @ K.T / np.sqrt(d)
poids = np.exp(scores - scores.max(axis=1, keepdims=True))
poids = poids / poids.sum(axis=1, keepdims=True)
sortie = poids @ V # chaque mot devient un mélange pondéré de tous les mots
print(pd.DataFrame(poids, index=mots, columns=mots).round(2))
print("Attention de « il » :", pd.Series(poids[5], index=mots).round(2).sort_values(ascending=False).head(3).to_dict())
print("Dimension de la sortie :", sortie.shape)
Trois projections du vecteur de chaque mot, apprises pendant l'entraînement. La requête d'un mot est comparée aux clés des autres pour calculer les poids, puis les valeurs des autres mots sont moyennées avec ces poids. L'analogie courante est celle d'une recherche : la requête, les étiquettes des documents, le contenu des documents.
Le produit scalaire de deux vecteurs grandit avec leur dimension. Sans correction, les scores deviennent très grands et la softmax donne presque tout le poids à un seul mot, ce qui freine l'apprentissage. Diviser par la racine de la dimension garde les scores dans une plage raisonnable.
On calcule plusieurs attentions en parallèle, chacune avec ses propres projections, puis on concatène les résultats. Chaque tête peut se spécialiser sur un type de relation entre les mots. Le Transformer original en utilisait 8 par couche.
Empile des couches d'attention et de petits réseaux. C'est là que l'attention prend toute sa puissance.
Voir la fiche → l'approche d'avantLit la phrase mot après mot et garde une mémoire. L'attention a d'abord été ajoutée à ces réseaux avant de les remplacer.
Voir la fiche → l'entrée du calculLes vecteurs de mots sur lesquels l'attention travaille. Leur qualité conditionne tout le reste.
Voir la fiche →Dataistudio forme les équipes au machine learning et à l'IA, sur des cas concrets.
Nous utilisons des cookies de mesure d'audience et de suivi publicitaire pour comprendre la fréquentation du site et l'efficacité de nos annonces. Rien n'est déposé sans votre accord. En savoir plus