{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"pygments_lexer":"ipython3","nbconvert_exporter":"python","version":"3.6.4","file_extension":".py","codemirror_mode":{"name":"ipython","version":3},"name":"python","mimetype":"text/x-python"}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"!pip install git+https://www.github.com/keras-team/keras-contrib.git","metadata":{"execution":{"iopub.status.busy":"2022-09-17T08:07:09.035676Z","iopub.execute_input":"2022-09-17T08:07:09.036601Z","iopub.status.idle":"2022-09-17T08:07:31.087464Z","shell.execute_reply.started":"2022-09-17T08:07:09.036556Z","shell.execute_reply":"2022-09-17T08:07:31.085728Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import os\nimport sys\n\nfrom pathlib import Path\n\nimport pandas as pd\nimport numpy as np\nfrom PIL import Image\nfrom datetime import datetime\nfrom tqdm.notebook import tqdm\n\nimport tensorflow as tf\nfrom tensorflow.keras.preprocessing.image import ImageDataGenerator, save_img\nimport keras\nfrom tensorflow.keras import layers\nfrom keras_contrib.layers.normalization.instancenormalization import InstanceNormalization\nfrom keras.layers import Dense, Conv2D, UpSampling2D, ReLU, LeakyReLU, Input, Concatenate, Activation, Add, Conv2DTranspose\nfrom keras.initializers import RandomNormal\nfrom keras import Model\nfrom tensorflow.keras.optimizers import Adam, SGD\nfrom tensorflow.keras.optimizers.schedules import ExponentialDecay\nfrom tensorflow.keras.losses import BinaryCrossentropy\n\nimport matplotlib.pyplot as plt\nimport seaborn as sb\n\n%matplotlib inline\n\npd.set_option('display.max_rows', None, 'display.max_columns', None)","metadata":{"execution":{"iopub.status.busy":"2022-09-17T08:07:31.090184Z","iopub.execute_input":"2022-09-17T08:07:31.090687Z","iopub.status.idle":"2022-09-17T08:07:38.738039Z","shell.execute_reply.started":"2022-09-17T08:07:31.090630Z","shell.execute_reply":"2022-09-17T08:07:38.736642Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# try:\n#     tpu = tf.distribute.cluster_resolver.TPUClusterResolver()\n#     print('Device:', tpu.master())\n#     tf.config.experimental_connect_to_cluster(tpu)\n#     tf.tpu.experimental.initialize_tpu_system(tpu)\n#     strategy = tf.distribute.experimental.TPUStrategy(tpu)\n# except:\n#     strategy = tf.distribute.get_strategy()\n# print('Number of replicas:', strategy.num_replicas_in_sync)\n\n# AUTOTUNE = tf.data.experimental.AUTOTUNE\n    \n# print(tf.__version__)","metadata":{"execution":{"iopub.status.busy":"2022-09-17T08:07:38.742168Z","iopub.execute_input":"2022-09-17T08:07:38.743023Z","iopub.status.idle":"2022-09-17T08:07:38.757991Z","shell.execute_reply.started":"2022-09-17T08:07:38.742976Z","shell.execute_reply":"2022-09-17T08:07:38.756182Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"!mkdir tmp\n!mkdir output","metadata":{"execution":{"iopub.status.busy":"2022-09-17T08:07:38.760564Z","iopub.execute_input":"2022-09-17T08:07:38.761637Z","iopub.status.idle":"2022-09-17T08:07:41.363826Z","shell.execute_reply.started":"2022-09-17T08:07:38.761573Z","shell.execute_reply":"2022-09-17T08:07:41.362086Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"src_folder = Path('/kaggle/input/gan-getting-started')\ntmp_folder = Path('.') / 'tmp'\noutput_folder = Path('.') / 'output'","metadata":{"execution":{"iopub.status.busy":"2022-09-17T08:07:41.366871Z","iopub.execute_input":"2022-09-17T08:07:41.367432Z","iopub.status.idle":"2022-09-17T08:07:41.376000Z","shell.execute_reply.started":"2022-09-17T08:07:41.367360Z","shell.execute_reply":"2022-09-17T08:07:41.374235Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"IMAGE_SHAPE = (256, 256)","metadata":{"execution":{"iopub.status.busy":"2022-09-17T08:07:41.378557Z","iopub.execute_input":"2022-09-17T08:07:41.379120Z","iopub.status.idle":"2022-09-17T08:07:41.390999Z","shell.execute_reply.started":"2022-09-17T08:07:41.379077Z","shell.execute_reply":"2022-09-17T08:07:41.389297Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"monet_recs = list((src_folder / 'monet_tfrec').rglob('*.tfrec'))\nphoto_recs = list((src_folder / 'photo_tfrec').rglob('*.tfrec'))\nprint(len(monet_recs), len(photo_recs))","metadata":{"execution":{"iopub.status.busy":"2022-09-17T08:07:41.393684Z","iopub.execute_input":"2022-09-17T08:07:41.394279Z","iopub.status.idle":"2022-09-17T08:07:41.422825Z","shell.execute_reply.started":"2022-09-17T08:07:41.394236Z","shell.execute_reply":"2022-09-17T08:07:41.421452Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"class TFRecDataLoader:\n    def __init__(self, src_folder, batch_size=1, num_batches_per_epoch=10):\n        self.batch_size = batch_size\n        self.num_batches_per_epoch = num_batches_per_epoch\n        self.monet_recs = list((src_folder / 'monet_tfrec').rglob('*.tfrec'))\n        self.photo_recs = list((src_folder / 'photo_tfrec').rglob('*.tfrec'))\n        \n        self.monet_dataset = self._load_tfrec_dataset(monet_recs, self.batch_size)\n        self.photo_dataset = self._load_tfrec_dataset(photo_recs, self.batch_size)\n        \n    def _decode_example(self, example):\n        desc = {\n                \"image_name\": tf.io.FixedLenFeature([], tf.string),\n                \"image\": tf.io.FixedLenFeature([], tf.string),\n                \"target\": tf.io.FixedLenFeature([], tf.string)\n               }\n\n        example = tf.io.parse_single_example(example, desc)\n        img = example['image']\n        img = tf.image.decode_jpeg(img, channels=3)\n        img = (tf.cast(img, tf.float32)/127.5) - 1\n        return img\n\n\n    def _load_tfrec_dataset(self, files, batch_size=1):\n        recs = tf.data.TFRecordDataset(files)\n        recs = recs.map(self._decode_example)\n        recs = recs.shuffle(1000)\n        return recs.batch(batch_size)\n\n    def __iter__(self):\n        for _ in range(self.num_batches_per_epoch):\n            yield next(self)\n            \n    def __next__(self):\n        return next(iter(self.monet_dataset)), next(iter(self.photo_dataset))","metadata":{"execution":{"iopub.status.busy":"2022-09-17T08:07:41.425132Z","iopub.execute_input":"2022-09-17T08:07:41.426218Z","iopub.status.idle":"2022-09-17T08:07:41.441673Z","shell.execute_reply.started":"2022-09-17T08:07:41.426159Z","shell.execute_reply":"2022-09-17T08:07:41.440380Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Display sample images","metadata":{}},{"cell_type":"code","source":"sample_img_A, sample_img_B = next(TFRecDataLoader(src_folder))","metadata":{"execution":{"iopub.status.busy":"2022-09-16T08:23:34.583996Z","iopub.execute_input":"2022-09-16T08:23:34.584383Z","iopub.status.idle":"2022-09-16T08:23:36.111145Z","shell.execute_reply.started":"2022-09-16T08:23:34.584349Z","shell.execute_reply":"2022-09-16T08:23:36.110109Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"fig, ax = plt.subplots(1, 2, figsize=(10, 7))\nax[0].imshow(sample_img_A[0]*0.5 + 0.5)\nax[0].axis('off')\nax[1].imshow(sample_img_B[0]*0.5 + 0.5)\nax[1].axis('off')\n\nfig.show()","metadata":{"execution":{"iopub.status.busy":"2022-09-16T08:23:36.360382Z","iopub.execute_input":"2022-09-16T08:23:36.361078Z","iopub.status.idle":"2022-09-16T08:23:36.706361Z","shell.execute_reply.started":"2022-09-16T08:23:36.361035Z","shell.execute_reply":"2022-09-16T08:23:36.705460Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"class ReflectionPadding2D(layers.Layer):\n    \"\"\"Implements Reflection Padding as a layer.\n\n    Args:\n        padding(tuple): Amount of padding for the\n        spatial dimensions.\n\n    Returns:\n        A padded tensor with the same type as the input tensor.\n    \"\"\"\n\n    def __init__(self, padding=(1, 1), **kwargs):\n        self.padding = tuple(padding)\n        super(ReflectionPadding2D, self).__init__(**kwargs)\n\n    def call(self, input_tensor, mask=None):\n        padding_width, padding_height = self.padding\n        padding_tensor = [\n            [0, 0],\n            [padding_height, padding_height],\n            [padding_width, padding_width],\n            [0, 0],\n        ]\n        return tf.pad(input_tensor, padding_tensor, mode=\"REFLECT\")","metadata":{"execution":{"iopub.status.busy":"2022-09-17T08:07:41.447995Z","iopub.execute_input":"2022-09-17T08:07:41.449261Z","iopub.status.idle":"2022-09-17T08:07:41.472096Z","shell.execute_reply.started":"2022-09-17T08:07:41.449215Z","shell.execute_reply":"2022-09-17T08:07:41.468342Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"class CycleGAN:\n    def __init__(self, input_shape, learning_rate, lambda_valid, lambda_reconstr, lambda_id, gen_n_filters, disc_n_filters,\n                generator='unet'):\n        self.learning_rate = learning_rate\n        self.lambda_valid = lambda_valid\n        self.lambda_reconstr = lambda_reconstr\n        self.lambda_id = lambda_id\n        self.gen_n_filters = gen_n_filters\n        self.disc_n_filters = disc_n_filters\n        self.input_size = input_shape\n        self.num_channels = input_shape[-1]\n        self.weight_init = RandomNormal(mean=0., stddev=0.02, seed=0)\n        self.epochs = 0\n        self.d_losses = []\n        self.g_losses = []\n        self.generator_type = generator\n        \n        self.compile()\n        \n    def _build_discriminator(self):\n        def conv2D(layer_input, filters, stride=2, norm=True):\n            y = Conv2D(filters,\n                       kernel_size=4, \n                       strides=stride, \n                       padding='same',\n                       kernel_initializer=tf.random_normal_initializer(0., 0.02)\n                      )(layer_input)\n            \n            if norm:\n                y = InstanceNormalization(axis=-1)(y)\n                \n            y = LeakyReLU(0.2)(y)\n            \n            return y\n        \n        img = Input(self.input_size)\n        \n        y = conv2D(img, self.disc_n_filters, stride=2, norm=False)\n        y = conv2D(y, 2*self.disc_n_filters, stride=2)\n        y = conv2D(y, 4*self.disc_n_filters, stride=2)\n        y = conv2D(y, 8*self.disc_n_filters, stride=2)\n        y = conv2D(y, 16*self.disc_n_filters, stride=1)\n        \n        output = Conv2D(1, kernel_size=4, strides=1, padding='same')(y)\n        \n        return Model(img, output)\n    \n    def _build_unet_generator(self):\n        def downsample(layer_input, filters, stride=2):\n            y = Conv2D(filters,\n                       kernel_size=4, \n                       strides=stride,\n                       padding='same',\n                       kernel_initializer=tf.random_normal_initializer(0., 0.02)\n                      )(layer_input)\n            \n            y = InstanceNormalization(axis=-1)(y)\n            y = Activation('relu')(y)\n            \n            return y\n        \n        def upsample(layer_input, skip_input, filters):\n            y = UpSampling2D(size=2)(layer_input)\n            y = Conv2D(filters,\n                       kernel_size=4,\n                       strides=1, \n                       padding='same',\n                       kernel_initializer=tf.random_normal_initializer(0., 0.02)\n                      )(y)\n            \n            y = InstanceNormalization(axis=-1)(y)\n            y = Activation('relu')(y)\n            y = Concatenate()([y, skip_input])\n            \n            return y\n        \n        img = Input(self.input_size)\n        \n        d1 = downsample(img, self.gen_n_filters)\n        d2 = downsample(d1, self.gen_n_filters*2)\n        d3 = downsample(d2, self.gen_n_filters*4)\n        d4 = downsample(d3, self.gen_n_filters*8)\n        \n        u1 = upsample(d4, d3, self.gen_n_filters*4)\n        u2 = upsample(u1, d2, self.gen_n_filters*2)\n        u3 = upsample(u2, d1, self.gen_n_filters)\n        \n        u4 = UpSampling2D(size=2)(u3)\n        output = Conv2D(filters=self.num_channels, kernel_size=4, strides=1, padding='same', activation='tanh')(u4)\n        \n        return Model(img, output)\n        \n    def _build_resnet_generator(self):\n        def conv7s1(layer_input, filters, final=False):\n            z = ReflectionPadding2D(padding=(3, 3))(layer_input)\n            z = Conv2D(filters,\n                       kernel_size=7,\n                       strides=1, \n                       padding='valid',\n                       kernel_initializer=self.weight_init\n                      )(z)\n            \n            if final:\n                z = Activation('tanh')(z)\n            else:    \n                z = InstanceNormalization(axis=-1, scale=False, center=False)(z)\n                z = Activation('relu')(z)\n            \n            return z\n        \n        def residual_block(layer_input, filters, strides=1):\n            z = ReflectionPadding2D(padding=(1, 1))(layer_input)\n            z = Conv2D(filters=filters,\n                      strides=1,\n                      kernel_size=3,\n                      padding='valid')(z)\n            z = InstanceNormalization(axis=-1, center=False, scale=False)(z)\n            z = ReLU()(z)\n            \n            z = ReflectionPadding2D(padding=(1, 1))(z)\n            z = Conv2D(filters=filters,\n                      strides=1,\n                      kernel_size=3,\n                      padding='valid')(z)\n            z = InstanceNormalization(axis=-1, center=False, scale=False)(z)\n            z = Activation('relu')(z)\n            \n            z = Add()([layer_input, z])\n            return z\n        \n        def downsample(layer_input, filters):\n            z = Conv2D(filters, kernel_size=3, strides=2, padding='same')(layer_input)\n            z = InstanceNormalization(axis=-1, center=False, scale=False)(z)\n            z = ReLU()(z)\n            return z\n        \n        def upsample(layer_input, filters):\n            z = Conv2DTranspose(filters, kernel_size=3, strides=2, padding='same')(layer_input)\n            z = InstanceNormalization(axis=-1, center=False, scale=False)(z)\n            z = ReLU()(z)\n            \n            return z\n        \n        img = Input(self.input_size)\n        \n        y = conv7s1(img, self.gen_n_filters)\n        \n        y = downsample(y, self.gen_n_filters*2)\n        y = downsample(y, self.gen_n_filters*4)\n        \n        for _ in range(9):\n            y = residual_block(y, self.gen_n_filters * 4)\n            \n        y = upsample(y, self.gen_n_filters*4)\n        y = upsample(y, self.gen_n_filters*2)\n        \n        y = conv7s1(y, 3, final=True)\n        output = y\n        \n        return Model(img, output)\n        \n    def compile(self):\n        self.d_A = self._build_discriminator()\n        self.d_B = self._build_discriminator()\n        \n        self.d_A.compile(loss=BinaryCrossentropy(from_logits=True),\n                         optimizer=Adam(learning_rate=self.learning_rate, beta_1=0.5),\n                         metrics=['accuracy']\n                        )\n        \n        self.d_B.compile(loss=BinaryCrossentropy(from_logits=True),\n                         optimizer=Adam(learning_rate=self.learning_rate, beta_1=0.5),\n                         metrics=['accuracy']\n                        )\n        \n        if self.generator_type == 'unet':\n            self.g_AB = self._build_unet_generator()\n            self.g_BA = self._build_unet_generator()\n        else:\n            self.g_AB = self._build_resnet_generator()\n            self.g_BA = self._build_resnet_generator()\n        self.d_A.trainable = False\n        self.d_B.trainable = False\n        \n        img_A = Input(self.input_size)\n        img_B = Input(self.input_size)\n        \n        fake_A = self.g_BA(img_B)\n        fake_B = self.g_AB(img_A)\n        \n        valid_A = self.d_A(fake_A)\n        valid_B = self.d_B(fake_B)\n        \n        reconstr_A = self.g_BA(self.g_AB(img_A))\n        reconstr_B = self.g_AB(self.g_BA(img_B))\n        \n        id_A = self.g_BA(img_A)\n        id_B = self.g_AB(img_B)\n        \n        self.model = Model(inputs=[img_A, img_B], \n                           outputs=[valid_A, valid_B,\n                                    reconstr_A, reconstr_B,\n                                    id_A, id_B]\n                          )\n        optimizer = Adam(learning_rate=self.learning_rate, beta_1=0.5)\n        \n        self.model.compile(loss=[BinaryCrossentropy(from_logits=True), BinaryCrossentropy(from_logits=True),\n                                'mae', 'mae',\n                                'mae', 'mae'],\n                           loss_weights=[self.lambda_valid, self.lambda_valid,\n                                        self.lambda_reconstr, self.lambda_reconstr,\n                                        self.lambda_id, self.lambda_id],\n                           optimizer=optimizer\n                          )\n        self.d_A.trainable = True\n        self.d_B.trainable = True\n        \n    def train(self, data_loader, epochs):\n        start_time = datetime.now()\n        patch = int(256/2**4)\n        disc_output_size = (patch, patch, 1)\n        \n        valid = np.ones(shape=(data_loader.batch_size,)+(disc_output_size))\n        fake = np.zeros(shape=(data_loader.batch_size,)+(disc_output_size))\n        \n        for epoch in range(self.epochs, epochs):\n            for i, batch in enumerate(data_loader):\n                img_A, img_B = batch\n                fake_A = self.g_BA(img_B)\n                fake_B = self.g_AB(img_A)\n\n                d_A_loss_real = self.d_A.train_on_batch(img_A, valid)\n                d_A_loss_fake = self.d_A.train_on_batch(fake_A, fake)\n                d_A_loss = 0.5 * np.add(d_A_loss_real, d_A_loss_fake)\n\n                d_B_loss_real = self.d_B.train_on_batch(img_B, valid)\n                d_B_loss_fake = self.d_B.train_on_batch(fake_B, fake)\n                d_B_loss = 0.5 * np.add(d_B_loss_real, d_B_loss_fake)\n\n                d_loss = 0.5 * np.add(d_A_loss, d_B_loss)\n\n                g_loss = self.model.train_on_batch([img_A, img_B], [valid, valid,\n                                                                   img_A, img_B,\n                                                                   img_A, img_B])\n                \n                elapsed_time = datetime.now() - start_time\n                \n                print(f\"Epoch: {epoch}/{epochs}, Batch: {i+1}/{data_loader.num_batches_per_epoch} [D loss: {d_loss[0]:.3f}, acc: {100*d_loss[1]:.3f}] \" \n                          f\"[G valid: {np.sum(g_loss[1:3]):.3f}, reconstr: {np.sum(g_loss[3:5]):.3f}, identity: {np.sum(g_loss[5:7]):.3f}] \"\n                          f\"Time: {elapsed_time}\")\n                \n                self.d_losses.append(d_loss[0])\n                self.g_losses.append(g_loss[0])\n            \n            self.epochs += 1\n            # if self.epochs % 2 == 0:\n            self.sample_output(self.epochs)\n            \n    def save_checkpoint(self):\n        pass\n        \n    def sample_output(self, epoch):\n        sample_img_A_fake = self.g_BA.predict(sample_img_B)\n        sample_img_B_fake = self.g_AB.predict(sample_img_A)\n        \n        fig, ax = plt.subplots(2, 2, figsize=(8, 8))\n        \n        ax[0, 0].imshow(sample_img_A[0]*0.5 + 0.5)\n        ax[0, 0].axis('off')\n        ax[0, 1].imshow(sample_img_B_fake[0]*0.5 + 0.5)\n        ax[0, 1].axis('off')\n        ax[1, 0].imshow(sample_img_B[0]*0.5 + 0.5)\n        ax[1, 0].axis('off')\n        ax[1, 1].imshow(sample_img_A_fake[0]*0.5 + 0.5)\n        ax[1, 1].axis('off')\n        # fig.show()\n        \n        fig.savefig(tmp_folder / f\"output_{epoch}.jpg\")","metadata":{"execution":{"iopub.status.busy":"2022-09-17T08:07:41.475974Z","iopub.execute_input":"2022-09-17T08:07:41.476485Z","iopub.status.idle":"2022-09-17T08:07:41.540154Z","shell.execute_reply.started":"2022-09-17T08:07:41.476421Z","shell.execute_reply":"2022-09-17T08:07:41.538663Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import tensorflow as tf\ntf.config.list_physical_devices('GPU')","metadata":{"execution":{"iopub.status.busy":"2022-09-17T08:07:41.542922Z","iopub.execute_input":"2022-09-17T08:07:41.543490Z","iopub.status.idle":"2022-09-17T08:07:41.791740Z","shell.execute_reply.started":"2022-09-17T08:07:41.543447Z","shell.execute_reply":"2022-09-17T08:07:41.789990Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"EPOCHS = 50\nBATCH_SIZE = 8\nNUM_BATCHES_PER_EPOCH = 20","metadata":{"execution":{"iopub.status.busy":"2022-09-17T08:07:58.107403Z","iopub.execute_input":"2022-09-17T08:07:58.107929Z","iopub.status.idle":"2022-09-17T08:07:58.114283Z","shell.execute_reply.started":"2022-09-17T08:07:58.107884Z","shell.execute_reply":"2022-09-17T08:07:58.112574Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"data_loader = TFRecDataLoader(src_folder, BATCH_SIZE, NUM_BATCHES_PER_EPOCH)","metadata":{"execution":{"iopub.status.busy":"2022-09-17T08:08:01.195589Z","iopub.execute_input":"2022-09-17T08:08:01.196037Z","iopub.status.idle":"2022-09-17T08:08:04.943564Z","shell.execute_reply.started":"2022-09-17T08:08:01.196004Z","shell.execute_reply":"2022-09-17T08:08:04.942125Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"gan = CycleGAN(\n               input_shape=(256, 256, 3),\n               learning_rate=2e-4, \n               lambda_valid=10,\n               lambda_reconstr=2, \n               lambda_id=10,\n               gen_n_filters=32,\n               disc_n_filters=32,\n               generator='unet'\n              )","metadata":{"execution":{"iopub.status.busy":"2022-09-17T08:08:14.972996Z","iopub.execute_input":"2022-09-17T08:08:14.973416Z","iopub.status.idle":"2022-09-17T08:08:17.343901Z","shell.execute_reply.started":"2022-09-17T08:08:14.973379Z","shell.execute_reply":"2022-09-17T08:08:17.342422Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"gan.train(data_loader, epochs=EPOCHS)","metadata":{"execution":{"iopub.status.busy":"2022-09-16T08:30:52.589681Z","iopub.execute_input":"2022-09-16T08:30:52.590139Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"fig, ax = plt.subplots(1, 2, figsize=(15, 5))\nsb.lineplot(data=gan.d_losses, ax=ax[0])\nax[0].set_title('Discriminator Loss')\nsb.lineplot(data=gan.g_losses, ax=ax[1])\nax[1].set_title('Generator Loss')\n\nfig.show()","metadata":{"execution":{"iopub.status.busy":"2022-09-11T04:46:33.983230Z","iopub.execute_input":"2022-09-11T04:46:33.983640Z","iopub.status.idle":"2022-09-11T04:46:34.364487Z","shell.execute_reply.started":"2022-09-11T04:46:33.983606Z","shell.execute_reply":"2022-09-11T04:46:34.363404Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"sample_img_A, sample_img_B = next(TFRecDataLoader(src_folder))\nsample_monet = gan.g_BA.predict(sample_img_B)\nsample_photo = gan.g_AB.predict(sample_img_A)\n\nfig, ax = plt.subplots(2, 2, figsize=(7, 7))\nax[0, 0].imshow(sample_img_A[0]*0.5 + 0.5)\nax[0, 0].axis('off')\nax[0, 1].imshow(sample_photo[0]*0.5 + 0.5)\nax[0, 1].axis('off')\n\nax[1, 0].imshow(sample_img_B[0]*0.5 + 0.5)\nax[1, 0].axis('off')\nax[1, 1].imshow(sample_monet[0]*0.5 + 0.5)\nax[1, 1].axis('off')\n\nfig.show()","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"photo_iterator = iter(TFRecDataLoader(src_folder, 1, 10000))","metadata":{"execution":{"iopub.status.busy":"2022-09-11T04:46:45.292402Z","iopub.execute_input":"2022-09-11T04:46:45.293454Z","iopub.status.idle":"2022-09-11T04:46:45.298811Z","shell.execute_reply.started":"2022-09-11T04:46:45.293405Z","shell.execute_reply":"2022-09-11T04:46:45.297490Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def deprocess_image(img):\n    return (img*127.5 + 127.5).astype(int)","metadata":{"execution":{"iopub.status.busy":"2022-09-11T05:39:21.422360Z","iopub.execute_input":"2022-09-11T05:39:21.422899Z","iopub.status.idle":"2022-09-11T05:39:21.428763Z","shell.execute_reply.started":"2022-09-11T05:39:21.422863Z","shell.execute_reply":"2022-09-11T05:39:21.427788Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"i = 1\nfor photos in tqdm(photo_iterator):\n    generated_monets = gan.g_BA.predict(photos[1])\n    for generated_monet in generated_monets:\n        save_img(output_folder / f'monet_{i}.jpg', deprocess_image(generated_monet))\n        i += 1","metadata":{"execution":{"iopub.status.busy":"2022-09-11T04:47:08.488921Z","iopub.execute_input":"2022-09-11T04:47:08.489275Z","iopub.status.idle":"2022-09-11T04:48:30.453313Z","shell.execute_reply.started":"2022-09-11T04:47:08.489244Z","shell.execute_reply":"2022-09-11T04:48:30.452037Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import shutil\nshutil.make_archive('images', 'zip', output_folder)","metadata":{"execution":{"iopub.status.busy":"2022-09-11T04:51:47.035218Z","iopub.execute_input":"2022-09-11T04:51:47.035736Z","iopub.status.idle":"2022-09-11T04:51:51.168020Z","shell.execute_reply.started":"2022-09-11T04:51:47.035686Z","shell.execute_reply":"2022-09-11T04:51:51.167062Z"},"trusted":true},"execution_count":null,"outputs":[]}]}