{"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":"code","source":"pip install imageio","metadata":{"execution":{"iopub.status.busy":"2023-06-25T06:28:14.373429Z","iopub.execute_input":"2023-06-25T06:28:14.373925Z","iopub.status.idle":"2023-06-25T06:28:19.107673Z","shell.execute_reply.started":"2023-06-25T06:28:14.373880Z","shell.execute_reply":"2023-06-25T06:28:19.106119Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import warnings\n# Ignore all warnings\nwarnings.filterwarnings(\"ignore\")","metadata":{"execution":{"iopub.status.busy":"2023-06-25T06:28:19.109975Z","iopub.execute_input":"2023-06-25T06:28:19.110363Z","iopub.status.idle":"2023-06-25T06:28:19.115420Z","shell.execute_reply.started":"2023-06-25T06:28:19.110326Z","shell.execute_reply":"2023-06-25T06:28:19.114428Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import tensorflow as tf\nimport numpy as np\nimport pandas as pd\nimport PIL\nimport imageio\nimport glob\nimport os\nimport time\nimport random\nimport matplotlib.pylab as plt\nimport matplotlib.image as mpimg\nfrom sklearn.model_selection import train_test_split\nimport cv2\nimport tqdm\nfrom IPython.display import clear_output\nAUTOTUNE = tf.data.AUTOTUNE \n#  TensorFlow will automatically determine the optimal number of parallel operations \n#  to execute based on the available computational resources, such as CPU or GPU.","metadata":{"execution":{"iopub.status.busy":"2023-06-25T06:28:19.116605Z","iopub.execute_input":"2023-06-25T06:28:19.116883Z","iopub.status.idle":"2023-06-25T06:28:19.129701Z","shell.execute_reply.started":"2023-06-25T06:28:19.116859Z","shell.execute_reply":"2023-06-25T06:28:19.128727Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from tensorflow.keras.initializers import RandomNormal\nfrom tensorflow.keras import layers\nfrom tensorflow.keras.models import Model\nfrom tensorflow.keras.layers import Input\nfrom tensorflow.keras.layers import Conv2D\nfrom tensorflow.keras.layers import Conv2DTranspose\nfrom tensorflow.keras.layers import LeakyReLU\nfrom tensorflow.keras.layers import Activation\nfrom tensorflow.keras.layers import Concatenate\nimport tensorflow_addons as tfa","metadata":{"execution":{"iopub.status.busy":"2023-06-25T06:28:19.132198Z","iopub.execute_input":"2023-06-25T06:28:19.132514Z","iopub.status.idle":"2023-06-25T06:28:19.142686Z","shell.execute_reply.started":"2023-06-25T06:28:19.132488Z","shell.execute_reply":"2023-06-25T06:28:19.141729Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Loading Dataset","metadata":{}},{"cell_type":"code","source":"monet_path = \"/kaggle/input/gan-getting-started/monet_jpg\"\nphoto_path = \"/kaggle/input/gan-getting-started/photo_jpg\"","metadata":{"execution":{"iopub.status.busy":"2023-06-25T06:28:19.143905Z","iopub.execute_input":"2023-06-25T06:28:19.144191Z","iopub.status.idle":"2023-06-25T06:28:19.151841Z","shell.execute_reply.started":"2023-06-25T06:28:19.144168Z","shell.execute_reply":"2023-06-25T06:28:19.150867Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"print(\"Monet_style- \")\nplt.figure(figsize=(25,25))\nfor i in range(4):\n    file = random.choice(os.listdir(monet_path))\n    image_path= os.path.join(monet_path, file)\n    img=mpimg.imread(image_path)\n    ax=plt.subplot(1,4,i+1)\n    ax.axis(\"off\")\n    plt.imshow(img)","metadata":{"execution":{"iopub.status.busy":"2023-06-25T06:28:19.152891Z","iopub.execute_input":"2023-06-25T06:28:19.153167Z","iopub.status.idle":"2023-06-25T06:28:20.008404Z","shell.execute_reply.started":"2023-06-25T06:28:19.153143Z","shell.execute_reply":"2023-06-25T06:28:20.007033Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"print(\"Photos- \")\nplt.figure(figsize=(25,25))\nfor i in range(4):\n    file = random.choice(os.listdir(photo_path))\n    image_path= os.path.join(photo_path, file)\n    img=mpimg.imread(image_path)\n    ax=plt.subplot(1,4,i+1)\n    ax.axis(\"off\")\n    plt.imshow(img)","metadata":{"execution":{"iopub.status.busy":"2023-06-25T06:28:20.009828Z","iopub.execute_input":"2023-06-25T06:28:20.010174Z","iopub.status.idle":"2023-06-25T06:28:20.766417Z","shell.execute_reply.started":"2023-06-25T06:28:20.010142Z","shell.execute_reply":"2023-06-25T06:28:20.764495Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"folder_path = monet_path\nimage_files = [file for file in os.listdir(folder_path) if file.endswith('.jpg')]\n\nmonet = []\n\nfor file in tqdm.tqdm(image_files):\n    image_path = os.path.join(folder_path, file)\n    image = cv2.imread(image_path)\n    if image is not None:\n        monet.append(image)\n\nmonet = np.array(monet)","metadata":{"execution":{"iopub.status.busy":"2023-06-25T06:28:20.767985Z","iopub.execute_input":"2023-06-25T06:28:20.768335Z","iopub.status.idle":"2023-06-25T06:28:21.519179Z","shell.execute_reply.started":"2023-06-25T06:28:20.768303Z","shell.execute_reply":"2023-06-25T06:28:21.517968Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"folder_path = photo_path\nimage_files = [file for file in os.listdir(folder_path) if file.endswith('.jpg')]\n\nphoto = []\n\nfor file in tqdm.tqdm(image_files):\n    image_path = os.path.join(folder_path, file)\n    image = cv2.imread(image_path)\n    if image is not None:\n        photo.append(image)\n\nphoto = np.array(photo)","metadata":{"execution":{"iopub.status.busy":"2023-06-25T06:28:21.520656Z","iopub.execute_input":"2023-06-25T06:28:21.521018Z","iopub.status.idle":"2023-06-25T06:28:36.694551Z","shell.execute_reply.started":"2023-06-25T06:28:21.520988Z","shell.execute_reply":"2023-06-25T06:28:36.693135Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"print(monet.shape)\nprint(photo.shape)","metadata":{"execution":{"iopub.status.busy":"2023-06-25T06:28:36.698434Z","iopub.execute_input":"2023-06-25T06:28:36.698769Z","iopub.status.idle":"2023-06-25T06:28:36.704234Z","shell.execute_reply.started":"2023-06-25T06:28:36.698740Z","shell.execute_reply":"2023-06-25T06:28:36.703049Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plt.figure(figsize=(15,15))\n\nfor i, img in enumerate(monet[:4]):\n  plt.subplot(2,4,i+1)\n  plt.imshow(img) \n\nfor i, img in enumerate(photo[:4]):\n  plt.subplot(2,4,i+5)\n  plt.imshow(img) \n    \nplt.show()","metadata":{"execution":{"iopub.status.busy":"2023-06-25T06:28:36.705474Z","iopub.execute_input":"2023-06-25T06:28:36.705763Z","iopub.status.idle":"2023-06-25T06:28:38.215067Z","shell.execute_reply.started":"2023-06-25T06:28:36.705738Z","shell.execute_reply":"2023-06-25T06:28:38.213765Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"## Converting Numpy array to Tensorflow dataset for further processing\nmonet = tf.data.Dataset.from_tensor_slices(monet)\nphoto = tf.data.Dataset.from_tensor_slices(photo)","metadata":{"execution":{"iopub.status.busy":"2023-06-25T06:28:38.216520Z","iopub.execute_input":"2023-06-25T06:28:38.216847Z","iopub.status.idle":"2023-06-25T06:28:39.337811Z","shell.execute_reply.started":"2023-06-25T06:28:38.216814Z","shell.execute_reply":"2023-06-25T06:28:39.336448Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Preprocessing the images\n\n**Data augmentation to avoid overfitting:**<br>\n**`jittering`** - Here we scale the image to 286x286 and then crop it to 256x256<br>\n**`mirror`** - Horizontal flipping of the image","metadata":{}},{"cell_type":"code","source":"BUFFER_SIZE = 1000 # This size defines the size used for shufling\nBATCH_SIZE = 1 # \nIMG_WIDTH = 256\nIMG_HEIGHT = 256","metadata":{"execution":{"iopub.status.busy":"2023-06-25T06:28:39.339014Z","iopub.execute_input":"2023-06-25T06:28:39.339316Z","iopub.status.idle":"2023-06-25T06:28:39.350085Z","shell.execute_reply.started":"2023-06-25T06:28:39.339290Z","shell.execute_reply":"2023-06-25T06:28:39.349151Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"**NOTE-** The **`BATCH_SIZE = 1`** beacuse we want to avoid batch normalisation instead we will apply instance normalisation ","metadata":{}},{"cell_type":"markdown","source":"#### Cropping","metadata":{}},{"cell_type":"code","source":"def random_crop(image):\n  cropped_image = tf.image.random_crop(\n      image, size=[IMG_HEIGHT, IMG_WIDTH, 3])\n\n  return cropped_image","metadata":{"execution":{"iopub.status.busy":"2023-06-25T06:28:39.351227Z","iopub.execute_input":"2023-06-25T06:28:39.351561Z","iopub.status.idle":"2023-06-25T06:28:39.361619Z","shell.execute_reply.started":"2023-06-25T06:28:39.351532Z","shell.execute_reply":"2023-06-25T06:28:39.360664Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"#### Normalize","metadata":{}},{"cell_type":"code","source":"# normalizing the images to [-1, 1]\ndef normalize(image):\n  image = tf.cast(image, tf.float32)\n  image = (image / 127.5) - 1\n  return image","metadata":{"execution":{"iopub.status.busy":"2023-06-25T06:28:39.362829Z","iopub.execute_input":"2023-06-25T06:28:39.363135Z","iopub.status.idle":"2023-06-25T06:28:39.371695Z","shell.execute_reply.started":"2023-06-25T06:28:39.363108Z","shell.execute_reply":"2023-06-25T06:28:39.370755Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"#### Jitter and Mirroring","metadata":{}},{"cell_type":"code","source":"def random_jitter(image):\n  # resizing to 286 x 286 x 3\n  image = tf.image.resize(image, [286, 286],\n                          method=tf.image.ResizeMethod.NEAREST_NEIGHBOR)\n\n  # randomly cropping to 256 x 256 x 3\n  image = random_crop(image)\n\n  # random mirroring\n  image = tf.image.random_flip_left_right(image)\n\n  return image","metadata":{"execution":{"iopub.status.busy":"2023-06-25T06:28:39.372924Z","iopub.execute_input":"2023-06-25T06:28:39.373227Z","iopub.status.idle":"2023-06-25T06:28:39.381873Z","shell.execute_reply.started":"2023-06-25T06:28:39.373200Z","shell.execute_reply":"2023-06-25T06:28:39.380943Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def preprocess_image(image):\n  image = random_jitter(image)\n  image = normalize(image)\n  return image","metadata":{"execution":{"iopub.status.busy":"2023-06-25T06:28:39.383085Z","iopub.execute_input":"2023-06-25T06:28:39.383402Z","iopub.status.idle":"2023-06-25T06:28:39.392421Z","shell.execute_reply.started":"2023-06-25T06:28:39.383362Z","shell.execute_reply":"2023-06-25T06:28:39.391400Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"## PREPROCESSING \n\nmonet = monet.cache().map(\n    preprocess_image, num_parallel_calls=AUTOTUNE).shuffle(\n    BUFFER_SIZE).batch(BATCH_SIZE)\n\nphoto = photo.cache().map(\n    preprocess_image, num_parallel_calls=AUTOTUNE).shuffle(\n    BUFFER_SIZE).batch(BATCH_SIZE)","metadata":{"execution":{"iopub.status.busy":"2023-06-25T06:28:39.393648Z","iopub.execute_input":"2023-06-25T06:28:39.393942Z","iopub.status.idle":"2023-06-25T06:28:39.646778Z","shell.execute_reply.started":"2023-06-25T06:28:39.393919Z","shell.execute_reply":"2023-06-25T06:28:39.645405Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Splitting the dataset","metadata":{}},{"cell_type":"code","source":"dataset_length = len(monet) # Calculate the total length of the dataset\n\nsplit_index = int(dataset_length * 0.9) # Calculate the split index for train and test\n\n# Split the dataset\ntrain_monet = monet.take(split_index)\ntest_monet = monet.skip(split_index)","metadata":{"execution":{"iopub.status.busy":"2023-06-25T06:28:39.648176Z","iopub.execute_input":"2023-06-25T06:28:39.648501Z","iopub.status.idle":"2023-06-25T06:28:39.655436Z","shell.execute_reply.started":"2023-06-25T06:28:39.648473Z","shell.execute_reply":"2023-06-25T06:28:39.654510Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"dataset_length = len(photo) # Calculate the total length of the dataset\n\nsplit_index = int(dataset_length * 0.9) # Calculate the split index for train and test\n\n# Split the dataset\ntrain_photo = photo.take(split_index)\ntest_photo = photo.skip(split_index)","metadata":{"execution":{"iopub.status.busy":"2023-06-25T06:28:39.656635Z","iopub.execute_input":"2023-06-25T06:28:39.656921Z","iopub.status.idle":"2023-06-25T06:28:39.756893Z","shell.execute_reply.started":"2023-06-25T06:28:39.656897Z","shell.execute_reply":"2023-06-25T06:28:39.755581Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"sample_monet = next(iter(train_monet))\nsample_photo = next(iter(train_photo))","metadata":{"execution":{"iopub.status.busy":"2023-06-25T06:28:39.758291Z","iopub.execute_input":"2023-06-25T06:28:39.758665Z","iopub.status.idle":"2023-06-25T06:28:41.314782Z","shell.execute_reply.started":"2023-06-25T06:28:39.758633Z","shell.execute_reply":"2023-06-25T06:28:41.313413Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"> **sample_monet = monet V/S sample_monet = next(iter(train_monet))**\n\n`sample_horse = train_horses` assigns the entire dataset object to the variable, while `sample_horse = next(iter(train_horses))` extracts a single data sample from the dataset and assigns it to the variable. The former allows you to work with the dataset as a whole, while the latter gives you access to individual data points for inspection, visualization, or further processing.","metadata":{}},{"cell_type":"code","source":"plt.subplot(121)\nplt.title('Monet')\nplt.imshow(sample_monet[0] * 0.5 + 0.5)\n\nplt.subplot(122)\nplt.title('Monet with random jitter')\nplt.imshow(random_jitter(sample_monet[0]) * 0.5 + 0.5)","metadata":{"execution":{"iopub.status.busy":"2023-06-25T06:28:41.316500Z","iopub.execute_input":"2023-06-25T06:28:41.316880Z","iopub.status.idle":"2023-06-25T06:28:41.819532Z","shell.execute_reply.started":"2023-06-25T06:28:41.316848Z","shell.execute_reply":"2023-06-25T06:28:41.818410Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plt.subplot(121)\nplt.title('Photo')\nplt.imshow(sample_photo[0] * 0.5 + 0.5)\n\nplt.subplot(122)\nplt.title('Photo with random jitter')\nplt.imshow(random_jitter(sample_photo[0]) * 0.5 + 0.5)","metadata":{"execution":{"iopub.status.busy":"2023-06-25T06:28:41.820872Z","iopub.execute_input":"2023-06-25T06:28:41.821188Z","iopub.status.idle":"2023-06-25T06:28:42.310992Z","shell.execute_reply.started":"2023-06-25T06:28:41.821161Z","shell.execute_reply":"2023-06-25T06:28:42.309856Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Generator","metadata":{}},{"cell_type":"code","source":"    def resnet_block(n_filters, input_layer):\n        # weight initialization\n        init = RandomNormal(stddev=0.02)\n        # first convolutional layer\n        g = Conv2D(n_filters, (3,3), padding='same', kernel_initializer=init)(input_layer)\n        g = tfa.layers.InstanceNormalization(axis=-1)(g)\n        g = Activation('relu')(g)\n        # second convolutional layer\n        g = Conv2D(n_filters, (3,3), padding='same', kernel_initializer=init)(g)\n        g = tfa.layers.InstanceNormalization(axis=-1)(g)\n        # concatenate merge channel-wise with input layer\n        g = Concatenate()([g, input_layer])\n        return g","metadata":{"execution":{"iopub.status.busy":"2023-06-25T06:28:42.312400Z","iopub.execute_input":"2023-06-25T06:28:42.312761Z","iopub.status.idle":"2023-06-25T06:28:42.320080Z","shell.execute_reply.started":"2023-06-25T06:28:42.312728Z","shell.execute_reply":"2023-06-25T06:28:42.319174Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"    def Generator(n_resnet=9):\n        # weight initialization\n        init = RandomNormal(stddev=0.02)\n        # image input\n        in_image = tf.keras.layers.Input(shape=[256, 256, 3])\n        \n        # c7s1-64\n        g = Conv2D(64, (7,7), padding='same', kernel_initializer=init)(in_image)\n        g = tfa.layers.InstanceNormalization(axis=-1)(g)\n        g = Activation('relu')(g)\n        # d128\n        g = Conv2D(128, (3,3), strides=(2,2), padding='same', kernel_initializer=init)(g)\n        g = tfa.layers.InstanceNormalization(axis=-1)(g)\n        g = Activation('relu')(g)\n        # d256\n        g = Conv2D(256, (3,3), strides=(2,2), padding='same', kernel_initializer=init)(g)\n        g = tfa.layers.InstanceNormalization(axis=-1)(g)\n        g = Activation('relu')(g)\n        # R256\n        for _ in range(n_resnet):\n            g = resnet_block(256, g)\n        # u128\n        g = Conv2DTranspose(128, (3,3), strides=(2,2), padding='same', kernel_initializer=init)(g)\n        g = tfa.layers.InstanceNormalization(axis=-1)(g)\n        g = Activation('relu')(g)\n        # u64\n        g = Conv2DTranspose(64, (3,3), strides=(2,2), padding='same', kernel_initializer=init)(g)\n        g = tfa.layers.InstanceNormalization(axis=-1)(g)\n        g = Activation('relu')(g)\n        # c7s1-3\n        g = Conv2D(3, (7,7), padding='same', kernel_initializer=init)(g)\n        g = tfa.layers.InstanceNormalization(axis=-1)(g)\n        out_image = Activation('tanh')(g)\n        \n        # define model\n        model = Model(in_image, out_image)\n        return model","metadata":{"execution":{"iopub.status.busy":"2023-06-25T06:28:42.321275Z","iopub.execute_input":"2023-06-25T06:28:42.321582Z","iopub.status.idle":"2023-06-25T06:28:42.336310Z","shell.execute_reply.started":"2023-06-25T06:28:42.321544Z","shell.execute_reply":"2023-06-25T06:28:42.335411Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"generator_g = Generator()","metadata":{"execution":{"iopub.status.busy":"2023-06-25T06:28:42.337309Z","iopub.execute_input":"2023-06-25T06:28:42.337574Z","iopub.status.idle":"2023-06-25T06:28:43.393619Z","shell.execute_reply.started":"2023-06-25T06:28:42.337552Z","shell.execute_reply":"2023-06-25T06:28:43.392254Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"photo = sample_photo[0] * 0.5 + 0.5\nexample_gen_output_y = generator_g(photo[tf.newaxis,...], training=False)\n\nplt.subplot(1,2,1)\nplt.imshow(photo, vmin=0, vmax=255) \n\nplt.subplot(1,2,2)\nplt.imshow(example_gen_output_y[0]) \n\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2023-06-25T06:28:43.395084Z","iopub.execute_input":"2023-06-25T06:28:43.395419Z","iopub.status.idle":"2023-06-25T06:28:44.177742Z","shell.execute_reply.started":"2023-06-25T06:28:43.395372Z","shell.execute_reply":"2023-06-25T06:28:44.176431Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Discriminator\n\nAs per the [paper](https://arxiv.org/pdf/1703.10593.pdf) on CycleGAN we will use a PatchGAN of 70x70.\nA PatchGAN will have <br>\nPatchGAN mathematics - https://sahiltinky94.medium.com/understanding-patchgan-9f3c8380c207","metadata":{}},{"cell_type":"code","source":"    def Discriminator():\n        # weight initialization\n        init = RandomNormal(stddev=0.02)\n        \n        # source image input\n        inp = tf.keras.layers.Input(shape=[256, 256, 3], name='input_image')\n        tar = tf.keras.layers.Input(shape=[256, 256, 3], name='target_image')\n        in_image = tf.keras.layers.concatenate([inp, tar])  # (batch_size, 256, 256, channels*2)\n        \n        # C64: 4x4 kernel Stride 2x2\n        d = Conv2D(64, (4,4), strides=(2,2), padding='same', kernel_initializer=init)(in_image)\n        d = LeakyReLU(alpha=0.2)(d)\n        # C128: 4x4 kernel Stride 2x2\n        d = Conv2D(128, (4,4), strides=(2,2), padding='same', kernel_initializer=init)(d)\n        d = tfa.layers.InstanceNormalization(axis=-1)(d)\n        d = LeakyReLU(alpha=0.2)(d)\n        # C256: 4x4 kernel Stride 2x2\n        d = Conv2D(256, (4,4), strides=(2,2), padding='same', kernel_initializer=init)(d)\n        d = tfa.layers.InstanceNormalization(axis=-1)(d)\n        d = LeakyReLU(alpha=0.2)(d)\n        # ZERO PADDING\n        d = tf.keras.layers.ZeroPadding2D()(d)\n        # second last output layer : 4x4 kernel but Stride 1x1\n        d = Conv2D(512, (4,4), strides=(1,1), padding='valid', kernel_initializer=init)(d)\n        d = tfa.layers.InstanceNormalization(axis=-1)(d)\n        d = LeakyReLU(alpha=0.2)(d)\n        # ZERO PADDING\n        d = tf.keras.layers.ZeroPadding2D()(d)\n        # patch output\n        patch_out = Conv2D(1, (4,4), strides=(1,1), padding='valid', kernel_initializer=init)(d)\n        \n        # define model\n        model = Model(inputs=[inp, tar], outputs=patch_out)\n        # compile model\n        return model","metadata":{"execution":{"iopub.status.busy":"2023-06-25T06:28:44.183335Z","iopub.execute_input":"2023-06-25T06:28:44.183711Z","iopub.status.idle":"2023-06-25T06:28:44.198198Z","shell.execute_reply.started":"2023-06-25T06:28:44.183679Z","shell.execute_reply":"2023-06-25T06:28:44.197226Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"discriminator_y = Discriminator()","metadata":{"execution":{"iopub.status.busy":"2023-06-25T06:28:44.199248Z","iopub.execute_input":"2023-06-25T06:28:44.199553Z","iopub.status.idle":"2023-06-25T06:28:44.381852Z","shell.execute_reply.started":"2023-06-25T06:28:44.199527Z","shell.execute_reply":"2023-06-25T06:28:44.380511Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"discriminator_y.summary()","metadata":{"execution":{"iopub.status.busy":"2023-06-25T06:28:44.383371Z","iopub.execute_input":"2023-06-25T06:28:44.383752Z","iopub.status.idle":"2023-06-25T06:28:44.429532Z","shell.execute_reply.started":"2023-06-25T06:28:44.383720Z","shell.execute_reply":"2023-06-25T06:28:44.428432Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"photo = sample_photo[0]*0.5 + 0.5\nexample_gen_output_y = generator_g(photo[tf.newaxis,...], training=False)\nexample_disc_out = discriminator_y([sample_photo, example_gen_output_y], training=False)\n\nprint(example_disc_out.shape)\n\nplt.figure(figsize=(10,10))\n\nplt.subplot(1,3,1)\nplt.imshow(photo, vmin=0, vmax=255) \n\nplt.subplot(1,3,2)\nplt.imshow(example_gen_output_y[0,...]) \n\nplt.subplot(1,3,3)\nm = example_disc_out[0,...,-1].numpy()*1000\nim = plt.imshow(m, vmin=-20, vmax=20, cmap='RdBu_r')\nplt.colorbar(im,fraction=0.046, pad=0.04)\n\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2023-06-25T06:28:44.430762Z","iopub.execute_input":"2023-06-25T06:28:44.431050Z","iopub.status.idle":"2023-06-25T06:28:45.805012Z","shell.execute_reply.started":"2023-06-25T06:28:44.431024Z","shell.execute_reply":"2023-06-25T06:28:45.803734Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"tpu = tf.distribute.cluster_resolver.TPUClusterResolver()\ntf.config.experimental_connect_to_cluster(tpu)\ntf.tpu.experimental.initialize_tpu_system(tpu)\nstrategy = tf.distribute.experimental.TPUStrategy(tpu)\nwith strategy.scope():\n    \n    generator_monet = Generator()\n    generator_photo = Generator()\n\n    discriminator_monet = Discriminator()\n    discriminator_photo = Discriminator()","metadata":{"execution":{"iopub.status.busy":"2023-06-25T06:32:37.694171Z","iopub.execute_input":"2023-06-25T06:32:37.694713Z","iopub.status.idle":"2023-06-25T06:33:04.917049Z","shell.execute_reply.started":"2023-06-25T06:32:37.694674Z","shell.execute_reply":"2023-06-25T06:33:04.915658Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"`tf.config.experimental_connect_to_cluster(tpu)`: This function establishes a connection between the local TensorFlow runtime and the TPU cluster specified by the tpu object. It sets up the necessary communication channels for data transfer and distributed training.\n\n`tf.tpu.experimental.initialize_tpu_system(tpu)`: This function initializes the TPU system. It handles the TPU-specific initialization steps, such as configuring the TPU devices and allocating necessary resources.\n\n`strategy = tf.distribute.experimental.TPUStrategy(tpu)`: This line creates an instance of tf.distribute.experimental.TPUStrategy using the tpu object. The strategy is initialized with the TPU cluster resolver, allowing for distributed training on TPUs.\n\nOnce these steps are executed, you can use the strategy object as a context manager (`with strategy.scope()`:) to define and train your model within the TPU strategy scope. This ensures that the model and its operations are distributed and executed efficiently across the TPU cores.","metadata":{}},{"cell_type":"code","source":"plt.figure(figsize=(8, 8))\n\nplt.subplot(121)\nplt.title('Monet Discriminator')\nplt.imshow(discriminator_monet(sample_monet,)[0, ..., -1], cmap='RdBu_r')\n\nplt.subplot(122)\nplt.title('Photo Discriminator')\nplt.imshow(discriminator_photo(sample_photo)[0, ..., -1], cmap='RdBu_r')\n\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2023-06-25T06:33:04.918918Z","iopub.execute_input":"2023-06-25T06:33:04.919242Z","iopub.status.idle":"2023-06-25T06:33:05.280725Z","shell.execute_reply.started":"2023-06-25T06:33:04.919213Z","shell.execute_reply":"2023-06-25T06:33:05.279220Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Loss Function\n\nHere we will have 3 types of losses:\n1. Generator Loss\n2. Discriminator Loss\n3. Cycle Consistency Loss","metadata":{}},{"cell_type":"code","source":"loss_obj = tf.keras.losses.BinaryCrossentropy(from_logits=True)","metadata":{"execution":{"iopub.status.busy":"2023-06-25T06:28:45.857849Z","iopub.status.idle":"2023-06-25T06:28:45.858207Z","shell.execute_reply.started":"2023-06-25T06:28:45.858029Z","shell.execute_reply":"2023-06-25T06:28:45.858046Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Discrminator Loss\n\n**The discriminator loss function takes 2 inputs;<br>\nFor the discriminator_photo will take as input:**<br>\nThe output of the discriminator_photo whose input is the real photo of the training set<br>\nThe output of the discriminator_photo whose input is the fake photo generated by the generator_photo<br>\n**For the discriminator_monet will take as input:**<br>\nThe output of the discriminator_monet whose input is the real Monet of the training set<br>\nThe output of the discriminator_monet whose input is the fake Monet generated by the generator_monet<br>\n*`The calculation of the loss has two components:\nreal_loss compare the real image with a matrix of 1. (All Ok)\ngenerate_loss compare the fake image with a matrix of 0 (All Fake)`*<br>\nSo the total_loss is 1/2 of the sum of the real_loss and the generate_loss","metadata":{}},{"cell_type":"code","source":"def discriminator_loss(real, generated):\n  real_loss = loss_obj(tf.ones_like(real), real)\n\n  generated_loss = loss_obj(tf.zeros_like(generated), generated)\n\n  total_disc_loss = real_loss + generated_loss\n\n  return total_disc_loss * 0.5","metadata":{"execution":{"iopub.status.busy":"2023-06-25T06:28:45.859114Z","iopub.status.idle":"2023-06-25T06:28:45.859459Z","shell.execute_reply.started":"2023-06-25T06:28:45.859276Z","shell.execute_reply":"2023-06-25T06:28:45.859293Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Generator Loss\n\nThere are two parts to the generator loss<br>\n1.) **Adversal loss** - Similar to the loss of DCGAN, where the input shall be compared to a matrix of ones.<br>\n2.) **Identity loss** - It is desired that if the generator_monet is executed with the image of the original monet painting, the result should be a very similar image, and also with the generator_photo and the original photo.<br>\n\nTherefore, the loss of identity forces what the generator generates to resemble the input.<br>\n\nIt takes as inputs, 2 images, the original image and the output of running the generator with the original image.<br>\nFor the loss of the generator_monet the function will take the training monet image and the output of the generator_monet with the same input (same_monet)<br>\nFor the loss of the generator_photo the function will take the training photo image and the output of the generator_photo with the same input (same_photo)<br>\nThe loss will be the mean absolute error between the real image and the generated one. \n","metadata":{}},{"cell_type":"code","source":"LAMBDA = 10","metadata":{"execution":{"iopub.status.busy":"2023-06-25T06:28:45.860663Z","iopub.status.idle":"2023-06-25T06:28:45.861006Z","shell.execute_reply.started":"2023-06-25T06:28:45.860828Z","shell.execute_reply":"2023-06-25T06:28:45.860844Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"The value of **LAMBDA** is a hyperparameter that can be adjusted during training to control the importance of the identity loss term relative to other components of the loss function. A higher value of **LAMBDA** places more emphasis on preserving the identity and may result in generated images that closely resemble the input images. Conversely, a lower value of **LAMBDA** reduces the impact of the identity loss term and allows more freedom for the generator to transform the input images.\n\nThe specific value of **LAMBDA** depends on the dataset, task requirements, and the desired balance between identity preservation and domain transformation. It is typically determined through experimentation and validation, finding the value that yields the best trade-off between image fidelity and domain translation quality.","metadata":{}},{"cell_type":"code","source":"# Adversial Loss\ndef generator_loss(generated): \n  return loss_obj(tf.ones_like(generated), generated)","metadata":{"execution":{"iopub.status.busy":"2023-06-25T06:28:45.862677Z","iopub.status.idle":"2023-06-25T06:28:45.863081Z","shell.execute_reply.started":"2023-06-25T06:28:45.862870Z","shell.execute_reply":"2023-06-25T06:28:45.862889Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def identity_loss(real_image, same_image):\n  loss = tf.reduce_mean(tf.abs(real_image - same_image))\n  return LAMBDA * 0.5 * loss\n# If you run the zebra-to-horse model on a horse or the horse-to-zebra model on a zebra, \n# it should not modify the image much since the image already contains the target class.","metadata":{"execution":{"iopub.status.busy":"2023-06-25T06:28:45.864462Z","iopub.status.idle":"2023-06-25T06:28:45.864804Z","shell.execute_reply.started":"2023-06-25T06:28:45.864628Z","shell.execute_reply":"2023-06-25T06:28:45.864644Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Cycle Consistency Loss","metadata":{}},{"cell_type":"code","source":"def calc_cycle_loss(real_image, cycled_image):\n  loss1 = tf.reduce_mean(tf.abs(real_image - cycled_image))\n  return LAMBDA * loss1","metadata":{"execution":{"iopub.status.busy":"2023-06-25T06:28:45.865721Z","iopub.status.idle":"2023-06-25T06:28:45.866056Z","shell.execute_reply.started":"2023-06-25T06:28:45.865883Z","shell.execute_reply":"2023-06-25T06:28:45.865899Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]}]}