Autoencoder i TensorFlow med eksempel
⚡ Smart opsummering
Autoencodere komprimerer input til en mindre intern repræsentation og genopbygger den derefter, hvorved de vigtigste funktioner læres uden etiketter. Denne gennemgang stabler fire tætte lag i TensorFlow og rekonstruerer CIFAR-10 hestebilleder.
Hvad er Autoencoder i Deep Learning?
An Autoencoder er et værktøj til effektivt at lære datakodning i en uden opsyn måde. Det er en type af kunstigt neuralt netværk som hjælper dig med at lære repræsentationen af datasæt til dimensionsreduktion ved at træne det neurale netværk til at ignorere signalstøj. Det er et fantastisk værktøj til at genskabe input.
Enkelt sagt tager maskinen, lad os sige, et billede og kan producere et nært beslægtet billede. Inputtet i denne type neuralt netværk er umærket, hvilket betyder, at netværket er i stand til at lære uden overvågning. Mere præcist er inputtet kodet af netværket til kun at fokusere på den mest kritiske funktion. Dette er en af grundene til, at autoencodere er populære til dimensionsreduktion. Derudover kan autoencodere bruges til at producere generative læringsmodeller. For eksempel kan det neurale netværk trænes med et sæt ansigter og derefter producere nye ansigter.
Hvordan virker TensorFlow Autoencoder?
Formålet med en autoencoder er at producere en tilnærmelse af inputtet ved kun at fokusere på de væsentlige funktioner. Du tænker måske, hvorfor ikke bare lære at kopiere og indsætte input for at producere output. Faktisk er en autoencoder et sæt begrænsninger, der tvinger netværket til at lære nye måder at repræsentere data på, anderledes end blot at kopiere outputtet.
En typisk autoencoder er defineret med et input, en intern repræsentation og et output (en tilnærmelse af inputtet). Læringen sker i de lag, der er knyttet til den interne repræsentation. Faktisk er der to hovedblokke af lag, der ligner et traditionelt neuralt netværk. Den lille forskel er, at laget, der indeholder outputtet, skal være lig med inputtet. I diagrammet nedenfor går det oprindelige input ind i den første blok kaldet encoderen. Denne interne repræsentation komprimerer (reducerer) størrelsen af inputtet. I den anden blok sker rekonstruktionen af inputtet. Dette er afkodningsfasen.

Modellen vil opdatere vægtene ved at minimere tabsfunktionen. Modellen straffes, hvis rekonstruktionsoutputtet er forskelligt fra inputtet.
Konkret kan man forestille sig et billede med en størrelse på 50×50 (dvs. 2,500 pixels) og et neuralt netværk med kun ét skjult lag bestående af hundrede neuroner. Læringen foregår på et feature map, der er 25 gange mindre end inputtet. Det betyder, at netværket skal finde en måde at rekonstruere 2,500 pixels med kun en vektor af neuroner lig med 100.
Eksempel på stablet autoencoder
I denne Autoencoder-tutorial lærer du, hvordan du bruger en stablet autoencoder. Arkitekturen ligner et traditionelt neuralt netværk. Inputtet går til et skjult lag for at blive komprimeret eller reduceret i størrelse, og når derefter rekonstruktionslagene. Målet er at producere et outputbillede, der er så tæt som muligt på originalen. Modellen skal lære en måde at udføre sin opgave under et sæt begrænsninger, det vil sige med en lavere dimension.
Nu om dage bruges autoencodere i deep learning primært til at fjerne støj fra billeder. Forestil dig et billede med ridser; et menneske er stadig i stand til at genkende indholdet. Ideen med at fjerne støj fra autoencodere er at tilføje støj til billedet for at tvinge netværket til at lære mønsteret bag dataene.
Den anden nyttige familie af Autoencoder Deep Learning er en variationel autoencoder. Denne type netværk kan generere nye billeder. Forestil dig, at du træner et netværk med billedet af en mand; et sådant netværk kan producere nye ansigter.
Tabellen nedenfor placerer den stablede autoencoder, der er bygget i denne vejledning, ved siden af de andre familier, du sandsynligvis vil støde på, så den begrænsning, som hver enkelt tilføjer, er nem at sammenligne.
| Autoencoder-type | Begrænsning tilføjet | Typisk brug |
|---|---|---|
| Underkomplet / stablet | Kodningslaget er smallere end inputtet | Dimensionsreduktion, funktionseksempeltraction |
| Denoising | Støj tilføjet til inputtet, rent mål | Billed- og signaloprydning |
| Sparsom | Straf på antallet af aktive enheder | Fortolkelige, delbaserede funktioner |
| Variationel | Kodningslaget lærer en sandsynlighedsfordeling | Generering af nye prøver |
Sådan bygger du en autoencoder med TensorFlow
I denne vejledning lærer du, hvordan du bygger en stablet autoencoder for at rekonstruere et billede.
Du skal bruge CIFAR-10-datasættet, som indeholder 60000 32×32 farvebilleder. Autoencoder-datasættet er allerede opdelt i 50000 billeder til træning og 10000 til test. Der er op til ti klasser:
- Fly
- Automobile
- Bird
- Cat
- Deer
- Dog
- Frog
- hest
- Forsendelse
- lastbil
Du skal downloade billederne fra CIFAR-10 datasætside og udpak arkivet. Mappen cifar-10-batches-py indeholder fem databatcher med 10000 billeder hver i en tilfældig rækkefølge.
Før du bygger og træner din model, skal du anvende noget databehandling. Du vil fortsætte som følger:
- Importer dataene
- Konverter dataene til sort/hvid-format
- Tilføj alle batches
- Konstruer træningsdatasættet
- Konstruer en billedvisualisering
Versionsnotat: Koden i denne vejledning er rettet mod TensorFlow 1.x. På TensorFlow 2 findes tf.contrib-modulet ikke længere, og pladsholdere, sessioner og den initialiserbare iterator findes under tf.compat.v1. Den hurtigste måde at køre listingerne uændrede er at kalde tf.compat.v1.disable_v2_behavior() efter importen.
Billedforbehandling
Trin 1) Importer dataene
Ifølge den officielle hjemmeside kan du uploade dataene med følgende kode. Autoencoder-koden vil indlæse dataene i en ordbog med dataene og etiketten. Bemærk at koden er en funktion.
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
Trin 2) Konverter dataene til sort/hvid-format
For nemheds skyld konverterer du dataene til en gråtoneskala. Det vil sige med kun én dimension mod tre for farver billede. Det meste af det neurale netværk fungerer kun med én dimensionsinput.
def grayscale(im): return im.reshape(im.shape[0], 3, 32, 32).mean(1).reshape(im.shape[0], -1)
Trin 3) Tilføj alle batches
Nu hvor begge funktioner er oprettet, og datasættet er indlæst, kan du skrive et loop for at tilføje dataene i hukommelsen. Hvis du tjekker omhyggeligt, hedder den udpakkede fil med dataene data_batch_ med et tal fra 1 til 5. Du kan løbe hen over filerne og tilføje dem til data.
Når dette trin er færdigt, konverterer du farvedataene til et gråtoneformat. Som du kan se, er dataenes form 50000 og 1024. De 32*32 pixels er nu fladtrykt til 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)
Bemærk: Skift './cifar-10-batches-py/data_batch_' til den faktiske placering af din fil. For eksempel for en Windows maskine, stien kunne være filnavn = 'E:\cifar-10-batches-py\data_batch_' + str(i)
Trin 4) Konstruer træningsdatasættet
For at gøre træningen hurtigere og nemmere, træner du kun en model på hestebillederne. Hestene har label 7 i labeldataene. Som nævnt i dokumentationen til CIFAR-10-datasættet indeholder hver klasse 5000 billeder. Du kan udskrive dataenes form for at bekræfte, at der er 5,000 billeder med 1024 kolonner, som vist i nedenstående TensorFlow Autoencoder-eksempeltrin.
horse_i = np.where(y == 7)[0]
horse_x = x[horse_i]
print(np.shape(horse_x))
(5000, 1024)
Trin 5) Konstruer en billedvisualisering
Til sidst konstruerer du en funktion til at plotte billederne. Du skal bruge denne funktion for at udskrive det rekonstruerede billede fra autoencoderen.
En nem måde at udskrive billeder på er at bruge funktionen imshow() fra Matplotlib-biblioteket. Bemærk, at du skal konvertere formen på dataene fra 1024 til 32*32 (dvs. formatet på et billede).
# 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")
Funktionen tager 3 argumenter:
- Billede: inputtet
- Form: liste, billedets dimension
- Cmap: vælg farvekortet. Som standard er det gråt
Du kan prøve at plotte det første billede i datasættet. Du burde se en mand på en hest.
plot_image(horse_x[1], shape=[32, 32], cmap = "Greys_r")
Kaldet returnerer gråtoneminiaturebilledet nedenfor, og det bekræfter, at omformningen fra 1024 værdier tilbage til et 32×32 billede er korrekt.
Indstil Datasæt Estimator
Okay, nu hvor datasættet er klar til brug, kan du begynde at bruge TensorFlow. Før du bygger modellen, skal du bruge TensorFlows datasætestimator til at forsyne netværket.
Du vil bygge et datasæt med TensorFlow-estimator. For at genopfriske dit sind skal du bruge:
- from_tensor_slices
- gentag
- parti
Den fulde kode til at bygge datasættet er:
dataset = tf.data.Dataset.from_tensor_slices(x).repeat().batch(batch_size)
Bemærk, at x er formet som en pladsholder [None,n_inputs]. Den første dimension er indstillet til None, fordi antallet af billeder, der sendes til netværket, er lig med batchstørrelsen, som kun bestemmes under kørsel. For detaljer, se venligst vejledningen om lineær regression med TensorFlow.
Derefter skal du oprette iteratoren. Uden denne kodelinje vil ingen data gå gennem pipelinen.
iter = dataset.make_initializable_iterator() # create the iteratorfeatures = iter.get_next()
Nu hvor pipelinen er klar, kan du kontrollere, om det første billede er det samme som før (dvs. en mand på en hest).
Du indstiller batchstørrelsen til 1, fordi du kun vil indlæse ét billede i datasættet. Du kan se dataenes dimensioner med print(sess.run(features).shape). Det er lig med (1, 1024). Tallet 1 betyder, at der indlæses et enkelt billede med 1024 værdier hver gang. Hvis batchstørrelsen er indstillet til to, vil to billeder gå gennem pipelinen. Du må ikke ændre batchstørrelsen, da det ellers vil give en fejl, fordi kun ét billede ad gangen kan gå til funktionen 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)
Pipelinen returnerer den samme rytter, der blev plottet direkte fra NumPy-matricen, hvilket beviser, at pladsholderen, iteratoren og batchstørrelsen er korrekt forbundet.
Byg netværket
Det er tid til at opbygge netværket. Du træner en stablet autoencoder, det vil sige et netværk med flere skjulte lag.
Dit netværk vil have ét inputlag med 1024 punkter, dvs. 32×32, billedets form.
Encoderblokken vil have et øverste skjult lag med 300 neuroner og et centralt lag med 150 neuroner. Dekoderblokken er symmetrisk i forhold til encoderen. Du kan visualisere netværket i diagrammet nedenfor. Bemærk, at du kan ændre værdierne for de skjulte og centrale lag.
At bygge en autoencoder ligner meget enhver anden deep learning-model.
Du vil konstruere modellen ved at følge disse trin:
- Definer parametrene
- Definer lagene
- Definer arkitekturen
- Definer optimeringen
- Kør modellen
- Vurder modellen
I det forrige afsnit lærte du, hvordan du opretter en pipeline til at fodre modellen, så der ikke er behov for at oprette datasættet igen. Du skal konstruere en autoencoder med fire lag. Du bruger Xavier-initialiseringen. Dette er en teknik til at indstille de indledende vægte i henhold til variansen af både input og output. Endelig bruger du ELU-aktiveringsfunktionen. Du regulariserer tabsfunktionen med en L2-regularisator.
Trin 1) Definer parametrene
Det første trin indebærer at definere antallet af neuroner i hvert lag, indlæringshastigheden og hyperparameteren for regularizeren.
Før det importerer du partialfunktionen. Det er en bedre metode til at definere parametrene for de tætte lag. Koden nedenfor definerer værdierne for autoencoder-arkitekturen. Som nævnt tidligere har encoderen to lag med 300 neuroner i det første lag og 150 i det andet lag. Deres værdier gemmes i n_hidden_1 og n_hidden_2.
Du skal definere læringshastigheden og L2-hyperparameteren. Værdierne gemmes i learning_rate og 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
Xavier-initialiseringsteknikken kaldes med objektet xavier_initializer fra estimatoren contrib. I den samme estimator kan du tilføje regularizeren med 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)
Versionsnotat: tf.contrib blev fjernet i TensorFlow 2. De direkte erstatninger er tf.keras.initializers.GlorotUniform() for xavier_initializer() og tf.keras.regularizers.l2() for l2_regularizer().
Trin 2) Definer lagene
Alle parametrene for de tætte lag er blevet indstillet; du kan pakke alt i variablen dense_layer ved at bruge objektet partial. dense_layer bruger derefter ELU-aktivering, Xavier-initialisering og L2-regularisering på hvert kald.
## Create the dense layer
dense_layer = partial(tf.layers.dense,
activation=tf.nn.elu,
kernel_initializer=xav_init,
kernel_regularizer=l2_regularizer)
Trin 3) Definer arkitekturen
Hvis du ser på arkitekturdiagrammet, bemærker du, at netværket stabler tre lag med et outputlag. I koden nedenfor forbinder du de relevante lag. For eksempel beregner det første lag prikproduktet mellem inputmatrixens funktioner og matricen, der indeholder de 300 vægte. Efter at prikproduktet er beregnet, går outputtet til ELU-aktiveringsfunktionen. Outputtet bliver input for det næste lag, derfor bruger du det til at beregne hidden_2 osv. Matrixmultiplikationen er den samme for hvert lag, fordi du bruger den samme aktiveringsfunktion. Bemærk, at det sidste lag, output, ikke anvender en aktiveringsfunktion. Det giver mening, fordi dette er det rekonstruerede input.
## 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)
Trin 4) Definer optimeringen
Det sidste trin er at konstruere optimeringsfunktionen. Du bruger den gennemsnitlige kvadratiske fejl (MSE) som en tabsfunktion. Hvis du husker vejledningen om lineær regression, ved du, at MSE beregnes med forskellen mellem det forudsagte output og den reelle label. Her er label-funktionen funktionen, fordi modellen forsøger at rekonstruere inputtet. Derfor ønsker du middelværdien af summen af den kvadrerede forskel mellem forudsagt output og input. Med TensorFlow kan du kode tabsfunktionen som følger:
loss = tf.reduce_mean(tf.square(outputs - features))
Derefter skal du optimere tabsfunktionen. Du bruger Adam-optimereren til at beregne gradienterne. Målfunktionen er at minimere tabet.
## Optimize
loss = tf.reduce_mean(tf.square(outputs - features))
optimizer = tf.train.AdamOptimizer(learning_rate)
train = optimizer.minimize(loss)
Endnu en indstilling før træning af modellen. Du vil bruge en batchstørrelse på 150, det vil sige at fodre pipelinen med 150 billeder hver iteration. Du skal beregne antallet af iterationer manuelt. Dette er trivielt at gøre:
Hvis du vil sende 150 billeder hver gang, og du ved, at der er 5000 billeder i datasættet, er antallet af iterationer lig med 5000 divideret med 150. I Python Du kan køre følgende koder og sørge for, at outputtet er 33:
BATCH_SIZE = 150 ### Number of batches : length dataset / batch size n_batches = horse_x.shape[0] // BATCH_SIZE print(n_batches) 33
Trin 5) Kør modellen
Sidst men ikke mindst, træn modellen. Du træner modellen med 100 epoker. Det vil sige, at modellen vil se billederne 100 gange, mens vægtene optimeres.
Du er allerede bekendt med koderne til at træne en model i TensorFlow. Den lille forskel er at sende dataene i pipe-format, før træningen køres. På denne måde trænes modellen hurtigere.
Du er interesseret i at udskrive tabet efter ti epoker for at se, om modellen lærer noget (dvs. tabet er faldende). Træningen tager 2 til 5 minutter, afhængigt af din maskinhardware.
## 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
Trin 6) Evaluer modellen
Nu hvor du har trænet din model, er det tid til at evaluere den. Du skal importere testsættet fra filen /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'])
Bemærk: For en Windows maskine, bliver koden test_data = unpickle(r”E:\cifar-10-batches-py\test_batch”)
Du kan prøve at udskrive billede 13, som er en hest.
plot_image(test_x[13], shape=[32, 32], cmap = "Greys_r")
Plottet bekræfter, at testbatchen er indlæst korrekt, og at billede 13 tilhører den klasse, som modellen blev trænet på.
For at evaluere modellen skal du bruge pixelværdien af dette billede og se, om encoderen kan rekonstruere det samme billede efter at have krympet det til 1024 pixels. Bemærk, at du definerer en funktion til at evaluere modellen på forskellige billeder. Modellen burde kun fungere bedre på heste.
Funktionen tager to argumenter:
- df: Importer testdataene
- billednummer: angiver hvilket billede der skal importeres
Funktionen er opdelt i tre dele:
- Omform billedet til den korrekte dimension, dvs. 1, 1024
- Fodre modellen med det usete billede, indkode/afkode billedet
- Udskriv det rigtige og rekonstruerede billede
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()
Nu hvor evalueringsfunktionen er defineret, kan du se på det rekonstruerede billede nummer tretten.
reconstruct_image(df =test_x, image_number = 13)
INFO:tensorflow:Restoring parameters from ./model.ckpt
Model restored.
(1, 1024)
Figuren placerer det originale testbillede til venstre og autoencoder-outputtet til højre, så tabet af fine detaljer efter 1024 til 150-komprimeringen er let at bedømme.




