From 065364445d4ea1ddec44c3f87d1b6b8acda592a6 Mon Sep 17 00:00:00 2001 From: EternalNooblet Date: Fri, 7 Oct 2022 15:25:01 -0400 Subject: [PATCH 001/219] added a flag to run as root if needed --- webui.sh | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/webui.sh b/webui.sh index 05ca497d..41649b9a 100755 --- a/webui.sh +++ b/webui.sh @@ -3,6 +3,7 @@ # Please do not make any changes to this file, # # change the variables in webui-user.sh instead # ################################################# + # Read variables from webui-user.sh # shellcheck source=/dev/null if [[ -f webui-user.sh ]] @@ -46,6 +47,17 @@ then LAUNCH_SCRIPT="launch.py" fi +# this script cannot be run as root by default +can_run_as_root=0 + +# read any command line flags to the webui.sh script +while getopts "f" flag +do + case ${flag} in + f) can_run_as_root=1;; + esac +done + # Disable sentry logging export ERROR_REPORTING=FALSE @@ -61,7 +73,7 @@ printf "\e[1m\e[34mTested on Debian 11 (Bullseye)\e[0m" printf "\n%s\n" "${delimiter}" # Do not run as root -if [[ $(id -u) -eq 0 ]] +if [[ $(id -u) -eq 0 && can_run_as_root -eq 0 ]] then printf "\n%s\n" "${delimiter}" printf "\e[1m\e[31mERROR: This script must not be launched as root, aborting...\e[0m" From bdc90837987ed8919dd611fd01553b0c170ded5c Mon Sep 17 00:00:00 2001 From: Roy Shilkrot Date: Thu, 27 Oct 2022 15:20:15 -0400 Subject: [PATCH 002/219] Add a barebones interrogate API --- launch.py | 2 +- modules/api/api.py | 25 ++++++++++++++++++++++++- modules/api/models.py | 13 ++++++++++++- webui.py | 12 ++++++++---- 4 files changed, 45 insertions(+), 7 deletions(-) diff --git a/launch.py b/launch.py index 8affd410..ae79b4a4 100644 --- a/launch.py +++ b/launch.py @@ -198,7 +198,7 @@ def prepare_enviroment(): def start_webui(): print(f"Launching Web UI with arguments: {' '.join(sys.argv[1:])}") import webui - webui.webui() + webui.webui_or_api() if __name__ == "__main__": diff --git a/modules/api/api.py b/modules/api/api.py index 6e9d6097..eabdb7b8 100644 --- a/modules/api/api.py +++ b/modules/api/api.py @@ -1,4 +1,4 @@ -from modules.api.models import StableDiffusionTxt2ImgProcessingAPI, StableDiffusionImg2ImgProcessingAPI +from modules.api.models import StableDiffusionTxt2ImgProcessingAPI, StableDiffusionImg2ImgProcessingAPI, InterrogateAPI from modules.processing import StableDiffusionProcessingTxt2Img, StableDiffusionProcessingImg2Img, process_images from modules.sd_samplers import all_samplers from modules.extras import run_pnginfo @@ -25,6 +25,11 @@ class ImageToImageResponse(BaseModel): parameters: Json info: Json +class InterrogateResponse(BaseModel): + caption: str = Field(default=None, title="Caption", description="The generated caption for the image.") + parameters: Json + info: Json + class Api: def __init__(self, app, queue_lock): @@ -33,6 +38,7 @@ class Api: self.queue_lock = queue_lock self.app.add_api_route("/sdapi/v1/txt2img", self.text2imgapi, methods=["POST"]) self.app.add_api_route("/sdapi/v1/img2img", self.img2imgapi, methods=["POST"]) + self.app.add_api_route("/sdapi/v1/interrogate", self.interrogateapi, methods=["POST"]) def __base64_to_image(self, base64_string): # if has a comma, deal with prefix @@ -118,6 +124,23 @@ class Api: return ImageToImageResponse(images=b64images, parameters=json.dumps(vars(img2imgreq)), info=processed.js()) + def interrogateapi(self, interrogatereq: InterrogateAPI): + image_b64 = interrogatereq.image + if image_b64 is None: + raise HTTPException(status_code=404, detail="Image not found") + + populate = interrogatereq.copy(update={ # Override __init__ params + } + ) + + img = self.__base64_to_image(image_b64) + + # Override object param + with self.queue_lock: + processed = shared.interrogator.interrogate(img) + + return InterrogateResponse(caption=processed, parameters=json.dumps(vars(interrogatereq)), info=None) + def extrasapi(self): raise NotImplementedError diff --git a/modules/api/models.py b/modules/api/models.py index 079e33d9..8be64749 100644 --- a/modules/api/models.py +++ b/modules/api/models.py @@ -63,7 +63,12 @@ class PydanticModelGenerator: self._model_name = model_name - self._class_data = merge_class_params(class_instance) + + if class_instance is not None: + self._class_data = merge_class_params(class_instance) + else: + self._class_data = {} + self._model_def = [ ModelDef( field=underscore(k), @@ -105,4 +110,10 @@ StableDiffusionImg2ImgProcessingAPI = PydanticModelGenerator( "StableDiffusionProcessingImg2Img", StableDiffusionProcessingImg2Img, [{"key": "sampler_index", "type": str, "default": "Euler"}, {"key": "init_images", "type": list, "default": None}, {"key": "denoising_strength", "type": float, "default": 0.75}, {"key": "mask", "type": str, "default": None}, {"key": "include_init_images", "type": bool, "default": False, "exclude" : True}] +).generate_model() + +InterrogateAPI = PydanticModelGenerator( + "Interrogate", + None, + [{"key": "image", "type": str, "default": None}] ).generate_model() \ No newline at end of file diff --git a/webui.py b/webui.py index ade7334b..7a4bb2a2 100644 --- a/webui.py +++ b/webui.py @@ -146,7 +146,9 @@ def webui(): app.add_middleware(GZipMiddleware, minimum_size=1000) if (launch_api): - create_api(app) + print('launching API') + api = create_api(app) + api.launch(server_name="0.0.0.0" if cmd_opts.listen else "127.0.0.1", port=cmd_opts.port if cmd_opts.port else 7861) wait_on_server(demo) @@ -161,10 +163,12 @@ def webui(): print('Restarting Gradio') - -task = [] -if __name__ == "__main__": +def webui_or_api(): if cmd_opts.nowebui: api_only() else: webui() + +task = [] +if __name__ == "__main__": + webui_or_api() \ No newline at end of file From 4b8a192f680101de247dca79e48974b53bf961fe Mon Sep 17 00:00:00 2001 From: AngelBottomless <35677394+aria1th@users.noreply.github.com> Date: Sat, 29 Oct 2022 16:36:43 +0900 Subject: [PATCH 003/219] add optimizer save option to shared.opts --- modules/shared.py | 1 + 1 file changed, 1 insertion(+) diff --git a/modules/shared.py b/modules/shared.py index e4f163c1..065b893d 100644 --- a/modules/shared.py +++ b/modules/shared.py @@ -286,6 +286,7 @@ options_templates.update(options_section(('system', "System"), { options_templates.update(options_section(('training', "Training"), { "unload_models_when_training": OptionInfo(False, "Move VAE and CLIP to RAM when training hypernetwork. Saves VRAM."), + "save_optimizer_state": OptionInfo(False, "Saves Optimizer state with checkpoints. This will cause file size to increase VERY much."), "dataset_filename_word_regex": OptionInfo("", "Filename word regex"), "dataset_filename_join_string": OptionInfo(" ", "Filename join string"), "training_image_repeats_per_epoch": OptionInfo(1, "Number of repeats for a single input image per epoch; used only for displaying epoch number", gr.Number, {"precision": 0}), From 20194fd9752a280306fb66b57b258609b0918c46 Mon Sep 17 00:00:00 2001 From: AngelBottomless <35677394+aria1th@users.noreply.github.com> Date: Sat, 29 Oct 2022 16:56:42 +0900 Subject: [PATCH 004/219] We have duplicate linear now --- modules/hypernetworks/ui.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/hypernetworks/ui.py b/modules/hypernetworks/ui.py index aad09ffc..c2d4b51c 100644 --- a/modules/hypernetworks/ui.py +++ b/modules/hypernetworks/ui.py @@ -9,7 +9,7 @@ from modules import devices, sd_hijack, shared from modules.hypernetworks import hypernetwork not_available = ["hardswish", "multiheadattention"] -keys = ["linear"] + list(x for x in hypernetwork.HypernetworkModule.activation_dict.keys() if x not in not_available) +keys = list(x for x in hypernetwork.HypernetworkModule.activation_dict.keys() if x not in not_available) def create_hypernetwork(name, enable_sizes, overwrite_old, layer_structure=None, activation_func=None, weight_init=None, add_layer_norm=False, use_dropout=False): # Remove illegal characters from name. From 9d96d7d0a0aa0a966a9aefd24342345eb65952ed Mon Sep 17 00:00:00 2001 From: aria1th <35677394+aria1th@users.noreply.github.com> Date: Sun, 30 Oct 2022 20:39:04 +0900 Subject: [PATCH 005/219] resolve conflicts --- modules/hypernetworks/hypernetwork.py | 44 +++++++++++++++++++++++---- 1 file changed, 38 insertions(+), 6 deletions(-) diff --git a/modules/hypernetworks/hypernetwork.py b/modules/hypernetworks/hypernetwork.py index a11e01d6..8f74cdea 100644 --- a/modules/hypernetworks/hypernetwork.py +++ b/modules/hypernetworks/hypernetwork.py @@ -21,6 +21,7 @@ from torch.nn.init import normal_, xavier_normal_, xavier_uniform_, kaiming_norm from collections import defaultdict, deque from statistics import stdev, mean +optimizer_dict = {optim_name : cls_obj for optim_name, cls_obj in inspect.getmembers(torch.optim, inspect.isclass) if optim_name != "Optimizer"} class HypernetworkModule(torch.nn.Module): multiplier = 1.0 @@ -139,6 +140,8 @@ class Hypernetwork: self.weight_init = weight_init self.add_layer_norm = add_layer_norm self.use_dropout = use_dropout + self.optimizer_name = None + self.optimizer_state_dict = None for size in enable_sizes or []: self.layers[size] = ( @@ -171,6 +174,10 @@ class Hypernetwork: state_dict['use_dropout'] = self.use_dropout state_dict['sd_checkpoint'] = self.sd_checkpoint state_dict['sd_checkpoint_name'] = self.sd_checkpoint_name + if self.optimizer_name is not None: + state_dict['optimizer_name'] = self.optimizer_name + if self.optimizer_state_dict: + state_dict['optimizer_state_dict'] = self.optimizer_state_dict torch.save(state_dict, filename) @@ -190,7 +197,14 @@ class Hypernetwork: self.add_layer_norm = state_dict.get('is_layer_norm', False) print(f"Layer norm is set to {self.add_layer_norm}") self.use_dropout = state_dict.get('use_dropout', False) - print(f"Dropout usage is set to {self.use_dropout}" ) + print(f"Dropout usage is set to {self.use_dropout}") + self.optimizer_name = state_dict.get('optimizer_name', 'AdamW') + print(f"Optimizer name is {self.optimizer_name}") + self.optimizer_state_dict = state_dict.get('optimizer_state_dict', None) + if self.optimizer_state_dict: + print("Loaded existing optimizer from checkpoint") + else: + print("No saved optimizer exists in checkpoint") for size, sd in state_dict.items(): if type(size) == int: @@ -392,8 +406,19 @@ def train_hypernetwork(hypernetwork_name, learn_rate, batch_size, data_root, log weights = hypernetwork.weights() for weight in weights: weight.requires_grad = True - # if optimizer == "AdamW": or else Adam / AdamW / SGD, etc... - optimizer = torch.optim.AdamW(weights, lr=scheduler.learn_rate) + # Here we use optimizer from saved HN, or we can specify as UI option. + if (optimizer_name := hypernetwork.optimizer_name) in optimizer_dict: + optimizer = optimizer_dict[hypernetwork.optimizer_name](params=weights, lr=scheduler.learn_rate) + else: + print(f"Optimizer type {optimizer_name} is not defined!") + optimizer = torch.optim.AdamW(params=weights, lr=scheduler.learn_rate) + optimizer_name = 'AdamW' + if hypernetwork.optimizer_state_dict: # This line must be changed if Optimizer type can be different from saved optimizer. + try: + optimizer.load_state_dict(hypernetwork.optimizer_state_dict) + except RuntimeError as e: + print("Cannot resume from saved optimizer!") + print(e) steps_without_grad = 0 @@ -455,8 +480,11 @@ def train_hypernetwork(hypernetwork_name, learn_rate, batch_size, data_root, log # Before saving, change name to match current checkpoint. hypernetwork_name_every = f'{hypernetwork_name}-{steps_done}' last_saved_file = os.path.join(hypernetwork_dir, f'{hypernetwork_name_every}.pt') + hypernetwork.optimizer_name = optimizer_name + if shared.opts.save_optimizer_state: + hypernetwork.optimizer_state_dict = optimizer.state_dict() save_hypernetwork(hypernetwork, checkpoint, hypernetwork_name, last_saved_file) - + hypernetwork.optimizer_state_dict = None # dereference it after saving, to save memory. textual_inversion.write_loss(log_directory, "hypernetwork_loss.csv", hypernetwork.step, len(ds), { "loss": f"{previous_mean_loss:.7f}", "learn_rate": scheduler.learn_rate @@ -514,14 +542,18 @@ Last saved hypernetwork: {html.escape(last_saved_file)}
Last saved image: {html.escape(last_saved_image)}

""" - report_statistics(loss_dict) filename = os.path.join(shared.cmd_opts.hypernetwork_dir, f'{hypernetwork_name}.pt') + hypernetwork.optimizer_name = optimizer_name + if shared.opts.save_optimizer_state: + hypernetwork.optimizer_state_dict = optimizer.state_dict() save_hypernetwork(hypernetwork, checkpoint, hypernetwork_name, filename) - + del optimizer + hypernetwork.optimizer_state_dict = None # dereference it after saving, to save memory. return hypernetwork, filename + def save_hypernetwork(hypernetwork, checkpoint, hypernetwork_name, filename): old_hypernetwork_name = hypernetwork.name old_sd_checkpoint = hypernetwork.sd_checkpoint if hasattr(hypernetwork, "sd_checkpoint") else None From 36966e3200943dbf890b5338cfa939df552d3c47 Mon Sep 17 00:00:00 2001 From: Muhammad Rizqi Nur Date: Mon, 31 Oct 2022 15:38:58 +0700 Subject: [PATCH 006/219] Fix #4035 --- modules/sd_models.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/sd_models.py b/modules/sd_models.py index f86dc3ed..a29c8c1a 100644 --- a/modules/sd_models.py +++ b/modules/sd_models.py @@ -201,7 +201,7 @@ def load_model_weights(model, checkpoint_info): if shared.opts.sd_checkpoint_cache > 0: checkpoints_loaded[checkpoint_info] = model.state_dict().copy() - while len(checkpoints_loaded) > shared.opts.sd_checkpoint_cache: + while len(checkpoints_loaded) > shared.opts.sd_checkpoint_cache + 1: checkpoints_loaded.popitem(last=False) # LRU else: print(f"Loading weights [{sd_model_hash}] from cache") From bf7a699845675eefdabb9cfa40c55398976274ae Mon Sep 17 00:00:00 2001 From: Muhammad Rizqi Nur Date: Mon, 31 Oct 2022 16:27:27 +0700 Subject: [PATCH 007/219] Fix #4035 for real now --- modules/sd_models.py | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/modules/sd_models.py b/modules/sd_models.py index a29c8c1a..b2dd005a 100644 --- a/modules/sd_models.py +++ b/modules/sd_models.py @@ -165,6 +165,9 @@ def load_model_weights(model, checkpoint_info): checkpoint_file = checkpoint_info.filename sd_model_hash = checkpoint_info.hash + if shared.opts.sd_checkpoint_cache > 0 and hasattr(model, "sd_checkpoint_info"): + checkpoints_loaded[model.sd_checkpoint_info] = model.state_dict().copy() + if checkpoint_info not in checkpoints_loaded: print(f"Loading weights [{sd_model_hash}] from {checkpoint_file}") @@ -198,16 +201,14 @@ def load_model_weights(model, checkpoint_info): model.first_stage_model.load_state_dict(vae_dict) model.first_stage_model.to(devices.dtype_vae) - - if shared.opts.sd_checkpoint_cache > 0: - checkpoints_loaded[checkpoint_info] = model.state_dict().copy() - while len(checkpoints_loaded) > shared.opts.sd_checkpoint_cache + 1: - checkpoints_loaded.popitem(last=False) # LRU else: print(f"Loading weights [{sd_model_hash}] from cache") - checkpoints_loaded.move_to_end(checkpoint_info) model.load_state_dict(checkpoints_loaded[checkpoint_info]) + if shared.opts.sd_checkpoint_cache > 0: + while len(checkpoints_loaded) > shared.opts.sd_checkpoint_cache: + checkpoints_loaded.popitem(last=False) # LRU + model.sd_model_hash = sd_model_hash model.sd_model_checkpoint = checkpoint_file model.sd_checkpoint_info = checkpoint_info From df6a7ebfe8cc4da23861e3e2583693bb7808d573 Mon Sep 17 00:00:00 2001 From: Roy Shilkrot Date: Mon, 31 Oct 2022 11:50:33 -0400 Subject: [PATCH 008/219] revert things to master --- launch.py | 2 +- modules/api/api.py | 2 -- modules/api/models.py | 6 +----- 3 files changed, 2 insertions(+), 8 deletions(-) diff --git a/launch.py b/launch.py index fe9cef3c..958336f2 100644 --- a/launch.py +++ b/launch.py @@ -220,7 +220,7 @@ def tests(argv): def start_webui(): print(f"Launching Web UI with arguments: {' '.join(sys.argv[1:])}") import webui - webui.webui_or_api() + webui.webui() if __name__ == "__main__": diff --git a/modules/api/api.py b/modules/api/api.py index c510a833..6a903e4c 100644 --- a/modules/api/api.py +++ b/modules/api/api.py @@ -117,8 +117,6 @@ class Api: return ImageToImageResponse(images=b64images, parameters=vars(img2imgreq), info=processed.js()) - def extrasapi(self): - raise NotImplementedError def extras_single_image_api(self, req: ExtrasSingleImageRequest): reqDict = setUpscalers(req) diff --git a/modules/api/models.py b/modules/api/models.py index 035a7179..82ab29b8 100644 --- a/modules/api/models.py +++ b/modules/api/models.py @@ -64,11 +64,7 @@ class PydanticModelGenerator: self._model_name = model_name - - if class_instance is not None: - self._class_data = merge_class_params(class_instance) - else: - self._class_data = {} + self._class_data = merge_class_params(class_instance) self._model_def = [ ModelDef( From 3f3d14afd5abd07d3843370dc1c28be299dbdbab Mon Sep 17 00:00:00 2001 From: Roy Shilkrot Date: Mon, 31 Oct 2022 11:51:21 -0400 Subject: [PATCH 009/219] nix unused thing --- modules/api/api.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/modules/api/api.py b/modules/api/api.py index 6a903e4c..536e3f16 100644 --- a/modules/api/api.py +++ b/modules/api/api.py @@ -182,10 +182,6 @@ class Api: if image_b64 is None: raise HTTPException(status_code=404, detail="Image not found") - populate = interrogatereq.copy(update={ # Override __init__ params - } - ) - img = self.__base64_to_image(image_b64) # Override object param From 467cae167a3066ffa2b2a5e6f16dd42642219aba Mon Sep 17 00:00:00 2001 From: TinkTheBoush Date: Tue, 1 Nov 2022 23:29:12 +0900 Subject: [PATCH 010/219] append_tag_shuffle --- modules/hypernetworks/hypernetwork.py | 4 ++-- modules/textual_inversion/dataset.py | 10 ++++++++-- modules/textual_inversion/textual_inversion.py | 4 ++-- modules/ui.py | 3 +++ 4 files changed, 15 insertions(+), 6 deletions(-) diff --git a/modules/hypernetworks/hypernetwork.py b/modules/hypernetworks/hypernetwork.py index a11e01d6..7630fb81 100644 --- a/modules/hypernetworks/hypernetwork.py +++ b/modules/hypernetworks/hypernetwork.py @@ -331,7 +331,7 @@ def report_statistics(loss_info:dict): -def train_hypernetwork(hypernetwork_name, learn_rate, batch_size, data_root, log_directory, training_width, training_height, steps, create_image_every, save_hypernetwork_every, template_file, preview_from_txt2img, preview_prompt, preview_negative_prompt, preview_steps, preview_sampler_index, preview_cfg_scale, preview_seed, preview_width, preview_height): +def train_hypernetwork(hypernetwork_name, learn_rate, batch_size, data_root, log_directory, training_width, training_height, steps, create_image_every, save_hypernetwork_every, template_file, preview_from_txt2img, shuffle_tags, preview_prompt, preview_negative_prompt, preview_steps, preview_sampler_index, preview_cfg_scale, preview_seed, preview_width, preview_height): # images allows training previews to have infotext. Importing it at the top causes a circular import problem. from modules import images @@ -376,7 +376,7 @@ def train_hypernetwork(hypernetwork_name, learn_rate, batch_size, data_root, log # dataset loading may take a while, so input validations and early returns should be done before this shared.state.textinfo = f"Preparing dataset from {html.escape(data_root)}..." with torch.autocast("cuda"): - ds = modules.textual_inversion.dataset.PersonalizedBase(data_root=data_root, width=training_width, height=training_height, repeats=shared.opts.training_image_repeats_per_epoch, placeholder_token=hypernetwork_name, model=shared.sd_model, device=devices.device, template_file=template_file, include_cond=True, batch_size=batch_size) + ds = modules.textual_inversion.dataset.PersonalizedBase(data_root=data_root, width=training_width, height=training_height, repeats=shared.opts.training_image_repeats_per_epoch, placeholder_token=hypernetwork_name, shuffle_tags=shuffle_tags, model=shared.sd_model, device=devices.device, template_file=template_file, include_cond=True, batch_size=batch_size) if unload: shared.sd_model.cond_stage_model.to(devices.cpu) diff --git a/modules/textual_inversion/dataset.py b/modules/textual_inversion/dataset.py index ad726577..e9d97cc1 100644 --- a/modules/textual_inversion/dataset.py +++ b/modules/textual_inversion/dataset.py @@ -24,7 +24,7 @@ class DatasetEntry: class PersonalizedBase(Dataset): - def __init__(self, data_root, width, height, repeats, flip_p=0.5, placeholder_token="*", model=None, device=None, template_file=None, include_cond=False, batch_size=1): + def __init__(self, data_root, width, height, repeats, flip_p=0.5, placeholder_token="*", shuffle_tags=True, model=None, device=None, template_file=None, include_cond=False, batch_size=1): re_word = re.compile(shared.opts.dataset_filename_word_regex) if len(shared.opts.dataset_filename_word_regex) > 0 else None self.placeholder_token = placeholder_token @@ -33,6 +33,7 @@ class PersonalizedBase(Dataset): self.width = width self.height = height self.flip = transforms.RandomHorizontalFlip(p=flip_p) + self.shuffle_tags = shuffle_tags self.dataset = [] @@ -98,7 +99,12 @@ class PersonalizedBase(Dataset): def create_text(self, filename_text): text = random.choice(self.lines) text = text.replace("[name]", self.placeholder_token) - text = text.replace("[filewords]", filename_text) + if self.tag_shuffle: + tags = filename_text.split(',') + random.shuffle(tags) + text = text.replace("[filewords]", ','.join(tags)) + else: + text = text.replace("[filewords]", filename_text) return text def __len__(self): diff --git a/modules/textual_inversion/textual_inversion.py b/modules/textual_inversion/textual_inversion.py index e0babb46..64700e23 100644 --- a/modules/textual_inversion/textual_inversion.py +++ b/modules/textual_inversion/textual_inversion.py @@ -224,7 +224,7 @@ def validate_train_inputs(model_name, learn_rate, batch_size, data_root, templat if save_model_every or create_image_every: assert log_directory, "Log directory is empty" -def train_embedding(embedding_name, learn_rate, batch_size, data_root, log_directory, training_width, training_height, steps, create_image_every, save_embedding_every, template_file, save_image_with_stored_embedding, preview_from_txt2img, preview_prompt, preview_negative_prompt, preview_steps, preview_sampler_index, preview_cfg_scale, preview_seed, preview_width, preview_height): +def train_embedding(embedding_name, learn_rate, batch_size, data_root, log_directory, training_width, training_height, steps, create_image_every, save_embedding_every, template_file, save_image_with_stored_embedding, preview_from_txt2img, shuffle_tags, preview_prompt, preview_negative_prompt, preview_steps, preview_sampler_index, preview_cfg_scale, preview_seed, preview_width, preview_height): save_embedding_every = save_embedding_every or 0 create_image_every = create_image_every or 0 validate_train_inputs(embedding_name, learn_rate, batch_size, data_root, template_file, steps, save_embedding_every, create_image_every, log_directory, name="embedding") @@ -271,7 +271,7 @@ def train_embedding(embedding_name, learn_rate, batch_size, data_root, log_direc # dataset loading may take a while, so input validations and early returns should be done before this shared.state.textinfo = f"Preparing dataset from {html.escape(data_root)}..." with torch.autocast("cuda"): - ds = modules.textual_inversion.dataset.PersonalizedBase(data_root=data_root, width=training_width, height=training_height, repeats=shared.opts.training_image_repeats_per_epoch, placeholder_token=embedding_name, model=shared.sd_model, device=devices.device, template_file=template_file, batch_size=batch_size) + ds = modules.textual_inversion.dataset.PersonalizedBase(data_root=data_root, width=training_width, height=training_height, repeats=shared.opts.training_image_repeats_per_epoch, placeholder_token=embedding_name, shuffle_tags=shuffle_tags, model=shared.sd_model, device=devices.device, template_file=template_file, batch_size=batch_size) embedding.vec.requires_grad = True optimizer = torch.optim.AdamW([embedding.vec], lr=scheduler.learn_rate) diff --git a/modules/ui.py b/modules/ui.py index 2c15abb7..ad383979 100644 --- a/modules/ui.py +++ b/modules/ui.py @@ -1267,6 +1267,7 @@ def create_ui(wrap_gradio_gpu_call): save_embedding_every = gr.Number(label='Save a copy of embedding to log directory every N steps, 0 to disable', value=500, precision=0) save_image_with_stored_embedding = gr.Checkbox(label='Save images with embedding in PNG chunks', value=True) preview_from_txt2img = gr.Checkbox(label='Read parameters (prompt, etc...) from txt2img tab when making previews', value=False) + shuffle_tags = gr.Checkbox(label='Shuffleing tags by "," when create texts', value=True) with gr.Row(): interrupt_training = gr.Button(value="Interrupt") @@ -1361,6 +1362,7 @@ def create_ui(wrap_gradio_gpu_call): template_file, save_image_with_stored_embedding, preview_from_txt2img, + shuffle_tags, *txt2img_preview_params, ], outputs=[ @@ -1385,6 +1387,7 @@ def create_ui(wrap_gradio_gpu_call): save_embedding_every, template_file, preview_from_txt2img, + shuffle_tags, *txt2img_preview_params, ], outputs=[ From bc607686065b8c7751d1af7c05b960378fa256de Mon Sep 17 00:00:00 2001 From: Billy Cao Date: Tue, 1 Nov 2022 23:26:55 +0800 Subject: [PATCH 011/219] Enable override_settings to take effect for hypernetworks --- modules/processing.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/modules/processing.py b/modules/processing.py index 57d3a523..86d015af 100644 --- a/modules/processing.py +++ b/modules/processing.py @@ -422,13 +422,15 @@ def process_images(p: StableDiffusionProcessing) -> Processed: try: for k, v in p.override_settings.items(): - opts.data[k] = v # we don't call onchange for simplicity which makes changing model, hypernet impossible + opts.data[k] = v # we don't call onchange for simplicity which makes changing model impossible + if k == 'sd_hypernetwork': shared.reload_hypernetworks() # make onchange call for changing hypernet since it is relatively fast to load on-change, while SD models are not res = process_images_inner(p) - finally: + finally: # restore opts to original state for k, v in stored_opts.items(): opts.data[k] = v + if k == 'sd_hypernetwork': shared.reload_hypernetworks() return res From 3178c35224467893cf8dcedb1028c59c6c23db58 Mon Sep 17 00:00:00 2001 From: AngelBottomless <35677394+aria1th@users.noreply.github.com> Date: Wed, 2 Nov 2022 22:16:32 +0900 Subject: [PATCH 012/219] resolve conflicts --- modules/shared.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/shared.py b/modules/shared.py index 065b893d..959937d7 100644 --- a/modules/shared.py +++ b/modules/shared.py @@ -285,7 +285,7 @@ options_templates.update(options_section(('system', "System"), { })) options_templates.update(options_section(('training', "Training"), { - "unload_models_when_training": OptionInfo(False, "Move VAE and CLIP to RAM when training hypernetwork. Saves VRAM."), + "unload_models_when_training": OptionInfo(False, "Move VAE and CLIP to RAM when training if possible. Saves VRAM."), "save_optimizer_state": OptionInfo(False, "Saves Optimizer state with checkpoints. This will cause file size to increase VERY much."), "dataset_filename_word_regex": OptionInfo("", "Filename word regex"), "dataset_filename_join_string": OptionInfo(" ", "Filename join string"), From 9b5f85ac83f864310fe19c9deab6670bad695b0d Mon Sep 17 00:00:00 2001 From: AngelBottomless <35677394+aria1th@users.noreply.github.com> Date: Wed, 2 Nov 2022 22:18:04 +0900 Subject: [PATCH 013/219] first revert --- modules/shared.py | 1 - 1 file changed, 1 deletion(-) diff --git a/modules/shared.py b/modules/shared.py index 959937d7..7e8c552b 100644 --- a/modules/shared.py +++ b/modules/shared.py @@ -286,7 +286,6 @@ options_templates.update(options_section(('system', "System"), { options_templates.update(options_section(('training', "Training"), { "unload_models_when_training": OptionInfo(False, "Move VAE and CLIP to RAM when training if possible. Saves VRAM."), - "save_optimizer_state": OptionInfo(False, "Saves Optimizer state with checkpoints. This will cause file size to increase VERY much."), "dataset_filename_word_regex": OptionInfo("", "Filename word regex"), "dataset_filename_join_string": OptionInfo(" ", "Filename join string"), "training_image_repeats_per_epoch": OptionInfo(1, "Number of repeats for a single input image per epoch; used only for displaying epoch number", gr.Number, {"precision": 0}), From 7ea5956ad5fa925f92116e8a3bf78d7f6517b654 Mon Sep 17 00:00:00 2001 From: AngelBottomless <35677394+aria1th@users.noreply.github.com> Date: Wed, 2 Nov 2022 22:18:55 +0900 Subject: [PATCH 014/219] now add --- modules/shared.py | 1 + 1 file changed, 1 insertion(+) diff --git a/modules/shared.py b/modules/shared.py index d8e99f85..7ecb40d8 100644 --- a/modules/shared.py +++ b/modules/shared.py @@ -309,6 +309,7 @@ options_templates.update(options_section(('system', "System"), { options_templates.update(options_section(('training', "Training"), { "unload_models_when_training": OptionInfo(False, "Move VAE and CLIP to RAM when training if possible. Saves VRAM."), + "save_optimizer_state": OptionInfo(False, "Saves Optimizer state with checkpoints. This will cause file size to increase VERY much."), "dataset_filename_word_regex": OptionInfo("", "Filename word regex"), "dataset_filename_join_string": OptionInfo(" ", "Filename join string"), "training_image_repeats_per_epoch": OptionInfo(1, "Number of repeats for a single input image per epoch; used only for displaying epoch number", gr.Number, {"precision": 0}), From e21fcd72fcf147904a1df060226c4df12acf251e Mon Sep 17 00:00:00 2001 From: evshiron Date: Wed, 2 Nov 2022 22:37:45 +0800 Subject: [PATCH 015/219] add back png info in image api --- modules/api/api.py | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/modules/api/api.py b/modules/api/api.py index 71c9c160..ceaf08b0 100644 --- a/modules/api/api.py +++ b/modules/api/api.py @@ -7,8 +7,9 @@ from fastapi import APIRouter, Depends, HTTPException import modules.shared as shared from modules.api.models import * from modules.processing import StableDiffusionProcessingTxt2Img, StableDiffusionProcessingImg2Img, process_images -from modules.sd_samplers import all_samplers, sample_to_image, samples_to_image_grid +from modules.sd_samplers import all_samplers from modules.extras import run_extras, run_pnginfo +from PIL import PngImagePlugin def upscaler_to_index(name: str): @@ -31,9 +32,21 @@ def setUpscalers(req: dict): def encode_pil_to_base64(image): - buffer = io.BytesIO() - image.save(buffer, format="png") - return base64.b64encode(buffer.getvalue()) + with io.BytesIO() as output_bytes: + + # Copy any text-only metadata + use_metadata = False + metadata = PngImagePlugin.PngInfo() + for key, value in image.info.items(): + if isinstance(key, str) and isinstance(value, str): + metadata.add_text(key, value) + use_metadata = True + + image.save( + output_bytes, "PNG", pnginfo=(metadata if use_metadata else None) + ) + bytes_data = output_bytes.getvalue() + return base64.b64encode(bytes_data) class Api: From a9e979977a8e3999b01b6a086bb1332ab7ab308b Mon Sep 17 00:00:00 2001 From: Artem Zagidulin Date: Wed, 2 Nov 2022 19:05:01 +0300 Subject: [PATCH 016/219] process_one --- modules/processing.py | 3 +++ modules/scripts.py | 16 ++++++++++++++++ 2 files changed, 19 insertions(+) diff --git a/modules/processing.py b/modules/processing.py index 3a364b5f..72a2ee4e 100644 --- a/modules/processing.py +++ b/modules/processing.py @@ -509,6 +509,9 @@ def process_images_inner(p: StableDiffusionProcessing) -> Processed: if len(prompts) == 0: break + if p.scripts is not None: + p.scripts.process_one(p) + with devices.autocast(): uc = prompt_parser.get_learned_conditioning(shared.sd_model, len(prompts) * [p.negative_prompt], p.steps) c = prompt_parser.get_multicond_learned_conditioning(shared.sd_model, prompts, p.steps) diff --git a/modules/scripts.py b/modules/scripts.py index 533db45c..9f82efea 100644 --- a/modules/scripts.py +++ b/modules/scripts.py @@ -70,6 +70,13 @@ class Script: pass + def process_one(self, p, *args): + """ + Same as process(), but called for every iteration + """ + + pass + def postprocess(self, p, processed, *args): """ This function is called after processing ends for AlwaysVisible scripts. @@ -294,6 +301,15 @@ class ScriptRunner: print(f"Error running process: {script.filename}", file=sys.stderr) print(traceback.format_exc(), file=sys.stderr) + def process_one(self, p): + for script in self.alwayson_scripts: + try: + script_args = p.script_args[script.args_from:script.args_to] + script.process_one(p, *script_args) + except Exception: + print(f"Error running process_one: {script.filename}", file=sys.stderr) + print(traceback.format_exc(), file=sys.stderr) + def postprocess(self, p, processed): for script in self.alwayson_scripts: try: From f1b6ac64e451036fb4dfabe66d79488c56c06776 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kyu=E2=99=A5?= <3ad4gum@gmail.com> Date: Wed, 2 Nov 2022 17:24:42 +0100 Subject: [PATCH 017/219] Added option to preview Created images on batch completion. --- modules/shared.py | 25 ++++++++++++++++--------- modules/ui.py | 2 +- 2 files changed, 17 insertions(+), 10 deletions(-) diff --git a/modules/shared.py b/modules/shared.py index d8e99f85..d4cf32a4 100644 --- a/modules/shared.py +++ b/modules/shared.py @@ -146,6 +146,9 @@ class State: self.interrupted = True def nextjob(self): + if opts.show_progress_every_n_steps == -1: + self.do_set_current_image() + self.job_no += 1 self.sampling_step = 0 self.current_image_sampling_step = 0 @@ -186,17 +189,21 @@ class State: """sets self.current_image from self.current_latent if enough sampling steps have been made after the last call to this""" def set_current_image(self): + if self.sampling_step - self.current_image_sampling_step >= opts.show_progress_every_n_steps and opts.show_progress_every_n_steps > 0: + self.do_set_current_image() + + def do_set_current_image(self): if not parallel_processing_allowed: return + if self.current_latent is None: + return + + if opts.show_progress_grid: + self.current_image = sd_samplers.samples_to_image_grid(self.current_latent) + else: + self.current_image = sd_samplers.sample_to_image(self.current_latent) - if self.sampling_step - self.current_image_sampling_step >= opts.show_progress_every_n_steps and self.current_latent is not None: - if opts.show_progress_grid: - self.current_image = sd_samplers.samples_to_image_grid(self.current_latent) - else: - self.current_image = sd_samplers.sample_to_image(self.current_latent) - - self.current_image_sampling_step = self.sampling_step - + self.current_image_sampling_step = self.sampling_step state = State() @@ -351,7 +358,7 @@ options_templates.update(options_section(('interrogate', "Interrogate Options"), options_templates.update(options_section(('ui', "User interface"), { "show_progressbar": OptionInfo(True, "Show progressbar"), - "show_progress_every_n_steps": OptionInfo(0, "Show image creation progress every N sampling steps. Set 0 to disable.", gr.Slider, {"minimum": 0, "maximum": 32, "step": 1}), + "show_progress_every_n_steps": OptionInfo(0, "Show image creation progress every N sampling steps. Set to 0 to disable. Set to -1 to show after completion of batch.", gr.Slider, {"minimum": -1, "maximum": 32, "step": 1}), "show_progress_grid": OptionInfo(True, "Show previews of all images generated in a batch as a grid"), "return_grid": OptionInfo(True, "Show grid in results for web"), "do_not_show_images": OptionInfo(False, "Do not show any images in results for web"), diff --git a/modules/ui.py b/modules/ui.py index 2609857e..29de1e10 100644 --- a/modules/ui.py +++ b/modules/ui.py @@ -276,7 +276,7 @@ def check_progress_call(id_part): image = gr_show(False) preview_visibility = gr_show(False) - if opts.show_progress_every_n_steps > 0: + if opts.show_progress_every_n_steps != 0: shared.state.set_current_image() image = shared.state.current_image From c07f1d0d7821f85b9ce1419992c118963d605bd7 Mon Sep 17 00:00:00 2001 From: DepFA <35278260+dfaker@users.noreply.github.com> Date: Wed, 2 Nov 2022 16:59:10 +0000 Subject: [PATCH 018/219] Convert callbacks into a private map, add utility functions for removing callbacks --- modules/script_callbacks.py | 68 ++++++++++++++++++++++--------------- 1 file changed, 41 insertions(+), 27 deletions(-) diff --git a/modules/script_callbacks.py b/modules/script_callbacks.py index c28e220e..4a7fb944 100644 --- a/modules/script_callbacks.py +++ b/modules/script_callbacks.py @@ -46,25 +46,23 @@ class CFGDenoiserParams: ScriptCallback = namedtuple("ScriptCallback", ["script", "callback"]) -callbacks_app_started = [] -callbacks_model_loaded = [] -callbacks_ui_tabs = [] -callbacks_ui_settings = [] -callbacks_before_image_saved = [] -callbacks_image_saved = [] -callbacks_cfg_denoiser = [] +__callback_map = dict( + callbacks_app_started=[], + callbacks_model_loaded=[], + callbacks_ui_tabs=[], + callbacks_ui_settings=[], + callbacks_before_image_saved=[], + callbacks_image_saved=[], + callbacks_cfg_denoiser=[] +) def clear_callbacks(): - callbacks_model_loaded.clear() - callbacks_ui_tabs.clear() - callbacks_ui_settings.clear() - callbacks_before_image_saved.clear() - callbacks_image_saved.clear() - callbacks_cfg_denoiser.clear() + for callback_list in __callback_map.values(): + callback_list.clear() def app_started_callback(demo: Optional[Blocks], app: FastAPI): - for c in callbacks_app_started: + for c in __callback_map['callbacks_app_started']: try: c.callback(demo, app) except Exception: @@ -72,7 +70,7 @@ def app_started_callback(demo: Optional[Blocks], app: FastAPI): def model_loaded_callback(sd_model): - for c in callbacks_model_loaded: + for c in __callback_map['callbacks_model_loaded']: try: c.callback(sd_model) except Exception: @@ -82,7 +80,7 @@ def model_loaded_callback(sd_model): def ui_tabs_callback(): res = [] - for c in callbacks_ui_tabs: + for c in __callback_map['callbacks_ui_tabs']: try: res += c.callback() or [] except Exception: @@ -92,7 +90,7 @@ def ui_tabs_callback(): def ui_settings_callback(): - for c in callbacks_ui_settings: + for c in __callback_map['callbacks_ui_settings']: try: c.callback() except Exception: @@ -100,7 +98,7 @@ def ui_settings_callback(): def before_image_saved_callback(params: ImageSaveParams): - for c in callbacks_before_image_saved: + for c in __callback_map['callbacks_before_image_saved']: try: c.callback(params) except Exception: @@ -108,7 +106,7 @@ def before_image_saved_callback(params: ImageSaveParams): def image_saved_callback(params: ImageSaveParams): - for c in callbacks_image_saved: + for c in __callback_map['callbacks_image_saved']: try: c.callback(params) except Exception: @@ -116,7 +114,7 @@ def image_saved_callback(params: ImageSaveParams): def cfg_denoiser_callback(params: CFGDenoiserParams): - for c in callbacks_cfg_denoiser: + for c in __callback_map['callbacks_cfg_denoiser']: try: c.callback(params) except Exception: @@ -129,17 +127,33 @@ def add_callback(callbacks, fun): callbacks.append(ScriptCallback(filename, fun)) + +def remove_current_script_callbacks(): + stack = [x for x in inspect.stack() if x.filename != __file__] + filename = stack[0].filename if len(stack) > 0 else 'unknown file' + if filename == 'unknown file': + return + for callback_list in __callback_map.values(): + for callback_to_remove in [cb for cb in callback_list if cb.script == filename]: + callback_list.remove(callback_to_remove) + + +def remove_callbacks_for_function(callback_func): + for callback_list in __callback_map.values(): + for callback_to_remove in [cb for cb in callback_list if cb.callback == callback_func]: + callback_list.remove(callback_to_remove) + def on_app_started(callback): """register a function to be called when the webui started, the gradio `Block` component and fastapi `FastAPI` object are passed as the arguments""" - add_callback(callbacks_app_started, callback) + add_callback(__callback_map['callbacks_app_started'], callback) def on_model_loaded(callback): """register a function to be called when the stable diffusion model is created; the model is passed as an argument""" - add_callback(callbacks_model_loaded, callback) + add_callback(__callback_map['callbacks_model_loaded'], callback) def on_ui_tabs(callback): @@ -152,13 +166,13 @@ def on_ui_tabs(callback): title is tab text displayed to user in the UI elem_id is HTML id for the tab """ - add_callback(callbacks_ui_tabs, callback) + add_callback(__callback_map['callbacks_ui_tabs'], callback) def on_ui_settings(callback): """register a function to be called before UI settings are populated; add your settings by using shared.opts.add_option(shared.OptionInfo(...)) """ - add_callback(callbacks_ui_settings, callback) + add_callback(__callback_map['callbacks_ui_settings'], callback) def on_before_image_saved(callback): @@ -166,7 +180,7 @@ def on_before_image_saved(callback): The callback is called with one argument: - params: ImageSaveParams - parameters the image is to be saved with. You can change fields in this object. """ - add_callback(callbacks_before_image_saved, callback) + add_callback(__callback_map['callbacks_before_image_saved'], callback) def on_image_saved(callback): @@ -174,7 +188,7 @@ def on_image_saved(callback): The callback is called with one argument: - params: ImageSaveParams - parameters the image was saved with. Changing fields in this object does nothing. """ - add_callback(callbacks_image_saved, callback) + add_callback(__callback_map['callbacks_image_saved'], callback) def on_cfg_denoiser(callback): @@ -182,5 +196,5 @@ def on_cfg_denoiser(callback): The callback is called with one argument: - params: CFGDenoiserParams - parameters to be passed to the inner model and sampling state details. """ - add_callback(callbacks_cfg_denoiser, callback) + add_callback(__callback_map['callbacks_cfg_denoiser'], callback) From de64146ad2fc2030a4cd3545676f9e18c93b8b18 Mon Sep 17 00:00:00 2001 From: Artem Zagidulin Date: Wed, 2 Nov 2022 21:30:50 +0300 Subject: [PATCH 019/219] add number of itter --- modules/processing.py | 2 +- modules/scripts.py | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/modules/processing.py b/modules/processing.py index 72a2ee4e..17f4a5ec 100644 --- a/modules/processing.py +++ b/modules/processing.py @@ -510,7 +510,7 @@ def process_images_inner(p: StableDiffusionProcessing) -> Processed: break if p.scripts is not None: - p.scripts.process_one(p) + p.scripts.process_one(p, n) with devices.autocast(): uc = prompt_parser.get_learned_conditioning(shared.sd_model, len(prompts) * [p.negative_prompt], p.steps) diff --git a/modules/scripts.py b/modules/scripts.py index 9f82efea..7aa0d56a 100644 --- a/modules/scripts.py +++ b/modules/scripts.py @@ -70,7 +70,7 @@ class Script: pass - def process_one(self, p, *args): + def process_one(self, p, n, *args): """ Same as process(), but called for every iteration """ @@ -301,11 +301,11 @@ class ScriptRunner: print(f"Error running process: {script.filename}", file=sys.stderr) print(traceback.format_exc(), file=sys.stderr) - def process_one(self, p): + def process_one(self, p, n): for script in self.alwayson_scripts: try: script_args = p.script_args[script.args_from:script.args_to] - script.process_one(p, *script_args) + script.process_one(p, n, *script_args) except Exception: print(f"Error running process_one: {script.filename}", file=sys.stderr) print(traceback.format_exc(), file=sys.stderr) From 313e14de04d9955c6ad077341feceb0fc7f2f1d3 Mon Sep 17 00:00:00 2001 From: Chris OBryan <13701027+cobryan05@users.noreply.github.com> Date: Wed, 2 Nov 2022 21:37:43 -0500 Subject: [PATCH 020/219] extras - skip unnecessary second hash of image There is no need to re-hash the input image each iteration of the loop. This also reverts PR #4026 as it was determined the cache hits it avoids were actually valid. --- modules/extras.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/modules/extras.py b/modules/extras.py index 8e2ab35c..71b93a06 100644 --- a/modules/extras.py +++ b/modules/extras.py @@ -136,12 +136,13 @@ def run_extras(extras_mode, resize_mode, image, image_folder, input_dir, output_ def run_upscalers_blend(params: List[UpscaleParams], image: Image.Image, info: str) -> Tuple[Image.Image, str]: blended_result: Image.Image = None + image_hash: str = hash(np.array(image.getdata()).tobytes()) for upscaler in params: upscale_args = (upscaler.upscaler_idx, upscaling_resize, resize_mode, upscaling_resize_w, upscaling_resize_h, upscaling_crop) - cache_key = LruCache.Key(image_hash=hash(np.array(image.getdata()).tobytes()), + cache_key = LruCache.Key(image_hash=image_hash, info_hash=hash(info), - args_hash=hash((upscale_args, upscale_first))) + args_hash=hash(upscale_args)) cached_entry = cached_images.get(cache_key) if cached_entry is None: res = upscale(image, *upscale_args) From 7a2e36b583ef9eaefa44322e16faff6f9f1af169 Mon Sep 17 00:00:00 2001 From: Bruno Seoane Date: Thu, 3 Nov 2022 00:51:22 -0300 Subject: [PATCH 021/219] Add config and lists endpoints --- modules/api/api.py | 97 ++++++++++++++++++++++++++++++++++++++++--- modules/api/models.py | 70 +++++++++++++++++++++++++++++-- 2 files changed, 159 insertions(+), 8 deletions(-) diff --git a/modules/api/api.py b/modules/api/api.py index 71c9c160..ed2dce5d 100644 --- a/modules/api/api.py +++ b/modules/api/api.py @@ -2,14 +2,17 @@ import base64 import io import time import uvicorn -from gradio.processing_utils import decode_base64_to_file, decode_base64_to_image -from fastapi import APIRouter, Depends, HTTPException +from threading import Lock +from gradio.processing_utils import encode_pil_to_base64, decode_base64_to_file, decode_base64_to_image +from fastapi import APIRouter, Depends, FastAPI, HTTPException import modules.shared as shared from modules.api.models import * from modules.processing import StableDiffusionProcessingTxt2Img, StableDiffusionProcessingImg2Img, process_images -from modules.sd_samplers import all_samplers, sample_to_image, samples_to_image_grid +from modules.sd_samplers import all_samplers from modules.extras import run_extras, run_pnginfo - +from modules.sd_models import checkpoints_list +from modules.realesrgan_model import get_realesrgan_models +from typing import List def upscaler_to_index(name: str): try: @@ -37,7 +40,7 @@ def encode_pil_to_base64(image): class Api: - def __init__(self, app, queue_lock): + def __init__(self, app: FastAPI, queue_lock: Lock): self.router = APIRouter() self.app = app self.queue_lock = queue_lock @@ -48,6 +51,19 @@ class Api: self.app.add_api_route("/sdapi/v1/png-info", self.pnginfoapi, methods=["POST"], response_model=PNGInfoResponse) self.app.add_api_route("/sdapi/v1/progress", self.progressapi, methods=["GET"], response_model=ProgressResponse) self.app.add_api_route("/sdapi/v1/interrupt", self.interruptapi, methods=["POST"]) + self.app.add_api_route("/sdapi/v1/options", self.get_config, methods=["GET"], response_model=OptionsModel) + self.app.add_api_route("/sdapi/v1/options", self.set_config, methods=["POST"]) + self.app.add_api_route("/sdapi/v1/cmd-flags", self.get_cmd_flags, methods=["GET"], response_model=FlagsModel) + self.app.add_api_route("/sdapi/v1/info", self.get_info, methods=["GET"]) + self.app.add_api_route("/sdapi/v1/samplers", self.get_samplers, methods=["GET"], response_model=List[SamplerItem]) + self.app.add_api_route("/sdapi/v1/upscalers", self.get_upscalers, methods=["GET"], response_model=List[UpscalerItem]) + self.app.add_api_route("/sdapi/v1/sd-models", self.get_sd_models, methods=["GET"], response_model=List[SDModelItem]) + self.app.add_api_route("/sdapi/v1/hypernetworks", self.get_hypernetworks, methods=["GET"], response_model=List[HypernetworkItem]) + self.app.add_api_route("/sdapi/v1/face-restorers", self.get_face_restorers, methods=["GET"], response_model=List[FaceRestorerItem]) + self.app.add_api_route("/sdapi/v1/realesrgan-models", self.get_realesrgan_models, methods=["GET"], response_model=List[RealesrganItem]) + self.app.add_api_route("/sdapi/v1/prompt-styles", self.get_promp_styles, methods=["GET"], response_model=List[PromptStyleItem]) + self.app.add_api_route("/sdapi/v1/artist-categories", self.get_artists_categories, methods=["GET"], response_model=List[str]) + self.app.add_api_route("/sdapi/v1/artists", self.get_artists, methods=["GET"], response_model=List[ArtistItem]) def text2imgapi(self, txt2imgreq: StableDiffusionTxt2ImgProcessingAPI): sampler_index = sampler_to_index(txt2imgreq.sampler_index) @@ -190,6 +206,77 @@ class Api: shared.state.interrupt() return {} + + def get_config(self): + options = {} + for key in shared.opts.data.keys(): + metadata = shared.opts.data_labels.get(key) + if(metadata is not None): + options.update({key: shared.opts.data.get(key, shared.opts.data_labels.get(key).default)}) + else: + options.update({key: shared.opts.data.get(key, None)}) + + return options + + def set_config(self, req: OptionsModel): + reqDict = vars(req) + for o in reqDict: + setattr(shared.opts, o, reqDict[o]) + + shared.opts.save(shared.config_filename) + return + + def get_cmd_flags(self): + return vars(shared.cmd_opts) + + def get_info(self): + + return { + "hypernetworks": [{"name": name, "path": shared.hypernetworks[name]} for name in shared.hypernetworks], + "face_restorers": [{"name":x.name(), "cmd_dir": getattr(x, "cmd_dir", None)} for x in shared.face_restorers], + "realesrgan_models":[{"name":x.name,"path":x.data_path, "scale":x.scale} for x in get_realesrgan_models(None)], + "promp_styles":[shared.prompt_styles.styles[k] for k in shared.prompt_styles.styles], + "artists_categories": shared.artist_db.cats, + # "artists": [{"name":x[0], "score":x[1], "category":x[2]} for x in shared.artist_db.artists] + } + + def get_samplers(self): + return [{"name":sampler[0], "aliases":sampler[2], "options":sampler[3]} for sampler in all_samplers] + + def get_upscalers(self): + upscalers = [] + + for upscaler in shared.sd_upscalers: + u = upscaler.scaler + upscalers.append({"name":u.name, "model_name":u.model_name, "model_path":u.model_path, "model_url":u.model_url}) + + return upscalers + + def get_sd_models(self): + return [{"title":x.title, "model_name":x.model_name, "hash":x.hash, "filename": x.filename, "config": x.config} for x in checkpoints_list.values()] + + def get_hypernetworks(self): + return [{"name": name, "path": shared.hypernetworks[name]} for name in shared.hypernetworks] + + def get_face_restorers(self): + return [{"name":x.name(), "cmd_dir": getattr(x, "cmd_dir", None)} for x in shared.face_restorers] + + def get_realesrgan_models(self): + return [{"name":x.name,"path":x.data_path, "scale":x.scale} for x in get_realesrgan_models(None)] + + def get_promp_styles(self): + styleList = [] + for k in shared.prompt_styles.styles: + style = shared.prompt_styles.styles[k] + styleList.append({"name":style[0], "prompt": style[1], "negative_prompr": style[2]}) + + return styleList + + def get_artists_categories(self): + return shared.artist_db.cats + + def get_artists(self): + return [{"name":x[0], "score":x[1], "category":x[2]} for x in shared.artist_db.artists] def launch(self, server_name, port): self.app.include_router(self.router) diff --git a/modules/api/models.py b/modules/api/models.py index 9ee42a17..b54b188a 100644 --- a/modules/api/models.py +++ b/modules/api/models.py @@ -1,11 +1,10 @@ import inspect -from click import prompt from pydantic import BaseModel, Field, create_model -from typing import Any, Optional +from typing import Any, Optional, Union from typing_extensions import Literal from inflection import underscore from modules.processing import StableDiffusionProcessingTxt2Img, StableDiffusionProcessingImg2Img -from modules.shared import sd_upscalers +from modules.shared import sd_upscalers, opts, parser API_NOT_ALLOWED = [ "self", @@ -165,3 +164,68 @@ class ProgressResponse(BaseModel): eta_relative: float = Field(title="ETA in secs") state: dict = Field(title="State", description="The current state snapshot") current_image: str = Field(default=None, title="Current image", description="The current image in base64 format. opts.show_progress_every_n_steps is required for this to work.") + +fields = {} +for key, value in opts.data.items(): + metadata = opts.data_labels.get(key) + optType = opts.typemap.get(type(value), type(value)) + + if (metadata is not None): + fields.update({key: (Optional[optType], Field( + default=metadata.default ,description=metadata.label))}) + else: + fields.update({key: (Optional[optType], Field())}) + +OptionsModel = create_model("Options", **fields) + +flags = {} +_options = vars(parser)['_option_string_actions'] +for key in _options: + if(_options[key].dest != 'help'): + flag = _options[key] + _type = str + if(_options[key].default != None): _type = type(_options[key].default) + flags.update({flag.dest: (_type,Field(default=flag.default, description=flag.help))}) + +FlagsModel = create_model("Flags", **flags) + +class SamplerItem(BaseModel): + name: str = Field(title="Name") + aliases: list[str] = Field(title="Aliases") + options: dict[str, str] = Field(title="Options") + +class UpscalerItem(BaseModel): + name: str = Field(title="Name") + model_name: str | None = Field(title="Model Name") + model_path: str | None = Field(title="Path") + model_url: str | None = Field(title="URL") + +class SDModelItem(BaseModel): + title: str = Field(title="Title") + model_name: str = Field(title="Model Name") + hash: str = Field(title="Hash") + filename: str = Field(title="Filename") + config: str = Field(title="Config file") + +class HypernetworkItem(BaseModel): + name: str = Field(title="Name") + path: str | None = Field(title="Path") + +class FaceRestorerItem(BaseModel): + name: str = Field(title="Name") + cmd_dir: str | None = Field(title="Path") + +class RealesrganItem(BaseModel): + name: str = Field(title="Name") + path: str | None = Field(title="Path") + scale: int | None = Field(title="Scale") + +class PromptStyleItem(BaseModel): + name: str = Field(title="Name") + prompt: str | None = Field(title="Prompt") + negative_prompt: str | None = Field(title="Negative Prompt") + +class ArtistItem(BaseModel): + name: str = Field(title="Name") + score: float = Field(title="Score") + category: str = Field(title="Category") \ No newline at end of file From 743fffa3d6c2e9e6bb5f48093a4c88f3b53e001d Mon Sep 17 00:00:00 2001 From: Bruno Seoane Date: Thu, 3 Nov 2022 00:52:01 -0300 Subject: [PATCH 022/219] Remove unused endpoint --- modules/api/api.py | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/modules/api/api.py b/modules/api/api.py index ed2dce5d..a49f3755 100644 --- a/modules/api/api.py +++ b/modules/api/api.py @@ -54,7 +54,6 @@ class Api: self.app.add_api_route("/sdapi/v1/options", self.get_config, methods=["GET"], response_model=OptionsModel) self.app.add_api_route("/sdapi/v1/options", self.set_config, methods=["POST"]) self.app.add_api_route("/sdapi/v1/cmd-flags", self.get_cmd_flags, methods=["GET"], response_model=FlagsModel) - self.app.add_api_route("/sdapi/v1/info", self.get_info, methods=["GET"]) self.app.add_api_route("/sdapi/v1/samplers", self.get_samplers, methods=["GET"], response_model=List[SamplerItem]) self.app.add_api_route("/sdapi/v1/upscalers", self.get_upscalers, methods=["GET"], response_model=List[UpscalerItem]) self.app.add_api_route("/sdapi/v1/sd-models", self.get_sd_models, methods=["GET"], response_model=List[SDModelItem]) @@ -229,17 +228,6 @@ class Api: def get_cmd_flags(self): return vars(shared.cmd_opts) - def get_info(self): - - return { - "hypernetworks": [{"name": name, "path": shared.hypernetworks[name]} for name in shared.hypernetworks], - "face_restorers": [{"name":x.name(), "cmd_dir": getattr(x, "cmd_dir", None)} for x in shared.face_restorers], - "realesrgan_models":[{"name":x.name,"path":x.data_path, "scale":x.scale} for x in get_realesrgan_models(None)], - "promp_styles":[shared.prompt_styles.styles[k] for k in shared.prompt_styles.styles], - "artists_categories": shared.artist_db.cats, - # "artists": [{"name":x[0], "score":x[1], "category":x[2]} for x in shared.artist_db.artists] - } - def get_samplers(self): return [{"name":sampler[0], "aliases":sampler[2], "options":sampler[3]} for sampler in all_samplers] From e33d6cbddd08870e348d10a58af41fb677a39fd6 Mon Sep 17 00:00:00 2001 From: Ju1-js <40339350+Ju1-js@users.noreply.github.com> Date: Wed, 2 Nov 2022 21:04:49 -0700 Subject: [PATCH 023/219] Make extension manager Remote links open a new tab --- modules/ui_extensions.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/ui_extensions.py b/modules/ui_extensions.py index ab807722..a81de9a7 100644 --- a/modules/ui_extensions.py +++ b/modules/ui_extensions.py @@ -86,7 +86,7 @@ def extension_table(): code += f""" - {html.escape(ext.remote or '')} + {html.escape(ext.remote or '')} {ext_status} """ From fb1374791bf4b4c9b49de5378f29b12fdabcac97 Mon Sep 17 00:00:00 2001 From: Billy Cao Date: Thu, 3 Nov 2022 13:08:11 +0800 Subject: [PATCH 024/219] Fix --nowebui argument being ineffective --- launch.py | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/launch.py b/launch.py index 958336f2..b061bce6 100644 --- a/launch.py +++ b/launch.py @@ -217,12 +217,15 @@ def tests(argv): proc.kill() -def start_webui(): - print(f"Launching Web UI with arguments: {' '.join(sys.argv[1:])}") +def start(): + print(f"Launching {'API server' if '--nowebui' in sys.argv else 'Web UI'} with arguments: {' '.join(sys.argv[1:])}") import webui - webui.webui() + if '--nowebui' in sys.argv: + webui.api_only() + else: + webui.webui() if __name__ == "__main__": prepare_enviroment() - start_webui() + start() From 0b143c1163a96b193a4e8512be9c5831c661a50d Mon Sep 17 00:00:00 2001 From: aria1th <35677394+aria1th@users.noreply.github.com> Date: Thu, 3 Nov 2022 14:30:53 +0900 Subject: [PATCH 025/219] Separate .optim file from model --- modules/hypernetworks/hypernetwork.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/modules/hypernetworks/hypernetwork.py b/modules/hypernetworks/hypernetwork.py index 8f74cdea..63c25de8 100644 --- a/modules/hypernetworks/hypernetwork.py +++ b/modules/hypernetworks/hypernetwork.py @@ -161,6 +161,7 @@ class Hypernetwork: def save(self, filename): state_dict = {} + optimizer_saved_dict = {} for k, v in self.layers.items(): state_dict[k] = (v[0].state_dict(), v[1].state_dict()) @@ -175,9 +176,10 @@ class Hypernetwork: state_dict['sd_checkpoint'] = self.sd_checkpoint state_dict['sd_checkpoint_name'] = self.sd_checkpoint_name if self.optimizer_name is not None: - state_dict['optimizer_name'] = self.optimizer_name + optimizer_saved_dict['optimizer_name'] = self.optimizer_name if self.optimizer_state_dict: - state_dict['optimizer_state_dict'] = self.optimizer_state_dict + optimizer_saved_dict['optimizer_state_dict'] = self.optimizer_state_dict + torch.save(optimizer_saved_dict, filename + '.optim') torch.save(state_dict, filename) @@ -198,9 +200,11 @@ class Hypernetwork: print(f"Layer norm is set to {self.add_layer_norm}") self.use_dropout = state_dict.get('use_dropout', False) print(f"Dropout usage is set to {self.use_dropout}") - self.optimizer_name = state_dict.get('optimizer_name', 'AdamW') + + optimizer_saved_dict = torch.load(self.filename + '.optim', map_location = 'cpu') if os.path.exists(self.filename + '.optim') else {} + self.optimizer_name = optimizer_saved_dict.get('optimizer_name', 'AdamW') print(f"Optimizer name is {self.optimizer_name}") - self.optimizer_state_dict = state_dict.get('optimizer_state_dict', None) + self.optimizer_state_dict = optimizer_saved_dict.get('optimizer_state_dict', None) if self.optimizer_state_dict: print("Loaded existing optimizer from checkpoint") else: From 1764ac3c8bc482bd575987850e96630d9115e51a Mon Sep 17 00:00:00 2001 From: aria1th <35677394+aria1th@users.noreply.github.com> Date: Thu, 3 Nov 2022 14:49:26 +0900 Subject: [PATCH 026/219] use hash to check valid optim --- modules/hypernetworks/hypernetwork.py | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/modules/hypernetworks/hypernetwork.py b/modules/hypernetworks/hypernetwork.py index 63c25de8..4230b8cf 100644 --- a/modules/hypernetworks/hypernetwork.py +++ b/modules/hypernetworks/hypernetwork.py @@ -177,11 +177,12 @@ class Hypernetwork: state_dict['sd_checkpoint_name'] = self.sd_checkpoint_name if self.optimizer_name is not None: optimizer_saved_dict['optimizer_name'] = self.optimizer_name - if self.optimizer_state_dict: - optimizer_saved_dict['optimizer_state_dict'] = self.optimizer_state_dict - torch.save(optimizer_saved_dict, filename + '.optim') torch.save(state_dict, filename) + if self.optimizer_state_dict: + optimizer_saved_dict['hash'] = sd_models.model_hash(filename) + optimizer_saved_dict['optimizer_state_dict'] = self.optimizer_state_dict + torch.save(optimizer_saved_dict, filename + '.optim') def load(self, filename): self.filename = filename @@ -204,7 +205,10 @@ class Hypernetwork: optimizer_saved_dict = torch.load(self.filename + '.optim', map_location = 'cpu') if os.path.exists(self.filename + '.optim') else {} self.optimizer_name = optimizer_saved_dict.get('optimizer_name', 'AdamW') print(f"Optimizer name is {self.optimizer_name}") - self.optimizer_state_dict = optimizer_saved_dict.get('optimizer_state_dict', None) + if sd_models.model_hash(filename) == optimizer_saved_dict.get('hash', None): + self.optimizer_state_dict = optimizer_saved_dict.get('optimizer_state_dict', None) + else: + self.optimizer_state_dict = None if self.optimizer_state_dict: print("Loaded existing optimizer from checkpoint") else: @@ -229,7 +233,7 @@ def list_hypernetworks(path): name = os.path.splitext(os.path.basename(filename))[0] # Prevent a hypothetical "None.pt" from being listed. if name != "None": - res[name] = filename + res[name + f"({sd_models.model_hash(filename)})"] = filename return res @@ -375,6 +379,7 @@ def train_hypernetwork(hypernetwork_name, learn_rate, batch_size, data_root, log else: hypernetwork_dir = None + hypernetwork_name = hypernetwork_name.rsplit('(', 1)[0] if create_image_every > 0: images_dir = os.path.join(log_directory, "images") os.makedirs(images_dir, exist_ok=True) From 7e5f1562ecb08557c2997bdc4fd26a77e41b0e25 Mon Sep 17 00:00:00 2001 From: byzod Date: Thu, 3 Nov 2022 18:54:25 +0800 Subject: [PATCH 027/219] Update edit-attention.js Fix https://github.com/AUTOMATIC1111/stable-diffusion-webui/issues/3904 (Some sort of a workaround, the best way is to add unique id or class name to those prompt boxes) --- javascript/edit-attention.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/javascript/edit-attention.js b/javascript/edit-attention.js index c0d29a74..b947cbec 100644 --- a/javascript/edit-attention.js +++ b/javascript/edit-attention.js @@ -1,7 +1,6 @@ addEventListener('keydown', (event) => { let target = event.originalTarget || event.composedPath()[0]; - if (!target.hasAttribute("placeholder")) return; - if (!target.placeholder.toLowerCase().includes("prompt")) return; + if (!target.matches("#toprow textarea.gr-text-input[placeholder]")) return; if (! (event.metaKey || event.ctrlKey)) return; From 17bd3f4ea730436599849eddbaa78e2879b793d2 Mon Sep 17 00:00:00 2001 From: Bruno Seoane Date: Thu, 3 Nov 2022 10:08:18 -0300 Subject: [PATCH 028/219] Add tests --- test/utils_test.py | 63 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 63 insertions(+) create mode 100644 test/utils_test.py diff --git a/test/utils_test.py b/test/utils_test.py new file mode 100644 index 00000000..65d3d177 --- /dev/null +++ b/test/utils_test.py @@ -0,0 +1,63 @@ +import unittest +import requests + +class UtilsTests(unittest.TestCase): + def setUp(self): + self.url_options = "http://localhost:7860/sdapi/v1/options" + self.url_cmd_flags = "http://localhost:7860/sdapi/v1/cmd-flags" + self.url_samplers = "http://localhost:7860/sdapi/v1/samplers" + self.url_upscalers = "http://localhost:7860/sdapi/v1/upscalers" + self.url_sd_models = "http://localhost:7860/sdapi/v1/sd-models" + self.url_hypernetworks = "http://localhost:7860/sdapi/v1/hypernetworks" + self.url_face_restorers = "http://localhost:7860/sdapi/v1/face-restorers" + self.url_realesrgan_models = "http://localhost:7860/sdapi/v1/realesrgan-models" + self.url_prompt_styles = "http://localhost:7860/sdapi/v1/prompt-styles" + self.url_artist_categories = "http://localhost:7860/sdapi/v1/artist-categories" + self.url_artists = "http://localhost:7860/sdapi/v1/artists" + + def test_options_get(self): + self.assertEqual(requests.get(self.url_options).status_code, 200) + + def test_options_write(self): + response = requests.get(self.url_options) + self.assertEqual(response.status_code, 200) + + pre_value = response.json()["send_seed"] + + self.assertEqual(requests.post(self.url_options, json={"send_seed":not pre_value}).status_code, 200) + + response = requests.get(self.url_options) + self.assertEqual(response.status_code, 200) + self.assertEqual(response.json()["send_seed"], not pre_value) + + requests.post(self.url_options, json={"send_seed": pre_value}) + + def test_cmd_flags(self): + self.assertEqual(requests.get(self.url_cmd_flags).status_code, 200) + + def test_samplers(self): + self.assertEqual(requests.get(self.url_samplers).status_code, 200) + + def test_upscalers(self): + self.assertEqual(requests.get(self.url_upscalers).status_code, 200) + + def test_sd_models(self): + self.assertEqual(requests.get(self.url_sd_models).status_code, 200) + + def test_hypernetworks(self): + self.assertEqual(requests.get(self.url_hypernetworks).status_code, 200) + + def test_face_restorers(self): + self.assertEqual(requests.get(self.url_face_restorers).status_code, 200) + + def test_realesrgan_models(self): + self.assertEqual(requests.get(self.url_realesrgan_models).status_code, 200) + + def test_prompt_styles(self): + self.assertEqual(requests.get(self.url_prompt_styles).status_code, 200) + + def test_artist_categories(self): + self.assertEqual(requests.get(self.url_artist_categories).status_code, 200) + + def test_artists(self): + self.assertEqual(requests.get(self.url_artists).status_code, 200) \ No newline at end of file From 86b7fc6e5ed56327fa12b444ca2444b13eb98aa8 Mon Sep 17 00:00:00 2001 From: thesved <2893181+thesved@users.noreply.github.com> Date: Thu, 3 Nov 2022 19:44:47 +0100 Subject: [PATCH 029/219] Make DDIM and PLMS work on Mac OS Fix register_buffer error on Mac OS --- modules/sd_hijack_inpainting.py | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/modules/sd_hijack_inpainting.py b/modules/sd_hijack_inpainting.py index fd92a335..202b42cf 100644 --- a/modules/sd_hijack_inpainting.py +++ b/modules/sd_hijack_inpainting.py @@ -1,4 +1,5 @@ import torch +import modules.devices as devices from einops import repeat from omegaconf import ListConfig @@ -314,6 +315,20 @@ class LatentInpaintDiffusion(LatentDiffusion): self.masked_image_key = masked_image_key assert self.masked_image_key in concat_keys self.concat_keys = concat_keys + + +# ================================================================================================= +# Fix register buffer bug for Mac OS, Viktor Tabori, viktor.doklist.com/start-here +# ================================================================================================= +def register_buffer(self, name, attr): + if type(attr) == torch.Tensor: + optimal_type = devices.get_optimal_device() + if attr.device != optimal_type: + if getattr(torch, 'has_mps', False): + attr = attr.to(device="mps", dtype=torch.float32) + else: + attr = attr.to(optimal_type) + setattr(self, name, attr) def should_hijack_inpainting(checkpoint_info): @@ -326,6 +341,8 @@ def do_inpainting_hijack(): ldm.models.diffusion.ddim.DDIMSampler.p_sample_ddim = p_sample_ddim ldm.models.diffusion.ddim.DDIMSampler.sample = sample_ddim + ldm.models.diffusion.ddim.DDIMSampler.register_buffer = register_buffer ldm.models.diffusion.plms.PLMSSampler.p_sample_plms = p_sample_plms - ldm.models.diffusion.plms.PLMSSampler.sample = sample_plms \ No newline at end of file + ldm.models.diffusion.plms.PLMSSampler.sample = sample_plms + ldm.models.diffusion.plms.PLMSSampler.register_buffer = register_buffer From b2c48091db394c2b7d375a33f18d90c924cd4363 Mon Sep 17 00:00:00 2001 From: Gur Date: Fri, 4 Nov 2022 06:55:03 +0800 Subject: [PATCH 030/219] fixed api compatibility with python 3.8 --- modules/api/models.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/modules/api/models.py b/modules/api/models.py index 9ee42a17..29a934ba 100644 --- a/modules/api/models.py +++ b/modules/api/models.py @@ -6,6 +6,7 @@ from typing_extensions import Literal from inflection import underscore from modules.processing import StableDiffusionProcessingTxt2Img, StableDiffusionProcessingImg2Img from modules.shared import sd_upscalers +from typing import List API_NOT_ALLOWED = [ "self", @@ -109,12 +110,12 @@ StableDiffusionImg2ImgProcessingAPI = PydanticModelGenerator( ).generate_model() class TextToImageResponse(BaseModel): - images: list[str] = Field(default=None, title="Image", description="The generated image in base64 format.") + images: List[str] = Field(default=None, title="Image", description="The generated image in base64 format.") parameters: dict info: str class ImageToImageResponse(BaseModel): - images: list[str] = Field(default=None, title="Image", description="The generated image in base64 format.") + images: List[str] = Field(default=None, title="Image", description="The generated image in base64 format.") parameters: dict info: str @@ -146,10 +147,10 @@ class FileData(BaseModel): name: str = Field(title="File name") class ExtrasBatchImagesRequest(ExtrasBaseRequest): - imageList: list[FileData] = Field(title="Images", description="List of images to work on. Must be Base64 strings") + imageList: List[FileData] = Field(title="Images", description="List of images to work on. Must be Base64 strings") class ExtrasBatchImagesResponse(ExtraBaseResponse): - images: list[str] = Field(title="Images", description="The generated images in base64 format.") + images: List[str] = Field(title="Images", description="The generated images in base64 format.") class PNGInfoRequest(BaseModel): image: str = Field(title="Image", description="The base64 encoded PNG image") From 0abb39f461baa343ae7c23abffb261e57c3168d4 Mon Sep 17 00:00:00 2001 From: aria1th <35677394+aria1th@users.noreply.github.com> Date: Fri, 4 Nov 2022 15:47:19 +0900 Subject: [PATCH 031/219] resolve conflict - first revert --- modules/hypernetworks/hypernetwork.py | 123 +++++++++++--------------- 1 file changed, 52 insertions(+), 71 deletions(-) diff --git a/modules/hypernetworks/hypernetwork.py b/modules/hypernetworks/hypernetwork.py index 4230b8cf..674fcedd 100644 --- a/modules/hypernetworks/hypernetwork.py +++ b/modules/hypernetworks/hypernetwork.py @@ -21,7 +21,6 @@ from torch.nn.init import normal_, xavier_normal_, xavier_uniform_, kaiming_norm from collections import defaultdict, deque from statistics import stdev, mean -optimizer_dict = {optim_name : cls_obj for optim_name, cls_obj in inspect.getmembers(torch.optim, inspect.isclass) if optim_name != "Optimizer"} class HypernetworkModule(torch.nn.Module): multiplier = 1.0 @@ -34,9 +33,12 @@ class HypernetworkModule(torch.nn.Module): "tanh": torch.nn.Tanh, "sigmoid": torch.nn.Sigmoid, } - activation_dict.update({cls_name.lower(): cls_obj for cls_name, cls_obj in inspect.getmembers(torch.nn.modules.activation) if inspect.isclass(cls_obj) and cls_obj.__module__ == 'torch.nn.modules.activation'}) + activation_dict.update( + {cls_name.lower(): cls_obj for cls_name, cls_obj in inspect.getmembers(torch.nn.modules.activation) if + inspect.isclass(cls_obj) and cls_obj.__module__ == 'torch.nn.modules.activation'}) - def __init__(self, dim, state_dict=None, layer_structure=None, activation_func=None, weight_init='Normal', add_layer_norm=False, use_dropout=False): + def __init__(self, dim, state_dict=None, layer_structure=None, activation_func=None, weight_init='Normal', + add_layer_norm=False, use_dropout=False): super().__init__() assert layer_structure is not None, "layer_structure must not be None" @@ -47,7 +49,7 @@ class HypernetworkModule(torch.nn.Module): for i in range(len(layer_structure) - 1): # Add a fully-connected layer - linears.append(torch.nn.Linear(int(dim * layer_structure[i]), int(dim * layer_structure[i+1]))) + linears.append(torch.nn.Linear(int(dim * layer_structure[i]), int(dim * layer_structure[i + 1]))) # Add an activation func if activation_func == "linear" or activation_func is None: @@ -59,7 +61,7 @@ class HypernetworkModule(torch.nn.Module): # Add layer normalization if add_layer_norm: - linears.append(torch.nn.LayerNorm(int(dim * layer_structure[i+1]))) + linears.append(torch.nn.LayerNorm(int(dim * layer_structure[i + 1]))) # Add dropout expect last layer if use_dropout and i < len(layer_structure) - 3: @@ -128,7 +130,8 @@ class Hypernetwork: filename = None name = None - def __init__(self, name=None, enable_sizes=None, layer_structure=None, activation_func=None, weight_init=None, add_layer_norm=False, use_dropout=False): + def __init__(self, name=None, enable_sizes=None, layer_structure=None, activation_func=None, weight_init=None, + add_layer_norm=False, use_dropout=False): self.filename = None self.name = name self.layers = {} @@ -140,13 +143,13 @@ class Hypernetwork: self.weight_init = weight_init self.add_layer_norm = add_layer_norm self.use_dropout = use_dropout - self.optimizer_name = None - self.optimizer_state_dict = None for size in enable_sizes or []: self.layers[size] = ( - HypernetworkModule(size, None, self.layer_structure, self.activation_func, self.weight_init, self.add_layer_norm, self.use_dropout), - HypernetworkModule(size, None, self.layer_structure, self.activation_func, self.weight_init, self.add_layer_norm, self.use_dropout), + HypernetworkModule(size, None, self.layer_structure, self.activation_func, self.weight_init, + self.add_layer_norm, self.use_dropout), + HypernetworkModule(size, None, self.layer_structure, self.activation_func, self.weight_init, + self.add_layer_norm, self.use_dropout), ) def weights(self): @@ -161,7 +164,6 @@ class Hypernetwork: def save(self, filename): state_dict = {} - optimizer_saved_dict = {} for k, v in self.layers.items(): state_dict[k] = (v[0].state_dict(), v[1].state_dict()) @@ -175,14 +177,8 @@ class Hypernetwork: state_dict['use_dropout'] = self.use_dropout state_dict['sd_checkpoint'] = self.sd_checkpoint state_dict['sd_checkpoint_name'] = self.sd_checkpoint_name - if self.optimizer_name is not None: - optimizer_saved_dict['optimizer_name'] = self.optimizer_name torch.save(state_dict, filename) - if self.optimizer_state_dict: - optimizer_saved_dict['hash'] = sd_models.model_hash(filename) - optimizer_saved_dict['optimizer_state_dict'] = self.optimizer_state_dict - torch.save(optimizer_saved_dict, filename + '.optim') def load(self, filename): self.filename = filename @@ -202,23 +198,13 @@ class Hypernetwork: self.use_dropout = state_dict.get('use_dropout', False) print(f"Dropout usage is set to {self.use_dropout}") - optimizer_saved_dict = torch.load(self.filename + '.optim', map_location = 'cpu') if os.path.exists(self.filename + '.optim') else {} - self.optimizer_name = optimizer_saved_dict.get('optimizer_name', 'AdamW') - print(f"Optimizer name is {self.optimizer_name}") - if sd_models.model_hash(filename) == optimizer_saved_dict.get('hash', None): - self.optimizer_state_dict = optimizer_saved_dict.get('optimizer_state_dict', None) - else: - self.optimizer_state_dict = None - if self.optimizer_state_dict: - print("Loaded existing optimizer from checkpoint") - else: - print("No saved optimizer exists in checkpoint") - for size, sd in state_dict.items(): if type(size) == int: self.layers[size] = ( - HypernetworkModule(size, sd[0], self.layer_structure, self.activation_func, self.weight_init, self.add_layer_norm, self.use_dropout), - HypernetworkModule(size, sd[1], self.layer_structure, self.activation_func, self.weight_init, self.add_layer_norm, self.use_dropout), + HypernetworkModule(size, sd[0], self.layer_structure, self.activation_func, self.weight_init, + self.add_layer_norm, self.use_dropout), + HypernetworkModule(size, sd[1], self.layer_structure, self.activation_func, self.weight_init, + self.add_layer_norm, self.use_dropout), ) self.name = state_dict.get('name', self.name) @@ -233,7 +219,7 @@ def list_hypernetworks(path): name = os.path.splitext(os.path.basename(filename))[0] # Prevent a hypothetical "None.pt" from being listed. if name != "None": - res[name + f"({sd_models.model_hash(filename)})"] = filename + res[name] = filename return res @@ -330,7 +316,7 @@ def statistics(data): std = 0 else: std = stdev(data) - total_information = f"loss:{mean(data):.3f}" + u"\u00B1" + f"({std/ (len(data) ** 0.5):.3f})" + total_information = f"loss:{mean(data):.3f}" + u"\u00B1" + f"({std / (len(data) ** 0.5):.3f})" recent_data = data[-32:] if len(recent_data) < 2: std = 0 @@ -340,7 +326,7 @@ def statistics(data): return total_information, recent_information -def report_statistics(loss_info:dict): +def report_statistics(loss_info: dict): keys = sorted(loss_info.keys(), key=lambda x: sum(loss_info[x]) / len(loss_info[x])) for key in keys: try: @@ -352,14 +338,18 @@ def report_statistics(loss_info:dict): print(e) - -def train_hypernetwork(hypernetwork_name, learn_rate, batch_size, data_root, log_directory, training_width, training_height, steps, create_image_every, save_hypernetwork_every, template_file, preview_from_txt2img, preview_prompt, preview_negative_prompt, preview_steps, preview_sampler_index, preview_cfg_scale, preview_seed, preview_width, preview_height): +def train_hypernetwork(hypernetwork_name, learn_rate, batch_size, data_root, log_directory, training_width, + training_height, steps, create_image_every, save_hypernetwork_every, template_file, + preview_from_txt2img, preview_prompt, preview_negative_prompt, preview_steps, + preview_sampler_index, preview_cfg_scale, preview_seed, preview_width, preview_height): # images allows training previews to have infotext. Importing it at the top causes a circular import problem. from modules import images save_hypernetwork_every = save_hypernetwork_every or 0 create_image_every = create_image_every or 0 - textual_inversion.validate_train_inputs(hypernetwork_name, learn_rate, batch_size, data_root, template_file, steps, save_hypernetwork_every, create_image_every, log_directory, name="hypernetwork") + textual_inversion.validate_train_inputs(hypernetwork_name, learn_rate, batch_size, data_root, template_file, steps, + save_hypernetwork_every, create_image_every, log_directory, + name="hypernetwork") path = shared.hypernetworks.get(hypernetwork_name, None) shared.loaded_hypernetwork = Hypernetwork() @@ -379,7 +369,6 @@ def train_hypernetwork(hypernetwork_name, learn_rate, batch_size, data_root, log else: hypernetwork_dir = None - hypernetwork_name = hypernetwork_name.rsplit('(', 1)[0] if create_image_every > 0: images_dir = os.path.join(log_directory, "images") os.makedirs(images_dir, exist_ok=True) @@ -395,39 +384,34 @@ def train_hypernetwork(hypernetwork_name, learn_rate, batch_size, data_root, log return hypernetwork, filename scheduler = LearnRateScheduler(learn_rate, steps, ititial_step) - + # dataset loading may take a while, so input validations and early returns should be done before this shared.state.textinfo = f"Preparing dataset from {html.escape(data_root)}..." with torch.autocast("cuda"): - ds = modules.textual_inversion.dataset.PersonalizedBase(data_root=data_root, width=training_width, height=training_height, repeats=shared.opts.training_image_repeats_per_epoch, placeholder_token=hypernetwork_name, model=shared.sd_model, device=devices.device, template_file=template_file, include_cond=True, batch_size=batch_size) + ds = modules.textual_inversion.dataset.PersonalizedBase(data_root=data_root, width=training_width, + height=training_height, + repeats=shared.opts.training_image_repeats_per_epoch, + placeholder_token=hypernetwork_name, + model=shared.sd_model, device=devices.device, + template_file=template_file, include_cond=True, + batch_size=batch_size) if unload: shared.sd_model.cond_stage_model.to(devices.cpu) shared.sd_model.first_stage_model.to(devices.cpu) size = len(ds.indexes) - loss_dict = defaultdict(lambda : deque(maxlen = 1024)) + loss_dict = defaultdict(lambda: deque(maxlen=1024)) losses = torch.zeros((size,)) previous_mean_losses = [0] previous_mean_loss = 0 print("Mean loss of {} elements".format(size)) - + weights = hypernetwork.weights() for weight in weights: weight.requires_grad = True - # Here we use optimizer from saved HN, or we can specify as UI option. - if (optimizer_name := hypernetwork.optimizer_name) in optimizer_dict: - optimizer = optimizer_dict[hypernetwork.optimizer_name](params=weights, lr=scheduler.learn_rate) - else: - print(f"Optimizer type {optimizer_name} is not defined!") - optimizer = torch.optim.AdamW(params=weights, lr=scheduler.learn_rate) - optimizer_name = 'AdamW' - if hypernetwork.optimizer_state_dict: # This line must be changed if Optimizer type can be different from saved optimizer. - try: - optimizer.load_state_dict(hypernetwork.optimizer_state_dict) - except RuntimeError as e: - print("Cannot resume from saved optimizer!") - print(e) + # if optimizer == "AdamW": or else Adam / AdamW / SGD, etc... + optimizer = torch.optim.AdamW(weights, lr=scheduler.learn_rate) steps_without_grad = 0 @@ -441,7 +425,7 @@ def train_hypernetwork(hypernetwork_name, learn_rate, batch_size, data_root, log if len(loss_dict) > 0: previous_mean_losses = [i[-1] for i in loss_dict.values()] previous_mean_loss = mean(previous_mean_losses) - + scheduler.apply(optimizer, hypernetwork.step) if scheduler.finished: break @@ -460,7 +444,7 @@ def train_hypernetwork(hypernetwork_name, learn_rate, batch_size, data_root, log losses[hypernetwork.step % losses.shape[0]] = loss.item() for entry in entries: loss_dict[entry.filename].append(loss.item()) - + optimizer.zero_grad() weights[0].grad = None loss.backward() @@ -475,9 +459,9 @@ def train_hypernetwork(hypernetwork_name, learn_rate, batch_size, data_root, log steps_done = hypernetwork.step + 1 - if torch.isnan(losses[hypernetwork.step % losses.shape[0]]): + if torch.isnan(losses[hypernetwork.step % losses.shape[0]]): raise RuntimeError("Loss diverged.") - + if len(previous_mean_losses) > 1: std = stdev(previous_mean_losses) else: @@ -489,11 +473,8 @@ def train_hypernetwork(hypernetwork_name, learn_rate, batch_size, data_root, log # Before saving, change name to match current checkpoint. hypernetwork_name_every = f'{hypernetwork_name}-{steps_done}' last_saved_file = os.path.join(hypernetwork_dir, f'{hypernetwork_name_every}.pt') - hypernetwork.optimizer_name = optimizer_name - if shared.opts.save_optimizer_state: - hypernetwork.optimizer_state_dict = optimizer.state_dict() save_hypernetwork(hypernetwork, checkpoint, hypernetwork_name, last_saved_file) - hypernetwork.optimizer_state_dict = None # dereference it after saving, to save memory. + textual_inversion.write_loss(log_directory, "hypernetwork_loss.csv", hypernetwork.step, len(ds), { "loss": f"{previous_mean_loss:.7f}", "learn_rate": scheduler.learn_rate @@ -529,7 +510,7 @@ def train_hypernetwork(hypernetwork_name, learn_rate, batch_size, data_root, log preview_text = p.prompt processed = processing.process_images(p) - image = processed.images[0] if len(processed.images)>0 else None + image = processed.images[0] if len(processed.images) > 0 else None if unload: shared.sd_model.cond_stage_model.to(devices.cpu) @@ -537,7 +518,10 @@ def train_hypernetwork(hypernetwork_name, learn_rate, batch_size, data_root, log if image is not None: shared.state.current_image = image - last_saved_image, last_text_info = images.save_image(image, images_dir, "", p.seed, p.prompt, shared.opts.samples_format, processed.infotexts[0], p=p, forced_filename=forced_filename, save_to_dirs=False) + last_saved_image, last_text_info = images.save_image(image, images_dir, "", p.seed, p.prompt, + shared.opts.samples_format, processed.infotexts[0], + p=p, forced_filename=forced_filename, + save_to_dirs=False) last_saved_image += f", prompt: {preview_text}" shared.state.job_no = hypernetwork.step @@ -551,15 +535,12 @@ Last saved hypernetwork: {html.escape(last_saved_file)}
Last saved image: {html.escape(last_saved_image)}

""" + report_statistics(loss_dict) filename = os.path.join(shared.cmd_opts.hypernetwork_dir, f'{hypernetwork_name}.pt') - hypernetwork.optimizer_name = optimizer_name - if shared.opts.save_optimizer_state: - hypernetwork.optimizer_state_dict = optimizer.state_dict() save_hypernetwork(hypernetwork, checkpoint, hypernetwork_name, filename) - del optimizer - hypernetwork.optimizer_state_dict = None # dereference it after saving, to save memory. + return hypernetwork, filename @@ -576,4 +557,4 @@ def save_hypernetwork(hypernetwork, checkpoint, hypernetwork_name, filename): hypernetwork.sd_checkpoint = old_sd_checkpoint hypernetwork.sd_checkpoint_name = old_sd_checkpoint_name hypernetwork.name = old_hypernetwork_name - raise + raise \ No newline at end of file From 0d07cbfa15d34294a4fa22d74359cdd6fe2f799c Mon Sep 17 00:00:00 2001 From: AngelBottomless <35677394+aria1th@users.noreply.github.com> Date: Fri, 4 Nov 2022 15:50:54 +0900 Subject: [PATCH 032/219] I blame code autocomplete --- modules/hypernetworks/hypernetwork.py | 76 ++++++++++----------------- 1 file changed, 27 insertions(+), 49 deletions(-) diff --git a/modules/hypernetworks/hypernetwork.py b/modules/hypernetworks/hypernetwork.py index 674fcedd..a11e01d6 100644 --- a/modules/hypernetworks/hypernetwork.py +++ b/modules/hypernetworks/hypernetwork.py @@ -33,12 +33,9 @@ class HypernetworkModule(torch.nn.Module): "tanh": torch.nn.Tanh, "sigmoid": torch.nn.Sigmoid, } - activation_dict.update( - {cls_name.lower(): cls_obj for cls_name, cls_obj in inspect.getmembers(torch.nn.modules.activation) if - inspect.isclass(cls_obj) and cls_obj.__module__ == 'torch.nn.modules.activation'}) + activation_dict.update({cls_name.lower(): cls_obj for cls_name, cls_obj in inspect.getmembers(torch.nn.modules.activation) if inspect.isclass(cls_obj) and cls_obj.__module__ == 'torch.nn.modules.activation'}) - def __init__(self, dim, state_dict=None, layer_structure=None, activation_func=None, weight_init='Normal', - add_layer_norm=False, use_dropout=False): + def __init__(self, dim, state_dict=None, layer_structure=None, activation_func=None, weight_init='Normal', add_layer_norm=False, use_dropout=False): super().__init__() assert layer_structure is not None, "layer_structure must not be None" @@ -49,7 +46,7 @@ class HypernetworkModule(torch.nn.Module): for i in range(len(layer_structure) - 1): # Add a fully-connected layer - linears.append(torch.nn.Linear(int(dim * layer_structure[i]), int(dim * layer_structure[i + 1]))) + linears.append(torch.nn.Linear(int(dim * layer_structure[i]), int(dim * layer_structure[i+1]))) # Add an activation func if activation_func == "linear" or activation_func is None: @@ -61,7 +58,7 @@ class HypernetworkModule(torch.nn.Module): # Add layer normalization if add_layer_norm: - linears.append(torch.nn.LayerNorm(int(dim * layer_structure[i + 1]))) + linears.append(torch.nn.LayerNorm(int(dim * layer_structure[i+1]))) # Add dropout expect last layer if use_dropout and i < len(layer_structure) - 3: @@ -130,8 +127,7 @@ class Hypernetwork: filename = None name = None - def __init__(self, name=None, enable_sizes=None, layer_structure=None, activation_func=None, weight_init=None, - add_layer_norm=False, use_dropout=False): + def __init__(self, name=None, enable_sizes=None, layer_structure=None, activation_func=None, weight_init=None, add_layer_norm=False, use_dropout=False): self.filename = None self.name = name self.layers = {} @@ -146,10 +142,8 @@ class Hypernetwork: for size in enable_sizes or []: self.layers[size] = ( - HypernetworkModule(size, None, self.layer_structure, self.activation_func, self.weight_init, - self.add_layer_norm, self.use_dropout), - HypernetworkModule(size, None, self.layer_structure, self.activation_func, self.weight_init, - self.add_layer_norm, self.use_dropout), + HypernetworkModule(size, None, self.layer_structure, self.activation_func, self.weight_init, self.add_layer_norm, self.use_dropout), + HypernetworkModule(size, None, self.layer_structure, self.activation_func, self.weight_init, self.add_layer_norm, self.use_dropout), ) def weights(self): @@ -196,15 +190,13 @@ class Hypernetwork: self.add_layer_norm = state_dict.get('is_layer_norm', False) print(f"Layer norm is set to {self.add_layer_norm}") self.use_dropout = state_dict.get('use_dropout', False) - print(f"Dropout usage is set to {self.use_dropout}") + print(f"Dropout usage is set to {self.use_dropout}" ) for size, sd in state_dict.items(): if type(size) == int: self.layers[size] = ( - HypernetworkModule(size, sd[0], self.layer_structure, self.activation_func, self.weight_init, - self.add_layer_norm, self.use_dropout), - HypernetworkModule(size, sd[1], self.layer_structure, self.activation_func, self.weight_init, - self.add_layer_norm, self.use_dropout), + HypernetworkModule(size, sd[0], self.layer_structure, self.activation_func, self.weight_init, self.add_layer_norm, self.use_dropout), + HypernetworkModule(size, sd[1], self.layer_structure, self.activation_func, self.weight_init, self.add_layer_norm, self.use_dropout), ) self.name = state_dict.get('name', self.name) @@ -316,7 +308,7 @@ def statistics(data): std = 0 else: std = stdev(data) - total_information = f"loss:{mean(data):.3f}" + u"\u00B1" + f"({std / (len(data) ** 0.5):.3f})" + total_information = f"loss:{mean(data):.3f}" + u"\u00B1" + f"({std/ (len(data) ** 0.5):.3f})" recent_data = data[-32:] if len(recent_data) < 2: std = 0 @@ -326,7 +318,7 @@ def statistics(data): return total_information, recent_information -def report_statistics(loss_info: dict): +def report_statistics(loss_info:dict): keys = sorted(loss_info.keys(), key=lambda x: sum(loss_info[x]) / len(loss_info[x])) for key in keys: try: @@ -338,18 +330,14 @@ def report_statistics(loss_info: dict): print(e) -def train_hypernetwork(hypernetwork_name, learn_rate, batch_size, data_root, log_directory, training_width, - training_height, steps, create_image_every, save_hypernetwork_every, template_file, - preview_from_txt2img, preview_prompt, preview_negative_prompt, preview_steps, - preview_sampler_index, preview_cfg_scale, preview_seed, preview_width, preview_height): + +def train_hypernetwork(hypernetwork_name, learn_rate, batch_size, data_root, log_directory, training_width, training_height, steps, create_image_every, save_hypernetwork_every, template_file, preview_from_txt2img, preview_prompt, preview_negative_prompt, preview_steps, preview_sampler_index, preview_cfg_scale, preview_seed, preview_width, preview_height): # images allows training previews to have infotext. Importing it at the top causes a circular import problem. from modules import images save_hypernetwork_every = save_hypernetwork_every or 0 create_image_every = create_image_every or 0 - textual_inversion.validate_train_inputs(hypernetwork_name, learn_rate, batch_size, data_root, template_file, steps, - save_hypernetwork_every, create_image_every, log_directory, - name="hypernetwork") + textual_inversion.validate_train_inputs(hypernetwork_name, learn_rate, batch_size, data_root, template_file, steps, save_hypernetwork_every, create_image_every, log_directory, name="hypernetwork") path = shared.hypernetworks.get(hypernetwork_name, None) shared.loaded_hypernetwork = Hypernetwork() @@ -384,29 +372,23 @@ def train_hypernetwork(hypernetwork_name, learn_rate, batch_size, data_root, log return hypernetwork, filename scheduler = LearnRateScheduler(learn_rate, steps, ititial_step) - + # dataset loading may take a while, so input validations and early returns should be done before this shared.state.textinfo = f"Preparing dataset from {html.escape(data_root)}..." with torch.autocast("cuda"): - ds = modules.textual_inversion.dataset.PersonalizedBase(data_root=data_root, width=training_width, - height=training_height, - repeats=shared.opts.training_image_repeats_per_epoch, - placeholder_token=hypernetwork_name, - model=shared.sd_model, device=devices.device, - template_file=template_file, include_cond=True, - batch_size=batch_size) + ds = modules.textual_inversion.dataset.PersonalizedBase(data_root=data_root, width=training_width, height=training_height, repeats=shared.opts.training_image_repeats_per_epoch, placeholder_token=hypernetwork_name, model=shared.sd_model, device=devices.device, template_file=template_file, include_cond=True, batch_size=batch_size) if unload: shared.sd_model.cond_stage_model.to(devices.cpu) shared.sd_model.first_stage_model.to(devices.cpu) size = len(ds.indexes) - loss_dict = defaultdict(lambda: deque(maxlen=1024)) + loss_dict = defaultdict(lambda : deque(maxlen = 1024)) losses = torch.zeros((size,)) previous_mean_losses = [0] previous_mean_loss = 0 print("Mean loss of {} elements".format(size)) - + weights = hypernetwork.weights() for weight in weights: weight.requires_grad = True @@ -425,7 +407,7 @@ def train_hypernetwork(hypernetwork_name, learn_rate, batch_size, data_root, log if len(loss_dict) > 0: previous_mean_losses = [i[-1] for i in loss_dict.values()] previous_mean_loss = mean(previous_mean_losses) - + scheduler.apply(optimizer, hypernetwork.step) if scheduler.finished: break @@ -444,7 +426,7 @@ def train_hypernetwork(hypernetwork_name, learn_rate, batch_size, data_root, log losses[hypernetwork.step % losses.shape[0]] = loss.item() for entry in entries: loss_dict[entry.filename].append(loss.item()) - + optimizer.zero_grad() weights[0].grad = None loss.backward() @@ -459,9 +441,9 @@ def train_hypernetwork(hypernetwork_name, learn_rate, batch_size, data_root, log steps_done = hypernetwork.step + 1 - if torch.isnan(losses[hypernetwork.step % losses.shape[0]]): + if torch.isnan(losses[hypernetwork.step % losses.shape[0]]): raise RuntimeError("Loss diverged.") - + if len(previous_mean_losses) > 1: std = stdev(previous_mean_losses) else: @@ -510,7 +492,7 @@ def train_hypernetwork(hypernetwork_name, learn_rate, batch_size, data_root, log preview_text = p.prompt processed = processing.process_images(p) - image = processed.images[0] if len(processed.images) > 0 else None + image = processed.images[0] if len(processed.images)>0 else None if unload: shared.sd_model.cond_stage_model.to(devices.cpu) @@ -518,10 +500,7 @@ def train_hypernetwork(hypernetwork_name, learn_rate, batch_size, data_root, log if image is not None: shared.state.current_image = image - last_saved_image, last_text_info = images.save_image(image, images_dir, "", p.seed, p.prompt, - shared.opts.samples_format, processed.infotexts[0], - p=p, forced_filename=forced_filename, - save_to_dirs=False) + last_saved_image, last_text_info = images.save_image(image, images_dir, "", p.seed, p.prompt, shared.opts.samples_format, processed.infotexts[0], p=p, forced_filename=forced_filename, save_to_dirs=False) last_saved_image += f", prompt: {preview_text}" shared.state.job_no = hypernetwork.step @@ -535,7 +514,7 @@ Last saved hypernetwork: {html.escape(last_saved_file)}
Last saved image: {html.escape(last_saved_image)}

""" - + report_statistics(loss_dict) filename = os.path.join(shared.cmd_opts.hypernetwork_dir, f'{hypernetwork_name}.pt') @@ -543,7 +522,6 @@ Last saved image: {html.escape(last_saved_image)}
return hypernetwork, filename - def save_hypernetwork(hypernetwork, checkpoint, hypernetwork_name, filename): old_hypernetwork_name = hypernetwork.name old_sd_checkpoint = hypernetwork.sd_checkpoint if hasattr(hypernetwork, "sd_checkpoint") else None @@ -557,4 +535,4 @@ def save_hypernetwork(hypernetwork, checkpoint, hypernetwork_name, filename): hypernetwork.sd_checkpoint = old_sd_checkpoint hypernetwork.sd_checkpoint_name = old_sd_checkpoint_name hypernetwork.name = old_hypernetwork_name - raise \ No newline at end of file + raise From 283249d2390f0f3a1c8a55d5d9aa551e3e9b2f9c Mon Sep 17 00:00:00 2001 From: aria1th <35677394+aria1th@users.noreply.github.com> Date: Fri, 4 Nov 2022 15:57:17 +0900 Subject: [PATCH 033/219] apply --- modules/hypernetworks/hypernetwork.py | 54 ++++++++++++++++++++++++--- 1 file changed, 49 insertions(+), 5 deletions(-) diff --git a/modules/hypernetworks/hypernetwork.py b/modules/hypernetworks/hypernetwork.py index 6e1a10cf..de8688a9 100644 --- a/modules/hypernetworks/hypernetwork.py +++ b/modules/hypernetworks/hypernetwork.py @@ -22,6 +22,8 @@ from collections import defaultdict, deque from statistics import stdev, mean +optimizer_dict = {optim_name : cls_obj for optim_name, cls_obj in inspect.getmembers(torch.optim, inspect.isclass) if optim_name != "Optimizer"} + class HypernetworkModule(torch.nn.Module): multiplier = 1.0 activation_dict = { @@ -142,6 +144,8 @@ class Hypernetwork: self.use_dropout = use_dropout self.activate_output = activate_output self.last_layer_dropout = kwargs['last_layer_dropout'] if 'last_layer_dropout' in kwargs else True + self.optimizer_name = None + self.optimizer_state_dict = None for size in enable_sizes or []: self.layers[size] = ( @@ -163,6 +167,7 @@ class Hypernetwork: def save(self, filename): state_dict = {} + optimizer_saved_dict = {} for k, v in self.layers.items(): state_dict[k] = (v[0].state_dict(), v[1].state_dict()) @@ -178,8 +183,15 @@ class Hypernetwork: state_dict['sd_checkpoint_name'] = self.sd_checkpoint_name state_dict['activate_output'] = self.activate_output state_dict['last_layer_dropout'] = self.last_layer_dropout - + + if self.optimizer_name is not None: + optimizer_saved_dict['optimizer_name'] = self.optimizer_name + torch.save(state_dict, filename) + if self.optimizer_state_dict: + optimizer_saved_dict['hash'] = sd_models.model_hash(filename) + optimizer_saved_dict['optimizer_state_dict'] = self.optimizer_state_dict + torch.save(optimizer_saved_dict, filename + '.optim') def load(self, filename): self.filename = filename @@ -202,6 +214,18 @@ class Hypernetwork: print(f"Activate last layer is set to {self.activate_output}") self.last_layer_dropout = state_dict.get('last_layer_dropout', False) + optimizer_saved_dict = torch.load(self.filename + '.optim', map_location = 'cpu') if os.path.exists(self.filename + '.optim') else {} + self.optimizer_name = optimizer_saved_dict.get('optimizer_name', 'AdamW') + print(f"Optimizer name is {self.optimizer_name}") + if sd_models.model_hash(filename) == optimizer_saved_dict.get('hash', None): + self.optimizer_state_dict = optimizer_saved_dict.get('optimizer_state_dict', None) + else: + self.optimizer_state_dict = None + if self.optimizer_state_dict: + print("Loaded existing optimizer from checkpoint") + else: + print("No saved optimizer exists in checkpoint") + for size, sd in state_dict.items(): if type(size) == int: self.layers[size] = ( @@ -223,7 +247,7 @@ def list_hypernetworks(path): name = os.path.splitext(os.path.basename(filename))[0] # Prevent a hypothetical "None.pt" from being listed. if name != "None": - res[name] = filename + res[name + f"({sd_models.model_hash(filename)})"] = filename return res @@ -369,6 +393,7 @@ def train_hypernetwork(hypernetwork_name, learn_rate, batch_size, data_root, log else: hypernetwork_dir = None + hypernetwork_name = hypernetwork_name.rsplit('(', 1)[0] if create_image_every > 0: images_dir = os.path.join(log_directory, "images") os.makedirs(images_dir, exist_ok=True) @@ -404,8 +429,19 @@ def train_hypernetwork(hypernetwork_name, learn_rate, batch_size, data_root, log weights = hypernetwork.weights() for weight in weights: weight.requires_grad = True - # if optimizer == "AdamW": or else Adam / AdamW / SGD, etc... - optimizer = torch.optim.AdamW(weights, lr=scheduler.learn_rate) + # Here we use optimizer from saved HN, or we can specify as UI option. + if (optimizer_name := hypernetwork.optimizer_name) in optimizer_dict: + optimizer = optimizer_dict[hypernetwork.optimizer_name](params=weights, lr=scheduler.learn_rate) + else: + print(f"Optimizer type {optimizer_name} is not defined!") + optimizer = torch.optim.AdamW(params=weights, lr=scheduler.learn_rate) + optimizer_name = 'AdamW' + if hypernetwork.optimizer_state_dict: # This line must be changed if Optimizer type can be different from saved optimizer. + try: + optimizer.load_state_dict(hypernetwork.optimizer_state_dict) + except RuntimeError as e: + print("Cannot resume from saved optimizer!") + print(e) steps_without_grad = 0 @@ -467,7 +503,11 @@ def train_hypernetwork(hypernetwork_name, learn_rate, batch_size, data_root, log # Before saving, change name to match current checkpoint. hypernetwork_name_every = f'{hypernetwork_name}-{steps_done}' last_saved_file = os.path.join(hypernetwork_dir, f'{hypernetwork_name_every}.pt') + hypernetwork.optimizer_name = optimizer_name + if shared.opts.save_optimizer_state: + hypernetwork.optimizer_state_dict = optimizer.state_dict() save_hypernetwork(hypernetwork, checkpoint, hypernetwork_name, last_saved_file) + hypernetwork.optimizer_state_dict = None # dereference it after saving, to save memory. textual_inversion.write_loss(log_directory, "hypernetwork_loss.csv", hypernetwork.step, len(ds), { "loss": f"{previous_mean_loss:.7f}", @@ -530,8 +570,12 @@ Last saved image: {html.escape(last_saved_image)}
report_statistics(loss_dict) filename = os.path.join(shared.cmd_opts.hypernetwork_dir, f'{hypernetwork_name}.pt') + hypernetwork.optimizer_name = optimizer_name + if shared.opts.save_optimizer_state: + hypernetwork.optimizer_state_dict = optimizer.state_dict() save_hypernetwork(hypernetwork, checkpoint, hypernetwork_name, filename) - + del optimizer + hypernetwork.optimizer_state_dict = None # dereference it after saving, to save memory. return hypernetwork, filename def save_hypernetwork(hypernetwork, checkpoint, hypernetwork_name, filename): From f5d394214d6ee74a682d0a1016bcbebc4b43c13a Mon Sep 17 00:00:00 2001 From: aria1th <35677394+aria1th@users.noreply.github.com> Date: Fri, 4 Nov 2022 16:04:03 +0900 Subject: [PATCH 034/219] split before declaring file name --- modules/hypernetworks/hypernetwork.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/hypernetworks/hypernetwork.py b/modules/hypernetworks/hypernetwork.py index de8688a9..9b6a3e62 100644 --- a/modules/hypernetworks/hypernetwork.py +++ b/modules/hypernetworks/hypernetwork.py @@ -382,6 +382,7 @@ def train_hypernetwork(hypernetwork_name, learn_rate, batch_size, data_root, log shared.state.textinfo = "Initializing hypernetwork training..." shared.state.job_count = steps + hypernetwork_name = hypernetwork_name.rsplit('(', 1)[0] filename = os.path.join(shared.cmd_opts.hypernetwork_dir, f'{hypernetwork_name}.pt') log_directory = os.path.join(log_directory, datetime.datetime.now().strftime("%Y-%m-%d"), hypernetwork_name) @@ -393,7 +394,6 @@ def train_hypernetwork(hypernetwork_name, learn_rate, batch_size, data_root, log else: hypernetwork_dir = None - hypernetwork_name = hypernetwork_name.rsplit('(', 1)[0] if create_image_every > 0: images_dir = os.path.join(log_directory, "images") os.makedirs(images_dir, exist_ok=True) From 5f0117154382eb0e2547c72630256681673e353b Mon Sep 17 00:00:00 2001 From: AUTOMATIC <16777216c@gmail.com> Date: Fri, 4 Nov 2022 10:07:29 +0300 Subject: [PATCH 035/219] shut down gradio's "everything allowed" CORS policy; I checked the main functionality to work with this, but if this breaks some exotic workflow, I'm sorry. --- README.md | 7 ++++--- webui.py | 6 ++++++ 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 55c050d5..33508f31 100644 --- a/README.md +++ b/README.md @@ -155,14 +155,15 @@ The documentation was moved from this README over to the project's [wiki](https: - Swin2SR - https://github.com/mv-lab/swin2sr - LDSR - https://github.com/Hafiidz/latent-diffusion - Ideas for optimizations - https://github.com/basujindal/stable-diffusion -- Doggettx - Cross Attention layer optimization - https://github.com/Doggettx/stable-diffusion, original idea for prompt editing. -- InvokeAI, lstein - Cross Attention layer optimization - https://github.com/invoke-ai/InvokeAI (originally http://github.com/lstein/stable-diffusion) -- Rinon Gal - Textual Inversion - https://github.com/rinongal/textual_inversion (we're not using his code, but we are using his ideas). +- Cross Attention layer optimization - Doggettx - https://github.com/Doggettx/stable-diffusion, original idea for prompt editing. +- Cross Attention layer optimization - InvokeAI, lstein - https://github.com/invoke-ai/InvokeAI (originally http://github.com/lstein/stable-diffusion) +- Textual Inversion - Rinon Gal - https://github.com/rinongal/textual_inversion (we're not using his code, but we are using his ideas). - Idea for SD upscale - https://github.com/jquesnelle/txt2imghd - Noise generation for outpainting mk2 - https://github.com/parlance-zz/g-diffuser-bot - CLIP interrogator idea and borrowing some code - https://github.com/pharmapsychotic/clip-interrogator - Idea for Composable Diffusion - https://github.com/energy-based-model/Compositional-Visual-Generation-with-Composable-Diffusion-Models-PyTorch - xformers - https://github.com/facebookresearch/xformers - DeepDanbooru - interrogator for anime diffusers https://github.com/KichangKim/DeepDanbooru +- Security advice - RyotaK - Initial Gradio script - posted on 4chan by an Anonymous user. Thank you Anonymous user. - (You) diff --git a/webui.py b/webui.py index 3b21c071..81df09dd 100644 --- a/webui.py +++ b/webui.py @@ -141,6 +141,12 @@ def webui(): # after initial launch, disable --autolaunch for subsequent restarts cmd_opts.autolaunch = False + # gradio uses a very open CORS policy via app.user_middleware, which makes it possible for + # an attacker to trick the user into opening a malicious HTML page, which makes a request to the + # running web ui and do whatever the attcker wants, including installing an extension and + # runnnig its code. We disable this here. Suggested by RyotaK. + app.user_middleware = [x for x in app.user_middleware if x.cls.__name__ != 'CORSMiddleware'] + app.add_middleware(GZipMiddleware, minimum_size=1000) if launch_api: From 1ca0bcd3a7003dd2c1324de7d97fd2a6fc5ddc53 Mon Sep 17 00:00:00 2001 From: aria1th <35677394+aria1th@users.noreply.github.com> Date: Fri, 4 Nov 2022 16:09:19 +0900 Subject: [PATCH 036/219] only save if option is enabled --- modules/hypernetworks/hypernetwork.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/hypernetworks/hypernetwork.py b/modules/hypernetworks/hypernetwork.py index 9b6a3e62..b1f308e2 100644 --- a/modules/hypernetworks/hypernetwork.py +++ b/modules/hypernetworks/hypernetwork.py @@ -188,7 +188,7 @@ class Hypernetwork: optimizer_saved_dict['optimizer_name'] = self.optimizer_name torch.save(state_dict, filename) - if self.optimizer_state_dict: + if shared.opts.save_optimizer_state and self.optimizer_state_dict: optimizer_saved_dict['hash'] = sd_models.model_hash(filename) optimizer_saved_dict['optimizer_state_dict'] = self.optimizer_state_dict torch.save(optimizer_saved_dict, filename + '.optim') From ccf1a15412ef6b518f9f54cc26a0ee5edf458108 Mon Sep 17 00:00:00 2001 From: AUTOMATIC <16777216c@gmail.com> Date: Fri, 4 Nov 2022 10:16:19 +0300 Subject: [PATCH 037/219] add an option to enable installing extensions with --listen or --share --- modules/shared.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/modules/shared.py b/modules/shared.py index 024c771a..0a39cdf2 100644 --- a/modules/shared.py +++ b/modules/shared.py @@ -44,6 +44,7 @@ parser.add_argument("--precision", type=str, help="evaluate at this precision", parser.add_argument("--share", action='store_true', help="use share=True for gradio and make the UI accessible through their site") parser.add_argument("--ngrok", type=str, help="ngrok authtoken, alternative to gradio --share", default=None) parser.add_argument("--ngrok-region", type=str, help="The region in which ngrok should start.", default="us") +parser.add_argument("--enable-insecure-extension-access", action='store_true', help="enable extensions tab regardless of other options") parser.add_argument("--codeformer-models-path", type=str, help="Path to directory with codeformer model file(s).", default=os.path.join(models_path, 'Codeformer')) parser.add_argument("--gfpgan-models-path", type=str, help="Path to directory with GFPGAN model file(s).", default=os.path.join(models_path, 'GFPGAN')) parser.add_argument("--esrgan-models-path", type=str, help="Path to directory with ESRGAN model file(s).", default=os.path.join(models_path, 'ESRGAN')) @@ -99,7 +100,7 @@ restricted_opts = { "outdir_save", } -cmd_opts.disable_extension_access = cmd_opts.share or cmd_opts.listen +cmd_opts.disable_extension_access = (cmd_opts.share or cmd_opts.listen) and not cmd_opts.enable_insecure_extension_access devices.device, devices.device_interrogate, devices.device_gfpgan, devices.device_swinir, devices.device_esrgan, devices.device_scunet, devices.device_codeformer = \ (devices.cpu if any(y in cmd_opts.use_cpu for y in [x, 'all']) else devices.get_optimal_device() for x in ['sd', 'interrogate', 'gfpgan', 'swinir', 'esrgan', 'scunet', 'codeformer']) From 321e13ca176b256177c4a752d1f2bbee79b5532e Mon Sep 17 00:00:00 2001 From: AUTOMATIC <16777216c@gmail.com> Date: Fri, 4 Nov 2022 10:35:30 +0300 Subject: [PATCH 038/219] produce a readable error message when setting an option fails on the settings screen --- modules/ui.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/modules/ui.py b/modules/ui.py index 633b56ef..3ac7540c 100644 --- a/modules/ui.py +++ b/modules/ui.py @@ -1439,8 +1439,7 @@ def create_ui(wrap_gradio_gpu_call): changed = 0 for key, value, comp in zip(opts.data_labels.keys(), args, components): - if comp != dummy_component and not opts.same_type(value, opts.data_labels[key].default): - return f"Bad value for setting {key}: {value}; expecting {type(opts.data_labels[key].default).__name__}", opts.dumpjson() + assert comp == dummy_component or opts.same_type(value, opts.data_labels[key].default), f"Bad value for setting {key}: {value}; expecting {type(opts.data_labels[key].default).__name__}" for key, value, comp in zip(opts.data_labels.keys(), args, components): if comp == dummy_component: @@ -1458,7 +1457,7 @@ def create_ui(wrap_gradio_gpu_call): opts.save(shared.config_filename) - return f'{changed} settings changed.', opts.dumpjson() + return opts.dumpjson(), f'{changed} settings changed.' def run_settings_single(value, key): if not opts.same_type(value, opts.data_labels[key].default): @@ -1622,9 +1621,9 @@ def create_ui(wrap_gradio_gpu_call): text_settings = gr.Textbox(elem_id="settings_json", value=lambda: opts.dumpjson(), visible=False) settings_submit.click( - fn=run_settings, + fn=wrap_gradio_call(run_settings, extra_outputs=[gr.update()]), inputs=components, - outputs=[result, text_settings], + outputs=[text_settings, result], ) for i, k, item in quicksettings_list: From f674c488d9701e577e2aaf25e331fb44ada4f1ef Mon Sep 17 00:00:00 2001 From: AUTOMATIC <16777216c@gmail.com> Date: Fri, 4 Nov 2022 10:45:34 +0300 Subject: [PATCH 039/219] bugfix: save image for hires fix BEFORE upscaling latent space --- modules/processing.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/modules/processing.py b/modules/processing.py index a46e592d..7a2fc218 100644 --- a/modules/processing.py +++ b/modules/processing.py @@ -665,17 +665,17 @@ class StableDiffusionProcessingTxt2Img(StableDiffusionProcessing): images.save_image(image, self.outpath_samples, "", seeds[index], prompts[index], opts.samples_format, suffix="-before-highres-fix") if opts.use_scale_latent_for_hires_fix: + for i in range(samples.shape[0]): + save_intermediate(samples, i) + samples = torch.nn.functional.interpolate(samples, size=(self.height // opt_f, self.width // opt_f), mode="bilinear") - + # Avoid making the inpainting conditioning unless necessary as # this does need some extra compute to decode / encode the image again. if getattr(self, "inpainting_mask_weight", shared.opts.inpainting_mask_weight) < 1.0: image_conditioning = self.img2img_image_conditioning(decode_first_stage(self.sd_model, samples), samples) else: image_conditioning = self.txt2img_image_conditioning(samples) - - for i in range(samples.shape[0]): - save_intermediate(samples, i) else: decoded_samples = decode_first_stage(self.sd_model, samples) lowres_samples = torch.clamp((decoded_samples + 1.0) / 2.0, min=0.0, max=1.0) From 7278897982bfb640ee95f144c97ed25fb3f77ea3 Mon Sep 17 00:00:00 2001 From: AngelBottomless <35677394+aria1th@users.noreply.github.com> Date: Fri, 4 Nov 2022 17:12:28 +0900 Subject: [PATCH 040/219] Update shared.py --- modules/shared.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/shared.py b/modules/shared.py index 4d6e1c8b..6e7a02e0 100644 --- a/modules/shared.py +++ b/modules/shared.py @@ -309,7 +309,7 @@ options_templates.update(options_section(('system', "System"), { options_templates.update(options_section(('training', "Training"), { "unload_models_when_training": OptionInfo(False, "Move VAE and CLIP to RAM when training if possible. Saves VRAM."), - "save_optimizer_state": OptionInfo(False, "Saves Optimizer state with checkpoints. This will cause file size to increase VERY much."), + "save_optimizer_state": OptionInfo(False, "Saves Optimizer state as separate *.optim file. Training can be resumed with HN itself and matching optim file."), "dataset_filename_word_regex": OptionInfo("", "Filename word regex"), "dataset_filename_join_string": OptionInfo(" ", "Filename join string"), "training_image_repeats_per_epoch": OptionInfo(1, "Number of repeats for a single input image per epoch; used only for displaying epoch number", gr.Number, {"precision": 0}), From 99043f33606d3057f83ea52a403e10cd29d1f7e7 Mon Sep 17 00:00:00 2001 From: AUTOMATIC <16777216c@gmail.com> Date: Fri, 4 Nov 2022 11:20:42 +0300 Subject: [PATCH 041/219] fix one of previous merges breaking the program --- modules/sd_models.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/modules/sd_models.py b/modules/sd_models.py index 63e07a12..34c57bfa 100644 --- a/modules/sd_models.py +++ b/modules/sd_models.py @@ -167,6 +167,8 @@ def load_model_weights(model, checkpoint_info, vae_file="auto"): sd_vae.restore_base_vae(model) checkpoints_loaded[model.sd_checkpoint_info] = model.state_dict().copy() + vae_file = sd_vae.resolve_vae(checkpoint_file, vae_file=vae_file) + if checkpoint_info not in checkpoints_loaded: print(f"Loading weights [{sd_model_hash}] from {checkpoint_file}") From eeb07330131012c0294afb79165b90270679b9c7 Mon Sep 17 00:00:00 2001 From: AUTOMATIC <16777216c@gmail.com> Date: Fri, 4 Nov 2022 11:21:40 +0300 Subject: [PATCH 042/219] change process_one virtual function for script to process_batch, add extra args and docs --- modules/processing.py | 2 +- modules/scripts.py | 16 +++++++++++----- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/modules/processing.py b/modules/processing.py index e20d8fc4..03c9143d 100644 --- a/modules/processing.py +++ b/modules/processing.py @@ -502,7 +502,7 @@ def process_images_inner(p: StableDiffusionProcessing) -> Processed: break if p.scripts is not None: - p.scripts.process_one(p, n) + p.scripts.process_batch(p, batch_number=n, prompts=prompts, seeds=seeds, subseeds=subseeds) with devices.autocast(): uc = prompt_parser.get_learned_conditioning(shared.sd_model, len(prompts) * [p.negative_prompt], p.steps) diff --git a/modules/scripts.py b/modules/scripts.py index 75e47cd2..366c90d7 100644 --- a/modules/scripts.py +++ b/modules/scripts.py @@ -73,9 +73,15 @@ class Script: pass - def process_one(self, p, n, *args): + def process_batch(self, p, *args, **kwargs): """ - Same as process(), but called for every iteration + Same as process(), but called for every batch. + + **kwargs will have those items: + - batch_number - index of current batch, from 0 to number of batches-1 + - prompts - list of prompts for current batch; you can change contents of this list but changing the number of entries will likely break things + - seeds - list of seeds for current batch + - subseeds - list of subseeds for current batch """ pass @@ -303,13 +309,13 @@ class ScriptRunner: print(f"Error running process: {script.filename}", file=sys.stderr) print(traceback.format_exc(), file=sys.stderr) - def process_one(self, p, n): + def process_batch(self, p, **kwargs): for script in self.alwayson_scripts: try: script_args = p.script_args[script.args_from:script.args_to] - script.process_one(p, n, *script_args) + script.process_batch(p, *script_args, **kwargs) except Exception: - print(f"Error running process_one: {script.filename}", file=sys.stderr) + print(f"Error running process_batch: {script.filename}", file=sys.stderr) print(traceback.format_exc(), file=sys.stderr) def postprocess(self, p, processed): From db50a9ab6cac5d66513e828db96e4270a33f7803 Mon Sep 17 00:00:00 2001 From: Dynamic Date: Fri, 4 Nov 2022 18:12:27 +0900 Subject: [PATCH 043/219] Update ko_KR.json Added new strings/Revamped edited strings --- localizations/ko_KR.json | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/localizations/ko_KR.json b/localizations/ko_KR.json index 874771f9..29e10075 100644 --- a/localizations/ko_KR.json +++ b/localizations/ko_KR.json @@ -24,6 +24,7 @@ "Add model hash to generation information": "생성 정보에 모델 해시 추가", "Add model name to generation information": "생성 정보에 모델 이름 추가", "Add number to filename when saving": "이미지를 저장할 때 파일명에 숫자 추가하기", + "Adds a tab to the webui that allows the user to automatically extract keyframes from video, and manually extract 512x512 crops of those frames for use in model training.": "WebUI에 비디오로부터 자동으로 키프레임을 추출하고, 그 키프레임으로부터 모델 훈련에 사용될 512x512 이미지를 잘라낼 수 있는 탭을 추가합니다.", "Aesthetic Gradients": "스타일 그라디언트", "Aesthetic Image Scorer": "스타일 이미지 스코어러", "Aesthetic imgs embedding": "스타일 이미지 임베딩", @@ -260,6 +261,7 @@ "Keep -1 for seeds": "시드값 -1로 유지", "keep whatever was there originally": "이미지 원본 유지", "keyword": "프롬프트", + "Krita Plugin.": "Kirta 플러그인입니다.", "Label": "라벨", "Lanczos": "Lanczos", "Last prompt:": "마지막 프롬프트 : ", @@ -441,8 +443,8 @@ "See": "자세한 설명은", "Seed": "시드", "Seed of a different picture to be mixed into the generation.": "결과물에 섞일 다른 그림의 시드", - "Select activation function of hypernetwork": "하이퍼네트워크 활성화 함수 선택", - "Select Layer weights initialization. relu-like - Kaiming, sigmoid-like - Xavier is recommended": "레이어 가중치 초기화 방식 선택 - relu류 : Kaiming 추천, sigmoid류 : Xavier 추천", + "Select activation function of hypernetwork. Recommended : Swish / Linear(none)": "하이퍼네트워크 활성화 함수 선택 - 추천 : Swish / Linear(None)", + "Select Layer weights initialization. Recommended: Kaiming for relu-like, Xavier for sigmoid-like, Normal otherwise": "레이어 가중치 초기화 방식 선택 - relu류 : Kaiming 추천, sigmoid류 : Xavier 추천, 그 외 : Normal", "Select which Real-ESRGAN models to show in the web UI. (Requires restart)": "WebUI에 표시할 Real-ESRGAN 모델을 선택하십시오. (재시작 필요)", "Send seed when sending prompt or image to other interface": "다른 화면으로 프롬프트나 이미지를 보낼 때 시드도 함께 보내기", "Send to extras": "부가기능으로 전송", @@ -458,7 +460,7 @@ "should be 2 or lower.": "이 2 이하여야 합니다.", "Show generation progress in window title.": "창 타이틀에 생성 진행도 보여주기", "Show grid in results for web": "웹에서 결과창에 그리드 보여주기", - "Show image creation progress every N sampling steps. Set 0 to disable.": "N번째 샘플링 스텝마다 이미지 생성 과정 보이기 - 비활성화하려면 0으로 설정", + "Show image creation progress every N sampling steps. Set to 0 to disable. Set to -1 to show after completion of batch.": "N번째 샘플링 스텝마다 이미지 생성 과정 보이기 - 비활성화하려면 0으로 설정, 배치 생성 완료시 보이려면 -1로 설정", "Show images zoomed in by default in full page image viewer": "전체 페이지 이미지 뷰어에서 기본값으로 이미지 확대해서 보여주기", "Show previews of all images generated in a batch as a grid": "배치에서 생성된 모든 이미지의 미리보기를 그리드 형식으로 보여주기", "Show progressbar": "프로그레스 바 보이기", @@ -520,6 +522,7 @@ "Train Embedding": "임베딩 훈련", "Train Hypernetwork": "하이퍼네트워크 훈련", "Training": "훈련", + "training-picker": "훈련용 선택기", "txt2img": "텍스트→이미지", "txt2img history": "텍스트→이미지 기록", "uniform": "uniform", From 5359fd30f2c4f6a3d9c42a6b837f8188d459a1ec Mon Sep 17 00:00:00 2001 From: Sihan Wang <31711261+shwang95@users.noreply.github.com> Date: Fri, 4 Nov 2022 17:52:46 +0800 Subject: [PATCH 044/219] Rename confusing translation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit "Denoising strength" in UI was translated as "重绘幅度" while "denoising" in the X/Y plot is translated as "去噪", totally confusing. --- localizations/zh_CN.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/localizations/zh_CN.json b/localizations/zh_CN.json index 56c8980e..ff785fc0 100644 --- a/localizations/zh_CN.json +++ b/localizations/zh_CN.json @@ -109,7 +109,7 @@ "Sigma noise": "Sigma noise", "Eta": "Eta", "Clip skip": "Clip 跳过", - "Denoising": "去噪", + "Denoising": "重绘幅度", "Cond. Image Mask Weight": "图像调节屏蔽度", "X values": "X轴数值", "Y type": "Y轴类型", From 821e2b883dbb42a187bc37379175cd55b7cd7e81 Mon Sep 17 00:00:00 2001 From: TinkTheBoush Date: Fri, 4 Nov 2022 19:39:03 +0900 Subject: [PATCH 045/219] change option position to Training setting --- modules/hypernetworks/hypernetwork.py | 4 ++-- modules/shared.py | 1 + modules/textual_inversion/dataset.py | 5 ++--- modules/textual_inversion/textual_inversion.py | 4 ++-- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/modules/hypernetworks/hypernetwork.py b/modules/hypernetworks/hypernetwork.py index 7630fb81..a11e01d6 100644 --- a/modules/hypernetworks/hypernetwork.py +++ b/modules/hypernetworks/hypernetwork.py @@ -331,7 +331,7 @@ def report_statistics(loss_info:dict): -def train_hypernetwork(hypernetwork_name, learn_rate, batch_size, data_root, log_directory, training_width, training_height, steps, create_image_every, save_hypernetwork_every, template_file, preview_from_txt2img, shuffle_tags, preview_prompt, preview_negative_prompt, preview_steps, preview_sampler_index, preview_cfg_scale, preview_seed, preview_width, preview_height): +def train_hypernetwork(hypernetwork_name, learn_rate, batch_size, data_root, log_directory, training_width, training_height, steps, create_image_every, save_hypernetwork_every, template_file, preview_from_txt2img, preview_prompt, preview_negative_prompt, preview_steps, preview_sampler_index, preview_cfg_scale, preview_seed, preview_width, preview_height): # images allows training previews to have infotext. Importing it at the top causes a circular import problem. from modules import images @@ -376,7 +376,7 @@ def train_hypernetwork(hypernetwork_name, learn_rate, batch_size, data_root, log # dataset loading may take a while, so input validations and early returns should be done before this shared.state.textinfo = f"Preparing dataset from {html.escape(data_root)}..." with torch.autocast("cuda"): - ds = modules.textual_inversion.dataset.PersonalizedBase(data_root=data_root, width=training_width, height=training_height, repeats=shared.opts.training_image_repeats_per_epoch, placeholder_token=hypernetwork_name, shuffle_tags=shuffle_tags, model=shared.sd_model, device=devices.device, template_file=template_file, include_cond=True, batch_size=batch_size) + ds = modules.textual_inversion.dataset.PersonalizedBase(data_root=data_root, width=training_width, height=training_height, repeats=shared.opts.training_image_repeats_per_epoch, placeholder_token=hypernetwork_name, model=shared.sd_model, device=devices.device, template_file=template_file, include_cond=True, batch_size=batch_size) if unload: shared.sd_model.cond_stage_model.to(devices.cpu) diff --git a/modules/shared.py b/modules/shared.py index 1ccb269a..e1d9bdf1 100644 --- a/modules/shared.py +++ b/modules/shared.py @@ -290,6 +290,7 @@ options_templates.update(options_section(('system', "System"), { options_templates.update(options_section(('training', "Training"), { "unload_models_when_training": OptionInfo(False, "Move VAE and CLIP to RAM when training if possible. Saves VRAM."), + "shuffle_tags": OptionInfo(False, "Shuffleing tags by "," when create texts."), "dataset_filename_word_regex": OptionInfo("", "Filename word regex"), "dataset_filename_join_string": OptionInfo(" ", "Filename join string"), "training_image_repeats_per_epoch": OptionInfo(1, "Number of repeats for a single input image per epoch; used only for displaying epoch number", gr.Number, {"precision": 0}), diff --git a/modules/textual_inversion/dataset.py b/modules/textual_inversion/dataset.py index e9d97cc1..df278dc2 100644 --- a/modules/textual_inversion/dataset.py +++ b/modules/textual_inversion/dataset.py @@ -24,7 +24,7 @@ class DatasetEntry: class PersonalizedBase(Dataset): - def __init__(self, data_root, width, height, repeats, flip_p=0.5, placeholder_token="*", shuffle_tags=True, model=None, device=None, template_file=None, include_cond=False, batch_size=1): + def __init__(self, data_root, width, height, repeats, flip_p=0.5, placeholder_token="*", model=None, device=None, template_file=None, include_cond=False, batch_size=1): re_word = re.compile(shared.opts.dataset_filename_word_regex) if len(shared.opts.dataset_filename_word_regex) > 0 else None self.placeholder_token = placeholder_token @@ -33,7 +33,6 @@ class PersonalizedBase(Dataset): self.width = width self.height = height self.flip = transforms.RandomHorizontalFlip(p=flip_p) - self.shuffle_tags = shuffle_tags self.dataset = [] @@ -99,7 +98,7 @@ class PersonalizedBase(Dataset): def create_text(self, filename_text): text = random.choice(self.lines) text = text.replace("[name]", self.placeholder_token) - if self.tag_shuffle: + if shared.opts.shuffle_tags: tags = filename_text.split(',') random.shuffle(tags) text = text.replace("[filewords]", ','.join(tags)) diff --git a/modules/textual_inversion/textual_inversion.py b/modules/textual_inversion/textual_inversion.py index 82dde931..0aeb0459 100644 --- a/modules/textual_inversion/textual_inversion.py +++ b/modules/textual_inversion/textual_inversion.py @@ -224,7 +224,7 @@ def validate_train_inputs(model_name, learn_rate, batch_size, data_root, templat if save_model_every or create_image_every: assert log_directory, "Log directory is empty" -def train_embedding(embedding_name, learn_rate, batch_size, data_root, log_directory, training_width, training_height, steps, create_image_every, save_embedding_every, template_file, save_image_with_stored_embedding, preview_from_txt2img, shuffle_tags, preview_prompt, preview_negative_prompt, preview_steps, preview_sampler_index, preview_cfg_scale, preview_seed, preview_width, preview_height): +def train_embedding(embedding_name, learn_rate, batch_size, data_root, log_directory, training_width, training_height, steps, create_image_every, save_embedding_every, template_file, save_image_with_stored_embedding, preview_from_txt2img, preview_prompt, preview_negative_prompt, preview_steps, preview_sampler_index, preview_cfg_scale, preview_seed, preview_width, preview_height): save_embedding_every = save_embedding_every or 0 create_image_every = create_image_every or 0 validate_train_inputs(embedding_name, learn_rate, batch_size, data_root, template_file, steps, save_embedding_every, create_image_every, log_directory, name="embedding") @@ -272,7 +272,7 @@ def train_embedding(embedding_name, learn_rate, batch_size, data_root, log_direc # dataset loading may take a while, so input validations and early returns should be done before this shared.state.textinfo = f"Preparing dataset from {html.escape(data_root)}..." with torch.autocast("cuda"): - ds = modules.textual_inversion.dataset.PersonalizedBase(data_root=data_root, width=training_width, height=training_height, repeats=shared.opts.training_image_repeats_per_epoch, placeholder_token=embedding_name, shuffle_tags=shuffle_tags, model=shared.sd_model, device=devices.device, template_file=template_file, batch_size=batch_size) + ds = modules.textual_inversion.dataset.PersonalizedBase(data_root=data_root, width=training_width, height=training_height, repeats=shared.opts.training_image_repeats_per_epoch, placeholder_token=embedding_name, model=shared.sd_model, device=devices.device, template_file=template_file, batch_size=batch_size) if unload: shared.sd_model.first_stage_model.to(devices.cpu) From 45b65e87e0ef64b3e457f7d20c62d591cdcd0e7b Mon Sep 17 00:00:00 2001 From: TinkTheBoush Date: Fri, 4 Nov 2022 19:48:28 +0900 Subject: [PATCH 046/219] remove ui option --- modules/ui.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/modules/ui.py b/modules/ui.py index 6f3836c6..45cd8c3f 100644 --- a/modules/ui.py +++ b/modules/ui.py @@ -1269,7 +1269,6 @@ def create_ui(wrap_gradio_gpu_call): save_embedding_every = gr.Number(label='Save a copy of embedding to log directory every N steps, 0 to disable', value=500, precision=0) save_image_with_stored_embedding = gr.Checkbox(label='Save images with embedding in PNG chunks', value=True) preview_from_txt2img = gr.Checkbox(label='Read parameters (prompt, etc...) from txt2img tab when making previews', value=False) - shuffle_tags = gr.Checkbox(label='Shuffleing tags by "," when create texts', value=True) with gr.Row(): interrupt_training = gr.Button(value="Interrupt") @@ -1364,7 +1363,6 @@ def create_ui(wrap_gradio_gpu_call): template_file, save_image_with_stored_embedding, preview_from_txt2img, - shuffle_tags, *txt2img_preview_params, ], outputs=[ @@ -1389,7 +1387,6 @@ def create_ui(wrap_gradio_gpu_call): save_embedding_every, template_file, preview_from_txt2img, - shuffle_tags, *txt2img_preview_params, ], outputs=[ From fd62727893f9face287b0a9620251afaa38a627d Mon Sep 17 00:00:00 2001 From: Isaac Poulton Date: Fri, 4 Nov 2022 18:34:35 +0700 Subject: [PATCH 047/219] Sort hypernetworks --- modules/hypernetworks/hypernetwork.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/hypernetworks/hypernetwork.py b/modules/hypernetworks/hypernetwork.py index 6e1a10cf..f1f04a70 100644 --- a/modules/hypernetworks/hypernetwork.py +++ b/modules/hypernetworks/hypernetwork.py @@ -224,7 +224,7 @@ def list_hypernetworks(path): # Prevent a hypothetical "None.pt" from being listed. if name != "None": res[name] = filename - return res + return dict(sorted(res.items())) def load_hypernetwork(filename): From c3cd0d7a86f35a5bfc58fdc3ecfaf203c0aee06f Mon Sep 17 00:00:00 2001 From: DepFA <35278260+dfaker@users.noreply.github.com> Date: Fri, 4 Nov 2022 12:19:16 +0000 Subject: [PATCH 048/219] Should be one underscore for module privates not two --- modules/script_callbacks.py | 37 ++++++++++++++++++------------------- 1 file changed, 18 insertions(+), 19 deletions(-) diff --git a/modules/script_callbacks.py b/modules/script_callbacks.py index 4a7fb944..83da7ca4 100644 --- a/modules/script_callbacks.py +++ b/modules/script_callbacks.py @@ -46,7 +46,7 @@ class CFGDenoiserParams: ScriptCallback = namedtuple("ScriptCallback", ["script", "callback"]) -__callback_map = dict( +_callback_map = dict( callbacks_app_started=[], callbacks_model_loaded=[], callbacks_ui_tabs=[], @@ -58,11 +58,11 @@ __callback_map = dict( def clear_callbacks(): - for callback_list in __callback_map.values(): + for callback_list in _callback_map.values(): callback_list.clear() def app_started_callback(demo: Optional[Blocks], app: FastAPI): - for c in __callback_map['callbacks_app_started']: + for c in _callback_map['callbacks_app_started']: try: c.callback(demo, app) except Exception: @@ -70,7 +70,7 @@ def app_started_callback(demo: Optional[Blocks], app: FastAPI): def model_loaded_callback(sd_model): - for c in __callback_map['callbacks_model_loaded']: + for c in _callback_map['callbacks_model_loaded']: try: c.callback(sd_model) except Exception: @@ -80,7 +80,7 @@ def model_loaded_callback(sd_model): def ui_tabs_callback(): res = [] - for c in __callback_map['callbacks_ui_tabs']: + for c in _callback_map['callbacks_ui_tabs']: try: res += c.callback() or [] except Exception: @@ -90,7 +90,7 @@ def ui_tabs_callback(): def ui_settings_callback(): - for c in __callback_map['callbacks_ui_settings']: + for c in _callback_map['callbacks_ui_settings']: try: c.callback() except Exception: @@ -98,7 +98,7 @@ def ui_settings_callback(): def before_image_saved_callback(params: ImageSaveParams): - for c in __callback_map['callbacks_before_image_saved']: + for c in _callback_map['callbacks_before_image_saved']: try: c.callback(params) except Exception: @@ -106,7 +106,7 @@ def before_image_saved_callback(params: ImageSaveParams): def image_saved_callback(params: ImageSaveParams): - for c in __callback_map['callbacks_image_saved']: + for c in _callback_map['callbacks_image_saved']: try: c.callback(params) except Exception: @@ -114,7 +114,7 @@ def image_saved_callback(params: ImageSaveParams): def cfg_denoiser_callback(params: CFGDenoiserParams): - for c in __callback_map['callbacks_cfg_denoiser']: + for c in _callback_map['callbacks_cfg_denoiser']: try: c.callback(params) except Exception: @@ -133,13 +133,13 @@ def remove_current_script_callbacks(): filename = stack[0].filename if len(stack) > 0 else 'unknown file' if filename == 'unknown file': return - for callback_list in __callback_map.values(): + for callback_list in _callback_map.values(): for callback_to_remove in [cb for cb in callback_list if cb.script == filename]: callback_list.remove(callback_to_remove) def remove_callbacks_for_function(callback_func): - for callback_list in __callback_map.values(): + for callback_list in _callback_map.values(): for callback_to_remove in [cb for cb in callback_list if cb.callback == callback_func]: callback_list.remove(callback_to_remove) @@ -147,13 +147,13 @@ def remove_callbacks_for_function(callback_func): def on_app_started(callback): """register a function to be called when the webui started, the gradio `Block` component and fastapi `FastAPI` object are passed as the arguments""" - add_callback(__callback_map['callbacks_app_started'], callback) + add_callback(_callback_map['callbacks_app_started'], callback) def on_model_loaded(callback): """register a function to be called when the stable diffusion model is created; the model is passed as an argument""" - add_callback(__callback_map['callbacks_model_loaded'], callback) + add_callback(_callback_map['callbacks_model_loaded'], callback) def on_ui_tabs(callback): @@ -166,13 +166,13 @@ def on_ui_tabs(callback): title is tab text displayed to user in the UI elem_id is HTML id for the tab """ - add_callback(__callback_map['callbacks_ui_tabs'], callback) + add_callback(_callback_map['callbacks_ui_tabs'], callback) def on_ui_settings(callback): """register a function to be called before UI settings are populated; add your settings by using shared.opts.add_option(shared.OptionInfo(...)) """ - add_callback(__callback_map['callbacks_ui_settings'], callback) + add_callback(_callback_map['callbacks_ui_settings'], callback) def on_before_image_saved(callback): @@ -180,7 +180,7 @@ def on_before_image_saved(callback): The callback is called with one argument: - params: ImageSaveParams - parameters the image is to be saved with. You can change fields in this object. """ - add_callback(__callback_map['callbacks_before_image_saved'], callback) + add_callback(_callback_map['callbacks_before_image_saved'], callback) def on_image_saved(callback): @@ -188,7 +188,7 @@ def on_image_saved(callback): The callback is called with one argument: - params: ImageSaveParams - parameters the image was saved with. Changing fields in this object does nothing. """ - add_callback(__callback_map['callbacks_image_saved'], callback) + add_callback(_callback_map['callbacks_image_saved'], callback) def on_cfg_denoiser(callback): @@ -196,5 +196,4 @@ def on_cfg_denoiser(callback): The callback is called with one argument: - params: CFGDenoiserParams - parameters to be passed to the inner model and sampling state details. """ - add_callback(__callback_map['callbacks_cfg_denoiser'], callback) - + add_callback(_callback_map['callbacks_cfg_denoiser'], callback) From f316280ad3634a2343b086a6de0bfcd473e18599 Mon Sep 17 00:00:00 2001 From: AUTOMATIC <16777216c@gmail.com> Date: Fri, 4 Nov 2022 16:48:40 +0300 Subject: [PATCH 049/219] fix the error that prevents from setting some options --- modules/shared.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/modules/shared.py b/modules/shared.py index a9e28b9c..962115f6 100644 --- a/modules/shared.py +++ b/modules/shared.py @@ -406,7 +406,8 @@ class Options: if key in self.data or key in self.data_labels: assert not cmd_opts.freeze_settings, "changing settings is disabled" - comp_args = opts.data_labels[key].component_args + info = opts.data_labels.get(key, None) + comp_args = info.component_args if info else None if isinstance(comp_args, dict) and comp_args.get('visible', True) is False: raise RuntimeError(f"not possible to set {key} because it is restricted") From 116bcf730ade8d3ac5d76d04c5887b6bba000970 Mon Sep 17 00:00:00 2001 From: AUTOMATIC <16777216c@gmail.com> Date: Fri, 4 Nov 2022 16:48:46 +0300 Subject: [PATCH 050/219] disable setting options via API until it is fixed by the author --- modules/api/api.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/modules/api/api.py b/modules/api/api.py index a49f3755..8a7ab2f5 100644 --- a/modules/api/api.py +++ b/modules/api/api.py @@ -218,6 +218,10 @@ class Api: return options def set_config(self, req: OptionsModel): + # currently req has all options fields even if you send a dict like { "send_seed": false }, which means it will + # overwrite all options with default values. + raise RuntimeError('Setting options via API is not supported') + reqDict = vars(req) for o in reqDict: setattr(shared.opts, o, reqDict[o]) From 08feb4c364e8b2aed929fd7d22dfa21a93d78b2c Mon Sep 17 00:00:00 2001 From: Isaac Poulton Date: Fri, 4 Nov 2022 20:53:11 +0700 Subject: [PATCH 051/219] Sort straight out of the glob --- modules/hypernetworks/hypernetwork.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/hypernetworks/hypernetwork.py b/modules/hypernetworks/hypernetwork.py index f1f04a70..a441ab10 100644 --- a/modules/hypernetworks/hypernetwork.py +++ b/modules/hypernetworks/hypernetwork.py @@ -219,12 +219,12 @@ class Hypernetwork: def list_hypernetworks(path): res = {} - for filename in glob.iglob(os.path.join(path, '**/*.pt'), recursive=True): + for filename in sorted(glob.iglob(os.path.join(path, '**/*.pt'), recursive=True)): name = os.path.splitext(os.path.basename(filename))[0] # Prevent a hypothetical "None.pt" from being listed. if name != "None": res[name] = filename - return dict(sorted(res.items())) + return res def load_hypernetwork(filename): From 4a73d433b19741cacebac82987f49a15bea9913e Mon Sep 17 00:00:00 2001 From: benlisquare <116663807+benlisquare@users.noreply.github.com> Date: Sat, 5 Nov 2022 02:48:36 +1100 Subject: [PATCH 052/219] General fixes to Traditional Chinese (zh_TW) localisation JSON --- localizations/zh_TW.json | 54 ++++++++++++++++++++++++---------------- 1 file changed, 33 insertions(+), 21 deletions(-) diff --git a/localizations/zh_TW.json b/localizations/zh_TW.json index 4e6dac44..b818936b 100644 --- a/localizations/zh_TW.json +++ b/localizations/zh_TW.json @@ -7,7 +7,7 @@ "Loading...": "載入中…", "view": "檢視", "api": "api", - "•": "•", + "•": " • ", "built with gradio": "基於 Gradio 構建", "Stable Diffusion checkpoint": "Stable Diffusion 模型權重存檔點", "txt2img": "文生圖", @@ -70,12 +70,12 @@ "Variation strength": "差異強度", "Resize seed from width": "自寬度縮放隨機種子", "Resize seed from height": "自高度縮放隨機種子", - "Open for Clip Aesthetic!": "打開美術風格 Clip!", + "Open for Clip Aesthetic!": "打開以調整 Clip 的美術風格!", "▼": "▼", "Aesthetic weight": "美術風格權重", "Aesthetic steps": "美術風格疊代步數", "Aesthetic learning rate": "美術風格學習率", - "Slerp interpolation": "Slerp 插值", + "Slerp interpolation": "球麵線性插值角度", "Aesthetic imgs embedding": "美術風格圖集 embedding", "None": "無", "Aesthetic text for imgs": "該圖集的美術風格描述", @@ -105,15 +105,15 @@ "Prompt order": "提示詞順序", "Sampler": "採樣器", "Checkpoint name": "模型權重存檔點的名稱", - "Hypernetwork": "超網路", - "Hypernet str.": "超網路強度", + "Hypernetwork": "超網路(Hypernetwork)", + "Hypernet str.": "超網路(Hypernetwork)強度", "Sigma Churn": "Sigma Churn", "Sigma min": "最小 Sigma", "Sigma max": "最大 Sigma", "Sigma noise": "Sigma noise", "Eta": "Eta", "Clip skip": "Clip 跳過", - "Denoising": "去噪", + "Denoising": "重繪幅度", "Cond. Image Mask Weight": "圖像調節屏蔽度", "X values": "X軸數值", "Y type": "Y軸類型", @@ -189,6 +189,7 @@ "Tile overlap": "圖塊重疊的畫素", "Upscaler": "放大演算法", "Lanczos": "Lanczos", + "Nearest": "最鄰近(整數縮放)", "LDSR": "LDSR", "BSRGAN 4x": "BSRGAN 4x", "ESRGAN_4x": "ESRGAN_4x", @@ -230,15 +231,15 @@ "for detailed explanation.": "以了解詳細說明", "Create embedding": "生成 embedding", "Create aesthetic images embedding": "生成美術風格圖集 embedding", - "Create hypernetwork": "生成 hypernetwork", + "Create hypernetwork": "生成超網路(Hypernetwork)", "Preprocess images": "圖像預處理", "Name": "名稱", "Initialization text": "初始化文字", "Number of vectors per token": "每個 token 的向量數", "Overwrite Old Embedding": "覆寫舊的 Embedding", "Modules": "模組", - "Enter hypernetwork layer structure": "輸入 hypernetwork 層結構", - "Select activation function of hypernetwork": "選擇 hypernetwork 的激活函數", + "Enter hypernetwork layer structure": "輸入超網路(Hypernetwork)層結構", + "Select activation function of hypernetwork": "選擇超網路(Hypernetwork)的激活函數", "linear": "linear", "relu": "relu", "leakyrelu": "leakyrelu", @@ -276,7 +277,7 @@ "XavierNormal": "Xavier 正態", "Add layer normalization": "加入層標準化", "Use dropout": "採用 dropout 防止過擬合", - "Overwrite Old Hypernetwork": "覆寫舊的 Hypernetwork", + "Overwrite Old Hypernetwork": "覆寫舊的超網路(Hypernetwork)", "Source directory": "來源目錄", "Destination directory": "目標目錄", "Existing Caption txt Action": "對已有的TXT說明文字的行為", @@ -298,11 +299,11 @@ "Create debug image": "生成除錯圖片", "Preprocess": "預處理", "Train an embedding; must specify a directory with a set of 1:1 ratio images": "訓練 embedding; 必須指定一組具有 1:1 比例圖像的目錄", - "Train an embedding or Hypernetwork; you must specify a directory with a set of 1:1 ratio images": "訓練 embedding 或者 hypernetwork; 必須指定一組具有 1:1 比例圖像的目錄", - "[wiki]": "[wiki]", + "Train an embedding or Hypernetwork; you must specify a directory with a set of 1:1 ratio images": "訓練 embedding 或者超網路(Hypernetwork); 必須指定一組具有 1:1 比例圖像的目錄", + "[wiki]": "[wiki文件]", "Embedding": "Embedding", "Embedding Learning rate": "Embedding 學習率", - "Hypernetwork Learning rate": "Hypernetwork 學習率", + "Hypernetwork Learning rate": "超網路(Hypernetwork)學習率", "Learning rate": "學習率", "Dataset directory": "資料集目錄", "Log directory": "日誌目錄", @@ -312,7 +313,7 @@ "Save a copy of embedding to log directory every N steps, 0 to disable": "每 N 步將 embedding 的副本儲存到日誌目錄,0 表示禁用", "Save images with embedding in PNG chunks": "儲存圖像,並在 PNG 圖片檔案中嵌入 embedding 檔案", "Read parameters (prompt, etc...) from txt2img tab when making previews": "進行預覽時,從文生圖頁籤中讀取參數(提示詞等)", - "Train Hypernetwork": "訓練 Hypernetwork", + "Train Hypernetwork": "訓練超網路(Hypernetwork)", "Train Embedding": "訓練 Embedding", "Create an aesthetic embedding out of any number of images": "從任意數量的圖像中建立美術風格 embedding", "Create images embedding": "生成圖集 embedding", @@ -418,7 +419,7 @@ "Checkpoints to cache in RAM": "快取在內存(RAM)中的模型權重存檔點", "SD VAE": "模型的VAE", "auto": "自動", - "Hypernetwork strength": "Hypernetwork 強度", + "Hypernetwork strength": "超網路(Hypernetwork)強度", "Inpainting conditioning mask strength": "局部重繪時圖像調節的蒙版屏蔽強度", "Apply color correction to img2img results to match original colors.": "對圖生圖結果套用顏色校正以匹配原始顏色", "With img2img, do exactly the amount of steps the slider specifies (normally you'd do less with less denoising).": "在進行圖生圖的時候,確切地執行滑塊指定的疊代步數(正常情況下更弱的重繪幅度需要更少的疊代步數)", @@ -488,7 +489,17 @@ "Extension": "擴充", "URL": "網址", "Update": "更新", + "a1111-sd-webui-tagcomplete": "標記自動補全", "unknown": "未知", + "deforum-for-automatic1111-webui": "Deforum", + "sd-dynamic-prompting": "動態提示詞", + "stable-diffusion-webui-aesthetic-gradients": "美術風格梯度", + "stable-diffusion-webui-aesthetic-image-scorer": "美術風格評等", + "stable-diffusion-webui-artists-to-study": "藝術家圖庫", + "stable-diffusion-webui-dataset-tag-editor": "資料集標記編輯器", + "stable-diffusion-webui-images-browser": "圖庫瀏覽器", + "stable-diffusion-webui-inspiration": "靈感", + "stable-diffusion-webui-wildcards": "萬用字元", "Load from:": "載入自", "Extension index URL": "擴充清單連結", "URL for extension's git repository": "擴充的 git 倉庫連結", @@ -527,8 +538,8 @@ "What to put inside the masked area before processing it with Stable Diffusion.": "在使用 Stable Diffusion 處理蒙版區域之前要在蒙版區域內放置什麼", "fill it with colors of the image": "用圖像的顏色(高強度模糊)填充它", "keep whatever was there originally": "保留原來的圖像,不進行預處理", - "fill it with latent space noise": "用潛空間的噪聲填充它", - "fill it with latent space zeroes": "用潛空間的零填充它", + "fill it with latent space noise": "於潛空間填充噪聲", + "fill it with latent space zeroes": "於潛空間填零", "Upscale masked region to target resolution, do inpainting, downscale back and paste into original image": "將蒙版區域(包括預留畫素長度的緩衝區域)放大到目標解析度,進行局部重繪。\n然後縮小並粘貼回原始圖像中", "Resize image to target resolution. Unless height and width match, you will get incorrect aspect ratio.": "將圖像大小調整為目標解析度。除非高度和寬度匹配,否則你將獲得不正確的縱橫比", "Resize the image so that entirety of target resolution is filled with the image. Crop parts that stick out.": "調整圖像大小,使整個目標解析度都被圖像填充。裁剪多出來的部分", @@ -560,6 +571,8 @@ "Select which Real-ESRGAN models to show in the web UI. (Requires restart)": "選擇哪些 Real-ESRGAN 模型顯示在網頁使用者介面。(需要重新啟動)", "Allowed categories for random artists selection when using the Roll button": "使用抽選藝術家按鈕時將會隨機的藝術家類別", "Append commas": "附加逗號", + "latest": "最新", + "behind": "落後", "Roll three": "抽三位出來", "Generate forever": "無限生成", "Cancel generate forever": "停止無限生成", @@ -581,10 +594,9 @@ "Start drawing": "開始繪製", "Description": "描述", "Action": "行動", - "Aesthetic Gradients": "美術風格", - "aesthetic-gradients": "美術風格", - "stable-diffusion-webui-wildcards": "萬用字元", - "Dynamic Prompts": "動態提示", + "Aesthetic Gradients": "美術風格梯度", + "aesthetic-gradients": "美術風格梯度", + "Dynamic Prompts": "動態提示詞", "images-browser": "圖庫瀏覽器", "Inspiration": "靈感", "Deforum": "Deforum", From 5844ef8a9a165e0f456a4658bda830282cf5a55e Mon Sep 17 00:00:00 2001 From: DepFA <35278260+dfaker@users.noreply.github.com> Date: Fri, 4 Nov 2022 16:02:25 +0000 Subject: [PATCH 053/219] remove private underscore indicator --- modules/script_callbacks.py | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/modules/script_callbacks.py b/modules/script_callbacks.py index 83da7ca4..74dfb880 100644 --- a/modules/script_callbacks.py +++ b/modules/script_callbacks.py @@ -46,7 +46,7 @@ class CFGDenoiserParams: ScriptCallback = namedtuple("ScriptCallback", ["script", "callback"]) -_callback_map = dict( +callback_map = dict( callbacks_app_started=[], callbacks_model_loaded=[], callbacks_ui_tabs=[], @@ -58,11 +58,11 @@ _callback_map = dict( def clear_callbacks(): - for callback_list in _callback_map.values(): + for callback_list in callback_map.values(): callback_list.clear() def app_started_callback(demo: Optional[Blocks], app: FastAPI): - for c in _callback_map['callbacks_app_started']: + for c in callback_map['callbacks_app_started']: try: c.callback(demo, app) except Exception: @@ -70,7 +70,7 @@ def app_started_callback(demo: Optional[Blocks], app: FastAPI): def model_loaded_callback(sd_model): - for c in _callback_map['callbacks_model_loaded']: + for c in callback_map['callbacks_model_loaded']: try: c.callback(sd_model) except Exception: @@ -80,7 +80,7 @@ def model_loaded_callback(sd_model): def ui_tabs_callback(): res = [] - for c in _callback_map['callbacks_ui_tabs']: + for c in callback_map['callbacks_ui_tabs']: try: res += c.callback() or [] except Exception: @@ -90,7 +90,7 @@ def ui_tabs_callback(): def ui_settings_callback(): - for c in _callback_map['callbacks_ui_settings']: + for c in callback_map['callbacks_ui_settings']: try: c.callback() except Exception: @@ -98,7 +98,7 @@ def ui_settings_callback(): def before_image_saved_callback(params: ImageSaveParams): - for c in _callback_map['callbacks_before_image_saved']: + for c in callback_map['callbacks_before_image_saved']: try: c.callback(params) except Exception: @@ -106,7 +106,7 @@ def before_image_saved_callback(params: ImageSaveParams): def image_saved_callback(params: ImageSaveParams): - for c in _callback_map['callbacks_image_saved']: + for c in callback_map['callbacks_image_saved']: try: c.callback(params) except Exception: @@ -114,7 +114,7 @@ def image_saved_callback(params: ImageSaveParams): def cfg_denoiser_callback(params: CFGDenoiserParams): - for c in _callback_map['callbacks_cfg_denoiser']: + for c in callback_map['callbacks_cfg_denoiser']: try: c.callback(params) except Exception: @@ -133,13 +133,13 @@ def remove_current_script_callbacks(): filename = stack[0].filename if len(stack) > 0 else 'unknown file' if filename == 'unknown file': return - for callback_list in _callback_map.values(): + for callback_list in callback_map.values(): for callback_to_remove in [cb for cb in callback_list if cb.script == filename]: callback_list.remove(callback_to_remove) def remove_callbacks_for_function(callback_func): - for callback_list in _callback_map.values(): + for callback_list in callback_map.values(): for callback_to_remove in [cb for cb in callback_list if cb.callback == callback_func]: callback_list.remove(callback_to_remove) @@ -147,13 +147,13 @@ def remove_callbacks_for_function(callback_func): def on_app_started(callback): """register a function to be called when the webui started, the gradio `Block` component and fastapi `FastAPI` object are passed as the arguments""" - add_callback(_callback_map['callbacks_app_started'], callback) + add_callback(callback_map['callbacks_app_started'], callback) def on_model_loaded(callback): """register a function to be called when the stable diffusion model is created; the model is passed as an argument""" - add_callback(_callback_map['callbacks_model_loaded'], callback) + add_callback(callback_map['callbacks_model_loaded'], callback) def on_ui_tabs(callback): @@ -166,13 +166,13 @@ def on_ui_tabs(callback): title is tab text displayed to user in the UI elem_id is HTML id for the tab """ - add_callback(_callback_map['callbacks_ui_tabs'], callback) + add_callback(callback_map['callbacks_ui_tabs'], callback) def on_ui_settings(callback): """register a function to be called before UI settings are populated; add your settings by using shared.opts.add_option(shared.OptionInfo(...)) """ - add_callback(_callback_map['callbacks_ui_settings'], callback) + add_callback(callback_map['callbacks_ui_settings'], callback) def on_before_image_saved(callback): @@ -180,7 +180,7 @@ def on_before_image_saved(callback): The callback is called with one argument: - params: ImageSaveParams - parameters the image is to be saved with. You can change fields in this object. """ - add_callback(_callback_map['callbacks_before_image_saved'], callback) + add_callback(callback_map['callbacks_before_image_saved'], callback) def on_image_saved(callback): @@ -188,7 +188,7 @@ def on_image_saved(callback): The callback is called with one argument: - params: ImageSaveParams - parameters the image was saved with. Changing fields in this object does nothing. """ - add_callback(_callback_map['callbacks_image_saved'], callback) + add_callback(callback_map['callbacks_image_saved'], callback) def on_cfg_denoiser(callback): @@ -196,4 +196,4 @@ def on_cfg_denoiser(callback): The callback is called with one argument: - params: CFGDenoiserParams - parameters to be passed to the inner model and sampling state details. """ - add_callback(_callback_map['callbacks_cfg_denoiser'], callback) + add_callback(callback_map['callbacks_cfg_denoiser'], callback) From d469186fb051aa8ae0c868d1b1e3e11b0c846312 Mon Sep 17 00:00:00 2001 From: benlisquare <116663807+benlisquare@users.noreply.github.com> Date: Sat, 5 Nov 2022 03:42:50 +1100 Subject: [PATCH 054/219] Minor fix to Traditional Chinese (zh_TW) JSON --- localizations/zh_TW.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/localizations/zh_TW.json b/localizations/zh_TW.json index b818936b..04bde864 100644 --- a/localizations/zh_TW.json +++ b/localizations/zh_TW.json @@ -75,7 +75,7 @@ "Aesthetic weight": "美術風格權重", "Aesthetic steps": "美術風格疊代步數", "Aesthetic learning rate": "美術風格學習率", - "Slerp interpolation": "球麵線性插值角度", + "Slerp interpolation": "球面線性插值角度", "Aesthetic imgs embedding": "美術風格圖集 embedding", "None": "無", "Aesthetic text for imgs": "該圖集的美術風格描述", From 0d7e01d9950e013784c4b77c05aa7583ea69edc8 Mon Sep 17 00:00:00 2001 From: innovaciones Date: Fri, 4 Nov 2022 12:14:32 -0600 Subject: [PATCH 055/219] Open extensions links in new tab Fixed for "Available" tab --- modules/ui_extensions.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/ui_extensions.py b/modules/ui_extensions.py index a81de9a7..8e0d41d5 100644 --- a/modules/ui_extensions.py +++ b/modules/ui_extensions.py @@ -188,7 +188,7 @@ def refresh_available_extensions_from_data(): code += f""" - {html.escape(name)} + {html.escape(name)} {html.escape(description)} {install_code} From b8435e632f7ba0da12a2c8e9c788dda519279d24 Mon Sep 17 00:00:00 2001 From: evshiron Date: Sat, 5 Nov 2022 02:36:47 +0800 Subject: [PATCH 056/219] add --cors-allow-origins cmd opt --- modules/shared.py | 7 ++++--- webui.py | 9 +++++++++ 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/modules/shared.py b/modules/shared.py index a9e28b9c..e83cbcdf 100644 --- a/modules/shared.py +++ b/modules/shared.py @@ -86,6 +86,7 @@ parser.add_argument("--nowebui", action='store_true', help="use api=True to laun parser.add_argument("--ui-debug-mode", action='store_true', help="Don't load model to quickly launch UI") parser.add_argument("--device-id", type=str, help="Select the default CUDA device to use (export CUDA_VISIBLE_DEVICES=0,1,etc might be needed before)", default=None) parser.add_argument("--administrator", action='store_true', help="Administrator rights", default=False) +parser.add_argument("--cors-allow-origins", type=str, help="Allowed CORS origins", default=None) cmd_opts = parser.parse_args() restricted_opts = { @@ -147,9 +148,9 @@ class State: self.interrupted = True def nextjob(self): - if opts.show_progress_every_n_steps == -1: + if opts.show_progress_every_n_steps == -1: self.do_set_current_image() - + self.job_no += 1 self.sampling_step = 0 self.current_image_sampling_step = 0 @@ -198,7 +199,7 @@ class State: return if self.current_latent is None: return - + if opts.show_progress_grid: self.current_image = sd_samplers.samples_to_image_grid(self.current_latent) else: diff --git a/webui.py b/webui.py index 81df09dd..3788af0b 100644 --- a/webui.py +++ b/webui.py @@ -5,6 +5,7 @@ import importlib import signal import threading from fastapi import FastAPI +from fastapi.middleware.cors import CORSMiddleware from fastapi.middleware.gzip import GZipMiddleware from modules.paths import script_path @@ -93,6 +94,11 @@ def initialize(): signal.signal(signal.SIGINT, sigint_handler) +def setup_cors(app): + if cmd_opts.cors_allow_origins: + app.add_middleware(CORSMiddleware, allow_origins=cmd_opts.cors_allow_origins.split(','), allow_methods=['*']) + + def create_api(app): from modules.api.api import Api api = Api(app, queue_lock) @@ -114,6 +120,7 @@ def api_only(): initialize() app = FastAPI() + setup_cors(app) app.add_middleware(GZipMiddleware, minimum_size=1000) api = create_api(app) @@ -147,6 +154,8 @@ def webui(): # runnnig its code. We disable this here. Suggested by RyotaK. app.user_middleware = [x for x in app.user_middleware if x.cls.__name__ != 'CORSMiddleware'] + setup_cors(app) + app.add_middleware(GZipMiddleware, minimum_size=1000) if launch_api: From 467d8b967b5d1b1984ab113bec3fff217736e7ac Mon Sep 17 00:00:00 2001 From: AngelBottomless <35677394+aria1th@users.noreply.github.com> Date: Sat, 5 Nov 2022 04:24:42 +0900 Subject: [PATCH 057/219] Fix errors from commit f2b697 with --hide-ui-dir-config https://github.com/AUTOMATIC1111/stable-diffusion-webui/commit/f2b69709eaff88fc3a2bd49585556ec0883bf5ea --- modules/ui.py | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/modules/ui.py b/modules/ui.py index 4c2829af..76ca9b07 100644 --- a/modules/ui.py +++ b/modules/ui.py @@ -1446,17 +1446,19 @@ def create_ui(wrap_gradio_gpu_call): continue oldval = opts.data.get(key, None) - - setattr(opts, key, value) - + try: + setattr(opts, key, value) + except RuntimeError: + continue if oldval != value: if opts.data_labels[key].onchange is not None: opts.data_labels[key].onchange() changed += 1 - - opts.save(shared.config_filename) - + try: + opts.save(shared.config_filename) + except RuntimeError: + return opts.dumpjson(), f'{changed} settings changed without save.' return opts.dumpjson(), f'{changed} settings changed.' def run_settings_single(value, key): From 30b1bcc64e67ad50c5d3af3a6fe1bd1e9553f34e Mon Sep 17 00:00:00 2001 From: AUTOMATIC <16777216c@gmail.com> Date: Fri, 4 Nov 2022 22:56:18 +0300 Subject: [PATCH 058/219] fix upscale loop erroneously applied multiple times --- modules/upscaler.py | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/modules/upscaler.py b/modules/upscaler.py index 83fde7ca..c4e6e6bd 100644 --- a/modules/upscaler.py +++ b/modules/upscaler.py @@ -57,10 +57,18 @@ class Upscaler: self.scale = scale dest_w = img.width * scale dest_h = img.height * scale + for i in range(3): - if img.width > dest_w and img.height > dest_h: - break + shape = (img.width, img.height) + img = self.do_upscale(img, selected_model) + + if shape == (img.width, img.height): + break + + if img.width >= dest_w and img.height >= dest_h: + break + if img.width != dest_w or img.height != dest_h: img = img.resize((int(dest_w), int(dest_h)), resample=LANCZOS) From c0f7dbda3361daaa3e315e747fe5bebb75ea55d0 Mon Sep 17 00:00:00 2001 From: hentailord85ez <112723046+hentailord85ez@users.noreply.github.com> Date: Fri, 4 Nov 2022 23:01:58 +0000 Subject: [PATCH 059/219] Update k-diffusion to release 0.0.10 --- launch.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/launch.py b/launch.py index 2a51f20e..5fa11560 100644 --- a/launch.py +++ b/launch.py @@ -142,7 +142,7 @@ def prepare_enviroment(): stable_diffusion_commit_hash = os.environ.get('STABLE_DIFFUSION_COMMIT_HASH', "69ae4b35e0a0f6ee1af8bb9a5d0016ccb27e36dc") taming_transformers_commit_hash = os.environ.get('TAMING_TRANSFORMERS_COMMIT_HASH', "24268930bf1dce879235a7fddd0b2355b84d7ea6") - k_diffusion_commit_hash = os.environ.get('K_DIFFUSION_COMMIT_HASH', "f4e99857772fc3a126ba886aadf795a332774878") + k_diffusion_commit_hash = os.environ.get('K_DIFFUSION_COMMIT_HASH', "60e5042ca0da89c14d1dd59d73883280f8fce991") codeformer_commit_hash = os.environ.get('CODEFORMER_COMMIT_HASH', "c5b4593074ba6214284d6acd5f1719b6c5d739af") blip_commit_hash = os.environ.get('BLIP_COMMIT_HASH', "48211a1594f1321b00f14c9f7a5b4813144b2fb9") From 6008c0773ea575353f9b87da8a58454e20cc7857 Mon Sep 17 00:00:00 2001 From: hentailord85ez <112723046+hentailord85ez@users.noreply.github.com> Date: Fri, 4 Nov 2022 23:03:05 +0000 Subject: [PATCH 060/219] Add support for new DPM-Solver++ samplers --- modules/sd_samplers.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/modules/sd_samplers.py b/modules/sd_samplers.py index c7c414ef..7ece6556 100644 --- a/modules/sd_samplers.py +++ b/modules/sd_samplers.py @@ -29,6 +29,10 @@ samplers_k_diffusion = [ ('LMS Karras', 'sample_lms', ['k_lms_ka'], {'scheduler': 'karras'}), ('DPM2 Karras', 'sample_dpm_2', ['k_dpm_2_ka'], {'scheduler': 'karras'}), ('DPM2 a Karras', 'sample_dpm_2_ancestral', ['k_dpm_2_a_ka'], {'scheduler': 'karras'}), + ('DPM-Solver++(2S) a', 'sample_dpmpp_2s_ancestral', ['k_dpmpp_2s_a'], {}), + ('DPM-Solver++(2M)', 'sample_dpmpp_2m', ['k_dpmpp_2m'], {}), + ('DPM-Solver++(2S) Karras', 'sample_dpmpp_2s_ancestral', ['k_dpmpp_2s_a_ka'], {'scheduler': 'karras'}), + ('DPM-Solver++(2M) Karras', 'sample_dpmpp_2m', ['k_dpmpp_2m_ka'], {'scheduler': 'karras'}), ] samplers_data_k_diffusion = [ From f92dc505a013af9e385c7edbdf97539be62503d6 Mon Sep 17 00:00:00 2001 From: hentailord85ez <112723046+hentailord85ez@users.noreply.github.com> Date: Fri, 4 Nov 2022 23:12:48 +0000 Subject: [PATCH 061/219] Fix name --- modules/sd_samplers.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/sd_samplers.py b/modules/sd_samplers.py index 7ece6556..b28a2e4c 100644 --- a/modules/sd_samplers.py +++ b/modules/sd_samplers.py @@ -31,7 +31,7 @@ samplers_k_diffusion = [ ('DPM2 a Karras', 'sample_dpm_2_ancestral', ['k_dpm_2_a_ka'], {'scheduler': 'karras'}), ('DPM-Solver++(2S) a', 'sample_dpmpp_2s_ancestral', ['k_dpmpp_2s_a'], {}), ('DPM-Solver++(2M)', 'sample_dpmpp_2m', ['k_dpmpp_2m'], {}), - ('DPM-Solver++(2S) Karras', 'sample_dpmpp_2s_ancestral', ['k_dpmpp_2s_a_ka'], {'scheduler': 'karras'}), + ('DPM-Solver++(2S) a Karras', 'sample_dpmpp_2s_ancestral', ['k_dpmpp_2s_a_ka'], {'scheduler': 'karras'}), ('DPM-Solver++(2M) Karras', 'sample_dpmpp_2m', ['k_dpmpp_2m_ka'], {'scheduler': 'karras'}), ] From 1b6c2fc749e12f12bbee4705e65f217d23fa9072 Mon Sep 17 00:00:00 2001 From: hentailord85ez <112723046+hentailord85ez@users.noreply.github.com> Date: Fri, 4 Nov 2022 23:28:13 +0000 Subject: [PATCH 062/219] Reorder samplers --- modules/sd_samplers.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/sd_samplers.py b/modules/sd_samplers.py index b28a2e4c..1e88f7ee 100644 --- a/modules/sd_samplers.py +++ b/modules/sd_samplers.py @@ -24,13 +24,13 @@ samplers_k_diffusion = [ ('Heun', 'sample_heun', ['k_heun'], {}), ('DPM2', 'sample_dpm_2', ['k_dpm_2'], {}), ('DPM2 a', 'sample_dpm_2_ancestral', ['k_dpm_2_a'], {}), + ('DPM-Solver++(2S) a', 'sample_dpmpp_2s_ancestral', ['k_dpmpp_2s_a'], {}), + ('DPM-Solver++(2M)', 'sample_dpmpp_2m', ['k_dpmpp_2m'], {}), ('DPM fast', 'sample_dpm_fast', ['k_dpm_fast'], {}), ('DPM adaptive', 'sample_dpm_adaptive', ['k_dpm_ad'], {}), ('LMS Karras', 'sample_lms', ['k_lms_ka'], {'scheduler': 'karras'}), ('DPM2 Karras', 'sample_dpm_2', ['k_dpm_2_ka'], {'scheduler': 'karras'}), ('DPM2 a Karras', 'sample_dpm_2_ancestral', ['k_dpm_2_a_ka'], {'scheduler': 'karras'}), - ('DPM-Solver++(2S) a', 'sample_dpmpp_2s_ancestral', ['k_dpmpp_2s_a'], {}), - ('DPM-Solver++(2M)', 'sample_dpmpp_2m', ['k_dpmpp_2m'], {}), ('DPM-Solver++(2S) a Karras', 'sample_dpmpp_2s_ancestral', ['k_dpmpp_2s_a_ka'], {'scheduler': 'karras'}), ('DPM-Solver++(2M) Karras', 'sample_dpmpp_2m', ['k_dpmpp_2m_ka'], {'scheduler': 'karras'}), ] From ebce0c57c78a3f22178e3a38938d19ec0dfb703d Mon Sep 17 00:00:00 2001 From: Billy Cao Date: Sat, 5 Nov 2022 11:38:24 +0800 Subject: [PATCH 063/219] Use typing.Optional instead of | to add support for Python 3.9 and below. --- modules/api/models.py | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/modules/api/models.py b/modules/api/models.py index 2ae75f43..a44c5ddd 100644 --- a/modules/api/models.py +++ b/modules/api/models.py @@ -1,6 +1,6 @@ import inspect from pydantic import BaseModel, Field, create_model -from typing import Any, Optional, Union +from typing import Any, Optional from typing_extensions import Literal from inflection import underscore from modules.processing import StableDiffusionProcessingTxt2Img, StableDiffusionProcessingImg2Img @@ -185,22 +185,22 @@ _options = vars(parser)['_option_string_actions'] for key in _options: if(_options[key].dest != 'help'): flag = _options[key] - _type = str - if(_options[key].default != None): _type = type(_options[key].default) + _type = str + if _options[key].default is not None: _type = type(_options[key].default) flags.update({flag.dest: (_type,Field(default=flag.default, description=flag.help))}) FlagsModel = create_model("Flags", **flags) class SamplerItem(BaseModel): name: str = Field(title="Name") - aliases: list[str] = Field(title="Aliases") + aliases: list[str] = Field(title="Aliases") options: dict[str, str] = Field(title="Options") class UpscalerItem(BaseModel): name: str = Field(title="Name") - model_name: str | None = Field(title="Model Name") - model_path: str | None = Field(title="Path") - model_url: str | None = Field(title="URL") + model_name: Optional[str] = Field(title="Model Name") + model_path: Optional[str] = Field(title="Path") + model_url: Optional[str] = Field(title="URL") class SDModelItem(BaseModel): title: str = Field(title="Title") @@ -211,21 +211,21 @@ class SDModelItem(BaseModel): class HypernetworkItem(BaseModel): name: str = Field(title="Name") - path: str | None = Field(title="Path") + path: Optional[str] = Field(title="Path") class FaceRestorerItem(BaseModel): name: str = Field(title="Name") - cmd_dir: str | None = Field(title="Path") + cmd_dir: Optional[str] = Field(title="Path") class RealesrganItem(BaseModel): name: str = Field(title="Name") - path: str | None = Field(title="Path") - scale: int | None = Field(title="Scale") + path: Optional[str] = Field(title="Path") + scale: Optional[int] = Field(title="Scale") class PromptStyleItem(BaseModel): name: str = Field(title="Name") - prompt: str | None = Field(title="Prompt") - negative_prompt: str | None = Field(title="Negative Prompt") + prompt: Optional[str] = Field(title="Prompt") + negative_prompt: Optional[str] = Field(title="Negative Prompt") class ArtistItem(BaseModel): name: str = Field(title="Name") From e9a5562b9b27a1a4f9c282637b111cefd9727a41 Mon Sep 17 00:00:00 2001 From: papuSpartan Date: Sat, 5 Nov 2022 04:06:51 -0500 Subject: [PATCH 064/219] add support for tls (gradio tls options) --- modules/shared.py | 3 +++ webui.py | 22 ++++++++++++++++++++-- 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/modules/shared.py b/modules/shared.py index 962115f6..7a20c3af 100644 --- a/modules/shared.py +++ b/modules/shared.py @@ -86,6 +86,9 @@ parser.add_argument("--nowebui", action='store_true', help="use api=True to laun parser.add_argument("--ui-debug-mode", action='store_true', help="Don't load model to quickly launch UI") parser.add_argument("--device-id", type=str, help="Select the default CUDA device to use (export CUDA_VISIBLE_DEVICES=0,1,etc might be needed before)", default=None) parser.add_argument("--administrator", action='store_true', help="Administrator rights", default=False) +parser.add_argument("--tls-keyfile", type=str, help="Partially enables TLS, requires --tls-certfile to fully function", default=None) +parser.add_argument("--tls-certfile", type=str, help="Partially enables TLS, requires --tls-keyfile to fully function", default=None) +parser.add_argument("--server-name", type=str, help="Sets hostname of server", default=None) cmd_opts = parser.parse_args() restricted_opts = { diff --git a/webui.py b/webui.py index 81df09dd..d366f4ca 100644 --- a/webui.py +++ b/webui.py @@ -34,7 +34,7 @@ from modules.shared import cmd_opts import modules.hypernetworks.hypernetwork queue_lock = threading.Lock() - +server_name = "0.0.0.0" if cmd_opts.listen else cmd_opts.server_name def wrap_queued_call(func): def f(*args, **kwargs): @@ -85,6 +85,22 @@ def initialize(): shared.opts.onchange("sd_hypernetwork", wrap_queued_call(lambda: modules.hypernetworks.hypernetwork.load_hypernetwork(shared.opts.sd_hypernetwork))) shared.opts.onchange("sd_hypernetwork_strength", modules.hypernetworks.hypernetwork.apply_strength) + if cmd_opts.tls_keyfile is not None and cmd_opts.tls_keyfile is not None: + + try: + if not os.path.exists(cmd_opts.tls_keyfile): + print("Invalid path to TLS keyfile given") + if not os.path.exists(cmd_opts.tls_certfile): + print(f"Invalid path to TLS certfile: '{cmd_opts.tls_certfile}'") + except TypeError: + cmd_opts.tls_keyfile = cmd_opts.tls_certfile = None + print(f"path: '{cmd_opts.tls_keyfile}' {type(cmd_opts.tls_keyfile)}") + print(f"path: '{cmd_opts.tls_certfile}' {type(cmd_opts.tls_certfile)}") + print("TLS setup invalid, running webui without TLS") + else: + print("Running with TLS") + + # make the program just exit at ctrl+c without waiting for anything def sigint_handler(sig, frame): print(f'Interrupted with signal {sig} in {frame}') @@ -131,8 +147,10 @@ def webui(): app, local_url, share_url = demo.launch( share=cmd_opts.share, - server_name="0.0.0.0" if cmd_opts.listen else None, + server_name=server_name, server_port=cmd_opts.port, + ssl_keyfile=cmd_opts.tls_keyfile, + ssl_certfile=cmd_opts.tls_certfile, debug=cmd_opts.gradio_debug, auth=[tuple(cred.split(':')) for cred in cmd_opts.gradio_auth.strip('"').split(',')] if cmd_opts.gradio_auth else None, inbrowser=cmd_opts.autolaunch, From a02bad570ef7718436369bb4e4aa5b8e0f1f5689 Mon Sep 17 00:00:00 2001 From: papuSpartan Date: Sat, 5 Nov 2022 04:14:21 -0500 Subject: [PATCH 065/219] rm dbg --- webui.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/webui.py b/webui.py index d366f4ca..222dbeee 100644 --- a/webui.py +++ b/webui.py @@ -94,8 +94,6 @@ def initialize(): print(f"Invalid path to TLS certfile: '{cmd_opts.tls_certfile}'") except TypeError: cmd_opts.tls_keyfile = cmd_opts.tls_certfile = None - print(f"path: '{cmd_opts.tls_keyfile}' {type(cmd_opts.tls_keyfile)}") - print(f"path: '{cmd_opts.tls_certfile}' {type(cmd_opts.tls_certfile)}") print("TLS setup invalid, running webui without TLS") else: print("Running with TLS") From 03b08c4a6b0609f24ec789d40100529b92ef0612 Mon Sep 17 00:00:00 2001 From: AUTOMATIC <16777216c@gmail.com> Date: Sat, 5 Nov 2022 15:04:48 +0300 Subject: [PATCH 066/219] do not die when an extension's repo has no remote --- modules/extensions.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/modules/extensions.py b/modules/extensions.py index 897af96e..8e0977fd 100644 --- a/modules/extensions.py +++ b/modules/extensions.py @@ -34,8 +34,11 @@ class Extension: if repo is None or repo.bare: self.remote = None else: - self.remote = next(repo.remote().urls, None) - self.status = 'unknown' + try: + self.remote = next(repo.remote().urls, None) + self.status = 'unknown' + except Exception: + self.remote = None def list_files(self, subdir, extension): from modules import scripts From a170e3d22231e145f42bb878a76ae5f76fdca230 Mon Sep 17 00:00:00 2001 From: Evgeniy Date: Sat, 5 Nov 2022 17:06:56 +0300 Subject: [PATCH 067/219] Python 3.8 typing compatibility Solves problems with ```Traceback (most recent call last): File "webui.py", line 201, in webui() File "webui.py", line 178, in webui create_api(app) File "webui.py", line 117, in create_api from modules.api.api import Api File "H:\AIart\stable-diffusion\stable-diffusion-webui\modules\api\api.py", line 9, in from modules.api.models import * File "H:\AIart\stable-diffusion\stable-diffusion-webui\modules\api\models.py", line 194, in class SamplerItem(BaseModel): File "H:\AIart\stable-diffusion\stable-diffusion-webui\modules\api\models.py", line 196, in SamplerItem aliases: list[str] = Field(title="Aliases") TypeError: 'type' object is not subscriptable``` and ```Traceback (most recent call last): File "webui.py", line 201, in webui() File "webui.py", line 178, in webui create_api(app) File "webui.py", line 117, in create_api from modules.api.api import Api File "H:\AIart\stable-diffusion\stable-diffusion-webui\modules\api\api.py", line 9, in from modules.api.models import * File "H:\AIart\stable-diffusion\stable-diffusion-webui\modules\api\models.py", line 194, in class SamplerItem(BaseModel): File "H:\AIart\stable-diffusion\stable-diffusion-webui\modules\api\models.py", line 197, in SamplerItem options: dict[str, str] = Field(title="Options") TypeError: 'type' object is not subscriptable``` --- modules/api/models.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/modules/api/models.py b/modules/api/models.py index a44c5ddd..f89da1ff 100644 --- a/modules/api/models.py +++ b/modules/api/models.py @@ -5,7 +5,7 @@ from typing_extensions import Literal from inflection import underscore from modules.processing import StableDiffusionProcessingTxt2Img, StableDiffusionProcessingImg2Img from modules.shared import sd_upscalers, opts, parser -from typing import List +from typing import Dict, List API_NOT_ALLOWED = [ "self", @@ -193,8 +193,8 @@ FlagsModel = create_model("Flags", **flags) class SamplerItem(BaseModel): name: str = Field(title="Name") - aliases: list[str] = Field(title="Aliases") - options: dict[str, str] = Field(title="Options") + aliases: List[str] = Field(title="Aliases") + options: Dict[str, str] = Field(title="Options") class UpscalerItem(BaseModel): name: str = Field(title="Name") @@ -230,4 +230,4 @@ class PromptStyleItem(BaseModel): class ArtistItem(BaseModel): name: str = Field(title="Name") score: float = Field(title="Score") - category: str = Field(title="Category") \ No newline at end of file + category: str = Field(title="Category") From 62e3d71aa778928d63cab81d9d8cde33e55bebb3 Mon Sep 17 00:00:00 2001 From: AUTOMATIC <16777216c@gmail.com> Date: Sat, 5 Nov 2022 17:09:42 +0300 Subject: [PATCH 068/219] rework the code to not use the walrus operator because colab's 3.7 does not support it --- modules/hypernetworks/hypernetwork.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/modules/hypernetworks/hypernetwork.py b/modules/hypernetworks/hypernetwork.py index 5ceed6ee..7f182712 100644 --- a/modules/hypernetworks/hypernetwork.py +++ b/modules/hypernetworks/hypernetwork.py @@ -429,13 +429,16 @@ def train_hypernetwork(hypernetwork_name, learn_rate, batch_size, data_root, log weights = hypernetwork.weights() for weight in weights: weight.requires_grad = True + # Here we use optimizer from saved HN, or we can specify as UI option. - if (optimizer_name := hypernetwork.optimizer_name) in optimizer_dict: + if hypernetwork.optimizer_name in optimizer_dict: optimizer = optimizer_dict[hypernetwork.optimizer_name](params=weights, lr=scheduler.learn_rate) + optimizer_name = hypernetwork.optimizer_name else: - print(f"Optimizer type {optimizer_name} is not defined!") + print(f"Optimizer type {hypernetwork.optimizer_name} is not defined!") optimizer = torch.optim.AdamW(params=weights, lr=scheduler.learn_rate) optimizer_name = 'AdamW' + if hypernetwork.optimizer_state_dict: # This line must be changed if Optimizer type can be different from saved optimizer. try: optimizer.load_state_dict(hypernetwork.optimizer_state_dict) From 159475e072f2ed3db8235aab9c3fa18640b93b80 Mon Sep 17 00:00:00 2001 From: AUTOMATIC <16777216c@gmail.com> Date: Sat, 5 Nov 2022 18:32:22 +0300 Subject: [PATCH 069/219] tweak names a bit for new samplers --- modules/sd_samplers.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/modules/sd_samplers.py b/modules/sd_samplers.py index 1e88f7ee..783992d2 100644 --- a/modules/sd_samplers.py +++ b/modules/sd_samplers.py @@ -24,15 +24,15 @@ samplers_k_diffusion = [ ('Heun', 'sample_heun', ['k_heun'], {}), ('DPM2', 'sample_dpm_2', ['k_dpm_2'], {}), ('DPM2 a', 'sample_dpm_2_ancestral', ['k_dpm_2_a'], {}), - ('DPM-Solver++(2S) a', 'sample_dpmpp_2s_ancestral', ['k_dpmpp_2s_a'], {}), - ('DPM-Solver++(2M)', 'sample_dpmpp_2m', ['k_dpmpp_2m'], {}), + ('DPM++ 2S a', 'sample_dpmpp_2s_ancestral', ['k_dpmpp_2s_a'], {}), + ('DPM++ 2M', 'sample_dpmpp_2m', ['k_dpmpp_2m'], {}), ('DPM fast', 'sample_dpm_fast', ['k_dpm_fast'], {}), ('DPM adaptive', 'sample_dpm_adaptive', ['k_dpm_ad'], {}), ('LMS Karras', 'sample_lms', ['k_lms_ka'], {'scheduler': 'karras'}), ('DPM2 Karras', 'sample_dpm_2', ['k_dpm_2_ka'], {'scheduler': 'karras'}), ('DPM2 a Karras', 'sample_dpm_2_ancestral', ['k_dpm_2_a_ka'], {'scheduler': 'karras'}), - ('DPM-Solver++(2S) a Karras', 'sample_dpmpp_2s_ancestral', ['k_dpmpp_2s_a_ka'], {'scheduler': 'karras'}), - ('DPM-Solver++(2M) Karras', 'sample_dpmpp_2m', ['k_dpmpp_2m_ka'], {'scheduler': 'karras'}), + ('DPM++ 2S a Karras', 'sample_dpmpp_2s_ancestral', ['k_dpmpp_2s_a_ka'], {'scheduler': 'karras'}), + ('DPM++ 2M Karras', 'sample_dpmpp_2m', ['k_dpmpp_2m_ka'], {'scheduler': 'karras'}), ] samplers_data_k_diffusion = [ From 29f48b7803dd0890cb5328fa290ab12045706316 Mon Sep 17 00:00:00 2001 From: Dynamic Date: Sun, 6 Nov 2022 00:37:37 +0900 Subject: [PATCH 070/219] Update ko_KR.json New setting option and some additional extension index strings --- localizations/ko_KR.json | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/localizations/ko_KR.json b/localizations/ko_KR.json index 29e10075..cf302aaf 100644 --- a/localizations/ko_KR.json +++ b/localizations/ko_KR.json @@ -16,6 +16,7 @@ "A merger of the two checkpoints will be generated in your": "체크포인트들이 병합된 결과물이 당신의", "A value that determines the output of random number generator - if you create an image with same parameters and seed as another image, you'll get the same result": "난수 생성기의 결과물을 지정하는 값 - 동일한 설정값과 동일한 시드를 적용 시, 완전히 똑같은 결과물을 얻게 됩니다.", "Action": "작업", + "Add a button to convert the prompts used in NovelAI for use in the WebUI. In addition, add a button that allows you to recall a previously used prompt.": "NovelAI에서 사용되는 프롬프트를 WebUI에서 사용할 수 있게 변환하는 버튼을 추가합니다. 덤으로 이전에 사용한 프롬프트를 불러오는 버튼도 추가됩니다.", "Add a random artist to the prompt.": "프롬프트에 랜덤한 작가 추가", "Add a second progress bar to the console that shows progress for an entire job.": "콘솔에 전체 작업의 진행도를 보여주는 2번째 프로그레스 바 추가하기", "Add difference": "차이점 추가", @@ -24,6 +25,7 @@ "Add model hash to generation information": "생성 정보에 모델 해시 추가", "Add model name to generation information": "생성 정보에 모델 이름 추가", "Add number to filename when saving": "이미지를 저장할 때 파일명에 숫자 추가하기", + "Adds a tab that lets you preview how CLIP model would tokenize your text.": "CLIP 모델이 텍스트를 어떻게 토큰화할지 미리 보여주는 탭을 추가합니다.", "Adds a tab to the webui that allows the user to automatically extract keyframes from video, and manually extract 512x512 crops of those frames for use in model training.": "WebUI에 비디오로부터 자동으로 키프레임을 추출하고, 그 키프레임으로부터 모델 훈련에 사용될 512x512 이미지를 잘라낼 수 있는 탭을 추가합니다.", "Aesthetic Gradients": "스타일 그라디언트", "Aesthetic Image Scorer": "스타일 이미지 스코어러", @@ -33,6 +35,7 @@ "Aesthetic text for imgs": "스타일 텍스트", "Aesthetic weight": "스타일 가중치", "Allowed categories for random artists selection when using the Roll button": "랜덤 버튼을 눌러 무작위 작가를 선택할 때 허용된 카테고리", + "Allows you to include various shortcodes in your prompts. You can pull text from files, set up your own variables, process text through conditional functions, and so much more - it's like wildcards on steroids.": "프롬프트에 다양한 숏코드를 추가할 수 있게 해줍니다. 파일로부터 텍스트 추출, 변수 설정, 조건 함수로 텍스트 처리 등등 - 스테로이드를 맞은 와일드카드라 할 수 있죠.", "Always print all generation info to standard output": "기본 아웃풋에 모든 생성 정보 항상 출력하기", "Always save all generated image grids": "생성된 이미지 그리드 항상 저장하기", "Always save all generated images": "생성된 이미지 항상 저장하기", @@ -54,6 +57,7 @@ "Batch Process": "이미지 여러장 처리", "Batch size": "배치 크기", "behind": "최신 아님", + "Booru tag autocompletion": "Booru 태그 자동완성", "BSRGAN 4x": "BSRGAN 4x", "built with gradio": "gradio로 제작되었습니다", "Calculates aesthetic score for generated images using CLIP+MLP Aesthetic Score Predictor based on Chad Scorer": "Chad 스코어러를 기반으로 한 CLIP+MLP 스타일 점수 예측기를 이용해 생성된 이미지의 스타일 점수를 계산합니다.", @@ -114,6 +118,7 @@ "Directory for saving images using the Save button": "저장 버튼을 이용해 저장하는 이미지들의 저장 경로", "Directory name pattern": "디렉토리명 패턴", "directory.": "저장 경로에 저장됩니다.", + "Displays autocompletion hints for tags from image booru boards such as Danbooru. Uses local tag CSV files and includes a config for customization.": "Danbooru 같은 이미지 booru 보드의 태그에 대한 자동완성 힌트를 보여줍니다. 로컬 환경에 저장된 CSV 파일을 사용하고 조정 가능한 설정 파일이 포함되어 있습니다.", "Do not add watermark to images": "이미지에 워터마크 추가하지 않기", "Do not do anything special": "아무것도 하지 않기", "Do not save grids consisting of one picture": "이미지가 1개뿐인 그리드는 저장하지 않기", @@ -317,6 +322,7 @@ "None": "없음", "Nothing": "없음", "Nothing found in the image.": "Nothing found in the image.", + "novelai-2-local-prompt": "NovelAI 프롬프트 변환기", "Number of columns on the page": "각 페이지마다 표시할 가로줄 수", "Number of grids in each row": "각 세로줄마다 표시될 그리드 수", "number of images to delete consecutively next": "연속적으로 삭제할 이미지 수", @@ -431,6 +437,7 @@ "Save images with embedding in PNG chunks": "PNG 청크로 이미지에 임베딩을 포함시켜 저장", "Save style": "스타일 저장", "Save text information about generation parameters as chunks to png files": "이미지 생성 설정값을 PNG 청크에 텍스트로 저장", + "Saves Optimizer state as separate *.optim file. Training can be resumed with HN itself and matching optim file.": "옵티마이저 상태를 별개의 *.optim 파일로 저장하기. 하이퍼네트워크 파일과 일치하는 optim 파일로부터 훈련을 재개할 수 있습니다.", "Saving images/grids": "이미지/그리드 저장", "Saving to a directory": "디렉토리에 저장", "Scale by": "스케일링 배수 지정", @@ -515,6 +522,7 @@ "Tile size for ESRGAN upscalers. 0 = no tiling.": "ESRGAN 업스케일러들의 타일 사이즈. 0 = 타일링 없음.", "Tiling": "타일링", "Time taken:": "소요 시간 : ", + "tokenizer": "토크나이저", "Torch active/reserved:": "활성화/예약된 Torch 양 : ", "Torch active: Peak amount of VRAM used by Torch during generation, excluding cached data.\nTorch reserved: Peak amount of VRAM allocated by Torch, including all active and cached data.\nSys VRAM: Peak amount of VRAM allocation across all applications / total GPU VRAM (peak utilization%).": "활성화된 Torch : 생성 도중 캐시된 데이터를 포함해 사용된 VRAM의 최대량\n예약된 Torch : 활성화되고 캐시된 모든 데이터를 포함해 Torch에게 할당된 VRAM의 최대량\n시스템 VRAM : 모든 어플리케이션에 할당된 VRAM 최대량 / 총 GPU VRAM (최고 이용도%)", "Train": "훈련", From 0b028c84ab8a8edcf9648622ed3fe4b8ca013334 Mon Sep 17 00:00:00 2001 From: Riccardo Giovanetti <29801031+Harvester62@users.noreply.github.com> Date: Sat, 5 Nov 2022 18:12:06 +0100 Subject: [PATCH 071/219] Italian localization - Additions and updates Updated localization with the latest version of these Scripts/Extensions: SD-Chad - Stable Diffusion Aesthetic Scorer (added) AlphaCanvas StylePile Alternate Sampler Noise Schedules SD Latent Mirroring (new) SD Dynamic Prompts Dataset Tag Editor Depth Maps (new) Improved prompt matrix (new) New Extensions: Auto-sd-paint-ext (new) training-picker (new) Unprompted NovelAI-2-local-prompt (new) tokenizer (new) Hope there aren't too many mistakes or wrong translations, in case let me know. --- localizations/it_IT.json | 514 ++++++++++++++++++++++++++++++++------- 1 file changed, 423 insertions(+), 91 deletions(-) diff --git a/localizations/it_IT.json b/localizations/it_IT.json index 83d0ccce..22a6f546 100644 --- a/localizations/it_IT.json +++ b/localizations/it_IT.json @@ -17,11 +17,14 @@ "Checkpoint Merger": "Miscelatore di Checkpoint", "Train": "Addestramento", "Create aesthetic embedding": "Crea incorporamento estetico", + "auto-sd-paint-ext Guide/Panel": "KRITA Plugin Guida", "Dataset Tag Editor": "Dataset Tag Editor", "Deforum": "Deforum", "Artists To Study": "Artisti per studiare", "Image Browser": "Galleria immagini", "Inspiration": "Ispirazione", + "Tokenizer": "Tokenizzatore", + "Training Picker": "Training Picker", "Settings": "Impostazioni", "Extensions": "Estensioni", "Prompt": "Prompt", @@ -49,11 +52,15 @@ "Heun": "Heun", "DPM2": "DPM2", "DPM2 a": "DPM2 a", + "DPM++ 2S a": "DPM++ 2S a", + "DPM++ 2M": "DPM++ 2M", "DPM fast": "DPM fast", "DPM adaptive": "DPM adaptive", "LMS Karras": "LMS Karras", "DPM2 Karras": "DPM2 Karras", "DPM2 a Karras": "DPM2 a Karras", + "DPM++ 2S a Karras": "DPM++ 2S a Karras", + "DPM++ 2M Karras": "DPM++ 2M Karras", "DDIM": "DDIM", "PLMS": "PLMS", "Width": "Larghezza", @@ -84,18 +91,30 @@ "Aesthetic text for imgs": "Estetica - Testo per le immagini", "Slerp angle": "Angolo Slerp", "Is negative text": "È un testo negativo", + "Unprompted": "Unprompted", + "Dry Run": "Esecuzione a vuoto (Debug)", + "NEW!": "NUOVO!", + "Premium Fantasy Card Template": "Premium Fantasy Card Template", + "is now available.": "è ora disponibile.", + "Generate a wide variety of creatures and characters in the style of a fantasy card game. Perfect for heroes, animals, monsters, and even crazy hybrids.": "Genera un'ampia varietà di creature e personaggi nello stile di un gioco di carte fantasy. Perfetto per eroi, animali, mostri e persino ibridi incredibili.", + "Learn More ➜": "Per saperne di più ➜", + "Purchases help fund the continued development of Unprompted. Thank you for your support!": "Gli acquisti aiutano a finanziare il continuo sviluppo di Unprompted. Grazie per il vostro sostegno!", + "Dismiss": "Rimuovi", "Script": "Script", "Random grid": "Generaz. casuale (griglia)", "Random": "Generaz. casuale (no griglia)", "StylePile": "StylePile", - "Advanced prompt matrix": "Matrice di prompt avanzata", "Advanced Seed Blending": "Miscelazione Semi Avanzata", "Alternate Sampler Noise Schedules": "Metodi alternativi di campionamento del rumore", "Animator v6": "Animator v6", "Asymmetric tiling": "Piastrellatura asimmetrica", + "SD Chad - Stable Diffusion Aesthetic Scorer": "SD Chad - Assegna Punteggio Estetica", "Custom code": "Codice personalizzato", - "Embedding to Shareable PNG": "Incorporamento convertito in PNG condivisibile", + "DepthMap v0.1.0": "DepthMap v0.1.0", + "Embedding to Shareable PNG": "Converte Incorporamento in PNG condivisibile", "Force symmetry": "Forza la simmetria", + "Improved prompt matrix": "Improved prompt matrix", + "Latent Mirroring": "Rispecchia e capovolge l'immagine latente", "Prompts interpolation": "Interpola Prompt", "Prompt matrix": "Matrice dei prompt", "Prompt morph": "Metamorfosi del prompt", @@ -104,7 +123,6 @@ "Seed travel": "Interpolazione semi", "Shift attention": "Sposta l'attenzione", "Text to Vector Graphics": "Da testo a grafica vettoriale", - "Unprompted": "Unprompted", "X/Y plot": "Grafico X/Y", "X/Y/Z plot": "Grafico X/Y/Z", "Dynamic Prompting v0.13.6": "Prompt dinamici v0.13.6", @@ -120,70 +138,186 @@ "Keep -1 for seeds": "Mantieni sempre il seme a -1", "x/y change": "Inverti ordine assi X/Y (Passi/CFG)", "Loops": "Cicli", - "Focus on:": "Focus su:", - "No focus": "Nessun Focus", - "Portraits (tick Restore faces above for best results)": "Ritratti (selezionare 'Restaura volti' in alto per ottenere i migliori risultati)", - "Feminine and extra attractive (tick Restore faces above for best results)": "Femminile ed estremamente attraente (selezionare 'Restaura volti' per ottenere i migliori risultati)", - "Masculine and extra attractive (tick Restore faces above for best results)": "Maschile ed estremamente attraente (selezionare 'Restaura volti' per ottenere i migliori risultati)", - "Monsters": "Mostri", - "Robots": "Robot", - "Retrofuturistic": "Retrofuturistico", - "Propaganda": "Propaganda", - "Landscapes": "Paesaggi", - "Hints": "Suggerimenti", + "Set Batch count to Sequential prompt count": "Imposta il lotto di immagini sul numero di prompt sequenziali", + "Sequential prompts [X]": "Prompt sequenziali [X]", + "Random prompts [R]": "Prompt randomici [R]", + "Image type strength": "Intensità del tipo di immagine", "Image type": "Tipo di immagine", "Not set": "Non impostato", "Photography": "Fotografia", "Digital art": "Arte digitale", - "3D Rendering": "3D Rendering", + "3D Rendering": "Rendering 3D", "Painting": "Dipinto", - "Sketch": "Schizzo", - "Classic Comics": "Fumetti classici", - "Modern Comics": "Fumetti moderni", - "Manga": "Manga", - "Vector art": "Arte vettoriale", - "Visual style": "Stile visivo", - "Realism": "Realismo", - "Photorealism": "Fotorealismo", - "Hyperrealism": "Iperrealismo", - "Surrealism": "Surrealismo", - "Modern Art": "Arte moderna", - "Fauvism": "Fauvismo", - "Futurism": "Futurismo", - "Painterly": "Pittorico", - "Pointillisme": "Puntinismo", - "Abstract": "Astratto", - "Pop Art": "Pop Art", - "Impressionist": "Impressionista", - "Cubism": "Cubismo", - "Linocut": "Linoleografia", - "Fantasy": "Fantasia", + "Vector Art": "Arte vettoriale", + "Mood": "Stato d'animo", + "Amusing": "Amusing", + "Angry": "Angry", + "Cosy": "Cosy", + "Depressing": "Depressing", + "Disgusting": "Disgusting", + "Embarrassing": "Embarrassing", + "Energetic": "Energetic", + "Evil": "Evil", + "Fearful": "Fearful", + "Frightening": "Frightening", + "Grim": "Grim", + "Guilty": "Guilty", + "Happy": "Happy", + "Hopeful": "Hopeful", + "Hopeless": "Hopeless", + "Lonely": "Lonely", + "Lustful": "Lustful", + "Peaceful": "Peaceful", + "Proud": "Proud", + "Relieving": "Relieving", + "Romantic": "Romantic", + "Sad": "Sad", + "Satisfying": "Satisfying", + "Shameful": "Shameful", + "Surprising": "Surprising", "Colors": "Colori", - "Chaotic": "Caotico", - "Primary colors": "Colori primari", - "Colorful": "Colorato", + "Primary Colors": "Primary Colors", "Vivid": "Vivido", - "Muted colors": "Colori tenui", - "Low contrast": "Basso contrasto", - "Desaturated": "Desaturato", - "Grayscale": "Scala di grigi", - "Black and white": "Bianco e nero", - "Infrared": "Infrarosso", - "Complementary": "Colori complementari", - "Non-complementary": "Colori non complementari", + "Pastel Colors": "Pastel Colors", + "Muted Colors": "Muted Colors", + "Grayscale": "Grayscale", + "Black and white": "Black and white", + "Infrared": "Infrared", "View": "Visuale", - "Tilt shift": "Tilt shift", - "Wide-angle": "Angolo ampio", + "Symmetrical": "Symmetrical", + "Tilt-shift": "Tilt-shift", + "Long shot angle": "Long shot angle", + "Medium shot angle": "Medium shot angle", + "Wide shot angle": "Wide shot angle", "Portrait": "Ritratto", + "Extreme close-up angle": "Extreme close-up angle", "Macro": "Macro", "Microscopic": "Microscopico", "Isometric": "Isometrico", "Panorama": "Panorama", - "Aerial photograph": "Fotografia aerea", - "Artist focus (not quite finished, not sure it helps)": "Focus sull'artista (non del tutto finito, non è sicuro che aiuti)", - "B/W Photograpy": "Fotografia B/N", - "Portrait photo": "Foto ritratto", - "Usage: a wearing ": "Utilizzo: a wearing ", + "Fisheye lens": "Fisheye lens", + "Overhead-angle": "Overhead-angle", + "Birds eye view": "Birds eye view", + "Focus on (unfinished)": "Focus su (incompleto)", + "No focus": "Nessun focus", + "Portraits": "Portraits", + "Feminine portrait": "Ritratto femminile", + "Masculine portrait": "Ritratto maschile", + "WaiFusion": "WaiFusion", + "Horrible Monsters": "Horrible Monsters", + "Robots": "Robot", + "Retrofuturism": "Retrofuturism", + "Propaganda": "Propaganda", + "Landscapes": "Paesaggi", + "Visual style strength": "Forza dello stile visivo", + "Visual style": "Stile visivo", + "Abstract": "Abstract", + "Acidwave": "Acidwave", + "Acrylic": "Acrylic", + "Aestheticism": "Aestheticism", + "Art Deco": "Art Deco", + "Nouveau": "Nouveau", + "Ashcan School Style": "Ashcan School Style", + "Avant-garde": "Avant-garde", + "Ballpoint Pen": "Ballpoint Pen", + "Baroque": "Baroque", + "Classicism": "Classicism", + "CoBrA": "CoBrA", + "Colored Pencil": "Colored Pencil", + "Constructivism": "Constructivism", + "Cubism": "Cubism", + "Dreamcore": "Dreamcore", + "Drip": "Drip", + "Encaustic": "Encaustic", + "Expressionism": "Expressionism", + "Fauvism": "Fauvism", + "Finger Painting": "Finger Painting", + "Futurism": "Futurism", + "Gouache": "Gouache", + "Hot Wax": "Hot Wax", + "Impressionism": "Impressionism", + "Ink Wash": "Ink Wash", + "Japanese": "Japanese", + "Korean": "Korean", + "Line Art": "Line Art", + "Linocut": "Linocut", + "Lowpoly": "Lowpoly", + "Manga": "Manga", + "Marker": "Marker", + "Modern Comics": "Fumetti moderni", + "Mural": "Mural", + "Neoclassicism": "Neoclassicism", + "Oil Painting": "Oil Painting", + "Pastel": "Pastel", + "Pencil": "Pencil", + "Photorealism": "Photorealism", + "Pixel Art": "Pixel Art", + "Pop Art": "Pop Art", + "Pop Surrealism": "Pop Surrealism", + "Psychedelic": "Psychedelic", + "Realism": "Realism", + "Renaissance": "Renaissance", + "Rococo": "Rococo", + "Sprite Artwork": "Sprite Artwork", + "Street Art": "Street Art", + "Suprematism": "Suprematism", + "Vaporwave": "Vaporwave", + "Vintage Comics": "Vintage Comics", + "Watercolor": "Watercolor", + "Artist influence": "Influenza dell'Artista", + "Artist": "Artista", + "Examples, Help and Tips": "Esempi, aiuto e suggerimenti", + "Style examples": "Esempi di Stile", + "Artist examples": "Esempi di Artisti", + "Mood examples": "Esempi di stato d'animo", + "Help": "Aiuto", + "Hello, StylePile here": "Ciao, questo è StylePile", + "Introduction": "Introduzione", + "is a mix and match system for adding elements to prompts that affect the style of the result. Hence the name. By default, these elements are placed in a specific order and given strength values. Which means the result sort-of evolves. I have generated thousands of images for each main": "è un sistema mescola e abbina per aggiungere elementi ai prompt che influiscono sullo stile del risultato. Da qui il nome. Per impostazione predefinita, questi elementi vengono inseriti in un ordine specifico e vengono assegnati valori di forza. Il che significa che il risultato si evolve. Ho generato migliaia di immagini per ogni principale", + "and tweaked the keywords to attempt giving expected results most of the time. Certainly, your suggestions for improvements are very welcome.": "e ottimizzato le parole chiave per tentare di fornire i risultati attesi per la maggior parte del tempo. Certamente, i tuoi suggerimenti per miglioramenti sono molto graditi.", + "Base workflow": "Flusso di lavoro di base", + "For example, if you select the": "Ad esempio, se si seleziona il", + "image type, then almost all results will look like Paintings. Selecting": "tipo di immagine, quindi quasi tutti i risultati sembreranno Dipinti. Selezione", + "will have a certain influence on the overall look in some way (if it's something humanoid it may show emotion, but also colors and overall feel may change). Setting": "avrà una certa influenza sull'aspetto generale in qualche modo (se è qualcosa di umanoide può mostrare emozioni, ma anche i colori e la sensazione generale possono cambiare). Ambientazione", + "will change the general tonality of the result. And setting": "cambierà la tonalità generale del risultato. E ambientazione", + "will attempt to change how the subject is viewed. Attempt, because view appears to be the least reliable keyword. These elements are placed in order of influence and supported by certain strength values. These basic settings produce very quick results close to the general look you want.": "tenterà di cambiare la modalità di visualizzazione dell'oggetto. Tentativo, perché view sembra essere la parola chiave meno affidabile. Questi elementi sono posti in ordine di influenza e supportati da determinati valori di forza. Queste impostazioni di base producono risultati molto rapidi vicini all'aspetto generale desiderato.", + "Moving on, adding a": "Andando avanti, aggiungendo a", + "will combine with": "si combinerà con", + "to influence how the result generally looks. These styles are based on classic and modern Painting/Art/design movements (which I picked after hours and thousands of samples of testing) and can have a strong influence on the end result. Either it will be more realistic or artistic, or look like a comic book etc. In general, this is a really strong element for getting the look you want. Its influence can be adjusted with the slider above. Experiment with the values, keeping in mind that anything above 1.5 will start becoming a mess. In a similar way, but more focused, you can select an": "per influenzare l'aspetto generale del risultato. Questi stili si basano su movimenti Pittura/Arte/design classici e moderni (che ho scelto dopo ore e migliaia di campioni di test) e possono avere una forte influenza sul risultato finale. O sarà più realistico o artistico, o assomiglierà a un fumetto, ecc. In generale, questo è un elemento davvero forte per ottenere l'aspetto che desideri. La sua influenza può essere regolata con il cursore in alto. Sperimenta con i valori, tenendo presente che qualsiasi cosa al di sopra di 1,5 inizierà a diventare un pasticcio. In modo simile, ma più mirato, puoi selezionare un", + "and, of course, that will have a very visible effect on the result as well. Currently there are 135 artists, 55 art styles and 25 emotions available for selection and represented with preview images.": "e, naturalmente, anche questo avrà un effetto molto visibile sul risultato. Attualmente ci sono 135 artisti, 55 stili artistici e 25 emozioni disponibili per la selezione e rappresentate con immagini di anteprima.", + "Strength of these settings has been preset at 1.3, as that appears to be the golden ratio for getting good results. Sometimes very low settings have an interesting result as well. You can, and should, freely mix and match these settings to get different results. Classic Painting styles affected or affecting 3D look quite interesting. Photography can look cool with some of the brighter, more artistic styles etc. Sometimes raising CFG scale to 15,20 or more also helps to REALLY push the style onto the image.": "La forza di queste impostazioni è stata preimpostata a 1,3, poiché sembra essere il rapporto aureo per ottenere buoni risultati. A volte anche impostazioni molto basse hanno un risultato interessante. Puoi, e dovresti, mescolare e abbinare liberamente queste impostazioni per ottenere risultati diversi. Gli stili di pittura classica influenzati o influenzati dal 3D sembrano piuttosto interessanti. La fotografia può sembrare interessante con alcuni degli stili più luminosi, più artistici, ecc. A volte aumentare la scala CFG a 15,20 o più aiuta anche a spingere VERAMENTE lo stile sull'immagine.", + "Advanced workflow": "Flusso di lavoro avanzato", + "StylePile can overtake the generation process, allowing you to generate a large amount of different results with very little extra work. There are two types of variables you can use: [X] and [R]. When you add an [X] to your prompt, it sequentially takes values from the": "StylePile può prendere il controllo del processo di generazione, consentendoti di generare una grande quantità di risultati diversi con pochissimo lavoro extra. Ci sono due tipi di variabili che puoi usare: [X] e [R]. Quando aggiungi una [X] al tuo prompt, prende in sequenza i valori da", + "Sequential prompts": "Prompt sequenziali", + "text area. You can have dozens of lines there and they will be processed in sequence. When you add [R] to the prompt a value from the": "area di testo. Puoi avere dozzine di righe lì e verranno elaborate in sequenza. Quando si aggiunge [R] al prompt un valore da", + "Random prompts": "Prompt casuali", + "text area will be inserted in its place. By combining these a huge variety in prompts is very easy to do.": "l'area di testo verrà inserita al suo posto. Combinando questi un'enorme varietà di prompt è molto facile da fare.", + "When using this,": "Quando si utilizza questo,", + "will move through the prompts and": "si sposterà attraverso i prompt e", + "will set how many copies with the given prompt to make. If the seed is not random, it will increase with each batch size step. Any random elements will still be picked randomly.": "imposterà quante copie fare con il prompt dato. Se il seme non è casuale, aumenterà ad ogni passaggio della dimensione del batch. Eventuali elementi casuali verranno comunque selezionati casualmente.", + "Tips and tricks": "Suggerimenti e trucchi", + "If you add your own Artist, I would recommend having \"by Artist\" in front of their name. Depending on Artist's popularity (or lack thereof) this appears to have a very tangible influence on the result.": "Se aggiungi il tuo artista, ti consiglio di avere \"per artista\" davanti al suo nome. A seconda della popolarità dell'artista (o della sua mancanza) questo sembra avere un'influenza molto tangibile sul risultato.", + "Parenthesis can be added to make pArts of the prompt stronger. So": "È possibile aggiungere parentesi per rendere più forti parti del prompt. Così", + "((cute kitten))": "((cute kitten))", + "will make it extra cute (try it out). This is also important if a style is affecting your original prompt too much. Make that prompt stronger by adding parenthesis around it, like this:": "lo renderà molto carino (provalo). Questo è importante anche se uno stile influisce troppo sul prompt originale. Rendi più forte quel prompt aggiungendo parentesi attorno ad esso, in questo modo:", + "((promt))": "((promt))", + ". A strength modifier value can also be used, like this": ". È anche possibile utilizzare un valore modificatore di forza, in questo modo", + "(prompt:1.1)": "(prompt:1.1)", + ". To save some typing you can select the line you want to make stronger and use": ". Per salvare un po' di digitazione puoi selezionare la linea che vuoi rendere più forte e utilizzare", + "Ctrl+Shift+Arrow keys up": "Ctrl+Shift+Freccia su", + "to add these parenthesis and change the value. As you can see by default values on most sliders, 1.3 seems like a good stArting point if you want to see some impact.": "per aggiungere queste parentesi e modificare il valore. Come puoi vedere per i valori predefiniti sulla maggior parte dei cursori, 1.3 sembra un buon punto di partenza se vuoi vedere un certo impatto.", + "Prompts can be split like": "I prompt possono essere divisi come", + "[A|B]": "[A|B]", + "to sequentially use terms, one after another on each step. For example": "per utilizzare in sequenza i termini, uno dopo l'altro in ogni passaggio. Per esempio", + "[cat|dog]": "[cat|dog]", + "will produce a hybrid catdog.": "produrrà un cane-gatto ibrido.", + "Using": "Usando", + "[A:B:0.4]": "[A:B:0.4]", + "will switch to other terms after the first one has been active for a certain percentage of steps. So": "passerà ad altri termini dopo che il primo è stato attivo per una certa percentuale di passaggi. Così", + "[cat:dog:0.4]": "[cat:dog:0.4]", + "will build a cat 40% of the time and then stArt turning it into a dog. Usually this needs more steps to work properly.": "costruirà un gatto il 40% delle volte e poi inizierà a trasformarlo in un cane. Di solito questo richiede più passaggi per funzionare correttamente.", + "In conclusion": "In conclusione", + "I made this because manually changing keywords, looking up possible styles, etc was a pain. It is meant as a fun tool to explore possibilities and make learning Stable Diffusion easier. If you have some ideas or, better yet, would like to contribute in some way*, just visit https://github.com/some9000/StylePile\n*Hey, if you have a 12Gb graphics card just laying around I'm happy to take it (:": "L'ho fatto perché cambiare manualmente le parole chiave, cercare possibili stili, ecc. era una seccatura. È inteso come uno strumento divertente per esplorare le possibilità e rendere più facile l'apprendimento della Diffusione stabile. Se hai qualche idea o, meglio ancora, vorresti contribuire in qualche modo*, visita pure https://github.com/some9000/StylePile\n*Hey, se hai una scheda grafica da 12 Gb in giro, sono felice di prenderla (:", "Seeds": "Semi", "Noise Scheduler": "Pianificazione del rumore", "Default": "Predefinito", @@ -217,7 +351,7 @@ "Prompt Template, applied to each keyframe below": "Modello di prompt, applicato a ciascun fotogramma chiave qui di seguito", "Positive Prompts": "Prompt positivi", "Negative Prompts": "Prompt negativi", - "Props, Stamps": "Immagini Clipart da diffondere (prop), o da applicare in post elaborazione e non essere diffuse (stamp).", + "Props, Stamps": "Immagini Clipart da diffondere (prop), o da applicare in post elaborazione e non essere diffuse (stamp)", "Poper_Folder:": "Cartella Immagini Clipart (PNG trasparenti):", "Supported Keyframes:": "Fotogrammi chiave supportati:", "time_s | source | video, images, img2img | path": "time_s | source | video, images, img2img | path", @@ -239,7 +373,22 @@ "Keyframes:": "Fotogrammi chiave:", "Tile X": "Piastrella asse X", "Tile Y": "Piastrella asse Y", + "Number of images to generate": "Numero di immagini da generare", "Python code": "Codice Python", + "Model": "Modello", + "dpt_large": "Depth large", + "dpt_hybrid": "Depth hybrid", + "midas_v21": "MIDAS v21", + "midas_v21_small": "MIDAS v21 small", + "Compute on": "Calcola", + "GPU": "GPU", + "CPU": "CPU", + "Save DepthMap": "Salva DepthMap", + "Show DepthMap": "Mostra DepthMap", + "Combine into one image.": "Combina in un'unica immagine.", + "Combine axis": "Combina gli assi", + "Vertical": "Verticale", + "Horizontal": "Orizzontale", "Source embedding to convert": "Incorporamento sorgente da convertire", "Embedding token": "Token Incorporamento", "Output directory": "Cartella di output", @@ -248,6 +397,16 @@ "Alt. symmetry method (blending)": "Metodo di simmetria alternativo (miscelazione)", "Apply every n steps": "Applica ogni n passi", "Skip last n steps": "Salta gli ultimi n passi", + "Usage: a wearing ": "Utilizzo: a wearing ", + "Mirror application mode": "modalità di applicazione specchiatura", + "Alternate Steps": "Passaggi alternati", + "Blend Average": "Miscelazione media", + "Mirror style": "Stile specchiatura", + "Vertical Mirroring": "Specchiatura verticale", + "Horizontal Mirroring": "Specchiatura orizzontale", + "90 Degree Rotation": "Rotazione 90 gradi", + "180 Degree Rotation": "Rotazione 180 gradi", + "Maximum steps fraction to mirror at": "Frazione di passi massima su cui eseguire la specchiatura", "Interpolation prompt": "Prompt di interpolazione", "Number of images": "Numero di immagini", "Make a gif": "Crea GIF", @@ -263,7 +422,7 @@ "Use same random seed for all lines": "Usa lo stesso seme casuale per tutte le righe", "List of prompt inputs": "Elenco di prompt di input", "Upload prompt inputs": "Carica un file contenente i prompt di input", - "n": "Esegui n volte", + "n": "n", "Destination seed(s) (Comma separated)": "Seme/i di destinazione (separati da virgola)", "Only use Random seeds (Unless comparing paths)": "Usa solo semi casuali (a meno che non si confrontino i percorsi)", "Number of random seed(s)": "Numero di semi casuali", @@ -296,13 +455,6 @@ "Transparent PNG": "PNG trasparente", "Noise Tolerance": "Tolleranza al rumore", "Quantize": "Quantizzare", - "Dry Run": "Esecuzione a vuoto (Debug)", - "NEW!": "NUOVO!", - "Premium Fantasy Card Template": "Premium Fantasy Card Template", - "is now available.": "è ora disponibile.", - "Generate a wide variety of creatures and characters in the style of a fantasy card game. Perfect for heroes, animals, monsters, and even crazy hybrids.": "Genera un'ampia varietà di creature e personaggi nello stile di un gioco di carte fantasy. Perfetto per eroi, animali, mostri e persino ibridi incredibili.", - "Learn More ➜": "Per saperne di più ➜", - "Purchases help fund the continued development of Unprompted. Thank you for your support!": "Gli acquisti aiutano a finanziare il continuo sviluppo di Unprompted. Grazie per il vostro sostegno!", "X type": "Parametro asse X", "Nothing": "Niente", "Var. seed": "Seme della variazione", @@ -347,8 +499,8 @@ "Prompt words after artist or style name": "Parole chiave dopo il nome dell'artista o dello stile", "Negative Prompt": "Prompt negativo", "Save": "Salva", - "Send to img2img": "Invia a img2img", - "Send to inpaint": "Invia a Inpaint", + "Send to img2img": "Invia a\nimg2img", + "Send to inpaint": "Invia a\nInpaint", "Send to extras": "Invia a Extra", "Make Zip when Save?": "Crea un file ZIP quando si usa 'Salva'", "Textbox": "Casella di testo", @@ -381,7 +533,7 @@ "Just resize": "Ridimensiona solamente", "Crop and resize": "Ritaglia e ridimensiona", "Resize and fill": "Ridimensiona e riempie", - "Advanced loopback": "Advanced loopback", + "Advanced loopback": "Elaborazione ricorsiva avanzata", "External Image Masking": "Immagine esterna per la mascheratura", "img2img alternative test": "Test alternativo per img2img", "img2tiles": "img2tiles", @@ -408,9 +560,9 @@ "Saturation enhancement per image": "Miglioramento della saturazione per ciascuna immagine", "Use sine denoising strength variation": "Utilizzare la variazione sinusoidale dell'intensità di riduzione del rumore", "Phase difference": "Differenza di Fase", - "Denoising strength exponentiation": "Esponenziazione dell'intensità di riduzione del rumore", + "Denoising strength exponentiation": "Esponente intensità denoising", "Use sine zoom variation": "Usa la variazione sinusoidale dello zoom", - "Zoom exponentiation": "Esponeniazione dello Zoom", + "Zoom exponentiation": "Esponente Zoom", "Use multiple prompts": "Usa prompt multipli", "Same seed per prompt": "Stesso seme per ogni prompt", "Same seed for everything": "Stesso seme per tutto", @@ -460,7 +612,7 @@ "right": "destra", "up": "sopra", "down": "sotto", - "Fall-off exponent (lower=higher detail)": "Esponente di decremento (più basso=maggior dettaglio)", + "Fall-off exponent (lower=higher detail)": "Esponente di decremento (più basso = maggior dettaglio)", "Color variation": "Variazione di colore", "Will upscale the image to twice the dimensions; use width and height sliders to set tile size": "Aumenterà l'immagine al doppio delle dimensioni; utilizzare i cursori di larghezza e altezza per impostare la dimensione della piastrella", "Upscaler": "Ampliamento immagine", @@ -523,7 +675,7 @@ "CodeFormer visibility": "Visibilità CodeFormer", "CodeFormer weight (0 = maximum effect, 1 = minimum effect)": "Peso di CodeFormer (0 = effetto massimo, 1 = effetto minimo)", "Upscale Before Restoring Faces": "Amplia prima di restaurare i volti", - "Send to txt2img": "Invia a txt2img", + "Send to txt2img": "Invia a\ntxt2img", "A merger of the two checkpoints will be generated in your": "I due checkpoint verranno fusi nella cartella dei", "checkpoint": "checkpoint", "directory.": ".", @@ -623,20 +775,75 @@ "Train Embedding": "Addestra Incorporamento", "Create an aesthetic embedding out of any number of images": "Crea un'incorporamento estetico da qualsiasi numero di immagini", "Create images embedding": "Crea incorporamento di immagini", + "Generate Krita Plugin Symlink Command": "Genera comando per creare collegamento simbolico del plugin Krita", + "Launch Krita.": "Avvia Krita.", + "On the menubar, go to": "Sulla barra dei menu, vai a", + "Settings > Manage Resources...": "Settings > Manage Resources...", + "In the window that appears, click": "Nella finestra che appare, fai clic su", + "Open Resource Folder": "Open Resource Folder", + "In the file explorer that appears, look for a folder called": "In Esplora file, una volta aperto, cerca una cartella chiamata", + "pykrita": "pykrita", + "or create it.": "o creala.", + "Enter the": "Entra nella", + "folder and copy the folder location from the address bar.": "cartella e copia il percorso della cartella dalla barra degli indirizzi.", + "Paste the folder location below.": "Incolla il percorso della cartella qui di seguito.", + "Pykrita Folder Location": "Posizione della cartella Pykrita", + "Search for \"Command Prompt\" in the Start Menu, right-click and click \"Run as Administrator...\", paste the follow commands and hit Enter:": "Cerca \"Prompt dei comandi\" nel menu Start, fai clic con il pulsante destro del mouse e fai clic su \"Esegui come amministratore...\", incolla i seguenti comandi e premi Invio:", + "mklink /j \"\\krita_diff\" \"C:\\stable-diffusion-webui\\extensions\\auto-sd-paint-ext\\frontends\\krita\\krita_diff\"\nmklink \"\\krita_diff.desktop\" \"C:\\stable-diffusion-webui\\extensions\\auto-sd-paint-ext\\frontends\\krita\\krita_diff.desktop\"": "mklink /j \"\\krita_diff\" \"C:\\stable-diffusion-webui\\extensions\\auto-sd-paint-ext\\frontends\\krita\\krita_diff\"\nmklink \"\\krita_diff.desktop\" \"C:\\stable-diffusion-webui\\extensions\\auto-sd-paint-ext\\frontends\\krita\\krita_diff.desktop\"", + "Linux command:": "comando Linux:", + "ln -s \"C:\\stable-diffusion-webui\\extensions\\auto-sd-paint-ext\\frontends\\krita\\krita_diff\" \"/krita_diff\"\nln -s \"C:\\stable-diffusion-webui\\extensions\\auto-sd-paint-ext\\frontends\\krita\\krita_diff.desktop\" \"/krita_diff.desktop\"": "ln -s \"C:\\stable-diffusion-webui\\extensions\\auto-sd-paint-ext\\frontends\\krita\\krita_diff\" \"/krita_diff\"\nln -s \"C:\\stable-diffusion-webui\\extensions\\auto-sd-paint-ext\\frontends\\krita\\krita_diff.desktop\" \"/krita_diff.desktop\"", + "NOTE": "NOTE", + ": Symlinks will break if you move or rename the repository or any\nof its parent folders or otherwise change the path such that the symlink\nbecomes invalid. In which case, repeat the above steps with the new": ": I collegamenti simbolici si interrompono se si sposta o si rinomina il repository o una qualsiasi\n delle sue cartelle principali o si modifica in altro modo il percorso in modo tale che il collegamento simbolico\ndiventi non valido. In tal caso, ripetere i passaggi precedenti con il nuovo ", + "folder location and (auto-detected) repository location.": "percorso della cartella e percorso del repository (rilevato automaticamente).", + ": Ensure": ": Assicurarsi che", + "webui-user.bat": "webui-user.bat", + "/": "/", + "webui-user.sh": "webui-user.sh", + "contains": "contenga", + "--api": "--api", + "in": "in", + "COMMANDLINE_ARGS": "COMMANDLINE_ARGS", + "!": "!", + "Enabling the Krita Plugin": "Abilitazione del plugin Krita", + "Restart Krita.": "Riavvia Krita.", + "Settings > Configure Krita...": "Settings > Configure Krita...", + "On the left sidebar, go to": "Nella barra laterale sinistra, vai a", + "Python Plugin Manager": "Python Plugin Manager", + "Look for": "Cerca", + "Stable Diffusion Plugin": "Stable Diffusion Plugin", + "and tick the checkbox.": "e spunta la casella.", + "Restart Krita again for changes to take effect.": "Riavvia Krita per rendere effettive le modifiche.", + "The": "Il", + "SD Plugin": "SD Plugin", + "docked window should appear on the left of the Krita window. If it does not, look on the menubar under": "dovrebbe apparire come finestra ancorata a sinistra della finestra di Krita. In caso contrario, guarda nella barra dei menu sotto", + "Settings > Dockers": "Settings > Dockers", + "for": "per", + "Next Steps": "Prossimi passi", + "Troubleshooting": "Risoluzione dei problemi", + "Update Guide": "Guida all'aggiornamento", + "Usage Guide": "Guida all'uso", + "TODO: Control/status panel": "TODO: pannello di controllo/stato", "-1": "-1", "This extension works well with text captions in comma-separated style (such as the tags generated by DeepBooru interrogator).": "Questa estensione funziona bene con i sottotitoli di testo in stile separato da virgole (come i tag generati dall'interrogatore DeepBooru).", "Save all changes": "Salva tutte le modifiche", "Backup original text file (original file will be renamed like filename.000, .001, .002, ...)": "Backup del file di testo originale (il file originale verrà rinominato come nomefile.000, .001, .002, ...)", "Note:": "Note:", - "New text file will be created if you are using filename as captions.": "Verrà creato un nuovo file di testo se si utilizza il nome del file come didascalia.", + "New text file will be created if you are using filename as captions.": " Verrà creato un nuovo file di testo se si utilizza il nome del file come didascalia.", "Results": "Risultati", "Load": "Carica", + "Load from subdirectories": "Carica da sotto cartella", "Dataset Images": "Immagini del Dataset", + "Displayed Images : 0 / 0 total": "Immagini mostrate : 0 / 0 totali", + "Current Tag Filter :": "Filtro Tag corrente :", + "Current Selection Filter : 0 images": "Filtro di selezione corrente : 0 immagini", + "Selected Image :": "Immagine selezionata :", "Filter and Edit Tags": "Filtra e modifica i tag", + "Filter by Selection": "Filtra per selezione", "Edit Caption of Selected Image": "Modifica la didascalia dell'immagine selezionata", "Search tags / Filter images by tags": "Cerca tag / Filtra le immagini per tag", "Search Tags": "Cerca tag", - "Clear all filters": "Rimuovi tutti i filtri", + "Clear tag filters": "Cancella i filtri dei tag", + "Clear ALL filters": "Rimuovi tutti i filtri", "Sort by": "Ordina per", "Alphabetical Order": "Ordine alfabetico", "Frequency": "Frequenza", @@ -664,6 +871,13 @@ "ex C.": "esempio C.", "Original Text = \"A, B, C, D, E\" Selected Tags = \"A, B, D\" Edit Tags = \", X, \"": "Testo originale = \"A, B, C, D, E\" Tag selezionati = \"A, B, D\" Modifica tag = \", X, \"", "Result = \"X, C, E\" (A->\"\", B->X, D->\"\")": "Risultato = \"X, C, E\" (A->\"\", B->X, D->\"\")", + "Select images from the left gallery.": "Seleziona le immagini dalla galleria di sinistra.", + "Add selection [Enter]": "Aggiungi selezione [Invio]", + "Filter Images": "Filtra le immagini", + "Remove selection [Delete]": "Rimuovi selezione [Canc]", + "Invert selection": "Inverti selezione", + "Clear selection": "Cancella selezione", + "Apply selection filter": "Applica il filtro di selezione", "Caption of Selected Image": "Didascalia dell'immagine selezionata", "Copy caption": "Copia didascalia", "Edit Caption": "Modifica didascalia", @@ -768,7 +982,7 @@ "bilinear": "bilinear", "nearest": "nearest", "save_depth_maps": "Salva le mappe di profondità", - "`animation_mode: None` batches on list of *prompts*. (Batch mode disabled atm, only animation_prompts are working)": "`modalità animazione: Nessuno` si inserisce nell'elenco di *prompt*. (Modalità batch disabilitata atm, funzionano solo i prompt di animazione)", + "`animation_mode: None` batches on list of *prompts*. (Batch mode disabled atm, only animation_prompts are working)": "`modalità animazione: Nessuno` si inserisce nell'elenco di *prompt*. (Modalità batch al momento disabilitata, funzionano solo i prompt di animazione)", "*Important change from vanilla Deforum!*": "*Importante cambiamento rispetto alla versione originale di Deforum!*", "This script uses the built-in webui weighting settings.": "Questo script utilizza le impostazioni di pesatura webui integrate.", "So if you want to use math functions as prompt weights,": "Quindi, se vuoi usare le funzioni matematiche come pesi dei prompt,", @@ -783,12 +997,16 @@ "strength": "Intensità", "init_image": "Immagine di inizializzazione", "use_mask": "Usa maschera", - "use_alpha_as_mask": "Usa alpha come maschera", + "use_alpha_as_mask": "Usa Alpha come maschera", "invert_mask": "Inverti la maschera", "overlay_mask": "Sovrapponi la maschera", "mask_file": "File della maschera", + "mask_contrast_adjust": "regolazione contrasto maschera", "mask_brightness_adjust": "Regola la luminosità della maschera", "mask_overlay_blur": "Sfocatura della sovrapposizione della maschera", + "mask_fill": "riempimento maschera", + "full_res_mask": "maschera a piena risoluzione", + "full_res_mask_padding": "riempimento maschera a piena risoluzione", "Video Input:": "Ingresso video:", "video_init_path": "Percorso del video di inizializzazione", "extract_nth_frame": "Estrai ogni ennesimo fotogramma", @@ -819,6 +1037,7 @@ "image_path": "Percorso immagine", "mp4_path": "Percorso MP4", "Click here after the generation to show the video": "Clicca qui dopo la generazione per mostrare il video", + "Close the video": "Chiudi il video", "NOTE: If the 'Generate' button doesn't work, go in Settings and click 'Restart Gradio and Refresh...'.": "NOTA: se il pulsante 'Genera' non funziona, vai in Impostazioni e fai clic su 'Riavvia Gradio e Aggiorna...'.", "Save Settings": "Salva le impostazioni", "Load Settings": "Carica le impostazioni", @@ -829,7 +1048,6 @@ "house": "casa", "portrait": "ritratto", "spaceship": "nave spaziale", - "anime": "anime", "cartoon": "cartoon", "digipa-high-impact": "digipa-high-impact", "digipa-med-impact": "digipa-med-impact", @@ -936,8 +1154,8 @@ "set_index": "Imposta indice", "load_switch": "Carica", "turn_page_switch": "Volta pagina", - "Checkbox": "Casella di controllo", - "Checkbox Group": "Seleziona immagini per", + "Checkbox": "Selezione", + "Checkbox Group": "Seleziona per", "artists": "Artisti", "flavors": "Stili", "mediums": "Tecniche", @@ -947,12 +1165,24 @@ "Abandoned": "Scartati", "Key word": "Parola chiave", "Get inspiration": "Ispirami", - "to txt2img": "Invia a txt2img", - "to img2img": "Invia a img2img", + "to txt2img": "Invia a\ntxt2img", + "to img2img": "Invia a\nimg2img", "Collect": "Salva nei preferiti", "Don't show again": "Scarta", "Move out": "Rimuovi", - "set button": "Pulsante imposta", + "set button": "Pulsante imposta", + "Before your text is sent to the neural network, it gets turned into numbers in a process called tokenization. These tokens are how the neural network reads and interprets text. Thanks to our great friends at Shousetsu愛 for inspiration for this feature.": "Prima che il tuo testo venga inviato alla rete neurale, verrà trasformato in numeri in un processo chiamato tokenizzazione. Questi token sono il modo in cui la rete neurale legge e interpreta il testo. Grazie ai nostri grandi amici di Shousetsu愛 per l'ispirazione per questa funzione.", + "Tokenize": "Tokenizzare", + "Text": "Testo", + "Tokens": "Token", + "Video to extract frames from:": "Video da cui estrarre fotogrammi:", + "Only extract keyframes (recommended)": "Estrae solo fotogrammi chiave (consigliato)", + "Extract Frames": "Estrai fotogrammi", + "Extracted Frame Set": "Set di fotogrammi estratti", + "Resize crops to 512x512": "Ridimensiona i ritagli a 512x512", + "Save crops to:": "Salva ritagli in:", + "<": "<", + ">": ">", "Apply settings": "Applica le impostazioni", "Saving images/grids": "Salva immagini/griglie", "Always save all generated images": "Salva sempre tutte le immagini generate", @@ -1007,6 +1237,7 @@ "Add a second progress bar to the console that shows progress for an entire job.": "Aggiungi una seconda barra di avanzamento alla console che mostra l'avanzamento complessivo del lavoro.", "Training": "Addestramento", "Move VAE and CLIP to RAM when training hypernetwork. Saves VRAM.": "Sposta VAE e CLIP nella RAM durante l'addestramento di Iperreti. Risparmia VRAM.", + "Saves Optimizer state as separate *.optim file. Training can be resumed with HN itself and matching optim file.": "Salva lo stato dell'ottimizzatore come file *.optim separato. L'addestramento può essere ripreso con lo stesso HN e il file optim corrispondente.", "Filename word regex": "Espressione regolare per estrarre parole dal nome del file", "Filename join string": "Stringa per unire le parole estratte dal nome del file", "Number of repeats for a single input image per epoch; used only for displaying epoch number": "Numero di ripetizioni per una singola immagine di input per epoca; utilizzato solo per visualizzare il numero di epoca", @@ -1111,10 +1342,14 @@ "aesthetic-gradients": "Gradienti Estetici (CLIP)", "https://github.com/AUTOMATIC1111/stable-diffusion-webui-aesthetic-gradients": "https://github.com/AUTOMATIC1111/stable-diffusion-webui-aesthetic-gradients", "unknown": "sconosciuto", + "auto-sd-paint-ext": "KRITA Plugin", + "https://github.com/Interpause/auto-sd-paint-ext": "https://github.com/Interpause/auto-sd-paint-ext", "dataset-tag-editor": "Dataset Tag Editor", "https://github.com/toshiaki1729/stable-diffusion-webui-dataset-tag-editor.git": "https://github.com/toshiaki1729/stable-diffusion-webui-dataset-tag-editor.git", "deforum-for-automatic1111-webui": "Deforum", "https://github.com/deforum-art/deforum-for-automatic1111-webui": "https://github.com/deforum-art/deforum-for-automatic1111-webui", + "novelai-2-local-prompt": "Converti NovelAI", + "https://github.com/animerl/novelai-2-local-prompt": "https://github.com/animerl/novelai-2-local-prompt", "sd-dynamic-prompts": "Prompt dinamici", "https://github.com/adieyal/sd-dynamic-prompts": "https://github.com/adieyal/sd-dynamic-prompts", "stable-diffusion-webui-aesthetic-image-scorer": "Punteggio immagini estetiche", @@ -1125,8 +1360,14 @@ "https://github.com/yfszzx/stable-diffusion-webui-images-browser": "https://github.com/yfszzx/stable-diffusion-webui-images-browser", "stable-diffusion-webui-inspiration": "Ispirazione", "https://github.com/yfszzx/stable-diffusion-webui-inspiration": "https://github.com/yfszzx/stable-diffusion-webui-inspiration", + "stable-diffusion-webui-tokenizer": "Tokenizzatore", + "https://github.com/AUTOMATIC1111/stable-diffusion-webui-tokenizer.git": "https://github.com/AUTOMATIC1111/stable-diffusion-webui-tokenizer.git", "tag-autocomplete": "Autocompletamento etichette", "https://github.com/DominikDoom/a1111-sd-webui-tagcomplete.git": "https://github.com/DominikDoom/a1111-sd-webui-tagcomplete.git", + "training-picker": "Selezionatore per l'addestramento", + "https://github.com/Maurdekye/training-picker.git": "https://github.com/Maurdekye/training-picker.git", + "unprompted": "Unprompted", + "https://github.com/ThereforeGames/unprompted": "https://github.com/ThereforeGames/unprompted", "wildcards": "Termini Jolly", "https://github.com/AUTOMATIC1111/stable-diffusion-webui-wildcards.git": "https://github.com/AUTOMATIC1111/stable-diffusion-webui-wildcards.git", "Load from:": "Carica da:", @@ -1161,7 +1402,8 @@ "Make an attempt to produce a picture similar to what would have been produced with same seed at specified resolution": "Prova a produrre un'immagine simile a quella che sarebbe stata prodotta con lo stesso seme alla risoluzione specificata", "This text is used to rotate the feature space of the imgs embs": "Questo testo viene utilizzato per ruotare lo spazio delle funzioni delle immagini incorporate", "How many times to repeat processing an image and using it as input for the next iteration": "Quante volte ripetere l'elaborazione di un'immagine e utilizzarla come input per l'iterazione successiva", - "Hello, StylePile here.\nUntil some weird bug gets fixed you will see this even if the script itself is not active. Meanwhile, some hints to take your artwork to new heights:\nUse the 'Focus on' dropdown to select complex presets. Toggle selections below (with or without Focus) to affect your results. Mix and match to get some interesting results. \nAnd some general Stable Diffusion tips that will take your designs to next level:\nYou can add parenthesis to make parts of the prompt stronger. So (((cute))) kitten will make it extra cute (try it out). This is alsow important if a style is affecting your original prompt too much. Make that prompt stronger by adding parenthesis around it, like this: ((promt)).\nYou can type promts like [A|B] to sequentially use terms one after another on each step. So, like [cat|dog] will produce a hybrid catdog. And [A:B:0.4] to switch to other terms after the first one has been active for a certain percentage of steps. So [cat:dog:0.4] will build a cat 40% of the time and then start turning it into a dog. This needs more steps to work properly.": "Salve, qui è StylePile.\nFinché qualche strano bug non verrà risolto, vedrai questo testo anche se lo script non è attivo. Nel frattempo, alcuni suggerimenti per portare la tua grafica a nuovi livelli:\nUtilizza il menu a discesa 'Focus on' per selezionare valori predefiniti complessi. Attiva o disattiva le selezioni seguenti (con o senza Focus) per influire sui risultati. Mescola e abbina per ottenere risultati interessanti. \nE alcuni suggerimenti generali su Stable Diffusion che porteranno i tuoi risultati a un livello superiore:\nPuoi aggiungere parentesi per aumentare l'influenza di certe parti del prompt. Quindi '(((cute))) kitten' lo renderà molto carino (fai delle prove). Questo è importante quando uno stile influisce troppo sul prompt originale. Rendi più forte quel prompt aggiungendo delle parentesi intorno ad esso, così: ((promt)).\nPuoi digitare prompt nel formato [A|B] per usare in sequenza i termini uno dopo l'altro in ogni passaggio. Quindi, come [cat|dog] produrrà un 'canegatto' ibrido. E [A:B:0.4] per passare ad altri termini dopo che il primo è stato attivo per una certa percentuale di passaggi. Quindi [cat:dog:0.4] genererà un gatto il 40% dei passaggi e poi inizierà a trasformarlo in un cane. Sono richiesti più passaggi perchè funzioni correttamente.", + "Insert [X] anywhere in main prompt to sequentially insert values from here.": "Inserisci [X] ovunque nel prompt principale per inserire in sequenza i valori da qui.", + "Insert [R] anywhere in main prompt to randomly insert values from here.": "Inserisci [R] ovunque nel prompt principale per inserire i valori in modo casuale da qui.", "Enter one prompt per line. Blank lines will be ignored.": "Immettere un prompt per riga. Le righe vuote verranno ignorate.", "Separate values for X axis using commas.": "Separare i valori per l'asse X usando le virgole.", "Separate values for Y axis using commas.": "Separare i valori per l'asse Y usando le virgole.", @@ -1188,8 +1430,10 @@ "1st and last digit must be 1. ex:'1, 2, 1'": "La prima e l'ultima cifra devono essere 1. Es.:'1, 2, 1'", "Path to directory with input images": "Percorso della cartella con immagini di input", "Path to directory where to write outputs": "Percorso della cartella in cui scrivere i risultati", + "C:\\\\...\\pykrita": "C:\\\\...\\pykrita", "C:\\directory\\of\\datasets": "C:\\cartella\\del\\dataset", "Input images directory": "Cartella di input delle immagini", + "Prompt for tokenization": "Prompt for tokenization", "Use following tags to define how filenames for images are chosen: [steps], [cfg], [prompt], [prompt_no_styles], [prompt_spaces], [width], [height], [styles], [sampler], [seed], [model_hash], [prompt_words], [date], [datetime], [job_timestamp]; leave empty for default.": "Usa i seguenti tag per definire come vengono scelti i nomi dei file per le immagini: [steps], [cfg], [prompt], [prompt_no_styles], [prompt_spaces], [width], [height], [styles], [sampler], [seed ], [model_hash], [prompt_words], [date], [datetime], [job_timestamp]; lasciare vuoto per usare l'impostazione predefinita.", "If this option is enabled, watermark will not be added to created images. Warning: if you do not add watermark, you may be behaving in an unethical manner.": "Se questa opzione è abilitata, la filigrana non verrà aggiunta alle immagini create. Attenzione: se non aggiungi la filigrana, potresti comportarti in modo non etico.", "Use following tags to define how subdirectories for images and grids are chosen: [steps], [cfg], [prompt], [prompt_no_styles], [prompt_spaces], [width], [height], [styles], [sampler], [seed], [model_hash], [prompt_words], [date], [datetime], [job_timestamp]; leave empty for default.": "Utilizzare i seguenti tag per definire come vengono scelte le sottodirectory per le immagini e le griglie: [steps], [cfg], [prompt], [prompt_no_styles], [prompt_spaces], [width], [height], [styles], [sampler], [seed], [model_hash], [prompt_words], [date], [datetime], [job_timestamp]; lasciare vuoto per usare l'impostazione predefinita.", @@ -1200,24 +1444,103 @@ "List of setting names, separated by commas, for settings that should go to the quick access bar at the top, rather than the usual setting tab. See modules/shared.py for setting names. Requires restarting to apply.": "Elenco dei nomi delle impostazioni, separati da virgole, per le impostazioni che dovrebbero essere visualizzate nella barra di accesso rapido in alto, anziché nella normale scheda delle impostazioni. Vedi modules/shared.py per impostare i nomi. Richiede il riavvio per applicare.", "If this values is non-zero, it will be added to seed and used to initialize RNG for noises when using samplers with Eta. You can use this to produce even more variation of images, or you can use this to match images of other software if you know what you are doing.": "Se questo valore è diverso da zero, verrà aggiunto al seed e utilizzato per inizializzare il generatore di numeri casuali per il rumore quando si utilizzano campionatori con ETA. Puoi usarlo per produrre ancora più variazioni di immagini, oppure puoi usarlo per abbinare le immagini di altri software se sai cosa stai facendo.", "Leave empty for auto": "Lasciare vuoto per automatico", + "NAIConvert": "Converti\nNovelAI", + "History": "Crononolgia", + "specify a custom settings file and ignore settings displayed in the interface": "specificare un file di impostazioni personalizzate e ignorare le impostazioni visualizzate nell'interfaccia", + "the path to a custom settings file": "il percorso di un file delle impostazioni personalizzate", + "The width of the output images, in pixels (must be a multiple of 64)": "La larghezza delle immagini di output, in pixel (deve essere un multiplo di 64)", + "The height of the output images, in pixels (must be a multiple of 64)": "L'altezza delle immagini di output, in pixel (deve essere un multiplo di 64)", + "enable additional seed settings": "abilitare impostazioni seme aggiuntive", + "How many times to improve the generated image iteratively; higher values take longer; very low values can produce bad results": "Quante volte migliorare l'immagine generata in modo iterativo; valori più alti richiedono più tempo; valori molto bassi possono produrre risultati negativi", + "output images will be placed in a folder with this name, inside of the img2img output folder": "le immagini di output verranno collocate in una cartella con questo nome, all'interno della cartella di output img2img", + "specify the format of the filename for output images": "specificare il formato del nome file per le immagini di output", + "defines the seed behavior that is used for animations": "definisce il comportamento del seme utilizzato per le animazioni", + "the seed value will increment by 1 for each subsequent frame of the animation": "il valore del seme aumenterà di 1 per ogni fotogramma successivo dell'animazione", + "selects the type of animation": "seleziona il tipo di animazione", + "only 2D motion parameters will be used, but this mode uses the least amount of VRAM. You can optionally enable flip_2d_perspective to enable some psuedo-3d animation parameters while in 2D mode.": "verranno utilizzati solo i parametri di movimento 2D, ma questa modalità utilizza la quantità minima di VRAM. Puoi facoltativamente abilitare flip_2d_perspective per abilitare alcuni parametri di animazione psuedo-3d mentre sei in modalità 2D.", + "the maximum number of output images to be created": "il numero massimo di immagini di output da creare", + "controls handling method of pixels to be generated when the image is smaller than the frame.": "controlla il metodo di gestione dei pixel da generare quando l'immagine è più piccola del fotogramma.", + "repeats the edge of the pixels, and extends them. Animations with quick motion may yield lines where this border function was attempting to populate pixels into the empty space created.": "ripete il bordo dei pixel e li estende. Le animazioni con movimento rapido possono produrre linee in cui questa funzione di bordo stava tentando di popolare i pixel nello spazio vuoto creato.", + "2D operator to rotate canvas clockwise/anticlockwise in degrees per frame": "Operatore 2D per ruotare la tela in senso orario/antiorario in gradi per fotogramma", + "2D operator that scales the canvas size, multiplicatively. [static = 1.0]": "Operatore 2D che ridimensiona le dimensioni della tela, in modo moltiplicativo. [statico = 1.0]", + "2D & 3D operator to move canvas left/right in pixels per frame": "Operatore 2D e 3D per spostare la tela a sinistra/destra in pixel per fotogramma", + "2D & 3D operator to move canvas up/down in pixels per frame": "Operatore 2D e 3D per spostare la tela su/giù in pixel per fotogramma", + "3D operator to move canvas towards/away from view [speed set by FOV]": "Operatore 3D per spostare la tela da/verso la visuale [velocità impostata da FOV]", + "3D operator to tilt canvas up/down in degrees per frame": "Operatore 3D per inclinare la tela su/giù in gradi per fotogramma", + "3D operator to pan canvas left/right in degrees per frame": "Operatore 3D per eseguire una panoramica della tela a sinistra/destra in gradi per fotogramma", + "3D operator to roll canvas clockwise/anticlockwise": "Operatore 3D per ruotare la tela in senso orario/antiorario", + "enables 2D mode functions to simulate faux 3D movement": "abilita le funzioni della modalità 2D per simulare falsi movimenti 3D", + "the roll effect angle": "l'angolo dell'effetto di rollio", + "the tilt effect angle": "l'angolo dell'effetto di inclinazione", + "the pan effect angle": "l'angolo dell'effetto panoramica", + "the 2D vanishing point of perspective (recommended range 30-160)": "il punto di fuga prospettico 2D (intervallo consigliato 30-160)", + "amount of graininess to add per frame for diffusion diversity": "quantità di granulosità da aggiungere per fotogramma per la diversità di diffusione", + "amount of presence of previous frame to influence next frame, also controls steps in the following formula [steps - (strength_schedule * steps)]": "quantità di presenza del fotogramma precedente per influenzare il fotogramma successivo, controlla anche i passaggi nella seguente formula [passi - (forza pianificazione * steps)]", + "adjusts the overall contrast per frame [default neutral at 1.0]": "regola il contrasto generale per fotogramma [neutro predefinito a 1.0]", + "how closely the image should conform to the prompt. Lower values produce more creative results. (recommended range 5-15)": "quanto l'immagine deve essere conforme al prompt. Valori più bassi producono risultati più creativi. (intervallo consigliato 5-15)", + "adjusts the scale at which the canvas is moved in 3D by the translation_z value. [maximum range -180 to +180, with 0 being undefined. Values closer to 180 will make the image have less depth, while values closer to 0 will allow more depth]": "regola la scala alla quale la tela viene spostata in 3D in base al valore traslazione_z. [intervallo massimo da -180 a +180, con 0 non definito. Valori più vicini a 180 renderanno l'immagine meno profonda, mentre valori più vicini a 0 consentiranno una maggiore profondità]", + "allows you to specify seeds at a specific schedule, if seed_behavior is set to schedule.": "ti consente di specificare i semi in base a una pianificazione specifica, se seed_behavior è impostato su pianificazione.", + "The color coherence will attempt to sample the overall pixel color information, and trend those values analyzed in the first frame to be applied to future frames.": "La coerenza del colore tenterà di campionare le informazioni complessive sul colore dei pixel e tendere quei valori analizzati nel primo fotogramma da applicare ai fotogrammi futuri.", + "LAB is a more linear approach to mimic human perception of color space - a good default setting for most users.": "LAB è un approccio più lineare per imitare la percezione umana dello spazio colore, una buona impostazione predefinita per la maggior parte degli utenti.", + "The default setting of 1 will cause every frame to receive diffusion in the sequence of image outputs. A setting of 2 will only diffuse on every other frame, yet motion will still be in effect. The output of images during the cadence sequence will be automatically blended, additively and saved to the specified drive. This may improve the illusion of coherence in some workflows as the content and context of an image will not change or diffuse during frames that were skipped. Higher values of 4-8 cadence will skip over a larger amount of frames and only diffuse the “Nth” frame as set by the diffusion_cadence value. This may produce more continuity in an animation, at the cost of little opportunity to add more diffused content. In extreme examples, motion within a frame will fail to produce diverse prompt context, and the space will be filled with lines or approximations of content - resulting in unexpected animation patterns and artifacts. Video Input & Interpolation modes are not affected by diffusion_cadence.": "L'impostazione predefinita di 1 farà sì che ogni fotogramma riceva la diffusione nella sequenza di output delle immagini. Un'impostazione di 2 si diffonderà solo su ogni altro fotogramma, ma il movimento sarà comunque attivo. L'output delle immagini durante la sequenza di cadenza verrà automaticamente miscelato, additivato e salvato nell'unità specificata. Ciò può migliorare l'illusione di coerenza in alcuni flussi di lavoro poiché il contenuto e il contesto di un'immagine non cambiano o si diffondono durante i fotogrammi che sono stati ignorati. Valori più alti di 4-8 cadenza salteranno una quantità maggiore di fotogrammi e diffonderanno solo il fotogramma 'Nth' come impostato dal valore di diffusione_cadenza. Ciò può produrre più continuità in un'animazione, a costo di poche opportunità di aggiungere contenuti più diffusi. In esempi estremi, il movimento all'interno di un fotogramma non riuscirà a produrre un contesto di richiesta diverso e lo spazio sarà riempito con linee o approssimazioni di contenuto, risultando in modelli di animazione e artefatti inaspettati. Le modalità di ingresso video e interpolazione non sono influenzate da diffusion_cadence.", + "enables instructions to warp an image dynamically in 3D mode only.": "abilita le istruzioni per deformare un'immagine dinamicamente solo in modalità 3D.", + "sets a midpoint at which a depthmap is to be drawn: range [-1 to +1]": "imposta un punto medio in cui deve essere disegnata una mappa di profondità: range [da -1 a +1]", + "instructs the handling of pixels outside the field of view as they come into the scene.": "indica la gestione dei pixel al di fuori del campo visivo quando entrano nella scena.", + "choose from Bicubic, Bilinear or Nearest modes. (Recommended: Bicubic)": "scegliere tra le modalità Bicubico, Bilineare o Più vicino. (Consigliato: Bicubico)", + "will output a greyscale depth map image alongside the output images.": "produrrà un'immagine della mappa di profondità in scala di grigi insieme alle immagini di output.", + "Diffuse the first frame based on an image, similar to img2img.": "Diffondi il primo fotogramma in base a un'immagine, simile a img2img.", + "Set the strength to 0 automatically when no init image is used": "Imposta automaticamente l'intensità su 0 quando non viene utilizzata alcuna immagine iniziale", + "Controls the strength of the diffusion on the init image. 0 = disabled": "Controlla l'intensità della diffusione sull'immagine iniziale 0 = disabilitato", + "the path to your init image": "il percorso alla tua immagine iniziale", + "Use a grayscale image as a mask on your init image. Whiter areas of the mask are areas that change more.": "Usa un'immagine in scala di grigi come maschera sull'immagine iniziale. Le aree più bianche della maschera sono aree che cambiano di più.", + "use the alpha channel of the init image as the mask": "usa il canale alfa dell'immagine iniziale come maschera", + "Inverts the colors of the mask": "Inverte i colori della maschera", + "Overlay the masked image at the end of the generation so it does not get degraded by encoding and decoding": "Sovrapponi l'immagine mascherata alla fine della generazione in modo che non venga degradata dalla codifica e dalla decodifica", + "the path to your mask image": "il percorso per l'immagine della maschera", + "adjust the brightness of the mask. Should be a positive number, with 1.0 meaning no adjustment.": "regola la luminosità della maschera. Dovrebbe essere un numero positivo, con 1.0 che significa nessuna correzione.", + "Blur edges of final overlay mask, if used. Minimum = 0 (no blur)": "Sfoca i bordi della maschera di sovrapposizione finale, se utilizzata. Minimo = 0 (nessuna sfocatura)", + "the directory at which your video file is located for Video Input mode only.": "la cartella in cui si trova il file video per la modalità solo Ingresso video.", + "during the run sequence, only frames specified by this value will be extracted, saved, and diffused upon. A value of 1 indicates that every frame is to be accounted for. Values of 2 will use every other frame for the sequence. Higher values will skip that number of frames respectively.": "durante la sequenza di esecuzione, verranno estratti, salvati e diffusi solo i frame specificati da questo valore. Un valore di 1 indica che deve essere contabilizzato ogni frame. I valori di 2 utilizzeranno ogni altro fotogramma per la sequenza. Valori più alti salteranno rispettivamente quel numero di fotogrammi.", + "when enabled, will re-extract video frames each run. When using video_input mode, the run will be instructed to write video frames to the drive. If you’ve already populated the frames needed, uncheck this box to skip past redundant extraction, and immediately start the render. If you have not extracted frames, you must run at least once with this box checked to write the necessary frames.": "quando abilitato, estrarrà nuovamente i fotogrammi video ad ogni esecuzione. Quando si utilizza la modalità Ingresso video, all'esecuzione verrà richiesto di scrivere fotogrammi video sull'unità. Se avete già popolato i fotogrammi necessari, deselezionate questa casella per saltare l'estrazione ridondante e avviare immediatamente il rendering. Se non sono stati estratti i frame, è necessario eseguire almeno una volta l'operazione con questa casella selezionata per scrivere i fotogrammi necessari.", + "video_input mode only, enables the extraction and use of a separate video file intended for use as a mask. White areas of the extracted video frames will not be affected by diffusion, while black areas will be fully effected. Lighter/darker areas are affected dynamically.": "in modalità solo video Input, consente l'estrazione e l'utilizzo di un file video separato destinato all'uso come maschera. Le aree bianche dei fotogrammi video estratti non saranno interessate dalla diffusione, mentre le aree nere saranno interamente interessate. Le aree più chiare/scure sono interessate in modo dinamico.", + "the directory in which your mask video is located.": "la cartella in cui si trova il video della maschera.", + "selects whether to ignore prompt schedule or _x_frames.": "seleziona se ignorare la pianificazione dei prompt o _x_frames.", + "the number of frames to transition thru between prompts (when interpolate_key_frames = true, then the numbers in front of the animation prompts will dynamically guide the images based on their value. If set to false, will ignore the prompt numbers and force interpole_x_frames value regardless of prompt number)": "il numero di fotogrammi per la transizione tra i prompt (quando interpola fotogrammi chiave = true, i numeri davanti ai prompt dell'animazione guideranno dinamicamente le immagini in base al loro valore. Se impostato su false, ignorerà i numeri dei prompt e forzerà il valore di interpola x fotogrammi indipendentemente da numero di richiesta)", + "instructs the run to start from a specified point": "avvia l'esecuzione da un punto specificato", + "the required timestamp to reference when resuming. Currently only available in 2D & 3D mode, the timestamp is saved as the settings .txt file name as well as images produced during your previous run. The format follows: yyyymmddhhmmss - a timestamp of when the run was started to diffuse.": "l'orario a cui fare riferimento quando si riprende. Attualmente disponibile solo in modalità 2D e 3D, l'orario viene salvato come nome del file .txt delle impostazioni e come immagini prodotte durante la corsa precedente. Il formato segue: yyyymmddhhmmss - l'orario di quando è stata avviata la diffusione dell'esecuzione.", + "when checked, do not output a video": "se selezionato, non produce un video", + "The frames per second that the video will run at": "I fotogrammi al secondo a cui verrà eseguito il video", + "select the type of video file to output": "selezionare il tipo di file video da produrre", + "create an animated GIF": "crea una GIF animata", + "the path to where ffmpeg is located": "il percorso in cui si trova ffmpeg", + "when this box is checked, and FFMPEG mp4 is selected as the output format, an audio file will be multiplexed with the video.": "quando questa casella è selezionata e FFMPEG mp4 è selezionato come formato di output, un file audio verrà multiplexato con il video.", + "the path to an audio file to accompany the video": "tIl percorso di un file audio per accompagnare il video", + "when this is unchecked, the video will automatically be created in the same output folder as the images. Check this box to specify different settings for the creation of the video, specified by the following options": "quando questo è deselezionato, il video verrà creato automaticamente nella stessa cartella di output delle immagini. Selezionare questa casella per specificare impostazioni diverse per la creazione del video, specificate dalle seguenti opzioni", + "render each step of diffusion as a separate frame": "renderizzare ogni fase di diffusione come fotogramma separato", + "the maximum number of frames to include in the video, when use_manual_settings is checked": "il numero massimo di fotogrammi da includere nel video, quando è selezionato 'Usa impostazioni manuali'", + "the location of images to create the video from, when use_manual_settings is checked": "la posizione delle immagini da cui creare il video, quando è selezionato 'Usa impostazioni manuali'", + "the output location of the mp4 file, when use_manual_settings is checked": "il percorso di output del file mp4, quando è selezionato 'Usa impostazioni manuali'", "Autocomplete options": "Opzioni di autocompletamento", "Enable Autocomplete": "Abilita autocompletamento", "Append commas": "Aggiungi virgole", + "Error": "Errore", + "F": "F", + "Time taken:": "Tempo impiegato:", + "latest": "aggiornato", + "behind": "da aggiornare", "AlphaCanvas": "AlphaCanvas", - "Close": "Chiudi", - "Grab Results": "Ottieni risultati", - "Apply Patch": "Applica Patch", "Hue:0": "Hue:0", "S:0": "S:0", "L:0": "L:0", "Load Canvas": "Carica Canvas", "Save Canvas": "Salva Canvas", - "latest": "aggiornato", - "behind": "da aggiornare", + "Close": "Chiudi", + "Grab Results": "Ottieni risultati", + "Apply Patch": "Applica Patch", "Description": "Descrizione", "Action": "Azione", "Aesthetic Gradients": "Gradienti estetici", - "Create an embedding from one or few pictures and use it to apply their style to generated images.": "Crea un incorporamento da una o poche immagini e usalo per applicare il loro stile alle immagini generate.", + "Create an embedding from one or few pictures and use it to apply their style to generated images.": "Crea un incorporamento da una o poche immagini e lo usa per applicare il loro stile alle immagini generate.", "Sample extension. Allows you to use __name__ syntax in your prompt to get a random line from a file named name.txt in the wildcards directory. Also see Dynamic Prompts for similar functionality.": "Estensione del campione. Consente di utilizzare la sintassi __name__ nel prompt per ottenere una riga casuale da un file denominato name.txt nella cartella dei termini jolly. Vedi anche 'Prompt dinamici' per funzionalità simili.", "Dynamic Prompts": "Prompt dinamici", "Implements an expressive template language for random or combinatorial prompt generation along with features to support deep wildcard directory structures.": "Implementa un modello di linguaggio espressivo per la generazione di prompt casuale o combinatoria insieme a funzionalità per supportare cartelle strutturate contenenti termini jolly.", @@ -1226,8 +1549,17 @@ "Randomly display the pictures of the artist's or artistic genres typical style, more pictures of this artist or genre is displayed after selecting. So you don't have to worry about how hard it is to choose the right style of art when you create.": "Visualizza in modo casuale le immagini dello stile tipico dell'artista o dei generi artistici, dopo la selezione vengono visualizzate più immagini di questo artista o genere. Così non dovete preoccuparvi della difficoltà di scegliere lo stile artistico giusto quando create.", "The official port of Deforum, an extensive script for 2D and 3D animations, supporting keyframable sequences, dynamic math parameters (even inside the prompts), dynamic masking, depth estimation and warping.": "Il porting ufficiale di Deforum, uno script completo per animazioni 2D e 3D, che supporta sequenze di fotogrammi chiave, parametri matematici dinamici (anche all'interno dei prompt), mascheramento dinamico, stima della profondità e warping.", "Artists to study": "Artisti per studiare", - "Shows a gallery of generated pictures by artists separated into categories.": "Mostra una galleria di immagini generate dagli artisti suddivise in categorie.", + "Shows a gallery of generated pictures by artists separated into categories.": "Mostra una galleria di immagini generate in base agli artisti e suddivise in categorie.", "Calculates aesthetic score for generated images using CLIP+MLP Aesthetic Score Predictor based on Chad Scorer": "Calcola il punteggio estetico per le immagini generate utilizzando il predittore del punteggio estetico CLIP+MLP basato su Chad Scorer", - "Lets you edit captions in training datasets.": "Consente di modificare i sottotitoli nei set di dati di addestramento.", - "Time taken:": "Tempo impiegato:" -} + "Lets you edit captions in training datasets.": "Consente di modificare le didascalie nei set di dati di addestramento.", + "Krita Plugin.": "Krita Plugin.", + "Adds a tab to the webui that allows the user to automatically extract keyframes from video, and manually extract 512x512 crops of those frames for use in model training.": "Aggiunge una scheda all'interfaccia Web che consente all'utente di estrarre automaticamente i fotogrammi chiave dal video ed estrarre manualmente ritagli 512x512 di quei fotogrammi da utilizzare nell'addestramento del modello.", + "Allows you to include various shortcodes in your prompts. You can pull text from files, set up your own variables, process text through conditional functions, and so much more - it's like wildcards on steroids..": "Consente di includere vari codici brevi nei prompt. Puoi estrarre il testo dai file, impostare le tue variabili, elaborare il testo tramite funzioni condizionali e molto altro ancora: è come i termini jolly ma potenziato.", + "Booru tag autocompletion": "Completamento automatico del tag Booru", + "Displays autocompletion hints for tags from image booru boards such as Danbooru. Uses local tag CSV files and includes a config for customization.": "Visualizza suggerimenti per il completamento automatico dei tag dalle schede di immagini Booru, come Danbooru. Utilizza file CSV di tag locali e include una configurazione per la personalizzazione.", + "Add a button to convert the prompts used in NovelAI for use in the WebUI. In addition, add a button that allows you to recall a previously used prompt.": "Aggiunge un pulsante per convertire i prompt utilizzati in NovelAI per l'uso in Stable Diffusion Web UI. Inoltre, aggiunge un pulsante che permette di richiamare un prompt utilizzato in precedenza.", + "tokenizer": "Tokenizzatore", + "Adds a tab that lets you preview how CLIP model would tokenize your text.": "Aggiunge una scheda che consente di visualizzare in anteprima il modo in cui il modello CLIP tokenizzerebbe il vostro testo.", + "parameters": "Parametri", + "The directory does not exist": "La cartella non esiste" +} \ No newline at end of file From 99b05addb1c98169d78957f13efef308aef0af94 Mon Sep 17 00:00:00 2001 From: Bruno Seoane Date: Sat, 5 Nov 2022 18:46:47 -0300 Subject: [PATCH 072/219] Fix options endpoint not showing the full list of options --- modules/api/models.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/modules/api/models.py b/modules/api/models.py index f89da1ff..0ea62155 100644 --- a/modules/api/models.py +++ b/modules/api/models.py @@ -168,9 +168,9 @@ class ProgressResponse(BaseModel): current_image: str = Field(default=None, title="Current image", description="The current image in base64 format. opts.show_progress_every_n_steps is required for this to work.") fields = {} -for key, value in opts.data.items(): - metadata = opts.data_labels.get(key) - optType = opts.typemap.get(type(value), type(value)) +for key, metadata in opts.data_labels.items(): + value = opts.data.get(key) + optType = opts.typemap.get(type(metadata.default), type(value)) if (metadata is not None): fields.update({key: (Optional[optType], Field( From 0ebf66b575f008a027097946eb2f6845feffd010 Mon Sep 17 00:00:00 2001 From: Bruno Seoane Date: Sat, 5 Nov 2022 18:58:19 -0300 Subject: [PATCH 073/219] Fix set config endpoint --- modules/api/api.py | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/modules/api/api.py b/modules/api/api.py index 112000b8..a924c83a 100644 --- a/modules/api/api.py +++ b/modules/api/api.py @@ -230,14 +230,10 @@ class Api: return options - def set_config(self, req: OptionsModel): - # currently req has all options fields even if you send a dict like { "send_seed": false }, which means it will - # overwrite all options with default values. - raise RuntimeError('Setting options via API is not supported') - - reqDict = vars(req) - for o in reqDict: - setattr(shared.opts, o, reqDict[o]) + def set_config(self, req: Dict[str, Any]): + + for o in req: + setattr(shared.opts, o, req[o]) shared.opts.save(shared.config_filename) return From 3c72055c22425dcde0739b5246e3501f4a3ec794 Mon Sep 17 00:00:00 2001 From: Bruno Seoane Date: Sat, 5 Nov 2022 19:05:15 -0300 Subject: [PATCH 074/219] Add skip endpoint --- modules/api/api.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/modules/api/api.py b/modules/api/api.py index a924c83a..c7ceb787 100644 --- a/modules/api/api.py +++ b/modules/api/api.py @@ -64,6 +64,7 @@ class Api: self.app.add_api_route("/sdapi/v1/png-info", self.pnginfoapi, methods=["POST"], response_model=PNGInfoResponse) self.app.add_api_route("/sdapi/v1/progress", self.progressapi, methods=["GET"], response_model=ProgressResponse) self.app.add_api_route("/sdapi/v1/interrupt", self.interruptapi, methods=["POST"]) + self.app.add_api_route("/sdapi/v1/skip", self.skip, methods=["POST"]) self.app.add_api_route("/sdapi/v1/options", self.get_config, methods=["GET"], response_model=OptionsModel) self.app.add_api_route("/sdapi/v1/options", self.set_config, methods=["POST"]) self.app.add_api_route("/sdapi/v1/cmd-flags", self.get_cmd_flags, methods=["GET"], response_model=FlagsModel) @@ -219,6 +220,11 @@ class Api: return {} + def skip(self): + shared.state.skip() + + return + def get_config(self): options = {} for key in shared.opts.data.keys(): From 7f63980e479c7ffaec907fb659b5024e96eb72e7 Mon Sep 17 00:00:00 2001 From: Bruno Seoane Date: Sat, 5 Nov 2022 19:09:13 -0300 Subject: [PATCH 075/219] Remove unnecesary return --- modules/api/api.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/modules/api/api.py b/modules/api/api.py index c7ceb787..33e6c6dc 100644 --- a/modules/api/api.py +++ b/modules/api/api.py @@ -223,8 +223,6 @@ class Api: def skip(self): shared.state.skip() - return - def get_config(self): options = {} for key in shared.opts.data.keys(): From 6603f63b7b8af39ab815091460c5c2a12d3f253e Mon Sep 17 00:00:00 2001 From: Han Lin Date: Sun, 6 Nov 2022 11:08:20 +0800 Subject: [PATCH 076/219] Fixes LDSR upscaler producing black bars --- modules/ldsr_model_arch.py | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/modules/ldsr_model_arch.py b/modules/ldsr_model_arch.py index 14db5076..90e0a2f0 100644 --- a/modules/ldsr_model_arch.py +++ b/modules/ldsr_model_arch.py @@ -101,8 +101,8 @@ class LDSR: down_sample_rate = target_scale / 4 wd = width_og * down_sample_rate hd = height_og * down_sample_rate - width_downsampled_pre = int(wd) - height_downsampled_pre = int(hd) + width_downsampled_pre = int(np.ceil(wd)) + height_downsampled_pre = int(np.ceil(hd)) if down_sample_rate != 1: print( @@ -110,7 +110,12 @@ class LDSR: im_og = im_og.resize((width_downsampled_pre, height_downsampled_pre), Image.LANCZOS) else: print(f"Down sample rate is 1 from {target_scale} / 4 (Not downsampling)") - logs = self.run(model["model"], im_og, diffusion_steps, eta) + + # pad width and height to multiples of 64, pads with the edge values of image to avoid artifacts + pad_w, pad_h = np.max(((2, 2), np.ceil(np.array(im_og.size) / 64).astype(int)), axis=0) * 64 - im_og.size + im_padded = Image.fromarray(np.pad(np.array(im_og), ((0, pad_h), (0, pad_w), (0, 0)), mode='edge')) + + logs = self.run(model["model"], im_padded, diffusion_steps, eta) sample = logs["sample"] sample = sample.detach().cpu() @@ -120,6 +125,9 @@ class LDSR: sample = np.transpose(sample, (0, 2, 3, 1)) a = Image.fromarray(sample[0]) + # remove padding + a = a.crop((0, 0) + tuple(np.array(im_og.size) * 4)) + del model gc.collect() torch.cuda.empty_cache() From a2a1a2f7270a865175f64475229838a8d64509ea Mon Sep 17 00:00:00 2001 From: AUTOMATIC <16777216c@gmail.com> Date: Sun, 6 Nov 2022 09:02:25 +0300 Subject: [PATCH 077/219] add ability to create extensions that add localizations --- javascript/ui.js | 2 ++ modules/localization.py | 6 ++++++ modules/scripts.py | 1 - modules/shared.py | 2 -- modules/ui.py | 3 +-- webui.py | 9 +++++---- 6 files changed, 14 insertions(+), 9 deletions(-) diff --git a/javascript/ui.js b/javascript/ui.js index 7e116465..95cfd106 100644 --- a/javascript/ui.js +++ b/javascript/ui.js @@ -208,4 +208,6 @@ function update_token_counter(button_id) { function restart_reload(){ document.body.innerHTML='

Reloading...

'; setTimeout(function(){location.reload()},2000) + + return [] } diff --git a/modules/localization.py b/modules/localization.py index b1810cda..f6a6f2fb 100644 --- a/modules/localization.py +++ b/modules/localization.py @@ -3,6 +3,7 @@ import os import sys import traceback + localizations = {} @@ -16,6 +17,11 @@ def list_localizations(dirname): localizations[fn] = os.path.join(dirname, file) + from modules import scripts + for file in scripts.list_scripts("localizations", ".json"): + fn, ext = os.path.splitext(file.filename) + localizations[fn] = file.path + def localization_js(current_localization_name): fn = localizations.get(current_localization_name, None) diff --git a/modules/scripts.py b/modules/scripts.py index 366c90d7..637b2329 100644 --- a/modules/scripts.py +++ b/modules/scripts.py @@ -3,7 +3,6 @@ import sys import traceback from collections import namedtuple -import modules.ui as ui import gradio as gr from modules.processing import StableDiffusionProcessing diff --git a/modules/shared.py b/modules/shared.py index 70b998ff..e8bacd3c 100644 --- a/modules/shared.py +++ b/modules/shared.py @@ -221,8 +221,6 @@ interrogator = modules.interrogate.InterrogateModels("interrogate") face_restorers = [] -localization.list_localizations(cmd_opts.localizations_dir) - def realesrgan_models_names(): import modules.realesrgan_model diff --git a/modules/ui.py b/modules/ui.py index 76ca9b07..23643c22 100644 --- a/modules/ui.py +++ b/modules/ui.py @@ -1563,11 +1563,10 @@ def create_ui(wrap_gradio_gpu_call): shared.state.need_restart = True restart_gradio.click( - fn=request_restart, + _js='restart_reload', inputs=[], outputs=[], - _js='restart_reload' ) if column is not None: diff --git a/webui.py b/webui.py index a5a520f0..4342a962 100644 --- a/webui.py +++ b/webui.py @@ -10,7 +10,7 @@ from fastapi.middleware.gzip import GZipMiddleware from modules.paths import script_path -from modules import devices, sd_samplers, upscaler, extensions +from modules import devices, sd_samplers, upscaler, extensions, localization import modules.codeformer_model as codeformer import modules.extras import modules.face_restoration @@ -28,9 +28,7 @@ import modules.txt2img import modules.script_callbacks import modules.ui -from modules import devices from modules import modelloader -from modules.paths import script_path from modules.shared import cmd_opts import modules.hypernetworks.hypernetwork @@ -64,6 +62,7 @@ def wrap_gradio_gpu_call(func, extra_outputs=None): def initialize(): extensions.list_extensions() + localization.list_localizations(cmd_opts.localizations_dir) if cmd_opts.ui_debug_mode: shared.sd_upscalers = upscaler.UpscalerLanczos().scalers @@ -99,7 +98,6 @@ def initialize(): else: print("Running with TLS") - # make the program just exit at ctrl+c without waiting for anything def sigint_handler(sig, frame): print(f'Interrupted with signal {sig} in {frame}') @@ -185,6 +183,9 @@ def webui(): print('Reloading extensions') extensions.list_extensions() + + localization.list_localizations(cmd_opts.localizations_dir) + print('Reloading custom scripts') modules.scripts.reload_scripts() print('Reloading modules: modules.ui') From e5b4e3f820cd09e751f1d168ab05d606d078a0d9 Mon Sep 17 00:00:00 2001 From: AUTOMATIC <16777216c@gmail.com> Date: Sun, 6 Nov 2022 10:12:53 +0300 Subject: [PATCH 078/219] add tags to extensions, and ability to filter out tags list changed Settings keys in UI do not print VRAM/etc stats everywhere but in calls that use GPU --- modules/ui.py | 25 ++++++++++-------- modules/ui_extensions.py | 55 ++++++++++++++++++++++++++++++++-------- style.css | 5 ++++ webui.py | 2 +- 4 files changed, 64 insertions(+), 23 deletions(-) diff --git a/modules/ui.py b/modules/ui.py index 23643c22..c946ad59 100644 --- a/modules/ui.py +++ b/modules/ui.py @@ -174,9 +174,9 @@ def save_pil_to_file(pil_image, dir=None): gr.processing_utils.save_pil_to_file = save_pil_to_file -def wrap_gradio_call(func, extra_outputs=None): +def wrap_gradio_call(func, extra_outputs=None, add_stats=False): def f(*args, extra_outputs_array=extra_outputs, **kwargs): - run_memmon = opts.memmon_poll_rate > 0 and not shared.mem_mon.disabled + run_memmon = opts.memmon_poll_rate > 0 and not shared.mem_mon.disabled and add_stats if run_memmon: shared.mem_mon.monitor() t = time.perf_counter() @@ -203,11 +203,18 @@ def wrap_gradio_call(func, extra_outputs=None): res = extra_outputs_array + [f"
{plaintext_to_html(type(e).__name__+': '+str(e))}
"] + shared.state.skipped = False + shared.state.interrupted = False + shared.state.job_count = 0 + + if not add_stats: + return tuple(res) + elapsed = time.perf_counter() - t elapsed_m = int(elapsed // 60) elapsed_s = elapsed % 60 elapsed_text = f"{elapsed_s:.2f}s" - if (elapsed_m > 0): + if elapsed_m > 0: elapsed_text = f"{elapsed_m}m "+elapsed_text if run_memmon: @@ -225,10 +232,6 @@ def wrap_gradio_call(func, extra_outputs=None): # last item is always HTML res[-1] += f"

Time taken: {elapsed_text}

{vram_html}
" - shared.state.skipped = False - shared.state.interrupted = False - shared.state.job_count = 0 - return tuple(res) return f @@ -1436,7 +1439,7 @@ def create_ui(wrap_gradio_gpu_call): opts.reorder() def run_settings(*args): - changed = 0 + changed = [] for key, value, comp in zip(opts.data_labels.keys(), args, components): assert comp == dummy_component or opts.same_type(value, opts.data_labels[key].default), f"Bad value for setting {key}: {value}; expecting {type(opts.data_labels[key].default).__name__}" @@ -1454,12 +1457,12 @@ def create_ui(wrap_gradio_gpu_call): if opts.data_labels[key].onchange is not None: opts.data_labels[key].onchange() - changed += 1 + changed.append(key) try: opts.save(shared.config_filename) except RuntimeError: - return opts.dumpjson(), f'{changed} settings changed without save.' - return opts.dumpjson(), f'{changed} settings changed.' + return opts.dumpjson(), f'{len(changed)} settings changed without save: {", ".join(changed)}.' + return opts.dumpjson(), f'{len(changed)} settings changed: {", ".join(changed)}.' def run_settings_single(value, key): if not opts.same_type(value, opts.data_labels[key].default): diff --git a/modules/ui_extensions.py b/modules/ui_extensions.py index 8e0d41d5..02ab9643 100644 --- a/modules/ui_extensions.py +++ b/modules/ui_extensions.py @@ -140,13 +140,15 @@ def install_extension_from_url(dirname, url): shutil.rmtree(tmpdir, True) -def install_extension_from_index(url): +def install_extension_from_index(url, hide_tags): ext_table, message = install_extension_from_url(None, url) - return refresh_available_extensions_from_data(), ext_table, message + code, _ = refresh_available_extensions_from_data(hide_tags) + + return code, ext_table, message -def refresh_available_extensions(url): +def refresh_available_extensions(url, hide_tags): global available_extensions import urllib.request @@ -155,13 +157,25 @@ def refresh_available_extensions(url): available_extensions = json.loads(text) - return url, refresh_available_extensions_from_data(), '' + code, tags = refresh_available_extensions_from_data(hide_tags) + + return url, code, gr.CheckboxGroup.update(choices=tags), '' -def refresh_available_extensions_from_data(): +def refresh_available_extensions_for_tags(hide_tags): + code, _ = refresh_available_extensions_from_data(hide_tags) + + return code, '' + + +def refresh_available_extensions_from_data(hide_tags): extlist = available_extensions["extensions"] installed_extension_urls = {normalize_git_url(extension.remote): extension.name for extension in extensions.extensions} + tags = available_extensions.get("tags", {}) + tags_to_hide = set(hide_tags) + hidden = 0 + code = f""" @@ -178,17 +192,24 @@ def refresh_available_extensions_from_data(): name = ext.get("name", "noname") url = ext.get("url", None) description = ext.get("description", "") + extension_tags = ext.get("tags", []) if url is None: continue + if len([x for x in extension_tags if x in tags_to_hide]) > 0: + hidden += 1 + continue + existing = installed_extension_urls.get(normalize_git_url(url), None) install_code = f"""""" + tags_text = ", ".join([f"{x}" for x in extension_tags]) + code += f""" - + @@ -199,7 +220,10 @@ def refresh_available_extensions_from_data():
{html.escape(name)}{html.escape(name)}
{tags_text}
{html.escape(description)} {install_code}
""" - return code + if hidden > 0: + code += f"

Extension hidden: {hidden}

" + + return code, list(tags) def create_ui(): @@ -238,21 +262,30 @@ def create_ui(): extension_to_install = gr.Text(elem_id="extension_to_install", visible=False) install_extension_button = gr.Button(elem_id="install_extension_button", visible=False) + with gr.Row(): + hide_tags = gr.CheckboxGroup(value=["ads", "localization"], label="Hide extensions with tags", choices=["script", "ads", "localization"]) + install_result = gr.HTML() available_extensions_table = gr.HTML() refresh_available_extensions_button.click( - fn=modules.ui.wrap_gradio_call(refresh_available_extensions, extra_outputs=[gr.update(), gr.update()]), - inputs=[available_extensions_index], - outputs=[available_extensions_index, available_extensions_table, install_result], + fn=modules.ui.wrap_gradio_call(refresh_available_extensions, extra_outputs=[gr.update(), gr.update(), gr.update()]), + inputs=[available_extensions_index, hide_tags], + outputs=[available_extensions_index, available_extensions_table, hide_tags, install_result], ) install_extension_button.click( fn=modules.ui.wrap_gradio_call(install_extension_from_index, extra_outputs=[gr.update(), gr.update()]), - inputs=[extension_to_install], + inputs=[extension_to_install, hide_tags], outputs=[available_extensions_table, extensions_table, install_result], ) + hide_tags.change( + fn=modules.ui.wrap_gradio_call(refresh_available_extensions_for_tags, extra_outputs=[gr.update()]), + inputs=[hide_tags], + outputs=[available_extensions_table, install_result] + ) + with gr.TabItem("Install from URL"): install_url = gr.Text(label="URL for extension's git repository") install_dirname = gr.Text(label="Local directory name", placeholder="Leave empty for auto") diff --git a/style.css b/style.css index a0382a8c..e2b71f25 100644 --- a/style.css +++ b/style.css @@ -563,6 +563,11 @@ img2maskimg, #img2maskimg > .h-60, #img2maskimg > .h-60 > div, #img2maskimg > .h opacity: 0.5; } +.extension-tag{ + font-weight: bold; + font-size: 95%; +} + /* The following handles localization for right-to-left (RTL) languages like Arabic. The rtl media type will only be activated by the logic in javascript/localization.js. If you change anything above, you need to make sure it is RTL compliant by just running diff --git a/webui.py b/webui.py index 4342a962..f4f1d74d 100644 --- a/webui.py +++ b/webui.py @@ -57,7 +57,7 @@ def wrap_gradio_gpu_call(func, extra_outputs=None): return res - return modules.ui.wrap_gradio_call(f, extra_outputs=extra_outputs) + return modules.ui.wrap_gradio_call(f, extra_outputs=extra_outputs, add_stats=True) def initialize(): From 9cd1a66648b4c19136687100f9705d442f31e7f9 Mon Sep 17 00:00:00 2001 From: AUTOMATIC <16777216c@gmail.com> Date: Sun, 6 Nov 2022 10:37:08 +0300 Subject: [PATCH 079/219] remove localization people from CODEOWNERS add a note --- CODEOWNERS | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/CODEOWNERS b/CODEOWNERS index a48d8012..7438c9bc 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -1,13 +1,12 @@ * @AUTOMATIC1111 -/localizations/ar_AR.json @xmodar @blackneoo -/localizations/de_DE.json @LunixWasTaken -/localizations/es_ES.json @innovaciones -/localizations/fr_FR.json @tumbly -/localizations/it_IT.json @EugenioBuffo -/localizations/ja_JP.json @yuuki76 -/localizations/ko_KR.json @36DB -/localizations/pt_BR.json @M-art-ucci -/localizations/ru_RU.json @kabachuha -/localizations/tr_TR.json @camenduru -/localizations/zh_CN.json @dtlnor @bgluminous -/localizations/zh_TW.json @benlisquare + +# if you were managing a localization and were removed from this file, this is because +# the intended way to do localizations now is via extensions. See: +# https://github.com/AUTOMATIC1111/stable-diffusion-webui/wiki/Developing-extensions +# Make a repo with your localization and since you are still listed as a collaborator +# you can add it to the wiki page yourself. This change is because some people complained +# the git commit log is cluttered with things unrelated to almost everyone and +# because I believe this is the best overall for the project to handle localizations almost +# entirely without my oversight. + + From 6e4de5b4422dfc0d45063b2c8c78b19f00321615 Mon Sep 17 00:00:00 2001 From: AUTOMATIC <16777216c@gmail.com> Date: Sun, 6 Nov 2022 11:20:23 +0300 Subject: [PATCH 080/219] add load_with_extra function for modules to load checkpoints with extended whitelist --- modules/safe.py | 40 +++++++++++++++++++++++++++++++++++++--- 1 file changed, 37 insertions(+), 3 deletions(-) diff --git a/modules/safe.py b/modules/safe.py index 348a24fc..a9209e38 100644 --- a/modules/safe.py +++ b/modules/safe.py @@ -23,11 +23,18 @@ def encode(*args): class RestrictedUnpickler(pickle.Unpickler): + extra_handler = None + def persistent_load(self, saved_id): assert saved_id[0] == 'storage' return TypedStorage() def find_class(self, module, name): + if self.extra_handler is not None: + res = self.extra_handler(module, name) + if res is not None: + return res + if module == 'collections' and name == 'OrderedDict': return getattr(collections, name) if module == 'torch._utils' and name in ['_rebuild_tensor_v2', '_rebuild_parameter']: @@ -52,7 +59,7 @@ class RestrictedUnpickler(pickle.Unpickler): return set # Forbid everything else. - raise pickle.UnpicklingError(f"global '{module}/{name}' is forbidden") + raise Exception(f"global '{module}/{name}' is forbidden") allowed_zip_names = ["archive/data.pkl", "archive/version"] @@ -69,7 +76,7 @@ def check_zip_filenames(filename, names): raise Exception(f"bad file inside {filename}: {name}") -def check_pt(filename): +def check_pt(filename, extra_handler): try: # new pytorch format is a zip file @@ -78,6 +85,7 @@ def check_pt(filename): with z.open('archive/data.pkl') as file: unpickler = RestrictedUnpickler(file) + unpickler.extra_handler = extra_handler unpickler.load() except zipfile.BadZipfile: @@ -85,16 +93,42 @@ def check_pt(filename): # if it's not a zip file, it's an olf pytorch format, with five objects written to pickle with open(filename, "rb") as file: unpickler = RestrictedUnpickler(file) + unpickler.extra_handler = extra_handler for i in range(5): unpickler.load() def load(filename, *args, **kwargs): + return load_with_extra(filename, *args, **kwargs) + + +def load_with_extra(filename, extra_handler=None, *args, **kwargs): + """ + this functon is intended to be used by extensions that want to load models with + some extra classes in them that the usual unpickler would find suspicious. + + Use the extra_handler argument to specify a function that takes module and field name as text, + and returns that field's value: + + ```python + def extra(module, name): + if module == 'collections' and name == 'OrderedDict': + return collections.OrderedDict + + return None + + safe.load_with_extra('model.pt', extra_handler=extra) + ``` + + The alternative to this is just to use safe.unsafe_torch_load('model.pt'), which as the name implies is + definitely unsafe. + """ + from modules import shared try: if not shared.cmd_opts.disable_safe_unpickle: - check_pt(filename) + check_pt(filename, extra_handler) except pickle.UnpicklingError: print(f"Error verifying pickled file from {filename}:", file=sys.stderr) From 55ca04095845b41bf66333b3b7343e3ea0babed1 Mon Sep 17 00:00:00 2001 From: Billy Cao Date: Sun, 6 Nov 2022 16:31:44 +0800 Subject: [PATCH 081/219] Resolve conflict --- modules/processing.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/processing.py b/modules/processing.py index 86d015af..db35983b 100644 --- a/modules/processing.py +++ b/modules/processing.py @@ -422,14 +422,14 @@ def process_images(p: StableDiffusionProcessing) -> Processed: try: for k, v in p.override_settings.items(): - opts.data[k] = v # we don't call onchange for simplicity which makes changing model impossible + setattr(opts, k, v) # we don't call onchange for simplicity which makes changing model impossible if k == 'sd_hypernetwork': shared.reload_hypernetworks() # make onchange call for changing hypernet since it is relatively fast to load on-change, while SD models are not res = process_images_inner(p) finally: # restore opts to original state for k, v in stored_opts.items(): - opts.data[k] = v + setattr(opts, k, v) if k == 'sd_hypernetwork': shared.reload_hypernetworks() return res From 32c0eab89538ba3900bf499291720f80ae4b43e5 Mon Sep 17 00:00:00 2001 From: AUTOMATIC <16777216c@gmail.com> Date: Sun, 6 Nov 2022 14:39:41 +0300 Subject: [PATCH 082/219] load all settings in one call instead of one by one when the page loads --- modules/ui.py | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/modules/ui.py b/modules/ui.py index c946ad59..34c31ef1 100644 --- a/modules/ui.py +++ b/modules/ui.py @@ -1141,7 +1141,7 @@ def create_ui(wrap_gradio_gpu_call): outputs=[html, generation_info, html2], ) - with gr.Blocks() as modelmerger_interface: + with gr.Blocks(analytics_enabled=False) as modelmerger_interface: with gr.Row().style(equal_height=False): with gr.Column(variant='panel'): gr.HTML(value="

A merger of the two checkpoints will be generated in your checkpoint directory.

") @@ -1161,7 +1161,7 @@ def create_ui(wrap_gradio_gpu_call): sd_hijack.model_hijack.embedding_db.load_textual_inversion_embeddings() - with gr.Blocks() as train_interface: + with gr.Blocks(analytics_enabled=False) as train_interface: with gr.Row().style(equal_height=False): gr.HTML(value="

See wiki for detailed explanation.

") @@ -1420,15 +1420,14 @@ def create_ui(wrap_gradio_gpu_call): if info.refresh is not None: if is_quicksettings: - res = comp(label=info.label, value=fun, elem_id=elem_id, **(args or {})) + res = comp(label=info.label, value=fun(), elem_id=elem_id, **(args or {})) create_refresh_button(res, info.refresh, info.component_args, "refresh_" + key) else: with gr.Row(variant="compact"): - res = comp(label=info.label, value=fun, elem_id=elem_id, **(args or {})) + res = comp(label=info.label, value=fun(), elem_id=elem_id, **(args or {})) create_refresh_button(res, info.refresh, info.component_args, "refresh_" + key) else: - res = comp(label=info.label, value=fun, elem_id=elem_id, **(args or {})) - + res = comp(label=info.label, value=fun(), elem_id=elem_id, **(args or {})) return res @@ -1639,6 +1638,17 @@ def create_ui(wrap_gradio_gpu_call): outputs=[component, text_settings], ) + component_keys = [k for k in opts.data_labels.keys() if k in component_dict] + + def get_settings_values(): + return [getattr(opts, key) for key in component_keys] + + demo.load( + fn=get_settings_values, + inputs=[], + outputs=[component_dict[k] for k in component_keys], + ) + def modelmerger(*args): try: results = modules.extras.run_modelmerger(*args) From 67c8e11be74180be19341aebbd6a246c37a79fbb Mon Sep 17 00:00:00 2001 From: snowmeow2 Date: Mon, 7 Nov 2022 02:32:06 +0800 Subject: [PATCH 083/219] Adding DeepDanbooru to the interrogation API --- modules/api/api.py | 16 ++++++++++++++-- modules/api/models.py | 1 + 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/modules/api/api.py b/modules/api/api.py index 688469ad..596a6616 100644 --- a/modules/api/api.py +++ b/modules/api/api.py @@ -15,6 +15,9 @@ from modules.sd_models import checkpoints_list from modules.realesrgan_model import get_realesrgan_models from typing import List +if shared.cmd_opts.deepdanbooru: + from modules.deepbooru import get_deepbooru_tags + def upscaler_to_index(name: str): try: return [x.name.lower() for x in shared.sd_upscalers].index(name.lower()) @@ -220,11 +223,20 @@ class Api: if image_b64 is None: raise HTTPException(status_code=404, detail="Image not found") - img = self.__base64_to_image(image_b64) + img = decode_base64_to_image(image_b64) + img = img.convert('RGB') # Override object param with self.queue_lock: - processed = shared.interrogator.interrogate(img) + if interrogatereq.model == "clip": + processed = shared.interrogator.interrogate(img) + elif interrogatereq.model == "deepdanbooru": + if shared.cmd_opts.deepdanbooru: + processed = get_deepbooru_tags(img) + else: + raise HTTPException(status_code=404, detail="Model not found. Add --deepdanbooru when launching for using the model.") + else: + raise HTTPException(status_code=404, detail="Model not found") return InterrogateResponse(caption=processed) diff --git a/modules/api/models.py b/modules/api/models.py index 34dbfa16..f9cd929e 100644 --- a/modules/api/models.py +++ b/modules/api/models.py @@ -170,6 +170,7 @@ class ProgressResponse(BaseModel): class InterrogateRequest(BaseModel): image: str = Field(default="", title="Image", description="Image to work on, must be a Base64 string containing the image's data.") + model: str = Field(default="clip", title="Model", description="The interrogate model used.") class InterrogateResponse(BaseModel): caption: str = Field(default=None, title="Caption", description="The generated caption for the image.") From 804d9fb83d0c63ca3acd36378707ce47b8f12599 Mon Sep 17 00:00:00 2001 From: AUTOMATIC <16777216c@gmail.com> Date: Sun, 6 Nov 2022 23:22:36 +0300 Subject: [PATCH 084/219] bump gradio to 3.9 --- requirements.txt | 2 +- requirements_versions.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/requirements.txt b/requirements.txt index 79e8b7c6..0fba0b23 100644 --- a/requirements.txt +++ b/requirements.txt @@ -4,7 +4,7 @@ fairscale==0.4.4 fonts font-roboto gfpgan -gradio==3.8 +gradio==3.9 invisible-watermark numpy omegaconf diff --git a/requirements_versions.txt b/requirements_versions.txt index 7bd16712..f7059f20 100644 --- a/requirements_versions.txt +++ b/requirements_versions.txt @@ -2,7 +2,7 @@ transformers==4.19.2 diffusers==0.3.0 basicsr==1.4.2 gfpgan==1.3.8 -gradio==3.8 +gradio==3.9 numpy==1.23.3 Pillow==9.2.0 realesrgan==0.3.0 From a258fd60dbe2d68325339405a2aa72816d06d2fd Mon Sep 17 00:00:00 2001 From: Keavon Chambers Date: Mon, 7 Nov 2022 00:13:58 -0800 Subject: [PATCH 085/219] Add CORS-allow policy launch argument using regex --- modules/shared.py | 7 ++++--- webui.py | 6 +++++- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/modules/shared.py b/modules/shared.py index e8bacd3c..55de286d 100644 --- a/modules/shared.py +++ b/modules/shared.py @@ -81,12 +81,13 @@ parser.add_argument("--disable-console-progressbars", action='store_true', help= parser.add_argument("--enable-console-prompts", action='store_true', help="print prompts to console when generating with txt2img and img2img", default=False) parser.add_argument('--vae-path', type=str, help='Path to Variational Autoencoders model', default=None) parser.add_argument("--disable-safe-unpickle", action='store_true', help="disable checking pytorch models for malicious code", default=False) -parser.add_argument("--api", action='store_true', help="use api=True to launch the api with the webui") -parser.add_argument("--nowebui", action='store_true', help="use api=True to launch the api instead of the webui") +parser.add_argument("--api", action='store_true', help="use api=True to launch the API together with the webui (use --nowebui instead for only the API)") +parser.add_argument("--nowebui", action='store_true', help="use api=True to launch the API instead of the webui") parser.add_argument("--ui-debug-mode", action='store_true', help="Don't load model to quickly launch UI") parser.add_argument("--device-id", type=str, help="Select the default CUDA device to use (export CUDA_VISIBLE_DEVICES=0,1,etc might be needed before)", default=None) parser.add_argument("--administrator", action='store_true', help="Administrator rights", default=False) -parser.add_argument("--cors-allow-origins", type=str, help="Allowed CORS origins", default=None) +parser.add_argument("--cors-allow-origins", type=str, help="Allowed CORS origin(s) in the form of a comma-separated list (no spaces)", default=None) +parser.add_argument("--cors-allow-origins-regex", type=str, help="Allowed CORS origin(s) in the form of a single regular expression", default=None) parser.add_argument("--tls-keyfile", type=str, help="Partially enables TLS, requires --tls-certfile to fully function", default=None) parser.add_argument("--tls-certfile", type=str, help="Partially enables TLS, requires --tls-keyfile to fully function", default=None) parser.add_argument("--server-name", type=str, help="Sets hostname of server", default=None) diff --git a/webui.py b/webui.py index f4f1d74d..066d94f7 100644 --- a/webui.py +++ b/webui.py @@ -107,8 +107,12 @@ def initialize(): def setup_cors(app): - if cmd_opts.cors_allow_origins: + if cmd_opts.cors_allow_origins and cmd_opts.cors_allow_origins_regex: + app.add_middleware(CORSMiddleware, allow_origins=cmd_opts.cors_allow_origins.split(','), allow_origin_regex=cmd_opts.cors_allow_origins_regex, allow_methods=['*']) + elif cmd_opts.cors_allow_origins: app.add_middleware(CORSMiddleware, allow_origins=cmd_opts.cors_allow_origins.split(','), allow_methods=['*']) + elif cmd_opts.cors_allow_origins_regex: + app.add_middleware(CORSMiddleware, allow_origin_regex=cmd_opts.cors_allow_origins_regex, allow_methods=['*']) def create_api(app): From 9ed4a126bd6421f91bf4a9bdd348b6aef0a378c6 Mon Sep 17 00:00:00 2001 From: kavorite Date: Mon, 7 Nov 2022 19:58:49 -0500 Subject: [PATCH 086/219] add gradio-inpaint-tool; color-sketch --- modules/img2img.py | 19 +++++++++++++------ modules/shared.py | 1 + modules/ui.py | 11 ++++++++++- 3 files changed, 24 insertions(+), 7 deletions(-) diff --git a/modules/img2img.py b/modules/img2img.py index be9f3653..00c6f827 100644 --- a/modules/img2img.py +++ b/modules/img2img.py @@ -59,18 +59,25 @@ def process_batch(p, input_dir, output_dir, args): processed_image.save(os.path.join(output_dir, filename)) -def img2img(mode: int, prompt: str, negative_prompt: str, prompt_style: str, prompt_style2: str, init_img, init_img_with_mask, init_img_inpaint, init_mask_inpaint, mask_mode, steps: int, sampler_index: int, mask_blur: int, inpainting_fill: int, restore_faces: bool, tiling: bool, n_iter: int, batch_size: int, cfg_scale: float, denoising_strength: float, seed: int, subseed: int, subseed_strength: float, seed_resize_from_h: int, seed_resize_from_w: int, seed_enable_extras: bool, height: int, width: int, resize_mode: int, inpaint_full_res: bool, inpaint_full_res_padding: int, inpainting_mask_invert: int, img2img_batch_input_dir: str, img2img_batch_output_dir: str, *args): +def img2img(mode: int, prompt: str, negative_prompt: str, prompt_style: str, prompt_style2: str, init_img, init_img_with_mask, init_img_with_mask_orig, init_img_inpaint, init_mask_inpaint, mask_mode, steps: int, sampler_index: int, mask_blur: int, inpainting_fill: int, restore_faces: bool, tiling: bool, n_iter: int, batch_size: int, cfg_scale: float, denoising_strength: float, seed: int, subseed: int, subseed_strength: float, seed_resize_from_h: int, seed_resize_from_w: int, seed_enable_extras: bool, height: int, width: int, resize_mode: int, inpaint_full_res: bool, inpaint_full_res_padding: int, inpainting_mask_invert: int, img2img_batch_input_dir: str, img2img_batch_output_dir: str, *args): is_inpaint = mode == 1 is_batch = mode == 2 if is_inpaint: # Drawn mask if mask_mode == 0: - image = init_img_with_mask['image'] - mask = init_img_with_mask['mask'] - alpha_mask = ImageOps.invert(image.split()[-1]).convert('L').point(lambda x: 255 if x > 0 else 0, mode='1') - mask = ImageChops.lighter(alpha_mask, mask.convert('L')).convert('L') - image = image.convert('RGB') + image = init_img_with_mask + is_mask_sketch = isinstance(image, dict) + if is_mask_sketch: + # Sketch: mask iff. not transparent + image, mask = image["image"], image["mask"] + mask = np.array(mask)[..., -1] > 0 + else: + # Color-sketch: mask iff. painted over + orig = init_img_with_mask_orig or image + mask = np.any(np.array(image) != np.array(orig), axis=-1) + mask = Image.fromarray(mask.astype(np.uint8) * 255, "L") + image = image.convert("RGB") # Uploaded mask else: image = init_img_inpaint diff --git a/modules/shared.py b/modules/shared.py index d8e99f85..325e37d9 100644 --- a/modules/shared.py +++ b/modules/shared.py @@ -71,6 +71,7 @@ parser.add_argument("--ui-settings-file", type=str, help="filename to use for ui parser.add_argument("--gradio-debug", action='store_true', help="launch gradio with --debug option") parser.add_argument("--gradio-auth", type=str, help='set gradio authentication like "username:password"; or comma-delimit multiple like "u1:p1,u2:p2,u3:p3"', default=None) parser.add_argument("--gradio-img2img-tool", type=str, help='gradio image uploader tool: can be either editor for ctopping, or color-sketch for drawing', choices=["color-sketch", "editor"], default="editor") +parser.add_argument("--gradio-inpaint-tool", type=str, choices=["sketch", "color-sketch"], default="sketch", help="gradio inpainting editor: can be either sketch to only blur/noise the input, or color-sketch to paint over it") parser.add_argument("--opt-channelslast", action='store_true', help="change memory type for stable diffusion to channels last") parser.add_argument("--styles-file", type=str, help="filename to use for styles", default=os.path.join(script_path, 'styles.csv')) parser.add_argument("--autolaunch", action='store_true', help="open the webui URL in the system's default browser upon launch", default=False) diff --git a/modules/ui.py b/modules/ui.py index 2609857e..db323e9c 100644 --- a/modules/ui.py +++ b/modules/ui.py @@ -840,8 +840,17 @@ def create_ui(wrap_gradio_gpu_call): init_img = gr.Image(label="Image for img2img", elem_id="img2img_image", show_label=False, source="upload", interactive=True, type="pil", tool=cmd_opts.gradio_img2img_tool).style(height=480) with gr.TabItem('Inpaint', id='inpaint'): - init_img_with_mask = gr.Image(label="Image for inpainting with mask", show_label=False, elem_id="img2maskimg", source="upload", interactive=True, type="pil", tool="sketch", image_mode="RGBA").style(height=480) + init_img_with_mask_orig = gr.State(None) + init_img_with_mask = gr.Image(label="Image for inpainting with mask", show_label=False, elem_id="img2maskimg", source="upload", interactive=True, type="pil", tool=cmd_opts.gradio_inpaint_tool, image_mode="RGBA").style(height=480) + def update_orig(image, state): + if image is not None: + same_size = state is not None and state.size == image.size + has_exact_match = np.any(np.all(np.array(image) == np.array(state), axis=-1)) + edited = same_size and has_exact_match + return image if not edited or state is None else state + + init_img_with_mask.change(update_orig, [init_img_with_mask, init_img_with_mask_orig], init_img_with_mask_orig) init_img_inpaint = gr.Image(label="Image for img2img", show_label=False, source="upload", interactive=True, type="pil", visible=False, elem_id="img_inpaint_base") init_mask_inpaint = gr.Image(label="Mask", source="upload", interactive=True, type="pil", visible=False, elem_id="img_inpaint_mask") From c5334fc56b3d44976425da2e6d0a303ae96836a1 Mon Sep 17 00:00:00 2001 From: AUTOMATIC <16777216c@gmail.com> Date: Tue, 8 Nov 2022 08:35:01 +0300 Subject: [PATCH 087/219] fix javascript duplication bug after pressing the restart UI button --- modules/ui.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/modules/ui.py b/modules/ui.py index 34c31ef1..67cf1d6a 100644 --- a/modules/ui.py +++ b/modules/ui.py @@ -1752,7 +1752,7 @@ def create_ui(wrap_gradio_gpu_call): return demo -def load_javascript(raw_response): +def reload_javascript(): with open(os.path.join(script_path, "script.js"), "r", encoding="utf8") as jsfile: javascript = f'' @@ -1768,7 +1768,7 @@ def load_javascript(raw_response): javascript += f"\n" def template_response(*args, **kwargs): - res = raw_response(*args, **kwargs) + res = shared.GradioTemplateResponseOriginal(*args, **kwargs) res.body = res.body.replace( b'', f'{javascript}'.encode("utf8")) res.init_headers() @@ -1777,4 +1777,5 @@ def load_javascript(raw_response): gradio.routes.templates.TemplateResponse = template_response -reload_javascript = partial(load_javascript, gradio.routes.templates.TemplateResponse) +if not hasattr(shared, 'GradioTemplateResponseOriginal'): + shared.GradioTemplateResponseOriginal = gradio.routes.templates.TemplateResponse From 8011be33c36eb7aa9e9498fc714614034e07f67a Mon Sep 17 00:00:00 2001 From: AUTOMATIC <16777216c@gmail.com> Date: Tue, 8 Nov 2022 08:37:05 +0300 Subject: [PATCH 088/219] move functions out of main body for image preprocessing for easier hijacking --- modules/textual_inversion/preprocess.py | 162 ++++++++++++++---------- 1 file changed, 93 insertions(+), 69 deletions(-) diff --git a/modules/textual_inversion/preprocess.py b/modules/textual_inversion/preprocess.py index e13b1894..488aa5b5 100644 --- a/modules/textual_inversion/preprocess.py +++ b/modules/textual_inversion/preprocess.py @@ -35,6 +35,84 @@ def preprocess(process_src, process_dst, process_width, process_height, preproce deepbooru.release_process() +def listfiles(dirname): + return os.listdir(dirname) + + +class PreprocessParams: + src = None + dstdir = None + subindex = 0 + flip = False + process_caption = False + process_caption_deepbooru = False + preprocess_txt_action = None + + +def save_pic_with_caption(image, index, params: PreprocessParams, existing_caption=None): + caption = "" + + if params.process_caption: + caption += shared.interrogator.generate_caption(image) + + if params.process_caption_deepbooru: + if len(caption) > 0: + caption += ", " + caption += deepbooru.get_tags_from_process(image) + + filename_part = params.src + filename_part = os.path.splitext(filename_part)[0] + filename_part = os.path.basename(filename_part) + + basename = f"{index:05}-{params.subindex}-{filename_part}" + image.save(os.path.join(params.dstdir, f"{basename}.png")) + + if params.preprocess_txt_action == 'prepend' and existing_caption: + caption = existing_caption + ' ' + caption + elif params.preprocess_txt_action == 'append' and existing_caption: + caption = caption + ' ' + existing_caption + elif params.preprocess_txt_action == 'copy' and existing_caption: + caption = existing_caption + + caption = caption.strip() + + if len(caption) > 0: + with open(os.path.join(params.dstdir, f"{basename}.txt"), "w", encoding="utf8") as file: + file.write(caption) + + params.subindex += 1 + + +def save_pic(image, index, params, existing_caption=None): + save_pic_with_caption(image, index, params, existing_caption=existing_caption) + + if params.flip: + save_pic_with_caption(ImageOps.mirror(image), index, params, existing_caption=existing_caption) + + +def split_pic(image, inverse_xy, width, height, overlap_ratio): + if inverse_xy: + from_w, from_h = image.height, image.width + to_w, to_h = height, width + else: + from_w, from_h = image.width, image.height + to_w, to_h = width, height + h = from_h * to_w // from_w + if inverse_xy: + image = image.resize((h, to_w)) + else: + image = image.resize((to_w, h)) + + split_count = math.ceil((h - to_h * overlap_ratio) / (to_h * (1.0 - overlap_ratio))) + y_step = (h - to_h) / (split_count - 1) + for i in range(split_count): + y = int(y_step * i) + if inverse_xy: + splitted = image.crop((y, 0, y + to_h, to_w)) + else: + splitted = image.crop((0, y, to_w, y + to_h)) + yield splitted + def preprocess_work(process_src, process_dst, process_width, process_height, preprocess_txt_action, process_flip, process_split, process_caption, process_caption_deepbooru=False, split_threshold=0.5, overlap_ratio=0.2, process_focal_crop=False, process_focal_crop_face_weight=0.9, process_focal_crop_entropy_weight=0.3, process_focal_crop_edges_weight=0.5, process_focal_crop_debug=False): width = process_width @@ -48,82 +126,28 @@ def preprocess_work(process_src, process_dst, process_width, process_height, pre os.makedirs(dst, exist_ok=True) - files = os.listdir(src) + files = listfiles(src) shared.state.textinfo = "Preprocessing..." shared.state.job_count = len(files) - def save_pic_with_caption(image, index, existing_caption=None): - caption = "" - - if process_caption: - caption += shared.interrogator.generate_caption(image) - - if process_caption_deepbooru: - if len(caption) > 0: - caption += ", " - caption += deepbooru.get_tags_from_process(image) - - filename_part = filename - filename_part = os.path.splitext(filename_part)[0] - filename_part = os.path.basename(filename_part) - - basename = f"{index:05}-{subindex[0]}-{filename_part}" - image.save(os.path.join(dst, f"{basename}.png")) - - if preprocess_txt_action == 'prepend' and existing_caption: - caption = existing_caption + ' ' + caption - elif preprocess_txt_action == 'append' and existing_caption: - caption = caption + ' ' + existing_caption - elif preprocess_txt_action == 'copy' and existing_caption: - caption = existing_caption - - caption = caption.strip() - - if len(caption) > 0: - with open(os.path.join(dst, f"{basename}.txt"), "w", encoding="utf8") as file: - file.write(caption) - - subindex[0] += 1 - - def save_pic(image, index, existing_caption=None): - save_pic_with_caption(image, index, existing_caption=existing_caption) - - if process_flip: - save_pic_with_caption(ImageOps.mirror(image), index, existing_caption=existing_caption) - - def split_pic(image, inverse_xy): - if inverse_xy: - from_w, from_h = image.height, image.width - to_w, to_h = height, width - else: - from_w, from_h = image.width, image.height - to_w, to_h = width, height - h = from_h * to_w // from_w - if inverse_xy: - image = image.resize((h, to_w)) - else: - image = image.resize((to_w, h)) - - split_count = math.ceil((h - to_h * overlap_ratio) / (to_h * (1.0 - overlap_ratio))) - y_step = (h - to_h) / (split_count - 1) - for i in range(split_count): - y = int(y_step * i) - if inverse_xy: - splitted = image.crop((y, 0, y + to_h, to_w)) - else: - splitted = image.crop((0, y, to_w, y + to_h)) - yield splitted - + params = PreprocessParams() + params.dstdir = dst + params.flip = process_flip + params.process_caption = process_caption + params.process_caption_deepbooru = process_caption_deepbooru + params.preprocess_txt_action = preprocess_txt_action for index, imagefile in enumerate(tqdm.tqdm(files)): - subindex = [0] + params.subindex = 0 filename = os.path.join(src, imagefile) try: img = Image.open(filename).convert("RGB") except Exception: continue + params.src = filename + existing_caption = None existing_caption_filename = os.path.splitext(filename)[0] + '.txt' if os.path.exists(existing_caption_filename): @@ -143,8 +167,8 @@ def preprocess_work(process_src, process_dst, process_width, process_height, pre process_default_resize = True if process_split and ratio < 1.0 and ratio <= split_threshold: - for splitted in split_pic(img, inverse_xy): - save_pic(splitted, index, existing_caption=existing_caption) + for splitted in split_pic(img, inverse_xy, width, height, overlap_ratio): + save_pic(splitted, index, params, existing_caption=existing_caption) process_default_resize = False if process_focal_crop and img.height != img.width: @@ -165,11 +189,11 @@ def preprocess_work(process_src, process_dst, process_width, process_height, pre dnn_model_path = dnn_model_path, ) for focal in autocrop.crop_image(img, autocrop_settings): - save_pic(focal, index, existing_caption=existing_caption) + save_pic(focal, index, params, existing_caption=existing_caption) process_default_resize = False if process_default_resize: img = images.resize_image(1, img, width, height) - save_pic(img, index, existing_caption=existing_caption) + save_pic(img, index, params, existing_caption=existing_caption) - shared.state.nextjob() \ No newline at end of file + shared.state.nextjob() From 1610b3258458025025e9c4faae57d290e4519745 Mon Sep 17 00:00:00 2001 From: AUTOMATIC <16777216c@gmail.com> Date: Tue, 8 Nov 2022 08:38:10 +0300 Subject: [PATCH 089/219] add callback for creating a tab in train UI --- modules/script_callbacks.py | 27 +++++++++++++++++++++++++-- modules/ui.py | 4 ++++ 2 files changed, 29 insertions(+), 2 deletions(-) diff --git a/modules/script_callbacks.py b/modules/script_callbacks.py index 74dfb880..f19e164c 100644 --- a/modules/script_callbacks.py +++ b/modules/script_callbacks.py @@ -7,6 +7,7 @@ from typing import Optional from fastapi import FastAPI from gradio import Blocks + def report_exception(c, job): print(f"Error executing callback {job} for {c.script}", file=sys.stderr) print(traceback.format_exc(), file=sys.stderr) @@ -45,15 +46,21 @@ class CFGDenoiserParams: """Total number of sampling steps planned""" +class UiTrainTabParams: + def __init__(self, txt2img_preview_params): + self.txt2img_preview_params = txt2img_preview_params + + ScriptCallback = namedtuple("ScriptCallback", ["script", "callback"]) callback_map = dict( callbacks_app_started=[], callbacks_model_loaded=[], callbacks_ui_tabs=[], + callbacks_ui_train_tabs=[], callbacks_ui_settings=[], callbacks_before_image_saved=[], callbacks_image_saved=[], - callbacks_cfg_denoiser=[] + callbacks_cfg_denoiser=[], ) @@ -61,6 +68,7 @@ def clear_callbacks(): for callback_list in callback_map.values(): callback_list.clear() + def app_started_callback(demo: Optional[Blocks], app: FastAPI): for c in callback_map['callbacks_app_started']: try: @@ -79,7 +87,7 @@ def model_loaded_callback(sd_model): def ui_tabs_callback(): res = [] - + for c in callback_map['callbacks_ui_tabs']: try: res += c.callback() or [] @@ -89,6 +97,14 @@ def ui_tabs_callback(): return res +def ui_train_tabs_callback(params: UiTrainTabParams): + for c in callback_map['callbacks_ui_train_tabs']: + try: + c.callback(params) + except Exception: + report_exception(c, 'callbacks_ui_train_tabs') + + def ui_settings_callback(): for c in callback_map['callbacks_ui_settings']: try: @@ -169,6 +185,13 @@ def on_ui_tabs(callback): add_callback(callback_map['callbacks_ui_tabs'], callback) +def on_ui_train_tabs(callback): + """register a function to be called when the UI is creating new tabs for the train tab. + Create your new tabs with gr.Tab. + """ + add_callback(callback_map['callbacks_ui_train_tabs'], callback) + + def on_ui_settings(callback): """register a function to be called before UI settings are populated; add your settings by using shared.opts.add_option(shared.OptionInfo(...)) """ diff --git a/modules/ui.py b/modules/ui.py index 67cf1d6a..7ea1177f 100644 --- a/modules/ui.py +++ b/modules/ui.py @@ -1270,6 +1270,10 @@ def create_ui(wrap_gradio_gpu_call): train_hypernetwork = gr.Button(value="Train Hypernetwork", variant='primary') train_embedding = gr.Button(value="Train Embedding", variant='primary') + params = script_callbacks.UiTrainTabParams(txt2img_preview_params) + + script_callbacks.ui_train_tabs_callback(params) + with gr.Column(): progressbar = gr.HTML(elem_id="ti_progressbar") ti_output = gr.Text(elem_id="ti_output", value="", show_label=False) From ac085628540d0ec6a988fad93f5b8f2154209571 Mon Sep 17 00:00:00 2001 From: AUTOMATIC <16777216c@gmail.com> Date: Tue, 8 Nov 2022 10:01:06 +0300 Subject: [PATCH 090/219] Remove old localizations from the main repo. Where are they now? Here: https://github.com/AUTOMATIC1111/stable-diffusion-webui-old-localizations --- localizations/ar_AR.json | 518 ------------- localizations/de_DE.json | 458 ----------- localizations/es_ES.json | 692 ----------------- localizations/fr_FR.json | 415 ---------- localizations/it_IT.json | 1565 -------------------------------------- localizations/ja_JP.json | 482 ------------ localizations/ko_KR.json | 592 -------------- localizations/pt_BR.json | 485 ------------ localizations/ru_RU.json | 475 ------------ localizations/tr_TR.json | 423 ----------- localizations/zh_CN.json | 624 --------------- localizations/zh_TW.json | 610 --------------- 12 files changed, 7339 deletions(-) delete mode 100644 localizations/ar_AR.json delete mode 100644 localizations/de_DE.json delete mode 100644 localizations/es_ES.json delete mode 100644 localizations/fr_FR.json delete mode 100644 localizations/it_IT.json delete mode 100644 localizations/ja_JP.json delete mode 100644 localizations/ko_KR.json delete mode 100644 localizations/pt_BR.json delete mode 100644 localizations/ru_RU.json delete mode 100644 localizations/tr_TR.json delete mode 100644 localizations/zh_CN.json delete mode 100644 localizations/zh_TW.json diff --git a/localizations/ar_AR.json b/localizations/ar_AR.json deleted file mode 100644 index abbbcff4..00000000 --- a/localizations/ar_AR.json +++ /dev/null @@ -1,518 +0,0 @@ -{ - "rtl": true, - "Loading...": "لحظة...", - "view": "اعرض ", - "api": "واجهة البرمجة", - "built with gradio": "مبني باستخدام gradio", - "Stable Diffusion checkpoint": "أوزان نموذج الإنتشار المسقر", - "txt2img": "نص إلى صورة", - "Prompt": "الطلب", - "Prompt (press Ctrl+Enter or Alt+Enter to generate)": "الطلب (لبدء الإنتاج Ctrl+Enter أو Alt+Enter اضغط)", - "Negative prompt": "عكس الطلب", - "Negative prompt (press Ctrl+Enter or Alt+Enter to generate)": "عكس الطلب (لبدء الإنتاج Ctrl+Enter أو Alt+Enter اضغط)", - "Add a random artist to the prompt.": "أضف فنان عشوائي للطلب", - "Read generation parameters from prompt or last generation if prompt is empty into user interface.": "اقرأ عوامل الإنتاج من الطلب أو من الإنتاج السابق إذا كان الطلب فارغا", - "Save style": "احتفظ بالطلب وعكسه كإضافة", - "Apply selected styles to current prompt": "ألحق الإضافات المحددة إلى الطلب وعكسه", - "Generate": "أنتج", - "Skip": "تخطى", - "Stop processing current image and continue processing.": "لا تكمل خطوات هذة الحزمة وانتقل إلى الحزمة التالية", - "Interrupt": "توقف", - "Stop processing images and return any results accumulated so far.": "توقف عن الإنتاج واعرض ما تم إلى الآن", - "Style 1": "الإضافة 1", - "Style to apply; styles have components for both positive and negative prompts and apply to both": "الإضافات (styles) عبارة عن كلمات تتكرر كثيرا يتم إلحاقها بالطلب وعكسه عند الرغبة", - "Style 2": "الإضافة 2", - "Do not do anything special": "لا يغير شيئا", - "Sampling Steps": "عدد الخطوات", - "Sampling method": "أسلوب الخطو", - "Which algorithm to use to produce the image": "Sampler: اسم نظام تحديد طريقة تغيير المسافات بين الخطوات", - "Euler a": "Euler a", - "Euler Ancestral - very creative, each can get a completely different picture depending on step count, setting steps to higher than 30-40 does not help": "Euler Ancestral: طريقة مبدعة يمكن أن تنتج صور مختلفة على حسب عدد الخطوات، لا تتغير بعد 30-40 خطوة", - "Euler": "Euler", - "LMS": "LMS", - "Heun": "Heun", - "DPM2": "DPM2", - "DPM2 a": "DPM2 a", - "DPM fast": "DPM fast", - "DPM adaptive": "DPM adaptive", - "LMS Karras": "LMS Karras", - "DPM2 Karras": "DPM2 Karras", - "DPM2 a Karras": "DPM2 a Karras", - "DDIM": "DDIM", - "Denoising Diffusion Implicit Models - best at inpainting": "Denoising Diffusion Implicit Models: الأفضل في الإنتاج الجزئي", - "PLMS": "PLMS", - "Width": "العرض", - "Height": "الإرتفاع", - "Restore faces": "تحسين الوجوه", - "Tiling": "ترصيف", - "Produce an image that can be tiled.": "أنتج صور يمكن ترصيفها بجانب بعضها كالبلاط", - "Highres. fix": "إصلاح الدقة العالية", - "Use a two step process to partially create an image at smaller resolution, upscale, and then improve details in it without changing composition": "أنتج صورة بدقة منخفضة ثم قم برفع الدقة فيما بعد لمنع التشوهات التي تحصل عندما تكون الدقة المطلوبة كبيرة", - "Firstpass width": "العرض الأولي", - "Firstpass height": "الإرتفاع الأولي", - "Denoising strength": "المدى", - "Determines how little respect the algorithm should have for image's content. At 0, nothing will change, and at 1 you'll get an unrelated image. With values below 1.0, processing will take less steps than the Sampling Steps slider specifies.": "Denoising strength: حدد مدى الإبتعاد عن الصورة (عدد الخطوات الفعلي = عدد الخطوات * المدى)", - "Batch count": "عدد الحزم", - "How many batches of images to create": "يتم إنتاج الصور على دفعات، كل دفعة فيها حزمة من الصور", - "Batch size": "حجم الحزمة", - "How many image to create in a single batch": "Batch size: إنتاج حزمة صور أسرع من إنتاجهم فرادى، حدد عدد الصور في كل حزمة", - "CFG Scale": "التركيز", - "Classifier Free Guidance Scale - how strongly the image should conform to prompt - lower values produce more creative results": "CFG scale: يحدد مقدار التركيز على تلبية الطلب وتجنب عكسه، كلما زاد قل الإبداع", - "Seed": "البذرة", - "A value that determines the output of random number generator - if you create an image with same parameters and seed as another image, you'll get the same result": "Seed: رقم طبيعي عشوائي يسمح بإعادة إنتاج نفس الصورة إذا توافقت قيم العوامل الأخرى", - "Set seed to -1, which will cause a new random number to be used every time": "استخدم بذرة جديدة في كل مرة (نرمز لهذا الخيار بجعل قيمة البذرة 1-)", - "Reuse seed from last generation, mostly useful if it was randomed": "أعد استخدام البذرة من الإنتاج السابق", - "Extra": "مزج", - "Variation seed": "بذرة الممزوج", - "Seed of a different picture to be mixed into the generation.": "Variation seed: بذرة صورة أخرى ليتم مزجها مع الصورة الحالية", - "Variation strength": "أثر الممزوج", - "How strong of a variation to produce. At 0, there will be no effect. At 1, you will get the complete picture with variation seed (except for ancestral samplers, where you will just get something).": "Variation seed strength: مقدار أثر الصورة المدمجة على النتيجة النهائية (0: لا أثر، 1: أثر كامل ما عدا عند استخدام أسلوب خطو سلفي Ancestral)", - "Resize seed from width": "عرض الممزوج", - "Resize seed from height": "إرتفاع الممزوج", - "Make an attempt to produce a picture similar to what would have been produced with same seed at specified resolution": "Seed resize from: حدد دقة صورة الممزوج (0: نفس دقة الإنتاج)", - "Open for Clip Aesthetic!": "تضمين تجميلي", - "▼": "▼", - "Aesthetic weight": "أثر التضمين", - "Aesthetic steps": "عدد الخطوات", - "Aesthetic learning rate": "معدل التعلم", - "Slerp interpolation": "امزج بطريقة كروية", - "Aesthetic imgs embedding": "التضمين", - "None": "بدون", - "Aesthetic text for imgs": "الطلب (اختياري)", - "This text is used to rotate the feature space of the imgs embs": "لإعادة توجيه التضمين التجميلي", - "Slerp angle": "أثر الطلب", - "Is negative text": "الطلب عكسي", - "Script": "أدوات خاصة", - "Prompt matrix": "مصفوفة طلبات", - "Put variable parts at start of prompt": "الجزء المتغير في بداية الطلب", - "Prompts from file or textbox": " قائمة طلبات", - "Iterate seed every line": "غير البذرة مع كل طلب", - "List of prompt inputs": "قائمة الطلبات", - "Upload prompt inputs": "اجلب الطلبات من ملف", - "Drop File Here": "اسقط ملف هنا", - "-": "-", - "or": "أو", - "Click to Upload": "انقر للرفع", - "X/Y plot": "مصفوفة عوامل", - "X type": "العامل الأول", - "Nothing": "لا شيء", - "Var. seed": "بذرة الممزوج", - "Var. strength": "أثر الممزوج", - "Steps": "عدد الخطوات", - "Prompt S/R": "كلمات بديلة", - "Prompt order": "ترتيب الكلمات", - "Sampler": "أسلوب الخطو", - "Checkpoint name": "ملف الأوزان", - "Hypernetwork": "الشبكة الفائقة", - "Hypernet str.": "قوة الشبكة الفائقة", - "Inpainting conditioning mask strength": "قوة قناع الإنتاج الجزئي", - "Only applies to inpainting models. Determines how strongly to mask off the original image for inpainting and img2img. 1.0 means fully masked, which is the default behaviour. 0.0 means a fully unmasked conditioning. Lower values will help preserve the overall composition of the image, but will struggle with large changes.": "حدد مدى صرامة قناع الإنتاج، يصبح القناع شفاف إذا قوته 0 (لا يعمل إلا مع ملفات أوزان الإنتاج الجزئي: inpainting)", - "Sigma Churn": "العشوائية (Schurn)", - "Sigma min": "أدنى تشويش (Stmin)", - "Sigma max": "أقصى تشويش (Stmax)", - "Sigma noise": "التشويش (Snoise)", - "Eta": "العامل Eta η", - "Clip skip": "تخطي آخر طبقات CLIP", - "Denoising": "المدى", - "Cond. Image Mask Weight": "قوة قناع الإنتاج الجزئي", - "X values": "قيم العامل الأول", - "Separate values for X axis using commas.": "افصل القيم بفواصل (,) من اليسار إلى اليمين", - "Y type": "العامل الثاني", - "Y values": "قيم العامل الثاني", - "Separate values for Y axis using commas.": "افصل القيم بفواصل (,) من الأعلى إلى الأسفل", - "Draw legend": "أضف مفتاح التوضيح", - "Include Separate Images": "أضف الصور منفصلة", - "Keep -1 for seeds": "استخدم بذور عشوائية", - "Save": "احفظ", - "Write image to a directory (default - log/images) and generation parameters into csv file.": "احفظ الصور مع ملف العوامل بصيغة CSV", - "Send to img2img": "أرسل لصورة إلى صورة", - "Send to inpaint": "أرسل للإنتاج الجزئي", - "Send to extras": "أرسل للمعالجة", - "Open images output directory": "افتح مجلد الصور المخرجة", - "Make Zip when Save?": "ضع النتائج في ملف مضغوط عند الحفظ", - "img2img": "صورة إلى صورة", - "Interrogate\nCLIP": "استجواب\nCLIP", - "Drop Image Here": "اسقط صورة هنا", - "Just resize": "تغيير الحجم فقط", - "Resize image to target resolution. Unless height and width match, you will get incorrect aspect ratio.": "غير حجم الصورة بدون مراعات اتزان الأبعاد", - "Crop and resize": "تغيير الحجم وقص الأطراف", - "Resize the image so that entirety of target resolution is filled with the image. Crop parts that stick out.": "غير حجم الصورة واقتص الأطراف الزائدة", - "Resize and fill": "تغيير الحجم وتبطين الأطراف", - "Resize the image so that entirety of image is inside target resolution. Fill empty space with image's colors.": "غير حجم الصورة واملأ الأطراف الزائدة بألوان من الصورة", - "img2img alternative test": "استجواب الصورة (تجريبي)", - "should be 2 or lower.": "يفترض أن يكون 2 أو أقل", - "Override `Sampling method` to Euler?(this method is built for it)": "استخدم أسلوب خطو Euler (مستحسن)", - "Override `prompt` to the same value as `original prompt`?(and `negative prompt`)": "استبدل الطلب وعكسه في الأعلى بالطلب الأصلي وعكسه التاليين", - "Original prompt": "الطلب الأصلي", - "Original negative prompt": "عكس الطلب الأصلي", - "Override `Sampling Steps` to the same value as `Decode steps`?": "استبدل عدد الخطوات بعدد الخطوات الأصلية", - "Decode steps": "عدد الخطوات الأصلية", - "Override `Denoising strength` to 1?": "اجعل المدى 1", - "Decode CFG scale": "التركيز", - "Randomness": "العشوائية", - "Sigma adjustment for finding noise for image": "لا تسمح بتثبيت قيمة التباين", - "Loopback": "اجترار وتكرار", - "Loops": "عدد المرات", - "How many times to repeat processing an image and using it as input for the next iteration": "كم مرة يتم أخذ مخرجات الإنتاج كمدخلات وإعادة الإنتاج مرة أخرى", - "Denoising strength change factor": "معدل تغيير المدى", - "In loopback mode, on each loop the denoising strength is multiplied by this value. <1 means decreasing variety so your sequence will converge on a fixed picture. >1 means increasing variety so your sequence will become more and more chaotic.": "يتم ضرب المدى بهذا الرقم في كل مرة، إذا استخدمت رقم أصغر من 1 يمكن الرسو على نتيجة، وإذا استخدمت رقم أكبر من 1 تصبح النتيجة عشوائية", - "Outpainting mk2": "توسيع الصورة (mk2)", - "Recommended settings: Sampling Steps: 80-100, Sampler: Euler a, Denoising strength: 0.8": "يفضل استخدام: 80-100 خطوة، أسلوب Euler a، المدى 0.8", - "Pixels to expand": "عدد البيكسلات", - "Mask blur": "تنعيم القناع", - "How much to blur the mask before processing, in pixels.": "مقدرا تنعيم القناع قبل استخدامه (يقاس بالبيكسل)", - "Outpainting direction": "اتجاه توسيع الصورة", - "left": "يسار", - "right": "يمين", - "up": "فوق", - "down": "تحت", - "Fall-off exponent (lower=higher detail)": "قوة السقوط (كلما قلت زادت التفاصيل)", - "Color variation": "تنوع الألوان", - "Poor man's outpainting": "توسيع الصورة (بدائي)", - "Masked content": "محتويات القناع", - "What to put inside the masked area before processing it with Stable Diffusion.": "ما يوضع مكان الفراغ في الصورة الذي نريد إنتاج محتوياته", - "fill": "ألوان", - "fill it with colors of the image": "املأ باستخدام ألوان مأخوذة من باقي الصورة", - "original": "بدون تغيير", - "keep whatever was there originally": "أبق محتويات ما تحت القناع كما هي", - "latent noise": "تشويش كامن", - "fill it with latent space noise": "املأه باستخدام تشويش من الفضاء الكامن", - "latent nothing": "تصفير كامن", - "fill it with latent space zeroes": "استبدل مكان القناع في الفضاء الكامن بأصفار", - "SD upscale": "مضاعفة الدقة بنموذج الإنتشار المستقر", - "Will upscale the image to twice the dimensions; use width and height sliders to set tile size": "سيتم تكبير حجم الصورة إلى الضعف، استخدم الطول والإرتفاع في الأعلى لتحديد حجم نافذة المكبر", - "Tile overlap": "تداخل النافذة", - "For SD upscale, how much overlap in pixels should there be between tiles. Tiles overlap so that when they are merged back into one picture, there is no clearly visible seam.": "المكبر ينظر إلى أجزاء الصورة من خلال نافذة لتكبير المحتوى ثم ينتقل إلى الجزء المجاور، يفضل أن يكون هناك تداخل بين كل رقعة لكي لا يكون هناك اختلاف واضح بينهم", - "Upscaler": "طريقة التكبير", - "Lanczos": "Lanczos", - "LDSR": "LDSR", - "ScuNET GAN": "ScuNET GAN", - "ScuNET PSNR": "ScuNET PSNR", - "ESRGAN_4x": "ESRGAN_4x", - "SwinIR 4x": "SwinIR 4x", - "Inpaint": "إنتاج جزئي", - "Draw mask": "ارسم القناع", - "Upload mask": "ارفع القناع", - "Inpaint masked": "أنتج ما بداخل القناع", - "Inpaint not masked": "أنتج ما حول القناع", - "Inpaint at full resolution": "إنتاج بالدقة الكاملة", - "Upscale masked region to target resolution, do inpainting, downscale back and paste into original image": "كبر ما يراد إعادة إنتاجه ثم صغر النتيجة وألصقها في مكانها", - "Inpaint at full resolution padding, pixels": "عدد بيكسلات التبطين", - "Batch img2img": "صور إلى صور", - "Process images in a directory on the same machine where the server is running.": "حدد مسار مجلد صور موجود في جهاز الخادم", - "Use an empty output directory to save pictures normally instead of writing to the output directory.": "يمكنك أيضا تحديد مجلد حفظ النتائج (غير الإفتراضي)", - "Input directory": "مجلد المدخلات", - "Output directory": "مجلد المخرجات", - "Extras": "معالجة", - "Single Image": "صورة واحدة", - "Source": "المصدر", - "Scale by": "مضاعفة الدقة", - "Resize": "تغيير الحجم", - "Upscaler 1": "المكبر الأول", - "Upscaler 2": "المكبر الثاني", - "Upscaler 2 visibility": "أثر المكبر الثاني", - "GFPGAN visibility": "أثر GFPGAN (محسن وجوه)", - "CodeFormer visibility": "أثر CodeFormer (محسن وجوه)", - "CodeFormer weight (0 = maximum effect, 1 = minimum effect)": "وزن CodeFormer (يزيد التفاصيل على حساب الجودة)", - "Upscale Before Restoring Faces": "كبر قبل تحسين الوجوه", - "Scale to": "دقة محددة", - "Crop to fit": "قص الأطراف الزائدة إذا لم تتناسب الأبعاد", - "Batch Process": "حزمة صور", - "Batch from Directory": "حزمة من مجلد", - "A directory on the same machine where the server is running.": "مسار مجلد صور موجود في جهاز الخادم", - "Leave blank to save images to the default path.": "اتركه فارغا لاستخدام المسار الإفتراضي", - "Show result images": "اعرض الصور الناتجة", - "PNG Info": "عوامل الصورة", - "Send to txt2img": "أرسل لنص إلى صورة", - "Checkpoint Merger": "مزج الأوزان", - "A merger of the two checkpoints will be generated in your": "سيتم مزج الأوزان التالية وحفظ الأوزان المدجمة مع ", - "checkpoint": "الأوزان", - "directory.": " مجلد.", - "Primary model (A)": "الأوزان الأولى (A)", - "Secondary model (B)": "الأوزان الثانية (B)", - "Tertiary model (C)": "الأوزان الثالثة (C)", - "Custom Name (Optional)": "الاسم الجديد (اختياري)", - "Multiplier (M) - set to 0 to get model A": "العامل M: مسافة الإبتعاد عن الأوزان الأولى A", - "Interpolation Method": "طريقة المزج", - "Weighted sum": "خطية", - "Result = A * (1 - M) + B * M": "النتيجة = A * (1 - M) + B * M", - "Add difference": "جمع الفرق", - "Result = A + (B - C) * M": "النتيجة = A + (B - C) * M", - "Save as float16": "احفظ بدقة float16", - "Run": "تشغيل", - "Train": "تدريب", - "See": "اقرأ", - "wiki": " الـwiki ", - "for detailed explanation.": "لمعرفة المزيد", - "Create embedding": "إنشاء تضمين", - "Name": "الاسم", - "Initialization text": "النص المبدأي", - "Number of vectors per token": "عدد المتجهات لكل وحدة لغوية", - "Overwrite Old Embedding": "استبدل التضمين القديم", - "Create hypernetwork": "إنشاء شبكة فائقة", - "Modules": "الأجزاء", - "Enter hypernetwork layer structure": "ترتيب مضاعفات عرض الطبقات", - "1st and last digit must be 1. ex:'1, 2, 1'": "المضاعفين الأول والأخير يجب أن يكونا 1، مثال: 1, 2, 1", - "Select activation function of hypernetwork": "دالة التنشيط", - "linear": "linear", - "relu": "relu", - "leakyrelu": "leakyrelu", - "elu": "elu", - "swish": "swish", - "tanh": "tanh", - "sigmoid": "sigmoid", - "celu": "celu", - "gelu": "gelu", - "glu": "glu", - "hardshrink": "hardshrink", - "hardsigmoid": "hardsigmoid", - "hardtanh": "hardtanh", - "logsigmoid": "logsigmoid", - "logsoftmax": "logsoftmax", - "mish": "mish", - "prelu": "prelu", - "rrelu": "rrelu", - "relu6": "relu6", - "selu": "selu", - "silu": "silu", - "softmax": "softmax", - "softmax2d": "softmax2d", - "softmin": "softmin", - "softplus": "softplus", - "softshrink": "softshrink", - "softsign": "softsign", - "tanhshrink": "tanhshrink", - "threshold": "threshold", - "Select Layer weights initialization. relu-like - Kaiming, sigmoid-like - Xavier is recommended": "تهيئة الأوزان (استخدم Kaiming مع relu وأمثالها وXavier مع sigmoid وأمثالها)", - "Normal": "Normal", - "KaimingUniform": "KaimingUniform", - "KaimingNormal": "KaimingNormal", - "XavierUniform": "XavierUniform", - "XavierNormal": "XavierNormal", - "Add layer normalization": "أضف تسوية الطبقات (LayerNorm)", - "Use dropout": "استخدم الإسقاط (Dropout)", - "Overwrite Old Hypernetwork": "استبدل الشبكة الفائقة القديمة", - "Preprocess images": "معالجة مسبقة للصور", - "Source directory": "مجلد المدخلات", - "Destination directory": "مجلد المخرجات", - "Existing Caption txt Action": "اذا كانت الصورة لديها توصيف (طلب)", - "ignore": "تجاهل", - "copy": "انسخ", - "prepend": "أسبق", - "append": "ألحق", - "Create flipped copies": "انشئ نسخ معكوسة للصور", - "Split oversized images": "قسّم الصور الكبيرة", - "Split image threshold": "حد تقسيم الصور الكبيرة", - "Split image overlap ratio": "نسبة تداخل اقسام الصور الكبيرة", - "Auto focal point crop": "اقتصاص تلقائي", - "Focal point face weight": "تمركز الوجوه", - "Focal point entropy weight": "تمركز التنوع", - "Focal point edges weight": "تمركز الحواف", - "Create debug image": "احفظ نتائج التحليل أيضا", - "Use BLIP for caption": "استخدم BLIP لتوصيف الصور", - "Use deepbooru for caption": "استخدم deepbooru لتوصيف الصور", - "Preprocess": "معالجة مسبقة", - "Train an embedding or Hypernetwork; you must specify a directory with a set of 1:1 ratio images": "درب التضمين أو الشبكة الفائقة: يجب تحديد مجلد يحتوي صور مربعة فقط ", - "[wiki]": "[wiki]", - "Embedding": "التضمين", - "Embedding Learning rate": "معدل تعلم التضمين", - "Hypernetwork Learning rate": "معدل تعلم الشبكة الفائقة", - "Dataset directory": "مجلد مجموعة البيانات", - "Path to directory with input images": "مسار مجلد الصور المدخلة", - "Log directory": "مجلد السجل", - "Path to directory where to write outputs": "مسار مجلد الصور المخرجة", - "Prompt template file": "ملف صيغ الطلبات", - "Max steps": "أقصى عدد لخطوات التدريب", - "Save an image to log directory every N steps, 0 to disable": "احفظ صورة في السجل بعد كل كم خطوة تدريب (إذا 0 لا تحفظ)", - "Save a copy of embedding to log directory every N steps, 0 to disable": "احفظ التضمين في السجل بعد كل كم خطوة تدريب (إذا 0 لا تحفظ)", - "Save images with embedding in PNG chunks": "احفظ التضمين بداخل ملف الصورة كعامل يمكن استخراجه من عوامل الصورة (صيغة PNG)", - "Read parameters (prompt, etc...) from txt2img tab when making previews": "استخدم قيم العوامل الموجودة في تبويب نص إلى صورة لعرض نتائجهم أثناء التدريب", - "Train Hypernetwork": "درّب الشبكة الفائقة", - "Train Embedding": "درّب التضمين", - "Create aesthetic embedding": "تضمين تجميلي", - "Create an aesthetic embedding out of any number of images": "انشئ تضمين تجميلي يعبر عن مجموعة من الصور", - "Create images embedding": "انشئ التضمين التجميلي", - "Image Browser": "معرض الصور", - "Load": "حمّل", - "Images directory": "مجلد الصور", - "First Page": "الصفحة الأولى", - "Prev Page": "الصفحة السابقة", - "Page Index": "رقم الصفحة", - "Next Page": "الصفحة التالية", - "End Page": "الصفحة الأخيرة", - "number of images to delete consecutively next": "عدد الصور المتتالية للحذف", - "Delete": "احذف", - "Generate Info": "معلومات عامة", - "File Name": "اسم الملف", - "Collect": "اجمع", - "extras": "معالجة", - "favorites": "المفضلة", - "custom fold": "مجلد آخر", - "Input images directory": "مجلد الصور المدخلة", - "Settings": "إعدادات", - "Apply settings": "طبق الإعدادت", - "Saving images/grids": "حفظ الصور وجداولها", - "Always save all generated images": "احفظ كل الصور المنتجة", - "File format for images": "صيغة ملفات الصور", - "Images filename pattern": "نمط تسمية الصور", - "Use following tags to define how filenames for images are chosen: [steps], [cfg], [prompt], [prompt_no_styles], [prompt_spaces], [width], [height], [styles], [sampler], [seed], [model_hash], [prompt_words], [date], [datetime], [datetime], [datetime