Veja 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.
Os buffers de protocolo são uma biblioteca multiplataforma e multilíngue para serialização eficiente de dados estruturados.
As mensagens de protocolo são definidas por arquivos .proto
, que geralmente são a maneira mais fácil de entender um tipo de mensagem.
A mensagem tf.train.Example
(ou protobuf) é um tipo de mensagem flexível que representa um mapeamento {"string": value}
. Ele foi projetado para uso com o TensorFlow e é usado em todas as APIs de nível superior, como TFX .
Este notebook demonstra como criar, analisar e usar a mensagem tf.train.Example
e, em seguida, serializar, gravar e ler mensagens tf.train.Example
de e para arquivos .tfrecord
.
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
é um mapeamento {"string": tf.train.Feature}
.
O tipo de mensagem tf.train.Feature
pode aceitar um dos três tipos a seguir (consulte o arquivo .proto
para referência). A maioria dos outros tipos genéricos podem ser coagidos a um destes:
tf.train.BytesList
(os seguintes tipos podem ser coagidos)-
string
-
byte
-
tf.train.FloatList
(os seguintes tipos podem ser coagidos)-
float
(float32
) -
double
(float64
)
-
tf.train.Int64List
(os seguintes tipos podem ser forçados)-
bool
-
enum
-
int32
-
uint32
-
int64
-
uint64
-
Para converter um tipo padrão do TensorFlow em um tf.train.Example
compatível com tf.train.Feature
, você pode usar as funções de atalho abaixo. Observe que cada função recebe um valor de entrada escalar e retorna um tf.train.Feature
contendo um dos três tipos de list
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 corresponder a um dos tipos coercíveis mencionados acima, a função gerará uma exceção (por exemplo _int64_feature(1.0)
apresentará um erro porque 1.0
é um float - portanto, deve ser usado com a função _float_feature
em vez disso ):
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 podem ser serializadas para uma string binária usando o método .SerializeToString
:
feature = _float_feature(np.exp(1))
feature.SerializeToString()
b'\x12\x06\n\x04T\xf8-@'
Criando uma mensagem tf.train.Example
Suponha que você queira criar uma mensagem tf.train.Example
a partir de dados existentes. Na prática, o conjunto de dados pode vir de qualquer lugar, mas o procedimento de criação da mensagem tf.train.Example
a partir de uma única observação será o mesmo:
Dentro de cada observação, cada valor precisa ser convertido em um
tf.train.Feature
contendo um dos 3 tipos compatíveis, usando uma das funções acima.Você cria um mapa (dicionário) da string do nome do recurso para o valor do recurso codificado produzido em #1.
O mapa produzido na etapa 2 é convertido em uma mensagem de
Features
.
Neste notebook, você criará um conjunto de dados usando o NumPy.
Este conjunto de dados terá 4 recursos:
- um recurso booleano,
False
ouTrue
com igual probabilidade - um recurso inteiro uniformemente escolhido aleatoriamente de
[0, 5]
- um recurso de string gerado a partir de uma tabela de strings usando o recurso de inteiro como um índice
- um recurso float de uma distribuição normal padrão
Considere uma amostra composta por 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 forçado a um tipo compatível com tf.train.Example
usando um de _bytes_feature
, _float_feature
, _int64_feature
. Você pode então criar uma mensagem tf.train.Example
a partir destes 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 a mensagem tf.train.Example
para esta observação usando create_message()
. Cada observação individual será escrita como uma mensagem de Features
conforme descrito acima. Observe que a mensagem tf.train.Example
é apenas um wrapper em torno da mensagem Features
:
# 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\x11\n\x08feature1\x12\x05\x1a\x03\n\x01\x04\n\x11\n\x08feature0\x12\x05\x1a\x03\n\x01\x00\n\x14\n\x08feature3\x12\x08\x12\x06\n\x04[\xd3|?'
Para decodificar a mensagem, use o método 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 } } } }
Detalhes do formato TFRecords
Um arquivo TFRecord contém uma sequência de registros. O arquivo só pode ser lido sequencialmente.
Cada registro contém uma cadeia de bytes, para a carga útil de dados, mais o comprimento dos dados e hashes CRC-32C ( CRC de 32 bits usando o polinômio Castagnoli ) 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 juntos para produzir o arquivo. Os CRCs são descritos aqui e a máscara de um CRC é:
masked_crc = ((crc >> 15) | (crc << 17)) + 0xa282ead8ul
Arquivos TFRecord usando tf.data
O módulo tf.data
também fornece ferramentas para leitura e gravação de dados no TensorFlow.
Escrevendo um arquivo TFRecord
A maneira mais fácil de obter os dados em um conjunto de dados é usar o método from_tensor_slices
.
Aplicado a um array, ele retorna um conjunto de dados de escalares:
tf.data.Dataset.from_tensor_slices(feature1)
<TensorSliceDataset element_spec=TensorSpec(shape=(), dtype=tf.int64, name=None)>
Aplicado a uma tupla de arrays, ele retorna um conjunto de dados de tuplas:
features_dataset = tf.data.Dataset.from_tensor_slices((feature0, feature1, feature2, feature3))
features_dataset
<TensorSliceDataset element_spec=(TensorSpec(shape=(), dtype=tf.bool, name=None), TensorSpec(shape=(), dtype=tf.int64, name=None), TensorSpec(shape=(), dtype=tf.string, name=None), TensorSpec(shape=(), dtype=tf.float64, name=None))>
# 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(4, shape=(), dtype=int64) tf.Tensor(b'goat', shape=(), dtype=string) tf.Tensor(0.5251196235602504, shape=(), dtype=float64)
Use o método tf.data.Dataset.map
para aplicar uma função a cada elemento de um Dataset
.
A função mapeada deve operar no modo gráfico do TensorFlow — ela deve operar e retornar tf.Tensors
. Uma função não tensora, como serialize_example
, pode ser encapsulada com tf.py_function
para torná-la compatível.
O uso de tf.py_function
requer especificar as informações de forma e tipo que de outra forma não estão disponí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'\nR\n\x14\n\x08feature3\x12\x08\x12\x06\n\x04=n\x06?\n\x11\n\x08feature0\x12\x05\x1a\x03\n\x01\x00\n\x14\n\x08feature2\x12\x08\n\x06\n\x04goat\n\x11\n\x08feature1\x12\x05\x1a\x03\n\x01\x04'>
Aplique esta função a cada elemento no conjunto de dados:
serialized_features_dataset = features_dataset.map(tf_serialize_example)
serialized_features_dataset
<MapDataset element_spec=TensorSpec(shape=(), dtype=tf.string, name=None)>
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 element_spec=TensorSpec(shape=(), dtype=tf.string, name=None)>
E grave-os em um arquivo TFRecord:
filename = 'test.tfrecord'
writer = tf.data.experimental.TFRecordWriter(filename)
writer.write(serialized_features_dataset)
WARNING:tensorflow:From /tmp/ipykernel_25215/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 a classe tf.data.TFRecordDataset
.
Mais informações sobre o consumo de arquivos TFRecord usando tf.data
podem ser encontradas no guia tf.data: Build TensorFlow input pipelines .
O uso TFRecordDataset
s pode ser útil para padronizar dados de entrada e otimizar o desempenho.
filenames = [filename]
raw_dataset = tf.data.TFRecordDataset(filenames)
raw_dataset
<TFRecordDatasetV2 element_spec=TensorSpec(shape=(), dtype=tf.string, name=None)>
Neste ponto, o conjunto de dados contém mensagens tf.train.Example
serializadas. Quando iterado, ele os retorna como tensores de string escalares.
Use o método .take
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'\nR\n\x11\n\x08feature0\x12\x05\x1a\x03\n\x01\x00\n\x11\n\x08feature1\x12\x05\x1a\x03\n\x01\x04\n\x14\n\x08feature2\x12\x08\n\x06\n\x04goat\n\x14\n\x08feature3\x12\x08\x12\x06\n\x04=n\x06?'> <tf.Tensor: shape=(), dtype=string, numpy=b'\nR\n\x11\n\x08feature1\x12\x05\x1a\x03\n\x01\x04\n\x11\n\x08feature0\x12\x05\x1a\x03\n\x01\x01\n\x14\n\x08feature3\x12\x08\x12\x06\n\x04\x9d\xfa\x98\xbe\n\x14\n\x08feature2\x12\x08\n\x06\n\x04goat'> <tf.Tensor: shape=(), dtype=string, numpy=b'\nQ\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\x04a\xc0r?\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\x01\n\x11\n\x08feature1\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\x92Q(?'> <tf.Tensor: shape=(), dtype=string, numpy=b'\nR\n\x14\n\x08feature2\x12\x08\n\x06\n\x04goat\n\x14\n\x08feature3\x12\x08\x12\x06\n\x04>\xc0\xe5>\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'\nU\n\x14\n\x08feature3\x12\x08\x12\x06\n\x04I!\xde\xbe\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'> <tf.Tensor: shape=(), dtype=string, numpy=b'\nQ\n\x11\n\x08feature1\x12\x05\x1a\x03\n\x01\x00\n\x11\n\x08feature0\x12\x05\x1a\x03\n\x01\x01\n\x14\n\x08feature3\x12\x08\x12\x06\n\x04\xe0\x1a\xab\xbf\n\x13\n\x08feature2\x12\x07\n\x05\n\x03cat'> <tf.Tensor: shape=(), dtype=string, numpy=b'\nQ\n\x13\n\x08feature2\x12\x07\n\x05\n\x03cat\n\x11\n\x08feature0\x12\x05\x1a\x03\n\x01\x01\n\x14\n\x08feature3\x12\x08\x12\x06\n\x04\x87\xb2\xd7?\n\x11\n\x08feature1\x12\x05\x1a\x03\n\x01\x00'> <tf.Tensor: shape=(), dtype=string, numpy=b'\nR\n\x11\n\x08feature1\x12\x05\x1a\x03\n\x01\x04\n\x11\n\x08feature0\x12\x05\x1a\x03\n\x01\x01\n\x14\n\x08feature3\x12\x08\x12\x06\n\x04n\xe19>\n\x14\n\x08feature2\x12\x08\n\x06\n\x04goat'> <tf.Tensor: shape=(), dtype=string, numpy=b'\nR\n\x14\n\x08feature3\x12\x08\x12\x06\n\x04\x1as\xd9\xbf\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\x08feature2\x12\x08\n\x06\n\x04goat'>
Esses tensores podem ser analisados usando a função abaixo. Observe que a feature_description
é necessária aqui porque tf.data.Dataset
s usam graph-execution e precisam dessa descrição para construir sua forma e assinatura de tipo:
# 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)
Como alternativa, use tf.parse example
para analisar todo o lote de uma vez. Aplique esta função a cada item no conjunto de dados usando o método tf.data.Dataset.map
:
parsed_dataset = raw_dataset.map(_parse_function)
parsed_dataset
<MapDataset element_spec={'feature0': TensorSpec(shape=(), dtype=tf.int64, name=None), 'feature1': TensorSpec(shape=(), dtype=tf.int64, name=None), 'feature2': TensorSpec(shape=(), dtype=tf.string, name=None), 'feature3': TensorSpec(shape=(), dtype=tf.float32, name=None)}>
Use a execução antecipada para exibir as observações no conjunto de dados. Existem 10.000 observações neste conjunto de dados, mas você exibirá apenas as 10 primeiras. Os dados são exibidos como um dicionário de recursos. Cada item é um tf.Tensor
e o elemento numpy
desse 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=0>, '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.5251196>} {'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.29878703>} {'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.94824797>} {'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.65749466>} {'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.44873232>} {'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.4338477>} {'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=-1.3367577>} {'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=1.6851357>} {'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.18152401>} {'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.6988251>}
Aqui, a função tf.parse_example
descompacta os campos tf.train.Example
em tensores padrão.
Arquivos TFRecord em Python
O módulo tf.io
também contém funções Python puras para leitura e gravação de arquivos TFRecord.
Escrevendo um arquivo TFRecord
Em seguida, grave as 10.000 observações no arquivo test.tfrecord
. Cada observação é convertida em uma mensagem tf.train.Example
e, em seguida, gravada 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
Esses tensores serializados podem ser facilmente analisados usando tf.train.Example.ParseFromString
:
filenames = [filename]
raw_dataset = tf.data.TFRecordDataset(filenames)
raw_dataset
<TFRecordDatasetV2 element_spec=TensorSpec(shape=(), dtype=tf.string, name=None)>
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: 4 } } } feature { key: "feature2" value { bytes_list { value: "goat" } } } feature { key: "feature3" value { float_list { value: 0.5251196026802063 } } } }
Isso retorna um proto tf.train.Example
que é difícil de usar como está, mas é fundamentalmente uma representação de:
Dict[str,
Union[List[float],
List[int],
List[str]]]
O código a seguir converte manualmente o Example
em um dicionário de matrizes NumPy, sem usar o TensorFlow Ops. Consulte o arquivo PROTO para detalhes.
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
{'feature3': array([0.5251196]), 'feature1': array([4]), 'feature0': array([0]), 'feature2': array([b'goat'], dtype='|S4')}
Passo a passo: Lendo e gravando dados de imagem
Este é um exemplo de ponta a ponta 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, depois 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 todo o processamento e modelagem posterior.
Primeiro, vamos baixar esta imagem de um gato na neve e esta foto da Williamsburg Bridge, 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>'))
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>'))
Escreva o arquivo TFRecord
Como antes, codifique os recursos como tipos compatíveis com tf.train.Example
. Isso armazena o recurso de string de imagem bruta, bem como o recurso de altura, largura, profundidade e label
arbitrário. O último é usado quando você escreve o arquivo para distinguir entre a imagem do gato e a imagem da ponte. Use 0
para a imagem do 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 agora estão armazenados na mensagem tf.train.Example
. Em seguida, funcionalize o código acima e grave as mensagens de exemplo em 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
Agora você tem o arquivo — images.tfrecords
— e pode iterar sobre os registros nele para ler o que escreveu. Dado que neste exemplo você reproduzirá apenas a imagem, o único recurso que você precisará é a string de imagem bruta. Extraia-o usando os getters descritos acima, ou seja, 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 element_spec={'depth': TensorSpec(shape=(), dtype=tf.int64, name=None), 'height': TensorSpec(shape=(), dtype=tf.int64, name=None), 'image_raw': TensorSpec(shape=(), dtype=tf.string, name=None), 'label': TensorSpec(shape=(), dtype=tf.int64, name=None), 'width': TensorSpec(shape=(), dtype=tf.int64, name=None)}>
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))