{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.10.12","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"nvidiaTeslaT4","dataSources":[{"sourceId":21755,"databundleVersionId":1475600,"sourceType":"competition"}],"dockerImageVersionId":30919,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"!pip uninstall tensorflow -y\n!pip install tensorflow==2.15.0","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-04T16:12:46.555532Z","iopub.execute_input":"2025-04-04T16:12:46.555807Z","iopub.status.idle":"2025-04-04T16:12:46.559221Z","shell.execute_reply.started":"2025-04-04T16:12:46.555786Z","shell.execute_reply":"2025-04-04T16:12:46.558416Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"!pip install tensorflow-addons","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-04T16:12:47.623260Z","iopub.execute_input":"2025-04-04T16:12:47.623566Z","iopub.status.idle":"2025-04-04T16:12:47.627333Z","shell.execute_reply.started":"2025-04-04T16:12:47.623544Z","shell.execute_reply":"2025-04-04T16:12:47.626334Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import matplotlib.pyplot as plt\nimport numpy as np\nimport tensorflow as tf\nimport tensorflow_addons as tfa\nimport cv2\nimport os\nfrom tensorflow.keras import layers, Model\n\n# TPU setup (if available)\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\nprint(tf.__version__)\n\n# Define directories\nmonet_jpg_directory = '/kaggle/input/gan-getting-started/monet_jpg'\nphoto_jpg_directory = '/kaggle/input/gan-getting-started/photo_jpg'","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true,"execution":{"iopub.status.busy":"2025-04-04T16:12:49.699684Z","iopub.execute_input":"2025-04-04T16:12:49.700054Z","iopub.status.idle":"2025-04-04T16:12:55.837422Z","shell.execute_reply.started":"2025-04-04T16:12:49.700018Z","shell.execute_reply":"2025-04-04T16:12:55.836681Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Function to get image paths\ndef getImagePaths(path):\n    image_names = []\n    for dirname, _, filenames in os.walk(path):\n        for filename in filenames:\n            fullpath = os.path.join(dirname, filename)\n            image_names.append(fullpath)\n    return image_names\n\nmonet_images_path = getImagePaths(monet_jpg_directory)\nphoto_images_path = getImagePaths(photo_jpg_directory)\n\nprint(f\"Number of Monet images: {len(monet_images_path)}\")\nprint(f\"Number of Photo images: {len(photo_images_path)}\")\n\n# Image preprocessing function\ndef preprocess_image(image_path):\n    image = tf.io.read_file(image_path)\n    image = tf.image.decode_jpeg(image, channels=3)\n    image = tf.cast(image, tf.float32)\n    image = (image / 127.5) - 1  # Normalize to [-1, 1]\n    return image\n\n# Create TensorFlow datasets\nmonet_ds = tf.data.Dataset.from_tensor_slices(monet_images_path).map(preprocess_image, num_parallel_calls=AUTOTUNE)\nphoto_ds = tf.data.Dataset.from_tensor_slices(photo_images_path).map(preprocess_image, num_parallel_calls=AUTOTUNE)\n\n# Batch and shuffle the datasets\nBATCH_SIZE = 1  # CycleGAN typically uses a batch size of 1\nmonet_ds = monet_ds.cache().shuffle(1000).batch(BATCH_SIZE).prefetch(AUTOTUNE)\nphoto_ds = photo_ds.cache().shuffle(1000).batch(BATCH_SIZE).prefetch(AUTOTUNE)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-04T16:13:34.821807Z","iopub.execute_input":"2025-04-04T16:13:34.822595Z","iopub.status.idle":"2025-04-04T16:13:53.481304Z","shell.execute_reply.started":"2025-04-04T16:13:34.822553Z","shell.execute_reply":"2025-04-04T16:13:53.480574Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Downsampling block\ndef downsample(filters, size, apply_instancenorm=True):\n    initializer = tf.random_normal_initializer(0., 0.02)\n    result = tf.keras.Sequential()\n    result.add(layers.Conv2D(filters, size, strides=2, padding='same',\n                             kernel_initializer=initializer, use_bias=False))\n    if apply_instancenorm:\n        result.add(tfa.layers.InstanceNormalization())\n    result.add(layers.LeakyReLU())\n    return result\n\n# Upsampling block\ndef upsample(filters, size, apply_dropout=False):\n    initializer = tf.random_normal_initializer(0., 0.02)\n    result = tf.keras.Sequential()\n    result.add(layers.Conv2DTranspose(filters, size, strides=2, padding='same',\n                                      kernel_initializer=initializer, use_bias=False))\n    result.add(tfa.layers.InstanceNormalization())\n    if apply_dropout:\n        result.add(layers.Dropout(0.5))\n    result.add(layers.ReLU())\n    return result\n\n# Generator model\ndef Generator():\n    inputs = layers.Input(shape=[256, 256, 3])\n    \n    # Encoder (downsampling)\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    # Decoder (upsampling)\n    up_stack = [\n        upsample(512, 4, apply_dropout=True),  # (bs, 2, 2, 512)\n        upsample(512, 4, apply_dropout=True),  # (bs, 4, 4, 512)\n        upsample(512, 4, apply_dropout=True),  # (bs, 8, 8, 512)\n        upsample(512, 4),  # (bs, 16, 16, 512)\n        upsample(256, 4),  # (bs, 32, 32, 256)\n        upsample(128, 4),  # (bs, 64, 64, 128)\n        upsample(64, 4),  # (bs, 128, 128, 64)\n    ]\n    \n    initializer = tf.random_normal_initializer(0., 0.02)\n    last = layers.Conv2DTranspose(3, 4, strides=2, padding='same',\n                                  kernel_initializer=initializer, activation='tanh')  # (bs, 256, 256, 3)\n    \n    x = inputs\n    skips = []  # For skip connections\n    for down in down_stack:\n        x = down(x)\n        skips.append(x)\n    \n    skips = reversed(skips[:-1])\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    return Model(inputs=inputs, outputs=x)\n\n# Instantiate generators\nwith strategy.scope():\n    monet_generator = Generator()  # Photo -> Monet\n    photo_generator = Generator()  # Monet -> Photo","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-04T16:14:01.833435Z","iopub.execute_input":"2025-04-04T16:14:01.833740Z","iopub.status.idle":"2025-04-04T16:14:04.238701Z","shell.execute_reply.started":"2025-04-04T16:14:01.833716Z","shell.execute_reply":"2025-04-04T16:14:04.238004Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def Discriminator():\n    initializer = tf.random_normal_initializer(0., 0.02)\n    inp = layers.Input(shape=[256, 256, 3], name='input_image')\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, kernel_initializer=initializer,\n                         use_bias=False)(zero_pad1)  # (bs, 31, 31, 512)\n    norm1 = tfa.layers.InstanceNormalization()(conv)\n    leaky_relu = layers.LeakyReLU()(norm1)\n    zero_pad2 = layers.ZeroPadding2D()(leaky_relu)  # (bs, 33, 33, 512)\n    last = layers.Conv2D(1, 4, strides=1, kernel_initializer=initializer)(zero_pad2)  # (bs, 30, 30, 1)\n    \n    return Model(inputs=inp, outputs=last)\n\n# Instantiate discriminators\nwith strategy.scope():\n    monet_discriminator = Discriminator()  # Discriminates Monet images\n    photo_discriminator = Discriminator()  # Discriminates Photo images","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-04T16:14:21.134162Z","iopub.execute_input":"2025-04-04T16:14:21.134502Z","iopub.status.idle":"2025-04-04T16:14:21.512200Z","shell.execute_reply.started":"2025-04-04T16:14:21.134477Z","shell.execute_reply":"2025-04-04T16:14:21.511478Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def generate_and_show_images(generator, input_dataset, num_images=3):\n    # Get one batch from the dataset\n    for sample_input in input_dataset.take(1):\n        # If batch size < num_images, adjust\n        batch_size = sample_input.shape[0]\n        num_images = min(num_images, batch_size)\n        \n        prediction = generator(sample_input, training=False)\n\n        plt.figure(figsize=(12, 6))\n        for i in range(num_images):\n            # Input image\n            plt.subplot(2, num_images, i + 1)\n            plt.imshow(((sample_input[i] + 1) / 2.0).numpy())  # Scale from [-1, 1] to [0, 1]\n            plt.title(\"Input\")\n            plt.axis(\"off\")\n\n            # Generated image\n            plt.subplot(2, num_images, i + 1 + num_images)\n            plt.imshow(((prediction[i] + 1) / 2.0).numpy())  # Scale from [-1, 1] to [0, 1]\n            plt.title(\"Generated\")\n            plt.axis(\"off\")\n\n        plt.tight_layout()\n        plt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-04T16:44:40.160777Z","iopub.execute_input":"2025-04-04T16:44:40.161209Z","iopub.status.idle":"2025-04-04T16:44:40.167450Z","shell.execute_reply.started":"2025-04-04T16:44:40.161175Z","shell.execute_reply":"2025-04-04T16:44:40.166448Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Loss functions (ensure scalar outputs)\nwith strategy.scope():\n    loss_obj = tf.keras.losses.BinaryCrossentropy(from_logits=True, reduction=tf.keras.losses.Reduction.NONE)\n\ndef discriminator_loss(real, generated):\n    real_loss = tf.reduce_mean(loss_obj(tf.ones_like(real), real))  # Reduce to scalar\n    generated_loss = tf.reduce_mean(loss_obj(tf.zeros_like(generated), generated))  # Reduce to scalar\n    total_disc_loss = real_loss + generated_loss\n    return total_disc_loss * 0.5\n\ndef generator_loss(generated):\n    return tf.reduce_mean(loss_obj(tf.ones_like(generated), generated))  # Reduce to scalar\n\ndef calc_cycle_loss(real_image, cycled_image, LAMBDA=10):\n    loss = tf.reduce_mean(tf.abs(real_image - cycled_image))\n    return LAMBDA * loss\n\ndef identity_loss(real_image, same_image, LAMBDA=10):\n    loss = tf.reduce_mean(tf.abs(real_image - same_image))\n    return LAMBDA * 0.5 * loss\n\n# Training step (already ensures scalar losses due to tf.reduce_mean in loss functions)\nwith 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    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)\n\n@tf.function\ndef train_step(real_monet, real_photo):\n    with tf.GradientTape(persistent=True) as tape:\n        fake_monet = monet_generator(real_photo, training=True)\n        cycled_photo = photo_generator(fake_monet, training=True)\n        fake_photo = photo_generator(real_monet, training=True)\n        cycled_monet = monet_generator(fake_photo, training=True)\n        same_monet = monet_generator(real_monet, training=True)\n        same_photo = photo_generator(real_photo, training=True)\n        disc_real_monet = monet_discriminator(real_monet, training=True)\n        disc_real_photo = photo_discriminator(real_photo, training=True)\n        disc_fake_monet = monet_discriminator(fake_monet, training=True)\n        disc_fake_photo = photo_discriminator(fake_photo, training=True)\n        monet_gen_loss = generator_loss(disc_fake_monet)\n        photo_gen_loss = generator_loss(disc_fake_photo)\n        total_cycle_loss = calc_cycle_loss(real_monet, cycled_monet) + calc_cycle_loss(real_photo, cycled_photo)\n        total_monet_gen_loss = monet_gen_loss + total_cycle_loss + identity_loss(real_monet, same_monet)\n        total_photo_gen_loss = photo_gen_loss + total_cycle_loss + identity_loss(real_photo, same_photo)\n        monet_disc_loss = discriminator_loss(disc_real_monet, disc_fake_monet)\n        photo_disc_loss = discriminator_loss(disc_real_photo, disc_fake_photo)\n    \n    monet_generator_gradients = tape.gradient(total_monet_gen_loss, monet_generator.trainable_variables)\n    photo_generator_gradients = tape.gradient(total_photo_gen_loss, photo_generator.trainable_variables)\n    monet_discriminator_gradients = tape.gradient(monet_disc_loss, monet_discriminator.trainable_variables)\n    photo_discriminator_gradients = tape.gradient(photo_disc_loss, photo_discriminator.trainable_variables)\n    \n    monet_generator_optimizer.apply_gradients(zip(monet_generator_gradients, monet_generator.trainable_variables))\n    photo_generator_optimizer.apply_gradients(zip(photo_generator_gradients, photo_generator.trainable_variables))\n    monet_discriminator_optimizer.apply_gradients(zip(monet_discriminator_gradients, monet_discriminator.trainable_variables))\n    photo_discriminator_optimizer.apply_gradients(zip(photo_discriminator_gradients, photo_discriminator.trainable_variables))\n    \n    return total_monet_gen_loss, total_photo_gen_loss, monet_disc_loss, photo_disc_loss\n\n# Training loop with corrected printing\n# Training loop with visual output every 10 epochs\nEPOCHS = 50\nfor epoch in range(EPOCHS):\n    print(f\"\\nEpoch {epoch + 1}/{EPOCHS}\")\n    for real_monet, real_photo in tf.data.Dataset.zip((monet_ds, photo_ds)):\n        monet_gen_loss, photo_gen_loss, monet_disc_loss, photo_disc_loss = train_step(real_monet, real_photo)\n    \n    # Convert tensors to NumPy scalars for printing\n    monet_gen_loss = monet_gen_loss.numpy()\n    photo_gen_loss = photo_gen_loss.numpy()\n    monet_disc_loss = monet_disc_loss.numpy()\n    photo_disc_loss = photo_disc_loss.numpy()\n\n    print(f\"Monet Gen Loss: {monet_gen_loss:.4f}, Photo Gen Loss: {photo_gen_loss:.4f}, \"\n          f\"Monet Disc Loss: {monet_disc_loss:.4f}, Photo Disc Loss: {photo_disc_loss:.4f}\")\n    \n    if (epoch + 1) % 10 == 0:\n        print(f\"\\nGenerated images at epoch {epoch + 1}\")\n        generate_and_show_images(monet_generator, photo_ds)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-04T16:45:31.910419Z","iopub.execute_input":"2025-04-04T16:45:31.910768Z","iopub.status.idle":"2025-04-04T18:35:43.736584Z","shell.execute_reply.started":"2025-04-04T16:45:31.910737Z","shell.execute_reply":"2025-04-04T18:35:43.735613Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def display_generated_images(photo_ds, num_images=5):\n    plt.figure(figsize=(25, 15))\n    for i, photo in enumerate(photo_ds.take(num_images)):\n        fake_monet = monet_generator(photo, training=False)\n        fake_monet = (fake_monet[0] * 0.5 + 0.5)  # Denormalize to [0, 1]\n        photo = (photo[0] * 0.5 + 0.5)  # Denormalize to [0, 1]\n        \n        plt.subplot(2, num_images, i + 1)\n        plt.imshow(photo)\n        plt.title(\"Original Photo\")\n        plt.axis('off')\n        \n        plt.subplot(2, num_images, i + 1 + num_images)\n        plt.imshow(fake_monet)\n        plt.title(\"Monet Style\")\n        plt.axis('off')\n    plt.show()\n\n# Display generated images\ndisplay_generated_images(photo_ds)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-04T18:35:43.738296Z","iopub.execute_input":"2025-04-04T18:35:43.738646Z","iopub.status.idle":"2025-04-04T18:35:46.074877Z","shell.execute_reply.started":"2025-04-04T18:35:43.738613Z","shell.execute_reply":"2025-04-04T18:35:46.073881Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import os\nimport zipfile\nimport numpy as np\nimport tensorflow as tf\nfrom PIL import Image\n\n# Define the output directory for temporary image storage\noutput_dir = '/kaggle/working/images'\nos.makedirs(output_dir, exist_ok=True)\n\n# Function to generate and save Monet-style images\ndef generate_and_save_images(photo_ds, monet_generator, num_images=7000):\n    \"\"\"\n    Generate Monet-style images from photos using the trained generator and save them as JPEG files.\n    \n    Args:\n        photo_ds: TensorFlow dataset containing photo images.\n        monet_generator: Trained CycleGAN generator model for Monet-style conversion.\n        num_images: Number of images to generate (default: 7000).\n    \"\"\"\n    count = 0\n    for photo in photo_ds:\n        if count >= num_images:\n            break\n        # Generate Monet-style image\n        fake_monet = monet_generator(photo, training=False)\n        # Denormalize from [-1, 1] to [0, 1]\n        fake_monet = (fake_monet[0] * 0.5 + 0.5)\n        # Ensure pixel values are within [0, 1]\n        fake_monet = tf.clip_by_value(fake_monet, 0, 1)\n        # Convert to uint8 format (0-255) for image saving\n        fake_monet = (fake_monet * 255).numpy().astype(np.uint8)\n        \n        # Save the image as JPEG (256x256x3 RGB format)\n        img = Image.fromarray(fake_monet)\n        img.save(os.path.join(output_dir, f'monet_{count:04d}.jpg'))\n        count += 1\n    print(f\"Generated {count} Monet-style images.\")\n\n# Placeholder for the photo dataset and generator (to be provided by the user)\n# Example: photo_ds = tf.data.Dataset.from_tensor_slices(...) # Load your photo dataset\n# Example: monet_generator = ... # Load your trained Monet generator model\n\n# Generate 7,000 Monet-style images (adjust num_images as needed between 7,000-10,000)\ngenerate_and_save_images(photo_ds, monet_generator, num_images=7000)\n\n# Create a zip file containing all generated images\nzip_filename = '/kaggle/working/images.zip'\nwith zipfile.ZipFile(zip_filename, 'w', compression=zipfile.ZIP_DEFLATED) as zipf:\n    for root, _, files in os.walk(output_dir):\n        for file in files:\n            # Add each image to the zip file with just the filename (no directory structure)\n            zipf.write(os.path.join(root, file), arcname=file)\n\n# Output confirmation\nprint(f\"Submission file created: {zip_filename}\")\nprint(f\"Total images zipped: {len(os.listdir(output_dir))}\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-04T18:35:46.077009Z","iopub.execute_input":"2025-04-04T18:35:46.077449Z","iopub.status.idle":"2025-04-04T18:43:54.626954Z","shell.execute_reply.started":"2025-04-04T18:35:46.077397Z","shell.execute_reply":"2025-04-04T18:43:54.625853Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null}]}