www.machinelearningmastery.ru

Машинное обучение, нейронные сети, искусственный интеллект
Header decor

Home

Руководство мастера по состязательным автоэнкодерам: Часть 2. Исследование скрытого пространства с помощью состязательных автоэнкодеров.

Дата публикации Aug 7, 2017

«Эта статья является продолжениемРуководство мастера по автоэнкодерам: Часть 1Если вы не читали его, но знакомы с основами автоэнкодеров, продолжайте. Вам нужно немного узнать о теории вероятностей, которую можно найтиВот«.

Часть 1:Автоассоциатор?

Мы остановили часть 1, передав значение (0, 0) нашему обученному декодеру (у которого есть 2 нейрона на входе) и найдя его выход. Это выглядело расплывчато и не представляло собой четкую цифру, оставляя нас с выводом, что выход кодерачас(также известный как скрытый код) не был распределен равномерно в определенном пространстве.

Таким образом, наша основная цель в этой части будет заключаться в том, чтобы заставить выходной сигнал энкодера соответствовать заданному предварительному распределению, это требуемое распределение может быть нормальным (гауссовым) распределением, равномерным распределением, гамма-распределением…. Это должно затем привести к равномерному распределению скрытого кода (выходного сигнала кодера) по данному предшествующему распределению, что позволило бы нашему декодеру изучить сопоставление от предшествующего распределения данных (в нашем случае распределение изображений MNIST).

Если вы абсолютно ничего не поняли из приведенного выше абзаца.

Допустим, вы учитесь в колледже и решили заняться машинным обучением (я не мог думать о другом курсе: p) как об одном из ваших курсов. Теперь, если преподаватель курса не предоставит учебный план или справочник, что вы будете изучать для своих выпускных? (предположим, что ваши занятия не помогли).

Вам могут задавать вопросы из любого подполя ML, что бы вы сделали? Макияж вещи с тем, что вы знаете ??

Это то, что происходит, если мы не ограничиваем вывод нашего кодера, чтобы следовать некоторому распределению, декодер не может узнать отображение любого числа на изображение.

Но, если вам дано правильное руководство по учебному плану, вы можете просто просмотреть материалы до экзамена, и у вас будет представление о том, чего ожидать.

Точно так же, если мы вынудим вывод кодера следовать известному распределению, подобному гауссовскому, то он может научиться расширять скрытый код для охвата всего распределения и изучать отображения без каких-либо пробелов.

Хорошо или плохо?

Теперь мы знаем, что автоэнкодер состоит из двух частей, каждая из которых выполняет совершенно противоположную задачу.

Два человека схожего характера никогда не могут остаться в одиночестве, для согласования нужны две противоположности.

- Рам Мохан

Кодер, который используется для получения скрытого кода (выход кодера) от входа с ограничением, что размер скрытого кода должен быть меньше, чем размер входного сигнала, и, во-вторых, декодер, который принимает этот скрытый код и пытается восстановить оригинальное изображение.

Блок-схема автоэнкодера

Давайте посмотрим, как распределились выходные данные кодера, когда мы ранее реализовали наш автоматический кодер (проверкачасть 1):

Гистограмма кодера и распределение

Из графика распределения (который направо) мы ясно видим, что выходное распределение нашего кодера повсюду. Первоначально кажется, что распределение сосредоточено в 0 с большинством значений, являющихся отрицательными. На более поздних этапах обучения отрицательные образцы распределяются дальше от 0 по сравнению с положительными (кроме того, мы можем даже не получить такое же распределение, если повторим эксперимент). Это приводит к большим промежуткам в распределении кодера, что не очень хорошо, если мы хотим использовать наш декодер в качестве генеративной модели.

Но почему эти пробелы вредны для нашего дистрибутива?

Если мы дадим ввод, который попадает в этот промежуток, обученному декодеру, то он выдаст странно выглядящие изображения, которые не представляют цифры на своем выходе (я знаю, в третий раз).

Другое важное наблюдение, которое было сделано, состоит в том, что обучение автоэнкодеру дает нам скрытые коды с похожими изображениями (например, все 2 или 3), которые находятся далеко друг от друга в евклидовом пространстве. Это, например, может привести к тому, что все 2 в нашем наборе данных будут отображены в разные области пространства. Мы хотим, чтобы скрытый код имел осмысленное представление, держа изображения похожих цифр близко друг к другу. Что-то вроде этого:

Хорошее 2D распределение

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

Теперь мы рассмотрим Adversarial Autoencoders, которые могут решить некоторые из вышеупомянутых проблем.


Автоматический кодер Adversarial очень похож на автоматический кодер, но кодер обучен в состязательном порядке, чтобы заставить его вывести требуемое распределение.

Понимание Adersarial Autoencoders (AAE) требует знания Generative Adversarial Networks (GAN), я написал статью о GAN, которую можно найти здесь:

GANs N ’Roses

«В этой статье предполагается, что читатель знаком с нейронными сетями и использует Tensorflow. Если нет, мы бы попросили вас ...

medium.com

Если вы уже знаете о GAN, вот краткое резюме (не стесняйтесь пропустить этот раздел, если вы помните следующие два пункта):

дискриминатор
Генератор
  • У GAN есть две нейронные сети, генератор и дискриминатор.
  • Генератор, хорошо генерирует поддельные изображения. Мы обучаем дискриминатор отличать реальные изображения из нашего набора данных от поддельных, сгенерированных нашим генератором.
  • Первоначально генератор генерирует некоторый случайный шум (потому что его вес будет случайным). После обучения нашего дискриминатора распознавать этот случайный шум и реальные изображения, мы подключим наш генератор к нашему дискриминатору и backprop только через генератор с ограничением, что выход дискриминатора должен быть 1 (т.е. дискриминатор должен классифицировать выход генератора как реальные образы).
  • Мы снова обучим наш дискриминатор, чтобы теперь отличать новые поддельные изображения от нашего генератора и настоящие от нашей базы данных. За этим следует тренировка генератора, чтобы он генерировал изображения, выглядящие лучше.
  • Мы продолжим этот процесс до тех пор, пока генератор не станет настолько хорош в создании поддельных изображений, что дискриминатор больше не сможет отличить реальные изображения от поддельных.
  • В конце концов, у нас останется генератор, который может создавать реально выглядящие поддельные изображения с произвольным набором чисел в качестве входных данных.

Вот блок-схема состязательного автоэнкодера:

Блок-схема AAE
  • x → Входное изображение
  • q (z / x) → Выход кодера при заданном входе x
  • z → скрытый код (ложный ввод), z взят из q (z / x)
  • z ’→ реальный вклад с необходимым распределением
  • p (x / z) → Выход декодера задан z
  • D () → Дискриминатор
  • x_ → Восстановленное изображение

Опять же, наша главная задача - принудительно заставить кодировщик выводить значения, которые имеют заданное предварительное распределение (это может быть нормальным, гамма-распределения). Мы будем использовать кодер (q (z / x)) в качестве нашего генератора, дискриминатор, чтобы сказать, являются ли выборки из предыдущего распределения (p (z)) или из выходных данных кодера (z) и декодера ( p (x / z)), чтобы вернуть исходное входное изображение.

Чтобы понять, как эту архитектуру можно использовать для наложения предшествующего распределения на выход кодера, давайте посмотрим, как мы обучаем AAE.

Обучение AAE имеет 2 этапа:

  • Этап реконструкции:

Мы обучим и кодер, и декодер минимизировать потери при восстановлении (среднеквадратическая ошибка между входными и выходными изображениями декодера, ознакомьтесь с частью 1 для получения более подробной информации). Забудьте, что дискриминатор даже существует на этом этапе (я выделил части, которые не требуются на этом этапе).

Этап реконструкции

Как обычно, мы передадим входные данные в кодировщик, который даст нам наш скрытый код, позже мы передадим этот скрытый код в декодер, чтобы вернуть входное изображение. Мы проведем обратный анализ как веса кодера, так и веса декодера, чтобы уменьшить потери при восстановлении.

  • Этап регуляризации:

На этом этапе нам нужно обучить дискриминатор и генератор (который является ничем иным, как нашим кодером). Просто забудьте, что декодер существует.

Обучение дискриминатора

Во-первых, мы обучаем дискриминатор для классификации выходного сигнала кодера (z) и некоторого случайного входного сигнала (z ’, у нас будет требуемое распределение). Например, случайный вход может быть нормально распределен со средним значением 0 и стандартным отклонением 5.

Таким образом, дискриминатор должен дать нам выход 1, если мы передадим случайные входы с желаемым распределением (действительные значения), и должен дать нам выход 0 (поддельные значения), когда мы передадим выход кодера. Интуитивно понятно, что и выход энкодера, и случайные входы в дискриминатор должны иметь одинаковый размер.

Следующим шагом будет принуждение кодера выводить скрытый код с желаемым распределением. Для этого мы подключим выход кодера в качестве входа к дискриминатору:

Мы установим вес дискриминатора в соответствии с тем, чем он является в настоящее время (сделаем его необучаемым), и установим цель на 1 на выходе дискриминатора. Позже мы передаем изображения в кодировщик и находим выход дискриминатора, который затем используется для определения потерь (функция стоимости кросс-энтропии). Мы будем выполнять обратное преобразование только через веса кодера, что заставляет кодер изучать требуемое распределение и выводить его, который будет иметь это распределение (установка целевого значения дискриминатора на 1 должна привести к тому, что кодировщик изучит требуемое распределение, глядя на веса дискриминатора ).


Теперь, когда теоретическая часть далека, давайте посмотрим, как мы можем реализовать это с помощью тензорного потока.

Вот весь код для части 2 (он очень похож на то, что мы обсуждали в части 1):

Naresh1318 / Adversarial_Autoencoder

Adversarial_Autoencoder - руководство мастера по Adversarial Autoencoder

github.com

Как обычно, у нас есть помощникdense():

Я не менял архитектуру кодера и декодера:

Архитектура кодировщика
Архитектура декодера

Вот архитектура дискриминатора:

Дискриминаторная архитектура

Это похоже на нашу архитектуру кодировщика, форма вводаz_dim(batch_size, z_dimна самом деле) и выход имеет форму 1 (batch_size, 1).

Обратите внимание, что я использовал префиксыe_,d_а такжеdc_при определении плотных слоев для кодера, декодера и дискриминатора соответственно. Использование этих обозначений помогает нам собирать веса для легкой тренировки:

Теперь мы знаем, что обучение AAE состоит из двух частей: первая - фаза реконструкции (мы обучим наш авто-кодер реконструировать вход) и фаза регуляризации (сначала обучается дискриминатор, а затем кодер).

Мы начнем этап реконструкции, соединив наш выход кодера со входом декодера:

Я использовалtf.variable_scope(tf.get_variable_scope())каждый раз, когда я вызываю любую из наших определенных архитектур, она позволяет нам распределять веса между всеми вызовами функций (это происходит только в том случае, еслиreuse=True).

Функция потери, как обычно, является среднеквадратичной ошибкой (MSE), с которой мы столкнулись вчасть 1,

Аналогично тому, что мы делали в первой части, оптимизатор (который обновит вес, чтобы уменьшить потери [надеюсь]) реализован следующим образом:

Я не мог с этим поделать: P

Вот и все на этапе реконструкции, затем мы переходим к этапу регуляризации:

Сначала мы обучим дискриминатор различать реальные выборки распределения и поддельные от генератора (в данном случае кодировщика).

  • real_distributionэто заполнитель, который я использовал для передачи значений с требуемым распределением в дискриминатор (это будет наш реальный вклад).
  • encoder_outputподключен к дискриминатору, который даст нам наш вывод дискриминатора для поддельных входовd_fake,
  • Вотreuse=Trueтак как мы хотим, чтобы во втором вызове были одинаковые веса дискриминатора (если это не указано, тензор потока создает новый набор случайно инициализированных весов [но поскольку я использовалget_variable()чтобы создать вес это будет через ошибку]).

Функция потери, которую я использовал для обучения дискриминатора:

Стоимость кросс-энтропии

Это может быть легко реализовано в тензорном потоке следующим образом:

Следующим шагом будет обучение генератора (энкодера) для вывода требуемого распределения. Как мы уже говорили, для этого необходимо, чтобы для цели дискриминатора было установлено значение 1, аd_fakeпеременная (кодировщик, подключенный к дискриминатору [вернуться и посмотреть]). Потери генератора снова являются кросс-энтропийной функцией стоимости.

Чтобы обновить только требуемые веса во время обучения, нам нужно будет передать все эти собранные веса вvar_listпараметр подminimize(), Итак, я передал переменные дискриминатора (dc_var) и генератор (кодировщик) переменных (en_var) во время их этапов обучения.

Мы почти закончили, все, что нам осталось, это передать наши изображения MNIST в качестве входных данных и в качестве цели вместе со случайными числами размераbatch_size, z_dimв качестве входных данных для дискриминатора (это сформирует требуемое распределение).

Обучающая часть может показаться пугающей, но если вы посмотрите на нее некоторое время, вы обнаружите, что она довольно интуитивна.

Параметры, которые я использовал во время обучения:

Я обучил модель для 300 эпох с необходимым распределением, начиная с нормального (гауссова) со средним 0 и 5 в качестве стандартного распределения. Вот выходные данные кодировщика и необходимые распределения вместе с их гистограммами:

Распределение кодера почти соответствует требуемому распределению, и гистограмма показывает нам, что он центрирован по нулю. Отлично, но как насчет дискриминатора, насколько хорошо он справился?

Хорошая новость: потери дискриминатора увеличиваются (становятся хуже), что говорит о том, что ему трудно отличить реальные и фальшивые данные.

Наконец, так как у нас естьz_dim=2(2D значения) мы можем передавать случайные входные данные, которые попадают под требуемое распределение, в наш обученный декодер и использовать его в качестве генератора (я знаю, я все это время вызывал кодировщик в качестве генератора, пока он генерировал ложные входы для дискриминатора, но поскольку декодер научился не отображать эти ложные входные данные для получения цифр на своем выходе, мы можем назвать наш декодер генератором). Я передавал значения от (-10, -10) до (10, 10) через равные промежутки времени в декодер и сохранял его выходные данные, как распределялись цифры:

На приведенном выше рисунке показана четкая кластеризация цифр и их переход при изучении значений, на которых обучается декодер. ААЕ приводит к тому, что промежутки в выходном распределении кодера становятся ближе, что позволило нам использовать декодер в качестве генератора.

Это оно! В следующей части мы сосредоточимся на том, как мы можем использовать AAE для отделения стиля изображения от его содержимого. Это довольно легко реализовать, так как мы сделали большую часть относительно сложных деталей.


Надеюсь, вам понравилась эта статья о AAE. Я бы открыто поощрял любую критику или предложения по улучшению моей работы.

Если вы считаете, что этот контент стоит поделиться, нажмите ❤️, мне нравятся уведомления, которые он мне отправляет !!

← Часть 1:Автоассоциатор?

→ Часть 3:Распутывание стиля и содержания.

Оригинальная статья

Footer decor

© www.machinelearningmastery.ru | Ссылки на оригиналы и авторов сохранены. | map