Zobacz na TensorFlow.org | Uruchom w Google Colab | Wyświetl źródło na GitHub | Pobierz notatnik |
Format TFRecord to prosty format do przechowywania sekwencji rekordów binarnych.
Bufory protokołów to wieloplatformowa, wielojęzyczna biblioteka do wydajnej serializacji uporządkowanych danych.
Komunikaty protokołu są definiowane przez pliki .proto
, są to często najłatwiejszy sposób zrozumienia typu komunikatu.
Komunikat tf.train.Example
(lub protobuf) to elastyczny typ komunikatu, który reprezentuje mapowanie {"string": value}
. Został zaprojektowany do użytku z TensorFlow i jest używany przez interfejsy API wyższego poziomu, takie jak TFX .
W tym notatniku pokazano, jak tworzyć, analizować i używać komunikatu tf.train.Example
, a następnie serializować, zapisywać i odczytywać komunikaty tf.train.Example
do iz plików .tfrecord
.
Ustawiać
import tensorflow as tf
import numpy as np
import IPython.display as display
tf.train.Example
Typy danych dla tf.train.Example
Zasadniczo tf.train.Example
to mapowanie {"string": tf.train.Feature}
.
Typ komunikatu tf.train.Feature
może akceptować jeden z następujących trzech typów (patrz plik .proto
w celu uzyskania informacji). Większość innych typów ogólnych można zmusić do jednego z tych:
tf.train.BytesList
(można wymusić następujące typy)-
string
-
byte
-
tf.train.FloatList
(można wymusić następujące typy)-
float
(float32
) -
double
(float64
)
-
tf.train.Int64List
(można wymusić następujące typy)-
bool
-
enum
-
int32
-
uint32
-
int64
-
uint64
-
Aby przekonwertować standardowy typ TensorFlow na tf.train.Example
tf.train.Feature
, możesz użyć poniższych funkcji skrótów. Zauważ, że każda funkcja pobiera skalarną wartość wejściową i zwraca tf.train.Feature
zawierającą jeden z trzech powyższych typów 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]))
Poniżej znajduje się kilka przykładów działania tych funkcji. Zwróć uwagę na różne typy wejść i standardowe typy wyjść. Jeśli typ danych wejściowych dla funkcji nie pasuje do jednego z typów koercjalnych wymienionych powyżej, funkcja zgłosi wyjątek (np _int64_feature(1.0)
błąd, ponieważ 1.0
jest liczbą zmiennoprzecinkową — w związku z tym powinna być używana z funkcją _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 }
Wszystkie komunikaty proto mogą być serializowane do ciągu binarnego przy użyciu metody .SerializeToString
:
feature = _float_feature(np.exp(1))
feature.SerializeToString()
b'\x12\x06\n\x04T\xf8-@'
Tworzenie tf.train.Example
wiadomość
Załóżmy, że chcesz utworzyć komunikat tf.train.Example
z istniejących danych. W praktyce zbiór danych może pochodzić z dowolnego miejsca, ale procedura tworzenia tf.train.Example
wiadomość z pojedynczej obserwacji będzie taka sama:
W ramach każdej obserwacji każda wartość musi zostać przekonwertowana na
tf.train.Feature
zawierającą jeden z 3 kompatybilnych typów przy użyciu jednej z powyższych funkcji.Tworzysz mapę (słownik) z ciągu nazwy elementu do zakodowanej wartości elementu utworzonej w #1.
Mapa utworzona w kroku 2 zostanie przekonwertowana na komunikat
Features
.
W tym notatniku utworzysz zestaw danych za pomocą NumPy.
Ten zbiór danych będzie miał 4 funkcje:
- funkcja logiczna,
False
lubTrue
z równym prawdopodobieństwem - cecha całkowita jednolicie losowo wybrana z
[0, 5]
- funkcja ciągu wygenerowana z tabeli ciągów przy użyciu funkcji liczb całkowitych jako indeksu
- funkcja zmiennoprzecinkowa ze standardowego rozkładu normalnego
Rozważmy próbkę składającą się z 10 000 niezależnie i identycznie rozłożonych obserwacji z każdego z powyższych rozkładów:
# 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)
Każdą z tych funkcji można przekształcić w typ zgodny z tf.train.Example
przy użyciu jednego z _bytes_feature
, _float_feature
, _int64_feature
. Następnie możesz utworzyć wiadomość tf.train.Example
z tych zakodowanych funkcji:
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()
Załóżmy na przykład, że masz pojedynczą obserwację ze zbioru danych, [False, 4, bytes('goat'), 0.9876]
. Możesz utworzyć i wydrukować komunikat tf.train.Example
dla tej obserwacji za pomocą funkcji create_message()
. Każda pojedyncza obserwacja zostanie zapisana jako komunikat Features
zgodnie z powyższym. Zauważ, że komunikat tf.train.Example
jest tylko opakowaniem wokół komunikatu 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|?'
Aby zdekodować wiadomość, użyj metody 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 } } } }
Szczegóły formatu TFRecords
Plik TFRecord zawiera sekwencję rekordów. Plik można odczytać tylko sekwencyjnie.
Każdy rekord zawiera ciąg bajtów dla ładunku danych oraz długość danych, a także skróty CRC-32C ( 32-bitowe CRC przy użyciu wielomianu Castagnoli ) służące do sprawdzania integralności.
Każdy rekord jest przechowywany w następujących formatach:
uint64 length
uint32 masked_crc32_of_length
byte data[length]
uint32 masked_crc32_of_data
Rekordy są łączone w celu utworzenia pliku. CRC są opisane tutaj , a maska CRC to:
masked_crc = ((crc >> 15) | (crc << 17)) + 0xa282ead8ul
Pliki TFRecord używające tf.data
Moduł tf.data
zapewnia również narzędzia do odczytywania i zapisywania danych w TensorFlow.
Zapisywanie pliku TFRecord
Najłatwiejszym sposobem wprowadzenia danych do zestawu danych jest użycie metody from_tensor_slices
.
Zastosowany do tablicy, zwraca zbiór danych skalarów:
tf.data.Dataset.from_tensor_slices(feature1)
<TensorSliceDataset element_spec=TensorSpec(shape=(), dtype=tf.int64, name=None)>
Zastosowany do krotki tablic, zwraca zbiór danych składający się z krotek:
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)
Użyj metody tf.data.Dataset.map
, aby zastosować funkcję do każdego elementu Dataset
.
Zmapowana funkcja musi działać w trybie wykresu TensorFlow — musi działać i zwracać tf.Tensors
. Funkcja bez tensora, taka jak serialize_example
, może być opakowana za pomocą tf.py_function
, aby była zgodna.
Użycie tf.py_function
wymaga podania informacji o kształcie i typie, które w innym przypadku są niedostępne:
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'>
Zastosuj tę funkcję do każdego elementu w zbiorze danych:
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)>
I zapisz je do pliku 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`
Czytanie pliku TFRecord
Plik TFRecord można również odczytać za pomocą klasy tf.data.TFRecordDataset
.
Więcej informacji na temat korzystania z plików TFRecord przy użyciu tf.data
można znaleźć w przewodniku tf.data: Build TensorFlow input pipelines guide.
Używanie TFRecordDataset
s może być przydatne do standaryzacji danych wejściowych i optymalizacji wydajności.
filenames = [filename]
raw_dataset = tf.data.TFRecordDataset(filenames)
raw_dataset
<TFRecordDatasetV2 element_spec=TensorSpec(shape=(), dtype=tf.string, name=None)>
W tym momencie zbiór danych zawiera zserializowane komunikaty tf.train.Example
. Po iteracji zwraca je jako tensory łańcuchów skalarnych.
Użyj metody .take
, aby wyświetlić tylko pierwszych 10 rekordów.
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'>
Te tensory można analizować za pomocą poniższej funkcji. Zwróć uwagę, że opis funkcji jest tutaj niezbędny, ponieważ feature_description
s używają tf.data.Dataset
wykresu i potrzebują tego opisu, aby zbudować swój kształt i sygnaturę typu:
# 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)
Alternatywnie użyj tf.parse example
, aby przeanalizować całą partię naraz. Zastosuj tę funkcję do każdego elementu w zbiorze danych za pomocą metody 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)}>
Użyj szybkiego wykonania, aby wyświetlić obserwacje w zestawie danych. W tym zbiorze danych znajduje się 10 000 obserwacji, ale wyświetlisz tylko pierwszych 10. Dane są wyświetlane jako słownik cech. Każdy element to tf.Tensor
, a element numpy
tego tensora wyświetla wartość funkcji:
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>}
Tutaj funkcja tf.parse_example
rozpakowuje pola tf.train.Example
do standardowych tensorów.
Pliki TFRecord w Pythonie
Moduł tf.io
zawiera również czyste funkcje Pythona do odczytu i zapisu plików TFRecord.
Zapisywanie pliku TFRecord
Następnie zapisz 10 000 obserwacji do pliku test.tfrecord
. Każda obserwacja jest konwertowana na komunikat tf.train.Example
, a następnie zapisywana do pliku. Następnie możesz sprawdzić, czy plik test.tfrecord
został utworzony:
# 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
Czytanie pliku TFRecord
Te serializowane tensory można łatwo przeanalizować za pomocą 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 } } } }
Zwraca to proto tf.train.Example
, który jest trudny w użyciu, ale jest zasadniczo reprezentacją:
Dict[str,
Union[List[float],
List[int],
List[str]]]
Poniższy kod ręcznie konwertuje Example
na słownik tablic NumPy, bez użycia TensorFlow Ops. Więcej informacji można znaleźć w pliku 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')}
Przewodnik: odczytywanie i zapisywanie danych obrazu
To jest kompletny przykład, jak czytać i zapisywać dane obrazu za pomocą TFRecords. Używając obrazu jako danych wejściowych, zapiszesz dane jako plik TFRecord, a następnie odczytasz plik i wyświetlisz obraz.
Może to być przydatne, jeśli na przykład chcesz użyć kilku modeli na tym samym wejściowym zbiorze danych. Zamiast przechowywać surowe dane obrazu, można je wstępnie przetworzyć do formatu TFRecords, który można wykorzystać we wszystkich dalszych procesach przetwarzania i modelowania.
Najpierw pobierzmy to zdjęcie kota na śniegu i to zdjęcie mostu Williamsburg, NYC w budowie.
Pobierz obrazy
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>'))
Zapisz plik TFRecord
Tak jak poprzednio, zakoduj funkcje jako typy zgodne z tf.train.Example
. To przechowuje funkcję nieprzetworzonego ciągu obrazu, a także wysokość, szerokość, głębokość i dowolną funkcję label
. Ten ostatni jest używany podczas pisania pliku, aby odróżnić obraz kota od obrazu mostu. Użyj 0
dla obrazu kota i 1
dla obrazu mostu:
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 } ...
Zauważ, że wszystkie funkcje są teraz przechowywane w komunikacie tf.train.Example
. Następnie sfunkcjonalizuj powyższy kod i zapisz przykładowe komunikaty do pliku o nazwie 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
Przeczytaj plik TFRecord
Masz teraz plik — images.tfrecords
— i możesz teraz przeglądać zapisane w nim rekordy, aby odczytać to, co napisałeś. Biorąc pod uwagę, że w tym przykładzie odtworzysz tylko obraz, jedyną potrzebną funkcją jest nieprzetworzony ciąg obrazu. Wyodrębnij go za pomocą opisanych powyżej metod pobierania, a mianowicie example.features.feature['image_raw'].bytes_list.value[0]
. Możesz również użyć etykiet, aby określić, który rekord jest kotem, a który mostem:
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)}>
Odzyskaj obrazy z pliku TFRecord:
for image_features in parsed_image_dataset:
image_raw = image_features['image_raw'].numpy()
display.display(display.Image(data=image_raw))