{"metadata":{"kernelspec":{"name":"python3","display_name":"Python 3","language":"python"},"language_info":{"name":"python","version":"3.10.13","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"colab":{"provenance":[],"machine_shape":"hm","gpuType":"V28"},"accelerator":"TPU","kaggle":{"accelerator":"none","dataSources":[{"sourceId":21755,"databundleVersionId":1475600,"sourceType":"competition"}],"dockerImageVersionId":30698,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":false}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"#**Advanced topics in Deep Learning**","metadata":{"id":"trKVlOrklCyk"}},{"cell_type":"markdown","source":"#**Name and ID:**\nTal Teri: 319123543\n\nYehuda Daniel: 211789680\n\nChen Shalev: 313584906\n\nIlan Brilovich: 322525072\n\nLin Tibi: 318232139\n","metadata":{"id":"t9P3pPgzhdLW"}},{"cell_type":"markdown","source":"#Kaggle Monet-cycleGan","metadata":{"id":"70b315f6-fd89-46c6-9065-bda418e66655"}},{"cell_type":"markdown","source":"Imports","metadata":{"id":"ppXRRuGaMhyp"}},{"cell_type":"code","source":"# Install packages\n!pip install seaborn\n!pip install tensorflow","metadata":{"execution":{"iopub.status.busy":"2024-05-02T21:43:51.613956Z","iopub.execute_input":"2024-05-02T21:43:51.614432Z","iopub.status.idle":"2024-05-02T21:44:37.072511Z","shell.execute_reply.started":"2024-05-02T21:43:51.614399Z","shell.execute_reply":"2024-05-02T21:44:37.071299Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import os, re, logging, warnings, functools, json\nimport tensorflow as tf\nfrom tensorflow import keras\nimport matplotlib.pyplot as plt\nimport matplotlib.colors as colors\nimport matplotlib\nimport numpy as np\nimport pandas as pd\nimport seaborn as sns\nimport random\n\nfrom tensorflow import GradientTape\n\nimport keras\nfrom keras.models import Sequential\nfrom keras.layers import (Dense, Conv2D, BatchNormalization, Dropout, Flatten, LeakyReLU,ReLU,\n                          Input, Conv2DTranspose, Concatenate, GroupNormalization, GaussianNoise, ZeroPadding2D)\nfrom sklearn.metrics import classification_report, confusion_matrix, accuracy_score\n\nimport cv2","metadata":{"id":"2Dryn0DmMgQX","execution":{"iopub.status.busy":"2024-05-02T21:48:19.641208Z","iopub.execute_input":"2024-05-02T21:48:19.641706Z","iopub.status.idle":"2024-05-02T21:48:19.927400Z","shell.execute_reply.started":"2024-05-02T21:48:19.641666Z","shell.execute_reply":"2024-05-02T21:48:19.926460Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Checking for TPU","metadata":{"id":"VgzuOPEGXaB-"}},{"cell_type":"code","source":"#Configuring TPU\ntry:\n  resolver = tf.distribute.cluster_resolver.TPUClusterResolver()\nexcept ValueError:\n  print(\"TPU not found. Using default strategy (may be slower).\")\n  resolver = None\n\nif resolver:\n  tf.config.experimental_connect_to_cluster(resolver)\n  tf.tpu.experimental.initialize_tpu_system(resolver)\n  strategy = tf.distribute.TPUStrategy(resolver)\nelse:\n  strategy = tf.distribute.get_strategy()","metadata":{"id":"Ss3YlCEaXbJh","execution":{"iopub.status.busy":"2024-05-02T21:48:26.229609Z","iopub.execute_input":"2024-05-02T21:48:26.230037Z","iopub.status.idle":"2024-05-02T21:48:26.245873Z","shell.execute_reply.started":"2024-05-02T21:48:26.230007Z","shell.execute_reply":"2024-05-02T21:48:26.244562Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Installing Kaggle","metadata":{"id":"Subip92ENHYQ"}},{"cell_type":"markdown","source":"##Loading the data","metadata":{"id":"NeCamduhOSu0"}},{"cell_type":"code","source":"AUTO = tf.data.experimental.AUTOTUNE\n\nmonet_files = tf.io.gfile.glob('/kaggle/input/gan-getting-started/monet_tfrec/*.tfrec')\nphotos_files = tf.io.gfile.glob('/kaggle/input/gan-getting-started/photo_tfrec/*.tfrec')\n\n#function for counting the number of photos\ndef photos_counter(files):\n  n = [int(re.compile(r\"-([0-9]*)\\.\").search(filename).group(1)) for filename in files]\n  return np.sum(n)\n\nmonet_len = photos_counter(monet_files)\nphotos_len = photos_counter(photos_files)\n\nprint(f'Monet TFRecords: {len(monet_files)}')\nprint(f'Monet images: {monet_len}')\nprint(f'Photo TFRecords: {len(photos_files)}')\nprint(f'Photo images: {photos_len}')","metadata":{"id":"6gqPB25MOUxF","outputId":"65b0e36a-5997-4b03-acd9-2d7e13aa7c0c","execution":{"iopub.status.busy":"2024-05-02T21:50:37.103672Z","iopub.execute_input":"2024-05-02T21:50:37.104218Z","iopub.status.idle":"2024-05-02T21:50:37.134195Z","shell.execute_reply.started":"2024-05-02T21:50:37.104179Z","shell.execute_reply":"2024-05-02T21:50:37.133066Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Normalizing the decoded images from the TFRecords files to be between [-1, 1], this will give us better results for cycleGAN\n","metadata":{"id":"jPn9RMKWUpnV"}},{"cell_type":"code","source":"def img_decoder(img):\n  img = tf.image.decode_jpeg(img, channels=3)\n  img = (tf.cast(img, tf.float32) / 127.5) - 1\n  img = tf.reshape(img, [256, 256, 3])\n  return img\n\ndef read_tfrecord(example):\n  format = {\n      'image_name': tf.io.FixedLenFeature([], tf.string),\n      'image': tf.io.FixedLenFeature([], tf.string),\n      'target': tf.io.FixedLenFeature([], tf.string)\n  }\n  example = tf.io.parse_single_example(example, format)\n  img = img_decoder(example['image'])\n  return img","metadata":{"id":"QjemsDSsVo1j","execution":{"iopub.status.busy":"2024-05-02T21:50:50.381562Z","iopub.execute_input":"2024-05-02T21:50:50.381946Z","iopub.status.idle":"2024-05-02T21:50:50.390945Z","shell.execute_reply.started":"2024-05-02T21:50:50.381917Z","shell.execute_reply":"2024-05-02T21:50:50.389541Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Extracting the images from the TFrecords files","metadata":{"id":"2seJSDOTPhhe"}},{"cell_type":"code","source":"def img_extractor(files):\n  data_set = tf.data.TFRecordDataset(files) #will recieve all the tfrecords files and return a dataset\n  data_set = data_set.map(read_tfrecord) #for every object in the data_set will activate read_tfrecord on it, which will return img\n  return data_set #will return all the images, extracted from the tfrecord files","metadata":{"id":"minO4NzsPmY3","execution":{"iopub.status.busy":"2024-05-02T21:50:57.558792Z","iopub.execute_input":"2024-05-02T21:50:57.559280Z","iopub.status.idle":"2024-05-02T21:50:57.565993Z","shell.execute_reply.started":"2024-05-02T21:50:57.559244Z","shell.execute_reply":"2024-05-02T21:50:57.564507Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Loading the datasets","metadata":{"id":"5Ge-c7CHSteS"}},{"cell_type":"code","source":"monet_data = img_extractor(monet_files).batch(1)\nphotos_data = img_extractor(photos_files).batch(1)","metadata":{"id":"NPmcCkguSs8m","execution":{"iopub.status.busy":"2024-05-02T21:50:59.331392Z","iopub.execute_input":"2024-05-02T21:50:59.331829Z","iopub.status.idle":"2024-05-02T21:50:59.615919Z","shell.execute_reply.started":"2024-05-02T21:50:59.331793Z","shell.execute_reply":"2024-05-02T21:50:59.614994Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"##Presenting images from the dataset","metadata":{"id":"WMlPLuaMiKrs"}},{"cell_type":"markdown","source":"Visualizing 18 samples, 9 are monet samples, and 9 are photo samples.","metadata":{"id":"YcKfmbObdGeo"}},{"cell_type":"code","source":"def present_sammples(files):\n  fig, axes = plt.subplots(3, 3, figsize=(7, 7))\n  for i in range(3):\n    for j in range(3):\n      index = i * 3 + j\n      if index < len(files):\n        img = files[index]*0.5+0.5\n        img = np.squeeze(img)\n        axes[i, j].imshow(img)\n        axes[i, j].axis('off')\n      else:\n        axes[i, j].axis('off')\n\n  plt.tight_layout()\n  plt.show()","metadata":{"id":"Gx_dLCQ4foiZ","execution":{"iopub.status.busy":"2024-05-02T21:51:02.130258Z","iopub.execute_input":"2024-05-02T21:51:02.130657Z","iopub.status.idle":"2024-05-02T21:51:02.141767Z","shell.execute_reply.started":"2024-05-02T21:51:02.130627Z","shell.execute_reply":"2024-05-02T21:51:02.139974Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"present_sammples(next(iter(monet_data.batch(9))))","metadata":{"id":"J5nfYofWc0Bl","outputId":"434338d1-000e-4f61-d406-6867743ac5bd","execution":{"iopub.status.busy":"2024-05-02T21:51:04.557630Z","iopub.execute_input":"2024-05-02T21:51:04.558063Z","iopub.status.idle":"2024-05-02T21:51:05.652854Z","shell.execute_reply.started":"2024-05-02T21:51:04.558032Z","shell.execute_reply":"2024-05-02T21:51:05.650055Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"present_sammples(next(iter(photos_data.batch(9))))","metadata":{"id":"jhZSLZ7mhKyG","outputId":"599c6afe-f5e0-42c1-84bc-19c804bef29b","execution":{"iopub.status.busy":"2024-05-02T21:51:10.745231Z","iopub.execute_input":"2024-05-02T21:51:10.745723Z","iopub.status.idle":"2024-05-02T21:51:11.720830Z","shell.execute_reply.started":"2024-05-02T21:51:10.745689Z","shell.execute_reply":"2024-05-02T21:51:11.719379Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"###Presenting The Color Channels","metadata":{"id":"0z9A9AuIHch-"}},{"cell_type":"code","source":"#function for creating and displaying a histogram for each image sample\ndef display_image_channels(file_path, num_samples=1, title=''):\n  files_names = os.listdir(file_path)\n  chosen_file_names = np.random.choice(files_names, size=num_samples)\n\n  fig, axes = plt.subplots(2*num_samples, 4, figsize=(20, 8*num_samples))\n\n  for i, fileName in enumerate(chosen_file_names):\n    sample_image_path = os.path.join(file_path, fileName)\n    decodedImage = cv2.imread(sample_image_path)\n    decodedImage = cv2.cvtColor(decodedImage, cv2.COLOR_BGR2RGB)\n\n    axes[i*2][0].imshow(decodedImage)\n    axes[i*2][0].axis(\"off\")\n    axes[i*2][0].set_title(f'{title} {i+1}', color=\"#3737ff\")\n\n    for j in range(3):\n      #extract an array from individual color channels and convery to 1D Array\n      image_channels = decodedImage[:, :, j].reshape(-1)\n      axes[i*2][j+1].hist(image_channels, bins=256, color=['#ad2004', '#007446', '#13358f'][j], alpha=0.3)\n      axes[i*2][j+1].set_title(f'{title} {i+1}', color='#3737ff')\n\n      #Gray scale image\n      axes[i*2+1][0].imshow(np.mean(decodedImage, axis=2), cmap='gray')\n      axes[i*2+1][0].set_title(f'{title} {i+1}', color='#3737ff')\n\n      #red, green, blue channels\n      for k in range(3):\n        image_chan = np.full_like(decodedImage, 0)\n        image_chan[:, :, k] = decodedImage[:, :, k]\n        axes[i*2+1][k+1].imshow(image_chan)\n        axes[i*2+1][k+1].set_title(f'{title} {i+1}', color='#3737ff')\n\n  plt.show()","metadata":{"id":"hjPfGv1DHivE","execution":{"iopub.status.busy":"2024-05-02T21:51:17.718145Z","iopub.execute_input":"2024-05-02T21:51:17.718824Z","iopub.status.idle":"2024-05-02T21:51:17.734377Z","shell.execute_reply.started":"2024-05-02T21:51:17.718782Z","shell.execute_reply":"2024-05-02T21:51:17.733050Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"####Displaying Monet Histogram with 2 samples","metadata":{"id":"90sSFWf7Rj6N"}},{"cell_type":"code","source":"display_image_channels(file_path='/kaggle/input/gan-getting-started/monet_jpg', num_samples=2, title=\"Monet\")","metadata":{"id":"YuQZpXzROgm3","outputId":"52342090-2814-4715-d92c-64e169d1f1ef","execution":{"iopub.status.busy":"2024-05-02T21:52:13.571518Z","iopub.execute_input":"2024-05-02T21:52:13.572064Z","iopub.status.idle":"2024-05-02T21:52:21.383041Z","shell.execute_reply.started":"2024-05-02T21:52:13.572028Z","shell.execute_reply":"2024-05-02T21:52:21.381629Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"","metadata":{"id":"jTOB34lgRwuL"}},{"cell_type":"markdown","source":"####Displaying Photo Histogram with 2 samples","metadata":{"id":"30xXdxfaRyWJ"}},{"cell_type":"code","source":"display_image_channels(file_path='/kaggle/input/gan-getting-started/photo_jpg', num_samples=2, title=\"Monet\")","metadata":{"id":"BXzY0cNARyWL","outputId":"87fc5fac-f7a8-4bb6-f822-f107700df41d","execution":{"iopub.status.busy":"2024-05-02T21:53:01.977848Z","iopub.execute_input":"2024-05-02T21:53:01.978324Z","iopub.status.idle":"2024-05-02T21:53:13.327363Z","shell.execute_reply.started":"2024-05-02T21:53:01.978289Z","shell.execute_reply":"2024-05-02T21:53:13.326036Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"##Data Augmentation","metadata":{"id":"L6_OEe0mk-Bf"}},{"cell_type":"markdown","source":"Using Data augmentation for GANs should be done with more considerations.\nIf we apply transformations which will alter the style of the image too much(such as: brightness, contrast, saturation etc) it will cause our generator to unefficiently learn the style.\nWe will be using on spatial transformations (flips, rotates, crops etc)","metadata":{"id":"OxDka3TVlDfQ"}},{"cell_type":"markdown","source":"###Rotation Augmentation","metadata":{"id":"ZE3myNYAbty7"}},{"cell_type":"code","source":"def image_rotation(image):\n  try:\n    #Defining the rotation angles\n    rotation_angles = tf.constant([0, 1, 2, 3], dtype=tf.int32) #0, 90, 180, 270 degrees (jumps of 90 deg)\n\n    #choosing one rotation randomly\n    shuffle = tf.random.shuffle(rotation_angles)\n    rotation_angle = shuffle[0]\n\n    #Rotate with the chosen angle\n    image = tf.image.rot90(image, k=rotation_angle)\n  except Exception as e:\n    print(\"Error in image rotation:\", e)\n  return image","metadata":{"id":"tnzVRvYqa6th"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"###Flip Augmentation","metadata":{"id":"s4Nbr6Egbx28"}},{"cell_type":"code","source":"def image_flip(image):\n  try:\n    return tf.image.random_flip_left_right(tf.image.random_flip_up_down(image))\n  except Exception as e:\n    print(\"Error in image flip:\", e)\n  return image","metadata":{"id":"PBTpd_YSb0is"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"###Transpose Augmentation","metadata":{"id":"XCTisQFacNaH"}},{"cell_type":"code","source":"def image_transpose(image):\n  try:\n    return tf.image.transpose(image)\n  except Exception as e:\n    print(\"Error in image transpose:\", e)\n  return image","metadata":{"id":"oNtA5XhncQmU"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"###Crop Augmentation","metadata":{"id":"ruZDjlPbcYDQ"}},{"cell_type":"code","source":"def image_crop(image, height=256, width=256):\n  try:\n    return tf.image.random_crop(image, size=[height, width, 3])\n  except Exception as e:\n    print(\"Error in image crop:\", e)\n  return image","metadata":{"id":"XjKoUY8Tca8j"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"##Applying Augmentation","metadata":{"id":"DdrN8iOndQpy"}},{"cell_type":"code","source":"def apply_aug(filenames, labeled=True, ordered=False, repeat=False, shuffle=False,\n              rotation=False, flip=False, transpose=False, crop=False, height=256, width=256):\n  dataset = tf.data.TFRecordDataset(filenames)\n  dataset = dataset.map(read_tfrecord, num_parallel_calls=AUTO)\n\n  if repeat: #used for number of epochs\n    dataset = dataset.repeat()\n  if shuffle:\n    dataset = dataset.shuffle(512)\n  if rotation:\n    dataset = dataset.map(image_rotation, num_parallel_calls=AUTO)\n  if flip:\n    dataset = dataset.map(image_flip, num_parallel_calls=AUTO)\n  if transpose:\n    dataset = dataset.map(image_transpose, num_parallel_calls=AUTO)\n  if crop:\n    crop_function = functools.partial(image_crop, height=height, width=width)\n    dataset = dataset.map(crop_function, num_parallel_calls=AUTO)\n\n  #When the GPU processes a batch, we will use the CPU to load the next batch ahead of use\n  dataset = dataset.prefetch(AUTO)\n\n  return dataset","metadata":{"id":"bkl8m9PndT2D"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"####Loading the Data","metadata":{"id":"ISptVkXmhIH8"}},{"cell_type":"code","source":"monetData = apply_aug(monet_files, labeled = True).batch(1)\nphotosData = apply_aug(photos_files, labeled = True).batch(1)","metadata":{"id":"_gfvIgedhMwX"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"##Building the Generator","metadata":{"id":"9zdHZbRWktMi"}},{"cell_type":"markdown","source":"###Downsampling - Used for gathering features.","metadata":{"id":"P8FWYpC_qoa9"}},{"cell_type":"code","source":"def downsample(filters, size, stride = 2, padding = 'same', apply_instancenorm=True):\n  #initializing weights to filters - creating random tensor of weights around the given\n  #mean, with margins of standard deviation.\n  init = tf.random_normal_initializer(0., 0.02)\n\n  #initialzing instance normazilation - Initializing two different initializers for\n  #future scaling and improving of the initializers\n  inst_init = keras.initializers.RandomNormal(mean = 0.0, stddev = 0.02)\n\n  layer = keras.Sequential()\n  layer.add(Conv2D(filters,\n                   size,\n                   strides = stride,\n                   padding = padding,\n                   kernel_initializer = init,\n                   use_bias=False))\n\n  if apply_instancenorm:\n    #GroupNormalization with -1 = for calculating the mean and sd, we run over\n    #the layers created by the filters (=channels).\n    #for each channel we run over every pixel in that channel (=feature map) and calculate\n    #accordingly. mean = μ(x, y, c) = (1 / W * H) * Σ( v(i, j, c) )\n    #standard deviation = σ²(x, y, c) = (1 / W * H) * Σ( (v(i, j, c) - μ(x, y, c))^2 )\n    layer.add(GroupNormalization(groups = -1, gamma_initializer = inst_init))\n  layer.add(LeakyReLU()) #Using leaky for negative values\n  return layer\n\n","metadata":{"id":"EU0Y-GW2hjTW"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"###Upsampling - Using the features to reconstruct the image.","metadata":{"id":"ksn1yA0mrEdO"}},{"cell_type":"code","source":"def upsample(filters, size, stride = 2, padding = 'same', apply_dropout=False, dropout_rate = 0.5):\n  init = tf.random_normal_initializer(0., 0.02)\n\n  inst_init = keras.initializers.RandomNormal(mean = 0.0, stddev = 0.02)\n\n  layer = keras.Sequential()\n  layer.add(Conv2DTranspose(filters,\n                   size,\n                   strides = stride,\n                   padding = padding,\n                   kernel_initializer = init,\n                   use_bias=False))\n\n  layer.add(GroupNormalization(groups = -1, gamma_initializer = inst_init))\n\n  if apply_dropout:\n    layer.add(Dropout(dropout_rate))\n\n  layer.add(ReLU())\n\n  return layer","metadata":{"id":"Tg7GxxZSrSxm"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"###Generator","metadata":{"id":"WhSdAOxaxloM"}},{"cell_type":"code","source":"def generator_builder(dropout_rate = 0.5, filter_size_L1 = 4, filters_size = 4, filters_L1 = 64, transfer_layers= 5, stride = 2, padding = 'same'):\n  inputs = Input(shape=[256, 256, 3])\n\n  # Encoder\n  downsample_layers=[\n      downsample(filters = filters_L1, size = filter_size_L1, stride = stride, padding = padding, apply_instancenorm=False), #IMG(128,128)\n      downsample(filters = filters_L1*2, size = filters_size, stride = stride, padding = padding), #IMG(64,64)\n      downsample(filters = filters_L1*2**2, size = filters_size, stride = stride, padding = padding), #IMG(32,32)\n  ]\n\n  downsample_layers += [\n      downsample(filters = filters_L1*2**2, size = filters_size, stride = stride, padding = padding)\n      for i in range(transfer_layers)\n  ]\n  # --------\n\n  upsample_layers=[]\n\n  upsample_layers += [\n      upsample(filters = filters_L1*2**2, size = filters_size, stride = stride, padding = padding, apply_dropout = True, dropout_rate = dropout_rate)\n      for i in range(transfer_layers - 1)\n  ]\n\n  upsample_layers.extend([\n      upsample(filters = filters_L1*2**2, size = filters_size, stride = stride, padding = padding),\n      upsample(filters = filters_L1*2**2, size = filters_size, stride = stride, padding = padding),\n      upsample(filters = filters_L1*2, size = filters_size, stride = stride, padding = padding),\n      upsample(filters = filters_L1, size = filters_size, stride = stride, padding = padding),\n  ])\n\n  final_init = tf.random_normal_initializer(0., 0.02)\n\n\n\n  final_layer = Conv2DTranspose(3, filter_size_L1, strides=stride, padding=padding, activation='tanh')\n\n  x = inputs\n  skips = []\n  for layer in downsample_layers:\n    x = layer(x)\n    skips.append(x)\n\n  skips = reversed(skips[:-1])\n\n\n  for layer, skip in zip(upsample_layers, skips):\n    x = layer(x)\n    x = Concatenate()([x, skip])\n\n  x = final_layer(x)\n\n  model = keras.Model(inputs=inputs, outputs=x)\n\n  return model","metadata":{"id":"B7zAuAL7xnsN"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"###Running the Generators","metadata":{"id":"inR41KtAlWbr"}},{"cell_type":"code","source":"with strategy.scope():\n  monet_gen = generator_builder() #Default parameters\n\n  photos_gen = generator_builder() #Default parameters\n\nprint('Generators Summary\\n')\nmonet_gen.summary()\n\n#applying the generators on the images\nphotoIter = next(iter(photosData))\nphoto2monet = monet_gen(photoIter)\n\nmonetIter = next(iter(monetData))\nmonet2photo = photos_gen(monetIter)\n\n#Plotting the results of the two generators\nplt.figure(figsize=(15, 2))\nplt.subplot(1, 4, 1)\nplt.title(\"Original Photo\")\nplt.imshow(photoIter[0] * 0.5 + 0.5)\n\nplt.subplot(1, 4, 2)\nplt.title(\"Generator G: converted photo to monet\")\nplt.imshow(photo2monet[0] * 0.5 + 0.5)\n\n\nplt.subplot(1, 4, 3)\nplt.title(\"Original Monet\")\nplt.imshow(monetIter[0] * 0.5 + 0.5)\n\nplt.subplot(1, 4, 4)\nplt.title(\"Generator F: converted monet to real photo\")\nplt.imshow(monet2photo[0] * 0.5 + 0.5)\nplt.show()","metadata":{"id":"X_yUbmKRlYZN","outputId":"8e8bbc87-85f0-4775-b602-993d1cbe9dc8"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"##Building the Discriminator","metadata":{"id":"2m4GfTfztdvY"}},{"cell_type":"code","source":"def discriminator_builder(filter_size = 4, filters_L1 = 64, downsample_layers_num=3, stride = 1):\n  init = tf.random_normal_initializer(0, 0.02)\n  inst_init = keras.initializers.RandomNormal(mean=0.0, stddev=0.02)\n\n  input = Input(shape=[256, 256, 3], name='input_layer')\n  x=input\n\n  noise = GaussianNoise(0.001)(input)\n  x = Concatenate()([x, noise])\n\n  downsample_layers = []\n\n  for i in range(downsample_layers_num):\n    filters = filters_L1 * (2**i)\n    if i==0:\n      downsample_layers.append(downsample(filters, size=filter_size, apply_instancenorm=False))\n    else:\n      downsample_layers.append(downsample(filters, size=filter_size))\n\n  for layer in downsample_layers:\n    x = layer(x)\n\n  padding = ZeroPadding2D()(x)\n  convLayer = Conv2D(filters_L1 * (2** (downsample_layers_num)), filter_size, strides=stride, kernel_initializer=init, use_bias=False)(padding)\n  normalize = GroupNormalization(groups=-1, gamma_initializer=inst_init)(convLayer)\n  leaky_relu = LeakyReLU()(normalize)\n\n  padding2 = ZeroPadding2D()(leaky_relu)\n  finalLayer = Conv2D(1, filter_size, strides=1, kernel_initializer=init)(padding2)\n\n  return keras.Model(inputs=input, outputs=finalLayer)","metadata":{"id":"ehq_rZw5tho0"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"##Building The CycleGan","metadata":{"id":"mm-hdj244yLd"}},{"cell_type":"code","source":"class CycleGan(keras.Model): #The class will inherit from keras.Model\n  def __init__(\n      self,\n      monet_gen,\n      photos_gen,\n      monet_dis,\n      photos_dis,\n      lambda_cycle=10,\n      buffer_size=50\n  ):\n    super(CycleGan, self).__init__() #Initializes the superclass, keras.Model\n\n    self.monetGen = monet_gen\n    self.photosGen = photos_gen\n    self.monetDis = monet_dis\n    self.photosDis = photos_dis\n    self.lambda_cycle = lambda_cycle\n    self.buffer_size = buffer_size\n\n  #defining the needed optimizers and loss functions for compiling the model\n  def compile(\n      self,\n      monetOptimizer,\n      photosOptimizer,\n      mDisOptimizer,\n      pDisOptimizer,\n      genLossFunc,\n      disLossFunc,\n      cycleLossFunc,\n      idLossFunc\n  ):\n    super(CycleGan, self).compile() #calling the compile method of keras.Model\n\n    self.monetOptimizer = monetOptimizer\n    self.photosOptimizer = photosOptimizer\n    self.mDisOptimizer = mDisOptimizer\n    self.pDisOptimizer = pDisOptimizer\n    self.genLossFunc = genLossFunc\n    self.disLossFunc = disLossFunc\n    self.cycleLossFunc = cycleLossFunc\n    self.idLossFunc = idLossFunc\n\n\n  def train_step(self, batch_data):\n    real_monet, real_photos = batch_data\n\n    #We will be using GradientTape which allows to compute the gradients during our training and to be used\n    #in the backpropagation process.\n    with GradientTape(persistent = True) as tape:\n      #---------------------------#\n      #    Forward Propagation    #\n      #---------------------------#\n\n      #------------ Generators G and F generating the images -----------#\n      #generates fake monet images and cycle the fake results back to regular photo\n      fakeMonet = self.monetGen(real_photos, training = True)\n      cycledPhotos = self.photosGen(fakeMonet, training = True)\n\n      #generate fake phots from monet pictures and cycle the fake results back to monet\n      fakePhotos = self.photosGen(real_monet, training = True)\n      cycledMonet = self.monetGen(fakeMonet, training = True)\n\n      #generate identity outputs (monet to monet, photo to photo)\n      idMonet = self.monetGen(real_monet, training = True)\n      idPhotos = self.photosGen(real_photos, training = True)\n\n      #--------------------------#\n      #      Discriminator       #\n      #--------------------------#\n\n      #send real images to discriminator for training\n      disRealMonet = self.monetDis(real_monet, training = True)\n      disRealPhotos = self.photosDis(real_photos, training = True)\n\n      #send fake images to discriminator\n      disFakeMonet = self.monetDis(fakeMonet, training = True)\n      disFakePhotos = self.photosDis(fakePhotos, training = True)\n\n      #-------------------------#\n      #    Back Propagation     #\n      #-------------------------#\n\n      #------- Loss Function --------#\n      #We want the generators to send fake images to the corresponding discriminator and think they are real\n      #Giving the loss function what the discriminator thought about the photo given to it.\n      monetGenLoss = self.genLossFunc(disFakeMonet)\n      photosGenLoss = self.genLossFunc(disFakePhotos)\n\n      #Checking if the cycled photos looks like their original.\n      cycleLoss = self.cycleLossFunc(real_monet, cycledMonet, self.lambda_cycle) + self.cycleLossFunc(real_photos, cycledPhotos, self.lambda_cycle)\n\n      #loss of the generators with the identity\n      totalMonetGenLoss = monetGenLoss + cycleLoss + self.idLossFunc(real_monet, idMonet, self.lambda_cycle)\n      totalPhotosGenLoss = photosGenLoss + cycleLoss + self.idLossFunc(real_photos, idPhotos, self.lambda_cycle)\n\n      #Loss of the discriminators\n      monetDisLoss = self.disLossFunc(disRealMonet, disFakeMonet)\n      photosDisLoss = self.disLossFunc(disRealPhotos, disFakePhotos)\n\n    #updating generator gradient\n    monetGenGradients = tape.gradient(totalMonetGenLoss, self.monetGen.trainable_variables)\n    photosGenGradients = tape.gradient(totalPhotosGenLoss, self.photosGen.trainable_variables)\n\n    #updating discriminator gradient\n    monetDisGradients = tape.gradient(monetDisLoss, self.monetDis.trainable_variables)\n    photosDisGradients = tape.gradient(photosDisLoss, self.photosDis.trainable_variables)\n\n    #Updating the parameters of generators and discriminators\n    self.monetOptimizer.apply_gradients(zip(monetGenGradients, self.monetGen.trainable_variables))\n    self.photosOptimizer.apply_gradients(zip(photosGenGradients, self.photosGen.trainable_variables))\n\n    self.mDisOptimizer.apply_gradients(zip(monetDisGradients, self.monetDis.trainable_variables))\n    self.mDisOptimizer.apply_gradients(zip(photosDisGradients, self.photosDis.trainable_variables))\n\n\n    return {\n        'monetGenLoss': totalMonetGenLoss,\n        'photosGenLoss': totalPhotosGenLoss,\n        'monetDisLoss': monetDisLoss,\n        'photosDisLoss': photosDisLoss,\n        'cycleLoss': cycleLoss,\n    }\n\n","metadata":{"id":"B3QG56vy432T"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"###Loss Functions","metadata":{"id":"B9wxq-8ouvE7"}},{"cell_type":"code","source":"with strategy.scope():\n  def discriminator_loss(real, fake):\n    real_loss = keras.losses.BinaryCrossentropy(from_logits=True, reduction=keras.losses.Reduction.NONE)(tf.ones_like(real), real)\n\n    generated_loss = keras.losses.BinaryCrossentropy(from_logits=True, reduction=keras.losses.Reduction.NONE)(tf.zeros_like(fake), fake)\n\n    totalDisLoss = real_loss + generated_loss\n\n    return totalDisLoss * 0.5 #Return the average sum of totalDisLoss\n\nwith strategy.scope():\n  def generator_loss(fake):\n    return keras.losses.BinaryCrossentropy(from_logits=True, reduction=keras.losses.Reduction.NONE)(tf.ones_like(fake), fake)\n\n\nwith strategy.scope():\n  def cycle_loss(real_image, cycled_image, Lambda):\n    loss = tf.reduce_mean(tf.abs(real_image - cycled_image)) #The difference between the real image and the cycled real image will give us the differences\n\n    return Lambda * loss\n\nwith strategy.scope():\n  def identity_loss(real_image, id_image, Lambda):\n    loss = tf.reduce_mean(real_image - id_image)\n\n    return Lambda * loss * 0.5\n\n\n\n","metadata":{"id":"ZNcvffrKuwdW"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"##Helper Function","metadata":{"id":"XkYZIBK96OuX"}},{"cell_type":"code","source":"# plot adversary, cycle losses\ndef plotting(history):\n    # Calculate mean losses\n    mean_monetGen_loss = np.mean(history['monetGenLoss'], axis=(1, 2, 3))\n    mean_photosGenLoss = np.mean(history['photosGenLoss'], axis=(1, 2, 3))\n    mean_monetDisLoss = np.mean(history['monetDisLoss'], axis=(1, 2, 3))\n    mean_photosDisLoss = np.mean(history['photosDisLoss'], axis=(1, 2, 3))\n\n\n    # Plotting the losses\n    epochs = range(1, len(mean_monetGen_loss) + 1)\n\n    plt.figure(figsize=(12, 5))\n    plt.plot(epochs, mean_monetGen_loss, 'b', label='Monet Gen Loss')\n    plt.plot(epochs, mean_photosGenLoss, 'r', label='Photo Gen Loss')\n    plt.plot(epochs, mean_monetDisLoss, 'g', label='Monet Disc Loss')\n    plt.plot(epochs, mean_photosDisLoss, 'y', label='Photo Disc Loss')\n    plt.plot(epochs, history['cycleLoss'], 'm', label='Cycle Loss')  # Added total cycle loss\n    plt.title('CycleGAN Training Losses')\n    plt.xlabel('Epochs')\n    plt.ylabel('Mean Loss')\n    plt.legend(loc='upper right')\n    plt.show()\n\n# Plot generated Monet-style photos\ndef visualizing(photos_data, monet_generator, photo_generator, num_images=5):\n    fig, ax = plt.subplots( num_images, 3, figsize=(12*3, 12*num_images))\n    fake_monet_features = []\n    real_monet_features = []\n\n    #for i, photo in enumerate(photo_data.take(num_images)):\n    total_images = len(list(photos_data))\n    random_indices = random.sample(range(total_images), num_images)\n\n    for i, idx in enumerate(random_indices):\n        photo = next(iter(photos_data.skip(idx).take(1)))\n        photo_monet = monet_generator(photo, training=False)\n        cycle_photo = photo_generator(photo_monet, training=False)\n        photo_monet = photo_monet[0].numpy()\n        photo_monet = (photo_monet * 127.5 + 127.5).astype(np.uint8)\n        cycle_photo = cycle_photo[0].numpy()\n        cycle_photo = (cycle_photo * 127.5 + 127.5).astype(np.uint8)\n        photo = (photo[0] * 127.5 + 127.5).numpy().astype(np.uint8)\n\n\n        ax[i, 0].imshow(photo)\n        ax[i, 1].imshow(photo_monet)\n        ax[i, 2].imshow(cycle_photo)\n\n        ax[i, 0].set_title(\"Input Photo\")\n        ax[i, 1].set_title(\"Monet-style Photo\")\n        ax[i, 2].set_title(\"Cycled Photo\")\n        ax[i, 0].axis(\"off\")\n        ax[i, 1].axis(\"off\")\n        ax[i, 2].axis(\"off\")\n\n    plt.show()","metadata":{"id":"qAQSoqSi6Qa_"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"##Training 1 - Base Model","metadata":{"id":"xOf-zws11OiC"}},{"cell_type":"markdown","source":"Parameters","metadata":{"id":"Yb4AoS401S1K"}},{"cell_type":"code","source":"EPOCHS = 5\nBATCH_SIZE= 1\nNUM_MONET_PHOTOS = 300 #we got this from part 1 of this notebook. No need to change\nLEARNING_RATE = 0.0001\nBETA_1 = 0.8\nLAMBDA = 10\nBUFFER_SIZE = 50\nDROPOUT_RATE_GEN = 0\nTRANSFER_LAYERS_GEN = 3\nSTRIDE_NUM_GEN, STRIDE_NUM_DIS = 2,1\nPADDING_GEN ='same'\nFILTER_SIZE_GEN, FILTER_SIZE_DIS = 2, 2\nFILTER_SIZE_L1_GEN = 2\nFILTER_L1_GEN ,FILTER_L1_DIS = 32,32\nDOWNSAMPLE_LAYER_NUM_DIS= 2","metadata":{"id":"SDfGG32f1QWy"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Building the generators and discriminators","metadata":{"id":"vw9KSQBt25_f"}},{"cell_type":"code","source":"with strategy.scope():\n  #----------------#\n  #   Generators   #\n  #----------------#\n\n  monet_generator = generator_builder(dropout_rate = DROPOUT_RATE_GEN, filter_size_L1 = FILTER_SIZE_L1_GEN, filters_size = FILTER_SIZE_GEN, filters_L1 = FILTER_L1_GEN,\n                                      transfer_layers= TRANSFER_LAYERS_GEN, stride = STRIDE_NUM_GEN, padding = PADDING_GEN)\n\n  photos_generator = generator_builder(dropout_rate = DROPOUT_RATE_GEN, filter_size_L1 = FILTER_SIZE_L1_GEN, filters_size = FILTER_SIZE_GEN, filters_L1 = FILTER_L1_GEN,\n                                      transfer_layers= TRANSFER_LAYERS_GEN, stride = STRIDE_NUM_GEN, padding = PADDING_GEN)\n\n  #------------------#\n  #  Discriminators  #\n  #------------------#\n\n  monet_discriminator = discriminator_builder(filter_size = FILTER_SIZE_DIS, filters_L1 = FILTER_L1_DIS, downsample_layers_num=DOWNSAMPLE_LAYER_NUM_DIS, stride = STRIDE_NUM_DIS)\n\n  photos_discriminator = discriminator_builder(filter_size = FILTER_SIZE_DIS, filters_L1 = FILTER_L1_DIS, downsample_layers_num=DOWNSAMPLE_LAYER_NUM_DIS, stride = STRIDE_NUM_DIS)\n\n  #----------------#\n  #   Optimizers   #\n  #----------------#\n\n  monetGen_optimizer = keras.optimizers.legacy.SGD(learning_rate=LEARNING_RATE, momentum=BETA_1)\n\n  photosGen_optimizer = keras.optimizers.legacy.SGD(learning_rate=LEARNING_RATE, momentum=BETA_1)\n\n  monetDis_optimizer = keras.optimizers.legacy.SGD(learning_rate=LEARNING_RATE, momentum=BETA_1)\n\n  photosDis_optimizer = keras.optimizers.legacy.SGD(learning_rate=LEARNING_RATE, momentum=BETA_1)\n","metadata":{"id":"nrh5zT0o27qK"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Creating the CycleGan instance","metadata":{"id":"ZacMB-0z5cqC"}},{"cell_type":"code","source":"with strategy.scope():\n  cycleGan = CycleGan(\n      monet_generator, photos_generator, monet_discriminator, photos_discriminator, lambda_cycle=LAMBDA, buffer_size=BUFFER_SIZE\n  )\n\n  cycleGan.compile(\n        monetOptimizer = monetGen_optimizer,\n        photosOptimizer = photosGen_optimizer,\n        mDisOptimizer = monetDis_optimizer,\n        pDisOptimizer = photosDis_optimizer,\n        genLossFunc = generator_loss,\n        disLossFunc = discriminator_loss,\n        cycleLossFunc = cycle_loss,\n        idLossFunc = identity_loss\n  )","metadata":{"id":"p8ic9vWH5fBD"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"monet_generator.summary()\n\nphotos_discriminator.summary()","metadata":{"id":"3x_1WB-f5U0M","outputId":"9b57678c-60ba-4ae7-e7aa-7a8bbf43e847"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"###Training\n","metadata":{"id":"k_lHv3376SPD"}},{"cell_type":"code","source":"history = cycleGan.fit(\n    tf.data.Dataset.zip((monetData, photosData)),\n    epochs=EPOCHS,\n    batch_size=BATCH_SIZE,\n)","metadata":{"id":"1Z7W6iY_IU5_","outputId":"4f162458-4cdf-43ea-b913-42f2b65959db"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Plot the loss","metadata":{"id":"bsceFH4P7ACp"}},{"cell_type":"code","source":"print(\"Monet Generator Loss shape:\", np.array(history.history['monetGenLoss']).shape)\nprint(\"Monet Discriminator Loss shape:\", np.array(history.history['monetDisLoss']).shape)\nprint(\"Monet total cycle Loss:\", history.history['cycleLoss'])","metadata":{"id":"oqf6u9kihNvr","outputId":"29a7da36-753e-4eb3-e328-f1ae7ac370a4"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plotting(history.history)","metadata":{"id":"6bUpj-MKmqAB","outputId":"e423ebd1-dc69-46db-8324-d192dd11ff8d"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"###Visualization Result","metadata":{"id":"C5lpPTz79Cww"}},{"cell_type":"markdown","source":"Displaying the images as a cycle:\nOriginal | Monet | Cycled back to Original","metadata":{"id":"8iVzKOfO8cc6"}},{"cell_type":"code","source":"visualizing(photosData, monet_generator, photos_generator, num_images=2)","metadata":{"id":"0CYdxxmD8i_z","outputId":"e1c06506-ad10-4a1a-b08b-408b14257045"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"##Training 2 - Tuned Parameters","metadata":{"id":"YmnBBpVv83Uu"}},{"cell_type":"markdown","source":"Parameters","metadata":{"id":"Fk-8VT3D83Uw"}},{"cell_type":"code","source":"EPOCHS = 5\nBATCH_SIZE= 2\nNUM_MONET_PHOTOS = 300\nLEARNING_RATE = 0.0003\nBETA_1 = 0.6\nLAMBDA = 3\nBUFFER_SIZE = 50\nDROPOUT_RATE_GEN = 0.5\nTRANSFER_LAYERS_GEN = 5\nSTRIDE_NUM_GEN, STRIDE_NUM_DIS = 2,1\nPADDING_GEN ='same'\nFILTER_SIZE_GEN, FILTER_SIZE_DIS = 4, 4\nFILTER_SIZE_L1_GEN = 4\nFILTER_L1_GEN ,FILTER_L1_DIS = 64,64\nDOWNSAMPLE_LAYER_NUM_DIS= 3","metadata":{"id":"QuywSCM-83Ux"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Building the generators and discriminators","metadata":{"id":"laHa8I_-83Uy"}},{"cell_type":"code","source":"with strategy.scope():\n  #----------------#\n  #   Generators   #\n  #----------------#\n\n  monet_generator = generator_builder(dropout_rate = DROPOUT_RATE_GEN, filter_size_L1 = FILTER_SIZE_L1_GEN, filters_size = FILTER_SIZE_GEN, filters_L1 = FILTER_L1_GEN,\n                                      transfer_layers= TRANSFER_LAYERS_GEN, stride = STRIDE_NUM_GEN, padding = PADDING_GEN)\n\n  photos_generator = generator_builder(dropout_rate = DROPOUT_RATE_GEN, filter_size_L1 = FILTER_SIZE_L1_GEN, filters_size = FILTER_SIZE_GEN, filters_L1 = FILTER_L1_GEN,\n                                      transfer_layers= TRANSFER_LAYERS_GEN, stride = STRIDE_NUM_GEN, padding = PADDING_GEN)\n\n  #------------------#\n  #  Discriminators  #\n  #------------------#\n\n  monet_discriminator = discriminator_builder(filter_size = FILTER_SIZE_DIS, filters_L1 = FILTER_L1_DIS, downsample_layers_num=DOWNSAMPLE_LAYER_NUM_DIS, stride = STRIDE_NUM_DIS)\n\n  photos_discriminator = discriminator_builder(filter_size = FILTER_SIZE_DIS, filters_L1 = FILTER_L1_DIS, downsample_layers_num=DOWNSAMPLE_LAYER_NUM_DIS, stride = STRIDE_NUM_DIS)\n\n  #----------------#\n  #   Optimizers   #\n  #----------------#\n\n  monetGen_optimizer = keras.optimizers.legacy.Adam(learning_rate=LEARNING_RATE, beta_1=BETA_1)\n\n  photosGen_optimizer = keras.optimizers.legacy.Adam(learning_rate=LEARNING_RATE, beta_1=BETA_1)\n\n  monetDis_optimizer = keras.optimizers.legacy.Adam(learning_rate=LEARNING_RATE, beta_1=BETA_1)\n\n  photosDis_optimizer = keras.optimizers.legacy.Adam(learning_rate=LEARNING_RATE, beta_1=BETA_1)\n","metadata":{"id":"gsQy4Xoi83Uz"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Creating the CycleGan instance","metadata":{"id":"g-6LrK-c83U0"}},{"cell_type":"code","source":"with strategy.scope():\n  cycleGan = CycleGan(\n      monet_generator, photos_generator, monet_discriminator, photos_discriminator, lambda_cycle=LAMBDA, buffer_size=BUFFER_SIZE\n  )\n\n  cycleGan.compile(\n        monetOptimizer = monetGen_optimizer,\n        photosOptimizer = photosGen_optimizer,\n        mDisOptimizer = monetDis_optimizer,\n        pDisOptimizer = photosDis_optimizer,\n        genLossFunc = generator_loss,\n        disLossFunc = discriminator_loss,\n        cycleLossFunc = cycle_loss,\n        idLossFunc = identity_loss\n  )","metadata":{"id":"hP64T2E_83U0"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"monet_generator.summary()\n\nphotos_discriminator.summary()","metadata":{"id":"S3-Rxk2O83Uz","outputId":"311296d0-7c9e-444f-e6b3-d4b2e58558ad"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"###Training\n","metadata":{"id":"iVh5FpJ683U1"}},{"cell_type":"code","source":"history = cycleGan.fit(\n    tf.data.Dataset.zip((monetData, photosData)),\n    epochs=EPOCHS,\n    batch_size=BATCH_SIZE,\n)","metadata":{"id":"yi9_zDc-83U1","outputId":"4aa30112-b504-4f8c-fd18-5d9b3acffed7"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Plot the loss","metadata":{"id":"O5gjKK5G83U1"}},{"cell_type":"code","source":"print(\"Monet Generator Loss shape:\", np.array(history.history['monetGenLoss']).shape)\nprint(\"Monet Discriminator Loss shape:\", np.array(history.history['monetDisLoss']).shape)\nprint(\"Monet total cycle Loss:\", history.history['cycleLoss'])","metadata":{"id":"BgMv-gJ583U2","outputId":"474feac7-7f40-490a-a3df-2af3a4e6a31f"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plotting(history.history)","metadata":{"id":"i5h6_yrv83U2","outputId":"a5436558-42c4-4d63-c083-8164433c432f"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"###Visualization Result","metadata":{"id":"mpiJ-Yit9IwW"}},{"cell_type":"markdown","source":"Displaying the images as a cycle:\nOriginal | Monet | Cycled back to Original","metadata":{"id":"au9iVs8483U2"}},{"cell_type":"code","source":"visualizing(photosData, monet_generator, photos_generator, num_images=3)","metadata":{"id":"uhv4iCog83U3","outputId":"695f490d-cca0-4b52-9201-b34419e1fff4"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"##Training 3 - Adding Image Augmentation","metadata":{"id":"kIEA_TBllKB9"}},{"cell_type":"markdown","source":"Parameters","metadata":{"id":"M6tjCWbJlKB-"}},{"cell_type":"code","source":"EPOCHS = 5\nBATCH_SIZE= 2\nLEARNING_RATE = 0.0003\nBUFFER_SIZE = 50\nBETA_1 = 0.5\nLAMBDA = 3\nNUM_MONET_PHOTOS = 300*2\n\nDROPOUT_RATE_GEN = 0.5\nTRANSFER_LAYERS_GEN = 5\nSTRIDE_NUM_GEN, STRIDE_NUM_DIS = 2,1\nPADDING_GEN ='same'\nFILTER_SIZE_GEN, FILTER_SIZE_DIS = 4, 4\nFILTER_SIZE_L1_GEN = 4\nFILTER_L1_GEN ,FILTER_L1_DIS = 64,64\nDOWNSAMPLE_LAYER_NUM_DIS= 3","metadata":{"id":"zvjU6SRAlKB-"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"monetData_aug = apply_aug(monet_files, labeled = True, ordered=False, repeat=True, shuffle=True, rotation=True, flip=True, transpose=True, crop=False, height=256, width=256).batch(BATCH_SIZE)\n\nphotosData_aug = apply_aug(photos_files, labeled = True, ordered=False, repeat=False, shuffle=True, rotation=True, flip=True, transpose=True, crop=False, height=256, width=256).batch(BATCH_SIZE)","metadata":{"id":"1AdNilGhljwa"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Building the generators and discriminators","metadata":{"id":"yBnApdj4lKB_"}},{"cell_type":"code","source":"with strategy.scope():\n  #----------------#\n  #   Generators   #\n  #----------------#\n\n  monet_generator = generator_builder(dropout_rate = DROPOUT_RATE_GEN, filter_size_L1 = FILTER_SIZE_L1_GEN, filters_size = FILTER_SIZE_GEN, filters_L1 = FILTER_L1_GEN,\n                                      transfer_layers= TRANSFER_LAYERS_GEN, stride = STRIDE_NUM_GEN, padding = PADDING_GEN)\n\n  photos_generator = generator_builder(dropout_rate = DROPOUT_RATE_GEN, filter_size_L1 = FILTER_SIZE_L1_GEN, filters_size = FILTER_SIZE_GEN, filters_L1 = FILTER_L1_GEN,\n                                      transfer_layers= TRANSFER_LAYERS_GEN, stride = STRIDE_NUM_GEN, padding = PADDING_GEN)\n\n  #------------------#\n  #  Discriminators  #\n  #------------------#\n\n  monet_discriminator = discriminator_builder(filter_size = FILTER_SIZE_DIS, filters_L1 = FILTER_L1_DIS, downsample_layers_num=DOWNSAMPLE_LAYER_NUM_DIS, stride = STRIDE_NUM_DIS)\n\n  photos_discriminator = discriminator_builder(filter_size = FILTER_SIZE_DIS, filters_L1 = FILTER_L1_DIS, downsample_layers_num=DOWNSAMPLE_LAYER_NUM_DIS, stride = STRIDE_NUM_DIS)\n\n  #----------------#\n  #   Optimizers   #\n  #----------------#\n\n  monetGen_optimizer = keras.optimizers.legacy.Adam(learning_rate=LEARNING_RATE, beta_1=BETA_1)\n\n  photosGen_optimizer = keras.optimizers.legacy.Adam(learning_rate=LEARNING_RATE, beta_1=BETA_1)\n\n  monetDis_optimizer = keras.optimizers.legacy.Adam(learning_rate=LEARNING_RATE, beta_1=BETA_1)\n\n  photosDis_optimizer = keras.optimizers.legacy.Adam(learning_rate=LEARNING_RATE, beta_1=BETA_1)\n","metadata":{"id":"tnZ4pfXrlKB_"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Creating the CycleGan instance","metadata":{"id":"YA1ghYXMlKB_"}},{"cell_type":"code","source":"with strategy.scope():\n  cycleGan = CycleGan(\n      monet_generator, photos_generator, monet_discriminator, photos_discriminator, lambda_cycle=LAMBDA, buffer_size=BUFFER_SIZE\n  )\n\n  cycleGan.compile(\n        monetOptimizer = monetGen_optimizer,\n        photosOptimizer = photosGen_optimizer,\n        mDisOptimizer = monetDis_optimizer,\n        pDisOptimizer = photosDis_optimizer,\n        genLossFunc = generator_loss,\n        disLossFunc = discriminator_loss,\n        cycleLossFunc = cycle_loss,\n        idLossFunc = identity_loss\n  )","metadata":{"id":"9glD8Vk6lKB_"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"monet_generator.summary()\n\nphotos_discriminator.summary()","metadata":{"outputId":"9f4ffa19-68c0-435b-863c-3a22c86f6260","id":"Mk1ZWuODlKCA"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"###Training\n","metadata":{"id":"iNB0El1TlKCA"}},{"cell_type":"code","source":"history2 = cycleGan.fit(\n    tf.data.Dataset.zip((monetData_aug, photosData_aug)),\n    batch_size=BATCH_SIZE,\n    epochs=EPOCHS,\n    steps_per_epoch=300,\n)","metadata":{"outputId":"5852860a-3908-4a9e-e7e7-5167f0bd36a6","id":"yOL-A88JlKCB"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Plot the loss","metadata":{"id":"fPRqHipLlKCB"}},{"cell_type":"code","source":"print(\"Monet Generator Loss shape:\", np.array(history.history['monetGenLoss']).shape)\nprint(\"Monet Discriminator Loss shape:\", np.array(history.history['monetDisLoss']).shape)\nprint(\"Monet total cycle Loss:\", history.history['cycleLoss'])","metadata":{"outputId":"0c39701a-a1fb-459e-c31f-f07faff944ae","id":"R66Q0TwUlKCC"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plotting(history.history)","metadata":{"outputId":"4256e793-5292-4ad9-c4cc-d3cdde1c86f8","id":"uqWf5PPQlKCC"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"###Visualization Result","metadata":{"id":"nVAQLCBmlKCC"}},{"cell_type":"markdown","source":"Displaying the images as a cycle:\nOriginal | Monet | Cycled back to Original","metadata":{"id":"NuChgkOulKCC"}},{"cell_type":"code","source":"visualizing(photosData, monet_generator, photos_generator, num_images=3)","metadata":{"outputId":"3874d636-2246-4392-f70d-27f206517d2d","id":"oWkOl6WJlKCC"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"##Training 4 - Adding Image Augmentations and Rate Scheduler","metadata":{"id":"CRa9mUeKK-7S"}},{"cell_type":"markdown","source":"Parameters","metadata":{"id":"rTe_Nb02K-7W"}},{"cell_type":"code","source":"EPOCHS = 20\nBATCH_SIZE= 9\nNUM_MONET_PHOTOS = 300*2\nNUM_PHOTOS = 7038\nLEARNING_RATE = 3e-4\nMIN_LEARNING_RATE = 1e-5\nDECAY_STEPS = int(NUM_PHOTOS / BATCH_SIZE) * 5\nDECAY_RATE = 0.6\n\nBETA_1 = 0.5\nLAMBDA = 3\nBUFFER_SIZE = 50\n\nDROPOUT_RATE_GEN = 0.5\nTRANSFER_LAYERS_GEN = 5\nSTRIDE_NUM_GEN, STRIDE_NUM_DIS = 2,1\nPADDING_GEN ='same'\nFILTER_SIZE_GEN, FILTER_SIZE_DIS = 4, 4\nFILTER_SIZE_L1_GEN = 4\nFILTER_L1_GEN ,FILTER_L1_DIS = 64,64\nDOWNSAMPLE_LAYER_NUM_DIS= 3","metadata":{"id":"Cdats7lMK-7W"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"###Building a learning rate scheduler","metadata":{"id":"VKuTYIwGPgLu"}},{"cell_type":"code","source":"class Scheduler(keras.optimizers.schedules.LearningRateSchedule):\n  def __init__(\n      self,\n      init_lr,\n      min_lr,\n      decay_steps,\n      decay_rate,\n    ):\n    super(Scheduler, self).__init__()\n\n    self.init_lr = init_lr\n    self.min_lr = min_lr\n    self.decay_steps = decay_steps\n    self.decay_rate = decay_rate\n\n  def __call__(self, step):\n    learningRate = tf.math.maximum(self.init_lr * self.decay_rate ** (step / self.decay_steps), self.min_lr)\n    return learningRate\n\n#Creating an instance of the class\nscheduler = Scheduler(init_lr=LEARNING_RATE, min_lr=MIN_LEARNING_RATE, decay_steps=DECAY_STEPS, decay_rate=DECAY_RATE)\n\n#plot the result\nstepsNum = int(NUM_PHOTOS / BATCH_SIZE * EPOCHS)\nlrs = [scheduler(tf.constant(step, dtype=tf.float32)).numpy() for step in range(stepsNum)]\n\nplt.figure(figsize=(10,5))\nplt.plot(range(stepsNum), lrs, color='#ebb73d')\nplt.xlabel('Step')\nplt.ylabel('Learning Rate')\nplt.title('Learning Rate Schedule')\nplt.grid(True)\nplt.show()","metadata":{"id":"R5l9JEWDPiov","outputId":"4d262c84-2620-41ac-d9c4-67afc415c698"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"###Loading Augmented data","metadata":{"id":"aOJxK2gWLeyk"}},{"cell_type":"code","source":"monetData_aug = apply_aug(monet_files, labeled = True, ordered=False, repeat=True, shuffle=True, rotation=True, flip=True, transpose=True, crop=False, height=256, width=256).batch(BATCH_SIZE)\n\nphotosData_aug = apply_aug(photos_files, labeled = True, ordered=False, repeat=False, shuffle=True, rotation=True, flip=True, transpose=True, crop=False, height=256, width=256).batch(BATCH_SIZE)","metadata":{"id":"Rb-cyBWiLgja"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Building the generators and discriminators","metadata":{"id":"DArNk3-3K-7X"}},{"cell_type":"code","source":"with strategy.scope():\n  #----------------#\n  #   Generators   #\n  #----------------#\n\n  monet_generator = generator_builder(dropout_rate = DROPOUT_RATE_GEN, filter_size_L1 = FILTER_SIZE_L1_GEN, filters_size = FILTER_SIZE_GEN, filters_L1 = FILTER_L1_GEN,\n                                      transfer_layers= TRANSFER_LAYERS_GEN, stride = STRIDE_NUM_GEN, padding = PADDING_GEN)\n\n  photos_generator = generator_builder(dropout_rate = DROPOUT_RATE_GEN, filter_size_L1 = FILTER_SIZE_L1_GEN, filters_size = FILTER_SIZE_GEN, filters_L1 = FILTER_L1_GEN,\n                                      transfer_layers= TRANSFER_LAYERS_GEN, stride = STRIDE_NUM_GEN, padding = PADDING_GEN)\n\n  #------------------#\n  #  Discriminators  #\n  #------------------#\n\n  monet_discriminator = discriminator_builder(filter_size = FILTER_SIZE_DIS, filters_L1 = FILTER_L1_DIS, downsample_layers_num=DOWNSAMPLE_LAYER_NUM_DIS, stride = STRIDE_NUM_DIS)\n\n  photos_discriminator = discriminator_builder(filter_size = FILTER_SIZE_DIS, filters_L1 = FILTER_L1_DIS, downsample_layers_num=DOWNSAMPLE_LAYER_NUM_DIS, stride = STRIDE_NUM_DIS)\n\n  #----------------#\n  #   Optimizers   #\n  #----------------#\n\n  monetGen_optimizer = keras.optimizers.legacy.Adam(learning_rate=scheduler, beta_1=BETA_1)\n\n  photosGen_optimizer = keras.optimizers.legacy.Adam(learning_rate=scheduler, beta_1=BETA_1)\n\n  monetDis_optimizer = keras.optimizers.legacy.Adam(learning_rate=scheduler, beta_1=BETA_1)\n\n  photosDis_optimizer = keras.optimizers.legacy.Adam(learning_rate=scheduler, beta_1=BETA_1)\n","metadata":{"id":"pVz-ohmyK-7X"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Creating the CycleGan instance","metadata":{"id":"1bb4rVtaK-7Y"}},{"cell_type":"code","source":"with strategy.scope():\n  cycleGan = CycleGan(\n      monet_generator, photos_generator, monet_discriminator, photos_discriminator, lambda_cycle=LAMBDA, buffer_size=BUFFER_SIZE\n  )\n\n  cycleGan.compile(\n        monetOptimizer = monetGen_optimizer,\n        photosOptimizer = photosGen_optimizer,\n        mDisOptimizer = monetDis_optimizer,\n        pDisOptimizer = photosDis_optimizer,\n        genLossFunc = generator_loss,\n        disLossFunc = discriminator_loss,\n        cycleLossFunc = cycle_loss,\n        idLossFunc = identity_loss\n  )","metadata":{"id":"ht9lBz_5K-7Y"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"monet_generator.summary()\n\nphotos_discriminator.summary()","metadata":{"outputId":"536509c0-9363-4a25-d1e2-698ed4fda369","id":"7jmSiSy2K-7Y"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"###Training\n","metadata":{"id":"gDPF_teiK-7Y"}},{"cell_type":"code","source":"history = cycleGan.fit(\n    tf.data.Dataset.zip((monetData_aug, photosData_aug)),\n    epochs=EPOCHS,\n    batch_size=BATCH_SIZE,\n)","metadata":{"outputId":"76dfd028-90de-4d3b-be3d-2ecc98cb7636","id":"6xyt3kv5K-7Z"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Plot the loss","metadata":{"id":"8t_eRRQfK-7Z"}},{"cell_type":"code","source":"plotting(history.history)","metadata":{"outputId":"27ee014d-1e78-4040-b8c3-3da09921d108","id":"shSehto4K-7a"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"###Visualization Result","metadata":{"id":"szqCW8NPK-7a"}},{"cell_type":"markdown","source":"Displaying the images as a cycle:\nOriginal | Monet | Cycled back to Original","metadata":{"id":"VQSbzzcUK-7a"}},{"cell_type":"code","source":"visualizing(photosData, monet_generator, photos_generator, num_images=20)","metadata":{"id":"-f0hNVeaK-7a"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"###Saving the weights","metadata":{"id":"A8fpPLhl-d4J"}},{"cell_type":"code","source":"# Save the weights\ncycleGan.save_weights('monet_cycleGan.h5')\n\n","metadata":{"id":"s310kPN3-fTO"},"execution_count":null,"outputs":[]}]}