1. Omówienie
W tym module zapoznasz się z nowoczesną architekturą konwolucyjną i wykorzystasz swoją wiedzę do wdrożenia prostej, ale skutecznej metody tzw. squeezenet.
Ten moduł zawiera niezbędne wyjaśnienia teorii dotyczące splotowych sieci neuronowych i jest dobrym punktem wyjścia dla deweloperów, którzy chcą poznać deep learning.
Ten moduł jest częścią 4 serii „Keras w TPU”. Możesz to zrobić w poniższej kolejności lub samodzielnie.
- Potoki danych działające z szybkością TPU: tf.data.Dataset i TFRecords
- Pierwszy model Keras z wykorzystaniem uczenia transferowego
- Splotowe sieci neuronowe z Keras i TPU
- [THIS LAB] Nowoczesne konwety, squeezenet, Xception z wykorzystaniem Keras i TPU
Czego się nauczysz
- Opanowanie stylu funkcjonalnego Keras
- Aby utworzyć model z architekturą squeezenet
- Aby używać TPU do szybkiego trenowania i ulepszania architektury
- Implementacja rozszerzania danych za pomocą funkcji tf.data.dataset
- Dostrojenie dużego wytrenowanego wstępnie modelu (Xception) na TPU
Prześlij opinię
Jeśli zauważysz, że w tym laboratorium z kodem coś jest nie tak, daj nam znać. Opinie można przesyłać za pomocą zgłoszeń na GitHubie [link do opinii].
2. Krótki przewodnik po Google Colaboratory
Ten moduł używa Google Collaboratory i nie wymaga konfiguracji. Colaboratory to internetowa platforma do tworzenia notatek przeznaczona do użytku edukacyjnego. Oferuje bezpłatne trenowanie dotyczące CPU, GPU i TPU.
Możesz otworzyć ten przykładowy notatnik i uruchomić kilka komórek, aby zapoznać się z Colaboratory.
Wybieranie backendu TPU
W menu Colab kliknij Środowisko wykonawcze > Zmień typ środowiska wykonawczego, a potem wybierz TPU. W tym laboratorium kodu skorzystasz z wydajnego TPU (jednostki Tensor Processing Unit) z przyspieszeniem sprzętowym. Połączenie z runtime nastąpi automatycznie przy pierwszym uruchomieniu. Możesz też użyć przycisku „Połącz” w prawym górnym rogu.
Wykonywanie notatnika
Uruchom po kolei komórki, klikając wybraną komórkę i naciskając klawisze Shift+ENTER. Aby uruchomić cały notatnik, możesz też kliknąć Ś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żesz kliknąć je dwukrotnie, aby zobaczyć kod, ale zwykle nie jest on zbyt interesujący. Zwykle są to funkcje obsługi lub wizualizacji. Aby zdefiniować funkcje, musisz uruchomić te komórki.
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 spowoduje uruchomienie procesu uwierzytelniania.
3. [INFO] Czym są jednostki Tensor Processing Unit (TPU)?
W skrócie
Kod do trenowania modelu na TPU w Keras (i domyślne użycie GPU lub procesora, jeśli TPU jest niedostępne):
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 jednostki TPU?
Nowoczesne procesory GPU są zorganizowane wokół programowalnych „rdzeni” i bardzo elastycznej architektury, która pozwala im wykonywać różne zadania, takie jak renderowanie 3D, uczenie głębokie czy symulacje fizyczne. TPU łączy klasyczny procesor wektorowy z dedykowaną jednostką mnożenia macierzy i doskonale sprawdza się w przypadku zadań, w których dominuje mnożenie dużych macierzy, np. w sieciach neuronowych.
Ilustracja: gęsta warstwa sieci neuronowej jako mnożenie macierzy z ośmioma obrazami przetwarzanymi przez sieć neuronową jednocześnie. 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
Rdzeń TPU v2 składa się z jednostki mnożenia macierzy (MXU), która wykonuje mnożenie macierzy, oraz jednostki przetwarzania wektorów (VPU) do wykonywania wszystkich innych zadań, takich jak aktywacje, softmax itp. VPU obsługuje obliczenia float32 i int32. Z kolei moduł MXU działa w mieszanym, 16-32-bitowym formacie zmiennoprzecinkowym o mieszanej dokładności.
Mieszana precyzja zmiennoprzecinkowa i bfloat16
MXU wykonuje mnożenie macierzy przy użyciu danych wejściowych bfloat16 i wyjść float32. Zbiorcze gromadzenie danych jest wykonywane z dokładnością do float32.
Trenowanie sieci neuronowej jest zwykle odporne na szum spowodowany zmniejszoną precyzją liczb zmiennoprzecinkowych. W niektórych przypadkach szum może nawet pomóc optymalizatorowi w konwergencji. 16-bitowa precyzja liczby zmiennoprzecinkowej była tradycyjnie używana do przyspieszania obliczeń, ale formaty float16 i float32 mają bardzo różne zakresy. Zmniejszenie precyzji z float32 do float16 zazwyczaj skutkuje przekroczeniem i niedopuszczalnym przepływem. Rozwiązania istnieją, ale do poprawnego działania typu float16 zazwyczaj trzeba się przyłożyć.
Właśnie dlatego wprowadziliśmy w jednostkach TPU format bfloat16. To skrócona liczba zmiennoprzecinkowa zmiennoprzecinkowa 32 z dokładnie takim samym zakresem jak w przypadku float32 Do tego dochodzi fakt, że procesory TPU obliczają mnożenia macierzy w mieszanej precyzji z wejściami bfloat16, a wyjściami float32, co oznacza, że zazwyczaj nie trzeba wprowadzać żadnych zmian w kodzie, aby skorzystać z wzrostu wydajności wynikającego z obniżenia precyzji.
Tablica skurczowa
MXU implementuje mnożenie macierzy na sprzęcie, korzystając z tzw. architektury „mnożnika systolicznego”, w której elementy danych przepływają przez tablicę jednostek obliczeniowych sprzętowych. (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 zaprogramowano ten iloczyn skalarny na „rdzeń” GPU, a następnie uruchamiał go równolegle na dowolnej liczbie dostępnych rdzeni, aby spróbować naraz obliczyć wszystkie wartości wynikowej macierzy. Jeśli wynikowa matryca ma rozmiar 128 x 128, wymaga to dostępności 128 x 128 = 16 tys. „rdzeni”, co zwykle jest niemoż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 zaimplementować 16 tys. z nich w MXU 128 × 128 i przetworzyć to mnożenie macierzy jednym poleceniem.
Ilustracja: macierz skurczowa MXU. Elementy obliczeniowe to mnożniki akumulacji. Wartości jednej macierzy są ładowane do tablicy (czerwone kropki). Wartości z innej macierzy przepływają przez tablicę (szare kropki). Linie pionowe propagują wartości w górę. Linie poziome rozprzestrzeniają sumy częściowe. 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.
Dodatkowo, gdy iloczyny są obliczane w MXU, sumy pośrednie są po prostu przesyłane między sąsiednimi jednostkami obliczeniowymi. Nie muszą być przechowywane ani pobierane z pamięci ani nawet z pliku rejestru. W efekcie architektura macierzowego układu TPU ma znaczną gęstość i moc, a także niebagatelną przewagę nad procesorem graficznym pod względem szybkości podczas wykonywania mnożenia macierzy.
Cloud TPU
Jeśli wyślesz żądanie Cloud TPU v2 w Google Cloud Platform, otrzymasz maszynę wirtualną z płytką TPU dołączoną przez PCI. Karta TPU ma 4 podwójne rdzenie 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 wtedy zazwyczaj połączona przez sieć z maszyną wirtualną, która jej zażądała. Pełny obraz wygląda więc tak:
Ilustracja: maszyna wirtualna z podłączonym do sieci akceleratorem „Cloud TPU” „Cloud TPU” składa się z maszyny wirtualnej z kartą TPU podłączoną do gniazda PCI z 4 podwójnymi rdzeniami TPU.
podsumowanie 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ą one obejmować do 512 rdzeni TPU v2 lub 2048 rdzeni TPU v3.
Ilustracja: pod TPU v3. Płyty i racki TPU połączone za pomocą interfejsu HPC.
Podczas trenowania gradienty są wymieniane między rdzeniami TPU przy użyciu algorytmu all-reduce ( dobre wyjaśnienie funkcji all-reduce znajdziesz tutaj). Trenowany model może korzystać z tego sprzętu, trenując na dużych rozmiarach wsadu.
Ilustracja: synchronizacja gradientów podczas trenowania z wykorzystaniem algorytmu all-reduce w Google TPU w sieci toroidalnej sieci HPC 2-D typu mesh.
Oprogramowanie
Trenowanie na dużym wsadzie
Idealna wielkość partii dla TPU to 128 elementów danych na rdzeń TPU, ale sprzęt może już dobrze wykorzystać 8 elementów danych na rdzeń TPU. Pamiętaj, że jedna z Cloud TPU ma 8 rdzeni.
W tym module kodu będziemy używać interfejsu Keras API. W Keras określona przez Ciebie partia jest globalnym rozmiarem partii dla całego TPU. Wsady zostaną automatycznie podzielone na 8 i będą uruchamiane w 8 rdzeniach TPU.
Więcej wskazówek dotyczących wydajności znajdziesz w przewodniku po wydajności TPU. W przypadku bardzo dużych partii w niektórych modelach może być wymagana szczególna ostrożność. Więcej informacji znajdziesz w LARSOptimizer.
Zaawansowane: XLA
Programy Tensorflow definiują grafy obliczeniowe. TPU nie uruchamia bezpośrednio kodu w Pythonie, tylko uruchamia wykres obliczeniowy zdefiniowany przez program Tensorflow. W tle kompilator XLA (kompilator przyspieszonej algebry liniowej) przekształca graf Tensorflow z węzłami obliczeniowymi w kod maszynowy TPU. Ten kompilator przeprowadza też wiele zaawansowanych optymalizacji kodu i układu pamięci. Kompilacja odbywa się automatycznie, gdy zadanie jest wysyłane do TPU. Nie musisz dodawać XLA do łańcucha tworzenia.
Ilustracja: aby można było uruchomić program na TPU, najpierw przekształca się zdefiniowany przez niego graf obliczeń w reprezentację XLA (kompilator przyspieszonej algebry liniowej), a potem kompiluje się go za pomocą XLA w kod maszynowy TPU.
Używanie TPU w Keras
Od wersji Tensorflow 2.1 TPU są obsługiwane przez interfejs Keras API. 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”). Dzięki zmiennej środowiskowej TPU_NAME te systemy wiedzą, gdzie znajduje się ich TPU. Jeśli tworzysz TPU ręcznie, ustaw zmienną środowiskową TPU_NAME na maszynie wirtualnej, z której korzystasz, lub wywołajTPUClusterResolver
z jawnymi parametrami:TPUClusterResolver(tp_uname, zone, project)
TPUStrategy
to część, która wdraża rozkład i algorytm synchronizacji gradientowej „all-reduce”.- Strategia jest stosowana za pomocą zakresu. Model musi być zdefiniowany w zakresie strategii (zakres).
- Funkcja
tpu_model.fit
oczekuje obiektu tf.data.Dataset jako danych wejściowych do trenowania na 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
. - Procesory TPU są bardzo szybkie, ale często wąskim gardłem jest pozyskiwanie danych. 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.
- Wartości int8 i int16 są traktowane jako int32. TPU nie ma sprzętu obsługującego liczby całkowite o 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 treningowego, czyli przejść do przodu i do tyłu przez model. W swojej ścieżce przetwarzania danych możesz nadal używać wszystkich operacji Tensorflow, ponieważ będą one wykonywane na procesorze.
- Model
tf.py_func
nie jest obsługiwany przez TPU.
4. [INFO] Podstawy sieci neuronowych
W skrócie
Jeśli znasz już wszystkie terminy wyróżnione pogrubieniem w następnym akapicie, możesz przejść do następnego ćwiczenia. Jeśli dopiero zaczynasz przygodę z technologią deep learning, witamy w Google i zapraszamy do lektury dalszej części.
W przypadku modeli utworzonych jako sekwencja warstw Keras oferuje interfejs Sequential API. Na przykład klasyfikator obrazów wykorzystujący 3 gęste warstwy możesz zapisać w Kerarze w taki 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, ... )
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 ich wyniki do innych warstw. Nazywa się ją „gęstą”, ponieważ każdy neuron jest połączony ze wszystkimi neuronami w poprzedniej warstwie.
Można przekazać obraz do takiej sieci, spłaszczając wartości RGB wszystkich jego pikseli do długiego wektora i używając go jako danych wejściowych. Nie jest to najlepsza technika rozpoznawania obrazów, ale ulepszymy ją w przyszłości.
Neurony, aktywacje, RELU
„Neuron” oblicza ważoną sumę wszystkich swoich danych wejściowych, dodaje wartość zwaną „odchyleniem” i wykorzystuje tak zwaną „funkcję aktywacji”. Wagi i uśrednienia są na początku nieznane. Zostaną one zainicjowane losowo i „wyuczą się” przez trenowanie sieci neuronowej na wielu znanych danych.
Najpopularniejszą funkcją aktywacji jest RELU (prostej jednostki liniowej). Jak widać na wykresie powyżej, jest to bardzo prosta funkcja.
Aktywacja Softmax
Sieć kończy się warstwą 5-neuronową, ponieważ kwiaty są klasyfikowane do 5 kategorii (róża, tulipan, mniszek lekarski, stokrotka, słonecznik). Neurony w warstwach pośrednich są aktywowane przy użyciu klasycznej funkcji aktywacji RELU. W ostatniej warstwie chcemy jednak obliczyć liczby z zakresu od 0 do 1, które będą odpowiadać prawdopodobieństwu, że dany kwiat to róża, tulipan itp. W tym celu użyjemy funkcji aktywacji o nazwie „softmax”.
Zastosowanie funkcji softmax do wektora odbywa się przez pobranie wykładniczej każdego pierwiastka, a następnie normalizację wektora, zwykle z użyciem normy L1 (sumy wartości bezwzględnych), tak aby sumy się sumowały do 1 i można je zinterpretować jako prawdopodobieństwa.
Utrata entropii krzyżowej
Teraz, gdy nasza sieć neuronowa generuje prognozy na podstawie danych wejściowych, musimy zmierzyć, jak dobre są te prognozy, czyli odległość między tym, co mówi nam sieć, a prawidłowymi odpowiedziami, które często nazywamy „oznaczeniami”. Pamiętaj, że mamy prawidłowe etykiety wszystkich obrazów w zbiorze danych.
Dobrze sprawdzi się dowolna odległość, ale w przypadku problemów z klasyfikacją najbardziej skuteczna jest tzw. odległość entropii krzyżowej. Będziemy to nazwać funkcją błędu lub „straty”:
Spadek wzdłuż gradientu
„Trenowanie” sieci neuronowej oznacza w istocie korzystanie z obrazów i etykietek treningowych w celu dostosowania wag i uprzedzeń, aby zminimalizować funkcję straty entropii krzyżowej. Oto jak to działa.
Entropia krzyżowa jest funkcją wag, odchyleń, pikseli obrazu treningowego i jego znanej klasy.
Jeśli obliczamy częściowe pochodne entropii krzyżowej względem wszystkich wag i wszystkich odchyleń, uzyskujemy „gradient” obliczony dla danego obrazu, etykiety oraz bieżącej wartości wag i odchylenia. Pamiętaj, że możemy mieć miliony wag i błędów, więc obliczenie gradientu wydaje się bardzo czasochłonne. Na szczęście Tensorflow robi to za nas. Właściwością matematyczną gradientu jest to, że skierowany jest „do góry”. Ponieważ chcemy uzyskać wartość entropii krzyżowej zbliżoną do zera, idziemy w przeciwnym kierunku. Wagi i odchylenia aktualizujemy według części gradientu. Następnie powtarzamy ten sam proces wielokrotnie, używając kolejnych partii obrazów i etykiet do treningu. Mamy nadzieję, że zmierza ono do miejsca, w którym entropia krzyżowa jest minimalna, ale nie ma nic, co gwarantowałoby, że to minimum jest unikalne.
Krótkie partie i pęd
Możesz obliczyć gradient na podstawie tylko jednego przykładowego obrazu i natychmiast zaktualizować wagi i uświadczenia, ale wykonanie tego na przykładzie 128 obrazów daje gradient, który lepiej odzwierciedla ograniczenia narzucone przez różne przykładowe obrazy, a zatem prawdopodobnie szybciej zbliża się do rozwiązania. Wielkość minigrupy, którą można dostosować, jest parametrem.
Ta technika, czasami nazywana „stochastycznym gradientem”, ma jeszcze jedną, bardziej pragmatyczną korzyść: praca z wsadami oznacza również pracę z większymi matrycami, które zwykle można łatwiej zoptymalizować w przypadku układów GPU i TPU.
Konwergencja może być jednak nieco chaotyczna i może nawet się zatrzymać, jeśli wektor gradientu składa się wyłącznie z zer. Czy to oznacza, że znaleźliśmy minimum? Nie zawsze. Składowa gradientu może być równa 0 w przypadku wartości minimalnej lub maksymalnej. W przypadku wektora gradientu zawierającego miliony elementów (jeśli wszystkie są zerami), prawdopodobieństwo, że każde zero odpowiada minimum i żadnym z nich nie znajdzie się w punkcie maksymalnym, jest bardzo małe. W wielowymiarowej przestrzeni punkty siodła są dość powszechne i nie chcemy się na nich zatrzymywać.
Ilustracja: punkt siodłowy. Gradient ma wartość 0, ale nie jest minimalny we wszystkich kierunkach. (źródło obrazu: Wikimedia: By Nicoguaro - Own work, CC BY 3.0)
Rozwiązaniem jest dodanie algorytmowi optymalizacji pewnej dynamiki, aby mógł on omijać punkty spoczynku bez zatrzymywania się.
Słownik
zbiorcze lub miniwsadowe: trenowanie jest zawsze wykonywane na grupach danych i etykiet do trenowania. Ułatwia to stosowanie algorytmu. 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).
Utrata entropii krzyżowej: specjalna funkcja straty często używana w klasyfikatorach.
gęsta warstwa: warstwa neuronów, w której każdy neuron jest połączony ze wszystkimi neuronami w poprzedniej warstwie.
funkcje: dane wejściowe sieci neuronowej są czasami nazywane „cechami”. Sztuka ustalania, które części zbioru danych (lub ich kombinacje) przekazać do sieci neuronowej w celu uzyskania dobrych prognoz, nosi nazwę „inżynierii cech”.
labels: inna nazwa „zajęć” lub poprawne odpowiedzi w zadaniu z klasyfikacją nadzorowaną.
szybkość uczenia się: odsetek gradientu, według którego wagi i odchylenia są aktualizowane przy każdej iteracji pętli trenowania.
logits: dane wyjściowe warstwy neuronów przed zastosowaniem funkcji aktywacji są nazywane „logitami”. Termin pochodzi od „funkcji logistycznej”, czyli „funkcji sigmoidalnej”, która była kiedyś najpopularniejszą funkcją aktywacji. „Neuron outputs before logistic function” (Wyjścia neuronu przed funkcją logistycznej) zostało skrócone do „logitów”.
strata: funkcja błędu porównująca dane wyjściowe sieci neuronowej z prawidłowymi odpowiedziami.
neuron: oblicza ważony ciąg danych wejściowych, dodaje odchylenie i przekazuje wynik przez funkcję aktywacji.
kodowanie jedno- gorące: klasa 3 z 5 jest zakodowana jako wektor pięciu elementów, z wyjątkiem trzeciego, czyli 1.
relu: skorygowana jednostka liniowa. Popularna funkcja aktywacji neuronów.
sigmoid: inna funkcja aktywacji, która była kiedyś popularna i przydaje się w szczególnych przypadkach.
softmax: specjalna funkcja aktywacji, która działa na wektorze, zwiększa różnicę między największym składnikiem a pozostałymi, a także normalizuje wektor do sumy 1, co umożliwia zinterpretowanie go jako wektora prawdopodobieństw. Jest używany jako ostatni krok w klasyfikatorach.
tensor: „tensor” jest jak macierz, ale z dowolną liczbą wymiarów. Jednowymiarowy tensor jest wektorem. Tensor 2-wymiarowy jest macierzą. Możesz też mieć tensory o 3, 4, 5 lub większej liczbie wymiarów.
5. [INFO] Konwolucyjne sieci neuronowe
W skrócie
Jeśli znasz już wszystkie terminy wyróżnione pogrubieniem w następnym akapicie, możesz przejść do następnego ćwiczenia. Jeśli dopiero zaczynasz korzystać z konwolucyjnych sieci neuronowych, czytaj dalej.
Ilustracja: filtrowanie obrazu za pomocą 2 kolejnych filtrów o wymiarach 4 × 4 × 3=48 wag możliwych do wyuczenia się na każdym z nich.
Tak wygląda prosta splotowa sieć neuronowa w Keras:
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'])
Splotowe sieci neuronowe 101
W warstwie sieci splotowej jeden „neuron” dokonuje ważonej sumy pikseli znajdujących się tuż nad nią i obejmuje tylko mały obszar obrazu. Dodaje ona odchylenie i przekazuje sumę przez funkcję aktywacji, tak jak neuron w zwykłej gęstej warstwie. Następnie operacja jest powtarzana w całym obrazie przy użyciu tych samych wag. Pamiętaj, że w gęstych warstwach każdy neuron ma własną wagę. Tutaj pojedynczy „patch” wag przesuwa się po obrazie w obu kierunkach („sprzężenie”). Dane wyjściowe mają tyle wartości, ile jest pikseli na obrazie (wymagane jest jednak dopełnienie na krawędziach). Jest to operacja filtrowania przy użyciu filtra wag 4 x 4=48.
Jednak 48 wag nie wystarczy. Aby dodać więcej stopni swobody, powtarzamy tę samą operację z nowym zbiorem wag. Spowoduje to wygenerowanie nowego zbioru wyników filtrowania. Nazwijmy go „kanałem” danych wyjściowych w analogii do kanałów R, G i B na obrazie wejściowym.
2 lub więcej zestawów wag można zsumować jako jeden tensor, dodając nowy wymiar. Dzięki temu otrzymujemy ogólny kształt tensora wag dla warstwy konwolucyjnej. Ponieważ liczba kanałów wejściowych i wyjściowych jest parametrami, możemy zacząć porządkować i łączyć splotowe warstwy.
Ilustracja: splotowa sieć neuronowa przekształca „sześciany” danych w inne „sześciany” danych.
Sploty rozproszone, maksymalna liczba pulsu
Wykonując splot 2 lub 3, możemy również zmniejszyć wynikową kostkę danych w wymiarach poziomych. Możesz to zrobić na 2 sposoby:
- Konwolucja skokowa: przesuwający się filtr jak powyżej, ale z interwałem >1
- Maksymalne zwijanie: przesuwające się okno, które stosuje operację MAX (zazwyczaj na polach 2 x 2, powtarzanych co 2 piksele).
Ilustracja: przesunięcie okna przetwarzania o 3 piksele powoduje zmniejszenie wartości wyjściowych. Konwolucje skokowe lub maksymalne złączanie (maksimum w oknie 2 x 2 przesuwanym o krok 2) to sposób na zmniejszenie sześcianu danych w wymiarach poziomych.
Klasyfikator synwolucyjny
Na koniec przypinamy głowę klasyfikacji, spłaszczając ostatnią kostkę danych i karmiąc ją przez gęstą, aktywowaną warstwę softmax. Typowy klasyfikator konwolucyjny może wyglądać tak:
Ilustracja: klasyfikator obrazów wykorzystujący warstwy splotowe i softmax. Wykorzystuje filtry 3 x 3 i 1 x 1. Warstwy maxpool wybierają maksymalną wartość grup 2 x 2 punktów danych. Głowica klasyfikacyjna jest implementowana za pomocą gęstej warstwy z aktywacją softmax.
W Keraście
Przedstawioną wyżej warstwę konwolucyjną można zaimplementować w Keras 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. [NOWE INFORMACJE] Nowoczesne architektury konwolucyjne
W skrócie
Ilustracja: „moduł” konwolucyjny. Co jest najlepsze w tej chwili? Warstwa z maksymalną pulą, po której następuje warstwa splotowa 1 x 1, czy inna kombinacja warstw? Wypróbuj je wszystkie, połącz wyniki i pozwól sieci podjąć decyzję. Po prawej: architektura konwolucyjna „ incepcja” wykorzystująca takie moduły.
Aby w Keras tworzyć modele, w których przepływ danych może się rozgałęziać i rozgałęziać, musisz użyć 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)
Inne sztuczki
Małe filtry 3 x 3
Na tej ilustracji widać wynik dwóch następujących po sobie filtrów 3 x 3. Spróbuj ustalić, które punkty danych przyczyniły się do wyniku: te 2 kolejne filtry 3 x 3 obliczają pewną kombinację regionu 5 x 5. Nie jest to dokładnie ta sama kombinacja, którą oblicza filtr 5 x 5, ale warto spróbować, ponieważ 2 kolejne filtry 3 x 3 są tańsze niż 1 filtr 5 x 5.
Sploty 1 x 1?
W języku matematycznym splocenie „1 x 1” to mnożenie przez stałą, co nie jest zbyt przydatną koncepcją. Pamiętaj jednak, że w sieciach neuronowych konwolucyjnych filtr jest stosowany do sześcieru danych, a nie tylko do obrazu 2D. Filtr „1 x 1” oblicza zatem ważoną sumę kolumny danych 1 x 1 (patrz ilustracja). Gdy przesuniesz go po danych, uzyskasz kombinację liniową kanałów wejściowych. To naprawdę przydatne. Jeśli spojrzysz na kanały na wyniki poszczególnych operacji filtrowania, na przykład filtr dla „spiczastych uszu”, kolejny dla „wąsów”, a trzeci dla „wąsów”, to warstwa splotowa „1 x 1” będzie obliczać wiele możliwych liniowych kombinacji tych cech, co może być przydatne, gdy szukasz „kota”. Ponadto warstwy 1 x 1 wykorzystują mniej wag.
7. Kombinezon
Prosty sposób na połączenie tych pomysłów został omówiony w publikacji „Squeezenet”. Autorzy sugerują bardzo prostą konstrukcję modułu konwolucyjnego, wykorzystującą tylko warstwy konwolucyjne 1 x 1 i 3 x 3.
Ilustracja: architektura squeezenet oparta na „modułach ognistych”. Naprzemiennie występują warstwy 1 × 1, które „ściskają” przychodzące dane w wymiarach pionowych, a za nimi 2 równoległe warstwy konwolucyjne 1 × 1 i 3 × 3, które ponownie „rozszerzają” głębię danych.
Ćwiczenia praktyczne
Kontynuuj pracę w poprzednim notatniku i utwórz sieć neuronową konwolucyjną inspirowaną squeezenet. Konieczna będzie zmiana kodu modelu na „styl funkcjonalny” Keras.
Keras_Flowers_TPU (playground).ipynb
Informacje dodatkowe
W tym ćwiczeniu warto zdefiniować funkcję pomocniczą dla modułu ściągawki:
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% trafności.
Do wypróbowania
Zacznij od pojedynczej warstwy konwolucyjnej, a potem dodaj warstwę „fire_modules
”, na przemian z warstwami MaxPooling2D(pool_size=2)
. Możesz eksperymentować z 2–4 warstwami maksymalnego złączania w sieci, a także z 1, 2 lub 3 kolejnymi modułami uruchamiania między warstwami maksymalnego złączania.
W modułach ognia parametr „squeeze” powinien zwykle być mniejszy niż parametr „expand”. Te parametry to w istocie liczby filtrów. Zwykle mają one wartość od 8 do 196. Możesz eksperymentować z architekturami, w których liczba filtrów stopniowo wzrasta w sieci, lub z prostymi architekturami, w których wszystkie moduły ognia 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 przynoszą oczekiwanych rezultatów i że cel polegający na osiągnięciu 80% zgodności wydaje się odległy. Czas na kilka tanich sztuczek.
Normalizacja wsadowa
Norma wsadowa pomoże rozwiązać napotkane problemy z konwersją. Szczegółowe wyjaśnienia tej techniki znajdziesz na kolejnych warsztatach. Na razie użyj jej jako „magicznego” pomocnika w czarnej skrzynce, dodając ten wiersz po każdym warstwie konwolucyjnej w swojej sieci, w tym warstwy wewnątrz 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 pędu należy zmniejszyć z wartości domyślnej od 0,99 do 0,9, ponieważ nasz zbiór danych jest mały. Na razie nie zapomnij o tych szczegółach.
Rozszerzanie danych
Możesz uzyskać kilka punktów procentowych, uzupełniając dane o łatwe przekształcenia, np. o obrócenie w pionie lub w poziomie:
W Tensorflow można to zrobić bardzo łatwo za pomocą interfejsu 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 końcowym przekształceniu danych (komórka „zbiory danych do trenowania i walidacji”, 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 opcjonalnie wzbogacać dane i dodać niezbędny kod, aby mieć pewność, że wzbogacane są tylko dane z zbioru danych do trenowania. Nie ma sensu rozszerzania zbioru danych do weryfikacji.
Dokładność na poziomie 80% w 35 epokach powinna być już w zasięgu.
Rozwiązanie
Oto notatnik z rozwiązaniem. Możesz go użyć, jeśli napotkasz problemy.
Keras_Flowers_TPU_squeezenet.ipynb
Omówione zagadnienia
- 🤔 Modele „styl funkcjonalny” Keras
- 🤓 Architektura Squeezenet
- 🤓 Rozszerzanie danych za pomocą tf.data.datset
Poświęć chwilę na zapoznanie się z tą listą kontrolną.
8. Xception dostrojony
Rozdzielalne sploty
Ostatnio zyskuje na popularności inny sposób wdrażania warstw splotowych: głęboko rozdzielane sploty. Wiem, że to łyka, ale pomysł jest dość prosty. Są one implementowane w Tensorflow i Keras jako tf.keras.layers.SeparableConv2D
.
Przekształcenie splotne również stosuje filtr do obrazu, ale używa osobnego zestawu wag dla każdego kanału obrazu wejściowego. Następnie następuje „konwolucja 1 x 1”, czyli seria iloczynów kropek, która daje ważoną sumę filtrowanych kanałów. Za każdym razem są używane nowe wagi, a każdy kanał jest łączony z innymi kanałami z uwzględnieniem wag.
Ilustracja: operacje splotu rozdzielnego. Faza 1. sploty z osobnym filtrem dla każdego kanału. Etap 2. Liniowa rekombinacja kanałów. Powtarzane z nowym zbiorem wag do osiągnięcia żądanej liczby 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, EfficientNet. Przy okazji – system MobileNetV2 był wcześniej używany do przenoszenia systemów uczących się.
Są tańsze niż zwykłe konwolucje i w praktyce okazują się równie skuteczne. Oto waga dla przykładu zilustrowanego powyżej:
Warstwa konwolucyjna: 4 x 4 x 3 x 5 = 240
Rozdzielana warstwa splotowa: 4 x 4 x 3 + 3 x 5 = 48 + 15 = 63
Pozostawiamy czytelnikowi obliczenie liczby mnożeń wymaganych do zastosowania każdego stylu skalowania warstwy konwolucyjnej w podobny sposób. Przekształcenia rozdzielcze są mniejsze i znacznie wydajniejsze pod względem obliczeniowym.
Ćwiczenie
Uruchom ponownie z notatnika „Transfer learning” na placu zabaw, ale tym razem jako już wytrenowany model wybierz Xception. Xception używa tylko rozdzielanych splotów. Pozostaw wszystkie wagi do trenowania. Będziemy dostrajać już wytrenowane wagi na naszych danych, zamiast korzystać z wytrenowanych warstw.
Keras Flowers transfer learning (playground).ipynb
Cel: dokładność > 95% (naprawdę, to możliwe!)
To ostatnie ćwiczenie, które wymaga nieco więcej pracy z kodem i naukami o danych.
Dodatkowe informacje o dostrajaniu
Xception jest dostępny w standardowych wytrenowanych modelach w tf.keras.application.* Tym razem nie zapomnij pozostawić wszystkich wag do 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żywać harmonogramu tempa uczenia się z okresem optymalizacyjnym. W ten sposób:
Rozpoczęcie trenowania ze standardową szybkością uczenia się spowodowałoby zakłócenie wstępnie wytrenowanych wag modelu. Początkowe uruchamianie modelu pozwala zachować te wartości do momentu, gdy model zacznie wykorzystywać dane do ich modyfikowania w racjonalny sposób. Po rampie możesz kontynuować z stałym lub wykładniczo malejącym tempem uczenia się.
W Keras tempo uczenia się jest określane przez wywołanie zwrotne, w którym można obliczyć odpowiednie tempo uczenia się dla każdej epoki. Keras przekaże optymalizatorowi prawidłową szybkość uczenia się na każdą epokę.
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 go użyć, jeśli napotkasz problemy.
07_Keras_Flowers_TPU_xception_fine_tuned_best.ipynb
Omówione zagadnienia
- 🤔 Konwolucja z oddzielaniem głębi
- 🤓 Harmonogramy tempa uczenia się
- 😈 Dostrajanie wytrenowanego modelu.
Poświęć chwilę na zapoznanie się z tą listą kontrolną.
9. Gratulacje!
Utworzyłeś/utworzyłaś pierwszą nowoczesną splotową sieć neuronową i wytrenowałeś/wytrenowałaś ją z dokładnością powyżej 90%, wykonując kolejne treningi w zaledwie kilka minut dzięki procesorom TPU. To już wszystkie 4 laboratoria programistyczne „Keras na TPU”:
- Potoki danych działające z szybkością TPU: tf.data.Dataset i TFRecords
- Pierwszy model Keras z wykorzystaniem uczenia transferowego
- Splotowe sieci neuronowe wykorzystujące Keras i TPU
- [THIS LAB] Nowoczesne sieci ConvNet, squeezenet, Xception z Keras i TPU
TPU w praktyce
TPU i GPU są dostępne na platformie Cloud AI:
- Na maszynach wirtualnych do deep learningu
- W Notatkach w AI Platform
- W zadaniach Trenowanie w AI Platform
Na koniec – chętnie poznamy Twoją opinię. Poinformuj nas, jeśli zauważysz w tym module coś nie tak lub jeśli uważasz, że można go ulepszyć. Opinię można przesłać, korzystając z formularza dotyczącego problemów na GitHubie [link do przesyłania opinii].
|