Files
perceptron-viewer/public/helptext/gradientdescent.md
T
Ninluc 6d4fdffee9
linter / quality (push) Successful in 5m1s
tests / ci (8.4) (push) Successful in 5m8s
tests / ci (8.5) (push) Successful in 6m31s
Wiki
2026-09-15 19:44:58 +02:00

9.9 KiB

La Descente du gradient

Comme on a pu le voir, le Perceptron présente quelques limitations :

  • Il est incapable de faire de la régression
  • Il n'optimise pas sa solution, la limite de décision "colle" les points du dataset.

La descente du gradient essaye d'améliorer l'algorithme d'entraînement et rend les valeurs des entrées et des sorties réelles (des nombres à décimale, positifs, négatifs ou nuls).

La descente du gradient n'essaye plus de ne plus faire aucune erreur comme le Perceptron, mais à la place va essayer de minimiser l'erreur quadratique moyenne (d'avoir une erreur quadratique moyenne la plus petite possible). Cette méthode de minimisation de l'erreur est appelée descente du gradient. L'erreur quadratique moyenne est calculée comme suit : la somme de l'erreur du réseau sur tous les exemples du dataset au carré, le tout divisé par 2. Cela revient à faire

E = \frac{1}{2} \sum^K_{k=1}{(e^{(k)})^2}

où :

  • E est l'erreur quadratique moyenne.
  • K le nombre d'exemples dans le dataset.
  • e^{(k)} l'erreur du réseau sur l'exemple k du dataset. (e = \text{ label } - y)

Structure de la Descente du gradient

La structure ne change pas par rapport au Perceptron simple, si ce n'est que la fonction d'activation est maintenant une droite y = x. Cela veut dire que la descente du gradient retourne des valeurs réelles non bornées.

Schéma général de la structure d'un neurone avec la descente du gradient

Fonctionnement de l'entraînement

Par rapport au Perceptron, la correction des poids se fait après chaque époque, et la condition de fin d'entraînement s'établit sur l'erreur quadratique moyenne.

  1. On initialise les poids synaptiques.
  2. On commence l'entraînement : pour chaque exemple du dataset choisi, on évalue la sortie du Perceptron (y).
  3. On fait le calcul de l'erreur (notée e), en soustrayant la sortie du Perceptron à la sortie attendue (le label). Comme l'entrée et la sortie de la descente du gradient sont des réels, ici l'erreur est plus précise que le perceptron qui avait une erreur de -1, 0 ou 1.
  4. On calcule, pour chaque poids synaptique, un signal d'erreur simmilaire au perceptron. Le signal d'erreur est égal à l'erreur multipliée par la donnée de l'exemple assignée à cette l'entrée, multipliée par le Taux d'apprentissage. Ce signal est ajouté à une variable de correction (notée Dw_1, Dw_2, Dw_3, ...) qui garde la somme des signaux d'erreurs pour chaque poids synaptique. Cette variable de correction est utilisée car on ne modifie les poids synaptiques qu'à la fin de l'époque, quand tous les exemples ont été évalués.
  5. Une fois tous les exemples du dataset parcourus, on actualise les poids synaptiques en appliquant leur variable de correction respectives.
  6. On calcule l'erreur quadratique moyenne (E) avec les nouveaux poids.
  7. Si l'erreur quadratique moyenne est plus petite que l'erreur minimale ou que le nombre maximal d'époques a été atteint, l'entraînement est terminé. Sinon, on recommence à partir du point 2. L'erreur minimale est un paramètre détaillé plus bas.
Reprenons le dataset oblique utilisé avec le Perceptron afin de vérifier que la descente du gradient corrige bien ses limitations :
  • Dataset : Classification - Oblique (linéairement séparable)

Puis cliquez sur "Lancer" tout en laissant les autres paramètres intacts.

On peut voir que la ligne de décision est au centre entre les deux classes, et qu'elle ne colle pas aux points. Toutefois un point négatif que l'on peut noter est qu'il est bien plus lent. Le nombre d'itérations est au-dessus de 1000 comparé à une centaine pour le perceptron.

Qu'est-ce que l'Erreur minimale fait ?

L'erreur minimale est un paramètre choisi par le développeur, c'est le seuil que le réseau doit atteindre pour pouvoir terminer l'entraînement. Plus le seuil est bas, plus le réseau doit être précis avant de pouvoir arrêter l'entraînement.

Avec une erreur minimale trop basse

L'on pourrait alors se dire de mettre l'erreur minimale à 0, pour avoir un modèle le plus précis possible.

Reprenons le dataset oblique afin de pouvoir comparer les résultats, et diminuons l'erreur minimale :
  • Dataset : Classification - Oblique (linéairement séparable)
  • Erreur minimale : en dessous de 0.05 ou même 0

Puis cliquez sur "Lancer" tout en laissant les autres paramètres intacts.

On peut voir en dessous du tableau que l'entraînement s'est arrêté car le nombre maximal d'époques a été atteint. On pourrait l'augmenter (max 5000 pour mon petit serveur), mais ce serait du temps perdu. La solution du réseau est suffisante et il n'y aurait pas beaucoup de gain, même pour le triple d'itérations maximales en plus. Pour le prouver, cliquez sur le bouton Afficher uniquement l'erreur quadratique moyenne, la ligne que l'on peut voir ressemble fortement à la fonction logarithme y = log(x^{-1}). La progression de la descente du gradient est donc logarithmique ; les plus gros changements se font dans les premières époques.

Avec une erreur minimale trop haute

Alors que fait une erreur minimale mise trop haute par le développeur ?

Reprenons le dataset oblique afin de pouvoir comparer les résultats, et augmentons l'erreur minimale :
  • Dataset : Classification - Oblique (linéairement séparable)
  • Erreur minimale : au-dessus de 0.15 (ex: 0.2)

Puis cliquez sur "Lancer" tout en laissant les autres paramètres intacts.

L'entraînement est très rapide, même un peu trop rapide... Le réseau ne donne pas une bonne solution, voire une solution sur laquelle l'entraînement du perceptron ne se serait pas arrêté.

Comment choisir une bonne valeur pour l'erreur minimale ?

Une méthode consiste à mettre l'erreur minimale à 0, mettre le nombre maximum d'époques à une valeur très haute, et surveiller l'erreur quadratique moyenne : si elle stagne, le réseau ne fera plus beaucoup d'avancées sur un nombre raisonnable d'époques.

Qu'est-ce que le Taux d'Apprentissage fait ?

Comme expliqué dans le processus d'entraînement du Perceptron et de la descente du gradient, le taux d'apprentissage est un paramètre permettant de contrôler avec quelle "force" les poids synaptiques se mettent à jour.

Avec un Taux d'Apprentissage trop haut

Reprenons le même dataset oblique que le test contrôle, mais en augmentant considérablement le Taux d'Apprentissage :
  • Dataset : Classification - Oblique (linéairement séparable)
  • Taux d'apprentissage : au dessus de 0.001 (ex: 0.002)
  • (Optionnel) Nombre maximum d'époques : 200

Puis cliquez sur "Lancer" tout en laissant les autres paramètres intacts.

Les valeurs des graphes et du tableau vont dans les extrêmes (même à NaN ("Not A Number")). À cause du taux d'apprentissage trop haut, à chaque correction des poids synaptiques, leurs valeurs ont augmentées de façon exponentielle. Créant un cycle vicieux.

Avec un Taux d'Apprentissage trop bas

Reprenons le même dataset oblique que le test contrôle, mais en diminuant considérablement le Taux d'Apprentissage :
  • Dataset : Classification - Oblique (linéairement séparable)
  • Taux d'apprentissage : en dessous de 0.0005 (ex: 0.0001)
  • (Optionnel) Nombre maximum d'époques : 4000

Puis cliquez sur "Lancer" tout en laissant les autres paramètres intacts.

L'entraînement est beaucoup plus long, le réseau atteint même peut-être le nombre maximum d'époques. Cela est dû à la correction des poids synaptiques qui est devenue plus petite à chaque époque. L'on pourrait enlever la limite du nombre maximum d'époques, attendre un peu plus longtemps, et avoir un résultat précis. Mais, le temps, c'est de l'argent. Faisons le parallèle avec OpenAI : l'entraînement d'un nouveau modèle coûte des millions de dollars en puissance de calcul et peut prendre des mois entiers. Si l'on réduit la vitesse à laquelle le modèle s'entraîne, la facture de l'entraînement peut vite être salée.

En note annexe : dans les frameworks actuels, cette variable est gérée automatiquement et je ne pense pas qu'elle pose vraiment un problème à OpenAI.

Comment choisir une bonne valeur pour le taux d'apprentissage ?

À l'essai et erreur ! Commencer avec une valeur arbitraire et diminuer tant que les poids synaptiques partent dans des valeurs infiniment grandes. Augmenter dans le cas contraire jusqu'à trouver une bonne valeur.

Test avec la régression

Comme dit dans l'introduction, quand un réseau de neurones fait de la régression, il essaye de créer la fonction mathématique qui épouse au mieux le nuage de données du dataset. Une des limitations du perceptron est le fait qu'il est incapable de faire de la régression. Grâce à ses entrées et sorties réelles, la descente du gradient est capable de faire de la régression.

Testons la régression avec un dataset simple :
  • Dataset : Régression - Oblique

Une fois sélectionné, on peut voir que le nuage de points du dataset forme presque une droite oblique. Imaginer une droite qui traverse au mieux tous les points, c'est-à-dire une droite qui est le plus proche possible de tous les points en même temps.

Cliquez sur "Lancer" tout en laissant les autres paramètres intacts.

On peut constater que la droite se dirige rapidement au bon endroit, le reste des époques ne font que du peaufinage. La descente du gradient essaye de minimiser l'erreur sans essayer de n'en faire aucune, ce qui est parfait comme avec un dataset comme celui-ci, il est impossible de relier tous les points avec une droite, et donc impossible de ne pas faire d'erreur.