- La rétropropagation (backpropagation) est au cœur de l’apprentissage des réseaux de neurones, mais si l’on ne comprend pas son fonctionnement interne, elle peut provoquer des erreurs inattendues dans une structure d’« abstraction qui fuit » (leaky abstraction)
- Les fonctions d’activation sigmoid et tanh peuvent entraîner un vanishing gradient si l’initialisation des poids est incorrecte, au point de bloquer l’apprentissage
- ReLU peut provoquer le phénomène de dead ReLU, où un neurone devient définitivement inactif lorsque son entrée est inférieure ou égale à 0
- Dans les RNN, des multiplications répétées de matrices peuvent entraîner un exploding gradient ; pour l’éviter, il faut utiliser le gradient clipping ou des LSTM
- Sans compréhension du fonctionnement de la rétropropagation, même si le framework la gère automatiquement, les capacités de debugging et d’amélioration du modèle chutent fortement
Pourquoi il faut comprendre la rétropropagation
- Dans le cours CS231n de Stanford, les devoirs demandent aux étudiants d’implémenter eux-mêmes la propagation avant et la rétropropagation
- Certains étudiants se plaignent que ce soit inutile, puisque des frameworks comme TensorFlow calculent automatiquement la rétropropagation
- Mais la rétropropagation n’est pas une abstraction complète, c’est une abstraction qui fuit : sans comprendre son fonctionnement interne, il devient difficile d’identifier pourquoi l’apprentissage échoue
- Se contenter de dire que « le framework s’en occupe » conduit à une dégradation des compétences en conception de modèles et en debugging
Le vanishing gradient avec la sigmoid
- Les fonctions non linéaires sigmoid et tanh entrent en saturation lorsque la valeur d’entrée est grande, et la sortie se rapproche alors de 0 ou de 1
- À ce moment-là, le gradient local z(1-z)* devient nul, ce qui bloque la propagation du gradient pendant la rétropropagation
- Le gradient maximal d’une sigmoid est de 0,25 ; à chaque passage, le signal est donc réduit à 1/4 ou moins
- En conséquence, la vitesse d’apprentissage des couches inférieures devient nettement plus lente que celle des couches supérieures
- Lorsqu’on utilise des couches sigmoid, il faut donc accorder une attention particulière à l’initialisation des poids et au prétraitement des données
Le problème des dead ReLU
- ReLU est une fonction qui renvoie 0 lorsque l’entrée est inférieure ou égale à 0
- Si, en propagation avant, la sortie d’un neurone est 0, alors pendant la rétropropagation, le gradient devient lui aussi 0, et ce neurone peut devenir définitivement inactif
- Pendant l’apprentissage, de grosses mises à jour de poids ou un taux d’apprentissage élevé peuvent figer un neurone dans un « état mort »
- Il arrive aussi qu’après l’apprentissage, une part importante des neurones du réseau produise 0
- Avec ReLU, le réglage du taux d’apprentissage et la stratégie d’initialisation sont donc essentiels
L’exploding gradient dans les RNN
- Dans un RNN simple, la même matrice d’état caché (Whh) est multipliée de façon répétée à chaque pas de temps
- Lors de la rétropropagation, selon la taille des valeurs propres (eigenvalues) de cette matrice, le gradient peut converger vers 0 ou croître à l’infini
- Si |b| < 1, on obtient un vanishing gradient ; si |b| > 1, un exploding gradient se produit
- Pour l’éviter, on applique en général du gradient clipping ou on utilise une architecture LSTM
Exemple de mauvais clipping dans du code DQN
- Dans une implémentation DQN basée sur TensorFlow, on a trouvé du code qui appliquait directement
tf.clip_by_value au delta (erreur Q)
- Avec cette approche, dès que le delta sort de l’intervalle, le gradient devient nul et l’apprentissage s’arrête
- L’intention était de faire du gradient clipping ; il faut donc utiliser à la place une Huber loss
- Dans l’exemple de code, la perte de Huber est implémentée de manière conditionnelle en combinant
tf.square et tf.abs
- Le problème a été signalé via une issue GitHub et corrigé immédiatement
Conclusion
- La rétropropagation n’est pas un simple outil d’automatisation, mais un mécanisme d’attribution du crédit (credit assignment) qui entraîne des conséquences complexes
- Sans compréhension de son fonctionnement interne, on se heurte à l’instabilité des modèles, aux échecs d’apprentissage et aux limites du debugging
- La rétropropagation n’est pas difficile mathématiquement, et on peut l’apprendre de manière intuitive grâce au cours CS231n et à ses devoirs
- Comprendre la rétropropagation améliore fortement la conception des réseaux de neurones et la capacité à résoudre les problèmes
- Plutôt que de dépendre uniquement de la différentiation automatique du framework, il est important de maîtriser le flux réel de la rétropropagation
1 commentaires
Commentaires sur Hacker News
On a l’impression que backpropagation se prend ici une mauvaise réputation de façon injustifiée
En réalité, cette discussion porte moins sur la rétropropagation elle-même que sur à quel point les gradients et les variantes de gradient descent constituent une abstraction imparfaite du processus d’optimisation
La rétropropagation n’est qu’un algorithme pour calculer la dérivée d’une fonction composée, et des problèmes comme la disparition du gradient causée par l’empilement de sigmoïdes ne sont pas des problèmes de rétropropagation, mais des propriétés de la fonction elle-même
Si on demande aux gens d’implémenter eux-mêmes la backward pass, c’est pour qu’ils ressentent concrètement, en calculant directement les dérivées, comment les termes exponentiels interviennent
L’essentiel, c’est que dans certaines situations on ne peut pas abstraire les détails de la rétropropagation, y compris le calcul du gradient
C’est particulièrement vrai quand on utilise gradient descent, et le problème peut être moindre avec d’autres algorithmes d’optimisation globale
Comme, en pratique aujourd’hui, la rétropropagation est la seule manière de calculer les gradients en deep learning, cette fuite d’abstraction est bien réelle
Je respecte la contribution de Karpathy, mais ses textes et ses conférences ont souvent tendance à brouiller les distinctions conceptuelles, ce qui crée des malentendus
À son niveau, on s’attend à une précision plus élevée
La contribution de Karpathy à l’enseignement du deep learning est vraiment énorme
Des billets courts jusqu’au texte de référence sur les RNN, en passant par ses cours sur YouTube et ses projets GitHub, tout est excellent
Le récent nanochat en est aussi un très bon exemple : un exemple complet, petit et clair aide énormément les personnes qui apprennent
Plus tard, j’ai compris qu’ils s’intéressaient davantage à faire confiance aux LLM et les utiliser qu’à les comprendre
En pratique, le fonctionnement des LLM les intéressait moins que des discussions spéculatives du type « une société où des machines intelligentes font tout »
Au lieu de simplement « demander à ChatGPT », il cherche lui-même, lit le code et trouve des bugs
Cette démarche d’exploration est un véritable apprentissage
En master, j’ai eu un devoir consistant à implémenter la rétropropagation à partir d’un article
Il fallait écrire la forward pass et la backward pass uniquement avec des opérations mathématiques, et ça a été ma meilleure expérience d’apprentissage de l’année
C’est le genre de travail qu’on ne fait pas spontanément, mais qui aide énormément quand on est obligé de le faire
J’avais aussi créé une UI pour visualiser comment les poids et les biais évoluaient pendant l’entraînement
Je me suis interrogé sur la relation entre la rétropropagation et l’optimizer
SGD se contente d’avancer dans la direction du gradient, mais des optimizers plus sophistiqués comme Adam n’utilisent pas le gradient tel quel : ils appliquent normalisation, momentum, clipping, etc.
Dans ce cas, a-t-on vraiment besoin d’un gradient exact, ou suffit-il de connaître approximativement la bonne direction ?
On peut citer les articles sur le bruit dans SGD et les travaux de visualisation
Mais estimer la direction « à peu près » reste risqué — la courbure de la fonction de loss (Hessian) peut varier brutalement
En pratique, c’est ce type d’idée qui a donné stochastic gradient descent, et on trouve aussi des approches comme Direct Feedback Alignment
Le résumé de Ben Recht sur le lien entre optimisation et apprentissage par renforcement est aussi intéressant
Ce qui compte, ce n’est pas tant la valeur de la loss que la forme du gradient et de la courbure
Des optimizers comme Adam ajustent le gradient en estimant, via une approximation du premier ordre, la sensibilité d’échelle de chaque paramètre
Une optimisation d’ordre supérieur est impossible avec des fonctions non linéaires comme ReLU
C’est une mesure indispensable pour résoudre le problème du vanishing gradient
Dans un espace de grande dimension, même une petite erreur peut avoir de gros effets, donc un calcul précis du gradient est très important
Le vrai problème, c’est déjà de savoir comment calculer cette « direction approximative »
Même des optimizers avancés comme AdamW reposent toujours fondamentalement sur le gradient
Vers 2016, j’ai l’impression qu’on utilisait bien plus souvent des astuces comme le gradient clipping
Par exemple, dans son article de 2013 Sequence Generation with RNNs, Alex Graves indique aussi avoir utilisé du clipping pour éviter l’explosion du gradient dans les LSTM
J’avais même suivi un cours spécialisé uniquement sur l’autograd de PyTorch, tellement l’importance de la rétropropagation me paraissait claire
Aujourd’hui, les frameworks prennent en charge le clipping, et la compréhension des problèmes d’entraînement s’est améliorée
Mais le problème lui-même n’a pas disparu — ReLU ou GELU restent des fonctions d’activation de base, et l’entraînement des LLM reste encore proche de l’« art noir »
Le Smol Training Playbook de Hugging Face en est la preuve
À long terme, je pense qu’il pourrait être avantageux d’entraîner des modèles robustes à la diversité des fonctions d’activation
Par exemple, on pourrait alterner aléatoirement entre ReLU, Swish, GELU, etc. pendant l’entraînement, afin d’obtenir une sorte d’effet de régularisation comparable au dropout
On pourrait alors, à l’inférence, remplacer ces fonctions par celle qui coûte le moins cher en calcul
Le titre d’origine, « Yes you should understand backprop », était bien plus clair et meilleur
Quand le code fait trop de choses à votre place, on tombe facilement dans l’illusion que « ça marche par magie »
Le fait d’avoir calculé moi-même à la main les convolutions et la rétropropagation en école doctorale m’a beaucoup aidé
La question « si le framework calcule automatiquement la backward pass, pourquoi faudrait-il l’écrire soi-même ? »
repose sur la même logique inquiétante que « pourquoi apprendre l’addition s’il existe des calculatrices ? »
De la même manière qu’il est utile de comprendre les compilateurs, les algorithmes de tri ou le fonctionnement des transistors, apprendre la rétropropagation a de la valeur
Mais le temps d’apprentissage est limité, donc la vraie question est de savoir si cela est plus utile que d’autres sujets
La rétropropagation mérite d’être étudiée parce que, si l’on ne comprend pas son fonctionnement interne, il devient difficile d’identifier ses modes de défaillance cachés
Je l’ai moi-même implémentée plusieurs fois, et c’est exactement le bon niveau de complexité pour évaluer un nouveau langage
Quand j’ai commencé à apprendre le deep learning, la rétropropagation me paraissait quasi magique
Mais en l’implémentant moi-même, j’ai découvert qu’il ne s’agissait que d’une suite de calculs simples, ce qui m’a donné bien plus de confiance pour déboguer ou comprendre pourquoi la loss stagnait
Si vous apprenez le deep learning, je recommande de l’implémenter vous-même au moins une fois
Il existe aussi un point de vue opposé
Je ne pense pas qu’il soit nécessaire que les étudiants implémentent la rétropropagation en NumPy
Les problèmes de fuite d’abstraction de BackProp seront résolus par les chercheurs avec de nouveaux optimizers, et les développeurs n’auront plus qu’à trouver de bons hyperparamètres
Une partie du problème vient de la conception du modèle ou de la boucle d’entraînement
Par exemple, le gradient clipping n’est pas la valeur par défaut dans la plupart des frameworks
Ce texte s’adresse à des lecteurs ayant une perspective de recherche ou universitaire
Si l’on ne comprend pas le comportement du gradient pour des fonctions comme sigmoid ou ReLU, on ne peut pas résoudre les problèmes d’explosion ou de disparition
Pour créer de nouvelles architectures de modèles, il faut comprendre le fonctionnement de la rétropropagation ; sinon, l’entraînement échoue ou les performances se dégradent
C’est en perçant les abstractions qu’on découvre enfin les véritables zones d’ignorance (unknown unknowns)