{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.10.12","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"gpu","dataSources":[{"sourceId":21755,"databundleVersionId":1475600,"sourceType":"competition"},{"sourceId":10883168,"sourceType":"datasetVersion","datasetId":6762655}],"dockerImageVersionId":30919,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"\"\"\"\n# This Python 3 environment comes with many helpful analytics libraries installed\n# It is defined by the kaggle/python Docker image: https://github.com/kaggle/docker-python\n# For example, here's several helpful packages to load\n\nimport numpy as np # linear algebra\nimport pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)\n\n# Input data files are available in the read-only \"../input/\" directory\n# For example, running this (by clicking run or pressing Shift+Enter) will list all files under the input directory\n\nimport os\nfor dirname, _, filenames in os.walk('/kaggle/input'):\n    for filename in filenames:\n        print(os.path.join(dirname, filename))\n\n# You can write up to 20GB to the current directory (/kaggle/working/) that gets preserved as output when you create a version using \"Save & Run All\" \n# You can also write temporary files to /kaggle/temp/, but they won't be saved outside of the current session\n\"\"\"","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true,"execution":{"iopub.status.busy":"2025-03-01T01:41:53.438950Z","iopub.execute_input":"2025-03-01T01:41:53.439249Z","iopub.status.idle":"2025-03-01T01:41:53.446573Z","shell.execute_reply.started":"2025-03-01T01:41:53.439214Z","shell.execute_reply":"2025-03-01T01:41:53.446012Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# Cycle GAN Part 2\n\nI trained a cycle GAN in another notbook, and saver a lot of checkpoints, this is because images from some epochs are for my taste better than others and not all the times improving (maybe i should have used some kind of modifier for hyperparametes as epochs went on but i did`t and i belive images are good enough). \n\nSo anyway in went out of space for creating the subbmision file. This is a small notbook loading network again (did not save entire model becasue of HDD space) and using weights from my favorite epoch and creating file for submission.","metadata":{}},{"cell_type":"code","source":"import os\nimport keras\nimport glob\nimport cv2\n\nimport numpy as np\nimport matplotlib.pyplot as plt\nimport tensorflow as tf\nimport tensorflow_datasets as tfds\n\nfrom PIL import Image\nfrom sklearn.cluster import KMeans\nfrom keras import layers, ops","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-03-01T01:41:53.447394Z","iopub.execute_input":"2025-03-01T01:41:53.447715Z","iopub.status.idle":"2025-03-01T01:42:07.045439Z","shell.execute_reply.started":"2025-03-01T01:41:53.447683Z","shell.execute_reply":"2025-03-01T01:42:07.044548Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# CycleGAN 1. Data transformation\n","metadata":{}},{"cell_type":"code","source":"#Read data\n# Get lists of file paths for each domain\nmonet_paths = glob.glob(\"/kaggle/input/gan-getting-started/monet_jpg/*.jpg\")\nphoto_paths = glob.glob(\"/kaggle/input/gan-getting-started/photo_jpg/*.jpg\")\n\n# Create datasets from file paths\nmonet_ds = tf.data.Dataset.from_tensor_slices(monet_paths)\nphoto_ds = tf.data.Dataset.from_tensor_slices(photo_paths)\n\n# Function to load an image, convert pixel values to [-1, 1], and assign a label.\ndef load_monet_image(path):\n    image = tf.io.read_file(path)\n    image = tf.image.decode_jpeg(image, channels=3)\n    image = tf.image.convert_image_dtype(image, tf.float32)  # Scales to [0, 1]\n    image = (image - 0.5) * 2  # Now in [-1, 1]\n    return image\n\ndef load_photo_image(path):\n    image = tf.io.read_file(path)\n    image = tf.image.decode_jpeg(image, channels=3)\n    image = tf.image.convert_image_dtype(image, tf.float32)  # Scales to [0, 1]\n    image = (image - 0.5) * 2  # Now in [-1, 1]\n    return image\n\n# Map the functions to load and decode images with labels\nmonet_ds = (\n    monet_ds.map(load_monet_image, num_parallel_calls=tf.data.AUTOTUNE)\n    .shuffle(buffer_size=1000)\n)\n\nphoto_ds = (\n     photo_ds.map(load_photo_image, num_parallel_calls=tf.data.AUTOTUNE)\n     .shuffle(buffer_size=1000)\n )\n\n# Organize datasets in a dictionary similar to CycleGAN's \"trainA\" and \"trainB\"\ndataset = {\n    \"trainA\": monet_ds,\n    \"trainB\": photo_ds\n}\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-03-01T01:42:07.046305Z","iopub.execute_input":"2025-03-01T01:42:07.046764Z","iopub.status.idle":"2025-03-01T01:42:08.341721Z","shell.execute_reply.started":"2025-03-01T01:42:07.046742Z","shell.execute_reply":"2025-03-01T01:42:08.341052Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"#buffer and batches\nbuffer_size = 256\nbatch_size = 1\n\n#loading datasets\ntrain_monet, train_photos = dataset[\"trainA\"], dataset[\"trainB\"]\ntrain_monet = (\n    train_monet.map(lambda img: img, num_parallel_calls=tf.data.AUTOTUNE)\n    .cache()\n    .shuffle(buffer_size)\n    .batch(batch_size)\n)\ntrain_photos = (\n    train_photos.map(lambda img: img, num_parallel_calls=tf.data.AUTOTUNE)\n    .cache()\n    .shuffle(buffer_size)\n    .batch(batch_size)\n)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-03-01T01:42:08.342572Z","iopub.execute_input":"2025-03-01T01:42:08.342870Z","iopub.status.idle":"2025-03-01T01:42:08.381802Z","shell.execute_reply.started":"2025-03-01T01:42:08.342842Z","shell.execute_reply":"2025-03-01T01:42:08.381230Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# Cycle GAN 2. Constructing NN","metadata":{}},{"cell_type":"code","source":"#Important Variables\nautotune = tf.data.AUTOTUNE\n#Kernel_init\nkernel_init = keras.initializers.RandomNormal(mean=0.0, stddev=0.02)\n# Gamma initializer for instance normalization.\ngamma_init = keras.initializers.RandomNormal(mean=0.0, stddev=0.02)\n#img size\ninput_img_size = (256, 256, 3)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-03-01T01:42:08.382496Z","iopub.execute_input":"2025-03-01T01:42:08.382702Z","iopub.status.idle":"2025-03-01T01:42:08.386560Z","shell.execute_reply.started":"2025-03-01T01:42:08.382685Z","shell.execute_reply":"2025-03-01T01:42:08.385815Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## Basic Functions","metadata":{}},{"cell_type":"code","source":"#Building blocks used in the CycleGAN generators and discriminators\n\n\"\"\"\n-------------------\nBlock of RNN\nRecieves x, type of activation function, kernel init, size, stride, uses padding same, gamma init an bias as false\n    \n    1. Convolution + normalization + activation funtion\n    2. Convolution + normalization\n    3. Residual or skip conection from initial x to final x\n\ndim = x.shape[-1]: Number of channels of RGB input - In a residual block, the goal is to learn a transformation that can be added back to the original input (the skip connection). For this addition to work, the input and the transformed output must have the same shape. By using x.shape[-1] (the number of channels in the input) as the number of filters for the convolutional layers, you ensure that the output of the block has the same number of channels as the input, making the element-wise addition possible. This design is a standard practice in architectures like ResNet and CycleGAN, where preserving the feature dimensions across a block helps in learning the residual mapping effectively.\n\n\"\"\"\n\ndef residual_block(\n    x,\n    activation,\n    kernel_initializer=kernel_init,\n    kernel_size=(3, 3),\n    strides=(1, 1),\n    padding=\"same\",  # Use 'same' padding instead of reflection padding\n    gamma_initializer=gamma_init,\n    use_bias=False,\n    ):\n    \n    dim = x.shape[-1] \n    input_tensor = x\n\n    # First convolutional layer with same padding\n    x = layers.Conv2D(\n        dim, # dim is the number of filters\n        kernel_size,\n        strides=strides,\n        kernel_initializer=kernel_initializer,\n        padding=padding,\n        use_bias=use_bias,\n    )(input_tensor)\n    x = keras.layers.GroupNormalization(groups=1, gamma_initializer=gamma_initializer)(x)\n    x = activation(x)\n\n    # Second convolutional layer with same padding\n    x = layers.Conv2D(\n        dim,\n        kernel_size,\n        strides=strides,\n        kernel_initializer=kernel_initializer,\n        padding=padding,\n        use_bias=use_bias,\n    )(x)\n    x = keras.layers.GroupNormalization(groups=1, gamma_initializer=gamma_initializer)(x)\n\n    # Add the input tensor (residual connection)\n    x = layers.add([input_tensor, x])\n    return x\n    \n\"\"\"\n-------------------\nDownsample function \nRecieves x, type of activation function, kernel init, size, stride, uses padding same, gamma init an bias as false\n    \n    1. Convolution + normalization (with a bigger stride to downsample)\n\"\"\"\n\ndef downsample(\n    x,\n    filters,\n    activation,\n    kernel_initializer=kernel_init,\n    kernel_size=(3, 3),\n    strides=(2, 2),\n    padding=\"same\",\n    gamma_initializer=gamma_init,\n    use_bias=False,\n):\n    x = layers.Conv2D(\n        filters,\n        kernel_size,\n        strides=strides,\n        kernel_initializer=kernel_initializer,\n        padding=padding,\n        use_bias=use_bias,\n    )(x)\n    x = keras.layers.GroupNormalization(groups=1, gamma_initializer=gamma_initializer)(\n        x\n    )\n    if activation:\n        x = activation(x)\n    return x\n    \n\"\"\"\n-------------------\nUpsample function \nRecieves x, type of activation function, kernel init, size, stride, uses padding same, gamma init an bias as false\n    \n    1. Inverse - Convolution + normalization (with a bigger stride to downsample)\n\"\"\"\n\ndef upsample(\n    x,\n    filters,\n    activation,\n    kernel_size=(3, 3),\n    strides=(2, 2),\n    padding=\"same\",\n    kernel_initializer=kernel_init,\n    gamma_initializer=gamma_init,\n    use_bias=False,\n):\n    x = layers.Conv2DTranspose(\n        filters,\n        kernel_size,\n        strides=strides,\n        padding=padding,\n        kernel_initializer=kernel_initializer,\n        use_bias=use_bias,\n    )(x)\n    x = keras.layers.GroupNormalization(groups=1, gamma_initializer=gamma_initializer)(\n        x\n    )\n    if activation:\n        x = activation(x)\n    return x","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-03-01T01:42:08.388808Z","iopub.execute_input":"2025-03-01T01:42:08.389004Z","iopub.status.idle":"2025-03-01T01:42:08.407198Z","shell.execute_reply.started":"2025-03-01T01:42:08.388988Z","shell.execute_reply":"2025-03-01T01:42:08.406386Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## RESNet Generator (Function)","metadata":{}},{"cell_type":"code","source":"\"\"\"\n--------------\n1. Convolution + Normalization + activation\n2. Downsampling - uses funtion defined previously\n3. Residual blocks - uses funtion defined previously\n3. Upsampling - uses funtion defined previously\n4. Final convolution and activtion\n\n\"\"\"\ndef get_resnet_generator(\n    filters=64,\n    num_downsampling_blocks=2,\n    num_residual_blocks=9,\n    num_upsample_blocks=2,\n    gamma_initializer=gamma_init,\n    name=None,\n):\n    img_input = layers.Input(shape=input_img_size, name=name + \"_img_input\")\n    x = img_input\n    x = layers.Conv2D(filters, (7, 7), padding=\"same\", kernel_initializer=kernel_init, use_bias=False)(x)\n    x = keras.layers.GroupNormalization(groups=1, gamma_initializer=gamma_initializer)(x)\n    x = layers.Activation(\"relu\")(x)\n\n    # Downsampling\n    for _ in range(num_downsampling_blocks):\n        filters *= 2\n        x = downsample(x, filters=filters, activation=layers.Activation(\"relu\"))\n\n    # Residual blocks\n    for _ in range(num_residual_blocks):\n        x = residual_block(x, activation=layers.Activation(\"relu\"))\n\n    # Upsampling\n    for _ in range(num_upsample_blocks):\n        filters //= 2\n        x = upsample(x, filters, activation=layers.Activation(\"relu\"))\n\n    # Final block\n    x = layers.Conv2D(3, (7, 7), padding=\"same\")(x)\n    x = layers.Activation(\"tanh\")(x)\n\n    model = keras.models.Model(img_input, x, name=name)\n    return model","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-03-01T01:42:08.408382Z","iopub.execute_input":"2025-03-01T01:42:08.408600Z","iopub.status.idle":"2025-03-01T01:42:08.425947Z","shell.execute_reply.started":"2025-03-01T01:42:08.408582Z","shell.execute_reply":"2025-03-01T01:42:08.425312Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## Discriminator (Function)","metadata":{}},{"cell_type":"code","source":"def get_discriminator(filters=64, kernel_initializer=kernel_init, num_downsampling=3, name=None):\n    img_input = layers.Input(shape=input_img_size, name=name + \"_img_input\")\n    x = layers.Conv2D(filters,(4, 4),strides=(2, 2), padding=\"same\", kernel_initializer=kernel_initializer,)(img_input)\n    x = layers.LeakyReLU(0.2)(x)\n\n    num_filters = filters\n    for num_downsample_block in range(3):\n        num_filters *= 2\n        if num_downsample_block < 2:\n            x = downsample(\n                x,\n                filters=num_filters,\n                activation=layers.LeakyReLU(0.2),\n                kernel_size=(4, 4),\n                strides=(2, 2),\n            )\n        else:\n            x = downsample(\n                x,\n                filters=num_filters,\n                activation=layers.LeakyReLU(0.2),\n                kernel_size=(4, 4),\n                strides=(1, 1),\n            )\n\n    x = layers.Conv2D(1, (4, 4), strides=(1, 1), padding=\"same\", kernel_initializer=kernel_initializer)(x)\n\n    model = keras.models.Model(inputs=img_input, outputs=x, name=name)\n    return model","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-03-01T01:42:08.426716Z","iopub.execute_input":"2025-03-01T01:42:08.426968Z","iopub.status.idle":"2025-03-01T01:42:08.445366Z","shell.execute_reply.started":"2025-03-01T01:42:08.426937Z","shell.execute_reply":"2025-03-01T01:42:08.444737Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## Creating Networks ","metadata":{}},{"cell_type":"code","source":"#\n#Get the generators\ngen_G = get_resnet_generator(name=\"generator_G\") # Translate features from monet to photos\ngen_F = get_resnet_generator(name=\"generator_F\") # reverse proces photos to monet\n\n# Get the discriminators\ndisc_X = get_discriminator(name=\"discriminator_X\") #Discrimination on monet real or fake\ndisc_Y = get_discriminator(name=\"discriminator_Y\") #Discriminator on photo real or fake","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-03-01T01:42:08.446102Z","iopub.execute_input":"2025-03-01T01:42:08.446373Z","iopub.status.idle":"2025-03-01T01:42:10.365937Z","shell.execute_reply.started":"2025-03-01T01:42:08.446354Z","shell.execute_reply":"2025-03-01T01:42:10.365003Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# Cycle GAN 3. Teaching to paint class CycleGan","metadata":{}},{"cell_type":"code","source":"class CycleGan(keras.Model):\n    def __init__(\n        self,\n        generator_G,\n        generator_F,\n        discriminator_X,\n        discriminator_Y,\n        lambda_cycle=10.0,\n        lambda_identity=0.5,\n    ):\n        super().__init__() # calls init from parent class (keras.Model)\n        self.gen_G = generator_G\n        self.gen_F = generator_F\n        self.disc_X = discriminator_X\n        self.disc_Y = discriminator_Y\n        self.lambda_cycle = lambda_cycle\n        self.lambda_identity = lambda_identity\n\n    def call(self, inputs):\n        return (\n            self.disc_X(inputs),\n            self.disc_Y(inputs),\n            self.gen_G(inputs),\n            self.gen_F(inputs),\n        )\n\n    def compile(\n        self,\n        gen_G_optimizer,\n        gen_F_optimizer,\n        disc_X_optimizer,\n        disc_Y_optimizer,\n        gen_loss_fn,\n        disc_loss_fn,\n    ):\n        super().compile()\n        self.gen_G_optimizer = gen_G_optimizer\n        self.gen_F_optimizer = gen_F_optimizer\n        self.disc_X_optimizer = disc_X_optimizer\n        self.disc_Y_optimizer = disc_Y_optimizer\n        self.generator_loss_fn = gen_loss_fn\n        self.discriminator_loss_fn = disc_loss_fn\n        self.cycle_loss_fn = keras.losses.MeanAbsoluteError()\n        self.identity_loss_fn = keras.losses.MeanAbsoluteError()\n\n    def train_step(self, batch_data):\n        # x is monet and y is photo\n        real_x, real_y = batch_data\n\n        # For CycleGAN, we need to calculate different\n        # kinds of losses for the generators and discriminators.\n        # We will perform the following steps here:\n        #\n        # 1. Pass real images through the generators and get the generated images\n        # 2. Pass the generated images back to the generators to check if we\n        #    can predict the original image from the generated image.\n        # 3. Do an identity mapping of the real images using the generators.\n        # 4. Pass the generated images in 1) to the corresponding discriminators.\n        # 5. Calculate the generators total loss (adversarial + cycle + identity)\n        # 6. Calculate the discriminators loss\n        # 7. Update the weights of the generators\n        # 8. Update the weights of the discriminators\n        # 9. Return the losses in a dictionary\n\n        with tf.GradientTape(persistent=True) as tape:\n            # monet to fake photo\n            fake_y = self.gen_G(real_x, training=True)\n            # photo to fake monet -> y2x\n            fake_x = self.gen_F(real_y, training=True)\n\n            # Cycle (monet to fake photo to fake monet): x -> y -> x\n            cycled_x = self.gen_F(fake_y, training=True)\n            # Cycle (photo to fake moent to fake photo) y -> x -> y\n            cycled_y = self.gen_G(fake_x, training=True)\n\n            # Identity mapping\n            same_x = self.gen_F(real_x, training=True)\n            same_y = self.gen_G(real_y, training=True)\n\n            # Discriminator output\n            disc_real_x = self.disc_X(real_x, training=True)\n            disc_fake_x = self.disc_X(fake_x, training=True)\n\n            disc_real_y = self.disc_Y(real_y, training=True)\n            disc_fake_y = self.disc_Y(fake_y, training=True)\n\n            # Generator adversarial loss\n            gen_G_loss = self.generator_loss_fn(disc_fake_y)\n            gen_F_loss = self.generator_loss_fn(disc_fake_x)\n\n            # Generator cycle loss\n            cycle_loss_G = self.cycle_loss_fn(real_y, cycled_y) * self.lambda_cycle\n            cycle_loss_F = self.cycle_loss_fn(real_x, cycled_x) * self.lambda_cycle\n\n            # Generator identity loss\n            id_loss_G = (\n                self.identity_loss_fn(real_y, same_y)\n                * self.lambda_cycle\n                * self.lambda_identity\n            )\n            id_loss_F = (\n                self.identity_loss_fn(real_x, same_x)\n                * self.lambda_cycle\n                * self.lambda_identity\n            )\n\n            # Total generator loss\n            total_loss_G = gen_G_loss + cycle_loss_G + id_loss_G\n            total_loss_F = gen_F_loss + cycle_loss_F + id_loss_F\n\n            # Discriminator loss\n            disc_X_loss = self.discriminator_loss_fn(disc_real_x, disc_fake_x)\n            disc_Y_loss = self.discriminator_loss_fn(disc_real_y, disc_fake_y)\n\n        # Get the gradients for the generators\n        grads_G = tape.gradient(total_loss_G, self.gen_G.trainable_variables)\n        grads_F = tape.gradient(total_loss_F, self.gen_F.trainable_variables)\n\n        # Get the gradients for the discriminators\n        disc_X_grads = tape.gradient(disc_X_loss, self.disc_X.trainable_variables)\n        disc_Y_grads = tape.gradient(disc_Y_loss, self.disc_Y.trainable_variables)\n\n        # Update the weights of the generators\n        self.gen_G_optimizer.apply_gradients(\n            zip(grads_G, self.gen_G.trainable_variables)\n        )\n        self.gen_F_optimizer.apply_gradients(\n            zip(grads_F, self.gen_F.trainable_variables)\n        )\n\n        # Update the weights of the discriminators\n        self.disc_X_optimizer.apply_gradients(\n            zip(disc_X_grads, self.disc_X.trainable_variables)\n        )\n        self.disc_Y_optimizer.apply_gradients(\n            zip(disc_Y_grads, self.disc_Y.trainable_variables)\n        )\n\n        return {\n            \"G_loss\": total_loss_G,\n            \"F_loss\": total_loss_F,\n            \"D_X_loss\": disc_X_loss,\n            \"D_Y_loss\": disc_Y_loss,\n        }\n        ","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-03-01T01:42:10.366982Z","iopub.execute_input":"2025-03-01T01:42:10.367288Z","iopub.status.idle":"2025-03-01T01:42:10.378363Z","shell.execute_reply.started":"2025-03-01T01:42:10.367260Z","shell.execute_reply":"2025-03-01T01:42:10.377591Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## Loss Functions","metadata":{}},{"cell_type":"code","source":"# Loss function for evaluating adversarial loss\nadv_loss_fn = keras.losses.MeanSquaredError()\n\n# Define the loss function for the generators\ndef generator_loss_fn(fake):\n    fake_loss = adv_loss_fn(ops.ones_like(fake), fake)\n    return fake_loss\n\n\n# Define the loss function for the discriminators\ndef discriminator_loss_fn(real, fake):\n    real_loss = adv_loss_fn(ops.ones_like(real), real)\n    fake_loss = adv_loss_fn(ops.zeros_like(fake), fake)\n    return (real_loss + fake_loss) * 0.5","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-03-01T01:42:10.379085Z","iopub.execute_input":"2025-03-01T01:42:10.379266Z","iopub.status.idle":"2025-03-01T01:42:10.397285Z","shell.execute_reply.started":"2025-03-01T01:42:10.379249Z","shell.execute_reply":"2025-03-01T01:42:10.396537Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## Compile and load weights (previously trained)","metadata":{}},{"cell_type":"code","source":"# Create cycle gan model\n\"\"\"\n---------------\nModel\n---------------\n\"\"\"\ncycle_gan_model = CycleGan(\n    generator_G=gen_G, generator_F=gen_F, discriminator_X=disc_X, discriminator_Y=disc_Y\n)\n\n# Compile (final configuration) of the model\n\ncycle_gan_model.compile(\n    gen_G_optimizer=keras.optimizers.Adam(learning_rate=2e-4, beta_1=0.5),\n    gen_F_optimizer=keras.optimizers.Adam(learning_rate=2e-4, beta_1=0.5),\n    disc_X_optimizer=keras.optimizers.Adam(learning_rate=2e-4, beta_1=0.5),\n    disc_Y_optimizer=keras.optimizers.Adam(learning_rate=2e-4, beta_1=0.5),\n    gen_loss_fn=generator_loss_fn,\n    disc_loss_fn=discriminator_loss_fn,\n)\n\n\"\"\"\n----------------\nModel from checkpoint \n---------------\n\"\"\"\ncycle_gan_model.load_weights(\"/kaggle/input/weights/cyclegan71_checkpoint.weights.h5\")\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-03-01T01:42:10.398145Z","iopub.execute_input":"2025-03-01T01:42:10.398407Z","iopub.status.idle":"2025-03-01T01:42:11.929661Z","shell.execute_reply.started":"2025-03-01T01:42:10.398388Z","shell.execute_reply":"2025-03-01T01:42:11.928802Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# Results - Submission","metadata":{}},{"cell_type":"code","source":"# Show painted the landscapes\n_, ax = plt.subplots(4, 2, figsize=(10, 15))\nfor i, img in enumerate(train_photos.take(4)):\n    prediction = cycle_gan_model.gen_F(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 image\")\n    ax[i, 1].set_title(\"Translated image\")\n    ax[i, 0].axis(\"off\")\n    ax[i, 1].axis(\"off\")\n\nplt.tight_layout()\nplt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-03-01T01:42:11.930914Z","iopub.execute_input":"2025-03-01T01:42:11.931235Z","iopub.status.idle":"2025-03-01T01:42:18.809760Z","shell.execute_reply.started":"2025-03-01T01:42:11.931205Z","shell.execute_reply":"2025-03-01T01:42:18.808589Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import os\nimport numpy as np\nimport PIL\nimport shutil\n\n# Create the directory if it doesn't exist\noutput_dir = \"../images\"\nos.makedirs(output_dir, exist_ok=True)\n\ni = 1\nfor img in train_photos:\n    prediction = cycle_gan_model.gen_F(img, training=False)[0].numpy()\n    prediction = (prediction * 127.5 + 127.5).astype(np.uint8)\n    im = PIL.Image.fromarray(prediction)\n    \n    save_path = os.path.join(output_dir, f\"{i}.jpg\")\n    im.save(save_path)\n\n    if i % 200 == 0:\n        print(f\"{i}/7038\")\n    \n    i += 1\n\n# Create a ZIP archive of the images directory\nshutil.make_archive(\"/kaggle/working/images\", 'zip', output_dir)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-03-01T01:42:18.811353Z","iopub.execute_input":"2025-03-01T01:42:18.811705Z","iopub.status.idle":"2025-03-01T01:52:49.544288Z","shell.execute_reply.started":"2025-03-01T01:42:18.811673Z","shell.execute_reply":"2025-03-01T01:52:49.543449Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":" # rm -rf /kaggle/working/","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-03-01T01:52:49.545087Z","iopub.execute_input":"2025-03-01T01:52:49.545317Z","iopub.status.idle":"2025-03-01T01:52:49.548705Z","shell.execute_reply.started":"2025-03-01T01:52:49.545289Z","shell.execute_reply":"2025-03-01T01:52:49.547975Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null}]}