Краткое описание сетей GAN

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

  1. Генератор
  2. Дискриминатор

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

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

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

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

Математическое уравнение порождающей состязательной сети:

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

Первая часть-

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

Вторая часть-

«Z» - это выборка случайного шума, а G (z) - изображение, сгенерированное с использованием выборки шума. Объяснение этого термина очень похоже. Генератор всегда хочет максимизировать вероятность того, что дискриминатор обманут сгенерированными изображениями. Это означает, что генератор должен стремиться максимизировать D (G (z)), поэтому он должен минимизировать 1- D (G (z)) и, следовательно, log (1-D (G (z))).

Создание изображений знаменитостей с использованием GAN

Набор изображений знаменитостей:

Набор данных CelebA - это коллекция из более чем 200 000 лиц знаменитостей с аннотациями. Поскольку в этом блоге я просто собираюсь сгенерировать лица, я не принимаю во внимание аннотации.

1) .Получение данных: -

import helper
helper.download_extract('celeba', data_dir)

Я создал файл helper.py, через который вы можете загружать изображения набора данных CelebA. При запуске этого фрагмента кода он загрузит набор данных CelebA (ссылка на исходный код приведена ниже).

2) .Предварительная обработка изображений: -

Поскольку я работаю только с лицами, я уменьшил его размер до 28 * 28, чтобы получить хорошие результаты. Я обрезал часть изображения, которая не включает часть изображения.

#snippet of Helper python file which preprocess the given image dataset.
def get_image(image_path, width, height, mode):
    """
    Read image from image_path
    :param image_path: Path of image
    :param width: Width of image
    :param height: Height of image
    :param mode: Mode of image
    :return: Image data
    """
    image = Image.open(image_path)
if image.size != (width, height):  
       
        face_width = face_height = 108
        j = (image.size[0] - face_width) // 2
        i = (image.size[1] - face_height) // 2
        image = image.crop([j, i, j + face_width, i + face_height])
        image = image.resize([width, height], Image.BILINEAR)
return np.array(image.convert(mode))

Так как Generative Adversarial Network очень сложно обучить (вы можете проверить эту ссылку, чтобы узнать почему обучение Generative Adversarial Network так сложно?).

Чтобы получить точные результаты, у нас должен быть хороший графический процессор (4 ГБ или больше), запустив этот фрагмент кода, вы можете узнать, установлен ли тензорный поток с графическим процессором или нет.

from distutils.version import LooseVersion
import warnings
import tensorflow as tf
# Check TensorFlow Version
assert LooseVersion(tf.__version__) >= LooseVersion('1.0'), 'Please use TensorFlow version 1.0 or newer.  You are using {}'.format(tf.__version__)
print('TensorFlow Version: {}'.format(tf.__version__))
# Check for a GPU
if not tf.test.gpu_device_name():
    warnings.warn('No GPU found. Please use a GPU to train your neural network.')
else:
    print('Default GPU Device: {}'.format(tf.test.gpu_device_name()))

3). Входные данные модели и сетевая архитектура.

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

Архитектура генератора: -

def generator(z, out_channel_dim, is_train=True, alpha=0.2, keep_prob=0.5):
  
    with tf.variable_scope('generator', reuse=(not is_train)):
        # First fully connected layer, 4x4x1024
        fc = tf.layers.dense(z, 4*4*1024, use_bias=False)
        fc = tf.reshape(fc, (-1, 4, 4, 1024))
        bn0 = tf.layers.batch_normalization(fc, training=is_train)
        lrelu0 = tf.maximum(alpha * bn0, bn0)
        drop0 = tf.layers.dropout(lrelu0, keep_prob, training=is_train)
        
        # Deconvolution, 7x7x512
        conv1 = tf.layers.conv2d_transpose(drop0, 512, 4, 1, 'valid', use_bias=False)
        bn1 = tf.layers.batch_normalization(conv1, training=is_train)
        lrelu1 = tf.maximum(alpha * bn1, bn1)
        drop1 = tf.layers.dropout(lrelu1, keep_prob, training=is_train)
        
        # Deconvolution, 14x14x256
        conv2 = tf.layers.conv2d_transpose(drop1, 256, 5, 2, 'same', use_bias=False)
        bn2 = tf.layers.batch_normalization(conv2, training=is_train)
        lrelu2 = tf.maximum(alpha * bn2, bn2)
        drop2 = tf.layers.dropout(lrelu2, keep_prob, training=is_train)
        
        # Output layer, 28x28xn
        logits = tf.layers.conv2d_transpose(drop2, out_channel_dim, 5, 2, 'same')
        
        out = tf.tanh(logits)
        
        return out
tests.test_generator(generator, tf)

Архитектура генератора имеет первый плотный слой и полностью связанный слой после этого деконволюционного слоя (каждый уровень содержит слой batch_normalization, просачивающийся relu и dropout, кроме выходного слоя). Генератор принимает случайный вектор шума z, после чего он преобразуется в форму 4D и передает его в ряд слоев с повышающей дискретизацией. каждый уровень повышающей дискретизации представляет собой операцию транспонированной свертки, то есть операцию деконволюции.

Все свертки транспонирования с глубиной, уменьшающейся от 1024 до 3, что представляет собой цветное изображение RGB. Последний слой выводит тензор 28 x28x3 через функцию гиперболического тангенса (tanh).

Архитектура Дискриминатора: -

def discriminator(images, reuse=False, alpha=0.2, keep_prob=0.5):
    
    with tf.variable_scope('discriminator', reuse=reuse):
        # Input layer is 28x28xn
        # Convolutional layer, 14x14x64
        conv1 = tf.layers.conv2d(images, 64, 5, 2, padding='same', kernel_initializer=tf.contrib.layers.xavier_initializer())
        lrelu1 = tf.maximum(alpha * conv1, conv1)
        drop1 = tf.layers.dropout(lrelu1, keep_prob)
        
        # Strided convolutional layer, 7x7x128
        conv2 = tf.layers.conv2d(drop1, 128, 5, 2, 'same', use_bias=False)
        bn2 = tf.layers.batch_normalization(conv2)
        lrelu2 = tf.maximum(alpha * bn2, bn2)
        drop2 = tf.layers.dropout(lrelu2, keep_prob)
        
        # Strided convolutional layer, 4x4x256
        conv3 = tf.layers.conv2d(drop2, 256, 5, 2, 'same', use_bias=False)
        bn3 = tf.layers.batch_normalization(conv3)
        lrelu3 = tf.maximum(alpha * bn3, bn3)
        drop3 = tf.layers.dropout(lrelu3, keep_prob)
        
        # fully connected
        flat = tf.reshape(drop3, (-1, 4*4*256))
        logits = tf.layers.dense(flat, 1)
        out = tf.sigmoid(logits)
        
        return out, logits
tests.test_discriminator(discriminator, tf)

Работа Дискриминатора заключается в том, чтобы определить, какое изображение настоящее, а какое - поддельное. Дискриминатор также представляет собой 4-х слойную CNN с пакетной нормализацией и просачивающимся слоем relu (кроме входного слоя). Дискриминатор получает выходное изображение (размер 28 * 28 * 3) и выполняет на нем свертки. наконец, дискриминатор показывает выходные вероятности, чтобы показать, является ли изображение реальным или поддельным, с помощью логистической сигмоидной функции.

Когда дискриминатор видит различия в изображении, он отправляет сигнал градиента в генератор, и этот сигнал проходит от дискриминатора к генератору.

4) .Потеря генератора и потеря дискриминатора: -

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

def model_loss(input_real, input_z, out_channel_dim, alpha=0.2, smooth_factor=0.1):
    
    # TODO: Implement Function
    d_model_real, d_logits_real = discriminator(input_real, alpha=alpha)
    
    d_loss_real = tf.reduce_mean(
        tf.nn.sigmoid_cross_entropy_with_logits(logits=d_logits_real,
                                                labels=tf.ones_like(d_model_real) * (1 - smooth_factor)))
    
    input_fake = generator(input_z, out_channel_dim, alpha=alpha)
    d_model_fake, d_logits_fake = discriminator(input_fake, reuse=True, alpha=alpha)
    
    d_loss_fake = tf.reduce_mean(
        tf.nn.sigmoid_cross_entropy_with_logits(logits=d_logits_fake, labels=tf.zeros_like(d_model_fake)))
    
    g_loss = tf.reduce_mean(
        tf.nn.sigmoid_cross_entropy_with_logits(logits=d_logits_fake, labels=tf.ones_like(d_model_fake)))
return d_loss_real + d_loss_fake, g_loss
tests.test_model_loss(model_loss)

Обучение и результаты: -

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

Создано изображений: -

и так далее постоянно создаются новые лица….

У меня также есть предварительно обученная сеть здесь, и если вы хотите запустить GAN, используя эти предварительно обученные сети, используйте этот файл python, который я предоставляю здесь.

после запуска будет сгенерирован набор из 10 поддельных изображений. некоторые из них-

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

На этом завершаются все удивительные вещи, связанные с генеративной состязательной сетью.

Использованная литература:-

  1. Учебное пособие по генеративным состязательным сетям
  2. Блог Шравана о GAN
  3. Хороший учебник по генеративной состязательной сети
  4. Понимание генеративной адерсарной сети k

Код этого проекта доступен в моем Github-: https://github.com/HACKERSHUBH/Face-Genaration-using-Generative-Adversarial-Network.