Skip to content

Latest commit

 

History

History
1002 lines (570 loc) · 37 KB

4.md

File metadata and controls

1002 lines (570 loc) · 37 KB

四、使用 DCGAN 生成动漫角色

众所周知,卷积层确实擅长处理图像。 他们能够学习重要的特征,例如边缘,形状和复杂的对象,有效的, ,例如神经网络,例如 Inception,AlexNet, 视觉几何组VGG)和 ResNet。 Ian Goodfellow 等人在其名为《生成对抗网络》的论文中提出了具有密集层的生成对抗网络GAN),该网络可在以下链接获得。 复杂的神经网络,例如卷积神经网络CNN),循环神经网络RNN)和长短期记忆LSTM)最初并未在 GAN 中进行测试。 深度卷积生成对抗网络DCGAN)的发展是使用 CNN 进行图像生成的重要一步。 DCGAN 使用卷积层而不是密集层。 它们是由研究人员 Alec Radford , Luke Metz , Soumith Chintala 等,在其论文《使用深度卷积生成对抗网络的无监督表示学习》中提出的,可以在以下链接中找到。 从那时起,DCGAN 被广泛用于各种图像生成任务。 在本章中,我们将使用 DCGAN 架构生成动漫角色。

在本章中,我们将介绍以下主题:

  • DCGAN 简介
  • GAN 网络的架构细节
  • 建立项目
  • 为训练准备数据集
  • DCGAN 的 Keras 实现以生成动画角色
  • 在动漫角色数据集上训练 DCGAN
  • 评估训练好的模型
  • 通过优化超参数优化网络
  • DCGAN 的实际应用

DCGAN 简介

CNN 在计算机视觉任务中非常出色,无论是用于分类图像还是检测图像中的对象。 CNN 善于理解图像,以至于激发研究人员在 GAN 网络中使用 CNN。 最初,GAN 官方论文的作者介绍了仅具有密集层的深层神经网络DNN)。 在 GAN 网络的原始实现中未使用卷积层。 在以前的 GAN 中,生成器和判别器网络仅使用密集的隐藏层。 相反,作者建议在 GAN 设置中可以使用不同的神经网络架构。

DCGAN 扩展了在判别器和生成器网络中使用卷积层的思想。 DCGAN 的设置类似于朴素 GAN。 它由两个网络组成:生成器和判别器。 生成器是具有卷积层的 DNN,而判别器是具有卷积层的 DNN。 训练 DCGAN 类似于训练普通 GAN 网络。 在第一章中,我们了解到网络参与了非合作博弈,其中判别器网络将其误差反向传播到生成器网络,生成器网络使用此误差来提高其权重。

在下一部分中,我们将探索两个网络的架构。

DCGAN 的架构细节

如前所述,DCGAN 网络在两个网络中都使用卷积层。 重申一下,CNN 是一个具有卷积层,紧随其后的归一化或池化层以及紧随其后的激活函数的网络。 在 DCGAN 中,判别器网络会拍摄图像,在卷积和池化层的帮助下对图像进行降采样,然后使用密集的分类层将图像分类为真实图像或伪图像。 生成器网络从潜在空间中获取随机噪声向量,使用上采样机制对其进行上采样,最后生成图像。 我们使用 Leaky ReLU 作为隐藏层的激活函数,并在 0.4 和 0.7 之间进行滤除以避免过拟合。

让我们看一下两个网络的配置。

配置生成器网络

在继续之前,让我们看一下生成器网络的架构:

来源:arXiv:1511.06434 [cs.LG]

上图包含了生成器网络架构中的不同层,并显示了它如何生成分辨率为64 x 64 x 3的图像。

DCGAN 的生成器网络包含 10 层。 它执行跨步卷积以增加张量的空间分辨率。 在 Keras 中,上采样和卷积层的组合等于跨步卷积层。 基本上,生成器网络会从均匀分布中获取采样的噪声向量,并不断对其进行转换,直到生成最终图像为止。 换句话说,它采取形状的张量(batch_size, 100),并输出形状的张量(batch_size, 64, 64, 3)。

让我们看一下生成器网络中的不同层:

编号 层名称 配置
1 输入层 input_shape=(batch_size, 100)output_shape=(batch_size, 100)
2 密集层 neurons=2048input_shape=(batch_size, 100)output_shape=(batch_size, 2048)activation='relu'
3. 密集层 neurons=16384input_shape=(batch_size, 100)output_shape=(batch_size, 2048)batch_normalization=Yesactivation='relu'
4. 重塑层 input_shape=(batch_size=16384)outp ut_shape=(batch_size, 8, 8, 256)
5. 上采样层 size=(2, 2)input_shape=(batch_size, 8, 8, 256)output_shape=(batch_size, 16, 16, 256)
6. 2D 卷积层 filters=128kernel_size=(5, 5)strides=(1, 1)padding='same'input_shape=(batch_size, 16, 16, 256)output_shape=(batch_size, 16, 16, 128)activation='relu'
7. 上采样层 size=(2, 2)input_shape=(batch_size, 16, 16, 128)output_shape=(batch_size, 32, 32, 128)
8. 2D 卷积层 filters=64kernel_size=(5, 5)strides=(1, 1)padding='same'activation=ReLUinput_shape=(batch_size, 32, 32, 128)output_shape=(batch_size, 32, 32, 64)activation='relu'
9. 上采样层 size=(2, 2)input_shape=(batch_size, 32, 32, 64)output_shape=(batch_size, 64, 64, 64)
10. 2D 卷积层 filters=3kernel_size=(5, 5)strides=(1, 1)padding='same'activation=ReLUinput_shape=(batch_size, 64, 64, 64)output_shape=(batch_size, 64, 64, 3)activation='tanh'

L 等人研究了张量如何从第一层流到最后一层。 下图显示了不同层的输入和输出形状:

该配置对具有 TensorFlow 后端和channels_last格式的 Keras API 有效。

配置判别器网络

在继续之前,让我们看一下判别器网络的架构:

上图给出了生成器网络架构的顶层概述。

如前所述,判别器网络是一个包含 10 层的 CNN(您可以根据需要向网络添加更多层)。 基本上,它会拍摄大小为64 x 64 x 3的图像,使用 2D 卷积层对其进行下采样,然后将其传递到完全连接的层进行分类。 它的输出是对给定图像是伪图像还是真实图像的预测。 可以为 0 或 1;可以为 0。 如果输出为 1,则传递到判别器的图像是真实的;如果输出为 0,则传递的图像是伪图像。

让我们看一下判别器网络中的各层:

编号 层名称 配置
1. 输入层 input_shape=(batch_size, 64, 64, 3)output_shape=(batch_size, 64, 64, 3)
2. 2D 卷积层 filters=128kernel_size=(5, 5)strides=(1, 1)padding='valid'input_shape=(batch_size, 64, 64, 3)output_shape=(batch_size, 64, 64, 128)activation='leakyrelu'leaky_relu_alpha=0.2
3. 2D 最大池化 pool_size=(2, 2)input_shape=(batch_size, 64, 64, 128)output_shape=(batch_size, 32, 32, 128)
4. 2D 卷积层 filters=256kernel_size=(3, 3)strides=(1, 1)padding='valid'input_shape=(batch_size, 32, 32, 128)output_shape=(batch_size, 30, 30, 256)activation='leakyrelu'leaky_relu_alpha=0.2
5. 2D 最大池化 pool_size=(2, 2)input_shape=(batch_size, 30, 30, 256)output_shape=(batch_size, 15, 15, 256)
6. 2D 卷积层 filters=512kernel_size=(3, 3)strides=(1, 1)padding='valid'input_shape=(batch_size, 15, 15, 256)output_shape=(batch_size, 13, 13, 512)activation='leakyrelu'leaky_relu_alpha=0.2
7. 2D 最大池化 pool_size=(2, 2)input_shape=(batch_size, 13, 13, 512)output_shape=(batch_size, 6, 6, 512)
8. 展开层 input_shape=(batch_size, 6, 6, 512)output_shape=(batch_size, 18432)
9. 密集层 neurons=1024input_shape=(batch_size, 18432)output_shape=(batch_size, 1024)activation='leakyrelu''leakyrelu_alpha'=0.2
10. 密集层 neurons=1input_shape=(batch_size, 1024)output_shape=(batch_size, 1)activation='sigmoid'

L 等人研究了张量如何从第一层流到最后一层。 下图显示了不同层的输入和输出形状:

该配置对具有 TensorFlow 后端和channels_last格式的 Keras API 有效。

设置项目

我们已经克隆/下载了所有章节的完整代码。 下载的代码包含一个名为Chapter04的目录,该目录包含本章的全部代码。 执行以下命令来设置项目:

  1. 首先,导航到父目录,如下所示:
cd Generative-Adversarial-Networks-Projects
  1. 现在,将目录从当前目录更改为Chapter04
cd Chapter04
  1. 接下来,为该项目创建一个 Python 虚拟环境:
virtualenv venv
virtualenv venv -p python3 # Create a virtual environment using 
 python3 interpreter
virtualenv venv -p python2 # Create a virtual environment using 
 python2 interpreter

我们将为此项目使用此新创建的虚拟环境。 每章都有其自己单独的虚拟环境。

  1. 接下来,激活虚拟环境:
source venv/bin/activate

激活虚拟环境后,所有其他命令将在此虚拟环境中执行。

  1. 接下来,通过执行以下命令来安装requirements.txt文件中给出的所有要求:
pip install -r requirements.txt

您可以参考 README.md 文件,以获取有关如何设置项目的更多说明。 开发人员经常会遇到依赖关系不匹配的问题。 为每个项目创建一个单独的虚拟环境将解决此问题。

在本节中,我们已成功设置项目并安装了所需的依赖项。 在下一部分中,我们将使用数据集,包括下载和清理数据集。

下载并准备动漫角色数据集

要训练 DCGAN 网络,我们需要一个动漫人物数据集,其中包含人物的裁剪面孔。 收集数据集有多种方法。 我们可以使用公开可用的数据集,也可以抓取一个,只要不违反网站的抓取策略即可。 在本章中,我们将仅出于教育和演示目的刮取图像。 我们使用名为 gallery-dl 的搜寻器工具从 pixiv.net 抓取了图像。 这是一个命令行工具,可用于从网站下载图像集,例如 pixiv.netexhentai.orgdanbooru.donmai.us 和更多。 它可通过以下链接获得

下载数据集

在本节中,我们将介绍安装依赖项和下载数据集所需的不同步骤。 在执行以下命令之前,激活为此项目创建的虚拟环境:

  1. 执行以下命令安装gallery-dl
pip install --upgrade gallery-dl
  1. 或者,您可以使用以下命令安装gallery-dl的最新开发版本:
pip install --upgrade https://github.com/mikf/gallery-dl/archive/master.zip
  1. 如果上述命令不起作用,请按照官方存储库中的说明进行操作:
# Official gallery-dl Github repo
https://github.com/mikf/gallery-dl
  1. 最后,执行以下命令以使用gallery-dl.danbooru.donmai.us下载图像:
gallery-dl https://danbooru.donmai.us/posts?tags=face

下载图像需要您自担风险。 所提供的信息仅用于教育目的,我们不支持非法刮取。 我们没有图像的版权,因为图像由其各自所有者托管。 出于商业目的,请联系网站的各自所有者或您所使用的内容。

探索数据集

在裁剪或调整图像大小之前,请查看下载的图像:

如您所见,有些图像还包含其他身体部位,我们在训练图像中不需要这些部位。 在下一部分中,我们将仅从这些图像中裁剪出人脸。 此外,我们会将所有图像调整为训练所需的大小。

裁剪数据集中的图像并调整其大小

在本节中,我们将从图像中裁剪出面孔。 我们将使用python-animeface从图像中裁剪出面孔。 这是一个开源 GitHub 存储库,可从命令行的图像中自动裁剪人脸。 它可以通过以下链接公开获得

执行以下步骤来裁剪图像并调整其大小:

  1. 首先,下载python-animeface
pip install animeface
  1. 接下来,导入任务所需的模块:
import glob
import os

import animeface
from PIL import Image
  1. 接下来,定义参数:
total_num_faces = 0
  1. 接下来,遍历所有图像以进行裁剪并一一调整其大小:
for index, filename in  
    enumerate(glob.glob('/path/to/directory/containing/images/*.*')):
  1. 在循环内,打开当前图像并检测其中的人脸:
  try:
        # Open image
        im = Image.open(filename)

        # Detect faces
        faces = animeface.detect(im)
    except Exception as e:
        print("Exception:{}".format(e))
        continue
  1. 接下来,获取图像中检测到的人脸坐标:
    fp = faces[0].face.pos

    # Get coordinates of the face detected in the image
  coordinates = (fp.x, fp.y, fp.x+fp.width, fp.y+fp.height)
  1. 现在,将人脸裁剪出图像:
 # Crop image  cropped_image = im.crop(coordinates)
  1. 接下来,将裁剪后的人脸图像调整为(64, 64)的大小:
 # Resize image  cropped_image = cropped_image.resize((64, 64), Image.ANTIALIAS)
  1. 最后,将裁剪并调整大小的图像保存到所需目录:
 cropped_image.save("/path/to/directory/to/store/cropped/images/filename.png"))

包装在 Python 函数中的完整代码如下所示:

import glob
import os

import animeface
from PIL import Image

total_num_faces = 0   for index, filename in enumerate(glob.glob('/path/to/directory/containing/images/*.*')):
    # Open image and detect faces
  try:
        im = Image.open(filename)
        faces = animeface.detect(im)
    except Exception as e:
        print("Exception:{}".format(e))
        continue

 # If no faces found in the current image if len(faces) == 0:
        print("No faces found in the image")
        continue    fp = faces[0].face.pos

    # Get coordinates of the face detected in the image
  coordinates = (fp.x, fp.y, fp.x+fp.width, fp.y+fp.height)

    # Crop image
  cropped_image = im.crop(coordinates)

    # Resize image
  cropped_image = cropped_image.resize((64, 64), Image.ANTIALIAS)

    # Show cropped and resized image
 # cropped_image.show()   # Save it in the output directory  cropped_image.save("/path/to/directory/to/store/cropped/images/filename.png"))

    print("Cropped image saved successfully")
    total_num_faces += 1   print("Number of faces detected till now:{}".format(total_num_faces))

print("Total number of faces:{}".format(total_num_faces))

前面的脚本将从包含下载图像的文件夹中加载所有图像,使用python-animeface库检测人脸,然后从初始图像中裁剪出人脸。 然后,裁切后的图像将被调整为64 x 64的大小。如果要更改图像的大小,请相应地更改生成器和判别器的架构。 我们现在准备在我们的网络上工作。

使用 Keras 实现 DCGAN

在本节中,我们将在 Keras 框架中编写 DCGAN 的实现。 Keras 是一个使用 TensorFlow 或 Teano 作为后端的元框架。 它提供了用于神经网络的高级 API。 与低级框架(如 TensorFlow)相比,它还具有预构建的神经网络层,优化器,正则化器,初始化器和数据预处理层,可轻松进行原型制作。 让我们开始编写生成器网络的实现。

生成器

如 DCGAN 部分的“架构”中所述,生成器网络由一些 2D 卷积层,上采样层,整形层和批归一化层组成 。 在 Keras 中,每个操作都可以指定为一个层。 甚至激活函数也是 Keras 中的层,可以像正常的密集层一样添加到模型中。

执行以下步骤来创建生成器网络:

  1. 让我们开始创建一个Sequential Keras 模型:
gen_model = Sequential()
  1. 接下来,添加一个具有 2,048 个节点的密集层,然后添加一个激活层tanh
gen_model.add(Dense(units=2048))
gen_model.add(Activation('tanh'))
  1. 接下来,添加第二层,它也是一个具有 16,384 个神经元的密集层。 接下来是batch normalization层,其中default hyperparameterstanh作为激活函数
gen_model.add(Dense(256`8`8))
gen_model.add(BatchNormalization())
gen_model.add(Activation('tanh')) 

第二密集层的输出是大小为16384的张量。 此处,(256, 8, 8)是密集层中神经元的数量。

  1. 接下来,向网络中添加一个重塑层,以将张量从最后一层重塑为(batch_size, 8, 8, 256)**:**形状的张量
# Reshape layer
gen_model.add(Reshape((8, 8, 256), input_shape=(256`8`8,)))
  1. 接下来,添加 2D 上采样层以将形状从(8, 8, 256)更改为(16, 16, 256)。 上采样大小为(2, 2),这将张量的大小增加到其原始大小的两倍。 在这里,我们有 256 个张量为16 x 16:的张量。
gen_model.add(UpSampling2D(size=(2, 2)))
  1. 接下来,添加一个 2D 卷积层。 这使用指定数量的过滤器在张量上应用 2D 卷积。 在这里,我们使用 64 个过滤器和一个(5, 5)形状的内核:
gen_model.add(Conv2D(128, (5, 5), padding='same'))
gen_model.add(Activation('tanh')) 
  1. 接下来,添加 2D 向上采样层以将张量的形状从 (batch_size, 16, 16, 64)更改为(batch_size, 32, 32, 64)
gen_model.add(UpSampling2D(size=(2, 2))) 

2D 上采样层将张量的行和列分别以[0][1]的大小重复 。

  1. 接下来,在第二个 2D 卷积层上添加 64 过滤器和,将(5, 5)核大小tanh作为激活函数:
gen_model.add(Conv2D(64, (5, 5), padding='same'))
gen_model.add(Activation('tanh'))
  1. 接下来,添加 2D 上采样层,将形状从 (batch_size, 32, 32, 64)更改为(batch_size, 64, 64, 64)
gen_model.add(UpSampling2D(size=(2, 2))) 
  1. 最后,在第三个 2D 卷积层上添加三个过滤器核大小(5, 5) ,然后是tanh作为激活函数:
gen_model.add(Conv2D(3, (5, 5), padding='same'))
gen_model.add(Activation('tanh'))

生成器网络将输出(batch_size, 64, 64, 3)形状的张量。 这批张量中的一个图像张量类似于具有三个通道的大小为64 x 64的图像: 红色,绿色蓝色RGB)。

用 Python 方法包装的生成器网络的完整代码如下所示:

def get_generator():
    gen_model = Sequential()

    gen_model.add(Dense(input_dim=100, output_dim=2048))
    gen_model.add(LeakyReLU(alpha=0.2))

    gen_model.add(Dense(256 * 8 * 8))
    gen_model.add(BatchNormalization())
    gen_model.add(LeakyReLU(alpha=0.2))

    gen_model.add(Reshape((8, 8, 256), input_shape=(256 * 8 * 8,)))
    gen_model.add(UpSampling2D(size=(2, 2)))

    gen_model.add(Conv2D(128, (5, 5), padding='same'))
    gen_model.add(LeakyReLU(alpha=0.2))

    gen_model.add(UpSampling2D(size=(2, 2)))

    gen_model.add(Conv2D(64, (5, 5), padding='same'))
    gen_model.add(LeakyReLU(alpha=0.2))

    gen_model.add(UpSampling2D(size=(2, 2)))

    gen_model.add(Conv2D(3, (5, 5), padding='same'))
    gen_model.add(LeakyReLU(alpha=0.2))
    return gen_model

现在我们已经创建了生成器网络,让我们开始创建判别器网络。

判别器

如 DCGAN 的架构中所述,判别器网络具有三个 2D 卷积层,每个层均具有激活函数,后跟两个最大合并层。 网络的尾部包含两个完全连接的(密集)层,用作分类层。 首先,让我们看一下判别器网络中的不同层:

  • 所有卷积层都具有LeakyReLU作为激活函数,其alpha值为 0.2
  • 卷积层分别具有 128、256 和 512 个过滤器。 它们的核大小分别为(5, 5)(3, 3)(3, 3)
  • 在卷积层之后,我们有一个展开层,它将输入平坦化为一维张量。
  • 此后,网络具有两个密集层,分别具有 1,024 个神经元和一个神经元。
  • 第一密集层具有LeakyReLU作为激活函数,而第二层具有 Sigmoid 作为激活函数。 Sigmoid 激活用于二分类。 我们正在训练辨别器网络,以区分真实图像还是伪图像。

执行以下步骤来创建判别器网络:

  1. 让我们开始创建一个Sequential Keras 模型:
dis_model = Sequential()
  1. 添加一个 2D 卷积层,该层采用形状为(64, 64, 3)的输入图像。 该层的超参数如下。 另外,添加具有0.2alpha值的LeakyReLU作为激活函数:
    • 过滤器:128
    • 核大小(5, 5)
    • 填充:相同
dis_model.add(Conv2D(filters=128, kernel_size=5, padding='same', 
 input_shape=(64, 64, 3)))
dis_model.add(LeakyReLU(alpha=0.2))
  1. 接下来,添加池大小为(2, 2)的 2D 最大池化层。 最大池用于对图像表示进行下采样,并通过在表示的非重叠子区域上使用最大过滤来应用它:
dis_model.add(MaxPooling2D(pool_size=(2, 2)))

来自第一层的输出张量的形状将为(batch_size, 32, 32, 128)

  1. 接下来,添加具有以下配置的另一个 2D 卷积层:
    • 过滤器:256
    • 核大小(3, 3)
    • 激活函数LeakyReLU,具有alpha 0.2
    • 2D 最大池中的池大小(2, 2)
dis_model.add(Conv2D(filters=256, kernel_size=3))
dis_model.add(LeakyReLU(alpha=0.2))
dis_model.add(MaxPooling2D(pool_size=(2, 2)))

该层的输出张量的形状将为 (batch_size, 30, 30, 256)

  1. 接下来,添加具有以下配置的第三个 2D 卷积层:
    • 过滤器: 512
    • 核大小(3, 3)
    • 激活函数LeakyReLU,带有alpha 0.2
    • 2D 最大池中的池大小(2, 2)
dis_model.add(Conv2D(512, (3, 3)))
dis_model.add(LeakyReLU(alpha=0.2))
dis_model.add(MaxPooling2D(pool_size=(2, 2)))

该层的输出张量的形状将为 (batch_size, 13, 13, 512)

  1. 接下来,添加一个展开层。 这将使输入变平而不影响批量大小。 它产生一个二维张量:
dis_model.add(Flatten())

来自平坦化层的张量的输出形状将为(batch_size, 18432,)

  1. 接下来,添加具有1024神经元和alpha 0.2 作为激活函数的LeakyReLU的密集层:
dis_model.add(Dense(1024))
dis_model.add(LeakyReLU(alpha=0.2))
  1. 最后,添加带有一个神经元的密集层以进行二分类。 Sigmoid 函数最适合二分类,因为它给出了分类的可能性:
dis_model.add(Dense(1))
dis_model.add(Activation('tanh'))

网络将生成形状为(batch_size, 1)的输出张量。 输出张量包含类的概率。

包裹在 Python 方法中的判别器网络的完整代码如下:

def get_discriminator():
    dis_model = Sequential()
    dis_model.add(
        Conv2D(128, (5, 5),
               padding='same',
               input_shape=(64, 64, 3))
    )
    dis_model.add(LeakyReLU(alpha=0.2))
    dis_model.add(MaxPooling2D(pool_size=(2, 2)))

    dis_model.add(Conv2D(256, (3, 3)))
    dis_model.add(LeakyReLU(alpha=0.2))
    dis_model.add(MaxPooling2D(pool_size=(2, 2)))

    dis_model.add(Conv2D(512, (3, 3)))
    dis_model.add(LeakyReLU(alpha=0.2))
    dis_model.add(MaxPooling2D(pool_size=(2, 2)))

    dis_model.add(Flatten())
    dis_model.add(Dense(1024))
    dis_model.add(LeakyReLU(alpha=0.2))

    dis_model.add(Dense(1))
    dis_model.add(Activation('sigmoid'))

    return dis_model

在本节中,我们已成功实现了判别器和生成器网络。 在下一部分中,我们将在“下载和准备动漫角色数据集”部分中准备的数据集上训练模型。

训练 DCGAN

同样,训练 DCGAN 类似于训练朴素 GAN 网络。 这是一个四步过程:

  1. 加载数据集。
  2. 构建和编译网络。
  3. 训练判别器网络。
  4. 训练生成器网络。

我们将在本节中一步一步地进行这些步骤。

让我们从定义变量和超参数开始:

dataset_dir = "/Path/to/dataset/directory/*.*" batch_size = 128  z_shape = 100 epochs = 10000 dis_learning_rate = 0.0005 gen_learning_rate = 0.0005 dis_momentum = 0.9 gen_momentum = 0.9 dis_nesterov = True gen_nesterov = True 

在这里,我们为训练指定了不同的超参数。 现在,我们将看到如何为训练加载数据集。

加载样本

要训​​练 DCGAN 网络,我们需要将数据集加载到内存中,并且需要定义一种机制来加载成批的内存。 执行以下步骤以加载数据集:

  1. 首先加载所有裁剪,调整大小并保存在cropped文件夹中的图像。 正确指定目录的路径,以便glob.glob方法可以创建其中所有文件的列表。 要读取图像,请使用scipy.misc模块中的imread方法。 以下代码显示了加载目录中所有图像的不同步骤:
# Loading images all_images = []
for index, filename in enumerate(glob.glob('/Path/to/cropped/images/directory/*.*')):
    image = imread(filename, flatten=False, mode='RGB')
    all_images.append(image)
  1. 接下来,为所有图像创建一个ndarray。 最终ndarray的形状将为(total_num_images, 64, 64, 3)。 此外,标准化所有图像:
# Convert to Numpy ndarray
X = np.array(all_images)
X = (X - 127.5) / 127.5 

现在我们已经加载了数据集,接下来我们将看到如何构建和编译网络。

建立和编译网络

在本节中,我们将构建和编译训练所需的网络:

  1. 首先定义训练所需的优化器,如下所示:
# Define optimizers dis_optimizer = SGD(lr=dis_learning_rate, momentum=dis_momentum, nesterov=dis_nesterov)
gen_optimizer = SGD(lr=gen_learning_rate, momentum=gen_momentum, nesterov=gen_nesterov)
  1. 接下来,创建生成器模型的实例,并编译生成器模型(编译将初始化权重参数,优化器算法,损失函数以及使用网络所需的其他必要步骤):
gen_model = build_generator()
gen_model.compile(loss='binary_crossentropy', optimizer=gen_optimizer)

使用binary_crossentropy作为生成器网络的loss函数,并使用gen_optimizer作为优化器。

  1. 接下来,创建判别模型的实例,并对其进行编译,如下所示:
dis_model = build_discriminator()
dis_model.compile(loss='binary_crossentropy', optimizer=dis_optimizer)

同样,使用binary_crossentropy作为判别器网络的损失函数,并使用dis_optimizer作为优化器。

  1. 接下来,创建一个对抗模型。 一个对抗者将两个网络都包含在一个模型中。 对抗模型的架构如下:
    • 输入 -> 生成器 -> 判别器 -> 输出

创建和编译对抗模型的代码如下:

adversarial_model = Sequential()
adversarial_model.add(gen_model)
dis_model.trainable = False adversarial_model.add(dis_model)

当我们训练该网络时,我们不想训练判别器网络,因此在将其添加到对抗模型之前,使其变为不可训练的。

编译对抗模型,如下所示:

adversarial_model.compile(loss='binary_crossentropy', optimizer=gen_optimizer)

使用binary_crossentropy作为损失函数,使用gen_optimizer作为对抗模型的优化器。

在开始训练之前,添加 TensorBoard 以可视化显示损失,如下所示:

tensorboard = TensorBoard(log_dir="logs/{}".format(time.time()), write_images=True, write_grads=True, write_graph=True)
tensorboard.set_model(gen_model)
tensorboard.set_model(dis_model)

我们将针对指定的迭代次数训练网络,因此创建一个应运行指定次数的循环。 在每个周期内,我们将在大小为 128 的微型批量上训练网络。 计算需要处理的批量数量:

for epoch in range(epcohs):
    print("Epoch is", epoch)
    number_of_batches = int(X.shape[0] / batch_size)
 print("Number of batches", number_of_batches)
    for index in range(number_of_batches):

现在,我们将仔细研究训练过程。 以下几点说明了 DCGAN 训练中涉及的不同步骤:

  • 最初,这两个网络都是幼稚的并且具有随机权重。
  • 训练 DCGAN 网络的标准过程是首先对一批样本进行判别器训练。
  • 为此,我们需要假样本和真实样本。 我们已经有了真实的样本,因此现在需要生成伪样本。
  • 要生成伪样本,请在均匀分布上创建形状为(100, )的潜向量。 将此潜向量馈入未经训练的生成器网络。 生成器网络将生成伪样本,我们将其用于训练判别器网络。
  • 合并真实图像和伪图像以创建一组新的样本图像。 我们还需要创建一个标签数组:真实图像使用标签 1,伪图像使用标签 0。

训练判别器网络

执行以下步骤来训练判别器网络:

  1. 首先从正态分布中采样一批噪声向量,如下所示:
z_noise = np.random.normal(0, 1, size=(batch_size, z_shape))

要对值进行采样,请使用 Numpy 库中np.random模块中的normal()方法。

  1. 接下来,从所有图像集中采样一批真实图像:
image_batch = X[index * batch_size:(index + 1) * batch_size]
  1. 接下来,使用生成器网络生成一批伪图像:
generated_images = gen_model.predict_on_batch(z_noise)
  1. 接下来,创建真实标签和伪标签:
y_real = np.ones(batch_size) - np.random.random_sample(batch_size) * 0.2 y_fake = np.random.random_sample(batch_size) * 0.2
  1. 接下来,在真实图像和真实标签上训练判别器网络:
 dis_loss_real = dis_model.train_on_batch(image_batch, y_real)
  1. 同样,在伪造图像和伪造标签上对其进行训练:
dis_loss_fake = dis_model.train_on_batch(generated_images, y_fake)
  1. 接下来,计算平均损失并将其打印到控制台:
d_loss = (dis_loss_real+dis_loss_fake)/2 print("d_loss:", d_loss)

到目前为止,我们一直在训练判别器网络。 在下一部分中,让我们训练生成器网络。

训练生成器网络

为了训练生成器网络,我们必须训练对抗模型。 当我们训练对抗模型时,它只训练生成器网络,而冻结判别器网络。 由于我们已经训练过判别器网络,因此我们不会对其进行训练。 执行以下步骤来训练对抗模型:

  1. 首先重新创建一批噪声向量。 从高斯/正态分布中采样以下噪声向量:
z_noise = np.random.normal(0, 1, size=(batch_size, z_shape))
  1. 接下来,对这批噪声向量训练对抗模型,如下所示:
g_loss = adversarial_model.train_on_batch(z_noise, [1] * batch_size)

我们在一批噪声向量和实数标签上训练对抗模型。 在这里,实数标签是一个所有值均等于 1 的向量。我们还在训练生成器,以欺骗判别器网络。 为此,我们为它提供一个向量,该向量的所有值均等于 1。在此步骤中,生成器将接收来自生成器网络的反馈,并相应地进行改进。

  1. 最后,将生成器损失打印到控制台以跟踪损失:
print("g_loss:", g_loss)

有一种被动的方法可以评估训练过程。 每 10 个周期后,生成伪造图像并手动检查图像质量:

 if epoch % 10 == 0:
        z_noise = np.random.normal(0, 1, size=(batch_size, z_shape))
        gen_images1 = gen_model.predict_on_batch(z_noise)

        for img in gen_images1[:2]:
            save_rgb_img(img, "results/one_{}.png".format(epoch))

这些图像将帮助您决定是继续训练还是尽早停止训练。 如果生成的高分辨率图像的质量良好,请停止训练。 或者继续训练,直到您的模型变好为止。

我们已经成功地在动画角色数据集上训练了 DCGAN 网络。 现在我们可以使用该模型生成动漫人物图像。

生成图像

为了生成图像,我们需要一个从潜在空间采样的噪声向量。 Numpy 有一种称为uniform()的方法,可以根据均匀分布生成向量。 让我们看看如何在以下步骤中生成图像:

  1. 通过添加以下代码行,创建大小为(batch_size, 100)的噪声向量:
z_noise = np.random.normal(0, 1, size=(batch_size, z_shape))
  1. 然后,使用生成器模型的predict_on_batch方法生成图像。 将上一步中创建的噪声向量馈入其中:
gen_images = gen_model.predict_on_batch(z_noise)
  1. 现在我们已经生成了图像,通过添加以下代码行将其保存。 创建一个名为results的目录来存储生成的图像:
imsave('results/image_{}.jpg'.format(epoch),gen_images[0])

现在,您可以打开这些生成的图像以测量生成的模型的质量。 这是一种评估模型表现的被动方法。

保存模型

在 Keras 中保存模型只需要一行代码。 要保存生成器模型,请添加以下行:

# Specify the path for the generator model
gen_model.save("directory/for/the/generator/model.h5") 

同样,通过添加以下行来保存判别器模型:

# Specify the path for the discriminator model
dis_model.save("directory/for/the/discriminator/model.h5") 

可视化生成的图像

在将网络训练了 100 个时间段后,生成器将开始生成合理的图像。 让我们看一下生成的图像。

在 100 个周期之后,图像显示如下:

在 200 个周期之后,图像显示如下:

要生成非常好的图像,请将网络训练 10,000 个周期。

可视化损失

为了可视化训练的损失,请按以下方式启动 TensorBoard 服务器:

tensorboard --logdir=logs

现在,在浏览器中打开localhost:6006。 Tensorboard 的标量部分包含两种损失的图:

这些图将帮助您决定是继续还是停止训练。 如果损失不再减少,您就可以停止训练,因为没有改善的机会。 如果损失持续增加,则必须停止训练。 使用超参数,然后选择一组您认为可以提供更好结果的超参数。 如果损失逐渐减少,请继续训练模型。

可视化图

Tensorboard 的GRAPHS部分包含两个网络的图。 如果网络表现不佳,这些图可以帮助您调试网络。 它们还显示了每个图中的张量流和不同的操作:

调整超参数

超参数是模型的属性,在模型训练期间是固定的。 不同的参数可以具有不同的精度。 让我们看一下一些常用的超参数:

  • 学习率
  • 批量大小
  • 周期数
  • 生成器优化器
  • 判别器优化器
  • 层数
  • 密集层中的单元数
  • 激活函数
  • 损失函数

在“使用 Keras 实现 DCGAN”的部分中,学习率是固定的:生成器模型为 0.0005,判别器模型为 0.0005。 批量大小为 128。调整这些值可能会导致我们创建更好的模型。 如果您的模型没有生成合理的图像,请尝试更改这些值,然后再次运行模型。

DCGAN 的实际应用

可以为不同的使用案例定制 DCGAN。 DCGAN 的各种实际应用包括:

  • 动画角色的生成:目前,动画师使用计算机软件手动绘制字符,有时还绘制在纸上。 这是一个手动过程,通常需要很多时间。 使用 DCGAN,可以在更短的时间内生成新的动漫角色,从而改善了创作过程。

  • 数据集的扩充:如果您想训练一个监督的机器学习模型,要训练一个好的模型,您将需要一个大的数据集。 DCGAN 可以通过扩展现有数据集来提供帮助,因此可以增加监督模型训练所需的数据集大小。

  • MNIST 字符的生成:MNIST 数据集包含 60,000 张手写数字图像。 要训​​练复杂的监督学习模型,MNIST 数据集是不够的。 DCGAN 一旦受过训练,将生成可以添加到原始数据集中的新数字。

  • 人脸生成:DCGAN 使用卷积神经网络,非常擅长生成逼真的图像。

  • 特征提取器:训练后,可以使用判别器从中间层提取特征。 这些提取的特征在样式迁移和人脸识别等任务中很有用。 样式迁移涉及生成图像的内部表示,用于计算样式和内容损失。 请参阅以下论文,以了解有关样式迁移的更多信息。

总结

在本章中,我们介绍了深度卷积生成对抗网络。 我们从基本介绍 DCGAN 开始,然后深入探讨了 DCGAN 网络的架构。 之后,我们设置项目并安装必要的依赖项。 然后,我们研究了下载和准备数据集所需的不同步骤。 然后,我们准备了网络的 Keras 实现,并在我们的数据集中对其进行了训练。 经过训练后,我们将其用于生成新的动漫角色。 我们还探讨了 DCGAN 在实际用例中的不同应用。

在下一章中,我们将研究用于高分辨率图像生成的 SRGAN。