2024年4月21日日曜日

作ったSDXLのLoRAをLoRA Block Weightで調整

前回SDXLのLoRAをメモリ少なめのカードで学習する方法を紹介しました。

そこで学習したLoRAですがメモリ制約でいろいろと省略したことで、ややいまいちな点になることに困っていました。具体的には色が平坦になったり、色味のバランスや、線描がベースにしたモデルとかけ離れたものになってしまったりということです。

そこでLoRA Block Weight(LBW)というプラグインで各層の重みを変更することで、調整をしてみました。SDXLは実はSD 1.5の時と層の数が異なるので、このプラグインの説明を少し丁寧にみる必要がありました。

1.  LoRA Block Weightプラグインの導入

A1111版のwebuiやwebui Forgeを使っている方は、Extentions->Install from URLで、URLに```https://github.com/hako-mikan/sd-webui-lora-block-weight.git‘‘‘と入力してインストール、UIの再起動をしてください。

 2.ベースモデルとLoRA適用の画像を見比べる

題材としたベースモデルは bluePencilXL_v600.safetensors です。
次の最初の画像が、ベースモデルだけの画像。下の画像が、最初の画像とプロンプトなどは同じ条件にしたうえで、自作LoRAを動作させて出力させたものです。

オリジナルモデルの画像

LoRA適用以外は上と同条件の画像
人物自体はかなり私好みになっているのですが、全体的に体の立体感が無く、赤味のコントラストや、髪の毛・体のエッジが強すぎてちょっとベースモデルの良さを生かせていません。そこで次に分析をしていきます。

3. LoRA Block Weightの"Effective Block Analyzer"機能を使う
この機能を使うことで、モデルの層ごとのLoRAの効き具合を調べることができます。これを使って過剰にLoRAによる補正がかかっている層を探すことができます。

3.1 プロンプトにLoRA Block Weight用の呪文を入れる

プロンプト内でLoRAを記載している個所を

<lora:original_lora:1:1:lbw=XYZ

のように1:lbw=という記載を追加します。1:がダブっているように見えますが合っています。(original_loraというのか仮称で、あなたが作ったLoRAのファイル名を入れてください。)

3.3 LBWを有効にし、Effective Block Analyzer を設定する。

下図の通りLBWを有効にして、LBW内のXYZ Plotで、「Effective Block Analyzer」を選択、Range, Blocksの各欄に、

Range:0,1

Blocks:12ALL

を記入し、あとはデフォルトのままとしてください。SD1.5の時に使ったことがある人は、あれ?17ALLではないのか、と思うかもしれませんが、SDXLでは12層しか適用されないのです

3.3 この状態で”Generate”を実行します。

4. 結果を見る

12枚+1枚の画像を出力し、最後に、グリッド画像が生成されます。これは12層の各層へのLoRAの適用をひとつずつOffにしてみた画像の列になります。 


今回作ったLoRAでは、 BASE層のほか、特にOUT01層を0、つまりOUT01層へのLoRAによる上書きを無効にした場合の差分が大きいようです。特にOUT01層を0にした場合の絵は色味がビビッドでありながら全体的にグラデーションが柔らかく、また、描線も軽くなってベースモデルにかなり近い印象です。

つまり、私が作ったblue_pencil-XL用のこのLoRAはOUT01層に対してかなり強めの矯正をかけていて、それがバランスを崩させているということがわかります。

5.解析の結果をもとに、LoRAの重みを変える。

プロンプト内で先程1:lbw=としたところを、書き換えます。書き換えにあたって、影響が強かった層のウェイトを下げます。具体的には、先程の例でいうOUT01層のウェイトを少し下げます。ここでも少し特殊な記法で、

<lora:original_lora:1:1:lbw=1,1,1,1,1,1,1,0.8,1,1,1,1>

と記載します。赤字で0.8としたところがOUT01層に相当する箇所です。ちなみに画像はこちら。

lbw=1,1,1,1,1,1,1,0.8,1,1,1,1

いかがでしょう。人物の風味を残しつつ、色味や絵の雰囲気はベースモデルに近づいています。0にするのではなく、1より少し小さい0.8とか0.7とかに重みを軽くするだけでも大分変化が出ます。ちなみに赤字の箇所を0にするとこちら。↓

lbw=1,1,1,1,1,1,1,0,1,1,1,1

これはこれでかわいらしいですね。blue_pencil-XLは少し幼めな感じが得意なモデルで、それが強く出てます。

 ちなみに、lbw=に続く数字の列は

lbw=BASE, IN04, IN05, IN07, IN08, MID, OUT00, OUT01,OUT02,OUT03, OUT04,OUT05

の各層への重みに対応しています。

 5. その他

SDXLの場合[IN04,IN05],[IN07,IN08]、[OUT00,OUT01,OUT02]、[OUT03,OUT04,OUT05]を塊としてLoRAの重みによる顕著な変化の傾向が見られます。これは、SDXLのUnetで画像を生成していく際に、サイズが変更がかかる層ごとの区切りのようです。私は、この塊ごとにプリセットを用意して、XYZプロットを実行してLoRAの影響具合を確認しています。。

私のプリセット(XLXXXとあるのがデフォルトに追加したもの)

6. SDXLモデルに関する所感

SD1.5に比べると、モデルの学習量がかなり疎な印象があります。SD1.5の時はどのモデルもどんなプロンプトでもそれなりの絵が出てきました。が、SDXLではモデルの得手不得手がはっきりしているような気がします。おそらく、SDXLで大きくなったネットワークに十分にデータをため込めていないのではと思いました。

LoRAで学習する際に、追加学習させようとした絵とモデルの知識がかけ離れている場合、今回のように特定の層にひずみをかけて適応が進むのだと思いました。

また、LoRAがSD1.5の時に比べると他のモデルに適用できないのもそのせいだと思います。 モデルごとにNWで学習がされている場所が異なり、LoRAが制御をかける箇所がモデルごとに異なるのだと思います。

いくつか試した中ではAnimagineXL3系モデルは、追加データをかなり厚く使って学習しておりLoRAも安定した出力が出る印象です。

今回使ったblue_pencil-XLはマージモデル(それでもかなりのモデルをマージしていますが)で今回の事象が顕著になったのかなと思いました。

 


2024年4月14日日曜日

8GBのGPUカード+Windows環境でSDXLのLoRA学習にチャレンジ

最近はSDXLを使った作品作りの試行錯誤をしています。いろいろやっていくとどうしても絵柄を調整したくなる。SD1.5では実はオリジナルのLoRAを作っていました。

私は手元ではメモリ8GBのGeForece RTX2070 Superを使っています。通常のRAMは16GBです。

SDXLのLoRA学習は画像生成時以上にメモリが必要とのことでしたが、調べるとU-net部分だけに絞るなどのテクを使えば可能、とあったのですが、いろいろ調べて試してみたら、fp8_baseというオプションを使うことで、そこそこの速度で、この環境でもテキストエンコーダも含めたLoRAが学習できたのでご紹介したいと思います。

SD 1.5でのLoRAづくりをしたことがある人を前提に記載しています。
また、グラボのドライバとgit,Python 3.10以上がインストールされていることも前提です。この辺りはwebuiなどを使っていればおそらく問題はないと思います。

1. 準備
・仮想メモリの割り当てを増やしておく
    システムのプロパティ-パフォーマンス-詳細設定タブ-仮想メモリで、最大仮想メモリが30GB弱割り当てられるようにしておく。(学習の初期に一瞬かなりのメモリを消費するポイントがあるようです)

2. sd-scriptsのインストール
git,pipなどを使って、インストールしていきます。

適当なフォルダを作り、powershellを起動し、そのフォルダの中で以下のコマンドを起動。スクリプト本体と作業用のpython仮想環境を作成します。
git clone  https://github.com/kohya-ss/sd-scripts.git
cd sd-scripts

python -m venv venv
.\venv\Scripts\activate

必要なライブラリを 入れていきます。

pip install torch==2.1.0 torchvision==0.16.0 torchaudio==2.1.0 --index-url https://download.pytorch.org/whl/cu118

pip install --upgrade -r requirements.txt

pip install xformers==0.0.22.post7 --index-url https://download.pytorch.org/whl/cu118

一部のファイルをコピーします。

cp .\bitsandbytes_windows\*.dll .\venv\Lib\site-packages\bitsandbytes\

cp .\bitsandbytes_windows\cextension.py .\venv\Lib\site-packages\bitsandbytes\cextension.py

cp .\bitsandbytes_windows\main.py .\venv\Lib\site-packages\bitsandbytes\cuda_setup\main.py

 いくつかフォルダも掘っておきます

mkdir dataset 

mkdir outputs

mkdir logs 


3.データの準備

mkdir dataset  

を実行します。その下に、1024x1024以上のサイズの画像と、キャプションをセットにしたデータを配置しますが、この例ではさらにサブフォルダに

    10_class名

という名前のフォルダを作り、その下にデータを置きます。dataset.tomlを指定する方法もあるのですが、上記フォルダの先頭が示す、その画像に対する繰り返し回数を画像セットごとに指定できるので、私は旧来からのこの方法でデータを配置しています。

また、一つのサブフォルダ内の画像セットの縦横のピクセル数は同一である必要があります。なお、ぴったり1024x1024ある必要は、この例ではありません。

また、キャプションテキストファイルの拡張子は.captionとしています。キャプションを付与するタガーの使い方などはここでは省略します。

4.config.yamlファイルの準備

 以下の内容の、config.yamlファイルを作ります。

command_file: null
commands: null
compute_environment: LOCAL_MACHINE
deepspeed_config: {}
distributed_type: 'NO'
downcast_bf16: 'no'
dynamo_backend: 'NO'
fsdp_config: {}
gpu_ids: all
machine_rank: 0
main_process_ip: null
main_process_port: null
main_training_function: main
megatron_lm_config: {}
mixed_precision: 'no'
num_machines: 1
num_processes: 1
rdzv_backend: static
same_network: true
tpu_name: null
tpu_zone: null
use_cpu: false

5.GPUメモリをできるだけ空ける

できるだけ、実行されているアプリを減らし、GPUメモリを空けます

  1. ブラウザ、常駐タスクを終了する。(タスクトレイアイコンも忘れずに)
  2. ディスプレイサイズを800x600にする
  3. 視覚効果を全部切る。(ウインドウマネージャが使うメモリを減らす)

   特に3点目、PC-プロパティ-システム詳細設定-システムのプロパティ-パフォーマンスオプション-「パフォーマンスを優先する」

です。ここまでやると、かなり学習以外のGPUメモリの消費量を下げれると思います。私はこんな感じです。


目標は、「専用GPUメモリ」だけをLoRAの学習に使わせることです。共有GPUメモリを使いだすととたんに学習に必要な時間が3~10倍になってしまいます。逆に、計算時間を我慢すれば、GPUメモリが少なくても共有GPUメモリの仕組みを使ってもう少し制約が少ないLoRAの学習ができないわけでもないです。

6. 学習の実行

以下のコマンドを実行します。bat,cmdファイルにしておいてもよいと思います。

accelerate launch --config_file=".\config.yaml" sdxl_train_network.py `
    --pretrained_model_name_or_path="学習の対象にしたいチェックポイント.safetensors"  `
    --vae="(VAEのありかのフルパス)sdxl_vae.safetensors" `
    --fp8_base `
    --output_dir=".\outputs"    `
    --output_name=sdxl_test_lora  `
    --save_model_as=safetensors  `
    --prior_loss_weight=1.0  `
    --max_train_steps=10  `
    --learning_rate=1e-4  `
    --optimizer_type="adafactor"  `
    --xformers  `
    --mixed_precision="fp16"  `
    --cache_latents_to_disk `
    --enable_bucket `
    --caption_extension=".caption" `
    --gradient_checkpointing `
    --save_every_n_epochs=1  `
    --network_module=networks.lora `
    --no_half_vae `
    --network_dim=8 `
    --network_alpha=2 `
    --bucket_reso_steps=64 `
    --logging_dir=".\logs" `
    --max_train_epochs=2 `
    --train_batch_size=3 `
    --train_data_dir=".\dataset_tmp" --resolution="1024,1024" --min_bucket_reso=256 --max_bucket_reso=2048 

ここではLoRAのRankのディメンジョン数を8、バッチサイズを3にしています。私の環境ではこれが限界でした。また、--fb8_base オプションが重要でして、これがあることで、必要GPUメモリがぐっと減らせます。学習をU-net部分に限定する --network_train_unet_only を指定する必要がなくなりました。

ちなみにこの設定の時の学習の状況は以下のような感じ。


まあ、ギリギリですかね。

さて、学習方法はこれで何とかつかめたのですが、なかなか良い感じの絵柄が生成できなくて困っています。しばらくパラメータを振ったりしていきたいと思います。

補足:Winodows環境では以下のワーニングが出てきます。tritonはWindowsではサポートされていないそうですが、無視しても大丈夫とのことです。 

A matching Triton is not available, some optimizations will not be enabled. Error caught was: No module named 'triton' 


 

2024年4月7日日曜日

ControlnetのtileでSDXL 1.0の高解像度化

Stable diffusion webui Forgeが登場して、メモリが節約されることで比較的前のスペックのGPUカードでもSDXL 1.0での生成が高速になったこともあるのか、多くのモデルやLoRAが登場しだしています。

私もこれから、SDXLでも作品を作っていこうかあぁと思っているのですが、一つ問題なのが、画像のスケールアップ。それなりのサイズの画像を作ろうとすると8GBのメモリではやはりきつい。そもそも大きい画像の生成は時間がかかるので、小さめの画像を作って、気に入ったものをアップスケールするというのが通常のやり方になるかと思います。

SD1.5ではforgeのimg2imgにあるSD Upscale+controlnetのTileを使っていました。
SDXL用のcontrolnetのモデルもつい先日、以下にリリースがされています。

https://huggingface.co/bdsqlsz/qinglong_controlnet-lllite/tree/main

ここではForgeでの使い方を説明します。ForgeならはじめからControlNetが使えるようになっていてあとはモデルダウンロードするだけですみます。

0. 上記URLのモデルをダウンロード&配置
ダウンロードしたら
 /webui/models/ControlNet
配下に置きます。UIを再起動します。

1.txt2imgで画像を生成する
    1024x1024で画像を生成します。例は以下のパラメータで生成しました。
  • 使用モデル:bluePencilXL_v600
  • プロンプト:1girl, best, japanese, pale blue casual dress, skinny body, Seductive expression, hotel bed room,smiling, black hair
  • ネガティブプロンプト:nsfw, lowres, bad anatomy, bad hands, text, error, missing fingers, extra digit, fewer digits, cropped, worst quality, low quality, normal quality, jpeg artifacts, signature, watermark, username, blurry, artist name
  • CFG Step:Steps: 23, Sampler: Euler a, CFG scale: 7.5

なかなかかわいらしくできました。

2.できた画像をimg2imgタブに送る
   ”Send image and generation parameters to img2img tab"でimg2imgタブに送ります。


Resizeモードは"Just Resize"を選びます。
画面最上部、Stable Diffusion checkpointとプロンプト、ネガティブプロンプトはtxt2imgの際と同じものを入力します。vae,clipskipなども指定していたら同様です。

3."Resize to"タブでWidthとHeightに元画像サイズと同じぐらいの値を指定する
 2倍の2048x2048にしたいなら、それぞれ1024です。小さくても、大きくても構いませんが、大きいとメモリを食って時間もかかります。小さいと、分割処理が細かくなってやはり時間がかかります。画像も荒れるかもしれません。

4. Denoising strengthを小さい数字にします
0.7ではおそらく絵が荒れます。 SD1.5では0.3ぐらいが多かったですが。口述しますが、SDXL1.0では0.2未満、0.17から0.15ぐらいがちょうどよいのではと思いました。

5.ControlNetの設定
  まず、”ControlNet Unit 0”にチェックを入れ、
  • Enableチェックボックスをチェック
  • Conrol Typeで”Tile”を選択
  • Preprocessorを選ぶ:これはSD1.5のものと同じでよいです。"tile_resample","tile_colorfix+sharp"など。私はどちらかというと"tile_resample"の方が好きです。絵が柔らかく仕上がります。
  • Moldelを選ぶ:手順0.のダウンロード・ファイル配置が正しければ"bdsqlsz_controlllite_xl_tile_realistic"が選べると思います。

6. Scriptの設定
 img2imgタブの一番下にある"Script"にて、”SD Upscale"を選びます。
  • TileOverlap:分割処理の際、処理を重ねるピクセル数。ここは64でよいと思います
  • ScaleFactor:元のサイズの何倍の絵にするか。1024x1024の絵を2048x2048にしたいのでここでは”2"を選びます。小数点2桁で指定ができます
  • Upscaler:お好みのアップスケーラを選びます。SD1.5と同じものが指定できます。私は4x-UltraSharp他は、SwinIR_4xやR-ESRGAN 4x+を選ぶことが多いです
Script




7. 実行
 Generateボタンを押して処理を待ちます。

以上です。
いろいろ試行錯誤していると、おかしくなることがあります。(おそらくGPUメモリへのモデルの出し入れのせい)その際は再起動しましょう

■Denoise Strength
4でも書きましたがDenoise Strength(D.S)はSDXL1.0はSD1.5よりセンシティブに思います。
         左 D.S 0.5                                右 D.S 0.17

一見同じように見えますが、D.Sが0.5の方はあちこちにノイズが入っています。

右の髪の毛の部分に変な湧きだしが生じています。また右目の目元にもゴミが出ています。

D.Sはなかなか調整が難しいのでアップスケーラの変更と合わせながら調整をするのがいいと思いますが。数字は控えめにするのがよいかと思います。

最後に今日の表現
ワンピースの服は英語では ”Casual dress"といいます。
水色 "pale blue" (淡い青色)

2024年4月3日水曜日

Stable diffusion の呪文として、使えそうな手の表現

Stable diffusion の呪文として、使えそうな手の表現

小指 pinky finger, little finger,
人差し指 index finger,pointer finger
中指 middle finger, long finger, second finger
薬指 third finger, ring finger
親指 thumb
親指の付け根の盛り上がったところ ball of the thumb 
つまむ pinch 
手の平を下に向けて水平にする palm down
指を伸ばす Fingers extended

スラっとした手 slender fingers
手を軽く握ってできる親指と人差し指で囲まれてできる穴:clasp
握られた親指と人差し指。A thumb and forefinger held in a grip.

薬指がthirdなのは、人差し指、中指に次いでの指ということらしいです
肌色のこと fair skin


拳:fist
Make a fist with your thumb inside