{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.8.17","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"tpu1vmV38","dataSources":[{"sourceId":10889869,"sourceType":"datasetVersion","datasetId":6767154},{"sourceId":10890083,"sourceType":"datasetVersion","datasetId":6767319}],"dockerImageVersionId":30529,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":false}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"# Dependencies","metadata":{}},{"cell_type":"code","source":"%matplotlib inline\nimport warnings\nwarnings.simplefilter(action='ignore', category=(RuntimeWarning, FutureWarning, UserWarning))\n\nimport gc\nimport time\nimport os\nimport urllib.request\nimport shutil\nimport numpy as np\nimport pandas as pd\nimport matplotlib.pyplot as plt\nfrom matplotlib.pyplot import subplots\nfrom PIL import Image\nimport pathlib\nimport tensorflow as tf\nimport keras\nfrom keras import layers, Model\nfrom keras.models import Sequential\nfrom keras.layers import Layer, Dense, Activation, Dropout, Input, concatenate, Average, Concatenate, Conv2D, Conv2DTranspose, BatchNormalization, ReLU, LeakyReLU, ZeroPadding2D, GaussianNoise\nfrom keras.optimizers import Adam\nfrom keras.utils import array_to_img\nfrom keras.callbacks import Callback\nfrom keras.initializers import RandomNormal\nfrom keras.losses import BinaryCrossentropy\n\n\nnp.random.seed(0)\ntf.random.set_seed(0)\n\nIN_COLAB = os.getenv(\"COLAB_RELEASE_TAG\") is not None\nON_KAGGLE = os.getenv(\"KAGGLE_KERNEL_RUN_TYPE\") is not None\n\nAUTOTUNE = tf.data.AUTOTUNE\n\nprint(\"tf version: \", tf.__version__)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-03-02T08:49:55.899824Z","iopub.execute_input":"2025-03-02T08:49:55.900205Z","iopub.status.idle":"2025-03-02T08:50:34.849217Z","shell.execute_reply.started":"2025-03-02T08:49:55.900172Z","shell.execute_reply":"2025-03-02T08:50:34.848332Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"url = 'https://raw.githubusercontent.com/mit-han-lab/data-efficient-gans/master/DiffAugment-stylegan2/DiffAugment_tf.py'\nfilename = 'DiffAugment_tf.py'\nurllib.request.urlretrieve(url, filename)\nimport DiffAugment_tf\n\nfunction_names = [name for name in dir(DiffAugment_tf) if callable(getattr(DiffAugment_tf, name))]\nprint(\"DiffAugment functions:\\n\", function_names)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-03-02T08:50:34.850881Z","iopub.execute_input":"2025-03-02T08:50:34.851359Z","iopub.status.idle":"2025-03-02T08:50:35.113849Z","shell.execute_reply.started":"2025-03-02T08:50:34.851334Z","shell.execute_reply":"2025-03-02T08:50:35.112751Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# MONET_DIR = pathlib.Path('/kaggle/input/something-painter-v2-512/something-painter-v2-512/monet_jpg')\n# PHOTO_DIR = pathlib.Path('/kaggle/input/something-painter-v2-512/something-painter-v2-512/photo_jpg')\nMONET_DIR = pathlib.Path('/kaggle/input/wikiart-monet-1024-v1/wikiart_monet_1024_v1')\nPHOTO_DIR = pathlib.Path('/kaggle/input/landscape-pictures-1024-v1/landscape_pictures_1024_v1')","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-03-02T08:50:35.115059Z","iopub.execute_input":"2025-03-02T08:50:35.115374Z","iopub.status.idle":"2025-03-02T08:50:35.120123Z","shell.execute_reply.started":"2025-03-02T08:50:35.115349Z","shell.execute_reply":"2025-03-02T08:50:35.119297Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"if ON_KAGGLE:\n    try:\n        tpu = tf.distribute.cluster_resolver.TPUClusterResolver.connect(tpu=\"local\")\n        strategy = tf.distribute.TPUStrategy(tpu)\n        print(\"on TPU\")\n    except tf.errors.NotFoundError:\n        print(\"not on TPU\")\n        strategy = tf.distribute.MirroredStrategy()\n\n    print(\"REPLICAS: \", strategy.num_replicas_in_sync)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-03-02T08:50:35.121139Z","iopub.execute_input":"2025-03-02T08:50:35.121386Z","iopub.status.idle":"2025-03-02T08:50:43.591995Z","shell.execute_reply.started":"2025-03-02T08:50:35.121366Z","shell.execute_reply":"2025-03-02T08:50:43.591144Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"if strategy.num_replicas_in_sync == 1:\n    BATCH_SIZE = 1  # Giảm từ 2 xuống 1\n    BUFFER_SIZE = 1024  # Tăng buffer size cho ảnh lớn hơn\nelse:\n    BATCH_SIZE_PER_REPLICA = 1\n    BATCH_SIZE = BATCH_SIZE_PER_REPLICA * strategy.num_replicas_in_sync\n    TEST_BATCH_SIZE_PER_REPLICA = 32\n    TEST_BATCH_SIZE = TEST_BATCH_SIZE_PER_REPLICA * strategy.num_replicas_in_sync","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-03-02T08:50:43.594147Z","iopub.execute_input":"2025-03-02T08:50:43.594415Z","iopub.status.idle":"2025-03-02T08:50:43.599725Z","shell.execute_reply.started":"2025-03-02T08:50:43.594389Z","shell.execute_reply":"2025-03-02T08:50:43.598812Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def decode_image(image_path):\n    shape = [1024, 1024, 3]  # Thay đổi kích thước thành 1024x1024\n    image = tf.io.read_file(image_path)\n    image = tf.image.decode_jpeg(image, channels=3)\n    image = tf.image.resize(image, [1024, 1024])\n    image = (tf.cast(image, tf.float32) / 127.5) - 1\n    image = tf.reshape(image, shape)\n    return image\n\ndef load_dataset_from_dir(directory):\n    files = tf.data.Dataset.list_files(str(directory / '*.jpg'))\n    dataset = files.map(decode_image, num_parallel_calls=AUTOTUNE)\n    return dataset\n\ndef data_augment(image):\n    image = tf.image.resize(image, [1148, 1148])  # Tăng kích thước crop để phù hợp với 1024x1024\n    image = tf.image.random_crop(image, size=[BATCH_SIZE, 1024, 1024, 3])\n    image = tf.image.random_flip_left_right(image)\n    return image","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-03-02T08:50:43.600659Z","iopub.execute_input":"2025-03-02T08:50:43.600877Z","iopub.status.idle":"2025-03-02T08:50:43.612877Z","shell.execute_reply.started":"2025-03-02T08:50:43.600856Z","shell.execute_reply":"2025-03-02T08:50:43.612227Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def prepare_gan_ds(photo_dir, monet_dir, augment_fn=None, repeat=True, shuffle=True, cache=True, batch_size=1):\n    monet_ds = load_dataset_from_dir(monet_dir)\n    photo_ds = load_dataset_from_dir(photo_dir)\n    if cache:\n        monet_ds = monet_ds.cache()\n        photo_ds = photo_ds.cache()\n    if repeat:\n        monet_ds = monet_ds.repeat()\n        photo_ds = photo_ds.repeat()\n    if shuffle:\n        monet_ds_entries = monet_ds.reduce(0, lambda x,_: x+1).numpy()\n        photo_ds_entries = photo_ds.reduce(0, lambda x,_: x+1).numpy()\n        monet_ds = monet_ds.shuffle(monet_ds_entries)\n        photo_ds = photo_ds.shuffle(photo_ds_entries)\n    monet_ds = monet_ds.batch(batch_size)\n    photo_ds = photo_ds.batch(batch_size)\n    if augment_fn:\n        monet_ds = monet_ds.map(augment_fn, num_parallel_calls=AUTOTUNE)\n        photo_ds = photo_ds.map(augment_fn, num_parallel_calls=AUTOTUNE)\n    monet_ds = monet_ds.prefetch(AUTOTUNE)\n    photo_ds = photo_ds.prefetch(AUTOTUNE)\n    gan_ds = tf.data.Dataset.zip((photo_ds, monet_ds))\n    return gan_ds","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-03-02T08:50:43.613721Z","iopub.execute_input":"2025-03-02T08:50:43.613955Z","iopub.status.idle":"2025-03-02T08:50:43.622339Z","shell.execute_reply.started":"2025-03-02T08:50:43.613934Z","shell.execute_reply":"2025-03-02T08:50:43.621676Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"train_ds = prepare_gan_ds(\n    PHOTO_DIR,\n    MONET_DIR,\n    augment_fn=data_augment,\n    repeat=True,\n    shuffle=False,\n    cache=False,\n    batch_size=BATCH_SIZE\n)\ntest_photo_ds = load_dataset_from_dir(PHOTO_DIR).batch(TEST_BATCH_SIZE).prefetch(TEST_BATCH_SIZE)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-03-02T08:50:43.623185Z","iopub.execute_input":"2025-03-02T08:50:43.623417Z","iopub.status.idle":"2025-03-02T08:50:44.262222Z","shell.execute_reply.started":"2025-03-02T08:50:43.623397Z","shell.execute_reply":"2025-03-02T08:50:44.261197Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def diffaug_fn(image):\n    return DiffAugment_tf.DiffAugment(image, \"color,translation,cutout\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-03-02T08:50:44.263350Z","iopub.execute_input":"2025-03-02T08:50:44.263633Z","iopub.status.idle":"2025-03-02T08:50:44.267899Z","shell.execute_reply.started":"2025-03-02T08:50:44.263606Z","shell.execute_reply":"2025-03-02T08:50:44.267128Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"class InstanceNormalization(tf.keras.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.scale = self.add_weight(\n            name='scale',\n            shape=input_shape[-1:],\n            initializer=tf.random_normal_initializer(1., 0.02),\n            trainable=True)\n        self.offset = self.add_weight(\n            name='offset',\n            shape=input_shape[-1:],\n            initializer='zeros',\n            trainable=True)\n\n    def call(self, x):\n        mean, variance = tf.nn.moments(x, axes=[1, 2], keepdims=True)\n        inv = tf.math.rsqrt(variance + self.epsilon)\n        normalized = (x - mean) * inv\n        return self.scale * normalized + self.offset","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-03-02T08:50:44.268845Z","iopub.execute_input":"2025-03-02T08:50:44.269122Z","iopub.status.idle":"2025-03-02T08:50:44.277614Z","shell.execute_reply.started":"2025-03-02T08:50:44.269098Z","shell.execute_reply":"2025-03-02T08:50:44.276954Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def downsample(filters, size, apply_instancenorm=True, add_noise=False):\n    initializer = tf.random_normal_initializer(0., 0.02)\n    result = keras.Sequential()\n    result.add(Conv2D(filters, size, strides=2, padding='same',\n                      kernel_initializer=initializer, use_bias=False))\n    if add_noise:\n        result.add(GaussianNoise(0.2))\n    if apply_instancenorm:\n        result.add(InstanceNormalization())\n    result.add(LeakyReLU())\n    return result\n\ndef upsample(filters, size, apply_dropout=False):\n    initializer = tf.random_normal_initializer(0., 0.02)\n    result = Sequential()\n    result.add(Conv2DTranspose(filters, size, strides=2,\n                               padding='same',\n                               kernel_initializer=initializer,\n                               use_bias=False))\n    result.add(InstanceNormalization())\n    if apply_dropout:\n        result.add(Dropout(0.5))\n    result.add(ReLU())\n    return result","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-03-02T08:50:44.278531Z","iopub.execute_input":"2025-03-02T08:50:44.278776Z","iopub.status.idle":"2025-03-02T08:50:44.289201Z","shell.execute_reply.started":"2025-03-02T08:50:44.278753Z","shell.execute_reply":"2025-03-02T08:50:44.288422Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def create_generator():\n    inputs = Input(shape=[1024, 1024, 3])  # Thay đổi input thành 1024x1024\n    output_channels = 3\n\n    down_stack = [\n        downsample(64, 4, apply_instancenorm=False),  # (bs, 512, 512, 64)\n        downsample(128, 4),  # (bs, 256, 256, 128)\n        downsample(256, 4),  # (bs, 128, 128, 256)\n        downsample(512, 4),  # (bs, 64, 64, 512)\n        downsample(512, 4),  # (bs, 32, 32, 512)\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(512, 4),  # (bs, 32, 32, 1024)\n        upsample(512, 4),  # (bs, 64, 64, 1024)\n        upsample(256, 4),  # (bs, 128, 128, 512)\n        upsample(128, 4),  # (bs, 256, 256, 256)\n        upsample(64, 4),   # (bs, 512, 512, 128)\n    ]\n    # Layer cuối cùng (last) đã tự động tạo output 1024x1024 nhờ chuỗi upsample.\n    \n    initializer = tf.random_normal_initializer(0., 0.02)\n    last = Conv2DTranspose(output_channels, 4,\n                           strides=2,\n                           padding='same',\n                           kernel_initializer=initializer,\n                           activation='tanh')  # (bs, 512, 512, 3)\n\n    x = inputs\n\n    skips = []\n    for down in down_stack:\n        x = down(x)\n        skips.append(x)\n\n    skips = reversed(skips[:-1])\n\n    for up, skip in zip(up_stack, skips):\n        x = up(x)\n        x = Concatenate()([x, skip])\n    outputs = last(x)\n    return keras.Model(inputs=inputs, outputs=outputs)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-03-02T08:50:44.290182Z","iopub.execute_input":"2025-03-02T08:50:44.290407Z","iopub.status.idle":"2025-03-02T08:50:44.299848Z","shell.execute_reply.started":"2025-03-02T08:50:44.290387Z","shell.execute_reply":"2025-03-02T08:50:44.299103Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def create_discriminator(add_noise=True):\n    initializer = tf.random_normal_initializer(0., 0.02)\n    inputs = Input(shape=[1024, 1024, 3], name='input_image')  # Thay đổi input thành 1024x1024\n    x = inputs\n    x = downsample(64, 4, False, add_noise=add_noise)(x)  # (bs, 256, 256, 64)\n    x = downsample(128, 4, add_noise=add_noise)(x)  # (bs, 128, 128, 128)\n    x = downsample(256, 4, add_noise=add_noise)(x)  # (bs, 64, 64, 256)\n    x = downsample(512, 4, add_noise=add_noise)(x)  # (bs, 32, 32, 512)\n    x = ZeroPadding2D()(x)  # (bs, 34, 34, 512)\n    x = Conv2D(512, 4, strides=1,\n               kernel_initializer=initializer,\n               use_bias=False)(x)  # (bs, 31, 31, 512)\n    if add_noise:\n        x = GaussianNoise(0.2)(x)\n    x = InstanceNormalization()(x)\n    x = LeakyReLU()(x)\n    x = ZeroPadding2D()(x)  # (bs, 33, 33, 512)\n    outputs = Conv2D(1, 4, strides=1,\n                     kernel_initializer=initializer)(x)  # (bs, 30, 30, 1)\n    return tf.keras.Model(inputs=inputs, outputs=outputs)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-03-02T08:50:44.300643Z","iopub.execute_input":"2025-03-02T08:50:44.300852Z","iopub.status.idle":"2025-03-02T08:50:44.311700Z","shell.execute_reply.started":"2025-03-02T08:50:44.300833Z","shell.execute_reply":"2025-03-02T08:50:44.311040Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"class TrainingGAN(Model):\n    def __init__(self, generator_g, discriminator_x, generator_f, discriminator_y,\n                 lambda_loss=10, gamma_loss=1e-4, lambda_id_loss=1e-5, diffaug_fn=None, batch_size=32, **kwargs):\n        super().__init__(**kwargs)\n        self.generator_g = generator_g\n        self.generator_f = generator_f\n        self.discriminator_x = discriminator_x\n        self.discriminator_y = discriminator_y\n        self.lambda_loss = lambda_loss\n        self.gamma_loss = gamma_loss\n        self.lambda_id_loss = lambda_id_loss\n        self.diffaug_fn = diffaug_fn\n        disc_inputs = Input(shape=[None, None, 3], name='input_image')\n        self.discriminator_features_x = Model(inputs=self.discriminator_x.input,\n                                              outputs=self.discriminator_x.layers[-2].output)\n        self.discriminator_features_y = Model(inputs=self.discriminator_y.input,\n                                              outputs=self.discriminator_y.layers[-2].output)\n\n    def compile(self, generator_g_optimizer, discriminator_x_optimizer,\n                generator_f_optimizer, discriminator_y_optimizer):\n        super().compile()\n        self.generator_g_optimizer = generator_g_optimizer\n        self.discriminator_x_optimizer = discriminator_x_optimizer\n        self.generator_f_optimizer = generator_f_optimizer\n        self.discriminator_y_optimizer = discriminator_y_optimizer\n\n    def _discriminator_bce_loss(self, real, generated):\n        real_loss = BinaryCrossentropy(\n            from_logits=True,\n            reduction=tf.keras.losses.Reduction.NONE)(tf.ones_like(real), real)\n        real_loss = tf.reduce_mean(real_loss)\n        generated_loss = BinaryCrossentropy(\n            from_logits=True,\n            reduction=tf.keras.losses.Reduction.NONE)(tf.zeros_like(generated), generated)\n        generated_loss = tf.reduce_mean(generated_loss)\n        total_disc_loss = real_loss + generated_loss\n        return total_disc_loss * 0.5\n\n    def _generator_bce_loss(self, generated):\n        loss = BinaryCrossentropy(\n            from_logits=True,\n            reduction=tf.keras.losses.Reduction.NONE)(tf.ones_like(generated), generated)\n        loss = tf.reduce_mean(loss)\n        return loss\n\n    def _cycle_loss(self, real_image, cycled_image):\n        loss = tf.reduce_mean(tf.abs(real_image - cycled_image))\n        return loss\n\n    def _identity_loss(self, real_image, same_image):\n        loss = tf.reduce_mean(tf.abs(real_image - same_image))\n        return 0.5 * loss\n\n    @tf.function\n    def train_step(self, batch):\n        (real_x, real_y) = batch\n        batch_size = tf.shape(real_y)[0]\n        with tf.GradientTape(persistent=True) as tape:\n            fake_y = self.generator_g(real_x, training=True)\n            cycled_x = self.generator_f(fake_y, training=True)\n            fake_x = self.generator_f(real_y, training=True)\n            cycled_y = self.generator_g(fake_x, training=True)\n            same_x = self.generator_f(real_x, training=True)\n            same_y = self.generator_g(real_y, training=True)\n\n            if self.diffaug_fn:\n                both_y = tf.concat([real_y, fake_y], axis=0)\n                aug_y = self.diffaug_fn(both_y)\n                aug_real_y = aug_y[:batch_size]\n                aug_fake_y = aug_y[batch_size:]\n                disc_real_y = self.discriminator_y(aug_real_y, training=True)\n                disc_fake_y = self.discriminator_y(aug_fake_y, training=True)\n            else:\n                disc_real_y = self.discriminator_y(real_y, training=True)\n                disc_fake_y = self.discriminator_y(fake_y, training=True)\n\n            disc_real_x = self.discriminator_x(real_x, training=True)\n            disc_fake_x = self.discriminator_x(fake_x, training=True)\n\n            disc_feat_x = self.discriminator_features_x(real_x, training=True)\n            disc_feat_cycled_x = self.discriminator_features_x(cycled_x, training=True)\n            disc_feat_y = self.discriminator_features_x(real_y, training=True)\n            disc_feat_cycled_y = self.discriminator_features_x(cycled_y, training=True)\n\n            gen_g_loss = self._generator_bce_loss(disc_fake_y)\n            gen_f_loss = self._generator_bce_loss(disc_fake_x)\n            cycle_loss_x = ((1 - self.gamma_loss) * self._cycle_loss(real_x, cycled_x) +\n                            self.gamma_loss * self._cycle_loss(disc_feat_x, disc_feat_cycled_x))\n            cycle_loss_y = ((1 - self.gamma_loss) *  self._cycle_loss(real_y, cycled_y) +\n                            self.gamma_loss * self._cycle_loss(disc_feat_y, disc_feat_cycled_y))\n            total_cycle_loss = self.lambda_loss * (cycle_loss_x + cycle_loss_y)\n            id_loss_y = self.lambda_id_loss * self._identity_loss(real_y, same_y)\n            id_loss_x = self.lambda_id_loss * self._identity_loss(real_x, same_x)\n            total_gen_g_loss = gen_g_loss + total_cycle_loss + id_loss_y\n            total_gen_f_loss = gen_f_loss + total_cycle_loss + id_loss_x\n\n            disc_x_loss = self._discriminator_bce_loss(disc_real_x, disc_fake_x)\n            disc_y_loss = self._discriminator_bce_loss(disc_real_y, disc_fake_y)\n\n        generator_g_gradients = tape.gradient(total_gen_g_loss, self.generator_g.trainable_variables)\n        generator_f_gradients = tape.gradient(total_gen_f_loss, self.generator_f.trainable_variables)\n        discriminator_x_gradients = tape.gradient(disc_x_loss, self.discriminator_x.trainable_variables)\n        discriminator_y_gradients = tape.gradient(disc_y_loss, self.discriminator_y.trainable_variables)\n\n        self.generator_g_optimizer.apply_gradients(zip(generator_g_gradients, self.generator_g.trainable_variables))\n        self.generator_f_optimizer.apply_gradients(zip(generator_f_gradients, self.generator_f.trainable_variables))\n        self.discriminator_x_optimizer.apply_gradients(zip(discriminator_x_gradients, self.discriminator_x.trainable_variables))\n        self.discriminator_y_optimizer.apply_gradients(zip(discriminator_y_gradients, self.discriminator_y.trainable_variables))\n\n        return {\n            \"disc_x_loss\": disc_x_loss,\n            \"disc_y_loss\": disc_y_loss,\n            \"total_gen_g_loss\": total_gen_g_loss,\n            \"total_gen_f_loss\": total_gen_f_loss,\n            \"gen_g_loss\": cycle_loss_x,\n            \"gen_f_loss\": cycle_loss_y,\n            }","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-03-02T08:50:44.315066Z","iopub.execute_input":"2025-03-02T08:50:44.315293Z","iopub.status.idle":"2025-03-02T08:50:44.338342Z","shell.execute_reply.started":"2025-03-02T08:50:44.315273Z","shell.execute_reply":"2025-03-02T08:50:44.337568Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"class PlotPredictionsCallback(keras.callbacks.Callback):\n    def __init__(self, input_image, model_generator, epoch_interval=None, nrows=1, figsize=(11, 11)):\n        self.input_image = input_image\n        self.model_generator = model_generator\n        self.epoch_interval = epoch_interval\n        self.nrows = nrows\n        self.figsize=(11, 11)\n\n    def _plot_test_and_pred(self):\n        preds = self.model_generator.predict(self.input_image, verbose=0)\n        (fig, axes) = subplots(nrows=self.nrows, ncols=2, figsize=self.figsize)\n        if self.nrows == 1:\n            axes = [axes]\n        for (ax, inp, pred) in zip(axes, self.input_image, preds):\n            ax[0].imshow(array_to_img(inp))\n            ax[0].set_title(\"Input Image\")\n            ax[0].set_axis_off()\n            ax[1].imshow(array_to_img(pred))\n            ax[1].set_title(\"Prediction\")\n            ax[1].set_axis_off()\n        plt.show()\n\n    def on_epoch_end(self, epoch, logs=None):\n        if self.epoch_interval and epoch % self.epoch_interval == 0:\n            self._plot_test_and_pred()\n\n    def on_train_end(self, logs=None):\n        self._plot_test_and_pred()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-03-02T08:50:44.339209Z","iopub.execute_input":"2025-03-02T08:50:44.339452Z","iopub.status.idle":"2025-03-02T08:50:44.348843Z","shell.execute_reply.started":"2025-03-02T08:50:44.339430Z","shell.execute_reply":"2025-03-02T08:50:44.348110Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"class FIDCalculator(object):\n    def __init__(self, images_x_ds, images_y_ds, model_generator, fid_model_base):\n        self.images_x_ds = images_x_ds\n        self.images_y_ds = images_y_ds\n        self.model_generator = model_generator\n        self.fid_model_base = fid_model_base\n        self.initialized = False\n        self.history = []\n\n    def init_stat_x(self):\n        self.mu_2, self.sigma_2 = self._calculate_activation_statistics_mod(self.images_y_ds, self.fid_model_base)\n        self.initialized = True\n\n    def _calculate_activation_statistics_mod(self, images, fid_model):\n        act = tf.cast(fid_model.predict(images, verbose=0), tf.float32)\n        mu = tf.reduce_mean(act, axis=0)\n        mean_x = tf.reduce_mean(act, axis=0, keepdims=True)\n        mx = tf.matmul(tf.transpose(mean_x), mean_x)\n        vx = tf.matmul(tf.transpose(act), act)/tf.cast(tf.shape(act)[0], tf.float32)\n        sigma = vx - mx\n        return mu, sigma\n\n    def _calculate_frechet_distance(self, mu_1, sigma_1, mu_2, sigma_2):\n        fid_epsilon = 1e-14\n        covmean = tf.linalg.sqrtm(tf.cast(tf.matmul(sigma_1, sigma_2), tf.complex64))\n        covmean = tf.cast(tf.math.real(covmean), tf.float32)\n        tr_covmean = tf.linalg.trace(covmean)\n        fid_value = tf.matmul(\n            tf.expand_dims(mu_1 - mu_2, axis=0),\n            tf.expand_dims(mu_1 - mu_2, axis=1)\n            ) + tf.linalg.trace(sigma_1) + tf.linalg.trace(sigma_2) - 2 * tr_covmean\n        return fid_value\n\n    def _get_gen_plus_fid_model(self):\n        inputs = layers.Input(shape=[1024, 1024, 3], name='input_image')  # Thay đổi input thành 1024x1024\n        x = self.model_generator(inputs)\n        outputs = self.fid_model_base(x)\n        fid_model = tf.keras.Model(inputs=inputs, outputs=outputs)\n        return fid_model\n\n    def calc_fid(self):\n        if not self.initialized:\n            self.init_stat_x()\n        fid_model_plus = self._get_gen_plus_fid_model()\n        mu_1, sigma_1 = self._calculate_activation_statistics_mod(self.images_x_ds, fid_model_plus)\n        fid_value = self._calculate_frechet_distance(mu_1, sigma_1, self.mu_2, self.sigma_2)\n        return fid_value","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-03-02T08:50:44.349796Z","iopub.execute_input":"2025-03-02T08:50:44.350090Z","iopub.status.idle":"2025-03-02T08:50:44.361397Z","shell.execute_reply.started":"2025-03-02T08:50:44.350067Z","shell.execute_reply":"2025-03-02T08:50:44.360693Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def create_fid_inception_model():\n    inception_model_base = tf.keras.applications.InceptionV3(\n        input_shape=(1024, 1024, 3),  # Thay đổi input thành 1024x1024\n        pooling=\"avg\",\n        include_top=False)\n    mix3  = inception_model_base.get_layer(\"mixed9\").output\n    f0 = tf.keras.layers.GlobalAveragePooling2D()(mix3)\n    inception_model = tf.keras.Model(inputs=inception_model_base.input, outputs=f0)\n    inception_model.trainable = False\n    return inception_model","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-03-02T08:50:44.362259Z","iopub.execute_input":"2025-03-02T08:50:44.362481Z","iopub.status.idle":"2025-03-02T08:50:44.371292Z","shell.execute_reply.started":"2025-03-02T08:50:44.362461Z","shell.execute_reply":"2025-03-02T08:50:44.370592Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"class FIDCallback(Callback):\n    def __init__(self, fid_calculator, epoch_interval=None):\n        self.fid_calculator = fid_calculator\n        self.epoch_interval = epoch_interval\n\n    def _get_fid(self):\n        fid = self.fid_calculator.calc_fid()\n        print(\"FID score:\", fid.numpy()[0,0])\n\n    def on_epoch_end(self, epoch, logs=None):\n        if self.epoch_interval and epoch % self.epoch_interval == 0:\n            self._get_fid()\n\n    def on_train_end(self, logs=None):\n        self._get_fid()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-03-02T08:50:44.372068Z","iopub.execute_input":"2025-03-02T08:50:44.372317Z","iopub.status.idle":"2025-03-02T08:50:44.379705Z","shell.execute_reply.started":"2025-03-02T08:50:44.372297Z","shell.execute_reply":"2025-03-02T08:50:44.378969Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"class UpdateLearningRateCallback(Callback):\n    def __init__(self, epochs_count, lr_start=2e-4, lr_end=5e-6):\n        super().__init__()\n        self.epoch_min = epochs_count // 2\n        epochs_update_count = epochs_count - self.epoch_min\n        self.lr_values = np.linspace(lr_start, lr_end, epochs_update_count)\n\n    def _scheduler_fn(self, epoch, lr):\n        if epoch < self.epoch_min:\n            return lr\n        else:\n            return self.lr_values[epoch-self.epoch_min]\n\n    def on_epoch_begin(self, epoch, logs=None):\n        self.model.generator_g_optimizer.lr = self._scheduler_fn(epoch, self.model.generator_g_optimizer.lr)\n        self.model.discriminator_x_optimizer.lr = self._scheduler_fn(epoch, self.model.generator_g_optimizer.lr)\n        self.model.generator_f_optimizer.lr = self._scheduler_fn(epoch, self.model.generator_g_optimizer.lr)\n        self.model.discriminator_y_optimizer.lr = self._scheduler_fn(epoch, self.model.generator_g_optimizer.lr)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-03-02T08:50:44.380580Z","iopub.execute_input":"2025-03-02T08:50:44.380798Z","iopub.status.idle":"2025-03-02T08:50:44.390067Z","shell.execute_reply.started":"2025-03-02T08:50:44.380779Z","shell.execute_reply":"2025-03-02T08:50:44.389317Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"class UpdateLossWeightsCallback(Callback):\n    def __init__(self, epochs, lambda_start=10, lambda_end=1e-4, gamma_start=1e-4, gamma_end=0.999):\n        super().__init__()\n        self.epochs = epochs\n        self.lambda_start = lambda_start\n        self.lambda_end = lambda_end\n        self.gamma_start = gamma_start\n        self.gamma_end = gamma_end\n\n    def on_train_begin(self, logs=None):\n        self.lambda_values = np.linspace(self.lambda_start, self.lambda_end, self.epochs)\n        self.gamma_values = np.linspace(self.gamma_start, self.gamma_end, self.epochs)\n\n    def on_epoch_begin(self, epoch, logs=None):\n        self.model.lambda_loss = self.lambda_values[epoch]\n        self.model.gamma_loss = self.gamma_values[epoch]","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-03-02T08:50:44.390859Z","iopub.execute_input":"2025-03-02T08:50:44.391118Z","iopub.status.idle":"2025-03-02T08:50:44.399036Z","shell.execute_reply.started":"2025-03-02T08:50:44.391086Z","shell.execute_reply":"2025-03-02T08:50:44.398261Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"EPOCHS = 20  # Giảm từ 20 để tổng thời gian khoảng 6 giờ với 1000 step/epoch\nSTEPS_PER_EPOCH = 1000  # Giảm từ 3000 để mỗi epoch khoảng 25 phút\nLAMBDA_START = 5  # Tăng nhẹ từ 3 để ưu tiên cycle consistency\nLAMBDA_END = 1e-4  # Giữ nguyên\nGAMMA_START = 1e-4  # Giữ nguyên\nGAMMA_END = 0.999  # Giữ nguyên\nLAMBDA_ID = 1e-4  # Giữ nguyên\nEPOCH_INTERVAL_PLOT = 2  # Giảm từ 5 để xem kết quả thường xuyên hơn\nEPOCH_INTERVAL_FID = None  # Giữ nguyên (hoặc 5 nếu muốn tính FID)\nLR_START = 2e-4  # Giữ nguyên\nLR_END = 5e-6  # Giữ nguyên","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-03-02T08:50:44.399924Z","iopub.execute_input":"2025-03-02T08:50:44.400153Z","iopub.status.idle":"2025-03-02T08:50:44.409003Z","shell.execute_reply.started":"2025-03-02T08:50:44.400134Z","shell.execute_reply":"2025-03-02T08:50:44.408246Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"with strategy.scope():\n    update_lr_cb = UpdateLearningRateCallback(EPOCHS, lr_start=LR_START, lr_end=LR_END)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-03-02T08:50:44.409880Z","iopub.execute_input":"2025-03-02T08:50:44.410136Z","iopub.status.idle":"2025-03-02T08:50:44.417762Z","shell.execute_reply.started":"2025-03-02T08:50:44.410116Z","shell.execute_reply":"2025-03-02T08:50:44.417087Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"with strategy.scope():\n    generator_g = create_generator()\n    generator_f = create_generator()\n    discriminator_x = create_discriminator(add_noise=True)\n    discriminator_y = create_discriminator(add_noise=True)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-03-02T08:50:44.418735Z","iopub.execute_input":"2025-03-02T08:50:44.419030Z","iopub.status.idle":"2025-03-02T08:51:09.454710Z","shell.execute_reply.started":"2025-03-02T08:50:44.419004Z","shell.execute_reply":"2025-03-02T08:51:09.453570Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"generator_g.summary()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-03-02T08:51:09.455727Z","iopub.execute_input":"2025-03-02T08:51:09.456023Z","iopub.status.idle":"2025-03-02T08:51:09.510702Z","shell.execute_reply.started":"2025-03-02T08:51:09.455997Z","shell.execute_reply":"2025-03-02T08:51:09.509872Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"discriminator_x.summary()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-03-02T08:51:09.511726Z","iopub.execute_input":"2025-03-02T08:51:09.512022Z","iopub.status.idle":"2025-03-02T08:51:09.537474Z","shell.execute_reply.started":"2025-03-02T08:51:09.511996Z","shell.execute_reply":"2025-03-02T08:51:09.536797Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"plot_pred_photo = next(iter(test_photo_ds.take(1)))\nplot_pred_photo = np.expand_dims(plot_pred_photo[0], axis=0)\nwith strategy.scope():\n    plot_pred_cb = PlotPredictionsCallback(\n        input_image=plot_pred_photo,\n        model_generator=generator_g,\n        epoch_interval=EPOCH_INTERVAL_PLOT)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-03-02T08:51:09.538295Z","iopub.execute_input":"2025-03-02T08:51:09.538515Z","iopub.status.idle":"2025-03-02T08:51:10.262421Z","shell.execute_reply.started":"2025-03-02T08:51:09.538495Z","shell.execute_reply":"2025-03-02T08:51:10.261272Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"fid_photo_ds = load_dataset_from_dir(PHOTO_DIR).take(1024).batch(64).prefetch(AUTOTUNE)\nfid_monet_ds = load_dataset_from_dir(MONET_DIR).batch(64).prefetch(AUTOTUNE)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-03-02T08:51:10.263707Z","iopub.execute_input":"2025-03-02T08:51:10.264089Z","iopub.status.idle":"2025-03-02T08:51:10.455902Z","shell.execute_reply.started":"2025-03-02T08:51:10.264057Z","shell.execute_reply":"2025-03-02T08:51:10.454643Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"with strategy.scope():\n    fid_model = create_fid_inception_model()\n    fid_calc = FIDCalculator(\n        images_x_ds=fid_photo_ds,\n        images_y_ds=fid_monet_ds,\n        model_generator=generator_g,\n        fid_model_base=fid_model)\n    fid_calc.init_stat_x()\n    fid_cb = FIDCallback(fid_calculator=fid_calc, epoch_interval=EPOCH_INTERVAL_FID)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-03-02T08:51:10.457187Z","iopub.execute_input":"2025-03-02T08:51:10.457502Z","iopub.status.idle":"2025-03-02T08:52:47.002815Z","shell.execute_reply.started":"2025-03-02T08:51:10.457474Z","shell.execute_reply":"2025-03-02T08:52:47.001410Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"with strategy.scope():\n    update_weights_cb = UpdateLossWeightsCallback(\n        EPOCHS,\n        lambda_start=LAMBDA_START,\n        lambda_end=LAMBDA_END,\n        gamma_start=GAMMA_START,\n        gamma_end=GAMMA_END)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-03-02T08:52:47.004219Z","iopub.execute_input":"2025-03-02T08:52:47.004509Z","iopub.status.idle":"2025-03-02T08:52:47.009614Z","shell.execute_reply.started":"2025-03-02T08:52:47.004485Z","shell.execute_reply":"2025-03-02T08:52:47.008668Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"with strategy.scope():\n    model_cycleGAN = TrainingGAN(\n        generator_g=generator_g,\n        generator_f=generator_f,\n        discriminator_x=discriminator_x,\n        discriminator_y=discriminator_y,\n        lambda_loss=LAMBDA_START,\n        lambda_id_loss=LAMBDA_ID,\n        gamma_loss=GAMMA_START,\n        diffaug_fn=diffaug_fn\n    )\n    generator_g_optimizer = Adam(learning_rate=LR_START, beta_1=0.5)\n    discriminator_x_optimizer = Adam(learning_rate=LR_START, beta_1=0.5)\n    generator_f_optimizer = Adam(learning_rate=LR_START, beta_1=0.5)\n    discriminator_y_optimizer = Adam(learning_rate=LR_START, beta_1=0.5)\n\n    model_cycleGAN.compile(\n        generator_g_optimizer=generator_g_optimizer,\n        discriminator_x_optimizer=discriminator_x_optimizer,\n        generator_f_optimizer=generator_f_optimizer,\n        discriminator_y_optimizer=discriminator_y_optimizer,\n    )","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-03-02T08:52:47.010751Z","iopub.execute_input":"2025-03-02T08:52:47.011050Z","iopub.status.idle":"2025-03-02T08:52:47.237193Z","shell.execute_reply.started":"2025-03-02T08:52:47.011023Z","shell.execute_reply":"2025-03-02T08:52:47.236196Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"%%time\nhistory = model_cycleGAN.fit(\n    train_ds,\n    epochs=EPOCHS,\n    callbacks=[plot_pred_cb, fid_cb, update_weights_cb, update_lr_cb],\n    steps_per_epoch=STEPS_PER_EPOCH\n)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-03-02T08:52:47.238270Z","iopub.execute_input":"2025-03-02T08:52:47.238530Z","iopub.status.idle":"2025-03-02T15:27:27.224740Z","shell.execute_reply.started":"2025-03-02T08:52:47.238507Z","shell.execute_reply":"2025-03-02T15:27:27.223409Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"generator_g.save('/kaggle/working/generator_g_trained_model.h5')\ndiscriminator_x.save('/kaggle/working/discriminator_x_trained_model.h5')\ngenerator_f.save('/kaggle/working/generator_f_trained_model.h5')\ndiscriminator_y.save('/kaggle/working/discriminator_y_trained_model.h5')","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-03-02T15:27:27.226740Z","iopub.execute_input":"2025-03-02T15:27:27.227133Z","iopub.status.idle":"2025-03-02T15:27:28.757439Z","shell.execute_reply.started":"2025-03-02T15:27:27.227101Z","shell.execute_reply":"2025-03-02T15:27:28.756005Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# Manual Download file in working kaggle ","metadata":{}},{"cell_type":"code","source":"!cd /kaggle/working\n!ls\nfrom IPython.display import FileLink\nFileLink(r'discriminator_y_trained_model.h5')","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"print(np.array(list(history.history.values())).shape)","metadata":{"trusted":true,"execution":{"execution_failed":"2025-03-02T15:30:23.289Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import numpy as np\nimport matplotlib.pyplot as plt\n\n# Chuyển đổi từ history.history sang numpy array\nloss_values = np.array(list(history.history.values()))\nepochs = np.arange(1, len(loss_values[0]) + 1)  # Số epoch\n\n# Các tên loss\nloss_names = list(history.history.keys())\n\n# Vẽ biểu đồ đường\nplt.figure(figsize=(18, 6))  # Chiều ngang lớn hơn\n\nfor i in range(len(loss_names)):\n    plt.plot(epochs, loss_values[i], marker='o', linestyle='-', label=loss_names[i])\n\nplt.xlabel(\"Epochs\")\nplt.ylabel(\"Loss\")\nplt.title(\"Training Loss over Epochs\")\nplt.legend(loc='upper right')  # Đưa chú thích lên góc trên bên phải\nplt.grid(True)\nplt.show()\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-03-02T15:27:28.766106Z","iopub.execute_input":"2025-03-02T15:27:28.766370Z","iopub.status.idle":"2025-03-02T15:27:29.092630Z","shell.execute_reply.started":"2025-03-02T15:27:28.766347Z","shell.execute_reply":"2025-03-02T15:27:29.091335Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import numpy as np\nimport matplotlib.pyplot as plt\n\n# Chuyển đổi từ history.history sang numpy array\nloss_values = np.array(list(history.history.values()))\nepochs = np.arange(1, len(loss_values[0]) + 1)  # Số epoch\n\n# Các tên loss\nloss_names = list(history.history.keys())\n\n# Vẽ biểu đồ đường\nplt.figure(figsize=(18, 6))  # Chiều ngang lớn hơn\n\nfor i in range(len(loss_names)):\n    plt.plot(epochs, loss_values[i], linestyle='-', label=loss_names[i])  # Xóa marker='o'\n\nplt.xlabel(\"Epochs\")\nplt.ylabel(\"Loss\")\nplt.title(\"Training Loss over Epochs\")\nplt.legend(loc='upper right')  # Đưa chú thích lên góc trên bên phải\nplt.grid(False)  # Tắt lưới\nplt.show()\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-03-02T15:27:29.094008Z","iopub.execute_input":"2025-03-02T15:27:29.094333Z","iopub.status.idle":"2025-03-02T15:27:29.404873Z","shell.execute_reply.started":"2025-03-02T15:27:29.094308Z","shell.execute_reply":"2025-03-02T15:27:29.403657Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import matplotlib.pyplot as plt\n\ndef plot_predictions(model, ds):\n    ds_iter = iter(ds)  # Tạo iterator từ dataset\n    num_samples = sum(1 for _ in ds)  # Đếm số lượng phần tử trong dataset\n    num_iter = min(8, num_samples)  # Giới hạn số lần lặp trong phạm vi hợp lệ\n\n    for n_sample in range(num_iter):\n        try:\n            example_sample = next(ds_iter)  # Lấy một mẫu từ dataset\n            generated_sample = model.predict(example_sample, verbose=0)\n\n            f = plt.figure(figsize=(13, 13))\n            plt.subplot(121)\n            plt.title('Input image')\n            plt.imshow(example_sample[0] * 0.5 + 0.5)\n            plt.axis('off')\n\n            plt.subplot(122)\n            plt.title('Generated image')\n            plt.imshow(generated_sample[0] * 0.5 + 0.5)\n            plt.axis('off')\n\n            plt.show()\n        except StopIteration:\n            print(\"Hết dữ liệu để hiển thị!\")\n            break","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-03-02T15:27:29.406120Z","iopub.execute_input":"2025-03-02T15:27:29.406410Z","iopub.status.idle":"2025-03-02T15:27:29.415688Z","shell.execute_reply.started":"2025-03-02T15:27:29.406385Z","shell.execute_reply":"2025-03-02T15:27:29.414683Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"plot_predictions(generator_g, test_photo_ds.shuffle(1000))","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-03-02T15:27:29.416706Z","iopub.execute_input":"2025-03-02T15:27:29.416959Z","execution_failed":"2025-03-02T15:30:23.288Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def generate_and_save(generator, ds):\n    count = 0\n    if os.path.exists('images.zip'):\n        os.remove('images.zip')\n    with zipfile.ZipFile('images.zip', 'w') as zipf:\n        for images_batch in ds:\n            predictions = generator(images_batch, training=False)\n            for pred in predictions:\n                count += 1\n                generated_image = array_to_img(pred)\n                generated_image_bytes = BytesIO()\n                generated_image.save(generated_image_bytes, format='JPEG')\n                generated_image_bytes.seek(0)\n                zipf.writestr(f'generated_image_{count}.jpg', generated_image_bytes.getvalue())\n                if count % 1024 == 0:\n                    print(f'Archived images: {count}')","metadata":{"trusted":true,"execution":{"execution_failed":"2025-03-02T15:30:23.288Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"%%time\ngenerate_and_save(generator_g, test_photo_ds)","metadata":{"trusted":true,"execution":{"execution_failed":"2025-03-02T15:30:23.288Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"[Paper: Unpaired Image-to-Image Translation using Cycle-Consistent Adversarial Networks](https://arxiv.org/abs/1703.10593)\n\n[Paper: CycleGAN with Better Cycles](https://www.tongzhouwang.info/better_cycles/report.pdf)\n\n[Paper: Improved Techniques for Training GANs](https://arxiv.org/abs/1606.03498)\n\n[Paper: Differentiable Augmentation for Data-Efficient GAN Training](https://arxiv.org/abs/2006.10738)\n\n[GitHub: Transforming the World Into Paintings with CycleGAN](https://github.com/sebtheiler/tutorials/tree/main/cyclegan)\n\n[Article: pix2pix: Image-to-image translation with a conditional GAN](https://www.tensorflow.org/tutorials/generative/pix2pix)\n\n[Notebook: Two-objective discriminator by UnfriendlyAI](https://www.kaggle.com/code/unfriendlyai/two-objective-discriminator)","metadata":{"id":"2SX6LFWPMRgP"}}]}