TFRecord und tf.train.Beispiel

Auf TensorFlow.org ansehen In Google Colab ausführen Quelle auf GitHub anzeigen Notizbuch herunterladen

Das TFRecord-Format ist ein einfaches Format zum Speichern einer Folge von Binärdatensätzen.

Protokollpuffer sind eine plattform- und sprachübergreifende Bibliothek zur effizienten Serialisierung strukturierter Daten.

Protokollnachrichten werden durch .proto Dateien definiert, diese sind oft der einfachste Weg, einen Nachrichtentyp zu verstehen.

Die tf.train.Example Nachricht (oder protobuf) ist ein flexibler Nachrichtentyp, der eine {"string": value} -Zuordnung darstellt. Es wurde für die Verwendung mit TensorFlow entwickelt und wird in allen übergeordneten APIs wie TFX verwendet .

Dieses Notizbuch zeigt, wie Sie die tf.train.Example Nachricht erstellen, analysieren und verwenden und dann tf.train.Example Nachrichten in und aus .tfrecord Dateien serialisieren, schreiben und lesen.

Einrichten

import tensorflow as tf

import numpy as np
import IPython.display as display

tf.train.Example

Datentypen für tf.train.Example

Grundsätzlich ist ein tf.train.Example ein {"string": tf.train.Feature} .

Der Nachrichtentyp tf.train.Feature kann einen der folgenden drei Typen akzeptieren (siehe die .proto Datei als Referenz). Die meisten anderen generischen Typen können zu einem dieser Typen gezwungen werden:

  1. tf.train.BytesList (die folgenden Typen können tf.train.BytesList werden)

    • string
    • byte
  2. tf.train.FloatList (die folgenden Typen können tf.train.FloatList werden)

    • float ( float32 )
    • double ( float64 )
  3. tf.train.Int64List (die folgenden Typen können tf.train.Int64List werden)

    • bool
    • enum
    • int32
    • uint32
    • int64
    • uint64

Um einen TensorFlow-Standardtyp in ein tf.train.Example -kompatibles tf.train.Feature , können Sie die unten stehenden Shortcut-Funktionen verwenden. Man beachte , daß jede Funktion einen skalaren Eingangswert nimmt und gibt eine tf.train.Feature einer der drei enthaltenden list Typen oben:

# The following functions can be used to convert a value to a type compatible
# with tf.train.Example.

def _bytes_feature(value):
  """Returns a bytes_list from a string / byte."""
  if isinstance(value, type(tf.constant(0))):
    value = value.numpy() # BytesList won't unpack a string from an EagerTensor.
  return tf.train.Feature(bytes_list=tf.train.BytesList(value=[value]))

def _float_feature(value):
  """Returns a float_list from a float / double."""
  return tf.train.Feature(float_list=tf.train.FloatList(value=[value]))

def _int64_feature(value):
  """Returns an int64_list from a bool / enum / int / uint."""
  return tf.train.Feature(int64_list=tf.train.Int64List(value=[value]))

Nachfolgend finden Sie einige Beispiele für die Funktionsweise dieser Funktionen. Beachten Sie die unterschiedlichen Eingabetypen und die standardisierten Ausgabetypen. Wenn der Eingabetyp für eine Funktion nicht über angegeben des coercible Typs entspricht, wird die Funktion eine Ausnahme auslösen (zB _int64_feature(1.0) werden Fehler aus , weil 1.0 ein schwimmer deshalb ist, sollte es mit dem verwendet wurde _float_feature statt Funktion ):

print(_bytes_feature(b'test_string'))
print(_bytes_feature(u'test_bytes'.encode('utf-8')))

print(_float_feature(np.exp(1)))

print(_int64_feature(True))
print(_int64_feature(1))
bytes_list {
  value: "test_string"
}

bytes_list {
  value: "test_bytes"
}

float_list {
  value: 2.7182817459106445
}

int64_list {
  value: 1
}

int64_list {
  value: 1
}

Alle Proto-Nachrichten können mit der .SerializeToString Methode in eine .SerializeToString werden:

feature = _float_feature(np.exp(1))

feature.SerializeToString()
b'\x12\x06\n\x04T\xf8-@'

Erstellen einer tf.train.Example Nachricht

Angenommen, Sie möchten eine tf.train.Example Nachricht aus vorhandenen Daten erstellen. In der Praxis kann der Datensatz von überall herkommen, aber das Verfahren zum Erstellen der tf.train.Example Nachricht aus einer einzelnen Beobachtung ist dasselbe:

  1. Innerhalb jeder Beobachtung muss jeder Wert mit einer der obigen Funktionen in ein tf.train.Feature umgewandelt werden, das einen der 3 kompatiblen Typen enthält.

  2. Sie erstellen eine Karte (Wörterbuch) aus der Zeichenfolge des Feature-Namens zu dem in #1 erzeugten codierten Feature-Wert.

  3. Die in Schritt 2 erstellte Karte wird in eine Features Meldung konvertiert.

In diesem Notebook erstellen Sie mit NumPy ein Dataset.

Dieser Datensatz hat 4 Funktionen:

  • ein boolesches Merkmal, False oder True mit gleicher Wahrscheinlichkeit
  • ein ganzzahliges Merkmal, das gleichmäßig zufällig ausgewählt ist aus [0, 5]
  • ein String-Feature, das aus einer String-Tabelle generiert wird, indem das Integer-Feature als Index verwendet wird
  • ein Float-Feature aus einer Standardnormalverteilung

Betrachten Sie eine Stichprobe, die aus 10.000 unabhängig und identisch verteilten Beobachtungen aus jeder der obigen Verteilungen besteht:

# The number of observations in the dataset.
n_observations = int(1e4)

# Boolean feature, encoded as False or True.
feature0 = np.random.choice([False, True], n_observations)

# Integer feature, random from 0 to 4.
feature1 = np.random.randint(0, 5, n_observations)

# String feature.
strings = np.array([b'cat', b'dog', b'chicken', b'horse', b'goat'])
feature2 = strings[feature1]

# Float feature, from a standard normal distribution.
feature3 = np.random.randn(n_observations)

Jedes dieser Features kann in einen tf.train.Example -kompatiblen Typ umgewandelt werden, indem eines von _bytes_feature , _float_feature , _int64_feature . Sie können dann eine tf.train.Example Nachricht aus diesen codierten Funktionen erstellen:

def serialize_example(feature0, feature1, feature2, feature3):
  """
  Creates a tf.train.Example message ready to be written to a file.
  """
  # Create a dictionary mapping the feature name to the tf.train.Example-compatible
  # data type.
  feature = {
      'feature0': _int64_feature(feature0),
      'feature1': _int64_feature(feature1),
      'feature2': _bytes_feature(feature2),
      'feature3': _float_feature(feature3),
  }

  # Create a Features message using tf.train.Example.

  example_proto = tf.train.Example(features=tf.train.Features(feature=feature))
  return example_proto.SerializeToString()

Angenommen, Sie haben eine einzelne Beobachtung aus dem Dataset, [False, 4, bytes('goat'), 0.9876] . Sie können die Nachricht tf.train.Example für diese Beobachtung mit create_message() erstellen und drucken. Jede einzelne Beobachtung wird wie oben beschrieben als Features Nachricht geschrieben. Beachten Sie, dass die tf.train.Example Nachricht nur ein Wrapper um die Features Nachricht ist:

# This is an example observation from the dataset.

example_observation = []

serialized_example = serialize_example(False, 4, b'goat', 0.9876)
serialized_example
b'\nR\n\x14\n\x08feature3\x12\x08\x12\x06\n\x04[\xd3|?\n\x11\n\x08feature1\x12\x05\x1a\x03\n\x01\x04\n\x11\n\x08feature0\x12\x05\x1a\x03\n\x01\x00\n\x14\n\x08feature2\x12\x08\n\x06\n\x04goat'

Verwenden tf.train.Example.FromString zum Decodieren der Nachricht die Methode tf.train.Example.FromString .

example_proto = tf.train.Example.FromString(serialized_example)
example_proto
features {
  feature {
    key: "feature0"
    value {
      int64_list {
        value: 0
      }
    }
  }
  feature {
    key: "feature1"
    value {
      int64_list {
        value: 4
      }
    }
  }
  feature {
    key: "feature2"
    value {
      bytes_list {
        value: "goat"
      }
    }
  }
  feature {
    key: "feature3"
    value {
      float_list {
        value: 0.9876000285148621
      }
    }
  }
}

Details zum TFRecords-Format

Eine TFRecord-Datei enthält eine Folge von Datensätzen. Die Datei kann nur sequentiell gelesen werden.

Jeder Datensatz enthält eine Byte-Zeichenfolge für die Datennutzlast plus die Datenlänge und CRC-32C - Hashes ( 32-Bit-CRC unter Verwendung des Castagnoli-Polynoms ) zur Integritätsprüfung.

Jeder Datensatz wird in den folgenden Formaten gespeichert:

uint64 length
uint32 masked_crc32_of_length
byte   data[length]
uint32 masked_crc32_of_data

Die Datensätze werden miteinander verkettet, um die Datei zu erzeugen. CRCs werden hier beschrieben , und die Maske eines CRC ist:

masked_crc = ((crc >> 15) | (crc << 17)) + 0xa282ead8ul

TFRecord-Dateien mit tf.data

Das Modul tf.data bietet auch Werkzeuge zum Lesen und Schreiben von Daten in TensorFlow.

Schreiben einer TFRecord-Datei

Die einfachste Möglichkeit, die Daten in ein Dataset zu übertragen, besteht darin, die Methode from_tensor_slices verwenden.

Auf ein Array angewendet, gibt es einen Datensatz von Skalaren zurück:

tf.data.Dataset.from_tensor_slices(feature1)
<TensorSliceDataset shapes: (), types: tf.int64>

Auf ein Tupel von Arrays angewendet, gibt es ein Dataset von Tupeln zurück:

features_dataset = tf.data.Dataset.from_tensor_slices((feature0, feature1, feature2, feature3))
features_dataset
<TensorSliceDataset shapes: ((), (), (), ()), types: (tf.bool, tf.int64, tf.string, tf.float64)>
# Use `take(1)` to only pull one example from the dataset.
for f0,f1,f2,f3 in features_dataset.take(1):
  print(f0)
  print(f1)
  print(f2)
  print(f3)
tf.Tensor(False, shape=(), dtype=bool)
tf.Tensor(3, shape=(), dtype=int64)
tf.Tensor(b'horse', shape=(), dtype=string)
tf.Tensor(0.3707167206984876, shape=(), dtype=float64)

Verwenden Sie die tf.data.Dataset.map Verfahren , eine Funktion zu jedem Element einer anzuwenden Dataset .

Die zugeordnete Funktion muss im TensorFlow-Grafikmodus arbeiten – sie muss auf tf.Tensors arbeiten und es zurückgeben. Eine Nicht-Tensor-Funktion wie serialize_example kann mit tf.py_function , um sie kompatibel zu machen.

Die Verwendung von tf.py_function erfordert die Angabe der Form- und tf.py_function , die ansonsten nicht verfügbar sind:

def tf_serialize_example(f0,f1,f2,f3):
  tf_string = tf.py_function(
    serialize_example,
    (f0, f1, f2, f3),  # Pass these args to the above function.
    tf.string)      # The return type is `tf.string`.
  return tf.reshape(tf_string, ()) # The result is a scalar.
tf_serialize_example(f0, f1, f2, f3)
<tf.Tensor: shape=(), dtype=string, numpy=b'\nS\n\x14\n\x08feature3\x12\x08\x12\x06\n\x04\x95\xce\xbd>\n\x11\n\x08feature0\x12\x05\x1a\x03\n\x01\x00\n\x15\n\x08feature2\x12\t\n\x07\n\x05horse\n\x11\n\x08feature1\x12\x05\x1a\x03\n\x01\x03'>

Wenden Sie diese Funktion auf jedes Element im Datensatz an:

serialized_features_dataset = features_dataset.map(tf_serialize_example)
serialized_features_dataset
<MapDataset shapes: (), types: tf.string>
def generator():
  for features in features_dataset:
    yield serialize_example(*features)
serialized_features_dataset = tf.data.Dataset.from_generator(
    generator, output_types=tf.string, output_shapes=())
serialized_features_dataset
<FlatMapDataset shapes: (), types: tf.string>

Und schreiben Sie sie in eine TFRecord-Datei:

filename = 'test.tfrecord'
writer = tf.data.experimental.TFRecordWriter(filename)
writer.write(serialized_features_dataset)

Lesen einer TFRecord-Datei

Sie können die TFRecord-Datei auch mit der Klasse tf.data.TFRecordDataset lesen.

Weitere Informationen zum Konsumieren von TFRecord-Dateien mit tf.data finden Sie im tf.data: Build TensorFlow input Pipelines Guide.

Die Verwendung von TFRecordDataset s kann nützlich sein, um Eingabedaten zu standardisieren und die Leistung zu optimieren.

filenames = [filename]
raw_dataset = tf.data.TFRecordDataset(filenames)
raw_dataset
<TFRecordDatasetV2 shapes: (), types: tf.string>

An dieser Stelle enthält der Datensatz serialisierte tf.train.Example Nachrichten. Wenn es iteriert wird, gibt es diese als skalare String-Tensoren zurück.

Verwenden Sie die .take Methode, um nur die ersten 10 Datensätze .take .

for raw_record in raw_dataset.take(10):
  print(repr(raw_record))
<tf.Tensor: shape=(), dtype=string, numpy=b'\nS\n\x15\n\x08feature2\x12\t\n\x07\n\x05horse\n\x11\n\x08feature1\x12\x05\x1a\x03\n\x01\x03\n\x14\n\x08feature3\x12\x08\x12\x06\n\x04\x95\xce\xbd>\n\x11\n\x08feature0\x12\x05\x1a\x03\n\x01\x00'>
<tf.Tensor: shape=(), dtype=string, numpy=b'\nS\n\x15\n\x08feature2\x12\t\n\x07\n\x05horse\n\x11\n\x08feature1\x12\x05\x1a\x03\n\x01\x03\n\x14\n\x08feature3\x12\x08\x12\x06\n\x04iX\x9a\xbe\n\x11\n\x08feature0\x12\x05\x1a\x03\n\x01\x01'>
<tf.Tensor: shape=(), dtype=string, numpy=b'\nS\n\x15\n\x08feature2\x12\t\n\x07\n\x05horse\n\x11\n\x08feature0\x12\x05\x1a\x03\n\x01\x00\n\x14\n\x08feature3\x12\x08\x12\x06\n\x04\xb6\xa2\xb5\xbf\n\x11\n\x08feature1\x12\x05\x1a\x03\n\x01\x03'>
<tf.Tensor: shape=(), dtype=string, numpy=b'\nU\n\x11\n\x08feature0\x12\x05\x1a\x03\n\x01\x00\n\x17\n\x08feature2\x12\x0b\n\t\n\x07chicken\n\x11\n\x08feature1\x12\x05\x1a\x03\n\x01\x02\n\x14\n\x08feature3\x12\x08\x12\x06\n\x04>!\x84\xbc'>
<tf.Tensor: shape=(), dtype=string, numpy=b'\nR\n\x14\n\x08feature2\x12\x08\n\x06\n\x04goat\n\x11\n\x08feature0\x12\x05\x1a\x03\n\x01\x01\n\x11\n\x08feature1\x12\x05\x1a\x03\n\x01\x04\n\x14\n\x08feature3\x12\x08\x12\x06\n\x04\xa9\xdcE?'>
<tf.Tensor: shape=(), dtype=string, numpy=b'\nQ\n\x13\n\x08feature2\x12\x07\n\x05\n\x03cat\n\x14\n\x08feature3\x12\x08\x12\x06\n\x04\x98\x8bb=\n\x11\n\x08feature0\x12\x05\x1a\x03\n\x01\x01\n\x11\n\x08feature1\x12\x05\x1a\x03\n\x01\x00'>
<tf.Tensor: shape=(), dtype=string, numpy=b"\nR\n\x14\n\x08feature3\x12\x08\x12\x06\n\x04\xb6\xe2'\xbf\n\x14\n\x08feature2\x12\x08\n\x06\n\x04goat\n\x11\n\x08feature0\x12\x05\x1a\x03\n\x01\x01\n\x11\n\x08feature1\x12\x05\x1a\x03\n\x01\x04">
<tf.Tensor: shape=(), dtype=string, numpy=b'\nS\n\x11\n\x08feature0\x12\x05\x1a\x03\n\x01\x00\n\x15\n\x08feature2\x12\t\n\x07\n\x05horse\n\x14\n\x08feature3\x12\x08\x12\x06\n\x04\x9c\xc4I>\n\x11\n\x08feature1\x12\x05\x1a\x03\n\x01\x03'>
<tf.Tensor: shape=(), dtype=string, numpy=b'\nQ\n\x11\n\x08feature0\x12\x05\x1a\x03\n\x01\x00\n\x14\n\x08feature3\x12\x08\x12\x06\n\x04p\xd3\xbd\xbc\n\x13\n\x08feature2\x12\x07\n\x05\n\x03cat\n\x11\n\x08feature1\x12\x05\x1a\x03\n\x01\x00'>
<tf.Tensor: shape=(), dtype=string, numpy=b'\nU\n\x14\n\x08feature3\x12\x08\x12\x06\n\x04`\x8bp?\n\x11\n\x08feature1\x12\x05\x1a\x03\n\x01\x02\n\x11\n\x08feature0\x12\x05\x1a\x03\n\x01\x00\n\x17\n\x08feature2\x12\x0b\n\t\n\x07chicken'>

Diese Tensoren können mit der folgenden Funktion geparst werden. Beachten Sie, dass die feature_description hier erforderlich ist, datf.data.Dataset s die Graph-Ausführung verwenden und diese Beschreibung benötigen, um ihre Form- undtf.data.Dataset zu erstellen:

# Create a description of the features.
feature_description = {
    'feature0': tf.io.FixedLenFeature([], tf.int64, default_value=0),
    'feature1': tf.io.FixedLenFeature([], tf.int64, default_value=0),
    'feature2': tf.io.FixedLenFeature([], tf.string, default_value=''),
    'feature3': tf.io.FixedLenFeature([], tf.float32, default_value=0.0),
}

def _parse_function(example_proto):
  # Parse the input `tf.train.Example` proto using the dictionary above.
  return tf.io.parse_single_example(example_proto, feature_description)

Alternativ können Sie tf.parse example , um den gesamten Batch auf einmal zu parsen. Wenden Sie diese Funktion mit der Methode tf.data.Dataset.map auf jedes Element im Dataset an:

parsed_dataset = raw_dataset.map(_parse_function)
parsed_dataset
<MapDataset shapes: {feature0: (), feature1: (), feature2: (), feature3: ()}, types: {feature0: tf.int64, feature1: tf.int64, feature2: tf.string, feature3: tf.float32}>

Verwenden Sie die Eager-Ausführung, um die Beobachtungen im Dataset anzuzeigen. Dieses Dataset enthält 10.000 Beobachtungen, aber Sie zeigen nur die ersten 10 an. Die Daten werden als Wörterbuch von Features angezeigt. Jedes Element ist ein tf.Tensor , und das numpy Element dieses Tensors zeigt den Wert des Merkmals an:

for parsed_record in parsed_dataset.take(10):
  print(repr(parsed_record))
{'feature0': <tf.Tensor: shape=(), dtype=int64, numpy=0>, 'feature1': <tf.Tensor: shape=(), dtype=int64, numpy=3>, 'feature2': <tf.Tensor: shape=(), dtype=string, numpy=b'horse'>, 'feature3': <tf.Tensor: shape=(), dtype=float32, numpy=0.37071672>}
{'feature0': <tf.Tensor: shape=(), dtype=int64, numpy=1>, 'feature1': <tf.Tensor: shape=(), dtype=int64, numpy=3>, 'feature2': <tf.Tensor: shape=(), dtype=string, numpy=b'horse'>, 'feature3': <tf.Tensor: shape=(), dtype=float32, numpy=-0.30145577>}
{'feature0': <tf.Tensor: shape=(), dtype=int64, numpy=0>, 'feature1': <tf.Tensor: shape=(), dtype=int64, numpy=3>, 'feature2': <tf.Tensor: shape=(), dtype=string, numpy=b'horse'>, 'feature3': <tf.Tensor: shape=(), dtype=float32, numpy=-1.419028>}
{'feature0': <tf.Tensor: shape=(), dtype=int64, numpy=0>, 'feature1': <tf.Tensor: shape=(), dtype=int64, numpy=2>, 'feature2': <tf.Tensor: shape=(), dtype=string, numpy=b'chicken'>, 'feature3': <tf.Tensor: shape=(), dtype=float32, numpy=-0.016129132>}
{'feature0': <tf.Tensor: shape=(), dtype=int64, numpy=1>, 'feature1': <tf.Tensor: shape=(), dtype=int64, numpy=4>, 'feature2': <tf.Tensor: shape=(), dtype=string, numpy=b'goat'>, 'feature3': <tf.Tensor: shape=(), dtype=float32, numpy=0.77289826>}
{'feature0': <tf.Tensor: shape=(), dtype=int64, numpy=1>, 'feature1': <tf.Tensor: shape=(), dtype=int64, numpy=0>, 'feature2': <tf.Tensor: shape=(), dtype=string, numpy=b'cat'>, 'feature3': <tf.Tensor: shape=(), dtype=float32, numpy=0.05530891>}
{'feature0': <tf.Tensor: shape=(), dtype=int64, numpy=1>, 'feature1': <tf.Tensor: shape=(), dtype=int64, numpy=4>, 'feature2': <tf.Tensor: shape=(), dtype=string, numpy=b'goat'>, 'feature3': <tf.Tensor: shape=(), dtype=float32, numpy=-0.6558031>}
{'feature0': <tf.Tensor: shape=(), dtype=int64, numpy=0>, 'feature1': <tf.Tensor: shape=(), dtype=int64, numpy=3>, 'feature2': <tf.Tensor: shape=(), dtype=string, numpy=b'horse'>, 'feature3': <tf.Tensor: shape=(), dtype=float32, numpy=0.19703907>}
{'feature0': <tf.Tensor: shape=(), dtype=int64, numpy=0>, 'feature1': <tf.Tensor: shape=(), dtype=int64, numpy=0>, 'feature2': <tf.Tensor: shape=(), dtype=string, numpy=b'cat'>, 'feature3': <tf.Tensor: shape=(), dtype=float32, numpy=-0.02317211>}
{'feature0': <tf.Tensor: shape=(), dtype=int64, numpy=0>, 'feature1': <tf.Tensor: shape=(), dtype=int64, numpy=2>, 'feature2': <tf.Tensor: shape=(), dtype=string, numpy=b'chicken'>, 'feature3': <tf.Tensor: shape=(), dtype=float32, numpy=0.9396267>}

Hier tf.parse_example Funktion tf.parse_example die tf.train.Example Felder in Standardtensoren.

TFRecord-Dateien in Python

Das Modul tf.io enthält auch reine Python-Funktionen zum Lesen und Schreiben von TFRecord-Dateien.

Schreiben einer TFRecord-Datei

Schreiben Sie als Nächstes die 10.000 Beobachtungen in die Datei test.tfrecord . Jede Beobachtung wird in eine tf.train.Example Nachricht umgewandelt und dann in eine Datei geschrieben. Sie können dann überprüfen, ob die Datei test.tfrecord erstellt wurde:

# Write the `tf.train.Example` observations to the file.
with tf.io.TFRecordWriter(filename) as writer:
  for i in range(n_observations):
    example = serialize_example(feature0[i], feature1[i], feature2[i], feature3[i])
    writer.write(example)
du -sh {filename}
984K    test.tfrecord

Lesen einer TFRecord-Datei

Diese serialisierten Tensoren können einfach mit tf.train.Example.ParseFromString geparst werden:

filenames = [filename]
raw_dataset = tf.data.TFRecordDataset(filenames)
raw_dataset
<TFRecordDatasetV2 shapes: (), types: tf.string>
for raw_record in raw_dataset.take(1):
  example = tf.train.Example()
  example.ParseFromString(raw_record.numpy())
  print(example)
features {
  feature {
    key: "feature0"
    value {
      int64_list {
        value: 0
      }
    }
  }
  feature {
    key: "feature1"
    value {
      int64_list {
        value: 3
      }
    }
  }
  feature {
    key: "feature2"
    value {
      bytes_list {
        value: "horse"
      }
    }
  }
  feature {
    key: "feature3"
    value {
      float_list {
        value: 0.37071672081947327
      }
    }
  }
}

Exemplarische Vorgehensweise: Bilddaten lesen und schreiben

Dies ist ein End-to-End-Beispiel für das Lesen und Schreiben von Bilddaten mit TFRecords. Wenn Sie ein Bild als Eingabedaten verwenden, schreiben Sie die Daten als TFRecord-Datei, lesen die Datei dann zurück und zeigen das Bild an.

Dies kann nützlich sein, wenn Sie beispielsweise mehrere Modelle für dasselbe Eingabe-Dataset verwenden möchten. Anstatt die Bilddaten roh zu speichern, können sie in das TFRecords-Format vorverarbeitet werden, das in allen weiteren Verarbeitungen und Modellierungen verwendet werden kann.

Laden wir zuerst dieses Bild einer Katze im Schnee und dieses Foto der Williamsburg Bridge, NYC im Bau, herunter.

Hol die Bilder

cat_in_snow  = tf.keras.utils.get_file(
    '320px-Felis_catus-cat_on_snow.jpg',
    'https://storage.googleapis.com/download.tensorflow.org/example_images/320px-Felis_catus-cat_on_snow.jpg')

williamsburg_bridge = tf.keras.utils.get_file(
    '194px-New_East_River_Bridge_from_Brooklyn_det.4a09796u.jpg',
    'https://storage.googleapis.com/download.tensorflow.org/example_images/194px-New_East_River_Bridge_from_Brooklyn_det.4a09796u.jpg')
Downloading data from https://storage.googleapis.com/download.tensorflow.org/example_images/320px-Felis_catus-cat_on_snow.jpg
24576/17858 [=========================================] - 0s 0us/step
Downloading data from https://storage.googleapis.com/download.tensorflow.org/example_images/194px-New_East_River_Bridge_from_Brooklyn_det.4a09796u.jpg
16384/15477 [===============================] - 0s 0us/step
display.display(display.Image(filename=cat_in_snow))
display.display(display.HTML('Image cc-by: <a "href=https://commons.wikimedia.org/wiki/File:Felis_catus-cat_on_snow.jpg">Von.grzanka</a>'))

jpeg

display.display(display.Image(filename=williamsburg_bridge))
display.display(display.HTML('<a "href=https://commons.wikimedia.org/wiki/File:New_East_River_Bridge_from_Brooklyn_det.4a09796u.jpg">From Wikimedia</a>'))

jpeg

Schreiben Sie die TFRecord-Datei

Codieren Sie die Features wie zuvor als Typen, die mit tf.train.Example kompatibel tf.train.Example . Dies speichert das Merkmal der Rohbildzeichenfolge sowie die Höhe, Breite, Tiefe und label Merkmal für beliebige label . Letzteres wird beim Schreiben der Datei verwendet, um zwischen dem Cat-Image und dem Bridge-Image zu unterscheiden. Verwenden Sie 0 für das Katzenbild und 1 für das Brückenbild:

image_labels = {
    cat_in_snow : 0,
    williamsburg_bridge : 1,
}
# This is an example, just using the cat image.
image_string = open(cat_in_snow, 'rb').read()

label = image_labels[cat_in_snow]

# Create a dictionary with features that may be relevant.
def image_example(image_string, label):
  image_shape = tf.io.decode_jpeg(image_string).shape

  feature = {
      'height': _int64_feature(image_shape[0]),
      'width': _int64_feature(image_shape[1]),
      'depth': _int64_feature(image_shape[2]),
      'label': _int64_feature(label),
      'image_raw': _bytes_feature(image_string),
  }

  return tf.train.Example(features=tf.train.Features(feature=feature))

for line in str(image_example(image_string, label)).split('\n')[:15]:
  print(line)
print('...')
features {
  feature {
    key: "depth"
    value {
      int64_list {
        value: 3
      }
    }
  }
  feature {
    key: "height"
    value {
      int64_list {
        value: 213
      }
...

Beachten Sie, dass alle Funktionen jetzt in der Nachricht tf.train.Example gespeichert sind. Als nächstes funktionalisieren Sie den obigen Code und schreiben die Beispielnachrichten in eine Datei namens images.tfrecords :

# Write the raw image files to `images.tfrecords`.
# First, process the two images into `tf.train.Example` messages.
# Then, write to a `.tfrecords` file.
record_file = 'images.tfrecords'
with tf.io.TFRecordWriter(record_file) as writer:
  for filename, label in image_labels.items():
    image_string = open(filename, 'rb').read()
    tf_example = image_example(image_string, label)
    writer.write(tf_example.SerializeToString())
du -sh {record_file}
36K images.tfrecords

Lesen Sie die TFRecord-Datei

Sie haben jetzt die Datei images.tfrecords und können nun über die darin enthaltenen Datensätze iterieren, um das Geschriebene images.tfrecords . Da Sie in diesem Beispiel nur das Bild reproduzieren, benötigen Sie nur die Rohbildzeichenfolge. Extrahieren Sie es mit den oben beschriebenen Gettern, nämlich example.features.feature['image_raw'].bytes_list.value[0] . Sie können auch die Labels verwenden, um zu bestimmen, welcher Datensatz die Katze und welcher die Brücke ist:

raw_image_dataset = tf.data.TFRecordDataset('images.tfrecords')

# Create a dictionary describing the features.
image_feature_description = {
    'height': tf.io.FixedLenFeature([], tf.int64),
    'width': tf.io.FixedLenFeature([], tf.int64),
    'depth': tf.io.FixedLenFeature([], tf.int64),
    'label': tf.io.FixedLenFeature([], tf.int64),
    'image_raw': tf.io.FixedLenFeature([], tf.string),
}

def _parse_image_function(example_proto):
  # Parse the input tf.train.Example proto using the dictionary above.
  return tf.io.parse_single_example(example_proto, image_feature_description)

parsed_image_dataset = raw_image_dataset.map(_parse_image_function)
parsed_image_dataset
<MapDataset shapes: {depth: (), height: (), image_raw: (), label: (), width: ()}, types: {depth: tf.int64, height: tf.int64, image_raw: tf.string, label: tf.int64, width: tf.int64}>

Stellen Sie die Bilder aus der TFRecord-Datei wieder her:

for image_features in parsed_image_dataset:
  image_raw = image_features['image_raw'].numpy()
  display.display(display.Image(data=image_raw))

jpeg

jpeg