Skip to content

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.

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 = 100
charge_cpu = np.random.uniform(10, 95, n_samples)
bruit = np.random.normal(0, 15, n_samples)
consommation = 8 * charge_cpu + 120 + bruit
X_simple = make_design_matrix(charge_cpu) # SANS standardisation
y = 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.99598663827
cout iteration 1: 308147.3603230701
cout iteration 4: 877598.336344736
cout iteration 50: 8603580719717.093
cout final (iteration 1999): inf
theta 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é.

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.60621997638
cout final: 90.74076344629351
theta 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.

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 ».

👉 Du linéaire au polynomial et au multivarié


Junior TSAFACK – 12/09/2026