TFRecord e tf.train.Example

Ver no TensorFlow.org Executar no Google Colab Ver fonte no GitHub Baixar caderno

O formato TFRecord é um formato simples para armazenar uma sequência de registros binários.

Buffers de protocolo são um cross-platform, biblioteca cross-language para serialização eficiente de dados estruturados.

Mensagens do protocolo são definidos por .proto arquivos, estes são muitas vezes a maneira mais fácil de entender um tipo de mensagem.

O tf.train.Example mensagem (ou protobuf) é um tipo de mensagem flexível que representa uma {"string": value} mapeamento. Foi concebido para ser utilizado com TensorFlow e é usado ao longo dos APIs de nível mais elevado, tais como TFX .

Este notebook demonstra como criar, analisar e usar o tf.train.Example mensagem, e depois serialize, escrever e ler tf.train.Example mensagens de e para .tfrecord arquivos.

Configurar

import tensorflow as tf

import numpy as np
import IPython.display as display

tf.train.Example

Tipos de dados para tf.train.Example

Fundamentalmente, um tf.train.Example é uma {"string": tf.train.Feature} mapeamento.

O tf.train.Feature tipo de mensagem pode aceitar um dos três tipos seguintes (Veja o .proto arquivo para referência). A maioria dos outros tipos genéricos podem ser forçados a um destes:

  1. tf.train.BytesList (os seguintes tipos podem ser coagido)

    • string
    • byte
  2. tf.train.FloatList (os seguintes tipos podem ser coagido)

    • float ( float32 )
    • double ( float64 )
  3. tf.train.Int64List (os seguintes tipos podem ser coagido)

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

Para converter um tipo TensorFlow padrão a um tf.train.Example -Compatível tf.train.Feature , você pode usar as funções de atalho abaixo. Note-se que cada função tem um valor de entrada escalar e retorna um tf.train.Feature contendo um dos três list tipos acima:

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

Abaixo estão alguns exemplos de como essas funções funcionam. Observe os diversos tipos de entrada e os tipos de saída padronizados. Se o tipo de entrada para uma função não coincide com um dos tipos coercible indicado acima, a função irá levantar uma excepção (por exemplo _int64_feature(1.0) será erro porque 1.0 é um float, por conseguinte, deve ser utilizada com o _float_feature função em vez ):

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
}

Todas as mensagens proto pode ser serializado para uma string binária usando o .SerializeToString método:

feature = _float_feature(np.exp(1))

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

Criando um tf.train.Example mensagem

Suponha que você queira criar um tf.train.Example mensagem a partir de dados existentes. Na prática, o conjunto de dados pode vir de qualquer lugar, mas o procedimento de criação da tf.train.Example mensagem de uma única observação será o mesmo:

  1. Dentro de cada observação, cada valor tem de ser convertida para um tf.train.Feature contendo um dos 3 tipos compatíveis, usando uma das funções acima.

  2. Você cria um mapa (dicionário) a partir da string do nome do recurso para o valor do recurso codificado produzido em # 1.

  3. O mapa produzido no passo 2 é convertido para um Features mensagem .

Neste bloco de notas, você criará um conjunto de dados usando NumPy.

Este conjunto de dados terá 4 recursos:

  • uma característica boolean, False ou True com igual probabilidade
  • uma característica inteiro uniformemente aleatoriamente escolhido a partir de [0, 5]
  • um recurso de string gerado a partir de uma tabela de string usando o recurso de inteiro como um índice
  • um recurso flutuante de uma distribuição normal padrão

Considere uma amostra que consiste em 10.000 observações distribuídas de forma independente e idêntica de cada uma das distribuições acima:

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

Cada um desses recursos pode ser coagido a um tf.train.Example tipo -Compatível usando um dos _bytes_feature , _float_feature , _int64_feature . Você pode então criar um tf.train.Example mensagem desses recursos codificados:

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

Por exemplo, suponha que você tenha uma única observação do conjunto de dados, [False, 4, bytes('goat'), 0.9876] . Você pode criar e imprimir o tf.train.Example mensagem para esta observação usando create_message() . Cada única observação vai ser escrito como uma Features mensagem de acordo com o acima. Note que o tf.train.Example mensagem é apenas um invólucro em torno do Features mensagem:

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

Para decodificar o uso de mensagem de tf.train.Example.FromString método.

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

Detalhes do formato TFRecords

Um arquivo TFRecord contém uma sequência de registros. O arquivo só pode ser lido sequencialmente.

Cada registo contém um byte-cadeia, por os dados de carga útil, além do comprimento dos dados, e CRC-32C ( 32 bits CRC utilizando o polinómio Castagnoli hash para verificação de integridade).

Cada registro é armazenado nos seguintes formatos:

uint64 length
uint32 masked_crc32_of_length
byte   data[length]
uint32 masked_crc32_of_data

Os registros são concatenados para produzir o arquivo. CRCs são descritos aqui , ea máscara de um CRC é:

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

TFRecord arquivos usando tf.data

O tf.data módulo também fornece ferramentas para ler e escrever dados em TensorFlow.

Gravando um arquivo TFRecord

A maneira mais fácil de obter os dados em um conjunto de dados é usar o from_tensor_slices método.

Aplicado a uma matriz, ele retorna um conjunto de dados de escalares:

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

Aplicado a uma tupla de matrizes, ele retorna um conjunto de dados de tuplas:

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)

Utilizar a tf.data.Dataset.map método para aplicar uma função de cada elemento de um Dataset .

A função mapeado deve operar no gráfico TensorFlow modo que devem operar em e retornar tf.Tensors . A função não-tensor, como serialize_example , pode ser embrulhado com tf.py_function para torná-lo compatível.

Usando tf.py_function requer para especificar a forma eo tipo de informação que é de outra forma indisponíveis:

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

Aplique esta função a cada elemento no conjunto de dados:

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 gravá-los em um arquivo 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`

Lendo um arquivo TFRecord

Você também pode ler o arquivo TFRecord usando o tf.data.TFRecordDataset classe.

Mais informações sobre consumir arquivos TFRecord usando tf.data pode ser encontrada no tf.data: Constituição dutos de entrada TensorFlow guia.

Usando TFRecordDataset s pode ser útil para normalizar os dados de entrada e optimizar o desempenho.

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

Neste ponto, o conjunto de dados contém serializados tf.train.Example mensagens. Quando iterado, ele os retorna como tensores de string escalar.

Use o .take método para mostrar apenas os 10 primeiros registros.

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

Esses tensores podem ser analisados ​​usando a função abaixo. Note que o feature_description é necessário aqui porque tf.data.Dataset uso gráfico execução s, e precisa esta descrição para construir a sua forma e tipo de assinatura:

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

Alternativamente, usar tf.parse example para analisar todo o lote de uma só vez. Aplicar esta função para cada item no conjunto de dados usando o tf.data.Dataset.map método:

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

Use a execução rápida para exibir as observações no conjunto de dados. Existem 10.000 observações neste conjunto de dados, mas você só exibirá as primeiras 10. Os dados são exibidos como um dicionário de recursos. Cada item é um tf.Tensor , eo numpy elemento desta tensor exibe o valor do recurso:

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

Aqui, o tf.parse_example função descompacta os tf.train.Example campos em tensores padrão.

Arquivos TFRecord em Python

O tf.io módulo também contém funções de Python puro para ler e escrever arquivos TFRecord.

Gravando um arquivo TFRecord

Em seguida, escreva as 10.000 observações para o arquivo test.tfrecord . Cada observação é convertido para um tf.train.Example mensagem, em seguida, gravados no arquivo. Você pode, então, verificar se o arquivo test.tfrecord foi criado:

# 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

Lendo um arquivo TFRecord

Estes tensores serializados podem ser facilmente analisado usando 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
      }
    }
  }
}

Que retorna um tf.train.Example proto que é dificil para uso como é, mas é fundamentalmente uma representação de um:

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

O código a seguir converte manualmente o Example de um dicionário de matrizes Numpy, sem utilizar TensorFlow oper. Consulte o arquivo PROTO para 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])}

Passo a passo: Leitura e gravação de dados de imagem

Este é um exemplo completo de como ler e gravar dados de imagem usando TFRecords. Usando uma imagem como dados de entrada, você gravará os dados como um arquivo TFRecord e, em seguida, lerá o arquivo de volta e exibirá a imagem.

Isso pode ser útil se, por exemplo, você quiser usar vários modelos no mesmo conjunto de dados de entrada. Em vez de armazenar os dados brutos da imagem, eles podem ser pré-processados ​​no formato TFRecords e podem ser usados ​​em todos os processamentos e modelagens posteriores.

Primeiro, vamos baixar esta imagem de um gato na neve e esta foto da ponte de Williamsburg, NYC em construção.

Pegue as imagens

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

Grave o arquivo TFRecord

Como antes, codificar as características como tipos compatíveis com tf.train.Example . Isso armazena o recurso corda cru imagem, bem como a altura, largura, profundidade e arbitrário label recurso. O último é usado quando você grava o arquivo para distinguir entre a imagem do gato e a imagem da ponte. Use 0 para a imagem de gato, e 1 para a imagem da ponte:

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

Observe que todos os recursos estão agora armazenadas no tf.train.Example mensagem. Em seguida, funcionalizar o código acima e escrever os exemplos de mensagens para um arquivo chamado 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

Leia o arquivo TFRecord

Você tem agora na janela de gestão images.tfrecords -e agora podem interagir sobre os registros em que voltar a ler o que você escreveu. Dado que, neste exemplo, você apenas reproduzirá a imagem, o único recurso de que precisará é a string de imagem bruta. Extraí-la utilizando os getters acima descrito, nomeadamente example.features.feature['image_raw'].bytes_list.value[0] . Você também pode usar os rótulos para determinar qual registro é o gato e qual é a 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}>

Recupere as imagens do arquivo TFRecord:

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

JPEG

JPEG