Merge pull request #209 from bmaltais/dev

v20.7.4
This commit is contained in:
bmaltais 2023-02-19 20:16:51 -05:00 committed by GitHub
commit 39ac6b0086
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 261 additions and 17 deletions

View File

@ -64,6 +64,12 @@ cp .\bitsandbytes_windows\main.py .\venv\Lib\site-packages\bitsandbytes\cuda_set
accelerate config accelerate config
``` ```
<!--
pip install torch==1.13.1+cu117 torchvision==0.14.1+cu117 --extra-index-url https://download.pytorch.org/whl/cu117
pip install --use-pep517 --upgrade -r requirements.txt
pip install -U -I --no-deps xformers==0.0.16
-->
コマンドプロンプトでは以下になります。 コマンドプロンプトでは以下になります。

View File

@ -163,9 +163,23 @@ This will store your a backup file with your current locally installed pip packa
## Change History ## Change History
* 2023/02/16 (v20.7.3) * 2023/02/19 (v20.7.4):
- Add `--use_lion_optimizer` to each training script to use [Lion optimizer](https://github.com/lucidrains/lion-pytorch).
- Please install Lion optimizer with `pip install lion-pytorch` (it is not in ``requirements.txt`` currently.)
- Add `--lowram` option to `train_network.py`. Load models to VRAM instead of VRAM (for machines which have bigger VRAM than RAM such as Colab and Kaggle). Thanks to Isotr0py!
- Default behavior (without lowram) has reverted to the same as before 14 Feb.
- Fixed git commit hash to be set correctly regardless of the working directory. Thanks to vladmandic!
* 2023/02/15 (v20.7.3):
- Update upgrade.ps1 script
- Integrate new kohya sd-script
- Noise offset is recorded to the metadata. Thanks to space-nuko! - Noise offset is recorded to the metadata. Thanks to space-nuko!
- Show the moving average loss to prevent loss jumping in `train_network.py` and `train_db.py`. Thanks to shirayu! - Show the moving average loss to prevent loss jumping in `train_network.py` and `train_db.py`. Thanks to shirayu!
- Add support with multi-gpu trainining for `train_network.py`. Thanks to Isotr0py!
- Add `--verbose` option for `resize_lora.py`. For details, see [this PR](https://github.com/kohya-ss/sd-scripts/pull/179). Thanks to mgz-dev!
- Git commit hash is added to the metadata for LoRA. Thanks to space-nuko!
- Add `--noise_offset` option for each training scripts.
- Implementation of https://www.crosslabs.org//blog/diffusion-with-offset-noise
- This option may improve ability to generate darker/lighter images. May work with LoRA.
* 2023/02/11 (v20.7.2): * 2023/02/11 (v20.7.2):
- `lora_interrogator.py` is added in `networks` folder. See `python networks\lora_interrogator.py -h` for usage. - `lora_interrogator.py` is added in `networks` folder. See `python networks\lora_interrogator.py -h` for usage.
- For LoRAs where the activation word is unknown, this script compares the output of Text Encoder after applying LoRA to that of unapplied to find out which token is affected by LoRA. Hopefully you can figure out the activation word. LoRA trained with captions does not seem to be able to interrogate. - For LoRAs where the activation word is unknown, this script compares the output of Text Encoder after applying LoRA to that of unapplied to find out which token is affected by LoRA. Hopefully you can figure out the activation word. LoRA trained with captions does not seem to be able to interrogate.

View File

@ -89,6 +89,7 @@ def save_configuration(
random_crop, random_crop,
bucket_reso_steps, bucket_reso_steps,
caption_dropout_every_n_epochs, caption_dropout_rate, caption_dropout_every_n_epochs, caption_dropout_rate,
optimizer,
): ):
# Get list of function parameters and values # Get list of function parameters and values
parameters = list(locals().items()) parameters = list(locals().items())
@ -179,6 +180,7 @@ def open_configuration(
random_crop, random_crop,
bucket_reso_steps, bucket_reso_steps,
caption_dropout_every_n_epochs, caption_dropout_rate, caption_dropout_every_n_epochs, caption_dropout_rate,
optimizer,
): ):
# Get list of function parameters and values # Get list of function parameters and values
parameters = list(locals().items()) parameters = list(locals().items())
@ -253,6 +255,7 @@ def train_model(
random_crop, random_crop,
bucket_reso_steps, bucket_reso_steps,
caption_dropout_every_n_epochs, caption_dropout_rate, caption_dropout_every_n_epochs, caption_dropout_rate,
optimizer,
): ):
if pretrained_model_name_or_path == '': if pretrained_model_name_or_path == '':
msgbox('Source model information is missing') msgbox('Source model information is missing')
@ -397,6 +400,7 @@ def train_model(
seed=seed, seed=seed,
caption_extension=caption_extension, caption_extension=caption_extension,
cache_latents=cache_latents, cache_latents=cache_latents,
optimizer=optimizer
) )
run_cmd += run_cmd_advanced_training( run_cmd += run_cmd_advanced_training(
@ -541,6 +545,7 @@ def dreambooth_tab(
seed, seed,
caption_extension, caption_extension,
cache_latents, cache_latents,
optimizer,
) = gradio_training( ) = gradio_training(
learning_rate_value='1e-5', learning_rate_value='1e-5',
lr_scheduler_value='cosine', lr_scheduler_value='cosine',
@ -668,6 +673,7 @@ def dreambooth_tab(
random_crop, random_crop,
bucket_reso_steps, bucket_reso_steps,
caption_dropout_every_n_epochs, caption_dropout_rate, caption_dropout_every_n_epochs, caption_dropout_rate,
optimizer,
] ]
button_open_config.click( button_open_config.click(

View File

@ -161,6 +161,13 @@ def train(args):
raise ImportError("No bitsand bytes / bitsandbytesがインストールされていないようです") raise ImportError("No bitsand bytes / bitsandbytesがインストールされていないようです")
print("use 8-bit Adam optimizer") print("use 8-bit Adam optimizer")
optimizer_class = bnb.optim.AdamW8bit optimizer_class = bnb.optim.AdamW8bit
elif args.use_lion_optimizer:
try:
import lion_pytorch
except ImportError:
raise ImportError("No lion_pytorch / lion_pytorch がインストールされていないようです")
print("use Lion optimizer")
optimizer_class = lion_pytorch.Lion
else: else:
optimizer_class = torch.optim.AdamW optimizer_class = torch.optim.AdamW
@ -272,6 +279,9 @@ def train(args):
# Sample noise that we'll add to the latents # Sample noise that we'll add to the latents
noise = torch.randn_like(latents, device=latents.device) noise = torch.randn_like(latents, device=latents.device)
if args.noise_offset:
# https://www.crosslabs.org//blog/diffusion-with-offset-noise
noise += args.noise_offset * torch.randn((latents.shape[0], latents.shape[1], 1, 1), device=latents.device)
# Sample a random timestep for each image # Sample a random timestep for each image
timesteps = torch.randint(0, noise_scheduler.config.num_train_timesteps, (b_size,), device=latents.device) timesteps = torch.randint(0, noise_scheduler.config.num_train_timesteps, (b_size,), device=latents.device)

View File

@ -85,6 +85,7 @@ def save_configuration(
random_crop, random_crop,
bucket_reso_steps, bucket_reso_steps,
caption_dropout_every_n_epochs, caption_dropout_rate, caption_dropout_every_n_epochs, caption_dropout_rate,
optimizer,
): ):
# Get list of function parameters and values # Get list of function parameters and values
parameters = list(locals().items()) parameters = list(locals().items())
@ -181,6 +182,7 @@ def open_config_file(
random_crop, random_crop,
bucket_reso_steps, bucket_reso_steps,
caption_dropout_every_n_epochs, caption_dropout_rate, caption_dropout_every_n_epochs, caption_dropout_rate,
optimizer,
): ):
# Get list of function parameters and values # Get list of function parameters and values
parameters = list(locals().items()) parameters = list(locals().items())
@ -262,6 +264,7 @@ def train_model(
random_crop, random_crop,
bucket_reso_steps, bucket_reso_steps,
caption_dropout_every_n_epochs, caption_dropout_rate, caption_dropout_every_n_epochs, caption_dropout_rate,
optimizer,
): ):
# create caption json file # create caption json file
if generate_caption_database: if generate_caption_database:
@ -386,6 +389,7 @@ def train_model(
seed=seed, seed=seed,
caption_extension=caption_extension, caption_extension=caption_extension,
cache_latents=cache_latents, cache_latents=cache_latents,
optimizer=optimizer,
) )
run_cmd += run_cmd_advanced_training( run_cmd += run_cmd_advanced_training(
@ -564,6 +568,7 @@ def finetune_tab():
seed, seed,
caption_extension, caption_extension,
cache_latents, cache_latents,
optimizer,
) = gradio_training(learning_rate_value='1e-5') ) = gradio_training(learning_rate_value='1e-5')
with gr.Row(): with gr.Row():
dataset_repeats = gr.Textbox(label='Dataset repeats', value=40) dataset_repeats = gr.Textbox(label='Dataset repeats', value=40)
@ -661,6 +666,7 @@ def finetune_tab():
random_crop, random_crop,
bucket_reso_steps, bucket_reso_steps,
caption_dropout_every_n_epochs, caption_dropout_rate, caption_dropout_every_n_epochs, caption_dropout_rate,
optimizer,
] ]
button_run.click(train_model, inputs=settings_list) button_run.click(train_model, inputs=settings_list)

View File

@ -445,6 +445,7 @@ def gradio_training(
value=2, value=2,
) )
seed = gr.Textbox(label='Seed', value=1234) seed = gr.Textbox(label='Seed', value=1234)
cache_latents = gr.Checkbox(label='Cache latent', value=True)
with gr.Row(): with gr.Row():
learning_rate = gr.Textbox( learning_rate = gr.Textbox(
label='Learning rate', value=learning_rate_value label='Learning rate', value=learning_rate_value
@ -464,7 +465,15 @@ def gradio_training(
lr_warmup = gr.Textbox( lr_warmup = gr.Textbox(
label='LR warmup (% of steps)', value=lr_warmup_value label='LR warmup (% of steps)', value=lr_warmup_value
) )
cache_latents = gr.Checkbox(label='Cache latent', value=True) optimizer = gr.Dropdown(
label='Optimizer',
choices=[
'AdamW',
'Lion',
],
value="AdamW",
interactive=True,
)
return ( return (
learning_rate, learning_rate,
lr_scheduler, lr_scheduler,
@ -478,6 +487,7 @@ def gradio_training(
seed, seed,
caption_extension, caption_extension,
cache_latents, cache_latents,
optimizer,
) )
@ -512,10 +522,34 @@ def run_cmd_training(**kwargs):
if kwargs.get('caption_extension') if kwargs.get('caption_extension')
else '', else '',
' --cache_latents' if kwargs.get('cache_latents') else '', ' --cache_latents' if kwargs.get('cache_latents') else '',
' --use_lion_optimizer' if kwargs.get('optimizer') == 'Lion' else '',
] ]
run_cmd = ''.join(options) run_cmd = ''.join(options)
return run_cmd return run_cmd
# # This function takes a dictionary of keyword arguments and returns a string that can be used to run a command-line training script
# def run_cmd_training(**kwargs):
# arg_map = {
# 'learning_rate': ' --learning_rate="{}"',
# 'lr_scheduler': ' --lr_scheduler="{}"',
# 'lr_warmup_steps': ' --lr_warmup_steps="{}"',
# 'train_batch_size': ' --train_batch_size="{}"',
# 'max_train_steps': ' --max_train_steps="{}"',
# 'save_every_n_epochs': ' --save_every_n_epochs="{}"',
# 'mixed_precision': ' --mixed_precision="{}"',
# 'save_precision': ' --save_precision="{}"',
# 'seed': ' --seed="{}"',
# 'caption_extension': ' --caption_extension="{}"',
# 'cache_latents': ' --cache_latents',
# 'optimizer': ' --use_lion_optimizer' if kwargs.get('optimizer') == 'Lion' else '',
# }
# options = [arg_map[key].format(value) for key, value in kwargs.items() if key in arg_map and value]
# cmd = ''.join(options)
# return cmd
def gradio_advanced_training(): def gradio_advanced_training():
with gr.Row(): with gr.Row():
@ -664,3 +698,34 @@ def run_cmd_advanced_training(**kwargs):
] ]
run_cmd = ''.join(options) run_cmd = ''.join(options)
return run_cmd return run_cmd
# def run_cmd_advanced_training(**kwargs):
# arg_map = {
# 'max_train_epochs': ' --max_train_epochs="{}"',
# 'max_data_loader_n_workers': ' --max_data_loader_n_workers="{}"',
# 'max_token_length': ' --max_token_length={}' if int(kwargs.get('max_token_length', 75)) > 75 else '',
# 'clip_skip': ' --clip_skip={}' if int(kwargs.get('clip_skip', 1)) > 1 else '',
# 'resume': ' --resume="{}"',
# 'keep_tokens': ' --keep_tokens="{}"' if int(kwargs.get('keep_tokens', 0)) > 0 else '',
# 'caption_dropout_every_n_epochs': ' --caption_dropout_every_n_epochs="{}"' if int(kwargs.get('caption_dropout_every_n_epochs', 0)) > 0 else '',
# 'caption_dropout_rate': ' --caption_dropout_rate="{}"' if float(kwargs.get('caption_dropout_rate', 0)) > 0 else '',
# 'bucket_reso_steps': ' --bucket_reso_steps={:d}' if int(kwargs.get('bucket_reso_steps', 64)) >= 1 else '',
# 'save_state': ' --save_state',
# 'mem_eff_attn': ' --mem_eff_attn',
# 'color_aug': ' --color_aug',
# 'flip_aug': ' --flip_aug',
# 'shuffle_caption': ' --shuffle_caption',
# 'gradient_checkpointing': ' --gradient_checkpointing',
# 'full_fp16': ' --full_fp16',
# 'xformers': ' --xformers',
# 'use_8bit_adam': ' --use_8bit_adam',
# 'persistent_data_loader_workers': ' --persistent_data_loader_workers',
# 'bucket_no_upscale': ' --bucket_no_upscale',
# 'random_crop': ' --random_crop',
# }
# options = [arg_map[key].format(value) for key, value in kwargs.items() if key in arg_map and value]
# cmd = ''.join(options)
# return cmd

View File

@ -12,6 +12,7 @@ import math
import os import os
import random import random
import hashlib import hashlib
import subprocess
from io import BytesIO from io import BytesIO
from tqdm import tqdm from tqdm import tqdm
@ -299,7 +300,7 @@ class BaseDataset(torch.utils.data.Dataset):
if self.shuffle_keep_tokens is None: if self.shuffle_keep_tokens is None:
if self.shuffle_caption: if self.shuffle_caption:
random.shuffle(tokens) random.shuffle(tokens)
tokens = dropout_tags(tokens) tokens = dropout_tags(tokens)
else: else:
if len(tokens) > self.shuffle_keep_tokens: if len(tokens) > self.shuffle_keep_tokens:
@ -308,7 +309,7 @@ class BaseDataset(torch.utils.data.Dataset):
if self.shuffle_caption: if self.shuffle_caption:
random.shuffle(tokens) random.shuffle(tokens)
tokens = dropout_tags(tokens) tokens = dropout_tags(tokens)
tokens = keep_tokens + tokens tokens = keep_tokens + tokens
@ -1100,6 +1101,13 @@ def addnet_hash_safetensors(b):
return hash_sha256.hexdigest() return hash_sha256.hexdigest()
def get_git_revision_hash() -> str:
try:
return subprocess.check_output(['git', 'rev-parse', 'HEAD'], cwd=os.path.dirname(__file__)).decode('ascii').strip()
except:
return "(unknown)"
# flash attention forwards and backwards # flash attention forwards and backwards
# https://arxiv.org/abs/2205.14135 # https://arxiv.org/abs/2205.14135
@ -1381,6 +1389,8 @@ def add_training_arguments(parser: argparse.ArgumentParser, support_dreambooth:
help="max token length of text encoder (default for 75, 150 or 225) / text encoderのトークンの最大長未指定で75、150または225が指定可") help="max token length of text encoder (default for 75, 150 or 225) / text encoderのトークンの最大長未指定で75、150または225が指定可")
parser.add_argument("--use_8bit_adam", action="store_true", parser.add_argument("--use_8bit_adam", action="store_true",
help="use 8bit Adam optimizer (requires bitsandbytes) / 8bit Adamオプティマイザを使うbitsandbytesのインストールが必要") help="use 8bit Adam optimizer (requires bitsandbytes) / 8bit Adamオプティマイザを使うbitsandbytesのインストールが必要")
parser.add_argument("--use_lion_optimizer", action="store_true",
help="use Lion optimizer (requires lion-pytorch) / Lionオプティマイザを使う lion-pytorch のインストールが必要)")
parser.add_argument("--mem_eff_attn", action="store_true", parser.add_argument("--mem_eff_attn", action="store_true",
help="use memory efficient attention for CrossAttention / CrossAttentionに省メモリ版attentionを使う") help="use memory efficient attention for CrossAttention / CrossAttentionに省メモリ版attentionを使う")
parser.add_argument("--xformers", action="store_true", parser.add_argument("--xformers", action="store_true",
@ -1413,6 +1423,10 @@ def add_training_arguments(parser: argparse.ArgumentParser, support_dreambooth:
help="scheduler to use for learning rate / 学習率のスケジューラ: linear, cosine, cosine_with_restarts, polynomial, constant (default), constant_with_warmup") help="scheduler to use for learning rate / 学習率のスケジューラ: linear, cosine, cosine_with_restarts, polynomial, constant (default), constant_with_warmup")
parser.add_argument("--lr_warmup_steps", type=int, default=0, parser.add_argument("--lr_warmup_steps", type=int, default=0,
help="Number of steps for the warmup in the lr scheduler (default is 0) / 学習率のスケジューラをウォームアップするステップ数デフォルト0") help="Number of steps for the warmup in the lr scheduler (default is 0) / 学習率のスケジューラをウォームアップするステップ数デフォルト0")
parser.add_argument("--noise_offset", type=float, default=None,
help="enable noise offset with this value (if enabled, around 0.1 is recommended) / Noise offsetを有効にしてこの値を設定する有効にする場合は0.1程度を推奨)")
parser.add_argument("--lowram", action="store_true",
help="enable low RAM optimization. e.g. load models to VRAM instead of RAM (for machines which have bigger VRAM than RAM such as Colab and Kaggle) / メインメモリが少ない環境向け最適化を有効にする。たとえばVRAMにモデルを読み込むなどColabやKaggleなどRAMに比べてVRAMが多い環境向け")
if support_dreambooth: if support_dreambooth:
# DreamBooth training # DreamBooth training
@ -1620,9 +1634,6 @@ def get_hidden_states(args: argparse.Namespace, input_ids, tokenizer, text_encod
else: else:
enc_out = text_encoder(input_ids, output_hidden_states=True, return_dict=True) enc_out = text_encoder(input_ids, output_hidden_states=True, return_dict=True)
encoder_hidden_states = enc_out['hidden_states'][-args.clip_skip] encoder_hidden_states = enc_out['hidden_states'][-args.clip_skip]
if weight_dtype is not None:
# this is required for additional network training
encoder_hidden_states = encoder_hidden_states.to(weight_dtype)
encoder_hidden_states = text_encoder.text_model.final_layer_norm(encoder_hidden_states) encoder_hidden_states = text_encoder.text_model.final_layer_norm(encoder_hidden_states)
# bs*3, 77, 768 or 1024 # bs*3, 77, 768 or 1024
@ -1649,6 +1660,10 @@ def get_hidden_states(args: argparse.Namespace, input_ids, tokenizer, text_encod
states_list.append(encoder_hidden_states[:, -1].unsqueeze(1)) # <EOS> states_list.append(encoder_hidden_states[:, -1].unsqueeze(1)) # <EOS>
encoder_hidden_states = torch.cat(states_list, dim=1) encoder_hidden_states = torch.cat(states_list, dim=1)
if weight_dtype is not None:
# this is required for additional network training
encoder_hidden_states = encoder_hidden_states.to(weight_dtype)
return encoder_hidden_states return encoder_hidden_states

View File

@ -100,6 +100,7 @@ def save_configuration(
random_crop, random_crop,
bucket_reso_steps, bucket_reso_steps,
caption_dropout_every_n_epochs, caption_dropout_rate, caption_dropout_every_n_epochs, caption_dropout_rate,
optimizer,
): ):
# Get list of function parameters and values # Get list of function parameters and values
parameters = list(locals().items()) parameters = list(locals().items())
@ -197,6 +198,7 @@ def open_configuration(
random_crop, random_crop,
bucket_reso_steps, bucket_reso_steps,
caption_dropout_every_n_epochs, caption_dropout_rate, caption_dropout_every_n_epochs, caption_dropout_rate,
optimizer,
): ):
# Get list of function parameters and values # Get list of function parameters and values
parameters = list(locals().items()) parameters = list(locals().items())
@ -278,6 +280,7 @@ def train_model(
random_crop, random_crop,
bucket_reso_steps, bucket_reso_steps,
caption_dropout_every_n_epochs, caption_dropout_rate, caption_dropout_every_n_epochs, caption_dropout_rate,
optimizer,
): ):
if pretrained_model_name_or_path == '': if pretrained_model_name_or_path == '':
msgbox('Source model information is missing') msgbox('Source model information is missing')
@ -457,6 +460,7 @@ def train_model(
seed=seed, seed=seed,
caption_extension=caption_extension, caption_extension=caption_extension,
cache_latents=cache_latents, cache_latents=cache_latents,
optimizer=optimizer,
) )
run_cmd += run_cmd_advanced_training( run_cmd += run_cmd_advanced_training(
@ -609,6 +613,7 @@ def lora_tab(
seed, seed,
caption_extension, caption_extension,
cache_latents, cache_latents,
optimizer,
) = gradio_training( ) = gradio_training(
learning_rate_value='0.0001', learning_rate_value='0.0001',
lr_scheduler_value='cosine', lr_scheduler_value='cosine',
@ -778,6 +783,7 @@ def lora_tab(
random_crop, random_crop,
bucket_reso_steps, bucket_reso_steps,
caption_dropout_every_n_epochs, caption_dropout_rate, caption_dropout_every_n_epochs, caption_dropout_rate,
optimizer,
] ]
button_open_config.click( button_open_config.click(

View File

@ -38,9 +38,10 @@ def save_to_file(file_name, model, state_dict, dtype, metadata):
torch.save(model, file_name) torch.save(model, file_name)
def resize_lora_model(lora_sd, new_rank, save_dtype, device): def resize_lora_model(lora_sd, new_rank, save_dtype, device, verbose):
network_alpha = None network_alpha = None
network_dim = None network_dim = None
verbose_str = "\n"
CLAMP_QUANTILE = 0.99 CLAMP_QUANTILE = 0.99
@ -96,6 +97,12 @@ def resize_lora_model(lora_sd, new_rank, save_dtype, device):
U, S, Vh = torch.linalg.svd(full_weight_matrix) U, S, Vh = torch.linalg.svd(full_weight_matrix)
if verbose:
s_sum = torch.sum(torch.abs(S))
s_rank = torch.sum(torch.abs(S[:new_rank]))
verbose_str+=f"{block_down_name:76} | "
verbose_str+=f"sum(S) retained: {(s_rank)/s_sum:.1%}, max(S) ratio: {S[0]/S[new_rank]:0.1f}\n"
U = U[:, :new_rank] U = U[:, :new_rank]
S = S[:new_rank] S = S[:new_rank]
U = U @ torch.diag(S) U = U @ torch.diag(S)
@ -113,7 +120,7 @@ def resize_lora_model(lora_sd, new_rank, save_dtype, device):
U = U.unsqueeze(2).unsqueeze(3) U = U.unsqueeze(2).unsqueeze(3)
Vh = Vh.unsqueeze(2).unsqueeze(3) Vh = Vh.unsqueeze(2).unsqueeze(3)
if args.device: if device:
U = U.to(org_device) U = U.to(org_device)
Vh = Vh.to(org_device) Vh = Vh.to(org_device)
@ -127,6 +134,8 @@ def resize_lora_model(lora_sd, new_rank, save_dtype, device):
lora_up_weight = None lora_up_weight = None
weights_loaded = False weights_loaded = False
if verbose:
print(verbose_str)
print("resizing complete") print("resizing complete")
return o_lora_sd, network_dim, new_alpha return o_lora_sd, network_dim, new_alpha
@ -151,7 +160,7 @@ def resize(args):
lora_sd, metadata = load_state_dict(args.model, merge_dtype) lora_sd, metadata = load_state_dict(args.model, merge_dtype)
print("resizing rank...") print("resizing rank...")
state_dict, old_dim, new_alpha = resize_lora_model(lora_sd, args.new_rank, save_dtype, args.device) state_dict, old_dim, new_alpha = resize_lora_model(lora_sd, args.new_rank, save_dtype, args.device, args.verbose)
# update metadata # update metadata
if metadata is None: if metadata is None:
@ -182,6 +191,8 @@ if __name__ == '__main__':
parser.add_argument("--model", type=str, default=None, parser.add_argument("--model", type=str, default=None,
help="LoRA model to resize at to new rank: ckpt or safetensors file / 読み込むLoRAモデル、ckptまたはsafetensors") help="LoRA model to resize at to new rank: ckpt or safetensors file / 読み込むLoRAモデル、ckptまたはsafetensors")
parser.add_argument("--device", type=str, default=None, help="device to use, cuda for GPU / 計算を行うデバイス、cuda でGPUを使う") parser.add_argument("--device", type=str, default=None, help="device to use, cuda for GPU / 計算を行うデバイス、cuda でGPUを使う")
parser.add_argument("--verbose", action="store_true",
help="Display verbose resizing information / rank変更時の詳細情報を出力する")
args = parser.parse_args() args = parser.parse_args()
resize(args) resize(args)

View File

@ -0,0 +1,59 @@
{
"pretrained_model_name_or_path": "runwayml/stable-diffusion-v1-5",
"v2": false,
"v_parameterization": false,
"logging_dir": "D:\\dataset\\marty_mcfly\\1985\\lora/log",
"train_data_dir": "D:\\dataset\\marty_mcfly\\1985\\lora\\img_gan",
"reg_data_dir": "",
"output_dir": "D:/lora/sd1.5/marty_mcfly",
"max_resolution": "512,512",
"learning_rate": "0.00003333",
"lr_scheduler": "cosine",
"lr_warmup": "0",
"train_batch_size": 8,
"epoch": "1",
"save_every_n_epochs": "1",
"mixed_precision": "bf16",
"save_precision": "fp16",
"seed": "1234",
"num_cpu_threads_per_process": 2,
"cache_latents": false,
"caption_extension": "",
"enable_bucket": true,
"gradient_checkpointing": false,
"full_fp16": false,
"no_token_padding": false,
"stop_text_encoder_training": 0,
"use_8bit_adam": false,
"xformers": true,
"save_model_as": "safetensors",
"shuffle_caption": false,
"save_state": false,
"resume": "",
"prior_loss_weight": 1.0,
"text_encoder_lr": "0.000016666",
"unet_lr": "0.00003333",
"network_dim": 128,
"lora_network_weights": "",
"color_aug": false,
"flip_aug": false,
"clip_skip": "1",
"gradient_accumulation_steps": 1.0,
"mem_eff_attn": false,
"output_name": "mrtmcfl_v2.0",
"model_list": "runwayml/stable-diffusion-v1-5",
"max_token_length": "75",
"max_train_epochs": "",
"max_data_loader_n_workers": "0",
"network_alpha": 128,
"training_comment": "",
"keep_tokens": "0",
"lr_scheduler_num_cycles": "",
"lr_scheduler_power": "",
"persistent_data_loader_workers": false,
"bucket_no_upscale": true,
"random_crop": true,
"bucket_reso_steps": 64.0,
"caption_dropout_every_n_epochs": 0.0,
"caption_dropout_rate": 0.1
}

View File

@ -13,6 +13,7 @@ gradio==3.16.2
altair==4.2.2 altair==4.2.2
easygui==0.98.3 easygui==0.98.3
tk==0.1.0 tk==0.1.0
lion-pytorch==0.0.6
# for BLIP captioning # for BLIP captioning
requests==2.28.2 requests==2.28.2
timm==0.6.12 timm==0.6.12
@ -21,8 +22,6 @@ fairscale==0.4.13
# tensorflow<2.11 # tensorflow<2.11
tensorflow==2.10.1 tensorflow==2.10.1
huggingface-hub==0.12.0 huggingface-hub==0.12.0
xformers @ https://github.com/C43H66N12O12S2/stable-diffusion-webui/releases/download/f/xformers-0.0.14.dev0-cp310-cp310-win_amd64.whl # xformers @ https://github.com/C43H66N12O12S2/stable-diffusion-webui/releases/download/f/xformers-0.0.14.dev0-cp310-cp310-win_amd64.whl
# for dadaptation
dadaptation
# for kohya_ss library # for kohya_ss library
. .

View File

@ -95,6 +95,7 @@ def save_configuration(
random_crop, random_crop,
bucket_reso_steps, bucket_reso_steps,
caption_dropout_every_n_epochs, caption_dropout_rate, caption_dropout_every_n_epochs, caption_dropout_rate,
optimizer,
): ):
# Get list of function parameters and values # Get list of function parameters and values
parameters = list(locals().items()) parameters = list(locals().items())
@ -195,6 +196,7 @@ def open_configuration(
random_crop, random_crop,
bucket_reso_steps, bucket_reso_steps,
caption_dropout_every_n_epochs, caption_dropout_rate, caption_dropout_every_n_epochs, caption_dropout_rate,
optimizer,
): ):
# Get list of function parameters and values # Get list of function parameters and values
parameters = list(locals().items()) parameters = list(locals().items())
@ -275,6 +277,7 @@ def train_model(
random_crop, random_crop,
bucket_reso_steps, bucket_reso_steps,
caption_dropout_every_n_epochs, caption_dropout_rate, caption_dropout_every_n_epochs, caption_dropout_rate,
optimizer,
): ):
if pretrained_model_name_or_path == '': if pretrained_model_name_or_path == '':
msgbox('Source model information is missing') msgbox('Source model information is missing')
@ -434,6 +437,7 @@ def train_model(
seed=seed, seed=seed,
caption_extension=caption_extension, caption_extension=caption_extension,
cache_latents=cache_latents, cache_latents=cache_latents,
optimizer=optimizer,
) )
run_cmd += run_cmd_advanced_training( run_cmd += run_cmd_advanced_training(
@ -623,6 +627,7 @@ def ti_tab(
seed, seed,
caption_extension, caption_extension,
cache_latents, cache_latents,
optimizer,
) = gradio_training( ) = gradio_training(
learning_rate_value='1e-5', learning_rate_value='1e-5',
lr_scheduler_value='cosine', lr_scheduler_value='cosine',
@ -756,6 +761,7 @@ def ti_tab(
random_crop, random_crop,
bucket_reso_steps, bucket_reso_steps,
caption_dropout_every_n_epochs, caption_dropout_rate, caption_dropout_every_n_epochs, caption_dropout_rate,
optimizer,
] ]
button_open_config.click( button_open_config.click(

View File

@ -124,6 +124,13 @@ def train(args):
raise ImportError("No bitsand bytes / bitsandbytesがインストールされていないようです") raise ImportError("No bitsand bytes / bitsandbytesがインストールされていないようです")
print("use 8-bit Adam optimizer") print("use 8-bit Adam optimizer")
optimizer_class = bnb.optim.AdamW8bit optimizer_class = bnb.optim.AdamW8bit
elif args.use_lion_optimizer:
try:
import lion_pytorch
except ImportError:
raise ImportError("No lion_pytorch / lion_pytorch がインストールされていないようです")
print("use Lion optimizer")
optimizer_class = lion_pytorch.Lion
else: else:
optimizer_class = torch.optim.AdamW optimizer_class = torch.optim.AdamW

View File

@ -156,9 +156,12 @@ def train(args):
# モデルを読み込む # モデルを読み込む
text_encoder, vae, unet, _ = train_util.load_target_model(args, weight_dtype) text_encoder, vae, unet, _ = train_util.load_target_model(args, weight_dtype)
# unnecessary, but work on low-ram device
text_encoder.to("cuda") # work on low-ram device
unet.to("cuda") if args.lowram:
text_encoder.to("cuda")
unet.to("cuda")
# モデルに xformers とか memory efficient attention を組み込む # モデルに xformers とか memory efficient attention を組み込む
train_util.replace_unet_modules(unet, args.mem_eff_attn, args.xformers) train_util.replace_unet_modules(unet, args.mem_eff_attn, args.xformers)
@ -213,9 +216,18 @@ def train(args):
raise ImportError("No bitsand bytes / bitsandbytesがインストールされていないようです") raise ImportError("No bitsand bytes / bitsandbytesがインストールされていないようです")
print("use 8-bit Adam optimizer") print("use 8-bit Adam optimizer")
optimizer_class = bnb.optim.AdamW8bit optimizer_class = bnb.optim.AdamW8bit
elif args.use_lion_optimizer:
try:
import lion_pytorch
except ImportError:
raise ImportError("No lion_pytorch / lion_pytorch がインストールされていないようです")
print("use Lion optimizer")
optimizer_class = lion_pytorch.Lion
else: else:
optimizer_class = torch.optim.AdamW optimizer_class = torch.optim.AdamW
optimizer_name = optimizer_class.__module__ + "." + optimizer_class.__name__
trainable_params = network.prepare_optimizer_params(args.text_encoder_lr, args.unet_lr) trainable_params = network.prepare_optimizer_params(args.text_encoder_lr, args.unet_lr)
# betaやweight decayはdiffusers DreamBoothもDreamBooth SDもデフォルト値のようなのでオプションはとりあえず省略 # betaやweight decayはdiffusers DreamBoothもDreamBooth SDもデフォルト値のようなのでオプションはとりあえず省略
@ -359,7 +371,8 @@ def train(args):
"ss_tag_frequency": json.dumps(train_dataset.tag_frequency), "ss_tag_frequency": json.dumps(train_dataset.tag_frequency),
"ss_bucket_info": json.dumps(train_dataset.bucket_info), "ss_bucket_info": json.dumps(train_dataset.bucket_info),
"ss_training_comment": args.training_comment, # will not be updated after training "ss_training_comment": args.training_comment, # will not be updated after training
"ss_sd_scripts_commit_hash": train_util.get_git_revision_hash() "ss_sd_scripts_commit_hash": train_util.get_git_revision_hash(),
"ss_optimizer": optimizer_name
} }
# uncomment if another network is added # uncomment if another network is added

View File

@ -214,6 +214,13 @@ def train(args):
raise ImportError("No bitsand bytes / bitsandbytesがインストールされていないようです") raise ImportError("No bitsand bytes / bitsandbytesがインストールされていないようです")
print("use 8-bit Adam optimizer") print("use 8-bit Adam optimizer")
optimizer_class = bnb.optim.AdamW8bit optimizer_class = bnb.optim.AdamW8bit
elif args.use_lion_optimizer:
try:
import lion_pytorch
except ImportError:
raise ImportError("No lion_pytorch / lion_pytorch がインストールされていないようです")
print("use Lion optimizer")
optimizer_class = lion_pytorch.Lion
else: else:
optimizer_class = torch.optim.AdamW optimizer_class = torch.optim.AdamW
@ -344,6 +351,9 @@ def train(args):
# Sample noise that we'll add to the latents # Sample noise that we'll add to the latents
noise = torch.randn_like(latents, device=latents.device) noise = torch.randn_like(latents, device=latents.device)
if args.noise_offset:
# https://www.crosslabs.org//blog/diffusion-with-offset-noise
noise += args.noise_offset * torch.randn((latents.shape[0], latents.shape[1], 1, 1), device=latents.device)
# Sample a random timestep for each image # Sample a random timestep for each image
timesteps = torch.randint(0, noise_scheduler.config.num_train_timesteps, (b_size,), device=latents.device) timesteps = torch.randint(0, noise_scheduler.config.num_train_timesteps, (b_size,), device=latents.device)

View File

@ -1,3 +1,14 @@
# Check if there are any changes that need to be committed
if (git status --short) {
Write-Error "There are changes that need to be committed. Please stash or undo your changes before running this script."
return
}
# Pull the latest changes from the remote repository
git pull git pull
# Activate the virtual environment
.\venv\Scripts\activate .\venv\Scripts\activate
# Upgrade the required packages
pip install --upgrade -r requirements.txt pip install --upgrade -r requirements.txt