生成對抗網絡——使用Pytorch搭建DCGAN

Introduction

最近幾年,人們對人工智能和大數據的熱情達到了膨脹,現在技術達到了瓶頸,但加載到新的產品裏面應用還有很大的發展空間。不知道各位最近看過愛情公寓5電視劇裏面的小黑做的高科技嗎——平均臉。對,就是平均臉,利用大量地人們所謂人的“平均臉”數據分析,獲取數據特徵,進行提取融合,然後再生成一張平均臉。最後,我們通過了大量的數據合成了一張現階段的平均臉了,那麼我們又怎麼樣來達到電視劇那種效果呢?
首先,我們的目標是將生成的平均臉和你想要的平均臉進行融合,具體需要我們將人臉五官對齊,
通過對圖像進行預處理,大小格式相同,檢測到人臉68個關鍵點,通過人臉特徵矩陣,給定算法,
進行五官融合,最終達到所期待的效果是不是突然之間覺得理論上很簡單,沒錯,理論上就這麼簡單,那理論上的使用的方面是什麼呢?那就是今天我要講解的一個知識點——DCGAN.
在這裏插入圖片描述

DCGAN

何爲DCGAN?DCGAN的全文是Deep Convolution Generative Adversarial Networks。對應的中文就是:深度卷積生成對抗網絡——一個GAN和卷積網絡的結合,從而極大地提升了原始GAN訓練的穩定性以及生成結果質量。原論文地址爲:點擊這裏

DCGAN主要是在網絡架構上改進了原始GAN,DCGAN的生成器與判別器都利用CNN架構替換了原始GAN的全連接網絡,主要改進之處有如下幾個方面:
1、DCGAN的生成器和判別器都捨棄了CNN的池化層,判別器保留CNN的整體架構,生成器則是將卷積層替換成了反捲積層(fractional-strided convolution)或者叫轉置卷積層(Convolution Transpose)。

2、在判別器和生成器中在每一層之後都使用了Batch Normalization(BN)層,有助於處理初始化不良導致的訓練問題,加速模型訓練,提升了訓練的穩定性。

3、利用1*1卷積層替換到所有的全連接層。

4、在生成器中除輸出層使用Tanh(Sigmoid)激活函數,其餘層全部使用ReLu激活函數。

5、在判別器所有層都使用LeakyReLU激活函數,防止梯度稀疏。
如下圖所示:生成網絡的結構圖示意
在這裏插入圖片描述

for example

Defining a generator network(Here, the code of a big guy is quoted)

class Generator(nn.Module):
    def __init__(self, ngpu):
        super(Generator, self).__init__()
        self.ngpu = ngpu
        self.main = nn.Sequential(
            # input is Z, going into a convolution
            nn.ConvTranspose2d(     nz, ngf * 8, 4, 1, 0, bias=False),
            nn.BatchNorm2d(ngf * 8),
            nn.ReLU(True),
            # state size. (ngf*8) x 4 x 4
            nn.ConvTranspose2d(ngf * 8, ngf * 4, 4, 2, 1, bias=False),
            nn.BatchNorm2d(ngf * 4),
            nn.ReLU(True),
            # state size. (ngf*4) x 8 x 8
            nn.ConvTranspose2d(ngf * 4, ngf * 2, 4, 2, 1, bias=False),
            nn.BatchNorm2d(ngf * 2),
            nn.ReLU(True),
            # state size. (ngf*2) x 16 x 16
            nn.ConvTranspose2d(ngf * 2,     ngf, 4, 2, 1, bias=False),
            nn.BatchNorm2d(ngf),
            nn.ReLU(True),
            # state size. (ngf) x 32 x 32
            nn.ConvTranspose2d(    ngf,      nc, 4, 2, 1, bias=False),
            nn.Tanh()
            # state size. (nc) x 64 x 64
        )

    def forward(self, input):
        if input.is_cuda and self.ngpu > 1:
            output = nn.parallel.data_parallel(self.main, input, range(self.ngpu))
        else:
            output = self.main(input)
        return output

Define discriminator network

class Discriminator(nn.Module):
    def __init__(self, ngpu):
        super(Discriminator, self).__init__()
        self.ngpu = ngpu
        self.main = nn.Sequential(
            # input is (nc) x 64 x 64
            nn.Conv2d(nc, ndf, 4, 2, 1, bias=False),
            nn.LeakyReLU(0.2, inplace=True),
            # state size. (ndf) x 32 x 32
            nn.Conv2d(ndf, ndf * 2, 4, 2, 1, bias=False),
            nn.BatchNorm2d(ndf * 2),
            nn.LeakyReLU(0.2, inplace=True),
            # state size. (ndf*2) x 16 x 16
            nn.Conv2d(ndf * 2, ndf * 4, 4, 2, 1, bias=False),
            nn.BatchNorm2d(ndf * 4),
            nn.LeakyReLU(0.2, inplace=True),
            # state size. (ndf*4) x 8 x 8
            nn.Conv2d(ndf * 4, ndf * 8, 4, 2, 1, bias=False),
            nn.BatchNorm2d(ndf * 8),
            nn.LeakyReLU(0.2, inplace=True),
            # state size. (ndf*8) x 4 x 4
            nn.Conv2d(ndf * 8, 1, 4, 1, 0, bias=False),
            nn.Sigmoid()
        )

    def forward(self, input):
        if input.is_cuda and self.ngpu > 1:
            output = nn.parallel.data_parallel(self.main, input, range(self.ngpu))
        else:
            output = self.main(input)

        return output.view(-1, 1).squeeze(1)

Task

粗略地講解了DCGAN的網絡結構,下面就來說明一下今天的任務:使用Pytorch搭建DCGAN生成動漫圖像。Maybe you will say:“說了這麼多,爲什麼不是生成人臉或者平均臉”答案是:一:萬事都先從簡單的開始,二是:你得有平均臉數據,畢竟搞深度學習的人都知道,最難弄的就是數據了。
so,let’s go on ! 你可以從上面copy代碼,或許你可以按照自己的思路構建/修改網絡。
然後就是,在DCGAN論文中,作者指定所有模型權重均應從 mean=0, stdev=0.02 的正態分佈中隨機初始化。該weights_init函數以已初始化的模型作爲輸入,並重新初始化所有卷積,卷積轉置和批處理規範化層,以符合此條件。初始化後立即將此功能應用於模型。

# 在netG和netD上調用的自定義權重初始化函數
def weights_init(m):
    classname = m.__class__.__name__
    if classname.find('Conv') != -1:
        nn.init.normal_(m.weight.data, 0.0, 0.02)
    elif classname.find('BatchNorm') != -1:
        nn.init.normal_(m.weight.data, 1.0, 0.02)
        nn.init.constant_(m.bias.data, 0)

當然,你也可以不加進去,就是訓練的時候,稍微收斂得不太好。
接着,我們需要定義一下關鍵參數

# 數據集根目錄
dataroot = "data/xxxx"

# 數據加載器能夠使用的進程數量
workers = 2

# 訓練時的批大小
batch_size = 128

# 訓練圖片的大小,所有的圖片給都將改變到該大小
# 轉換器使用的大小.
image_size = 64

# 訓練圖片的通道數,彩色圖片是3
nc = 3

# 本徵向量z的大小(生成器的輸入大小)
nz = 100

# 生成器中特徵圖大小
ngf = 64

# 判別器中特徵圖大小
ndf = 64

# 訓練次數
num_epochs = 5

# 優化器學習率
lr = 0.0002

# Adam優化器的Beta1超參
beta1 = 0.5

# 可利用的GPU數量,使用0將運行在CPU模式。
ngpu = 1

最後,就是開始訓練了。其實跟網上的大同小異

# 初始化 BCE損失函數
criterion = nn.BCELoss()

# 創建一個批次的本徵向量用於可視化生成器訓練的過程。
fixed_noise = torch.randn(64, nz, 1, 1, device=device)

# 建立一個在訓練中使用的真實和假的標記
real_label = 1
fake_label = 0

# 爲G和D都設置Adam優化器
optimizerD = optim.Adam(netD.parameters(), lr=lr, betas=(beta1, 0.999))
optimizerG = optim.Adam(netG.parameters(), lr=lr, betas=(beta1, 0.999))

訓練過程要求:爲了能夠更好地訓練DCGAN網絡,我們一般都是按照論文上的思路,將訓練分成了兩個部分。
1.Training discriminator:要求最大化將給定輸入正確分類爲真實(label=1)或假(label=0),也就是說我們想要最大損失:
log(D(x))+log(1-D(G(z)))。其中log(D(x))代表爲實際真實樣本損失,log(1-D(G(z)))爲生成器生成的假樣本損失。
2Training generator:要求實現通過最小化log(1-D(G(z)))來訓練生成器,以便生成較完美的樣本,達到以假換真的目的
但Goodfellow表明這不會提供足夠的梯度,尤其是在學習過程的早期階段。 作爲修改,我們希望最大化 log(D(G(z)))。
對第1部分的 Generator 輸出進行分類,使用真實標籤作爲 GT計算G的損失,在反向傳遞中計算G的梯度,最後使用優化器步驟更新G的參數。
最後,想要完整代碼的,可以參考我的GitHub點擊這裏
注:由於上傳時發生了錯誤,缺少了一些文件,想要訓練成功的話,記得添加一些文件。
在這裏插入圖片描述
還有就是得助於某位網友網上爬下來的數據,因爲可能存在一些髒的數據,因此本人已經通過相關濾波算法和非線性轉化對圖像進行了預處理。相比未處理前,模型提升了百分之幾的提升性能。
最後,有用的話,記得點個贊吧!

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