【机器学习】生成对抗网络(GAN)

本文为机器学习的学习总结,讲解生成对抗网络(GAN)。欢迎在评论区与我交流 😃

导论

GAN 的基本概念

在 GAN 中,我们需要训练一个生成器(Generator),输入一个向量,让机器生成一些影像或诗词:

在这里插入图片描述

条件生成器输入已知的东西,而不是随机的向量,例如输入文字,让机器输出对的图片。条件生成器有很多应用,之后会详细讲解。

生成器是一个神经网络,即一个函数。在影像生成中,输出的图片就是高维向量。例如输入向量,输出头像,向量每一维代表一个特征:

在这里插入图片描述

与此同时,我们还会训练识别器(discriminator),识别器也是一个神经网络。例如输入图片,输出代表真实度的数值。

例如下面的例子,枯叶蝶是生成器,麻雀是识别器。枯叶蝶为了避免被捕食会不断进化,而麻雀为了捕食猎物也会不断进化:

在这里插入图片描述

识别器判断图片生成器生成的还是真实的图片,此时标准可能是是否为彩色等简单的标准。下一代的生成器想办法骗过第一代的识别器,从而进化到第二代;然后识别器也进化到第二代,学会判断第二代生成器与真实图片的差异。如此往复,不断进化。像天敌和被捕食者的关系。

当然对抗关系只是一种比喻,从另一个角度看也可以是互助的关系。例如学生画画(生成器),老师告诉学生如何画(识别器)。老师的标准不断严格,学生的水平也不断提高。

在这里插入图片描述

那么生成器为什么不自己学?识别器为什么不自己做?这两个问题我们后面会讲到。

这里用语言描述算法步骤:

首先随机初始化生成器和识别器。

在每次迭代中:

  1. 固定生成器 G G G,更新识别器参数。数据库给出范例,训练目标是:数据库范例输入时,输出 1;生成器图像输入时,输出 0.
  2. 固定识别器 D D D,调整生成器参数。生成器需要骗过识别器,希望生成器输出的图像,识别器能给高分,从而使生成的图像更真实。

实际中将生成器和识别器的神经网络和起来形成一个更大的神经网络,其中中间某层(隐藏层)输出一个图像。调参时固定一部分层的参数,调另一部分。

然后我们对算法进行数学描述:

初始化 D D D 的参数 θ d \theta_d θd G G G 的参数 θ g \theta_g θg

在每次迭代中:

更新识别器参数 θ d \theta_d θd

  1. 在数据库中选取 m m m 个样本 { x 1 , … , x m } \{x^1,…,x^m\} {x1,,xm}

  2. 从随机分布中选取 m m m 个样本 { z 1 , … , z m } \{z^1,…,z^m\} {z1,,zm}

  3. 计算生成器结果(产生图片) { x ~ 1 , … , x ~ m } \{\tilde{x}^1,…,\tilde{x}^m\} {x~1,,x~m},其中 x ~ i = G ( z i ) \tilde{x}^i=G(z^i) x~i=G(zi)

  4. 最大化 V ~ \tilde{V} V~ 从而更新识别器参数 θ d \theta_d θd,因为值在 0-1 之间,不用使用 sigmod 函数。
    V ~ = 1 m ∑ i = 1 m log ⁡ D ( x i ) + 1 m ∑ i = 1 m log ⁡ ( 1 − D ( x ~ i ) ) \tilde{V}=\frac{1}{m}\sum\limits_{i=1}^m\log{D(x^i)}+\frac{1}{m}\sum\limits_{i=1}^m\log(1-D(\tilde{x}^i)) V~=m1i=1mlogD(xi)+m1i=1mlog(1D(x~i))
    梯度下降法更新公式。这里因为是最大化 V ~ \tilde{V} V~,因此这里为加号。
    θ d ← θ d + η ∇ V ~ ( θ d ) \theta_d\leftarrow\theta_d+\eta\nabla\tilde{V}(\theta_d) θdθd+ηV~(θd)

更新生成器参数 θ g \theta_g θg

  1. 从随机分布中选取 m m m 个样本 { z 1 , … , z m } \{z^1,…,z^m\} {z1,,zm}

  2. 最大化 V ~ \tilde{V} V~ 从而更新生成器参数 θ g \theta_g θg
    V ~ = 1 m ∑ i = 1 m log ⁡ ( D ( G ( z i ) ) ) \tilde{V}=\frac{1}{m}\sum\limits_{i=1}^m\log(D(G(z^i))) V~=m1i=1mlog(D(G(zi)))
    梯度下降法更新公式:
    θ g ← θ g + η ∇ V ~ ( θ g ) \theta_g\leftarrow\theta_g+\eta\nabla\tilde{V}(\theta_g) θgθg+ηV~(θg)

GAN 作为结构化学习

首先简单介绍一下结构化学习(structured learning)。在回归和分类问题中,我们输出的结果为值和类型。如果我们需要输出的预测为序列、矩阵、图或树等,这就称为结构化学习。例如机器翻译、演讲识别和聊天机器人都输出一个句子。

为什么结构化学习具有挑战性

如果将结构化学习中每个句子都看作是一个类别,在预测时输出的句子很可能在训练时从没见过,我们将其视为创造。因此,结构化学习可以看作是一个极端的单/零样本学习(one-shot/zero-shot learning)。单/零样本学习是指我们之前没有这个类别的训练样本,或训练样本极少。

结构化学习中,机器生成的对象是有很多部分组成的,这些部分相互依赖,组成的整体才是有意义的,因此机器需要有整体的概念,而不是每次只关注生成一个像素值。例如输出图像的例子,机器首先在图像中间输出一个黑点,我们无法判断此时这个是正确还是错误的,只有完全输出图像时,我们才能知道黑点的正确性:

在这里插入图片描述

结构化学习中有 2 类方法:

  • Botton Up:从每个部件开始生成对象,即生成器的方法。缺点是无法了解到整体的正确性。
  • Top Down:估计每个对象整体,从而找到最好的一个,即识别器的方法。缺点是很难进行生成,后面会详细讲。

生成器自主学习

在传统监督学习中,提供给机器训练集,不断训练就能得到结果。而现在我们需要输入向量,输出图像,生成器的传统监督学习方法与手写数字识别相反。

在这里插入图片描述

如果生成器自主学习,训练集需要给出每个图像对应的一个向量。但是这个向量很难选择,如果随机赋值,那么相似度较高的图像对应的向量距离可能会很大,我们不希望这种情况发生。

对于向量如何赋值的问题,我们可以训练编码神经网络(NN Encoder),输入一张图片,输出一个向量:
在这里插入图片描述

使用自编码器来训练编码神经网络。同时编码和解码神经网络,将编码神经网络输出的向量作为解码神经网络的输出,从而解码神经网络输出一个图像,我们要使得输入图像和输出图像越像越好。

在这里插入图片描述

我们很容易发现,此时的 Decoder 神经网络就是我们要求的生成器。例如一个数字生成器,输入一个二维向量,输出一张图形:

在这里插入图片描述

横轴表示是否有圈,纵轴表示方向。

自编码器还有一个问题,如果我们输入向量 a,输出向左的 1,输入向量 b,输出向右的 1。如果输入 a 和 b 的平均向量,我们希望会产生竖直的 1,但因为神经网络是非线性的,产生的结果可能为噪声。

在这里插入图片描述

我们需要用 VAE(Variational Auto-encoder)解决这个问题。这里编码器不仅输出向量编码,还输出 σ i \sigma_i σi(越接近 1 越好),从正态分布中选几个样本与 σ i \sigma_i σi 相乘,加到向量编码 m i m_i mi 上,解码器再根据有噪声的向量还原图片:

在这里插入图片描述

这样解码器训练地会更加稳定。

通常向量是低维度的,图像是高维度的,但其分布本质为低维度的。向量的维度需要进行调整。单纯提高向量的维度可能并没用,虽然代价会更低,但性能可能并不会很好。

训练生成器造成丢失

生成器生成的图像要越像真实图片越好,在训练生成器时,我们将两张图片写成向量,计算每个像素间的距离,然后最小化这个距离。

但是在实际训练的时候,生成器会出错误,在某些地方不得不做妥协,误差位置也很重要,例如下图中第一行虽然只有 1 个像素的误差,但图像却无法正确识别;第二行虽然相差 6 个像素,但误差位置比较好,只是笔画长了一些,相似度还是很高的。因此我们不能单纯的计算图像间的距离。

在这里插入图片描述

假定我们已经知道了 L-1 层神经元的值,现在要求最后一层神经元的值,我们期望的是最后一层神经元的部分之间的像素值之间不要差太多,这样才不会出现下图中最左边图中离群的点,但最后一层的输出并不会考虑这个问题。

在这里插入图片描述

这就是单独学习一个生成器困难的地方。

但其实这种情况也是有解的,我们可以多加几层隐藏层就可以将像素的相关性考虑进来。因此,对于同样一个任务,用自编码器单纯训练生成器的神经网络的深度要远远大于用 GAN 训练。
在这里插入图片描述

用生成器得到的最好结果为蓝色点所示,绿色点为目标结果。可以看出在每个分布之间还有一些蓝色的点,效果并不好。

为什么识别器无法生成

识别器

输入一个对象,输出这个对象有多好(scalar)。识别器产生对象时比生成器更容易考虑到部件间的关系,因为识别器的输入是生成好的完整图片。例如识别子是卷积神经网络,其中一个过滤器如下,该过滤器判断是否有孤立像素,如果有就给低分。

假设我们已经有识别器,穷举所有可能的 x x x 作为输入,得到最高分的 x x x 就是生成结果:
x ~ = arg ⁡ max ⁡ x ∈ X D ( x ) \tilde{x}=\arg\max\limits_{x\in X} D(x) x~=argxXmaxD(x)
识别器需要输入正样本(输出为 1)和负样本(输出为 0)进行训练,而此时训练集中只有正样本。我们还需要一些负样本,如果负样本只是白噪声,那么识别器可能会将除了白噪声以外的图像都视为真实图像,因此负样本的质量需要很高。产生质量好的负样本则需要一个好的识别器,而一个好的识别器又需要质量好的负样本,如此便陷入了死循环中。

识别器的训练算法:

输入正样本集和随机生成的负样本集

每次迭代中:

  1. 训练识别器,使其能区别出正负样本
  2. x ~ = arg ⁡ max ⁡ x ∈ X D ( x ) \tilde{x}=\arg\max\limits_{x\in X} D(x) x~=argxXmaxD(x) 问题,用识别器生成样本。在下一代迭代中,将随机生成的负样本换成识别器生成的样本

在实际中,特征维度会很多,我们很难像下图一维空间中将除了正样本以外的所有 D ( x ) D(x) D(x) 都压低:

在这里插入图片描述

算法的做法是,对于下面的样本点,绿色代表真实图像,蓝色代表生成的图像,在一次学习后可能得到的识别器函数为 D ( x ) D(x) D(x),在没有样本的地方识别器的值可能会高于真实图像:
在这里插入图片描述

识别器会给自己生成的图片高分:

在这里插入图片描述

在下一次迭代中,识别器学习到要给自己产生的图像低分,将右侧的图像压低:

在这里插入图片描述

算法寻找识别器的弱点,找到非正样本的高分部分,将其压低。

最终正负样本的分布重合,算法收敛:

在这里插入图片描述

于是,仅用识别器也可以做生成。

生成器 VS 识别器

神经网络优点缺点
生成器(Generator)很容易生成,训练简单的神经网络很难考虑部件之间的关系
学习时模仿目标(像素间的相似度),仅学到目标的表象
识别器(Discriminator)可以考虑到图像的全局需要解一个很难的 arg ⁡ max ⁡ \arg\max argmax 问题,要假设识别器模型为线性的,功能受限

因此我们将生成器和识别器结合,将识别器中很难计算的 arg ⁡ max ⁡ \arg\max argmax 问题用生成器解决,生成器可以很容易地生成高分样本。这种做法十分有效且容易一般化。生成器仍然一部分一部分地产生对象,但得到的代价反馈不再是像素间的距离,而是一个有全局观的识别器。

GAN 产生的结果见下图,簇之间几乎没有杂点:

在这里插入图片描述

我们来比较一下 GAN 和 VAE 的性能。下图纵轴越小说明产生图片越相似,GAN 通常很敏感,只有特定参数才能训练,因此其性能有很大的范围。左边为生成数字的数据集,右边为生成 10 种不同图案的数据集。

在这里插入图片描述

赋予不同的参数,VAE 的性能比较稳定,但其最佳性能与 GAN 有很大的差距。

有帮助的话点个赞加关注吧 😃

  • 6
    点赞
  • 13
    收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Louis1874

你的鼓励将是我创作的最大动力

¥2 ¥4 ¥6 ¥10 ¥20
输入1-500的整数
余额支付 (余额:-- )
扫码支付
扫码支付:¥2
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值