Seit seiner Veröffentlichung im Jahr 2016 hat sich PyTorch zum beliebtesten Deep-Learning-Frameworks entwickelt. Es wird für eine Vielzahl von Anwendungen - von der Bild- und Spracherkennung, Large-Language-Models (LLMs) und Reinforcement Learning eingesetzt.
Dieser Artikel zielt darauf ab, die erzielten Leistungsverbesserungen von PyTorch auf verschieden GPU Modellen über die Zeit zu messen und zu dokumentieren. Hierfür verwenden wir als Benchmark die GPU-Trainingsleistung der Modelle BERT und ResNet-50.
Für einen schnellen Einstieg werden im folgenden die verwendeten Modelle und wichtigen Begriffen kurz erklärt:
BERT
Für unsere Benchmarks haben wir die BERT Variante „BERT large cased“. BERT large besteht aus 24 Schichten, 1024 Hidden-Dimensions, 16 Attention-Heads, insgesamt 335 Millionen Parametern. Cased bedeuted, dass im Input-Layer die Groß- / Kleinschreibung von Wörtern beachtet wird.
BERT steht für Bidirectional Encoder Representations from Transformers und ist ein 2018 von Google entwickeltes Deep-Learning-Modell für die Verarbeitung natürlicher Sprache. Es nutzt die Transformer-Architektur, um eine kontextsensitive Darstellung von Wörtern in einem Text zu lernen. BERT wurde an einer großen Menge unbeschriebenem (unlabeled) Text trainiert, um ein allgemeines Verständnis der natürlichen Sprache zu erlangen. Durch dieses Training kann BERT kontextspezifische Bedeutungen von Wörtern verstehen und mehrdeutige Ausdrücke unterscheiden. Das Besondere an BERT ist seine bidirektionale Modellierung. Im Gegensatz zu früheren Sprachmodellen, die nur die vorangehenden Wörter als Kontext betrachteten, modelliert BERT den Kontext bidirektional. Das bedeutet, dass BERT sowohl die vorangehenden als auch die nachfolgenden Wörter im Text verwendet, um die Bedeutung eines bestimmten Wortes zu verstehen.
ResNet-50
Für unsere Benchmarks verwendete wir das ResNet-50 Modell in Version 1.5. Resnet-50 besteht aus 48 Faltungsschichten sowie einer MaxPool- und einer Average-Pool-Schicht, also insgesamt 48+1+1=50 Schichten mit insgesamt 25 Millionen Parametern.
Da es in vielen Benchmarks verwendet wird, steht eine nahezu optimale Implementierung zur Verfügung, die die Leistung einer GPU ausreizt und es ermöglicht, die Leistungsgrenzen der Hardware aufzuzeigen.
ResNet (Residual Neural Network) gilt als eines der ersten echten Deep-Learning-Netzwerke und wurde erstmals 2015 zur Bildklassifizierung eingeführt. Es löste das Problem des verschwindenden/explodierenden Gradienten, das in zuvor verwendeten Perzeptron-Netzwerkstrukturen auftrat, wenn die Anzahl der Zwischenschichten erhöht wurde (siehe Deep Residual Learning for Image Recognition). Das charakteristische Merkmal von residualen Netzwerken ist die Verwendung von "Sprungverbindungen" ("skip connections") zwischen verschiedenen Schichten, wodurch einzelne Schichten übersprungen werden können. Dies ermöglicht die Bildung viel tieferer Netzwerke und löst das oben erwähnte Problem verschwindender/explodierender Gradienten.
Stapelgröße bzw. Batch Size ('bs')
Einer der wichtigsten Metaparameter im Deep-Learning-Training ist die Batchgröße. Sie bezieht sich auf die Anzahl der Stichproben (samples) aus dem Datensatz, die jeweils in einer Trainingsiteration verarbeitet werden. Der Trainingsdatensatz wird in Stapel bzw. "Batches" unterteilt, die nacheinander durch das System propagiert werden, bis der gesamte Datensatz verarbeitet wurde, wodurch eine Epoche abgeschlossen wird. Bei kleinen Datensätzen, die vollständig in den GPU-Speicher passen, kann die Stapelgröße auch den gesamten Datensatz umfassen, was zu nur einem Durchlauf pro Epoche führt. Dies ist jedoch typischerweise nicht der Fall, weshalb es sinnvoll ist, den Datensatz in kleinere Batches aufzuteilen. In der Literatur wird Batch oft als Mini-Batch bezeichnet, um diesen vom gesamten Datensatz zu unterscheiden. Da die Modellgewichtungen basierend auf den Erkenntnissen aus dem aktuellen Stapel (batch) nach jeder Iteration aktualisiert werden, wirkt sich die Wahl der Stapelgröße auch auf die Trainingsergebnisse und die Systemleistung, also die Performance aus.
In unseren Benchmark-Ergebnissen ist die für die jeweilige GPU verwendete Batchgröße mit „bs“ gekennzeichnet.
Numerische Genauigkeit: fp32/AMP
Die numerische Genauigkeit (numerical precision), mit der die Gewichtungen und zugehörigen Werte in Deep-Learning-Modellen berechnet werden, spielt eine wichtige Rolle im Trainingsprozess. Eine höhere Genauigkeit ermöglicht feinere Gewichtseinstellungen, erfordert aber auch mehr Speicher und verlangsamt die Berechnung. In unseren Benchmarks untersuchen wir die Leistung von "fp32"-Datentypen und Berechnungen, die die "Automatic Mixed Precision"-Technik verwenden.
Der Datentyp „fp32“ (floating point 32-bit) ist der am weitesten verbreitete Standard im Deep Learning. Er verwendet eine 32-Bit-Kodierung, bestehend aus 1 Bit für das Vorzeichen, 8 Bit für den Exponenten und 23 Bit für die Mantisse.
Automatic Mixed Precision (AMP) ist eine Technik, die in der Deep-Learning-Community immer beliebter wird. Sie beinhaltet die Verwendung unterschiedlicher numerischer Genauigkeiten (z. B. fp8, fp16, fp32 und fp64) während des Trainingsprozesses, um die Effizienz und Genauigkeit von Deep-Learning-Modellen zu verbessern. Die Idee hinter AMP ist, dass einige Teile des Modells empfindlicher auf numerische Genauigkeit reagieren als andere. Durch die Verwendung einer höheren Genauigkeit dort, wo es notwendig ist, und einer geringeren Genauigkeit, wo es weniger wichtig ist, können Berechnungen insgesamt schneller und effizienter durchgeführt werden, ohne die Genauigkeit des Modells zu beeinträchtigen. Die Implementierung von Automatic Mixed Precision kann jedoch komplex sein und erfordert häufig spezielle Hardwareunterstützung.
Der PyTorch Compile Modus
Mit der Veröffentlichung von PyTorch 2.0 im März 2023 wurde zur Leistungssteigerung von PyTorch eine Reihe bedeutender Änderungen eingeführt eine davon ist Torch.compile
welches als zusätzlicher Ausführungsmodus für PyTorch 2 verwendet werden kann. Diese Funktion Torch.compile umschließt ("wrapped") ein Modell und liefert eine auf die GPU kompilierte Version des Modells zurück. Das kompilierte Modell kann dann mit einer erheblichen Leistungssteigerung auf der GPU berechnet werden. Das PyTorch 2 Compile-Feature kann in den meisten Fällen durch Hinzufügen einer einzigen Codezeile aktiviert werden:
model = torch.compile(model)
MultiGPU-Training
Um die Kapazität aller am Multi-GPU-Training beteiligten GPUs voll auszunutzen, wurde das DistributedDataParallel-Modul von PyTorch mit einem Sub-Prozess pro GPU verwendet, was zu einer deutlich besseren Leistung führte, als bei Verwendung von DataParallel, bei dem alle Berechnungen im selben Prozess stattfinden.
Testumgebung
Die Benchmarks wurden mit dem AIME Benchmark-Tool durchgeführt, das von GitHub (pytorch-benchmark) heruntergeladen werden kann. Folgende PyTorch-Versionen wurden für die Benchmarks mit NVIDIA-GPUs verwendet:
- PyTorch 2.0.0 mit CUDA 11.8.89 und Python 3.8.10
- PyTorch 2.5.1 mit CUDA 12.1.105 und Python 3.10.12
Die AMD GPUs wurden mit folgenden Versionen getestet:
- PyTorch 2.0.0 mit ROCM 5.4.2 und Python 3.8.10
- PyTorch 2.5.1 mit ROCM 6.2 und Python 3.10.12
Je nach GPU-Typ kamen zwei unterschiedliche AIME-Systeme zum Einsatz, da einige GPUs nur für Workstations geeignet sind, während andere, insbesondere solche mit passiver Kühlung, nur in Servern zum Einsatz kommen sollten.
Die folgenden GPUs wurden mit der AIME Workstation G500 getestet:
- NVIDIA RTX 6000 Ada
- NVIDIA RTX 5000 Ada
- NVIDIA RTX 4500 Ada
- NVIDIA Geforce RTX 4090
- NVIDIA Geforce RTX 4060 TI
- NVIDIA Geforce RTX 3090
- NVIDIA Geforce RTX 2080 TI
- NVIDIA RTX A6000
- NVIDIA RTX A5000
Mit dem AIME Server A4004 wurden diese GPUs getestet:
- NVIDIA H200 NVL 141GB
- NVIDIA H100 NVL 94GB
- NVIDIA H100 80GB
- NVIDIA A100 80GB
- NVIDIA A100 40GB
- AMD Instinct MI100
- NVIDIA Tesla V100
Benchmark-Ergebnisse
Die folgenden Balkendiagramme zeigen für jede GPU die Trainingsleistung des jeweiligen Modells für verschiedene PyTorch-Versionen mit und ohne Kompilierung des Modells.
Bert Training mit fp32
BERT large cased, Datentyp fp32Bert Training mit Automatic Mixed Precision
BERT large cased, automatic mixed precisionResNet-50 Training mit fp32
ResNet-50, Datentyp fp32ResNet-50 Training mit Automatic Mixed Precision
ResNet-50, automatic mixed precisionEs ist deutlich erkennbar, dass die Trainingsleistung für beide Modelle auf allen GPUs signifikant verbessert, wenn eine neuere Version von PyTorch verwendet wird. Insbesondere die GPUs der Ada- und Hopper-Generation profitieren von der Verwendung von PyTorch 2.5.1 und dem Kompiliermodus. In einigen Fällen, zum Beispiel auf dem NVIDIA H200 und bei Verwendung des BERT-Modells, kann durch die Verwendung des Kompiliermodus eine Verbesserung von fast Faktor 4 erzielt werden.
Pytorch Multi-GPU Training
Als Nächstes untersuchen wir die Leistung für Multi-GPU-Training mit NVIDIA A100 40GB, NVIDIA A100 80GB, NVIDIA RTX 6000 Ada, NVIDIA RTX 4090 und NVIDIA RTX 5000 am Beispiel von ResNet-50 mit fp32-Präzision und BERT Base Cased mit AMP.
Um die best mögliche Performance zu erzielen, wurde das PyTorch Modul DistributedDataParallel
verwendet um das Multi-GPU Training zu implementieren.
Mit Resnet-50 liegt der Leistungsskalierungsfaktor zwischen 0,9 und 0,95, was bedeutet, dass jede zusätzliche GPU dem System zwischen 90 % und 95 % Einzel-GPU-Leistung hinzufügt. Ein ähnliches Verhalten wird beim BERT base cased Modell mit AMP beobachtet.
Schlussfolgerungen
Dank des Compile-Modus von PyTorch 2 kann die Trainingsleistung durch eine bessere Auslastung der GPU-Hardware deutlich erhöht werden.
Bei fast allen GPU-Modellen kann mit der PyTorch 2 AMP-Genauigkeit die erreichbare Leistung im Vergleich zu Float32 nahezu verdoppelt werden.
Mit einem Skalierungsfaktor von 90-95 Prozent pro GPU ist Multi-GPU-Training eine geeignete Möglichkeit mit Pytorch die Leistung eines Deep Learning Servers zu skalieren.
Das Aktualisieren Ihrer Anwendung auf die neueste PyTorch-Version lohnt sich! Ohne großen Aufwand erhalten Sie eine kostenlose Leistungssteigerung für alle aktuellen GPU-Modelle.