生成对抗网络项目:6~9(3)

本文涉及的产品
服务治理 MSE Sentinel/OpenSergo,Agent数量 不受限
注册配置 MSE Nacos/ZooKeeper,118元/月
云原生网关 MSE Higress,422元/月
简介: 生成对抗网络项目:6~9(3)

生成对抗网络项目:6~9(2)https://developer.aliyun.com/article/1426898

可视化损失

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

tensorboard --logdir=logs

现在,在浏览器中打开localhost:6006。 TensorBoard 的标量部分包含两个损失的曲线图,如下所示:

第一阶段的判别器网络的损失图如下所示:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-UY1cSkeq-1681652906146)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/gan-proj/img/8d391386-69b9-4890-bd5a-a078ba996754.png)]

第一阶段的生成器网络的损失图如下所示:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-m3IfsDoq-1681652906147)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/gan-proj/img/905056c0-7994-444e-b42b-4ebce2f093d9.png)]

可以类似地从 Tensorboard 获得第二阶段的生成器网络和判别器网络的损失图。

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

可视化图

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

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3361gjcm-1681652906147)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/gan-proj/img/b2df0366-0c95-4e61-a490-7efa0da76e73.png)]

StackGAN 的实际应用

StackGAN 的行业应用包括:

  • 自动生成高分辨率图像以用于娱乐或教育目的
  • 创建漫画:使用 StackGAN 可以将漫画创建过程缩短至几天,因为 StackGAN 可以自动生成漫画并协助创作过程
  • 电影创作:StackGAN 可以通过根据文本描述生成帧来协助电影创作者
  • 艺术创作:StackGAN 可以通过根据文字描述生成草图来协助艺术家

总结

在本章中,我们了解并实现了 StackGAN 网络,该网络可从文本描述生成高分辨率图像。 我们从对 StackGAN 的基本介绍开始,在其中我们探讨了 StackGAN 的架构细节,并发现了用于训练 StackGAN 的损失。 然后,我们下载并准备了数据集。 之后,我们开始在 Keras 框架中实现 StackGAN。 实现之后,我们依次训练了第一阶段和第二阶段 StackGANS。 成功训练网络后,我们评估了模型并将其保存以备将来使用。

在下一章中,我们将与 CycleGAN 合作,该网络可以将绘画转换为照片。

七、CycleGAN - 将绘画变成照片

CycleGAN 是一种生成对抗网络GAN),用于跨域迁移任务,例如更改图像的样式,将绘画转变为照片, 反之亦然,例如照片增强功能,更改照片的季节等等。 CycleGAN 由朱俊彦,Taesung Park,Phillip Isola 和 Alexei A. Efros 在题为《使用循环生成对抗网络的非配对图像到图像转换》中引入。 该产品于 2018 年 2 月在加州大学伯克利分校的 Berkeley AI ResearchBAIR)实验室生产,可通过以下链接获得。 由于其广泛的使用案例,CycleGAN 在 GAN 社区引起了轰动。 在本章中,我们将与 CycleGAN 一起使用,尤其是使用它们将绘画转换为照片。

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

  • CycleGAN 简介
  • CycleGAN 的架构
  • 数据收集与准备
  • Keras 的 CycleGAN 实现
  • 目标函数
  • 训练 CycleGAN
  • CycleGAN 的实际应用

CycleGAN 简介

为了将照片变成一幅画或一幅画,再将它们变成照片,普通 GAN 需要一对图像。 CycleGAN 是一种 GAN 网络,可以将图像从一个域 X 转换为另一个域 Y,而无需配对图像。 CycleGAN 尝试学习生成器网络,而生成器网络又学习了两个映射。 CycleGAN 无需训练大多数 GAN 中使用的单个生成器网络,而是训练两个生成器和两个判别器网络。

CycleGAN 中有两个生成器网络,如下所示:

  1. 生成器A:学习映射G: X -> Y,其中X是源域,Y是目标域。 它从源域A拍摄图像,并将其转换为与目标域B相似的图像。 基本上,网络的目的是学习映射,以使G(X)Y相似。
  2. 生成器B:学习映射F: Y -> X,然后从目标域B中获取图像,并将其转换为与源域A中的图像相似的图像。类似地, 网络要学习另一个映射,以便F(G(X))类似于X)。

这两个网络的架构相同,但我们分别对其进行训练。

CycleGAN 中有两个判别器网络,如下所示:

  1. 判别器A:判别器A的工作是区分由生成器网络A生成的图像,这些图像表示为G(X)和来自源域A的真实图像,它们表示为X
  2. 判别器B:判别器B的工作是区分由生成器网络B生成的图像,这些图像表示为F(Y)以及来自源域B的真实图像,它们表示为Y

两个网络的架构是相同的。 与生成器网络类似,我们分别训练判别器网络。 如下图所示:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FlevXRLf-1681652906147)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/gan-proj/img/969f8518-7d6b-42ce-9030-fdc7ca31818b.png)]

具有两个生成器和两个对抗性判别器网络的 CycleGAN 的插图。来源:arxiv:1703.10593

在下一节中,让我们详细了解 CycleGAN 的架构。

CycleGAN 的架构

CycleGAN 总体上由两种架构组成:生成器和判别器。 生成器架构用于创建两个模型,生成器 A 和生成器 B。判别器架构用于创建另外两个模型,判别器 A 和判别器 B。我们现在将在接下来的两节中介绍两个网络的架构。

生成器的架构

生成器网络是自编码器类型的网络。 它以图像作为输入并输出另一个图像。 它由两部分组成:编码器和解码器。 编码器包含具有下采样功能的卷积层,并将128x128x3形状的输入转换为内部表示。 解码器包含两个上采样块和最后一个卷积层,该层将内部表示形式转换为128x128x3形状的输出。

生成器网络包含以下块:

  • 卷积块
  • 残差块
  • 上采样块
  • 最后的卷积层

让我们逐一介绍每个组件:

  • 卷积块:卷积块包含 2D 卷积层,然后是实例规范化层和 relu 作为激活函数。 请参阅第 1 章,“生成对抗网络简介”,以了解有关“实例规范化”的更多信息。

生成器网络包含三个卷积块,其配置如下:

层名称 超参数 输入形状 输出形状
2D 卷积层 filters=32, kernel_size=7, strides=1, padding='same' (128, 128, 3) (128, 128, 32)
实例规范化层 axis=1 (128, 128, 32) (128, 128, 32)
激活层 activation='relu' (128, 128, 32) (128, 128, 32)
2D 卷积层 filters=64, kernel_size=3, strides=2, padding='same' (128, 128, 32) (64, 64, 64)
实例规范化层 axis=1 (64, 64, 64) (64, 64, 64)
激活层 activation='relu' (64, 64, 64) (64, 64, 64)
2D 卷积层 filters=128, kernel_size=3, strides=2, padding='same' (64, 64, 64) (32, 32, 128)
实例规范化层 axis=1 (32, 32, 128) (32, 32, 128)
激活层 activation='relu' (32, 32, 128) (32, 32, 128)
  • 残差块:残差块包含两个 2D 卷积层。 两层之后是动量值等于 0.8 的批归一化层。 生成器网络包含六个残差块,其配置如下:
层名称 超参数 输入形状 输出形状
2D 卷积层 filters=128, kernel_size=3, strides=1, padding='same' (32, 32, 128) (32, 32, 128)
批量规范化层 axis=3, momentum=0.9, epsilon=1e-5 (32, 32, 128) (32, 32, 128)
2D 卷积层 filters=138, kernel_size=3, strides=1, padding='same' (32, 32, 128) (32, 32, 128)
批量规范化层 axis=3, momentum=0.9, epsilon=1e-5 (32, 32, 128) (32, 32, 128)
加法层 None (32, 32, 128) (32, 32, 128)

加法层计算输入到块的张量与最后一个批量归一化层的输出之和。

  • 上采样块:上采样块包含 2D 转置卷积层,并使用relu作为激活函数。 生成器网络中有两个上采样模块。 第一个上采样模块的配置如下:
层名称 超参数 输入形状 输出形状
2D 转置卷积层 filters=64, kernel_size=3, strides=2, padding='same', use_bias=False (32, 32, 128) (64, 64, 64)
实例规范化层 axis=1 (64, 64, 64) (64, 64, 64)
激活层 activation='relu' (64, 64, 64) (64, 64, 64)

第二个上采样模块的配置如下:

层名称 超参数 输入形状 输出形状
2D 转置卷积层 filters=32, kernel_size=3, strides=2, padding='same', use_bias=False (64, 64, 64) (128, 128, 32)
实例规范化层 axis=1 (128, 128, 32) (128, 128, 32)
激活层 activation='relu' (128, 128, 32) (128, 128, 32)
  • 最后的卷积层:最后一层是使用tanh作为激活函数的 2D 卷积层。 它生成形状为(256, 256, 3)的图像。 最后一层的配置如下:
层名称 超参数 输入形状 输出形状
2D 卷积层 filters=3, kernel_size=7, strides=1, padding='same', activation='tanh' (128, 128, 32) (128, 128, 3)

这些超参数最适合 Keras 框架。 如果使用任何其他框架,请进行相应的修改。

判别器的架构

判别器网络的架构类似于 PatchGAN 网络中的判别器架构。 它是一个深度卷积神经网络,包含多个卷积块。 基本上,它会拍摄形状为(128, 128, 3)的图像,并预测该图像是真实的还是假的。 它包含几个 2D 零填充,可以在以下链接中找到其文档。 下表详细显示了判别器网络的架构:

层名称 超参数 输入形状 输出形状
输入层 none (128, 128, 3) (128, 128, 3)
2D 零填充层 padding(1, 1) (128, 128, 3) (130, 130, 3)
2D 卷积层 filters=64, kernel_size=4, strides=2, padding='valid' (130, 130, 3) (64, 64, 64)
激活层 activation='leakyrelu', alpha=0.2 (64, 64, 64) (64, 64, 64)
2D 零填充层 padding(1, 1) (64, 64, 64) (66, 66, 64)
2D 卷积层 filters=128, kernel_size=4, strides=2, padding='valid' (66, 66, 64) (32, 32, 128)
实例规范化层 axis=1 (32, 32, 128) (32, 32, 128)
激活层 activation='leakyrelu', alpha=0.2 (32, 32, 128) (32, 32, 128)
2D 零填充层 padding(1, 1) (32, 32, 128) (34, 34, 128)
2D 卷积层 filters=256, kernel_size=4, strides=2, padding='valid' (34, 34, 128) (16, 16, 256)
实例规范化层 axis=1 (16, 16, 256) (16, 16, 256)
激活层 activation='leakyrelu', alpha=0.2 (16, 16, 256) (16, 16, 256)
2D 零填充层 padding(1, 1) (16, 16, 256) (18, 18, 256)
2D 卷积层 filters=512, kernel_size=4, strides=2, padding='valid' (18, 18, 256) (8, 8, 512)
实例规范化层 axis=1 (8, 8, 512) (8, 8, 512)
激活层 activation='leakyrelu', alpha=0.2 (8, 8, 512) (8, 8, 512)
2D 零填充层 padding(1, 1) (8, 8, 512) (10, 10, 512)
2D 卷积层 filters=1, kernel_size=4, strides=1, padding='valid', activation='sigmoid' (10, 10, 512) (7, 7, 1)

判别器网络返回形状为(7, 7, 1)的张量。 现在,我们已经介绍了这两个网络的详细架构。 在下一节中,我们将介绍训练 CycleGAN 所需的目标函数。

ZeroPadding2D层在图像张量的顶部,底部,左侧和右侧添加零行和零列。

训练目标函数

与其他 GAN 相似,CycleGAN 具有训练目标函数,我们需要将其最小化以训练模型。 损失函数是以下损失的加权总和:

  1. 对抗损失
  2. 循环一致性损失

在以下各节中,让我们详细研究对抗性损失和周期一致性损失。

对抗损失

对抗性损失是实际分布AB的图像与生成器网络生成的图像之间的损失。 我们有两个映射函数,我们将对两个映射应用对抗性损失。

映射G: X -> Y的对抗损失如下所示:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dsyP7TIx-1681652906147)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/gan-proj/img/f278fd84-eb49-4d88-a98e-31396fe4ea3a.png)]

在此,x是来自分布A的一个域的图像,y是来自分布B的另一个域的图像。判别器D[y]试图区分G映射(G(x))生成的图像和来自不同的分布B的真实图像y。判别器D[x]试图区分F映射生成的图像(F(y))和来自分布A的真实图像xG的目的是使对抗损失函数D最小,后者不断尝试使其最大化。

循环一致性损失

仅使用对抗损失的问题在于,网络可以将同一组输入图像映射到目标域中图像的任何随机排列。 因此,任何学习的映射都可以学习类似于目标分布的输出分布。 x[i]y[i]之间可能有许多可能的映射函数。 循环一致性损失通过减少可能的映射数来克服了这个问题。 周期一致映射函数是可以将图像x从域A转换为域B中的另一个图像y并生成原始图像的函数。

前向循环一致性映射函数如下所示:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-O7sMRtBE-1681652906147)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/gan-proj/img/b6e02c98-294c-42d4-b687-3c2c7e84644a.png)]

向后循环一致映射函数如下所示:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-YDzyWD46-1681652906148)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/gan-proj/img/bf736fcf-a789-4a17-b1a9-a452b23e07f9.png)]

循环一致性损失的公式如下:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Ca5ZOSzP-1681652906148)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/gan-proj/img/bae8d146-d70d-479e-bc91-801a8140d502.png)]

由于循环一致性损失,由F(G(x))G(F(y))重构的图像分别类似于xy

完整目标函数

完整目标函数是对抗损失和周期一致性损失两者的加权总和,表示如下:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-H1dK6Hco-1681652906148)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/gan-proj/img/b72c39e8-2d9b-487b-83df-3b73ab2c550f.png)]

在此,l[GAN](G, D[Y], X, Y)是第一个对抗性损失,l[GAN](F, D[X], Y, X)是第二个对抗性损失。 在生成器A和判别器B上计算第一个对抗损失。在生成器B和判别器A上计算第二个对抗损失。

要训练 CycleGAN,我们需要优化以下函数:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KFnvJcaO-1681652906148)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/gan-proj/img/b0e30420-c79d-434a-b6d9-6fcaaa2a61ad.png)]

前面的等式表明,训练一个 CycleGAN,需要最小化生成器网络的损失,并使判别器网络的损失最大化。 优化之后,我们将获得一组训练有素的网络,能够从绘画中生成照片。

设置项目

如果尚未使用所有章节的完整代码克隆存储库,请立即克隆存储库。 下载的代码有一个名为Chapter07的目录,其中包含本章的全部代码。 执行以下命令来设置项目:

  1. 首先,导航到父目录,如下所示:
cd Generative-Adversarial-Networks-Projects
  1. 现在,将目录从当前目录更改为 Chapter07,如以下示例所示:
cd Chapter07
  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 文件,以获取有关如何设置项目的更多说明。 开发人员经常会遇到依赖关系不匹配的问题。 为每个项目创建一个单独的虚拟环境将解决此问题。

在本节中,我们已经成功设置了项目并安装了必需的依赖项。 在下一节中,我们将处理数据集。

下载数据集

在本章中,我们将使用monet2photo数据集。 该数据集是开放源代码,可以由 UC Berkeley 的 Berkeley AI ResearchBAIR)实验室使用。 您可以从以下链接选择手动下载数据集

下载后,将其解压缩到根目录中。

或者,要自动下载数据集,请执行以下命令:

wget https://people.eecs.berkeley.edu/~taesung_park/CycleGAN/datasets/monet2photo.zip
upzip monet2photo.zip

这些命令将下载数据集并将其解压缩到项目的根目录中。

monet2photo数据集仅可用于教育目的。 要将其用于商业项目,您必须获得 BAIR 实验室 UC Berkeley 的许可。 我们不拥有数据集中可用图像的版权。

CycleGAN 的 Keras 实现

如本章前面“CycleGAN 简介”部分中所述,CycleGAN 具有两种网络架构,即生成器网络和判别器网络。 在本节中,我们将编写所有网络的实现。

但是,在开始编写实现之前,请创建一个 Python 文件main.py并导入基本模块,如下所示:

from glob import glob
import matplotlib.pyplot as plt
import numpy as np
import tensorflow as tf
from keras import Input, Model
from keras.layers import Conv2D, BatchNormalization, Activation, Add, Conv2DTranspose, \
    ZeroPadding2D, LeakyReLU
from keras.optimizers import Adam
from keras_contrib.layers import InstanceNormalization
from scipy.misc import imread, imresize

生成器网络

在本章前面的“生成器网络的架构”部分中,我们已经探讨了生成器网络的架构。 让我们首先在 Keras 框架中编写生成器网络的层,然后使用 Keras 框架的函数式 API 创建 Keras 模型。

执行以下步骤以在 Keras 中实现生成器网络:

  1. 首先定义生成器网络所需的超参数,如下所示:
input_shape = (128, 128, 3)
residual_blocks = 6
  1. 接下来,创建一个输入层,将输入馈送到网络,如下所示:
input_layer = Input(shape=input_shape)
  1. 将第一个卷积块与先前在“生成器网络”部分的架构中指定的超参数相加,如下所示:
x = Conv2D(filters=32, kernel_size=7, strides=1, padding="same")(input_layer)
x = InstanceNormalization(axis=1)(x)
x = Activation("relu")(x)
  1. 添加第二个卷积块,如下所示:
x = Conv2D(filters=64, kernel_size=3, strides=2, padding="same")(x)
x = InstanceNormalization(axis=1)(x)
x = Activation("relu")(x)
  1. 添加第三个卷积块,如下所示:
x = Conv2D(filters=128, kernel_size=3, strides=2, padding="same")(x)
x = InstanceNormalization(axis=1)(x)
x = Activation("relu")(x)
  1. 定义残差块,如下所示:
def residual_block(x):
    """
 Residual block """  res = Conv2D(filters=128, kernel_size=3, strides=1, padding="same")(x)
    res = BatchNormalization(axis=3, momentum=0.9, epsilon=1e-5)(res)
    res = Activation('relu')(res)
    res = Conv2D(filters=128, kernel_size=3, strides=1, padding="same")(res)
    res = BatchNormalization(axis=3, momentum=0.9, epsilon=1e-5)(res)
    return Add()([res, x])

现在,使用residual_block()函数向模型添加六个残差块,如以下示例所示:

for _ in range(residual_blocks):
    x = residual_block(x)
  1. 接下来,添加一个上采样块,如下所示:
x = Conv2DTranspose(filters=64, kernel_size=3, strides=2, padding='same', use_bias=False)(x)
x = InstanceNormalization(axis=1)(x)
x = Activation("relu")(x)
  1. 添加另一个上采样模块,如下所示:
x = Conv2DTranspose(filters=32, kernel_size=3, strides=2, padding='same', use_bias=False)(x)
x = InstanceNormalization(axis=1)(x)
x = Activation("relu")(x)
  1. 最后,添加输出卷积层,如下所示:
x = Conv2D(filters=3, kernel_size=7, strides=1, padding="same")(x)
output = Activation('tanh')(x)

这是生成器网络的最后一层。 它生成形状为(128, 128, 3)的图像。

  1. 现在,通过为网络指定inputsoutputs来创建 Keras 模型,如下所示:
model = Model(inputs=[input_layer], outputs=[output])

生成器网络的整个代码如下所示:

def build_generator():
    """
 Create a generator network using the hyperparameter values defined below """  input_shape = (128, 128, 3)
    residual_blocks = 6
  input_layer = Input(shape=input_shape)
    # First Convolution block
  x = Conv2D(filters=32, kernel_size=7, strides=1, padding="same")(input_layer)
    x = InstanceNormalization(axis=1)(x)
    x = Activation("relu")(x)
    # 2nd Convolution block
  x = Conv2D(filters=64, kernel_size=3, strides=2, padding="same")(x)
    x = InstanceNormalization(axis=1)(x)
    x = Activation("relu")(x)
    # 3rd Convolution block
  x = Conv2D(filters=128, kernel_size=3, strides=2, padding="same")(x)
    x = InstanceNormalization(axis=1)(x)
    x = Activation("relu")(x)
    # Residual blocks
  for _ in range(residual_blocks):
        x = residual_block(x)
    # Upsampling blocks
     # 1st Upsampling block
  x = Conv2DTranspose(filters=64, kernel_size=3, strides=2, padding='same', use_bias=False)(x)
    x = InstanceNormalization(axis=1)(x)
    x = Activation("relu")(x)
    # 2nd Upsampling block
  x = Conv2DTranspose(filters=32, kernel_size=3, strides=2, padding='same', use_bias=False)(x)
    x = InstanceNormalization(axis=1)(x)
    x = Activation("relu")(x)
    # Last Convolution layer
  x = Conv2D(filters=3, kernel_size=7, strides=1, padding="same")(x)
    output = Activation('tanh')(x)
    model = Model(inputs=[input_layer], outputs=[output])
    return model

我们已经成功地为生成器网络创建了 Keras 模型。 在下一节中,我们将为判别器网络创建 Keras 模型。

判别器网络

我们已经在“判别器网络的架构”部分中探索了判别器网络的架构。让我们首先在 Keras 框架中编写判别器网络的层,然后使用 Keras 框架的函数式 API 创建 Keras 模型。

执行以下步骤以在 Keras 中实现判别器网络:

  1. 首先定义判别器网络所需的超参数,如下所示:
input_shape = (128, 128, 3)
hidden_layers = 3
  1. 接下来,添加一个输入层,将输入馈送到网络,如下所示:
input_layer = Input(shape=input_shape)
  1. 接下来,添加一个二维零填充层,如下所示:
x = ZeroPadding2D(padding=(1, 1))(input_layer)

该层将在xy轴上为输入张量添加填充。

  1. 接下来,使用先前在“判别器网络”部分的架构中指定的超参数添加卷积块,如下所示:
x = Conv2D(filters=64, kernel_size=4, strides=2, padding="valid")(x)
x = LeakyReLU(alpha=0.2)(x)
  1. 接下来,添加另一个 2D 零填充层,如下所示:
x = ZeroPadding2D(padding=(1, 1))(x)
  1. 接下来,使用先前在“判别器网络”部分中指定的超参数添加三个卷积块,如下所示:
for i in range(1, hidden_layers + 1):
    x = Conv2D(filters=2 ** i * 64, kernel_size=4, strides=2, padding="valid")(x)
    x = InstanceNormalization(axis=1)(x)
    x = LeakyReLU(alpha=0.2)(x)
    x = ZeroPadding2D(padding=(1, 1))(x)

每个卷积块都有两个卷积层,实例规范化层,激活层和 2D 零填充层。

  1. 现在,将最终(output)卷积层添加到网络,如下所示:
output = Conv2D(filters=1, kernel_size=4, strides=1, activation="sigmoid")(x)
  1. 最后,通过指定网络的输入和输出来创建 Keras 模型,如下所示:
model = Model(inputs=[input_layer], outputs=[output])

判别器网络的整个代码如下所示:

def build_discriminator():
    """
 Create a discriminator network using the hyperparameter values defined below """  input_shape = (128, 128, 3)
    hidden_layers = 3    input_layer = Input(shape=input_shape)
    x = ZeroPadding2D(padding=(1, 1))(input_layer)
    # 1st Convolutional block
  x = Conv2D(filters=64, kernel_size=4, strides=2, padding="valid")(x)
    x = LeakyReLU(alpha=0.2)(x)
    x = ZeroPadding2D(padding=(1, 1))(x)
    # 3 Hidden Convolution blocks
  for i in range(1, hidden_layers + 1):
        x = Conv2D(filters=2 ** i * 64, kernel_size=4, strides=2, padding="valid")(x)
        x = InstanceNormalization(axis=1)(x)
        x = LeakyReLU(alpha=0.2)(x)
        x = ZeroPadding2D(padding=(1, 1))(x)
    # Last Convolution layer
  output = Conv2D(filters=1, kernel_size=4, strides=1, activation="sigmoid")(x)
    model = Model(inputs=[input_layer], outputs=[output])
    return model

我们也已经成功地为判别器网络创建了 Keras 模型。 在下一部分中,我们将训练网络。

训练 CycleGAN

我们已经在“CycleGANs 简介”部分中介绍了训练目标函数。 我们还为两个网络分别创建了 Keras 模型。 训练 CycleGAN 是一个多步骤的过程。 我们将执行以下步骤来训练网络:

  1. 加载数据集
  2. 创建生成器和判别器网络
  3. 训练网络以达到指定次数
  4. 绘制损失
  5. 生成新图像

让我们在开始训练网络之前定义基本变量,如下所示:

data_dir = "/Path/to/dataset/directory/*.*" batch_size = 1 epochs = 500

加载数据集

在执行其他任何操作之前,请执行以下步骤来加载数据集:

  1. 首先使用glob模块创建图像路径列表,如下所示:
imagesA = glob(data_dir + '/testA/*.*')
imagesB = glob(data_dir + '/testB/*.*')

我们具有来自两个域AB的数据,这就是为什么我们创建了两个列表的原因。

  1. 接下来,遍历列表。 在循环中加载,调整大小和水平翻转图像,如下所示:
allImagesA = []
allImagesB = []
 # Iterate over the lists
for index, filename in enumerate(imagesA):
     # Load images
     imgA = imread(filename, mode='RGB')
     imgB = imread(imagesB[index], mode='RGB')
     # Resize images
     imgA = imresize(imgA, (128, 128))
     imgB = imresize(imgB, (128, 128))
     # Randomly horizontally flip images
     if np.random.random() > 0.5:
         imgA = np.fliplr(imgA)
         imgB = np.fliplr(imgB)
     allImagesA.append(imgA)
     allImagesB.append(imgB)
  1. 现在,对图像进行归一化以使像素值在 -1 和 1 之间的范围内,如下所示:
# Normalize images allImagesA = np.array(allImagesA) / 127.5 - 1. allImagesB = np.array(allImagesB) / 127.5 - 1.

加载数据集的整个代码如下所示:

def load_images(data_dir):
    imagesA = glob(data_dir + '/testA/*.*')
    imagesB = glob(data_dir + '/testB/*.*')
    allImagesA = []
    allImagesB = []
    for index, filename in enumerate(imagesA):
        # Load images
        imgA = imread(filename, mode='RGB')
        imgB = imread(imagesB[index], mode='RGB')
        # Resize images
        imgA = imresize(imgA, (128, 128))
        imgB = imresize(imgB, (128, 128))
        # Randomly horizontally flip images
        if np.random.random() > 0.5:
            imgA = np.fliplr(imgA)
            imgB = np.fliplr(imgB)
        allImagesA.append(imgA)
        allImagesB.append(imgB)
    # Normalize images
  allImagesA = np.array(allImagesA) / 127.5 - 1.
  allImagesB = np.array(allImagesB) / 127.5 - 1.    return allImagesA, allImagesB

前面的函数将返回两个 Numpy ndarray。 在开始训练之前,我们将使用它来加载和预处理图像。

建立和编译网络

在本节中,让我们构建必要的网络并准备进行训练。 执行以下步骤:

  1. 首先定义训练所需的优化器,如以下代码所示:
# Define the common optimizer common_optimizer = Adam(0.0002, 0.5)

我们将使用Adam优化器,其中learning_rate等于 0.0002,并且beta_1值等于 0.5。

  1. 首先创建判别器网络,如以下代码所示:
discriminatorA = build_discriminator()
discriminatorB = build_discriminator()

如“判别器网络的架构”部分所述,CycleGAN 具有两个判别器网络。

  1. 接下来,编译网络,如下所示:
discriminatorA.compile(loss='mse', optimizer=common_optimizer, metrics=['accuracy'])
discriminatorB.compile(loss='mse', optimizer=common_optimizer, metrics=['accuracy'])

使用mse作为损失函数,并使用accuracy作为度量标准来编译网络。

  1. 接下来,创建生成器网络AgeneratorAToB)和BgeneratorBToA)。 生成器网络A的输入是数据集A的真实图像(realA),输出将是重构图像(fakeB)。 生成器网络B的输入是来自数据集B的真实图像(realB),输出将是重构图像(fakeA),如下所示:
generatorAToB = build_generator()
generatorBToA = build_generator()

如“CycleGAN 的架构”部分所述,CycleGAN 具有两个生成器网络。 generatorAToB会将图像从域A转换为域BgeneratorBToA会将图像从域B转换为域A

现在,我们已经创建了两个生成器网络和两个判别器网络。 在下一个小节中,我们将创建并编译一个对抗网络。

创建和编译对抗网络

对抗网络是一个组合网络。 它在单个 Keras 模型中使用所有四个网络。 创建对抗网络的主要目的是训练生成器网络。 当我们训练对抗网络时,它只训练生成器网络,但冻结了判别器网络的训练。 让我们创建一个具有所需功能的对抗模型。

  1. 首先为网络创建两个输入层,如下所示:
inputA = Input(shape=(128, 128, 3))
inputB = Input(shape=(128, 128, 3))

两个输入都将拍摄大小为(128, 128, 3)的图像。 这些是符号输入变量,不包含实际值。 它们用于创建 Keras 模型(TensorFlow 图)。

  1. 接下来,使用生成器网络生成伪造图像,如下所示:
generatedB = generatorAToB(inputA)
generatedA = generatorBToA(inputB)

使用符号输入层生成图像。

  1. 现在,再次使用生成器网络重建原始图像,如下所示:
reconstructedA = generatorBToA(generatedB)
reconstructedB = generatorAToB(generatedA)
  1. 使用生成器网络生成伪造图像,如下所示:
generatedAId = generatorBToA(inputA)
generatedBId = generatorAToB(inputB)

生成器网络AgeneratorAToB)将图像从域A转换为域B。类似地,生成器网络BgeneratorBToA)将图像从域B转换为域A

  1. 接下来,使两个判别器网络均不可训练,如下所示:
discriminatorA.trainable = False discriminatorB.trainable = False

我们不想在我们的对抗网络中训练判别器网络。

  1. 使用判别器网络来预测每个生成的图像是真实的还是伪造的,如下所示:
probsA = discriminatorA(generatedA)
probsB = discriminatorB(generatedB)
  1. 创建 Keras 模型并指定网络的输入和输出,如下所示:
adversarial_model = Model(inputs=[inputA, inputB],outputs=[probsA, probsB, reconstructedA, reconstructedB, generatedAId, generatedBId])

我们的对抗网络将采用两个输入值(即张量),并返回六个输出值(即张量)。

  1. 接下来,按如下所示编译对抗网络:
adversarial_model.compile(loss=['mse', 'mse', 'mae', 'mae', 'mae', 'mae'],
  loss_weights=[1, 1, 10.0, 10.0, 1.0, 1.0],
  optimizer=common_optimizer)

对抗网络返回六个值,我们需要为每个输出值指定损失函数。 对于前两个值,我们使用均方误差损失,因为这是对抗性损失的一部分。 对于接下来的四个值,我们使用平均绝对误差损失,这是周期一致性损失的一部分。 六个不同损失的权重值为 1,1,10.0,10.0,1.0,1.0。 我们正在使用common_optimizer训练网络。

现在,我们已经成功为对抗网络创建了 Keras 模型。 如果您在理解 Keras 模型的工作方式时遇到困难,请查看 TensorFlow 图及其函数的文档。

在开始训练之前,请执行以下两个基本步骤。 TensorBoard 将在后面的部分中使用:

添加 TensorBoard 来存储损失和图以用于可视化目的,如下所示:

tensorboard = TensorBoard(log_dir="logs/{}".format(time.time()), write_images=True, write_grads=True,
  write_graph=True)
tensorboard.set_model(generatorAToB)
tensorboard.set_model(generatorBToA)
tensorboard.set_model(discriminatorA)
tensorboard.set_model(discriminatorB)

创建一个包含所有等于 1 的值的 4 维数组,该数组表示真实标签。 同样,创建另一个所有值均等于零的三维数组,代表伪标签,如下所示:

real_labels = np.ones((batch_size, 7, 7, 1))
fake_labels = np.zeros((batch_size, 7, 7, 1))

使用 numpy 的ones()zeros()函数创建所需的ndarray。 现在我们已经准备好基本组件,让我们开始训练。

开始训练

要针对指定的周期数训练网络,请执行以下步骤:

  1. 首先加载两个域的数据集,如下所示:
imagesA, imagesB = load_images(data_dir=data_dir)

我们已经在定义了load_images函数。

  1. 接下来,创建一个for循环,该循环应运行由周期数指定的次数,如下所示:
for epoch in range(epochs):
    print("Epoch:{}".format(epoch))
  1. 创建两个列表以存储所有小批量的损失,如下所示:
dis_losses = []
gen_losses = []
  1. 计算epochs循环内的小批量数量,如下所示:
num_batches = int(min(imagesA.shape[0], imagesB.shape[0]) /  
                  batch_size)
print("Number of batches:{}".format(num_batches))
  1. 接下来,在周期循环内创建另一个循环,并使其运行num_batches指定的次数,如下所示:
for index in range(num_batches):
        print("Batch:{}".format(index))

我们用于判别器网络和对抗网络训练的整个代码将在此循环内。

训练判别器网络

本小节中的代码是上一节中代码的延续。 在这里,您将看到如何训练判别器网络:

  1. 首先对两个域的图像进行小批量采样,如以下代码所示:
batchA = imagesA[index * batch_size:(index + 1) * batch_size]
        batchB = imagesB[index * batch_size:(index + 1) * batch_size]
  1. 接下来,使用生成器网络生成伪造图像,如下所示:
generatedB = generatorAToB.predict(batchA)
        generatedA = generatorBToA.predict(batchB)
  1. 然后,对判别器网络A进行真实图像和伪图像(由生成器网络生成)的训练,如下所示:
dALoss1 = discriminatorA.train_on_batch(batchA, real_labels)
        dALoss2 = discriminatorB.train_on_batch(generatedA, fake_labels)

此步骤将在真实图像和伪图像的微型批量上训练判别器A,并会稍微改善网络。

  1. 接下来,对判别器B进行真实图像和伪图像的训练,如下所示:
dBLoss1 = discriminatorB.train_on_batch(batchB, real_labels)
dbLoss2 = discriminatorB.train_on_batch(generatedB, fake_labels)
  1. 现在,计算判别器网络的总损失值,如下所示:
d_loss = 0.5 * np.add(0.5 * np.add(dALoss1, dALoss2), 0.5 * 
         np.add(dBLoss1, dbLoss2))

到目前为止,我们一直在添加代码来训练判别器网络。 在下一部分中,我们将训练对抗性网络以训练生成器网络。

训练对抗网络

为了训练对抗网络,我们需要输入值和真实值。 网络的输入值为batchAbatchB。 基本真值是real_labelsreal_labelsbatchAbatchBbatchAbatchB,如下所示:

g_loss = adversarial_model.train_on_batch([batchA, batchB],
  [real_labels, real_labels, batchA, batchB, batchA, batchB])

此步骤将训练生成器网络,而无需训练生成器网络。

在每个微型批量上完成一次迭代(循环)之后,将损失存储在名为dis_lossesgen_losses的列表中,如下所示:

dis_losses.append(d_loss)
        gen_losses.append(g_loss)

每 10 个周期后,使用生成器网络生成一组图像:

# Sample and save images after every 10 epochs if epoch % 10 == 0:
    # Get a batch of test data
  batchA, batchB = load_test_batch(data_dir=data_dir, batch_size=2)
    # Generate images
  generatedB = generatorAToB.predict(batchA)
    generatedA = generatorBToA.predict(batchB)
    # Get reconstructed images
  reconsA = generatorBToA.predict(generatedB)
    reconsB = generatorAToB.predict(generatedA)
    # Save original, generated and reconstructed images
  for i in range(len(generatedA)):
        save_images(originalA=batchA[i], generatedB=generatedB[i], recosntructedA=reconsA[i],
  originalB=batchB[i], generatedA=generatedA[i], reconstructedB=reconsB[i],
  path="results/gen_{}_{}".format(epoch, i))

将前面的代码块放入epochs循环中。 每隔 10 个时间段,它将生成一批伪图像并将其保存到结果目录。

接下来,将平均损失存储到 TensorBoard 中以进行可视化。 既存储损失,也要存储生成器网络的平均损失和判别器网络的平均损失,如以下示例所示:

write_log(tensorboard, 'discriminator_loss', np.mean(dis_losses), 
          epoch)
write_log(tensorboard, 'generator_loss', np.mean(gen_losses), epoch)

将前面的代码块放入epochs循环中。

生成对抗网络项目:6~9(4)https://developer.aliyun.com/article/1426900

相关实践学习
基于MSE实现微服务的全链路灰度
通过本场景的实验操作,您将了解并实现在线业务的微服务全链路灰度能力。
相关文章
|
3月前
|
Java Spring
【编程笔记】在 Spring 项目中使用 RestTemplate 发送网络请求
【编程笔记】在 Spring 项目中使用 RestTemplate 发送网络请求
112 0
|
3月前
|
存储 算法 Linux
【实战项目】网络编程:在Linux环境下基于opencv和socket的人脸识别系统--C++实现
【实战项目】网络编程:在Linux环境下基于opencv和socket的人脸识别系统--C++实现
158 7
|
3月前
|
机器学习/深度学习 移动开发 数据可视化
生成对抗网络项目:6~9(4)
生成对抗网络项目:6~9(4)
89 0
|
3月前
|
机器学习/深度学习 存储 算法框架/工具
生成对抗网络项目:6~9(1)
生成对抗网络项目:6~9(1)
86 0
|
16天前
|
数据采集 资源调度 JavaScript
Node.js 适合做高并发、I/O密集型项目、轻量级实时应用、前端构建工具、命令行工具以及网络爬虫和数据处理等项目
【8月更文挑战第4天】Node.js 适合做高并发、I/O密集型项目、轻量级实时应用、前端构建工具、命令行工具以及网络爬虫和数据处理等项目
30 5
|
1月前
|
机器学习/深度学习 人工智能 计算机视觉
好的资源-----打卡机+Arm+Qt+OpenCV嵌入式项目-基于人脸识别的考勤系统-----B站神经网络与深度学习,商城
好的资源-----打卡机+Arm+Qt+OpenCV嵌入式项目-基于人脸识别的考勤系统-----B站神经网络与深度学习,商城
|
2月前
|
安全 生物认证 网络安全
信息打点-红蓝队自动化项目&资产侦察&武器库部署&企查产权&网络空间
信息打点-红蓝队自动化项目&资产侦察&武器库部署&企查产权&网络空间
|
2月前
|
缓存 JavaScript API
【vue实战项目】通用管理系统:封装token操作和网络请求
【vue实战项目】通用管理系统:封装token操作和网络请求
26 0
|
3月前
|
前端开发 JavaScript Java
Java网络商城项目 SpringBoot+SpringCloud+Vue 网络商城(SSM前后端分离项目)五(前端页面
Java网络商城项目 SpringBoot+SpringCloud+Vue 网络商城(SSM前后端分离项目)五(前端页面
Java网络商城项目 SpringBoot+SpringCloud+Vue 网络商城(SSM前后端分离项目)五(前端页面
|
3月前
|
运维 网络协议 Linux
2023年河南省中等职业教育技能大赛网络建设与运维项目比赛试题(一)
2023年河南省中等职业教育技能大赛网络建设与运维项目比赛试题(一)