📌 Travaux Pratiques

TP : Descente de Gradient en Python

TP : Implémentation de la Descente de Gradient en Python

🎯 Objectifs pédagogiques

  • Comprendre le principe mathématique de la descente de gradient
  • Implémenter la méthode de descente de gradient en Python
  • Visualiser le processus d'optimisation
  • Résoudre un problème de régression linéaire simple

Partie 1 : Rappel Théorique

1. Qu'est-ce que la descente de gradient ?

La descente de gradient est une méthode d'optimisation qui permet de minimiser une fonction de coût. On met à jour les paramètres θ en suivant la direction opposée au gradient de la fonction coût :

θ = θ - α · ∇J(θ)

où :

  • θ : les paramètres du modèle
  • α : le taux d'apprentissage (learning rate)
  • ∇J(θ) : le gradient de la fonction coût J

Partie 2 : Exemple de Régression Linéaire

Fonction à minimiser :

J(θ₀, θ₁) = (1/2m) Σ(hθ(xᵢ) - yᵢ)²

où hθ(x) = θ₀ + θ₁x

Partie 3 : Code Complet en Python

Étape 1 : Import des bibliothèques

imports.py
import numpy as np
import matplotlib.pyplot as plt

Étape 2 : Génération de données simples

data_generation.py
# Génération de données linéaires
np.random.seed(0)
X = 2 * np.random.rand(100, 1)
y = 4 + 3 * X + np.random.randn(100, 1)

Étape 3 : Fonction de coût

cost_function.py
def compute_cost(X, y, theta):
    m = len(y)
    predictions = X.dot(theta)
    cost = (1/(2*m)) * np.sum((predictions - y) ** 2)
    return cost

Étape 4 : Fonction de descente de gradient

gradient_descent.py
def gradient_descent(X, y, theta, learning_rate=0.1, iterations=1000):
    m = len(y)
    cost_history = []

    for i in range(iterations):
        gradients = (1/m) * X.T.dot(X.dot(theta) - y)
        theta = theta - learning_rate * gradients
        cost = compute_cost(X, y, theta)
        cost_history.append(cost)

        if i % 100 == 0:
            print(f"Iteration {i} | Coût: {cost:.4f}")
    
    return theta, cost_history

Étape 5 : Préparation des données

data_preparation.py
# Ajout de l'interception (x0 = 1)
X_b = np.c_[np.ones((100, 1)), X]

# Initialisation des paramètres
theta_initial = np.random.randn(2, 1)

Étape 6 : Exécution de la descente de gradient

run_gradient_descent.py
theta_final, cost_history = gradient_descent(X_b, y, theta_initial, learning_rate=0.1, iterations=1000)

print("Paramètres finaux :", theta_final.ravel())

Étape 7 : Visualisation

1. Visualiser la droite de régression

visualization.py
plt.plot(X, y, "b.")
plt.plot(X, X_b.dot(theta_final), "r-", linewidth=2)
plt.title("Régression linéaire par descente de gradient")
plt.xlabel("X")
plt.ylabel("y")
plt.show()

2. Visualiser la convergence du coût

cost_visualization.py
plt.plot(cost_history)
plt.title("Évolution du coût au fil des itérations")
plt.xlabel("Itérations")
plt.ylabel("Coût")
plt.grid(True)
plt.show()

Partie 4 : Résolution d'un problème d'optimisation simple

Analyse mathématique

Fonction à minimiser :

f(x) = (x - 3)² + 4

Dérivée de la fonction :

f'(x) = 2(x - 3)

Implémentation Python

simple_gradient_descent.py
import matplotlib.pyplot as plt

# Fonction à minimiser
def f(x):
    return (x - 3)**2 + 4

# Dérivée de la fonction
def df(x):
    return 2 * (x - 3)

# Descente de gradient
def gradient_descent(initial_x, learning_rate, n_iterations):
    x = initial_x
    history = [x]  # Pour enregistrer les valeurs de x à chaque étape

    for i in range(n_iterations):
        grad = df(x)                    # Calcul du gradient
        x = x - learning_rate * grad    # Mise à jour de x
        history.append(x)               # Sauvegarde

        print(f"Iteration {i+1}: x = {x:.6f}, f(x) = {f(x):.6f}")

    return x, history

Paramètres et exécution

execution.py
# Paramètres de la descente
initial_x = 0
learning_rate = 0.1
n_iterations = 25

# Exécution
final_x, x_history = gradient_descent(initial_x, learning_rate, n_iterations)

print("\nMinimum atteint pour x =", final_x)
print("Valeur minimale de f(x) =", f(final_x))

Visualisation du processus

visualization_simple.py
# Affichage graphique
import numpy as np

x_vals = np.linspace(-2, 8, 200)
y_vals = f(x_vals)

plt.plot(x_vals, y_vals, label="f(x)")
plt.scatter(x_history, [f(x) for x in x_history], color='red', label='Itérations')
plt.plot(x_history, [f(x) for x in x_history], '--', color='red')
plt.xlabel("x")
plt.ylabel("f(x)")
plt.title("Descente de gradient sur f(x) = (x-3)^2 + 4")
plt.legend()
plt.grid(True)
plt.show()

Résultat final

Le point de départ était x = 0

Après 25 itérations avec un taux d'apprentissage de 0.1, on obtient :

Minimum atteint pour x ≈ 2.999999
Valeur minimale de f(x) ≈ 4.000000

Questions de compréhension

  1. Quel est le rôle du taux d'apprentissage dans l'algorithme ?
  2. Que se passe-t-il si on utilise un taux d'apprentissage trop élevé ou trop faible ?
  3. Pourquoi ajoute-t-on une colonne de 1 à X ?
  4. Que représente le gradient dans cet algorithme ?

Extensions possibles

  • Implémentez une version stochastique de la descente de gradient (SGD)
  • Testez avec un polynôme de degré 2 (régression quadratique)
  • Ajoutez un critère d'arrêt basé sur la variation du coût

Commentaires