Autoenkoder w TensorFlow z przykładem
Co to jest autoenkoder w głębokim uczeniu się?
An Autokoder to narzędzie do efektywnej nauki kodowania danych w sposób bez nadzoru. Jest to rodzaj sztucznej sieci neuronowej, która pomaga nauczyć się reprezentacji zbiorów danych w celu redukcji wymiarowości poprzez uczenie sieci neuronowej ignorowania szumu sygnału. Jest to doskonałe narzędzie do odtwarzania danych wejściowych.
Krótko mówiąc, maszyna wykonuje, powiedzmy, obraz i może wyprodukować obraz ściśle powiązany. Dane wejściowe w tego rodzaju sieci neuronowej nie są oznakowane, co oznacza, że sieć może się uczyć bez nadzoru. Mówiąc dokładniej, dane wejściowe są kodowane przez sieć w celu skupienia się tylko na najbardziej krytycznej funkcji. Jest to jeden z powodów, dla których autoenkoder jest popularny ze względu na redukcję wymiarowości. Poza tym do produkcji można używać autoenkoderów generatywne modele uczenia się. Na przykład sieć neuronową można trenować za pomocą zestawu twarzy, a następnie tworzyć nowe twarze.
Jak działa autoenkoder TensorFlow?
Celem autoenkodera jest uzyskanie przybliżenia danych wejściowych poprzez skupienie się tylko na istotnych cechach. Możesz pomyśleć, dlaczego nie po prostu nauczyć się kopiować i wklejać dane wejściowe, aby uzyskać wynik. W rzeczywistości autoenkoder to zestaw ograniczeń, które zmuszają sieć do uczenia się nowych sposobów reprezentowania danych, innych niż zwykłe kopiowanie danych wyjściowych.
Typowy autoenkoder ma wejście, reprezentację wewnętrzną i wyjście (przybliżenie sygnału wejściowego). Uczenie się odbywa się w warstwach dołączonych do reprezentacji wewnętrznej. W rzeczywistości istnieją dwa główne bloki warstw, które wyglądają jak tradycyjna sieć neuronowa. Niewielka różnica polega na tym, że warstwa zawierająca dane wyjściowe musi być równa wejściu. Na poniższym obrazku oryginalne wejście trafia do pierwszego bloku zwanego koder. Ta wewnętrzna reprezentacja kompresuje (zmniejsza) rozmiar danych wejściowych. W drugim bloku następuje rekonstrukcja wejścia. To jest faza dekodowania.
Model zaktualizuje wagi poprzez minimalizację funkcji straty. Model jest karany, jeśli wynik rekonstrukcji różni się od danych wejściowych.
Konkretnie wyobraźmy sobie obraz o wymiarach 50×50 (tj. 250 pikseli) i sieć neuronową z tylko jedną ukrytą warstwą złożoną ze stu neuronów. Uczenie odbywa się na mapie cech, która jest dwa razy mniejsza niż dane wejściowe. Oznacza to, że sieć musi znaleźć sposób na zrekonstruowanie 250 pikseli przy użyciu jedynie wektora neuronów równego 100.
Przykład skumulowanego autoenkodera
W tym samouczku Autoencoder nauczysz się, jak używać autoencodera skumulowanego. Architektura jest podobna do tradycyjnej sieci neuronowej. Dane wejściowe trafiają do ukrytej warstwy, aby je skompresować lub zmniejszyć ich rozmiar, a następnie docierają do warstw rekonstrukcji. Celem jest wytworzenie obrazu wyjściowego tak bliskiego oryginałowi. Model musi nauczyć się sposobu wykonania swojego zadania przy zachowaniu zestawu ograniczeń, czyli przy niższym wymiarze.
Obecnie autoenkodery w głęboki Learning są używane głównie do odszumiania obrazu. Wyobraź sobie obraz z zadrapaniami; człowiek nadal jest w stanie rozpoznać treść. Pomysł odszumiania autoenkodera polega na dodaniu szumu do obrazu, aby zmusić sieć do poznania wzorca kryjącego się za danymi.
Inną użyteczną rodziną głębokiego uczenia się Autoenkodera jest autoenkoder wariacyjny. Ten typ sieci może generować nowe obrazy. Wyobraź sobie, że trenujesz sieć za pomocą obrazu mężczyzny; taka sieć może stworzyć nowe twarze.
Jak zbudować autoenkoder za pomocą TensorFlow
W tym samouczku dowiesz się, jak zbudować skumulowany autokoder w celu rekonstrukcji obrazu.
Użyjesz Zbiór danych CIFAR-10 który zawiera 60000 kolorowych obrazów 32×32. Zbiór danych Autoenkodera jest już podzielony na 50000 10000 obrazów do trenowania i XNUMX XNUMX do testowania. Istnieje aż dziesięć klas:
- Samolot
- Samochód
- Ptak
- Kot
- Jeleń
- Pies
- żaba
- Koń
- Statek
- Ciężarówka
Musisz pobrać obrazy z tego adresu URL https://www.cs.toronto.edu/~kriz/cifar.html i rozpakować je. Folder for-10-batches-py zawiera pięć partii danych po 10000 obrazów każda w losowej kolejności.
Zanim zbudujesz i wytrenujesz model, musisz zastosować przetwarzanie danych. Będziesz postępować w następujący sposób:
- Importuj dane
- Konwertuj dane do formatu czarno-białego
- Dołącz wszystkie partie
- Skonstruuj zbiór danych szkoleniowych
- Skonstruuj wizualizator obrazu
Wstępne przetwarzanie obrazu
Krok 1) Zaimportuj dane
Według oficjalnej strony internetowej, możesz przesłać dane za pomocą następującego kodu. Kod Autoencodera załaduje dane do słownika za pomocą dane i etykieta. Należy pamiętać, że kod jest funkcją.
import numpy as np import tensorflow as tf import pickle def unpickle(file): import pickle with open(file, 'rb') as fo: dict = pickle.load(fo, encoding='latin1') return dict
Krok 2) Konwertuj dane na format czarno-biały
Dla uproszczenia skonwertujesz dane do skali szarości. Oznacza to, że tylko jeden wymiar w porównaniu z trzema dla obrazu kolorów. Większość sieci neuronowych działa tylko z wejściem jednego wymiaru.
def grayscale(im): return im.reshape(im.shape[0], 3, 32, 32).mean(1).reshape(im.shape[0], -1)
Krok 3) Dołącz wszystkie partie
Teraz, gdy obie funkcje są już utworzone i załadowany jest zbiór danych, możesz napisać pętlę, która dołączy dane do pamięci. Jeśli sprawdzisz dokładnie, rozpakowany plik z danymi będzie nosił nazwę data_batch_ z liczbą od 1 do 5. Możesz przeglądać pliki w pętli i dołączać je do danych.
Po wykonaniu tego kroku dane dotyczące kolorów zostaną przekonwertowane na format skali szarości. Jak widać, kształt danych wynosi 50000 i 1024. Piksele 32*32 są teraz spłaszczone do roku 2014.
# Load the data into memory data, labels = [], [] ## Loop over the b for i in range(1, 6): filename = './cifar-10-batches-py/data_batch_' + str(i) open_data = unpickle(filename) if len(data) > 0: data = np.vstack((data, open_data['data'])) labels = np.hstack((labels, open_data['labels'])) else: data = open_data['data'] labels = open_data['labels'] data = grayscale(data) x = np.matrix(data) y = np.array(labels) print(x.shape) (50000, 1024)
Uwaga: Zmień „./cifar-10-batches-py/data_batch_” na rzeczywistą lokalizację pliku. Na przykład dla Windows maszynie, ścieżka może mieć postać filename = 'E:\cifar-10-batches-py\data_batch_' + str(i)
Krok 4) Skonstruuj zbiór danych uczących
Aby trening był szybszy i łatwiejszy, będziesz trenował modela wyłącznie na obrazach koni. Konie stanowią siódmą klasę w danych na etykiecie. Jak wspomniano w dokumentacji zbioru danych CIFAR-10, każda klasa zawiera 5000 obrazów. Możesz wydrukować kształt danych, aby potwierdzić, że istnieje 5.000 obrazów z 1024 kolumnami, jak pokazano poniżej TensorFlow Przykładowy krok autoenkodera.
horse_i = np.where(y == 7)[0] horse_x = x[horse_i] print(np.shape(horse_x)) (5000, 1024)
Krok 5) Skonstruuj wizualizator obrazu
Na koniec konstruujesz funkcję, która wykreśla obrazy. Ta funkcja będzie potrzebna do wydrukowania zrekonstruowanego obrazu z autoenkodera.
Łatwym sposobem drukowania obrazów jest użycie obiektu imshow z biblioteki matplotlib. Pamiętaj, że musisz przekonwertować kształt danych z 1024 na 32*32 (tj. format obrazu).
# To plot pretty figures %matplotlib inline import matplotlib import matplotlib.pyplot as plt def plot_image(image, shape=[32, 32], cmap = "Greys_r"): plt.imshow(image.reshape(shape), cmap=cmap,interpolation="nearest") plt.axis("off")
Funkcja przyjmuje 3 argumenty:
- Obraz: wejście
- Shape: lista, wymiar obrazu
- Mapa:wybierz mapę kolorów. Domyślnie szary
Możesz spróbować wykreślić pierwszy obraz w zestawie danych. Powinieneś zobaczyć mężczyznę na koniu.
plot_image(horse_x[1], shape=[32, 32], cmap = "Greys_r")
Ustaw estymator zbioru danych
W porządku, teraz, gdy zbiór danych jest gotowy do użycia, możesz zacząć korzystać z Tensorflow. Przed zbudowaniem modelu użyjmy estymatora zestawu danych Tensorflow do zasilania sieci.
Zbudujesz zbiór danych za pomocą estymatora TensorFlow. Aby odświeżyć umysł, musisz użyć:
- from_tensor_slices
- powtarzać
- partia
Pełny kod do zbudowania zbioru danych to:
dataset = tf.data.Dataset.from_tensor_slices(x).repeat().batch(batch_size)
Należy pamiętać, że x jest symbolem zastępczym o następującym kształcie:
- [Brak, n_wejść]: Ustaw na Brak, ponieważ liczba obrazów przesyłanych do sieci jest równa wielkości partii.
Aby uzyskać szczegółowe informacje, zapoznaj się z samouczkiem regresja liniowa.
Następnie musisz utworzyć iterator. Bez tego wiersza kodu żadne dane nie zostaną przesłane przez potok.
iter = dataset.make_initializable_iterator() # create the iteratorfeatures = iter.get_next()
Teraz, gdy rurociąg jest już gotowy, możesz sprawdzić, czy pierwszy obraz jest taki sam jak poprzednio (tj. mężczyzna na koniu).
Ustawiłeś rozmiar partii na 1, ponieważ chcesz zasilić zestaw danych tylko jednym obrazem. Możesz zobaczyć wymiary danych za pomocą print(sess.run(features).shape). Jest on równy (1, 1024). 1 oznacza, że tylko jeden obraz z 1024 jest zasilony. Jeśli rozmiar partii jest ustawiony na dwa, to przez potok przejdą dwa obrazy. (Nie zmieniaj rozmiaru partii. W przeciwnym razie zostanie zgłoszony błąd. Tylko jeden obraz na raz może trafić do funkcji plot_image().
## Parameters n_inputs = 32 * 32 BATCH_SIZE = 1 batch_size = tf.placeholder(tf.int64) # using a placeholder x = tf.placeholder(tf.float32, shape=[None,n_inputs]) ## Dataset dataset = tf.data.Dataset.from_tensor_slices(x).repeat().batch(batch_size) iter = dataset.make_initializable_iterator() # create the iterator features = iter.get_next() ## Print the image with tf.Session() as sess: # feed the placeholder with data sess.run(iter.initializer, feed_dict={x: horse_x, batch_size: BATCH_SIZE}) print(sess.run(features).shape) plot_image(sess.run(features), shape=[32, 32], cmap = "Greys_r") (1, 1024)
Zbuduj sieć
Nadszedł czas na budowę sieci. Będziesz trenować skumulowany autoenkoder, czyli sieć z wieloma ukrytymi warstwami.
Twoja sieć będzie miała jedną warstwę wejściową zawierającą 1024 punkty, tj. kształt obrazu 32×32.
Blok kodera będzie miał jedną górną warstwę ukrytą zawierającą 300 neuronów i warstwę centralną zawierającą 150 neuronów. Blok dekodera jest symetryczny względem kodera. Sieć można zwizualizować na poniższym obrazku. Pamiętaj, że możesz zmienić wartości warstw ukrytych i środkowych.
Budowanie autoenkodera jest bardzo podobne do każdego innego modelu głębokiego uczenia się.
Model zbudujesz, wykonując następujące kroki:
- Zdefiniuj parametry
- Zdefiniuj warstwy
- Zdefiniuj architekturę
- Zdefiniuj optymalizację
- Uruchom model
- Oceń model
W poprzedniej sekcji nauczyłeś się, jak utworzyć potok zasilający model, więc nie ma potrzeby ponownego tworzenia zbioru danych. Skonstruujesz autoenkoder z czterema warstwami. Używasz inicjalizacji Xaviera. Jest to technika polegająca na ustaleniu początkowych wag równych wariancji zarówno danych wejściowych, jak i wyjściowych. Na koniec użyj funkcji aktywacji elu. Regularyzujesz funkcję straty za pomocą regularyzatora L2.
Krok 1) Zdefiniuj parametry
Pierwszy krok polega na zdefiniowaniu liczby neuronów w każdej warstwie, szybkości uczenia się i hiperparametru regularyzatora.
Przedtem importujesz funkcję częściowo. Jest to lepsza metoda definiowania parametrów gęstych warstw. Poniższy kod definiuje wartości architektury autoenkodera. Jak wspomniano wcześniej, autoenkoder ma dwie warstwy, z 300 neuronami w pierwszej warstwie i 150 w drugiej warstwie. Ich wartości są przechowywane w n_hidden_1 i n_hidden_2.
Musisz zdefiniować szybkość uczenia się i hiperparametr L2. Wartości są przechowywane w learning_rate i l2_reg
from functools import partial ## Encoder n_hidden_1 = 300 n_hidden_2 = 150 # codings ## Decoder n_hidden_3 = n_hidden_1 n_outputs = n_inputs learning_rate = 0.01 l2_reg = 0.0001
Technika inicjalizacji Xaviera jest wywoływana z obiektem xavier_initializer z estymatora contrib. W tym samym estymatorze możesz dodać regularyzator za pomocą l2_regularizer
## Define the Xavier initialization xav_init = tf.contrib.layers.xavier_initializer() ## Define the L2 regularizer l2_regularizer = tf.contrib.layers.l2_regularizer(l2_reg)
Krok 2) Zdefiniuj warstwy
Ustawiono wszystkie parametry gęstych warstw; możesz spakować wszystko do zmiennej gęstej_warstwy, używając obiektu częściowego. gęsty_warstwa, który wykorzystuje aktywację ELU, inicjalizację Xaviera i regularyzację L2.
## Create the dense layer dense_layer = partial(tf.layers.dense, activation=tf.nn.elu, kernel_initializer=xav_init, kernel_regularizer=l2_regularizer)
Krok 3) Zdefiniuj architekturę
Jeśli spojrzysz na zdjęcie architektury, zauważysz, że sieć układa trzy warstwy z warstwą wyjściową. W poniższym kodzie łączysz odpowiednie warstwy. Na przykład pierwsza warstwa oblicza iloczyn skalarny między cechami macierzy wejściowych i macierzami zawierającymi 300 wag. Po obliczeniu iloczynu skalarnego dane wyjściowe trafiają do funkcji aktywacji Elu. Dane wyjściowe stają się danymi wejściowymi następnej warstwy, dlatego używasz ich do obliczenia hidden_2 itd. Mnożenie macierzy jest takie samo dla każdej warstwy, ponieważ używasz tej samej funkcji aktywacji. Zauważ, że ostatnia warstwa, wyjściowa, nie stosuje funkcji aktywacji. Ma to sens, ponieważ jest to zrekonstruowane dane wejściowe.
## Make the mat mul hidden_1 = dense_layer(features, n_hidden_1) hidden_2 = dense_layer(hidden_1, n_hidden_2) hidden_3 = dense_layer(hidden_2, n_hidden_3) outputs = dense_layer(hidden_3, n_outputs, activation=None)
Krok 4) Zdefiniuj optymalizację
Ostatnim krokiem jest skonstruowanie optymalizatora. Używasz błędu średniokwadratowego jako funkcji straty. Jeśli pamiętasz samouczek dotyczący regresji liniowej, wiesz, że MSE jest obliczane na podstawie różnicy między przewidywanym wynikiem a rzeczywistą etykietą. W tym przypadku etykieta jest cechą, ponieważ model próbuje zrekonstruować dane wejściowe. Dlatego potrzebna jest średnia sumy różnicy kwadratów między przewidywanymi wynikami i danymi wejściowymi. Za pomocą TensorFlow możesz zakodować funkcję straty w następujący sposób:
loss = tf.reduce_mean(tf.square(outputs - features))
Następnie należy zoptymalizować funkcję straty. Do obliczania gradientów używasz optymalizatora Adama. Funkcja celu to minimalizacja straty.
## Optimize loss = tf.reduce_mean(tf.square(outputs - features)) optimizer = tf.train.AdamOptimizer(learning_rate) train = optimizer.minimize(loss)
Jeszcze jedno ustawienie przed trenowaniem modelu. Chcesz użyć partii o rozmiarze 150, czyli zasilić potok 150 obrazami w każdej iteracji. Należy ręcznie obliczyć liczbę iteracji. Jest to banalne:
Jeśli chcesz przekazać 150 obrazów za każdym razem i wiesz, że w zestawie danych jest 5000 obrazów, liczba iteracji jest równa . W Pythonie możesz uruchomić następujące kody i upewnić się, że wynik wynosi 33:
BATCH_SIZE = 150 ### Number of batches : length dataset / batch size n_batches = horse_x.shape[0] // BATCH_SIZE print(n_batches) 33
Krok 5) Uruchom model
Na koniec należy wytrenować model. Trenujesz model za pomocą 100 epok. Oznacza to, że model zobaczy 100 razy więcej obrazów przy zoptymalizowanych wagach.
Znasz już kody do uczenia modelu w Tensorflow. Niewielka różnica polega na przesłaniu danych przed uruchomieniem szkolenia. W ten sposób model trenuje szybciej.
Interesuje Cię wydrukowanie straty po dziesięciu epokach, aby sprawdzić, czy model się czegoś uczy (tj. strata maleje). Szkolenie trwa od 2 do 5 minut, w zależności od sprzętu maszyny.
## Set params n_epochs = 100 ## Call Saver to save the model and re-use it later during evaluation saver = tf.train.Saver() with tf.Session() as sess: sess.run(tf.global_variables_initializer()) # initialise iterator with train data sess.run(iter.initializer, feed_dict={x: horse_x, batch_size: BATCH_SIZE}) print('Training...') print(sess.run(features).shape) for epoch in range(n_epochs): for iteration in range(n_batches): sess.run(train) if epoch % 10 == 0: loss_train = loss.eval() # not shown print("\r{}".format(epoch), "Train MSE:", loss_train) #saver.save(sess, "./my_model_all_layers.ckpt") save_path = saver.save(sess, "./model.ckpt") print("Model saved in path: %s" % save_path) Training... (150, 1024) 0 Train MSE: 2934.455 10 Train MSE: 1672.676 20 Train MSE: 1514.709 30 Train MSE: 1404.3118 40 Train MSE: 1425.058 50 Train MSE: 1479.0631 60 Train MSE: 1609.5259 70 Train MSE: 1482.3223 80 Train MSE: 1445.7035 90 Train MSE: 1453.8597 Model saved in path: ./model.ckpt
Krok 6) Oceń model
Teraz, gdy masz już wyszkolony model, czas go ocenić. Musisz zaimportować zestaw testowy z pliku /cifar-10-batches-py/.
test_data = unpickle('./cifar-10-batches-py/test_batch') test_x = grayscale(test_data['data']) #test_labels = np.array(test_data['labels'])
UWAGA: Dla Windows maszynie, kod staje się test_data = unpickle(r”E:\cifar-10-batches-py\test_batch”)
Możesz spróbować wydrukować obrazki 13, które przedstawiają konia
plot_image(test_x[13], shape=[32, 32], cmap = "Greys_r")
Aby ocenić model, użyjesz wartości pikseli tego obrazu i sprawdzisz, czy koder może zrekonstruować ten sam obraz po zmniejszeniu o 1024 piksele. Pamiętaj, że definiujesz funkcję do oceny modelu na różnych obrazach. Model powinien lepiej działać tylko na koniach.
Funkcja przyjmuje dwa argumenty:
- df: Importuj dane testowe
- numer_obrazu: wskaż, który obraz ma zostać zaimportowany
Funkcja jest podzielona na trzy części:
- Zmień kształt obrazu do prawidłowego wymiaru, tj. 1, 1024
- Nakarm model niewidzialnym obrazem, zakoduj/dekoduj obraz
- Wydrukuj obraz rzeczywisty i zrekonstruowany
def reconstruct_image(df, image_number = 1): ## Part 1: Reshape the image to the correct dimension i.e 1, 1024 x_test = df[image_number] x_test_1 = x_test.reshape((1, 32*32)) ## Part 2: Feed the model with the unseen image, encode/decode the image with tf.Session() as sess: sess.run(tf.global_variables_initializer()) sess.run(iter.initializer, feed_dict={x: x_test_1, batch_size: 1}) ## Part 3: Print the real and reconstructed image # Restore variables from disk. saver.restore(sess, "./model.ckpt") print("Model restored.") # Reconstruct image outputs_val = outputs.eval() print(outputs_val.shape) fig = plt.figure() # Plot real ax1 = fig.add_subplot(121) plot_image(x_test_1, shape=[32, 32], cmap = "Greys_r") # Plot estimated ax2 = fig.add_subplot(122) plot_image(outputs_val, shape=[32, 32], cmap = "Greys_r") plt.tight_layout() fig = plt.gcf()
Teraz, gdy funkcja oceny jest zdefiniowana, możesz przyjrzeć się zrekonstruowanemu obrazowi numer trzynaście
reconstruct_image(df =test_x, image_number = 13)
INFO:tensorflow:Restoring parameters from ./model.ckpt Model restored. (1, 1024)
Podsumowanie
- Podstawowym celem autoenkodera jest kompresja danych wejściowych, a następnie dekompresja ich do postaci wyjściowej, która wygląda bardzo podobnie do oryginalnych danych.
- Architektura autoenkodera jest symetryczna i posiada warstwę bazową zwaną warstwą centralną.
- Możesz utworzyć autoenkoder za pomocą:
Częściowa: aby utworzyć gęste warstwy przy typowym ustawieniu:
tf.layers.dense, activation=tf.nn.elu, kernel_initializer=xav_init, kernel_regularizer=l2_regularizer
gęsta_warstwa(): aby wykonać mnożenie macierzy
loss = tf.reduce_mean(tf.square(outputs - features)) optimizer = tf.train.AdamOptimizer(learning_rate) train = optimizer.minimize(loss)