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
这个用来计算生成图像和真实图像之间的差异
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会越来越大,直到接近相等,训练完毕。