[Kohya_ss] 分層訓練與參數筆記

分層訓練紀錄

說在最前面的,這個分層訓練僅是針對分層的概念作的實驗,若想瞭解更多關於分層的設定,可以參考 b 站或是其他學習資源。這裡僅記錄過程,每個分層的設定都必須自己慢慢實驗才知道怎樣才合適。


Kohya_ss 的分層訓練

我這裡所使用的 Kohya_ss 版本是 v21.7.7,所以若你想要參考這篇文章使用分層訓練,請先確認你的版本是否為 v21.7.7


分層權重

分層的概念是從 SD WebUI Lora Block Weight 來的,主要的目的是可以針對 Lora/LoCon 來指定層的權重,用以降低過擬合,或是減少 Lora 之間的互相干擾問題。

關於分層權重的部分,可以參考這一位大佬的文章:

他做了一個分層計算機,並分享到 https://github.com/Zuntan03/LoraBlockWeightPlotHelper 上面,有興趣的人強烈推薦閱讀。

關於分層權重的設定,可以參考這裡:Weights Setting。每一個層(Block)會發生什麼作用,請自行參考上個區段分層權重的資料。或者你可參考 Effective Block Analyzer 的作法,自行使用 X/Y/Z plot,去找出比較適合的參數來使用。


Kohya_ss 的分層訓練

目前在 Kohya_ss 上面,僅有 Standard (Lora), Kohya LoCon 及 Kohya DyLoRa 支援分層訓練。

分層訓練設定

分層訓練區分為,

  • Down LR Weights 淺層至深層。
  • Mid LR Weights 中間層。
  • Up LR Weights 深層至淺層。

預設是都不設定,就是全訓練,也就是每一層的參數都會是 1 的情況下去做訓練。

另外 Blocks LR zero threshold 請不要亂寫,他的意思是訓練權重若沒有大於此設定,則會捨棄該 Lora 的訓練建立,換句話說,你若是設定的數值,你訓練出來的 Lora 等於沒有訓練。

請注意,這個欄位所謂的 weight 是指跟學習率相乘後的結果,並不是前面幾個欄位的設定值,所以,當你的學習率是 0.0001 的話,這邊的數字如果寫 0.0001,其實也等於沒有訓練,因為全面的預設全訓練是 1,乘上學習率之後還是 0.0001,並沒有比 Blocks LR zero threshold 來得大,所以訓練會被捨棄。

保持 Blocks LR zero threshold0 是個明智的選擇。


分層訓練設定

根據 Kohya-ss #PR355 的說法,每個分層學習率都需要填寫 12 組數字,這是 LoCon 的最大數字(共 25 + 1 層)。所以當你在分層訓練 Lora/LoCon 時,請留意你的分層數字是否設定正確。關於分層權重的區塊,可以參考這裡:Weights Setting

在分層設定中,除了填寫 12 個數字之外,從 Kohya_ss 的原始碼中,還有幾個特殊參數可以使用,

# 層別学習率用に層ごとの学習率に対する倍率を定義する、外部から呼び出される可能性を考慮しておく
def get_block_lr_weight(
    down_lr_weight, mid_lr_weight, up_lr_weight, zero_threshold
) -> Tuple[List[float], List[float], List[float]]:
    # パラメータ未指定時は何もせず、今までと同じ動作とする
    if up_lr_weight is None and mid_lr_weight is None and down_lr_weight is None:
        return None, None, None

    max_len = LoRANetwork.NUM_OF_BLOCKS  # フルモデル相当でのup,downの層の数

    def get_list(name_with_suffix) -> List[float]:
        import math

        tokens = name_with_suffix.split("+")
        name = tokens[0]
        base_lr = float(tokens[1]) if len(tokens) > 1 else 0.0

        if name == "cosine":
            return [math.sin(math.pi * (i / (max_len - 1)) / 2) + base_lr for i in reversed(range(max_len))]
        elif name == "sine":
            return [math.sin(math.pi * (i / (max_len - 1)) / 2) + base_lr for i in range(max_len)]
        elif name == "linear":
            return [i / (max_len - 1) + base_lr for i in range(max_len)]
        elif name == "reverse_linear":
            return [i / (max_len - 1) + base_lr for i in reversed(range(max_len))]
        elif name == "zeros":
            return [0.0 + base_lr] * max_len
        else:
            print(
                "Unknown lr_weight argument %s is used. Valid arguments:  / 不明なlr_weightの引数 %s が使われました。有効な引数:\n\tcosine, sine, linear, reverse_linear, zeros"
                % (name)
            )
            return None

所以 Down/Up LR Weights 可以設定,

  • cosine 使用餘弦函數。
  • sine 使用正弦函數。
  • linear 使用線性函數。
  • reverse_linear 使用線性函數(反向)。
  • zeros 使用常數 0.0 加上指定數字 base_lr

所以,如果我在 Down LR Weights 設定為 sine+0.25,那麼最終你會獲得這樣的數字,

down_lr_weight (shallower -> deeper, 浅い層->深い層): [0.25, 0.39231483827328517, 0.5317325568414297, 0.6654150130018863, 0.7906408174555976, 0.904860733945285, 1.0057495743542582, 1.091253532831181, 1.1596319953545184, 1.2094929736144975, 1.2398214418809328, 1.25]

他會自己幫你展開成 12 個數字,分別從 0.251.25,這幾個數字是由 sine(n) + 0.25 計算而來。所以,當你開始跑訓練時,你會看到每一個層(Block)會依據你所設定的 UNet 學習率,乘上這個數字,來獲得每一層不同的學習率。

使用 cosine_with_restart 且分層學習的學習率 Log 圖

分層訓練的效果好嗎?

這個問題講真的我不知道。

以下測試皆使用相同 Prompt,

(8k, RAW photo, best quality, masterpiece:1.2),
(realistic, photo-realistic:1.2), ultra-detailed,
a girl wearing a hat with ears on it's head and a teddy bear,
relax face, black eyes, smile, facing viewer, upper body,
the high-key lighting with a soft bokeh and ethereal feel,

負面提示詞皆使用,

easyNegative, illustration, 3d, sepia, painting,
cartoons, sketch, (worst quality), disabled body,
(ugly), sketches, manicure:1.2,
ng_deepnegative_v1_75t, negative_hand-neg
全訓練與分層訓練 1
全訓練與分層訓練 2

v188, v191 使用預設全訓練,v189, v190 使用以下訓練參數:

  • Down LR Weights 設定 sine+.25
  • Mid LR Weights 設定 1
  • Up LR Weights 設定 cosine+.25

訓練集與其餘訓練參數皆相同,

  • 使用 Lion,超參數 weight_decay=0.02 betas="0.95,0.98"
  • UNet 學習率 0.0001
  • 總步數 3,150,訓練 12 個 Epoch。
  • Total Batch Size2
  • Gradient accumulate steps2
全訓練與分層訓練 3

v187 為全訓練,v186 使用常數分層訓練,訓練參數為:

  • Down LR Weights 設定 0,0.5,1,0.5,0.5,0.5,0,1,1,0,0,0
  • Mid LR Weights 設定 1
  • Up LR Weights 設定 0.5,0.5,1,1,1,1,0.5,0.5,0.5,0.5,0,0.5

訓練集與其餘訓練參數皆相同。


結語

如果需要更好的泛型,或是訓練風格,可以考慮分層,人物的話就必需要做更多測試,才會抓到比較好的分層訓練的設定數值。

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