[GAN01]GAN原理介绍并使用Keras实现DCGAN基于Mnist数据集的图像生成

前言

打算开坑实现一系列GAN,并基于这些模型对GAN的原理进行深入理解与挖掘。

第一篇是DCGAN。

理论部分

GAN的原理在这里插入图片描述

从图中可以看到,GAN分为两部分,生成器和辨别器。

生成器与辨别器

生成器的目的是利用噪音生成以假乱真的图片,因此,其输入是无意义的噪音,输出是利用该噪音生成的图片。

辨别器的目的是区分出生成器生成的图片与真正的图片,因此,其输入是两种图片,输出是两种图片对应的种类(fake or real)。

生成器是如何利用噪音生成图片的?

我们希望生成的图片可以看作在空间中按照一定概率密度Pd(x)分布的高维张量。
注意这个概率分布不能简单的理解为X∈(长,宽,通道),y∈[0,1]的一个概率分布,我们学习到的是一种更为高维与复杂的分布,它至少包含了一部分像素之间的关系(因为用到了超过1*1的卷积核)。

如果用能够用概率函数Pg(x)拟合出这个高维分布,就能够利用噪音生成所需图片,至于如何拟合有两种思路。

一是自编码器(Auto Encoder)和变分编码器(VAE)的思路,个人认为这种思路的本质就是在做极大似然拟合,也就是说,通过采样,让样本点出现概率最大来调整参数,最终对真正分布进行拟合。李宏毅讲,因为只是根据pd(x)与pg(x)之间的距离进行调整,所以这种做法的问题是生成器比较死板,即使是距离相同的分布,可能实际效果是大不相同的。

二是对抗生成神经网络(GAN)的思路,我们实际训练两个模型:生成器G和判别器D。
在训练D的时候,我们将fake标注为0,real标注为1,损失函数采用二分类交叉熵函数,这样,如果D能够让损失降低,也就说明D能够正确地将fake和real区分开。

在训练G的时候,将fake标注为1,损失函数依然采用二分类交叉熵函数,如果G能够让损失降低,也就是让fake和real都被判断为real,说明G能够正确地用fake伪装real。
在这里插入图片描述

实验

DCGAN

DCGAN是第一个可用的GAN,他是在融合了前人的如下成果的基础上提出的
1.使用stride=2的卷积层替代pooling层,让网络自己学习下采样。
2.使用leaky relu替代relu,Relu如果一旦被激活为0,则会永远保持0,因为负数时的梯度永远也为0,leaky relu给了他一个recover的机会。
3.使用dropout和BN层。
4.使用反卷积做生成器的上采样工作,上采样的意思是将size较小的噪声转化为size较大的图片。

模型概览

  • class DCGAN():
    • self. D
    • self. G
    • self. DM #辨别器训练模型
    • self. AM #生成器训练模型

将DCGAN模型包装成一个类,这不仅是为了逻辑上的简洁性,更重要的是为了让DM和AM训练同一个辨别器(self.D)。
注意这里必须将D,M,DM和AM区分开,换句话说,四者都必须给出独立的接口,因为D在DM和AM中分别参与训练,G需要给出实验结果(fake图片),DM和AM需要分别训练。

辨别器

在这里插入图片描述

def discirminator(self):
        if self.D:
            return self.D
        self.D=Sequential()
        self.D.add(Conv2D(64,(5,5),strides=2,input_shape=(28,28,1),padding='same',\
              activation=LeakyReLU(alpha=0.2)))
        #self.D.add()
        self.D.add(Dropout(0.4))
        self.D.add(Conv2D(128,(5,5),strides=2,padding='same',activation=LeakyReLU(alpha=0.2)))
        self.D.add(Dropout(0.4))
        self.D.add(Conv2D(256,(5,5),strides=2,padding='same',activation=LeakyReLU(alpha=0.2)))
        self.D.add(Dropout(0.25))
        self.D.add(Conv2D(512,(5,5),strides=1,padding='same',activation=LeakyReLU(alpha=0.2)))
        self.D.add(Dropout(0.4))
        self.D.add(Flatten())
        self.D.add(Dense(1,activation='sigmoid'))
        return self.D

注意事项

1.生成器通过stride=2的卷积层而不是常规的pooling层将28*28多次下采样成4*4
2.每一层的激活函数选择leaky relu
3.激活函数之后加入dropout层

生成器

在这里插入图片描述

def generator(self):
        if self.G:
            return self.G
        self.G=Sequential()
        #使用UpSamping2D+Conv2D替代TransposedConv2D
        self.G.add(Dense(256*7*7,input_dim=100))
        self.G.add(BatchNormalization(momentum=0.9))
        self.G.add(Activation('relu'))
        self.G.add(Reshape((7,7,256)))
    
        self.G.add(UpSampling2D())
        self.G.add(Conv2DTranspose(128,5,padding='same'))
        self.G.add(BatchNormalization(momentum=0.9))
        self.G.add(Activation('relu'))
        
        self.G.add(UpSampling2D())
        self.G.add(Conv2DTranspose(64,5,padding='same'))
        self.G.add(BatchNormalization(momentum=0.9))
        self.G.add(Activation('relu'))
        self.G.add(Conv2DTranspose(32,5,padding='same'))
        self.G.add(BatchNormalization(momentum=0.9))
        self.G.add(Activation('relu'))
        self.G.add(Conv2DTranspose(1,5,padding='same'))
        self.G.add(Activation('sigmoid'))
        #G.summary()
        return self.G
注意事项

1.这里我采用了UpSampling层+Conv2DTranpose层做上采样,实际效果与UpSampling+Conv2D类似,因为真正在做上采样的是UpSamping层
2.每层上采样之后加入BN层

辨别器训练模型

def D_model(self):
        if self.DM:
            return self.DM
        self.DM=Sequential()
        self.DM.add(self.discirminator())
        self.DM.compile(loss='binary_crossentropy',optimizer=RMSprop(lr=0.0002,decay=6e-8),\
                  metrics=['accuracy'])
        return self.DM

生成器训练模型

def A_model(self):
        if self.AM:
            return self.AM
        self.AM=Sequential()
        self.AM.add(self.generator())
        self.AM.add(self.discirminator())
        self.AM.compile(loss='binary_crossentropy',optimizer=RMSprop(lr=0.0001,decay=3e-8),\
                  metrics=['accuracy'])
        return self.AM

生成器与辨别器连接成为生成对抗模型,本质是训练生成器,因此这里可以将辨别器的参数冻结。
但是因为GAN中辨别器一般处于强势,我在训练时没有冻结其参数,不失为一种削弱辨别器的方式。

训练

noisy=gauss_random
fake=G.predict(noisy)
real=mnist_random
X=concatcrate(fake,real)
Y=[0000.....11111]
DM.train(X,Y)
noisy=gauss_random
fake=G.predict(noisy)
Y=[1....1]
AM.train(X,Y)

训练思路已经说过了,CSDN突然贴不了代码,打一些伪代码在这,python代码的话可以去GitHub查阅。

结果

100回合

在这里插入图片描述

500回合

在这里插入图片描述

1000回合

在这里插入图片描述

感谢

Gan By Keras

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章