Создание номеров MNIST с использованием LSTM-CGAN в TensorFlow

Вдохновленный этой статьей, я пытаюсь создать условный GAN, который будет использовать LSTM для генерации чисел MNIST. Надеюсь, что я использую ту же архитектуру, что и на изображении ниже (за исключением двунаправленного RNN в дискриминаторе, взятого из этой статьи):

enter image description here

Когда я запускаю эту модель, у меня очень странные результаты. Это изображение показывает мою модель, производящую номер 3 после каждой эпохи. Это должно выглядеть больше похоже на это. Это очень плохо.

enter image description here

Потеря моей сети дискриминаторов снижается очень быстро, вплоть до нуля. Однако потеря моей сети генератора колеблется вокруг некоторой фиксированной точки (возможно, медленно расходятся). Я действительно не знаю, что происходит. Вот самая важная часть моего кода (полный код здесь):

timesteps = 28
X_dim = 28
Z_dim = 100
y_dim = 10

X = tf.placeholder(tf.float32, [None, timesteps, X_dim]) # reshaped MNIST image to 28x28
y = tf.placeholder(tf.float32, [None, y_dim]) # one-hot label
Z = tf.placeholder(tf.float32, [None, timesteps, Z_dim]) # numpy.random.uniform noise in range [-1; 1]

y_timesteps = tf.tile(tf.expand_dims(y, axis=1), [1, timesteps, 1]) # [None, timesteps, y_dim] - replicate y along axis=1

def discriminator(x, y):
    with tf.variable_scope('discriminator', reuse=tf.AUTO_REUSE) as vs:
        inputs = tf.concat([x, y], axis=2)
        D_cell = tf.contrib.rnn.LSTMCell(64)
        output, _ = tf.nn.dynamic_rnn(D_cell, inputs, dtype=tf.float32)
        last_output = output[:, -1, :]
        logit = tf.contrib.layers.fully_connected(last_output, 1, activation_fn=None)
        pred = tf.nn.sigmoid(logit)
        variables = [v for v in tf.all_variables() if v.name.startswith(vs.name)]
        return variables, pred, logit

def generator(z, y):
    with tf.variable_scope('generator', reuse=tf.AUTO_REUSE) as vs:
        inputs = tf.concat([z, y], axis=2)
        G_cell = tf.contrib.rnn.LSTMCell(64)
        output, _ = tf.nn.dynamic_rnn(G_cell, inputs, dtype=tf.float32)
        logit = tf.contrib.layers.fully_connected(output, X_dim, activation_fn=None)
        pred = tf.nn.sigmoid(logit)
        variables = [v for v in tf.all_variables() if v.name.startswith(vs.name)]
        return variables, pred

G_vars, G_sample = run_generator(Z, y_timesteps)
D_vars, D_real, D_logit_real = run_discriminator(X, y_timesteps)
_, D_fake, D_logit_fake = run_discriminator(G_sample, y_timesteps)

D_loss = -tf.reduce_mean(tf.log(D_real) + tf.log(1. - D_fake))
G_loss = -tf.reduce_mean(tf.log(D_fake))

D_solver = tf.train.AdamOptimizer().minimize(D_loss, var_list=D_vars)
G_solver = tf.train.AdamOptimizer().minimize(G_loss, var_list=G_vars)

Скорее всего, что-то не так с моей моделью. Кто-нибудь может помочь мне свести сеть генераторов?

Ответ 1

Есть несколько вещей, которые вы можете сделать, чтобы улучшить свою архитектуру сети и этап обучения.

  1. Удалите tf.nn.sigmoid(logit) как из генератора, так и из дискриминатора. Верните только pred.
  2. Используйте численно стабильную функцию для вычисления ваших функций потерь и устранения функций потерь:

    D_loss = -tf.reduce_mean (tf.log(D_real) + tf.log(1. - D_fake)) G_loss = -tf.reduce_mean (tf.log(D_fake))

должно быть:

D_loss_real = tf.nn.sigmoid_cross_entropy_with_logits(
              logits=D_real,
              labels=tf.ones_like(D_real))
D_loss_fake = tf.nn.sigmoid_cross_entropy_with_logits(
              logits=D_fake,
              labels=tf.zeros_like(D_fake))

D_loss = -tf.reduce_mean(D_loss_real + D_loss_fake)
G_loss = -tf.reduce_mean(tf.nn.sigmoid_cross_entropy_with_logits(
              logits=D_real,
              labels=tf.ones_like(D_real)))

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