Potoki danych działające z szybkością TPU: tf.data.Dataset i TFRecords
Informacje o tym ćwiczeniu (w Codelabs)
1. Omówienie
Jednostki TPU są bardzo szybkie. Strumień danych treningowych musi na bieżąco odpowiadać szybkości trenowania. W tym module dowiesz się, jak wczytać dane z GCS przy użyciu interfejsu tf.data.Dataset API w celu przesyłania plików danych TPU.
Ten moduł jest częścią 1 projektu „Keras w TPU” serii. Możesz to zrobić w poniższej kolejności lub samodzielnie.
- [THIS LAB] Potoki danych działające z szybkością TPU: tf.data.Dataset i TFRecords
- Twój pierwszy model Keras z nauką przenoszenia
- Splotowe sieci neuronowe wykorzystujące Keras i TPU
- Nowoczesne konwnety, squeezenet, Xception z wykorzystaniem Keras i TPU
Czego się nauczysz
- Używanie interfejsu tf.data.Dataset API do wczytywania danych treningowych
- Używanie formatu TFRecord do efektywnego wczytywania danych treningowych z GCS
Prześlij opinię
Jeśli zauważysz, że w tym laboratorium z kodem coś jest nie tak, daj nam znać. Opinię można przesłać, korzystając z formularza dotyczącego problemów na GitHubie [link do przesyłania opinii].
2. Krótki przewodnik po Google Colaboratory
Ten moduł używa Google Collaboratory i nie wymaga konfiguracji. Colaboratory to internetowa platforma do obsługi notatników do celów edukacyjnych. Oferuje bezpłatne trenowanie dotyczące CPU, GPU i TPU.
Aby zapoznać się z Colaboratory, możesz otworzyć ten przykładowy notatnik i przejrzeć kilka komórek.
Wybierz backend TPU
W menu Colab wybierz Środowisko wykonawcze > Zmień typ środowiska wykonawczego i wybierz TPU. W tym module z kodem wykorzystasz potężną jednostkę TPU (Tensor Processing Unit) wyposażoną w procesor akceleracji sprzętowej. Połączenie ze środowiskiem wykonawczym następuje automatycznie przy pierwszym uruchomieniu. Możesz też skorzystać z opcji „Połącz” w prawym górnym rogu.
Wykonywanie notatnika
Uruchomienie komórki po kolei przez kliknięcie komórki i naciśnięcie klawiszy Shift+ENTER. Możesz też uruchomić cały notatnik, wybierając Środowisko wykonawcze > Uruchom wszystko
Spis treści
Wszystkie notatniki mają spis treści. Możesz go otworzyć, klikając czarną strzałkę po lewej stronie.
Ukryte komórki
W niektórych komórkach będzie widoczny tylko tytuł. Jest to funkcja notatnika specyficzna dla Colab. Można je dwukrotnie kliknąć, aby zobaczyć w nich kod, ale zwykle nie jest to zbyt interesujące. Zwykle są to funkcje wspomagające lub wizualizacyjne. Nadal musisz uruchomić te komórki, aby zdefiniować funkcje znajdujące się w nich.
Uwierzytelnianie
Colab może uzyskać dostęp do Twoich prywatnych zasobników Google Cloud Storage, o ile uwierzytelnisz się na autoryzowanym koncie. Powyższy fragment kodu aktywuje proces uwierzytelniania.
3. [INFO] Czym są jednostki przetwarzania Tensor (TPU)?
W skrócie
Kod do trenowania modelu w TPU w Keras (i korzystania z GPU lub CPU, jeśli jednostka TPU jest niedostępna):
try: # detect TPUs
tpu = tf.distribute.cluster_resolver.TPUClusterResolver.connect()
strategy = tf.distribute.TPUStrategy(tpu)
except ValueError: # detect GPUs
strategy = tf.distribute.MirroredStrategy() # for CPU/GPU or multi-GPU machines
# use TPUStrategy scope to define model
with strategy.scope():
model = tf.keras.Sequential( ... )
model.compile( ... )
# train model normally on a tf.data.Dataset
model.fit(training_dataset, epochs=EPOCHS, steps_per_epoch=...)
Wykorzystamy dziś jednostki TPU do utworzenia i zoptymalizowania klasyfikatora kwiatów z szybkością interaktywną (minuty na bieg trenowania).
Dlaczego TPU?
Nowoczesne procesory graficzne są zorganizowane wokół programowalnych „rdzeni”, czyli bardzo elastycznej architektury, która umożliwia im wykonywanie różnych zadań, takich jak renderowanie 3D, deep learning, symulacje fizyczne itp. Z kolei jednostki TPU łączą klasyczny procesor wektorowy z osobną jednostką mnożenia macierzy i świetnie sprawdzają się w każdym zadaniu, w którym dominują duże wielokrotności, takich jak sieci neuronowe.
Ilustracja: gęsta warstwa sieci neuronowej jako efekt mnożenia macierzy, z grupą 8 obrazów przetwarzanych jednocześnie przez sieć neuronową. Sprawdź, czy mnożenie 1 wiersza z kolumną ma ważoną sumę wszystkich wartości pikseli na obrazie. Warstwy splotowe można również przedstawić jako mnożniki macierzy, chociaż jest to nieco bardziej skomplikowane ( wyjaśnienie znajduje się w sekcji 1).
Sprzęt
MXU i VPU
Rdzenie TPU v2 składa się z mnożnej jednostki macierzy (MXU), która uruchamia mnożniki macierzy, oraz jednostki przetwarzania wektorów (VPU) do wszystkich innych zadań, takich jak aktywacje czy softmax. VPU obsługuje obliczenia float32 i int32. MXU działa natomiast w mieszanym, 16-32-bitowym formacie zmiennoprzecinkowym o mieszanej dokładności.
Mieszana precyzja zmiennoprzecinkowa i bfloat16
MXU oblicza mnożniki macierzy, używając danych wejściowych bfloat16 i danych wyjściowych float32. Zbiorcze gromadzenie danych jest wykonywane z dokładnością do float32.
Trenowanie sieci neuronowych jest zwykle odporne na szum generowany przez zmniejszoną precyzję liczby zmiennoprzecinkowej. W niektórych przypadkach szum pomaga nawet uzyskać zgodność optymalizatora. 16-bitowa precyzja zmiennoprzecinkowa jest tradycyjnie używana do przyspieszania obliczeń, ale formaty float16 i float32 mają bardzo różne zakresy. Zmniejszenie precyzji z float32 do float16 zwykle powoduje nadmierne i niedostateczne przepływy. Rozwiązania istnieją, ale do poprawnego działania typu float16 zazwyczaj trzeba się przyłożyć.
W związku z tym firma Google wprowadziła w przypadku jednostek TPU format bfloat16. Argument bfloat16 to skrócona liczba zmiennoprzecinkowa float32 z dokładnie takimi samymi liczbami bitów wykładnika i zakresem jak float32 W związku z tym, że jednostki TPU mnożą macierz obliczeniową z mieszaną precyzją z danymi wejściowymi bfloat16, ale z danymi wyjściowymi float32, oznacza to, że zwykle nie trzeba wprowadzać żadnych zmian w kodzie, aby skorzystać ze zmniejszonej dokładności, aby uzyskać wzrost wydajności.
Tablica skurczowa
MXU implementuje mnożniki macierzy w sprzęcie za pomocą tak zwanej „tablicy skurczowej” Architektura, w której elementy danych przepływają przez tablicę sprzętowych jednostek obliczeniowych. (W medycynie termin „skurczowy” odnosi się do skurczów serca i przepływu krwi, a tutaj mówimy o przepływie danych.
Podstawowym elementem mnożenia macierzy jest iloczyn skalarny między linią z jednej macierzy a kolumną z drugiej macierzy (zobacz ilustrację u góry tej sekcji). W przypadku mnożenia macierzy Y=X*W jednym z elementów wyniku będzie:
Y[2,0] = X[2,0]*W[0,0] + X[2,1]*W[1,0] + X[2,2]*W[2,0] + ... + X[2,n]*W[n,0]
W przypadku GPU można zaprogramować iloczyn skalarny na „rdzeń” GPU a następnie uruchamiaj go na wszystkich „rdzeniach” które są dostępne równolegle, aby spróbować
wyliczyć wszystkie wartości wynikowej macierzy jednocześnie. Jeśli wynikowa macierz ma dużą wielkość 128 x 128, to wymagałoby to 128 x 128=16 tys. „rdzeni” co zwykle nie jest możliwe. Największe procesory graficzne mają około 4000 rdzeni. Z kolei TPU używa absolutnego minimum potrzebnego do obsługi jednostek obliczeniowych w MXU: mnożniki (bfloat16 x bfloat16 => float32
) i nic więcej. Są one tak małe, że TPU może umieścić ich 16 KB w rozmiarze 128 x 128 MXU i przetworzyć to mnożenie macierzy za jednym razem.
Ilustracja: tablica skurczowa MXU. Elementy obliczeniowe to zasobniki pomnożone. Wartości jednej macierzy są wczytywane do tablicy (czerwone kropki). Wartości innej macierzy przepływają przez tablicę (szare kropki). Linie pionowe propagują wartości w górę. Linie poziome przekazują częściowe sumy. W ramach ćwiczenia dla użytkownika należy sprawdzić, czy w miarę przepływu danych przez tablicę pojawia się wynik mnożenia macierzy po prawej stronie.
Poza tym, chociaż iloczyn skalarny są obliczane na MXU, sumy pośrednie przepływają po prostu między sąsiednimi jednostkami obliczeniowymi. Nie trzeba ich przechowywać ani pobierać do/z pamięci czy nawet do pliku rejestru. W efekcie architektura układów skurczowych TPU charakteryzuje się znaczną gęstością i mocą, a przy mnożeniu macierzy ma istotny wzrost szybkości w porównaniu z GPU.
Cloud TPU
Gdy poprosisz o „ Cloud TPU v2” w Google Cloud Platform otrzymujesz maszynę wirtualną z płytką TPU dołączoną do PCI. Płyta TPU jest wyposażona w 4 dwurdzeniowe układy TPU. Każdy rdzeń TPU obejmuje jednostkę VPU (Vector Processing Unit) i jednostkę mnożenia matriX o wymiarach 128 x 128 MXU. Ta „Cloud TPU” jest zwykle połączony przez sieć z maszyną wirtualną, która go zażądała. Pełny obraz wygląda więc tak:
Ilustracja: maszyna wirtualna z podłączonym siecią „Cloud TPU” akceleratora. „Cloud TPU” jest wykonany z maszyny wirtualnej z płytką TPU dołączoną do PCI i 4 dwurdzeniowymi układami TPU.
Pody TPU
W centrach danych Google jednostki TPU są połączone z połączeniami międzysieciowymi o wysokiej wydajności (HPC), co może sprawić, że będą one postrzegane jako jeden bardzo duży akcelerator. Google nazywa je podami i mogą obejmować do 512 rdzeni TPU v2 lub 2048 rdzeni TPU v3.
Ilustracja: pod TPU v3. Płyty TPU i szafy rackowe połączone za pomocą połączenia międzysieciowego HPC.
Podczas trenowania gradienty są wymieniane między rdzeniami TPU przy użyciu algorytmu all-reduce ( dobre wyjaśnienie funkcji all-reduce znajdziesz tutaj). Wytrenowany model może wykorzystać możliwości sprzętowe, trenując na dużych wsadach.
Ilustracja: synchronizacja gradientów podczas trenowania z wykorzystaniem algorytmu all-reduce w Google TPU w sieci toroidalnej siatki HPC 2-D.
Oprogramowanie
Trenowanie na dużym wsadzie
Idealny rozmiar wsadu dla jednostek TPU to 128 elementów danych na rdzeń TPU, ale sprzęt może już wykazywać dobre wykorzystanie z 8 elementów danych na rdzeń TPU. Pamiętaj, że jedna z Cloud TPU ma 8 rdzeni.
W tym module kodu użyjemy interfejsu Keras API. W Keras określona wsad jest reprezentowana przez globalny rozmiar wsadu dla całej jednostki TPU. Wsady zostaną automatycznie podzielone na 8 i będą uruchamiane w 8 rdzeniach TPU.
Dodatkowe wskazówki dotyczące wydajności znajdziesz w przewodniku po wydajności TPU. W przypadku niektórych modeli należy zachować szczególną ostrożność w przypadku bardzo dużych wsadów. Więcej informacji znajdziesz w artykule LARSOptimizer.
Zaawansowane: XLA
Programy Tensorflow definiują grafy obliczeniowe. TPU nie uruchamia bezpośrednio kodu Pythona, tylko uruchamia wykres obliczeniowy zdefiniowany przez program Tensorflow. Działa w nim kompilator o nazwie XLA (przyspieszony kompilator linearnych algebra), który przekształca graf Tensorflow węzłów obliczeniowych w kod maszyny TPU. Ten kompilator przeprowadza też wiele zaawansowanych optymalizacji kodu i układu pamięci. Kompilacja odbywa się automatycznie, gdy dane są przesyłane do TPU. Nie musisz dodawać XLA do łańcucha tworzenia.
Ilustracja: aby działał w TPU, graf obliczeniowy zdefiniowany w programie Tensorflow jest najpierw przekształcany w reprezentację formatu XLA (przyspieszonego kompilatora algebry liniowej), a następnie skompilowany przez XLA do kodu maszynowego TPU.
Używanie TPU w Keras
Jednostki TPU są obsługiwane przez interfejs Keras API od Tensorflow 2.1. Obsługa Keras działa na TPU i podach TPU. Ten przykład działa z użyciem TPU, GPU i CPU:
try: # detect TPUs
tpu = tf.distribute.cluster_resolver.TPUClusterResolver.connect()
strategy = tf.distribute.TPUStrategy(tpu)
except ValueError: # detect GPUs
strategy = tf.distribute.MirroredStrategy() # for CPU/GPU or multi-GPU machines
# use TPUStrategy scope to define model
with strategy.scope():
model = tf.keras.Sequential( ... )
model.compile( ... )
# train model normally on a tf.data.Dataset
model.fit(training_dataset, epochs=EPOCHS, steps_per_epoch=...)
W tym fragmencie kodu:
TPUClusterResolver().connect()
znajduje jednostkę TPU w sieci. Działa bez parametrów w większości systemów Google Cloud (zadania AI Platform, Colaboratory, Kubeflow, maszyny wirtualne do deep learningu utworzone za pomocą narzędzia „ctpu up”). Dzięki zmiennej środowiskowej TPU_NAME te systemy wiedzą, gdzie znajduje się ich TPU. Jeśli tworzysz TPU ręcznie, ustaw środ. TPU_NAME. zmien. na maszynie wirtualnej, z której go używasz, lub wywołaj funkcjęTPUClusterResolver
z jawnymi parametrami:TPUClusterResolver(tp_uname, zone, project)
TPUStrategy
to część, która implementuje dystrybucję oraz metodę „all-reduce” algorytm synchronizacji gradientu.- Strategia jest stosowana za pomocą zakresu. Model musi być zdefiniowany w zakresie strategii (zakres).
- Funkcja
tpu_model.fit
oczekuje obiektu tf.data.Dataset na potrzeby danych wejściowych na potrzeby trenowania TPU.
Typowe zadania przenoszenia TPU
- Istnieje wiele sposobów wczytywania danych w modelu Tensorflow, ale w przypadku jednostek TPU wymagany jest interfejs API
tf.data.Dataset
. - TPU są bardzo szybkie, a przetwarzanie danych często staje się wąskim gardłem działające na nich. W przewodniku po wydajności TPU znajdziesz narzędzia, które pomogą Ci wykrywać wąskie gardła danych i korzystać z innych wskazówek dotyczących wydajności.
- Liczby int8 i int16 są traktowane jako int32. TPU nie ma sprzętu z liczbami całkowitymi działającymi na mniej niż 32 bitach.
- Niektóre operacje Tensorflow nie są obsługiwane. Listę znajdziesz tutaj. Dobra wiadomość jest taka, że to ograniczenie dotyczy tylko kodu trenowania, tj. przekazywania przez model do przodu i do tyłu. Nadal możesz używać wszystkich operacji Tensorflow w potoku danych wejściowych, ponieważ będą one wykonywane na CPU.
- Model
tf.py_func
nie jest obsługiwany przez TPU.
4. Wczytuję dane
Pracujemy ze zbiorem zdjęć kwiatów. Chcemy nauczyć się je kategoryzować na 5 rodzajów kwiatów. Dane są wczytywane za pomocą interfejsu API tf.data.Dataset
. Najpierw poznajmy interfejs API.
Nauka praktyczna
Otwórz ten notatnik, uruchom komórki (Shift + ENTER) i postępuj zgodnie z instrukcjami w miejscu, w którym pojawia się komunikat „WYMAGANE PRACY”. .
Fun with tf.data.Dataset (playground).ipynb
Informacje dodatkowe
Informacje o „kwiatach” zbiór danych
Zbiór danych jest podzielony na 5 folderów. Każdy folder zawiera kwiaty jednego rodzaju. Foldery te mają nazwy: słoneczniki, stokrotka, mniszek, tulipany i róże. Dane są przechowywane w publicznym zasobniku w Google Cloud Storage. Fragment:
gs://flowers-public/sunflowers/5139971615_434ff8ed8b_n.jpg
gs://flowers-public/daisy/8094774544_35465c1c64.jpg
gs://flowers-public/sunflowers/9309473873_9d62b9082e.jpg
gs://flowers-public/dandelion/19551343954_83bb52f310_m.jpg
gs://flowers-public/dandelion/14199664556_188b37e51e.jpg
gs://flowers-public/tulips/4290566894_c7f061583d_m.jpg
gs://flowers-public/roses/3065719996_c16ecd5551.jpg
gs://flowers-public/dandelion/8168031302_6e36f39d87.jpg
gs://flowers-public/sunflowers/9564240106_0577e919da_n.jpg
gs://flowers-public/daisy/14167543177_cd36b54ac6_n.jpg
Dlaczego tf.data.Dataset?
Keras i Tensorflow akceptują zbiory danych we wszystkich funkcjach trenowania i oceny. Gdy wczytasz dane do zbioru danych, interfejs API udostępnia wszystkie typowe funkcje przydatne w przypadku danych do trenowania sieci neuronowych:
dataset = ... # load something (see below)
dataset = dataset.shuffle(1000) # shuffle the dataset with a buffer of 1000
dataset = dataset.cache() # cache the dataset in RAM or on disk
dataset = dataset.repeat() # repeat the dataset indefinitely
dataset = dataset.batch(128) # batch data elements together in batches of 128
AUTOTUNE = tf.data.AUTOTUNE
dataset = dataset.prefetch(AUTOTUNE) # prefetch next batch(es) while training
Wskazówki dotyczące skuteczności i sprawdzone metody dotyczące zbiorów danych znajdziesz w tym artykule. Dokumentacja referencyjna znajduje się tutaj.
Podstawowe informacje o zbiorze danych tf.data.Dataset
Dane zwykle są zapisane w wielu plikach, tutaj są obrazy. Zbiór danych z nazwami plików możesz utworzyć, wywołując:
filenames_dataset = tf.data.Dataset.list_files('gs://flowers-public/*/*.jpg')
# The parameter is a "glob" pattern that supports the * and ? wildcards.
Kliknij „Mapuj”, funkcję do każdej nazwy pliku, która zwykle wczytuje i dekoduje plik w pamięci rzeczywiste dane:
def decode_jpeg(filename):
bits = tf.io.read_file(filename)
image = tf.io.decode_jpeg(bits)
return image
image_dataset = filenames_dataset.map(decode_jpeg)
# this is now a dataset of decoded images (uint8 RGB format)
Powtarzanie zbioru danych:
for data in my_dataset:
print(data)
Zbiory danych krotek
W uczeniu nadzorowanym zbiór danych treningowych składa się zwykle z par danych treningowych i prawidłowych odpowiedzi. Aby to umożliwić, funkcja dekodowania może zwracać krotki. Po wykonaniu iteracji otrzymasz zbiór danych z krotkami i krotkami, który zostanie zwrócony. Zwracane wartości to tensory Tensorflow gotowe do wykorzystania przez model. Możesz wywołać dla nich metodę .numpy()
, aby wyświetlić nieprzetworzone wartości:
def decode_jpeg_and_label(filename):
bits = tf.read_file(filename)
image = tf.io.decode_jpeg(bits)
label = ... # extract flower name from folder name
return image, label
image_dataset = filenames_dataset.map(decode_jpeg_and_label)
# this is now a dataset of (image, label) pairs
for image, label in dataset:
print(image.numpy().shape, label.numpy())
Wniosek:ładowanie pojedynczych obrazów jest powolne.
Podczas iteracji tego zbioru możesz zauważyć, że ładuje się np. 1–2 obrazy na sekundę. To jest zbyt wolne! Akceleratory sprzętowe, których będziemy używać do trenowania, w wielu przypadkach wytrzymają ten wskaźnik. W następnej sekcji dowiesz się, jak to zrobić.
Rozwiązanie
Oto notatnik rozwiązań. Możesz go użyć, jeśli napotkasz problemy.
Fun with tf.data.Dataset (solution).ipynb
Omówione zagadnienia
- 🤔 tf.data.Dataset.list_files
- 🤔 tf.data.Dataset.map
- 🤔 Zbiory danych z krotkami
- 😀 powtarzanie za pomocą zbiorów danych
Poświęć chwilę na przejrzenie tej listy kontrolnej.
5. Szybkie ładowanie danych
Akceleratory sprzętowe Tensor Processing Unit (TPU), których użyjemy w tym module, działają bardzo szybko. Często wyzwaniem jest jednak na tyle szybko, by dostarczyć im dane, by utrzymać ich zainteresowanie. Google Cloud Storage (GCS) jest w stanie utrzymać bardzo dużą przepustowość, ale tak jak w przypadku wszystkich systemów pamięci masowej w chmurze, inicjowanie połączenia z siecią wiąże się z pewnymi kosztami. Dlatego przechowywanie danych w postaci tysięcy pojedynczych plików nie jest idealnym rozwiązaniem. Podzielimy je na mniejszą liczbę plików i wykorzystamy możliwości zbioru tf.data.Dataset do równoległego odczytu z wielu plików.
Odczyt
Kod, który wczytuje pliki graficzne, zmienia ich rozmiar do wspólnego rozmiaru, a następnie zapisuje je w 16 plikach TFRecord, znajduje się w poniższym notatniku. Prosimy o szybkie zapoznanie się z nim. Jego wykonywanie nie jest konieczne, ponieważ w pozostałej części ćwiczenia z programowania otrzymasz dane w prawidłowym formacie TFRecord.
Flower pictures to TFRecords.ipynb
Idealny układ danych zapewniający optymalną przepustowość GCS
Format pliku TFRecord
Preferowanym przez Tensorflow formatem plików do przechowywania danych jest format TFRecord oparty na protobuf. Inne formaty serializacji też zadziałają, ale możesz załadować zbiór danych z plików TFRecord bezpośrednio, wpisując:
filenames = tf.io.gfile.glob(FILENAME_PATTERN)
dataset = tf.data.TFRecordDataset(filenames)
dataset = dataset.map(...) # do the TFRecord decoding here - see below
W celu uzyskania optymalnej wydajności zalecamy używanie poniższego bardziej złożonego kodu do odczytu z wielu plików TFRecord jednocześnie. Ten kod będzie odczytywać równolegle z N plików i zignorować kolejność danych na rzecz szybkości czytania.
AUTOTUNE = tf.data.AUTOTUNE
ignore_order = tf.data.Options()
ignore_order.experimental_deterministic = False
filenames = tf.io.gfile.glob(FILENAME_PATTERN)
dataset = tf.data.TFRecordDataset(filenames, num_parallel_reads=AUTOTUNE)
dataset = dataset.with_options(ignore_order)
dataset = dataset.map(...) # do the TFRecord decoding here - see below
Ściągawka TFRecord
W plikach TFRecord można przechowywać 3 typy danych: ciągi bajtów (lista bajtów), 64-bitowe liczby całkowite i 32-bitowe liczby zmiennoprzecinkowe. Są one zawsze przechowywane jako listy, a pojedynczy element danych będzie listą o rozmiarze 1. Aby zapisać dane w pliku TFRecord, możesz użyć poniższych funkcji pomocniczych.
zapis ciągów bajtów
# warning, the input is a list of byte strings, which are themselves lists of bytes
def _bytestring_feature(list_of_bytestrings):
return tf.train.Feature(bytes_list=tf.train.BytesList(value=list_of_bytestrings))
zapisywanie liczb całkowitych
def _int_feature(list_of_ints): # int64
return tf.train.Feature(int64_list=tf.train.Int64List(value=list_of_ints))
pisanie liczba zmiennoprzecinkowa
def _float_feature(list_of_floats): # float32
return tf.train.Feature(float_list=tf.train.FloatList(value=list_of_floats))
napisanie TFRecord, korzystając z powyższych wskazówek
# input data in my_img_bytes, my_class, my_height, my_width, my_floats
with tf.python_io.TFRecordWriter(filename) as out_file:
feature = {
"image": _bytestring_feature([my_img_bytes]), # one image in the list
"class": _int_feature([my_class]), # one class in the list
"size": _int_feature([my_height, my_width]), # fixed length (2) list of ints
"float_data": _float_feature(my_floats) # variable length list of floats
}
tf_record = tf.train.Example(features=tf.train.Features(feature=feature))
out_file.write(tf_record.SerializeToString())
Aby odczytywać dane z rekordów TFRecord, musisz najpierw zadeklarować układ przechowywanych rekordów. W deklaracji możesz uzyskać dostęp do dowolnego nazwanego pola w postaci listy o stałej długości lub listy o zmiennej długości:
odczytywanie z plików TFRecord
def read_tfrecord(data):
features = {
# tf.string = byte string (not text string)
"image": tf.io.FixedLenFeature([], tf.string), # shape [] means scalar, here, a single byte string
"class": tf.io.FixedLenFeature([], tf.int64), # shape [] means scalar, i.e. a single item
"size": tf.io.FixedLenFeature([2], tf.int64), # two integers
"float_data": tf.io.VarLenFeature(tf.float32) # a variable number of floats
}
# decode the TFRecord
tf_record = tf.io.parse_single_example(data, features)
# FixedLenFeature fields are now ready to use
sz = tf_record['size']
# Typical code for decoding compressed images
image = tf.io.decode_jpeg(tf_record['image'], channels=3)
# VarLenFeature fields require additional sparse.to_dense decoding
float_data = tf.sparse.to_dense(tf_record['float_data'])
return image, sz, float_data
# decoding a tf.data.TFRecordDataset
dataset = dataset.map(read_tfrecord)
# now a dataset of triplets (image, sz, float_data)
Przydatne fragmenty kodu:
odczytywanie pojedynczych elementów danych
tf.io.FixedLenFeature([], tf.string) # for one byte string
tf.io.FixedLenFeature([], tf.int64) # for one int
tf.io.FixedLenFeature([], tf.float32) # for one float
czytanie list elementów o stałym rozmiarze
tf.io.FixedLenFeature([N], tf.string) # list of N byte strings
tf.io.FixedLenFeature([N], tf.int64) # list of N ints
tf.io.FixedLenFeature([N], tf.float32) # list of N floats
odczytywanie zmiennej liczby elementów danych
tf.io.VarLenFeature(tf.string) # list of byte strings
tf.io.VarLenFeature(tf.int64) # list of ints
tf.io.VarLenFeature(tf.float32) # list of floats
Funkcja VarLenFeature zwraca wektor rozproszony i po zdekodowaniu pliku TFRecord jest wymagany dodatkowy krok:
dense_data = tf.sparse.to_dense(tf_record['my_var_len_feature'])
W plikach TFRecord można też mieć opcjonalne pola. Jeśli podczas odczytu pola określisz wartość domyślną, a pole nie zostanie puste, to zamiast błędu będzie zwracana wartość domyślna.
tf.io.FixedLenFeature([], tf.int64, default_value=0) # this field is optional
Omówione zagadnienia
- 🤔 fragmentacja plików danych z myślą o szybkim dostępie z GCS
- 😓 jak zapisywać pliki TFRecord. (Nie pamiętasz już składni? Nie szkodzi. Dodaj tę stronę do zakładek jako ściągawkę).
- 🤔 wczytuję zbiór danych z plików TFRecord przy użyciu TFRecordDataset
Poświęć chwilę na przejrzenie tej listy kontrolnej.
6. Gratulacje!
Możesz teraz przesyłać dane do TPU. Przejdź do następnego modułu
- [THIS LAB] Potoki danych działające z szybkością TPU: tf.data.Dataset i TFRecords
- Twój pierwszy model Keras z nauką przenoszenia
- Splotowe sieci neuronowe wykorzystujące Keras i TPU
- Nowoczesne konwnety, squeezenet, Xception z wykorzystaniem Keras i TPU
TPU w praktyce
Układy TPU i GPU są dostępne w Cloud AI Platform:
- na maszynach wirtualnych deep learning.
- W Notatkach w AI Platform
- w zadaniach AI Platform Training,
Bardzo zależy nam na opiniach użytkowników. Daj nam znać, jeśli zauważysz, że w tym module coś jest nie tak lub jeśli uważasz, że coś jest nie tak. Opinię można przesłać, korzystając z formularza dotyczącego problemów na GitHubie [link do przesyłania opinii].
|