独自のキャラクター(人型でないキャラクター)をLoRAを利用して学習する (SDXL版) - Stable Diffusion
人型でない独自のキャラクターをLoRAを利用して学習して、どのような出力が得られるか確認します。
概要
こちらの記事ではStable DiffusionでLoRAを利用して、
人型でない独自のキャラクターを学習する手順を紹介しました。
この記事では、SDXLでLoRAを利用して学習する手順を紹介します。
メモ
人型でないキャラクターを学習するのは難易度が高く、学習が苦手とされています。今回の記事でも実用面では不十分な結果となっています。
が、2024年6月版では品質の向上がだいぶ進みました。
事前準備:sd-scriptsのインストール
sd-scriptsをインストールします。手順は
こちらの記事を参照してください。
SDXLの学習はsdxlブランチでないと実行できない場合があります。その際は以下のコマンドを実行して、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
オプションを利用します。
オプションの詳細は
こちらの記事を参照してください。
accelerate launch --num_cpu_threads_per_process 1 sdxl_train_network.py --config_file=D:\data\lora-toricchi-xl2\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
[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)」となりました。
学習設定ファイル
accelerate launch --num_cpu_threads_per_process 1 sdxl_train_network.py --config_file=D:\data\lora-toricchi-xl3\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
[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
を指定してテキストエンコーダーのみの学習としています。
設定ファイル
accelerate launch --num_cpu_threads_per_process 1 sdxl_train_network.py --config_file=D:\data\lora-toricchi-2024-06\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"
[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
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の作業もする。