Fehlerbehebung

Dieser Leitfaden enthält Informationen zur Fehlerbehebung für Nutzer, die ihre eigenen TensorFlow-Modelle auf Cloud TPU ausführen möchten. Ein allgemeiner Leitfaden zum Einstieg in Cloud TPU finden Sie in der Kurzanleitung oder der MNIST-Anleitung.

Übersicht

Die empfohlene Strategie für die Ausführung von TensorFlow-Modellen in Cloud TPU ist die Verwendung der TPUEstimator API. Wenn Sie die Estimator API für TensorFlow bereits nutzen, müssen Sie in der Regel nur wenige Zeilen Code ändern, um zu TPUEstimator zu wechseln. Zum Laden von Daten in TPUEstimator wird die Verwendung der tf.data API empfohlen. Das MNIST-Beispiel unter TPUEstimator API mit Cloud TPU verwenden ist ein Praxisbeispiel für die Implementierung von TPUEstimator und tf.data. Weitere Informationen finden Sie unter MNIST Estimator zu TPUEstimator portieren.

Prüfen Sie nach der Konvertierung des Modells in TPUEstimator, ob es mit dem Flag use_tpu=False korrekt funktioniert. Wird das Flag auf "false" festgelegt, greift TensorFlow auf die Estimator API zurück und verwendet keinen TPU-spezifischen Code. Beliebige Probleme, die beim Ausführen Ihres Modells mit use_tpu=False auftreten, stehen in keinem Zusammenhang mit der TPU und werden in dieser Anleitung nicht behandelt. Weiterführende Informationen dazu finden Sie in der TensorFlow-Programmieranleitung.

Sobald ein Modell erfolgreich mit TPUEstimator und use_tpu=False ausgeführt werden kann, muss für dessen Ausführung auf der TPU idealerweise nur use_tpu=True festgelegt und master auf eine TPU-Server-URL verwiesen werden (in der Regel mithilfe eines Cluster-Resolvers). Da TensorFlow-Modelle jedoch sehr komplex sein können und die TPU ihre eigene Ausführungs-Engine verwendet, können TPU-spezifische Probleme auftreten. Diese Probleme können in folgende Kategorien gegliedert werden:

  1. Das Trainingsskript kann keine Verbindung zum TPU-Server herstellen.

  2. Die TPU gibt bei dem Versuch, das Modell auszuführen, einen Fehler zurück.

  3. Das Modell überschreitet den Speicherplatz der TPU.

  4. Das Modell kann auf der TPU ausgeführt werden, die Trainingsgeschwindigkeit entspricht jedoch nicht den Erwartungen.

  5. Das Modell kann auf der TPU ausgeführt werden, die Genauigkeit des mit der TPU trainierten Modells ist jedoch geringer als die ursprüngliche mit der CPU/GPU trainierte Variante.

Darüber hinaus enthält diese Anleitung FAQ zur allgemeinen Funktionalität von TPUs.

Weitere spezielle Informationen zum Portieren bestimmter Typen neuronaler Netzwerke auf die TPU finden Sie in den Anleitungen zu Cloud TPU.

Fehler beim Herstellen einer Verbindung zum TPU-Server

Zum Ausführen eines Modells auf der TPU müssen Sie eine Remote-TPU-Server-URL an den master-Parameter in RunConfig übergeben. Im Hintergrund baut TensorFlow eine Remote-tf.Session mit diesem Server auf. Dieser Abschnitt enthält Informationen zur Fehlerbehebung in Situationen, in denen sich TensorFlow beim Herstellen einer Verbindung zum TPU-Server aufhängt oder einen Fehler ausgibt. Beachten Sie, dass der Schritt zur Kompilierung des TPU-Graphen bei großen Modellen sehr lange dauern kann. Das Skript sollte daher mindestens 5 Minuten lang ausgeführt werden, um zu ermitteln, ob es angehalten wurde.

Der erste Schritt besteht darin, zu prüfen, ob es sich um ein Problem mit dem Server selbst oder mit Ihrer TensorFlow-Trainings-Pipeline handelt. Führen Sie dazu die Schritte der MNIST-Anleitung über Ihre TPU-Server-URL aus und prüfen Sie, ob sie ordnungsgemäß funktioniert. Wenn weiterhin Probleme beim Herstellen der Verbindung mit der MNIST-Anleitung bestehen, bestätigt dies, dass ein Problem beim TPU-Server vorliegt. Was in diesem Fall zu tun ist:

  1. Führen Sie den folgenden Befehl aus, um die verfügbaren TPUs aufzulisten:

    (vm)$ gcloud compute tpus list
    

    Sie müssen möglicherweise auch Ihre zone und Ihr project festlegen, wie in der MNIST-Anleitung gezeigt. Dabei wird beispielsweise Folgendes ausgegeben:

    NAME       ZONE           ACCELERATOR_TYPE  NETWORK_ENDPOINT   NETWORK  RANGE          STATUS
    demo-tpu   us-central1-b  v2-8              10.240.1.2:8470    default  10.240.1.0  READY

  2. Prüfen Sie, ob Sie den richtigen Wert an --tpu übergeben haben (demo-tpu im Beispiel oben) und ob diese TPU als READY gelistet ist. Achten Sie auch darauf, dass zone und project folgendermaßen eingestellt wurden:

    (vm)$ gcloud config set project your-project-name
    
    (vm)$ gcloud config set compute/zone us-central1-b
    
  3. Wenn Ihre TPU nicht als READY gelistet ist oder Sie weiterhin keine Verbindung herstellen können, starten Sie mit gcloud compute tpus stop $TPU_SERVER_NAME && gcloud compute tpus start $TPU_SERVER_NAME den Server manuell neu. Im obigen Beispiel entspricht $TPU_NAME demo-tpu. Dieser Vorgang kann einige Minuten dauern.

  4. Führen Sie den oben genannten Befehl ... tpus list noch einmal aus und warten Sie, bis sich die TPU im READY befindet. Dieser Vorgang kann einige Minuten dauern.

  5. Versuchen Sie, die MNIST-Anleitung noch einmal auszuführen.

  6. Wenn Sie weiterhin Probleme beim Ausführen der MNIST-Anleitung haben, können Sie über einen der unter Support beschriebenen Wege Unterstützung anfordern.

Wenn das MNIST-Beispiel korrekt ausgeführt wird, Ihr Modell jedoch weiterhin nicht reagiert, ist dies wahrscheinlich auf Ihre Trainingspipeline zurückzuführen. Prüfen Sie zuerst, ob Ihr Modell die TPUEstimator API verwendet, da diese nicht nur die komplexe Verarbeitungspipeline, sondern auch den mühelosen Wechsel zwischen der TPU- und Nicht-TPU-Ausführung mit dem Flag use_tpu unterstützt. Weitere Informationen und Beispiele für die Verwendung von TPUEstimator finden Sie in den TPU-Anleitungen. Sobald Ihr Modell die TPUEstimator API verwendet, prüfen Sie, ob sie ordnungsgemäß ausgeführt wird, wenn use_tpu=False festgelegt ist. Wird Ihr Modell nicht ordnungsgemäß ausgeführt, wenn use_tpu=False festgelegt ist, hängt das Problem nicht mit der TPU zusammen.

Behebung von allgemeinen Fehlern

Das lokale Dateisystem kann nicht verwendet werden.

Fehlermeldung

InvalidArgumentError: Unimplemented: File system scheme '[local]' not implemented

Details

Alle Eingabedateien und das Modellverzeichnis müssen einen Pfad zu einem Cloud Storage-Bucket verwenden (gs://bucket-name/... ) und dieser Bucket muss über den TPU-Server zugänglich sein. Beachten Sie, dass alle Datenverarbeitungs- und Modellprüfpunkte auf dem TPU-Server und nicht auf dem lokalen Computer ausgeführt werden. Informationen zum ordnungsgemäßen Konfigurieren von Cloud Storage für die Verwendung mit der TPU finden Sie im Leitfaden Verbindung mit Cloud Storage-Buckets herstellen.

tf.data.Dataset.cache() kann nicht im lokalen Dateisystem zwischengespeichert werden

Fehlermeldung

tensorflow.python.framework.errors_impl.UnimplementedError: File system scheme '[local]' not implemented (file: '[filename].lockfile')

Details

Ein tf.data.Dataset kann im Cache gespeichert werden. Der Aufruf .cache() kann auf zwei Arten implementiert werden:

  1. Im Arbeitsspeicher, wenn kein Argument übergeben wird.

  2. Im Dateisystem, wenn ein Dateipfad als Argument übergeben wird.

Auf Cloud TPU funktioniert die 1. Variante, solange der verfügbare Arbeitsspeicher ausreicht. Die 2. Variante mit der Speicherung im lokalen Dateisystem funktioniert jedoch nicht und führt zu einem Fehler.

Die folgenden Code-Snippets veranschaulichen die zwei Situationen:

(1)
 import tensorflow as tf

def main():
  print('Hello world!')
  ds = tf.data.Dataset.range(10)
  ds = ds.cache()

runs to completion.

(2)
 import tensorflow as tf

def main():
  print('Hello world!')
  ds = tf.data.Dataset.range(10)
  ds = ds.cache('/tmp/foo')

generates the error.

In der API-Anleitung finden Sie ausführlichere Informationen zu tf.data.Dataset.cache().

Nicht unterstützter Datentyp

Fehlermeldung

TypeError: DataType is not a supported TPU infeed type.

Details

Derzeit werden auf der TPU nur die Datentypen tf.float32, tf.int32, tf.bfloat16 und tf.bool unterstützt. Andere gängige Datentypen, wie tf.uint8, tf.string und tf.int64, müssen während der Datenvorverarbeitung in einen der unterstützten Datentypen konvertiert werden (d. h. in input_fn von TPUEstimator). Ein weiteres Beispiel finden Sie in der MNIST-Anleitung. Dieses Code-Snippet von MNIST wandelt zum Beispiel einen image-Tensor, der als Bytefolge tf.uint8 gespeichert ist, in einen tf.float32-Tensor um:

image = tf.decode_raw(image, tf.uint8)
image = tf.cast(image, tf.float32)
image = tf.reshape(image, [784])

Mit diesem Snippet wird ein als tf.int64 gespeicherter label-Tensor in einen tf.int32-Tensor konvertiert:

label = tf.cast(label, tf.int32)

Dynamische Formen werden nicht unterstützt

Fehlermeldung

ValueError: shape [Shape] must have a fixed size for dimension d that is known at graph construction time.

Details

Um ein Modell auf der TPU auszuführen, kompiliert TensorFlow das Modell mit dem XLA-Framework. Während dieser Kompilierungsschritt die Trainingsgeschwindigkeit und die Speichernutzung signifikant verbessert, müssen die Formen (Dimensionsgrößen) aller Tensoren im Graphen statisch sein, d. h. deren Werte müssen beim Kompilieren des Graphen bekannt sein. Wenn beim Kompilieren keine Formen erkannt werden können, schlägt die TPU-Kompilierung mit einem Fehler wie dem obigen fehl.

Ein gängiges Verfahren, das eine dynamische Form zurückgibt, ist dataset.batch(batch_size), da die Anzahl der in einem Stream verbleibenden Stichproben möglicherweise geringer ist als die Batchgröße. Verwenden Sie daher beim Training auf der TPU tf.contrib.data.batch_and_drop_remainder(batch_size). Dadurch werden möglicherweise die letzten Stichproben aus einer Datei gelöscht, damit jeder Batch die statische Form batch_size aufweist. Beispiel:

dataset = ...
dataset = dataset.apply(tf.contrib.data.batch_and_drop_remainder(batch_size))

Nicht verfügbare TensorFlow-Operation

Fehlermeldung

NotFoundError: No registered 'OpName' OpKernel for XLA_TPU_JIT devices compatible with node

Details

Das Modell verwendet eine TensorFlow-Operation, die derzeit nicht auf der TPU verfügbar ist.

Eine Liste der auf der TPU verfügbaren Operationen sowie Pläne für zukünftige Unterstützung und Vorschläge für Workarounds finden Sie in der Anleitung zu verfügbaren TensorFlow-Operationen.

Fehlermeldung aufgrund von fehlendem Speicherplatz

Fehlermeldung

ResourceExhaustedError: Ran out of memory in memory space hbm; used: YYY; limit: 7.48G.

Details

Jede Cloud TPU besteht aus acht TPU-Kernen, die jeweils 8 GB RAM (oder HBM, High-Bandwidth Memory) haben. Dieser Speicher dient zum Speichern der Gewichtungssensoren (Variable) sowie der Zwischenergebnistensoren, die für die Gradientenberechnung benötigt werden. Wenn das Modell für den TPU-RAM zu groß ist, schlägt die Initialisierung fehl und die obige Fehlermeldung wird ausgegeben. Weitere Informationen finden Sie unter Arbeitsspeichernutzung reduzieren.

CrossShardOptimizer wird nicht verwendet

Fehlermeldung

ValueError: CrossShardOptimizer must be used for model training on TPUs.

Details

Bei der Definition eines Modells mit der TensorFlow Python API muss der Großteil des vom Nutzer geschriebenen Codes nicht speziell auf die TPU abgestimmt sein. Die wichtigste Ausnahme ist das Optimierungstool, das in tf.contrib.tpu.CrossShardOptimizer() eingeschlossen werden muss, wie nachstehend gezeigt:

optimizer = tf.train.GradientDescentOptimizer(learning_rate=learning_rate)
if FLAGS.use_tpu:
  optimizer = tf.contrib.tpu.CrossShardOptimizer(optimizer)
train_op=optimizer.minimize(loss, tf.train.get_global_step())

Jede Cloud TPU besteht aus 8 TPU-Kernen, die unabhängige Verarbeitungseinheiten sind. Für jeden Trainingsschritt (d. h. Gewichtungsaktualisierung) führt jeder TPU-Kern die Vorwärtsdurchlauf- und Gradientenberechnung an einem unabhängigen Mini-Datenbatch durch. Danach tauschen alle Kerne Gradienten untereinander aus. In den meisten Fällen entspricht dies mathematisch der Berechnung der Gradienten in einem großen Batch, obwohl einige Einschränkungen unter Datenfragmentierung erläutert werden.

Dieser Gradientenaustausch wird von CrossShardOptimizer ausgeführt. Standardmäßig berechnet CrossShardOptimizer Gradienten des mittleren Verlusts über die Kerne, kann jedoch so konfiguriert werden, dass durch Übergabe von reduction=losses.Reduction.SUM der Gesamtverlust berechnet wird.

Verbindung zum TPU-Server nicht möglich

Fehlermeldung

An error was raised while a session was being created. This may be due to a preemption of a connected worker or parameter server. A new session is created.

Details

Dieser Fehler wird ausgegeben, wenn TensorFlow keine Verbindung mit der URL des TPU-Servers herstellen kann, die an master übergeben wird. Weitere Informationen finden Sie im Abschnitt Fehler bei der Verbindung zum TPU-Server.

Fehler während des Trainings

Wenn ein Modell auf der TPU nicht erfolgreich ausgeführt werden kann, werden alle damit verbundenen Fehler während der Initialisierung abgefangen. Daher ist es selten, dass ein Modell während des Trainings fehlschlägt. Wenn dies der Fall ist, ist die wahrscheinlichste Ursache ein Problem in der Funktion für Datenvorverarbeitung. Wenn Sie beispielsweise die Dataset API verwenden, müssen Sie in der Regel dataset = dataset.repeat() aufrufen. Andernfalls schlägt das Training fehl, nachdem die Daten einmal durchlaufen wurden. Dynamische Ausführungsvorgänge wie tf.while_loop() können auch nur in Abhängigkeit von den Eingabedaten fehlschlagen. Es besteht auch die seltene Möglichkeit von irreführenden Hardware- oder Netzwerkfehlern.

Probleme beim Beenden der Ausführung

Wenn TensorFlow während der TPU-Ausführung einen Fehler feststellt, scheint das Skript manchmal hängen zu bleiben, anstatt die Operation zu beenden und zur Shell zurückzukehren. Drücken Sie in diesem Fall die Tastenkombination CTRL+\ auf der Tastatur, um einen SIGQUIT auszulösen, wodurch Python sofort beendet wird.

Entsprechend wird mit der Tastenkombination CTRL+C während der TPU-Ausführung TensorFlow nicht sofort heruntergefahren, sondern bis zum Ende der aktuellen Iterationsschleife gewartet, um die Operation ordnungsgemäß zu beenden. Wenn Sie CTRL+\ drücken, wird Python sofort beendet.

Falls bei einem neuen Verbindungsaufbau zum TPU-Server nach einer solchen Beendigung neue Fehler wie DeadlineExceededError auftreten, setzen Sie den TPU-Server mit dem Befehl gcloud compute tpus stop $TPU_SERVER_NAME && gcloud compute tpus start $TPU_SERVER_NAME manuell zurück, wobei $TPU_SERVER_NAME aus der ersten Spalte des Befehls gcloud compute tpus list übernommen wird.

Arbeitsspeichernutzung reduzieren

Wenn beim Ausführen Ihres Modells auf der TPU ein Fehler aufgrund fehlenden Speichers auftritt, müssen Sie Maßnahmen ergreifen, um die Arbeitsspeichernutzung des Modells zu reduzieren. In diesem Abschnitt werden verschiedene spezifische Ursachen für Speicherprobleme beschrieben und Richtlinien zum Beheben dieser Probleme bereitgestellt.

Große Anzahl von Modellgewichtungen

Mögliche Ursache des Speicherproblems

Für jede Modellgewichtung vom Typ float32 sind 4 Byte erforderlich. Diese Gewichtungen werden auf jedem TPU-Kern repliziert. Daher ist ein Modell mit mehreren hundert Millionen Gewichtungen wahrscheinlich zu groß für die TPU.

So reduzieren Sie die Arbeitsspeichernutzung

  1. Bestimmte Optimierungstools benötigen zusätzlichen Arbeitsspeicher pro Gewichtung, um Aktualisierungsstatistiken zu speichern. Insbesondere benötigen AdamOptimizer und AdadeltaOptimizer jeweils zusätzliche 8 Byte pro Gewichtung. AdagradOptimizer und MomentumOptimizer erfordern zusätzliche 4 Byte pro Gewichtung. Das Standardoptimierungstool GradientDescentOptimizer erfordert keinen zusätzlichen Speicher, erzielt jedoch im Hinblick auf die endgültige Modellgenauigkeit möglicherweise nicht so gute Leistungen wie andere Optimierungstools. Das experimentelle Optimierungstool AdafactorOptimizer benötigt fast keinen zusätzlichen Speicher und funktioniert genauso gut wie das Optimierungstool Adam beim Training von Transformer-Modellen.
  2. Wenn es sich bei den meisten Gewichtungen um Worteinbettungen handelt, hat die Verwendung von Methoden wie WordPiece gezeigt, dass die Vokabulargröße deutlich reduziert und die Genauigkeit bei verschiedenen Aufgaben gleichzeitig erhöht wurde.
  3. Ein künftiger Release von TensorFlow wird 16-Bit-Gleitkommagewichtungen und -Gradienten in der experimentellen Phase unterstützen, wodurch der Arbeitsspeicherbedarf um die Hälfte reduziert wird.

Übermäßiges Padding von Tensoren

Mögliche Ursache des Speicherproblems

Tensoren im TPU-Speicher werden mit Leerzeichen aufgefüllt, d. h. die TPU rundet die Größen von Tensoren ab, die im Speicher abgelegt sind, damit Berechnungen effizienter durchgeführt werden. Das Padding erfolgt auf transparente Weise auf der Hardwareebene und hat keine Auswirkungen auf die Ergebnisse. In bestimmten Fällen kann Padding jedoch zu einer deutlich erhöhten Speicherauslastung und Ausführungszeit führen.

So reduzieren Sie die Arbeitsspeichernutzung

Die TPU-Software versucht, Tensoren im Speicher auszulegen, um die Rechenleistung zu maximieren und das Padding zu minimieren. Dieser Speicher-Layout-Prozess ist jedoch komplex. Zur Erzielung optimaler Ergebnisse sollte das Modell nach folgender Faustregel ausgelegt werden. Wenn der Speicheraufwand minimiert und die Recheneffizienz maximiert werden soll, muss eine der folgenden Bedingungen zutreffen:

  • Die Gesamt-Batchgröße sollte ein Vielfaches von 64 sein (8 pro TPU-Kern). Die Feature-Dimensionen sollten ein Vielfaches von 128 sein.

    Oder

  • Die Gesamt-Batchgröße sollte ein Vielfaches von 1.024 (128 pro TPU-Kern) sein. Die Feature-Dimensionen sollten ein Vielfaches von 8 sein.

Die Verwendung einer Batchgröße von 1.024 und von Feature-Dimensionen, die ein Vielfaches von 128 sind, ermöglicht eine optimale Effizienz, obwohl dies unter Umständen nicht für alle Modelle möglich ist. Der Einfachheit halber bezieht sich "Feature-Dimension" auf die versteckte Größe einer vollständig verbundenen Ebene oder die Anzahl der Ausgabekanäle in einer Faltung. Nicht alle Ebenen können dieser Regel entsprechen. Dies gilt insbesondere für die erste und die letzte Ebene des Netzwerks. Das ist in Ordnung und die meisten Modelle erfordern voraussichtlich ein gewisses Maß an Padding.

Batchgröße ist zu groß

Mögliche Ursache des Speicherproblems

Beim Trainieren eines neuronalen Netzwerks auf einer CPU, GPU oder TPU hat die Speichernutzung zwei Ursachen:

  1. Speichern der Gewichtungen, der Gewichtungsgradienten und Statistiken, die für das Optimierungstool spezifisch sind, z. B. Momentum. Die Arbeitsspeichernutzung ist direkt proportional zur Anzahl der Gewichtungen im Modell, jedoch nicht zur Batchgröße.
  2. Speichern von Zwischenaktivierungen aus dem Vorwärtsdurchlauf, die für die Berechnung des Rückwärtsdurchlaufs erforderlich sind. Die Arbeitsspeichernutzung ist direkt proportional zur Batchgröße, zu den Ebenengrößen und zur Anzahl der Ebenen.

Daher hängt der von einem Modell benötigte Speicher weitgehend von der Batchgröße ab.

So reduzieren Sie die Arbeitsspeichernutzung

Versuchen Sie, die Batchgröße langsam dem Speicher entsprechend zu reduzieren und achten Sie darauf, dass die Gesamt-Batchgröße ein Vielfaches von 64 ist (die Batchgröße pro Kern sollte ein Vielfaches von 8 sein). Beachten Sie, dass größere Batches auf der TPU effizienter sind. Eine Gesamt-Batchgröße von 1.024 (128 pro Kern) ist im Allgemeinen ein guter Ausgangspunkt.

Modell ist zu groß

Mögliche Ursache des Speicherproblems

Der von einem Modell benötigte Speicher hängt stark von der Anzahl der Operatoren im Graph ab (d. h. den Ebenen im Netzwerk). Diese Speicheranforderung besteht unabhängig von der Anzahl der Gewichtungen. Beispielsweise kann die Berechnung des Gradienten eines Operators wie tf.nn.conv2d() die Speichernutzung zusätzlich zu jedem Speicher erhöhen, der zum Speichern von Gewichtungen verwendet wird.

Die TPU-Engine versucht, bestimmte Operatoren strategisch neu zu berechnen, um das Modell an den Arbeitsspeicher anzupassen (sogenannte Rematerialisierung, ähnlich wie die Gradienten-Prüfpunktausführung), dies ist jedoch nicht immer möglich.

So reduzieren Sie die Arbeitsspeichernutzung

Wenn das Modell auch mit einer kleinen Batchgröße (z. B. 64) nicht auf der TPU ausgeführt werden kann, versuchen Sie, die Anzahl der Ebenen oder die Ebenengrößen zu reduzieren. Ein künftiger Release von TensorFlow wird "Modellparallelität" auf der TPU unterstützen, wodurch deutlich größere Modelle auf Cloud TPU ausgeführt werden können. Dabei werden verschiedene Teile des Modells auf verschiedenen TPU-Kernen ausgeführt.

Verbesserung der Trainingsgeschwindigkeit

Wenn Ihr Modell erfolgreich auf der TPU ausgeführt werden kann, die Trainingsgeschwindigkeit jedoch geringer als erwartet ist, finden Sie in diesem Abschnitt eine Beschreibung der verschiedenen Möglichkeiten zur Verbesserung der Geschwindigkeit.

Zu geringe Anzahl von Iterationen pro Schleife

Beschreibung des Leistungsproblems

Mit dem Parameter iterations_per_loop für TPUConfig wird gesteuert, wie viele Datensammlungen pro "Trainingsschleife" an die TPU gesendet werden. Jede Trainingsschleife erfordert umfangreiche Kommunikation zwischen dem lokalen Computer und dem TPU-Server. Wenn also iterations_per_loop zu klein ist, kann das Training erheblich verlangsamt werden.

So ermitteln Sie, ob Ihr Modell betroffen ist

Wenn die Logging-Meldung Enqueue next (X) batch(es) of data to infeed sehr häufig ausgegeben wird (z. B. alle 3 Sekunden), könnte dies bei Ihrem Training zu einem erheblichen Mehraufwand durch die Trainingsschleife führen.

So leiten Sie Gegenmaßnahmen ein

Setzen Sie iterations_per_loop auf einen höheren Wert. In der MNIST-Anleitung wird dies durch das Flag --iterations gesteuert. Solange die Meldung Enqueue next (X) batch(es) of data to infeed nicht öfter als einige Male pro Minute ausgegeben wird, sollte der aktuelle Wert ausreichend sein. iterations_per_loop kann auf einen sehr hohen Wert gesetzt werden, mit dem einzigen Nachteil, dass das Logging und die Prüfpunktausführung von Nachrichten nur am Ende einer Schleife möglich ist.

Engpass bei der Eingabeverarbeitung

Beschreibung des Leistungsproblems

Während die TPU an einem bestimmten Datenblock trainiert, bereitet die Eingabeverarbeitungsfunktion den nächsten Datenblock auf der CPU vor. Wenn also die Eingabefunktion weniger Zeit benötigt als die Modellfunktion, sind die Kosten der Eingabeverarbeitung praktisch null. Eine Eingabefunktion, die länger als die Modellfunktion dauert, erzeugt jedoch einen Engpass.

So ermitteln Sie, ob Ihr Modell betroffen ist

Folgen Sie der Anleitung unter Cloud TPU Tools: Input Pipeline Analyzer, um die Analyse der Eingabe-Pipeline in TensorBoard aufzurufen:

Bild

Die Seite für die Analyse der Eingabe-Pipeline zeigt eine übersichtliche Zusammenfassung an, der zu entnehmen ist, ob die Eingabeverarbeitung bei Ihrem Modell einen Engpass verursacht hat. Auf derselben Seite wird auch die Ausführungszeit pro Operation angezeigt, sodass Sie problematische Operationen ermitteln können.

So leiten Sie Gegenmaßnahmen ein

Beim Laden von Daten mit der Dataset API gibt es mehrere mögliche Maßnahmen:

  1. Speichern Sie die Daten als Sammlung von tf.train.Example-Strukturen in TFRecord-Dateien und laden Sie sie mit TFRecordDataset. Beispiele finden Sie in der Dataset API-Anleitung und der ResNet-Anleitung.
  2. Verwenden Sie zum Puffern der Eingabedaten dataset.cache() und/oder dataset.prefetch(). Dadurch wird verhindert, dass sporadische Verlangsamungen beim Dateizugriff zu Engpässen führen.
  3. Legen Sie den Parameter num_parallel_calls der Funktion dataset.map() fest, um Multithread-Vorgänge vom Typ map() zu aktivieren.
  4. Führen Sie die teure Datenvorverarbeitung offline durch, sodass dafür nur einmal Kosten anfallen und nicht in jeder Epoche jedes Trainings.

Die gesamte Eingabeverarbeitung erfolgt auf CPUs, die sich auf dem TPU-Server befinden, nicht etwa auf dem lokalen Computer. Daher spielt die Geschwindigkeit des lokalen Computers keine Rolle.

Zu viele Operationen, die keine Matrixmultiplikationen sind

Beschreibung des Leistungsproblems

Die Cloud TPU kann Matrixmultiplikationen und -faltungen bei unglaublich hohen Geschwindigkeiten ausführen. Die meisten anderen TensorFlow-Operationen haben effiziente Implementierungen auf der TPU, diese sind im Verhältnis zu anderer Hardware jedoch nicht deren primäre Stärke. Daher sollte ein Modell von den Matrixmultiplikationen oder -faltungen dominiert werden, um die TPU optimal nutzen zu können.

So ermitteln Sie, ob Ihr Modell betroffen ist

In der Übersicht Cloud TPU-Tools: Op Profile wird beschrieben, wie Sie ein Leistungsprofil für Ihr Modell erstellen, das nach Operationstyp aufgeschlüsselt ist. Im Allgemeinen wird die überwiegende Mehrheit moderner neuronaler Netzwerkarchitekturen von Matrixmultiplikationen und -faltungen dominiert.

So leiten Sie Gegenmaßnahmen ein

Wenn die nicht vorhandenen Matrixmultiplikationen in Ihrem Modell hauptsächlich auf Probleme bei der Trainingsgeschwindigkeit auf anderer Hardware zurückzuführen sind, sollten Sie die Leistung dieser Modelle auf der TPU messen, um eine bessere Geschwindigkeit zu erzielen. Wenn das Fehlen von Matrixmultiplikationen eine grundlegende Eigenschaft des Modells ist, dann ist die TPU möglicherweise nicht die optimale Hardware-Wahl.

Übermäßiges Padding von Tensoren

Beschreibung des Leistungsproblems

Die TPU füllt Tensoren im Speicher auf, sodass die TPU ihre Recheneinheiten effizient nutzen kann. Durch Padding kann die Nutzung des Speichers und auch der Speicherbandbreite gesteigert werden. Weitere Informationen zu Problemen beim Padding von Tensoren und zu deren Behebung finden Sie im Abschnitt Padding von Tensoren.

Batchgröße zu klein

Beschreibung des Leistungsproblems

In der Regel führt die Verwendung größerer Batchgrößen im Hinblick auf Stichproben/Sekunde zu einer höheren Trainingsgeschwindigkeit auf der TPU.

So ermitteln Sie, ob Ihr Modell betroffen ist

Die Batchgröße jedes Modells sollte immer mindestens 64 betragen (8 pro TPU-Kern), da die TPU die Tensoren immer entsprechend der Größe auffüllt. Die ideale Batchgröße beim Training auf der TPU ist 1.024 (128 pro TPU-Kern), da hierdurch Ineffizienzen in Bezug auf die Speicherübertragung und das Padding beseitigt werden.

So leiten Sie Gegenmaßnahmen ein

Es wird empfohlen, die größte Batchgröße zu verwenden, die in den Speicher passt und ein Vielfaches von 64 ist. Der einfachste Weg, dies zu erreichen, besteht darin, mit 1.024 zu beginnen. Wenn dies zu einem Fehler aufgrund fehlenden Speichers führt, versuchen Sie, die Batchgröße zu reduzieren, bis das Modell erfolgreich ausgeführt wird. Wenn Sie die Batchgröße eines Modells ändern, müssen Sie möglicherweise andere Hyperparameter anpassen, um die gleiche Modellgenauigkeit wie die Lernrate zu erreichen. Dies muss jedoch von Fall zu Fall überprüft werden.

Ebenengrößen zu klein

Beschreibung des Leistungsproblems

Selbst wenn ein Modell von Matrixmultiplikationen oder -faltungen dominiert wird, läuft die TPU möglicherweise nicht mit voller Effizienz, wenn die Eingangstensoren klein sind. Im Vergleich zu anderer Hardware wird die TPU am effizientesten ausgeführt, wenn die Batchgröße und die Ebenengröße größer sind (z. B. Dimension >= 512).

So ermitteln Sie, ob Ihr Modell betroffen ist

Als allgemeine Regel gilt, dass Ebenengrößen kleiner als 128 eine schlechte Effizienz auf der TPU erreichen, da 128 die native Dimension der TPU-Matrixmultiplikationseinheit ist. Für vollständig verbundene Ebenen wird zur Erzielung einer hohen Effizienz eine minimale versteckte Größe von 512 empfohlen. Beachten Sie, dass Faltungsebenen in der Regel nicht so groß wie vollständig verbundene Ebenen sein müssen, um ein gleiches Effizienzniveau zu erreichen. Zum Beispiel erreicht eine 3 × 3-Faltung der Größe 256 eine ähnliche (hohe) Effizienz im Vergleich zu einer vollständig verbundenen Ebene der Größe 2.048, da 3 × 3 × 256 = 2.304.

So leiten Sie Gegenmaßnahmen ein

Wenn kleine Ebenengrößen die Hauptmotivation in Ihrem Modell darstellen, sollten Sie die Leistung Ihrer Modelle mit größeren Ebenen auf der TPU neu messen. Wenn Sie beispielsweise die Ausgabegröße einer Ebene von 256 auf 512 erhöhen, wird die Trainingszeit nur um 20 % erhöht, obwohl das Modell die Berechnung zweimal ausführt.

Modellprofilierung auf Operationsebene

Häufig ist es hilfreich, die Ausführungszeit und Speichernutzung auf der Operationsebene zu messen, um Leistungsengpässe zu identifizieren. Weitere Informationen dazu finden Sie in der Anleitung
Cloud TPU-Tools: Trace Viewer.

Debugging verringert die Modellgenauigkeit

Eines der Ziele der Cloud TPU-Umgebung ist, dass jedes Modell, das gerade auf einer CPU oder GPU trainiert wird, eine sehr ähnliche Genauigkeit erreicht, wenn es auf der TPU trainiert wird, und zwar mit möglicherweise geringeren Anpassungen an Hyperparameter wie Batchgröße und Lernrate. Gelegentlich können Nutzer jedoch eine Verschlechterung der Genauigkeit beobachten, wenn sie Modelle auf der TPU trainieren. Die Behebung solcher Probleme kann aufgrund der zufälligen Art des neuronalen Netzwerktrainings extrem frustrierend sein. In diesem Abschnitt wird erläutert, wie Sie die Ursache für die Verringerung der Modellgenauigkeit bei der Portierung eines Modells auf die TPU ermitteln können.

Informationen zur Datenfragmentierung (Datenparallelität)

Eines der Hauptziele von TensorFlow besteht darin, dass jeder Vorgang nahezu identische Ergebnisse liefert, unabhängig davon, ob er auf der CPU, GPU oder TPU ausgeführt wird. Hiervon gibt es bestimmte Ausnahmen, z. B. zufällige Vorgänge. Wenn Sie einen signifikanten Unterschied zwischen der Ausgabe nicht zufälliger Operationen auf der TPU und der CPU feststellen, melden Sie dies als Programmfehler.

Für die Trainingspipeline insgesamt besteht jedoch ein deutlicher Unterschied zwischen dem Training auf der CPU/GPU und der TPU: Bei Verwendung von TPUEstimator und use_tpu=False greift TensorFlow auf seine standardmäßige Ausführungs-Engine zurück. Diese Engine trainiert mit einem Batch pro Schritt. Beim Training auf der TPU führt TensorFlow jedoch eine Datenfragmentierung durch, die auch als Datenparallelität mit synchronem SGD bezeichnet wird. Der Grund dafür ist, dass jede Cloud TPU aus 8 TPU-Kernen besteht, die als unabhängige Verarbeitungseinheiten arbeiten. Daher wird für jeden Trainingsschritt ein Datenbatch an jeden TPU-Kern gesendet, die Gewichtungsgradienten werden berechnet, die Gradienten untereinander ausgetauscht und anschließend wird die Gewichtungsaktualisierung berechnet. Standardmäßig wird der Verlust über die Kerne gemittelt, er kann aber auch summiert werden, indem der Parameter CrossShardOptimizer geändert wird.

Wenn der Gesamtverlust des Modells als der Durchschnitt (oder die Summe) der unabhängigen Verluste pro Stichprobe berechnet werden kann, entspricht dieses Verfahren mathematisch dem Training für einen einzelnen großen Batch. Die gängigste nicht unabhängige Operation pro Stichprobe ist die Batchnormalisierung, die jeden Pro-Kern-Batch getrennt durchläuft. Wenn der Batch eine Gesamtgröße von beispielsweise 128 aufweist, beträgt die Batchgröße pro Kern 16 und jeder der 8 Kerne führt die Batchnormalisierung für die eigenen 16 Stichproben aus. In einigen Fällen hat die Durchführung der Batchnormalisierung für kleine Batches (z. B. weniger als 32) zu einer Verschlechterung der Genauigkeit geführt. Im Idealfall kann die Gesamt-Batchgröße beim Training auf der TPU groß sein (zum Beispiel 256 bis 1.024), sodass Batches dieser Größe kein ernsthaftes Problem darstellen. Wenn eine solche Batchgröße jedoch zu groß ist, um in den Speicher zu passen, muss der Fragmentierungseffekt von Fall zu Fall bewertet werden.

Aufgrund der Komplexität durch die Fragmentierung besteht der erste Schritt bei der Fehlerbehebung darin, ein deterministisches TPU-Training mit einem Kern auszuführen und es mit einem auf der CPU/GPU trainierten Modell zu vergleichen. Dies kann im Allgemeinen schnell durchgeführt werden, da kein Modell für die Konvergenz trainiert werden muss.

Deterministisches Training

Ein Grund dafür, dass es schwierig ist, Fehler im Zusammenhang mit den Unterschieden bei der Modellgenauigkeit zu beheben, besteht darin, dass TensorFlow jedes Mal, wenn ein Modell trainiert wird, eine unterschiedliche Gewichtungsinitialisierung und Datenfragmentierung verwendet. Es ist vorteilhaft, den Trainingsprozess so zu ändern, dass er deterministisch ist, damit mehrere Ausführungen nahezu identische Modelle erzeugen. In diesem Abschnitt wird die deterministische Ausführung der MNIST-Anleitung veranschaulicht:

  1. Erstellen Sie eine erste Prüfpunktdatei durch Ausführen eines einzelnen Schritts auf der CPU. Mit diesem Schritt erzielen Sie eine deterministische Gewichtungsinitialisierung. Dies kann auch durch die Ausführung eines Seedings für die variablen Initialisierer erreicht werden, gestaltet sich jedoch schwieriger.
# Run training for 1 step to create an initial checkpoint.
python mnist_tpu.py \
  --use_tpu=False \
  --data_dir=${STORAGE_BUCKET}/data/ \
  --model_dir=${STORAGE_BUCKET}/init_output \
  --random_seed=12345 \
  --iterations=1
  --train_steps=1
  1. Ändern Sie alle Funktionen der Datenfragmentierung in Ihrer Eingabefunktion, um einen zufälligen Ausgangswert zu verwenden. Dies wurde bereits im Rahmen der MNIST-Anleitung durchgeführt. Dies funktioniert für die Vorgänge der Eingabedatenverarbeitung, da diese immer auf der CPU ausgeführt werden. Zufallsvorgänge in der Modellfunktion sind zwischen der TPU und der CPU möglicherweise nicht deterministisch. Beispiel:
# In the flag definitions
tf.flags.DEFINE_integer("batch_size", None, "Random seed for training")

# In the input_fn
if FLAGS.random_seed is not None:
dataset = dataset.shuffle(seed=FLAGS.random_seed)
  1. Führen Sie das gleiche Modell zweimal auf der CPU aus, um zu prüfen, ob das Training deterministisch ist. Beachten Sie, dass das Training für eine angemessene Anzahl von Schritten (z. B. 1.000), jedoch nicht zur Konvergenz ausgeführt werden muss, da dies auf der CPU sehr langsam sein kann.

    Da das CPU-Training mit einem Einzelkern-TPU-Training verglichen wird, verwenden Sie eine vollständige Batchgröße, die auf einen einzelnen TPU-Kern passt (in der Regel die vollständige Batchgröße geteilt durch 8). TensorFlow garantiert keinen bitweisen Determinismus zwischen Ausführungen, aber der Verlust sollte den dabei erreichten Werten sehr nahe kommen:
# Copy the initial weights
gsutil mkdir ${STORAGE_BUCKET}/cpu_output_1
gsutil cp -f ${STORAGE_BUCKET}/init_output/* ${STORAGE_BUCKET}/cpu_output_1
gsutil mkdir ${STORAGE_BUCKET}/cpu_output_2
gsutil cp -f ${STORAGE_BUCKET}/init_output/* ${STORAGE_BUCKET}/cpu_output_2

# Run 1
python mnist_tpu.py \
  --use_tpu=False \
  --data_dir=${STORAGE_BUCKET}/data/ \
  --model_dir=${STORAGE_BUCKET}/cpu_output_1 \
  --batch_size=128 \
  --random_seed=12345 \
  --train_steps=2000 \
  --eval_steps=10

# Output 1
accuracy = 0.9910644, global_step = 1000, loss = 0.025323588

# Run 2
python mnist_tpu.py \
  --use_tpu=False \
  --data_dir=${STORAGE_BUCKET}/data/ \
  --model_dir=${STORAGE_BUCKET}/cpu_output_1 \
  --batch_size=128 \
  --random_seed=12345 \
  --train_steps=2000 \
  --eval_steps=10

# Output 2
accuracy = 0.9910644, global_step = 1000, loss = 0.025323414

Einzelkern-TPU-Training

Sobald Sie die MNIST-Anleitung deterministisch ausführen können, besteht der nächste Schritt darin, die CPU-trainierten Ergebnisse auf der TPU zu replizieren, wobei ein einzelner TPU-Kern verwendet wird, um festzustellen, ob das Problem mit der Datenfragmentierung oder der TPU-Ausführungsengine selbst zusammenhängt.

So führen Sie das Einzelkern-Training und die Bewertung in der MNIST-Anleitung aus:

# Use the same weight initialization as the CPU
gsutil cp -f ${STORAGE_BUCKET}/init_output/* ${STORAGE_BUCKET}/tpu_output

# Run training for 1000 steps
python mnist.py \
    --use_tpu=True \
    --master=$GRPC_SERVER \
    --train_file=${STORAGE_BUCKET}/data/train.tfrecords \
    --model_dir=${STORAGE_BUCKET}/tpu_output \
    --random_seed=12345 \
    --batch_size=128 \
    --train_steps=1000 \
    --eval_steps=10

  accuracy = 0.9910644, global_step = 1000, loss = 0.02514153

Der Verlust stimmt nicht genau mit dem CPU-trainierten Modell überein, kommt diesem jedoch nahe. Ist Letzteres bei Ihrem Modell nicht der Fall, kann dies darauf hindeuten, dass ein Fehler in der TPU-Ausführungs-Engine vorliegt. Prüfen Sie Folgendes, bevor Sie einen Fehlerbericht senden:

  1. Sie übergeben num_shards=1 an TPUConfig.

  2. In Ihrer Modellfunktion liegen keine zufälligen Operationen vor und in Ihrer Eingabefunktion wird für alle zufälligen Operationen ein korrektes Seeding ausgeführt.

  3. Sie verwenden für das CPU- und das TPU-Training dieselbe initiale Prüfpunktdatei.

Fehlerbehebung beim Mehrkern-TPU-Training

Wenn Ihr Modell den gleichen Verlust auf der CPU und der Einzelkern-TPU erreicht, liegt möglicherweise eines der folgenden Probleme vor:

(a) Die Verschlechterung ist auf die natürliche zufällige Varianz zurückzuführen, wenn neuronale Modelle mit unterschiedlichen Initialisierungen trainiert werden.

(b) Die Verschlechterung ist auf ein Problem bei der Datenfragmentierung auf der TPU zurückzuführen.

Um festzustellen, ob Problem (a) zutrifft, kann es hilfreich sein, das vollständige Modell auf der CPU/GPU und der Mehrkern-TPU mit der gleichen Gewichtungsinitialisierung zu trainieren, wie oben beschrieben.

Wenn Sie sicher sind, dass der Genauigkeitsabfall statistisch signifikant ist, handelt es sich bei den Problemen im Zusammenhang mit der Datenfragmentierung mit hoher Wahrscheinlichkeit um die Folgenden:

  1. Wenn Ihr Modell den Verlust als Summe der Fehler pro Stichprobe berechnet, möchten Sie wahrscheinlich reduction=losses.Reduction.SUM an CrossShardOptimizer übergeben. Standardmäßig berechnet CrossShardOptimizer den Mittelwert der Verluste und nicht die Summe.
  2. Wenn das Modell Batchnormalisierung verwendet, kann eine Gesamt-Batchgröße von weniger als 256 (z. B. weniger als 32 pro Kern) die Genauigkeit verringern.
  3. Wenn Ihr Modell eine Verlustfunktion pro Batch hat, wird dies durch die Fragmentierung beeinflusst. Solche Verlustfunktionen sind in der Regel ziemlich speziell. Beispiel: Karras et al. 2017 verwendet beim Trainieren eines generativen kontradiktorischen Netzwerks (GAN, Generative Adversarial Network) beispielsweise einen Batchdiskriminator.