Stochastic Gradient Descent (SGD)
SGD entraîne un modèle à l’aide de nombreuses mises à jour peu coûteuses des poids, calculées sur de petits lots de données aléatoires. Au programme : règle de mise à jour, momentum, taille des lots et code.
La descente de gradient stochastique (SGD) est un algorithme d’optimisation qui entraîne un modèle en mettant à jour de façon répétée ses poids à l’aide du gradient de la perte calculée sur un petit échantillon aléatoire des données d’entraînement, plutôt que sur l’ensemble du jeu de données. Le gradient de chaque échantillon est une estimation bruitée, mais non biaisée, du gradient calculé sur tout le jeu de données ; SGD effectue donc de nombreuses mises à jour peu coûteuses pendant le temps nécessaire à la descente de gradient par lots complets pour en effectuer une seule, coûteuse. Cette méthode descend de la méthode d’approximation stochastique de Robbins et Monro publiée en 1951 et, avec momentum, reste un optimiseur standard pour les réseaux neuronaux convolutifs (CNN).
Fonctionnement de SGD#
À chaque étape, SGD prend un mini-lot B, calcule la dérivée de la perte sur ce mini-lot par rétropropagation, puis déplace chaque poids d’un petit pas dans le sens opposé au gradient : w ← w − η·∇L_B(w), où η est le taux d’apprentissage. À strictement parler, SGD utilise un exemple par étape, mais les frameworks d’apprentissage profond l’appliquent à des mini-lots de quelques dizaines à plusieurs milliers d’exemples ; en pratique, « SGD » et « descente de gradient par mini-lots » sont donc synonymes. Une taille de lot plus grande produit un gradient moins bruité et une meilleure utilisation du matériel, au prix d’un nombre inférieur de mises à jour par époque.
L’entraînement mélange les données au début de chaque époque, les parcourt par mini-lots et effectue une étape par lot. L’ajustement d’une droite à 1 000 points bruités illustre l’ensemble du processus :
import torch
torch.manual_seed(0)
# 1,000 noisy samples of y = 3x + 2
x = torch.randn(1000, 1)
y = 3 * x + 2 + 0.1 * torch.randn(1000, 1)
model = torch.nn.Linear(1, 1)
optimizer = torch.optim.SGD(model.parameters(), lr=0.05, momentum=0.9)
for epoch in range(5):
# Reshuffle every epoch, then update the weights once per 32-sample mini-batch
for idx in torch.randperm(1000).split(32):
loss = torch.nn.functional.mse_loss(model(x[idx]), y[idx])
optimizer.zero_grad()
loss.backward()
optimizer.step()
print(f"epoch {epoch}: w = {model.weight.item():.3f}, b = {model.bias.item():.3f}, loss = {loss.item():.4f}")Après deux époques, soit 64 mises à jour au total, le poids atteint 3.081 et le biais 2.012. Au cours des trois époques suivantes, le poids continue d’osciller entre 2.967 et 3.003 au lieu de se stabiliser, car le gradient de chaque mini-lot comporte un bruit d’échantillonnage ; la perte du dernier lot reste proche de 0.01, la variance du bruit ajouté à y.
Taux d’apprentissage, bruit et taille de lot#
Avec un taux d’apprentissage constant, SGD oscille dans une région autour du minimum, dont la taille augmente avec le taux d’apprentissage et le bruit du gradient. La théorie de l’approximation stochastique garantit la convergence uniquement lorsque le taux d’apprentissage tend vers zéro. En pratique, on le réduit donc au fil du temps à l’aide d’échéanciers par paliers ou cosinus, généralement après une courte phase de préchauffage. Le bruit du gradient des petits lots oriente aussi SGD vers des minima plats qui généralisent mieux que les minima pointus que tend à trouver l’entraînement avec de grands lots, une forme implicite de régularisation.
La taille du lot et le taux d’apprentissage interagissent. En augmentant le taux d’apprentissage proportionnellement à la taille du lot, avec un préchauffage de cinq époques, ResNet-50 a pu s’entraîner sur ImageNet en une heure avec des mini-lots de 8 192 images et sans perte de précision.
Momentum et momentum de Nesterov#
Dans une vallée longue et étroite de la surface de perte, le gradient pointe surtout en travers de la vallée. SGD classique zigzague donc entre les parois tout en progressant lentement le long du fond. Le momentum conserve une vitesse cumulée, v ← μ·v + g, et avance dans sa direction, w ← w − η·v : les directions de gradient cohérentes accélèrent, tandis que les directions oscillantes s’annulent. La valeur par défaut habituelle du coefficient est μ = 0,9. Le momentum de Nesterov évalue le gradient après un pas d’anticipation dans la direction de la vitesse, ce qui atténue davantage le dépassement. Le SGD de PyTorch implémente les deux méthodes et applique weight_decay en ajoutant λ·w au gradient, ce qui, pour SGD, équivaut à une pénalité L2 sur les poids.
SGD et les autres optimiseurs#
- Descente de gradient par lot : Calcule le gradient exact sur l’ensemble du jeu de données à chaque mise à jour. Chaque époque ne produit donc qu’un seul pas, et les besoins en mémoire augmentent avec la taille du jeu de données.
- Adam : Attribue à chaque paramètre son propre pas à partir des moyennes mobiles de ses gradients et de leurs carrés, et stocke deux valeurs d’état par paramètre, contre une pour SGD avec momentum. Adam progresse plus vite au début et est moins sensible au taux d’apprentissage, tandis que SGD avec momentum, bien réglé, atteint souvent une précision finale équivalente ou supérieure sur les CNN. AdamW, sa variante avec décroissance des poids découplée, est l’optimiseur standard pour les transformers.
- Muon : Orthogonalise la mise à jour du momentum de chaque matrice de poids dans son ensemble, et a été adapté à l’entraînement de grands modèles de langage.
L’entraînement Ultralytics YOLO construit SGD PyTorch avec l’impulsion de Nesterov lorsque optimizer="SGD" est défini, en utilisant lr0=0.01 et momentum=0.937 par défaut. Le paramètre optimizer="auto" par défaut ignore lr0 et choisit MuSGD, une méthode hybride qui combine les mises à jour SGD et Muon, pour les exécutions de plus de 10 000 itérations, et AdamW pour les plus courtes.
Utilisations de SGD#
SGD avec momentum a entraîné la plupart des célèbres CNN d’ImageNet. Les modèles ResNet d’origine utilisaient un momentum de 0,9, une décroissance des poids de 0,0001 et des mini-lots de 256 images, avec un taux d’apprentissage initial de 0,1, divisé par 10 chaque fois que l’erreur plafonnait. En dehors de l’apprentissage profond, les classes SGDClassifier et SGDRegressor de scikit-learn ajustent des modèles linéaires tels que la régression logistique et les machines à vecteurs de support linéaires avec SGD, et leur méthode partial_fit entraîne les modèles sur des jeux de données trop volumineux pour tenir en mémoire, un bloc à la fois.










