Created
May 20, 2020 10:58
-
-
Save Thimira/8b34ea9deb9c59aa0262e7debf6ec616 to your computer and use it in GitHub Desktop.
Handwritten Digit Generation by Deep Convolutional Generative Adversarial Networks. Requires TensorFlow 2, OpenCV, Matplotlib, and imageio
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import tensorflow as tf | |
import glob | |
import imageio | |
import matplotlib.pyplot as plt | |
import numpy as np | |
import os | |
import PIL | |
from tensorflow.keras import layers | |
import time | |
import cv2 | |
(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 # Normalize the images to [-1, 1] | |
BUFFER_SIZE = 60000 | |
BATCH_SIZE = 256 | |
# Batch and shuffle the data | |
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) # Note: None is the 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') | |
plt.show() | |
plt.close() | |
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) | |
# This method returns a helper function to compute cross entropy loss | |
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 = 200 | |
noise_dim = 100 | |
num_examples_to_generate = 16 | |
# We will reuse this seed overtime (so it's easier) | |
# to visualize progress in the animated GIF) | |
seed = tf.random.normal([num_examples_to_generate, noise_dim]) | |
# Notice the use of `tf.function` | |
# This annotation causes the function to be "compiled". | |
@tf.function | |
def 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): | |
train_start = time.time() | |
for epoch in range(epochs): | |
start = time.time() | |
for image_batch in dataset: | |
train_step(image_batch) | |
# Produce images for the GIF as we go | |
# display.clear_output(wait=True) | |
generate_and_save_images(generator, | |
epoch + 1, | |
seed, | |
display = True) | |
# Save the model every 15 epochs | |
if (epoch + 1) % 15 == 0: | |
checkpoint.save(file_prefix = checkpoint_prefix) | |
print ('Time for epoch {} is {} sec'.format(epoch + 1, time.time()-start)) | |
print ('Time for total training is {} sec'.format(time.time()-train_start)) | |
# Generate after the final epoch | |
# display.clear_output(wait=True) | |
# generate_and_save_images(generator, | |
# epochs, | |
# seed, | |
# display = True) | |
def generate_and_save_images(model, epoch, test_input, display = False): | |
# Notice `training` is set to False. | |
# This is so all layers run in inference mode (batchnorm). | |
predictions = model(test_input, training=False) | |
fig = plt.figure(figsize=(4,4), facecolor='black') | |
for i in range(predictions.shape[0]): | |
plt.subplot(4, 4, i+1) | |
image = predictions[i, :, :, 0] * 127.5 + 127.5 | |
plt.imshow(image, cmap='gray') | |
plt.axis('off') | |
plt.savefig('new/image_at_epoch_{:04d}.png'.format(epoch), facecolor=fig.get_facecolor()) | |
plt.close() | |
disp_image = cv2.imread('new/image_at_epoch_{:04d}.png'.format(epoch)) | |
disp_image = cv2.bitwise_not(disp_image) | |
cv2.imwrite('new/image_at_epoch_{:04d}.png'.format(epoch), disp_image) | |
if (display): | |
cv2.imshow("Results", disp_image) | |
cv2.waitKey(100) | |
train(train_dataset, EPOCHS) | |
checkpoint.restore(tf.train.latest_checkpoint(checkpoint_dir)) | |
cv2.destroyAllWindows() | |
anim_file = 'dcgan.gif' | |
with imageio.get_writer(anim_file, mode='I') as writer: | |
filenames = glob.glob('new/image*.png') | |
filenames = sorted(filenames) | |
last = -1 | |
for i,filename in enumerate(filenames): | |
frame = 2*(i**0.5) | |
if round(frame) > round(last): | |
last = frame | |
else: | |
continue | |
image = imageio.imread(filename) | |
writer.append_data(image) | |
cv2.imshow("Results", image) | |
cv2.waitKey(100) | |
image = imageio.imread(filename) | |
writer.append_data(image) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment