{"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":"import os\nimport math\nimport random\nimport cv2\nimport matplotlib.pyplot as plt\nimport numpy as np\nimport tensorflow as tf\nfrom tensorflow import keras\nfrom tensorflow.keras import layers\nimport tensorflow_addons as tfa\nfrom kaggle_datasets import KaggleDatasets\nfrom keras.preprocessing.image import load_img, img_to_array\nfrom keras.applications.vgg16 import preprocess_input, decode_predictions, VGG16\nfrom keras.models import Model\nfrom pickle import dump\n\n\nuse_vgg = True\nvgg_frozen_layers = 20 # integer [0-13]\n\n\ntry:\n    tpu = tf.distribute.cluster_resolver.TPUClusterResolver()\n    print('Device:', tpu.master())\n    tf.config.experimental_connect_to_cluster(tpu)\n    tf.tpu.experimental.initialize_tpu_system(tpu)\n    strategy = tf.distribute.experimental.TPUStrategy(tpu)\nexcept:\n    strategy = tf.distribute.get_strategy()\nprint('Number of replicas:', strategy.num_replicas_in_sync)\n\nAUTOTUNE = tf.data.experimental.AUTOTUNE\n    \n\n","metadata":{"_uuid":"d629ff2d2480ee46fbb7e2d37f6b5fab8052498a","_cell_guid":"79c7e3d0-c299-4dcb-8224-4455121ee9b0","execution":{"iopub.status.busy":"2021-07-25T14:26:33.455191Z","iopub.execute_input":"2021-07-25T14:26:33.455633Z","iopub.status.idle":"2021-07-25T14:26:33.466209Z","shell.execute_reply.started":"2021-07-25T14:26:33.455598Z","shell.execute_reply":"2021-07-25T14:26:33.465338Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Load in the data\n\nWe want to keep our photo dataset and our Monet dataset separate. First, load in the filenames of the TFRecords.\n\n**if yoy want to train with TPU for quicker results, do it after chhecking EDA as it requires to remove the second dataset (real-sg-256):**\n* there is an issue with running TPU with multiple datasets in kaggle. do the following after checking out EDA part\n* change GCS_PATH to KaggleDatasets().get_gcs_path()\n* remove real-sg-25 dataset from \"input\" (right side of the screen)\n* do not run EDA part (it will pop an error. you can change value of \n* continue next part and run all blocks","metadata":{}},{"cell_type":"code","source":"# GCS_PATH = KaggleDatasets().get_gcs_path()  # only valid if there is a single dataset input\nGCS_PATH = '../input/gan-getting-started'","metadata":{"execution":{"iopub.status.busy":"2021-07-25T14:24:28.921225Z","iopub.execute_input":"2021-07-25T14:24:28.921685Z","iopub.status.idle":"2021-07-25T14:24:28.924989Z","shell.execute_reply.started":"2021-07-25T14:24:28.921652Z","shell.execute_reply":"2021-07-25T14:24:28.924271Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"MONET_FILENAMES = tf.io.gfile.glob(str(GCS_PATH + '/monet_tfrec/*.tfrec'))\nprint('Monet TFRecord Files:', len(MONET_FILENAMES))\n\nPHOTO_FILENAMES = tf.io.gfile.glob(str(GCS_PATH + '/photo_tfrec/*.tfrec'))\nprint('Photo TFRecord Files:', len(PHOTO_FILENAMES))","metadata":{"execution":{"iopub.status.busy":"2021-07-25T14:24:28.926329Z","iopub.execute_input":"2021-07-25T14:24:28.926766Z","iopub.status.idle":"2021-07-25T14:24:28.954885Z","shell.execute_reply.started":"2021-07-25T14:24:28.926736Z","shell.execute_reply":"2021-07-25T14:24:28.953856Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"All the images for the competition are already sized to 256x256. As these images are RGB images, set the channel to 3. Additionally, we need to scale the images to a [-1, 1] scale. Because we are building a generative model, we don't need the labels or the image id so we'll only return the image from the TFRecord.","metadata":{}},{"cell_type":"code","source":"IMAGE_SIZE = [256, 256]\n\ndef decode_image(image):\n    image = tf.image.decode_jpeg(image, channels=3)\n    image = (tf.cast(image, tf.float32) / 127.5) - 1\n    image = tf.reshape(image, [*IMAGE_SIZE, 3])\n    return image\n\ndef read_tfrecord(example):\n    tfrecord_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, tfrecord_format)\n    image = decode_image(example['image'])\n    return image","metadata":{"execution":{"iopub.status.busy":"2021-07-25T14:24:28.956332Z","iopub.execute_input":"2021-07-25T14:24:28.956726Z","iopub.status.idle":"2021-07-25T14:24:28.968535Z","shell.execute_reply.started":"2021-07-25T14:24:28.956693Z","shell.execute_reply":"2021-07-25T14:24:28.967003Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def load_dataset(filenames, labeled=True, ordered=False):\n    dataset = tf.data.TFRecordDataset(filenames)\n    dataset = dataset.map(read_tfrecord, num_parallel_calls=AUTOTUNE)\n    return dataset\n\nmonet_ds = load_dataset(MONET_FILENAMES, labeled=True).batch(1)\nphoto_ds = load_dataset(PHOTO_FILENAMES, labeled=True).batch(1)\n\nexample_monet = next(iter(monet_ds))\nexample_photo = next(iter(photo_ds))","metadata":{"execution":{"iopub.status.busy":"2021-07-25T14:24:32.378041Z","iopub.execute_input":"2021-07-25T14:24:32.378499Z","iopub.status.idle":"2021-07-25T14:24:32.813168Z","shell.execute_reply.started":"2021-07-25T14:24:32.378423Z","shell.execute_reply":"2021-07-25T14:24:32.811816Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# EDA\nhere we will look at some images, and take a deeper dive on some examples by comparing Monet images and photo images by:\n* RGB histogram graph, \n* visualizations of each channel, \n* grayscale visualizations. \n\nfor this part we decided to use an image not from given dataset of photos, but specifically a photo of the location of famous painting \"San-Giorgio mariore at dusk\", taken at dusk hours,  compared with the painting. ","metadata":{}},{"cell_type":"code","source":"\"\"\"\ndecalre visualization funcs \n\"\"\"\ndef channels_visualization(image_path, figsize=(16, 4)):\n    plt.figure(figsize=figsize)\n    \n    img = cv2.imread(image_path)\n    img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) \n    plt.subplot(1, 4, 1)\n    plt.imshow(img)\n    plt.axis('off')\n    \n    for i in range(3):\n        plt.subplot(1, 4, i + 2)\n        tmp_img = np.full_like(img, 0)\n        tmp_img[:, :, i] = img[:, :, i]\n        plt.imshow(tmp_img)\n        plt.xlim(0, 255)\n        plt.xticks([])\n        plt.yticks([])\n    plt.show()\n    \n\ndef grayscale_visualization(image_path, figsize=(16, 4)):\n    plt.figure(figsize=figsize)\n    \n    img = cv2.imread(image_path)\n    img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) \n    plt.subplot(1, 3, 1)\n    plt.imshow(img)\n    plt.axis('off')\n    \n    plt.subplot(1, 3, 2)\n    tmp_img = np.full_like(img, 0)\n    for i in range(3):\n        tmp_img[:, :, i] = img.mean(axis=-1)\n    plt.imshow(tmp_img)\n    plt.axis('off')\n    \n    img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)\n    plt.subplot(1,3,3)\n    plt.imshow(img)\n    plt.axis(\"off\")\n    \n    plt.show()\n    \n    \ndef color_graph(image_path, figsize=(16, 4)):\n    plt.figure(figsize=figsize)\n    \n    img = cv2.imread(image_path)\n    img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) \n    plt.subplot(1, 2, 1)\n    plt.imshow(img)\n    plt.axis('off')\n    \n    chans = cv2.split(img)\n    colors = (\"b\", \"g\", \"r\")\n    plt.subplot(1, 2, 2)\n    plt.title(\"'Flattened' Color Histogram\")\n    plt.xlabel(\"Bins\")\n    plt.ylabel(\"# of Pixels\")\n    features = []\n    # loop over the image channels\n    for (chan, color) in zip(chans, colors):\n        # create a histogram for the current channel and\n        # concatenate the resulting histograms for each\n        # channel\n        hist = cv2.calcHist([chan], [0], None, [256], [0, 256])\n        features.extend(hist)\n        # plot the histogram\n        plt.plot(hist, color = color)\n        plt.xlim([0, 256])\n    \n    plt.show()\n    \n    \ndef batch_visualization(path, n_images, is_random=True, figsize=(16, 16)):\n    plt.figure(figsize=figsize)\n    \n    w = int(n_images ** .5)\n    h = math.ceil(n_images / w)\n    \n    all_names = os.listdir(path)\n    \n    image_names = all_names[:n_images]\n    if is_random:\n        image_names = random.sample(all_names, n_images)\n    \n    for ind, image_name in enumerate(image_names):\n        img = cv2.imread(os.path.join(path, image_name))\n        img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) \n        plt.subplot(h, w, ind + 1)\n        plt.imshow(img)\n        plt.axis('off')\n    \n    plt.show()","metadata":{"execution":{"iopub.status.busy":"2021-07-25T14:24:39.663962Z","iopub.execute_input":"2021-07-25T14:24:39.664343Z","iopub.status.idle":"2021-07-25T14:24:39.687134Z","shell.execute_reply.started":"2021-07-25T14:24:39.664312Z","shell.execute_reply":"2021-07-25T14:24:39.685936Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"visually checkout some examples from each ds","metadata":{}},{"cell_type":"code","source":"base_path = '../input/gan-getting-started/'\nmonet_path = os.path.join(base_path, 'monet_jpg')\nphoto_path = os.path.join(base_path, 'photo_jpg')","metadata":{"execution":{"iopub.status.busy":"2021-07-25T14:24:42.938567Z","iopub.execute_input":"2021-07-25T14:24:42.939073Z","iopub.status.idle":"2021-07-25T14:24:42.943678Z","shell.execute_reply.started":"2021-07-25T14:24:42.939041Z","shell.execute_reply":"2021-07-25T14:24:42.942916Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"batch_visualization(monet_path,9)","metadata":{"execution":{"iopub.status.busy":"2021-07-25T14:24:45.032964Z","iopub.execute_input":"2021-07-25T14:24:45.033603Z","iopub.status.idle":"2021-07-25T14:24:46.359154Z","shell.execute_reply.started":"2021-07-25T14:24:45.033549Z","shell.execute_reply":"2021-07-25T14:24:46.356026Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"batch_visualization(photo_path,9)","metadata":{"execution":{"iopub.status.busy":"2021-07-25T14:24:51.089743Z","iopub.execute_input":"2021-07-25T14:24:51.090111Z","iopub.status.idle":"2021-07-25T14:24:52.290435Z","shell.execute_reply.started":"2021-07-25T14:24:51.090083Z","shell.execute_reply":"2021-07-25T14:24:52.289579Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"\"\"\" load image from each dataset \"\"\"\n\nmonet_sg = r\"../input/gan-getting-started/monet_jpg/89d970411d.jpg\"\nphoto_sg = r\"../input/real-sg-256/san_giorgio_maggiore_at_dusk_256.jpg\"  # use picture of san-giorgio maggiore, manually added dataset","metadata":{"execution":{"iopub.status.busy":"2021-07-25T14:25:00.731404Z","iopub.execute_input":"2021-07-25T14:25:00.732005Z","iopub.status.idle":"2021-07-25T14:25:00.737166Z","shell.execute_reply.started":"2021-07-25T14:25:00.731967Z","shell.execute_reply":"2021-07-25T14:25:00.73584Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"channels visualizatons: ","metadata":{}},{"cell_type":"code","source":"print(\"Monet: \")\nchannels_visualization(monet_sg)\nprint(\"\\nPhoto: \")\nchannels_visualization(photo_sg)","metadata":{"execution":{"iopub.status.busy":"2021-07-25T14:25:40.419232Z","iopub.execute_input":"2021-07-25T14:25:40.419693Z","iopub.status.idle":"2021-07-25T14:25:41.071417Z","shell.execute_reply.started":"2021-07-25T14:25:40.419655Z","shell.execute_reply":"2021-07-25T14:25:41.070087Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"grayscale visualization: ","metadata":{}},{"cell_type":"code","source":"print(\"Monet: \")\ngrayscale_visualization(monet_sg)\nprint(\"\\nPhoto: \")\ngrayscale_visualization(photo_sg)","metadata":{"execution":{"iopub.status.busy":"2021-07-25T14:25:49.595925Z","iopub.execute_input":"2021-07-25T14:25:49.596333Z","iopub.status.idle":"2021-07-25T14:25:50.202661Z","shell.execute_reply.started":"2021-07-25T14:25:49.5963Z","shell.execute_reply":"2021-07-25T14:25:50.20181Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"RGB histogram graph","metadata":{}},{"cell_type":"code","source":"print(\"Monet: \")\ncolor_graph(monet_sg)\nprint(\"\\nPhoto: \")\ncolor_graph(photo_sg)","metadata":{"execution":{"iopub.status.busy":"2021-07-25T14:25:52.946664Z","iopub.execute_input":"2021-07-25T14:25:52.947156Z","iopub.status.idle":"2021-07-25T14:25:53.480541Z","shell.execute_reply.started":"2021-07-25T14:25:52.947125Z","shell.execute_reply":"2021-07-25T14:25:53.479572Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Build the generator\n\nWe'll be using a UNET architecture for our CycleGAN. To build our generator, let's first define our `downsample` and `upsample` methods.\n\nThe `downsample`, as the name suggests, reduces the 2D dimensions, the width and height, of the image by the stride. The stride is the length of the step the filter takes. Since the stride is 2, the filter is applied to every other pixel, hence reducing the weight and height by 2.\n\nWe'll be using an instance normalization instead of batch normalization. As the instance normalization is not standard in the TensorFlow API, we'll use the layer from TensorFlow Add-ons.","metadata":{}},{"cell_type":"code","source":"OUTPUT_CHANNELS = 3\n\ndef downsample(filters, size, apply_instancenorm=True):\n    initializer = tf.random_normal_initializer(0., 0.02)\n    gamma_init = keras.initializers.RandomNormal(mean=0.0, stddev=0.02)\n\n    result = keras.Sequential()\n    result.add(layers.Conv2D(filters, size, strides=2, padding='same',\n                             kernel_initializer=initializer, use_bias=False))\n\n    if apply_instancenorm:\n        result.add(tfa.layers.InstanceNormalization(gamma_initializer=gamma_init))\n\n    result.add(layers.LeakyReLU())\n\n    return result","metadata":{"execution":{"iopub.status.busy":"2021-07-25T14:25:59.451751Z","iopub.execute_input":"2021-07-25T14:25:59.452105Z","iopub.status.idle":"2021-07-25T14:25:59.459926Z","shell.execute_reply.started":"2021-07-25T14:25:59.452076Z","shell.execute_reply":"2021-07-25T14:25:59.4587Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"`Upsample` does the opposite of downsample and increases the dimensions of the of the image. `Conv2DTranspose` does basically the opposite of a `Conv2D` layer.","metadata":{}},{"cell_type":"code","source":"def upsample(filters, size, apply_dropout=False):\n    initializer = tf.random_normal_initializer(0., 0.02)\n    gamma_init = keras.initializers.RandomNormal(mean=0.0, stddev=0.02)\n\n    result = keras.Sequential()\n    result.add(layers.Conv2DTranspose(filters, size, strides=2,\n                                      padding='same',\n                                      kernel_initializer=initializer,\n                                      use_bias=False))\n\n    result.add(tfa.layers.InstanceNormalization(gamma_initializer=gamma_init))\n\n    if apply_dropout:\n        result.add(layers.Dropout(0.5))\n\n    result.add(layers.ReLU())\n\n    return result","metadata":{"execution":{"iopub.status.busy":"2021-07-25T14:26:01.468295Z","iopub.execute_input":"2021-07-25T14:26:01.468699Z","iopub.status.idle":"2021-07-25T14:26:01.476662Z","shell.execute_reply.started":"2021-07-25T14:26:01.468667Z","shell.execute_reply":"2021-07-25T14:26:01.475305Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Let's build our generator!\n\nThe generator first downsamples the input image and then upsample while establishing long skip connections. Skip connections are a way to help bypass the vanishing gradient problem by concatenating the output of a layer to multiple layers instead of only one. Here we concatenate the output of the downsample layer to the upsample layer in a symmetrical fashion.","metadata":{}},{"cell_type":"code","source":"def Generator():\n    inputs = layers.Input(shape=[256,256,3])\n\n    # bs = batch size\n    down_stack = [\n        downsample(64, 4, apply_instancenorm=False), # (bs, 128, 128, 64)\n        downsample(128, 4), # (bs, 64, 64, 128)\n        downsample(256, 4), # (bs, 32, 32, 256)\n        downsample(512, 4), # (bs, 16, 16, 512)\n        downsample(512, 4), # (bs, 8, 8, 512)\n        downsample(512, 4), # (bs, 4, 4, 512)\n        downsample(512, 4), # (bs, 2, 2, 512)\n        downsample(512, 4), # (bs, 1, 1, 512)\n    ]\n\n    up_stack = [\n        upsample(512, 4, apply_dropout=True), # (bs, 2, 2, 1024)\n        upsample(512, 4, apply_dropout=True), # (bs, 4, 4, 1024)\n        upsample(512, 4, apply_dropout=True), # (bs, 8, 8, 1024)\n        upsample(512, 4), # (bs, 16, 16, 1024)\n        upsample(256, 4), # (bs, 32, 32, 512)\n        upsample(128, 4), # (bs, 64, 64, 256)\n        upsample(64, 4), # (bs, 128, 128, 128)\n    ]\n\n    initializer = tf.random_normal_initializer(0., 0.02)\n    last = layers.Conv2DTranspose(OUTPUT_CHANNELS, 4,\n                                  strides=2,\n                                  padding='same',\n                                  kernel_initializer=initializer,\n                                  activation='tanh') # (bs, 256, 256, 3)\n\n    x = inputs\n\n    # Downsampling through the model\n    skips = []\n    for down in down_stack:\n        x = down(x)\n        skips.append(x)\n\n    skips = reversed(skips[:-1])\n\n    # Upsampling and establishing the skip connections\n    for up, skip in zip(up_stack, skips):\n        x = up(x)\n        x = layers.Concatenate()([x, skip])\n\n    x = last(x)\n\n    return keras.Model(inputs=inputs, outputs=x)","metadata":{"execution":{"iopub.status.busy":"2021-07-25T14:26:03.957267Z","iopub.execute_input":"2021-07-25T14:26:03.957672Z","iopub.status.idle":"2021-07-25T14:26:03.971904Z","shell.execute_reply.started":"2021-07-25T14:26:03.957639Z","shell.execute_reply":"2021-07-25T14:26:03.970812Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Build the discriminator\n\nThe discriminator takes in the input image and classifies it as real or fake (generated). Instead of outputing a single node, the discriminator outputs a smaller 2D image with higher pixel values indicating a real classification and lower values indicating a fake classification.","metadata":{}},{"cell_type":"code","source":"def Discriminator():\n    initializer = tf.random_normal_initializer(0., 0.02)\n    gamma_init = keras.initializers.RandomNormal(mean=0.0, stddev=0.02)\n\n    inp = layers.Input(shape=[256, 256, 3], name='input_image')\n\n    x = inp\n\n    down1 = downsample(64, 4, False)(x) # (bs, 128, 128, 64)\n    down2 = downsample(128, 4)(down1) # (bs, 64, 64, 128)\n    down3 = downsample(256, 4)(down2) # (bs, 32, 32, 256)\n\n    zero_pad1 = layers.ZeroPadding2D()(down3) # (bs, 34, 34, 256)\n    conv = layers.Conv2D(512, 4, strides=1,\n                         kernel_initializer=initializer,\n                         use_bias=False)(zero_pad1) # (bs, 31, 31, 512)\n\n    norm1 = tfa.layers.InstanceNormalization(gamma_initializer=gamma_init)(conv)\n\n    leaky_relu = layers.LeakyReLU()(norm1)\n\n    zero_pad2 = layers.ZeroPadding2D()(leaky_relu) # (bs, 33, 33, 512)\n\n    last = layers.Conv2D(1, 4, strides=1,\n                         kernel_initializer=initializer)(zero_pad2) # (bs, 30, 30, 1)\n\n    return tf.keras.Model(inputs=inp, outputs=last)","metadata":{"execution":{"iopub.status.busy":"2021-07-25T14:26:07.770929Z","iopub.execute_input":"2021-07-25T14:26:07.771311Z","iopub.status.idle":"2021-07-25T14:26:07.783686Z","shell.execute_reply.started":"2021-07-25T14:26:07.771277Z","shell.execute_reply":"2021-07-25T14:26:07.78265Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def vgg_discrimnator():  \n    initializer = tf.random_normal_initializer(0., 0.02)\n    gamma_init = keras.initializers.RandomNormal(mean=0.0, stddev=0.02)\n\n    # load model without classifier layers\n    model = VGG16(include_top=False, input_shape=(256, 256, 3))  #weights=None\n    \n    # mark loaded layers as not trainable\n    for count, layer in enumerate(model.layers):\n        if count > vgg_frozen_layers:\n            break\n        layer.trainable = False\n        \n    conv = layers.Conv2D(512, 3, strides=1,\n                         kernel_initializer=initializer,\n                         use_bias=False)(model.layers[-6].output) # (bs, 31, 31, 512)\n\n    norm1 = tfa.layers.InstanceNormalization(gamma_initializer=gamma_init)(conv)\n\n    leaky_relu = layers.LeakyReLU()(norm1)\n\n    zero_pad2 = layers.ZeroPadding2D()(leaky_relu) # (bs, 33, 33, 512)\n\n    output = layers.Conv2D(1, 3, strides=1,\n                         kernel_initializer=initializer)(zero_pad2) # (bs, 30, 30, 1)\n\n    model = Model(inputs=model.inputs, outputs=output)\n    return model","metadata":{"execution":{"iopub.status.busy":"2021-07-25T14:26:09.136284Z","iopub.execute_input":"2021-07-25T14:26:09.137163Z","iopub.status.idle":"2021-07-25T14:26:09.145998Z","shell.execute_reply.started":"2021-07-25T14:26:09.137118Z","shell.execute_reply":"2021-07-25T14:26:09.145067Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def normal_discriminator():\n    initializer = tf.random_normal_initializer(0., 0.02)\n    gamma_init = keras.initializers.RandomNormal(mean=0.0, stddev=0.02)\n\n    inp = layers.Input(shape=[256, 256, 3], name='input_image')\n\n    x = inp\n\n    down1 = downsample(64, 4, False)(x) # (bs, 128, 128, 64)\n    down2 = downsample(128, 4)(down1) # (bs, 64, 64, 128)\n    down3 = downsample(256, 4)(down2) # (bs, 32, 32, 256)\n\n    zero_pad1 = layers.ZeroPadding2D()(down3) # (bs, 34, 34, 256)\n    conv = layers.Conv2D(512, 4, strides=1,\n                         kernel_initializer=initializer,\n                         use_bias=False)(zero_pad1) # (bs, 31, 31, 512)\n\n    norm1 = tfa.layers.InstanceNormalization(gamma_initializer=gamma_init)(conv)\n\n    leaky_relu = layers.LeakyReLU()(norm1)\n\n    zero_pad2 = layers.ZeroPadding2D()(leaky_relu) # (bs, 33, 33, 512)\n\n    output = layers.Conv2D(1, 4, strides=1,\n                         kernel_initializer=initializer)(zero_pad2) # (bs, 30, 30, 1)\n\n    return tf.keras.Model(inputs=inp, outputs=output)\n#     return output","metadata":{"execution":{"iopub.status.busy":"2021-07-25T14:26:10.518477Z","iopub.execute_input":"2021-07-25T14:26:10.519172Z","iopub.status.idle":"2021-07-25T14:26:10.528806Z","shell.execute_reply.started":"2021-07-25T14:26:10.519132Z","shell.execute_reply":"2021-07-25T14:26:10.527563Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def Discriminator_vgg():\n    initializer = tf.random_normal_initializer(0., 0.02)\n    gamma_init = keras.initializers.RandomNormal(mean=0.0, stddev=0.02)\n    inp = layers.Input(shape=[256, 256, 3], name='input_image')\n    x = inp\n    normal_model = normal_discriminator()\n    vgg_model = vgg_discrimnator()\n#     mergedOut = Concatenate()([normal_model.output,vgg_model.output])\n    out1 = normal_model(x)    \n    out2 = vgg_model(x)    \n    mergedOut = layers.Concatenate()([out1,out2])    \n    mergedOut = layers.Conv2D(1, 1, strides=1,\n                         kernel_initializer=initializer,\n                         use_bias=False)(mergedOut)\n    \n    \n    merged_model = Model(inp,mergedOut)\n    return merged_model ","metadata":{"execution":{"iopub.status.busy":"2021-07-25T14:26:12.78349Z","iopub.execute_input":"2021-07-25T14:26:12.784092Z","iopub.status.idle":"2021-07-25T14:26:12.790987Z","shell.execute_reply.started":"2021-07-25T14:26:12.784055Z","shell.execute_reply":"2021-07-25T14:26:12.790145Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"with strategy.scope():\n    monet_generator = Generator() # transforms photos to Monet-esque paintings\n    photo_generator = Generator() # transforms Monet paintings to be more like photos\n    \n    if not use_vgg:\n        monet_discriminator = Discriminator() # differentiates real Monet paintings and generated Monet paintings\n        photo_discriminator = Discriminator() # differentiates real photos and generated photos\n    else:\n        monet_discriminator = Discriminator_vgg() # differentiates real Monet paintings and generated Monet paintings\n        photo_discriminator = Discriminator_vgg() # differentiates real photos and generated photos\n        ","metadata":{"execution":{"iopub.status.busy":"2021-07-25T14:26:45.587577Z","iopub.execute_input":"2021-07-25T14:26:45.588187Z","iopub.status.idle":"2021-07-25T14:26:52.505796Z","shell.execute_reply.started":"2021-07-25T14:26:45.588143Z","shell.execute_reply":"2021-07-25T14:26:52.504761Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# show output of untrained Generator \nto_monet = monet_generator(example_photo)\n\nplt.subplot(1, 2, 1)\nplt.title(\"Original Photo\")\nplt.imshow(example_photo[0] * 0.5 + 0.5)\n\nplt.subplot(1, 2, 2)\nplt.title(\"Pusedo-monet Photo\")\nplt.imshow(to_monet[0] * 0.5 + 0.5)\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2021-07-25T14:27:14.632931Z","iopub.execute_input":"2021-07-25T14:27:14.63337Z","iopub.status.idle":"2021-07-25T14:27:15.37334Z","shell.execute_reply.started":"2021-07-25T14:27:14.633314Z","shell.execute_reply":"2021-07-25T14:27:15.372498Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Build the CycleGAN model\n\nWe will subclass a `tf.keras.Model` so that we can run `fit()` later to train our model. During the training step, the model transforms a photo to a Monet painting and then back to a photo. The difference between the original photo and the twice-transformed photo is the cycle-consistency loss. We want the original photo and the twice-transformed photo to be similar to one another.\n\nThe losses are defined in the next section.","metadata":{}},{"cell_type":"code","source":"class CycleGan(keras.Model):\n    def __init__(\n        self,\n        monet_generator,\n        photo_generator,\n        monet_discriminator,\n        photo_discriminator,\n        lambda_cycle=10,\n    ):\n        super(CycleGan, self).__init__()\n        self.m_gen = monet_generator\n        self.p_gen = photo_generator\n        self.m_disc = monet_discriminator\n        self.p_disc = photo_discriminator\n        self.lambda_cycle = lambda_cycle\n        \n    def compile(\n        self,\n        m_gen_optimizer,\n        p_gen_optimizer,\n        m_disc_optimizer,\n        p_disc_optimizer,\n        gen_loss_fn,\n        disc_loss_fn,\n        cycle_loss_fn,\n        identity_loss_fn\n    ):\n        super(CycleGan, self).compile()\n        self.m_gen_optimizer = m_gen_optimizer\n        self.p_gen_optimizer = p_gen_optimizer\n        self.m_disc_optimizer = m_disc_optimizer\n        self.p_disc_optimizer = p_disc_optimizer\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    def train_step(self, batch_data):\n        real_monet, real_photo = batch_data\n        \n        with tf.GradientTape(persistent=True) as tape:\n            # photo to monet back to photo\n            fake_monet = self.m_gen(real_photo, training=True)\n            cycled_photo = self.p_gen(fake_monet, training=True)\n\n            # monet to photo back to monet\n            fake_photo = self.p_gen(real_monet, training=True)\n            cycled_monet = self.m_gen(fake_photo, training=True)\n\n            # generating itself\n            same_monet = self.m_gen(real_monet, training=True)\n            same_photo = self.p_gen(real_photo, training=True)\n\n            # discriminator used to check, inputing real images\n            disc_real_monet = self.m_disc(real_monet, training=True)\n            disc_real_photo = self.p_disc(real_photo, training=True)\n\n            # discriminator used to check, inputing fake images\n            disc_fake_monet = self.m_disc(fake_monet, training=True)\n            disc_fake_photo = self.p_disc(fake_photo, training=True)\n\n            # evaluates generator loss\n            monet_gen_loss = self.gen_loss_fn(disc_fake_monet)\n            photo_gen_loss = self.gen_loss_fn(disc_fake_photo)\n\n            # evaluates total cycle consistency loss\n            total_cycle_loss = self.cycle_loss_fn(real_monet, cycled_monet, self.lambda_cycle) + self.cycle_loss_fn(real_photo, cycled_photo, self.lambda_cycle)\n\n            # evaluates total generator loss\n            total_monet_gen_loss = monet_gen_loss + total_cycle_loss + self.identity_loss_fn(real_monet, same_monet, self.lambda_cycle)\n            total_photo_gen_loss = photo_gen_loss + total_cycle_loss + self.identity_loss_fn(real_photo, same_photo, self.lambda_cycle)\n\n            # evaluates discriminator loss\n            monet_disc_loss = self.disc_loss_fn(disc_real_monet, disc_fake_monet)\n            photo_disc_loss = self.disc_loss_fn(disc_real_photo, disc_fake_photo)\n\n        # Calculate the gradients for generator and discriminator\n        monet_generator_gradients = tape.gradient(total_monet_gen_loss,\n                                                  self.m_gen.trainable_variables)\n        photo_generator_gradients = tape.gradient(total_photo_gen_loss,\n                                                  self.p_gen.trainable_variables)\n\n        monet_discriminator_gradients = tape.gradient(monet_disc_loss,\n                                                      self.m_disc.trainable_variables)\n        photo_discriminator_gradients = tape.gradient(photo_disc_loss,\n                                                      self.p_disc.trainable_variables)\n\n        # Apply the gradients to the optimizer\n        self.m_gen_optimizer.apply_gradients(zip(monet_generator_gradients,\n                                                 self.m_gen.trainable_variables))\n\n        self.p_gen_optimizer.apply_gradients(zip(photo_generator_gradients,\n                                                 self.p_gen.trainable_variables))\n\n        self.m_disc_optimizer.apply_gradients(zip(monet_discriminator_gradients,\n                                                  self.m_disc.trainable_variables))\n\n        self.p_disc_optimizer.apply_gradients(zip(photo_discriminator_gradients,\n                                                  self.p_disc.trainable_variables))\n        \n        return {\n            \"monet_gen_loss\": total_monet_gen_loss,\n            \"photo_gen_loss\": total_photo_gen_loss,\n            \"monet_disc_loss\": monet_disc_loss,\n            \"photo_disc_loss\": photo_disc_loss\n        }","metadata":{"execution":{"iopub.status.busy":"2021-07-25T14:28:08.865181Z","iopub.execute_input":"2021-07-25T14:28:08.865672Z","iopub.status.idle":"2021-07-25T14:28:08.885869Z","shell.execute_reply.started":"2021-07-25T14:28:08.865633Z","shell.execute_reply":"2021-07-25T14:28:08.884739Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Define loss functions\n\nThe discriminator loss function below compares real images to a matrix of 1s and fake images to a matrix of 0s. The perfect discriminator will output all 1s for real images and all 0s for fake images. The discriminator loss outputs the average of the real and generated loss.","metadata":{}},{"cell_type":"code","source":"with strategy.scope():\n    def discriminator_loss(real, generated):\n        real_loss = tf.keras.losses.BinaryCrossentropy(from_logits=True, reduction=tf.keras.losses.Reduction.NONE)(tf.ones_like(real), real)\n\n        generated_loss = tf.keras.losses.BinaryCrossentropy(from_logits=True, reduction=tf.keras.losses.Reduction.NONE)(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":"2021-07-25T14:28:11.065385Z","iopub.execute_input":"2021-07-25T14:28:11.065829Z","iopub.status.idle":"2021-07-25T14:28:11.073334Z","shell.execute_reply.started":"2021-07-25T14:28:11.065789Z","shell.execute_reply":"2021-07-25T14:28:11.07172Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"The generator wants to fool the discriminator into thinking the generated image is real. The perfect generator will have the discriminator output only 1s. Thus, it compares the generated image to a matrix of 1s to find the loss.","metadata":{}},{"cell_type":"code","source":"with strategy.scope():\n    def generator_loss(generated):\n        return tf.keras.losses.BinaryCrossentropy(from_logits=True, reduction=tf.keras.losses.Reduction.NONE)(tf.ones_like(generated), generated)","metadata":{"execution":{"iopub.status.busy":"2021-07-25T14:28:12.941413Z","iopub.execute_input":"2021-07-25T14:28:12.941847Z","iopub.status.idle":"2021-07-25T14:28:12.947715Z","shell.execute_reply.started":"2021-07-25T14:28:12.941813Z","shell.execute_reply":"2021-07-25T14:28:12.946681Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"We want our original photo and the twice transformed photo to be similar to one another. Thus, we can calculate the cycle consistency loss be finding the average of their difference.","metadata":{}},{"cell_type":"code","source":"with strategy.scope():\n    def calc_cycle_loss(real_image, cycled_image, LAMBDA):\n        loss1 = tf.reduce_mean(tf.abs(real_image - cycled_image))\n\n        return LAMBDA * loss1","metadata":{"execution":{"iopub.status.busy":"2021-07-25T14:28:14.268427Z","iopub.execute_input":"2021-07-25T14:28:14.269004Z","iopub.status.idle":"2021-07-25T14:28:14.275049Z","shell.execute_reply.started":"2021-07-25T14:28:14.268957Z","shell.execute_reply":"2021-07-25T14:28:14.27363Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"The identity loss compares the image with its generator (i.e. photo with photo generator). If given a photo as input, we want it to generate the same image as the image was originally a photo. The identity loss compares the input with the output of the generator.","metadata":{}},{"cell_type":"code","source":"with strategy.scope():\n    def identity_loss(real_image, same_image, LAMBDA):\n        loss = tf.reduce_mean(tf.abs(real_image - same_image))\n        return LAMBDA * 0.5 * loss","metadata":{"execution":{"iopub.status.busy":"2021-07-25T14:28:15.505718Z","iopub.execute_input":"2021-07-25T14:28:15.506125Z","iopub.status.idle":"2021-07-25T14:28:15.511165Z","shell.execute_reply.started":"2021-07-25T14:28:15.506088Z","shell.execute_reply":"2021-07-25T14:28:15.510124Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Train the CycleGAN\n\nLet's compile our model. Since we used `tf.keras.Model` to build our CycleGAN, we can just ude the `fit` function to train our model.","metadata":{}},{"cell_type":"code","source":"with strategy.scope():\n    monet_generator_optimizer = tf.keras.optimizers.Adam(2e-4, beta_1=0.5)\n    photo_generator_optimizer = tf.keras.optimizers.Adam(2e-4, beta_1=0.5)\n\n    monet_discriminator_optimizer = tf.keras.optimizers.Adam(2e-4, beta_1=0.5)\n    photo_discriminator_optimizer = tf.keras.optimizers.Adam(2e-4, beta_1=0.5)","metadata":{"execution":{"iopub.status.busy":"2021-07-25T14:28:26.70819Z","iopub.execute_input":"2021-07-25T14:28:26.70861Z","iopub.status.idle":"2021-07-25T14:28:26.716488Z","shell.execute_reply.started":"2021-07-25T14:28:26.708575Z","shell.execute_reply":"2021-07-25T14:28:26.71472Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"with strategy.scope():\n    cycle_gan_model = CycleGan(\n        monet_generator, photo_generator, monet_discriminator, photo_discriminator\n    )\n\n    cycle_gan_model.compile(\n        m_gen_optimizer = monet_generator_optimizer,\n        p_gen_optimizer = photo_generator_optimizer,\n        m_disc_optimizer = monet_discriminator_optimizer,\n        p_disc_optimizer = photo_discriminator_optimizer,\n        gen_loss_fn = generator_loss,\n        disc_loss_fn = discriminator_loss,\n        cycle_loss_fn = calc_cycle_loss,\n        identity_loss_fn = identity_loss\n    )","metadata":{"execution":{"iopub.status.busy":"2021-07-25T14:28:27.070562Z","iopub.execute_input":"2021-07-25T14:28:27.070975Z","iopub.status.idle":"2021-07-25T14:28:27.101064Z","shell.execute_reply.started":"2021-07-25T14:28:27.070942Z","shell.execute_reply":"2021-07-25T14:28:27.099817Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"history = cycle_gan_model.fit(\n    tf.data.Dataset.zip((monet_ds, photo_ds)),\n    epochs=25,\n#     verbose=True\n)","metadata":{"execution":{"iopub.status.busy":"2021-07-25T14:28:32.199688Z","iopub.execute_input":"2021-07-25T14:28:32.20005Z","iopub.status.idle":"2021-07-25T15:09:51.748037Z","shell.execute_reply.started":"2021-07-25T14:28:32.20002Z","shell.execute_reply":"2021-07-25T15:09:51.745086Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"###print loss############\nmonet_gen_loss = np.asarray(history.history['monet_gen_loss'])\nmonet_gen_loss_mean = monet_gen_loss.mean(axis=(1, 2, 3))\nphoto_gen_loss = np.asarray(history.history['photo_gen_loss'])\nphoto_gen_loss_mean = photo_gen_loss.mean(axis=(1, 2, 3))\nmonet_disc_loss = np.asarray(history.history['monet_disc_loss'])\nmonet_disc_loss_mean = monet_disc_loss.mean(axis=(1, 2, 3))\nphoto_disc_loss = np.asarray(history.history['photo_disc_loss'])\nphoto_disc_loss_mean = photo_disc_loss.mean(axis=(1, 2, 3))\n\nplt.plot(monet_gen_loss_mean.flatten())\nplt.plot(photo_gen_loss_mean.flatten())\nplt.plot(monet_disc_loss_mean.flatten())\nplt.plot(photo_disc_loss_mean.flatten())\nplt.title('model loss')\nplt.ylabel('loss')\nplt.xlabel('epoch')\nplt.legend(['monet_gen_loss', 'photo_gen_loss', 'monet_disc_loss', 'photo_disc_loss'], loc='upper left')\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2021-07-25T15:09:51.753745Z","iopub.execute_input":"2021-07-25T15:09:51.754198Z","iopub.status.idle":"2021-07-25T15:09:52.008014Z","shell.execute_reply.started":"2021-07-25T15:09:51.754128Z","shell.execute_reply":"2021-07-25T15:09:52.006758Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Visualize our Generated Peudo-Monet photos","metadata":{}},{"cell_type":"code","source":"_, ax = plt.subplots(5, 2, figsize=(150, 150))\nfor i, img in enumerate(photo_ds.take(5)):\n    prediction = monet_generator(img, training=False)[0].numpy()\n    prediction = (prediction * 127.5 + 127.5).astype(np.uint8)\n    img = (img[0] * 127.5 + 127.5).numpy().astype(np.uint8)\n\n    ax[i, 0].imshow(img)\n    ax[i, 1].imshow(prediction)\n    ax[i, 0].set_title(\"Input Photo\")\n    ax[i, 1].set_title(\"Monet-esque\")\n    ax[i, 0].axis(\"off\")\n    ax[i, 1].axis(\"off\")\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2021-06-19T19:32:21.982915Z","iopub.execute_input":"2021-06-19T19:32:21.98321Z","iopub.status.idle":"2021-06-19T19:32:27.959219Z","shell.execute_reply.started":"2021-06-19T19:32:21.983181Z","shell.execute_reply":"2021-06-19T19:32:27.958022Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Create submission file","metadata":{}},{"cell_type":"code","source":"import PIL\n! mkdir ../images","metadata":{"execution":{"iopub.status.busy":"2021-06-19T14:48:27.657013Z","iopub.execute_input":"2021-06-19T14:48:27.657318Z","iopub.status.idle":"2021-06-19T14:48:28.436797Z","shell.execute_reply.started":"2021-06-19T14:48:27.65729Z","shell.execute_reply":"2021-06-19T14:48:28.435467Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"i = 1\nfor img in photo_ds:\n    prediction = monet_generator(img, training=False)[0].numpy()\n    prediction = (prediction * 127.5 + 127.5).astype(np.uint8)\n    im = PIL.Image.fromarray(prediction)\n    im.save(\"../images/\" + str(i) + \".jpg\")\n    i += 1","metadata":{"execution":{"iopub.status.busy":"2021-06-19T14:48:28.438924Z","iopub.execute_input":"2021-06-19T14:48:28.439397Z","iopub.status.idle":"2021-06-19T14:54:31.778098Z","shell.execute_reply.started":"2021-06-19T14:48:28.439348Z","shell.execute_reply":"2021-06-19T14:54:31.775212Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import shutil\nshutil.make_archive(\"/kaggle/working/images\", 'zip', \"/kaggle/images\")\n\n\n\n\n\n\n\n","metadata":{"execution":{"iopub.status.busy":"2021-06-19T14:54:31.77897Z","iopub.status.idle":"2021-06-19T14:54:31.7794Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# another experiment - with augmentations\n\nsince the Monet dataset is very small, we'll try to enrich it by adding augmentations of existing images. \nin our case, since our main interest is the image style, flipping the images around the horizontal axis makes sense and can be used, as well as rotations and crops. \nwe preferred not to change anything with the colors and saturation values, as it may affect the learned style. ","metadata":{}},{"cell_type":"code","source":"HEIGHT = 256\nWIDTH = 256\nHEIGHT_RESIZE = 128\nWIDTH_RESIZE = 128\nCHANNELS = 3\nBATCH_SIZE = 16\nEPOCHS = 25","metadata":{"execution":{"iopub.status.busy":"2021-07-23T20:54:42.069194Z","iopub.execute_input":"2021-07-23T20:54:42.069559Z","iopub.status.idle":"2021-07-23T20:54:42.074418Z","shell.execute_reply.started":"2021-07-23T20:54:42.069528Z","shell.execute_reply":"2021-07-23T20:54:42.073274Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def normalize_img(img):\n    img = tf.cast(img, dtype=tf.float32)\n    # Map values in the range [-1, 1]\n    return (img / 127.5) - 1.0\n\ndef decode_image(image):\n    image = tf.image.decode_jpeg(image, channels=CHANNELS)\n    image = tf.reshape(image, [HEIGHT, WIDTH, CHANNELS])\n    return image\n\ndef read_tfrecord(example):\n    tfrecord_format = {\n        'image':      tf.io.FixedLenFeature([], tf.string)\n    }\n    example = tf.io.parse_single_example(example, tfrecord_format)\n    image = decode_image(example['image'])\n    return image\n\ndef load_dataset(filenames):\n    dataset = tf.data.TFRecordDataset(filenames)\n    dataset = dataset.map(read_tfrecord, num_parallel_calls=AUTOTUNE)\n    return dataset\n\ndef get_dataset(filenames, augment=None, repeat=True, shuffle=True, batch_size=1):\n    dataset = load_dataset(filenames)\n\n    if augment:\n        dataset = dataset.map(augment, num_parallel_calls=AUTOTUNE)\n    dataset = dataset.map(normalize_img, num_parallel_calls=AUTOTUNE)\n    if repeat:\n        dataset = dataset.repeat()\n    if shuffle:\n        dataset = dataset.shuffle(512)\n        \n    dataset = dataset.batch(batch_size)\n    dataset = dataset.cache()\n    dataset = dataset.prefetch(AUTOTUNE)\n    \n    return dataset\n\n\n        \n        \ndef data_augment(image):\n    p_spatial = tf.random.uniform([], 0, 1.0, dtype=tf.float32)\n    p_rotate = tf.random.uniform([], 0, 1.0, dtype=tf.float32)\n\n    \n    # 90º rotations\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    # Flips\n    image = tf.image.random_flip_left_right(image)\n    image = tf.image.random_flip_up_down(image)\n    if p_spatial > .75:\n        image = tf.image.transpose(image)\n    \n            \n#     # crops\n#     image = tf.image.random_crop(image, size=[HEIGHT_RESIZE, WIDTH_RESIZE, CHANNELS])\n        \n    \n    return image\n\n\n","metadata":{"execution":{"iopub.status.busy":"2021-07-23T21:12:45.018443Z","iopub.execute_input":"2021-07-23T21:12:45.018823Z","iopub.status.idle":"2021-07-23T21:12:45.034396Z","shell.execute_reply.started":"2021-07-23T21:12:45.018791Z","shell.execute_reply":"2021-07-23T21:12:45.033276Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Create dataset\nmonet_ds = get_dataset(MONET_FILENAMES, augment=data_augment, batch_size=BATCH_SIZE)\nphoto_ds = get_dataset(PHOTO_FILENAMES, augment=data_augment, batch_size=BATCH_SIZE)","metadata":{"execution":{"iopub.status.busy":"2021-07-23T21:12:45.46573Z","iopub.execute_input":"2021-07-23T21:12:45.466109Z","iopub.status.idle":"2021-07-23T21:12:46.058914Z","shell.execute_reply.started":"2021-07-23T21:12:45.46608Z","shell.execute_reply":"2021-07-23T21:12:46.057767Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### from here go back to main workflow and train using data with augmentations. \n\n* results shown no significant improvement to model without augmentations. \n\n\nsome examples of augmentaed images:","metadata":{}},{"cell_type":"code","source":"example_monet_1 = next(iter(monet_ds))\nexample_monet_2 = next(iter(monet_ds))","metadata":{"execution":{"iopub.status.busy":"2021-07-23T21:12:47.115616Z","iopub.execute_input":"2021-07-23T21:12:47.115984Z","iopub.status.idle":"2021-07-23T21:12:48.521858Z","shell.execute_reply.started":"2021-07-23T21:12:47.115954Z","shell.execute_reply":"2021-07-23T21:12:48.520817Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plt.subplot(121)\nplt.title('Augmentation_1')\nplt.imshow(example_monet_1[0] * 0.5 + 0.5)\n\nplt.subplot(122)\nplt.title('Augmentation_2')\nplt.imshow(example_monet_2[0] * 0.5 + 0.5)","metadata":{"execution":{"iopub.status.busy":"2021-07-23T21:12:48.523524Z","iopub.execute_input":"2021-07-23T21:12:48.523932Z","iopub.status.idle":"2021-07-23T21:12:48.817658Z","shell.execute_reply.started":"2021-07-23T21:12:48.523875Z","shell.execute_reply":"2021-07-23T21:12:48.816873Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# history = cycle_gan_model.fit(\n#     tf.data.Dataset.zip((monet_ds, photo_ds)),\n#     epochs=25,\n# #     verbose=True\n# )","metadata":{"execution":{"iopub.status.busy":"2021-07-23T20:43:00.64443Z","iopub.execute_input":"2021-07-23T20:43:00.645228Z","iopub.status.idle":"2021-07-23T20:43:00.677296Z","shell.execute_reply.started":"2021-07-23T20:43:00.645178Z","shell.execute_reply":"2021-07-23T20:43:00.675419Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]}]}