ML Community Day è il 9 novembre! Unisciti a noi per gli aggiornamenti da tensorflow, JAX, e più Per saperne di più

TFRecord e tf.train.Example

Visualizza su TensorFlow.org Esegui in Google Colab Visualizza la fonte su GitHub Scarica taccuino

Il formato TFRecord è un formato semplice per memorizzare una sequenza di record binari.

Buffer di protocollo sono un cross-platform, libreria multi-lingua per la serializzazione efficiente di dati strutturati.

Messaggi di protocollo sono definiti da .proto file, questi sono spesso il modo più semplice per capire un tipo di messaggio.

Il tf.train.Example messaggio (o protobuf) è un tipo di messaggio flessibile, che rappresenta una {"string": value} mappatura. È progettato per l'uso con tensorflow ed è utilizzato in tutto le API di livello superiore come TFX .

Questo notebook viene illustrato come creare, analizzare e utilizzare il tf.train.Example messaggio, quindi serializzare, scrittura e lettura tf.train.Example messaggi da e verso .tfrecord file.

Impostare

import tensorflow as tf

import numpy as np
import IPython.display as display

tf.train.Example

Tipi di dati per tf.train.Example

Fondamentalmente, un tf.train.Example è un {"string": tf.train.Feature} mappatura.

Il tf.train.Feature tipo di messaggio può accettare uno dei seguenti tre tipi (Vedere la .proto file di riferimento). La maggior parte degli altri tipi generici può essere forzata in uno di questi:

  1. tf.train.BytesList (i seguenti tipi possono essere costretti)

    • string
    • byte
  2. tf.train.FloatList (i seguenti tipi possono essere costretti)

    • float ( float32 )
    • double ( float64 )
  3. tf.train.Int64List (i seguenti tipi possono essere costretti)

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

Per convertire un tipo tensorflow standard per un tf.train.Example compatibile tf.train.Feature , è possibile utilizzare le funzioni di collegamento qui sotto. Notare che ogni funzione prende un valore di ingresso scalare e restituisce una tf.train.Feature contenente uno dei tre list precedenti tipologie:

# 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]))

Di seguito sono riportati alcuni esempi di come funzionano queste funzioni. Notare i diversi tipi di input e i tipi di output standardizzati. Se il tipo di ingresso per una funzione non corrisponde a uno dei tipi Coercible cui sopra, la funzione solleverà un'eccezione (es _int64_feature(1.0) si verificheranno errori perché 1.0 è un flottante pertanto, deve essere utilizzato con la _float_feature funzione invece ):

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
}

Tutti i messaggi proto può essere serializzato a un binario stringa usando il .SerializeToString metodo:

feature = _float_feature(np.exp(1))

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

Creazione di un tf.train.Example messaggio

Si supponga di voler creare un tf.train.Example messaggio dai dati esistenti. In pratica, il set di dati possono provenire da qualsiasi luogo, ma la procedura di creazione di tf.train.Example messaggio da una singola osservazione sarà lo stesso:

  1. All'interno di ciascuna osservazione, ciascuno esigenze valore da convertire in un tf.train.Feature contenente uno dei tipi compatibili 3, utilizzando una delle suddette funzioni.

  2. Si crea una mappa (dizionario) dalla stringa del nome dell'elemento al valore dell'elemento codificato prodotto in #1.

  3. La mappa prodotta nella fase 2 viene convertito in un Features messaggio .

In questo notebook creerai un set di dati utilizzando NumPy.

Questo set di dati avrà 4 caratteristiche:

  • una funzione booleana, False o True con uguale probabilità
  • una caratteristica intero uniformemente scelti a caso da [0, 5]
  • una caratteristica stringa generata da una tabella di stringhe usando la caratteristica intera come indice
  • una funzione float da una distribuzione normale standard

Considera un campione composto da 10.000 osservazioni distribuite in modo indipendente e identicamente da ciascuna delle suddette distribuzioni:

# 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)

Ciascuna di queste caratteristiche possono essere costretto ad un tf.train.Example tipo compatibile utilizza uno _bytes_feature , _float_feature , _int64_feature . È quindi possibile creare un tf.train.Example messaggio a queste caratteristiche codificate:

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()

Ad esempio, si supponga di avere una sola osservazione dal set di dati, [False, 4, bytes('goat'), 0.9876] . È possibile creare e stampare il tf.train.Example messaggio per questa osservazione utilizzando create_message() . Ogni singola osservazione sarà scritto come Features messaggio come da sopra. Si noti che il tf.train.Example messaggio è solo un involucro intorno al Features messaggio:

# 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\x08feature2\x12\x08\n\x06\n\x04goat\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'

Per decodificare il messaggio uso del tf.train.Example.FromString metodo.

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
      }
    }
  }
}

Dettagli sul formato TFRecords

Un file TFRecord contiene una sequenza di record. Il file può essere letto solo in sequenza.

Ogni record contiene un byte-stringa, per controllare, payload, più la lunghezza dei dati, e CRC-32C ( CRC a 32 bit utilizzando il polinomio Castagnoli ) hash per la verifica dell'integrità.

Ogni record è archiviato nei seguenti formati:

uint64 length
uint32 masked_crc32_of_length
byte   data[length]
uint32 masked_crc32_of_data

I record vengono concatenati insieme per produrre il file. CRC sono descritte qui , e la maschera di un CRC è:

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

File TFRecord utilizzando tf.data

Il tf.data modulo fornisce anche strumenti per la lettura e scrittura dei dati in tensorflow.

Scrivere un file TFRecord

Il modo più semplice per ottenere i dati in un set di dati è quello di utilizzare il from_tensor_slices metodo.

Applicato a un array, restituisce un set di dati di scalari:

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

Applicato a una tupla di array, restituisce un set di dati di tuple:

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(True, shape=(), dtype=bool)
tf.Tensor(1, shape=(), dtype=int64)
tf.Tensor(b'dog', shape=(), dtype=string)
tf.Tensor(-0.9885608219225024, shape=(), dtype=float64)

Utilizzare il tf.data.Dataset.map metodo per applicare una funzione a ciascun elemento di un Dataset .

La funzione mappata deve operare in modalità grafico tensorflow-deve operare e ritorno tf.Tensors . Una funzione non-tensore, come serialize_example , può essere avvolto con tf.py_function per renderlo compatibile.

Utilizzando tf.py_function richiede di specificare le informazioni di forma e il tipo che è altrimenti non disponibili:

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'\nQ\n\x14\n\x08feature3\x12\x08\x12\x06\n\x04R\x12}\xbf\n\x11\n\x08feature1\x12\x05\x1a\x03\n\x01\x01\n\x13\n\x08feature2\x12\x07\n\x05\n\x03dog\n\x11\n\x08feature0\x12\x05\x1a\x03\n\x01\x01'>

Applica questa funzione a ciascun elemento nel set di dati:

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>

E scrivili in un file TFRecord:

filename = 'test.tfrecord'
writer = tf.data.experimental.TFRecordWriter(filename)
writer.write(serialized_features_dataset)
WARNING:tensorflow:From /tmp/ipykernel_16482/3575438268.py:2: TFRecordWriter.__init__ (from tensorflow.python.data.experimental.ops.writers) is deprecated and will be removed in a future version.
Instructions for updating:
To write TFRecords to disk, use `tf.io.TFRecordWriter`. To save and load the contents of a dataset, use `tf.data.experimental.save` and `tf.data.experimental.load`

Lettura di un file TFRecord

È inoltre possibile leggere il file TFRecord utilizzando la tf.data.TFRecordDataset di classe.

Maggiori informazioni sul consumo di file utilizzando TFRecord tf.data può essere trovato nel tf.data: costruire oleodotti ingresso tensorflow guida.

Utilizzando TFRecordDataset s può essere utile per la standardizzazione dei dati di ingresso e di ottimizzare le prestazioni.

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

A questo punto l'insieme di dati contiene serializzati tf.train.Example messaggi. Quando viene ripetuto, restituisce questi come tensori di stringa scalari.

Utilizzare il .take metodo per mostrare solo i primi 10 record.

for raw_record in raw_dataset.take(10):
  print(repr(raw_record))
<tf.Tensor: shape=(), dtype=string, numpy=b'\nQ\n\x14\n\x08feature3\x12\x08\x12\x06\n\x04R\x12}\xbf\n\x11\n\x08feature0\x12\x05\x1a\x03\n\x01\x01\n\x13\n\x08feature2\x12\x07\n\x05\n\x03dog\n\x11\n\x08feature1\x12\x05\x1a\x03\n\x01\x01'>
<tf.Tensor: shape=(), dtype=string, numpy=b'\nQ\n\x14\n\x08feature3\x12\x08\x12\x06\n\x04\xb5\x91\xdc\xbb\n\x11\n\x08feature1\x12\x05\x1a\x03\n\x01\x00\n\x11\n\x08feature0\x12\x05\x1a\x03\n\x01\x01\n\x13\n\x08feature2\x12\x07\n\x05\n\x03cat'>
<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\x14\n\x08feature3\x12\x08\x12\x06\n\x04\xbd\x91g=\n\x11\n\x08feature1\x12\x05\x1a\x03\n\x01\x02'>
<tf.Tensor: shape=(), dtype=string, numpy=b'\nQ\n\x11\n\x08feature0\x12\x05\x1a\x03\n\x01\x00\n\x13\n\x08feature2\x12\x07\n\x05\n\x03dog\n\x11\n\x08feature1\x12\x05\x1a\x03\n\x01\x01\n\x14\n\x08feature3\x12\x08\x12\x06\n\x04e\xc5\x98>'>
<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\x04e\xa4|>\n\x11\n\x08feature0\x12\x05\x1a\x03\n\x01\x01'>
<tf.Tensor: shape=(), dtype=string, numpy=b'\nQ\n\x11\n\x08feature0\x12\x05\x1a\x03\n\x01\x00\n\x13\n\x08feature2\x12\x07\n\x05\n\x03cat\n\x14\n\x08feature3\x12\x08\x12\x06\n\x04\x0b\xb3\x02@\n\x11\n\x08feature1\x12\x05\x1a\x03\n\x01\x00'>
<tf.Tensor: shape=(), dtype=string, numpy=b'\nQ\n\x14\n\x08feature3\x12\x08\x12\x06\n\x04G\xa4\xda\xbf\n\x13\n\x08feature2\x12\x07\n\x05\n\x03dog\n\x11\n\x08feature0\x12\x05\x1a\x03\n\x01\x01\n\x11\n\x08feature1\x12\x05\x1a\x03\n\x01\x01'>
<tf.Tensor: shape=(), dtype=string, numpy=b'\nQ\n\x11\n\x08feature1\x12\x05\x1a\x03\n\x01\x01\n\x11\n\x08feature0\x12\x05\x1a\x03\n\x01\x00\n\x13\n\x08feature2\x12\x07\n\x05\n\x03dog\n\x14\n\x08feature3\x12\x08\x12\x06\n\x04\xd2/\xcf\xbf'>
<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\x04<\xedO?\n\x11\n\x08feature1\x12\x05\x1a\x03\n\x01\x00\n\x13\n\x08feature2\x12\x07\n\x05\n\x03cat'>
<tf.Tensor: shape=(), dtype=string, numpy=b'\nR\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\x041I\xe1?\n\x14\n\x08feature2\x12\x08\n\x06\n\x04goat'>

Questi tensori possono essere analizzati utilizzando la funzione seguente. Si noti che il feature_description è necessario qui perché tf.data.Dataset s uso grafico-esecuzione, e hanno bisogno di questa descrizione per costruire la loro forma e tipo di firma:

# 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)

In alternativa, utilizzare tf.parse example per analizzare l'intera partita in una volta. Applicare questa funzione per ciascun elemento del set di dati utilizzando il tf.data.Dataset.map metodo:

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}>

Utilizzare l'esecuzione desiderosa per visualizzare le osservazioni nel set di dati. Ci sono 10.000 osservazioni in questo set di dati, ma verranno visualizzate solo le prime 10. I dati vengono visualizzati come un dizionario di caratteristiche. Ogni elemento è un tf.Tensor , e la numpy elemento di questo tensore visualizza il valore della funzione:

for parsed_record in parsed_dataset.take(10):
  print(repr(parsed_record))
{'feature0': <tf.Tensor: shape=(), dtype=int64, numpy=1>, 'feature1': <tf.Tensor: shape=(), dtype=int64, numpy=1>, 'feature2': <tf.Tensor: shape=(), dtype=string, numpy=b'dog'>, 'feature3': <tf.Tensor: shape=(), dtype=float32, numpy=-0.9885608>}
{'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.006731237>}
{'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.05653547>}
{'feature0': <tf.Tensor: shape=(), dtype=int64, numpy=0>, 'feature1': <tf.Tensor: shape=(), dtype=int64, numpy=1>, 'feature2': <tf.Tensor: shape=(), dtype=string, numpy=b'dog'>, 'feature3': <tf.Tensor: shape=(), dtype=float32, numpy=0.298381>}
{'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.24672087>}
{'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=2.042178>}
{'feature0': <tf.Tensor: shape=(), dtype=int64, numpy=1>, 'feature1': <tf.Tensor: shape=(), dtype=int64, numpy=1>, 'feature2': <tf.Tensor: shape=(), dtype=string, numpy=b'dog'>, 'feature3': <tf.Tensor: shape=(), dtype=float32, numpy=-1.7081383>}
{'feature0': <tf.Tensor: shape=(), dtype=int64, numpy=0>, 'feature1': <tf.Tensor: shape=(), dtype=int64, numpy=1>, 'feature2': <tf.Tensor: shape=(), dtype=string, numpy=b'dog'>, 'feature3': <tf.Tensor: shape=(), dtype=float32, numpy=-1.6186469>}
{'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.81221366>}
{'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=1.7600461>}

Qui, la tf.parse_example funzione di spacchetta i tf.train.Example campi in tensori standard.

File TFRecord in Python

Il tf.io modulo contiene anche funzioni pure-Python per la lettura e la scrittura di file TFRecord.

Scrivere un file TFRecord

Avanti, scrivere le 10.000 osservazioni al file test.tfrecord . Ogni osservazione viene convertito in un tf.train.Example messaggio, quindi scritto file. È quindi possibile verificare che il file test.tfrecord si è creato:

# 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

Lettura di un file TFRecord

Questi tensori serializzati possono essere facilmente analizzati utilizzando tf.train.Example.ParseFromString :

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: 1
      }
    }
  }
  feature {
    key: "feature1"
    value {
      int64_list {
        value: 1
      }
    }
  }
  feature {
    key: "feature2"
    value {
      bytes_list {
        value: "dog"
      }
    }
  }
  feature {
    key: "feature3"
    value {
      float_list {
        value: -0.9885607957839966
      }
    }
  }
}

Che restituisce un tf.train.Example proto che è a malapena sufficiente a uso come è, ma è fondamentalmente una rappresentazione di una:

Dict[str,
     Union[List[float],
           List[int],
           List[str]]]

Il codice seguente converte manualmente l' Example di un dizionario di array NumPy, senza utilizzare tensorflow Ops. Fare riferimento al file PROTO per detials.

result = {}
# example.features.feature is the dictionary
for key, feature in example.features.feature.items():
  # The values are the Feature objects which contain a `kind` which contains:
  # one of three fields: bytes_list, float_list, int64_list

  kind = feature.WhichOneof('kind')
  result[key] = np.array(getattr(feature, kind).value)

result
{'feature1': array([1]),
 'feature0': array([1]),
 'feature2': array([b'dog'], dtype='|S3'),
 'feature3': array([-0.9885608])}

Procedura dettagliata: lettura e scrittura di dati immagine

Questo è un esempio end-to-end di come leggere e scrivere dati di immagine utilizzando TFRecords. Utilizzando un'immagine come dati di input, si scriveranno i dati come file TFRecord, quindi si rileggerà il file e si visualizzerà l'immagine.

Ciò può essere utile se, ad esempio, si desidera utilizzare più modelli sullo stesso set di dati di input. Invece di memorizzare i dati dell'immagine non elaborati, è possibile preelaborarli nel formato TFRecords e utilizzarli in tutte le ulteriori elaborazioni e modelli.

In primo luogo, cerchiamo di scaricare questa immagine di un gatto nella neve e questa foto del ponte di Williamsburg, New York in costruzione.

Scarica le immagini

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
32768/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
24576/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

Scrivi il file TFRecord

Come prima, codificare le caratteristiche come tipi compatibili con tf.train.Example . Questo memorizza il greggio caratteristica stringa immagine, così come l'altezza, larghezza, profondità e arbitrario label includono. Quest'ultimo viene utilizzato quando si scrive il file per distinguere tra l'immagine del gatto e l'immagine del ponte. Utilizzare 0 per l'immagine di gatto, e 1 per l'immagine bridge:

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
      }
...

Si noti che tutte le funzioni sono ora immagazzinate nella tf.train.Example messaggio. Avanti, funzionalizzare il codice precedente e scrivere i messaggi di esempio in un file denominato 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

Leggi il file TFRecord

Ora avete nella gestione dei images.tfrecords -e ora possibile iterare negli record in esso rileggere quello che hai scritto. Dato che in questo esempio riprodurrai solo l'immagine, l'unica caratteristica di cui avrai bisogno è la stringa dell'immagine grezza. Estrarlo utilizzando i getter sopra descritte, cioè example.features.feature['image_raw'].bytes_list.value[0] . Puoi anche utilizzare le etichette per determinare quale record è il gatto e quale è il ponte:

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}>

Recupera le immagini dal file TFRecord:

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

jpeg

jpeg