La descente de gradient
Ne plus essayer à l'aveugle, mais calculer à chaque étape dans quelle direction et de combien modifier les paramètres. Comprendre la dérivée à partir de la pente, calculer les gradients à la main, écrire la boucle de la descente de gradient, puis voir de ses propres yeux ce qui se passe avec un taux d'apprentissage trop petit, trop grand, et des données non standardisées.
- Environ 45 minutes
- Niveau : Débutant
- Testé : 2026-09-14 numpy 2.5, graine aléatoire fixée
Le code et les sorties des programmes sont reproduits tels qu’ils ont tourné : commentaires et sorties sont donc en chinois.
La leçon précédente a trouvé la meilleure droite par recherche sur grille, mais a aussi montré son impasse : dès qu'il y a beaucoup de paramètres, le nombre de combinaisons à essayer devient astronomique.
Imaginez que vous vous tenez les yeux bandés sur le flanc d'une montagne, et que vous voulez rejoindre le point le plus bas de la vallée. Vous ne voyez pas la montagne, mais vos pieds sentent de quel côté le sol penche. Alors vous faites un petit pas vers la descente, vous tâtez de nouveau, vous faites un autre pas. En continuant ainsi, vous finissez au fond de la vallée.
C'est la descente de gradient (gradient descent). La « montagne », c'est la perte ; l'endroit où vous vous tenez, ce sont les paramètres actuels ; « de quel côté ça penche », c'est le gradient.
La dérivée : simplement une pente
Regardons d'abord un seul paramètre w, en fixant b = 0. Si l'on décale w un tout petit peu vers la droite, de combien la perte change-t-elle ? La variation divisée par le décalage, c'est la pente de la perte en ce point. Mesurons-la directement de façon numérique :
def mse(w, b, x=area, y=price):
return np.mean((w * x + b - y) ** 2)
w, b = 1.0, 0.0
for h in [0.1, 0.01, 0.001]:
slope = (mse(w + h, b) - mse(w, b)) / h
print(f" w 往右挪 {h:<6},损失变化 / 挪动距离 = {slope:10.2f}")
== 1. 在 w=1.0, b=0 这一点,损失对 w 的斜率
w 往右挪 0.1 ,损失变化 / 挪动距离 = -7300.21
w 往右挪 0.01 ,损失变化 / 挪动距离 = -8256.23
w 往右挪 0.001 ,损失变化 / 挪动距离 = -8351.83
Plus le décalage est petit, plus la pente mesurée est stable, et elle s'approche peu à peu d'une valeur fixe. Cette « pente pour un décalage infiniment petit » est la dérivée. Elle nous dit deux choses :
- Le signe : ici il est négatif, ce qui signifie que décaler
wvers la droite (l'augmenter) fait baisser la perte. Il faut donc augmenterw. - La grandeur : la valeur absolue est grande, ce qui signifie que la pente est raide ici, et que la perte est très sensible à
w.
Le gradient : une dérivée par paramètre
Nous avons deux paramètres, w et b. On dérive par rapport à chacun séparément (en dérivant par rapport à w, on traite b comme une constante, et inversement), et les deux nombres obtenus forment ensemble le gradient.
La mesure numérique est trop lente et imprécise. Heureusement, la dérivée de l'erreur quadratique moyenne s'écrit directement en formule. La perte est moyenne((w×x + b - y)²), et selon les règles de dérivation :
损失对 w 的导数 = 平均( 2 × (w×x + b - y) × x )
损失对 b 的导数 = 平均( 2 × (w×x + b - y) )
Inutile de retenir cette démonstration ; il suffit de savoir qu'elle « calcule exactement, d'un coup, par l'algèbre, ce qu'on mesurait plus haut ». En code :
def gradients(w, b, x=area, y=price):
error = w * x + b - y
dw = np.mean(2 * error * x) # 损失对 w 的导数
db = np.mean(2 * error) # 损失对 b 的导数
return dw, db
== 2. 公式算出的梯度:dw=-8362.45,db=-79.98
dw = -8362.45, très proche du résultat de la mesure numérique ci-dessus (-8351,83 pour un décalage de 0,001). C'est une bonne habitude : vérifier numériquement une formule de gradient qu'on a établie soi-même permet de trouver beaucoup d'erreurs. Nous referons ainsi à la leçon suivante, en écrivant la rétropropagation.
La boucle de la descente de gradient
Le gradient pointe dans la direction où la perte augmente le plus vite. Pour faire baisser la perte, on fait un petit pas dans la direction opposée au gradient :
w = w - 学习率 × dw
b = b - 学习率 × db
Le taux d'apprentissage (learning rate) règle la taille de chaque pas. En partant de w = 0, b = 0, on répète ce pas :
def descend(lr, steps, x=area, y=price, report=()):
"""从 w=0, b=0 出发走 steps 步。发散时返回 None。"""
w, b = 0.0, 0.0
for step in range(1, steps + 1):
dw, db = gradients(w, b, x, y)
w -= lr * dw
b -= lr * db
if abs(w) > 1e6: # 越走越远,已经发散了
print(f" 第 {step} 步:w 已经变成 {w:.3g},发散了")
return None
if step in report:
print(f" 第 {step:5d} 步:w={w:7.4f} b={b:7.3f} 损失 {mse(w, b, x, y):10.2f}")
return w, b
Voilà toute la logique centrale de l'entraînement. Pour entraîner GPT au module 09, la boucle a exactement la même structure ; seuls les paramètres sont plus nombreux, et le calcul du gradient est remplacé par la rétropropagation de la leçon suivante.
En marche : pas si facile
Avec un taux d'apprentissage de 0,00005, 20 000 pas :
== 3. 学习率 0.00005,走 20000 步
第 1 步:w= 1.4804 b= 0.014 损失 244.38
第 10 步:w= 1.3935 b= 0.014 损失 164.22
第 100 步:w= 1.3934 b= 0.027 损失 164.18
第 1000 步:w= 1.3922 b= 0.155 损失 163.81
第 5000 步:w= 1.3871 b= 0.711 损失 162.27
第 20000 步:w= 1.3695 b= 2.615 损失 157.43
Dès le premier pas, la perte passe de plusieurs milliers à 244 ; après 10 pas, à 164. Puis elle ne bouge presque plus : après 20 000 pas, elle n'est descendue qu'à 157, alors que la recherche sur grille de la leçon précédente avait trouvé une perte minimale de 143. b est encore plus étonnamment lent : en 20 000 pas, il n'est passé que de 0 à 2,6, loin de la meilleure valeur (environ 14,5).
Pourquoi ? Les deux expériences suivantes vont le révéler.
Le taux d'apprentissage : trop petit c'est lent, trop grand ça explose
Quelques autres taux d'apprentissage, 1000 pas chacun :
== 4. 不同的学习率(都走 1000 步)
学习率 1e-05 :w=1.3932 b=0.041 损失 164.14
学习率 5e-05 :w=1.3922 b=0.155 损失 163.81
学习率 9e-05 :w=1.3912 b=0.268 损失 163.50
第 115 步:w 已经变成 1.03e+06,发散了
学习率 0.0001 :发散
Plus le taux d'apprentissage est grand, plus on avance vite et plus b va loin. Mais en passant de 0,00009 à 0,0001, un tout petit écart, tout explose : au pas 115, w dépasse le million.
La divergence se produit ainsi : dans la direction de w, la pente est trop raide (nous l'avons mesurée à -8362) ; avec un pas un peu trop grand, on franchit d'un coup le fond de la vallée et on atterrit plus haut de l'autre côté ; là, la pente est encore plus raide, et le pas suivant va encore plus loin… Chaque pas éloigne davantage du fond que le précédent, les valeurs grandissent sans cesse, jusqu'au dépassement de capacité numérique.
La racine du problème : la pente est trop raide dans la direction de w, trop douce dans celle de b. dw vaut -8362, db seulement -80, un facteur cent. Le taux d'apprentissage doit être assez petit pour que w ne diverge pas, et b ne peut alors avancer que très lentement. Un seul taux d'apprentissage ne peut pas satisfaire les deux directions à la fois.
La standardisation : une pente à peu près égale dans chaque direction
Pourquoi la pente est-elle si raide dans la direction de w ? Parce que les valeurs de surface sont grandes, de quelques dizaines à plus de cent mètres carrés. Dans la formule du gradient, dw = moyenne(2 × erreur × x) : plus x est grand, plus dw l'est.
La solution : convertir la surface en nombres de « moyenne 0 et d'écart type 1 ». C'est la standardisation :
mean, std = area.mean(), area.std()
area_n = (area - mean) / std
Après standardisation, les surfaces sont toutes entre -2 et 2 environ, et les pentes dans les directions de w et b sont à peu près aussi raides. On peut alors utiliser sans crainte un taux d'apprentissage de 0,1, pour seulement 100 pas :
== 5. 面积标准化之后(均值 98.0,标准差 32.1),学习率 0.1 只走 100 步
第 1 步:w= 8.0605 b= 27.588 损失 13360.27
第 10 步:w=35.9749 b=123.129 损失 381.15
第 50 步:w=40.3018 b=137.939 损失 143.05
第 100 步:w=40.3023 b=137.941 损失 143.05
换算回原单位:w=1.2571 b=14.806
En 50 pas, le point le plus bas est atteint, perte 143,05, un peu plus basse encore que les 143,1 de la recherche sur grille de la leçon précédente (la recherche sur grille n'essayait que tous les 0,01, et le meilleur point peut tomber entre deux cases). Reconverti dans les unités d'origine : w = 1.2571, b = 14.806.
Ce que 20 000 pas ne suffisaient pas à faire, 50 pas l'accomplissent après standardisation. C'est un enseignement très pratique pour l'entraînement des réseaux de neurones : les plages de valeurs des entrées doivent être comparables. Les diverses « normalisations » que vous rencontrerez plus tard (LayerNorm, BatchNorm) partent de la même idée.
Récapitulatif de la descente de gradient
- Les dérivées de la perte par rapport à chaque paramètre forment ensemble le gradient, qui pointe dans la direction où la perte augmente le plus vite.
- À chaque pas, on avance un peu dans la direction opposée au gradient, la longueur du pas étant fixée par le taux d'apprentissage.
- Un taux d'apprentissage trop petit avance lentement ; trop grand, il diverge. C'est le nombre qu'on règle le plus lors d'un entraînement.
- Quand les plages de valeurs des entrées diffèrent beaucoup, l'entraînement est difficile à régler : standardisez d'abord.
Notre droite n'a que deux paramètres, et la formule du gradient se démontre à la main. Mais un réseau de neurones a des centaines ou des milliers de paramètres, couche après couche ; démontrer à la main la dérivée de chacun est impossible. La leçon suivante montre comment faire calculer automatiquement par l'ordinateur les gradients de tous les paramètres : la rétropropagation.
Exercices
- Sur les données standardisées, passez le taux d'apprentissage à 0,5, 1,0 et 1,1, 100 pas chacun, et regardez les résultats. Quel est à peu près le taux d'apprentissage critique ?
- Sans standardisation, avec seulement un taux de 0,00009, combien de pas faut-il pour que la perte descende sous 144 ? Estimez, puis vérifiez en exécutant.
- Pour la dérivation numérique, un
hplus petit est-il toujours meilleur ? Passezhà1e-10et1e-15et regardez la pente mesurée. Le résultat empire-t-il au contraire ? Réfléchissez à pourquoi (indice : la précision des nombres décimaux dans un ordinateur est limitée).
Auto-test
1. Pourquoi la descente de gradient va-t-elle dans la direction « opposée » au gradient ?
Le gradient pointe dans la direction où la perte augmente le plus vite. Notre but est de faire baisser la perte, il faut donc aller dans la direction opposée.
2. Le taux d'apprentissage est passé seulement de 0,00009 à 0,0001, et l'entraînement a divergé. Que s'est-il passé ?
Dans la direction de w, la pente de la perte est très raide. Avec un taux un peu trop grand, un seul pas franchit le point le plus bas et atterrit plus haut de l'autre côté, où la pente est encore plus raide, et le pas suivant va encore plus loin. Chaque pas s'éloigne davantage du point le plus bas que le précédent, et les valeurs grandissent jusqu'au dépassement de capacité.
3. Pourquoi l'entraînement est-il devenu des centaines de fois plus rapide après la standardisation de la surface ?
Sans standardisation, les surfaces ont de grandes valeurs, et le gradient dans la direction de w est cent fois plus grand que dans celle de b. Le taux d'apprentissage doit s'adapter à la direction raide de w et rester très petit, si bien que b avance très lentement. Après standardisation, les deux pentes sont à peu près aussi raides, on peut utiliser un taux bien plus grand, et les deux paramètres atteignent vite le point le plus bas.
Questions et discussion
Bloqué sur cette leçon ? Posez votre question ici. Et si vous pouvez répondre à quelqu'un, n'hésitez pas.
Une question rapporte 3 points, une réponse 6. Les messages paraissent après vérification.
Chargement de la discussion…