{"metadata":{"kernelspec":{"name":"python3","display_name":"Python 3","language":"python"},"language_info":{"name":"python","version":"3.11.11","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"nvidiaTeslaT4","dataSources":[{"sourceId":21755,"databundleVersionId":1475600,"sourceType":"competition"}],"dockerImageVersionId":31041,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"# **Libraries**","metadata":{}},{"cell_type":"code","source":"import tensorflow as tf\nfrom tensorflow.keras import layers, Model\nfrom tensorflow.keras.layers import GroupNormalization\nfrom tensorflow.keras.models import Sequential\nfrom tensorflow.keras.layers import Layer, Conv2D, Conv2DTranspose, ReLU, Activation, Lambda, GroupNormalization\nimport numpy as np \nimport pandas as pd\nimport os\nimport time\nimport matplotlib.pyplot as plt\nfrom IPython.display import clear_output\nimport cv2\n\nAUTOTUNE = tf.data.AUTOTUNE","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true,"execution":{"iopub.status.busy":"2025-07-03T07:36:01.283383Z","iopub.execute_input":"2025-07-03T07:36:01.283737Z","iopub.status.idle":"2025-07-03T07:36:15.483512Z","shell.execute_reply.started":"2025-07-03T07:36:01.283704Z","shell.execute_reply":"2025-07-03T07:36:15.482663Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# **Configurations**","metadata":{}},{"cell_type":"code","source":"monet_path = \"/kaggle/input/gan-getting-started/monet_jpg\"\nphotos_path = \"/kaggle/input/gan-getting-started/photo_jpg\"\n\nBUFFER_SIZE = 1000\nIMG_WIDTH = 256\nIMG_HEIGHT = 256\nAUG_PER_IMAGE = 5\nBATCH_SIZE = 8","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-03T07:36:15.484319Z","iopub.execute_input":"2025-07-03T07:36:15.484809Z","iopub.status.idle":"2025-07-03T07:36:15.489372Z","shell.execute_reply.started":"2025-07-03T07:36:15.484788Z","shell.execute_reply":"2025-07-03T07:36:15.488458Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# **Data loading and Preprocessing**","metadata":{}},{"cell_type":"code","source":"def count_images(directory):\n    return sum(1 for file in os.scandir(directory) \n               if file.name.lower().endswith(('.jpg', '.jpeg', '.png')))","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-03T07:36:15.490227Z","iopub.execute_input":"2025-07-03T07:36:15.490483Z","iopub.status.idle":"2025-07-03T07:36:15.555256Z","shell.execute_reply.started":"2025-07-03T07:36:15.490455Z","shell.execute_reply":"2025-07-03T07:36:15.554373Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"print(f'Total Monet images: {count_images(monet_path)}')\nprint(f'Total photos: {count_images(photos_path)}')","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-03T07:36:15.557366Z","iopub.execute_input":"2025-07-03T07:36:15.557602Z","iopub.status.idle":"2025-07-03T07:36:15.678903Z","shell.execute_reply.started":"2025-07-03T07:36:15.557585Z","shell.execute_reply":"2025-07-03T07:36:15.677756Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"'''transform = A.Compose(\n    [\n        A.Resize(width = 256, height = 256),\n        A.HorizontalFlip(p = 0.5),\n        A.ColorJitter(p = 0.1),\n        A.Normalize(mean = [0.5, 0.5, 0.5], \n                    std = [0.5, 0.5, 0.5], \n                    max_pixel_value = 255),\n        ToTensorV2(),\n    ],\n    additional_targets = {\"image0\": \"image\"}\n)'''","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-03T07:36:15.679743Z","iopub.execute_input":"2025-07-03T07:36:15.679940Z","iopub.status.idle":"2025-07-03T07:36:15.686470Z","shell.execute_reply.started":"2025-07-03T07:36:15.679924Z","shell.execute_reply":"2025-07-03T07:36:15.685558Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def load_and_preprocess(file_path, augmentations_per_image=AUG_PER_IMAGE):\n    image = tf.io.read_file(file_path)\n    image = tf.image.decode_jpeg(image, channels=3)\n    image = tf.image.resize(image, [286, 286])\n\n    def augment_fn(_):\n        aug = tf.image.random_crop(image, [256, 256, 3])\n        aug = tf.image.random_flip_left_right(aug)\n        aug = tf.cast(aug, tf.float32) / 127.5 - 1.0\n        return aug\n\n    return tf.data.Dataset.range(augmentations_per_image).map(augment_fn)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-03T07:36:15.687355Z","iopub.execute_input":"2025-07-03T07:36:15.687645Z","iopub.status.idle":"2025-07-03T07:36:15.710849Z","shell.execute_reply.started":"2025-07-03T07:36:15.687595Z","shell.execute_reply":"2025-07-03T07:36:15.710098Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"**Create datasets of Monet and normal photos**","metadata":{}},{"cell_type":"code","source":"tf_monet = tf.data.Dataset.list_files(monet_path + \"/*.jpg\", shuffle=True)\ntf_photos = tf.data.Dataset.list_files(photos_path + \"/*.jpg\", shuffle=True)\n\nmonet_dataset = (\n    tf_monet\n    .flat_map(load_and_preprocess)\n    .shuffle(BUFFER_SIZE)\n    .batch(BATCH_SIZE)\n    .prefetch(tf.data.AUTOTUNE)\n)\n\nphoto_dataset = (\n    tf_photos\n    .flat_map(load_and_preprocess)\n    .shuffle(BUFFER_SIZE)\n    .batch(BATCH_SIZE)\n    .prefetch(tf.data.AUTOTUNE)\n)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-03T07:36:15.711879Z","iopub.execute_input":"2025-07-03T07:36:15.712222Z","iopub.status.idle":"2025-07-03T07:36:22.309596Z","shell.execute_reply.started":"2025-07-03T07:36:15.712164Z","shell.execute_reply":"2025-07-03T07:36:22.309024Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"Counting data, can be excluded and deleted","metadata":{}},{"cell_type":"code","source":"'''monet_count = sum(1 for _ in monet_dataset)\nphoto_count = sum(1 for _ in photo_dataset)\n\nprint(\"Monet dataset size:\", \n      monet_count)\nprint(\"Photo dataset size:\", photo_count)\n'''","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-03T07:36:22.310249Z","iopub.execute_input":"2025-07-03T07:36:22.310459Z","iopub.status.idle":"2025-07-03T07:36:22.315405Z","shell.execute_reply.started":"2025-07-03T07:36:22.310443Z","shell.execute_reply":"2025-07-03T07:36:22.314776Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# **Visualizing dataset in batches**","metadata":{}},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# **Reflection Padding**","metadata":{}},{"cell_type":"code","source":"import tensorflow as tf\nfrom tensorflow.keras.layers import Layer, InputSpec\n\nclass ReflectionPadding2D(Layer):\n    def __init__(self, padding=(1, 1), **kwargs):\n        self.padding = tuple(padding)\n        self.input_spec = [InputSpec(ndim=4)]\n        super(ReflectionPadding2D, self).__init__(**kwargs)\n\n    def call(self, x, mask=None):\n        w_pad, h_pad = self.padding\n        return tf.pad(x, [[0, 0], [h_pad, h_pad], [w_pad, w_pad], [0, 0]], mode='REFLECT')\n\n    def compute_output_shape(self, input_shape):\n        return (input_shape[0],\n                input_shape[1] + 2 * self.padding[1],\n                input_shape[2] + 2 * self.padding[0],\n                input_shape[3])\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-03T07:36:22.316139Z","iopub.execute_input":"2025-07-03T07:36:22.316419Z","iopub.status.idle":"2025-07-03T07:36:22.327957Z","shell.execute_reply.started":"2025-07-03T07:36:22.316392Z","shell.execute_reply":"2025-07-03T07:36:22.327050Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# **Instance Normalization by Group Normalization**","metadata":{}},{"cell_type":"code","source":"class InstanceLikeGroupNorm(tf.keras.layers.Layer):\n    def __init__(self, **kwargs):\n        super().__init__()\n        self.kwargs = kwargs\n        self.gn = None\n\n    def build(self, input_shape):\n        channels = input_shape[-1]\n        self.gn = tf.keras.layers.GroupNormalization(groups=channels, axis=-1, **self.kwargs)\n\n    def call(self, inputs):\n        return self.gn(inputs)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-03T07:36:22.328783Z","iopub.execute_input":"2025-07-03T07:36:22.329095Z","iopub.status.idle":"2025-07-03T07:36:22.339538Z","shell.execute_reply.started":"2025-07-03T07:36:22.329072Z","shell.execute_reply":"2025-07-03T07:36:22.338752Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# **Downsample and Upsample**","metadata":{}},{"cell_type":"code","source":"class DownsampleBlock(tf.keras.layers.Layer):\n    def __init__(self, filters, kernel_size, apply_norm=True):\n        super().__init__()\n        self.model = tf.keras.Sequential()\n        self.model.add(layers.Conv2D(filters, kernel_size, strides=2, padding='same',\n                                     kernel_initializer=tf.random_normal_initializer(0., 0.02),\n                                     use_bias=False))\n        if apply_norm:\n            self.model.add(InstanceLikeGroupNorm())\n        self.model.add(layers.LeakyReLU())\n\n    def call(self, x):\n        return self.model(x)\n\n\nclass UpsampleBlock(tf.keras.layers.Layer):\n    def __init__(self, filters, kernel_size):\n        super().__init__()\n        self.model = tf.keras.Sequential([\n            layers.Conv2DTranspose(filters, kernel_size, strides=2, padding='same',\n                                   kernel_initializer=tf.random_normal_initializer(0., 0.02),\n                                   use_bias=False),\n            InstanceLikeGroupNorm(),\n            layers.ReLU()\n        ])\n\n    def call(self, x):\n        return self.model(x)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-03T07:36:22.340358Z","iopub.execute_input":"2025-07-03T07:36:22.340557Z","iopub.status.idle":"2025-07-03T07:36:22.352491Z","shell.execute_reply.started":"2025-07-03T07:36:22.340541Z","shell.execute_reply":"2025-07-03T07:36:22.351619Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# **Residual Block**","metadata":{}},{"cell_type":"code","source":"class ResBlock(tf.keras.layers.Layer):\n    def __init__(self, filters):\n        super().__init__()\n        self.pad1 = ReflectionPadding2D((1, 1))\n        self.conv1 = layers.Conv2D(filters, 3, padding='valid',\n                                   kernel_initializer=tf.random_normal_initializer(0., 0.02),\n                                   use_bias=False)\n        self.norm1 = InstanceLikeGroupNorm()\n        self.relu = layers.ReLU()\n\n        self.pad2 = ReflectionPadding2D((1, 1))\n        self.conv2 = layers.Conv2D(filters, 3, padding='valid',\n                                   kernel_initializer=tf.random_normal_initializer(0., 0.02),\n                                   use_bias=False)\n        self.norm2 = InstanceLikeGroupNorm()\n\n    def call(self, x_input):\n        x = self.pad1(x_input)\n        x = self.conv1(x)\n        x = self.norm1(x)\n        x = self.relu(x)\n\n        x = self.pad2(x)\n        x = self.conv2(x)\n        x = self.norm2(x)\n\n        return layers.Add()([x_input, x])\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-03T07:36:22.353405Z","iopub.execute_input":"2025-07-03T07:36:22.353644Z","iopub.status.idle":"2025-07-03T07:36:22.367493Z","shell.execute_reply.started":"2025-07-03T07:36:22.353601Z","shell.execute_reply":"2025-07-03T07:36:22.366644Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# **ResNet Generator**","metadata":{}},{"cell_type":"code","source":"class ResNetGenerator(tf.keras.Model):\n    def __init__(self, output_channels=3, n_blocks=9):\n        super().__init__()\n        self.initializer = tf.random_normal_initializer(0., 0.02)\n\n        self.pad1 = ReflectionPadding2D((3, 3))\n        self.conv1 = layers.Conv2D(64, kernel_size=7, padding='valid',\n                                   kernel_initializer=self.initializer, use_bias=False)\n        self.norm1 = InstanceLikeGroupNorm()\n        self.relu1 = layers.ReLU()\n\n        self.down1 = DownsampleBlock(128, 3)\n        self.down2 = DownsampleBlock(256, 3)\n\n        self.res_blocks = [ResBlock(256) for _ in range(n_blocks)]\n\n        self.up1 = UpsampleBlock(128, 3)\n        self.up2 = UpsampleBlock(64, 3)\n\n        self.pad2 = ReflectionPadding2D((3, 3))\n        self.out_conv = layers.Conv2D(output_channels, kernel_size=7, padding='valid',\n                                      kernel_initializer=self.initializer, activation='tanh')\n\n    def call(self, inputs):\n        x = self.pad1(inputs)\n        x = self.conv1(x)\n        x = self.norm1(x)\n        x = self.relu1(x)\n\n        x = self.down1(x)\n        x = self.down2(x)\n\n        for block in self.res_blocks:\n            x = block(x)\n\n        x = self.up1(x)\n        x = self.up2(x)\n\n        x = self.pad2(x)\n        return self.out_conv(x)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-03T07:36:22.370493Z","iopub.execute_input":"2025-07-03T07:36:22.370713Z","iopub.status.idle":"2025-07-03T07:36:22.386004Z","shell.execute_reply.started":"2025-07-03T07:36:22.370698Z","shell.execute_reply":"2025-07-03T07:36:22.385355Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# **PatchGAN Discriminator**","metadata":{}},{"cell_type":"code","source":"class PatchGANDiscriminator(tf.keras.Model):\n    def __init__(self, target=False):\n        super().__init__()\n        self.initializer = tf.random_normal_initializer(0., 0.02)\n        self.target = target\n\n        self.down1 = DownsampleBlock(64, 4, apply_norm=False)\n        self.down2 = DownsampleBlock(128, 4)\n        self.down3 = DownsampleBlock(256, 4)\n\n        self.pad1 = ReflectionPadding2D((1, 1))\n        self.conv = layers.Conv2D(512, 4, strides=1, padding='valid',\n                                  kernel_initializer=self.initializer, use_bias=False)\n        self.norm = InstanceLikeGroupNorm()\n        self.leaky_relu = layers.LeakyReLU()\n\n        self.pad2 = ReflectionPadding2D((1, 1))\n        self.final = layers.Conv2D(1, 4, strides=1, padding='valid',\n                                   kernel_initializer=self.initializer)\n\n    def call(self, input_image, target_image=None):\n        x = tf.concat([input_image, target_image], axis=-1) if self.target else input_image\n        x = self.down1(x)\n        x = self.down2(x)\n        x = self.down3(x)\n\n        x = self.pad1(x)\n        x = self.conv(x)\n        x = self.norm(x)\n        x = self.leaky_relu(x)\n\n        x = self.pad2(x)\n        return self.final(x)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-03T07:36:22.386785Z","iopub.execute_input":"2025-07-03T07:36:22.386992Z","iopub.status.idle":"2025-07-03T07:36:22.398425Z","shell.execute_reply.started":"2025-07-03T07:36:22.386977Z","shell.execute_reply":"2025-07-03T07:36:22.397648Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# **Generators and Discriminators initialize**","metadata":{}},{"cell_type":"code","source":"# Generator: Translates images from Photo → Monet\ngenerator_photo_to_monet = ResNetGenerator(output_channels=3, n_blocks=9)\n\n# Generator: Translates images from Monet → Photo\ngenerator_monet_to_photo = ResNetGenerator(output_channels=3, n_blocks=9)\n\n# Discriminator: Judges real vs fake Monet images\ndiscriminator_monet = PatchGANDiscriminator(target=False)\n\n# Discriminator: Judges real vs fake Photo images\ndiscriminator_photo = PatchGANDiscriminator(target=False)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-03T07:36:22.399407Z","iopub.execute_input":"2025-07-03T07:36:22.399703Z","iopub.status.idle":"2025-07-03T07:36:22.533325Z","shell.execute_reply.started":"2025-07-03T07:36:22.399685Z","shell.execute_reply":"2025-07-03T07:36:22.532744Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import matplotlib.pyplot as plt\n\ndef visualize_results(input_img, fake_img, reconstructed_img, title_prefix=\"\"):\n    input_img = (input_img + 1) / 2  # from [-1, 1] → [0, 1]\n    fake_img = (fake_img + 1) / 2\n    reconstructed_img = (reconstructed_img + 1) / 2\n\n    plt.figure(figsize=(12, 4))\n\n    titles = [f\"{title_prefix}Input\", f\"{title_prefix}Fake\", f\"{title_prefix}Reconstructed\"]\n    images = [input_img[0], fake_img[0], reconstructed_img[0]]\n\n    for i in range(3):\n        plt.subplot(1, 3, i + 1)\n        plt.imshow(images[i])\n        plt.title(titles[i])\n        plt.axis(\"off\")\n\n    plt.tight_layout()\n    plt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-03T07:36:22.534066Z","iopub.execute_input":"2025-07-03T07:36:22.534255Z","iopub.status.idle":"2025-07-03T07:36:22.540240Z","shell.execute_reply.started":"2025-07-03T07:36:22.534240Z","shell.execute_reply":"2025-07-03T07:36:22.539354Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"sample_input = tf.random.normal([1, 256, 256, 3])\n\nfake_monet = generator_photo_to_monet(sample_input)\nreconstructed_photo = generator_monet_to_photo(fake_monet)\n\ndecision_photo = discriminator_photo(sample_input)\ndecision_monet = discriminator_monet(fake_monet)\n\nprint(\"Fake Monet shape:         \", fake_monet.shape)\nprint(\"Reconstructed Photo shape:\", reconstructed_photo.shape)\nprint(\"Disc Photo output shape:  \", decision_photo.shape)\nprint(\"Disc Monet output shape:  \", decision_monet.shape)\n\nvisualize_results(sample_input, fake_monet, reconstructed_photo, title_prefix=\"Photo → Monet → Photo: \")\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-03T07:36:22.540989Z","iopub.execute_input":"2025-07-03T07:36:22.541543Z","iopub.status.idle":"2025-07-03T07:36:28.716931Z","shell.execute_reply.started":"2025-07-03T07:36:22.541520Z","shell.execute_reply":"2025-07-03T07:36:28.715988Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# **Optimizers**","metadata":{}},{"cell_type":"code","source":"# Generator: Translates images from Photo → Monet\ngenerator_photo_to_monet_opt = tf.keras.optimizers.Adam(2e-4, beta_1=0.5)\n\n# Generator: Translates images from Monet → Photo\ngenerator_monet_to_photo_opt = tf.keras.optimizers.Adam(2e-4, beta_1=0.5)\n\n# Discriminator: Judges real vs fake Monet images\ndiscriminator_monet_opt = tf.keras.optimizers.Adam(2e-4, beta_1=0.5)\n# Discriminator: Judges real vs fake Photo images\ndiscriminator_photo_opt = tf.keras.optimizers.Adam(2e-4, beta_1=0.5)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-03T07:36:28.718156Z","iopub.execute_input":"2025-07-03T07:36:28.718513Z","iopub.status.idle":"2025-07-03T07:36:28.745222Z","shell.execute_reply.started":"2025-07-03T07:36:28.718485Z","shell.execute_reply":"2025-07-03T07:36:28.744549Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# **Loss Module**","metadata":{}},{"cell_type":"code","source":"LAMBDA = 10\nloss_obj = tf.keras.losses.BinaryCrossentropy(from_logits=True)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-03T07:36:28.746057Z","iopub.execute_input":"2025-07-03T07:36:28.746283Z","iopub.status.idle":"2025-07-03T07:36:28.750051Z","shell.execute_reply.started":"2025-07-03T07:36:28.746265Z","shell.execute_reply":"2025-07-03T07:36:28.749230Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def discriminator_loss(real, generated):\n  real_loss = loss_obj(tf.ones_like(real), real)\n\n  generated_loss = loss_obj(tf.zeros_like(generated), generated)\n\n  total_disc_loss = real_loss + generated_loss\n\n  return total_disc_loss * 0.5","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-03T07:36:28.750896Z","iopub.execute_input":"2025-07-03T07:36:28.751178Z","iopub.status.idle":"2025-07-03T07:36:28.758804Z","shell.execute_reply.started":"2025-07-03T07:36:28.751161Z","shell.execute_reply":"2025-07-03T07:36:28.758082Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def generator_loss(generated):\n  return loss_obj(tf.ones_like(generated), generated)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-03T07:36:28.759800Z","iopub.execute_input":"2025-07-03T07:36:28.760711Z","iopub.status.idle":"2025-07-03T07:36:28.773210Z","shell.execute_reply.started":"2025-07-03T07:36:28.760685Z","shell.execute_reply":"2025-07-03T07:36:28.772479Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def calc_cycle_loss(real_image, cycled_image):\n  loss1 = tf.reduce_mean(tf.abs(real_image - cycled_image))\n\n  return LAMBDA * loss1","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-03T07:36:28.774091Z","iopub.execute_input":"2025-07-03T07:36:28.774766Z","iopub.status.idle":"2025-07-03T07:36:28.785369Z","shell.execute_reply.started":"2025-07-03T07:36:28.774741Z","shell.execute_reply":"2025-07-03T07:36:28.784865Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def identity_loss(real_image, same_image):\n  loss = tf.reduce_mean(tf.abs(real_image - same_image))\n  return LAMBDA * 0.5 * loss","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-03T07:36:28.786085Z","iopub.execute_input":"2025-07-03T07:36:28.786327Z","iopub.status.idle":"2025-07-03T07:36:28.797799Z","shell.execute_reply.started":"2025-07-03T07:36:28.786305Z","shell.execute_reply":"2025-07-03T07:36:28.797169Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"class Loss():\n    def __init__(self, real_image, synthetic_image, mode=None, LAMBDA=10):\n        self.real_img = real_image\n        self.synth_img = synthetic_image\n        self.mode = mode\n        self.LAMBDA = LAMBDA\n        self.loss_obj = tf.keras.losses.BinaryCrossentropy(from_logits=True)\n\n    def discriminator_loss(self, real, generated):\n        real_loss = self.loss_obj(tf.ones_like(real), real)\n        generated_loss = self.loss_obj(tf.zeros_like(generated), generated)\n        total_disc_loss = real_loss + generated_loss\n        return total_disc_loss * 0.5\n        \n    def generator_loss(self, generated):\n        return self.loss_obj(tf.ones_like(generated), generated)\n\n    def calc_cycle_loss(self, real_image, cycled_image):\n        loss1 = tf.reduce_mean(tf.abs(real_image - cycled_image))\n        return self.LAMBDA * loss1\n        \n    def identity_loss(self, real_image, same_image):\n        loss = tf.reduce_mean(tf.abs(real_image - same_image))\n        return self.LAMBDA * 0.5 * loss\n\n    def __call__(self):\n        if self.mode == 'Identity':\n            return self.identity_loss(self.real_img, self.synth_img)\n        elif self.mode == 'Cycle':\n            return self.calc_cycle_loss(self.real_img, self.synth_img)\n        elif self.mode == 'Generator':\n            return self.generator_loss(self.synth_img)\n        elif self.mode == 'Discriminator':\n            return self.discriminator_loss(self.real_img, self.synth_img)\n        else:\n            raise ValueError(f\"Unknown mode: {self.mode}\")\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-03T07:36:28.798487Z","iopub.execute_input":"2025-07-03T07:36:28.798758Z","iopub.status.idle":"2025-07-03T07:36:28.810474Z","shell.execute_reply.started":"2025-07-03T07:36:28.798736Z","shell.execute_reply":"2025-07-03T07:36:28.809843Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# **Checkpoint saver**","metadata":{}},{"cell_type":"code","source":"checkpoint_path = \"/kaggle/working/\"","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-03T07:37:18.565866Z","iopub.execute_input":"2025-07-03T07:37:18.566186Z","iopub.status.idle":"2025-07-03T07:37:18.570117Z","shell.execute_reply.started":"2025-07-03T07:37:18.566169Z","shell.execute_reply":"2025-07-03T07:37:18.569260Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"class CheckPoint:\n    def __init__(self, checkpoint_path, max_ckpts,\n                 generators, discriminators, optimizers):\n        self.path = checkpoint_path\n        self.keep = max_ckpts\n\n        self.checkpoint = tf.train.Checkpoint(\n            generator_photo_to_monet=generators[\"photo_to_monet\"],\n            generator_monet_to_photo=generators[\"monet_to_photo\"],\n            discriminator_monet=discriminators[\"monet\"],\n            discriminator_photo=discriminators[\"photo\"],\n            generator_photo_to_monet_opt=optimizers[\"photo_to_monet\"],\n            generator_monet_to_photo_opt=optimizers[\"monet_to_photo\"],\n            discriminator_monet_opt=optimizers[\"monet\"],\n            discriminator_photo_opt=optimizers[\"photo\"]\n        )\n\n        self.ckpt_manager = tf.train.CheckpointManager(\n            self.checkpoint, self.path, max_to_keep=self.keep\n        )\n\n    def restore_latest(self):\n        if self.ckpt_manager.latest_checkpoint:\n            print(f\"Restoring from {self.ckpt_manager.latest_checkpoint}\")\n            self.checkpoint.restore(self.ckpt_manager.latest_checkpoint).expect_partial()\n        else:\n            print(\"No checkpoint found at the given path.\")\n\n    def save(self):\n        ckpt_path = self.ckpt_manager.save()\n        print(f\"Checkpoint saved at {ckpt_path}\")\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-03T07:37:18.572678Z","iopub.execute_input":"2025-07-03T07:37:18.572969Z","iopub.status.idle":"2025-07-03T07:37:18.586217Z","shell.execute_reply.started":"2025-07-03T07:37:18.572951Z","shell.execute_reply":"2025-07-03T07:37:18.585384Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# **Training**","metadata":{}},{"cell_type":"code","source":"generators = {\n    \"photo_to_monet\": generator_photo_to_monet,\n    \"monet_to_photo\": generator_monet_to_photo,\n}\ndiscriminators = {\n    \"monet\": discriminator_monet,\n    \"photo\": discriminator_photo,\n}\noptimizers = {\n    \"photo_to_monet\": generator_photo_to_monet_opt,\n    \"monet_to_photo\": generator_monet_to_photo_opt,\n    \"monet\": discriminator_monet_opt,\n    \"photo\": discriminator_photo_opt,\n}\n\nckpt_manager = CheckPoint(checkpoint_path, 10, generators, discriminators, optimizers)\n\nckpt_manager.restore_latest()\n\n# during training:\n# ckpt_manager.save()\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-03T07:37:18.587403Z","iopub.execute_input":"2025-07-03T07:37:18.587677Z","iopub.status.idle":"2025-07-03T07:37:18.602412Z","shell.execute_reply.started":"2025-07-03T07:37:18.587656Z","shell.execute_reply":"2025-07-03T07:37:18.601678Z"}},"outputs":[],"execution_count":null}]}