{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"pygments_lexer":"ipython3","nbconvert_exporter":"python","version":"3.6.4","file_extension":".py","codemirror_mode":{"name":"ipython","version":3},"name":"python","mimetype":"text/x-python"}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"## Information and more are taken from the official tensorflow documentation and from the Machine learning mastery website. \n## Also special thanks for the idea with the layer Instance Normalization and Discriminator Conrad Kleykamp\n\n## links\n### https://www.kaggle.com/code/conradkleykamp/using-gans-to-create-monet-style-art-cyclegan\n### https://machinelearningmastery.com/how-to-implement-pix2pix-gan-models-from-scratch-with-keras/\n### https://www.tensorflow.org/tutorials/generative/pix2pix?hl=ru\n### https://www.tensorflow.org/tutorials/generative/cyclegan?hl=ru","metadata":{}},{"cell_type":"code","source":"import os\nimport keras\nimport time\n\nimport numpy as np\nimport pandas as pd\nimport tensorflow as tf\nimport matplotlib.pyplot as plt\nimport tensorflow_addons as tfa\n\nfrom skimage import io\nfrom PIL import Image","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"monet_jpg = []\n\nfor dirname, _, filenames in os.walk('/kaggle/input/gan-getting-started/monet_jpg'):\n    for filename in filenames:\n        image = io.imread(os.path.join(dirname, filename))\n        \n        monet_jpg.append(image)\nprint('GOAL')","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2023-07-29T09:34:11.782659Z","iopub.execute_input":"2023-07-29T09:34:11.783005Z","iopub.status.idle":"2023-07-29T09:34:13.158836Z","shell.execute_reply.started":"2023-07-29T09:34:11.782973Z","shell.execute_reply":"2023-07-29T09:34:13.157727Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"photo_jpg = []\n\nfor dirname, _, filenames in os.walk('/kaggle/input/gan-getting-started/photo_jpg'):\n    for filename in filenames:\n        image = io.imread(os.path.join(dirname, filename))\n        \n        photo_jpg.append(image)\nprint('GOAL')","metadata":{"execution":{"iopub.status.busy":"2023-07-29T09:34:13.161690Z","iopub.execute_input":"2023-07-29T09:34:13.162049Z","iopub.status.idle":"2023-07-29T09:34:43.794348Z","shell.execute_reply.started":"2023-07-29T09:34:13.162008Z","shell.execute_reply":"2023-07-29T09:34:43.793299Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"len(monet_jpg), len(photo_jpg)","metadata":{"execution":{"iopub.status.busy":"2023-07-29T09:34:43.796007Z","iopub.execute_input":"2023-07-29T09:34:43.796384Z","iopub.status.idle":"2023-07-29T09:34:43.804302Z","shell.execute_reply.started":"2023-07-29T09:34:43.796349Z","shell.execute_reply":"2023-07-29T09:34:43.803031Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"dataset = tf.data.Dataset.from_tensor_slices((photo_jpg[:len(monet_jpg)], monet_jpg))\n\ndataset_2 = tf.data.Dataset.from_tensor_slices(photo_jpg[len(monet_jpg):len(monet_jpg)+200])","metadata":{"execution":{"iopub.status.busy":"2023-07-29T09:34:43.806365Z","iopub.execute_input":"2023-07-29T09:34:43.806700Z","iopub.status.idle":"2023-07-29T09:36:33.354918Z","shell.execute_reply.started":"2023-07-29T09:34:43.806674Z","shell.execute_reply":"2023-07-29T09:36:33.353853Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"BUFFER_SIZE = 1000\nBATCH_SIZE = 1\nIMG_WIDTH = 256\nIMG_HEIGHT = 256\n\ndef random_crop(input_image, real_image):\n    stacked_image = tf.stack([input_image, real_image], axis=0)\n    \n    cropped_image = tf.image.random_crop(\n      stacked_image, size=[2, IMG_HEIGHT, IMG_WIDTH, 3])\n    \n    return cropped_image[0], cropped_image[1]\n\ndef norm(img, img_2):\n    img = tf.cast(img, tf.float32)\n    \n    img = (img / 127.5) - 1\n    \n    img_2 = tf.cast(img_2, tf.float32)\n    \n    img_2 = (img_2 / 127.5) - 1\n    \n    return img, img_2\n\n@tf.function()\ndef random_jitter(input_image, real_image):\n    # Random cropping back to 256x256\n    input_image, real_image = random_crop(input_image, real_image)\n    \n    if tf.random.uniform(()) > 0.5:\n        input_image = tf.image.flip_left_right(input_image)\n        real_image = tf.image.flip_left_right(real_image)\n\n    return input_image, real_image\n\ndef preprocess_image_train(image, label):\n    image, label = random_jitter(image, label)\n    image, label = norm(image, label)\n  \n    return image, label\n\ndef preprocess_image_test(image):\n    img = tf.cast(image, tf.float32)\n    \n    img = (img / 127.5) - 1\n  \n    return img\n\ndataset_norm = lambda x: x.map(\n    preprocess_image_train, num_parallel_calls=tf.data.AUTOTUNE).shuffle(\n    BUFFER_SIZE).batch(BATCH_SIZE)\n\ndataset_norm_2 = lambda x: x.map(\n    preprocess_image_test).shuffle(\n    BUFFER_SIZE).batch(BATCH_SIZE)\n\ntrain_dataset = dataset_norm(dataset)\ntest_dataset = dataset_norm_2(dataset_2)","metadata":{"execution":{"iopub.status.busy":"2023-07-29T09:36:33.356442Z","iopub.execute_input":"2023-07-29T09:36:33.356792Z","iopub.status.idle":"2023-07-29T09:36:33.675261Z","shell.execute_reply.started":"2023-07-29T09:36:33.356759Z","shell.execute_reply":"2023-07-29T09:36:33.674276Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"for i in test_dataset.take(3):\n    plt.imshow(i[0])\n    plt.show()","metadata":{"execution":{"iopub.status.busy":"2023-07-29T09:37:12.377425Z","iopub.execute_input":"2023-07-29T09:37:12.377803Z","iopub.status.idle":"2023-07-29T09:37:13.660534Z","shell.execute_reply.started":"2023-07-29T09:37:12.377774Z","shell.execute_reply":"2023-07-29T09:37:13.659535Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"OUTPUT_CHANNELS = 3\n\ndef downsample(filters, size, apply=True):\n    intializer = tf.random_normal_initializer(0., .02)\n    \n    model = tf.keras.Sequential()\n    \n    model.add(keras.layers.Conv2D(filters, size, strides=2, padding='same',\n                             kernel_initializer=intializer, use_bias=False))\n    \n    if apply:\n        model.add(tfa.layers.InstanceNormalization(gamma_initializer=intializer))\n    \n    model.add(keras.layers.LeakyReLU(alpha=0.2))\n    \n    return model\n\ndown_model = downsample(3, 4)\nfor i in test_dataset.take(1):\n    down_result = down_model(tf.expand_dims(i[0], 0))\n\ndown_result.shape","metadata":{"execution":{"iopub.status.busy":"2023-07-29T10:46:56.140021Z","iopub.execute_input":"2023-07-29T10:46:56.140911Z","iopub.status.idle":"2023-07-29T10:46:56.509978Z","shell.execute_reply.started":"2023-07-29T10:46:56.140870Z","shell.execute_reply":"2023-07-29T10:46:56.508958Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def upsample(filters, size, apply=False):\n    initializer = tf.random_normal_initializer(0., .02)\n\n    model = tf.keras.Sequential()\n    model.add(\n    keras.layers.Conv2DTranspose(filters, size, strides=2,\n                                    padding='same',\n                                    kernel_initializer=initializer,\n                                    use_bias=False))\n\n    model.add(tfa.layers.InstanceNormalization(gamma_initializer=initializer))\n\n    if apply:\n        model.add(keras.layers.Dropout(.5))\n\n    model.add(keras.layers.ReLU())\n\n    return model\n\nup_model = upsample(3, 4)\nup_result = up_model(down_result)\n\nup_result.shape","metadata":{"execution":{"iopub.status.busy":"2023-07-29T10:46:58.186912Z","iopub.execute_input":"2023-07-29T10:46:58.187310Z","iopub.status.idle":"2023-07-29T10:46:58.258221Z","shell.execute_reply.started":"2023-07-29T10:46:58.187275Z","shell.execute_reply":"2023-07-29T10:46:58.257128Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def Generator():\n    inputs = keras.layers.Input(shape=[256, 256, 3])\n\n    down_stack = [\n        downsample(64, 4, apply=False),# (batch_size, 128, 128, 64)\n        downsample(128, 4),  # (batch_size, 64, 64, 128)\n        downsample(256, 4),  # (batch_size, 32, 32, 256)\n        downsample(512, 4),  # (batch_size, 16, 16, 512)\n        downsample(512, 4),  # (batch_size, 8, 8, 512)\n        downsample(512, 4),  # (batch_size, 4, 4, 512)\n        downsample(512, 4),  # (batch_size, 2, 2, 512)\n        downsample(512, 4),  # (batch_size, 1, 1, 512)\n        ]\n\n    up_stack = [\n        upsample(512, 4, apply=True), # (batch_size, 2, 2, 1024)\n        upsample(512, 4, apply=True),  # (batch_size, 4, 4, 1024)\n        upsample(512, 4, apply=True),  # (batch_size, 8, 8, 1024)\n        upsample(512, 4),  # (batch_size, 16, 16, 1024)\n        upsample(256, 4),  # (batch_size, 32, 32, 512)\n        upsample(128, 4),  # (batch_size, 64, 64, 256)\n        upsample(64, 4),  # (batch_size, 128, 128, 128)\n        ]\n\n    initializer = tf.random_normal_initializer(0., 0.02)\n    last = keras.layers.Conv2DTranspose(OUTPUT_CHANNELS, 4,\n                                         strides=2,\n                                         padding='same',\n                                         kernel_initializer=initializer)  # (batch_size, 256, 256, 3)\n    out_image = keras.layers.Activation('tanh')\n\n    x = inputs\n\n    skips = []\n    for down in down_stack:\n        x = down(x)\n        skips.append(x)\n\n    skips = reversed(skips[:-1])\n\n    for up, skip in zip(up_stack, skips):\n        x = up(x)\n        x = keras.layers.Concatenate()([x, skip])\n\n    x = out_image(last(x))\n\n    return keras.Model(inputs=inputs, outputs=x)\n\ngenerator_g = Generator()\ngenerator_f = Generator()\n\nkeras.utils.plot_model(generator_g, show_shapes=True, dpi=64)","metadata":{"execution":{"iopub.status.busy":"2023-07-29T10:49:29.121609Z","iopub.execute_input":"2023-07-29T10:49:29.121967Z","iopub.status.idle":"2023-07-29T10:49:32.038265Z","shell.execute_reply.started":"2023-07-29T10:49:29.121938Z","shell.execute_reply":"2023-07-29T10:49:32.035364Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def Discriminator():\n    initializer = tf.random_normal_initializer(0., .02)\n    gamma_init = keras.initializers.RandomNormal(mean=.0, stddev=.02)\n\n    inp = keras.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 = keras.layers.ZeroPadding2D()(down3) # (bs, 34, 34, 256)\n    conv = keras.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 = keras.layers.LeakyReLU()(norm1)\n\n    zero_pad2 = keras.layers.ZeroPadding2D()(leaky_relu) # (bs, 33, 33, 512)\n\n    last = keras.layers.Conv2D(1, 4, strides=1,\n                         kernel_initializer=initializer)(zero_pad2) # (bs, 30, 30, 1)\n\n    return keras.Model(inputs=inp, outputs=last)\n\ndiscriminator_x = Discriminator()\ndiscriminator_y = Discriminator()","metadata":{"execution":{"iopub.status.busy":"2023-07-29T10:49:40.630728Z","iopub.execute_input":"2023-07-29T10:49:40.631150Z","iopub.status.idle":"2023-07-29T10:49:41.069565Z","shell.execute_reply.started":"2023-07-29T10:49:40.631117Z","shell.execute_reply":"2023-07-29T10:49:41.068511Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"LAMBDA = 10\n\nloss_obj = tf.keras.losses.BinaryCrossentropy(from_logits=True)\n\ngenerator_g_optimizer = tf.keras.optimizers.Adam(2e-4, beta_1=0.5)\ngenerator_f_optimizer = tf.keras.optimizers.Adam(2e-4, beta_1=0.5)\n\ndiscriminator_x_optimizer = tf.keras.optimizers.Adam(2e-4, beta_1=0.5)\ndiscriminator_y_optimizer = tf.keras.optimizers.Adam(2e-4, beta_1=0.5)\n\ndef 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\n\ndef generator_loss(generated):\n    return loss_obj(tf.ones_like(generated), generated)\n\ndef calc_cycle_loss(real_image, cycled_image):\n    loss1 = tf.reduce_mean(tf.abs(real_image - cycled_image))\n\n    return LAMBDA * loss1\n\ndef identity_loss(real_image, same_image):\n    loss = tf.reduce_mean(tf.abs(real_image - same_image))\n    \n    return LAMBDA * 0.5 * loss","metadata":{"execution":{"iopub.status.busy":"2023-07-29T10:49:54.398428Z","iopub.execute_input":"2023-07-29T10:49:54.398811Z","iopub.status.idle":"2023-07-29T10:49:54.417634Z","shell.execute_reply.started":"2023-07-29T10:49:54.398778Z","shell.execute_reply":"2023-07-29T10:49:54.416647Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def generate_images(model, test_input, dataset=True):\n    if dataset:\n        for i in test_input.take(1):\n            prediction = model(i)\n    else:\n        i = test_input\n        prediction = model(i)\n        \n    plt.figure(figsize=(12, 12))\n\n    display_list = [i[0], prediction[0]]\n    title = ['Input Image', 'Predicted Image']\n\n    for i in range(2):\n        plt.subplot(1, 2, i+1)\n        plt.title(title[i])\n        # getting the pixel values between [0, 1] to plot it.\n        plt.imshow(display_list[i] * 0.5 + 0.5)\n        plt.axis('off')\n    \n    plt.show()","metadata":{"execution":{"iopub.status.busy":"2023-07-29T11:51:20.826565Z","iopub.execute_input":"2023-07-29T11:51:20.826999Z","iopub.status.idle":"2023-07-29T11:51:20.836176Z","shell.execute_reply.started":"2023-07-29T11:51:20.826966Z","shell.execute_reply":"2023-07-29T11:51:20.834890Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"@tf.function\ndef train_step(real_x, real_y):\n    # persistent is set to True because the tape is used more than\n    # once to calculate the gradients.\n    with tf.GradientTape(persistent=True) as tape:\n        # Generator G translates X -> Y\n        # Generator F translates Y -> X.\n\n        fake_y = generator_g(real_x, training=True)\n        cycled_x = generator_f(fake_y, training=True)\n\n        fake_x = generator_f(real_y, training=True)\n        cycled_y = generator_g(fake_x, training=True)\n\n        # same_x and same_y are used for identity loss.\n        same_x = generator_f(real_x, training=True)\n        same_y = generator_g(real_y, training=True)\n\n        disc_real_x = discriminator_x(real_x, training=True)\n        disc_real_y = discriminator_y(real_y, training=True)\n\n        disc_fake_x = discriminator_x(fake_x, training=True)\n        disc_fake_y = discriminator_y(fake_y, training=True)\n\n        # calculate the loss\n        gen_g_loss = generator_loss(disc_fake_y)\n        gen_f_loss = generator_loss(disc_fake_x)\n\n        total_cycle_loss = calc_cycle_loss(real_x, cycled_x) + calc_cycle_loss(real_y, cycled_y)\n\n        # Total generator loss = adversarial loss + cycle loss\n        total_gen_g_loss = gen_g_loss + total_cycle_loss + identity_loss(real_y, same_y)\n        total_gen_f_loss = gen_f_loss + total_cycle_loss + identity_loss(real_x, same_x)\n\n        disc_x_loss = discriminator_loss(disc_real_x, disc_fake_x)\n        disc_y_loss = discriminator_loss(disc_real_y, disc_fake_y)\n\n    generator_g_gradients = tape.gradient(total_gen_g_loss, \n                                        generator_g.trainable_variables)\n    generator_f_gradients = tape.gradient(total_gen_f_loss, \n                                        generator_f.trainable_variables)\n\n    discriminator_x_gradients = tape.gradient(disc_x_loss, \n                                                discriminator_x.trainable_variables)\n    discriminator_y_gradients = tape.gradient(disc_y_loss, \n                                                discriminator_y.trainable_variables)\n\n    generator_g_optimizer.apply_gradients(zip(generator_g_gradients, \n                                                generator_g.trainable_variables))\n\n    generator_f_optimizer.apply_gradients(zip(generator_f_gradients, \n                                                generator_f.trainable_variables))\n\n    discriminator_x_optimizer.apply_gradients(zip(discriminator_x_gradients,\n                                                    discriminator_x.trainable_variables))\n\n    discriminator_y_optimizer.apply_gradients(zip(discriminator_y_gradients,\n                                                    discriminator_y.trainable_variables))","metadata":{"execution":{"iopub.status.busy":"2023-07-29T10:50:01.118409Z","iopub.execute_input":"2023-07-29T10:50:01.118846Z","iopub.status.idle":"2023-07-29T10:50:01.505115Z","shell.execute_reply.started":"2023-07-29T10:50:01.118813Z","shell.execute_reply":"2023-07-29T10:50:01.503968Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"EPOCHS = 25\n\nfor epoch in range(EPOCHS):\n    start = time.time()\n\n    for image_x, image_y in train_dataset:\n        train_step(image_x, image_y)\n    \n    generate_images(generator_g, test_dataset)\n\n    print ('Time taken for epoch {} is {} sec\\n'.format(epoch + 1,\n                                                      time.time()-start))","metadata":{"execution":{"iopub.status.busy":"2023-07-29T10:50:04.981695Z","iopub.execute_input":"2023-07-29T10:50:04.982074Z","iopub.status.idle":"2023-07-29T11:41:42.470966Z","shell.execute_reply.started":"2023-07-29T10:50:04.982043Z","shell.execute_reply":"2023-07-29T11:41:42.470073Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# real data check\n\nimage_path = '/kaggle/input/real-data/real.jpg'\nimage_path_2 = '/kaggle/working/real.jpg'\n\nimg = Image.open(image_path)\n\nnew_image = img.resize((256, 256))\n\nnew_image.save(image_path_2)\n\ngenerate_images(generator_g, (np.array([io.imread(image_path_2)]) / 127.5) - 1, False)","metadata":{"execution":{"iopub.status.busy":"2023-07-29T12:01:10.810334Z","iopub.execute_input":"2023-07-29T12:01:10.810732Z","iopub.status.idle":"2023-07-29T12:01:11.462153Z","shell.execute_reply.started":"2023-07-29T12:01:10.810699Z","shell.execute_reply":"2023-07-29T12:01:11.459907Z"},"trusted":true},"execution_count":null,"outputs":[]}]}