Автокодер у TensorFlow із прикладом
⚡ Розумний підсумок
Автоенкодер стискає вхідні дані до меншого внутрішнього представлення, а потім перебудовує їх, вивчаючи найважливіші функції без міток. Цей посібник об'єднує чотири щільні шари в TensorFlow та реконструює зображення коней CIFAR-10.

Що таке Autoencoder у Deep Learning?
An Автокодер це інструмент для ефективного навчання кодуванню даних у без нагляду спосіб. Це тип штучна нейронна мережа що допомагає вам вивчити представлення наборів даних для зменшення розмірності шляхом навчання нейронної мережі ігнорувати шум сигналу. Це чудовий інструмент для відтворення вхідних даних.
Простими словами, машина бере, скажімо, зображення та може створити тісно пов'язане з ним зображення. Вхідні дані в такій нейронній мережі не мають міток, тобто мережа здатна навчатися без нагляду. Точніше, вхідні дані кодуються мережею, щоб зосередитися лише на найважливішій особливі. Це одна з причин, чому автоенкодер популярний для зменшення розмірності. Крім того, автоенкодер можна використовувати для створення моделей генеративного навчання. Наприклад, нейронну мережу можна навчити на наборі облич, а потім створити нові.
Як працює TensorFlow Autoencoder?
Метою автокодувальника є створення наближення вхідних даних, зосереджуючись лише на основних характеристиках. Ви можете подумати, чому б просто не навчитися копіювати та вставляти вхідні дані для отримання результату. Насправді автокодер — це набір обмежень, які змушують мережу вивчати нові способи представлення даних, відмінні від простого копіювання виводу.
Типовий автоенкодер визначається входом, внутрішнім представленням та виходом (наближенням входу). Навчання відбувається в шарах, приєднаних до внутрішнього представлення. Фактично, існує два основні блоки шарів, які виглядають як традиційна нейронна мережа. Невелика відмінність полягає в тому, що шар, що містить вихід, має дорівнювати входу. На діаграмі нижче оригінальний вхід надходить у перший блок, який називається кодером. Це внутрішнє представлення стискає (зменшує) розмір входу. У другому блоці відбувається реконструкція входу. Це фаза декодування.

Модель оновить ваги шляхом мінімізації функції втрат. Модель штрафується, якщо вихідні дані реконструкції відрізняються від вхідних.
Конкретно, уявіть собі зображення розміром 50×50 (тобто 2,500 пікселів) та нейронну мережу з одним прихованим шаром, що складається зі ста нейронів. Навчання відбувається на карті ознак, яка в двадцять п'ять разів менша за вхідні дані. Це означає, що мережі потрібно знайти спосіб реконструювати 2,500 пікселів, маючи лише вектор нейронів, що дорівнює 100.
Приклад стекового автокодувальника
У цьому посібнику з автоенкодера ви дізнаєтеся, як використовувати багатошаровий автоенкодер. Архітектура схожа на традиційну нейронну мережу. Вхідні дані надходять до прихованого шару для стиснення або зменшення розміру, а потім досягають шарів реконструкції. Мета полягає в тому, щоб створити вихідне зображення, максимально наближене до оригіналу. Модель повинна навчитися виконувати своє завдання з певним набором обмежень, тобто з меншою розмірністю.
Сьогодні автоенкодер у глибокому навчанні в основному використовуються для усунення шуму на зображенні. Уявіть собі зображення з подряпинами; людина все ще здатна розпізнати вміст. Ідея автоенкодера для усунення шуму полягає в тому, щоб додати шум до зображення, щоб змусити мережу вивчити закономірність, що стоїть за даними.
Інша корисна родина Autoencoder Глибоке навчання — це варіаційний автоенкодер. Цей тип мережі може генерувати нові зображення. Уявіть, що ви навчаєте мережу на зображенні людини; така мережа може створювати нові обличчя.
У таблиці нижче багатошаровий автоенкодер, побудований у цьому посібнику, розміщено поруч з іншими сімействами, з якими ви, ймовірно, зустрінетеся, тому обмеження, які додає кожен з них, легко порівняти.
| Тип автоенкодера | Додано обмеження | Типове використання |
|---|---|---|
| Недоповнено / складено | Кодовий шар вужчий за вхідний | Зменшення розмірності, ознака extracції |
| Шумить | Шум додано до вхідного сигналу, ціль чиста | Очищення зображення та сигналу |
| Розріджений | Штраф за кількість активних одиниць | Інтерпретовані, частково засновані функції |
| Варіаційний | Кодовий рівень вивчає розподіл ймовірностей | Генерація нових зразків |
Як створити автокодер із TensorFlow
У цьому підручнику ви дізнаєтеся, як побудувати стековий автокодер для реконструкції зображення.
Ви використовуватимете набір даних CIFAR-10, який містить 60000 кольорових зображень розміром 32×32. Набір даних Autoencoder вже розділений на 50000 зображень для навчання та 10000 для тестування. Існує до десяти класів:
- Літак
- автомобіль
- Птах
- Кішка
- Олень
- Пес
- Жаба
- Кінь
- Судно
- Вантажні автомобілі
Вам потрібно завантажити зображення з Сторінка набору даних CIFAR-10 та розпакуйте архів. Папка cifar-10-batches-py містить п'ять пакетів даних по 10000 зображень кожен у випадковому порядку.
Перш ніж створювати та навчати свою модель, потрібно застосувати певну обробку даних. Ви будете діяти наступним чином:
- Імпортуйте дані
- Перетворіть дані в чорно-білий формат
- Додайте всі партії
- Створіть навчальний набір даних
- Створіть візуалізатор зображень
Примітка до версії: Код у цьому посібнику орієнтований на TensorFlow 1.x. У TensorFlow 2 модуль tf.contrib більше не існує, а заповнювачі, сесії та ініціалізований ітератор знаходяться у tf.compat.v1. Виклик tf.compat.v1.disable_v2_behavior() після імпорту – це найшвидший спосіб виконати списки без змін.
Попередня обробка зображення
Крок 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 тепер зведені до 1024.
# 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) Створіть навчальний набір даних
Щоб зробити навчання швидшим та простішим, ви навчатимете модель лише на зображеннях коней. Коні мають мітку 7 у даних міток. Як зазначено в документації набору даних CIFAR-10, кожен клас містить 5000 зображень. Ви можете роздрукувати форму даних, щоб підтвердити наявність 5,000 зображень з 1024 стовпцями, як показано в наведеному нижче прикладі TensorFlow Autoencoder.
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")
Виклик повертає мініатюру у градаціях сірого нижче та підтверджує правильність зміни форми зображення з 1024 значень назад до 32×32.
Установити оцінювач набору даних
Добре, тепер, коли набір даних готовий до використання, ви можете почати використовувати TensorFlow. Перед побудовою моделі використовуйте оцінювач набору даних TensorFlow для зв'язку з мережею.
Ви створите набір даних за допомогою оцінювача TensorFlow. Щоб освіжити свій розум, вам потрібно скористатися:
- from_tensor_slices
- повторювати
- партія
Повний код для створення набору даних:
dataset = tf.data.Dataset.from_tensor_slices(x).repeat().batch(batch_size)
Зверніть увагу, що x – це заповнювач у формі [None,n_inputs]. Перший вимір встановлено на None, оскільки кількість зображень, що передаються в мережу, дорівнює розміру пакета, який визначається лише під час виконання. Для отримання детальної інформації зверніться до посібника з лінійна регресія з TensorFlow.
Після цього вам потрібно створити ітератор. Без цього рядка коду жодні дані не проходитимуть через конвеєр.
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)
Конвеєр повертає той самий райдер, який був нанесений безпосередньо на матрицю NumPy, що доводить, що заповнювач, ітератор та розмір пакета з'єднані правильно.
Побудуйте мережу
Настав час будувати мережу. Ви навчите стековий автокодер, тобто мережу з кількома прихованими шарами.
Ваша мережа матиме один вхідний шар з 1024 точками, тобто 32×32, форма зображення.
Блок кодера матиме один верхній прихований шар з 300 нейронами та центральний шар зі 150 нейронами. Блок декодера симетричний до кодера. Ви можете візуалізувати мережу на діаграмі нижче. Зверніть увагу, що ви можете змінювати значення прихованого та центрального шарів.
Створення автокодувальника дуже схоже на будь-яку іншу модель глибокого навчання.
Ви побудуєте модель, дотримуючись таких кроків:
- Визначте параметри
- Визначте шари
- Визначте архітектуру
- Визначте оптимізацію
- Запустіть модель
- Оцініть модель
У попередньому розділі ви дізналися, як створити конвеєр для живлення моделі, тому немає потреби створювати набір даних ще раз. Ви створите автоенкодер з чотирма шарами. Ви використовуєте ініціалізацію Ксав'є. Це техніка для встановлення початкових ваг відповідно до дисперсії як вхідних, так і вихідних даних. Нарешті, ви використовуєте функцію активації 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_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)
Примітка до версії: tf.contrib було видалено в TensorFlow 2. Прямими замінами є tf.keras.initializers.GlorotUniform() замість xavier_initializer() та tf.keras.regularizers.l2() замість l2_regularizer().
Крок 2) Визначення шарів
Усі параметри щільних шарів встановлено; ви можете упакувати все у змінну dense_layer, використовуючи об'єкт partial. Потім 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) Визначення оптимізації
Останній крок – побудова оптимізатора. Ви використовуєте середньоквадратичну похибку як функцію втрат. Якщо ви пам'ятаєте навчальний посібник з лінійної регресії, то знаєте, що середньоквадратична похибка обчислюється з різницею між прогнозованим виходом і реальною міткою. Тут мітка – це ознака, оскільки модель намагається реконструювати вхід. Тому вам потрібне середнє значення суми квадратів різниці між прогнозованим виходом і вхідними даними. За допомогою 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 зображень, кількість ітерацій дорівнює 5000, поділеним на 150. У 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")
Графік підтверджує правильність завантаження тестової партії та належність зображення 13 до класу, на якому навчалася модель.
Щоб оцінити модель, ви використаєте значення пікселя цього зображення та перевірите, чи зможе кодер реконструювати те саме зображення після стиснення його до 1024 пікселів. Зверніть увагу, що ви визначаєте функцію для оцінки моделі на різних зображеннях. Модель повинна працювати краще лише на кіньх.
Функція приймає два аргументи:
- df: Імпорт тестових даних
- image_number: вказує, яке зображення імпортувати
Функція розділена на три частини:
- Змініть форму зображення до правильного розміру, тобто 1, 1024
- Подайте на модель невидиме зображення, закодуйте/декодуйте зображення
- Роздрукуйте реальне та реконструйоване зображення
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)
На рисунку оригінальне тестове зображення розміщено ліворуч, а вихід автоенкодеру – праворуч, тому втрату дрібних деталей після стиснення від 1024 до 150 легко оцінити.




