第十八周:机器学习周报

目录

摘要

Absrtact

Unsupervised learning Deep Generative Model(无监督学习深度生成模型)

Generative Models(生成模型)

PixelRNN

Variational Auto Encoder(变分自编码器)

Auto-encoder(自编码器)

为什么要用VAE?

Conditional VAE

Problems of VAE(VAE存在的问题)

GAN(生成式对抗网络)

GAN - Discriminator

GAN - Generator

 GAN - Toy Example

GAN生成手写数字Demo

总结


摘要

上周学习了GAN模型,它其实属于生成模型的一种,这周对无监督学习的深度生成模型进行深入学习,生成模型比较有名的有PixelRNN、Variational Autoencoder(VAE)、Generative Adversarial Network(GAN)这三种模型。首先学习了PixelRNN如何根据已有的输入得到机器自主生成的结果。其次了解到VAE的产生是为了弥补Auto-encoder存在的不足,通过直观和科学的解释,分析VAE为何可以对niose范围采样的数据生成更好的图片。分析VAE的不足之处,也就是GAN产生原因,最后学习GAN中生成器和判别器的演化,并通过生成手写数字的例子熟悉GAN模型的搭建以及训练过程。

Absrtact

Last week ,we learned about the GAN mode,which is actually belongs to a type of generative model. This week, we delve deeper into Unsupervised learning Deep Generative Model. The well-known generative models include PixelRNN, Variational Autoencoder (VAE), and Generative Adversarial Network (GAN). Firstly, we learned how PixelRNN can obtain machine generated results based on existing inputs. Secondly, we understand that the generation of VAE is to compensate for the shortcomings of Auto encoder. Through intuitive and scientific explanations, we analyze why VAE can generate better images from data sampled within the niose range. Analyze the shortcomings of VAE, which is the cause of GAN generation, and finally learn the evolution of generators and discriminators in GAN. Familiarize yourself with the construction and training process of GAN models by generating examples of handwritten numbers.

Unsupervised learning Deep Generative Model(无监督学习深度生成模型)


Generative Models(生成模型)

生成模型就是让机器自主进行学习,例如在图像上,我们现有的模型可以机器对图像进行分类,例如分类猫和狗的照片,那如果让机器自己画出一张猫的图片,那就是属于创造吗,也就是Generative Models要做的事情。

850ce4c217b94b9d80747a141f263099.png

比较有名的Generative Models有下面几种:

PixelRNN
Variational Autoencoder(VAE)
Generative Adversarial Network(GAN)

PixelRNN

Pixel RNN不需要label就可以 train,根据前面的pixel,输出下一个pixel。假如今天的目标是让machine自己画一张解析度为3×3,有9个pixel的图形。假设先随机给这个image一个橙色的pixel,将这个pixel作为NN的输入,得到的pixel,(颜色RGB是三种颜色,因此一个pixel就是一个三维的向量)将它转“换为颜色涂上去。接下来就把这两个颜色一起作为NN的输入,然后得到第三个pixel,直到得到9个pixel。machine看到前面的颜色就可以得到后面应该涂的颜色。

dbcb348ca5af4501991da37d10728a66.png

在不同general image方法里面,Pixel RNN是产生的图是最清晰的,这是一个非监督模型,例如给出一张狗狗照片的上半部分,让machine生成下半部分。

7d673005dcf44a749e60fbe1a39edbea.png

这个方法不仅可以用在image上,还可以用在语音上

Variational Auto Encoder(变分自编码器)

Auto-encoder(自编码器)

首先回顾一下Auto-encoder,将一个图片作为输入,先经过NN Encoder进行编码,将得到的code输入NN Decoder进行解码得到一个图片的输出,我们希望输入和输出越接近越好。

627c8ac3c0b142c388b51b0c12a1a624.png

 如果用Auto Encode做生成任务,则不需要Encoder进行编码,随机产生一个向量作为code输入到NN Decoder产生一张图片。但这种方式生成的图片都不太好,解决方法就是采用VAE。

daf348b520b04c62999385b9497248a5.png

VAE模型与Auto-encoder的区别在于,现在NN Encoder会输出两组向量eq?%5Cbegin%7Bbmatrix%7D%20m_%7B1%7D%5C%5C%20m_%7B2%7D%5C%5C%20m_%7B3%7D%20%5Cend%7Bbmatrix%7Deq?%5Cbegin%7Bbmatrix%7D%20%5Csigma_%7B1%7D%5C%5C%20%5Csigma_%7B2%7D%5C%5C%20%5Csigma_%7B3%7D%20%5Cend%7Bbmatrix%7D,然后再从normal distribution中sample生成一个向量eq?%5Cbegin%7Bbmatrix%7D%20e_%7B1%7D%5C%5C%20e_%7B2%7D%5C%5C%20e_%7B3%7D%20%5Cend%7Bbmatrix%7D,将eq?%5Cbegin%7Bbmatrix%7D%20%5Csigma_%7B1%7D%5C%5C%20%5Csigma_%7B2%7D%5C%5C%20%5Csigma_%7B3%7D%20%5Cend%7Bbmatrix%7D取exponential,然后再乘上向量eq?%5Cbegin%7Bbmatrix%7D%20e_%7B1%7D%5C%5C%20e_%7B2%7D%5C%5C%20e_%7B3%7D%20%5Cend%7Bbmatrix%7D,最后加上eq?%5Cbegin%7Bbmatrix%7D%20m_%7B1%7D%5C%5C%20m_%7B2%7D%5C%5C%20m_%7B3%7D%20%5Cend%7Bbmatrix%7D,得到的向量eq?%5Cbegin%7Bbmatrix%7D%20c_%7B1%7D%5C%5C%20c_%7B2%7D%5C%5Cc_%7B3%7D%20%5Cend%7Bbmatrix%7D就是code,将其放入NN Decoder得到输出。除了输入输出的误差要最小化之外还要满足右下角的目标。

8adfd511f3bf43bebdd77f91ed285177.png

为什么要用VAE?

直观解释

有个直观的例子说明,当输入一个满月的图片到auto-encoder模型,我们希望得到一个同样的满月图片。同理,当输入一个半月的图片,我们希望得到一个半月的图片。如果在满月和半月之间sample一个code,我们会希望得到一个介于满月和半月两者之间的图像,但实际输出往往不是这样。

而在使用VAE的时候,当输入一个满月图片,在code上会有一个noise,即加上一个范围,意味着在noise的范围内得到的图片都是满月,同理可得,输入一个半月的图片,可以在一个范围内得到半月的图片。那这个时候满月和半月的noise范围会有重叠,在重叠的code那个点,使用VAE的时候就会minimize它的mean square error,得到一张介于满月和半月之间的的图片。

6007bc737cd4451683baaecf082c5e33.png

总结:从code的空间上sample一个code,在产生iamge的时候,VAE比Auto-encoder可以产生更好的理想结果。

eq?%5Cbegin%7Bbmatrix%7D%20m_%7B1%7D%5C%5C%20m_%7B2%7D%5C%5C%20m_%7B3%7D%20%5Cend%7Bbmatrix%7D代表原来的code

eq?%5Cbegin%7Bbmatrix%7D%20c_%7B1%7D%5C%5C%20c_%7B2%7D%5C%5Cc_%7B3%7D%20%5Cend%7Bbmatrix%7D代表加上noise之后的code

eq?%5Cbegin%7Bbmatrix%7D%20%5Csigma_%7B1%7D%5C%5C%20%5Csigma_%7B2%7D%5C%5C%20%5Csigma_%7B3%7D%20%5Cend%7Bbmatrix%7D代表noise的方差,由NN Encoder自主学习得到。

eq?%5Cbegin%7Bbmatrix%7D%20e_%7B1%7D%5C%5C%20e_%7B2%7D%5C%5C%20e_%7B3%7D%20%5Cend%7Bbmatrix%7D是常量,但是它决定noise的大小

右下角这个公式是对方差eq?%5Cbegin%7Bbmatrix%7D%20%5Csigma_%7B1%7D%5C%5C%20%5Csigma_%7B2%7D%5C%5C%20%5Csigma_%7B3%7D%20%5Cend%7Bbmatrix%7D加一些限制,为了确保这个方差是正的,所以加上了exp。但是仅仅是这样是不够的,因为这个方差是自己学的,这样模型会让学习到的方差都是0来得到最小的reconstruction error,那就回到了原来的Auto-encoder。因此需要对这个方差作出限制,防止它学习到很小的方差。

afd6d9dab09b4bec981f4b3c67fada42.png

这个公式里面eq?exp%28%5Csigma%20_%7Bi%7D%29用蓝色表示,eq?%281+%5Csigma%20_%7Bi%7D%29用红色表示,eq?exp%28%5Csigma%20_%7Bi%7D%29-%281+%5Csigma%20_%7Bi%7D%29用绿色表示,将蓝色的线减去红色的线得到的是绿色的那条线,这条线的最低点在eq?%5Csigma%20%3D0的地方,而eq?%5Csigma%20%3D0eq?exp%280%29%3D1,意味着它的方差就是1,eq?%5Csigma%20%3D0的时候loss最低,也就是方差等于1的时候,loss最低,因此machine就不会让方差为0,或者是太小。最后的eq?%28m_%7Bi%7D%29%5E%7B2%7D是L2正则化,让结果比较sparse。

科学解释

上面的是直观的解释,那么更正式的解释如下:

假设要machine做的事情是generate宝可梦的图,宝可梦的图可以当作高维空间的一个点,(图中用一维空间描述),其实要做的事情就是估计高维空间上面的几率分布p(x)(x是一个向量)。可以根据几率的值sample一张象宝可梦的图。因此在是宝可梦图片的地方,p(x)的值应该是大的,也就是几率是大的。

9bdf8f06161a480bac5d333a6b4fd7e6.png

那怎么估计一个probability distribution(P(x))呢?就需要用到Gaussian Mixture Model

Gaussian Mixture Model(高斯混合模型)

下图中黑色的线是由多个高斯分布(蓝色的线)通过不同的weight叠合起来得到的分布,只要数量多就可以产生一个很复杂的高斯分布。每个高斯分布都会有对应的权重,需要根据weight决定从哪个高斯分布sample data,来组成Gaussian Mixture Model。于是这个决定的过程可以看做是一个关于m个样本的采样,从第m个高斯采样的概率是eq?P%28m%29,找到指定的高斯以后,再根据这个高斯的参数eq?%28%5Cmu%20%5E%7Bm%7D%2C%5Csum%20%5E%7Bm%7D%29进行采样。

1790153304ab4a178e5af886c399afad.png

怎么得到这个P(x)呢,通过下面的公式来计算。

ae9729a0ead646eaadc44fc3aa71ba37.png

m=0,1……m代表第几个高斯分布。

eq?P%28m%29是选择第m个高斯分布的几率,也就是组成混合高斯的每一个小高斯的权重。

eq?P%28x%7Cm%29是从第m个高斯分布选取数据x的概率。

Gaussian Mixture Model有种种问题,例如你要决定mixture的数目。在确定mixture的数目之后,根据拥有的data、x,就可以很容易的估计这些高斯分布和这些分布对应的weight、mean和variance,用EM algorithm就可以解决了。現在每一个x都是从某一个 mixture 被 sample 出來的,这件事情就类似于在做 classification,每一个 x,它都来自于一个某个分类,而用某一个分类来表示是不够准确的,正确的做法是用一个分布来表示x,也就是说x可以表示为:有多少的几率从第a分布采样出来,有多少几率从b分布采样出来。因此回到VAE,VAE就可以看做是GMM中x的分布表示。

f223c71305dc4cb8bbdbaf18845b8e89.png

做法就是,首先从一个normal distribution随机sample一个z,z代表的是normal distribution的一个向量,向量z的每一维代表某种attribute,代表现在要sample的那个东西的某种特质。有了z之后,我们可以决定z对应的参数eq?%28%5Cmu%20%2C%5Csum%20%29,假设mean和方差都来自一个函数,这个函数就可以是neural network,将z作为NN的输入就可以得到对应的mean和方差。

p(x)的公式如下所示,p(z)就是抽取z的函数,eq?P%28x%7Cz%29 就是从z的某一个高斯里面来抽取x的概率。

ddfada3eece442bbb11b409bf7bac785.png

注意这里是积分,因为z是连续的。它和上面离散的GMM不一样了,刚才的GMM如果由10个高斯分布组成,那么对应的参数eq?%28%5Cmu%20%2C%5Csum%20%29也就有10组,是可以定下来的。这里的z表示连续的分布,也就意味着有无穷多个高斯分布,无穷多组参数eq?%28%5Cmu%20%2C%5Csum%20%29,因此,这里我们用一个函数表示z所对应的高斯分布参数,写成:eq?%5Cmu%20%28z%29%2C%5Csigma%20%28z%29
另外z不一定是从normal distribution中sample的,即使z是从简单的normal distribution得到的,P(x)也可以很复杂。

最大似然求解

根据上面公式,可知P(x)是一个简单的正态分布,而p(x|z)是eq?N%28%5Cmu%20%28z%29%2C%5Csigma%20%28z%29%29的分布,只要知道z,就可以决定x是从什么样的mean和方差的高斯分布中产生的,mean和方差的函数eq?%5Cmu%20%28z%29%5Csigma%20%28z%29就是要去估测的,而eq?%5Cmu%20%28z%29%5Csigma%20%28z%29是由一个neural network产生,

现在我们手上有一组观测变量x,希望找到一组函数eq?%5Cmu%20%28z%29%5Csigma%20%28z%29来表达,使产生的eq?%5Cmu%20%28z%29%5Csigma%20%28z%29,可以使得使得x从P(x)分布中取出来的概率最大。用最大似然的思想写出来的损失函数为:

eq?L%3D%20%5Csum_%7Bx%7D%5E%7B%7DlogP%28x%29

8e30520ca8224d38970ad486af2f1657.png

这里需要另一个分布eq?q%28z%7Cx%29,它与上面的NN相反,它是输入x,得到对应的z的mean和方差,上面的NN就是VAE中的Decoder,下面的NN就是VAE里面的Encoder。

b65519f7c43240ce9aa40d02f93c45ab.png

69dc83d159b0451f9996b64792a26098.png原本我们只是找eq?P%28x%7Cz%29这一项来maxmize eq?L_%7Bb%7D,现在还需要找到eq?q%28z%7Cx%29,同时找到这两项去maxmize eq?L_%7Bb%7D。因为要找的likelihoodeq?L%3D%20%5Csum_%7Bx%7D%5E%7B%7DlogP%28x%29eq?L_%7Bb%7D的upper bound,eq?logP%28x%29%3DL_%7Bb%7D+KL,如果只通过eq?P%28x%7Cz%29这一项来maxmize eq?L_%7Bb%7D的话,与KL没关系,因此KL的值不会发生变化,而当eq?L_%7Bb%7D增大的时候有可能会增加likelihood eq?logP%28x%29。而eq?q%28z%7Cx%29这一项与eq?logP%28x%29没有任何关系,但与eq?L_%7Bb%7D和KL 有关,因此通过eq?q%28z%7Cx%29去maxmize eq?L_%7Bb%7Deq?logP%28x%29的值是不会发生变化的。

如果固定住eq?P%28x%7Cz%29,只通过eq?q%28z%7Cx%29这一项来maxmize eq?L_%7Bb%7D,会让eq?L_%7Bb%7Deq?logP%28x%29越来越接近。当eq?q%28z%7Cx%29eq?P%28x%7Cz%29完全一样的时候,KL会为0,但因为eq?logP%28x%29%3E%3DL_%7Bb%7D,如果一直maxmize eq?L_%7Bb%7D,那likelihood eq?logP%28x%29也一定会上升。

a8eb2680fd414132805481bb294ac948.png

由变形后的公式eq?L_%7Bb%7D%5Cgeq%20%5Cint_%7Bz%7D%5E%7B%7Dq%28z%7Cx%29logP%28x%7Cz%29dz-KL%28q%28z%7Cx%29%7C%7CP%28z%29%29可知,要maximizeeq?L_%7Bb%7D,就是Maxmize eq?%5Cint%20q%28z%7Cx%29logP%28x%7Cz%29dz,Minimize eq?KL%28q%28z%7Cx%29%7C%7CP%28z%29%29,Minimize是通过调节而q对应的一个neural network的输出,让它产生的distributioneq?q%28z%7Cx%29可以和一个normal distribution越接近越好。

2d0d5430643c4986bcd56acbb87ed745.png

 Maxmize这一项可以当作是有一个eq?logP%28x%7Cz%29,它用eq?q%28z%7Cx%29来做weight sum,因此可以写成是eq?logP%28x%7Cz%29根据eq?q%28z%7Cx%29的期望值,意思就是给我们一个x,计算eq?q%28z%7Cx%29这个几率分布,然后从eq?q%28z%7Cx%29去sample data让eq?logP%28x%7Cz%29的几率越大越好。这个就是Auto-encoder一直在做的事情。怎么从eq?q%28z%7Cx%29去sample data呢?根据放入NN的x产生一个mean和方差,然后根据eq?%5Cmu%20%5E%7B%27%7D%28x%29eq?%5Csigma%20%5E%7B%27%7D%28x%29

就可以sample出一个z,maxmize根据z产生x的几率,而这个几率是将z丢入另一个NN产生的eq?%5Cmu%28x%29eq?%5Csigma%20%5Cmu%28x%29,也就是让eq?%5Cmu%28x%29eq?%5Csigma%28x%29最大化,如果只考虑eq?%5Cmu%28x%29这一项的话,因为eq?%5Cmu%28x%29是一个高斯分布,那么在等于mean的地方几率是最大的,即eq?%5Cmu%28x%29%3Dx让输入和输出越接近越好。

34067e30963245caa7c16c518612889d.png

 这两项合起来就是VAE的loss function

Conditional VAE

它可以做的事情有产生手写的数字,给它一个digit,它可以抽出特性例如手写数字的粗细等,生成具有同样特性的图片。

242916335a374251805226404dcf28fb.png

Problems of VAE(VAE存在的问题)

VAE主要的问题是它从来没有去真的学怎么产生一张看起来是真正的图片,这也是为什么后面产生GAN。它想要产生一张image跟data base里面某张image越接近越好,但它不知道在评估相似度的时候,我们是用mean square error(均方误差)等。因此当Decoder的output的与data base的图片只相差一个piexl,但是这个piexl在不同的位置,给人直观上的差别是不一样的,例如图中的两个位置,左边的看起来很真实,但右边的很像生成的图片,但是他们都只与目标图片相差一个piexl,对于人来说,这两个图片相差很大,但是对于VAE来说,他们是一样的好坏。VAE从来没有想过产生以假乱真的图片,唯一做的就是模仿,也就是说它产生的图片其实就是data base里面image的线性组合得到的,从来没有想过产生新的图片。

73c80131ba784cfbacb5c084f4f3bb3f.png

GAN(生成式对抗网络)

而在GAN里面,Generator从来没有见过真正的image长什么样子,Discriminator见过真正的image长什么样子,它会比较与Generator生成的图片的不同,因此Generator产生的iamge是data base里面从来没有见过的,这才像machine要做的事情。

GAN - Discriminator

Generator和Discriminator其实都是一个network,下图中的Generator v1就是VAE的Decoder,从一个分布随机产生一个向量输入到里面,产生图片。Discriminator就是就是根据输入的图片,来输出0/1,通过sigmoid这样激活函数这样。输入的图片,真正的图片为1,Generator 产生的图片标为0,来训练这个Discriminator来更新参数。这个是Discriminator的演化aee020e8a8a6464aaf12123269a31ab6.png

GAN - Generator

而在Generator 的演化中,Generator 和Discriminator可以合成一个network,将随机的一个vector作为network的输入,输入到Generator ,将生成的图片再输入到Discriminator。我们想让这个vector产生的图片通过Discriminator得到的数值是1。因为整个是一个network,因此想要得到的输出为1其实是一件很简单的事情,通过gradient descent进行更新参数就行,但需要注意的是,在调整参数的时候,只能调整,也就是只能计算Generator 的参数network的output的gradient,然后更新Generator 的参数。如果不固定Generator的参数一起训练,那只要discriminator的w为0,b为1就好。

8f7849767ee141b4be796cf47c3425f7.png

 GAN - Toy Example

这个是GAN的原始paper的Toy Example。在里面z是一维的东西(从normal distribution里面sample出来的),作为Decoder的input,丢在Generator的network里面会产生另外一个一维的东西x。不同的z可以得到不同的x,x的分布就是图中绿色的分布,黑色的点代表真实data的分布,我们希望那个绿色的点的分布和黑色的点的分布越接近越好。

0c1f78621e8a420d9efa44a02171ff5a.png

按照gan的概念,就是把绿色的点和黑色的真实的点放进Discriminator里面,得到一个数值,这个数值代表输入的x是来自真实data的几率和是生成图片的几率,真的为1假的为0。然后会调整参数,那个蓝色的线就是x通过Discriminator得到的对应output,Generator会根据Generator的判断进一步训练,当左边的Discriminator得分比较高的时候,Generator产生的结果就会向左边靠拢,达到骗过Discriminator的目的,而Discriminator又会根据新的输入图片来更新那个蓝色的线。这个过程会反复进行下去,直到生成的分布与真实的分布重合,Discriminator无法再分辨。

0d7fd6651f5a476e96704ebd19fbbc24.png 注意:如果移动太多,会导致更差的结果,因此移动的距离很难把握,所以GAN是比较难train的,需要小心调参数。

Gan的训练最大的问题就是你不知道Discriminator是不是对的。假设Discriminator得到一个很好的结果,那可能Generator太废了。假设Discriminator得到一个很差的结果,可能Discriminator太差了。

GAN生成手写数字Demo

①获取torch自带的MNIST数据集

Resize(28):因为图片为28×28的,固定大小为28。
ToTensor():将image转化为tensor,可以转化为0-1之间的浮点数。
Normalize():normalize里面的参数为均值和方差都设置为0.5

因此得到的每个样本size为1×28×28,1为通道数。

#MNIST数据集获取,样本数约为六万个
dataset = torchvision.datasets.MNIST("mnist_data", train=True, download=True,
                                     transform=torchvision.transforms.Compose(
                                         [
                                             torchvision.transforms.Resize(28),
                                             torchvision.transforms.ToTensor(),
                                             torchvision.transforms.Normalize([0.5], [0.5]),
                                         ]
                                                                             )
                                     )

之后通过DataLoader方法加载数据集,代码如下:

dataloader = torch.utils.data.DataLoader(dataset, batch_size=batch_size, shuffle=True, drop_last=True)

准备好数据就可以构建模型,GAN模型包含生成器(Generator)和判别器(Discriminator),模型搭建均采用的全连接层,

②生成器模型搭建:

生成器是一个只有一个隐藏层的神经网络,将维度不断扩大,一直到1023,最后nn.Linear(1024, np.prod(image_size, dtype=np.int32))要把1024降维到image size,将特征空间映射到图片的大小,prod()为连乘,得到1×28×28。映射完之后加一个Sigmoid激活函数,
在隐藏层中使用 ReLU激活函数,与将任何负输入映射
到0的常ReLU函数不同, 在输出层使用sigmoid激活函数, 输出更为典型的0到1范围内的值,它有助于生成更清断的图像。

输入为z,z的形式为[batchsize,1,28,28]

class Generator(nn.Module):

    def __init__(self):
        super(Generator, self).__init__()

        self.model = nn.Sequential(
            nn.Linear(latent_dim, 128), #全连接层
            torch.nn.BatchNorm1d(128),
            torch.nn.RELU(),

            nn.Linear(128, 256),
            torch.nn.BatchNorm1d(256),
            torch.nn.RELU(),
            nn.Linear(256, 512),
            torch.nn.BatchNorm1d(512),
            torch.nn.RELU(),
            nn.Linear(512, 1024),
            torch.nn.BatchNorm1d(1024),
            torch.nn.RELU(),
            nn.Linear(1024, np.prod(image_size, dtype=np.int32)),
            nn.Sigmoid(),
        )

    def forward(self, z):
        # shape of z: [batchsize, latent_dim]

        output = self.model(z)
        image = output.reshape(z.shape[0], *image_size)

        return image

③​ 判别器模型搭建:

判别器接收到的是一张28×28×1的图像,并输出表示输入是否被视为真而不是假的概率。为简单起见,我们构造的判别器网络看起来与生成器几乎相同,相反的是,判别器网络是一步一步降低我们的维度,刚开始设置为大维度,然后依次降低它的维度,最后做一个逻辑回归回到一维,得到一个Sigmoid的概率值。为了将图片送入模型,需要reshape一下,image.reshape(image.shape[0], -1)将imag的第零个维度作为第一维,其他的维度一起作为第二维,将image重塑为一个二维的数据。

class Discriminator(nn.Module):#判断图片是真正的图片还是生成的

    def __init__(self):
        super(Discriminator, self).__init__()

        self.model = nn.Sequential(
            nn.Linear(np.prod(image_size, dtype=np.int32), 512),
            torch.nn.RELU(),
            nn.Linear(512, 256),
            torch.nn.RELU(),
            nn.Linear(256, 128),
            torch.nn.RELU(),
            nn.Linear(128, 64),
            torch.nn.RELU(),
            nn.Linear(64, 32),
            torch.nn.RELU(),
            nn.Linear(32, 1),
            nn.Sigmoid(),
        )

    def forward(self, image):
        # shape of image: [batchsize, 1, 28, 28]

        prob = self.model(image.reshape(image.shape[0], -1))

        return prob

④模型搭建好后,我们会对损失函数、优化器等参数进行设置,需要两个Adam优化器,分别对生成器的参数和判别器的参数进行优化,需要用到它们的参数,所以对生成器模型和判别器模型都要实例化。这里采用的是BCELOSS损失函数。

g_optimizer = torch.optim.Adam(generator.parameters(), lr=0.0003, betas=(0.4, 0.8), weight_decay=0.0001)
d_optimizer = torch.optim.Adam(discriminator.parameters(), lr=0.0003, betas=(0.4, 0.8), weight_decay=0.0001)
loss_fn = nn.BCELoss()

⑤训练GAN网络

num_epoch 迭代次数设置为 200,batch_size批次数设置为32。

训练为两个循环,将for循环放在每个需要遍历训练数据集的epoch上,在这个for循环中是另一个嵌套的for循环,它遍历每批样本enumrate,其中一个批次具有指定的batch大小样本数。

第一步:随机生成一个服从正态分布的

第二步:将z放入生成器模型得到一个预测的照片

第三步:定义一个生成器loss,再将得到的预测图片放入辨别器模型得到一个概率,然后同目标target一起放入,(因为这里是在训练优化生成器,希望判别器全部预测为真实的图片所以target应该全部设置为1的状态)就会得到一个g_loss,再通过g_loss.backward()计算它的后降梯度,最后通过g_optimizer.step()更新generator的参数。

第四步:对判别器进行优化,优化有两个部分,第一部分将真实的图片送入判别器进行优化,它的标签应改为torch.ones,希望把真实的照片分类成1,第二部分将生成的预测图片送入判别器,它的标签应改为torch.zero,希望判别器把生成的图片分类为0。由于d_loss不需要对生成器部分计算梯度,因此在pred_image这一项加上detach()隔离出去。

num_epoch = 200
for epoch in range(num_epoch):
    for i, mini_batch in enumerate(dataloader):
        gt_images, _ = mini_batch


        z = torch.randn(batch_size, latent_dim)


        pred_images = generator(z)
        g_optimizer.zero_grad()

      
        g_loss = loss_fn(discriminator(pred_images), labels_one)

        g_loss.backward()
        g_optimizer.step()

        d_optimizer.zero_grad()

        real_loss = loss_fn(discriminator(gt_images), labels_one)
        fake_loss = loss_fn(discriminator(pred_images.detach()), labels_zero)
        d_loss = (real_loss + fake_loss)

        # 观察real_loss与fake_loss,同时下降同时达到最小值,并且差不多大,说明D已经稳定了

        d_loss.backward()
        d_optimizer.step()

f0a8322ee3e240d594c9e6cf677740a1.png

总结

在Auto-encoder中,可以将输入的图像进行编码再解码恢复图像,让输入与输出越接近越好,但VAE可以将这些图片的编码向量存起来,通过这些编码向量来重构产生新的图像。可以对编码器添加约束,强迫它产生服从单位高斯分布的潜在变量。因此产生新的图片也变得容易,只要从单位高斯分布中进行采样,然后把它传给解码器就可以了。而VAE的一个劣势就是没有使用对抗网络,它永远只是在模仿,并没有生成真正的图像,所以会更趋向于产生模糊的图片,因此才有了GAN的产生,它可以想办法生成“骗过”辨别器的图像。比较VAE与GAN的效果,我们可以得到以下两点:1、GAN生成的效果要优于VAE,2、GAN比VAE要难于训练

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值