深度学习生成模型-DCGAN

原理分析

DCGAN 和GAN的原理是相同的,就是DCGAN和CNN结合,用CNN更有利于图形处理。
关于GAN的原理可以看一下这篇博客:GAN新手入门指南+keras&TensorFlow代码详解(WIN10)

然后我们可以具体看一下model实现:

实现生成器

这是最简单的Keras Sequnatial模型,我们可以发现他的输入为(None, 100),而输出则是(None, 28, 28, 1)。看到28就知道这是一个关于生成手写数字的GAN模型。

def make_generator_model():
    model = tf.keras.Sequential()
    model.add(tf.keras.layers.Dense(7 * 7 * 256, use_bias=False, input_shape=(100,)))
    model.add(tf.keras.layers.BatchNormalization())
    model.add(tf.keras.layers.LeakyReLU())

    model.add(tf.keras.layers.Reshape((7, 7, 256)))
    assert model.output_shape == (None, 7, 7, 256)  # Note: None is the batch size

    model.add(tf.keras.layers.Conv2DTranspose(128, (5, 5), strides=(1, 1), padding='same', use_bias=False))
    assert model.output_shape == (None, 7, 7, 128)
    model.add(tf.keras.layers.BatchNormalization())
    model.add(tf.keras.layers.LeakyReLU())

    model.add(tf.keras.layers.Conv2DTranspose(64, (5, 5), strides=(2, 2), padding='same', use_bias=False))
    assert model.output_shape == (None, 14, 14, 64)
    model.add(tf.keras.layers.BatchNormalization())
    model.add(tf.keras.layers.LeakyReLU())

    model.add(
        tf.keras.layers.Conv2DTranspose(1, (5, 5), strides=(2, 2), padding='same', use_bias=False, activation='tanh'))
    assert model.output_shape == (None, 28, 28, 1)

    return model

鉴别器

它的输入是应该是图像(None, 28, 28, 1),但是对于不同数据的时候它的输入 input_shape是 不一样。重要的不是输入而输出,输出维度为1用来表示是否这张图为真还是为假。

def make_discriminator_model():
    model = tf.keras.Sequential()
    model.add(tf.keras.layers.Conv2D(64, (5, 5), strides=(2, 2), padding='same'))
    model.add(tf.keras.layers.LeakyReLU())
    model.add(tf.keras.layers.Dropout(0.3))

    model.add(tf.keras.layers.Conv2D(128, (5, 5), strides=(2, 2), padding='same'))
    model.add(tf.keras.layers.LeakyReLU())
    model.add(tf.keras.layers.Dropout(0.3))

    model.add(tf.keras.layers.Flatten())
    model.add(tf.keras.layers.Dense(1))
    return model

loss函数

生成器损失函数

这个用来计算生成图像和真实图像之间的差异

def generator_loss(generated_output):
    return tf.losses.sigmoid_cross_entropy(tf.ones_like(generated_output), generated_output)
鉴别器损失函数
 def discriminator_loss(real_output, generated_output):
    # [1,1,...,1] with real output since it is true and we want our generated examples to look like it
    real_loss = tf.losses.sigmoid_cross_entropy(multi_class_labels=tf.ones_like(real_output), logits=real_output)

    # [0,0,...,0] with generated images since they are fake
    generated_loss = tf.losses.sigmoid_cross_entropy(multi_class_labels=tf.zeros_like(generated_output), logits=generated_output)

    total_loss = real_loss + generated_loss

    return total_loss

训练

每一步训练
def train_step(images):
  # generating noise from a normal distribution
  noise = tf.random_normal([batch_size, noise_dim])

  with tf.GradientTape() as gen_tape, tf.GradientTape() as disc_tape:
      generated_images = generator(noise, training=True)

      real_output = discriminator(images, training=True)
      generated_output = discriminator(generated_images, training=True)

      gen_loss = generator_loss(generated_output)
      disc_loss = discriminator_loss(real_output, generated_output)

  gradients_of_generator = gen_tape.gradient(gen_loss, generator.variables)
  gradients_of_discriminator = disc_tape.gradient(disc_loss, discriminator.variables)

  generator_optimizer.apply_gradients(zip(gradients_of_generator, generator.variables))
  discriminator_optimizer.apply_gradients(zip(gradients_of_discriminator, discriminator.variables))
训练函数
def train(dataset, epochs):
    for epoch in range(epochs):
        start = time.time()

        for images in dataset:
            train_step(images)

        display.clear_output(wait=True)
        generate_and_save_images(generator,
                                 epoch + 1,
                                 random_vector_for_generation)

        # saving (checkpoint) the model every 15 epochs
        if (epoch + 1) % 15 == 0:
            checkpoint.save(file_prefix=checkpoint_prefix)

        print('Time taken for epoch {} is {} sec'.format(epoch + 1,
                                                         time.time() - start))
    # generating after the final epoch
    display.clear_output(wait=True)
    generate_and_save_images(generator,
                             epochs,
                             random_vector_for_generation)

如果我们设置我们的batch_size = 256,因为我们知道我们的生成器的input_shape=(None, 100),所以我们现在每一步生成器的输入就(256, 100)的随机噪声矩阵。这个矩阵通过生成器之后就变成了(256, 28, 28, 1)的矩阵了,然后我们再将这个生成的东西丢入鉴别器中,就得到(256, 1)的矩阵,这个东西就是判断每张图像是否为真的依据。当然因为是前几个epoch所以值都无限接近与0(假),所以他和1(真)的gen_loss就比较大。然后我们再讲我们训练数据中的真图放入鉴别其中也会得到一个(256, 1)的输出,这个输出的都比较接近与1(真),所以disc_loss开始值就比较小。然后求梯度啊,就会发现gen_loss越来越小,disc_loss会越来越大,直到接近相等,训练完毕。

你可能感兴趣的:(深度学习)