Witamy w części 3 Serii Applied Deep Learning. Część 1 Była praktycznym wprowadzeniem do sztucznych sieci neuronowych, obejmującym zarówno teorię, jak i aplikację z wieloma przykładami kodu i wizualizacją. W części 2 zastosowaliśmy deep learning do rzeczywistych zbiorów danych, obejmując 3 najczęściej spotykane problemy jako studia przypadków: klasyfikacja binarna, klasyfikacja wieloklasowa i regresja.
teraz zaczniemy nurkować w konkretnych architekturach głębokiego uczenia, zaczynając od najprostszych: Autoencoderów.
- wprowadzenie
- Architektura
- implementacja
- usuwanie Autoencoderów
- rzadkie Autoencodery
- przypadki użycia
- podsumowanie
kod do tego artykułu jest dostępny tutaj jako notatnik Jupyter, zapraszam do pobrania i wypróbowania go samemu.
wprowadzenie
Autoencodery są specyficznym rodzajem sieci neuronowych, w których wejście jest takie samo jak wyjście. Kompresują one dane wejściowe do kodu o niższym wymiarze, a następnie rekonstruują dane wyjściowe z tej reprezentacji. Kod jest zwartym „podsumowaniem” lub „kompresją” wejścia, zwanym także reprezentacją utajonej przestrzeni.
autoencoder składa się z 3 komponentów: kodera, kodu i dekodera. Koder kompresuje wejście i wytwarza kod, dekoder następnie rekonstruuje wejście tylko za pomocą tego kodu.
aby zbudować autoencoder potrzebujemy 3 rzeczy: metody kodowania, metody dekodowania i funkcji utraty, aby porównać wyjście z celem. Omówimy je w następnej sekcji.
Autoenkodery to głównie algorytm redukcji wymiarowości (lub kompresji) z kilkoma ważnymi właściwościami:
- specyficzne dla danych: Autoencodery są w stanie tylko w znaczący sposób kompresować dane podobne do tego, na czym zostały przeszkolone. Ponieważ uczą się funkcji specyficznych dla danych treningowych, różnią się od standardowego algorytmu kompresji danych, takiego jak gzip. Nie możemy więc oczekiwać, że autoencoder wyszkolony na odręcznych cyfrach kompresuje zdjęcia krajobrazowe.
- stratny: Wyjście autoencodera nie będzie dokładnie takie samo jak wejście, będzie to bliskie, ale zdegradowane przedstawienie. Jeśli chcesz bezstratnej kompresji, nie są one drogą do zrobienia.
- bez nadzoru: aby wytrenować autoencoder nie musimy robić nic wymyślnego, wystarczy rzucić w niego surowe dane wejściowe. Autoencoderzy są uważani za technikę uczenia się bez nadzoru, ponieważ nie potrzebują wyraźnych etykiet, aby trenować. Ale mówiąc dokładniej, są one sam nadzorowane, ponieważ generują własne etykiety na podstawie danych treningowych.
Architektura
przyjrzyjmy się szczegółom kodera, kodu i dekodera. Zarówno koder, jak i dekoder są w pełni połączonymi sieciami neuronowymi, zasadniczo Ann, które omówiliśmy w części 1. Kod to pojedyncza warstwa ANN o wybranej przez nas wymiarowości. Liczba węzłów w warstwie kodu (rozmiar kodu) jest hiperparametrem, który ustawiamy przed szkoleniem autoencodera.
jest to bardziej szczegółowa wizualizacja autoencodera. Najpierw wejście przechodzi przez koder, który jest w pełni podłączonym ANN, aby wytworzyć kod. Dekoder, który ma podobną strukturę ANN, następnie wytwarza wyjście tylko przy użyciu kodu. Celem jest uzyskanie wyjścia identycznego z wejściem. Zauważ, że architektura dekodera jest lustrzanym odbiciem kodera. Nie jest to wymóg, ale zazwyczaj tak jest. Jedynym wymogiem jest wymiarowość wejścia i wyjścia musi być taka sama. Wszystko w środku można grać.
są 4 hiperparametry, które musimy ustawić przed treningiem autoencodera:
- rozmiar kodu: Liczba węzłów w warstwie środkowej. Mniejszy rozmiar powoduje większą kompresję.
- Liczba warstw: autoencoder może być tak głęboki, jak chcemy. Na powyższym rysunku mamy 2 warstwy zarówno w koderze, jak i dekoderze, bez uwzględnienia wejścia i wyjścia.
- Liczba węzłów na warstwę: Architektura autoencodera, nad którą pracujemy, nazywa się autoencoderem stosowym, ponieważ warstwy są ułożone jedna po drugiej. Zwykle ułożone autoencodery wyglądają jak „sandwitch”. Liczba węzłów na warstwę maleje z każdą kolejną warstwą enkodera i wzrasta z powrotem w dekoderze. Również dekoder jest symetryczny do kodera pod względem struktury warstw. Jak wspomniano powyżej, nie jest to konieczne i mamy całkowitą kontrolę nad tymi parametrami.
- funkcja utraty: używamy błędu średniego kwadratu (MSE) lub crossentropii binarnej. Jeśli wartości wejściowe są w zakresie, to zwykle używamy crossentropii, w przeciwnym razie używamy średniego błędu kwadratowego. Aby uzyskać więcej informacji, sprawdź ten film.
Autoencoders są szkoleni w taki sam sposób jak ANNs poprzez backpropagację. Zapoznaj się z wprowadzeniem części 1, Aby uzyskać więcej informacji na temat szkolenia sieci neuronowych, dotyczy to bezpośrednio autoencoderów.
implementacja
teraz zaimplementujmy autoencoder dla następującej architektury, 1 ukryta warstwa w koderze i dekoderze.
jako dane wejściowe użyjemy niezwykle popularnego zbioru danych MNIST. Zawiera czarno-białe obrazy odręcznych cyfr.
mają rozmiar 28×28 i używamy ich jako wektora 784 liczb pomiędzy . Szczegóły w notatniku jupyter.
teraz zaimplementujemy autoencoder z Kerasem. Hiperparametry to: 128 węzłów w warstwie ukrytej, rozmiar kodu to 32, A crossentropia binarna to funkcja strat.
jest to bardzo podobne do Ann, nad którymi pracowaliśmy, ale teraz używamy funkcjonalnego API Keras. Zapoznaj się z tym przewodnikiem, aby uzyskać szczegółowe informacje, ale oto szybkie porównanie. Wcześniej dodawaliśmy warstwy za pomocą sekwencyjnego API w następujący sposób:
model.add(Dense(16, activation='relu'))
model.add(Dense(8, activation='relu'))
dzięki funkcjonalnemu API robimy to:
layer_1 = Dense(16, activation='relu')(input)
layer_2 = Dense(8, activation='relu')(layer_1)
jest to bardziej gadatliwy, ale bardziej elastyczny sposób definiowania złożonych modeli. Możemy łatwo pobrać części naszego modelu, na przykład tylko dekoder, i pracować z tym. Wyjście metody gęstej jest warstwą wywoływalną, korzystając z funkcjonalnego API dostarczamy mu dane wejściowe i przechowujemy dane wyjściowe. Wyjście warstwy staje się wejściem następnej warstwy. Dzięki sequential API metoda add domyślnie obsłużyła to za nas.
zauważ, że wszystkie warstwy używają funkcji aktywacji relu, ponieważ jest to standard w przypadku głębokich sieci neuronowych. Ostatnia warstwa używa aktywacji esicy, ponieważ potrzebujemy wyjścia pomiędzy . Wejście również znajduje się w tym samym zakresie.
zwróć również uwagę na funkcję call to fit, wcześniej z ANNs robiliśmy:
model.fit(x_train, y_train)
ale teraz mamy:
model.fit(x_train, x_train)
pamiętaj, że cele autoencodera są takie same jak wejście. Dlatego dostarczamy dane treningowe jako cel.
Wizualizacja
teraz wyobraźmy sobie, jak dobrze nasz autoencoder rekonstruuje swoje dane wejściowe.
uruchamiamy autoencoder na zestawie testowym po prostu za pomocą funkcji predict Keras. Dla każdego obrazu w zestawie testowym otrzymujemy wyjście autoencodera. Oczekujemy, że wyjście będzie bardzo podobne do wejścia.
są one rzeczywiście bardzo podobne, ale nie do końca takie same. Wyraźniej możemy to zauważyć w ostatniej cyfrze „4”. Ponieważ było to proste zadanie, nasz autoencoder wykonał całkiem dobrze.
porady
mamy całkowitą kontrolę nad architekturą autoencodera. Możemy uczynić go bardzo potężnym, zwiększając liczbę warstw, węzłów na warstwę i co najważniejsze rozmiar kodu. Zwiększenie tych hiperparametrów pozwoli autoencoderowi nauczyć się bardziej złożonych kodowań. Ale powinniśmy uważać, aby nie uczynić go zbyt potężnym. W przeciwnym razie autoencoder po prostu nauczy się kopiować swoje dane wejściowe na dane wyjściowe, nie ucząc się żadnej znaczącej reprezentacji. Będzie po prostu naśladować funkcję tożsamości. Autoencoder doskonale zrekonstruuje dane treningowe, ale będzie przepełniony, nie mogąc generalizować na nowe instancje, czego nie chcemy.
dlatego preferujemy architekturę „sandwitch” i celowo utrzymujemy mały rozmiar kodu. Ponieważ warstwa kodująca ma mniejszą wymiarowość niż dane wejściowe, mówi się, że autoencoder jest niedokończony. Nie będzie w stanie bezpośrednio skopiować swoich wejść na wyjście i będzie zmuszony nauczyć się inteligentnych funkcji. Jeśli Dane wejściowe mają Wzorzec, na przykład cyfra „1” zwykle zawiera nieco prostą linię, a cyfra „0” jest okrągła, nauczy się tego faktu i zakoduje go w bardziej zwartej formie. Jeśli Dane wejściowe były całkowicie losowe bez żadnej wewnętrznej korelacji lub zależności, wtedy niedompletny autoencoder nie będzie w stanie go idealnie odzyskać. Ale na szczęście w prawdziwym świecie istnieje wiele zależności.
Denoising Autoencoders
utrzymanie małej warstwy kodu zmusiło nasz autoencoder do nauczenia się inteligentnej reprezentacji danych. Istnieje inny sposób, aby zmusić autoencoder do nauczenia się przydatnych funkcji, który dodaje losowy szum do swoich wejść i sprawia, że odzyskuje oryginalne dane bezszumowe. W ten sposób autoencoder nie może po prostu skopiować wejścia na jego wyjście, ponieważ wejście zawiera również losowy szum. Prosimy o odjęcie szumu i wytworzenie istotnych danych. To się nazywa autoencoder denoising.
Górny rząd zawiera oryginalne obrazy. Dodajemy do nich losowy szum Gaussa, a hałaśliwe dane stają się wejściem do autoencodera. Autoencoder w ogóle nie widzi oryginalnego obrazu. Ale oczekujemy, że autoencoder zregeneruje oryginalny obraz bez szumów.
jest tylko jedna mała różnica między implementacją autoencodera denoising a zwykłą. Architektura w ogóle się nie zmienia, tylko funkcja fit. Trenowaliśmy regularny autoencoder w następujący sposób:
autoencoder.fit(x_train, x_train)
Denoising autoencoder jest szkolony jako:
autoencoder.fit(x_train_noisy, x_train)
Wszystko inne jest takie samo. Wejście do autoencodera to głośny obraz, a oczekiwany cel to oryginalny bezszumowy.
Wizualizacja
teraz wyobraźmy sobie, czy jesteśmy w stanie odzyskać obrazy pozbawione szumów.
wygląda całkiem nieźle. Dolny wiersz jest wyjściem autoencodera. Możemy zrobić to lepiej, używając bardziej złożonej architektury autoencodera, takiej jak konwolucyjne autoencodery. Omówimy zawiłości w nadchodzącym artykule.
nieliczne Autoencodery
wprowadziliśmy dwa sposoby wymuszenia na autoencoderze nauki przydatnych funkcji: utrzymanie małego rozmiaru kodu i odcięcie autoencoderów. Trzecia metoda polega na regularyzacji. Możemy regularyzować autoencoder używając ograniczenia sparsity tak, że tylko ułamek węzłów miałby niezerowe wartości, zwane aktywnymi węzłami.
w szczególności dodajemy okres karny do funkcji utraty, tak że tylko ułamek węzłów staje się aktywny. Zmusza to autoencoder do reprezentowania każdego wejścia jako kombinacji małej liczby węzłów i wymaga od niego odkrycia interesującej struktury danych. Ta metoda działa nawet jeśli rozmiar kodu jest duży, ponieważ tylko mały podzbiór węzłów będzie aktywny w dowolnym momencie.
w Kerasie jest to dość łatwe z jednym parametrem. Dla przypomnienia, wcześniej stworzyliśmy warstwę kodu w następujący sposób:
code = Dense(code_size, activation='relu')(input_img)
teraz dodajemy kolejny parametr o nazwie activity_regularizer, określając siłę regularyzacji. Zazwyczaj jest to wartość w zakresie . Tutaj wybraliśmy 10e-6.
code = Dense(code_size, activation='relu', activity_regularizer=l1(10e-6))(input_img)
ostateczna utrata modelu sparse jest o 0,01 wyższa niż standardowy, ze względu na dodatkowy termin regularyzacji.
zademonstrujmy, że kodowania generowane przez model regularyzowany są rzeczywiście rzadkie. Jeśli spojrzymy na histogram wartości kodu dla obrazów w zestawie testowym, rozkład jest następujący:
średnia dla Modelu Standardowego to 6,6, ale dla modelu regularnego to 0,8, dość duża redukcja. Widzimy, że duża część wartości kodu w modelu regularyzowanym to w rzeczywistości 0, czego chcieliśmy. Wariancja modelu regularnego jest również dość niska.
przypadki użycia
teraz możemy zadać następujące pytania. Jak dobre są autoencodery w kompresji wejścia? Czy są one powszechnie stosowaną techniką głębokiego uczenia się?
niestety autoencodery nie są szeroko stosowane w rzeczywistych aplikacjach. Jako metoda kompresji nie działają lepiej niż jej alternatywy, na przykład JPEG robi kompresję zdjęć lepiej niż autoencoder. A fakt, że autoencodery są specyficzne dla danych sprawia, że są niepraktyczne jako ogólna technika. Mają jednak 3 typowe przypadki użycia:
- denoising danych: widzieliśmy tego przykład na zdjęciach.
- redukcja wymiarowości: wizualizacja danych o dużych wymiarach to wyzwanie. t-SNE jest najczęściej stosowaną metodą, ale zmaga się z dużą liczbą wymiarów (zazwyczaj powyżej 32). Tak więc autoenkodery są używane jako etap wstępnego przetwarzania w celu zmniejszenia wymiarowości, a ta skompresowana reprezentacja jest używana przez T-SNE do wizualizacji danych w przestrzeni 2D. Świetne artykuły na temat T-SNE można znaleźć tutaj i tutaj.
- Variational Autoencoders (VAE): jest to bardziej nowoczesny i złożony przypadek użycia autoencoderów i omówimy je w innym artykule. Ale jako szybkie podsumowanie, VAE uczy się parametrów rozkładu prawdopodobieństwa modelowania danych wejściowych, zamiast uczyć się arbitralnej funkcji w przypadku autoenkoderów waniliowych. Przez punkty próbkowania z tego rozkładu możemy również użyć VAE jako modelu generatywnego. Oto dobre odniesienie.
podsumowanie
Autoencodery są bardzo przydatną techniką redukcji wymiarów. Są bardzo popularne jako materiał dydaktyczny na wprowadzających kursach deep learning, najprawdopodobniej ze względu na ich prostotę. W tym artykule omówiliśmy je szczegółowo i mam nadzieję, że ci się podobało.
cały kod tego artykułu jest dostępny tutaj, jeśli chcesz włamać się na nim samodzielnie. Jeśli masz jakieś uwagi, skontaktuj się ze mną na Twitterze.