AP – Elixir – AP5

Apprendre à partir d'exemples

Du gradient à un petit réseau Axon

AP5 · mardi 15 décembre 2026 · 3 h

mardi 15 décembre 2026
AP – Elixir – AP5

Où en sommes-nous ?

En AP4 : des points en {n, 2}, des cibles en {n, 1}, et un score dont nous choisissions les paramètres à la main. Aujourd'hui :

  1. Choisir les paramètres en suivant le gradient d'une perte.
  2. Changer de famille de fonctions avec un réseau Axon.
  3. Comparer des essais sur des exemples gardés à part.
mardi 15 décembre 2026
AP – Elixir – AP5

Comment suivre la séance

Prédisez ce que changera un essai, exécutez-le dans Livebook, puis expliquez le résultat.

Les carnets se suivent : recopiez vos propres fonctions dans les cellules indiquées.

Gardez vos essais, y compris ceux dont la perte ne diminue pas.

mardi 15 décembre 2026
AP – Elixir – AP5

01 · Comment choisir les paramètres ?

Commençons par une règle que notre score sait représenter, :

Point (−1, −1) (−1, 1) (1, −1) (1, 1)
Cible −2.5 −0.5 1.5 3.5

Il faudra retrouver et ; l'algorithme ne voit que ces exemples.

mardi 15 décembre 2026
AP – Elixir – AP5

La perte mesure l'erreur d'un réglage

Départ : et .

Point (−1, −1) (−1, 1) (1, −1) (1, 1)
Score −0.1 −0.5 0.5 0.1
Cible −2.5 −0.5 1.5 3.5
Écart 2.4 0 −1.0 −3.4

mardi 15 décembre 2026
AP – Elixir – AP5

La dérivée mesure une sensibilité

Prenons une fonction d'un seul nombre, , et partons de :

0 0.1 0.01
9 8.41 8.9401
−5.9 −5.99

La dérivée vaut en : un petit pas change d'environ .

mardi 15 décembre 2026
AP – Elixir – AP5

Le gradient : une dérivée par paramètre

On fait varier un paramètre, les autres restant fixés : c'est une dérivée partielle, notée .

De même, et . Le gradient regroupe ces trois nombres.

mardi 15 décembre 2026
AP – Elixir – AP5

Descendre : un pas contre la pente

Perte
Départ 0.3 −0.2 0 4.58
Gradient −3.4 −2.4 −1.0
Après un pas, 0.64 0.04 0.1 2.9312

regroupe les paramètres ; , le taux d'apprentissage, règle la longueur du pas.

mardi 15 décembre 2026
AP – Elixir – AP5

Un pas trop long peut faire remonter la perte

Sur la parabole q(u) = (u − 3)², depuis u = 0 où la pente vaut −6 : un pas de taux 0.1 mène à 0.6 où q vaut 5.76 ; un pas de taux 1.2 franchit le minimum et mène à 7.2 où q vaut 17.64.

La pente ne renseigne que sur le voisinage du point de départ.

mardi 15 décembre 2026
AP – Elixir – AP5

grad calcule ces dérivées pour nous

defmodule Descent do
  import Nx.Defn
  defn step(position, rate) do
    slope = grad(position, fn u -> Parabola.value(u) end)
    position - rate * slope
  end
end

Parabola.value(u) calcule dans un defn ; grad(valeur, f) rend la dérivée de f en valeur.

mardi 15 décembre 2026
AP – Elixir – AP5

Ce que demande le carnet 01

À écrire, avec defn Contrat
Linear.predict(params, x) votre score d'AP4 : {n, 2} donne {n, 1}
Linear.loss(params, x, y) la MSE, un scalaire : 4.58 au départ
Linear.step(params, x, y, rate) une nouvelle map, chaque paramètre moins rate fois sa dérivée

Fournis ensuite : 80 pas répétés, un pas à 1.2, puis les mêmes réglages avec les classes alternées des quadrants.
Prédisez chaque résultat avant d'exécuter.

mardi 15 décembre 2026
AP – Elixir – AP5

Elixir pour cet atelier · 01

train = fn targets ->
  Enum.reduce(1..80, params, fn _, current ->
    Linear.step(current, x, targets, 0.1)
  end)
end
  • Dans defn, grad(params, fn p -> loss(p, x, y) end) rend une map de dérivées de même structure que params.
  • Un defn peut rendre une map : %{weights: …, bias: …}.
  • Nx.all_close(a, b) compare deux tenseurs à une tolérance près.
mardi 15 décembre 2026
AP – Elixir – AP5

À vous · 01 · Faire descendre l'erreur

Ouvrez ap5-01-gradient.livemd. 30 min.

Écrivez la perte et le pas de descente avec grad.
Retrouvez la règle affine, puis changez seulement les cibles.
Expliquez le plateau sur les classes alternées et l'effet d'un pas trop grand.

mardi 15 décembre 2026
AP – Elixir – AP5

Reprise · Une perte bloquée à 0.25

Même départ, même taux, même nombre de pas : la règle affine est apprise, les classes alternées plafonnent.
Sur ces quatre coins, la meilleure fonction affine répond 0.5 partout.

Le pas, les données ou la famille de fonctions : qu'est-ce qui bloque ?
Quelle observation vous permet de trancher ?

mardi 15 décembre 2026
AP – Elixir – AP5

Pause · 10 min

Sauvegardez votre premier essai.
Nous allons ensuite changer la famille de fonctions que le modèle peut apprendre.

mardi 15 décembre 2026
AP – Elixir – AP5

02 · Une couche cachée transforme les coordonnées

Une couche dense de unités calcule scores comme celui d'AP4, chacun avec ses poids et son biais :

Une seconde couche combine ces valeurs en une prédiction.

mardi 15 décembre 2026
AP – Elixir – AP5

Deux couches affines restent affines

Avec un seul nombre : puis donnent .

Avec des matrices, de même :

Il faut une fonction non linéaire entre les deux couches.

mardi 15 décembre 2026
AP – Elixir – AP5

Une activation s'applique à chaque valeur

−2 0 2
−0.96 0 0.96
sigmoid 0.12 0.5 0.88

tanh écrase chaque valeur cachée entre −1 et 1 ; la sigmoid donne une sortie entre 0 et 1, lue comme la probabilité de la classe 1.

Classe prédite : 1 si la sortie atteint 0.5.

mardi 15 décembre 2026
AP – Elixir – AP5

Axon décrit l'architecture avec des pipes

model =
  Axon.input("points", shape: {nil, 2})
  |> Axon.dense(8, activation: :tanh)
  |> Axon.dense(1, activation: :sigmoid)

Les formes passent de {n, 2} à {n, 8}, puis à {n, 1}.
Paramètres : , puis , soit .

mardi 15 décembre 2026
AP – Elixir – AP5

Une perte pour des classes : l'entropie croisée

Sortie , pour une cible 0.9 0.6 0.1
Perte 0.105 0.511 2.303

Pour les pas, nous choisissons Adam, qui adapte leur longueur à l'historique des gradients.

mardi 15 décembre 2026
AP – Elixir – AP5

La boucle d'entraînement rend un état

optimizer = Polaris.Optimizers.adam(learning_rate: 0.03)
loop = Axon.Loop.trainer(model, :binary_cross_entropy, optimizer,
         seed: 42, log: 0)
state = Axon.Loop.run(loop, [{x, y}], Axon.ModelState.empty(),
          epochs: 200)
state.step_state.model_state   # les paramètres appris

Une époque parcourt tout le lot d'entraînement : ici, un seul lot, donc un pas par époque.

mardi 15 décembre 2026
AP – Elixir – AP5

Ce que demande le carnet 02

recipe = %{kind: :hidden, width: 8, activation: :tanh,
           rate: 0.03, epochs: 200, seed: 42}
  • Classifier.model(recipe) : pour :linear, une sortie sigmoid ; pour :hidden, width unités avec l'activation demandée, puis la sortie.
  • Classifier.fit(model, data, recipe) : la boucle, depuis un état vide, avec le taux, les époques et la graine de la recette.
  • Fournis : 144 points en trois lots, les prédictions, l'exactitude, la perte et le dessin.
mardi 15 décembre 2026
AP – Elixir – AP5

Elixir pour cet atelier · 02

linear_recipe = %{recipe | kind: :linear, width: nil, activation: nil}
train_rows = Enum.filter(rows, &(&1.split < 3))   # fn p -> p.split < 3 end
x = elem(train, 0)                                 # case 0 du tuple {x, y}
  • %{map | clé: valeur} copie une map en remplaçant des clés qui existent déjà.
  • Deux clauses de model/1 reconnaissent la recette par un motif de map, comme les nœuds d'AP2.
  • Avant la boucle, vérifiez un lot : entrées {87, 2}, cibles {87, 1}.
mardi 15 décembre 2026
AP – Elixir – AP5

À vous · 02 · Apprendre une frontière

Ouvrez ap5-02-axon.livemd. 30 min.

Décrivez le réseau selon la recette, puis comptez ses paramètres.
Entraînez-le, récupérez ses paramètres et dessinez ses prédictions.
Prédisez sur papier ce que donnerait la même recette sans activation cachée.

mardi 15 décembre 2026
AP – Elixir – AP5

Reprise · Qu'avons-nous donné au modèle ?

Nous lui avons donné des coordonnées, des cibles et une famille de fonctions.
La règle x * y > 0 n'est pas écrite dans le réseau.

Montrez un point correctement prédit et un point hésitant.
Où se trouvent les erreurs sur votre dessin ?

mardi 15 décembre 2026
AP – Elixir – AP5

03 · Sur quels points choisir le modèle ?

Lot Points À quoi sert-il ?
Entraînement 87 Calculer les gradients et modifier les paramètres.
Validation 29 Comparer les recettes et choisir.
Test 28 Mesurer une seule fois la recette retenue.

Les trois lots sont disjoints et fixés avant les essais.

mardi 15 décembre 2026
AP – Elixir – AP5

Le test peut devenir un entraînement indirect

Vous essayez dix architectures, regardez leurs scores de test et gardez la meilleure.

Même sans gradient calculé sur le test, vous l'avez utilisé pour choisir.
Sur quelles données pourrez-vous désormais estimer ce choix ?

mardi 15 décembre 2026
AP – Elixir – AP5

Comparer un essai demande de fixer le reste

Essai Ce que vous changez Ce que vous observez
Pas d'apprentissage Le taux, avec le même départ. Les pertes et les classes prédites.
Non-linéarité L'activation cachée, avec le même protocole. La frontière et les erreurs.
Capacité La largeur de la couche cachée. L'écart entraînement–validation.

Commencez par une seule comparaison.

mardi 15 décembre 2026
AP – Elixir – AP5

Une frontière montre où le modèle se trompe

Coloriez les points d'une grille fine avec la prédiction du modèle, sans réentraîner.
Superposez quelques observations dont vous connaissez la classe.

Une bonne moyenne peut cacher une région mal prédite.
Un point près de la frontière ne se lit pas comme un point loin des axes.

mardi 15 décembre 2026
AP – Elixir – AP5

Ce que demande le carnet 03

À écrire Contrat
Trial.run/3 Reçoit une recette et les tuples {x, y} de train et de validation ; entraîne depuis un état vide ; rend la recette, le modèle, l'état, les pertes et exactitudes des deux lots.

Puis : prédire le classement des trois références, choisir votre question, arrêter un choix sur la validation, ouvrir le test une seule fois.
Les erreurs de validation et la frontière sont fournies.

mardi 15 décembre 2026
AP – Elixir – AP5

Elixir pour cet atelier · 03

%{kind: :hidden, width: 8, activation: :tanh,
  rate: 0.03, seed: 42, epochs: 200}
def run(recipe, {train_x, train_y} = train, {validation_x, validation_y})

Une recette et ses mesures tiennent dans une map ; un motif en tête de fonction décompose un tuple tout en le gardant entier.
Chaque résultat conserve cette recette, les pertes et les exactitudes train et validation.

mardi 15 décembre 2026
AP – Elixir – AP5

À vous · 03 · Comparer sans se tromper

Ouvrez ap5-03-experiences.livemd. 40 min.

Comparez deux recettes sur la validation et expliquez leurs frontières.
Proposez un essai distinguant capacité du modèle et difficulté d'apprentissage.
Arrêtez votre choix, puis évaluez-le une fois sur le test gardé à part.

mardi 15 décembre 2026
AP – Elixir – AP5

Reprise · Que pouvez-vous conclure ?

Présentez une observation qui soutient votre choix et une limite de l'expérience.

Expliquez ce que vous changeriez ensuite et sur quelles données vous le vérifieriez.
Le test final permet-il de répondre à cette nouvelle question ?

mardi 15 décembre 2026
AP – Elixir – AP5

Ce que vous savez maintenant expérimenter

Vous pouvez préparer des données, écrire un calcul, en dériver les paramètres et entraîner un petit réseau.

Ces notions se retrouvent dans d'autres bibliothèques : tenseurs, gradient, architecture, optimisation et validation.

Conservez vos carnets, vos mesures et l'explication d'un essai corrigé.

mardi 15 décembre 2026
AP – Elixir – AP5

Amplified : nos expériences à une autre échelle

Pour analyser des brevets, Christopher Grainger montre en 2024 l'adaptation d'un modèle de texte BERT : 64 GPU comparent des configurations, avec des courbes suivies dans Livebook.

Ce que nous avons étudié Ce qui permet d'aller plus loin
Décrire un réseau et ses paramètres avec Axon. Bumblebee charge des modèles déjà entraînés.
Comparer des configurations sur des données de validation. Répartir des essais indépendants entre plusieurs machines.
Calculer une prédiction. Nx.Serving regroupe les requêtes dans un service supervisé.

Comment lancer plusieurs calculs, suivre leurs résultats et réagir à une panne ? Nous allons étudier la concurrence.

Livebook et FLAME, billet du 24 septembre 2024 · Bumblebee · Nx.Serving.

mardi 15 décembre 2026
AP – Elixir – AP5

Prolongement · Reconnaître un vêtement

AP5 · 04 · Fashion-MNIST reprend les mêmes idées avec des images de 28 × 28 pixels et dix classes.

Écrivez le modèle, vérifiez ses dimensions et inspectez ses confusions.
Comparez une erreur visuellement plausible et une erreur surprenante.

Cette piste s'inspire du cours PyTorch de Sébastien Boisgérault.

mardi 15 décembre 2026

À dire : Bonjour à tous. Nous commençons par le quiz sur AP4 : dix minutes, puis la correction ensemble. Aujourd'hui, nous faisons ce que nous avons préparé la semaine dernière : laisser un algorithme choisir les paramètres d'un modèle à partir d'exemples. Nous nous servirons pour cela de dérivées, que nous calculerons d'abord à la main sur de petits exemples. Rappelons d'abord où nous en sommes. Repères : quiz sur AP4 avant le lancement, sujet et clé dans quiz/quiz-5-tenseurs (chapitre 7 du poly, pour les données, les tenseurs et le graphe de calcul), dix minutes de réponse puis cinq de correction, pris sur la marge du créneau. Ouverture de 5 min avec les deux pages suivantes. Les élèves ont leurs fonctions d'AP4. Nx 1.0 et Axon 0.9, calcul sur CPU BinaryBackend ; aucune installation GPU.

À dire : La semaine dernière, nous avons rangé nos points dans des tenseurs {n, 2}, les cibles dans des colonnes {n, 1}, et écrit un score affine. Mais les poids et le biais, c'est nous qui les choisissions, et nous avons démontré qu'aucune droite ne sépare nos quatre coins. Aujourd'hui, trois étapes. D'abord, laisser un algorithme trouver les paramètres : c'est la descente de gradient. Ensuite, puisque la droite ne suffit pas, changer de modèle pour un petit réseau de neurones, décrit avec la bibliothèque Axon. Enfin, apprendre à comparer honnêtement deux essais. Repères : une bonne séparation visuelle, une perte faible et une bonne généralisation ne sont pas la même chose ; la séance distingue les trois. La règle de nos points reste cachée au modèle pendant l'apprentissage. Le but est de comprendre les mécanismes, pas de retenir les options de la bibliothèque.

À dire : Même rythme qu'en AP4 : un peu de cours, un carnet, une reprise, trois fois. Dans chaque carnet, vous allez lancer des essais ; avant chacun, écrivez ce que vous attendez, même en une ligne, puis comparez. Un essai qui échoue n'est pas à effacer : un essai bien expliqué compte autant qu'une meilleure mesure. Ouvrez le premier carnet et lancez sa cellule d'installation pendant que nous commençons. Repères : fin de l'ouverture. Montrer les trois ateliers et leurs repères sur la page AP5 du site. Les modèles restent petits et les exécutions courtes ; ne pas lancer de recherche exhaustive pendant que l'on discute d'une seule expérience. Le rendu et son périmètre sont précisés en cours.

À dire : Première partie : comment un algorithme peut-il choisir des paramètres ? Pour vérifier chaque étape, commençons par un cas où nous connaissons la réponse. Les cibles sont fabriquées par la règle 2x1 + x2 + 0.5 ; calculons-en une ensemble : pour le coin (−1, −1), 2 fois −1, moins 1, plus 0.5 donne −2.5. Notre score affine peut représenter exactement cette règle, avec les poids 2 et 1 et le biais 0.5. L'algorithme, lui, ne connaît que les quatre points et leurs cibles, et il part de paramètres quelconques. Il lui faut d'abord un moyen de dire à quel point un réglage est mauvais. Repères : cours 01, 20 min jusqu'à la consigne. Ce sont des nombres, pas encore des classes. Les mêmes quatre coins serviront à l'essai des classes alternées.

À dire : Partons de paramètres quelconques : 0.3 et −0.2 pour les poids, 0 pour le biais. Pour le premier coin, le score vaut 0.3 fois −1, plus −0.2 fois −1, soit −0.1, alors que la cible est −2.5 : l'écart est de 2.4. On fait de même pour les quatre coins. Comme en AP4, on met les écarts au carré et on fait la moyenne : 4.58. Ce nombre, c'est la perte : il résume à quel point ce réglage se trompe, et il vaut 0 si toutes les réponses sont exactes. Apprendre, ce sera modifier les paramètres pour faire baisser ce nombre. Mais dans quel sens les modifier ? Il faut savoir comment la perte réagit quand on touche à un paramètre. Repères : c'est la MSE d'Error.mse en AP4, et la première vérification du carnet. Faire vérifier une colonne par la salle, par ex. (1, 1) : 0.3 − 0.2 = 0.1, écart 0.1 − 3.5 = −3.4. Le score peut sortir de [0, 1] : ce n'est pas encore une probabilité.

À dire : Oublions un instant notre modèle et prenons une fonction très simple, q(u) égale (u − 3) au carré. En u = 0, elle vaut 9. Avançons un peu : en 0.1, elle vaut 8.41 ; elle a baissé de 0.59 pour un pas de 0.1, soit un rapport de −5.9. Avec un pas dix fois plus petit, le rapport vaut −5.99 : il se rapproche de −6, la dérivée en 0, que la formule 2(u − 3) donne directement. Retenez deux lectures de ce nombre : son signe dit dans quel sens q varie quand u augmente, ici elle baisse ; sa taille dit à quelle vitesse, ici environ six fois le petit pas. C'est en ce sens que la dérivée mesure une sensibilité. Notre perte, elle, dépend de trois paramètres. Repères : rester sur la pente d'une courbe et le taux de variation, sans limite formelle ; la définition par la limite est une piste d'approfondissement pour les questions. Dessiner la courbe et sa tangente au tableau. Valeurs exactes ; −5.999 avec un pas de 0.001.

À dire : Notre perte L dépend de trois nombres, w1, w2 et b. On applique la même idée à chacun : faire varier un seul paramètre, en gardant les deux autres fixés, et regarder la pente. C'est une dérivée partielle, notée avec ce d arrondi. Calculons celle du biais. Quand b augmente de h, chaque score augmente de h, donc chaque écart aussi ; la dérivée d'un carré (s − y)² est alors 2(s − y). Pour la moyenne, on additionne les quatre écarts, on multiplie par 2 et on divise par 4 : −1. Pour les poids, chaque écart est en plus multiplié par la coordonnée correspondante, ce qui donne −3.4 et −2.4. Les trois dérivées sont négatives : augmenter un peu n'importe quel paramètre ferait baisser la perte. Le gradient, noté nabla, est simplement le vecteur de ces trois nombres. Comment s'en servir pour avancer ? Repères : piste d'approfondissement, la formule générale ∂L/∂w_j = (2/n) Σ (s_i − y_i) x_ij. Pour w1, avec les premières coordonnées −1, −1, 1, 1 : (2/4)(−2.4 + 0 − 1.0 − 3.4) = −3.4. Valeurs vérifiées avec grad de Nx 1.0. Le gradient est pris par rapport aux paramètres ; les points et les cibles restent fixes. Un gradient nul ne prouve pas une bonne classification.

À dire : Imaginez que vous descendez une vallée dans le brouillard : vous ne voyez pas le fond, mais vous sentez la pente sous vos pieds, et vous faites un pas vers le bas. Le gradient indique la direction où la perte monte ; nous faisons donc un pas dans la direction opposée, d'où le signe moins. La lettre thêta regroupe nos trois paramètres, et êta, le taux d'apprentissage, règle la longueur du pas. Calculons avec êta égal à 0.1 : w1 devient 0.3 moins 0.1 fois −3.4, soit 0.64 ; de même, w2 passe à 0.04 et b à 0.1. La perte tombe de 4.58 à 2.93. En répétant ce pas, elle continue de baisser : 1.88, puis 1.20, puis 0.77. C'est toute la descente de gradient. Mais la longueur du pas compte. Repères : pertes des cinq premiers pas, vérifiées : 2.9312, 1.8760, 1.2006, 0.7684, 0.4918 ; après 80 pas, poids proches de (2, 1), biais 0.5, perte sous 1e-8. Ce sont les vérifications du carnet ; les élèves écrivent ce pas eux-mêmes.

À dire : Revenons à notre parabole pour voir l'effet du taux. Depuis u = 0, la pente vaut −6. Avec un taux de 0.1, on avance de 0.6 : q passe de 9 à 5.76, c'est mieux. Avec un taux de 1.2, on avance de 7.2 : on a franchi le minimum, situé en 3, et q monte à 17.64. La direction était bonne, mais le pas trop long. À l'inverse, un taux minuscule ne fait presque pas bouger les paramètres dans le nombre de pas disponible. Dans le carnet, vous ferez le même essai sur notre modèle : prédisez si la perte montera ou descendra. Reste à obtenir ces dérivées sans les calculer à la main. Repères : sur le modèle du carnet, un pas à 1.2 fait passer la MSE de 4.58 à 8.9768 ; ne pas le dire avant l'essai. Un taux très grand peut faire osciller ou diverger ; un résultat Inf ou NaN est un échec à noter. Ne pas promettre que tout taux élevé diverge, ni attribuer toute absence de progrès à Nx.

À dire : Calculer les dérivées à la main devient vite pénible quand le modèle grandit. C'est ici que le graphe d'AP4 sert : puisque Nx connaît la liste des opérations, et la dérivée de chacune, il peut les enchaîner par la règle de dérivation des fonctions composées. C'est la différentiation automatique. Dans ce bout de code, grad reçoit la position et la fonction à dériver, et rend la pente en ce point, −6 en 0 ; step fait ensuite un pas, et Descent.step(0.0, 0.1) rend 0.6. Nous n'avons écrit la formule 2(u − 3) nulle part. Dans le carnet, le premier argument de grad sera la map de vos paramètres, et grad rendra une map de même structure, avec une dérivée par paramètre. Repères : valeurs vérifiées avec Nx 1.0 : pente −6.0 ; pas à 0.1, position 0.6 et valeur 5.76 ; pas à 1.2, position 7.2 et valeur 17.64. Distinguer l'autodiff, le calcul symbolique, qui produit une formule lisible, et les différences finies, qui approchent la pente par un petit pas comme dans notre tableau. La position initiale n'est pas modifiée.

À dire : Le carnet 01 vous demande trois fonctions dans un module Linear, toutes avec defn. predict reprend votre score d'AP4 ; loss calcule la MSE de ces prédictions ; step calcule le gradient avec grad, puis rend une nouvelle map où chaque paramètre a reculé de rate fois sa dérivée. Les vérifications sont celles que nous venons de calculer : 4.58, puis 2.9312 après un pas. La répétition sur 80 pas est ensuite fournie, et vous devez retrouver les poids 2 et 1 et le biais 0.5. Viennent enfin deux essais : un pas trop long, et surtout les mêmes réglages avec d'autres cibles, les classes alternées de nos quadrants. Avant ce dernier essai, écrivez ce que vous attendez, en vous souvenant de la reprise d'AP4. Repères : le socle s'arrête à l'explication du plateau ; la preuve du minimum, un contre-exemple inventé et la vérification par différence finie sont des prolongements ; pour cette dernière, un epsilon autour de 1e-3 convient en f32. Le carnet contrôle aussi les poids [0.64, 0.04] et le biais 0.1 après un pas.

À dire : Côté Elixir, trois formes nouvelles. grad, à l'intérieur d'un defn, rend une map de dérivées qui a la même structure que params, avec un champ weights et un champ bias. Un defn peut rendre une map, que l'on construit comme d'habitude. La répétition, elle, est fournie : Enum.reduce parcourt les nombres de 1 à 80 en transportant un accumulateur, les paramètres courants, comme les accumulateurs d'AP1 ; le trait bas ignore le numéro du tour. Enfin, pour comparer deux tenseurs de flottants, Nx.all_close tolère un petit écart. À vous ! Repères : calcul et répétition sont séparés pour pouvoir inspecter les premiers pas. train repart de params à chaque appel : aucune continuation cachée de l'essai précédent. Nx.broadcast(0.5, {4, 1}) fabrique un tenseur rempli de 0.5 dans les vérifications.

À dire : Trente minutes pour le carnet 01. Commencez par vérifier un seul pas : si 4.58 puis 2.9312 sortent, le reste suivra. Notez vos prédictions avant les deux essais de la fin, et gardez une observation sur le taux. Repères : 30 min. Socle : un pas vérifié, la réussite affine, les mêmes réglages sur les classes alternées, une limite expliquée. Les deux répétitions sont fournies. Si le temps manque, terminer un pas ensemble au tableau et observer la boucle du corrigé. Éviter la recherche du meilleur nombre d'itérations.

À dire : Qu'avez-vous observé ? Avec la règle affine, la perte tombe presque à zéro et l'on retrouve 2, 1 et 0.5. Avec les classes alternées, les mêmes réglages s'arrêtent à 0.25, et les quatre scores valent 0.5. Le pas n'est pas en cause, puisqu'il a fonctionné juste avant sur les mêmes points : c'est la famille de fonctions. Nous l'avions démontré en AP4, aucune droite ne sépare ces coins, et la meilleure réponse affine consiste ici à dire 0.5 partout ; davantage de pas n'y changera rien. Retenez la méthode : une perte qui explose fait regarder le pas, une perte bloquée avec des erreurs fait regarder la capacité du modèle, une perte trop belle fait vérifier les cibles et les formes. Après la pause, nous changerons de famille. Repères : reprise de 5 min. Demander des preuves : deux pertes successives, les formes, un dessin des quatre points. Prolongement : sur ces coins, la perte vaut w1² + w2² + (b − 0.5)² + 0.25, dont le minimum est 0.25 ; ce chiffre ne vaut pas pour un sous-échantillon quelconque. Une perte constante peut aussi venir d'un taux nul ou d'un paramètre non mis à jour : ce diagnostic n'est pas automatique.

À dire : Dix minutes de pause. Sauvegardez votre carnet ; si Axon ne s'est pas installé chez vous, dites-le-moi maintenant. Repères : 10 min. Vérifier l'installation d'Axon. Les paramètres appris à la main ne seront pas chargés dans le réseau : nouvelle architecture, nouvel état.

À dire : Deuxième partie. Puisqu'une droite ne suffit pas, changeons de modèle. Au lieu de calculer un seul score à partir des deux coordonnées, calculons-en plusieurs, chacun avec ses propres poids et son propre biais. Avec huit unités, chaque point devient ainsi huit nombres, z1 à z8 : c'est une couche dense, dense parce que chaque unité reçoit toutes les entrées. Une seconde couche combine ensuite ces huit nombres en une prédiction. Vous vous souvenez du prolongement d'AP4, où l'on ajoutait la coordonnée x1 fois x2 ? Avec elle, un seuil suffisait. L'espoir est qu'une couche apprenne d'elle-même, à partir des exemples, une transformation utile de ce genre. Mais il y a un piège. Repères : cours 02, 15 min jusqu'à la consigne. Pour un lot, les huit scores s'obtiennent d'un coup : x de forme {n, 2} fois une matrice de poids {2, 8}, plus un biais {8}, donne {n, 8} ; c'est le produit matriciel, une piste d'approfondissement plutôt qu'un passage obligé du cours. Une couche est dite cachée parce que nous ne lui fournissons aucune cible.

À dire : Que se passe-t-il si l'on enchaîne deux couches affines ? Faisons-le avec un seul nombre : f multiplie par 2 et ajoute 1, g multiplie par 3 et retire 4. g de f de x, c'est 3 fois (2x + 1) moins 4, soit 6x − 1 : encore une fonction affine. Avec des matrices, c'est pareil : on développe, et l'on retrouve une matrice fois x, plus un vecteur. Deux couches affines, ou dix, ne valent donc qu'une seule couche affine, et la frontière reste une droite. Il faut casser la linéarité entre les couches, avec une fonction qui ne soit pas affine. Repères : faire développer au tableau. Empiler des couches linéaires ne règle pas nos classes alternées ; l'atelier 03 le mesure en retirant l'activation. Ne pas parler de neurones qui « comprennent » des quadrants avant de l'avoir observé.

À dire : Une activation est une fonction appliquée séparément à chacune des valeurs produites par une couche. Entre les deux couches, nous utiliserons tanh : elle laisse passer les petites valeurs presque telles quelles et écrase les grandes vers −1 ou 1. Elle n'est pas affine : tanh de 4 vaut presque 1, pas le double de tanh de 2. En sortie, nous utiliserons la sigmoid, qui transforme n'importe quel score en un nombre entre 0 et 1 ; un score nul donne 0.5. Nous lirons ce nombre comme la probabilité que le point soit de classe 1, et nous déciderons la classe 1 dès qu'il atteint 0.5. Voyons comment Axon assemble ces briques. Repères : σ(z) = 1 / (1 + e^(−z)). Valeurs arrondies, vérifiées avec Nx : tanh(2) ≈ 0.964, σ(2) ≈ 0.881, σ(−2) ≈ 0.119. Une sortie sigmoid n'est pas automatiquement une probabilité bien calibrée, et le seuil n'entre pas dans la perte. relu, proposée dans le carnet 03, remplace les valeurs négatives par 0. Rester sur nos coordonnées bornées : des valeurs extrêmes satureraient les activations.

À dire : Voici le réseau de la séance, décrit avec Axon. On part d'une entrée de deux coordonnées ; nil signifie que le nombre d'exemples n'est pas fixé. Puis une couche dense de huit unités avec tanh, et une couche dense d'une unité avec sigmoid. Comptons les paramètres : la première couche a deux poids par unité, soit seize, plus huit biais ; la seconde a huit poids et un biais ; 33 en tout. Attention, ce pipe construit une description du réseau, comme le graphe de defn : il n'a rien appris et ne contient encore aucun nombre. Comment choisir ces 33 paramètres ? Avec une perte et des pas de gradient, comme tout à l'heure, mais avec deux changements. Repères : la première couche a un noyau {2, 8} et un biais {8}, la seconde un noyau {8, 1} et un biais {1} (vérifié avec Axon 0.9). Faire retrouver le compte si le groupe avance bien. Le carnet demande une version configurable par une recette, avec ou sans couche cachée.

À dire : Nos cibles sont maintenant des classes, 0 ou 1, et notre sortie un nombre entre 0 et 1. On utilise d'ordinaire une autre perte, l'entropie croisée binaire, BCE en anglais. Lisons-la pour une cible égale à 1 : le second terme disparaît, et il reste moins le logarithme de p. Si le modèle annonce 0.9, la perte vaut 0.105 ; s'il annonce 0.6, elle vaut 0.511 ; s'il annonce 0.1, elle vaut 2.303. Les deux premières réponses donnent la même décision, classe 1, et pourtant la perte les distingue : elle pénalise d'autant plus une réponse qu'elle est confiante et fausse. Pour une cible 0, c'est le second terme qui compte, de façon symétrique. Pour les pas, nous remplaçons notre taux fixe par Adam, un optimiseur, c'est-à-dire une règle de mise à jour, qui adapte la longueur des pas. Ce sont nos choix : Axon accepterait aussi la MSE et la descente simple. Repères : ln est le logarithme népérien ; −ln p devient grand quand p s'approche de 0. Utiliser la perte de la bibliothèque, qui évite ln(0). La mécanique prédire, mesurer, dériver, mettre à jour reste la même ; les valeurs de MSE et de BCE ne se comparent pas. Pour isoler ensuite la non-linéarité, l'essai sans activation garde sigmoid, BCE et Adam.

À dire : Axon fournit la boucle que nous écrivions à la main. trainer assemble le modèle, la perte et l'optimiseur ; run part d'un état vide, tire des paramètres initiaux au hasard avec la graine 42, puis parcourt les données 200 fois. Chaque passage complet sur les données est une époque ; comme nos données forment un seul lot, une époque fait ici un seul pas. run rend un état qui contient beaucoup de choses, dont l'état d'Adam ; les paramètres appris se trouvent dans state.step_state.model_state. Gardez bien la distinction : model décrit le calcul, l'état contient les nombres. Repères : exemple de lecture d'API, pas une cellule autonome ; x et y sont les tenseurs du lot d'entraînement. Taux de référence 0.03 pour Adam, 200 époques : budget du carnet, pas un seuil universel. Une graine fixe reproduit le même tirage initial, sans promettre une identité bit à bit entre versions ou backends. Tirer les poids au hasard évite que toutes les unités cachées restent identiques.

À dire : Chaque essai sera décrit par une recette, une map qui consigne nos choix : la famille du modèle, la largeur de la couche cachée, l'activation, le taux, le nombre d'époques et la graine. Distinguez bien deux familles de nombres : les poids et les biais sont les paramètres, ajustés par l'entraînement ; ce qui est dans la recette, ce sont des hyperparamètres, choisis avant. Le carnet vous demande deux fonctions. model construit le réseau à partir de la recette, avec une clause pour le modèle linéaire, une seule sortie sigmoid, et une clause pour le modèle caché. fit lance la boucle que nous venons de voir, depuis un état vide, avec les réglages de la recette. Tout le reste est fourni : la grille de 144 points répartie en trois lots, dont seuls les 87 points d'entraînement servent ici, et les fonctions de mesure. Repères : contrôles du carnet : 33 paramètres, sortie {87, 1}, exactitude d'entraînement supérieure à 0.85. Pour :linear, largeur et activation valent nil ; pour :hidden, activation: :none garde la couche cachée sans non-linéarité, contre-exemple préparé pour l'atelier 03. Ne pas distribuer un programme complet dont on ne changerait que la taille de la couche.

À dire : Trois formes d'Elixir à connaître pour ce carnet. La mise à jour de map, avec la barre verticale, copie une map en remplaçant des clés existantes : c'est ainsi que l'on dérive une recette d'une autre. La capture &(&1.split < 3) est une abréviation de fn p -> p.split < 3 end, &1 désignant le premier argument. elem lit une case d'un tuple, en comptant à partir de 0. Enfin, comme en AP2, une fonction peut avoir plusieurs clauses qui reconnaissent leur argument par motif : une clause pour chaque famille de recette. À vous ! Repères : dernière minute de cours. Le carnet fournit la préparation des lots et le nom d'entrée points. Enum.zip_with et Map.put servent au dessin fourni. Pas de pipeline de fichiers ni de téléchargement de données.

À dire : Trente minutes pour le carnet 02. Comptez les paramètres avant de lancer la vérification, et regardez le dessin des prédictions : ressemble-t-il à nos quadrants ? Pour la dernière question, raisonnez sur papier ; nous mesurerons cet essai dans l'atelier suivant. Repères : 30 min. Les élèves écrivent model/1 et fit/3 à partir de leurs contrats. Garder une prédiction de forme et les points de contrôle : 33 paramètres, sortie {87, 1}. La visualisation fournie sert d'instrument, pas de nouvel objectif de programmation. Si Axon demande une reprise, fournir la configuration de référence en expliquant chaque brique.

À dire : Reprenons. Qu'a reçu le réseau ? Des coordonnées, des classes et une famille de fonctions à 33 paramètres ; nulle part la règle x fois y positif. Pourtant, le dessin ressemble à nos quadrants. Montrez-moi un point bien prédit, puis un point hésitant : où se trouve-t-il ? En général, près des axes, là où la classe change. Mais attention : ces points ont servi à l'entraînement, le dessin montre ce que le modèle a ajusté, pas ce qu'il ferait sur des points nouveaux. C'est la question de la dernière partie. Repères : reprise de 5 min. Regarder particulièrement les axes, où les classes changent. Notre jeu simple ne prouve pas que le réseau découvrirait n'importe quelle règle. Un modèle appris ne remplace pas une formule connue lorsqu'elle suffit au besoin réel.

À dire : Troisième partie : comment savoir si un modèle est bon ? Pas sur les points qui ont servi à l'entraîner : il les a vus, et un modèle assez souple pourrait les ajuster par cœur. Le carnet partage donc la grille de 144 points en trois lots fixés à l'avance. Le lot d'entraînement sert à calculer les gradients ; le lot de validation sert à comparer des recettes et à choisir ; le lot de test reste de côté jusqu'à la fin, pour mesurer une seule fois la recette retenue. Pourquoi ne pas choisir directement sur le test ? Repères : cours 03, 10 min jusqu'à la consigne. Partition déterministe par un reste modulo 5 des indices, avec les deux classes dans chaque lot. Le test n'est ni le lot suivant de la boucle ni un jeu sur lequel sélectionner une architecture. Une grille synthétique évalue un cas limité : aucune promesse sur des données réelles ou hors du carré.

À dire : Imaginez que vous essayiez dix architectures, que vous regardiez leur score sur le test et que vous gardiez la meilleure. Aucun gradient n'a été calculé sur le test, et pourtant il a servi à choisir : la meilleure des dix a pu gagner un peu par chance sur ces 28 points. Sur quelles données estimer maintenant ce choix ? Il en faudrait de nouvelles. Dès qu'un lot sert à choisir, il joue le rôle d'une validation, quel que soit son nom. C'est pourquoi nous comparons sur la validation et n'ouvrons le test qu'une fois. Repères : réponse attendue, de nouvelles données gardées à part ou un nouveau protocole décidé avant les essais. Les petits échantillons fluctuent : sur 29 points, une erreur de plus ou de moins déplace l'exactitude d'environ 3,4 points ; ne pas conclure sur un seul point de pourcentage.

À dire : Une comparaison n'apprend quelque chose que si elle ne change qu'un seul facteur. Le carnet vous donne trois recettes de référence : la recette tanh au taux 0.03, la même sans activation cachée, et la même avec un taux cent fois plus petit. Prédisez laquelle sera la meilleure en validation, et pourquoi. Notez avant d'exécuter ce que vous changez et ce que vous gardez : mêmes données, même graine, même budget, même perte. Quand on élargit la couche, la forme des poids change : la même graine donne alors un départ reproductible, mais pas les mêmes paramètres. Enfin, un réseau plus large peut faire baisser la perte d'entraînement sans améliorer la validation : c'est le surapprentissage, qu'il ne faut annoncer que si les mesures le montrent. Repères : références du carnet, avec les versions et la graine fixées : 93,1 %, 58,6 % et 48,3 % d'exactitude en validation ; repères de lecture, pas des scores à atteindre. Comparer les activations peut aussi changer la facilité d'optimisation. Ne pas promettre de surapprentissage sur une grille sans bruit ; une extension contrôlée réduit le train ou corrompt quelques-unes de ses cibles, sans toucher à la validation ni au test.

À dire : Une exactitude est une moyenne : elle dit combien d'erreurs, pas où elles sont. Pour voir où, on calcule les prédictions sur une grille fine de 31 par 31 points, sans réentraîner, et on les colorie : c'est la frontière de décision, la ligne où la sortie passe par 0.5. On peut aussi lister les erreurs de validation et regarder leur position. Sont-elles près des axes, là où la classe change ? Le modèle hésite-t-il, avec une sortie proche de 0.5, ou se trompe-t-il avec aplomb ? Ces observations servent à formuler votre prochaine hypothèse. Repères : le carnet fournit l'affichage et la liste des erreurs. Ne pas présenter les couleurs comme une preuve de calibration. Les points sur les axes ont la classe 0 par convention ; un modèle continu peut hésiter au voisinage de cette discontinuité. Le dessin est un outil de diagnostic, pas un nouveau score pour sélectionner.

À dire : Le carnet 03 commence par recopier vos modules Points et Classifier du carnet précédent. Vous écrivez ensuite une seule fonction, Trial.run : elle construit un modèle à partir de la recette, l'entraîne depuis un état vide, mesure pertes et exactitudes sur l'entraînement et la validation, et rend tout cela dans une map qui garde la recette. Conserver la recette dans le résultat évite de perdre ce qui a produit chaque mesure. Puis vient votre expérience : choisissez une question, changez un seul facteur, notez hypothèse, recette, mesures et limite. Une question est proposée sans protocole : comment distinguer « ce modèle ne peut pas représenter la règle » de « mon entraînement ne l'a pas encore apprise » ? Enfin, arrêtez votre choix sur la validation, et seulement alors ouvrez le test. Repères : BCE, Adam et les partitions restent fixes et sont notés en tête du tableau. Deux ou trois essais argumentés suffisent ; une recherche automatique ne remplace pas le raisonnement. Bruit, surapprentissage et nouvelles graines sont des prolongements.

À dire : Deux formes pour ce carnet. La recette est la même map qu'au carnet précédent, passée à Classifier.model et Classifier.fit. Dans la tête de run, le motif {train_x, train_y} = train décompose le tuple d'entraînement en deux tenseurs, tout en gardant le tuple entier sous le nom train ; on peut aussi utiliser elem. Pour choisir, Enum.max_by rend l'élément qui maximise une fonction, le premier en cas d'égalité. À vous ! Repères : pour :linear, width et activation valent nil ; activation: :none retire l'activation cachée d'un modèle :hidden. Une largeur différente implique des poids de dimensions différentes. Le test n'apparaît qu'après le choix arrêté. Map.take, Enum.zip et not in sont expliqués dans le carnet.

À dire : Quarante minutes pour le carnet 03 : c'est la partie la plus libre de la séance. Annoncez votre hypothèse avant chaque essai, gardez la recette complète avec ses mesures, et n'ouvrez le test qu'à la fin. Deux ou trois essais bien expliqués valent mieux qu'une longue liste. Repères : 40 min, à protéger. Les références tanh, sans activation et taux 0.0001 aident à lire deux difficultés ; chaque groupe choisit ensuite sa question. La question sans protocole demande un transfert, pas une API supplémentaire. Socle : comparaison contrôlée, décision fondée sur la validation, test final. Réduire les variantes si besoin.

À dire : Reprenons avec deux ou trois groupes. Quelle observation soutient votre choix, et quelle limite reconnaissez-vous ? Par ex., sans activation, la validation plafonne autour de 59 % : c'est cohérent avec une frontière affine. Avec un taux minuscule, elle reste à 48 % : la famille pourrait mieux faire, c'est l'entraînement qui n'a pas eu le temps. Et si vous vouliez maintenant essayer autre chose, sur quelles données le vérifieriez-vous ? Pas sur le test, déjà consulté : il rapporte le choix arrêté, mais une nouvelle phase de choix demande de nouvelles données réservées. Je valorise une expérience bien diagnostiquée, même si son exactitude est moins bonne. Repères : reprise de 5 min. Faire distinguer erreur de code, difficulté d'optimisation, limite du modèle et limite du jeu de données. Sur cette petite grille, un test sans erreur est possible : ni une preuve de perfection, ni une raison de masquer les erreurs de validation.

À dire : Faisons le bilan des deux séances. Vous savez préparer des données, décrire un calcul sur des tenseurs, mesurer une erreur, en suivre le gradient, et entraîner un petit réseau dont vous comprenez chaque brique. Ces mots, tenseur, perte, gradient, architecture, optimiseur, validation, sont ceux de PyTorch ou de JAX : ce que vous avez appris se transporte. Conservez vos carnets avec vos mesures et l'explication d'au moins un essai corrigé. Pour le quiz d'AP6, relisez le chapitre 8 du poly, de la perte jusqu'aux comparaisons. Pour finir, un exemple réel de ce que ces outils permettent. Repères : bilan de 5 min avec la page suivante. Le cours ne prétend pas couvrir la recherche en IA. Les prochaines séances abordent la concurrence. Les attendus du cycle et l'éventuel prolongement sont précisés en cours, pas dans ce support.

À dire : Vous vous souvenez d'Amplified, présentée en AP1 ? Cette entreprise aide à retrouver des brevets proches d'une invention. En 2024, son CTO montre comment ils adaptent un modèle de texte à des brevets en comparant des configurations, exactement ce que vous venez de faire, mais sur 64 GPU, avec les courbes suivies dans Livebook. Pour aller plus loin, Bumblebee charge des modèles déjà entraînés, et Nx.Serving expose un modèle à de nombreux appelants. Une question apparaît alors : comment lancer plusieurs calculs en même temps, récupérer leurs résultats et réagir si l'un tombe en panne ? C'est la concurrence, le sujet des prochaines séances. Repères : 2 min incluses dans le bilan. Le billet décrit un cas client Amplified, avec fine-tuning BERT et exploration d'hyperparamètres sur des machines L40s ; il présente une démonstration d'ElixirConf US 2024, distincte de la keynote européenne. Les GPU exécutent des essais distincts, ce n'est pas un entraînement unique distribué sur 64 GPU. Le tableau est un rapprochement pédagogique, pas l'architecture complète du produit.

À dire : Pour ceux qui veulent aller plus loin, ou si je l'annonce à la place de l'atelier d'expériences, ce carnet reprend exactement les mêmes questions sur de vraies images : des vêtements en 28 par 28 pixels, dix classes. Chaque image devient un vecteur de 784 nombres, et le réseau sort dix scores, un par classe. Vous écrirez le modèle, compterez ses paramètres avant de l'entraîner, puis regarderez quelles classes il confond. Il s'inspire du cours PyTorch de Sébastien Boisgérault. Repères : réserve, sans temps ajouté aux 180 min. Selon l'avancement, ce carnet remplace l'atelier d'expériences de 40 min ou se poursuit hors séance ; il ne s'ajoute pas au socle. Précharger les données si ce parcours est retenu. 12 730 paramètres pour la largeur 16 ; comparer modèle linéaire et MLP. Le lecteur IDX fait le lien avec les binaires d'AP3, sans devenir un prérequis. Validation et test restent distincts.