如何使用深度学习生成图像?详细操作指南

2021年11月28日04:39:24 发表评论 1,978 次浏览
特色图片

深度学习如何生成图像?我们正处于人工智能时代,人工智能正以惊人的速度发展。说人工智能现在正在自动化人工智能是非常公正的。本文探讨了我刚刚提到的惊人事实的细节。

根据埃隆马斯克的说法,人工智能的这种令人难以置信的进步速度接近指数级,同时也见证了计算机视觉领域的一些令人兴奋的突破。通过创建名为 GAN 的算法,即 Generative Adversarial Networks 的缩写,著名的深度学习研究员 Ian Goodfellow 将传统的计算机视觉转变为新的计算机视觉。好吧,我创造了这些名称“传统”和“新”,而不是 CV 社区,看到为几个计算机视觉问题生成数据的巨大转变。


传统与新计算机视觉

如何使用深度学习生成图像?传统的计算机视觉涉及通过下载、清理、渲染并将它们存储到数据库中或手动捕获图片、制作视频并使其能够被网络使用来创建大型数据集。考虑到限制,尤其是时间、资源和生成的数据质量不合格,这种技术对研究人员和开发人员构成了巨大的挑战。

事实上,新计算机视觉让人松了一口气,减轻了迄今为止收集最佳数据集的巨大负担。生成对抗网络 (GAN) 现在用于生成与可用的有限数据具有相同特征的数据。因此,将研究人员从收集和管理数据的繁忙日常工作中解脱出来。


GAN 是如何工作的?

这个流行语 GAN 的想法是关于两个相互竞争的神经网络。这些相互竞争的神经网络以学习可用数据中存在的概率分布的方式执行分配的任务。基于这种概率分布,生成具有与训练数据相同特征的逼真数据。

两个相互竞争的神经网络

这些相互竞争的网络被称为生成器和鉴别器。Generator 网络学习训练数据中的模式并生成图像。同时,鉴别器检查生成图像的真实性,即它决定生成的图像是否属于训练集。简单来说,它会检查生成的图像是“真实”还是“伪造”。

生成器

当给定一组随机值或噪声,在执行一系列非线性计算并将其传递给鉴别器后,生成器会生成一个新的假图像。它这样做是因为它希望被鉴别器声明为真实的。简单地说,生成器的目标是创建图像来撒谎​​而不会被发现,即愚弄鉴别器。

发电机网络,信用
生成器网络,来源

鉴别器Discriminator

Discriminator 的目标是处理来自 Generator 的图像(如下所示的假图像)并将它们识别为假图像。它的作用是二元分类器。它需要两个输入;真实图像(来自训练数据)和来自生成器的生成图像。它比较它们并告诉它们是否来自相同的分布。“真实”表示它们来自相同的分布,而“假”表示它们所属的分布不同。

鉴别器网络,学分
鉴别器网络, 来源

GAN的训练与收敛

如何使用深度学习生成图像?GAN 的训练以另一种方式进行,即生成器保持不变,而判别器正在学习将生成的图像真正分类为“真实”或“假冒”,即捕捉生成器的缺陷,而判别器在生成器学习时保持不变愚弄鉴别器(生成器试图让鉴别器将其伪造的生成图像归类为真实图像)。这种来回训练允许 GAN 模型收敛,否则会变得棘手。这种训练有助于克服训练有素的生成器和训练有素的判别器的双赢局面,反之亦然,否则这是不可避免的。

生成器性能的提高会恶化鉴别器的性能,因为它不能轻易区分真假。如果生成器工作正常,判别器的准确度为 50%。实际上,判别器所做的与抛硬币进行预测没有什么不同。

这使得整体上不可能收敛:判别器的反馈对生成器来说意义不大。如果在 Discriminator 达到给出完全随机反馈的点后继续训练 GAN,那么 Generator 开始对垃圾(误导性反馈)进行训练,其自身的质量就会崩溃。

因此,交替训练对于 GAN 的收敛至关重要。

GAN架构,学分
GAN 架构, 学分

GAN 背后的数学

深度学习如何生成图像?现在我们更深入地研究 GAN 的数学基础。

GAN 包含两个神经网络:生成器 G 和鉴别器 D,它们相互竞争,因为它们一起学习训练数据集的未知分布。我们的明显目标是生成器生成与训练数据无法区分的图像。

因此,生成器的权重应该使得生成器生成鉴别器无法识别为假的假图像。这使得这个优化成为一个最小-最大优化问题,我们希望生成器的权重最小化鉴别器正确分类真实和假样本的速率(成本函数 J(D),如下所示)。我们想要使这个速率最大化的鉴别器的权重。由于在这种情况下使用二元类分类,我们使用二元交叉熵函数作为我们的成本函数。

甘数学
GAN数学

成本函数 J(D) 中的第一项表示馈入鉴别器的真实数据,它希望最大化预测一个的对数概率,显示数据是真实的。第二项表示生成器 G 生成的假图像。鉴别器想要最大化预测零的对数概率,显示数据是假的。另一方面,生成器寻求最小化鉴别器正确的对数概率。这种权衡的平衡点是这个优化问题的解决方案,即鉴别器损失的鞍点。

GAN数学
GAN数学

D()是给定图像属于训练数据的概率X。对于生成器;我们想最小化log(1-D(G(z)),即当D(G(z))为高时,则D认为G(z)X,这使得1-D(G(z))非常低。我们希望最小化这一点,这甚至更低。对于鉴别器,我们希望最大化D(X)(1-D(G(z)))。所以 的最优状态DP(x)=0.5。但是,生成器G应该进行训练,以便为鉴别器生成结果,D从而D无法区分zX

我们称之为最小-最大优化的原因在于鉴别器试图最大化目标而生成器试图最小化它。由于这种最小化和最大化,我们说它是 min-max。他们都通过交替梯度下降一起学习。


GAN 的实现

如何使用深度学习生成图像?本节将在编码中实现 GAN,以了解它在理论基础之前是如何工作的。为此,我们将使用 TensorFlow 库。使用的版本是 TensorFlow v2.3.0 和 Keras v2.4.3。

你可以自己编写代码,也可以在Google colab上访问完整代码 。

导入包

需要一些库,让我们全部获取

import os
import time
import numpy as np
import tensorflow as tf
from tensorflow.keras import layers
import argparse
from IPython import display
import matplotlib.pyplot as plt
# %matplotlib inline
from tensorflow import keras

数据加载和预处理

(x_train, y_train), (x_test, y_test) = tf.keras.datasets.fashion_mnist.load_data()
x_train = x_train.reshape(x_train.shape[0], 28, 28, 1).astype('float32')
x_train = (x_train - 127.5) / 127.5 # Normalize the images to [-1, 1]
# Batch and shuffle the data
train_dataset = tf.data.Dataset.from_tensor_slices(x_train).\
shuffle(60000).batch(args.batch_size)

我们使用tf_kerasdatasets 模块来加载 Fashion MNIST 数据集。该模块加载现成的数据。由于不需要标签来解决这个问题,我们只使用训练图像x_train。我们重塑图像并将它们转换为 float32(数据默认为 uint8 格式)。

然后,我们将数据从[0, 255]到标准化[-1, 1]。最后,我们构建 TensorFlow 输入管道。简而言之,tf.data.Dataset.from_tensor_slices接受训练数据、混洗并切成张量,允许我们在训练期间访问指定批量大小的张量。shuffle 中的缓冲区大小参数会影响 shuffle 的随机性。

创建生成器网络

def generator(image_dim):
  inputs = keras.Input(shape=(100,), name='input_layer')
  x = layers.Dense(128, kernel_initializer=tf.keras.initializers.he_uniform, name='dense_1')(inputs)
  #print(x.dtype)
  x = layers.LeakyReLU(0.2, name='leaky_relu_1')(x)
  x = layers.Dense(256, kernel_initializer=tf.keras.initializers.he_uniform, name='dense_2')(x) 
  x = layers.BatchNormalization(momentum=0.1,  epsilon=0.8, name='bn_1')(x)
  x = layers.LeakyReLU(0.2, name='leaky_relu_2')(x)
  x = layers.Dense(512, kernel_initializer=tf.keras.initializers.he_uniform, name='dense_3')(x) 
  x = layers.BatchNormalization(momentum=0.1,  epsilon=0.8, name='bn_2')(x)
  x = layers.LeakyReLU(0.2, name='leaky_relu_3')(x)
  x = layers.Dense(1024, kernel_initializer=tf.keras.initializers.he_uniform,  name='dense_4')(x) 
  x = layers.BatchNormalization(momentum=0.1,  epsilon=0.8, name='bn_3')(x)
  x = layers.LeakyReLU(0.2, name='leaky_relu_4')(x)
  x = layers.Dense(image_dim, kernel_initializer=tf.keras.initializers.he_uniform, activation='tanh',  name='dense_5')(x) 
  outputs = tf.reshape(x, [-1, 28, 28, 1], name='Reshape_Layer')
  model = tf.keras.Model(inputs, outputs, name="Generator")
  return model

深度学习如何生成图像?我们用从正态分布采样的 100 维噪声向量馈送生成器。接下来我们定义输入层,形状为 (100,)。在 TensorFlow 中,线性层的默认权重初始化器是 he_uniform。

批规范层的动量值更改为 0.1(默认为 0.99)。

最后,我们使用 tf.reshape 将 784-D 张量重塑为 (Batch Size, 28, 28, 1),其中第一个参数是输入张量,第二个参数是张量的新形状。最后,我们通过传递生成器函数的输入和输出层来创建模型。

创建判别器网络

def discriminator():
  inputs = keras.Input(shape=(28,28,1), name='input_layer')
  input = tf.reshape(inputs, [-1, 784], name='reshape_layer')
  x = layers.Dense(512, kernel_initializer=tf.keras.initializers.he_uniform, name='dense_1')(input)
  x = layers.LeakyReLU(0.2, name='leaky_relu_1')(x)
  x = layers.Dense(256, kernel_initializer=tf.keras.initializers.he_uniform, name='dense_2')(x) 
  x = layers.LeakyReLU(0.2, name='leaky_relu_2')(x)
  outputs = layers.Dense(1, kernel_initializer=tf.keras.initializers.he_uniform, activation='sigmoid', name='dense_3') (x) 
  model = tf.keras.Model(inputs, outputs, name="Discriminator")
  return model

鉴别器是一个二元分类器,仅由全连接层组成。因此,鉴别器需要一个形状张量 (Batch Size, 28, 28, 1)。但是鉴别器函数仅由密集层组成。因此,我们将张量重塑为形状向量(批量大小,784)。最后一层有 sigmoid 激活函数,它使输出值介于 0(假)和 1(真实)之间。

损失函数

binary_cross_entropy = tf.keras.losses.BinaryCrossentropy()

这就是二元交叉熵损失。

以下是生成器和鉴别器的个别损失。

生成器损耗

def generator_loss(fake_output):
  gen_loss = binary_cross_entropy(tf.ones_like(fake_output), fake_output)
  return gen_loss

鉴别器损失

def discriminator_loss(real_output, fake_output):
  real_loss = binary_cross_entropy(tf.ones_like(real_output), real_output)
  fake_loss = binary_cross_entropy(tf.zeros_like(fake_output), fake_output)
  total_loss = real_loss + fake_loss
  return total_loss

优化器

generator_optimizer = tf.keras.optimizers.Adam(learning_rate = args.lr, beta_1 = args.b1, beta_2 = args.b2 )
discriminator_optimizer = tf.keras.optimizers.Adam(learning_rate = args.lr, beta_1 = args.b1, beta_2 = args.b2 )

我们使用 Adam Optimizer 来优化 Generator 和 Discriminator,它有两个参数:

  1. 的学习率2e-4
  2. 贝塔系数:b1b2

这些计算反向传播期间梯度的运行平均值。

训练循环(所有功能组合用于训练 GAN)

@tf.function
def train_step(images):
  noise = tf.random.normal([args.batch_size, args.latent_dim])
  
  with tf.GradientTape() as gen_tape, tf.GradientTape() as disc_tape:
    generated_images = generator(noise, training=True)

    real_output = discriminator(images, training=True)
    fake_output = discriminator(generated_images, training=True)
    
    gen_loss = generator_loss(fake_output)
    disc_loss = discriminator_loss(real_output, fake_output)
      
      
  gradients_of_gen = gen_tape.gradient(gen_loss, generator.trainable_variables) # computing the gradients
  
  
  gradients_of_disc = disc_tape.gradient(disc_loss, discriminator.trainable_variables) # computing the gradients
      
  
  generator_optimizer.apply_gradients(zip(gradients_of_gen, generator.trainable_variables)) # updating generator parameter 
  
      
  discriminator_optimizer.apply_gradients(zip(gradients_of_disc,discriminator.trainable_variables)) # updating discriminator parameter

train_step 函数是整个 GAN 训练的核心。因为在这里,我们结合了上面定义的所有训练函数。

@tf.function将 train_step 函数编译为可调用的 TensorFlow 图。同时,减少训练时间 整个训练过程涉及以下步骤:

  • 首先,我们从正态分布中采样噪声并将其输入到生成器中。
  • 生成器产生假图像,然后输入判别器。鉴别器也给出了真实的图像。
  • 鉴别器将图像(来自生成器)分类为真实(从训练集提取)或假图像(由生成器生成)
  • 对于这些模型中的每一个,都会计算损失:gen_loss 和 disc_loss。
  • 计算梯度后,使用 Adam 优化器更新生成器和鉴别器参数。

训练

def train(dataset, epochs):
  for epoch in range(epochs):
    start = time.time()
    i = 0
    D_loss_list, G_loss_list = [], []
    for image_batch in dataset:
      i += 1
      train_step(image_batch)

    display.clear_output(wait=True)
    generate_and_save_images(generator,
                              epoch + 1,
                              seed)

    # Save the model every 15 epochs
    if (epoch + 1) % 15 == 0:
      checkpoint.save(file_prefix = checkpoint_prefix)

    print ('Time for epoch {} is {} sec'.format(epoch + 1, time.time()-start))

  # Generate after the final epoch
  display.clear_output(wait=True)
  generate_and_save_images(generator,
                          epochs,
                          seed)

终于到了我们可以坐下来观看魔术的时候了。但只是一秒钟。你必须将两个参数(训练数据和时代数)传递给上面的函数。给它那些,运行程序,放松一下,看看 GAN 可以为你做什么。

结果

深度学习如何生成图像?下面显示的三个图像网格,每个包含 16 个图像,由生成器在训练的三个不同阶段生成。你可以看到,最初,生成器会生成嘈杂的图像。但随着训练的进行,生成器会改进并开始生成看起来更逼真的时尚图像。

由我们的网络生成的图片
由我们的网络生成的图像

概括

如何使用深度学习生成图像?简而言之,我们开始介绍 GAN、我们为什么需要它们、它们的优势以及它们的直觉。然后我们深入挖掘并理解了 GAN 的组成部分,即 Generator 和 Discriminator。然后我们详细讨论了两个最重要的方面:训练策略和 GAN 的目标函数。

最后,我们使用 Fashion-MNIST 数据集在 TensorFlow 框架中实现了 GAN,并取得了惊人的结果。

这就是 GAN 和用它们生成图像的全部内容。该领域正以惊人的速度发展。但我相信这篇文章为你提供了大量关于 GAN 的理论和实践知识,你可以轻松跟上正在进行的进步和改进。

请记住,你可以在Google colab 中获得所有这些代码的工作示例 。

谢谢阅读

木子山

发表评论

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: