Optimierung des Deep-Learning-Trainings für maximale GPU-Auslastung
Eine der häufigsten Fragen neuer Data Scientists und ML-Ingenieure ist, ob ihre Deep-Learning-Trainingsprozesse optimal laufen. In diesem Leitfaden lernen Sie, wie Sie Deep-Learning-Leistungsprobleme diagnostizieren und beheben, unabhängig davon, ob Sie auf einem einzelnen Rechner oder mehreren Maschinen arbeiten. Ziel ist es, die effektive Nutzung der verfügbaren Cloud-GPUs zu maximieren.
Wir beginnen mit dem Verständnis der GPU-Auslastung und schließen mit der Diskussion über die optimale Batchgröße für maximale GPU-Auslastung.
Hinweis: Dieser Leitfaden setzt Grundkenntnisse des Linux-Betriebssystems und der Programmiersprache Python voraus. Die neuesten Linux-Distributionen werden standardmäßig mit Ubuntu geliefert, sodass Sie pip und conda installieren können, da wir diese hier verwenden werden.
Voraussetzungen
Um diesem Artikel folgen zu können, benötigen Sie Erfahrung mit Python-Code sowie grundlegende Kenntnisse im Bereich Deep Learning. Wir gehen davon aus, dass alle Leser Zugriff auf ausreichend leistungsstarke Maschinen haben, um den bereitgestellten Code auszuführen.
Was ist GPU-Auslastung?
Bei Deep-Learning-Trainingsprozessen ist die GPU-Auslastung der wichtigste Aspekt, den Sie überwachen sollten. Diese Informationen sind über bekannte Drittanbieter- und integrierte GPU-Überwachungstools verfügbar.
Die GPU-Auslastung wird definiert als die Geschwindigkeit, mit der eine oder mehrere GPU-Kerne in der letzten Sekunde gearbeitet haben. Dies entspricht der Nutzung einer GPU durch ein Deep-Learning-Programm.
Wann wissen Sie, dass Sie mehr GPU-Rechenleistung benötigen?
Betrachten wir ein praxisnahes Szenario.
Ein Data Scientist hat in der Regel zwei GPUs zur Verfügung – diese sollten für die meisten Aufgaben ausreichen. Während der Entwicklungsphase gibt es normalerweise keine Probleme, da kurze GPU-Zyklen benötigt werden und der Arbeitsablauf reibungslos verläuft. Doch sobald das Training beginnt, steigt der Bedarf an GPU-Rechenleistung, die nicht sofort verfügbar ist.
Das bedeutet, dass mehr Rechenressourcen erforderlich sind, um signifikante Arbeiten auszuführen. Folgende Aufgaben sind nahezu unmöglich, wenn der gesamte Arbeitsspeicher bereits belegt ist:
- Durchführung weiterer Experimente
- Multi-GPU-Training zur Beschleunigung des Trainings für größere Batchgrößen und höhere Modellgenauigkeit
- Arbeiten an einem neuen Modell, während ein anderes Modell unabhängig trainiert wird
Vorteile der GPU-Auslastung
Generell führen Verbesserungen in diesem Bereich zu einer Verdopplung der Hardware-Nutzung und einer 100%igen Steigerung der Trainingsgeschwindigkeit.
Eine hohe GPU-Auslastung ermöglicht eine effizientere Verwaltung von Ressourcen, reduziert GPU-Leerlaufzeiten und erhöht die Cluster-Auslastung.
Aus Sicht eines Deep-Learning-Spezialisten eröffnet eine höhere GPU-Nutzung mehr Möglichkeiten für Experimente, steigert die Produktivität und verbessert die Modellqualität.
Zusätzlich können IT-Administratoren verteilte Trainingsmodelle mit mehreren GPUs betreiben.
Die optimale Batchgröße für die GPU-Auslastung
Die Wahl der richtigen Batchgröße kann verwirrend sein, da es keine universelle „beste“ Batchgröße für ein bestimmtes Datenset oder eine Modellarchitektur gibt. Eine größere Batchgröße trainiert das Modell schneller und benötigt mehr Speicher, kann aber die Genauigkeit verringern.
Was ist eine Batchgröße?
Beim Training eines Deep-Learning-Modells ist es entscheidend, eine Batchgröße festzulegen. Einfach ausgedrückt gibt die Batchgröße an, wie viele Trainingsbeispiele gleichzeitig in einem Forward- und Backpropagation-Schritt verarbeitet werden.
Beispiel zur Veranschaulichung der Batchgröße
Angenommen, wir trainieren ein Modell zur Klassifizierung von Katzenrassen. Unsere Datenbank enthält 1.000 Katzenbilder.
Wenn wir eine Batchgröße von 10 wählen, bedeutet dies, dass das Modell 10 Bilder auf einmal verarbeitet, bevor es seine Gewichte aktualisiert. Statt alle 1.000 Bilder gleichzeitig zu verarbeiten, werden diese in kleinere, handhabbare Gruppen unterteilt.
Ohne Batching könnten wir jedes Bild einzeln durch das Modell schicken, was jedoch ineffizient wäre. Andererseits könnte das gleichzeitige Verarbeiten aller 1.000 Bilder den Arbeitsspeicher überlasten.
Warum sollte man Batches verwenden?
Wie bereits erwähnt, trägt eine größere Batchgröße dazu bei, ein Modell schneller durch jede Trainings-Epoche zu führen. Dies liegt daran, dass moderne GPUs in der Lage sind, mehrere Samples gleichzeitig zu verarbeiten, anstatt nur ein einzelnes Datum zu bearbeiten.
Jedoch kann eine zu große Batchgröße die Fähigkeit des Modells zur Generalisierung verringern, was zu Overfitting führen kann. Daher ist die richtige Wahl der Batchgröße entscheidend.
Die Batchgröße ist ein Hyperparameter, der basierend auf der Modellleistung im Training optimiert werden muss. Darüber hinaus sollte überwacht werden, wie effizient die GPU mit verschiedenen Batchgrößen genutzt wird.
Beispiel zur GPU-Auslastung und Batchgröße
Setzen wir die Batchgröße auf 100, könnte unser System möglicherweise nicht genügend Ressourcen haben, um alle 100 Bilder gleichzeitig zu verarbeiten. Falls die GPU an ihre Kapazitätsgrenze stößt, muss die Batchgröße reduziert werden.
Nun, da wir das Konzept der Batchgröße verstanden haben, werfen wir einen Blick darauf, wie wir die optimale Batchgröße mithilfe von PyTorch und Keras bestimmen können.
Die richtige Batchgröße mit PyTorch finden
In diesem Abschnitt zeigen wir, wie man die optimale Batchgröße für das Training eines ResNet18-Modells bestimmt. Zur Messung der Leistung und der GPU-Auslastung verwenden wir den PyTorch Profiler.
TensorBoard zur Überwachung der Leistung verwenden
Um eine detailliertere Analyse zu ermöglichen, integrieren wir den PyTorch Profiler mit TensorBoard, sodass wir die Leistungsmetriken während des Trainings visualisieren können.
So folgen Sie dieser Anleitung
Auf Ihrem Cloud-GPU-System können Sie das entsprechende Notebook mit wget
herunterladen und es anschließend mit Jupyter Lab öffnen, indem Sie die folgenden Befehle ausführen:
wget https://raw.githubusercontent.com/gradient-ai/batch-optimization-DL/refs/heads/main/notebook.ipynb
jupyter lab
Einrichtung und Vorbereitung von Daten und Modell
Installieren Sie zunächst die erforderlichen Abhängigkeiten für PyTorch, torchvision und den PyTorch Profiler:
pip3 install torch torchvision torch-tb-profiler
Das Dataset laden und das Modell trainieren
Der folgende Code lädt das CIFAR-10-Dataset und führt Transfer Learning mit einem vortrainierten ResNet18-Modell durch.
import torch
import torch.nn
import torch.optim
import torch.profiler
import torch.utils.data
import torchvision.datasets
import torchvision.models
import torchvision.transforms as T
# Vorbereitung der Eingabedaten und Transformationen
transform = T.Compose([
T.Resize(224),
T.ToTensor(),
T.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))
])
# CIFAR-10-Dataset laden
train_set = torchvision.datasets.CIFAR10(root='./data', train=True, download=True, transform=transform)
train_loader = torch.utils.data.DataLoader(train_set, batch_size=1, shuffle=True, num_workers=4)
# Modell, Verlustfunktion und Optimierer initialisieren
device = torch.device("cuda:0")
model = torchvision.models.resnet18(pretrained=True).cuda(device)
criterion = torch.nn.CrossEntropyLoss().cuda(device)
optimizer = torch.optim.SGD(model.parameters(), lr=0.001, momentum=0.9)
model.train()
# Trainingsfunktion definieren
def train(data):
inputs, labels = data[0].to(device), data[1].to(device)
outputs = model(inputs)
loss = criterion(outputs, labels)
optimizer.zero_grad()
loss.backward()
optimizer.step()
Profiling für Leistungsoptimierung aktivieren
Nachdem das Grundmodell eingerichtet ist, aktivieren wir optionale Funktionen im Profiler, um während des Trainings weitere Informationen zu erfassen.
Die folgenden Parameter werden verwendet:
schedule
– Nimmt einen einzelnenstep(int)
-Wert und gibt die jeweilige Profiler-Aktion zurück.profile_memory
– Aktiviert die Zuweisung von GPU-Speicher. Die Aktivierung kann zusätzliche Zeit in Anspruch nehmen.with_stack
– Zeichnet Quellinformationen für alle Abläufe auf.
Profiler-Code
with torch.profiler.profile(
schedule=torch.profiler.schedule(wait=1, warmup=1, active=3, repeat=2),
on_trace_ready=torch.profiler.tensorboard_trace_handler('./log/resnet18_batchsize1'),
record_shapes=True,
profile_memory=True,
with_stack=True
) as prof:
for step, batch_data in enumerate(train_loader):
if step >= (1 + 1 + 3) * 2:
break
train(batch_data)
prof.step() # Profiler über Schrittgrenzen informieren
Die richtige Batchgröße mit Keras finden
Wir verwenden in diesem Fall ein beliebiges Sequential-Modell.
Das Modell definieren
Unten sehen Sie ein Beispiel für ein einfaches Sequential-Modell in Keras:
model = Sequential([
Dense(units=16, input_shape=(1,), activation='relu'),
Dense(units=32, activation='relu', kernel_regularizer=regularizers.l2(0.01)),
Dense(units=2, activation='sigmoid')
])
Das Modell mit einer definierten Batchgröße trainieren
Der Parameter batch_size
bestimmt, wie viele Samples auf einmal verarbeitet werden, bevor die Gewichte des Modells aktualisiert werden.
Im folgenden Code setzen wir batch_size=10, d. h. 10 Samples werden in einem einzelnen Schritt verarbeitet.
model.fit(
x=scaled_train_samples,
y=train_labels,
validation_data=valid_set,
batch_size=10,
epochs=20,
shuffle=True,
verbose=2
)
Warum werden Batches verwendet?
Eine größere Batchgröße ermöglicht es einem Modell, jedes Epoch schneller abzuschließen, da mehrere Datenpunkte gleichzeitig verarbeitet werden. Dies hat jedoch auch Nachteile:
- Speichernutzung: Größere Batches erfordern mehr GPU-Speicher.
- Modellgenauigkeit: Zu große Batches können die Genauigkeit und Generalisierung verschlechtern.
- GPU-Auslastung: Eine ordnungsgemäße Batch-Optimierung gewährleistet eine ausgewogene GPU-Nutzung.
Beispielsweise kann eine Batchgröße von 100 die GPU-Kapazität überschreiten, sodass eine Reduzierung erforderlich ist.
Wichtige Punkte beim Batch-Training
1. Geschwindigkeit und Speicher
Größere Batchgrößen erhöhen normalerweise die Geschwindigkeit. Kleine Batches verursachen jedoch mehr Overhead durch häufige Gewichtsanpassungen. Große Batchgrößen erfordern mehr GPU-Speicher, was zu Speicherüberlauf-Fehlern führen kann.
2. Modellkonvergenz
Die Batchgröße beeinflusst die Generalisierung des Modells. Bei der Verwendung von Stochastic Gradient Descent (SGD) oder dessen Varianten können große Batches zu schlechterer Generalisierung führen. Übliche Batchgrößen in Computer Vision liegen zwischen 32 und 512 Bildern.
3. Potenzielle GPU-Probleme
Während des Multi-GPU-Trainings kann eine falsche Batch-Größe zu Problemen führen:
- Wenn die Datensatzgröße nicht durch die Batch-Größe teilbar ist, kann die letzte Batch weniger Samples enthalten.
- Bestimmte Layer, wie z. B. die Batch-Normalisierung, können fehlschlagen, wenn sie mit inkonsistenten Batch-Größen arbeiten, was zu NaN-Werten führt.
Um dies zu vermeiden, empfehlen wir, die Batch-Größe für alle GPUs festzulegen und konsistent zu halten. Falls eine Batch nicht der erwarteten Größe entspricht, kann sie entweder verworfen oder mit wiederholten Samples aufgefüllt werden.
Beschädigung der GPUs
Während des Multi-GPU-Trainings kann es passieren, dass die letzte Batch eines Epochenlaufs weniger Samples als erwartet enthält. Falls dies geschieht:
- Erhalten einige GPUs möglicherweise keine Daten.
- Können Batch-Normalisierungsschichten fehlschlagen und NaN-Werte erzeugen.
- Scheint das Training normal zu verlaufen, kann jedoch zu beschädigten Modellgewichten führen.
Um dies zu verhindern:
- Stellen Sie sicher, dass die Batch-Größen festgelegt sind.
- Verwerfen Sie unvollständige Batches oder füllen Sie sie auf die erforderliche Größe auf.
- Verwenden Sie eine Batch-Größe, die größer ist als die Gesamtanzahl der GPUs.
Fazit
In diesem Artikel haben wir verschiedene Methoden zur Maximierung der GPU-Auslastung durch Bestimmung der optimalen Batchgröße untersucht. Die richtige Wahl der Batchgröße verbessert die Trainingseffizienz, Speicherauslastung und Modellleistung.
Solange Sie eine angemessene Batchgröße (ab 16) wählen und dieselbe Anzahl an Iterationen und Epochen beibehalten, wird sich die Batchgröße kaum auf die endgültige Leistung auswirken. Allerdings beeinflusst sie die Trainingsdauer.
Für das Multi-GPU-Training wird empfohlen, die kleinste mögliche Batchgröße pro GPU zu verwenden, um die Kapazität jeder GPU voll auszuschöpfen. Ein guter Ausgangspunkt ist 16 Samples pro GPU, um eine Balance zwischen Geschwindigkeit und Performance zu gewährleisten.