La méthode qui permet à un réseau de neurones d'apprendre. Après chaque prédiction, l'erreur est renvoyée de la sortie vers l'entrée, couche par couche, pour calculer la part de responsabilité de chaque poids. Un optimiseur corrige ensuite les poids. Tous les réseaux actuels, des scores clients aux LLM, apprennent ainsi.
Une chaîne de production sort une pièce défectueuse. On remonte la chaîne poste par poste en demandant à chacun : de combien ton réglage a-t-il contribué au défaut ? Puis chacun ajuste un peu son réglage.
Les données traversent le réseau de l'entrée à la sortie. Le réseau donne une probabilité de départ pour chaque client.
On compare la prédiction au réel avec une fonction de perte, ici l'entropie croisée : elle est forte quand le réseau est sûr de lui et se trompe.
L'erreur est renvoyée de la sortie vers l'entrée. À chaque couche, la règle de dérivation en chaîne donne la contribution de chaque poids à l'erreur : c'est le gradient.
Chaque poids bouge un peu dans le sens qui réduit l'erreur (descente de gradient). On recommence sur des milliers de passes jusqu'à ce que la perte ne baisse plus.
Ancienneté, appels au support, montant mensuel, type de contrat, incidents récents, et le départ observé. Un réseau minuscule, 8 neurones cachés, codé à la main pour voir chaque étape.
Sur le jeu d'exemple, la perte passe de 0,80 au départ à 0,45 après 500 passes, puis ne bouge presque plus. Le réseau obtient une AUC de 0,79 sur les clients jamais vus, au niveau d'une régression logistique.
C'est le tableau de bord de l'apprentissage. Si elle ne baisse pas, le pas est mal réglé ou le gradient est faux. Si la perte de validation remonte pendant que celle d'entraînement baisse, le réseau récite : il faut l'arrêter.
La rétropropagation elle-même n'a pas de réglage. Ce qui compte, ce sont les choix qui l'entourent.
La taille de la correction à chaque passe (0,5 ici). Trop grand, la perte oscille ou explose ; trop petit, l'apprentissage traîne.
Des poids tirés au hasard, ni trop grands ni trop petits. Tous à zéro, les neurones restent identiques et n'apprennent rien de différent. Les frameworks utilisent des tirages calibrés (Glorot, He).
tanh ou sigmoïde s'écrasent aux extrêmes et le gradient s'éteint dans les réseaux profonds. ReLU limite ce problème, d'où son usage par défaut.
# Churn clients : rétropropagation codée à la main en R
clients <- read.csv("clients_churn.csv")
X <- model.matrix(~ anciennete + appels_support + montant + contrat + incidents_3m, data = clients)[, -1]
y <- clients$churn
set.seed(42)
idx <- sample(nrow(X), round(0.7 * nrow(X)))
X_train <- scale(X[idx, ])
X_test <- scale(X[-idx, ], center = attr(X_train, "scaled:center"), scale = attr(X_train, "scaled:scale"))
y_train <- y[idx]
# Poids tirés au hasard (termes constants omis pour la lisibilité)
W1 <- matrix(rnorm(ncol(X) * 8, 0, 0.5), ncol(X), 8)
W2 <- matrix(rnorm(8, 0, 0.5), 8, 1)
sigmoide <- function(z) 1 / (1 + exp(-z))
for (epoque in 0:1500) {
h <- tanh(X_train %*% W1) # passe avant : couche cachée de 8 neurones
p <- sigmoide(h %*% W2) # puis probabilité de départ
d2 <- (p - y_train) / length(y_train) # passe arrière : erreur en sortie
d1 <- (d2 %*% t(W2)) * (1 - h^2) # erreur renvoyée à la couche cachée
W2 <- W2 - 0.5 * t(h) %*% d2 # chaque poids corrigé selon sa part d'erreur
W1 <- W1 - 0.5 * t(X_train) %*% d1
if (epoque %% 500 == 0) cat("époque", epoque, ": perte =", round(-mean(y_train * log(p) + (1 - y_train) * log(1 - p)), 3), "\n")
}
proba <- as.vector(sigmoide(tanh(X_test %*% W1) %*% W2))
y_test <- y[-idx]
cat("Probabilité moyenne, partants :", round(mean(proba[y_test == 1]), 2), "| restés :", round(mean(proba[y_test == 0]), 2), "\n")
# Churn clients : rétropropagation codée à la main en Python
import numpy as np
import pandas as pd
from sklearn.metrics import roc_auc_score
from sklearn.model_selection import train_test_split
clients = pd.read_csv("clients_churn.csv")
X = pd.get_dummies(clients[["anciennete", "appels_support", "montant", "contrat", "incidents_3m"]], dtype=float).values
y = clients[["churn"]].values
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42)
moy, ecart = X_train.mean(axis=0), X_train.std(axis=0)
X_train, X_test = (X_train - moy) / ecart, (X_test - moy) / ecart
rng = np.random.default_rng(42)
W1, W2 = rng.normal(0, 0.5, (X.shape[1], 8)), rng.normal(0, 0.5, (8, 1)) # sans termes constants, pour la lisibilité
sigmoide = lambda z: 1 / (1 + np.exp(-z))
for epoque in range(1501):
h = np.tanh(X_train @ W1) # passe avant : couche cachée de 8 neurones
p = sigmoide(h @ W2) # puis probabilité de départ
d2 = (p - y_train) / len(y_train) # passe arrière : erreur en sortie
d1 = (d2 @ W2.T) * (1 - h ** 2) # erreur renvoyée à la couche cachée
W2, W1 = W2 - 0.5 * h.T @ d2, W1 - 0.5 * X_train.T @ d1 # chaque poids corrigé selon sa part d'erreur
if epoque % 500 == 0:
perte = -np.mean(y_train * np.log(p) + (1 - y_train) * np.log(1 - p))
print(f"époque {epoque:4d} : perte = {perte:.3f}")
proba = sigmoide(np.tanh(X_test @ W1) @ W2)
print("AUC test :", round(roc_auc_score(y_test.ravel(), proba.ravel()), 3))
La rétropropagation calcule le gradient : de combien l'erreur change quand on bouge chaque poids. La descente de gradient utilise ce gradient pour corriger les poids. La première est un calcul, la seconde une méthode d'optimisation, et on les emploie toujours ensemble.
Parce qu'un réseau est une suite de fonctions emboîtées. La dérivée de l'erreur par rapport à un poids de la première couche est le produit des dérivées de toutes les couches qui suivent. La rétropropagation calcule ce produit de la sortie vers l'entrée, en réutilisant les résultats déjà calculés.
Dans un réseau profond, le gradient est un produit de nombreux termes. S'ils sont souvent inférieurs à 1, comme avec la sigmoïde aux extrêmes, le produit devient minuscule et les premières couches n'apprennent plus. ReLU, la batch normalization et les raccourcis des ResNet ont été introduits en grande partie pour cela.
La rétropropagation calcule la pente, la descente de gradient s'en sert pour corriger les poids.
Voir la fiche → ce qu'elle entraîneLe réseau le plus simple. scikit-learn ou nnet font la rétropropagation à votre place.
Voir la fiche → l'optimiseur par défautUtilise les gradients fournis par la rétropropagation, avec un pas adapté à chaque poids.
Voir la fiche →Dataistudio forme les équipes au machine learning et à l'IA, sur des cas concrets.
Nous utilisons des cookies de mesure d'audience et de suivi publicitaire pour comprendre la fréquentation du site et l'efficacité de nos annonces. Rien n'est déposé sans votre accord. En savoir plus