Multi-GPU-Training
Multi-GPU-Training in LibreYOLO verwendet PyTorch DistributedDataParallel: Ein Prozess pro GPU hält jeweils eine vollständige Modellreplik und einen Teil jedes Batches. Die Gradienten werden bei jedem Schritt über alle Ränge gemittelt.
Ausführung auf zwei GPUs
Übergib eine Geräteliste. Alles andere bleibt unverändert.
from libreyolo import LibreYOLO # Dieser Guard bleibt unterstützt; normale Skripte funktionieren auch ohne ihn.# Für Callbacks oder Logger mit Standard-Pickle-Fallback muss er bleiben.if __name__ == "__main__": model = LibreYOLO("LibreYOLO9s.pt") model.train( data="my-dataset.yaml", epochs=100, batch=32, # globaler Batch: 16 Bilder je GPU bei zwei GPUs device="0,1", )libreyolo train model=LibreYOLO9s.pt data=my-dataset.yaml \ epochs=100 batch=32 device=0,1Bei mehr als einem Gerät und ohne torchrun-Umgebung speichert train() des Modells die Gewichte in einer temporären Datei, bestimmt bei Bedarf Autobatch und startet vom Koordinator verwaltete Worker-Prozesse, einen pro GPU. Jeder Worker importiert die Modellklasse erneut, baut sie aus den gespeicherten Gewichten auf und verwendet den normalen Einzelgerätepfad, weil innerhalb eines gestarteten Workers die torchrun-Umgebungsvariablen gesetzt sind. Nach dem Lauf wird der beste Checkpoint von Rank 0 in die Modellinstanz des Aufrufers geladen.
device akzeptiert "0,1", [0, 1], 0, "cuda:0", "cpu", "mps"
und "auto". Nur eine Liste mit mehr als einem CUDA-Index startet mehrere
Prozesse.
libreyolo train device=0,1 oder device=[0,1] baut das Modell auf der ersten
aufgeführten GPU auf und übergibt die Liste an train(), das die Worker auf
dieselbe Weise startet.
Automatischer Start und Main-Guard
model.train(device=[0, 1]) und device="0,1" verwenden vom Koordinator verwaltete Ranks, ohne den Top-Level-Code eines gewöhnlichen ungeschützten Skripts erneut auszuführen. Skripte mit Main-Guard und explizites torchrun bleiben unterstützt. Koordinatorjobs verwenden cloudpickle; Callback- oder Logger-Objekte, die den Standard-pickle-Fallback benötigen, erfordern weiterhin einen Guard if __name__ == "__main__":.
batch als globale Batch-Größe
batch ist die Anzahl der Bilder pro Optimizer-Schritt über alle GPUs hinweg.
Der Dataloader jedes Rangs wird mit batch // world_size und einem
DistributedSampler erstellt. batch=32 auf zwei GPUs bedeutet daher 16
Bilder pro GPU und nicht 32.
Eine Batch-Größe, die nicht ohne Rest durch die Weltgröße teilbar ist, löst einen Fehler aus, statt unbemerkt mit einer anderen Größe zu trainieren:
batch=6 is the global batch and must be divisible by world_size=4: each ranktrains at batch // world_size, so this value would silently train at adifferent global batch than requested. Use batch=4 or batch=8.DDP mittelt die Gradienten selbst. Deshalb wird der Loss ohne Skalierung übergeben. Eine zusätzliche Multiplikation mit der Weltgröße würde die effektive Lernrate ungefähr um die Anzahl der GPUs erhöhen.
Autobatch unter DDP
batch=-1 funktioniert und gibt eine durch die Weltgröße teilbare globale
Batch-Größe zurück.
from libreyolo import LibreYOLO if __name__ == "__main__": model = LibreYOLO("LibreYOLO9s.pt") # Einmal auf GPU 0 testen und auf ein Vielfaches der Weltgröße skalieren. model.train(data="my-dataset.yaml", batch=-1, device="0,1")Beim Spawn-Pfad läuft die Messung im übergeordneten Prozess auf dem ersten Gerät, bevor ein Worker existiert. Jeder Worker erhält daher eine konkrete Ganzzahl und es ist keine Koordination zwischen Prozessen erforderlich. Unter torchrun misst Rang 0 und verteilt das Ergebnis als einzelnen Long-Tensor.
Die Messung ermittelt die Kapazität einer GPU und multipliziert sie mit der
Weltgröße. Wenn nbs gesetzt ist, wird der globale Batch auf nbs begrenzt
und auf ein Vielfaches der Weltgröße abgerundet. Beim Hinzufügen von GPUs sinkt
daher die Anzahl der Akkumulationsschritte, statt dass der Batch pro GPU
kleiner wird. Die Funktionsweise der Messung selbst wird unter
Hyperparameter beschrieben.
SyncBatchNorm
Unter DDP sehen die BatchNorm-Schichten jedes Rangs nur dessen eigenen Teil.
Bei batch // world_size kann dieser Teil so klein sein, dass die laufenden
Statistiken das konvergierte Modell gegenüber einem Single-GPU-Lauf
verschlechtern.
sync_bn=True wandelt jede BatchNorm in SyncBatchNorm um, sodass die
Statistiken über den globalen Batch berechnet werden. Die Umwandlung erfolgt
nur bei aktivem verteiltem Training. Ein Single-GPU-Lauf bleibt daher
unabhängig vom Flag unverändert.
Für die BatchNorm-lastigen Convolutional-Familien ist die Option bereits
standardmäßig aktiviert: YOLOX, YOLOv7, YOLOv9 und seine Varianten, YOLO-NAS,
PicoDet, RTMDet und FOMO. Bei allen anderen Familien ist sie standardmäßig
deaktiviert. Der Trainer warnt, wenn ein Modell BatchNorm enthält, sync_bn
deaktiviert ist und der Batch pro Rang unter 16 liegt.
from libreyolo import LibreYOLO if __name__ == "__main__": model = LibreYOLO("LibreRTDETRr18.pt") model.train( data="my-dataset.yaml", batch=32, device="0,1", sync_bn=True, )Für sync_bn gibt es kein CLI-Flag. Es ist ein Python-Argument.
Start mit torchrun
torchrun funktioniert ebenfalls und ist die richtige Wahl, wenn bereits ein Cluster-Scheduler den Prozessstart steuert. Schreibe das Skript für ein einzelnes Gerät und lasse torchrun die Rangumgebung festlegen.
from libreyolo import LibreYOLO if __name__ == "__main__": model = LibreYOLO("LibreYOLO9s.pt") model.train(data="my-dataset.yaml", epochs=100, batch=32)torchrun --nproc_per_node=2 train.pyKombiniere die beiden Verfahren nicht. Wenn die torchrun-Umgebung vorhanden
ist, startet device="0,1" keine Prozesse. Der Trainer verwendet
cuda:LOCAL_RANK, während torchrun die Prozessanzahl steuert.
Verhalten der Ränge
Rang 0 steuert jeden Seiteneffekt. Er ermittelt das Ausgabeverzeichnis und verteilt den aufgelösten Namen, damit alle Ränge übereinstimmen. Außerdem schreibt er Checkpoints und Artefakte und löst Nutzer-Callbacks sowie Logger aus. Die anderen Ränge trainieren und tragen Gradienten bei.
Jeder Rang initialisiert seinen Dataloader und den Zufallszahlengenerator der
Augmentierung anders. Die Werte werden aus dem konfigurierten seed abgeleitet,
damit die Ränge keine identischen Augmentierungen ziehen.
Plattform und Backend
Das Backend wird automatisch gewählt: NCCL, wenn sowohl CUDA als auch NCCL verfügbar sind, andernfalls Gloo. NCCL ist unter Windows nicht enthalten. Windows-Läufe verwenden daher ohne weitere Konfiguration Gloo. Die Prozessgruppe wird mit einem Timeout von drei Stunden initialisiert.
Nicht unter DDP ausgeführte Funktionen
- CUDA-Graph-Erfassung.
cuda_graph=Trueprotokolliert eine Zeile und trainiert im Eager-Modus. Siehe Trainingsperformance. - Der Trainings-Profiler.
profile=Truewird mit einer Warnung ignoriert.
Nicht jede Familie unterstützt den automatischen Spawn. 24 Familien tun dies und decken die trainierbaren Familien für Erkennung, Klassifikation, semantische Segmentierung und Restaurierung ab. Erhält eine Familie ohne diese Unterstützung mehrere GPUs, löst sie einen Fehler aus, der die Modell-API und den torchrun-Befehl nennt, statt unbemerkt nur auf einer GPU zu trainieren.
Verwandte Themen
- Unter Hyperparameter findest du Informationen
zu
batch,nbsund dem Fortsetzen eines Laufs. - Experiment-Logger beschreibt die Anforderung an die Pickle-Kompatibilität von Callbacks.
- Cloud-GPUs beschreibt das Mieten eines Multi-GPU-Rechners.