Окружающая окклюзия с помощью GAN - правильная архитектура и функции потерь? - PullRequest
0 голосов
/ 14 мая 2019

Я пытаюсь воссоздать Deep Illumination (https://arxiv.org/pdf/1710.09834.pdf) с помощью GAN, но вместо того, чтобы научить сеть отображать глобальное освещение, я сосредотачиваюсь только на Ambient Occlusion.

В моем случае входом являются карты нормалей и карты глубины, объединенные дает изображение с четырьмя каналами - (240, 320, 4)

def build_generator(image_shape):

    inputs = Input(shape = image_shape)

    x1 = Conv2D(filters=4, kernel_size=(3,3), strides = 1, padding='same')(inputs)
    x1 = LeakyReLU(0.2)(x1)
    x1 = BatchNormalization()(x1)

    x2 = Conv2D(filters=8, kernel_size=(3,3), strides = 2, padding='same')(x1)
    x2 = LeakyReLU(0.2)(x2)
    x2 = BatchNormalization()(x2)

(...)

    x1s = Conv2DTranspose(filters=4, kernel_size=(3,3), strides = 2, padding='same')(x2s)
    x1s = LeakyReLU(0.2)(x1s)
    x1s = BatchNormalization()(x1s)

    x1s = Add()([x1s, x1]) # SKIP Connection

    x_out = Conv2DTranspose(filters=1, kernel_size=(3,3), strides = 1, padding='same')(x1s)
    output = Activation("tanh")(x_out)

    model = Model(inputs=inputs, outputs=output, name='Generator')
    return model

У генератора больше сверток, но я отключил "нет", чтобы занять слишком много места. Размер ядра остается тем же, шаг за шагом, за исключением одного среднего слоя с 32 фильтрами, где шаг равен 1.

def build_discriminator(input_shape):    

    inputs = Input(shape = input_shape)

    x = Conv2D(filters = 4, kernel_size = 3, strides = 2, padding = "same", input_shape=input_shape)(inputs)
    x = LeakyReLU(0.2)(x)

    x = Conv2D(filters = 8, kernel_size = 3, strides = 2, padding = "same", input_shape=input_shape)(x)
    x = LeakyReLU(0.2)(x)
    x = BatchNormalization()(x)

    x = Conv2D(filters = 16, kernel_size = 3, strides = 1, padding = "same", input_shape=input_shape)(x)
    x = LeakyReLU(0.2)(x)
    x = BatchNormalization()(x)

    x = Conv2D(filters = 32, kernel_size = 3, strides = 1, padding = "same", input_shape=input_shape)(x)
    x = LeakyReLU(0.2)(x)
    x = BatchNormalization()(x)

    x = Flatten()(x)
    x = Dense(1, activation='sigmoid')(x)

    model = Model(inputs=inputs, outputs=x, name='Discriminator')
    return model
def get_gan_network(discriminator, shape, generator, optimizer, d_loss):
    discriminator.trainable = False
    gan_input = Input(shape=shape)
    x = generator(gan_input)
    gan_output = discriminator(x)
    gan = Model(inputs=gan_input, outputs=[x,gan_output])
    gan.compile(loss=[d_loss, "binary_crossentropy"], loss_weights=[1., 1e-3], optimizer=optimizer)

    return gan
def train(X, Y, epochs, steps, batch_size):#, save_interval=50):
    valid = np.ones((batch_size, 1))
    fake = np.zeros((batch_size, 1))

    for epoch in range(epochs):
        for step in range(steps):
            rand_num = np.random.permutation(num_of_data)
            image_batch_x = X[rand_num[:batch_size]]
            image_batch_y = Y[rand_num[:batch_size]]
            gen_imgs = g.predict(image_batch_x)

            d.trainable = True
            d_loss_real = d.train_on_batch(image_batch_y, valid)
            d_loss_fake = d.train_on_batch(gen_imgs, fake)
            d_loss = 0.5 * (d_loss_fake + d_loss_real)
            d.trainable = False

            g_loss = gan.train_on_batch(image_batch_x, [image_batch_y, valid])

Я тестировал различные функции потерь, размеры пакетов, loss_weights и оптимизаторы - во всех случаях это приводит к снижению функции потерь до нуля, а потеря GAN застревает при некотором значении, например. 16,75344. При этом, как я должен интерпретировать значения функции потерь, и какие значения я должен ожидать?

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

Я был бы очень благодарен за любые советы или идеи.

...