{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.11.11","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"none","dataSources":[{"sourceId":21755,"databundleVersionId":1475600,"sourceType":"competition"},{"sourceId":400248,"sourceType":"modelInstanceVersion","isSourceIdPinned":true,"modelInstanceId":327524,"modelId":348399}],"dockerImageVersionId":31040,"isInternetEnabled":false,"language":"python","sourceType":"notebook","isGpuEnabled":false}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"# Cell 1: Import\nimport os\nimport numpy as np\nimport tensorflow as tf\nfrom PIL import Image\nfrom tqdm import tqdm\nfrom tensorflow.keras import layers, Model, Sequential\n\n\n","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true,"execution":{"iopub.status.busy":"2025-05-18T12:44:52.871660Z","iopub.execute_input":"2025-05-18T12:44:52.871913Z","iopub.status.idle":"2025-05-18T12:45:10.643965Z","shell.execute_reply.started":"2025-05-18T12:44:52.871892Z","shell.execute_reply":"2025-05-18T12:45:10.643192Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from tensorflow.keras.utils import register_keras_serializable, deserialize_keras_object, serialize_keras_object\nfrom tensorflow import keras\nimport tensorflow as tf\n\n@register_keras_serializable()\nclass CycleGan(keras.Model):\n    def __init__(\n        self,\n        monet_generator=None,\n        photo_generator=None,\n        monet_discriminator=None,\n        photo_discriminator=None,\n        lambda_cycle=10,\n        **kwargs\n    ):\n        super(CycleGan, self).__init__(**kwargs)\n        self.m_gen = monet_generator\n        self.p_gen = photo_generator\n        self.m_disc = monet_discriminator\n        self.p_disc = photo_discriminator\n        self.lambda_cycle = lambda_cycle\n\n    @tf.function   \n    def call(self, inputs, training=False):\n        if self.m_gen is None:\n            raise ValueError(\"monet_generator belum dimuat. Pastikan model memiliki generator.\")\n        return self.m_gen(inputs, training=training)\n\n    @classmethod\n    def from_config(cls, config):\n        monet_generator = deserialize_keras_object(config.get('monet_generator'))\n        photo_generator = deserialize_keras_object(config.get('photo_generator'))\n        monet_discriminator = deserialize_keras_object(config.get('monet_discriminator'))\n        photo_discriminator = deserialize_keras_object(config.get('photo_discriminator'))\n\n        return cls(\n            monet_generator=monet_generator,\n            photo_generator=photo_generator,\n            monet_discriminator=monet_discriminator,\n            photo_discriminator=photo_discriminator,\n            lambda_cycle=config.get('lambda_cycle', 10),\n            name=config.get('name')\n        )\n\n    def get_config(self):\n        config = super().get_config()\n        if self.m_gen is not None:\n            config['monet_generator'] = serialize_keras_object(self.m_gen)\n        if self.p_gen is not None:\n            config['photo_generator'] = serialize_keras_object(self.p_gen)\n        if self.m_disc is not None:\n            config['monet_discriminator'] = serialize_keras_object(self.m_disc)\n        if self.p_disc is not None:\n            config['photo_discriminator'] = serialize_keras_object(self.p_disc)\n        config['lambda_cycle'] = self.lambda_cycle\n        return config\n\n    def build_from_config(self, build_config):\n        \"\"\"Digunakan saat memuat model untuk membangun ulang struktur internal.\"\"\"\n        input_shape = build_config.get(\"input_shape\")\n        if input_shape is not None:\n            self.build(input_shape)\n\n    def get_build_config(self):\n        \"\"\"Mengembalikan informasi bentuk input untuk digunakan saat save/load.\"\"\"\n        return {\"input_shape\": self.input_shape}\n\n    def compile(\n        self,\n        m_gen_optimizer=None,\n        p_gen_optimizer=None,\n        m_disc_optimizer=None,\n        p_disc_optimizer=None,\n        gen_loss_fn=None,\n        disc_loss_fn=None,\n        cycle_loss_fn=None,\n        identity_loss_fn=None\n    ):\n        super().compile()\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        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    def train_step(self, batch_data):\n        raise NotImplementedError(\"train_step tidak tersedia untuk inference.\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-18T12:45:10.645851Z","iopub.execute_input":"2025-05-18T12:45:10.646404Z","iopub.status.idle":"2025-05-18T12:45:10.669762Z","shell.execute_reply.started":"2025-05-18T12:45:10.646371Z","shell.execute_reply":"2025-05-18T12:45:10.668972Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def upsample(filters, size, apply_dropout=False):\n    initializer = tf.random_normal_initializer(0., 0.02)\n\n    result = keras.Sequential()\n    result.add(layers.Conv2DTranspose(filters, size, strides=2,\n                                      padding='same',\n                                      kernel_initializer=initializer,\n                                      use_bias=False))\n\n    result.add(InstanceNormalization())\n    if apply_dropout:\n        result.add(layers.Dropout(0.5))\n\n    result.add(layers.ReLU())\n\n    return result","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-18T12:45:10.671139Z","iopub.execute_input":"2025-05-18T12:45:10.671398Z","iopub.status.idle":"2025-05-18T12:45:10.857742Z","shell.execute_reply.started":"2025-05-18T12:45:10.671376Z","shell.execute_reply":"2025-05-18T12:45:10.856820Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"OUTPUT_CHANNELS = 3\n\ndef downsample(filters, size, apply_instancenorm=True):\n    initializer = tf.random_normal_initializer(0., 0.02)\n    gamma_init = keras.initializers.RandomNormal(mean=0.0, stddev=0.02)\n\n    result = keras.Sequential()\n    result.add(layers.Conv2D(filters, size, strides=2, padding='same',\n                             kernel_initializer=initializer, use_bias=False))\n\n    if apply_instancenorm:\n        result.add(InstanceNormalization())\n\n    result.add(layers.LeakyReLU())\n\n    return result","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-18T12:45:10.858666Z","iopub.execute_input":"2025-05-18T12:45:10.859020Z","iopub.status.idle":"2025-05-18T12:45:10.879134Z","shell.execute_reply.started":"2025-05-18T12:45:10.858971Z","shell.execute_reply":"2025-05-18T12:45:10.878250Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"class InstanceNormalization(layers.Layer):\n    def __init__(self, epsilon=1e-5):\n        super(InstanceNormalization, self).__init__()\n        self.epsilon = epsilon\n\n    def build(self, input_shape):\n        self.gamma = self.add_weight(shape=(input_shape[-1],),\n                                     initializer=\"ones\",\n                                     trainable=True)\n        self.beta = self.add_weight(shape=(input_shape[-1],),\n                                    initializer=\"zeros\",\n                                    trainable=True)\n\n    def call(self, inputs):\n        mean, var = tf.nn.moments(inputs, axes=[1, 2], keepdims=True)\n        inv = tf.math.rsqrt(var + self.epsilon)\n        normalized = (inputs - mean) * inv\n        return self.gamma * normalized + self.beta","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-18T12:45:10.880216Z","iopub.execute_input":"2025-05-18T12:45:10.880703Z","iopub.status.idle":"2025-05-18T12:45:10.896369Z","shell.execute_reply.started":"2025-05-18T12:45:10.880668Z","shell.execute_reply":"2025-05-18T12:45:10.895151Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Impor dulu bagian yang dibutuhkan\n\ndef Generator():\n    inputs = layers.Input(shape=[256,256,3])\n\n    # bs = batch size\n    down_stack = [\n        downsample(64, 4, apply_instancenorm=False), # (bs, 128, 128, 64)\n        downsample(128, 4), # (bs, 64, 64, 128)\n        downsample(256, 4), # (bs, 32, 32, 256)\n        downsample(512, 4), # (bs, 16, 16, 512)\n        downsample(512, 4), # (bs, 8, 8, 512)\n        downsample(512, 4), # (bs, 4, 4, 512)\n        downsample(512, 4), # (bs, 2, 2, 512)\n        downsample(512, 4), # (bs, 1, 1, 512)\n    ]\n\n    up_stack = [\n        upsample(512, 4, apply_dropout=True), # (bs, 2, 2, 1024)\n        upsample(512, 4, apply_dropout=True), # (bs, 4, 4, 1024)\n        upsample(512, 4, apply_dropout=True), # (bs, 8, 8, 1024)\n        upsample(512, 4), # (bs, 16, 16, 1024)\n        upsample(256, 4), # (bs, 32, 32, 512)\n        upsample(128, 4), # (bs, 64, 64, 256)\n        upsample(64, 4), # (bs, 128, 128, 128)\n    ]\n\n    initializer = tf.random_normal_initializer(0., 0.02)\n    last = layers.Conv2DTranspose(OUTPUT_CHANNELS, 4,\n                                  strides=2,\n                                  padding='same',\n                                  kernel_initializer=initializer,\n                                  activation='tanh') # (bs, 256, 256, 3)\n\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 = layers.Concatenate()([x, skip])\n\n    x = last(x)\n\n    return keras.Model(inputs=inputs, outputs=x)\n\ngenerator = Generator()\ngenerator.summary()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-18T12:45:10.898286Z","iopub.execute_input":"2025-05-18T12:45:10.898532Z","iopub.status.idle":"2025-05-18T12:45:12.115207Z","shell.execute_reply.started":"2025-05-18T12:45:10.898513Z","shell.execute_reply":"2025-05-18T12:45:12.114332Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Cell 2: Load model pre-trained dari Kaggle\nmodel = tf.keras.models.load_model(\n    '/kaggle/input/monetmodel/keras/default/1/model_epoch_5.keras',\n    custom_objects={'CycleGan': CycleGan},\n    compile=False\n)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-18T12:45:12.116130Z","iopub.execute_input":"2025-05-18T12:45:12.116437Z","iopub.status.idle":"2025-05-18T12:45:26.192061Z","shell.execute_reply.started":"2025-05-18T12:45:12.116410Z","shell.execute_reply":"2025-05-18T12:45:26.191177Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"\n# Cell 3: Load data photo dari input\ndef load_image(filename):\n    # Pastikan filename bertipe string\n    filename = tf.cast(filename, tf.string)\n    \n    image = tf.io.read_file(filename)\n    image = tf.image.decode_jpeg(image, channels=3)\n    image = tf.image.resize(image, [256, 256])\n    image = (tf.cast(image, tf.float32) / 127.5) - 1  # Normalisasi ke [-1, 1]\n    return image\n\ntest_dir = '/kaggle/input/gan-getting-started/photo_jpg'\nfilenames = tf.io.gfile.glob(os.path.join(test_dir, '*.jpg'))\n\ndataset = tf.data.Dataset.from_tensor_slices(filenames)\ndataset = dataset.map(load_image, num_parallel_calls=tf.data.AUTOTUNE)\ndataset = dataset.batch(1)\n\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-18T12:45:26.192979Z","iopub.execute_input":"2025-05-18T12:45:26.193265Z","iopub.status.idle":"2025-05-18T12:45:34.102683Z","shell.execute_reply.started":"2025-05-18T12:45:26.193236Z","shell.execute_reply":"2025-05-18T12:45:34.101935Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"generator = model.m_gen  # Bisa juga 'monet_generator' tergantung nama atribut","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-18T14:16:11.548440Z","iopub.execute_input":"2025-05-18T14:16:11.548781Z","iopub.status.idle":"2025-05-18T14:16:11.554232Z","shell.execute_reply.started":"2025-05-18T14:16:11.548759Z","shell.execute_reply":"2025-05-18T14:16:11.553207Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Cell 4: Simpan hasil prediksi\nos.makedirs('images', exist_ok=True)\n\nfor i, img in enumerate(tqdm(dataset)):\n    prediction = generator(img, training=False)[0].numpy()\n    prediction = (prediction + 1.0) * 127.5  # Denormalisasi ke [0, 255]\n    prediction = np.clip(prediction, 0, 255).astype(np.uint8)\n\n    pil_img = Image.fromarray(prediction)\n    pil_img.save(f'images/pred_{i}.jpg')\n\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-18T12:45:34.103434Z","iopub.execute_input":"2025-05-18T12:45:34.103640Z","iopub.status.idle":"2025-05-18T13:19:30.201169Z","shell.execute_reply.started":"2025-05-18T12:45:34.103623Z","shell.execute_reply":"2025-05-18T13:19:30.199944Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import os\nfrom PIL import Image\nimport matplotlib.pyplot as plt\n\nimage_dir = 'images/'\nimage_files = sorted([f for f in os.listdir(image_dir) if f.endswith('.jpg')])\n\nplt.figure(figsize=(15, 15))\nfor i, filename in enumerate(image_files[:5]):  # Tampilkan 5 pertama\n    img = Image.open(os.path.join(image_dir, filename))\n    plt.subplot(1, 5, i+1)\n    plt.imshow(img)\n    plt.title(filename)\n    plt.axis('off')\nplt.tight_layout()\nplt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-18T13:55:51.541496Z","iopub.execute_input":"2025-05-18T13:55:51.541909Z","iopub.status.idle":"2025-05-18T13:55:52.328947Z","shell.execute_reply.started":"2025-05-18T13:55:51.541878Z","shell.execute_reply":"2025-05-18T13:55:52.327718Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from zipfile import ZipFile\n\n# Create ZIP file\nwith ZipFile('images.zip', 'w') as zipf:\n    for filename in os.listdir('images'):\n        zipf.write(f'images/{filename}')","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-18T13:23:44.003652Z","iopub.execute_input":"2025-05-18T13:23:44.005089Z","iopub.status.idle":"2025-05-18T13:23:45.389698Z","shell.execute_reply.started":"2025-05-18T13:23:44.005045Z","shell.execute_reply":"2025-05-18T13:23:45.388747Z"}},"outputs":[],"execution_count":null}]}