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

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

  1. Vanilla GAN: это оригинальная архитектура GAN, состоящая из генератора и сети дискриминатора.
  2. DCGAN (глубокая сверточная GAN). Этот тип GAN использует сверточные слои как в сети генератора, так и в сети дискриминатора, что позволяет генерировать изображения с высоким разрешением.
  3. WGAN (Wasserstein GAN): этот тип GAN заменяет традиционную функцию потерь GAN на расстояние Вассерштейна, которое более стабильно во время обучения и приводит к меньшему коллапсу моды.
  4. LSGAN (GAN методом наименьших квадратов): этот тип GAN использует функцию потерь методом наименьших квадратов вместо традиционной бинарной кросс-энтропийной потери, что обеспечивает более стабильный процесс обучения.
  5. CycleGAN: этот тип GAN может переводить изображение из одного домена в другой, например, преобразовывая изображение лошади в изображение зебры.
  6. BEGAN (Генеративные состязательные сети с граничным равновесием): Этот тип GAN использует цель равновесия, которая помогает стабилизировать процесс обучения, а также обеспечивает меру качества сгенерированных изображений.
  7. BigGAN. Этот тип GAN представляет собой большую генеративно-состязательную сеть, которая генерирует изображения высокого разрешения с мелкими деталями и высоким качеством.

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

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

Введение в набор данных

Набор данных рукописных цифр — это набор изображений рукописных цифр вместе с соответствующими им метками (т. е. правильной цифрой). Эти наборы данных обычно используются для обучения и оценки алгоритмов машинного обучения, особенно в области распознавания изображений и компьютерного зрения. Одним из самых популярных наборов данных этого типа является набор данных MNIST, который состоит из 60 000 обучающих изображений и 10 000 тестовых изображений рукописных цифр вместе с соответствующими им метками. Мы собираемся использовать этот набор данных для обучения нашей модели GAN. Изображения в этом наборе данных имеют размер 28x28 пикселей и изображения в градациях серого, и он широко используется в качестве эталонного набора данных для тестирования и сравнения производительности различных алгоритмов машинного обучения. Другие примеры наборов данных рукописных цифр включают набор данных USPS, который содержит изображения почтовых индексов USPS, и набор данных KMNIST, который представляет собой более разнообразный набор рукописных цифр, чем набор данных MNIST.

fig, ax = plt.subplots(ncols = 4, nrows = 4, figsize = (20,20))
for i in range(4):
  for j in range(4):
    ax[i][j].imshow(trainX[(i+1)*(j+1)-1], cmap ='gray_r')

Предварительная обработка

  1. Масштабирование функций. Масштабирование функций – важный этап предварительной обработки данных. Если масштабирование функций не выполняется, алгоритм машинного обучения будет считать большие значения более высокими, а меньшие – меньше, независимо от единицы измерения. Используемый здесь масштабатор — это традиционный масштабатор MinMax. Масштабатор Minmax Преобразование объектов путем масштабирования каждого объекта до заданного диапазона [0,1]
  2. Развернуть размеры. В библиотеке Python NumPy numpy.expand_dims — это функция, которая вставляет новую ось с размером 1. Она принимает входной массив и положение оси, в которое должна быть вставлена ​​новая ось. Он возвращает новый массив со вставленным новым измерением.
def load_real_samples():
  # load mnist dataset
  (trainX, _), (_, _) = load_data()
  # expand to 3d, e.g. add channels dimension
  X = np.expand_dims(trainX, axis=-1)
  # convert from unsigned ints to floats
  X = X.astype('float32')
  # scale from [0,255] to [0,1]
  X = X / 255.0
  return X

Работа условных GAN

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

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

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

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

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

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

Построение модели дискриминатора

В условной GAN (cGAN) сеть дискриминатора отвечает за различение реальных выборок и синтетических выборок, обусловленных входной переменной. Вход в сеть дискриминатора включает в себя как реальные выборки, синтетические выборки, так и переменную кондиционирования. Выход сети дискриминатора представляет собой скалярное значение, обычно от 0 до 1, которое представляет вероятность того, что данная выборка реальна.

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

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

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

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

def define_discriminator_model(in_shape = (28,28,1), n_classes = 10):
  in_label = Input(shape=(1,))
  # embedding for categorical input
  li = Embedding(n_classes, 50)(in_label)
  # scale up to image dimensions with linear activation
  n_nodes = in_shape[0] * in_shape[1]
  li = Dense(n_nodes)(li)
  # reshape to additional channel
  li = Reshape((in_shape[0], in_shape[1], 1))(li)
  # image input
  in_image = Input(shape=in_shape)
  # concat label as a channel
  merge = Concatenate()([in_image, li])
  # downsample
  fe = Conv2D(128, (3,3), strides=(2,2), padding='same')(merge)
  fe = LeakyReLU(alpha=0.2)(fe)
  # downsample
  fe = Conv2D(128, (3,3), strides=(2,2), padding='same')(fe)
  fe = LeakyReLU(alpha=0.2)(fe)
  # flatten feature maps
  fe = Flatten()(fe)
  # dropout
  fe = Dropout(0.4)(fe)
  # output
  out_layer = Dense(1, activation='sigmoid')(fe)
  # define model
  model = Model([in_image, in_label], out_layer)
  # compile model
  opt = Adam(lr=0.0002, beta_1=0.5)
  model.compile(loss='binary_crossentropy', optimizer=opt, metrics=['accuracy'])
  return model
discriminator = define_discriminator_model()
discriminator.summary()
plot_model(discriminator, to_file='discriminator_plot.png', show_shapes=True, show_layer_names=True)

из приведенной выше модели графика мы видим, что модель дискриминатора принимает два входа: первый — это метка, а другой — изображение размера (28,28). Затем метка класса передается через слой Embedding с размером 50. Это означает, что каждый из 10 классов для набора данных MNIST (от 0 до 9) будет отображаться в другое представление вектора из 50 элементов, которое будет изучено дискриминатором. модель. Затем выходные данные встраивания передаются на полносвязный слой с линейной активацией.

Модель генератора зданий

В условной GAN (cGAN) сеть генератора отвечает за создание синтетических образцов, которые похожи на реальные образцы из целевого распределения и согласуются с переменной кондиционирования. Сеть генератора принимает в качестве входных данных как вектор случайного шума, так и обусловливающую переменную и создает синтетическую выборку.

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

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

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

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

def define_generator(latent_dim, n_classes=10):
  in_label = Input(shape=(1,))
  # embedding for categorical input
  li = Embedding(n_classes, 50)(in_label)
  # linear multiplication
  n_nodes = 7 * 7
  li = Dense(n_nodes)(li)
  # reshape to additional channel
  li = Reshape((7, 7, 1))(li)
  # image generator input
  in_lat = Input(shape=(latent_dim,))
  # foundation for 7x7 image
  n_nodes = 128 * 7 * 7
  gen = Dense(n_nodes)(in_lat)
  gen = LeakyReLU(alpha=0.2)(gen)
  gen = Reshape((7, 7, 128))(gen)
  # merge image gen and label input
  merge = Concatenate()([gen, li])
  # upsample to 14x14
  gen = Conv2DTranspose(128, (4,4), strides=(2,2), padding='same')(merge)
  gen = LeakyReLU(alpha=0.2)(gen)
  # upsample to 28x28
  gen = Conv2DTranspose(128, (4,4), strides=(2,2), padding='same')(gen)
  gen = LeakyReLU(alpha=0.2)(gen)
  # output
  out_layer = Conv2D(1, (7,7), activation='tanh', padding='same')(gen)
  # define model
  model = Model([in_lat, in_label], out_layer)
  return model
generator = define_generator(100)
plot_model(generator, to_file='generator_plot.png', show_shapes=True, show_layer_names=True)

Модель генератора должна быть обновлена, чтобы принять метку класса. Это приводит к тому, что точка в скрытом пространстве зависит от предоставленной метки класса. Как и в дискриминаторе, метка класса проходит через слой внедрения, чтобы сопоставить его с уникальным вектором из 50 элементов, а затем передается через полносвязный слой с линейной активацией перед изменением размера. В этом случае активации полносвязного слоя преобразуются в единую карту признаков 7 × 7. Это должно соответствовать активациям карты признаков 7 × 7 модели безусловного генератора. Новая карта объектов 7 × 7 добавляется как еще один канал к существующим 128, в результате чего получается 129 карт объектов, которые затем подвергаются повышающей дискретизации, как в предыдущей модели.

Перед построением комбинированной модели GAN мы должны сначала изучить необходимую предварительную обработку,

Предварительная обработка

def load_real_samples():
  # load dataset
  (trainX, trainy), (_, _) = load_data()
  # expand to 3d, e.g. add channels
  X = expand_dims(trainX, axis=-1)
  # convert from ints to floats
  X = X.astype('float32')
  # scale from [0,255] to [0,1]
  X = (X - 127.5) / 127.5
  return [X, trainy]
# select real samples
def generate_real_samples(dataset, n_samples):
  # split into images and labels
  images, labels = dataset
  # choose random instances
  ix = randint(0, images.shape[0], n_samples)
  # select images and labels
  X, labels = images[ix], labels[ix]
  # generate class labels
  y = ones((n_samples, 1))
  return [X, labels], y

def generate_latent_points(latent_dim, n_samples, n_classes=10):
  # generate points in the latent space
  x_input = randn(latent_dim * n_samples)
  # reshape into a batch of inputs for the network
  z_input = x_input.reshape(n_samples, latent_dim)
  # generate labels
  labels = randint(0, n_classes, n_samples)
  return [z_input, labels]

def generate_fake_samples(generator, latent_dim, n_samples):
  # generate points in latent space
  z_input, labels_input = generate_latent_points(latent_dim, n_samples)
  # predict outputs
  images = generator.predict([z_input, labels_input])
  # create class labels
  y = zeros((n_samples, 1))
  return [images, labels_input], y

из приведенного выше фрагмента мы видим, что мы масштабировали данные от [0,255] до [0,1]. Реальные образцы выбираются случайным образом и помечаются соответствующим образом, в то время как поддельные образцы выбираются путем создания случайных скрытых точек и помечаются как ноль.

Создание cGAN

def define_gan(g_model, d_model):
  # make weights in the discriminator not trainable
  d_model.trainable = False
  # get noise and label inputs from generator model
  gen_noise, gen_label = g_model.input
  # get image output from the generator model
  gen_output = g_model.output
  # connect image output and label input from generator as inputs to discriminator
  gan_output = d_model([gen_output, gen_label])
  # define gan model as taking noise and label and outputting a classification
  model = Model([gen_noise, gen_label], gan_output)
  # compile model
  opt = Adam(lr=0.0002, beta_1=0.5)
  model.compile(loss='binary_crossentropy', optimizer=opt)
  return model

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

Обучение cGAN

def train(g_model, d_model, gan_model, dataset, latent_dim, n_epochs=50, n_batch=128):
  bat_per_epo = int(dataset[0].shape[0] / n_batch)
  half_batch = int(n_batch / 2)
  # manually enumerate epochs
  for i in range(n_epochs):
    # enumerate batches over the training set
    for j in range(bat_per_epo):
      # get randomly selected ✬real✬ samples
      [X_real, labels_real], y_real = generate_real_samples(dataset, half_batch)
      # update discriminator model weights
      d_loss1, _ = d_model.train_on_batch([X_real, labels_real], y_real)
      # generate ✬fake✬ examples
      [X_fake, labels], y_fake = generate_fake_samples(g_model, latent_dim, half_batch)
      # update discriminator model weights
      d_loss2, _ = d_model.train_on_batch([X_fake, labels], y_fake)
      # prepare points in latent space as input for the generator
      [z_input, labels_input] = generate_latent_points(latent_dim, n_batch)
      # create inverted labels for the fake samples
      y_gan = ones((n_batch, 1))
      # update the generator via the discriminator✬s error
      g_loss = gan_model.train_on_batch([z_input, labels_input], y_gan)
      # summarize loss on this batch
      print('>%d, %d/%d, d1=%.3f, d2=%.3f g=%.3f' %
      (i+1, j+1, bat_per_epo, d_loss1, d_loss2, g_loss))
  g_model.save('cgan_generator.h5')
latent_dim = 100
# create the discriminator
d_model = define_discriminator_model()
# create the generator
g_model = define_generator(latent_dim)
gan_model = define_gan(g_model, d_model)
# load image data
dataset = load_real_samples()
# train model
train(g_model, d_model, gan_model, dataset, latent_dim)

Модель GAN сначала обучается для 60 эпох с размером пакета 128, модель дискриминатора обучается для половины реальных и половины поддельных пакетов, а затем модель генератора обучается с использованием эффективной модели cGAN.

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

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

Ресурсы

https://machinelearningmastery.com/how-to-develop-a-conditional-generative-adversarial-network-from-scr