Autoencoder în TensorFlow cu Exemplu
⚡ Rezumat inteligent
Autoencoderele comprimă o intrare într-o reprezentare internă mai mică și apoi o reconstruiesc, învățând cele mai importante caracteristici fără etichete. Această demonstrație suprapune patru straturi dense în TensorFlow și reconstruiește imaginile de cai CIFAR-10.
Ce este Autoencoder în Deep Learning?
An Autocoder este un instrument pentru învățarea eficientă a codării datelor într-un nesupravegheați mod. Este un tip de retele neuronale artificiale care te ajută să înveți reprezentarea seturilor de date pentru reducerea dimensionalității prin antrenarea rețelei neuronale să ignore zgomotul semnalului. Este un instrument excelent pentru recrearea unei intrări.
În cuvinte simple, mașina preia, să zicem, o imagine și poate produce o imagine strâns legată. Intrarea în acest tip de rețea neuronală nu este etichetată, ceea ce înseamnă că rețeaua este capabilă să învețe fără supraveghere. Mai precis, intrarea este codificată de rețea pentru a se concentra doar pe cea mai critică caracteristică. Acesta este unul dintre motivele pentru care autoencoderele sunt populare pentru reducerea dimensionalității. În plus, autoencoderele pot fi utilizate pentru a produce modele de învățare generativă. De exemplu, rețeaua neuronală poate fi antrenată cu un set de fețe și apoi poate produce fețe noi.
Cum funcționează TensorFlow Autoencoder?
Scopul unui autoencoder este de a produce o aproximare a intrării concentrându-se doar pe caracteristicile esențiale. Vă puteți gândi de ce să nu învățați pur și simplu cum să copiați și să lipiți intrarea pentru a produce rezultatul. De fapt, un autoencoder este un set de constrângeri care forțează rețeaua să învețe noi moduri de a reprezenta datele, diferite de simpla copiere a ieșirii.
Un autoencoder tipic este definit cu o intrare, o reprezentare internă și o ieșire (o aproximare a intrării). Învățarea are loc în straturile atașate reprezentării interne. De fapt, există două blocuri principale de straturi care arată ca o rețea neuronală tradițională. Mica diferență este că stratul care conține ieșirea trebuie să fie egal cu intrarea. În diagrama de mai jos, intrarea originală intră în primul bloc numit codificator. Această reprezentare internă comprimă (reduce) dimensiunea intrării. În al doilea bloc are loc reconstrucția intrării. Aceasta este faza de decodare.

Modelul va actualiza greutățile reducând la minimum funcția de pierdere. Modelul este penalizat dacă rezultatul de reconstrucție este diferit de intrare.
Concret, imaginați-vă o imagine cu dimensiunea de 50×50 (adică 2,500 de pixeli) și o rețea neuronală cu un singur strat ascuns compus din o sută de neuroni. Învățarea se face pe o hartă a caracteristicilor care este de douăzeci și cinci de ori mai mică decât datele de intrare. Aceasta înseamnă că rețeaua trebuie să găsească o modalitate de a reconstrui 2,500 de pixeli cu un singur vector de neuroni egal cu 100.
Exemplu de codificare automată stivuită
În acest tutorial despre Autoencoder, veți învăța cum să utilizați un autoencoder suprapus. Arhitectura este similară cu o rețea neuronală tradițională. Datele de intrare merg către un strat ascuns pentru a fi comprimate sau pentru a-i reduce dimensiunea, apoi ajung la straturile de reconstrucție. Obiectivul este de a produce o imagine de ieșire cât mai apropiată de original. Modelul trebuie să învețe o modalitate de a-și îndeplini sarcina sub un set de constrângeri, adică cu o dimensiune mai mică.
În zilele noastre, autoencoderele din Deep Learning sunt folosite în principal pentru a elimina zgomotul dintr-o imagine. Imaginați-vă o imagine cu zgârieturi; un om este încă capabil să recunoască conținutul. Ideea eliminării zgomotului prin autoencoder este de a adăuga zgomot imaginii pentru a forța rețeaua să învețe modelul din spatele datelor.
Cealaltă familie utilă de Autoencodere Invatare profunda este un autoencoder variațional. Acest tip de rețea poate genera imagini noi. Imaginați-vă că antrenați o rețea cu imaginea unui bărbat; o astfel de rețea poate produce fețe noi.
Tabelul de mai jos plasează autoencoderul suprapus construit în acest tutorial lângă alte familii pe care este posibil să le întâlniți, astfel încât constrângerea pe care o adaugă fiecare este ușor de comparat.
| Tipul de autoencoder | Constrângere adăugată | Utilizare tipică |
|---|---|---|
| Subcomplet / suprapus | Stratul de codare mai îngust decât intrarea | Reducerea dimensionalității, exemplu de caracteristicătracTION |
| Dezgomot | Zgomot adăugat la intrare, țintă curată | Curățarea imaginii și a semnalului |
| Rară | Penalizare pentru numărul de unități active | Caracteristici interpretabile, bazate pe părți |
| Variațională | Stratul de codare învață o distribuție de probabilitate | Generarea de noi mostre |
Cum să construiți un codificator automat cu TensorFlow
În acest tutorial, veți învăța cum să construiți un autoencoder stivuit pentru a reconstrui o imagine.
Veți utiliza setul de date CIFAR-10, care conține 60000 de imagini color de 32×32. Setul de date Autoencoder este deja împărțit în 50000 de imagini pentru antrenament și 10000 pentru testare. Există până la zece clase:
- Avion
- Auto
- Pasăre
- Pisica
- Cerb
- Câine
- Broască
- Cal
- Navă
- Camion
Trebuie să descărcați imaginile de pe Pagina setului de date CIFAR-10 și dezarhivați arhiva. Folderul cifar-10-batches-py conține cinci seturi de date cu câte 10000 de imagini fiecare, în ordine aleatorie.
Înainte de a vă construi și antrena modelul, trebuie să aplicați o anumită prelucrare a datelor. Veți proceda după cum urmează:
- Importă datele
- Convertiți datele în format alb-negru
- Adăugați toate loturile
- Construiți setul de date de antrenament
- Construiți un vizualizator de imagine
Notă privind versiunea: Codul din acest tutorial vizează TensorFlow 1.x. Pe TensorFlow 2, modulul tf.contrib nu mai există, iar substituenții, sesiunile și iteratorul inițializabil se află sub tf.compat.v1. Apelarea funcției tf.compat.v1.disable_v2_behavior() după import este cea mai rapidă modalitate de a rula listările neschimbate.
Preprocesarea imaginii
Pasul 1) Importați datele
Conform site-ului oficial, puteți încărca datele cu următorul cod. Codul Autoencoder va încărca datele într-un dicționar cu datele și eticheta. Rețineți că codul este o funcție.
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
Pasul 2) Convertiți datele în format alb-negru
Pentru simplitate, veți converti datele în tonuri de gri. Adică, cu o singură dimensiune față de trei pentru imaginea în culori. Majoritatea rețelei neuronale funcționează doar cu o intrare de dimensiune.
def grayscale(im): return im.reshape(im.shape[0], 3, 32, 32).mean(1).reshape(im.shape[0], -1)
Pasul 3) Adăugați toate loturile
Acum, că ambele funcții sunt create și setul de date este încărcat, puteți scrie o buclă pentru a adăuga datele în memorie. Dacă verificați cu atenție, fișierul dezarhivat cu datele se numește data_batch_ cu un număr de la 1 la 5. Puteți parcurge fișierele și le puteți adăuga la data.
După finalizarea acestui pas, convertiți datele de culoare într-un format de tonuri de gri. După cum puteți vedea, forma datelor este 50000 și 1024. Cei 32*32 pixeli sunt acum aplatizați la 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)
Notă: Schimbați „./cifar-10-batches-py/data_batch_” cu locația reală a fișierului. De exemplu, pentru un Windows mașină, calea ar putea fi nume de fișier = „E:\cifar-10-batches-py\data_batch_” + str(i)
Pasul 4) Construiți setul de date de antrenament
Pentru a face antrenamentul mai rapid și mai ușor, veți antrena un model doar pe baza imaginilor cu cai. Caii poartă eticheta 7 în datele etichetei. Așa cum se menționează în documentația setului de date CIFAR-10, fiecare clasă conține 5000 de imagini. Puteți imprima forma datelor pentru a confirma că există 5,000 de imagini cu 1024 de coloane, așa cum se arată în pasul exemplu de mai jos pentru TensorFlow Autoencoder.
horse_i = np.where(y == 7)[0]
horse_x = x[horse_i]
print(np.shape(horse_x))
(5000, 1024)
Pasul 5) Construiți un vizualizator de imagine
În cele din urmă, construiți o funcție pentru a reprezenta imaginile. Veți avea nevoie de această funcție pentru a imprima imaginea reconstruită din autoencoder.
O modalitate ușoară de a imprima imagini este să utilizați funcția imshow() din biblioteca Matplotlib. Rețineți că trebuie să convertiți forma datelor de la 1024 la 32*32 (adică formatul unei imagini).
# 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")
Funcția ia 3 argumente:
- Imagine: intrarea
- Formă: listă, dimensiunea imaginii
- Cmap: alegeți harta de culori. În mod implicit, gri
Puteți încerca să trasați prima imagine din setul de date. Ar trebui să vezi un bărbat pe cal.
plot_image(horse_x[1], shape=[32, 32], cmap = "Greys_r")
Apelul returnează miniatura în tonuri de gri de mai jos și confirmă că remodelarea de la 1024 de valori înapoi la o imagine de 32×32 este corectă.
Setați estimatorul setului de date
Bine, acum că setul de date este gata de utilizare, puteți începe să utilizați TensorFlow. Înainte de a construi modelul, utilizați estimatorul de seturi de date al TensorFlow pentru a alimenta rețeaua.
Veți construi un set de date cu estimatorul TensorFlow. Pentru a vă împrospăta mintea, trebuie să utilizați:
- din_slice_tensor
- repeta
- lot
Codul complet pentru construirea setului de date este:
dataset = tf.data.Dataset.from_tensor_slices(x).repeat().batch(batch_size)
Rețineți că x are forma unui provizoriu [None,n_inputs]. Prima dimensiune este setată la None deoarece numărul de imagini introduse în rețea este egal cu dimensiunea lotului, care este decisă doar la momentul execuției. Pentru detalii, vă rugăm să consultați tutorialul despre regresie liniară cu TensorFlow.
După aceea, trebuie să creați iteratorul. Fără această linie de cod, nicio dată nu va trece prin conductă.
iter = dataset.make_initializable_iterator() # create the iteratorfeatures = iter.get_next()
Acum că conducta este gata, puteți verifica dacă prima imagine este aceeași ca înainte (adică, un bărbat pe cal).
Ai setat dimensiunea lotului la 1 deoarece vrei să alimentezi setul de date cu o singură imagine. Poți vedea dimensiunea datelor cu print(sess.run(features).shape). Aceasta este egală cu (1, 1024). Valoarea 1 înseamnă că de fiecare dată se alimentează o singură imagine cu 1024 de valori. Dacă dimensiunea lotului este setată la două, atunci două imagini vor trece prin pipeline. Nu modifică dimensiunea lotului, altfel va genera o eroare, deoarece doar o imagine poate ajunge la funcția 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)
Canalul returnează același rider care a fost reprezentat grafic direct din matricea NumPy, ceea ce dovedește că substituentul, iteratorul și dimensiunea lotului sunt conectate corect.
Construiește rețeaua
Este timpul să construim rețeaua. Veți antrena un autoencoder stivuit, adică o rețea cu mai multe straturi ascunse.
Rețeaua ta va avea un strat de intrare cu 1024 de puncte, adică 32×32, forma imaginii.
Blocul de codificare va avea un strat ascuns superior cu 300 de neuroni și un strat central cu 150 de neuroni. Blocul decodificator este simetric față de codificator. Puteți vizualiza rețeaua în diagrama de mai jos. Rețineți că puteți modifica valorile straturilor ascunse și centrale.
Construirea unui autoencoder este foarte asemănătoare cu orice alt model de deep learning.
Veți construi modelul urmând acești pași:
- Definiți parametrii
- Definiți straturile
- Definiți arhitectura
- Definiți optimizarea
- Rulați modelul
- Evaluați modelul
În secțiunea anterioară, ați învățat cum să creați o conductă pentru a alimenta modelul, astfel încât nu este nevoie să creați din nou setul de date. Veți construi un autoencoder cu patru straturi. Veți utiliza inițializarea Xavier. Aceasta este o tehnică de setare a ponderilor inițiale în funcție de varianța atât a intrării, cât și a ieșirii. În cele din urmă, utilizați funcția de activare ELU. Regularizați funcția de pierdere cu un regularizator L2.
Pasul 1) Definiți parametrii
Primul pas presupune definirea numărului de neuroni din fiecare strat, a ratei de învățare și a hiperparametrului regulatorului.
Înainte de asta, importați funcția parțială. Este o metodă mai bună pentru a defini parametrii straturilor dense. Codul de mai jos definește valorile arhitecturii autoencoderului. Așa cum s-a menționat anterior, codificatorul are două straturi, cu 300 de neuroni în primul strat și 150 în al doilea strat. Valorile lor sunt stocate în n_hidden_1 și n_hidden_2.
Trebuie să definiți rata de învățare și hiperparametrul L2. Valorile sunt stocate în 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
Tehnica de inițializare Xavier este apelată cu obiectul xavier_initializer din estimatorul contrib. În același estimator, puteți adăuga regularizatorul cu 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)
Notă privind versiunea: `tf.contrib` a fost eliminat în TensorFlow 2. Înlocuitorii direcți sunt `tf.keras.initializers.GlorotUniform()` pentru `xavier_initializer()` și `tf.keras.regularizers.l2()` pentru `l2_regularizer().
Pasul 2) Definiți straturile
Toți parametrii straturilor dense au fost setați; puteți include totul în variabila dense_layer folosind obiectul partial. dense_layer folosește apoi activarea ELU, inițializarea Xavier și regularizarea L2 la fiecare apel.
## Create the dense layer
dense_layer = partial(tf.layers.dense,
activation=tf.nn.elu,
kernel_initializer=xav_init,
kernel_regularizer=l2_regularizer)
Pasul 3) Definiți arhitectura
Dacă vă uitați la diagrama arhitecturii, observați că rețeaua stivuiește trei straturi cu un strat de ieșire. În codul de mai jos, conectați straturile corespunzătoare. De exemplu, primul strat calculează produsul scalar dintre caracteristicile matricei de intrare și matricea care conține cele 300 de ponderi. După ce produsul scalar este calculat, ieșirea merge la funcția de activare ELU. Ieșirea devine intrarea următorului strat, de aceea o utilizați pentru a calcula hidden_2 și așa mai departe. Înmulțirea matricei este aceeași pentru fiecare strat, deoarece utilizați aceeași funcție de activare. Rețineți că ultimul strat, outputs (ieșiri), nu aplică o funcție de activare. Are sens, deoarece aceasta este intrarea reconstruită.
## 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)
Pasul 4) Definiți optimizarea
Ultimul pas este construirea optimizatorului. Folosești Eroarea Pătratică Medie ca funcție de pierdere. Dacă îți amintești tutorialul despre regresia liniară, știi că MSE este calculată cu diferența dintre ieșirea prezisă și eticheta reală. Aici, eticheta este caracteristica deoarece modelul încearcă să reconstruiască intrarea. Prin urmare, dorești media sumei diferenței la pătrat dintre ieșirea prezisă și intrare. Cu TensorFlow, poți codifica funcția de pierdere după cum urmează:
loss = tf.reduce_mean(tf.square(outputs - features))
Apoi, trebuie să optimizați funcția de pierdere. Folosiți optimizatorul Adam pentru a calcula gradienții. Funcția obiectiv este de a minimiza pierderea.
## Optimize
loss = tf.reduce_mean(tf.square(outputs - features))
optimizer = tf.train.AdamOptimizer(learning_rate)
train = optimizer.minimize(loss)
Încă o setare înainte de antrenamentul modelului. Doriți să utilizați o dimensiune de lot de 150, adică să alimentați conducta cu 150 de imagini la fiecare iterație. Trebuie să calculați manual numărul de iterații. Acest lucru este banal de făcut:
Dacă vrei să transmiți 150 de imagini de fiecare dată și știi că există 5000 de imagini în setul de date, numărul de iterații este egal cu 5000 împărțit la 150. În Python Puteți rula următoarele coduri și vă puteți asigura că rezultatul este 33:
BATCH_SIZE = 150 ### Number of batches : length dataset / batch size n_batches = horse_x.shape[0] // BATCH_SIZE print(n_batches) 33
Pasul 5) Rulați modelul
Nu în ultimul rând, antrenează modelul. Antrenezi modelul cu 100 de epoci. Adică, modelul va vedea imaginile de 100 de ori, optimizând în același timp ponderile.
Cunoști deja codurile pentru antrenarea unui model în TensorFlow. Mica diferență este că datele sunt redirecționate prin pipe înainte de a rula antrenamentul. În acest fel, modelul se antrenează mai rapid.
Sunteți interesat să imprimați pierderea după zece epoci pentru a vedea dacă modelul învață ceva (adică pierderea este în scădere). Antrenamentul durează între 2 și 5 minute, în funcție de hardware-ul mașinii dvs.
## 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
Pasul 6) Evaluați modelul
Acum că ați antrenat modelul, este timpul să îl evaluați. Trebuie să importați setul de teste din fișierul /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'])
Notă: Pentru o Windows mașină, codul devine test_data = unpickle(r”E:\cifar-10-batches-py\test_batch”)
Poți încerca să imprimi imaginea 13, care este un cal.
plot_image(test_x[13], shape=[32, 32], cmap = "Greys_r")
Graficul confirmă că lotul de testare a fost încărcat corect și că imaginea 13 aparține clasei în care a fost antrenat modelul.
Pentru a evalua modelul, veți utiliza valoarea pixelilor acestei imagini și veți vedea dacă codificatorul poate reconstrui aceeași imagine după micșorarea ei la 1024 pixeli. Rețineți că definiți o funcție pentru a evalua modelul pe diferite imagini. Modelul ar trebui să funcționeze mai bine doar pe cai.
Funcția ia două argumente:
- df: Importați datele de test
- imagine_număr: indică ce imagine să fie importată
Funcția este împărțită în trei părți:
- Reforma imaginea la dimensiunea corectă, adică 1, 1024
- Alimentați modelul cu imaginea nevăzută, codificați/decodificați imaginea
- Tipăriți imaginea reală și reconstruită
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()
Acum, că funcția de evaluare este definită, puteți arunca o privire asupra imaginii reconstruite numărul treisprezece.
reconstruct_image(df =test_x, image_number = 13)
INFO:tensorflow:Restoring parameters from ./model.ckpt
Model restored.
(1, 1024)
Figura plasează imaginea de test originală în stânga și ieșirea autoencoderului în dreapta, astfel încât pierderea detaliilor fine după compresia de la 1024 la 150 este ușor de evaluat.




