{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.10.14","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"none","dataSources":[{"sourceId":21755,"databundleVersionId":1475600,"sourceType":"competition"},{"sourceId":1457241,"sourceType":"datasetVersion","datasetId":854421}],"dockerImageVersionId":30786,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":false}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"# This Python 3 environment comes with many helpful analytics libraries installed\n# It is defined by the kaggle/python Docker image: https://github.com/kaggle/docker-python\n# For example, here's several helpful packages to load\n\nimport numpy as np # linear algebra\nimport pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)\n\n# Input data files are available in the read-only \"../input/\" directory\n# For example, running this (by clicking run or pressing Shift+Enter) will list all files under the input directory\n\nimport os\nfor dirname, _, filenames in os.walk('/kaggle/input'):\n    for filename in filenames:\n        print(os.path.join(dirname, filename))\n\n# You can write up to 20GB to the current directory (/kaggle/working/) that gets preserved as output when you create a version using \"Save & Run All\" \n# You can also write temporary files to /kaggle/temp/, but they won't be saved outside of the current session","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true,"execution":{"iopub.status.busy":"2024-11-26T07:22:45.789829Z","iopub.execute_input":"2024-11-26T07:22:45.790552Z","iopub.status.idle":"2024-11-26T07:22:51.931759Z","shell.execute_reply.started":"2024-11-26T07:22:45.790510Z","shell.execute_reply":"2024-11-26T07:22:51.930626Z"},"collapsed":true,"jupyter":{"outputs_hidden":true}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"\nimport tensorflow as tf\n\ntf.keras.backend.clear_session()\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-11-26T07:23:46.294306Z","iopub.execute_input":"2024-11-26T07:23:46.294730Z","iopub.status.idle":"2024-11-26T07:23:46.594321Z","shell.execute_reply.started":"2024-11-26T07:23:46.294695Z","shell.execute_reply":"2024-11-26T07:23:46.593224Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import tensorflow as tf \nfrom tensorflow import keras \nfrom tensorflow.keras import layers \n# import tensorflow_addons as tfa\nfrom kaggle_datasets import KaggleDatasets\nimport matplotlib.pyplot as plt\nimport numpy as np\nimport seaborn as sns \nsns.set()\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    \nprint(tf.__version__)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-11-26T07:23:49.980786Z","iopub.execute_input":"2024-11-26T07:23:49.981200Z","iopub.status.idle":"2024-11-26T07:23:50.646305Z","shell.execute_reply.started":"2024-11-26T07:23:49.981164Z","shell.execute_reply":"2024-11-26T07:23:50.645132Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import os\nprint(os.listdir('/kaggle/input'))","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-11-26T07:23:52.053775Z","iopub.execute_input":"2024-11-26T07:23:52.054374Z","iopub.status.idle":"2024-11-26T07:23:52.060396Z","shell.execute_reply.started":"2024-11-26T07:23:52.054337Z","shell.execute_reply":"2024-11-26T07:23:52.059164Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"GCS_PATH = KaggleDatasets().get_gcs_path('gan-getting-started')","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-11-26T07:23:52.797316Z","iopub.execute_input":"2024-11-26T07:23:52.797840Z","iopub.status.idle":"2024-11-26T07:23:53.329720Z","shell.execute_reply.started":"2024-11-26T07:23:52.797792Z","shell.execute_reply":"2024-11-26T07:23:53.328617Z"}},"outputs":[],"execution_count":null},{"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":{"trusted":true,"execution":{"iopub.status.busy":"2024-11-26T07:23:54.150280Z","iopub.execute_input":"2024-11-26T07:23:54.150692Z","iopub.status.idle":"2024-11-26T07:23:56.507025Z","shell.execute_reply.started":"2024-11-26T07:23:54.150655Z","shell.execute_reply":"2024-11-26T07:23:56.505877Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def parse_tfrecord(example):\n    # Define features in TFRecord\n    feature_description = {\n        'image': tf.io.FixedLenFeature([], tf.string),  # Serialized image data\n    }\n    parsed_example = tf.io.parse_single_example(example, feature_description)\n    \n    # Decode the image\n    image = tf.io.decode_jpeg(parsed_example['image'], channels=3)\n    return image","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-11-26T07:23:56.508701Z","iopub.execute_input":"2024-11-26T07:23:56.509000Z","iopub.status.idle":"2024-11-26T07:23:56.514539Z","shell.execute_reply.started":"2024-11-26T07:23:56.508970Z","shell.execute_reply":"2024-11-26T07:23:56.513524Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def preprocess_image(image, img_size=128):\n    # Resize image\n    image = tf.image.resize(image, [img_size, img_size])\n    \n    # Normalize to [-1, 1] for GANs\n    image = (image / 127.5) - 1.0\n\n    return image\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-11-26T07:23:57.438607Z","iopub.execute_input":"2024-11-26T07:23:57.438999Z","iopub.status.idle":"2024-11-26T07:23:57.444675Z","shell.execute_reply.started":"2024-11-26T07:23:57.438962Z","shell.execute_reply":"2024-11-26T07:23:57.443436Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def load_and_preprocess_dataset(filenames, batch_size=32, img_size=128):\n    dataset = tf.data.TFRecordDataset(filenames)\n    \n    # Map parsing and preprocessing\n    dataset = dataset.map(\n        lambda x: preprocess_image(parse_tfrecord(x), img_size),\n        num_parallel_calls=tf.data.AUTOTUNE\n    )\n    \n    # Shuffle, batch, and prefetch for performance\n    dataset = dataset.shuffle(buffer_size=1000).batch(batch_size).prefetch(tf.data.AUTOTUNE)\n    \n    return dataset\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-11-26T07:23:59.185809Z","iopub.execute_input":"2024-11-26T07:23:59.186229Z","iopub.status.idle":"2024-11-26T07:23:59.193151Z","shell.execute_reply.started":"2024-11-26T07:23:59.186192Z","shell.execute_reply":"2024-11-26T07:23:59.191902Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"monet_dataset = load_and_preprocess_dataset(MONET_FILENAMES,batch_size=32)\nphotos_dataset = load_and_preprocess_dataset(PHOTO_FILENAMES,batch_size=32)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-11-26T07:24:01.941358Z","iopub.execute_input":"2024-11-26T07:24:01.941812Z","iopub.status.idle":"2024-11-26T07:24:02.168296Z","shell.execute_reply.started":"2024-11-26T07:24:01.941772Z","shell.execute_reply":"2024-11-26T07:24:02.167107Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"example_monet = next(iter(monet_dataset))\nexample_photo = next(iter(photos_dataset))","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-11-26T07:24:02.981917Z","iopub.execute_input":"2024-11-26T07:24:02.982342Z","iopub.status.idle":"2024-11-26T07:24:24.988972Z","shell.execute_reply.started":"2024-11-26T07:24:02.982304Z","shell.execute_reply":"2024-11-26T07:24:24.987788Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"plt.subplot(121)\nplt.title('Monet')\nplt.imshow(example_monet[0] * 0.5 + 0.5)\n\nplt.subplot(122)\nplt.title('Photo')\nplt.imshow(example_photo[0] * 0.5 + 0.5)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-11-26T07:24:24.990897Z","iopub.execute_input":"2024-11-26T07:24:24.991247Z","iopub.status.idle":"2024-11-26T07:24:25.704296Z","shell.execute_reply.started":"2024-11-26T07:24:24.991215Z","shell.execute_reply":"2024-11-26T07:24:25.703095Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def build_generator():\n    inputs = layers.Input(shape=(128, 128, 3))\n\n    # Encoder (downsampling)\n    x = layers.Conv2D(64, (4, 4), strides=2, padding=\"same\")(inputs)\n    x = layers.ReLU()(x)\n    x = layers.Conv2D(128, (4, 4), strides=2, padding=\"same\")(x)\n    x = layers.ReLU()(x)\n\n    # Residual blocks\n    for _ in range(6):  # Add 6 residual blocks\n        res = x\n        x = layers.Conv2D(128, (3, 3), padding=\"same\")(x)\n        x = layers.ReLU()(x)\n        x = layers.Conv2D(128, (3, 3), padding=\"same\")(x)\n        x = layers.Add()([x, res])\n\n    # Decoder (upsampling)\n    x = layers.Conv2DTranspose(64, (4, 4), strides=2, padding=\"same\")(x)\n    x = layers.ReLU()(x)\n    x = layers.Conv2DTranspose(3, (4, 4), strides=2, padding=\"same\")(x)\n    outputs = layers.Activation(\"tanh\")(x)\n\n    return tf.keras.Model(inputs, outputs)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-11-26T07:24:25.705673Z","iopub.execute_input":"2024-11-26T07:24:25.706030Z","iopub.status.idle":"2024-11-26T07:24:25.720068Z","shell.execute_reply.started":"2024-11-26T07:24:25.705995Z","shell.execute_reply":"2024-11-26T07:24:25.718669Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def build_discriminator():\n    inputs = layers.Input(shape=(128, 128, 3))\n\n    # Convolutional layers\n    x = layers.Conv2D(64, (4, 4), strides=2, padding=\"same\")(inputs)\n    x = layers.LeakyReLU(0.2)(x)\n    x = layers.Conv2D(128, (4, 4), strides=2, padding=\"same\")(x)\n    x = layers.LeakyReLU(0.2)(x)\n\n    # Final layer\n    x = layers.Conv2D(1, (4, 4), padding=\"same\")(x)\n    outputs = layers.Activation(\"sigmoid\")(x)\n\n    return tf.keras.Model(inputs, outputs)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-11-26T07:24:25.722591Z","iopub.execute_input":"2024-11-26T07:24:25.722954Z","iopub.status.idle":"2024-11-26T07:24:25.741077Z","shell.execute_reply.started":"2024-11-26T07:24:25.722911Z","shell.execute_reply":"2024-11-26T07:24:25.739815Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def build_cyclegan(generator_a_to_b, generator_b_to_a, discriminator_a, discriminator_b):\n    # Inputs\n    input_a = layers.Input(shape=(128, 128, 3))  # Monet image\n    input_b = layers.Input(shape=(128, 128, 3))  # Photo\n\n    # Generated images\n    fake_b = generator_a_to_b(input_a)  # Monet -> Photo\n    fake_a = generator_b_to_a(input_b)  # Photo -> Monet\n\n    # Cycled images\n    cycled_a = generator_b_to_a(fake_b)  # Monet -> Photo -> Monet\n    cycled_b = generator_a_to_b(fake_a)  # Photo -> Monet -> Photo\n\n    # Discriminators\n    valid_a = discriminator_a(fake_a)  # Discriminator for Monet\n    valid_b = discriminator_b(fake_b)  # Discriminator for Photos\n\n    return tf.keras.Model(inputs=[input_a, input_b], outputs=[fake_a, fake_b, cycled_a, cycled_b, valid_a, valid_b])\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-11-26T07:24:25.742324Z","iopub.execute_input":"2024-11-26T07:24:25.742703Z","iopub.status.idle":"2024-11-26T07:24:25.758046Z","shell.execute_reply.started":"2024-11-26T07:24:25.742649Z","shell.execute_reply":"2024-11-26T07:24:25.757018Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def adversarial_loss(y_true, y_pred):\n    return tf.keras.losses.MeanSquaredError()(y_true, y_pred)\n\ndef cycle_consistency_loss(real, cycled):\n    return tf.keras.losses.MeanAbsoluteError()(real, cycled)\n\ndef identity_loss(real, same):\n    return tf.keras.losses.MeanAbsoluteError()(real, same)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-11-26T07:24:25.759678Z","iopub.execute_input":"2024-11-26T07:24:25.760184Z","iopub.status.idle":"2024-11-26T07:24:25.779275Z","shell.execute_reply.started":"2024-11-26T07:24:25.760134Z","shell.execute_reply":"2024-11-26T07:24:25.778058Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Hyperparameters\nEPOCHS = 200\nBATCH_SIZE = 1  # CycleGANs are typically trained with a batch size of 1\nLEARNING_RATE = 2e-4\nLAMBDA_CYCLE = 10.0  # Weight for cycle consistency loss\nLAMBDA_IDENTITY = 0.5  # Weight for identity loss\n\n# Build models\ngenerator_a_to_b = build_generator()  # Monet -> Photo\ngenerator_b_to_a = build_generator()  # Photo -> Monet\ndiscriminator_a = build_discriminator()  # For Monet\ndiscriminator_b = build_discriminator()  # For Photos\n\n\n# Separate optimizers for each model\ngen_a_to_b_optimizer = tf.keras.optimizers.Adam(LEARNING_RATE, beta_1=0.5)\ngen_b_to_a_optimizer = tf.keras.optimizers.Adam(LEARNING_RATE, beta_1=0.5)\ndisc_a_optimizer = tf.keras.optimizers.Adam(LEARNING_RATE, beta_1=0.5)\ndisc_b_optimizer = tf.keras.optimizers.Adam(LEARNING_RATE, beta_1=0.5)\n\n\n# Training loop\nfor epoch in range(EPOCHS):\n    for real_a, real_b in zip(monet_dataset, photos_dataset):\n        with tf.GradientTape(persistent=True) as tape:\n            # Generate fake images\n            fake_b = generator_a_to_b(real_a)\n            fake_a = generator_b_to_a(real_b)\n\n            # Cycle back\n            cycled_a = generator_b_to_a(fake_b)\n            cycled_b = generator_a_to_b(fake_a)\n\n            # Identity mapping\n            same_a = generator_b_to_a(real_a)\n            same_b = generator_a_to_b(real_b)\n\n            # Discriminator outputs\n            valid_a = discriminator_a(fake_a)\n            valid_b = discriminator_b(fake_b)\n            real_a_valid = discriminator_a(real_a)\n            real_b_valid = discriminator_b(real_b)\n\n            # Losses\n            gen_a_to_b_loss = adversarial_loss(tf.ones_like(valid_b), valid_b)\n            gen_b_to_a_loss = adversarial_loss(tf.ones_like(valid_a), valid_a)\n\n            cycle_loss = (\n                cycle_consistency_loss(real_a, cycled_a)\n                + cycle_consistency_loss(real_b, cycled_b)\n            ) * LAMBDA_CYCLE\n\n            identity_loss_a = identity_loss(real_a, same_a) * LAMBDA_IDENTITY\n            identity_loss_b = identity_loss(real_b, same_b) * LAMBDA_IDENTITY\n\n            total_gen_loss = (\n                gen_a_to_b_loss\n                + gen_b_to_a_loss\n                + cycle_loss\n                + identity_loss_a\n                + identity_loss_b\n            )\n\n            disc_a_loss = adversarial_loss(tf.ones_like(real_a_valid), real_a_valid) + \\\n                          adversarial_loss(tf.zeros_like(valid_a), valid_a)\n            disc_b_loss = adversarial_loss(tf.ones_like(real_b_valid), real_b_valid) + \\\n                          adversarial_loss(tf.zeros_like(valid_b), valid_b)\n\n            # Update generators\n            gen_a_to_b_grads = tape.gradient(total_gen_loss, generator_a_to_b.trainable_variables)\n            gen_b_to_a_grads = tape.gradient(total_gen_loss, generator_b_to_a.trainable_variables)\n\n            gen_a_to_b_optimizer.apply_gradients(zip(gen_a_to_b_grads, generator_a_to_b.trainable_variables))\n            gen_b_to_a_optimizer.apply_gradients(zip(gen_b_to_a_grads, generator_b_to_a.trainable_variables))\n\n            # Update discriminators\n            disc_a_grads = tape.gradient(disc_a_loss, discriminator_a.trainable_variables)\n            disc_b_grads = tape.gradient(disc_b_loss, discriminator_b.trainable_variables)\n\n            disc_a_optimizer.apply_gradients(zip(disc_a_grads, discriminator_a.trainable_variables))\n            disc_b_optimizer.apply_gradients(zip(disc_b_grads, discriminator_b.trainable_variables))\n\n\n    print(f\"Epoch {epoch+1}/{EPOCHS} completed.\")\n    # checkpoint = tf.train.Checkpoint(generator=generator_a_to_b, optimizer=gen_optimizer)\n    # checkpoint.save('./checkpoints/my_checkpoint')\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-11-26T07:24:25.781319Z","iopub.execute_input":"2024-11-26T07:24:25.781738Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Save Photo → Monet generator\ngenerator_b_to_a.save('generator_b_to_a.h5')\n\n# Save Monet → Photo generator\ngenerator_a_to_b.save('generator_a_to_b.h5')\n","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import os\nimport zipfile\nimport tensorflow as tf\nfrom tensorflow.keras.utils import array_to_img\n\n# Directory to save generated images temporarily\ntemp_dir = \"../tmp/monet_images\"\nos.makedirs(temp_dir, exist_ok=True)\n\n# Define number of images to generate\nNUM_IMAGES = 8000  # Adjust as needed between 7000 and 10000\n\n# Generate and save Monet-style images\nfor i, photo_batch in enumerate(photos_dataset.take(NUM_IMAGES)):\n    # Ensure batch size is 1 for individual image generation\n    photo = tf.expand_dims(photo_batch[0], axis=0)  # Add batch dimension\n    monet_image = generator_b_to_a(photo, training=False)  # Generate Monet-style image\n    monet_image = array_to_img((monet_image[0] + 1.0) * 127.5)  # Denormalize to [0, 255]\n    \n    # Save the image in the temporary directory\n    monet_image.save(f\"{temp_dir}/monet_{i + 1}.jpg\")\n    print(f\"Saved: monet_{i + 1}.jpg\")\n    \n    # Stop if we've generated enough images\n    if i + 1 >= NUM_IMAGES:\n        break\n\n# Create a zip file containing all generated images\noutput_zip = \"images.zip\"\nwith zipfile.ZipFile(output_zip, 'w') as zf:\n    for root, _, files in os.walk(temp_dir):\n        for file in files:\n            zf.write(os.path.join(root, file), arcname=file)  # Add to zip, without folder structure\n\nprint(f\"Zip file {output_zip} created successfully.\")\n","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import matplotlib.pyplot as plt\n\n# Iterate over a few images in the photo dataset\nfor photo_batch in photos_dataset.take(3):  # Take 5 batches of photos\n    # Extract a single photo tensor from the batch\n    photo = photo_batch[0]  \n    photo = tf.expand_dims(photo, axis=0)  # Add batch dimension for generator\n\n    # Generate Monet-style image using the generator\n    monet_image = generator_b_to_a(photo, training=False)  \n\n    # Remove batch dimension and denormalize for visualization\n    photo = (photo[0] + 1.0) / 2.0  \n    monet_image = (monet_image[0] + 1.0) / 2.0  \n\n    # Plot original photo and Monet-style image\n    plt.figure(figsize=(10, 5))\n    \n  \n    plt.subplot(1, 2, 1)\n    plt.imshow(photo)\n    plt.title(\"Original Photo\")\n    \n  \n    plt.subplot(1, 2, 2)\n    plt.imshow(monet_image)\n    plt.title(\"Monet-Style Image\")\n    \n    plt.show()\n","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null}]}