In [1]:
import numpy as np
import pandas as pd
import tensorflow as tf
import matplotlib.pyplot as plt
import seaborn as sns
from scipy import misc
sns.set()
path = '/home/husein/space/facedataset/img_align_celeba/'
In [2]:
dataset = pd.read_csv('desc.csv')
dataset.head()
Out[2]:
In [3]:
black_hair = dataset[dataset['Black_Hair'] == 1].iloc[:40000, :]
brown_hair = dataset[dataset['Brown_Hair'] == 1].iloc[:40000, :]
In [4]:
def scale(x):
return x / 127.5 - 1
def originate(x):
return (x + 1.) / 2
In [5]:
img = misc.imread(path + black_hair.iloc[0, 0])
img = misc.imresize(img, (64, 64))
scaled_image = scale(img)
fig = plt.figure(figsize = (15, 5))
plt.subplot(1, 3, 1)
plt.imshow(img)
plt.title('original')
plt.subplot(1, 3, 2)
plt.imshow(scaled_image)
plt.title('scaled')
plt.subplot(1, 3, 3)
plt.imshow(originate(scaled_image))
plt.title('originated')
plt.show()
In [6]:
def generate_sample(samples):
idx = [i for i in xrange(16)]
fig, axes = plt.subplots(4, 4, sharex = True, sharey = True, figsize = (5,5))
for ii, ax in zip(idx, axes.flatten()):
ax.imshow(originate(samples[ii,:,:,:]), aspect = 'equal')
ax.xaxis.set_visible(False)
ax.yaxis.set_visible(False)
plt.subplots_adjust(wspace = 0, hspace = 0)
plt.show()
In [7]:
def huber_loss(logits, labels, max_gradient = 1.0):
err = tf.abs(labels - logits)
mg = tf.constant(max_gradient)
lin = mg * (err - 0.5 * mg)
quad = 0.5 * err * err
return tf.where(err < mg, quad, lin)
def generator(z, name, reuse = False, alpha = 0.2, training = True):
with tf.variable_scope(name, reuse = reuse):
x1 = tf.layers.conv2d(z, 64, 4, strides = 2, padding = 'same')
bn1 = tf.layers.batch_normalization(x1, training = training)
relu1 = tf.maximum(alpha * bn1, bn1)
x2 = tf.layers.conv2d(relu1, 128, 4, strides = 2, padding = 'same')
bn2 = tf.layers.batch_normalization(x2, training = training)
relu2 = tf.maximum(alpha * bn2, bn2)
x3 = tf.layers.conv2d(relu2, 256, 4, strides = 2, padding = 'same')
bn3 = tf.layers.batch_normalization(x3, training = training)
relu3 = tf.maximum(alpha * bn3, bn3)
x4 = tf.layers.conv2d(relu3, 512, 4, strides = 2, padding = 'same')
bn4 = tf.layers.batch_normalization(x4, training = training)
relu4 = tf.maximum(alpha * bn4, bn4)
x5 = tf.layers.conv2d(relu4, 100, 4, strides = 2, padding = 'same')
bn5 = tf.layers.batch_normalization(x5, training = training)
relu5 = tf.maximum(alpha * bn5, bn5)
x6 = tf.layers.conv2d_transpose(relu5, 512, 4, strides = 2, padding = 'same')
bn6 = tf.layers.batch_normalization(x6, training = training)
relu6 = tf.maximum(alpha * bn6, bn6)
x7 = tf.layers.conv2d_transpose(relu6, 256, 4, strides = 2, padding = 'same')
bn7 = tf.layers.batch_normalization(x7, training = training)
relu7 = tf.maximum(alpha * bn7, bn7)
x8 = tf.layers.conv2d_transpose(relu7, 128, 4, strides = 2, padding = 'same')
bn8 = tf.layers.batch_normalization(x8, training = training)
relu8 = tf.maximum(alpha * bn8, bn8)
x9 = tf.layers.conv2d_transpose(relu8, 64, 4, strides = 2, padding = 'same')
bn9 = tf.layers.batch_normalization(x9, training = training)
relu9 = tf.maximum(alpha * bn9, bn9)
x10 = tf.layers.conv2d_transpose(relu9, 3, 5, strides = 2, padding = 'same')
return tf.nn.tanh(x10)
def discriminator(z, name, reuse = False, alpha = 0.2):
with tf.variable_scope(name, reuse = reuse):
x1 = tf.layers.conv2d(z, 64, 4, strides = 2, padding = 'same')
relu1 = tf.maximum(alpha * x1, x1)
x2 = tf.layers.conv2d(relu1, 128, 4, strides = 2, padding = 'same')
bn2 = tf.layers.batch_normalization(x2, training = True)
relu2 = tf.maximum(alpha * bn2, bn2)
x3 = tf.layers.conv2d(relu2, 256, 4, strides = 2, padding = 'same')
bn3 = tf.layers.batch_normalization(x3, training = True)
relu3 = tf.maximum(alpha * bn3, bn3)
x4 = tf.layers.conv2d(relu3, 512, 4, strides = 2, padding = 'same')
bn4 = tf.layers.batch_normalization(x4, training = True)
relu4 = tf.maximum(alpha * bn4, bn4)
flat = tf.reshape(relu4, (-1, 4 * 4 * 512))
logits = tf.layers.dense(flat, 1)
return logits
In [8]:
class standardGAN:
def __init__(self, learning_rate = 0.0002, alpha = 0.2):
self.X = tf.placeholder(tf.float32, (None, 64, 64, 3))
self.Y = tf.placeholder(tf.float32, (None, 64, 64, 3))
g_model = generator(self.X, 'generator', alpha = alpha)
self.g_out = generator(self.X, 'generator', reuse = True, training = False)
d_logits_real = discriminator(self.Y, 'discriminator', alpha = alpha)
d_logits_fake = discriminator(g_model, 'discriminator', reuse = True, alpha = alpha)
d_loss_real = tf.reduce_mean(tf.nn.sigmoid_cross_entropy_with_logits(logits = d_logits_real, labels = tf.ones_like(d_logits_real)))
d_loss_fake = tf.reduce_mean(tf.nn.sigmoid_cross_entropy_with_logits(logits = d_logits_fake, labels = tf.zeros_like(d_logits_real)))
self.g_loss = tf.reduce_mean(tf.nn.sigmoid_cross_entropy_with_logits(logits = d_logits_fake, labels = tf.ones_like(d_logits_real)))
self.d_loss = d_loss_real + d_loss_fake
t_vars = tf.trainable_variables()
d_vars = [var for var in t_vars if var.name.startswith('discriminator')]
g_vars = [var for var in t_vars if var.name.startswith('generator')]
self.d_train_opt = tf.train.AdamOptimizer(learning_rate, beta1 = 0.5, beta2 = 0.999).minimize(self.d_loss, var_list = d_vars)
self.g_train_opt = tf.train.AdamOptimizer(learning_rate, beta1 = 0.5, beta2 = 0.999).minimize(self.g_loss, var_list = g_vars)
class GAN_with_huber:
def __init__(self, learning_rate = 0.0002, alpha = 0.2):
self.X = tf.placeholder(tf.float32, (None, 64, 64, 3))
self.Y = tf.placeholder(tf.float32, (None, 64, 64, 3))
g_model = generator(self.X, 'generator_AB', alpha = alpha)
self.g_out = generator(self.X, 'generator_AB', reuse = True, training = False)
g_huber = generator(g_model, 'generator_BA', alpha = alpha)
l_const_a = tf.reduce_mean(huber_loss(g_huber, self.X))
d_logits_real = discriminator(self.Y, 'discriminator', alpha = alpha)
d_logits_fake = discriminator(g_model, 'discriminator', reuse = True, alpha = alpha)
d_loss_real = tf.reduce_mean(tf.nn.sigmoid_cross_entropy_with_logits(logits = d_logits_real, labels = tf.ones_like(d_logits_real)))
d_loss_fake = tf.reduce_mean(tf.nn.sigmoid_cross_entropy_with_logits(logits = d_logits_fake, labels = tf.zeros_like(d_logits_real)))
self.g_loss = tf.reduce_mean(tf.nn.sigmoid_cross_entropy_with_logits(logits = d_logits_fake, labels = tf.ones_like(d_logits_real)))
self.d_loss = d_loss_real + d_loss_fake
self.g_loss += l_const_a
t_vars = tf.trainable_variables()
d_vars = [var for var in t_vars if var.name.startswith('discriminator')]
g_vars_AB = [var for var in t_vars if var.name.startswith('generator_AB')]
g_vars_BA = [var for var in t_vars if var.name.startswith('generator_BA')]
self.d_train_opt = tf.train.AdamOptimizer(learning_rate, beta1 = 0.5, beta2 = 0.999).minimize(self.d_loss, var_list = d_vars)
self.g_train_opt = tf.train.AdamOptimizer(learning_rate, beta1 = 0.5, beta2 = 0.999).minimize(self.g_loss, var_list = g_vars_AB + g_vars_BA)
class DiscoGAN:
def __init__(self, learning_rate = 0.0002, alpha = 0.2):
self.X = tf.placeholder(tf.float32, (None, 64, 64, 3))
self.Y = tf.placeholder(tf.float32, (None, 64, 64, 3))
g_AB_model = generator(self.X, 'generator_AB', alpha = alpha)
g_BA_model = generator(self.Y, 'generator_BA', alpha = alpha)
self.g_out_AB = generator(self.X, 'generator_AB', reuse = True, training = False)
self.g_out_BA = generator(self.Y, 'generator_BA', reuse = True, training = False)
g_huber_A = generator_BA_reuse(g_AB_model, 'generator_BA', reuse = True, alpha = alpha)
g_huber_B = generator_AB_reuse(g_BA_model, 'generator_AB', reuse = True, alpha = alpha)
l_const_a = tf.reduce_mean(huber_loss(g_huber_A, self.X))
l_const_b = tf.reduce_mean(huber_loss(g_huber_B, self.Y))
d_logits_real_A = discriminator(self.Y, 'discriminator_A', alpha = alpha)
d_logits_fake_A = discriminator(g_AB_model, 'discriminator_A', reuse = True, alpha = alpha)
d_logits_real_B = discriminator(self.X, 'discriminator_B', alpha = alpha)
d_logits_fake_B = discriminator(g_BA_model, 'discriminator_B', reuse = True, alpha = alpha)
d_loss_real_A = tf.reduce_mean(tf.nn.sigmoid_cross_entropy_with_logits(logits = d_logits_real_A, labels = tf.ones_like(d_logits_real_A)))
d_loss_fake_A = tf.reduce_mean(tf.nn.sigmoid_cross_entropy_with_logits(logits = d_logits_fake_A, labels = tf.zeros_like(d_logits_fake_A)))
self.g_loss_AB = tf.reduce_mean(tf.nn.sigmoid_cross_entropy_with_logits(logits = d_logits_fake_A, labels = tf.ones_like(d_logits_real_A)))
d_loss_real_B = tf.reduce_mean(tf.nn.sigmoid_cross_entropy_with_logits(logits = d_logits_real_B, labels = tf.ones_like(d_logits_real_B)))
d_loss_fake_B = tf.reduce_mean(tf.nn.sigmoid_cross_entropy_with_logits(logits = d_logits_fake_B, labels = tf.zeros_like(d_logits_fake_B)))
self.g_loss_BA = tf.reduce_mean(tf.nn.sigmoid_cross_entropy_with_logits(logits = d_logits_fake_B, labels = tf.ones_like(d_logits_real_B)))
self.d_loss = d_loss_real_A + d_loss_fake_A + d_loss_real_B + d_loss_fake_B
self.g_loss = self.g_loss_AB + self.g_loss_BA + l_const_a + l_const_b
t_vars = tf.trainable_variables()
d_vars_A = [var for var in t_vars if var.name.startswith('discriminator_A')]
d_vars_B = [var for var in t_vars if var.name.startswith('discriminator_B')]
g_vars_AB = [var for var in t_vars if var.name.startswith('generator_AB')]
g_vars_BA = [var for var in t_vars if var.name.startswith('generator_BA')]
self.d_train_opt = tf.train.AdamOptimizer(learning_rate, beta1 = 0.5, beta2 = 0.999).minimize(self.d_loss, var_list = d_vars_A + d_vars_B)
self.g_train_opt = tf.train.AdamOptimizer(learning_rate, beta1 = 0.5, beta2 = 0.999).minimize(self.g_loss, var_list = g_vars_AB + g_vars_BA)
Train Standard GAN
In [9]:
def train(model, X, Y, batch, epoch):
LOSS_D, LOSS_G = [], []
for i in xrange(epoch):
g_loss, d_loss = 0, 0
for k in xrange(0, (X.shape[0] // batch) * batch, batch):
batch_x = np.zeros((batch, 64, 64, 3), dtype = np.float32)
batch_y = np.zeros((batch, 64, 64, 3), dtype = np.float32)
for n in xrange(batch):
img_x = misc.imread(path + X.iloc[k + n, 0])
img_x = misc.imresize(img_x, (64, 64))
img_y = misc.imread(path + Y.iloc[k + n, 0])
img_y = misc.imresize(img_y, (64, 64))
batch_x[n, :, :, :] = scale(img_x)
batch_y[n, :, :, :] = scale(img_y)
_, lossd = sess.run([model.d_train_opt, model.d_loss], feed_dict = {model.X: batch_x, model.Y: batch_y})
_, lossg = sess.run([model.g_train_opt, model.g_loss], feed_dict = {model.X: batch_x, model.Y: batch_y})
g_loss += lossg; d_loss += lossd
g_loss /= (X.shape[0] // batch); d_loss /= (X.shape[0] // batch)
print("Epoch {}/{}".format(i + 1, EPOCH), "Discriminator Loss: {}".format(d_loss), "Generator Loss: {}".format(g_loss))
LOSS_G.append(g_loss); LOSS_D.append(d_loss)
batch_x = np.zeros((16, 64, 64, 3), dtype = np.float32)
batch_y = np.zeros((16, 64, 64, 3), dtype = np.float32)
for n in xrange(16):
img_x = misc.imread(path + X.iloc[n, 0])
img_x = misc.imresize(img_x, (64, 64))
img_y = misc.imread(path + Y.iloc[n, 0])
img_y = misc.imresize(img_y, (64, 64))
batch_x[n, :, :, :] = scale(img_x)
batch_y[n, :, :, :] = scale(img_y)
# if the model is discoGAN
try:
outputs = sess.run(model.g_out_AB, feed_dict = {model.X: batch_x})
print 'GENERATOR A'
generate_sample(outputs)
print 'GENERATOR B'
outputs = sess.run(model.g_out_BA, feed_dict = {model.Y: batch_y})
generate_sample(outputs)
# if the model is not discoGAN
except:
outputs = sess.run(model.g_out, feed_dict = {model.X: batch_x})
generate_sample(outputs)
epoch = [i for i in xrange(len(LOSS_D))]
plt.plot(epoch,LOSS_D, label = 'Discriminator', alpha = 0.5)
plt.plot(epoch, LOSS_G, label = 'Generator', alpha = 0.5)
plt.title("Training Losses")
plt.legend()
plt.show()
In [10]:
EPOCH = 5
BATCH_SIZE = 128
I will train for 5 epoch and 128 batch size only, to see, how much the networks learned in a short period
In [11]:
tf.reset_default_graph()
sess = tf.InteractiveSession()
model = standardGAN()
sess.run(tf.global_variables_initializer())
train(model, black_hair, brown_hair, BATCH_SIZE, EPOCH)
In [12]:
tf.reset_default_graph()
sess = tf.InteractiveSession()
model = GAN_with_huber()
sess.run(tf.global_variables_initializer())
train(model, black_hair, brown_hair, BATCH_SIZE, EPOCH)
In [ ]:
tf.reset_default_graph()
sess = tf.InteractiveSession()
model = DiscoGAN()
sess.run(tf.global_variables_initializer())
train(model, black_hair, brown_hair, BATCH_SIZE, EPOCH)