{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.7.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":3965080,"sourceType":"datasetVersion","datasetId":2353282},{"sourceId":9295250,"sourceType":"datasetVersion","datasetId":5627695}],"dockerImageVersionId":30214,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"\n\nimport os\nimport pathlib\n\n\n\nimport time\nimport datetime\nimport imageio\nfrom glob import glob\n\n\n\nimport tensorflow as tf\nimport numpy as np \nimport tensorflow.keras.backend as K\nimport tensorflow_addons as tfa\n\n\nfrom matplotlib import pyplot as plt\nfrom IPython import display\nfrom termcolor import colored\nfrom tqdm import tqdm\nfrom IPython.display import Image\nimport PIL\nfrom PIL import ImageDraw\nfrom IPython import display\n\ndef color_print(print_str,\n                 print_color='green'):\n    \n    '''print in given  color (default green)'''\n    print(colored(print_str,print_color))\n\n","metadata":{"execution":{"iopub.status.busy":"2024-09-01T14:47:12.948367Z","iopub.execute_input":"2024-09-01T14:47:12.94883Z","iopub.status.idle":"2024-09-01T14:47:12.95778Z","shell.execute_reply.started":"2024-09-01T14:47:12.948792Z","shell.execute_reply":"2024-09-01T14:47:12.956689Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import tensorflow as tf\nprint(tf.__version__)","metadata":{"execution":{"iopub.status.busy":"2024-09-01T14:47:18.99452Z","iopub.execute_input":"2024-09-01T14:47:18.994977Z","iopub.status.idle":"2024-09-01T14:47:19.000386Z","shell.execute_reply.started":"2024-09-01T14:47:18.994939Z","shell.execute_reply":"2024-09-01T14:47:18.999284Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"\ndef set_seed(seed):\n    np.random.seed(seed)\n    tf.random.set_seed(seed)\n    os.environ['PYTHONHASHSEED'] = str(seed)\n    os.environ['TF_DETERMINISTIC_OPS'] = '1'\n    print(f'setting seed to {seed}')\n    \n\nclass CFG:\n    \n    # Dimension of image\n    IMG_WIDTH =  512\n    IMG_HEIGHT = 512\n    \n    #resize image \n    resize_height = 700\n    resize_width = 1200\n    \n    #the lambda param in loss\n    LAMBDA = 10\n    #--------train pipe-------------\n    BUFFER_SIZE = 100\n    # The batch size of 1 produced better results for the U-Net in the original pix2pix experiment\n    BATCH_SIZE = 2\n    \n    #cache \n    cache= 50\n    \n    #learning rate \n    learning_rate = 0.00025\n    \n    \n    seed = 7 \n    \n\nset_seed(CFG.seed)","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2024-09-01T14:47:41.665822Z","iopub.execute_input":"2024-09-01T14:47:41.666781Z","iopub.status.idle":"2024-09-01T14:47:41.675056Z","shell.execute_reply.started":"2024-09-01T14:47:41.666742Z","shell.execute_reply":"2024-09-01T14:47:41.674086Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<h2 style='color:green'> Data directories </h2>\n","metadata":{}},{"cell_type":"code","source":"day_dir = '/kaggle/input/dataset-1'\nnight_dir = '../input/daynight-cityview/night'\n\n\n#plotting a sample image \nplt.figure(figsize=(16,8))\n\nimg = plt.imread(day_dir + '/' + os.listdir(day_dir)[0])\nplt.imshow(img)\nplt.axis('off')\nplt.title('sample image')\nprint(f'Image dimensions {img.shape}')\nplt.show()","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2024-09-01T15:17:04.551186Z","iopub.execute_input":"2024-09-01T15:17:04.551602Z","iopub.status.idle":"2024-09-01T15:17:04.875077Z","shell.execute_reply.started":"2024-09-01T15:17:04.551569Z","shell.execute_reply":"2024-09-01T15:17:04.874082Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def load_image(image_file):\n    '''load a image file'''\n    image = tf.io.read_file(image_file)\n    image = tf.io.decode_jpeg(image)\n    \n    return image\n\n\ndef random_crop(image):\n    '''randomly crop image into defined size '''\n    cropped_image = tf.image.random_crop(image, size=[CFG.IMG_HEIGHT, CFG.IMG_WIDTH, 3])\n\n    return cropped_image\n\n\ndef normalize(image):\n    '''normalizing the images to [-1, 1]'''\n    image = tf.cast(image, tf.float32)\n    image = (image / 127.5) - 1\n    return image\n\n\ndef de_normalize(image):\n    '''De normalize the image to be in range (0,1)'''\n    \n    return (image * 0.5) + 0.5\n    ","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2024-09-01T14:49:20.565345Z","iopub.execute_input":"2024-09-01T14:49:20.566379Z","iopub.status.idle":"2024-09-01T14:49:20.57394Z","shell.execute_reply.started":"2024-09-01T14:49:20.566337Z","shell.execute_reply":"2024-09-01T14:49:20.572939Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def image_augmentations(image):\n    '''perform spatial augmentations (rotation and flips) on input image\n    \n    from : https://www.kaggle.com/code/dimitreoliveira/improving-cyclegan-monet-paintings'''\n    \n    \n    # --------------------rotations----------\n    #rotation probabliity\n    p_rotate = tf.random.uniform([], 0, 1.0, dtype=tf.float32)\n    \n    if p_rotate > .8:\n        image = tf.image.rot90(image, k=3) # rotate 270º\n    elif p_rotate > .6:\n        image = tf.image.rot90(image, k=2) # rotate 180º\n    elif p_rotate > .4:\n        image = tf.image.rot90(image, k=1) # rotate 90º\n    \n    \n    \n    # ----------------------Flips---------------------\n    p_flip = tf.random.uniform([], 0, 1.0, dtype=tf.float32)\n    \n    if p_flip > 0.7:    \n        image = tf.image.random_flip_left_right(image)\n    elif p_flip < 0.3:\n        image = tf.image.random_flip_up_down(image)\n    \n    return image","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2024-09-01T14:49:26.502044Z","iopub.execute_input":"2024-09-01T14:49:26.502441Z","iopub.status.idle":"2024-09-01T14:49:26.511939Z","shell.execute_reply.started":"2024-09-01T14:49:26.502406Z","shell.execute_reply":"2024-09-01T14:49:26.510849Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def random_jitter(image):\n    '''resize and randommly crop the input image'''\n    \n#     # resizing image\n    image = tf.image.resize(image, size=(CFG.resize_height, CFG.resize_width),\n                          method=tf.image.ResizeMethod.NEAREST_NEIGHBOR)\n\n    # randomly cropping to 512,512\n    image = random_crop(image)\n    \n    return image\n\n\ndef preprocess_image_train(image):\n    image = load_image(image)\n    image = random_jitter(image)\n    image= image_augmentations(image)\n    image = normalize(image)\n    return image\n\n\n#same function, withou the augemntation\ndef preprocess_image_eval(image):\n    image = load_image(image)\n    image = random_jitter(image)\n    image = normalize(image)\n    return image\n\n","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2024-09-01T14:49:26.830879Z","iopub.execute_input":"2024-09-01T14:49:26.831296Z","iopub.status.idle":"2024-09-01T14:49:26.839457Z","shell.execute_reply.started":"2024-09-01T14:49:26.831259Z","shell.execute_reply":"2024-09-01T14:49:26.838335Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"\n\ndef create_img_dataset(directory,\n                       image_preprocess_fn,\n                       image_extension = 'jpg',         \n                       repeat=True\n                      ):\n    '''create a tf dataset object from a directory of images'''\n    img_list = glob(directory+f'/*{image_extension}')\n    \n    dataset = tf.data.Dataset.list_files(img_list)\n    \n    dataset = dataset.map(image_preprocess_fn,\n                          num_parallel_calls=tf.data.AUTOTUNE)\n    \n    if repeat :\n        dataset = dataset.repeat()\n              \n    dataset = dataset.shuffle(CFG.BUFFER_SIZE) \n    dataset = dataset.batch(CFG.BATCH_SIZE)\n    return dataset\n\n\nDay_Dataset = create_img_dataset(directory = day_dir,image_preprocess_fn = preprocess_image_train)\n\n#without augmentation\nDay_eval = create_img_dataset(directory = day_dir,\n                            image_preprocess_fn = preprocess_image_eval)\n\n\n\nfig,ax = plt.subplots(figsize=(16,8))\n    \ninp_img = next(iter(Day_Dataset))\nplt.imshow(de_normalize(inp_img[0]))\nplt.title('Sample Day image')\nplt.axis('off')\n\nplt.show()","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2024-09-01T15:18:07.35678Z","iopub.execute_input":"2024-09-01T15:18:07.357832Z","iopub.status.idle":"2024-09-01T15:18:07.411908Z","shell.execute_reply.started":"2024-09-01T15:18:07.357788Z","shell.execute_reply":"2024-09-01T15:18:07.410544Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"Night_Dataset = create_img_dataset(directory = night_dir,image_preprocess_fn = preprocess_image_train)\nNight_eval = create_img_dataset(directory = night_dir,\n                                image_preprocess_fn = preprocess_image_eval)\nfig,ax = plt.subplots(figsize=(16,8))\n\n\ninp_img = next(iter(Night_Dataset))\nplt.imshow(de_normalize(inp_img[0]))\nplt.title('Sample Night image')\nplt.axis('off')\n\nplt.show()\n","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2024-09-01T14:49:58.277047Z","iopub.execute_input":"2024-09-01T14:49:58.277866Z","iopub.status.idle":"2024-09-01T14:50:01.746904Z","shell.execute_reply.started":"2024-09-01T14:49:58.277819Z","shell.execute_reply":"2024-09-01T14:50:01.745985Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# train data set \n\nTrain_Dataset = tf.data.Dataset.zip((Day_Dataset,Night_Dataset))","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2024-09-01T14:50:06.741261Z","iopub.execute_input":"2024-09-01T14:50:06.741706Z","iopub.status.idle":"2024-09-01T14:50:06.747807Z","shell.execute_reply.started":"2024-09-01T14:50:06.741661Z","shell.execute_reply":"2024-09-01T14:50:06.746763Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<h2 style='color:green'> Building Model</h2>\n","metadata":{}},{"cell_type":"markdown","source":"**Upsampling and downsampling blocks**","metadata":{}},{"cell_type":"code","source":"\n#conv weights initilaizer\nconv_initializer = tf.random_normal_initializer(mean=0.0,\n                                                stddev=0.02)\n\n#init for intance normalization\ngamma_initializer = tf.keras.initializers.RandomNormal(mean=0.0, \n                                                       stddev=0.02)\n    \n    \n    \n    \ndef downsample(input_layer,\n               filters,\n               name,\n               size=3, \n               strides=2, \n               activation=tf.keras.layers.ReLU(), \n               ):\n    \n    '''perform a downsampling by applying a convolution,followed by instance norm and activation'''\n    conv = tf.keras.layers.Conv2D(filters, \n                                  size, \n                                  strides=strides, \n                                  padding='same', \n                                  use_bias=False, \n                                  kernel_initializer=conv_initializer, \n                                  name=f'encoder_{name}')(input_layer)\n\n    \n    conv = tfa.layers.InstanceNormalization(axis=-1,gamma_initializer=gamma_initializer)(conv)\n        \n    conv = activation(conv)\n\n    return conv\n\n\ndef upsample(input_layer,\n             filters,\n             name,\n             size=3,\n             strides=2,\n             activation='relu'):\n    \n    res = tf.keras.layers.Conv2DTranspose(filters, size, \n                                          strides=strides, \n                                          padding='same', \n                                          use_bias=False, \n                                          kernel_initializer=conv_initializer, \n                                          name=f'decoder_{name}')(input_layer)\n\n    res = tfa.layers.InstanceNormalization(gamma_initializer=gamma_initializer)(res)\n\n    res =  tf.keras.layers.Activation(activation)(res)\n    \n    return res","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2024-09-01T14:50:36.905802Z","iopub.execute_input":"2024-09-01T14:50:36.906811Z","iopub.status.idle":"2024-09-01T14:50:36.918734Z","shell.execute_reply.started":"2024-09-01T14:50:36.906771Z","shell.execute_reply":"2024-09-01T14:50:36.917668Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"**Residual block**","metadata":{}},{"cell_type":"code","source":"\ndef residual_block(input_layer, \n                   size=3, \n                   strides=1, \n                   name='block_x'):\n    '''performs 2 convolutions followed by an added skip connection with the input'''\n    \n    \n    filters = input_layer.shape[-1]\n    block = tf.keras.layers.Conv2D(filters, \n                     size,\n                     strides=strides,\n                     padding='same',\n                     use_bias=False, \n                     kernel_initializer=conv_initializer,\n                     name=f'residual_{name}')(input_layer)\n    \n    block = tf.keras.layers.Activation('relu')(block)\n    block = tf.keras.layers.Conv2D(filters, size, strides=strides, padding='same', use_bias=False, \n                     kernel_initializer=conv_initializer, name=f'transformer_{name}_2')(block)    \n    \n    #skip connection\n    res = tf.keras.layers.Add()([block, input_layer])\n\n    return res\n\n\ndef concat_layer(layer_1,layer_2,name):\n    '''concatenation of layers for skip connections'''\n    return tf.keras.layers.Concatenate(name=name)([layer_1,layer_2])\n","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2024-09-01T14:51:09.634219Z","iopub.execute_input":"2024-09-01T14:51:09.634977Z","iopub.status.idle":"2024-09-01T14:51:09.64424Z","shell.execute_reply.started":"2024-09-01T14:51:09.634932Z","shell.execute_reply":"2024-09-01T14:51:09.642941Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<h3 style='color:lightgreen'> Building Generator</h3>\n","metadata":{}},{"cell_type":"code","source":"def get_generator(num_residual_connections=6):\n    \n    input_ = tf.keras.layers.Input(shape=(CFG.IMG_WIDTH,CFG.IMG_HEIGHT,3), \n                                   name='input_layer')\n    \n    #-----------------------ENCODER-------------------------------\n    #downsample images \n    enc1 = downsample(input_layer = input_, filters=64,  strides =  1, size=7, name='dwn_1')    # (bs, 512,512, 64)\n    enc2 = downsample(input_layer=enc1,filters= 128,size =  3, strides =  2, name='dwn_2')      # (bs, 256, 256, 128)\n    enc3 = downsample(input_layer=enc2, filters=256,size =  3, strides =2, name='dwn_3')        # (bs, 128,128,256)\n    enc4 = downsample(input_layer=enc3, filters=256,size =  3, strides =2, name='dwn_4')        # (bs, 64,64,256)\n    \n    \n    #-----------------------Residual connections-------------------------------\n    x = enc4\n    for n in range(num_residual_connections):\n        x = residual_block(input_layer=x, name=f'res_block_{n+1}')     # (bs, 64, 64, 256)\n\n    #-----------------------DECODER-------------------------------\n    #UNET like skip connection \n    #upsample 1\n    x_skip = concat_layer(layer_1=x,layer_2=enc4,name='skip_1')               \n    dec1 = upsample(x_skip,filters=256 ,name='upsam_1')  # (bs, 128, 128, 256)\n    \n    #upsample 2\n    x_skip = concat_layer(layer_1=dec1,layer_2=enc3,name='skip_2')               \n    dec_2 = upsample(x_skip, filters=128,name='upsam_2') # (bs, 256, 256, 128)\n       \n    #upsample 3\n    x_skip = concat_layer(layer_1=dec_2,layer_2=enc2,name='skip_3')               \n    dec_3 = upsample(x_skip, filters= 64,name='upsam_3') # (bs, 512, 512, 64)\n    \n    #penultimate\n    x_skip = concat_layer(layer_1=dec_3,\n                          layer_2=enc1,\n                          name='skip_final')\n\n    output = tf.keras.layers.Conv2D(filters = 3,kernel_size = 7, strides=1, padding='same', \n                                  kernel_initializer=conv_initializer, use_bias=False, activation='tanh', \n                                  name='output_layer')(x_skip) \n\n    \n    return tf.keras.models.Model(inputs=input_,outputs=output)\n\n\n\n\n# day images -> night images \nday2night_gen = get_generator()\n\n# night images -> day images  \nnight2day_gen = get_generator()\n\n\n#plot model\n# tf.keras.utils.plot_model(day2night_gen)","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2024-09-01T14:51:17.159606Z","iopub.execute_input":"2024-09-01T14:51:17.160567Z","iopub.status.idle":"2024-09-01T14:51:18.432844Z","shell.execute_reply.started":"2024-09-01T14:51:17.160528Z","shell.execute_reply":"2024-09-01T14:51:18.432007Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#passing in a input to generator for check \n#plot a sample output\ngen_output = night2day_gen(inp_img, training=False)[0]\nplt.subplots(1,2,figsize=(16,8))\n\n\nplt.subplot(1,2,1)\nplt.imshow(gen_output.numpy().squeeze())\nplt.title('Untrained Night2Day Generator output')\nplt.axis('off')\n\n\nplt.subplot(1,2,2)\nplt.imshow(de_normalize(inp_img[0]))\nplt.title('Original Night image')\nplt.axis('off')\n\nplt.show()","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2024-09-01T14:51:22.195493Z","iopub.execute_input":"2024-09-01T14:51:22.195899Z","iopub.status.idle":"2024-09-01T14:51:29.630297Z","shell.execute_reply.started":"2024-09-01T14:51:22.195865Z","shell.execute_reply":"2024-09-01T14:51:29.629353Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<h3 style='color:green'> Building Discriminator</h3>\n","metadata":{}},{"cell_type":"code","source":"\n\ndef PATCH_discriminator(leak_rate = 0.2):\n    '''PATCH discriminator network'''\n    leaky_relu = tf.keras.layers.LeakyReLU(leak_rate)\n\n    \n    input_ = tf.keras.layers.Input(shape=(CFG.IMG_WIDTH,CFG.IMG_HEIGHT,3), \n                               name='input_layer')\n    # Encoder    \n    # Input image 512,512\n    x = downsample(input_layer = input_, filters=64,  strides =  2, size=4, name='dwn_1',activation = leaky_relu)    #h,w =256\n    x = downsample(input_layer = x, filters=128,  strides =  2, size=4, name='dwn_2',activation = leaky_relu)        #h,w =128\n    x = downsample(input_layer = x, filters=256,  strides =  2, size=4, name='dwn_3',activation = leaky_relu)        #h,w = 64\n    x = downsample(input_layer = x, filters=512,  strides =  2, size=4, name='dwn_4',activation = leaky_relu)        #h,w = 32\n    x = downsample(input_layer = x, filters=512,  strides =  1, size=4, name='dwn_5',activation = leaky_relu)        #h,w = 32\n    \n    \n    output = tf.keras.layers.Conv2D(1, 4, strides=1, padding='valid', kernel_initializer=conv_initializer)(x)         #(29, 29, 1)\n    \n    return tf.keras.models.Model(inputs=input_,outputs=output)\n\n\n\n#create instance of discriminators \nday2night_disc = PATCH_discriminator()  # identify night images\nnight2day_disc = PATCH_discriminator()  # identify day images\n","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2024-09-01T14:51:38.697744Z","iopub.execute_input":"2024-09-01T14:51:38.698819Z","iopub.status.idle":"2024-09-01T14:51:39.02194Z","shell.execute_reply.started":"2024-09-01T14:51:38.698775Z","shell.execute_reply":"2024-09-01T14:51:39.02088Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#check on dicriminator \n\ndisc_output = day2night_disc(inp_img, training=False)\nplt.subplots(1,1,figsize=(8,8))\n\nplt.imshow(disc_output.numpy().mean(axis=0),cmap='gray')\nplt.title('Untrained Night2Day disc output')\nplt.axis('off')\n\nplt.show()","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2024-09-01T14:51:44.249898Z","iopub.execute_input":"2024-09-01T14:51:44.250852Z","iopub.status.idle":"2024-09-01T14:51:44.489002Z","shell.execute_reply.started":"2024-09-01T14:51:44.250811Z","shell.execute_reply":"2024-09-01T14:51:44.487953Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def generate_cycle(gen_1,gen_2,input_image):\n    '''generate a full cycle of images using given generators'''\n    gen_img_1 = gen_1(input_image,training=True)\n    gen_img_2 = gen_2(gen_img_1,training=True)\n    \n    return gen_img_1,gen_img_2\n\n\ndef calc_and_apply_gradients(tape,\n                             model,\n                             loss,\n                             optimizer):\n    '''Apply gradients for a given model using given optimizer'''\n    \n    #calculate gradients of loss function\n    gradients = tape.gradient(loss,model.trainable_variables)\n    \n    #apply gradients \n    optimizer.apply_gradients(zip(gradients,model.trainable_variables))\n    return ","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2024-09-01T14:51:54.496342Z","iopub.execute_input":"2024-09-01T14:51:54.497192Z","iopub.status.idle":"2024-09-01T14:51:54.504136Z","shell.execute_reply.started":"2024-09-01T14:51:54.497152Z","shell.execute_reply":"2024-09-01T14:51:54.502868Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<h3 style='color:green' >losses </h3>","metadata":{}},{"cell_type":"code","source":"def discriminator_loss(real, generated):\n    '''discriminator Binary CrossEntropy loss'''\n    real_loss = tf.keras.losses.BinaryCrossentropy(from_logits=True)(tf.ones_like(real), real)\n\n    generated_loss = tf.keras.losses.BinaryCrossentropy(from_logits=True)(tf.zeros_like(generated), generated)\n\n    total_disc_loss = real_loss + generated_loss\n\n    return total_disc_loss * 0.5\n\n# Generator Adverserial loss\ndef generator_loss(generated):\n    '''adverserial generator loss (BCE)'''\n    return tf.keras.losses.BinaryCrossentropy(from_logits=True)(tf.ones_like(generated), generated)\n\n    \n# Cycle consistency loss \n    \ndef calc_cycle_loss(real_image, cycled_image, LAMBDA):\n    '''pixel wise cycle loss between original image and cycled image'''\n    mae_loss = tf.reduce_mean(tf.abs(real_image - cycled_image))\n\n    return LAMBDA * mae_loss\n\n\n# identity loss\ndef identity_loss(real_image, same_image, LAMBDA):    \n    mae_loss = tf.reduce_mean(tf.abs(real_image - same_image))\n    return LAMBDA * 0.5 * mae_loss","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2024-09-01T14:51:58.058021Z","iopub.execute_input":"2024-09-01T14:51:58.058928Z","iopub.status.idle":"2024-09-01T14:51:58.06789Z","shell.execute_reply.started":"2024-09-01T14:51:58.058895Z","shell.execute_reply":"2024-09-01T14:51:58.066883Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<h2 style='color:green'>Cycle GAN</h2>\n","metadata":{}},{"cell_type":"code","source":"class CycleGAN(tf.keras.models.Model):\n    def __init__(self,\n                 lambda_cycle=10):\n        super(CycleGAN, self).__init__()\n        self.gen_d2n = day2night_gen # Day -> Night \n        self.gen_n2d = night2day_gen # Night -> Day\n        self.disc_d2n = day2night_disc # Classifies Night Images\n        self.disc_n2d = night2day_disc # Classifier Day Images \n        self.lambda_cycle = lambda_cycle #lambda in cycle consistancy loss\n        \n        \n    \n    def compile(self,\n                gen_loss_fn,\n                disc_loss_fn,\n                cycle_loss_fn,\n                identity_loss_fn,\n                common_opt = tf.keras.optimizers.Adam(learning_rate = CFG.learning_rate,beta_1 = 0.5)):\n        \n        super(CycleGAN, self).compile()\n        \n        # -------optimizers ---------\n        self.opt_gen_d2n = common_opt\n        self.opt_gen_n2d = common_opt\n        self.opt_disc_d2n = common_opt\n        self.opt_disc_n2d = common_opt\n        \n        \n        # -------losses ---------\n        self.gen_loss_fn = gen_loss_fn\n        self.disc_loss_fn = disc_loss_fn\n        self.cycle_loss_fn = cycle_loss_fn\n        self.identity_loss_fn = identity_loss_fn\n        \n        \n    def train_step(self, batch_data):\n        day_image, night_image = batch_data\n        \n        with tf.GradientTape(persistent=True) as tape:\n            \n            #-----day->night->day\n            fake_night,cycled_day = generate_cycle(self.gen_d2n,\n                                                     self.gen_n2d,\n                                                     day_image)\n                 \n\n            # --------night -> day- > night\n            fake_day,cycled_night = generate_cycle(self.gen_n2d,\n                                                   self.gen_d2n,\n                                                   night_image)\n            \n            #---------- generating itself (for identity loss)\n            iden_day = self.gen_d2n(night_image, training=True)\n            iden_night = self.gen_n2d(day_image, training=True)\n\n            # -----------discriminator on real images\n            disc_night = self.disc_d2n(night_image, training=True)\n            disc_day = self.disc_n2d(day_image, training=True)\n\n            # -----------discriminator on fake images-----------------\n            disc_fake_night   = self.disc_d2n(fake_night, training=True)\n            disc_fake_day = self.disc_n2d(fake_day, training=True)\n\n            # -------------------------generator loss-------------\n               #---1)adverserial loss\n            night_gen_loss = self.gen_loss_fn(disc_fake_night) \n            day_gen_loss = self.gen_loss_fn(disc_fake_day)\n\n                #---2)Cycle loss loss\n            total_cycle_loss = self.cycle_loss_fn(night_image, cycled_night, self.lambda_cycle) + self.cycle_loss_fn(day_image, cycled_day, self.lambda_cycle)\n\n                # +++++3) Total Gen loss (day gen and night gen)\n            total_gen_d2n_loss = night_gen_loss + total_cycle_loss + self.identity_loss_fn(night_image, iden_night,self.lambda_cycle)\n            total_gen_n2d_loss = day_gen_loss + total_cycle_loss + self.identity_loss_fn(day_image, iden_day, self.lambda_cycle)\n            \n            \n            # -------------------------Discriminator loss-------------\n            night_disc_loss = self.disc_loss_fn(disc_night, disc_fake_night)  # check classifying generated and real night\n            day_disc_loss = self.disc_loss_fn(disc_day, disc_fake_day)        # check  classifying generated and real day\n\n        ## ------------------------- Calculating and Updating gradients------------------\n        \n        # day->night gen gradeints\n        _ = calc_and_apply_gradients(tape=tape,\n                                     model= self.gen_d2n,\n                                     loss = total_gen_d2n_loss,\n                                     optimizer = self.opt_gen_d2n)\n        \n        # night - >day  gen gradeints\n        _ = calc_and_apply_gradients(tape=tape,\n                                     model= self.gen_n2d,\n                                     loss = total_gen_n2d_loss,\n                                     optimizer = self.opt_gen_n2d)\n        \n        #  discrim gradients (classifies night images)\n        _ = calc_and_apply_gradients(tape=tape,\n                                     model= self.disc_d2n,\n                                     loss = night_disc_loss,\n                                     optimizer = self.opt_disc_d2n)\n        \n        # Day discrim gradients (classifies day images)\n        _ = calc_and_apply_gradients(tape=tape,\n                                     model= self.disc_n2d,\n                                     loss = day_disc_loss,\n                                     optimizer = self.opt_disc_n2d)\n        \n        \n        return {'gen_D2N_loss': total_gen_d2n_loss,\n                'gen_N2D_loss': total_gen_n2d_loss,\n                'disc_day_loss': day_disc_loss,\n                'disc_night_loss': night_disc_loss\n               }\n        \n    \n        ","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2024-09-01T14:53:36.080788Z","iopub.execute_input":"2024-09-01T14:53:36.081614Z","iopub.status.idle":"2024-09-01T14:53:36.103155Z","shell.execute_reply.started":"2024-09-01T14:53:36.081575Z","shell.execute_reply":"2024-09-01T14:53:36.101911Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#creat a instance of Cycle gan \ngan = CycleGAN()\n\n\n#complie with the losses \ngan.compile(gen_loss_fn=generator_loss,\n            disc_loss_fn=discriminator_loss,\n            cycle_loss_fn=calc_cycle_loss,\n            identity_loss_fn=identity_loss)","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2024-09-01T14:53:36.382404Z","iopub.execute_input":"2024-09-01T14:53:36.382739Z","iopub.status.idle":"2024-09-01T14:53:36.396609Z","shell.execute_reply.started":"2024-09-01T14:53:36.382711Z","shell.execute_reply":"2024-09-01T14:53:36.395605Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<h3 style='color:green'>Callbacks</h3>\n\n        For reducing Learning Rate,stopping training and Visulization","metadata":{}},{"cell_type":"code","source":"#learning rate schedule \n\ndef scheduler(epoch, \n              lr,\n              decay_rate = 0.05,\n              warm_up_period = 10):\n    \n    if epoch < warm_up_period:\n        return lr\n    elif (epoch > warm_up_period and epoch<40):\n        return lr * tf.math.exp(decay_rate)\n    else:\n        return lr * tf.math.exp(decay_rate*2)\n        \n    \n    \n    \nlr_scheduler = tf.keras.callbacks.LearningRateScheduler(scheduler,\n                                                        verbose = 0)\n\n\n#early stopping \n\n# early_stop = tf.keras.callbacks.EarlyStopping(monitor = 'gen_N2D_loss',\n#                                               mode = 'min',\n#                                               patience = 10,\n#                                              restore_best_weights = True)","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2024-09-01T14:53:54.311211Z","iopub.execute_input":"2024-09-01T14:53:54.311996Z","iopub.status.idle":"2024-09-01T14:53:54.319381Z","shell.execute_reply.started":"2024-09-01T14:53:54.311959Z","shell.execute_reply":"2024-09-01T14:53:54.318396Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# early stopping : from https://stackoverflow.com/questions/64556120/early-stopping-with-multiple-conditions\n\nclass CustomEarlyStopping(tf.keras.callbacks.Callback):\n    def __init__(self, patience=0):\n        super(CustomEarlyStopping, self).__init__()\n        self.patience = patience\n        self.best_weights = None\n        \n    def on_train_begin(self, logs=None):\n        \n        # The number of epoch it has waited when loss is no longer minimum.\n        self.wait = 0\n        # The epoch the training stops at.\n        self.stopped_epoch = 0\n        # Initialize the best as infinity.\n        self.n2d_loss = np.Inf\n        self.d2n_loss = np.Inf\n\n    def on_epoch_end(self, epoch, logs=None): \n        n2d_loss=logs.get('gen_N2D_loss')\n        d2n_loss=logs.get('gen_D2N_loss')\n\n        # If both the conditions are met, continue training\n        if (np.less(n2d_loss, self.n2d_loss) and np.less(d2n_loss, self.d2n_loss)):\n            self.d2n_loss = d2n_loss\n            self.n2d_loss = n2d_loss\n            self.wait = 0\n            # Record the best weights if current results is better (less).\n            self.best_weights = self.model.get_weights()\n            \n        # if above xondition not met, continue training till patiance epochs\n        else:\n            self.wait += 1\n            if self.wait >= self.patience:\n                self.stopped_epoch = epoch\n                self.model.stop_training = True\n                print(\"Restoring model weights from the end of the best epoch.\")\n                self.model.set_weights(self.best_weights)\n                \n    def on_train_end(self, logs=None):\n        if self.stopped_epoch > 0:\n            print(\"Epoch %05d: early stopping\" % (self.stopped_epoch + 1))\n","metadata":{"execution":{"iopub.status.busy":"2024-09-01T14:55:31.058347Z","iopub.execute_input":"2024-09-01T14:55:31.059661Z","iopub.status.idle":"2024-09-01T14:55:31.073014Z","shell.execute_reply.started":"2024-09-01T14:55:31.059586Z","shell.execute_reply":"2024-09-01T14:55:31.071706Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#--------------------------------------Viz Callbacks : from https://www.kaggle.com/code/dimitreoliveira/improving-cyclegan-monet-paintings -----------------------------------------\ndef display_samples(ds, n_samples):\n    ds_iter = iter(ds)\n    for n_sample in range(n_samples):\n        example_sample = next(ds_iter)\n        plt.subplot(121)\n        plt.imshow(example_sample[0] * 0.5 + 0.5)\n        plt.axis('off')\n        plt.show()\n        \ndef display_generated_samples(ds, model, n_samples):\n    ds_iter = iter(ds)\n    for n_sample in range(n_samples):\n        example_sample = next(ds_iter)\n        print(example_sample)\n        generated_sample = model.predict(example_sample)\n        \n        f = plt.figure(figsize=(16,8))\n        \n        plt.subplot(121)\n        plt.title('Input image')\n        plt.imshow(example_sample[0] * 0.5 + 0.5)\n        plt.axis('off')\n        \n        plt.subplot(122)\n        plt.title('Generated image')\n        plt.imshow(generated_sample[0] * 0.5 + 0.5)\n        plt.axis('off')\n        plt.show()\n        \ndef evaluate_cycle(ds, generator_a, generator_b, n_samples=1):\n    fig, axes = plt.subplots(n_samples, 3, figsize=(22, (n_samples*6)))\n    axes = axes.flatten()\n    \n    ds_iter = iter(ds)\n    for n_sample in range(n_samples):\n        idx = n_sample*3\n        example_sample = next(ds_iter)\n        generated_a_sample = generator_a.predict(example_sample)\n        generated_b_sample = generator_b.predict(generated_a_sample)\n        \n        axes[idx].set_title('Input image', fontsize=18)\n        axes[idx].imshow(example_sample[0] * 0.5 + 0.5)\n        axes[idx].axis('off')\n        \n        axes[idx+1].set_title('Generated image', fontsize=18)\n        axes[idx+1].imshow(generated_a_sample[0] * 0.5 + 0.5)\n        axes[idx+1].axis('off')\n        \n        axes[idx+2].set_title('Cycled image', fontsize=18)\n        axes[idx+2].imshow(generated_b_sample[0] * 0.5 + 0.5)\n        axes[idx+2].axis('off')\n        \n    plt.show()\n        \ndef predict_and_save(input_ds, generator_model, output_path):\n    i = 1\n    for img in input_ds:\n        prediction = generator_model(img, training=False)[0].numpy() # make predition\n        prediction = (prediction * 127.5 + 127.5).astype(np.uint8)   # re-scale\n        im = PIL.Image.fromarray(prediction)\n        im.save(f'{output_path}{str(i)}.jpg')\n        i += 1\n\n# Callback\nclass GANMonitor(tf.keras.callbacks.Callback):\n    \"\"\"A callback to generate and save images after each epoch\"\"\"\n\n    def __init__(self, \n                 num_img=1, \n                 day_paths='generated_day', \n                 night_paths='generated_night'):\n        self.num_img = num_img\n        self.day_paths = day_paths\n        self.night_paths = night_paths\n        \n        # dir to save genereated day images\n        if not os.path.exists(self.day_paths):\n            os.makedirs(self.day_paths)\n            \n            \n        # dir to save genereated night images\n        if not os.path.exists(self.night_paths):\n            os.makedirs(self.night_paths)\n\n            \n            \n    def on_epoch_end(self, epoch, logs=None):\n        #generated night \n        for i, img in enumerate(Day_eval.take(self.num_img)):\n            \n            \n            prediction = day2night_gen(img, training=False)[0].numpy()\n            prediction = (prediction * 127.5 + 127.5).astype(np.uint8)\n            prediction = PIL.Image.fromarray(prediction)\n            prediction.save(f'{self.night_paths}/generated_{i}_{epoch+1}.png')\n            \n        # generated day images \n        for i, img in enumerate(Night_eval.take(self.num_img)):\n            prediction = night2day_gen(img, training=False)[0].numpy()\n            prediction = (prediction * 127.5 + 127.5).astype(np.uint8)\n            prediction = PIL.Image.fromarray(prediction)\n            prediction.save(f'{self.day_paths}/generated_{i}_{epoch+1}.png')","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2024-09-01T14:55:58.564157Z","iopub.execute_input":"2024-09-01T14:55:58.564525Z","iopub.status.idle":"2024-09-01T14:55:58.591657Z","shell.execute_reply.started":"2024-09-01T14:55:58.564495Z","shell.execute_reply":"2024-09-01T14:55:58.590452Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"generated_sample = day2night_gen.predict('/kaggle/input/dataset-1/th.jpeg')","metadata":{"execution":{"iopub.status.busy":"2024-09-01T15:14:39.284925Z","iopub.execute_input":"2024-09-01T15:14:39.285838Z","iopub.status.idle":"2024-09-01T15:14:39.320837Z","shell.execute_reply.started":"2024-09-01T15:14:39.2858Z","shell.execute_reply":"2024-09-01T15:14:39.319578Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<h2 style='color:green'>Fitting the model</h2>\n","metadata":{}},{"cell_type":"code","source":"EPOCHS = 50\ncallbacks = [lr_scheduler,GANMonitor(),CustomEarlyStopping(patience = 10)]\ncheckpoint_callback = ModelCheckpoint(\n    filepath='/kaggle/working/model_checkpoint.h5',  # Path where to save the model\n    save_best_only=True,      # Save only the best model according to the monitored metric\n    monitor='loss',           # Metric to monitor, can also be 'val_loss' if using validation data\n    mode='min',               # Mode should be 'min' for loss (lower is better)\n    verbose=1                 # Verbosity mode, 1 will print messages when saving\n)\ncallbacks = [lr_scheduler, GANMonitor(), CustomEarlyStopping(patience=10), checkpoint_callback]\n\nsteps_per_epoch = 200\n\n\nhistory = gan.fit(Train_Dataset,\n                epochs = EPOCHS,\n                steps_per_epoch=steps_per_epoch,\n                callbacks = callbacks)","metadata":{"execution":{"iopub.status.busy":"2024-09-01T14:56:06.368169Z","iopub.execute_input":"2024-09-01T14:56:06.369015Z","iopub.status.idle":"2024-09-01T15:08:07.490006Z","shell.execute_reply.started":"2024-09-01T14:56:06.368971Z","shell.execute_reply":"2024-09-01T15:08:07.488468Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<h2 style='color:green'>Visualizing Training Progress</h2>","metadata":{}},{"cell_type":"markdown","source":"<h3 style='color:lightgreen'> Visualizing Training Progress for Night -> Day generator</h3>\n\n","metadata":{}},{"cell_type":"markdown","source":"<iframe src=\"./day.gif\" height=\"300\" \n        style=\"margin: 0 auto; width: 100%; max-width: 950px;\" frameborder=\"0\" scrolling=\"auto\" title=\"Training Progress - Day\"></iframe>","metadata":{}},{"cell_type":"markdown","source":"<h3 style='color:lightgreen'> Visualizing Training Progress for Day -> Night generator</h3>\n","metadata":{}},{"cell_type":"markdown","source":"<h1 style='color:green'>Results</h1>\n","metadata":{}},{"cell_type":"markdown","source":"<h2 style='color:lightgreen'>Evaluating Day -> Night Generator</h2>\n","metadata":{}},{"cell_type":"code","source":"display_generated_samples(Day_eval.take(1), day2night_gen, 1)","metadata":{"execution":{"iopub.status.busy":"2024-09-01T15:17:40.213247Z","iopub.execute_input":"2024-09-01T15:17:40.214148Z","iopub.status.idle":"2024-09-01T15:17:43.684792Z","shell.execute_reply.started":"2024-09-01T15:17:40.214106Z","shell.execute_reply":"2024-09-01T15:17:43.683922Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"display_generated_samples(Day_eval.take(2), day2night_gen, 2)","metadata":{"execution":{"iopub.status.busy":"2022-08-08T08:44:16.374076Z","iopub.execute_input":"2022-08-08T08:44:16.374502Z","iopub.status.idle":"2022-08-08T08:44:26.622378Z","shell.execute_reply.started":"2022-08-08T08:44:16.374456Z","shell.execute_reply":"2022-08-08T08:44:26.62136Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"display_generated_samples(Day_eval.take(2), day2night_gen, 2)","metadata":{"execution":{"iopub.status.busy":"2022-08-08T08:44:26.624615Z","iopub.execute_input":"2022-08-08T08:44:26.625095Z","iopub.status.idle":"2022-08-08T08:44:36.871876Z","shell.execute_reply.started":"2022-08-08T08:44:26.625056Z","shell.execute_reply":"2022-08-08T08:44:36.870856Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<h2 style='color:lightgreen'>Evaluating Night -> Day Generator</h2>\n","metadata":{}},{"cell_type":"code","source":"display_generated_samples(Night_eval.take(2), night2day_gen, 2)","metadata":{"execution":{"iopub.status.busy":"2022-08-08T08:44:36.874853Z","iopub.execute_input":"2022-08-08T08:44:36.875425Z","iopub.status.idle":"2022-08-08T08:44:47.121123Z","shell.execute_reply.started":"2022-08-08T08:44:36.875386Z","shell.execute_reply":"2022-08-08T08:44:47.120112Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"display_generated_samples(Night_eval.take(2), night2day_gen, 2)","metadata":{"execution":{"iopub.status.busy":"2022-08-08T08:44:47.12319Z","iopub.execute_input":"2022-08-08T08:44:47.12365Z","iopub.status.idle":"2022-08-08T08:44:53.313876Z","shell.execute_reply.started":"2022-08-08T08:44:47.123612Z","shell.execute_reply":"2022-08-08T08:44:53.312668Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"display_generated_samples(Night_eval.take(2), night2day_gen, 2)","metadata":{"execution":{"iopub.status.busy":"2022-08-08T08:44:53.315897Z","iopub.execute_input":"2022-08-08T08:44:53.316258Z","iopub.status.idle":"2022-08-08T08:44:59.780939Z","shell.execute_reply.started":"2022-08-08T08:44:53.316226Z","shell.execute_reply":"2022-08-08T08:44:59.779842Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<h2 style='color:lightgreen'>Evaluating Identity for Day to Night Generator so that Night -> Night </h2>\n","metadata":{}},{"cell_type":"code","source":"display_generated_samples(Night_eval.take(2), day2night_gen, 2)","metadata":{"execution":{"iopub.status.busy":"2022-08-08T08:44:59.783979Z","iopub.execute_input":"2022-08-08T08:44:59.784862Z","iopub.status.idle":"2022-08-08T08:45:06.361696Z","shell.execute_reply.started":"2022-08-08T08:44:59.784826Z","shell.execute_reply":"2022-08-08T08:45:06.360641Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"display_generated_samples(Night_eval.take(2), day2night_gen, 2)","metadata":{"execution":{"iopub.status.busy":"2022-08-08T08:45:06.363713Z","iopub.execute_input":"2022-08-08T08:45:06.364055Z","iopub.status.idle":"2022-08-08T08:45:16.60988Z","shell.execute_reply.started":"2022-08-08T08:45:06.364023Z","shell.execute_reply":"2022-08-08T08:45:16.608827Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"display_generated_samples(Night_eval.take(2), day2night_gen, 2)","metadata":{"execution":{"iopub.status.busy":"2022-08-08T08:45:16.617026Z","iopub.execute_input":"2022-08-08T08:45:16.617336Z","iopub.status.idle":"2022-08-08T08:45:26.860838Z","shell.execute_reply.started":"2022-08-08T08:45:16.617308Z","shell.execute_reply":"2022-08-08T08:45:26.859825Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<h2 style='color:lightgreen'>Evaluating Identity for Night to Day Generator so that Day -> Day </h2>\n","metadata":{}},{"cell_type":"code","source":"display_generated_samples(Day_eval.take(2), night2day_gen, 2)","metadata":{"execution":{"iopub.status.busy":"2022-08-08T08:45:50.670841Z","iopub.execute_input":"2022-08-08T08:45:50.671986Z","iopub.status.idle":"2022-08-08T08:46:00.916231Z","shell.execute_reply.started":"2022-08-08T08:45:50.671939Z","shell.execute_reply":"2022-08-08T08:46:00.915124Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"display_generated_samples(Day_eval.take(2), night2day_gen, 2)","metadata":{"execution":{"iopub.status.busy":"2022-08-08T08:46:00.923121Z","iopub.execute_input":"2022-08-08T08:46:00.923508Z","iopub.status.idle":"2022-08-08T08:46:06.708804Z","shell.execute_reply.started":"2022-08-08T08:46:00.92347Z","shell.execute_reply":"2022-08-08T08:46:06.707939Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"display_generated_samples(Day_eval.take(2), night2day_gen, 2)","metadata":{"execution":{"iopub.status.busy":"2022-08-08T08:46:06.710978Z","iopub.execute_input":"2022-08-08T08:46:06.711938Z","iopub.status.idle":"2022-08-08T08:46:12.018091Z","shell.execute_reply.started":"2022-08-08T08:46:06.711887Z","shell.execute_reply":"2022-08-08T08:46:12.016963Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<h2 style='color:lightgreen'>Cycle : Day(real image) -> Night -> Day</h2>\n","metadata":{}},{"cell_type":"code","source":"evaluate_cycle(Day_eval.take(2),\n               day2night_gen, \n               night2day_gen, \n               n_samples=2)","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2022-08-08T08:46:25.310537Z","iopub.execute_input":"2022-08-08T08:46:25.310901Z","iopub.status.idle":"2022-08-08T08:46:35.629665Z","shell.execute_reply.started":"2022-08-08T08:46:25.310872Z","shell.execute_reply":"2022-08-08T08:46:35.628609Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"evaluate_cycle(Day_eval.take(2),\n               day2night_gen, \n               night2day_gen, \n               n_samples=2)","metadata":{"execution":{"iopub.status.busy":"2022-08-08T08:46:35.632105Z","iopub.execute_input":"2022-08-08T08:46:35.632517Z","iopub.status.idle":"2022-08-08T08:46:45.979577Z","shell.execute_reply.started":"2022-08-08T08:46:35.632478Z","shell.execute_reply":"2022-08-08T08:46:45.978568Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<h2 style='color:lightgreen'>Cycle : Day(real image) -> Night -> Day</h2>\n","metadata":{}},{"cell_type":"code","source":"evaluate_cycle(Night_eval.take(2),\n               night2day_gen, \n               day2night_gen, \n               n_samples=2)\n","metadata":{"execution":{"iopub.status.busy":"2022-08-08T08:46:45.981235Z","iopub.execute_input":"2022-08-08T08:46:45.982157Z","iopub.status.idle":"2022-08-08T08:46:56.298274Z","shell.execute_reply.started":"2022-08-08T08:46:45.982118Z","shell.execute_reply":"2022-08-08T08:46:56.297136Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"evaluate_cycle(Night_eval.take(2),\n               night2day_gen, \n               day2night_gen, \n               n_samples=2)","metadata":{"execution":{"iopub.status.busy":"2022-08-08T08:46:56.301072Z","iopub.execute_input":"2022-08-08T08:46:56.301472Z","iopub.status.idle":"2022-08-08T08:47:03.046101Z","shell.execute_reply.started":"2022-08-08T08:46:56.301435Z","shell.execute_reply":"2022-08-08T08:47:03.045041Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# References and Resources \n\n* https://www.cs.cmu.edu/~junyanz/projects/CycleGAN/CycleGAN.pdf\n* https://www.tensorflow.org/tutorials/generative/cyclegan\n* https://www.kaggle.com/code/dimitreoliveira/improving-cyclegan-monet-paintings\n","metadata":{}}]}