[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

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