StyleGAN:可以操控的生成
在這個系列裡,你已經從「辨識影像」走到「想像影像」,從機率式的 VAE 走到 GAN 的對抗對決,再走到讓這場對決能穩定訓練的硬功夫。現在我們抵達 GAN 影像品質的最高點——這個架構第一次生成出銳利到幾乎騙過所有人的人臉:StyleGAN。它生成的「不存在的人」照片成了大眾對 GAN 能力的印象,而它也是最完美的收尾,因為它把你學過的一切融合成一台「可操控」的機器。
標準 GAN 的生成器拿一個隨機雜訊向量——也就是一個 潛在變數——直接餵進第一層,再讓網路把它「長」成一張影像。StyleGAN 用兩個步驟做得更聰明。第一,它先讓雜訊通過一個小小的「映射網路」(只是幾層全連接層),把原始雜訊轉成一組中間編碼。第二,它不再只在最底層餵進一次,而是用一種叫做自適應實例正規化(AdaIN)的機制,把這組編碼當成「風格」注入到 生成器 的每一層。於是同一組學到的風格編碼,會在每一個解析度上都有發言權——從最粗的 4×4 特徵圖,一路到最細的 1024×1024 細節。
示意圖:生成器從潛在編碼產生影像,由判別器判斷為真或假。
把它想成一位分階段作畫的畫家。一開始他先打底構圖——頭擺在哪、面朝哪個方向、臉的整體輪廓。之後才慢慢修飾細節——皮膚的質感、一根一根的髮絲、眼睛裡的反光。StyleGAN 的各層運作方式一模一樣:注入在粗略、早期層的風格控制「大東西」(姿勢、臉型、人物朝左還朝右),而注入在精細、後期層的風格控制「小東西」(膚質、雀斑、髮絲細節、光照)。因為每一層都有自己的風格輸入,你可以拿 A 臉的粗略風格、配上 B 臉的精細風格——這就是風格混合(style mixing),也是為什麼 StyleGAN 能在保留 A 的姿勢與身分的同時,借用 B 的髮質與膚色。
自適應實例正規化:先把特徵圖正規化,再用風格指定的統計量重新蓋印上去。
我們把 AdaIN 一塊一塊拆開來看。在生成器內部,正在成形的影像是以一疊特徵圖的形式存在;x_i 就是其中一張特徵圖(一個通道)。μ(x_i) 和 σ(x_i) 是這個通道自己的平均值與標準差——它目前的「統計量」。式子 (x_i − μ(x_i)) / σ(x_i) 其實就是正規化:把這個通道自身的亮度與對比剝除,留下一個平均為 0、散布為 1 的標準化樣式。接著 y_{s,i} 和 y_{b,i}——由這個通道對應的風格編碼算出的縮放與偏移——把新的統計量重新蓋印上去:乘上新的縮放、加上新的偏移。一句話總結:把每張特徵圖自身的統計量剝掉,再蓋上由所選風格指定的統計量——這個「重新蓋印」就是風格在那一層被「畫」到影像上的字面動作。具體來說,假設某通道目前平均 μ = 4、標準差 σ = 2,而某個像素 x_i = 8。正規化得到 (8 − 4)/2 = 2。如果風格要求縮放 y_s = 0.5、偏移 y_b = 10,輸出就是 0.5 × 2 + 10 = 11。改變風格的 y_s 與 y_b,同一個底層樣式就會變得更亮、更暗、對比更高或更低——這就是「風格在發聲」。
W 空間與截斷技巧
我們先前略過了一個值得單獨聚焦的細節:映射網路產生的中間編碼住在一個慣稱為 W 的空間裡,而這些編碼本身仍是 潛在變數——只是「規矩」得多。W 最重要的性質叫做解耦(disentanglement)。簡單說,當你在潛在空間裡能移動的每一個方向,都各自控制一個對人類有意義的屬性——年齡、微笑、或一個人面對鏡頭的程度——而不會牽連到其他屬性時,這個空間就是解耦的。沿著「年齡」方向移動,臉會變老,但身分、姿勢、光照都保持不變;這種乾淨的分離,正是解耦的意思。
為什麼多加一個映射網路就能換到這個好處?原始雜訊空間(叫它 Z)被強制成一個簡單的形狀——通常是一顆圓圓的高斯球。但真實的人臉分布並不是圓的:有些組合很常見(年輕又微笑的人),有些很罕見甚至不可能(嬰兒長鬍子)。如果你硬要直接從一顆圓球上讀出屬性,屬性就會糾纏在一起——推動一個旋鈕,無可避免會扭到好幾個,因為這顆球必須被拉扯、摺疊,才能覆蓋一個歪斜的現實。映射網路的任務,就是替你做這個拉扯與摺疊:它把圓的 Z 扭曲成一個形狀貼合「人臉真正如何變化」的 W 空間,於是在 W 裡,有意義的方向會對齊並乾淨地彼此分開。
第二個概念是截斷技巧(truncation trick),而且它出乎意料地實用又好上手。先在大量樣本上算出平均的 W 編碼——把它叫做「平均臉」。要生成一張新臉時,先抽一個新的 W 編碼,再在生成之前把它往平均臉「拉近」一段,用一個介於 0 到 1 的旋鈕 ψ 控制要拉多近。ψ = 1 時保留原樣本(變化最豐富);ψ = 0 時每次都塌縮到平均臉(完全沒有變化);像 ψ = 0.7 這種值則落在中間。代價是一個直接的取捨:靠近平均的編碼正是 生成模型 最有把握的地方,所以往內拉會得到更乾淨、更逼真的臉——但臉也會變得更相似、更「平均」、更不多樣。這是一個可調的「品質對多樣性」旋鈕,也正是第 4 篇「模式覆蓋」張力的具體回響:在那裡,我們擔心 GAN 會不小心只覆蓋太少的模式;在這裡,我們刻意拿一些覆蓋率去換品質,只不過現在它是我們能掌控的旋鈕,而不是被迫承受的失敗。
pix2pix:成對的影像轉影像
到目前為止,我們建的每一個生成器都從雜訊開始。但這項技術最實用的應用形式恰恰相反:不是憑空變出一張影像,而是「轉換」一張你已經有的影像。這就是影像轉影像(image-to-image translation),而經典方法是 pix2pix。它的想法是把 GAN 做成有條件的——一個 條件式 GAN 在某個額外輸入的條件下產生輸出,而在 pix2pix 裡,這個輸入本身就是一張影像。餵它一張手繪草圖,得到一張照片;餵它一張街道地圖,得到對應的衛星影像;餵它一條邊緣輪廓,得到一張貓的照片。生成器的任務不再是「做出任何一張像樣的臉」,而是「做出對應於『這個』輸入的那張特定輸出」。
有兩個架構選擇讓 pix2pix 能運作,兩者都值得具體理解。第一個是生成器:pix2pix 使用 U-Net,也就是你在影像分割系列見過的「編碼器—解碼器加跳接」設計。編碼器把輸入影像壓縮成一個小而抽象的摘要;解碼器再把這個摘要展開回完整解析度的輸出。關鍵在於跳接(skip connections):在每一個解析度上,編碼器都把它的特徵圖直接遞交給對應的解碼器層。為什麼這在這裡很重要?因為在影像轉換裡,輸出和輸入在空間上是對齊的——地圖上某處的屋頂,應該變成衛星照片上同一處的屋頂。跳接讓精細的空間細節(精確的邊緣、準確的位置)繞過那個狹窄的瓶頸,存活到輸出裡,而不是被壓縮過程糊掉。
U 形網路:左側下採樣編碼器、右側上採樣解碼器,並以水平跳接連接對應的層級。
第二個選擇是判別器。pix2pix 不看整張影像然後吐出一個「真或假」的單一判決,而是使用 PatchGAN:它在影像上滑動,評斷許多小的局部區塊——比方說各 70×70 像素——對每一塊問「這塊看起來像真的嗎?」,再把答案平均起來。這讓 對抗損失 聚焦在局部的紋理與結構上,而那正是「逼真」所在之處(皮膚毛孔、磚塊紋理、葉緣);它還有一個實際好處:評斷固定大小的區塊,所需參數遠少於評斷一整張高解析度影像。結果就是用更低的成本得到更銳利的紋理。
pix2pix 的目標函數:一個負責逼真的對抗項,加上一個負責忠於成對目標的 L1 項。
完整的目標函數有兩部分。對抗項 L_adv 就是前幾篇熟悉的「偽造者對偵探」遊戲:它逼生成器 G 做出讓 PatchGAN 分不出真假的輸出。第二項是新的。這裡 x 是輸入影像,y 是真正的成對目標(與這張草圖搭配的真實照片),G(x) 是生成器的嘗試。項 ||y − G(x)||_1 是 L1 距離——把生成像素與目標像素之間的絕對差加總起來——它把輸出釘在已知的正確答案上,於是生成器不能只是產出「一張」逼真的照片,而必須產出「那張正確」的照片。λ(lambda)是權重,常設在 100 左右,決定這個忠實項對抗逼真項的力道有多強。一個細微但重要的細節:pix2pix 用 L1(絕對差)而不是 L2(平方差),正是為了對抗我們在第 2 篇 VAE 看到的模糊問題——L2 會獎勵生成器用「把好幾個合理答案平均成一團糊」來避險,而 L1 則容許「果斷地押注在一個銳利的答案上」。具體來說,若某目標像素是 180、生成器輸出 200,這個像素就對 L1 總和貢獻 |200 − 180| = 20;對每個像素加總起來,就是讓轉換保持誠實的壓力。而這裡有一個定義了 pix2pix、也鋪陳本篇其餘內容的關鍵限制:它需要成對的訓練資料——每個輸入都必須附上它精確對應的目標。草圖配照片、地圖配衛星:得有人去蒐集,而且要完美對齊;對許多問題(把馬變成斑馬)來說,這種成對資料根本不存在。
CycleGAN:不需成對資料的轉換
pix2pix 很強大,但它對「完美成對資料」的胃口是一道真實的牆。你永遠不會有一張「同一匹馬、同一個姿勢」的照片,一次是馬、一次是斑馬。你能輕鬆蒐集到的,是一堆馬的照片,和另一堆彼此不對應的斑馬照片。CycleGAN 正是那個突破:它學會在兩個這樣的領域之間互譯,而且完全不需要任何成對範例——它的做法是重複利用 pix2pix 的對抗機制,再加上一個漂亮的額外點子。
CycleGAN 同時訓練四個網路:兩個 生成器 和兩個 判別器。一個生成器 G 學著把領域 X 變成領域 Y(馬 → 斑馬);另一個 F 學反方向,Y → X(斑馬 → 馬)。每個領域各有自己的判別器,把關輸出看起來是否像該領域的真正成員。但光靠對抗壓力還不夠:G 可能學會「對任何一匹馬都輸出『某一隻』逼真的斑馬」,卻完全無視拿到的是『哪一匹』馬。解法是循環一致性(cycle consistency):如果你把一匹馬轉成斑馬、再把那隻斑馬轉回去,你應該要還原出原本那匹馬。把它想成把一句話從英文翻成法文、再翻回英文——如果回來是一團亂碼,這趟來回就不忠實;如果回來幾乎沒變,這個翻譯就保住了意義。CycleGAN 對它的影像翻譯器要求的,正是同一種忠實。
一組生成器與判別器;CycleGAN 使用兩組這樣的配對,一組把 X 翻成 Y,一組把 Y 翻成 X。
循環一致性損失:對「來回往返」偏離原圖的程度做懲罰,兩個方向都算。
把這個損失讀成兩趟來回。在第一項裡,x 是領域 X 的一張真實影像(一匹馬)。G(x) 把它送到領域 Y(一隻斑馬),接著 F(G(x)) 再把它帶回領域 X(又變回一匹馬)。如果系統忠實,F(G(x)) 應該等於原本的 x;任何差異都會被 ||F(G(x)) − x||_1 懲罰,也就是來回往返後的影像與原圖之間的絕對像素差總和。第二項做的是鏡像的旅程,從一隻真實斑馬 y 出發:G(F(y)) 應該還原出原本的 y。兩項相加,就讓兩個方向都保持誠實。最深刻的一點,是這個約束「取代」了什麼。在 pix2pix 裡,對真實目標的 L1 項是忠實的來源——但那需要成對資料。在這裡沒有目標可比對,所以「來回往返」本身就成了監督訊號:生成器要滿足循環一致性,唯一的辦法就是保留底層的內容(馬的姿勢、位置、形狀),只改變風格(毛色從棕色變成條紋)。如果 G 把內容丟掉了——比方說把每匹馬都對應到「一隻記住的斑馬」——F 就永遠無法重建那張特定的原圖,損失就會狠狠懲罰它。這正是循環一致性能阻止生成器作弊的原因。
# One CycleGAN training step (pseudocode). # G: X -> Y, F: Y -> X, D_Y and D_X are the domain discriminators. x = sample_real(domain_X) # e.g. a horse photo y = sample_real(domain_Y) # e.g. an UNRELATED zebra photo # 1. Translate across domains fake_y = G(x) # horse -> zebra fake_x = F(y) # zebra -> horse # 2. Translate back -- the round trip rec_x = F(fake_y) # horse -> zebra -> horse, should match x rec_y = G(fake_x) # zebra -> horse -> zebra, should match y # 3. Cycle-consistency loss: L1 over both round trips loss_cyc = L1(rec_x, x) + L1(rec_y, y) # 4. Adversarial loss: make each translation look like its target domain loss_adv = adv(D_Y, fake_y) + adv(D_X, fake_x) # 5. Total generator loss; lam weights faithfulness vs realism loss_G = loss_adv + lam * loss_cyc update(G, F, minimize=loss_G) update(D_X, D_Y, ...) # discriminators learn to spot the fakes
選對工具,以及通往擴散模型的路
退一步看整個系列。你現在掌握了兩大類生成模型,也能看到第三類正在地平線上浮現。誠實的事實是:沒有哪一種放諸四海皆最好;每一種都做了不同的取捨,而高明的實作者會依照眼前的任務來選擇。
VAE(變分自編碼器,第 2 篇)是穩定、機率式的選擇:它訓練可靠,給你一個乾淨又有結構、容易抽樣與內插的潛在空間,還附帶一個明確的機率目標——但它的影像往往偏模糊,因為在概似損失下做重建會獎勵「安全的平均」。GAN(第 3–5 篇,包含 StyleGAN)是銳利、可操控的選擇:在最佳狀態下能產出最銳利、最逼真的結果,並提供像風格混合、解耦編輯這類了不起的把手——但它出了名地難訓練,可能塌縮到少數幾個模式,而且不給你一個乾淨的概似可供推理。擴散模型(diffusion models)是之後某個系列的主題,是較新的後起之秀,如今在品質與穩定性上都領先:它從純雜訊出發,分許多步、每次去除一點點雜訊來生成,因此能像 VAE 一樣穩定訓練,卻達到超越 GAN 的影像品質——代價是抽樣慢,因為它要走很多步。
那你該伸手拿哪一個?如果你需要一個整理良好的潛在空間來做下游任務——分群、平滑內插、異常偵測——或者你單純需要穩如磐石的訓練,VAE 是穩健的首選。如果你需要在像人臉這類受限領域裡達到最高的銳利度與細緻的創作操控,而且願意投入心力細心訓練,那麼像 StyleGAN 這樣的 GAN 仍然出色;至於影像轉影像的工作,pix2pix(在你有成對資料時)或 CycleGAN(在你沒有時)就是首選工具。如果你想要頂尖的品質與文字生成影像、又能容忍較慢的抽樣,擴散模型是現今的預設選擇——這也正是為什麼之後有一整個系列專門講它。
一個序列:從左邊一片隨機雜訊,逐步去雜訊,到右邊一張銳利的影像。
這裡有一條把一切串起來、又指向下一步的主線。本系列裡的每一個模型,追逐的都是同一個目標:把真實影像的分布 p(x) 學得夠好,好到能從中抽出全新的樣本。一個 生成模型 不多也不少,就是這件事。VAE 用機率式的編碼器—解碼器去追它;GAN 用對抗對決去追它;而你接下來會遇到的擴散模型,用一個截然不同、迭代式的點子去追同一個 p(x)——逐步把隨機雜訊去噪成一個樣本。你離開這個系列時,已經深入理解了三大途徑中的兩個,也準備好把第三個,認出是對一個你早已了然於心的問題所給出的全新答案。