Wiki
@@ -0,0 +1,72 @@
|
||||
# ADAptative LINear Element
|
||||
|
||||
ADALINE est une variante de la descente du gradient
|
||||
|
||||
La descente du gradient attend d'avoir évalué chaque exemple du dataset avant de corriger les poids synaptiques et de calculer l'erreur quadratique moyenne. ADALINE rends le processus plus rapide en corrigeant les poids à chaque exemple, comme le Perceptron.
|
||||
|
||||
On peut considérer ADALINE comme un Perceptron avec la fonction linéaire comme fonction d'activation et une condition d'arrêt de l'entraînement qui utilise l'erreur quadratique moyenne.
|
||||
|
||||
## Structure d'ADALINE
|
||||
|
||||
Pas de changement par rapport à la structure de la Descente du gradient.
|
||||
|
||||

|
||||
|
||||
## Fonctionnement de l'entraînement
|
||||
|
||||
En comparaison à la Descente du gradient, la correction des poids se fait à chaque évaluation d'un exemple, comme pour le Perceptron.
|
||||
|
||||
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*).
|
||||
4. On met à jour les poids synaptiques avec la même formule que le Perceptron : on ajoute à la valeur du poids l'erreur multipliée par la valeur de l'exemple assignée à l'entrée, multipliée par le **Taux d'apprentissage**. Ce qui donne : $w_i' = w_i + \eta \times (\text{label } - y) \times x_i$ pour tout poids synaptique $i$ où $w_i'$ est le poids synaptique corrigé et $x_i$ est l'entrée numéro $i$.
|
||||
5. Une fois tous les exemples du dataset parcourus, on calcule l'erreur quadratique moyenne ($E$) avec les derniers poids synaptiques.
|
||||
6. 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.
|
||||
|
||||
<div class="exercice">
|
||||
Reprenons le dataset oblique afin de faire un test contrôle :
|
||||
|
||||
- <span>Dataset</span> : `Classification - Oblique (linéairement séparable)`
|
||||
|
||||
Puis cliquez sur "Lancer" tout en laissant les autres paramètres intacts.
|
||||
|
||||
Cliquez sur le bouton `Afficher uniquement l'erreur quadratique moyenne`, la ligne que l'on peut voir est moins "douce" et contient des "bosses" avec les mêmes paramètres que la descente du gradient. Cela est dû au fait que les corrections se font à chaque exemple du dataset. Le taux d'apprentissage devrait être mis un peu plus bas pour faire disparaître ces "bosses", mais ici elles sont encore petites et ne posent pas de problèmes.
|
||||
</div>
|
||||
|
||||
## Ajustements du Taux d'apprentissage
|
||||
|
||||
La descente du gradient est plus lente que le Perceptron. Est-ce qu'ADALINE règle ce problème ?
|
||||
|
||||
<div class="exercice">
|
||||
Reprenons le dataset oblique afin de pouvoir comparer les résultats, et augmentons un peu le taux d'apprentissage :
|
||||
|
||||
- <span>Dataset</span> : `Classification - Oblique (linéairement séparable)`
|
||||
- <span>Taux d'apprentissage</span> : entre $0.002$ et $0.01$ (ex: $0.005$)
|
||||
- (Optionnel) <span>Nombre maximum d'époques</span> : $1000$ (plus d'époques seront affichées)
|
||||
|
||||
Puis cliquez sur "Lancer" tout en laissant les autres paramètres intacts.
|
||||
|
||||
On peut voir que le nombre d'époques que l'entraînement a pris est bien plus petit : de 200 à 900 époques en fonction du taux d'apprentissage choisi, contre presque 2000 pour le test contrôle.
|
||||
|
||||
Cliquez sur le bouton `Afficher uniquement l'erreur quadratique moyenne`, la ligne que l'on peut observer est encore moins douce. Les "bosses" sont amplifiées à cause de la hausse du taux d'apprentissage.
|
||||
</div>
|
||||
|
||||
|
||||
### Avec un taux d'apprentissage trop haut
|
||||
|
||||
On a déjà vu avec la descente du gradient ce que faisait un taux d'apprentissage trop bas et trop haut. Mais comme on le voit, l'erreur quadratique moyenne du perceptron forme des bosses qui s'amplifient avec le taux d'apprentissage. Que se passe-t-il alors quand le paramètre est trop haut ?
|
||||
|
||||
<div class="exercice">
|
||||
Reprenons le dataset oblique afin de pouvoir comparer les résultats, et augmentons le taux d'apprentissage à une valeur trop grande :
|
||||
|
||||
- <span>Dataset</span> : `Classification - Oblique (linéairement séparable)`
|
||||
- <span>Taux d'apprentissage</span> : $0.023$
|
||||
|
||||
Puis cliquez sur "Lancer" tout en laissant les autres paramètres intacts.
|
||||
|
||||
Les erreurs vacillent et le neurone a du mal à converger.
|
||||
|
||||
Cliquez sur le bouton `Afficher uniquement l'erreur quadratique moyenne`, les bosses de la ligne sont trop amplifiées et l'entraînement se joue sur la chance de tomber sur le bon prochain exemple. Relancer l'entraînement plusieurs fois et vous aurez des nombres d'époque finale différents. Ce n'est bien sûr pas optimal sauf si l'on se sent chanceux.
|
||||
</div>
|
||||
|
||||
Mettre une valeur de taux d'apprentissage encore plus haute va donner le même résultat que la descente du gradient : des valeurs de poids qui s'emballent dans des extrêmes.
|
||||
@@ -0,0 +1,9 @@
|
||||
<div class="exercice">
|
||||
Reprenons le dataset oblique afin de pouvoir comparer les résultats, et diminuons l'erreur minimale :
|
||||
|
||||
- <span>Dataset</span> : `Classification - Oblique (linéairement séparable)`
|
||||
- <span>Erreur minimale</span> : en dessous de $0.05$ ou même $0$
|
||||
- (Optionnel) <span>Nombre maximum d'époques</span> : $4000$
|
||||
|
||||
Puis cliquez sur "Lancer" tout en laissant les autres paramètres intacts.
|
||||
</div>
|
||||
@@ -0,0 +1,137 @@
|
||||
# La Descente du gradient
|
||||
|
||||
Comme on a pu le voir, le [Perceptron](/perceptron?type=simple) 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.
|
||||
|
||||

|
||||
|
||||
## 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.
|
||||
|
||||
<div class="exercice">
|
||||
Reprenons le dataset oblique utilisé avec le Perceptron afin de vérifier que la descente du gradient corrige bien ses limitations :
|
||||
|
||||
- <span>Dataset</span> : `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.
|
||||
</div>
|
||||
|
||||
## 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.
|
||||
|
||||
<div class="exercice">
|
||||
Reprenons le dataset oblique afin de pouvoir comparer les résultats, et diminuons l'erreur minimale :
|
||||
|
||||
- <span>Dataset</span> : `Classification - Oblique (linéairement séparable)`
|
||||
- <span>Erreur minimale</span> : 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.
|
||||
|
||||
</div>
|
||||
|
||||
### Avec une erreur minimale trop haute
|
||||
|
||||
Alors que fait une erreur minimale mise trop haute par le développeur ?
|
||||
|
||||
<div class="exercice">
|
||||
Reprenons le dataset oblique afin de pouvoir comparer les résultats, et augmentons l'erreur minimale :
|
||||
|
||||
- <span>Dataset</span> : `Classification - Oblique (linéairement séparable)`
|
||||
- <span>Erreur minimale</span> : 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é.
|
||||
</div>
|
||||
|
||||
### 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
|
||||
|
||||
<div class="exercice">
|
||||
Reprenons le même dataset oblique que le test contrôle, mais en augmentant considérablement le Taux d'Apprentissage :
|
||||
|
||||
- <span>Dataset</span> : `Classification - Oblique (linéairement séparable)`
|
||||
- <span>Taux d'apprentissage</span> : au dessus de $0.001$ (ex: $0.002$)
|
||||
- (Optionnel) <span>Nombre maximum d'époques</span> : $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.
|
||||
</div>
|
||||
|
||||
### Avec un Taux d'Apprentissage trop bas
|
||||
|
||||
<div class="exercice">
|
||||
Reprenons le même dataset oblique que le test contrôle, mais en diminuant considérablement le Taux d'Apprentissage :
|
||||
|
||||
- <span>Dataset</span> : `Classification - Oblique (linéairement séparable)`
|
||||
- <span>Taux d'apprentissage</span> : en dessous de $0.0005$ (ex: $0.0001$)
|
||||
- (Optionnel) <span>Nombre maximum d'époques</span> : $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.
|
||||
</div>
|
||||
|
||||
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.
|
||||
|
||||
<div class="exercice">
|
||||
Testons la régression avec un dataset simple :
|
||||
|
||||
- <span>Dataset</span> : `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.
|
||||
</div>
|
||||
|
After Width: | Height: | Size: 72 KiB |
|
After Width: | Height: | Size: 17 KiB |
|
After Width: | Height: | Size: 199 KiB |
|
After Width: | Height: | Size: 28 KiB |
|
After Width: | Height: | Size: 57 KiB |
|
After Width: | Height: | Size: 165 KiB |
|
After Width: | Height: | Size: 28 KiB |
|
After Width: | Height: | Size: 39 KiB |
|
After Width: | Height: | Size: 28 KiB |
@@ -0,0 +1,96 @@
|
||||
# Perceptron Viewer
|
||||
|
||||
Cet outil vous permet d'expérimenter avec les réseaux de neurones et les perceptrons. Vous pouvez ajuster les paramètres et observer l'apprentissage en temps réel.
|
||||
|
||||
## Contexte
|
||||
|
||||
Ce projet a été d'abord créé pour un cours de réseaux de neurones artificiels que j'ai suivi durant mon master en Architecture des Systèmes Informatiques à la Haute École de la Province de Liège. Il s'agit ici d'une version plus conviviale, documentée et optimisée. Cependant le projet n'est pas très mobile friendly et je conseille l'utilisation d'un écran horizontal. 📵
|
||||
|
||||
Je conseille de finir de lire les prochains chapitres qui traitent des bases des réseaux de neurones et qui présentent l'interface. Je conseille ensuite d'utiliser les onglets au-dessus de la page dans l'ordre indiqué. Chaque onglet présente une évolution des réseaux de neurones dans l'ordre chronologique des découvertes et des améliorations faites.
|
||||
|
||||
## Introduction aux Réseaux de Neurones Artificiels
|
||||
|
||||
Le but principal d'un réseau de neurones artificiels est de **reproduire une fonction mathématique complexe**. En résumé, un réseau de neurones est conçu pour apprendre des relations complexes entre des données d'entrée et des données de sortie (la prédiction souhaitée). Il apprend à faire correspondre une entrée $X$ à une sortie $Y$ via une série de calculs pondérés et d'activations.
|
||||
|
||||
### Premières Découvertes des neurones artificiels
|
||||
|
||||
Les bases des réseaux de neurones remontent à la modélisation biologique du cerveau. Les premières tentatives par un neuropsychiatre et logicien vers 1943 visaient à créer des modèles simplifiés pour comprendre comment le cerveau traite l'information. Il s'agissait de **simuler la capacité du cerveau à apprendre et à prendre des décisions à partir de données brutes**, ce qui était essentiel pour comprendre la cognition et le traitement du *signal*.
|
||||
|
||||
Le résultat qui nous intéresse de cette recherche est l'"Electronic Brain", très semblable au [Perceptron](/perceptron?type=simple) que l'on va voir au premier onglet. Il transforme les données d'entrée ($X$) pour en sortie donner une décision ($Y$)
|
||||
|
||||
Exemple d'Electronic Brain à 3 entrées : 
|
||||
|
||||
### Le Machine Learning
|
||||
|
||||
Les neurones artificiels sont la structure "intelligente" du réseau. Cependant, il faut d'abord l'entraîner afin de déterminer les paramètres qui rendent ce réseau intelligent. C'est là que rentre en jeu le Machine Learning (souvent abrévié "ML"). On distingue principalement deux grandes catégories :
|
||||
|
||||
#### L'Apprentissage Supervisé
|
||||
|
||||
Des données d'entraînement sont données au modèle, appelées *exemples*. À chaque exemple est associée une bonne réponse appelée *tag* (ou *étiquette* en français).
|
||||
|
||||
Pendant l'apprentissage, pour chaque exemple, le réseau de neurones est consulté. Si la sortie du réseau ($Y$) n'est pas égale à la réponse attendue (le *tag* de l'exemple), les paramètres du réseau sont modifiés. Enfin, l'on passe à l'exemple suivant.
|
||||
|
||||
L'apprentissage supervisé demande donc d'étiqueter (ou "tagger") chaque exemple avec une réponse attendue précise et fiable. À défaut, le réseau de neurones pourrait manquer de précision et de fiabilité.
|
||||
|
||||
#### L'Apprentissage Non Supervisé
|
||||
|
||||
L'apprentissage non supervisé n'utilise pas de *tag* dans les données. À la place, il utilise des méthodes d'analyse de données mathématiques comme l'[ACP](https://notes.matthiasg.dev/#/page/school%2Fexploration%20de%20donn%C3%A9es%2F1.%20acp).
|
||||
Cet apprentissage est utilisé pour trouver des pattern dans des données.
|
||||
|
||||
Tous les réseaux présentés ici utilisent l'**Apprentissage Supervisé**. L'apprentissage non supervisé ne sera donc pas vu plus en détail.
|
||||
|
||||
### Types de problèmes à résoudre
|
||||
|
||||
Les réseaux de neurones peuvent résoudre plusieurs types de problèmes. Nous allons ici en voir deux :
|
||||
|
||||
#### La Régression
|
||||
|
||||
Le réseau de neurones estime la fonction mathématique continue d'une suite ou d'un nuage de points, afin par exemple de pouvoir prédire les données suivantes.
|
||||
|
||||
Exemple : à partir des températures des cinq dernières années, entraîner un réseau de neurones pour qu'il reproduise la fonction mathématique qui se rapproche le plus de tous les points. Une fois entraîné, le réseau est capable d'estimer les prochaines températures.
|
||||

|
||||
|
||||
#### La classification
|
||||
|
||||
Le réseau de neurones va attribuer la catégorie la plus probable à chaque exemple. Ces catégories sont appelées *classes* en mathématique. Un réseau de neurones peut classer les données dans autant de classes que nécessaire, mais le réseau doit être adapté en conséquence au niveau de la *couche de sortie* que l'on verra dans les réseaux multicouches.
|
||||
|
||||
Exemples : détection d'objets dans une image, déterminer si un e-mail est un spam ou non, déterminer l'état de santé d'un patient à partir de ses données vitales, ...
|
||||
|
||||

|
||||
|
||||
Chaque point contenu dans les zones sera catégorisé par le réseau de neurones dans la classe correspondante.
|
||||
|
||||
### [Quand la technologie copie la nature](https://fr.wikipedia.org/wiki/Biomim%C3%A9tisme)
|
||||
|
||||
Les neurones artificiels sont très semblables aux neurones biologiques. Un neurone biologique est une unité de traitement, capable de recevoir des signaux, de les traiter et de transmettre des informations via des connexions appelées *synapses*.
|
||||
|
||||
### Anatomie du Neurone Artificiel
|
||||
|
||||
Un neurone artificiel (ou une couche neuronale) est composé de plusieurs éléments interconnectés qui collaborent pour produire une sortie. Voici les composants clés :
|
||||
|
||||

|
||||
|
||||
- **Entrée ($x_1$, $x_2$, $x_3$, ...)** : Les données brutes des exemples donnés au réseau (ex : la température en janvier, février, mars, etc.).
|
||||
- **Poids Synaptique ($w_1$, $w_2$, $w_3$, ...)** : Un coefficient numérique qui détermine l'importance de chaque entrée pour la prochaine étape. Ce sont les paramètres que le réseau modifie quand il "apprend".
|
||||
- **Biais ou Entrée Fictive ($w_0$)** : Une poids ajouté qui permet de déplacer la fonction d'activation, aidant le modèle à mieux s'ajuster aux données. Ce poids est toujours lié à une entrée constante avec comme valeur $1$.
|
||||
- **Potentiel ($p$)** : La somme pondérée de toutes les entrées et des biais : $p = (\sum w_i x_i) + w_0$.
|
||||
- **Fonction d'Activation ($f(x)$)** : Une fonction non linéaire qui va borner la valeur. Cette fonction est choisie par le développeur ou imposée par le type de neurone, comme on va le voir par exemple pour [ADALINE](perceptron?type=adaline).
|
||||
- **Sortie ($y$)** : Le résultat final du neurone, la sortie du réseau, ce que le réseau a déterminé à partir de l'exemple.
|
||||
|
||||
## Autre vocabulaire
|
||||
|
||||
- **Dataset** : collections d'exemples étiquetté ayant la même structure et traitant du même sujet. Exemple : un dataset contenant la température enregistrée pour chaque jour des cinq dernières années. Pour chaque exemple on a donc le jour et la température.
|
||||
|
||||
## Présentation de Perceptron Viewer
|
||||
|
||||
Perceptron Viewer permet de modifier les paramètres d'entraînement, d'entraîner des réseaux de neurones et perceptrons sur un serveur, et de visualiser en direct les erreurs, les zones décisionnelles et les prédictions du réseau.
|
||||
|
||||
### Présentation de l'interface
|
||||
|
||||

|
||||
|
||||
La configuration de l'entraînement et les graphes seront expliqués plus en détail dans l'onglet [Perceptron](/perceptron?type=simple).
|
||||
|
||||
---
|
||||
|
||||
Je vous invite dès à présent à vous rendre sur l'[onglet 1 : Perceptron Simple](/perceptron?type=simple).
|
||||
@@ -0,0 +1,51 @@
|
||||
# Le Réseau Monocouche
|
||||
|
||||
Jusqu'ici, nous avons vu des réseaux avec un seul neurone. Une des limites d'un tel réseau est qu'**un seul neurone ne peut séparer que deux classes**. En effet, un neurone ne peut pas donner simultanément l'appartenance ou non à plusieurs classes.
|
||||
|
||||
Pour séparer des données de plusieurs classes, il devient nécessaire d'utiliser plusieurs neurones, chacun étant spécialisé pour détecter l'appartenance ou non à une classe spécifique.
|
||||
|
||||
Exemples :
|
||||
|
||||
- Pour séparer 3 classes, il faut au moins 3 neurones.
|
||||
- Pour séparer 2 classes, un seul neurone suffit (si $y > 0.5$ alors classe A, sinon classe B).
|
||||
|
||||
C'est exactement ce qu'un réseau monocouche fait : il permet d'avoir une quantité infinie de neurones. Le nombre de neurones est contrôlé automatiquement par PerceptronViewer en fonction du nombre de classes différentes dans le dataset.
|
||||
|
||||
<div class="exercice">
|
||||
Reprenons le dataset oblique afin de pouvoir comparer les résultats avec ceux d'un réseau à un neurone :
|
||||
|
||||
- <span>Dataset</span> : `Classification - Oblique (linéairement séparable)`
|
||||
|
||||
Puis cliquez sur "Lancer" tout en laissant les autres paramètres intacts.
|
||||
|
||||
On peut voir maintenant des zones apparaître sur le graphe de décision. Chacune de ces zones représente la ligne de décision d'un neurone : si un point se trouve dans une de ces zones, il sera considéré comme faisant partie de la classe correspondante.
|
||||
</div>
|
||||
|
||||
## Structure du réseau monocouche
|
||||
|
||||
Le réseau monocouche permet de choisir quel type de neurone utiliser. Dans le cadre de PerceptronViewer, des neurones ADALINE ont été utilisés.
|
||||
|
||||
Afin de clarifier les schémas de réseaux complexes, les perceptrons sont représentés par un cercle.
|
||||
|
||||

|
||||
|
||||
Chaque neurone est connecté à toutes les entrées et la valeur de leur sortie va déterminer la classe à laquelle l'exemple appartient.
|
||||
|
||||
## Fonctionnement de l'entraînement
|
||||
|
||||
L'entraînement va dépendre du type de neurone utilisé. Globalement, deux approches principales existent :
|
||||
|
||||
1. Entraîner tous les neurones simultanément : au moment de la correction des poids synaptiques, on parcourt tous les neurones.
|
||||
2. Entraîner les neurones séparément : considérer les neurones comme des réseaux séparés. On entraîne le premier réseau, puis on passe au suivant.
|
||||
|
||||
La méthode d'entraînement utilisée dans PerceptronViewer est la première car elle se rapproche de l'entraînement du réseau multicouches, ce qui évite d'implémenter des méthodes différentes.
|
||||
|
||||
<div class="exercice">
|
||||
Exploitons l'avantage du réseau monocouche en utilisant un dataset composé de 3 classes :
|
||||
|
||||
- <span>Dataset</span> : `Classification - 3 classes (linéairement séparable)`
|
||||
|
||||
Puis cliquez sur "Lancer" tout en laissant les autres paramètres intacts.
|
||||
|
||||
On obtient une séparation nette entre les 3 classes qui est assez bien généralisée (si l'on ajoute un nouveau point, il sera dans la classe la plus proche)
|
||||
</div>
|
||||
@@ -0,0 +1,78 @@
|
||||
# Le Réseau Multicouches
|
||||
|
||||
> Et les datasets non linéairement séparables dans tout ça ?
|
||||
|
||||
Jusqu'à présent, nous avons utilisé que des datasets linéairement séparables, pour la simple raison que les réseaux à une seule couche ne produisent que des frontières de décision linéaires (des droites).
|
||||
|
||||
Pour séparer des classes de manière non linéaire, il est nécessaire d'utiliser des fonctions non linéaires au sein du réseau. C'est là que les réseaux multicouches rentrent en jeu : utiliser plusieurs couches permet d'avoir des frontières de décision non linéaires.
|
||||
|
||||
## Structure du réseau monocouche
|
||||
|
||||
Par rapport au réseau monocouche, on rajoute des couches dans lesquelles tous les neurones sont interconnectés aux neurones de la couche suivante.
|
||||
|
||||

|
||||
|
||||
On distingue 3 types de couches :
|
||||
|
||||
- La couche d'entrée : ne contient pas de neurones à proprement parler car ils n'effectuent aucun traitement sur les données d'entrées.
|
||||
- Les couches cachées : chaque couche contient des neurones qui vont "mâcher" les données pour les couches suivantes. Dans PerceptronViewer, le nombre de neurones par couches cachées peut être choisi avec le paramètre **Nombre de neurones par couche cachée** et le nombre de couches cachées peut être choisi avec le paramètre **Nombre de couches cachées**.
|
||||
- La couche de sortie : contient les neurones finaux qui vont transformer les données de sortie de la couche cachée en données utilisables (prédiction ou classification).
|
||||
|
||||
## Fonctionnement de l'entraînement
|
||||
|
||||
L'entraînement d'un réseau multicouche demande plus de technique à cause de la présence de plusieurs couches.
|
||||
|
||||
Voici le fonctionnement de l'entraînement dans les grandes lignes :
|
||||
|
||||
1. On initialise les poids synaptiques.
|
||||
2. On commence l'entraînement : pour chaque exemple du dataset choisi, on évalue la sortie du réseau avec la *propagation avant* (forward propagation en anglais) : les données passent de la couche d'entrée, traversent les couches cachées et arrivent enfin à la couche de sortie. Pour chaque couche, l'entrée de chaque neurone correspond à la sortie des neurones de la couche précédente.
|
||||
3. On calcule l'erreur du réseau sur cet exemple en utilisant la *rétropropagation* (backpropagation en anglais) : on calcule le signal d'erreur de la couche de sortie et on le propage à travers les couches jusqu'à la couche d'entrée.
|
||||
4. On met à jour les poids synaptiques en fonction du signal d'erreur.
|
||||
|
||||
Je ne détaillerai pas ici la rétropropagation et la mise à jour des poids synaptiques. Cependant, si vous êtes intéressés, vous pouvez trouver les détails ici : [Wikipédia - Apprentissage du perceptron multicouche](https://fr.wikipedia.org/wiki/Perceptron_multicouche#Apprentissage).
|
||||
|
||||
<div class="exercice">
|
||||
Exploitons l'avantage du réseau multicouche avec un dataset non linéairement séparable :
|
||||
|
||||
- <span>Dataset</span> : `Classification - Donut (non linéairement séparable)`
|
||||
|
||||
Puis cliquez sur "Lancer" tout en laissant les autres paramètres intacts.
|
||||
|
||||
Le réseau commence avec une zone uniforme qui couvre tout le graphe, ensuite, progressivement, crée une forme ovale qui englobe la classe du milieu du donut. Le reste des époques est passé à peaufiner la forme pour qu'elle englobe au mieux tous les exemples.
|
||||
</div>
|
||||
|
||||
## Qu'est-ce que le nombre de couches et de neurones par couche fait ?
|
||||
|
||||
Ces deux paramètres sont très importants car ils vont déterminer la précision et le temps d'entraînement du réseau. Il n'y a pas réellement de formule magique, les bonnes valeurs sont obtenues par essai et erreur. Voici tout de même ce que va changer chaque paramètre et comment mieux choisir les valeurs.
|
||||
|
||||
### Quels sont les effets
|
||||
|
||||
Augmenter les paramètres va augmenter le nombre total de neurones. Plus il y a de neurones, plus la ligne de décision peut être complexe. Une ligne plus complexe va pouvoir dessiner les contours plus précisément et suivre des courbes complexes.
|
||||
|
||||
Il faut un minimum de nombre total de couches en fonction du dataset :
|
||||
|
||||
- 1 seule couche : la ligne de décision est une droite, comme les perceptrons et le réseau monocouche vu précédemment.
|
||||
- 2 couches : la ligne de décision peux courber et modéliser des formes non linéaires (résout des datasets non linéairement séparables).
|
||||
- +2 couches : la ligne de décision a la possibilité d'être de plus en plus complexe, plus le nombre de couches est haut.
|
||||
|
||||
Il est recommandé de ne pas avoir plus de neurones par couche qu'il y a d'exemples dans le dataset. Sinon le modèle risque d'apprendre par cœur le dataset en retenant un exemple par neurone. Ce problème est appelé **surapprentissage**, il apparaît quand le modèle est tellement bon sur le dataset, qu'il est incapable de généraliser.
|
||||
|
||||
Trop peu de neurones empêche le réseau de pouvoir faire le contour des classes et de devoir faire des erreurs.
|
||||
|
||||
## La régression avec un réseau multicouches
|
||||
|
||||
La régression peut également demander plus de couches de neurones pour pouvoir épouser des formes complexes.
|
||||
|
||||
<div class="exercice">
|
||||
Essayons cela avec un dataset de régression trop complexe pour les réseaux à une seule couche :
|
||||
|
||||
- <span>Dataset</span> : `Régression - Vague`
|
||||
|
||||
Puis cliquez sur "Lancer" tout en laissant les autres paramètres intacts.
|
||||
|
||||
Là où un réseau monocouche essaierait de trouver la moyenne des points avec une droite, le réseau multicouches est capable d'épouser les formes complexes du nuage.
|
||||
</div>
|
||||
|
||||
---
|
||||
|
||||
Ici s'achève la théorie. Quelques datasets n'ont pas été utilisés comme `Classification - Oblique modifié (non linéairement séparable)`, qui contient quelques points ajoutés ou dont la classe a été inversée (erreur d'encodage ? Anomalies dans la récolte des données ? Valeur anormale ? À vous de voir). Ce dataset est intéressant à faire avec tous les types de perceptrons et réseaux car il montre le comportement de chacun face à un dataset non linéairement séparable mais toujours réalisable.
|
||||
@@ -0,0 +1,80 @@
|
||||
# Perceptron Simple
|
||||
|
||||
Un perceptron est un neurone artificiel avec un mécanisme d'apprentissage supervisé.
|
||||
|
||||
Découvert par Frank Rosenblatt en simulant le neurone artificiel sur une machine IBM 704
|
||||
|
||||
Le nombre d'entrées du Perceptron ($x_1$, $x_2$, $x_3$, ...) peut être infini, mais le Perceptron n'aura toujours qu'une seule sortie ($y$). Étant donné que le perceptron ne contient qu'un seul neurone, il n'est capable de sortir qu'une réponse binaire, ce qui veut dire qu'il ne peut faire que de la classification à $2$ classes.
|
||||
|
||||
## Structure du Perceptron
|
||||
|
||||
Structure classique d'un neurone, avec l'utilisation de la fonction en escalier qui va limiter les valeurs possibles de sortie à $0$ ou $1$.
|
||||
|
||||

|
||||
|
||||
Voici le procédé qu'un Perceptron utilise pour transformer un exemple d'entrée ($X$) en signal de sortie ($Y$) :
|
||||
|
||||
1. On assigne chaque donnée de l'exemple du dataset à une entrée ($x_1$, $x_2$, $x_3$, ...). Dans notre cas, on utilise des points dans un espace 2D, donc $x_1 = \text{ Coordonnee x du point d'exemple}$ et $x_2 = \text{ Coordonnee y du point d'exemple}$ pour la classification.
|
||||
2. On multiplie chaque entrée par le poids synaptique correspondant ($x_1 \times w_1$, $x_2 \times w_2$, ...), sans oublier l'entrée fictive ($1 \times w_0$).
|
||||
3. On additionne le tout ($(1 \times w_1) + (x_1 \times w_1) + (x_2 \times w_2) + \cdots$), ce qui donne le *potentiel* ($p$).
|
||||
4. On passe le potentiel dans la fonction d'activation qui, dans le cas du Perceptron, est la fonction en escalier. Cela revient à faire : si $p < 0$ alors le Perceptron retourne $0$, sinon le Perceptron retourne $1$. Le résultat du Perceptron est le signal $y$.
|
||||
|
||||
## Fonctionnement de l'entraînement
|
||||
|
||||
1. On initialise les poids synaptiques. Il existe plusieurs manières de les initialiser, ici PerceptronViewer permet de choisir entre "zeros" et "random" (aléatoire). Il n'y a pas beaucoup de différence entre les deux méthodes, si ce n'est qu'avec l'initialisation à $0$, l'on peux reproduire le comportement de l'entraînement. Cette reproductibilité permet de voir directement l'impact de modifications des autres paramètres d'entraînement.
|
||||
2. On commence l'entraînement : pour chaque exemple du dataset choisis, on évalue la sortie du Perceptron ($y$), avec le procédé vu plus haut. Le passage sur tous les exemples du dataset s'appelle une **époque** ("epoch" en anglais).
|
||||
3. On fait le calcul de l'erreur (notée $e$), en soustrayant la sortie du Perceptron à la sortie attendue (le *label*). Cela revient à $e = \text{ label } - y$. Si le perceptron a bien estimé la sortie, alors l'erreur est de $0$. Dans le cas contraire où le Perceptron n'a pas bien estimé la sortie, l'erreur est de $1$ ou $-1$.
|
||||
4. Si l'erreur n'est pas nulle ($\neq 0$), alors on *corrige les poids synaptiques* du Perceptron ($w_0$, $w_1$, $w_2$, ...) comme suit pour chaque poids synaptique :
|
||||
- Ajouter à la valeur du poids l'erreur multipliée par la valeur de l'exemple assignée à l'entrée, multipliée par une variable nommée **Taux d'apprentissage** (notée $\eta$). Ce qui donne : $w_i' = w_i + \eta \times (\text{label } - y) \times x_i$ pour tout poids synaptique $i$ où $w_i'$ est le poids synaptique corrigé et $x_i$ est l'entrée numéro $i$. Le taux d'apprentissage est défini par le développeur et est un paramètre très important comme on le verra par la suite.
|
||||
5. Une fois tous les exemples du dataset parcourus. Si le Perceptron a commis une erreur ($e \neq 0$) pour un des exemples de ce dataset, alors l'entraînement n'est pas terminé et l'on recommence à partir du point 2. Si le Perceptron n'a pas commis d'erreur, alors l'entraînement est terminé.
|
||||
|
||||
Afin d'éviter que le Perceptron ne s'entraîne sans s'arrêter pour les datasets impossibles, un paramètre **Nombre maximum d'époques** a été ajouté. L'entraînement s'arrêtera si le nombre d'époques maximal a été atteint.
|
||||
|
||||
<div class="exercice">
|
||||
|
||||
Il est temps de tester ! Essayez de lancer un entraînement avec :
|
||||
|
||||
- <span>Dataset</span> : `Classification - Porte logique ET (linéairement séparable)`
|
||||
|
||||
Puis cliquez sur "Lancer" tout en laissant les autres paramètres intacts. Le Perceptron devrait vite converger et trouver une solution (de 3 à 8 époques d'après mes tests).
|
||||
|
||||
Le graphe du dessus montre le dataset avec chaque donnée représentée comme un point ayant la couleur de la classe correspondante. Dans le cas du dataset de la porte logique ET, il n'y a qu'un seul point faisant partie de la classe 1.
|
||||
⚠️ Le nommage des classes est arbitraire et ne représente pas l'étiquette. La ligne de décision (en blanc) représente la bordure entre la zone où le Perceptron va considérer le point comme faisant partie de la classe A ou B. Comme on peut le voir, la ligne de décision est très proche des points, c'est une des limites dont nous parlerons plus bas.
|
||||
|
||||
Le graphe du dessous montre les erreurs faites par le perceptron, chaque bâton représente une époque, avec chaque bloc de couleur représentant l'erreur pour l'exemple correspondant. Le graphe contient aussi une ligne de l'**Erreur quadratique moyenne de l'époque** qui est une métrique utilisée pour examiner l'évolution de l'erreur du réseau de neurones sur le dataset à chaque époque. Comme on va le voir plus loin, cette métrique permet de mieux comprendre ce qu'il se passe durant l'entraînement et de juger les modifications nécessaires. Pour l'instant, on peut voir que cette métrique tombe à $0$ à la dernière époque, ce qui montre que le Perceptron ne fait plus d'erreurs sur le dataset et a donc terminé son entraînement.
|
||||
</div>
|
||||
|
||||
## Comment choisir un dataset ?
|
||||
|
||||
Comme vous pouvez le voir dans la liste déroulante "Dataset", il en existe plusieurs types. Voici leurs significations :
|
||||
|
||||
### Classification VS Régression
|
||||
|
||||
Comme écrit dans l'introduction, la classification et la régression sont deux types de problèmes que les réseaux de neurones que nous voyons ici peuvent résoudre. Comme tous les datasets contiennent des points en 2D, cela veux dire :
|
||||
|
||||
- Pour la classification, le Perceptron va avoir 2 entrées ($x_1 = \text{ Coordonnee x du point d'exemple}$ et $x_2 = \text{ Coordonnee y du point d'exemple}$) et une sortie qui indique si le point fait partie d'une classe A ou B.
|
||||
- Pour la régression, le Perceptron va avoir 1 entrée ($x_1 = \text{ Coordonnee x du point d'exemple}$) et la sortie représentera la coordonnée y du point d'exemple puisqu'il n'y a qu'une seule classe dans un dataset de régression.
|
||||
|
||||
### Classification : linéairement séparable ou non linéairement séparable
|
||||
|
||||
La notion de séparabilité linéaire dans la classification fait référence à la capacité d'un modèle à séparer les classes par un plan (ou une frontière) simple. Si les données sont linéairement séparables, cela veut dire qu'elles peuvent être séparées à l'aide d'une fonction mathématique linéaire (une droite).
|
||||
|
||||
## Limitations du Perceptron
|
||||
|
||||
Étant donné que sa sortie est binaire, le Perceptron présente deux limitations fondamentales :
|
||||
|
||||
- Il est incapable de faire de la régression. Car il s'arrête dès qu'il ne fait plus d'erreurs, mais avec une seule classe, il est impossible de faire une erreur.
|
||||
- Il est incapable de faire de la classification à plus de deux classes différentes.
|
||||
|
||||
La limite de décision du Perceptron est souvent collée aux points. Une solution parfaite mettrait la limite à égale distance entre les points des deux classes. Cele est dû à l'entraînement qui s'arrête au moment où il n'y a plus d'erreurs, sans chercher à "optimiser" ou "généraliser" la solution.
|
||||
|
||||
<div class="exercice">
|
||||
|
||||
Pour voir le perceptron qui colle les points, essayez de lancer un entraînement avec :
|
||||
|
||||
- <span>Dataset</span> : `Classification - Oblique (linéairement séparable)`
|
||||
|
||||
L'on peut voir que l'entraînement dure déjà plus longtemps car il faut que le Perceptron trouve une pente et une hauteur qui fait passer la droite de décision dans un "trou" plus étroit. Mais l'on voit également que le Perceptron va coller les points à l'entrée et à la sortie de ce "trou".
|
||||
</div>
|
||||
|
||||
Ces limitations ont été éliminées par [la descente du gradient](/perceptron?type=gradientdescent) qui utilise des entrées et des sorties réelles.
|
||||