Я пытаюсь воссоздать 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 очень сложны и их трудно обучать. Но, возможно, я упускаю что-то очевидное или совершил какую-то глупую ошибку, которую я не могу уловить, что приводит к провалу обучения.
Я был бы очень благодарен за любые советы или идеи.