文章目录

  • 一、day1:生成对抗网络介绍
    • 1.1 生成对抗网络概述
      • 1.1.1 GAN的应用
      • 1.1.2 GAN发展历史
    • 1.2 GAN原理
    • 1.3 生成对抗网络的训练
    • 1.4 DCGAN及代码实现
    • 1.5 PaddleGAN介绍
  • 二、day2:GAN的技术演进及人脸生成应用
    • 2.1 GAN技术的演进
      • 2.1.1 GAN和DCGAN的问题
      • 2.1.2 LSGAN:MSE损失函数代替二分类损失函数
      • 2.1.3 WGAN和WGAN-GP:EM距离代替JS,KL散度
    • 2.2 GAN在人脸生成的改进
      • 2.2.1 渐近式增长生成对抗网络PGGAN
        • 2.2.1.1 渐进式增长
        • 2.2.1.2 平滑过度:
        • 2.2.1.3 PPGAN的缺陷:特征纠缠
        • 2.2.1.4 PPGAN的TF实现
      • 2.2.2 StyleGAN:基于样式的生成对抗网络
        • 2.2.2.1 StyleGAN 总览
        • 2.2.2.2 映射网络:为输入向量的特征解缠提供一条学习的通路
        • 2.2.2.3 Synthesis network样式模块:AdaIN精确控制样式信息,而保留图片的关键信息
        • 2.2.2.4 常数输入(ConstantInput)
        • 2.2.2.5 噪声输入改进
        • 2.2.2.6 混合正则化
      • 2.2.3 StyleGAN 2
        • 2.2.3.1 消除伪影
        • 2.2.3.2 改进渐进式增长网络结构
        • 2.2.3.3 StyleGAN2的应用体验
    • 2.3 PaddleGAN的使用
  • 三、day3:图像翻译及人像卡通化
    • 3.1 背景介绍
    • 3.2 技术原理
      • 3.2.1 Conditional GAN
      • 3.2.2 pixel2pixel
      • 3.2.3 CycleGAN
      • 3.2.4 U-GAT-IT
      • 3.2.5 Photo2Cartoon
        • 3.2.5.1 Photo2Cartoon模型结构
        • 3.2.5.2 递进训练
        • 3.2.5.3 效果展示和扩展应用
    • 3.3 卡通化实战
      • 3.3.1 Pixel2Pixel实现人像卡通化
    • 数据准备:
      • 3.3.2 Photo2cartoon
        • 3.3.2.1 测试、推理
        • 3.3.2.2 训练

本文参考:

  • paddle课程《生成对抗网络七日打卡营》、博客文章《NLP 中的对抗训练(附 PyTorch 实现)》及bilibili视频、天池新闻文本分类——bert模型源码(加入生成对抗网络)
  • 生成式对抗网络系列论文地址在《PaddleGAN预习课程》中有。 建议对照打卡营视频讲解观看,更容易理解。

一、day1:生成对抗网络介绍

  kaggle在2019年曾经举办一项奖金高达100万美元的比赛《Deepfake Detection Challenge》,主要是识别视频中哪些人脸是真实哪些是AI生成的。

1.1 生成对抗网络概述

1.1.1 GAN的应用

  生成式对抗网络,简称GAN,在图像/视频领域、人机交互领域都有应用,比如:

  • 图像视频生成、图像上色、图像修复、超分辨率(视频信息增强、遥感成像)
  • Text to Image Generation:根据文字描述生成对应图像
  • Image to Image Translation:图像到图像的转化(比如马转成斑马)
  • Photo to Cartoon:图像翻译:人物/实景动漫化、风格迁移
  • Motion Driving:人脸表情动作迁移
  • Lip Sythesis:唇形动作合成
  • 对抗神经机器翻译

以下这幅图中的人脸就都是神经网络生成的:

根据文字描述生成对应图像、医疗影像由生成对抗网络进行数据增广和生成

1.1.2 GAN发展历史

2014年提出以来,生成对抗网络快速发展

以下红色部分在本次课程中会讲到:

1.2 GAN原理

  我们之前学习的图片分类、语义分割、目标检测都是判别模型,根据图片特征训练后得到标签,而GAN是生成模型,根据噪声和标签生成需要的图片。

  GANs(Generative Adversarial Networks,生成对抗网络)是从对抗训练中估计一个生成模型,其由两个基础神经网络组成,即生成器神经网络G(Generator Neural Network) 和判别器神经网络D(Discriminator Neural Network)。
  生成器G从给定噪声中(一般是指均匀分布或者正态分布)采样来合成数据,判别器D用于判别样本是真实样本还是G生成的样本。G的目标就是尽量生成真实的图片去欺骗判别网络D,使D犯错;而D的目标就是尽量把G生成的图片和真实的图片分别开来。二者互相博弈,共同进化,最终的结果是D(G(z)) = 0.5,此时G生成的数据逼近真实数据(图片、序列、视频等)。

  • 左图表示,均匀分布的噪声Random noise输入生成器得到假的图片Fake Image,Fake Image和Real Image一起输入判别器中,得到判别分数(分数1为真实图片,0为生成图片)。

  • 右图是GAN的数学描述:

    • G是一个生成图片的网络,接收随机噪声z,通过这个噪声生成图片记做G(z),D(G(z))是D网络判断G生成的图片的是否真实的概率;
    • D是一个判别网络,输入参数x(表示一张图片),输出D(x)代表x为真实图片的概率;
    • PrP_{r}Pr​ → 真实数据的分布,X → PrP_{r}Pr​的样本(真实图片)
    • PzP_{z}Pz​ → 生成数据的分布,Z → PzP_{z}Pz​的样本(噪声)
    • G的目的:希望生成的图片“越接近真实越好,D(G(z))变大,V(D, G)会变小。记做minG\underset{G}{min}Gmin​。
    • D的目的:希望判别越来越准,D(x)变大,D(G(x))变小,V(D,G)会变大。记做maxD\underset{D}{max}Dmax​。
    • 最后博弈的结果D(G(z)) = 0.5。最理想的状态下,G可以生成足以“以假乱真”的图片G(z)。对于D来说,它难以判定G生成的图片究竟是不是真实的,因此D(G(z)) = 0.5。

  最终通过不断的训练,生成的图片会相当真实。但是目前的局限性,就是生成的内容非常逼真(GANs的目标就是以假乱真)不够多样性。

  现在图片生成领域,最火的还是扩散模型。扩散模型从20年开始,从DDPM到improved DDPM、Diffusion Models Beat GANs到最近的DALL·E2Imagen,使用了一系列的技巧来提高扩散模型的保真度,使得扩散模型的保真度可以媲美GANs,而且多样性和原创性更强。

1.3 生成对抗网络的训练

  生成器G希望从数据的真实分布中采样到一种分布,加入随机噪声(比如0-1之间的均匀分布的噪声)后映射成接近真实分布的生成器分布。可视化就是:


如上图所示:

  1. 初始训练出生成器网络G和判别器网络D;
  2. 固定判别器的权重,训练生成器,生成更逼真的图片,所以此时Fake Image标签为1(表示接近真实图片)。以生成器和真实分布的差异作为损失函数训练生成网络。
  3. 固定生成器的权重,训练判别器,识别出生成图片,所以此时Fake Image标签为0(表示生成图片)。 以真实图片和生成图片的二分类问题训练判别网络。
  4. 重复2、3步

1.4 DCGAN及代码实现

参考:论文《UNSUPERVISED REPRESENTATION LEARNING WITH DEEP CONVOLUTIONAL GENERATIVE ADVERSARIAL NETWORKS》、代码链接

  由于卷积神经网络(Convolutional neural network, CNN)比MLP有更强的拟合与表达能力,并在判别式模型中取得了很大的成果。因此,Alec等人将CNN引入生成器和判别器,称作深度卷积对抗神经网络(Deep Convolutional GAN, DCGAN),Convolutional表示卷积算子。另外还讨论了 GAN 特征的可视化、潜在空间插值等问题。

GAN最初用在手写数字识别的网络结构入如下:

  • 如上所示,输入图片是尺寸是[B,1,28,28],转为B×784维向量;随机噪声是100维向量经过全连接层也转为784维向量。最后判别器经过一个[784,1]的全连接层得到判别结果。
  • 一层神经网络太浅,效果不好,所以网络D和G都加到了三层。(G其实主要是训练噪声,然后加上图片向量成为生成图片向量,所以G的初始输入是噪声的维度100,而不是图片的维度784)

DCGAN的改进:

  • 使用更深的网络、添加BatchNorm
  • 判别器使用卷积算子Convolutional,这样相比全连接层,参数量大大减少,而且卷积层更能提取图片信息,更适用于计算机视觉任务。另外激活函数使用LeakyRelu。
  • 生成器需要上采样,所以使用转置卷积,激活函数使用Relu。转置卷积原理可参考我的另一篇笔记:《动手深度学习13:计算机视觉——语义分割、风格迁移》第二章。

代码如下:(来自《DCGAN实践》、)

  1. 加载数据集
import os
import random
import paddle
import paddle.nn as nn
import paddle.optimizer as optim
import paddle.vision.datasets as dset
import paddle.vision.transforms as transforms
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animationdemo_dataset = paddle.vision.datasets.MNIST(mode='train')
#rezize到32×32,然后归一化到-1和1之间
dataset = paddle.vision.datasets.MNIST(mode='train', transform=transforms.Compose([transforms.Resize((32,32)),transforms.Normalize([127.5], [127.5])]))
dataloader = paddle.io.DataLoader(dataset, batch_size=32,shuffle=True, num_workers=4)
  1. Generator网络输入z经过四个转置卷积层之后,形状由[B,100,1,1]变成[B,1,32,32]。
# Generator Code
class Generator(nn.Layer):def __init__(self, ):super(Generator, self).__init__()self.gen = nn.Sequential(# input is Z, [B,100,1,1] -> [B,64*4,4,4]nn.Conv2DTranspose(100,64*4,4,1,0, bias_attr=False),nn.BatchNorm2D(64*4),nn.ReLU(True),# state size. [B,64*4,4,4] -> [B,64*2,8,8]nn.Conv2DTranspose(64*4,64*2,4,2,1, bias_attr=False),nn.BatchNorm2D(64*2),nn.ReLU(True),# state size. [B,64*2,8,8] -> [B,64,16,16]nn.Conv2DTranspose(64*2,64,4,2,1, bias_attr=False),nn.BatchNorm2D(64),nn.ReLU(True),# state size. [B,64,16,16] -> [B,1,32,32]nn.Conv2DTranspose(64,1,4,2,1, bias_attr=False),nn.Tanh()#最后输出值在-1到1之间)def forward(self, x):return self.gen(x)
  1. Discriminator网络输入x经过四个转置卷积层之后,形状由[B,1,32,32]变成[B,1]。
class Discriminator(nn.Layer):def __init__(self,):super(Discriminator, self).__init__()self.dis = nn.Sequential(# input [B,1,32,32] -> [B,64,16,16]nn.Conv2D(1,64,4,2,1, bias_attr=False),nn.LeakyReLU(0.2),# state size. [B,64,16,16] -> [B,128,8,8]nn.Conv2D(64,64*2,4,2,1, bias_attr=False),nn.BatchNorm2D(64*2),nn.LeakyReLU(0.2),# state size. [B,128,8,8] -> [B,256,4,4]nn.Conv2D(64*2,64*4,4,2,1, bias_attr=False),nn.BatchNorm2D(64*4),nn.LeakyReLU(0.2),# state size. [B,256,4,4] -> [B,1,1,1] -> [B,1]nn.Conv2D(64*4,1,4,1,0,bias_attr=False),nn.Sigmoid())def forward(self, x):return self.dis(x)
#定义的初始化函数weights_init略去了
netG = Generator()
netG.apply(weights_init)
netD = Discriminator()
netD.apply(weights_init)
loss = nn.BCELoss()#二分类损失函数
# 创建噪声
fixed_noise = paddle.randn([32, 100, 1, 1], dtype='float32')
# 设置真实图片和生成图片的标签
real_label ,fake_label= 1.,0.# 设置两个优化器,训练一个网络时固定另一个网络的权重
optimizerD = optim.Adam(parameters=netD.parameters(), learning_rate=0.0002, beta1=0.5, beta2=0.999)
optimizerG = optim.Adam(parameters=netG.parameters(), learning_rate=0.0002, beta1=0.5, beta2=0.999)
losses = [[], []]
#plt.ion()
now = 0
for pass_id in range(100):for batch_id, (data, target) in enumerate(dataloader):"""(1) Update D network: maximize log(D(x)) + log(1 - D(G(z)))"""optimizerD.clear_grad()#梯度清零real_img = databs_size = real_img.shape[0]label = paddle.full((bs_size, 1, 1, 1), real_label, dtype='float32')#判别器真实图片标签为1real_out = netD(real_img)errD_real = loss(real_out, label)errD_real.backward()"""生成器根据噪声生成图片,并且把标签设为0"""noise = paddle.randn([bs_size, 100, 1, 1], 'float32')fake_img = netG(noise)label = paddle.full((bs_size, 1, 1, 1), fake_label, dtype='float32')fake_out = netD(fake_img.detach())errD_fake = loss(fake_out,label)errD_fake.backward()optimizerD.step()optimizerD.clear_grad()errD = errD_real + errD_fakelosses[0].append(errD.numpy()[0])"""(2) Update G network: maximize log(D(G(z)))唯一不同是生成器生成的图片标签改为1,因为生成器要生成接近真实的图片"""optimizerG.clear_grad()noise = paddle.randn([bs_size, 100, 1, 1],'float32')fake = netG(noise)label = paddle.full((bs_size, 1, 1, 1), real_label, dtype=np.float32,)output = netD(fake)errG = loss(output,label)errG.backward()optimizerG.step()optimizerG.clear_grad()losses[1].append(errG.numpy()[0])"""每一百步做一次可视化,打印输出"""if batch_id % 100 == 0:generated_image = netG(noise).numpy()imgs = []plt.figure(figsize=(15,15))try:for i in range(10):image = generated_image[i].transpose()image = np.where(image > 0, image, 0)image = image.transpose((1,0,2))plt.subplot(10, 10, i + 1)plt.imshow(image[...,0], vmin=-1, vmax=1)plt.axis('off')plt.xticks([])plt.yticks([])plt.subplots_adjust(wspace=0.1, hspace=0.1)msg = 'Epoch ID={0} Batch ID={1} \n\n D-Loss={2} G-Loss={3}'.format(pass_id, batch_id, errD.numpy()[0], errG.numpy()[0])print(msg)plt.suptitle(msg,fontsize=20)plt.draw()plt.savefig('{}/{:04d}_{:04d}.png'.format('work', pass_id, batch_id), bbox_inches='tight')plt.pause(0.01)except IOError:print(IOError)paddle.save(netG.state_dict(), "work/generator.params")

训练结果如下:

1.5 PaddleGAN介绍

paddle官网、github地址。官网没啥用,主要看github。

paddle代码仓库结构预览:

二、day2:GAN的技术演进及人脸生成应用

2.1 GAN技术的演进

2.1.1 GAN和DCGAN的问题

GAN和DCGAN存在以下问题:

  • 模式坍塌:生成器生成非常窄的分布,仅覆盖真实数据分布中的单一模式。生成器只能生成非常相似的样本(比如MNIST中的单个数字),多样性不够。
  • 没有指标可以告诉我们收敛情况。生成器和判别器的 loss并没有告诉我们任何收敛相关信息
  • 训练不稳定

模式坍塌的原因一句话概括就是:等 价优化的距离衡量(KL散度、JS散度)不合理,生成器随机初始化后的生成分布很难与真实分布有不可忽略的重叠。

  1. GAN网络训练的重点在于均衡生成器与判别器,我们越训练判别器,它就越接近最优。 在最优判别器的下,我们可以把原始GAN定义的生成器loss等价变换为最小化真实分布与生成分布之间的JS散度。 (推导见下图)
  2. JS散度存在的问题:通过优化JS散度就能将生成分布拉向真实分布,最终以假乱真,前提是两个分布有所重叠。但是如果两 个分布完全没有重叠的部分,或者它们重叠的部分可忽略, 那它们的JS散度就一直是 log2
  3. 生成器随机初始化后的生成分布很难与真实分布有不可忽略的重叠(上升到高维时),所以在判别器太强时,梯度为0,loss没不再下降,生成器学习不到东西,生成图像的质量便不会再有提升。

    目标函数推导:
  • 设真实数据分布Pr(x)=aP_{r}(x)=aPr​(x)=a,生成数据分布为PG(x)=bP_{G}(x)=bPG​(x)=b,通过导数求极值,最终可以得到判别器函数的极值点D∗(x)D^{*}(x)D∗(x)。
  • 将D∗(x)D^{*}(x)D∗(x)代入生成器目标函数中(只有后一项),根据KL散度和JS散度公式,可以得到生成器函数为-2log2+JS散度值。-2log2是因为log式子中分母除以2
  • 所以最终判别器收敛到接近最优点D∗(x)D^{*}(x)D∗(x)时,生成器函数是常数加上生成分布和真实分布之间的JS散度

      而JS散度的问题是:两个不重合分布的JS散度等于常数log2,梯度为0,网络无法继续优化。

2.1.2 LSGAN:MSE损失函数代替二分类损失函数

论文:Least Squares Generative Adversarial Networks

  针对GAN存在的JS散度导致的问题,LSGAN(LeastSquare GAN)提出用MSE损失函数代替二分类损失函数,改善了传统 GAN 生成的图片质量不高,且训练过程十分不稳定的问题。

  训练营第二课作业《代码题 DCGAN改写LSGAN》中需要改的代码就两处:

2.1.3 WGAN和WGAN-GP:EM距离代替JS,KL散度

参考:论文Wasserstein GAN、代码链接、论文解读《WGAN(Wasserstein GAN)看这一篇就够啦,WGAN论文解读》

  1. WGAN

  WGAN利用EM距离代替JS,KL散度来表示生成与真实分布的距离衡量,从而改进了原始GAN存在的两类问题。(Wasserstein距离 优越性在于: 即使两个分布没有任何重叠,也可以反应他们之间的距离。)

  假设真实分布是PrP_rPr​,生成器分布是PθP_\thetaPθ​,两种分布就像两堆土,如下图所示:

  将右边土堆堆成左边土堆的方式有无数种,其中一种消耗最少的称为推土机距离EM(Earth-Moverdistance)。

  • 推土机距离公式代入GAN网络经过一堆推导得到中间那行式子,其中判别器D要满足D∈1−lipschitzD\in 1-lipschitzD∈1−lipschitz限制。这个限制直观来说会让生成器的标签足够平滑,即输出的变化要小于输入的变化。
  • 输入x是不好限制的,那么可以限制参数w。在神经网络中的实现就是判别器参数截断,即w∈[c,-c],用clip即可实现。
  • WGAN与原始GAN第一种形式相比,只改了四点:
    • 判别器最后一层去掉sigmoid
    • 生成器和判别器的loss不取log
    • 每次更新判别器的参数之后把它们的值截断到不超过一个 固定常数c
    • 不要用基于动量的优化算法(包括momentum和 Adam),推荐RMSProp
  1. WGAN-GP
    在神经网络中,w即使很小,累积多层之后输出也可能很大,不能保证输入一定小于输出,由此提出WGAN-GP,其目标函数如下:


如上图所示,目标函数改成第二行的式子。其中:

  • x∼Ppenaltyx \sim P_{penalty}x∼Ppenalty​表示PrP_rPr​和PGP_GPG​之间的采样。
  • ∥▽xD(x)∥\left \| \bigtriangledown _{x} D(x)\right \|∥▽x​D(x)∥表示判别器输出分数对x的导数的范数。
  • WGAN-GP目标函数第三项表示希望∥▽xD(x)∥\left \| \bigtriangledown _{x} D(x)\right \|∥▽x​D(x)∥小于1。如果大于1那么max之后得到一个正值,前面乘以-λ作为惩罚。
  • interpolates就是上图的x∼Ppenaltyx \sim P_{penalty}x∼Ppenalty​采样,最终得到的惩罚项gradient_penalty作为损失。
  • 代码最后和式子有点不一样,是作者觉得这样效果更好。

2.2 GAN在人脸生成的改进

  • 从2014年的GAN、2015年DCGAN、2017年PGGAN、到2018年的StyleGAN,GAN生成的图片越来越清晰。DCGAN要生成高分辨率一点的图片,发现会生成一些很奇怪的图片,分辨率继续扩大,问题会越来越明显。
  • PGGAN损失函数使用了WGAN-GP的损失函数,网络结构如下:(左边是DCGAN生成的奇怪人脸)

2.2.1 渐近式增长生成对抗网络PGGAN

参考:论文PROGRESSIVE GROWING OF GANS FOR IMPROVED QUALITY, STABILITY, AND VARIATION

2.2.1.1 渐进式增长

  如果直接生成大分辨率的图片,建立从latent code 到 1024x1024 pixels样本的映射网络G,肯定是很难工作的。因为,在生成的过程中, 判别器D很容易就可以识别出G生成的“假图像”,G难以训练 。因此,提出PGGAN(progressive gan)来进行逐层训练。
  这项技术首先通过学习即使在低分辨率图像中也可以显示的基本特征,来创建图像的基本部分,并且随着分辨率的提高和时间的推移,学习越来越多的细节。由于每次前面的层已经训练好,所以会集中训练后添加的层,所以提高分辨率后,新的训练难度不会提高。低分辨率图像的训练不仅简单、快速,而且有助于更高级别的训练,因此,整体的训练也就更快。
  如下图所示,模型先训练一个生成4*4分辨率图片的的生成器和对应的判别器,效果不错之后再添加一层,训练8*8分辨率的生成器和判别器。。。。。。不断逐层添加卷积层和转置卷积层,最终得到分辨率为1024*1024的生成对抗网络。

PGGAN网络结构如下:

2.2.1.2 平滑过度:
  • Generator 内部的网络只有一个,但是在训练过程中网络的结构是在动态变化的。引入这些层时,不是立即跳到该分辨率,而是通过参数α(介于0-1之间,从0到1线性缩放)平滑的增加高分辨率的新层。
  • 如果从 4×4 的输出直接变为 8×8 的输出的话,网络层数的突变会造成 GANs 原有参数失效,导致急剧不稳定这会影响模型训练的效率(新添加的层,参数一开始是初始化的。如果直接输出,那么之前训练好的结果也被破坏了)。所以PGGAN 提出了平滑过渡技术。


  当把生成器和判别器的分辨率加倍时,会平滑地增大新的层。我们以从16 × 16 像素的图片转换到 32 × 32 像素的图片为例。在转换(b)过程中,把在更高分辨 率上操作的层视为一个残缺块,权重 α 从 0 到 1 线性增长。当 α 为 0 的时候,相当于图(a),当 α 为 1 的时候,相当于图©。所以,在转换过程中,生成样本的像素,是从 16x16 到 32x32 转换的。同理,对真实样本也做了类似的平滑过渡,也就是,在这个阶段的某个 训练 batch,真实样本是:

  • 上图中的 2× 和 0.5× 指利用最近邻卷积和平均池化分别对图片分辨率加倍和折半。
  • toRGB 表示将一个层中的特征向量投射到 RGB 颜色空间中,
  • fromRGB 正好是相反的过程; 这两个过程都是利用 1 × 1 卷积。

  当训练判别器时,插入下采样后的真实图片去匹配网络中 的当前分辨率。在分辨率转换过程中,会在两张真实图片的分辨率之间插值,类似于将两个分辨率结合到一起用生成器输出。其它改进还有:

  • 生成器中的像素级特征归一化。 动机是训练的稳定性,训练发散的早期迹象之一是特征的爆炸式增长,将图像中的所有点映射到一组向量,然后对其进行归一化 。
  • 小批量标准差(仅应用判别器)、均衡学习率:略
2.2.1.3 PPGAN的缺陷:特征纠缠

  由于 PPGAN 是逐级直接生成图片,我们没有对其增添控制,我们也就无法获知它在每一级上学 到的特征是什么,这就导致了它 控制所生成图像的特定特征的能力非常有限,即PPGAN 容易发生特征纠缠。换句话说,这些特性是互相关联的,因此尝试调整一下输入,即使是一点儿,通常也会同时影响多个特性。
  如下图,比如我们希望噪声第二个维度可以控制人脸的肤色,理想是第二维向量由0.9改为0.7之后,会生成第二张图片。但是结果可能生成完全不一样的图片,比如第三张图,这就是相互纠缠的一个例子。

   我们希望有一种更好的模型,能让我们控制住输出的图片是长什么样的,也就是在生成 图片过程中每一级的特征,要能够特定决定生成图片某些方面的表象,并且相互间的影响尽 可能小。于是,在 PPGAN 的基础上,StyleGAN 作出了进一步的改进与提升。

2.2.1.4 PPGAN的TF实现
import matplotlib.pyplot as plt
import tensorflow as tf
import tensorflow_hub as hubwith tf.Graph().as_default():# 提前从TFHub导入PGGANmodule = hub.Module("progan-128_1")#运行时采样的维度latent_dim = 512# 改变种子得到不同的人脸latent_vector = tf.random.normal([1, latent_dim], seed=1337)# 使用该模块从潜在空间生成图像interpolated_images = module(latent_vector)# 运行Tensorflow session 得到(1,128,128,3)的图像with tf.compat.v1.Session() as session:session.run(tf.compat.v1.global_variables_initializer())image_out = session.run(interpolated_images)plt.imshow(image_out.reshape(128,128,3))
plt.show()

2.2.2 StyleGAN:基于样式的生成对抗网络

参考:

  • 论文A Style-Based Generator Architecture for Generative Adversarial Networks
  • 《StyleGAN 架构解读(重读StyleGAN )精细》

  PGGAN的问题: 控制生成图像特定特征的能力有限。 以下图来说:

  • 图a表示,假设真实数据中有两个人脸特征,x轴越往左表示越man;y轴越往上表示头发越长。一般认为不存在头发长又很man的人,所以左上角区域是不存在的。
  • b图表示噪声分布,噪声一般是从简单对称分布中取出,所以其区域是一个圆形。为了填补左上角空缺,就会对特征分布做一个扭曲。 这样当图片向量仅仅改变一个维度时,输出图片的多个特征都会变化,这就是特征纠缠现象。
  • c图表示,StyleGAN引入映射网络之后,会拟合真实数据分布的形状,缓解特征纠缠。

2.2.2.1 StyleGAN 总览

   StyleGAN 用风格(style)来影响人脸的姿态、身份特征等,用噪声 ( noise ) 来影响头发丝、皱纹、肤色等细节部分。StyleGAN 的网络结构包含两个部分:映射网络Mapping network和Synthesis network。
  Mapping network,即下图 (b)中的左部分,由隐藏变量 z 生成 中间隐藏变量 w的过程,这个 w 就是用来控制生成图像的style,即风格。
  Synthesis network,它的作用是生成图像,创新之处在于给每一层子网络都喂了 A 和 B,A 是由 w 转换得到的仿射变换,用于控制生成图像的风格,B 是转换后的随机噪声,用于丰富生成图像的细节,即每个卷积层都能根据输入的A来调整"style",通过B来调整细节。
  整个网络结构还是保持了 PG-GAN (progressive growing GAN) 的结构。最后论文还提供了一个高清人脸数据集FFHQ。

架构解读:
  StyleGAN 首先重点关注了 ProGAN 的生成器网络,它发现,渐进层的一个的好处是,如果使用得当,它们能够控制图像的不同视觉特征。层和分辨率越低,它所影响的特征就越粗糙。简要将这些特征分为三种类型:

1、粗糙的——分辨率不超过82,影响姿势、一般发型、面部形状等;
2、中等的——分辨率为162至322,影响更精细的面部特征、发型、眼睛的睁开或是闭合等;
3、高质的——分辨率为642到10242,影响颜色(眼睛、头发和皮肤)和微观特征。

  然后,StyleGAN 就在 ProGAN 的生成器的基础上增添了很多附加模块以实现样式上更细微和精确的控制。

2.2.2.2 映射网络:为输入向量的特征解缠提供一条学习的通路

  StyleGAN的第一点改进是:Mapping network 对隐藏空间(latent space)进行解耦,缓解特征纠缠 。Generator的输入加上了由8个全连接层组成的Mapping Network,并且 Mapping Network 的输出W′与输入层Z(512×1)的形状大小相同。中间向量W′(或者叫潜在因子)后续会传给生成网络得到 18 个控制向量,使得该控制向量的不同元素能够控制不同的视觉特征。
  如果不加这个 Mapping Network 的话,后续得到的 18个控制向量之间会存在特征纠缠的现象——比如说我们想调节 8*8 分辨率上的控制向量(假 设它能控制人脸生成的角度),但是我们会发现 32*32 分辨率上的控制内容(譬如肤色)也被改变了,这个就叫做特征纠缠。所以 Mapping Network 的作用就是为输入向量的特征解缠提供一条学习的通路。
  为何 Mapping Network 能够学习到特征解缠呢?简单来说, 如果仅使用输入向量来控制视觉特征,能力是非常有限的,因此它必须遵循训练数据的概率密度。例如,如果黑头发 的人的图像在数据集中更常见,那么更多的输入值将会被映射到该特征上。因此,该模型无法将部分输入(向量中的元素)映射到特征上,这就会造成特征纠缠。然而, 通过使用另一个神经网络,该模型可以生成一个不必遵循训练数据分布的向量,并且可以减少特征之间的相关性。

2.2.2.3 Synthesis network样式模块:AdaIN精确控制样式信息,而保留图片的关键信息

   StyleGAN第二点改进是,将特征解缠后的中间向量W′变换为样式控制向量,从而参与影响生成器的生成过程。AdaIN表示自适应实例归一化。

  实例归一化是上图Instance Norm中,对蓝色部分进行归一化。每个batch中只取一个样本,计算其在每个通道上的均值μ(x)\mu (x)μ(x)和标准差σ(x)\sigma (x)σ(x),γ和β表示缩放因子和偏置。自适应归一化AdaIN是其变体。

  上图右下是风格迁移任务的网络示意图,我们希望上面实景图有下面那张漫画图的风格。论文实验发现,在实例归一化中,将实景图的γ和β换成漫画图的均值和标准差,最终会取得比较好的风格迁移效果。这就是自适应归一化的过程。StyleGAN就借鉴了这一种思路。

  风格迁移任务更多细节,可以参考我另一篇帖子:《动手深度学习13:计算机视觉——语义分割、风格迁移》

   AdaIN 的具体实现过程如上右图所示:将潜在因子W′通过一个可学习的仿射变换A(简单理解就是一个全连接层)后输出,输出扩大为原来的两倍(2×n),分别作为缩放因子ys,iy_{s,i}ys,i​和偏差因子yb,iy_{b,i}yb,i​。输入xix_ixi​进过标准化(减均值除方差)后,与两个因子进行AdaIN,就完成了一次W′影响原始输出xix_ixi​的过程。
   AdaIN 代码见左下,W′经过FC层之后变成原来两倍,reshape成前后两部分。这两部分分别作为两个因子,最后x=ys,i∗x+yb,ix=y_{s,i}*x+y_{b,i}x=ys,i​∗x+yb,i​。(x在AdaIN之前先标准化)

  生成器从 分辨率4*4,变换到 8*8,并最终到 1024*1024,一共由 9 个生成阶段组成,而每个阶段都会受两个控制向量(A)对其施加影响。其中一个控制向量在 Upsample之后对其影响一次,另外一个控制向量在 Convolution 之后对其影响一次,影响的方式都采用 AdaIN。因此,中间向量W′总共被变换成 18 个控制向量(A)传给生成器。
   这种影响方式能够实现样式控制,主要是因为它让变换后的W′影响图片的全局信息(注意标准化抹去了对图片局部信息的可见性),而保留生成人脸的关键信息由上采样层和卷积层来决定,因此W′只能够影响到图片的样式信息。

2.2.2.4 常数输入(ConstantInput)


  上图左侧网络表示传统的GAN网络输入是一个随机变量或者隐藏变量 z,右侧表示Synthesis network中最开始的输入变成了常数张量。
  既然 StyleGAN 生成图像的特征是由

生成对抗网络,从DCGAN到StyleGAN、pixel2pixel,人脸生成和图像翻译。相关推荐

  1. 深度学习100例-生成对抗网络(DCGAN)手写数字生成 | 第19天

    文章目录 深度卷积生成对抗网络(DCGAN) 一.前言 二.什么是生成对抗网络? 1. 设置GPU 2. 加载和准备数据集 三.创建模型 1. 生成器 2. 判别器 四.定义损失函数和优化器 1. 判 ...

  2. 深度卷积生成对抗网络(DCGAN)原理与实现(采用Tensorflow2.x)

    深度卷积生成对抗网络(DCGAN)原理与实现(采用Tensorflow2.x) GAN直观理解 DCGAN网络结构 GAN训练目标 DCGAN实现 数据加载 网络 鉴别网络 生成网络 网络训练 定义损 ...

  3. 生成对抗网络简介,深度卷积生成对抗网络(DCGAN)简介

    本博客是个人学习的笔记,讲述的是生成对抗网络(generate adversarial network ) 的一种架构:深度生成对抗网络 的简单介绍,下一节将使用 tensorflow 搭建 DCGA ...

  4. 深度学习100例-生成对抗网络(DCGAN)生成动漫人物 | 第20天

    文章目录 一.前言 二.什么是生成对抗网络? 1. 设置GPU 2. 加载和准备数据集 三.创建模型 1. 生成器 2. 判别器 四.定义损失函数和优化器 1. 判别器损失 2. 生成器损失 五.保存 ...

  5. 【视频课】生成对抗网络经典任务,详解基于GAN的图像生成算法!

    前言 欢迎大家关注有三AI的视频课程系列,我们的视频课程系列共分为5层境界,内容和学习路线图如下: 第1层:掌握学习算法必要的预备知识,包括Python编程,深度学习基础,数据使用,框架使用. 第2层 ...

  6. 生成对抗网络gan原理_必读!TOP10生成对抗网络GAN论文(附链接)

    来源:新智元 本文约2200字,建议阅读7分钟. 本文所选论文提供了一个易读的对GAN的介绍,帮助你理解GAN技术的基础. [ 导读 ]生成对抗网络 (GAN) 是深度学习中最有趣.最受欢迎的应用之一 ...

  7. 深度学习100例-生成对抗网络(GAN)手写数字生成 | 第18天

    文章目录 一.前期工作 1. 设置GPU 2. 定义训练参数 二.什么是生成对抗网络 1. 简单介绍 2. 应用领域 三.网络结构 四.构建生成器 五.构建鉴别器 六.训练模型 1. 保存样例图片 2 ...

  8. Pytorch:GAN生成对抗网络实现MNIST手写数字的生成

    github:https://github.com/SPECTRELWF/pytorch-GAN-study 个人主页:liuweifeng.top:8090 网络结构 最近在疯狂补深度学习一些基本架 ...

  9. 生成对抗网络的损失函数如何设计_理解生成对抗网络,一步一步推理得到GANs(一)...

    作者:Joseph Rocca 编译:ronghuaiyang 导读 GANs在2014年提出,然后就在图像生成领域取得了巨大的成功,但是其背后的原理却不是那么好理解,这篇文章带你从最基础的随机变量开 ...

  10. GAN生成对抗网络-CGAN原理与基本实现-条件生成对抗网络04

    CGAN - 条件GAN 原始GAN的缺点 代码实现 import tensorflow as tf from tensorflow import keras from tensorflow.kera ...

最新文章

  1. python 虚拟环境使用
  2. CC2530之Flash笔记
  3. miui通知栏要点两下_「MIUI玩机技巧84」MIUI12状态栏如何切旧版控制中心
  4. Eclipse设置server Locations及getServletContext().getRealPath获取到的工程目录路径
  5. Xshell 连接CentOS服务器解密
  6. php课后题,知到PHP语言程序设计课后习题答案
  7. POJ训练计划3096_Surprising Strings(STL/map)
  8. 无法远程连接到计算机 虚拟内存,远程桌面连接显示内存不足怎么破?
  9. Ubuntu 安装 tbb 步骤详解
  10. python命令输入if_SPSS中Recode、Compute、Count、If命令
  11. 怎么用计算机算组合数c,排列组合c怎么算 公式是什么
  12. hdfs 元数据维护机制
  13. 【C语言进阶】⑤关于数组传参和指针传参辨析
  14. poi在word输出复选框windows远程突然不能复制的解决方法
  15. 02-表格基本格式以及各个标签的属性、boder/cellpadding/cellspacing的区分、th标签、caption标签
  16. 【深度学习】时间注意力模块与空间注意力模块
  17. Python自动生成代码 - 通过tkinter图形化操作生成代码框架
  18. 解决IDEA 前端返回值乱码问题
  19. csu1726 你经历过绝望吗?两次!
  20. 前端的你平时都在哪找免费的可商业用的图片素材?

热门文章

  1. 计算机主机机箱结构图,带大家认识电脑主机拆开,内部结构
  2. 收获与期待——2016第四届中国计算机行业发展成就奖揭晓
  3. 配置Model Optimizer的Python 3.7.4 ECHO 处于关闭状态。‘pip3‘ 不是内部或外部命令,也不是可运行的程序或批处理文件
  4. 持续交付+springboot+k8s
  5. 斯坦福发布AI年度报告,中国AI论文数全球第二,第一也不是美国【附下载】
  6. HTML实现W3school导航栏(附带重置样式表reset.css)
  7. 适用于Win7系统下Intel 7代核心显卡驱动程序
  8. 安装 Unity Hub 发现 进不了 Unity3D 了
  9. 囧从流氓同事的河蟹喜酒归来......
  10. Ilasm And Ildasm Practice