基於CPPN與GAN+VAE生成高解析度圖像(一)

編者按:Google Brain機器學習開發者hardmu使用TensorFlow,基於CPPN與GAN+VAE生成高解析度圖像。一起來看看他是怎麼做的吧。

註:本文系作者授權論智(公眾號:jqr_ai)編譯,請勿隨意改編。

基於CPPN與GAN+VAE的生成式模型

介紹

在數字生成藝術的某些領域,藝術家通常不會直接使用圖像編輯器創作。藝術家通常會編程一組過程,由過程生成實際的圖像。這些過程由指示機器在特定坐標上繪製線條和形狀的指令組成,並以某種數學定義的方式操作顏色。最終的作品(可能作為像素圖像呈現,或列印在物理介質上)可以由一組數學過程完全刻畫和定義。

許多自然圖像具有有趣的數學特性。人們已經編寫簡單的數學函數來產生自然的分形紋理,如樹枝和雪花。像分形一樣,一組簡單的數學規則有時能生成一個非常複雜的圖像,這樣的圖像可以被無限放大或縮小。

想像一下,如果你可以接受任何圖像作為輸入,並不將該圖像存儲為一組像素,而是嘗試找出一個逼近圖像的數學函數,也就是說,特定位置的像素(x, y)可以由f(x, y)表示。

一旦找到這樣的函數,僅僅通過縮放輸入就能自動縮放和拉伸圖像。如果這個函數有一些有趣的性質或者表現出某種內部結構,那麼看看把圖像放大到比原始圖像大得多的解析度是什麼效果會很有趣。

這個函數也可以定義為一個具有任意架構的神經網路。有人將這類網路稱為複合模式生成網路(Compositional Pattern Producing Networks),這類網路是一種用函數表示整張圖像的方式。由於神經網路是普適的函數逼近器,給定一個足夠大的網路,任何有限解析度的圖像都可以用這種方法表示。

訓練神經網路繪畫(基於karpathy的convnet.js demo)

我認為由各種架構的神經網路生成的作品的風格看起來真不賴,所以我打算探索下這類生成式網路是否可以用來生成整類圖像,而不僅僅是單個圖像。最近有研究使用神經網路來生成某個特定類別的像素圖像,我想看看能不能用上述生成式網路達到類似的效果。

在這篇文章中,我將介紹使用CPPN生成高解析度手寫數字圖像的經驗,作為一個開始,我將在MNIST(28x28 px)上進行訓練。將來我可能會嘗試在更複雜的圖像集上使用這一方法。

我們的CPPN將基於隨機潛向量Z生成一個高解析度的MNIST圖像

背景

在前一篇文章中,我們探索了使用CPPN生成有趣的隨機紋理的高解析度圖像。由於CPPN的輸入由某個像素的坐標組成,而輸出是該坐標的顏色,因此CPPN可以生成機器內存所允許的任意解析度的圖像。 這一特性為CPPN提供了一些類似於分形的特徵,因為只需調整圖像所需視圖對應的縮放輸入坐標,即可任意縮放圖像。隨機化CPPN的權重可以產生許多在某些人看來很美的抽象紋理。而且,如果我們固定神經網路架構和一組隨機權重,我們可以通過調整額外加入網路的潛向量輸入來探索CPPN可生成圖像的空間。

以隨機權重初始化的未經訓練的網路生成的圖像,將在MNIST數據集上訓練該網路

我之前使用CPPN生成了許多奇怪的圖像,並且一直為此方法可以生成的圖片範圍而感到驚訝。除了隨機生成抽象的藝術紋理,這種方法也被用於基因藝術生成。在以前的項目中,藝術通過「基因」慢慢演化,我發現,生成「最好」的藝術需要放棄實際創作某一特定事物的目標。例如,如果一個藝術家想用CPPN-NEAT來生成一張貓的圖像,她很可能不會得到任何類似貓的東西。但如果藝術家著手選擇她認為看起來有趣的紋理,並將它們混合起來以產生下一代圖像,最終她可能會得到看起來更有趣的東西。Ken Stanley在其著作Novelty Search中強調了這一現象,我發現這是一個非常迷人的看待AI研究領域的方法,同時也是一個面對生活的一般方法。

不過,我確實認為讓CPPN生成所需的指定圖像是可能的。給定一個足夠大的網路,而不是一個微小的NEAT網路,我們可以逼近任何東西,甚至karpathy的簡單JS繪畫演示證明,給定足夠大的網路和足夠長的訓練時間,這一方法可以繪製任何圖像。

然而,相比依靠過擬合網路權重來匹配某個目標圖像以生成特定的圖像,這種網路是否能夠產生新概念圖像是一件更有趣的任務。例如,我們希望能夠讓網路生成一隻貓的隨機圖片,並能夠讓這隻貓慢慢漸變為狗。這樣的話,網路就不是真的過擬合某個特定的訓練圖像,而是內在地理解貓和狗的概念,以至於能夠想像介於貓和狗之間的新圖像。若干年前,我認為這會被視為科學幻想,但我們實際上已經達成了這一點。

最近,我們已經看到了能夠生成人、浴室、貓和動漫人物的深度神經網路。這些方法將圖像中的像素建模為可觀測的隨機變數X。除非是像白牆這樣非常瑣碎的圖像集,否則X內所有像素的聯合概率分布是非常複雜的,不太可能用一些人類可以理解的更簡單的分布來建模。然而,神經網路有可能勝任這一艱巨的任務,學習如何將這種複雜的分布映射到人類可以理解和使用的簡單分布,比如高斯分布。所以訣竅就是將這樣複雜的可觀測的隨機變數(一張圖像中的所有像素)建模為因變數,它的值取決於一組表示更簡單的概率分布的變數,例如由一打單位正態高斯構成的向量。該向量通常記為Z,即潛向量。

所以我們的目標是讓神經網路從一個非常簡單的由實數組成的潛向量Z中學習能夠生成一張非常複雜的圖像X的條件概率分布P(X|Z)。此外,一個附贈的學習P(Z|X)的網路也是非常有用的,可以用來將複雜圖像編碼為潛向量。

回想一下統計學的第一門課程,你會發現這與主成分分析(PCA)有些關係。PCA嘗試將一個大的觀測集分解成數量較少的因子,改變這些小的因子集可以預測大的觀測集會有什麼樣的改變。唯一的區別是PCA是基於線性代數的,PCA假定數據可以解釋為較小因子的線性組合,而這種基於神經網路的方法能夠以高度非線性的方式分解大的觀測集,因而更為強大。

目前,從潛向量生成圖像的前沿技術通常基於生成對抗網路(GAN),變分自動編碼器(VAE)或這些方法的組合,下文會描述它們。想要了解更多關於這些方法的信息,請參閱深度卷積生成對抗網路(DCGAN),一個知名的該領域中最先進的技術,而DRAW演算法是VAE最前沿的擴展。我對這個領域的研究基於carpedm20的DCGAN實現和Jan Hendrik的VAE實現,兩者都使用了TensorFlow庫。他們的代碼和解釋對我的理解有很大幫助。我也研究了這兩種方法的結合,同時用了一些技巧來穩定GAN的訓練。

就目前的文獻而言,訓練數據集通常由小圖像組成(例如32x32 px或64x64,儘管我看到過使用128x128和256x256的)。為了與訓練數據匹配,生成器網路將具有與訓練數據的像素數量一樣多的輸出。因此,通常情況下,在64x64像素的圖像數據集上訓練的網路也會直接輸出64x64像素。目前的方法很難生成解析度遠高於256x256的圖像,因為所需的內存可能超過現代顯卡的可用顯存。

本文將使用CPPN基於MNIST訓練集的較小圖像生成大圖像。由於CPPN可以生成任意大解析度的圖像,我想嘗試訓練一個生成圖像的CPPN會是非常簡潔的,就像使用GAN和VAE一樣,只是將直接生成所有輸出像素的生成網路替換為CPPN而已。訓練時,我們可以直接將CPPN的輸出解析度設置為與輸入相同。訓練後,我們可以增加輸出圖像的解析度,看看CPPN如何用由網路定義的內部風格來填補空白。之所以將CPPN的訓練解析度設置為與訓練數據相同的大小,是為了讓現代的顯卡能夠承受整個訓練過程。

由於CPPN架構的間接編碼本質,相比於直接輸出所有像素的網路,CPPN可能產生的圖像的空間會相當受限。所以就這個立場而言,訓練CPPN被證明更具挑戰性,在簡單的MNIST數據集的訓練,相比VAE或GAN模型要花費更多的時間。在一個MNIST之類的簡單數據集上,用結合GAN和VAE的CPPN模型得到了一些令人滿意的結果後,我們可以考慮未來在更複雜的真實、彩色的物體圖像集上測試這種演算法。

生成對抗模型

正如背景一節所討論的,圖像生成的挑戰是得以對圖像中的像素的聯合概率分布進行建模。一旦我們有了所有像素逼真的概率分布,我們就可以從該概率分布中採樣以生成逼真的圖像。然而,由於真實圖像非常複雜,人工建模概率分布太噁心了,所以訣竅在於使用神經網路將人類可理解的更簡單的概率分布(如單位高斯隨機變數)轉化為與訓練集中正常圖像的真實概率分布類似的概率分布。生成概率分布的複雜性受限於神經網路架構的複雜性。在我們的例子中,生成圖像的神經網路會是CPPN:

生成網路架構

這個網路與上一篇文章中使用的網路屬於一類。輸入向量Z是從單位高斯隨機數生成器中取得的32個實數組成的向量,這些實數均互相獨立。向量x、y和r是我們想要計算的圖像中的像素亮度的所有可能的坐標,因此對於26x26的圖像,我們需要計算共計676個像素的亮度,以構成(32+676+676+676)個網路輸入。有很重要的一點需要注意,每個像素強度將基於具有相同權重集合的完全相同的網路計算,所以如果內存有限的話,理論上我們也可以傳給我們的網路(32+1+1+1)個輸入並得到1個像素,在保持權重不變的前提下,重複這一步驟676次。

正如我們前面所看到的那樣,保持網路的權重不變,我們可以通過控制輸入Z向量獲得豐富的輸出圖像集。這裡的目標是訓練我們的網路,對於我們傳入的任何隨機Z向量,其輸出看起來像MNIST訓練集中的圖像。如果我們能夠成功地做到這一點,那麼我們就成功使用CPPN建模了MNIST圖像的概率分布,並且我們可以通過採樣簡單的IID單元高斯變數來繪製隨機圖像。

但是,我們究竟如何訓練這個網路的權重,以便將一串單位高斯隨機數轉換成一張隨機MNIST圖像呢?活在2013年的人會認為這是科幻小說。但是,如果你沒有因為困在一個山洞裡導致網路中斷的話,那麼過去幾年你可能會聽說過生成對抗網路框架。 GAN背後的概念是引入一個判別(Discriminator)網路來配合上面的生成(Generator)網路。

判別網路架構

判別網路能夠判斷圖像是否屬於訓練集。所以它將被用於檢測不合法、不真實的MNIST數字的虛假圖像。生成網路自然試圖產生一個隨機的MNIST數字圖像,該圖像可以欺騙判別網路。如果判別網路的表現足夠好,能夠達到人類的水平,而此時生成網路還能欺騙判別網路的話,這就意味著生成網路能夠生成可以欺騙人類的假MNIST圖像,也就意味著我們的工作已經完成了。

我依照DCGAN的類似方法,使用了三個簡單的卷積網路層。卷積網路已被證明在圖像分類方面非常出色,而且由於判別網路的輸出在這種情況下是二元的(真/假),因此這是一個比數字分類更簡單的分類問題。

判別網路的輸入是圖像,輸出y是零到一之間的實數。如果y接近1,則判別網路堅信輸入圖像一定是合法的MNIST數字,如果y接近0,則判別網路堅信圖像不是MNIST數字,而是一個試圖愚弄和侵蝕其智能的欺詐嘗試。如果判別網路的輸出接近0.5,那麼網路就會感到困惑和悲傷,喪失了它作為正常神經網路發揮功能的信心。

我們可以定義表現指標或損失函數來評估生成網路的表現:

G_loss = -log(y | G生成的圖像)

可以看到,如果生成網路表現得很糟糕,那麼判別網路的輸出y將是一個非常小、接近於零的數字,而一個接近0的很小的數字的對數的相反數,會是一個很大的正數。

如果生成網路表現得很出色,狠狠地愚弄了判別網路,那麼輸出值y將是一個接近一的數字,而接近1的數字(如0.999)的對數的相反數,會是一個接近零的數字。

如果生成網路創建的圖像導致判別網路很困惑,無法分辨出差異,則輸出y將是一個接近0.5的數字,而G_loss會是一個接近-log 0.5也就是0.69的數字。

同理,我們可以用類似的方式評估判別網路的表現:

D_loss_real = -log( y | 真實訓練樣本)D_loss_fake = -log( 1-y | G生成的圖像)D_loss = 0.5 * D_loss_real + 0.5 * D_loss_fake

如果判別網路表現出色,D_loss_real和D_loss_fake會同時趨向於零。反之,D_loss_real和D_loss_fake會同時趨向於一個很大的數。如果判別網路很困惑,D_loss_real和D_loss_fake將趨向於0.69,因而判別網路在識別真實圖像和虛假圖像時都存在困難。我們將D_loss定義為兩者的平均值。

給定以上的損失函數,使用反向傳播來訓練判別網路將是非常自然的。反向傳播將通過調整權重Wd來學習分辨真假MNIST數字。調整權重的梯度方向將使D_loss在遇到一組真實樣本和生成網路新生成的虛假樣本後變小。

生成網路同樣可以通過反向傳播訓練。反向傳播調整權重的梯度方向將使G_loss變小(因此同時使D_loss變大)。

注意訓練生成網路需要花費更多精力,因為在反向傳播的過程中,梯度首先將穿過判別網路層,至生成網路所生成的每個像素(因此首先將計算d(G_loss)/d(X_ij))。此後,對應於每個像素的每個損失微分的梯度將反向穿過生成網路的每個權重(Wg)。同時,因為我們使用CPPN演算法生成圖像,每個像素由權重相同的同一網路生成,只是輸入的坐標(x, y, r)不同。由於權重是共享的,累計從像素層次反向傳播到梯度的權重可以計算d(G_loss)/d(W_g)。這意味著,如果我們正對一組圖像進行minibatch訓練,訓練CPPN意味著我們將處理batch中的batch。我花了一番工夫才弄清楚如何在TensorFlow中正確實現這個功能,因為許多默認忽略batch處理的快捷方式用不了了。

GAN模型的介紹就到這裡,在本文的第二部分,我將介紹如何訓練GAN,並融入VAE以解決訓練GAN時發現的問題。

未完待續……

原文地址:blog.otoro.net/2016/04/

推薦閱讀:

TAG:生成對抗網路GAN | 機器學習 | 深度學習DeepLearning |