Автоенкодер в TensorFlow с пример

Какво е Autoencoder в Deep Learning?

An Автокодер е инструмент за ефективно изучаване на кодиране на данни по неконтролиран начин. Това е вид изкуствена невронна мрежа, която ви помага да научите представянето на набори от данни за намаляване на размерността, като обучавате невронната мрежа да игнорира шума на сигнала. Това е чудесен инструмент за пресъздаване на вход.

С прости думи, машината взема, да речем, изображение и може да създаде тясно свързана картина. Входът в този вид невронна мрежа е немаркиран, което означава, че мрежата може да се учи без надзор. По-точно, входът се кодира от мрежата, за да се фокусира само върху най-критичната характеристика. Това е една от причините, поради които автоенкодерът е популярен за намаляване на размерността. Освен това могат да се използват автоенкодери за производство генеративни модели на обучение. Например, невронната мрежа може да бъде обучена с набор от лица и след това може да създаде нови лица.

Как работи TensorFlow Autoencoder?

Целта на автокодера е да създаде приближение на входа, като се фокусира само върху основните характеристики. Може да си помислите защо просто не се научите как да копирате и поставите входа, за да създадете изхода. Всъщност автокодерът е набор от ограничения, които принуждават мрежата да научи нови начини за представяне на данните, различни от простото копиране на изхода.

Типичният автоенкодер се дефинира с вход, вътрешно представяне и изход (приближение на входа). Обучението се извършва в слоевете, прикрепени към вътрешното представяне. Всъщност има два основни блока от слоеве, които изглеждат като традиционна невронна мрежа. Малката разлика е, че слоят, съдържащ изхода, трябва да бъде равен на входа. На снимката по-долу оригиналният вход влиза в първия блок, наречен енкодер. Това вътрешно представяне компресира (намалява) размера на входа. Във втория блок се извършва реконструкцията на входа. Това е фазата на декодиране.

Работа на Autoencoder
Работа на Autoencoder

Работа на Autoencoder

Моделът ще актуализира теглата чрез минимизиране на функцията за загуба. Моделът се наказва, ако изходът на реконструкцията е различен от входа.

По-конкретно, представете си картина с размер 50×50 (т.е. 250 пиксела) и невронна мрежа само с един скрит слой, съставен от сто неврона. Обучението се извършва на карта на функции, която е два пъти по-малка от входа. Това означава, че мрежата трябва да намери начин да реконструира 250 пиксела само с вектор от неврони, равен на 100.

Пример за подреден автоенкодер

В този урок за Autoencoder ще научите как да използвате подреден автоматичен енкодер. Архитектурата е подобна на традиционната невронна мрежа. Входът отива към скрит слой, за да бъде компресиран или да намали размера си и след това достига до слоевете за реконструкция. Целта е да се създаде изходно изображение толкова близко до оригинала. Моделът трябва да научи начин да постигне задачата си при набор от ограничения, тоест с по-ниско измерение.

В наши дни автоенкодерите в Дълбоко обучение се използват главно за обезшумяване на изображение. Представете си изображение с драскотини; човек все още може да разпознае съдържанието. Идеята на обезшумяването на автокодера е да се добави шум към картината, за да се принуди мрежата да научи модела зад данните.

Другото полезно семейство на Autoencoder Deep Learning е variational autoencoder. Този тип мрежа може да генерира нови изображения. Представете си, че тренирате мрежа с образа на човек; такава мрежа може да създаде нови лица.

Как да изградите автоенкодер с TensorFlow

В този урок ще научите как да изградите подреден автоенкодер, за да реконструирате изображение.

Ще използвате Набор от данни CIFAR-10 който съдържа 60000 32 цветни изображения 32×50000. Наборът от данни на Autoencoder вече е разделен между 10000 XNUMX изображения за обучение и XNUMX XNUMX за тестване. Има до десет класа:

  • Самолет
  • Автомобил
  • Птица
  • Котка
  • Елен
  • Куче
  • Жаба
  • Кон
  • Адрес за доставка
  • Truck

Трябва да изтеглите изображенията от този URL https://www.cs.toronto.edu/~kriz/cifar.html и да го разархивирате. Папката for-10-batches-py съдържа пет партиди данни с 10000 XNUMX изображения всяка в произволен ред.

Преди да изградите и обучите вашия модел, трябва да приложите известна обработка на данни. Ще продължите както следва:

  1. Импортирайте данните
  2. Преобразувайте данните в черно-бял формат
  3. Добавете всички партиди
  4. Конструирайте набора от данни за обучение
  5. Конструирайте визуализатор на изображения

Предварителна обработка на изображението

Стъпка 1) Импортирайте данните

Според официалния уебсайт можете да качите данните със следния код. Кодът на Autoencoder ще зареди данните в речник с данни и етикет. Имайте предвид, че кодът е функция.

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

Стъпка 2) Преобразувайте данните в черно-бял формат

За простота ще преобразувате данните в скала на сивото. Тоест само с едно измерение срещу три за цветно изображение. Повечето от невронните мрежи работят само с едно измерение.

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

Стъпка 3) Добавете всички партиди

След като и двете функции са създадени и наборът от данни е зареден, можете да напишете цикъл, за да добавите данните в паметта. Ако проверите внимателно, разархивираният файл с данните се нарича data_batch_ с номер от 1 до 5. Можете да преминете през файловете и да го добавите към data.

Когато тази стъпка приключи, преобразувате данните за цветовете във формат на сивата скала. Както можете да видите, формата на данните е 50000 1024 и 32. 32*2014 пиксела вече са изравнени до XNUMX.

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

Забележка: Променете „./cifar-10-batches-py/data_batch_“ на действителното местоположение на вашия файл. Например за Windows машина, пътят може да бъде име на файл = 'E:\cifar-10-batches-py\data_batch_' + str(i)

Стъпка 4) Конструирайте набора от данни за обучение

За да направите обучението по-бързо и лесно, ще обучите модел само върху изображенията на конете. Конете са седми клас по данни на етикета. Както се споменава в документацията на набора от данни CIFAR-10, всеки клас съдържа 5000 изображения. Можете да отпечатате формата на данните, за да потвърдите, че има 5.000 изображения с 1024 колони, както е показано по-долу TensorFlow Примерна стъпка за автоенкодер.

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

Стъпка 5) Конструирайте визуализатор на изображения

Накрая създавате функция за начертаване на изображенията. Ще ви е необходима тази функция, за да отпечатате реконструираното изображение от автокодера.

Лесен начин за отпечатване на изображения е да използвате обекта imshow от библиотеката matplotlib. Имайте предвид, че трябва да преобразувате формата на данните от 1024 в 32*32 (т.е. формат на изображение).

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

Функцията приема 3 аргумента:

  • Изображение: входът
  • Форма: списък, размерът на изображението
  • Cmap: изберете цветовата карта. По подразбиране сиво

Можете да опитате да начертаете първото изображение в набора от данни. Трябва да видите човек на кон.

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

Конструирайте визуализатор на изображения

Задайте оценител на набор от данни

Добре, сега, когато наборът от данни е готов за използване, можете да започнете да използвате Tensorflow. Преди да изградим модела, нека използваме оценителя на набора от данни на Tensorflow, за да захранваме мрежата.

Ще изградите набор от данни с оценител TensorFlow. За да освежите ума си, трябва да използвате:

  • от_тензорни_срезове
  • повтарям
  • партида

Пълният код за изграждане на набора от данни е:

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

Обърнете внимание, че x е контейнер със следната форма:

  • [None,n_inputs]: Задайте на None, тъй като броят на подаванията на изображения към мрежата е равен на размера на партидата.

за подробности, моля, вижте урока на линейна регресия.

След това трябва да създадете итератора. Без този ред код никакви данни няма да преминат през тръбопровода.

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

Сега, когато конвейерът е готов, можете да проверите дали първото изображение е същото като преди (т.е. човек на кон).

Задавате размера на партидата на 1, защото искате да захранвате набора от данни само с едно изображение. Можете да видите размерите на данните с print(sess.run(features).shape). То е равно на (1, 1024). 1 означава само едно изображение с 1024 за всеки. Ако размерът на пакета е зададен на две, тогава две изображения ще преминат през конвейера. (Не променяйте размера на пакета. В противен случай ще изведе грешка. Само едно изображение наведнъж може да отиде до функцията 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)

Задайте оценител на набор от данни

Изградете мрежата

Време е да изградим мрежата. Ще обучите подреден автоенкодер, тоест мрежа с множество скрити слоеве.

Вашата мрежа ще има един входен слой с 1024 точки, т.е. 32×32, формата на изображението.

Блокът на енкодера ще има един горен скрит слой с 300 неврона, централен слой със 150 неврона. Декодерният блок е симетричен спрямо енкодера. Можете да визуализирате мрежата на снимката по-долу. Имайте предвид, че можете да промените стойностите на скритите и централните слоеве.

Изградете мрежата
Изграждане на мрежата за Autoencoder

Изграждането на автоенкодер е много подобно на всеки друг модел на дълбоко обучение.

Ще изградите модела, като следвате тези стъпки:

  1. Определете параметрите
  2. Дефинирайте слоевете
  3. Определете архитектурата
  4. Дефинирайте оптимизацията
  5. Стартирайте модела
  6. Оценете модела

В предишния раздел научихте как да създадете конвейер за захранване на модела, така че няма нужда да създавате отново набора от данни. Ще конструирате автоенкодер с четири слоя. Използвате инициализацията на Xavier. Това е техника за задаване на първоначалните тегла, равни на дисперсията както на входа, така и на изхода. Накрая използвате функцията за активиране на elu. Вие регулирате функцията на загубата с L2 регулатор.

Стъпка 1) Определете параметрите

Първата стъпка предполага да се определи броят на невроните във всеки слой, скоростта на обучение и хиперпараметърът на регулатора.

Преди това импортирате функцията частично. Това е по-добър метод за определяне на параметрите на плътните слоеве. Кодът по-долу дефинира стойностите на архитектурата на автокодера. Както беше посочено по-горе, автоенкодерът има два слоя, с 300 неврона в първите слоеве и 150 във вторите слоеве. Техните стойности се съхраняват в n_hidden_1 и n_hidden_2.

Трябва да дефинирате скоростта на обучение и хиперпараметъра L2. Стойностите се съхраняват в learning_rate и 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 се извиква с обекта xavier_initializer от contrib на оценителя. В същия оценител можете да добавите регулатор с 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)

Стъпка 2) Дефинирайте слоевете

Всички параметри на плътните слоеве са зададени; можете да опаковате всичко в променливата dense_layer, като използвате частичния обект. dense_layer, който използва ELU активиране, Xavier инициализация и L2 регуляризация.

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

Стъпка 3) Определете архитектурата

Ако погледнете снимката на архитектурата, забелязвате, че мрежата подрежда три слоя с изходен слой. В кода по-долу свързвате подходящите слоеве. Например, първият слой изчислява точковия продукт между характеристиките на входната матрица и матриците, съдържащи 300 тегла. След като точковият продукт бъде изчислен, изходът отива към функцията за активиране на Elu. Изходът става вход на следващия слой, затова го използвате за изчисляване на hidden_2 и т.н. Умножението на матриците е едно и също за всеки слой, защото използвате една и съща функция за активиране. Имайте предвид, че последният слой, изходи, не прилага функция за активиране. Има смисъл, защото това е реконструираният вход

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

Стъпка 4) Дефинирайте оптимизацията

Последната стъпка е да конструирате оптимизатора. Използвате средната квадратична грешка като функция за загуба. Ако си спомняте урока за линейна регресия, знаете, че MSE се изчислява с разликата между прогнозирания изход и реалния етикет. Тук етикетът е функцията, защото моделът се опитва да реконструира входа. Следователно искате средната стойност на сумата от разликата на квадрата между прогнозирания изход и вход. С TensorFlow можете да кодирате функцията за загуба, както следва:

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

След това трябва да оптимизирате функцията за загуба. Използвате оптимизатора на Adam, за да изчислите градиентите. Целевата функция е да се минимизират загубите.

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

Още една настройка преди обучение на модела. Искате да използвате размер на партида от 150, тоест да захранвате конвейера със 150 изображения на всяка итерация. Трябва да изчислите броя на итерациите ръчно. Това е тривиално да се направи:

Ако искате да предавате 150 изображения всеки път и знаете, че има 5000 изображения в набора от данни, броят на итерациите е равен на . В python можете да стартирате следните кодове и да се уверите, че изходът е 33:

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

Стъпка 5) Стартирайте модела

Не на последно място, обучете модела. Вие обучавате модела със 100 епохи. Това означава, че моделът ще види 100 пъти повече изображения до оптимизирани тегла.

Вече сте запознати с кодовете за обучение на модел в Tensorflow. Малката разлика е данните да се подават преди провеждане на обучението. По този начин моделът тренира по-бързо.

Интересувате се от отпечатване на загубата след десет епохи, за да видите дали моделът научава нещо (т.е. загубата намалява). Обучението отнема от 2 до 5 минути, в зависимост от хардуера на вашата машина.

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

Стъпка 6) Оценете модела

Сега, след като вашият модел е обучен, е време да го оцените. Трябва да импортирате тестовия набор от файла /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'])

ЗАБЕЛЕЖКА: За Windows машина, кодът става test_data = unpickle(r”E:\cifar-10-batches-py\test_batch”)

Можете да опитате да отпечатате изображения 13, което е кон

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

Оценете модела

За да оцените модела, ще използвате стойността на пикселите на това изображение и ще видите дали енкодерът може да реконструира същото изображение след свиване на 1024 пиксела. Имайте предвид, че дефинирате функция за оценка на модела на различни картини. Моделът трябва да работи по-добре само на коне.

Функцията приема два аргумента:

  • df: Импортирайте тестовите данни
  • номер_на_изображение: посочете какво изображение да импортирате

Функцията е разделена на три части:

  1. Преоформете изображението до правилното измерение, т.е. 1, 1024
  2. Захранете модела с невидяното изображение, кодирайте/декодирайте изображението
  3. Отпечатайте реалното и реконструирано изображение
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()

Сега, когато функцията за оценка е дефинирана, можете да погледнете реконструираното изображение номер тринадесет

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

Оценете модела

Oбобщение

  • Основната цел на автокодера е да компресира входните данни и след това да ги декомпресира в изход, който прилича много на оригиналните данни.
  • Архитектурата на автокодер, симетричен с осов слой, наречен централен слой.
  • Можете да създадете автокодера, като използвате:
  • Частичен: за създаване на плътни слоеве с типичната настройка:

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

    dense_layer(): за да направите умножение на матрицата

  • Можете да дефинирате функцията на загубата и оптимизацията с:
  • loss = tf.reduce_mean(tf.square(outputs - features))
    optimizer = tf.train.AdamOptimizer(learning_rate)
    train  = optimizer.minimize(loss)
    
  • Последно изпълнете сесия за обучение на модела.

Обобщете тази публикация с: