🤖 Генеративная состязательная сеть (GAN) для чайников – пошаговое руководство
Лучшее руководство для новичков по пониманию, созданию и обучению GAN с надежным кодом на Python.
Эта статья познакомит вас со всем необходимым для вхождения в мир генеративных состязательных сетей. Никакого предварительного знакомства с GANами не требуется. Мы предоставим пошаговое руководство по обучению GANов на наборах данных с большими изображениями и по их использованию для генерации новых лиц знаменитостей с помощью Keras.
Генеративная Состязательная Сеть – самая интересная идея в машинном обучении за последние десять лет.
Хотя генеративная состязательная сеть – это старая идея, происходящая из теории игр, они были введены в коммьюнити машинного обучения в 2014-м Йэном Гудфеллоу и соавторами в статье "Генеративные состязательные сети". Как же работают GAN и для чего они хороши?
GANы могут создавать изображения, выглядящие как фотографии человеческих лиц, несмотря на то, что эти лица не принадлежат ни одному реальному человеку.
В прошлой статье мы уже видели, как генерировать фотореалистичные изображения с помощью вариационного автоэнкодера. Наш VAE был обучен на хорошо известном наборе данных лиц знаменитостей.
VAE обычно генерируют размытые и не фотореалистичные изображения. Это и является стимулом к созданию генеративных состязательных сетей (GANов).
В этой статье мы увидим, как GANы предлагают совершенно иной подход к генерации данных, похожих на тренировочные данные.
Игра вероятностей
Генерация новых данных – это игра вероятностей. Когда мы наблюдаем мир вокруг себя и собираем данные, мы производим эксперимент. Простой пример – это фотографирование лиц знаменитостей.
Это можно считать вероятностным экспериментом с неизвестным результатом X, также называемого случайной переменной.
Если эксперимент повторяется несколько раз, мы обычно определяем вероятность того, что случайная переменная X примет значение x, как долю количества раз, в которых произошло x, по отношению к общему количеству экспериментов.
Например, мы можем определить вероятность того, что наше лицо будет лицом Тайриза, знаменитого певца.
Набор всех возможных результатов такого эксперимента образует так называемое пространство выборки, обозначаемое символом "омега" (в нашем случае – все возможные лица знаменитостей).
Таким образом, мы можем считать вероятность функцией, принимающей один из результатов (элемент из пространства выборки – в нашем случае фото знаменитости) и возвращающей неотрицательное действительное число, такое, чтобы сумма этих чисел для всех результатов была равна 1.
Мы также называем это функцией распределения вероятности P(X). Если мы знаем пространство выборки (все возможные лица знаменитостей) и распределение вероятности (вероятность появления каждого лица), у нас есть полное описание эксперимента, и мы можем делать выводы о его результатах.
Вы можете освежить свои знания о вероятностях, прочитав нашу статью.
Распределение вероятностей лиц знаменитостей
Генерацию новых лиц можно определить как задачу генерации случайной переменной. Лицо описывается случайными переменными, при этом значения RGB его пикселей "сплющиваются" в вектор из N чисел.
Наши лица знаменитостей имеют ширину 218 пикселей, высоту 178 пикселей и 3 цветовых канала. Таким образом, каждый вектор будет иметь 116412 измерений.
Если мы построим пространство со 116412 (N) измерениями, каждое лицо будет точкой в этом пространстве. Функция распределения вероятности лиц знаменитостей P(X) поставит каждому лицу в соответствие неотрицательное целое число, чтобы сумма этих чисел была равна 1.
Некоторые точки этого пространства, скорее всего, представляют лица знаменитостей, а многие другие, скорее всего, не представляют.
GAN генерирует новое лицо знаменитости, генерируя новый вектор, следуя распределению вероятности лиц знаменитостей в векторном пространстве размерности N.
Проще говоря, GAN генерирует случайную переменную в соответствии с заданным распределением вероятности.
Как генерировать случайные переменные со сложными распределениями?
Распределение вероятности лиц знаменитостей в N-мерном векторном пространстве очень сложное, и мы не знаем, как напрямую генерировать сложные случайные переменные.
К счастью, мы можем представить нашу сложную случайную переменную в виде функции, примененной к равномерной случайной переменной. В этом заключается идея метода трансформации. Он сначала генерирует N независимых друг от друга равномерных случайных переменных, что просто. Затем она применяет е этой простой случайной переменной очень сложную функцию! Очень сложные функции естественно аппроксимируются нейронной сетью. После обучения нейронная сеть сможет принимать в качестве входа простую N-мерную равномерную случайную переменную и вернет другую N-мерную случайную переменную, имеющую наше распределение вероятности лиц знаменитостей. Это – основная идея, лежащая в основе генеративных состязательных сетей.
Почему "генеративные состязательные сети"?
На каждой итерации обучения нейронной сети трансформации мы могли бы сравнивать выборку лиц из тренировочного набора данных лиц знаменитостей с выборкой сгенерированных лиц.
Теоретически, мы могли бы использовать эти выборки для сравнения истинного распределения со сгенерированным распределением, используя подход максимального среднего расхождения (Maximum Mean Discrepancy, MMD). Он предоставил бы нам ошибку несоответствия распределения, которую можно было бы использовать для обновления весов методом обратного распространения ошибки (backpropagation). На практике этот прямой метод очень трудно реализовать.
Вместо прямого сравнения истинного и сгенерированного распределений, GANы решают не-дискриминационную задачу между истинной и сгенерированной выборками.
GAN имеет три основных компонента: модель генератора для генерации новых данных, модель дискриминатора для определения, являются ли сгенерированные данные реальными лицами, и состязательная сеть, которая сталкивает их друг против друга.
Генеративная часть отвечает за ввод N-мерных равномерно распределенных случайных чисел (шума) и генерацию ложных лиц. Генератор усваивает вероятность P(X), где X – это входные данные.
Дискриминационная часть – это простой классификатор, оценивающий и отделяющий сгенерированные лица от истинных лиц знаменитостей. Дискриминатор усваивает условную вероятность P(Y | X), где X – это входные данные, а Y – метка.
Обучение генеративных состязательных сетей
Генеративная сеть обучается с целью максимизации итоговой ошибки классификации (между истинными и сгенерированными данными), а дискриминационная сеть обучается с целью минимизации этой ошибки. Вот откуда происходит термин "состязательная сеть".
С точки зрения теории игр, равновесие достигается, когда генератор создает изображения, соответствующие распределению лиц знаменитостей с той же вероятностью, с которой дискриминатор предсказывает, истинное изображение или ложное, как если бы он просто бросал монетку.
Важно, чтобы обе сети в процессе обучения учились с одинаковой скоростью и сходились вместе. Часто происходит, что дискриминационная сеть слишком быстро обучается распознавать фейковые изображения, загоняя генеративную в тупик.
При обучении дискриминатора мы игнорируем потери генератора и используем только функцию потерь дискриминатора, которая штрафует дискриминатор за неверную классификацию сгенерированных лиц как истинных или истинных лиц как фейковых. Веса дискриминатора обновляются методом обратного распространения (backpropagation). Веса генератора не обновляются.
При обучении генератора мы используем функцию потерь генератора, штрафующую генератор за неудачный обман дискриминатора, то есть за генерацию лица, которое дискриминатор признал фейковым. В процессе обучения генератора дискриминатор заморожен, и только веса генератора обновляются методом обратного распространения.
Это и есть магия, синтезирующая лица знаменитостей с помощью GAN. Сходимость часто выглядит мимолетной, а не стабильной. Если вы все сделали правильно, GANы выдают невероятные результаты, как показано ниже.
Построение и обучение модели DCGAN
В этом разделе мы пройдем через все шаги, необходимые для создания, компиляции и обучения модели DCGAN (Deep Convolution GAN, то есть GAN с применением сверточных слоев).
Дискриминатор
Дискриминатором может быть любой классификатор изображений, даже дерево решений. Мы используем вместо него сверточную нейронную сеть с четырьмя блоками слоев. Каждый блок включает сверточный слой, слой нормализации пакета, еще один сверточный слой с шагом, чтобы уменьшить изображение в 2 раза, и еще один слой нормализации пакета. Результат проходит через группировку усреднения (average pooling), за которой следует полносвязный сигмоидный слой, возвращающий единственную выходную вероятность.
Генератор
Генератор принимает вектор шума с размерностью скрытого пространства и генерирует изображение. Размеры этого изображения должны совпадать с размерами входа дискриминатора (spatial_dim * spatial_dim).
Сначала генератор размножает вектор шума с помощью полносвязного слоя, чтобы получить достаточно данных для преобразования в форму, необходимую для первого блока генератора. Цель этой проекции – получить такие же размеры, как в последнем блоке архитектуры дискриминатора. Как мы покажем ниже, это эквивалентно форме 4 * 4 * количество фильтров в последнем сверточном слое дискриминатора.
Каждый блок генератора применяет развертку (deconvolution) для увеличения изображения и нормализацию пакета. Мы используем 4 блока декодирования и финальный сверточный слой для получения 3-мерного тензора, представляющего фейковое изображение с 3 каналами.
Собственно GAN
Объединенная DCGAN создается добавлением дискриминатора над генератором.
Перед компиляцией полной модели мы должны установить, что модель дискриминатора не обучается. Это заморозит ее веса и сообщит, что единственная обучаемая часть общей сети – это генератор.
Хотя мы и компилируем дискриминатор, нам не нужно компилировать модель генератора, поскольку мы не используем генератор сам по себе.
Этот порядок обеспечивает, что дискриминатор будет обновляться в нужное время, а в остальное время будет заморожен. Таким образом, если мы обучаем всю модель, она обновляет только генератор, а когда мы обучаем дискриминатор, обновляется только дискриминатор.
Обучение GAN
Теперь мы приступаем к сложной и длительной части: обучению генеративной состязательной сети. Поскольку GAN состоит из двух раздельно обучаемых сетей, определить сходимость трудно.
Следующие шаги выполняются в прямом и обратном направлении, позволяя GAN справиться с проблемами генерации, которые иначе оказались бы неразрешимыми:
Шаг 1. Выбираем несколько реальных изображений из тренировочного набора
Шаг 2. Генерируем несколько фейковых изображений. Для этого мы создаем несколько случайных векторов шума и создаем из них изображения с помощью генератора.
Шаг 3. Обучаем дискриминатор на протяжении одной или большего количества эпох, используя как реальные, так и фейковые изображения. При этом будут обновляться только веса дискриминатора, поскольку мы пометим все реальные изображения как 1, а фейковые как 0.
Шаг 4. Создаем еще несколько фейковых изображений.
Шаг 5. Обучаем полную модель GAN на протяжении одной или большего количества эпох, используя только фейковые изображения. При этом будут обновляться только веса генератора, а всем фейковым изображениям будет назначена метка 1.
Как мы видим, наш генератор работает неплохо. Сгенерированные лица выглядят неплохо, хотя качество фото не такое хорошее, как в наборе данных CelebA. Это произошло потому, что мы обучили наш GAN на уменьшенных изображениях 64 * 64, которые гораздо более размыты, чем исходные изображения 218 * 178.
Разница между VAE и GAN
По сравнению с лицами, сгенерированными Вариационным АвтоЭнкодером из нашей прошлой статьи, лица, сгенерированные DCGAN, выглядят достаточно яркими, чтобы представлять лица, близкие к реальности.
GAN'ы, как правило, намного лучшие глубокие генеративные модели, чем VAE. Хотя VAE работают только в скрытом пространстве, их легче создавать и проще обучать. Можно считать, что VAE обучаются с частичным привлечением учителя (semi-supervised learning), поскольку они обучаются минимизировать потери при воспроизведении конкретных изображений. С другой стороны, GAN'ы – это уже задача обучения без учителя.
Заключение
В этой статье я рассказал, как генеративные состязательные сети могут аппроксимировать распределение вероятности большого набора изображений, и использовать эту аппроксимацию для генерации фотореалистичных изображений.
Я предоставил работающий код на Python, который позволит вам строить и обучать собственные GANы для решения ваших задач.
Вы можете больше узнать о GANах на Google Developers или из статьи Джозефа Рокка. Вариационные автоэнкодеры были рассмотрены в моей прошлой статье.
Хочу освоить алгоритмы и структуры данных, но сложно разобраться самостоятельно. Что делать?
Алгоритмы и структуры данных действительно непростая тема для самостоятельного изучения: не у кого спросить и что-то уточнить. Поэтому мы запустили курс «Алгоритмы и структуры данных», на котором в формате еженедельных вебинаров вы:
- изучите сленг, на котором говорят все разработчики независимо от языка программирования: язык алгоритмов и структур данных;
- научитесь применять алгоритмы и структуры данных при разработке программ;
- подготовитесь к техническому собеседованию и продвинутой разработке.
Курс подходит как junior, так и middle-разработчикам.