{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.11.11","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"},{"sourceId":400870,"sourceType":"modelInstanceVersion","isSourceIdPinned":true,"modelInstanceId":328024,"modelId":348877}],"dockerImageVersionId":31040,"isInternetEnabled":false,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"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\n#import numpy as np # linear algebra\n#import 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\n#import os\n#import shutil\n\n#for dirname, _, filenames in os.walk('/kaggle/input/gan_model'):\n#    for filename in filenames:\n#        print(os.path.join(dirname, filename))\n\n#def delete_directory_contents(dir_path):\n#    \"\"\"Deletes all files and subdirectories within a specified directory.\n#\n#    Args:\n#        dir_path: The path to the directory whose contents should be deleted.\n#    \"\"\"\n#    for filename in os.listdir(dir_path):\n#        file_path = os.path.join(dir_path, filename)\n#        try:\n#            if os.path.isfile(file_path) or os.path.islink(file_path):\n#                os.unlink(file_path)\n#            elif os.path.isdir(file_path):\n#                shutil.rmtree(file_path)\n#        except Exception as e:\n#            print(f\"Failed to delete {file_path}. Reason: {e}\")\n\n#delete_directory_contents('/kaggle/input/gan_model/')\n#for dirname, _, filenames in os.walk('/kaggle/input/gan_model):\n#    for filename in filenames:\n#        print(os.path.join(dirname, filename))\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","execution":{"iopub.status.busy":"2025-05-20T20:13:13.492451Z","iopub.execute_input":"2025-05-20T20:13:13.492669Z","iopub.status.idle":"2025-05-20T20:13:27.334516Z","shell.execute_reply.started":"2025-05-20T20:13:13.492647Z","shell.execute_reply":"2025-05-20T20:13:27.333884Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Import necessary libraries\nimport os\nimport time\nimport zipfile\nimport numpy as np\nimport pandas as pd\nimport matplotlib.pyplot as plt\nfrom glob import glob\nfrom tqdm.notebook import tqdm\n\nimport tensorflow as tf\nfrom tensorflow import keras\nfrom tensorflow.keras import layers\nfrom tensorflow.keras.preprocessing.image import load_img, img_to_array\nfrom tensorflow.data.experimental import AUTOTUNE\n\nimport warnings\nwarnings.filterwarnings('ignore')\n\n# Set random seeds for reproducibility\nSEED = 42\nnp.random.seed(SEED)\ntf.random.set_seed(SEED)\n\n# Define paths\nMONET_JPG_PATH = '/kaggle/input/gan-getting-started/monet_jpg/'\nPHOTO_JPG_PATH = '/kaggle/input/gan-getting-started/photo_jpg/'\nMONET_TFREC_PATH = '/kaggle/input/gan-getting-started/monet_tfrec/'\nPHOTO_TFREC_PATH = '/kaggle/input/gan-getting-started/photo_tfrec/'\n\n# Count images in each directory\nmonet_jpg_files = tf.io.gfile.glob(os.path.join(MONET_JPG_PATH, '*.jpg'))\nphoto_jpg_files = tf.io.gfile.glob(os.path.join(PHOTO_JPG_PATH, '*.jpg'))\nmonet_tfrec_files = tf.io.gfile.glob(os.path.join(MONET_TFREC_PATH, '*.tfrec'))\nphoto_tfrec_files = tf.io.gfile.glob(os.path.join(PHOTO_TFREC_PATH, '*.tfrec'))\n\nprint(f\"Number of Monet paintings (JPG): {len(monet_jpg_files)}\")\nprint(f\"Number of Photos (JPG): {len(photo_jpg_files)}\")\nprint(f\"\\nNumber of Monet TFRECs: {len(monet_tfrec_files)}\")\nprint(f\"Number of Photos TFRECs: {len(photo_tfrec_files)}\")\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-19T17:16:18.504501Z","iopub.execute_input":"2025-05-19T17:16:18.504797Z","iopub.status.idle":"2025-05-19T17:16:39.139819Z","shell.execute_reply.started":"2025-05-19T17:16:18.504780Z","shell.execute_reply":"2025-05-19T17:16:39.139174Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"IMAGE_SIZE = [256, 256] # All images are 256x256\nBATCH_SIZE_PER_REPLICA = 16 \nGLOBAL_BATCH_SIZE = BATCH_SIZE_PER_REPLICA * tf.distribute.get_strategy().num_replicas_in_sync\nAUTOTUNE = tf.data.AUTOTUNE\n\n# Decode TFREC Images\ndef decode_image(image_data):\n    image = tf.image.decode_jpeg(image_data, channels=3)\n    image = tf.cast(image, tf.float32) / 127.5 - 1 # Normalize to [-1, 1]\n    image = tf.reshape(image, [*IMAGE_SIZE, 3])\n    return image\n\n# Read TFREC records\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    \n    example = tf.io.parse_single_example(example, tfrecord_format)\n    image = decode_image(example['image'])\n    return image\n\n# Function to Load dataset\ndef load_dataset(filenames, labeled=True, ordered=False):\n    dataset = tf.data.TFRecordDataset(filenames, num_parallel_reads=AUTOTUNE)\n    dataset = dataset.map(read_tfrecord, num_parallel_calls=AUTOTUNE)\n    return dataset\n\n\n# Load Monet & Phoro TFREC files\nmonet_ds = load_dataset(monet_tfrec_files, labeled=True)\nphoto_ds = load_dataset(photo_tfrec_files, labeled=True)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-19T17:16:39.140482Z","iopub.execute_input":"2025-05-19T17:16:39.141000Z","iopub.status.idle":"2025-05-19T17:16:40.444917Z","shell.execute_reply.started":"2025-05-19T17:16:39.140979Z","shell.execute_reply":"2025-05-19T17:16:40.444210Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Data augmentation function\ndef data_augmentation(image):\n    # Random flip\n    image = tf.image.random_flip_left_right(image)\n    \n    # Random crop and resize\n    image = tf.image.resize(image, [286, 286])  # Resize larger\n    image = tf.image.random_crop(image, size=[IMAGE_SIZE[0], IMAGE_SIZE[1], 3])  # Then crop\n    \n    # Small random brightness/contrast changes\n    image = tf.image.random_brightness(image, max_delta=0.1)\n    image = tf.image.random_contrast(image, lower=0.9, upper=1.1)\n    \n    # Ensure values stay in [-1, 1]\n    image = tf.clip_by_value(image, -1, 1)\n    \n    return image\n\n# Apply data augmentation\nmonet_ds = monet_ds.map(data_augmentation, num_parallel_calls=AUTOTUNE)\nphoto_ds = photo_ds.map(data_augmentation, num_parallel_calls=AUTOTUNE)\n\n# Cache, shuffle and batch datasets for training\nBUFFER_SIZE = 1000\nBATCH_SIZE=1\n\n# Prepare datasets for training\nmonet_ds = monet_ds.shuffle(BUFFER_SIZE).batch(BATCH_SIZE).cache()\nphoto_ds = photo_ds.shuffle(BUFFER_SIZE).batch(BATCH_SIZE).cache()\n\n# Make datasets repeat indefinitely for training\nmonet_ds = monet_ds.repeat()\nphoto_ds = photo_ds.repeat()\n\n# Prefetch for performance\nmonet_ds = monet_ds.prefetch(AUTOTUNE)\nphoto_ds = photo_ds.prefetch(AUTOTUNE)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-19T17:16:40.445727Z","iopub.execute_input":"2025-05-19T17:16:40.445971Z","iopub.status.idle":"2025-05-19T17:16:42.116467Z","shell.execute_reply.started":"2025-05-19T17:16:40.445954Z","shell.execute_reply":"2025-05-19T17:16:42.115916Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Visualize a few augmented examples\ndef visualize_augmented_samples(dataset, num_examples=5, title=\"Augmented Images\"):\n    samples = []\n    for image in dataset.take(num_examples):\n        samples.append(image[0])  # Get the first image from batch\n    \n    plt.figure(figsize=(15, 5))\n    for i, sample in enumerate(samples):\n        # Convert from [-1, 1] to [0, 1]\n        sample = (sample + 1) / 2.0\n        plt.subplot(1, num_examples, i+1)\n        plt.imshow(sample)\n        plt.title(f\"Sample {i+1}\")\n        plt.axis('off')\n    plt.suptitle(title)\n    plt.show()\n\nprint(\"Monet Augmented Samples:\")\nvisualize_augmented_samples(monet_ds, title=\"Augmented Monet Paintings\")\n\nprint(\"Photo Augmented Samples:\")\nvisualize_augmented_samples(photo_ds, title=\"Augmented Photos\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-19T17:16:42.117178Z","iopub.execute_input":"2025-05-19T17:16:42.117398Z","iopub.status.idle":"2025-05-19T17:16:45.086577Z","shell.execute_reply.started":"2025-05-19T17:16:42.117381Z","shell.execute_reply":"2025-05-19T17:16:45.085833Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Downsampling block for the generator\ndef downsample(filters, size, apply_batchnorm=True):\n    initializer = tf.random_normal_initializer(0., 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_batchnorm:\n        result.add(layers.BatchNormalization())\n    \n    result.add(layers.LeakyReLU(0.2))\n    \n    return result\n\n# Upsampling block for the generator\ndef upsample(filters, size, apply_dropout=False):\n    initializer = tf.random_normal_initializer(0., 0.02)\n    \n    result = keras.Sequential()\n    result.add(layers.Conv2DTranspose(filters, size, strides=2, padding='same',\n                                    kernel_initializer=initializer, use_bias=False))\n    \n    result.add(layers.BatchNormalization())\n    \n    if apply_dropout:\n        result.add(layers.Dropout(0.5))\n    \n    result.add(layers.ReLU())\n    \n    return result\n\n# Residual block for the generator\ndef residual_block(input_tensor, filters, size=3):\n    initializer = tf.random_normal_initializer(0., 0.02)\n    x = input_tensor\n    \n    x = layers.Conv2D(filters, size, padding='same', \n                    kernel_initializer=initializer, use_bias=False)(x)\n    x = layers.BatchNormalization()(x)\n    x = layers.ReLU()(x)\n    \n    x = layers.Conv2D(filters, size, padding='same',\n                    kernel_initializer=initializer, use_bias=False)(x)\n    x = layers.BatchNormalization()(x)\n    \n    # Add skip connection\n    return layers.add([input_tensor, x])\n\n# Generator model with ResNet blocks (ResNet generator)\ndef build_generator():\n    inputs = layers.Input(shape=[IMAGE_SIZE[0], IMAGE_SIZE[1], 3])\n    \n    # Initial downsampling\n    x = layers.Conv2D(64, 7, padding='same', use_bias=False)(inputs)\n    x = layers.BatchNormalization()(x)\n    x = layers.ReLU()(x)\n    \n    # Downsampling\n    x = downsample(128, 3)(x)  # (128, 128, 128)\n    x = downsample(256, 3)(x)  # (64, 64, 256)\n    \n    # 9 Residual blocks\n    for _ in range(9):\n        x = residual_block(x, 256)\n    \n    # Upsampling\n    x = upsample(128, 3)(x)  # (128, 128, 128)\n    x = upsample(64, 3)(x)   # (256, 256, 64)\n    \n    # Final layer with tanh activation\n    x = layers.Conv2D(3, 7, padding='same', activation='tanh')(x)  # (256, 256, 3)\n    \n    return keras.Model(inputs=inputs, outputs=x)\n\n# PatchGAN discriminator\ndef build_discriminator():\n    initializer = tf.random_normal_initializer(0., 0.02)\n    \n    inp = layers.Input(shape=[IMAGE_SIZE[0], IMAGE_SIZE[1], 3], name='input_image')\n    \n    # Downsampling layers\n    x = layers.Conv2D(64, 4, strides=2, padding='same',\n                    kernel_initializer=initializer)(inp)  # (128, 128, 64)\n    x = layers.LeakyReLU(0.2)(x)\n    \n    x = layers.Conv2D(128, 4, strides=2, padding='same',\n                    kernel_initializer=initializer, use_bias=False)(x)  # (64, 64, 128)\n    x = layers.BatchNormalization()(x)\n    x = layers.LeakyReLU(0.2)(x)\n    \n    x = layers.Conv2D(256, 4, strides=2, padding='same',\n                    kernel_initializer=initializer, use_bias=False)(x)  # (32, 32, 256)\n    x = layers.BatchNormalization()(x)\n    x = layers.LeakyReLU(0.2)(x)\n    \n    x = layers.Conv2D(512, 4, strides=1, padding='same',\n                    kernel_initializer=initializer, use_bias=False)(x)  # (32, 32, 512)\n    x = layers.BatchNormalization()(x)\n    x = layers.LeakyReLU(0.2)(x)\n    \n    # Final layer (output 1-channel PatchGAN)\n    x = layers.Conv2D(1, 4, strides=1, padding='same',\n                    kernel_initializer=initializer)(x)  # (32, 32, 1)\n    \n    return keras.Model(inputs=inp, outputs=x)\n\n# Instantiate the models\ngenerator_g = build_generator()  # Photo to Monet\ngenerator_f = build_generator()  # Monet to Photo\n\ndiscriminator_x = build_discriminator()  # Discriminator for Monet\ndiscriminator_y = build_discriminator()  # Discriminator for Photos\n\n# Print model summaries\ngenerator_g.summary()\ndiscriminator_x.summary()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-19T17:16:45.088947Z","iopub.execute_input":"2025-05-19T17:16:45.089240Z","iopub.status.idle":"2025-05-19T17:16:46.794990Z","shell.execute_reply.started":"2025-05-19T17:16:45.089216Z","shell.execute_reply":"2025-05-19T17:16:46.794407Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Define the loss functions\ndef discriminator_loss(real, generated):\n    real_loss = tf.keras.losses.BinaryCrossentropy(from_logits=True)(tf.ones_like(real), real)\n    generated_loss = tf.keras.losses.BinaryCrossentropy(from_logits=True)(tf.zeros_like(generated), generated)\n    total_loss = real_loss + generated_loss\n    return total_loss * 0.5\n\ndef generator_loss(generated):\n    return tf.keras.losses.BinaryCrossentropy(from_logits=True)(tf.ones_like(generated), generated)\n\ndef calc_cycle_loss(real_image, cycled_image, lambda_value=10):\n    return lambda_value * tf.reduce_mean(tf.abs(real_image - cycled_image))\n\ndef identity_loss(real_image, same_image, lambda_value=5):\n    return lambda_value * 0.5 * tf.reduce_mean(tf.abs(real_image - same_image))\n\n# Define the optimizers for each model\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)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-19T17:16:46.795947Z","iopub.execute_input":"2025-05-19T17:16:46.796234Z","iopub.status.idle":"2025-05-19T17:16:46.813706Z","shell.execute_reply.started":"2025-05-19T17:16:46.796205Z","shell.execute_reply":"2025-05-19T17:16:46.813103Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Define checkpoints for saving model progress\ncheckpoint_dir = \"/kaggle/temp/\"\ncheckpoint_prefix = os.path.join(checkpoint_dir, \"ckpt\")\ncheckpoint = tf.train.Checkpoint(\n    generator_g=generator_g,\n    generator_f=generator_f,\n    discriminator_x=discriminator_x,\n    discriminator_y=discriminator_y,\n    generator_g_optimizer=generator_g_optimizer,\n    generator_f_optimizer=generator_f_optimizer,\n    discriminator_x_optimizer=discriminator_x_optimizer,\n    discriminator_y_optimizer=discriminator_y_optimizer\n)\n\nos.makedirs(checkpoint_dir, exist_ok=True)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-19T17:16:46.814571Z","iopub.execute_input":"2025-05-19T17:16:46.814770Z","iopub.status.idle":"2025-05-19T17:16:46.819477Z","shell.execute_reply.started":"2025-05-19T17:16:46.814754Z","shell.execute_reply":"2025-05-19T17:16:46.818868Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def train_step(real_x, real_y):\n    # real_x: Monet, real_y: Photo\n    with tf.GradientTape(persistent=True) as tape:\n        # Generators G: Photo -> Monet, F: Monet -> Photo\n        \n        # Generator G translates Photos (Y) to Monet style (X)\n        fake_x = generator_g(real_y, training=True)\n        # Generator F translates Monet (X) to Photo style (Y)\n        fake_y = generator_f(real_x, training=True)\n        \n        # Cycle consistency (reconstruct original images)\n        cycled_x = generator_f(fake_x, training=True)  # Y -> X -> Y\n        cycled_y = generator_g(fake_y, training=True)  # X -> Y -> X\n        \n        # Identity mapping (optional, helps preserve color composition)\n        same_x = generator_g(real_x, training=True)  # X -> X\n        same_y = generator_f(real_y, training=True)  # Y -> Y\n        \n        # Discriminator outputs\n        disc_real_x = discriminator_x(real_x, training=True)\n        disc_fake_x = discriminator_x(fake_x, training=True)\n        \n        disc_real_y = discriminator_y(real_y, training=True)\n        disc_fake_y = discriminator_y(fake_y, training=True)\n        \n        # Generator losses\n        gen_g_loss = generator_loss(disc_fake_x)  # Photo -> Monet generator loss\n        gen_f_loss = generator_loss(disc_fake_y)  # Monet -> Photo generator loss\n        \n        # Cycle consistency losses\n        cycle_loss_x = calc_cycle_loss(real_x, cycled_x)\n        cycle_loss_y = calc_cycle_loss(real_y, cycled_y)\n        total_cycle_loss = cycle_loss_x + cycle_loss_y\n        \n        # Identity losses (optional)\n        id_loss_x = identity_loss(real_x, same_x)\n        id_loss_y = identity_loss(real_y, same_y)\n        \n        # Total generator losses\n        total_gen_g_loss = gen_g_loss + total_cycle_loss + id_loss_x\n        total_gen_f_loss = gen_f_loss + total_cycle_loss + id_loss_y\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    # Calculate gradients and apply to optimizers\n    # Generator G gradients\n    generator_g_gradients = tape.gradient(total_gen_g_loss, generator_g.trainable_variables)\n    generator_g_optimizer.apply_gradients(zip(generator_g_gradients, generator_g.trainable_variables))\n    \n    # Generator F gradients\n    generator_f_gradients = tape.gradient(total_gen_f_loss, generator_f.trainable_variables)\n    generator_f_optimizer.apply_gradients(zip(generator_f_gradients, generator_f.trainable_variables))\n    \n    # Discriminator X gradients\n    discriminator_x_gradients = tape.gradient(disc_x_loss, discriminator_x.trainable_variables)\n    discriminator_x_optimizer.apply_gradients(zip(discriminator_x_gradients, discriminator_x.trainable_variables))\n    \n    # Discriminator Y gradients\n    discriminator_y_gradients = tape.gradient(disc_y_loss, discriminator_y.trainable_variables)\n    discriminator_y_optimizer.apply_gradients(zip(discriminator_y_gradients, discriminator_y.trainable_variables))\n    \n    return {\n        'gen_g_loss': total_gen_g_loss,\n        'gen_f_loss': total_gen_f_loss,\n        'disc_x_loss': disc_x_loss,\n        'disc_y_loss': disc_y_loss\n    }\n\n# Function to generate sample images during training\ndef generate_images(model, test_input, typ=1):\n    prediction = model(test_input)\n    \n    plt.figure(figsize=(12, 6))\n    \n    display_list = [test_input[0], prediction[0]]\n    if typ==1:\n        title = ['Input Photo', 'Generated Monet-style Image']\n    else:\n        title = ['Input Monet-style Image', 'Generated Photo']\n    \n    for i in range(2):\n        plt.subplot(1, 2, i+1)\n        plt.title(title[i])\n        # Convert from [-1, 1] to [0, 1]\n        img = (display_list[i] + 1) / 2.0\n        plt.imshow(img)\n        plt.axis('off')\n    \n    plt.tight_layout()\n    plt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-19T17:16:46.820091Z","iopub.execute_input":"2025-05-19T17:16:46.820339Z","iopub.status.idle":"2025-05-19T17:16:46.834192Z","shell.execute_reply.started":"2025-05-19T17:16:46.820318Z","shell.execute_reply":"2025-05-19T17:16:46.833391Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Run the training\nepochs = 10\nprint(\"Starting training...\")\n# Sample test inputs for visualization during training\nsample_monet = next(iter(monet_ds))\nsample_photo = next(iter(photo_ds))\n\nhistory = {\n        'gen_g_loss': [],\n        'gen_f_loss': [],\n        'disc_x_loss': [],\n        'disc_y_loss': []\n    }\n    \n\n# Calculate the number of steps per epoch\nsteps_per_epoch = min(len(monet_jpg_files), len(photo_jpg_files)) // BATCH_SIZE\n\n# Start training\nfor epoch in range(epochs):\n    start = time.time()\n    \n    # Initialize metrics for this epoch\n    epoch_metrics = {\n        'gen_g_loss': [],\n        'gen_f_loss': [],\n        'disc_x_loss': [],\n        'disc_y_loss': []\n    }\n    \n    # Training loop\n    for step, (x, y) in enumerate(zip(monet_ds, photo_ds)):\n        if step >= steps_per_epoch:\n            break\n            \n        metrics = train_step(x, y)\n        \n        # Track metrics\n        for k, v in metrics.items():\n            epoch_metrics[k].append(float(v))\n            \n        # Print progress\n        if step % 50 == 0:\n            print(f\"Epoch {epoch+1}/{epochs}, Step {step}/{steps_per_epoch}\")\n            for k, v in metrics.items():\n                print(f\"  {k}: {v:.4f}\")\n    \n    # Calculate average metrics for the epoch\n    avg_metrics = {k: np.mean(v) for k, v in epoch_metrics.items()}\n    \n    # Generate sample images\n    generate_images(generator_g, sample_photo, typ=1)\n    generate_images(generator_f, sample_monet, typ=2)\n    \n    # Save checkpoint\n    if (epoch + 1) % 5 == 0:\n        checkpoint.save(file_prefix=checkpoint_prefix)\n\n    print(\"--------------------------------------\")\n    print(f\"Time taken for epoch {epoch+1}: {time.time()-start:.2f} sec\")\n    print(f\"Generator G loss: {avg_metrics['gen_g_loss']:.4f}\")\n    history['gen_g_loss'].append(avg_metrics['gen_g_loss'])\n    print(f\"Generator F loss: {avg_metrics['gen_f_loss']:.4f}\")\n    history['gen_f_loss'].append(avg_metrics['gen_f_loss'])\n    print(f\"Discriminator X loss: {avg_metrics['disc_x_loss']:.4f}\")\n    history['disc_x_loss'].append(avg_metrics['disc_x_loss'])\n    print(f\"Discriminator Y loss: {avg_metrics['disc_y_loss']:.4f}\")\n    history['disc_y_loss'].append(avg_metrics['disc_y_loss'])\n    print(\"--------------------------------------\")\n\n# Save the final model\ncheckpoint.save(file_prefix=checkpoint_prefix)\n\n# Define paths\noutput_dir = '/kaggle/temp/generated_jpg_images/'\noutput_zip = '/kaggle/working/images.zip' \nos.makedirs(output_dir, exist_ok=True)\n\n# Get all test photos\ntest_photos = glob(os.path.join(PHOTO_JPG_PATH, '*.jpg')) \nprint(f\"Generating Monet-style images for {len(test_photos)} photos...\")\n\n# Process each photo\nfor i, photo_path in enumerate(test_photos):\n    # Extract filename\n    base_filename = os.path.splitext(os.path.basename(photo_path))[0] + '.jpg'\n    \n    # Load and preprocess the image\n    img = load_img(photo_path, target_size=(IMAGE_SIZE[0], IMAGE_SIZE[1]))\n    img = img_to_array(img)\n    img = (img / 127.5) - 1.0  # Normalize to [-1, 1]\n    \n    # Generate Monet-style image \n    generated_img_tensor = generator_g(img[np.newaxis, ...])\n    \n    # Convert back to [0, 255] range and uint8\n    generated_img_np = ((generated_img_tensor[0] + 1.0) * 127.5).numpy().astype(np.uint8)\n    \n    # Save the generated image\n    output_path = os.path.join(output_dir, base_filename)\n    tf.keras.preprocessing.image.save_img(output_path, generated_img_np)\n    \n    # Print progress occasionally\n    if (i + 1) % 1000 == 0:  # Increased frequency of progress updates\n        print(f\"Processed {i+1}/{len(test_photos)} images\")\n\nprint(f\"Finished generating images.\")\n\n# Create ZIP file for submission\nwith zipfile.ZipFile(output_zip, 'w') as zipf:\n    for file_in_dir in os.listdir(output_dir):\n        zipf.write(os.path.join(output_dir, file_in_dir), file_in_dir)\n\nprint(f\"Submission file created: {output_zip}\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-19T17:16:46.834990Z","iopub.execute_input":"2025-05-19T17:16:46.835234Z","iopub.status.idle":"2025-05-19T17:46:21.621239Z","shell.execute_reply.started":"2025-05-19T17:16:46.835212Z","shell.execute_reply":"2025-05-19T17:46:21.620171Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"for dirname, _, filenames in os.walk('/kaggle/working/'):\n    for filename in filenames:\n        print(os.path.join(dirname, filename))","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-19T17:46:26.890076Z","iopub.execute_input":"2025-05-19T17:46:26.890653Z","iopub.status.idle":"2025-05-19T17:46:26.894572Z","shell.execute_reply.started":"2025-05-19T17:46:26.890632Z","shell.execute_reply":"2025-05-19T17:46:26.893949Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Load test photos for evaluation\ndef load_test_photos(photo_path, num_samples=5):\n    all_photos = glob(os.path.join(photo_path, '*.jpg'))\n    selected_photos = np.random.choice(all_photos, num_samples, replace=False)\n    \n    test_photos = []\n    for path in selected_photos:\n        img = load_img(path, target_size=(IMAGE_SIZE[0], IMAGE_SIZE[1]))\n        img = img_to_array(img)\n        img = (img / 127.5) - 1  # Normalize to [-1, 1]\n        test_photos.append(img)\n    \n    return np.array(test_photos)\n\n\n#checkpoint.restore(tf.train.latest_checkpoint('/kaggle/working/checkpoint/'))\n\nnum_samples=5\n# Generate some test images\ntest_photos = load_test_photos(PHOTO_JPG_PATH, num_samples=num_samples)\n\nplt.figure(figsize=(15, 12))\nfor i, photo in enumerate(test_photos):\n    # Generate Monet-style image\n    monet_style = generator_g(photo[np.newaxis, ...])\n    \n    # Display original and stylized images\n    plt.subplot(num_samples, 2, 2*i+1)\n    plt.title(f\"Original Photo {i+1}\")\n    plt.imshow((photo + 1) / 2)  # Convert from [-1, 1] to [0, 1]\n    plt.axis('off')\n    \n    plt.subplot(num_samples, 2, 2*i+2)\n    plt.title(f\"Monet-Style Photo {i+1}\")\n    plt.imshow((monet_style[0] + 1) / 2)  # Convert from [-1, 1] to [0, 1]\n    plt.axis('off')\n\nplt.tight_layout()\nplt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-19T17:46:33.668246Z","iopub.execute_input":"2025-05-19T17:46:33.668952Z","iopub.status.idle":"2025-05-19T17:46:34.799683Z","shell.execute_reply.started":"2025-05-19T17:46:33.668930Z","shell.execute_reply":"2025-05-19T17:46:34.798950Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from PIL import Image\ngenerated_files = glob(os.path.join(output_dir, '*.jpg'))\nif generated_files:\n    plt.figure(figsize=(15, 5))\n    for i in range(min(3, len(generated_files))): # Display up to 3 images\n        img = Image.open(generated_files[i])\n        plt.subplot(1, 3, i+1)\n        plt.imshow(img)\n        plt.title(f\"Generated {i+1}\")\n        plt.axis('off')\n    plt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-19T17:49:00.680845Z","iopub.execute_input":"2025-05-19T17:49:00.681288Z","iopub.status.idle":"2025-05-19T17:49:01.343337Z","shell.execute_reply.started":"2025-05-19T17:49:00.681266Z","shell.execute_reply":"2025-05-19T17:49:01.342565Z"}},"outputs":[],"execution_count":null}]}