[Lora] 關於訓練的 Noise 與 Loss

AIGC

說在最前面的,這些訓練數據可能會因為演算法、優化器、排程器或是各種相關套件更新而失準。本次的實驗主要是要測試 Noise 對於整體訓練的差異,與可能可以怎麼選擇或是設定的紀錄。


Kohya GUI

本次所使用的 Kohya GUI 版本是 24.1.4,如果你不是這個版本,或者是你是直接使用 kohya-ss/sd-script v0.8.7 也可以。

我們在 Kohya 的進階設定中可以找到本篇文章所提到的各種設定,你可以參考我之前的文章 [Lora] Kohya_ss GUI 介面筆記,我這邊就不贅述。


Noise 噪聲

在生成對抗網絡(Generative Adversarial Networks, GANs)中,噪聲(Noise)通常作為輸入注入到生成器網絡中,為生成的圖像引入隨機變化。在 Stable Diffusion 的做法是在最初的低分辨率層次由全噪聲(Pure Noise)然後根據生成的時間步數(timesteps)逐漸的降噪(Denoising)進而生成目標圖片。

Stable Diffusion 噪聲與降噪
Generated by GPT-4o

我把這件事情拿去問了 GPT-4o 他給了我上面這張奇怪的圖,覺得可愛所以我放上來,但應該不是很正確啦(笑)。


Noise Offset

關於 Noise Offset 我這邊就不多做解釋,有興趣理解原理的可以參考這個影片,他解釋的很清楚!

Noise Offset

以下參考資料有興趣的人可以自行翻閱

Diffusion with Offset Noise

Understanding “Common Diffusion Noise Schedules and Sample Steps are Flawed” and Offset Noise

在 Kohya 訓練當中,關於 Noise Offset 有兩種,

參數 說明
Original 原始噪聲
Multires 多分辨率噪聲,又有人稱金字塔噪聲

而跟噪聲有關的設定,則有,

參數 說明
Noise offset random strength 0 ~ Noise Offset 之中取一個亂數來當作 Noise Offset
Adaptive noise scale 使用一個潛空間平均絕對值(latent mean absolute value),乘上這個數字來當作 Noise Offset
Multires noise iterations 多分辨率噪聲迭代的次數
Multires noise discount 降低在不同層次尺度注入噪聲時的強度
IP noise gamma 擾動噪聲
IP noise gamma random strength 隨機由 0 ~ IP noise gamma 之間取擾動噪聲

關於 Loss

這裡 #PR294 的資訊量巨大,有興趣的人可以自己去爬文研究。


min SNR gamma

就是一個從論文來的方法,然後建議用 5%,大家也就用了好像也沒什麼問題。

論文在這裡 https://arxiv.org/abs/2303.09556


Debiased Estimation loss

跟 min SNR gamma 一樣,也是一篇論文的實作,但效果跟 min-SNR gamma 有點不太一樣。

論文在這裡 https://arxiv.org/abs/2310.08442


Huber Loss

以下是我詢問 Claude 他給我的解釋,

Huber Loss 是一種常用的損失函數(Loss Function),通常應用於迴歸問題中。它的全名為Huber平滑絕對損失(Huber Smooth L1 Loss),是 L1 損失(絕對損失)和 L2 損失(平方損失)的一種混合形式,結合了兩者的優點。

Huber Loss 的數學定義如下:

L_δ(y, f(x)) = \begin{cases}
\frac{1}{2}(y - f(x))^2 & \text{if } |y - f(x)| < \delta \
\delta|y - f(x)| - \frac{1}{2}\delta^2 & \text{otherwise}
\end{cases}

其中δ稱為平滑參數(Smoothing Parameter),通常取一個較小的正值。

當|y - f(x)|較小時,Huber Loss 等同於 L2 損失,具有連續可微的優點,適合微小誤差情況。
當|y - f(x)|較大時,Huber Loss 等同於 L1 損失,對離群值(outlier)具有一定的鮮活性,不會過度放大其影響。

因此,Huber Loss結合了 L1 和 L2 損失的優點,在小誤差情況下更平滑,在大誤差情況下更鮮活,往往比單一的 L1 或 L2 損失表現更好。它常被用於迴歸模型的訓練,特別是對離群值較為敏感的場景。

而我之前有提過,在 Kohya-ss 的 #PR1228 裡有提到他的作法與原本 Huber 的算法有點不太一樣。


比對與測試

首先,以下是我測試的差異參數,

參數/版本 v53 v54 v55 v56 v57 v58 v59 v60 v61 v62 v63 v64
精度 fp8 fp8 fp8 fp8 fp8 fp8 fp8 fp8 fp8 fp8 fp8 fp16
優化器 DAP L8 DAP DAP DAP DAP DAP DAP Pg Pg DAP DAP
min-SNR gamma 5 x x x 5 5 5 5 5 5 5 5
Debiased x v v v x x x x x x x x
Noise Offset 0.0357 x x x 0.0357 x x x 0.0357 0.0357 x x
Multires noise iterations x x x x x 10 x 6 x x x 6
IP noise gamma x x x x 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1
huber_c x x 0.01 0.05 x x 0.08 x x x x x
BS 4 4 4 4 4 4 4 4 2 2 4 4
梯度累加 1 1 1 1 1 1 1 1 2 2 4 1

DAP = DAdaptAdamPreprint
L8 = Lion8bit
Pg = Prodigy
Debiased = Debiased Estimation loss
BS = Total batch Size
huber_c = use Scheduled Huber Loss, Loss type: huber, Huber schedule: snr

這些測試除了學習率,與特別寫出的 BS2Gradient accumulate steps 以外,其他參數都全數固定,為了降低影響,在 v60 以前,提詞都是同一組,而 v61 以後則採用另一組提詞。而所有的訓練集都使用同一組,且解析度都以 2048x2048 為基準,並且使用 Don't upscale bucket resolution 與 ARB 分桶,分桶的尺寸是 32


影響層面

根據這些測試,我先整理一個影響層面給大家參考,

參數 影響
Noise Offset 0.0357 這是 SDXL 預設的一組 Noise Offset 數值,對畫面的亮部或暗部的強化(或弱化)的效果會因為噪聲而有所變化
Multires noise iterations 6 金字塔噪聲在這個數字越大時,對於邊緣處理的強度會越強,維持 6 是明智的選擇
Multires noise discount 0.3 這個數字如果很大,那麼他對於邊緣處理的效果就越低,你用 0.8 有時候會有柔膚效果
min-SNR gamma 5 邊緣處理柔和,細節部分會產生失真,大面積特徵效果處理的比較平滑
Huber Loss, snr, huber_c: 0.01 擬合速度很快,如果你的訓練步數很多,你所拿到的擬合強度會非常高
Huber Loss, snr, huber_c: 0.05 因為增高了 huber_c,所以擬合速度會放緩,強度也會稍微弱一點
Debiased Estimation loss 這個啟用後,邊緣處理的強度會非常強,跟 min-SNR gamma 5 有極大的差異
IP noise gamma 0.1 增加擾動噪聲時,對於學習過程中可以補足部分細節,但強度過高會有奇怪的細節產生
fp8_basefp16 相較之下 fp16 的表現內容比較多元(不一定是細節)

測試結果

我們來看看這些產出的結果,

v53, v56, v57, v58 比對結果

你會發現 v53v57 在頭髮的部分有一點差異,在 IP noise gamma 的作用下,細節會比沒有使用要來的多一些。臉部的肌理、服裝細節與陰影的部分也會比較豐富。

v57v58 相比之下,使用了多分辨率噪聲的情況下,他的頭髮表現就更強,甚至有一點過度強化的感覺,這一點就看資料集是否需要,如果資料集的解析度偏低的情況下,多分辨率噪聲可能會比較好。

回頭看 v56,完全不使用噪聲偏移,單純靠 Debiased Estimation loss 就把頭髮細節跟顏色做得很好。你會發現除了 v56 以外,所有的人物顏色都偏黃,我後來回頭檢查資料集,發現是有些照片並沒有做白平衡的調整,而是維持室內黃光。

我們再看另一組例子,

v53, v56, v57, v58 比對結果

你會發現 v58 在多分辨率噪聲的加持下,臉部光影跟細節都表現的不錯,而 v57 也因為有 IP noise gamma 而在細節上有所提升。

v53, v57

接著我們看一下不同優化器所產生的結果,

v61, v60

v61 採用了 Prodigyv60 則是 DAdaptAdamPreprint,你會說噪聲參數不同步公平,那麼你可以再往上一點跟 v57 比較。

整體上來說,在 Prodigy 的學習狀況來看,他的擬合速度比我想像中的還快,整體的表現其實已經是過擬合的狀況,之所以沒有爆炸應該是提詞的方式救了他。對於高品質的訓練集來說,使用 Prodigy 可能不是一個好的選項(對我而言來說,他表現反而不好)。

但是,雖然擬合程度高,不過沒有出現過度偏黃的問題。我們來看一組故意讓他模擬底片表現的效果,

v61, v60

這個時候你會發現 Prodigy 的顏色表現很穩定(起碼沒有偏黃)。


接著我們來背景表現的狀況,

v57, v60, v64

你會發現三張的背景都不太合理,幾乎都是左右對切的不連貫狀況。由於提詞泛化程度很高,目前不確定是否是提詞影響。

但,由於我重點只跟他說 a girl standing in front of the coffeeshop bar,其他都是描述服裝、光影、品質等等的提詞,所以那個 in front of 是對的,但是 coffeeshop bar 可能就很自由發揮了。

不過,你可以對比 v60v64 兩者是 fp8fp16 的訓練差異。實際上在 fp16 的結果上,他的話面豐富度會比較多一點。


高強度的結果

我上面有提到幾個東西會造成邊緣強度過高,例如 Debiased Estimation loss 這件事。

Debiased Estimation loss 對於頭髮的表現

頭髮的強度你這樣看起來就會發現,他有點太超過了。

而,更超過的還有一個,就是使用 Huber Loss, snr, huber_c: 0.01 加上 Debiased Estimation loss,由於 huber_c: 0.01 的關係,外加 Debiased Estimation loss 本身就會加速擬合,所以就會拿到這種結果(特徵不像是因為我沒下觸發詞的關係),

Debiased Estimation loss 過擬合

所以大抵上來說,如果你的訓練集狀況不是很好(當然也不能太爛),那麼用 Huber Loss 搭配 Debiased Estimation loss 或許是一個不錯的選擇。當然,你的 huber_c 可以的話先從 0.05 開始嘗試會比較好,最後再視狀況往上或是往下。

我這邊有一個 0.05 的例子(就是 v56),

huber_c 0.05 + Debiased Estimation loss

所以對於細節或是特徵比較要求的話,使用 Debiased Estimation loss 確實效果不錯,至於是不是要使用 Huber Loss 就端看你的資料集跑起來,哪個比較好來決定。


意外的發現

當我在測試 v62v63 的時候,其實是沒有完整跑完的,但是卻發現了一件事,就是他們的擬合速度出乎我意料之外,

v61, v62, v63

上面三張的總步數是這樣,

版本 總步數
v61 6,000
v62-000005 1,180
v63-000006 1,428

令人驚訝的是絕大部分的特徵在 1,500 步內已經有了七八成的訓練結果!

這兩個版本剛好是因為 Prodigy 我無法跑到 Train batch size: 4 的設定,所以只好搭配 Train batch size: 4 加上 Gradient accumulate steps 2 來去執行。

中間為了修改設定而中斷了 v62 這一爐,而另開 v63 的時候,沒注意到 Gradient accumulate steps 2 的情況下,就用 DAdaptAdamPreprint 開跑了,所以就這樣突然發現他們擬合的速度好快!

但是!

這個狀況拿來測試是可以的,因為步數相當低,而 Epochs 數量也不高,所以對於背景或其他物件的表現就不會太好。

v62-00005 背景表現

背景被切成三塊,衣服與人物連接觸的不自然陰影等。臉部的瑕疵大概還可以用 ADetailer 去修正,其他的部分就稍微麻煩一點,當然你用 segment-anything 切下來另外做也是可以。


加噪這件事

這邊要說一件事,使用 IP noise gamma 是他隨機加入一個固定權重的擾動噪聲,對訓練來說,這個動作確實會增加一點細節,但過多會產生不必要的東西。

使用這個參數對於你的 訓練集 內容是 使用 AI 產生的圖 來說,會有一定的幫助,這個擾動噪聲可以避免學習這些 AI 產生的圖的 副作用

AI 產出的圖拿來訓練,大部分會有超快速擬合的副作用。

關於這一點,我所使用解決的方式有幾種,

  1. 圖片丟進 Photoshop 手工加入一點噪訊(只能一點點,太多會變成風格被學起來)
  2. 使用 Lightroom 統一把圖片套用某種風格(強度不能太高,太強也是會變成風格被學起來)
  3. JPEG 破壞壓縮縮小 0.9 再放大回原本尺寸(故意破壞畫面)

現在有 IP noise gamma 是可以比較省事一點,但就是強度自己斟酌,雖然會增加細節,但是也會有機會 長出不對的細節


結語

要我推薦參數就 v53, v57, v60, v64 這些吧。

Hina Chen
偏執與強迫症的患者,算不上是無可救藥,只是我已經遇上我的良醫了。
Taipei