見出し画像

【StableDiffusion】SDXL対応の「あ」~「お」発音のLoRAを作るまで【traintrain】

■記事の対象ユーザ

1.LoRAを自作したことがある(つよつよGPUを持っている)
2.WebUI-traintrainを使っている
3.SDXLのLoRA作りの具体的なパラメータに困っている

つまり

■ようするに?

これは僕がSDXL版の「あ」~「お」の口LoRAを作るまで物語だ

・コピー機LoRA収束しない!→バッチサイズと学習率変えよう
・効果が出にくい!→network dimとalphaを変えてみよう
・強く当てないと効かない!→マージの時に調整しよう


第1章 はじめに

今回の記事はsd-webui-traintrainを使ってSDXL対応のLoRAを作るとき
上手く行かなかったからパラメータを色々試してみたよって話だよ。
Kohya_ssに比べると大分入力パラメータが少ないけど、使ってるパラメータは同じなのでKohya使ってる人にも参考になればいいなと思います。

今回作る「あ」~「お」の口をするLoRAなんだけど
2023年9月頃に既に十条さんがSD1.5版を作ってくださっていたのですが
1.SDXL版が欲しい
2.「open moouth」のようなトリガーワードなしで動作して欲しい
3.ウチの子モデルの表情に寄せたい

という要望を叶えるため自分で作ってみることにした次第です。

そして、SDXLのLoRAを作るにあたり
「実際に使うモデルをベースにLoRAを作ると良い」
という情報があったため、どのモデルをベースにすべきかを
下記の記事で色々なSDXLモデルに表情出させて調べていました。
今回はこの結果を受けてAnimagine XL 3.1を選定しています。

また、SD1.5のLoRAは作ったことあったんですが、SDXL版は未経験だったので作り方を調べた内容も下記の記事にまとめました。

試行錯誤で大量のLoRAを作ることが大変だったんだけど、そんなときsd-webui-traintrainに出会ったんです!

オペレーター増員中

traintrainは設定を入れてキューイングしておけるので、いろんな設定を試したい今回みたいなケースでは非常に重宝しました。夜寝る前とか朝会社行く前に試したい設定を入れておくと時間を無駄にせずに済むもんね。

蹴りたい背中。逃げたい現実。

詳細は以下の記事でまとめてるので、良かったら見てみてね。

作りたいものと、作り方と、ベースとするモデルが決まり
ここから1ヵ月間の試行錯誤がはじまるのでした。

第2章 SDXLで作って見るよ

当時の設定は残ってないから今となっては何がダメだったのかは分からないんですが、はじめてSDXL版「あ」の口LoRAを作った時は適用しても画像に全く作用しない無能LoRAが出来上がってしまいました。

これではいけない!ということでまずは学習時間が短くて済むSD1.5で「あ」の口LoRAを作ってみて、そのノウハウを元にSDXL版を作ろうと考えたんです。

SD1.5のコピー機学習法を試してみる

まず最初に月須和さんの初級編の記事を読みながらモノクロLoRAを作成、
その後VRoidStudioで撮影した口を閉じた画像と開けた画像2枚を使い
「あ」の口LoRAを作成してみました。

私が撮影しました

複数作ってマージしてみる

同じく月須和さんの中級編の内容でsvd_mergeを使う方法と
似たような効果のLoRAのマージによる効果の安定化をやってみました。

この時は、似たような効果を持つLoRAを作るのにVRoidStudioで撮影する画像を正面だけでなく、左向き、右向きを用意しました。

また、十条さんもパーツ系LoRAを作るノウハウとして挙げているように「ちょっと大げさなくらいの変化」を意識し、撮影した画像の口の部分をPhotoShopで150%くらいに拡大して素材を作っています。

用意した画像がこちら

これらでコピー機学習させた「あ」の口LoRAを作り、3種をマージしてまぁまぁ安定した効果が得られることが確認できました。
SDXLにおいても基本方針はこの流れで作ることにします。

なんでそんなこわいこというの

SDXLで同じことをやってみた

素材画像をSD1.5の512x512から1024x1024で撮影しなおして
SDXLで同じように「あ」の口LoRAを作って見ようとしたのですが
完成品の口がぼやけてしまい、とても使えないものが出来てしまいました。

はて?と思い前段で作るコピー機LoRAを確認したところ、
なんということでしょう!SD1.5の時と違い全く収束していないではありませんか!

ここが収束していないから、コピー機学習法で差分が上手く取れず
結果としてぼやけた口になってしまったのだと仮定し、SDXLでのコピー機LoRAの収束について検証していくことになります。

第3章 コピー機LoRAが上手くできない

コピー機LoRAが収束していないのである!

SD1.5の時に上手くいった設定で全く収束していないことが分かったので、
単純に「ステップ数を増やせば上手くいくやろ!」の精神で検証してみたのですが、ある程度近いかな?ってラインを超えると虚無が現れたりノイズの様なものが乗ったりと安定しない挙動をするようになりました。

ステップ数上げても無駄無駄ァ!

本来ステップ数を重ねると一定のライン以上は全て過学習状態で同じような画像が出るようになるので、これは明らかにSDXLだと何かの設定が間違っていると思われます。

色々変えて見たんだけど

オプティマイザやスケジューラを調べていくつか試してみましたが全く改善されず途方に暮れていたところ、ふと見たKohyaさんの以下の記事に

また学習率として1e-3と比較的高めの数値を設定しています。これは破綻しない範囲で学習時間を短縮するためです。バッチサイズを小さくした場合は、学習率を下げたほうが良いようです(たとえばバッチサイズ4なら2e-4程度?)。

Kohyaさんの記事より

学習率1e-3はこれまでは月須和さんの記事でも

通常LoRAは1e-4で、コピー機LoRAは1e-3で学習しています。

上述の月須和さんの記事より

と一致しているのでSDXL環境でも1e-3でいいんだ!と疑いもして無かったんですが

バッチサイズを小さくした場合は、学習率を下げたほうが良いようです(たとえばバッチサイズ4なら2e-4程度?)。

大事なことだから2回引用してます

ウチのバッチサイズは「1」・・・、Kohyaさんは・・・「12」!?!?

※ウチのGTX3080ちゃんではバッチサイズ「3」くらいで動かなくなるし「2」でも動くか怪しいです。

そのKohyaさんがバッチサイズを「12」→「4」にするなら
学習率1e-3(0.001)→2e-4(0.0002)くらい?と言っている

じゃあウチは「1」ってことは・・・ 

12 = 0.001(1e-3)
6 = 0.0005(5e-4)
4 = 0.000333…(3e-4くらい)
3 = 0.00025(2.5e-4)
1 = 0.0000833…(8e-5くらい)

ってことぉ!?

余談:オプティマイザについて

この時、オプティマイザについても色々調べてたんですが、
まとめると以下の様な感じだったので今回はLionを採用しています。

・LoRA界隈でよく使われているのはAdam8W
・Adam8WはAdamW(32bit)の8bit版。少ないVRAMでAdamWと同等程度の性能らしい
・学習率とスケジューラ部分を自動で調整するタイプがありAdafactorとProdidyはその系統のもの
・Adafactorは自動調整を謳っているが実際は10,000STEPくらいまではスケジューラ=constant(定数)と変わらないらしくLoRAの様な低STEP学習には向かない
・sd-webui-traintrain公式情報で差分LoRAでは推奨はAdamW、Adam8Wは非推奨とのこと(精度が落ちるらしい)
・LionはNetwork dimが小さい時に早く学習が収束する傾向にあることから
差分LoRAを作る時の速度の向上が見込まれる。
・VRAMの使用量の観点からみると
AdamW > Adafactor > AdamW(8bit)
・学習速度の観点からみると
Lion > AdamW > Adafactor
・十条さんの目LoRAなどはProdigyを使っている模様

しらべたこと

学習率を変えて試してみる

8e-5は少し気持ち悪かったので、学習率を5e-5(0.00005)にして以下の様なパラメータでコピー機LoRAを作ってみました。

network dim = 16
network alpha = 16
iterations = 1000
batch = 1
lerning rate = 0.00005
optimizer = lion
lr scheduler = cosine
block = all 1.0
conv dim = 8
conv alpha = 8
seed = 1111

SD1.5みたいに完全一致はしない?

SD1.5でコピー機LoRAを作った時は、500STEPも回せば同じ画像しか出来ないLoRAが出来てたんですが、SDXLだとついぞ完全なコピー機には至りませんでした。

SD1.5の時に作ったコピー機LoRA
SDXLで良しとしたコピー機LoRA
気分は間違い探しよ

もしかしたらSDXLではコピー機LoRAは完全には収束しないのかも知れません。もう少し良くする方法があるのかもしれないけど、この程度の誤差であればLoRAに影響しないと判断して今回はここで妥協しています。

第4章 収束した設定でLoRAの作成

コピー機LoRAが概ね収束したので、これを使って再び「あ」の口LoRAを作ってみるよ。

ちくしょう!なんでだ!どうして背景がスタジアムになるんだ!!

traintrainの2pass目の検証

1pass目の設定は3章で上手くいった設定を使い、2pass目の設定を色々と変えて検証してみたよ。

dim=4 / alpha=4 & conv dim=4 / conv alpha=4
dim=16 / alpha=16 & conv dim=8 / conv alpha=8
dim=8 / alpha=8 & conv dim=4 / alpha=4

あれは一体何だったんだろう。間違えて存在しないLoRAとか指定してたのかな・・・

上記のdimやconvの他にも、STEP数を3000とか変えてみたり、シード値を固定からランダムにしたり、input画像とoutput画像を逆にしてみたり、学習するblockをallから(顔に関係する)OUT3-5に限定してみたりと色々試してみたところ、次の設定でいい感じになりました。

[1pass目]
network dim = 16
network alpha = 16
iterations = 1000
batch = 1
lerning rate = 0.00005
optimizer = lion
lr scheduler = cosine
block = all 1.0
conv dim = 8
conv alpha = 8
seed = 1111

[2pass目]
network dim = 4
network alpha = 4
iterations = 1000
batch = 1
learning rate = 0.00005
optimizer = lion
lr scheduler = cosine
conv dim = 0
conv alpha = 0
seed = 1111
上手く行った設定の出力

別角度の画像からもLoRAを作成

正面、左向き、右向き画像

ここまでは正面の画像からLoRAを作っていましたが、左向きと右向きの画像でも同様のパラメータでLoRAを作成していきます。
出来上がった3つの「あ」の口LoRAを重ね掛けした時の画像が以下。

第5章 「あ」は上手く出来たのに・・・

即死2コマ

ちゃんとLoRAとしては効いてるんだけど、出力が微妙になってて
以下のツイートでは一番マシな画像をチョイスしてるけど、特に「い」と「え」はこれ以上強く適応すると画像が崩れてしまい、とてもとても実用できる仕上がりには・・・

network dimの変更

ここで再び学習率やnetwork dimを調整して検証を開始。
STEP数は1000とか3000にして100~500刻みで中間の物も作成し動作を確認していきました。

上手くいかなかったパターン

SD1.5の時はnetwork dimはLoRAは8くらいで良い!という記事情報を元に作っていて、SDXL版LoRAを作り始めた時は「画像サイズが大きくなるからdimも上げといた方がいいだろうな!」と安易にdim=16に固定していました。

ここで一度network dimについてちゃんと調べた方がいいかなと多い、調べてみました。

余談:network dimについて

LoRAのファイルサイズとVRAM使用量、学習時間に影響する。
一般的には8~128と言われているがデカければ良いというものではない。

network dimとファイルサイズは参考記事によると以下の通り

参考記事より引用

サイズに影響することから分かるようにこの値が大きいほどLoRAが覚えられる情報量が多くなるのだが、LoRAで記憶したい情報なんてAnimagineとかPonyとかのモデルが学習している量に比べたら微々たるもの。
何千・何万枚と学習してるであろうモデルのファイルサイズが6GBとかなのでnetowrk_dim=256とかデカすぎんだろ・・・の世界に見える。

STEP数とnetwork dimの関係について
「これって私の感想ですよね?」
というイメージで話しますが、
STEP数とnetwork dimを絡めて考えた時、同じSTEP数ならnetwork dimがデカいほど学習の効果が出にくくなる感じ。

例えばSTEP数を水に例えると、コップに1滴落とすのがnetwork_dim=2
(落とした水のコップに対する割合は大きい)とすると
network dim=8ならバケツとか、128ならプールに1滴落とすようなもの。
当然network dimが大きければSTEP数を多くしなければ当然、LoRAは学習による影響を受けにくくなる。

この水滴のサイズは学習素材によって異なり、コピー機LoRAみたいな微小な変化だと小さく、画風の様な変化量が大きいものは大きくなる。
(=1滴の水の量が多くなる)

逆に水滴の数が多すぎる、水滴のサイズが大きすぎる学習素材に対してnetwork dimが小さすぎると、水が溢れてしまい学習しきれないため効果が十分に出ない。

network dim=16で学習率を変えた時のコピー機LoRAの収束具合で見ると

学習率0.0005の時
800STEP → 学習不足
900STEP → 学習不足
1,000STEP → 収束
1,100STEP → 収束
1,200STEP → 収束
と一定ラインを越えたら安定したものが

学習率0.00085の時だと
800STEP → 学習不足
900STEP → 学習不足
1,000STEP → 破綻
1,100STEP → 破綻+
1,200STEP → 破綻++(破綻がひどくなってる表現)
という風に過学習で収束しないような現象になっていました。

※個人の感想です

話を戻して

network dimについて調べたところで、今度は試しにdim=32に変えて
効果を確認してみました。

dim=32の時の設定

すると、強く適用しても大きくならなかった「え」の口に変化が出ました。

この時の試作LoRAが迷子になっちゃったので画像はないんですが、
この後作った「う」の口LoRAが変化量が小さすぎるためか効果が出ず
dim上げただけじゃだめかぁ~となったので、今度はnetwork alphaに着目することになります。

network alphaの変更

これまでnetwork alphaのことを理解していなかったので、値はなんとなくnetwork dimと同じ=無効にしていました。

そもそもnetwork alphaが何かっていうのを次の記事から引用させてもらうと

Network alpha:

これは、LoRA保存時にウェイトが0に丸め込まれてしまうのを防ぐための便宜上の処置として導入されたものです。

LoRAはその構造上、ニューラルネットのウェイト値が小さくなりがちで、小さくなりすぎるとゼロ(つまりなにも学習していないのと同じ)と見分けがつかなくなってしまう恐れがあります。そこで、実際の(保存される)ウェイト値は大きく保ちつつ、学習時には常にウェイトを一定の割合で弱めてウェイト値を小さく見せかける、というテクニックが提案されました。この「ウェイトを弱める割合」を決めるのがNetwork alphaです。

Network alpha値が小さければ小さいほど、保存されるLoRAのニューラルネットのウェイト値が大きくなります。


使用時にウェイトがどれだけ弱まるか(使用強度)は「Network_Alpha/Network_Rank」で計算され(ほぼ0~1の値)、Network Rank数と深く関係しています。

学習後のLoRAの精度がいまいちな場合、ウェイトデータが小さすぎて0に潰れてしまっている可能性があります。そんな時はNetwork Alpha値を下げてみる(=保存ウェイト値を大きくする)とよいでしょう。

デフォルトは1(つまり保存ウェイト値をなるべく最大にする)です。

Network AlphaとNetwork Rankが同じ値の場合、効果はオフになります。

※Network Alpha値がNetwork Rank値を超えてはいけません。超える数字を指定することは可能ですが、高確率で意図しないLoRAになります。

また、Network Alphaを設定するときは、学習率への影響を考える必要があります。

例えばAlphaが16、Rankが32の場合、ウェイトの使用強度は16/32 = 0.5になり、つまり学習率が「Learning Rate」設定値のさらに半分の効力しか持たないことになります。

AlphaとRankが同じ数字であれば使用強度は1になり、学習率に何の影響も与えません。

下記記事から引用

つまり普通なら捨てられてしまうような微小な変化点に対してゲタを履かせて学習できるようにするというもので、今回の「う」の口の様に微小な変化のコピー機LoRAには効きそうな設定に見えます。

ここで次の様にalphaの値をnetwork dimの1/4に設定し、代わりにSTEP数を増やしてどうなるかを10,000STEPを途中経過を保存しながら回して効果を確認しました。

dim=8 / alpha=2とした設定

この時、dim=32も同じようにalphaの値を下げた版もtraintrainにキューイングして仕事に行っていたのですが、こちらはさらに良い結果が得られました。

dim=32 / alpha=8とした設定

一番画像映えするのが「い」だったので上記ツイートでははしゃいでるけど、「う」が効かない問題が解消されたのが一番の収穫だったのよね。

第6章 dim32版で作り直してみる

上手く行ってなかった「う」と「え」で良い効果が得られたので
この設定で改めて「あ」~「お」LoRAを作り直してみたよ。

traintrainがあって本当によかった

dim32版LoRAの効果確認

dim32版「あ」の口LoRA3種
dim32版「い」の口LoRA3種
dim32版「う」の口LoRA3種
dim32版「え」の口LoRA3種
dim32版「お」の口LoRA3種

dim32版の出来について

全部いい感じになることを予想していたんだけど、「あ」の正面は効果が出てなかったり、「い」の口の左向きなんかは画風にまで影響でちゃってるのでdim32で作ればおっけーってわけでもないみたいです。

左様

効果を出すためにdimのサイズを大きくしたけど、もしかしたらalphaをもっと小さくした方が良いのかも知れないね。でも今回は上手く行ったからこれ以上は追わないことにするよ!

逃げるは恥だが生き残ったもん勝ちよぉ!

第7章 LoRAのマージ

もうちょっとだけ続くんじゃ

ここまでに出来たいい感じのLoRA単品でも問題ないとは思うんだけど、すごい人も「類似効果を持つLoRAをマージすることで効果の安定が図れる可能性がある」と言っているので、SVDを使ってLoRAをマージしてみるよ

コピー機学習法で同じ系統のLoRAをいくつか作ってSVDマージでまとめるって手法。素材枚数増やす代わりにLoRA増やして混ぜようぜ!って考えですね。
これにより、それぞれLoRA欠点を同種のLoRAで補完させ合うことで、より効果的なLoRAが生み出せます。……単に欠点を濃縮しただけのゴミが出来ることもあります。

月須和さんの記事より

マージにはWebUI拡張にあるSuperMergeを使っていきます

SuperMergeの画面

設定方法

今回設定する項目は以下の3つ
filename(option):マージ後の名前
remake dimension:マージ後のnetwork dim
LoRAname1:ratio1:Blocks1…:マージ対象のLoRAと倍率

マージ対象となるLoRAは画面の下部に選択できる場所があって、そこからマージしたいLoRAにチェックを入れると、自動的にLoRAname1の欄に出てくるよ。WebUI拡張なのでWebUIの認識できる場所に置いておかないと一覧には出てこないから気を付けてね。

参考:「い」LoRAマージ時の設定

パラメータの検証

マージの時に設定するパラメータはマージ後のnetwork dimと、どのLoRAをどの倍率でマージするかのratioくらいなので、3つの「あ」LoRAのマージするのにそれぞれ検証してみたよ。

network dim
ratioを3つとも1.0、dimだけを変更したパターン

dim=4
dim=8
dim=16

・dim=4だと1.0~1.5の変化量が細かく効いている様に見える。
・dim=8とdim=16は両方とも1.4~1.5で「うわぁ急に効果をだすな!」状態で2つに大きな変化は見えない

マージratio
dim=autoで固定してratioを変更させたパターン

dim=auto / ratio=1.0

3つのモデルをマージするから割合を3等分にしてみた → 効かねぇ。ゴムだからか?

dim=auto / ratio=0.33
dim=auto / ratio=0.5
dim=auto / ratio=0.6
dim=auto / ratio=0.7

間を取って0.6くらいがいいかなーと思いもう少し細かく適用度を刻んだ画像を出してみると、結構いい感じに見えたのでこれで行こうと思います。

dim=auto / ratio=0.6 1.0~2.0を別シードで確認

マージ設定

dim32版で作った3種のLoRAのマージでも良かったんだけど、一部のLoRAについては思ったほど効果が出ていないため、これまでの検証で作ってきたLoRAの中から出来が良かったものをマージしようと思います。

マージの設定は上記の検証でいい感じだったものを使うので次の設定で行います。

remake dimension:8
LoRAname1:ratio1:Blocks1…:LoRA1:0.6, LoRA2:0.6, LoRA3:0.6 ...

いくつかのLoRAでdim=autoとdim=8と両方試してみたけど、
どちらもほぼ同じ結果になったから明示的にdim=8に指定しているよ。
(十条さんも小さい変化ならdim=8とかにしていると言っていたし・・・)

どんなモデルをマージしたか代表で1つ例示するね

マージ元のLoRA

他のLoRAは大体3つのLoRAをマージしていたんだけど、「え」の口 LoRAだけは5種類をマージしたんだけど・・・。5つともratio=0.6で適用したら効きすぎてしまったのでここだけratio=0.3に落としてマージしました。

第8章 完成品のレビュー

検証として
1.シード値「1111」「2222」「3333」3つに対して
LoRAの適用度を-1.0~2.0の間で変化させたx/y/z plotの画像
2.ランダムなシード値9つに適用度「1.0」「1.5」「2.0」を当てた画像
をそれぞれ作成。効き具合について確認してみるよ


「あ」LoRA

x/y/z plot
ランダムSeed

「い」LoRA

x/y/z plot
ランダムSeed

「う」LoRA

x/y/z plot
ランダムSeed

「え」LoRA

x/y/z plot
ランダムSeed

「お」LoRA

x/y/z plot
ランダムSeed

これでも最初に比べたら大分抑制されるようになってるので、1.5とかに弱めて当てれば問題なく使えそう。大丈夫大丈夫。

検証結果もいい感触だったし、ローカルに置いておくだけだと勿体ないから折角なのでCivitaiにアップロードしておくよ。

使い方がわからんマン参上!

第9章 おわりに

えらく長いこと同じところで足踏みすることにはなりましたが、なんとかLoRAの完成までこぎつけることができました。

最初にも書いた通りSDXL版「あ」~「お」の口LoRAには目的があって、2023年12月頃に遊んでたStreamDiffusionでの課題(open mouthだけでは口の形までは制御できない)を解決するために作り始めたものだったんだけど、なんやかんや長いことLoRA沼に嵌ることになってしまいました。

愚者が経験に学んでるところの一部始終をまとめただけですが、似たようなところで引っかかってる人の役に立てば幸いです。

高カロリー記事のご視聴、クソありがとうございました!


この記事が気に入ったらサポートをしてみませんか?