{"nbformat":4,"nbformat_minor":0,"metadata":{"colab":{"name":"ex7 - vae.ipynb","provenance":[],"collapsed_sections":[],"toc_visible":true,"authorship_tag":"ABX9TyNS2VkU+59d9c7FppBT4a6T"},"kernelspec":{"name":"python3","display_name":"Python 3"},"language_info":{"name":"python"}},"cells":[{"cell_type":"markdown","source":["## Variational autoencoder (VAE)\n","\n","Variational autoencoders are a slightly more modern and interesting take on autoencoding.\n","\n","

\n"," \n","

\n","\n","What is a variational autoencoder, you ask? It's a type of autoencoder with added constraints on the encoded representations being learned. More precisely, it is an autoencoder that learns a [latent variable model](https://en.wikipedia.org/wiki/Latent_variable_model) for its input data. So instead of letting your neural network learn an arbitrary function, you are learning the parameters of a probability distribution modeling your data. If you sample points from this distribution, you can generate new input data samples: a VAE is a \"generative model\".\n","\n","How does a variational autoencoder work?\n","\n","First, an encoder network turns the input samples x into two parameters in a latent space, which we will note z_mean and z_log_sigma. Then, we randomly sample similar points z from the latent normal distribution that is assumed to generate the data, via z = z_mean + exp(z_log_sigma) * epsilon, where epsilon is a random normal tensor. Finally, a decoder network maps these latent space points back to the original input data.\n","\n","The parameters of the model are trained via two loss functions: a reconstruction loss forcing the decoded samples to match the initial inputs (just like in our previous autoencoders), and the KL divergence between the learned latent distribution and the prior distribution, acting as a regularization term. You could actually get rid of this latter term entirely, although it does help in learning well-formed latent spaces and reducing overfitting to the training data.\n","\n","Because a VAE is a more complex example, we have made the code available on [Github](https://github.com/fchollet/keras/blob/master/examples/variational_autoencoder.py) as a standalone script. Here we will review step by step how the model is created.\n","\n","### Loss\n","\n","The loss function of the VAE is defined by two terms, the reconstruction loss and the regularizer which is essentially a KL divergence between the encoder’s distribution and the latent space.\n","\n","$$\\mathcal{L}(\\theta, \\phi) = -\\mathbb{E}_{X \\sim q_{\\theta}}[P_{\\theta}(x|z)] + \\mathcal{D}_\\text{KL}(q_{\\phi}(z|x) || p_{\\theta}(z)) $$\n","\n","where the KL divergence is defined below\n","\n","$$\\mathcal{D}_\\text{KL}(P||Q) = \\sum_x P(x) \\log(\\frac{P(x)}{Q(x)})$$\n","\n","\n","### KL divergence\n","\n","What does KL divergence mean?\n","\n","

\n"," \n","

\n","\n","Solution for $\\mathcal{D}(P||Q)$ is below\n","\n","

\n"," \n","

\n","\n","and for $\\mathcal{D}(Q||P)$ is below\n","\n","

\n","\n"],"metadata":{"id":"0Xn0_vxIFBnp"}},{"cell_type":"code","source":["# import\n","import keras\n","from keras import layers"],"metadata":{"id":"oNKhpEW1FodY","executionInfo":{"status":"ok","timestamp":1655999857963,"user_tz":240,"elapsed":1216,"user":{"displayName":"Yiqiao Yin","userId":"17143243938280119775"}}},"execution_count":15,"outputs":[]},{"cell_type":"code","execution_count":16,"metadata":{"id":"OA6SV_pfE-b-","executionInfo":{"status":"ok","timestamp":1655999858290,"user_tz":240,"elapsed":6,"user":{"displayName":"Yiqiao Yin","userId":"17143243938280119775"}}},"outputs":[],"source":["# input\n","original_dim = 28 * 28\n","intermediate_dim = 64\n","latent_dim = 2\n","\n","inputs = keras.Input(shape=(original_dim,))\n","h = layers.Dense(intermediate_dim, activation='relu')(inputs)\n","z_mean = layers.Dense(latent_dim)(h)\n","z_log_sigma = layers.Dense(latent_dim)(h)"]},{"cell_type":"code","source":["from keras import backend as K\n","\n","def sampling(args):\n"," z_mean, z_log_sigma = args\n"," epsilon = K.random_normal(shape=(K.shape(z_mean)[0], latent_dim),\n"," mean=0., stddev=0.00001)\n"," return z_mean + K.exp(z_log_sigma) * epsilon\n","\n","z = layers.Lambda(sampling)([z_mean, z_log_sigma])"],"metadata":{"id":"PTJ43ziqFn-k","executionInfo":{"status":"ok","timestamp":1656000826749,"user_tz":240,"elapsed":3,"user":{"displayName":"Yiqiao Yin","userId":"17143243938280119775"}}},"execution_count":25,"outputs":[]},{"cell_type":"markdown","source":["Finally, we can map these sampled latent points back to reconstructed inputs:"],"metadata":{"id":"TJcaR3eRFsQ7"}},{"cell_type":"code","source":["# Create encoder\n","encoder = keras.Model(inputs, [z_mean, z_log_sigma, z], name='encoder')\n","\n","# Create decoder\n","latent_inputs = keras.Input(shape=(latent_dim,), name='z_sampling')\n","x = layers.Dense(intermediate_dim, activation='relu')(latent_inputs)\n","outputs = layers.Dense(original_dim, activation='sigmoid')(x)\n","decoder = keras.Model(latent_inputs, outputs, name='decoder')\n","\n","# instantiate VAE model\n","outputs = decoder(encoder(inputs)[2])\n","vae = keras.Model(inputs, outputs, name='vae_mlp')"],"metadata":{"id":"AEONH7VhFsvb","executionInfo":{"status":"ok","timestamp":1656000827623,"user_tz":240,"elapsed":368,"user":{"displayName":"Yiqiao Yin","userId":"17143243938280119775"}}},"execution_count":26,"outputs":[]},{"cell_type":"code","source":["# summary\n","vae.summary()"],"metadata":{"colab":{"base_uri":"https://localhost:8080/"},"id":"NvqtVAHNV3hN","executionInfo":{"status":"ok","timestamp":1656001632925,"user_tz":240,"elapsed":361,"user":{"displayName":"Yiqiao Yin","userId":"17143243938280119775"}},"outputId":"2d909a2e-90ef-4f83-c597-a57e0f5946ad"},"execution_count":33,"outputs":[{"output_type":"stream","name":"stdout","text":["Model: \"vae_mlp\"\n","__________________________________________________________________________________________________\n"," Layer (type) Output Shape Param # Connected to \n","==================================================================================================\n"," input_3 (InputLayer) [(None, 784)] 0 [] \n"," \n"," encoder (Functional) [(None, 2), 50500 ['input_3[0][0]'] \n"," (None, 2), \n"," (None, 2)] \n"," \n"," decoder (Functional) (None, 784) 51152 ['encoder[0][2]'] \n"," \n"," dense_5 (Dense) (None, 64) 50240 ['input_3[0][0]'] \n"," \n"," dense_7 (Dense) (None, 2) 130 ['dense_5[0][0]'] \n"," \n"," dense_6 (Dense) (None, 2) 130 ['dense_5[0][0]'] \n"," \n"," tf.__operators__.add_4 (TFOpLa (None, 2) 0 ['dense_7[0][0]'] \n"," mbda) \n"," \n"," tf.math.square_2 (TFOpLambda) (None, 2) 0 ['dense_6[0][0]'] \n"," \n"," tf.cast_2 (TFOpLambda) (None, 784) 0 ['input_3[0][0]'] \n"," \n"," tf.convert_to_tensor_6 (TFOpLa (None, 784) 0 ['decoder[0][0]'] \n"," mbda) \n"," \n"," tf.math.subtract_4 (TFOpLambda (None, 2) 0 ['tf.__operators__.add_4[0][0]', \n"," ) 'tf.math.square_2[0][0]'] \n"," \n"," tf.math.exp_2 (TFOpLambda) (None, 2) 0 ['dense_7[0][0]'] \n"," \n"," tf.keras.backend.binary_crosse (None, 784) 0 ['tf.cast_2[0][0]', \n"," ntropy_2 (TFOpLambda) 'tf.convert_to_tensor_6[0][0]'] \n"," \n"," tf.math.subtract_5 (TFOpLambda (None, 2) 0 ['tf.math.subtract_4[0][0]', \n"," ) 'tf.math.exp_2[0][0]'] \n"," \n"," tf.math.reduce_mean_4 (TFOpLam (None,) 0 ['tf.keras.backend.binary_crossen\n"," bda) tropy_2[0][0]'] \n"," \n"," tf.math.reduce_sum_2 (TFOpLamb (None,) 0 ['tf.math.subtract_5[0][0]'] \n"," da) \n"," \n"," tf.math.multiply_4 (TFOpLambda (None,) 0 ['tf.math.reduce_mean_4[0][0]'] \n"," ) \n"," \n"," tf.math.multiply_5 (TFOpLambda (None,) 0 ['tf.math.reduce_sum_2[0][0]'] \n"," ) \n"," \n"," tf.__operators__.add_5 (TFOpLa (None,) 0 ['tf.math.multiply_4[0][0]', \n"," mbda) 'tf.math.multiply_5[0][0]'] \n"," \n"," tf.math.reduce_mean_5 (TFOpLam () 0 ['tf.__operators__.add_5[0][0]'] \n"," bda) \n"," \n"," add_loss_2 (AddLoss) () 0 ['tf.math.reduce_mean_5[0][0]'] \n"," \n","==================================================================================================\n","Total params: 101,652\n","Trainable params: 101,652\n","Non-trainable params: 0\n","__________________________________________________________________________________________________\n"]}]},{"cell_type":"markdown","source":["What we've done so far allows us to instantiate 3 models:\n","\n","- an end-to-end autoencoder mapping inputs to reconstructions\n","- an encoder mapping inputs to the latent space\n","- a generator that can take points on the latent space and will output the corresponding reconstructed samples.\n"],"metadata":{"id":"F83uMIWgF2ET"}},{"cell_type":"markdown","source":["We train the model using the end-to-end model, with a custom loss function: the sum of a reconstruction term, and the KL divergence regularization term."],"metadata":{"id":"AVJLeODfGJct"}},{"cell_type":"code","source":["reconstruction_loss = keras.losses.binary_crossentropy(inputs, outputs)\n","reconstruction_loss *= original_dim\n","kl_loss = 1 + z_log_sigma - K.square(z_mean) - K.exp(z_log_sigma)\n","kl_loss = K.sum(kl_loss, axis=-1)\n","kl_loss *= -0.5\n","vae_loss = K.mean(reconstruction_loss + kl_loss)\n","vae.add_loss(vae_loss)\n","vae.compile(optimizer='adam')"],"metadata":{"id":"iUt31yd8GJXl","executionInfo":{"status":"ok","timestamp":1656000827624,"user_tz":240,"elapsed":3,"user":{"displayName":"Yiqiao Yin","userId":"17143243938280119775"}}},"execution_count":27,"outputs":[]},{"cell_type":"markdown","source":["We train our VAE on MNIST digits:"],"metadata":{"id":"Nhhkm1D1GMQH"}},{"cell_type":"code","source":["from keras.datasets import mnist\n","import numpy as np"],"metadata":{"id":"xTUZRfgSGTDb","executionInfo":{"status":"ok","timestamp":1656000827624,"user_tz":240,"elapsed":3,"user":{"displayName":"Yiqiao Yin","userId":"17143243938280119775"}}},"execution_count":28,"outputs":[]},{"cell_type":"code","source":["(x_train, y_train), (x_test, y_test) = mnist.load_data()\n","\n","x_train = x_train.astype('float32') / 255.\n","x_test = x_test.astype('float32') / 255.\n","x_train = x_train.reshape((len(x_train), np.prod(x_train.shape[1:])))\n","x_test = x_test.reshape((len(x_test), np.prod(x_test.shape[1:])))\n","\n","vae.fit(x_train, x_train,\n"," epochs=100,\n"," batch_size=32,\n"," validation_data=(x_test, x_test))"],"metadata":{"colab":{"base_uri":"https://localhost:8080/"},"id":"31VVeOkAF3n0","executionInfo":{"status":"ok","timestamp":1656001630626,"user_tz":240,"elapsed":803004,"user":{"displayName":"Yiqiao Yin","userId":"17143243938280119775"}},"outputId":"c41bac9b-b4ea-4614-899f-844f5f3cccd4"},"execution_count":29,"outputs":[{"output_type":"stream","name":"stdout","text":["Epoch 1/100\n","1875/1875 [==============================] - 10s 5ms/step - loss: 188.5094 - val_loss: 168.4880\n","Epoch 2/100\n","1875/1875 [==============================] - 10s 5ms/step - loss: 165.7443 - val_loss: 162.4903\n","Epoch 3/100\n","1875/1875 [==============================] - 8s 4ms/step - loss: 160.8530 - val_loss: 159.2367\n","Epoch 4/100\n","1875/1875 [==============================] - 8s 4ms/step - loss: 157.5824 - val_loss: 156.4051\n","Epoch 5/100\n","1875/1875 [==============================] - 8s 4ms/step - loss: 155.4839 - val_loss: 154.7016\n","Epoch 6/100\n","1875/1875 [==============================] - 8s 4ms/step - loss: 154.1239 - val_loss: 153.7073\n","Epoch 7/100\n","1875/1875 [==============================] - 8s 4ms/step - loss: 153.0794 - val_loss: 153.4391\n","Epoch 8/100\n","1875/1875 [==============================] - 8s 4ms/step - loss: 152.2299 - val_loss: 152.1881\n","Epoch 9/100\n","1875/1875 [==============================] - 8s 4ms/step - loss: 151.5184 - val_loss: 151.5402\n","Epoch 10/100\n","1875/1875 [==============================] - 8s 4ms/step - loss: 150.9030 - val_loss: 150.8686\n","Epoch 11/100\n","1875/1875 [==============================] - 8s 4ms/step - loss: 150.3664 - val_loss: 150.4436\n","Epoch 12/100\n","1875/1875 [==============================] - 8s 4ms/step - loss: 149.8738 - val_loss: 149.9316\n","Epoch 13/100\n","1875/1875 [==============================] - 8s 4ms/step - loss: 149.4327 - val_loss: 149.5811\n","Epoch 14/100\n","1875/1875 [==============================] - 8s 4ms/step - loss: 149.0481 - val_loss: 149.1727\n","Epoch 15/100\n","1875/1875 [==============================] - 8s 4ms/step - loss: 148.6743 - val_loss: 149.1334\n","Epoch 16/100\n","1875/1875 [==============================] - 8s 4ms/step - loss: 148.3363 - val_loss: 148.7839\n","Epoch 17/100\n","1875/1875 [==============================] - 8s 4ms/step - loss: 148.0163 - val_loss: 148.8763\n","Epoch 18/100\n","1875/1875 [==============================] - 8s 4ms/step - loss: 147.7662 - val_loss: 148.0526\n","Epoch 19/100\n","1875/1875 [==============================] - 8s 4ms/step - loss: 147.4717 - val_loss: 148.1878\n","Epoch 20/100\n","1875/1875 [==============================] - 8s 4ms/step - loss: 147.2687 - val_loss: 147.8080\n","Epoch 21/100\n","1875/1875 [==============================] - 8s 4ms/step - loss: 147.0676 - val_loss: 147.6892\n","Epoch 22/100\n","1875/1875 [==============================] - 8s 4ms/step - loss: 146.8312 - val_loss: 147.4462\n","Epoch 23/100\n","1875/1875 [==============================] - 8s 4ms/step - loss: 146.6662 - val_loss: 147.3632\n","Epoch 24/100\n","1875/1875 [==============================] - 8s 4ms/step - loss: 146.4653 - val_loss: 147.3523\n","Epoch 25/100\n","1875/1875 [==============================] - 8s 4ms/step - loss: 146.3300 - val_loss: 147.4919\n","Epoch 26/100\n","1875/1875 [==============================] - 8s 4ms/step - loss: 146.1455 - val_loss: 147.1599\n","Epoch 27/100\n","1875/1875 [==============================] - 8s 4ms/step - loss: 145.9840 - val_loss: 147.0888\n","Epoch 28/100\n","1875/1875 [==============================] - 9s 5ms/step - loss: 145.8554 - val_loss: 146.7264\n","Epoch 29/100\n","1875/1875 [==============================] - 8s 4ms/step - loss: 145.7151 - val_loss: 146.7624\n","Epoch 30/100\n","1875/1875 [==============================] - 8s 4ms/step - loss: 145.6190 - val_loss: 146.7112\n","Epoch 31/100\n","1875/1875 [==============================] - 8s 4ms/step - loss: 145.4919 - val_loss: 146.4333\n","Epoch 32/100\n","1875/1875 [==============================] - 8s 4ms/step - loss: 145.3505 - val_loss: 146.5393\n","Epoch 33/100\n","1875/1875 [==============================] - 8s 4ms/step - loss: 145.2668 - val_loss: 147.0874\n","Epoch 34/100\n","1875/1875 [==============================] - 8s 4ms/step - loss: 145.1603 - val_loss: 146.2859\n","Epoch 35/100\n","1875/1875 [==============================] - 8s 4ms/step - loss: 145.0606 - val_loss: 146.1930\n","Epoch 36/100\n","1875/1875 [==============================] - 8s 4ms/step - loss: 144.9507 - val_loss: 145.9885\n","Epoch 37/100\n","1875/1875 [==============================] - 8s 4ms/step - loss: 144.8741 - val_loss: 146.0838\n","Epoch 38/100\n","1875/1875 [==============================] - 8s 4ms/step - loss: 144.7839 - val_loss: 146.0788\n","Epoch 39/100\n","1875/1875 [==============================] - 8s 4ms/step - loss: 144.7077 - val_loss: 145.8134\n","Epoch 40/100\n","1875/1875 [==============================] - 8s 4ms/step - loss: 144.6270 - val_loss: 146.0575\n","Epoch 41/100\n","1875/1875 [==============================] - 8s 4ms/step - loss: 144.5752 - val_loss: 145.8880\n","Epoch 42/100\n","1875/1875 [==============================] - 8s 4ms/step - loss: 144.5074 - val_loss: 145.8622\n","Epoch 43/100\n","1875/1875 [==============================] - 8s 4ms/step - loss: 144.4054 - val_loss: 145.7831\n","Epoch 44/100\n","1875/1875 [==============================] - 8s 4ms/step - loss: 144.3751 - val_loss: 145.8580\n","Epoch 45/100\n","1875/1875 [==============================] - 8s 4ms/step - loss: 144.2587 - val_loss: 145.5450\n","Epoch 46/100\n","1875/1875 [==============================] - 8s 4ms/step - loss: 144.2138 - val_loss: 145.6825\n","Epoch 47/100\n","1875/1875 [==============================] - 8s 4ms/step - loss: 144.1333 - val_loss: 145.7980\n","Epoch 48/100\n","1875/1875 [==============================] - 8s 4ms/step - loss: 144.0699 - val_loss: 145.6631\n","Epoch 49/100\n","1875/1875 [==============================] - 8s 4ms/step - loss: 144.0382 - val_loss: 145.4380\n","Epoch 50/100\n","1875/1875 [==============================] - 8s 4ms/step - loss: 143.9829 - val_loss: 145.5930\n","Epoch 51/100\n","1875/1875 [==============================] - 8s 4ms/step - loss: 143.8797 - val_loss: 145.4716\n","Epoch 52/100\n","1875/1875 [==============================] - 8s 4ms/step - loss: 143.8812 - val_loss: 145.2853\n","Epoch 53/100\n","1875/1875 [==============================] - 8s 4ms/step - loss: 143.7988 - val_loss: 145.5275\n","Epoch 54/100\n","1875/1875 [==============================] - 8s 4ms/step - loss: 143.7534 - val_loss: 145.3301\n","Epoch 55/100\n","1875/1875 [==============================] - 8s 4ms/step - loss: 143.6887 - val_loss: 145.5430\n","Epoch 56/100\n","1875/1875 [==============================] - 8s 4ms/step - loss: 143.6289 - val_loss: 145.2061\n","Epoch 57/100\n","1875/1875 [==============================] - 8s 4ms/step - loss: 143.5893 - val_loss: 145.1447\n","Epoch 58/100\n","1875/1875 [==============================] - 8s 4ms/step - loss: 143.5442 - val_loss: 145.6349\n","Epoch 59/100\n","1875/1875 [==============================] - 8s 4ms/step - loss: 143.4988 - val_loss: 145.0847\n","Epoch 60/100\n","1875/1875 [==============================] - 9s 5ms/step - loss: 143.4332 - val_loss: 145.0155\n","Epoch 61/100\n","1875/1875 [==============================] - 8s 4ms/step - loss: 143.4090 - val_loss: 145.1808\n","Epoch 62/100\n","1875/1875 [==============================] - 8s 4ms/step - loss: 143.3701 - val_loss: 145.2663\n","Epoch 63/100\n","1875/1875 [==============================] - 8s 4ms/step - loss: 143.3111 - val_loss: 144.9385\n","Epoch 64/100\n","1875/1875 [==============================] - 8s 4ms/step - loss: 143.2792 - val_loss: 145.0052\n","Epoch 65/100\n","1875/1875 [==============================] - 8s 4ms/step - loss: 143.2265 - val_loss: 144.9833\n","Epoch 66/100\n","1875/1875 [==============================] - 8s 4ms/step - loss: 143.1718 - val_loss: 145.1300\n","Epoch 67/100\n","1875/1875 [==============================] - 9s 5ms/step - loss: 143.1454 - val_loss: 144.8909\n","Epoch 68/100\n","1875/1875 [==============================] - 8s 4ms/step - loss: 143.0817 - val_loss: 144.8549\n","Epoch 69/100\n","1875/1875 [==============================] - 8s 4ms/step - loss: 143.0709 - val_loss: 144.6850\n","Epoch 70/100\n","1875/1875 [==============================] - 8s 4ms/step - loss: 143.0379 - val_loss: 145.0110\n","Epoch 71/100\n","1875/1875 [==============================] - 8s 4ms/step - loss: 142.9976 - val_loss: 144.7770\n","Epoch 72/100\n","1875/1875 [==============================] - 8s 4ms/step - loss: 142.9654 - val_loss: 144.9857\n","Epoch 73/100\n","1875/1875 [==============================] - 8s 4ms/step - loss: 142.9173 - val_loss: 144.5193\n","Epoch 74/100\n","1875/1875 [==============================] - 8s 4ms/step - loss: 142.8678 - val_loss: 144.9479\n","Epoch 75/100\n","1875/1875 [==============================] - 8s 4ms/step - loss: 142.8758 - val_loss: 144.7753\n","Epoch 76/100\n","1875/1875 [==============================] - 8s 4ms/step - loss: 142.8078 - val_loss: 144.9018\n","Epoch 77/100\n","1875/1875 [==============================] - 8s 4ms/step - loss: 142.7642 - val_loss: 144.6623\n","Epoch 78/100\n","1875/1875 [==============================] - 8s 4ms/step - loss: 142.7427 - val_loss: 144.6104\n","Epoch 79/100\n","1875/1875 [==============================] - 8s 4ms/step - loss: 142.7003 - val_loss: 144.6850\n","Epoch 80/100\n","1875/1875 [==============================] - 8s 4ms/step - loss: 142.7116 - val_loss: 144.7783\n","Epoch 81/100\n","1875/1875 [==============================] - 8s 4ms/step - loss: 142.6468 - val_loss: 144.6641\n","Epoch 82/100\n","1875/1875 [==============================] - 8s 4ms/step - loss: 142.6089 - val_loss: 144.5801\n","Epoch 83/100\n","1875/1875 [==============================] - 8s 4ms/step - loss: 142.5903 - val_loss: 144.5565\n","Epoch 84/100\n","1875/1875 [==============================] - 8s 4ms/step - loss: 142.5556 - val_loss: 144.6215\n","Epoch 85/100\n","1875/1875 [==============================] - 8s 4ms/step - loss: 142.5426 - val_loss: 144.6276\n","Epoch 86/100\n","1875/1875 [==============================] - 8s 4ms/step - loss: 142.4849 - val_loss: 144.6281\n","Epoch 87/100\n","1875/1875 [==============================] - 8s 4ms/step - loss: 142.4780 - val_loss: 144.5118\n","Epoch 88/100\n","1875/1875 [==============================] - 8s 4ms/step - loss: 142.4492 - val_loss: 144.5258\n","Epoch 89/100\n","1875/1875 [==============================] - 8s 4ms/step - loss: 142.4130 - val_loss: 144.5294\n","Epoch 90/100\n","1875/1875 [==============================] - 8s 4ms/step - loss: 142.3701 - val_loss: 144.3222\n","Epoch 91/100\n","1875/1875 [==============================] - 8s 4ms/step - loss: 142.3708 - val_loss: 144.5715\n","Epoch 92/100\n","1875/1875 [==============================] - 8s 4ms/step - loss: 142.3378 - val_loss: 144.4745\n","Epoch 93/100\n","1875/1875 [==============================] - 8s 4ms/step - loss: 142.3087 - val_loss: 144.6283\n","Epoch 94/100\n","1875/1875 [==============================] - 8s 4ms/step - loss: 142.2634 - val_loss: 144.5271\n","Epoch 95/100\n","1875/1875 [==============================] - 8s 4ms/step - loss: 142.2438 - val_loss: 144.4693\n","Epoch 96/100\n","1875/1875 [==============================] - 8s 4ms/step - loss: 142.2114 - val_loss: 144.2991\n","Epoch 97/100\n","1875/1875 [==============================] - 8s 4ms/step - loss: 142.1932 - val_loss: 144.3207\n","Epoch 98/100\n","1875/1875 [==============================] - 8s 4ms/step - loss: 142.1853 - val_loss: 144.5853\n","Epoch 99/100\n","1875/1875 [==============================] - 8s 4ms/step - loss: 142.1597 - val_loss: 144.3332\n","Epoch 100/100\n","1875/1875 [==============================] - 8s 4ms/step - loss: 142.1251 - val_loss: 144.3431\n"]},{"output_type":"execute_result","data":{"text/plain":[""]},"metadata":{},"execution_count":29}]},{"cell_type":"code","source":["# prediction\n","pred_ = vae.predict(x_test)"],"metadata":{"id":"heuHkUlGGOHO","executionInfo":{"status":"ok","timestamp":1656001630959,"user_tz":240,"elapsed":337,"user":{"displayName":"Yiqiao Yin","userId":"17143243938280119775"}}},"execution_count":30,"outputs":[]},{"cell_type":"code","source":["# import \n","import matplotlib.pyplot as plt"],"metadata":{"id":"RG8ooW_QR0K2","executionInfo":{"status":"ok","timestamp":1656001631307,"user_tz":240,"elapsed":349,"user":{"displayName":"Yiqiao Yin","userId":"17143243938280119775"}}},"execution_count":31,"outputs":[]},{"cell_type":"code","source":["# Use Matplotlib (don't ask)\n","n = 10 # How many digits we will display\n","plt.figure(figsize=(20, 4))\n","for i in range(n):\n"," # Display original\n"," ax = plt.subplot(2, n, i + 1)\n"," plt.imshow(x_test[i].reshape(28, 28))\n"," plt.gray()\n"," ax.get_xaxis().set_visible(False)\n"," ax.get_yaxis().set_visible(False)\n","\n"," # Display reconstruction\n"," ax = plt.subplot(2, n, i + 1 + n)\n"," plt.imshow(pred_[i].reshape(28, 28))\n"," plt.gray()\n"," ax.get_xaxis().set_visible(False)\n"," ax.get_yaxis().set_visible(False)\n","plt.show()"],"metadata":{"colab":{"base_uri":"https://localhost:8080/","height":248},"id":"Tfk02IrORu6o","executionInfo":{"status":"ok","timestamp":1656001631974,"user_tz":240,"elapsed":668,"user":{"displayName":"Yiqiao Yin","userId":"17143243938280119775"}},"outputId":"debf656f-5293-4d44-a166-999dbd6959af"},"execution_count":32,"outputs":[{"output_type":"display_data","data":{"text/plain":["
"],"image/png":"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URifCqOpTpriMnbs2Gi7Tz75JMTr168Psb9P6XPpP//5z2jdjBkzQvzKK6+EeMqUKdF2H330UeLno3A6nYJZ3Mb0WdNfE4U64IADQvzZZ59F6+bOnRvil156KVqn19ynn37aoO8uBCNtAAAAAAAAMoiXNgAAAAAAABnESxsAAAAAAIAMatQ5bbTEt5lZv379Qjx79uxoXa9evUKcllc8dOjQEC9dujTESSX66qJ5bKtXrw6xlrP2lixZEi1X65w2SuevaKjLLrssxD169EjcTnNJ61pGdl1++eUh9tcM7ag0xowZE2Ityd1QWtp0w4YN0bpOnTqFWMvOTpw4Mdpu22233er9yDufz61lmxcsWBDiX/7yl2Xbp5NPPrls34XN7bvvvtHywIEDE7fVZ5vHH3+8ZPuUF23atImWv/rVryZue/7554dYnxtLTeexeeqppxK383Pa+PkgYXbppZeGWEu4F8rP03bMMceE2JcN1/lvSjkHRl6lzTOz3377hVhLPXsTJkwIsf6uXLRoUbRdx44dQ6xzmZoVZx5AbE7fB1x88cUh9m1s1113rfPv33rrrWj5xRdfDPGbb74ZrdPfIDq34pAhQ6LttE847rjjonXTpk0LsZYNLzZG2gAAAAAAAGQQL20AAAAAAAAyqFHTo55++unUZeVLtX3Jlxvt379/iHWY0+DBgwver48//jjE8+bNC7FP2dKhUjo0HVvnhBNOCLGWztxhhx2i7VatWhXi//mf/4nWffjhhyXaO2ytzp07R8uDBg0KsbY3M0ojFsuhhx4aLe+zzz4h1uG9hQ719cM/dXiyls40Mzv88MNDnFaO+L/+679CPHLkyIL2o9pceeWV0bIOEdeh+D5Frdj03uevLYaLl1dayo7n0wiQ7je/+U20/O///u8h1udLM7P77ruvLPvkDR8+PMR77LFHtO6vf/1riP/2t7+Va5cqhqbumpmde+65dW43ffr0aHnlypUhPvLIIxM/v3nz5iHW1Cszs7vuuivEb7/99pZ3tsr55/+77747xJoOZRanB6elDCqfEqX89Bcovj/96U/Rsqa1pZXv1vcGr7/+eoh//OMfR9vp73rvwAMPDLE+h952223Rdvp+QfsAM7Obb745xA888ECIi50qy0gbAAAAAACADOKlDQAAAAAAQAY1anpUMaxbty5afvbZZ+vcLi31Ko0O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\n"},"metadata":{"needs_background":"light"}}]},{"cell_type":"markdown","source":["Investigation ends here."],"metadata":{"id":"mAFw6BJMewIs"}}]}