diff --git a/CHANGELOG.md b/CHANGELOG.md index fbeb78785..8dd418e4b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ ## Update for 06/03/2023 +- added extra networks to xyz grid options + now you can have more fun with all your loras :) - new vae decode method to help with larger batch sizes, thanks @bigdog - profiling of scripts/extensions callbacks - additional exception handling so bad exception does not crash main app diff --git a/extensions-builtin/Lora/ui_extra_networks_lora.py b/extensions-builtin/Lora/ui_extra_networks_lora.py index 259e99ac8..dad4500e7 100644 --- a/extensions-builtin/Lora/ui_extra_networks_lora.py +++ b/extensions-builtin/Lora/ui_extra_networks_lora.py @@ -14,21 +14,20 @@ class ExtraNetworksPageLora(ui_extra_networks.ExtraNetworksPage): def list_items(self): for name, lora_on_disk in lora.available_loras.items(): - path, ext = os.path.splitext(lora_on_disk.filename) - + path, _ext = os.path.splitext(lora_on_disk.filename) alias = lora_on_disk.get_alias() - yield { "name": name, "filename": path, "preview": self.find_preview(path), "description": self.find_description(path), "search_term": self.search_terms_from_path(lora_on_disk.filename), - "prompt": json.dumps(f""), + "prompt": json.dumps(f""), "local_preview": f"{path}.{shared.opts.samples_format}", "metadata": json.dumps(lora_on_disk.metadata, indent=4) if lora_on_disk.metadata else None, } def allowed_directories_for_previews(self): return [shared.cmd_opts.lora_dir] - diff --git a/extensions-builtin/sd-webui-agent-scheduler b/extensions-builtin/sd-webui-agent-scheduler index b07031958..08cdc1854 160000 --- a/extensions-builtin/sd-webui-agent-scheduler +++ b/extensions-builtin/sd-webui-agent-scheduler @@ -1 +1 @@ -Subproject commit b0703195833b8ea055e07b80902cbda1a01363f6 +Subproject commit 08cdc1854f126ec213f8462bdf81cdb0032bee69 diff --git a/extensions-builtin/sd-webui-controlnet b/extensions-builtin/sd-webui-controlnet index d8551e447..f36493878 160000 --- a/extensions-builtin/sd-webui-controlnet +++ b/extensions-builtin/sd-webui-controlnet @@ -1 +1 @@ -Subproject commit d8551e447d8718e15b8ff5de04036d3fd1b3c5ce +Subproject commit f36493878b299c367bc51f2935fd7e6d19188569 diff --git a/extensions-builtin/stable-diffusion-webui-images-browser b/extensions-builtin/stable-diffusion-webui-images-browser index 5795886be..488c5393d 160000 --- a/extensions-builtin/stable-diffusion-webui-images-browser +++ b/extensions-builtin/stable-diffusion-webui-images-browser @@ -1 +1 @@ -Subproject commit 5795886bee895c2e69e5c64e67aa643da423511c +Subproject commit 488c5393db60f0b1ddfb8ab18f3db9119227c962 diff --git a/javascript/set-hints.js b/javascript/set-hints.js index 64d18b43b..029db6422 100644 --- a/javascript/set-hints.js +++ b/javascript/set-hints.js @@ -18,3 +18,11 @@ onUiUpdate(() => { select.onchange = () => select.title = titles[select.value] || ''; }); }); + +/* +// dump elements +const elements = [ + ...Array.from(gradioApp().querySelectorAll('button')).map(el => ({id: el.id, text: el.textContent, title: el.title })), + ...Array.from(gradioApp().querySelectorAll('label > span')).map(el => ({id: el.id, text: el.textContent, title: el.title })), +]; +*/ diff --git a/modules/devices.py b/modules/devices.py index 510e02a03..5a2785974 100644 --- a/modules/devices.py +++ b/modules/devices.py @@ -98,6 +98,17 @@ def test_fp16(): shared.opts.no_half_vae = True return False +def test_bf16(): + if shared.cmd_opts.experimental: + return True + try: + import torch.nn.functional as F + image = torch.randn(1, 4, 32, 32).to(device="cuda", dtype=torch.bfloat16) + _out = F.interpolate(image, size=(64, 64), mode="nearest") + except: + shared.log.warning('Torch BF16 test failed: Fallback to FP16 operations') + return False + def set_cuda_params(): shared.log.debug('Verifying Torch settings') @@ -117,25 +128,32 @@ def set_cuda_params(): except: pass global dtype, dtype_vae, dtype_unet, unet_needs_upcast # pylint: disable=global-statement - ok = test_fp16() if shared.cmd_opts.use_directml and not shared.cmd_opts.experimental: # TODO DirectML does not have full autocast capabilities shared.opts.no_half = True shared.opts.no_half_vae = True - if ok and shared.opts.cuda_dtype == 'FP32': - shared.log.info('CUDA FP16 test passed but desired mode is set to FP32') - if shared.opts.cuda_dtype == 'FP16' and ok: - dtype = torch.float16 - dtype_vae = torch.float16 - dtype_unet = torch.float16 - if shared.opts.cuda_dtype == 'BF16' and ok: - dtype = torch.bfloat16 - dtype_vae = torch.bfloat16 - dtype_unet = torch.bfloat16 - if shared.opts.cuda_dtype == 'FP32' or shared.opts.no_half or not ok: + if shared.opts.cuda_dtype == 'FP32': + dtype = torch.float32 + dtype_vae = torch.float32 + dtype_unet = torch.float32 + if shared.opts.cuda_dtype == 'BF16' or dtype == torch.bfloat16: + bf16_ok = test_bf16() + dtype = torch.bfloat16 if bf16_ok else torch.float16 + dtype_vae = torch.bfloat16 if bf16_ok else torch.float16 + dtype_unet = torch.bfloat16 if bf16_ok else torch.float16 + if shared.opts.cuda_dtype == 'FP16' or dtype == torch.bfloat16: + fp16_ok = test_fp16() + dtype = torch.float16 if fp16_ok else torch.float32 + dtype_vae = torch.float16 if fp16_ok else torch.float32 + dtype_unet = torch.float16 if fp16_ok else torch.float32 + else: + pass + if shared.opts.no_half: + shared.log.info('Torch override dtype: no-half set') dtype = torch.float32 dtype_vae = torch.float32 dtype_unet = torch.float32 if shared.opts.no_half_vae: # set dtype again as no-half-vae options take priority + shared.log.info('Torch override VAE dtype: no-half-vae set') dtype_vae = torch.float32 unet_needs_upcast = shared.opts.upcast_sampling shared.log.debug(f'Desired Torch parameters: dtype={shared.opts.cuda_dtype} no-half={shared.opts.no_half} no-half-vae={shared.opts.no_half_vae} upscast={shared.opts.upcast_sampling}') @@ -150,7 +168,7 @@ if args.use_ipex: CondFunc('torch.nn.modules.GroupNorm.forward', lambda orig_func, *args, **kwargs: orig_func(args[0], args[1].to(args[0].weight.data.dtype)), lambda *args, **kwargs: args[2].dtype != args[1].weight.data.dtype) - + #Use XPU instead of CPU. %20 Perf improvement on weak CPUs. if args.device_id is not None: cpu = torch.device(f"xpu:{args.device_id}") diff --git a/modules/lora b/modules/lora index 7c38c33ed..0fe1afd4e 160000 --- a/modules/lora +++ b/modules/lora @@ -1 +1 @@ -Subproject commit 7c38c33ed62fa1becab94f967a52aca18ffaccc0 +Subproject commit 0fe1afd4efda89d3d4c8f25c5193c6859a32bc42 diff --git a/modules/memstats.py b/modules/memstats.py index 00260bebf..792d1fdc5 100644 --- a/modules/memstats.py +++ b/modules/memstats.py @@ -19,6 +19,8 @@ def memory_stats(): s = torch.cuda.mem_get_info() gpu = { 'used': gb(s[1] - s[0]), 'total': gb(s[1]) } s = dict(torch.cuda.memory_stats()) + if s['num_ooms'] > 0: + shared.state.oom = True mem.update({ 'gpu': gpu, 'retries': s['num_alloc_retries'], @@ -35,6 +37,8 @@ def memory_stats(): 'retries': s['num_alloc_retries'], 'oom': s['num_ooms'] }) + if s['num_ooms'] > 0: + shared.state.oom = True return mem except: pass diff --git a/modules/shared.py b/modules/shared.py index e30532978..88f1ce227 100644 --- a/modules/shared.py +++ b/modules/shared.py @@ -102,6 +102,7 @@ class State: time_start = None need_restart = False server_start = None + oom = False def skip(self): log.debug('Requested skip') @@ -496,8 +497,10 @@ options_templates.update(options_section(('upscaling', "Upscaling"), { "lora_functional": OptionInfo(False, "Use Kohya method for handling multiple Loras", gr.Checkbox, { "visible": False }), })) -# options_templates.update(options_section(('lora', "Lora"), { -# })) +options_templates.update(options_section(('lora', "Lora"), { + "lyco_patch_lora": OptionInfo(False, "Use LyCoris handler for all Lora types", gr.Checkbox, { "visible": True }), # TODO: lyco-patch-lora + "lora_functional": OptionInfo(False, "Use Kohya method for handling multiple Loras", gr.Checkbox, { "visible": True }), +})) options_templates.update(options_section(('face-restoration', "Face restoration"), { "face_restoration_model": OptionInfo("CodeFormer", "Face restoration model", gr.Radio, lambda: {"choices": [x.name() for x in face_restorers]}), diff --git a/modules/ui_extra_networks.py b/modules/ui_extra_networks.py index 79e5c5ae1..929f671c5 100644 --- a/modules/ui_extra_networks.py +++ b/modules/ui_extra_networks.py @@ -4,7 +4,7 @@ import os.path import urllib.parse from pathlib import Path import gradio as gr -from modules import shared +from modules import shared, scripts from modules.generation_parameters_copypaste import image_from_url_text from modules.ui_components import ToolButton @@ -54,10 +54,27 @@ class ExtraNetworksPage: self.card_short = shared.html("extra-networks-card-short.html") self.allow_negative_prompt = False self.metadata = {} + self.items = [] def refresh(self): pass + def create_xyz_grid(self): + xyz_grid = [x for x in scripts.scripts_data if x.script_class.__module__ == "xyz_grid.py"][0].module + + def add_prompt(p, opt, x): + for item in [x for x in self.items if x["name"] == opt]: + try: + p.prompt = f'{p.prompt} {eval(item["prompt"])}' # pylint: disable=eval-used + except Exception as e: + shared.log.error(f'Cannot evaluate extra network prompt: {item["prompt"]} {e}') + + if not any(self.title in x.label for x in xyz_grid.axis_options): + if self.title == 'Checkpoints': + return + opt = xyz_grid.AxisOption(f"[Network] {self.title}", str, add_prompt, choices=lambda: [x["name"] for x in self.items]) + xyz_grid.axis_options.append(opt) + def link_preview(self, filename): quoted_filename = urllib.parse.quote(filename.replace('\\', '/')) mtime = os.path.getmtime(filename) @@ -93,12 +110,14 @@ class ExtraNetworksPage: if subdirs: subdirs = {"": 1, **subdirs} subdirs_html = "".join([f""" - -""" for subdir in subdirs]) + + """ for subdir in subdirs]) try: - for item in self.list_items(): + self.items = list(self.list_items()) + self.create_xyz_grid() + for item in self.items: metadata = item.get("metadata") if metadata: self.metadata[item["name"]] = metadata diff --git a/scripts/xyz_grid.py b/scripts/xyz_grid.py index cfa56fa12..43304cb4b 100644 --- a/scripts/xyz_grid.py +++ b/scripts/xyz_grid.py @@ -207,35 +207,34 @@ class AxisOptionTxt2Img(AxisOption): axis_options = [ AxisOption("Nothing", str, do_nothing, fmt=format_nothing), - AxisOption("Seed", int, apply_field("seed")), - AxisOption("Var. seed", int, apply_field("subseed")), - AxisOption("Var. strength", float, apply_field("subseed_strength")), - AxisOption("Steps", int, apply_field("steps")), - AxisOptionTxt2Img("Hires steps", int, apply_field("hr_second_pass_steps")), - AxisOption("CFG Scale", float, apply_field("cfg_scale")), - AxisOptionImg2Img("Image CFG Scale", float, apply_field("image_cfg_scale")), + AxisOption("Checkpoint name", str, apply_checkpoint, fmt=format_value, confirm=confirm_checkpoints, cost=1.0, choices=lambda: list(sd_models.checkpoints_list)), + AxisOption("VAE", str, apply_vae, cost=0.7, choices=lambda: ['None'] + list(sd_vae.vae_dict)), AxisOption("Prompt S/R", str, apply_prompt, fmt=format_value), - AxisOption("Prompt order", str_permutations, apply_order, fmt=format_value_join_list), + AxisOption("Styles", str, apply_styles, choices=lambda: list(shared.prompt_styles.styles)), AxisOptionTxt2Img("Sampler", str, apply_sampler, fmt=format_value, confirm=confirm_samplers, choices=lambda: [x.name for x in sd_samplers.samplers]), AxisOptionImg2Img("Sampler", str, apply_sampler, fmt=format_value, confirm=confirm_samplers, choices=lambda: [x.name for x in sd_samplers.samplers_for_img2img]), - AxisOption("Checkpoint name", str, apply_checkpoint, fmt=format_value, confirm=confirm_checkpoints, cost=1.0, choices=lambda: list(sd_models.checkpoints_list)), - AxisOption("Sigma Churn", float, apply_field("s_churn")), - AxisOption("Sigma min", float, apply_field("s_tmin")), - AxisOption("Sigma max", float, apply_field("s_tmax")), - AxisOption("Sigma noise", float, apply_field("s_noise")), - AxisOption("Eta", float, apply_field("eta")), + AxisOption("Seed", int, apply_field("seed")), + AxisOption("Steps", int, apply_field("steps")), + AxisOption("CFG Scale", float, apply_field("cfg_scale")), + AxisOption("Var. seed", int, apply_field("subseed")), + AxisOption("Var. strength", float, apply_field("subseed_strength")), AxisOption("Clip skip", int, apply_clip_skip), AxisOption("Denoising", float, apply_field("denoising_strength")), + AxisOptionTxt2Img("Hires steps", int, apply_field("hr_second_pass_steps")), + AxisOptionImg2Img("Image CFG Scale", float, apply_field("image_cfg_scale")), + AxisOption("Prompt order", str_permutations, apply_order, fmt=format_value_join_list), + AxisOption("Sampler Sigma Churn", float, apply_field("s_churn")), + AxisOption("Sampler Sigma min", float, apply_field("s_tmin")), + AxisOption("Sampler Sigma max", float, apply_field("s_tmax")), + AxisOption("Sampler Sigma noise", float, apply_field("s_noise")), + AxisOption("Sampler Eta", float, apply_field("eta")), AxisOptionTxt2Img("Hires upscaler", str, apply_field("hr_upscaler"), choices=lambda: [*shared.latent_upscale_modes, *[x.name for x in shared.sd_upscalers]]), - AxisOptionTxt2Img("Fallback latent upscaler sampler", str, apply_fallback, fmt=format_value, confirm=confirm_samplers, choices=lambda: [x.name for x in sd_samplers.samplers]), - AxisOptionImg2Img("Cond. Image Mask Weight", float, apply_field("inpainting_mask_weight")), - AxisOption("VAE", str, apply_vae, cost=0.7, choices=lambda: ['None'] + list(sd_vae.vae_dict)), - AxisOption("Styles", str, apply_styles, choices=lambda: list(shared.prompt_styles.styles)), + AxisOptionImg2Img("Image Mask Weight", float, apply_field("inpainting_mask_weight")), AxisOption("UniPC Order", int, apply_uni_pc_order, cost=0.5), AxisOption("Face restore", str, apply_face_restore, fmt=format_value), - AxisOption("ToMe ratio",float,apply_token_merging_ratio), - AxisOption("ToMe ratio for Hires fix",float,apply_token_merging_ratio_hr), - AxisOption("ToMe random pertubations",str,apply_token_merging_random, choices = lambda: ["Yes","No"]) + AxisOption("ToMe ratio",float, apply_token_merging_ratio), + AxisOption("ToMe ratio for Hires fix",float, apply_token_merging_ratio_hr), + AxisOption("ToMe random pertubations",str, apply_token_merging_random, choices = lambda: ["Yes","No"]) ] diff --git a/webui.py b/webui.py index 13d7faa9f..8f090b415 100644 --- a/webui.py +++ b/webui.py @@ -222,7 +222,7 @@ def start_ui(): gradio_auth_creds += [x.strip() for x in line.split(',') if x.strip()] import installer - global local_url + global local_url # pylint: disable=global-statement app, local_url, share_url = shared.demo.launch( share=cmd_opts.share, server_name=server_name,