Автоэнкодер в TensorFlow с примером
⚡ Умное резюме
Автокодировщики сжимают входные данные в меньшее внутреннее представление, а затем восстанавливают его, изучая наиболее важные признаки без меток. В этом пошаговом руководстве показано, как объединить четыре полносвязных слоя в TensorFlow и восстановить изображения лошадей из набора данных CIFAR-10.
Что такое автоэнкодер в глубоком обучении?
An автоассоциатор Это инструмент для эффективного обучения кодированию данных. бесконтрольный манера. Это один из типов. искусственная нейронная сеть Это помогает изучить представление наборов данных для уменьшения размерности путем обучения нейронной сети игнорировать шум сигнала. Это отличный инструмент для воссоздания входных данных.
Проще говоря, машина принимает, скажем, изображение и может создать похожее на него изображение. Входные данные в такой нейронной сети не размечены, то есть сеть способна обучаться без учителя. Точнее, входные данные кодируются сетью таким образом, чтобы сосредоточиться только на наиболее важных признаках. Это одна из причин, почему автокодировщик популярен для уменьшения размерности. Кроме того, автокодировщики могут использоваться для создания моделей генеративного обучения. Например, нейронную сеть можно обучить на наборе лиц, а затем она сможет создавать новые лица.
Как работает автоэнкодер TensorFlow?
Цель автоэнкодера — получить аппроксимацию входных данных, сосредоточив внимание только на основных функциях. Вы можете подумать, почему бы просто не научиться копировать и вставлять входные данные для получения выходных данных. Фактически, автокодировщик — это набор ограничений, которые заставляют сеть изучать новые способы представления данных, отличные от простого копирования выходных данных.
Типичный автокодировщик определяется с помощью входных данных, внутреннего представления и выходных данных (приближения к входным данным). Обучение происходит в слоях, прикрепленных к внутреннему представлению. Фактически, существует два основных блока слоев, которые выглядят как традиционная нейронная сеть. Небольшое отличие заключается в том, что слой, содержащий выходные данные, должен быть равен входным данным. На приведенной ниже диаграмме исходные входные данные поступают в первый блок, называемый кодировщиком. Это внутреннее представление сжимает (уменьшает) размер входных данных. Во втором блоке происходит восстановление входных данных. Это фаза декодирования.

Модель обновит веса, минимизировав функцию потерь. Модель наказывается, если выходные данные реконструкции отличаются от входных.
В частности, представьте себе изображение размером 50×50 (то есть 2,500 пикселей) и нейронную сеть всего с одним скрытым слоем, состоящим из ста нейронов. Обучение происходит на карте признаков, которая в двадцать пять раз меньше входного изображения. Это означает, что сети необходимо найти способ восстановить 2,500 пикселей, используя вектор нейронов, равный 100.
Пример составного автоэнкодера
В этом уроке по автокодировщику вы узнаете, как использовать многослойный автокодировщик. Его архитектура похожа на традиционную нейронную сеть. Входные данные поступают в скрытый слой для сжатия, или уменьшения их размера, а затем достигают слоев реконструкции. Цель состоит в том, чтобы получить выходное изображение, максимально приближенное к оригиналу. Модель должна научиться выполнять свою задачу в рамках заданных ограничений, то есть с меньшей размерностью.
В настоящее время автокодировщики в глубоком обучении в основном используются для шумоподавления изображений. Представьте себе изображение с царапинами; человек все еще способен распознать их. Идея автокодировщика с шумоподавлением заключается в добавлении шума к изображению, чтобы заставить нейронную сеть изучить закономерности, лежащие в основе данных.
Другое полезное семейство автокодировщиков Глубокое обучение Это вариационный автокодировщик. Этот тип сети может генерировать новые изображения. Представьте, что вы обучаете сеть на изображении мужчины; такая сеть может создавать новые лица.
В таблице ниже представлен сложенный автокодировщик, созданный в этом руководстве, в сравнении с другими семействами, с которыми вы, вероятно, столкнетесь, что позволяет легко сравнить ограничения, добавляемые каждым из них.
| Тип автокодировщика | Добавлено ограничение | Типичное использование |
|---|---|---|
| Неполный / многослойный | Кодирующий слой уже, чем входные данные. | Снижение размерности, демонстрация признаковtracпроизводство |
| шумодав | На вход добавлен шум, целевой сигнал очищен. | Очистка изображения и сигнала |
| Разреженный | Штраф за количество активных единиц | Интерпретируемые, основанные на частях характеристики |
| Вариационный | Кодирующий слой изучает распределение вероятностей | Создание новых образцов |
Как создать автоэнкодер с помощью 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) Импортируйте данные
Согласно официальному сайту, загрузку данных можно выполнить с помощью следующего кода. Код автокодировщика загрузит данные в словарь, содержащий сами данные и метки. Обратите внимание, что код представляет собой функцию.
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 пикселя сведены к 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 машине, путь может быть filename = 'E:\cifar-10-batches-py\data_batch_' + str(i)
Шаг 4) Создайте набор обучающих данных
Чтобы ускорить и упростить обучение, вы будете обучать модель только на изображениях лошадей. Лошади имеют метку 7 в данных меток. Как указано в документации к набору данных 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")
В результате выполнения запроса возвращается представленное ниже изображение в оттенках серого, а также подтверждается правильность преобразования из 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) Определите параметры
На первом этапе необходимо определить количество нейронов в каждом слое, скорость обучения и гиперпараметр регуляризатора.
Перед этим необходимо импортировать функцию partial. Это лучший способ определить параметры полносвязных слоев. Приведенный ниже код определяет значения архитектуры автокодировщика. Как указывалось ранее, кодировщик имеет два слоя: 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 из пакета estimator. В том же самом estimator можно добавить регуляризатор с помощью 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)
Примечание к версии: В TensorFlow 2 был удалён модуль tf.contrib. Его прямой заменой стали tf.keras.initializers.GlorotUniform() для xavier_initializer() и tf.keras.regularizers.l2() для l2_regularizer().
Шаг 2) Определение слоев
Все параметры полносвязных слоев заданы; вы можете упаковать все в переменную dense_layer, используя объект partial. Затем dense_layer использует функцию активации ELU, инициализацию Ксавье и 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). Если вы помните руководство по линейной регрессии, вы знаете, что 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 изображений, то количество итераций равно 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.




