對抗生成網絡(Generative Adversarial Network)

本課程是針對李宏毅教授在Youtube上上傳的機器學習課程視頻《Introduction of Generative Adversarial Network (GAN)》的學習筆記。

課程視頻地址

Introduction

某人在Quara上的問題:非監督學習領域最近有沒有什麼突破性的進展呢?

Lecun大神親自回答:對抗訓練可能是有史以來(since sliced bread,有一個好東西出現的意思)最酷的東西。

又有人問:最近在深度學習領域最近有沒有什麼突破性的進展呢?

Lecun大神答:Generative Adversarial Network (also called GAN), it’s the most interesting idea in the last 10 years in ML in my opinion。

  • How to pronounce “GAN” (2333)

Outline

Basic Idea of GAN

我們通常用GAN來生成某些東西,即需要一個生成器(Generator),他可以是一個神經網絡(NN),或者任意一個函數。

那生成器怎麼生成東西呢?我們會餵給生成器一個向量,這樣它就會給定一個我們想要的輸出。至於輸出什麼就取決於我們需要什麼。比如我們需要輸出圖片,那麼實際上生成器就應該輸出一個能表示圖片的矩陣。也可以讓生成器輸出一句話/sequence。

如下圖:我們用二次元人臉生成作爲例子。

輸入給生成器的向量的不同維度代表了輸出結果的某些特徵。比如假設第一個維度代表了人物頭髮的長度,那麼其值越大,生成的人物的頭髮就越長。或者假設倒數第二維決定頭髮是不是藍色;或者假設最後一個維度代表嘴巴是張開的還是閉着的。

GAN的突出部分在於:它還引入了另一個角色–判別器(Discriminator)。

判別器本身也是一個NN。當將一個圖片輸入判別器,它會輸出一個標量(scalar),表示該圖片有多大可能性是人畫出來的,值越大表示它認爲這張圖片越可能是人畫的,反之則認爲是機器生成的。

能不能比較準確地判別取決於判別器學得好不好。

那爲什麼我們會需要判別器呢?

Ian Goodfellow(GAN的作者)給了一個很符合直覺的比喻:

印假鈔的犯罪者會盡量製作和真鈔儘可能想象的鈔票(生成器),而警察會盡力去判別哪些鈔票是真的,哪些是假的(判別器),而針對警察鑑別能力的提升,犯罪者也會不斷針對性地提高印假鈔的技術,使得警察無法鑑別真鈔和假鈔,即騙過警察。

這裏,李老師也舉了一個例子:

枯葉蝶可以很好地僞裝成一個枯萎的樹葉的樣子,但它的祖先其實並不是這樣,而是和普通的蝴蝶一樣顏色五彩繽紛,還很鮮豔。但是枯葉蝶一直有一個天敵鳥,天敵鳥會認爲彩色的明顯是蝴蝶,不會是枯葉的那種棕色的。於是由於物競天擇,枯葉蝶進化了一代,變成了棕色,但是不久後,天敵鳥也學到了,它進一步瞭解到,蝴蝶是不會有葉脈的的。於是又由於物競天擇,枯葉蝶生成了葉脈紋路,進化成了今天的樣子。而,天敵鳥也跟着進化…兩者的進化不斷交替,不斷升級…

在這個例子中,枯葉蝶扮演了生成器的角色,而天敵鳥扮演了判別器的角色。

那生成器和判別器的互動是怎麼進行的呢?

如下圖,一開始,生成器NN的參數是隨機的,給它輸入,它一般會產生很混亂、不符合期望的圖片。而我們會給它喂人造的圖片(real images),讓它學習人畫的圖片是什麼樣子的,有哪些特徵?然後判別器就來判斷:某張圖片是生成器生成的,還是人畫的。

比如,可能第一代的生成器(v1)很弱,只能生成黑白的圖片,而人造圖片都是彩色的,所以判別器只需要看圖片是黑白還是彩色就能準確判斷。

那麼接着,生成器就會有針對性地進化到第二代(v2),進化的方向是能夠騙過當前的判別器,比如第一代的判別器靠顏色來判斷,那生成器就會開始也生成彩色圖片。

而判別器發現它會被生成器僞造的的彩色圖片騙過後,它也會開始有針對性地進化,即開始嘗試發現真實彩色照片和生成器僞造彩色照片之間的差別,比如說可能僞造的照片都沒有嘴巴,而真實的照片都有。於是,判別器開始根據有無嘴巴來判斷。

那麼,接着,生成器也繼續進化(v3),開始畫嘴巴…兩者如此互相交替循環地針對對方的新能力進行進化,互相角力,促使彼此都做得更好。(這也就是對抗生成網絡中的“對抗”(adversarial)一詞的由來)

  • 那爲什麼不能說生成器和判別器是合作互相促進呢?

答:其實也可以,只是說法問題。我們再看下面的例子:

把生成器看做學生,判別器看做老師。老師知道什麼樣的人物畫是好的,什麼樣的不好,而學生就要和老師學習判別的能力。

那麼一年級的學生(v1)什麼都不會,畫的東西給一年級老師看,一年級老師指出來不行,沒有眼睛。

然後學生學了一年畫眼睛後,把畫給現在的二年級的老師看,以爲二年級的老師會表揚他畫得好,結果二年級的老師說,不行,沒有嘴巴。

然後學生又學了一年畫嘴巴….

這樣,學生畫的越來越好,老師也變得越來越嚴格。

這樣,我們又有了兩個新的問題:

  • 爲什麼生成器不能自己照着真實圖片學,非要判別器和它對抗呢?
  • 爲什麼判別器不自己做呢?(自己畫好的東西)

接下來,我們將逐漸嘗試回答上述兩個問題。

老師自己用GAN做的成果:

  • update 100次:

  • update 1000次:生成器學到了要產生眼睛

  • update 2000次:生成器學到了要產生嘴巴

  • update 5000次:生成器學到了動漫人物要有水汪汪的大眼睛

  • update 10000次:

  • update 20000次:生成器學到了不能有模糊的部分

  • update 50000次,收斂:生成器學到了不能有兩個眼睛不一樣的圖片,整體效果不錯,不過仍有些圖片有大小眼問題。

如下圖,那麼除了產生二次元人物頭像以外,還能用於產生真人頭像。但是這樣做的意義在哪裏呢?如果只是要獲得頭像,去街上拍照不是會更快嗎?

不過,GAN厲害的地方在於,它能產生本來不存在的頭像,但它卻非常像實際中可能存在的真人的頭像。

但是,光讓機器產生人物頭像是沒有什麼特別的地方,因爲機器很有可能是“背好了”訓練數據中的圖片,而我們需要生成器去輸出一張照片時,它可能只是在訓練數據裏找了一張背好的圖丟出來即可。

那麼,爲了避免生成器背圖,我們可以怎麼做呢?

答:我們可以要求生成器產生兩張圖片的interpolation(竄改,插補)。

如下圖,我們假設生成器在輸入[0,0]時,會產生最左邊的圖片,輸入[0.9,0.9]時,會產生最右邊的圖片,那麼輸入[0,0]和[0.9,0.9]之間的各種向量時,就會產生中間狀態的圖片(比如從嚴肅臉到微笑臉,從頭向左看到向右看),而這些中間狀態的圖片就是本來不存在的一些圖片,這些圖片狀態時機器自己學到的。

不過到現在爲止,舉得例子都是GAN做影像生成,似乎GAN的用途還是不甚明確。

When do we need GAN?

有些人認爲:GAN可以用來生成更多訓練數據,幫忙解決訓練數據少的問題

但是李老師不是很贊成這個想法:比如如果要訓練一個馬的判別器,而假設已有的訓練數據中的馬都是朝左側的,那就算用GAN也只能生成朝左的馬,不會生成很不一樣的訓練數據,不如自己蒐集更多的數據更有效率。如果要讓GAN產生更多的有用的數據,前提是需要加入更多的信息。比如,訓練數據的馬都是朝左的,但是還有別的斑馬的數據,有些斑馬是朝右的,那麼利用後面會講到的cycle GAN就可以生成朝左的馬的數據,就可能有用。

另外,如果要訓練的分類器是不具備泛化能力的(比如knn分類器),它看過的圖片越多,能力就一定會越強。但是,像NN這樣具備很泛化能力的,不一定更多的照片會有更好的效果。而針對類似knn的分類器,GAN生成的更多的數據也會是有用的。

這裏李老師指的“泛化能力”不太明白其意思,存個疑。

李老師認爲GAN可以用到的地方:

  • Structured Learning

結構化學習會要求機器輸出一個複雜的object,它是由很多組件(component)以一定方式組合而成的。而很多機器學習的教材可能不教結構化學習,甚至會說,機器學習的問題只包含迴歸和分類,這就好比告訴你,這個世界就是這五大洲,而其實這個五大洲之外還有一個很大的黑暗大陸(李老師23333),那就是結構化學習。而從五大洲到黑暗大陸的一個跨越途徑,就是GAN。

所以GAN的應用其實還蠻廣泛的

在輸出序列方面:

  • 機器翻譯
  • 語音識別
  • 聊天機器人

在輸出矩陣方面:

  • 圖片生成(模型圖轉真實圖片,圖片上色)
  • 根據文本敘述生成相應圖片

在決策制定與控制方面:

之前在強化學習裏面提到過,Actor會採取一系列的action來應對Observation,而這些action共同組成了一個序列(sequence)的整體,所以這種問題也可以看做是一種結構化學習的問題。因此,我們也可以嘗試把GAN的概念引入。

  • 爲什麼結構化學習很具有挑戰性呢?(機器解結構化學習能力必須具備的能力)

1.因爲結構化學習本身是一個One-shot/Zero-shot Learning的問題:

One-shot/Zero-shot learning是遷移學習課程中講到過的概念,可以回顧一下。簡而言之,就是某些類的訓練數據很少,只有一個,或者甚至是沒有。

在一般的分類問題中,每個類都是有對應的一些訓練樣例的。但是在結構化學習中,如果把每個可能的輸出都當成一類,那很可能所有可能的輸出是一個無法窮舉的集合。所以訓練的時候,很多類都沒有對應的訓練樣例的。

因此,在一般分類中,機器實際上做的事情可以稱之爲“歸納”,即每個類都給定一些樣例,機器去歸納每個類對應的特徵有哪些。但在結構化學習中,機器需要“創造”,因爲它要面對從未見過的類。

2.機器必須有規劃(planning)的能力/大局觀

機器生成對象時,是逐元素(component-by-component)進行的(生成句子時是逐字進行,生成圖像時,是逐像素進行)。因此,如果要生成有意義的、人看的明白的對象,就需要機器有“大局觀”,即它最後生成的對象是要在整體上合理的,即機器在產生每個元素時,它需要進行全局考慮

如下圖,在圖像生成中,在圖的中央點一個點本身無好壞之分,但是在生成數字1和數字0時所產生的對圖像的影響就完全不一樣,因此機器在生成數字時需要考慮每個元素是否在整體上看來也是合理的。

還有在語句生成中(比如詩句生成中),也是這樣。

  • 結構化學習的途徑

    • Bottom Up:學習去逐元素的產生對象。
    • Top Down:評估對象整體,並找到最好的那個。(疑問是:怎麼用top down的方法去產生對象,因爲它好像只學會瞭如何評估一個對象)

而其實,GAN中的生成器採用的就是bottom up的方法,而判別器採用的就是top down的方法

GAN as structured learning algorithm

做Generation方面,GAN生成器可以接收向量然後生成圖像或句子等,但是光這麼做似乎用處不大。真正有用的應該是Conditional Generation(讓機器根據不同的情境產生不同的輸出)。

這裏有學生提到輸入向量的維度問題:怎麼確定輸入維度,能不能和圖片的維度一樣,甚至超過圖片的維度。但李老師也不確定,讓學生在做作業時嘗試一下。

如下圖,回到之前的兩個重要問題,我們現在來嘗試回答:

問題一:爲什麼生成器不自己學

其實按理來說,生成器完全可以自己學,它只要有輸出的目標圖片和對應的圖片輸入向量(編碼,code)就可以自己去訓練了,不過一般來說,目標圖片我們是比較容易蒐集的,關鍵在於圖片對應的輸入向量從何處來呢?

先假設我們有辦法獲得目標圖片的對應編碼,那麼我們對每個圖片現在都能獲得一個編碼,然後我們就拿編碼當輸入數據,讓生成器儘量產生和目標圖片相近的圖片就好了。

而這個過程我們可以對照分類任務來看:分類是輸入圖片(高維),然後輸出圖片所屬的類別(低維)。

那麼,問題就落腳到了如何獲得圖片的編碼上,我們的做法是:訓練出一個自編碼器(Auto-encoder)

自編碼器的詳細知識可以參考前面已有的同名博客。

自編碼器本質就是對輸入數據做降維,獲得輸入數據的低維編碼。

  • 快速帶過自編碼器的知識:

編碼器(encoder)和解碼器(decoder)單獨都無法學習,需要合作。

那麼GAN中的生成器做的事情就很像自編碼器中的解碼器:吃進編碼,輸出圖片

因此,學出一個自編碼器,拿出其中的解碼器,就可以當做一個GAN的生成器。

  • 下面是MNIST上的嘗試效果:

回到GAN!好,那麼現在我們也可以獲得目標圖片的編碼了,但是還有一個問題:

假設我們有編碼a和編碼b,但是很有可能,我們沒有編碼a和b以某種方式(比如平均)組合所得的編碼對應的目標圖片,那面對這種編碼,生成器該如何生成圖片?可能生成器只能產生noise。

解決這種問題的方法之一是用VAE(Variational Auto-encoder)

VAE就是編碼器在產生編碼的同時,還會產生一組隨機噪聲(服從正態分佈),並把噪聲和編碼組合加在一起,給解碼器訓練。於是利用VAE,我們可以增強解碼器的抗干擾能力,即它面對沒看過的編碼,也可能輸出好的結果。

不過同樣地,編碼器生成噪音時,爲了減小reconstruction error,它會有動機將噪音全部設置爲0,這樣就回到了普通的自編碼器,於是我們需要在噪音過小時,給自編碼器一些懲罰(penalty)。

  • 還少了什麼?

目前看來沒什麼問題,

思考:生成器在學習做生成的時候,它是怎麼學的?

學習過程中,希望目標圖片和生成圖片越接近越好(接近即:兩張圖片pixel-wise的l1或l2範數),而如果生成器可以完全地複製目標圖片,看起來似乎沒什麼問題。但是這樣產生和已有數據一模一樣的數據就又沒什麼意義了,於是我們要允許生成器犯一點錯誤。不過錯誤有嚴重的,有輕微的…

但是如下圖,問題在於:有時候的錯誤雖然較少(像素的錯誤),但是反而是更不能接受的結果。比如下面四副圖中的上面兩幅,都是一個像素的錯誤(多了一點或少了一點),而下面兩幅都是六個像素的錯誤。可是上面兩幅的小錯誤就造成了整幅圖的不合理,而下面兩幅圖就還能夠接受!

因此,組件之間的關聯是很重要的。(還是上圖的例子:我們更希望,如果生成器多塗了某個點,則它應該把和主體以及多塗的點之間的點也都塗上顏色,這樣才比較合理)

而聯繫到NN模型本身,因爲生成器本質就是一個NN,它的最後一層輸出層的每個神經元都和一個輸出圖片的像素相對應,於是當輸出層某個神經元要輸出顏色時,它會希望它相鄰的神經元也輸出顏色(“旁邊的,我們產生一樣的顏色”),但是輸出層的任一神經元的輸出都是由上一個隱藏層決定的,因此不會受相鄰神經元的影響(“誰管你!”)。

那怎麼辦呢?

答:用深度架構去捕捉組件之間的關係。

假設我們現在想要一個生成器學習生成下圖中藍色的點,那麼我們就可以訓練一個VAE,但是我們會發現很難讓生成器擬合目標點。雖然生成器知道藍色點密集的地方,但是它也會在密集區之間也產生很多點。

這裏不太明白李老師想表達的意思…

問題一:爲什麼機器不自己做

判別器一直在批評,那它爲什麼不自己來做呢?

  • Discriminator

判別器可以看做一個binary的分類器,其本質是一個函數D(網絡,可以是深層的)。

判別器在不同的文獻上還有不同的名字:評估函數(evaluation function),potential function(潛在函數),energy function(能量函數),它們的作用和判別器一樣。

問題是:我們能用判別器來產生對象嗎

答:可以!

top-down的方法(判別器的學習策略)更容易捕捉到組件之間的關係。

舉例來說,對於下圖中的兩個“2”圖像,判別器可以很容易地學習到應該給左邊多了一個像素顏色的“2”打較低分,給右邊的“2”打較高分。

  • 怎麼用判別器生成對象

窮舉所有input,哪個input能夠在判別器這裏得到相應最好的分數,那個input就作爲輸出。

但是,窮舉x看起來是個很荒謬的做法!!!不過,我們先假設能做到…

於是,問題再次落腳到:我們怎麼訓練出一個判別器去判斷對象的好壞呢?

常規思路當然是:給判別器一些分別對應好的對象以及壞的對象的訓練數據。

不過,我們手上一般只有好的對象的數據(人手繪的圖),所以光有這些數據,判別器肯定是沒辦法學的。因此,我們需要一些負例(Negative Examples)

就好比一個小孩從小在都是好人的世界裏成長,長大後他就會以爲人人都是善良的,它無法分辨善惡,明辨是非。

那怎麼產生負例呢?

有人想到,可以隨機生成一些很爛的圖片作負例,但是這樣會有一個問題:當判別器碰到實際也很差,但是因爲之前給它學的圖片都太爛了,導致它認爲只要是比它學的那些圖片好一點的,都能打高分,那也不行。

好比每天讓人吃難吃的草根、昆蟲,突然有一天給了他一桶方便麪,他便堅定認爲方便麪是世界上最好吃的事物,這種打分是有失偏頗的。

因此,要學出好的判別器,我們給它的負例也一定要越接近真實越好。

比如下圖中的右邊兩張圖,我們生成一個很接近真實圖片的人物圖,但是由於她的眼睛是異色的,所以它其實也是一個負例。那麼判別器就從這個負例中學到:好圖的任務眼睛應該是同色的。

那又要怎麼產生非常好的假的圖片呢?

誒!注意了!這個問題不就是我們【生成器】的要求嗎?那麼,這樣一想,生成器和判別器的訓練問題,不就成了一個雞生蛋,蛋生雞的互相依賴了嗎?這不就跟自編碼器很像嗎?

  • 判別器——訓練

    • 一般算法

    先用已有的正例和隨機生成的一些負例訓練判別器,然後再用訓練後的判別器生成一些新的負例。

    再用新的負例和原來的正例一起訓練判別器,再讓訓練後的判別器生成新的負例。

    迭代上述過程……

下面我們再換個方式講解一下判別器的訓練過程。

如下圖,假設對象只有一個特徵,橫軸代表特徵的取值,縱軸是判別器給對象的打分。綠色的點代表真實樣例,藍色的點代表假的樣例(負例),我們希望判別器學習後的效果是:真實樣例點對應的評分更高,假樣例點得到的評分更低。不過,因爲我們不可能窮舉所有假的樣例,因此,如果要全面降低非真實樣例分佈的區域的評分值,我們需要用一些聰明的方法來找出需要壓低的區域。

如下圖,假設最開始學出的判別函數的分佈如最上面的那副圖,於是當我們再次用判別函數隨機生成一些負例後,再用新的負例和原來的正例更新判別器參數時,判別器函數的分佈就會變成中間的那副圖,再重複一次,得到最下面的圖……最後,我們的判別器所產生的樣例和正例是重合的,即判別器函數和正例的分佈基本相同。

  • 李老師轉談結構化學習的架構

  • 生成器和判別器的優缺點

生成器+判別器

由生成器來解argmax問題:生成器生成的x˜ 就是argmax問題的解

現在,我們希望找到一些image,它丟到判別器裏產生的output值越大越好(之前我們單獨針對判別器討論時,說的是窮舉所有image),而現在,我們要用生成器來產生這些image。

因爲生成器和判別器本質都是神經網絡(假設都是5層的NN),那麼我們現在將兩個NN接在一起,作爲一個NN的隱藏層(10層),整個新NN的輸入是code,輸出是評分。

假設我們要生成的image是100*100像素的,那麼隱藏層第五層的神經元的數目就是100*100,它的輸出拿出來就是對應的image。

而我們訓練的目的就是使得最後的評分儘可能的高,而方法就是不斷去調生成器的參數(梯度上升)。

  • 訓練方法

  • GAN的好處

    • 從判別器角度來看:生成器是用來生成負例的;
    • 從生成器角度來看:它自己仍然是一個一個組件地在生成對象,不過它從判別器那裏學會了大局觀。

  • 例子

訓練目標是產生下圖中藍色的點,但訓練好後,GAN也會產生一些非藍色區域的點。以及VAE和GAN比較起來,VAE生成的圖片大多比較模糊(藍點羣之間的離異點)。

Conditional Generation by GAN

之前,生成器都是在隨機生成一些圖片,不過現在,我們希望機器能根據指令來生成對應圖片。

我們之前講到,input code的不同維度就對應了一些圖片的特質,但是我們如何把維度和特質一一進行對應起來呢?

我們現在有一個生成器(輸入z,輸出x),可是我們的問題是:給定x,我們怎麼知道對應的z是什麼樣子的?

答:借鑑自編碼器的思想,訓練一個編碼器(輸入x,輸出z)。

當我們獲得了一個訓練好的編碼器,它就能幫我們確定一個圖片對應的正確編碼是什麼樣子。

下圖中,我們將短髮人物變成長髮人物(En(x)代表編碼器函數)

下面是NVIDIA做出來的一個效果:

  • Conditional GAN

如下圖:如果用監督學習的方式來做根據指令(比如”正在行駛的火車“)生成圖片,那麼機器會產生模糊的結果,因爲對於監督學習模型來說,它會從自己的數據庫裏面去找到所有符合指令的圖片,並取它們的平均,而這個結果不是我們想要的。

因此,我們需要用GAN的思路來做:我們給生成器輸入指令c和先驗分佈z,c控制生成圖像的內容(火車對象),而z控制生成圖像的具體形式(正面的火車還是側面的火車)。

那麼,判別器該怎麼設計呢?

如果只用傳統的方法,讓判別器去關注生成器的結果是否足夠真實,則這回促使生成器根本不在意我們的c輸入,而只輸出判別器會打高分的內容(比如我們想讓生成器生成”火車“,但是判別器目前的狀況是隻認爲含有貓的圖片是真實的,於是促使生成器生成貓的圖片,而不生成火車)。

爲了避免這個問題,我們要讓判別器同時關注生成器的輸入與輸出,即它給出的評分包括兩部分:

  • x是否真實?
  • c和x是否匹配?

  • 文獻中的例子

輸入文字,產生對應圖片:

輸入圖片,產生圖片:

這種GAN怎麼訓練呢?

這種技術可以應用於:

  • 低像素圖片的清晰化

  • 影片生成

  • 語音去噪

發佈了81 篇原創文章 · 獲贊 193 · 訪問量 32萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章