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 einzelnen step(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.

Kostenlosen Account erstellen

Registrieren Sie sich jetzt und erhalten Sie Zugang zu unseren Cloud Produkten.

Das könnte Sie auch interessieren: