Optimization Algorithm
Un algoritmo di ottimizzazione aggiorna i pesi di un modello per minimizzarne la loss durante l'addestramento. Include discesa del gradiente, momentum, Adam, AdamW, Muon e codice.
Un algoritmo di ottimizzazione, o ottimizzatore, è la regola che un processo di addestramento usa per modificare i parametri di un modello in modo da ridurre la sua funzione di perdita. Nel deep learning, l’ottimizzatore riceve da backpropagation il gradiente della perdita rispetto a ogni peso del modello e decide di quanto e in quale direzione spostarlo. Insieme al suo tasso di apprendimento, l’ottimizzatore determina la velocità di convergenza dell’addestramento, la sua stabilità, la quantità di memoria necessaria e spesso la capacità del modello finale di generalizzare.
Come funzionano gli ottimizzatori#
Quasi tutti gli ottimizzatori di deep learning sono varianti della discesa del gradiente: calcolano il gradiente g della perdita su un mini-batch, poi spostano i pesi di un piccolo passo nella direzione opposta, w ← w − η·g. Gli ottimizzatori differiscono per il modo in cui elaborano g prima del passo. I metodi con momentum mediano i gradienti nel tempo per aumentare la velocità lungo direzioni costanti. I metodi adattivi dividono il passo di ciascun parametro per una stima mobile dell’ampiezza del suo gradiente. Muon ortogonalizza l’aggiornamento di ciascuna matrice dei pesi nel suo insieme. I metodi del secondo ordine usano anche la curvatura, rendendo ogni passo più informato ma molto più costoso da calcolare. I metodi che non richiedono gradienti, come gli algoritmi evolutivi e la ricerca casuale, ottimizzano provando diverse alternative e conservando la migliore:
La regola di aggiornamento è più importante quando la superficie di perdita è mal condizionata, con una curvatura ripida in alcune direzioni e lieve in altre. Avviare tre ottimizzatori dallo stesso punto in una valle stretta mostra la differenza:
import torch
# A long, narrow valley: f(w) = w1^2 + 50 * w2^2, with its minimum at (0, 0)
scale = torch.tensor([1.0, 50.0])
optimizers = {
"SGD": lambda p: torch.optim.SGD(p, lr=0.015),
"SGD + momentum": lambda p: torch.optim.SGD(p, lr=0.015, momentum=0.9),
"Adam": lambda p: torch.optim.Adam(p, lr=0.1),
}
for name, make_optimizer in optimizers.items():
w = torch.tensor([5.0, 1.0], requires_grad=True)
optimizer = make_optimizer([w])
# Same loss and starting point for every optimizer; only the update rule differs
for step in range(100):
loss = (scale * w**2).sum()
optimizer.zero_grad()
loss.backward()
optimizer.step()
print(f"{name:15s} f(w) after 100 steps: {(scale * w**2).sum().item():.6f}")SGD semplice si ferma a 0.056531 perché la direzione ripida w2 limita il tasso di apprendimento: qualsiasi tasso superiore a 0.02 fa superare a w2 il valore corretto sempre di più a ogni passo, e a 0.021 la perdita sale a circa 9,5 miliardi entro 100 passi. Con questo limite, i progressi lungo la direzione più lieve w1 sono lenti. Il momentum raggiunge 0.000216 aumentando la velocità lungo w1, mentre Adam raggiunge 0.001953 assegnando a ciascuna coordinata una propria dimensione del passo.
Algoritmi di ottimizzazione comuni#
- Discesa stocastica del gradiente (SGD): Esegue passi nella direzione opposta al gradiente del mini-batch. Con momentum pari a 0.9, ha addestrato la maggior parte delle reti convoluzionali di riferimento e memorizza un valore aggiuntivo per parametro.
- AdaGrad e RMSProp: Ridimensionano il passo di ciascun parametro in base alla cronologia dei suoi gradienti al quadrato. AdaGrad divide per la radice della loro somma cumulativa, che cresce soltanto, quindi i suoi passi si riducono per tutta la durata dell’addestramento. RMSProp usa invece una media con decadimento esponenziale, mantenendo così le dimensioni dei passi reattive.
- Adam: Combina il momentum con il ridimensionamento di tipo RMSProp e corregge entrambe le medie mobili per il loro valore iniziale pari a zero. I valori predefiniti, un tasso di apprendimento di 0.001 con β1 = 0.9 e β2 = 0.999, funzionano in molti problemi.
- AdamW: Adam con decadimento dei pesi disaccoppiato, che riduce direttamente i pesi invece di farlo tramite il ridimensionamento adattivo del gradiente. È l’ottimizzatore standard per i Transformer e i grandi modelli linguistici (LLMs).
- Muon: Ortogonalizza l’aggiornamento del momentum di ogni matrice dei pesi 2D con iterazioni di Newton–Schulz e mantiene un singolo buffer di stato per parametro. Moonshot AI lo ha esteso al preaddestramento degli LLM.
- L-BFGS: Un metodo quasi-Newton che costruisce una stima della curvatura a partire dai gradienti recenti. Converge in pochi passi nei problemi regolari con batch completo, mentre i gradienti rumorosi dei mini-batch lo rendono poco adatto alle reti di grandi dimensioni.
Il pacchetto di ottimizzazione di PyTorch implementa tutti questi metodi, incluso torch.optim.Muon, oltre a scheduler del tasso di apprendimento compatibili con ciascuno di essi.
Ottimizzatore e termini correlati#
- Funzione di perdita: L’obiettivo che l’ottimizzatore minimizza, come la cross-entropy per la classificazione o l’errore quadratico medio per la regressione.
- Scheduler del tasso di apprendimento: Regola la dimensione del passo η durante l’addestramento, con warmup, decadimento a gradini o annealing coseno, in aggiunta a qualsiasi ottimizzatore.
- Ottimizzazione degli iperparametri: Una ricerca esterna di impostazioni come ottimizzatore, tasso di apprendimento e dimensione del batch, in cui ogni alternativa richiede un addestramento completo o parziale. Metodi senza gradiente, come l’ottimizzazione bayesiana e la ricerca evolutiva, svolgono questo compito perché un punteggio di convalida non è differenziabile rispetto a scelte come l’ottimizzatore.
Scegliere un ottimizzatore#
L’ottimizzatore e il tasso di apprendimento si scelgono insieme, perché ogni ottimizzatore ha un intervallo di valori proprio: SGD con momentum parte in genere da 0.01 a 0.1, mentre gli ottimizzatori della famiglia Adam si aggirano intorno a 0.001. L’addestramento di Ultralytics YOLO effettua la scelta automaticamente: l’impostazione predefinita optimizer="auto" ignora lr0 e seleziona AdamW con un tasso di apprendimento adattato al numero di classi per le esecuzioni fino a 10.000 iterazioni, oppure MuSGD, l’ibrido SGD e Muon usato per addestrare i checkpoint YOLO26 rilasciati, per pianificazioni più lunghe. Specificando un ottimizzatore, lr0 diventa effettivo:
from ultralytics import YOLO
# Carica un modello YOLO26n preaddestrato
model = YOLO("yolo26n.pt")
# Scegli SGD esplicitamente; lr0 si applica solo quando l'ottimizzatore non è "auto"
results = model.train(data="coco8.yaml", epochs=5, optimizer="SGD", lr0=0.01)Con optimizer="SGD", il trainer abilita anche il momentum di Nesterov, usando l’argomento momentum, pari a 0.937 per impostazione predefinita, come coefficiente.










