Посмотреть на TensorFlow.org | Запустить в Google Colab | Посмотреть исходный код на GitHub | Скачать блокнот |
Формат TFRecord — это простой формат для хранения последовательности двоичных записей.
Буферы протоколов — это межплатформенная и межъязыковая библиотека для эффективной сериализации структурированных данных.
Сообщения протокола определяются файлами .proto
, часто это самый простой способ понять тип сообщения.
Сообщение tf.train.Example
(или protobuf) — это гибкий тип сообщения, представляющий сопоставление {"string": value}
. Он предназначен для использования с TensorFlow и используется во всех API более высокого уровня, таких как TFX .
В этой записной книжке показано, как создавать, анализировать и использовать сообщение tf.train.Example
, а затем сериализовать, записывать и читать сообщения tf.train.Example
в файлы .tfrecord
и из них.
Настраивать
import tensorflow as tf
import numpy as np
import IPython.display as display
tf.train.Example
Типы данных для tf.train.Example
По сути, tf.train.Example
представляет собой сопоставление {"string": tf.train.Feature}
.
Тип сообщения tf.train.Feature
может принимать один из следующих трех типов (см . файл .proto
для справки). Большинство других универсальных типов можно привести к одному из следующих:
tf.train.BytesList
(можно принудительно указать следующие типы)-
string
-
byte
-
tf.train.FloatList
(можно принудительно указать следующие типы)-
float
(float32
) -
double
(float64
)
-
tf.train.Int64List
(можно принудительно использовать следующие типы)-
bool
-
enum
-
int32
-
uint32
-
int64
-
uint64
-
Чтобы преобразовать стандартный тип TensorFlow в tf.train.Example
совместимый tf.train.Feature
, вы можете использовать функции быстрого доступа ниже. Обратите внимание, что каждая функция принимает скалярное входное значение и возвращает tf.train.Feature
, содержащий один из трех типов list
выше:
# 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]))
Ниже приведены несколько примеров того, как работают эти функции. Обратите внимание на различные типы ввода и стандартизированные типы вывода. Если тип входных данных для функции не соответствует одному из указанных выше принудительных типов, функция вызовет исключение (например _int64_feature(1.0)
выдаст ошибку, поскольку 1.0
является числом с плавающей запятой, поэтому его следует использовать вместо этого с функцией _float_feature
):
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 }
Все прото-сообщения можно сериализовать в двоичную строку с помощью метода .SerializeToString
:
feature = _float_feature(np.exp(1))
feature.SerializeToString()
b'\x12\x06\n\x04T\xf8-@'
Создание сообщения tf.train.Example
Предположим, вы хотите создать сообщение tf.train.Example
из существующих данных. На практике набор данных может прийти откуда угодно, но процедура создания сообщения tf.train.Example
из одного наблюдения будет одинаковой:
В каждом наблюдении каждое значение должно быть преобразовано в
tf.train.Feature
, содержащий один из 3 совместимых типов, с использованием одной из вышеперечисленных функций.Вы создаете карту (словарь) из строки имени объекта в закодированное значение объекта, полученное в #1.
Карта, созданная на шаге 2, преобразуется в сообщение о
Features
.
В этой записной книжке вы создадите набор данных с помощью NumPy.
Этот набор данных будет иметь 4 функции:
- логическая функция,
False
илиTrue
с равной вероятностью - целочисленный признак, равномерно выбранный случайным образом из
[0, 5]
- строковая функция, сгенерированная из таблицы строк с использованием целочисленной функции в качестве индекса
- функция с плавающей запятой из стандартного нормального распределения
Рассмотрим выборку, состоящую из 10 000 независимо и одинаково распределенных наблюдений из каждого из приведенных выше распределений:
# 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)
Каждая из этих функций может быть преобразована в тип, совместимый с tf.train.Example
, с помощью одного из _bytes_feature
, _float_feature
, _int64_feature
. Затем вы можете создать сообщение tf.train.Example
из этих закодированных функций:
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()
Например, предположим, что у вас есть одно наблюдение из набора данных [False, 4, bytes('goat'), 0.9876]
. Вы можете создать и распечатать сообщение tf.train.Example
для этого наблюдения, используя create_message()
. Каждое отдельное наблюдение будет записано как сообщение о Features
, как указано выше. Обратите внимание, что сообщение tf.train.Example
— это всего лишь обертка сообщения 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|?'
Для декодирования сообщения используйте метод 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 } } } }
Сведения о формате TFRecords
Файл TFRecord содержит последовательность записей. Файл может быть прочитан только последовательно.
Каждая запись содержит строку байтов для полезной нагрузки данных, а также длину данных и хэши CRC-32C ( 32-разрядная CRC с использованием полинома Кастаньоли ) для проверки целостности.
Каждая запись хранится в следующих форматах:
uint64 length
uint32 masked_crc32_of_length
byte data[length]
uint32 masked_crc32_of_data
Записи объединяются вместе для создания файла. CRC описаны здесь , а маска CRC:
masked_crc = ((crc >> 15) | (crc << 17)) + 0xa282ead8ul
Файлы TFRecord с использованием tf.data
Модуль tf.data
также предоставляет инструменты для чтения и записи данных в TensorFlow.
Запись файла TFRecord
Самый простой способ получить данные в наборе данных — использовать метод from_tensor_slices
.
Применительно к массиву он возвращает набор скаляров:
tf.data.Dataset.from_tensor_slices(feature1)
<TensorSliceDataset element_spec=TensorSpec(shape=(), dtype=tf.int64, name=None)>
Применительно к кортежу массивов он возвращает набор данных кортежей:
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)
Используйте метод tf.data.Dataset.map
, чтобы применить функцию к каждому элементу Dataset
.
Сопоставляемая функция должна работать в режиме графа TensorFlow — она должна работать и возвращать tf.Tensors
. Нетензорную функцию, такую как serialize_example
, можно обернуть tf.py_function
, чтобы сделать ее совместимой.
Использование tf.py_function
требует указать информацию о форме и типе, которая иначе недоступна:
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'>
Примените эту функцию к каждому элементу в наборе данных:
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)>
И запишите их в файл 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`
Чтение файла TFRecord
Вы также можете прочитать файл TFRecord, используя класс tf.data.TFRecordDataset
.
Дополнительную информацию об использовании файлов TFRecord с использованием tf.data
можно найти в руководстве tf.data: Build TensorFlow input Pipelines .
Использование TFRecordDataset
может быть полезно для стандартизации входных данных и оптимизации производительности.
filenames = [filename]
raw_dataset = tf.data.TFRecordDataset(filenames)
raw_dataset
<TFRecordDatasetV2 element_spec=TensorSpec(shape=(), dtype=tf.string, name=None)>
На данный момент набор данных содержит сериализованные сообщения tf.train.Example
. При повторении он возвращает их как тензоры скалярных строк.
Используйте метод .take
, чтобы отобразить только первые 10 записей.
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'>
Эти тензоры можно проанализировать с помощью функции ниже. Обратите внимание, что здесь необходимо использовать feature_description
, потому что tf.data.Dataset
использует графовое выполнение и нуждается в этом описании для создания своей формы и сигнатуры типа:
# 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)
В качестве альтернативы используйте tf.parse example
для одновременного анализа всего пакета. Примените эту функцию к каждому элементу в наборе данных, используя метод 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)}>
Используйте активное выполнение для отображения наблюдений в наборе данных. В этом наборе данных 10 000 наблюдений, но вы отобразите только первые 10. Данные отображаются в виде словаря признаков. Каждый элемент представляет собой tf.Tensor
, и элемент numpy
этого тензора отображает значение функции:
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>}
Здесь функция tf.parse_example
распаковывает поля tf.train.Example
в стандартные тензоры.
Файлы TFRecord в Python
Модуль tf.io
также содержит функции чистого Python для чтения и записи файлов TFRecord.
Запись файла TFRecord
Затем запишите 10 000 наблюдений в файл test.tfrecord
. Каждое наблюдение преобразуется в сообщение tf.train.Example
, а затем записывается в файл. Затем вы можете убедиться, что файл test.tfrecord
создан:
# 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
Чтение файла TFRecord
Эти сериализованные тензоры можно легко проанализировать с помощью 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 } } } }
Это возвращает tf.train.Example
, который сложно использовать как есть, но в основном это представление:
Dict[str,
Union[List[float],
List[int],
List[str]]]
Следующий код вручную преобразует Example
в словарь массивов NumPy без использования TensorFlow Ops. Подробности см. в файле PROTO .
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')}
Пошаговое руководство: чтение и запись данных изображения
Это сквозной пример того, как читать и записывать данные изображения с помощью TFRecords. Используя изображение в качестве входных данных, вы запишете данные в виде файла TFRecord, затем прочитаете файл обратно и отобразите изображение.
Это может быть полезно, если, например, вы хотите использовать несколько моделей в одном наборе входных данных. Вместо того, чтобы хранить необработанные данные изображения, их можно предварительно обработать в формате TFRecords, и это можно использовать во всей дальнейшей обработке и моделировании.
Во-первых, давайте загрузим это изображение кота в снегу и это фото строящегося Вильямсбургского моста в Нью-Йорке.
Получить изображения
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>'))
Запишите файл TFRecord
Как и прежде, закодируйте функции как типы, совместимые с tf.train.Example
. Здесь хранится функция необработанной строки изображения, а также функция высоты, ширины, глубины и произвольной label
. Последнее используется, когда вы пишете файл, чтобы различать изображение кошки и изображение моста. Используйте 0
для изображения кошки и 1
для изображения моста:
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 } ...
Обратите внимание, что все функции теперь хранятся в сообщении tf.train.Example
. Затем функционализируйте приведенный выше код и запишите примеры сообщений в файл с именем 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
Прочитайте файл TFRecord
Теперь у вас есть файл images.tfrecords
и теперь вы можете перебирать записи в нем, чтобы прочитать то, что вы написали. Учитывая, что в этом примере вы будете воспроизводить только изображение, единственная функция, которая вам понадобится, — это необработанная строка изображения. Извлеките его с помощью геттеров, описанных выше, а именно example.features.feature['image_raw'].bytes_list.value[0]
. Вы также можете использовать метки, чтобы определить, какая запись является кошкой, а какая — мостом:
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)}>
Восстановите изображения из файла TFRecord:
for image_features in parsed_image_dataset:
image_raw = image_features['image_raw'].numpy()
display.display(display.Image(data=image_raw))