{"metadata":{"kernelspec":{"display_name":"Python 3","language":"python","name":"python3"},"language_info":{"name":"python","version":"3.10.14","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"}],"dockerImageVersionId":30804,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true},"papermill":{"default_parameters":{},"duration":2848.744185,"end_time":"2024-06-15T16:55:27.187819","environment_variables":{},"exception":null,"input_path":"__notebook__.ipynb","output_path":"__notebook__.ipynb","parameters":{},"start_time":"2024-06-15T16:07:58.443634","version":"2.5.0"}},"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":{"trusted":true,"execution":{"iopub.status.busy":"2024-12-17T22:57:42.567784Z","iopub.execute_input":"2024-12-17T22:57:42.568510Z","iopub.status.idle":"2024-12-17T22:57:46.387340Z","shell.execute_reply.started":"2024-12-17T22:57:42.568471Z","shell.execute_reply":"2024-12-17T22:57:46.386432Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Import library TensorFlow sebagai basis pembuatan model Machine Learning\nimport tensorflow as tf\n\n# Mengimpor pustaka `keras` dari TensorFlow. Keras adalah API tinggi (high-level API) \n# yang digunakan untuk membuat dan melatih model neural network.\nfrom tensorflow import keras\n\n# Dari modul `keras`, kita mengimpor `layers`. Modul `layers` menyediakan lapisan-lapisan \n# neural network seperti Dense, Conv2D, MaxPooling, dsb., untuk membangun arsitektur model.\nfrom tensorflow.keras import layers\n\n# Mengimpor pustaka KaggleDatasets. Library ini digunakan untuk memuat dan mengakses dataset \n# pada lingkungan Kaggle. Berguna jika Anda sedang bekerja di Kaggle Notebook.\nfrom kaggle_datasets import KaggleDatasets\n\n# Mengimpor pustaka Matplotlib untuk membuat visualisasi grafik atau plot.\n# plt disingkat dari `matplotlib.pyplot` untuk mempermudah pemanggilan fungsi plotting.\nimport matplotlib.pyplot as plt\n\n# Mengimpor pustaka NumPy, yang digunakan untuk memproses dan memanipulasi data dalam bentuk array.\nimport numpy as np","metadata":{"_cell_guid":"79c7e3d0-c299-4dcb-8224-4455121ee9b0","_uuid":"d629ff2d2480ee46fbb7e2d37f6b5fab8052498a","papermill":{"duration":12.143679,"end_time":"2024-06-15T16:08:13.364309","exception":false,"start_time":"2024-06-15T16:08:01.220630","status":"completed"},"scrolled":true,"tags":[],"trusted":true,"execution":{"iopub.status.busy":"2024-12-17T22:57:46.388915Z","iopub.execute_input":"2024-12-17T22:57:46.389329Z","iopub.status.idle":"2024-12-17T22:57:58.018944Z","shell.execute_reply.started":"2024-12-17T22:57:46.389299Z","shell.execute_reply":"2024-12-17T22:57:58.018245Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"try:\n    # Menginisialisasi TPU (Tensor Processing Unit) jika tersedia\n    tpu = tf.distribute.cluster_resolver.TPUClusterResolver()\n    # Menampilkan alamat master TPU\n    print('Device:', tpu.master())\n    \n    # Menghubungkan TensorFlow ke cluster TPU yang ditemukan\n    tf.config.experimental_connect_to_cluster(tpu)\n    # Menginisialisasi sistem TPU agar siap digunakan\n    tf.tpu.experimental.initialize_tpu_system(tpu)\n    \n    # Membuat strategi distribusi untuk menggunakan TPU\n    # Strategi ini memungkinkan pelatihan model menggunakan banyak core TPU secara efisien\n    strategy = tf.distribute.experimental.TPUStrategy(tpu)\n\n# Jika kode di dalam blok \"try\" mengalami error (misalnya TPU tidak tersedia),\n# kode di bawah akan dijalankan.\nexcept:\n    # Mengecek apakah perangkat GPU tersedia\n    if tf.config.list_physical_devices('GPU'):\n        # Jika GPU ditemukan, gunakan MirroredStrategy untuk distribusi di GPU\n        # MirroredStrategy digunakan untuk pelatihan multi-GPU (sinkronisasi replikasi model)\n        strategy = tf.distribute.MirroredStrategy()\n        print(\"Running on GPU.\")  # Menampilkan pesan bahwa GPU digunakan\n    else:\n        # Jika TPU dan GPU tidak tersedia, strategi default (CPU) digunakan\n        strategy = tf.distribute.get_strategy()\n        print(\"Running on CPU.\")  # Menampilkan pesan bahwa CPU digunakan\n\n# Menampilkan jumlah replikasi perangkat yang digunakan dalam strategi distribusi\n# (berlaku untuk TPU atau GPU/CPU yang digunakan untuk pelatihan multi-device)\nprint('Number of replicas:', strategy.num_replicas_in_sync)\n\n# Variabel AUTOTUNE digunakan untuk mengatur penyesuaian otomatis dalam prefetch data\n# agar proses pelatihan menjadi lebih optimal\nAUTOTUNE = tf.data.experimental.AUTOTUNE\n\n# Menampilkan versi TensorFlow yang digunakan\nprint(tf.__version__)","metadata":{"papermill":{"duration":0.739387,"end_time":"2024-06-15T16:08:14.144775","exception":false,"start_time":"2024-06-15T16:08:13.405388","status":"completed"},"tags":[],"trusted":true,"execution":{"iopub.status.busy":"2024-12-17T22:57:58.019953Z","iopub.execute_input":"2024-12-17T22:57:58.020459Z","iopub.status.idle":"2024-12-17T22:57:58.769095Z","shell.execute_reply.started":"2024-12-17T22:57:58.020428Z","shell.execute_reply":"2024-12-17T22:57:58.767895Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"#digunakan untuk mendapatkan lokasi path google cloud storage dari dataset yang saya gunakan\nGCS_PATH = KaggleDatasets().get_gcs_path()","metadata":{"papermill":{"duration":0.497599,"end_time":"2024-06-15T16:08:14.683614","exception":false,"start_time":"2024-06-15T16:08:14.186015","status":"completed"},"tags":[],"trusted":true,"execution":{"iopub.status.busy":"2024-12-17T22:57:58.770432Z","iopub.execute_input":"2024-12-17T22:57:58.770859Z","iopub.status.idle":"2024-12-17T22:57:59.132851Z","shell.execute_reply.started":"2024-12-17T22:57:58.770806Z","shell.execute_reply":"2024-12-17T22:57:59.132152Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Menggunakan fungsi glob dari tf.io.gfile untuk mengambil semua file dengan pola yang sesuai.\n# Di sini, kita mencari semua file dengan ekstensi \".tfrec\" di folder \"monet_tfrec\"\nMONET_FILENAMES = tf.io.gfile.glob(str(GCS_PATH + '/monet_tfrec/*.tfrec'))\n\n# Menampilkan jumlah file TFRecord yang ditemukan untuk gambar Monet\nprint('Monet TFRecord Files:', len(MONET_FILENAMES))\n\n# Melakukan hal yang sama untuk file dengan ekstensi \".tfrec\" di folder \"photo_tfrec\"\nPHOTO_FILENAMES = tf.io.gfile.glob(str(GCS_PATH + '/photo_tfrec/*.tfrec'))\n\n# Menampilkan jumlah file TFRecord yang ditemukan untuk foto biasa\nprint('Photo TFRecord Files:', len(PHOTO_FILENAMES))","metadata":{"papermill":{"duration":2.079559,"end_time":"2024-06-15T16:08:16.777122","exception":false,"start_time":"2024-06-15T16:08:14.697563","status":"completed"},"tags":[],"trusted":true,"execution":{"iopub.status.busy":"2024-12-17T22:57:59.134865Z","iopub.execute_input":"2024-12-17T22:57:59.135134Z","iopub.status.idle":"2024-12-17T22:57:59.487006Z","shell.execute_reply.started":"2024-12-17T22:57:59.135107Z","shell.execute_reply":"2024-12-17T22:57:59.486150Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Mendefinisikan ukuran gambar sebagai list dengan dimensi 256x256 piksel.\nIMAGE_SIZE = [256, 256]\n\n# Fungsi untuk mendekode (membaca) gambar dari format JPEG menjadi tensor\ndef decode_image(image):\n    # Menggunakan tf.image.decode_jpeg untuk mendekode file gambar JPEG.\n    # Parameter channels=3 menunjukkan gambar memiliki 3 channel (RGB).\n    image = tf.image.decode_jpeg(image, channels=3)\n    \n    # Mengonversi nilai piksel gambar ke dalam range [-1, 1].\n    # - tf.cast(image, tf.float32) mengubah tipe data piksel menjadi float32.\n    # - Membagi dengan 127.5 dan menguranginya dengan 1 menyebabkan nilai piksel\n    #   yang semula dalam rentang [0, 255] menjadi [-1, 1].\n    image = (tf.cast(image, tf.float32) / 127.5) - 1\n    \n    # Mengubah (reshape) tensor gambar menjadi ukuran tetap: [256, 256, 3].\n    # *IMAGE_SIZE melakukan unpack list menjadi dua angka (256, 256),\n    # sedangkan '3' menunjukkan 3 channel (RGB).\n    image = tf.reshape(image, [*IMAGE_SIZE, 3])\n    \n    # Mengembalikan gambar yang sudah diproses.\n    return image\n\n# Fungsi untuk membaca data dari TFRecord dan mengurai isinya\ndef read_tfrecord(example):\n    # Mendefinisikan format TFRecord.\n    # TFRecord adalah format untuk menyimpan data secara efisien di TensorFlow.\n    tfrecord_format = {\n        \"image_name\": tf.io.FixedLenFeature([], tf.string), # Field nama gambar\n        \"image\": tf.io.FixedLenFeature([], tf.string),      # Field data gambar dalam format string (bytes)\n        \"target\": tf.io.FixedLenFeature([], tf.string)      # Field target atau label dalam format string\n    }\n    \n    # Mengurai satu contoh (record) TFRecord menggunakan format yang didefinisikan di atas.\n    example = tf.io.parse_single_example(example, tfrecord_format)\n    \n    # Memanggil fungsi decode_image untuk memproses data gambar yang sudah diambil.\n    # Menggunakan key 'image' dari record yang telah di-parse.\n    image = decode_image(example['image'])\n    \n    # Mengembalikan gambar yang sudah di-decode.\n    return image","metadata":{"papermill":{"duration":0.023658,"end_time":"2024-06-15T16:08:16.843165","exception":false,"start_time":"2024-06-15T16:08:16.819507","status":"completed"},"tags":[],"trusted":true,"execution":{"iopub.status.busy":"2024-12-17T22:57:59.488045Z","iopub.execute_input":"2024-12-17T22:57:59.488355Z","iopub.status.idle":"2024-12-17T22:57:59.494601Z","shell.execute_reply.started":"2024-12-17T22:57:59.488325Z","shell.execute_reply":"2024-12-17T22:57:59.493754Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Fungsi untuk memuat dataset dari file-file TFRecord\ndef load_dataset(filenames, labeled=True, ordered=False):\n    # Membuat objek dataset dari daftar file TFRecord\n    # tf.data.TFRecordDataset digunakan untuk membaca data dalam format TFRecord\n    dataset = tf.data.TFRecordDataset(filenames)\n    \n    # Mengaplikasikan fungsi \"read_tfrecord\" untuk memproses setiap contoh (record) dari dataset\n    # Fungsi \"read_tfrecord\" akan mem-parsing (membaca) TFRecord dan memproses datanya.\n    # Parameter \"num_parallel_calls=AUTOTUNE\" digunakan untuk mem-paralelkan pemrosesan data,\n    # sehingga dapat berjalan lebih cepat secara otomatis.\n    dataset = dataset.map(read_tfrecord, num_parallel_calls=AUTOTUNE)\n    \n    # Mengembalikan dataset yang sudah diproses\n    return dataset","metadata":{"papermill":{"duration":0.020924,"end_time":"2024-06-15T16:08:16.904977","exception":false,"start_time":"2024-06-15T16:08:16.884053","status":"completed"},"tags":[],"trusted":true,"execution":{"iopub.status.busy":"2024-12-17T22:57:59.495641Z","iopub.execute_input":"2024-12-17T22:57:59.495937Z","iopub.status.idle":"2024-12-17T22:57:59.509073Z","shell.execute_reply.started":"2024-12-17T22:57:59.495901Z","shell.execute_reply":"2024-12-17T22:57:59.508427Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Membuat dataset dari file TFRecord untuk gambar Monet\n# Fungsi load_dataset akan memuat dan memproses data dari MONET_FILENAMES\n# Kemudian, metode .batch(1) digunakan untuk membagi dataset ke dalam batch berukuran 1\n# Artinya, setiap iterasi akan menghasilkan satu gambar dalam satu batch.\nmonet_ds = load_dataset(MONET_FILENAMES, labeled=True).batch(1)\n\n# Membuat dataset dari file TFRecord untuk gambar foto biasa\n# Fungsi load_dataset akan memuat dan memproses data dari PHOTO_FILENAMES\n# Sama seperti sebelumnya, metode .batch(1) membagi dataset menjadi batch dengan ukuran 1\nphoto_ds = load_dataset(PHOTO_FILENAMES, labeled=True).batch(1)","metadata":{"papermill":{"duration":0.196588,"end_time":"2024-06-15T16:08:17.143060","exception":false,"start_time":"2024-06-15T16:08:16.946472","status":"completed"},"tags":[],"trusted":true,"execution":{"iopub.status.busy":"2024-12-17T22:57:59.510384Z","iopub.execute_input":"2024-12-17T22:57:59.510868Z","iopub.status.idle":"2024-12-17T22:57:59.652531Z","shell.execute_reply.started":"2024-12-17T22:57:59.510824Z","shell.execute_reply":"2024-12-17T22:57:59.651829Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Memilih satu contoh gambar Monet dari dataset \"monet_ds\"\n# - \"iter(monet_ds)\" membuat iterator dari dataset \"monet_ds\" yang sudah di-load sebelumnya.\n# - \"next()\" mengambil elemen pertama dari iterator tersebut, yaitu satu batch gambar.\nexample_monet = next(iter(monet_ds))\n\n# Memilih satu contoh gambar foto biasa dari dataset \"photo_ds\"\n# - Sama seperti di atas, \"iter(photo_ds)\" membuat iterator dari dataset \"photo_ds\".\n# - \"next()\" mengambil elemen pertama dari iterator tersebut, yaitu satu batch gambar.\nexample_photo = next(iter(photo_ds))","metadata":{"papermill":{"duration":5.176766,"end_time":"2024-06-15T16:08:22.361832","exception":false,"start_time":"2024-06-15T16:08:17.185066","status":"completed"},"tags":[],"trusted":true,"execution":{"iopub.status.busy":"2024-12-17T22:57:59.653441Z","iopub.execute_input":"2024-12-17T22:57:59.653679Z","iopub.status.idle":"2024-12-17T22:58:00.695986Z","shell.execute_reply.started":"2024-12-17T22:57:59.653653Z","shell.execute_reply":"2024-12-17T22:58:00.695097Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Menampilkan dua gambar (foto biasa dan gambar Monet) secara berdampingan menggunakan subplot\n\n# Subplot pertama (kiri)\nplt.subplot(121)  # Membuat subplot pada posisi pertama dari layout 1 baris dan 2 kolom\nplt.title('Photo')  # Menambahkan judul untuk subplot pertama\n# Menampilkan contoh gambar foto biasa (example_photo)\n# - example_photo[0] adalah tensor gambar pertama dari batch.\n# - Dikalikan 0.5 dan ditambahkan 0.5 untuk mengembalikan nilai piksel ke rentang [0, 1].\n#   Ini karena nilai gambar awal berada pada rentang [-1, 1].\nplt.imshow(example_photo[0] * 0.5 + 0.5)  \n\n# Subplot kedua (kanan)\nplt.subplot(122)  # Membuat subplot pada posisi kedua dari layout 1 baris dan 2 kolom\nplt.title('Monet')  # Menambahkan judul untuk subplot kedua\n# Menampilkan contoh gambar Monet (example_monet)\n# - Sama seperti sebelumnya, example_monet[0] diproses untuk mengembalikan nilai piksel ke rentang [0, 1].\nplt.imshow(example_monet[0] * 0.5 + 0.5)\n\n# Menampilkan kedua subplot di atas\nplt.show()\n","metadata":{"papermill":{"duration":0.549264,"end_time":"2024-06-15T16:08:22.952919","exception":false,"start_time":"2024-06-15T16:08:22.403655","status":"completed"},"tags":[],"trusted":true,"execution":{"iopub.status.busy":"2024-12-17T22:58:00.697049Z","iopub.execute_input":"2024-12-17T22:58:00.697329Z","iopub.status.idle":"2024-12-17T22:58:01.108037Z","shell.execute_reply.started":"2024-12-17T22:58:00.697301Z","shell.execute_reply":"2024-12-17T22:58:01.107061Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Mengambil daftar semua file gambar dengan format .jpg di dalam direktori Monet dan Photo\n\n# tf.io.gfile.glob digunakan untuk mencari semua file yang cocok dengan pola tertentu di path yang diberikan.\n# GCS_PATH adalah path (lokasi) ke penyimpanan dataset di Google Cloud Storage (GCS).\n# '/monet_jpg/*.jpg' menunjukkan bahwa semua file dengan ekstensi \".jpg\" di dalam folder \"monet_jpg\" akan diambil.\nMONET_JPG = tf.io.gfile.glob(str(GCS_PATH + '/monet_jpg/*.jpg'))\n\n# Sama seperti di atas, tetapi mencari semua file .jpg di dalam folder \"photo_jpg\"\nPHOTO_JPG = tf.io.gfile.glob(str(GCS_PATH + '/photo_jpg/*.jpg'))\n\n# Menampilkan jumlah file gambar yang ditemukan di direktori Monet\n# len(MONET_JPG) menghitung jumlah file dalam list MONET_JPG\nprint('Number of images in Monet directory: ', len(MONET_JPG))\n\n# Menampilkan jumlah file gambar yang ditemukan di direktori Photo\n# len(PHOTO_JPG) menghitung jumlah file dalam list PHOTO_JPG\nprint('Number of images in photo directory: ', len(PHOTO_JPG))\n","metadata":{"papermill":{"duration":10.410702,"end_time":"2024-06-15T16:08:33.414491","exception":false,"start_time":"2024-06-15T16:08:23.003789","status":"completed"},"tags":[],"trusted":true,"execution":{"iopub.status.busy":"2024-12-17T22:58:01.109364Z","iopub.execute_input":"2024-12-17T22:58:01.109700Z","iopub.status.idle":"2024-12-17T22:58:02.403910Z","shell.execute_reply.started":"2024-12-17T22:58:01.109666Z","shell.execute_reply":"2024-12-17T22:58:02.403019Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Fungsi downsample untuk membuat layer-layer CNN yang digunakan untuk menurunkan resolusi gambar\n# Biasanya digunakan dalam model Generator atau Discriminator di GAN (Generative Adversarial Networks)\n\n# OUTPUT_CHANNELS diinisialisasi dengan 3, untuk gambar berwarna (RGB) dengan 3 saluran warna\nOUTPUT_CHANNELS = 3\n\n# Fungsi downsample digunakan untuk mengurangi resolusi gambar, contohnya pada jaringan Convolutional (CNN).\ndef downsample(filters, size, apply_instancenorm=True):\n    # inisialisasi untuk bobot pada layer konvolusi (Conv2D) menggunakan distribusi normal\n    initializer = tf.random_normal_initializer(0., 0.02)\n    # inisialisasi untuk gamma pada normalisasi grup (GroupNormalization), juga menggunakan distribusi normal\n    gamma_init = keras.initializers.RandomNormal(mean=0.0, stddev=0.02)\n\n    # Membuat model Sequential sebagai container untuk layer-layer\n    result = keras.Sequential()\n\n    # Menambahkan layer konvolusi 2D\n    # - \"filters\" menentukan jumlah filter (output channels) untuk layer konvolusi\n    # - \"size\" adalah ukuran kernel (filter) pada konvolusi\n    # - strides=2 mengatur langkah konvolusi untuk mengurangi resolusi gambar (downsampling)\n    # - padding='same' untuk menjaga dimensi gambar agar tetap konsisten\n    # - kernel_initializer digunakan untuk menginisialisasi bobot kernel\n    # - use_bias=False menonaktifkan penggunaan bias untuk layer ini\n    result.add(layers.Conv2D(filters, size, strides=2, padding='same',\n                             kernel_initializer=initializer, use_bias=False))\n\n    # Menambahkan normalisasi grup (GroupNormalization) jika apply_instancenorm adalah True\n    if apply_instancenorm:\n        # GroupNormalization adalah jenis normalisasi yang membagi channel gambar ke dalam grup dan menghitung statistik\n        # - gamma_initializer digunakan untuk menginisialisasi nilai gamma untuk normalisasi grup\n        # - groups=-1 berarti menggunakan semua channel sebagai satu grup\n        result.add(tf.keras.layers.GroupNormalization(gamma_initializer=gamma_init, groups = -1))\n\n    # Menambahkan fungsi aktivasi LeakyReLU setelah konvolusi dan normalisasi grup\n    # LeakyReLU memungkinkan nilai negatif (dengan slope kecil), menghindari vanishing gradient pada jaringan dalam\n    result.add(layers.LeakyReLU())\n\n    # Mengembalikan hasil yang telah dibuat (model dengan layer-layer tersebut)\n    return result","metadata":{"papermill":{"duration":0.027225,"end_time":"2024-06-15T16:08:33.566075","exception":false,"start_time":"2024-06-15T16:08:33.538850","status":"completed"},"tags":[],"trusted":true,"execution":{"iopub.status.busy":"2024-12-17T22:58:02.405211Z","iopub.execute_input":"2024-12-17T22:58:02.405600Z","iopub.status.idle":"2024-12-17T22:58:02.412518Z","shell.execute_reply.started":"2024-12-17T22:58:02.405558Z","shell.execute_reply":"2024-12-17T22:58:02.411595Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Fungsi upsample digunakan untuk meningkatkan resolusi gambar (upsampling)\n# Biasanya digunakan dalam model Generator pada jaringan GAN (Generative Adversarial Networks)\n# UpSampling dilakukan untuk memperbesar gambar ke resolusi yang lebih tinggi dengan teknik Conv2DTranspose\n\ndef upsample(filters, size, apply_dropout=False): \n    # Inisialisasi nilai awal bobot untuk kernel dengan distribusi normal\n    initializer = tf.random_normal_initializer(0., 0.02)\n    # Inisialisasi gamma untuk GroupNormalization juga menggunakan distribusi normal\n    gamma_init = keras.initializers.RandomNormal(mean=0.0, stddev=0.02)\n\n    # Membuat model Sequential sebagai container untuk layer-layer upsampling\n    result = keras.Sequential()\n\n    # Layer Conv2DTranspose digunakan untuk upsampling\n    # - filters: jumlah filter (saluran output) yang dihasilkan\n    # - size: ukuran kernel yang digunakan untuk upsampling (misalnya, 4x4)\n    # - strides=2: resolusi output menjadi 2 kali lipat dari input (upsampling)\n    # - padding='same': menjaga dimensi output agar tetap konsisten\n    # - kernel_initializer: bobot kernel diinisialisasi dengan distribusi normal\n    # - use_bias=False: tidak menggunakan bias\n    result.add(layers.Conv2DTranspose(filters, size, strides=2,\n                                      padding='same',\n                                      kernel_initializer=initializer,\n                                      use_bias=False))\n\n    # Menambahkan GroupNormalization untuk menormalisasi fitur peta (feature maps)\n    # - Membantu stabilisasi pelatihan dengan menghitung statistik berdasarkan grup channel\n    result.add(tf.keras.layers.GroupNormalization(gamma_initializer=gamma_init, groups=-1))\n\n    # Jika parameter apply_dropout bernilai True, tambahkan layer Dropout\n    # Dropout membantu mencegah overfitting dengan \"mematikan\" sebagian unit neuron secara acak\n    if apply_dropout:\n        result.add(layers.Dropout(0.5))\n\n    # Menambahkan fungsi aktivasi ReLU\n    # ReLU digunakan untuk membuat nilai negatif menjadi nol dan mempertahankan nilai positif\n    result.add(layers.ReLU())\n\n    # Mengembalikan hasil model Sequential\n    return result","metadata":{"papermill":{"duration":0.026244,"end_time":"2024-06-15T16:08:33.643984","exception":false,"start_time":"2024-06-15T16:08:33.617740","status":"completed"},"tags":[],"trusted":true,"execution":{"iopub.status.busy":"2024-12-17T22:58:02.414083Z","iopub.execute_input":"2024-12-17T22:58:02.414460Z","iopub.status.idle":"2024-12-17T22:58:02.429761Z","shell.execute_reply.started":"2024-12-17T22:58:02.414421Z","shell.execute_reply":"2024-12-17T22:58:02.428977Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Fungsi Generator untuk model GAN (Generative Adversarial Networks)\n# Arsitektur ini mirip dengan U-Net yang menggunakan teknik downsampling dan upsampling\n# serta menerapkan **skip connections** antara layer yang sesuai untuk mempertahankan detail gambar\n\ndef Generator():\n    # Layer Input yang menerima gambar dengan ukuran 256x256 dan 3 channel warna (RGB)\n    inputs = layers.Input(shape=[256, 256, 3])\n\n    # **Downsampling Stack**: Melakukan downsampling gambar secara bertahap,\n    # di mana resolusi gambar diperkecil, dan jumlah filter bertambah di setiap tahap.\n    down_stack = [\n        downsample(64, 4, apply_instancenorm=False), # Ukuran: (bs, 128, 128, 64), tidak menggunakan GroupNormalization\n        downsample(128, 4), # Ukuran: (bs, 64, 64, 128)\n        downsample(256, 4), # Ukuran: (bs, 32, 32, 256)\n        downsample(512, 4), # Ukuran: (bs, 16, 16, 512)\n        downsample(512, 4), # Ukuran: (bs, 8, 8, 512)\n        downsample(512, 4), # Ukuran: (bs, 4, 4, 512)\n        downsample(512, 4), # Ukuran: (bs, 2, 2, 512)\n        downsample(512, 4), # Ukuran: (bs, 1, 1, 512)\n    ]\n\n    # **Upsampling Stack**: Melakukan upsampling gambar secara bertahap,\n    # di mana resolusi gambar diperbesar kembali sambil menggabungkan hasil skip connections.\n    up_stack = [\n        upsample(512, 4, apply_dropout=True), # Ukuran: (bs, 2, 2, 1024), dropout digunakan\n        upsample(512, 4, apply_dropout=True), # Ukuran: (bs, 4, 4, 1024), dropout digunakan\n        upsample(512, 4, apply_dropout=True), # Ukuran: (bs, 8, 8, 1024), dropout digunakan\n        upsample(512, 4), # Ukuran: (bs, 16, 16, 1024)\n        upsample(256, 4), # Ukuran: (bs, 32, 32, 512)\n        upsample(128, 4), # Ukuran: (bs, 64, 64, 256)\n        upsample(64, 4), # Ukuran: (bs, 128, 128, 128)\n    ]\n\n    # Inisialisasi bobot layer terakhir dengan distribusi normal\n    initializer = tf.random_normal_initializer(0., 0.02)\n\n    # Layer terakhir menggunakan Conv2DTranspose untuk menghasilkan output\n    # - OUTPUT_CHANNELS = 3 (gambar RGB)\n    # - Ukuran kernel = 4x4, strides = 2 untuk melakukan upsampling terakhir\n    # - padding='same' menjaga ukuran output tetap konsisten\n    # - Activation='tanh' digunakan karena output di-normalisasi pada rentang [-1, 1]\n    last = layers.Conv2DTranspose(OUTPUT_CHANNELS, 4,\n                                  strides=2,\n                                  padding='same',\n                                  kernel_initializer=initializer,\n                                  activation='tanh') # Ukuran: (bs, 256, 256, 3)\n\n    # Variabel `x` menyimpan hasil dari input layer\n    x = inputs\n\n    # **Proses Downsampling**:\n    # Iterasi melalui `down_stack` untuk membuat fitur map dengan resolusi lebih kecil\n    skips = []  # List untuk menyimpan output dari setiap layer downsampling\n    for down in down_stack:\n        x = down(x)  # Aplikasikan layer downsampling\n        skips.append(x)  # Simpan hasil layer untuk skip connections\n\n    # Membalik urutan layer skip connections (kecuali layer terakhir) agar sesuai dengan upsampling\n    skips = reversed(skips[:-1])  # Hilangkan hasil terakhir (karena itu bottleneck)\n\n    # **Proses Upsampling**:\n    # Iterasi melalui `up_stack` (upsampling layer) sambil menggabungkan skip connections\n    for up, skip in zip(up_stack, skips):\n        x = up(x)  # Aplikasikan layer upsampling\n        x = layers.Concatenate()([x, skip])  # Gabungkan hasil upsampling dengan hasil downsampling (skip connection)\n\n    # Layer terakhir untuk menghasilkan output dengan resolusi penuh\n    x = last(x)\n\n    # Mengembalikan model Generator, dengan input dan output yang sudah didefinisikan\n    return keras.Model(inputs=inputs, outputs=x)","metadata":{"papermill":{"duration":0.029927,"end_time":"2024-06-15T16:08:33.724046","exception":false,"start_time":"2024-06-15T16:08:33.694119","status":"completed"},"tags":[],"trusted":true,"execution":{"iopub.status.busy":"2024-12-17T22:58:02.432705Z","iopub.execute_input":"2024-12-17T22:58:02.433037Z","iopub.status.idle":"2024-12-17T22:58:02.450389Z","shell.execute_reply.started":"2024-12-17T22:58:02.433010Z","shell.execute_reply":"2024-12-17T22:58:02.449696Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"!pip install pydot","metadata":{"papermill":{"duration":13.640778,"end_time":"2024-06-15T16:08:47.415055","exception":false,"start_time":"2024-06-15T16:08:33.774277","status":"completed"},"tags":[],"trusted":true,"execution":{"iopub.status.busy":"2024-12-17T22:58:02.451401Z","iopub.execute_input":"2024-12-17T22:58:02.451634Z","iopub.status.idle":"2024-12-17T22:58:11.636906Z","shell.execute_reply.started":"2024-12-17T22:58:02.451609Z","shell.execute_reply":"2024-12-17T22:58:11.635884Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Membuat instance (objek) dari model Generator\n# Fungsi Generator sebelumnya telah didefinisikan untuk arsitektur U-Net\ngenerator = Generator()\n\n# Menampilkan visualisasi arsitektur model menggunakan fungsi `plot_model`\n# - show_shapes=True: Menampilkan bentuk (shape) input dan output untuk setiap layer\n# - dpi=64: Resolusi gambar yang akan dihasilkan, semakin tinggi angkanya semakin jelas gambar\n\ntf.keras.utils.plot_model(generator, show_shapes=True, dpi=64)","metadata":{"papermill":{"duration":0.674794,"end_time":"2024-06-15T16:08:48.107479","exception":false,"start_time":"2024-06-15T16:08:47.432685","status":"completed"},"tags":[],"trusted":true,"execution":{"iopub.status.busy":"2024-12-17T22:58:11.638629Z","iopub.execute_input":"2024-12-17T22:58:11.639624Z","iopub.status.idle":"2024-12-17T22:58:12.459474Z","shell.execute_reply.started":"2024-12-17T22:58:11.639578Z","shell.execute_reply":"2024-12-17T22:58:12.458597Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def Discriminator():\n    # Inisialisasi bobot menggunakan distribusi normal untuk layer Conv2D\n    initializer = tf.random_normal_initializer(0., 0.02)\n    \n    # Inisialisasi bobot gamma pada GroupNormalization menggunakan distribusi normal\n    gamma_init = keras.initializers.RandomNormal(mean=0.0, stddev=0.02)\n\n    # Layer input menerima gambar berukuran 256x256 dengan 3 channel warna (RGB)\n    # Layer ini dinamai 'input_image' agar lebih mudah dipahami\n    inp = layers.Input(shape=[256, 256, 3], name='input_image')\n\n    x = inp  # Variabel x digunakan sebagai placeholder untuk menyimpan hasil proses pada setiap layer\n\n    # **Downsampling Block 1**:\n    # - Menerapkan layer Conv2D dengan filter 64 dan ukuran kernel 4x4\n    # - GroupNormalization **tidak diterapkan** di sini\n    # - Resolusi gambar berkurang menjadi (128, 128), jumlah channel menjadi 64\n    down1 = downsample(64, 4, False)(x) # (bs, 128, 128, 64)\n\n    # **Downsampling Block 2**:\n    # - Resolusi gambar dikurangi lagi menjadi (64, 64), jumlah channel menjadi 128\n    down2 = downsample(128, 4)(down1) # (bs, 64, 64, 128)\n\n    # **Downsampling Block 3**:\n    # - Resolusi gambar dikurangi menjadi (32, 32), jumlah channel menjadi 256\n    down3 = downsample(256, 4)(down2) # (bs, 32, 32, 256)\n\n    # **Zero Padding 1**:\n    # - Menambahkan padding kosong di sekitar tepi gambar untuk menjaga bentuk tensor\n    # - Ukuran tensor berubah menjadi (34, 34, 256)\n    zero_pad1 = layers.ZeroPadding2D()(down3) # (bs, 34, 34, 256)\n\n    # **Conv Layer**:\n    # - Layer Conv2D dengan filter 512 dan ukuran kernel 4x4\n    # - Strides = 1 berarti ukuran resolusi gambar tidak akan berkurang banyak\n    # - Ukuran tensor berubah menjadi (31, 31, 512)\n    conv = layers.Conv2D(512, 4, strides=1,\n                         kernel_initializer=initializer,\n                         use_bias=False)(zero_pad1) # (bs, 31, 31, 512)\n\n    # **Group Normalization**:\n    # - Normalisasi diterapkan pada output dari layer Conv2D\n    norm1 = tf.keras.layers.GroupNormalization(gamma_initializer=gamma_init, groups=-1)(conv)\n\n    # **Leaky ReLU Activation**:\n    # - Fungsi aktivasi Leaky ReLU untuk memperkenalkan non-linearitas\n    leaky_relu = layers.LeakyReLU()(norm1)\n\n    # **Zero Padding 2**:\n    # - Padding kosong ditambahkan lagi di sekitar gambar\n    # - Ukuran tensor berubah menjadi (33, 33, 512)\n    zero_pad2 = layers.ZeroPadding2D()(leaky_relu) # (bs, 33, 33, 512)\n\n    # **Layer Terakhir (Output)**:\n    # - Layer Conv2D dengan **1 filter** dan ukuran kernel 4x4 untuk menghasilkan output akhir\n    # - Strides = 1 digunakan, sehingga ukuran resolusi berkurang menjadi (30, 30)\n    # - Output memiliki 1 channel, yang digunakan sebagai **prediksi real/fake** pada GAN\n    last = layers.Conv2D(1, 4, strides=1,\n                         kernel_initializer=initializer)(zero_pad2) # (bs, 30, 30, 1)\n\n    # Mengembalikan model Discriminator dengan input berupa gambar (inp)\n    # dan output berupa tensor ukuran (30, 30, 1)\n    return tf.keras.Model(inputs=inp, outputs=last)","metadata":{"papermill":{"duration":0.031231,"end_time":"2024-06-15T16:08:48.199032","exception":false,"start_time":"2024-06-15T16:08:48.167801","status":"completed"},"tags":[],"trusted":true,"execution":{"iopub.status.busy":"2024-12-17T22:58:12.460773Z","iopub.execute_input":"2024-12-17T22:58:12.461600Z","iopub.status.idle":"2024-12-17T22:58:12.471222Z","shell.execute_reply.started":"2024-12-17T22:58:12.461558Z","shell.execute_reply":"2024-12-17T22:58:12.470363Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"discriminator = Discriminator()\ntf.keras.utils.plot_model(discriminator, show_shapes=True, dpi=64)","metadata":{"papermill":{"duration":0.181618,"end_time":"2024-06-15T16:08:48.440596","exception":false,"start_time":"2024-06-15T16:08:48.258978","status":"completed"},"tags":[],"trusted":true,"execution":{"iopub.status.busy":"2024-12-17T22:58:12.472400Z","iopub.execute_input":"2024-12-17T22:58:12.472780Z","iopub.status.idle":"2024-12-17T22:58:12.629579Z","shell.execute_reply.started":"2024-12-17T22:58:12.472733Z","shell.execute_reply":"2024-12-17T22:58:12.628596Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"with strategy.scope():\n    monet_generator = Generator() # transforms photos to Monet-esque paintings\n    photo_generator = Generator() # transforms Monet paintings to be more like photos\n\n    monet_discriminator = Discriminator() # differentiates real Monet paintings and generated Monet paintings\n    photo_discriminator = Discriminator() # differentiates real photos and generated photos","metadata":{"papermill":{"duration":0.865241,"end_time":"2024-06-15T16:08:49.327206","exception":false,"start_time":"2024-06-15T16:08:48.461965","status":"completed"},"tags":[],"trusted":true,"execution":{"iopub.status.busy":"2024-12-17T22:58:12.630762Z","iopub.execute_input":"2024-12-17T22:58:12.631100Z","iopub.status.idle":"2024-12-17T22:58:13.151455Z","shell.execute_reply.started":"2024-12-17T22:58:12.631064Z","shell.execute_reply":"2024-12-17T22:58:13.150460Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Menggunakan generator (monet_generator) untuk mengubah gambar asli menjadi gaya Monet\n# Input: example_photo (gambar input dengan gaya foto asli)\n# Output: Gambar yang dihasilkan oleh generator yang memiliki gaya seperti lukisan Monet\nto_monet = monet_generator(example_photo)\n\n# **Visualisasi Gambar Asli (Photo) dan Hasil Transformasi (Monet Style)**\n\n# Menampilkan dua subplot dalam satu baris (1x2)\nplt.subplot(1, 2, 1)  # Plot pertama (kolom pertama)\nplt.title(\"Original Photo\")  # Judul untuk gambar asli\n# Menampilkan gambar asli (example_photo)\n# - `example_photo[0]` digunakan karena gambar yang ditampilkan berada dalam batch pertama\n# - Dikalikan 0.5 dan ditambah 0.5 untuk mengembalikan nilai piksel ke rentang [0,1]\nplt.imshow(example_photo[0] * 0.5 + 0.5)\n\nplt.subplot(1, 2, 2)  # Plot kedua (kolom kedua)\nplt.title(\"Untrained Monet style Photo\")  # Judul untuk gambar hasil transformasi\n# Menampilkan gambar hasil dari generator (to_monet)\n# - Sama seperti sebelumnya, output generator memiliki rentang [-1,1]\n#   sehingga harus dikembalikan ke rentang [0,1]\nplt.imshow(to_monet[0] * 0.5 + 0.5)\n\n# Menampilkan semua subplot di layar\nplt.show()","metadata":{"papermill":{"duration":2.973065,"end_time":"2024-06-15T16:08:52.363229","exception":false,"start_time":"2024-06-15T16:08:49.390164","status":"completed"},"tags":[],"trusted":true,"execution":{"iopub.status.busy":"2024-12-17T22:58:13.152739Z","iopub.execute_input":"2024-12-17T22:58:13.153437Z","iopub.status.idle":"2024-12-17T22:58:15.567964Z","shell.execute_reply.started":"2024-12-17T22:58:13.153391Z","shell.execute_reply":"2024-12-17T22:58:15.567054Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# **Class CycleGan**:  \n# Kelas ini adalah implementasi **CycleGAN** sebagai subclass dari `keras.Model`.  \n# CycleGAN digunakan untuk mengubah gambar dari satu domain ke domain lain  \n# (misalnya dari foto ke lukisan Monet, atau sebaliknya) **tanpa paired data** (data yang berpasangan).\n\nclass CycleGan(keras.Model):\n    def __init__(\n        self,\n        monet_generator,       # Generator untuk mengubah foto menjadi gaya Monet\n        photo_generator,       # Generator untuk mengubah lukisan Monet ke foto asli\n        monet_discriminator,   # Discriminator untuk memvalidasi gambar dengan gaya Monet\n        photo_discriminator,   # Discriminator untuk memvalidasi gambar berupa foto\n        lambda_cycle=10,       # Bobot untuk **cycle consistency loss**\n    ):\n        super(CycleGan, self).__init__()  # Memanggil konstruktor superclass (keras.Model)\n        \n        # Menyimpan model generator dan discriminator sebagai atribut kelas\n        self.m_gen = monet_generator       # Generator Monet\n        self.p_gen = photo_generator       # Generator Foto\n        self.m_disc = monet_discriminator  # Discriminator Monet\n        self.p_disc = photo_discriminator  # Discriminator Foto\n        \n        self.lambda_cycle = lambda_cycle   # Faktor untuk loss konsistensi siklus\n\n    # **Fungsi compile**:  \n    # Digunakan untuk mendefinisikan optimizer dan fungsi loss yang diperlukan.\n    def compile(\n        self,\n        m_gen_optimizer,     # Optimizer untuk generator Monet\n        p_gen_optimizer,     # Optimizer untuk generator Foto\n        m_disc_optimizer,    # Optimizer untuk discriminator Monet\n        p_disc_optimizer,    # Optimizer untuk discriminator Foto\n        gen_loss_fn,         # Fungsi loss untuk generator\n        disc_loss_fn,        # Fungsi loss untuk discriminator\n        cycle_loss_fn,       # Fungsi cycle consistency loss\n        identity_loss_fn     # Fungsi identity loss\n    ):\n        super(CycleGan, self).compile()  # Memanggil fungsi compile dari superclass\n        \n        # Menyimpan optimizer dan fungsi loss sebagai atribut kelas\n        self.m_gen_optimizer = m_gen_optimizer\n        self.p_gen_optimizer = p_gen_optimizer\n        self.m_disc_optimizer = m_disc_optimizer\n        self.p_disc_optimizer = p_disc_optimizer\n        \n        self.gen_loss_fn = gen_loss_fn\n        self.disc_loss_fn = disc_loss_fn\n        self.cycle_loss_fn = cycle_loss_fn\n        self.identity_loss_fn = identity_loss_fn\n\n    # **Fungsi train_step**:  \n    # Mendefinisikan satu langkah training untuk melatih generator dan discriminator.\n    def train_step(self, batch_data):\n        real_monet, real_photo = batch_data  # Membaca input batch berisi gambar Monet dan Foto\n\n        with tf.GradientTape(persistent=True) as tape:  # Merekam operasi untuk menghitung gradien\n            # **Photo ke Monet lalu kembali ke Foto (CycleGAN Forward Cycle)**\n            fake_monet = self.m_gen(real_photo, training=True)  # Menghasilkan gambar Monet dari foto\n            cycled_photo = self.p_gen(fake_monet, training=True)  # Mengubah kembali ke gambar foto\n            \n            # **Monet ke Foto lalu kembali ke Monet (CycleGAN Backward Cycle)**\n            fake_photo = self.p_gen(real_monet, training=True)  # Menghasilkan foto dari gambar Monet\n            cycled_monet = self.m_gen(fake_photo, training=True)  # Mengubah kembali ke gambar Monet\n\n            # **Identity Loss**: Menghasilkan gambar yang sama jika inputnya sama\n            same_monet = self.m_gen(real_monet, training=True)\n            same_photo = self.p_gen(real_photo, training=True)\n\n            # **Discriminator Loss**:\n            # Memvalidasi gambar nyata (real)\n            disc_real_monet = self.m_disc(real_monet, training=True)  # Discriminator Monet memeriksa gambar asli\n            disc_real_photo = self.p_disc(real_photo, training=True)  # Discriminator Foto memeriksa gambar asli\n\n            # Memvalidasi gambar palsu (fake)\n            disc_fake_monet = self.m_disc(fake_monet, training=True)  # Discriminator Monet memeriksa gambar palsu\n            disc_fake_photo = self.p_disc(fake_photo, training=True)  # Discriminator Foto memeriksa gambar palsu\n\n            # **Menghitung Generator Loss** (kehilangan untuk gambar yang dihasilkan)\n            monet_gen_loss = self.gen_loss_fn(disc_fake_monet)\n            photo_gen_loss = self.gen_loss_fn(disc_fake_photo)\n\n            # **Menghitung Cycle Consistency Loss**: Memastikan input asli dan hasil siklus sama\n            total_cycle_loss = (\n                self.cycle_loss_fn(real_monet, cycled_monet, self.lambda_cycle) +\n                self.cycle_loss_fn(real_photo, cycled_photo, self.lambda_cycle)\n            )\n\n            # **Total Generator Loss**: Kombinasi loss generator, cycle loss, dan identity loss\n            total_monet_gen_loss = monet_gen_loss + total_cycle_loss + self.identity_loss_fn(real_monet, same_monet, self.lambda_cycle)\n            total_photo_gen_loss = photo_gen_loss + total_cycle_loss + self.identity_loss_fn(real_photo, same_photo, self.lambda_cycle)\n\n            # **Menghitung Discriminator Loss**: Memastikan perbedaan gambar nyata dan palsu\n            monet_disc_loss = self.disc_loss_fn(disc_real_monet, disc_fake_monet)\n            photo_disc_loss = self.disc_loss_fn(disc_real_photo, disc_fake_photo)\n\n        # **Menghitung Gradien untuk Generator dan Discriminator**\n        monet_generator_gradients = tape.gradient(total_monet_gen_loss, self.m_gen.trainable_variables)\n        photo_generator_gradients = tape.gradient(total_photo_gen_loss, self.p_gen.trainable_variables)\n\n        monet_discriminator_gradients = tape.gradient(monet_disc_loss, self.m_disc.trainable_variables)\n        photo_discriminator_gradients = tape.gradient(photo_disc_loss, self.p_disc.trainable_variables)\n\n        # **Mengupdate Gradien menggunakan Optimizer**\n        self.m_gen_optimizer.apply_gradients(zip(monet_generator_gradients, self.m_gen.trainable_variables))\n        self.p_gen_optimizer.apply_gradients(zip(photo_generator_gradients, self.p_gen.trainable_variables))\n\n        self.m_disc_optimizer.apply_gradients(zip(monet_discriminator_gradients, self.m_disc.trainable_variables))\n        self.p_disc_optimizer.apply_gradients(zip(photo_discriminator_gradients, self.p_disc.trainable_variables))\n\n        # **Mengembalikan Nilai Loss untuk Setiap Komponen**  \n        return {\n            \"monet_gen_loss\": total_monet_gen_loss,\n            \"photo_gen_loss\": total_photo_gen_loss,\n            \"monet_disc_loss\": monet_disc_loss,\n            \"photo_disc_loss\": photo_disc_loss\n        }","metadata":{"papermill":{"duration":0.043681,"end_time":"2024-06-15T16:08:52.474923","exception":false,"start_time":"2024-06-15T16:08:52.431242","status":"completed"},"tags":[],"trusted":true,"execution":{"iopub.status.busy":"2024-12-17T22:58:15.569561Z","iopub.execute_input":"2024-12-17T22:58:15.569914Z","iopub.status.idle":"2024-12-17T22:58:15.583820Z","shell.execute_reply.started":"2024-12-17T22:58:15.569871Z","shell.execute_reply":"2024-12-17T22:58:15.582932Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# Loss functions","metadata":{"papermill":{"duration":0.022086,"end_time":"2024-06-15T16:08:52.519633","exception":false,"start_time":"2024-06-15T16:08:52.497547","status":"completed"},"tags":[]}},{"cell_type":"code","source":"# **Menggunakan strategy.scope()**:  \n# - Digunakan untuk mendistribusikan model dan variabel pada beberapa device (misalnya GPU/TPU)  \n#   agar training dapat berjalan lebih efisien dalam konteks strategi distribusi TensorFlow.\n\nwith strategy.scope():  \n    # **Fungsi discriminator_loss**:  \n    # Fungsi ini digunakan untuk menghitung kehilangan (loss) pada **discriminator**.  \n    # Discriminator bertugas membedakan gambar asli (real) dan gambar yang dihasilkan (fake/generated).\n\n    def discriminator_loss(real, generated):\n        # **Loss untuk gambar asli (real_loss):**\n        # - Menggunakan fungsi Binary Cross-Entropy (BCE) untuk menghitung seberapa dekat  \n        #   output dari discriminator untuk gambar **asli** dengan label \"1\" (benar/asli).  \n        # - `tf.ones_like(real)` menghasilkan tensor berisi nilai 1 dengan bentuk yang sama seperti `real`.  \n        # - `reduction=tf.keras.losses.Reduction.NONE`: Menghindari penggabungan langsung hasil loss  \n        #   agar bisa dihitung per elemen sebelum dijumlahkan manual.\n\n        real_loss = tf.keras.losses.BinaryCrossentropy(\n            from_logits=True,  # Menyatakan bahwa output dari discriminator belum dalam bentuk probabilitas (logits).\n            reduction=tf.keras.losses.Reduction.NONE  # Tidak mengurangi hasil loss secara otomatis\n        )(tf.ones_like(real), real)  # Membandingkan nilai real dengan label 1.\n\n        # **Loss untuk gambar hasil generator (generated_loss):**\n        # - Sama seperti pada `real_loss`, tetapi di sini menghitung perbedaan  \n        #   antara output discriminator untuk gambar **palsu** dengan label \"0\" (palsu).  \n        # - `tf.zeros_like(generated)` menghasilkan tensor berisi nilai 0 dengan bentuk yang sama seperti `generated`.\n\n        generated_loss = tf.keras.losses.BinaryCrossentropy(\n            from_logits=True,  # Output masih berupa logits\n            reduction=tf.keras.losses.Reduction.NONE  # Tidak direduksi otomatis\n        )(tf.zeros_like(generated), generated)  # Membandingkan nilai generated dengan label 0.\n\n        # **Menghitung total loss untuk discriminator:**\n        # - Loss total adalah jumlah dari `real_loss` dan `generated_loss`  \n        #   (sebesar separuh dari total agar seimbang dalam optimasi).\n\n        total_disc_loss = real_loss + generated_loss  # Menjumlahkan loss gambar asli dan gambar palsu.\n\n        return total_disc_loss * 0.5  # Mengalikan dengan 0.5 untuk menyeimbangkan kontribusi total loss","metadata":{"papermill":{"duration":0.03095,"end_time":"2024-06-15T16:08:52.572790","exception":false,"start_time":"2024-06-15T16:08:52.541840","status":"completed"},"tags":[],"trusted":true,"execution":{"iopub.status.busy":"2024-12-17T22:58:15.584990Z","iopub.execute_input":"2024-12-17T22:58:15.585281Z","iopub.status.idle":"2024-12-17T22:58:15.612293Z","shell.execute_reply.started":"2024-12-17T22:58:15.585253Z","shell.execute_reply":"2024-12-17T22:58:15.611435Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"with strategy.scope():\n    def generator_loss(generated):\n        return tf.keras.losses.BinaryCrossentropy(from_logits=True, reduction=tf.keras.losses.Reduction.NONE)(tf.ones_like(generated), generated)","metadata":{"papermill":{"duration":0.03181,"end_time":"2024-06-15T16:08:52.672326","exception":false,"start_time":"2024-06-15T16:08:52.640516","status":"completed"},"tags":[],"trusted":true,"execution":{"iopub.status.busy":"2024-12-17T22:58:15.613455Z","iopub.execute_input":"2024-12-17T22:58:15.613822Z","iopub.status.idle":"2024-12-17T22:58:15.627045Z","shell.execute_reply.started":"2024-12-17T22:58:15.613781Z","shell.execute_reply":"2024-12-17T22:58:15.626237Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"with strategy.scope():\n    def calc_cycle_loss(real_image, cycled_image, LAMBDA):\n        loss1 = tf.reduce_mean(tf.abs(real_image - cycled_image))\n\n        return LAMBDA * loss1","metadata":{"papermill":{"duration":0.030269,"end_time":"2024-06-15T16:08:52.770198","exception":false,"start_time":"2024-06-15T16:08:52.739929","status":"completed"},"tags":[],"trusted":true,"execution":{"iopub.status.busy":"2024-12-17T22:58:15.628157Z","iopub.execute_input":"2024-12-17T22:58:15.628538Z","iopub.status.idle":"2024-12-17T22:58:15.638011Z","shell.execute_reply.started":"2024-12-17T22:58:15.628494Z","shell.execute_reply":"2024-12-17T22:58:15.637236Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"with strategy.scope():\n    def identity_loss(real_image, same_image, LAMBDA):\n        loss = tf.reduce_mean(tf.abs(real_image - same_image))\n        return LAMBDA * 0.5 * loss","metadata":{"papermill":{"duration":0.03065,"end_time":"2024-06-15T16:08:52.868383","exception":false,"start_time":"2024-06-15T16:08:52.837733","status":"completed"},"tags":[],"trusted":true,"execution":{"iopub.status.busy":"2024-12-17T22:58:15.638905Z","iopub.execute_input":"2024-12-17T22:58:15.639126Z","iopub.status.idle":"2024-12-17T22:58:15.649639Z","shell.execute_reply.started":"2024-12-17T22:58:15.639103Z","shell.execute_reply":"2024-12-17T22:58:15.648957Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# CycleGAN Model training","metadata":{"papermill":{"duration":0.022657,"end_time":"2024-06-15T16:08:52.913154","exception":false,"start_time":"2024-06-15T16:08:52.890497","status":"completed"},"tags":[]}},{"cell_type":"markdown","source":"#### Optimizers","metadata":{"papermill":{"duration":0.022033,"end_time":"2024-06-15T16:08:52.957476","exception":false,"start_time":"2024-06-15T16:08:52.935443","status":"completed"},"tags":[]}},{"cell_type":"code","source":"with 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\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)","metadata":{"papermill":{"duration":0.04212,"end_time":"2024-06-15T16:08:53.021957","exception":false,"start_time":"2024-06-15T16:08:52.979837","status":"completed"},"tags":[],"trusted":true,"execution":{"iopub.status.busy":"2024-12-17T22:58:15.650560Z","iopub.execute_input":"2024-12-17T22:58:15.650784Z","iopub.status.idle":"2024-12-17T22:58:15.672425Z","shell.execute_reply.started":"2024-12-17T22:58:15.650760Z","shell.execute_reply":"2024-12-17T22:58:15.671776Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## CycleGAN Model Instantiation","metadata":{"papermill":{"duration":0.02212,"end_time":"2024-06-15T16:08:53.066509","exception":false,"start_time":"2024-06-15T16:08:53.044389","status":"completed"},"tags":[]}},{"cell_type":"code","source":"with strategy.scope():\n    cycle_gan_model = CycleGan(\n        monet_generator, photo_generator, monet_discriminator, photo_discriminator\n    )\n\n    cycle_gan_model.compile(\n        m_gen_optimizer = monet_generator_optimizer,\n        p_gen_optimizer = photo_generator_optimizer,\n        m_disc_optimizer = monet_discriminator_optimizer,\n        p_disc_optimizer = photo_discriminator_optimizer,\n        gen_loss_fn = generator_loss,\n        disc_loss_fn = discriminator_loss,\n        cycle_loss_fn = calc_cycle_loss,\n        identity_loss_fn = identity_loss\n    )","metadata":{"papermill":{"duration":0.039282,"end_time":"2024-06-15T16:08:53.127941","exception":false,"start_time":"2024-06-15T16:08:53.088659","status":"completed"},"tags":[],"trusted":true,"execution":{"iopub.status.busy":"2024-12-17T22:58:15.673276Z","iopub.execute_input":"2024-12-17T22:58:15.673502Z","iopub.status.idle":"2024-12-17T22:58:15.685442Z","shell.execute_reply.started":"2024-12-17T22:58:15.673478Z","shell.execute_reply":"2024-12-17T22:58:15.684579Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## Model fit","metadata":{"papermill":{"duration":0.022391,"end_time":"2024-06-15T16:08:53.172965","exception":false,"start_time":"2024-06-15T16:08:53.150574","status":"completed"},"tags":[]}},{"cell_type":"code","source":"cycle_gan_model.fit(\n    tf.data.Dataset.zip((monet_ds, photo_ds)),\n    epochs=25\n)","metadata":{"papermill":{"duration":2256.008089,"end_time":"2024-06-15T16:46:29.203647","exception":false,"start_time":"2024-06-15T16:08:53.195558","status":"completed"},"tags":[],"trusted":true,"execution":{"iopub.status.busy":"2024-12-17T22:58:15.686618Z","iopub.execute_input":"2024-12-17T22:58:15.686884Z","iopub.status.idle":"2024-12-17T23:34:23.544138Z","shell.execute_reply.started":"2024-12-17T22:58:15.686857Z","shell.execute_reply":"2024-12-17T23:34:23.543267Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# Monet-like images from our Model fit:","metadata":{"papermill":{"duration":0.637935,"end_time":"2024-06-15T16:46:30.487736","exception":false,"start_time":"2024-06-15T16:46:29.849801","status":"completed"},"tags":[]}},{"cell_type":"code","source":"_, ax = plt.subplots(5, 2, figsize=(12, 12))\nfor i, img in enumerate(photo_ds.take(5)):\n    prediction = monet_generator(img, training=False)[0].numpy()\n    prediction = (prediction * 127.5 + 127.5).astype(np.uint8)\n    img = (img[0] * 127.5 + 127.5).numpy().astype(np.uint8)\n\n    ax[i, 0].imshow(img)\n    ax[i, 1].imshow(prediction)\n    ax[i, 0].set_title(\"Input Photo\")\n    ax[i, 1].set_title(\"Monet Style\")\n    ax[i, 0].axis(\"off\")\n    ax[i, 1].axis(\"off\")\nplt.show()","metadata":{"papermill":{"duration":4.582907,"end_time":"2024-06-15T16:46:35.774440","exception":false,"start_time":"2024-06-15T16:46:31.191533","status":"completed"},"tags":[],"trusted":true,"execution":{"iopub.status.busy":"2024-12-17T23:34:23.545355Z","iopub.execute_input":"2024-12-17T23:34:23.545641Z","iopub.status.idle":"2024-12-17T23:34:25.259089Z","shell.execute_reply.started":"2024-12-17T23:34:23.545612Z","shell.execute_reply":"2024-12-17T23:34:25.258111Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# Generate submission file","metadata":{"papermill":{"duration":0.655979,"end_time":"2024-06-15T16:46:37.080805","exception":false,"start_time":"2024-06-15T16:46:36.424826","status":"completed"},"tags":[]}},{"cell_type":"code","source":"import PIL\n! mkdir ../images","metadata":{"papermill":{"duration":1.644025,"end_time":"2024-06-15T16:46:39.406987","exception":false,"start_time":"2024-06-15T16:46:37.762962","status":"completed"},"tags":[],"trusted":true,"execution":{"iopub.status.busy":"2024-12-17T23:34:25.260341Z","iopub.execute_input":"2024-12-17T23:34:25.260642Z","iopub.status.idle":"2024-12-17T23:34:26.317221Z","shell.execute_reply.started":"2024-12-17T23:34:25.260606Z","shell.execute_reply":"2024-12-17T23:34:26.316237Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"i = 1\nfor img in photo_ds:\n    prediction = monet_generator(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":{"papermill":{"duration":515.179226,"end_time":"2024-06-15T16:55:15.253219","exception":false,"start_time":"2024-06-15T16:46:40.073993","status":"completed"},"tags":[],"trusted":true,"execution":{"iopub.status.busy":"2024-12-17T23:49:36.306429Z","iopub.execute_input":"2024-12-17T23:49:36.306724Z","iopub.status.idle":"2024-12-17T23:57:09.019558Z","shell.execute_reply.started":"2024-12-17T23:49:36.306695Z","shell.execute_reply":"2024-12-17T23:57:09.018694Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import shutil\nshutil.make_archive(\"/kaggle/working/images\", 'zip', \"/kaggle/images\")","metadata":{"papermill":{"duration":4.732578,"end_time":"2024-06-15T16:55:20.634684","exception":false,"start_time":"2024-06-15T16:55:15.902106","status":"completed"},"tags":[],"trusted":true,"execution":{"iopub.status.busy":"2024-12-17T23:49:33.080011Z","iopub.execute_input":"2024-12-17T23:49:33.080325Z","iopub.status.idle":"2024-12-17T23:49:36.303718Z","shell.execute_reply.started":"2024-12-17T23:49:33.080296Z","shell.execute_reply":"2024-12-17T23:49:36.302869Z"}},"outputs":[],"execution_count":null}]}