Diagnostiquer l'entraînement : le piège du taux d'apprentissage
Cette leçon documente un échec réellement rencontré en préparant ce cours — pas un exemple fabriqué pour l’occasion. Il illustre une erreur si fréquente qu’elle mérite d’être vue une fois en vrai.
Les données
Section titled “Les données”Une relation linéaire simple entre la charge CPU (10 à 95 %) et la consommation électrique (en kWh), avec du bruit :
np.random.seed(42)n_samples = 100charge_cpu = np.random.uniform(10, 95, n_samples)bruit = np.random.normal(0, 15, n_samples)consommation = 8 * charge_cpu + 120 + bruitPremière tentative — ça explose
Section titled “Première tentative — ça explose”X_simple = make_design_matrix(charge_cpu) # SANS standardisationy = consommation.reshape(-1, 1)theta_init = np.random.randn(2, 1)
theta_final, cost_history = gradient_descent( X_simple, y, theta_init, learning_rate=0.0007, n_iterations=2000)print("cout iteration 0:", cost_history[0])print("cout iteration 1:", cost_history[1])print("cout iteration 4:", cost_history[4])print("cout iteration 50:", cost_history[50])print("cout final (iteration 1999):", cost_history[-1])print("theta final:", theta_final.ravel())cout iteration 0: 217621.99598663827cout iteration 1: 308147.3603230701cout iteration 4: 877598.336344736cout iteration 50: 8603580719717.093cout final (iteration 1999): inftheta final: [-9.94894191e+152 -1.58851509e+151]Le coût augmente à chaque itération au lieu de diminuer, jusqu’à déborder la capacité numérique des flottants (inf). Les paramètres finaux (-9.9 × 10¹⁵²) n’ont plus aucun sens : le modèle a divergé.
Pourquoi ça diverge
Section titled “Pourquoi ça diverge”charge_cpu varie entre 10 et 95 — une échelle non négligeable. Le gradient de theta[0] (la pente) est proportionnel à charge_cpu, donc à chaque mise à jour, un learning_rate pourtant modeste (0.0007) se retrouve multiplié par des valeurs de l’ordre de la centaine : le pas devient trop grand, on dépasse le minimum de la fonction de coût, puis on s’en éloigne de plus en plus à chaque itération — un peu comme une bille qui, au lieu de rouler au fond d’une vallée, prend de plus en plus d’élan sur ses flancs jusqu’à s’envoler.
La correction : standardiser avant d’entraîner
Section titled “La correction : standardiser avant d’entraîner”def standardize(x): return (x - x.mean()) / x.std()
charge_cpu_std = standardize(charge_cpu)X_simple = make_design_matrix(charge_cpu_std)theta_init = np.random.randn(2, 1)
theta_final, cost_history = gradient_descent( X_simple, y, theta_init, learning_rate=0.05, n_iterations=2000)print("cout initial:", cost_history[0])print("cout final:", cost_history[-1])print("theta final (pente, biais):", theta_final.ravel())cout initial: 139200.60621997638cout final: 90.74076344629351theta appris (pente, biais): [199.23741321 519.70670009]Une fois charge_cpu centrée-réduite (moyenne 0, écart-type 1), un learning_rate bien plus élevé (0.05 contre 0.0007) devient non seulement stable, mais converge en 2000 itérations vers un coût proche de zéro.
La leçon à retenir
Section titled “La leçon à retenir”Standardiser les features n’est pas une optimisation cosmétique : sans elle, la plage de valeurs d’une feature dicte le comportement numérique de l’entraînement entier, au point de le faire diverger silencieusement.
Ce réflexe (standardize avant gradient_descent) sera systématique pour le reste de ce module. Le module 6 (Deep Learning) reviendra sur ce même phénomène sous un angle visuel, avec le « paysage de perte ».
Prochaine étape
Section titled “Prochaine étape”👉 Du linéaire au polynomial et au multivarié
Junior TSAFACK – 12/09/2026