TensorFlow DCGAN模型:稳定性和收敛问题

时间:2017-04-30 19:30:01

标签: python machine-learning tensorflow neural-network conv-neural-network

我在DCGANTensorFlow培训中为MNIST建立了自己的实现。

完整代码(runnable)可在github上找到:https://github.com/Daniel451/tfdcgan

随意提交拉取请求:)

虽然该模型试图学习生成MNIST样本,但其稳定性非常差且收敛速度慢(即使在10个时期之后,生成的样本看起来仍然非常人为)。

有趣的是,我首先在Keras(使用TensorFlow后端)中实现了非常相同的模型,这可以按预期工作。它学习了合理的滤波器,并且当用标准正态分布馈送时,发电机返回漂亮的MNIST样本。

我怀疑丢失函数或模型配置存在问题,但我无法找到确切的问题。

我注意到的另一个奇怪的事情是TensorFlow实现需要 Discriminator的输出才能具有(batch_size, 2)的形状。因此,我使用[0, 1]编码生成器/假图像进行训练,使用[1, 0]编码实际训练图像。

我的期望是只有tf.nn.sparse_softmax_cross_entropy_with_logits才需要这种形状,因为它需要稀疏标签才能工作......但即使是tf.nn.softmax_cross_entropy_with_logitstf.nn.sigmoid_cross_entropy_with_logits也不会在判别器时返回有用的损失计算形状为(batch_size, 1),其中编码器对于生成器/假图像只有0.0,对于真实训练图像则为1.0。

Keras实现适用于不同的丢失函数和单个输出神经元用于判别器。

这是生成器 G 模型:

def model_generator(self, Z, reuse=True):

        init_op = tf.contrib.layers.xavier_initializer(uniform=True, dtype=tf.float32)

        with tf.variable_scope("g", initializer=init_op, reuse=reuse, dtype=tf.float32):

            with tf.variable_scope("reshape"):
                out = tf.layers.dense(Z, 7 * 7 * 256, activation=None)
                out = tf.reshape(out, [-1, 7, 7, 256])
                out = tf.layers.batch_normalization(out)
                out = tf.nn.tanh(out)

            with tf.variable_scope("deconv1"):
                out = tf.layers.conv2d_transpose(out, 128, [3, 3], strides=[2, 2], padding="same")
                out = tf.layers.batch_normalization(out)
                out = tf.nn.tanh(out)

            with tf.variable_scope("deconv2"):
                out = tf.layers.conv2d_transpose(out, 64, [3, 3], strides=[2, 2], padding="same")
                out = tf.layers.batch_normalization(out)
                out = tf.nn.tanh(out)

            with tf.variable_scope("output"):
                out = tf.layers.conv2d_transpose(out, 1, [5, 5], strides=[1, 1], padding="same")
                logits = out
                output = tf.nn.tanh(out)

        return output, logits

...这是判别器 D )型号:

def model_discriminator(self, X, reuse=True, trainable=True):

        init_op = tf.contrib.layers.xavier_initializer(uniform=False, dtype=tf.float32)

        with tf.variable_scope("d", initializer=init_op, reuse=reuse, dtype=tf.float32):

            with tf.variable_scope("conv1"):
                out = tf.layers.conv2d(X, 64, [5, 5], strides=[2, 2], padding="same",
                                       trainable=trainable)
                out = tf.nn.tanh(out)

            with tf.variable_scope("conv2"):
                out = tf.layers.conv2d(out, 128, [3, 3], strides=[2, 2], padding="same",
                                       trainable=trainable)
                out = tf.nn.tanh(out)

            with tf.variable_scope("output"):
                out = tf.reshape(out, [-1, 7 * 7 * 128])
                out = tf.layers.dense(out, 2, activation=None, trainable=trainable)
                logits = out
                output = tf.sigmoid(out)

        return output, logits

我已尝试过这些损失功能

self.d_loss = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(logits=self.D_logits, labels=self.Y))
self.dg_loss = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(logits=self.DG_logits, labels=self.Y))

self.d_loss = tf.reduce_mean(tf.nn.sigmoid_cross_entropy_with_logits(logits=self.D_logits, labels=self.Y))
self.dg_loss = tf.reduce_mean(tf.nn.sigmoid_cross_entropy_with_logits(logits=self.DG_logits, labels=self.Y))

self.d_loss = tf.reduce_mean(tf.nn.sparse_softmax_cross_entropy_with_logits(logits=self.D_logits, labels=self.Y))
self.dg_loss = tf.reduce_mean(tf.nn.sparse_softmax_cross_entropy_with_logits(logits=self.DG_logits, labels=self.Y))

以下是相应的培训操作

self.d_train_op = tf.train.AdamOptimizer(learning_rate=2e-4, beta1=0.5, beta2=0.999, name="Adam_D")\
            .minimize(self.d_loss, var_list=tf.get_collection(tf.GraphKeys.GLOBAL_VARIABLES, scope="d"))
self.g_train_op = tf.train.AdamOptimizer(learning_rate=2e-4, beta1=0.5, beta2=0.999, name="Adam_DG")\
            .minimize(self.dg_loss, var_list=tf.get_collection(tf.GraphKeys.GLOBAL_VARIABLES, scope="g"))
链接文件建议

... beta1 = 0.5,var_list=...确保 D G 受到培训,但不会同时进行。

我将MNIST输入图像归一化[-1.0, 1.0]区间,就像几个来源所建议的那样。

self.G(生成器;用于预测),self.D(判别器;用于分类)和self.DG(生成器+ Discrimnator,为了训练生成器)的实例化如下所示:

# placeholder for noise Z, fed into G
self.Z = tf.placeholder(tf.float32, shape=[None, 100], name="Z")
# placeholder for X, image data fed into D
self.X = tf.placeholder(tf.float32, shape=[None, 28, 28, 1], name="X")
# placeholder for Y, labels for training
self.Y = tf.placeholder(tf.int32, shape=[None], name="Y")

self.G, self.G_logits = self.model_generator(self.Z, reuse=False)
self.D, self.D_logits = self.model_discriminator(self.X, reuse=False)
self.DG, self.DG_logits = self.model_discriminator(self.G, trainable=False)

我正在每批3个步骤训练DCGAN:

  1. 用真实图像训练D
  2. 用发电机/假图像训练D
  3. 火车G
  4. 关于为什么这个网络表现不佳的任何想法?

1 个答案:

答案 0 :(得分:0)

我从您的问题中注意到的一件事是您提到要分3步训练。通常,一列火车分两步或一步。您可以分别(两个步骤)或一起(一个步骤)训练鉴别器和生成器。

训练鉴别器时,您可以使用鉴别器的输出获取真实样本和伪样本,并为二者生成损失并应用梯度。

如果要一步一步训练,则需要确保以正确的顺序应用渐变。