選自towardsdatascience
作者:Nolan Kent
機器之心編譯
參與:Luo Sainan、Geek AI
不能寫一手好代碼的工程師不是好數據科學家!本文作者 Nolan Kent 曾經是一名惡意軟體分析師,具有很強的工程能力。在本文中,他編寫了一個可視化工具用於觀察 StyleGAN 模型中的特徵圖,對理解該模型起到了巨大作用。
圖 1:修改單一位置的空間特徵圖以生成動漫人物
「寫在前面」
這篇技術博客介紹了一個使用生成式對抗網絡完成的項目。由於這是一個個人項目,我採用了一個在專業領域中通常不會使用的動漫人物數據集「DANBOORU2018」。
下面給出了這個數據集的連結以及使用該數據集模型的詳細介紹:
https://www.gwern.net/Danbooru2018?source=post_page4cf764578e--
作者表示,所做的大部分工作純粹是出於學習的目的,但最後得到了更為有趣的結果:矩形肖像的嘴部動畫。
圖 2:快速/平滑的嘴部動畫。由於缺乏數據,男性肖像的質量通常更低
在這個項目中,有一個部分是使得和生成對抗網絡交互並且對其進行學習更容易的工具,但是現在這個工具對用戶而言並不是十分友好。
如果繼續該項目,一個很重要的目標是發布一個新版本的工具,可以使任何人能立即上手來製作一個如圖 2 所示的動漫人物。但是現在,它主要還是一個用於研究的工具:
圖 3:該工具部分界面的截圖。用戶界面確實需要改進,但目前這仍然只是一個原型,我將經常在其基礎上添加和刪除一些功能。
我發現,比起使用 jupyter notebook,將實驗代碼融合到這樣的工具中,可以更容易地在不同的設定下重複實驗。有些思想只有通過重複的實驗才能越來越明朗,所以如果沒有這個工具,我覺得我可能會遺漏博客中提到的一些見解。如果你只是對示例的動漫圖像感興趣而並不關注技術細節,你可以直接跳到本文的「實驗結果:動漫人物」這一章。
許多個人項目存在的主要問題之一是:它們只包含單一的視角。我寫此博客的目的是為了獲取他人對該課題的看法,詳細描述我在這個項目中的工作經驗,並接受建設性的批評和指正。
引言和成果小結
這些年,我養成了定期復現有關生成式模型論文的習慣,所以我大約在 StyleGAN 論文發表的時候,就陸陸續續的開始了這個項目,我的工作主要包含三個部分:
1. 復現了 StyleGAN,並作出了一些調整
2. 基於我的實現訓練了該模型
3. 實現了一個用於可視化模型並與模型交互的工具
首先,我抱著學習練習的心態復現了 StyleGAN,這也是因為當時官方代碼(https://github.com/NVlabs/stylegan)還沒有開源。StyleGAN 的結果比我接觸過的其它模型要好得多,所以我想要進一步深入研究一番。
一個令我很興奮的生成式模型的應用是:它能夠為電子遊戲自動生成資源。對於我來說,StyleGAN 是我復現的第一個在電子遊戲上生成的結果可接受的模型,所以我的初步嘗試就是讓「Unity」等遊戲引擎加載該模型。
為此,我製作了一個「.NET」動態連結庫(DLL),它可以與模型進行交互,從理論上來講也能夠被導入到「Unity」中。為了測試這個動態連結庫,我創建了一個與之交互的工具。最終,我為這個工具添加了越來越多的功能,直到這個工具成為了本項目最大的組成部分之一。
以下是項目的整體架構:
圖 4:從 TensorFlow python 實現到使用工具生成圖像的工作流程
我喜歡使用工具來可視化「不透明」的數字對象(比如惡意軟體和深度學習模型)並與之交互,所以我增加的一個功能就是對特徵圖的可視化及修改(見圖 5,https://towardsdatascience.com/applied-deep-learning-part-4-convolutional-neural-networks-584bc134c1e2)。
觀察不同圖像上各層特徵圖最活躍的部分有助於我了解模型在做什麼,並且會使對一些面部特徵的自動定位變得簡單。當對圖片進行修改時,我注意到,對特徵圖特定區域的值進行加或減會產生一些有意義的變化,比如張開和合上嘴巴(見圖 2)。與自動面部特徵檢測相結合,這可被用來在不需要標籤的情況下,對所有生成的圖像進行一致且有意義的修改。(見圖 9、10)。
圖 5:特徵圖可被用來識別有意義的區域(上面一行圖像:眼睛,下面一行圖像:人臉)。紅色方塊表示負激活值,綠色方塊表示正激活值,白色方形表示激活值接近 0。
小結:以上是使用特徵圖來修改面部特徵的功能,以下是本博客剩餘部分內容的組織結構。
生成式模型的應用使用工具生成動漫人物關於代碼的簡要討論復現的細節對數據的討論對訓練步驟的討論應用
總的來說,我對生成式模型的以下幾個方面很感興趣:
更好地通過程序化的方式生成遊戲資源讓藝術創作變得更容易更快無監督學習的基本潛能與生成式因素解耦(disentaglement)相結合更好地通過程序化的方式生成遊戲資源
生成式模型有望將程序化生成推向一個新的高度,這令我十分激動。據我所知,現今的基於規則的程序化生成技術不能根據高度複雜的分布隨機創造樣本。例如,程序化生成的關卡的一個小節多半可以與該關卡的其餘部分獨立開來,並且仍然被玩家所接受。
隨機生成人物肖像類的圖像是更難的,因為好看的人物圖片趨向於反映真實世界,而現實世界具有特別多的相互依賴性,因此每個像素都需要在其它像素的上下文中被考慮到。為了使圖片看起來好看,即使非寫實的圖片也需要一致的光源、解剖結構、紋理、視角、風格等等。
這種依賴性也適用於音頻、對話、動漫、故事情節的自動生成。我認為生成式模型是當前能夠可靠地根據如此複雜的分布生成樣本的最佳方式。
讓藝術創作變得更容易更快
在使用生成式模型時,通過交互式工具有可能使外行人也能夠創作本來需要有經驗的藝術家才能創作的圖像,或者讓藝術家們能夠更快地完成他們工作中較為常規的部分。
我並不認為生成模型會很快消除對有創意的藝術家的需求,因為生成模型(以及大多數機器學習模型)專注於對特定的分布建模。這使得生成與訓練分布中任何樣本都不同的高質量圖像(即有創意的圖像)是非常困難的。
然而,像本博客中使用的這種工具,使人們能夠添加有助於生成更多獨特的圖片的自定義變更(尤其是如果模型已經學到了一些基本的圖形概念(比如照明和透視))。
無監督學習的基本潛能與生成式因素解耦相結合
由於無標籤數據的數量遠超於有標籤數據,並且深度學習是極其需要數據的,我認為今後無監督/半監督學習有逐漸取代有監督方法的潛力。尤其是,我們已經提出了一些針對深度生成模型的方法,用來解耦數據集中的變化因素:圖 7 和圖 8 展示了 StyleGAN 是如何做到這一點的(至少部分做到)。
實際上,對於「解耦」並沒有一個一致的的形式化定義。我的理解是,僅有有限的實驗證據表明它對下遊任務是有用的。然而,將「解耦」與 GAN 一起使用,讓我抱有一種它是有用的樂觀態度。儘管生成器不能為它未生成的圖像生成內部表徵,但是還有幾種其它類型的生成模型可以在視覺質量上和 GAN 一較高下,並且可能更適合於下遊任務。
實驗結果:動漫人物
我在一個名為「Danbooru2018」的動漫數據集上訓練出了自己最佳的模型(https://www.gwern.net/Danbooru2018)。我將在數據部分討論它的優缺點,其中一個主要缺點是缺乏多樣性:難以生成男性圖像。
下面所有的例子都是用這個工具生成的。
我最初是在 一個 jupyter notebook 中生成了這些圖片,但是接著又使用專門的工具顯著地加快了圖像生成的速度,並且讓我以不同的視角來理解模型是如何工作的。下面的圖像大致按照生成的複雜程度排序:在不使用該工具的情況下,圖 7/8 比圖 6 生成起來更麻煩,圖 9/10 比圖 7/8 更難生成。
圖 6 是幾張圖像的中間潛變量(intermediate latent variable)之間插值的示例。通過使用 GAN 我們可以得到一個很酷的結果:確保插值後的圖像與最終圖像的質量相似。
圖 6:隨機潛向量之間的插值
圖 7 是通過定位中間潛空間中具有特定意義(在本例中是頭髮或者眼睛顏色)的向量來修改圖像並且向該方向移動的示例。比如,可以將許多黑髮人臉圖像的平均潛變量值計算出來,減掉其它所有圖像的平均潛變量值,即可得到黑色頭髮的向量。我將會在「訓練/後處理」部分進一步討論。
圖 7:在有意義的方向上改變潛變量
圖 8 展示了將生成圖 7 的想法應用於「嘴巴張開」這一屬性的效果。這在某種程度上有用,但是屬性並不是完全解耦的:除了嘴巴發生了變化外,圖像的每個部分都能看到一些變化。常識告訴我們,一個人可以只動動嘴巴而不顯著改變身體的其它部分。一個簡單的技巧就是把動漫人物的嘴粘貼到另外一個靜態圖像上,但是這在改變「嘴巴張開」的向量的同時也會改變皮膚色調或圖像風格的情況下並不起作用。
圖 8:改變嘴部向量也改變了其它屬性
圖 9 展示了一個在靠近人物嘴部的空間位置修改特定特徵圖以產生說話(或咀嚼)的動畫,且不引起全局改變的示例。通過少量的手動操作,在不需要多於兩個帶標籤的數據樣本的情況下,就可以找到修改後可以產生這種變化的特徵圖。這些都可以通過該工具完成。
這一過程受到了 DCGAN (https://arxiv.org/abs/1511.06434)論文的啟發,通過修改特徵圖來刪除圖中的窗口。這些修改是對特定特徵圖的局部區域做簡單的加或減操作。我將在以後的博客中展示如何使用該工具完成這一工作。
圖 9:通過空間局部修改產生說話的動畫。一旦找到對應於有意義的變化的特徵圖,無論圖像的質量或風格如何,它們都可以被應用於大多數圖像。
除了有無髮帶之外,圖 10 展示了和圖 9 相同的內容。這一技術可以被應用於許多不同的屬性。
圖 10:使用局部修改添加/刪除髮帶
實驗結果:代碼
考慮到我的空閒時間是有限的,並且我的首要目標是學習,我忽略了對大多數項目來說很重要的幾個方面:
規劃/設計:我起初儘可能少做計劃,增加了我想到的功能/變化。UI 設計:我使用貪心策略來添加我想到的功能。代碼風格:我開展本項目的主要目的不是為了讓別人來讀我的代碼,而是想要儘可能快地得到結果。我曾經從事惡意軟體逆向工程的工作,所以我自己本身並不是很害怕調試低質量的代碼。快速開發非常適用於本工具,但是在實現深度學習模型方面我的速度要慢得多,因為可能很難發現和調試錯誤。該項目的代碼質量遠遠不能滿足專業項目的要求。下面給出我的 github 連結,它們仍處於積極開發中,因此某些提交中可能存在一些漏洞:
StyleGAN 的復現:
https://github.com/nolan-dev/stylegan_reimplementation
我製作的工具:
https://github.com/nolan-dev/GANInterface
復現細節
在這一節中我將介紹復現 StyleGAN 和訓練模型的技術細節。
復現 StyleGAN
在論文「A Style-Based Generator Architecture for Generative Adversarial Networks」(https://arxiv.org/abs/1812.04948)發布後不久,大概是官方代碼發布前的幾個月,我開始復現 StyleGAN。
我將在此討論我碰到的一些挑戰和採取的應對方法(假設你熟悉 StyleGAN 和 TensorFlow)。
StyleGAN 以 PGGAN (https://arxiv.org/abs/1710.10196)(我曾經復現過)為基礎。這些模型使用了「漸進增大」的訓練方式,即判別器和生成器在訓練期間不斷增添卷積層以處理越來越高的解析度。
擴展一個模型的做法是比較罕見的——所有我復現過的其它模型在訓練期間都不需要改變它們的結構。幸運的是,Tensorflow 有一些比較方便的功能,比如只為模型的一部分加載已保存的權重並隨機初始化其餘的權重。遷移學習中也會使用這種方法。
我非常喜歡 TensorFlow 2.0 的風格,它將模型創建為繼承自「tf.keras.Model」的類。我用這種方式創建了大多數層、生成器、判別器和映射網絡。我也試著在動態圖執行(eager excution)和傳統的基於圖的執行之間能夠進行切換。動態圖執行使得調試更容易,我認為它是一種更好地理解程序的方法(也是一種惡意軟體分析中常用的技術)。
不幸的是,現在動態圖機執行比在圖模式下運行慢得多,所以最終我停止了對該功能的更新。使用「tf.keras.Model」的好處之一就是它在動態圖和傳統的圖模式下都可以工作,因此從理論上講,再轉而使用動態圖執行也不會太難。與此同時,我剛剛使用了「tfdebug」命令行界面和「TensorBoard」,在這一點上我相當滿意。
StyleGAN 和 PGGAN 有一些重要的區別。有一種方法在使用「自適應實例歸一化」操作時,將特定圖像的潛在數據作為樣式(非空間屬性)提供給特徵圖。理論上講,這很容易根據論文中所述細節實現,但我選擇用「tf.nn.moments」來計算均值和方差,這並不如官方實現的版本那樣有效(官方使用較低級別的操作來計算這些值)。
我猜這是由於數值問題造成的,當時我並不想對此進行調試,因此我沒有更多地研究它。通常,我很樂於深入研究此類問題,因為研究它們顯然使我有機會學更多知識,但是由於這個項目只是我的愛好,因此我必須優先考慮充分利用我的時間。
StyleGAN 也使用了一個中間潛空間,該空間假設通過增加對潛變量值範圍的靈活性和依賴性促進解耦(論文中有一些實證證據)。比如說,如果我們假設人群中的男性都沒有長頭髮,那麼當對應於性別的潛向量出現在「男性」區域中時,對應於頭髮長度的潛向量應該永遠不會出現在「長發」區域中。如果潛向量是獨立的(在沒有映射網絡時會發生這種情況),我們最終將「長發」和「男性」一起採樣,生成器將會生成非男性或是短髮來騙過判別器。
這意味著即使頭髮長度的潛向量處在「長發」區域,當其它潛變量值在其正常範圍內時,我們最終有可能生成短髮圖像。值得注意的是,對一些解耦的定義需要進行「軸對齊」(修改單個潛變量值會帶來有意義的變化),我的理解是 StyleGAN 的映射網絡促使中間潛空間成為輪流軸對齊解耦旋轉之後的形式(修改潛變量會產生有意義的變化)
在我看來,使用中間潛變量值就像通過風格將信息融合到網絡中一樣有趣。它也很容易實現。除非另有說明,否則本系列博客中提到的潛變量值指的就是中間潛變量值。
如果起初看起來像是論文次要細節的部分變成了最難復現的部分,那就真的太令人煩惱了。StyleGAN 就遇到了這種情況——StyleGAN 和 PGGAN 之間的一個區別就是對雙線性上採樣(和下採樣)還有 R1 regularization(https://arxiv.org/abs/1801.04406)(對判別器的梯度懲罰)的使用不同。
這兩種方法都很容易單獨實現,但是當我嘗試將它們組合時,發現 TensorFlow 無法計算「tf.nn.depthwise_conv2d」操作的二階導數。
Depth-wise 卷積被用來將卷積核分別應用於每個通道。在卷積神經網絡中通常並不需要這樣做,因為(除去一些用於行動裝置的 CNN)每個卷積核都與前一層的所有通道相連。通常用於實現雙線性插值的模糊卷積一次只能處理一個特徵圖,所以需要進行深度卷積。如果沒有實現二階導,我將無法計算 R1 懲罰,而這需要使用梯度的梯度。
當時我對自動微分還不夠了解,不能自己輕易地實現二階導。我花了一些時間嘗試更好的理解自動微分,那時我已經完成了除此部分以外的所有工作,隨後不久官方的代碼就發布了。英偉達團隊在模糊卷積中使用兩個「tf.custom_gradient」函數很好地解決了這個問題。
我對 StyleGAN 進行了幾次實驗調整,並取得了不同程度的成功。
1. 我通過將初始解析度改為 8x4 並隨後增大解析度來測試矩形圖像。
2. 我嘗試用 ACGAN 和帶有投影判別器的 cGan 來實現「條件 StyleGAN」。
第一個實驗在矩形圖像上的效果很好,用 ACGAN 和 cGan 實現的「條件 StyleGAN」效果則較差。這可能是由於我的超參數選擇不夠好,但是通常來說,結果比無條件訓練後在潛空間中找到有意義的特徵對應的向量的結果差(本文將在「訓練/後處理」部分中進行討論)。
數據
隨 StyleGAN 論文一起發布的 FFHQ 數據集含有 70,000 張高解析度圖像。為了更接近生成完整任務的目標,我嘗試修改英偉達提供的數據抽取腳本,按照 8:4(高:寬)的比率來提取圖像。
除了提取臉部,也從臉部下方提取了相同量的數據。將高度和寬度加倍將需要原始輸入尺寸提升 4 倍,而僅將高度加倍則需要將尺寸提升 2 倍。人臉下方的數據也應具有比背景數據更少的變化(差異主要來自不同的衣服),不獲取背景數據意味著網絡不需要為不屬於人物的數據分配容量。
不幸的是,FFHQ 數據集的 70,000 張圖片中只有 20,000 張在人臉以下的區域有足夠的數據來按照預期的縱橫比來創造圖片。如圖 11 所示,我並不能使用這個小數據及得到特別高質量的結果,但是仍然可能存在提高質量的方法(比如提升收錄一張圖片的標準)。
圖 11:矩形 FFHQ 圖像趨於低質量
我也對 GAN 在風格化繪畫上的能力很感興趣,我看到最近「Danbooru2018」(https://www.gwern.net/Danbooru2018)發布了。這一數據集有大量高解析度的圖像且帶有非常豐富的標籤數據。
它確實有一些潛在的缺點,比如男性圖像的數量少得不成比例,這大大降低了該類圖像的質量(圖 12)。圖 12 中的男性圖像是從生成的大約 1,000 張圖像中則有挑選出來的質量最高的圖像。我確實認為這方面有很大的提升空間,尤其是針對平均男性圖像使用截斷技巧(truncation trick)。
圖 12:由於數據集的限制,大多數男性肖像(頂部的圖像)畫質均較低。即使隨意挑選,女性肖像(底部圖像)往往具有更高的畫質。以上圖片均未使用截斷技巧來獲得更高質量的圖像。
該數據也包含很大一部分不適合上班時間瀏覽的圖片(羞羞的汙圖),儘管我認為生成式模型的一種潛在用途是自動修改媒體內容以使其更適合於不同的受眾。
我能夠利用收藏該圖片的人數,圖像解析度,標籤,創建日期等元數據,來選擇要收錄的候選圖片。為了減少差異並提高圖像質量,我排除了收藏量很少和六年以前創建的圖片。我也只保留解析度最低為 512x256(高 x 寬)的圖片。512x256 是模型的目標解析度。最後,我過濾掉了一些帶有可能增大肖像風格差異的標籤的圖片,比如「躺著」和「側身」,或者帶有色情暗示的圖片。
為了生成數據,我使用了以下兩個工具的組合,並修改相應的部分以提取所需縱橫比的圖像。
https://towardsdatascience.com/animating-ganime-with-stylegan-part-1-4cf764578e
https://github.com/nagadomi/lbpcascade_animeface
這些工具並不總是正確地提取圖像,所以我使用了「illustration2vec」(https://github.com/rezoo/illustration2vec )來過濾結果,因為那種無法檢測到人的圖像很可能是糟糕的。
我還創建了一個能顯示大的圖像網格的工具,我可以通過它快速手動刪除壞的圖片,但是這對於包含超過 30,000 張圖片的數據集來說太花費時間了。我最終得到的是包含了具有各種質量和標籤的圖像的幾個不同的數據集,圖像的數量從 40,000 張到 160,000 張圖像不等。完成所有這些工作後,我們得到了一個比我構建的擁有 20,000 張圖像的 FFHQ 數據集好得多的一個模型。