GAN нейросеть - меняется шум, но показания прежние. Как это возможно?
Играюсь с нейросетью из туториала гугла https://www.tensorflow.org/tutorials/generative/dcgan
Этапы построения
1)Подготавливаем выборку изображений
2)Делаем генератор (вход - много нейронов(7x7x256), выход - 1 изображения размером 28 на 28 в оттенках серого от -1 до 1)
3)Делаем дискриминатор - на вход - изображение размером 28 на 28 в оттенках серого, выход - цифра-вердикт, если 1, то изображение 100% истинно и, если 0, то изображение точно фейк.
4)Запускаем тренировку:
Скармливаем случайный шум генератору
Генератор выдает картинку
Дискриминатор смотрит что это за картинка и выносит свой вердикт(допустим 0.1)
Дискриминатор смотрит на идеальные картинки и выносит свой вердикт
Высчитываем ошибку генератора (она равна кросс-энтропии между правильным ответом дискриминатора на идеальную картинку( т.е. единице) и тем, как оценил дискриминатор нашу картинку(0.1)
Высчитываем ошибку дискриминатора(она равна кросс энтропии между единицей и тем, как дискриминатор оценил идеальные картинки плюс кросс энтропия между нулем и тем как дискриминатор оценил неправильные картинки)
Применяем этим ошибки для обучения наших моделей
gradients_of_generator = gen_tape.gradient(gen_loss, createGenerator.trainable_variables)
gradients_of_discriminator = disc_tape.gradient(disc_loss, discriminator.trainable_variables)
generator_optimizer.apply_gradients(zip(gradients_of_generator, createGenerator.trainable_variables))
discriminator_optimizer.apply_gradients(zip(gradients_of_discriminator, discriminator.trainable_variables))
`
Повторяем раз за разом.
Вопросы
1)Правильно ли я понял алгоритм работы генеративно-состязательной сети?
2)Почему первых нейронов у генератора на входе так много? Почему 7х7х256? 256 - это BATCH_SIZE, использовалось при подготовке образцов. Но зачем умножать еще на 7х7?
model.add(layers.Dense(7*7*256, use_bias=False, input_shape=(100, )))
3)Каждый раз в итерации обучения входной шум меняется! Причем случайно! При обучении модели мы добавляем в неё градиенты, основанные на ошибках, но если входные данные все время случайны - разве может мы получать правильные ответы? Сеть работает, и после 50 итераций цифры похожи на цифры, но почему не мешает случайный шум?
noise = random.normal([256, 100])
with GradientTape() as gen_tape, GradientTape() as disc_tape:
# получаем изображения от генератора изображений, передавая туда шум.
generated_images = createGenerator(noise, training=True)
```
Ответы (1 шт):
Попробую ответить на некоторые из ваших вопросов.
- Вы правильно описали этапы построения модели, но описали ее для случая когда BATCH_SIZE = 1. За один шаг генератор создаёт
BATCH_SIZEкартинок из белого шума, а дискриминатор высчитывает ошибку дляBATCH_SIZEфейковых картинок созданных генератором и дляBATCH_SIZEреальных картинок и суммирует ошибку. "Почему 7х7х256?"256 - в данном случае это глубина первого слоя. Даже если бы изменилиBATCH_SIZE- мы не должны были бы менять глубину входного тензора. Размерность первого слоя подбирается таким образом, чтобы получить на выходе правильныё размер тензора с созданными картинками после всех слоев развёртки (deconvolution / transpose convolution) . Т.е. размерность первого слоя зависит от размерности генерируемой картинки и от количества слоёв развёртки - чем больше слоёв тем глубже должна быть размерность вначале.- Если на вход генератору подавать одни и те же данные, то он и научится создавать одинаковые картинки и только для данных входных данных. Случайный шум помогает обучать и генератор и дискриминатор. Генератор учится создавать картинки более похожие на исходные реальные картинки, а дискриминатор обучается отличать все более качественные фейки от реальных картинок.
Другой пример DCGAN архитектуры:
Для простоты описываем этапы для одной картинки. В реальном случае это будут тензоры с дополнительной размерностью - batch_size, т.е. число картинок обрабатывающихся за один шаг работы сети / модели.
Генератор
- На вход полносвязному слою подается вектор из 100 случайных чисел, на выходе тензор размерности
4x4x1024 - На вход развёрточному слою подаётся тензор размерности
4x4x1024. После слоя развёртки получаем тензор размерности8x8x512, т.е. размерность картики увеличилась вдвое, а глубина уменьшилась вдвое. - продолжаем развёртку:
8x8x512-->16x16x256 - продолжаем развёртку:
16x16x256-->32x32x128 - последний развёрточный слой создаёт картинку нужной нам размерности и глубины (в данном случае с одним цветовым каналом - оттенки серого)
Дискриминатор
- На вход сверточного слоя получаем картинку размерности
64x64x1, на выходе тензор размерности32x32x64 - свёрточный слой:
32x32x64-->16x16x128 - свёрточный слой:
16x16x128-->8x8x256 - свёрточный слой:
8x8x256-->4x4x512 - полносвязный слой:
4x4x512-->1(вероятность того, что картинка реальная)
Таким образом размерность тензора для первого разверточного слоя генератора подбирают так, чтобы после всех слоёв развертки получить картинку нужной размерности (в описанном выше случае - 64x64x1).
