Autoencoder no TensorFlow com exemplo

O que é Autoencoder em Deep Learning?

An Codificador automático é uma ferramenta para aprender a codificação de dados de maneira eficiente e não supervisionada. É um tipo de rede neural artificial que ajuda você a aprender a representação de conjuntos de dados para redução de dimensionalidade, treinando a rede neural para ignorar o ruído do sinal. É uma ótima ferramenta para recriar uma entrada.

Em palavras simples, a máquina tira, digamos, uma imagem e pode produzir uma imagem intimamente relacionada. A entrada neste tipo de rede neural não é rotulada, o que significa que a rede é capaz de aprender sem supervisão. Mais precisamente, a entrada é codificada pela rede para focar apenas no recurso mais crítico. Esta é uma das razões pelas quais o autoencoder é popular para redução de dimensionalidade. Além disso, autoencoders podem ser usados ​​para produzir modelos de aprendizagem generativos. Por exemplo, a rede neural pode ser treinada com um conjunto de faces e então produzir novas faces.

Como funciona o codificador automático do TensorFlow?

O objetivo de um autoencoder é produzir uma aproximação da entrada concentrando-se apenas nos recursos essenciais. Você pode pensar por que não simplesmente aprender como copiar e colar a entrada para produzir a saída. Na verdade, um autoencoder é um conjunto de restrições que força a rede a aprender novas maneiras de representar os dados, diferente de apenas copiar a saída.

Um autoencoder típico é definido com uma entrada, uma representação interna e uma saída (uma aproximação da entrada). A aprendizagem ocorre nas camadas ligadas à representação interna. Na verdade, existem dois blocos principais de camadas que se parecem com uma rede neural tradicional. A pequena diferença é que a camada que contém a saída deve ser igual à entrada. Na figura abaixo, a entrada original vai para o primeiro bloco chamado encoder. Esta representação interna comprime (reduz) o tamanho da entrada. No segundo bloco ocorre a reconstrução da entrada. Esta é a fase de decodificação.

Funcionamento do Autoencoder
Funcionamento do Autoencoder

Funcionamento do Autoencoder

O modelo atualizará os pesos minimizando a função de perda. O modelo é penalizado se a saída da reconstrução for diferente da entrada.

Concretamente, imagine uma imagem com tamanho de 50×50 (ou seja, 250 pixels) e uma rede neural com apenas uma camada oculta composta por cem neurônios. O aprendizado é feito em um mapa de características duas vezes menor que a entrada. Isso significa que a rede precisa encontrar uma maneira de reconstruir 250 pixels com apenas um vetor de neurônios igual a 100.

Exemplo de codificador automático empilhado

Neste tutorial do Autoencoder, você aprenderá como usar um autoencoder empilhado. A arquitetura é semelhante a uma rede neural tradicional. A entrada vai para uma camada oculta para ser comprimida, ou reduzir seu tamanho, e então chega às camadas de reconstrução. O objetivo é produzir uma imagem de saída tão próxima quanto a original. O modelo tem que aprender uma forma de realizar a sua tarefa sob um conjunto de restrições, ou seja, com uma dimensão menor.

Hoje em dia, Autoencoders em Deep Learning são usados ​​​​principalmente para eliminar ruído de uma imagem. Imagine uma imagem com arranhões; um humano ainda é capaz de reconhecer o conteúdo. A ideia do autoencoder de eliminação de ruído é adicionar ruído à imagem para forçar a rede a aprender o padrão por trás dos dados.

A outra família útil de Autoencoder Deep Learning é o autoencoder variacional. Este tipo de rede pode gerar novas imagens. Imagine que você treina uma rede com a imagem de um homem; tal rede pode produzir novos rostos.

Como construir um autoencoder com TensorFlow

Neste tutorial, você aprenderá como construir um autoencoder empilhado para reconstruir uma imagem.

Você vai usar o Conjunto de dados CIFAR-10 que contém 60000 imagens coloridas de 32×32. O conjunto de dados do Autoencoder já está dividido entre 50000 imagens para treinamento e 10000 para teste. Existem até dez aulas:

  • Avião
  • Automobile
  • Pássaro
  • Gato
  • Veado
  • Cachorro
  • Sapo
  • Horse
  • Navio
  • Truck

Você precisa baixar as imagens neste URL https://www.cs.toronto.edu/~kriz/cifar.html e descompactá-las. A pasta for-10-batches-py contém cinco lotes de dados com 10000 imagens cada em ordem aleatória.

Antes de construir e treinar seu modelo, você precisa aplicar algum processamento de dados. Você procederá da seguinte forma:

  1. Importar os dados
  2. Converta os dados para o formato preto e branco
  3. Anexar todos os lotes
  4. Construa o conjunto de dados de treinamento
  5. Construa um visualizador de imagens

Pré-processamento de imagem

Etapa 1) Importe os dados

De acordo com o site oficial, você pode fazer upload dos dados com o seguinte código. O código do Autoencoder carregará os dados em um dicionário com o dados, e os votos de rótulo. Observe que o código é uma função.

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

Etapa 2) Converta os dados para o formato preto e branco

Para simplificar, você converterá os dados em escala de cinza. Ou seja, com apenas uma dimensão contra três para imagem em cores. A maior parte da rede neural funciona apenas com entrada de uma dimensão.

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

Etapa 3) Anexe todos os lotes

Agora que ambas as funções foram criadas e o conjunto de dados carregado, você pode escrever um loop para anexar os dados na memória. Se você verificar com cuidado, o arquivo descompactado com os dados é denominado data_batch_ com um número de 1 a 5. Você pode percorrer os arquivos e anexá-los aos dados.

Quando esta etapa for concluída, você converte os dados de cores em um formato de escala de cinza. Como você pode ver, o formato dos dados é 50000 e 1024. Os 32*32 pixels agora estão nivelados para 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)

Nota: Altere './cifar-10-batches-py/data_batch_' para o local real do seu arquivo. Por exemplo para Windows máquina, o caminho pode ser filename = 'E:\cifar-10-batches-py\data_batch_' + str(i)

Etapa 4) Construa o conjunto de dados de treinamento

Para tornar o treinamento mais rápido e fácil, você treinará um modelo apenas nas imagens do cavalo. Os cavalos são a sétima classe nos dados do rótulo. Conforme mencionado na documentação do conjunto de dados CIFAR-10, cada classe contém 5000 imagens. Você pode imprimir o formato dos dados para confirmar que existem 5.000 imagens com 1024 colunas, conforme mostrado abaixo TensorFlow Etapa de exemplo do codificador automático.

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

Etapa 5) Construa um visualizador de imagens

Finalmente, você constrói uma função para plotar as imagens. Você precisará desta função para imprimir a imagem reconstruída do autoencoder.

Uma maneira fácil de imprimir imagens é usar o objeto imshow da biblioteca matplotlib. Observe que você precisa converter o formato dos dados de 1024 para 32*32 (ou seja, formato de uma imagem).

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

A função leva 3 argumentos:

  • Imagem: a entrada
  • Shape: lista, a dimensão da imagem
  • cmap:escolha o mapa de cores. Por padrão, cinza

Você pode tentar plotar a primeira imagem no conjunto de dados. Você deveria ver um homem a cavalo.

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

Construa um visualizador de imagens

Definir estimador de conjunto de dados

Tudo bem, agora que o conjunto de dados está pronto para uso, você pode começar a usar o Tensorflow. Antes de construir o modelo, vamos usar o estimador Dataset do Tensorflow para alimentar a rede.

Você construirá um conjunto de dados com estimador TensorFlow. Para refrescar sua mente, você precisa usar:

  • from_tensor_slices
  • repetir
  • fornada

O código completo para construir o conjunto de dados é:

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

Observe que x é um espaço reservado com o seguinte formato:

  • [None,n_inputs]: Defina como Nenhum porque o número de imagens alimentadas na rede é igual ao tamanho do lote.

para obter detalhes, consulte o tutorial em regressão linear.

Depois disso, você precisa criar o iterador. Sem esta linha de código, nenhum dado passará pelo pipeline.

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

Agora que o pipeline está pronto, você pode verificar se a primeira imagem é a mesma de antes (ou seja, um homem a cavalo).

Você define o tamanho do lote como 1 porque deseja alimentar o conjunto de dados apenas com uma imagem. Você pode ver a dimensão dos dados com print(sess.run(features).shape). É igual a (1, 1024). 1 significa que apenas uma imagem com 1024 é alimentada cada. Se o tamanho do lote for definido como dois, duas imagens passarão pelo pipeline. (Não altere o tamanho do lote. Caso contrário, ocorrerá um erro. Apenas uma imagem por vez pode ir para a função 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)

Definir estimador de conjunto de dados

Construa a rede

É hora de construir a rede. Você treinará um autoencoder empilhado, ou seja, uma rede com múltiplas camadas ocultas.

Sua rede terá uma camada de entrada com 1024 pontos, ou seja, 32×32, o formato da imagem.

O bloco codificador terá uma camada oculta superior com 300 neurônios, uma camada central com 150 neurônios. O bloco decodificador é simétrico ao codificador. Você pode visualizar a rede na imagem abaixo. Observe que você pode alterar os valores das camadas ocultas e centrais.

Construa a rede
Construindo a rede para Autoencoder

Construir um autoencoder é muito semelhante a qualquer outro modelo de aprendizado profundo.

Você construirá o modelo seguindo estas etapas:

  1. Defina os parâmetros
  2. Defina as camadas
  3. Defina a arquitetura
  4. Defina a otimização
  5. Execute o modelo
  6. Avalie o modelo

Na seção anterior, você aprendeu como criar um pipeline para alimentar o modelo, portanto não há necessidade de criar novamente o conjunto de dados. Você construirá um autoencoder com quatro camadas. Você usa a inicialização do Xavier. Esta é uma técnica para definir os pesos iniciais iguais à variância da entrada e da saída. Finalmente, você usa a função de ativação elu. Você regulariza a função de perda com o regularizador L2.

Passo 1) Defina os parâmetros

O primeiro passo implica definir o número de neurônios em cada camada, a taxa de aprendizagem e o hiperparâmetro do regularizador.

Antes disso, você importa a função parcialmente. É o melhor método para definir os parâmetros das camadas densas. O código abaixo define os valores da arquitetura do autoencoder. Conforme listado anteriormente, o autoencoder possui duas camadas, com 300 neurônios nas primeiras camadas e 150 nas segundas camadas. Seus valores são armazenados em n_hidden_1 e n_hidden_2.

Você precisa definir a taxa de aprendizagem e o hiperparâmetro L2. Os valores são armazenados em learning_rate e 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

A técnica de inicialização Xavier é chamada com o objeto xavier_initializer do estimador contrib. No mesmo estimador, você pode adicionar o regularizador com 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)

Passo 2) Defina as camadas

Todos os parâmetros das camadas densas foram definidos; você pode empacotar tudo na variável densa_layer usando o objeto parcial. densa_layer que usa a ativação ELU, inicialização Xavier e regularização L2.

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

Passo 3) Defina a arquitetura

Se você observar a imagem da arquitetura, notará que a rede empilha três camadas com uma camada de saída. No código abaixo, você conecta as camadas apropriadas. Por exemplo, a primeira camada calcula o produto escalar entre os recursos da matriz de entradas e as matrizes contendo os 300 pesos. Depois que o produto escalar é calculado, a saída vai para a função de ativação Elu. A saída se torna a entrada da próxima camada, é por isso que você a usa para calcular hidden_2 e assim por diante. A multiplicação das matrizes é a mesma para cada camada porque você usa a mesma função de ativação. Observe que a última camada, saídas, não aplica uma função de ativação. Faz sentido porque esta é a entrada reconstruída

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

Passo 4) Defina a otimização

A última etapa é construir o otimizador. Você usa o erro quadrático médio como uma função de perda. Se você se lembra do tutorial sobre regressão linear, sabe que o MSE é calculado com a diferença entre a saída prevista e o rótulo real. Aqui, o rótulo é o recurso porque o modelo tenta reconstruir a entrada. Portanto, você deseja a média da soma da diferença do quadrado entre a produção e a entrada previstas. Com o TensorFlow, você pode codificar a função de perda da seguinte maneira:

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

Então, você precisa otimizar a função de perda. Você usa o otimizador Adam para calcular os gradientes. A função objetivo é minimizar a perda.

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

Mais uma configuração antes de treinar o modelo. Você deseja usar um tamanho de lote de 150, ou seja, alimentar o pipeline com 150 imagens a cada iteração. Você precisa calcular o número de iterações manualmente. Isso é trivial de fazer:

Se você deseja passar 150 imagens de cada vez e sabe que há 5000 imagens no conjunto de dados, o número de iterações é igual a. Em python você pode executar os seguintes códigos e garantir que a saída seja 33:

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

Passo 5) Execute o modelo

Por último, mas não menos importante, treine o modelo. Você está treinando o modelo com 100 épocas. Ou seja, o modelo verá 100 vezes mais imagens com pesos otimizados.

Você já está familiarizado com os códigos para treinar um modelo no Tensorflow. A pequena diferença é canalizar os dados antes de executar o treinamento. Dessa forma, o modelo treina mais rápido.

Você está interessado em imprimir a perda após dez épocas para ver se o modelo está aprendendo alguma coisa (ou seja, a perda está diminuindo). O treinamento leva de 2 a 5 minutos, dependendo do hardware da sua máquina.

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

Passo 6) Avalie o modelo

Agora que você treinou seu modelo, é hora de avaliá-lo. Você precisa importar o conjunto de teste do arquivo /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'])

NOTA: Para Windows máquina, o código se torna test_data = unpickle(r”E:\cifar-10-batches-py\test_batch”)

Você pode tentar imprimir a imagem 13, que é um cavalo

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

Avalie o Modelo

Para avaliar o modelo, você usará o valor do pixel desta imagem e verá se o codificador consegue reconstruir a mesma imagem após reduzir 1024 pixels. Observe que você define uma função para avaliar o modelo em diferentes imagens. O modelo deveria funcionar melhor apenas em cavalos.

A função leva dois argumentos:

  • df: Importe os dados de teste
  • número_da_imagem: indique qual imagem importar

A função é dividida em três partes:

  1. Remodele a imagem para a dimensão correta, ou seja, 1, 1024
  2. Alimente o modelo com a imagem invisível, codifique/decodifique a imagem
  3. Imprima a imagem real e reconstruída
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()

Agora que a função de avaliação está definida, você pode dar uma olhada na imagem reconstruída número treze

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

Avalie o Modelo

Resumo

  • O objetivo principal de um autoencoder é compactar os dados de entrada e, em seguida, descompactá-los em uma saída que se pareça muito com os dados originais.
  • A arquitetura de um autoencoder simétrico com uma camada pivô denominada camada central.
  • Você pode criar o autoencoder usando:
  • Parcial: para criar camadas densas com a configuração típica:

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

    camada_densa(): para fazer a multiplicação da matriz

  • Você pode definir a função de perda e otimização com:
  • loss = tf.reduce_mean(tf.square(outputs - features))
    optimizer = tf.train.AdamOptimizer(learning_rate)
    train  = optimizer.minimize(loss)
    
  • Por último, execute uma sessão para treinar o modelo.