Niveau 3 — technique
La mécanique.
Six laboratoires où vous conduisez les maths vous-même : de vrais produits scalaires, une vraie matrice d'attention, une vraie descente de gradient — calculés en direct dans votre navigateur. Aucune IA en direct, aucune donnée, rien ne quitte la page.
Ceci est l'étage profond. Si « jetons » et « plongements » sont des mots neufs, commencez par le guide des modèles — puis revenez ici.
1 — Un mot est une direction
Avant tout, le modèle transforme chaque jeton en vecteur — une liste de nombres, une direction dans l'espace. Les sens proches pointent dans la même direction. Toute la machine repose là-dessus : le sens devient géométrie, et la géométrie se multiplie.
Les vrais modèles utilisent 4 096 dimensions ou plus. Ici on en prend 2 pour les voir. Le produit scalaire est identique — juste une somme plus longue.
Voir le code
import numpy as np
ciel = np.array([0.86, 0.78])
bleu = np.array([0.92, 0.60])
dot = ciel @ bleu # 0.86*0.92 + 0.78*0.60
cos = dot / (np.linalg.norm(ciel) * np.linalg.norm(bleu))
print(dot, cos) # similarité brute, similarité normalisée
2 — L'attention, calculée
Chaque jeton pose une question à tous les autres. Le score est un produit scalaire; on le divise par √d pour garder des nombres sages; le softmax transforme la ligne en poids qui somment à 1. Cliquez une ligne pour voir son arithmétique — et coupez le √d pour voir l'attention s'effondrer sur une seule case.
Le masque causal est ce qui empêche un modèle de lire le futur : tout ce qui est à droite de la diagonale est mis à −∞ avant le softmax, donc son poids devient exactement zéro.
Voir le code
d = Q.shape[-1]
scores = Q @ K.T / np.sqrt(d) # (n, n) — chaque jeton contre chaque jeton
scores = np.where(mask, scores, -np.inf) # masque causal : pas de futur
weights = softmax(scores, axis=-1) # chaque ligne somme à 1
out = weights @ V # moyenne pondérée des valeurs
3 — Le flux résiduel
Un bloc ne remplace pas le vecteur — il s'y ajoute. L'attention écrit une correction, le MLP en écrit une autre, et la normalisation garde l'échelle sous contrôle. Empilez ça 32 ou 96 fois et vous obtenez la profondeur : chaque couche corrige un brouillon en cours plutôt que de repartir de zéro.
Barres grises = le vecteur avant l'étape. Rouge = ce que le bloc vient d'ajouter.
Voir le code
def block(x):
x = x + attention(norm(x)) # le « + » EST le flux résiduel
x = x + mlp(norm(x))
return x
for layer in layers: # 32, 96, 120...
x = block(x)
4 — L'échantillonnage : température, top-k, top-p
Le modèle sort un score par jeton. Le softmax transforme les scores en probabilités; la température les étire ou les aplatit; top-k et top-p coupent la queue. Puis un jeton est tiré. Refroidissez à 0,1 et la machine devient répétitive et sûre; chauffez au-delà de 1,2 et elle part en vrille.
L'entropie (H) mesure l'indécision de la distribution, en bits. Entropie basse = peu d'options réelles.
Voir le code
probs = softmax(logits / T) # T petit = plus tranché
idx = np.argsort(-probs)[:k] # top-k : on ne garde que k candidats
cum = np.cumsum(probs[idx])
idx = idx[cum <= p] # top-p : on coupe la queue
token = np.random.choice(idx, p=probs[idx] / probs[idx].sum())
5 — Apprendre, c'est descendre une pente
L'entraînement compare le jeton prédit au vrai : la perte, c'est −log de la probabilité que le modèle donnait à la bonne réponse. Le gradient dit où est la descente pour chaque poids; le taux d'apprentissage dit de combien avancer. Poussez-le trop haut et la bille rebondit sur les parois — c'est un entraînement qui diverge.
La perplexité, c'est exp(perte) : en gros, « entre combien d'options également probables hésite-t-il? ».
Voir le code
logits = model(x)
loss = cross_entropy(logits, y) # −log p(bon jeton)
loss.backward() # gradient pour CHAQUE paramètre
optimizer.step() # θ ← θ − η·∇L
optimizer.zero_grad()
6 — Ce que ça coûte
Les paramètres croissent avec le carré de la largeur : 12·d² par couche, plus la table du vocabulaire. L'attention croît avec le carré du contexte : doublez le prompt et vous quadruplez la matrice de scores. Voilà pourquoi les longs contextes coûtent cher, et pourquoi le cache KV dévore la mémoire.
Vérifiez la formule sur un modèle connu : d = 12 288, 96 couches, vocabulaire de 50 k tombe à un pour cent des 175 milliards publiés de GPT-3.
Voir le code
params = V * d + L * 12 * d**2 # plongements + blocs
flops = 2 * params # par jeton, passe avant
scores = n**2 * L * heads # le mur du n²
# d=12288, L=96, V=50257 -> ~175 G paramètres
Oyez
Le moteur est ouvert. Reste à bâtir.
Cette page explique la machine. Le parcours du bâtisseur s'en sert : recherche documentaire, agents, évaluation d'outils, et un agent local souverain que vous assemblez vous-même.