独自のキャラクター(人型でないキャラクター)をLoRAを利用して学習する (SDXL版) - Stable Diffusion

人型でない独自のキャラクターをLoRAを利用して学習して、どのような出力が得られるか確認します。

概要

こちらの記事ではStable DiffusionでLoRAを利用して、 人型でない独自のキャラクターを学習する手順を紹介しました。 この記事では、SDXLでLoRAを利用して学習する手順を紹介します。
メモ
人型でないキャラクターを学習するのは難易度が高く、学習が苦手とされています。今回の記事でも実用面では不十分な結果となっています。 が、2024年6月版では品質の向上がだいぶ進みました。

事前準備:sd-scriptsのインストール

sd-scriptsをインストールします。手順はこちらの記事を参照してください。

SDXLの学習はsdxlブランチでないと実行できない場合があります。その際は以下のコマンドを実行して、sdxlブランチに切り替えます。
git switch sdxl 
または
(git.exe のフルパス) switch sdxl 

教師データの準備

まずは、少ないデータでどの程度の出力が得られるのかを確認します。以下の画像とキャプションを用意します。
学習データはこちらの記事の「学習データ (テスト用 ミニ v2)」を使用します。
今回正則化画像は用意しません。

ファイルの配置とtomlファイルの準備

学習データを配置してtomlファイルを作成します。以下のtomlファイルを作成します。
学習データの配置先は、C:\data\lora-toricchi-xl\toricchiです。 tomlファイルは C:\data\lora-toricchi-xl\config.toml に配置します。
[general]
enable_bucket = true 

[[datasets]]
resolution = 1024
batch_size = 1

[[datasets.subsets]]
image_dir = 'C:\data\lora-toricchi-xl\toricchi'
caption_extension = '.txt'
num_repeats = 1

sd-scripts起動バッチファイルの作成

sd-scriptsを起動するコマンドを記述したバッチファイルを作成します。 今回は、"CounterfeitXL β" モデルに対して学習を実行します。
作成したバッチファイルはC:\data\lora-toricchi-xl\exec.bat に配置します。
Stable Diffusionとの違いは、実行するスクリプトが train_network.py から sdxl_train_network.py に変更になります。 また、--network_train_unet_only --cache_text_encoder_outputs のオプションを追加しています。

テキストエンコーダーを学習しない理由
--network_train_unet_only オプションを追加し、テキストエンコーダーを学習しない設定にしています。 SDXLはテキストエンコーダーが2つあり、テキストエンコーダーの学習時の挙動がよくわかっていない部分があるため、 また、SDXLのテキストエンコーダーのもともとの性能が高いため、 テキストエンコーダーの学習をせずに、U-Netのみを学習したほうが良いとされています。
accelerate launch ^
--num_cpu_threads_per_process 1 ^
sdxl_train_network.py ^
--pretrained_model_name_or_path=C:\data\model\CounterfeitXL_beta.safetensors ^
--dataset_config=C:\data\lora-toricchi-xl\config.toml ^
--output_dir=C:\data\lora-toricchi-xl\output ^
--output_name=toricchi ^
--save_model_as=safetensors ^
--prior_loss_weight=1.0 ^
--max_train_steps=500 ^
--learning_rate=1e-4 ^
--optimizer_type=AdamW8bit ^
--xformers ^
--mixed_precision="bf16" ^
--cache_latents ^
--gradient_checkpointing ^
--save_every_n_epochs=1 ^
--persistent_data_loader_workers ^
--network_train_unet_only ^
--cache_text_encoder_outputs ^
--network_module=networks.lora

学習の実行

仮想環境に切り替えて、exec.batを実行します。
実行コマンド例
cd C:\Storage\Image-Gen\sd-scripts-xl\sd-scripts
.\venv\Scripts\Activation.bat
C:\data\lora-toricchi-xl\exec.bat


学習が実行できると、safetensorsファイルが指定したEpochごとにファイルに出力されます。

動作確認

次の4つのプロンプトで動作を確認します。
Prompt1: girl
Prompt: 1girl, illustration <lora:toricchi:1>
Negative prompt: worst quality, low quality
Prompt2: toricchi
Prompt: toricchi, illustration <lora:toricchi:1>
Negative prompt: worst quality, low quality
Prompt3: toricchi duck
Prompt: toricchi duck, illustration <lora:toricchi:1>
Negative prompt: worst quality, low quality
Prompt4: girl + toricchi duck
Prompt: 1girl holding toricchi duck, illustration <lora:toricchi:1>
Negative prompt: worst quality, low quality

LoRAなし

LoRAなしの場合の結果です。
Prompt1: girl
Prompt2: toricchi
Prompt3: toricchi duck
Prompt4: girl + toricchi duck

Epoch:30 (210 Step)

Epoch 30 のLoRAを適用した結果です。Girlのプロンプトにはわずかな変化しかありませんが、toricchiプロンプトには鳥のイメージが出力されます。 toricchi duckは学習元画像の結果がそれなりに反映されています。gitl+toricchi duckにも学習元画像が反映されていますが、girlも鳥になってしまうケースがあります。
Prompt1: girl
Prompt2: toricchi
Prompt3: toricchi duck
Prompt4: girl + toricchi duck

Epoch:50 (350 Step)

Epoch 50 のLoRAを適用した結果です。Girlのプロンプトにも変化が出始め、若干コミカルな絵が出力されます。toricchiプロンプトには鳥のイメージが出力されます。 toricchi duckは学習元画像の結果がそれなりに反映されています。gitl+toricchi duckにも学習元画像が反映されていますが、girlも鳥になってしまうケースがあります。
Prompt1: girl
Prompt2: toricchi
Prompt3: toricchi duck
Prompt4: girl + toricchi duck

Epoch:70 (490 Step)

Epoch 70 のLoRAを適用した結果です。Girlのプロンプトにも絵柄が反映され、ややコミカルな画像の出力になります。toricchiプロンプトは鳥のイメージが出力されます。 toricchi duckは学習元画像の結果がかなり反映されています。gitl+toricchi duckにも学習元画像が反映されていますが、girlもtoricchiになってしまう出力です。
Prompt1: girl
Prompt2: toricchi
Prompt3: toricchi duck
Prompt4: girl + toricchi duck

SDXLに対して学習する

あまりうまくいかなかったため、SDXLのベースモデルに対して学習したLoRAをアニメモデルに適用して結果を確認します。

学習設定ファイル

今回は --config-file オプションを利用します。 オプションの詳細はこちらの記事を参照してください。
exec.bat
accelerate launch --num_cpu_threads_per_process 1 sdxl_train_network.py --config_file=D:\data\lora-toricchi-xl2\config.toml
config.toml
[model_arguments]
pretrained_model_name_or_path = "D:\\data\\model\\sdXL_v10VAEFix.safetensors"

[additional_network_arguments]
network_train_unet_only = true
cache_text_encoder_outputs = true
network_module = "networks.lora"

[optimizer_arguments]
optimizer_type = "AdamW8bit"
learning_rate = 1e-4

[dataset_arguments]
dataset_config = "D:\\data\\lora-toricchi-xl2\\dataset.toml"
cache_latents = true

[training_arguments]
output_dir = "D:\\data\\lora-toricchi-xl2\\output"
output_name = "toricchi"
save_every_n_epochs = 1
save_model_as = "safetensors"
max_train_steps = 500
xformers = true
mixed_precision= "bf16"
gradient_checkpointing = true
persistent_data_loader_workers = true

[dreambooth_arguments]
prior_loss_weight = 1.0
dataset.toml
[general]
enable_bucket = true 

[[datasets]]
resolution = 1024
batch_size = 1

[[datasets.subsets]]
image_dir = 'D:\data\lora-toricchi-xl2\toricchi'
caption_extension = '.txt'
num_repeats = 1

Epoch:70 (490 Step)

実行結果は以下です。girlプロンプトに toricchiがあまり反映されておらず、いい感じです。toricchi や toricchi duckには学習元の画像がある程度反映されています。
さらに学習を進めるともしかすると良い結果が出るかもしれません。
Prompt1: girl
Prompt2: toricchi
Prompt3: toricchi duck
Prompt4: girl + toricchi duck

Epoch:140 (980 Step)

学習を重ねても、多少の変化はありましたが、大きな変化は出ませんでした。
Prompt1: girl
Prompt2: toricchi
Prompt3: toricchi duck
Prompt4: girl + toricchi duck

toricchi <lora:toricchi-000140:1> のプロンプトで下図の画像が生成されました。何も表示されていませんが、キャプションに含まれる"black border"により、輪郭線がないものとして学習されたのかもしれません。

SDXLに対して学習する + keep_tokensを指定

検討した結果次の対処を入れることにしました。
  • VAEを焼きこんだモデルに対して学習するのはあまりよくないという情報を得たため、VAEなしのSDXLで学習
  • キャプションから、black border を除去
  • 白いキャラクターを白背景で学習するのは良くないのではないかとの懸念から背景をグレーに
  • keep_tokens を設定し、toricchi のキャプションが先頭になる動作に変更

学習データ

学習データはこちらの記事の「学習データ (テスト用 ミニ v3)」となりました。

学習設定ファイル

exec.bat
accelerate launch --num_cpu_threads_per_process 1 sdxl_train_network.py --config_file=D:\data\lora-toricchi-xl3\config.toml
config.toml
[model_arguments]
pretrained_model_name_or_path = "D:\\data\\model\\sdXL_v10.safetensors"

[additional_network_arguments]
network_train_unet_only = true
cache_text_encoder_outputs = true
network_module = "networks.lora"

[optimizer_arguments]
optimizer_type = "AdamW8bit"
learning_rate = 1e-4
network_dim = 128
network_alpha = 1

[dataset_arguments]
dataset_config = "D:\\data\\lora-toricchi-xl3\\dataset.toml"
cache_latents = true

[training_arguments]
output_dir = "D:\\data\\lora-toricchi-xl3\\output"
output_name = "toricchi"
save_every_n_epochs = 10
save_model_as = "safetensors"
max_train_steps = 1000
xformers = true
mixed_precision= "bf16"
gradient_checkpointing = true
persistent_data_loader_workers = true

keep_tokens = 1

[dreambooth_arguments]
prior_loss_weight = 1.0
dataset.toml
[general]
enable_bucket = true 

[[datasets]]
resolution = 1024
batch_size = 1

[[datasets.subsets]]
image_dir = 'D:\data\lora-toricchi-xl3\toricchi'
caption_extension = '.txt'
num_repeats = 1

Epoch:70 (490 Step)

Prompt1: girl
Prompt2: toricchi
Prompt3: toricchi duck
Prompt4: girl + toricchi duck

Epoch:140 (980 Step)

toricchiプロンプトはノイズ画像になってしまいます。
Prompt1: girl
Prompt2: toricchi
Prompt3: toricchi duck
Prompt4: girl + toricchi duck

学習データの見直しと、network_dim, network_alpha の値の選定

学習データを見直します。
"duck" と結び付けて学習したほうが良さそうなため、キャプションに"duck"を追加します。また、"Pokemon" は学習への影響が強い印象があるため削除します。"manga"や"comic"は "manga style", "comic style", "anime style" としてstyleを追記します。
作成したデータセットは、こちらのページの「学習データ (テスト用 ミニ v4)」になります。

network_dimの値は4とします。詳しくはこちらの記事を参照してください。
また、network_alpha の値は2とします。詳しくはこちらの記事を参照してください。

結果

次のプロンプトで出力結果を確認します。
Prompt
Prompt: <lora:toricchi-000nnn:1> toricchi duck
Negative prompt: worst quality, low quality

Epoch 40

崩れは少ないですが、形状が学習元画像をあまり反映していないです。

Epoch 70

形状が学習元画像をやや反映していますが、幾何学模様のような出力結果が増え、崩れが目立ちます。

Epoch 100

形状が学習元画像をやや反映していますが、幾何学模様のような出力結果がさらに増え、崩れが目立ちます。

Epoch 140

形状が学習元画像をそこそこ忠実に反映していますが、幾何学模様のような出力結果が目立ちます。

評価・所感

幾何学模様のような画像を出さないためには、network_alphaの値をもっと下げたほうが良さそうです。つまり network_alphaは1が良さそうです。
学習の回数を増やすことで学習元の形状が忠実に出力されるため、学習回数を増やし、network_dimの値を上げるのが良さそうです。

再作成

network_dim=32, network_alpha=1 で作成します。学習回数を10,000回に設定します。
Epoch100ごとの出力画像の違いを確認します。
次のプロンプトで出力結果を確認します。
Prompt
Prompt: <lora:toricchi-000nnn:1> toricchi duck
Negative prompt: worst quality, low quality
Epoch: 100

アヒルと学習画像が混じったイメージが出力されます。崩れも目立ちます。
Epoch: 200

学習画像に近づきます。崩れも若干あります。
Epoch: 300

学習画像にかなり忠実になります。
Epoch: 400

学習画像に忠実になります。
Epoch: 500

Epoch500以上ではほぼ違いがありません。
Epoch: 600
Epoch: 700
Epoch: 800
Epoch: 900
Epoch: 1000
Epoch: 1100
Epoch: 1200
Epoch: 1300
Epoch: 1400

プロンプトを変更して出力結果を確認します。
Prompt
Prompt: <lora:toricchi-000nnn:1> toricchi duck, on the beach
Negative prompt: worst quality, low quality
Epoch: 200

学習画像が反映されていますが、若干崩れがあります。
Epoch: 400

Epch400以上ではほとんど違いがありません。
Epoch: 800

Epoch: 1200

2024年6月版 : Prodigy使用

Prodigyを利用して、LoRAを作成します。Animagine XL v3.1に対して学習します。
network_train_unet_only = true を指定してテキストエンコーダーのみの学習としています。

設定ファイル

exec.bat (起動用バッチファイル)
accelerate launch --num_cpu_threads_per_process 1 sdxl_train_network.py --config_file=D:\data\lora-toricchi-2024-06\config.toml
config.toml
[model_arguments]
pretrained_model_name_or_path = "D:\\data\\model\\animagine-xl-3.1.safetensors"

[additional_network_arguments]
network_train_unet_only = true
cache_text_encoder_outputs = true
network_module = "networks.lora"

[optimizer_arguments]
optimizer_type = "prodigy"
optimizer_args = ["betas=0.9,0.999", "weight_decay=0"]
unet_lr = 1
network_dim = 16
network_alpha = 1
network_args = ["conv_dim=8"]

[dataset_arguments]
dataset_config = "D:\\data\\lora-toricchi-2024-06\\dataset.toml"
cache_latents = true

[training_arguments]
output_dir = "D:\\data\\lora-toricchi-2024-06\\output"
output_name = "toricchi"
save_every_n_epochs = 1
save_model_as = "safetensors"
max_train_steps = 2000
xformers = true
mixed_precision= "fp16"
save_precision = "fp16"
gradient_checkpointing = true
persistent_data_loader_workers = true

[dreambooth_arguments]
prior_loss_weight = 1.0

[sample_arguments]
sample_every_n_epochs = 2
sample_sampler = "k_euler_a"
sample_prompts = "D:\\data\\lora-toricchi-2024-06\\prompts.txt"
dataset.toml
[general]
enable_bucket = true 

[[datasets]]
resolution = 1024
batch_size = 12

[[datasets.subsets]]
image_dir = 'D:\data\lora-toricchi-2024-06\image'
caption_extension = '.txt'
num_repeats = 64
prompts.txt
toricchi, duck, sitting, --w 1024 --h 1024 --d 100000
toricchi, duck, standing, --w 1024 --h 1024 --d 200000
toricchi, duck, up arms, --w 1024 --h 1024 --d 100000
toricchi, duck, jumping, --w 1024 --h 1024 --d 200000

学習データ

こちらの記事の「学習データ (2024-06版)」を使用します。

結果

次のプロンプトで出力結果を確認します。
LoRAはEpoch 4 を使用します。

以下のプロンプトで生成します。
Prompt
Prompt: toricchi, duck,masterpiece, <lora:toricchi-000004:1>
Negative prompt: worst quality, low quality
Sampling method: DPM++ 2M, Schedule type: Automatic, Sampling steps: 20

崩れてしまう画像もありますが、まずまずの結果の画像も多いです。
Animagine XL v3.1

AnimaPencil v5.0.0


Prompt
Prompt: toricchi, duck, cyberpunk, dark city, battle, masterpiece, <lora:toricchi-000004:1>
Negative prompt: worst quality, low quality
Sampling method: DPM++ 2M, Schedule type: Automatic, Sampling steps: 20

プロンプトが元の画像のイメージと大きく違うためか、リアルに脚色されてしまう場合もありますが、それらしいキャラクターは描画できています。
Animagine XL v3.1

AnimaPencil v5.0.0


Prompt
Prompt: toricchi, duck,1 girl hugging toricchi, sunflower field background, blue sky, masterpiece, <lora:toricchi-000004:1>
Negative prompt: worst quality, low quality
Sampling method: DPM++ 2M, Schedule type: Automatic, Sampling steps: 20
成功率は低いですが、女の子が「とりっち」を抱いているイメージが生成できています。
Animagine XL v3.1

AnimaPencil v5.0.0

評価・所感

学習画像を増やし、Prodigyを利用して学習したLoRAを使用しましたが、成功率は低いですが、品質面ではまずまずの画像が生成できています。

学習の所感

学習画像の枚数がある程度多いため、num_repeats = 64 は大きすぎる印象です。もう少し小さい値(32,16)で刻んだほうが良さそうです。
著者
iPentecのメインデザイナー
Webページ、Webクリエイティブのデザインを担当。PhotoshopやIllustratorの作業もする。
掲載日: 2023-08-12
iPentec all rights reserverd.