{"metadata":{"kernelspec":{"display_name":"Python 3","language":"python","name":"python3"},"language_info":{"codemirror_mode":{"name":"ipython","version":3},"file_extension":".py","mimetype":"text/x-python","name":"python","nbconvert_exporter":"python","pygments_lexer":"ipython3","version":"3.10.14"},"kaggle":{"accelerator":"gpu","dataSources":[{"sourceId":21755,"databundleVersionId":1475600,"sourceType":"competition"}],"isInternetEnabled":false,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"import tensorflow as tf\nfrom tensorflow import keras\nfrom tensorflow.keras import layers\nimport os\nfrom kaggle_datasets import KaggleDatasets\nimport matplotlib.pyplot as plt\nimport numpy as np\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":{"_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","execution":{"iopub.status.busy":"2024-11-28T04:39:05.369022Z","iopub.execute_input":"2024-11-28T04:39:05.369350Z","iopub.status.idle":"2024-11-28T04:39:16.890353Z","shell.execute_reply.started":"2024-11-28T04:39:05.369314Z","shell.execute_reply":"2024-11-28T04:39:16.889402Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"GCS_PATH = '/kaggle/input/gan-getting-started'\nmonet_dir = os.path.join(GCS_PATH, 'monet_jpg')\nphoto_dir = os.path.join(GCS_PATH, 'photo_jpg')","metadata":{"execution":{"iopub.status.busy":"2024-11-28T04:39:16.891730Z","iopub.execute_input":"2024-11-28T04:39:16.892271Z","iopub.status.idle":"2024-11-28T04:39:16.896493Z","shell.execute_reply.started":"2024-11-28T04:39:16.892241Z","shell.execute_reply":"2024-11-28T04:39:16.895554Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import tensorflow as tf\nimport os\n\ndef load_image_data(monet_dir, photo_dir, image_size=(256, 256), batch_size=10):\n    \"\"\"\n    Load dữ liệu hình ảnh từ thư mục Monet và Photo, resize và chia thành batch.\n    \n    Parameters:\n    - monet_dir (str): Đường dẫn đến thư mục chứa ảnh Monet.\n    - photo_dir (str): Đường dẫn đến thư mục chứa ảnh Photo.\n    - image_size (tuple): Kích thước resize ảnh (default: (256, 256)).\n    - batch_size (int): Kích thước của mỗi batch (default: 30).\n\n    Returns:\n    - monet_dataset (tf.data.Dataset): Dataset chứa ảnh Monet đã chia batch.\n    - photo_dataset (tf.data.Dataset): Dataset chứa ảnh Photo đã chia batch.\n    \"\"\"\n\n    def preprocess_image(image_path):\n        \"\"\"Load và resize hình ảnh.\"\"\"\n        image = tf.io.read_file(image_path)\n        image = tf.image.decode_jpeg(image, channels=3)  # Decode ảnh JPG\n        image = tf.image.resize(image, image_size)      # Resize về kích thước cố định\n        image = image / 255.0                           # Chuẩn hóa giá trị pixel về [0, 1]\n        return image\n\n    # Tìm tất cả tệp hình ảnh từ các thư mục Monet và Photo\n    monet_images = tf.io.gfile.glob(os.path.join(monet_dir, '*.jpg'))  # Tìm tất cả file .jpg\n    photo_images = tf.io.gfile.glob(os.path.join(photo_dir, '*.jpg'))\n\n    # Tạo dataset TensorFlow cho từng loại ảnh\n    monet_dataset = tf.data.Dataset.from_tensor_slices(monet_images)\n    photo_dataset = tf.data.Dataset.from_tensor_slices(photo_images)\n\n    # Map để load và preprocess từng hình ảnh\n    monet_dataset = monet_dataset.map(preprocess_image, num_parallel_calls=tf.data.AUTOTUNE)\n    photo_dataset = photo_dataset.map(preprocess_image, num_parallel_calls=tf.data.AUTOTUNE)\n\n    # Chia batch và tiền xử lý trước khi sử dụng\n    monet_dataset = monet_dataset.batch(batch_size).prefetch(tf.data.AUTOTUNE)\n    photo_dataset = photo_dataset.batch(batch_size).prefetch(tf.data.AUTOTUNE)\n\n    return monet_dataset, photo_dataset","metadata":{"execution":{"iopub.status.busy":"2024-11-28T04:39:16.897506Z","iopub.execute_input":"2024-11-28T04:39:16.897751Z","iopub.status.idle":"2024-11-28T04:39:16.919541Z","shell.execute_reply.started":"2024-11-28T04:39:16.897727Z","shell.execute_reply":"2024-11-28T04:39:16.918811Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"monet_dataset, photo_dataset = load_image_data(monet_dir, photo_dir, batch_size=10)\n\nprint(\"Monet Dataset:\")\nfor batch in monet_dataset.take(1):  # Lấy batch đầu tiên\n    print(\"Batch shape:\", batch.shape)\n\nprint(\"Photo Dataset:\")\nfor batch in photo_dataset.take(1):  # Lấy batch đầu tiên\n    print(\"Batch shape:\", batch.shape)\ndataset = list(zip(monet_dataset, photo_dataset))","metadata":{"execution":{"iopub.status.busy":"2024-11-28T04:39:16.920626Z","iopub.execute_input":"2024-11-28T04:39:16.921001Z","iopub.status.idle":"2024-11-28T04:39:21.829618Z","shell.execute_reply.started":"2024-11-28T04:39:16.920975Z","shell.execute_reply":"2024-11-28T04:39:21.828737Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import matplotlib.pyplot as plt\n\n# Lấy 3 ảnh từ Monet Dataset\nfor batch in monet_dataset.take(1):  # Lấy batch đầu tiên từ Monet dataset\n    plt.figure(figsize=(15, 5))  # Tạo một hình với kích thước 15x5\n    for i in range(3):  # Hiển thị 3 ảnh đầu tiên\n        plt.subplot(1, 3, i + 1)  # 1 hàng, 3 cột\n        plt.imshow(batch[i].numpy())  # Chuyển tensor sang numpy array và hiển thị\n        plt.axis('off')  # Tắt hiển thị trục\n        plt.title(f\"Monet {i+1}\")  # Tiêu đề cho từng ảnh\n    plt.show()\nfor batch in photo_dataset.take(1):  # Lấy batch đầu tiên từ Photo dataset\n    plt.figure(figsize=(15, 5))  # Tạo một hình với kích thước 15x5\n    for i in range(3):  # Hiển thị 3 ảnh đầu tiên\n        plt.subplot(1, 3, i + 1)  # 1 hàng, 3 cột\n        plt.imshow(batch[i].numpy())  # Chuyển tensor sang numpy array và hiển thị\n        plt.axis('off')  # Tắt hiển thị trục\n        plt.title(f\"Photo {i+1}\")  # Tiêu đề cho từng ảnh\n    plt.show()","metadata":{"execution":{"iopub.status.busy":"2024-11-28T04:39:21.835023Z","iopub.execute_input":"2024-11-28T04:39:21.835375Z","iopub.status.idle":"2024-11-28T04:39:22.966083Z","shell.execute_reply.started":"2024-11-28T04:39:21.835337Z","shell.execute_reply":"2024-11-28T04:39:22.965032Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def Encoder(inputs, initializer, filters_list):\n    \"\"\"\n    Tạo Encoder cho Generator.\n    \n    Parameters:\n    - inputs: Đầu vào của Encoder (tensor).\n    - initializer: Kernel initializer.\n    - filters_list: Danh sách số lượng filters cho các lớp Conv2D.\n\n    Returns:\n    - Tensor: Output của Encoder.\n    \"\"\"\n    x = inputs\n    for filters in filters_list:\n        x = layers.Conv2D(filters, 3 if filters != 64 else 7, strides=2 if filters != 64 else 1, \n                          padding='same', kernel_initializer=initializer, use_bias=False)(x)\n        x = layers.BatchNormalization()(x)\n        x = layers.ReLU()(x)\n    return x\n\n\ndef Transformer(x, num_residual_blocks):\n    \"\"\"\n    Tạo Transformer cho Generator (bao gồm các Residual Blocks).\n\n    Parameters:\n    - x: Đầu vào của Transformer (tensor).\n    - num_residual_blocks: Số lượng residual blocks.\n\n    Returns:\n    - Tensor: Output của Transformer.\n    \"\"\"\n    for _ in range(num_residual_blocks):\n        x = residual_block(x, filters=x.shape[-1])  # Số filters giữ nguyên\n    return x\n\n\ndef Decoder(x, initializer, filters_list):\n    \"\"\"\n    Tạo Decoder cho Generator.\n\n    Parameters:\n    - x: Đầu vào của Decoder (tensor).\n    - initializer: Kernel initializer.\n    - filters_list: Danh sách số lượng filters cho các lớp Conv2DTranspose.\n\n    Returns:\n    - Tensor: Output của Decoder.\n    \"\"\"\n    for filters in filters_list:\n        x = layers.Conv2DTranspose(filters, 3, strides=2, padding='same', \n                                    kernel_initializer=initializer, use_bias=False)(x)\n        x = layers.BatchNormalization()(x)\n        x = layers.ReLU()(x)\n    return x\ndef residual_block(x, filters, size=3):\n    \"\"\"\n    Tạo một Residual Block:\n    - Bao gồm hai lớp convolution, normalization và ReLU activation.\n    - Shortcut để giữ lại thông tin từ input.\n\n    Parameters:\n    - x: Đầu vào của layer.\n    - filters: Số bộ lọc (filters) trong Conv2D.\n    - size: Kích thước kernel (kernel size).\n\n    Returns:\n    - Tensor: Output của Residual Block.\n    \"\"\"\n    initializer = tf.random_normal_initializer(0., 0.02)\n\n    # Lớp convolution đầu tiên\n    res = layers.Conv2D(filters, size, strides=1, padding='same', \n                        kernel_initializer=initializer, use_bias=False)(x)\n    res = layers.BatchNormalization()(res)\n    res = layers.ReLU()(res)\n\n    # Lớp convolution thứ hai\n    res = layers.Conv2D(filters, size, strides=1, padding='same',\n                        kernel_initializer=initializer, use_bias=False)(res)\n    res = layers.BatchNormalization()(res)\n\n    # Cộng với đầu vào (skip connection)\n    return layers.add([x, res])","metadata":{"execution":{"iopub.status.busy":"2024-11-28T04:39:22.967578Z","iopub.execute_input":"2024-11-28T04:39:22.967999Z","iopub.status.idle":"2024-11-28T04:39:22.981578Z","shell.execute_reply.started":"2024-11-28T04:39:22.967956Z","shell.execute_reply":"2024-11-28T04:39:22.980676Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"Generator","metadata":{}},{"cell_type":"code","source":"def Generator(image_size=(256, 256, 3), num_residual_blocks=6):\n    \"\"\"\n    Xây dựng Generator với các thành phần Encoder, Transformer, và Decoder.\n\n    Parameters:\n    - image_size (tuple): Kích thước đầu vào của ảnh (height, width, channels).\n    - num_residual_blocks (int): Số lượng residual blocks trong phần Transformer.\n\n    Returns:\n    - tf.keras.Model: Mạng Generator.\n    \"\"\"\n    initializer = tf.random_normal_initializer(0., 0.02)\n\n    # Input layer\n    inputs = layers.Input(shape=image_size)\n\n    # Encoder\n    encoder_filters = [64, 128, 256]\n    x = Encoder(inputs, initializer, encoder_filters)\n\n    # Transformer (Residual Blocks)\n    x = Transformer(x, num_residual_blocks)\n\n    # Decoder\n    decoder_filters = [128, 64]\n    x = Decoder(x, initializer, decoder_filters)\n\n    # Output layer\n    outputs = layers.Conv2D(3, 7, strides=1, padding='same',\n                            kernel_initializer=initializer, activation='tanh')(x)\n\n    return tf.keras.Model(inputs=inputs, outputs=outputs)","metadata":{"execution":{"iopub.status.busy":"2024-11-28T04:39:22.982683Z","iopub.execute_input":"2024-11-28T04:39:22.983060Z","iopub.status.idle":"2024-11-28T04:39:22.998245Z","shell.execute_reply.started":"2024-11-28T04:39:22.983033Z","shell.execute_reply":"2024-11-28T04:39:22.997396Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"generator = Generator(image_size=(256, 256, 3), num_residual_blocks=9)\ngenerator.summary()","metadata":{"execution":{"iopub.status.busy":"2024-11-28T04:39:22.999112Z","iopub.execute_input":"2024-11-28T04:39:22.999345Z","iopub.status.idle":"2024-11-28T04:39:23.392784Z","shell.execute_reply.started":"2024-11-28T04:39:22.999321Z","shell.execute_reply":"2024-11-28T04:39:23.391839Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"Discriminator","metadata":{}},{"cell_type":"code","source":"def Discriminator(image_size=(256, 256, 3)):\n    \"\"\"\n    Xây dựng mạng Discriminator theo kiến trúc PatchGAN.\n\n    Parameters:\n    - image_size (tuple): Kích thước đầu vào của ảnh (height, width, channels).\n\n    Returns:\n    - tf.keras.Model: Mạng Discriminator.\n    \"\"\"\n    initializer = tf.random_normal_initializer(0., 0.02)\n\n    # Input layer\n    inputs = layers.Input(shape=image_size)\n\n    # Downsample\n    x = layers.Conv2D(64, 4, strides=2, padding='same',\n                      kernel_initializer=initializer, use_bias=False)(inputs)\n    x = layers.LeakyReLU(alpha=0.2)(x)\n\n    x = layers.Conv2D(128, 4, strides=2, padding='same',\n                      kernel_initializer=initializer, use_bias=False)(x)\n    x = layers.BatchNormalization()(x)\n    x = layers.LeakyReLU(alpha=0.2)(x)\n\n    x = layers.Conv2D(256, 4, strides=2, padding='same',\n                      kernel_initializer=initializer, use_bias=False)(x)\n    x = layers.BatchNormalization()(x)\n    x = layers.LeakyReLU(alpha=0.2)(x)\n\n    x = layers.Conv2D(512, 4, strides=1, padding='same',\n                      kernel_initializer=initializer, use_bias=False)(x)\n    x = layers.BatchNormalization()(x)\n    x = layers.LeakyReLU(alpha=0.2)(x)\n\n    # Output layer\n    outputs = layers.Conv2D(1, 4, strides=1, padding='same',\n                            kernel_initializer=initializer)(x)\n\n    return tf.keras.Model(inputs=inputs, outputs=outputs)","metadata":{"execution":{"iopub.status.busy":"2024-11-28T04:39:23.394112Z","iopub.execute_input":"2024-11-28T04:39:23.394809Z","iopub.status.idle":"2024-11-28T04:39:23.403346Z","shell.execute_reply.started":"2024-11-28T04:39:23.394747Z","shell.execute_reply":"2024-11-28T04:39:23.402338Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"discriminator = Discriminator(image_size=(256, 256, 3))\ndiscriminator.summary()","metadata":{"execution":{"iopub.status.busy":"2024-11-28T04:39:23.404401Z","iopub.execute_input":"2024-11-28T04:39:23.404655Z","iopub.status.idle":"2024-11-28T04:39:23.482305Z","shell.execute_reply.started":"2024-11-28T04:39:23.404624Z","shell.execute_reply":"2024-11-28T04:39:23.481549Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"binary_cross_entropy = tf.keras.losses.BinaryCrossentropy(from_logits=True)\n\ndef generator_loss(fake_output):\n    \"\"\"\n    Mất mát của Generator dựa trên kết quả của Discriminator.\n    \"\"\"\n    return binary_cross_entropy(tf.ones_like(fake_output), fake_output)\n\ndef discriminator_loss(real_output, fake_output):\n    \"\"\"\n    Mất mát của Discriminator dựa trên dữ liệu thật và giả.\n    \"\"\"\n    real_loss = binary_cross_entropy(tf.ones_like(real_output), real_output)\n    fake_loss = binary_cross_entropy(tf.zeros_like(fake_output), fake_output)\n    return (real_loss + fake_loss) * 0.5\ndef cycle_consistency_loss(real_image, cycled_image):\n    \"\"\"\n    Tính mất mát chu kỳ để đảm bảo đầu ra sau khi qua Generator không bị biến đổi quá nhiều.\n    \"\"\"\n    return tf.reduce_mean(tf.abs(real_image - cycled_image))","metadata":{"execution":{"iopub.status.busy":"2024-11-28T04:39:23.483450Z","iopub.execute_input":"2024-11-28T04:39:23.483790Z","iopub.status.idle":"2024-11-28T04:39:23.489590Z","shell.execute_reply.started":"2024-11-28T04:39:23.483732Z","shell.execute_reply":"2024-11-28T04:39:23.488816Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"generator_optimizer_g = tf.keras.optimizers.Adam(learning_rate=0.0002, beta_1=0.5)\ngenerator_optimizer_f = tf.keras.optimizers.Adam(learning_rate=0.0002, beta_1=0.5)\ndiscriminator_optimizer_x = tf.keras.optimizers.Adam(learning_rate=0.0002, beta_1=0.5)\ndiscriminator_optimizer_y = tf.keras.optimizers.Adam(learning_rate=0.0002, beta_1=0.5)\ngenerator_g = Generator()  # Create generator for G\ngenerator_f = Generator()  # Create generator for F\ndiscriminator_x = Discriminator()  # Create discriminator for X\ndiscriminator_y = Discriminator()  # Create discriminator for Y","metadata":{"execution":{"iopub.status.busy":"2024-11-28T04:39:23.490821Z","iopub.execute_input":"2024-11-28T04:39:23.491155Z","iopub.status.idle":"2024-11-28T04:39:24.139482Z","shell.execute_reply.started":"2024-11-28T04:39:23.491109Z","shell.execute_reply":"2024-11-28T04:39:24.138829Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import tensorflow as tf\nfrom tqdm import tqdm\n\ndef generator_loss(disc_fake):\n    \"\"\"Generator loss giúp tạo ra ảnh giả có thể qua được discriminator\"\"\"\n    return tf.reduce_mean(tf.abs(disc_fake - 1))\n\ndef cycle_consistency_loss(real_image, cycled_image):\n    \"\"\"Cycle Consistency Loss đảm bảo tính nhất quán vòng lặp giữa ảnh gốc và ảnh đã chuyển đổi qua lại.\"\"\"\n    return tf.reduce_mean(tf.abs(real_image - cycled_image))\n\ndef discriminator_loss(disc_real, disc_fake):\n    \"\"\"Discriminator loss nhằm phân biệt ảnh thật và ảnh giả.\"\"\"\n    return tf.reduce_mean(tf.abs(disc_real - 1) + tf.abs(disc_fake))\n\ndef identity_loss(real_image, same_image):\n    \"\"\"Identity loss giúp đảm bảo ảnh không bị biến dạng khi generator không cần phải thay đổi chúng.\"\"\"\n    return tf.reduce_mean(tf.abs(real_image - same_image))","metadata":{"execution":{"iopub.status.busy":"2024-11-28T04:39:24.140379Z","iopub.execute_input":"2024-11-28T04:39:24.140604Z","iopub.status.idle":"2024-11-28T04:39:24.150879Z","shell.execute_reply.started":"2024-11-28T04:39:24.140580Z","shell.execute_reply":"2024-11-28T04:39:24.150074Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import matplotlib.pyplot as plt\nimport tensorflow as tf\n\n# Dùng để lưu trữ giá trị loss của các thành phần\nhistory = {\n    'gen_g_loss': [],\n    'gen_f_loss': [],\n    'disc_x_loss': [],\n    'disc_y_loss': []\n}\n@tf.function\ndef train_step(real_monet, real_photo, \n               generator_g, generator_f, \n               discriminator_x, discriminator_y,\n               lambda_cycle=10, lambda_identity=0.5):\n    \"\"\"Huấn luyện một bước với dữ liệu từ hai miền Monet và Photo.\"\"\"\n    with tf.GradientTape(persistent=True) as tape:\n        # Generator G: Photo -> Monet\n        fake_monet = generator_g(real_photo, training=True)\n        cycled_photo = generator_f(fake_monet, training=True)\n\n        # Generator F: Monet -> Photo\n        fake_photo = generator_f(real_monet, training=True)\n        cycled_monet = generator_g(fake_photo, training=True)\n\n        # Identity Mapping\n        same_monet = generator_g(real_monet, training=True)\n        same_photo = generator_f(real_photo, training=True)\n\n        # Discriminator X: Photo\n        disc_real_photo = discriminator_x(real_photo, training=True)\n        disc_fake_photo = discriminator_x(fake_photo, training=True)\n\n        # Discriminator Y: Monet\n        disc_real_monet = discriminator_y(real_monet, training=True)\n        disc_fake_monet = discriminator_y(fake_monet, training=True)\n\n        # Losses\n        gen_g_loss = generator_loss(disc_fake_monet)\n        gen_f_loss = generator_loss(disc_fake_photo)\n\n        cycle_loss_g = cycle_consistency_loss(real_photo, cycled_photo)\n        cycle_loss_f = cycle_consistency_loss(real_monet, cycled_monet)\n\n        identity_loss_g = identity_loss(real_monet, same_monet)\n        identity_loss_f = identity_loss(real_photo, same_photo)\n\n        total_gen_g_loss = gen_g_loss + lambda_cycle * cycle_loss_g + lambda_identity * identity_loss_g\n        total_gen_f_loss = gen_f_loss + lambda_cycle * cycle_loss_f + lambda_identity * identity_loss_f\n\n        disc_x_loss = discriminator_loss(disc_real_photo, disc_fake_photo)\n        disc_y_loss = discriminator_loss(disc_real_monet, disc_fake_monet)\n\n    # Gradients\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 Gradients\n    generator_optimizer_g.apply_gradients(zip(generator_g_gradients, generator_g.trainable_variables))\n    generator_optimizer_f.apply_gradients(zip(generator_f_gradients, generator_f.trainable_variables))\n    discriminator_optimizer_x.apply_gradients(zip(discriminator_x_gradients, discriminator_x.trainable_variables))\n    discriminator_optimizer_y.apply_gradients(zip(discriminator_y_gradients, discriminator_y.trainable_variables))\n    # Lưu trữ giá trị loss trong history\n    history['gen_g_loss'].append(total_gen_g_loss)\n    history['gen_f_loss'].append(total_gen_f_loss)\n    history['disc_x_loss'].append(disc_x_loss)\n    history['disc_y_loss'].append(disc_y_loss)\n\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    }","metadata":{"execution":{"iopub.status.busy":"2024-11-28T04:39:24.153759Z","iopub.execute_input":"2024-11-28T04:39:24.154034Z","iopub.status.idle":"2024-11-28T04:39:24.164727Z","shell.execute_reply.started":"2024-11-28T04:39:24.154010Z","shell.execute_reply":"2024-11-28T04:39:24.163962Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def train(dataset, epochs, generator_g, generator_f, discriminator_x, discriminator_y, lambda_cycle=10, lambda_identity=0.5, verbose=1):\n    \"\"\"Vòng lặp huấn luyện chính cho CycleGAN, đồng thời hiển thị tiến trình huấn luyện.\"\"\"\n    for epoch in range(epochs):\n        print(f\"Epoch {epoch + 1}/{epochs}\")\n        \n        # Dùng tqdm để hiển thị progress bar cho mỗi epoch\n        epoch_losses = {\n            \"gen_g_loss\": [],\n            \"gen_f_loss\": [],\n            \"disc_x_loss\": [],\n            \"disc_y_loss\": []\n        }\n        \n        # Tiến trình huấn luyện cho mỗi batch\n        for batch, (real_monet, real_photo) in tqdm(enumerate(dataset), total=len(dataset), desc=f\"Epoch {epoch + 1}\", ncols=100):\n            losses = train_step(\n                real_monet, real_photo, \n                generator_g, generator_f, \n                discriminator_x, discriminator_y,\n                lambda_cycle, lambda_identity\n            )\n            \n            # Lưu các giá trị mất mát vào epoch_losses\n            epoch_losses[\"gen_g_loss\"].append(losses[\"gen_g_loss\"])\n            epoch_losses[\"gen_f_loss\"].append(losses[\"gen_f_loss\"])\n            epoch_losses[\"disc_x_loss\"].append(losses[\"disc_x_loss\"])\n            epoch_losses[\"disc_y_loss\"].append(losses[\"disc_y_loss\"])\n\n            # Hiển thị thông tin cho mỗi batch nếu verbose = 1\n            if verbose == 1 and batch % 10 == 0:  # In mỗi 10 batch\n                print(f\"  Batch {batch + 1}: Gen_G_Loss = {losses['gen_g_loss']:.4f}, Gen_F_Loss = {losses['gen_f_loss']:.4f}, Disc_X_Loss = {losses['disc_x_loss']:.4f}, Disc_Y_Loss = {losses['disc_y_loss']:.4f}\")\n        \n        # Sau mỗi epoch, in ra thông tin mất mát trung bình\n        avg_gen_g_loss = sum(epoch_losses[\"gen_g_loss\"]) / len(epoch_losses[\"gen_g_loss\"])\n        avg_gen_f_loss = sum(epoch_losses[\"gen_f_loss\"]) / len(epoch_losses[\"gen_f_loss\"])\n        avg_disc_x_loss = sum(epoch_losses[\"disc_x_loss\"]) / len(epoch_losses[\"disc_x_loss\"])\n        avg_disc_y_loss = sum(epoch_losses[\"disc_y_loss\"]) / len(epoch_losses[\"disc_y_loss\"])\n\n        print(f\"Epoch {epoch + 1} Summary:\")\n        print(f\"  Average Gen_G_Loss = {avg_gen_g_loss:.4f}, Gen_F_Loss = {avg_gen_f_loss:.4f}\")\n        print(f\"  Average Disc_X_Loss = {avg_disc_x_loss:.4f}, Disc_Y_Loss = {avg_disc_y_loss:.4f}\")","metadata":{"execution":{"iopub.status.busy":"2024-11-28T04:39:24.165635Z","iopub.execute_input":"2024-11-28T04:39:24.165884Z","iopub.status.idle":"2024-11-28T04:39:24.186505Z","shell.execute_reply.started":"2024-11-28T04:39:24.165860Z","shell.execute_reply":"2024-11-28T04:39:24.185783Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Now you can train the models\ntrain(dataset, epochs=50, \n      generator_g=generator_g, \n      generator_f=generator_f, \n      discriminator_x=discriminator_x, \n      discriminator_y=discriminator_y, \n      lambda_cycle=10, \n      lambda_identity=0.5, \n      verbose=1)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-11-28T04:39:24.187457Z","iopub.execute_input":"2024-11-28T04:39:24.187688Z","iopub.status.idle":"2024-11-28T05:35:45.439876Z","shell.execute_reply.started":"2024-11-28T04:39:24.187664Z","shell.execute_reply":"2024-11-28T05:35:45.439008Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import numpy as np\nimport matplotlib.pyplot as plt\n\n# Tạo một figure với 3 hàng và 2 cột để hiển thị ảnh\n_, ax = plt.subplots(3, 2, figsize=(12, 12))  # Bố trí 3 hàng và 2 cột\n\n# Lấy 3 batch ảnh từ photo_dataset và tạo ảnh Monet tương ứng\nfor i, img in enumerate(photo_dataset.take(3)):  # Lấy 3 ảnh từ photo_dataset\n    # Chuyển đổi batch ảnh từ photo_dataset thành ảnh giả Monet bằng Generator\n    prediction = generator_g(img, training=False)[0].numpy()  # Giả sử batch size = 1\n    prediction = (prediction * 127.5 + 127.5).astype(np.uint8)  # Giả sử ảnh đầu ra trong phạm vi [-1, 1]\n\n    # Đổi chuẩn cho ảnh thật (input photo)\n    img = (img[0] * 127.5 + 127.5).numpy().astype(np.uint8)  # Chuyển đổi giá trị pixel về [0, 255]\n\n    # Hiển thị ảnh gốc (photo) và ảnh Monet giả (Monet-esque)\n    ax[i, 0].imshow(img)\n    ax[i, 1].imshow(prediction)\n    ax[i, 0].set_title(f\"Photo {i+1}\")\n    ax[i, 1].set_title(f\"Monet-esque {i+1}\")\n    ax[i, 0].axis(\"off\")  # Ẩn trục ảnh\n    ax[i, 1].axis(\"off\")  # Ẩn trục ảnh\n\nplt.show()  # Hiển thị các ảnh","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-11-28T05:35:45.441004Z","iopub.execute_input":"2024-11-28T05:35:45.441289Z","iopub.status.idle":"2024-11-28T05:35:46.480258Z","shell.execute_reply.started":"2024-11-28T05:35:45.441262Z","shell.execute_reply":"2024-11-28T05:35:46.479344Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import PIL\n! mkdir ../images","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-11-28T05:35:46.481275Z","iopub.execute_input":"2024-11-28T05:35:46.481520Z","iopub.status.idle":"2024-11-28T05:35:47.544021Z","shell.execute_reply.started":"2024-11-28T05:35:46.481496Z","shell.execute_reply":"2024-11-28T05:35:47.542848Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"i = 1\nfor img in photo_dataset:\n    prediction = generator_g(img, training=False)[0].numpy()\n    prediction = (prediction * 127.5 + 127.5).astype(np.uint8)\n    im = PIL.Image.fromarray(prediction)\n    im.save(\"../images/\" + str(i) + \".jpg\")\n    i += 1","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-11-28T05:35:47.545679Z","iopub.execute_input":"2024-11-28T05:35:47.546054Z","iopub.status.idle":"2024-11-28T05:36:55.306850Z","shell.execute_reply.started":"2024-11-28T05:35:47.546021Z","shell.execute_reply":"2024-11-28T05:36:55.306101Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import shutil\nshutil.make_archive(\"/kaggle/working/images\", 'zip', \"/kaggle/images\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-11-28T05:36:55.308144Z","iopub.execute_input":"2024-11-28T05:36:55.308922Z","iopub.status.idle":"2024-11-28T05:36:55.548811Z","shell.execute_reply.started":"2024-11-28T05:36:55.308881Z","shell.execute_reply":"2024-11-28T05:36:55.547979Z"}},"outputs":[],"execution_count":null}]}