Microbatch, Rückwärtsdurchlauf und Aktualisierung trennen
Der Microbatch ist die Gruppe von Beispielen, die in einem Vorwärtsdurchlauf auf einer Replik verarbeitet wird. Der Rückwärtsdurchlauf berechnet seinen Beitrag zu den Gradienten. Die Aktualisierung des Optimierers nutzt die verfügbaren Gradienten, um die Parameter zu ändern. Bei Akkumulation gehen dieser Aktualisierung mehrere Vorwärts-/Rückwärtsdurchläufe voraus; die Parameter bleiben während der Gruppe unverändert.
In PyTorch akkumulieren sich die Gradienten in den dafür vorgesehenen Tensoren. Die Gradienten nach jedem Microbatch zu löschen würde daher die gewünschte Akkumulation aufheben. Umgekehrt würde ein Vergessen des Zurücksetzens zwischen zwei Gruppen dazu führen, dass Beispiele der vorherigen Aktualisierung beitragen.
Legen Sie Ihre Protokollierungseinheit fest: Microbatch-Nummer, Optimierer-Aktualisierung, gesehene Beispiele oder Tokens. Das Wort „step“ allein ist mehrdeutig. Eine Verlustkurve lässt sich nicht korrekt vergleichen, wenn die Achse in einem der Experimente achtmal mehr Beispiele darstellt.
Technische Quellen: PyTorch — Akkumulation und Zurücksetzen der Gradienten
Den effektiven Batch berechnen, ohne die GPUs doppelt zu zählen
Bezeichnen wir mit m die Anzahl der Beispiele pro Microbatch und pro Replik, mit A die Anzahl der akkumulierten Microbatches, mit D die Anzahl der Datenparallelismus-Replikate. Wenn diese Größen konstant sind und die Beispiele korrekt verteilt werden, ist die Anzahl der Beispiele, die zu einer globalen Aktualisierung beitragen, m × A × D.
Der Faktor D bezeichnet nicht unbedingt alle Karten des Rechners. GPUs, die sich ein und dasselbe Modell durch Tensor- oder Pipeline-Parallelismus teilen, werden nicht zu ebenso vielen Datenreplikaten. Tragen Sie die tatsächlich konfigurierten Gruppen ein, nicht einfach die kommerzielle Menge des Batches.
Arithmetisches Beispiel: zwei Beispiele pro Microbatch, acht Akkumulationen und zwei Repliken ergeben 32 Beispiele pro globalem Update. Jede Replike verarbeitet sechzehn Beispiele in dieser Gruppe. Die Tabelle vergleicht Zählwerte; sie bewertet nicht deren Speicher oder Geschwindigkeit.
| m | A | D | Beispiele pro globalem Update |
|---|---|---|---|
| 2 | 8 | 2 | 32 |
| 1 | 16 | 2 | 32 |
| 4 | 4 | 2 | 32 |
| 2 | 8 | 1 | 16 |
Technische Quellen: PyTorch — effektive Batch-Größe und Akkumulation in gemischter Präzision · PyTorch — Verhalten der Repliken bei DistributedDataParallel
Den Verlust nach den tatsächlich ausgewerteten Elementen normalisieren
Für einen mittleren Verlust über Microbatches mit derselben Anzahl relevanter Elemente ergibt die Division jedes Beitrags durch A den Mittelwert der Gruppe. Diese Regel setzt voraus, dass das Framework diese Normalisierung nicht bereits vornimmt. Bei einem Werkzeug, das die Akkumulation übernimmt, lesen Sie dessen Vertrag nach, bevor Sie eine manuelle Division hinzufügen.
Bei einem mittleren Verlust pro Token verändern unterschiedliche Längen den Nenner. Die Summe der Verluste muss auf die tatsächlich überwachten Tokens der Gruppe bezogen werden, ohne Padding und ignorierte Positionen. Der Mittelwert der Microbatch-Mittelwerte liefert in der Regel nicht dasselbe Ziel.
Theoretisches Beispiel: Ein Microbatch zählt 512 überwachte Tokens mit einem mittleren Verlust von 2; ein anderer zählt 1 536 mit einem Mittelwert von 4. Der gewichtete Mittelwert beträgt (512 × 2 + 1 536 × 4) ÷ 2 048 = 3,5. Der ungewichtete Mittelwert beträgt 3 und überbewertet die kleine Gruppe. Diese Werte dienen nur der Veranschaulichung der Berechnung.
Technische Quellen: Hugging Face Accelerate — Akkumulation mit Beispielen variabler Größe
Eine vollständige Akkumulationsgruppe organisieren
Legen Sie zunächst die Grenzen der Gruppe und ihren Nenner fest. Berechnen Sie für jeden Microbatch die Ausgabe, den normalisierten Verlust und den Rückwärtsdurchlauf ohne zwischenzeitliches Update. Geben Sie Ausgaben frei, die Sie nicht mehr benötigen; das Aufbewahren von Verlusten, die an ihren Graphen gebunden sind, in einer Liste kann die Lebensdauer der Allokationen verlängern.
Wenden Sie nach dem letzten Beitrag die vorgesehenen Operationen auf den vollständigen Gradienten an, dann das Update. Setzen Sie anschließend die Gradienten für die nächste Gruppe zurück. Wenn der Durchlauf mit weniger als A Microbatches endet, entscheiden Sie ausdrücklich, ob Sie diese Teilgruppe mit ihrem echten Nenner verarbeiten oder sie verwerfen; notieren Sie die betroffenen Beispiele.
Bei gemischter Präzision mit GradScaler bleibt der Skalierungsfaktor während der Akkumulation konstant. Die tatsächliche Rückskalierung und ein eventuelles Clipping erfolgen nach den Beiträgen; die Aktualisierung des Scalers folgt dem Schrittversuch. Prüfungen auf nicht-endliche Werte können die Änderung der Parameter verhindern.
Der Scheduler muss der von Ihrer Schleife angekündigten Einheit folgen. Ist er pro Update des Optimierers definiert, würde ein Aufruf bei jedem Microbatch den Zeitplan verändern. Erfassen Sie Versuche und tatsächlich angewendete Updates getrennt, wenn Ihr System einige überspringen kann.
Technische Quellen: PyTorch — Autograd-Graphen und für backward aufbewahrte Tensoren · PyTorch — Akkumulation, Unscale, Clipping und GradScaler
Bei Multi-GPU Reduktion und Verteilung der Beispiele überprüfen
DistributedDataParallel synchronisiert die Gradienten zwischen den Repliken. In seinem üblichen Verhalten mittelt die Reduktion sie; ein summierter Verlust und ein lokal gemittelter Verlust haben daher nicht dieselbe Skala. Bei unterschiedlichen Token-Anzahlen je Replike müssen der globale Nenner und diese Reduktion gemeinsam betrachtet werden.
Überprüfen Sie die tatsächlich verarbeiteten IDs: Dieselben Beispiele versehentlich auf allen Karten zu duplizieren, erhöht die Information der Gruppe nicht entsprechend. Um zwischenzeitliche Kommunikationen zu verzögern, kann no_sync bei den Microbatches vor der abschließenden Synchronisation verwendet werden; sein Kontext muss auch den Vorwärtsdurchlauf abdecken.
Übertragen Sie diese Regel nicht auf alle verteilten Systeme. Sharding der Zustände, Pipeline, Kommunikations-Hooks und Frameworks können die effektiven Operationen verändern. Beginnen Sie mit der von Ihrem Werkzeug unterstützten Konfiguration und prüfen Sie dann eine vollständige Gruppe auf jeder Replike.
Technische Quellen: PyTorch — Gradientenreduktion und Geltungsbereich von no_sync in DDP
Warum dieselbe effektive Batch-Größe nicht dieselbe Erfahrung garantiert
Die Gleichung m × A × D ist eine Zählung. Um einen Gradienten eines großen Batches zurückzugewinnen, braucht man insbesondere korrekt gewichtete Beiträge, denselben Parameterzustand während der Gruppe und mit dieser Zerlegung kompatible Operationen. Die numerische Nähe wird mit einer geeigneten Toleranz überprüft; sie lässt sich nicht aus dem Produkt allein ableiten.
BatchNorm berechnet Statistiken aus den Eingaben seines Durchlaufs: mehrere kleine Mikrobatches präsentieren ihm nicht dieselben Gruppen wie ein großes Batch. Zufällige Operationen, die Reihenfolge der Berechnungen und Rundungen können ebenfalls variieren. Versprechen Sie keine bitgenau identischen finalen Gewichte.
Eine Änderung des globalen Batch kann auch die Anzahl der Aktualisierungen bei gleicher Anzahl gesehener Beispiele verändern. Legen Sie im Voraus die Vergleichsachse und Ihre Qualitätsregel fest. Ändern Sie nicht gleichzeitig Lernrate, Scheduler und Dauer, ohne diese neuen Annahmen zu dokumentieren.
Technische Quellen: PyTorch — BatchNorm1d-Statistiken · PyTorch — Grenzen der Reproduzierbarkeit
Speicher kontrollieren und über das weitere Vorgehen entscheiden
Instrumentieren Sie eine Gruppe einschließlich der Rückwärtsdurchläufe und der ersten Aktualisierung, dann die folgenden Gruppen. Ein Erfolg im Forward validiert nicht die Gradienten oder die vom Optimierer erzeugten Zustände. Die Zähler müssen ihren Geltungsbereich pro Device beibehalten. Das Speicher-Dossier liefert die Methode zum Ablesen der Baselines und Spitzen.
Wenn eine Gruppe fehlschlägt, reduzieren Sie das Mikrobatch und berechnen Sie A neu, um das angestrebte effektive Batch beizubehalten, sofern diese Wahl weiterhin sinnvoll ist. Diese Änderung garantiert weder eine proportionale Aufteilung der Spitze noch eine bessere Dauer. Wenn die Gewichte oder Zustände dominieren, kann die Akkumulation allein unzureichend sein.
Kontrollieren Sie vor einer Kampagne eine Aktualisierung auf einem kleinen, beherrschten Datensatz: dieselben Beispiele, gewichtete Loss, endliche Gradienten, Gruppengrenze und Anzahl der Schritte. Bewerten Sie dann die Qualität mit dem gewählten Protokoll. Das kleine Inferenz-MLP aus dem herunterladbaren Dossier führt dieses Trainingsrezept nicht aus; es ersetzt diese Kontrolle nicht.
Ihr abschließendes Datenblatt vereint m, A, D, die überwachten Tokens, die Präzision, die Normalisierung, die Behandlung der letzten Gruppe und die beobachteten Spitzen. Kehren Sie anschließend zur Wahl der Konfiguration und zum Experimentbudget zurück und trennen Sie Vorbereitung, Versuche und tatsächlich akzeptierte Ergebnisse.
- Ungewöhnlich kleiner Loss: nach einer doppelten Division durch die Akkumulation suchen.
- Ergebnis variiert mit der Aufteilung: ignorierte Tokens und Mittelwert der Mittelwerte prüfen.
- Akkumulation ohne Wirkung: zero_grad und optimizer.step prüfen.
- Wachsender Speicher: nach zwischen Mikrobatches beibehaltenen Referenzen suchen.
- Verschobener Zeitplan: Rückwärtsdurchläufe und Aktualisierungen unterscheiden.
Technische Quellen: Hugging Face — Speicher-Snapshots eines Trainings
Praktische Fragen
Multipliziert das Akkumulieren von sechzehn Mikrobatches den Speicher mit sechzehn?
Nicht unbedingt: Die Beiträge werden nacheinander verarbeitet. Die Gradienten bleiben bestehen, während unnötige Aktivierungen freigegeben werden können. Die Spitze hängt jedoch vom Modell, den beibehaltenen Referenzen und den Optimiererzuständen ab; messen Sie die vollständige Gruppe.
Verdoppeln zwei GPUs immer das effektive Batch?
Nur wenn diese GPUs als zwei Datenrepliken mit dem angegebenen Mikrobatch teilnehmen. Karten, die sich ein und dasselbe Modell teilen, bilden nicht automatisch zwei Repliken. Prüfen Sie die verteilten Gruppen und die verarbeiteten Beispiele.
Kann ich alle Losses durch die Anzahl der Akkumulationen teilen?
Diese einfache Regel entspricht Mikrobatches mit gleichem Gewicht, ohne bereits vom Framework gehandhabte Normalisierung. Bei variablen Anzahlen überwachter Tokens oder einer unvollständigen letzten Gruppe verwenden Sie den tatsächlichen Nenner des Ziels.