对抗生成网络学习(二)

您所在的位置:网站首页 人脸设计素描图片 对抗生成网络学习(二)

对抗生成网络学习(二)

2024-06-13 18:33| 来源: 网络整理| 查看: 265

一、背景

DCGAN的全程为Deep Convolutional Generative Adversarial Network,即深度卷积对抗网络。该实验的主要目的是利用DCGAN来生成人脸图像。DCGAN是Alec Radfor等人[1]于2015年提出的一种模型,该模型基于GAN,并加入了卷积网络,以实现对图像的处理。

本实验以一批人脸图像为例,尽可能的用比较少的代码实现DCGAN。

[1]文章链接:https://arxiv.org/pdf/1511.06434.pdf

二、DCGAN原理

DCGAN的原理CSDN上已经有非常完善的介绍,这里只做简单介绍。

DCGAN可以看成是CNN+GAN,将卷积神经网络引入到GAN当中。DCGAN的贡献在论文中也有提及,主要包含以下四点:

• We propose and evaluate a set of constraints on the architectural topology of Convolutional GANs that make them stable to train in most settings. We name this class of architectures Deep Convolutional GANs (DCGAN)(在卷积GAN的网络拓扑结构中设置一系列限制,使得其能够稳定的训练。)

• We use the trained discriminators for image classification tasks, showing competitive performance with other unsupervised algorithms.(将DCGAN的判别器用于图像分类任务,能够产生与非监督算法相媲美的效果)

• We visualize the filters learnt by GANs and empirically show that specific filters have learned to draw specific objects.(对GAN学习到的filter进行了可视化)

• We show that the generators have interesting vector arithmetic properties allowing for easy manipulation of many semantic qualities of generated samples.(利用DCGAN生成器的生成矢量易于生成样本)

DCGAN的generator的网络结构如下所示:

在generator中,传统CNN中的pooling层用batch normalization层代替,这样做的好处在于能够减少由于层数加深带来的梯度消散的影响。

网上也有一些比较好理解的代码,下面给出链接供大家参考:

[2]https://github.com/HyeongminLEE/Tensorflow_DCGAN

[3]https://github.com/jazzsaxmafia/dcgan_tensorflow/tree/master/lsun

[4]https://github.com/MINGUKKANG/DCGAN-tensorflow

我主要参考了[4]的代码,并在原有代码基础上进行改进,用尽量简单易读的方式实现DCGAN。

三、DCGAN实现——以人脸数据集为例 1.定义超参数 hyper parameter

首先导入模型需要的库,并定义相关参数

# 导入需要的包 from PIL import Image # Image 用于读取影像 from skimage import io # io也可用于读取影响,效果比Image读取的更好一些 import tensorflow as tf # 用于构建神经网络模型 import matplotlib.pyplot as plt # 用于绘制生成影像的结果 import numpy as np # 读取影像 import os # 文件夹操作 import time # 计时 # 设置相关参数 is_training = True input_dir = "./face/" # 原始数据的文件夹路径 # 设置超参数 hyper parameters batch_size = 64 image_width = 64 image_height = 64 image_channel = 3 data_shape = [64, 64, 3] data_length = 64 * 64 * 3 z_dim = 100 learning_rate = 0.00005 beta1 = 0.5 epoch = 500 2.数据准备

原始数据主要为人脸数据,数据可以从网上自行下载,或者利用自己的数据,这里对数据的没有严格要求。

我是采用了网络上的数据集,这里给出数据的下载地址:https://anonfile.com/p7w3m0d5be/face-swap.zip

下载好数据并解压,按照如下方式设置文件夹:

-- *.py -- face (文件夹) |--------A (A的人脸数据集) |--------image1.jpg |--------image2.jpg |--------image3.jpg |--------..... |--------B (B的人脸数据集) |--------image1.jpg |--------image2.jpg |--------image3.jpg |--------.....

数据的所有文件的格式均为*.jpg,图像的尺寸大小均为256 * 256 * 3,真彩色影像,且每张图片均含有不同状态的人脸信息。设置好的文件夹及数据的结果如下:

直接的原始数据无法进行处理,我们需要将其读到程序中,读取图像的代码为:

# 读取数据的函数 def prepare_data(input_dir, floder): ''' 函数功能:通过输入图像的路径,读取训练数据 :参数 input_dir: 图像数据所在的根目录,即"./face" :参数 floder: 图像数据所在的子目录, 即"./face/A" :return: 返回读取好的训练数据 ''' # 遍历图像路径,并获取图像数量 images = os.listdir(input_dir + floder) image_len = len(images) # 设置一个空data,用于存放数据 data = np.empty((image_len, image_width, image_height, image_channel), dtype="float32") # 逐个图像读取 for i in range(image_len): #如果导入的是skimage.io,则读取影像应该写为img = io.imread(input_dir + images[i]) img = Image.open(input_dir + floder + "/" + images[i]) #打开图像 img = img.resize((image_width, image_height)) #将256*256变成64*64 arr = np.asarray(img, dtype="float32") #将格式改为np.array data[i, :, :, :] = arr #将其放入data中 sess = tf.Session() sess.run(tf.initialize_all_variables()) data = tf.reshape(data, [-1, image_width, image_height, image_channel]) train_data = data * 1.0 / 127.5 - 1.0 #对data进行正则化 train_data = tf.reshape(train_data, [-1, data_length]) #将其拉伸成一维向量 train_set = sess.run(train_data) sess.close() return train_set 3.编写网络结构

网络结构的思路和编写GAN的思路一样,网络结构的核心是生成器generator和判别器discriminator,同时再加上存储函数即可。

定义生成器generator函数:

# 定义生成器 def Generator(z, is_training, reuse): ''' 函数功能:输入噪声z,生成图像gen_img :param z:即输入数据,一般为噪声 :param is_training:是否为训练环节 :return: 返回生成影像gen_img ''' # 图像的channel维度变化为1->1024->512->256->128->3 depths = [1024, 512, 256, 128] + [data_shape[2]] with tf.variable_scope("Generator", reuse=reuse): # 第一层全连接层 with tf.variable_scope("g_fc1", reuse=reuse): output = tf.layers.dense(z, depths[0]*4*4, trainable=is_training) output = tf.reshape(output, [batch_size, 4, 4, depths[0]]) output = tf.nn.relu(tf.layers.batch_normalization(output, training=is_training)) # 第二层反卷积层1024 with tf.variable_scope("g_dc1", reuse=reuse): output = tf.layers.conv2d_transpose(output, depths[1], [5, 5], strides=(2, 2), padding="SAME", trainable=is_training) output = tf.nn.relu(tf.layers.batch_normalization(output, training=is_training)) # 第三层反卷积层512 with tf.variable_scope("g_dc2", reuse=reuse): output = tf.layers.conv2d_transpose(output, depths[2], [5, 5], strides=(2, 2), padding="SAME", trainable=is_training) output = tf.nn.relu(tf.layers.batch_normalization(output, training=is_training)) # 第四层反卷积层256 with tf.variable_scope("g_dc3", reuse=reuse): output = tf.layers.conv2d_transpose(output, depths[3], [5, 5], strides=(2, 2), padding="SAME", trainable=is_training) output = tf.nn.relu(tf.layers.batch_normalization(output, training=is_training)) # 第五层反卷积层128 with tf.variable_scope("g_dc4", reuse=reuse): output = tf.layers.conv2d_transpose(output, depths[4], [5, 5], strides=(2, 2), padding="SAME", trainable=is_training) gen_img = tf.nn.tanh(output) return gen_img

编写判别器discriminator函数:

# 定义判别器 def Discriminator(x, is_training, reuse): ''' 函数功能:判别输入的图像是真或假 :param x: 输入数据 :param is_training: 是否为训练环节 :return: 判别结果 ''' # channel维度变化为:3->64->128->256->512 depths = [data_shape[2]] + [64, 128, 256, 512] with tf.variable_scope("Discriminator", reuse=reuse): # 第一层卷积层,注意用的是leaky_relu函数 with tf.variable_scope("d_cv1", reuse=reuse): output = tf.layers.conv2d(x, depths[1], [5, 5], strides=(2, 2), padding="SAME", trainable=is_training) output = tf.nn.leaky_relu(tf.layers.batch_normalization(output, training=is_training)) # 第二层卷积层,注意用的是leaky_relu函数 with tf.variable_scope("d_cv2", reuse=reuse): output = tf.layers.conv2d(output, depths[2], [5, 5], strides=(2, 2), padding="SAME", trainable=is_training) output = tf.nn.leaky_relu(tf.layers.batch_normalization(output, training=is_training)) # 第三层卷积层,注意用的是leaky_relu函数 with tf.variable_scope("d_cv3", reuse=reuse): output = tf.layers.conv2d(output, depths[3], [5, 5], strides=(2, 2), padding="SAME", trainable=is_training) output = tf.nn.leaky_relu(tf.layers.batch_normalization(output, training=is_training)) # 第四层卷积层,注意用的是leaky_relu函数 with tf.variable_scope("d_cv4", reuse=reuse): output = tf.layers.conv2d(output, depths[4], [5, 5], strides=(2, 2), padding="SAME", trainable=is_training) output = tf.nn.leaky_relu(tf.layers.batch_normalization(output, training=is_training)) # 第五层全链接层 with tf.variable_scope("d_fc1", reuse=reuse): output = tf.layers.flatten(output) disc_img = tf.layers.dense(output, 1, trainable=is_training) return disc_img

编写保存结果的函数:

def plot_and_save(order, images): ''' 函数功能:绘制生成器的结果,并保存 :param order: :param images: :return: ''' # 将一个batch_size的所有图像进行保存 batch_size = len(images) n = np.int(np.sqrt(batch_size)) # 读取图像大小,并生成掩模canvas image_size = np.shape(images)[2] n_channel = np.shape(images)[3] images = np.reshape(images, [-1, image_size, image_size, n_channel]) canvas = np.empty((n * image_size, n * image_size, image_channel)) # 为每个掩模赋值 for i in range(n): for j in range(n): canvas[i*image_size:(i+1)*image_size, j*image_size:(j+1)*image_size, :] = images[n*i+j].reshape(64, 64, 3) # 绘制结果,并设置坐标轴 plt.figure(figsize=(8, 8)) plt.imshow(canvas, cmap="gray") label = "Epoch: {0}".format(order+1) plt.xlabel(label) # 为每个文件命名 if type(order) is str: file_name = order else: file_name = "face_gen" + str(order) # 保存绘制的结果 plt.savefig(file_name) print(os.getcwd()) print("Image saved in file: ", file_name) plt.close()

准备好以上的函数,即可以开始编写训练过程。

4.编写训练过程

定义训练过程的函数:

# 定义训练过程 def training(): ''' 函数功能:实现DCGAN的训练过程 ''' # 准备数据。这里输入根目录,以A的影像为例进行图像生成 data = prepare_data(input_dir, "A") # 构建网络结构,这是程序的核心部分--------------------------------------------- x = tf.placeholder(tf.float32, shape=[None, data_length], name="Input_data") x_img = tf.reshape(x, [-1] + data_shape) z = tf.placeholder(tf.float32, shape=[None, z_dim], name="latent_var") G = Generator(z, is_training=True, reuse=False) D_fake_logits = Discriminator(G, is_training=True, reuse=False) D_true_logits = Discriminator(x_img, is_training=True, reuse=True) # 定义生成器的损失函数G_loss G_loss = tf.reduce_mean(tf.nn.sigmoid_cross_entropy_with_logits( logits=D_fake_logits, labels=tf.ones_like(D_fake_logits))) # 定义判别器的损失函数D_loss D_loss_1 = tf.reduce_mean(tf.nn.sigmoid_cross_entropy_with_logits( logits=D_true_logits, labels=tf.ones_like(D_true_logits))) D_loss_2 = tf.reduce_mean(tf.nn.sigmoid_cross_entropy_with_logits( logits=D_fake_logits, labels=tf.zeros_like(D_fake_logits))) D_loss = D_loss_1 + D_loss_2 # 定义方差 total_vars = tf.trainable_variables() d_vars = [var for var in total_vars if "d_" in var.name] g_vars = [var for var in total_vars if "g_" in var.name] # 定义优化方式 with tf.control_dependencies(tf.get_collection(tf.GraphKeys.UPDATE_OPS)): g_optimization = tf.train.AdamOptimizer(learning_rate=learning_rate, beta1=beta1).minimize(G_loss, var_list=g_vars) d_optimization = tf.train.AdamOptimizer(learning_rate=learning_rate, beta1=beta1).minimize(D_loss, var_list=d_vars) print("we successfully make the network") # 网络模型构建结束------------------------------------------------------------ # 训练模型初始化 start_time = time.time() #计时 sess = tf.Session() sess.run(tf.initialize_all_variables()) # 逐个epoch训练 for i in range(epoch): total_batch = int(len(data)/batch_size) d_value = 0 g_value = 0 # 逐个batch训练 for j in range(total_batch): batch_xs = data[j*batch_size:j*batch_size + batch_size] # 训练判别器 z_sampled1 = np.random.uniform(low=-1.0, high=1.0, size=[batch_size, z_dim]) Op_d, d_ = sess.run([d_optimization, D_loss], feed_dict={x: batch_xs, z: z_sampled1}) # 训练生成器 z_sampled2 = np.random.uniform(low=-1.0, high=1.0, size=[batch_size, z_dim]) Op_g, g_ = sess.run([g_optimization, G_loss], feed_dict={x: batch_xs, z: z_sampled2}) # 尝试生成影像并保存 images_generated = sess.run(G, feed_dict={z: z_sampled2}) d_value += d_/total_batch g_value += g_/total_batch plot_and_save(i, images_generated) # 输出时间和损失函数loss hour = int((time.time() - start_time)/3600) min = int(((time.time() - start_time) - 3600*hour)/60) sec = int((time.time() - start_time) - 3600*hour - 60*min) print("Time: ", hour, "h", min, "min", sec, "sec", " Epoch: ", i, "G_loss: ", g_value, "D_loss: ", d_value) 5.训练

整个训练过程非常简单:

if __name__ == "__main__": training() 四、实验结果

实验暂时设置epoch=500,编写好*.py的结构之后,直接运行即可进行实验,用GPU(GTX1060 3G)运行约19分钟可跑完整个过程,训练的效果如下:

实验1个epoch的结果:

实验50个epoch的结果,此时实验结果已经有了颜色的变化:

实验100个epoch的结果,此时已经能够隐约看见人脸的轮廓:

实验150个epoch的结果,此时人脸的颜色更接近真实一些:

实验进行300个epoch的结果,此时已经又了眼睛和鼻子的轮廓:

实验进行500个epoch的结果,此时的生成图像已经比较清晰了,甚至可以看到牙齿:

五、分析

1. DCGA引入了CNN的思想,能够更好的处理彩色图像,但是训练的过程比较漫长

2. 整个网络的结构为:

from PIL import Image #导入Image import ... #导入相关的库 # 设置超参数 is_training =... ... # 定义读取数据函数 def prepare_data(input_dir, floder):... # 定义生成器 def Generator(z, is_training, reuse):... # 定义判别器 def Discriminator(x, is_training, reuse):... # 定义绘制及保存函数 def plot_and_save(order, images):... # 定义训练过程 def training():... if __name__ == "__main__": training()

 



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3