Autoencoder v TensorFlow s příkladem
⚡ Chytré shrnutí
Autoenkodéry komprimují vstup do menší interní reprezentace a poté ji znovu sestavují, přičemž se učí nejdůležitější vlastnosti bez popisků. Tento návod skládá čtyři husté vrstvy v TensorFlow a rekonstruuje obrázky koní CIFAR-10.
Co je Autoencoder v Deep Learning?
An Autokodér je nástroj pro efektivní učení kódování dat v bez dozoru způsobem. Je to druh umělá neuronová síť který vám pomůže naučit se reprezentaci datových sad pro redukci dimenzionality trénováním neuronové sítě tak, aby ignorovala šum signálu. Je to skvělý nástroj pro znovuvytvoření vstupu.
Jednoduše řečeno, stroj pořídí například obrázek a dokáže vytvořit úzce související obrázek. Vstup do tohoto typu neuronové sítě je neoznačený, což znamená, že se síť dokáže učit bez dozoru. Přesněji řečeno, vstup je síťí kódován tak, aby se zaměřil pouze na nejdůležitější prvek. To je jeden z důvodů, proč je autoenkodér oblíbený pro redukci dimenzionality. Kromě toho lze autoenkodéry použít k vytváření generativních učebních modelů. Neuronová síť může být například trénována se sadou obličejů a poté může vytvářet nové obličeje.
Jak funguje TensorFlow Autoencoder?
Účelem automatického kodéru je vytvořit aproximaci vstupu zaměřením se pouze na základní vlastnosti. Možná vás napadne, proč se jen nenaučit, jak zkopírovat a vložit vstup a vytvořit výstup. Autokodér je ve skutečnosti sada omezení, která nutí síť naučit se nové způsoby reprezentace dat, které se liší od pouhého kopírování výstupu.
Typický autoenkodér je definován vstupem, interní reprezentací a výstupem (aproximací vstupu). Učení probíhá ve vrstvách připojených k interní reprezentaci. Ve skutečnosti existují dva hlavní bloky vrstev, které vypadají jako tradiční neuronová síť. Mírný rozdíl spočívá v tom, že vrstva obsahující výstup musí být stejná jako vstup. Na níže uvedeném diagramu vstupuje původní vstup do prvního bloku nazývaného kodér. Tato interní reprezentace komprimuje (zmenšuje) velikost vstupu. Ve druhém bloku probíhá rekonstrukce vstupu. Toto je fáze dekódování.

Model aktualizuje váhy minimalizací funkce ztráty. Model je penalizován, pokud se výstup rekonstrukce liší od vstupu.
Konkrétně si představte obrázek o velikosti 50×50 (tj. 2 500 pixelů) a neuronovou síť s pouze jednou skrytou vrstvou složenou ze sta neuronů. Učení probíhá na mapě rysů, která je dvacetpětkrát menší než vstup. To znamená, že síť musí najít způsob, jak rekonstruovat 2 500 pixelů s pouze vektorem neuronů rovným 100.
Příklad skládaného automatického kodéru
V tomto tutoriálu o autoenkodéru se naučíte, jak používat vrstvený autoenkodér. Architektura je podobná tradiční neuronové síti. Vstup jde do skryté vrstvy, kde je komprimován nebo zmenšen, a poté se dostane do rekonstrukčních vrstev. Cílem je vytvořit výstupní obraz co nejblíže originálu. Model se musí naučit způsob, jak dosáhnout svého úkolu za určitých omezení, tj. s nižší dimenzí.
V dnešní době se autoenkodéry v hlubokém učení používají hlavně k odšumování obrazu. Představte si obrázek se škrábanci; člověk je stále schopen rozpoznat jeho obsah. Myšlenkou odšumovacího autoenkodéru je přidat k obrazu šum, aby se síť donutila naučit se vzorec za daty.
Další užitečná rodina Autoencoderů Hluboké učení je variační autoenkodér. Tento typ sítě dokáže generovat nové obrazy. Představte si, že trénujete síť s obrazem muže; taková síť dokáže vytvářet nové tváře.
Níže uvedená tabulka umisťuje vrstvený autoenkodér vytvořený v tomto tutoriálu vedle ostatních rodin, se kterými se pravděpodobně setkáte, takže omezení, která každý z nich přidává, je snadné porovnat.
| Typ automatického kodéru | Omezení přidáno | Typické použití |
|---|---|---|
| Neúplné / naskládané | Kódovací vrstva užší než vstup | Redukce rozměrů, prvek extracvání |
| Odšumování | Na vstupu byl přidán šum, cíl čistý | Čištění obrazu a signálu |
| Řídké | Penalizace za počet aktivních jednotek | Interpretovatelné, částečně založené funkce |
| Variační | Kódovací vrstva se učí rozdělení pravděpodobnosti | Generování nových vzorků |
Jak vytvořit automatický kodér s TensorFlow
V tomto tutoriálu se naučíte, jak vytvořit skládaný autokodér pro rekonstrukci obrázku.
Použijete datovou sadu CIFAR-10, která obsahuje 60 000 barevných obrázků o rozměrech 32×32. Datová sada Autoencoder je již rozdělena mezi 50 000 obrázků pro trénování a 10 000 obrázků pro testování. Existuje až deset tříd:
- Letoun
- Automobil
- Pták
- Kočka
- Jelen
- Pes
- Žába
- Kůň
- Loď
- nákladní auto
Obrázky si musíte stáhnout z Stránka datové sady CIFAR-10 a rozbalte archiv. Složka cifar-10-batches-py obsahuje pět dávek dat s 10 000 obrázky v náhodném pořadí.
Než svůj model postavíte a vycvičíte, musíte použít určité zpracování dat. Budete postupovat následovně:
- Importujte data
- Převeďte data do černobílého formátu
- Připojte všechny dávky
- Sestavte trénovací datovou sadu
- Vytvořte vizualizér obrázků
Poznámka k verzi: Kód v tomto tutoriálu je zaměřen na TensorFlow 1.x. V TensorFlow 2 již modul tf.contrib neexistuje a zástupné symboly, relace a inicializovatelný iterátor se nacházejí v souboru tf.compat.v1. Volání tf.compat.v1.disable_v2_behavior() po importu je nejrychlejší způsob, jak spustit výpisy beze změny.
Předzpracování obrazu
Krok 1) Importujte data
Podle oficiálních webových stránek můžete data nahrát pomocí následujícího kódu. Kód Autoencoderu načte data do slovníku s daty a popiskem. Upozorňujeme, že kód je funkce.
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) Převeďte data do černobílého formátu
Pro jednoduchost převedete data do odstínů šedi. To znamená, že pouze jeden rozměr proti třem pro barevný obraz. Většina neuronové sítě pracuje pouze s jednorozměrným vstupem.
def grayscale(im): return im.reshape(im.shape[0], 3, 32, 32).mean(1).reshape(im.shape[0], -1)
Krok 3) Připojte všechny dávky
Nyní, když jsou obě funkce vytvořeny a datová sada načtena, můžete napsat smyčku pro přidávání dat do paměti. Pokud se pečlivě podíváte, rozbalený soubor s daty se jmenuje data_batch_ s číslem od 1 do 5. Můžete procházet soubory a přidávat je k datům.
Po dokončení tohoto kroku převedete barevná data do formátu ve stupních šedi. Jak vidíte, tvar dat je 50000 a 1024. Pixely o rozměrech 32*32 jsou nyní srovnány na 1024.
# 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)
Poznámka: Změňte './cifar-10-batches-py/data_batch_' na skutečné umístění vašeho souboru. Například pro Windows počítači, cesta může být název_souboru = 'E:\cifar-10-batches-py\data_batch_' + str(i)
Krok 4) Vytvořte trénovací datovou sadu
Aby bylo trénování rychlejší a snazší, budete trénovat model pouze na obrázcích koní. Koně nesou v datech označení 7. Jak je uvedeno v dokumentaci k datové sadě CIFAR-10, každá třída obsahuje 5000 obrázků. Můžete vytisknout tvar dat, abyste se ujistili, že existuje 5 000 obrázků s 1024 sloupci, jak je znázorněno v níže uvedeném příkladu TensorFlow Autoencoder.
horse_i = np.where(y == 7)[0]
horse_x = x[horse_i]
print(np.shape(horse_x))
(5000, 1024)
Krok 5) Vytvořte vizualizér obrázků
Nakonec vytvoříte funkci pro vykreslení obrázků. Tuto funkci budete potřebovat pro tisk rekonstruovaného obrázku z autokodéru.
Snadný způsob tisku obrázků je použití funkce imshow() z knihovny Matplotlib. V takovém případě je třeba převést tvar dat z 1024 na 32*32 (tj. formát obrázku).
# 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")
Funkce má 3 argumenty:
- Obrázek: vstup
- Tvar: seznam, rozměr obrázku
- Cmap: vyberte barevnou mapu. Ve výchozím nastavení je šedá.
Můžete zkusit vykreslit první obrázek v datové sadě. Měli byste vidět muže na koni.
plot_image(horse_x[1], shape=[32, 32], cmap = "Greys_r")
Volání vrátí níže zobrazenou miniaturu ve stupních šedi a potvrdí, že změna tvaru z 1024 hodnot zpět na obrázek o rozměrech 32×32 je správná.
Nastavit odhad datové sady
Dobře, nyní, když je datová sada připravena k použití, můžete začít používat TensorFlow. Před vytvořením modelu použijte odhad datové sady TensorFlow k naplnění sítě.
Vytvoříte datovou sadu s odhadem TensorFlow. Chcete-li osvěžit svou mysl, musíte použít:
- z_tensor_slices
- opakovat
- várka
Úplný kód pro sestavení datové sady je:
dataset = tf.data.Dataset.from_tensor_slices(x).repeat().batch(batch_size)
Všimněte si, že x je zástupný symbol ve tvaru [None,n_inputs]. První dimenze je nastavena na None, protože počet obrázků přiváděných do sítě se rovná velikosti dávky, která je určena pouze za běhu. Podrobnosti naleznete v tutoriálu na lineární regrese s TensorFlow.
Poté musíte vytvořit iterátor. Bez tohoto řádku kódu neprojdou potrubím žádná data.
iter = dataset.make_initializable_iterator() # create the iteratorfeatures = iter.get_next()
Nyní, když je potrubí připraveno, můžete zkontrolovat, zda je první obrázek stejný jako předtím (tj. muž na koni).
Velikost dávky nastavíte na 1, protože chcete do datové sady odeslat pouze jeden obrázek. Rozměr dat si můžete prohlédnout pomocí příkazu print(sess.run(features).shape). Je roven (1, 1024). 1 znamená, že pokaždé je odeslán jeden obrázek s 1024 hodnotami. Pokud je velikost dávky nastavena na dva, pak kanálem projdou dva obrázky. Velikost dávky neměňte, jinak dojde k chybě, protože do funkce plot_image() může jít vždy pouze jeden obrázek.
## 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)
Kanál vrací stejný rider, který byl vykreslen přímo z matice NumPy, což dokazuje, že zástupný symbol, iterátor a velikost dávky jsou správně zapojeny.
Vybudujte síť
Je čas vybudovat síť. Budete trénovat skládaný autokodér, tedy síť s více skrytými vrstvami.
Vaše síť bude mít jednu vstupní vrstvu s 1024 body, tj. 32×32, což je tvar obrázku.
Blok kodéru bude mít jednu horní skrytou vrstvu s 300 neurony a centrální vrstvu se 150 neurony. Blok dekodéru je symetrický vzhledem k kodéru. Síť si můžete vizualizovat na níže uvedeném diagramu. Všimněte si, že hodnoty skrytých a centrálních vrstev můžete změnit.
Vytvoření autokodéru je velmi podobné jakémukoli jinému modelu hlubokého učení.
Model vytvoříte podle následujících kroků:
- Definujte parametry
- Definujte vrstvy
- Definujte architekturu
- Definujte optimalizaci
- Spusťte model
- Vyhodnoťte model
V předchozí části jste se naučili, jak vytvořit pipeline pro napájení modelu, takže není nutné znovu vytvářet datovou sadu. Vytvoříte autoenkodér se čtyřmi vrstvami. Použijete Xavierovu inicializaci. Jedná se o techniku pro nastavení počátečních vah podle rozptylu vstupu i výstupu. Nakonec použijete aktivační funkci ELU. Ztrátovou funkci regularizujete pomocí L2 regularizátoru.
Krok 1) Definování parametrů
První krok znamená definovat počet neuronů v každé vrstvě, rychlost učení a hyperparametr regularizátoru.
Předtím importujete parciální funkci. Je to lepší metoda pro definování parametrů hustých vrstev. Níže uvedený kód definuje hodnoty architektury autoencoderu. Jak již bylo uvedeno, kodér má dvě vrstvy, s 300 neurony v první vrstvě a 150 ve druhé vrstvě. Jejich hodnoty jsou uloženy v n_hidden_1 a n_hidden_2.
Je třeba definovat rychlost učení a hyperparametr L2. Hodnoty jsou uloženy v learning_rate a 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 inicializace Xavier se volá s objektem xavier_initializer z estimátoru contrib. Ve stejném estimátoru můžete přidat regularizátor s 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)
Poznámka k verzi: Funkce tf.contrib byla v TensorFlow 2 odstraněna. Přímými náhradami jsou tf.keras.initializers.GlorotUniform() za xavier_initializer() a tf.keras.regularizers.l2() za l2_regularizer().
Krok 2) Definujte vrstvy
Všechny parametry hustých vrstev byly nastaveny; vše můžete zabalit do proměnné dense_layer pomocí objektu partial. dense_layer pak při každém volání použije aktivaci ELU, inicializaci Xaviera a regularizaci 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) Definování architektury
Pokud se podíváte na diagram architektury, všimnete si, že síť skládá tři vrstvy s výstupní vrstvou. V níže uvedeném kódu propojíte příslušné vrstvy. Například první vrstva vypočítá skalární součin mezi vstupními maticovými prvky a maticí obsahující 300 vah. Po výpočtu skalárního součinu jde výstup do aktivační funkce ELU. Výstup se stává vstupem další vrstvy, proto jej používáte k výpočtu hidden_2 atd. Násobení matic je pro každou vrstvu stejné, protože používáte stejnou aktivační funkci. Všimněte si, že poslední vrstva, outputs (výstupy), neaplikuje aktivační funkci. Dává to smysl, protože se jedná o rekonstruovaný vstup.
## 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) Definování optimalizace
Posledním krokem je konstrukce optimalizátoru. Jako ztrátovou funkci použijete střední kvadratickou chybu (MSE). Pokud si vzpomenete na tutoriál o lineární regresi, víte, že MSE se počítá z rozdílu mezi predikovaným výstupem a skutečným popiskem. Zde je popisek rysem, protože model se snaží rekonstruovat vstup. Proto chcete průměr součtu čtverců rozdílu mezi predikovaným výstupem a vstupem. Pomocí TensorFlow můžete ztrátovou funkci naprogramovat následovně:
loss = tf.reduce_mean(tf.square(outputs - features))
Pak je třeba optimalizovat ztrátovou funkci. Pro výpočet gradientů použijete optimalizátor Adam. Cílovou funkcí je minimalizovat ztráty.
## Optimize
loss = tf.reduce_mean(tf.square(outputs - features))
optimizer = tf.train.AdamOptimizer(learning_rate)
train = optimizer.minimize(loss)
Ještě jedno nastavení před tréninkem modelu. Chcete použít velikost dávky 150, to znamená vložit do potrubí 150 obrázků v každé iteraci. Počet iterací musíte vypočítat ručně. Toto je triviální udělat:
Pokud chcete pokaždé předat 150 obrázků a víte, že v datové sadě je 5000 obrázků, počet iterací se rovná 5000 děleno 150. V Python Můžete spustit následující kódy a ujistit se, že výstup je 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) Spusťte model
V neposlední řadě trénujte model. Model trénujete se 100 epochami. To znamená, že model uvidí obrázky 100krát a zároveň optimalizuje váhy.
Již znáte kódy pro trénování modelu v TensorFlow. Mírný rozdíl spočívá v propojení dat před spuštěním trénování. Tímto způsobem se model trénuje rychleji.
Máte zájem vytisknout ztrátu po deseti epochách, abyste viděli, zda se model něco učí (tj. ztráta se snižuje). Školení trvá 2 až 5 minut v závislosti na hardwaru vašeho stroje.
## 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) Vyhodnoťte model
Nyní, když máte model natrénovaný, je čas ho vyhodnotit. Je třeba importovat testovací sadu ze souboru /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'])
Poznámka: Pro Windows stroj, kód se změní na test_data = unpickle(r”E:\cifar-10-batches-py\test_batch”)
Můžete zkusit vytisknout obrázek 13, na kterém je kůň.
plot_image(test_x[13], shape=[32, 32], cmap = "Greys_r")
Graf potvrzuje, že testovací dávka byla načtena správně a že obrázek 13 patří do třídy, na které byl model trénován.
Pro vyhodnocení modelu použijete hodnotu pixelu tohoto obrázku a zjistíte, zda kodér dokáže rekonstruovat stejný obrázek po jeho zmenšení na 1024 pixelů. Všimněte si, že definujete funkci pro vyhodnocení modelu na různých obrázcích. Model by měl fungovat lépe pouze na koních.
Funkce má dva argumenty:
- df: Import testovacích dat
- číslo_obrázku: určuje, který obrázek se má importovat
Funkce je rozdělena do tří částí:
- Změňte tvar obrázku na správný rozměr, tj. 1, 1024
- Naplňte model neviditelným obrázkem, zakódujte/dekódujte obrázek
- Vytiskněte skutečný a rekonstruovaný obrázek
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()
Nyní, když je vyhodnocovací funkce definována, se můžete podívat na rekonstruovaný obrázek číslo třináct.
reconstruct_image(df =test_x, image_number = 13)
INFO:tensorflow:Restoring parameters from ./model.ckpt
Model restored.
(1, 1024)
Obrázek umisťuje původní testovací obraz vlevo a výstup autoencoderu vpravo, takže je snadné posoudit ztrátu jemných detailů po kompresi 1024 na 150.




