\chapter{Deep learning}
\label{ch:deep}

Un réseau de neurones est un ensemble d'unités élémentaires, appelées neurones artificiels, reliées entre elles et permettant d'effectuer différentes transformations non linéaires. Ces modèles sont issus des travaux des chercheurs en neuro-sciences qui dès les années 1950 ont commencé à travailler sur des modèles mathématiques conceptualisant le fonctionnement des neurones naturels. Ces modèles ont connu un succès certains jusqu'aux années 1990, période où le domaine de l'apprentissage machine a connu un nouveau bouleversement avec la théorie du cadre inductif proposée par \citet{vapnik:1999}. Pendant cette période, peu d'avancement a été réalisé dans l'application et l'utilisation des réseaux de neurones. Les progrès technologiques dans les composantes matérielles de ces dernières années ont cependant permis un regain d'intérêt pour l'apprentissage avec les réseaux de neurones. En particulier, les nouveaux processeurs graphiques (GPU - Graphics Processing Unit) et l'augmentation de la capacité des mémoires vives ont permis la conception et l'apprentissage des réseaux de neurones multicouches avec des architectures plus complexes, connus sous le nom de l'apprentissage profond (deep learning)\index{apprentissage!profond}\index{deep learning|see{apprentissage profond}}. Depuis 2010, nous sommes témoins d'une percée importante de l'application de ces réseaux de neurones profonds dans plusieurs domaines phares en informatique comme la vision par ordinateur ou le traitement automatique du langage naturel. Ce chapitre a pour vocation de présenter les principes de base de l'apprentissage de ces réseaux.
\section{Neurone formel}
\label{sec:deep-neuron}

Un neurone formel est un modèle mathématique très simplifié de neurone biologique qui possède des entrées binaires ou réelles, correspondant à un signal représenté par un vecteur $\obs$ de dimension $\d$, et une sortie unique. Sa fonction consiste à effectuer une somme pondérée et biaisée des entrées, puis à appliquer à cette somme une fonction d'activation, $\Trf:\mathbb{R}\rightarrow\mathbb{R}$. La pondération est modélisée par un vecteur de coefficients synaptiques $\w$ et le biais par un coefficient $\biais$. La figure \ref{fig:NeuroneFormel} illustre schématiquement ce modèle.

\begin{figure}[h!]
\centering
\includegraphics[width=.8\textwidth]{./Figs/chapter-DeepLrn/NeuroneFormel.png}
\caption{Illustration d'un neurone formel\index{poids synaptiques}.}
\label{fig:NeuroneFormel}
\end{figure}

La fonction de transfert du neurone formel s'écrit~:
\begin{equation}
h_{\bar{w}}(\obs)=\Trf\left(\left\langle \w,\obs\right\rangle+\biais\right)=\Trf\left(\sum_{j=1}^\d w_jx_j+\biais\right)
\label{eq:NeuroneFormel}
\end{equation}
avec $\bar{w}=(\w,\biais)$. Dans le premier modèle proposé par \cite{mcculloch:1943}, la fonction d'activation $\Trf(.)$ était la fonction caractéristique de $\mathbb{R}^+$ ou la fonction de transfert Heaviside\index{activation!Heaviside}. Si la somme pondérée est supérieure au seuil $-\biais$, la sortie vaut $1$ ; dans le cas contraire, elle vaut~$0$. Par analogie, $-\biais$ est le seuil d'activation du neurone avec la sortie $0$ correspondant à un neurone éteint.

Ce modèle à seuil sépare l'espace d'entrée en deux demi-espaces par l'hyperplan d'équation:
\[
\sum_{j=1}^\d w_jx_j+\biais=0
\]
D'autres fonctions de transfert ont également été proposées afin d'obtenir des solutions réelles et non plus binaires.  Les formes les plus généralement employées pour la fonction d'activation sont dans ce cas~:
\begin{itemize}
\item la fonction linéaire~:
\begin{equation*}
\Trf:z \mapsto \alpha z
\end{equation*}
avec $\alpha$ un réel positif non nul~;
\item la fonction linéaire par morceaux~:
\[
\Trf(z)=\begin{cases}
1& \text{si }z\geq 0.5\\
z+0.5 & \text{si } -0.5<z<0.5\\
0& \text{sinon}
\end{cases}
\]
\item la fonction tangente hyperbolique ou la fonction sigmoïde définie par~:
\begin{equation*}
\Trf(z)=~\frac{1}{1+e^{-z}}
\end{equation*}
\end{itemize}

\section{Réseaux simples}

Les réseaux à une seule couche et unités d'activation à seuil ont été étudiés par \cite{rosenblatt:1958} à la fin des années 1950. Il appela ces réseaux des perceptrons car ils ont été conçus à l'origine en s'inspirant du système perceptif. Ces réseaux ont été appliqués à des tâches de classification qui concernaient pour la plupart des images binaires. 
Nous allons exposer brièvement les principes de base de ce modèle, ainsi que le modèle ADALINE\index{perceptron}\index{algorithme!ADALINE} proposé un peu plus tard par \cite{widrow:1960} et dont la compréhension aide à mieux appréhender le fonctionnement des perceptrons multicouches\index{perceptron!multicouche} qui représentent la première famille des réseaux de neurones profonds.

\subsection{Perceptron}
\label{sec:perceptron}
En partant d'un tableau lumineux représentant une rétine et avec des entrées binaires correspondant aux états éteint et allumé d'une ampoule, \cite{rosenblatt:1958} a utilisé des fonctions linéaires dites \textit{d'association} pour transformer les signaux d'entrée (figure \ref{fig:perceptron}). Ces fonctions ont des poids reliés d'une manière aléatoire à un sous-ensemble des entrées du tableau. Un neurone formel tel que décrit précédemment est ensuite appliqué aux entrées ainsi transformées. Dans ce modèle, la fonction d'activation est l'identité \index{activation!linéaire} et la sortie calculée par le perceptron pour un signal $\obs$ est égale~à~:
\begin{equation}
h_{\bar{w}}(\obs)=\Trf\left(\left\langle \w,\Phi(\obs)\right\rangle+\biais\right)=\sum_{j=1}^\d w_j \phi_j(\obs)+\biais
\label{eq:FullPerceptron}
\end{equation}
où  $\Phi(\obs)= (\phi_1(\obs),\ldots,\phi_\d(\obs))$ représente le vecteur d'association pour le signal $\obs$, $\w=(w_1, w_2, \ldots, w_\d)$ est le vecteur des poids synaptiques et $\biais$ est le biais du neurone. Les fonctions d'association ont des poids fixes et ne font pas partie du neurone formel tel que décrit ci-dessus. Nous consid\'ererons donc comme entrées dans la suite le résultat de l'application de ces fonctions au signal d'entrée initial. La fonction de transfert se simplifie~en~:
\begin{equation}
h_{\wgt}(\obs)=\Trf\left(\left\langle \w,\obs\right\rangle+\biais\right)=\sum_{j=1}^\d w_j x_j+\biais
\label{eq:PerceptronNeuron}
\end{equation}

\begin{figure}[h!]
\centering
\includegraphics[width=.7\textwidth]{./Figs/chapter-DeepLrn/Perceptron.pdf}
\caption{Architecture d'un perceptron inspiré du système perceptif et composé de quatre composantes principales : la rétine, les fonctions d'association, les poids synaptiques et l'unité à seuil.}
\label{fig:perceptron}
\end{figure}
L'algorithme du perceptron trouve les paramètres du modèle, $\wgt=(\w,\biais)$ en minimisant la distance, ou la marge\index{marge!d'un exemple}, des exemples mal classés à la frontière de décision. 
Ainsi, comme la distance d'un exemple à l'hyperplan séparateur\index{hyperplan!séparateur} est proportionnelle à la prédiction du modèle linéaire pour cet exemple  (voir exercice~7.1) et comme, pour un exemple mal classé, le produit de cette prédiction avec l'étiquette de classe de l'exemple est négatif, l'algorithme d'apprentissage du perceptron tente de minimiser la fonction-objectif\index{fonction!objectif} suivante :
\begin{equation}
\label{ch4:perceptron:Foncobj}
\mathcal{L}(\wgt)=-\sum_{i\in \mathcal{I_{\wgt}}} \y_{i}(\langle \w,\obs_{i}\rangle+\biais)
\end{equation} 
où $\mathcal{I_{\wgt}}$ est l'indice des exemples d'apprentissage mal classés par le modèle défini par les paramètres $\wgt$. 

Cet algorithme est basé sur celui de la descente de gradient ou de la descente selon la plus forte pente (respectivement \textit{gradient descent} et \textit{steepest descent}),\index{gradient!descente|see{algorithme du gradient}} qui est\index{steepest descent|see{algorithme du gradient}} une approche d'optimisation itérative simple et populaire pour trouver le minimum d'une fonction-objectif convexe et dérivable. 

Dans le cas de la minimisation globale de la fonction de coût (traitement par lots ou minimisation en mode \textit{batch}),\index{mode!batch} on initialise les poids $\wgt^{(0)}$ de façon aléatoire et on minimise la fonction de coût en mettant à jour itérativement les vecteurs poids. Cette mise à jour se fait dans la direction opposée à celle du gradient\index{direction de descente|see{gradient}} de la fonction de coût, qui localement indique la plus forte pente de cette fonction. Ainsi, à l'itération $t$, les nouvelles valeurs de poids $\wgt^{(t+1)}$ sont estimées d'après les valeurs de poids à l'étape précédente $\wgt^{(t)}$ et le gradient\index{vecteur!gradient} de la fonction de coût estimé au poids $\wgt^{(t)}$. 

En supposant que l'ensemble $\mathcal{I_{\wgt}}$ est localement fixe, le gradient de $\mathcal{L}$ (eq.~\ref{ch4:perceptron:Foncobj}) est égal à :
\begin{eqnarray}
\label{eq:Perceptron:Gradients}
\frac{\partial \mathcal{L}}{\partial \biais}(\wgt) & = & - \sum_{i\in \mathcal{I_{\wgt}}} \y_{i}\\
\nabla_{\w} \mathcal{L}(\wgt) & = & -\sum_{i\in \mathcal{I_{\wgt}}} \y_{i}\obs_{i}
\end{eqnarray}
La règle de mise à jour s'écrit:
\begin{equation}
\label{eq:RegGradient}
\forall t\in\mathbb{N}, \wgt^{(t+1)}=\wgt^{(t)}-\eta\nabla\mathcal{L}(\wgt^{(t)})
\end{equation}
avec $\nabla\mathcal{L}$, le vecteur $(\nabla_{\w} \mathcal{L},\partial \mathcal{L}/\partial \biais)$ et où $\eta\in\mathbb{R}_+^{*}$ est un réel strictement positif appelé le pas (ou le taux) d'apprentissage\index{pas d'apprentissage}\index{learning rate|see{pas de descente}}.

\restylealgo{algoruled}
\begin{algorithm}[b!]
    \SetKwInOut{Entr}{Entrée}
    \SetKwInOut{Sort}{Sortie}
    \SetKwInOut{Init}{Initialisation}
\caption{Algorithme de Perceptron}
    \Entr{\begin{itemize}\item une base d'entraînement $\TrnSet=\left(\obs_i, \y_i\right)_{1\le i\le m}$ \item pas d'apprentissage $\eta > 0$ \item le nombre d'exemples mal classés toléré $K$\end{itemize}}
    \Init{\begin{itemize} \item initialiser le vecteur des poids $\wgt^{(0)}$\item $t\leftarrow 0$\end{itemize}}
    \Repeter{le nombre d'exemples mal classés est inférieur ou égal~à~$K$}{
    tirer aléatoirement un exemple d'apprentissage $(\obs,\y)$\\
    \Si{$\y\times\left\langle \w^{(t)}, \obs \right\rangle + \biais^{(t)}\leq 0$}{
      $\biais^{(t+1)}\leftarrow \biais^{(t)}+\eta\times \y$\\
       $\w^{(t+1)}\leftarrow  \w^{(t)}+\eta \times \y \times \obs$\\
      $t \leftarrow t+1$
    }
    }
    \Sort{les paramètres du modèle linéaire $\wgt^{(t)}=(\w^{(t)},\biais^{(t)})$}
\label{algo:chap5:Perceptron}
\end{algorithm} 

Une des difficultés d'utilisation de cet algorithme est le choix du pas d'apprentissage. S'il est trop grand, la règle de mise à jour (eq. \ref{eq:RegGradient}) peut amener à des oscillations autour du minimum. S'il est trop petit, la convergence vers le minimum se fera très lentement et, dans certains cas, peut devenir vite irréaliste (voir exercice 7.2).
En pratique, cet apprentissage est réalisé à l'aide d'un algorithme \textit{en ligne} (algorithme~\ref{algo:chap5:Perceptron}) où, à chaque itération, un exemple est choisi aléatoirement et le vecteur des poids à une itération $t$, $\wgt(t)$, est mis à jour si le classifieur donne une mauvaise prédiction de classe pour cet exemple, soit :
\begin{equation}
\label{ch4:eq:regle2MiseAJourPerceptron}
\forall (\obs,\y), \text{ si } \y(\langle \w^{(t)},\obs\rangle+\biais^{(t)})\leq 0 \text{ alors} \begin{pmatrix}\biais^{(t+1)}\\ \w^{(t+1)}\end{pmatrix}\leftarrow\begin{pmatrix}\biais^{(t)}\\  \w^{(t)}\end{pmatrix}+\eta \begin{pmatrix}\y\\ \y\times \obs\end{pmatrix}
\end{equation}
La figure \ref{fig:perceptron:regledemiseajour} illustre géométriquement la règle de mise à jour de l'algorithme sur un exemple jouet.

\begin{figure}[h!]
%\input{./Figs/Chapter3/PerceptronIllustration.tex}
\centering
\includegraphics[width=.85\textwidth]{./Figs/chapter-DeepLrn/PerceptronIllustration.png}
\caption{Illustration de la règle de mise à jour de l'algorithme du perceptron (eq. \ref{ch4:eq:regle2MiseAJourPerceptron}) avec l'exemple $(\obs_3,-1)$ choisi, qui est mal classé par l'hyperplan de vecteur normal $\w^{(t)}$.}
\label{fig:perceptron:regledemiseajour}
\end{figure}


Cet algorithme, bien que simple, peut être très performant dans certains cas. C'est de plus le précurseur de nombreux autres algorithmes d'apprentissage, notamment le perceptron multicouche présenté dans la suite de ce chapitre. Un des résultats importants est que, si le problème de classification est linéairement séparable\index{linéairement séparable}, alors l'algorithme de perceptron trouvera l'hyperplan séparateur\index{hyperplan!séparateur} en un nombre fini d'itérations. Il existe différentes démonstrations pour ce résultat, dont celle proposée par \cite{novikoff:1962} que nous étudierons dans l'exercice 8.3.


\subsection{ADALINE}
\label{sec:adaline}
Parallèlement au perceptron, \cite{widrow:1960} ont proposé l'ADALINE (Adaptive Linear Neuron)\index{Adaptive Linear Neuron|see{algorithme ADALINE}} dont le modèle formel\index{algorithme!ADALINE}  est celui de la figure \ref{fig:NeuroneFormel} avec la fonction linéaire comme fonction d'activation. Ainsi, avec des poids synaptiques $\wgt~=~(\w,\biais)$, la sortie de ce modèle pour une entrée $\obs$ vaut $h_{\wgt}(\obs)~=~\langle \w,\obs\rangle+\biais$. \cite{widrow:1960} ont  proposé un algorithme  basé sur la technique du gradient stochastique\index{gradient!stochastique} pour apprendre les paramètres de ce modèle. Cet algorithme minimise l'erreur quadratique\index{erreur!quadratique} moyenne entre les étiquettes de classes des exemples d'une base d'entraînement\index{base!d'entraînement} $S=\left((\obs_1, \y_1) ... (\obs_m, \y_m) \right)$  et les prédictions de classe du modèle pour ces exemples : 
\begin{equation}
\label{eq:ch5:Adaline}
\mathcal L(\wgt)=\frac{1}{m}\sum_{i=1}^m (\y_i-h_{\wgt}(\obs_i))^2
\end{equation}


Pour un pas d'apprentissage\index{pas d'apprentissage} $\eta>0$ et un exemple tiré aléatoirement $(\obs,\y)$,  la règle de mise à jour des poids s'écrit:
 \begin{equation}
\label{eq:ch5:AdalineMiseaJour}
\forall (\obs,\y), \begin{pmatrix}\biais^{(t+1)}\\ \w^{(t+1)}\end{pmatrix}\leftarrow\begin{pmatrix}\biais^{(t)}\\ \w^{(t)}\end{pmatrix}+\eta (\y-h_{\wgt^{(t)}}(\obs)) \begin{pmatrix}1\\ \obs\end{pmatrix}
\end{equation}
La différence majeure avec la règle d'apprentissage du perceptron (eq.~\ref{ch4:eq:regle2MiseAJourPerceptron}) est que les poids sont mis à jour sur tous les exemples tirés, mal classés ou non. La figure \ref{fig:ch5:AdalinevsPerceptron} illustre sur un exemple jouet la différence de comportement entre le perceptron et l'adaline. En minimisant le nombre d'erreurs, le perceptron trouve l'hyperplan qui\index{hyperplan!séparateur} sépare au mieux les classes ; ceci au risque d'une mauvaise classification dans le cas de données bruitées. L'adaline fait des erreurs, mais la solution trouvée est généralement plus robuste. 
\begin{figure}[h!]
\centering
%\input{./Figs/Chapter3/AdalinevsPerceptron.tex}
\includegraphics[width=.6\textwidth]{./Figs/chapter-DeepLrn/AdalinevsPerceptron.png}
\medskip

\caption{Illustration des solutions trouvées par les algorithmes du perceptron (en pointillés) et de l'adaline (en trait plein) pour un problème de classification linéairement séparable\index{linéairement séparable}.}
\label{fig:ch5:AdalinevsPerceptron}
\end{figure}

\subsection{Perceptrons multicouches (PMC)}
\label{sec:ch4:PMC}
\index{perceptron!multicouche}Le perceptron multicouche (PMC ou \textit{multi-layer perceptron})\index{multi-layer perceptron|see{perceptron multicouche}}\index{PMC|see{perceptron multicouche}} est une généralisation de l'algorithme du perceptron. Il est par essence un modèle multiclasse représentant l'association entre une observation (ou une entrée) et sa sortie réelle avec une  fonction multivariée définie comme étant une composition de plusieurs fonctions non linéaires. 

Par analogie avec les modèles formels associés au perceptron, la représentation formelle d'un PMC est un réseau avec des couches successives d'unités de base, où chaque unité d'une couche est reliée à celles de la couche suivante. Un PMC est ainsi considéré comme le premier réseau de neurones profond, la profondeur étant égale au nombre de couches cachées plus la couche de sortie. 

\smallskip
Les deux types de réseaux neuronaux les plus étudiés dans la littérature sont les réseaux récurrents\index{réseaux récurrents}, où il existe des boucles entre les différentes couches cachées et aussi entre les unités de ces couches, et les réseaux à propagation avant (ou \textit{feed forward}) sans boucle, que nous considérons dans la suite\index{feed forward}. Ils sont généralement organisés en couches d'unités neuronales chacune semblable à celle décrite dans la section~\ref{sec:deep-neuron}. La figure~\ref{fig:ch4:PMC} montre un exemple d'un tel réseau avec une seule couche cachée (de profondeur 2), où il y a $v$ cellules entrées, chacune prenant la valeur de la caractéristique d'un vecteur d'entrée, $\ell$~unités sur la couche cachée et $k$~unités sur la couche de sortie. La fonction de transfert globale du réseau peut s'écrire~: $z=f(x)$ et $c=g(z)$ ou $c=(g \circ f)(x)$.

\begin{figure}[h!]
\centering
%\input{Figs/Chapter4/PMC.tex}
\includegraphics[width=.45\textwidth]{Figs/chapter-DeepLrn/PMC.png}
\index{perceptron!multicouche!architecture}
\caption{Architecture d'un perceptron multicouche à une couche cachée (de profondeur 2). Sur cet exemple, les paramètres des biais sont introduits par des poids liés à deux unités supplémentaires associés à la couche d'entrée et à la première couche cachée  ayant respectivement les valeurs fixées $x_0=1$ et $z_0=1$.}
\label{fig:ch4:PMC}
\end{figure}

Un vecteur de poids et un biais sont associés indépendamment à chacune des unités neuronales. Si l'on combine tous les vecteurs de poids et tous les biais d'une même couche, on obtient respectivement une matrice de poids et un vecteur de biais et la sortie de la couche avant l'application de la fonction d'activation se calcule par le produit de la matrice de poids par le vecteur d'entrée suivi de l'addition du vecteur de biais. On peut se ramener à un simple produit matrice~$\times$~vecteur en ajoutant une composante fictive égale à 1 dans les vecteurs d'entrée de chaque couche. On notera $W_f$ et $W_g$ les matrices de poids (incluant les biais) qui définissent respectivement les fonctions $f$ et $g$ dans l'exemple précédent et qui généralisent les vecteurs étendus $\wgt$ définis pour un neurone formel individuel.

\section{Réseaux à propagation avant}
\label{sec:feed-forward}

L'architecture du perceptron multicouche telle que décrite dans la section~\ref{sec:ch4:PMC} peut être généralisée, non seulement en augmentant le nombre de couches, mais également en faisant varier très largement le type de fonction implémenté dans les couches. Nous allons considérer ici une architecture modulaire extrêmement générale dans laquelle un réseau implémente une composition séquentielle de fonctions, chacune correspondant à une couche et étant définie par son propre jeu de paramètres.

\subsection{Composition de fonctions}
\label{sec:func-comp}

Nous considérons pour commencer le cas séquentiel simple où la fonction~$F_W$ ou F(W) correspondant à la transformation effectuée globalement par le réseau est la composition de $N$ fonctions $F_n(W_n)$ avec $1 \leq n \leq N$~:
\begin{equation}
\label{eq:CompFunc}
F(W) = F_N(W_N) \circ ... \circ F_2(W_2) \circ F_1(W_1)
\end{equation}
On note ici $F(W)$ la fonction qui à X fait correspondre $F_W(X)$ ou encore $F(W,X)$. La fonction composée est déterminée par le vecteur $W$ qui est la concaténation des vecteurs $W_n$ avec $1 \leq n \leq N$. Les fonctions $F_n$ peuvent dépendre différemment de leur vecteur de paramètres $W_n$ et ces vecteurs peuvent avoir des tailles différentes, certaines fonctions $F_n$ n'ayant pas de paramètres du tout. Les vecteurs~$W_n$ peuvent également encapsuler des structures plus complexes, comme des matrices ou des tenseurs de poids mais, au niveau considéré ici, ils n'apparaîtront que comme des vecteurs, les structures qu'ils contiennent étant toujours sérialisées. Les fonctions $F_n$ peuvent être quelconques pourvu qu'elles soient différentiables par rapport à leurs données et par rapport à leurs paramètres.

\smallskip
Dans la présentation classique des réseaux de neurones, l'application d'une fonction correspond en général à une couche de neurones formels. En pratique cependant, une couche de neurones dans ce sens classique est souvent implémentée en deux fonctions successives, correspondant à deux types différents de couches (ou de sous-couches)~: l'une, dite \guil{couche linéaire}, qui correspond strictement au produit d'une matrice par un vecteur pour la partie linéaire et l'autre, dite \guil{couche point à point}, qui correspond à l'application de la fonction d'activation composante par composante pour la partie non linéaire. Des fonctions supplémentaires, de normalisation ou de régularisation par exemple, sont également parfois insérées. La méthode de rétro-propagation de l'erreur décrite ci-après pour l'entraînement de ce type de réseaux est très générale et s'applique à n'importe quelle combinaison de fonctions différentiables et paramétrables. Nous ne décrivons ici que le cas d'une combinaison séquentielle de fonctions, mais la méthode est en fait encore plus générale car elle s'applique à des combinaisons de fonctions assemblées selon n'importe quel graphe acyclique. 

\subsection{Fonction-objectif et descente de gradient stochastique par mini-lots}

Pour entraîner un réseau défini par une fonction globale $F_W$ dépendant d'un vecteur de paramètres $W$, on utilise généralement une méthode basée sur une descente de gradient stochastique\index{gradient!stochastique} par mini-lots, telle que décrite dans le chapitre~\ref{ch:optimisation}. On dispose d'une base d'entraînement $\TrnSet$ composée d'échantillons $(\obs,\by)$, $\obs$ étant une observation (entrée) et $\by$ étant une valeur attendue asociée (sortie); on cherche à minimiser une fonction-objectif~$\mathcal{L}_{\TrnSet}$ typiquement définie comme~:
\begin{equation}
\label{eq:ObjFuncReg}
\mathcal{L}_{\TrnSet}(W) = \frac{1}{\mid \TrnSet \mid}\sum_{(\obs,\by) \in \TrnSet}C(F_W(\obs),\by) + \lambda \Omega(W)
\end{equation}
La fonction $C$ (ou encore le \guil{critère}), supposée continûment différentiable, associe un coût à la différence entre une valeur $F_W(\obs)$ prédite par le réseau et la sortie attendue $\by$ correspondante. $\Omega(W)$ est un terme dit de régularisation dont le but est de prévenir le surapprentissage et/ou la divergence du vecteur de paramètres au cours du processus d'optimisation. La fonction $\Omega$ est elle aussi supposée continûment différentiable et le paramètre $\lambda$ sert à doser la \guil{force} relative souhaitée pour le terme de régularisation.

Dans la version stochastique par mini-lots de l'algorithme de descente de gradient, on effectue une mise à jour du vecteur $W$ en fonction d'un sous-ensemble de la base d'entraînement $\mathcal M_\TrnSet\subseteq \TrnSet$, appelé mini-lot, selon la formule:
\begin{equation}
\label{eq:BatchGradientDescent}
W(t+1)=W(t)-\frac{\eta}{\mid \mathcal M_\TrnSet \mid}\sum_{(\obs,\by) \in \mathcal M_\TrnSet}\nabla_W\mathcal{L}_{(\obs,\by)}(W(t))
\end{equation}
avec :
\begin{equation}
\label{eq:ObjFuncRegOne}
\mathcal{L}_{(\obs,\by)}(W) = C(F_W(\obs),\by) + \lambda \Omega(W)
\end{equation}
Par exemple, la différence entre la valeur prédite et celle attendue peut être mesurée par la distance euclidienne et la régularisation se faire en minimisant la norme du vecteur $W$~:
\begin{equation}
\label{eq:ObjFuncRegEx}
\mathcal{L}_{(\obs,\by)}(W) = \frac{1}{2}\left\Vert F_W(\obs)-\by \right\Vert^2 + \frac{\lambda}{2} \left\Vert W \right\Vert^2
\end{equation}

Pour mettre en {\oe}uvre la descente de gradient telle que décrite dans les équations~\ref{eq:BatchGradientDescent} et~\ref{eq:ObjFuncRegOne}, nous devons pouvoir calculer $\nabla_W E(W,\obs,\by)$ pour une paire exemple $(\obs,\by)$ avec $E(W,\obs,\by) = C(F_W(\obs),\by)$. Notons que, pour la mise en {\oe}uvre des équations~\ref{eq:BatchGradientDescent} et~\ref{eq:ObjFuncRegOne}, le calcul de $\nabla_W \Omega(W)$ ne pose généralement pas de problème. Par exemple, si $\Omega(W) = \frac{1}{2} \Vert W \Vert^2$, alors $\nabla_W \Omega(W) = W^T$. Cette régularisation équivaut à appliquer un taux de décroissance $\eta\lambda$ aux composantes de $W$ à chaque itération ({\em weight decay}).


\subsection{Calcul des gradients par rétro-propagation de l'erreur}
\label{sec:back-prop}

Dans le cas d'une fonction composée telle que décrite dans la section~\ref{sec:func-comp}, nous noterons $X_n$ avec $0 \leq n \leq N$ les valeurs successives de la donnée d'entrée $\obs$ au cours de l'application successive des fonctions $F_n(W_n)$. On aura $X_0=\obs$ et $X_n=F_n(W_n)(X_{n-1})=F_n(W_n,X_{n-1})$ pour $1 \leq n \leq N$. $E(W,\obs,\by) = C(X_N,\by)$ mesure l'erreur entre la valeur prédite pour l'entrée~$\obs$ et la sortie attendue $\by$. $W$ étant la concaténation des vecteurs $W_n$ avec $1 \leq n \leq N$, $\nabla_W E(W,\obs,\by)$ est la concaténation des $\nabla_{W_n} E(W,\obs,\by)$ que nous noterons de manière simplifiée $\partial E/\partial W_n$.

\smallskip
Les morceaux de gradient $\partial E/\partial W_n$ qui composent le gradient global $\partial E/\partial W$ sont calculés en utilisant l'algorithme dit de rétro-propagation de l'erreur. Celui-ci comprend trois parties.

\smallskip
La première partie est appelée {\em passe avant} ou {\em propagation}. Elle correspond au fonctionnement normal du réseau en mode prédiction. Dans cette passe, les valeurs $X_n$ sont calculées par récurrence avant à partir de l'entrée courante $X_0=\obs$ par application successive des fonctions $F_n(W_n)$. Additionnellement, l'erreur résiduelle (ou le coût associé) est calculée comme $E = C(X_N,\by)$.

\smallskip
La deuxième partie, {\em rétro-propagation selon les données}, se fait dans le cadre d'une {\em passe arrière}. Dans cette partie de la passe arrière, on calcule par récurrence {\em arrière}, c'est-à-dire pour des valeurs décroissantes de $n$ en partant de $N$, les gradients par rapport à la donnée $X_n$ de l'erreur $E$ par~:
\begin{equation}
\label{eq:BackDataN}
\frac{\partial E}{\partial X_N} = \frac{\partial C(X_N,\by)}{\partial X_N} = \frac{\partial C}{\partial X_N}
\end{equation}
à partir de $E = C(X_N,\by)$ et~:
\begin{equation}
\label{eq:BackData}
\frac{\partial E}{\partial X_{n-1}} = \frac{\partial E}{\partial X_n} \frac{\partial F_n(W_n,X_{n-1})}{\partial X_{n-1}} = \frac{\partial E}{\partial X_n} \frac{\partial X_n}{\partial X_{n-1}}
\end{equation}
à partir de $X_n=F_n(W_n,X_{n-1})$.

\smallskip
La troisième partie, {\em rétro-propagation selon les paramètres}, est considérée comme faisant partie de la passe arrière mais elle ne fait pas intervenir de relation de récurrence, les calculs ne faisant pas intervenir de dépendance avant ou arrière sur les valeurs de $n$ une fois que les $\partial E/\partial X_n$ ont été calculés. Les gradients par rapport aux paramètres $W_n$ de l'erreur $E$ sont finalement calculés par~:
\begin{equation}
\label{eq:BackParam}
\frac{\partial E}{\partial W_n} = \frac{\partial E}{\partial X_n} \frac{\partial F_n(W_n,X_{n-1})}{\partial W_n} = \frac{\partial E}{\partial X_n} \frac{\partial X_n}{\partial W_n}
\end{equation}
à partir des $\partial E/\partial X_n$ précédemment calculés et de $X_n=F_n(W_n,X_{n-1})$.

\smallskip
Il est à noter que $E$ est un scalaire, que tous les $X_n$ et $W_n$ sont des vecteurs de nombres réels\footnote{Les vecteurs de paramètres $W_n$ apparaissent toujours comme des vecteurs simples de nombres réels au niveau extérieur aux fonctions. Selon la nature exacte des fonctions, à l'intérieur de celles-ci, ils peuvent apparaître sous la forme d'autres structures, ce qui peut nécessiter de les \guil{désérialiser} en entrée et de les \guil{resérialiser} en sortie (pour le gradient $\partial E/\partial W_n$). Par exemple, dans le cas d'une fonction implémentant une transformation linéaire entre le vecteur d'entrée $X_{n-1}$ et le vecteur de sortie $X_n$, $W_n$ apparaît en interne comme une matrice. De même, dans le cas de réseaux convolutifs, les données $X_n$ (et donc les gradients associés $\partial E/\partial X_n$) apparaissent en interne comme des tenseurs d'ordre 3 ou plus.}, tous les $\partial E/\partial X_n$ et $\partial E/\partial W_n$ sont des vecteurs de type dual respectivement par rapport aux vecteurs $X_n$ et $W_n$ (c'est-à-dire que les premiers sont de type colonne et les seconds sont de type ligne), que les Jacobiens $\partial X_n/\partial X_{n-1}$ et $\partial X_n/\partial W_n$ sont des matrices et que les produits matrice-vecteur apparaissant dans les équations~\ref{eq:BackData} et~\ref{eq:BackParam} ne sont pas commutatifs.

\smallskip
En pratique, il est nécessaire de calculer numériquement les vecteurs $X_n$, $\partial E/\partial X_n$ et $\partial E/\partial W_n$. Par contre, il n'est pas nécessaire de calculer les matrices Jacobiennes $\partial X_n/\partial X_{n-1}$ et $\partial X_n/\partial W_n$. Il suffit d'implémenter une fonction qui calcule directement le produit de ces matrices par le vecteur gradient auquel elles doivent être appliquées, ce qui ne nécessite généralement pas de les développer.


\subsection{Architecture modulaire}
\label{sec:arch-mod}

La figure~\ref{fig:Archi} montre l'architecture modulaire d'un système d'entraînement d'un réseau multicouche par descente de gradient stochastique\index{gradient!stochastique}. Il comprend~:
\begin{itemize}
\item un module \guil{optimiseur}, 
\item $N$ modules \guil{couches},
\item  et un module \guil{critère}.
\end{itemize}
En phase de prédiction, l'architecture est simplifiée : seuls les modules couches sont conservés et à l'intérieur de ceux-ci, seule la partie \guil{propagation avant} est conservée. Le vecteur de paramètres $W$  appris durant la phase d'entraînement est fixe et les morceaux $W_n$ peuvent être stockés directement comme des constantes dans les modules couches correspondants.

\begin{figure}[htbp]
\centering
\includegraphics[width=.6\textwidth]{./Figs/chapter-DeepLrn/Archi.pdf}
\caption{Architecture modulaire d'un système d'entraînement d'un réseau mul\-ti\-cou\-che (inspiré de~\cite{lecun:2013}). Propagation avant~: du bas vers le haut~; rétro-propagation selon les données~: du haut vers le bas ; rétro-propagation selon les paramètres~: du haut vers la gauche.}
\label{fig:Archi}
\end{figure}

\medskip
\textbf{Le module optimiseur} stocke le vecteur des paramètres $W$. Il le distribue par morceaux $(W_n)_{1\le n\le N}$ aux modules couches. Il récupère en retour des morceaux de gradients $(\partial E/\partial W_n)_{1\le n\le N}$ qu'il assemble en un gradient global $\partial E/\partial W$. Il accumule ces vecteurs gradients globaux pour les échantillons $(\obs,\by)\in \mathcal M_\TrnSet$ d'un sous-ensemble de la base d'entraînement $\mathcal M_\TrnSet\subseteq \TrnSet$, appelé mini-lot. Enfin, il met à jour le vecteur $W$ en fonction du vecteur gradient cumulé correspondant à ce mini-lot et en fonction éventuellement du vecteur gradient d'un terme de régularisation devant être ajouté à $E$ et dépendant uniquement de $W$, qu'il calcule en interne.

\medskip
\textbf{Le module couche} implémente les trois parties du calcul du gradient: propagation avant des données entrantes, rétro-propagation de l'erreur selon les données et rétro-propagation de l'erreur selon les paramètres. 
%Additionnellement, l'erreur résiduelle (ou le coût associé) est calculé comme $E = C(X_N,\by)$ où $\by\in\{0,1\}^K$ est le vecteur indicateur de classe associé à la classe $y$ de l'exemple $\obs$; i.e. un vecteur binaire dont toutes les composantes sont égales à $0$ sauf la composante correspondant à la classe de l'exemple, qui vaut $1$ :
%\begin{equation}
%\label{VecIndClasse}
%\forall (\obs, y), y=k \Leftrightarrow\by^\top = \left(\underbrace{y_1,\ldots,y_{k-1}}_{\small \text{tous égaux à 0}}, \underbrace{y_k}_{=1}, \underbrace{y_{k+1},\ldots,y_K}_{\small \text{tous égaux à 0}}\right)
%\end{equation} 
La figure~\ref{fig:LayerModule} montre l'architecture interne d'un tel module. Dans ce schéma, $F$, $W$, $X_{in}$ et $X_{out}$ (noms internes) correspondent respectivement à $F_n$, $W_n$, $X_{n-1}$ et $X_n$ (noms externes) pour le module couche $n$. 

\begin{figure}[htbp]
\centering
\includegraphics[width=.96\textwidth]{./Figs/chapter-DeepLrn/LayerModule.pdf}
\caption{Module \guil{couche}.  Propagation avant~: du bas vers le haut~; rétro-propagation selon les données~: du haut vers le bas ; rétro-propagation selon les paramètres~: du haut vers la gauche.}
\label{fig:LayerModule}
\end{figure}

Le module couche doit implémenter la fonction $F$ et les deux fonctions dérivées $B_{X_{in}}$ et $B_{W}$ telles que~:
\begin{eqnarray}
\label{eq:BackPropFuncD}
B_{X_{in}}(X_{in},W,V) & = & V.\frac{\partial F(X_{in},W)}{\partial X_{in}} \\
\label{eq:BackPropFuncP}
     B_{W}(X_{in},W,V) & = & V.\frac{\partial F(X_{in},W)}{\partial W}
\end{eqnarray}
Lors de la passe arrière, ces deux fonctions sont appliquées avec ${V=\partial E/\partial X_{out}}$. Le module couche peut se décliner en un grand nombre de variantes, les deux principales étant le module \guil{linéaire} et le module \guil{point à point}.

\medskip
\textbf{Le module linéaire} ({\em linear module}) correspond typiquement à l'étape linéaire (c'est-à-dire sans la fonction d'activation et également sans le biais) dans une couche de neurones formels de type \guil{tous vers tous}. Il applique une transformation linéaire déterminée par une matrice~$W$ entre l'entrée~$X_{in}$ et la sortie~$X_{out}$~:
\begin{equation}
\label{eq:ForwardLinear}
X_{out} = W X_{in}
\end{equation}
Notons que, du point de vue interne au module, $W$ apparaît comme une matrice alors que, du point de vue externe, il apparaît comme un vecteur. Ceci implique qu'en entrée $W$ soit \guil{désérialisé} et qu'en sortie $\partial E/\partial W$ soit \guil{resérialisé}. Ce genre de tranformation se fait couramment et même avec des tenseurs de dimension 3, 4 ou 5 dans le cas des couches linéaires des réseaux convolutionnels (section~\ref{sec:ConvNets}).

\smallskip
La fonction de transformation $F$ est linéaire par rapport à chacune de ses deux entrées, $W$ et $X_{in}$, ce qui conduit à des expressions extrêmement simples et à des calculs très efficaces pour les fonctions de rétro-propagation~:
\begin{eqnarray}
\label{eq:BackPropFuncLinearD}
\frac{\partial E}{\partial X_{in}} & = & \frac{\partial E}{\partial X_{out}} W \\
\label{eq:BackPropFuncLinearP}
\frac{\partial E}{\partial W} & = & X_{in} \frac{\partial E}{\partial X_{out}}
\end{eqnarray}
On rappelle que $X_{in}$ et $X_{out}$ sont ici des vecteurs colonnes et que $\partial E/\partial X_{in}$ et $\partial E/\partial X_{out}$ sont des vecteurs lignes. En ce qui concerne $W$, compte tenu des opérations de désérialisation et de resérialisation, du point de vue externe, $W$ et $\partial E/\partial W$ sont respectivement un vecteur colonne et un vecteur ligne et, du point de vue interne, ce sont respectivement une matrice et une matrice correspondante transposée. Dans l'équation~\ref{eq:BackPropFuncLinearD}, le produit à gauche d'un vecteur ligne par une matrice donne un vecteur ligne. Dans l'équation~\ref{eq:BackPropFuncLinearP}, le produit d'un vecteur colonne par un vecteur ligne (produit extérieur) donne une matrice (transposée par rapport à W). Pour vérifier les formules~\ref{eq:BackPropFuncLinearD} et~\ref{eq:BackPropFuncLinearP} à partir de la formule~\ref{eq:ForwardLinear}, il suffit de développer les formules~\ref{eq:BackPropFuncD} et~\ref{eq:BackPropFuncP} pour chacune des composantes des vecteurs ou des matrices concernées.

\medskip
\textbf{Le module point à point} ({\em pointwise module}) correspond typiquement à l'étape non linéaire (c'est-à-dire la fonction d'activation) dans une couche de neurones formels.

On considère une fonction scalaire $\Trf$ (de $\mathbb{R}$ dans $\mathbb{R}$) continûment différentiable et on convient de la \guil{surcharger} pour n'importe quel type d'objet composé de nombre réels (typiquement~: vecteurs colonnes, vecteurs lignes, matrices ou tenseurs plus généraux) en appliquant en parallèle la fonction $\Trf$ à chacune des composantes indépendamment, par exemple~: $\Trf(x_1,x_2 \; ... \; x_d) = (\Trf(x_1),\Trf(x_2) \; ... \; \Trf(x_d))$.

Par commodité, on prendra également en compte au niveau de ce module le vecteur $W$ constitué des paramètre de biais $\biais$, puisque ceux-ci sont aussi appliqués composante par composante au niveau du vecteur de sortie du module linéaire précédent et donc au niveau de l'entrée pour le module \guil{point à point}. La transformation non linéaire avec biais est déterminée par la fonction $\Trf$ et par le vecteur $W$ entre l'entrée $X_{in}$ et la sortie $X_{out}$~:
\begin{equation}
\label{eq:ForwardPointwise}
X_{out} = F(W,\Trf,X_{in}) = \Trf(X_{in}+W)
\end{equation}
Les vecteurs $X_{in}$, $X_{out}$ et $W$ doivent tous avoir la même taille et sont tous de type colonne. La fonction scalaire $\Trf$ peut ici être vue comme un paramètre supplémentaire et particulier de la fonction $F$. Bien que diverses fonctions $\Trf$ puissent effectivement être considérées, ce paramètre de la fonction $F$ reste constant durant le processus d'optimisation et fait partie de la définition du réseau~; il ne fait pas de paramètres optimisés par descente de gradient. Pour rester strictement dans le modèle décrit, il faudrait considérer un type de module point à point et de fonction $F$ par fonction $\Trf$. En pratique, $\Trf$ est considérée comme un hyper-paramètre dans la définition du réseau, comme le nombre, le type et la taille des différentes couches et, plus généralement, comme la spécification du graphe complet.

Cette fois encore, la définition de la fonction $F$ conduit à des expressions simples et à des calculs efficaces pour les fonctions de rétro-propagation~:
\begin{eqnarray}
\label{eq:BackPropFuncPointwiseD}
\frac{\partial E}{\partial X_{in}} & = & \frac{\partial E}{\partial X_{out}} \circ (\Trf'(X_{in}+B))^\top \\
\label{eq:BackPropFuncPointwiseP}
\frac{\partial E}{\partial B} & = & \frac{\partial E}{\partial X_{out}} \circ (\Trf'(X_{in}+B))^\top
\end{eqnarray}
$\circ$ est ici le produit de Hadamard entre deux vecteurs (lignes), c'est-à-dire le vecteur composé des produits terme à terme. On remarque que les gradients par rapport à $X_{in}$ et par rapport à $B$ sont identiques.

\textbf{Le module critère} peut être vu et implémenté comme un cas particulier de module couche avec les spécificités suivantes : les vecteurs $W$ et $\partial E/\partial W$ sont de taille nulle puisque ce module n'a pas de paramètre ; le gradient descendant est un vecteur de taille 1 dont la valeur est la constante 1 (correspondant à $\partial E/\partial E$); et le module a deux entrées de données au lieu d'une (on ne calcule cependant que le gradient par rapport à l'entrée~$X_N$, le gradient par rapport à~$\by$ n'étant pas nécessaire pour le calcul de~$\partial E / \partial W$).

Dans le cas d'une fonction de coût basée sur une distance euclidienne~:
\begin{equation}
\label{eq:ForwardEuclidean}
E = C(X_N,\by) = \frac{1}{2}\left\Vert X_N-\by \right\Vert^2
\end{equation}
la fonction de rétropropagation appliquée à la constante 1 donne~:
\begin{eqnarray}
\label{eq:BackPropFuncEuclideanD}
\frac{\partial E}{\partial X_N} & = & (X_N-\by)^T
\end{eqnarray}
Comme dans tous les cas où il n'y a pas de paramètre, il n'y a pas de fonction de rétro-propagation correspondante.


%%%%%%%%%%%%%
%
% Le principe de la minimisation du risque empirique pour trouver les paramètres d'un modèle est déjà présenté au cahpitre sur les modèles 
% discriminants et 
% 
%%%%%%%%%%%%%

%\subsubsection{Fonction objectif}
%Considérons une fonction de classification (ou de régression) $F$ dépendant d'un vecteur de paramètres $W$ qui, à une entrée $\obs$, fait correspondre un vecteur de sortie $\by$, correspondant au vecteur indicateur de classe associé à $\y$. On note~: $O = \Trf_W(I)$ ou $O = \Trf(W,I)$. $W$ est ici un vecteur de nombre réels. $O$ et $I$ sont également des vecteurs de nombres réels (ou un scalaire réel) et la fonction $\Trf$ est supposée continûment différentiable par rapport à $I$ et par rapport à $W$.

%On dispose d'un ensemble données d'entraînement $S$ composé de paires constituées chacune d'un exemple (ou échantillon) d'entrée et de la sortie attendue correspondante. On note~: $S = (I_p,O_p)_{1 \leq p \leq P}$, $P$ étant le nombre d'exemples d'apprentissage. On souhaite déterminer un vecteur de paramètres $W$ tel que la fonction $\Trf_W$ généralise au mieux $S$ pour des valeurs d'entrée $I$ quelconques. Dans ce but, on utilise une fonction ``objectif'' $\mathcal{L}$ qui permet d'associer un ``coût'' moyen à un vecteur de paramètres $W$ relativement aux données d'entraînement $S$. On note~:
%\begin{equation}
%\label{eq:ObjFunc}
%\mathcal{L}_S(W) = \frac{1}{P}\sum_{p=1}^{p=P}C(\Trf_W(I_p),O_p)
%\end{equation}
%La fonction $C$ ou encore le ``critère'', égalemant supposée continûment différentiable, mesure l'erreur entre une valeur prédite $\Trf_W(I_p)$ et la sortie attendue $O_p$ correspondante. La fonction objectif $\mathcal{L}$ est souvent complétée par un terme dit de régularisation $\Omega(W)$ dont le but est de prévenir le surapprentissage et/ou la divergence du vecteur de paramètres au cours du processus d'optimisation~:
%\begin{equation}
%\label{eq:ObjFuncReg}
%\mathcal{L}_S(W) = \frac{1}{P}\sum_{p=1}^{p=P}C(\Trf_W(I_p),O_p) + \lambda \Omega(W)
%\end{equation}
%La fonction $\Omega$ est elle aussi choisie comme continûment différentiable et le paramètre $\lambda$ sert à spécifier la ``force'' relative souhaitée pour le terme de régularisation. Ce type de paramètre est appelé {\em hyper-paramètre} car, contrairement aux composantes de $W$, il ne détermine pas le comportement de la fonction à apprendre elle-même mais au contraire le comportement de l'algorithme d'apprentissage. Les hyper-paramètres sont en général déterminés de manière empirique, le plus souvent par validation croisée. 

%Par exemple, l'erreur peut être mesurée par la distance euclidienne et la régularisation peut se faire en minimisant la norme du vecteur $W$~:
%\begin{equation}
%\label{eq:ObjFuncRegEx}
%\mathcal{L}_S(W) = \frac{1}{P}\sum_{p=1}^{p=P} \frac{1}{2}\left\Vert \Trf_W(I_p)-O_p \right\Vert^2 + \frac{\lambda}{2} \left\Vert W \right\Vert^2
%\end{equation}

%\subsubsection{Descente de gradient}

%Dans le cas ci-dessus, $\Trf$, $C$ et éventuellement $\Omega$ étant supposée continûment différentiables, $\mathcal{L}$ l'est également. Nous cherchons à trouver la valeur de $W$ qui minimise $\mathcal{L}_S(W)$. Nous considèrerons $S$ constant et nous supprimerons donc l'indice $S$ dans cette section.

%La descente de gradient ou la descente selon la plus forte pente (respectivement \textit{gradient descent} et \textit{steepest descent})\index{gradient!descent |see{algorithme du gradient}} est\index{steepest descent |see{algorithme du gradient}} une approche d'optimisation itérative simple et populaire pour trouver le minimum d'une fonction objectif convexe et différentiable. On initialise le vecteur $W^{(0)}$ de façon aléatoire et on minimise la fonction objectif $\mathcal{L}$ en mettant à jour itérativement le vecteur $W^{(t)}$. Cette mise à jour se fait en allant dans la direction opposée à celle du gradient\index{direction de descente!gradient} de la fonction objectif, qui indique localement la plus forte pente de cette fonction. Ainsi, à l'itération $t$, la nouvelle valeur $W^{(t+1)}$ est estimée d'après la valeur à l'étape précédente $W^{(t)}$ et le gradient\index{vecteur!gradient} $\partial \mathcal{L}/\partial W$ de la fonction objectif estimé pour cette même valeur $W^{(t)}$~:
%\begin{equation}
%\label{eq:GradientDescent}
%W^{(t+1)}=W^{(t)}-\eta\left(\nabla\mathcal{L}(W^{(t)})\right)^\top=W^{(t)}-\eta\left(\frac{\partial\mathcal{L}}{\partial W}(W^{(t)})\right)^\top
%\end{equation}
%où $\eta$ est un réel strictement positif appelé le pas (ou le taux) d'apprentissage\index{pas d'apprentissage}\index{learning rate|see{pas d'apprentissage}}. La transposition de $\partial\mathcal{L}/\partial W$ est nécessaire car si $W$ est un vecteur colonne, $\partial \mathcal{L}/\partial W$ doit être un vecteur ligne (de façon à ce qu'on puisse écrire $d\mathcal{L}=(\partial \mathcal{L}/\partial W).dW$ comme le produit d'un vecteur ligne par un vecteur colonne). Pour simplifier l'écriture, on ommettra l'opérateur de transposition et on le considèrera comme implicite dans les variantes suivantes de l'équation~\ref{eq:GradientDescent} (sauf pour l'équation~\ref{eq:GradientDescent2}).
% colonne = contravariant
% ligne = covariant
% LeCun et Ranzato, Tutoriel ICML 2013, slide 41

%La multiplication par $\eta$ combinée avec la transposition peut alternativement être remplacée par un opérateur linéaire qui transforme un vecteur ligne en vecteur colonne. Dans le cas où la fonction $\mathcal{L}$ est deux fois différentiable et suffisamment régulière, le meilleur choix est d'utiliser $((\partial^2 \mathcal{L}/\partial W^2)^{-1})(W^{(t)})$.
%\begin{equation}
%\label{eq:GradientDescent2}
%W^{(t+1)}=W^{(t)}-\left(\frac{\partial\mathcal{L}}{\partial W}(W^{(t)})\right)\left(\frac{\partial^2\mathcal{L}}{\partial W^2}(W^{(t)})\right)^{-1}
%\end{equation}
%Ceci revient à utiliser à la fois le gradient et la courbure de la fonction $\mathcal{L}$ pour estimer au mieux la position du minimum de la fonction (ou d'un de ses minimums locaux)\footnote{C'est la version multi-dimensionnelle de la méthode de Newton-Raphson appliquée à la recherche du point (ou d'un point) pour lequel gradient de la fonction $\mathcal{L}$ est nul. Si $W$ est un vecteur colonne, $\partial \mathcal{L}/\partial W$ est un vecteur ligne, $\partial^2 \mathcal{L}/\partial W^2$ est un tenseur d'ordre 2 ``doublement ligne'' et son inverse est une tenseur d'ordre 2 ``doublement colonne'', lequel multiplié (à gauche) par le vecteur ligne $\partial \mathcal{L}/\partial W$ donne bien un vecteur colonne qui peut être ajouté directement à $W$. Le tenseur $(\partial^2 \mathcal{L}/\partial W^2)^{-1}$ étant symmétrique, le choix de l'indice colonne par rapport auquel on effectue le produit ligne-colonne n'a pas d'importance.} Par rapport à la méthode simple décrite dans l'équation~\ref{eq:GradientDescent}, cette stratégie donne à la fois la meilleure direction possible et le meilleur déplacement possible dans cette direction, le tout sans avoir à choisir un pas d'apprentissage. Malheureusement, la calcul de $\partial^2 \mathcal{L}/\partial W^2$ et a fortiori son inversion, ou même simplement l'application de l'inverse au vecteur gradient sans la calculer complètement sont impraticables pour des vecteurs $W$ de grande ou très grande dimension et, dans la cas des réseaux de neurones, on n'utilise que la version du premier ordre qui donne seulement une direction de descente mais pas forcément la meilleure et aucun indice sur l'amplitude du déplacement à effectuer.

%Une des difficultés d'utilisation de l'algorithme au premier ordre est donc le choix du pas d'apprentissage. Si ce pas est trop grand, la règle de mise à jour (Eq. \ref{eq:GradientDescent}) peut amener à des mouvements d'oscillation autour du minimum ou même à une divergence. Si le pas est trop petit, la convergence vers le minimum se fera très lentement et, dans certains cas, elle peut devenir vite irréaliste (voir exercice {\color{red} TBD}). En pratique, on utilise souvent un pas d'apprentissage variable en fonction de l'itération, $\eta(t)$. Le paramètre $\eta$ ou les paramètres déterminant la loi $\eta(t)$ sont également des hyper-paramètres.

%Si la fonction $\mathcal{L}$ est convexe et bornée inférieurement, elle a un minimum global unique et, si le pas d'apprentissage $\eta$ est choisi suffisamment petit, on montre que l'agorithme de descente de gradient converge vers ce minimum. Dans le cas des réseaux de neurones à plus d'une couche, la fonction $\mathcal{L}$ n'est en général pas convexe et elle présente un nombre extrêmement grand de minimums locaux. Heureusement, en pratique, si le pas d'apprentissage $\eta$ est choisi suffisamment petit ou, plus précisément, si la loi $\eta(t)$ est bien choisie, l'algorithme converge toujours vers un minimum local. La position exacte ainsi que la qualité de ce minimum local dépendent de la valeur initiale $W(0)$ choisie, de la loi $\eta(t)$ et parfois d'autres facteurs comme par exemple des arrondis de calcul. Dans le cas des réseaux de neurones, il a été observé en pratique que la plupart des minimums locaux trouvés par l'algorithme de descente de gradient sont de qualité équivalente ou presque, c'est à dire que les fonctions de classification qu'ils définissent ont des performances équivalentes ou presque en généralisation~\citep{kawaguchi:2016}.

%\subsubsection{Descente de gradient stochastique}

%Dans les cas d'une fonction objectif définie comme dans les équations~\ref{eq:ObjFunc} ou~\ref{eq:ObjFuncReg}, on peut écrire~:
%\begin{equation}
%\label{eq:ObjFuncRegSum}
%\mathcal{L}_S(W) = \frac{1}{P}\sum_{p=1}^{p=P}\mathcal{L}_p(W)
%\end{equation}
%avec~:
%\begin{equation}
%\label{eq:ObjFuncRegSamp}
%\mathcal{L}_p(W) = C(\Trf_W(I_p),O_p) + \lambda \Omega(W)
%\end{equation}
%La formule formule~\ref{eq:GradientDescent} de mise à jour du vecteur de paramètres devient alors~:
%\begin{equation}
%\label{eq:SumGradientDescent}
%W(t+1)=W(t)-\frac{\eta}{P}\sum_{p=1}^{p=P}\nabla\mathcal{L}_p(W(t))
%\end{equation}
%La descente de gradient {\em stochastique} consiste à remplacer chacune des itérations effectuée selon cette formule par une séquence, appelée {\em époque}, de $P$ itérations selon l'indice $p$ de la formule~:
%\begin{equation}
%\label{eq:StoGradientDescent}
%W(t+1)=W(t)-\frac{\eta}{P}\nabla\mathcal{L}_p(W(t))
%\end{equation}
%L'avantage principal de la descente de gradient stochastique est que la correction sur le vecteur $W$ apportée par le traitement d'un échantillon est immédiatement prise en compte pour le traitement des échantillons suivants, ce qui assure une convergence plus rapide. Dans le cas de la descente de gradient simple, cette prise en compte n'intervient que lorsque tous les échantillons correspondant à une époque ont été traités.

%L'inconvénient est que chaque correction est bruitée car elle n'intègre l'information que d'un seul échantillon et, si la correction globale se fait statistiquement dans la bonne direction, ce n'est pas forcément le cas de chaque correction individuelle. Ceci est atténué par le facteur $1/P$ qui la pondère mais l'effet peut être ponctuellement très négatif.

%La complexité globale ne change pas approximativement car si le nombre d'itérations est multiplié par $P$, le nombre de calculs de gradients ne change pas, ceux-ci devant de toutes façon être calculés indépendament pour chaque échantillon comme indiqué dans la formule~\ref{eq:SumGradientDescent}.

\subsection{Réseaux quelconques}

Il est possible de créer des réseaux selon un graphe orienté quelconque pourvu que celui-ci soit acyclique. Les n{\oe}uds correspondent aux modules couches et les arcs correspondent aux données, lesquelles sont toujours des vecteurs de nombres réels. Chaque arc reliant les modules couches transmet les données dans le sens avant et le gradient de l'erreur par rapport à cette même donnée dans le sens opposé, comme indiqué dans la figure~\ref{fig:Archi} qui correspond au cas ou chaque module couche a une seule entrée et une seule sortie.

Si plusieurs arcs arrivent sur un même n{\oe}ud, la fonction de propagation prend en entrée un vecteur de données par arc entrant plus un vecteur de paramètres, celui-ci pouvant être de taille nulle. On remarque que le module couche décrit dans la figure~\ref{fig:LayerModule} et les deux fonctions de rétro-propagation du gradient dérivées définies dans les équations~\ref{eq:BackPropFuncD} et~\ref{eq:BackPropFuncP} sont parfaitement symétriques d'un point de vue interne au module par rapport aux deux vecteurs d'entrée $X_{in}$ et $W$. Les modules couches se généralisent facilement au cas de fonctions de propagation prenant plusieurs vecteurs de données et/ou plusieurs vecteurs de paramètres en entrée~; le gradient de la sortie est alors rétro-propagé de la même façon pour chacune des entrées, qu'elle soit de type donnée ou de type paramètre.

Si plusieurs arcs partent d'un même n{\oe}ud, les gradients arrivant en retour sont sommés avant d'être passés aux fonctions de rétro-propagation. Si un même vecteur de paramètres est utilisé par plusieurs n{\oe}uds, tous les gradients correspondants doivent également être sommés avant d'être retournés au module optimiseur. En pratique aussi, il est possible qu'un module couche reçoive plusieurs vecteurs de paramètres comme il peut recevoir plusieurs vecteurs de données et, du point de vue interne au module, tous ces vecteurs apparaissent de manière complètement symétrique.

Les gradients correspondant aux entrées du réseau ($\obs$ et $\by$ dans le cas du réseau décrit dans la figure~\ref{fig:Archi}) ne sont pas utilisés et n'ont pas besoin d'être calculés. Le calcul de la sortie finale~$E$ n'est pas non plus nécessaire pour l'optimisation de~$W$ mais elle peut être utile car, en moyennant sa valeur sur les différentes époques (voir la section~\ref{sec:mini-batch}), on peut mesurer l'évolution de la fonction-objectif au cours de celles-ci. Cette information peut servir pour définir un critère d'arrêt et/ou pour décider de l'évolution du taux d'apprentissage~$\eta$.

\subsection{Différentiation automatique}

\index{différentiation automatique}De nombreux outils sont capables de générer et d'appliquer automatiquement, pour chaque module, les fonctions de rétro-propagation à partir de la définition de la fonction de propagation $\Trf$. Ces outils sont capables de traiter des graphes orientés acycliques quelconques à partir de la seule définition du graphe et des fonctions de propagation \guil{avant} \citep{baydin:2015}. Ils propagent les données et rétro-propagent les gradients correspondants automatiquement pour des fonctions ayant un nombre quelconque d'entrées. Ils ne font aucune différence selon le type des entrées, donnée ou paramètre. Cette différence apparaît uniquement au niveau des connexions (arcs) : celles qui se font directement avec le module optimiseur correspondent aux paramètres et toutes les autres correspondent aux données. Les sorties sont toujours des données.

\smallskip
Chaque arc du graphe, qu'il soit de type donnée ou de type paramètre, correspond à une variable vectorielle $V$ de type colonne, qui est doublée, chaque fois que le gradient correspondant est nécessaire, d'une variable vectorielle associée $\partial E/\partial V$ de type ligne. En pratique, ces deux variables sont stockées séquentiellement dans un tableau en mémoire avec leurs composantes dans un ordre correspondant, indépendamment du fait qu'elles soient de type ligne ou colonne. Plus généralement, ces variables peuvent être des tenseurs d'ordre deux comme les matrices $W$ des modules linéaires, ou d'ordre supérieur comme les tenseurs définissant les filtres dans les couches convolutionnelles. Ces tenseurs et les tenseurs transposés pour les gradients sont également stockés de manière sérialisée comme des tableaux en mémoire. Pour la plupart, les outils de différentiation automatiques savent gérer directement ce type de variables multi-dimensionnelles, rendant inutiles les opérations effectives de désérialisation de ces variables et de resérialisation de leurs gradients. Celles-ce ne sont en fait nécessaires que conceptuellement pour faciliter la formalisation de la méthode de rétro-propagation du gradient.

\section{Réseaux convolutifs}
\label{sec:ConvNets}

\subsection{Couche de convolution}
\label{sec:ConvNets}

Dans les réseaux PMC que nous avons vus jusqu'ici (section~\ref{sec:ch4:PMC}), chaque couche est constituée d'un ensemble de neurones formels qui sont tous connectés à tous les neurones formels de la couche précédente (ou à toutes les entrées pour la première couche). Dans ce schéma de connexion \guil{tous vers tous} (ou FC pour {\em fully connected}), tous les poids de toutes les connexions et tous les biais de tous les neurones sont indépendants. Par ailleurs, il n'y a pas de topologie dans l'organisation des neurones dans les couches, ceux-ci constituant un ensemble et non pas un vecteur, une matrice ou une autre structure, même si les valeurs d'entrée ou de sortie sont en pratique rassemblées dans des vecteurs de nombre réels.

\smallskip
Dans un certain nombre de cas cependant, les données d'entrée sont organisées selon une certaine topologie, le cas typique étant celui des images pour lesquelles une topologie de grille à deux dimensions existe naturellement. Dans ces cas, il est intéressant de la préserver et de l'exploiter, au moins dans les premières couches des réseaux, pour optimiser l'utilisation des paramètres disponibles et de la capacité de calcul. Ceci se fait, d'une part, en limitant les connexions possibles selon une distance maximum dans la grille et, d'autre part, en partageant les poids entre les unités d'une même couche qui ont différentes positions dans la grille. Ceci conduit à des opérations de type convolutions, qui sont invariantes par translation et qui ont un support limité, à la place d'opérations de type produits d'une matrice par un vecteur. En fait, en pratique, on combine les deux. Pour cela, on associe non pas un neurone unique à chaque position dans la grille, mais un ensemble de neurones identiques d'une position à une autre.

\smallskip
Si les données d'entrée sont organisées selon une grille à $D$ dimensions (par exemple $D=1$ pour un signal audio, $D=2$ pour un signal image, $D=3$ pour un signal vidéo ou pour des données de scanner), celles manipulées par les couches en entrée et en sortie auront les mêmes $D$~dimensions topologiques plus une dimension {\em non topologique} qui correspond au fait que ces données sont composées de valeurs multiples en chaque point de la grille. Ces dernières se retrouvent de la même façon en chaque point de la grille où elles constituent des {\em cartes}, chacune étant un tableau avec une valeur par position dans la grille. Le nombre de ces cartes est fixé indépendamment pour chaque étape dans le traitement des données.

\smallskip
Dans le cas d'une topologie à deux dimensions, les données d'entrée $X_{in}$ et de sortie $X_{out}$ sont des tenseurs d'ordre 3, respectivement de taille ${d_{in} \times w_{in} \times h_{in}}$ et ${d_{out} \times w_{out} \times h_{out}}$ ; $d_{in}$ et $d_{out}$ sont les nombre de cartes dans $X_{in}$ et dans $X_{out}$ ; $w_{in} \times h_{in}$ et $w_{out} \times h_{out}$ sont les tailles des grilles sur lesquelles sont définis $X_{in}$ et $X_{out}$. La partie linéaire (ou affine) d'une couche de convolution est définie par~:
\begin{equation}
\label{eq:convFilter}
X_{out}(l,i,j) = B(l)+\sum_{k=1}^{k=d_{in}} \sum_{m=-w}^{m=+w} \sum_{n=-w}^{n=+w} K(l,k,m,n)X_{in}(k,i-m,j-n)
\end{equation}
pour $1 \leq i \leq w_{out}$, $1 \leq j \leq h_{out}$ et $1 \leq l \leq d_{out}$.  $w$ est la distance maximum dans la grille à laquelle des points peuvent être connectés.

\smallskip
Les $d_{out}$ cartes de $X_{out}$ sont calculées indépendamment les unes des autres et chacune à partir de l'ensemble des $d_{in}$ cartes de $X_{in}$. Un opérateur qui calcule une des cartes de sortie à partir de l'ensemble des cartes d'entrée est appelé un {\em filtre} de convolution. Chacun de ces $d_{out}$ filtres est défini par un scalaire $B(l)$ et par un tenseur d'ordre 3 $K(l,.,.,.)$ appelé {\em noyau} de ce filtre. La taille de ce noyau est $d_{in} \times (2w+1) \times (2w+1)$ et on convient que la taille du filtre est de $(2w+1) \times (2w+1)$. La couche de convolution complète est définie par le vecteur $B$ et le tenseur d'ordre 4 $K$.

\smallskip
On remarque que, si on a $d_{out} = d_{in} = 1$, l'équation~\ref{eq:convFilter} se réduit à une convolution classique en deux dimensions (plus un biais). De même, si on a $w = 0$, l'équation~\ref{eq:convFilter} se réduit à un réseau de type \guil{tous vers tous} répété de manière identique et indépendante en chaque point de la grille (couche de convolution $1 \times 1$).

\smallskip
On remarque aussi que l'équation~\ref{eq:convFilter} peut conduire à des \guil{effets de bord} si les indices $i-m$ et/ou $j-m$ désignent des points en dehors de la grille définie pour $X_{in}$. Il y a deux façons de les résoudre~: la première est d'étendre $X_{in}$ sur les côtés, soit par continuité, soit avec des valeurs constantes ({\em padding}), la seconde est de réduire la taille de la grille de sortie, typiquement en choisissant $w_{out} = w_{in}-2w$ et $h_{out} = h_{in}-2w$ (ce qui nécessite aussi de prévoir un décalage de $w$ dans les indices).

\smallskip
Par rapport au formalisme présenté dans la section~\ref{sec:feed-forward}, le vecteur des biais $B$ et le tenseur des noyaux $K$ constituent, une fois sérialisés, le vecteur de paramètres $W$ définissant la partie linéaire (ou affine) de la couche de convolution. Une particularité est que ce vecteur $W$ est en fait utilisé autant de fois qu'il y a de positions dans la grille pour la passe de propagation avant. En ce qui concerne les passes de propagation arrière, un vecteur de gradient doit être calculé pour chaque position et accumulé selon l'ensemble des positions pour le traitement de chaque image d'entrée.

\smallskip
En ce qui concerne l'application des \index{fonction!d'activation}fonctions d'activation, elle reste faite point à point~: pour chaque position dans la grille et pour chaque carte. Elle ne fait pas intervenir de paramètre si le biais est pris en compte dans la couche linéaire (qui devient alors affine).

\subsection{Changements de résolution}

Dans les réseaux profonds traitant les données de bout en bout ({\em end-to-end}), les données brutes sont entrées directement sans prétraitement, ou avec des prétraitements minimaux comme une mise à l'échelle et une normalisation de l'intensité pour les images fixes. Pour les images en couleurs, les trois plans RVB peuvent être entrés directement comme trois cartes avec une taille de grille correspondant à celle de l'image après mise à l'échelle. En général, au fur et à mesure que l'on avance dans les traitements, et donc dans les couches neuronales, on réduit progressivement la résolution des grilles de façon à diminuer la taille des représentations et d'augmenter leur niveau d'abstraction.

\smallskip
Il y a deux manières de réduire la résolution des représentations~: par simple sous-échantillonage ({\em stride}), c'est-à-dire qu'on ne calcule, par exemple, qu'une valeur sur deux ou sur quatre dans chaque dimension, ou par regroupement ({\em pooling}) en utilisant un opérateur associatif, en général le maximum ({\em max-pooling})\index{max-pooling} ou la moyenne ({\em average-pooling}), sur des blocs typiquement de taille $2 \times 2$. Par rapport au formalisme présenté dans la section~\ref{sec:feed-forward}, les opérateurs de changement de résolution basés sur un regroupement correspondent à un type de module couche particulier, avec des fonctions de propagation avant et de rétro-propagation spécifiques, qui s'insère entre les couches point à point précédentes et les couches linéaires suivantes.

\smallskip
Selon la profondeur (nombre de couches neuronales) des réseaux, les changements de résolution sont effectués seulement de temps en temps entre deux couches. En général aussi, lorqu'on réduit la résolution des grilles, on augmente en même temps le nombre de cartes, de façon à conserver une quantité d'information globale suffisante. L'augmentation du nombre de cartes ne compense toutefois pas totalement le changement de résolution.

\subsection{Passage à des couches complètement connectées}

Vers la fin des traitements, on revient en général à des couches complètement connectées classiques. Elles sont en général peu nombreuses, typiquement de une à trois. Il doit y avoir une transition entre la dernière couche topologique et la première couche complètement connectée. Ceci se fait simplement par la sérialisation des représentations produites par la dernière couche topologique. Une dernière étape de changement de résolution ou de regroupement peut être définie entre les deux.

\subsection{Un exemple : AlexNet}

Le tableau~\ref{tab:AlexNet} décrit l'architecture du réseau \guil{AlexNet}~\citep{krizhevsky:2012} qui a remporté très largement en 2012 le défi ILSVRC~\citep{russakovsky:2015}. La donnée d'entrée est directement constituée des trois plans RVB de l'image après un simple redimensionnement/rognage pour arriver à une taille fixe de $224\times224$. La valeur moyenne pixel par pixel sur l'ensemble d'entraînement est également soustraite. La donnée de sortie est directement un vecteur de 1000 valeurs qui correspondent aux probabilités de présence de chacune des 1000 classes à détecter.

\begin{table}[htbp]
\caption{Description des couches du réseau AlexNet}
\label{tab:AlexNet}
\vspace{2mm}
\begin{center}
\begin{tabular}{l}
\hline
Donnée d'entrée : $3\times224\times224$ \\[-5pt]
Conv1 : 96 filtres de taille $11\times11$ avec stride de 4 \\[-5pt]
Donnée cachée : $96\times55\times55$ \\[-5pt]
Conv2 : 256 filtres de taille $5\times5$ avec max-pooling $2\times2$ \\[-5pt]
Donnée cachée : $256\times27\times27$ \\[-5pt]
Conv3 : 384 filtres de taille $3\times3$ avec max-pooling $2\times2$ \\[-5pt]
Donnée cachée : $384\times13\times13$ \\[-5pt]
Conv4 : 384 filtres de taille $3\times3$ sans stride ni pooling \\[-5pt]
Donnée cachée : $384\times13\times13$ \\[-5pt]
Conv5 : 256 filtres de taille $3\times3$ avec max-pooling $2\times2$ \\[-5pt]
Donnée cachée : $256\times6\times6$ sérialisée en 9216 valeurs \\[-5pt]
FC6 : 4096 neurones à 9216 entrées \\[-5pt]
Donnée cachée : 4096 valeurs \\[-5pt]
FC7 : 4096 neurones à 4096 entrées \\[-5pt]
Donnée cachée : 4096 valeurs \\[-5pt]
FC8 : 1000 neurones à 4096 entrées \\[-5pt]
Donnée de sortie : 1000 valeurs \\
\hline
\end{tabular}
\end{center}
\end{table}

Il est à noter que chacune des couches de convolution (Conv) et chacune des couches complètement connectées (FC) correspond en réalité à deux ou plus fonctions $F_n(W_n)$ et donc à deux ou plus modules couches au sens défini dans les sections~\ref{sec:func-comp} et~\ref{sec:arch-mod}. Les deux premières fonctions sont toujours la partie linéaire (ou affine) et la fonction d'activation point à point, laquelle est toujours ici la fonction ReLU (section~\ref{sec:act-func}). Quand elle est présente, l'opération de {\em max-pooling} correspond à une fonction supplémentaire. Une normalisation locale correspondant à une inhibition latérale locale entre les cartes est également insérée après la fonction d'activation des couches de convolution 1, 2 et 5. Une opération de {\em dropout} (section~\ref{sec:dropout}) est incluse dans les deux premières couches de convolution. Finalement, une opération de type {\em softmax} est appliquée en plus sur les sorties du réseau dans le but de les normaliser selon des probabilités pour des classes exclusives. Le réseau est au total la composition de 22 fonctions élémentaires successives, chacune correspondant à un module couche dans l'implémentation. Le réseau AlexNet original différait aussi de celui qui est ici décrit par le fait qu'il était constitué de deux branches parallèles partiellement couplées de façon à les distribuer sur deux cartes GPU.

\section{Optimisations supplémentaires}

\subsection{Traitement par mini-lots}
\label{sec:mini-batch}

En pratique, on utilise souvent une solution intermédiaire entre la descente de gradient stochastique\index{gradient!stochastique} pure, qui effectue une mise à jour de~$W$ pour chaque échantillon, et la descente de gradient classique, qui effectue chaque mise à jour en utilisant l'ensemble des échantillons disponibles selon la formule~\ref{eq:ObjFuncReg}. Cette solution consiste à traiter les échantillons par {\em mini-lots} (ou {\em mini-batchs}), c'est-à-dire qu'on décompose les $P$ échantillons de l'ensmble d'entraînement en $P/B$ mini-lots de $B$ échantillons chacun et qu'on applique la formule de mise à jour~:
\begin{equation}
\label{eq:BatchGradientDescentB}
W(t+1)=W(t)-\frac{\eta}{B}\sum_{b=1}^{b=B}\nabla\mathcal{L}_{p(b)}(W(t))
\end{equation}
Cette formule est appliquée $P/B$ fois pour chaque époque. Dans cette formule, l'indice $p(b)$ parcourt, pour chaque mini-lot, les échantillons associés à celui-ci. Lors d'une époque, chaque échantillon doit apparaître une et une seule fois dans un des mini-lots. Il a été observé expérimentalement qu'il est mieux de permuter aléatoirement et de manière différente à chaque époque les échantillons dans le découpage des mini-lots. L'utilisation de mini-lots facilite la répartition des calculs sur des architectures parallèles comme les GPU. Naturellement, si on prend $B=P$, on retombe sur le cas de la descente de gradient simple, qu'on appelle traitement par lot, les mini-lots correspondant des valeurs de $B$ faibles par rapport à $P$. En pratique, on choisit pour $B$ des valeurs comprises entre 32 et 256.

\subsection{Moment}

La méthode du {\em moment} \citep{polyak:1964,sutskever:2013} consiste à remplacer la formule de mise à jour~\ref{eq:ObjFuncReg} par le couple de formules~:
\begin{eqnarray}
\label{eq:MomGradientDescent}
V^{(t+1)} & = & \mu V^{(t)}-\varepsilon\nabla\mathcal{L}(W^{(t)}) \\
W^{(t+1)} & = & W^{(t)}+V^{(t+1)}
\end{eqnarray}
Par analogie avec la physique, cela revient à attribuer une inertie au vecteur $W$, la correction étant appliquée à sa \guil{vitesse} plutôt qu'à lui-même directement. Cela a pour effet d'étaler et de lisser le bruit apporté par chaque échantillon ou par chaque mini-lot dans la variante stochastique de la descente de gradient. Par ailleurs, si les hyper-paramètres~$\mu$ et~$\varepsilon$ sont bien choisis, la convergence peut être accélérée. $\mu$~doit être compris entre 0 et 1 et il détermine la force de l'inertie ; plus il est proche de 1, plus celle-ci est importante. On choisit typiquement une valeur proche de~0.9. $\varepsilon$~joue le même rôle que le taux d'apprentissage $\eta$. On peut d'ailleurs dériver une valeur équivalente comme $\eta=\varepsilon/(1-\mu)$.


\subsection{Fonctions d'activation}
\label{sec:act-func}

La classe de fonctions globales implémentée par un réseau dépend de l'architecture générale de ce dernier et des paramètres (nombre, taille et type des couches) en déterminant une instance particulière. Pour une même architecture et les mêmes paramètres, la fonction globale dépend de manière cruciale des fonctions d'activation \guil{point à point} utilisées après les transformations linéaires. En théorie, presque n'importe quelle fonction non linéaire peut conduire à une gamme de fonctions globales suffisamment riche pour généraliser n'importe quel jeu de données d'entraînement. En pratique, certaines se révèlent beaucoup plus efficaces que d'autres en termes de qualité de généralisation et de rapidité de convergence. Les fonctions de type \guil{unité linéaire rectifiée} ({\em Rectified Linear Unit} ou ReLU)\index{ReLU}\index{rectified linear unit|see{ReLU}} sont à la fois particulièrement simples et efficaces~\citep{nair:2010}. Elles conduisent à des temps de convergence jusqu'à 10 fois plus courts que les fonctions de type sigmoïdes et elles assurent aussi une convergence là ou les fonctions d'activation classiques ne le permettent pas. Ce sont notamment ces fonctions qui ont permis l'entraînement de réseaux très profonds et ultra-profonds en atténuant très fortement le problème de l'affaiblissement des gradients ({\em vanishing gradients}). La fonction ReLU basique est définie par~:
\begin{equation}
\Trf(z) = \max(0,z)
\end{equation}
Une variante est la fonction PReLU (ReLU programmable)\index{PReLU} définie par~:
\begin{equation}
\Trf(z) = \max(\alpha z,z)
\end{equation}
dans laquelle $\alpha$ est soit une valeur fixe choisie assez petite mais non nulle, typiquement 0.05 ou 0.1, soit un paramètre à apprendre, c'est-à-dire inclus dans le vecteur de paramètre $W$.

\subsection{Dropout}
\label{sec:dropout}

Le {\em dropout} (\guil{abandon} ou \guil{décrochage}) \citep{srivastava:2014} est une technique de régularisation qui consiste à neutraliser aléatoirement une certaine proportion $p$ de connexions à chaque exécution d'une passe avant et d'une passe arrière lors de la phase d'apprentissage. La neutralisation consiste à forcer à zéro la donnée arrivant sur la connexion dans la passe avant et à faire de même avec la composante correspondante du gradient dans la passe arrière. Lors de la phase de reconnaissance, aucune connexion n'est neutralisée, mais chacune est affaiblie dans le rapport $1-p$ de telle sorte que l'intensité moyenne de l'activation reste la même. Ceci a pour effet de répartir la propagation de l'information beaucoup plus uniformément entre les différentes connexions et d'assurer qu'aucune d'entre elles ne domine toutes les autres. Cette technique ralentit la convergence dans la proportion $1/(1-p)$ mais, en contrepartie, elle réduit considérablement les effets de surapprentissage et permet d'atteindre des performances bien supérieures après convergence. En pratique, le {\em dropout} est implémenté sous la forme d'un module couche particulier qui est placé juste en amont d'un module couche linéaire. La fonction implémentée ne rentre pas exactement dans le schéma décrit dans la section~\ref{sec:feed-forward}, car elle varie selon une source aléatoire non modélisée dans ce cadre, mais cela ne pose pas de problème en pratique. Le taux de {\em dropout} est en pratique choisi entre 0.2 et 0.5 et la technique est appliquée surtout sur les couches de convolution.

\subsection{Normalisation de lots}
\label{sec:batch-norm}

La normalisation de lots ({\em batch normalisation})~\citep{ioffe:2015} est une méthode qui vise à accélérer la convergence, ou simplement à la rendre possible, dans le cas de réseaux très profonds ou ultra-profonds. Le problème principal pour cette convergence est que, lorsqu'on met à jour les poids dans certaines couches, cela modifie la distribution (moyenne et variance) des données dans les couches suivantes. Dans le cas, le plus fréquent, où les données d'apprentissage sont traitées par mini-lots (section~\ref{sec:mini-batch}), il est possible de compenser dynamiquement ce changement en normalisant la moyenne et la variance des données au niveau d'un mini-lot, de telle sorte que la couche courante reçoive des données à peu près dans la même plage lors du traitement de chaque nouveau mini-lot. Il convient de compenser par ailleurs ce changement de dynamique, ce que l'on fait en apprenant en même temps les coefficients d'une transformation affine qui replacent la moyenne et la variance des données d'entrée à un niveau optimal. Cette technique donne une convergence jusqu'à 10 fois plus rapide ou simplement assure une convergence qui ne se produirait pas autrement.

\subsection{Augmentation de données}

Le succès des méthodes d'apprentissage profond\index{apprentissage!profond} en classification d'images est dû à un certain nombre de facteurs, parmi lesquels la disponibilité d'exemples annotés avec une bonne qualité et en grande quantité comme dans la collection ImageNet~\citep{russakovsky:2015}. Toutefois, même ces grosses collections contiennent une quantité d'information insuffisante pour apprendre au mieux les dizaines de millions de paramètres que contiennent les modèles les plus avancés. Une technique simple, l'augmentation de données, consiste à accroître artificiellement et de manière importante la quantité et la variabilité des données disponibles pour un coût négligeable. Elle utilise chaque donnée disponible en la modifiant légèrement selon des méthodes qui ne changent pas leur contenu sémantique, donc leurs étiquettes. Dans le cas des images fixes, les transformations possibles sont les translations, les symétries gauche-droite, les rotations, les rognages, les étirements ou les changements de luminosité. Mis à part le cas des symétries, ces transformations doivent rester de petite amplitude, de façon à ce que le contenu sémantique soit préservé. Elles sont en général appliquées dynamiquement et aléatoirement à chaque fois qu'un échantillon est utilisé dans les passes avant et arrière. Leur coût de calcul est en général négligeable devant celui des calculs impliqués dans une passe avant et arrière. L'augmentation des données ne change pas la vitesse de convergence lors de l'entraînement, mais elle améliore souvent fortement la performance du réseau en classification.

%\section{Applications en catégorisation d'i\-ma\-ges et en recherche d'information}

\section{Réseaux pour la catégorisation d'images}

Suite à la percée des réseaux de neurones lors du défi de catégorisation d'images ILSVRC 2012 \citep{krizhevsky:2012,russakovsky:2015}, l'architecture de ces réseaux a évolué très rapidement à la fois vers plus de profondeur et vers plus de généricité. Dans une première étape, deux approches principales ont été explorées, les deux faisant passer des 8 couches (réseaux profonds) d'AlexNet à une vingtaine de couches (réseaux très profonds). La première approche, GoogLeNet~\citep{szegedy:2015}, dans laquelle des modules \guil{inception} sont cascadés, chacun d'entre eux contenant en parallèle trois ou quatre branches de une à deux couches et avec des tailles de filtres variables de $1\times1$ à $5\times5$. Ceci permet de capturer et d'assembler des détails de tailles variables avec une utilisation optimale des paramètres. La seconde approche, VGGNet~\citep{simonyan:2014}, vise au contraire une simplicité maximale~: uniquement des couches de convolution avec des filtres de taille $3\times3$, couches identiques pour une même résolution, doublement du nombre de cartes à chaque division par deux de leur résolution, une seule couche complètement connectée en sortie. Le fait que les filtres soient de taille minimale est compensé par celui qu'une succession de filtres avec un petit support donne globalement des filtres avec un grand support tout en leur permettant de partager des caractéristiques extraites communes. Dans les deux approches, c'est la normalisation de lots (section~\ref{sec:batch-norm}) qui a permis l'entraînement de réseaux aussi profonds.

\smallskip
Dans une seconde étape, des réseaux de plus de 100 couches (ultra-profonds) ont pu être développés grâce à l'utilisation de connexions \guil{court-circuits} capables de faire entrer dans une couche des connexions remontant à plusieurs couches en amont. Dans l'approche ResNet~\citep{he:2016}, un réseau est construit sur la base de VGGNet, mais les couches sont regroupées par deux ou par trois et la sortie du mini-bloc correspondant est combinée de manière additive avec l'entrée du même mini-bloc avant d'être passée au mini-bloc suivant. Le mini-bloc apprend ainsi une correction par rapport à son entrée plutôt qu'une transformation complète. Les connexions courts-circuits permettent à l'information de gradient de remonter avec une intensité plus forte vers les niveaux initiaux et donc au réseau de pouvoir effectivement être entraîné. De fait, les réseaux de type ResNet sont équivalents à un montage à la fois en série et en parallèle des mini-blocs, bénéficiant des avantages des deux montages et conduisant à une profondeur \guil{effective} plus faible que celle du chemin le plus long.

\smallskip
Dans une troisième étape, le principe des connexions courts-circuits a été systématisé. Dans l'approche DenseNet~\citep{huang:2017}, des connexions directes sont implémentées entre toutes les couches faisant partie d'un bloc de résolution donnée, chaque couche recevant alors des entrées de toutes les couches précédentes de même résolution. Ces blocs connectés de façon dense sont séparés par des couches de changement de résolution ({\em max-pooling}). Dans un même bloc, le signal d'entrée peut passer de l'entrée à travers un nombre variable de couches, allant de une au nombre total de couches dans le bloc. Ces voies à la fois en série et en parallèle permettent une réutilisation optimale de toutes les caractéristiques extraites. Elle conduisent également à la remontée d'un signal fort de gradient garantissant un entraînement efficace de ces réseaux.

      \section{Exercices}
      
      
      
      
\begin{itemize}[itemindent=20mm]
\Quest{8.1} Les fonctions-objectifs considérées $\w\mapsto \mathcal{L}(\w)$ pour apprendre les réseaux de neurones sont généralement convexes, continues et doublement dérivables. Dans cet exercice, nous allons nous intéresser à la forme des lignes de niveau de ces fonctions (formées par des points dans l'espace des poids à $\mathcal{L}$ constant) autour de leur minimum. 


\begin{itemize}
\item[a)] Montrer que le développement  de Taylor d'ordre 2\index{développement de Taylor} de $\mathcal{L}(\w)$ autour de son minimum atteint au point $\w^*$ est~:
\begin{equation}
\label{eq:Approximation}
\mathcal{L}(\w)=\mathcal{L}(\w^*)+\frac{1}{2}(\w-\w^*)^{\top}\mathbf{H}(\w-\w^*)+o(\parallel \w-\w^*\parallel^2)
\end{equation}
où $\mathbf{H}$ est la matrice hessienne\index{hessienne} de la fonction de coût \index{coût!convexe} $\mathcal{L}(\w)$, estimée au point~$\w^*$ et l'exposant $^\top$ est le signe de transposée.
\item[b)] Montrer que la matrice hessienne $\mathbf{H}$ est symétrique\index{hessienne!symétrique positive définie}.
\item[c)] D'après le théorème de Schwarz\index{théorème!de Schwarz}, en déduire que les vecteurs propres\index{vecteur!propre} $(\boldsymbol v_i)_{i=1}^d$ de  $\mathbf{H}$ forment une base orthonormée. 
\item[d)] Pour tout vecteur $\w$ qui se trouve au voisinage du minimiseur de la fonction de coût, montrer que $\w-\w^*$ peut se décomposer sur cette base de façon unique :
\begin{equation}
\label{eq:Decomposition}
\w-\w^*=\sum_{i=1}^d q_i v_i 
\end{equation}
\item[e)] En substituant cette égalité dans l'équation (eq. \ref{eq:Approximation}), montrer que~:
\begin{equation}
\label{eq:Approx2}
\mathcal{L}(\w)=\mathcal{L}(\w^*)+\frac{1}{2} \sum_{i=1}^d \lambda_i q_i^2 
\end{equation}
\item[f)] La semi-définie positivité de la matrice hessienne, montrer que les valeurs propres\index{valeur propre} de $\mathbf{H}$ sont ainsi toutes positives, ainsi que l'équation~\ref{eq:Approx2}.
\item[g)] En déduire que les lignes de niveau\index{ligne de niveau} de $\mathbf{H}$\index{hessienne} sont des ellipses.
\end{itemize}

\Quest{8.2} Dans cet exercice, nous allons nous intéresser à la convergence de l'algorithme de la descente du gradient utilisé comme outil de base pour l'apprentissage des poids des réseaux de neurones pour certaines valeurs du pas d'apprentissge. Soit $\mathcal{L}(\w)$ une fonction de coût continue et doublement dérivable. Considérons le développement de Taylor\index{développement de Taylor} d'ordre 2 de $\mathcal{L}(\w)$  autour de son minimum global atteint en  $\w^*$ (ex. 7.1, eq. \ref{eq:Approximation}). 
\begin{itemize}
\item[a)] Montrer que la dérivée de l'approximation de $\mathcal{L}(\w)$ à un point $\w$ au voisinage du minimum $\w^*$ s'écrit~:
\[
\nabla \mathcal{L}(\w)=\mathbf{H}(\w-\w^*)
\] 
\item[b)] En prenant la décomposition du vecteur $\w-\w^*$ sur la base orthonormée $(\boldsymbol v_i)_{i=1}^d$ constituée des vecteurs propres\index{vecteur!propre} de la hessienne\index{hessienne} $\mathbb{H}$ estimée au point $\w^*$, montrer que~:
\[
\nabla \mathcal{L}(\w)=\sum_{i=1}^d q_i \lambda_i \boldsymbol{v}_i
\]
\item[c)] Pour $t\in \mathbb{N}^*$, soit $\w^{(t-1)}$ et $\w^{(t)}$ les vecteurs poids obtenus après $t-1$ et $t$ applications de l'algorithme du gradient (chapitre \ref{ch:optimisation})~:
\[
\w^{(t)}=\w^{(t-1)}-\eta\nabla \mathcal{L}(\w^{(t-1)})
\]
où $\nabla \mathcal{L}(\w^{(t-1)})$ est le gradient de la fonction-objectif au point $\w^{(t-1)}$. En vous aidant de la propriété d'orthonormalité des vecteurs propres\index{vecteur!propre}, montrer que :
\[
\forall i, q^{(t)}_i-q^{(t-1)}_i=-\eta q^{(t-1)}_i \lambda_i 
\]
\item[e)] En déduire qu'après $t$ mises à jour du vecteur poids, nous avons :
\[
\forall i, q^{(t)}_i=(1-\eta \lambda_i)^t q^{(0)}_i
\]
\item[f)] Quelle est la condition pour assurer la convergence et pour quelle valeur du pas d'apprentissage aura-t-elle lieu?
\end{itemize}

\Quest{8.3} Dans cet exercice, nous nous intéressons à la convergence de l'algorithme du Perceptron\index{algorithme!perceptron} (algorithme \ref{algo:chap5:Perceptron}) dans le cas où les données d'une base d'apprentissage $S=(\obs_i,y_i)_{1\le i \le m}$ sont linéairement séparables, résultat proposé par \cite{novikoff:1962}.
\begin{itemize}
\item[a)] Nous supposons qu'il existe des poids $\w^*$ tels que ${\forall (\obs_i,y_i)\in S; y_i\times \langle \w^*,\obs_i\rangle >0}$ et nous définissons ${\rho=\mathop{\min}_{i\in\{1,\ldots,m\}} \left(y_i\langle\frac{w^*}{||w^*||},\\obs_i\rangle\right)}$. Que représente $\rho$? 
\item[b)] Montrer que, dans le cas où les données d'apprentissage sont linéairement séparables, la valeur $\rho$ précédente est strictement positive?

\item[c)] Nous supposons que tous les exemples de la base d'entraînement sont contenus dans une hypersphère de rayon $R$ (i.e. $\forall \obs_i\in S, ||\obs_i||\leq R$). De plus, nous initialisons les vecteurs poids (i.e. $\w^{(0)}=0$) ainsi que le pas d'apprentissage $\eta=1$. Montrer que, après $t$ mises à jour, la norme des vecteurs poids courants satisfait~:
\begin{equation}
\label{eq1}
||w^{(t)}||^2\leq t\times R^2
\end{equation} 
\textit{Indication : } Considérer $||\w^{(t)}||^2$ comme $||\w^{(t)}-\w^{(0)}||^2$

\item[d)] En utilisant les mêmes conditions que la question précédente, montrer que, après $t$ mises à jour du vecteur poids, nous avons~:
\begin{equation}
\label{eq2}
\left\langle\frac{\w^*}{||\w^*||},\w^{(t)}\right\rangle\geq t\times \rho
\end{equation} 

\item[e)] Déduire des questions précédentes que le nombre d'itérations est borné par~:
\[
t\leq \left\lfloor \left( \frac{R}{\rho}\right)^2 \right\rfloor
\] 
où $\lfloor z\rfloor$ est la partie entière de $z\in\mathbb{R}$.

\item[f)] Commenter le résultat précédent.
\end{itemize}
\end{itemize}