{"cells":[{"metadata":{"id":"1_aSvteS56_A"},"cell_type":"markdown","source":"v9 latent_dim = 20 -> 200, dropout_rate = 0.4 -> 0.3\n****\nv12 n_epochs = 20 -> 225\n***\nv15 remove layers, image_size 128 -> 64, trainable_params 6e+6 -> 2e+6, n_epochs = 200 -> 50\n***\nv17 add batch normalization\n***\nv18 change data load method because ImageDataGenerator is suspected of malfunctioning\n***\nchange vae model"},{"metadata":{"id":"PBJJGXV256_G"},"cell_type":"markdown","source":"## Import modules"},{"metadata":{"_uuid":"a6775e9d-395e-4ff6-a885-42d0d08e4765","_cell_guid":"22171281-ceae-46ac-91ea-4ae56b412424","trusted":true,"id":"DsLUt-Wq56_H"},"cell_type":"code","source":"import os\nimport glob\n\nimport numpy as np\nimport pandas as pd\nimport matplotlib.pyplot as plt\n\nimport warnings\nwarnings.filterwarnings(\"ignore\")\n\nfrom sklearn.model_selection import train_test_split\n\nimport tensorflow as tf\n\nfrom tensorflow.keras.callbacks import ModelCheckpoint, ReduceLROnPlateau, EarlyStopping\nfrom tensorflow.keras.optimizers import Adam","execution_count":null,"outputs":[]},{"metadata":{"id":"dRENAXdl56_I"},"cell_type":"markdown","source":"## Configuration class"},{"metadata":{"trusted":true,"id":"uXBPOAK656_I","executionInfo":{"status":"ok","timestamp":1613598437532,"user_tz":-180,"elapsed":58839,"user":{"displayName":"Klyatiy Margenal","photoUrl":"https://lh3.googleusercontent.com/a-/AOh14GggSMUrFR8x93YcrHDOltIcbal70uWYj-MpQub-=s64","userId":"08107893185882164888"}},"outputId":"f8cc5474-0b7d-486d-c3b0-3e71c8bf25fc"},"cell_type":"code","source":"class Config:\n    seed = 44\n    n_epochs = 50\n    batch_size = 32\n    dropout_rate = 0.3\n    latent_space_dim = 200\n        \n    validation_rate = 0.2\n    \n    image_size = 128\n    channels = 3\n    \n    \n    optimizer = 'adam'\n    \n    reduce_lr = ReduceLROnPlateau(monitor='val_loss',\n                                  mode='auto',\n                                  factor=0.8,\n                                  patience=2,\n                                  epsilon=1e-4,\n                                  coldown=5,\n                                  min_lr=1e-5,\n                                  verbose=1)\n    \n    checkpoint_best = ModelCheckpoint('best_model.h5',\n                                      monitor='val_loss',\n                                      mode='min',\n                                      verbose=1,\n                                      save_best_only=True,\n                                      save_weights_only=False)\n    \n    checkpoint_last = ModelCheckpoint('last_model.h5',\n                                      monitor='val_loss',\n                                      mode='min',\n                                      verbose=1,\n                                      save_best_only=False,\n                                      save_weights_only=False)\n  \n    \n    callbacks = [reduce_lr, checkpoint_best, checkpoint_last]\n    \n    paths = {'images_folder': '/kaggle/input/celeba-dataset/img_align_celeba/img_align_celeba/',\n             'list_attributes_file': '/kaggle/input/celeba-dataset/list_attr_celeba.csv'}","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"id":"SSVw6p-w56_J"},"cell_type":"code","source":"config = Config()","execution_count":null,"outputs":[]},{"metadata":{"id":"0jCaoMMi56_K"},"cell_type":"markdown","source":"## Data load"},{"metadata":{"trusted":true,"id":"CkQAiov-56_K"},"cell_type":"code","source":"def build_decoder(test=False, out_size=(config.image_size, config.image_size)):\n    def decoder(path):\n        img = file_bytes = tf.io.read_file(path)\n        img = tf.image.decode_jpeg(file_bytes, channels=config.channels)  \n        img = tf.image.resize(img, (config.image_size, config.image_size))\n        img = tf.cast(img, tf.float32) / 255.0\n        return img\n    def decoder_train(path):\n        return decoder(path), decoder(path)\n\n    return decoder if test else decoder_train","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"id":"IXS9TcTR56_K"},"cell_type":"code","source":"def build_dataset(paths, test=False, shuffle=1, batch_size=1):\n    AUTO = tf.data.experimental.AUTOTUNE\n    decoder = build_decoder(test)\n\n    dset = tf.data.Dataset.from_tensor_slices(paths)\n    dset = dset.map(decoder, num_parallel_calls=AUTO)\n    \n    dset = dset.shuffle(shuffle)\n    dset = dset.batch(batch_size)\n    return dset","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"id":"H57ZaqSj56_L"},"cell_type":"code","source":"image_paths = glob.glob(config.paths['images_folder'] + '*.jpg')\n\ntrain_paths, valid_paths, _, _ = train_test_split(image_paths, image_paths, test_size=config.validation_rate, shuffle=True)\n\ntrain_dataset = build_dataset(train_paths, batch_size=config.batch_size)\nvalid_dataset = build_dataset(valid_paths, batch_size=config.batch_size)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"id":"_I-rqmFX56_L","executionInfo":{"status":"ok","timestamp":1613598448413,"user_tz":-180,"elapsed":69668,"user":{"displayName":"Klyatiy Margenal","photoUrl":"https://lh3.googleusercontent.com/a-/AOh14GggSMUrFR8x93YcrHDOltIcbal70uWYj-MpQub-=s64","userId":"08107893185882164888"}},"outputId":"0c7cd8e1-e8e8-42be-c79c-a120d6f6f90e"},"cell_type":"code","source":"plt.figure(figsize=(4,4))\nfor n, (image, label) in enumerate(train_dataset.unbatch().take(1)):\n    f, (ax1, ax2) = plt.subplots(1, 2) \n    \n    ax1.imshow(image)\n    ax2.imshow(label)\nplt.show()","execution_count":null,"outputs":[]},{"metadata":{"id":"8VW7VrCl56_P"},"cell_type":"markdown","source":"\n## Model architecture"},{"metadata":{"trusted":true,"id":"mf4M5Oua56_Q"},"cell_type":"code","source":"from tensorflow.keras.models import Model\nfrom tensorflow.keras.layers import Input, Conv2D, Dropout, BatchNormalization, MaxPooling2D\nfrom tensorflow.keras.layers import Flatten, Dense, Lambda, UpSampling2D, Conv2DTranspose, Reshape\n\nfrom tensorflow.keras.utils import plot_model\nfrom tensorflow.keras.losses import binary_crossentropy\nfrom tensorflow.keras import backend as K","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"id":"GtO6vyM656_Q"},"cell_type":"code","source":"def sampling(args):\n    z_mean, z_log_var = args\n    batch = K.shape(z_mean)[0]\n    \n    epsilon = K.random_normal(shape=(batch, config.latent_space_dim))\n    return z_mean + K.exp(0.5 * z_log_var) * epsilon","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"id":"BypuPTCu56_R"},"cell_type":"code","source":"def VAE(input_shape=(config.image_size, config.image_size, config.channels)):\n    \n    #Encoder\n    input_encoder = Input(shape=(input_shape))\n    x = Conv2D(32, (3, 3), padding='same', activation='relu')(input_encoder)\n    x = BatchNormalization()(x)\n    x = MaxPooling2D((2, 2))(x)    \n    x = Conv2D(32, (3, 3), padding='same', activation='relu')(x)\n    x = BatchNormalization()(x)\n    x = MaxPooling2D((2, 2))(x)   \n    x = Conv2D(64, (3, 3), padding='same', activation='relu')(x)\n    x = BatchNormalization()(x)\n    x = MaxPooling2D((2, 2))(x)   \n    x = Conv2D(64, (3, 3), padding='same', activation='relu')(x)\n    x = BatchNormalization()(x)\n    x = MaxPooling2D((2, 2))(x)    \n    x = Flatten()(x)\n\n    latent_mu = Dense(config.latent_space_dim, name='latent_mean')(x)\n    latent_log_var = Dense(config.latent_space_dim, name='latent_log_var')(x)\n    latent_sample = Lambda(sampling)([latent_mu, latent_log_var])\n\n    encoder = Model(input_encoder, [latent_mu, latent_log_var, latent_sample], name='encoder')\n\n    latent_input = Input(shape=(config.latent_space_dim,), name='decoder_input')\n    x = Dense(8 * 8 * config.image_size)(latent_input)\n    x = Reshape((8, 8, config.image_size))(x)\n    x = UpSampling2D((2, 2))(x)\n    X = Conv2DTranspose(64, (3, 3), padding='same', activation='relu')(x)\n    x = BatchNormalization()(x)\n    x = UpSampling2D((2, 2))(X)\n    X = Conv2DTranspose(64, (3, 3), padding='same', activation='relu')(x)\n    x = BatchNormalization()(x)\n    x = UpSampling2D((2, 2))(x)\n    X = Conv2DTranspose(32, (3, 3), padding='same', activation='relu')(x)\n    x = BatchNormalization()(x)\n    x = UpSampling2D((2, 2))(x)\n    X = Conv2DTranspose(32, (3, 3), padding='same', activation='relu')(x)\n    x = BatchNormalization()(x)\n    output_decoder = Conv2DTranspose(config.channels, (3, 3), activation='sigmoid', padding='same')(x)\n    \n    decoder = Model(latent_input, output_decoder, name='decoder')\n\n    output_vae = decoder(encoder(input_encoder)[2])\n    vae = Model(input_encoder, output_vae, name ='vae')\n    \n    \n    reconstruction_loss = binary_crossentropy(input_encoder, output_vae) * (config.image_size * config.image_size)\n    reconstruction_loss = K.mean(reconstruction_loss)\n\n    kl_loss = 1 + latent_log_var - K.square(latent_mu) - K.exp(latent_log_var)\n    kl_loss = K.sum(kl_loss, axis=-1)\n    kl_loss *= -0.5\n\n    vae_loss = K.mean(reconstruction_loss + kl_loss)\n\n    vae.add_loss(vae_loss)  \n    vae.add_metric(reconstruction_loss, name='reconstruction_loss')\n    vae.add_metric(kl_loss, name='kl_divergence_loss')\n\n    return vae, encoder, decoder","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"id":"Qk3SUXrm56_S","executionInfo":{"status":"ok","timestamp":1613598449035,"user_tz":-180,"elapsed":70259,"user":{"displayName":"Klyatiy Margenal","photoUrl":"https://lh3.googleusercontent.com/a-/AOh14GggSMUrFR8x93YcrHDOltIcbal70uWYj-MpQub-=s64","userId":"08107893185882164888"}},"outputId":"6f9c8776-3b42-41d2-ad89-e1b7f61d5ac3"},"cell_type":"code","source":"vae, encoder, decoder = VAE()\nvae.compile(optimizer=config.optimizer)\n    \nvae.build(input_shape=(config.image_size, config.image_size, config.channels))\nencoder.summary()\ndecoder.summary()\nvae.summary()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"id":"a6cT1rhS56_U","executionInfo":{"status":"ok","timestamp":1613598450243,"user_tz":-180,"elapsed":71460,"user":{"displayName":"Klyatiy Margenal","photoUrl":"https://lh3.googleusercontent.com/a-/AOh14GggSMUrFR8x93YcrHDOltIcbal70uWYj-MpQub-=s64","userId":"08107893185882164888"}},"outputId":"8389a5fa-b7a8-4cfc-989b-061fc462bf49"},"cell_type":"code","source":"plot_model(encoder, to_file='encoder.png', show_shapes=True, show_layer_names=True)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"id":"gAft2DBN56_U","executionInfo":{"status":"ok","timestamp":1613598450244,"user_tz":-180,"elapsed":71455,"user":{"displayName":"Klyatiy Margenal","photoUrl":"https://lh3.googleusercontent.com/a-/AOh14GggSMUrFR8x93YcrHDOltIcbal70uWYj-MpQub-=s64","userId":"08107893185882164888"}},"outputId":"ad01f0a0-61c7-4366-e477-b6eb65bbbaaa"},"cell_type":"code","source":"plot_model(decoder, to_file='decoder.png', show_shapes=True, show_layer_names=True)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"id":"Ua9rDXHp56_U"},"cell_type":"code","source":"if os.path.isfile(\"best_model.h5\"):\n    vae.load_weights('best_model.h5')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"id":"d0qhU_SN56_V","executionInfo":{"status":"ok","timestamp":1613618261582,"user_tz":-180,"elapsed":14032711,"user":{"displayName":"Klyatiy Margenal","photoUrl":"https://lh3.googleusercontent.com/a-/AOh14GggSMUrFR8x93YcrHDOltIcbal70uWYj-MpQub-=s64","userId":"08107893185882164888"}},"outputId":"865970c2-eab4-4ce0-d251-93af0d97184f"},"cell_type":"code","source":"vae.fit(train_dataset,\n        epochs=config.n_epochs,\n        callbacks=config.callbacks,\n        validation_data=valid_dataset)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"id":"YdYHAtq456_V"},"cell_type":"code","source":"vae.load_weights('./best_model.h5')","execution_count":null,"outputs":[]},{"metadata":{"id":"BxUAML3G56_V"},"cell_type":"markdown","source":"## Reconstruction result"},{"metadata":{"id":"JXQE9C3_kQW4","trusted":true},"cell_type":"code","source":"test_dataset = build_dataset(valid_paths, test=True)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"id":"Tfh0vyf356_V","executionInfo":{"status":"ok","timestamp":1613623995432,"user_tz":-180,"elapsed":3842,"user":{"displayName":"Klyatiy Margenal","photoUrl":"https://lh3.googleusercontent.com/a-/AOh14GggSMUrFR8x93YcrHDOltIcbal70uWYj-MpQub-=s64","userId":"08107893185882164888"}},"outputId":"cb01c85a-dadf-4e1f-f838-6231d0f40ba1"},"cell_type":"code","source":"data = list(test_dataset.take(20))\n\nfig = plt.figure(figsize=(30, 10))\nfor n in range(0, 20, 2):\n    image = vae.predict(data[n])\n    \n    plt.subplot(2, 10, n + 1)\n    plt.imshow(np.squeeze(data[n]))\n    plt.title('original image')\n    \n    plt.subplot(2, 10, n + 2)\n    plt.imshow(np.squeeze(image))\n    plt.title('reconstruct')\n    \nplt.show()","execution_count":null,"outputs":[]},{"metadata":{"id":"R55-wxYT56_W"},"cell_type":"markdown","source":"## Generation new faces"},{"metadata":{"trusted":true,"id":"KcaLyZ7g56_W","executionInfo":{"status":"ok","timestamp":1613618268438,"user_tz":-180,"elapsed":2326,"user":{"displayName":"Klyatiy Margenal","photoUrl":"https://lh3.googleusercontent.com/a-/AOh14GggSMUrFR8x93YcrHDOltIcbal70uWYj-MpQub-=s64","userId":"08107893185882164888"}},"outputId":"ddb2755f-ac99-47ce-a490-551c8d0ca0ea"},"cell_type":"code","source":"n_show_new_images = 60\nrandom_codes = np.random.normal(size=(n_show_new_images, config.latent_space_dim))\nnew_faces = decoder.predict(np.array(random_codes))\n\nfig = plt.figure(figsize=(30, 15))\n\nfor i in range(n_show_new_images):\n    ax = fig.add_subplot(6, 10, i+1)\n    ax.imshow(new_faces[i])\n    ax.axis('off')\nplt.show()","execution_count":null,"outputs":[]},{"metadata":{"id":"kej5u_EYctIo"},"cell_type":"markdown","source":"## Show latent space distribution"},{"metadata":{"id":"pgOTJESoogwi","executionInfo":{"status":"ok","timestamp":1613623731232,"user_tz":-180,"elapsed":83075,"user":{"displayName":"Klyatiy Margenal","photoUrl":"https://lh3.googleusercontent.com/a-/AOh14GggSMUrFR8x93YcrHDOltIcbal70uWYj-MpQub-=s64","userId":"08107893185882164888"}},"outputId":"22005ded-a86c-4a74-f52f-0ab003153a64","trusted":true},"cell_type":"code","source":"z_test = encoder.predict(test_dataset, verbose = 1)","execution_count":null,"outputs":[]},{"metadata":{"id":"gV2Llwa1e3Cn","executionInfo":{"status":"ok","timestamp":1613623975835,"user_tz":-180,"elapsed":6898,"user":{"displayName":"Klyatiy Margenal","photoUrl":"https://lh3.googleusercontent.com/a-/AOh14GggSMUrFR8x93YcrHDOltIcbal70uWYj-MpQub-=s64","userId":"08107893185882164888"}},"outputId":"4dcdfdf0-13fb-44f6-d643-bb03d2cb2220","trusted":true},"cell_type":"code","source":"from scipy.stats import norm\n\nz_test_samples = z_test[2]\nx = np.linspace(-3, 3, 100)\n\nfig = plt.figure(figsize=(30, 15))\nfig.subplots_adjust(hspace=0.6, wspace=0.4)\n\nfor i in range(50):\n    ax = fig.add_subplot(5, 10, i+1)\n    ax.hist(z_test_samples[:, i], density=True, bins = 20)\n\n    ax.text(0.5, -0.35, str(i), fontsize=10, ha='center', transform=ax.transAxes)\n    ax.plot(x, norm.pdf(x))\n\nplt.show()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"id":"mwsaQPpV56_X"},"cell_type":"code","source":"","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}