Datenpipelines mit TPU-Geschwindigkeit: tf.data.Dataset und TFRecords

Datenpipelines mit TPU-Geschwindigkeit:
tf.data.Dataset und TFRecords

Informationen zu diesem Codelab

subjectZuletzt aktualisiert: Okt. 4, 2021
account_circleVerfasst von Martin Görner - @martin_gorner

1. Übersicht

TPUs sind sehr schnell. Die Trainingsdaten müssen mit ihrer Trainingsgeschwindigkeit Schritt halten. In diesem Lab lernen Sie, wie Sie Daten aus GCS mit der tf.data.Dataset API laden, um Ihre TPU zu speisen.

Dieses Lab ist Teil 1 von „Keras on TPU“ . Sie können sie in der folgenden Reihenfolge oder einzeln durchführen.

ca8cc21f6838eccc.png

Lerninhalte

  • So verwenden Sie die tf.data.Dataset API zum Laden von Trainingsdaten
  • Um das TFRecord-Format zum effizienten Laden von Trainingsdaten aus GCS zu verwenden

Feedback

Bitte teilen Sie uns mit, wenn Sie in diesem Code-Lab etwas nicht erkennen. Sie können Feedback über GitHub-Probleme [ feedback link] geben.

2. Kurzanleitung für Google Colaboratory

Für dieses Lab wird Google Collaboratory verwendet. Sie müssen nichts einrichten. Colaboratory ist eine Online-Notebook-Plattform für Bildungszwecke. Sie bietet kostenloses CPU-, GPU- und TPU-Training.

688858c21e3beff2.png

Sie können dieses Beispielnotebook öffnen und einige Zellen durchgehen, um sich mit Colaboratory vertraut zu machen.

c3df49e90e5a654f.png Welcome to Colab.ipynb

TPU-Back-End auswählen

8832c6208c99687d.png

Wählen Sie im Colab-Menü Laufzeit > Laufzeittyp ändern und dann „TPU“ auswählen. In diesem Code-Lab verwenden Sie eine leistungsstarke TPU (Tensor Processing Unit), die für hardwarebeschleunigtes Training unterstützt wird. Die Verbindung zur Laufzeit erfolgt bei der ersten Ausführung automatisch. Alternativ können Sie „Verbinden“ verwenden oben rechts auf die Schaltfläche.

Notebook-Ausführung

76d05caa8b4db6da.png

Führen Sie einzelne Zellen aus, indem Sie auf eine Zelle klicken und die Umschalttaste und die Eingabetaste drücken. Sie können auch das gesamte Notebook ausführen. Wählen Sie dazu Laufzeit > Alle ausführen

Inhaltsverzeichnis

429f106990037ec4.png

Alle Notebooks haben ein Inhaltsverzeichnis. Sie können ihn mit dem schwarzen Pfeil auf der linken Seite öffnen.

Ausgeblendete Zellen

edc3dba45d26f12a.png

Bei einigen Zellen wird nur der Titel angezeigt. Dies ist eine Colab-spezifische Notebook-Funktion. Sie können darauf doppelklicken, um den darin enthaltenen Code anzuzeigen, aber normalerweise ist er nicht sehr interessant. In der Regel Support- oder Visualisierungsfunktionen. Sie müssen diese Zellen trotzdem ausführen, damit die darin enthaltenen Funktionen definiert werden.

Authentifizierung

cdd4b41413100543.png

Colab kann auf Ihre privaten Google Cloud Storage-Buckets zugreifen, sofern Sie sich mit einem autorisierten Konto authentifizieren. Das obige Code-Snippet löst einen Authentifizierungsprozess aus.

3. [INFO] Was sind Tensor Processing Units (TPUs)?

Kurz und bündig

f88cf6facfc70166.png

Der Code zum Trainieren eines Modells auf einer TPU in Keras (und für den Fallback auf die GPU oder CPU, wenn keine TPU verfügbar ist):

try: # detect TPUs
    tpu
= tf.distribute.cluster_resolver.TPUClusterResolver.connect()
    strategy
= tf.distribute.TPUStrategy(tpu)
except ValueError: # detect GPUs
    strategy
= tf.distribute.MirroredStrategy() # for CPU/GPU or multi-GPU machines

# use TPUStrategy scope to define model
with strategy.scope():
  model
= tf.keras.Sequential( ... )
  model
.compile( ... )

# train model normally on a tf.data.Dataset
model
.fit(training_dataset, epochs=EPOCHS, steps_per_epoch=...)

Wir verwenden TPUs heute, um einen Blumenklassifikator mit interaktiven Geschwindigkeiten (Minuten pro Trainingslauf) zu entwickeln und zu optimieren.

688858c21e3beff2.png

Warum TPUs?

Moderne GPUs sind um programmierbare „Kerne“ organisiert, eine sehr flexible Architektur, mit der eine Vielzahl von Aufgaben wie 3D-Rendering, Deep Learning, physische Simulationen usw. ausgeführt werden können. TPUs hingegen kombinieren einen klassischen Vektorprozessor mit einer dedizierten Matrixmultiplikationseinheit. Sie eignen sich für alle Aufgaben, bei denen große Matrixmultiplikationen dominieren, z. B. neuronale Netzwerke.

8eb3e718b8e2ed08.png

Illustration: Eine dichte neuronale Netzwerkschicht als Matrixmultiplikation mit einem Batch von acht Bildern, die gleichzeitig durch das neuronale Netzwerk verarbeitet werden. Führen Sie die Multiplikation einer Zeile x Spalten durch, um zu überprüfen, ob wirklich eine gewichtete Summe aller Pixelwerte eines Bildes erstellt wird. Faltungsschichten können auch als Matrixmultiplikationen dargestellt werden, obwohl dies etwas komplizierter ist ( Erläuterung in Abschnitt 1).

Die Hardware

MXU und VPU

Ein TPU v2-Kern besteht aus einer Matrix Multiply Unit (MXU), die Matrixmultiplikationen ausführt, und einer Vector Processing Unit (VPU) für alle anderen Aufgaben wie Aktivierungen, Softmax usw. Die VPU verarbeitet float32- und int32-Berechnungen. Die MXU hingegen arbeitet in einem Gleitkommaformat mit gemischter Präzision von 16–32 Bit.

7d68944718f76b18.png

Gemischte Precision-/Gleitkommazahlen und bfloat16

Die MXU berechnet Matrixmultiplikationen mit bfloat16-Eingaben und float32-Ausgaben. Zwischenakkumulierungen werden mit der Genauigkeit float32 ausgeführt.

19c5fc432840c714.png

Das Training eines neuronalen Netzwerks ist in der Regel gegen Rauschen resistent, die durch eine reduzierte Gleitkommagenauigkeit entstehen. Es gibt Fälle, in denen das Rauschen dem Optimierungstool sogar beim Konvergieren hilft. Üblicherweise wurde 16-Bit-Gleitkommagenauigkeit zur Beschleunigung von Berechnungen verwendet, aber die Formate float16 und float32 haben sehr unterschiedliche Bereiche. Die Reduzierung der Precision von float32 auf float16 führt in der Regel zu Über- und Unterflüssen. Es gibt Lösungen, aber in der Regel ist zusätzliche Arbeit erforderlich, damit float16 funktioniert.

Aus diesem Grund hat Google das bfloat16-Format für TPUs eingeführt. bfloat16 ist eine abgeschnittene Gleitkommazahl von Gleitkommazahl32 mit genau denselben Exponentenbits und demselben Bereich wie float32. Hinzu kommt, dass TPUs Matrixmultiplikationen mit gemischter Präzision mit bfloat16-Eingaben und float32-Ausgaben berechnen, was bedeutet, dass normalerweise keine Codeänderungen erforderlich sind, um von den Leistungssteigerungen durch reduzierte Genauigkeit zu profitieren.

Systolic Array

Die MXU implementiert Matrixmultiplikationen in der Hardware mithilfe eines sogenannten „systolischen Arrays“. Architektur, in der Datenelemente durch eine Reihe von Hardware-Recheneinheiten fließen (In der Medizin bezieht sich „systolisch“ auf Herzkontraktionen und den Blutfluss, hier der Datenfluss.)

Das Grundelement einer Matrixmultiplikation ist ein Punktprodukt zwischen einer Linie aus einer Matrix und einer Spalte aus der anderen Matrix (siehe Abbildung oben in diesem Abschnitt). Für eine Matrixmultiplikation Y=X*W wäre ein Element des Ergebnisses:

Y[2,0] = X[2,0]*W[0,0] + X[2,1]*W[1,0] + X[2,2]*W[2,0] + ... + X[2,n]*W[n,0]

Auf einer GPU würde man dieses Punktprodukt in einen GPU-„Kern“ programmieren. und dann auf so vielen „Kernen“ die parallel zur Verfügung stehen, um jeden Wert der Matrix auf einmal zu berechnen. Wenn die resultierende Matrix 128 x 128 groß ist, sind 128 x 128=16.000 Kerne erforderlich. was normalerweise nicht möglich ist. Die größten GPUs haben etwa 4.000 Kerne. Eine TPU verwendet dagegen nur das absolute Minimum an Hardware für die Recheneinheiten in der MXU: nur bfloat16 x bfloat16 => float32 Multiplikationsakkumulatoren, sonst nichts. Diese sind so klein, dass eine TPU 16.000 davon in einer 128 x 128 MXU implementieren und diese Matrixmultiplikation in einem Schritt verarbeiten kann.

f1b283fc45966717.gif

Illustration: Das systolische Array von MXU. Die Rechenelemente sind Multiplikatoren. Die Werte einer Matrix werden in das Array geladen (rote Punkte). Die Werte der anderen Matrix fließen durch das Array (graue Punkte). Vertikale Linien bringen die Werte nach oben. Horizontale Linien geben Teilsummen weiter. Es bleibt dem Nutzer als Übung überlassen, um zu prüfen, ob Sie das Ergebnis der Matrixmultiplikation auf der rechten Seite erhalten, während die Daten durch das Array fließen.

Während die Punktprodukte in einer MXU berechnet werden, fließen Zwischensummen einfach zwischen benachbarten Recheneinheiten. Sie müssen nicht gespeichert und aus dem Speicher oder aus einer Registrierungsdatei abgerufen werden. Das Endergebnis ist, dass die systolische TPU-Array-Architektur bei der Berechnung von Matrixmultiplikationen einen erheblichen Dichte- und Leistungsvorteil sowie einen nicht vernachlässigbaren Geschwindigkeitsvorteil gegenüber einer GPU hat.

Cloud TPU

Wenn Sie eine " Cloud TPU v2" auf der Google Cloud Platform erhalten Sie eine virtuelle Maschine (VM) mit einer mit PCI verbundenen TPU-Platine. Die TPU-Platine hat vier Dual-Core-TPU-Chips. Jeder TPU-Kern verfügt über eine VPU (Vector Processing Unit) und eine 128 × 128 MXU (MatriX Multiplikation Unit). Diese „Cloud TPU“ normalerweise über das Netzwerk mit der VM verbunden, die sie angefordert hat. Das vollständige Bild sieht also so aus:

dfce5522ed644ece.png

Abbildung: VM mit einer mit dem Netzwerk verbundenen „Cloud TPU“ Beschleuniger. „Die Cloud TPU“ aus einer VM mit einer PCI-angehängten TPU-Platine mit vier Dual-Core-TPU-Chips.

TPU-Pods

In den Rechenzentren von Google sind TPUs mit einer Hochleistungs-Computing-Verbindung (High Performance Computing, HPC) verbunden, wodurch sie wie ein sehr großer Beschleuniger erscheinen können. Google nennt sie Pods und sie können bis zu 512 TPU v2-Kerne oder 2048 TPU v3-Kerne umfassen.

2ec1e0d341e7fc34.jpeg

Illustration: Ein TPU v3-Pod. TPU-Boards und -Racks, die über HPC Interconnect verbunden sind.

Während des Trainings werden Gradienten zwischen TPU-Kernen mit dem Algorithmus zur vollständigen Reduzierung ausgetauscht ( hier eine gute Erklärung von All-Reduce). Das trainierte Modell kann die Hardware nutzen, indem es mit großen Batchgrößen trainiert wird.

d97b9cc5d40fdb1d.gif

Illustration: Synchronisierung von Gradienten während des Trainings mit dem Algorithmus „All-Reduce“ im 2-D-Toroidal-Mesh-HPC-Netzwerk von Google TPU.

Die Software

Training mit großen Batchgrößen

Die ideale Batchgröße für TPUs liegt bei 128 Datenelementen pro TPU-Kern, aber die Hardware kann bereits mit 8 Datenelementen pro TPU-Kern eine gute Auslastung nachweisen. Denken Sie daran, dass eine Cloud TPU 8 Kerne hat.

In diesem Code-Lab verwenden wir die Keras API. In Keras ist der von Ihnen angegebene Batch die globale Batchgröße für die gesamte TPU. Ihre Batches werden automatisch in acht aufgeteilt und auf den 8 Kernen der TPU ausgeführt.

da534407825f01e3.png

Weitere Tipps zur Leistung finden Sie im TPU-Leistungsleitfaden. Bei sehr großen Batchgrößen sind bei einigen Modellen besondere Sorgfalt erforderlich. Weitere Informationen finden Sie unter LARSOptimizer.

Details: XLA

TensorFlow-Programme definieren Berechnungsgrafiken. Auf der TPU wird Python-Code nicht direkt ausgeführt, sondern der von Ihrem Tensorflow-Programm definierte Berechnungsgraph. Intern wandelt ein Compiler namens XLA (beschleunigte lineare Algebra-Compiler-) den Tensorflow-Graphen von Rechenknoten in TPU-Maschinencode um. Dieser Compiler führt auch viele erweiterte Optimierungen an Ihrem Code und Ihrem Speicherlayout durch. Die Kompilierung erfolgt automatisch, während die Arbeit an die TPU gesendet wird. Sie müssen XLA nicht explizit in Ihre Build-Kette aufnehmen.

edce61112cd57972.png

Illustration: Zur Ausführung auf TPU wird der von Ihrem Tensorflow-Programm definierte Berechnungsgraph zuerst in eine XLA-Darstellung (beschleunigte lineare Algebra-Compiler-Darstellung) übersetzt und dann von XLA in TPU-Maschinencode kompiliert.

TPUs in Keras verwenden

TPUs werden ab Tensorflow 2.1 durch die Keras API unterstützt. Keras-Unterstützung funktioniert auf TPUs und TPU-Pods. Das folgende Beispiel funktioniert mit TPU, GPU(s) und CPU:

try: # detect TPUs
    tpu
= tf.distribute.cluster_resolver.TPUClusterResolver.connect()
    strategy
= tf.distribute.TPUStrategy(tpu)
except ValueError: # detect GPUs
    strategy
= tf.distribute.MirroredStrategy() # for CPU/GPU or multi-GPU machines

# use TPUStrategy scope to define model
with strategy.scope():
  model
= tf.keras.Sequential( ... )
  model
.compile( ... )

# train model normally on a tf.data.Dataset
model
.fit(training_dataset, epochs=EPOCHS, steps_per_epoch=...)

In diesem Code-Snippet gilt Folgendes:

  • TPUClusterResolver().connect() findet die TPU im Netzwerk. Die Funktion funktioniert ohne Parameter in den meisten Google Cloud-Systemen (AI Platform-Jobs, Colaboratory, Kubeflow sowie Deep-Learning-VMs, die mit dem Dienstprogramm „ctpu up“ erstellt wurden). Diese Systeme wissen dank einer TPU_NAME-Umgebungsvariable, wo sich ihre TPU befindet. Wenn Sie eine TPU manuell erstellen, legen Sie entweder die TPU_NAME-Umgebung fest. Variable auf der VM, von der aus Sie sie verwenden, oder rufen Sie TPUClusterResolver mit expliziten Parametern auf: TPUClusterResolver(tp_uname, zone, project)
  • TPUStrategy ist der Teil, der die Verteilung und die „all-reduce“ implementiert. Algorithmus der Gradientensynchronisierung.
  • Die Strategie wird über einen Umfang angewendet. Das Modell muss innerhalb des Gebotsstrategiebereichs (Scope()) definiert werden.
  • Die Funktion tpu_model.fit erwartet ein tf.data.Dataset-Objekt als Eingabe für das TPU-Training.

Häufige TPU-Portierungsaufgaben

  • Es gibt viele Möglichkeiten, Daten in ein TensorFlow-Modell zu laden. Für TPUs ist jedoch die Verwendung der tf.data.Dataset API erforderlich.
  • TPUs sind sehr schnell und die Datenaufnahme führt bei der Ausführung oft zum Engpass. Im TPU-Leistungsleitfaden finden Sie Tools, mit denen Sie Datenengpässe erkennen können, sowie weitere Leistungstipps.
  • int8- oder int16-Zahlen werden als int32 behandelt. Die TPU hat keine Ganzzahl-Hardware, die mit weniger als 32 Bit arbeitet.
  • Einige TensorFlow-Vorgänge werden nicht unterstützt. Die Liste finden Sie hier. Die gute Nachricht ist, dass diese Einschränkung nur für Trainingscode gilt, d.h. für den Vorwärts- und Rückwärtsdurchlauf durch Ihr Modell. Sie können weiterhin alle Tensorflow-Vorgänge in Ihrer Dateneingabepipeline verwenden, da sie auf der CPU ausgeführt werden.
  • tf.py_func wird auf TPUs nicht unterstützt.

4. Daten werden geladen

c0ecb860e4cad0a9.jpeg cc4781a7739c49ae.jpeg 81236b00f8bbf39e.jpeg 961e2228974076bb.jpeg 7517dc163bdffcd5.jpeg 96392df4767f566d.png

Wir arbeiten mit einem Dataset mit Blumenbildern. Ziel ist es, zu lernen, sie in fünf Blumenarten zu unterteilen. Die Daten werden mit der tf.data.Dataset API geladen. Zunächst machen wir uns mit der API vertraut.

Praktische Übung

Öffnen Sie das folgende Notebook, führen Sie die Zellen aus (Umschalttaste + Eingabetaste) und folgen Sie den Anweisungen, wenn „ARBEITSERFORDERLICH“ angezeigt wird .

c3df49e90e5a654f.png Fun with tf.data.Dataset (playground).ipynb

Weitere Informationen

Über „Blumen“ Dataset

Das Dataset ist in 5 Ordner organisiert. Jeder Ordner enthält Blumen einer Art. Die Ordner heißen Sonnenblumen, Gänseblümchen, Löwenzahn, Tulpen und Rosen. Die Daten werden in einem öffentlichen Bucket in Google Cloud Storage gehostet. Auszug:

gs://flowers-public/sunflowers/5139971615_434ff8ed8b_n.jpg
gs
://flowers-public/daisy/8094774544_35465c1c64.jpg
gs
://flowers-public/sunflowers/9309473873_9d62b9082e.jpg
gs
://flowers-public/dandelion/19551343954_83bb52f310_m.jpg
gs
://flowers-public/dandelion/14199664556_188b37e51e.jpg
gs
://flowers-public/tulips/4290566894_c7f061583d_m.jpg
gs
://flowers-public/roses/3065719996_c16ecd5551.jpg
gs
://flowers-public/dandelion/8168031302_6e36f39d87.jpg
gs
://flowers-public/sunflowers/9564240106_0577e919da_n.jpg
gs
://flowers-public/daisy/14167543177_cd36b54ac6_n.jpg

Warum tf.data.Dataset?

Keras und Tensorflow akzeptieren Datasets in allen ihren Trainings- und Bewertungsfunktionen. Nachdem Sie Daten in ein Dataset geladen haben, bietet die API alle allgemeinen Funktionen, die für das Trainieren neuronaler Netzwerke nützlich sind:

dataset = ... # load something (see below)
dataset = dataset.shuffle(1000) # shuffle the dataset with a buffer of 1000
dataset = dataset.cache() # cache the dataset in RAM or on disk
dataset = dataset.repeat() # repeat the dataset indefinitely
dataset = dataset.batch(128) # batch data elements together in batches of 128
AUTOTUNE = tf.data.AUTOTUNE
dataset = dataset.prefetch(AUTOTUNE) # prefetch next batch(es) while training

Tipps zur Leistung und Best Practices für Datasets finden Sie in diesem Artikel. Die Referenzdokumentation finden Sie hier.

Grundlagen von tf.data.Dataset

Daten bestehen normalerweise in mehreren Dateien, hier Bildern. Sie können ein Dataset mit Dateinamen erstellen, indem Sie Folgendes aufrufen:

filenames_dataset = tf.data.Dataset.list_files('gs://flowers-public/*/*.jpg')
# The parameter is a "glob" pattern that supports the * and ? wildcards.

Anschließend können Sie eine -Funktion zu jedem Dateinamen, mit der die Datei in der Regel in tatsächliche Daten im Speicher geladen und decodiert wird:

def decode_jpeg(filename):
  bits
= tf.io.read_file(filename)
  image
= tf.io.decode_jpeg(bits)
 
return image

image_dataset
= filenames_dataset.map(decode_jpeg)
# this is now a dataset of decoded images (uint8 RGB format)

So iterieren Sie ein Dataset:

for data in my_dataset:
 
print(data)

Datasets mit Tupeln

Beim überwachten Lernen besteht ein Trainings-Dataset in der Regel aus Paaren von Trainingsdaten und richtigen Antworten. Um dies zu ermöglichen, kann die Decodierungsfunktion Tupel zurückgeben. Sie haben dann ein Dataset mit Tupeln und Tupeln, die zurückgegeben werden, wenn Sie es iterieren. Die zurückgegebenen Werte sind Tensorflow-Tensoren, die von Ihrem Modell verwendet werden können. Sie können für sie .numpy() aufrufen, um Rohwerte zu sehen:

def decode_jpeg_and_label(filename):
  bits
= tf.read_file(filename)
  image
= tf.io.decode_jpeg(bits)
  label
= ... # extract flower name from folder name
 
return image, label

image_dataset
= filenames_dataset.map(decode_jpeg_and_label)
# this is now a dataset of (image, label) pairs

for image, label in dataset:
 
print(image.numpy().shape, label.numpy())

Fazit:Bilder einzeln zu laden ist langsam.

Bei der Iteration dieses Datasets werden Sie feststellen, dass Sie etwa ein bis zwei Bilder pro Sekunde laden können. Das ist zu langsam! Die Hardwarebeschleuniger, die wir für das Training verwenden, können diese Geschwindigkeit um ein Vielfaches erreichen. Im nächsten Abschnitt erfahren Sie, wie wir das erreichen.

Lösung

Hier ist das Lösungs-Notebook. Sie können sie verwenden, wenn Sie nicht weiterkommen.

c3df49e90e5a654f.png Fun with tf.data.Dataset (solution).ipynb

Behandelte Themen

  • 🤔 tf.data.Dataset.list_files
  • 🤔 tf.data.Dataset.map
  • 🤔 Datasets mit Tupeln
  • 😀 Durch Datasets iterieren

Bitte nehmen Sie sich einen Moment Zeit und gehen Sie diese Checkliste durch.

5. Daten schnell laden

Die TPU-Hardwarebeschleuniger der Tensor Processing Unit (TPU), die wir in diesem Lab verwenden, sind sehr schnell. Die Herausforderung besteht oft darin, sie so schnell mit Daten zu versorgen, dass sie damit auf dem Laufenden bleiben. Google Cloud Storage (GCS) kann einen sehr hohen Durchsatz aufrechterhalten, aber wie bei allen Cloud-Speichersystemen kostet das Initiieren einer Verbindung ein gewisses Netzwerk hin und her. Daher ist es nicht ideal, unsere Daten in Tausenden von einzelnen Dateien zu speichern. Wir werden sie in einer kleineren Anzahl von Dateien zusammenfassen und die Leistungsfähigkeit von tf.data.Dataset nutzen, um parallel aus mehreren Dateien zu lesen.

Lesen

Der Code, mit dem Bilddateien geladen, auf eine gängige Größe geändert und dann in 16 TFRecord-Dateien gespeichert werden, befindet sich im folgenden Notebook. Bitte lesen Sie sich das Dokument schnell durch. Die Ausführung ist nicht erforderlich, da ordnungsgemäß TFRecord-formatierte Daten für den Rest des Codelabs bereitgestellt werden.

c3df49e90e5a654f.png Flower pictures to TFRecords.ipynb

Ideales Datenlayout für optimalen GCS-Durchsatz

Das TFRecord-Dateiformat

Das bevorzugte Dateiformat zum Speichern von Daten ist das protobuf-basierte TFRecord-Format. Andere Serialisierungsformate würden ebenfalls funktionieren, aber Sie können ein Dataset direkt aus TFRecord-Dateien laden, indem Sie Folgendes schreiben:

filenames = tf.io.gfile.glob(FILENAME_PATTERN)
dataset
= tf.data.TFRecordDataset(filenames)
dataset
= dataset.map(...) # do the TFRecord decoding here - see below

Für eine optimale Leistung wird empfohlen, den folgenden komplexeren Code zu verwenden, um gleichzeitig aus mehreren TFRecord-Dateien zu lesen. Dieser Code liest parallel aus N Dateien und ignoriert die Datenreihenfolge zugunsten der Lesegeschwindigkeit.

AUTOTUNE = tf.data.AUTOTUNE
ignore_order
= tf.data.Options()
ignore_order
.experimental_deterministic = False

filenames
= tf.io.gfile.glob(FILENAME_PATTERN)
dataset
= tf.data.TFRecordDataset(filenames, num_parallel_reads=AUTOTUNE)
dataset
= dataset.with_options(ignore_order)
dataset
= dataset.map(...) # do the TFRecord decoding here - see below

TFRecord auf einen Blick

Drei Arten von Daten können in TFRecords gespeichert werden: Bytestrings (Liste der Byte), 64-Bit-Ganzzahlen und 32-Bit-Gleitkommazahlen. Sie werden immer als Listen gespeichert. Ein einzelnes Datenelement ist eine Liste der Größe 1. Mit den folgenden Hilfsfunktionen können Sie Daten in TFRecords speichern.

Bytestrings schreiben

# warning, the input is a list of byte strings, which are themselves lists of bytes
def _bytestring_feature(list_of_bytestrings):
 
return tf.train.Feature(bytes_list=tf.train.BytesList(value=list_of_bytestrings))

Ganzzahlen schreiben

def _int_feature(list_of_ints): # int64
 
return tf.train.Feature(int64_list=tf.train.Int64List(value=list_of_ints))

Gleitkommazahlen werden geschrieben

def _float_feature(list_of_floats): # float32
 
return tf.train.Feature(float_list=tf.train.FloatList(value=list_of_floats))

Schreiben eines TFRecord mit den obigen Hilfsprogrammen

# input data in my_img_bytes, my_class, my_height, my_width, my_floats
with tf.python_io.TFRecordWriter(filename) as out_file:
  feature = {
    "image": _bytestring_feature([my_img_bytes]), # one image in the list
    "class": _int_feature([my_class]),            # one class in the list
    "size": _int_feature([my_height, my_width]),  # fixed length (2) list of ints
    "float_data": _float_feature(my_floats)       # variable length  list of floats
  }
  tf_record = tf.train.Example(features=tf.train.Features(feature=feature))
  out_file.write(tf_record.SerializeToString())

Zum Lesen von Daten aus TFRecords müssen Sie zuerst das Layout der gespeicherten Datensätze deklarieren. In der -Deklaration können Sie auf jedes benannte Feld als Liste mit fester Länge oder als Liste mit variabler Länge zugreifen:

aus TFRecords lesen

def read_tfrecord(data):
  features = {
    # tf.string = byte string (not text string)
    "image": tf.io.FixedLenFeature([], tf.string), # shape [] means scalar, here, a single byte string
    "class": tf.io.FixedLenFeature([], tf.int64),  # shape [] means scalar, i.e. a single item
    "size": tf.io.FixedLenFeature([2], tf.int64),  # two integers
    "float_data": tf.io.VarLenFeature(tf.float32)  # a variable number of floats
  }

  # decode the TFRecord
  tf_record = tf.io.parse_single_example(data, features)

  # FixedLenFeature fields are now ready to use
  sz = tf_record['size']

  # Typical code for decoding compressed images
  image = tf.io.decode_jpeg(tf_record['image'], channels=3)

  # VarLenFeature fields require additional sparse.to_dense decoding
  float_data = tf.sparse.to_dense(tf_record['float_data'])

  return image, sz, float_data

# decoding a tf.data.TFRecordDataset
dataset = dataset.map(read_tfrecord)
# now a dataset of triplets (image, sz, float_data)

Nützliche Code-Snippets:

einzelne Datenelemente lesen

tf.io.FixedLenFeature([], tf.string)   # for one byte string
tf
.io.FixedLenFeature([], tf.int64)    # for one int
tf
.io.FixedLenFeature([], tf.float32)  # for one float

Listen von Elementen mit fester Größe lesen

tf.io.FixedLenFeature([N], tf.string)   # list of N byte strings
tf.io.FixedLenFeature([N], tf.int64)    # list of N ints
tf.io.FixedLenFeature([N], tf.float32)  # list of N floats

eine variable Anzahl von Datenelementen lesen

tf.io.VarLenFeature(tf.string)   # list of byte strings
tf
.io.VarLenFeature(tf.int64)    # list of ints
tf
.io.VarLenFeature(tf.float32)  # list of floats

Ein VarLenFeature gibt einen dünnbesetzten Vektor zurück und nach der Decodierung des TFRecord ist ein zusätzlicher Schritt erforderlich:

dense_data = tf.sparse.to_dense(tf_record['my_var_len_feature'])

Es ist auch möglich, optionale Felder in TFRecords zu haben. Wenn Sie beim Lesen eines Felds einen Standardwert angeben, wird dieser anstelle eines Fehlers zurückgegeben, wenn das Feld fehlt.

tf.io.FixedLenFeature([], tf.int64, default_value=0) # this field is optional

Behandelte Themen

  • 🤔 Fragmentierung von Datendateien für schnellen Zugriff über GCS
  • 🎬 Wie schreibt man TFRecords? (Sie haben die Syntax bereits vergessen? Kein Problem, erstellen Sie ein Lesezeichen für diese Seite als Spickzettel.)
  • 🤔 Dataset aus TFRecords mit TFRecordDataset laden

Bitte nehmen Sie sich einen Moment Zeit und gehen Sie diese Checkliste durch.

6. Glückwunsch!

Sie können jetzt eine TPU mit Daten versorgen. Fahren Sie mit dem nächsten Lab fort.

TPUs in der Praxis

TPUs und GPUs sind auf der Cloud AI Platform verfügbar:

Zu guter Letzt freuen wir uns über Feedback. Bitte teilen Sie uns mit, wenn Ihnen in diesem Lab etwas fehlt oder Sie der Meinung sind, dass es verbessert werden sollte. Sie können Feedback über GitHub-Probleme [ feedback link] geben.

HR.png

Martin Görner ID, klein.jpg
Der Autor: Martin Görner
Twitter: @martin_gorner