{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.6.6","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"gpu","dataSources":[{"sourceId":16880,"databundleVersionId":858837,"sourceType":"competition"},{"sourceId":250645,"sourceType":"datasetVersion","datasetId":105271}],"dockerImageVersionId":29845,"isInternetEnabled":true,"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\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","execution":{"iopub.status.busy":"2024-05-21T13:56:12.257129Z","iopub.execute_input":"2024-05-21T13:56:12.257462Z","iopub.status.idle":"2024-05-21T13:56:13.092021Z","shell.execute_reply.started":"2024-05-21T13:56:12.257395Z","shell.execute_reply":"2024-05-21T13:56:13.091206Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"!pip install mtcnn tensorflow opencv-python pandas numpy scikit-learn\n","metadata":{"execution":{"iopub.status.busy":"2024-05-21T13:56:13.094685Z","iopub.execute_input":"2024-05-21T13:56:13.095001Z","iopub.status.idle":"2024-05-21T13:56:21.123733Z","shell.execute_reply.started":"2024-05-21T13:56:13.094946Z","shell.execute_reply":"2024-05-21T13:56:21.122633Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import os\nimport cv2\nimport numpy as np\nimport pandas as pd\nfrom mtcnn import MTCNN\nfrom tqdm import tqdm\n\n# Initialize MTCNN face detector\ndetector = MTCNN()\n\n# Paths and setup\nvideo_folder = '../input/deepfake-detection-challenge/train_sample_videos/'\nmetadata_path = '../input/deepfake-detection-challenge/train_sample_videos/metadata.json'\noutput_real_folder = './extracted_faces/real/'\noutput_fake_folder = './extracted_faces/fake/'\n\n# Create directories if they don't exist\nos.makedirs(output_real_folder, exist_ok=True)\nos.makedirs(output_fake_folder, exist_ok=True)\n\n# Load metadata\ntrain_sample_metadata = pd.read_json(metadata_path).T\n\n# Function to detect and save faces from video frames\ndef extract_faces(video_path, output_folder, label, video_name):\n    cap = cv2.VideoCapture(video_path)\n    frame_count = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))\n    frame_interval = max(frame_count // 5, 1)  # Ensure at least 5 frames are captured at regular intervals\n\n    captured_frames = 0\n    for i in range(0, frame_count, frame_interval):\n        cap.set(cv2.CAP_PROP_POS_FRAMES, i)\n        ret, frame = cap.read()\n        if not ret or captured_frames >= 5:\n            break\n        \n        frame_rgb = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)\n        faces = detector.detect_faces(frame_rgb)\n        \n        for j, face in enumerate(faces):\n            x, y, width, height = face['box']\n            face_img = frame_rgb[y:y+height, x:x+width]\n            face_img = cv2.resize(face_img, (224, 224))  # Resize face to 224x224\n            \n            # Save the face image\n            face_filename = f\"{label}_{video_name}_{i}_{j}.jpg\"\n            face_filepath = os.path.join(output_folder, face_filename)\n            cv2.imwrite(face_filepath, cv2.cvtColor(face_img, cv2.COLOR_RGB2BGR))\n        \n        captured_frames += 1\n    \n    cap.release()\n\n# Extract faces from videos\nfor video_name, row in tqdm(train_sample_metadata.iterrows(), total=train_sample_metadata.shape[0]):\n    video_path = os.path.join(video_folder, video_name)\n    label = row['label']\n    output_folder = output_real_folder if label == 'REAL' else output_fake_folder\n    extract_faces(video_path, output_folder, label, video_name)\n","metadata":{"execution":{"iopub.status.busy":"2024-05-21T13:56:21.125790Z","iopub.execute_input":"2024-05-21T13:56:21.126075Z","iopub.status.idle":"2024-05-21T14:07:54.292066Z","shell.execute_reply.started":"2024-05-21T13:56:21.126023Z","shell.execute_reply":"2024-05-21T14:07:54.290721Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"!pip install -q git+https://github.com/tensorflow/examples.git\n","metadata":{"execution":{"iopub.status.busy":"2024-05-21T14:09:35.412971Z","iopub.execute_input":"2024-05-21T14:09:35.413313Z","iopub.status.idle":"2024-05-21T14:09:48.150659Z","shell.execute_reply.started":"2024-05-21T14:09:35.413252Z","shell.execute_reply":"2024-05-21T14:09:48.149628Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import tensorflow as tf\nfrom tensorflow_examples.models.pix2pix import pix2pix\nimport os\nimport time\nfrom IPython.display import clear_output\nimport matplotlib.pyplot as plt\nfrom glob import glob\n\n# Load and preprocess the dataset\ndef load_image(image_file):\n    image = tf.io.read_file(image_file)\n    image = tf.image.decode_jpeg(image)\n    image = tf.cast(image, tf.float32)\n    image = tf.image.resize(image, [256, 256])\n    image = (image / 127.5) - 1\n    return image\n\ndef load_image_train(image_file):\n    image = load_image(image_file)\n    return image\n\ndef load_image_test(image_file):\n    image = load_image(image_file)\n    return image\n\n# Define the dataset\ndef get_dataset(image_dir):\n    image_files = glob(os.path.join(image_dir, '*'))\n    dataset = tf.data.Dataset.from_tensor_slices(image_files)\n    dataset = dataset.map(load_image_train, num_parallel_calls=tf.data.experimental.AUTOTUNE)\n    dataset = dataset.shuffle(buffer_size=len(image_files))\n    dataset = dataset.batch(1)\n    return dataset\n\n# Directories for real and fake faces\nreal_image_dir = './extracted_faces/real/'\nfake_image_dir = './extracted_faces/fake/'\n\nreal_dataset = get_dataset(real_image_dir)\nfake_dataset = get_dataset(fake_image_dir)\n\n# Define the CycleGAN model\nOUTPUT_CHANNELS = 3\n\ndef unet_generator(output_channels, norm_type='batchnorm'):\n    initializer = tf.random_normal_initializer(0., 0.02)\n\n    down_stack = [\n        pix2pix.downsample(64, 4, apply_norm=False),  # (bs, 128, 128, 64)\n        pix2pix.downsample(128, 4),  # (bs, 64, 64, 128)\n        pix2pix.downsample(256, 4),  # (bs, 32, 32, 256)\n        pix2pix.downsample(512, 4),  # (bs, 16, 16, 512)\n        pix2pix.downsample(512, 4),  # (bs, 8, 8, 512)\n        pix2pix.downsample(512, 4),  # (bs, 4, 4, 512)\n        pix2pix.downsample(512, 4),  # (bs, 2, 2, 512)\n        pix2pix.downsample(512, 4),  # (bs, 1, 1, 512)\n    ]\n\n    up_stack = [\n        pix2pix.upsample(512, 4, apply_dropout=True),  # (bs, 2, 2, 1024)\n        pix2pix.upsample(512, 4, apply_dropout=True),  # (bs, 4, 4, 1024)\n        pix2pix.upsample(512, 4, apply_dropout=True),  # (bs, 8, 8, 1024)\n        pix2pix.upsample(512, 4),  # (bs, 16, 16, 1024)\n        pix2pix.upsample(256, 4),  # (bs, 32, 32, 512)\n        pix2pix.upsample(128, 4),  # (bs, 64, 64, 256)\n        pix2pix.upsample(64, 4),  # (bs, 128, 128, 128)\n    ]\n\n    last = tf.keras.layers.Conv2DTranspose(output_channels, 4,\n                                           strides=2,\n                                           padding='same',\n                                           kernel_initializer=initializer,\n                                           activation='tanh')  # (bs, 256, 256, output_channels)\n\n    concat = tf.keras.layers.Concatenate()\n\n    inputs = tf.keras.layers.Input(shape=[256, 256, 3])\n    x = inputs\n\n    # Downsampling through the model\n    skips = []\n    for down in down_stack:\n        x = down(x)\n        skips.append(x)\n\n    skips = reversed(skips[:-1])\n\n    # Upsampling and establishing the skip connections\n    for up, skip in zip(up_stack, skips):\n        x = up(x)\n        x = concat([x, skip])\n\n    x = last(x)\n\n    return tf.keras.Model(inputs=inputs, outputs=x)\n\ngenerator_g = unet_generator(OUTPUT_CHANNELS, norm_type='instancenorm')\ngenerator_f = unet_generator(OUTPUT_CHANNELS, norm_type='instancenorm')\n\ndiscriminator_x = pix2pix.discriminator(norm_type='instancenorm', target=False)\ndiscriminator_y = pix2pix.discriminator(norm_type='instancenorm', target=False)\n\n# Loss functions\nLAMBDA = 10\n\nloss_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    total_disc_loss = real_loss + generated_loss\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    return LAMBDA * loss1\n\ndef identity_loss(real_image, same_image):\n    loss = tf.reduce_mean(tf.abs(real_image - same_image))\n    return LAMBDA * 0.5 * loss\n\n# Optimizers\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\ncheckpoint_path = \"./checkpoints/train\"\nckpt = tf.train.Checkpoint(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\nckpt_manager = tf.train.CheckpointManager(ckpt, checkpoint_path, max_to_keep=5)\n\nif ckpt_manager.latest_checkpoint:\n    ckpt.restore(ckpt_manager.latest_checkpoint)\n    print('Latest checkpoint restored!!')\n\n# Training Step\n@tf.function\ndef train_step(real_x, real_y):\n    with tf.GradientTape(persistent=True) as tape:\n        # Generator G translates X -> Y\n        fake_y = generator_g(real_x, training=True)\n        cycled_x = generator_f(fake_y, training=True)\n\n        # Generator F translates Y -> X\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_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    # Calculate the gradients for generators and discriminators\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    # Apply the gradients to the optimizer\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))\n\n# Training Loop\nEPOCHS = 40\n\nfor epoch in range(EPOCHS):\n    start = time.time()\n\n    for image_x, image_y in tf.data.Dataset.zip((real_dataset, fake_dataset)):\n        train_step(image_x, image_y)\n\n    clear_output(wait=True)\n    print(f'Time taken for epoch {epoch + 1} is {time.time() - start} sec\\n')\n\n    if (epoch + 1) % 5 == 0:\n        ckpt_manager.save()\n\n# Save the model\ngenerator_g.save('generator_g.h5')\ngenerator_f.save('generator_f.h5')\n","metadata":{"execution":{"iopub.status.busy":"2024-05-20T14:10:37.863405Z","iopub.execute_input":"2024-05-20T14:10:37.863732Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import tensorflow as tf\nfrom tensorflow_examples.models.pix2pix import pix2pix\nimport os\nimport time\nfrom IPython.display import clear_output\nimport matplotlib.pyplot as plt\nfrom glob import glob\n\n# Load and preprocess the dataset\ndef load_image(image_file):\n    image = tf.io.read_file(image_file)\n    image = tf.image.decode_jpeg(image)\n    image = tf.cast(image, tf.float32)\n    image = tf.image.resize(image, [256, 256])\n    image = (image / 127.5) - 1\n    return image\n\ndef load_image_train(image_file):\n    image = load_image(image_file)\n    return image\n\ndef load_image_test(image_file):\n    image = load_image(image_file)\n    return image\n\n# Define the dataset\ndef get_dataset(image_dir):\n    image_files = glob(os.path.join(image_dir, '*'))\n    dataset = tf.data.Dataset.from_tensor_slices(image_files)\n    dataset = dataset.map(load_image_train, num_parallel_calls=tf.data.experimental.AUTOTUNE)\n    dataset = dataset.shuffle(buffer_size=len(image_files))\n    dataset = dataset.batch(1)\n    return dataset\n\n# Directories for real and fake faces\nreal_image_dir = '/kaggle/input/real-and-fake-face-detection/real_and_fake_face/training_real'\nfake_image_dir = '/kaggle/input/real-and-fake-face-detection/real_and_fake_face/training_fake'\n\nreal_dataset = get_dataset(real_image_dir)\nfake_dataset = get_dataset(fake_image_dir)\n\n# Define the CycleGAN model\nOUTPUT_CHANNELS = 3\n\ndef unet_generator(output_channels, norm_type='batchnorm'):\n    initializer = tf.random_normal_initializer(0., 0.02)\n\n    down_stack = [\n        pix2pix.downsample(64, 4, apply_norm=False),  # (bs, 128, 128, 64)\n        pix2pix.downsample(128, 4),  # (bs, 64, 64, 128)\n        pix2pix.downsample(256, 4),  # (bs, 32, 32, 256)\n        pix2pix.downsample(512, 4),  # (bs, 16, 16, 512)\n        pix2pix.downsample(512, 4),  # (bs, 8, 8, 512)\n        pix2pix.downsample(512, 4),  # (bs, 4, 4, 512)\n        pix2pix.downsample(512, 4),  # (bs, 2, 2, 512)\n        pix2pix.downsample(512, 4),  # (bs, 1, 1, 512)\n    ]\n\n    up_stack = [\n        pix2pix.upsample(512, 4, apply_dropout=True),  # (bs, 2, 2, 1024)\n        pix2pix.upsample(512, 4, apply_dropout=True),  # (bs, 4, 4, 1024)\n        pix2pix.upsample(512, 4, apply_dropout=True),  # (bs, 8, 8, 1024)\n        pix2pix.upsample(512, 4),  # (bs, 16, 16, 1024)\n        pix2pix.upsample(256, 4),  # (bs, 32, 32, 512)\n        pix2pix.upsample(128, 4),  # (bs, 64, 64, 256)\n        pix2pix.upsample(64, 4),  # (bs, 128, 128, 128)\n    ]\n\n    last = tf.keras.layers.Conv2DTranspose(output_channels, 4,\n                                           strides=2,\n                                           padding='same',\n                                           kernel_initializer=initializer,\n                                           activation='tanh')  # (bs, 256, 256, output_channels)\n\n    concat = tf.keras.layers.Concatenate()\n\n    inputs = tf.keras.layers.Input(shape=[256, 256, 3])\n    x = inputs\n\n    # Downsampling through the model\n    skips = []\n    for down in down_stack:\n        x = down(x)\n        skips.append(x)\n\n    skips = reversed(skips[:-1])\n\n    # Upsampling and establishing the skip connections\n    for up, skip in zip(up_stack, skips):\n        x = up(x)\n        x = concat([x, skip])\n\n    x = last(x)\n\n    return tf.keras.Model(inputs=inputs, outputs=x)\n\ngenerator_g = unet_generator(OUTPUT_CHANNELS, norm_type='instancenorm')\ngenerator_f = unet_generator(OUTPUT_CHANNELS, norm_type='instancenorm')\n\ndiscriminator_x = pix2pix.discriminator(norm_type='instancenorm', target=False)\ndiscriminator_y = pix2pix.discriminator(norm_type='instancenorm', target=False)\n\n# Loss functions\nLAMBDA = 10\n\nloss_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    total_disc_loss = real_loss + generated_loss\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    return LAMBDA * loss1\n\ndef identity_loss(real_image, same_image):\n    loss = tf.reduce_mean(tf.abs(real_image - same_image))\n    return LAMBDA * 0.5 * loss\n\n# Optimizers\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\ncheckpoint_path = \"./checkpoints/train\"\nckpt = tf.train.Checkpoint(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\nckpt_manager = tf.train.CheckpointManager(ckpt, checkpoint_path, max_to_keep=5)\n\nif ckpt_manager.latest_checkpoint:\n    ckpt.restore(ckpt_manager.latest_checkpoint)\n    print('Latest checkpoint restored!!')\n\n# Function to generate and display images\ndef generate_images(model, test_input, tar, save=False, epoch=0):\n    prediction = model(test_input, training=True)\n    plt.figure(figsize=(15, 15))\n\n    display_list = [test_input[0], tar[0], prediction[0]]\n    title = ['Input Image', 'Target Image', 'Predicted Image']\n\n    for i in range(3):\n        plt.subplot(1, 3, i+1)\n        plt.title(title[i])\n        plt.imshow((display_list[i] * 0.5 + 0.5).numpy())\n        plt.axis('off')\n    \n    if save:\n        plt.savefig(f'epoch_{epoch}_result.png')\n    plt.show()\n\n# Training Step\n@tf.function\ndef train_step(real_x, real_y):\n    with tf.GradientTape(persistent=True) as tape:\n        # Generator G translates X -> Y\n        fake_y = generator_g(real_x, training=True)\n        cycled_x = generator_f(fake_y, training=True)\n\n        # Generator F translates Y -> X\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_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    # Calculate the gradients for generators and discriminators\n    generator_g_gradients = tape.gradient(total_gen_g_loss, generator_g.trainable_variables)\n    generator_f_gradients = tape.gradient(total_gen_f_loss, generator_f.trainable_variables)\n\n    discriminator_x_gradients = tape.gradient(disc_x_loss, discriminator_x.trainable_variables)\n    discriminator_y_gradients = tape.gradient(disc_y_loss, discriminator_y.trainable_variables)\n\n    # Apply the gradients to the optimizer\n    generator_g_optimizer.apply_gradients(zip(generator_g_gradients, generator_g.trainable_variables))\n    generator_f_optimizer.apply_gradients(zip(generator_f_gradients, generator_f.trainable_variables))\n\n    discriminator_x_optimizer.apply_gradients(zip(discriminator_x_gradients, discriminator_x.trainable_variables))\n    discriminator_y_optimizer.apply_gradients(zip(discriminator_y_gradients, discriminator_y.trainable_variables))\n    \n    return total_gen_g_loss, total_gen_f_loss, disc_x_loss, disc_y_loss\n\n# Training Loop\nEPOCHS = 10\n\nfor epoch in range(EPOCHS):\n    start = time.time()\n    total_gen_g_loss = 0\n    total_gen_f_loss = 0\n    total_disc_x_loss = 0\n    total_disc_y_loss = 0\n    num_batches = 0\n\n    for image_x, image_y in tf.data.Dataset.zip((real_dataset, fake_dataset)):\n        gen_g_loss, gen_f_loss, disc_x_loss, disc_y_loss = train_step(image_x, image_y)\n        total_gen_g_loss += gen_g_loss\n        total_gen_f_loss += gen_f_loss\n        total_disc_x_loss += disc_x_loss\n        total_disc_y_loss += disc_y_loss\n        num_batches += 1\n\n    # Calculate the average loss for this epoch\n    avg_gen_g_loss = total_gen_g_loss / num_batches\n    avg_gen_f_loss = total_gen_f_loss / num_batches\n    avg_disc_x_loss = total_disc_x_loss / num_batches\n    avg_disc_y_loss = total_disc_y_loss / num_batches\n\n    clear_output(wait=True)\n    print(f'Epoch {epoch + 1}, Time taken: {time.time() - start} sec')\n    print(f'Generator G Loss: {avg_gen_g_loss.numpy()}, Generator F Loss: {avg_gen_f_loss.numpy()}')\n    print(f'Discriminator X Loss: {avg_disc_x_loss.numpy()}, Discriminator Y Loss: {avg_disc_y_loss.numpy()}')\n\n    # Generate and display images after each epoch\n    for example_real_image, example_fake_image in zip(real_dataset.take(1), fake_dataset.take(1)):\n        generate_images(generator_g, example_real_image, example_fake_image, save=True, epoch=epoch + 1)\n\n    if (epoch + 1) % 5 == 0:\n        ckpt_manager.save()\n\n# Save the model\ngenerator_g.save('generator_g.h5')\ngenerator_f.save('generator_f.h5')\n","metadata":{"execution":{"iopub.status.busy":"2024-05-21T14:46:13.701264Z","iopub.execute_input":"2024-05-21T14:46:13.701644Z","iopub.status.idle":"2024-05-21T15:18:47.707848Z","shell.execute_reply.started":"2024-05-21T14:46:13.701578Z","shell.execute_reply":"2024-05-21T15:18:47.706476Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]}]}