{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"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"},"kaggle":{"accelerator":"nvidiaTeslaT4","dataSources":[{"sourceId":21755,"databundleVersionId":1475600,"sourceType":"competition"},{"sourceId":1003830,"sourceType":"datasetVersion","datasetId":550917}],"dockerImageVersionId":30698,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"# 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)\nimport tensorflow as tf\nfrom tensorflow.io.gfile import glob\nimport os\nimport matplotlib.pyplot as plt\nimport tensorflow.keras as keras\nimport tensorflow.keras.layers as layers\nfrom sklearn.decomposition import PCA\nfrom tensorflow.keras.preprocessing.image import load_img\nfrom tensorflow.keras.preprocessing.image import ImageDataGenerator\nimport shutil\nimport PIL\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\nimport os\n### Setting my path to the input file\n#os.chdir(\"/kaggle/input/gan-getting-started\")\nfor dirname, _, filenames in os.walk('/kaggle/input'):\n    print(dirname, len(os.listdir(dirname)))\nAUTOTUNE = tf.data.experimental.AUTOTUNE\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","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","execution":{"iopub.status.busy":"2024-06-13T23:47:15.395384Z","iopub.execute_input":"2024-06-13T23:47:15.396084Z","iopub.status.idle":"2024-06-13T23:48:09.740348Z","shell.execute_reply.started":"2024-06-13T23:47:15.396051Z","shell.execute_reply":"2024-06-13T23:48:09.739365Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Training strategy (TPU or GPU)\n\nLater I create the one for TPUs","metadata":{}},{"cell_type":"code","source":"if len(tf.config.list_physical_devices()) >= 3:\n    strategy = tf.distribute.MirroredStrategy()\n    print(\"Number of devices\", strategy.num_replicas_in_sync)    \nelse: \n    strategy = tf.distribute.get_strategy()\nstrategy","metadata":{"execution":{"iopub.status.busy":"2024-06-13T23:48:09.742130Z","iopub.execute_input":"2024-06-13T23:48:09.742719Z","iopub.status.idle":"2024-06-13T23:48:09.754418Z","shell.execute_reply.started":"2024-06-13T23:48:09.742689Z","shell.execute_reply":"2024-06-13T23:48:09.753388Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Loading data\nUsing the TFRecord files\n\n### ","metadata":{}},{"cell_type":"code","source":"Monet_files = glob(str('/kaggle/input/gan-getting-started/monet_tfrec/*.tfrec'))\nprint('Monet TFRecord Files:', len(Monet_files))\nPhoto_files = glob(str('/kaggle/input/gan-getting-started/photo_tfrec/*.tfrec'))\nprint('Photo TFRecord Files:', len(Photo_files))","metadata":{"execution":{"iopub.status.busy":"2024-06-13T23:48:09.756341Z","iopub.execute_input":"2024-06-13T23:48:09.756924Z","iopub.status.idle":"2024-06-13T23:48:09.774342Z","shell.execute_reply.started":"2024-06-13T23:48:09.756897Z","shell.execute_reply":"2024-06-13T23:48:09.773394Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### TFRecord reading to get feature names\nTo decode the TFRecords you need to specify the feature name and type in form of a dictionary","metadata":{}},{"cell_type":"code","source":"raw_dataset = tf.data.TFRecordDataset(Monet_files[0])\nfor raw_record in raw_dataset.take(1):\n    example = tf.train.Example()\n    example.ParseFromString(raw_record.numpy())\n    Monet_features = [i for i in example.features.feature]\n\nraw_dataset = tf.data.TFRecordDataset(Photo_files[0])\nfor raw_record in raw_dataset.take(1):\n    example = tf.train.Example()\n    example.ParseFromString(raw_record.numpy())\n    Photo_features = [i for i in example.features.feature]\n\nprint('Monet tfrecord Features:', Monet_features)\nprint('Photo tfrecord Features:', Photo_features)","metadata":{"execution":{"iopub.status.busy":"2024-06-13T23:48:09.776337Z","iopub.execute_input":"2024-06-13T23:48:09.776728Z","iopub.status.idle":"2024-06-13T23:48:09.919425Z","shell.execute_reply.started":"2024-06-13T23:48:09.776701Z","shell.execute_reply":"2024-06-13T23:48:09.918478Z"},"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.image.convert_image_dtype(image, tf.float32)\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\n\ndef load_dataset(filenames, labeled=True, ordered=False, repeat = False):\n    dataset = tf.data.TFRecordDataset(filenames)\n    dataset = dataset.map(read_tfrecord, num_parallel_calls=AUTOTUNE)\n    if repeat:\n        dataset = dataset.repeat(count = 20)\n    dataset = dataset.shuffle(1000)\n    dataset = dataset.prefetch(buffer_size=tf.data.experimental.AUTOTUNE)\n    return dataset","metadata":{"execution":{"iopub.status.busy":"2024-06-13T23:48:09.920557Z","iopub.execute_input":"2024-06-13T23:48:09.920886Z","iopub.status.idle":"2024-06-13T23:48:09.929240Z","shell.execute_reply.started":"2024-06-13T23:48:09.920854Z","shell.execute_reply":"2024-06-13T23:48:09.928293Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Image generators","metadata":{}},{"cell_type":"code","source":"batch_size = 15\nphoto_ds = load_dataset(Photo_files, labeled = True).batch(15)\nmonet_ds = load_dataset(Monet_files, labeled = True, repeat = True).batch(15)\nexample_monet = next(iter(monet_ds))\nexample_photo = next(iter(photo_ds))","metadata":{"execution":{"iopub.status.busy":"2024-06-13T23:48:09.930548Z","iopub.execute_input":"2024-06-13T23:48:09.930915Z","iopub.status.idle":"2024-06-13T23:48:11.919964Z","shell.execute_reply.started":"2024-06-13T23:48:09.930882Z","shell.execute_reply":"2024-06-13T23:48:11.919113Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Visualize categories","metadata":{}},{"cell_type":"code","source":"fig, axes = plt.subplots(nrows=2, ncols=5, figsize=(15, 6))\nfig.suptitle('Image Categories', fontsize=16)\n\nfor i in range(0,5):\n    ax = axes[0, i]\n    ax.imshow(example_monet[i])\n    ax.axis('off')\n\nfor i in range(0,5):\n    ax = axes[1, i]\n    ax.imshow(example_photo[i])\n    ax.axis('off')\n\naxes[0, 2].set_title('Monet', size='large', loc='center')\naxes[1, 2].set_title('Photo', size='large', loc='center')\nplt.tight_layout()  # Adjust layout to make room for the main title\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2024-06-13T23:48:11.921162Z","iopub.execute_input":"2024-06-13T23:48:11.921452Z","iopub.status.idle":"2024-06-13T23:48:12.951396Z","shell.execute_reply.started":"2024-06-13T23:48:11.921427Z","shell.execute_reply":"2024-06-13T23:48:12.950292Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Basic blocks\n\n## Downsample block","metadata":{}},{"cell_type":"code","source":"class Downsample(keras.layers.Layer):\n    def __init__(self,filters, kernel_size = (2,2), strides=(2, 2), padding='same', activation = 'leaky_relu', **kwargs):\n        \n        super(Downsample, self).__init__(**kwargs)\n        self.initializer = tf.random_normal_initializer(0., 0.02)\n        self.gamma_init = keras.initializers.RandomNormal(mean=0.0, stddev=0.02)\n        self.conv = layers.Conv2D(filters, kernel_size = kernel_size, \n                                  strides = strides, padding = padding, kernel_initializer = self.initializer)\n        self.bn = layers.BatchNormalization()\n        self.activation = layers.Activation(activation = activation)\n        \n    def call(self, inputs,training = False):\n        x = self.conv(inputs)\n        x = self.bn(x, training = training)\n        x = self.activation(x)\n        \n        return x\n    \n    def get_config(self):\n        config = super(Downsample, self).get_config()\n        config.update({\n            'filters': self.conv.filters,\n            'kernel_size': self.conv.kernel_size,\n            'strides': self.conv.strides,\n            'padding': self.conv.padding,\n            'activation': self.activation.activation,\n        })\n        return config","metadata":{"execution":{"iopub.status.busy":"2024-06-13T23:48:12.952707Z","iopub.execute_input":"2024-06-13T23:48:12.953014Z","iopub.status.idle":"2024-06-13T23:48:12.963198Z","shell.execute_reply.started":"2024-06-13T23:48:12.952988Z","shell.execute_reply":"2024-06-13T23:48:12.962231Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def apply_pca_and_visualize(convolved_images):\n    # Flatten the convolved images\n    shape = convolved_images.shape\n    normalized_image = convolved_images / 255.0\n    reshaped_image = tf.reshape(normalized_image, (-1, shape[-1]))\n    reshaped_array = reshaped_image.numpy()\n    # Apply PCA\n    pca = PCA(n_components=1)\n    pca_result = pca.fit_transform(reshaped_array)\n    # Reshape back\n    pca_image_reshaped = pca_result.reshape(shape[0], shape[1], 1)\n    return pca_image_reshaped","metadata":{"execution":{"iopub.status.busy":"2024-06-13T23:48:12.964432Z","iopub.execute_input":"2024-06-13T23:48:12.965073Z","iopub.status.idle":"2024-06-13T23:48:12.973681Z","shell.execute_reply.started":"2024-06-13T23:48:12.965036Z","shell.execute_reply":"2024-06-13T23:48:12.972826Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"filters = [32,64,128,256]\nconvolutions = []\nconvolutions.append(example_monet)\nfor count,element in enumerate(filters):\n    Block = Downsample(element)\n    convolutions.append(Block(convolutions[count]))\n\nfig, axes = plt.subplots(nrows=1, ncols=6, figsize=(15, 3))\nfig.suptitle('Downsampling', fontsize=16)\n\nbatch_number = 3\n## Original visualization\nax = axes[0]\nax.imshow(convolutions[0][batch_number])\naxes[0].set_title('Original Monet', size='large', loc='center')\n\n# PCA of original\nax = axes[1]\nax.imshow(apply_pca_and_visualize(convolutions[0][batch_number])*255.0, cmap = 'winter')\naxes[1].set_title('PCA', size='large', loc='center')\n\n# \nfor i in range(1, len(convolutions)):\n    ax = axes[i+1]\n    ax.imshow(apply_pca_and_visualize(convolutions[i][batch_number])*255.0, cmap = 'winter')\n    axes[i+1].set_title(f'Downsample {convolutions[i].shape[-1]} filters', size='medium', loc='center')\n    \nplt.show()","metadata":{"execution":{"iopub.status.busy":"2024-06-13T23:48:12.977036Z","iopub.execute_input":"2024-06-13T23:48:12.977373Z","iopub.status.idle":"2024-06-13T23:48:14.449851Z","shell.execute_reply.started":"2024-06-13T23:48:12.977343Z","shell.execute_reply":"2024-06-13T23:48:14.448806Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Residual Block","metadata":{}},{"cell_type":"code","source":"class ResidualBlock(keras.layers.Layer):\n    def __init__(self, filters = 512, kernel_size=(3, 3), strides=(1, 1), padding='same', activation = 'leaky_relu', **kwargs):\n        super(ResidualBlock, self).__init__(**kwargs)\n        self.conv1 = layers.Conv2D(filters, kernel_size, strides, padding)\n        self.bn1 = layers.BatchNormalization()\n        self.activation = layers.ReLU()\n        self.conv2 = layers.Conv2D(filters, kernel_size, strides, padding)\n        self.bn2 = layers.BatchNormalization()\n\n    def call(self, inputs, training=False):\n        x = self.conv1(inputs)\n        x = self.bn1(x, training=training)\n        x = self.activation(x)\n        x = self.conv2(x)\n        x = self.bn2(x)\n        return layers.Add()([inputs, x])","metadata":{"execution":{"iopub.status.busy":"2024-06-13T23:48:14.451189Z","iopub.execute_input":"2024-06-13T23:48:14.451584Z","iopub.status.idle":"2024-06-13T23:48:14.461238Z","shell.execute_reply.started":"2024-06-13T23:48:14.451547Z","shell.execute_reply":"2024-06-13T23:48:14.460153Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Upsample block","metadata":{}},{"cell_type":"code","source":"class Upsample(keras.layers.Layer):\n    def __init__(self,filters, kernel_size = (2,2), strides=(2, 2), padding='same', activation = 'leaky_relu', dropout = 0.2,**kwargs):\n        \n        super(Upsample, self).__init__(**kwargs)\n        self.initializer = tf.random_normal_initializer(0., 0.02)\n        self.conv = layers.Conv2DTranspose(filters, kernel_size = kernel_size, \n                                           strides = strides, padding = padding, kernel_initializer = self.initializer)\n        self.bn = layers.BatchNormalization()\n        self.dropout = layers.Dropout(dropout)\n        self.activation = layers.Activation(activation = activation)\n    \n    def call(self, inputs,training = False, dropout = False):\n        x = self.conv(inputs)\n        x = self.bn(x, training = training)\n        if dropout:\n            x = self.dropout(x)\n        x = self.activation(x)\n        \n        return x\n    \n    def get_config(self):\n        config = super(Upsample, self).get_config()\n        config.update({\n            'filters': self.conv.filters,\n            'kernel_size': self.conv.kernel_size,\n            'strides': self.conv.strides,\n            'padding': self.conv.padding,\n            'activation': self.activation.activation,\n        })\n        return config","metadata":{"execution":{"iopub.status.busy":"2024-06-13T23:48:14.462441Z","iopub.execute_input":"2024-06-13T23:48:14.462778Z","iopub.status.idle":"2024-06-13T23:48:14.474692Z","shell.execute_reply.started":"2024-06-13T23:48:14.462752Z","shell.execute_reply":"2024-06-13T23:48:14.473767Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"upsample_filters = [512,256,128,3]\nupsample_test = []\nupsample_test.append(convolutions[-1])\nfor count,element in enumerate(upsample_filters):\n    upsample_block = Upsample(element)\n    upsample_test.append(upsample_block(upsample_test[count], dropout = True, training = False))\n    \nfig, axes = plt.subplots(nrows=1, ncols=6, figsize=(15, 3))\nfig.suptitle('Upsampling', fontsize=16)\n\nbatch_number = 3\n \nfor i in range(0, len(upsample_test)-1):\n    ax = axes[i]\n    ax.imshow(apply_pca_and_visualize(upsample_test[i][batch_number])*255.0, cmap = 'winter')\n    axes[i].set_title(f'Upsample {upsample_test[i].shape[-1]} filters', size='medium', loc='center')\n\n# PCA of the predicted original\nax = axes[4]\nax.imshow(apply_pca_and_visualize(upsample_test[-1][batch_number])*255.0, cmap = 'winter')\naxes[4].set_title('PCA', size='large', loc='center')\n\n# PCA of the predicted original\nax = axes[5]\nax.imshow(upsample_test[-1][batch_number]*255.0)\naxes[5].set_title('Original', size='large', loc='center')\n\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2024-06-13T23:48:14.476054Z","iopub.execute_input":"2024-06-13T23:48:14.476336Z","iopub.status.idle":"2024-06-13T23:48:16.388559Z","shell.execute_reply.started":"2024-06-13T23:48:14.476311Z","shell.execute_reply":"2024-06-13T23:48:16.387597Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Defining generator","metadata":{}},{"cell_type":"code","source":"class Generator(keras.Model):\n    def __init__(self, name = 'Generator',**kwargs):\n        super(Generator, self).__init__(name = name, **kwargs)\n        \n        ### Downsampling layers\n        self.downsample1 = Downsample(64, name = 'Donwsample_same', strides = (1,1), kernel_size = (5,5))   ## (bs,256,256,64)\n        self.downsample2 = Downsample(128, name = 'Donwsample_128')   ## (bs,128,128,128)\n        self.downsample3 = Downsample(128, name = 'Donwsample_64')  ## (bs,64,64,128)\n        self.downsample4 = Downsample(256, name = 'Donwsample_32')  ## (bs,32,32,256)\n        self.downsample5 = Downsample(512, name = 'Donwsample_16')  ## (bs,16,16,512)\n        self.downsample6 = Downsample(512, name = 'Donwsample_8')  ## (bs,8,8,512)\n        self.downsample7 = Downsample(512, name = 'Donwsample_4')  ## (bs,4,4,512)\n        \n        self.residual1 = ResidualBlock()\n        self.residual2 = ResidualBlock()\n        self.residual3 = ResidualBlock()\n        \n        ## Upsampling layers\n        self.upsample1 = Upsample(512, name = 'Upsample_8') ## (bs,8,8,512)\n        self.upsample2 = Upsample(512, name = 'Upsample_16') ## (bs,16,16,512)\n        self.upsample3 = Upsample(256,name = 'Upsample_32' ) ## (bs,32,32,512)\n        self.upsample4 = Upsample(128, name = 'Upsample_64') ## (bs,64,64,256)\n        self.upsample5 = Upsample(128, name = 'Upsample_128') ## (bs,128,128,128)\n        self.upsample6 = Upsample(64, name = 'Upsample_256') ## (bs,256,256,64)\n        self.final_upsample = Upsample(3, activation = 'tanh', name = 'Output_layer', strides = (1,1)) # (bs,256,256,3)\n        \n        \n    def call(self, inputs, training = False):\n        ### Downsampling\n        d1 = self.downsample1(inputs, training = training)\n        d2 = self.downsample2(d1, training = training)\n        d3 = self.downsample3(d2, training = training)\n        d4 = self.downsample4(d3, training = training)\n        d5 = self.downsample5(d4, training = training)\n        d6 = self.downsample6(d5, training = training)\n        d7 = self.downsample7(d6, training = training)\n        \n        r1 = self.residual1(d7, training = training)\n        r2 = self.residual2(r1, training = training)\n        r3 = self.residual3(r2, training = training)\n\n        ## Upsampling\n        u1 = self.upsample1(r3, training = training)\n        u1_concat = tf.concat([u1, d6], axis=-1)\n        u2 = self.upsample2(u1_concat, training = training)\n        u2_concat = tf.concat([u2, d5], axis=-1)\n        u3 = self.upsample3(u2_concat, training = training)\n        u3_concat = tf.concat([u3, d4], axis=-1)\n        u4 = self.upsample4(u3_concat, training = training)\n        u4_concat = tf.concat([u4, d3], axis=-1)\n        u5 = self.upsample5(u4_concat, training = training)\n        u5_concat = tf.concat([u5, d2], axis=-1)\n        u6 = self.upsample6(u5_concat, training = training)\n        u6_concat = tf.concat([u6, d1], axis=-1)\n        x = self.final_upsample(u6_concat, training = training)\n        return x","metadata":{"execution":{"iopub.status.busy":"2024-06-13T23:57:16.655487Z","iopub.execute_input":"2024-06-13T23:57:16.656135Z","iopub.status.idle":"2024-06-13T23:57:16.671415Z","shell.execute_reply.started":"2024-06-13T23:57:16.656101Z","shell.execute_reply":"2024-06-13T23:57:16.670040Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Compiling the Generator\nJust to make sure everything is working properly","metadata":{}},{"cell_type":"code","source":"g = Generator()\ng.compile(optimizer = 'adam', loss = 'mse')\nx = g(example_photo, training = True)  ## to build the generator you need to pass an input trough the network\ng.summary()","metadata":{"execution":{"iopub.status.busy":"2024-06-13T23:57:47.563303Z","iopub.execute_input":"2024-06-13T23:57:47.564011Z","iopub.status.idle":"2024-06-13T23:57:52.335868Z","shell.execute_reply.started":"2024-06-13T23:57:47.563972Z","shell.execute_reply":"2024-06-13T23:57:52.334911Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Visualize the generator\nSince its not trained it will only show blank images. Just to make sure the shape of the generated images are correct","metadata":{}},{"cell_type":"code","source":"fig, axes = plt.subplots(nrows=1, ncols=2, figsize=(15, 6))\nfig.suptitle('Monet Generator', fontsize=16)\nax = axes[0]\nax.imshow(example_photo[2])\naxes[0].set_title('Photo', size='large', loc='center')\nax = axes[1]\nax.imshow(x[2])\naxes[1].set_title('Photo as a Monet', size='large', loc='center')\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2024-06-14T00:00:15.119401Z","iopub.execute_input":"2024-06-14T00:00:15.120366Z","iopub.status.idle":"2024-06-14T00:00:15.846329Z","shell.execute_reply.started":"2024-06-14T00:00:15.120330Z","shell.execute_reply":"2024-06-14T00:00:15.844095Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Defining the discriminator","metadata":{}},{"cell_type":"code","source":"class Discriminator(keras.Model):\n    def __init__(self, name = 'Discriminator', dense = 64, activation = 'leaky_relu', **kwargs):\n        super(Discriminator, self).__init__(name = name, **kwargs)\n        self.initializer = tf.random_normal_initializer(0., 0.02)\n        self.downsample1 = Downsample(64, name = 'Downsample_128')   ## (bs,128,128,64)\n        self.downsample2 = Downsample(128, name = 'Downsample_64')  ## (bs, 64,64,128)\n        self.downsample3 = Downsample(256, name = 'Downsample_32')  ## (bs, 32,32,256)\n        self.downsample4 = Downsample(256, name = 'Downsample_16')  ## (bs, 32,32,256)\n        self.zeropad = layers.ZeroPadding2D(name = 'Zero_Padding')\n        self.downsample5 = Downsample(512, strides = (1,1), kernel_size = (2,2), name = 'Downsample_stride_1')  ## (bs,32,32,512)\n        self.flatten = layers.Flatten(name = 'Flatten_layer')\n        self.dense = layers.Dense(dense, name = f'Hiden_layer_{dense}')\n        self.dropout = layers.Dropout(0.2, name = 'Dropout')\n        self.activation = layers.Activation(activation,name =  f'{activation}')\n        self.last = layers.Dense(1, activation = 'sigmoid')\n        \n    def call(self,inputs, training = False):\n        x = self.downsample1(inputs, training = training)\n        x = self.downsample2(x, training = training)\n        x = self.downsample3(x, training = training)\n        x = self.downsample4(x, training = training)\n        x = self.zeropad(x)\n        x = self.downsample5(x, training =training)\n        x = self.flatten(x)\n        x = self.dense(x)\n        x = self.dropout(x)\n        x = self.activation(x)\n        x = self.last(x)\n        return x","metadata":{"execution":{"iopub.status.busy":"2024-06-13T23:58:07.454327Z","iopub.execute_input":"2024-06-13T23:58:07.454715Z","iopub.status.idle":"2024-06-13T23:58:07.465920Z","shell.execute_reply.started":"2024-06-13T23:58:07.454687Z","shell.execute_reply":"2024-06-13T23:58:07.464762Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Compiling the discriminator","metadata":{}},{"cell_type":"code","source":"d = Discriminator()\nd.compile(optimizer = 'adam', loss = 'mse')\ny = d(example_monet, training = False)\nd.summary()","metadata":{"jupyter":{"source_hidden":true},"execution":{"iopub.status.busy":"2024-06-13T23:58:09.366201Z","iopub.execute_input":"2024-06-13T23:58:09.366587Z","iopub.status.idle":"2024-06-13T23:58:10.018749Z","shell.execute_reply.started":"2024-06-13T23:58:09.366557Z","shell.execute_reply":"2024-06-13T23:58:10.017799Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Cycle-Consistent Adversarial Networks\n### Documentation https://arxiv.org/pdf/1703.10593\nThis specific architecture was designed for learning to translate an image from a source domain $X$ to a target domain $Y$ in the absence of paired examples.  \n\"What if Monet had happened upon the little harbor in\nCassis on a cool summer evening. A brief stroll through a gallery of Monet paintings makes it\npossible to imagine how he would have rendered the scene:\nperhaps in pastel shades, with abrupt dabs of paint, and a\nsomewhat flattened dynamic range.\"\n\n## Why we need two generators and two discriminators?\nTranslation should be “cycle consistent”, in the sense that if we translate, e.g., a sentence from English to French, and then translate it back from French to English, we should arrive back\nat the original sentence. Mathematically, if we have a\ntranslator $G : X \\rightarrow Y$ and another translator $F : Y \\rightarrow X$,\nthen $G$ and $F$ should be inverses of each other, and both\nmappings should be bijections. We apply this structural assumption by training both the mapping $G$ and $F$ simultaneously, and adding a cycle consistency loss that encourages $F(G(x)) ≈ x$ and $G(F(y)) ≈ y$\n\nOur model contains two mapping functions $G : X \\rightarrow Y$ and $F : Y \\rightarrow X$, and associated adversarial\ndiscriminators $D_Y$ and $D_x$. $D_y$ encourages $G$ to translate $X$ into outputs indistinguishable from domain $Y$ , and vice versa\nfor $D_x$ and $F$. To further regularize the mappings, we introduce two cycle consistency losses that capture the intuition that if\nwe translate from one domain to the other and back again we should arrive at where we started\n\nIn simpler words:  \nWe have two generators  $F:  \\text{Monet} \\rightarrow \\text{Photo}$, $G:  \\text{Photo} \\rightarrow \\text{Monet}$; and two discriminators $D_x: \\text{ Is a real Monet?}$, $D_y: \\text{ Is a real Photo?}$  \nIf we input the result of a generator in the other one, the 2nd should output similar results to the original","metadata":{}},{"cell_type":"markdown","source":"## Explaining each loss function\nWell go explaining each function and testing it to give an example of how they work. To better understand them. There's $x$ and $y$; the output of and untrained generator and discriminator respectivelly\n### Generator Loss\nHow good the Generator is able to fool the discriminator  \nMathematically : $L_G = -log(D(G((z))$ where $G(z)$ is the generated image and \n$(D(G(z))$ is the probability that the generated image is real  \nIn the generator loss, we'll compare the output of the discriminator $D(G(z))$ with a tensor with equal shape filled with ones. This tensor represents the goal of the Generator, create 'real' examples that in our case are labeled with 1","metadata":{}},{"cell_type":"code","source":"def generator_loss(disc_output):\n    ### BinaryCrossentropy cause were using only two categories (real or fake)\n    ### from_logits to avoid passing the discriminator output trough a sigmoid activation\n    return keras.losses.BinaryCrossentropy(from_logits=False)(tf.ones_like(disc_output), disc_output)\n\nprint('Generator loss: ', generator_loss(y))","metadata":{"execution":{"iopub.status.busy":"2024-06-13T23:58:15.327911Z","iopub.execute_input":"2024-06-13T23:58:15.328638Z","iopub.status.idle":"2024-06-13T23:58:15.356512Z","shell.execute_reply.started":"2024-06-13T23:58:15.328590Z","shell.execute_reply":"2024-06-13T23:58:15.355487Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Discriminator Loss\nHow well the discriminator is able to distinguish between real and fake images.  \nMathematically $L_D = -log(D(x)) + -log((D(G(z))$ where we're going to compare the discriminator output when trying to classify real images with a tensor filled with ones, and the oposite, compare the discriminator output when classifying generated images with a tensor filled with zeros.","metadata":{}},{"cell_type":"code","source":"def discriminator_loss(real_output, fake_output):\n    ### D(x) when classifying real examples\n    real_loss = tf.keras.losses.BinaryCrossentropy(from_logits=False)(tf.ones_like(real_output), real_output)\n    ### D(y) when classiying fake examples\n    fake_loss = tf.keras.losses.BinaryCrossentropy(from_logits=False)(tf.zeros_like(fake_output), fake_output)\n    return real_loss + fake_loss\n\nprint('Discriminator loss: ', discriminator_loss(y,y))","metadata":{"execution":{"iopub.status.busy":"2024-06-13T23:58:16.976088Z","iopub.execute_input":"2024-06-13T23:58:16.976453Z","iopub.status.idle":"2024-06-13T23:58:16.988179Z","shell.execute_reply.started":"2024-06-13T23:58:16.976424Z","shell.execute_reply":"2024-06-13T23:58:16.987023Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Cycle Consistency Loss\nEnsures that the process of translating and image from one domain and back, should result in the original image. $F(G(x)) ≈ x$ and $G(F(y)) ≈ y$  \nMathematically: $L_{cycle} = ||F(G(x)) - x||_1 + ||G(F(y)) - y||_1$\nIn simpler words, this compares original image against the full cycled image and computes the average absolute difference between them, this for both categories.  \nIn the paper they add $\\lambda$, this is a wight factor that controls the importance of the objective. In this case ${\\lambda}_{cycle}$ multiplies $L_{cycle}$ to denote how important for our purpose is the cycle consistency","metadata":{}},{"cell_type":"code","source":"### Compares the original image against the cycled one\ndef cycle_loss(real_image, cycled_image, lambda_cycle=10):\n    return lambda_cycle * tf.reduce_mean(tf.abs(real_image - cycled_image))\n### When comparing the same images, the cycle loss should be 0\nprint('Cycle loss: ', cycle_loss(x[0],x[0]))","metadata":{"execution":{"iopub.status.busy":"2024-06-13T23:58:17.632619Z","iopub.execute_input":"2024-06-13T23:58:17.633582Z","iopub.status.idle":"2024-06-13T23:58:17.643236Z","shell.execute_reply.started":"2024-06-13T23:58:17.633537Z","shell.execute_reply":"2024-06-13T23:58:17.641974Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Identity loss\nHelps preserve the color composition between input and output $G(x) ≈ x$, this doesn't compared the full cycled image, this compares input and output from a generator that translates to the same domain.  \nMathematically: $L_{Identity} = ||G(x) - x||_1 + ||F(y) - y||_1$\nAlso we need to multiply by $\\lambda$, can be different than ${\\lambda}_{cycle}$ . In this case ${\\lambda}_{Identity}$ multiplies $L_{Identity}$ to denote how important for our purpose is the color composition","metadata":{}},{"cell_type":"code","source":"def identity_loss(real_image, same_image, lambda_identity=5):\n    ## Real image is the original image from the source domain\n    ## Same image: image processed by the generator but in the same domain\n    return lambda_identity * tf.reduce_mean(tf.abs(real_image - same_image))\n\n### When comparing the same images, the cycle loss should be 0\nprint('Identity Loss: ', identity_loss(x[0],x[0]))","metadata":{"execution":{"iopub.status.busy":"2024-06-13T23:58:18.254662Z","iopub.execute_input":"2024-06-13T23:58:18.255442Z","iopub.status.idle":"2024-06-13T23:58:18.264375Z","shell.execute_reply.started":"2024-06-13T23:58:18.255403Z","shell.execute_reply":"2024-06-13T23:58:18.263265Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Building the CycleGAN","metadata":{}},{"cell_type":"code","source":"class CycleGAN(keras.Model):\n    def __init__(self, name = 'CycleGAN', lambda_cycle = 10, lambda_identity = 5):\n        super(CycleGAN,self).__init__(name = name)\n        self.monet_generator_ = Generator(name = 'Monet_Generator')\n        self.monet_discriminator_ = Discriminator(name = 'Monet_Discriminator')\n        self.photo_generator_ = Generator(name = 'Photo_Generator')\n        self.photo_discriminator_ = Discriminator(name = 'Photo_Discriminator')\n        self.lambda_cycle = lambda_cycle\n        self.lambda_identity = lambda_identity\n\n    def compile(self, m_gen_optimizer, p_gen_optimizer, m_disc_optimizer, p_disc_optimizer,  **kwargs):\n        super(CycleGAN, self).compile(**kwargs)\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.bce_ = tf.keras.losses.BinaryCrossentropy(from_logits = False)\n        \n    def generator_loss_(self, disc_output):\n        return self.bce_(tf.ones_like(disc_output), disc_output)\n    \n    def discriminator_loss_(self, real_output, fake_output):\n        real_loss = self.bce_(tf.ones_like(real_output), real_output)\n        fake_loss = self.bce_(tf.zeros_like(fake_output), fake_output)\n        return real_loss + fake_loss\n    \n    def cycle_loss_(self,real_image, cycled_image):\n        return self.lambda_cycle * tf.reduce_mean(tf.abs(real_image - cycled_image))\n    \n    def identity_loss_(self, real_image, same_image):\n        return self.lambda_identity * tf.reduce_mean(tf.abs(real_image - same_image))\n    \n    def train_step(self, batch_data):\n        real_monet, real_photo = batch_data\n        ### Persistent True to compute multiple gradients for the same tape\n        with tf.GradientTape(persistent = True) as tape:\n            \n            ### Forward pass\n            fake_monet = self.monet_generator_(real_photo, training = True) ## Photo to fake Monet\n            cycled_photo =self.photo_generator_(fake_monet, training = True) ## fake Monet to photo\n            fake_photo = self.photo_generator_(real_monet, training = True)  ## Monet to fake photo\n            cycled_monet = self.monet_generator_(fake_photo, training = True) ## fake Photo to Monet\n            \n            ### Identity mapping (G(x) to x, F(y) to y)\n            same_monet = self.monet_generator_(real_monet, training = True) ## Monet to monet\n            same_photo = self.photo_generator_(real_photo, training = True) ## Photo to photo\n            \n            #### Discriminator prediction\n            disc_real_monet = self.monet_discriminator_(real_monet, training = True) ## Monet is real Monet\n            disc_fake_monet = self.monet_discriminator_(fake_monet, training = True) ## Fake Monet is real Monet\n            disc_real_photo = self.photo_discriminator_(real_photo, training = True) ## Photo is a real photo\n            disc_fake_photo = self.photo_discriminator_(fake_photo, training = True) ## Fake Photo is a real photo\n            \n            ### Compute the loss functions\n            ## Generators\n            gen_monet_loss = self.generator_loss_(disc_fake_monet)  \n            gen_photo_loss = self.generator_loss_(disc_fake_photo)\n            ## Discriminators\n            disc_monet_loss = self.discriminator_loss_(disc_real_monet, disc_fake_monet)\n            disc_photo_loss = self.discriminator_loss_(disc_real_photo, disc_fake_photo)\n            ### Cycle\n            cycle_loss = self.cycle_loss_(real_monet, cycled_monet) + self.cycle_loss_(real_photo, cycled_photo)\n            ### Identity\n            identity_loss = self.identity_loss_(real_monet,same_monet) + self.identity_loss_(real_photo, same_photo)\n            ### Generators total loss\n            total_gen_monet_loss = gen_monet_loss + cycle_loss + identity_loss\n            total_gen_photo_loss = gen_photo_loss + cycle_loss + identity_loss\n            \n        ###Gradients\n        monet_generator_gradients = tape.gradient(total_gen_monet_loss, self.monet_generator_.trainable_variables)\n        photo_generator_gradients = tape.gradient(total_gen_photo_loss, self.photo_generator_.trainable_variables)\n        monet_discriminator_gradients = tape.gradient(disc_monet_loss, self.monet_discriminator_.trainable_variables)\n        photo_discriminator_gradients = tape.gradient(disc_photo_loss, self.photo_discriminator_.trainable_variables)\n\n        ### Aplying gradients\n        self.m_gen_optimizer.apply_gradients(zip(monet_generator_gradients,self.monet_generator_.trainable_variables))\n        self.p_gen_optimizer.apply_gradients(zip(photo_generator_gradients,self.photo_generator_.trainable_variables))\n        self.m_disc_optimizer.apply_gradients(zip(monet_discriminator_gradients,self.monet_discriminator_.trainable_variables))\n        self.p_disc_optimizer.apply_gradients(zip(photo_discriminator_gradients,self.photo_discriminator_.trainable_variables))\n\n        return {\n            \"monet_gen_loss\": total_gen_monet_loss,\n            \"photo_gen_loss\": total_gen_photo_loss,\n            \"monet_disc_loss\": disc_monet_loss,\n            \"photo_disc_loss\": disc_photo_loss}","metadata":{"execution":{"iopub.status.busy":"2024-06-13T23:58:19.109238Z","iopub.execute_input":"2024-06-13T23:58:19.110042Z","iopub.status.idle":"2024-06-13T23:58:19.128625Z","shell.execute_reply.started":"2024-06-13T23:58:19.110006Z","shell.execute_reply":"2024-06-13T23:58:19.127381Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Training\n## Callbacks\nSetting up callbacks to visualize the training process. Could use wandb but it's better to have everything on the notebook","metadata":{}},{"cell_type":"code","source":"class callbacks(keras.callbacks.Callback):\n    def on_epoch_end(self, epoch, logs={}):\n        ### Every 5 epochs plot the generator\n        randomint = np.random.randint(0,15,1)[0]\n        if epoch != 0:\n            fig, axes = plt.subplots(nrows=1, ncols=4, figsize=(15, 4))\n            fig.suptitle(f'Generator evolution epoch #{epoch}', fontsize=16)\n            ax = axes[0]\n            ax.imshow(example_photo[randomint])\n            axes[0].set_title('Original Photo', size='large', loc='center')\n            ax.axis('off')\n            ax = axes[1]\n            ax.imshow(cycle_gan.monet_generator_(example_photo)[randomint])\n            axes[1].set_title('Photo to Monet', size='large', loc='center')\n            ax.axis('off')\n            ax = axes[2]\n            ax.imshow(example_monet[randomint])\n            axes[2].set_title('Original Monet', size='large', loc='center')\n            ax.axis('off')\n            ax = axes[3]\n            ax.imshow(cycle_gan.photo_generator_(example_monet)[randomint])\n            axes[3].set_title('Monet to photo', size='large', loc='center')\n            ax.axis('off')\n            plt.show()\n        if epoch == 0:\n            fig, axes = plt.subplots(nrows=1, ncols=4, figsize=(15, 4))\n            fig.suptitle(f'Starting point', fontsize=16)\n            ax = axes[0]\n            ax.imshow(example_photo[randomint])\n            axes[0].set_title('Original Photo', size='large', loc='center')\n            ax.axis('off')\n            ax = axes[1]\n            ax.imshow(cycle_gan.monet_generator_(example_photo)[randomint])\n            axes[1].set_title('Photo to Monet', size='large', loc='center')\n            ax.axis('off')\n            ax = axes[2]\n            ax.imshow(example_monet[randomint])\n            axes[2].set_title('Original Monet', size='large', loc='center')\n            ax.axis('off')\n            ax = axes[3]\n            ax.imshow(cycle_gan.photo_generator_(example_monet)[randomint])\n            axes[3].set_title('Monet to photo', size='large', loc='center')\n            ax.axis('off')\n            plt.show()\ncallback = callbacks()","metadata":{"execution":{"iopub.status.busy":"2024-06-13T23:58:22.877125Z","iopub.execute_input":"2024-06-13T23:58:22.878063Z","iopub.status.idle":"2024-06-13T23:58:22.890196Z","shell.execute_reply.started":"2024-06-13T23:58:22.878029Z","shell.execute_reply":"2024-06-13T23:58:22.889035Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Optimizers\nNot sure what to use, using Adam","metadata":{}},{"cell_type":"code","source":"initial_learning_rate = 0.001\ndecay_steps = 100000\ndecay_rate = 0.96\n\nwith strategy.scope():\n    # Learning rate schedules for each optimizer\n    monet_gen_lr_schedule = tf.keras.optimizers.schedules.ExponentialDecay(\n        initial_learning_rate, decay_steps, decay_rate, staircase=True)\n\n    photo_gen_lr_schedule = tf.keras.optimizers.schedules.ExponentialDecay(\n        initial_learning_rate, decay_steps, decay_rate, staircase=True)\n\n    monet_disc_lr_schedule = tf.keras.optimizers.schedules.ExponentialDecay(\n        initial_learning_rate, decay_steps, decay_rate, staircase=True)\n\n    photo_disc_lr_schedule = tf.keras.optimizers.schedules.ExponentialDecay(\n        initial_learning_rate, decay_steps, decay_rate, staircase=True)\n    m_gen_opt = tf.keras.optimizers.Adam(learning_rate = monet_gen_lr_schedule, beta_1=0.5)\n    p_gen_opt = tf.keras.optimizers.Adam(learning_rate = photo_gen_lr_schedule, beta_1=0.5)\n    m_disc_opt = tf.keras.optimizers.Adam(learning_rate = monet_disc_lr_schedule, beta_1=0.5)\n    p_disc_opt = tf.keras.optimizers.Adam(learning_rate = photo_disc_lr_schedule, beta_1=0.5)","metadata":{"execution":{"iopub.status.busy":"2024-06-13T23:59:39.416061Z","iopub.execute_input":"2024-06-13T23:59:39.416433Z","iopub.status.idle":"2024-06-13T23:59:39.430540Z","shell.execute_reply.started":"2024-06-13T23:59:39.416405Z","shell.execute_reply":"2024-06-13T23:59:39.429515Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"with strategy.scope():\n    m_gen_opt = tf.keras.optimizers.Adam(2e-4, beta_1=0.5)\n    p_gen_opt = tf.keras.optimizers.Adam(2e-4, beta_1=0.5)\n    m_disc_opt = tf.keras.optimizers.Adam(2e-4, beta_1=0.5)\n    p_disc_opt = tf.keras.optimizers.Adam(2e-4, beta_1=0.5)","metadata":{"execution":{"iopub.status.busy":"2024-06-13T23:59:40.308746Z","iopub.execute_input":"2024-06-13T23:59:40.309116Z","iopub.status.idle":"2024-06-13T23:59:40.322514Z","shell.execute_reply.started":"2024-06-13T23:59:40.309087Z","shell.execute_reply":"2024-06-13T23:59:40.321527Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Creating the model\nMirrored strategy for using multiple GPU's","metadata":{}},{"cell_type":"code","source":"with strategy.scope():\n    cycle_gan = CycleGAN()\n    cycle_gan.compile(m_gen_opt, p_gen_opt, m_disc_opt, p_disc_opt)\ncycle_gan.summary()","metadata":{"execution":{"iopub.status.busy":"2024-06-13T23:59:42.326597Z","iopub.execute_input":"2024-06-13T23:59:42.327270Z","iopub.status.idle":"2024-06-13T23:59:42.547143Z","shell.execute_reply.started":"2024-06-13T23:59:42.327238Z","shell.execute_reply":"2024-06-13T23:59:42.546112Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"cycle_gan.fit(tf.data.Dataset.zip((monet_ds, photo_ds)), epochs=5, verbose = 1, callbacks = callback)","metadata":{"execution":{"iopub.status.busy":"2024-05-31T19:05:08.526158Z","iopub.execute_input":"2024-05-31T19:05:08.526570Z","iopub.status.idle":"2024-05-31T19:23:51.080002Z","shell.execute_reply.started":"2024-05-31T19:05:08.526538Z","shell.execute_reply":"2024-05-31T19:23:51.078803Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"fig, axes = plt.subplots(nrows=2, ncols=5, figsize=(15, 6))\nfig.suptitle('Results', fontsize=16)\n\nmonet_results = cycle_gan.monet_generator_(example_photo)[0:5]\nfor i in range(0,5):\n    ax = axes[0, i]\n    ax.imshow(example_photo[i])\n    ax.axis('off')\n\nfor count,element in enumerate(monet_results):\n    ax = axes[1, count]\n    ax.imshow(element)\n    ax.axis('off')\n\naxes[0, 2].set_title('Photos', size='large', loc='center')\naxes[1, 2].set_title('Photos as Monet', size='large', loc='center')\nplt.tight_layout()  # Adjust layout to make room for the main title\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2024-05-31T19:23:51.082318Z","iopub.execute_input":"2024-05-31T19:23:51.082678Z","iopub.status.idle":"2024-05-31T19:23:52.118655Z","shell.execute_reply.started":"2024-05-31T19:23:51.082650Z","shell.execute_reply":"2024-05-31T19:23:52.117357Z"},"jupyter":{"source_hidden":true},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Submission Files\nIm using the [Dogs vs Cats](https://www.kaggle.com/competitions/dogs-vs-cats/data) dataset to create the submission for the competition","metadata":{}},{"cell_type":"code","source":"Dog_files = glob(str('/kaggle/input/microsoft-catsvsdogs-dataset/PetImages/Dog/*.jpg'))[0:5000]\nprint('Dog_files:', len(Dog_files))\nCat_files = glob(str('/kaggle/input/microsoft-catsvsdogs-dataset/PetImages/Cat/*.jpg'))[0:5000]\nprint('Cat_files:', len(Cat_files))\nsubmission_images = Dog_files + Cat_files\nsubmission_images.pop(3389)  ## Images that I identified as corrupted. Easier to pop them like this\nsubmission_images.pop(3970)\nsubmission_images.pop(5222)","metadata":{"execution":{"iopub.status.busy":"2024-05-31T19:24:38.506538Z","iopub.execute_input":"2024-05-31T19:24:38.506933Z","iopub.status.idle":"2024-05-31T19:24:41.292984Z","shell.execute_reply.started":"2024-05-31T19:24:38.506904Z","shell.execute_reply":"2024-05-31T19:24:41.291979Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def is_valid_image(image):\n    return tf.shape(image).shape[-1] ==  3\n\ndef decode_image_2(image):\n    try:\n        image = tf.image.decode_image(image, channels=3,expand_animations=False)\n        image.set_shape([None, None, 3])\n        image = tf.image.convert_image_dtype(image, tf.float32)\n        if is_valid_image(image):\n            image =  tf.image.resize_with_crop_or_pad(image, 256, 256)\n            image = tf.reshape(image, [*IMAGE_SIZE, 3])\n            return image\n        else:\n            return tf.zeros([256, 256, 3], dtype=tf.float32)\n    except Exception as e:\n        print(f\"Error decoding image: {e}\")\n        return tf.zeros([256, 256, 3], dtype=tf.float32)\n\ndef read_and_decode_image(filename):\n    try:\n        image = tf.io.read_file(filename)\n        if tf.size(image) > 0: \n            return decode_image_2(image)\n        else:\n            return tf.zeros([256, 256, 3], dtype=tf.float32)\n        \n    except Exception as e:\n        print(f\"Error reading image file: {e}\")\n        return tf.zeros([256, 256, 3], dtype=tf.float32) \n    \ndef load_sub_dataset(filenames, labeled=True, ordered=False, repeat = False):\n    dataset = tf.data.Dataset.from_tensor_slices(filenames)\n    dataset = dataset.map(read_and_decode_image, num_parallel_calls=AUTOTUNE)\n    #dataset = dataset.prefetch(buffer_size=tf.data.experimental.AUTOTUNE)\n    return dataset","metadata":{"execution":{"iopub.status.busy":"2024-05-31T19:24:52.570924Z","iopub.execute_input":"2024-05-31T19:24:52.571837Z","iopub.status.idle":"2024-05-31T19:24:52.584976Z","shell.execute_reply.started":"2024-05-31T19:24:52.571803Z","shell.execute_reply":"2024-05-31T19:24:52.583804Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"Dogs = load_sub_dataset(Dog_files).batch(15)\nexample_dog = next(iter(Dogs))\nCats = load_sub_dataset(Cat_files).batch(15)\nexample_cat = next(iter(Cats))\nsubmission_dataset = load_sub_dataset(submission_images).batch(1)","metadata":{"execution":{"iopub.status.busy":"2024-05-31T19:27:00.638103Z","iopub.execute_input":"2024-05-31T19:27:00.638524Z","iopub.status.idle":"2024-05-31T19:27:01.507027Z","shell.execute_reply.started":"2024-05-31T19:27:00.638492Z","shell.execute_reply":"2024-05-31T19:27:01.505934Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Data visualization","metadata":{}},{"cell_type":"code","source":"fig, axes = plt.subplots(nrows=1, ncols = 4, figsize=(15, 4))\nfig.suptitle('Dogs and Cats', fontsize=16)\n\nax = axes[0]\nax.imshow(example_dog[0])\naxes[0].set_title('Dog or Cat', size='large', loc='center')\nax.axis('off')\n\nax = axes[1]\nax.imshow(cycle_gan.monet_generator_(example_dog)[0])\naxes[1].set_title('Monetized Dog dd', size='large', loc='center')\nax.axis('off')\n\nax = axes[2]\nax.imshow(example_cat[0])\naxes[2].set_title('Cat', size='large', loc='center')\nax.axis('off')\n\nax = axes[3]\nax.imshow(cycle_gan.monet_generator_(example_cat)[0])\naxes[3].set_title('Monetized Cat dd', size='large', loc='center')\nax.axis('off')\n\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2024-05-31T19:24:57.356488Z","iopub.execute_input":"2024-05-31T19:24:57.356873Z","iopub.status.idle":"2024-05-31T19:24:58.077091Z","shell.execute_reply.started":"2024-05-31T19:24:57.356840Z","shell.execute_reply":"2024-05-31T19:24:58.076105Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"try:\n    shutil.rmtree(\"/kaggle/working/images\")\nexcept:\n    pass\nos.mkdir(\"/kaggle/working/images\")\nfor count,element in enumerate(submission_dataset):\n    prediction = cycle_gan.monet_generator_(element, training = False)[0]\n    image = tf.image.convert_image_dtype(prediction, tf.uint8)\n    image = tf.image.encode_jpeg(image)\n    tf.io.write_file(f'/kaggle/working/images/{count}.jpg', image)\nshutil.make_archive(\"/kaggle/working/images\", 'zip', \"/kaggle/working/images\")\nprint('zip file done')\nshutil.rmtree(\"/kaggle/working/images\")","metadata":{"execution":{"iopub.status.busy":"2024-05-31T19:36:10.271081Z","iopub.execute_input":"2024-05-31T19:36:10.272060Z","iopub.status.idle":"2024-05-31T19:46:36.844497Z","shell.execute_reply.started":"2024-05-31T19:36:10.272020Z","shell.execute_reply":"2024-05-31T19:46:36.843477Z"},"trusted":true},"execution_count":null,"outputs":[]}]}