CraftDuino v2.0
  • - это CraftDuino - наш вариант полностью Arduino-совместимой платы.
  • CraftDuino - настоящий конструктор, для очень быстрого прототипирования и реализации идей.
  • Любая возможность автоматизировать что-то с лёгкостью реализуется с CraftDuino!
Просто добавьте CraftDuino!

GAN — генеративные состязательные сети

архитектура GAN
GAN — Generative Adversarial Networks — генеративные состязательные сети.

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

Генеративные сети — это очень интересный класс нейронных сетей, которые учатся генерировать определённые объекты. Сейчас, подобные сети очень популярны и используются для самых разных задач — от генерирования пугающих картинок и суперразрешения до поиска лекарств от рака.

Впервые представлены в 2014 году Ian Goodfellow в [1].

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

Таким образом, генеративная cостязательная сеть, фактически, состоит из двух сетей:
1 — генератор (G)
2 — дискриминатор (D)

Генератор — нейронная сеть, которая получает на вход, так называемые, скрытые переменные (latent space) (случайный шум), а на выходе получаются данные ( изображение).

Дискриминатор – это обычный бинарный классификатор, который выдаёт:
1 — для реальных данных,
0 — для поддельных данных.

Подробнее с теорией работы GAN помогут статьи:
Автоэнкодеры в Keras, Часть 5: GAN(Generative Adversarial Networks) и tensorflow
Нейросетевая игра в имитацию

Пример реализации GAN в Keras




def make_trainable(net, val):
    net.trainable = val
    for l in net.layers:
        l.trainable = val

def create_gan(channels, height, width):

    input_img = Input(shape=(channels, height, width))

    m_height, m_width = int(height/8), int(width/8)

    # generator
    z = Input(shape=(latent_dim, ))
    x = Dense(256*m_height*m_width)(z)
    #x = BatchNormalization()(x)
    x = Activation('relu')(x)
    #x = Dropout(0.3)(x)

    x = Reshape((256, m_height, m_width))(x)

    x = Conv2DTranspose(256, kernel_size=(5, 5), strides=(2, 2), padding='same', activation='relu')(x)

    x = Conv2DTranspose(128, kernel_size=(5, 5), strides=(2, 2), padding='same', activation='relu')(x)

    x = Conv2DTranspose(64, kernel_size=(5, 5), strides=(2, 2), padding='same', activation='relu')(x)

    x = Conv2D(channels, (5, 5), padding='same')(x)
    g = Activation('tanh')(x)

    generator = Model(z, g, name='Generator')

    # discriminator
    x = Conv2D(128, (5, 5), padding='same')(input_img)
    #x = BatchNormalization()(x)
    x = LeakyReLU()(x)
    #x = Dropout(0.3)(x)
    x = MaxPooling2D(pool_size=(2, 2), padding='same')(x)
    x = Conv2D(256, (5, 5), padding='same')(x)
    x = LeakyReLU()(x)
    x = MaxPooling2D(pool_size=(2, 2), padding='same')(x)
    x = Conv2D(512, (5, 5), padding='same')(x)
    x = LeakyReLU()(x)
    x = MaxPooling2D(pool_size=(2, 2), padding='same')(x)
    x = Flatten()(x)
    x = Dense(2048)(x)
    x = LeakyReLU()(x)
    x = Dense(1)(x)
    d = Activation('sigmoid')(x)

    discriminator = Model(input_img, d, name='Discriminator')

    gan = Sequential()
    gan.add(generator)
    make_trainable(discriminator, False) #discriminator.trainable = False
    gan.add(discriminator)

    return generator, discriminator, gan

gan_gen, gan_ds, gan = create_gan(channels, height, width)

gan_gen.summary()
gan_ds.summary()
gan.summary()

opt = Adam(lr=1e-3)
gopt = Adam(lr=1e-4)
dopt = Adam(lr=1e-4)

gan_gen.compile(loss='binary_crossentropy', optimizer=gopt)
gan.compile(loss='binary_crossentropy', optimizer=opt)

make_trainable(gan_ds, True)
gan_ds.compile(loss='binary_crossentropy', optimizer=dopt)


Процедура обучения GAN


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


for epoch in range(epochs):
    print('Epoch {} from {} ...'.format(epoch, epochs))

    n = x_train.shape[0]
    image_batch = x_train[np.random.randint(0, n, size=batch_size),:,:,:]    

    noise_gen = np.random.uniform(-1, 1, size=[batch_size, latent_dim])

    generated_images = gan_gen.predict(noise_gen, batch_size=batch_size)

    if epoch % 10 == 0:
        print('Save gens ...')
        save_images(generated_images)
        gan_gen.save_weights('temp/gan_gen_weights_'+str(height)+'.h5', True)
        gan_ds.save_weights('temp/gan_ds_weights_'+str(height)+'.h5', True)
        # save loss
        df = pd.DataFrame( {'d_loss': d_loss, 'g_loss': g_loss} )
        df.to_csv('temp/gan_loss.csv', index=False)

    x_train2 = np.concatenate( (image_batch, generated_images) )
    y_tr2 = np.zeros( [2*batch_size, 1] )
    y_tr2[:batch_size] = 1

    d_history = gan_ds.train_on_batch(x_train2, y_tr2)
    print('d:', d_history)
    d_loss.append( d_history )

    noise_gen = np.random.uniform(-1, 1, size=[batch_size, latent_dim])
    g_history = gan.train_on_batch(noise_gen, np.ones([batch_size, 1]))
    print('g:', g_history)
    g_loss.append( g_history )


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

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

Рекомендации по архитектуре из статьи конца 2015 года от facebook research про DCGAN (Deep Convolutional GAN):
Unsupervised Representation Learning with Deep Convolutional Generative Adversarial Networks,
а так же набор рекомендаций, позволяющий заставить GAN работать:
How to Train a GAN? Tips and tricks to make GANs work

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

далее: Создание покемонов с помощью генеративных состязательных сетей

Статьи
1. Generative Adversarial Networks

Ссылки
Нейросетевая игра в имитацию
Автоэнкодеры в Keras, Часть 5: GAN(Generative Adversarial Networks) и tensorflow
Генеративные модели от OpenAI
GAN by Example using Keras on Tensorflow Backend
Deep Convolutional GANs (DCGAN): Unsupervised Representation Learning with Deep Convolutional Generative Adversarial Networks
How to Train a GAN? Tips and tricks to make GANs work
MNIST Generative Adversarial Model in Keras
Generative Adversarial Networks Part 2 — Implementation with Keras 2.0
Keras implementation of Deep Convolutional Generative Adversarial Networks (DCGAN)
Учим робота готовить пиццу. Часть 2: Состязание нейронных сетей

По теме
Сегментация изображений при помощи нейронной сети: U-Net
Детектирование объектов — нейросетевой подход

Нейронная сеть
Нейронная сеть — введение
Принцип обучения многослойной нейронной сети с помощью алгоритма обратного распространения
Пример работы самоорганизующейся инкрементной нейронной сети SOINN
  • 0
  • 12 октября 2017, 17:55
  • noonv

Комментарии (0)

RSS свернуть / развернуть

Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.