Автокодер у TensorFlow із прикладом

Що таке Autoencoder у Deep Learning?

An Автокодер це інструмент для ефективного вивчення кодування даних без нагляду. Це тип штучної нейронної мережі, яка допомагає навчитися представленню наборів даних для зменшення розмірності, навчаючи нейронну мережу ігнорувати шум сигналу. Це чудовий інструмент для відтворення введення.

Простіше кажучи, машина приймає, скажімо, зображення, і може створювати тісно пов’язане зображення. Вхідні дані в цьому типі нейронної мережі не позначені, тобто мережа здатна навчатися без нагляду. Точніше, вхідні дані кодуються мережею, щоб зосередитися лише на найважливішій функції. Це одна з причин, чому автокодер популярний для зменшення розмірності. Крім того, для виробництва можна використовувати автокодери генеративні моделі навчання. Наприклад, нейронну мережу можна навчити з набором облич, а потім створити нові обличчя.

Як працює TensorFlow Autoencoder?

Метою автокодувальника є створення наближення вхідних даних, зосереджуючись лише на основних характеристиках. Ви можете подумати, чому б просто не навчитися копіювати та вставляти вхідні дані для отримання результату. Насправді автокодер — це набір обмежень, які змушують мережу вивчати нові способи представлення даних, відмінні від простого копіювання виводу.

Типовий автокодер визначається входом, внутрішнім представленням і виходом (наближенням входу). Навчання відбувається в шарах, приєднаних до внутрішнього представлення. Насправді є два основних блоки шарів, які виглядають як традиційна нейронна мережа. Невелика різниця полягає в тому, що шар, що містить вихід, повинен бути рівним входу. На малюнку нижче оригінальний вхідний сигнал переходить у перший блок під назвою кодіровщік. Це внутрішнє представлення стискає (зменшує) розмір вхідних даних. У другому блоці відбувається реконструкція входу. Це етап декодування.

Робота автокодера
Робота автокодера

Робота автокодера

Модель оновить ваги шляхом мінімізації функції втрат. Модель штрафується, якщо вихідні дані реконструкції відрізняються від вхідних.

Конкретніше, уявіть картинку розміром 50×50 (тобто 250 пікселів) і нейронну мережу лише з одним прихованим шаром, що складається зі ста нейронів. Навчання виконується на карті функцій, яка вдвічі менша за вхідні дані. Це означає, що мережі потрібно знайти спосіб реконструювати 250 пікселів лише з вектором нейронів, що дорівнює 100.

Приклад стекового автокодувальника

У цьому підручнику Autoencoder ви дізнаєтеся, як використовувати стековий автокодер. Архітектура схожа на традиційну нейронну мережу. Вхідні дані надходять до прихованого шару для стиснення або зменшення його розміру, а потім досягають шарів реконструкції. Мета полягає в тому, щоб отримати вихідне зображення так само близько до оригінального. Модель має навчитися досягати свого завдання за набору обмежень, тобто з меншою розмірністю.

Зараз автокодери в Глибоке навчання в основному використовуються для зменшення шуму зображення. Уявіть собі зображення з подряпинами; людина все ще здатна розпізнати вміст. Ідея усунення шумів у автокодері полягає в додаванні шуму до зображення, щоб змусити мережу дізнатися шаблон, що стоїть за даними.

Іншим корисним сімейством Autoencoder Deep Learning є варіаційний автокодер. Цей тип мережі може створювати нові зображення. Уявіть, що ви тренуєте мережу із зображенням людини; така мережа може створити нові обличчя.

Як створити автокодер із TensorFlow

У цьому підручнику ви дізнаєтеся, як побудувати стековий автокодер для реконструкції зображення.

Ви будете використовувати Набір даних CIFAR-10 який містить 60000 кольорових зображень 32×32. Набір даних Autoencoder уже розділений на 50000 10000 зображень для навчання та XNUMX XNUMX для тестування. Є до десяти класів:

  • Літак
  • автомобіль
  • Птах
  • Кішка
  • Олень
  • Пес
  • Жаба
  • Кінь
  • Судно
  • Вантажні автомобілі

Вам потрібно завантажити зображення за цією 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. Ви можете прокрутити файли та додати їх до даних.

Коли цей крок виконано, ви перетворюєте дані про кольори у формат градацій сірого. Як бачите, форма даних 50000 і 1024. 32*32 пікселя тепер зведені до 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)

Примітка. Змініть './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. Щоб освіжити свій розум, вам потрібно скористатися:

  • from_tensor_slices
  • повторювати
  • партія

Повний код для створення набору даних:

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. Значення зберігаються в learn_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)

Оцініть модель

Підсумки

  • Основне призначення автокодувальника — стиснути вхідні дані, а потім розпакувати їх у вихідні дані, які дуже схожі на вихідні дані.
  • Архітектура автокодувальника, симетричного з опорним шаром, який називається центральним шаром.
  • Ви можете створити автокодер за допомогою:
  • Частковий: для створення щільних шарів із типовим налаштуванням:

      	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)
    
  • Останній запуск сеансу для навчання моделі.