Thomas Piacentini
← Atelier

La fabrique · Du texte au Transformer

Construire un LLM.

Un petit modèle, entraîné ici. Six expériences pour comprendre ses calculs, puis construire en Python.

01 / 06

Préparer le texte

Le modèle reçoit des nombres. Commencez par transformer chaque caractère en un identifiant, puis vérifiez que vous pouvez retrouver le texte.

100–20 000 tokens · 2–100 caractères distincts · calculs locaux

Texte → identifiants

Identifiants → texte

Comprendre cette étape

Un token est une unité de texte. Ici, un caractère Unicode normalisé = un token. Les modèles du livre utilisent ensuite une tokenisation BPE, où un token peut contenir plusieurs caractères. Le vocabulaire est construit sur le corpus entier ; seuls les 80 % initiaux servent aux mises à jour.

chars = sorted(set(text))
stoi = {c: i for i, c in enumerate(chars)}
ids = [stoi[c] for c in text]
assert ''.join(chars[i] for i in ids) == text
Raschka · chapitre 2 ↗

02 / 06

Créer une cible

Pour apprendre, le modèle tente de prédire le caractère suivant à chaque position. Déplacez la fenêtre, puis complétez sa dernière cible.

Indices dans la partie entraînement. ␠ = espace ; ↵ = saut de ligne.

Quel caractère complète la dernière cible ?
Comprendre cette étape

Le contexte est le nombre maximal de tokens lus à la fois. Les cibles sont la même séquence décalée d’un token. On sépare entraînement et validation avant de créer les fenêtres : aucune ne traverse cette frontière. La validation mesure la prédiction sur du texte réservé, pas la compréhension.

train, validation = ids[:split], ids[split:]
x = train[start:start + context]
y = train[start + 1:start + context + 1]
assert x[1:] == y[:-1]
Raschka · chapitre 2 ↗

03 / 06

Masquer le futur

Une position peut lire ce qui la précède, jamais ce qui la suit. Choisissez une position et désactivez le masque pour observer la fuite.

Position qui lit le contexte

Q/K fixes, exemple de six positions. Désactivez puis réactivez le masque pour vérifier le repère.

Comprendre cette étape

Les requêtes Q et les clés K produisent des scores de proximité. On masque les scores futurs avant le softmax, qui transforme les scores en poids dont la somme vaut 1. Les valeurs V sont ensuite combinées avec ces poids. Cet exemple utilise des Q/K fixes pour isoler le masque ; les Q/K/V du modèle seront appris.

scores = q @ k.transpose(-2, -1) / sqrt(head_dim)
scores = scores.masked_fill(future, float('-inf'))
weights = scores.softmax(dim=-1)
context = weights @ v
Raschka · chapitre 3 ↗

04 / 06

Assembler le modèle

Reliez les briques, puis faites vérifier les dimensions et le masque sur le vrai modèle. Ses poids démarrent aléatoirement.

1 bloc · 2 têtes · float32
  1. Tokens
  2. Embeddings
  3. Attention + MLP
  4. Logits
Ce que le test vérifie

On modifie la seconde moitié d’une fenêtre réelle. Les logits de la première moitié doivent rester identiques : aucune information future ne doit fuir. Le nombre de paramètres et la forme de sortie sont aussi vérifiés. Le moteur numérique ne se charge qu’à cette étape.

Comprendre cette étape

Un embedding associe un vecteur à chaque token et à sa position. Deux têtes d’attention lisent des relations différentes. Un MLP transforme le résultat ; les connexions résiduelles et LayerNorm stabilisent le calcul. Les logits sont des scores, un par token possible. Un seul bloc et aucun dropout ici pour garder le modèle petit et les calculs reproductibles.

x = token_embedding(ids) + position_embedding(positions)
x = x + attention(norm1(x))
x = x + mlp(norm2(x))
logits = output(final_norm(x))
Raschka · chapitre 4 ↗

05 / 06

Apprendre et mesurer

Lancez 80 mises à jour. Le modèle corrige ses prédictions sur le texte d’entraînement ; le texte de validation reste réservé à la mesure.

0 / 400 pas maximum

Les mesures apparaîtront au lancement.

Lire les mesures
Loss moyenne sur 8 fenêtres fixes par ensemble
PasTrainValidation

Le calcul tourne dans un worker pour garder la page utilisable. Vous pouvez arrêter entre deux mises à jour. Limite de 400 pas pour cette expérience ; poursuivez en Python pour aller plus loin.

Comprendre cette étape

La loss est l’erreur moyenne de prédiction (entropie croisée, en nats). Plus elle est basse, mieux le modèle prédit ces cibles. Le gradient indique comment modifier les poids ; Adam fait les mises à jour à un taux de 0,003, avec norme du gradient limitée à 1. Les mesures utilisent toujours les mêmes 8 fenêtres par ensemble. Si train baisse et validation remonte, le modèle surapprend. Le meilleur checkpoint est celui dont la loss de validation mesurée est la plus basse.

loss = cross_entropy(logits.flatten(0, 1), targets.flatten())
optimizer.zero_grad()
loss.backward()
clip_grad_norm_(model.parameters(), 1.0)
optimizer.step()
Raschka · chapitre 5 ↗

06 / 06

Produire un token

Donnez une amorce au modèle entraîné. Observez les probabilités, tirez un token, puis réutilisez la sortie comme contexte.

Votre texte apparaîtra ici.

Comprendre cette étape

La température divise les logits avant le softmax. Une valeur basse concentre la distribution ; une valeur haute la répartit davantage. On tire ici dans tout le vocabulaire, sans top-k. Les probabilités affichées décrivent la dernière décision de génération. Même graine et mêmes poids donnent la même séquence. Un corpus de quelques lignes produit un modèle de démonstration, pas un assistant ni une capacité de raisonnement.

logits = model(ids[:, -context:])[:, -1, :]
probabilities = (logits / temperature).softmax(-1)
next_id = multinomial(probabilities, 1)
ids = cat((ids, next_id), dim=1)
Raschka · chapitre 5 ↗

Votre prochain établi

Construire en Python.

Emportez votre corpus, votre architecture et vos poids. Le notebook vous guide pour réécrire les briques et les tester.

  1. Conserver cette expérience

    Le projet JSON restaure le modèle dans cette page. Les poids et mesures sont inclus ; l’état interne de l’optimiseur est réinitialisé à la reprise.

  2. Coder, avec des tests

    Python 3.10+ et PyTorch 2.x. Le notebook contient six exercices courts, leurs tests et des solutions à ouvrir si nécessaire. Vos poids peuvent y être rechargés sans réentraînement.

    Télécharger le notebook

    Sans modèle construit : corpus exemple et poids aléatoires.

    Installer et débloquer un problème
    python -m venv .venv
    # macOS / Linux
    source .venv/bin/activate
    # Windows
    # .venv\Scripts\activate
    python -m pip install torch jupyterlab
    python -m jupyter lab
    ModuleNotFoundError: torch
    Installez torch dans l’environnement du kernel sélectionné dans Jupyter.
    Mémoire GPU insuffisante
    Choisissez DEVICE = "cpu" dans la configuration ; conservez d=16 et contexte=8.
    Loss de validation en hausse
    Reprenez le meilleur checkpoint. Ajoutez des données avant d’augmenter la taille du modèle.

Effacer le projet local

Efface le texte, les poids et la progression de cet appareil. Exportez le JSON si vous souhaitez les conserver.

Après le petit Transformer

Aborder le raisonnement.

Le second ouvrage et le cours repartent de Qwen3 préentraîné. Notre modèle miniature illustre le préentraînement ; il ne remplace pas ce point de départ. Commencez par mesurer la justesse sur un jeu de problèmes réservé.

1. Vérifier et voter · sans modifier les poids

Exemple écrit à la main : 12 milles en 3 heures. Le vérificateur attend 4 nœuds ; un vote majoritaire peut se tromper. Modifiez les réponses (une par ligne).

Le vote compare des textes ; le vérificateur accepte uniquement des décimaux finis. Aucun modèle de raisonnement n’est exécuté ici.

Chapitre 4 · self-consistency ↗
2. Récompenser · modifier les poids avec GRPO

Comparez les récompenses au sein d’un groupe. Une récompense au-dessus de la moyenne donne un avantage positif. Si toutes sont identiques, ce signal est nul.

Récompenses → avantages normalisés

Ce calcul isole les avantages ; ce n’est pas une boucle GRPO complète (loss, clipping et KL restent à implémenter).

Chapitre 6 · GRPO ↗
3. Distiller · apprendre de réponses sélectionnées

Un modèle enseignant produit des réponses. Après filtrage, un modèle élève apprend sur ces exemples. Évaluez base, vote, GRPO et distillation sur les mêmes problèmes : justesse, tokens et temps. Le chapitre 7 du premier livre introduit le fine-tuning sur instructions ; le chapitre 8 du dépôt raisonnement développe la distillation.

Chapitre 8 · distillation ↗

Explications, exercices et code originaux. Les PDF ne sont pas redistribués. Les coches attestent de manipulations locales ; elles ne certifient ni le code Python ni une compétence générale.