{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"pygments_lexer":"ipython3","nbconvert_exporter":"python","version":"3.6.4","file_extension":".py","codemirror_mode":{"name":"ipython","version":3},"name":"python","mimetype":"text/x-python"}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"<h2 style='color:green'> Imports </h2>\n","metadata":{}},{"cell_type":"code","source":"\n\nimport os\nimport pathlib\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":"2023-04-28T08:14:55.797665Z","iopub.execute_input":"2023-04-28T08:14:55.798084Z","iopub.status.idle":"2023-04-28T08:15:02.210271Z","shell.execute_reply.started":"2023-04-28T08:14:55.797995Z","shell.execute_reply":"2023-04-28T08:15:02.209203Z"},"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":"2023-04-28T08:15:02.212392Z","iopub.execute_input":"2023-04-28T08:15:02.213043Z","iopub.status.idle":"2023-04-28T08:15:02.221172Z","shell.execute_reply.started":"2023-04-28T08:15:02.213010Z","shell.execute_reply":"2023-04-28T08:15:02.220137Z"},"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 = '../input/daynight-cityview/day'\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":"2023-04-28T08:15:02.223997Z","iopub.execute_input":"2023-04-28T08:15:02.225262Z","iopub.status.idle":"2023-04-28T08:15:02.931410Z","shell.execute_reply.started":"2023-04-28T08:15:02.225218Z","shell.execute_reply":"2023-04-28T08:15:02.930274Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<h2 style='color:green'> building data loading pipeline </h2>\n","metadata":{}},{"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":"2023-04-28T08:15:02.933477Z","iopub.execute_input":"2023-04-28T08:15:02.933896Z","iopub.status.idle":"2023-04-28T08:15:02.942758Z","shell.execute_reply.started":"2023-04-28T08:15:02.933863Z","shell.execute_reply":"2023-04-28T08:15:02.941912Z"},"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":"2023-04-28T08:15:02.944162Z","iopub.execute_input":"2023-04-28T08:15:02.944680Z","iopub.status.idle":"2023-04-28T08:15:03.098378Z","shell.execute_reply.started":"2023-04-28T08:15:02.944648Z","shell.execute_reply":"2023-04-28T08:15:03.097313Z"},"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":"2023-04-28T08:15:03.099820Z","iopub.execute_input":"2023-04-28T08:15:03.100312Z","iopub.status.idle":"2023-04-28T08:15:03.110949Z","shell.execute_reply.started":"2023-04-28T08:15:03.100267Z","shell.execute_reply":"2023-04-28T08:15:03.110080Z"},"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":"2023-04-28T08:15:03.116878Z","iopub.execute_input":"2023-04-28T08:15:03.118550Z","iopub.status.idle":"2023-04-28T08:15:14.172113Z","shell.execute_reply.started":"2023-04-28T08:15:03.118511Z","shell.execute_reply":"2023-04-28T08:15:14.171253Z"},"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":"2023-04-28T08:15:14.173385Z","iopub.execute_input":"2023-04-28T08:15:14.174145Z","iopub.status.idle":"2023-04-28T08:15:20.016721Z","shell.execute_reply.started":"2023-04-28T08:15:14.174089Z","shell.execute_reply":"2023-04-28T08:15:20.015885Z"},"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":"2023-04-28T08:15:20.017946Z","iopub.execute_input":"2023-04-28T08:15:20.018789Z","iopub.status.idle":"2023-04-28T08:15:20.025810Z","shell.execute_reply.started":"2023-04-28T08:15:20.018749Z","shell.execute_reply":"2023-04-28T08:15:20.025062Z"},"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":"2023-04-28T08:15:20.027667Z","iopub.execute_input":"2023-04-28T08:15:20.028091Z","iopub.status.idle":"2023-04-28T08:15:20.058313Z","shell.execute_reply.started":"2023-04-28T08:15:20.028055Z","shell.execute_reply":"2023-04-28T08:15:20.057461Z"},"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":"2023-04-28T08:15:20.063297Z","iopub.execute_input":"2023-04-28T08:15:20.063603Z","iopub.status.idle":"2023-04-28T08:15:20.072650Z","shell.execute_reply.started":"2023-04-28T08:15:20.063578Z","shell.execute_reply":"2023-04-28T08:15:20.071629Z"},"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":"2023-04-28T08:15:20.074032Z","iopub.execute_input":"2023-04-28T08:15:20.074807Z","iopub.status.idle":"2023-04-28T08:15:21.108480Z","shell.execute_reply.started":"2023-04-28T08:15:20.074770Z","shell.execute_reply":"2023-04-28T08:15:21.107510Z"},"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":"2023-04-28T08:15:21.110136Z","iopub.execute_input":"2023-04-28T08:15:21.110565Z","iopub.status.idle":"2023-04-28T08:15:28.893659Z","shell.execute_reply.started":"2023-04-28T08:15:21.110525Z","shell.execute_reply":"2023-04-28T08:15:28.892835Z"},"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":"2023-04-28T08:15:28.894983Z","iopub.execute_input":"2023-04-28T08:15:28.896364Z","iopub.status.idle":"2023-04-28T08:15:29.194616Z","shell.execute_reply.started":"2023-04-28T08:15:28.896326Z","shell.execute_reply":"2023-04-28T08:15:29.193648Z"},"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":"2023-04-28T08:15:29.195977Z","iopub.execute_input":"2023-04-28T08:15:29.196977Z","iopub.status.idle":"2023-04-28T08:15:29.475973Z","shell.execute_reply.started":"2023-04-28T08:15:29.196920Z","shell.execute_reply":"2023-04-28T08:15:29.474511Z"},"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":"2023-04-28T08:15:29.483125Z","iopub.execute_input":"2023-04-28T08:15:29.487328Z","iopub.status.idle":"2023-04-28T08:15:29.494793Z","shell.execute_reply.started":"2023-04-28T08:15:29.487266Z","shell.execute_reply":"2023-04-28T08:15:29.493918Z"},"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":"2023-04-28T08:15:29.498082Z","iopub.execute_input":"2023-04-28T08:15:29.498848Z","iopub.status.idle":"2023-04-28T08:15:29.509366Z","shell.execute_reply.started":"2023-04-28T08:15:29.498804Z","shell.execute_reply":"2023-04-28T08:15:29.508587Z"},"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":"2023-04-28T08:15:29.511332Z","iopub.execute_input":"2023-04-28T08:15:29.512061Z","iopub.status.idle":"2023-04-28T08:15:29.534869Z","shell.execute_reply.started":"2023-04-28T08:15:29.512021Z","shell.execute_reply":"2023-04-28T08:15:29.533824Z"},"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":"2023-04-28T08:15:29.536306Z","iopub.execute_input":"2023-04-28T08:15:29.537063Z","iopub.status.idle":"2023-04-28T08:15:29.565883Z","shell.execute_reply.started":"2023-04-28T08:15:29.537023Z","shell.execute_reply":"2023-04-28T08:15:29.564772Z"},"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":"2023-04-28T08:15:29.567259Z","iopub.execute_input":"2023-04-28T08:15:29.567894Z","iopub.status.idle":"2023-04-28T08:15:29.575436Z","shell.execute_reply.started":"2023-04-28T08:15:29.567858Z","shell.execute_reply":"2023-04-28T08:15:29.574341Z"},"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":"2023-04-28T08:15:29.577109Z","iopub.execute_input":"2023-04-28T08:15:29.577829Z","iopub.status.idle":"2023-04-28T08:15:29.591207Z","shell.execute_reply.started":"2023-04-28T08:15:29.577793Z","shell.execute_reply":"2023-04-28T08:15:29.590140Z"},"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        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":"2023-04-28T08:15:29.593130Z","iopub.execute_input":"2023-04-28T08:15:29.593942Z","iopub.status.idle":"2023-04-28T08:15:29.622476Z","shell.execute_reply.started":"2023-04-28T08:15:29.593904Z","shell.execute_reply":"2023-04-28T08:15:29.621479Z"},"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 = 75\ncallbacks = [lr_scheduler,GANMonitor(),CustomEarlyStopping(patience = 10)]\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":"2023-04-28T08:15:29.624191Z","iopub.execute_input":"2023-04-28T08:15:29.625041Z","iopub.status.idle":"2023-04-28T10:04:20.876112Z","shell.execute_reply.started":"2023-04-28T08:15:29.625003Z","shell.execute_reply":"2023-04-28T10:04:20.875028Z"},"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":"code","source":"\n\n# from https://www.kaggle.com/code/dimitreoliveira/improving-cyclegan-monet-paintings\ndef create_gif(images_path, gif_path):\n    images = []\n    filenames = glob(images_path)\n    filenames.sort(key=lambda x: int(''.join(filter(str.isdigit, x))))\n    for epoch, filename in enumerate(filenames):\n        img = PIL.ImageDraw.Image.open(filename)\n        ImageDraw.Draw(img).text((0, 0),  # Coordinates\n                                 f'Epoch {epoch+1}')\n        images.append(img)\n    imageio.mimsave(gif_path, images, fps=2) # Save gif\n    \n    \n    \ncreate_gif('./generated_day/*.png', 'day.gif')\n\nprint('Training progress for Night -> Day Generator')\ndisplay.Image('./day.gif')","metadata":{"execution":{"iopub.status.busy":"2023-04-28T10:04:20.877569Z","iopub.execute_input":"2023-04-28T10:04:20.878243Z","iopub.status.idle":"2023-04-28T10:05:21.477422Z","shell.execute_reply.started":"2023-04-28T10:04:20.878204Z","shell.execute_reply":"2023-04-28T10:05:21.476112Z"},"trusted":true},"execution_count":null,"outputs":[]},{"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":"code","source":"create_gif('./generated_night/*.png', 'night.gif')\n\n\nprint('Training progress for Day-> Generator')\ndisplay.Image('./night.gif')","metadata":{"execution":{"iopub.status.busy":"2023-04-28T10:05:21.479670Z","iopub.execute_input":"2023-04-28T10:05:21.480570Z","iopub.status.idle":"2023-04-28T10:05:24.964812Z","shell.execute_reply.started":"2023-04-28T10:05:21.480527Z","shell.execute_reply":"2023-04-28T10:05:24.962022Z"},"trusted":true},"execution_count":null,"outputs":[]},{"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(2), day2night_gen, 2)","metadata":{"execution":{"iopub.status.busy":"2023-04-28T10:05:24.966707Z","iopub.execute_input":"2023-04-28T10:05:24.967497Z","iopub.status.idle":"2023-04-28T10:05:31.428369Z","shell.execute_reply.started":"2023-04-28T10:05:24.967445Z","shell.execute_reply":"2023-04-28T10:05:31.427222Z"},"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":"2023-04-28T10:05:31.430399Z","iopub.execute_input":"2023-04-28T10:05:31.430975Z","iopub.status.idle":"2023-04-28T10:05:37.247188Z","shell.execute_reply.started":"2023-04-28T10:05:31.430924Z","shell.execute_reply":"2023-04-28T10:05:37.246111Z"},"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":"2023-04-28T10:05:37.249526Z","iopub.execute_input":"2023-04-28T10:05:37.250005Z","iopub.status.idle":"2023-04-28T10:05:47.490393Z","shell.execute_reply.started":"2023-04-28T10:05:37.249944Z","shell.execute_reply":"2023-04-28T10:05:47.489274Z"},"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":"2023-04-28T10:05:47.492583Z","iopub.execute_input":"2023-04-28T10:05:47.493073Z","iopub.status.idle":"2023-04-28T10:05:53.743231Z","shell.execute_reply.started":"2023-04-28T10:05:47.493037Z","shell.execute_reply":"2023-04-28T10:05:53.742264Z"},"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":"2023-04-28T10:05:53.744984Z","iopub.execute_input":"2023-04-28T10:05:53.745680Z","iopub.status.idle":"2023-04-28T10:06:03.989705Z","shell.execute_reply.started":"2023-04-28T10:05:53.745645Z","shell.execute_reply":"2023-04-28T10:06:03.988670Z"},"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":"2023-04-28T10:06:03.992032Z","iopub.execute_input":"2023-04-28T10:06:03.992720Z","iopub.status.idle":"2023-04-28T10:06:14.236502Z","shell.execute_reply.started":"2023-04-28T10:06:03.992681Z","shell.execute_reply":"2023-04-28T10:06:14.235442Z"},"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":"2023-04-28T10:06:14.243547Z","iopub.execute_input":"2023-04-28T10:06:14.243855Z","iopub.status.idle":"2023-04-28T10:06:24.488090Z","shell.execute_reply.started":"2023-04-28T10:06:14.243829Z","shell.execute_reply":"2023-04-28T10:06:24.486919Z"},"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":"2023-04-28T10:06:24.490677Z","iopub.execute_input":"2023-04-28T10:06:24.491616Z","iopub.status.idle":"2023-04-28T10:06:34.736752Z","shell.execute_reply.started":"2023-04-28T10:06:24.491573Z","shell.execute_reply":"2023-04-28T10:06:34.735674Z"},"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":"2023-04-28T10:06:34.739864Z","iopub.execute_input":"2023-04-28T10:06:34.740571Z","iopub.status.idle":"2023-04-28T10:06:44.983525Z","shell.execute_reply.started":"2023-04-28T10:06:34.740533Z","shell.execute_reply":"2023-04-28T10:06:44.982486Z"},"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":"2023-04-28T10:06:44.986895Z","iopub.execute_input":"2023-04-28T10:06:44.987284Z","iopub.status.idle":"2023-04-28T10:06:55.230702Z","shell.execute_reply.started":"2023-04-28T10:06:44.987254Z","shell.execute_reply":"2023-04-28T10:06:55.229598Z"},"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":"2023-04-28T10:06:55.233012Z","iopub.execute_input":"2023-04-28T10:06:55.233632Z","iopub.status.idle":"2023-04-28T10:07:05.480133Z","shell.execute_reply.started":"2023-04-28T10:06:55.233591Z","shell.execute_reply":"2023-04-28T10:07:05.478982Z"},"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":"2023-04-28T10:07:05.482186Z","iopub.execute_input":"2023-04-28T10:07:05.482883Z","iopub.status.idle":"2023-04-28T10:07:11.558897Z","shell.execute_reply.started":"2023-04-28T10:07:05.482844Z","shell.execute_reply":"2023-04-28T10:07:11.558040Z"},"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":"2023-04-28T10:07:11.560950Z","iopub.execute_input":"2023-04-28T10:07:11.561772Z","iopub.status.idle":"2023-04-28T10:07:17.968647Z","shell.execute_reply.started":"2023-04-28T10:07:11.561734Z","shell.execute_reply":"2023-04-28T10:07:17.967705Z"},"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":"2023-04-28T10:07:17.970632Z","iopub.execute_input":"2023-04-28T10:07:17.971475Z","iopub.status.idle":"2023-04-28T10:07:24.728742Z","shell.execute_reply.started":"2023-04-28T10:07:17.971438Z","shell.execute_reply":"2023-04-28T10:07:24.727320Z"},"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":"2023-04-28T10:07:24.731107Z","iopub.execute_input":"2023-04-28T10:07:24.731551Z","iopub.status.idle":"2023-04-28T10:07:35.053704Z","shell.execute_reply.started":"2023-04-28T10:07:24.731514Z","shell.execute_reply":"2023-04-28T10:07:35.052664Z"},"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":"2023-04-28T10:07:35.055816Z","iopub.execute_input":"2023-04-28T10:07:35.056550Z","iopub.status.idle":"2023-04-28T10:07:41.536506Z","shell.execute_reply.started":"2023-04-28T10:07:35.056510Z","shell.execute_reply":"2023-04-28T10:07:41.535415Z"},"trusted":true},"execution_count":null,"outputs":[]}]}