Autokodare i TensorFlow med exempel

Vad är Autoencoder i Deep Learning?

An Autokodare är ett verktyg för att lära sig datakodning effektivt på ett oövervakat sätt. Det är en typ av konstgjorda neurala nätverk som hjälper dig att lära dig representationen av datamängder för dimensionsreduktion genom att träna det neurala nätverket att ignorera signalbruset. Det är ett utmärkt verktyg för att återskapa en ingång.

Med enkla ord, maskinen tar, låt oss säga en bild, och kan producera en närbesläktad bild. Ingången i denna typ av neurala nätverk är omärkt, vilket betyder att nätverket kan lära sig utan övervakning. Närmare bestämt är ingången kodad av nätverket för att bara fokusera på den mest kritiska egenskapen. Detta är en av anledningarna till att autoencoder är populärt för dimensionsreducering. Dessutom kan autoencoders användas för att producera generativa inlärningsmodeller. Till exempel kan det neurala nätverket tränas med en uppsättning ansikten och kan sedan producera nya ansikten.

Hur fungerar TensorFlow Autoencoder?

Syftet med en autoencoder är att producera en approximation av ingången genom att bara fokusera på de väsentliga funktionerna. Du kanske tänker varför inte bara lära dig hur man kopierar och klistrar in indata för att producera utdata. Faktum är att en autoencoder är en uppsättning begränsningar som tvingar nätverket att lära sig nya sätt att representera data, annorlunda än att bara kopiera utdata.

En typisk autokodare definieras med en ingång, en intern representation och en utgång (en approximation av ingången). Inlärningen sker i de lager som är knutna till den interna representationen. Faktum är att det finns två huvudblock av lager som ser ut som ett traditionellt neuralt nätverk. Den lilla skillnaden är att lagret som innehåller utgången måste vara lika med ingången. På bilden nedan går den ursprungliga ingången in i det första blocket som kallas kodare. Denna interna representation komprimerar (minskar) storleken på inmatningen. I det andra blocket sker rekonstruktionen av ingången. Detta är avkodningsfasen.

Fungerar av Autoencoder
Fungerar av Autoencoder

Fungerar av Autoencoder

Modellen kommer att uppdatera vikterna genom att minimera förlustfunktionen. Modellen straffas om rekonstruktionsutgången skiljer sig från ingången.

Föreställ dig konkret en bild med en storlek på 50×50 (dvs. 250 pixlar) och ett neuralt nätverk med bara ett dolt lager bestående av hundra neuroner. Inlärningen sker på en funktionskarta som är två gånger mindre än inmatningen. Det betyder att nätverket måste hitta ett sätt att rekonstruera 250 pixlar med endast en vektor av neuroner lika med 100.

Exempel på staplad autokodare

I den här självstudien för Autoencoder kommer du att lära dig hur du använder en staplad autoencoder. Arkitekturen liknar ett traditionellt neuralt nätverk. Inmatningen går till ett dolt lager för att komprimeras eller minska dess storlek och når sedan rekonstruktionslagren. Målet är att producera en utgående bild så nära originalet. Modellen måste lära sig ett sätt att uppnå sin uppgift under en uppsättning begränsningar, det vill säga med en lägre dimension.

Nuförtiden, autoencoders in Deep Learning används främst för att försvaga en bild. Föreställ dig en bild med repor; en människa kan fortfarande känna igen innehållet. Idén med att denoising autoencoder är att lägga till brus till bilden för att tvinga nätverket att lära sig mönstret bakom data.

Den andra användbara familjen av Autoencoder Deep Learning är variationsautokodare. Den här typen av nätverk kan generera nya bilder. Föreställ dig att du tränar ett nätverk med bilden av en man; ett sådant nätverk kan skapa nya ansikten.

Hur man bygger en autokodare med TensorFlow

I den här handledningen kommer du att lära dig hur du bygger en staplad autokodare för att rekonstruera en bild.

Du kommer att använda CIFAR-10 dataset som innehåller 60000 32×32 färgbilder. Autoencoder-dataset är redan uppdelat mellan 50000 10000 bilder för träning och XNUMX XNUMX för testning. Det finns upp till tio klasser:

  • Flygplan
  • Automobile
  • Fågel
  • Cat
  • Deer
  • Dog
  • groda
  • Häst
  • Ship
  • Lastbil

Du måste ladda ner bilderna i denna URL https://www.cs.toronto.edu/~kriz/cifar.html och packa upp den. Mappen för-10-batches-py innehåller fem partier data med 10000 XNUMX bilder vardera i en slumpmässig ordning.

Innan du bygger och tränar din modell måste du tillämpa viss databehandling. Du kommer att gå tillväga enligt följande:

  1. Importera data
  2. Konvertera data till svartvitt format
  3. Lägg till alla satser
  4. Konstruera träningsdatauppsättningen
  5. Konstruera en bildvisualiserare

Bildförbehandling

Steg 1) Importera data

Enligt den officiella webbplatsen kan du ladda upp data med följande kod. Autoencoder-koden kommer att ladda data i en ordbok med datum och etikett. Observera att koden är 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

Steg 2) Konvertera data till svartvitt format

För enkelhetens skull kommer du att konvertera data till en gråskala. Det vill säga med endast en dimension mot tre för färgbild. Det mesta av det neurala nätverket fungerar bara med endimensionell input.

def grayscale(im):
    return im.reshape(im.shape[0], 3, 32, 32).mean(1).reshape(im.shape[0], -1)

Steg 3) Lägg till alla satser

Nu när båda funktionerna har skapats och datauppsättningen laddats kan du skriva en loop för att lägga till data i minnet. Om du kontrollerar noggrant, heter unzip-filen med data data_batch_ med ett nummer från 1 till 5. Du kan loopa över filerna och lägga till dem i data.

När detta steg är klart konverterar du färgdata till ett gråskaleformat. Som du kan se är formen på data 50000 och 1024. De 32*32 pixlarna är nu plattade till 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)

Obs: Ändra './cifar-10-batches-py/data_batch_' till den faktiska platsen för din fil. Till exempel för Windows maskin, sökvägen kan vara filnamn = 'E:\cifar-10-batches-py\data_batch_' + str(i)

Steg 4) Konstruera träningsdatauppsättningen

För att göra träningen snabbare och enklare kommer du att träna en modell endast på hästbilderna. Hästarna är den sjunde klassen i etikettdata. Som nämnts i dokumentationen för CIFAR-10-datauppsättningen innehåller varje klass 5000 bilder. Du kan skriva ut formen på data för att bekräfta att det finns 5.000 1024 bilder med XNUMX XNUMX kolumner som visas i nedan TensorFlow Exempelsteg för autoencoder.

horse_i = np.where(y == 7)[0]
horse_x = x[horse_i]
print(np.shape(horse_x)) 
(5000, 1024)

Steg 5) Konstruera en bildvisualiserare

Slutligen konstruerar du en funktion för att plotta bilderna. Du behöver denna funktion för att skriva ut den rekonstruerade bilden från autoencodern.

Ett enkelt sätt att skriva ut bilder är att använda objektet imshow från matplotlib-biblioteket. Observera att du måste konvertera formen på data från 1024 till 32*32 (dvs formatet på en bild).

# 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 tar 3 argument:

  • Bild: ingången
  • Forma: lista, bildens dimension
  • cmap:välj färgkartan. Som standard, grå

Du kan försöka plotta den första bilden i datamängden. Du borde se en man på en häst.

plot_image(horse_x[1], shape=[32, 32], cmap = "Greys_r")

Konstruera en bildvisualiserare

Ställ in Dataset Estimator

Okej, nu när datasetet är klart att använda kan du börja använda Tensorflow. Innan vi bygger modellen, låt oss använda Dataset-estimatorn för Tensorflow för att mata nätverket.

Du kommer att bygga en datamängd med TensorFlow estimator. För att fräscha upp ditt sinne måste du använda:

  • from_tensor_slices
  • upprepa
  • sats

Den fullständiga koden för att bygga datamängden är:

dataset = tf.data.Dataset.from_tensor_slices(x).repeat().batch(batch_size)

Observera att x är en platshållare med följande form:

  • [None,n_inputs]: Ställ in på None eftersom antalet bildmatningar till nätverket är lika med batchstorleken.

för detaljer, se handledningen om linjär regression.

Efter det måste du skapa iteratorn. Utan denna kodrad kommer ingen data att gå genom pipelinen.

iter = dataset.make_initializable_iterator() # create the iteratorfeatures = iter.get_next()

Nu när pipelinen är klar kan du kontrollera om den första bilden är densamma som tidigare (dvs en man på en häst).

Du ställer in batchstorleken till 1 eftersom du bara vill mata datamängden med en bild. Du kan se dimensionen på datan med print(sess.run(features).shape). Det är lika med (1, 1024). 1 betyder att endast en bild med 1024 matas vardera. Om batchstorleken är inställd på två, kommer två bilder att gå genom pipelinen. (Ändra inte batchstorleken. Annars kommer det att skapa ett fel. Endast en bild åt gången kan gå till 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)

Ställ in Dataset Estimator

Bygg nätverket

Det är dags att bygga nätverket. Du kommer att träna en staplad autokodare, det vill säga ett nätverk med flera dolda lager.

Ditt nätverk kommer att ha ett indatalager med 1024 punkter, dvs 32×32, bildens form.

Kodarblocket kommer att ha ett övre dolt lager med 300 neuroner, ett centralt lager med 150 neuroner. Avkodarblocket är symmetriskt till kodaren. Du kan visualisera nätverket på bilden nedan. Observera att du kan ändra värdena för dolda och centrala lager.

Bygg nätverket
Bygga nätverket för Autoencoder

Att bygga en autoencoder är mycket likt vilken annan modell för djupinlärning som helst.

Du kommer att konstruera modellen enligt dessa steg:

  1. Definiera parametrarna
  2. Definiera lagren
  3. Definiera arkitekturen
  4. Definiera optimeringen
  5. Kör modellen
  6. Utvärdera modellen

I det föregående avsnittet lärde du dig hur man skapar en pipeline för att mata modellen, så det finns inget behov av att skapa datauppsättningen en gång till. Du kommer att konstruera en autoencoder med fyra lager. Du använder Xavier-initieringen. Detta är en teknik för att ställa in de initiala vikterna lika med variansen för både ingången och utmatningen. Slutligen använder du elu-aktiveringsfunktionen. Du reglerar förlustfunktionen med L2 regularizer.

Steg 1) Definiera parametrarna

Det första steget innebär att definiera antalet neuroner i varje lager, inlärningshastigheten och hyperparametern för regularizern.

Innan dess importerar du funktionen delvis. Det är en bättre metod att definiera parametrarna för de täta lagren. Koden nedan definierar värdena för autoencoder-arkitekturen. Som nämnts tidigare har autokodaren två lager, med 300 neuroner i det första lagret och 150 i det andra lagret. Deras värden lagras i n_hidden_1 och n_hidden_2.

Du måste definiera inlärningshastigheten och hyperparametern L2. Värdena lagras i learning_rate och 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-initieringstekniken anropas med objektet xavier_initializer från estimatorns bidrag. I samma estimator kan du lägga till regularizern 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)

Steg 2) Definiera lagren

Alla parametrar för de täta lagren har ställts in; du kan packa allt i variabeln dense_layer genom att använda objektet partial. dense_layer som använder ELU-aktivering, Xavier-initiering och L2-regularisering.

## Create the dense layer
dense_layer = partial(tf.layers.dense,
                         activation=tf.nn.elu,
                         kernel_initializer=xav_init,
                         kernel_regularizer=l2_regularizer)

Steg 3) Definiera arkitekturen

Om du tittar på bilden av arkitekturen, noterar du att nätverket staplar tre lager med ett utdatalager. I koden nedan kopplar du ihop lämpliga lager. Till exempel beräknar det första lagret punktprodukten mellan inmatningsmatrisegenskaperna och matriserna som innehåller de 300 vikterna. Efter att punktprodukten har beräknats går utsignalen till Elu-aktiveringsfunktionen. Utdatan blir indata för nästa lager, det är därför du använder den för att beräkna hidden_2 och så vidare. Matrismultiplikationen är densamma för varje lager eftersom du använder samma aktiveringsfunktion. Observera att det sista lagret, utgångar, inte tillämpar en aktiveringsfunktion. Det är vettigt eftersom detta är den rekonstruerade ingången

## 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)

Steg 4) Definiera optimeringen

Det sista steget är att konstruera optimeraren. Du använder Mean Square Error som en förlustfunktion. Om du kommer ihåg handledningen om linjär regression, vet du att MSE beräknas med skillnaden mellan den förutspådda utsignalen och den verkliga etiketten. Här är etiketten funktionen eftersom modellen försöker rekonstruera ingången. Därför vill du ha medelvärdet av summan av skillnaden i kvadraten mellan förutsagd utdata och ingång. Med TensorFlow kan du koda förlustfunktionen enligt följande:

loss = tf.reduce_mean(tf.square(outputs - features))

Sedan måste du optimera förlustfunktionen. Du använder Adam optimizer för att beräkna gradienterna. Den objektiva funktionen är att minimera förlusten.

## Optimize
loss = tf.reduce_mean(tf.square(outputs - features))
optimizer = tf.train.AdamOptimizer(learning_rate)
train  = optimizer.minimize(loss)

Ytterligare en inställning innan du tränar modellen. Du vill använda en batchstorlek på 150, det vill säga mata pipelinen med 150 bilder varje iteration. Du måste beräkna antalet iterationer manuellt. Detta är trivialt att göra:

Om du vill skicka 150 bilder varje gång och du vet att det finns 5000 bilder i datamängden är antalet iterationer lika med . I python kan du köra följande koder och se till att utdata är 33:

BATCH_SIZE = 150
### Number of batches :  length dataset / batch size
n_batches = horse_x.shape[0] // BATCH_SIZE
print(n_batches)
33

Steg 5) Kör modellen

Sist men inte minst, träna modellen. Du tränar modellen med 100 epoker. Det vill säga, modellen kommer att se 100 gånger bilderna till optimerade vikter.

Du är redan bekant med koderna för att träna en modell i Tensorflow. Den lilla skillnaden är att röra data innan du kör träningen. På så sätt tränar modellen snabbare.

Du är intresserad av att skriva ut förlusten efter tio epoker för att se om modellen lär sig något (dvs. förlusten minskar). Utbildningen tar 2 till 5 minuter, beroende på din maskinvara.

## 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

Steg 6) Utvärdera modellen

Nu när du har tränat din modell är det dags att utvärdera den. Du måste importera testserien från 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'])

ANMÄRKNINGAR: För en Windows maskin, koden blir test_data = unpickle(r”E:\cifar-10-batches-py\test_batch”)

Du kan prova att skriva ut bilderna 13, som är en häst

plot_image(test_x[13], shape=[32, 32], cmap = "Greys_r")

Utvärdera modellen

För att utvärdera modellen kommer du att använda pixelvärdet för denna bild och se om kodaren kan rekonstruera samma bild efter att ha krympt 1024 pixlar. Observera att du definierar en funktion för att utvärdera modellen på olika bilder. Modellen borde fungera bättre bara på hästar.

Funktionen tar två argument:

  • df: Importera testdata
  • bildnummer: ange vilken bild som ska importeras

Funktionen är uppdelad i tre delar:

  1. Forma om bilden till rätt dimension, dvs 1, 1024
  2. Mata modellen med den osynliga bilden, koda/avkoda bilden
  3. Skriv ut den verkliga och rekonstruerade bilden
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 när utvärderingsfunktionen är definierad kan du ta en titt på den rekonstruerade bilden nummer tretton

reconstruct_image(df =test_x, image_number = 13)
INFO:tensorflow:Restoring parameters from ./model.ckpt
Model restored.
(1, 1024)

Utvärdera modellen

Sammanfattning

  • Det primära syftet med en autoencoder är att komprimera indata och sedan komprimera den till en utdata som liknar originaldata.
  • Arkitekturen för en autoencoder symmetrisk med ett pivotlager som heter det centrala lagret.
  • Du kan skapa autokodaren med:
  • Partiell: för att skapa de täta lagren med den typiska inställningen:

      	tf.layers.dense,                         
      	activation=tf.nn.elu,                         
      	kernel_initializer=xav_init,                         
      	kernel_regularizer=l2_regularizer

    dense_layer(): för att göra matrismultiplikationen

  • Du kan definiera förlustfunktionen och optimeringen med:
  • loss = tf.reduce_mean(tf.square(outputs - features))
    optimizer = tf.train.AdamOptimizer(learning_rate)
    train  = optimizer.minimize(loss)
    
  • Kör senast ett pass för att träna modellen.