{"metadata":{"kernelspec":{"name":"python3","display_name":"Python 3","language":"python"},"language_info":{"name":"python","version":"3.10.13","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"gpu","dataSources":[{"sourceId":21755,"databundleVersionId":1475600,"sourceType":"competition"},{"sourceId":8218703,"sourceType":"datasetVersion","datasetId":4871780}],"dockerImageVersionId":30699,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"#### Imports","metadata":{}},{"cell_type":"code","source":"# Standard Python modules\nimport numpy as np\nimport pandas as pd\nimport matplotlib.pyplot as plt\nimport os\n\n# Third-party modules\nfrom PIL import Image\n\n# TensorFlow and Keras for machine learning tools\nimport tensorflow as tf\nfrom tensorflow import keras\nfrom keras.layers import Input, Conv2D, Conv2DTranspose, Dropout, LeakyReLU, ReLU, ZeroPadding2D, GroupNormalization, Concatenate\nfrom keras.models import Model\nfrom keras.losses import BinaryCrossentropy\nfrom keras.optimizers import Adam","metadata":{"execution":{"iopub.status.busy":"2024-04-24T17:11:50.177328Z","iopub.execute_input":"2024-04-24T17:11:50.177868Z","iopub.status.idle":"2024-04-24T17:11:50.185654Z","shell.execute_reply.started":"2024-04-24T17:11:50.177826Z","shell.execute_reply":"2024-04-24T17:11:50.18353Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"#### Parameters\n\n","metadata":{}},{"cell_type":"code","source":"IMAGES_FORMAT = (256,256)\nIMAGES_FOLDER = '/kaggle/input/calm-images/dataset2'","metadata":{"execution":{"iopub.status.busy":"2024-04-24T17:11:50.188298Z","iopub.execute_input":"2024-04-24T17:11:50.188848Z","iopub.status.idle":"2024-04-24T17:11:50.206378Z","shell.execute_reply.started":"2024-04-24T17:11:50.18881Z","shell.execute_reply":"2024-04-24T17:11:50.204877Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"#### Original dataset (monet)\n\nList all the tfrec files in the dataset folder","metadata":{}},{"cell_type":"code","source":"photo_files= tf.io.gfile.glob('/kaggle/input/gan-getting-started/photo_tfrec')\nprint('Number of Photo TFRecord files: ',len(photo_files))","metadata":{"execution":{"iopub.status.busy":"2024-04-24T17:11:50.20791Z","iopub.execute_input":"2024-04-24T17:11:50.209557Z","iopub.status.idle":"2024-04-24T17:11:50.220474Z","shell.execute_reply.started":"2024-04-24T17:11:50.209479Z","shell.execute_reply":"2024-04-24T17:11:50.219041Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"#### Load both the kaggle and custom dataset","metadata":{}},{"cell_type":"code","source":"IMAGE_SIZE = [256, 256] \n\ndef decode_img(image):\n    image = tf.image.decode_jpeg(image, channels=3)  \n    image = (tf.cast(image, tf.float32) / 255) * 2 - 1  \n    image = tf.reshape(image, shape=[*IMAGE_SIZE, 3])  \n    return image\n\ndef read_image(image_path):\n    image = tf.io.read_file(image_path)  \n    image = decode_img(image) \n    return image\n\ndef read_tfrec(example):                                       \n    tfrec_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, tfrec_format)\n    image= decode_img(example['image'])\n    return image\n\n\ndef load_custom_data(image_dir):\n    image_paths = [os.path.join(image_dir, filename) for filename in os.listdir(image_dir)]\n    images = [read_image(image_path) for image_path in image_paths]\n    data = tf.data.Dataset.from_tensor_slices(images)\n    return data\n\n\"\"\"\ndef load_custom_data(image_dir):\n    image_paths = [os.path.join(image_dir, filename) for filename in os.listdir(image_dir)]\n    images = [read_image(image_path) for image_path in image_paths]\n    \n    # Convertir les images en tenseurs et ajouter une dimension supplémentaire pour les lot\n    images = tf.convert_to_tensor(images)\n    images = tf.expand_dims(images, axis=0)\n    \n    # Créer un Dataset TensorFlow à partir des images\n    dataset = tf.data.Dataset.from_tensor_slices(images)\n    \n    return dataset\n\"\"\"\ndef load_data(files):\n    data= tf.data.TFRecordDataset(files)\n    data= data.map(read_tfrec)                                  \n    return data\n\n# Data load from a standard dataset from kaggle\n#monet_data= load_data(monet_files).batch(1)    \nphoto_files= tf.io.gfile.glob('/kaggle/input/gan-getting-started/photo_tfrec/photo00-352.tfrec')\nphoto_data= load_data(photo_files).batch(1)\n\n# Data loadi from my custom ai generated images\ncustom_data = load_custom_data('/kaggle/input/calm-images/dataset2')\ncustom_data_batched = custom_data.batch(1)  \n","metadata":{"execution":{"iopub.status.busy":"2024-04-24T17:11:50.223309Z","iopub.execute_input":"2024-04-24T17:11:50.224111Z","iopub.status.idle":"2024-04-24T17:11:51.891502Z","shell.execute_reply.started":"2024-04-24T17:11:50.224082Z","shell.execute_reply":"2024-04-24T17:11:51.889537Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"photo_files= tf.io.gfile.glob('/kaggle/input/gan-getting-started/photo_tfrec')\nprint('Number of Photo TFRecord files: ',len(photo_files))","metadata":{"execution":{"iopub.status.busy":"2024-04-24T17:11:51.892916Z","iopub.execute_input":"2024-04-24T17:11:51.893391Z","iopub.status.idle":"2024-04-24T17:11:51.902089Z","shell.execute_reply.started":"2024-04-24T17:11:51.89327Z","shell.execute_reply":"2024-04-24T17:11:51.900745Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"ex_ai       = next(iter(custom_data_batched))\nex_photo    = next(iter(photo_data))\n#ex_monet    = next(iter(monet_data))\n\nplt.figure(figsize=(15, 5))\n# Plot AI Generated image\nplt.subplot(1, 3, 1)\nplt.title('AI Generated image')\nplt.imshow(ex_ai[0] * 0.5 + 0.5)\n\n# Plot Kaggle dataset - random image\nplt.subplot(1, 3, 2)\nplt.title('Kaggle dataset (random images)')\nplt.imshow(ex_photo[0] * 0.5 + 0.5)\n\n# Plot Monet dataset\n#plt.subplot(1, 3, 3)\n#plt.title('Monet dataset')\n#plt.imshow(ex_monet[0] * 0.5 + 0.5)\nplt.tight_layout()\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2024-04-24T17:11:51.903329Z","iopub.execute_input":"2024-04-24T17:11:51.903621Z","iopub.status.idle":"2024-04-24T17:11:52.759834Z","shell.execute_reply.started":"2024-04-24T17:11:51.903599Z","shell.execute_reply":"2024-04-24T17:11:52.758246Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def downsample(filters, size, instance_norm= True):                                   # for extracting important features (size is reduced)\n    initializer= tf.random_normal_initializer(0,0.02)                                 # mean=0 and standard deviation=0.02 for initializing kernel weights\n    gamma_init= keras.initializers.RandomNormal(mean= 0, stddev= 0.02)\n    \n    model= keras.Sequential()                                          \n    model.add(Conv2D(filters, size, strides=2, padding='same', kernel_initializer= initializer, use_bias= False))\n    \n    if instance_norm:\n         model.add(GroupNormalization(groups= -1, gamma_initializer= gamma_init))     # groups= -1 to make it work like Instance Normalization\n   \n    model.add(LeakyReLU())\n    \n    return model","metadata":{"execution":{"iopub.status.busy":"2024-04-24T17:11:52.761382Z","iopub.execute_input":"2024-04-24T17:11:52.76186Z","iopub.status.idle":"2024-04-24T17:11:52.76942Z","shell.execute_reply.started":"2024-04-24T17:11:52.761825Z","shell.execute_reply":"2024-04-24T17:11:52.767886Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def upsample(filters, size, dropout= False):                                         # for locating features accurately using skip connections \n    initializer= tf.random_normal_initializer(0,0.02)\n    gamma_init= keras.initializers.RandomNormal(mean= 0, stddev= 0.02)\n    \n    model= keras.Sequential()\n    model.add(Conv2DTranspose(filters, size, strides= 2, padding= 'same', kernel_initializer= initializer, use_bias= False))\n    model.add(GroupNormalization(groups= -1, gamma_initializer= gamma_init))\n    \n    if dropout:\n        model.add(Dropout(0.5))\n    \n    model.add(ReLU())\n    \n    return model","metadata":{"execution":{"iopub.status.busy":"2024-04-24T17:11:52.771537Z","iopub.execute_input":"2024-04-24T17:11:52.772027Z","iopub.status.idle":"2024-04-24T17:11:52.790383Z","shell.execute_reply.started":"2024-04-24T17:11:52.771989Z","shell.execute_reply":"2024-04-24T17:11:52.788897Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def generator():\n    down_stack= [\n        downsample(64,4,False),                 # size= (128,128,64)  (size denotes the dimensions of image after the corresponding layer/operation)\n        downsample(128,4),                      # size= (64,64,128)\n        downsample(256,4),                      # size= (32,32,256)\n        downsample(512,4),                      # size= (16,16,512)\n        downsample(512,4),                      # size= (8,8,512)\n        downsample(512,4),                      # size= (4,4,512)\n        downsample(512,4),                      # size= (2,2,512)\n        downsample(512,4),                      # size= (1,1,512)\n    ]\n    \n    up_stack= [\n        upsample(512,4,True),                   # size= (2,2,1024)  (no. of channels doubled because upsample block concats output of last downsample block)    \n        upsample(512,4,True),                   # size= (4,4,1024)\n        upsample(512,4,True),                   # size= (8,8,1024)\n        upsample(512,4),                        # size= (16,16,1024)  (dropout= false so that information is maintained for generating detailed outputs)\n        upsample(256,4),                        # size= (32,32,512)\n        upsample(128,4),                        # size= (64,64,256)\n        upsample(64,4)                          # size= (128,128,128)\n    ]\n    \n    initializer= tf.random_normal_initializer(0,0.02)\n    last_layer= Conv2DTranspose(3, 4, strides= 2, padding= 'same', kernel_initializer= initializer, activation= 'tanh')     # 3 output channels required\n    \n    i= Input(shape= [256,256,3])                # input layer\n    x= i\n    skips= []\n    for down in down_stack:                     # downsampling\n        x= down (x) \n        skips.append(x)                         # appending skip connections to the 'skips' list\n        \n    skips= reversed(skips[:-1])                 # last skip connection is not used because of alignment with upsampling path\n    \n    for up, skip in zip(up_stack,skips):        # upsampling and concatenating output with skip connection\n        x= up (x)\n        x= Concatenate() ([x,skip])\n        \n    x= last_layer(x)                            # last layer (Conv2DTranspose) for generating the final output \n    \n    model= Model(i,x)\n    \n    return model","metadata":{"execution":{"iopub.status.busy":"2024-04-24T17:11:52.793724Z","iopub.execute_input":"2024-04-24T17:11:52.794257Z","iopub.status.idle":"2024-04-24T17:11:52.806687Z","shell.execute_reply.started":"2024-04-24T17:11:52.794226Z","shell.execute_reply":"2024-04-24T17:11:52.805413Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def discriminator():\n    i= Input(shape= [256,256,3])\n    x= downsample(64,4) (i)                                 # size= (128,128,64) \n    x= downsample(128,4) (x)                                # size= (64,64,128) \n    x= downsample(256,4) (x)                                # size= (32,32,256)\n    \n    x= ZeroPadding2D() (x)                                  # size= (34,34,256)    (1 pixel padding is added at top,bottom,left,right) \n    \n    initializer= tf.random_normal_initializer(0,0.02)\n    gamma_init= keras.initializers.RandomNormal(mean= 0, stddev= 0.02)\n    x= Conv2D(512, 4, strides= 1, padding= 'same', kernel_initializer= initializer, use_bias= False) (x)      # size= (31,31,512) (size= orig - kernel + 1)\n    x= GroupNormalization(groups= -1, gamma_initializer= gamma_init) (x)\n    x= LeakyReLU() (x)\n    \n    x= ZeroPadding2D() (x)                                  # size= (33,33,512)    (zero padding applied to maintain spatial information)\n    \n    x= Conv2D(1, 4, strides= 1, padding= 'same', kernel_initializer= initializer) (x)       # size= (30,30,1) \n                                                                                            # sigmoid not used to output unbounded logits\n    model= Model(i,x)                                                                       # (more numerically stable during training)\n    \n    return model","metadata":{"execution":{"iopub.status.busy":"2024-04-24T17:11:52.807792Z","iopub.execute_input":"2024-04-24T17:11:52.808088Z","iopub.status.idle":"2024-04-24T17:11:52.82426Z","shell.execute_reply.started":"2024-04-24T17:11:52.80806Z","shell.execute_reply":"2024-04-24T17:11:52.822878Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# with strategy.scope():\nai_generator= generator()                     # photo to AI-esque\nai_discriminator= discriminator()             # to differentiate between generated ai-esque images and real images\nphoto_generator= generator()                     # ai-esque to photo\nphoto_discriminator= discriminator()             # to differentiate between generated 'normal' images and ai 'normal' images","metadata":{"execution":{"iopub.status.busy":"2024-04-24T17:11:52.825592Z","iopub.execute_input":"2024-04-24T17:11:52.825948Z","iopub.status.idle":"2024-04-24T17:11:54.826872Z","shell.execute_reply.started":"2024-04-24T17:11:52.825919Z","shell.execute_reply":"2024-04-24T17:11:54.825516Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"photo_to_ai= ai_generator(ex_photo)                # won't generate monet-esque photos as we have not fit the data into generator yet\n\nplt.subplot(1,2,1)                                       # creating a subplot with 1 row and 2 columns\nplt.title('Original Photo')\nplt.imshow(ex_photo[0]*0.5 +0.5)                         # rescaling the image to [0,1] for displaying\n\nplt.subplot(1,2,2)\nplt.title('Generated AI-esque photo')\nplt.imshow(photo_to_ai[0]*0.5 +0.5)        ","metadata":{"execution":{"iopub.status.busy":"2024-04-24T17:11:54.828974Z","iopub.execute_input":"2024-04-24T17:11:54.829431Z","iopub.status.idle":"2024-04-24T17:11:55.708902Z","shell.execute_reply.started":"2024-04-24T17:11:54.829395Z","shell.execute_reply":"2024-04-24T17:11:55.706887Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"class CycleGAN(keras.Model):                       # CycleGAN class inheriting from keras.Model class so that it can use its methods to train, compile etc.\n    def __init__(                                  # arguments to be passed in a CycleGAN class object   \n        self,\n        monet_gen,\n        monet_disc,\n        photo_gen,\n        photo_disc,\n        lambda_cycle= 10                           # 'lambda_cycle' controls the importance of cycle consistency loss\n    ):\n        super(CycleGAN,self).__init__()            # calls the constructor of the parent class (keras.Model), initializing the base properties and methods\n        self.m_gen= monet_gen                      # assigning argument values to attributes of a CycleGAN class object/instance\n        self.m_disc= monet_disc\n        self.p_gen= photo_gen\n        self.p_disc= photo_disc\n        self.lambda_cycle= lambda_cycle\n        \n    def compile(                                   \n        self,\n        m_gen_optimizer,\n        m_disc_optimizer,\n        p_gen_optimizer,\n        p_disc_optimizer,\n        gen_loss_function,\n        disc_loss_function,\n        cycle_loss_function,\n        identity_loss_function\n    ):\n        super(CycleGAN,self).compile()             # calls the 'compile' fn of the parent class (keras.Model), initializing the base properties and methods\n        self.m_gen_optimizer = m_gen_optimizer\n        self.m_disc_optimizer = m_disc_optimizer\n        self.p_gen_optimizer = p_gen_optimizer\n        self.p_disc_optimizer = p_disc_optimizer\n        self.gen_loss_function = gen_loss_function\n        self.disc_loss_function = disc_loss_function\n        self.cycle_loss_function = cycle_loss_function\n        self.identity_loss_function = identity_loss_function\n        \n    def train_step(self,batch_data):                                # automatically invoked when fit() method is called \n        real_monet, real_photo= batch_data\n        \n        with tf.GradientTape(persistent= True) as tape:             # to keep a track of operations (persistent= True bcz of multiple calls to Gradient())\n            \n            fake_monet= self.m_gen(real_photo, training= True)      # photo to monet and then cycled back to photo\n            cycled_photo= self.p_gen(fake_monet, training= True)\n            \n            fake_photo= self.p_gen(real_monet, training= True)      # monet to photo and then cycled back to monet\n            cycled_monet= self.m_gen(fake_photo, training= True)\n            \n            same_photo= self.p_gen(real_photo, training= True)      # generating itself (useful in calculating identity loss)\n            same_monet= self.m_gen(real_monet, training= True)      \n            \n            disc_real_photo= self.p_disc(real_photo, training= True)   # discriminator used to check by inputing real images\n            disc_real_monet= self.m_disc(real_monet, training= True)   \n            \n            disc_fake_photo= self.p_disc(fake_photo, training= True)   # discriminator used to check by inputing fake images\n            disc_fake_monet= self.m_disc(fake_monet, training= True)\n            \n            gen_monet_loss= self.gen_loss_function(disc_fake_monet)    # generator loss\n            gen_photo_loss= self.gen_loss_function(disc_fake_photo)\n            \n            total_cycle_loss = (self.cycle_loss_function(real_monet, cycled_monet, self.lambda_cycle) +     # total cycle consistency loss\n            self.cycle_loss_function(real_photo, cycled_photo, self.lambda_cycle))\n            \n            total_gen_monet_loss= (gen_monet_loss + total_cycle_loss   +                                    # total generator monet loss\n            self.identity_loss_function(real_monet, same_monet, self.lambda_cycle) )  \n            \n            total_gen_photo_loss= (gen_photo_loss + total_cycle_loss   +                                    # total generator photo loss\n            self.identity_loss_function(real_photo, same_photo, self.lambda_cycle) )\n            \n            disc_monet_loss= self.disc_loss_function(disc_real_monet, disc_fake_monet)                      # discriminator monet loss \n            disc_photo_loss= self.disc_loss_function(disc_real_photo, disc_fake_photo)                      # discriminator photo loss\n            \n            \n        gen_monet_gradients= tape.gradient(total_gen_monet_loss, self.m_gen.trainable_variables)            # calculate gradients for generators\n        gen_photo_gradients= tape.gradient(total_gen_photo_loss, self.p_gen.trainable_variables)            # diff loss fn wrt trainable variables of model\n        \n        disc_monet_gradients= tape.gradient(disc_monet_loss, self.m_disc.trainable_variables)               # calculate gradients for discriminators\n        disc_photo_gradients= tape.gradient(disc_photo_loss, self.p_disc.trainable_variables)\n        \n        self.m_gen_optimizer.apply_gradients(zip(gen_monet_gradients, self.m_gen.trainable_variables))      # apply the gradients to optimizer\n        self.p_gen_optimizer.apply_gradients(zip(gen_photo_gradients, self.p_gen.trainable_variables))      # basically performing gradient descent\n        self.m_disc_optimizer.apply_gradients(zip(disc_monet_gradients, self.m_disc.trainable_variables))\n        self.p_disc_optimizer.apply_gradients(zip(disc_photo_gradients, self.p_disc.trainable_variables))\n        \n        return {\n            'gen_monet_loss': total_gen_monet_loss,\n            'gen_photo_loss': total_gen_photo_loss,\n            'disc_monet_loss': disc_monet_loss,\n            'disc_photo_loss': disc_photo_loss\n        }","metadata":{"execution":{"iopub.status.busy":"2024-04-24T17:11:55.711023Z","iopub.execute_input":"2024-04-24T17:11:55.711371Z","iopub.status.idle":"2024-04-24T17:11:55.729373Z","shell.execute_reply.started":"2024-04-24T17:11:55.711341Z","shell.execute_reply":"2024-04-24T17:11:55.727663Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# with strategy.scope():\ndef gen_loss_fn(generated):            # from_logits=True used bcz disc return unbounded values & NONE redn used to return tensor of indiv losses bcz those values are returned at each epoch\n    return BinaryCrossentropy(from_logits= True, reduction= tf.keras.losses.Reduction.NONE)(tf.ones_like(generated),generated)","metadata":{"execution":{"iopub.status.busy":"2024-04-24T17:11:55.73189Z","iopub.execute_input":"2024-04-24T17:11:55.732805Z","iopub.status.idle":"2024-04-24T17:11:55.751103Z","shell.execute_reply.started":"2024-04-24T17:11:55.732691Z","shell.execute_reply":"2024-04-24T17:11:55.749381Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# with strategy.scope():\ndef disc_loss_fn(real, generated):\n    loss_real= BinaryCrossentropy(from_logits= True, reduction= tf.keras.losses.Reduction.NONE)(tf.ones_like(real),real)\n    loss_fake= BinaryCrossentropy(from_logits= True, reduction= tf.keras.losses.Reduction.NONE)(tf.zeros_like(generated),generated)\n        \n    total_loss= (loss_real + loss_fake)/2\n        \n    return total_loss","metadata":{"execution":{"iopub.status.busy":"2024-04-24T17:11:55.752429Z","iopub.execute_input":"2024-04-24T17:11:55.752762Z","iopub.status.idle":"2024-04-24T17:11:55.771243Z","shell.execute_reply.started":"2024-04-24T17:11:55.75273Z","shell.execute_reply":"2024-04-24T17:11:55.769662Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# with strategy.scope():\ndef cycle_loss_fn(real, cycled, lambda_cycle):\n    loss= tf.reduce_mean(tf.abs(real - cycled))\n        \n    return lambda_cycle*loss                        # lambda controls the weight of cycle consistency loss in overall loss ","metadata":{"execution":{"iopub.status.busy":"2024-04-24T17:11:55.772325Z","iopub.execute_input":"2024-04-24T17:11:55.77265Z","iopub.status.idle":"2024-04-24T17:11:55.785326Z","shell.execute_reply.started":"2024-04-24T17:11:55.772621Z","shell.execute_reply":"2024-04-24T17:11:55.783973Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# with strategy.scope():\ndef identity_loss_fn(real, same, Lambda):           # LAMBDA has same use as in case of cycle consistency loss\n    loss= tf.reduce_mean(tf.abs(real - same))\n        \n    return Lambda*loss*0.5                          # factor of '0.5' used for normalization purposes","metadata":{"execution":{"iopub.status.busy":"2024-04-24T17:11:55.787245Z","iopub.execute_input":"2024-04-24T17:11:55.787799Z","iopub.status.idle":"2024-04-24T17:11:55.800687Z","shell.execute_reply.started":"2024-04-24T17:11:55.787693Z","shell.execute_reply":"2024-04-24T17:11:55.799302Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# with strategy.scope():\nm_gen_opt= Adam(learning_rate= 2e-4, beta_1= 0.5)\nm_disc_opt= Adam(learning_rate= 2e-4, beta_1= 0.5)\n\np_gen_opt= Adam(learning_rate= 2e-4, beta_1= 0.5)\np_disc_opt= Adam(learning_rate= 2e-4, beta_1= 0.5)","metadata":{"execution":{"iopub.status.busy":"2024-04-24T17:11:55.80236Z","iopub.execute_input":"2024-04-24T17:11:55.802731Z","iopub.status.idle":"2024-04-24T17:11:55.827158Z","shell.execute_reply.started":"2024-04-24T17:11:55.802678Z","shell.execute_reply":"2024-04-24T17:11:55.825816Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# with strategy.scope():\ncyclegan_model= CycleGAN(ai_generator, ai_discriminator, photo_generator, photo_discriminator, 10)\ncyclegan_model.compile(m_gen_opt, m_disc_opt, p_gen_opt, p_disc_opt, gen_loss_fn, disc_loss_fn, \n                        cycle_loss_fn, identity_loss_fn)","metadata":{"execution":{"iopub.status.busy":"2024-04-24T17:11:55.828962Z","iopub.execute_input":"2024-04-24T17:11:55.829424Z","iopub.status.idle":"2024-04-24T17:11:55.848285Z","shell.execute_reply.started":"2024-04-24T17:11:55.829385Z","shell.execute_reply":"2024-04-24T17:11:55.846798Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Extraire un élément du jeu de données custom_data\nfor image in custom_data.take(1):\n    print(\"Forme de l'image dans custom_data:\", image.shape)\n\n# Extraire un élément du jeu de données photo_data\nfor image in photo_data.take(1):\n    print(\"Forme de l'image dans photo_data:\", image.shape)\n\n\ncustom_data = custom_data.map(lambda x: tf.expand_dims(x, axis=0))","metadata":{"execution":{"iopub.status.busy":"2024-04-24T17:11:55.850199Z","iopub.execute_input":"2024-04-24T17:11:55.850503Z","iopub.status.idle":"2024-04-24T17:11:56.087937Z","shell.execute_reply.started":"2024-04-24T17:11:55.850477Z","shell.execute_reply":"2024-04-24T17:11:56.086564Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"custom_data = custom_data.repeat()\nphoto_data = photo_data.repeat()\ncyclegan_model.fit(tf.data.Dataset.zip((custom_data, photo_data)), epochs= 1, steps_per_epoch=300)","metadata":{"execution":{"iopub.status.busy":"2024-04-24T17:11:56.089314Z","iopub.execute_input":"2024-04-24T17:11:56.089685Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"fig,ax= plt.subplots(6,2, figsize=(7,20))\nfor i,img in enumerate(photo_data.take(6)):\n    pred= ai_generator(img, training= False)[0].numpy()   # training= False to make sure not to update model's weights\n    pred= (pred*127.5 + 127.5).astype(np.uint8)              # making pixel range to [0,255]\n    img= (img[0]*127.5 + 127.5).numpy().astype(np.uint8)\n    \n    ax[i,0].imshow(img)\n    ax[i,1].imshow(pred)\n    ax[i,0].set_title('Real Photo')\n    ax[i,1].set_title('Generated AI-esque')\n    ax[i,0].axis('off')\n    ax[i,1].axis('off')","metadata":{"trusted":true},"execution_count":null,"outputs":[]}]}