First we need modules different modules. Numpy to handle the dataset and mini-batches, Keras to create the neural networks and matplotlib to display results.
from numpy import load, ones, zeros, concatenate
from numpy.random import randint, randn, normal, random
from keras.models import Sequential, load_model
from keras.layers import Dense, Conv2D, Conv2DTranspose, LeakyReLU, Flatten, Reshape, Dropout, BatchNormalization
from keras.optimizers import Adam
from keras.initializers import RandomNormal
from matplotlib import pyplot as plt
from sklearn.utils import shuffle
#The dataset comes from https://www.kaggle.com/barthpaleologue/fire-emblem-three-houses-portraits-complete
def load_dataset(filename):
dataset = load(filename)
data = dataset["arr_0"].astype("float32")
data = (data - 127.5) / 127.5 #map image data from [0,255] to [-1,1]
return data
# initializing weights from the normal distribution improves the begining of training
init = RandomNormal(mean=0.0, stddev=0.02, seed=None)
def createDiscriminator(input_shape=(128,128,3)):
dropout = 0.25
momentum = .8
alpha = .2
model = Sequential()
model.add(Conv2D(128, 3, strides=(2,2),input_shape=input_shape, padding="same", kernel_initializer=init))
model.add(BatchNormalization(momentum=momentum))
model.add(LeakyReLU(alpha=alpha))
model.add(Dropout(dropout))
model.add(Conv2D(128, 3, strides=(2,2), padding="same", kernel_initializer=init))
model.add(BatchNormalization(momentum=momentum))
model.add(LeakyReLU(alpha=alpha))
model.add(Dropout(dropout))
model.add(Conv2D(128, 3, strides=(2,2), padding="same", kernel_initializer=init))
model.add(BatchNormalization(momentum=momentum))
model.add(LeakyReLU(alpha=alpha))
model.add(Dropout(dropout))
model.add(Conv2D(256, 3, strides=(2,2), padding="same", kernel_initializer=init))
model.add(BatchNormalization(momentum=momentum))
model.add(LeakyReLU(alpha=alpha))
model.add(Dropout(dropout))
model.add(Conv2D(512, 3, strides=(2,2), padding="same", kernel_initializer=init))
model.add(BatchNormalization(momentum=momentum))
model.add(LeakyReLU(alpha=alpha))
model.add(Dropout(dropout))
model.add(Flatten())
model.add(Dense(1, activation="sigmoid", kernel_initializer=init))
opt = Adam(lr=.0002, beta_1=.5)
model.compile(loss="binary_crossentropy", optimizer=opt)
model.summary()
return model
def createGenerator(latent_dim):
momentum = .9
alpha = .2
model = Sequential()
model.add(Dense(4*4*256, input_dim=latent_dim, kernel_initializer=init))
model.add(LeakyReLU(alpha=.2))
model.add(Reshape([4,4,256]))
model.add(Conv2DTranspose(512, 3, strides=(2,2), padding="same", kernel_initializer=init))
model.add(BatchNormalization(momentum=momentum))
model.add(LeakyReLU(alpha=alpha))
model.add(Conv2DTranspose(256, 3, strides=(2,2), padding="same", kernel_initializer=init))
model.add(BatchNormalization(momentum=momentum))
model.add(LeakyReLU(alpha=alpha))
model.add(Conv2DTranspose(128, 3, strides=(2,2), padding="same", kernel_initializer=init))
model.add(BatchNormalization(momentum=momentum))
model.add(LeakyReLU(alpha=alpha))
model.add(Conv2DTranspose(128, 3, strides=(2,2), padding="same", kernel_initializer=init))
model.add(BatchNormalization(momentum=momentum))
model.add(LeakyReLU(alpha=alpha))
model.add(Conv2DTranspose(128, 3, strides=(2,2), padding="same", kernel_initializer=init))
model.add(BatchNormalization(momentum=momentum))
model.add(LeakyReLU(alpha=alpha))
model.add(Conv2D(3, 5, padding="same", activation="tanh", kernel_initializer=init))
model.summary()
return model
def createGan(g_model, d_model):
d_model.trainable = False #the discriminator is not trainable here.
model = Sequential()
model.add(g_model)
model.add(d_model)
opt = Adam(lr=.0002, beta_1=.5)
model.compile(loss="binary_crossentropy", optimizer=opt)
model.summary()
return model
def generate_latent_points(latent_dim, nbpoints):
random_points = randn(latent_dim * nbpoints)
random_points = random_points.reshape((nbpoints, latent_dim))
return random_points
def getRealSamples(dataset, nb_samples):
random_indexes = randint(0, dataset.shape[0], nb_samples)
samples = dataset[random_indexes]
labels = ones((nb_samples, 1)) - 0.1
return samples, labels
def getFakeSamples(g_model, latent_dim, nb_samples):
latent_inputs = generate_latent_points(latent_dim, nb_samples)
samples = g_model.predict(latent_inputs)
labels = zeros((nb_samples,1))
return samples, labels
D_loss = []
G_loss = []
def train(g_model, d_model, gan_model, dataset, iterations, batch_size, latent_dim):
for i in range(iterations):
d_model.trainable = True
x_real, y_real = getRealSamples(dataset, batch_size)
x_fake, y_fake = getFakeSamples(g_model, latent_dim, batch_size)
d_loss1 = d_model.train_on_batch(x_real, y_real)
d_loss2 = d_model.train_on_batch(x_fake, y_fake)
D_loss.append((d_loss1+d_loss2) / 2)
d_model.trainable = False
x_gan = generate_latent_points(latent_dim, batch_size)
y_gan = ones((batch_size,1))
g_loss = gan_model.train_on_batch(x_gan, y_gan)
G_loss.append(g_loss)
print(f"Iteration {i}", end="\r")
if i%500==0:
d_model.save(f"checkpoints/discri_{i}.h5")
g_model.save(f"checkpoints/gene_{i}.h5")
if i%100==0:
g_model.save("checkpoints/onthefly.h5")
fakedemo = getFakeSamples(g_model, latent_dim, 9)
plt.figure()
for j in range(9):
plt.subplot(3,3,j+1)
plt.axis("off")
plt.imshow((fakedemo[0][j]+1)/2)
if i%500 == 0:
plt.savefig(f"resultat{i}.png")
plt.show()
plt.figure()
plt.plot(D_loss[-1000:])
plt.plot(G_loss[-1000:])
plt.show()
Dataset Importation
dataset = load_dataset(filename="dataset128.npz")
print(dataset.shape)
A few global settings
latent_dim = 128
iterations = 50000
batch_size = 64
Creating/Loading the discriminator
d_model = load_model("checkpoints/discri_9000.h5")
#d_model = createDiscriminator()
Creating/Loading the generator
g_model = load_model("checkpoints/gene_9000.h5")
#g_model = createGenerator(latent_dim)
Associate both to create the GAN
gan_model = createGan(g_model, d_model)
Training time !!!
train(g_model, d_model, gan_model, dataset, iterations, batch_size, latent_dim)