{"cells":[{"metadata":{},"cell_type":"markdown","source":"# Resources\n* https://arxiv.org/abs/1511.06434\n* https://arxiv.org/abs/1606.03498\n* https://machinelearningmastery.com/how-to-train-stable-generative-adversarial-networks/\n* https://machinelearningmastery.com/rectified-linear-activation-function-for-deep-learning-neural-networks/"},{"metadata":{},"cell_type":"markdown","source":"# CHANGELOG\n\nv\n\nv12:\n\n* Fix loss plot (again)\n* Try changing batch size to 64\n\nv11:\n\n* Add back loss plot\n* Reduce epochs from 30 to 25 to reduce time taken\n* Reduce repeats from 50 to 45 to reduce time taken\n\nv10:\n\n* Remove loss plot it somehow broke\n\nv9:\n\n* Remove minibatch discrimination\n* Add plot of losses\n* Add more noise using random rotation\n\nv8:\n\n* Add spectral normalisation for downscaling and upscaling (Broken, needs work)\n* Add minibatch discrimination to discriminator\n\nv7:\n\n* Hopefully fixed the output being too small\n* Increased epochs from 25 to 30\n\nv6:\n\n* Change dropout from 0.5 to 0.2 to see what happens\n\nv5:\n\n* Undo switch to batch normalisation\n\nv4:\n\n* Add 50% dropout to downscaling to see what happens\n* Change instance normalisation to batch normalisation to see what happens\n\nv3:\n\nMade more changes in accordance with recommendations by [this paper](https://arxiv.org/abs/1511.06434)\n* Remove Dense layer just before output\n* Use ReLU instead of LeakyReLU for Generator\n* Use only a single layer to up/downscale\n\nv2:\n\n* Replace MaxPool2D with Conv2D with strides=2 as recommended by [this paper](https://arxiv.org/abs/1511.06434)\n\nv1:\n\n* Add random_jitter_and_flip for more noise to see what happens"},{"metadata":{"trusted":true},"cell_type":"code","source":"from __future__ import absolute_import, division, print_function\nimport tensorflow as tf\nfrom tensorflow import keras\nfrom tensorflow.keras import layers, optimizers, applications, Sequential\nfrom tensorflow.keras.callbacks import EarlyStopping, ModelCheckpoint, LearningRateScheduler\nimport tensorflow_addons as tfa\nimport tensorflow_datasets as tfds\n\nfrom kaggle_datasets import KaggleDatasets\nimport glob\nimport imageio\nimport matplotlib.pyplot as plt\nimport numpy as np\nimport pandas as pd\nimport os\n\nimport sys\nprint(\"Python version:\", sys.version)\nimport PIL\nimport time\nimport shutil\n\nfrom functools import partial\nfrom albumentations import (\n    Compose, RandomBrightness, JpegCompression, HueSaturationValue, RandomContrast, HorizontalFlip,\n    Rotate\n)\n\nfrom IPython import display\n\nfrom functools import partial\nfrom albumentations import (\n    Compose, RandomBrightness, JpegCompression, HueSaturationValue, RandomContrast, HorizontalFlip,\n    Rotate\n)\n\nfrom tensorflow.python.eager import def_function\nfrom tensorflow.python.framework import dtypes\nfrom tensorflow.python.framework import tensor_shape\nfrom tensorflow.python.keras import backend as K\nfrom tensorflow.python.keras import layers\nfrom tensorflow.python.keras import initializers\nfrom tensorflow.python.ops import array_ops\nfrom tensorflow.python.ops import math_ops\n\n#Define minibatch discrimination layer\n# https://github.com/garridoq/gan-guide/blob/master/Minibatch%20discrimination%20%2B%20label%20smoothing.ipynb\nclass MinibatchDiscrimination(tf.keras.layers.Layer):\n\n    def __init__(self, num_kernel, dim_kernel,kernel_initializer='glorot_uniform', **kwargs):\n        self.num_kernel = num_kernel\n        self.dim_kernel = dim_kernel\n        self.kernel_initializer = kernel_initializer\n        super(MinibatchDiscrimination, self).__init__(**kwargs)\n\n    def build(self, input_shape):\n        # Create a trainable weight variable for this layer.\n        self.kernel = self.add_weight(name='kernel', \n                                      shape=(input_shape[-1], self.num_kernel*self.dim_kernel),\n                                      initializer=self.kernel_initializer,\n                                      trainable=True)\n        super(MinibatchDiscrimination, self).build(input_shape)\n        \n    def call(self, x):\n        activation = tf.matmul(x, self.kernel)\n        activation = tf.reshape(activation, shape=(-1, self.num_kernel, self.dim_kernel))\n        #Mi\n        tmp1 = tf.expand_dims(activation, 3)\n        #Mj\n        tmp2 = tf.transpose(activation, perm=[1, 2, 0])\n        tmp2 = tf.expand_dims(tmp2, 0)\n        \n        diff = tmp1 - tmp2\n        \n        l1 = tf.reduce_sum(tf.math.abs(diff), axis=2)\n        features = tf.reduce_sum(tf.math.exp(-l1), axis=2)\n        return tf.concat([x, features], axis=1)\n    \n    def compute_output_shape(self, input_shape):\n        return (input_shape[0], input_shape[1] + self.num_kernel)\n\n#Define spectral normalization layer\n# https://medium.com/@FloydHsiu0618/spectral-normalization-implementation-of-tensorflow-2-0-keras-api-d9060d26de77\nclass SpectralNormalization(tf.keras.layers.Layer): # tried layers.Wrapper, also got error\n    \"\"\"\n    Attributes:\n       layer: tensorflow keras layers (with kernel attribute)\n    \"\"\"\n\n    def __init__(self, layer, **kwargs):\n        super(SpectralNormalization, self).__init__(layer, **kwargs)\n        self.layer = layer\n\n    def build(self, input_shape):\n        \"\"\"Build `Layer`\"\"\"\n\n        if not self.layer.built:\n            self.layer.build(input_shape)\n\n        if not hasattr(self.layer, 'kernel'):\n            raise ValueError(\n                '`SpectralNormalization` must wrap a layer that'\n                ' contains a `kernel` for weights')\n\n        self.w = self.layer.kernel\n        self.w_shape = self.w.shape.as_list()\n        self.u = self.add_variable(\n            shape=tuple([1, self.w_shape[-1]]),\n            initializer=initializers.TruncatedNormal(stddev=0.02),\n            name='sn_u',\n            trainable=False,\n            dtype=dtypes.float32)\n\n        super(SpectralNormalization, self).build()\n\n    @def_function.function\n    def call(self, inputs, training=None):\n        \"\"\"Call `Layer`\"\"\"\n        if training is None:\n            training = K.learning_phase()\n        \n        if training==True:\n            # Recompute weights for each forward pass\n            self._compute_weights()\n        \n        output = self.layer(inputs)\n        return output\n\n    def _compute_weights(self):\n        \"\"\"Generate normalized weights.\n        This method will update the value of self.layer.kernel with the\n        normalized value, so that the layer is ready for call().\n        \"\"\"\n        w_reshaped = array_ops.reshape(self.w, [-1, self.w_shape[-1]])\n        eps = 1e-12\n        _u = array_ops.identity(self.u)\n        _v = math_ops.matmul(_u, array_ops.transpose(w_reshaped))\n        _v = _v / math_ops.maximum(math_ops.reduce_sum(_v**2)**0.5, eps)\n        _u = math_ops.matmul(_v, w_reshaped)\n        _u = _u / math_ops.maximum(math_ops.reduce_sum(_u**2)**0.5, eps)\n\n        self.u.assign(_u)\n        sigma = math_ops.matmul(math_ops.matmul(_v, w_reshaped), array_ops.transpose(_u))\n\n        self.layer.kernel.assign(self.w / sigma)\n\n    def compute_output_shape(self, input_shape):\n        return tensor_shape.TensorShape(\n            self.layer.compute_output_shape(input_shape).as_list())","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"d629ff2d2480ee46fbb7e2d37f6b5fab8052498a","_cell_guid":"79c7e3d0-c299-4dcb-8224-4455121ee9b0","trusted":true},"cell_type":"code","source":"try:\n    tpu = tf.distribute.cluster_resolver.TPUClusterResolver()\n    print('Device:', tpu.master())\n    tf.config.experimental_connect_to_cluster(tpu)\n    tf.tpu.experimental.initialize_tpu_system(tpu)\n    strategy = tf.distribute.experimental.TPUStrategy(tpu)\nexcept:\n    strategy = tf.distribute.get_strategy()\nprint('Number of replicas:', strategy.num_replicas_in_sync)\n\nAUTOTUNE = tf.data.experimental.AUTOTUNE\n\nprint(tf.__version__)\nprint(tfa.__version__)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"import re\n\nGCS_PATH = KaggleDatasets().get_gcs_path()\n\nMONET_FILENAMES = tf.io.gfile.glob(str(GCS_PATH + '/monet_tfrec/*.tfrec'))\nprint('Monet TFRecord Files:', len(MONET_FILENAMES))\n\nPHOTO_FILENAMES = tf.io.gfile.glob(str(GCS_PATH + '/photo_tfrec/*.tfrec'))\nprint('Photo TFRecord Files:', len(PHOTO_FILENAMES))\n\ndef count_data_items(filenames):\n    n = [int(re.compile(r\"-([0-9]*)\\.\").search(filename).group(1)) for filename in filenames]\n    return np.sum(n)\n\nn_monet_samples = count_data_items(MONET_FILENAMES)\nn_photo_samples = count_data_items(PHOTO_FILENAMES)\n\nprint(f'Monet TFRecord files: {len(MONET_FILENAMES)}')\nprint(f'Monet image files: {n_monet_samples}')\nprint(f'Photo TFRecord files: {len(PHOTO_FILENAMES)}')\nprint(f'Photo image files: {n_photo_samples}')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def normalize(image):\n    return (tf.cast(image, tf.float32) / 127.5) - 1\n\ndef decode_image(image):\n    image = tf.image.decode_jpeg(image, channels=3)\n    image = tf.reshape(image, [256, 256, 3])\n    return image\n\ndef random_rotate(image):\n    p = tf.random.uniform([], 0, 1.0, dtype=tf.float32)\n    if p < 0.2:\n        image = tf.image.rot90(image, k=1)\n    elif p < 0.4:\n        image = tf.image.rot90(image, k=2)\n    elif p < 0.6:\n        image = tf.image.rot90(image, k=3)\n    return image\n\ndef random_crop(image):\n    cropped_image = tf.image.random_crop(image, size=[256, 256, 3])\n    return cropped_image\n\ndef random_jitter(image):\n    # resizing to 286 x 286 x 3 \n    image = tf.image.resize(image, [int(256*1.3), int(256*1.3)],\n                          method=tf.image.ResizeMethod.NEAREST_NEIGHBOR)\n    # randomly cropping to 256 x 256 x 3\n    image = random_crop(image)\n    return image\n\ndef random_jitter_and_flip(image):\n    # resizing to 286 x 286 x 3 \n    image = tf.image.resize(image, [int(256*1.3), int(256*1.3)],\n                          method=tf.image.ResizeMethod.NEAREST_NEIGHBOR)\n    # randomly cropping to 256 x 256 x 3\n    image = random_crop(image)\n    # random mirroring\n    image = random_flip(image)\n    return image\n\ndef random_flip(image):\n    return tf.image.flip_left_right(image)\n\ndef preprocess_image_train(image, label=None):\n    image = random_jitter(image)\n    return image\n\ndef read_tfrecord(example):\n    tfrecord_format = {\n        \"image_name\": tf.io.FixedLenFeature([], tf.string),\n        \"image\": tf.io.FixedLenFeature([], tf.string),\n        \"target\": tf.io.FixedLenFeature([], tf.string)\n    }\n    example = tf.io.parse_single_example(example, tfrecord_format)\n    image = decode_image(example['image'])\n    return image\n\ndef load_dataset(filenames, labeled=False, ordered=False, repeats=200, noise=False):\n    dataset = tf.data.TFRecordDataset(filenames)\n    dataset = dataset.map(read_tfrecord, num_parallel_calls=AUTOTUNE);\n    if noise == True:\n        dataset = dataset.concatenate(dataset.map(random_jitter_and_flip, num_parallel_calls=AUTOTUNE).shuffle(10000))\n        dataset = dataset.concatenate(dataset.map(random_flip, num_parallel_calls=AUTOTUNE).shuffle(100000))\n        dataset = dataset.concatenate(dataset.map(random_rotate, num_parallel_calls=AUTOTUNE).shuffle(100000))\n        dataset = dataset.concatenate(dataset.map(random_jitter, num_parallel_calls=AUTOTUNE).shuffle(10000, reshuffle_each_iteration=True).repeat(repeats))\n    dataset = dataset.map(normalize, num_parallel_calls=AUTOTUNE).shuffle(10000)\n    return dataset","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"OUTPUT_CHANNELS = 3\nLATENT_DIM = 1024\n\ndef downsample(filters, size, apply_dropout=False, apply_instancenorm=False, apply_spectralnorm=False):\n    initializer = tf.random_normal_initializer(0., 0.02)\n    gamma_init = keras.initializers.RandomNormal(mean=0.0, stddev=0.02)\n\n    result = keras.Sequential()\n    #result.add(layers.Conv2D(filters, size, strides=1, padding='same',\n    #                         kernel_initializer=initializer, use_bias=False))\n\n    if apply_instancenorm:\n        result.add(layers.Conv2D(filters, size, strides=2, padding='same',\n                         kernel_initializer=initializer, use_bias=False))\n        result.add(tfa.layers.InstanceNormalization(gamma_initializer=gamma_init))\n        #result.add(layers.BatchNormalization(gamma_initializer=gamma_init))\n    elif apply_spectralnorm:\n        result.add(SpectralNormalization(layers.Conv2D(filters, size, strides=2, padding='same', kernel_initializer=initializer, use_bias=False)))\n    else:\n        result.add(layers.Conv2D(filters, size, strides=2, padding='same',\n                         kernel_initializer=initializer, use_bias=False))\n        \n    if apply_dropout:\n        result.add(layers.Dropout(0.2))\n\n    result.add(layers.ReLU())\n\n    return result","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def upsample(filters, size, apply_dropout=False, apply_instancenorm=False, apply_spectralnorm=False):\n    initializer = tf.random_normal_initializer(0., 0.02)\n    gamma_init = keras.initializers.RandomNormal(mean=0.0, stddev=0.02)\n\n    result = keras.Sequential()\n    #result.add(layers.Conv2DTranspose(filters, size, strides=1,\n    #                                  padding='same',\n    #                                  kernel_initializer=initializer,\n    #                                  use_bias=False))\n    \n    if apply_instancenorm:\n        result.add(layers.Conv2DTranspose(filters, size, strides=2,\n                                  padding='same',\n                                  kernel_initializer=initializer,\n                                  use_bias=False))\n        #result.add(layers.BatchNormalization(gamma_initializer=gamma_init))\n        result.add(tfa.layers.InstanceNormalization(gamma_initializer=gamma_init))\n    elif apply_spectralnorm:\n        result.add(SpectralNormalization(layers.Conv2DTranspose(filters, size, strides=2, padding='same', kernel_initializer=initializer, use_bias=False)))\n    else:\n        result.add(layers.Conv2DTranspose(filters, size, strides=2,\n                                  padding='same',\n                                  kernel_initializer=initializer,\n                                  use_bias=False))\n\n    if apply_dropout:\n        result.add(layers.Dropout(0.2))\n\n    result.add(layers.ReLU())\n\n    return result","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"EPOCHS = 25\n\nLR_G = 2e-4\nLR_D = 3e-4\nbeta_1 = .5\n\nreal_label = .9\nfake_label = 0","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def CycleGenerator():\n    inputs = layers.Input(shape=[256,256,3])\n\n    # bs = batch size\n    down_stack = [\n        downsample(64, 4), # (bs, 128, 128, 64)\n        downsample(128, 4, apply_instancenorm=True), # (bs, 64, 64, 128)\n        downsample(256, 4, apply_instancenorm=True), # (bs, 32, 32, 256)\n        downsample(512, 4, apply_instancenorm=True), # (bs, 16, 16, 512)\n        downsample(512, 4, apply_instancenorm=True), # (bs, 8, 8, 512)\n        downsample(512, 4, apply_instancenorm=True), # (bs, 4, 4, 512)\n        downsample(512, 4, apply_instancenorm=True), # (bs, 2, 2, 512)\n        downsample(512, 4, apply_instancenorm=True), # (bs, 1, 1, 512)\n    ]\n\n    up_stack = [\n        upsample(512, 4, apply_dropout=True, apply_instancenorm=True), # (bs, 2, 2, 1024)\n        upsample(512, 4, apply_dropout=True, apply_instancenorm=True), # (bs, 4, 4, 1024)\n        upsample(512, 4, apply_dropout=True, apply_instancenorm=True), # (bs, 8, 8, 1024)\n        upsample(512, 4, apply_instancenorm=True), # (bs, 16, 16, 1024)\n        upsample(256, 4, apply_instancenorm=True), # (bs, 32, 32, 512)\n        upsample(128, 4, apply_instancenorm=True), # (bs, 64, 64, 256)\n        upsample(64, 4), # (bs, 128, 128, 128)\n    ]\n\n    initializer = tf.random_normal_initializer(0., 0.02)\n    last = layers.Conv2DTranspose(OUTPUT_CHANNELS, 4,\n                                  strides=2,\n                                  padding='same',\n                                  kernel_initializer=initializer,\n                                  activation='tanh') # (bs, 256, 256, 3)\n\n    x = inputs\n\n    # Downsampling through the model\n    skips = []\n    for down in down_stack:\n        x = down(x)\n        skips.append(x)\n\n    skips = reversed(skips[:-1])\n\n    # Upsampling and establishing the skip connections\n    for up, skip in zip(up_stack, skips):\n        x = up(x)\n        x = layers.Concatenate()([x, skip])\n    x = last(x)\n\n    return keras.Model(inputs=inputs, outputs=x)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"''' Minibatch version\ndef CycleDiscriminator():\n    initializer = tf.random_normal_initializer(0., 0.02)\n    gamma_init = keras.initializers.RandomNormal(mean=0.0, stddev=0.02)\n\n    inp = layers.Input(shape=[256, 256, 3], name='input_image')\n\n    x = inp\n\n    down1 = downsample(64, 4, apply_dropout=True)(x) # (bs, 128, 128, 64)\n    down2 = downsample(128, 4, apply_instancenorm=True)(down1) # (bs, 64, 64, 128)\n    down3 = downsample(256, 4, apply_instancenorm=True)(down2) # (bs, 32, 32, 256)\n\n    zero_pad1 = layers.ZeroPadding2D()(down3) # (bs, 34, 34, 256)\n    conv = layers.Conv2D(512, 4, strides=1,\n                         kernel_initializer=initializer,\n                         use_bias=False)(zero_pad1) # (bs, 31, 31, 512)\n    \n    leaky_relu1 = layers.LeakyReLU()(conv)\n\n    norm1 = tfa.layers.InstanceNormalization(gamma_initializer=gamma_init)(leaky_relu1)\n    \n    flatten = layers.Flatten()(norm1)\n    \n    dense1 = layers.Dense(512)(flatten)\n    \n    leaky_relu2 = layers.LeakyReLU()(dense1)\n\n    minibatch = MinibatchDiscrimination(num_kernel=512, dim_kernel=5)(leaky_relu2)\n\n    last_relu = layers.LeakyReLU(alpha=0.2)(minibatch)\n    last_pool = layers.Flatten()(last_relu)\n    #last = layers.Dense(1, activation='sigmoid')(last_pool)\n\n    return tf.keras.Model(inputs=inp, outputs=last_pool)\n'''\n\ndef CycleDiscriminator():\n    initializer = tf.random_normal_initializer(0., 0.02)\n    gamma_init = keras.initializers.RandomNormal(mean=0.0, stddev=0.02)\n\n    inp = layers.Input(shape=[256, 256, 3], name='input_image')\n\n    x = inp\n\n    down1 = downsample(64, 4, apply_dropout=True, apply_instancenorm=False)(x) # (bs, 128, 128, 64)\n    down2 = downsample(128, 4)(down1) # (bs, 64, 64, 128)\n    down3 = downsample(256, 4)(down2) # (bs, 32, 32, 256)\n\n    zero_pad1 = layers.ZeroPadding2D()(down3) # (bs, 34, 34, 256)\n    conv = layers.Conv2D(512, 4, strides=1,\n                         kernel_initializer=initializer,\n                         use_bias=False)(zero_pad1) # (bs, 31, 31, 512)\n\n    norm1 = tfa.layers.InstanceNormalization(gamma_initializer=gamma_init)(conv)\n\n    leaky_relu = layers.LeakyReLU()(norm1)\n\n    zero_pad2 = layers.ZeroPadding2D()(leaky_relu) # (bs, 33, 33, 512)\n\n    last_conv = layers.Conv2D(1, 4, strides=1,\n                         kernel_initializer=initializer)(zero_pad2) # (bs, 30, 30, 1)\n\n    last_relu = layers.LeakyReLU(alpha=0.2)(last_conv)\n    last_pool = layers.Flatten()(last_relu)\n    #last = layers.Dense(1, activation='sigmoid')(last_pool)\n\n    return tf.keras.Model(inputs=inp, outputs=last_pool)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"with strategy.scope():\n    monet_cycle_generator = CycleGenerator() # transforms photos to Monet-esque paintings\n    photo_cycle_generator = CycleGenerator() # transforms Monet paintings to be more like photos\n\n    monet_cycle_discriminator = CycleDiscriminator() # differentiates real Monet paintings and generated Monet paintings\n    photo_cycle_discriminator = CycleDiscriminator() # differentiates real photos and generated photos","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"class CycleGan(keras.Model):\n    def __init__(\n        self,\n        monet_generator,\n        photo_generator,\n        monet_discriminator,\n        photo_discriminator,\n        lambda_cycle=10,\n        real_label=.5\n    ):\n        super(CycleGan, self).__init__()\n        self.m_gen = monet_generator\n        self.p_gen = photo_generator\n        self.m_disc = monet_discriminator\n        self.p_disc = photo_discriminator\n        self.lambda_cycle = lambda_cycle\n        self.real_label = real_label\n        \n    def compile(\n        self,\n        m_gen_optimizer,\n        p_gen_optimizer,\n        m_disc_optimizer,\n        p_disc_optimizer,\n        gen_loss_fn,\n        disc_loss_fn,\n        cycle_loss_fn,\n        identity_loss_fn\n    ):\n        super(CycleGan, self).compile()\n        self.m_gen_optimizer = m_gen_optimizer\n        self.p_gen_optimizer = p_gen_optimizer\n        self.m_disc_optimizer = m_disc_optimizer\n        self.p_disc_optimizer = p_disc_optimizer\n        self.gen_loss_fn = gen_loss_fn\n        self.disc_loss_fn = disc_loss_fn\n        self.cycle_loss_fn = cycle_loss_fn\n        self.identity_loss_fn = identity_loss_fn\n        \n    def train_step(self, batch_data):\n        real_monet, real_photo = batch_data\n        \n        batch_size = tf.shape(real_photo)[0]\n        labels_real = tf.zeros((batch_size, 1)) + self.real_label\n        labels_real += 0.05 * tf.random.uniform(tf.shape(labels_real))        \n        \n        with tf.GradientTape(persistent=True) as tape:\n            # photo to monet back to photo\n            fake_monet = self.m_gen(real_photo, training=True)\n            cycled_photo = self.p_gen(fake_monet, training=True)\n\n            # monet to photo back to monet\n            fake_photo = self.p_gen(real_monet, training=True)\n            cycled_monet = self.m_gen(fake_photo, training=True)\n\n            # generating itself\n            same_monet = self.m_gen(real_monet, training=True)\n            same_photo = self.p_gen(real_photo, training=True)\n\n            # discriminator used to check, inputing real images\n            disc_real_monet = self.m_disc(real_monet, training=True)\n            disc_real_photo = self.p_disc(real_photo, training=True)\n\n            # discriminator used to check, inputing fake images\n            disc_fake_monet = self.m_disc(fake_monet, training=True)\n            disc_fake_photo = self.p_disc(fake_photo, training=True)\n\n            # evaluates generator loss\n            monet_gen_loss = self.gen_loss_fn(disc_real_monet, disc_fake_monet, labels_real)\n            photo_gen_loss = self.gen_loss_fn(disc_real_photo, disc_fake_photo, labels_real)\n\n            # evaluates total cycle consistency loss\n            total_cycle_loss = self.cycle_loss_fn(real_monet, cycled_monet, self.lambda_cycle) + self.cycle_loss_fn(real_photo, cycled_photo, self.lambda_cycle)\n\n            # evaluates total generator loss\n            total_monet_gen_loss = monet_gen_loss + total_cycle_loss + self.identity_loss_fn(real_monet, same_monet, self.lambda_cycle)\n            total_photo_gen_loss = photo_gen_loss + total_cycle_loss + self.identity_loss_fn(real_photo, same_photo, self.lambda_cycle)\n\n            # evaluates discriminator loss\n            monet_disc_loss = self.disc_loss_fn(disc_real_monet, disc_fake_monet, labels_real)\n            photo_disc_loss = self.disc_loss_fn(disc_real_photo, disc_fake_photo, labels_real)\n\n        # Calculate the gradients for generator and discriminator\n        monet_generator_gradients = tape.gradient(total_monet_gen_loss,\n                                                  self.m_gen.trainable_variables)\n        photo_generator_gradients = tape.gradient(total_photo_gen_loss,\n                                                  self.p_gen.trainable_variables)\n\n        monet_discriminator_gradients = tape.gradient(monet_disc_loss,\n                                                      self.m_disc.trainable_variables)\n        photo_discriminator_gradients = tape.gradient(photo_disc_loss,\n                                                      self.p_disc.trainable_variables)\n\n        # Apply the gradients to the optimizer\n        self.m_gen_optimizer.apply_gradients(zip(monet_generator_gradients,\n                                                 self.m_gen.trainable_variables))\n\n        self.p_gen_optimizer.apply_gradients(zip(photo_generator_gradients,\n                                                 self.p_gen.trainable_variables))\n\n        self.m_disc_optimizer.apply_gradients(zip(monet_discriminator_gradients,\n                                                  self.m_disc.trainable_variables))\n\n        self.p_disc_optimizer.apply_gradients(zip(photo_discriminator_gradients,\n                                                  self.p_disc.trainable_variables))\n        \n        return {\n            \"monet_gen_loss\": total_monet_gen_loss,\n            \"photo_gen_loss\": total_photo_gen_loss,\n            \"monet_disc_loss\": monet_disc_loss,\n            \"photo_disc_loss\": photo_disc_loss\n        }","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"with strategy.scope():\n    def discriminator_loss(predictions_real, predictions_gen, labels_real):\n        return (tf.reduce_mean((predictions_gen  - tf.reduce_mean(predictions_real) + labels_real) ** 2) +\n                tf.reduce_mean((predictions_real - tf.reduce_mean(predictions_gen)  - labels_real) ** 2))/2\n    \n    def generator_loss(predictions_real, predictions_gen, labels_real):\n        return (tf.reduce_mean((predictions_real - tf.reduce_mean(predictions_gen)  + labels_real) ** 2) +\n                tf.reduce_mean((predictions_gen  - tf.reduce_mean(predictions_real) - labels_real) ** 2)) / 2","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"with strategy.scope():\n    def calc_cycle_loss(real_image, cycled_image, LAMBDA):\n        loss1 = tf.reduce_mean(tf.abs(real_image - cycled_image))\n\n        return LAMBDA * loss1","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"with strategy.scope():\n    def identity_loss(real_image, same_image, LAMBDA):\n        loss = tf.reduce_mean(tf.abs(real_image - same_image))\n        return LAMBDA * 0.5 * loss","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"with strategy.scope():\n    monet_generator_optimizer = tf.keras.optimizers.Adam(LR_G, beta_1=0.5)\n    photo_generator_optimizer = tf.keras.optimizers.Adam(LR_G, beta_1=0.5)\n\n    monet_discriminator_optimizer = tf.keras.optimizers.Adam(LR_D, beta_1=0.5)\n    photo_discriminator_optimizer = tf.keras.optimizers.Adam(LR_D, beta_1=0.5)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"with strategy.scope():\n    cycle_gan_model = CycleGan(\n        monet_cycle_generator, photo_cycle_generator, monet_cycle_discriminator, photo_cycle_discriminator, real_label=0.66\n    )\n\n    cycle_gan_model.compile(\n        m_gen_optimizer = monet_generator_optimizer,\n        p_gen_optimizer = photo_generator_optimizer,\n        m_disc_optimizer = monet_discriminator_optimizer,\n        p_disc_optimizer = photo_discriminator_optimizer,\n        gen_loss_fn = generator_loss,\n        disc_loss_fn = discriminator_loss,\n        cycle_loss_fn = calc_cycle_loss,\n        identity_loss_fn = identity_loss\n    )","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_kg_hide-output":true},"cell_type":"code","source":"history = cycle_gan_model.fit(\n    tf.data.Dataset.zip((load_dataset(MONET_FILENAMES, labeled=True, repeats=45, noise=True).batch(128, drop_remainder=True), load_dataset(PHOTO_FILENAMES, labeled=True, repeats=2, noise=True).batch(128, drop_remainder=True))),\n    epochs=EPOCHS\n)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"plt.plot(history.history['photo_gen_loss'], label='photo_gen_loss')\nplt.plot(history.history['photo_disc_loss'], label='photo_disc_loss')\nplt.title('Photo GAN')\nplt.ylabel('Loss value')\nplt.xlabel('No. Epoch')\nplt.legend(loc=\"upper left\")\nplt.show()\n\nplt.plot(history.history['monet_gen_loss'], label='monet_gen_loss')\nplt.plot(history.history['monet_disc_loss'], label='monet_disc_loss')\nplt.title('Monet GAN')\nplt.ylabel('Loss value')\nplt.xlabel('No. Epoch')\nplt.legend(loc=\"upper left\")\nplt.show()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"_, ax = plt.subplots(2, 5, figsize=(25, 5))\nfor i, img in enumerate(load_dataset(PHOTO_FILENAMES, labeled=True, repeats=2, noise=True).batch(100, drop_remainder=True).take(5)):\n    prediction = monet_cycle_generator(img, training=False)[0].numpy()\n    prediction = (prediction * 127.5 + 127.5).astype(np.uint8)\n    img = (img[0] * 127.5 + 127.5).numpy().astype(np.uint8)\n\n    ax[0, i].imshow(img)\n    ax[1, i].imshow(prediction)\n    ax[0, i].set_title(\"Input Photo\")\n    ax[1, i].set_title(\"Monet-esque\")\n    ax[0, i].axis(\"off\")\n    ax[1, i].axis(\"off\")\nplt.show()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"import PIL\n! mkdir ../images","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"i = 1\nfor img in load_dataset(PHOTO_FILENAMES, labeled=True, repeats=1).batch(1):\n    prediction = monet_cycle_generator(img, training=False)[0].numpy()\n    prediction = (prediction * 127.5 + 127.5).astype(np.uint8)\n    im = PIL.Image.fromarray(prediction)\n    im.save(\"../images/\" + str(i) + \".jpg\")\n    i += 1\n    \nprint(i)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"import shutil\nshutil.make_archive(\"/kaggle/working/images\", 'zip', \"/kaggle/images\")","execution_count":null,"outputs":[]}],"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"pygments_lexer":"ipython3","nbconvert_exporter":"python","version":"3.6.4","file_extension":".py","codemirror_mode":{"name":"ipython","version":3},"name":"python","mimetype":"text/x-python"}},"nbformat":4,"nbformat_minor":4}