写点什么

tensorflow 实现深度卷积生成对抗网络(DCGAN)生成手写数字图片

用户头像
AI_robot
关注
发布于: 2021 年 03 月 31 日
tensorflow实现深度卷积生成对抗网络(DCGAN)生成手写数字图片

生成对抗网络(GANs)是当今计算机科学领域最有趣的想法之一。两个模型通过对抗过程同时训练。一个生成器(“艺术家”)学习创造看起来真实的图像,而判别器(“艺术评论家”)学习区分真假图像。

训练过程中,生成器在生成逼真图像方面逐渐变强,而判别器在辨别这些图像的能力上逐渐变强。当判别器不再能够区分真实图片和伪造图片时,训练过程达到平衡。

本例子代码下载:

https://github.com/wennaz/Deep_Learning/


本笔记在 MNIST 数据集上演示了该过程。下方动画展示了当训练了 50 个 epoch (全部数据集迭代 50 次) 时生成器所生成的一系列图片。图片从随机噪声开始,随着时间的推移越来越像手写数字。


本教程演示了如何使用深度卷积生成对抗网络(DCGAN)生成手写数字图片。该代码是使用 Keras Sequential API 与 tf.GradientTape 训练循环编写的。

生成器和判别器均使用 Keras Sequential API 定义。

生成器 生成器使用 tf.keras.layers.Conv2DTranspose (上采样)层来从种子(随机噪声)中产生图片。以一个使用该种子作为输入的 Dense 层开始,然后多次上采样直到达到所期望的 28x28x1 的图片尺寸。注意除了输出层使用 tanh 之外,其他每层均使用 tf.keras.layers.LeakyReLU 作为激活函数。

import tensorflow as tf import globimport imageioimport matplotlib.pyplot as pltimport numpy as npimport osimport PILfrom tensorflow.keras import layersimport timefrom IPython import display
(train_images, train_labels), (_, _) = tf.keras.datasets.mnist.load_data()train_images = train_images.reshape(train_images.shape[0], 28, 28, 1).astype('float32')train_images = (train_images - 127.5) / 127.5 # 将图片标准化到 [-1, 1] 区间内
BUFFER_SIZE = 60000BATCH_SIZE = 256# 批量化和打乱数据train_dataset = tf.data.Dataset.from_tensor_slices(train_images).shuffle(BUFFER_SIZE).batch(BATCH_SIZE)
def make_generator_model(): model = tf.keras.Sequential() model.add(layers.Dense(7*7*256, use_bias=False, input_shape=(100,))) model.add(layers.BatchNormalization()) model.add(layers.LeakyReLU())
model.add(layers.Reshape((7, 7, 256))) assert model.output_shape == (None, 7, 7, 256) # 注意:batch size 没有限制
model.add(layers.Conv2DTranspose(128, (5, 5), strides=(1, 1), padding='same', use_bias=False)) assert model.output_shape == (None, 7, 7, 128) model.add(layers.BatchNormalization()) model.add(layers.LeakyReLU())
model.add(layers.Conv2DTranspose(64, (5, 5), strides=(2, 2), padding='same', use_bias=False)) assert model.output_shape == (None, 14, 14, 64) model.add(layers.BatchNormalization()) model.add(layers.LeakyReLU())
model.add(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
generator = make_generator_model()
noise = tf.random.normal([1, 100])generated_image = generator(noise, training=False)
plt.imshow(generated_image[0, :, :, 0], cmap='gray')
def make_discriminator_model(): model = tf.keras.Sequential() model.add(layers.Conv2D(64, (5, 5), strides=(2, 2), padding='same',input_shape=[28, 28, 1])) model.add(layers.LeakyReLU()) model.add(layers.Dropout(0.3))
model.add(layers.Conv2D(128, (5, 5), strides=(2, 2), padding='same')) model.add(layers.LeakyReLU()) model.add(layers.Dropout(0.3))
model.add(layers.Flatten()) model.add(layers.Dense(1))
return model
discriminator = make_discriminator_model()decision = discriminator(generated_image)print (decision)
# 该方法返回计算交叉熵损失的辅助函数cross_entropy = tf.keras.losses.BinaryCrossentropy(from_logits=True)
def discriminator_loss(real_output, fake_output): real_loss = cross_entropy(tf.ones_like(real_output), real_output) fake_loss = cross_entropy(tf.zeros_like(fake_output), fake_output) total_loss = real_loss + fake_loss return total_loss
def generator_loss(fake_output): return cross_entropy(tf.ones_like(fake_output), fake_output)
generator_optimizer = tf.keras.optimizers.Adam(1e-4)discriminator_optimizer = tf.keras.optimizers.Adam(1e-4)
checkpoint_dir = './training_checkpoints'checkpoint_prefix = os.path.join(checkpoint_dir, "ckpt")checkpoint = tf.train.Checkpoint(generator_optimizer=generator_optimizer, discriminator_optimizer=discriminator_optimizer, generator=generator, discriminator=discriminator)
EPOCHS = 50noise_dim = 100num_examples_to_generate = 16

# 我们将重复使用该种子(因此在动画 GIF 中更容易可视化进度)seed = tf.random.normal([num_examples_to_generate, noise_dim])
# 注意 `tf.function` 的使用# 该注解使函数被“编译”@tf.functiondef train_step(images): 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) fake_output = discriminator(generated_images, training=True)
gen_loss = generator_loss(fake_output) disc_loss = discriminator_loss(real_output, fake_output)
gradients_of_generator = gen_tape.gradient(gen_loss, generator.trainable_variables) gradients_of_discriminator = disc_tape.gradient(disc_loss, discriminator.trainable_variables)
generator_optimizer.apply_gradients(zip(gradients_of_generator, generator.trainable_variables)) discriminator_optimizer.apply_gradients(zip(gradients_of_discriminator, discriminator.trainable_variables))
def train(dataset, epochs): for epoch in range(epochs): start = time.time()
for image_batch in dataset: train_step(image_batch)
# 继续进行时为 GIF 生成图像 display.clear_output(wait=True) generate_and_save_images(generator, epoch + 1, seed)
# 每 15 个 epoch 保存一次模型 if (epoch + 1) % 15 == 0: checkpoint.save(file_prefix = checkpoint_prefix) print ('Time for epoch {} is {} sec'.format(epoch + 1, time.time()-start))# 最后一个 epoch 结束后生成图片 display.clear_output(wait=True) generate_and_save_images(generator,epochs,seed)
def generate_and_save_images(model, epoch, test_input): # 注意 training` 设定为 False # 因此,所有层都在推理模式下运行(batchnorm)。 predictions = model(test_input, training=False)
fig = plt.figure(figsize=(4,4))
for i in range(predictions.shape[0]): plt.subplot(4, 4, i+1) plt.imshow(predictions[i, :, :, 0] * 127.5 + 127.5, cmap='gray') plt.axis('off')
plt.savefig('image_at_epoch_{:04d}.png'.format(epoch)) plt.show()


train(train_dataset, EPOCHS)checkpoint.restore(tf.train.latest_checkpoint(checkpoint_dir))
# 使用 epoch 数生成单张图片def display_image(epoch_no): return PIL.Image.open('image_at_epoch_{:04d}.png'.format(epoch_no))
display_image(EPOCHS)
复制代码

输出结果:

Out[57]:


用户头像

AI_robot

关注

还未添加个人签名 2021.03.31 加入

Deep Learning从业者

评论

发布
暂无评论
tensorflow实现深度卷积生成对抗网络(DCGAN)生成手写数字图片