转置卷积、微步卷积、空洞卷积

1、转置卷积 又可以称为 反卷积(数据从低维到高维)

转置卷积是一个将低维特征转换到高维特征。为什么叫做转置卷积呢?其实就是引入了转置的思想。

  • 假设我们现在有一个p维的向量Z,然后有个d维的向量X,p<d.
  • 这样就会出现 Z = W·X,其中W的维度为(p,d),叫做转换矩阵.
  • 现在,我们要从Z通过相似的方法来得到X,这样我们不难想到:X= W.T · X 其中W.T的维度是(d,p),但是这两个W并不是同一个值,而是具有转置的形式而已。

上面的例子是一维向量的情况,在卷积操作中,也可以借用这个思想,从低维到高维的转变可以在形式上看成是转置操作。

  • 比如我们现在对一个4 * 4的输入做3 * 3的卷积操作(m=3核的大小,stride=1,padding=0),得到一个2 * 2的特征映射
  • 如果我们想对这个2 * 2特征映射进行3 * 3卷积,并反过来得到4 * 4的输出,就可以用到转置卷积:

如上图所示,对2 * 2的特征映射先做(m-1) padding得到6 * 6的输入,然后对其进行3*3的卷积操作,从而得到4 * 4的特征映射。 同样,这个两个3 * 3的卷积参数不是一致的,都是可学习的。

2、微步卷积(步长不为1的转置卷积(反卷积))

微步卷积其实是一个转置卷积的一个特殊情况,就是卷积操作的stride ≠ 1。因为在现实中,为了大幅度降低特征维数,卷积的步长会大于1。同样,为了大幅度提高特征维度,我们也可以用通过卷积来实现,这种卷积stride < 1 ,所以叫做微步卷积。

  • 如果卷积操作stride>1,其对应的转置卷积步长为1/s :就是在输入特征之间插入s – 1个0,来使得步长变’小’。
  • 例如,我对一个5 * 5的输入做3 * 3的卷积操作(m=3, padding=0,但是stride=2),从而我得到的特征输出为2 * 2.
  • 现在对其进行微步卷积:

跟转置卷积一样,先对2 * 2的输入做(m-1)padding ,然后再在特征之间插入stride -1个0,从而得到一个7 * 7的特征输入,然后对其做3 * 3 的卷积操作,得到5 * 5的特征输出。

如何计算反卷积:

当输入的矩阵高宽为n,核大小为k,padding为p,stride为s

  • 当输入的矩阵高宽为 n ,核大小为 k ,padding为 p , stride为 s 。
  • 转置卷积作用后的尺寸变化: \(n^{1}=s n+k-2 p-s\) 。如果想让高宽成倍增加,那么 \(k=2 p+s\) 。
  • 卷积作用后的尺寸变化: \(n^{1}=\left\lfloor\frac{n-k+2 p+s}{s}\right\rfloor\) 。如果想让高宽成倍减少,那么 \(k=2 p+1\)。

1、当填充为0步长为1时

将输入填充 k − 1 。(k是 卷积核大小)
将核矩阵上下,左右翻转。
之后正常做填充为0(无填充),步幅为1的卷积。

2 当填充为 p 步幅为1时

将输入填充 k − p − 1 。
将核矩阵上下,左右翻转。
之后正常做填充为0,步幅为1的卷积。

3 当填充为 p pp 步幅为s ss时

在行和列之间插入s − 1 行和列。
将输入填充 k − p − 1。
将核矩阵上下,左右翻转。
之后正常做填充为0,步幅为1的卷积。

3、空洞卷积(膨胀卷积)

通常来说,对于一个卷积层,如果希望增加输出单元的感受野,一般由三个方式:

  1. 增加卷积核大小
  2. 增加层数
  3. 进行pooling操作

其中1和2都会增加参数量,而3会丢失特征信息。这样我们就可以引入‘空洞卷积’的概念,它不增加参数量,同时它也可以增加输出的感受野。
它主要是通过给卷积核插入空洞来增加其感受野大小,如果卷积核每两个元素之间插入d-1个空洞,那么卷积核的有效大小为:M = m + (m-1)*(d-1)

GAN系列之—Deep Convolutional GAN(DCGAN)

DCGAN 的判别器和生成器都使用了卷积神经网络(CNN)来替代GAN 中的多层感知机,同时为了使整个网络可微,拿掉了CNN 中的池化层,另外将全连接层以全局池化层替代以减轻计算量。

去卷积(反卷积,Deconvolution)

从上图中可以看到,生成器G 将一个100 维的噪音向量扩展成64 * 64 * 3 的矩阵输出,整个过程采用的是微步卷积的方式。作者在文中将其称为fractionally-strided convolutions,并特意强调不是deconvolutions。

去卷积(链接:反卷积)又包含转置卷积和微步卷积,两者的区别在于padding 的方式不同,看看下面这张图片就可以明白了:

3. 训练方法

DCGAN 的训练方法跟GAN 是一样的,分为以下三步:

(1)for k steps:训练D 让式子【logD(x) + log(1 – D(G(Z)) (G keeps still)】的值达到最大

(2)保持D 不变,训练G 使式子【logD(G(z))】的值达到最大

(3)重复step(1)和step(2)直到G 与D 达到纳什均衡

4. 相比于GAN 的改进

DCGAN 相比于GAN 或者是普通CNN 的改进包含以下几个方面:

(1)使用卷积和去卷积代替池化层

(2)在生成器和判别器中都添加了批量归一化操作

(3)去掉了全连接层,使用全局池化层替代

(4)生成器的输出层使用Tanh 激活函数,其他层使用RELU

(5)判别器的所有层都是用LeakyReLU 激活函数

5. 漫游隐空间

通过使用插值微调噪音输入z 的方式可以导致隐空间结构发生变化从而引导生成图像发生语义上的平滑过度,比如说从有窗户到没窗户,从有电视到没电视等等。

6. 语义遮罩

通过标注窗口,并判断激活神经元是否在窗口内的方式来找出影响窗户形成的神经元,将这些神经元的权重设置为0,那么就可以导致生成的图像中没有窗户。从下图可以看到,上面一行图片都是有窗户的,下面一行通过语义遮罩的方式拿掉了窗户,但是空缺的位置依然是平滑连续的,使整幅图像的语义没有发生太大的变化。

7. 矢量算法

在向量算法中有一个很经典的例子就是【vector(“King”) – vector(“Man”) + vector(“Woman”) = vector(“Queue”)】,作者将该思想引入到图像生成当中并得到了以下实验结果:【smiling woman – neutral woman + neutral man = smiling man】

BicycleGAN-图像一对多转换测试

2024年 12月
 1
2345678
9101112131415
16171819202122
23242526272829
3031  

CycleGAN、pix2pix、iGAN的主要贡献者最近在NIPS 2017上又推出了一篇文章Toward Multimodal Image-to-Image Translation(见https://junyanz.github.io/BicycleGAN/,https://arxiv.org/pdf/1711.11586.pdf),讨论如何从一张图像同时转换为多张风格不一成对的图像。

Pix2pix 和 CycleGAN 是非常的流行GAN,不仅在学术界有许多变体,同时也有许多基于此的应用。但是,它们都有一个缺点——图像的输出看起来几乎总是相同的。例如,如果我们要执行斑马到马的转换,被转换的同一马的照片将始终具有相同的外观和色调。这是由于GAN固有的特性,它学会过滤了噪声的随机性。

像pix2pix这样的图像转换(一对一)的方式是存在歧义的,因为不可能只对应一个输出。因此作者提出了一种一对多的输出,即将可能输出的图像是存在一定的分布特性的。

论文的主要方法如下图所示:

下图是 BicycleGAN 相关的模型和配置。图(a)是推理的配置,图像A与噪声相结合以生成图像B ^ ,可以将此看作是 cGAN 。在BicyleGAN中,形状为(256, 256, 3)的图像A是条件,而从潜在编码 z采样的噪声为大小为8的一维向量。图(b)是 pix2pix + 噪声 的训练配置。而图(c) 和 图(d) 的两个配置由 BicycleGAN 训练时使用:

简而言之,BicycleGAN 可以找到潜在编码z与目标图像B之间的关系,因此生成器可以在给定不同的z时学会生成不同的图像B ^ 。如上图所示,BicycleGAN 通过组合 cVAE-GAN 和 cLR-GAN 这两种模型来做到这一点。

cVAE-GAN
  VAE-GAN 的作者认为,L1 损失并不是衡量图像视觉质量的良好指标。例如,如果图像向右移动几个像素,则人眼看起来可能没有什么不同,但会导致较大的L1损失。因此使用 GAN 的鉴别器来学习目标函数,以判断伪造的图像是否真实,并使用 VAE 作为生成器,生成的图像更清晰。如果忽略上图(c)中的图像 A ,那就是 VAE-GAN ,由于以 A 为条件,其成为条件 cVAE-GAN 。训练步骤如下:

  • VAE 将真实图片 B编码为多元高斯分布的潜在编码,然后从它们中采样以创建噪声输入,此流程是标准的VAE工作流程;
  • 使用图像 A 作为条件及从潜矢量 z 采样的噪声用于生成伪图像B ^

训练中的数据流为 B − > z − > B ^ ( 图(c) 中的实线箭头),总的损失函数由三个损失组成:

对抗损失 \(L_{GAN}^{VAE}\)

L1​重建损失 \(L_{1}^{VAE}(G)\)

KL散度损失 \(L_{KL}(E)\)

cLR-GAN(Conditional Latent Regressor GAN)
  在 cVAE-GAN 中,对真实图像B进行编码,以提供潜在矢量的真实样本并从中进行采样。但是,cLR-GAN 的处理方式有所不同,其首先使用生成器从随机噪声中生成伪图像 B^,然后对伪图像 B^ 进行编码,最后计算其与输入随机噪声差异。
前向计算步骤如下:

首先,类似于 cGAN ,随机产生一些噪声,然后串联图像A以生成伪图像 B ^ ,之后,使用来自 VAE-GAN 的同一编码器将伪图像 B ^ 编码为潜矢量。
最后,从编码的潜矢量中采样 z ^ ,并用输入噪声 z 计算损失。数据流为 z −> B ^ −> z ^ ( 图(d) 中的实线箭头),有两个损失:

对抗损失 \(L_{GAN}\)

噪声 N(z) 与潜在编码之间的 L1损失 \(L_{1}^{latent}\)

通过组合这两个数据流,在输出和潜在空间之间得到了一个双映射循环。 BicycleGAN 中的 bi 来自双映射(双向单射),这是一个数学术语,简单来说其表示一对一映射,并且是可逆的。在这种情况下,BicycleGAN 将输出映射到潜在空间,并且类似地从潜在空间映射到输出。总损失如下:

最总的损失:

可以分为两块来理解,第一块就是cVAE-GAN的训练,我们分析的基础就是鞋子纹理风格生成为例。

鞋子纹理图片经过编码器得到编码后的latent z通过KL距离将其拉向我们事先定义好的分布N(z)上,将服从分布的z与鞋子草图A结合后送入生成器G中得到重构的鞋子纹理图。 此时为了衡量重构和真实的误差,这里用了L1损失和GAN的对抗思想实现,我们在后面损失函数分析部分再说。这样cVAE-GAN部分就可以训练了,cVAE GAN的重点还是在得到的embedding z

另一块就是cLR-GAN的训练,将鞋子草图A和分布N(z)结合经过生成器G得到鞋子纹理图, 再通过对生成的纹理图编码后得到的z去趋近分布N(z)来反向矫正生成图,达到一个变相的循环。

当这两部分训练的很好时,这个就是我们需要的BicycleGAN了,在检验训练效果时我们只需要,输入A加上N(z)就可以生成鞋子的纹理图了, 这个N(z)具体为什么怎么取将决定生成为纹理的风格了。

一些细节

  • 这里有一个小trike就是z和图片A的结合送入生成器G的结合方法,文中给出了两种方法:一种直接concat在input的channel上,一种Unet在压缩的时候,每次结果都加。 我们通过图解可以更好理解。

pytorch代码:https://github.com/junyanz/BicycleGAN

神经网络可视化工具

2024年 12月
 1
2345678
9101112131415
16171819202122
23242526272829
3031  

来源:磐创AI分享

神经网络可视化工具

Convolution Visualizer

https://ezyang.github.io/convolution-visualizer/index.html

这种交互式可视化演示了各种卷积参数如何影响输入、权重和输出矩阵之间的形状和数据依赖性。将鼠标悬停在输入/输出上将突出显示相应的输出/输入,而将鼠标悬停在权重上将突出显示哪些输入与该权重相乘以计算输出。(严格来说,这里可视化的操作是相关性,而不是卷积,因为真正的卷积在执行相关性之前会翻转其权重。但是,大多数深度学习框架仍然称这些卷积,最终与梯度下降相同.)

Weights & Biases

https://docs.wandb.ai/v/zh-hans/

Weights & Biases 可以帮助跟踪你的机器学习项目。使用我们的工具记录运行中的超参数和输出指标(Metric),然后对结果进行可视化和比较,并快速与同事分享你的发现。

通过wandb,能够给你的机器学习项目带来强大的交互式可视化调试体验,能够自动化记录Python脚本中的图标,并且实时在网页仪表盘展示它的结果,例如,损失函数、准确率、召回率,它能够让你在最短的时间内完成机器学习项目可视化图片的制作。

总结而言,wandb有4项核心功能:

看板:跟踪训练过程,给出可视化结果
报告:保存和共享训练过程中一些细节、有价值的信息
调优:使用超参数调优来优化你训练的模型
工具:数据集和模型版本化
也就是说,wandb并不单纯的是一款数据可视化工具。它具有更为强大的模型和数据版本管理。此外,还可以对你训练的模型进行调优。

draw_convnet

一个用于画卷积神经网络的Python脚本

https://github.com/gwding/draw_convnet

NNSVG

http://alexlenail.me/NN-SVG/LeNet.html

PlotNeuralNet:用于为报告和演示绘制神经网络的 Latex 代码。

https://github.com/HarisIqbal88/PlotNeuralNet

Tensorboard

https://www.tensorflow.org/tensorboard/graphs

Caffe

https://github.com/BVLC/caffe/blob/master/python/caffe/draw.py

Matlab

http://www.mathworks.com/help/nnet/ref/view.html

Keras.js

https://transcranial.github.io/keras-js/#/inception-v3

DotNet

https://github.com/martisak/dotnets

Graphviz

http://www.graphviz.org/

ConX

https://conx.readthedocs.io/en/latest/index.html

ENNUI

https://math.mit.edu/ennui/

Neataptic

https://wagenaartje.github.io/neataptic/

pyTorch模型可视化

visdom:

在PyTorch深度学习中,最常用的模型可视化工具是Facebook(中文为脸书,目前已改名为Meta)公司开源的Visdom

Visdom可以直接接受来自PyTorch的张量,而不用转化成NumPy中的数组,从而运行效率很高。此外,Visdom可以直接在内存中获取数据,毫秒级刷新,速度很快。

Visdom的安装很简单,直接执行以下命令即可:

pip install visdom

开启服务,因为visdom本质上是一个类似于Jupyter Notebook 的Web服务器,在使用之前需要在终端打开服务,代码如下:

python -m visdom.server

正常执行后,根据提示在浏览器中输入相应地址即可,默认地址为:

http://localhost:8097/

实例

本例通过使用PyTorch的可视化工具Visdom对手写数字数据集进行建模。

步骤1:先导入模型需要的包,代码如下。

import torch

import torch.nn as nn

import torch.nn.functional as F

import torch.optim as optim

from torchvision import datasets, transforms

from visdom import Visdom

步骤2:定义训练参数,代码如下。

batch_size=200

learning_rate=0.01

epochs=10

… …

执行成功后,在visdom网页可以看到实时更新的训练过程的数据变化,每一个epoch测试数据更新一次,如图9-15所示。

Visdom是由Plotly 提供的可视化支持,所以提供一下可视化的接口:

  • vis.scatter : 2D 或 3D 散点图
  • vis.line : 线图
  • vis.stem : 茎叶图
  • vis.heatmap : 热力图
  • vis.bar : 条形图
  • vis.histogram: 直方图
  • vis.boxplot : 箱型图
  • vis.surf : 表面图
  • vis.contour : 轮廓图
  • vis.quiver : 绘出二维矢量场
  • vis.image : 图片
  • vis.text : 文本
  • vis.mesh : 网格图
  • vis.save : 序列化状态

更新损失函数

在训练的时候我们每一批次都会打印一下训练的损失和测试的准确率,这样展示的图表是需要动态增加数据的,下面我们来模拟一下这种情况:

x,y=0,0
env2 = Visdom()
pane1= env2.line(
    X=np.array([x]),
    Y=np.array([y]),
    opts=dict(title='dynamic data'))

Setting up a new session…

for i in range(10):
    time.sleep(1) #每隔一秒钟打印一次数据
    x+=i
    y=(y+i)*1.5
    print(x,y)
    env2.line(
        X=np.array([x]),
        Y=np.array([y]),
        win=pane1,#win参数确认使用哪一个pane
        update='append') #我们做的动作是追加

TensorBoard

pytorch也支持tensorboard的使用:

Tensorboard的使用逻辑

Tensorboard的工作流程简单来说是

  • 将代码运行过程中的,某些你关心的数据保存在一个文件夹中:
这一步由代码中的writer完成
  • 再读取这个文件夹中的数据,用浏览器显示出来:
这一步通过在命令行运行tensorboard完成。

官方:

https://pytorch.org/docs/stable/tensorboard.html?highlight=tensorboard

其中可视化的主要功能如下:

(1)Scalars:展示训练过程中的准确率、损失值、权重/偏置的变化情况。

(2)Images:展示训练过程中记录的图像。

(3)Audio:展示训练过程中记录的音频。

(4)Graphs:展示模型的数据流图,以及训练在各个设备上消耗的内存和时间。

(5)Distributions:展示训练过程中记录的数据的分部图。

(6)Histograms:展示训练过程中记录的数据的柱状图。

(7)Embeddings:展示词向量后的投影分部。

动手练习:可视化模型参数

步骤1:首先导入相关的第三方包,代码如下。

import numpy as np

from torch.utils.tensorboard import SummaryWriter

步骤2:将loss写到Loss_Accuracy路径下面,代码如下。

np.random.seed(10)

writer = SummaryWriter(‘runs/Loss_Accuracy’)

步骤3:然后将loss写到writer中,其中add_scalars()函数可以将不同的变量添加到同一个图,代码如下。

for n_iter in range(100):

writer.add_scalar(‘Loss/train’, np.random.random(), n_iter)

writer.add_scalar(‘Loss/test’, np.random.random(), n_iter)

writer.add_scalar(‘Accuracy/train’, np.random.random(), n_iter)

writer.add_scalar(‘Accuracy/test’, np.random.random(), n_iter)

代码体中要做的事

首先导入tensorboard

from torch.utils.tensorboard import SummaryWriter   

这里的SummaryWriter的作用就是,将数据以特定的格式存储到刚刚提到的那个文件夹中。

首先我们将其实例化

writer = SummaryWriter('./path/to/log')

这里传入的参数就是指向文件夹的路径,之后我们使用这个writer对象“拿出来”的任何数据都保存在这个路径之下。

这个对象包含多个方法,比如针对数值,我们可以调用

writer.add_scalar(tag, scalar_value, global_step=None, walltime=None)

这里的tag指定可视化时这个变量的名字,scalar_value是你要存的值,global_step可以理解为x轴坐标。

举一个简单的例子:

for epoch in range(100)
    mAP = eval(model)
    writer.add_scalar('mAP', mAP, epoch)

这样就会生成一个x轴跨度为100的折线图,y轴坐标代表着每一个epoch的mAP。这个折线图会保存在指定的路径下(但是现在还看不到)

同理,除了数值,我们可能还会想看到模型训练过程中的图像。

 writer.add_image(tag, img_tensor, global_step=None, walltime=None, dataformats='CHW')
 writer.add_images(tag, img_tensor, global_step=None, walltime=None, dataformats='NCHW')

可视化

我们已经将关心的数据拿出来了,接下来我们只需要在命令行运行:

tensorboard --logdir=./path/to/the/folder --port 8123

然后打开浏览器,访问地址http://localhost:8123/即可。这里的8123只是随便一个例子,用其他的未被占用端口也没有任何问题,注意命令行的端口与浏览器访问的地址同步。

如果发现不显示数据,注意检查一下路径是否正确,命令行这里注意是

--logdir=./path/to/the/folder 

而不是

--logdir= './path/to/the/folder '

另一点要注意的是tensorboard并不是实时显示(visdom是完全实时的),而是默认30秒刷新一次。

细节

1.变量归类

命名变量的时候可以使用形如

writer.add_scalar('loss/loss1', loss1, epoch)
writer.add_scalar('loss/loss2', loss2, epoch)
writer.add_scalar('loss/loss3', loss3, epoch)

的格式,这样3个loss就会被显示在同一个section。

2.同时显示多个折线图

假如使用了两种学习率去训练同一个网络,想要比较它们训练过程中的loss曲线,只需要将两个日志文件夹放到同一目录下,并在命令行运行

tensorboard --logdir=./path/to/the/root --port 8123

物体检测中小物体问题

摘自:3D视觉初学者

0.介绍

检测小物体是计算机视觉中最具挑战性和重要的问题之一。在这篇文章中,我们将讨论通过迭代数百种小物体检测模型在Roboflow上开发的一些策略。无人机在公共空中海上数据集中从上方看到的小物体

为了提高模型在小对象上的性能,我们建议以下技术入手:

  • 提高图像拍摄分辨率
  • 增加模型的输入分辨率
  • 平铺图片
  • 通过扩充生成更多数据
  • 自动学习模型
  • 过滤掉多余的类

小物件很难!例如,在EfficientDet中,小型对象的AP仅为12%,大型对象的AP为51%。那几乎是五倍的差异!那么,为什么很难检测小物体呢?一切都取决于模型。对象检测模型通过聚合卷积层中的像素来形成特征。

PP-YOLO中用于对象检测的特征聚合

如果地面物体本来就不大,而在进行训练时还会变小。因此,小物体最有可能出现数据标记错误,甚至可能会省略其标识。从经验和理论上讲,小物体都很难检测。

提高图像拍摄分辨率

分辨率,分辨率,分辨率……全都与分辨率有关。

很小的物体在边界框内可能只包含几个像素,这意味着增加图像的分辨率以增加检测器可以从该边界框提取信息的丰富度,这非常重要。因此,如果可能我们建议捕获尽可能高分辨率的图像。

增加模型的输入分辨率

获得更高分辨率的图像后,就可以扩大模型的输入分辨率。警告:这将导致大型模型需要花费较长的训练时间,并且在开始部署时将较慢地推断出来。您可能需要进行实验以找出速度与性能之间的权衡。

平铺图片

检测小图像的另一种很好的策略是将图像平铺作为预处理步骤。平铺可以有效地将检测器放大到小物体上,但可以保持所需的小输入分辨率,以便能够进行快速推理。

通过扩充生成更多数据

数据扩充会从基本数据集中生成新图像。这对于防止模型过度拟合训练集非常有用。对于小物体检测,一些特别有用的增强包括随机裁剪,随机旋转和镶嵌增强。自动学习模型的锚定框

锚定框是模型学习预测的原型边界框。也就是说,锚框可以预先设置,有时对于训练数据而言不是最佳的。自定义调整这些参数以适合我们需要完成的任务,这是很好的。YOLOv5模型架构会根据小伙伴的自定义数据自动为您完成此操作。我们要做的就只是是开始训练。

过滤掉多余的类

类管理是提高数据集质量的一项重要技术。如果有两个类明显重叠的类,则应从数据集中过滤一个。如果因为认为数据集中的小对象不值得检测,并希望将他们先去除。大家可以通过运行Roboflow Pro的高级数据集来快速识别所有这些小对象。可以通过Roboflow的管理工具来实现类遗漏和类重命名。

GAN系列之 StarGAN

StarGAN: Unified Generative Adversarial Networks for Multi-Domain Image-to-Image Translation

Authors

Yunjey Choi, Minje Choi, Munyoung Kim, Jung-Woo Ha, Sunghun Kim, Jaegul Choo

Abstract

Recent studies have shown remarkable success in image-to-image translation for two domains. However, existing approaches have limited scalability and robustness in handling more than two domains, since different models should be built independently for every pair of image domains. To address this limitation, we propose StarGAN, a novel and scalable approach that can perform image-to-image translations for multiple domains using only a single model. Such a unified model architecture of StarGAN allows simultaneous training of multiple datasets with different domains within a single network. This leads to StarGAN’s superior quality of translated images compared to existing models as well as the novel capability of flexibly translating an input image to any desired target domain. We empirically demonstrate the effectiveness of our approach on a facial attribute transfer and a facial expression synthesis tasks.

Pix2Pix模型解决了有Pair对数据的图像翻译问题;CycleGAN解决了Unpaired数据下的图像翻译问题。但无论是Pix2Pix还是CycleGAN,都是解决了一对一的问题,即一个领域到另一个领域的转换。当有很多领域要转换了,对于每一个领域转换,都需要重新训练一个模型去解决。这样的行为太低效了。本文所介绍的StarGAN就是将多领域转换用统一框架实现的算法。

下图是StarGAN的效果,在同一种模型下,可以做多个图像翻译任务,比如更换头发颜色,更换表情,更换年龄等。

StarGAN,顾名思义,就是星形网络结构,在StarGAN中,生成网络G被实现成星形。

1.CycleGAN 不能解决多领域迁移的问题。 只能两个领域的互相转化A->B,B-A。 但是实际场景中,我们可能遇到 多个数据集,或者多种属性的互相转化的要求。这样的话我们就需要O(n^2)的G model。(如下图)

2.有些属性(如人的表情),如果只取其中的两个属性(笑和不笑),那么就无法利用上其他训练数据(比如生气/恐惧等表情数据)。

1.作者提出了StarGAN 来处理多个domain之间互相generate图像 的问题。只用一个generator网络。

假如想实现四个域内图像风格的相互转换,要实现这个目标,通过cycleGAN需要创建12个生成器(如图a)。而starGAN的直观构造如图b,只需要一个生成器即可。

2. G的输入除了图片,还有domain的label,对应的把生成图片变到指定的domain。

starGAN的提出是为了解决多数据集在多域间图像转换的问题,starGAN可以接受多个不同域的训练数据,并且只需要训练一个生成器,就可以拟合所有可用域中的数据。

StarGAN的大致训练流程

i)如图a,训练判别器,将 real_img 和 fake_img 分别传递给判别器,判别器会判别图像的真假,同时它还会判别该图像来自哪个域(只对real_img 的label做判别)。
ii)如图b,训练生成器,与CGAN类似,这里除了输入图像外,还要输入该图像想转换的目标域,这个目标域类似于约束条件,它要求生成器尽可能去生成该目标域中的图像。
iii)如图c,表示循环一致性的过程,如果只是单纯的使用条件去控制生成器生成,那么生成器就会生成满足条件但可能与输入图像无关的数据,为了避免这种情况,便使用循环一致性的思想,即将生成的图像加上输入图像所在的域作为生成器的输入,希望获得的输出与原输入图像越接近越好。
iiii)如图d,表示训练生成器,即将生成器生成的图片交给判别器,让判别器判别图像的真假以及图像所在的域是否正确。

损失函数:

Adversarial loss 为 conditional gan常用的。(实际替换为WGAN的loss)

Reconstruction loss 为L1 Loss (和Cyclegan一样)

Domain classification loss(属性分类)就是传统分类log NLLloss。

类别损失,该损失被分成两个,训练D的时候,使用真实图像在原始领域进行,训练G的时候,使用生成的图像在目标领域进行。

多数据集训练
在多数据集下训练StarGAN存在一个问题,那就是数据集之间的类别可能是不相交的,但内容可能是相交的。比如CelebA数据集合RaFD数据集,前者拥有很多肤色,年龄之类的类别。而后者拥有的是表情的类别。但前者的图像很多也是有表情的,这就导致前一类的图像在后一类的标记是不可知的。

为了解决这个问题,在模型输入中加入了Mask,即如果来源于数据集B,那么将数据集A中的标记全部设为0.

GAN系列之 CycleGAN

摘自 https://zhuanlan.zhihu.com/p/306442363

pixtopix需要一对一,一个image对应一个image,训练集的两组图片一一对应才能训练

CycleGAN的介绍

1.CycleGAN的原理

CycleGAN,即循环生成对抗网络,出自发表于 ICCV17 的论文《Unpaired Image-to-Image Translation using Cycle-Consistent Adversarial Networks》,和它的兄长Pix2Pix(均为朱大神作品)一样,用于图像风格迁移任务。以前的GAN都是单向生成,CycleGAN为了突破Pix2Pix对数据集图片一一对应的限制,采用了双向循环生成的结构,因此得名CycleGAN。

首先,CycleGAN也是一个GAN模型,通过判别器和生成器的对抗训练,学习数据集图片的像素概率分布来生成图片。

要完成X域到Y域的图片风格迁移,就要求GAN网络既要拟合Y域图片的风格分布分布,又要保持X域图片对应的内容特征。打个比方,用草图风格的猫图片生成照片风格的猫图片时,要求生成的猫咪“即要活灵活现,又要姿势不变”。“拟合数据分布”本来就是GAN干的活儿,而“保持原图片特征”在Pix2Pix上是这么实现的:

因为Pix2Pix是一个CGAN,所以,我们通过用X域图片当约束条件来限制Pix2Pix的输出Y域风格图片时保有X域图片的特征。

而送入CycleGAN的两组(X域Y域)图片没有一一对应关系,即使我们将X域图片当成限制条件输入到一个CGAN中,也起不到限制模型输出保有X域图片特征的作用。因为,送入的两组图片完全是随机配在一起,CGAN学不到任何联系。因此,CycleGAN采取了一个绝妙的设计:通过添加“循环生成”并优化一致性损失(Consistency Loss)来代替CGAN中使用的约束条件来限制生成器保有原域图片特征。这样就不需要训练集图片一一对应了。

2.CycleGAN的流程

下面,我们就来看看循环生成网络(CycleGAN)到底是怎么“循环起来”的:

上图左半部分,将原域图片x送入(x2y方向)生成器G生成目标域图片y^,然后再将生成的目标域图片y^送入(y2x方向)生成器F反过来生成原域图片x^。生成x^的目的就是用它与输入的真图片x来算L1 Loss。我们知道Pix2Pix优化时除了使用GAN Loss(对抗损失)外,还加入了生成器输入图片和输出图片的L1 Loss来对齐生成图片与输入图片的宏观轮廓(所谓低频信息)。同样的逻辑,我们也能在CycleGAN中用L1 Loss来对齐“循环生成”的x^与输入的原图片x的内容自然,x生成的y^的轮廓也是和x对齐的了。这就达到了(原论文中的例子)“马变斑马,花纹变,姿势不变”的目的了。(我在网上看到的CycleGAN资料都没有点明这一点的,所以只好自行脑补,欢迎指正。)

在这个x->y^->x^的生成过程中,可以通过判别器Dy与生成器(x2y)G进行对抗训练。那么这个链条上的反向生成器(y2x)F怎么办?当然是加个判别器Dx与它进行对抗训练了。这样CycleGAN就有了两个方向相反的生成器,两个分别判别x域、y域图片的判别器。但要注意一个问题:就像GAN的生成器和判别器不能同时训练一样,Cyc1eGAN的两个生成器、两个判别器也只能一个一个训练,这就形成了CycleGAN训练的两条“环路”。

3.CycleGAN的结构

接下来,我们再看看这两对判别器、生成器怎么摆:

上半部份是生成器G和判别器Dy进行x2y的训练过程,下半部份是生成器F和判别器Dx进行y2x的训练过程。很像是两个风格迁移方向相反Pix2Pix模型,只是这两个GAN是普通GAN,不是Pix2Pix那样的CGAN。这一点,从生成器和判别器的输入就可以看出来,输入的只有原域图片并没有像Pix2Pix一样融合条件图片。

4.CycleGAN的loss函数

前面分析了CycleGAN的原理,我们已经知道了CycleGAN的loss由对抗损失(称为gan loss或adversarial loss)和循环一致性损失(consitency loss)组成,下面看看公式:

上面公式中:

​指的是x2y过程的对抗损失(adversarial loss)

​指的是y2x过程的对抗损失(adversarial loss)

​指的是生成器G和生成器F的循环一致性损失。

其中为循环一致性损失(consitency loss)的缩放系数,是一个超参数。

实际上,原论文的代码还加入了本体映射损失(identity loss),只是默认设置为关闭。CycleGAN正常训练时,生成器G输入x,生成y^。计算生成器G的本体映射损失(identity loss)时,生成器G输入y,生成y^,然后用y与y^的L1 loss作为G的identity loss。相应地,生成器F的identity loss则是输入的x与生成的x^的L1 loss。优化CycleGAN时,如果启用identity loss则将这两部分加到模型总loss中。与循环一致性损失(consistency loss)一样,也使用缩放系数超参控制其在总loss中所占比重。

论文中提到,CycleGAN使用identity loss的目的是在迁移的过程中保持原色调,下面是使用identity loss的对比效果:

上面图片最右边一列使用identity loss后果然纠正了生成器的色偏。

code:

https://github.com/eriklindernoren/PyTorch-GAN

GAN系列之pix2pix

也许是CycleGAN的光芒太过耀眼,Pix2Pix就像家中的次子,还没得宠多长时间,就被弟弟CycleGAN抢走了风头。这也怪不得它们的“爹滴”朱大神把“域风格迁移”的CycleGAN(下个项目介绍)造得太好用了,似乎完全能够代替“像素风格迁移”的Pix2Pix,以至于都来不及给Pix2Pix起个××GAN的名字~

其实,除了“白天照片变夜晚”、“图片着色”、“蓝图变街景”等它弟弟CycleGAN更容易玩儿的花样儿外,Pix2Pix是有着自己的独门绝技的。比如,用自然风景照片训练好的Pix2Pix模型,能实时将手绘的草图渲染成对应风景照片。如果训练集照片里包括老虎等动物,我们几笔在一个圆圈脑袋上画个王字,Pix2Pix模型就能生成一张活灵活现的大老虎,比《照相馆的故事》快多了~Pix2Pix的工作也启发了一些更具体的应用,比如专门手绘照片的SketchyGAN、手绘人脸的模型DeepFaceDrawing等。另外Pix2Pix->Pix2PixHD(高清渲染)->Vid2Vid(视频实时渲染)也是一条发展路线。试想,只需建好游戏人物和场景的结构模型,然后机器自动按训练的风格渲染人物和场景,游戏设计师们有没有感到点儿激动。

1. Pix2Pix的原理

发表在CVPR2017上的论文《Image-to-Image Translation with Conditional Adversarial Networks》是将GAN应用于有监督的图像到图像翻译的经典论文,提出的GAN模型被简称为Pix2Pix(不叫××GAN,很像是小名儿吧~)。为了解决图像到图像的翻译(也就是前面提到的那些上色、手绘草图的应用),我们需要建立一个模型实现图像到图像的映射。

以前曾经有过尝试搭建一个CNN网络进行映射,并用L1距离来度量、优化模型,结果发现效果很模糊(用L2距离更模糊),就像下面这样:

那么,既然GAN能够较好地生成图片的细节,我们何不拿来一用?显然,经典GAN是不行的,没法控制输出嘛。CGAN正好拿来一用。对此,朱大神在报告里曾经解释过:如果我们用经典GAN,判别器判别时会出现这样的问题。

这样的生成图片判别为真没问题

但是,这样的生成图片也判断为真就有问题了。显而易见,生成的猫图片与手绘的猫草图的形态完全不一致。但因为这也是一张猫图片,是符合训练集图片的像素概率分布的,所以会被经典GAN判别为真图片。

为了解决这一问题,我们将输入的猫草图作为“条件标签”和生成的猫图片一起送入判别器进行判断,如下图:

这看上去是不是有点儿CGAN的影子?没错,这个Pix2Pix就是个CGAN!

2.Pix2Pix的结构

我们将Pix2Pix的结构与上篇CGAN的结构对比一下:

上图的上半部份是普通CGAN的结构,下半部分是Pix2Pix的结构。对比发现,Pix2Pix与CGAN的结构有两点不同:

  1. 在Pix2Pix中,输入生成器的控制条件由“分类标签y”变成了A组(原风格)图片,因为这里我们要用A组(原风格)图片做为控制条件来生成B组(目标风格)图片。由于输入生成器的A组图片的维度(图片尺寸)与生成器输出的B组图片的维度相同,足以映射复杂分布,所以,我们不必再输入噪声z。细心的同学可能会发现:在刚才那张“对比普通CGAN和Pix2Pix结构”的图片中,我们对“条件y”的解释,与上一张“介绍给Pix2Pix加标签原因”的图片中的解释不一样。“对比结构”的图片中将生成器的输入解释为“条件y”,而“解释用CGAN原因”的图片中将生成器的输入解释为“输入x”。实际上这两种对生成器输入的解释都指的是A(原风格)组图片,不影响后面的推理。但个人觉得:将生成器的输入解释为“条件y”更容易帮助理解Pix2Pix的CGAN本质。我理解,Pix2Pix拟合的是训练集中B组(目标风格)图片的像素概率分布,A组(原风格)图片是作为“约束条件”来使用的。对比一下普通CGAN的结构就清楚了。
  2. 在Pix2Pix中,输入判别器的控制条件也由“分类标签y”变成了A组(原风格)图片。A组(原风格)图片作为“条件y”要和真B组(目标风格)图片或生成器生成的假B组图片(在图像通道维度上)拼接在一起送入判别器。这个很好理解,也说明了前面把生成器的输入解释为“条件y”更“工整”。

这样,Pix2Pix做了以上改动后,整个模型从“输入噪声、输出图片”的流程,变成了“输入A组图片、输出B组图片”的流程。

3.Pix2Pix的loss

在大神造Pix2Pix的过程中也试过各种“配方”。包括使用L1损失、使用CGAN损失和使用两者之和,测试结果如下:

观察结果发现:

  • 只用L1损失时,生成的图片比较模糊。
  • 只用CGAN损失时,生成的图片很清晰,但颜色风格与Ground Truth图片差别较大。
  • 使用L1+CGAN损失时,生成的图片又清晰,又保留了更多Ground Truth图片的特征。

所以,最后Pix2Pix使用了L1+CGAN损失。我们看下loss的构成。

先看L1损失:

L1损失的计算方法就是真B组(目标风格)图片与生成器生成的假B组图片逐像素求差的绝对值再求平均。公式中的x指A组(原风格)图片,y指B组(目标风格)图片,z指C输入给生成器的(一般是高斯分布的)噪声,代码中并未使用。

再来看看CGAN损失:

Pix2Pix的CGAN损失和普通CGAN损失一模一样

Pix2Pix总的损失是这两者之和:

GAN系列之CGAN(Conditional GAN)

GAN只是拟合原数据集的像素概率分布,生成的样本并没有提供新的信息以优化模型的分类边界。我理解,样本插值还能优化一下分类边界,原始GAN充其量只能添加一点噪声,或许能增强一点模型泛化能力吧(真做数据增强还得InforGAN、styleGAN这样的才好,能通过潜空间插值对图像做高级语义的增强,这是后话。)。

原始GAN用起来也不方便,为了分别生成0~9的数字,得将原数据集按标签分为10组,每组用一个模型训练,一共需要10个模型。训练时由于每组的数据量少到原来的十分之一,也会发生因样本太少导致模型无法拟合的现象。所以,意欲降伏GAN的大神给原始GAN装了个钮,让GAN乖乖要啥给啥。这个带按钮的改进版就是CGAN。

CGAN(Conditional GAN)介绍

1、CGAN的原理

CGAN的全称是Conditional Generative Adversarial Nets,即条件生成对抗网络。故名思议,就是通过添加限制条件,来控制GAN生成数据的特征(类别)。

当我第一次了解了CGAN原理,我惊诧于它给GAN“加按钮”的方法竟然如此简单粗暴,要做仅仅就是“把按钮加上去”——训练时将控制生成类别的标签连同噪声一起送进生成器的输入端,这样在预测时,生成器就会同样根据输入的标签生成指定类别的图片了判别器的处理也是一样,仅仅在输入加上类别标签就可以了。

那么,为什么加了标签,CGAN就乖乖听话、要啥给啥了呢?原理也是十分简单,我们知道GAN要干的就是拟合数据的概率分布,而CGAN拟合的就是条件下的概率分布。

GAN:

原生GAN中的概率全改成条件概率:

而上面CGAN公式中的条件y就是咱给GAN装的“钮”。加上了这个条件按钮,GAN优化的概率期望分布公式就变成了CGAN优化的条件概率期望分布公式。即CGAN优化的目标是:在条件Y下,在判别器最大化真实数据与生成数据差异的情况下,最小化这个差距。训练CGAN的生成器时要同时送入随机噪声z和和条件y(在本项目中y就是MNIST手写数字数据集的数字标签)。就是这么简单!

2、CGAN的结构

CGAN设计巧妙,而结构也十分简单、清晰,与经典GAN只有输入部分稍许不同。

我们看看原始GAN与CGAN的结构对比(包括生成器和判别器),上半部份的是经典GAN,下半部分是CGAN:

我们先回顾下经典GAN的结构流程(如上图上半部份所示):

  • 训练判别器。将噪声z送入生成器,输出fake_x;将fake_x送入判别器,在更新判别器参数时尝试拉近判别器的输出与真标签1的距离,即最小化判别器输出与真标签1的交叉熵损失。再将真图片送入判别器,更新判别器参数时尝试拉近判别器的输出与假标签0的距离,即最小化判别器输出与假标签0的交叉熵损失。这个过程中,用真、“假”图片训练判别器的顺序不必需固定,真、假标签取值0、1也无需固定(可相反,效果没有区别)。要注意的是,训练判别器的过程中,只更新判别器参数,不更新生成器参数。
  • 训练生成器。生成器训练的过程和判别器基本一样,只是将生成器输出的“假图片”送入判别器后,将判别器的输出与真标签(1)拉近。目的就是,使生成器参数更新的方向朝着“骗过判别器的目标”进行,也就是所谓“对抗过程”。当然判别器出掌(判别器更新参数)时,生成器不还手(生成器不更新参数),轮到生成器还手(生成器更新参数)时,判别器也得双手背后(判别器不更新参数)。不然就打成一团,谁也看不到招式(无法正确更新参数,提高生成能力)了

我们再看下CGAN给GAN加的“料”(如上图下半部份所示):

  • 先看判别器。如图,无论是给判别器送入真图片还是生成器生成的假图片时,都要加上个“条件y”,也就是分类标签。判别器输出没有变化仍然只是判断输入图片的真假。老实说,当时我曾想:既然咱都conditional GAN了,这个判别器是不是要输出分类标签y来训练Condition那部分?但转念一想,不行,判别器还是得判别真假,不然没法和生成器对抗了。BUT,后来我发现还真有走这个路线的GAN,叫InfoGAN。这个InfoGAN给生成器配了两个判别器,一个判真假,一个分类别。
  • 再看生成器。生成器的输入除了随机噪声z外,也加入了“条件y”。到这儿,我又想:既然有了条件标签,就不用输入噪声z了吧~。答案当然是,不行!因为,噪声z的维度是和生成器输出图片的尺寸、复杂度相关的。本项目中输出图片尺寸是28×28=784。按理说模型进行映射的输入、输出尺寸应该是相等的。但是输出图片只是手写数字,规律比较简单,输入的尺寸可以进行一定程度的压缩。一般噪声z的维度为几十到一百就能生成比较理想的图片细节,如果太低会导致生成器拟合能力不足,生成图片质量低下。条件z只是一个取值0~9的维度为一的向量,模型拟合像素概率分布的效果可想而知。后面我们介绍的Pix2Pix模型的输入是一张和输出尺寸相同的图片,就不再输入噪声z了。

CGAN需要注意的一点是:输入的条件标签y不但要在输入时与噪声z融合在一起,在生成器和判别器的每一层输入里都要与特征图相融合,才能让模型“学好条件y”。不然,标签可能不灵~

code https://github.com/eriklindernoren/PyTorch-GAN

GAN系列之经典GAN(一)

reference:

https://zhuanlan.zhihu.com/p/78777020

https://zhuanlan.zhihu.com/p/28853704

GAN全称:Generative Adversarial Network 即生成对抗网络,由Ian J. Goodfellow等人于2014年10月发表在NIPS大会上的论文《Generative Adversarial Nets》中提出。此后各种花式变体Pix2Pix、CYCLEGAN、STARGAN、StyleGAN等层出不穷,在“换脸”、“换衣”、“换天地”等应用场景下生成的图像、视频以假乱真,好不热闹。前段时间PaddleGAN实现的First Order Motion表情迁移模型,能用一张照片生成一段唱歌视频。各种搞笑鬼畜视频火遍全网。用的就是一种GAN模型哦。深度学习三巨神之一的LeCun也对GAN大加赞赏,称“adversarial training is the coolest thing since sliced bread”。

对抗生成模型GAN首先是一个生成模型,和大家比较熟悉的、用于分类的判别模型不同。

判别模型的数学表示是y=f(x),也可以表示为条件概率分布p(y|x)。当输入一张训练集图片x时,判别模型输出分类标签y。模型学习的是输入图片x与输出的类别标签的映射关系。即学习的目的是在输入图片x的条件下,尽量增大模型输出分类标签y的概率。

而生成模型的数学表示是概率分布p(x)。没有约束条件的生成模型是无监督模型,将给定的简单先验分布π(z)(通常是高斯分布),映射为训练集图片的像素概率分布p(x),即输出一张服从p(x)分布的具有训练集特征的图片。模型学习的是先验分布π(z)与训练集像素概率分布p(x)的映射关系。

生成对抗网络一般由一个生成器(生成网络),和一个判别器(判别网络)组成。生成器的作用是,通过学习训练集数据的特征,在判别器的指导下,将随机噪声分布尽量拟合为训练数据的真实分布,从而生成具有训练集特征的相似数据。而判别器则负责区分输入的数据是真实的还是生成器生成的假数据,并反馈给生成器。两个网络交替训练,能力同步提高,直到生成网络生成的数据能够以假乱真,并与与判别网络的能力达到一定均衡。

GAN的本质

其实GAN模型以及所有的生成模型都一样,做的事情只有一件:拟合训练数据的分布。对图片生成任务来说就是拟合训练集图片的像素概率分布。下面我们从原理的角度演示一下GAN的训练过程:

上图中: 黑色点线为训练集数据分布曲线 蓝色点线为判别器输出的分布曲线 绿色实线为生成器输出的分布曲线 z展示的是生成器映射前的简单概率分布(一般是高斯分布)的范围和密度 x展示的是生成器映射后学到的训练集的概率分布的范围和密度 (a)判别器与生成器均未训练呈随机分布 (b)判别器经过训练,输出的分布在靠近训练集“真”数据分布的区间趋近于1(真),在靠近生成器生成的“假”数据分布的区间趋近于0(假) (c)生成器根据判别器输出的(真假)分布,更新参数,使自己的输出分布趋近于训练集“真”数据的分布。 经过(b)(c)(b)(c)…步骤的循环交替。判别器的输出分布随着生成器输出的分布与训练集分布的接近而更加平缓;生成器输出的分布则在判别器输出分布的指引下逐渐趋近于训练集“真”数据的分布。 (d)训练完成时,生成器输出的分布完美拟合了训练集数据的分布,判别器的输出由于生成器的完美拟合而无法判别生成器输出的真伪而呈一条取值约为0.5(真假之间)的直线。

GAN的组成

  1. 解读GAN的loss函数

GAN网络的训练优化目标就是如下公式:

公式出自Goodfellow在2014年发表的论文Generative Adversarial Nets。这里简单介绍下公式的含义和如何应用到代码中。上式中等号左边的部分: V(D,G)表示的是生成样本和真实样本的差异度,可以使用二分类(真、假两个类别)的交叉熵损失。

maxV(D, G)表示在生成器固定的情况下,通过最大化交叉熵损失V(D,G)来更新判别器D的参数。

min maxV(D, G)表示生成器要在判别器最大化真、假图片交叉熵损失V(D,G)的情况下,最小化这个交叉熵损失

首先固定G训练D :

1)训练D的目的是希望这个式子的值越大越好。真实数据希望被D分成1,生成数据希望被分成0。

第一项,如果有一个真实数据被分错,那么log(D(x))<<0,期望会变成负无穷大。

第二项,如果被分错成1的话,第二项也会是负无穷大。

很多被分错的话,就会出现很多负无穷,那样可以优化的空间还有很多。可以修正参数,使V的数值增大。

2)训练G ,它是希望V的值越小越好,让D分不开真假数据。

因为目标函数的第一项不包含G,是常数,所以可以直接忽略 不受影响。

对于G来说 它希望D在划分他的时候能够越大越好,他希望被D划分1(真实数据)。

第二个式子和第一个式子等价。在训练的时候,第二个式子训练效果比较好 常用第二个式子的形式。

证明V是可以收敛导最佳解的。

(1)global optimum 存在

(2)global optimum训练过程收敛

全局优化首先固定G优化D,D的最佳情况为:

1、证明D*G(x)是最优解

由于V是连续的所以可以写成积分的形式来表示期望:

通过假设x=G(z)可逆进行了变量替换,整理式子后得到:

然后对V(G,D)进行最大化:对D进行优化令V取最大

取极值,对V进行求导并令导数等于0.求解出来可得D的最佳解D*G(x)结果一样。

2、假设我们已经知道D*G(x)是最佳解了,这种情况下G想要得到最佳解的情况是:G产生出来的分布要和真实分布一致,即:

在这个条件下,D*G(x)=1/2。

接下来看G的最优解是什么,因为D的这时已经找到最优解了,所以只需要调整G ,令

对于D的最优解我们已经知道了,D*G(x),可以直接把它带进来 并去掉前面的Max

然后对 log里面的式子分子分母都同除以2,分母不动,两个分子在log里面除以2 相当于在log外面 -log(4) 可以直接提出来:

结果可以整理成两个KL散度-log(4)

KL散度是大于等于零的,所以C的最小值是 -log(4)

当且仅当

所以证明了 当G产生的数据和真实数据是一样的时候,C取得最小值也就是最佳解。

如上图所示GAN由一个判别器(Discriminator)和一个生成器(Generator)两个网络组成。

训练时先训练判别器:将训练集数据(Training Set)打上真标签(1)和生成器(Generator)生成的假图片(Fake image)打上假标签(0)一同组成batch送入判别器(Discriminator),对判别器进行训练。计算loss时使判别器对真数据(Training Set)输入的判别趋近于真(1),对生成器(Generator)生成的假图片(Fake image)的判别趋近于假(0)。此过程中只更新判别器(Discriminator)的参数,不更新生成器(Generator)的参数。

然后再训练生成器:将高斯分布的噪声z(Random noise)送入生成器(Generator),然后将生成器(Generator)生成的假图片(Fake image)打上真标签(1)送入判别器(Discriminator)。计算loss时使判别器对生成器(Generator)生成的假图片(Fake image)的判别趋近于真(1)。此过程中只更新生成器(Generator)的参数,不更新判别器(Discriminator)的参数。

判别器结构:

生成器结构:

代码实现:http://139.9.1.231/index.php/2021/12/29/gan/