Aller au contenu principal

Les réseaux de neurones : couches et non-linéarité

Ce que ce chapitre apporte 6 points
  • Reconnaître qu'un neurone est exactement le modèle linéaire du chapitre 8.
  • Montrer qu'empiler des couches sans non-linéarité ne produit rien de nouveau.
  • Écrire la passe avant et la passe arrière d'un réseau à une couche cachée, et vérifier le gradient rétropropagé par différence finie.
  • Dire ce que garantit le théorème d'approximation universelle, et ce qu'il ne garantit pas.
  • Choisir un nombre de cellules cachées et reconnaître un échec d'initialisation.
  • Nommer les difficultés propres aux réseaux profonds.
Sur le plateau de Vérelles, où la coopérative collecte le blé de ses adhérents, la rouille frappe deux sortes de parcelles qui ne se ressemblent pas : celles des fonds de vallée humides semées tard, et celles du plateau sec semées tôt. Le modèle de la coopérative, une seule combinaison de ses attributs, ne parvient pas à les réunir. Le chapitre 8 s'est arrêté sur cette impossibilité : aucune droite ne sépare deux classes disposées en damier, et sept erreurs sur vingt-huit sont le mieux qu'elle puisse faire. Un réseau de neurones empile des couches, et sans fonction non linéaire entre elles, l'empilement ne vaut pas mieux qu'une seule. La réponse tient en une couche de calcul supplémentaire, et tout ce qui a été construit depuis le chapitre 5 y sert d'un coup : une erreur à minimiser, un gradient, une descente. La rétropropagation, dont le nom impressionne, n'est que la règle de dérivation des fonctions composées appliquée avec méthode.

Un neurone

Ce qu'est un neurone

Un neurone calcule une somme pondérée de ses entrées, ajoute un biais, puis applique une fonction non linéaire appelée activation :

a=f(w⋅x+b)a = f(w \cdot x + b)

Avec la fonction logistique pour activation, c'est exactement la régression logistique du chapitre 8. Rien de plus, et le vocabulaire ne doit pas faire croire le contraire.

Un neurone est une droite, et le restera. La partie w⋅x+bw \cdot x + b est une combinaison linéaire, donc une droite en deux dimensions, un plan en trois, un hyperplan au-delà. L'activation ne fait qu'écraser le résultat entre deux bornes : elle change la valeur rendue, jamais la forme de la frontière.
La figure ci-dessous le vérifie. Un réseau réduit à une seule cellule cachée, entraîné aussi longtemps qu'on veut sur le damier, se stabilise à sept erreurs sur vingt-huit, c'est-à-dire au plancher que le chapitre 8 avait établi pour une droite.
Ce n'est donc pas la non-linéarité seule qui débloque le problème : c'est le fait d'en avoir plusieurs, et de les combiner.

02460246premier attributsecond attribut
3000 pas7 / 28 erreursperte 0,4788

7 erreurs sur 28. La frontière se déforme encore : chaque cellule cachée tire dans sa direction, et la sortie combine leurs avis.

Une seule cellule cachée, entraînée trois mille pas. La frontière est et reste une droite, et le compte s'arrête à sept erreurs sur vingt-huit : exactement le plancher démontré au chapitre 8. Une cellule, une direction.
Vérification rapideon peut se reprendre

Un neurone à activation logistique, c'est…

Empiler ne suffit pas

main.py
Sortie
>_ Prêt à exécuter…
La non-linéarité n'est pas un raffinement, c'est la condition
Sans activation, la couche cachée applique z↦W1z+b1z \mapsto W_1 z + b_1 et la sortie a↦W2a+b2a \mapsto W_2 a + b_2. Leur composition vaut z↦(W2W1)z+(W2b1+b2)z \mapsto (W_2 W_1) z + (W_2 b_1 + b_2), c'est-à-dire une seule application linéaire.
Le bloc ne se contente pas de l'affirmer : il calcule W2W1W_2 W_1, obtient une droite, et vérifie qu'elle commet exactement les mêmes erreurs que le réseau à huit cellules.
Quel que soit le nombre de couches empilées, tant qu'aucune n'est non linéaire, le tout se replie sur une droite. Cent couches sans activation valent une régression linéaire, en plus lent.
C'est la raison pour laquelle l'activation est entre les couches et non seulement à la fin : c'est elle qui empêche l'effondrement.
Vérification rapideon peut se reprendre

Empiler dix couches sans aucune activation donne…

Plusieurs cellules, et la frontière se courbe

02460246premier attributsecond attribut
3000 pas0 / 28 erreursperte 0,0009

Aucune erreur. Une couche cachée de 4 cellules a produit une frontière qu'aucune droite ne pouvait tracer.

Quatre cellules cachées sur les mêmes points. Avancer depuis le départ montre le trajet complet : la frontière commence droite, parce qu'un réseau aux poids tirés au hasard n'est presque rien, puis se courbe, puis se referme sur les quatre coins. Ce qu'aucune droite ne pouvait faire est atteint en trois mille pas.

Comment quatre droites font une frontière courbe. Chaque cellule cachée calcule sa propre combinaison w⋅x+bw \cdot x + b et l'écrase entre −1-1 et 11. Chacune est donc une question binaire floue : « ce point est-il d'un côté ou de l'autre de ma droite, et à quel point ».
La couche de sortie ne voit plus les attributs d'origine : elle voit les réponses des quatre cellules. Dans cet espace-là, les classes sont devenues séparables par un simple hyperplan, ce qu'elles n'étaient pas dans l'espace de départ.
C'est la seconde issue annoncée au chapitre 8 : plutôt que de changer d'espace à la main en ajoutant l'attribut x×yx \times y, on laisse le réseau construire lui-même l'espace où le problème devient facile. C'est là toute la différence, et c'est ce qui a rendu ces méthodes irremplaçables.

La rétropropagation

Passe avant, passe arrière

Avant : a=tanh⁡(W1z+b1)a = \tanh(W_1 z + b_1) puis p=σ(W2⋅a+b2)p = \sigma(W_2 \cdot a + b_2).

Arrière : partir de l'écart à la sortie, δ2=p−y\delta_2 = p - y, et le ramener derrière la couche cachée par la règle de dérivation des fonctions composées :

δ1=(δ2 W2)⊙(1−a2)\delta_1 = (\delta_2 \, W_2) \odot (1 - a^2)

Les gradients s'en déduisent : ∇W2=δ2 a\nabla_{W_2} = \delta_2\, a, ∇W1=δ1z⊤\nabla_{W_1} = \delta_1 z^{\top}.

Le terme 1−a21 - a^2 est la dérivée de tanh⁡\tanh, exprimée à partir de sa propre valeur.

main.py
Sortie
>_ Prêt à exécuter…
Pourquoi ce nom, et pourquoi il intimide à tort
« Rétropropagation » désigne un simple ordre de calcul. Pour obtenir la dérivée de la perte par rapport à un poids de la première couche, il faut multiplier les dérivées locales de tout ce qui vient après. Les calculer de la sortie vers l'entrée permet de réutiliser à chaque étage ce qui a été calculé à l'étage précédent.
La différence de coût est décisive : par différence finie, obtenir le gradient d'un modèle à mm paramètres demande 2m2m passes avant. Par rétropropagation, une passe avant et une passe arrière suffisent, quel que soit mm.
Sur un modèle à un milliard de paramètres, le premier est impensable et le second est une routine. C'est cette seule différence qui rend l'apprentissage profond possible, et c'est pourquoi la découverte de 1986 a compté.
Vérification rapideon peut se reprendre

1.Qu'est-ce que la rétropropagation ?

2.Comment vérifier qu'un gradient rétropropagé est juste ?

Combien de cellules, et l'initialisation

main.py
Sortie
>_ Prêt à exécuter…
02460246premier attributsecond attribut
3000 pas12 / 28 erreursperte 0,3472

12 erreurs sur 28. La frontière se déforme encore : chaque cellule cachée tire dans sa direction, et la sortie combine leurs avis.

Deux cellules cachées, le minimum théorique pour ce problème, avec une initialisation malheureuse. La descente s'installe dans un creux dont elle ne sortira pas : douze erreurs sur vingt-huit après trois mille pas, et la frontière ne se referme jamais. Le même réseau à deux cellules y arrive sans peine avec d'autres départs. C'est le minimum local du chapitre 6, sous une nouvelle forme.
À manipuler
Dans la figure à quatre cellules, faire avancer le curseur d'apprentissage depuis le départ et noter le nombre d'erreurs affiché : la frontière commence droite, se courbe, puis se referme sur les quatre coins. Faire de même dans la figure à deux cellules ci-dessus : le compte se fige à douze erreurs sur vingt-huit, et la frontière ne se referme jamais. Constater que le même problème, résolu par quatre cellules, peut rester bloqué avec deux selon le départ.
Trois raisons de ne pas viser le minimum de cellules
La fiabilité. Deux cellules suffisent en théorie et échouent une fois sur trois en pratique, faute d'une bonne initialisation. Trois y arrivent à tous les coups.
Le paysage. Ajouter des cellules ne rend pas la surface d'erreur plus lisse par magie, mais multiplie les chemins qui descendent. Un modèle un peu large trouve plus facilement une issue qu'un modèle exactement dimensionné.
La régularisation existe. Le chapitre 7 l'a montré : ce n'est pas le nombre de paramètres qui nuit à la généralisation, c'est leur liberté. Un réseau plus large et pénalisé se comporte mieux qu'un réseau étroit et laissé libre.
Le réflexe qui consiste à réduire la taille du modèle quand il sur-apprend n'est donc pas le premier à avoir. Pénaliser, ou collecter davantage, viennent avant.

Ce qu'une seule couche cachée peut faire

main.py
Sortie
>_ Prêt à exécuter…
Théorème d'approximation universelle

Une seule couche cachée, avec assez de cellules et une activation non polynomiale, approche n'importe quelle fonction continue sur un domaine borné, avec la précision que l'on veut.

Ce que ce théorème ne dit pas, et c'est l'essentiel
Il est souvent cité comme si toute la question était réglée. Il laisse pourtant ouvert tout ce qui compte.
Il ne dit pas combien de cellules. « Assez » peut vouloir dire un nombre astronomique, croissant exponentiellement avec la dimension d'entrée.
Il ne dit pas qu'on trouvera ces poids. Il affirme qu'ils existent. Rien ne garantit qu'une descente de gradient les atteigne, et la figure aux deux cellules montre qu'elle échoue déjà sur un damier.
Il ne dit rien de la généralisation. Approcher parfaitement la fonction sur les points connus est exactement ce que le chapitre 7 appelle apprendre le bruit.
Il ne justifie pas la profondeur. Il porte sur une seule couche cachée. Si la profondeur s'est imposée, c'est parce que certaines fonctions demandent exponentiellement moins de cellules quand on empile les couches, et parce que les couches successives apprennent des représentations réutilisables. Ce n'est pas une question de pouvoir d'expression, c'est une question d'économie.
Vérification rapideon peut se reprendre

1.Le théorème d'approximation universelle garantit…

2.Pourquoi ReLU plutôt que la sigmoïde dans les couches cachées profondes ?

Ce qui va mal en profondeur

Quatre difficultés, et leurs remèdes.

Les gradients qui s'évanouissent. La rétropropagation multiplie les dérivées locales couche après couche. Avec une sigmoïde, dont la dérivée ne dépasse jamais 0,25, dix couches multiplient par au plus 0,25100{,}25^{10}, soit un millionième : les premières couches n'apprennent plus rien. Le remède principal a été de remplacer la sigmoïde par ReLU, max⁡(0,z)\max(0, z), dont la dérivée vaut 1 sur toute la partie active.
La saturation. Un neurone dont l'entrée est très grande en valeur absolue a une dérivée quasi nulle et cesse d'apprendre. C'est la même raison qui, au chapitre 8, disqualifiait la perte carrée sur une sigmoïde.
L'initialisation. Des poids trop grands saturent d'emblée, des poids trop petits laissent le signal s'éteindre. Les recettes usuelles règlent l'écart-type initial en fonction du nombre d'entrées de chaque couche.
Le déséquilibre entre couches. La normalisation par lots et les connexions résiduelles, qui laissent le signal court-circuiter une couche, sont les deux réponses qui ont rendu les réseaux très profonds entraînables.

Ce que ferait une bibliothèque
import torch, torch.nn as nn

modele = nn.Sequential(nn.Linear(2, 4), nn.Tanh(), nn.Linear(4, 1))
perte, opt = nn.BCEWithLogitsLoss(), torch.optim.Adam(modele.parameters(), lr=0.05)

for _ in range(3000):
    opt.zero_grad()
    e = perte(modele(Z).squeeze(), y)
    e.backward()          # la retropropagation, ecrite a la main plus haut
    opt.step()

e.backward() fait exactement ce que le bloc de vérification a écrit en dix lignes, à ceci près qu'il le déduit tout seul de la suite des opérations. BCEWithLogitsLoss combine sigmoïde et perte logarithmique en un seul calcul, plus stable numériquement que les deux séparés. Et Adam est l'optimiseur décrit au chapitre 6.

Mettre en pratique

Un réseau se compte en paramètres, et ce compte dit à la fois ce qu'il peut apprendre et ce qu'il risque de sur-apprendre.

Compter les paramètres d'un réseau

  • 1.

    Une couche reçoit 4 entrées et produit 5 sorties. Combien de poids comporte-t-elle ?

  • 2.

    Combien de biais comporte-t-elle ?

  • 3.

    Un réseau enchaîne une couche de 4 vers 5, puis une couche de 5 vers 3. Combien de paramètres compte-t-il au total ?

  • 4.

    Ces deux couches sont empilées SANS fonction d'activation entre elles. À combien de couches ce réseau équivaut-il ?

Ce que la non-linéarité achète. Sans elle, empiler dix couches ne produit rien de plus qu'une seule : la composée reste linéaire, donc la frontière reste une droite. Les quarante-trois paramètres du réseau ci-dessus n'auraient alors pas plus de pouvoir que les quinze d'une couche unique de 4 vers 3.
La fonction d'activation n'est donc pas un réglage de confort. C'est la seule chose qui distingue un réseau profond d'un modèle linéaire coûteux.

Le réseau à deux cellules de la coopérative reconnaît-il les deux sortes de parcelles que la rouille frappe ?

Chaque parcelle est décrite par deux attributs codés 0 ou 1 : uu vaut 1 si elle est en fond de vallée humide, ss vaut 1 si elle a été semée tard. Le réseau calcule deux cellules cachées avec l'activation ReLU, puis un score de sortie, passé dans la sigmoïde pour donner la probabilité d'être touchée :

h1=max⁡(0, u+s−1)h2=max⁡(0, 1−u−s)z=4 (h1+h2)−2h_1 = \max(0,\ u + s - 1) \qquad h_2 = \max(0,\ 1 - u - s) \qquad z = 4\,(h_1 + h_2) - 2

Calculer la probabilité pour les quatre sortes de parcelles : (u,s)(u, s) = (1, 1), (0, 0), (1, 0) et (0, 1).

Par où commencer ? Calculer les deux cellules cachées pour chaque parcelle avant le score de sortie : chacune répond à une seule question.

Vérification rapideon peut se reprendre

Pourquoi deux cellules cachées, et non une seule ?

Le corrigé
  1. Calculer la première cellule. h1=max⁡(0,u+s−1)h_1 = \max(0, u + s - 1) vaut 1 pour (1, 1) et 0 pour les trois autres : elle ne s'allume que pour une parcelle humide semée tard.
  2. Calculer la seconde cellule. h2=max⁡(0,1−u−s)h_2 = \max(0, 1 - u - s) vaut 1 pour (0, 0) et 0 pour les trois autres : elle ne s'allume que pour une parcelle sèche semée tôt.
  3. Calculer le score de sortie. z=4×1−2=2z = 4 \times 1 - 2 = 2 pour (1, 1) et (0, 0), z=−2z = -2 pour (1, 0) et (0, 1).
  4. Passer à la probabilité. 1/(1+e−2)≈0,881/(1 + e^{-2}) \approx 0{,}88 pour les deux sortes de parcelles touchées, 1/(1+e2)≈0,121/(1 + e^{2}) \approx 0{,}12 pour les deux autres.
  5. Vérifier ce qu'une couche ajoute. Les quatre parcelles forment un damier : aucune droite, donc aucun neurone seul, ne met (1, 1) et (0, 0) d'un même côté. Ici chaque cellule isole un coin, et la sortie, qui ne voit que h1h_1 et h2h_2, les sépare par un simple seuil sur leur somme.
Deux cellules cachées suffisent en théorie pour le damier. Faut-il s'en tenir là ?

Par où commencer ? Relire ce que la troisième figure du chapitre a montré du réseau à deux cellules, selon son départ.

Le corrigé
  1. Mesurer la fiabilité. Le chapitre le mesure : avec deux cellules, une initialisation sur trois échoue et reste bloquée, à douze erreurs sur vingt-huit. Avec trois, les trois initialisations réussissent. Le minimum théorique est fragile.
  2. Penser au paysage d'erreur. Des cellules supplémentaires multiplient les chemins qui descendent, et rendent les creux sans issue plus rares.
  3. Se rappeler que la régularisation existe. Le chapitre 7 a montré que ce n'est pas le nombre de paramètres qui nuit à la généralisation, mais leur liberté.
  4. Conclure, et vérifier l'ordre des gestes. Garder de la marge. Rétrécir le modèle dès qu'il sur-apprend n'est pas le bon premier geste : pénaliser, ou collecter plus de données, viennent avant.
Un réseau à deux cellules repère les lampadaires défaillants d'une ville. Lesquels signale-t-il ?

Chaque lampadaire est décrit par deux attributs codés 0 ou 1 : aa vaut 1 s'il fait nuit selon le capteur de lumière, bb vaut 1 si la lampe est allumée. Un lampadaire est suspect quand les deux sont en désaccord : éteint la nuit, ou allumé le jour. Le réseau calcule :

h1=max⁡(0, a−b)h2=max⁡(0, b−a)z=4 (h1+h2)−2h_1 = \max(0,\ a - b) \qquad h_2 = \max(0,\ b - a) \qquad z = 4\,(h_1 + h_2) - 2

Calculer la probabilité de défaillance pour (a,b)(a, b) = (1, 0), (0, 1), (1, 1) et (0, 0).

Par où commencer ? Calculer les deux cellules cachées pour chaque lampadaire avant le score de sortie.

Le corrigé
  1. Calculer la première cellule. h1=max⁡(0,a−b)h_1 = \max(0, a - b) vaut 1 pour (1, 0) seulement : la nuit, lampe éteinte.
  2. Calculer la seconde cellule. h2=max⁡(0,b−a)h_2 = \max(0, b - a) vaut 1 pour (0, 1) seulement : le jour, lampe allumée.
  3. Calculer le score de sortie. z=2z = 2 pour (1, 0) et (0, 1), z=−2z = -2 pour (1, 1) et (0, 0).
  4. Passer à la probabilité. Environ 0,88 pour les deux lampadaires en désaccord, qui sont signalés, et 0,12 pour les deux autres.
  5. Vérifier en comparant au cas précédent. Les coins réunis ne sont plus les mêmes : ici (1, 0) et (0, 1), là (1, 1) et (0, 0). Mais c'est le même damier, et la même architecture le résout : une cellule par coin à isoler, une sortie qui les additionne. Seuls les poids des cellules ont changé.

Chapitre révisé en novembre 2026 · Une erreur dans ce chapitre ?

Dans la bibliothèque d'exercices