Comment le réseau d’AP5 calcule-t-il la dérivée de sa perte par rapport à tous ses paramètres ? En AP5, grad faisait ce travail pour nous. Dans ce prototype AP9, vous écrivez vous-même un petit moteur de différentiation automatique, c-à-d. un programme qui calcule les dérivées d’un calcul en suivant sa structure, sans formule symbolique ni approximation, puis vous l’utilisez pour apprendre XOR. Les graphes d’AP2–AP4 rencontrent ici le gradient d’AP5.

Télécharger le squelette Micrograd

Le projet commence en cours et se poursuit à la maison. Le README de l’archive donne le parcours complet : notions, représentations, fonctions, tests et expériences. Les modalités du projet noté seront annoncées avant le lancement ; les étapes ne sont pas un barème et les prolongements ne constituent pas un second projet.

Un graphe, des valeurs et des dérivées

Le moteur travaille sur des nombres ordinaires, sans tenseur. Chaque opération ajoute un nœud à un graphe de calcul : le nœud garde sa valeur, l’opération qui l’a produite et les identifiants de ses arguments. Une multiplication conserve ainsi les identifiants de ses deux arguments, même s’ils désignent la même valeur. Si une valeur est réutilisée, les contributions à sa dérivée doivent être additionnées. L’ordre de parcours fourni garantit que toutes ces contributions sont reçues avant de poursuivre.

Trois chemins depuis x contribuent à la dérivée de x² + x.

Lisons le schéma. Pour x*x + x, la valeur x alimente deux fois le produit et une fois l’addition. En x = 3, le produit renvoie deux contributions de 3 et l’addition une contribution de 1 : la dérivée totale vaut 7, ce que la formule 2x + 1 confirme. Pouvez-vous deviner ce que répondrait un moteur qui transformerait la liste des parents [x, x] en ensemble ? Il perdrait l’une des deux contributions du produit et répondrait 4 au lieu de 7.

Deux notions suffisent pour tout le projet. La dérivée locale d’une opération est sa dérivée par rapport à chacun de ses arguments, prise isolément : pour un produit a * b, c’est b pour a et a pour b. La propagation inverse, ou rétropropagation, part du résultat, dont la dérivée par rapport à lui-même vaut 1, et remonte vers les feuilles en multipliant la dérivée reçue par la dérivée locale de chaque argument, puis en additionnant les chemins qui se rejoignent : c’est la règle de la chaîne, appliquée nœud par nœud.

Le graphe reste immuable. Une map distincte contient les gradients ; chaque appel repart d’une map neuve, sans variable globale ni dictionnaire de processus. Les dérivées locales du produit et de tanh, puis la propagation inverse, sont vos trois fonctions à compléter, dans lib/micrograd_lab/backward.ex.

Démarrer et avancer

mix compile
mix test --only provided
mix run -e 'IO.inspect(MicrogradLab.Demo.forward())'

Ces commandes fonctionnent avant les trous : les quatre tests du code fourni passent, et le dernier appel affiche notamment value: 12.0, c-à-d. x*x + x en x = 3, calculé sans aucune dérivée. Poursuivez avec les dérivées locales (mix test --only local), la propagation (mix test --exclude training), puis le réseau (mix test). Le README introduit chaque règle au moment où vous en avez besoin, avec les fonctions Elixir utiles (Enum.reduce/3, Enum.zip/2, Map.update/4).

Le graphe, son parcours, le petit réseau 2–4–1 (deux entrées, quatre neurones cachés, une sortie, soit 17 paramètres), la boucle d’apprentissage et le dessin sont fournis. Elixir suffit, sans bibliothèque numérique ni GPU. Vous n’avez aucun code web à écrire. Le dernier essai exporte une courbe CSV et une image SVG avec mix run -e 'MicrogradLab.Demo.run()'.

Une vérification indépendante accompagne votre moteur : les différences finies approchent une dérivée par (f(x + h) - f(x - h)) / (2h), avec deux évaluations ordinaires et sans votre algorithme. Le test du réseau compare ainsi vos 17 dérivées à cette approximation. Pourquoi un h extrêmement petit ne donne-t-il pas forcément une meilleure mesure ? La réponse tient à la précision des flottants ; gardez-la pour le compte rendu.

Ce que vous devez pouvoir expliquer

Conservez un exemple de valeur utilisée plusieurs fois, une comparaison avec les différences finies et une expérience sur l’apprentissage (le taux, le nombre de pas, ou les gradients de tanh sur de grandes valeurs), en ne changeant qu’un réglage à la fois. Les quatre points XOR sont les données apprises ; leur classification correcte ne mesure pas la généralisation à des observations nouvelles, et le fond du dessin montre une prédiction du modèle, pas une vérité de référence.

Votre projet conserve le code, vos tests personnels, une recette de lancement et un compte rendu qui explique un graphe partagé, la vérification numérique et l’expérience choisie. Le dossier out/ est ignoré par Git : copiez les CSV et SVG retenus dans rendu/. En quittant la séance, notez le prochain point de passage.

Le parcours topologique, une nouvelle opération ou les nombres duaux offrent des prolongements après le socle. L’idée s’inspire de micrograd de Karpathy, avec un état explicite adapté à Elixir.

Revenir aux sujets par thème.

Pour toute question, vous pouvez me contacter par email : aurelien.noce@minesparis.psl.eu.

Pour les curieux : le fascicule

Un petit fascicule d’approfondissement accompagne ce sujet : les idées derrière le projet, leur histoire, ce qu’elles deviennent dans les systèmes réels et quoi lire ensuite. C’est un cadeau de fin de cours ; rien n’y est à rendre.

Ouvrir le fascicule (PDF)