From 04924241218bb51bee255bebc6c66ef1de449f4a Mon Sep 17 00:00:00 2001 From: bluelovers Date: Sun, 12 Mar 2023 10:18:33 +0800 Subject: feat: try sort as ignore-case https://github.com/AUTOMATIC1111/stable-diffusion-webui/issues/8368 --- modules/shared.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'modules/shared.py') diff --git a/modules/shared.py b/modules/shared.py index 805f9cc1..1322b96d 100644 --- a/modules/shared.py +++ b/modules/shared.py @@ -702,7 +702,7 @@ mem_mon.start() def listfiles(dirname): - filenames = [os.path.join(dirname, x) for x in sorted(os.listdir(dirname)) if not x.startswith(".")] + filenames = [os.path.join(dirname, x) for x in sorted(os.listdir(dirname), key=str.lower) if not x.startswith(".")] return [file for file in filenames if os.path.isfile(file)] -- cgit v1.2.3 From 2a4d3d21242dcc8b2b9cef85aa8f4227e855dc96 Mon Sep 17 00:00:00 2001 From: space-nuko <24979496+space-nuko@users.noreply.github.com> Date: Mon, 27 Mar 2023 12:04:45 -0400 Subject: Add temporary "disable all extensions" option for debugging use --- launch.py | 4 ++++ modules/extensions.py | 4 ++++ modules/shared.py | 3 ++- 3 files changed, 10 insertions(+), 1 deletion(-) (limited to 'modules/shared.py') diff --git a/launch.py b/launch.py index c41ae82d..1321b77a 100644 --- a/launch.py +++ b/launch.py @@ -206,6 +206,10 @@ def list_extensions(settings_file): print(e, file=sys.stderr) disabled_extensions = set(settings.get('disabled_extensions', [])) + disable_all_extensions = settings.get('disable_all_extensions', False) + + if disable_all_extensions: + return [] return [x for x in os.listdir(extensions_dir) if x not in disabled_extensions] diff --git a/modules/extensions.py b/modules/extensions.py index 0d34b89a..1493e8c8 100644 --- a/modules/extensions.py +++ b/modules/extensions.py @@ -97,6 +97,10 @@ def list_extensions(): if not os.path.isdir(extensions_dir): return + if shared.opts.disable_all_extensions: + print("*** \"Disable all extensions\" option was set, will not load any extensions ***") + return + extension_paths = [] for dirname in [extensions_dir, extensions_builtin_dir]: if not os.path.isdir(dirname): diff --git a/modules/shared.py b/modules/shared.py index 3ad0862b..c79ec67b 100644 --- a/modules/shared.py +++ b/modules/shared.py @@ -422,7 +422,8 @@ options_templates.update(options_section(('postprocessing', "Postprocessing"), { })) options_templates.update(options_section((None, "Hidden options"), { - "disabled_extensions": OptionInfo([], "Disable those extensions"), + "disabled_extensions": OptionInfo([], "Disable these extensions"), + "disable_all_extensions": OptionInfo(False, "Disable all extensions (preserves the list of disabled extensions)"), "sd_checkpoint_hash": OptionInfo("", "SHA256 hash of the current checkpoint"), })) -- cgit v1.2.3 From fc8e1008ea93f98554907f25aaf52f24ce661847 Mon Sep 17 00:00:00 2001 From: space-nuko <24979496+space-nuko@users.noreply.github.com> Date: Mon, 27 Mar 2023 12:44:49 -0400 Subject: Make disable configurable between builtin/extra extensions --- javascript/extensions.js | 6 +++--- launch.py | 4 ---- modules/extensions.py | 13 +++++++++---- modules/shared.py | 2 +- modules/ui_extensions.py | 21 +++++++++++++++++---- 5 files changed, 30 insertions(+), 16 deletions(-) (limited to 'modules/shared.py') diff --git a/javascript/extensions.js b/javascript/extensions.js index c593cd2e..72924a28 100644 --- a/javascript/extensions.js +++ b/javascript/extensions.js @@ -1,5 +1,5 @@ -function extensions_apply(_, _){ +function extensions_apply(_, _, disable_all){ var disable = [] var update = [] @@ -13,10 +13,10 @@ function extensions_apply(_, _){ restart_reload() - return [JSON.stringify(disable), JSON.stringify(update)] + return [JSON.stringify(disable), JSON.stringify(update), disable_all] } -function extensions_check(){ +function extensions_check(_, _){ var disable = [] gradioApp().querySelectorAll('#extensions input[type="checkbox"]').forEach(function(x){ diff --git a/launch.py b/launch.py index 1321b77a..c41ae82d 100644 --- a/launch.py +++ b/launch.py @@ -206,10 +206,6 @@ def list_extensions(settings_file): print(e, file=sys.stderr) disabled_extensions = set(settings.get('disabled_extensions', [])) - disable_all_extensions = settings.get('disable_all_extensions', False) - - if disable_all_extensions: - return [] return [x for x in os.listdir(extensions_dir) if x not in disabled_extensions] diff --git a/modules/extensions.py b/modules/extensions.py index 1493e8c8..3a7a0372 100644 --- a/modules/extensions.py +++ b/modules/extensions.py @@ -15,7 +15,12 @@ if not os.path.exists(extensions_dir): def active(): - return [x for x in extensions if x.enabled] + if shared.opts.disable_all_extensions == "all": + return [] + elif shared.opts.disable_all_extensions == "extra": + return [x for x in extensions if x.enabled and x.is_builtin] + else: + return [x for x in extensions if x.enabled] class Extension: @@ -97,9 +102,10 @@ def list_extensions(): if not os.path.isdir(extensions_dir): return - if shared.opts.disable_all_extensions: + if shared.opts.disable_all_extensions == "all": print("*** \"Disable all extensions\" option was set, will not load any extensions ***") - return + elif shared.opts.disable_all_extensions == "extra": + print("*** \"Disable all extensions\" option was set, will only load built-in extensions ***") extension_paths = [] for dirname in [extensions_dir, extensions_builtin_dir]: @@ -116,4 +122,3 @@ def list_extensions(): for dirname, path, is_builtin in extension_paths: extension = Extension(name=dirname, path=path, enabled=dirname not in shared.opts.disabled_extensions, is_builtin=is_builtin) extensions.append(extension) - diff --git a/modules/shared.py b/modules/shared.py index c79ec67b..5fd0eecb 100644 --- a/modules/shared.py +++ b/modules/shared.py @@ -423,7 +423,7 @@ options_templates.update(options_section(('postprocessing', "Postprocessing"), { options_templates.update(options_section((None, "Hidden options"), { "disabled_extensions": OptionInfo([], "Disable these extensions"), - "disable_all_extensions": OptionInfo(False, "Disable all extensions (preserves the list of disabled extensions)"), + "disable_all_extensions": OptionInfo("none", "Disable all extensions (preserves the list of disabled extensions)", gr.Radio, {"choices": ["none", "extra", "all"]}), "sd_checkpoint_hash": OptionInfo("", "SHA256 hash of the current checkpoint"), })) diff --git a/modules/ui_extensions.py b/modules/ui_extensions.py index b4a0d6ec..efd6cda2 100644 --- a/modules/ui_extensions.py +++ b/modules/ui_extensions.py @@ -21,7 +21,7 @@ def check_access(): assert not shared.cmd_opts.disable_extension_access, "extension access disabled because of command line flags" -def apply_and_restart(disable_list, update_list): +def apply_and_restart(disable_list, update_list, disable_all): check_access() disabled = json.loads(disable_list) @@ -43,6 +43,7 @@ def apply_and_restart(disable_list, update_list): print(traceback.format_exc(), file=sys.stderr) shared.opts.disabled_extensions = disabled + shared.opts.disable_all_extensions = disable_all shared.opts.save(shared.config_filename) shared.state.interrupt() @@ -99,9 +100,13 @@ def extension_table(): else: ext_status = ext.status + style = "" + if shared.opts.disable_all_extensions == "extra" and not ext.is_builtin or shared.opts.disable_all_extensions == "all": + style = ' style="color: var(--primary-400)"' + code += f""" - + {html.escape(ext.name)} {remote} {ext.version} {ext_status} @@ -294,16 +299,24 @@ def create_ui(): with gr.Row(elem_id="extensions_installed_top"): apply = gr.Button(value="Apply and restart UI", variant="primary") check = gr.Button(value="Check for updates") + extensions_disable_all = gr.Radio(label="Disable all extensions", choices=["none", "extra", "all"], value=shared.opts.disable_all_extensions, elem_id="extensions_disable_all") extensions_disabled_list = gr.Text(elem_id="extensions_disabled_list", visible=False).style(container=False) extensions_update_list = gr.Text(elem_id="extensions_update_list", visible=False).style(container=False) - info = gr.HTML() + html = "" + if shared.opts.disable_all_extensions != "none": + html = """ + + "Disable all extensions" was set, change it to "none" to load all extensions again + + """ + info = gr.HTML(html) extensions_table = gr.HTML(lambda: extension_table()) apply.click( fn=apply_and_restart, _js="extensions_apply", - inputs=[extensions_disabled_list, extensions_update_list], + inputs=[extensions_disabled_list, extensions_update_list, extensions_disable_all], outputs=[], ) -- cgit v1.2.3 From b3593d0997bfdcca7f8aa01663e81720db50e494 Mon Sep 17 00:00:00 2001 From: For Sure Date: Thu, 6 Apr 2023 19:42:26 +0300 Subject: Add support for saving init images in img2img --- modules/processing.py | 8 ++++++++ modules/shared.py | 3 +++ 2 files changed, 11 insertions(+) (limited to 'modules/shared.py') diff --git a/modules/processing.py b/modules/processing.py index 6d9c6a8d..5556afc5 100644 --- a/modules/processing.py +++ b/modules/processing.py @@ -3,6 +3,7 @@ import math import os import sys import warnings +import hashlib import torch import numpy as np @@ -476,6 +477,7 @@ def create_infotext(p, all_prompts, all_seeds, all_subseeds, comments=None, iter "Conditional mask weight": getattr(p, "inpainting_mask_weight", shared.opts.inpainting_mask_weight) if p.is_using_inpainting_conditioning else None, "Clip skip": None if clip_skip <= 1 else clip_skip, "ENSD": None if opts.eta_noise_seed_delta == 0 else opts.eta_noise_seed_delta, + "Init image hash": getattr(p, 'init_img_hash', None) } generation_params.update(p.extra_generation_params) @@ -1007,6 +1009,12 @@ class StableDiffusionProcessingImg2Img(StableDiffusionProcessing): self.color_corrections = [] imgs = [] for img in self.init_images: + + # Save init image + if opts.save_init_img: + self.init_img_hash = hashlib.md5(img.tobytes()).hexdigest() + images.save_image(img, path=opts.outdir_init_images, basename=None, forced_filename=self.init_img_hash, save_to_dirs=False) + image = images.flatten(img, opts.img2img_background_color) if crop_region is None and self.resize_mode != 3: diff --git a/modules/shared.py b/modules/shared.py index 5fd0eecb..69c2b21e 100644 --- a/modules/shared.py +++ b/modules/shared.py @@ -39,6 +39,7 @@ restricted_opts = { "outdir_grids", "outdir_txt2img_grids", "outdir_save", + "outdir_init_images" } ui_reorder_categories = [ @@ -253,6 +254,7 @@ options_templates.update(options_section(('saving-images', "Saving images/grids" "use_upscaler_name_as_suffix": OptionInfo(False, "Use upscaler name as filename suffix in the extras tab"), "save_selected_only": OptionInfo(True, "When using 'Save' button, only save a single selected image"), "do_not_add_watermark": OptionInfo(False, "Do not add watermark to images"), + "save_init_img": OptionInfo(True, "Save init images when using img2img"), "temp_dir": OptionInfo("", "Directory for temporary images; leave empty for default"), "clean_temp_dir_at_start": OptionInfo(False, "Cleanup non-default temporary directory when starting webui"), @@ -268,6 +270,7 @@ options_templates.update(options_section(('saving-paths', "Paths for saving"), { "outdir_txt2img_grids": OptionInfo("outputs/txt2img-grids", 'Output directory for txt2img grids', component_args=hide_dirs), "outdir_img2img_grids": OptionInfo("outputs/img2img-grids", 'Output directory for img2img grids', component_args=hide_dirs), "outdir_save": OptionInfo("log/images", "Directory for saving images using the Save button", component_args=hide_dirs), + "outdir_init_images": OptionInfo("outputs/init-images", "Directory for saving init images when using img2img", component_args=hide_dirs), })) options_templates.update(options_section(('saving-to-dirs', "Saving to a directory"), { -- cgit v1.2.3 From 63a6f9b4d98a192bb359910cb284cf00582baabf Mon Sep 17 00:00:00 2001 From: forsurefr <67145502+forsurefr@users.noreply.github.com> Date: Fri, 7 Apr 2023 12:13:51 +0300 Subject: Do not save init image by default --- modules/shared.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'modules/shared.py') diff --git a/modules/shared.py b/modules/shared.py index 69c2b21e..c5a1b5ad 100644 --- a/modules/shared.py +++ b/modules/shared.py @@ -254,7 +254,7 @@ options_templates.update(options_section(('saving-images', "Saving images/grids" "use_upscaler_name_as_suffix": OptionInfo(False, "Use upscaler name as filename suffix in the extras tab"), "save_selected_only": OptionInfo(True, "When using 'Save' button, only save a single selected image"), "do_not_add_watermark": OptionInfo(False, "Do not add watermark to images"), - "save_init_img": OptionInfo(True, "Save init images when using img2img"), + "save_init_img": OptionInfo(False, "Save init images when using img2img"), "temp_dir": OptionInfo("", "Directory for temporary images; leave empty for default"), "clean_temp_dir_at_start": OptionInfo(False, "Cleanup non-default temporary directory when starting webui"), -- cgit v1.2.3 From f4b332f0419e09cec6983edcd07aae2ee0c14c24 Mon Sep 17 00:00:00 2001 From: missionfloyd Date: Tue, 18 Apr 2023 17:01:46 -0600 Subject: Add "None" option to extra networks dropdowns --- extensions-builtin/Lora/extra_networks_lora.py | 2 +- extensions-builtin/Lora/scripts/lora_script.py | 2 +- modules/extra_networks_hypernet.py | 2 +- modules/shared.py | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) (limited to 'modules/shared.py') diff --git a/extensions-builtin/Lora/extra_networks_lora.py b/extensions-builtin/Lora/extra_networks_lora.py index 6be6ef73..45f899fc 100644 --- a/extensions-builtin/Lora/extra_networks_lora.py +++ b/extensions-builtin/Lora/extra_networks_lora.py @@ -8,7 +8,7 @@ class ExtraNetworkLora(extra_networks.ExtraNetwork): def activate(self, p, params_list): additional = shared.opts.sd_lora - if additional != "" and additional in lora.available_loras and len([x for x in params_list if x.items[0] == additional]) == 0: + if additional != "None" and additional in lora.available_loras and len([x for x in params_list if x.items[0] == additional]) == 0: p.all_prompts = [x + f"" for x in p.all_prompts] params_list.append(extra_networks.ExtraNetworkParams(items=[additional, shared.opts.extra_networks_default_multiplier])) diff --git a/extensions-builtin/Lora/scripts/lora_script.py b/extensions-builtin/Lora/scripts/lora_script.py index 0adab225..3fc38ab9 100644 --- a/extensions-builtin/Lora/scripts/lora_script.py +++ b/extensions-builtin/Lora/scripts/lora_script.py @@ -52,5 +52,5 @@ script_callbacks.on_before_ui(before_ui) shared.options_templates.update(shared.options_section(('extra_networks', "Extra Networks"), { - "sd_lora": shared.OptionInfo("None", "Add Lora to prompt", gr.Dropdown, lambda: {"choices": [""] + [x for x in lora.available_loras]}, refresh=lora.list_available_loras), + "sd_lora": shared.OptionInfo("None", "Add Lora to prompt", gr.Dropdown, lambda: {"choices": ["None"] + [x for x in lora.available_loras]}, refresh=lora.list_available_loras), })) diff --git a/modules/extra_networks_hypernet.py b/modules/extra_networks_hypernet.py index d3a4d7ad..33d100dd 100644 --- a/modules/extra_networks_hypernet.py +++ b/modules/extra_networks_hypernet.py @@ -9,7 +9,7 @@ class ExtraNetworkHypernet(extra_networks.ExtraNetwork): def activate(self, p, params_list): additional = shared.opts.sd_hypernetwork - if additional != "" and additional in shared.hypernetworks and len([x for x in params_list if x.items[0] == additional]) == 0: + if additional != "None" and additional in shared.hypernetworks and len([x for x in params_list if x.items[0] == additional]) == 0: p.all_prompts = [x + f"" for x in p.all_prompts] params_list.append(extra_networks.ExtraNetworkParams(items=[additional, shared.opts.extra_networks_default_multiplier])) diff --git a/modules/shared.py b/modules/shared.py index 5fd0eecb..5a5fbae6 100644 --- a/modules/shared.py +++ b/modules/shared.py @@ -361,7 +361,7 @@ options_templates.update(options_section(('extra_networks', "Extra Networks"), { "extra_networks_card_width": OptionInfo(0, "Card width for Extra Networks (px)"), "extra_networks_card_height": OptionInfo(0, "Card height for Extra Networks (px)"), "extra_networks_add_text_separator": OptionInfo(" ", "Extra text to add before <...> when adding extra network to prompt"), - "sd_hypernetwork": OptionInfo("None", "Add hypernetwork to prompt", gr.Dropdown, lambda: {"choices": [""] + [x for x in hypernetworks.keys()]}, refresh=reload_hypernetworks), + "sd_hypernetwork": OptionInfo("None", "Add hypernetwork to prompt", gr.Dropdown, lambda: {"choices": ["None"] + [x for x in hypernetworks.keys()]}, refresh=reload_hypernetworks), })) options_templates.update(options_section(('ui', "User interface"), { -- cgit v1.2.3 From d40e44ade479f7bba30d5317381cbc58c861775b Mon Sep 17 00:00:00 2001 From: Deciare <1689220+deciare@users.noreply.github.com> Date: Tue, 18 Apr 2023 23:18:58 -0400 Subject: Option to use CPU for random number generation. Makes a given manual seed generate the same images across different platforms, independently of the GPU architecture in use. Fixes #9613. --- modules/devices.py | 8 ++++++-- modules/sd_samplers_common.py | 9 +++++++++ modules/sd_samplers_kdiffusion.py | 2 +- modules/shared.py | 1 + 4 files changed, 17 insertions(+), 3 deletions(-) (limited to 'modules/shared.py') diff --git a/modules/devices.py b/modules/devices.py index 52c3e7cd..3bc86a6a 100644 --- a/modules/devices.py +++ b/modules/devices.py @@ -92,14 +92,18 @@ def cond_cast_float(input): def randn(seed, shape): + from modules.shared import opts + torch.manual_seed(seed) - if device.type == 'mps': + if opts.use_cpu_randn or device.type == 'mps': return torch.randn(shape, device=cpu).to(device) return torch.randn(shape, device=device) def randn_without_seed(shape): - if device.type == 'mps': + from modules.shared import opts + + if opts.use_cpu_randn or device.type == 'mps': return torch.randn(shape, device=cpu).to(device) return torch.randn(shape, device=device) diff --git a/modules/sd_samplers_common.py b/modules/sd_samplers_common.py index a1aac7cf..e6a372d5 100644 --- a/modules/sd_samplers_common.py +++ b/modules/sd_samplers_common.py @@ -60,3 +60,12 @@ def store_latent(decoded): class InterruptedException(BaseException): pass + +if opts.use_cpu_randn: + import torchsde._brownian.brownian_interval + + def torchsde_randn(size, dtype, device, seed): + generator = torch.Generator(devices.cpu).manual_seed(int(seed)) + return torch.randn(size, dtype=dtype, device=devices.cpu, generator=generator).to(device) + + torchsde._brownian.brownian_interval._randn = torchsde_randn diff --git a/modules/sd_samplers_kdiffusion.py b/modules/sd_samplers_kdiffusion.py index e9f08518..13f4567a 100644 --- a/modules/sd_samplers_kdiffusion.py +++ b/modules/sd_samplers_kdiffusion.py @@ -190,7 +190,7 @@ class TorchHijack: if noise.shape == x.shape: return noise - if x.device.type == 'mps': + if opts.use_cpu_randn or x.device.type == 'mps': return torch.randn_like(x, device=devices.cpu).to(x.device) else: return torch.randn_like(x) diff --git a/modules/shared.py b/modules/shared.py index 5fd0eecb..59b037d5 100644 --- a/modules/shared.py +++ b/modules/shared.py @@ -331,6 +331,7 @@ options_templates.update(options_section(('sd', "Stable Diffusion"), { "comma_padding_backtrack": OptionInfo(20, "Increase coherency by padding from the last comma within n tokens when using more than 75 tokens", gr.Slider, {"minimum": 0, "maximum": 74, "step": 1 }), "CLIP_stop_at_last_layers": OptionInfo(1, "Clip skip", gr.Slider, {"minimum": 1, "maximum": 12, "step": 1}), "upcast_attn": OptionInfo(False, "Upcast cross attention layer to float32"), + "use_cpu_randn": OptionInfo(False, "Use CPU for random number generation to make manual seeds generate the same image across platforms. This may change existing seeds."), })) options_templates.update(options_section(('compatibility', "Compatibility"), { -- cgit v1.2.3 From dec5cdd9b89dd683f04fb904ebd8a56dfce860ae Mon Sep 17 00:00:00 2001 From: AdjointOperator Date: Wed, 19 Apr 2023 15:35:50 +0800 Subject: add tiled inference support for ScuNET --- extensions-builtin/ScuNET/scripts/scunet_model.py | 83 +++++++++++++++++++---- modules/shared.py | 2 + 2 files changed, 70 insertions(+), 15 deletions(-) (limited to 'modules/shared.py') diff --git a/extensions-builtin/ScuNET/scripts/scunet_model.py b/extensions-builtin/ScuNET/scripts/scunet_model.py index e0fbf3a3..c7fd5739 100644 --- a/extensions-builtin/ScuNET/scripts/scunet_model.py +++ b/extensions-builtin/ScuNET/scripts/scunet_model.py @@ -5,11 +5,15 @@ import traceback import PIL.Image import numpy as np import torch +from tqdm import tqdm + from basicsr.utils.download_util import load_file_from_url import modules.upscaler from modules import devices, modelloader from scunet_model_arch import SCUNet as net +from modules.shared import opts +from modules import images class UpscalerScuNET(modules.upscaler.Upscaler): @@ -42,28 +46,78 @@ class UpscalerScuNET(modules.upscaler.Upscaler): scalers.append(scaler_data2) self.scalers = scalers - def do_upscale(self, img: PIL.Image, selected_file): + @staticmethod + @torch.no_grad() + def tiled_inference(img, model): + # test the image tile by tile + h, w = img.shape[2:] + tile = opts.SCUNET_tile + tile_overlap = opts.SCUNET_tile_overlap + if tile == 0: + return model(img) + + device = devices.get_device_for('scunet') + assert tile % 8 == 0, "tile size should be a multiple of window_size" + sf = 1 + + stride = tile - tile_overlap + h_idx_list = list(range(0, h - tile, stride)) + [h - tile] + w_idx_list = list(range(0, w - tile, stride)) + [w - tile] + E = torch.zeros(1, 3, h * sf, w * sf, dtype=img.dtype, device=device) + W = torch.zeros_like(E, dtype=devices.dtype, device=device) + + with tqdm(total=len(h_idx_list) * len(w_idx_list), desc="ScuNET tiles") as pbar: + for h_idx in h_idx_list: + + for w_idx in w_idx_list: + + in_patch = img[..., h_idx: h_idx + tile, w_idx: w_idx + tile] + + out_patch = model(in_patch) + out_patch_mask = torch.ones_like(out_patch) + + E[ + ..., h_idx * sf: (h_idx + tile) * sf, w_idx * sf: (w_idx + tile) * sf + ].add_(out_patch) + W[ + ..., h_idx * sf: (h_idx + tile) * sf, w_idx * sf: (w_idx + tile) * sf + ].add_(out_patch_mask) + pbar.update(1) + output = E.div_(W) + + return output + + def do_upscale(self, img: PIL.Image.Image, selected_file): + torch.cuda.empty_cache() model = self.load_model(selected_file) if model is None: + print(f"ScuNET: Unable to load model from {selected_file}", file=sys.stderr) return img device = devices.get_device_for('scunet') - img = np.array(img) - img = img[:, :, ::-1] - img = np.moveaxis(img, 2, 0) / 255 - img = torch.from_numpy(img).float() - img = img.unsqueeze(0).to(device) - - with torch.no_grad(): - output = model(img) - output = output.squeeze().float().cpu().clamp_(0, 1).numpy() - output = 255. * np.moveaxis(output, 0, 2) - output = output.astype(np.uint8) - output = output[:, :, ::-1] + tile = opts.SCUNET_tile + h, w = img.height, img.width + np_img = np.array(img) + np_img = np_img[:, :, ::-1] # RGB to BGR + np_img = np_img.transpose((2, 0, 1)) / 255 # HWC to CHW + torch_img = torch.from_numpy(np_img).float().unsqueeze(0).to(device) # type: ignore + + if tile > h or tile > w: + _img = torch.zeros(1, 3, max(h, tile), max(w, tile), dtype=torch_img.dtype, device=torch_img.device) + _img[:, :, :h, :w] = torch_img # pad image + torch_img = _img + + torch_output = self.tiled_inference(torch_img, model).squeeze(0) + torch_output = torch_output[:, :h * 1, :w * 1] # remove padding, if any + np_output: np.ndarray = torch_output.float().cpu().clamp_(0, 1).numpy() + del torch_img, torch_output torch.cuda.empty_cache() - return PIL.Image.fromarray(output, 'RGB') + + output = np_output.transpose((1, 2, 0)) # CHW to HWC + output = output[:, :, ::-1] # BGR to RGB + return PIL.Image.fromarray((output * 255).astype(np.uint8)) def load_model(self, path: str): device = devices.get_device_for('scunet') @@ -84,4 +138,3 @@ class UpscalerScuNET(modules.upscaler.Upscaler): model = model.to(device) return model - diff --git a/modules/shared.py b/modules/shared.py index 5fd0eecb..056f9fc6 100644 --- a/modules/shared.py +++ b/modules/shared.py @@ -283,6 +283,8 @@ options_templates.update(options_section(('upscaling', "Upscaling"), { "ESRGAN_tile_overlap": OptionInfo(8, "Tile overlap, in pixels for ESRGAN upscalers. Low values = visible seam.", gr.Slider, {"minimum": 0, "maximum": 48, "step": 1}), "realesrgan_enabled_models": OptionInfo(["R-ESRGAN 4x+", "R-ESRGAN 4x+ Anime6B"], "Select which Real-ESRGAN models to show in the web UI. (Requires restart)", gr.CheckboxGroup, lambda: {"choices": shared_items.realesrgan_models_names()}), "upscaler_for_img2img": OptionInfo(None, "Upscaler for img2img", gr.Dropdown, lambda: {"choices": [x.name for x in sd_upscalers]}), + "SCUNET_tile": OptionInfo(256, "Tile size for SCUNET upscalers. 0 = no tiling.", gr.Slider, {"minimum": 0, "maximum": 512, "step": 16}), + "SCUNET_tile_overlap": OptionInfo(8, "Tile overlap, in pixels for SCUNET upscalers. Low values = visible seam.", gr.Slider, {"minimum": 0, "maximum": 64, "step": 1}), })) options_templates.update(options_section(('face-restoration', "Face restoration"), { -- cgit v1.2.3 From 0e071ae504a8219934b2f35a1d88dcb1f628d7c3 Mon Sep 17 00:00:00 2001 From: missionfloyd Date: Fri, 21 Apr 2023 20:19:58 -0600 Subject: Custom delimiters --- javascript/edit-attention.js | 2 +- modules/shared.py | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) (limited to 'modules/shared.py') diff --git a/javascript/edit-attention.js b/javascript/edit-attention.js index 2307fd7a..588c7b77 100644 --- a/javascript/edit-attention.js +++ b/javascript/edit-attention.js @@ -46,7 +46,7 @@ function keyupEditAttention(event){ function selectCurrentWord(){ if (selectionStart !== selectionEnd) return false; - const delimiters = " .,\\/!?%^*;:{}=`~()\r\n\t"; + const delimiters = opts.keyedit_delimiters + " \r\n\t"; // seek backward until to find beggining while (!delimiters.includes(text[selectionStart - 1]) && selectionStart > 0) { diff --git a/modules/shared.py b/modules/shared.py index 5fd0eecb..3cc2f8ba 100644 --- a/modules/shared.py +++ b/modules/shared.py @@ -382,6 +382,7 @@ options_templates.update(options_section(('ui', "User interface"), { "dimensions_and_batch_together": OptionInfo(True, "Show Width/Height and Batch sliders in same row"), "keyedit_precision_attention": OptionInfo(0.1, "Ctrl+up/down precision when editing (attention:1.1)", gr.Slider, {"minimum": 0.01, "maximum": 0.2, "step": 0.001}), "keyedit_precision_extra": OptionInfo(0.05, "Ctrl+up/down precision when editing ", gr.Slider, {"minimum": 0.01, "maximum": 0.2, "step": 0.001}), + "keyedit_delimiters": OptionInfo(".,\/!?%^*;:{}=`~()", "Ctrl+up/down word delimiters"), "quicksettings": OptionInfo("sd_model_checkpoint", "Quicksettings list"), "hidden_tabs": OptionInfo([], "Hidden UI tabs (requires restart)", ui_components.DropdownMulti, lambda: {"choices": [x for x in tab_names]}), "ui_reorder": OptionInfo(", ".join(ui_reorder_categories), "txt2img/img2img UI item order"), -- cgit v1.2.3 From 5fe0dd79beaa5ef737ff85254ee9870f60ae9464 Mon Sep 17 00:00:00 2001 From: AUTOMATIC <16777216c@gmail.com> Date: Sat, 29 Apr 2023 11:29:37 +0300 Subject: rename CPU RNG to RNG source in settings, add infotext and parameters copypaste support to RNG source --- modules/devices.py | 4 ++-- modules/generation_parameters_copypaste.py | 5 +++++ modules/processing.py | 3 ++- modules/sd_samplers_common.py | 3 ++- modules/sd_samplers_kdiffusion.py | 2 +- modules/shared.py | 2 +- 6 files changed, 13 insertions(+), 6 deletions(-) (limited to 'modules/shared.py') diff --git a/modules/devices.py b/modules/devices.py index 3bc86a6a..c705a3cb 100644 --- a/modules/devices.py +++ b/modules/devices.py @@ -95,7 +95,7 @@ def randn(seed, shape): from modules.shared import opts torch.manual_seed(seed) - if opts.use_cpu_randn or device.type == 'mps': + if opts.randn_source == "CPU" or device.type == 'mps': return torch.randn(shape, device=cpu).to(device) return torch.randn(shape, device=device) @@ -103,7 +103,7 @@ def randn(seed, shape): def randn_without_seed(shape): from modules.shared import opts - if opts.use_cpu_randn or device.type == 'mps': + if opts.randn_source == "CPU" or device.type == 'mps': return torch.randn(shape, device=cpu).to(device) return torch.randn(shape, device=device) diff --git a/modules/generation_parameters_copypaste.py b/modules/generation_parameters_copypaste.py index 6df76858..e7269363 100644 --- a/modules/generation_parameters_copypaste.py +++ b/modules/generation_parameters_copypaste.py @@ -284,6 +284,10 @@ Steps: 20, Sampler: Euler a, CFG scale: 7, Seed: 965400086, Size: 512x512, Model restore_old_hires_fix_params(res) + # Missing RNG means the default was set, which is GPU RNG + if "RNG" not in res: + res["RNG"] = "GPU" + return res @@ -304,6 +308,7 @@ infotext_to_setting_name_mapping = [ ('UniPC skip type', 'uni_pc_skip_type'), ('UniPC order', 'uni_pc_order'), ('UniPC lower order final', 'uni_pc_lower_order_final'), + ('RNG', 'randn_source'), ] diff --git a/modules/processing.py b/modules/processing.py index 5556afc5..7bac154d 100644 --- a/modules/processing.py +++ b/modules/processing.py @@ -477,7 +477,8 @@ def create_infotext(p, all_prompts, all_seeds, all_subseeds, comments=None, iter "Conditional mask weight": getattr(p, "inpainting_mask_weight", shared.opts.inpainting_mask_weight) if p.is_using_inpainting_conditioning else None, "Clip skip": None if clip_skip <= 1 else clip_skip, "ENSD": None if opts.eta_noise_seed_delta == 0 else opts.eta_noise_seed_delta, - "Init image hash": getattr(p, 'init_img_hash', None) + "Init image hash": getattr(p, 'init_img_hash', None), + "RNG": (opts.randn_source if opts.randn_source != "GPU" else None) } generation_params.update(p.extra_generation_params) diff --git a/modules/sd_samplers_common.py b/modules/sd_samplers_common.py index e6a372d5..bc074238 100644 --- a/modules/sd_samplers_common.py +++ b/modules/sd_samplers_common.py @@ -61,7 +61,8 @@ def store_latent(decoded): class InterruptedException(BaseException): pass -if opts.use_cpu_randn: + +if opts.randn_source == "CPU": import torchsde._brownian.brownian_interval def torchsde_randn(size, dtype, device, seed): diff --git a/modules/sd_samplers_kdiffusion.py b/modules/sd_samplers_kdiffusion.py index 13f4567a..a547d1b5 100644 --- a/modules/sd_samplers_kdiffusion.py +++ b/modules/sd_samplers_kdiffusion.py @@ -190,7 +190,7 @@ class TorchHijack: if noise.shape == x.shape: return noise - if opts.use_cpu_randn or x.device.type == 'mps': + if opts.randn_source == "CPU" or x.device.type == 'mps': return torch.randn_like(x, device=devices.cpu).to(x.device) else: return torch.randn_like(x) diff --git a/modules/shared.py b/modules/shared.py index b5b401fe..73704889 100644 --- a/modules/shared.py +++ b/modules/shared.py @@ -334,7 +334,7 @@ options_templates.update(options_section(('sd', "Stable Diffusion"), { "comma_padding_backtrack": OptionInfo(20, "Increase coherency by padding from the last comma within n tokens when using more than 75 tokens", gr.Slider, {"minimum": 0, "maximum": 74, "step": 1 }), "CLIP_stop_at_last_layers": OptionInfo(1, "Clip skip", gr.Slider, {"minimum": 1, "maximum": 12, "step": 1}), "upcast_attn": OptionInfo(False, "Upcast cross attention layer to float32"), - "use_cpu_randn": OptionInfo(False, "Use CPU for random number generation to make manual seeds generate the same image across platforms. This may change existing seeds."), + "randn_source": OptionInfo("GPU", "Random number generator source. Changes seeds drastically. Use CPU to produce the same picture across different vidocard vendors.", gr.Radio, {"choices": ["GPU", "CPU"]}), })) options_templates.update(options_section(('compatibility', "Compatibility"), { -- cgit v1.2.3