{"cells":[{"metadata":{},"cell_type":"markdown","source":"In this kernel we just adapt the tensorflow's repository's tutorial [Deep Convolutional Generative Adversarial Network](https://github.com/tensorflow/docs/blob/master/site/en/r2/tutorials/generative/dcgan.ipynb) to the data set of this competition.\n\nThere are minimal changes from the tutorial. Namely, the color channels (from grayscale to RGB) and a few layers in the generator and descriminator have been added/updated to suit the dog's images.  \n\nThe results are overly stylized dogs, so abstract that it might be hard for a casual observer to decide on what is it exactly... But knowing the context, a pinch of imagination leads to observing hypothetical mixed-and-remixed-many-times-already-crossed-breed breed of dogs."},{"metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true,"_kg_hide-input":true,"_kg_hide-output":true},"cell_type":"code","source":"!pip install tensorflow-gpu==2.0.0-beta1","execution_count":null,"outputs":[]},{"metadata":{"_cell_guid":"79c7e3d0-c299-4dcb-8224-4455121ee9b0","_uuid":"d629ff2d2480ee46fbb7e2d37f6b5fab8052498a","trusted":true,"_kg_hide-input":true,"_kg_hide-output":true},"cell_type":"code","source":"from __future__ import absolute_import, division, print_function, unicode_literals\n\nimport pandas as pd\nimport xml.etree.ElementTree as ET \nimport zipfile \nimport glob\nimport imageio\nimport matplotlib.pyplot as plt\nimport numpy as np\nimport os\nimport PIL\nfrom tensorflow.keras import layers\nimport time\n\nfrom IPython import display\nfrom PIL import Image \n\nimport tensorflow as tf","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"The images are cropped adapting the code from [Chris' kernel](https://www.kaggle.com/cdeotte/supervised-generative-dog-net), which he adapted from [Paulo Pinto](https://www.kaggle.com/paulorzp/show-annotations-and-breeds)'s kernel."},{"metadata":{"trusted":true},"cell_type":"code","source":"ROOT = '../input/'\nbreeds = os.listdir(ROOT + 'annotation/Annotation/') \n\nidxIn = 0; \nnamesIn = []\nimagesIn = np.zeros((25000, 64, 64, 3))\n\nfor breed in breeds:\n    for dog in os.listdir(ROOT+'annotation/Annotation/'+breed):\n        try: img = Image.open(ROOT+'all-dogs/all-dogs/'+dog+'.jpg')\n        except: continue           \n        tree = ET.parse(ROOT+'annotation/Annotation/'+breed+'/'+dog)\n        root = tree.getroot()\n        objects = root.findall('object')\n        for o in objects:\n            bndbox = o.find('bndbox') \n            xmin = int(bndbox.find('xmin').text)\n            ymin = int(bndbox.find('ymin').text)\n            xmax = int(bndbox.find('xmax').text)\n            ymax = int(bndbox.find('ymax').text)\n            w = np.min((xmax - xmin, ymax - ymin))\n            img2 = img.crop((xmin, ymin, xmin+w, ymin+w))\n            img2 = img2.resize((64,64), Image.ANTIALIAS)\n            imagesIn[idxIn,:,:,:] = np.asarray(img2)\n            namesIn.append(breed)\n            idxIn += 1","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train_images = imagesIn.reshape(imagesIn.shape[0], 64, 64, 3).astype('float32')  \ntrain_images = (train_images - 127.5) / 127.5 # Normalize the images to [-1, 1]\n\nBUFFER_SIZE = 60000\nBATCH_SIZE = 256\n\n# Batch and shuffle the data\ntrain_dataset = tf.data.Dataset.from_tensor_slices(train_images).shuffle(BUFFER_SIZE).batch(BATCH_SIZE)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def make_generator_model():\n    model = tf.keras.Sequential()\n    model.add(layers.Dense(8*8*256, use_bias=False, input_shape=(100,)))\n    model.add(layers.BatchNormalization())\n    model.add(layers.LeakyReLU())\n\n    model.add(layers.Reshape((8, 8, 256)))\n    assert model.output_shape == (None, 8, 8, 256) # Note: None is the batch size\n\n    model.add(layers.Conv2DTranspose(128, (5, 5), strides=(1, 1), padding='same', use_bias=False))\n    assert model.output_shape == (None, 8, 8, 128)\n    model.add(layers.BatchNormalization())\n    model.add(layers.LeakyReLU())\n\n    model.add(layers.Conv2DTranspose(64, (5, 5), strides=(2, 2), padding='same', use_bias=False))\n    assert model.output_shape == (None, 16, 16, 64)\n    model.add(layers.BatchNormalization())\n    model.add(layers.LeakyReLU())\n    \n    model.add(layers.Conv2DTranspose(32, (5, 5), strides=(2, 2), padding='same', use_bias=False))\n    assert model.output_shape == (None, 32, 32, 32)\n    model.add(layers.BatchNormalization())\n    model.add(layers.LeakyReLU())\n\n    model.add(layers.Conv2DTranspose(3, (5, 5), strides=(2, 2), padding='same', use_bias=False, activation='tanh'))\n    assert model.output_shape == (None, 64, 64, 3) \n\n    return model\n\ngenerator = make_generator_model()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def make_discriminator_model():\n    model = tf.keras.Sequential()\n    model.add(layers.Conv2D(64, (5, 5), strides=(2, 2), padding='same',\n                                     input_shape=[64, 64, 3]))\n    model.add(layers.LeakyReLU())\n    model.add(layers.Dropout(0.3))\n\n    model.add(layers.Conv2D(128, (5, 5), strides=(2, 2), padding='same'))\n    model.add(layers.LeakyReLU())\n    model.add(layers.Dropout(0.3))\n    \n    model.add(layers.Conv2D(256, (5, 5), strides=(2, 2), padding='same'))\n    model.add(layers.LeakyReLU())\n    model.add(layers.Dropout(0.3))    \n\n    model.add(layers.Flatten())\n    model.add(layers.Dense(1))\n\n    return model\n\ndiscriminator = make_discriminator_model()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# This method returns a helper function to compute cross entropy loss\ncross_entropy = tf.keras.losses.BinaryCrossentropy(from_logits=True)\n\ndef discriminator_loss(real_output, fake_output):\n    real_loss = cross_entropy(tf.ones_like(real_output), real_output)\n    fake_loss = cross_entropy(tf.zeros_like(fake_output), fake_output)\n    total_loss = real_loss + fake_loss\n    return total_loss\n  \ndef generator_loss(fake_output):\n    return cross_entropy(tf.ones_like(fake_output), fake_output)\n  \ngenerator_optimizer = tf.keras.optimizers.Adam(1e-4)\ndiscriminator_optimizer = tf.keras.optimizers.Adam(1e-4)\n\ncheckpoint_dir = './training_checkpoints'\ncheckpoint_prefix = os.path.join(checkpoint_dir, \"ckpt\")\ncheckpoint = tf.train.Checkpoint(generator_optimizer=generator_optimizer,\n                                 discriminator_optimizer=discriminator_optimizer,\n                                 generator=generator,\n                                 discriminator=discriminator)\n\nEPOCHS = 300\nnoise_dim = 100\nsqrt_num_examples_to_generate = 4\n\nseed = tf.random.normal([sqrt_num_examples_to_generate * sqrt_num_examples_to_generate, noise_dim])","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Notice the use of `tf.function`\n# This annotation causes the function to be \"compiled\".\n@tf.function\ndef train_step(images):\n    noise = tf.random.normal([BATCH_SIZE, noise_dim])\n\n    with tf.GradientTape() as gen_tape, tf.GradientTape() as disc_tape:\n        generated_images = generator(noise, training=True)\n\n        real_output = discriminator(images, training=True)\n        fake_output = discriminator(generated_images, training=True)\n\n        gen_loss = generator_loss(fake_output)\n        disc_loss = discriminator_loss(real_output, fake_output)\n\n        gradients_of_generator = gen_tape.gradient(gen_loss, generator.trainable_variables)\n        gradients_of_discriminator = disc_tape.gradient(disc_loss, discriminator.trainable_variables)\n\n        generator_optimizer.apply_gradients(zip(gradients_of_generator, generator.trainable_variables))\n        discriminator_optimizer.apply_gradients(zip(gradients_of_discriminator, discriminator.trainable_variables))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def train(dataset, epochs):\n    for epoch in range(epochs):\n        start = time.time()\n\n        for image_batch in dataset:\n            train_step(image_batch)\n\n        # Save the model every 15 epochs\n        if (epoch + 1) % 15 == 0:\n            checkpoint.save(file_prefix = checkpoint_prefix)\n\n        print ('Time for epoch {} is {} sec'.format(epoch + 1, time.time()-start))\n\n    # Generate after the final epoch\n    display.clear_output(wait=True)\n    generate_and_save_images(generator, seed)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def generate_and_save_images(model, test_input):\n    # Notice `training` is set to False.\n    # This is so all layers run in inference mode (batchnorm).\n    predictions = model(test_input, training=False)\n    fig = plt.figure(figsize=(15,15))\n    for i in range(predictions.shape[0]):\n        plt.subplot(sqrt_num_examples_to_generate, sqrt_num_examples_to_generate, i+1)\n        plt.imshow((predictions[i, :, :, :] + 1.0) / 2.0)\n        plt.axis('off')\n\n    plt.savefig('image_latest_epoch.png')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"%%time\ntrain(train_dataset, EPOCHS)","execution_count":null,"outputs":[]}],"metadata":{"kernelspec":{"display_name":"Python 3","language":"python","name":"python3"},"language_info":{"name":"python","version":"3.6.4","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"}},"nbformat":4,"nbformat_minor":1}