{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.12.12","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"gpu","dataSources":[{"sourceId":21755,"databundleVersionId":1475600,"sourceType":"competition"}],"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"# **Getting Started** ","metadata":{}},{"cell_type":"markdown","source":"# Library","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19"}},{"cell_type":"code","source":"# Suppress TensorFlow warnings\nimport os\nos.environ['TF_CPP_MIN_LOG_LEVEL'] = '3'\n\nimport tensorflow as tf\nimport logging\ntf.get_logger().setLevel(logging.ERROR)\nloss_obj = tf.keras.losses.BinaryCrossentropy(from_logits=True)\n\n# Standard libraries\nimport numpy as np\nimport matplotlib.pyplot as plt\nimport zipfile\nfrom tensorflow.keras import layers\nimport shutil\n\n#Plots\nimport matplotlib.pyplot as plt\nfrom PIL import Image","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-15T04:03:57.570944Z","iopub.execute_input":"2026-02-15T04:03:57.571650Z","iopub.status.idle":"2026-02-15T04:03:57.576304Z","shell.execute_reply.started":"2026-02-15T04:03:57.571621Z","shell.execute_reply":"2026-02-15T04:03:57.575457Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"**Loading Dataset**","metadata":{}},{"cell_type":"code","source":"DATA_PATH = \"/kaggle/input/gan-getting-started\"\n\nmonet_path = os.path.join(DATA_PATH, \"monet_jpg\")\nphoto_path = os.path.join(DATA_PATH, \"photo_jpg\")\n\nprint(\"Photos:\", len(os.listdir(photo_path)))\nprint(\"Monet:\", len(os.listdir(monet_path)))\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-15T02:47:10.134504Z","iopub.execute_input":"2026-02-15T02:47:10.135098Z","iopub.status.idle":"2026-02-15T02:47:10.223409Z","shell.execute_reply.started":"2026-02-15T02:47:10.135069Z","shell.execute_reply":"2026-02-15T02:47:10.222670Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"**Build TensorFlow Dataset (Nothing Fancy)**","metadata":{}},{"cell_type":"code","source":"train_photo = tf.data.Dataset.list_files(photo_path + \"/*.jpg\", shuffle=True)\ntrain_monet = tf.data.Dataset.list_files(monet_path + \"/*.jpg\", shuffle=True)\n\nprint(train_photo)\nprint(train_monet)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-15T02:47:14.496704Z","iopub.execute_input":"2026-02-15T02:47:14.497031Z","iopub.status.idle":"2026-02-15T02:47:19.259081Z","shell.execute_reply.started":"2026-02-15T02:47:14.496985Z","shell.execute_reply":"2026-02-15T02:47:19.258412Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"**Image Preprocessing**","metadata":{}},{"cell_type":"code","source":"def preprocess_image(file_path):\n    image = tf.io.read_file(file_path)\n    image = tf.image.decode_jpeg(image, channels=3)\n    image = tf.image.convert_image_dtype(image, tf.float32)\n    image = (image * 2.0) - 1.0  # Normalize to [-1,1]\n    return image\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-15T02:47:36.085140Z","iopub.execute_input":"2026-02-15T02:47:36.085916Z","iopub.status.idle":"2026-02-15T02:47:36.089820Z","shell.execute_reply.started":"2026-02-15T02:47:36.085889Z","shell.execute_reply":"2026-02-15T02:47:36.089150Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"**Apply Preprocessing + Batch**","metadata":{}},{"cell_type":"code","source":"AUTOTUNE = tf.data.AUTOTUNE\nBATCH_SIZE = 1\n\ntrain_photo_ds = train_photo.map(preprocess_image, num_parallel_calls=AUTOTUNE)\ntrain_monet_ds = train_monet.map(preprocess_image, num_parallel_calls=AUTOTUNE)\n\ntrain_photo_ds = train_photo_ds.batch(BATCH_SIZE)\ntrain_monet_ds = train_monet_ds.batch(BATCH_SIZE)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-15T02:47:47.713346Z","iopub.execute_input":"2026-02-15T02:47:47.713953Z","iopub.status.idle":"2026-02-15T02:47:47.954588Z","shell.execute_reply.started":"2026-02-15T02:47:47.713927Z","shell.execute_reply":"2026-02-15T02:47:47.953833Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"**Inspect Dataset: a few inages**","metadata":{}},{"cell_type":"code","source":"sample_photo = next(iter(train_photo_ds))\nsample_monet = next(iter(train_monet_ds))\n\nfig, axes = plt.subplots(1, 2, figsize=(6,6))\n\naxes[0].imshow((sample_photo[0] + 1) / 2)\naxes[0].set_title(\"Sample Photo\")\naxes[0].set_xticks([])\naxes[0].set_yticks([])\naxes[0].set_frame_on(True)\n\naxes[1].imshow((sample_monet[0] + 1) / 2)\naxes[1].set_title(\"Sample Monet Painting\")\naxes[1].set_xticks([])\naxes[1].set_yticks([])\naxes[1].set_frame_on(True)\n\nplt.tight_layout()\nplt.show()\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-15T02:48:04.917114Z","iopub.execute_input":"2026-02-15T02:48:04.917462Z","iopub.status.idle":"2026-02-15T02:48:05.116473Z","shell.execute_reply.started":"2026-02-15T02:48:04.917436Z","shell.execute_reply":"2026-02-15T02:48:05.115815Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"**Build Generator**","metadata":{}},{"cell_type":"code","source":"# CycleGAN Generator\ndef resnet_block(x):\n    skip = x\n    x = layers.Conv2D(256, 3, padding=\"same\")(x)\n    x = layers.ReLU()(x)\n    x = layers.Conv2D(256, 3, padding=\"same\")(x)\n    return layers.add([skip, x])\n\ndef build_generator():\n    inputs = layers.Input(shape=[256,256,3])\n    \n    x = layers.Conv2D(64, 7, padding=\"same\")(inputs)\n    x = layers.ReLU()(x)\n    \n    x = layers.Conv2D(128, 3, strides=2, padding=\"same\")(x)\n    x = layers.ReLU()(x)\n    \n    x = layers.Conv2D(256, 3, strides=2, padding=\"same\")(x)\n    x = layers.ReLU()(x)\n    \n    for _ in range(6):\n        x = resnet_block(x)\n    \n    x = layers.Conv2DTranspose(128, 3, strides=2, padding=\"same\")(x)\n    x = layers.ReLU()(x)\n    \n    x = layers.Conv2DTranspose(64, 3, strides=2, padding=\"same\")(x)\n    x = layers.ReLU()(x)\n    \n    outputs = layers.Conv2D(3, 7, padding=\"same\", activation=\"tanh\")(x)\n    \n    return tf.keras.Model(inputs, outputs)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-15T02:48:08.234691Z","iopub.execute_input":"2026-02-15T02:48:08.235280Z","iopub.status.idle":"2026-02-15T02:48:08.241810Z","shell.execute_reply.started":"2026-02-15T02:48:08.235252Z","shell.execute_reply":"2026-02-15T02:48:08.241046Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"**Create Generators**","metadata":{}},{"cell_type":"code","source":"generator_g = build_generator()  # Photo → Monet\ngenerator_f = build_generator()  # Monet → Photo\n\nprint(\"Generator G (Photo → Monet):\")\ngenerator_g.summary()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-15T02:48:15.560729Z","iopub.execute_input":"2026-02-15T02:48:15.561341Z","iopub.status.idle":"2026-02-15T02:48:16.564465Z","shell.execute_reply.started":"2026-02-15T02:48:15.561314Z","shell.execute_reply":"2026-02-15T02:48:16.563729Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"**Build Discriminator**","metadata":{}},{"cell_type":"code","source":"def build_discriminator():\n    inputs = layers.Input(shape=[256,256,3])\n    \n    x = layers.Conv2D(64, 4, strides=2, padding=\"same\")(inputs)\n    x = layers.LeakyReLU(0.2)(x)\n    \n    x = layers.Conv2D(128, 4, strides=2, padding=\"same\")(x)\n    x = layers.LeakyReLU(0.2)(x)\n    \n    x = layers.Conv2D(256, 4, strides=2, padding=\"same\")(x)\n    x = layers.LeakyReLU(0.2)(x)\n    \n    outputs = layers.Conv2D(1, 4, padding=\"same\")(x)\n    \n    return tf.keras.Model(inputs, outputs)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-15T02:48:21.330864Z","iopub.execute_input":"2026-02-15T02:48:21.331473Z","iopub.status.idle":"2026-02-15T02:48:21.336157Z","shell.execute_reply.started":"2026-02-15T02:48:21.331443Z","shell.execute_reply":"2026-02-15T02:48:21.335388Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"**Create Discriminator**","metadata":{}},{"cell_type":"code","source":"discriminator_x = build_discriminator()  # Photo discriminator\ndiscriminator_y = build_discriminator()  # Monet discriminator\n\nprint(\"Discriminators created successfully.\")\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-15T02:48:25.506131Z","iopub.execute_input":"2026-02-15T02:48:25.506895Z","iopub.status.idle":"2026-02-15T02:48:25.571345Z","shell.execute_reply.started":"2026-02-15T02:48:25.506867Z","shell.execute_reply":"2026-02-15T02:48:25.570598Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"**Define Loss Functions**","metadata":{}},{"cell_type":"code","source":"loss_obj = tf.keras.losses.BinaryCrossentropy(from_logits=True)\n\ndef discriminator_loss(real, generated):\n    real_loss = loss_obj(tf.ones_like(real), real)\n    generated_loss = loss_obj(tf.zeros_like(generated), generated)\n    return (real_loss + generated_loss) * 0.5\n\ndef generator_loss(generated):\n    return loss_obj(tf.ones_like(generated), generated)\n\ndef cycle_loss(real_image, cycled_image):\n    return tf.reduce_mean(tf.abs(real_image - cycled_image)) * 10\n    \ndef identity_loss(real_image, same_image):\n    return tf.reduce_mean(tf.abs(real_image - same_image)) * 5\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-15T02:48:27.424081Z","iopub.execute_input":"2026-02-15T02:48:27.424637Z","iopub.status.idle":"2026-02-15T02:48:27.429837Z","shell.execute_reply.started":"2026-02-15T02:48:27.424605Z","shell.execute_reply":"2026-02-15T02:48:27.429230Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"**Optimizers**","metadata":{}},{"cell_type":"code","source":"generator_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\nprint(\"Optimizers ready.\")\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-15T02:48:31.300847Z","iopub.execute_input":"2026-02-15T02:48:31.301121Z","iopub.status.idle":"2026-02-15T02:48:31.317948Z","shell.execute_reply.started":"2026-02-15T02:48:31.301100Z","shell.execute_reply":"2026-02-15T02:48:31.317402Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"**Training Step Function**","metadata":{}},{"cell_type":"code","source":"@tf.function\ndef train_step(real_x, real_y):\n    with tf.GradientTape(persistent=True) as tape:\n        \n        # Photo → Monet\n        fake_y = generator_g(real_x, training=True)\n        cycled_x = generator_f(fake_y, training=True)\n        \n        # Monet → Photo\n        fake_x = generator_f(real_y, training=True)\n        cycled_y = generator_g(fake_x, training=True)\n\n        # Identity mapping\n        same_x = generator_f(real_x, training=True)\n        same_y = generator_g(real_y, training=True)\n\n        # Discriminator predictions\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        # Generator losses\n        gen_g_loss = generator_loss(disc_fake_y)\n        gen_f_loss = generator_loss(disc_fake_x)\n        \n\n        total_cycle_loss = cycle_loss(real_x, cycled_x) + cycle_loss(real_y, cycled_y)\n\n        # Identity loss\n        id_loss = identity_loss(real_y, same_y) + identity_loss(real_x, same_x)\n\n        total_gen_g_loss = gen_g_loss + total_cycle_loss + id_loss\n        total_gen_f_loss = gen_f_loss + total_cycle_loss + id_loss\n\n        # Discriminator losses\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    # Apply gradients\n    generator_g_optimizer.apply_gradients(\n        zip(tape.gradient(total_gen_g_loss, generator_g.trainable_variables),\n            generator_g.trainable_variables)\n    )\n    \n    generator_f_optimizer.apply_gradients(\n        zip(tape.gradient(total_gen_f_loss, generator_f.trainable_variables),\n            generator_f.trainable_variables)\n    )\n    \n    discriminator_x_optimizer.apply_gradients(\n        zip(tape.gradient(disc_x_loss, discriminator_x.trainable_variables),\n            discriminator_x.trainable_variables)\n    )\n    \n    discriminator_y_optimizer.apply_gradients(\n        zip(tape.gradient(disc_y_loss, discriminator_y.trainable_variables),\n            discriminator_y.trainable_variables)\n    )\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-15T02:48:34.962707Z","iopub.execute_input":"2026-02-15T02:48:34.963311Z","iopub.status.idle":"2026-02-15T02:48:34.970687Z","shell.execute_reply.started":"2026-02-15T02:48:34.963283Z","shell.execute_reply":"2026-02-15T02:48:34.970011Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"**Training Loop(Trial)**","metadata":{}},{"cell_type":"code","source":"EPOCHS = 30 \n\nfor epoch in range(EPOCHS):\n    print(f\"Starting Epoch {epoch+1}/{EPOCHS}\")\n    \n    for real_x, real_y in tf.data.Dataset.zip((train_photo_ds, train_monet_ds)):\n        train_step(real_x, real_y)\n    \n    print(f\"Finished Epoch {epoch+1}\")\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-15T02:48:38.529711Z","iopub.execute_input":"2026-02-15T02:48:38.530490Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"**Displaying Output after training on 30 epocs**","metadata":{}},{"cell_type":"code","source":"\ndef show_translation(photo_batch, generator):\n    prediction = generator(photo_batch, training=False)\n\n    plt.figure(figsize=(10,7))\n\n    display_list = [photo_batch[0], prediction[0]]\n    title = ['Input Photo', 'Monet Style Output']\n\n    for i in range(2):\n        plt.subplot(1,2,i+1 )\n        plt.title(title[i])\n        plt.imshow((display_list[i] * 0.5) + 0.5)  # denormalize\n        plt.axis('off')\n\n    plt.show()\n\n# Take one sample batch\nfor sample_photo in train_photo_ds.take(4):\n    show_translation(sample_photo, generator_g)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-15T04:46:09.161637Z","iopub.execute_input":"2026-02-15T04:46:09.161921Z","iopub.status.idle":"2026-02-15T04:46:10.263067Z","shell.execute_reply.started":"2026-02-15T04:46:09.161896Z","shell.execute_reply":"2026-02-15T04:46:10.262532Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"**Kaggle Submission Session**","metadata":{}},{"cell_type":"markdown","source":"<h4>part 1</h4>","metadata":{}},{"cell_type":"markdown","source":"**Submission File**","metadata":{}},{"cell_type":"code","source":"\n#output_dir = \"generated_images\"\n#os.makedirs(output_dir, exist_ok=True)\n\n#count = 0\n\n#for batch in train_photo_ds:\n    #prediction = generator_g(batch, training=False)\n    \n    #for i in range(prediction.shape[0]):\n       # img = (prediction[i] * 0.5 + 0.5) * 255\n       # img = tf.cast(img, tf.uint8)\n       # img = Image.fromarray(img.numpy())\n       # img.save(f\"{output_dir}/{count}.jpg\")\n       # count += 1\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-14T18:55:27.940911Z","iopub.execute_input":"2026-02-14T18:55:27.941193Z","iopub.status.idle":"2026-02-14T18:59:29.152072Z","shell.execute_reply.started":"2026-02-14T18:55:27.941172Z","shell.execute_reply":"2026-02-14T18:59:29.151473Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"\n#with zipfile.ZipFile(\"images.zip\", \"w\") as z:\n  #  for file in os.listdir(output_dir):\n       # z.write(os.path.join(output_dir, file), arcname=file)\n#print(\"Zip file created successfully.\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-14T18:59:29.152874Z","iopub.execute_input":"2026-02-14T18:59:29.153152Z","iopub.status.idle":"2026-02-14T18:59:29.828870Z","shell.execute_reply.started":"2026-02-14T18:59:29.153131Z","shell.execute_reply":"2026-02-14T18:59:29.828238Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"","metadata":{}},{"cell_type":"code","source":"from PIL import Image\nimport os\nimport numpy as np\nimport shutil\n\nos.makedirs(\"/kaggle/working/images\", exist_ok=True)\n\ni = 1\nfor img in train_photo_ds.unbatch().take(10000):\n\n    img = tf.expand_dims(img, axis=0)\n    prediction = generator_g(img, training=False)[0].numpy()\n\n    prediction = (prediction * 127.5 + 127.5).astype(np.uint8)\n\n    im = Image.fromarray(prediction)\n    im.save(f\"/kaggle/working/images/{i}.jpg\")\n\n    i += 1\n\nshutil.make_archive(\"images\", 'zip', \"/kaggle/working/images\")\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-15T04:21:31.793399Z","iopub.execute_input":"2026-02-15T04:21:31.793994Z","iopub.status.idle":"2026-02-15T04:25:34.157520Z","shell.execute_reply.started":"2026-02-15T04:21:31.793963Z","shell.execute_reply":"2026-02-15T04:25:34.156723Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null}]}