PyTorch torch.optim Optimizer-Modul
Optimierer sind Kernkomponenten im Deep Learning und dafür verantwortlich, Modellparameter auf Grundlage des Gradienten der Verlustfunktion anzupassen, wodurch sich das Modell schrittweise der optimalen Lösung nähert.
In PyTorch stellt das Modul torch.optim Implementierungen verschiedener Optimierungsalgorithmen bereit und ist ein unverzichtbares Werkzeug zum Trainieren neuronaler Netzwerke.
Warum Optimierer benötigt werden
Optimierer spielen im Deep Learning eine entscheidende Rolle und lösen das mühsame Problem der manuellen Aktualisierung von Parametern.
- Automatische Parameteraktualisierungen: Manuelles Berechnen und Aktualisieren jedes Parameters ist sehr mühsam, und der Optimierer erledigt dies automatisch.
- Beschleunigte Konvergenz: Die Verwendung von Optimierungsalgorithmen findet die optimale Lösung schneller als reiner Gradientenabstieg.
- Lokale Optima vermeiden: Einige Optimierer können lokalen Optima entkommen.
Gängige Optimierer-Typen
Verschiedene Optimierer eignen sich für verschiedene Szenarien. Die Wahl des richtigen Optimierers kann Trainingsergebnisse erheblich verbessern.
| Optimierer-Name | Hauptfunktionen | Geeignete Szenarien |
|---|---|---|
| SGD | Einfach und grundlegend, unterstützt Momentum | Grundlegende Lehre, einfache Modelle, CNN |
| Adam | Adaptive Lernrate | Die meisten Deep-Learning-Aufgaben |
| AdamW | Adam + entkoppelter Weight Decay | Aufgaben, die L2-Regularisierung erfordern |
| RMSprop | Adaptive Lernrate | RNN-Netzwerke, Spracherkennung |
| Adagrad | Lernrate pro Parameter | Sparse-Daten, Textverarbeitung |
| Adadelta | Adaptive Lernrate | Langfristige Trainingsaufgaben |
Zentrale Optimizer-API
Die Beherrschung des grundlegenden Nutzungsablaufs von Optimierern ist der erste Schritt im Deep Learning.
Grundlegender Nutzungsablauf
Die Verwendung von Optimierern folgt einem festen Muster: Instanz erstellen → Gradienten nullen → Backward-Pass → Parameter aktualisieren.
Beispiel
import torch.nn as nn
import torch.optim as optim
# 1. Ein einfaches Modell definieren
class SimpleNet(nn.Module):
def __init__(self):
super().__init__()
self.fc = nn.Linear(784, 10)
def forward(self, x):
return self.fc(x)
model = SimpleNet()
# 2. Optimizer-Instanz erstellen
optimizer = optim.Adam(model.parameters(), lr=0.001)
# 3. Trainingsschleife
for epoch in range(epochs):
# Vorwärtsdurchlauf
outputs = model(inputs)
loss = criterion(outputs, labels)
# Rückwärtsdurchlauf
optimizer.zero_grad() # Den Gradienten-Cache auf Null setzen, um Gradientenakkumulation zu vermeiden
loss.backward() # Gradienten berechnen
# Parameteraktualisierung
optimizer.step() # Parameter aktualisieren
Erklärung der wichtigsten Methoden
Der Optimierer bietet mehrere zentrale Methoden zur Verwaltung des Parameteraktualisierungsprozesses.
- zero_grad(set_to_none=True): Setzt den Parameter-Gradienten-Cache auf null. Wenn auf True gesetzt, werden Gradienten auf None gesetzt, was mehr Speicher spart, als sie auf 0 zu setzen.
- step(): Führt eine einzelne Parameteraktualisierung durch, wobei Modellparameter anhand von Gradienten und Lernrate aktualisiert werden.
- state_dict(): Ruft das Zustands-Dictionary des Optimierers ab, das zum Speichern von Checkpoints verwendet werden kann.
- load_state_dict(state_dict): Lädt den Optimiererzustand, um das Training fortzusetzen.
- add_param_group(param_group): Fügt dynamisch eine Parametergruppe hinzu.
Hinweis: Sie müssen zero_grad() vor jedem Backward-Pass aufrufen, da sich sonst Gradienten ansammeln und zu instabilem Training führen. Es wird empfohlen, zero_grad(set_to_none=True) zu verwenden, um Speicher zu sparen.
Speichern und Laden des Optimiererzustands
Beim Fortsetzen des Trainings müssen sowohl der Modell- als auch der Optimiererzustand gespeichert werden.
Beispiel
checkpoint = {
'epoch': epoch,
'model_state_dict': model.state_dict(),
'optimizer_state_dict': optimizer.state_dict(),
'scheduler_state_dict': scheduler.state_dict(),
'loss': loss,
}
torch.save(checkpoint, 'checkpoint.pth')
# Checkpoint laden
checkpoint = torch.load('checkpoint.pth')
model.load_state_dict(checkpoint['model_state_dict'])
optimizer.load_state_dict(checkpoint['optimizer_state_dict'])
scheduler.load_state_dict(checkpoint['scheduler_state_dict'])
start_epoch = checkpoint['epoch'] + 1
Detaillierte Erklärung gängiger Optimierer
SGD (Stochastic Gradient Descent)
SGD ist der grundlegendste Optimierungsalgorithmus; er aktualisiert Parameter, indem Gradienten aus einer einzelnen Stichprobe oder einem Mini-Batch von Stichproben berechnet werden. Er ist der Eckpfeiler der Deep-Learning-Optimierung, und viele fortgeschrittene Optimierer basieren auf SGD.
Beispiel
# params: Zu optimierende Parameter (normalerweise aus model.parameters())
# lr: Lernrate, steuert die Schrittweite der Parameteraktualisierungen, Standard 0.01
# momentum: Momentum-Faktor, wird verwendet, um die Konvergenz zu beschleunigen und Oszillationen zu reduzieren, Standard 0
# weight_decay: L2-Regularisierungskoeffizient, wird verwendet, um Overfitting zu verhindern, Standard 0
# dampening: Momentum-Dämpfung, steuert die Berechnung des Momentum-Terms, Standard 0
# nesterov: ob Nesterov-Momentum verwendet werden soll, Standard False
optimizer = optim.SGD(
params=model.parameters(),
lr=0.01, # Lernrate
momentum=0.9, # Momentum-Faktor
weight_decay=1e-4, # L2-Regularisierung
nesterov=True # Nesterov-Momentum aktivieren
)
Beschreibung der Kernparameter:
- lr (float): Lernrate, steuert die Schrittweite der Parameteraktualisierungen
- momentum (float): Momentum-Faktor, wird verwendet, um die Konvergenz zu beschleunigen und Oszillationen zu reduzieren, üblicher Wert 0.9
- weight_decay (float): L2-Regularisierungskoeffizient, wird verwendet, um Überanpassung zu verhindern, üblicher Wert 1e-4
- nesterov (bool): ob Nesterov-Momentum verwendet werden soll; die Aktivierung kann Oszillationen reduzieren
Funktionen:
- Einfach zu implementieren, es ist der grundlegende Algorithmus der Deep-Learning-Optimierung
- Das Hinzufügen eines Momentum-Terms kann die Konvergenz beschleunigen und die Trainingsstabilität verbessern
- Langsamere Konvergenzgeschwindigkeit, aber die endgültige Genauigkeit kann höher sein
- Geeignet als Benchmark für den Vergleich mit anderen Optimierern
Obwohl SGD einfach ist, kann es mit geeigneten Hyperparametern oft sehr gute Ergebnisse erzielen, was es zu einem guten Ausgangspunkt für das Erlernen von Optimierungsalgorithmen macht. Bei Bildklassifikationsaufgaben bleibt SGD mit Momentum eine gängige Wahl.
Adam (Adaptive Moment Estimation)
Adam ist einer der am häufigsten verwendeten Optimierer und kombiniert die Vorteile von Momentum und adaptiven Lernraten. Er passt die Lernrate für jeden Parameter adaptiv an, indem er Schätzungen des ersten und zweiten Moments der Gradienten berechnet.
Beispiel
# params: zu optimierende Parameter
# lr: Lernrate, Standardwert 0.001 (empfohlener Wert)
# betas: Koeffizienten des gleitenden Durchschnitts zur Berechnung von Gradienten und quadrierten Gradienten (beta1, beta2)
# beta1 steuert die Schätzung des ersten Moments (Momentum), Standardwert 0.9
# beta2 steuert die Schätzung des zweiten Moments (Varianz), Standardwert 0.999
# eps: Term für numerische Stabilität, verhindert Division durch null, Standardwert 1e-8
# weight_decay: L2-Regularisierungskoeffizient, Standardwert 0
# amsgrad: ob die AMSGrad-Variante verwendet werden soll, Standardwert False
optimizer = optim.Adam(
params=model.parameters(),
lr=0.001, # Es wird empfohlen, eine kleinere Lernrate zu verwenden
betas=(0.9, 0.999), # Häufig verwendete Momentum-Parameter
eps=1e-8, # Term zur numerischen Stabilität
weight_decay=1e-4, # L2-Regularisierung
amsgrad=False # Ob AMSGrad verwendet werden soll
)
Beschreibung der Kernparameter:
- betas (Tuple[float, float]): steuern den exponentiellen gleitenden Durchschnitt von Gradienten und quadrierten Gradienten
- eps (float): Term zur numerischen Stabilität, verhindert, dass der Nenner null wird
- amsgrad (bool): ob die AMSGrad-Variante verwendet werden soll; ihre Verwendung kann Konvergenz garantieren
Funktionen:
- Adaptive Lernrate: passt die Lernrate automatisch anhand des historischen Gradienten des Parameters an
- Integriert das Momentum-Konzept: verwendet eine Schätzung des ersten Moments, um die Konvergenz zu beschleunigen
- Hohe Robustheit: relativ unempfindlich gegenüber der Wahl der Hyperparameter
- Schnelle Konvergenzgeschwindigkeit, geeignet für schnelles Prototyping
Adam ist die Standardwahl für die meisten Deep-Learning-Aufgaben, aber in bestimmten spezifischen Szenarien (wie GAN, Reinforcement Learning) muss man möglicherweise andere Optimierer ausprobieren.
AdamW(Adam mit Weight Decay)
AdamW ist eine verbesserte Version von Adam, die Weight Decay von Gradienten-Updates entkoppelt, was theoretisch förderlicher für die Konvergenz ist. In praktischen Anwendungen schneidet AdamW normalerweise besser ab als Adam.
Beispiel
# Hauptunterschied zu Adam: andere Implementierung von weight_decay
# Der Weight Decay von AdamW ist korrekter und wirkt sich nicht auf die Gradientenberechnung aus
optimizer = optim.AdamW(
params=model.parameters(),
lr=0.001,
betas=(0.9, 0.999),
weight_decay=0.01, # Weight-Decay-Koeffizient, normalerweise größer eingestellt als bei Adam
amsgrad=False
)
# Empfohlene Konfiguration: AdamW verwendet normalerweise einen weight_decay von 0.01
# Während Adam normalerweise 0.001 verwendet
Wenn Ihre Aufgabe Weight Decay (L2-Regularisierung) erfordert, wird dringend empfohlen, AdamW anstelle von Adam zu verwenden.
RMSprop
RMSprop ist ein Optimierer mit adaptiver Lernrate, der besonders für die Behandlung nicht-stationärer Ziele und rekurrenter neuronaler Netze geeignet ist.
Beispiel
# Normalisiert die Lernrate durch Division durch den exponentiell gewichteten Durchschnitt der Gradienten
optimizer = optim.RMSprop(
params=model.parameters(),
lr=0.01, # Lernrate
alpha=0.99, # Exponentielle Abklingrate für quadrierte Gradienten
eps=1e-8, # Term zur numerischen Stabilität
weight_decay=0, # L2-Regularisierung
momentum=0, # Momentum-Faktor
centered=False # Ob die Gradienten zentriert werden sollen
)
Adagrad
Adagrad eignet sich für die Verarbeitung von dünnbesetzten Daten; es passt die Lernrate adaptiv für jeden Parameter an.
Beispiel
# Geeignet für die Optimierung dünnbesetzter Daten, verwendet eine kleinere Lernrate für häufig aktualisierte Parameter
optimizer = optim.Adagrad(
params=model.parameters(),
lr=0.01, # Lernrate
lr_decay=0, # Lernratenabfall
weight_decay=0, # L2-Regularisierung
initial_accumulator_value=0 # Anfangswert des Akkumulators
)
Fortgeschrittene Optimierer-Techniken
Lernratenplanung
Die Lernratenplanung ermöglicht es, die Lernrate während des Trainings dynamisch anzupassen, was häufig die Modellkonvergenz deutlich verbessern kann.
Beispiel: Mehrere Lernraten-Scheduler
StepLR, # Stufenweiser Abfall
MultiStepLR, # Mehrstufiger Abfall
ExponentialLR, # Exponentieller Abfall
CosineAnnealingLR, # Kosinus-Annealing
ReduceLROnPlateau, # Automatische Anpassung anhand von Metriken
)
# Methode 1: StepLR - wird alle 30 Epochen verringert
optimizer = optim.SGD(model.parameters(), lr=0.1)
scheduler = StepLR(optimizer, step_size=30, gamma=0.1)
# Methode 2: MultiStepLR - wird zu festgelegten Epochen verringert
optimizer = optim.SGD(model.parameters(), lr=0.1)
scheduler = MultiStepLR(optimizer, milestones=[30, 60, 80], gamma=0.1)
# Methode 3: CosineAnnealingLR - Cosinus-Kurven-Annealing
optimizer = optim.Adam(model.parameters(), lr=0.001)
scheduler = CosineAnnealingLR(optimizer, T_max=50, eta_min=1e-6)
# Methode 4: ReduceLROnPlateau - passt sich automatisch anhand der überwachten Metrik an
optimizer = optim.Adam(model.parameters(), lr=0.001)
scheduler = ReduceLROnPlateau(
optimizer, mode='min', # Verlust überwachen
factor=0.5, # Abklingfaktor
patience=5, # Anzahl der Epochen zum Warten
verbose=True # Informationen ausgeben
)
# Trainingsschleife
for epoch in range(100):
train_loss = train(...)
val_loss = validate(...)
# StepLR und andere Scheduler
scheduler.step()
# ReduceLROnPlateau erfordert, dass die überwachte Metrik übergeben wird
scheduler.step(val_loss)
Der Lernraten-Scheduler muss zusammen mit dem Optimierer verwendet werden; step() muss nach optimizer.step() aufgerufen werden, andernfalls kann die Aktualisierung der Lernrate fehlerhaft sein.
Parametergruppen-Optimierung
Durch die Parametergruppierung können für verschiedene Schichten unterschiedliche Lernraten festgelegt werden, was insbesondere beim Transferlernen nützlich ist.
Beispiel
# Unterschiedliche Lernraten für verschiedene Schichten festlegen
# Normalerweise: Das Backbone-Netzwerk verwendet eine kleinere Lernrate, und der Klassifizierungskopf verwendet eine größere Lernrate
optimizer = optim.SGD([
{'params': model.base.parameters(), 'lr': 1e-3}, # Basisschichten: große Lernrate
{'params': model.classifier.parameters(), 'lr': 1e-2} # Klassifizierungsschicht: große Lernrate
], lr=1e-4) # Globale Standard-Lernrate (verwendet, wenn keine Parametergruppe angegeben ist)
# Gebräuchlichere Notation in praktischen Anwendungen
optimizer = optim.Adam([
{'params': model.fc.parameters(), 'lr': 1e-3}, # Klassifizierungskopf
{'params': [p for n, p in model.named_parameters() # Backbone-Netzwerk
if not n.startswith('fc')],
'lr': 1e-5},
])
Gradienten-Clipping
Gradienten-Clipping kann Gradientenexplosionen verhindern und die Trainingsstabilität verbessern. Es ist besonders nützlich in tiefen Netzwerken wie RNN und LSTM.
Beispiel
# Beispiel für Gradienten-Clipping
# max_norm: die maximale Norm der Gradienten; Gradienten, die diesen Wert überschreiten, werden skaliert
# norm_type: Normtyp, Standard ist 2 (L2-Norm)
nn.utils.clip_grad_norm_(model.parameters(), max_norm=1.0)
# Position in der Trainingsschleife
for epoch in range(epochs):
optimizer.zero_grad()
outputs = model(inputs)
loss = criterion(outputs, labels)
loss.backward()
# Gradienten nach loss.backward() und vor optimizer.step() clippen
nn.utils.clip_grad_norm_(model.parameters(), max_norm=1.0)
optimizer.step()
# Eine weitere Möglichkeit des Gradienten-Clippings: Clipping nach Wert
for param in model.parameters():
if param.grad is not None:
param.grad.data.clamp_(min=-1.0, max=1.0)
Gradienten-Clipping ist eine gängige Technik zum Trainieren tiefer neuronaler Netzwerke (insbesondere RNN, LSTM usw.) und kann Trainingsabstürze, die durch Gradientenexplosion verursacht werden, effektiv verhindern.
Gradientenakkumulation
Wenn der Grafikspeicher nicht ausreicht, kann die Gradientenakkumulation verwendet werden, um den Trainingseffekt einer großen Batchgröße zu simulieren.
Beispiel
# Tatsächliche batch_size = batch_size * accumulation_steps
accumulation_steps = 4 # 4 kleine Batches akkumulieren
optimizer.zero_grad()
for i, (inputs, labels) in enumerate(train_loader):
outputs = model(inputs)
loss = criterion(outputs, labels)
# Den Verlust durch die Akkumulationsschritte teilen, um eine Mittelung zu erreichen
loss = loss / accumulation_steps
loss.backward()
# Parameter nach der angegebenen Anzahl von Akkumulationsschritten einmal aktualisieren
if (i + 1) % accumulation_steps == 0:
nn.utils.clip_grad_norm_(model.parameters(), max_norm=1.0)
optimizer.step()
optimizer.zero_grad()
# Die verbleibenden Gradienten verarbeiten
if (i + 1) % accumulation_steps != 0:
optimizer.step()
optimizer.zero_grad()
Vollständiges Trainingsbeispiel
Das Folgende ist eine vollständige Trainingspipeline, die Best Practices für Optimierer demonstriert.
Beispiel
import torch.nn as nn
import torch.optim as optim
from torch.optim.lr_scheduler import CosineAnnealingLR
# Konfiguration
DEVICE = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
EPOCHS = 100
BATCH_SIZE = 32
LR = 1e-3
# Modell erstellen und auf Gerät verschieben
model = SimpleNet().to(DEVICE)
# Verlustfunktion und Optimierer
criterion = nn.CrossEntropyLoss()
optimizer = optim.AdamW(model.parameters(), lr=LR, weight_decay=0.01)
# Lernraten-Scheduler (Cosinus-Annealing)
scheduler = CosineAnnealingLR(optimizer, T_max=EPOCHS, eta_min=1e-6)
# Trainingsschleife
best_acc = 0.0
for epoch in range(EPOCHS):
model.train()
total_loss = 0.0
correct = 0
for inputs, labels in train_loader:
inputs = inputs.to(DEVICE)
labels = labels.to(DEVICE)
# Gradienten zurücksetzen (empfohlen: set_to_none=True)
optimizer.zero_grad(set_to_none=True)
# Vorwärtsdurchlauf
outputs = model(inputs)
loss = criterion(outputs, labels)
# Rückwärtsdurchlauf
loss.backward()
# Gradientenclipping (Gradientenexplosion verhindern)
nn.utils.clip_grad_norm_(model.parameters(), max_norm=1.0)
# Parameter aktualisieren
optimizer.step()
# Statistiken
total_loss += loss.item()
correct += (outputs.argmax(1) == labels).sum().item()
# Lernrate aktualisieren
scheduler.step()
# Trainingsinformationen ausgeben
avg_loss = total_loss / len(train_loader)
accuracy = correct / len(train_loader.dataset)
current_lr = scheduler.get_last_lr()[0]
print(f"Epoche {epoch+1}/{EPOCHS} | Verlust: {avg_loss:.4f} | "
f"Genauigkeit: {accuracy:.4f} | Lernrate: {current_lr:.6f}")
# Bestes Modell speichern
if accuracy > best_acc:
best_acc = accuracy
torch.save({
'epoch': epoch,
'model_state_dict': model.state_dict(),
'optimizer_state_dict': optimizer.state_dict(),
'scheduler_state_dict': scheduler.state_dict(),
'best_acc': best_acc,
}, 'best_model.pth')
print(f"Training abgeschlossen, beste Genauigkeit: {best_acc:.4f}")
Leitfaden zur Optimierer-Auswahl
Die Wahl des richtigen Optimierers muss anhand der konkreten Aufgabe, der Datenmerkmale und der Trainingsphase erfolgen.
Auswahl nach Aufgabe
Verschiedene Aufgabentypen haben unterschiedliche Optimierer-Empfehlungen.
| Aufgabentyp | Empfohlener Optimierer | Empfohlene Lernrate | Hinweise |
|---|---|---|---|
| Bildklassifizierung (CNN) | SGD + Momentum | 0.01 ~ 0.1 | Langsame Konvergenz, aber hohe Genauigkeit |
| Bildklassifizierung (CNN) | AdamW | 0.001 | Schnelle Konvergenz |
| NLP / Transformer | AdamW | 1e-5 ~ 1e-4 | Kleinere Lernrate |
| RNN / LSTM | RMSprop / Adam | 0.001 | Adaptive Lernrate |
| GAN | Adam (G) / Adam (D) | 0.0001 | Kleinere Lernrate |
| Bestärkendes Lernen | Adam / RMSprop | 0.0001 ~ 0.001 | Hängt von der jeweiligen Aufgabe ab |
| Schnelle Experimentierung | Adam / AdamW | 0.001 | Schnelle Konvergenz |
Leistungsvergleich
| Optimierer | Konvergenzgeschwindigkeit | Speichernutzung | Hyperparameter-Empfindlichkeit | Endgültige Genauigkeit |
|---|---|---|---|---|
| SGD + Momentum | Langsam | Niedrig | Hoch | Hoch |
| Adam | Schnell | Mittel | Niedrig | Mittel |
| AdamW | Schnell | Mittel | Niedrig | Hoch |
| RMSprop | Mittel | Mittel | Mittel | Mittel |
| Adagrad | Mittel | Hoch | Mittel | Niedrig |
Häufige Probleme und Lösungen
- Instabiles Training (Loss-Oszillation): Lernrate reduzieren, Gradientenclipping hinzufügen
- Konvergenz zu langsam: Adam oder AdamW verwenden, Lernrate erhöhen
- Overfitting: weight_decay erhöhen, Regularisierung verwenden
- Unzureichender Videospeicher: batch_size reduzieren, Gradientenakkumulation verwenden
Die Wahl des Optimierers ist nicht absolut; es wird empfohlen, mit Adam oder AdamW zu beginnen und andere Optimierer in Betracht zu ziehen, wenn die Ergebnisse nicht zufriedenstellend sind. Für spezifische Aufgaben sind möglicherweise Experimente erforderlich, um die optimale Wahl zu bestimmen.
Für ausführlichere Informationen sieheoffizielle PyTorch-Dokumentation。
Weitere Erweiterungen