JOVANA
Explore Library Glossary Getting Started Three Levels Fields How it works Mission
Join the mission
All guides

精通控制:影像編輯、ControlNet 與前沿

從「生成」邁向「導演」——填補遮罩區域、用邊緣或姿態鎖定構圖、比較 DALL-E 的設計取捨,並正視合成影像真實的極限與倫理。

模型動物園:DALL-E 與同伴們

你現在已經完整理解了一條文字生成圖像的流程:文字提示引導一個 U-Net 去對微小的潛在表示去噪,再由解碼器轉成像素。這個心智模型就是你的地圖圖例——幾乎每個知名系統都是它的變體。所以在我們學會「控制」這些模型之前,先逛一逛這座動物園,看看大型動物之間有何不同。先講重點:它們全都共用你在第 2、3 篇學到的同一個擴散核心。沒有任何一個發明了全新的造圖方法;它們只是在「什麼東西在條件化去噪器」、「用什麼資料訓練」、以及「擴散在流程的哪個位置執行」這幾點上做了不同選擇。

看看 DALL·E 2。它最關鍵的選擇是把一切都導流經過 CLIP——就是那個替「圖像與文字是否相符」打分的視覺—語言模型。DALL·E 2 不把文字直接餵給去噪器,而是先訓練一個小型的先驗(prior)網路,把 CLIP 的「文字」嵌入映射成 CLIP 的「圖像」嵌入(也就是猜「在 CLIP 的座標系裡,相符的圖片大概長什麼樣?」)。接著第二個擴散解碼器以那個 CLIP 圖像嵌入為條件來生成圖像。這種兩階段的「unCLIP」設計,意味著真正的圖片是以一個「圖像形狀」的向量為條件,而非生硬的文字——這往往帶來乾淨、連貫的構圖,也讓產生變體變得容易(用同一個嵌入重新解碼,就會得到同一張圖的兄弟姊妹)。

DALL·E 3 動的是另一根槓桿:語言理解。它的洞見是:大部分失敗來自「模糊或描述不足的提示」,所以它把圖像模型與一個大型語言模型(LLM)緊密耦合。當你打「一隻貓在椅子上」,LLM 會在擴散模型看到之前,悄悄把它改寫成一段長而生動的描述——顏色、姿態、光線、背景。它同時也用「圖像配上這些更豐富的機器撰寫說明」來訓練,因此學會了遵循細緻的指令與複雜的場景(甚至能更可靠地把招牌上的短文字畫出來)。底層的擴散引擎仍然在做第 3 篇那件事;LLM 只是坐在它前面的一位聰明翻譯。

兩條軸線就能整理整座動物園。第一條是擴散在哪裡執行。早期的 DALL·E 與 Imagen 在「像素空間」去噪(通常先生成小圖,再用獨立的放大模型放大),而 Stable Diffusion 則在你學過的壓縮「潛在空間」去噪——也就是那個讓它便宜到能在筆電 GPU 上跑的 潛在擴散 技巧。像素空間可以很銳利但昂貴;潛在空間快又省記憶體,代價是多了一趟自編碼器的來回。第二條軸線是你怎麼用得到它:封閉的 API 模型(DALL·E、Midjourney)把權重藏起來、透過網路服務你;而開放權重的模型(Stable Diffusion 及其親族)直接把整個網路釋出,讓任何人都能下載、微調,並打造像本篇這些工具。

影像修補與外延:在畫面內動刀

從零生成很有趣,但真正的工作是編輯:「這張幾乎完美——只要把角落那個亂入的人去掉就好。」這正是 擴散修補 在做的事。你給模型一張圖、一個標出「要重新生成的區域」的遮罩(mask),以及一段描述該處該出現什麼的提示。模型會保持遮罩外的一切原封不動,並在遮罩內憑空生成能與周遭無縫融合的新內容——對的光線、相符的牆面紋理、延續下去的地平線。外延(outpainting)則是同一個點子朝外指:你把畫布擴展到原本的邊界之外,讓模型想像「剛好在鏡頭外」的東西。

遮罩其實就是逐像素的標籤圖:這裡標出哪些像素屬於哪個區域。修補時我們用它的二值版本——保留 vs 重新生成。

一張被切分成多個標籤區域的照片,說明遮罩如何把每個像素指派到某個區域。

為什麼填補的內容會與照片一致,而不是漂移成一團亂編?訣竅優雅地簡單,而且原封不動地重用第 3 篇的反向過程。我們照常跑一步步去噪的迴圈,但在「每一步」都把潛在表示中「已知(未遮罩)」的部分,覆寫成加噪到當前時間步的原始圖像。網路永遠只被允許在遮罩內自由發揮;其餘地方,每一步都把現實重新釘回去。因為去噪器在每一輪都看到「真實周遭」一個正確的、帶噪的版本,它就不斷被推著讓那個洞與周遭相容。

x_{t-1} \;=\; m \odot x_{t-1}^{\text{known}} \;+\; (1-m) \odot x_{t-1}^{\text{gen}}

在每一步去噪之後施行的「遮罩混合」更新。

我們逐個符號拆解。x_{t-1} 是我們帶進下一步的潛在表示。m二值遮罩,與潛在表示同形狀:值為 1 代表「保留這個像素」0 代表「重新生成它」。符號 \odot 代表逐元素相乘——把對應位置相乘,不是矩陣乘法。所以 m \odot x_{t-1}^{\text{known}} 只挑出「原始圖像加噪到第 t-1 步」之中要保留的像素;而 (1-m) 把遮罩翻轉(現在洞內是 1),於是 (1-m) \odot x_{t-1}^{\text{gen}} 只挑出網路輸出 x_{t-1}^{\text{gen}} 中剛去噪好的像素。把兩半相加,就縫成一個潛在表示。小例子:若某像素 m=1,更新變成 1\cdot x^{\text{known}} + 0\cdot x^{\text{gen}} = x^{\text{known}}——原圖獲勝。若 m=0,變成 0 + 1\cdot x^{\text{gen}} = x^{\text{gen}}——生成內容獲勝。「每一步」(而非只在最後)都釘住已知區域,正是逼那個洞長得與鄰居相符的關鍵。

# Diffusion inpainting: pin the known region at every denoising step.
# image0  : the original latent we want to edit
# m       : binary mask, 1 = keep, 0 = regenerate (same shape as the latent)

x_t = random_noise()                       # the masked hole starts as pure noise

for t in reversed(range(T)):               # T -> 0, the Guide-3 reverse process
    # 1) the network freely denoises the WHOLE latent one step.
    #    The prompt + guidance still steer WHAT appears in the hole.
    x_gen = denoise_step(x_t, t, prompt)

    # 2) re-noise the ORIGINAL image to exactly this timestep (Guide 2 forward step)
    x_known = forward_noise(image0, t - 1)

    # 3) blend: keep the known pixels, accept generated pixels only in the hole
    x_t = m * x_known + (1 - m) * x_gen

# Outpainting is the SAME loop: just enlarge the canvas and set the new
# border pixels to 0 in the mask so the model must invent them.
result = decode(x_t)
修補就是標準採樣器加上「每步一行混合」。外延則靠擴展畫布來重用同一段程式。

ControlNet:用結構導引生成

提示詞很擅長說「是什麼」——「一位身穿金甲的騎士」——卻對說「在哪裡」束手無策。再多的文字也無法可靠地把騎士的左臂擺成這個精確角度,或讓新大樓符合舊大樓的輪廓。語言是一根模糊的指頭。ControlNet 正是那個工具,它讓擴散模型獲得精準的空間控制:你可以遞給模型第二個直接攜帶幾何資訊的輸入——邊緣圖、姿態骨架、深度圖、或一張粗略的塗鴉。

這個架構既聰明又保守。你拿一個已訓練好的 Stable Diffusion U-Net,把它凍結——權重永不改變。接著你做一份它編碼層的「可訓練副本」,當作一條平行分支來跑,這條分支讀取控制圖(比方說,一張參考照片的 Canny 邊緣圖)。在每一層,分支的特徵會被加回凍結主網路的對應層。基礎模型保留了它原有的全部世界知識;新分支只學一項額外技能——「把那些知識朝這個形狀彎過去」。因為原模型被凍結,訓練一個 ControlNet 既便宜又絕不會損壞基礎模型——你可以保有很多個(姿態、深度、邊緣),像換鏡頭一樣替換。

有一個小設計讓這套訓練起來很安全,而且名字很親切:零卷積(zero-convolution)。把新分支接到凍結網路的那些連接,一開始全部初始化為零,所以在訓練的第一步,分支貢獻「正好為零」——整個系統的行為與未經改動的基礎模型完全相同。隨著訓練進行,那些連接才慢慢長離零點,於是控制是溫和、漸進地「淡入」,絕不會嚇到預訓練網路或毀掉它原有的品質。

這在實務上替你換來什麼?把參考照片裡一位舞者的精確姿態,套到一個完全不同的角色身上(抽取姿態骨架、提示新角色)。把五分鐘的鉛筆草稿變成完成的成品,同時保住你的構圖(塗鴉控制)。把一棟大樓從混凝土改為玻璃,而它的窗戶與屋頂線維持不動(深度或邊緣控制)。替線稿上色,而 AI 不會重畫線條。每一種情況裡,控制圖提供「結構」,提示詞提供「內容與風格」。

提示詞工藝與負面提示

你日後做的大部分導引,都是透過平白的語言發生的,所以刻意地寫提示很值得。好的提示是分層的,不是一個名詞。一個可靠的配方:先點出主體(誰/什麼、在做什麼、在哪裡),再來是媒材(照片、油畫、3D 渲染)、風格(某個藝術運動、某個年代、某種有名的美學)、光線(黃金時刻、柔和的攝影棚光、霓虹),最後是品質提示(銳利對焦、高度細緻)。你不是在唸咒語——每一個詞組都把模型推向它訓練分布中「確實見過」的某個區域。

# BEFORE - thin prompt -> generic, flat, unpredictable
prompt = "a cat"

# AFTER - layered prompt -> subject, medium, style, lighting, quality
prompt = (
    "a tabby cat sitting on a wooden windowsill, "   # subject + scene
    "oil painting, impressionist style, "            # medium + style
    "warm afternoon light, soft shadows, "           # lighting
    "highly detailed, sharp focus"                   # quality cues
)

# NEGATIVE prompt - an explicit condition to steer AWAY from
negative = "blurry, lowres, deformed hands, extra limbs, watermark, text"

# Emphasis syntax (tool-dependent): (cat:1.3) up-weights, (text:0.5) down-weights.
# guidance_scale ~7 balances prompt-fidelity against natural-looking freedom.
同一個模型、同一個種子——唯一的變化是文字承載了多少意圖。

現在來談那個看起來像民間傳說、其實是純粹力學的東西:負面提示。回想第 4 篇的無分類器引導。為了生成,模型每一步把去噪器跑兩次——一次「以你的提示為條件」,一次「以空條件」——然後從空結果朝有條件的結果外推。無分類器引導 字面上就是「往『提示所加上的方向』推」。負面提示只是把那個空條件換成一個「明確的、不想要的」條件。模型不再是「遠離『空無』」,而是現在「遠離『模糊、多出來的手指』」。

\hat{\epsilon} \;=\; \epsilon_\theta(x_t, c_{\text{neg}}) \;+\; w\,\big(\epsilon_\theta(x_t, c_{\text{pos}}) - \epsilon_\theta(x_t, c_{\text{neg}})\big)

負面提示引導:從「不想要的」條件朝「想要的」條件外推。

逐個符號看:\hat{\epsilon} 是採樣器這一步要用的「最終、已引導」的噪聲估計。\epsilon_\theta(x_t, c) 是 U-Net 在條件 c 下、對當前帶噪潛在表示 x_t 預測的噪聲。這裡 c_{\text{pos}} 是你真正的提示,c_{\text{neg}} 是負面提示(在一般 CFG 裡,c_{\text{neg}} 只是空字串)。括號 \big(\epsilon_\theta(x_t, c_{\text{pos}}) - \epsilon_\theta(x_t, c_{\text{neg}})\big) 是一個方向向量:它從「不想要的條件所預測的」指向「想要的條件所預測的」。引導強度 w(見 引導強度)是我們沿那個方向走幾步。具體而言,若 w=1 你只得到正向預測;w=7 把結果沿著「朝想要的、遠離不想要的」這支箭頭多推七倍——所以更大的 w 會同時「更用力遵守提示」且「更用力逃離負面提示」。負面提示之所以有效,整個原因就是我們把那支箭頭的起點從「空無」換成了「正是我們討厭的東西」,於是箭頭現在主動把它排斥開。

極限、失效模式與倫理

精通意味著知道工具在哪裡會壞。擴散模型有一組可辨識的失效。手與手指常常畸形(太多、黏在一起、彎錯方向)。招牌與標籤上的文字會變成亂碼,除非模型特別為此訓練過。數數並不可靠——你要「正好五隻鳥」,可能得到四隻或七隻。屬性綁定錯誤把特徵掛到錯的物件上:「藍色球體上的紅色立方體」有時會變成紅色球體上的藍色立方體。還有老掉牙的速度問題:多步採樣器可能每張圖要花上數秒,這正是下一節的前沿要攻克的瓶頸。

為什麼是這些特定的失效?它們直接追溯到模型如何學習。手很小、變異大、又很少是被描述的主體,所以網路對它們的結構只收到微弱的訊號。數數與綁定會失敗,是因為文字編碼器把一句話壓成一個向量,而這個向量捕捉「大意」勝過捕捉「精確關係」——「紅」、「藍」、「立方體」、「球體」都在裡面,但把每個形容詞綁到它名詞上的那條繩子是鬆的。知道成因就知道解法:冗餘而明確地描述(「一個單獨的紅色立方體,擱在一個大的藍色球體上方」)、用 ControlNet 或修補來釘死佈局、並選一個用更好說明文字訓練的模型。

模型繼承其訓練資料的統計。若某職稱在資料中多由某一性別或膚色呈現,模型就會複製——並且往往放大——那種偏斜。

一張比較不同群體結果比率的圖,說明如何衡量模型輸出中的偏見與公平性。

更深的問題是社會性的,不是算術性的。偏見:在網際網路的一個切片上訓練,模型吸收了它的刻板印象。提示「一位執行長」或「一位護理師」,你往往得到一個狹隘、可預測的人口樣貌——模型反映並放大的是「誰被拍進」這些角色,而不是「誰能夠」擔任這些角色。這不是邊緣的小毛病;它形塑了數以百萬計的生成圖像如何描繪世界,這正是為什麼公平性值得被明確衡量與緩解,而不是聳聳肩帶過。

再來是來源與同意。這些模型是在從網路抓取的數十億張圖像上訓練的,其中很多有版權,很多是從未同意過的真實人物——這引發了活生生的法律與道德問題:一個「仿照在世藝術家 X 風格」的生成作品,究竟是致敬還是挪用。還有錯誤資訊:照片級寫實的 文字生成圖像 讓「製作真實人物與事件的逼真假圖」變得既便宜又能大規模生產——未經同意的影像、捏造的「證據」、政治深偽。讓你能用 Stable Diffusion 來打造東西的那份開放性,同時也拿掉了封閉 API 能強制施行的護欄。

  1. 整理資料:在模型學習之前,過濾訓練集以減少非法、有害與嚴重偏斜的內容。
  2. 替輸出加上浮水印與標記:嵌入隱形的來源訊號(例如 C2PA 風格的內容憑證),讓生成圖像在下游能被偵測與追溯。
  3. 施加安全過濾:在 API 或應用層阻擋明顯有害類別的提示與輸出。
  4. 尊重退出機制:支援登錄名冊與「請勿訓練」訊號,讓藝術家與個人能把自己的作品與肖像從未來資料集中移除。
  5. 揭露:向你的受眾標明合成媒體,尤其是任何描繪真實人物或事件的內容。

下一步:擴散模型的前沿

你現在握有整條流程,以及導引它的工具——那就來掃一掃地平線。最火熱的前沿是速度。標準採樣需要很多步,但蒸餾(distillation)一致性模型(consistency models)訓練網路在區區 1–4 步內就跳完大半路程。把這連到第 3 篇:在那裡,DDIM 讓我們從帶噪的潛在表示預測乾淨圖像 x_0 並邁開大步。一致性模型把這個點子推到極限——它被訓練成:從噪聲路徑上「任何一點」都直接跳到同一個 x_0 預測。把它壓到只跳一次,你就得到近乎即時的生成:圖像隨你打字即時更新。

第二條線是數學上的整理。流匹配(flow matching)修正流(rectified flow)重新表述擴散,使得模型學到的不是一條蜿蜒的帶噪軌跡,而是從噪聲到資料近乎「筆直」的路徑。你學過的 擴散模型 是描述這趟旅程的一種方式;流匹配則是對同一條常微分方程更乾淨、更一般化的描述——而那正是 DDIM 採樣 求解器早已暗示過的東西。更直的路徑更容易積分,這也是這些較新模型為何能在寥寥數步內採樣得這麼好的部分原因。潛在一致性模型(latent consistency models)把這個與第 4 篇的潛在技巧結合,驅動了你或許見過的那種「邊畫邊出圖」的即時工具。

而最大的躍進是進入新的維度。影片擴散加進了時間:網路對一疊影格聯合去噪,學習跨越運動的一致性,好讓貓不會在影格之間長出第六條腿。3D 生成(NeRF 風格及其後繼者)走向空間:模型學到的不是一張平面圖,而是一個你能讓相機繞著飛的場景——它最佳化一個連續函數,回傳空間中每一點的顏色與密度。你學過的關於條件化、引導與潛在表示的一切都能延用——畫布只是多了一根軸。

從 2D 到 3D:NeRF 學到一個連續的體積——空間中每一點的顏色與密度——於是你能從任何相機角度渲染出全新的視角。

一張顯示光線穿過 3D 體積以渲染新相機視角的圖,說明神經輻射場的原理。

  1. 趁你已有直覺,讀那兩篇奠基論文:〈Denoising Diffusion Probabilistic Models〉(DDPM)了解核心的訓練/採樣,以及〈High-Resolution Image Synthesis with Latent Diffusion Models〉了解 Stable Diffusion 背後的潛在技巧。
  2. 在本機跑一條開放的流程:安裝 diffusers 函式庫,從一段提示生成,接著加上負面提示並觀察變化。
  3. 加上 ControlNet:餵入一張姿態圖或 Canny 邊緣圖,用你自己的提示重現一個參考佈局。
  4. 試試修補:把照片裡一個物件遮掉、提示一個乾淨的替換,看著「遮罩混合」技巧把邊緣維持得天衣無縫。
  5. 然後追逐前沿:載入一個潛在一致性或 LCM-LoRA 模型,親自感受少步、近乎即時的生成。