mirror of
https://github.com/kohya-ss/sd-scripts.git
synced 2026-04-09 06:45:09 +00:00
update cache_latents/text_encoder_outputs
This commit is contained in:
@@ -325,7 +325,7 @@ class TextEncoderOutputsCachingStrategy:
|
|||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
cache_to_disk: bool,
|
cache_to_disk: bool,
|
||||||
batch_size: int,
|
batch_size: Optional[int],
|
||||||
skip_disk_cache_validity_check: bool,
|
skip_disk_cache_validity_check: bool,
|
||||||
is_partial: bool = False,
|
is_partial: bool = False,
|
||||||
is_weighted: bool = False,
|
is_weighted: bool = False,
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ from accelerate.utils import set_seed
|
|||||||
import torch
|
import torch
|
||||||
from tqdm import tqdm
|
from tqdm import tqdm
|
||||||
|
|
||||||
from library import config_util
|
from library import config_util, flux_utils, strategy_base, strategy_flux, strategy_sd, strategy_sdxl
|
||||||
from library import train_util
|
from library import train_util
|
||||||
from library import sdxl_train_util
|
from library import sdxl_train_util
|
||||||
from library.config_util import (
|
from library.config_util import (
|
||||||
@@ -17,42 +17,73 @@ from library.config_util import (
|
|||||||
BlueprintGenerator,
|
BlueprintGenerator,
|
||||||
)
|
)
|
||||||
from library.utils import setup_logging, add_logging_arguments
|
from library.utils import setup_logging, add_logging_arguments
|
||||||
|
|
||||||
setup_logging()
|
setup_logging()
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
def set_tokenize_strategy(is_sd: bool, is_sdxl: bool, is_flux: bool, args: argparse.Namespace) -> None:
|
||||||
|
if is_flux:
|
||||||
|
_, is_schnell, _ = flux_utils.check_flux_state_dict_diffusers_schnell(args.pretrained_model_name_or_path)
|
||||||
|
else:
|
||||||
|
is_schnell = False
|
||||||
|
|
||||||
|
if is_sd or is_sdxl:
|
||||||
|
tokenize_strategy = strategy_sd.SdTokenizeStrategy(args.v2, args.max_token_length, args.tokenizer_cache_dir)
|
||||||
|
elif is_sdxl:
|
||||||
|
tokenize_strategy = strategy_sdxl.SdxlTokenizeStrategy(args.max_token_length, args.tokenizer_cache_dir)
|
||||||
|
else:
|
||||||
|
if args.t5xxl_max_token_length is None:
|
||||||
|
if is_schnell:
|
||||||
|
t5xxl_max_token_length = 256
|
||||||
|
else:
|
||||||
|
t5xxl_max_token_length = 512
|
||||||
|
else:
|
||||||
|
t5xxl_max_token_length = args.t5xxl_max_token_length
|
||||||
|
|
||||||
|
logger.info(f"t5xxl_max_token_length: {t5xxl_max_token_length}")
|
||||||
|
tokenize_strategy = strategy_flux.FluxTokenizeStrategy(t5xxl_max_token_length, args.tokenizer_cache_dir)
|
||||||
|
strategy_base.TokenizeStrategy.set_strategy(tokenize_strategy)
|
||||||
|
|
||||||
|
|
||||||
def cache_to_disk(args: argparse.Namespace) -> None:
|
def cache_to_disk(args: argparse.Namespace) -> None:
|
||||||
setup_logging(args, reset=True)
|
setup_logging(args, reset=True)
|
||||||
train_util.prepare_dataset_args(args, True)
|
train_util.prepare_dataset_args(args, True)
|
||||||
|
|
||||||
# check cache latents arg
|
# assert args.cache_latents_to_disk, "cache_latents_to_disk must be True / cache_latents_to_diskはTrueである必要があります"
|
||||||
assert args.cache_latents_to_disk, "cache_latents_to_disk must be True / cache_latents_to_diskはTrueである必要があります"
|
args.cache_latents = True
|
||||||
|
args.cache_latents_to_disk = True
|
||||||
|
|
||||||
use_dreambooth_method = args.in_json is None
|
use_dreambooth_method = args.in_json is None
|
||||||
|
|
||||||
if args.seed is not None:
|
if args.seed is not None:
|
||||||
set_seed(args.seed) # 乱数系列を初期化する
|
set_seed(args.seed) # 乱数系列を初期化する
|
||||||
|
|
||||||
# tokenizerを準備する:datasetを動かすために必要
|
is_sd = not args.sdxl and not args.flux
|
||||||
if args.sdxl:
|
is_sdxl = args.sdxl
|
||||||
tokenizer1, tokenizer2 = sdxl_train_util.load_tokenizers(args)
|
is_flux = args.flux
|
||||||
tokenizers = [tokenizer1, tokenizer2]
|
|
||||||
|
set_tokenize_strategy(is_sd, is_sdxl, is_flux, args)
|
||||||
|
|
||||||
|
if is_sd or is_sdxl:
|
||||||
|
latents_caching_strategy = strategy_sd.SdSdxlLatentsCachingStrategy(is_sd, True, args.vae_batch_size, args.skip_cache_check)
|
||||||
else:
|
else:
|
||||||
tokenizer = train_util.load_tokenizer(args)
|
latents_caching_strategy = strategy_flux.FluxLatentsCachingStrategy(True, args.vae_batch_size, args.skip_cache_check)
|
||||||
tokenizers = [tokenizer]
|
strategy_base.LatentsCachingStrategy.set_strategy(latents_caching_strategy)
|
||||||
|
|
||||||
# データセットを準備する
|
# データセットを準備する
|
||||||
|
use_user_config = args.dataset_config is not None
|
||||||
if args.dataset_class is None:
|
if args.dataset_class is None:
|
||||||
blueprint_generator = BlueprintGenerator(ConfigSanitizer(True, True, False, True))
|
blueprint_generator = BlueprintGenerator(ConfigSanitizer(True, True, args.masked_loss, True))
|
||||||
if args.dataset_config is not None:
|
if use_user_config:
|
||||||
logger.info(f"Load dataset config from {args.dataset_config}")
|
logger.info(f"Loading dataset config from {args.dataset_config}")
|
||||||
user_config = config_util.load_user_config(args.dataset_config)
|
user_config = config_util.load_user_config(args.dataset_config)
|
||||||
ignored = ["train_data_dir", "in_json"]
|
ignored = ["train_data_dir", "reg_data_dir", "in_json"]
|
||||||
if any(getattr(args, attr) is not None for attr in ignored):
|
if any(getattr(args, attr) is not None for attr in ignored):
|
||||||
logger.warning(
|
logger.warning(
|
||||||
"ignore following options because config file is found: {0} / 設定ファイルが利用されるため以下のオプションは無視されます: {0}".format(
|
"ignoring the following options because config file is found: {0} / 設定ファイルが利用されるため以下のオプションは無視されます: {0}".format(
|
||||||
", ".join(ignored)
|
", ".join(ignored)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
@@ -83,17 +114,11 @@ def cache_to_disk(args: argparse.Namespace) -> None:
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
blueprint = blueprint_generator.generate(user_config, args, tokenizer=tokenizers)
|
blueprint = blueprint_generator.generate(user_config, args)
|
||||||
train_dataset_group = config_util.generate_dataset_group_by_blueprint(blueprint.dataset_group)
|
train_dataset_group = config_util.generate_dataset_group_by_blueprint(blueprint.dataset_group)
|
||||||
else:
|
else:
|
||||||
train_dataset_group = train_util.load_arbitrary_dataset(args, tokenizers)
|
# use arbitrary dataset class
|
||||||
|
train_dataset_group = train_util.load_arbitrary_dataset(args)
|
||||||
# datasetのcache_latentsを呼ばなければ、生の画像が返る
|
|
||||||
|
|
||||||
current_epoch = Value("i", 0)
|
|
||||||
current_step = Value("i", 0)
|
|
||||||
ds_for_collator = train_dataset_group if args.max_data_loader_n_workers == 0 else None
|
|
||||||
collator = train_util.collator_class(current_epoch, current_step, ds_for_collator)
|
|
||||||
|
|
||||||
# acceleratorを準備する
|
# acceleratorを準備する
|
||||||
logger.info("prepare accelerator")
|
logger.info("prepare accelerator")
|
||||||
@@ -106,72 +131,27 @@ def cache_to_disk(args: argparse.Namespace) -> None:
|
|||||||
|
|
||||||
# モデルを読み込む
|
# モデルを読み込む
|
||||||
logger.info("load model")
|
logger.info("load model")
|
||||||
if args.sdxl:
|
if is_sd:
|
||||||
|
_, vae, _, _ = train_util.load_target_model(args, weight_dtype, accelerator)
|
||||||
|
elif is_sdxl:
|
||||||
(_, _, _, vae, _, _, _) = sdxl_train_util.load_target_model(args, accelerator, "sdxl", weight_dtype)
|
(_, _, _, vae, _, _, _) = sdxl_train_util.load_target_model(args, accelerator, "sdxl", weight_dtype)
|
||||||
else:
|
else:
|
||||||
_, vae, _, _ = train_util.load_target_model(args, weight_dtype, accelerator)
|
vae = flux_utils.load_ae(args.ae, weight_dtype, "cpu", disable_mmap=args.disable_mmap_load_safetensors)
|
||||||
|
|
||||||
|
if is_sd or is_sdxl:
|
||||||
if torch.__version__ >= "2.0.0": # PyTorch 2.0.0 以上対応のxformersなら以下が使える
|
if torch.__version__ >= "2.0.0": # PyTorch 2.0.0 以上対応のxformersなら以下が使える
|
||||||
vae.set_use_memory_efficient_attention_xformers(args.xformers)
|
vae.set_use_memory_efficient_attention_xformers(args.xformers)
|
||||||
|
|
||||||
vae.to(accelerator.device, dtype=vae_dtype)
|
vae.to(accelerator.device, dtype=vae_dtype)
|
||||||
vae.requires_grad_(False)
|
vae.requires_grad_(False)
|
||||||
vae.eval()
|
vae.eval()
|
||||||
|
|
||||||
# dataloaderを準備する
|
# cache latents with dataset
|
||||||
train_dataset_group.set_caching_mode("latents")
|
# TODO use DataLoader to speed up
|
||||||
|
train_dataset_group.new_cache_latents(vae, accelerator)
|
||||||
# DataLoaderのプロセス数:0 は persistent_workers が使えないので注意
|
|
||||||
n_workers = min(args.max_data_loader_n_workers, os.cpu_count()) # cpu_count or max_data_loader_n_workers
|
|
||||||
|
|
||||||
train_dataloader = torch.utils.data.DataLoader(
|
|
||||||
train_dataset_group,
|
|
||||||
batch_size=1,
|
|
||||||
shuffle=True,
|
|
||||||
collate_fn=collator,
|
|
||||||
num_workers=n_workers,
|
|
||||||
persistent_workers=args.persistent_data_loader_workers,
|
|
||||||
)
|
|
||||||
|
|
||||||
# acceleratorを使ってモデルを準備する:マルチGPUで使えるようになるはず
|
|
||||||
train_dataloader = accelerator.prepare(train_dataloader)
|
|
||||||
|
|
||||||
# データ取得のためのループ
|
|
||||||
for batch in tqdm(train_dataloader):
|
|
||||||
b_size = len(batch["images"])
|
|
||||||
vae_batch_size = b_size if args.vae_batch_size is None else args.vae_batch_size
|
|
||||||
flip_aug = batch["flip_aug"]
|
|
||||||
alpha_mask = batch["alpha_mask"]
|
|
||||||
random_crop = batch["random_crop"]
|
|
||||||
bucket_reso = batch["bucket_reso"]
|
|
||||||
|
|
||||||
# バッチを分割して処理する
|
|
||||||
for i in range(0, b_size, vae_batch_size):
|
|
||||||
images = batch["images"][i : i + vae_batch_size]
|
|
||||||
absolute_paths = batch["absolute_paths"][i : i + vae_batch_size]
|
|
||||||
resized_sizes = batch["resized_sizes"][i : i + vae_batch_size]
|
|
||||||
|
|
||||||
image_infos = []
|
|
||||||
for i, (image, absolute_path, resized_size) in enumerate(zip(images, absolute_paths, resized_sizes)):
|
|
||||||
image_info = train_util.ImageInfo(absolute_path, 1, "dummy", False, absolute_path)
|
|
||||||
image_info.image = image
|
|
||||||
image_info.bucket_reso = bucket_reso
|
|
||||||
image_info.resized_size = resized_size
|
|
||||||
image_info.latents_npz = os.path.splitext(absolute_path)[0] + ".npz"
|
|
||||||
|
|
||||||
if args.skip_existing:
|
|
||||||
if train_util.is_disk_cached_latents_is_expected(
|
|
||||||
image_info.bucket_reso, image_info.latents_npz, flip_aug, alpha_mask
|
|
||||||
):
|
|
||||||
logger.warning(f"Skipping {image_info.latents_npz} because it already exists.")
|
|
||||||
continue
|
|
||||||
|
|
||||||
image_infos.append(image_info)
|
|
||||||
|
|
||||||
if len(image_infos) > 0:
|
|
||||||
train_util.cache_batch_latents(vae, True, image_infos, flip_aug, alpha_mask, random_crop)
|
|
||||||
|
|
||||||
accelerator.wait_for_everyone()
|
accelerator.wait_for_everyone()
|
||||||
accelerator.print(f"Finished caching latents for {len(train_dataset_group)} batches.")
|
accelerator.print(f"Finished caching latents to disk.")
|
||||||
|
|
||||||
|
|
||||||
def setup_parser() -> argparse.ArgumentParser:
|
def setup_parser() -> argparse.ArgumentParser:
|
||||||
@@ -182,7 +162,11 @@ def setup_parser() -> argparse.ArgumentParser:
|
|||||||
train_util.add_training_arguments(parser, True)
|
train_util.add_training_arguments(parser, True)
|
||||||
train_util.add_dataset_arguments(parser, True, True, True)
|
train_util.add_dataset_arguments(parser, True, True, True)
|
||||||
config_util.add_config_arguments(parser)
|
config_util.add_config_arguments(parser)
|
||||||
|
parser.add_argument(
|
||||||
|
"--ae", type=str, default=None, help="Autoencoder model of FLUX to use / 使用するFLUXのオートエンコーダモデル"
|
||||||
|
)
|
||||||
parser.add_argument("--sdxl", action="store_true", help="Use SDXL model / SDXLモデルを使用する")
|
parser.add_argument("--sdxl", action="store_true", help="Use SDXL model / SDXLモデルを使用する")
|
||||||
|
parser.add_argument("--flux", action="store_true", help="Use FLUX model / FLUXモデルを使用する")
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"--no_half_vae",
|
"--no_half_vae",
|
||||||
action="store_true",
|
action="store_true",
|
||||||
@@ -191,7 +175,8 @@ def setup_parser() -> argparse.ArgumentParser:
|
|||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"--skip_existing",
|
"--skip_existing",
|
||||||
action="store_true",
|
action="store_true",
|
||||||
help="skip images if npz already exists (both normal and flipped exists if flip_aug is enabled) / npzが既に存在する画像をスキップする(flip_aug有効時は通常、反転の両方が存在する画像をスキップ)",
|
help="[Deprecated] This option does not work. Existing .npz files are always checked. Use `--skip_cache_check` to skip the check."
|
||||||
|
" / [非推奨] このオプションは機能しません。既存の .npz は常に検証されます。`--skip_cache_check` で検証をスキップできます。",
|
||||||
)
|
)
|
||||||
return parser
|
return parser
|
||||||
|
|
||||||
|
|||||||
@@ -9,55 +9,68 @@ from accelerate.utils import set_seed
|
|||||||
import torch
|
import torch
|
||||||
from tqdm import tqdm
|
from tqdm import tqdm
|
||||||
|
|
||||||
from library import config_util
|
from library import (
|
||||||
|
config_util,
|
||||||
|
flux_train_utils,
|
||||||
|
flux_utils,
|
||||||
|
sdxl_model_util,
|
||||||
|
strategy_base,
|
||||||
|
strategy_flux,
|
||||||
|
strategy_sd,
|
||||||
|
strategy_sdxl,
|
||||||
|
)
|
||||||
from library import train_util
|
from library import train_util
|
||||||
from library import sdxl_train_util
|
from library import sdxl_train_util
|
||||||
|
from library import utils
|
||||||
from library.config_util import (
|
from library.config_util import (
|
||||||
ConfigSanitizer,
|
ConfigSanitizer,
|
||||||
BlueprintGenerator,
|
BlueprintGenerator,
|
||||||
)
|
)
|
||||||
from library.utils import setup_logging, add_logging_arguments
|
from library.utils import setup_logging, add_logging_arguments
|
||||||
|
from tools import cache_latents
|
||||||
|
|
||||||
setup_logging()
|
setup_logging()
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
def cache_to_disk(args: argparse.Namespace) -> None:
|
def cache_to_disk(args: argparse.Namespace) -> None:
|
||||||
setup_logging(args, reset=True)
|
setup_logging(args, reset=True)
|
||||||
train_util.prepare_dataset_args(args, True)
|
train_util.prepare_dataset_args(args, True)
|
||||||
|
|
||||||
# check cache arg
|
args.cache_text_encoder_outputs = True
|
||||||
assert (
|
args.cache_text_encoder_outputs_to_disk = True
|
||||||
args.cache_text_encoder_outputs_to_disk
|
|
||||||
), "cache_text_encoder_outputs_to_disk must be True / cache_text_encoder_outputs_to_diskはTrueである必要があります"
|
|
||||||
|
|
||||||
# できるだけ準備はしておくが今のところSDXLのみしか動かない
|
|
||||||
assert (
|
|
||||||
args.sdxl
|
|
||||||
), "cache_text_encoder_outputs_to_disk is only available for SDXL / cache_text_encoder_outputs_to_diskはSDXLのみ利用可能です"
|
|
||||||
|
|
||||||
use_dreambooth_method = args.in_json is None
|
use_dreambooth_method = args.in_json is None
|
||||||
|
|
||||||
if args.seed is not None:
|
if args.seed is not None:
|
||||||
set_seed(args.seed) # 乱数系列を初期化する
|
set_seed(args.seed) # 乱数系列を初期化する
|
||||||
|
|
||||||
# tokenizerを準備する:datasetを動かすために必要
|
is_sd = not args.sdxl and not args.flux
|
||||||
if args.sdxl:
|
is_sdxl = args.sdxl
|
||||||
tokenizer1, tokenizer2 = sdxl_train_util.load_tokenizers(args)
|
is_flux = args.flux
|
||||||
tokenizers = [tokenizer1, tokenizer2]
|
|
||||||
else:
|
assert (
|
||||||
tokenizer = train_util.load_tokenizer(args)
|
is_sdxl or is_flux
|
||||||
tokenizers = [tokenizer]
|
), "Cache text encoder outputs to disk is only supported for SDXL and FLUX models / テキストエンコーダ出力のディスクキャッシュはSDXLまたはFLUXでのみ有効です"
|
||||||
|
assert (
|
||||||
|
is_sdxl or args.weighted_captions is None
|
||||||
|
), "Weighted captions are only supported for SDXL models / 重み付きキャプションはSDXLモデルでのみ有効です"
|
||||||
|
|
||||||
|
cache_latents.set_tokenize_strategy(is_sd, is_sdxl, is_flux, args)
|
||||||
|
|
||||||
# データセットを準備する
|
# データセットを準備する
|
||||||
|
use_user_config = args.dataset_config is not None
|
||||||
if args.dataset_class is None:
|
if args.dataset_class is None:
|
||||||
blueprint_generator = BlueprintGenerator(ConfigSanitizer(True, True, False, True))
|
blueprint_generator = BlueprintGenerator(ConfigSanitizer(True, True, args.masked_loss, True))
|
||||||
if args.dataset_config is not None:
|
if use_user_config:
|
||||||
logger.info(f"Load dataset config from {args.dataset_config}")
|
logger.info(f"Loading dataset config from {args.dataset_config}")
|
||||||
user_config = config_util.load_user_config(args.dataset_config)
|
user_config = config_util.load_user_config(args.dataset_config)
|
||||||
ignored = ["train_data_dir", "in_json"]
|
ignored = ["train_data_dir", "reg_data_dir", "in_json"]
|
||||||
if any(getattr(args, attr) is not None for attr in ignored):
|
if any(getattr(args, attr) is not None for attr in ignored):
|
||||||
logger.warning(
|
logger.warning(
|
||||||
"ignore following options because config file is found: {0} / 設定ファイルが利用されるため以下のオプションは無視されます: {0}".format(
|
"ignoring the following options because config file is found: {0} / 設定ファイルが利用されるため以下のオプションは無視されます: {0}".format(
|
||||||
", ".join(ignored)
|
", ".join(ignored)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
@@ -88,15 +101,11 @@ def cache_to_disk(args: argparse.Namespace) -> None:
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
blueprint = blueprint_generator.generate(user_config, args, tokenizer=tokenizers)
|
blueprint = blueprint_generator.generate(user_config, args)
|
||||||
train_dataset_group = config_util.generate_dataset_group_by_blueprint(blueprint.dataset_group)
|
train_dataset_group = config_util.generate_dataset_group_by_blueprint(blueprint.dataset_group)
|
||||||
else:
|
else:
|
||||||
train_dataset_group = train_util.load_arbitrary_dataset(args, tokenizers)
|
# use arbitrary dataset class
|
||||||
|
train_dataset_group = train_util.load_arbitrary_dataset(args)
|
||||||
current_epoch = Value("i", 0)
|
|
||||||
current_step = Value("i", 0)
|
|
||||||
ds_for_collator = train_dataset_group if args.max_data_loader_n_workers == 0 else None
|
|
||||||
collator = train_util.collator_class(current_epoch, current_step, ds_for_collator)
|
|
||||||
|
|
||||||
# acceleratorを準備する
|
# acceleratorを準備する
|
||||||
logger.info("prepare accelerator")
|
logger.info("prepare accelerator")
|
||||||
@@ -105,66 +114,68 @@ def cache_to_disk(args: argparse.Namespace) -> None:
|
|||||||
|
|
||||||
# mixed precisionに対応した型を用意しておき適宜castする
|
# mixed precisionに対応した型を用意しておき適宜castする
|
||||||
weight_dtype, _ = train_util.prepare_dtype(args)
|
weight_dtype, _ = train_util.prepare_dtype(args)
|
||||||
|
t5xxl_dtype = utils.str_to_dtype(args.t5xxl_dtype, weight_dtype)
|
||||||
|
|
||||||
# モデルを読み込む
|
# モデルを読み込む
|
||||||
logger.info("load model")
|
logger.info("load model")
|
||||||
if args.sdxl:
|
if is_sdxl:
|
||||||
(_, text_encoder1, text_encoder2, _, _, _, _) = sdxl_train_util.load_target_model(args, accelerator, "sdxl", weight_dtype)
|
_, text_encoder1, text_encoder2, _, _, _, _ = sdxl_train_util.load_target_model(
|
||||||
|
args, accelerator, sdxl_model_util.MODEL_VERSION_SDXL_BASE_V1_0, weight_dtype
|
||||||
|
)
|
||||||
|
text_encoder1.to(accelerator.device, weight_dtype)
|
||||||
|
text_encoder2.to(accelerator.device, weight_dtype)
|
||||||
text_encoders = [text_encoder1, text_encoder2]
|
text_encoders = [text_encoder1, text_encoder2]
|
||||||
else:
|
else:
|
||||||
text_encoder1, _, _, _ = train_util.load_target_model(args, weight_dtype, accelerator)
|
clip_l = flux_utils.load_clip_l(
|
||||||
text_encoders = [text_encoder1]
|
args.clip_l, weight_dtype, accelerator.device, disable_mmap=args.disable_mmap_load_safetensors
|
||||||
|
)
|
||||||
|
|
||||||
|
t5xxl = flux_utils.load_t5xxl(args.t5xxl, None, accelerator.device, disable_mmap=args.disable_mmap_load_safetensors)
|
||||||
|
|
||||||
|
if t5xxl.dtype == torch.float8_e4m3fnuz or t5xxl.dtype == torch.float8_e5m2 or t5xxl.dtype == torch.float8_e5m2fnuz:
|
||||||
|
raise ValueError(f"Unsupported fp8 model dtype: {t5xxl.dtype}")
|
||||||
|
elif t5xxl.dtype == torch.float8_e4m3fn:
|
||||||
|
logger.info("Loaded fp8 T5XXL model")
|
||||||
|
|
||||||
|
if t5xxl_dtype != t5xxl_dtype:
|
||||||
|
if t5xxl.dtype == torch.float8_e4m3fn and t5xxl_dtype.itemsize() >= 2:
|
||||||
|
logger.warning(
|
||||||
|
"The loaded model is fp8, but the specified T5XXL dtype is larger than fp8. This may cause a performance drop."
|
||||||
|
" / ロードされたモデルはfp8ですが、指定されたT5XXLのdtypeがfp8より高精度です。精度低下が発生する可能性があります。"
|
||||||
|
)
|
||||||
|
logger.info(f"Casting T5XXL model to {t5xxl_dtype}")
|
||||||
|
t5xxl.to(t5xxl_dtype)
|
||||||
|
|
||||||
|
text_encoders = [clip_l, t5xxl]
|
||||||
|
|
||||||
for text_encoder in text_encoders:
|
for text_encoder in text_encoders:
|
||||||
text_encoder.to(accelerator.device, dtype=weight_dtype)
|
|
||||||
text_encoder.requires_grad_(False)
|
text_encoder.requires_grad_(False)
|
||||||
text_encoder.eval()
|
text_encoder.eval()
|
||||||
|
|
||||||
# dataloaderを準備する
|
# build text encoder outputs caching strategy
|
||||||
train_dataset_group.set_caching_mode("text")
|
if is_sdxl:
|
||||||
|
text_encoder_outputs_caching_strategy = strategy_sdxl.SdxlTextEncoderOutputsCachingStrategy(
|
||||||
# DataLoaderのプロセス数:0 は persistent_workers が使えないので注意
|
args.cache_text_encoder_outputs_to_disk, None, args.skip_cache_check, is_weighted=args.weighted_captions
|
||||||
n_workers = min(args.max_data_loader_n_workers, os.cpu_count()) # cpu_count or max_data_loader_n_workers
|
|
||||||
|
|
||||||
train_dataloader = torch.utils.data.DataLoader(
|
|
||||||
train_dataset_group,
|
|
||||||
batch_size=1,
|
|
||||||
shuffle=True,
|
|
||||||
collate_fn=collator,
|
|
||||||
num_workers=n_workers,
|
|
||||||
persistent_workers=args.persistent_data_loader_workers,
|
|
||||||
)
|
)
|
||||||
|
else:
|
||||||
# acceleratorを使ってモデルを準備する:マルチGPUで使えるようになるはず
|
text_encoder_outputs_caching_strategy = strategy_flux.FluxTextEncoderOutputsCachingStrategy(
|
||||||
train_dataloader = accelerator.prepare(train_dataloader)
|
args.cache_text_encoder_outputs_to_disk,
|
||||||
|
args.text_encoder_batch_size,
|
||||||
# データ取得のためのループ
|
args.skip_cache_check,
|
||||||
for batch in tqdm(train_dataloader):
|
is_partial=False,
|
||||||
absolute_paths = batch["absolute_paths"]
|
apply_t5_attn_mask=args.apply_t5_attn_mask,
|
||||||
input_ids1_list = batch["input_ids1_list"]
|
|
||||||
input_ids2_list = batch["input_ids2_list"]
|
|
||||||
|
|
||||||
image_infos = []
|
|
||||||
for absolute_path, input_ids1, input_ids2 in zip(absolute_paths, input_ids1_list, input_ids2_list):
|
|
||||||
image_info = train_util.ImageInfo(absolute_path, 1, "dummy", False, absolute_path)
|
|
||||||
image_info.text_encoder_outputs_npz = os.path.splitext(absolute_path)[0] + train_util.TEXT_ENCODER_OUTPUTS_CACHE_SUFFIX
|
|
||||||
image_info
|
|
||||||
|
|
||||||
if args.skip_existing:
|
|
||||||
if os.path.exists(image_info.text_encoder_outputs_npz):
|
|
||||||
logger.warning(f"Skipping {image_info.text_encoder_outputs_npz} because it already exists.")
|
|
||||||
continue
|
|
||||||
|
|
||||||
image_info.input_ids1 = input_ids1
|
|
||||||
image_info.input_ids2 = input_ids2
|
|
||||||
image_infos.append(image_info)
|
|
||||||
|
|
||||||
if len(image_infos) > 0:
|
|
||||||
b_input_ids1 = torch.stack([image_info.input_ids1 for image_info in image_infos])
|
|
||||||
b_input_ids2 = torch.stack([image_info.input_ids2 for image_info in image_infos])
|
|
||||||
train_util.cache_batch_text_encoder_outputs(
|
|
||||||
image_infos, tokenizers, text_encoders, args.max_token_length, True, b_input_ids1, b_input_ids2, weight_dtype
|
|
||||||
)
|
)
|
||||||
|
strategy_base.TextEncoderOutputsCachingStrategy.set_strategy(text_encoder_outputs_caching_strategy)
|
||||||
|
|
||||||
|
# build text encoding strategy
|
||||||
|
if is_sdxl:
|
||||||
|
text_encoding_strategy = strategy_sdxl.SdxlTextEncodingStrategy()
|
||||||
|
else:
|
||||||
|
text_encoding_strategy = strategy_flux.FluxTextEncodingStrategy(args.apply_t5_attn_mask)
|
||||||
|
strategy_base.TextEncodingStrategy.set_strategy(text_encoding_strategy)
|
||||||
|
|
||||||
|
# cache text encoder outputs
|
||||||
|
train_dataset_group.new_cache_text_encoder_outputs(text_encoders, accelerator)
|
||||||
|
|
||||||
accelerator.wait_for_everyone()
|
accelerator.wait_for_everyone()
|
||||||
accelerator.print(f"Finished caching latents for {len(train_dataset_group)} batches.")
|
accelerator.print(f"Finished caching latents for {len(train_dataset_group)} batches.")
|
||||||
@@ -179,11 +190,20 @@ def setup_parser() -> argparse.ArgumentParser:
|
|||||||
train_util.add_dataset_arguments(parser, True, True, True)
|
train_util.add_dataset_arguments(parser, True, True, True)
|
||||||
config_util.add_config_arguments(parser)
|
config_util.add_config_arguments(parser)
|
||||||
sdxl_train_util.add_sdxl_training_arguments(parser)
|
sdxl_train_util.add_sdxl_training_arguments(parser)
|
||||||
|
flux_train_utils.add_flux_train_arguments(parser)
|
||||||
parser.add_argument("--sdxl", action="store_true", help="Use SDXL model / SDXLモデルを使用する")
|
parser.add_argument("--sdxl", action="store_true", help="Use SDXL model / SDXLモデルを使用する")
|
||||||
|
parser.add_argument("--flux", action="store_true", help="Use FLUX model / FLUXモデルを使用する")
|
||||||
|
parser.add_argument(
|
||||||
|
"--t5xxl_dtype",
|
||||||
|
type=str,
|
||||||
|
default=None,
|
||||||
|
help="T5XXL model dtype, default: None (use mixed precision dtype) / T5XXLモデルのdtype, デフォルト: None (mixed precisionのdtypeを使用)",
|
||||||
|
)
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"--skip_existing",
|
"--skip_existing",
|
||||||
action="store_true",
|
action="store_true",
|
||||||
help="skip images if npz already exists (both normal and flipped exists if flip_aug is enabled) / npzが既に存在する画像をスキップする(flip_aug有効時は通常、反転の両方が存在する画像をスキップ)",
|
help="[Deprecated] This option does not work. Existing .npz files are always checked. Use `--skip_cache_check` to skip the check."
|
||||||
|
" / [非推奨] このオプションは機能しません。既存の .npz は常に検証されます。`--skip_cache_check` で検証をスキップできます。",
|
||||||
)
|
)
|
||||||
return parser
|
return parser
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user