From b82caf132274aa3cd9b087ed9dc671e8987a4686 Mon Sep 17 00:00:00 2001 From: Andray Date: Fri, 5 Jul 2024 19:28:16 +0400 Subject: [PATCH 01/37] fix ui flashing on reloading and fast scrollong --- modules/ui_gradio_extensions.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/modules/ui_gradio_extensions.py b/modules/ui_gradio_extensions.py index 18fbd6777..c895b3b63 100644 --- a/modules/ui_gradio_extensions.py +++ b/modules/ui_gradio_extensions.py @@ -41,6 +41,8 @@ def css_html(): if os.path.exists(user_css): head += stylesheet(user_css) + head += '' + return head From ec580374e54cb45cce504b9c8455a748fa1f991d Mon Sep 17 00:00:00 2001 From: w-e-w <40751091+w-e-w@users.noreply.github.com> Date: Sun, 7 Jul 2024 00:22:27 +0900 Subject: [PATCH 02/37] background-color: background_fill_primary --- modules/shared_gradio_themes.py | 41 +++++++++++++++++++++++++++++++++ modules/ui_gradio_extensions.py | 5 +++- 2 files changed, 45 insertions(+), 1 deletion(-) diff --git a/modules/shared_gradio_themes.py b/modules/shared_gradio_themes.py index b6dc31450..b4e3f32bc 100644 --- a/modules/shared_gradio_themes.py +++ b/modules/shared_gradio_themes.py @@ -69,3 +69,44 @@ def reload_gradio_theme(theme_name=None): # append additional values gradio_theme shared.gradio_theme.sd_webui_modal_lightbox_toolbar_opacity = shared.opts.sd_webui_modal_lightbox_toolbar_opacity shared.gradio_theme.sd_webui_modal_lightbox_icon_opacity = shared.opts.sd_webui_modal_lightbox_icon_opacity + + +def resolve_var(name: str, gradio_theme=None, history=None): + """ + Attempt to resolve a theme variable name to its value + + Parameters: + name (str): The name of the theme variable + ie "background_fill_primary", "background_fill_primary_dark" + spaces and asterisk (*) prefix is removed from name before lookup + gradio_theme (gradio.themes.ThemeClass): The theme object to resolve the variable from + blank to use the webui default shared.gradio_theme + history (list): A list of previously resolved variables to prevent circular references + for regular use leave blank + Returns: + str: The resolved value + + Error handling: + return either #000000 or #ffffff depending on initial name ending with "_dark" + """ + try: + if history is None: + history = [] + if gradio_theme is None: + gradio_theme = shared.gradio_theme + + name = name.strip() + name = name[1:] if name.startswith("*") else name + + if name in history: + raise ValueError(f'Circular references: name "{name}" in {history}') + + if value := getattr(gradio_theme, name, None): + return resolve_var(value, gradio_theme, history + [name]) + else: + return name + + except Exception: + name = history[0] if history else name + errors.report(f'resolve_color({name})', exc_info=True) + return '#000000' if name.endswith("_dark") else '#ffffff' diff --git a/modules/ui_gradio_extensions.py b/modules/ui_gradio_extensions.py index c895b3b63..ed57c1e98 100644 --- a/modules/ui_gradio_extensions.py +++ b/modules/ui_gradio_extensions.py @@ -41,7 +41,10 @@ def css_html(): if os.path.exists(user_css): head += stylesheet(user_css) - head += '' + from modules.shared_gradio_themes import resolve_var + light = resolve_var('background_fill_primary') + dark = resolve_var('background_fill_primary_dark') + head += f'' return head From 11cfe0dd054926b5df81632f9e2b2a78738ccf95 Mon Sep 17 00:00:00 2001 From: AUTOMATIC1111 <16777216c@gmail.com> Date: Sun, 7 Jul 2024 16:36:53 +0300 Subject: [PATCH 03/37] sd3 TI support --- modules/models/sd3/other_impls.py | 8 +++++--- modules/models/sd3/sd3_cond.py | 6 +++++- modules/sd_hijack.py | 17 ++++++++++++++++- 3 files changed, 26 insertions(+), 5 deletions(-) diff --git a/modules/models/sd3/other_impls.py b/modules/models/sd3/other_impls.py index f992db9bd..78c1dc687 100644 --- a/modules/models/sd3/other_impls.py +++ b/modules/models/sd3/other_impls.py @@ -5,6 +5,8 @@ import math from torch import nn from transformers import CLIPTokenizer, T5TokenizerFast +from modules import sd_hijack + ################################################################################################# ### Core/Utility @@ -110,9 +112,9 @@ class CLIPEncoder(torch.nn.Module): class CLIPEmbeddings(torch.nn.Module): - def __init__(self, embed_dim, vocab_size=49408, num_positions=77, dtype=None, device=None): + def __init__(self, embed_dim, vocab_size=49408, num_positions=77, dtype=None, device=None, textual_inversion_key="clip_l"): super().__init__() - self.token_embedding = torch.nn.Embedding(vocab_size, embed_dim, dtype=dtype, device=device) + self.token_embedding = sd_hijack.TextualInversionEmbeddings(vocab_size, embed_dim, dtype=dtype, device=device, textual_inversion_key=textual_inversion_key) self.position_embedding = torch.nn.Embedding(num_positions, embed_dim, dtype=dtype, device=device) def forward(self, input_tokens): @@ -127,7 +129,7 @@ class CLIPTextModel_(torch.nn.Module): intermediate_size = config_dict["intermediate_size"] intermediate_activation = config_dict["hidden_act"] super().__init__() - self.embeddings = CLIPEmbeddings(embed_dim, dtype=torch.float32, device=device) + self.embeddings = CLIPEmbeddings(embed_dim, dtype=torch.float32, device=device, textual_inversion_key=config_dict.get('textual_inversion_key', 'clip_l')) self.encoder = CLIPEncoder(num_layers, embed_dim, heads, intermediate_size, intermediate_activation, dtype, device) self.final_layer_norm = nn.LayerNorm(embed_dim, dtype=dtype, device=device) diff --git a/modules/models/sd3/sd3_cond.py b/modules/models/sd3/sd3_cond.py index bade90ba1..325c512d5 100644 --- a/modules/models/sd3/sd3_cond.py +++ b/modules/models/sd3/sd3_cond.py @@ -40,6 +40,7 @@ CLIPG_CONFIG = { "intermediate_size": 5120, "num_attention_heads": 20, "num_hidden_layers": 32, + "textual_inversion_key": "clip_g", } T5_URL = "https://huggingface.co/AUTOMATIC/stable-diffusion-3-medium-text-encoders/resolve/main/t5xxl_fp16.safetensors" @@ -204,7 +205,10 @@ class SD3Cond(torch.nn.Module): self.t5xxl.transformer.load_state_dict(SafetensorsMapping(file), strict=False) def encode_embedding_init_text(self, init_text, nvpt): - return torch.tensor([[0]], device=devices.device) # XXX + return self.model_lg.encode_embedding_init_text(init_text, nvpt) + + def tokenize(self, texts): + return self.model_lg.tokenize(texts) def medvram_modules(self): return [self.clip_g, self.clip_l, self.t5xxl] diff --git a/modules/sd_hijack.py b/modules/sd_hijack.py index d5b2989f4..0de830541 100644 --- a/modules/sd_hijack.py +++ b/modules/sd_hijack.py @@ -359,13 +359,28 @@ class EmbeddingsWithFixes(torch.nn.Module): vec = embedding.vec[self.textual_inversion_key] if isinstance(embedding.vec, dict) else embedding.vec emb = devices.cond_cast_unet(vec) emb_len = min(tensor.shape[0] - offset - 1, emb.shape[0]) - tensor = torch.cat([tensor[0:offset + 1], emb[0:emb_len], tensor[offset + 1 + emb_len:]]) + tensor = torch.cat([tensor[0:offset + 1], emb[0:emb_len], tensor[offset + 1 + emb_len:]]).to(dtype=inputs_embeds.dtype) vecs.append(tensor) return torch.stack(vecs) +class TextualInversionEmbeddings(torch.nn.Embedding): + def __init__(self, num_embeddings: int, embedding_dim: int, textual_inversion_key='clip_l', **kwargs): + super().__init__(num_embeddings, embedding_dim, **kwargs) + + self.embeddings = model_hijack + self.textual_inversion_key = textual_inversion_key + + @property + def wrapped(self): + return super().forward + + def forward(self, input_ids): + return EmbeddingsWithFixes.forward(self, input_ids) + + def add_circular_option_to_conv_2d(): conv2d_constructor = torch.nn.Conv2d.__init__ From 7b2917255a7d2065e7c956eb263b59b8262e97f3 Mon Sep 17 00:00:00 2001 From: Richard Tallent Date: Sun, 7 Jul 2024 11:18:17 -0500 Subject: [PATCH 04/37] Fix noisy DS_Store files for MacOS --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 96cfe22db..091f77961 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,7 @@ __pycache__ *.ckpt *.safetensors *.pth +.DS_Store /ESRGAN/* /SwinIR/* /repositories From 21e72d1a5e6cac133c379cae62a4315fec81ee9d Mon Sep 17 00:00:00 2001 From: w-e-w <40751091+w-e-w@users.noreply.github.com> Date: Mon, 8 Jul 2024 14:07:26 +0900 Subject: [PATCH 05/37] py 3.9 find_vae() --- scripts/xyz_grid.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/scripts/xyz_grid.py b/scripts/xyz_grid.py index b184721be..b702c74d8 100644 --- a/scripts/xyz_grid.py +++ b/scripts/xyz_grid.py @@ -118,11 +118,10 @@ def apply_size(p, x: str, xs) -> None: def find_vae(name: str): - match name := name.lower().strip(): - case 'auto', 'automatic': - return 'Automatic' - case 'none': - return 'None' + if name := name.strip().lower() in ('auto', 'automatic'): + return 'Automatic' + elif name == 'none': + return 'None' return next((k for k in modules.sd_vae.vae_dict if k.lower() == name), print(f'No VAE found for {name}; using Automatic') or 'Automatic') From c3d8b78b47dddb03bb4558d62c6eaffc167cc51b Mon Sep 17 00:00:00 2001 From: w-e-w <40751091+w-e-w@users.noreply.github.com> Date: Mon, 8 Jul 2024 14:17:51 +0900 Subject: [PATCH 06/37] py 3.9 compatibility --- extensions-builtin/Lora/networks.py | 1 + 1 file changed, 1 insertion(+) diff --git a/extensions-builtin/Lora/networks.py b/extensions-builtin/Lora/networks.py index 63e8c9465..9ed8fa435 100644 --- a/extensions-builtin/Lora/networks.py +++ b/extensions-builtin/Lora/networks.py @@ -1,3 +1,4 @@ +from __future__ import annotations import gradio as gr import logging import os From 1b0823db94ab491924fd1dc57287ef9dc5bff234 Mon Sep 17 00:00:00 2001 From: w-e-w <40751091+w-e-w@users.noreply.github.com> Date: Mon, 8 Jul 2024 14:51:06 +0900 Subject: [PATCH 07/37] shlex.join launch args in console log --- modules/launch_utils.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/modules/launch_utils.py b/modules/launch_utils.py index e22da4ec6..93890cd10 100644 --- a/modules/launch_utils.py +++ b/modules/launch_utils.py @@ -9,6 +9,7 @@ import importlib.util import importlib.metadata import platform import json +import shlex from functools import lru_cache from modules import cmd_args, errors @@ -461,7 +462,7 @@ def configure_for_tests(): def start(): - print(f"Launching {'API server' if '--nowebui' in sys.argv else 'Web UI'} with arguments: {' '.join(sys.argv[1:])}") + print(f"Launching {'API server' if '--nowebui' in sys.argv else 'Web UI'} with arguments: {shlex.join(sys.argv[1:])}") import webui if '--nowebui' in sys.argv: webui.api_only() From 7d7f7f4b49cc4265b48ee08fe13b7e7b03cecf98 Mon Sep 17 00:00:00 2001 From: w-e-w <40751091+w-e-w@users.noreply.github.com> Date: Mon, 8 Jul 2024 15:45:45 +0900 Subject: [PATCH 08/37] sysinfo handle psutil not working --- modules/sysinfo.py | 34 +++++++++++++++++++++++----------- 1 file changed, 23 insertions(+), 11 deletions(-) diff --git a/modules/sysinfo.py b/modules/sysinfo.py index f336251e4..614334661 100644 --- a/modules/sysinfo.py +++ b/modules/sysinfo.py @@ -5,7 +5,6 @@ import sys import platform import hashlib import pkg_resources -import psutil import re import launch @@ -69,9 +68,27 @@ def check(x): return h.hexdigest() == m.group(1) -def get_dict(): - ram = psutil.virtual_memory() +def get_cpu_info(): + cpu_info = {"model": platform.processor()} + try: + import psutil + cpu_info["count logical"] = psutil.cpu_count(logical=True) + cpu_info["count physical"] = psutil.cpu_count(logical=False) + except Exception as e: + cpu_info["error"] = str(e) + return cpu_info + +def get_ram_info(): + try: + import psutil + ram = psutil.virtual_memory() + return {x: pretty_bytes(getattr(ram, x, 0)) for x in ["total", "used", "free", "active", "inactive", "buffers", "cached", "shared"] if getattr(ram, x, 0) != 0} + except Exception as e: + return str(e) + + +def get_dict(): res = { "Platform": platform.platform(), "Python": platform.python_version(), @@ -84,14 +101,8 @@ def get_dict(): "Commandline": get_argv(), "Torch env info": get_torch_sysinfo(), "Exceptions": errors.get_exceptions(), - "CPU": { - "model": platform.processor(), - "count logical": psutil.cpu_count(logical=True), - "count physical": psutil.cpu_count(logical=False), - }, - "RAM": { - x: pretty_bytes(getattr(ram, x, 0)) for x in ["total", "used", "free", "active", "inactive", "buffers", "cached", "shared"] if getattr(ram, x, 0) != 0 - }, + "CPU": get_cpu_info(), + "RAM": get_ram_info(), "Extensions": get_extensions(enabled=True), "Inactive extensions": get_extensions(enabled=False), "Environment": get_environment(), @@ -123,6 +134,7 @@ def get_argv(): return res + re_newline = re.compile(r"\r*\n") From 11f827c58b276dff946dccf4167d8e11159eeba5 Mon Sep 17 00:00:00 2001 From: w-e-w <40751091+w-e-w@users.noreply.github.com> Date: Mon, 8 Jul 2024 16:33:02 +0900 Subject: [PATCH 09/37] use pip freeze --all to get packages --- modules/sysinfo.py | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/modules/sysinfo.py b/modules/sysinfo.py index 614334661..65d4e3c98 100644 --- a/modules/sysinfo.py +++ b/modules/sysinfo.py @@ -4,7 +4,6 @@ import sys import platform import hashlib -import pkg_resources import re import launch @@ -88,6 +87,19 @@ def get_ram_info(): return str(e) +def get_packages(): + try: + import subprocess + return subprocess.check_output([sys.executable, '-m', 'pip', 'freeze', '--all']).decode("utf8").splitlines() + except Exception as pip_error: + try: + import importlib.metadata + packages = importlib.metadata.distributions() + return sorted([f"{package.metadata['Name']}=={package.version}" for package in packages]) + except Exception as e2: + return {'error pip': pip_error, 'error importlib': str(e2)} + + def get_dict(): res = { "Platform": platform.platform(), @@ -108,7 +120,7 @@ def get_dict(): "Environment": get_environment(), "Config": get_config(), "Startup": timer.startup_record, - "Packages": sorted([f"{pkg.key}=={pkg.version}" for pkg in pkg_resources.working_set]), + "Packages": get_packages(), } return res From 27947a79d619eac5ce40b3f2db62d422313d12f6 Mon Sep 17 00:00:00 2001 From: w-e-w <40751091+w-e-w@users.noreply.github.com> Date: Mon, 8 Jul 2024 16:56:06 +0900 Subject: [PATCH 10/37] git status --- modules/launch_utils.py | 8 ++++++++ modules/sysinfo.py | 11 +++++------ 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/modules/launch_utils.py b/modules/launch_utils.py index e22da4ec6..0688f4826 100644 --- a/modules/launch_utils.py +++ b/modules/launch_utils.py @@ -85,6 +85,14 @@ def git_tag(): return "" +@lru_cache() +def git_status(): + try: + return subprocess.check_output([git, "-C", script_path, "status"], shell=False, encoding='utf8').strip() + except Exception as e: + return str(e) + + def run(command, desc=None, errdesc=None, custom_env=None, live: bool = default_command_live) -> str: if desc is not None: print(desc) diff --git a/modules/sysinfo.py b/modules/sysinfo.py index 65d4e3c98..52617573b 100644 --- a/modules/sysinfo.py +++ b/modules/sysinfo.py @@ -1,13 +1,12 @@ import json import os import sys - +import subprocess import platform import hashlib import re -import launch -from modules import paths_internal, timer, shared, extensions, errors +from modules import paths_internal, timer, shared, extensions, errors, launch_utils checksum_token = "DontStealMyGamePlz__WINNERS_DONT_USE_DRUGS__DONT_COPY_THAT_FLOPPY" environment_whitelist = { @@ -89,7 +88,6 @@ def get_ram_info(): def get_packages(): try: - import subprocess return subprocess.check_output([sys.executable, '-m', 'pip', 'freeze', '--all']).decode("utf8").splitlines() except Exception as pip_error: try: @@ -104,8 +102,9 @@ def get_dict(): res = { "Platform": platform.platform(), "Python": platform.python_version(), - "Version": launch.git_tag(), - "Commit": launch.commit_hash(), + "Version": launch_utils.git_tag(), + "Commit": launch_utils.commit_hash(), + "Git status": launch_utils.git_status(), "Script path": paths_internal.script_path, "Data path": paths_internal.data_path, "Extensions dir": paths_internal.extensions_dir, From dd4f798b97de3e32d0a6a1a18816b4cc28c6008e Mon Sep 17 00:00:00 2001 From: w-e-w <40751091+w-e-w@users.noreply.github.com> Date: Mon, 8 Jul 2024 19:20:49 +0900 Subject: [PATCH 11/37] fallback get_config() --- modules/sysinfo.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/modules/sysinfo.py b/modules/sysinfo.py index 52617573b..2c08dd226 100644 --- a/modules/sysinfo.py +++ b/modules/sysinfo.py @@ -179,5 +179,9 @@ def get_extensions(*, enabled): def get_config(): try: return shared.opts.data - except Exception as e: - return str(e) + except Exception as _: + try: + with open(shared.cmd_opts.ui_settings_file, 'r') as f: + return json.load(f) + except Exception as e: + return str(e) From 27d96fa608da81b334163835fe39c1bb32984a7c Mon Sep 17 00:00:00 2001 From: w-e-w <40751091+w-e-w@users.noreply.github.com> Date: Mon, 8 Jul 2024 20:31:50 +0900 Subject: [PATCH 12/37] fallback Extensions info --- modules/sysinfo.py | 56 ++++++++++++++++++++++++++++++++++------------ 1 file changed, 42 insertions(+), 14 deletions(-) diff --git a/modules/sysinfo.py b/modules/sysinfo.py index 2c08dd226..c2bb35cdf 100644 --- a/modules/sysinfo.py +++ b/modules/sysinfo.py @@ -99,6 +99,7 @@ def get_packages(): def get_dict(): + config = get_config() res = { "Platform": platform.platform(), "Python": platform.python_version(), @@ -114,10 +115,10 @@ def get_dict(): "Exceptions": errors.get_exceptions(), "CPU": get_cpu_info(), "RAM": get_ram_info(), - "Extensions": get_extensions(enabled=True), - "Inactive extensions": get_extensions(enabled=False), + "Extensions": get_extensions(enabled=True, fallback_disabled_extensions=config.get('disabled_extensions', [])), + "Inactive extensions": get_extensions(enabled=False, fallback_disabled_extensions=config.get('disabled_extensions', [])), "Environment": get_environment(), - "Config": get_config(), + "Config": config, "Startup": timer.startup_record, "Packages": get_packages(), } @@ -159,19 +160,46 @@ def get_torch_sysinfo(): return str(e) -def get_extensions(*, enabled): - +def run_git(path, *args): try: - def to_json(x: extensions.Extension): - return { - "name": x.name, - "path": x.path, - "version": x.version, - "branch": x.branch, - "remote": x.remote, - } + if os.path.isdir(os.path.join(path, '.git')): + return subprocess.check_output([launch_utils.git, '-C', path, *args], shell=False, encoding='utf8').strip() + return None + except Exception as e: + return str(e) - return [to_json(x) for x in extensions.extensions if not x.is_builtin and x.enabled == enabled] + +def get_info_from_repo_path(path): + return { + 'name': os.path.basename(path), + 'path': path, + 'version': run_git(path, 'rev-parse', 'HEAD'), + 'branch': run_git(path, 'branch', '--show-current'), + 'remote': run_git(path, 'remote', 'get-url', 'origin') + } + + +def get_extensions(*, enabled, fallback_disabled_extensions=None): + try: + if extensions.extensions: + def to_json(x: extensions.Extension): + return { + "name": x.name, + "path": x.path, + "version": x.version, + "branch": x.branch, + "remote": x.remote, + } + return [to_json(x) for x in extensions.extensions if not x.is_builtin and x.enabled == enabled] + else: + extensions_list = [] + for extension_dirname in sorted(os.listdir(paths_internal.extensions_dir)): + path = os.path.join(paths_internal.extensions_dir, extension_dirname) + if enabled == (extension_dirname in fallback_disabled_extensions): + continue + if os.path.isdir(path): + extensions_list.append(get_info_from_repo_path(path)) + return extensions_list except Exception as e: return str(e) From 3f6dcda3e50594a6581bee68f482901cd9ba5d5b Mon Sep 17 00:00:00 2001 From: w-e-w <40751091+w-e-w@users.noreply.github.com> Date: Mon, 8 Jul 2024 20:33:15 +0900 Subject: [PATCH 13/37] Extensions info full commit hash --- modules/sysinfo.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/sysinfo.py b/modules/sysinfo.py index c2bb35cdf..13427af63 100644 --- a/modules/sysinfo.py +++ b/modules/sysinfo.py @@ -173,7 +173,7 @@ def get_info_from_repo_path(path): return { 'name': os.path.basename(path), 'path': path, - 'version': run_git(path, 'rev-parse', 'HEAD'), + 'commit': run_git(path, 'rev-parse', 'HEAD'), 'branch': run_git(path, 'branch', '--show-current'), 'remote': run_git(path, 'remote', 'get-url', 'origin') } @@ -186,7 +186,7 @@ def get_extensions(*, enabled, fallback_disabled_extensions=None): return { "name": x.name, "path": x.path, - "version": x.version, + "commit": x.commit_hash, "branch": x.branch, "remote": x.remote, } From 4debd4d3ef62449787d6d02943f82ead356bfe48 Mon Sep 17 00:00:00 2001 From: w-e-w <40751091+w-e-w@users.noreply.github.com> Date: Tue, 9 Jul 2024 01:02:11 +0900 Subject: [PATCH 14/37] compact get_info_from_repo_path --- modules/sysinfo.py | 27 ++++++++++----------------- 1 file changed, 10 insertions(+), 17 deletions(-) diff --git a/modules/sysinfo.py b/modules/sysinfo.py index 13427af63..aa4328ed1 100644 --- a/modules/sysinfo.py +++ b/modules/sysinfo.py @@ -5,6 +5,7 @@ import subprocess import platform import hashlib import re +from pathlib import Path from modules import paths_internal, timer, shared, extensions, errors, launch_utils @@ -162,20 +163,19 @@ def get_torch_sysinfo(): def run_git(path, *args): try: - if os.path.isdir(os.path.join(path, '.git')): - return subprocess.check_output([launch_utils.git, '-C', path, *args], shell=False, encoding='utf8').strip() - return None + return subprocess.check_output([launch_utils.git, '-C', path, *args], shell=False, encoding='utf8').strip() except Exception as e: return str(e) -def get_info_from_repo_path(path): +def get_info_from_repo_path(path: Path): + is_repo = (path / '.git').is_dir() return { - 'name': os.path.basename(path), - 'path': path, - 'commit': run_git(path, 'rev-parse', 'HEAD'), - 'branch': run_git(path, 'branch', '--show-current'), - 'remote': run_git(path, 'remote', 'get-url', 'origin') + 'name': path.name, + 'path': str(path), + 'commit': run_git(path, 'rev-parse', 'HEAD') if is_repo else None, + 'branch': run_git(path, 'branch', '--show-current') if is_repo else None, + 'remote': run_git(path, 'remote', 'get-url', 'origin') if is_repo else None, } @@ -192,14 +192,7 @@ def get_extensions(*, enabled, fallback_disabled_extensions=None): } return [to_json(x) for x in extensions.extensions if not x.is_builtin and x.enabled == enabled] else: - extensions_list = [] - for extension_dirname in sorted(os.listdir(paths_internal.extensions_dir)): - path = os.path.join(paths_internal.extensions_dir, extension_dirname) - if enabled == (extension_dirname in fallback_disabled_extensions): - continue - if os.path.isdir(path): - extensions_list.append(get_info_from_repo_path(path)) - return extensions_list + return [get_info_from_repo_path(d) for d in Path(paths_internal.extensions_dir).iterdir() if d.is_dir() and enabled != (str(d.name) in fallback_disabled_extensions)] except Exception as e: return str(e) From 72cfa2829d9595b6c92d554035aec6e5d92a6602 Mon Sep 17 00:00:00 2001 From: w-e-w <40751091+w-e-w@users.noreply.github.com> Date: Tue, 9 Jul 2024 01:30:55 +0900 Subject: [PATCH 15/37] safer Imports --- modules/sysinfo.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/modules/sysinfo.py b/modules/sysinfo.py index aa4328ed1..2faa50757 100644 --- a/modules/sysinfo.py +++ b/modules/sysinfo.py @@ -7,7 +7,7 @@ import hashlib import re from pathlib import Path -from modules import paths_internal, timer, shared, extensions, errors, launch_utils +from modules import paths_internal, timer, shared_cmd_options, errors, launch_utils checksum_token = "DontStealMyGamePlz__WINNERS_DONT_USE_DRUGS__DONT_COPY_THAT_FLOPPY" environment_whitelist = { @@ -135,11 +135,11 @@ def get_argv(): res = [] for v in sys.argv: - if shared.cmd_opts.gradio_auth and shared.cmd_opts.gradio_auth == v: + if shared_cmd_options.cmd_opts.gradio_auth and shared_cmd_options.cmd_opts.gradio_auth == v: res.append("") continue - if shared.cmd_opts.api_auth and shared.cmd_opts.api_auth == v: + if shared_cmd_options.cmd_opts.api_auth and shared_cmd_options.cmd_opts.api_auth == v: res.append("") continue @@ -181,6 +181,7 @@ def get_info_from_repo_path(path: Path): def get_extensions(*, enabled, fallback_disabled_extensions=None): try: + from modules import extensions if extensions.extensions: def to_json(x: extensions.Extension): return { @@ -199,10 +200,11 @@ def get_extensions(*, enabled, fallback_disabled_extensions=None): def get_config(): try: + from modules import shared return shared.opts.data except Exception as _: try: - with open(shared.cmd_opts.ui_settings_file, 'r') as f: + with open(shared_cmd_options.cmd_opts.ui_settings_file, 'r') as f: return json.load(f) except Exception as e: return str(e) From 6a7042fe2fe2974b61e7f6271bd8dad3fedd9dd1 Mon Sep 17 00:00:00 2001 From: w-e-w <40751091+w-e-w@users.noreply.github.com> Date: Tue, 9 Jul 2024 01:51:47 +0900 Subject: [PATCH 16/37] move git_status to sysinfo --- modules/launch_utils.py | 9 --------- modules/sysinfo.py | 7 ++++++- 2 files changed, 6 insertions(+), 10 deletions(-) diff --git a/modules/launch_utils.py b/modules/launch_utils.py index 0688f4826..b2cc71277 100644 --- a/modules/launch_utils.py +++ b/modules/launch_utils.py @@ -85,14 +85,6 @@ def git_tag(): return "" -@lru_cache() -def git_status(): - try: - return subprocess.check_output([git, "-C", script_path, "status"], shell=False, encoding='utf8').strip() - except Exception as e: - return str(e) - - def run(command, desc=None, errdesc=None, custom_env=None, live: bool = default_command_live) -> str: if desc is not None: print(desc) @@ -453,7 +445,6 @@ def prepare_environment(): exit(0) - def configure_for_tests(): if "--api" not in sys.argv: sys.argv.append("--api") diff --git a/modules/sysinfo.py b/modules/sysinfo.py index 2faa50757..e9a83d74e 100644 --- a/modules/sysinfo.py +++ b/modules/sysinfo.py @@ -106,7 +106,7 @@ def get_dict(): "Python": platform.python_version(), "Version": launch_utils.git_tag(), "Commit": launch_utils.commit_hash(), - "Git status": launch_utils.git_status(), + "Git status": git_status(paths_internal.script_path), "Script path": paths_internal.script_path, "Data path": paths_internal.data_path, "Extensions dir": paths_internal.extensions_dir, @@ -168,6 +168,11 @@ def run_git(path, *args): return str(e) +def git_status(path): + if (Path(path) / '.git').is_dir(): + return run_git(paths_internal.script_path, 'status') + + def get_info_from_repo_path(path: Path): is_repo = (path / '.git').is_dir() return { From 5a5fe7494ad6e4ace6b31bcb00f1e606c5755909 Mon Sep 17 00:00:00 2001 From: w-e-w <40751091+w-e-w@users.noreply.github.com> Date: Mon, 8 Jul 2024 16:32:20 +0900 Subject: [PATCH 17/37] .gitignore sysinfo.json --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 96cfe22db..40f659d3c 100644 --- a/.gitignore +++ b/.gitignore @@ -40,3 +40,4 @@ notification.mp3 /test/test_outputs /cache trace.json +/sysinfo-????-??-??-??-??.json From 9cc7142dd7c89cc0105e27ecdcf2125b43349bf3 Mon Sep 17 00:00:00 2001 From: Andray Date: Tue, 9 Jul 2024 14:07:12 +0400 Subject: [PATCH 18/37] update installation guide linux --- README.md | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index fc582e15c..60d4d7399 100644 --- a/README.md +++ b/README.md @@ -78,7 +78,7 @@ A web interface for Stable Diffusion, implemented using Gradio library. - Clip skip - Hypernetworks - Loras (same as Hypernetworks but more pretty) -- A separate UI where you can choose, with preview, which embeddings, hypernetworks or Loras to add to your prompt +- A separate UI where you can choose, with preview, which embeddings, hypernetworks or Loras to add to your prompt - Can select to load a different VAE from settings screen - Estimated completion time in progress bar - API @@ -122,16 +122,35 @@ Alternatively, use online services (like Google Colab): # Debian-based: sudo apt install wget git python3 python3-venv libgl1 libglib2.0-0 # Red Hat-based: -sudo dnf install wget git python3 gperftools-libs libglvnd-glx +sudo dnf install wget git python3 gperftools-libs libglvnd-glx # openSUSE-based: sudo zypper install wget git python3 libtcmalloc4 libglvnd # Arch-based: sudo pacman -S wget git python3 ``` +If your system is very new, you need to install python3.11 or python3.10: +```bash +# Ubuntu 24.04 +sudo add-apt-repository ppa:deadsnakes/ppa +sudo apt update +sudo apt install python3.11 + +# Manjaro/Arch +sudo pacman -S yay +yay -S python311 # do not confuse with python3.11 package + +# Then set up env variable in launch script (only for 3.11) +export python_cmd="python3.11" +``` 2. Navigate to the directory you would like the webui to be installed and execute the following command: ```bash wget -q https://raw.githubusercontent.com/AUTOMATIC1111/stable-diffusion-webui/master/webui.sh ``` +Or just clone the repo wherever you want: +```bash +git clone https://github.com/AUTOMATIC1111/stable-diffusion-webui +``` + 3. Run `webui.sh`. 4. Check `webui-user.sh` for options. ### Installation on Apple Silicon From 26cccd8faab7ade582458611b083cd168993ade0 Mon Sep 17 00:00:00 2001 From: Andray Date: Tue, 9 Jul 2024 14:22:08 +0400 Subject: [PATCH 19/37] update --- README.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 60d4d7399..bc62945c0 100644 --- a/README.md +++ b/README.md @@ -139,8 +139,11 @@ sudo apt install python3.11 sudo pacman -S yay yay -S python311 # do not confuse with python3.11 package -# Then set up env variable in launch script (only for 3.11) +# Only for 3.11 +# Then set up env variable in launch script export python_cmd="python3.11" +# or in webui-user.sh +python_cmd="python3.11" ``` 2. Navigate to the directory you would like the webui to be installed and execute the following command: ```bash From d57ff884edd5fe3e813dbb65adb45a8966dd15b2 Mon Sep 17 00:00:00 2001 From: Andray Date: Tue, 9 Jul 2024 16:12:39 +0400 Subject: [PATCH 20/37] do not send image size on paste inpaint --- modules/infotext_utils.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/modules/infotext_utils.py b/modules/infotext_utils.py index f1e8f54ba..32dbafa65 100644 --- a/modules/infotext_utils.py +++ b/modules/infotext_utils.py @@ -146,18 +146,19 @@ def connect_paste_params_buttons(): destination_height_component = next(iter([field for field, name in fields if name == "Size-2"] if fields else []), None) if binding.source_image_component and destination_image_component: + need_send_dementions = destination_width_component and binding.tabname != 'inpaint' if isinstance(binding.source_image_component, gr.Gallery): - func = send_image_and_dimensions if destination_width_component else image_from_url_text + func = send_image_and_dimensions if need_send_dementions else image_from_url_text jsfunc = "extract_image_from_gallery" else: - func = send_image_and_dimensions if destination_width_component else lambda x: x + func = send_image_and_dimensions if need_send_dementions else lambda x: x jsfunc = None binding.paste_button.click( fn=func, _js=jsfunc, inputs=[binding.source_image_component], - outputs=[destination_image_component, destination_width_component, destination_height_component] if destination_width_component else [destination_image_component], + outputs=[destination_image_component, destination_width_component, destination_height_component] if need_send_dementions else [destination_image_component], show_progress=False, ) From b1695c1b68f0e52cfe8dc4b9ed28228bd3710336 Mon Sep 17 00:00:00 2001 From: w-e-w <40751091+w-e-w@users.noreply.github.com> Date: Thu, 11 Jul 2024 18:45:13 +0900 Subject: [PATCH 21/37] fix #16169 Py 3.9 compatibility Co-Authored-By: SLAPaper Pang --- scripts/xyz_grid.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/xyz_grid.py b/scripts/xyz_grid.py index b702c74d8..566493266 100644 --- a/scripts/xyz_grid.py +++ b/scripts/xyz_grid.py @@ -118,7 +118,7 @@ def apply_size(p, x: str, xs) -> None: def find_vae(name: str): - if name := name.strip().lower() in ('auto', 'automatic'): + if (name := name.strip().lower()) in ('auto', 'automatic'): return 'Automatic' elif name == 'none': return 'None' From 3d2dbefcde4091ce4e6d915b3eda16ca964097f2 Mon Sep 17 00:00:00 2001 From: Andray Date: Thu, 11 Jul 2024 23:54:25 +0400 Subject: [PATCH 22/37] fix OSError: cannot write mode P as JPEG --- modules/api/api.py | 2 +- modules/shared_state.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/api/api.py b/modules/api/api.py index 307476bdd..97ec7514e 100644 --- a/modules/api/api.py +++ b/modules/api/api.py @@ -113,7 +113,7 @@ def encode_pil_to_base64(image): image.save(output_bytes, format="PNG", pnginfo=(metadata if use_metadata else None), quality=opts.jpeg_quality) elif opts.samples_format.lower() in ("jpg", "jpeg", "webp"): - if image.mode == "RGBA": + if image.mode in ("RGBA", "P"): image = image.convert("RGB") parameters = image.info.get('parameters', None) exif_bytes = piexif.dump({ diff --git a/modules/shared_state.py b/modules/shared_state.py index f74eafc58..4cd53af62 100644 --- a/modules/shared_state.py +++ b/modules/shared_state.py @@ -162,7 +162,7 @@ class State: errors.record_exception() def assign_current_image(self, image): - if shared.opts.live_previews_image_format == 'jpeg' and image.mode == 'RGBA': + if shared.opts.live_previews_image_format == 'jpeg' and image.mode in ('RGBA', 'P'): image = image.convert('RGB') self.current_image = image self.id_live_preview += 1 From 589dda3cf2954beaeef65928c063e2bb5c680209 Mon Sep 17 00:00:00 2001 From: Andray Date: Fri, 12 Jul 2024 16:08:36 +0400 Subject: [PATCH 23/37] do not break progressbar on non-job actions --- modules/call_queue.py | 25 +++++++++++++++++-------- modules/ui.py | 4 ++-- modules/ui_common.py | 4 ++-- modules/ui_extensions.py | 14 +++++++------- modules/ui_settings.py | 4 ++-- 5 files changed, 30 insertions(+), 21 deletions(-) diff --git a/modules/call_queue.py b/modules/call_queue.py index d22c23b31..555c35312 100644 --- a/modules/call_queue.py +++ b/modules/call_queue.py @@ -47,6 +47,22 @@ def wrap_gradio_gpu_call(func, extra_outputs=None): def wrap_gradio_call(func, extra_outputs=None, add_stats=False): + @wraps(func) + def f(*args, **kwargs): + try: + res = func(*args, **kwargs) + finally: + shared.state.skipped = False + shared.state.interrupted = False + shared.state.stopping_generation = False + shared.state.job_count = 0 + shared.state.job = "" + return res + + return wrap_gradio_call_no_job(f, extra_outputs, add_stats) + + +def wrap_gradio_call_no_job(func, extra_outputs=None, add_stats=False): @wraps(func) def f(*args, extra_outputs_array=extra_outputs, **kwargs): run_memmon = shared.opts.memmon_poll_rate > 0 and not shared.mem_mon.disabled and add_stats @@ -66,9 +82,6 @@ def wrap_gradio_call(func, extra_outputs=None, add_stats=False): arg_str += f" (Argument list truncated at {max_debug_str_len}/{len(arg_str)} characters)" errors.report(f"{message}\n{arg_str}", exc_info=True) - shared.state.job = "" - shared.state.job_count = 0 - if extra_outputs_array is None: extra_outputs_array = [None, ''] @@ -77,11 +90,6 @@ def wrap_gradio_call(func, extra_outputs=None, add_stats=False): devices.torch_gc() - shared.state.skipped = False - shared.state.interrupted = False - shared.state.stopping_generation = False - shared.state.job_count = 0 - if not add_stats: return tuple(res) @@ -123,3 +131,4 @@ def wrap_gradio_call(func, extra_outputs=None, add_stats=False): return tuple(res) return f + diff --git a/modules/ui.py b/modules/ui.py index 5af34ecb0..8edce620f 100644 --- a/modules/ui.py +++ b/modules/ui.py @@ -10,7 +10,7 @@ import gradio as gr import gradio.utils import numpy as np from PIL import Image, PngImagePlugin # noqa: F401 -from modules.call_queue import wrap_gradio_gpu_call, wrap_queued_call, wrap_gradio_call +from modules.call_queue import wrap_gradio_gpu_call, wrap_queued_call, wrap_gradio_call, wrap_gradio_call_no_job # noqa: F401 from modules import gradio_extensons, sd_schedulers # noqa: F401 from modules import sd_hijack, sd_models, script_callbacks, ui_extensions, deepbooru, extra_networks, ui_common, ui_postprocessing, progress, ui_loadsave, shared_items, ui_settings, timer, sysinfo, ui_checkpoint_merger, scripts, sd_samplers, processing, ui_extra_networks, ui_toprow, launch_utils @@ -889,7 +889,7 @@ def create_ui(): )) image.change( - fn=wrap_gradio_call(modules.extras.run_pnginfo), + fn=wrap_gradio_call_no_job(modules.extras.run_pnginfo), inputs=[image], outputs=[html, generation_info, html2], ) diff --git a/modules/ui_common.py b/modules/ui_common.py index 48992a3c1..fb3967701 100644 --- a/modules/ui_common.py +++ b/modules/ui_common.py @@ -228,7 +228,7 @@ def create_output_panel(tabname, outdir, toprow=None): ) save.click( - fn=call_queue.wrap_gradio_call(save_files), + fn=call_queue.wrap_gradio_call_no_job(save_files), _js="(x, y, z, w) => [x, y, false, selected_gallery_index()]", inputs=[ res.generation_info, @@ -244,7 +244,7 @@ def create_output_panel(tabname, outdir, toprow=None): ) save_zip.click( - fn=call_queue.wrap_gradio_call(save_files), + fn=call_queue.wrap_gradio_call_no_job(save_files), _js="(x, y, z, w) => [x, y, true, selected_gallery_index()]", inputs=[ res.generation_info, diff --git a/modules/ui_extensions.py b/modules/ui_extensions.py index 6b6403f23..23aff7096 100644 --- a/modules/ui_extensions.py +++ b/modules/ui_extensions.py @@ -624,37 +624,37 @@ def create_ui(): ) install_extension_button.click( - fn=modules.ui.wrap_gradio_call(install_extension_from_index, extra_outputs=[gr.update(), gr.update()]), + fn=modules.ui.wrap_gradio_call_no_job(install_extension_from_index, extra_outputs=[gr.update(), gr.update()]), inputs=[extension_to_install, selected_tags, showing_type, filtering_type, sort_column, search_extensions_text], outputs=[available_extensions_table, extensions_table, install_result], ) search_extensions_text.change( - fn=modules.ui.wrap_gradio_call(search_extensions, extra_outputs=[gr.update()]), + fn=modules.ui.wrap_gradio_call_no_job(search_extensions, extra_outputs=[gr.update()]), inputs=[search_extensions_text, selected_tags, showing_type, filtering_type, sort_column], outputs=[available_extensions_table, install_result], ) selected_tags.change( - fn=modules.ui.wrap_gradio_call(refresh_available_extensions_for_tags, extra_outputs=[gr.update()]), + fn=modules.ui.wrap_gradio_call_no_job(refresh_available_extensions_for_tags, extra_outputs=[gr.update()]), inputs=[selected_tags, showing_type, filtering_type, sort_column, search_extensions_text], outputs=[available_extensions_table, install_result] ) showing_type.change( - fn=modules.ui.wrap_gradio_call(refresh_available_extensions_for_tags, extra_outputs=[gr.update()]), + fn=modules.ui.wrap_gradio_call_no_job(refresh_available_extensions_for_tags, extra_outputs=[gr.update()]), inputs=[selected_tags, showing_type, filtering_type, sort_column, search_extensions_text], outputs=[available_extensions_table, install_result] ) filtering_type.change( - fn=modules.ui.wrap_gradio_call(refresh_available_extensions_for_tags, extra_outputs=[gr.update()]), + fn=modules.ui.wrap_gradio_call_no_job(refresh_available_extensions_for_tags, extra_outputs=[gr.update()]), inputs=[selected_tags, showing_type, filtering_type, sort_column, search_extensions_text], outputs=[available_extensions_table, install_result] ) sort_column.change( - fn=modules.ui.wrap_gradio_call(refresh_available_extensions_for_tags, extra_outputs=[gr.update()]), + fn=modules.ui.wrap_gradio_call_no_job(refresh_available_extensions_for_tags, extra_outputs=[gr.update()]), inputs=[selected_tags, showing_type, filtering_type, sort_column, search_extensions_text], outputs=[available_extensions_table, install_result] ) @@ -667,7 +667,7 @@ def create_ui(): install_result = gr.HTML(elem_id="extension_install_result") install_button.click( - fn=modules.ui.wrap_gradio_call(lambda *args: [gr.update(), *install_extension_from_url(*args)], extra_outputs=[gr.update(), gr.update()]), + fn=modules.ui.wrap_gradio_call_no_job(lambda *args: [gr.update(), *install_extension_from_url(*args)], extra_outputs=[gr.update(), gr.update()]), inputs=[install_dirname, install_url, install_branch], outputs=[install_url, extensions_table, install_result], ) diff --git a/modules/ui_settings.py b/modules/ui_settings.py index 087b91f3b..e53ad50f8 100644 --- a/modules/ui_settings.py +++ b/modules/ui_settings.py @@ -1,7 +1,7 @@ import gradio as gr from modules import ui_common, shared, script_callbacks, scripts, sd_models, sysinfo, timer, shared_items -from modules.call_queue import wrap_gradio_call +from modules.call_queue import wrap_gradio_call_no_job from modules.options import options_section from modules.shared import opts from modules.ui_components import FormRow @@ -295,7 +295,7 @@ class UiSettings: def add_functionality(self, demo): self.submit.click( - fn=wrap_gradio_call(lambda *args: self.run_settings(*args), extra_outputs=[gr.update()]), + fn=wrap_gradio_call_no_job(lambda *args: self.run_settings(*args), extra_outputs=[gr.update()]), inputs=self.components, outputs=[self.text_settings, self.result], ) From 7e5cdaab4b386621a186999e7348f6d0af7317a7 Mon Sep 17 00:00:00 2001 From: AUTOMATIC1111 <16777216c@gmail.com> Date: Mon, 15 Jul 2024 08:31:55 +0300 Subject: [PATCH 24/37] SD3 lora support --- extensions-builtin/Lora/network.py | 6 +- extensions-builtin/Lora/network_lora.py | 10 ++- extensions-builtin/Lora/networks.py | 96 +++++++++++++++++++------ modules/models/sd3/mmdit.py | 5 +- modules/models/sd3/sd3_impls.py | 1 + modules/models/sd3/sd3_model.py | 12 ++++ 6 files changed, 106 insertions(+), 24 deletions(-) diff --git a/extensions-builtin/Lora/network.py b/extensions-builtin/Lora/network.py index 3c39c49d7..98ff367fd 100644 --- a/extensions-builtin/Lora/network.py +++ b/extensions-builtin/Lora/network.py @@ -7,6 +7,7 @@ import torch.nn as nn import torch.nn.functional as F from modules import sd_models, cache, errors, hashes, shared +import modules.models.sd3.mmdit NetworkWeights = namedtuple('NetworkWeights', ['network_key', 'sd_key', 'w', 'sd_module']) @@ -114,7 +115,10 @@ class NetworkModule: self.sd_key = weights.sd_key self.sd_module = weights.sd_module - if hasattr(self.sd_module, 'weight'): + if isinstance(self.sd_module, modules.models.sd3.mmdit.QkvLinear): + s = self.sd_module.weight.shape + self.shape = (s[0] // 3, s[1]) + elif hasattr(self.sd_module, 'weight'): self.shape = self.sd_module.weight.shape elif isinstance(self.sd_module, nn.MultiheadAttention): # For now, only self-attn use Pytorch's MHA diff --git a/extensions-builtin/Lora/network_lora.py b/extensions-builtin/Lora/network_lora.py index 4cc402951..a7a088949 100644 --- a/extensions-builtin/Lora/network_lora.py +++ b/extensions-builtin/Lora/network_lora.py @@ -1,6 +1,7 @@ import torch import lyco_helpers +import modules.models.sd3.mmdit import network from modules import devices @@ -10,6 +11,13 @@ class ModuleTypeLora(network.ModuleType): if all(x in weights.w for x in ["lora_up.weight", "lora_down.weight"]): return NetworkModuleLora(net, weights) + if all(x in weights.w for x in ["lora_A.weight", "lora_B.weight"]): + w = weights.w.copy() + weights.w.clear() + weights.w.update({"lora_up.weight": w["lora_B.weight"], "lora_down.weight": w["lora_A.weight"]}) + + return NetworkModuleLora(net, weights) + return None @@ -29,7 +37,7 @@ class NetworkModuleLora(network.NetworkModule): if weight is None and none_ok: return None - is_linear = type(self.sd_module) in [torch.nn.Linear, torch.nn.modules.linear.NonDynamicallyQuantizableLinear, torch.nn.MultiheadAttention] + is_linear = type(self.sd_module) in [torch.nn.Linear, torch.nn.modules.linear.NonDynamicallyQuantizableLinear, torch.nn.MultiheadAttention, modules.models.sd3.mmdit.QkvLinear] is_conv = type(self.sd_module) in [torch.nn.Conv2d] if is_linear: diff --git a/extensions-builtin/Lora/networks.py b/extensions-builtin/Lora/networks.py index 9ed8fa435..4ad98714b 100644 --- a/extensions-builtin/Lora/networks.py +++ b/extensions-builtin/Lora/networks.py @@ -20,6 +20,7 @@ from typing import Union from modules import shared, devices, sd_models, errors, scripts, sd_hijack import modules.textual_inversion.textual_inversion as textual_inversion +import modules.models.sd3.mmdit from lora_logger import logger @@ -166,12 +167,26 @@ def load_network(name, network_on_disk): keys_failed_to_match = {} is_sd2 = 'model_transformer_resblocks' in shared.sd_model.network_layer_mapping + if hasattr(shared.sd_model, 'diffusers_weight_map'): + diffusers_weight_map = shared.sd_model.diffusers_weight_map + elif hasattr(shared.sd_model, 'diffusers_weight_mapping'): + diffusers_weight_map = {} + for k, v in shared.sd_model.diffusers_weight_mapping(): + diffusers_weight_map[k] = v + shared.sd_model.diffusers_weight_map = diffusers_weight_map + else: + diffusers_weight_map = None matched_networks = {} bundle_embeddings = {} for key_network, weight in sd.items(): - key_network_without_network_parts, _, network_part = key_network.partition(".") + + if diffusers_weight_map: + key_network_without_network_parts, network_name, network_weight = key_network.rsplit(".", 2) + network_part = network_name + '.' + network_weight + else: + key_network_without_network_parts, _, network_part = key_network.partition(".") if key_network_without_network_parts == "bundle_emb": emb_name, vec_name = network_part.split(".", 1) @@ -183,7 +198,11 @@ def load_network(name, network_on_disk): emb_dict[vec_name] = weight bundle_embeddings[emb_name] = emb_dict - key = convert_diffusers_name_to_compvis(key_network_without_network_parts, is_sd2) + if diffusers_weight_map: + key = diffusers_weight_map.get(key_network_without_network_parts, key_network_without_network_parts) + else: + key = convert_diffusers_name_to_compvis(key_network_without_network_parts, is_sd2) + sd_module = shared.sd_model.network_layer_mapping.get(key, None) if sd_module is None: @@ -347,6 +366,28 @@ def load_networks(names, te_multipliers=None, unet_multipliers=None, dyn_dims=No purge_networks_from_memory() +def allowed_layer_without_weight(layer): + if isinstance(layer, torch.nn.LayerNorm) and not layer.elementwise_affine: + return True + + return False + + +def store_weights_backup(weight): + if weight is None: + return None + + return weight.to(devices.cpu, copy=True) + + +def restore_weights_backup(obj, field, weight): + if weight is None: + setattr(obj, field, None) + return + + getattr(obj, field).copy_(weight) + + def network_restore_weights_from_backup(self: Union[torch.nn.Conv2d, torch.nn.Linear, torch.nn.GroupNorm, torch.nn.LayerNorm, torch.nn.MultiheadAttention]): weights_backup = getattr(self, "network_weights_backup", None) bias_backup = getattr(self, "network_bias_backup", None) @@ -356,21 +397,15 @@ def network_restore_weights_from_backup(self: Union[torch.nn.Conv2d, torch.nn.Li if weights_backup is not None: if isinstance(self, torch.nn.MultiheadAttention): - self.in_proj_weight.copy_(weights_backup[0]) - self.out_proj.weight.copy_(weights_backup[1]) + restore_weights_backup(self, 'in_proj_weight', weights_backup[0]) + restore_weights_backup(self.out_proj, 'weight', weights_backup[0]) else: - self.weight.copy_(weights_backup) + restore_weights_backup(self, 'weight', weights_backup) - if bias_backup is not None: - if isinstance(self, torch.nn.MultiheadAttention): - self.out_proj.bias.copy_(bias_backup) - else: - self.bias.copy_(bias_backup) + if isinstance(self, torch.nn.MultiheadAttention): + restore_weights_backup(self.out_proj, 'bias', bias_backup) else: - if isinstance(self, torch.nn.MultiheadAttention): - self.out_proj.bias = None - else: - self.bias = None + restore_weights_backup(self, 'bias', bias_backup) def network_apply_weights(self: Union[torch.nn.Conv2d, torch.nn.Linear, torch.nn.GroupNorm, torch.nn.LayerNorm, torch.nn.MultiheadAttention]): @@ -389,22 +424,22 @@ def network_apply_weights(self: Union[torch.nn.Conv2d, torch.nn.Linear, torch.nn weights_backup = getattr(self, "network_weights_backup", None) if weights_backup is None and wanted_names != (): - if current_names != (): - raise RuntimeError("no backup weights found and current weights are not unchanged") + if current_names != () and not allowed_layer_without_weight(self): + raise RuntimeError(f"{network_layer_name} - no backup weights found and current weights are not unchanged") if isinstance(self, torch.nn.MultiheadAttention): - weights_backup = (self.in_proj_weight.to(devices.cpu, copy=True), self.out_proj.weight.to(devices.cpu, copy=True)) + weights_backup = (store_weights_backup(self.in_proj_weight), store_weights_backup(self.out_proj.weight)) else: - weights_backup = self.weight.to(devices.cpu, copy=True) + weights_backup = store_weights_backup(self.weight) self.network_weights_backup = weights_backup bias_backup = getattr(self, "network_bias_backup", None) if bias_backup is None and wanted_names != (): if isinstance(self, torch.nn.MultiheadAttention) and self.out_proj.bias is not None: - bias_backup = self.out_proj.bias.to(devices.cpu, copy=True) + bias_backup = store_weights_backup(self.out_proj) elif getattr(self, 'bias', None) is not None: - bias_backup = self.bias.to(devices.cpu, copy=True) + bias_backup = store_weights_backup(self.bias) else: bias_backup = None @@ -412,6 +447,7 @@ def network_apply_weights(self: Union[torch.nn.Conv2d, torch.nn.Linear, torch.nn # Only report if bias is not None and current bias are not unchanged. if bias_backup is not None and current_names != (): raise RuntimeError("no backup bias found and current bias are not unchanged") + self.network_bias_backup = bias_backup if current_names != wanted_names: @@ -419,7 +455,7 @@ def network_apply_weights(self: Union[torch.nn.Conv2d, torch.nn.Linear, torch.nn for net in loaded_networks: module = net.modules.get(network_layer_name, None) - if module is not None and hasattr(self, 'weight'): + if module is not None and hasattr(self, 'weight') and not isinstance(module, modules.models.sd3.mmdit.QkvLinear): try: with torch.no_grad(): if getattr(self, 'fp16_weight', None) is None: @@ -479,6 +515,24 @@ def network_apply_weights(self: Union[torch.nn.Conv2d, torch.nn.Linear, torch.nn continue + if isinstance(self, modules.models.sd3.mmdit.QkvLinear) and module_q and module_k and module_v: + try: + with torch.no_grad(): + # Send "real" orig_weight into MHA's lora module + qw, kw, vw = self.weight.chunk(3, 0) + updown_q, _ = module_q.calc_updown(qw) + updown_k, _ = module_k.calc_updown(kw) + updown_v, _ = module_v.calc_updown(vw) + del qw, kw, vw + updown_qkv = torch.vstack([updown_q, updown_k, updown_v]) + self.weight += updown_qkv + + except RuntimeError as e: + logging.debug(f"Network {net.name} layer {network_layer_name}: {e}") + extra_network_lora.errors[net.name] = extra_network_lora.errors.get(net.name, 0) + 1 + + continue + if module is None: continue diff --git a/modules/models/sd3/mmdit.py b/modules/models/sd3/mmdit.py index 4d2b85551..8ddf49a4e 100644 --- a/modules/models/sd3/mmdit.py +++ b/modules/models/sd3/mmdit.py @@ -175,6 +175,9 @@ class VectorEmbedder(nn.Module): ################################################################################# +class QkvLinear(torch.nn.Linear): + pass + def split_qkv(qkv, head_dim): qkv = qkv.reshape(qkv.shape[0], qkv.shape[1], 3, -1, head_dim).movedim(2, 0) return qkv[0], qkv[1], qkv[2] @@ -202,7 +205,7 @@ class SelfAttention(nn.Module): self.num_heads = num_heads self.head_dim = dim // num_heads - self.qkv = nn.Linear(dim, dim * 3, bias=qkv_bias, dtype=dtype, device=device) + self.qkv = QkvLinear(dim, dim * 3, bias=qkv_bias, dtype=dtype, device=device) if not pre_only: self.proj = nn.Linear(dim, dim, dtype=dtype, device=device) assert attn_mode in self.ATTENTION_MODES diff --git a/modules/models/sd3/sd3_impls.py b/modules/models/sd3/sd3_impls.py index e2f6cad5b..59f11b2cb 100644 --- a/modules/models/sd3/sd3_impls.py +++ b/modules/models/sd3/sd3_impls.py @@ -67,6 +67,7 @@ class BaseModel(torch.nn.Module): } self.diffusion_model = MMDiT(input_size=None, pos_embed_scaling_factor=None, pos_embed_offset=None, pos_embed_max_size=pos_embed_max_size, patch_size=patch_size, in_channels=16, depth=depth, num_patches=num_patches, adm_in_channels=adm_in_channels, context_embedder_config=context_embedder_config, device=device, dtype=dtype) self.model_sampling = ModelSamplingDiscreteFlow(shift=shift) + self.depth = depth def apply_model(self, x, sigma, c_crossattn=None, y=None): dtype = self.get_dtype() diff --git a/modules/models/sd3/sd3_model.py b/modules/models/sd3/sd3_model.py index dbec8168f..37cf85eb3 100644 --- a/modules/models/sd3/sd3_model.py +++ b/modules/models/sd3/sd3_model.py @@ -82,3 +82,15 @@ class SD3Inferencer(torch.nn.Module): def fix_dimensions(self, width, height): return width // 16 * 16, height // 16 * 16 + + def diffusers_weight_mapping(self): + for i in range(self.model.depth): + yield f"transformer.transformer_blocks.{i}.attn.to_q", f"diffusion_model_joint_blocks_{i}_x_block_attn_qkv_q_proj" + yield f"transformer.transformer_blocks.{i}.attn.to_k", f"diffusion_model_joint_blocks_{i}_x_block_attn_qkv_k_proj" + yield f"transformer.transformer_blocks.{i}.attn.to_v", f"diffusion_model_joint_blocks_{i}_x_block_attn_qkv_v_proj" + yield f"transformer.transformer_blocks.{i}.attn.to_out.0", f"diffusion_model_joint_blocks_{i}_x_block_attn_proj" + + yield f"transformer.transformer_blocks.{i}.attn.add_q_proj", f"diffusion_model_joint_blocks_{i}_context_block.attn_qkv_q_proj" + yield f"transformer.transformer_blocks.{i}.attn.add_k_proj", f"diffusion_model_joint_blocks_{i}_context_block.attn_qkv_k_proj" + yield f"transformer.transformer_blocks.{i}.attn.add_v_proj", f"diffusion_model_joint_blocks_{i}_context_block.attn_qkv_v_proj" + yield f"transformer.transformer_blocks.{i}.attn.add_out_proj.0", f"diffusion_model_joint_blocks_{i}_context_block_attn_proj" From f5866199c4787f905b229581a8adf765bc42da40 Mon Sep 17 00:00:00 2001 From: Haoming Date: Tue, 16 Jul 2024 11:07:22 +0800 Subject: [PATCH 25/37] add ids --- modules/ui.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/modules/ui.py b/modules/ui.py index 5af34ecb0..47d01b4a0 100644 --- a/modules/ui.py +++ b/modules/ui.py @@ -622,8 +622,8 @@ def create_ui(): with gr.Column(elem_id="img2img_column_size", scale=4): selected_scale_tab = gr.Number(value=0, visible=False) - with gr.Tabs(): - with gr.Tab(label="Resize to", elem_id="img2img_tab_resize_to") as tab_scale_to: + with gr.Tabs(elem_id="img2img_tabs_resize"): + with gr.Tab(label="Resize to", id="to", elem_id="img2img_tab_resize_to") as tab_scale_to: with FormRow(): with gr.Column(elem_id="img2img_column_size", scale=4): width = gr.Slider(minimum=64, maximum=2048, step=8, label="Width", value=512, elem_id="img2img_width") @@ -632,7 +632,7 @@ def create_ui(): res_switch_btn = ToolButton(value=switch_values_symbol, elem_id="img2img_res_switch_btn", tooltip="Switch width/height") detect_image_size_btn = ToolButton(value=detect_image_size_symbol, elem_id="img2img_detect_image_size_btn", tooltip="Auto detect size from img2img") - with gr.Tab(label="Resize by", elem_id="img2img_tab_resize_by") as tab_scale_by: + with gr.Tab(label="Resize by", id="by", elem_id="img2img_tab_resize_by") as tab_scale_by: scale_by = gr.Slider(minimum=0.05, maximum=4.0, step=0.05, label="Scale", value=1.0, elem_id="img2img_scale") with FormRow(): From 2b50233f3ffa522d5183bacaee3411b9382cbe2c Mon Sep 17 00:00:00 2001 From: AUTOMATIC1111 <16777216c@gmail.com> Date: Tue, 16 Jul 2024 20:50:25 +0300 Subject: [PATCH 26/37] fix bugs in lora support --- extensions-builtin/Lora/networks.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/extensions-builtin/Lora/networks.py b/extensions-builtin/Lora/networks.py index 4ad98714b..67f9abe2a 100644 --- a/extensions-builtin/Lora/networks.py +++ b/extensions-builtin/Lora/networks.py @@ -398,7 +398,7 @@ def network_restore_weights_from_backup(self: Union[torch.nn.Conv2d, torch.nn.Li if weights_backup is not None: if isinstance(self, torch.nn.MultiheadAttention): restore_weights_backup(self, 'in_proj_weight', weights_backup[0]) - restore_weights_backup(self.out_proj, 'weight', weights_backup[0]) + restore_weights_backup(self.out_proj, 'weight', weights_backup[1]) else: restore_weights_backup(self, 'weight', weights_backup) @@ -437,7 +437,7 @@ def network_apply_weights(self: Union[torch.nn.Conv2d, torch.nn.Linear, torch.nn bias_backup = getattr(self, "network_bias_backup", None) if bias_backup is None and wanted_names != (): if isinstance(self, torch.nn.MultiheadAttention) and self.out_proj.bias is not None: - bias_backup = store_weights_backup(self.out_proj) + bias_backup = store_weights_backup(self.out_proj.bias) elif getattr(self, 'bias', None) is not None: bias_backup = store_weights_backup(self.bias) else: From 2abc628899aaddb7e28840d7f7a40d516cb5073d Mon Sep 17 00:00:00 2001 From: w-e-w <40751091+w-e-w@users.noreply.github.com> Date: Thu, 18 Jul 2024 23:49:49 +0900 Subject: [PATCH 27/37] bat activate venv --- webui.bat | 1 + 1 file changed, 1 insertion(+) diff --git a/webui.bat b/webui.bat index a8d479b05..7b162ce27 100644 --- a/webui.bat +++ b/webui.bat @@ -48,6 +48,7 @@ echo Warning: Failed to upgrade PIP version :activate_venv set PYTHON="%VENV_DIR%\Scripts\Python.exe" +call "%VENV_DIR%\Scripts\activate.bat" echo venv %PYTHON% :skip_venv From a5f66b5003527508c2e2c49c79360ab20071fec2 Mon Sep 17 00:00:00 2001 From: v0xie <28695009+v0xie@users.noreply.github.com> Date: Thu, 18 Jul 2024 15:53:54 -0700 Subject: [PATCH 28/37] feature: beta scheduler --- modules/sd_schedulers.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/modules/sd_schedulers.py b/modules/sd_schedulers.py index 84b0abb6a..19d294c1d 100644 --- a/modules/sd_schedulers.py +++ b/modules/sd_schedulers.py @@ -2,6 +2,7 @@ import dataclasses import torch import k_diffusion import numpy as np +from scipy import stats from modules import shared @@ -115,6 +116,17 @@ def ddim_scheduler(n, sigma_min, sigma_max, inner_model, device): return torch.FloatTensor(sigs).to(device) +def beta_scheduler(n, sigma_min, sigma_max, inner_model, device): + # From "Beta Sampling is All You Need" [arXiv:2407.12173] (Lee et. al, 2024) """ + alpha = 0.6 + beta = 0.6 + timesteps = 1 - np.linspace(0, 1, n) + timesteps = [stats.beta.ppf(x, alpha, beta) for x in timesteps] + sigmas = [sigma_min + ((x)*(sigma_max-sigma_min)) for x in timesteps] + [0.0] + sigmas = torch.FloatTensor(sigmas).to(device) + return sigmas + + schedulers = [ Scheduler('automatic', 'Automatic', None), Scheduler('uniform', 'Uniform', uniform, need_inner_model=True), @@ -127,6 +139,7 @@ schedulers = [ Scheduler('simple', 'Simple', simple_scheduler, need_inner_model=True), Scheduler('normal', 'Normal', normal_scheduler, need_inner_model=True), Scheduler('ddim', 'DDIM', ddim_scheduler, need_inner_model=True), + Scheduler('beta', 'Beta', beta_scheduler, need_inner_model=True), ] schedulers_map = {**{x.name: x for x in schedulers}, **{x.label: x for x in schedulers}} From 964fc13a99d47263d023f4e3116ac2c220acec88 Mon Sep 17 00:00:00 2001 From: w-e-w <40751091+w-e-w@users.noreply.github.com> Date: Sat, 20 Jul 2024 04:00:54 +0900 Subject: [PATCH 29/37] fix upscale logic --- modules/upscaler.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/upscaler.py b/modules/upscaler.py index 28c60cdcd..507881fed 100644 --- a/modules/upscaler.py +++ b/modules/upscaler.py @@ -56,8 +56,8 @@ class Upscaler: dest_w = int((img.width * scale) // 8 * 8) dest_h = int((img.height * scale) // 8 * 8) - for _ in range(3): - if img.width >= dest_w and img.height >= dest_h and scale != 1: + for i in range(3): + if img.width >= dest_w and img.height >= dest_h and (i > 0 or scale != 1): break if shared.state.interrupted: From 7e1bd3e3c30e1d7e95f719a925f11d9225251f7c Mon Sep 17 00:00:00 2001 From: v0xie <28695009+v0xie@users.noreply.github.com> Date: Fri, 19 Jul 2024 13:44:22 -0700 Subject: [PATCH 30/37] refactor: syntax and add 0.0 on new line --- modules/sd_schedulers.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/modules/sd_schedulers.py b/modules/sd_schedulers.py index 19d294c1d..6f2dc6308 100644 --- a/modules/sd_schedulers.py +++ b/modules/sd_schedulers.py @@ -122,9 +122,9 @@ def beta_scheduler(n, sigma_min, sigma_max, inner_model, device): beta = 0.6 timesteps = 1 - np.linspace(0, 1, n) timesteps = [stats.beta.ppf(x, alpha, beta) for x in timesteps] - sigmas = [sigma_min + ((x)*(sigma_max-sigma_min)) for x in timesteps] + [0.0] - sigmas = torch.FloatTensor(sigmas).to(device) - return sigmas + sigmas = [sigma_min + (x * (sigma_max-sigma_min)) for x in timesteps] + sigmas += [0.0] + return torch.FloatTensor(sigmas).to(device) schedulers = [ From 3a5a66775c4c9dd03ffbf3c1696ae0db64a71793 Mon Sep 17 00:00:00 2001 From: v0xie <28695009+v0xie@users.noreply.github.com> Date: Fri, 19 Jul 2024 14:08:08 -0700 Subject: [PATCH 31/37] add new options 'beta_dist_alpha', 'beta_dist_beta' --- modules/shared_options.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/modules/shared_options.py b/modules/shared_options.py index 096366e0a..203f7a32b 100644 --- a/modules/shared_options.py +++ b/modules/shared_options.py @@ -404,6 +404,8 @@ options_templates.update(options_section(('sampler-params', "Sampler parameters" 'uni_pc_lower_order_final': OptionInfo(True, "UniPC lower order final", infotext='UniPC lower order final'), 'sd_noise_schedule': OptionInfo("Default", "Noise schedule for sampling", gr.Radio, {"choices": ["Default", "Zero Terminal SNR"]}, infotext="Noise Schedule").info("for use with zero terminal SNR trained models"), 'skip_early_cond': OptionInfo(0.0, "Ignore negative prompt during early sampling", gr.Slider, {"minimum": 0.0, "maximum": 1.0, "step": 0.01}, infotext="Skip Early CFG").info("disables CFG on a proportion of steps at the beginning of generation; 0=skip none; 1=skip all; can both improve sample diversity/quality and speed up sampling"), + 'beta_dist_alpha': OptionInfo(0.6, "Beta scheduler - alpha", gr.Slider, {"minimum": 0.0, "maximum": 1.0, "step": 0.01}, infotext='Beta scheduler alpha').info('Default = 0.6; the alpha parameter of the beta distribution used in Beta sampling'), + 'beta_dist_beta': OptionInfo(0.6, "Beta scheduler - beta", gr.Slider, {"minimum": 0.0, "maximum": 1.0, "step": 0.01}, infotext='Beta scheduler beta').info('Default = 0.6; the beta parameter of the beta distribution used in Beta sampling'), })) options_templates.update(options_section(('postprocessing', "Postprocessing", "postprocessing"), { From f6f055a93df4fb1a59fa8f28e3b8f092fd7ba511 Mon Sep 17 00:00:00 2001 From: v0xie <28695009+v0xie@users.noreply.github.com> Date: Fri, 19 Jul 2024 14:08:44 -0700 Subject: [PATCH 32/37] use configured alpha/beta values in Beta scheduling --- modules/sd_schedulers.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/sd_schedulers.py b/modules/sd_schedulers.py index 6f2dc6308..f4d16e309 100644 --- a/modules/sd_schedulers.py +++ b/modules/sd_schedulers.py @@ -118,8 +118,8 @@ def ddim_scheduler(n, sigma_min, sigma_max, inner_model, device): def beta_scheduler(n, sigma_min, sigma_max, inner_model, device): # From "Beta Sampling is All You Need" [arXiv:2407.12173] (Lee et. al, 2024) """ - alpha = 0.6 - beta = 0.6 + alpha = shared.opts.beta_dist_alpha + beta = shared.opts.beta_dist_beta timesteps = 1 - np.linspace(0, 1, n) timesteps = [stats.beta.ppf(x, alpha, beta) for x in timesteps] sigmas = [sigma_min + (x * (sigma_max-sigma_min)) for x in timesteps] From e285af6e4817a34c86212d1b640aad7225f0c022 Mon Sep 17 00:00:00 2001 From: v0xie <28695009+v0xie@users.noreply.github.com> Date: Fri, 19 Jul 2024 14:15:10 -0700 Subject: [PATCH 33/37] add beta schedule opts to xyz options --- scripts/xyz_grid.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/scripts/xyz_grid.py b/scripts/xyz_grid.py index 566493266..6a42a04d9 100644 --- a/scripts/xyz_grid.py +++ b/scripts/xyz_grid.py @@ -259,6 +259,8 @@ axis_options = [ AxisOption("Schedule min sigma", float, apply_override("sigma_min")), AxisOption("Schedule max sigma", float, apply_override("sigma_max")), AxisOption("Schedule rho", float, apply_override("rho")), + AxisOption("Beta schedule alpha", float, apply_override("beta_dist_alpha")), + AxisOption("Beta schedule beta", float, apply_override("beta_dist_beta")), AxisOption("Eta", float, apply_field("eta")), AxisOption("Clip skip", int, apply_override('CLIP_stop_at_last_layers')), AxisOption("Denoising", float, apply_field("denoising_strength")), From 94275b115c2a6c3c273baa92caf0b5f4ff3cc43f Mon Sep 17 00:00:00 2001 From: v0xie <28695009+v0xie@users.noreply.github.com> Date: Fri, 19 Jul 2024 14:15:55 -0700 Subject: [PATCH 34/37] enforce beta_dist_alpha / beta_dist_beta > 0 to avoid nan --- modules/shared_options.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/shared_options.py b/modules/shared_options.py index 203f7a32b..4ff7f51c0 100644 --- a/modules/shared_options.py +++ b/modules/shared_options.py @@ -404,8 +404,8 @@ options_templates.update(options_section(('sampler-params', "Sampler parameters" 'uni_pc_lower_order_final': OptionInfo(True, "UniPC lower order final", infotext='UniPC lower order final'), 'sd_noise_schedule': OptionInfo("Default", "Noise schedule for sampling", gr.Radio, {"choices": ["Default", "Zero Terminal SNR"]}, infotext="Noise Schedule").info("for use with zero terminal SNR trained models"), 'skip_early_cond': OptionInfo(0.0, "Ignore negative prompt during early sampling", gr.Slider, {"minimum": 0.0, "maximum": 1.0, "step": 0.01}, infotext="Skip Early CFG").info("disables CFG on a proportion of steps at the beginning of generation; 0=skip none; 1=skip all; can both improve sample diversity/quality and speed up sampling"), - 'beta_dist_alpha': OptionInfo(0.6, "Beta scheduler - alpha", gr.Slider, {"minimum": 0.0, "maximum": 1.0, "step": 0.01}, infotext='Beta scheduler alpha').info('Default = 0.6; the alpha parameter of the beta distribution used in Beta sampling'), - 'beta_dist_beta': OptionInfo(0.6, "Beta scheduler - beta", gr.Slider, {"minimum": 0.0, "maximum": 1.0, "step": 0.01}, infotext='Beta scheduler beta').info('Default = 0.6; the beta parameter of the beta distribution used in Beta sampling'), + 'beta_dist_alpha': OptionInfo(0.6, "Beta scheduler - alpha", gr.Slider, {"minimum": 0.01, "maximum": 1.0, "step": 0.01}, infotext='Beta scheduler alpha').info('Default = 0.6; the alpha parameter of the beta distribution used in Beta sampling'), + 'beta_dist_beta': OptionInfo(0.6, "Beta scheduler - beta", gr.Slider, {"minimum": 0.01, "maximum": 1.0, "step": 0.01}, infotext='Beta scheduler beta').info('Default = 0.6; the beta parameter of the beta distribution used in Beta sampling'), })) options_templates.update(options_section(('postprocessing', "Postprocessing", "postprocessing"), { From 9de7084884f4266a19e4ed3f503687927c845c4d Mon Sep 17 00:00:00 2001 From: v0xie <28695009+v0xie@users.noreply.github.com> Date: Fri, 19 Jul 2024 14:54:24 -0700 Subject: [PATCH 35/37] always add alpha/beta to extra_generation_params when schedule is Beta --- modules/sd_samplers_kdiffusion.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/modules/sd_samplers_kdiffusion.py b/modules/sd_samplers_kdiffusion.py index 95a354dac..4e5310bc6 100644 --- a/modules/sd_samplers_kdiffusion.py +++ b/modules/sd_samplers_kdiffusion.py @@ -119,6 +119,10 @@ class KDiffusionSampler(sd_samplers_common.Sampler): if scheduler.need_inner_model: sigmas_kwargs['inner_model'] = self.model_wrap + + if scheduler.label == 'Beta': + p.extra_generation_params["Beta schedule alpha"] = opts.beta_dist_alpha + p.extra_generation_params["Beta schedule beta"] = opts.beta_dist_beta sigmas = scheduler.function(n=steps, **sigmas_kwargs, device=devices.cpu) From 874954060297d847bf30cc5d220effe80ac18968 Mon Sep 17 00:00:00 2001 From: v0xie <28695009+v0xie@users.noreply.github.com> Date: Fri, 19 Jul 2024 15:33:07 -0700 Subject: [PATCH 36/37] fix lint --- modules/sd_samplers_kdiffusion.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/sd_samplers_kdiffusion.py b/modules/sd_samplers_kdiffusion.py index 4e5310bc6..0c94d100d 100644 --- a/modules/sd_samplers_kdiffusion.py +++ b/modules/sd_samplers_kdiffusion.py @@ -119,7 +119,7 @@ class KDiffusionSampler(sd_samplers_common.Sampler): if scheduler.need_inner_model: sigmas_kwargs['inner_model'] = self.model_wrap - + if scheduler.label == 'Beta': p.extra_generation_params["Beta schedule alpha"] = opts.beta_dist_alpha p.extra_generation_params["Beta schedule beta"] = opts.beta_dist_beta From 24a23e1225244a5ee92acad8b96077e0af858761 Mon Sep 17 00:00:00 2001 From: w-e-w <40751091+w-e-w@users.noreply.github.com> Date: Sat, 20 Jul 2024 15:59:28 +0900 Subject: [PATCH 37/37] option to disable save button log.csv --- modules/shared_options.py | 1 + modules/ui_common.py | 17 ++++++++++------- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/modules/shared_options.py b/modules/shared_options.py index 096366e0a..a482c7c6d 100644 --- a/modules/shared_options.py +++ b/modules/shared_options.py @@ -64,6 +64,7 @@ options_templates.update(options_section(('saving-images', "Saving images/grids" "use_original_name_batch": OptionInfo(True, "Use original name for output filename during batch process in extras tab"), "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"), + "save_write_log_csv": OptionInfo(True, "Write log.csv when saving images using 'Save' button"), "save_init_img": OptionInfo(False, "Save init images when using img2img"), "temp_dir": OptionInfo("", "Directory for temporary images; leave empty for default"), diff --git a/modules/ui_common.py b/modules/ui_common.py index 48992a3c1..af5857e61 100644 --- a/modules/ui_common.py +++ b/modules/ui_common.py @@ -3,6 +3,7 @@ import dataclasses import json import html import os +from contextlib import nullcontext import gradio as gr @@ -103,14 +104,15 @@ def save_files(js_data, images, do_make_zip, index): # NOTE: ensure csv integrity when fields are added by # updating headers and padding with delimiters where needed - if os.path.exists(logfile_path): + if shared.opts.save_write_log_csv and os.path.exists(logfile_path): update_logfile(logfile_path, fields) - with open(logfile_path, "a", encoding="utf8", newline='') as file: - at_start = file.tell() == 0 - writer = csv.writer(file) - if at_start: - writer.writerow(fields) + with (open(logfile_path, "a", encoding="utf8", newline='') if shared.opts.save_write_log_csv else nullcontext()) as file: + if file: + at_start = file.tell() == 0 + writer = csv.writer(file) + if at_start: + writer.writerow(fields) for image_index, filedata in enumerate(images, start_index): image = image_from_url_text(filedata) @@ -130,7 +132,8 @@ def save_files(js_data, images, do_make_zip, index): filenames.append(os.path.basename(txt_fullfn)) fullfns.append(txt_fullfn) - writer.writerow([parsed_infotexts[0]['Prompt'], parsed_infotexts[0]['Seed'], data["width"], data["height"], data["sampler_name"], data["cfg_scale"], data["steps"], filenames[0], parsed_infotexts[0]['Negative prompt'], data["sd_model_name"], data["sd_model_hash"]]) + if file: + writer.writerow([parsed_infotexts[0]['Prompt'], parsed_infotexts[0]['Seed'], data["width"], data["height"], data["sampler_name"], data["cfg_scale"], data["steps"], filenames[0], parsed_infotexts[0]['Negative prompt'], data["sd_model_name"], data["sd_model_hash"]]) # Make Zip if do_make_zip: