Dieser Artikel wurde von der Huawei Cloud Community „ Distributed Training of Large Model LLM “ geteilt, Autor: Hua Shanghua_Lancer.
Aufgrund des rasanten Wachstums der Menge an Sprachmodellparametern und erforderlichen Trainingsdaten können die begrenzten Ressourcen auf einer einzelnen Maschine die Anforderungen für das Training großer Sprachmodelle nicht mehr erfüllen. Es muss ein verteiltes Schulungssystem (Distributed Training) entwickelt werden, um das Problem des enormen Bedarfs an Rechen- und Speicherressourcen zu lösen.
In einer verteilten Trainingssystemumgebung ist es notwendig, eine Modelltrainingsaufgabe in mehrere Unteraufgaben aufzuteilen und die Unteraufgaben auf mehrere Computergeräte zu verteilen, um Ressourcenengpässe zu beheben. Aber wie können wir einen Cluster aus Zehntausenden Rechenbeschleunigungschips nutzen, um ein umfangreiches Sprachmodell mit Hunderten Milliarden oder sogar Billionen Modellparametern zu trainieren? Dies umfasst eine Reihe von Technologien wie Clusterarchitektur, Parallelstrategie, Modellarchitektur, Speicheroptimierung und Rechenoptimierung.
Ich werde die Grundkonzepte verteilter Systeme für maschinelles Lernen, die Architektur verteilter Trainingscluster und parallele Strategien für verteiltes Training im Detail vorstellen und DeepSpeed als Beispiel verwenden, um vorzustellen, wie große Sprachmodelle auf einem Cluster trainiert werden.
1. Überblick über verteilte Schulungen
Unter verteiltem Training versteht man die Zerlegung von Trainingsaufgaben für maschinelles Lernen oder Deep-Learning-Modelle in mehrere Teilaufgaben und deren paralleles Training auf mehreren Computergeräten. Abbildung 1 zeigt ein Beispiel für ein einzelnes Computergerät und mehrere Computergeräte. Das Computergerät kann hier eine Zentraleinheit (CPU), eine Grafikverarbeitungseinheit (GPU) oder eine Tensorverarbeitungseinheit (Tensor Processing Unit) sein. TPU) kann auch ein neuronaler Netzwerkprozessor (Neural Network Processing Unit, NPU) sein.
Da der Speicher möglicherweise nicht von mehreren Computergeräten innerhalb desselben Servers gemeinsam genutzt wird, unabhängig davon, ob sich diese Computergeräte in einem oder mehreren Servern befinden, fällt ihre Systemarchitektur in die Kategorie der verteilten Systeme. Eine Modelltrainingsaufgabe hat oft eine große Anzahl von Trainingsbeispielen als Eingabe, die mit einem Computergerät abgeschlossen werden können, oder die gesamte Modelltrainingsaufgabe kann in Teilaufgaben aufgeteilt und auf verschiedene Computergeräte verteilt werden, um eine parallele Berechnung zu erreichen.
Danach muss die Ausgabe jedes Computergeräts kombiniert werden, um schließlich das Berechnungsergebnis zu erhalten, das dem eines einzelnen Computergeräts entspricht. Da jedes Rechengerät nur für Teilaufgaben verantwortlich sein muss und mehrere Rechengeräte parallel arbeiten können, kann es die Gesamtberechnung schneller abschließen und letztendlich den gesamten Rechenprozess beschleunigen.
Abbildung 1 Beispiele für die Datenverarbeitung mit einem einzelnen Computergerät und mehreren Computergeräten
Einer der wichtigsten Gründe, warum Menschen verteilte Trainingssysteme entwerfen, ist, dass die Rechenleistung eines einzelnen Computergeräts nicht mehr ausreicht, um das Modelltraining zu unterstützen. Abbildung 2 zeigt den Rechenleistungsbedarf des maschinellen Lernmodells und die Rechenleistung, die ein einzelnes Computergerät im gleichen Zeitraum bereitstellen kann. Wie in der Abbildung gezeigt, entwickeln sich Modelle für maschinelles Lernen rasant: Von AlexNet im Jahr 2013 bis zum Palm-Modell mit 540 Milliarden Parametern im Jahr 2022 entwickeln sich Modelle für maschinelles Lernen alle 18 Monate 56-mal. Mit zunehmender Modellparameterskala steigen auch die Anforderungen an die Menge der Trainingsdaten exponentiell, was den Bedarf an Rechenleistung erhöht.
In den letzten Jahren war der Anstieg der CPU-Rechenleistung jedoch weitaus geringer als das Mooresche Gesetz. Obwohl Rechenbeschleunigungsgeräte (wie GPU, TPU usw.) eine große Menge an Rechenleistung für Modelle des maschinellen Lernens bereitstellen, ist ihre Wachstumsrate immer noch hat das Mooresche Gesetz der Verdoppelung alle 18 Monate nicht überschritten. Um der Entwicklung von Modellen für maschinelles Lernen gerecht zu werden, kann nur ein verteiltes Trainingssystem den wachsenden Anforderungen an die Rechenleistung des Modells gerecht werden.
Abbildung 2 Vergleich zwischen dem Wachstum der Parameter des maschinellen Lernmodells und dem Wachstum der Rechenleistung der Computerhardware
Das übergeordnete Ziel des verteilten Trainings besteht darin, die Gesamttrainingsgeschwindigkeit zu erhöhen und die Gesamtzeit des Modelltrainings zu verkürzen. Die Gesamttrainingsgeschwindigkeit lässt sich mit folgender Formel kurz abschätzen:
Gesamttrainingsgeschwindigkeit ∝ Rechengeschwindigkeit eines einzelnen Geräts × Gesamtzahl der Rechengeräte × Beschleunigungsverhältnis mehrerer Geräte
Unter diesen wird die Rechengeschwindigkeit eines einzelnen Geräts hauptsächlich durch die Rechengeschwindigkeit und die Daten-E/A-Funktionen eines einzelnen Rechenbeschleunigungschips bestimmt. Um die Trainingseffizienz eines einzelnen Geräts zu optimieren, gehören zu den wichtigsten technischen Mitteln gemischte Präzisionsschulungen und Bediener Fusion, Gradientenakkumulation usw. Je größer die Anzahl der Computergeräte in einem verteilten Trainingssystem ist, desto höher ist die theoretische Spitzenrechengeschwindigkeit. Abhängig von der Kommunikationseffizienz führt jedoch eine Zunahme der Anzahl der Computergeräte zu einem schnellen Anstieg Verringerung des Beschleunigungsverhältnisses; Das Beschleunigungsverhältnis mehrerer Geräte wird durch die Kombination von Algorithmen und Netzwerktopologie zur Optimierung bestimmt. Das Hauptziel der verteilten Trainings-Parallelstrategie besteht darin, das Beschleunigungsverhältnis mehrerer Geräte zu verbessern das verteilte Trainingssystem.
Die Menge der großen Parameter des Sprachmodells und die Menge der verwendeten Daten sind sehr groß, daher wird eine verteilte Trainingsarchitektur verwendet, um das Training abzuschließen. Dokument [5] stellt nur den Trainingsprozess von GPT-3 mit NVIDIA V100-GPUs vor. Dokument [31] stellt vor, dass OPT 992 NVIDIA A100 80G-GPUs verwendet und Fully Shared Data Parallelism [130] verwendet. Die gesamte Ausbildungszeit beträgt knapp 2 Monate.
Die Forscher des BLOOM-Modells[33] gaben weitere Details zur verwendeten Hardware und Systemarchitektur bekannt. Das Training des Modells dauerte insgesamt 3,5 Monate und nutzte 48 Rechenknoten. Jeder Knoten enthält 8 NVIDIA A100 80G-GPUs (insgesamt 384 GPUs) und verwendet 4*NVLink für die Kommunikation zwischen GPUs innerhalb des Knotens. Knoten kommunizieren miteinander über ein erweitertes 8-dimensionales Hypercube-Netzwerk mit globaler Topologie, das aus vier Omni-Path-100-Gbit/s-Netzwerkkarten besteht.
Die Literatur [37] gibt nicht die spezifische Konfiguration und Netzwerktopologie des im LLaMA-Modelltraining verwendeten Clusters an, sondern die gesamten GPU-Stunden für verschiedene Parameterskalen. Für das LLaMA-Modelltraining werden A100-80-GB-GPUs verwendet, für das LLaMA-7B-Modelltraining sind 82432 GPU-Stunden erforderlich, für das LLaMA-13B-Modelltraining sind 135168 GPU-Stunden erforderlich, für das LLaMA-33B-Modelltraining sind 530432 GPU-Stunden erforderlich und für das LLaMA-65B-Modelltraining sind bis zu 1022362 GPU-Stunden erforderlich Stunde. Da die Menge der von LLaMA verwendeten Trainingsdaten die der OPT- und BLOOM-Modelle bei weitem übersteigt, obwohl die Anzahl der Modellparameter viel geringer ist als bei den beiden oben genannten Modellen, ist der erforderliche Rechenaufwand immer noch sehr beeindruckend.
Durch die Verwendung eines verteilten Trainingssystems kann der Trainingszyklus großer Sprachmodelle von Jahrzehnten auf einem einzelnen Computergerät auf Dutzende Tage mit Tausenden von Computergeräten verkürzt werden. Allerdings müssen verteilte Trainingssysteme noch verschiedene Herausforderungen wie Computerwände, Videospeicherwände und Kommunikationswände bewältigen, um sicherzustellen, dass alle Ressourcen innerhalb des Clusters vollständig genutzt werden, wodurch der Trainingsprozess beschleunigt und der Trainingszyklus verkürzt wird.
• Rechenwand: Es besteht eine große Diskrepanz zwischen der Rechenleistung, die ein einzelnes Computergerät bereitstellen kann, und dem gesamten Rechenaufwand, der für ein großes Sprachmodell erforderlich ist. Die im März 2022 veröffentlichte NVIDIA H100 SXM verfügt über eine FP16-Rechenleistung einer einzelnen Karte von nur 2000 TFLOPs, während GPT-3
eine Gesamtrechenleistung von 314 ZFLOPs benötigt. Der Unterschied zwischen den beiden beträgt 8 Größenordnungen.
• Videospeicherwand: Ein einzelnes Computergerät kann die Parameter eines großen Sprachmodells nicht vollständig speichern. GPT-3 enthält 175 Milliarden Parameter. Wenn es im FP16-Format gespeichert wird, sind 700 GB Speicherplatz auf dem Computergerät erforderlich, und die NVIDIA H100-GPU verfügt nur über 80 GB Videospeicher.
• Kommunikationswand: Zwischen Computergeräten in einem verteilten Trainingssystem sind häufige Parameterübertragungen und Synchronisierungen erforderlich. Aufgrund von Kommunikationslatenz und Bandbreitenbeschränkungen kann dies zu einem Engpass im Trainingsprozess werden. Wenn während des GPT-3-Trainingsprozesses 128 Modellkopien im verteilten System vorhanden sind, müssen bei jeder Iteration mindestens 89,6 TB Gradientendaten übertragen werden. Ab August 2023 kann eine einzelne InfiniBand-Verbindung nur noch eine Bandbreite von mehr als 800 Gbit/s bereitstellen. Die Computing Wall und die Video Memory Wall entstehen aus dem Konflikt zwischen den begrenzten Rechen- und Speicherkapazitäten eines einzelnen Computergeräts und den enormen Rechen- und Speicheranforderungen des Modells. Dieses Problem kann durch die Verwendung einer verteilten Trainingsmethode gelöst werden, aber das verteilte Training steht vor der Herausforderung von Kommunikationswänden. Beim Training mehrerer Maschinen und Karten traten diese Probleme nach und nach auf. Mit zunehmenden Parametern großer Modelle nimmt auch die entsprechende Clustergröße zu und diese Probleme treten stärker in den Vordergrund. Wenn große Cluster über einen längeren Zeitraum trainiert werden, kann gleichzeitig ein Geräteausfall den Trainingsprozess beeinträchtigen oder unterbrechen, was ebenfalls hohe Anforderungen an das verteilte System stellt.
2. Parallele Strategie für verteiltes Training
Das Ziel des verteilten Trainingssystems besteht darin, das Einzelknoten-Modelltraining in ein äquivalentes verteiltes paralleles Modelltraining umzuwandeln. Bei großen Sprachmodellen besteht der Trainingsprozess darin, die Parameter des neuronalen Netzwerkmodells mithilfe von Optimierungsalgorithmen auf der Grundlage von Daten und Verlustfunktionen zu aktualisieren. Die Struktur des Einzelknoten-Modelltrainingssystems ist in Abbildung 3 dargestellt und besteht hauptsächlich aus zwei Teilen: Daten und Modell. Der Trainingsprozess wird durch mehrere Daten-Mini-Batches (Mini-Batches) abgeschlossen.
Die Daten in der Abbildung stellen eine kleine Datenmenge dar. Das Trainingssystem verwendet kleine Datenmengen, um Gradienten basierend auf Verlustfunktionen und Optimierungsalgorithmen zur Korrektur von Modellparametern zu generieren. Der Ausführungsprozess eines mehrschichtigen neuronalen Netzwerks für ein großes Sprachmodell kann durch einen Rechengraphen (Computational Graph) dargestellt werden. Dieses Diagramm verfügt über mehrere miteinander verbundene Operatoren (Operatoren), jeder Operator implementiert eine neuronale Netzwerkschicht (Neural Network Layer) und die Parameter stellen die Gewichte dar, die von dieser Schicht während des Trainings aktualisiert werden.
Abbildung 3 Ein-Geräte-Modell-Trainingssystem
Der Ausführungsprozess des Berechnungsdiagramms kann in zwei Phasen unterteilt werden: Vorwärtsberechnung und Rückwärtsberechnung. Der Vorwärtsberechnungsprozess besteht darin, die Daten in den ersten Operator einzulesen, die entsprechende Ausgabestruktur zu berechnen und dann den Vorwärtsberechnungsprozess bis zum Ende des letzten Operators zu wiederholen. Der umgekehrte Berechnungsprozess basiert auf der Optimierungsfunktion und dem Verlust. Jeder Operator berechnet nacheinander den Gradienten und verwendet den Gradienten, um die lokalen Parameter zu aktualisieren. Nachdem die umgekehrte Berechnung abgeschlossen ist und die Berechnung des Daten-Minibatchs abgeschlossen ist, liest das System den nächsten Daten-Minibatch und setzt die nächste Runde der Modellparameteraktualisierungen fort.
Gemäß dem Prozess des Einzelgeräte-Modelltrainingssystems können wir sehen, dass eine parallele Beschleunigung aus zwei Dimensionen betrachtet werden kann: Daten und Modell. Erstens können die Daten partitioniert werden (Partition), das gleiche Modell kann auf mehrere Geräte kopiert werden und verschiedene Daten-Shards können parallel ausgeführt werden. Diese Methode wird normalerweise als Datenparallelität (DP) bezeichnet. Das Modell kann auch geteilt werden und die Operatoren im Modell können jeweils zur Vervollständigung auf mehrere Geräte verteilt werden. Diese Methode wird üblicherweise als Modellparallelität (MP) bezeichnet. Beim Training sehr umfangreicher Sprachmodelle ist es häufig erforderlich, die Daten und das Modell gleichzeitig aufzuteilen, um einen höheren Grad an Parallelität zu erreichen. Diese Methode wird häufig als Hybridparallelität (HP) bezeichnet.
2.1. Datenparallelität
In einem datenparallelen System verfügt jedes Computergerät über eine vollständige Kopie des gesamten neuronalen Netzwerkmodells (Modellreplik). Bei der Iteration wird jedem Computergerät nur eine Teilmenge eines Datenprobenstapels zugewiesen, und zwar basierend auf dem Probenstapel Eine Teilmenge der Daten wird für die Vorwärtsberechnung des Netzwerkmodells verwendet. Nehmen Sie an, dass die Anzahl der Trainingsproben in einem Stapel N beträgt und M Computergeräte für die parallele Berechnung verwendet werden und jedem Computergerät N/M Proben zugewiesen werden. Nachdem die Vorwärtsberechnung abgeschlossen ist, berechnet jedes Computergerät den Verlustfehler basierend auf der lokalen Stichprobe, um den Gradienten Gi zu erhalten (i ist die Nummer der Beschleunigerkarte) und sendet den lokalen Gradienten Gi. Alle Computergeräte müssen die von anderen Beschleunigungskarten bereitgestellten Gradientenwerte aggregieren und dann den durchschnittlichen Gradienten (ΣNi = 1Gi)/N verwenden, um das Modell zu aktualisieren und das Batch-Training abzuschließen. Abbildung 4 zeigt ein Beispiel eines datenparallelen Trainingssystems, das aus zwei Computergeräten besteht.
Abbildung 4 Beispiel eines datenparallelen Trainingssystems mit zwei Knoten
Das datenparallele Trainingssystem kann den Gesamttrainingsdurchsatz und die globale Stapelgröße pro Sekunde (Global Batch Size Per Second) durch Hinzufügen von Computerausrüstung effektiv verbessern. Im Vergleich zum Training mit einem einzelnen Computergerät besteht der Hauptunterschied darin, dass die Gradienten bei der umgekehrten Berechnung auf allen Computergeräten synchronisiert werden müssen, um sicherzustellen, dass das Endergebnis auf jedem Computergerät der Durchschnitt der Gradienten aller Prozesse ist.
Gängige neuronale Netzwerk-Frameworks verfügen über spezifische Implementierungen der Datenparallelität, darunter: TensorFlow DistributedStrategy, PyTorch Distributed, Horovod DistributedOptimizer usw. Da jeder Operator in einem großen Sprachmodell, das auf der Transformer-Architektur basiert, auf Einzeldaten und nicht auf Stapeldaten basiert, hat die Datenparallelität keinen Einfluss auf seine Berechnungslogik. Im Allgemeinen ist die Vorwärtsberechnung in jedem Trainingsgerät unabhängig und hat keinen Einfluss auf die Berechnungslogik . Beinhaltet Synchronisierungsprobleme. Datenparalleles Training weist die höchste Beschleunigungsrate auf, erfordert jedoch die Sicherung einer Kopie des Modells auf jedem Gerät und verbraucht relativ viel Videospeicher.
Der Code für die Verwendung von PyTorch DistributedDataParallel zum Implementieren mehrerer Beschleunigerkartentrainings auf einem einzelnen Server lautet wie folgt. Erstellen Sie zunächst die DistributedSampler-Klasse, um die Stichproben des Datensatzes zufällig zu unterbrechen und sie auf verschiedene Computergeräte zu verteilen:
Klasse DistributedSampler(Sampler): def __init__(self, dataset, num_replicas=None, rank=None, shuffle=True, Seed=0): wenn num_replicas None ist: wenn nicht dist.is_available(): raise RuntimeError("Verteiltes Paket muss verfügbar sein") num_replicas = dist.get_world_size() wenn der Rang „None“ ist: wenn nicht dist.is_available(): raise RuntimeError("Verteiltes Paket muss verfügbar sein") rank = dist.get_rank() self.dataset = Datensatz #dataset self.num_replicas = num_replicas #Die Anzahl der Prozesse ist standardmäßig auf world_size (Anzahl der GPUs) eingestellt. self.rank = rank # Zu welchem Prozess/GPU aktuell gehört self.epoch = 0 self.num_samples = int(math.ceil(len(self.dataset) * 1.0 / self.num_replicas)) #Anzahl der Proben pro Prozess self.total_size = self.num_samples * self.num_replicas #Die Anzahl der Gesamtproben im Datensatz self.shuffle = shuffle # Ob der Datensatz gemischt werden soll self.seed = Samen def __iter__(self): # 1. Shuffle-Verarbeitung: Unterbrechen Sie die Reihenfolge des Datensatzes wenn self.shuffle: # Verschleierung basierend auf Epoche und Samen g = Torch.Generator() # Hier ist self.seed ein fester Wert. Das Ändern von self.epoch durch set_epoch kann unseren Initialisierungs-Seed ändern. # Dadurch kann die Mischreihenfolge der Datensätze in jeder Epoche unterschiedlich sein, sodass in jeder Epoche # Jede GPU erhält unterschiedliche Daten, was ein besseres Training ermöglichen kann. g.manual_seed(self.seed + self.epoch) indices = Torch.randperm(len(self.dataset), Generator=g).tolist() anders: indizes = list(range(len(self.dataset))) # Datenergänzung indizes += indices[:(self.total_size - len(indices))] behaupten len(indices) == self.total_size # Daten zuordnen indices = indices[self.rank:self.total_size:self.num_replicas] behaupten len(indices) == self.num_samples Rückgabeiter (Indizes) def __len__(self): Gibt self.num_samples zurück def set_epoch(self, epoch): self.epoch = Epoche
Verwenden Sie DistributedSampler, um ein vollständiges Trainingsprogrammbeispiel main.py wie folgt zu erstellen:
argparse importieren Importieren Sie uns Shutil importieren Importzeit Warnungen importieren numpy als np importieren warnings.filterwarnings('ignore') Taschenlampe importieren importiere Torch.nn als nn Torch.nn.parallel importieren importiere Torch.backends.cudnn als cudnn import Torch.distributed as dist Torch.optim importieren Torch.utils.data importieren importiere Torch.utils.data.distributed aus Torch.utils.data.distributed Import DistributedSampler aus Modellen importieren DeepLab aus Datensatzimport Stadtbilder parser = argparse.ArgumentParser(description='DeepLab') parser.add_argument('-j', '--workers', default=4, type=int, metavar='N', help='Anzahl der Datenladearbeiter (Standard: 4)') parser.add_argument('--epochs', default=100, type=int, metavar='N', help='Anzahl der insgesamt auszuführenden Epochen') parser.add_argument('--start-epoch', default=0, type=int, metavar='N', help='manuelle Epochennummer (nützlich bei Neustarts)') parser.add_argument('-b', '--batch-size', default=3, type=int, metavar='N') parser.add_argument('--local_rank', default=0, type=int, help='Knotenrang für verteiltes Training') args = parser.parse_args() Torch.distributed.init_process_group(backend="nccl") #Initialization print("GPU verwenden: {} für das Training".format(args.local_rank)) # Modell erstellen Modell = DeepLab() Torch.cuda.set_device(args.local_rank) #Aktuelle Grafikkarte model = model.cuda() # Das Modell wird auf der Grafikkarte platziert model = Torch.nn.parallel.DistributedDataParallel(model, device_ids=[args.local_rank], (output_device=args.local_rank, find_unused_parameters=True) # Datenparallelität Kriterium = nn.CrossEntropyLoss().cuda() Optimizer = Torch.optim.SGD(model.parameters(), args.lr, momentum=args.momentum,weight_decay=args.weight_decay) train_dataset = Cityscaples() train_sampler = DistributedSampler(train_dataset) # Daten verteilen train_loader = Torch.utils.data.DataLoader(train_dataset, batch_size=args.batch_size, shuffle=False, num_workers=args.workers, pin_memory=True, sampler=train_sampler)
Starten Sie das obige Programm über die folgende Befehlszeile:
CUDA_VISIBLE_DEVICES=0,1 python -m Torch.distributed.launch --nproc_per_node=2 main.py
2.2 Modellparallelität
Modellparallelität wird häufig verwendet, um das Problem unzureichenden Speichers auf einem einzelnen Knoten zu lösen. Nehmen Sie als Beispiel das GPT-3-Modell mit 175 Milliarden Parametern. Wenn jeder Parameter im Modell durch eine 32-Bit-Gleitkommazahl dargestellt wird, muss das Modell 700 GB (d. h. 175 GB × 4 Byte) Speicher belegen dargestellt durch eine 16-Bit-Gleitkommazahl. Jede Modellkopie erfordert 350 GB Speicher. Die im März 2022 von NVIDIA veröffentlichte H100-Beschleunigerkarte unterstützt nur 80 GB Videospeicher und das gesamte Modell kann nicht vollständig darin untergebracht werden. Modellparallelität kann aus der Sicht von Rechengraphen in die folgenden zwei Formen unterteilt werden:
(1) Aufteilung in verschiedene Geräte gemäß den Schichten des Modells, dh Parallelität zwischen Schichten oder Parallelität zwischen Operatoren (Inter-Operator-Parallelität), auch Pipeline-Parallelität (Pipeline Parallelism, PP) genannt;
(2) Teilen Sie die Parameter in der Berechnungsschicht in verschiedene Geräte auf, dh Intra-Layer-Parallelität oder Intra-Operator-Parallelität (Intra-Operator-Parallelität), auch Tensor-Parallelität (Tensor-Parallelität, TP) genannt.
Ein Beispiel für ein paralleles Trainingssystem mit zwei Knoten ist in Abbildung 4.9 dargestellt. Die linke Seite zeigt die Pipeline-Parallelität, und die rechte Seite zeigt die Tensor-Parallelität und verschiedene Parameter in derselben Schicht werden im Gerät auf verschiedene Berechnungen aufgeteilt.
Pipeline-Parallelität
Pipeline-Parallelität (PP) ist eine parallele Rechenstrategie, die jede Schicht des Modells in Segmenten verarbeitet und jedes Segment auf verschiedene Computergeräte verteilt, sodass die vorherigen und nachfolgenden Stufen in einer Pipeline und in Stapeln arbeiten können. Pipeline-Parallelität wird normalerweise in parallelen Systemen großer Modelle angewendet, um das Problem unzureichenden Speichers auf einem einzelnen Computergerät wirksam zu lösen. Abbildung 4.6 zeigt ein Pipeline-Parallelsystem, das aus vier Rechengeräten besteht, einschließlich Vorwärtsberechnung und Rückwärtsberechnung. Darunter stellen F1, F2, F3 und F4 jeweils vier Vorwärtspfade dar, die sich auf verschiedenen Geräten befinden, während B4, B3, B2 und B1 die Rückwärtspfade darstellen, die sich ebenfalls auf vier verschiedenen Geräten befinden. Wie aus der Abbildung ersichtlich ist, muss das Downstream-Gerät (Downstream Device) im Berechnungsdiagramm jedoch lange Zeit im Leerlauf bleiben und darauf warten, dass das Upstream-Gerät (Upstream Device) seine Berechnungen abschließt, bevor es mit der Berechnung seiner eigenen beginnen kann Aufgaben.
Abbildung 5 Beispiel eines parallelen Trainingssystems mit zwei Knotenmodellen
Diese Situation führte zu einer erheblichen Reduzierung der durchschnittlichen Nutzung des Geräts und zur Bildung einer Modellparallelitätsblase, auch Pipeline-Blase genannt.
Abbildung 6 Beispiel für eine parallele Pipeline
Die durch die naive Pipeline-Strategie erzeugten parallelen Blasen verhindern, dass das System die Rechenressourcen vollständig nutzt, und verringern die Gesamtrecheneffizienz des Systems. Um parallele Blasen zu reduzieren, wurde in der Literatur [131] die GPipe-Methode vorgeschlagen, die den Mini-Batch weiter in kleinere Mikro-Batches aufteilt und das Pipeline-Parallelschema verwendet, um jeweils einen Mikro-Batch mit Daten zu verarbeiten.
Nachdem die Berechnung in der aktuellen Phase abgeschlossen ist und die Ergebnisse vorliegen, werden die Ergebnisse des Mikrobatches an das nachgeschaltete Gerät gesendet und gleichzeitig werden die Daten des nächsten Mikrobatches verarbeitet, was zu einer Reduzierung führen kann bis zu einem gewissen Grad parallele Blasen. Abbildung 7: Beispiel für eine parallele GPipe-Richtlinienpipeline. Wie in der Abbildung gezeigt, ist die Vorwärtsberechnung von F1 in F11, F12, F13 und F14 unterteilt. Nachdem die Berechnung von F11 in Computergerät 1 abgeschlossen ist, wird die Berechnung von F21 in Computergerät 2 gestartet Gleichzeitig wird F12 parallel im Rechengerät 1 gestartet. Berechnung. Im Vergleich zur ursprünglichen Pipeline-Parallelmethode kann die GPipe-Pipeline-Methode parallele Blasen effektiv reduzieren.
Abbildung 7 Beispiel für eine parallele Gpipe-Richtlinienpipeline
Obwohl die GPipe-Strategie bestimmte parallele Blasen reduzieren kann, kann die Rückwärtsberechnung erst beginnen, nachdem alle Vorwärtsberechnungen in einem Mini-Batch abgeschlossen sind. Daher werden immer noch viele parallele Blasen erzeugt, wodurch die parallele Effizienz des Systems verringert wird. Megatron-LM[132] schlug eine 1F1B-Pipeline-Strategie vor, die aus einem Vorwärtskanal und einem Rückwärtskanal besteht. Die 1F1B-Pipeline-Strategie führt einen Aufgabenplanungsmechanismus ein, der es nachgeschalteten Geräten ermöglicht, andere parallele Aufgaben auszuführen, während sie auf vorgelagerte Berechnungen warten, wodurch die Geräteauslastung verbessert wird. 1F1B bietet zwei Planungsmethoden: nicht verschachtelt und verschachtelt, wie in Abbildung 8 dargestellt.
Der nicht verschachtelte 1F1B-Planungsmodus kann in drei Stufen unterteilt werden. Die erste ist eine Aufwärmphase, in der im Computergerät unterschiedlich viele Vorwärtsberechnungen durchgeführt werden. Die nächste Phase ist die Vorwärts-Rückwärts-Phase, in der das Computergerät nacheinander eine Vorwärtsberechnung und dann eine Rückwärtsberechnung durchführt. Die letzte Phase ist die Rückwärtsphase, in der das Computergerät die letzte Rückwärtsberechnung durchführt. Im Vergleich zur GPipe-Strategie ist der nicht verschachtelte Planungsmodus hinsichtlich der Speichereinsparung besser geeignet. Es benötigt jedoch die gleiche Zeit wie die GPipe-Strategie, um eine Berechnungsrunde abzuschließen.
Der verschachtelte Planungsmodus 1F1B erfordert, dass die Anzahl der Mikrobatches ein ganzzahliges Vielfaches der Pipeline-Stufen ist. Jedes Gerät ist nicht mehr allein für die Berechnung mehrerer aufeinanderfolgender Schichten verantwortlich, sondern kann Teilmengen mehrerer Schichten, sogenannte Modellnuggets, verarbeiten. Insbesondere könnte im Vorgängermodell Gerät 1 für die Schichten 1–4 verantwortlich sein, Gerät 2 für die Schichten 5–8 usw. Im neuen Modus kann Gerät 1 jedoch die Schichten 1, 2, 9, 10 verarbeiten, Gerät 2 kann die Schichten 3, 4, 11, 12 usw. verarbeiten. In diesem Modus wird jedes Gerät mehreren Stufen in der Pipeline zugewiesen. Beispielsweise kann Gerät 1 an einer Teilmenge von Aufgaben in der Aufwärmphase, der Vorwärtsberechnungsphase und der Rückwärtsberechnungsphase beteiligt sein. Jedes Gerät kann Rechenaufgaben in verschiedenen Phasen parallel ausführen und so die Vorteile der Pipeline-Parallelität besser nutzen. Dieser Modus weist nicht nur eine gute Leistung im Hinblick auf den Speicherverbrauch auf, sondern verbessert auch die Recheneffizienz, sodass parallele Systeme für große Modelle Rechenaufgaben effizienter erledigen können.
Abbildung 8 Beispiel einer parallelen 1F1B- Pipeline-Strategie
PyTorch enthält auch die API-Funktion Pipe zur Implementierung der Pipeline. Informationen zur spezifischen Implementierung finden Sie in der Klasse „torch.distributed.pipeline.sync.Pipe“. Mit dieser API können Sie wie folgt ein Beispiel erstellen, das zwei lineare Schichten enthält und in zwei verschiedenen Computergeräten platziert wird:
{# Schritt 0. Zuerst muss das RPC-Framework initialisiert werden. os.environ['MASTER_ADDR'] = 'localhost' os.environ['MASTER_PORT'] = '29500' Torch.distributed.rpc.init_rpc('worker', rank=0, world_size=1) # Schritt 1: Erstellen Sie ein Modell mit zwei linearen Ebenen fc1 = nn.Linear(16, 8).cuda(0) fc2 = nn.Linear(8, 4).cuda(1) # Schritt 2: Wickeln Sie die beiden Schichten mit nn.Sequential ein Modell = nn.Sequential(fc1, fc2) # Schritt 3: Pipe erstellen (torch.distributed.pipeline.sync.Pipe) model = Pipe(model, chunks=8) # Training/Inferenz durchführen Eingabe = Torch.rand(16, 16).cuda(0) Output_rref = Modell(Eingabe) }
Tensorparallelität
Tensorparallelität (TP) muss zwei Probleme lösen: Wie werden Parameter entsprechend der spezifischen Struktur und dem Operatortyp des Modells in verschiedene Geräte aufgeteilt, und wie kann nach der Aufteilung die mathematische Konsistenz sichergestellt werden. Große Sprachmodelle basieren auf der Transformer-Struktur. Die Transformer-Struktur besteht hauptsächlich aus den folgenden drei Operatoren: eingebettete Darstellung (Einbettung), Matrixmultiplikation (MatMul) und Berechnung des Kreuzentropieverlusts (Cross Entropy Loss).
Diese drei Arten von Operatoren sind sehr unterschiedlich, und es müssen entsprechende Tensor-Parallelstrategien [130] entwickelt werden, um Parameter in verschiedene Geräte aufzuteilen. Wenn für den Einbettungsoperator die Gesamtzahl der Vokabulare sehr groß ist, kann der Videospeicher eines einzelnen Computergeräts die Parameter der Einbettungsschicht nicht aufnehmen. Wenn beispielsweise die Anzahl der Vokabulare 64.000 beträgt, die Einbettungsdarstellungsdimension 5.120 beträgt und der Typ Gleitkommazahlen mit 32-Bit-Präzision verwendet, beträgt der für die gesamte Parameterschicht erforderliche Videospeicher etwa 64.000 × 5120 × 4/1024 /1024 = 1250 MB, und der umgekehrte Gradient ist derselbe. Erfordert 1250 MB, fast 2,5 GB allein für die Speicherung.
Die in die Präsentationsschicht eingebetteten Parameter können entsprechend der Wortdimension unterteilt werden. Jedes Computergerät speichert nur einen Teil des Wortvektors, und dann wird der vollständige Wortvektor durch Zusammenfassen der Teilwortvektoren auf jedem Gerät erhalten. Abbildung 4.9 zeigt ein schematisches Diagramm der Einbettung mit einem Knoten und der Tensorparallelität mit zwei Knoten.
Führen Sie auf einem einzelnen Knoten den Einbettungsvorgang aus, bz ist die Stapelgröße (Stapelgröße), die Parametergröße der Einbettung ist [Wortgröße, versteckte_Größe] und der Tensor [bz, versteckte_Größe] wird berechnet. Das Einbettungs-Tensor-Parallel-Beispiel in Abbildung 4.9 unterteilt die Einbettungsparameter in zwei Blöcke entlang der Word_size-Dimension. Jeder Block hat eine Größe von [Wortgröße/2, versteckte_Größe] und wird jeweils auf zwei Geräten gespeichert. Wenn jeder Knoten seine eigene Wortliste abfragt und es nicht gefunden werden kann, ist die Darstellung des Wortes 0. Nach der Abfrage des jeweiligen Geräts wird der Ergebnistensor [bz, versteckte_Größe] erhalten und schließlich durch AllReduce_Sum-Kommunikation ¬ summiert , erhalten wir Aus den vollständigen Ergebnissen ist ersichtlich, dass die Ausgabeergebnisse hier mit den Ergebnissen übereinstimmen, die von einem einzelnen Computergerät ausgeführt werden.
Abbildung 9 Beispiel für einen parallelen Tensor mit Einbettungsoperator und zwei Knoten
Die Tensorparallelität der Matrixmultiplikation (MatMul) sollte das Prinzip der Matrixblockmultiplikation vollständig nutzen. Um beispielsweise die folgende Matrixmultiplikation zu implementieren: Y = X × A, wobei X die Eingabematrix mit der Dimension M × N, A die Parametermatrix mit der Dimension N × K und Y die Ergebnismatrix mit der Dimension M × K ist. Wenn die Parametermatrix A sehr groß ist oder sogar die Videospeicherkapazität einer einzelnen Karte überschreitet, kann die Parametermatrix A auf mehrere Karten aufgeteilt werden und die Ergebnisse können durch gemeinsame Kommunikation gesammelt werden, um sicherzustellen, dass das Endergebnis mathematisch ist entspricht einem einzelnen Computergerät. Berechnungsergebnisse. Es gibt zwei Möglichkeiten, die Parametermatrix A zu segmentieren:
(1) Die Parametermatrix A wird in Spalten geschnitten und die Matrix A wird in Spalten geschnitten: A = [A1,A2]
(2) Die Parametermatrix A wird in Zeilen geschnitten, und die Matrix A wird in Zeilen geschnitten:
Abbildung 10 zeigt ein Beispiel für die Aufteilung der Parametermatrix nach Spalten. Die Parametermatrix A platziert A1 und A2 jeweils auf zwei Rechengeräten. Zwei Rechengeräte berechnen Y1 = X ×A1 bzw. Y2 = X ×A2. Nach Abschluss der Berechnung kommunizieren mehrere Computergeräte miteinander, um die Berechnungsergebnisse auf anderen Computergeräten abzurufen, und fügen sie zusammen, um die Endergebnismatrix Y zu erhalten. Dieses Ergebnis entspricht mathematisch dem Berechnungsergebnis eines einzelnen Computergeräts.
Abbildung 10 Beispiel für die parallele Aufteilung von Zwei-Knoten-Matrixmultiplikationsoperator-Tensoren nach Spalten
Abbildung 11 zeigt ein Beispiel für die Aufteilung der Parametermatrix durch Spalten und Zeilen. Um die Matrixmultiplikationsregeln zu erfüllen, muss die Eingabematrix X durch Spalten X = [X1|X2] geteilt werden. Gleichzeitig wird die Matrix in Blöcke unterteilt und auf zwei Computergeräten platziert. Jedes Computergerät berechnet Y1 = X1 × A1 bzw. Y2 = X2 × A2. Nachdem die Berechnung abgeschlossen ist, kommunizieren mehrere Computergeräte, um die Berechnungsergebnisse auf anderen Karten zu erhalten und zu reduzieren, und die endgültige Ergebnismatrix Y kann erhalten werden. In ähnlicher Weise kann diese Aufteilungsmethode nicht nur die Äquivalenz mathematischer Berechnungen sicherstellen, sondern auch das Problem lösen, dass ein einzelnes Computergerät den Videospeicher nicht aufnehmen kann, und kann auch sicherstellen, dass ein einzelnes Computergerät durch Aufteilung Parameter A aufnehmen kann.
Die FFN-Struktur in Transformer enthält zwei vollständig verbundene (FC) Schichten, das heißt, es gibt zwei Matrixmultiplikationen, und diese beiden Matrixmultiplikationen übernehmen die beiden oben genannten Segmentierungsmethoden, wie in Abbildung 4.12 dargestellt. Die Parametermatrix der ersten FC-Schicht wird spaltenweise in Blöcke geschnitten, und die Parametermatrix der zweiten FC-Schicht wird zeilenweise in Blöcke geschnitten. Auf diese Weise entspricht die Ausgabe der ersten FC-Schicht genau den Dateneingabeanforderungen der zweiten FC-Schicht (aufgeteilt nach Spalten), sodass der zusammenfassende Kommunikationsvorgang nach der ersten FC-Schicht weggelassen werden kann. Die Tensorparallelität des Mehrkopf-Selbstaufmerksamkeitsmechanismus ähnelt der von FFN. Da sie über mehrere unabhängige Köpfe verfügt, ist die Parallelität einfacher als die von FFN. Die Matrixsegmentierungsmethode ist in Abbildung 4.13 dargestellt. Einzelheiten finden Sie in [130].
Die letzte Schicht des Klassifizierungsnetzwerks verwendet im Allgemeinen Softmax- und Cross_entropy-Operatoren, um den Kreuzentropieverlust (Kreuzentropieverlust) zu berechnen. Wenn die Anzahl der Kategorien sehr groß ist, kann der Speicher eines einzelnen Computergeräts die Logit-Matrix nicht speichern und berechnen. Für diesen Operatortyp kann er nach der Kategoriedimension unterteilt werden, und gleichzeitig kann der endgültige globale Kreuzentropieverlust durch Zwischenergebniskommunikation ermittelt werden.
Abbildung 11 Beispiel für die parallele Aufteilung des Zwei-Knoten-Matrixmultiplikationsoperators Tensor nach Zeilen
Abbildung 12 FNN-Struktur-Tensor-Paralleldiagramm
Als erstes muss der Softmax-Wert berechnet werden. Die Formel lautet wie folgt:
Unter diesen stellt p die Gerätenummer der Tensorparallelität dar. Nach Erhalt des Softmax-Berechnungsergebnisses wird das Label-Ziel gleichzeitig nach Kategorien unterteilt und jedes Gerät erhält einen Teil des Verlusts. Schließlich wird eine weitere Kommunikation durchgeführt, um den Verlust aller Kategorien zu ermitteln. Der gesamte Prozess erfordert nur drei kleine Kommunikationsmengen, um die Berechnung des Kreuzentropieverlusts abzuschließen. PyTorch bietet eine feinkörnige parallele API auf Tensorebene, DistributedTensor. Es bietet außerdem eine grobkörnige API auf Modellebene, um Tensorparallelität für „nn.Module“ durchzuführen. Sie können einen großen Tensor mit den folgenden Codezeilen fragmentieren:
Taschenlampe importieren aus Torch.distributed._tensor importieren DTensor, DeviceMesh, Shard, distribution_tensor # Erstellen Sie ein Gerätenetz mit verfügbaren Geräten (Multi-Host oder Einzel-Host). device_mesh = DeviceMesh("cuda", [0, 1, 2, 3]) # wenn wir zeilenweises Sharding durchführen wollen rowwise_placement=[Shard(0)] # wenn wir spaltenweises Sharding durchführen wollen colwise_placement=[Shard(1)] big_tensor = Torch.randn(888, 12) # Der zurückgegebene verteilte Tensor wird über die in den Platzierungen angegebene Dimension aufgeteilt rowwise_tensor = distribution_tensor(big_tensor, device_mesh=device_mesh, Placements=rowwise_placement)
Für Module wie „nn.Linear“, die bereits „torch.Tensor“ als Parameter haben, wird auch die API „distribute_module“ auf Modulebene bereitgestellt, um Tensorparallelität auf Modellebene durchzuführen. Der Referenzcode lautet wie folgt:
Taschenlampe importieren aus Torch.distributed._tensor importieren DeviceMesh, Shard, distribution_tensor,distribute_module Klasse MyModule(nn.Module): def __init__(self): super().__init__() self.fc1 = nn.Linear(8, 8) self.fc2 = nn.Linear(8, 8) self.relu = nn.ReLU() def forward(self, input): return self.relu(self.fc1(input) + self.fc2(input)) mesh = DeviceMesh(device_type="cuda", mesh=[[0, 1], [2, 3]]) def shard_params(mod_name, mod, mesh): rowwise_placement = [Shard(0)] def to_dist_tensor(t): return distribution_tensor(t, mesh, rowwise_placement) mod._apply(to_dist_tensor) sharded_module = distribution_module(MyModule(), mesh, partition_fn=shard_params) def shard_fc(mod_name, mod, mesh): rowwise_placement = [Shard(0)] wenn mod_name == "fc1": mod.weight = Torch.nn.Parameter(distribute_tensor(mod.weight, mesh, rowwise_placement)) sharded_module = distribution_module(MyModule(), mesh, partition_fn=shard_fc)
2.3 Hybride Parallelität
Hybrid Parallelism (HP) ist eine Mischung aus mehreren parallelen Strategien wie Datenparallelität, Pipeline-Parallelität und Tensor-Parallelität. Durch die Kombination verschiedener Parallelstrategien kann die Hybridparallelität die Vorteile verschiedener Parallelstrategien voll ausnutzen, um die Rechenleistung und -effizienz zu maximieren.
Bei großen Sprachmodellen mit einer Größenordnung von Hunderten von Milliarden wird normalerweise innerhalb jedes Servers eine Tensor-Parallel-Strategie verwendet. Da diese Strategie einen großen Umfang an Netzwerkkommunikation erfordert, ist es notwendig, eine Hochgeschwindigkeits-Kommunikationsbandbreite zwischen verschiedenen Computergeräten zu nutzen Server. Durch Pipeline-Parallelität werden verschiedene Schichten des Modells in mehrere Stufen unterteilt, und jede Stufe wird von einer anderen Maschine berechnet. Auf diese Weise kann die Rechenleistung mehrerer Maschinen voll ausgenutzt werden und Berechnungsergebnisse und Zwischendaten können durch Hochgeschwindigkeitskommunikation zwischen Maschinen übertragen werden, um die Gesamtrechengeschwindigkeit und -effizienz zu verbessern.
Schließlich wird die Datenparallelitätsstrategie der äußeren Schicht überlagert, um die Anzahl der Parallelitäten zu erhöhen und die Gesamttrainingsgeschwindigkeit zu verbessern. Durch Datenparallelität werden Trainingsdaten zur parallelen Verarbeitung auf mehrere Servergruppen verteilt, und jede Servergruppe verarbeitet unterschiedliche Datenstapel. Dadurch können die Rechenressourcen mehrerer Server voll ausgenutzt und die Parallelität des Trainings erhöht werden, wodurch die Gesamtgeschwindigkeit des Trainings beschleunigt wird.
BLOOM verwendet für das Training das Megatron-DeepSpeed-Framework, das hauptsächlich aus zwei Teilen besteht: Megatron-LM bietet Tensor-Parallelfunktionen und Datenladeprimitive; DeepSpeed stellt den ZeRO-Optimierer, die Modellpipeline und herkömmliche verteilte Trainingskomponenten bereit. Auf diese Weise kann eine dreidimensionale Parallelität von Daten, Tensoren und Pipelines erreicht werden. Die beim BLOOM-Modelltraining verwendete parallele Rechenstruktur ist in Abbildung 14 dargestellt.
Beim BLOOM-Modelltraining wird ein Cluster aus 48 NVIDIA DGX-A100-Servern verwendet. Jeder DGX-A100-Server enthält 8 NVIDIA A100 80-GB-GPUs, also insgesamt 384. Die beim BLOOM-Training angewandte Strategie besteht darin, den Cluster zunächst zur Datenparallelisierung in Gruppen zu je 48 Personen aufzuteilen.
Als nächstes wird das gesamte Modell zur Pipeline-Parallelisierung in 12 Phasen unterteilt. Das Modell jeder Stufe ist zur Tensorparallelität in 4 GPUs unterteilt. Gleichzeitig verwendet BLOOM auch ZeRO (Zero Redundancy Optimizer) [134], um die Belegung des Videospeichers durch das Modell weiter zu reduzieren. Durch die oben genannten vier Schritte kann eine effiziente parallele Berechnung von Hunderten von GPUs erreicht werden.
Abbildung 14 Parallele Rechenstruktur, die beim BLOOM-Modelltraining verwendet wird
2.4 Speicheroptimierung von Computergeräten
Das aktuelle Training großer Sprachmodelle verwendet normalerweise den Adam-Optimierungsalgorithmus, der zusätzlich zum Gradienten jedes Parameters einen Impuls erster Ordnung (Momentum) und einen Impuls zweiter Ordnung (Varianz) erfordert. Obwohl der Adam-Optimierungsalgorithmus im Allgemeinen besser und stabiler ist als der SGD-Algorithmus, verbraucht er deutlich mehr Speicher auf dem Computergerät.
Um die Speichernutzung zu reduzieren, haben die meisten Systeme die Mixed Precision Training-Methode übernommen, das heißt, es gibt Werte in den Formaten FP16 (16-Bit-Gleitkomma) oder BF16 (Bfloat16) und FP32 (32-Bit-Gleitkomma). . FP32, FP16 und BF16 werden wie in Abbildung 4.15 dargestellt dargestellt. In FP32 ist Bit 31 das Vorzeichenbit, die Bits 30 bis 23 werden zur Darstellung des Exponenten verwendet und die Bits 22 bis 0 werden zur Darstellung der Mantisse verwendet. In FP16 ist Bit 15 das Vorzeichenbit, die Bits 14 bis 10 werden zur Darstellung des Exponenten und die Bits 9 bis 9 zur Darstellung der Mantisse verwendet. In BF16 ist Bit 15 das Vorzeichenbit, die Bits 14 bis 7 werden zur Darstellung des Exponenten und die Bits 6 bis 0 zur Darstellung der Mantisse verwendet. Da der Wertebereich von FP16 viel kleiner ist als der von FP32, kann es während des Berechnungsprozesses leicht zu Über- und Unterläufen kommen. Im Vergleich zu FP16 bietet BF16 Präzision gegen einen größeren Wertebereich. Aufgrund der geringeren Genauigkeit von FP16 und BF16 im Vergleich zu FP32 können jedoch während des Trainingsprozesses Probleme mit dem Verschwinden des Gradienten und der Modellinstabilität auftreten.
Daher müssen einige Technologien zur Lösung dieser Probleme eingesetzt werden, z. B. dynamische Verlustskalierung (Dynamic Loss Scaling) und Mixed Precision Optimizer (Mixed Precision Optimizer). Der Prozess der gemischten Präzisionsoptimierung ist in Abbildung 4.16 dargestellt. Der Zustand des Adam-Optimierers umfasst die Sicherung der in FP32 gespeicherten Modellparameter, und Impulse erster Ordnung und Impulse zweiter Ordnung werden ebenfalls im FP32-Format gespeichert. Unter der Annahme, dass die Anzahl der Modellparameter Φ beträgt und die Modellparameter und -verläufe im FP16-Format gespeichert werden, sind insgesamt 2Φ + 2Φ + (4Φ + 4Φ + 4Φ) = 16Φ Bytes Speicher erforderlich.
Davon macht der Adam-Status 75 % aus. Vor der dynamischen Verlustskalierung wird die Verluständerung (dLoss) manuell um das 2.000-fache erhöht, damit der während der Backpropagation erhaltene Aktivierungsfunktionsgradient nicht überläuft. Nach der Backpropagation wird der Gewichtsgradient um das 2.000-fache reduziert und auf den normalen Wert zurückgesetzt. Beispielsweise sind für ein Modell mit 7,5 Milliarden Parametern bei Verwendung des FP16-Formats nur 15 GB Speicher des Computergeräts erforderlich, aber der Modellstatus verbraucht während der Trainingsphase tatsächlich 120 GB.
Zusätzlich zum Modellstatus weist der von der Computerkarte belegte Speicher auch Restzustände (Restzustände) auf, darunter Aktivierungswerte (Aktivierung), verschiedene temporäre Puffer (Puffer) und unbrauchbare Videospeicherfragmente (Fragmentierung) usw. Da der Aktivierungswert Checkpointing (Activation Checkpointing) verwenden kann, um den Speicherbedarf des Aktivierungswerts erheblich zu reduzieren, ist die Reduzierung des Modellzustands, insbesondere des Adam-Optimiererzustands, der Schlüssel zur Lösung des Speicherbedarfsproblems.
Abbildung 16 Optimierungsprozess mit gemischter Präzision
Das Obige ist meine kurze Einführung in die Grundkonzepte verteilter maschineller Lernsysteme, verteilter Trainingsclusterarchitektur und verteilter Trainingsparallelstrategien. DeepSpeed ist ein Beispiel dafür, wie man ein großes Sprachmodell auf einem Cluster trainiert Es ist Ihnen im nächsten Artikel willkommen, es zu mögen und zu unterstützen, Ihre Unterstützung ist die treibende Kraft für meine Kreation.
Referenzinhalt:
(1) Sammlung丨Freigabe von 30 großen Datensätzen zum Thema Sprachmodelltraining – Zhihu https://zhuanlan.zhihu.com/p/612243919.
(2) Vier gängige Verarbeitungsmethoden für große Sprachmodell-Trainingsdaten – Zhihu https://zhuanlan.zhihu.com/p/673045395.
(3) „Groß angelegtes Sprachmodell: Von der Theorie zur Praxis“ Zhang Qi et al. – Peking: Electronic Industry Press
(4) Überprüfung großer Sprachmodelle – Renmin University of China http://ai.ruc.edu.cn/research/science/20230605100.html.
Ein in den 1990er Jahren geborener Programmierer hat eine Videoportierungssoftware entwickelt und in weniger als einem Jahr über 7 Millionen verdient. Das Ende war sehr bestrafend! High-School-Schüler erstellen im Rahmen einer Coming-of-Age-Zeremonie ihre eigene Open-Source-Programmiersprache – scharfe Kommentare von Internetnutzern: Der inländische Dienst Taobao (taobao.com) verließ sich aufgrund des grassierenden Betrugs auf RustDesk und stellte die inländischen Dienste ein und startete die Arbeit zur Optimierung der Webversion von Java neu 17 ist die am häufigsten verwendete Java LTS-Version. Windows 11 erreicht weiterhin einen Rückgang. Open Source Daily unterstützt die Übernahme von Open Source Rabbit R1; Electric schließt die offene Plattform Apple veröffentlicht M4-Chip Google löscht Android Universal Kernel (ACK) Unterstützung für RISC-V-Architektur Yunfeng ist von Alibaba zurückgetreten und plant, in Zukunft unabhängige Spiele auf der Windows-Plattform zu produzieren