{"metadata":{"kernelspec":{"name":"python3","display_name":"Python 3","language":"python"},"language_info":{"name":"python","version":"3.10.13","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"toc":{"base_numbering":1,"nav_menu":{},"number_sections":true,"sideBar":true,"skip_h1_title":true,"title_cell":"Table of Contents","title_sidebar":"Contents","toc_cell":false,"toc_position":{},"toc_section_display":true,"toc_window_display":false},"kaggle":{"accelerator":"gpu","dataSources":[{"sourceId":21755,"databundleVersionId":1475600,"sourceType":"competition"}],"dockerImageVersionId":30648,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"# DTSA-5511: Week 5 Mini- Project\n## Brief description of the problem and data\n\nThis project is based on Kaggle competition [\"I’m Something of a Painter Myself\"](https://www.kaggle.com/competitions/gan-getting-started),  I will make use of Generative Adversarial Networks (GANs) to replicate the distinctive artistic style of Claude Monet. GANs consist of generator and discriminator neural networks, working in tandem yet with opposing goals. The generator strives to create images, in this case in the style of Monet.\n\nThis competition challenges participants to construct a GAN capable of producing 7,000 to 10,000 images mirroring Monet’s unique artistic essence, exploring the potential of data science in mimicking intricate artistic styles traditionally perceived as solely human endeavors.","metadata":{}},{"cell_type":"code","source":"pip install tensorflow-addons","metadata":{"execution":{"iopub.status.busy":"2024-02-07T05:48:16.809150Z","iopub.execute_input":"2024-02-07T05:48:16.809570Z","iopub.status.idle":"2024-02-07T05:48:33.154298Z","shell.execute_reply.started":"2024-02-07T05:48:16.809525Z","shell.execute_reply":"2024-02-07T05:48:33.152878Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import sys\nimport platform\nimport numpy as np \nimport pandas as pd\nimport matplotlib.pyplot as plt\nimport os\nimport warnings\n\nimport PIL\nimport shutil\n\nimport tensorflow as tf\nimport tensorflow_addons as tfa\n\nfrom tensorflow import keras\nfrom tensorflow.keras import layers\n\n\nwarnings.simplefilter(action = 'ignore', category = FutureWarning)\nwarnings.simplefilter(action = 'ignore', category = Warning)","metadata":{"ExecuteTime":{"start_time":"2024-02-06T07:33:01.044Z"},"execution":{"iopub.status.busy":"2024-02-07T05:48:58.759718Z","iopub.execute_input":"2024-02-07T05:48:58.760142Z","iopub.status.idle":"2024-02-07T05:48:58.959101Z","shell.execute_reply.started":"2024-02-07T05:48:58.760094Z","shell.execute_reply":"2024-02-07T05:48:58.958035Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"sys.version","metadata":{"execution":{"iopub.status.busy":"2024-02-07T05:49:06.833896Z","iopub.execute_input":"2024-02-07T05:49:06.834287Z","iopub.status.idle":"2024-02-07T05:49:06.842502Z","shell.execute_reply.started":"2024-02-07T05:49:06.834258Z","shell.execute_reply":"2024-02-07T05:49:06.841205Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"tf.__version__","metadata":{"execution":{"iopub.status.busy":"2024-02-07T05:49:08.582235Z","iopub.execute_input":"2024-02-07T05:49:08.582653Z","iopub.status.idle":"2024-02-07T05:49:08.589467Z","shell.execute_reply.started":"2024-02-07T05:49:08.582616Z","shell.execute_reply":"2024-02-07T05:49:08.588345Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"tf.config.list_physical_devices('GPU')","metadata":{"execution":{"iopub.status.busy":"2024-02-07T05:49:11.814675Z","iopub.execute_input":"2024-02-07T05:49:11.815084Z","iopub.status.idle":"2024-02-07T05:49:12.044905Z","shell.execute_reply.started":"2024-02-07T05:49:11.815046Z","shell.execute_reply":"2024-02-07T05:49:12.043745Z"},"trusted":true},"execution_count":null,"outputs":[]},{"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()\n    if tf.test.is_gpu_available():\n        print(\"GPU is available.\")\n        !nvidia-smi\n    else:\n        print(\"Training on CPU.\")\n\nprint('Number of replicas:', strategy.num_replicas_in_sync)\n\nAUTOTUNE = tf.data.experimental.AUTOTUNE","metadata":{"execution":{"iopub.status.busy":"2024-02-07T05:49:16.222995Z","iopub.execute_input":"2024-02-07T05:49:16.223681Z","iopub.status.idle":"2024-02-07T05:49:17.683849Z","shell.execute_reply.started":"2024-02-07T05:49:16.223645Z","shell.execute_reply":"2024-02-07T05:49:17.682549Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Unfortunately I can't fix the errors. After some googling, I figured that it is a common error when running WSL 2. If you know how to fix it, please tell me.\n\n# Exploratory Data Analysis(EDA) - Inspect, Visualize and Clean the Data\n\nI would now start inspecting our dataset","metadata":{}},{"cell_type":"code","source":"os.listdir(\".\")","metadata":{"execution":{"iopub.status.busy":"2024-02-07T05:49:26.763471Z","iopub.execute_input":"2024-02-07T05:49:26.763944Z","iopub.status.idle":"2024-02-07T05:49:26.771907Z","shell.execute_reply.started":"2024-02-07T05:49:26.763907Z","shell.execute_reply":"2024-02-07T05:49:26.770753Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"count = 0\nfor root, folders, filenames in os.walk('/kaggle/input'):\n   print(root, folders)","metadata":{"execution":{"iopub.status.busy":"2024-02-07T05:49:31.926191Z","iopub.execute_input":"2024-02-07T05:49:31.926618Z","iopub.status.idle":"2024-02-07T05:49:36.829447Z","shell.execute_reply.started":"2024-02-07T05:49:31.926585Z","shell.execute_reply":"2024-02-07T05:49:36.828383Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"MONET_FILENAMES = tf.io.gfile.glob(str('/kaggle/input/gan-getting-started/monet_tfrec/*.tfrec'))\nprint('Monet TFRecord Files:', len(MONET_FILENAMES))\n\nPHOTO_FILENAMES = tf.io.gfile.glob(str('/kaggle/input/gan-getting-started/photo_tfrec/*.tfrec'))\nprint('Photo TFRecord Files:', len(PHOTO_FILENAMES))","metadata":{"execution":{"iopub.status.busy":"2024-02-07T05:49:36.831162Z","iopub.execute_input":"2024-02-07T05:49:36.831501Z","iopub.status.idle":"2024-02-07T05:49:36.842583Z","shell.execute_reply.started":"2024-02-07T05:49:36.831473Z","shell.execute_reply":"2024-02-07T05:49:36.841386Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"IMAGE_SIZE = [256, 256]\n\ndef decode_image(image):\n    image = tf.image.decode_jpeg(image, channels=3)\n    image = (tf.cast(image, tf.float32) / 127.5) - 1\n    image = tf.reshape(image, [*IMAGE_SIZE, 3])\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","metadata":{"execution":{"iopub.status.busy":"2024-02-07T05:49:39.845354Z","iopub.execute_input":"2024-02-07T05:49:39.846332Z","iopub.status.idle":"2024-02-07T05:49:39.854620Z","shell.execute_reply.started":"2024-02-07T05:49:39.846290Z","shell.execute_reply":"2024-02-07T05:49:39.853368Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def load_dataset(filenames, labeled=True, ordered=False):\n    dataset = tf.data.TFRecordDataset(filenames)\n    dataset = dataset.map(read_tfrecord, num_parallel_calls=AUTOTUNE)\n    return dataset","metadata":{"execution":{"iopub.status.busy":"2024-02-07T05:49:48.002566Z","iopub.execute_input":"2024-02-07T05:49:48.002971Z","iopub.status.idle":"2024-02-07T05:49:48.008957Z","shell.execute_reply.started":"2024-02-07T05:49:48.002935Z","shell.execute_reply":"2024-02-07T05:49:48.007601Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"monet_ds = load_dataset(MONET_FILENAMES, labeled=True).batch(1)\nphoto_ds = load_dataset(PHOTO_FILENAMES, labeled=True).batch(1)","metadata":{"execution":{"iopub.status.busy":"2024-02-07T05:49:50.652374Z","iopub.execute_input":"2024-02-07T05:49:50.652811Z","iopub.status.idle":"2024-02-07T05:49:51.233625Z","shell.execute_reply.started":"2024-02-07T05:49:50.652778Z","shell.execute_reply":"2024-02-07T05:49:51.232662Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def count_items_in_dataset(dataset):\n    count = 0\n    for _ in dataset:\n        count += 1\n    return count\n\nprint(f\"Number of Monet images: {count_items_in_dataset(monet_ds)}\")\nprint(f\"Number of Photo images: {count_items_in_dataset(photo_ds)}\")","metadata":{"execution":{"iopub.status.busy":"2024-02-07T05:49:52.215841Z","iopub.execute_input":"2024-02-07T05:49:52.216273Z","iopub.status.idle":"2024-02-07T05:49:58.919364Z","shell.execute_reply.started":"2024-02-07T05:49:52.216240Z","shell.execute_reply":"2024-02-07T05:49:58.918327Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def display_samples(ds, title, samples = 5):\n    plt.figure(figsize = (20, 8))\n    for i, img in enumerate(ds.take(samples)):\n        plt.subplot(1, samples, i + 1)\n        plt.title(f'{title} {i + 1}')\n        plt.imshow(img[0] * 0.5 + 0.5)\n        plt.axis('off')\n    plt.show()","metadata":{"execution":{"iopub.status.busy":"2024-02-07T05:49:58.929633Z","iopub.execute_input":"2024-02-07T05:49:58.929975Z","iopub.status.idle":"2024-02-07T05:49:58.938788Z","shell.execute_reply.started":"2024-02-07T05:49:58.929948Z","shell.execute_reply":"2024-02-07T05:49:58.937779Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Let us check some of the first pictures","metadata":{}},{"cell_type":"code","source":"display_samples(monet_ds, 'Monet')\ndisplay_samples(photo_ds, 'Photo')","metadata":{"execution":{"iopub.status.busy":"2024-02-07T05:49:59.762704Z","iopub.execute_input":"2024-02-07T05:49:59.763096Z","iopub.status.idle":"2024-02-07T05:50:01.384578Z","shell.execute_reply.started":"2024-02-07T05:49:59.763065Z","shell.execute_reply":"2024-02-07T05:50:01.383415Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"The dataset provides 300 Monet images and 7,038 photo images. It is distinctive that Monet paintings exhibit quite strong characteristics when compared to photos. Next, we will create and train a model to generate Monet-like photos, detailing how we achieve the objective.","metadata":{}},{"cell_type":"markdown","source":"# Model Architecture\n## Model selection\nThere are several GAN models available, GAN, CycleGAN, Pix2Pix, StyleGAN, StarGAN and others. For this project, we have chosen to implement the CycleGAN while some of models required paired training samples.\n### CycleGAN\nCycleGAN is a deep CNN approach for learning for image-to-image translation, enabling the transformation of images from one domain to another without paired training examples. It utilizes a cycle-consistency loss to ensure that the translation is coherent and can be reverted back to the original image.\n\nIt can learn to translate between two image domains without paired training data, which is a significant advantage in real-world scenarios where obtaining such pairs is often unfeasible.\n#### Building the generator(UNET architecture)\nWe would reduce the 2D dimensions of the image, using Conv2D layers, Instance Normalization, and LeakyReLU activation.","metadata":{}},{"cell_type":"code","source":"OUTPUT_CHANNELS = 3\n\ndef downsample(filters, size, apply_instancenorm=True):\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=2, padding='same',\n                             kernel_initializer=initializer, use_bias=False))\n\n    if apply_instancenorm:\n        result.add(tfa.layers.InstanceNormalization(gamma_initializer=gamma_init))\n\n    result.add(layers.LeakyReLU())\n\n    return result","metadata":{"execution":{"iopub.status.busy":"2024-02-07T05:50:05.297914Z","iopub.execute_input":"2024-02-07T05:50:05.298717Z","iopub.status.idle":"2024-02-07T05:50:05.306295Z","shell.execute_reply.started":"2024-02-07T05:50:05.298679Z","shell.execute_reply":"2024-02-07T05:50:05.305224Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"We would also increases the 2D dimensions of the image using Conv2DTranspose layers, Instance Normalization, and ReLU activation.","metadata":{}},{"cell_type":"code","source":"def upsample(filters, size, apply_dropout=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=2,\n                                      padding='same',\n                                      kernel_initializer=initializer,\n                                      use_bias=False))\n\n    result.add(tfa.layers.InstanceNormalization(gamma_initializer=gamma_init))\n\n    if apply_dropout:\n        result.add(layers.Dropout(0.5))\n\n    result.add(layers.ReLU())\n\n    return result","metadata":{"execution":{"iopub.status.busy":"2024-02-07T05:50:07.947045Z","iopub.execute_input":"2024-02-07T05:50:07.947464Z","iopub.status.idle":"2024-02-07T05:50:07.955530Z","shell.execute_reply.started":"2024-02-07T05:50:07.947431Z","shell.execute_reply":"2024-02-07T05:50:07.954243Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Concatenates the output of downsample layers to upsample layers symmetrically to bypass the vanishing gradient problem and outputs an image into the target domain.","metadata":{}},{"cell_type":"code","source":"def Generator():\n    inputs = layers.Input(shape=[256,256,3])\n\n    # bs = batch size\n    down_stack = [\n        downsample(64, 4, apply_instancenorm=False), # (bs, 128, 128, 64)\n        downsample(128, 4), # (bs, 64, 64, 128)\n        downsample(256, 4), # (bs, 32, 32, 256)\n        downsample(512, 4), # (bs, 16, 16, 512)\n        downsample(512, 4), # (bs, 8, 8, 512)\n        downsample(512, 4), # (bs, 4, 4, 512)\n        downsample(512, 4), # (bs, 2, 2, 512)\n        downsample(512, 4), # (bs, 1, 1, 512)\n    ]\n\n    up_stack = [\n        upsample(512, 4, apply_dropout=True), # (bs, 2, 2, 1024)\n        upsample(512, 4, apply_dropout=True), # (bs, 4, 4, 1024)\n        upsample(512, 4, apply_dropout=True), # (bs, 8, 8, 1024)\n        upsample(512, 4), # (bs, 16, 16, 1024)\n        upsample(256, 4), # (bs, 32, 32, 512)\n        upsample(128, 4), # (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\n    x = last(x)\n\n    return keras.Model(inputs=inputs, outputs=x)","metadata":{"execution":{"iopub.status.busy":"2024-02-07T05:50:10.366944Z","iopub.execute_input":"2024-02-07T05:50:10.367335Z","iopub.status.idle":"2024-02-07T05:50:10.380611Z","shell.execute_reply.started":"2024-02-07T05:50:10.367307Z","shell.execute_reply":"2024-02-07T05:50:10.379254Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"2D image where higher pixel values indicate real classifications and lower values indicate fake classifications.","metadata":{}},{"cell_type":"code","source":"def Discriminator():\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, 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 = layers.Conv2D(1, 4, strides=1,\n                         kernel_initializer=initializer)(zero_pad2) # (bs, 30, 30, 1)\n\n    return tf.keras.Model(inputs=inp, outputs=last)","metadata":{"execution":{"iopub.status.busy":"2024-02-07T05:50:13.463595Z","iopub.execute_input":"2024-02-07T05:50:13.464028Z","iopub.status.idle":"2024-02-07T05:50:13.475449Z","shell.execute_reply.started":"2024-02-07T05:50:13.463997Z","shell.execute_reply":"2024-02-07T05:50:13.474163Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"with strategy.scope():\n    monet_generator = Generator() # transforms photos to Monet-esque paintings\n    photo_generator = Generator() # transforms Monet paintings to be more like photos\n\n    monet_discriminator = Discriminator() # differentiates real Monet paintings and generated Monet paintings\n    photo_discriminator = Discriminator() # differentiates real photos and generated photos","metadata":{"execution":{"iopub.status.busy":"2024-02-07T05:50:16.059812Z","iopub.execute_input":"2024-02-07T05:50:16.060223Z","iopub.status.idle":"2024-02-07T05:50:20.086258Z","shell.execute_reply.started":"2024-02-07T05:50:16.060193Z","shell.execute_reply":"2024-02-07T05:50:20.085250Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"#### Building the CycleGAN model","metadata":{}},{"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    ):\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        \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        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_fake_monet)\n            photo_gen_loss = self.gen_loss_fn(disc_fake_photo)\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)\n            photo_disc_loss = self.disc_loss_fn(disc_real_photo, disc_fake_photo)\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        }","metadata":{"execution":{"iopub.status.busy":"2024-02-07T05:50:20.546109Z","iopub.execute_input":"2024-02-07T05:50:20.546494Z","iopub.status.idle":"2024-02-07T05:50:20.567741Z","shell.execute_reply.started":"2024-02-07T05:50:20.546467Z","shell.execute_reply":"2024-02-07T05:50:20.566672Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"#### Defining the loss functions","metadata":{}},{"cell_type":"code","source":"with strategy.scope():\n    def discriminator_loss(real, generated):\n        real_loss = tf.keras.losses.BinaryCrossentropy(from_logits=True, reduction=tf.keras.losses.Reduction.NONE)(tf.ones_like(real), real)\n\n        generated_loss = tf.keras.losses.BinaryCrossentropy(from_logits=True, reduction=tf.keras.losses.Reduction.NONE)(tf.zeros_like(generated), generated)\n\n        total_disc_loss = real_loss + generated_loss\n\n        return total_disc_loss * 0.5","metadata":{"execution":{"iopub.status.busy":"2024-02-07T05:50:26.096783Z","iopub.execute_input":"2024-02-07T05:50:26.097209Z","iopub.status.idle":"2024-02-07T05:50:26.104369Z","shell.execute_reply.started":"2024-02-07T05:50:26.097177Z","shell.execute_reply":"2024-02-07T05:50:26.103260Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"with strategy.scope():\n    def generator_loss(generated):\n        return tf.keras.losses.BinaryCrossentropy(from_logits=True, reduction=tf.keras.losses.Reduction.NONE)(tf.ones_like(generated), generated)","metadata":{"execution":{"iopub.status.busy":"2024-02-07T05:50:27.977853Z","iopub.execute_input":"2024-02-07T05:50:27.978264Z","iopub.status.idle":"2024-02-07T05:50:27.984238Z","shell.execute_reply.started":"2024-02-07T05:50:27.978233Z","shell.execute_reply":"2024-02-07T05:50:27.982991Z"},"trusted":true},"execution_count":null,"outputs":[]},{"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","metadata":{"execution":{"iopub.status.busy":"2024-02-07T05:50:29.650496Z","iopub.execute_input":"2024-02-07T05:50:29.651492Z","iopub.status.idle":"2024-02-07T05:50:29.657079Z","shell.execute_reply.started":"2024-02-07T05:50:29.651454Z","shell.execute_reply":"2024-02-07T05:50:29.655937Z"},"trusted":true},"execution_count":null,"outputs":[]},{"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","metadata":{"execution":{"iopub.status.busy":"2024-02-07T05:50:31.858054Z","iopub.execute_input":"2024-02-07T05:50:31.858452Z","iopub.status.idle":"2024-02-07T05:50:31.864274Z","shell.execute_reply.started":"2024-02-07T05:50:31.858422Z","shell.execute_reply":"2024-02-07T05:50:31.863154Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"#### Train the CycleGAN","metadata":{}},{"cell_type":"code","source":"with strategy.scope():\n    monet_generator_optimizer = tf.keras.optimizers.Adam(2e-4, beta_1=0.5)\n    photo_generator_optimizer = tf.keras.optimizers.Adam(2e-4, beta_1=0.5)\n\n    monet_discriminator_optimizer = tf.keras.optimizers.Adam(2e-4, beta_1=0.5)\n    photo_discriminator_optimizer = tf.keras.optimizers.Adam(2e-4, beta_1=0.5)","metadata":{"execution":{"iopub.status.busy":"2024-02-07T05:50:34.013256Z","iopub.execute_input":"2024-02-07T05:50:34.013677Z","iopub.status.idle":"2024-02-07T05:50:34.029251Z","shell.execute_reply.started":"2024-02-07T05:50:34.013648Z","shell.execute_reply":"2024-02-07T05:50:34.027827Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"#### Train the model (Epoch = 50)","metadata":{}},{"cell_type":"code","source":"with strategy.scope():\n    cycle_gan_model_400 = CycleGan(\n        monet_generator, photo_generator, monet_discriminator, photo_discriminator\n    )\n\n    cycle_gan_model_400.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    )","metadata":{"execution":{"iopub.status.busy":"2024-02-07T05:50:35.980529Z","iopub.execute_input":"2024-02-07T05:50:35.980960Z","iopub.status.idle":"2024-02-07T05:50:36.013221Z","shell.execute_reply.started":"2024-02-07T05:50:35.980929Z","shell.execute_reply":"2024-02-07T05:50:36.012292Z"}},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"cycle_gan_model_400.fit(\n    tf.data.Dataset.zip((monet_ds, photo_ds)),\n    epochs=400,\n)","metadata":{"execution":{"iopub.status.busy":"2024-02-07T05:50:38.178814Z","iopub.execute_input":"2024-02-07T05:50:38.179588Z","iopub.status.idle":"2024-02-07T07:49:55.627913Z","shell.execute_reply.started":"2024-02-07T05:50:38.179524Z","shell.execute_reply":"2024-02-07T07:49:55.626832Z"}},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def plot_image():\n    _, ax = plt.subplots(5, 2, figsize=(12, 12))\n    for i, img in enumerate(photo_ds.take(5)):\n        prediction = monet_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[i, 0].imshow(img)\n        ax[i, 1].imshow(prediction)\n        ax[i, 0].set_title(\"Input Photo\")\n        ax[i, 1].set_title(\"Monet-esque\")\n        ax[i, 0].axis(\"off\")\n        ax[i, 1].axis(\"off\")\n    plt.show()","metadata":{"execution":{"iopub.status.busy":"2024-02-07T07:49:55.629934Z","iopub.execute_input":"2024-02-07T07:49:55.630293Z","iopub.status.idle":"2024-02-07T07:49:55.638769Z","shell.execute_reply.started":"2024-02-07T07:49:55.630266Z","shell.execute_reply":"2024-02-07T07:49:55.637677Z"}},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plot_image()","metadata":{"execution":{"iopub.status.busy":"2024-02-07T07:49:55.639880Z","iopub.execute_input":"2024-02-07T07:49:55.640143Z","iopub.status.idle":"2024-02-07T07:49:57.778195Z","shell.execute_reply.started":"2024-02-07T07:49:55.640121Z","shell.execute_reply":"2024-02-07T07:49:57.776983Z"}},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def generate_images(image_path):\n    \n    i = 1\n    for img in photo_ds:\n        prediction = monet_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(image_path + str(i) + \".jpg\")\n        i += 1","metadata":{"execution":{"iopub.status.busy":"2024-02-07T07:49:57.780767Z","iopub.execute_input":"2024-02-07T07:49:57.781173Z","iopub.status.idle":"2024-02-07T07:49:57.789398Z","shell.execute_reply.started":"2024-02-07T07:49:57.781141Z","shell.execute_reply":"2024-02-07T07:49:57.788116Z"}},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"os.makedirs(\"images_400\")\ngenerate_images('./images_400/')","metadata":{"execution":{"iopub.status.busy":"2024-02-07T07:49:57.791069Z","iopub.execute_input":"2024-02-07T07:49:57.791464Z","iopub.status.idle":"2024-02-07T08:01:09.992613Z","shell.execute_reply.started":"2024-02-07T07:49:57.791432Z","shell.execute_reply":"2024-02-07T08:01:09.991122Z"}},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import shutil\nshutil.make_archive(\"/kaggle/working/images\", 'zip', \"/kaggle/working/images_400\")","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"#### Train the model (Epoch = 100)","metadata":{}},{"cell_type":"markdown","source":"with strategy.scope():\n    cycle_gan_model_100 = CycleGan(\n        monet_generator, photo_generator, monet_discriminator, photo_discriminator\n    )\n\n    cycle_gan_model_100.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    )","metadata":{"execution":{"iopub.status.busy":"2024-02-07T08:01:09.995361Z","iopub.execute_input":"2024-02-07T08:01:09.995761Z","iopub.status.idle":"2024-02-07T08:01:10.018092Z","shell.execute_reply.started":"2024-02-07T08:01:09.995729Z","shell.execute_reply":"2024-02-07T08:01:10.017151Z"}}},{"cell_type":"markdown","source":"cycle_gan_model_100.fit(\n    tf.data.Dataset.zip((monet_ds, photo_ds)),\n    epochs=100\n)","metadata":{"execution":{"iopub.status.busy":"2024-02-07T08:01:10.019355Z","iopub.execute_input":"2024-02-07T08:01:10.019697Z"}}},{"cell_type":"markdown","source":"plot_image()","metadata":{}},{"cell_type":"markdown","source":"os.makedirs(\"images_100\")\ngenerate_images('./images_100/')","metadata":{}},{"cell_type":"markdown","source":"import shutil\nshutil.make_archive(\"/kaggle/working/images_100\", 'zip', \"/kaggle/images\")","metadata":{}},{"cell_type":"markdown","source":"#### Train the model (Epoch = 400)","metadata":{}},{"cell_type":"markdown","source":"with strategy.scope():\n    cycle_gan_model_400 = CycleGan(\n        monet_generator, photo_generator, monet_discriminator, photo_discriminator\n    )\n\n    cycle_gan_model_400.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    )","metadata":{"execution":{"iopub.status.busy":"2024-02-07T05:47:51.974259Z","iopub.status.idle":"2024-02-07T05:47:51.974776Z","shell.execute_reply.started":"2024-02-07T05:47:51.974497Z","shell.execute_reply":"2024-02-07T05:47:51.974517Z"}}},{"cell_type":"markdown","source":"cycle_gan_model_400.fit(\n    tf.data.Dataset.zip((monet_ds, photo_ds)),\n    epochs=400\n)","metadata":{"execution":{"iopub.status.busy":"2024-02-07T05:47:51.976862Z","iopub.status.idle":"2024-02-07T05:47:51.977246Z","shell.execute_reply.started":"2024-02-07T05:47:51.977058Z","shell.execute_reply":"2024-02-07T05:47:51.977074Z"}}},{"cell_type":"markdown","source":"plot_image()","metadata":{"execution":{"iopub.status.busy":"2024-02-07T05:47:51.979050Z","iopub.status.idle":"2024-02-07T05:47:51.979591Z","shell.execute_reply.started":"2024-02-07T05:47:51.979304Z","shell.execute_reply":"2024-02-07T05:47:51.979326Z"}}},{"cell_type":"markdown","source":"os.makedirs(\"images_400\")\ngenerate_images('./images_400/')","metadata":{"execution":{"iopub.status.busy":"2024-02-07T05:47:51.981411Z","iopub.status.idle":"2024-02-07T05:47:51.981807Z","shell.execute_reply.started":"2024-02-07T05:47:51.981619Z","shell.execute_reply":"2024-02-07T05:47:51.981635Z"}}},{"cell_type":"markdown","source":"import shutil\nshutil.make_archive(\"/kaggle/working/images_400\", 'zip', \"/kaggle/images\")","metadata":{}}]}