Definicion de un Autoencoder

Como primer ejecricio se hara un autoencoder que codifique la entrada en menores dimensiones (encode) y luego reconstruya esa entrada (decode) para que la red de como salida la propia entrada.


In [20]:
import tensorflow as tf
import numpy as np

class Autoencoder:
    def __init__(self, input_dim, hidden_dim, epoch=250, learning_rate=0.001):
        self.epoch = epoch # Numero de ciclos para aprender
        self.learning_rate = learning_rate #Hiper parametro para el optimizador (RMSProppOptimizer en este caso)
        # Capa de entrada (Input X que es el Dataset). shape=[None,input_dim] significa que en vez de None puede haber cualquier numero ahi (para poder hacer batch)
        x = tf.placeholder(dtype=tf.float32, shape=[None, input_dim])
        # Definir variables y operador del encoder (Del Input a la Hidden Layer)
        with tf.name_scope('encode'):
            weights = tf.Variable(tf.random_normal([input_dim, hidden_dim], dtype=tf.float32), name='weights')
            biases = tf.Variable(tf.zeros([hidden_dim]), name='biases')
            encoded = tf.nn.tanh(tf.matmul(x,weights) + biases)
        # Definir variables y operador del decoder (De la Hidden Layer al Output)    
        with tf.name_scope('decode'):
            weights = tf.Variable(tf.random_normal([hidden_dim, input_dim], dtype=tf.float32), name='weights')
            biases = tf.Variable(tf.zeros([hidden_dim]), name='biases')
            decoded = tf.nn.tanh(tf.matmul(encoded,weights) + biases)
        # Asignar a variables de la clase para que otro metodos de ella las puedan usar
        self.x = x
        self.encoded = encoded
        self.decoded = decoded
        # Funcion de costo (diferencia entre el output del autoencoder y el output esperado 
        # que en este caso es el propio input)
        self.loss = tf.sqrt(tf.reduce_mean(tf.square(tf.subtract(self.x,self.decoded))))
        # Definir el optimizador a utilizar y salvar los parametros que se iran aprendiendo en cada epoch
        self.train_op = tf.train.RMSPropOptimizer(self.learning_rate).minimize(self.loss)
        self.saver = tf.train.Saver()
        
    def train(self, data):
        num_samples = len(data)
        with tf.Session() as sess:
            sess.run(tf.global_variables_initializer())
            for i in range(self.epoch):
                for j in range(num_samples): # Entrenat la red sample por sample durante i epoch's
                    l, _ = sess.run([self.loss, self.train_op], feed_dict={self.x: [data[j]]})
                if i%10==0: # Solo imprimir como va la red cada 10 iteraciones (Vigilar como desciende el error!)
                    print("Epoch {}: loss = {}".format(i,l))
                    self.saver.save(sess, './checkpoints/autoencoder_model.ckpt')

    def test(self, data): #Data es un solo ejemplo (nunca antes visto) que entrara a la red y esta dara el resultado (que debe de ser el propio input si se entreno correctamente)
        with tf.Session() as sess:
            self.saver.restore(sess, './checkpoints/autoencoder_model.ckpt')
            hidden,reconstructed = sess.run([self.encoded, self.decoded], feed_dict={self.x: data})
        print('input', data)
        print('compressed',hidden)
        print('reconstructed',reconstructed)
        return reconstructed

Ejecutar el autoencoder


In [21]:
from sklearn import datasets

hidden_dim = 1
data = datasets.load_iris().data
input_dim = len(data[0])
ae = Autoencoder(input_dim, hidden_dim,epoch=500)
ae.train(data)
ae.test([[ 5.0 ,3.9,  2.4,  1.2]])


[ 5.1  3.5  1.4  0.2]
Epoch 0: loss = 3.7618191242218018
Epoch 10: loss = 3.3742692470550537
Epoch 20: loss = 3.3714780807495117
Epoch 30: loss = 3.3712639808654785
Epoch 40: loss = 3.3712174892425537
Epoch 50: loss = 3.3712072372436523
Epoch 60: loss = 3.3712048530578613
Epoch 70: loss = 3.371203660964966
Epoch 80: loss = 3.3712031841278076
Epoch 90: loss = 3.3712027072906494
Epoch 100: loss = 3.3712027072906494
Epoch 110: loss = 3.3712024688720703
Epoch 120: loss = 3.3712024688720703
Epoch 130: loss = 3.371202230453491
Epoch 140: loss = 3.371202230453491
Epoch 150: loss = 3.371201992034912
Epoch 160: loss = 3.371201992034912
Epoch 170: loss = 3.371201992034912
Epoch 180: loss = 3.371201992034912
Epoch 190: loss = 3.371201992034912
Epoch 200: loss = 3.371201992034912
Epoch 210: loss = 3.371201992034912
Epoch 220: loss = 3.371201992034912
Epoch 230: loss = 3.371201753616333
Epoch 240: loss = 3.371201753616333
Epoch 250: loss = 3.371201753616333
Epoch 260: loss = 3.371201753616333
Epoch 270: loss = 3.371201753616333
Epoch 280: loss = 3.371201753616333
Epoch 290: loss = 3.371201753616333
Epoch 300: loss = 3.371201753616333
Epoch 310: loss = 3.371201753616333
Epoch 320: loss = 3.371201753616333
Epoch 330: loss = 3.371201753616333
Epoch 340: loss = 3.371201753616333
Epoch 350: loss = 3.371201753616333
Epoch 360: loss = 3.371201753616333
Epoch 370: loss = 3.371201753616333
Epoch 380: loss = 3.371201753616333
Epoch 390: loss = 3.371201753616333
Epoch 400: loss = 3.371201753616333
Epoch 410: loss = 3.371201753616333
Epoch 420: loss = 3.371201753616333
Epoch 430: loss = 3.371201753616333
Epoch 440: loss = 3.371201753616333
Epoch 450: loss = 3.371201753616333
Epoch 460: loss = 3.371201753616333
Epoch 470: loss = 3.371201753616333
Epoch 480: loss = 3.371201753616333
Epoch 490: loss = 3.371201753616333
input [[5.1, 3.5, 1.4, 0.2]]
compressed [[-0.99999309]]
reconstructed [[ 1.          0.99999982  1.          0.99999768]]
Out[21]:
array([[ 1.        ,  0.99999982,  1.        ,  0.99999768]], dtype=float32)