La pièce qu’un modèle de langage répète
Un bloc de transformeur est l’unité dont un modèle de langage est fait, et un modèle empile ce même bloc de nombreuses fois. Il contient une attention masquée à plusieurs têtes, puis un petit réseau pour chaque jeton. Des raccourcis et une remise à l’échelle entourent les deux.
Qui connaît un bloc connaît la forme du modèle entier.
À la fin de cette leçon
Remarque
Je peux suivre un jeton à travers les étapes d’un bloc de transformeur.
Mots-clés
| Mot | Ce que ça veut dire |
|---|---|
| Masque causal | empêche un jeton de regarder les jetons suivants |
| Tête | une étape d’attention avec ses propres tables de requête, clé et valeur |
| Étape dense | un petit réseau appliqué à chaque jeton seul |
| Connexion résiduelle | ajoute l’entrée d’une étape à sa sortie |
| Normalisation | remet un vecteur à l’échelle pour garder ses nombres d’une taille stable |
| Bloc | attention et étape dense avec leurs résidus, répétés pour bâtir un modèle |
Les cellules que les étudiants remplissent restent vides dans cet aperçu.
Un masque causal cache le futur
Un modèle de langage apprend à deviner le jeton suivant. Si un jeton pouvait regarder les jetons d’après, il verrait la réponse.
Un masque causal laisse donc chaque jeton regarder seulement lui-même et les jetons d’avant. Un jeton plus loin reçoit un poids de 0. En pratique, son score passe à moins l’infini avant le softmax, car e puissance moins l’infini vaut 0.
Exemple travaillé : les poids avec le futur masqué
| Jeton | Scores | Peut regarder | Poids |
|---|---|---|---|
| Premier | 1, 2, 0 | le premier seul | 1, 0, 0 |
| Deuxième | 2, 1, 1 | le premier et le deuxième | 0,731, 0,269, 0 |
| Troisième | 0, 1, 3 | les trois | 0,042, 0,114, 0,844 |
Les cellules que les étudiants remplissent restent vides dans cet aperçu.
Masquer le futur en Python
import math
# scores[i][j] : à quel point la requête du jeton i correspond à la clé du jeton j.
scores = [[1, 2, 0], [2, 1, 1], [0, 1, 3]]
for i in range(3):
puissances = []
for j in range(3):
if j <= i:
puissances.append(math.exp(scores[i][j]))
else:
# Un jeton plus loin : masqué, il ne reçoit aucun poids.
puissances.append(0)
total = sum(puissances)
poids = []
for p in puissances:
poids.append(round(p / total, 3))
print("jeton", i, "poids", poids)
# Remplacez j <= i par True, pour ne rien masquer, puis cliquez sur Exécuter.
# Comment change la ligne du premier jeton, et pourquoi est-ce tricher ?
Le même masque avec NumPy
docker exec jupyter python3 -c "import numpy as np; S = np.array([[1, 2, 0], [2, 1, 1], [0, 1, 3]], dtype=float); S[np.triu(np.ones((3, 3), dtype=bool), 1)] = -np.inf; W = np.exp(S) / np.exp(S).sum(axis=1, keepdims=True); print(W.round(3).tolist())"Affichée ici, non exécutée. Créez un compte gratuit pour appuyer sur Exécuter et la saisir dans le terminal de votre propre labo.
Plusieurs têtes cherchent des choses différentes
Une étape d’attention ne mélange que d’une seule façon. Un bloc fait donc tourner plusieurs têtes côte à côte, chacune avec ses propres tables de requête, clé et valeur.
Une tête peut relier un mot au mot d’avant. Une autre peut relier un adjectif au nom qu’il décrit. Leurs sorties sont mises bout à bout, puis une dernière table apprise les ramène à la longueur habituelle.
Exemple travaillé : joindre deux têtes
| Étape | Pour le jeton bondé |
|---|---|
| Sortie de la tête 1 | 7,88, 2,12 |
| Sortie de la tête 2 | 1, 3 |
| Mises bout à bout | 7,88, 2,12, 1, 3 |
| Après la table de mélange | retour à la longueur habituelle |
Les cellules que les étudiants remplissent restent vides dans cet aperçu.
Étape dense, résidus et normalisation
Après l’attention, chaque jeton passe seul dans une petite étape dense : deux couches avec ReLU entre elles, comme dans le module d’apprentissage profond.
Une connexion résiduelle ajoute l’entrée de chaque étape à sa sortie, si bien que rien de déjà connu ne se perd. La normalisation remet chaque vecteur à l’échelle : ses nombres ont une moyenne de 0 et un écart stable. Les deux gardent une pile profonde entraînable.
Exemple travaillé : un résidu, puis la normalisation
| Étape | Nombres |
|---|---|
| Entrée de bondé | 1, 2 |
| Sortie de l’attention | 7,88, 2,12 |
| Résidu : les additionner | 8,88, 4,12 |
| Normalisé : moyenne 0 | 1, -1 |
Les cellules que les étudiants remplissent restent vides dans cet aperçu.
Normaliser un vecteur avec NumPy
docker exec jupyter python3 -c "import numpy as np; x = np.array([2.0, 4.0, 6.0]); print(x.mean(), ((x - x.mean()) / x.std()).round(2).tolist())"Affichée ici, non exécutée. Créez un compte gratuit pour appuyer sur Exécuter et la saisir dans le terminal de votre propre labo.
Une erreur fréquente
Attention
Beaucoup pensent que l’étape dense fait dialoguer les jetons entre eux. Elle travaille sur chaque jeton seul. Les jetons ne partagent de l’information que dans l’attention, donc un fait venu d’un autre jeton doit d’abord passer par là.