LECO~特定の概念を削除したり強化したりするLoraの作り方~(Stable Diffusion)

2023年7月26日水曜日

stable-diffusion

t f B! P L

LECOとは

  • 教師画像なしで学習可能
  • モデルが持っている概念を削除したり強化したりできる
  • LoRAとして機能

という特徴を持った新しい学習方法です。この記事ではGoogle Colabで動かしていますが、ファイルパスなどを適切に設定すればローカルでも動くはずです。

erase(削除)を試す(題材: cat earsの削除)

Stable Diffusion から特定の概念を忘れさせる学習を行ってみるを参考に 試しに簡単なのを動かしてみます。

目的

プロンプトに1girl, cat tailとだけ入力して生成。当然猫耳しっぽの女の子が出てきます。

しっぽはプロンプトに入れたから出てくるのはわかりますが、cat earsを入力していないにもかかわらず猫耳も生えているのが気になります。気になりますね!

cat tailとcat earsの結びつきが強いからこうなると予想ができますが、しっぽだけがほしいという状況もあると思います。多分。

なのでサンプルに猫耳追加があったのでcat earsをerase(削除)してしっぽはあるが猫耳のない女の子を生成できるLoraをLECOを使って作ります。

config.yaml, prompt.yamlを書く

適当なディレクトリにerasecatearsというフォルダを作り、https://github.com/p1atdev/LECO/tree/main/examplesの例を参考にerase_cat_ears.yamlとerase_cat_ears_prompts.yamlを書いていきます。yamlファイル内に記述するファイルパスはGoogleドライブからファイルを読み取りGoogle Colabで学習することを考慮して記述します。

erase_cat_ears.yaml

prompts_file: "/content/drive/MyDrive/leco/erasecatears/erase_cat_ears_prompts.yaml"

pretrained_model:
  name_or_path: "/content/drive/MyDrive/SD/AOM3.safetensors" # you can also use .ckpt or .safetensors models
  v2: false # true if model is v2.x
  v_pred: false # true if model uses v-prediction

network:
  type: "lierla" # or "c3lier"
  rank: 4
  alpha: 1.0
  training_method: "full"

train:
  precision: "float32"
  noise_scheduler: "ddim" # or "ddpm", "lms", "euler_a"
  iterations: 500
  lr: 1e-4
  optimizer: "AdamW"
  lr_scheduler: "constant"

save:
  name: "erase_cat_ears"
  path: "/content/drive/MyDrive/leco/erasecatears/outputs"
  per_steps: 100
  precision: "float32"

logging:
  use_wandb: false
  verbose: false

other:
  use_xformers: true
  • 今回のケースではname_or_pathにGoogleドライブ内のAOM3を指定しています
  • sd1.5で使いたいのでv2とv_predをfalseにします
  • rankはよくわからないので初期値。少し上げてもいいかもしれません
  • precisionはfloat32。Colabの無料枠で使えるT4はbfloat16を使えず、float16だと学習の途中でlossがnanに飛んで失敗します

erase_cat_ears_prompts.yaml

- target: "cat ears" # what word for erasing the positive concept from
  positive: "cat ears" # concept to erase
  unconditional: "" # word to take the difference from the positive concept
  neutral: "" # starting point for conditioning the target
  action: "erase" # erase or enhance
  guidance_scale: 1.0
  resolution: 512
  batch_size: 1
  • batch_sizeを2にするとnanに飛んだので1にしてます。

これらをGoogleドライブに保存します。構造は以下の通り。

  • leco
    • erasecatears
      • erase_cat_ears.yaml
      • erase_cat_ears_prompts.yaml

(画像のoutputフォルダは無視してください。後で生成されます。)

学習

参考サイトを参考にColabで動かします。まずはGoogleドライブをマウント。

from google.colab import drive
drive.mount('/content/drive')

リポジトリをクローンしてライブラリをインストール。

!git clone https://github.com/p1atdev/LECO
%cd LECO

!virtualenv venv
!venv/bin/pip install torch torchvision --index-url https://download.pytorch.org/whl/cu118
!venv/bin/pip install xformers
!venv/bin/pip install -r requirements.txt

実行

!venv/bin/python ./train_lora.py --config_file "/content/drive/MyDrive/leco/erasecatears/erase_cat_ears.yaml"

2時間13分かかりました。yamlに書いたディレクトリにloraが生成されています。

Loss*1k: 0.9959: 100% 500/500 [2:13:03<00:00, 15.97s/it]
Saving...
Done.

学習に関係ないですが、colabの接続を切るコードを最後に予約しておくと放置中に学習が終わったら自動で接続を解除してくれます。コンピューティングユニットの無駄遣いを減らせます。

from google.colab import runtime
runtime.unassign()

作ったLoRAで画像生成して結果を見る

モデルはAOM3B2で出力しました。

  • しっぽ付き猫耳無しは出せた
  • ネガティブプロンプトにcat earsをつけるよりはlecoのほうが成功率が高い
  • おそらくiteration500, max_denoising_steps50は多い
  • 結びつきの強い概念が衝突しているせいか、loraのweightを上げると1girlごと概念が消えている気がする
  • loraをマイナス適用させて強める方向のほうが使いやすそう

今回作ったlecoのloraはweightが1のとき、cat tailのweightを1.2に強めないと耳、しっぽのどちらも出てきませんでした。

prompts

1girl,  (cat tail:1.2)
Negative prompt: (worst quality, low quality:1.4), censored, futanari, monochrome, extra digits, extra legs, nsfw, cleavage, cat
Steps: 20, Sampler: DPM++ 2M Karra

lecoで作ったloraを効かせた方は猫耳が生えておらず、しっぽが生えている。動物の猫が出るとその猫にcat earsとcat tailが吸われるのでネガティブにcatを入れました。

xにプロンプト(lecoの有無)、yにネガティブcat earsの有無。単にネガティブにcat earsとするよりはlecoで作ったloraを効かせたほうが効果がありそう。

lora効かせた方に申し訳程度に尻尾が生えている。negativeのcat earsはあまり効いてなさそう。

loraがある方は全身の描写になることが多かったです。512x512の全身絵ということもあって人物がボケている。なんとなくプロンプトに1girlを入れなかったときと雰囲気が似ている気がする。

iteration500が多かったのかweightが強すぎるのか。色々試してちょうどいいところを探す必要がありました。

1girl, (cat tail:1.2) <lora:erase_cat_ears_last:0.6>
Negative prompt: (worst quality, low quality:1.4), nsfw
Steps: 20, Sampler: Euler a

怪しいところもありますが、期待通り耳はなさそう。

loraのマイナス適用

今回の設定だとloraの強度がプラスだと全身のぼやけた絵が出やすかったです。逆にマイナス適用のほうがきれいな絵が出やすい印象でした。

1girl, <lora:erase_cat_ears_last:-2.5>, brown eyes, smile, meadow, sun, (wariza:1.2)
1girl, <lora:erase_cat_ears_last:-2.5>, brown eyes, smile, meadow, sun, jumping

適切なweightを探る必要がありますが、マイナス適用できれいに猫耳が出ました。しっぽも無い。

enhance(強化)を試す(題材: 白い髪と赤い目)

目的

白髪赤目がデフォルトで出るようにenhanceしたい。

設定

config.yaml。iterationsを500から200に減らし、max_denoising_stepsも50から20に減らしました。dim, alphaは16, 8。lr_schedulerをなんとなくcosineに。

prompts_file: "/content/drive/MyDrive/leco/enhancewhitehairredeyes/prompts.yaml"

pretrained_model:
  name_or_path: "/content/drive/MyDrive/SD/AOM3.safetensors" # you can also use .ckpt or .safetensors models
  v2: false # true if model is v2.x
  v_pred: false # true if model uses v-prediction

network:
  type: "lierla" # or "c3lier"
  rank: 16
  alpha: 8.0
  training_method: "full"

train:
  precision: "float32"
  noise_scheduler: "ddim" # or "ddpm", "lms", "euler_a"
  iterations: 200
  lr: "1e-4"
  optimizer: "AdamW"
  lr_scheduler: "cosine"
  max_denoising_steps: 20

save:
  name: "enhansewhitehairredeyes"
  path: "/content/drive/MyDrive/leco/enhancewhitehairredeyes/lecoenhansewhitehairredeyes"
  per_steps: 10
  precision: "float32"

logging:
  use_wandb: false
  verbose: false

other:
  use_xformers: true

prompts.yaml。actionをenhanceに。

- target: "1girl" # what word for erasing the positive concept from
  positive: "1girl, white hair, red eyes"
  unconditional: "" # word to take the difference from the positive concept
  neutral: "" # starting point for conditioning the target
  action: "enhance" # erase or enhance
  guidance_scale: 1.0
  resolution: 512
  batch_size: 1

学習

iterationsとmax_denoising_stepsを減らしたので30分ほどで学習が終了しました。

Loss*1k: 0.0093: 100% 200/200 [28:59<00:00,  8.70s/it]
Saving...
Done.

結果

1girl, upper bodyにloraを適用。weightは-4から4まで。weight1から白い髪、赤い目が出ています。可愛い雰囲気からどんどんと目つきが鋭くなって最後にはキリッとしているのは赤い目白い髪のキャラクターがそういう属性を持っていることが多いからだと思います。

1girl, upper body, sleepingを基準に、白髪赤目要素をloraで付けた場合とpromptで記述した場合の比較。sleepingだけでちゃんと目を瞑ってくれる。これが個人的に一番気になっていたことでしたがうまくいってよかったです。

1girl, upper body, blue dress, crown, wings, closed eyesを基準に生成。closed eyesを入力したがうっかり〇〇eyesを外し忘れて半目になる問題が解決できそうです。

たまに髪の色が衣服などの色にひっぱられるのでweight2で生成。特に品質の低下のようなものはなさそう。

  • enhanceで目の属性を強化したからといってclosed eyesと喧嘩するようなことはなかった
  • もしかしたら衣服を一つのタグにまとめられるかもしれない。そしてupper bodyなどで全身が表示されない構図でも問題なく表示されるかもしれない(skirtを入れっぱなしだとskirtを無理やり入れようとする問題)

LECOを使ってみた感想

  • 今までのLoraの学習と比べると学習そのものには時間がかかるが、教師画像を必要としないのでその分手軽
  • 単純なプロンプト、ネガティブプロンプトを入力したときと効き方が違う
  • iterationsやmax_denoising_stepsの良さそうな値を見つけるには試行錯誤がいる印象(画像を用意して作るLoRAのepoch数やsteps数も同じ)

新しい技術と使いやすい形でコードを書いてくれた方のおかげでまた画像生成AIにおける表現の幅が広がりそうです。

QooQ