Создание номеров MNIST с использованием LSTM-CGAN в TensorFlow
Вдохновленный этой статьей, я пытаюсь создать условный GAN, который будет использовать LSTM для генерации чисел MNIST. Надеюсь, что я использую ту же архитектуру, что и на изображении ниже (за исключением двунаправленного RNN в дискриминаторе, взятого из этой статьи):
Когда я запускаю эту модель, у меня очень странные результаты. Это изображение показывает мою модель, производящую номер 3 после каждой эпохи. Это должно выглядеть больше похоже на это. Это очень плохо.
Потеря моей сети дискриминаторов снижается очень быстро, вплоть до нуля. Однако потеря моей сети генератора колеблется вокруг некоторой фиксированной точки (возможно, медленно расходятся). Я действительно не знаю, что происходит. Вот самая важная часть моего кода (полный код здесь):
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
Есть несколько вещей, которые вы можете сделать, чтобы улучшить свою архитектуру сети и этап обучения.
- Удалите
tf.nn.sigmoid(logit)
как из генератора, так и из дискриминатора. Верните только pred
. -
Используйте численно стабильную функцию для вычисления ваших функций потерь и устранения функций потерь:
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). Надеюсь, поможет