-
2021-10-26 20:09:35
文章目录
GAN能干什么?
要问生成对抗网络(GAN)为什么这么火,就得看看它能干什么。
GAN是最近2年很热门的一种无监督算法,他能生成出非常逼真的照片,图像甚至视频。我们手机里的照片处理软件中就会使用到它。
GAN的核心思想是通过学习真实训练数据,生成“以假乱真”的数据。
GAN的设计初衷
一句话来概括 GAN 的设计动机就是——自动化。
-
从人工提取特征——到自动提取特征
深度学习最特别最厉害的地方就是能够自己学习特征提取。
机器的超强算力可以解决很多人工无法解决的问题。自动化后,学习能力更强,适应性也更强。 -
从人工判断生成结果的好坏——到自动判断和优化
监督学习中,训练集需要大量的人工标注数据,这个过程是成本很高且效率很低的。
而人工判断生成结果的好坏也是如此,有成本高和效率低的问题。
而 GAN 能自动完成这个过程,且不断的优化,这是一种效率非常高,且成本很低的方式。
下面我们通过GAN的原理来理解它是如何实现自动化的。
GAN 的基本原理(大白话)
生成对抗网络(GAN)由2个重要的部分构成
- 生成器(Generator):通过机器生成数据(大部分情况下是图像),目的是“骗过”判别器。
- 判别器(Discriminator):判断这张图像是真实的还是机器生成的,目的是找出生成器做的“假数据”。
生成模型的任务是生成看起来自然真实的、和原始数据相似的实例。判别模型的任务是判断给定的实例看起来是自然真实的还是人为伪造的(真实实例来源于数据集,伪造实例来源于生成模型)。
训练过程
- 第一阶段:固定“判别器D”,训练“生成器G”
我们使用一个还 OK 的判别器,让一个“生成器G”不断生成“假数据”,然后给这个“判别器D”去判断。
一开始,“生成器G”还很弱,所以很容易被揪出来。
但是随着不断的训练,“生成器G”技能不断提升,最终骗过了“判别器D”。
到了这个时候,“判别器D”基本属于瞎猜的状态,判断是否为假数据的概率为50%。 - 第二阶段:固定“生成器G”,训练“判别器D”
当通过了第一阶段,继续训练“生成器G”就没有意义了。这个时候我们固定“生成器G”,然后开始训练“判别器D”。
“判别器D”通过不断训练,提高了自己的鉴别能力,最终他可以准确的判断出所有的假图片。
到了这个时候,“生成器G”已经无法骗过“判别器D”。 - 循环阶段一和阶段二
通过不断的循环,“生成器G”和“判别器D”的能力都越来越强。
最终我们得到了一个效果非常好的“生成器G”,我们就可以用它来生成我们想要的图片了。
也就是说,生成器(generator)试图欺骗判别器(discriminator),判别器则努力不被生成器欺骗。
模型经过交替优化训练,两种模型都能得到提升,但最终我们要得到的是效果提升到很高很好的生成模型(造假团伙),这个生成模型(造假团伙)所生成的产品能达到真假难分的地步。
这样我们就可以使用这个生成器来生成我们想要的图片了(用于做训练集之类的)。GAN的总结
- GAN(Generative Adversarial Networks) 是一种深度学习模型,是近年来复杂分布上无监督学习最具前景的方法之一。
- 模型通过框架中(至少)两个模块:生成模型(Generative Model)和判别模型(Discriminative Model)的互相博弈学习产生相当好的输出。
- 原始 GAN 理论中,并不要求 G 和 D 都是神经网络,只需要是能拟合相应生成和判别的函数即可。但实用中一般均使用深度神经网络作为 G 和 D 。
- 一个优秀的GAN应用需要有良好的训练方法,否则可能由于神经网络模型的自由性而导致输出不理想。
GAN的提出:“Generative Adversarial Networks”(2014NIPS)
-
文章总结:
框架中同时训练两个模型:捕获数据分布的生成模型G,和估计样本来自训练数据的概率的判别模型D。
G的训练程序是将D错误的概率最大化。这个框架对应一个最大值集下限的双方对抗游戏。
可以证明在任意函数G和D的空间中,存在唯一的解决方案,使得G重现训练数据分布,而D=0.5。
在G和D由多层感知器定义的情况下,整个系统可以用反向传播进行训练。
在训练或生成样本期间,不需要任何马尔可夫链或展开的近似推理网络。实验通过对生成的样品的定性和定量评估证明了本框架的潜力。 -
解释
1.生成模型(Generative Model)和判别模型(Discriminative Model)的工作
判别模型对输入变量进行预测。
生成模型是给定某种隐含信息,来随机产生观测数据。
举个简单的例子:
— 判别模型:给定一张图,判断这张图里的动物是猫还是狗。
— 生成模型:给一系列猫的图片,生成一张新的猫咪(不在数据集里)。
2.它们两的损失函数
对于判别模型,损失函数是容易定义的,因为输出的目标相对简单。
但生成模型的损失函数的定义就不是那么容易。我们对于生成结果的期望,往往是一个暧昧不清,难以数学公理化定义的范式。所以不妨把生成模型的回馈部分,交给判别模型处理。这就是Goodfellow将机器学习中的两大类模型,Generative和Discrimitive给紧密地联合在了一起。
3.原理
GAN的基本原理其实非常简单,这里以生成图片为例进行说明。
假设我们有两个网络,G(Generator)和D(Discriminator)。
正如它的名字所暗示的那样,它们的功能分别是:
— G是一个生成图片的网络,它接收一个随机的噪声z,通过这个噪声生成图片,记做G(z)。
— D是一个判别网络,判别一张图片是不是“真实的”。它的输入参数是x,x代表一张图片,输出D(x)代表x为真实图片的概率,如果为1,就代表100%是真实的图片,而输出为0,就代表不可能是真实的图片。
如图,GAN网络整体示意如下:
在训练过程中,生成网络G的目标就是尽量生成真实的图片去欺骗判别网络D。而D的目标就是尽量把G生成的图片和真实的图片分别开来。这样,G和D构成了一个动态的“博弈过程”。
最后博弈的结果是什么?在最理想的状态下,G可以生成足以“以假乱真”的图片G(z)。对于D来说,它难以判定G生成的图片究竟是不是真实的,因此D(G(z)) = 0.5。
(插一嘴:纳什均衡,它是指博弈中这样的局面,对于每个参与者来说,只要其他人不改变策略,他就无法改善自己的状况。对应的,对于GAN,情况就是生成模型 G 恢复了训练数据的分布(造出了和真实数据一模一样的样本),判别模型再也判别不出来结果,准确率为 50%,约等于乱猜。这是双方网路都得到利益最大化,不再改变自己的策略,也就是不再更新自己的权重。)
这样我们的目的就达成了:我们得到了一个生成式的模型G,它可以用来生成图片。 -
Goodfellow从理论上证明了该算法的收敛性,以及在模型收敛时,生成数据具有和真实数据相同的分布(保证了模型效果)。GAN模型的目标函数如下:
公式中x表示真实图片,z表示输入G网络的噪声,G(z)表示G网络生成的图片,D(·)表示D网络判断图片是否真实的概率。
在这里,训练判别器D使得最大概率地分辩训练样本的标签(最大化log D(x)和log(1 – D(G(z)))),训练网络G最小化log(1 – D(G(z))),即最大化判别器D的损失。
而训练过程中固定一方,更新另一个网络的参数,交替迭代,使得对方的错误最大化,最终,G 能估测出样本数据的分布,也就是生成的样本更加的真实。
对以上阐述的进一步解释:
1.交替优化,每轮迭代中,先优化D,再保持D不变,优化G,如此迭代多次。
2.需要平衡D和G的训练次数。G的目标函数里包含D,训练出优秀G的前提是训练出优秀的D,因此一般在每轮迭代中,先训练k次D(k为大于等于1的整数),再训练一次G。
3.训练G时,一般固定D,此时目标函数中的Ex~pdata(x)[logD(x)]相当于常数,可以忽略,因此G的优化目标变成原始目标函数的后一项,即最小化Ez~pz(z)[log(1-D(G(z)))]。
4.在训练早期阶段,G的生成能力较弱,D能轻松分辨出真假样本,此时log(1-D(G(z)))接近0,其导数在0附近变化较小,不利于梯度下降优化。一般会将G的优化目标从最小化Ez~pz(z)[log(1-D(G(z)))]改为最大化Ez~pz(z)[logD(G(z))],便于早期学习。
从式子中理解对抗: 我们知道G网络的训练是希望使判别器对其生成的数据的判别D(G(z))趋近于1,也就是正类,这样G的loss就会最小。而D网络的训练就是一个2分类,目标是分清楚真实数据和生成数据,也就是希望真实数据的D输出趋近于1,而生成数据的输出即D(G(z))趋近于0,或是负类。这里就是体现了对抗的思想。 -
对 Goodfellow的GAN模型的目标函数的详细解释
1.x为真实数据的随机向量,各元素服从某个特定的分布pdata(x)。假设真实数据为28×28的灰度图像,那么x可以为784维向量;假设真实数据为长度252的时间序列,那么x为252维向量。
2.z为噪音向量,也称为隐变量(Latent Variable),各元素服从分布pz(z),一般将z的各元素设为独立同分布,且服从标准正态分布或[0,1]的均匀分布。噪音的维度可自由定义,例如将z设为100维向量。
3.x~pdata(x)相当于真实数据的一次采样,每次采样得到一条真实样本,例如一张真实图像、一条真实股价序列;z~pz(z)相当于噪音数据的一次采样。
4.生成器G的结构为神经网络,神经网络本质上是某个从输入到输出的非线性映射。G的输入为噪音向量z,输出为虚假数据G(z),G(z)的维数和真实数据x相同。假设真实数据为长度252的时间序列,x为252维向量,那么G(z)也是252维向量。
5.判别器D的结构为神经网络。D的输入为真实数据x或虚假数据G(z),输出为0~1之间的实数,相当于判别器对样本的真假判断。输出越接近1代表判别器认为输入数据偏向于真样本,越接近0代表判别器认为输入数据偏向于假样本。
6.对判别器D的输出取对数log,如logD(x)及log(1-D(G(z))),是常见的判别模型损失函数构建方式。对数的作用是将[0,1]区间内的数映射到(-∞,0]的范围,以便对其求导而后进行梯度下降优化。
7.Ex~pdata(x)[logD(x)]代表判别器对真实样本判断结果的期望。对于最优判别器D*,真实样本判断结果D(x)应为1,logD(x)为0;若判别器非最优,logD(x)小于0。换言之,若希望判别器达到最优,E~pdata(x)[logD(x)]应越大越好。
8.类似地,Ez~pz(z)[log(1-D(G(z)))]代表判别器对虚假样本判断结果的期望。对于最优判别器D*,虚假样本判断结果D(G(z))应为0,1-D(G(z))为1,log(1-D(G(z)))为0;若判别器非最优,log(1-D(G(z)))小于0。换言之,若希望判别器达到最优,Ez~pz(z)[log(1-D(G(z)))]应越大越好。
9.V(D,G)为上述两项的加总,称为价值函数(Value Function),相当于目标函数,本质是交叉熵损失函数。判别器真假识别能力越强,V(D,G)应越大。
10.GAN求解的是minimax(极小化极大)问题。第一步,我们希望寻找最优判别器D*,使得优化目标V(D,G)取最大值,即maxDV(D,G)部分,第一步的逻辑参见上一点。关键在于第二步,我们希望继续寻找最优生成器G*,使得最优判别器下的目标函数取最小值,即生成的样本令判别器表现越差越好,即minGmaxDV(D,G)部分,博弈的思想正体现在此处。 -
另一种解释帮助理解
生成器的作用是,通过学习训练集数据的特征,在判别器的指导下,将随机噪声分布尽量拟合为训练数据的真实分布,从而生成具有训练集特征的相似数据。而判别器则负责区分输入的数据是真实的还是生成器生成的假数据,并反馈给生成器。两个网络交替训练,能力同步提高,直到生成网络生成的数据能够以假乱真,并与判别网络的能力达到一定均衡。
GAN的优缺点
-
优势
1.能更好建模数据分布(图像更锐利、清晰)
2.G的参数更新不是直接来自数据样本,而是使用来自D的反向传播。
3.理论上,GANs 能训练任何一种生成器网络(只要是可微分函数都可以用于构建D和G,能够与深度神经网络结合做深度生成式模型)。其他的框架需要生成器网络有一些特定的函数形式,比如输出层是高斯的。
4.GANs可以比完全明显的信念网络(NADE,PixelRNN,WaveNet等)更快的产生样本,因为它不需要在采样序列生成不同的数据。
5.模型只用到了反向传播,无需利用马尔科夫链反复采样(GANs生成实例的过程只需要模型运行一次,而不是以马尔科夫链的形式迭代很多次),无需在学习过程中进行推断,没有复杂的变分下界,避开近似计算棘手的概率的难题。 -
缺陷
1.难训练,不稳定。生成器和判别器之间需要很好的同步,但是在实际训练中很容易D收敛,G发散。D/G 的训练需要精心的设计。(训练GAN需要达到纳什均衡,有时候可以用梯度下降法做到,有时候做不到。我们还没有找到很好的达到纳什均衡的方法,所以训练GAN相比VAE或者PixelRNN是不稳定的)
2.模式缺失(Mode Collapse)问题。GANs的学习过程可能出现模式缺失,生成器开始退化,总是生成同样的样本点,无法继续学习。
3.它很难去学习生成离散的数据,就像文本。(所以GAN的应用领域都在图像方面)
相比玻尔兹曼机,GANs很难根据一个像素值去猜测另外一个像素值,GANs天生就是做一件事的,那就是一次产生所有像素,你可以用BiGAN来修正这个特性,它能让你像使用玻尔兹曼机一样去使用Gibbs采样来猜测缺失值。
4.可解释性差,生成模型的分布 Pg(G)没有显式的表达。
GAN 的实际应用
-
生成图像数据集
人工智能的训练是需要大量的数据集的,如果全部靠人工收集和标注,成本是很高的。
GAN 可以自动的生成一些数据集,提供低成本的训练数据。
例如在人脸识别、行人重识别等任务中,可以通过GAN来生成具有多样高级语义特征的样本来充实训练集数据,以帮助提升模型精度。(数据增强) -
图像到图像的转换
简单说就是把一种形式的图像转换成另外一种形式的图像,就好像加滤镜一样神奇。例如:
— 把草稿转换成照片
— 把卫星照片转换为Google地图的图片
— 把照片转换成油画
— 把白天转换成黑夜 -
文字到图像的转换
-
语意 – 图像 – 照片 的转换
-
自动生成模特
-
照片到Emojis
GANs 可以通过人脸照片自动生成对应的表情(Emojis)。 -
照片编辑
使用GAN可以生成特定的照片,例如更换头发颜色、更改面部表情、甚至是改变性别。 -
预测不同年龄的长相
给一张人脸照片, GAN 就可以帮你预测不同年龄阶段你会长成什么样。 -
提高照片分辨率,让照片更清晰
给GAN一张照片,他就能生成一张分辨率更高的照片,使得这个照片更加清晰。 -
照片修复
假如照片中有一个区域出现了问题(例如被涂上颜色或者被抹去),GAN可以修复这个区域,还原成原始的状态。 -
自动生成3D模型
给出多个不同角度的2D图像,就可以生成一个3D模型。
应用总结:
图像生成 :GAN最常使用的地方就是图像生成,如超分辨率任务,语义分割等等。
(观察以上应用,感觉GAN的应用都是和图像处理相关的。)
数据增强 :用GAN生成的图像来做数据增强。
主要解决的问题是:对于小数据集,数据量不足, 如果能生成一些就好了。GAN 生成数据是可以用在实际的图像问题上的。(感觉也是和图像相关的)
至于给GAN 生成的数据有分配标签的方式, 有以下三类:(假设我们做五分类)- 把生成的数据都当成新的一类, 六分类,那么生成图像的 label 就可以是 (0, 0, 0, 0, 0, 1) 这样给。
- 按照置信度最高的 动态去分配,那个概率高就给谁 比如第三类概率高(0, 0, 1, 0, 0)。
- 既然所有类都不是,那么可以参考inceptionv3,搞label smooth,每一类置信度相同(0.2, 0.2, 0.2, 0.2, 0.2)。
GAN的一些经典变种
1. DCGAN:
DCGAN原文:Unsupervised Representation Learning with Deep Convolutional Generative Adversarial Networks
DCGAN是继GAN之后比较好的改进,其主要的改进主要是在网络结构上,到目前为止,DCGAN的网络结构还是被广泛的使用,DCGAN极大的提升了GAN训练的稳定性以及生成结果质量。
DCGAN把上述的G和D用了两个卷积神经网络(CNN)。同时对卷积神经网络的结构做了一些改变,以提高样本的质量和收敛的速度,这些改变有:
- 取消所有pooling层。G网络中使用转置卷积(transposed convolutional layer)进行上采样,D网络中用加入stride的卷积代替pooling。
- 在D和G中均使用batch normalization
- 去掉FC层,使网络变为全卷积网络
- G网络中使用ReLU作为激活函数,最后一层使用tanh
- D网络中使用LeakyReLU作为激活函数
2. WGAN和WGAN-GP:
WGAN原文:Wasserstein GAN
WGAN主要从损失函数的角度对GAN做了改进,损失函数改进之后的WGAN即使在全链接层上也能得到很好的表现结果,具体的来说,WGAN对GAN的改进有:
- 判别器最后一层去掉sigmoid。
- 生成器和判别器的loss不取log。
- 对更新后的权重强制截断到一定范围内,比如[-0.01,0.01],以满足论文中提到的lipschitz连续性条件。
- 论文中也推荐使用SGD, RMSprop等优化器,不要基于使用动量的优化算法,比如adam。
WGAN-GP原文:Improved Training of Wasserstein GANs
之前的WGAN虽然理论上有极大贡献,但在实验中却发现依然存在着训练困难、收敛速度慢的问题,这个时候WGAN-GP就出来了,它的贡献是:
- 提出了一种新的lipschitz连续性限制手法—梯度惩罚,解决了训练梯度消失梯度爆炸的问题。
- 比标准WGAN拥有更快的收敛速度,并能生成更高质量的样本。
- 提供稳定的GAN训练方式,几乎不需要怎么调参,成功训练多种针对图片生成和语言模型的GAN架构。
3. Conditional GAN:
因为原始的GAN过于自由,训练会很容易失去方向,从而导致不稳定又效果差。而Conditional GAN就是在原来的GAN模型中加入一些先验条件,使得GAN变得更加的可控制。
具体的来说,我们可以在生成模型G和判别模型D中同时加入条件约束y来引导数据的生成过程。条件可以是任何补充的信息,如类标签,其它模态的数据等。然后这样的做法应用也很多,比如图像标注,利用text生成图片等等。
对比之前的目标函数,Conditional GAN的目标函数其实差不多:
就是多了把噪声z和条件y作为输入同时送进生成器或者把数据x和条件y作为输入同时送进判别器,如图。这样在外加限制条件的情况下生成图片。
其他生成网络简介
前面说过,GAN的目的是得到一个性能优秀的生成模型。
所以说,对抗生成模型GAN首先是一个生成模型,和大家比较熟悉的、用于分类的判别模型不同。判别模型的数学表示是y=f(x),也可以表示为条件概率分布p(y|x)。当输入一张训练集图片x时,判别模型输出分类标签y。模型学习的是输入图片x与输出的类别标签的映射关系。即学习的目的是在输入图片x的条件下,尽量增大模型输出分类标签y的概率。
而生成模型的数学表示是概率分布p(x)。没有约束条件的生成模型是无监督模型,将给定的简单先验分布π(z)(通常是高斯分布),映射为训练集图片的像素概率分布p(x),即输出一张服从p(x)分布的具有训练集特征的图片。模型学习的是先验分布π(z)与训练集像素概率分布p(x)的映射关系。
其实GAN模型以及所有的生成模型都一样,做的事情只有一件:拟合训练数据的分布。对图片生成任务来说就是拟合训练集图片的像素概率分布。生成网络并非只有GAN,介绍下其他几种:
- 自回归模型(Autoregressive model)是从回归分析中的线性回归发展而来,只是不用x预测y,而是用x预测 x(自己),所以叫做自回归。多用于序列数据生成如文本、语音。PixelRNN/CNN则使用这种方法生成图片,效果还不错。但是由于是按照像素点去生成图像导致计算成本高, 在可并行性上受限,在处理大型数据如大型图像或视频是具有一定麻烦的。
- 变分自编码器(VAE):VAE是在AE(Autoencoder自编码器)的基础上让图像编码的潜在向量服从高斯分布从而实现图像的生成,优化了数据对数似然的下界,VAE在图像生成上是可并行的, 但是VAE存在着生成图像模糊的问题。
- 基于流的模型(Flow-based Model)包括Glow、RealNVP、NICE等。流模型思想很直观:寻找一种变换 y = f(x)(f 可逆,且 y 与 x 的维度相同) 将数据空间映射到另一个空间,新空间各个维度相互独立。这些年,看着GAN一直出风头,流模型表示各种不服,自从2016年问世以来,一直在“不服中…”。
而GAN模型可以说是生成模型中的“明星”。
参考链接
更多相关内容 -
-
JS生成二维码
2015-12-30 23:04:52JS生成二维码,兼容各种浏览器及手机端,支持中文。 -
Mysql数据库文档生成工具
2016-02-16 22:21:52给大家介绍一款数据库文档生成工具 目前只支持mysql 主要是生成docx的 客户有些时候需要数据库文档,为了方便,于是我就写了这个工具, 通过数据库读取相关表数据,达到输出所有注释到文档中,大大提高了工作效率 -
mybatis-generator 代码自动生成工具---内有详细介绍
2016-03-09 15:45:51mybatis-generator 代码自动生成工具,里面有详细介绍 -
java代码生成器(亲测,好用)
2017-03-23 13:16:47亲测,好用,欢迎下载+教程 -
c#二维码生成
2013-10-23 16:59:03ASP.NET 二维码生成源码,Web界面,输入需要转换的文字或字符串,生成对应的二维码。代码精简,函数封装,便于复用。 -
android各种分辨率图标生成工具
2015-07-26 17:30:21可以将mdpi,hdpi,xhdpi,xxhdpi,xxxhdpi的图标自动生成mdpi,hdpi,xhdpi,xxhdpi,xxxhdpi的图标 -
最小生成树详解(模板 + 例题)
2020-10-15 16:04:26文章目录1、什么是树2、最小生成树3、最小生成树的应用4、实现最小生成树的两种算法4.1 prim (普里姆算法)4.2 kruskal (克鲁斯卡尔算法)5、总结 1、什么是树 如果一个无向连通图不包含回路(连通图中不存在环),.作为一个伪ACMer,先来首广为人知的打油诗:
模拟只会猜题意,贪心只能过样例,数学上来先打表,规律一般是DP,组合数学碰运气,计算几何瞎暴力,图论一顿套模板,数论只会GCD,递归递推伤不起,搜索茫然TLE,分治做得像枚举,暴力枚举数第一,数据结构干瞪眼,怒刷水题找信心。1、什么是树
如果一个无向连通图不包含回路(连通图中不存在环),那么就是一个树。
2、最小生成树
一个图中可能存在多条相连的边,我们一定可以从一个图中挑出一些边生成一棵树。这仅仅是生成一棵树,还未满足最小,当图中每条边都存在权重时,这时候我们从图中生成一棵树(n - 1 条边)时,生成这棵树的总代价就是每条边的权重相加之和。
一个有N个点的图,边一定是大于等于N-1条的。图的最小生成树,就是在这些边中选择N-1条出来,连接所有的N个点。这N-1条边的边权之和是所有方案中最小的。
3、最小生成树的应用
要在n个城市之间铺设光缆,主要目标是要使这 n 个城市的任意两个之间都可以通信,但铺设光缆的费用很高,且各个城市之间铺设光缆的费用不同,因此另一个目标是要使铺设光缆的总费用最低。这就需要找到带权的最小生成树。
4、实现最小生成树的两种算法
4.1 prim (普里姆算法)
算法分析:
Prim算法每次循环都将一个蓝点u变为白点,并且此蓝点u与白点相连的最小边权min[u]还是当前所有蓝点中最小的。这样相当于向生成树中添加了n-1次最小的边,最后得到的一定是最小生成树。
我们通过对下图最小生成树的求解模拟来理解上面的思想。蓝点和虚线代表未进入最小生成树的点、边;白点和实线代表已进入最小生成树的点、边。
初始时所有点都是蓝点,min[1]=0,min[2、3、4、5]=∞。权值之和MST=0。
第一次循环自然是找到min[1]=0最小的蓝点1。将1变为白点,接着枚举与1相连的所有蓝点2、3、4,修改它们与白点相连的最小边权。
min[2]=w[1][2]=2;
min[3]=w[1][3]=4;
min[4]=w[1][4]=7;
第二次循环是找到min[2]最小的蓝点2。将2变为白点,接着枚举与2相连的所有蓝点3、5,修改它们与白点相连的最小边权。min[3]=w[2][3]=1;
min[5]=w[2][5]=2;第三次循环是找到min[3]最小的蓝点3。将3变为白点,接着枚举与3相连的所有蓝点4、5,修改它们与白点相连的最小边权。
min[4]=w[3][4]=1;
由于min[5]=2 < w[3][5]=6;所以不修改min[5]的值。
最后两轮循环将点4、5以及边w[2][5],w[3][4]添加进最小生成树。最后权值之和MST=6。这n次循环,每次循环我们都能让一个新的点加入生成树,n次循环就能把所有点囊括到其中;每次循环我们都能让一条新的边加入生成树,n-1次循环就能生成一棵含有n个点的树;每次循环我们都取一条最小的边加入生成树,n-1次循环结束后,我们得到的就是一棵最小的生成树。这就是Prim采取贪心法生成一棵最小生成树的原理。算法时间复杂度:O (N2)。
精彩例题:
Code:
// prim 算法求最小生成树 #include <cstdio> #include <string> #include <cstring> #include <iostream> #include <algorithm> #define INF 0x3f3f3f3f using namespace std; const int maxn = 505; int a[maxn][maxn]; int vis[maxn],dist[maxn]; int n,m; int u,v,w; long long sum = 0; int prim(int pos) { dist[pos] = 0; // 一共有 n 个点,就需要 遍历 n 次,每次寻找一个权值最小的点,记录其下标 for(int i = 1; i <= n; i ++) { int cur = -1; for(int j = 1; j <= n; j ++) { if(!vis[j] && (cur == -1 || dist[j] < dist[cur])) { cur = j; } } // 这里需要提前终止 if(dist[cur] >= INF) return INF; sum += dist[cur]; vis[cur] = 1; for(int k = 1; k <= n; k ++) { // 只更新还没有找到的最小权值 if(!vis[k]) dist[k] = min(dist[k],a[cur][k]); } } return sum; } int main(void) { scanf("%d%d",&n,&m); memset(a,0x3f,sizeof(a)); memset(dist,0x3f,sizeof(dist)); for(int i = 1; i <= m; i ++) { scanf("%d%d%d",&u,&v,&w); a[u][v] = min(a[u][v],w); a[v][u] = min(a[v][u],w); } int value = prim(1); if(value >= INF) puts("impossible"); else printf("%lld\n",sum); return 0; }
4.2 kruskal (克鲁斯卡尔算法)
Kruskal(克鲁斯卡尔)算法是一种巧妙利用并查集来求最小生成树的算法。
算法描述:
在描述 kruskal 算法时先了解一下连通块的概念, 我们将无向图中相互连通的一些点称为处于同一个连通块中。
从上图我们可以清晰的看到,有 3 个连通块(1,2),(3),(4,5,6)。
Kruskal算法将一个连通块当做一个集合。Kruskal首先将所有的边按从小到大顺序排序(一般使用快排),并认为每一个点都是孤立的,分属于n个独立的集合。然后按顺序枚举每一条边。如果这条边连接着两个不同的集合,那么就把这条边加入最小生成树,这两个不同的集合就合并成了一个集合;如果这条边连接的两个点属于同一集合,就跳过。直到选取了n-1条边为止。
Kruskal(克鲁斯卡尔)算法开始时,认为每一个点都是孤立的,分属于n个独立的集合。
5个集合{ {1},{2},{3},{4},{5} }
生成树中没有边
Kruskal每次都选择一条最小的边,而且这条边的两个顶点分属于两个不同的集合。将选取的这条边加入最小生成树,并且合并集合。
第一次选择的是<1,2>这条边,将这条边加入到生成树中,并且将它的两个顶点1、2合并成一个集合。4个集合{ {1,2},{3},{4},{5} }
生成树中有一条边{ <1,2> }
第二次选择的是<4,5>这条边,将这条边加入到生成树中,并且将它的两个顶点4、5合并成一个集合。3个集合{ {1,2},{3},{4,5} }
生成树中有2条边{ <1,2> ,<4,5>}
第三次选择的是<3,5>这条边,将这条边加入到生成树中,并且将它的两个顶点3、5所在的两个集合合并成一个集合2个集合{ {1,2},{3,4,5} }
生成树中有3条边{ <1,2> ,<4,5>,< 3,5>}
第四次选择的是<2,5>这条边,将这条边加入到生成树中,并且将它的两个顶点2、5所在的两个集合合并成一个集合。1个集合{ {1,2,3,4,5} }
生成树中有4条边{ <1,2> ,<4,5>,< 3,5>,<2,5>}
算法结束,最小生成树权值为19。通过上面的模拟能够看到,Kruskal算法每次都选择一条最小的,且能合并两个不同集合的边,一张n个点的图总共选取n-1次边。因为每次我们选的都是最小的边,所以最后的生成树一定是最小生成树。每次我们选的边都能够合并两个集合,最后n个点一定会合并成一个集合。通过这样的贪心策略,Kruskal算法就能得到一棵有n-1条边,连接着n个点的最小生成树。
精彩例题:
Code:
// Kruskal 算法求最小生成树 #include <cstdio> #include <string> #include <cstring> #include <iostream> #include <algorithm> using namespace std; const int maxn = 2e5 + 10; struct node { int x,y,z; }edge[maxn]; bool cmp(node a,node b) { return a.z < b.z; } int fa[maxn]; int n,m; int u,v,w; long long sum; int get(int x) { return x == fa[x] ? x : fa[x] = get(fa[x]); } int main(void) { scanf("%d%d",&n,&m); for(int i = 1; i <= m; i ++) { scanf("%d%d%d",&edge[i].x,&edge[i].y,&edge[i].z); } for(int i = 0; i <= n; i ++) { fa[i] = i; } sort(edge + 1,edge + 1 + m,cmp); // 每次加入一条最短的边 for(int i = 1; i <= m; i ++) { int x = get(edge[i].x); int y = get(edge[i].y); if(x == y) continue; fa[y] = x; sum += edge[i].z; } int ans = 0; for(int i = 1; i <= n; i ++) { if(i == fa[i]) ans ++; } if(ans > 1) puts("impossible"); else printf("%lld\n",sum); return 0; }
5、总结
从上面的两道模板可得知,解决最小生成树的问题一般有两种方式:prim 和 Kruskal ,那么,什么时候选择哪种策略就成为了我们应该思考的一个问题:
稀疏图一般选择 prim,采用 邻接矩阵 进行存储边之间的关系。
稠密图一般选择 Kruskal ,采用邻接表进行存储边之间的关系(更多采用结构体的方式)。 -
pfx证书一键生成
2013-11-17 12:03:00pfx证书一键生成 压缩文档内有详细说明,利用批处理便捷的生成pfx证书. -
pb生成二维码
2011-11-26 10:21:47pb生成二维码源代码 二维码是QR 二维码 QR码是二维条码的一种,QR 来自英文 “Quick Response” 的缩写,即快速反应的意思,源自发明者希望 QR 码可让其内容快速被解码。QR码比普通条码可储存更多资料,亦无需像... -
淘宝商品标题生成器-v3.1免费绿色版
2012-11-28 19:23:59亲们,感谢大家一直以来的支持,也感谢大提出的宝贵的意见,宝贝标题生成器升级到v3.0啦! 大家经常在上传商品时为商品标题而苦恼,不知道什么样的标题淘宝搜索排行高,不知道该给自己商品加哪些关键字!以下这款软件... -
根据数据库生成javabean的eclipse插件
2014-05-01 11:02:202、 支持oracle指定表空间生成。 3、 支持批量生成javabean。 4、 支持重写“toString”方法(返回json格式字符串)。 5、 支持国际化。 6、 支持返回字段属性数组。 7、 支持java元注释。 8、 支持生成ibatis... -
MATLAB 生成随机数 方法总汇 (各分布配图参考)
2021-12-22 16:01:34生成 Weibull 分布随机数的语法是: wblrnd(A,B,[M,N,P,...]) 还有非中心卡方分布(ncx2rnd),非中心F分布(ncfrnd),非中心t分布(nctrnd),括号中是生成服从这些分布的函数,具体用法用:help 函数名 的方法查找。...目录
a. 基本随机数
Matlab 中有两个最基本生成随机数的函数。
1.rand()
生成(0,1)区间上均匀分布的随机变量。基本语法:
rand([M,N,P ...])
生成排列成 M*N*P... 多维向量的随机数。如果只写 M,则生成 M*M 矩阵;如果参数为 [M,N] 可以省略掉方括号。例如:
通过下面代码,可以生成大量随机数,查看大致的分布情况:
x=rand(100000,1); hist(x,30);
由此可以看到生成的随机数很符合均匀分布。
2.randn()
生成服从标准正态分布(均值为 0,方差为 1)的随机数。基本语法和 rand() 类似。
randn([M,N,P ...])
生成排列成 M*N*P... 多维向量的随机数。如果只写 M,则生成 M*M 矩阵;如果参数为 [M,N] 可以省略掉方括号。例如:
通过下面代码,可以生成大量随机数,查看大致的分布情况:
x=randn(100000,1); hist(x,50);
由图可以看到生成的随机数很符合标准正态分布。
b. 连续型分布随机数
如果你安装了统计工具箱(Statistic Toolbox),除了这两种基本分布外,还可以用 Matlab 内部函数生成符合下面这些分布的随机数。
3.unifrnd()
这个函数生成某个区间内均匀分布的随机数。基本语法
unifrnd(a,b,[M,N,P,...])
生成的随机数区间在 (a,b) 内,排列成 M*N*P... 多维向量。如果只写 M,则生成 M*M 矩阵;如果参数为 [M,N] 可以省略掉方括号。例如:
%注:上述语句生成的随机数都在 (-2,3) 区间内.
通过下面代码,可以生成大量随机数,查看大致的分布情况:
x=unifrnd(-2,3,100000,1); hist(x,50);
由图可以看到生成的随机数很符合区间 (-2,3) 上面的均匀分布。
4.normrnd()
此函数生成指定均值、标准差的正态分布的随机数。基本语法
normrnd(mu,sigma,[M,N,P,...])
生成的随机数服从均值为 mu,标准差为 sigma(注意标准差是正数)正态分布,这些随机数排列成 M*N*P... 多维向量。如果只写 M,则生成 M*M 矩阵;如果参数为 [M,N] 可以省略掉方括号。例如:
%注:上述语句生成的随机数所服从的正态分布都是均值为 2,标准差为 3.
通过下面代码,可以生成大量随机数,查看大致的分布情况:
x=normrnd(2,3,100000,1); hist(x,50);
如图,上半部分是由上一行语句生成的均值为 2,标准差为 3 的 10 万个随机数的大致分布,下半部分是用小节 “randn()” 中最后那段语句生成 10 万个标准正态分布随机数的大致分布。
注意到上半个图像的对称轴向正方向偏移(准确说移动到 x=2 处),这是由于均值为2的结果。
而且,由于标准差是 3,比标准正态分布的标准差(1)要高,所以上半部分图形更胖 (注意 x 轴刻度的不同)。
5.chi2rnd()
此函数生成服从卡方(Chi-square) 分布的随机数。卡方分布只有一个参数:自由度 v。基本语法
chi2rnd(v,[M,N,P,...])
生成的随机数服从自由度为 v 的卡方分布,这些随机数排列成 M*N*P... 多维向量。如果只写 M,则生成 M*M 矩阵;如果参数为 [M,N] 可以省略掉方括号。例如:
%注:上述语句生成的随机数所服从的卡方分布的自由度都是5
通过下面代码,可以生成大量随机数,查看大致的分布情况:
x=chi2rnd(5,100000,1); hist(x,50);
6.frnd()
此函数生成服从 F 分布的随机数。F分布有2个参数:v1, v2。基本语法
frnd(v1,v2,[M,N,P,...])
生成的随机数服从参数为 (v1,v2) 的卡方分布,这些随机数排列成 M*N*P... 多维向量。如果只写 M,则生成 M*M 矩阵;如果参数为 [M,N] 可以省略掉方括号。例如:
%注:上述语句生成的随机数所服从的参数为 (v1=3,v2=5) 的 F 分布
通过下面代码,可以生成大量随机数,查看大致的分布情况:
x=frnd(3,5,100000,1); hist(x,50);
从结果可以看出来, F分布集中在 x 正半轴的左侧,但是它在极端值处也很可能有一些取值。
7.trnd()
此函数生成服从 t 分布 (Student's t Distribution,这里 Student 不是学生的意思,而是 Cosset.W.S. 的笔名) 的随机数。t 分布有 1 个参数:自由度 v。基本语法
trnd(v,[M,N,P,...])
生成的随机数服从参数为 v 的t分布,这些随机数排列成 M*N*P... 多维向量。如果只写 M,则生成 M*M 矩阵;如果参数为 [M,N] 可以省略掉方括号。例如:
%注:上述语句生成的随机数所服从的参数为 (v=7) 的 t 分布
通过下面代码,可以生成大量随机数,查看大致的分布情况:
x=trnd(7,100000,1); hist(x,50);
可以发现t分布比标准正太分布要 “瘦”,不过随着自由度 v 的增大,t 分布会逐渐变胖,当自由度为正无穷时,它就变成标准正态分布了。
接下来的分布相对没有这么常用,同时这些函数的语法和前面函数语法相同,所以写得就简略一些。
8.betarnd()
此函数生成服从 Beta 分布的随机数。Beta 分布有两个参数分别是 A 和 B。
生成beta分布随机数的语法是:
betarnd(A,B,[M,N,P,...])
通过下面代码,可以生成大量随机数,查看大致的分布情况:
x=betarnd(3,5,100000,1); hist(x,50);
9.exprnd()
此函数生成服从指数分布的随机数。指数分布只有一个参数: mu。
生成指数分布随机数的语法是:
exprnd(mu,[M,N,P,...])
通过下面代码,可以生成大量随机数,查看大致的分布情况:
x=exprnd(0.5,100000,1); hist(x,50);
10.gamrnd()
生成服从 Gamma 分布的随机数。Gamma 分布有两个参数:A 和 B。
生成 Gamma 分布随机数的语法是:
gamrnd(A,B,[M,N,P,...])
通过下面代码,可以生成大量随机数,查看大致的分布情况:
x=gamrnd(3,5,100000,1); hist(x,50);
11.lognrnd()
生成服从对数正态分布的随机数。其有两个参数:mu 和 sigma,服从这个这样的随机数取对数后就服从均值为 mu,标准差为 sigma 的正态分布。
生成对数正态分布随机数的语法是:
lognrnd(mu,sigma,[M,N,P,...])
通过下面代码,可以生成大量随机数,查看大致的分布情况:
x=lognrnd(-1,1/1.2,100000,1); hist(x,50);
12.raylrnd()
生成服从瑞利(Rayleigh)分布的随机数。其分布有 1 个参数:B。
生成瑞利分布随机数的语法是:
raylrnd(B,[M,N,P,...])
通过下面代码,可以生成大量随机数,查看大致的分布情况:
x=raylrnd(2,100000,1); hist(x,50);
13.wblrnd()
生成服从威布尔(Weibull)分布的随机数。其分布有 2 个参数:scale 参数 A 和 shape 参数 B。
生成 Weibull 分布随机数的语法是:
wblrnd(A,B,[M,N,P,...])
还有非中心卡方分布(ncx2rnd),非中心F分布(ncfrnd),非中心t分布(nctrnd),括号中是生成服从这些分布的函数,具体用法用:help 函数名 的方法查找。
通过下面代码,可以生成大量随机数,查看大致的分布情况:
x=wblrnd(3,2,100000,1); hist(x,50);
c. 离散型分布随机数
离散分布的随机数可能的取值是离散的,一般是整数。
14.unidrnd()
此函数生成服从离散均匀分布的随机数。Unifrnd 是在某个区间内均匀选取实数(可为小数或整数),Unidrnd 是均匀选取整数随机数。离散均匀分布随机数有 1 个参数:n, 表示从 {1, 2, 3, ... N} 这 n 个整数中以相同的概率抽样。基本语法:
unidrnd(n,[M,N,P,...])
这些随机数排列成 M*N*P... 多维向量。如果只写 M,则生成 M*M 矩阵;如果参数为 [M,N] 可以省略掉方括号。例如:
%注:上述语句生成的随机数所服从的参数为 (10,0.3) 的二项分布
通过下面代码,可以生成大量随机数,查看大致的分布情况:
x=unidrnd(9,100000,1); hist(x,9);
可见,每个整数的取值可能性基本相同。
15.binornd()
此函数生成服从二项分布的随机数。二项分布有 2 个参数:n, p。考虑一个打靶的例子,每枪命中率为 p,共射击 N 枪,那么一共击中的次数就服从参数为(N,p)的二项分布。注意 p 要小于等于1 且非负,N 要为整数。基本语法:
binornd(n,p,[M,N,P,...])
生成的随机数服从参数为 (N,p) 的二项分布,这些随机数排列成 M*N*P... 多维向量。如果只写 M,则生成 M*M 矩阵;如果参数为 [M,N] 可以省略掉方括号。例如:
%注:上述语句生成的随机数所服从的参数为 (10,0.3) 的二项分布
通过下面代码,可以生成大量随机数,查看大致的分布情况:
x=binornd(10,0.45,100000,1); hist(x,11);
我们可以将此直方图解释为,假设每枪射击命中率为 0.45,每论射击 10 次,共进行 10 万轮,这个图就表示这 10 万轮每轮命中成绩可能的一种情况。
16.geornd()
此函数生成服从几何分布的随机数。几何分布的参数只有一个:p。几何分布的现实意义可以解释为,打靶命中率为 p,不断地打靶,直到第一次命中目标时没有击中次数之和。注意 p 是概率,所以要小于等于1且非负。基本语法:
geornd(p,[M,N,P,...])
这些随机数排列成 M*N*P... 多维向量。如果只写 M,则生成 M*M 矩阵;如果参数为 [M,N] 可以省略掉方括号。例如:
%注:上述语句生成的随机数所服从的参数为(0.4)的二项分布
通过下面代码,可以生成大量随机数,查看大致的分布情况:
x=geornd(0.4,100000,1); hist(x,50);
17.poissrnd()
此函数生成服从泊松 (Poisson) 分布的随机数。泊松分布的参数只有一个:lambda。此参数要大于零。基本语法:
geornd(p,[M,N,P,...])
这些随机数排列成 M*N*P... 多维向量。如果只写 M,则生成 M*M 矩阵;如果参数为 [M,N] 可以省略掉方括号。例如:
%注:上述语句生成的随机数所服从的参数为(2)的泊松分布
通过下面代码,可以生成大量随机数,查看大致的分布情况:
x=poissrnd(2,100000,1); hist(x,50);
其他离散分布还有超几何分布 (Hyper-geometric, 函数是 hygernd) 等,详细见 Matlab 帮助文档。
本博客文字大多来自博客 MATLAB随机数生成_MALSIS的博客-CSDN博客_matlab生成一个随机数
-
条形码、二维码扫描、生成Demo 完整源码
2012-08-05 12:58:49使用Google ZXing开源项目制作的条形码、二维码的生成、扫描Demo -
dimens文件生成器
2017-05-22 17:44:18dimens文件生成器 -
深度学习生成对抗网络(GAN)
2021-12-20 11:27:50生成对抗网络(Generative Adversarial Networks)是一种无监督深度学习模型,用来通过计算机生成数据,由Ian J. Goodfellow等人于2014年提出。模型通过框架中(至少)两个模块:生成模型(Generative Model)和判别模型...一、概述
生成对抗网络(Generative Adversarial Networks)是一种无监督深度学习模型,用来通过计算机生成数据,由Ian J. Goodfellow等人于2014年提出。模型通过框架中(至少)两个模块:生成模型(Generative Model)和判别模型(Discriminative Model)的互相博弈学习产生相当好的输出。生成对抗网络被认为是当前最具前景、最具活跃度的模型之一,目前主要应用于样本数据生成、图像生成、图像修复、图像转换、文本生成等方向。
GAN这种全新的技术在生成方向上带给了人工智能领域全新的突破。在之后的几年中生GAN成为深度学习领域中的研究热点,近几年与GAN有关的论文数量也急速上升,目前数量仍然在持续增加中。
GAN论文数量增长示意图
2018年,对抗式神经网络的思想被《麻省理工科技评论》评选为2018年“全球十大突破性技术”(10 Breakthrough Technologies)之一。 Yann LeCun(“深度学习三巨头”之一,纽约大学教授,前Facebook首席人工智能科学家)称赞生成对抗网络是“过去20年中深度学习领域最酷的思想”,而在国内被大家熟知的前百度首席科学家Andrew Ng也把生成对抗网络看作“深度学习领域中一项非常重大的进步”。
二、GAN基本原理
1. 构成
GAN由两个重要的部分构成:生成器(Generator,简写作G)和判别器(Discriminator,简写作D)。
- 生成器:通过机器生成数据,目的是尽可能“骗过”判别器,生成的数据记做G(z);
- 判别器:判断数据是真实数据还是「生成器」生成的数据,目的是尽可能找出「生成器」造的“假数据”。它的输入参数是x,x代表数据,输出D(x)代表x为真实数据的概率,如果为1,就代表100%是真实的数据,而输出为0,就代表不可能是真实的数据。
这样,G和D构成了一个动态对抗(或博弈过程),随着训练(对抗)的进行,G生成的数据越来越接近真实数据,D鉴别数据的水平越来越高。在理想的状态下,G可以生成足以“以假乱真”的数据;而对于D来说,它难以判定生成器生成的数据究竟是不是真实的,因此D(G(z)) = 0.5。训练完成后,我们得到了一个生成模型G,它可以用来生成以假乱真的数据。
GAN示意图
2. 训练过程
- 第一阶段:固定「判别器D」,训练「生成器G」。使用一个性能不错的判别器,G不断生成“假数据”,然后给这个D去判断。开始时候,G还很弱,所以很容易被判别出来。但随着训练不断进行,G技能不断提升,最终骗过了D。这个时候,D基本属于“瞎猜”的状态,判断是否为假数据的概率为50%。
- 第二阶段:固定「生成器G」,训练「判别器D」。当通过了第一阶段,继续训练G就没有意义了。这时候我们固定G,然后开始训练D。通过不断训练,D提高了自己的鉴别能力,最终他可以准确判断出假数据。
- 重复第一阶段、第二阶段。通过不断的循环,「生成器G」和「判别器D」的能力都越来越强。最终我们得到了一个效果非常好的「生成器G」,就可以用它来生成数据。
3. GAN的优缺点
1)优点
- 能更好建模数据分布(图像更锐利、清晰);
- 理论上,GANs 能训练任何一种生成器网络。其他的框架需要生成器网络有一些特定的函数形式,比如输出层是高斯的;
- 无需利用马尔科夫链反复采样,无需在学习过程中进行推断,没有复杂的变分下界,避开近似计算棘手的概率的难题。
2)缺点
- 模型难以收敛,不稳定。生成器和判别器之间需要很好的同步,但是在实际训练中很容易D收敛,G发散。D/G 的训练需要精心的设计。
- 模式缺失(Mode Collapse)问题。GANs的学习过程可能出现模式缺失,生成器开始退化,总是生成同样的样本点,无法继续学习。
4. GAN的应用
1)生成数据集
人工智能的训练是需要大量的数据集,可以通过GAN自动生成低成本的数据集。
2)人脸生成
3)物品生成
4)图像转换
5)图像修复
三、GAN的数学原理
1.GAN的数学推导
生成模型会从一个输入空间将数据映射到生成空间(即通过输入数据,在函数作用下生成输出数据),写成公式的形式是x=G(z)。通常,输入z会满足一个简单形式的随机分布(比如高斯分布或者均匀分布等),为了使得生成的数据分布能够尽可能地逼近真实数据分布,生成函数G会是一个神经网络的形式,通过神经网络可以模拟出各种完全不同的分布类型。
以下是生成对抗网络中的代价函数,以判别器D为例,代价函数写作J(D)J^{(D)}J(D),形式如下所示:
其中,E表示期望概率,x∼Pdatax \sim P_{data}x∼Pdata表示x满足PdataP_{data}Pdata分布。
对于生成器来说它与判别器是紧密相关的,我们可以把两者看作一个零和博弈,它们的代价综合应该是零,所以生成器的代价函数应满足如下等式:
J(G)=−J(D)J^{(G)} = -J^{(D)} J(G)=−J(D)
这样一来,我们可以设置一个价值函数V来表示J(G)J^{(G)}J(G)和J(D)J^{(D)}J(D):
我们现在把问题变成了需要寻找一个合适的V(θ(D),θ(G))V(θ^{(D)},θ^{(G)})V(θ(D),θ(G))使得J(G)J^{(G)}J(G)和J(D)J^{(D)}J(D)都尽可能小,也就是说对于判别器而言越大越V(θ(D),θ(G))V(θ^{(D)},θ^{(G)})V(θ(D),θ(G))好,而对于生成器来说则是越小越好V(θ(D),θ(G))V(θ^{(D)},θ^{(G)})V(θ(D),θ(G)),从而形成了两者之间的博弈关系。
在博弈论中,博弈双方的决策组合会形成一个纳什平衡点(Nash equilibrium),在这个博弈平衡点下博弈中的任何一方将无法通过自身的行为而增加自己的收益。在生成对抗网络中,我们要计算的纳什平衡点正是要寻找一个生成器G与判别器D使得各自的代价函数最小,从上面的推导中也可以得出我们希望找到一个V(θ(D),θ(G))V(θ^{(D)},θ^{(G)})V(θ(D),θ(G))对于生成器来说最小而对判别器来说最大,我们可以把它定义成一个寻找极大极小值的问题,公式如下所示:
我们可以用图形化的方法理解一下这个极大极小值的概念,一个很好的例子就是鞍点(saddle point),如下图所示,即在一个方向是函数的极大值点,而在另一个方向是函数的极小值点。
在上面公式的基础上,我们可以分别求出理想的判别器D*和生成器G*:
下面我们先来看一下如何求出理想的判别器,对于上述的D*,我们假定生成器G是固定的,令式子中的G(z)=x。推导如下:
我们现在的目标是希望寻找一个D使得V最大,我们希望对于积分中的项f(x)=pdata(x)logD(x)+pg(x)log(1−D(x))f(x)=p_{data}(x)logD(x)+p_g(x)log(1-D(x))f(x)=pdata(x)logD(x)+pg(x)log(1−D(x)),无论x取何值都能最大。其中,我们已知pdatap_datapdata是固定的,之前我们也假定生成器G固定,所以pgp_gpg也是固定的,所以我们可以很容易地求出D以使得f(x)最大。我们假设x固定,f(x)对D(x)求导等于零,下面是求解D(x)的推导。
可以看出它是一个范围在0到1的值,这也符合我们判别器的模式,理想的判别器在接收到真实数据时应该判断为1,而对于生成数据则应该判断为0,当生成数据分布与真实数据分布非常接近的时候,应该输出的结果为1/2.
找到了D*之后,我们再来推导一下生成器G*。现在先把D*(x)代入前面的积分式子中重新表示:
到了这一步,我们需要先介绍一个定义——Jensen–Shannon散度,我们这里简称JS散度。在概率统计中,JS散度也与前面提到的KL散度一样具备了测量两个概率分布相似程度的能力,它的计算方法基于KL散度,继承了KL散度的非负性等,但有一点重要的不同,JS散度具备了对称性。JS散度的公式如下,我们还是以P和Q作为例子,另外我们设定M=12(P+Q)M=\frac{1}{2}(P+Q)M=21(P+Q),KL为KL散度公式。
对于上面的MaxV(G,D)MaxV(G,D)MaxV(G,D),由于JS散度是非负的,当且仅当pdata=pgp_{data}=p_gpdata=pg的时候,上式可以取得全局最小值−log(4)-log(4)−log(4)。所以我们要求的最优生成器G*,正是要使得G*的分布pg=pdatap_g=p_{data}pg=pdata.
2. GAN的可视化理解
下面我们用一个可视化概率分布的例子来更深入地认识一下生成对抗网络。Ian Goodfellow的论中给出了这样一个GAN的可视化实现的例子:下图中的点线为真实数据分布,曲线为生成数据样本,生成对抗网络在这个例子中的目标在于,让曲线(也就是生成数据的分布)逐渐逼近点线(代表的真实数据分布)。
虚线为生成对抗网络中的判别器,它被赋予了初步区分真实数据与生成数据的能力,并对于它的划分性能加上一定的白噪声,使得模拟环境更为真实。输入域为z(图中下方的直线)在这个例子里默认为一个均匀分布的数据,生成域为x(图中上方的直线)为不均匀分布数据,通过生成函数x=G(z)形成一个映射关系,如图中的那些箭头所示,将均匀分布的数据映射成非均匀数据。
从a到d的四张图可以展现整个生成对抗网络的运作过程。在a图中,可以说是一种初始的状态,生成数据与真实数据还有比较大的差距,判别器具备初步划分是否为真实数据的能力,但是由于存在噪声,效果仍有缺陷。b图中,通过使用两类标签数据对于判别器的训练,判别器D开始逐渐向一个比较完善的方向收敛,最终呈现出图中的结果。当判别器逐渐完美后,我们开始迭代生成器G,如图c所示。通过判别器D的倒数梯度方向作为指导,我们让生成数据向真实数据的分布方向移动,让生成数据更容易被判别器判断为真实数据。在反复的一系列上述训练过程后,生成器与判别器会进入图d的最终状态,此时pgp_gpg会非常逼近甚至完全等于pdatap_{data}pdata,当达到理想的pg=pdatap_g=p_{data}pg=pdata的时候,D与G都已经无法再更进一步优化了,此时G生成的数据已经达到了我们期望的目的,能够完全模拟出真实数据的分布,而D在这个状态下已经无法分辨两种数据分布(因为它们完全相同),此时D(x)=12D(x)=\frac{1}{2}D(x)=21.
四、DCGAN
1. 概述
DCGAN的创始论文《Unsupervised Representation Learning with Deep Convolutional Generative Adversarial Networks》(基于深层卷积生成对抗网络的无监督表示学习)发表于2015年,文章在GAN的基础之上提出了全新的DCGAN架构,该网络在训练过程中状态稳定,并可以有效实现高质量的图片生成及相关的生成模型应用。由于其具有非常强的实用性,在它之后的大量GAN模型都是基于DCGAN进行的改良版本。为了使得GAN能够很好地适应于卷积神经网络架构,DCGAN提出了四点架构设计规则,分别是:
- 使用卷积层替代池化层。首先第一点是把传统卷积网络中的池化层全部去除,使用卷积层代替。对于判别器,我们使用步长卷积(strided convolution)来代替池化层;对于生成器,我们使用分数步长卷积(fractional-strided convolutions)来代替池化层。
- 去除全连接层。目前的研究趋势中我们会发现非常多的研究都在试图去除全连接层,常规的卷积神经网络往往会在卷积层后添加全连接层用以输出最终向量,但我们知道全连接层的缺点在于参数过多,当神经网络层数深了以后运算速度会变得非常慢,此外全连接层也会使得网络容易过度拟合。有研究使用了全局平均池化(global average pooling)来替代全连接层,可以使得模型更稳定,但也影响了收敛速度。论文中说的一种折中方案是将生成器的随机输入直接与卷积层特征输入进行连接,同样地对于判别器的输出层也是与卷积层的输出特征连接,具体的操作会在后面的框架结构介绍中说明。
- 使用批归一化(batch normalization)。由于深度学习的神经网络层数很多,每一层都会使得输出数据的分布发生变化,随着层数的增加网络的整体偏差会越来越大。批归一化的目标则是为了解决这一问题,通过对每一层的输入进行归一化处理,能够有效使得数据服从某个固定的数据分布。
- 使用恰当的激活函数。在DCGAN网络框架中,生成器和判别器使用了不同的激活函数来设计。生成器中使用ReLU函数,但对于输出层使用了Tanh激活函数,因为研究者们在实验中观察到使用有边界的激活函数可以让模型更快地进行学习,并能快速覆盖色彩空间。而在判别器中对所有层均使用LeakyReLU,在实际使用中尤其适用于高分辨率的图像判别模型。这些激活函数的选择是研究者在多次实验测试中得出的结论,可以有效使得DCGAN得到最优的结果。
2. 网络结构
下图是DCGAN生成器G的架构图,输入数据为100维的随机数据z,服从范围在[-1,1]的均匀分布,经过一系列分数步长卷积后,最后形成一幅64×64×3的RGB图片,与训练图片大小一致。
对于判别器D的架构,基本是生成器G的反向操作,如下图所示。输入层为64×64×3的图像数据,经过一系列卷积层降低数据的维度,最终输出的是一个二分类数据。
3. 训练细节
1)对于用于训练的图像数据样本,仅将数据缩放到[-1,1]的范围内,这个也是tanh的取值范围,并不做任何其他处理。
2)模型均采用Mini-Batch大小为128的批量随机梯度下降方法进行训练。权重的初始化使用满足均值为0、方差为0.02的高斯分布的随机变量。
3)对于激活函数LeakyReLU,其中Leak的部分设置斜率为0.2。
4)训练过程中使用Adam优化器进行超参数调优。学习率使用0.0002,动量β1取0.5,使得训练更加稳定。
五、实现DCGAN
1. 任务目标
实现DCGAN,并利用其合成卡通人物头像。
2. 数据集
样本内容:卡通人物头像
样本数量:51223个
3. 实验结果
为了加快训练速度,实际只采用了8903个样本进行训练,执行每20轮一次增量训练。实验结果如下:
- 1轮训练
- 5轮训练
- 10轮训练
- 20轮训练
- 40轮训练
- 60轮训练
六、其它GAN模型
1)文本生成图像:GAWWN
2)匹配数据图像转换:Pix2Pix
3)非匹配数据图像转换:CycleGAN,用于实现两个领域图片互转
4)多领域图像转换:StarGAN
七、参考资源
1. 在线视频
1)李宏毅GAN教程:https://www.ixigua.com/pseries/6783110584444387843/?logTag=cZwYY0OhI8vRiNppza2UW
2. 书籍
1)《生成对抗网络入门指南》,史丹青编著,机械工业出版社
-
“狗屁不通文章生成器”登顶GitHub热榜,分分钟写出万字形式主义大作
2019-11-13 18:40:00一、垃圾文字生成器介绍 最近在浏览GitHub的时候,发现了这样一个骨骼清奇的雷人项目,而且热度还特别高。 项目中文名:狗屁不通文章生成器 项目英文名:BullshitGenerator 根据作者的介绍,他是偶尔需要一些中文... -
动态图片生成方案
2022-03-07 00:50:26比如在起点读书小程序中,每本书都需要生成一个动态图片,包含:书名、作者、类别和当前页面小程序码,这几个内容都是会动态改变的。 那如何抽象化&高性能的实现这一类需求呢?下面我们一起来探讨动态图片的生成方案... -
AI实现艺术品自动生成?太牛了
2022-05-12 14:36:41作品下载 三、效果展示 四、总结 前言 前几日在网上学习NFT制作时,发现了一个NFT作品自动生成的网站wombo,原本以为是通过身体组件遍历组合生成新NFT作品,结果发现是通过提供关键词使AI自动生成作品。 AI都已经... -
SQL 中的生成列/计算列以及主流数据库实现
2020-02-04 13:40:33在 SQL 数据库中,生成列(Generated Column)是指由表中其他字段计算得到的列,因此也称为计算列(Computed Column)。 本文介绍各种主流数据库对于生成列/计算列的实现,包括 Oracle、MySQL、SQL Server、... -
vSphere6、vCenterServer6许可证生成器(打包下载)
2015-08-28 10:42:43连生成器现在都分期发放了... 好难找,整理一下发给大家咯 这两个对我是够用了,不够用的同学继续google吧. -
详解生成对抗网络(GAN)
2020-11-04 22:34:39详解生成对抗网络(GAN) 本篇博文从以下几个结构介绍GAN模型 概述 模型优化训练 GAN的一些经典变种 1 概述 GAN是由Ian Goodfellow于2014年首次提出,学习GAN的初衷,即生成不存在于真实世界的数据。类似于... -
python列表生成式与列表生成器的使用
2020-11-25 21:12:47列表生成式:会将所有的结果全部计算出来,把结果存放到内存中,如果列表中数据比较多,就会占用过多的内存空间,可能会导致MemoryError内存错误或者导致程序在运行时出现卡顿的情况列表生成器:会创建一个列表生成... -
Git生成生成公钥和私钥
2022-01-26 11:11:102、执行生成公钥和私钥的命令:ssh-keygen -t rsa 并按回车3下(为什么按三下,是因为有提示你是否需要设置密码,如果设置了每次使用Git都会用到密码,一般都是直接不写为空,直接回车就好了)。会在一个文件夹里面 -
QRCode二维码生成组件(珍藏版)
2014-01-18 15:58:14因为项目的需要,需要在网站中增加一个生成二维码分析网址的功能,在谷歌大幅度抽筋的情况下无奈使用百度。百度N多,找到一些项目,但是可用性不强。终于在codeplex上找到一个“神器”,这个“神器”可以很方便的... -
前有狗屁不通文章生成器 | 后有申论生成器
2021-12-16 09:41:58前有狗屁不通文章生成器,后有申论生成器! Github有趣的项目:Slscq 申论生成器 申论文章生成器,输入主题字数,输出随机拼凑的文章。 在线网址:https://lab.magiconch.com/slscq/ C++版本 json 库请使用:... -
Java生成唯一id的几种方式(已验证)
2020-10-22 16:34:09数据库方式比较简单,比如oracle可以用序列生成id,Mysql中的AUTO_INCREMENT等,这样可以生成唯一的ID,性能和稳定性依赖于数据库!如mysql主键递增: 2.系统时间戳 这种方式每秒最多一千个,如果是单体web系统集群... -
python之迭代器和生成器全解--包含实现原理及应用场景
2021-02-18 22:50:34在日常提升Python基本功的时候,可能会被Python的迭代器和生成器搞晕,之前在学习和使用时,本来for in 循环体和enumerate函数用的飞起,觉得自己已经彻底了解了Python的迭代特性,但接触了迭代器和生成器后,突然... -
ASP.NET 生成二维码(采用ThoughtWorks.QRCode和QrCode.Net两种方式)
2014-12-18 12:43:48最近做项目遇到生成二维码的问题,发现网上用的最多的是ThoughtWorks.QRCode和QrCode.Net两种方式,所以访问官网看着例子写了两个Demo,使用过程中发现两个都挺好用的,ThoughtWorks.QRCode的功能更多一些,但是dll... -
前端代码生成器
2021-11-20 09:27:03地址:CodeFun - UI 设计稿智能生成源代码 效果: 2.PxCook 介绍:高效易用的自动标注工具, 生成前端代码, 设计研发协作利器 地址:PxCook - 高效易用的自动标注工具,生成前端代码,设计研发协作利器 效果...