mirror of
https://github.com/kohya-ss/sd-scripts.git
synced 2026-04-08 06:28:48 +00:00
* feat: SD1.x/2.x と SDXL 向けの LECO 学習スクリプトを追加 (#2285)
* Add LECO training script and associated tests
- Implemented `sdxl_train_leco.py` for training with LECO prompts, including argument parsing, model setup, training loop, and weight saving functionality.
- Created unit tests for `load_prompt_settings` in `test_leco_train_util.py` to validate loading of prompt configurations in both original and slider formats.
- Added basic syntax tests for `train_leco.py` and `sdxl_train_leco.py` to ensure modules are importable.
* fix: use getattr for safe attribute access in argument verification
* feat: add CUDA device compatibility validation and corresponding tests
* Revert "feat: add CUDA device compatibility validation and corresponding tests"
This reverts commit 6d3e51431b.
* feat: update predict_noise_xl to use vector embedding from add_time_ids
* feat: implement checkpointing in predict_noise and predict_noise_xl functions
* feat: remove unused submodules and update .gitignore to exclude .codex-tmp
---------
Co-authored-by: Kohya S. <52813779+kohya-ss@users.noreply.github.com>
* fix: format
* fix: LECO PR #2285 のレビュー指摘事項を修正
- train_util.py/deepspeed_utils.py の getattr 化を元に戻し、LECO パーサーにダミー引数を追加
- sdxl_train_util のモジュールレベルインポートをローカルインポートに変更
- PromptEmbedsCache.__getitem__ でキャッシュミス時に KeyError を送出するよう修正
- 設定ファイル形式を YAML から TOML に変更(リポジトリの規約に統一)
- 重複コード (build_network_kwargs, get_save_extension, save_weights) を leco_train_util.py に統合
- _expand_slider_target の冗長な PromptSettings 構築を簡素化
- add_time_ids 用に専用の batch_add_time_ids 関数を追加
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* docs: LECO 学習ガイドを大幅に拡充
コマンドライン引数の全カテゴリ別解説、プロンプト TOML の全フィールド説明、
2つの guidance_scale の違い、推奨設定表、YAML からの変換ガイド等を追加。
英語本文と日本語折り畳みの二言語構成。
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: apply_noise_offset の dtype 不一致を修正
torch.randn のデフォルト float32 により latents が暗黙的にアップキャストされる問題を修正。
float32/CPU で生成後に latents の dtype/device へ変換する安全なパターンを採用。
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Umisetokikaze <52318966+umisetokikaze@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
117 lines
3.2 KiB
Python
117 lines
3.2 KiB
Python
from pathlib import Path
|
|
|
|
import torch
|
|
|
|
from library.leco_train_util import load_prompt_settings
|
|
|
|
|
|
def test_load_prompt_settings_with_original_format(tmp_path: Path):
|
|
prompt_file = tmp_path / "prompts.toml"
|
|
prompt_file.write_text(
|
|
"""
|
|
[[prompts]]
|
|
target = "van gogh"
|
|
guidance_scale = 1.5
|
|
resolution = 512
|
|
""".strip(),
|
|
encoding="utf-8",
|
|
)
|
|
|
|
prompts = load_prompt_settings(prompt_file)
|
|
|
|
assert len(prompts) == 1
|
|
assert prompts[0].target == "van gogh"
|
|
assert prompts[0].positive == "van gogh"
|
|
assert prompts[0].unconditional == ""
|
|
assert prompts[0].neutral == ""
|
|
assert prompts[0].action == "erase"
|
|
assert prompts[0].guidance_scale == 1.5
|
|
|
|
|
|
def test_load_prompt_settings_with_slider_targets(tmp_path: Path):
|
|
prompt_file = tmp_path / "slider.toml"
|
|
prompt_file.write_text(
|
|
"""
|
|
guidance_scale = 2.0
|
|
resolution = 768
|
|
neutral = ""
|
|
|
|
[[targets]]
|
|
target_class = ""
|
|
positive = "high detail"
|
|
negative = "low detail"
|
|
multiplier = 1.25
|
|
weight = 0.5
|
|
""".strip(),
|
|
encoding="utf-8",
|
|
)
|
|
|
|
prompts = load_prompt_settings(prompt_file)
|
|
|
|
assert len(prompts) == 4
|
|
|
|
first = prompts[0]
|
|
second = prompts[1]
|
|
third = prompts[2]
|
|
fourth = prompts[3]
|
|
|
|
assert first.target == ""
|
|
assert first.positive == "low detail"
|
|
assert first.unconditional == "high detail"
|
|
assert first.action == "erase"
|
|
assert first.multiplier == 1.25
|
|
assert first.weight == 0.5
|
|
assert first.get_resolution() == (768, 768)
|
|
|
|
assert second.positive == "high detail"
|
|
assert second.unconditional == "low detail"
|
|
assert second.action == "enhance"
|
|
assert second.multiplier == 1.25
|
|
|
|
assert third.action == "erase"
|
|
assert third.multiplier == -1.25
|
|
|
|
assert fourth.action == "enhance"
|
|
assert fourth.multiplier == -1.25
|
|
|
|
|
|
def test_predict_noise_xl_uses_vector_embedding_from_add_time_ids():
|
|
from library import sdxl_train_util
|
|
from library.leco_train_util import PromptEmbedsXL, predict_noise_xl
|
|
|
|
class DummyScheduler:
|
|
def scale_model_input(self, latent_model_input, timestep):
|
|
return latent_model_input
|
|
|
|
class DummyUNet:
|
|
def __call__(self, x, timesteps, context, y):
|
|
self.x = x
|
|
self.timesteps = timesteps
|
|
self.context = context
|
|
self.y = y
|
|
return torch.zeros_like(x)
|
|
|
|
latents = torch.randn(1, 4, 8, 8)
|
|
prompt_embeds = PromptEmbedsXL(
|
|
text_embeds=torch.randn(2, 77, 2048),
|
|
pooled_embeds=torch.randn(2, 1280),
|
|
)
|
|
add_time_ids = torch.tensor(
|
|
[
|
|
[1024, 1024, 0, 0, 1024, 1024],
|
|
[1024, 1024, 0, 0, 1024, 1024],
|
|
],
|
|
dtype=prompt_embeds.pooled_embeds.dtype,
|
|
)
|
|
|
|
unet = DummyUNet()
|
|
noise_pred = predict_noise_xl(unet, DummyScheduler(), torch.tensor(10), latents, prompt_embeds, add_time_ids)
|
|
|
|
expected_size_embeddings = sdxl_train_util.get_size_embeddings(
|
|
add_time_ids[:, :2], add_time_ids[:, 2:4], add_time_ids[:, 4:6], latents.device
|
|
).to(prompt_embeds.pooled_embeds.dtype)
|
|
|
|
assert noise_pred.shape == latents.shape
|
|
assert unet.context is prompt_embeds.text_embeds
|
|
assert torch.equal(unet.y, torch.cat([prompt_embeds.pooled_embeds, expected_size_embeddings], dim=1))
|