Pull to refresh

Comments 8

Генератор передает свой вывод дискриминатору и использует потери BCE дискриминатора для настройки своих весов с целью максимизации потерь дискриминатора

Правильно ли я понял, что последовательность обучения такая:
1) Делаем вектор случайного шума с гаусовским распределением (что изменится, если не с гаусовским?). В данном случае 100.
2) Подаём этот вектор на вход полносвязной сети A. Получаем картинку 28x28.
3) Подаём эту картинку от сети A на вход полносвязной сети B. Получаем одно число, означающее настоящее изображение (ближе к 1) или мусор (ближе к 0).
4) Вот шаг обучения сети A тут я не понял. Допустим сеть B сказала, что получился мусор (пусть ответ 0.1). Обратным распространением можно получить ошибку на входе сети B и считать её ошибкой сети A по которой и обучать сеть A. Но это если бы мы знали бы правильный ответ (мусор или нет). Но мы его не знаем для изображения от сети A. Тогда как быть?
5) Периодически подсовываем сети B истинные изображения/мусор и обучаем её отдельно точно зная, что мы подавали.


Итого, вопрос по пункту 4.

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

что изменится, если не с гаусовским?

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

Но это если бы мы знали бы правильный ответ (мусор или нет). Но мы его не знаем для изображения от сети A. Тогда как быть?

Идея GAN в том, что это будет работать даже если мы не знаем.

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

GAN же устроен совсем иначе.

Дискриминатор не говорит, мусор получился или нет. У нас есть настоящие картинки с цифрами и то, что выдал генератор. Задача дискриминатора — сказать, где настоящее, а где сгенерированное. В 4 пункте мы точно знаем правильный ответ, так как выход генератора — это сгенерированная картинка по определению.

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

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

Спасибо, я уже нашёл как это работает. Но есть нюанс.
Вопрос вот какой: вот есть у меня нейронка дискриминатора. Я ей подал истинное изображение. Ответ сети real_output=0.7. Подал мнимое. Ответ сети fake_output=0.3. Возникает вопрос, а какой считать ошибку на выходе сети, чтобы выполнять обратное распространение (то самое желаемое минус полученное)? Если я сделаю эту ошибку Error=-log(real_output)-log(1-fake_output), то такая сеть будет тащить fake_output к 1, а должна бы к 0. Если я сделаю Error=-log(real_output)+log(1-fake_output) (обращаю внимание на плюс вместо минуса!), то такая сеть обучится, но притянет real_output к 0.5 и fake_output тоже к 0.5. Но это неверно. Если же делать вычисление градиентов по-отдельности для каждого случае, то тогда получится, что для реального изображения Error=-log(real_output), а для мнимого Error=log(fake_output) (без минуса!). Но так у меня тоже не получается обучить. Такой же вопрос к обучению генератора.
Пишут:
image
Но тут непонятно, что значит "в сторону возрастания градиента"? Что задать как ошибка на выходе сети?
В общем, пока у меня не заработало — не обучается.

Наконец, как и было обещано, мы создадим анимацию, показанную вверху поста.

Зачем нам эта анимация?

В статье не было вводной. В статье не было объяснения зачем. В статье не было объяснения практически ничего.

Было только утверждение что "это круто", "это надо" и "посмотрите как".

P.S. Да даже "на минималках", для абсолютного начала, следовало объяснить что яркость важнее цвета и почему.

Вроде бы у меня обучение самодельной GAN заработало (не на питоне). Но вот в чём проблема — генератор сам выбирает одно-единственное изображение и тренируется в его рисовании. А действительно, с чего бы ему учиться рисовать разные картинки, если проще всего научиться рисовать одну при любых входах (например, занулить все коээфициенты, а вектором сдвигов сместить точки в позиции одного истинного изображения). Есть какой-то нюанс. Может быть, скорость обучения нужна меньше? Может быть, дропаут обязательно нужен? Не понятно пока.
Вот тут этот вопрос уже задавали.


Upd. Нашёл ответ тут.


Волшебное изменение одного символа в коде состоит в том, чтобы внести следующее изменение:
Изменение от:
def generate_latent_points(self, n_samples):
return np.random.rand(n_samples, self.latent_dim)
Чтобы:
def generate_latent_points(self, n_samples):
return np.random.randn(n_samples, self.latent_dim)
Надеюсь, что эта очень тонкая деталь может помочь тем, кто часами ломает голову над процессом обучения GAN.
np.random.rand дает равномерное распределение по [0, 1)
np.random.randn дает одномерное «нормальное» (гауссово) распределение среднего 0 и дисперсии 1

Впрочем, истинная причина раскрыта в комментариях. Просто надо случайные числа подавать в широком диапазоне (например, -10...+10). Тогда и будут получаться разные картинки.

Sign up to leave a comment.

Articles