Conditional Variational AutoEncoder

Viewed 301

I tried to implement conditional variational auto encoder, using variational auto encoder at the Keras website : https://keras.io/examples/generative/vae/

I added the second input to the model but I don't know how to fit two inputs to encoder. I think custom train_step() function has some problem and should be updated according to encoder that has two inputs.

I got this error:

ValueError: Layer decoder expects 2 input(s), but it received 1 input tensors. Inputs received: [<tf.Tensor 'encoder/12_enc_sampling/add:0' shape=(8, 8) dtype=float32>]

and here is my script:

import numpy as np
import tensorflow as tf
from tensorflow import keras
from tensorflow.keras import layers
import matplotlib.pyplot as plt

from tensorflow.keras.utils import plot_model


from VAEfunctions import track_loss, sample_decoding, test, latent_space_mds

# Add Graphviz to windows PATH for plot_model
import os
# os.environ["PATH"] += os.pathsep + 'C:/Program Files/Graphviz/bin/'

print("tensorflow version:",tf.__version__)

# =====================================Set initial parameters ==============================
epoch = 3
batch_size = 8
latent_dim = 8
random_sample_points = 3    #Number of random sample points from latent space

# ==========================================================================
# for seed_value in range(7, 8):     # change the seed to find the best seed_value
# Seed value
seed_value = 7  #7  #8good

# 1. Set `PYTHONHASHSEED` environment variable at a fixed value
import os
os.environ['PYTHONHASHSEED'] = str(seed_value)

# 2. Set `python` built-in pseudo-random generator at a fixed value
import random
random.seed(seed_value)

# 3. Set `numpy` pseudo-random generator at a fixed value
import numpy as np
np.random.seed(seed_value)

# 4. Set the `tensorflow` pseudo-random generator at a fixed value
import tensorflow as tf
tf.random.set_seed(seed_value)
# for later versions:
# tf.compat.v1.set_random_seed(seed_value)

# 5. Configure a new global `tensorflow` session

session_conf = tf.compat.v1.ConfigProto(intra_op_parallelism_threads=1, inter_op_parallelism_threads=1)
sess = tf.compat.v1.Session(graph=tf.compat.v1.get_default_graph(), config=session_conf)
tf.compat.v1.keras.backend.set_session(sess)

# ========================================Load data===============================

x_train = np.load('data_x_train_3D_all_par_3D_800_64_64_64_1.npy')  # load data, #shape:(800,64,64,64,1)
x_test = np.load('data_x_test_3D_all_par_3D_200_64_64_64_1.npy')
x = np.load('data_x_3D_all_par_3D_1000_64_64_64_1.npy')
input_num = x_train.shape[0]
input_d1 = x_train.shape[1]
input_d2 = x_train.shape[2]
input_d3 = x_train.shape[3]
input_channels = x_train.shape[4]


# ================================== Load one_hot_vector (Parameters) ===================

one_hot_vec_train = np.load('one_hot_vec.npy')[:800]
print(one_hot_vec_train.shape)

# ======================View a few images=======================
print("min of x_train is:", np.min(x_train), "max of x_train is:", np.max(x_train))
print("min of x is:", np.min(x), "max of x is:", np.max(x))
plt.figure(10)
fig, axes = plt.subplots(2, 2)
# fig.tight_layout()
for ax in axes.flat:
    i = 1
    im = ax.imshow(x_train[100*i][31][:][:], vmin=0, vmax=1)
    i = i+1
cbar_ax = fig.add_axes([0.9, 0.15, 0.03, 0.70])
fig.colorbar(im, cax=cbar_ax)
plt.suptitle('Slide[31] of four input samples')
plt.show()

""""****************************** Variational Auto Encoder Model *************************"""

# ======================================= sampling layer ===============================================

class Sampling(layers.Layer):
    """Uses (z_mean, z_log_var) to sample z, the vector encoding a digit."""
    # tf.random.set_seed(0)
    def call(self, inputs):
        z_mean, z_log_var = inputs
        batch = tf.shape(z_mean)[0]
        dim = tf.shape(z_mean)[1]
        epsilon = tf.keras.backend.random_normal(shape=(batch, dim))
        return z_mean + tf.exp(0.5 * z_log_var) * epsilon


# ===================== Define the VAE as a `Model` with a custom `train_step` ==============================


class CVAE(keras.Model):
    # tf.random.set_seed(0)
    def __init__(self, encoder, decoder, **kwargs):
        super(CVAE, self).__init__(**kwargs)
        self.encoder = encoder
        self.decoder = decoder
        self.total_loss_tracker = keras.metrics.Mean(name="total_loss")
        self.reconstruction_loss_tracker = keras.metrics.Mean(
            name="reconstruction_loss"
        )
        self.kl_loss_tracker = keras.metrics.Mean(name="kl_loss")
        self.rec_tracker = keras.metrics.Mean(name="rec")       ####

    @property
    def metrics(self):
        return [
            self.total_loss_tracker,
            self.reconstruction_loss_tracker,
            self.kl_loss_tracker,
            self.rec_tracker,           ####
        ]

    def train_step(self, data):
        with tf.GradientTape() as tape:
            z_mean, z_log_var, z = self.encoder(data)
            reconstruction = self.decoder(z)
            reconstruction_loss = tf.reduce_mean(
                tf.reduce_sum(
                    keras.losses.mean_squared_error(data, reconstruction), axis=(1, 2, 3)
                )
            )

            rec = tf.reduce_mean(                           #####
                tf.reduce_mean(
                    keras.losses.mean_squared_error(data, reconstruction), axis=(1, 2, 3)
                )
            )

            kl_loss = -0.5 * (1 + z_log_var - tf.square(z_mean) - tf.exp(z_log_var))
            kl_loss = tf.reduce_mean(tf.reduce_sum(kl_loss, axis=1))
            total_loss = reconstruction_loss + kl_loss
        grads = tape.gradient(total_loss, self.trainable_weights)
        self.optimizer.apply_gradients(zip(grads, self.trainable_weights))
        self.total_loss_tracker.update_state(total_loss)
        self.reconstruction_loss_tracker.update_state(reconstruction_loss)
        self.kl_loss_tracker.update_state(kl_loss)
        self.rec_tracker.update_state(rec)          ####
        return {
            "loss": self.total_loss_tracker.result(),
            "reconstruction_loss": self.reconstruction_loss_tracker.result(),
            "kl_loss": self.kl_loss_tracker.result(),
            "rec": self.rec_tracker.result()           #####
        }


# ===================================== Build the encoder ====================================
input_shape = (input_d1, input_d2, input_d3, input_channels)        # input_shape=(64, 64, 64, 1)

encoder_input = keras.Input(shape=input_shape, name="enc_input")
input_one_hot_vec = keras.Input(shape=(27, ), name="one_hot_vec_input")           # one_hot_vect input layer shape=(27)

x = layers.Conv3D(32, 3, activation="relu", padding="same", name="1_enc_conv")(encoder_input)  # delete strides=2
x = layers.MaxPooling3D(name="2_enc_MaxPool")(x)
x = layers.Dropout(0.2)(x)
x = layers.Conv3D(32, 3, activation="relu", padding="same", name="3_enc_conv")(x)
x = layers.MaxPooling3D(name="4_enc_MaxPool")(x)
x = layers.Dropout(0.2)(x)
x = layers.Conv3D(32, 3, activation="relu", padding="same", name="5_enc_conv")(x)
x = layers.MaxPooling3D(name="6_enc_MaxPool")(x)
x = layers.Dropout(0.2)(x)
x = layers.Conv3D(32, 3, activation="relu", padding="same", name="7_en_conv")(x)
enc_last_conv = x.shape
x = layers.Flatten(name="8_enc_flat")(x)

# ============Add one_hot_vector here: ==============
concat_layer_enc = layers.concatenate([x, input_one_hot_vec], axis=1)                 # ====== concat one_hot_vec here

x = layers.Dense(16, activation="relu", name="9_enc_dense")(concat_layer_enc)
z_mean = layers.Dense(latent_dim, name="10_enc_z_mean")(x)
z_log_var = layers.Dense(latent_dim, name="11_enc_z_log_var")(x)
z = Sampling(name="12_enc_sampling")([z_mean, z_log_var])
encoder = keras.Model([encoder_input, input_one_hot_vec], [z_mean, z_log_var, z], name="encoder")
print(encoder.summary())
plot_model(encoder, to_file='Plot_Model/CVAE/encoder.jpg', show_shapes=True)
print("encoder model created")

# ===================================== Build the decoder ====================


latent_input = keras.Input(shape=(latent_dim,), name="dec_input")
concat_layer_dec = layers.concatenate([latent_input, input_one_hot_vec], axis=1)     # ======= concat one_hot_vec here

x = layers.Dense(enc_last_conv[1] * enc_last_conv[2] * enc_last_conv[3] * enc_last_conv[4], activation="relu", name="1_dec_dense")(concat_layer_dec)
x = layers.Reshape((enc_last_conv[1], enc_last_conv[2], enc_last_conv[3], enc_last_conv[4]), name="2_dec")(x)
x = layers.Conv3DTranspose(32, 3, activation="relu", padding="same", name="3_dec_conv")(x)
x = layers.UpSampling3D(name="4_dec_MaxPool")(x)
x = layers.Conv3DTranspose(32, 3, activation="relu", padding="same", name="5_dec_conv")(x)
x = layers.UpSampling3D(name="6_dec_MaxPool")(x)
x = layers.Conv3DTranspose(32, 3, activation="relu", padding="same", name="7_dec_conv")(x)
x = layers.UpSampling3D(name="8_dec_MaxPool")(x)
x = layers.Conv3DTranspose(32, 3, activation="relu", padding="same", name="9_dec_conv")(x)
decoder_outputs = layers.Conv3DTranspose(1, 3, activation="sigmoid", padding="same", name="10_dec_conv_out")(x)
decoder = keras.Model([latent_input, input_one_hot_vec], decoder_outputs, name="decoder")
print(decoder.summary())
plot_model(decoder, to_file='Plot_Model/CVAE/decoder.jpg', show_shapes=True)

# =========================================== **Train the CVAE** ==================================================

random.seed(seed_value)
cvae = CVAE(encoder, decoder)
cvae.compile(optimizer=keras.optimizers.Adam())
history = cvae.fit([x_train, one_hot_vec_train], epochs=epoch, batch_size=batch_size)        

track_loss(history, epoch, batch_size, latent_dim, random_sample_points, seed_value)
random_sample_list = latent_space_mds(cvae, x_train, epoch, latent_dim, random_sample_points, seed_value)
sample_decoding(cvae, epoch, latent_dim, random_sample_points, random_sample_list, seed_value)
test(cvae, x_test, 4, epoch, latent_dim)

# end of seed loop

print("finish")

Here is the model that I created: Encoder model:

encoder model

and

Here is the decoder model:

decoder model

Thanks!

0 Answers
Related