On appelle réseau de neurone “à propagation avant” (feedforward neural network) un réseau de neurone sans connection récurrente.
Un perceptron multi-couches (PMC, ou multi-layer perceptron, MLP), ou réseau de
neurones multi-couches, définit une famille de fonctions. Considérons d’abord
le cas le plus classique, celui d’un réseau de neurones à une couche cachée,
qui associe à un vecteur de dimension un vecteur de longueur
(par exemple, pour effectuer une régression) :
où :
La fonction , qui retourne un vecteur, est
appelée la sortie de la couche cachée. Notons que dans le réseau
ci-dessus, la sortie est une transformation affine de la couche cachée. Une
non-linéarité peut être appliquée par dessus dans certaines architectures.
Les éléments de la couche cachée sont appelés unités cachées.
Il est possible d’appliquer à nouveau le même genre de transformation à
elle-même, avec des paramètres (biais et poids) différents. Cela
donnerait un réseau de neurones multi-couches (à propagation avant) avec deux
couches cachées. De manière plus générale, on peut construire un réseau de
neurones profond en empilant plusieurs de ces couches. Chacune des couches
peut avoir une taille différente (le
utilisé ci-dessus).
Une variante commune est l’ajout de connexions directes, c’est-à-dire qu’une
couche peut prendre comme entrée à la fois la couche précédente et d’autres
couches plus basses (plus proches de l’entrée).
Soit , où
représente la fonction non-linéaire
de sortie. En apprentissage supervisé, la sortie
peut être
comparée avec une valeur cible,
, par une fonction d’erreur,
.
Voici quelques fonctions d’erreur utilisées communément, avec la non-linéarité
de sortie correspondante :
Il s’agit simplement d’appliquer l’algorithme récursif de calcul du gradient, vu précédemment, au graphe formé par le PMC, avec un nœud par unité d’entrée, par unité cachée, et par unité de sortie. Notons que chaque paramètre (biais ou poids) correspond aussi à un nœud.
Voici quelques conventions de notation pour les PMC avec plus d’une couche
cachée. On note le vecteur de sortie de la couche
, en
commençant par
(l’entrée), jusqu’à la couche de sortie,
, qui produit la prédiction, ou sortie, du réseau.
Avec des unités tanh (dont la fonction d’activation est la tangente hyperbolique) dans les couches cachées, nous avons (en utilisant la notation matricielle) :
Pour à
:
où est un vecteur de biais, et
est une matrice de
poids, connectant la couche
à la couche
.
Le calcul scalaire associé à une unité donnée
de la couche
est
.
Dans le cas d’un classifieur probabiliste, nous avons un softmax sur la couche de sortie, c’est-à-dire :
où nous notons la sortie parce que c’est un vecteur indiquant une
distribution de probabilité sur les classes. L’erreur est
où est la classe cible, c’est-à-dire que l’on veut maximiser
, qui est un estimateur de la probabilité conditionnelle
de la classe
étant donnée l’entrée
.
Voyons maintenant comment se fait, dans cette structure, l’application récursive de la règle de dérivation en chaîne dans un graphe de flot. Soit
l’argument de la non-linéarité à chaque couche, que nous appellerons le potentiel, notons que (par une dérivation rapide)
et que
Maintenant, appliquons la méthode de la rétropropagation dans le graphe de
flot correspondant. Chaque paramètre (chaque poids et chaque biais) est un
nœud, le potentiel et la sortie
de chaque
neurone est aussi un nœud.
On part du nœud de sortie:
Ensuite, on calcule le gradient de par rapport à chacune des sommes
précédant le softmax,
:
Maintenant, on peut répéter la procédure pour chaque couche. Pour
descendant jusqu’à 1 :
On obtient facilement le gradient de par rapport aux biais :
On calcule le gradient par rapport aux poids :
On rétropropage le gradient vers la couche précédente, si :
La régression logistique est un cas particulier de PMC, qui n’a pas de couche cachée (l’entrée est directement connectée à la sortie), dont l’erreur est l’entropie croisée (sortie sigmoïde), ou la log-vraisemblance négative (sortie softmax). C’est un classifieur linéaire probabiliste, et le critère d’entraînement est convexe selon les paramètres (ce qui garantit qu’il existe un seul minimum, global).
De nombreux algorithmes pour entraîner des réseaux de neurones multi-couches ont été proposés, mais les plus couramment utilisés sont à base de gradient.
Deux principes fondamentaux guident les différentes stratégies employées pour entraîner des PMC :
L’optimisation du critère d’apprentissage dans les réseaux de neurones multi-couches est difficile car il y a de nombreux minima locaux. On peut même démontrer que de trouver les poids optimaux est NP-dur. Cependant on se contente de trouver un bon minimum local, ou même simplement une valeur suffisamment basse du critère. Comme ce qui nous intéresse est la généralisation et non pas l’erreur d’apprentissage (ce qu’on minimise n’est pas ce qu’on voudrait vraiment minimiser), la différence entre “près d’un minimum” et “au minimum” est souvent sans importance. Par ailleurs, comme il n’y a pas de solution analytique au problème de minimisation, on est forcé de faire cette optimisation de manière itérative.
En principe, une manière d’accélérer la descente de gradient
est de faire des choix qui rendent la matrice
Hessienne
mieux conditionnée. La dérivée seconde dans une certaine
direction indique la courbure de la fonction de coût dans
cette direction. Plus la courbure est grande (vallée étroite)
et plus petites doivent être les mises à jour des paramètres
si on éviter que l’erreur augmente. Plus précisement,
le pas de gradient optimal est 1 sur la courbure. On
peut voir cela par une simple expansion de Taylor du
coût et est derrière le fameux algorithme de Newton
pour l’optimisation. Mettons que l’on soit à
et que l’on veuille choisir
pour qu’il
soit un minimum:
Donc on veut un pas de gradient égal à l’inverse de la dérivée seconde. On peut montrer que le nombre d’itération d’un algorithme de descente de gradient sera proportionnel au ratio de la plus grande à la plus petite valeur propre de la matrice Hessienne (avec une approximation quadratique de la fonction de coût). La raison de base en est que la plus grande valeur propre limite le pas de gradient maximum (on ne peut aller plus vite que la courbure la plus forte parmi toutes les directions possibles, sinon l’erreur remonte), mais qu’en utilisant le même pas de gradient dans toutes les directions, la convergence sera la plus longue dans la direction la plus “plate” (valeur propre la plus petite).
- En théorie une couche cachée suffit, mais cette théorie ne dit pas que cette représentation de la fonction sera efficace. En pratique cela a été le choix le plus commun avant 2006, sauf pour les réseaux de neurones à convolution (qui peuvent avoir 5 ou 6 couches par exemple). Parfois on obtient de bien meilleurs résultats avec 2 couches cachées. En fait on peut obtenir une bien meilleure généralisation avec encore plus de couches, mais une initialisation aléatoire ne fonctionne pas bien avec plus de deux couches (mais voir les travaux depuis 2006 sur l’initialisation non-supervisée vorace pour les architectures profondes).
- Pour la régression ou avec des cibles réelles et non-bornées en général, il vaut généralement mieux utiliser des neurones linéaires à la couche de sortie. Pour la classification, il vaut généralement mieux utiliser des neurones avec non-linéralité (sigmoide ou softmax) à la couche de sortie.
- Dans certains cas une connexion directe entre l’entrée et la sortie peut être utile. Dans le cas de la régression, elle peut aussi être initialisée directement par le résultat d’une régression linéaire des sorties sur les entrées. Les neurones cachées servent alors seulement à apprendre la partie non-linéaire manquante.
- Une architecture avec poids partagés, ou bien le partage de certains éléments de l’architecture (e.g., la première couche) entre les réseaux associés à plusieurs tâches connexes, peuvent significativement améliorer la généralisation. Voir aussi la discussion à venir sur les réseaux à convolution.
- Il vaut mieux utiliser une non-linéarité symétrique dans les couches cachées (comme la tanh, et non pas la sigmoide), afin d’améliorer le conditionnement du Hessien et éviter la saturation des couches cachées.
Il est impératif que les entrées soient de moyenne pas trop loin
de zéro et de variance pas trop loin de 1. Les valeurs en entrées
devraient aussi ne pas avoir une magnitude trop grande. On peut faire
certaines transformations monotones non-linéaires qui réduisent les
grandes valeurs. Si on a une entrée
très grande, elle fait saturer plusieurs neurones et bloque
l’apprentissage pour cet exemple. Les magnitudes (variances) des
entrées de chaque couche devraient aussi être du même ordre
quand on utilise un pas de gradient commun pour toute les couches,
pour éviter que l’une des couches devienne le goulot d’étranglement
(plus lent à entraîner).
En fait, dans le cas linéaire,
le conditionnement du Hessien est optimal quand les entrées
sont normalisées (donc avec matrice de covariance = identité),
ce qui peut se faire en les projetant dans l’espace des
vecteurs propres de la matrice , où
est la matrice
de dimension nombre d’exemples par nombre d’entrées.
Dans le cas d’apprentissage par minimisation d’un coût quadratique, on doit s’assurer que les sorties désirées
sont toujours dans l’intervalle des valeurs que la non-linéarité de la couche de sortie peut produire (et sont à peu près normales N(0,1) dans le cas linéaire),
ne sont pas trop proches des valeurs limites de la non-linéarité de la couche de sortie: pour la classification, une valeur optimale est près d’un des deux points d’inflexion (i.e., les points de courbure (dérivée seconde) maximale, environ -0.6 et 0.6 pour tanh, 0.2 et 0.8 pour la sigmoide).
Il vaut mieux utiliser le critère d’entropie croisée (ou la vraisemblance conditionnelle) pour la classification probabiliste, ou bien le critère de marge “hinge” (comme pour le perceptron et les SVMs, mais en pénalisant les écarts à la surface de décision au-delà d’une marge). Dans le cas multiclasse, ça donne
où
est la partie positive et
est la sortie (sans non-linéarité) pour la classe
.
En entrée comme en sortie, on va généralement représenter les variables discrètes par des groupes d’unités (un groupe de k unités par variable discrète pouvant prendre k valeurs). L’exception pratique est le cas d’une variable binaire, qu’on encode généralement avec une seule unité. Dans le cas des sorties on va associer à chaque groupe une distribution discrète (binomiale pour un seul bit, multinomiale pour une variable discrète générale).
Quand le nombre d’exemples est grand (plusieurs milliers) la descente de gradient stochastique est souvent le meilleur choix (surtout pour la classification), en terme de vitesse et en terme de contrôle de la capacité: il est plus difficile d’avoir de l’overfitting avec la descente de gradient stochastique. En effet, la descente de gradient stochastique ne tombe pas facilement dans les minima très pointus (qui ne généralisent pas bien, car une légére perturbation des données déplaçant la surface d’erreur donnerait une très mauvaise performance), à cause du bruit induit par le pas de gradient et le gradient “bruité”. Ce gradient bruité aide aussi à sortir de certains minima locaux, pour la même raison.
Quand la descente de gradient stochastique est utilisée, il est IMPÉRATIF que les exemples soient bien mélangés: par exemple si on a beaucoup d’exemples consécutifs de la même classe, la convergence sera très lente. Il suffit de permuter aléatoirement les exemples une fois pour toute, pour éliminer toute dépendence entre les exemples successifs. Avec certaines architectures qui captent des dépendences temporelles (signaux, musique, parole, séries chrono, vidéo) on a pas le choix de présenter des séquences dont les éléments sont fortement dépendents, mais on peut mélanger les séquences (l’ensemble d’apprentissage est une suite de séquences).
En principe le pas de gradient devrait être
graduellement réduit pendant l’apprentissage pour
garantir la convergence asymptotique. Pour certains
problèmes (surtout de classification) cela ne semble pas
nécessaire, et peut même nuire. Une cédule de descente raisonnable est par
exemple
comme discuté ici.
Si on pouvait le calculer, le pas de gradient optimal
serait
, i.e., l’inverse
de la valeur propre la plus grande de la matrice Hessienne,
et le pas de gradient maximal (avant divergence) est
deux fois plus grand. Le Cun propose une méthode pour
estimer efficacemenet
(voir son
tutorial sur le sujet), mais cette technique ne semble
pas courramment utilisée.
Quand le nombre d’exemples (et donc de paramètres) est plus petit, et surtout pour la régression, les techniques du second degré (surtout la technique des gradients conjugués) permettent une convergence beaucoup plus rapide. Ces techniques sont batch (modification des paramètres après calcul de l’erreur et gradient sur tous les exemples). Ces techniques sont généralement plus facile à ajuster que la descente de gradient stochastique (moins d’hyper-paramètres ou moins nécessaire de les ajuster par rapport à une valeur par défaut), mais la généralisation est parfois moins bonne à cause de la facilité de tomber dans des minima pointus.
Jusqu’à quelques dizaines de milliers d’exemples, la descente de gradient conjugués reste une des meilleures techniques pour l’optimisation des réseaux de neurones. Au-delà il vaut généralement mieux s’en tenir au gradient stochastique ou à sa version minibatch.
On ne peut initialiser tous les poids à zéro sans quoi
tous les neurones cachés sont condamnés à toujours faire
la même chose (qu’on peut voir par un simple argument de symétrie).
On veut aussi éviter la saturation des neurones (sortie près des
limites de la non-linéarité, donc gradient presque 0),
mais ne pas être trop près initialement d’une fonction
linéaire. Quand les paramètres sont tous près de 0,
le réseau multicouche calcule une transformation
affine (linéaire), donc sa capacité effective
par sortie est égale au nombre d’entrées plus 1.
En se basant sur ces considérations, le point idéal
d’opération du neurone devrait être proche du point d’inflexion
de la non-linéarité (entre la partie linéaire près
de l’origine et la partie saturation).
Par ailleurs, on aimerait que la variance moyenne des valeurs
des unités cachées soit préservée quand on propage
les “activations” de l’entrée vers la sortie, et
de la même manière on aimerait que la variance des
gradients le soit aussi quand on les propage de la sortie
vers l’entrée.
Pour atteindre cet objectif,
on peut argumenter que les poids initiaux
devraient être initialisés de manière uniforme
dans un intervalle , où
est le fan-in, i.e., le nombre d’entrées du neurone, le nombre
de neurones de la couche précédente, et
est le fan-out,
i.e., le nombre de neurones de la couche visée. Cela suppose
que les entrées sont approximativement uniformes dans l’intervalle (-1,1)
(et remarquez comme les sorties des unités cachées tanh sont aussi
dans le même intervalle).
Un des problèmes fréquents pendant l’apprentissage est la saturation des neurones, souvent dûe à une mauvaise normalisation des entrées ou des sorties désirées ou une mauvaise initialisation des poids, ou bien à l’utilisation de la sigmoide plutôt qu’une fonction de non-linéarité symétrique comme la tanh. On peut contrôler cela on observant la distribution des sorties des neurones (en particulier, la moyenne des valeurs absolues de la somme pondérée est un bon indice). Quand les neurones saturent fréquemment, l’apprentissage est bloqué sur un plateau de la fonction de coût dû à de très petits gradients sur certains paramètres (donc un très mauvais conditionnement du Hessien).
La théorie du structural risk minimization de Vapnik nous dit qu’il existe une capacité optimale autour de laquelle l’erreur de généralisation augmente (c’est un minimum global et unique). Les techniques de contrôle de la capacité effective visent donc à chercher ce minimum (evidemment de façon approximative).
early stopping: il s’agit d’une des techniques les plus populaires et les plus efficaces, mais elle ne marche pas bien quand le nombre d’exemples disponibles est très petit. L’idée est très simple: on utilise un ensemble d’exemples de validation non-utilisés pour l’apprentissage par descente de gradient pour estimer l’erreur de généralisation au fur et à mesure que l’apprentissage itératif progresse (normalement, après chaque époque on mesure l’erreur sur l’ensemble de validation). On garde les paramètres correspondant au minimum de cette courbe d’erreur de généralisation estimée (et on peut s’arrêter quand cette erreur commence à remonter sérieusement ou qu’un minimum a été atteint depuis un certain nombre d’époques). Cela a l’avantage de répondre à une des questions difficile de l’optimisation, qui est: quand arrêter? De plus on remarque qu’on a ainsi choisi pour pas cher (en temps de calcul) un hyper-paramètre important (le nombre d’itérations d’entraînement) qui touche à la fois l’optimisation et la généralisation.
contrôle du nombre d’unités cachées: ce nombre influence directement la capacité. Dans ce cas il faut malheureusement faire plusieurs d’expériences d’apprentissage, à moins d’utiliser un algorithme d’apprentissage constructif (qui rajoute des ressources au fur et à mesure), voir l’algorithme de cascade-correlation (Fahlman, 1990). On peut utiliser un ensemble de validation ou la validation croisée pour estimer l’erreur de généralisation. Il faut faire attention au fait que cet estimé est bruité (d’autant plus qu’il y a peu d’exemples de validation). Quand on a plusieurs couches cachées, choisir le même nombre d’unités par couche semble bien fonctionner. Le prix à payer pour un nombre d’unités trop grand est surtout que les calculs sont plus longs, car le nombre accru de paramètre est généralement compensé par le early stopping. Par contre quand le nombre d’unités cachées est trop petit, l’effet sur l’erreur de généralisation et sur l’erreur d’apprentissage peut être beaucoup plus grand. On va généralement choisir la taille des réseau de façon empirique, en gardant ces considérations à l’esprit pour éviter d’avoir à essayer trop de valeurs de la taille.
weight decay: c’est une méthode de régularisation (pour contrôler la capacité, empêcher l’overfitting) dont le but est de pénaliser les poids forts. En effet, on peut montrer que la capacité est bornée par la magnitude des poids du réseau de neurones. On rajoute la pénalité
à la fonction de coût. On l’appelle régularisation L2 car on minimise la norme 2 des paramètres. Certains l’appliquent uniquement aux poids et non pas au biais.
Comme dans le cas précédent, il faut faire plusieurs expériences d’apprentissage et choisir le facteur de pénalité
(un hyper-paramètre) qui minimise l’erreur de généralisation estimée. On l’estime avec un ensemble de validation ou bien par validation croisée.
Une forme de régularisation de plus en plus utilisée comme alternative à la régularisation L2 est la régularisation L1, qui a comme avantage que les petits paramètres seront carrément amenés à 0, donnant lieu à un vecteur de paramètres qui est sparse. On va donc minimiser la somme des valeurs absolues des paramètres.