{"cells":[{"metadata":{},"cell_type":"markdown","source":"**Import packages:**"},{"metadata":{"_uuid":"d629ff2d2480ee46fbb7e2d37f6b5fab8052498a","_cell_guid":"79c7e3d0-c299-4dcb-8224-4455121ee9b0","trusted":true},"cell_type":"code","source":"from __future__ import absolute_import, division, print_function # bring to first line\nimport tensorflow as tf\nfrom tensorflow import keras\nfrom tensorflow.keras import layers, optimizers, applications, Sequential\nfrom tensorflow.keras.callbacks import EarlyStopping, ModelCheckpoint, LearningRateScheduler\nimport tensorflow_addons as tfa\nimport tensorflow_datasets as tfds\n\nfrom kaggle_datasets import KaggleDatasets\nimport glob\nimport imageio\nimport matplotlib.pyplot as plt\nimport numpy as np\nimport pandas as pd\nimport os\nimport sys\nprint(\"Python version:\", sys.version)\nimport PIL\nimport time\n\nfrom functools import partial\nfrom albumentations import (\n    Compose, RandomBrightness, JpegCompression, HueSaturationValue, RandomContrast, HorizontalFlip,\n    Rotate\n)\n\nfrom IPython import display","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"***Set the accelerator to TPU* and then run the following code:**"},{"metadata":{"trusted":true},"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)\nexcept:\n    strategy = tf.distribute.get_strategy()\nprint('Number of replicas:', strategy.num_replicas_in_sync)\n\nAUTOTUNE = tf.data.experimental.AUTOTUNE\n\nprint(tf.__version__)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"**Load the data:**\n\n(The various definitions are used to augment the small data set)"},{"metadata":{"trusted":true},"cell_type":"code","source":"GCS_PATH = KaggleDatasets().get_gcs_path()\n\nMONET_FILENAMES = tf.io.gfile.glob(str(GCS_PATH + '/monet_tfrec/*.tfrec'))\nprint('Monet TFRecord Files:', len(MONET_FILENAMES))\n\nIMAGE_SIZE = [256, 256]\n\ndef normalize(image):\n    return (tf.cast(image, tf.float32) / 127.5) - 1\n\ndef decode_image(image):\n    image = tf.image.decode_jpeg(image, channels=3)\n    image = tf.reshape(image, [*IMAGE_SIZE, 3])\n    return image\n\ndef random_crop(image):\n    cropped_image = tf.image.random_crop(image, size=[256, 256, 3])\n    return cropped_image\n\ndef random_jitter(image):\n    # resizing to 286 x 286 x 3 \n    image = tf.image.resize(image, [int(256*1.3), int(256*1.3)],\n                          method=tf.image.ResizeMethod.NEAREST_NEIGHBOR)\n    # randomly cropping to 256 x 256 x 3\n    image = random_crop(image)\n    # random mirroring\n    return image\n\ndef flip(image):\n    return tf.image.flip_left_right(image)\n\ndef preprocess_image_train(image, label=None):\n    image = random_jitter(image)\n    return image\n\ndef read_tfrecord(example):\n    tfrecord_format = {\n        \"image_name\": tf.io.FixedLenFeature([], tf.string),\n        \"image\": tf.io.FixedLenFeature([], tf.string),\n        \"target\": tf.io.FixedLenFeature([], tf.string)\n    }\n    example = tf.io.parse_single_example(example, tfrecord_format)\n    image = decode_image(example['image'])\n    return image\n\ndef load_dataset(filenames, labeled=False, ordered=False, repeats=200):\n    dataset = tf.data.TFRecordDataset(filenames)\n    dataset = dataset.map(read_tfrecord, num_parallel_calls=AUTOTUNE)\n    dataset = dataset.concatenate(dataset.map(flip, num_parallel_calls=AUTOTUNE).shuffle(100000))\n    dataset = dataset.concatenate(dataset.map(random_jitter, num_parallel_calls=AUTOTUNE).shuffle(10000, reshuffle_each_iteration=True).repeat(repeats))\n    dataset = dataset.map(normalize, num_parallel_calls=AUTOTUNE).shuffle(10000)\n    return dataset\n\nmonet_ds = load_dataset(MONET_FILENAMES, labeled=True, repeats=100).batch(100, drop_remainder=True)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"**Display the first images from the dataset:**"},{"metadata":{"trusted":true},"cell_type":"code","source":"def view_image(ds, rows=2):\n    image = next(iter(ds)) # extract 1 batch from the dataset\n    image = image.numpy()\n\n    fig = plt.figure(figsize=(22, rows * 5.05 ))\n    for i in range(5 * rows):\n        ax = fig.add_subplot(rows, 5, i+1, xticks=[], yticks=[])\n        ax.imshow(image[i] / 2 + .5)\n\nview_image(monet_ds)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"**Create the generator:**\n\n(The generator samples noise, reshapes and upsamples it to Monetize according to the current distribution)"},{"metadata":{"trusted":true},"cell_type":"code","source":"def Generator(LATENT_DIM=128, OUTPUT_CHANNELS=3):\n    model = tf.keras.Sequential()\n    model.add(layers.Dense(4*4*LATENT_DIM, use_bias=False, input_shape=(LATENT_DIM,)))\n    model.add(layers.BatchNormalization())\n    model.add(layers.ReLU())\n\n    model.add(layers.Reshape((4, 4, LATENT_DIM)))\n    assert model.output_shape == (None, 4, 4, LATENT_DIM) # Note: None is the batch size\n\n    initializer = tf.random_normal_initializer(0., 0.02)\n    model.add(layers.Conv2DTranspose(LATENT_DIM, 4, strides=(2, 2), padding='same', kernel_initializer=initializer, use_bias=False))\n    assert model.output_shape == (None, 8, 8, LATENT_DIM)\n    model.add(layers.BatchNormalization())\n    model.add(layers.ReLU())\n\n    initializer = tf.random_normal_initializer(0., 0.02)\n    model.add(layers.Conv2DTranspose(LATENT_DIM, 4, strides=(2, 2), padding='same', kernel_initializer=initializer, use_bias=False))\n    assert model.output_shape == (None, 16, 16, LATENT_DIM)\n    model.add(layers.BatchNormalization())\n    model.add(layers.ReLU())\n    \n    initializer = tf.random_normal_initializer(0., 0.02)\n    model.add(layers.Conv2DTranspose(LATENT_DIM//2, 4, strides=(2, 2), padding='same', kernel_initializer=initializer, use_bias=False))\n    assert model.output_shape == (None, 32, 32, LATENT_DIM//2)\n    model.add(layers.BatchNormalization())\n    model.add(layers.ReLU())\n    \n    initializer = tf.random_normal_initializer(0., 0.02)\n    model.add(layers.Conv2DTranspose(LATENT_DIM//4, 4, strides=(2, 2), padding='same', kernel_initializer=initializer, use_bias=False))\n    assert model.output_shape == (None, 64, 64, LATENT_DIM//4)\n    model.add(layers.BatchNormalization())\n    model.add(layers.ReLU())\n\n    initializer = tf.random_normal_initializer(0., 0.02)\n    model.add(layers.Conv2DTranspose(LATENT_DIM//8, 4, strides=(2, 2), padding='same', kernel_initializer=initializer, use_bias=False))\n    assert model.output_shape == (None, 128, 128, LATENT_DIM//8)\n    model.add(layers.BatchNormalization())\n    model.add(layers.ReLU())\n    \n    initializer = tf.random_normal_initializer(0., 0.02)\n    model.add(layers.Conv2DTranspose(OUTPUT_CHANNELS, 4, strides=(2, 2), padding='same', kernel_initializer=initializer, use_bias=False, activation='tanh'))\n    assert model.output_shape == (None, 256, 256, 3) # changed from (None, 256, 256, 4)\n    model.add(layers.BatchNormalization())\n    model.add(layers.ReLU())\n\n    return model","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"**Create the discriminator:**\n\n(The discriminator takes in the input image and classifies it as real or fake (generated). But instead of outputting a single node, the discriminator outputs a smaller 2D image with higher pixel values indicating a real classification and lower values indicating a fake classification.)"},{"metadata":{"trusted":true},"cell_type":"code","source":"def Discriminator():\n    model = tf.keras.Sequential()\n    initializer = tf.random_normal_initializer(0., 0.02)\n    model.add(layers.Conv2D(64, 4, strides=(2, 2), padding='same', kernel_initializer=initializer,\n                                     input_shape=[256, 256, 3], use_bias=False))\n    model.add(layers.LeakyReLU())\n    model.add(layers.Dropout(0.3))\n\n    initializer = tf.random_normal_initializer(0., 0.02)\n    model.add(layers.Conv2D(128, 4, strides=(2, 2), padding='same', kernel_initializer=initializer, use_bias=False))\n    model.add(layers.LeakyReLU())\n    model.add(layers.Dropout(0.3))\n    \n    initializer = tf.random_normal_initializer(0., 0.02)\n    model.add(layers.Conv2D(256, 4, strides=(2, 2), padding='same', kernel_initializer=initializer, use_bias=False))\n    model.add(layers.LeakyReLU())\n    model.add(layers.Dropout(0.3))\n    \n    model.add(layers.ZeroPadding2D())\n    initializer = tf.random_normal_initializer(0., 0.02)\n    gamma_init = keras.initializers.RandomNormal(mean=0.0, stddev=0.02)\n    model.add(layers.Conv2D(512, 4, strides=1, kernel_initializer=initializer, use_bias=False))\n    model.add(tfa.layers.InstanceNormalization(gamma_initializer=gamma_init))\n    model.add(layers.LeakyReLU())\n    model.add(layers.ZeroPadding2D())\n    model.add(layers.Conv2D(1, 4, strides=1, kernel_initializer=initializer))\n    model.add(layers.LeakyReLU(alpha=0.2))\n    \n    model.add(layers.Flatten())\n    model.add(layers.Dense(1))\n    model.add(layers.LeakyReLU())\n\n    return model","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"**Define least squares loss:**"},{"metadata":{"trusted":true},"cell_type":"code","source":"#Least squares\nwith strategy.scope():\n    def discriminator_loss(predictions_real, predictions_gen, labels_real):\n        gen_loss  = tf.reduce_mean((predictions_gen  - tf.reduce_mean(predictions_real) + labels_real) ** 2)\n        real_loss = tf.reduce_mean((predictions_real - tf.reduce_mean(predictions_gen)  - labels_real) ** 2)\n        return (gen_loss + real_loss) / 2\n    \n    def generator_loss(predictions_real, predictions_gen, labels_real):\n        gen_loss  = tf.reduce_mean((predictions_gen  - tf.reduce_mean(predictions_real) - labels_real) ** 2)\n        real_loss = tf.reduce_mean((predictions_real - tf.reduce_mean(predictions_gen)  + labels_real) ** 2)\n        return (gen_loss + real_loss) / 2","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"**Alternatively, BCE loss:**"},{"metadata":{"trusted":true},"cell_type":"code","source":"#BCE loss\nwith strategy.scope():\n    def discriminator_loss(predictions_real, predictions_gen):\n        bce = tf.keras.losses.BinaryCrossentropy(from_logits=True, reduction=tf.keras.losses.Reduction.NONE)\n        loss1 = tf.reduce_sum(bce(tf.ones_like(predictions_real), predictions_real)) * (1. / 32) # 32 is the default batch size for model_fit\n        loss2 = tf.reduce_sum(bce(tf.zeros_like(predictions_gen), predictions_gen)) * (1. / 32)\n        return loss1 + loss2\n    \n    def generator_loss(predictions_gen):\n        bce = tf.keras.losses.BinaryCrossentropy(from_logits=True, reduction=tf.keras.losses.Reduction.NONE)\n        return tf.reduce_sum(bce(tf.ones_like(predictions_gen), predictions_gen)) * (1. / 32)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"**Define GAN monitor (for images)**<br>\nSeems like this will generate 3 images at the end of each epoch from random noise<br>\nSo after 50 epochs, there will be 50*3 = 150 images"},{"metadata":{"trusted":true},"cell_type":"code","source":"gen_dir = 'generated'\n\nif not os.path.exists(gen_dir):\n    os.makedirs(gen_dir)\n\nclass GANMonitor(keras.callbacks.Callback):\n    def __init__(self, num_img=3, latent_dim=128):\n        self.num_img = num_img\n        self.latent_dim = latent_dim\n\n    def on_epoch_end(self, epoch, logs=None):\n        random_latent_vectors = tf.random.normal(shape=(self.num_img, self.latent_dim))\n        generated_images = self.model.generator(random_latent_vectors)\n        generated_images *= 255\n        generated_images.numpy()\n        for i in range(self.num_img):\n            img = keras.preprocessing.image.array_to_img(generated_images[i])\n            img.save(\"generated/generated_img_{i}_{epoch}.png\".format(i=i, epoch=epoch))","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"**Define MonetGAN (least squares loss):**"},{"metadata":{"trusted":true},"cell_type":"code","source":"class MonetGan(keras.Model):\n    def __init__(self, monet_generator, monet_discriminator, latent_dim, real_label=0.5, fake_label=0):\n        super(MonetGan, self).__init__()\n        self.generator = monet_generator\n        self.discriminator = monet_discriminator\n        self.latent_dim = latent_dim\n        self.real_label = real_label\n        self.fake_label = fake_label\n        \n    def compile(self, d_opt, g_opt, d_loss_fn, g_loss_fn):\n        super(MonetGan, self).compile()\n        self.d_opt = d_opt\n        self.g_opt = g_opt\n        self.d_loss_fn = d_loss_fn\n        self.g_loss_fn = g_loss_fn\n        \n    def train_step(self, images):\n    \n        if isinstance(images, tuple):\n            images = images[0]\n    \n        # Sample random points in the latent space\n        batch_size = tf.shape(images)[0]\n        noise = tf.random.normal(shape=(batch_size, self.latent_dim))\n        \n        labels_gen  = tf.zeros((batch_size, 1)) + self.fake_label\n        labels_real = tf.zeros((batch_size, 1)) + self.real_label\n        \n        # Add random noise to the labels - important trick!\n        labels_gen  += 0.05 * tf.random.uniform(tf.shape(labels_gen))\n        labels_real += 0.05 * tf.random.uniform(tf.shape(labels_real))\n    \n        with tf.GradientTape() as disc_tape: \n            generated_images = self.generator(noise, training=False)\n        \n            real_output = self.discriminator(images, training=True)\n            fake_output = self.discriminator(generated_images, training=True)\n    \n            disc_loss = self.d_loss_fn(real_output, fake_output, labels_real)\n    \n        with tf.GradientTape() as gen_tape: \n            generated_images = self.generator(noise, training=True)\n        \n            real_output = self.discriminator(images, training=False)\n            fake_output = self.discriminator(generated_images, training=False) \n    \n            gen_loss = self.g_loss_fn(real_output, fake_output, labels_real)\n\n        gradients_of_discriminator = disc_tape.gradient(disc_loss, self.discriminator.trainable_weights)\n        gradients_of_generator = gen_tape.gradient(gen_loss, self.generator.trainable_weights)\n\n        self.g_opt.apply_gradients(zip(gradients_of_generator, self.generator.trainable_weights))\n        self.d_opt.apply_gradients(zip(gradients_of_discriminator, self.discriminator.trainable_weights))\n    \n        return {\"d_loss\": disc_loss, \"g_loss\": gen_loss}","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"**Define MonetGAN (BCE loss):**"},{"metadata":{"trusted":true},"cell_type":"code","source":"class MonetGan(keras.Model):\n    def __init__(self, monet_generator, monet_discriminator, latent_dim, real_label=0.5, fake_label=0):\n        super(MonetGan, self).__init__()\n        self.generator = monet_generator\n        self.discriminator = monet_discriminator\n        self.latent_dim = latent_dim\n        self.real_label = real_label\n        self.fake_label = fake_label\n        \n    def compile(self, d_opt, g_opt, d_loss_fn, g_loss_fn):\n        super(MonetGan, self).compile()\n        self.d_opt = d_opt\n        self.g_opt = g_opt\n        self.d_loss_fn = d_loss_fn\n        self.g_loss_fn = g_loss_fn\n        \n    def train_step(self, images):\n    \n        if isinstance(images, tuple):\n            images = images[0]\n    \n        # Sample random points in the latent space\n        batch_size = tf.shape(images)[0]\n        noise = tf.random.normal(shape=(batch_size, self.latent_dim))\n        \n        labels_gen  = tf.zeros((batch_size, 1)) + self.fake_label\n        labels_real = tf.zeros((batch_size, 1)) + self.real_label\n        \n        # Add random noise to the labels - important trick!\n        labels_gen  += 0.05 * tf.random.uniform(tf.shape(labels_gen))\n        labels_real += 0.05 * tf.random.uniform(tf.shape(labels_real))\n            \n        with tf.GradientTape() as disc_tape:\n            generated_images = self.generator(noise, training=False)\n        \n            real_output = self.discriminator(images, training=True)\n            fake_output = self.discriminator(generated_images, training=True)\n    \n            disc_loss = self.d_loss_fn(real_output, fake_output)\n        \n        with tf.GradientTape() as gen_tape:\n            generated_images = self.generator(noise, training=True)\n            \n            real_output = self.discriminator(images, training=False)\n            fake_output = self.discriminator(generated_images, training=False)\n            \n            gen_loss = self.g_loss_fn(fake_output)\n            \n        gradients_of_generator = gen_tape.gradient(gen_loss, self.generator.trainable_weights)\n        gradients_of_discriminator = disc_tape.gradient(disc_loss, self.discriminator.trainable_weights)\n            \n        self.g_opt.apply_gradients(zip(gradients_of_generator, self.generator.trainable_weights))\n        self.d_opt.apply_gradients(zip(gradients_of_discriminator, self.discriminator.trainable_weights))\n    \n        return {\"d_loss\": disc_loss, \"g_loss\": gen_loss}","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"**Training parameters and checkpoints (creates new model)**"},{"metadata":{"trusted":true},"cell_type":"code","source":"# LR_G, LR_D\nt0 = (0.001, 0.0005)\nt1 = (0.001, 0.001)\nt2 = (0.001, 0.002)\nt3 = (0.001, 0.004)\nt4 = (0.001, 0.00025)\nt5 = (0.00025, 0.001)\nt6 = (0.0005, 0.001)\nt7 = (0.002, 0.001)\nt8 = (0.004, 0.001)\n\nLR_G = t5[0]\nLR_D = t5[1]\ncheckpoint_path = 'training_1/cp-{epoch:04d}.h5' # try h5 instead of ckpt\ncheckpoint_dir = os.path.dirname(checkpoint_path)\nif not os.path.exists(checkpoint_dir):\n    os.makedirs(checkpoint_dir)\n\n\n# Creates checkpoint callback to pass to model.fit\ncp_callback = tf.keras.callbacks.ModelCheckpoint(checkpoint_path,\n                                                save_weights_only=False,\n                                                verbose=1,\n                                                periods=5)\n\n#Training \nEPOCHS = 100\n\nbeta_1 = .5\n\nreal_label = .66\nfake_label = 0\n\nOUTPUT_CHANNELS = 3\nLATENT_DIM = 128\n\nwith strategy.scope():\n\n    monet_generator = Generator(LATENT_DIM, 3) # generates Monet-esque paintings\n    monet_discriminator = Discriminator() # differentiates real Monet paintings and generated\n    \n    \n    monet_gan = MonetGan(monet_discriminator=monet_discriminator, \n                         monet_generator=monet_generator, \n                         latent_dim=LATENT_DIM,\n                         real_label=real_label,\n                         fake_label=fake_label)\n    \n    monet_gan.compile(\n        #d_opt = tf.keras.optimizers.Adam(learning_rate=LR_D, beta_1=beta_1),\n        #g_opt = tf.keras.optimizers.Adam(learning_rate=LR_G, beta_1=beta_1),\n        d_opt = tf.keras.optimizers.SGD(learning_rate=LR_D),\n        g_opt = tf.keras.optimizers.SGD(learning_rate=LR_G),\n        d_loss_fn=discriminator_loss,\n        g_loss_fn=generator_loss\n    )","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"**Look at saved checkpoints**<br>\nlist files in the checkpoint_dir"},{"metadata":{"trusted":true},"cell_type":"code","source":"!ls {checkpoint_dir}","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"**load latest checkpoint (if not training from scratch)**"},{"metadata":{"trusted":true},"cell_type":"code","source":"import glob\n\nlist_of_files = glob.glob(checkpoint_dir + '/*.h5') # * means all if need specific format then *.csv\nlatest_file = max(list_of_files, key=os.path.getctime)\nprint(latest_file)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"monet_gan.load_weights(latest_file)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Or choose a checkpoint to load from"},{"metadata":{"trusted":true},"cell_type":"code","source":"monet_gan.load_weights(checkpoint_dir + '/cp-0003.h5')","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"**Training loop**"},{"metadata":{"trusted":true},"cell_type":"code","source":"from tensorflow.keras.callbacks import History\nhistory = History()\n\nmonet_gan.fit(\n    monet_ds,\n    epochs=EPOCHS,\n    callbacks=[\n        cp_callback,\n        GANMonitor(num_img=3, latent_dim=LATENT_DIM),\n        history\n    ]\n)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"**Display image from epoch-number**"},{"metadata":{"trusted":true},"cell_type":"code","source":"# plot losses and save plot\nplt.plot(history.history['g_loss'])\nplt.plot(history.history['d_loss'])\nplt.title('model loss')\nplt.ylabel('loss')\nplt.xlabel('epoch')\nplt.legend(['generator', 'discriminator'], loc='upper left')\nplt.savefig('loss_graph--G_{LR_G:.5f}--D_{LR_D:.5f}--.png'.format(LR_G = LR_G, LR_D=LR_D)) \n# can change the {}s to {EPOCHS:3d} if varying epochs\nplt.show()\n# save losses to csv file\nhist = history.history\nhist_df = pd.DataFrame.from_dict(hist)\nhist_df.index = list(range(1,len(hist_df)+1))\nhist_df.to_csv('hist--G_{LR_G:.5f}--D_{LR_D:.5f}--.csv'.format(LR_G = LR_G, LR_D=LR_D), \n               # can change the {}s to {EPOCHS:3d} if varying epochs\n               index_label = 'Epoch')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def display_image(num_img, epoch_no):\n  return PIL.Image.open('generated/generated_img_{i}_{epoch}.png'.format(i = num_img, epoch = epoch_no))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# epoch_no from 0 to 49\n# choose num_img from 0 to 2. if want more samples, in monet_gan.fit(), set GAN_monitor(num_img=n,) for your choice of n\ndisplay_image(0, 2) ","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"**Create gif**"},{"metadata":{"trusted":true},"cell_type":"code","source":"anim_file = 'dcgan.gif'\n\nwith imageio.get_writer(anim_file, mode='I') as writer:\n    filenames = glob.glob('generated/generated*.png')\n    filenames = sorted(filenames)\n    for filename in filenames:\n        image = imageio.imread(filename)\n        writer.append_data(image)\n    image = imageio.imread(filename)\n    writer.append_data(image)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"!pip install git+https://github.com/tensorflow/docs\nimport tensorflow_docs.vis.embed as embed\nembed.embed_file(anim_file)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"**Predict images**"},{"metadata":{"trusted":true},"cell_type":"code","source":"image_dir =  '../images'\nif not os.path.exists(image_dir):\n    os.makedirs(image_dir)\n\nfor i in range(7000):\n    prediction = monet_generator(np.random.randn(1, LATENT_DIM), training=False)[0].numpy()\n    prediction = (prediction * 127.5 + 127.5).astype(np.uint8)\n    im = PIL.Image.fromarray(prediction)\n    im.save(f\"../images/{i}.jpg\")","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"import shutil\nshutil.make_archive(\"/kaggle/working/images\", 'zip', \"/kaggle/images\")","execution_count":null,"outputs":[]}],"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":4,"nbformat_minor":4}