← Retour au portfolio RSS

· 10 min de lecture

M4 · Dérivées, dérivées partielles et gradient

De la pente d'une courbe à la direction de plus forte montée d'une fonction à plusieurs variables, et au gradient d'une fonction de perte.

Mastering AI · Required Maths · Semaine 2 (calcul différentiel) · Partie 4

Objectif de l’étape

Entraîner un modèle, c’est chercher les paramètres qui rendent la perte minimale. Pour savoir dans quelle direction bouger les paramètres, on a besoin d’une seule chose : le gradient. Cette semaine de calcul différentiel commence par lui.

À la fin de cet article, tu sauras :

  • interpréter une dérivée comme une pente locale et la calculer numériquement ;
  • calculer des dérivées partielles et assembler un gradient ;
  • expliquer pourquoi le gradient indique la direction de plus forte montée ;
  • dériver à la main le gradient de la MSE et de la log-loss, et le vérifier numériquement.

Notions clés

1. La dérivée : une pente locale

Intuition. Zoome assez sur une courbe lisse, elle finit par ressembler à une droite. La pente de cette droite, c’est la dérivée. Elle dit : « si je bouge x x un tout petit peu, de combien f f bouge-t-elle ? ».

On l’obtient comme limite des pentes des sécantes :

f ′ ( x ) = lim h → 0 f ( x + h ) − f ( x ) h f'(x) = \lim_{h \to 0} \frac{f(x+h) - f(x)}{h}

f(x) = x³ − 2x, ses sécantes depuis x = 1 pour h = 1 (pente 4) et h = 0,5 (pente 2,25), et la tangente en x = 1 de pente f’(1) = 1, limite des sécantes quand h tend vers 0.

Sur la figure, la sécante entre x = 1 x = 1 et x = 2 x = 2 a une pente de 4, celle entre 1 1 et 1 , 5 1{,}5 une pente de 2,25. Quand h h tend vers 0, on obtient la tangente de pente f ′ ( 1 ) = 3 ⋅ 1 2 − 2 = 1 f'(1) = 3 \cdot 1^2 - 2 = 1 .

Les règles qu’on utilise tout le temps :

Fonction Dérivée
x k x^k k x k − 1 k\,x^{k-1}
e x e^x e x e^x
ln x \ln x 1 / x 1/x
u + v u + v u ′ + v ′ u' + v'
u ⋅ v u \cdot v u ′ v + u v ′ u'v + uv'
u ( v ( x ) ) u(v(x)) u ′ ( v ( x ) ) ⋅ v ′ ( x ) u'(v(x))\cdot v'(x) (règle de la chaîne, voir M5)

En pratique numérique, on approche la dérivée par des différences finies. La version centrée est bien plus précise que la version « avant » :

f ′ ( x ) ≈ f ( x + h ) − f ( x − h ) 2 h f'(x) \approx \frac{f(x+h) - f(x-h)}{2h}

L’erreur de la version avant est proportionnelle à h h , celle de la version centrée à h 2 h^2 (on le démontrera avec Taylor en M6). Mais attention : si h h est trop petit, les erreurs d’arrondi des flottants dominent.

2. Dérivées partielles et gradient

Intuition. Une perte dépend de nombreux paramètres w 1 , … , w d w_1, \dots, w_d . La dérivée partielle ∂ f / ∂ w i \partial f / \partial w_i mesure l’effet d’un petit changement de w i w_i seul, tous les autres étant figés. Le gradient range toutes ces dérivées partielles dans un vecteur :

∇ f ( w ) = ( ∂ f ∂ w 1 , … , ∂ f ∂ w d ) \nabla f(w) = \left(\frac{\partial f}{\partial w_1}, \dots, \frac{\partial f}{\partial w_d}\right)

Exemple : pour g ( w ) = w 1 2 4 + w 2 2 g(w) = \frac{w_1^2}{4} + w_2^2 , on a ∇ g ( w ) = ( w 1 2 , 2 w 2 ) \nabla g(w) = \left(\frac{w_1}{2},\ 2w_2\right) , donc ∇ g ( 2 , 1 ) = ( 1 , 2 ) \nabla g(2, 1) = (1, 2) .

3. Pourquoi le gradient pointe vers la plus forte montée

Intuition. Debout sur une colline, dans quelle direction monter le plus vite ? Le gradient répond.

Si on fait un petit pas ε u \varepsilon u dans une direction u u de norme 1, la fonction varie d’environ :

f ( w + ε u ) − f ( w ) ≈ ε ⟨ ∇ f ( w ) , u ⟩ f(w + \varepsilon u) - f(w) \approx \varepsilon\, \langle \nabla f(w), u \rangle

C’est un produit scalaire (M1) : il est maximal quand u u est aligné avec ∇ f \nabla f , et vaut alors ‖ ∇ f ‖ \|\nabla f\| . Il est nul quand u u est perpendiculaire au gradient : on reste à la même hauteur. Trois conséquences :

  • ∇ f \nabla f indique la direction de plus forte montée, et ‖ ∇ f ‖ \|\nabla f\| la pente dans cette direction ;
  • − ∇ f -\nabla f indique la direction de plus forte descente : c’est toute l’idée de la descente de gradient (M10) ;
  • le gradient est perpendiculaire aux lignes de niveau (les courbes où f f est constante).

Lignes de niveau de g(w) = w₁²/4 + w₂² (ellipses grises). Les flèches rouges du gradient sont perpendiculaires aux lignes de niveau et pointent vers l’extérieur ; le chemin bleu suit −η·grad g et descend vers le minimum.

Sur la figure, les ellipses sont les lignes de niveau de g g . Les flèches rouges (le gradient) traversent chaque ellipse à angle droit. Le chemin bleu applique la règle w ← w − η ∇ g ( w ) w \leftarrow w - \eta \nabla g(w) : il descend vers le minimum, d’abord vite dans la direction verticale (où g g est plus pentue), puis plus lentement horizontalement.

4. Le gradient des pertes qu’on utilise

MSE de la régression linéaire. Avec L ( w ) = 1 n ‖ X w − y ‖ 2 L(w) = \frac{1}{n}\|Xw - y\|^2 :

∇ L ( w ) = 2 n X ⊤ ( X w − y ) \nabla L(w) = \frac{2}{n} X^\top (Xw - y)

Annuler ce gradient donne X ⊤ X w = X ⊤ y X^\top X w = X^\top y : ce sont exactement les équations normales obtenues géométriquement en M2.

Log-loss de la régression logistique. Avec p i = σ ( x i ⊤ w ) p_i = \sigma(x_i^\top w) et σ ( z ) = 1 1 + e − z \sigma(z) = \frac{1}{1 + e^{-z}} , on utilise une propriété remarquable de la sigmoïde :

σ ′ ( z ) = σ ( z ) ( 1 − σ ( z ) ) \sigma'(z) = \sigma(z)\,\big(1 - \sigma(z)\big)

En dérivant L ( w ) = − 1 n ∑ i [ y i log p i + ( 1 − y i ) log ( 1 − p i ) ] L(w) = -\frac{1}{n}\sum_i \big[y_i \log p_i + (1 - y_i)\log(1 - p_i)\big] , presque tout se simplifie :

∇ L ( w ) = 1 n X ⊤ ( σ ( X w ) − y ) \nabla L(w) = \frac{1}{n} X^\top \big(\sigma(Xw) - y\big)

Le gradient est simplement la somme des exemples, pondérés par l’erreur de prédiction p i − y i p_i - y_i . Avec une régularisation L 2 L_2 λ 2 ‖ w ‖ 2 \frac{\lambda}{2}\|w\|^2 , on ajoute λ w \lambda w . C’est cette formule qu’utilise la régression logistique de la partie 16.


Exemple de code

Différences finies : avant contre centrée

import numpy as np

def f(x):
    return x**3 - 2 * x

def f_prime(x):
    return 3 * x**2 - 2

x0 = 1.0
print("dérivée exacte :", f_prime(x0))
for h in (1e-1, 1e-3, 1e-5, 1e-8, 1e-12):
    avant = (f(x0 + h) - f(x0)) / h
    centree = (f(x0 + h) - f(x0 - h)) / (2 * h)
    print(f"h={h:.0e}  avant: erreur={abs(avant - f_prime(x0)):.2e}   centrée: erreur={abs(centree - f_prime(x0)):.2e}")
h h Erreur, version avant Erreur, version centrée
10 − 1 10^{-1} 3 , 1 × 10 − 1 3{,}1 \times 10^{-1} 1 , 0 × 10 − 2 1{,}0 \times 10^{-2}
10 − 3 10^{-3} 3 , 0 × 10 − 3 3{,}0 \times 10^{-3} 1 , 0 × 10 − 6 1{,}0 \times 10^{-6}
10 − 5 10^{-5} 3 , 0 × 10 − 5 3{,}0 \times 10^{-5} 9 , 5 × 10 − 11 9{,}5 \times 10^{-11}
10 − 8 10^{-8} 1 , 6 × 10 − 8 1{,}6 \times 10^{-8} 6 , 1 × 10 − 9 6{,}1 \times 10^{-9}
10 − 12 10^{-12} 8 , 9 × 10 − 5 8{,}9 \times 10^{-5} 8 , 9 × 10 − 5 8{,}9 \times 10^{-5}

La version avant gagne un facteur 100 quand h h est divisé par 100 (erreur en h h ). La version centrée gagne un facteur 10 000 (erreur en h 2 h^2 ). En dessous de h ≈ 10 − 5 h \approx 10^{-5} , les erreurs d’arrondi reprennent le dessus : à h = 10 − 12 h = 10^{-12} , les deux méthodes sont mauvaises.

Gradient numérique et direction de plus forte pente

import numpy as np

def g(w):
    return w[0] ** 2 / 4 + w[1] ** 2

def grad_g(w):
    return np.array([w[0] / 2, 2 * w[1]])

def grad_numerique(F, w, h=1e-5):
    gr = np.zeros_like(w)
    for i in range(len(w)):
        e = np.zeros_like(w)
        e[i] = h
        gr[i] = (F(w + e) - F(w - e)) / (2 * h)
    return gr

w = np.array([2.0, 1.0])
print("gradient exact     :", grad_g(w))
print("gradient numérique :", grad_numerique(g, w).round(6))

# on teste 360 directions de norme 1 : laquelle fait monter g le plus vite ?
angles = np.linspace(0, 2 * np.pi, 360, endpoint=False)
dirs = np.stack([np.cos(angles), np.sin(angles)], axis=1)
pentes = dirs @ grad_g(w)
best = dirs[np.argmax(pentes)]
print("direction de plus forte pente :", best.round(3),
      "| gradient normalisé :", (grad_g(w) / np.linalg.norm(grad_g(w))).round(3),
      "| pente max :", pentes.max().round(3), "= ||grad|| :", np.linalg.norm(grad_g(w)).round(3))

Le gradient numérique vaut exactement ( 1 , 2 ) (1, 2) . Parmi 360 directions, la meilleure est ( 0 , 454 ; 0 , 891 ) (0{,}454;\ 0{,}891) , à moins d’un degré du gradient normalisé ( 0 , 447 ; 0 , 894 ) (0{,}447;\ 0{,}894) , et la pente maximale vaut 2 , 236 = ‖ ∇ g ‖ = 5 2{,}236 = \|\nabla g\| = \sqrt 5 .

Gradient de la log-loss : analytique contre numérique

On vérifie la formule 1 n X ⊤ ( σ ( X w ) − y ) + λ w \frac{1}{n}X^\top(\sigma(Xw) - y) + \lambda w sur des données simulées, puis on suit − ∇ L -\nabla L pour voir la perte baisser.

import numpy as np

rng = np.random.default_rng(0)
n, d = 500, 3
X = rng.normal(size=(n, d))
w_vrai = np.array([1.5, -2.0, 0.5])

def sigmoide(z):
    return 1 / (1 + np.exp(-z))

y = (rng.random(n) < sigmoide(X @ w_vrai)).astype(float)

def log_loss(w, lam=0.0):
    p = sigmoide(X @ w)
    eps = 1e-12
    return -np.mean(y * np.log(p + eps) + (1 - y) * np.log(1 - p + eps)) + lam / 2 * w @ w

def grad_log_loss(w, lam=0.0):
    return X.T @ (sigmoide(X @ w) - y) / n + lam * w

def grad_numerique(F, w, h=1e-5):
    gr = np.zeros_like(w)
    for i in range(len(w)):
        e = np.zeros_like(w)
        e[i] = h
        gr[i] = (F(w + e) - F(w - e)) / (2 * h)
    return gr

w_test = rng.normal(size=d)
for lam in (0.0, 0.1):
    ga = grad_log_loss(w_test, lam)
    gn = grad_numerique(lambda v: log_loss(v, lam), w_test)
    print(f"lambda={lam}: écart max analytique/numérique = {np.abs(ga - gn).max():.1e}")

# suivre -gradient : la perte baisse
w_k = np.zeros(d)
for k in range(201):
    if k in (0, 1, 5, 20, 50, 200):
        print(f"itération {k:>3} : log-loss = {log_loss(w_k):.4f}, w = {w_k.round(3)}")
    w_k = w_k - 1.0 * grad_log_loss(w_k)

L’écart entre gradient analytique et numérique est de l’ordre de 10 − 11 10^{-11} : la formule est juste. La descente fait passer la log-loss de 0 , 693 0{,}693 (c’est ln 2 \ln 2 , la perte d’un modèle qui répond toujours 50 %) à 0 , 463 0{,}463 en 200 itérations, avec w ≈ ( 1 , 19 ; − 1 , 68 ; 0 , 24 ) w \approx (1{,}19;\ -1{,}68;\ 0{,}24) . Les signes et les proportions de w vrai = ( 1 , 5 ; − 2 ; 0 , 5 ) w_{\text{vrai}} = (1{,}5;\ -2;\ 0{,}5) sont retrouvés. L’écart restant vient du bruit d’échantillonnage sur 500 exemples.

Cette vérification par différences finies (le gradient check) est un réflexe à garder : dès que tu écris un gradient à la main, compare-le à sa version numérique.


Exercice pratique

  1. À la main. Calcule f ′ ( x ) f'(x) pour f ( x ) = x 2 e − x f(x) = x^2 e^{-x} et f ( x ) = ln ( 1 + e x ) f(x) = \ln(1 + e^x) (la fonction softplus). Vérifie avec la différence centrée. Que remarques-tu sur la dérivée de softplus ?
  2. Le gradient de la MSE. Écris grad_mse(w) = 2 n X ⊤ ( X w − y ) = \frac{2}{n}X^\top(Xw - y) pour une régression linéaire, vérifie-le avec grad_numerique, puis résous ∇ L = 0 \nabla L = 0 avec np.linalg.solve et compare à la solution de M2.
  3. Lignes de niveau. Pour h ( w ) = w 1 2 + w 1 w 2 + 2 w 2 2 h(w) = w_1^2 + w_1 w_2 + 2 w_2^2 , calcule ∇ h \nabla h . Trace quelques lignes de niveau avec plt.contour et superpose les flèches du gradient avec plt.quiver. Vérifie visuellement l’orthogonalité.
  4. Le piège du pas. Dans la descente de gradient sur la log-loss, essaie un pas de 10 puis de 50 au lieu de 1. Que se passe-t-il ? (On l’expliquera en M6 et M10 avec la courbure.)
  5. Fil rouge. Pour un modèle logistique sur les 9 features de la partie 14, quelle est la dimension du gradient ? Combien d’opérations coûte son calcul pour n n exemples ? Compare avec le coût d’une prédiction.

Indice pour la question 1 : la dérivée de softplus est une fonction que tu connais déjà très bien.


Ressources pour aller plus loin

  • 3Blue1Brown, Essence of Calculus, épisodes 1 à 4 : la dérivée comme pente, en animation.
  • Khan Academy, Multivariable calculus, chapitre Gradient and directional derivatives.
  • Deisenroth et al., Mathematics for Machine Learning, chapitre 5 (calcul vectoriel), sections 5.1 à 5.3.
  • CS231n (Stanford), notes sur le gradient checking.

Ce que tu dois savoir faire avant de passer à la suite

  • Expliquer une dérivée comme une pente locale, avec un dessin
  • Calculer une dérivée numériquement et choisir un h h raisonnable
  • Calculer un gradient à la main pour une fonction de plusieurs variables
  • Expliquer pourquoi on suit − ∇ f -\nabla f pour faire baisser f f , avec le produit scalaire
  • Retrouver 1 n X ⊤ ( σ ( X w ) − y ) \frac{1}{n}X^\top(\sigma(Xw) - y) comme gradient de la log-loss
  • Faire un gradient check systématique

Partie suivante : M5 · Règle de la chaîne et rétropropagation. Dériver une composition de fonctions, c’est exactement ce que fait un réseau de neurones à l’entraînement.