No account yet ?
Variational autoencoders make it possible to rewrite statistical inference problems into statistical optimization problems.
Variational autoencoders are intended to map the input variable to a multivariate latent distribution.
This type of model was initially designed for unsupervised learning, its effectiveness has been proven for semi-supervised learning and supervised learning.
Tested in Anaconda and Python 3.7
import numpy as np import matplotlib.pyplot as plt from scipy.stats import norm from keras.layers import Input, Dense, Lambda from keras.models import Model from keras import backend as K from keras import objectives from keras.datasets import mnist # Hyperparameters batch_size = 100 original_dim = 784 latent_dim = 2 intermediate_dim = 256 nb_epoch = 10 epsilon_std = 1.0 #encoder ''' The encoder's jo is to map inputs to our hidden distribution parameters. We take the input and send it through a dense fully connected layer with ReLU (classic non-linearity to squash dimensionality). Next, we convert the input data into two parameters in the hidden space. We predefine the size using dense, fully connected layers — z mean and z log sigma. ''' x = Input(batch_shape = (batch_size, original_dim)) h = Dense(intermediate_dim, activation = 'relu')(x) z_mean = Dense(latent_dim)(h) z_log_var = Dense(latent_dim)(h) print(z_mean) print(z_log_var) ''' The decoder(in the next block) will take z as its input and output the parameters to the probability distribution of the data. Epsilon is a random normal tensor ''' def sampling(args): z_mean, z_log_var = args epsilon = K.random_normal(shape=(batch_size, latent_dim), mean=0.) return z_mean + K.exp(z_log_var / 2) * epsilon # note that "output_shape" isn't necessary with the TensorFlow backend z = Lambda(sampling, output_shape=(latent_dim,))([z_mean, z_log_var]) #latent hidden state print(z) ''' we first initialize it with two fully connected layers and their own respective activation functions. Because the data is extracted from a small dimensionality to a larger one, some of it will be lost in the reconstruction process. ''' #decoder # we instantiate these layers separately so as to reuse them later decoder_h = Dense(intermediate_dim, activation='relu') decoder_mean = Dense(original_dim, activation='sigmoid') h_decoded = decoder_h(z) x_decoded_mean = decoder_mean(h_decoded) print(x_decoded_mean) ''' The first term below measures the reconstruction loss. If the decoder output is bad at reconstructing data, the cost in terms of loss will be considerable at this point. The next term is a regularizer, meaning it keeps the representation of each digit as diverse as possible. So for instance, if two different people were to write out the digit three, the representations might end up looking very different because, of course, different people write differently. This can be bad, and the regularizer comes to rescue! We penalize bad behaviour (like the example here) and ensure similar representations are close together. Our total loss function is defined as the sum of our reconstruction term, and the KL divergence regularization term. ''' #loss def vae_loss(x, x_decoded_mean): xent_loss = original_dim * objectives.binary_crossentropy(x, x_decoded_mean) kl_loss = - 0.5 * K.sum(1 + z_log_var - K.square(z_mean) - K.exp(z_log_var), axis=-1) return xent_loss + kl_loss vae = Model(x, x_decoded_mean) vae.compile(optimizer='rmsprop', loss=vae_loss) # train the VAE on MNIST digits (x_train, y_train), (x_test, y_test) = mnist.load_data() x_train = x_train.astype('float32') / 255. x_test = x_test.astype('float32') / 255. x_train = x_train.reshape((len(x_train), np.prod(x_train.shape[1:]))) x_test = x_test.reshape((len(x_test), np.prod(x_test.shape[1:]))) vae.fit(x_train, x_train, shuffle=True, nb_epoch=nb_epoch, batch_size=batch_size, validation_data=(x_test, x_test),verbose=1) #plot latent/hidden space # build a model to project inputs on the latent space encoder = Model(x, z_mean) # display a 2D plot of the digit classes in the latent space x_test_encoded = encoder.predict(x_test, batch_size=batch_size) plt.figure(figsize=(6, 6)) plt.scatter(x_test_encoded[:, 0], x_test_encoded[:, 1], c=y_test) plt.colorbar() plt.show() ''' Another way to represent this is to generate digits by scanning the latent plan, sampling latent points at regular intervals and generating the corresponding digit for each of these points like so: ''' # build a digit generator that can sample from the learned distribution decoder_input = Input(shape=(latent_dim,)) _h_decoded = decoder_h(decoder_input) _x_decoded_mean = decoder_mean(_h_decoded) generator = Model(decoder_input, _x_decoded_mean) # display a 2D manifold of the digits n = 15 # figure with 15x15 digits digit_size = 28 figure = np.zeros((digit_size * n, digit_size * n)) # linearly spaced coordinates on the unit square were transformed through the inverse CDF (ppf) of the Gaussian # to produce values of the latent variables z, since the prior of the latent space is Gaussian grid_x = norm.ppf(np.linspace(0.05, 0.95, n)) grid_y = norm.ppf(np.linspace(0.05, 0.95, n)) for i, yi in enumerate(grid_x): for j, xi in enumerate(grid_y): z_sample = np.array([[xi, yi]]) x_decoded = generator.predict(z_sample) digit = x_decoded[0].reshape(digit_size, digit_size) figure[i * digit_size: (i + 1) * digit_size, j * digit_size: (j + 1) * digit_size] = digit plt.figure(figsize=(10, 10)) plt.imshow(figure, cmap='Greys_r') plt.show()
Variational-Auto-Encoders - GitHub
Deep-Recurrent-Attention-Writer - GitHub
Deep-Recurrent-Attention-Writer - GitHub
main.py
Tested in Anaconda and Python 3.7
import os ## GAN Variants from GAN import GAN from CGAN import CGAN from infoGAN import infoGAN from ACGAN import ACGAN from EBGAN import EBGAN from WGAN import WGAN from WGAN_GP import WGAN_GP from DRAGAN import DRAGAN from LSGAN import LSGAN from BEGAN import BEGAN ## VAE Variants from VAE import VAE from CVAE import CVAE from utils import show_all_variables from utils import check_folder import tensorflow as tf import argparse """parsing and configuration""" def parse_args(): desc = "Tensorflow implementation of GAN collections" parser = argparse.ArgumentParser(description=desc) parser.add_argument('--gan_type', type=str, default='GAN', choices=['GAN', 'CGAN', 'infoGAN', 'ACGAN', 'EBGAN', 'BEGAN', 'WGAN', 'WGAN_GP', 'DRAGAN', 'LSGAN', 'VAE', 'CVAE'], help='The type of GAN', required=True) parser.add_argument('--dataset', type=str, default='mnist', choices=['mnist', 'fashion-mnist', 'celebA'], help='The name of dataset') parser.add_argument('--epoch', type=int, default=20, help='The number of epochs to run') parser.add_argument('--batch_size', type=int, default=64, help='The size of batch') parser.add_argument('--z_dim', type=int, default=62, help='Dimension of noise vector') parser.add_argument('--checkpoint_dir', type=str, default='checkpoint', help='Directory name to save the checkpoints') parser.add_argument('--result_dir', type=str, default='results', help='Directory name to save the generated images') parser.add_argument('--log_dir', type=str, default='logs', help='Directory name to save training logs') return check_args(parser.parse_args()) """checking arguments""" def check_args(args): # --checkpoint_dir check_folder(args.checkpoint_dir) # --result_dir check_folder(args.result_dir) # --result_dir check_folder(args.log_dir) # --epoch assert args.epoch >= 1, 'number of epochs must be larger than or equal to one' # --batch_size assert args.batch_size >= 1, 'batch size must be larger than or equal to one' # --z_dim assert args.z_dim >= 1, 'dimension of noise vector must be larger than or equal to one' return args """main""" def main(): # parse arguments args = parse_args() if args is None: exit() # open session models = [GAN, CGAN, infoGAN, ACGAN, EBGAN, WGAN, WGAN_GP, DRAGAN, LSGAN, BEGAN, VAE, CVAE] with tf.Session(config=tf.ConfigProto(allow_soft_placement=True)) as sess: # declare instance for GAN gan = None for model in models: if args.gan_type == model.model_name: gan = model(sess, epoch=args.epoch, batch_size=args.batch_size, z_dim=args.z_dim, dataset_name=args.dataset, checkpoint_dir=args.checkpoint_dir, result_dir=args.result_dir, log_dir=args.log_dir) if gan is None: raise Exception("[!] There is no option for " + args.gan_type) # build graph gan.build_model() # show network architecture show_all_variables() # launch the graph in a session gan.train() print(" [*] Training finished!") # visualize learned generator gan.visualize_results(args.epoch-1) print(" [*] Testing finished!") if __name__ == '__main__': main()
VAE.py
Tested in Anaconda and Python 3.7
#-*- coding: utf-8 -*- from __future__ import division import os import time import tensorflow as tf import numpy as np from ops import * from utils import * import prior_factory as prior class VAE(object): model_name = "VAE" # name for checkpoint def __init__(self, sess, epoch, batch_size, z_dim, dataset_name, checkpoint_dir, result_dir, log_dir): self.sess = sess self.dataset_name = dataset_name self.checkpoint_dir = checkpoint_dir self.result_dir = result_dir self.log_dir = log_dir self.epoch = epoch self.batch_size = batch_size if dataset_name == 'mnist' or dataset_name == 'fashion-mnist': # parameters self.input_height = 28 self.input_width = 28 self.output_height = 28 self.output_width = 28 self.z_dim = z_dim # dimension of noise-vector self.c_dim = 1 # train self.learning_rate = 0.0002 self.beta1 = 0.5 # test self.sample_num = 64 # number of generated images to be saved # load mnist self.data_X, self.data_y = load_mnist(self.dataset_name) # get number of batches for a single epoch self.num_batches = len(self.data_X) // self.batch_size else: raise NotImplementedError # Gaussian Encoder def encoder(self, x, is_training=True, reuse=False): # Network Architecture is exactly same as in infoGAN (https://arxiv.org/abs/1606.03657) # Architecture : (64)4c2s-(128)4c2s_BL-FC1024_BL-FC62*4 with tf.variable_scope("encoder", reuse=reuse): net = lrelu(conv2d(x, 64, 4, 4, 2, 2, name='en_conv1')) net = lrelu(bn(conv2d(net, 128, 4, 4, 2, 2, name='en_conv2'), is_training=is_training, scope='en_bn2')) net = tf.reshape(net, [self.batch_size, -1]) net = lrelu(bn(linear(net, 1024, scope='en_fc3'), is_training=is_training, scope='en_bn3')) gaussian_params = linear(net, 2 * self.z_dim, scope='en_fc4') # The mean parameter is unconstrained mean = gaussian_params[:, :self.z_dim] # The standard deviation must be positive. Parametrize with a softplus and # add a small epsilon for numerical stability stddev = 1e-6 + tf.nn.softplus(gaussian_params[:, self.z_dim:]) return mean, stddev # Bernoulli decoder def decoder(self, z, is_training=True, reuse=False): # Network Architecture is exactly same as in infoGAN (https://arxiv.org/abs/1606.03657) # Architecture : FC1024_BR-FC7x7x128_BR-(64)4dc2s_BR-(1)4dc2s_S with tf.variable_scope("decoder", reuse=reuse): net = tf.nn.relu(bn(linear(z, 1024, scope='de_fc1'), is_training=is_training, scope='de_bn1')) net = tf.nn.relu(bn(linear(net, 128 * 7 * 7, scope='de_fc2'), is_training=is_training, scope='de_bn2')) net = tf.reshape(net, [self.batch_size, 7, 7, 128]) net = tf.nn.relu( bn(deconv2d(net, [self.batch_size, 14, 14, 64], 4, 4, 2, 2, name='de_dc3'), is_training=is_training, scope='de_bn3')) out = tf.nn.sigmoid(deconv2d(net, [self.batch_size, 28, 28, 1], 4, 4, 2, 2, name='de_dc4')) return out def build_model(self): # some parameters image_dims = [self.input_height, self.input_width, self.c_dim] bs = self.batch_size """ Graph Input """ # images self.inputs = tf.placeholder(tf.float32, [bs] + image_dims, name='real_images') # noises self.z = tf.placeholder(tf.float32, [bs, self.z_dim], name='z') """ Loss Function """ # encoding self.mu, sigma = self.encoder(self.inputs, is_training=True, reuse=False) # sampling by re-parameterization technique z = self.mu + sigma * tf.random_normal(tf.shape(self.mu), 0, 1, dtype=tf.float32) # decoding out = self.decoder(z, is_training=True, reuse=False) self.out = tf.clip_by_value(out, 1e-8, 1 - 1e-8) # loss marginal_likelihood = tf.reduce_sum(self.inputs * tf.log(self.out) + (1 - self.inputs) * tf.log(1 - self.out), [1, 2]) KL_divergence = 0.5 * tf.reduce_sum(tf.square(self.mu) + tf.square(sigma) - tf.log(1e-8 + tf.square(sigma)) - 1, [1]) self.neg_loglikelihood = -tf.reduce_mean(marginal_likelihood) self.KL_divergence = tf.reduce_mean(KL_divergence) ELBO = -self.neg_loglikelihood - self.KL_divergence self.loss = -ELBO """ Training """ # optimizers t_vars = tf.trainable_variables() with tf.control_dependencies(tf.get_collection(tf.GraphKeys.UPDATE_OPS)): self.optim = tf.train.AdamOptimizer(self.learning_rate*5, beta1=self.beta1) \ .minimize(self.loss, var_list=t_vars) """" Testing """ # for test self.fake_images = self.decoder(self.z, is_training=False, reuse=True) """ Summary """ nll_sum = tf.summary.scalar("nll", self.neg_loglikelihood) kl_sum = tf.summary.scalar("kl", self.KL_divergence) loss_sum = tf.summary.scalar("loss", self.loss) # final summary operations self.merged_summary_op = tf.summary.merge_all() def train(self): # initialize all variables tf.global_variables_initializer().run() # graph inputs for visualize training results self.sample_z = prior.gaussian(self.batch_size, self.z_dim) # saver to save model self.saver = tf.train.Saver() # summary writer self.writer = tf.summary.FileWriter(self.log_dir + '/' + self.model_name, self.sess.graph) # restore check-point if it exits could_load, checkpoint_counter = self.load(self.checkpoint_dir) if could_load: start_epoch = (int)(checkpoint_counter / self.num_batches) start_batch_id = checkpoint_counter - start_epoch * self.num_batches counter = checkpoint_counter print(" [*] Load SUCCESS") else: start_epoch = 0 start_batch_id = 0 counter = 1 print(" [!] Load failed...") # loop for epoch start_time = time.time() for epoch in range(start_epoch, self.epoch): # get batch data for idx in range(start_batch_id, self.num_batches): batch_images = self.data_X[idx*self.batch_size:(idx+1)*self.batch_size] batch_z = prior.gaussian(self.batch_size, self.z_dim) # update autoencoder _, summary_str, loss, nll_loss, kl_loss = self.sess.run([self.optim, self.merged_summary_op, self.loss, self.neg_loglikelihood, self.KL_divergence], feed_dict={self.inputs: batch_images, self.z: batch_z}) self.writer.add_summary(summary_str, counter) # display training status counter += 1 print("Epoch: [%2d] [%4d/%4d] time: %4.4f, loss: %.8f, nll: %.8f, kl: %.8f" \ % (epoch, idx, self.num_batches, time.time() - start_time, loss, nll_loss, kl_loss)) # save training results for every 300 steps if np.mod(counter, 300) == 0: samples = self.sess.run(self.fake_images, feed_dict={self.z: self.sample_z}) tot_num_samples = min(self.sample_num, self.batch_size) manifold_h = int(np.floor(np.sqrt(tot_num_samples))) manifold_w = int(np.floor(np.sqrt(tot_num_samples))) save_images(samples[:manifold_h * manifold_w, :, :, :], [manifold_h, manifold_w], './' + check_folder(self.result_dir + '/' + self.model_dir) + '/' + self.model_name + '_train_{:02d}_{:04d}.png'.format( epoch, idx)) # After an epoch, start_batch_id is set to zero # non-zero value is only for the first epoch after loading pre-trained model start_batch_id = 0 # save model self.save(self.checkpoint_dir, counter) # show temporal results self.visualize_results(epoch) # save model for final step self.save(self.checkpoint_dir, counter) def visualize_results(self, epoch): tot_num_samples = min(self.sample_num, self.batch_size) image_frame_dim = int(np.floor(np.sqrt(tot_num_samples))) """ random condition, random noise """ z_sample = prior.gaussian(self.batch_size, self.z_dim) samples = self.sess.run(self.fake_images, feed_dict={self.z: z_sample}) save_images(samples[:image_frame_dim * image_frame_dim, :, :, :], [image_frame_dim, image_frame_dim], check_folder( self.result_dir + '/' + self.model_dir) + '/' + self.model_name + '_epoch%03d' % epoch + '_test_all_classes.png') """ learned manifold """ if self.z_dim == 2: assert self.z_dim == 2 z_tot = None id_tot = None for idx in range(0, 100): #randomly sampling id = np.random.randint(0,self.num_batches) batch_images = self.data_X[id * self.batch_size:(id + 1) * self.batch_size] batch_labels = self.data_y[id * self.batch_size:(id + 1) * self.batch_size] z = self.sess.run(self.mu, feed_dict={self.inputs: batch_images}) if idx == 0: z_tot = z id_tot = batch_labels else: z_tot = np.concatenate((z_tot, z), axis=0) id_tot = np.concatenate((id_tot, batch_labels), axis=0) save_scattered_image(z_tot, id_tot, -4, 4, name=check_folder( self.result_dir + '/' + self.model_dir) + '/' + self.model_name + '_epoch%03d' % epoch + '_learned_manifold.png') @property def model_dir(self): return "{}_{}_{}_{}".format( self.model_name, self.dataset_name, self.batch_size, self.z_dim) def save(self, checkpoint_dir, step): checkpoint_dir = os.path.join(checkpoint_dir, self.model_dir, self.model_name) if not os.path.exists(checkpoint_dir): os.makedirs(checkpoint_dir) self.saver.save(self.sess,os.path.join(checkpoint_dir, self.model_name+'.model'), global_step=step) def load(self, checkpoint_dir): import re print(" [*] Reading checkpoints...") checkpoint_dir = os.path.join(checkpoint_dir, self.model_dir, self.model_name) ckpt = tf.train.get_checkpoint_state(checkpoint_dir) if ckpt and ckpt.model_checkpoint_path: ckpt_name = os.path.basename(ckpt.model_checkpoint_path) self.saver.restore(self.sess, os.path.join(checkpoint_dir, ckpt_name)) counter = int(next(re.finditer("(\d+)(?!.*\d)",ckpt_name)).group(0)) print(" [*] Success to read {}".format(ckpt_name)) return True, counter else: print(" [*] Failed to find a checkpoint") return False, 0
utils.py
Tested in Anaconda and Python 3.7
""" Most codes from https://github.com/carpedm20/DCGAN-tensorflow """ from __future__ import division import math import random import pprint import cv2 import imageio import numpy as np from time import gmtime, strftime from six.moves import xrange import matplotlib.pyplot as plt import os, gzip import tensorflow as tf import tensorflow.contrib.slim as slim def load_mnist(dataset_name): data_dir = os.path.join("./data", dataset_name) def extract_data(filename, num_data, head_size, data_size): with gzip.open(filename) as bytestream: bytestream.read(head_size) buf = bytestream.read(data_size * num_data) data = np.frombuffer(buf, dtype=np.uint8).astype(np.float) return data data = extract_data(data_dir + '/train-images-idx3-ubyte.gz', 60000, 16, 28 * 28) trX = data.reshape((60000, 28, 28, 1)) data = extract_data(data_dir + '/train-labels-idx1-ubyte.gz', 60000, 8, 1) trY = data.reshape((60000)) data = extract_data(data_dir + '/t10k-images-idx3-ubyte.gz', 10000, 16, 28 * 28) teX = data.reshape((10000, 28, 28, 1)) data = extract_data(data_dir + '/t10k-labels-idx1-ubyte.gz', 10000, 8, 1) teY = data.reshape((10000)) trY = np.asarray(trY) teY = np.asarray(teY) X = np.concatenate((trX, teX), axis=0) y = np.concatenate((trY, teY), axis=0).astype(np.int) seed = 547 np.random.seed(seed) np.random.shuffle(X) np.random.seed(seed) np.random.shuffle(y) y_vec = np.zeros((len(y), 10), dtype=np.float) for i, label in enumerate(y): y_vec[i, y[i]] = 1.0 return X / 255., y_vec def check_folder(log_dir): if not os.path.exists(log_dir): os.makedirs(log_dir) return log_dir def show_all_variables(): model_vars = tf.trainable_variables() slim.model_analyzer.analyze_vars(model_vars, print_info=True) def get_image(image_path, input_height, input_width, resize_height=64, resize_width=64, crop=True, grayscale=False): image = imread(image_path, grayscale) return transform(image, input_height, input_width, resize_height, resize_width, crop) def save_images(images, size, image_path): return imsave(inverse_transform(images), size, image_path) def imread(path, grayscale = False): if (grayscale): return imageio.imread(path, flatten = True).astype(np.float) else: return imageio.imread(path).astype(np.float) def merge_images(images, size): return inverse_transform(images) def merge(images, size): h, w = images.shape[1], images.shape[2] if (images.shape[3] in (3,4)): c = images.shape[3] img = np.zeros((h * size[0], w * size[1], c)) for idx, image in enumerate(images): i = idx % size[1] j = idx // size[1] img[j * h:j * h + h, i * w:i * w + w, :] = image return img elif images.shape[3]==1: img = np.zeros((h * size[0], w * size[1])) for idx, image in enumerate(images): i = idx % size[1] j = idx // size[1] img[j * h:j * h + h, i * w:i * w + w] = image[:,:,0] return img else: raise ValueError('in merge(images,size) images parameter ''must have dimensions: HxW or HxWx3 or HxWx4') def imsave(images, size, path): image = np.squeeze(merge(images, size)) return imageio.imsave(path, image) def center_crop(x, crop_h, crop_w, resize_h=64, resize_w=64): if crop_w is None: crop_w = crop_h h, w = x.shape[:2] j = int(round((h - crop_h)/2.)) i = int(round((w - crop_w)/2.)) return cv2.resize(x[j:j+crop_h, i:i+crop_w], [resize_h, resize_w]) def transform(image, input_height, input_width, resize_height=64, resize_width=64, crop=True): if crop: cropped_image = center_crop(image, input_height, input_width, resize_height, resize_width) else: cropped_image = cv2.resize(image, [resize_height, resize_width]) return np.array(cropped_image)/127.5 - 1. def inverse_transform(images): return (images+1.)/2. """ Drawing Tools """ # borrowed from https://github.com/ykwon0407/variational_autoencoder/blob/master/variational_bayes.ipynb def save_scattered_image(z, id, z_range_x, z_range_y, name='scattered_image.jpg'): N = 10 plt.figure(figsize=(8, 6)) plt.scatter(z[:, 0], z[:, 1], c=np.argmax(id, 1), marker='o', edgecolor='none', cmap=discrete_cmap(N, 'jet')) plt.colorbar(ticks=range(N)) axes = plt.gca() axes.set_xlim([-z_range_x, z_range_x]) axes.set_ylim([-z_range_y, z_range_y]) plt.grid(True) plt.savefig(name) # borrowed from https://gist.github.com/jakevdp/91077b0cae40f8f8244a def discrete_cmap(N, base_cmap=None): """Create an N-bin discrete colormap from the specified input map""" # Note that if base_cmap is a string or None, you can simply do # return plt.cm.get_cmap(base_cmap, N) # The following works for string, None, or a colormap instance: base = plt.cm.get_cmap(base_cmap) color_list = base(np.linspace(0, 1, N)) cmap_name = base.name + str(N) return base.from_list(cmap_name, color_list, N)
tensorflow-generative-model-collections
Copyright (c) Apache.
python main.py --dataset mnist --gan_type VAE --epoch 25 --batch_size 64
python main.py --dataset fashion-mnist --gan_type VAE --epoch 40 --batch_size 64
Welcome, my name is Eric Soupet and I am the administrator of the site elodees.com. elodees.com is a state of the art of Artificial Intelligence and aims to be collaborative, you can now offer content such as articles, events, tutorials, ... so don't hesitate !
Platform images credit : Pixabay - Pixabay License | Pexels - Pexels License