Einleitung
Die Schulung eines Machine Learning Modells und die Beobachtung des Rückgangs des Verlusts vermittelt ein Gefühl des Fortschritts, bis die Validierungsgenauigkeit ein Plateau erreicht oder der Verlust zu steigen beginnt, ohne dass klar ist, was die Ursache dafür ist. An diesem Punkt fügen die meisten Analysten zusätzliche Protokollierungen hinzu oder beginnen, Hyperparameter zu optimieren, in der Hoffnung, dass sich etwas ändert. Was viele Analysten in dieser Phase jedoch auslassen, ist die tatsächliche Einsicht in das, was während des Trainings im Inneren des Modells geschieht. Visuelle Debugging-Tools können in dieser Phase nützliche Einblicke bieten.
In diesem Artikel werden drei Themen behandelt: Was während des Trainings visualisiert werden sollte (Gradienten, Verluste und Einbettungen), die Tools, die diese Visualisierungen bereitstellen (TensorBoard und seine Hauptalternativen), sowie die Methoden zur direkten Erfassung von Modellberechnungen mithilfe von Hooks und Haltepunkten. Besonders hilfreich sind hierbei wichtige Skills und Fallstricke für Einsteiger in die Datenwissenschaft.
Visualisierung von Gradienten, Verlusten und Einbettungen
Verlustkurven
Bei der Schulung eines Modells ist die Verlustkurve in der Regel das erste, was überprüft wird. Wenn sowohl der Trainingsverlust als auch der Validierungsverlust sinken und nahe beieinander bleiben, deutet dies darauf hin, dass das Training gut voranschreitet. Wenn der Validierungsverlust zu steigen beginnt, während der Trainingsverlust weiter fällt, überanpasst das Modell. Wenn beide Kurven frühzeitig ein Plateau erreichen, lernt das Modell nicht, was typischerweise auf ein Problem mit den Daten oder der Lernrate hinweist.
Darüber hinaus ist der Gradientfluss ebenfalls wichtig. Das Problem des verschwindenden Gradienten kann in der Praxis auftreten, wenn die Verlustkurven zwar gleichmäßig, aber zu langsam sinken, was darauf hindeutet, dass die Gradienten zu klein sind, wenn sie die frühen Schichten erreichen.
Die nachstehende Grafik simuliert ein typisches Überanpassungsmuster. Beide Verluste sinken in den ersten zehn Epochen zusammen, und dann beginnt der Validierungsverlust zu steigen, während der Trainingsverlust weiter fällt.
Die rote gestrichelte Linie markiert den Punkt, an dem die Divergenz beginnt: In einem echten Lauf ist das der Punkt, an dem man mit der Untersuchung von Regularisierung oder frühem Stoppen beginnen sollte.
Rohgradienten
Die Grafik zeigt die durchschnittlichen Gradienten für jede Schicht nach einem Rückwärtsdurchlauf. Die Ausgabe ist wie folgt:
- Schicht 4 (Linear): 0.031250
- Schicht 3 (Tanh): 0.004646
- Schicht 2 (Linear): 0.004241
- Schicht 1 (Tanh): 0.002126
- Schicht 0 (Linear): 0.001631
Die Grafik liest sich von rechts nach links: Schicht 4 stellt die Ausgabeschicht dar, und Schicht 0 ist die erste. Die Ausgabeschicht erhält einen Gradienten von 0.031, aber bis sie Schicht 0 erreicht, ist dieser Wert auf 0.0016 gefallen – etwa 20 Mal kleiner.
Die rote Balkenanzeige, die auf jeder der ersten drei Schichten erscheint, zeigt an, dass die Gradienten bereits im Risikobereich sind, bevor sie jemals den Anfang des Netzwerks erreichen. In einem echten Trainingslauf bei einem tieferen Modell würden diese anfänglichen Schichten ihre Gewichte so langsam anpassen, dass sie kaum etwas lernen würden.
Dies ist ein praktisches Beispiel für das Problem des verschwindenden Gradienten: Die frühen Schichten lernen stillschweigend zu wenig, was ohne diese Art von Grafik nicht sichtbar ist.
Gradientenvisualisierung
Das Plotten der Gradientenmagnituden schichtweise während des Trainings gibt einen direkten Einblick, ob die Gradienten die frühen Teile des Netzwerks mit erheblichen Werten erreichen. In tiefen Modellen können Gradienten verschwinden, während sie durch die Schichten zurückfließen. Die Histogramme der Gradientenwerte für jede Schicht, die während des Trainings aufgezeichnet werden, können dieses Muster aufdecken und uns helfen, das Problem frühzeitig zu identifizieren.
Die Funktion register_backward_hook von PyTorch ermöglicht es uns, Gradienten-Tensoren aus jeder Schicht zu erhalten, ohne die Trainingsschleife zu ändern. Wir verbinden einen Hook mit einem Modul, der während jedes Rückwärtsdurchlaufs aktiviert wird und die Gradienten-Tensoren an einen bestimmten Callback sendet.
Das Histogramm zeigt die vollständige Verteilung der Gradientenwerte für jede Schicht nach einem Rückwärtsdurchlauf. Jedes Unterdiagramm stellt eine einzelne Schicht dar, geordnet von der Anfangsschicht bis zur letzten.
Was wir in einem gesunden Netzwerk suchen, sind Histogramme über die Schichten mit ungefähr ähnlichen Verteilungen.
Wenn die frühen Schichten eine sehr enge, spitzenartige Verteilung aufweisen, die eng um Null zentriert ist, könnte dies ein Warnsignal sein, das auf verschwindende Gradienten hinweist.
Die Gradienten existieren zwar noch, sind aber so klein, dass sie fast keine Lerninformationen tragen. Diese Visualisierung kann uns helfen, dieses Muster nach den ersten paar Batches zu erkennen, anstatt nach einem vollständigen Trainingslauf.
Einbettungen
Wenn ein Modell Eingaben in eine erlernte Darstellung abbildet, zeigt die Visualisierung dieser Darstellung, ob das Modell die Daten wie erwartet trennt. Der gebräuchlichste Ansatz besteht darin, die Einbettungen aus einem trainierten (oder teilweise trainierten) Modell zu entnehmen, ihre Dimensionalität mithilfe von t-SNE oder UMAP zu reduzieren und sie mit Klassenlabels als Farben zu plotten.
Wenn die Klassen eng und gut getrennt sind, bedeutet das, dass das Modell nützliche Trennungen gelernt hat. Überlappende Klassen bedeuten, dass das Modell die Konzepte noch nicht getrennt hat. Dieser Schritt ist nützlich, um Modelle, die auf Text oder Bildern trainiert wurden, zu debuggen, bevor die endgültige Klassifizierungsschicht hinzugefügt wird.
TensorBoard und seine Alternativen
TensorBoard
TensorBoard ist der Standardstartpunkt. Ursprünglich für TensorFlow entwickelt, funktioniert es auch mit PyTorch über torch.utils.tensorboard. Daten können über ein SummaryWriter-Objekt protokolliert werden, und die Ergebnisse können in einem Browser-Tab angezeigt werden. Es verarbeitet Skalare (Verlust, Genauigkeit), Histogramme (Gewichts- und Gradientenverteilungen), Bilder und einen Einbettungsprojektor zur Visualisierung hochdimensionaler Darstellungen.
Die Hauptbeschränkung besteht in seiner Lokalität. Um Ihre Ergebnisse mit einem Team zu teilen, müssen Sie einen gemeinsamen Speicher für Protokolldateien einrichten oder TensorBoard.dev verwenden, das Einschränkungen hinsichtlich des Supports hat.
Weights & Biases
Weights & Biases (W&B) ist das, was die meisten Machine Learning-Teams für die Zusammenarbeit oder detailliertere Nachverfolgung verwenden. Die Verwendung von effizienten Python-Skripten zur Automatisierung der explorativen Datenanalyse kann hierbei ebenfalls hilfreich sein.
Die Einrichtung erfolgt mit zwei Zeilen: wandb.init() zu Beginn eines Laufs und wandb.log() innerhalb der Trainingsschleife. Alles wird automatisch mit einem Cloud-Dashboard synchronisiert, und die Läufe werden nach Projekt gruppiert, was den Vergleich von Experimenten erleichtert.
Ein Beispielcode sieht wie folgt aus:
import wandb
wandb.init(project="my-model", config={"lr": 0.001, "epochs": 20, "batch_size": 32})
for epoch in range(wandb.config.epochs):
train_loss = 1 / (1 + 0.3 * epoch) # simuliert
val_loss = train_loss + max(0, 0.04 * (epoch - 10)) # simuliert
wandb.log({"epoch": epoch, "train_loss": train_loss, "val_loss": val_loss})
wandb.finish()
Nach Abschluss des Laufs können die protokollierten Metriken im W&B-Dashboard zusammen mit der Konfiguration, die sie erzeugt hat, angezeigt werden. Der Vergleich von zwei Läufen mit unterschiedlichen Parametern kann einfach durch Auswahl in der Benutzeroberfläche erfolgen, ohne dass eine manuelle Protokollanalyse erforderlich ist.
W&B unterstützt auch Hyperparameter-Sweeps mit integrierter Visualisierung, die zeigt, welche Hyperparameter den Ausgang am meisten beeinflusst haben.
Systemmetriken wie GPU-Auslastung und Speichernutzung werden ebenfalls automatisch protokolliert. Für Teams, die viele Experimente parallel durchführen, beseitigt der gemeinsame Arbeitsbereich einen Großteil des manuellen Aufwands zur Nachverfolgung dessen, was ausprobiert wurde.
Sacred
Sacred verfolgt einen anderen Ansatz. Es konzentriert sich auf Reproduzierbarkeit statt auf Visualisierung. Wir annotieren ein Trainingsskript mit dem Experiment-Dekorator von Sacred, der die gesamte Konfiguration, alle während der Laufzeit vorgenommenen Änderungen und alle protokollierten Metriken in einer Datenbank (in der Regel MongoDB) aufzeichnet. Auf diese Weise wird jeder Lauf und seine genauen Einstellungen zu einem dauerhaften Protokoll.
Für den Visualisierungsteil kombiniert Sacred sich mit Front-Ends wie Omniboard oder Sacredboard. Dies fügt im Vergleich zu TensorBoard oder W&B Komplexität hinzu, aber die Stärke liegt in der Prüfbarkeit: Jeder Lauf aus der Vergangenheit kann genau so reproduziert werden, wie er konfiguriert wurde.
Guild.ai
Guild.ai arbeitet über die Befehlszeile und erfordert keine Änderungen am Trainingscode. Wir führen ein Trainingsskript über Guild aus, indem wir guild run train.py verwenden, das alle Protokolle, die vom Skript erzeugt werden, zusammen mit allen Ausgabedateien aufzeichnet und sie mit diesem bestimmten Lauf verknüpft. Metriken und Laufvergleiche sind über die Befehlszeilenschnittstelle (CLI) von Guild oder die lokale Benutzeroberfläche verfügbar.
Dieses Framework ist eine gute Wahl, wenn mit bestehenden Skripten oder Drittanbieter-Code gearbeitet wird, den wir nicht ändern möchten. Es bietet weniger Funktionen als W&B, aber die Einrichtungskosten sind ebenfalls geringer.
Verwendung von Haltepunkten und Hooks für Machine Learning Berechnungen
Vorwärts- und Rückwärts-Hooks
Das Hook-System von PyTorch ermöglicht es uns, Berechnungen an jedem Punkt im Vorwärts- oder Rückwärtsdurchlauf eines Modells abzufangen. Die Funktion register_forward_hook verbindet einen Callback mit einer Schicht, der jedes Mal ausgelöst wird, wenn diese Schicht einen Batch verarbeitet. Der Callback erfasst die Eingangs- und Ausgangstensoren der Schicht, die wir dann protokollieren, auf NaN-Werte überprüfen oder plotten können.
Die Funktion register_backward_hook funktioniert für den Rückwärtsdurchlauf ähnlich und gibt uns Zugriff auf die Gradienten-Tensoren, die durch jede Schicht fließen. Zusammen decken diese beiden Hooks die meisten Aspekte ab, die wir während des Trainings inspizieren möchten, ohne die Modelldefinition oder die Trainingsschleife zu ändern.
Eine praktische Anwendung ist die Erkennung von NaN-Werten. Ein Vorwärts-Hook, der tensor.isnan().any() bei jedem Ausgang einer Schicht auswertet, erkennt numerische Instabilitäten sofort und verhindert, dass sie sich ausbreiten und den Rest des Trainings schädigen.
Hier ist ein minimales funktionierendes Beispiel, das ein dreischichtiges Modell mit einem Hook an jeder Schicht verwendet:
import torch
import torch.nn as nn
model = nn.Sequential(nn.Linear(8, 16), nn.ReLU(), nn.Linear(16, 4))
def nan_hook(layer, input, output):
if output.isnan().any():
print(f"[NaN detected] Layer: {layer.__class__.__name__}")
else:
print(f"[Clean] Layer: {layer.__class__.__name__}, output shape: {tuple(output.shape)}")
for layer in model:
layer.register_forward_hook(nan_hook)
print("--- Normal input ---")
model(torch.randn(2, 8))
print("\n--- Corrupted input ---")
bad_input = torch.randn(2, 8)
bad_input[0, 3] = float('nan')
model(bad_input)
Erwartete Ausgabe bei Ausführung:
--- Normal input --- [Clean] Layer: Linear, output shape: (2, 16) [Clean] Layer: ReLU, output shape: (2, 16) [Clean] Layer: Linear, output shape: (2, 4) --- Corrupted input --- [NaN detected] Layer: Linear [NaN detected] Layer: ReLU [NaN detected] Layer: Linear
In diesem Beispiel überprüft der Hook den Ausgangstensor nach jedem Layer und berichtet, ob er sauber oder beschädigt ist.
Die Ausführung erfolgt zweimal – einmal mit normalem Input und einmal mit einem einzelnen NaN, der injiziert wurde – und demonstriert, wie Instabilität schichtweise durch das Netzwerk propagiert.
Debugger-Haltepunkte
Standard-Python-Debugger funktionieren gut innerhalb von Trainingsschleifen.
Das Einfügen von import pdb; pdb.set_trace() an beliebiger Stelle pausiert die Ausführung und öffnet ein interaktives Prompt, das es uns ermöglicht, Tensorformen zu überprüfen, sicherzustellen, dass die Datenvorverarbeitung keine unerwarteten Werte erzeugt hat, und manuell durch den Vorwärtsdurchlauf zu schrittweise.
Die meisten Entwicklungsumgebungen für Machine Learning – sowohl VSCode als auch PyCharm – ermöglichen es uns, Haltepunkte grafisch zu setzen und Tensoren in einem speziellen Bereich zu inspizieren, was eine schnellere Alternative zur terminalbasierten pdb-Oberfläche bietet.
Haltepunkte sind jedoch besonders wertvoll während der ersten ein oder zwei Batches, da wir bestätigen, dass die Daten, das Modell und die Verlustfunktion ordnungsgemäß funktionieren, bevor wir einen vollständigen Trainingslauf starten.
Fazit
Ein Modell zu trainieren, ohne zu visualisieren, was im Inneren geschieht, bedeutet, Symptome zu interpretieren, anstatt die tatsächlichen Ursachen zu erkennen.
Wenn ein Modell trainiert wird, sei es, dass die Verlustkurve frühzeitig ein Plateau erreicht, Gradienten verschwinden oder Einbettungen sich nicht trennen, ohne die richtige Instrumentierung kündigt keines dieser Faktoren sich klar an.
Die in diesem Artikel behandelten Tools arbeiten auf unterschiedlichen Ebenen. Verlustkurven und Gradientenhistogramme bieten kontinuierliches Feedback während des Trainings und erkennen Probleme wie Überanpassung oder verschwindende Gradienten, bevor sie sich verstärken und das Framework brechen.
Einbettungsvisualisierungen zeigen, ob das Modell eine gute Trennung von den Daten lernt. TensorBoard, W&B, Sacred und Guild.ai behandeln die Protokollierung und Nachverfolgung unterschiedlich, dienen jedoch alle demselben Zweck: die Experimenthistorie durchsuchbar und vergleichbar zu machen, anstatt verstreut zu sein. Schließlich gehen Hooks und Debugger einen Schritt weiter und ermöglichen es, die tatsächlichen Tensoren, die durch das Netzwerk fließen, an jeder Schicht zu pausieren und zu inspizieren.
Dennoch können diese Tools ein defektes Modell nicht von sich aus reparieren. Was sie tun, ist, die Distanz zwischen einem Fehler und dem Verständnis, warum er aufgetreten ist, zu verkürzen – was in der Regel den Großteil der Arbeit ausmacht.
Nate Rosidi ist Datenwissenschaftler und in der Produktstrategie tätig. Er ist auch Dozent für Analytik und Gründer von StrataScratch, einer Plattform, die Datenwissenschaftlern hilft, sich auf ihre Interviews mit echten Interviewfragen von Top-Unternehmen vorzubereiten. Nate schreibt über die neuesten Trends auf dem Arbeitsmarkt, gibt Interviewtipps, teilt Projekte zur Datenwissenschaft und behandelt alles rund um SQL.
„`
Quellen: kdnuggets
Bildquelle: KI generiert