← Retour au portfolio RSS

· 2 min de lecture

La régression linéaire, en bas niveau

Un seul neurone entraîné par descente de gradient : le modèle, la fonction de coût, le gradient, et la solution analytique.

La régression linéaire est le point d’entrée classique du deep learning : un seul neurone, sans fonction d’activation, entraîné par descente de gradient. Comprendre son fonctionnement mécanique — pas juste model.fit() — donne les bases de tout ce qui suit (réseaux profonds, backprop, optimiseurs).

Le modèle

On cherche une fonction affine qui approxime y y à partir de x x :

y ^ = w x + b \hat{y} = w x + b

Avec plusieurs variables d’entrée, x ∈ ℝ n x \in \mathbb{R}^n devient un vecteur, et w ∈ ℝ n w \in \mathbb{R}^n également :

y ^ = w ⊤ x + b = ∑ i = 1 n w i x i + b \hat{y} = w^\top x + b = \sum_{i=1}^{n} w_i x_i + b

La fonction de coût

On mesure l’erreur sur tout le jeu d’entraînement avec l’erreur quadratique moyenne :

J ( w , b ) = 1 m ∑ i = 1 m ( y ^ ( i ) − y ( i ) ) 2 J(w, b) = \frac{1}{m} \sum_{i=1}^{m} \left( \hat{y}^{(i)} - y^{(i)} \right)^2

où m m est le nombre d’exemples. Le carré pénalise davantage les grosses erreurs et rend la fonction dérivable partout, contrairement à la valeur absolue.

Le gradient

Pour minimiser J J , on calcule sa dérivée par rapport à chaque paramètre. Pour w w :

∂ J ∂ w = 2 m ∑ i = 1 m ( y ^ ( i ) − y ( i ) ) x ( i ) \frac{\partial J}{\partial w} = \frac{2}{m} \sum_{i=1}^{m} \left( \hat{y}^{(i)} - y^{(i)} \right) x^{(i)}

Et pour b b :

∂ J ∂ b = 2 m ∑ i = 1 m ( y ^ ( i ) − y ( i ) ) \frac{\partial J}{\partial b} = \frac{2}{m} \sum_{i=1}^{m} \left( \hat{y}^{(i)} - y^{(i)} \right)

La descente de gradient

On met à jour les paramètres dans la direction opposée au gradient, pondérée par un taux d’apprentissage η \eta :

w ← w − η ∂ J ∂ w w \leftarrow w - \eta \frac{\partial J}{\partial w}

b ← b − η ∂ J ∂ b b \leftarrow b - \eta \frac{\partial J}{\partial b}

On répète jusqu’à convergence. Un η \eta trop grand fait diverger l’entraînement ; trop petit, il converge mais très lentement.

Implémentation minimale

import numpy as np

def train(X, y, lr=0.01, epochs=1000):
    m, n = X.shape
    w = np.zeros(n)
    b = 0.0

    for _ in range(epochs):
        y_hat = X @ w + b
        error = y_hat - y

        dw = (2 / m) * X.T @ error
        db = (2 / m) * np.sum(error)

        w -= lr * dw
        b -= lr * db

    return w, b

La solution analytique

Pour ce cas précis, il existe une solution exacte, sans itération : les équations normales.

w = ( X ⊤ X ) − 1 X ⊤ y w = (X^\top X)^{-1} X^\top y

Elle évite la descente de gradient entièrement, mais devient coûteuse quand n n est grand (inversion de matrice en O ( n 3 ) O(n^3) ), ou impossible si X ⊤ X X^\top X n’est pas inversible. La descente de gradient, elle, se généralise directement aux réseaux profonds — c’est pour ça qu’on l’apprend en premier.