Fix to work PIECEWISE_CONSTANT, update requirement.txt and README #1393

This commit is contained in:
Kohya S
2024-09-11 21:44:36 +09:00
parent fd68703f37
commit 6dbfd47a59
3 changed files with 54 additions and 25 deletions

View File

@@ -139,6 +139,15 @@ The majority of scripts is licensed under ASL 2.0 (including codes from Diffuser
### Working in progress ### Working in progress
- __important__ The dependent libraries are updated. Please see [Upgrade](#upgrade) and update the libraries.
- transformers, accelerate and huggingface_hub are updated.
- If you encounter any issues, please report them.
- en: The INVERSE_SQRT, COSINE_WITH_MIN_LR, and WARMUP_STABLE_DECAY learning rate schedules are now available in the transformers library. See PR [#1393](https://github.com/kohya-ss/sd-scripts/pull/1393) for details. Thanks to sdbds!
- See the [transformers documentation](https://huggingface.co/docs/transformers/v4.44.2/en/main_classes/optimizer_schedules#schedules) for details on each scheduler.
- `--lr_warmup_steps` and `--lr_decay_steps` can now be specified as a ratio of the number of training steps, not just the step value. Example: `--lr_warmup_steps=0.1` or `--lr_warmup_steps=10%`, etc.
https://github.com/kohya-ss/sd-scripts/pull/1393
- When enlarging images in the script (when the size of the training image is small and bucket_no_upscale is not specified), it has been changed to use Pillow's resize and LANCZOS interpolation instead of OpenCV2's resize and Lanczos4 interpolation. The quality of the image enlargement may be slightly improved. PR [#1426](https://github.com/kohya-ss/sd-scripts/pull/1426) Thanks to sdbds! - When enlarging images in the script (when the size of the training image is small and bucket_no_upscale is not specified), it has been changed to use Pillow's resize and LANCZOS interpolation instead of OpenCV2's resize and Lanczos4 interpolation. The quality of the image enlargement may be slightly improved. PR [#1426](https://github.com/kohya-ss/sd-scripts/pull/1426) Thanks to sdbds!
- Sample image generation during training now works on non-CUDA devices. PR [#1433](https://github.com/kohya-ss/sd-scripts/pull/1433) Thanks to millie-v! - Sample image generation during training now works on non-CUDA devices. PR [#1433](https://github.com/kohya-ss/sd-scripts/pull/1433) Thanks to millie-v!

View File

@@ -42,7 +42,10 @@ from torch.optim import Optimizer
from torchvision import transforms from torchvision import transforms
from transformers import CLIPTokenizer, CLIPTextModel, CLIPTextModelWithProjection from transformers import CLIPTokenizer, CLIPTextModel, CLIPTextModelWithProjection
import transformers import transformers
from diffusers.optimization import SchedulerType as DiffusersSchedulerType, TYPE_TO_SCHEDULER_FUNCTION as DIFFUSERS_TYPE_TO_SCHEDULER_FUNCTION from diffusers.optimization import (
SchedulerType as DiffusersSchedulerType,
TYPE_TO_SCHEDULER_FUNCTION as DIFFUSERS_TYPE_TO_SCHEDULER_FUNCTION,
)
from transformers.optimization import SchedulerType, TYPE_TO_SCHEDULER_FUNCTION from transformers.optimization import SchedulerType, TYPE_TO_SCHEDULER_FUNCTION
from diffusers import ( from diffusers import (
StableDiffusionPipeline, StableDiffusionPipeline,
@@ -2974,7 +2977,7 @@ def add_sd_models_arguments(parser: argparse.ArgumentParser):
def add_optimizer_arguments(parser: argparse.ArgumentParser): def add_optimizer_arguments(parser: argparse.ArgumentParser):
def int_or_float(value): def int_or_float(value):
if value.endswith('%'): if value.endswith("%"):
try: try:
return float(value[:-1]) / 100.0 return float(value[:-1]) / 100.0
except ValueError: except ValueError:
@@ -3041,13 +3044,15 @@ def add_optimizer_arguments(parser: argparse.ArgumentParser):
"--lr_warmup_steps", "--lr_warmup_steps",
type=int_or_float, type=int_or_float,
default=0, default=0,
help="Int number of steps for the warmup in the lr scheduler (default is 0) or float with ratio of train steps / 学習率のスケジューラをウォームアップするステップ数デフォルト0", help="Int number of steps for the warmup in the lr scheduler (default is 0) or float with ratio of train steps"
" / 学習率のスケジューラをウォームアップするステップ数デフォルト0、または学習ステップの比率1未満のfloat値の場合",
) )
parser.add_argument( parser.add_argument(
"--lr_decay_steps", "--lr_decay_steps",
type=int_or_float, type=int_or_float,
default=0, default=0,
help="Int number of steps for the decay in the lr scheduler (default is 0) or float with ratio of train steps", help="Int number of steps for the decay in the lr scheduler (default is 0) or float (<1) with ratio of train steps"
" / 学習率のスケジューラを減衰させるステップ数デフォルト0、または学習ステップの比率1未満のfloat値の場合",
) )
parser.add_argument( parser.add_argument(
"--lr_scheduler_num_cycles", "--lr_scheduler_num_cycles",
@@ -3071,13 +3076,16 @@ def add_optimizer_arguments(parser: argparse.ArgumentParser):
"--lr_scheduler_timescale", "--lr_scheduler_timescale",
type=int, type=int,
default=None, default=None,
help="Inverse sqrt timescale for inverse sqrt scheduler,defaults to `num_warmup_steps`", help="Inverse sqrt timescale for inverse sqrt scheduler,defaults to `num_warmup_steps`"
" / 逆平方根スケジューラのタイムスケール、デフォルトは`num_warmup_steps`",
,
) )
parser.add_argument( parser.add_argument(
"--lr_scheduler_min_lr_ratio", "--lr_scheduler_min_lr_ratio",
type=float, type=float,
default=None, default=None,
help="The minimum learning rate as a ratio of the initial learning rate for cosine with min lr scheduler and warmup decay scheduler", help="The minimum learning rate as a ratio of the initial learning rate for cosine with min lr scheduler and warmup decay scheduler"
" / 初期学習率の比率としての最小学習率を指定する、cosine with min lr と warmup decay スケジューラ で有効",
) )
@@ -4327,8 +4335,12 @@ def get_scheduler_fix(args, optimizer: Optimizer, num_processes: int):
""" """
name = args.lr_scheduler name = args.lr_scheduler
num_training_steps = args.max_train_steps * num_processes # * args.gradient_accumulation_steps num_training_steps = args.max_train_steps * num_processes # * args.gradient_accumulation_steps
num_warmup_steps: Optional[int] = int(args.lr_warmup_steps * num_training_steps) if isinstance(args.lr_warmup_steps, float) else args.lr_warmup_steps num_warmup_steps: Optional[int] = (
num_decay_steps: Optional[int] = int(args.lr_decay_steps * num_training_steps) if isinstance(args.lr_decay_steps, float) else args.lr_decay_steps int(args.lr_warmup_steps * num_training_steps) if isinstance(args.lr_warmup_steps, float) else args.lr_warmup_steps
)
num_decay_steps: Optional[int] = (
int(args.lr_decay_steps * num_training_steps) if isinstance(args.lr_decay_steps, float) else args.lr_decay_steps
)
num_stable_steps = num_training_steps - num_warmup_steps - num_decay_steps num_stable_steps = num_training_steps - num_warmup_steps - num_decay_steps
num_cycles = args.lr_scheduler_num_cycles num_cycles = args.lr_scheduler_num_cycles
power = args.lr_scheduler_power power = args.lr_scheduler_power
@@ -4369,15 +4381,17 @@ def get_scheduler_fix(args, optimizer: Optimizer, num_processes: int):
# logger.info(f"adafactor scheduler init lr {initial_lr}") # logger.info(f"adafactor scheduler init lr {initial_lr}")
return wrap_check_needless_num_warmup_steps(transformers.optimization.AdafactorSchedule(optimizer, initial_lr)) return wrap_check_needless_num_warmup_steps(transformers.optimization.AdafactorSchedule(optimizer, initial_lr))
name = SchedulerType(name) or DiffusersSchedulerType(name) if name == DiffusersSchedulerType.PIECEWISE_CONSTANT.value:
schedule_func = TYPE_TO_SCHEDULER_FUNCTION[name] or DIFFUSERS_TYPE_TO_SCHEDULER_FUNCTION[name] name = DiffusersSchedulerType(name)
schedule_func = DIFFUSERS_TYPE_TO_SCHEDULER_FUNCTION[name]
return schedule_func(optimizer, **lr_scheduler_kwargs) # step_rules and last_epoch are given as kwargs
name = SchedulerType(name)
schedule_func = TYPE_TO_SCHEDULER_FUNCTION[name]
if name == SchedulerType.CONSTANT: if name == SchedulerType.CONSTANT:
return wrap_check_needless_num_warmup_steps(schedule_func(optimizer, **lr_scheduler_kwargs)) return wrap_check_needless_num_warmup_steps(schedule_func(optimizer, **lr_scheduler_kwargs))
if name == DiffusersSchedulerType.PIECEWISE_CONSTANT:
return schedule_func(optimizer, **lr_scheduler_kwargs) # step_rules and last_epoch are given as kwargs
# All other schedulers require `num_warmup_steps` # All other schedulers require `num_warmup_steps`
if num_warmup_steps is None: if num_warmup_steps is None:
raise ValueError(f"{name} requires `num_warmup_steps`, please provide that argument.") raise ValueError(f"{name} requires `num_warmup_steps`, please provide that argument.")
@@ -4408,11 +4422,11 @@ def get_scheduler_fix(args, optimizer: Optimizer, num_processes: int):
if name == SchedulerType.COSINE_WITH_MIN_LR: if name == SchedulerType.COSINE_WITH_MIN_LR:
return schedule_func( return schedule_func(
optimizer, optimizer,
num_warmup_steps=num_warmup_steps, num_warmup_steps=num_warmup_steps,
num_training_steps=num_training_steps, num_training_steps=num_training_steps,
num_cycles=num_cycles / 2, num_cycles=num_cycles / 2,
min_lr_rate=min_lr_ratio, min_lr_rate=min_lr_ratio,
**lr_scheduler_kwargs, **lr_scheduler_kwargs,
) )
@@ -4421,16 +4435,22 @@ def get_scheduler_fix(args, optimizer: Optimizer, num_processes: int):
raise ValueError(f"{name} requires `num_decay_steps`, please provide that argument.") raise ValueError(f"{name} requires `num_decay_steps`, please provide that argument.")
if name == SchedulerType.WARMUP_STABLE_DECAY: if name == SchedulerType.WARMUP_STABLE_DECAY:
return schedule_func( return schedule_func(
optimizer, optimizer,
num_warmup_steps=num_warmup_steps, num_warmup_steps=num_warmup_steps,
num_stable_steps=num_stable_steps, num_stable_steps=num_stable_steps,
num_decay_steps=num_decay_steps, num_decay_steps=num_decay_steps,
num_cycles=num_cycles / 2, num_cycles=num_cycles / 2,
min_lr_ratio=min_lr_ratio if min_lr_ratio is not None else 0.0, min_lr_ratio=min_lr_ratio if min_lr_ratio is not None else 0.0,
**lr_scheduler_kwargs, **lr_scheduler_kwargs,
) )
return schedule_func(optimizer, num_warmup_steps=num_warmup_steps, num_training_steps=num_training_steps, num_decay_steps=num_decay_steps, **lr_scheduler_kwargs) return schedule_func(
optimizer,
num_warmup_steps=num_warmup_steps,
num_training_steps=num_training_steps,
num_decay_steps=num_decay_steps,
**lr_scheduler_kwargs,
)
def prepare_dataset_args(args: argparse.Namespace, support_metadata: bool): def prepare_dataset_args(args: argparse.Namespace, support_metadata: bool):

View File

@@ -1,5 +1,5 @@
accelerate==0.30.0 accelerate==0.30.0
transformers==4.41.2 transformers==4.44.0
diffusers[torch]==0.25.0 diffusers[torch]==0.25.0
ftfy==6.1.1 ftfy==6.1.1
# albumentations==1.3.0 # albumentations==1.3.0
@@ -16,7 +16,7 @@ altair==4.2.2
easygui==0.98.3 easygui==0.98.3
toml==0.10.2 toml==0.10.2
voluptuous==0.13.1 voluptuous==0.13.1
huggingface-hub==0.23.3 huggingface-hub==0.24.5
# for Image utils # for Image utils
imagesize==1.4.1 imagesize==1.4.1
# for BLIP captioning # for BLIP captioning