【實踐】偽造名人的臉—做一個小示例瞭解生成式對抗網路
生成式對抗網路(GAN)的概念由Ian Goodfellow提出。Goodfellow使用了藝術評論家和藝術家的比喻來描述這兩個模型比喻發生器和鑑別,它們組成了GAN。一個藝術評論家(鑑別器)試圖判斷影象是不是偽造的。一個想愚弄藝術評論家的藝術家(生成器)試圖創造一個看起來儘可能真實的偽造的形象。他們“相互鬥爭”;鑑別器使用生成器的輸出作為訓練資料,而生成器則從鑑別器中得到反饋。在這個過程中,每個模型都變得更加強大。通過這種方式,GANs能夠根據一些已知的輸入資料生成新的複雜資料。
實現GAN並不像聽起來那麼難。在本教程中,我們將使用TensorFlow來構建一個能夠生成人臉影象的GAN。
DCGAN架構
在本教程中,我們並不是試圖模擬簡單的數值資料,我們試圖模擬一個甚至可以愚弄人類的影象。生成器將隨機生成的噪聲向量作為輸入資料,然後使用一種名為反捲積的技術將資料轉換為影象。
鑑別器是一種經典的卷積神經網路,它將真實的和假的影象進行分類。
GAN結構的簡單視覺化
我們將使用論文“無監督表徵學習的深卷積生成對抗網路”中原始的DCGAN架構,它由四個卷積層作為鑑別器,四個反捲積層作為發生器。
安裝
請訪問https://github.com/dmonn/dcgan-oreilly。README檔案中完整的說明。helper函式會自動下載CelebA資料集,讓你快速啟動和執行。請確保安裝了matplotlib。如果不想自己安裝,那麼在儲存庫中就有一個Docker映象。
CelebA資料集
名人的屬性資料集包含超過20萬張名人圖片,每一張都有40個屬性註釋。因為我們只想生成隨機的人臉影象,所以忽略註釋即可。資料集包含了10,000多個不同的身份,這對我們很有幫助。
資料集中部分名人的影象
在這一點上,我們還將定義一個用於批處理的函式。這個函式將載入我們的影象,並根據我們稍後設定的批處理大小給我們提供一系列影象。為了得到更好的結果,我們將會對影象進行裁剪,只有臉部才會顯示。我們還將使影象歸一化,讓它們的畫素值範圍在-0.5到+0.5之間。最後,我們將把影象縮小到28×28。這樣雖然我們損失了一些影象質量,但卻大大減少了訓練時間。
定義網路輸入
在我們開始定義我們的兩個網路之前,我們先定義我們的輸入。這樣做是確保不讓訓練功能不會變得更亂。在這裡,我們只是簡單地為我們的真實和虛假輸入定義TensorFlow佔位符,以及學習率。
def discriminator(images, reuse=False):
"""
Create the discriminator network
"""
with tf.variable_scope('discriminator', reuse=reuse):
# … the model
TensorFlow為佔位符分配變數特別簡便。完成這一操作之後,我們可以通過稍後指定一個饋送詞典(feed dictionary)來使用我們網路中的佔位符。
鑑別器網路
鑑別器相當於“藝術評論家”,試圖區分真實和虛假的影象。簡單地說,這是一個用於影象分類的卷積神經網路。如果你已經有了一些深度學習的經驗,那麼你有可能建立過與之相似網路。
鑑別器執行多重卷積
定義這個網路時,我們要使用一個TensorFlow變數作用域。這有助於我們稍後的訓練過程,所以我們可以重複使用我們鑑別器和發生器的變數名。
def discriminator(images, reuse=False):
"""
Create the discriminator network
"""
with tf.variable_scope('discriminator', reuse=reuse):
# … the model
鑑別器網路由三個卷積層組成,與原始架構中的四個卷積層不同。我們刪除最後一層來簡化模型。這樣訓練進行得非常快,也不會損失太多的質量。網路的每一層,我們都要進行卷積,然後我們要進行批量歸一化,使網路更快,更準確,最後我們要執行Leaky ReLu來進一步加速訓練。最後,我們將最後一層的輸出變平,並使用sigmoid啟用函式來獲得分類。不管影象真實與否,我們現在得到了一個預測結果。
發生器網路
發生器:試圖欺騙鑑別者的是藝術家(造假畫的人)。發生器利用反捲積層。它們與卷積圖層完全相反:除了將影象轉換為簡單的數值資料(如分類)之外,我們執行反捲積以將數值資料轉換為影象,而不是執行卷積。這不是像簡單的卷積層那樣的概念,它被用於更高階的地方。正如我們在鑑別器網路中所做的那樣,我們也將其包含在一個可變範圍內。
發生器執行多重反捲積
我們在這裡做的和鑑別者一樣,只是方向相反。首先,我們接受我們的輸入(稱為Z)並將其輸入到第一個反捲積層。每個反捲積層執行反捲積,然後執行批量歸一化和Leaky ReLu。然後,我們返回tanh啟用函式。
開始訓練
在我們真正開始訓練過程之前,我們還有要做的事情。首先,我們需要定義所有幫助我們計算損失的變數。其次,我們需要定義我們的優化函式。最後,我們將建立一個小的函式來輸出生成的影象,接著訓練網路。
損失函式
我們需要定義三個損失函式:發生器的損失函式,使用真實影象時鑑別器的損失函式,以及使用假影象時鑑別器的損失函式。假影象和真實影象的損失總和應是整個鑑別器損失。
首先,我們定義我們對真實影象的損失函式。為此,我們在處理真實影象時要傳遞鑑別器的輸出,並將其與所有1的標籤進行比較(1代表真實)。我們在這裡使用一種名為“label smoothing”的技術,它通過將0.9和1s相乘,來幫助我們的網路更加準確。
然後,我們為我們的假影象定義損失函式。這次我們在處理假的影象時將鑑別器的輸出傳遞給我們的標籤,這些標籤都是0(這表示他們都是假的)。
最後,對於發生器的損失函式,我們的做法就像在最後一步一樣,但是我們沒有把輸出與所有的0相比,而是用1s來比較,因為我們想要欺騙鑑別器。
優化和視覺化
在優化步驟中,我們正在尋找所有可以通過使用tf.trainable_variables函式進行訓練的變數。既然我們之前使用了變數作用域,我們可以非常舒適地檢索這些變數。然後我們使用Adam優化器為我們減少損失。
def model_opt(d_loss, g_loss, learning_rate, beta1):
"""
Get optimization operations
"""
t_vars= tf.trainable_variables()
d_vars= [varfor varin t_varsif var.name.startswith('discriminator')]
g_vars= [varfor varin t_varsif var.name.startswith('generator')]
在我們準備的最後一步,我們正在編寫一個小的函式,使用matplotlib庫在膝上型電腦上顯示生成的影象。
訓練
我們正在最後一步!現在,我們只獲取我們之前定義的輸入,損失和優化,呼叫一個TensorFlow會話並分批執行批處理。每400一批,我們通過顯示生成的影象和生成器以及鑑別器的損失來輸出當前的進度。現在身體向後靠,你會看到臉出現。根據你的設定,進度可能需要一個小時或更長的時間。
生成的臉
結論
如果你順利讀完,那麼恭喜你,你已經瞭解了GAN的用途,甚至知道如何使用它們生成人臉影象。你可能會問:“我將永遠用不到生成隨機面部的影象。”雖然這可能是真的,但是GAN還有很多其他的應用。
密歇根大學和德國馬克斯普朗克研究所的研究人員使用GAN從文字生成影象。根據論文描述,他們能夠產生非常逼真的花鳥。它還可以擴充套件到非常有用的其他領域,如模擬畫像或平面設計。
伯克利的研究人員也設法建立了一個GAN,增強了模糊影象的清晰度,甚至重建了已損壞的影象資料。
GAN是非常強大的,誰知道 – 也許你會發明他們的下一個開創性的應用程式。