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