Nowoczesne konwnety, squeezenet, Xception przy użyciu Keras i TPU

1. Przegląd

W tym module poznasz nowoczesną architekturę konwolucyjną i wykorzystasz tę wiedzę do wdrożenia prostej, ale skutecznej sieci konwolucyjnej o nazwie „squeezenet”.

Ten moduł zawiera niezbędne wyjaśnienia teoretyczne dotyczące konwolucyjnych sieci neuronowych i jest dobrym punktem wyjścia dla programistów, którzy chcą dowiedzieć się więcej o deep learning.

Ten moduł jest czwartą częścią serii „Keras on TPU”. Możesz wykonać je w podanej kolejności lub niezależnie od siebie.

ca8cc21f6838eccc.png

Czego się nauczysz

  • Aby opanować styl funkcjonalny Keras
  • Aby utworzyć model przy użyciu architektury squeezenet
  • korzystać z TPU, aby szybko trenować modele i iteracyjnie ulepszać architekturę;
  • Implementowanie rozszerzania danych za pomocą tf.data.dataset
  • Dostrajanie wstępnie wytrenowanego dużego modelu (Xception) na TPU

Prześlij opinię

Jeśli zauważysz w tym module coś nieprawidłowego, poinformuj nas o tym. Opinie można przesyłać za pomocą zgłoszeń w GitHub [link do opinii].

2. Krótkie wprowadzenie do Google Colaboratory

W tym module używamy Google Collaboratory, więc nie musisz niczego konfigurować. Colaboratory to platforma online z notatnikami przeznaczona do celów edukacyjnych. Oferuje bezpłatne szkolenia dotyczące procesorów, procesorów graficznych i TPU.

688858c21e3beff2.png

Możesz otworzyć ten przykładowy notatnik i uruchomić kilka komórek, aby zapoznać się z Colaboratory.

c3df49e90e5a654f.png Welcome to Colab.ipynb

Wybieranie backendu TPU

8832c6208c99687d.png

W menu Colab kliknij Środowisko wykonawcze > Zmień typ środowiska wykonawczego, a następnie wybierz TPU. W tym module nauczysz się korzystać z wydajnej jednostki TPU (Tensor Processing Unit) do trenowania z akceleracją sprzętową. Połączenie z czasem działania nastąpi automatycznie przy pierwszym wykonaniu kodu. Możesz też użyć przycisku „Połącz” w prawym górnym rogu.

Wykonywanie notatnika

76d05caa8b4db6da.png

Uruchamiaj komórki pojedynczo, klikając je i naciskając Shift + Enter. Możesz też uruchomić cały notatnik, klikając Środowisko wykonawcze > Uruchom wszystko.

Spis treści

429f106990037ec4.png

Wszystkie notatniki mają spis treści. Możesz go otworzyć, klikając czarną strzałkę po lewej stronie.

Ukryte komórki

edc3dba45d26f12a.png

Niektóre komórki będą wyświetlać tylko swój tytuł. Jest to funkcja notatnika Colab. Możesz kliknąć je dwukrotnie, aby zobaczyć kod w środku, ale zwykle nie jest on zbyt interesujący. Zwykle są to funkcje pomocnicze lub wizualizacyjne. Aby zdefiniować funkcje w komórkach, musisz je uruchomić.

Uwierzytelnianie

cdd4b41413100543.png

Colab może uzyskać dostęp do Twoich prywatnych zasobników Google Cloud Storage, jeśli uwierzytelnienie nastąpi przy użyciu autoryzowanego konta. Powyższy fragment kodu uruchomi proces uwierzytelniania.

3. [INFO] Czym są jednostki Tensor Processing Unit (TPU)?

W skrócie

f88cf6facfc70166.png

Kod do trenowania modelu na TPU w Keras (z możliwością powrotu do GPU lub CPU, jeśli TPU nie jest dostępny):

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=...)

Dziś użyjemy TPU do zbudowania i zoptymalizowania klasyfikatora kwiatów w interaktywnym tempie (minuty na przebieg trenowania).

688858c21e3beff2.png

Dlaczego jednostki TPU?

Nowoczesne procesory graficzne są zorganizowane wokół programowalnych „rdzeni”, co stanowi bardzo elastyczną architekturę, która umożliwia im wykonywanie różnych zadań, takich jak renderowanie 3D, uczenie głębokie, symulacje fizyczne itp. TPU z kolei łączą klasyczny procesor wektorowy z dedykowaną jednostką mnożenia macierzy i doskonale sprawdzają się w każdym zadaniu, w którym dominują duże mnożenia macierzy, np. w sieciach neuronowych.

8eb3e718b8e2ed08.png

Ilustracja: gęsta warstwa sieci neuronowej jako mnożenie macierzy, w którym partia 8 obrazów jest przetwarzana przez sieć neuronową jednocześnie. Wykonaj mnożenie wiersza przez kolumnę, aby sprawdzić, czy rzeczywiście oblicza ważoną sumę wartości wszystkich pikseli obrazu. Warstwy konwolucyjne też można przedstawić jako mnożenie macierzy, choć jest to nieco bardziej skomplikowane ( wyjaśnienie znajdziesz tutaj, w sekcji 1).

Sprzęt

MXU i VPU

Rdzeń TPU v2 składa się z jednostki mnożnika macierzy (MXU), która wykonuje mnożenie macierzy, oraz jednostki przetwarzania wektorowego (VPU), która wykonuje wszystkie inne zadania, takie jak aktywacje, softmax itp. Jednostka VPU obsługuje obliczenia zmiennoprzecinkowe 32-bitowe i całkowite 32-bitowe. MXU działa natomiast w formacie zmiennoprzecinkowym o mieszanej precyzji 16–32 bitów.

7d68944718f76b18.png

Zmiennoprzecinkowe liczby mieszanej precyzji i bfloat16

MXU oblicza mnożenie macierzy przy użyciu danych wejściowych bfloat16 i danych wyjściowych float32. Pośrednie akumulacje są wykonywane z precyzją float32.

19c5fc432840c714.png

Trenowanie sieci neuronowych jest zwykle odporne na szum wprowadzany przez zmniejszoną precyzję zmiennoprzecinkową. W niektórych przypadkach szum pomaga nawet optymalizatorowi osiągnąć zbieżność. 16-bitowa precyzja zmiennoprzecinkowa była tradycyjnie używana do przyspieszania obliczeń, ale formaty float16 i float32 mają bardzo różne zakresy. Zmniejszenie precyzji z float32 do float16 zwykle powoduje przekroczenie zakresu w górę i w dół. Istnieją rozwiązania, ale zwykle wymagają dodatkowej pracy, aby float16 działał prawidłowo.

Dlatego w TPU wprowadziliśmy format bfloat16. Jest to skrócony format float32, który ma dokładnie te same bity wykładnika i zakres co float32. W połączeniu z faktem, że TPU wykonują mnożenie macierzy w mieszanej precyzji z danymi wejściowymi bfloat16, ale danymi wyjściowymi float32, oznacza to, że zwykle nie są potrzebne żadne zmiany w kodzie, aby skorzystać ze wzrostu wydajności wynikającego z mniejszej precyzji.

Macierz systoliczna

MXU wykonuje mnożenie macierzy w sprzęcie za pomocą tzw. architektury „tablicy systolicznej”, w której elementy danych przepływają przez tablicę jednostek obliczeniowych. (W medycynie termin „skurczowy” odnosi się do skurczów serca i przepływu krwi, a w tym przypadku do przepływu danych).

Podstawowym elementem mnożenia macierzy jest iloczyn skalarny wiersza jednej macierzy i kolumny drugiej macierzy (ilustracja u góry tej sekcji). W przypadku mnożenia macierzy Y=X*W jeden element wyniku to:

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]

Na procesorze graficznym programuje się ten iloczyn skalarny w „rdzeniu” procesora graficznego, a następnie wykonuje się go równolegle na tylu „rdzeniach”, ile jest dostępnych, aby spróbować obliczyć wszystkie wartości wynikowej macierzy naraz. Jeśli wynikowa macierz ma rozmiar 128 x 128, wymagałoby to 128 x 128=16 tys. „rdzeni”, co zwykle nie jest możliwe. Największe procesory graficzne mają około 4000 rdzeni. TPU z kolei wykorzystuje w jednostkach obliczeniowych MXU absolutne minimum sprzętu: tylko bfloat16 x bfloat16 => float32 mnożarki-akumulatory. Są one tak małe, że jednostka TPU może zaimplementować 16 tys. takich jednostek w macierzy MXU o wymiarach 128 x 128 i przetworzyć to mnożenie macierzy za jednym razem.

f1b283fc45966717.gif

Ilustracja: tablica skurczowa MXU. Elementami obliczeniowymi są mnożniki-akumulatory. Wartości jednej macierzy są wczytywane do tablicy (czerwone kropki). Wartości z drugiej macierzy przepływają przez tablicę (szare kropki). Linie pionowe przenoszą wartości w górę. Linie poziome propagują sumy częściowe. Sprawdzenie, czy w miarę przepływu danych przez tablicę po prawej stronie pojawia się wynik mnożenia macierzy, pozostawiamy użytkownikowi.

Dodatkowo podczas obliczania iloczynów skalarnych w MXU sumy pośrednie przepływają między sąsiednimi jednostkami obliczeniowymi. Nie trzeba ich przechowywać ani pobierać z pamięci ani nawet z pliku rejestru. W rezultacie architektura tablicy systolicznej TPU ma znaczną przewagę pod względem gęstości i mocy, a także niepomijalną przewagę pod względem szybkości nad GPU podczas obliczania mnożenia macierzy.

Cloud TPU

Gdy poprosisz o 1 „Cloud TPU v2” na Google Cloud Platform, otrzymasz maszynę wirtualną z płytą TPU podłączoną przez PCI. Płyta TPU ma 4 dwurdzeniowe układy TPU. Każdy rdzeń TPU ma jednostkę VPU (Vector Processing Unit) i jednostkę MXU (MatriX multiply Unit) o wymiarach 128 x 128. Ta „Cloud TPU” jest zwykle połączona przez sieć z maszyną wirtualną, która ją zażądała. Pełny obraz wygląda więc tak:

dfce5522ed644ece.png

Ilustracja: maszyna wirtualna z akceleratorem „Cloud TPU” podłączonym do sieci. „Cloud TPU” to maszyna wirtualna z płytą TPU podłączoną przez PCI, na której znajdują się 4 dwurdzeniowe układy TPU.

Pody TPU

W centrach danych Google układy TPU są połączone z interfejsem komputera o dużej mocy obliczeniowej (HPC), dzięki czemu mogą działać jako jeden bardzo duży akcelerator. Google nazywa je podami. Mogą one obejmować do 512 rdzeni TPU v2 lub 2048 rdzeni TPU v3.

2ec1e0d341e7fc34.jpeg

Ilustracja: pod TPU v3. Płyty i szafy TPU połączone za pomocą połączenia międzysieciowego HPC.

Podczas trenowania gradienty są wymieniane między rdzeniami TPU za pomocą algorytmu all-reduce ( dobre wyjaśnienie algorytmu all-reduce znajdziesz tutaj). Trenowany model może wykorzystywać sprzęt, trenując na dużych rozmiarach wsadu.

d97b9cc5d40fdb1d.gif

Ilustracja: synchronizacja gradientów podczas trenowania z użyciem algorytmu all-reduce w dwuwymiarowej sieci HPC o topologii toroidu na jednostkach TPU Google.

Oprogramowanie

Trenowanie z dużą wielkością wsadu

Idealna wielkość wsadu w przypadku TPU to 128 elementów danych na rdzeń TPU, ale sprzęt może już wykazywać dobre wykorzystanie od 8 elementów danych na rdzeń TPU. Pamiętaj, że jedna Cloud TPU ma 8 rdzeni.

W tym module użyjemy interfejsu Keras API. W Keras określona przez Ciebie wielkość wsadu jest globalną wielkością wsadu dla całego TPU. Partie zostaną automatycznie podzielone na 8 części i uruchomione na 8 rdzeniach TPU.

da534407825f01e3.png

Dodatkowe wskazówki dotyczące wydajności znajdziesz w przewodniku po wydajności TPU. W przypadku bardzo dużych rozmiarów partii w niektórych modelach może być wymagana szczególna ostrożność. Więcej informacji znajdziesz w artykule LARSOptimizer.

Dla zaawansowanych: XLA

Programy TensorFlow definiują wykresy obliczeniowe. TPU nie uruchamia bezpośrednio kodu Pythona, ale wykonuje wykres obliczeniowy zdefiniowany przez program TensorFlow. W tle kompilator XLA (kompilator przyspieszonej algebry liniowej) przekształca wykres obliczeniowy TensorFlow w kod maszynowy TPU. Ten kompilator wykonuje też wiele zaawansowanych optymalizacji kodu i układu pamięci. Kompilacja odbywa się automatycznie w miarę przesyłania zadań do TPU. Nie musisz wyraźnie uwzględniać XLA w łańcuchu kompilacji.

edce61112cd57972.png

Ilustracja: aby uruchomić program na TPU, graf obliczeniowy zdefiniowany przez program TensorFlow jest najpierw tłumaczony na reprezentację XLA (kompilator przyspieszonej algebry liniowej), a następnie kompilowany przez XLA do kodu maszynowego TPU.

Korzystanie z TPU w Keras

TPU są obsługiwane przez interfejs Keras API od wersji TensorFlow 2.1. Obsługa Keras działa na TPU i podach TPU. Oto przykład, który działa na 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 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”). Te systemy wiedzą, gdzie znajduje się ich TPU, dzięki zmiennej środowiskowej TPU_NAME. Jeśli utworzysz TPU ręcznie, ustaw zmienną środowiskową TPU_NAME na maszynie wirtualnej, z której korzystasz, lub wywołaj polecenie TPUClusterResolver z jawnymi parametrami: TPUClusterResolver(tp_uname, zone, project)
  • TPUStrategy to część, która implementuje algorytm dystrybucji i synchronizacji gradientów „all-reduce”.
  • Strategia jest stosowana w ramach zakresu. Model musi być zdefiniowany w zakresie funkcji strategy().
  • Funkcja tpu_model.fit oczekuje obiektu tf.data.Dataset jako danych wejściowych do trenowania na TPU.

Typowe zadania związane z przenoszeniem kodu na TPU

  • Dane do modelu TensorFlow można wczytywać na wiele sposobów, ale w przypadku TPU wymagane jest użycie interfejsu tf.data.Dataset.
  • Procesory TPU są bardzo szybkie, więc podczas ich używania wąskim gardłem często staje się wczytywanie danych. W przewodniku po wydajności TPU znajdziesz narzędzia, które pomogą Ci wykryć wąskie gardła danych, oraz inne wskazówki dotyczące wydajności.
  • Liczby int8 lub int16 są traktowane jako int32. TPU nie ma sprzętu do liczb całkowitych działającego na mniej niż 32 bitach.
  • Niektóre operacje TensorFlow nie są obsługiwane. Lista jest dostępna tutaj. Dobra wiadomość jest taka, że to ograniczenie dotyczy tylko kodu trenującego, czyli przejścia w przód i w tył przez model. W potoku wprowadzania danych nadal możesz używać wszystkich operacji TensorFlow, ponieważ będą one wykonywane na procesorze.
  • tf.py_func nie jest obsługiwany na TPU.

4. [INFO] Klasyfikator sieci neuronowej – podstawy

W skrócie

Jeśli znasz już wszystkie pogrubione terminy w następnym akapicie, możesz przejść do kolejnego ćwiczenia. Jeśli dopiero zaczynasz przygodę z uczeniem głębokim, witamy. Czytaj dalej.

W przypadku modeli zbudowanych jako sekwencja warstw Keras oferuje interfejs Sequential API. Na przykład klasyfikator obrazów korzystający z 3 warstw gęstych można zapisać w Kerasie w ten sposób:

model = tf.keras.Sequential([
    tf.keras.layers.Flatten(input_shape=[192, 192, 3]),
    tf.keras.layers.Dense(500, activation="relu"),
    tf.keras.layers.Dense(50, activation="relu"),
    tf.keras.layers.Dense(5, activation='softmax') # classifying into 5 classes
])

# this configures the training of the model. Keras calls it "compiling" the model.
model.compile(
  optimizer='adam',
  loss= 'categorical_crossentropy',
  metrics=['accuracy']) # % of correct answers

# train the model
model.fit(dataset, ... )

688858c21e3beff2.png

Gęsta sieć neuronowa

Jest to najprostsza sieć neuronowa do klasyfikowania obrazów. Składa się z „neuronów” ułożonych w warstwach. Pierwsza warstwa przetwarza dane wejściowe i przekazuje wyniki do innych warstw. Jest ona nazywana „gęstą”, ponieważ każdy neuron jest połączony ze wszystkimi neuronami w poprzedniej warstwie.

c21bae6dade487bc.png

Obraz możesz przekazać do takiej sieci, spłaszczając wartości RGB wszystkich pikseli do długiego wektora i używając go jako danych wejściowych. Nie jest to najlepsza technika rozpoznawania obrazów, ale w przyszłości ją ulepszymy.

Neurony, aktywacje, RELU

„Neuron” oblicza ważoną sumę wszystkich danych wejściowych, dodaje wartość zwaną „obciążeniem” i przekazuje wynik przez tzw. „funkcję aktywacji”. Wagi i wartości progowe są początkowo nieznane. Są one inicjowane losowo i „uczone” przez trenowanie sieci neuronowej na wielu znanych danych.

644f4213a4ee70e5.png

Najpopularniejsza funkcja aktywacji to RELU (Rectified Linear Unit). Jest to bardzo prosta funkcja, co widać na wykresie powyżej.

Funkcja aktywacji softmax

Powyższa sieć kończy się warstwą 5 neuronów, ponieważ klasyfikujemy kwiaty w 5 kategoriach (róża, tulipan, mniszek lekarski, stokrotka, słonecznik). Neurony w warstwach pośrednich są aktywowane za pomocą klasycznej funkcji aktywacji RELU. W ostatniej warstwie chcemy jednak obliczyć liczby z zakresu od 0 do 1, które będą reprezentować prawdopodobieństwo, że dany kwiat jest różą, tulipanem itp. W tym celu użyjemy funkcji aktywacji o nazwie „softmax”.

Zastosowanie funkcji softmax do wektora polega na obliczeniu wartości wykładniczej każdego elementu, a następnie znormalizowaniu wektora, zwykle za pomocą normy L1 (sumy wartości bezwzględnych), tak aby wartości sumowały się do 1 i można je było interpretować jako prawdopodobieństwa.

ef0d98c0952c262d.png d51252f75894479e.gif

Funkcja straty entropii krzyżowej

Gdy nasza sieć neuronowa generuje prognozy na podstawie obrazów wejściowych, musimy zmierzyć, jak dobre są te prognozy, czyli odległość między tym, co mówi nam sieć, a prawidłowymi odpowiedziami, często nazywanymi „etykietami”. Pamiętaj, że mamy prawidłowe etykiety dla wszystkich obrazów w zbiorze danych.

Sprawdzi się dowolna odległość, ale w przypadku problemów z klasyfikacją najskuteczniejsza jest tzw. odległość entropii krzyżowej. Nazwiemy ją funkcją błędu lub „straty”:

7bdf8753d20617fb.png

Metoda gradientu prostego

„Trenowanie” sieci neuronowej polega na używaniu obrazów i etykiet treningowych do dostosowywania wag i odchyleń w celu zminimalizowania funkcji straty entropii krzyżowej. Działa to w następujący sposób:

Entropia krzyżowa jest funkcją wag, odchyleń, pikseli obrazu treningowego i jego znanej klasy.

Jeśli obliczymy pochodne cząstkowe entropii krzyżowej względem wszystkich wag i wszystkich odchyleń, otrzymamy „gradient” obliczony dla danego obrazu, etykiety oraz bieżącej wartości wag i odchyleń. Pamiętaj, że możemy mieć miliony wag i odchyleń, więc obliczanie gradientu wydaje się bardzo pracochłonne. Na szczęście TensorFlow robi to za nas. Własnością matematyczną gradientu jest to, że wskazuje on „w górę”. Chcemy, aby entropia krzyżowa była jak najmniejsza, więc idziemy w przeciwnym kierunku. Wagi i odchylenia aktualizujemy o ułamek gradientu. Następnie powtarzamy ten proces w przypadku kolejnych partii obrazów i etykiet treningowych w pętli trenowania. Mamy nadzieję, że zbiegnie się to w miejscu, w którym entropia krzyżowa jest minimalna, chociaż nic nie gwarantuje, że to minimum jest unikalne.

gradient descent2.png

Mini-batching i dynamika

Możesz obliczyć gradient na podstawie tylko jednego przykładowego obrazu i od razu zaktualizować wagi i odchylenia, ale zrobienie tego na podstawie np. 128 obrazów daje gradient, który lepiej odzwierciedla ograniczenia narzucone przez różne przykładowe obrazy, a tym samym prawdopodobnie szybciej zbiega się do rozwiązania. Rozmiar mini-partii jest parametrem, który można dostosować.

Ta technika, czasami nazywana „stochastycznym spadkiem gradientu”, ma jeszcze jedną, bardziej praktyczną zaletę: praca z partiami oznacza też pracę z większymi macierzami, które zwykle łatwiej jest optymalizować na GPU i TPU.

Proces zbieżności może być jednak nieco chaotyczny, a nawet zatrzymać się, jeśli wektor gradientu będzie składać się z samych zer. Czy to oznacza, że znaleźliśmy minimum? Nie zawsze. Składnik gradientu może wynosić zero w przypadku wartości minimalnej lub maksymalnej. W przypadku wektora gradientu z milionami elementów, jeśli wszystkie są zerami, prawdopodobieństwo, że każde zero odpowiada minimum, a żadne z nich nie odpowiada punktowi maksimum, jest dość małe. W przestrzeni wielowymiarowej punkty siodłowe są dość powszechne i nie chcemy się w nich zatrzymywać.

52e824fe4716c4a0.png

Ilustracja: punkt siodłowy. Gradient wynosi 0, ale nie jest minimum we wszystkich kierunkach. (Atrybucja obrazu: Wikimedia: By Nicoguaro - Own work, CC BY 3.0)

Rozwiązaniem jest dodanie do algorytmu optymalizacji pewnego rozpędu, aby mógł on przechodzić przez punkty siodłowe bez zatrzymywania się.

Słownik

wsadowe lub miniwsadowe: trenowanie jest zawsze przeprowadzane na partiach danych treningowych i etykiet. Ułatwia to algorytmowi zbieżność. Wymiar „batch” jest zwykle pierwszym wymiarem tensorów danych. Na przykład tensor o kształcie [100, 192, 192, 3] zawiera 100 obrazów o wymiarach 192 x 192 piksele z 3 wartościami na piksel (RGB).

funkcja straty entropii krzyżowej: specjalna funkcja straty często używana w klasyfikatorach.

warstwa gęsta: warstwa neuronów, w której każdy neuron jest połączony ze wszystkimi neuronami w poprzedniej warstwie.

cechy: dane wejściowe sieci neuronowej są czasami nazywane „cechami”. Sztuka określania, które części zbioru danych (lub ich kombinacje) należy przekazać do sieci neuronowej, aby uzyskać dobre prognozy, jest nazywana „inżynierią cech”.

etykiety: inna nazwa „klas” lub prawidłowych odpowiedzi w problemie klasyfikacji nadzorowanej.

Tempo uczenia się: ułamek gradientu, o który wagi i odchylenia są aktualizowane w każdej iteracji pętli trenowania.

Logity: wyniki warstwy neuronów przed zastosowaniem funkcji aktywacji są nazywane „logitami”. Nazwa pochodzi od „funkcji logistycznej”, czyli „funkcji sigmoidalnej”, która była najpopularniejszą funkcją aktywacji. „Neuron outputs before logistic function” (Wyniki neuronu przed funkcją logistyczną) skrócono do „logits” (logity).

funkcja straty: funkcja błędu porównująca dane wyjściowe sieci neuronowej z prawidłowymi odpowiedziami;

Neuron: oblicza ważoną sumę danych wejściowych, dodaje do niej wartość progową i przekazuje wynik przez funkcję aktywacji.

Kodowanie 1 z n: klasa 3 z 5 jest kodowana jako wektor 5 elementów, z których wszystkie są zerami z wyjątkiem 3 elementu, który ma wartość 1.

relu: jednostka liniowa z prostownikiem. Popularna funkcja aktywacji neuronów.

sigmoid: kolejna funkcja aktywacji, która była kiedyś popularna i nadal jest przydatna w szczególnych przypadkach.

softmax: specjalna funkcja aktywacji, która działa na wektor, zwiększa różnicę między największym komponentem a wszystkimi pozostałymi, a także normalizuje wektor, aby jego suma wynosiła 1, dzięki czemu można go interpretować jako wektor prawdopodobieństw. Używana jako ostatni krok w klasyfikatorach.

tensor: „tensor” to macierz o dowolnej liczbie wymiarów. Tensor 1-wymiarowy to wektor. Tensor 2-wymiarowy to macierz. Możesz też mieć tensory o 3, 4, 5 wymiarach lub więcej.

5. [INFO] Splotowe sieci neuronowe

W skrócie

Jeśli znasz już wszystkie pogrubione terminy w następnym akapicie, możesz przejść do kolejnego ćwiczenia. Jeśli dopiero zaczynasz przygodę z konwolucyjnymi sieciami neuronowymi, czytaj dalej.

convolutional.gif

Ilustracja: filtrowanie obrazu za pomocą 2 kolejnych filtrów, z których każdy ma 48 wag do nauczenia (4 x 4 x 3=48).

Tak wygląda prosta splotowa sieć neuronowa w Kerasie:

model = tf.keras.Sequential([
  # input: images of size 192x192x3 pixels (the three stands for RGB channels)
  tf.keras.layers.Conv2D(kernel_size=3, filters=24, padding='same', activation='relu', input_shape=[192, 192, 3]),
  tf.keras.layers.Conv2D(kernel_size=3, filters=24, padding='same', activation='relu'),
  tf.keras.layers.MaxPooling2D(pool_size=2),
  tf.keras.layers.Conv2D(kernel_size=3, filters=12, padding='same', activation='relu'),
  tf.keras.layers.MaxPooling2D(pool_size=2),
  tf.keras.layers.Conv2D(kernel_size=3, filters=6, padding='same', activation='relu'),
  tf.keras.layers.Flatten(),
  # classifying into 5 categories
  tf.keras.layers.Dense(5, activation='softmax')
])

model.compile(
  optimizer='adam',
  loss= 'categorical_crossentropy',
  metrics=['accuracy'])

688858c21e3beff2.png

Wprowadzenie do konwolucyjnych sieci neuronowych

W warstwie sieci konwolucyjnej jeden „neuron” oblicza ważoną sumę pikseli znajdujących się bezpośrednio nad nim, ale tylko w niewielkim obszarze obrazu. Dodaje on odchylenie i przekazuje sumę przez funkcję aktywacji, tak jak neuron w zwykłej warstwie gęstej. Następnie operacja jest powtarzana na całym obrazie z użyciem tych samych wag. Pamiętaj, że w warstwach gęstych każdy neuron miał własne wagi. W tym przypadku pojedynczy „fragment” wag przesuwa się po obrazie w obu kierunkach (jest to „splot”). Dane wyjściowe mają tyle wartości, ile pikseli na obrazie (chociaż na krawędziach konieczne jest pewne wypełnienie). Jest to operacja filtrowania z użyciem filtra o 48 wagach (4 x 4 x 3=48).

Jednak 48 wag nie wystarczy. Aby dodać więcej stopni swobody, powtarzamy tę samą operację z nowym zestawem wag. Spowoduje to wygenerowanie nowego zestawu danych wyjściowych filtra. Nazwijmy go „kanałem” wyników, analogicznie do kanałów R, G, B na obrazie wejściowym.

Screen Shot 2016-07-29 at 16.02.37.png

Dwa (lub więcej) zestawy wag można zsumować jako jeden tensor, dodając nowy wymiar. Daje nam to ogólny kształt tensora wag dla warstwy konwolucyjnej. Liczba kanałów wejściowych i wyjściowych jest parametrem, więc możemy zacząć układać i łączyć warstwy konwolucyjne.

d1b557707bcd1cb9.png

Ilustracja: konwolucyjna sieć neuronowa przekształca „kostki” danych w inne „kostki” danych.

Konwolucje z krokiem, maksymalne próbkowanie

Wykonując konwolucje z krokiem 2 lub 3, możemy też zmniejszyć wynikowy sześcian danych w wymiarach poziomych. Można to zrobić na 2 sposoby:

  • Konwolucja z krokiem: przesuwany filtr jak powyżej, ale z krokiem > 1.
  • Maksymalne uśrednianie: okno przesuwne stosujące operację MAX (zwykle na fragmentach 2x2, powtarzane co 2 piksele).

2b2d4263bb8470b.gif

Ilustracja: przesunięcie okna obliczeniowego o 3 piksele powoduje zmniejszenie liczby wartości wyjściowych. Sploty z krokiem lub maksymalne próbkowanie (maksymalna wartość w oknie 2x2 przesuwającym się o krok 2) to sposób na zmniejszenie kostki danych w wymiarach poziomych.

Klasyfikator konwolucyjny

Na koniec dołączamy głowicę klasyfikacji, spłaszczając ostatnią kostkę danych i przekazując ją przez gęstą warstwę aktywowaną funkcją softmax. Typowy klasyfikator konwolucyjny może wyglądać tak:

4a61aaffb6cba3d1.png

Ilustracja: klasyfikator obrazów korzystający z warstw konwolucyjnych i softmax. Wykorzystuje filtry 3x3 i 1x1. Warstwy maxpool wybierają maksymalną wartość z grup punktów danych o rozmiarze 2x2. Głowica klasyfikacji jest zaimplementowana za pomocą warstwy gęstej z funkcją aktywacji softmax.

W Keras

Przedstawiony powyżej stos konwolucyjny można zapisać w Kerasie w ten sposób:

model = tf.keras.Sequential([
  # input: images of size 192x192x3 pixels (the three stands for RGB channels)    
  tf.keras.layers.Conv2D(kernel_size=3, filters=32, padding='same', activation='relu', input_shape=[192, 192, 3]),
  tf.keras.layers.Conv2D(kernel_size=1, filters=32, padding='same', activation='relu'),
  tf.keras.layers.MaxPooling2D(pool_size=2),
  tf.keras.layers.Conv2D(kernel_size=3, filters=32, padding='same', activation='relu'),
  tf.keras.layers.Conv2D(kernel_size=1, filters=32, padding='same', activation='relu'),
  tf.keras.layers.MaxPooling2D(pool_size=2),
  tf.keras.layers.Conv2D(kernel_size=3, filters=32, padding='same', activation='relu'),
  tf.keras.layers.Conv2D(kernel_size=1, filters=32, padding='same', activation='relu'),
  tf.keras.layers.MaxPooling2D(pool_size=2),
  tf.keras.layers.Conv2D(kernel_size=3, filters=32, padding='same', activation='relu'),
  tf.keras.layers.Conv2D(kernel_size=1, filters=32, padding='same', activation='relu'),
  tf.keras.layers.MaxPooling2D(pool_size=2),
  tf.keras.layers.Conv2D(kernel_size=3, filters=16, padding='same', activation='relu'),
  tf.keras.layers.Conv2D(kernel_size=1, filters=8, padding='same', activation='relu'),
  tf.keras.layers.Flatten(),
  # classifying into 5 categories
  tf.keras.layers.Dense(5, activation='softmax')
])

model.compile(
  optimizer='adam',
  loss= 'categorical_crossentropy',
  metrics=['accuracy'])

6. [NEW INFO] Nowoczesne architektury konwolucyjne

W skrócie

7968830b57b708c0.png

Ilustracja: moduł konwolucyjny. Co w tej sytuacji będzie najlepsze? Warstwa max-pool, a po niej warstwa konwolucyjna 1x1 lub inna kombinacja warstw? Wypróbuj je wszystkie, połącz wyniki i pozwól sieci zdecydować. Po prawej stronie: architektura konwolucyjna „ inception” wykorzystująca takie moduły.

W Kerasie do tworzenia modeli, w których przepływ danych może się rozgałęziać, musisz używać stylu modelu „funkcjonalnego”. Oto przykład:

l = tf.keras.layers # syntax shortcut

y = l.Conv2D(filters=32, kernel_size=3, padding='same',
             activation='relu', input_shape=[192, 192, 3])(x) # x=input image

# module start: branch out
y1 = l.Conv2D(filters=32, kernel_size=1, padding='same', activation='relu')(y)
y3 = l.Conv2D(filters=32, kernel_size=3, padding='same', activation='relu')(y)
y = l.concatenate([y1, y3]) # output now has 64 channels
# module end: concatenation

# many more layers ...

# Create the model by specifying the input and output tensors.
# Keras layers track their connections automatically so that's all that's needed.
z = l.Dense(5, activation='softmax')(y)
model = tf.keras.Model(x, z)

688858c21e3beff2.png

Inne tanie sztuczki

Małe filtry 3x3

40a7b15fb7dbe75c.png

Na tej ilustracji widać wynik zastosowania dwóch kolejnych filtrów 3x3. Spróbuj prześledzić, które punkty danych przyczyniły się do uzyskania wyniku: te 2 kolejne filtry 3x3 obliczają pewną kombinację regionu 5x5. Nie jest to dokładnie ta sama kombinacja, którą obliczyłby filtr 5x5, ale warto spróbować, ponieważ 2 kolejne filtry 3x3 są tańsze niż 1 filtr 5x5.

Konwolucje 1x1

fd7cac16f8ecb423.png

W matematyce konwolucja „1x1” to mnożenie przez stałą, co nie jest zbyt przydatne. Pamiętaj jednak, że w przypadku konwolucyjnych sieci neuronowych filtr jest stosowany do kostki danych, a nie tylko do obrazu 2D. Filtr „1x1” oblicza ważoną sumę kolumny danych o rozmiarze 1x1 (patrz ilustracja), a przesuwając go po danych, uzyskasz kombinację liniową kanałów wejściowych. To jest przydatne. Jeśli potraktujesz kanały jako wyniki poszczególnych operacji filtrowania, np. filtr „spiczaste uszy”, „wąsy” i „szczelinowe oczy”, to warstwa konwolucyjna „1x1” będzie obliczać wiele możliwych kombinacji liniowych tych cech, co może być przydatne podczas wyszukiwania „kota”. Dodatkowo warstwy 1x1 używają mniejszej liczby wag.

7. Squeezenet

Prosty sposób na połączenie tych pomysłów został przedstawiony w publikacji „Squeezenet”. Autorzy proponują bardzo prostą architekturę modułu konwolucyjnego, w której używane są tylko warstwy konwolucyjne 1x1 i 3x3.

1730ac375379269b.png

Ilustracja: architektura SqueezeNet oparta na „modułach Fire”. Na przemian stosują warstwę 1x1, która „ściska” dane przychodzące w wymiarze pionowym, a następnie 2 równoległe warstwy konwolucyjne 1x1 i 3x3, które ponownie „rozszerzają” głębię danych.

Praktyczne

Kontynuuj pracę w poprzednim notatniku i zbuduj konwolucyjną sieć neuronową inspirowaną architekturą SqueezeNet. Musisz zmienić kod modelu na „styl funkcjonalny” Keras.

c3df49e90e5a654f.png Keras_Flowers_TPU (playground).ipynb

Dodatkowe informacje

W tym ćwiczeniu przyda się zdefiniowanie funkcji pomocniczej dla modułu SqueezeNet:

def fire(x, squeeze, expand):
  y = l.Conv2D(filters=squeeze, kernel_size=1, padding='same', activation='relu')(x)
  y1 = l.Conv2D(filters=expand//2, kernel_size=1, padding='same', activation='relu')(y)
  y3 = l.Conv2D(filters=expand//2, kernel_size=3, padding='same', activation='relu')(y)
  return tf.keras.layers.concatenate([y1, y3])

# this is to make it behave similarly to other Keras layers
def fire_module(squeeze, expand):
  return lambda x: fire(x, squeeze, expand)

# usage:
x = l.Input(shape=[192, 192, 3])
y = fire_module(squeeze=24, expand=48)(x) # typically, squeeze is less than expand
y = fire_module(squeeze=32, expand=64)(y)
...
model = tf.keras.Model(x, y)

Tym razem celem jest osiągnięcie 80% dokładności.

Warto spróbować

Zacznij od jednej warstwy splotowej, a potem dodaj „fire_modules”, na przemian z warstwami MaxPooling2D(pool_size=2). Możesz eksperymentować z 2–4 warstwami maksymalnego pulowania w sieci, a także z 1, 2 lub 3 kolejnymi modułami Fire między warstwami maksymalnego pulowania.

W modułach dotyczących pożarów parametr „squeeze” powinien być zwykle mniejszy niż parametr „expand”. Te parametry to w rzeczywistości liczby filtrów. Zwykle mieszczą się w zakresie od 8 do 196. Możesz eksperymentować z architekturami, w których liczba filtrów stopniowo rośnie w sieci, lub z prostymi architekturami, w których wszystkie moduły fire mają taką samą liczbę filtrów.

Oto przykład:

x = tf.keras.layers.Input(shape=[*IMAGE_SIZE, 3]) # input is 192x192 pixels RGB

y = tf.keras.layers.Conv2D(kernel_size=3, filters=32, padding='same', activation='relu')(x)
y = fire_module(24, 48)(y)
y = tf.keras.layers.MaxPooling2D(pool_size=2)(y)
y = fire_module(24, 48)(y)
y = tf.keras.layers.MaxPooling2D(pool_size=2)(y)
y = fire_module(24, 48)(y)
y = tf.keras.layers.GlobalAveragePooling2D()(y)
y = tf.keras.layers.Dense(5, activation='softmax')(y)

model = tf.keras.Model(x, y)

W tym momencie możesz zauważyć, że eksperymenty nie przebiegają zbyt dobrze i że osiągnięcie 80-procentowej dokładności wydaje się odległe. Czas na kilka kolejnych tanich sztuczek.

Batch Normalization

Normalizacja wsadowa pomoże Ci rozwiązać problemy ze zbieżnością. Szczegółowe wyjaśnienia tej techniki znajdziesz w następnych warsztatach. Na razie używaj jej jako „magicznego” pomocnika, dodając ten wiersz po każdej warstwie konwolucyjnej w swojej sieci, w tym po warstwach w funkcji fire_module:

y = tf.keras.layers.BatchNormalization(momentum=0.9)(y)
# please adapt the input and output "y"s to whatever is appropriate in your context

Parametr momentum musi zostać zmniejszony z domyślnej wartości 0,99 do 0,9, ponieważ nasz zbiór danych jest mały. Na razie nie przejmuj się tym szczegółem.

Augmentacja danych

Możesz uzyskać kilka dodatkowych punktów procentowych, wzbogacając dane o proste przekształcenia, takie jak odwrócenie obrazu w pionie lub poziomie albo zmiany nasycenia:

4ed2958e09b487ca.png

ad795b70334e0d6b.png

W TensorFlow jest to bardzo proste dzięki interfejsowi tf.data.Dataset API. Zdefiniuj nową funkcję przekształcenia danych:

def data_augment(image, label):
    image = tf.image.random_flip_left_right(image)
    image = tf.image.random_saturation(image, lower=0, upper=2)
    return image, label

Następnie użyj go w ostatecznym przekształceniu danych (komórka „training and validation datasets”, funkcja „get_batched_dataset”):

dataset = dataset.repeat() # existing line
# insert this
if augment_data:
  dataset = dataset.map(data_augment, num_parallel_calls=AUTO)
dataset = dataset.shuffle(2048) # existing line

Nie zapomnij, aby rozszerzanie danych było opcjonalne, i dodaj niezbędny kod, aby mieć pewność, że rozszerzany jest tylko zbiór danych treningowych. Nie ma sensu powiększać zbioru danych weryfikacyjnych.

Osiągnięcie dokładności na poziomie 80% w 35 epokach powinno być teraz możliwe.

Rozwiązanie

Oto notatnik z rozwiązaniem. Możesz z niej skorzystać, jeśli utkniesz w martwym punkcie.

c3df49e90e5a654f.png Keras_Flowers_TPU_squeezenet.ipynb

Omówione zagadnienia

  • 🤔 Modele Keras w „stylu funkcyjnym”
  • 🤓 Architektura Squeezenet
  • 🤓 Rozszerzanie danych za pomocą tf.data.dataset

Poświęć chwilę na przejrzenie tej listy kontrolnej.

8. Dostrojony model Xception

Konwolucje rozdzielne

Ostatnio zyskuje popularność inny sposób implementacji warstw konwolucyjnych: konwolucje rozdzielne głębiowo. Wiem, że to skomplikowane, ale sama koncepcja jest dość prosta. Są one zaimplementowane w TensorFlow i Keras jako tf.keras.layers.SeparableConv2D.

Konwolucja separowalna również stosuje filtr do obrazu, ale używa innego zestawu wag dla każdego kanału obrazu wejściowego. Następnie następuje „konwolucja 1x1”, czyli seria iloczynów skalarnych, które dają ważoną sumę odfiltrowanych kanałów. Za każdym razem z nowymi wagami obliczana jest wymagana liczba ważonych rekombinacji kanałów.

615720b803bf8dda.gif

Ilustracja: konwolucje separowalne. Faza 1. Konwolucje z osobnym filtrem dla każdego kanału. Faza 2: liniowe rekombinacje kanałów. Powtarzane z nowym zestawem wag, aż zostanie osiągnięta żądana liczba kanałów wyjściowych. Etap 1 można też powtórzyć, za każdym razem z nowymi wagami, ale w praktyce rzadko się to zdarza.

Konwolucje rozdzielne są używane w najnowszych architekturach sieci konwolucyjnych: MobileNetV2, Xception i EfficientNet. Nawiasem mówiąc, MobileNetV2 to model, którego używasz do uczenia przez przenoszenie.

Są one tańsze od zwykłych splotów i w praktyce okazują się równie skuteczne. Oto waga w przypadku przykładu przedstawionego powyżej:

Warstwa konwolucyjna: 4 x 4 x 3 x 5 = 240

Warstwa konwolucyjna z separacją: 4 x 4 x 3 + 3 x 5 = 48 + 15 = 63

Obliczenie liczby mnożeń wymaganych do zastosowania każdego stylu warstwy konwolucyjnej pozostawiamy czytelnikowi. Są one mniejsze i znacznie bardziej wydajne obliczeniowo.

Praktyczne

Zacznij od nowa w notatniku „transfer learning”, ale tym razem wybierz Xception jako wstępnie wytrenowany model. Xception używa tylko konwolucji rozdzielnych. Pozostaw wszystkie wagi z możliwością trenowania. Zamiast używać wstępnie wytrenowanych warstw, będziemy dostrajać wstępnie wytrenowane wagi na podstawie naszych danych.

c3df49e90e5a654f.png Keras Flowers transfer learning (playground).ipynb

Cel: dokładność > 95% (tak, to możliwe!)

To ostatnie ćwiczenie wymaga nieco więcej pracy związanej z kodowaniem i nauką o danych.

Dodatkowe informacje o dostrajaniu

Model Xception jest dostępny w standardowych wytrenowanych modelach w tf.keras.application.* Tym razem nie zapomnij pozostawić wszystkich wag z możliwością trenowania.

pretrained_model = tf.keras.applications.Xception(input_shape=[*IMAGE_SIZE, 3],
                                                  include_top=False)
pretrained_model.trainable = True

Aby uzyskać dobre wyniki podczas dostrajania modelu, musisz zwrócić uwagę na tempo uczenia się i użyć harmonogramu tempa uczenia się z okresem optymalizacyjnym. W ten sposób:

9b1af213b2b36d47.png

Rozpoczęcie od standardowego tempa uczenia się zakłóciłoby wstępnie wytrenowane wagi modelu. Stopniowe rozpoczynanie zachowuje je, dopóki model nie zostanie dopasowany do Twoich danych i nie będzie w stanie ich odpowiednio modyfikować. Po okresie rozgrzewki możesz kontynuować ze stałym lub wykładniczo malejącym tempem uczenia się.

W Keras tempo uczenia się jest określane za pomocą wywołania zwrotnego, w którym możesz obliczyć odpowiednie tempo uczenia się dla każdej epoki. Keras przekaże do optymalizatora odpowiednie tempo uczenia się dla każdej epoki.

def lr_fn(epoch):
  lr = ...
  return lr

lr_callback = tf.keras.callbacks.LearningRateScheduler(lr_fn, verbose=True)

model.fit(..., callbacks=[lr_callback])

Rozwiązanie

Oto notatnik z rozwiązaniem. Możesz z niej skorzystać, jeśli utkniesz w martwym punkcie.

c3df49e90e5a654f.png 07_Keras_Flowers_TPU_xception_fine_tuned_best.ipynb

Omówione zagadnienia

  • 🤔 Konwolucja z rozdzieleniem głębi
  • 🤓 Harmonogramy tempa uczenia się
  • 😈 Dostrajanie wstępnie wytrenowanego modelu.

Poświęć chwilę na przejrzenie tej listy kontrolnej.

9. Gratulacje!

Udało Ci się zbudować pierwszą nowoczesną splotową sieć neuronową i wytrenować ją do dokładności ponad 90%. Dzięki TPU kolejne iteracje szkolenia zajęły Ci tylko kilka minut. To koniec 4 samouczków „Keras na TPU”:

TPU w praktyce

TPU i GPU są dostępne na Cloud AI Platform:

Na koniec dodamy, że chętnie poznamy Twoją opinię. Jeśli zauważysz w tym module coś nieprawidłowego lub uważasz, że można go ulepszyć, daj nam znać. Opinie można przesyłać za pomocą zgłoszeń w GitHub [link do opinii].

HR.png

Martin Görner ID small.jpg
Autor: Martin Görner
Twitter: @martin_gorner

tensorflow logo.jpg
www.tensorflow.org