那些说不完的 GAN - Unsupervised Representation Learning with Deep Convolutional Generative Adversarial Networks
Deep Convolutional Generative Adversarial Networks( DCGAN ),中文名称深度卷积生成对抗网络,于 2016 年被 Alec Radford 等人提出。目的是为了减小 CNN 在监督学习和无监督学习上的差距。DCGAN 通过一定的架构约束,在大量的数据集上证明了 DCGAN 对 CNN 在无监督学习中的发展发挥了重要作用。
在此之前,使用 CNN + GAN 的尝试也有过,但都不是很理想。但 DCGAN 使用了一种全新的架构,不仅提高了训练的稳定性,也允许更高分辨率的图片和更深的网络。CNN 架构的变化主要有三个:
1. 使用全卷积神经网络( all convolutional net )。通过使用跨步卷积( strided convolution )替代确定性的池化操作,从而让网络自己学习下采样。在生成器和判别器中均使用了这种方式。
2. 取消全连接层。常见的做法有使用全局平均池( global average pooling )化代替全连接层。全局平均池化提升了模型的稳定性,但是却降低了收敛速度。GAN的输入采用均匀分布初始化,可能会使用全连接层(矩阵相乘),然后得到的结果可以转换成一个 4 dimension 的 tensor,然后后面堆叠卷积层即可;对于鉴别器,最后的卷积层可以先 flatten,然后送入一个 sigmoid 分类器。
3. 批归一化( Batch Normalization )。 将每一层的输入分布变换为0均值和单位方差,BN 被证明是深度学习中非常重要的加速收敛和减缓过拟合的手段。但是将所有层都进行 Batch Normalization,会导致样本震荡和模型不稳定,因此只对生成器的输出层和鉴别器的输入层使用 BN。
4. 激活函数的使用。生成器的输出层使用 tanh 激活函数,其余层使用 relu 激活函数。鉴别器采用 leaky relu 函数。

文章提出了一套更稳定的架构来训练生成式对抗网络,并通过大量的数据集测试表明,对抗网络为监督学习和生成建模学习了良好的图像表示。但任然存在某些情况下的模型不稳定性。
使用 mnist 手写数据集来写一个简单的 DCGAN,使得生成器网络可以对任意输出入的噪声,产生相应的数字图片。
#代码参考来源:https://tensorflow.google.cn/tutorials/generative/dcgan?hl=zh-cn #tensorflow 2.10.0, Python 3.9 import tensorflow as tf import keras from keras import layers, datasets import matplotlib.pyplot as plt import time print(tf.__version__) #超参数的定义 Batch_Size = 128 Epoches = 100 Noise_Dim = 100 #噪音的数量 Learning_Rate = 0.0001 Buffer_Size = 60000 seed = tf.random.normal([16, Noise_Dim]) # 16组随机数组,每组含100个随机数,用来生成16张图片。 #获取mnist数据集并对数据进行处理 (train_images, train_labels), (_, _) = datasets.mnist.load_data() train_images = train_images / 255.0 #数据归一化 train_images = train_images.reshape(train_images.shape[0], 28, 28, 1) #在第一个维度进行切分,生成 train_images.shape[0] 多的 tensord dataset datasets = tf.data.Dataset.from_tensor_slices(train_images) #从Buffer_Size大小的数据中随机选取填充缓冲区实现选取,合并成 Batch_Size大小 datasets = datasets.shuffle(Buffer_Size).batch(Batch_Size) #建立生成器 def Generator(): model = keras.Sequential([ layers.Dense(7 * 7 * 256, use_bias=False, input_shape=(100,)), layers.BatchNormalization(), layers.ReLU(), layers.Reshape((7, 7, 256)), layers.Conv2DTranspose(128, (5, 5), strides=(1, 1), padding='same', use_bias=False), layers.BatchNormalization(), layers.ReLU(), layers.Conv2DTranspose(64, (5, 5), strides=(2, 2), padding='same', use_bias=False), layers.BatchNormalization(), layers.ReLU(), layers.Conv2DTranspose(1, (5, 5), strides=(2, 2), padding='same', use_bias=False, activation='tanh') ]) return model #定义判别器 def Discriminator(): model = keras.Sequential([ layers.Conv2D(64, (5, 5), strides=(2, 2), padding='same', input_shape=[28, 28, 1]), layers.LeakyReLU(), layers.Dropout(0.3), layers.Conv2D(128, (5, 5), strides=(2, 2), padding='same'), layers.LeakyReLU(), layers.Dropout(0.3), layers.Flatten(), layers.Dense(1) ]) return model #定义各自的优化函数 generator_opt = keras.optimizers.Adam(Learning_Rate) discriminator_opt = keras.optimizers.Adam(Learning_Rate) #定义损失函数,二进制交叉熵适用于二分类问题 cross_entropy = keras.losses.BinaryCrossentropy(from_logits=True) #判别器对真实图片的预测值与值全为 1 的数组进行对比 #将判别器对伪造(生成的)图片的预测值与值全为 0 的数组进行对比 def discriminator_loss(real_out, fake_out): #real_out是判别器对数据集图片的输出,fake_out是判别器对生成图片的输出 real_loss = cross_entropy(tf.ones_like(real_out), real_out) fake_loss = cross_entropy(tf.zeros_like(fake_out), fake_out) return real_loss + fake_loss def generator_loss(fake_out): return cross_entropy(tf.ones_like(fake_out), fake_out) #实例化生成器和判别器 generator = Generator() discriminator = Discriminator() #定义模型训练过程 def train(): for epoch in range(Epoches): start = time.time() for image_batch in datasets: #生成随机数来生成图片 noise = tf.random.normal([Batch_Size, Noise_Dim]) with tf.GradientTape() as gen_tape, tf.GradientTape() as disc_tape: #等价于:gen_tape = tf.GradientTape(), disc_tape = tf.GradientTape() real_out = discriminator(image_batch, training=True) gen_image = generator(noise, training=True) fake_out = discriminator(gen_image, training=True) gen_loss = generator_loss(fake_out) disc_loss = discriminator_loss(real_out, fake_out) #进行梯度的计算与更新 gradient_gen = gen_tape.gradient(gen_loss, generator.trainable_variables) gradient_disc = disc_tape.gradient(disc_loss, discriminator.trainable_variables) generator_opt.apply_gradients(zip(gradient_gen, generator.trainable_variables)) discriminator_opt.apply_gradients(zip(gradient_disc, discriminator.trainable_variables)) print('Time for epoch {} is {} sec'.format(epoch + 1, time.time() - start)) if(epoch%10==0): generate_plot_image(generator, seed) def generate_plot_image(gen_model, test_noise): pre_images = gen_model(test_noise, training=False) fig = plt.figure(figsize=(4, 4)) for i in range(pre_images.shape[0]): plt.subplot(4, 4, i+1) plt.imshow((pre_images[i, :, :, 0] + 1)/2, cmap='gray') plt.axis('off') plt.show() if __name__ == '__main__': train()
DCGAN 训练结果:


浙公网安备 33010602011771号