02.17 使用Adversarial Network生成人脸(Python+Tensorflow)

使用Adversarial Network生成人脸(Python+Tensorflow)

在这篇文章中,我将向您展示如何生成可能在现实生活中不存在的新人脸。我将使用生成对抗网络(GAN)来完成任务。我正在使用CelebA数据集来训练网络。该数据集包含2,00,000个知名人物的图像。我假设您对GAN有理论上的理解。我将在本教程中使用Tensorflow框架。

这就是我们的管道的样子

  1. 归一化图像。
  2. 创建Generator和Discriminator网络。
  3. 训练神经网络并生成新面孔。

以下是我们机器学习数据集中的少量图像。

使用Adversarial Network生成人脸(Python+Tensorflow)

CelebA数据集

归一化图像

  • 作为第一步,我们导入我们将使用的Python库。
  • 我们使用PIL加载所有图像。在加载图像时,我们会裁剪脸部周围的所有图像并将其调整为(64,64,3)
  • 这些图像的范围为(0,255)。我们将这些图像的位范围压缩在(-1,1)之间,这是在tanh激活的范围内。

Python代码如下:

import glob
import numpy as np
from PIL import Image
import tensorflow as tf
import matplotlib.pyplot as plt
from tensorflow import reduce_mean
from tensorflow.train import AdamOptimizer as adam
from tensorflow.nn import sigmoid_cross_entropy_with_logits as loss
from tensorflow.layers import dense, batch_normalization, conv2d_transpose, conv2d
image_ids = glob.glob('../input/data/*')
crop = (30, 55, 150, 175)
images = [np.array((Image.open(i).crop(crop)).resize((64,64))) for i in image_ids]
for i in range(len(images)):
images[i] = ((images[i] - images[i].min())/(255 - images[i].min()))
images[i] = images[i]*2-1

images = np.array(images)
使用Adversarial Network生成人脸(Python+Tensorflow)

辅助函数

def view_samples(epoch, samples, nrows, ncols, figsize=(10,10)):

fig, axes = plt.subplots(figsize=figsize, nrows=nrows, ncols=ncols)

for ax, img in zip(axes.flatten(), samples[epoch]):

ax.axis('off')
img = (((img+1)/2)*255).astype(np.uint8)
im = ax.imshow(img)

plt.subplots_adjust(wspace=0, hspace=0)
return fig, axes
使用Adversarial Network生成人脸(Python+Tensorflow)

创建网络

  • 具体来说,我在这里实现DCGAN。这叫做深度卷积生成对抗性网络。这是Ian Goodfellow在2014年推出的GAN标准的变体。DCGAN使用卷积层,而不是所有全连接层。
  • GAN背后的概念是它有两个名为Generator和 Discriminator的网络。Generator的工作是从噪声中生成逼真的图像,并欺骗Discriminator。另一方面,Discriminator的工作是区分真实和虚假图像。这两个网络都是分开训练的。
  • 在开始时,两个网络的工作都很差,但是当我们继续训练时,Discriminator在识别真实和假图像方面变得会更好,而Generator在生成真实图像方面变得更好,这样它就可以欺骗Discriminator。但是,训练GAN的任务并不容易。
  • 网络的体系结构和超参数的选择与DCGAN论文中使用的非常相似。

Generator的Python实现如下:

def generator(noise, reuse=False, alpha=0.2, training=True):

with tf.variable_scope('generator', reuse=reuse):

x = dense(noise, 4*4*512)
x = tf.reshape(x, (-1, 4, 4, 512))
x = batch_normalization(x, training=training)
x = tf.maximum(0., x)

x = conv2d_transpose(x, 256, 5, 2, padding='same')
x = batch_normalization(x, training=training)
x = tf.maximum(0., x)

x = conv2d_transpose(x, 128, 5, 2, padding='same')
x = batch_normalization(x, training=training)

x = tf.maximum(0., x)

x = conv2d_transpose(x, 64, 5, 2, padding='same')
x = batch_normalization(x, training=training)
x = tf.maximum(0., x)

logits = conv2d_transpose(x, 3, 5, 2, padding='same')
out = tf.tanh(logits)

return out, logits
使用Adversarial Network生成人脸(Python+Tensorflow)

  • 我们将均匀分布的噪声传递给Generator。发生器将此噪声转换为(64,64,3)尺寸的图像。我们在这个过程中使用转置 卷积。在转置卷积层之后使用批归一化层,而不是最后一层。我们在批归一层之后使用Relu激活。我们通过tanh激活将最终图像压缩到(- 1,1)之间的像素范围。

Discriminator的Python实现如下:

def discriminator(x, reuse=False, alpha=0.2, training=True):

with tf.variable_scope('discriminator', reuse=reuse):

x = conv2d(x, 32, 5, 2, padding='same')
x = tf.maximum(alpha*x, x)

x = conv2d(x, 64, 5, 2, padding='same')
x = batch_normalization(x, training=training)
x = tf.maximum(alpha*x, x)

x = conv2d(x, 128, 5, 2, padding='same')
x = batch_normalization(x, training=training)
x = tf.maximum(alpha*x, x)

x = conv2d(x, 256, 5, 2, padding='same')
x = batch_normalization(x, training=training)
x = tf.maximum(alpha*x, x)

flatten = tf.reshape(x, (-1, 4*4*256))
logits = dense(flatten, 1)
out = tf.sigmoid(logits)

return out, logits
使用Adversarial Network生成人脸(Python+Tensorflow)

  • 我们将传递一个形状张量(64,64,3)给Discriminator。Discriminator给出一个单一的输出,告诉这个图像是真的还是假的。我们通过sigmoid激活传递最终的输出。如果输出值接近于1,则表示Discriminator将图像识别为真实图像,如果输出值接近于0,则将图像识别为假图像。
def inputs(real_dim, noise_dim):

inputs_real = tf.placeholder(tf.float32, (None, *real_dim), name='input_real')
inputs_noise = tf.placeholder(tf.float32, (None, noise_dim), name='input_noise')
return inputs_real, inputs_noise
# building the graph
tf.reset_default_graph()
input_real, input_noise = inputs(input_shape, noise_size)
gen_noise, gen_logits = generator(input_noise)
dis_out_real, dis_logits_real = discriminator(input_real)
dis_out_fake, dis_logits_fake = discriminator(gen_noise, reuse=True)
# defining losses
shape = dis_logits_real
dis_loss_real = reduce_mean(loss(logits=dis_logits_real, labels=tf.ones_like(shape*smooth)))
dis_loss_fake = reduce_mean(loss(logits=dis_logits_fake, labels=tf.zeros_like(shape)))
gen_loss = reduce_mean(loss(logits=dis_logits_fake, labels=tf.ones_like(shape*smooth)))
dis_loss = dis_loss_real + dis_loss_fake
# defining optimizers
total_vars = tf.trainable_variables()
dis_vars = [var for var in total_vars if var.name[0] == 'd']
gen_vars = [var for var in total_vars if var.name[0] == 'g']
dis_opt = adam(learning_rate=learning_rate, beta1=beta1).minimize(dis_loss, var_list=dis_vars)
gen_opt = adam(learning_rate=learning_rate, beta1=beta1).minimize(gen_loss, var_list=gen_vars)
使用Adversarial Network生成人脸(Python+Tensorflow)

  • 定义了Generator和Discriminator两种不同的损失函数。优化器也是如此

训练网络

  • 下面是超参数的选择。学习率为0.0002,噪声大小为100,标签平滑因子为0.9,LeakyRelu的leak参数为0.2,Adam optimizer的beta1为0.5。
# hyperparameters
beta1 = 0.5
alpha = 0.2
smooth = 0.9
noise_size = 100
learning_rate = 0.0002
input_shape = (64,64,3)
使用Adversarial Network生成人脸(Python+Tensorflow)

  • Batch-size是128。以下是训练的Python代码。
batch_size = 128
epochs = 100
saver = tf.train.Saver(var_list = gen_vars)
with tf.Session() as sess:

sess.run(tf.global_variables_initializer())

for e in range(epochs):

iters = 10000//batch_size

for i in range(1):

batch_images= get_images(batch_size)
batch_noise = np.random.uniform(-1, 1, size=(batch_size, noise_size))

sess.run(dis_opt, feed_dict={input_real: batch_images, input_noise: batch_noise})
sess.run(gen_opt, feed_dict={input_real: batch_images, input_noise: batch_noise})

loss_dis = sess.run(dis_loss, {input_noise: batch_noise, input_real: batch_images})
loss_gen = gen_loss.eval({input_real: batch_images, input_noise: batch_noise})

print("Epoch {}/{}...".format(e+1, epochs),"Discriminator Loss: {:.4f}...".format(loss_dis),
"Generator Loss: {:.4f}".format(loss_gen))

sample_noise = np.random.uniform(-1, 1, size=(8, noise_size))
gen_samples = sess.run(generator(input_noise, reuse=True, alpha=alpha),
feed_dict={input_noise: sample_noise})
view_samples(-1, gen_samples, 2, 4, (10,5))
plt.show()
saver.save(sess, './checkpoints/generator.ckpt')
使用Adversarial Network生成人脸(Python+Tensorflow)

  • 以下是网络训练后生成的图像。我们可以通过使网络更深来生成更逼真的图像,但是需要花费大量时间来训练模型。我们还可以修改我们的网络以生成高分辨率图像,但同样需要以训练时间为代价。
使用Adversarial Network生成人脸(Python+Tensorflow)

训练后生成的人脸



分享到:


相關文章: