diff --git a/CHANGELOG.md b/CHANGELOG.md index f6c46d236..68b1dc707 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,15 @@ - new cache for models/lora/lyco metadata: `metadata.json` drastically reduces disk access on app startup +- allow saving of **ui default values** + settings -> ui defaults +- ability to run server without loaded model + default is to auto-load model on startup, can be changed in settings -> stable diffusion + if disabled, model will be loaded on first request, e.g. when you click generate +- updated `accelerate` and `xformers` +- huge nubmer of changes ported from a1111 upstream + hopefully this does not cause any regressions + ## Update for 06/12/2023 diff --git a/TODO.md b/TODO.md index f6f064d70..b78230b5c 100644 --- a/TODO.md +++ b/TODO.md @@ -23,11 +23,7 @@ Stuff to be investigated... Pick & merge PRs from main repo... -- -- TODO: - - ruff stuff from 05/10/2023 - - modules/sub_quadratic_attention.py - - +- TODO: - STATUS: up-to-date 05/13/2023 ## Integration diff --git a/cli/generate.py b/cli/generate.py index 929a87634..5cfd9b0fd 100755 --- a/cli/generate.py +++ b/cli/generate.py @@ -278,7 +278,7 @@ def args(): # parse cmd arguments data = json.load(f) random = Map(data) log.debug({ 'random template': sd }) - except: + except Exception: log.error({ 'random template error': params.random}) exit() elif os.path.isfile(os.path.join(home, params.random)): @@ -287,7 +287,7 @@ def args(): # parse cmd arguments data = json.load(f) random = Map(data) log.debug({ 'random template': sd }) - except: + except Exception: log.error({ 'random template error': params.random}) exit() else: diff --git a/cli/image-exif.py b/cli/image-exif.py index 8531ef687..311797737 100755 --- a/cli/image-exif.py +++ b/cli/image-exif.py @@ -31,7 +31,7 @@ class Exif: # pylint: disable=single-string-used-for-slots exif_dict = {} try: exif_dict = dict(img._getexif().items()) # pylint: disable=protected-access - except: + except Exception: exif_dict = dict(img.info.items()) for key, val in exif_dict.items(): if isinstance(val, bytes): # decode bytestring @@ -65,7 +65,7 @@ class Exif: # pylint: disable=single-string-used-for-slots if len(val) == 0: # remove empty strings val = None return val - except: + except Exception: pass return None diff --git a/cli/image-watermark.py b/cli/image-watermark.py index 16f3fb14a..aea4b5729 100755 --- a/cli/image-watermark.py +++ b/cli/image-watermark.py @@ -26,13 +26,13 @@ def get_exif(image): for k, v in exif.items(): key = list(vars(piexif.ExifIFD).keys())[list(vars(piexif.ExifIFD).values()).index(k)] res1[key] = piexif.helper.UserComment.load(v) - except: + except Exception: pass # using pillow res2 = {} try: res2 = { TAGS[k]: v for k, v in image.getexif().items() if k in TAGS } - except: + except Exception: pass return {**res1, **res2} @@ -54,7 +54,7 @@ def get_watermark(image, params): decoded = decoder.decode(data, options.method) try: s = str(decoded, 'UTF-8').replace('\x00', '') - except: + except Exception: s = '' return s diff --git a/cli/run-benchmark.py b/cli/run-benchmark.py index 498f0cff3..112cbeff7 100755 --- a/cli/run-benchmark.py +++ b/cli/run-benchmark.py @@ -37,7 +37,7 @@ async def txt2img(): data = {} try: data = await sdapi.post('/sdapi/v1/txt2img', options) - except: + except Exception: return -1 if 'error' in data: return -1 diff --git a/cli/train.py b/cli/train.py index 6f4a18467..afb3aee63 100755 --- a/cli/train.py +++ b/cli/train.py @@ -44,7 +44,7 @@ def setup_logging(clean=False): if clean and os.path.isfile(log_file): os.remove(log_file) time.sleep(0.1) # prevent race condition - except: + except Exception: pass from rich.theme import Theme from rich.logging import RichHandler @@ -128,7 +128,7 @@ def prepare_server(): try: server_status = util.Map(sdapi.progresssync()) server_state = server_status['state'] - except: + except Exception: log.error(f'server error: {server_status}') exit(1) if server_state['job_count'] > 0: diff --git a/cli/util.py b/cli/util.py index 0fafe664c..a5ac0d37e 100755 --- a/cli/util.py +++ b/cli/util.py @@ -65,7 +65,7 @@ def get_memory(): 'gpu-inactive': inactive, 'events': events, }) - except: + except Exception: pass return Map(mem) diff --git a/extensions-builtin/LDSR/ldsr_model_arch.py b/extensions-builtin/LDSR/ldsr_model_arch.py index 7f450086f..17a7a4a97 100644 --- a/extensions-builtin/LDSR/ldsr_model_arch.py +++ b/extensions-builtin/LDSR/ldsr_model_arch.py @@ -110,7 +110,6 @@ class LDSR: diffusion_steps = int(steps) eta = 1.0 - gc.collect() if torch.cuda.is_available: torch.cuda.empty_cache() diff --git a/extensions-builtin/LDSR/sd_hijack_autoencoder.py b/extensions-builtin/LDSR/sd_hijack_autoencoder.py index 81c5101b7..a0e8fefe0 100644 --- a/extensions-builtin/LDSR/sd_hijack_autoencoder.py +++ b/extensions-builtin/LDSR/sd_hijack_autoencoder.py @@ -6,9 +6,7 @@ import torch import pytorch_lightning as pl import torch.nn.functional as F from contextlib import contextmanager - from torch.optim.lr_scheduler import LambdaLR - from ldm.modules.ema import LitEma from taming.modules.vqvae.quantize import VectorQuantizer2 as VectorQuantizer from ldm.modules.diffusionmodules.model import Encoder, Decoder diff --git a/extensions-builtin/Lora/lora.py b/extensions-builtin/Lora/lora.py index eec147122..5273c9f82 100644 --- a/extensions-builtin/Lora/lora.py +++ b/extensions-builtin/Lora/lora.py @@ -82,7 +82,7 @@ class LoraOnDisk: try: self.metadata = sd_models.read_metadata_from_safetensors(filename) except Exception as e: - errors.display(e, f"reading lora {filename}") + errors.display(e, f"reading lora metadata: {filename}") if self.metadata: m = {} diff --git a/installer.py b/installer.py index bddb49cc9..d67b432b1 100644 --- a/installer.py +++ b/installer.py @@ -53,7 +53,7 @@ def setup_logging(clean=False): if clean and os.path.isfile(log_file): os.remove(log_file) time.sleep(0.1) # prevent race condition - except: + except Exception: pass from rich.theme import Theme from rich.logging import RichHandler @@ -83,7 +83,7 @@ def setup_logging(clean=False): def print_profile(profile: cProfile.Profile, msg: str): try: from rich import print # pylint: disable=redefined-builtin - except: + except Exception: pass profile.disable() stream = io.StringIO() @@ -261,7 +261,7 @@ def check_torch(): elif allow_cuda and (shutil.which('nvidia-smi') is not None or os.path.exists(os.path.join(os.environ.get('SystemRoot') or r'C:\Windows', 'System32', 'nvidia-smi.exe'))): log.info('nVidia CUDA toolkit detected') torch_command = os.environ.get('TORCH_COMMAND', 'torch torchvision --index-url https://download.pytorch.org/whl/cu118') - xformers_package = os.environ.get('XFORMERS_PACKAGE', 'xformers==0.0.17' if opts.get('cross_attention_optimization', '') == 'xFormers' else 'none') + xformers_package = os.environ.get('XFORMERS_PACKAGE', 'xformers==0.0.20' if opts.get('cross_attention_optimization', '') == 'xFormers' else 'none') elif allow_rocm and (shutil.which('rocminfo') is not None or os.path.exists('/opt/rocm/bin/rocminfo') or os.path.exists('/dev/kfd')): log.info('AMD ROCm toolkit detected') os.environ.setdefault('HSA_OVERRIDE_GFX_VERSION', '10.3.0') @@ -318,7 +318,7 @@ def check_torch(): log.info(f'Torch backend: DirectML ({version})') for i in range(0, torch_directml.device_count()): log.info(f'Torch detected GPU: {torch_directml.device_name(i)}') - except: + except Exception: log.warning("Torch reports CUDA not available") except Exception as e: log.error(f'Could not load torch: {e}') @@ -359,7 +359,7 @@ def check_modified_files(): files = [x for x in files if len(x) > 0 and not x.startswith('extensions') and not x.startswith('wiki') and not x.endswith('.json')] if len(files) > 0: log.warning(f'Modified files: {files}') - except: + except Exception: pass @@ -479,7 +479,7 @@ def install_extensions(): if not args.skip_update: try: update(os.path.join(folder, ext)) - except: + except Exception: log.error(f'Error updating extension: {os.path.join(folder, ext)}') if not args.skip_extensions: run_extension_installer(os.path.join(folder, ext)) @@ -522,7 +522,7 @@ def install_submodules(): try: name = submodule.split()[1].strip() update(name) - except: + except Exception: log.error(f'Error updating submodule: {submodule}') if args.profile: print_profile(pr, 'Submodule') @@ -656,7 +656,7 @@ def update_wiki(): try: update(os.path.join(os.path.dirname(__file__), "wiki")) update(os.path.join(os.path.dirname(__file__), "wiki", "origin-wiki")) - except: + except Exception: log.error('Error updating wiki') @@ -745,7 +745,7 @@ def extensions_preload(parser): preload_extensions(ext_dir, parser) t1 = time.time() log.info(f'Extension preload: {round(t1 - t0, 1)}s {ext_dir}') - except: + except Exception: log.error('Error running extension preloading') if args.profile: print_profile(pr, 'Preload') diff --git a/javascript/set-hints.js b/javascript/set-hints.js index cb144d379..3bbfb87b3 100644 --- a/javascript/set-hints.js +++ b/javascript/set-hints.js @@ -44,6 +44,7 @@ async function setHints() { if (!locale.el) tooltipCreate(); let localized = 0; let hints = 0; + locale.finished = true; for (el of elements) { const found = locale.data.find(l => l.label === el.textContent); if (found?.localized?.length > 0) { @@ -63,8 +64,7 @@ async function setHints() { } } } - console.log('set-hints', { type: locale.type, elements: elements.length, localized, hints, data: locale.data }); - locale.finished = true; + console.log('set-hints', { type: locale.type, elements: elements.length, localized, hints, data: locale.data.length }); } onAfterUiUpdate(async () => { diff --git a/javascript/style.css b/javascript/style.css index 7d81b1340..a1aa3d448 100644 --- a/javascript/style.css +++ b/javascript/style.css @@ -405,6 +405,10 @@ div#extras_scale_to_tab div.form{ padding: 2em; } +.ui-defaults-none{ + color: #aaa !important; +} + /* fullpage image viewer */ #lightboxModal{ diff --git a/launch.py b/launch.py index 83f23eb68..3eb254f0d 100644 --- a/launch.py +++ b/launch.py @@ -183,7 +183,7 @@ if __name__ == "__main__": while True: try: alive = instance.thread.is_alive() - except: + except Exception: alive = False if round(time.time()) % 120 == 0: installer.log.debug(f'Server alive: {alive} Memory {get_memory_stats()}') diff --git a/modules/api/api.py b/modules/api/api.py index 420e774f2..33e84f114 100644 --- a/modules/api/api.py +++ b/modules/api/api.py @@ -2,7 +2,7 @@ import io import time import base64 from io import BytesIO -from typing import List +from typing import List, Dict, Any from threading import Lock from secrets import compare_digest from fastapi import APIRouter, Depends, FastAPI @@ -14,7 +14,7 @@ import piexif.helper import uvicorn import gradio as gr from modules import errors, shared, sd_samplers, deepbooru, sd_hijack, images, scripts, ui, postprocessing -from modules.api.models import * # pylint: disable=unused-wildcard-import, wildcard-import +from modules.api import models from modules.processing import StableDiffusionProcessingTxt2Img, StableDiffusionProcessingImg2Img, process_images from modules.textual_inversion.textual_inversion import create_embedding, train_embedding from modules.textual_inversion.preprocess import preprocess @@ -97,7 +97,7 @@ def encode_pil_to_base64(image): class Api: def __init__(self, app: FastAPI, queue_lock: Lock): - self.credentials = dict() + self.credentials = {} if shared.cmd_opts.auth: for auth in shared.cmd_opts.auth.split(","): user, password = auth.split(":") @@ -111,37 +111,37 @@ class Api: self.router = APIRouter() self.app = app self.queue_lock = queue_lock - self.add_api_route("/sdapi/v1/txt2img", self.text2imgapi, methods=["POST"], response_model=TextToImageResponse) - self.add_api_route("/sdapi/v1/img2img", self.img2imgapi, methods=["POST"], response_model=ImageToImageResponse) - self.add_api_route("/sdapi/v1/extra-single-image", self.extras_single_image_api, methods=["POST"], response_model=ExtrasSingleImageResponse) - self.add_api_route("/sdapi/v1/extra-batch-images", self.extras_batch_images_api, methods=["POST"], response_model=ExtrasBatchImagesResponse) - self.add_api_route("/sdapi/v1/png-info", self.pnginfoapi, methods=["POST"], response_model=PNGInfoResponse) - self.add_api_route("/sdapi/v1/progress", self.progressapi, methods=["GET"], response_model=ProgressResponse) + self.add_api_route("/sdapi/v1/txt2img", self.text2imgapi, methods=["POST"], response_model=models.TextToImageResponse) + self.add_api_route("/sdapi/v1/img2img", self.img2imgapi, methods=["POST"], response_model=models.ImageToImageResponse) + self.add_api_route("/sdapi/v1/extra-single-image", self.extras_single_image_api, methods=["POST"], response_model=models.ExtrasSingleImageResponse) + self.add_api_route("/sdapi/v1/extra-batch-images", self.extras_batch_images_api, methods=["POST"], response_model=models.ExtrasBatchImagesResponse) + self.add_api_route("/sdapi/v1/png-info", self.pnginfoapi, methods=["POST"], response_model=models.PNGInfoResponse) + self.add_api_route("/sdapi/v1/progress", self.progressapi, methods=["GET"], response_model=models.ProgressResponse) self.add_api_route("/sdapi/v1/interrogate", self.interrogateapi, methods=["POST"]) self.add_api_route("/sdapi/v1/interrupt", self.interruptapi, methods=["POST"]) self.add_api_route("/sdapi/v1/skip", self.skip, methods=["POST"]) - self.add_api_route("/sdapi/v1/options", self.get_config, methods=["GET"], response_model=OptionsModel) + self.add_api_route("/sdapi/v1/options", self.get_config, methods=["GET"], response_model=models.OptionsModel) self.add_api_route("/sdapi/v1/options", self.set_config, methods=["POST"]) - self.add_api_route("/sdapi/v1/cmd-flags", self.get_cmd_flags, methods=["GET"], response_model=FlagsModel) - self.add_api_route("/sdapi/v1/samplers", self.get_samplers, methods=["GET"], response_model=List[SamplerItem]) - self.add_api_route("/sdapi/v1/upscalers", self.get_upscalers, methods=["GET"], response_model=List[UpscalerItem]) - self.add_api_route("/sdapi/v1/sd-models", self.get_sd_models, methods=["GET"], response_model=List[SDModelItem]) - self.add_api_route("/sdapi/v1/hypernetworks", self.get_hypernetworks, methods=["GET"], response_model=List[HypernetworkItem]) - self.add_api_route("/sdapi/v1/face-restorers", self.get_face_restorers, methods=["GET"], response_model=List[FaceRestorerItem]) - self.add_api_route("/sdapi/v1/realesrgan-models", self.get_realesrgan_models, methods=["GET"], response_model=List[RealesrganItem]) - self.add_api_route("/sdapi/v1/prompt-styles", self.get_prompt_styles, methods=["GET"], response_model=List[PromptStyleItem]) - self.add_api_route("/sdapi/v1/embeddings", self.get_embeddings, methods=["GET"], response_model=EmbeddingsResponse) + self.add_api_route("/sdapi/v1/cmd-flags", self.get_cmd_flags, methods=["GET"], response_model=models.FlagsModel) + self.add_api_route("/sdapi/v1/samplers", self.get_samplers, methods=["GET"], response_model=List[models.SamplerItem]) + self.add_api_route("/sdapi/v1/upscalers", self.get_upscalers, methods=["GET"], response_model=List[models.UpscalerItem]) + self.add_api_route("/sdapi/v1/sd-models", self.get_sd_models, methods=["GET"], response_model=List[models.SDModelItem]) + self.add_api_route("/sdapi/v1/hypernetworks", self.get_hypernetworks, methods=["GET"], response_model=List[models.HypernetworkItem]) + self.add_api_route("/sdapi/v1/face-restorers", self.get_face_restorers, methods=["GET"], response_model=List[models.FaceRestorerItem]) + self.add_api_route("/sdapi/v1/realesrgan-models", self.get_realesrgan_models, methods=["GET"], response_model=List[models.RealesrganItem]) + self.add_api_route("/sdapi/v1/prompt-styles", self.get_prompt_styles, methods=["GET"], response_model=List[models.PromptStyleItem]) + self.add_api_route("/sdapi/v1/embeddings", self.get_embeddings, methods=["GET"], response_model=models.EmbeddingsResponse) self.add_api_route("/sdapi/v1/refresh-checkpoints", self.refresh_checkpoints, methods=["POST"]) - self.add_api_route("/sdapi/v1/create/embedding", self.create_embedding, methods=["POST"], response_model=CreateResponse) - self.add_api_route("/sdapi/v1/create/hypernetwork", self.create_hypernetwork, methods=["POST"], response_model=CreateResponse) - self.add_api_route("/sdapi/v1/preprocess", self.preprocess, methods=["POST"], response_model=PreprocessResponse) - self.add_api_route("/sdapi/v1/train/embedding", self.train_embedding, methods=["POST"], response_model=TrainResponse) - self.add_api_route("/sdapi/v1/train/hypernetwork", self.train_hypernetwork, methods=["POST"], response_model=TrainResponse) + self.add_api_route("/sdapi/v1/create/embedding", self.create_embedding, methods=["POST"], response_model=models.CreateResponse) + self.add_api_route("/sdapi/v1/create/hypernetwork", self.create_hypernetwork, methods=["POST"], response_model=models.CreateResponse) + self.add_api_route("/sdapi/v1/preprocess", self.preprocess, methods=["POST"], response_model=models.PreprocessResponse) + self.add_api_route("/sdapi/v1/train/embedding", self.train_embedding, methods=["POST"], response_model=models.TrainResponse) + self.add_api_route("/sdapi/v1/train/hypernetwork", self.train_hypernetwork, methods=["POST"], response_model=models.TrainResponse) self.add_api_route("/sdapi/v1/shutdown", self.shutdown, methods=["POST"]) - self.add_api_route("/sdapi/v1/memory", self.get_memory, methods=["GET"], response_model=MemoryResponse) + self.add_api_route("/sdapi/v1/memory", self.get_memory, methods=["GET"], response_model=models.MemoryResponse) self.add_api_route("/sdapi/v1/unload-checkpoint", self.unloadapi, methods=["POST"]) self.add_api_route("/sdapi/v1/reload-checkpoint", self.reloadapi, methods=["POST"]) - self.add_api_route("/sdapi/v1/scripts", self.get_scripts_list, methods=["GET"], response_model=ScriptsList) + self.add_api_route("/sdapi/v1/scripts", self.get_scripts_list, methods=["GET"], response_model=models.ScriptsList) self.default_script_arg_txt2img = [] self.default_script_arg_img2img = [] @@ -166,7 +166,7 @@ class Api: def get_scripts_list(self): t2ilist = [str(title.lower()) for title in scripts.scripts_txt2img.titles] i2ilist = [str(title.lower()) for title in scripts.scripts_img2img.titles] - return ScriptsList(txt2img = t2ilist, img2img = i2ilist) + return models.ScriptsList(txt2img = t2ilist, img2img = i2ilist) def get_script(self, script_name, script_runner): if script_name is None or script_name == "": @@ -218,7 +218,7 @@ class Api: return script_args - def text2imgapi(self, txt2imgreq: StableDiffusionTxt2ImgProcessingAPI): + def text2imgapi(self, txt2imgreq: models.StableDiffusionTxt2ImgProcessingAPI): script_runner = scripts.scripts_txt2img if not script_runner.scripts: script_runner.initialize_scripts(False) @@ -255,9 +255,9 @@ class Api: shared.state.end() b64images = list(map(encode_pil_to_base64, processed.images)) if send_images else [] - return TextToImageResponse(images=b64images, parameters=vars(txt2imgreq), info=processed.js()) + return models.TextToImageResponse(images=b64images, parameters=vars(txt2imgreq), info=processed.js()) - def img2imgapi(self, img2imgreq: StableDiffusionImg2ImgProcessingAPI): + def img2imgapi(self, img2imgreq: models.StableDiffusionImg2ImgProcessingAPI): init_images = img2imgreq.init_images if init_images is None: raise HTTPException(status_code=404, detail="Init image not found") @@ -306,16 +306,16 @@ class Api: if not img2imgreq.include_init_images: img2imgreq.init_images = None img2imgreq.mask = None - return ImageToImageResponse(images=b64images, parameters=vars(img2imgreq), info=processed.js()) + return models.ImageToImageResponse(images=b64images, parameters=vars(img2imgreq), info=processed.js()) - def extras_single_image_api(self, req: ExtrasSingleImageRequest): + def extras_single_image_api(self, req: models.ExtrasSingleImageRequest): reqDict = setUpscalers(req) reqDict['image'] = decode_base64_to_image(reqDict['image']) with self.queue_lock: result = postprocessing.run_extras(extras_mode=0, image_folder="", input_dir="", output_dir="", save_output=False, **reqDict) - return ExtrasSingleImageResponse(image=encode_pil_to_base64(result[0][0]), html_info=result[1]) + return models.ExtrasSingleImageResponse(image=encode_pil_to_base64(result[0][0]), html_info=result[1]) - def extras_batch_images_api(self, req: ExtrasBatchImagesRequest): + def extras_batch_images_api(self, req: models.ExtrasBatchImagesRequest): reqDict = setUpscalers(req) image_list = reqDict.pop('imageList', []) @@ -324,15 +324,15 @@ class Api: with self.queue_lock: result = postprocessing.run_extras(extras_mode=1, image_folder=image_folder, image="", input_dir="", output_dir="", save_output=False, **reqDict) - return ExtrasBatchImagesResponse(images=list(map(encode_pil_to_base64, result[0])), html_info=result[1]) + return models.ExtrasBatchImagesResponse(images=list(map(encode_pil_to_base64, result[0])), html_info=result[1]) - def pnginfoapi(self, req: PNGInfoRequest): + def pnginfoapi(self, req: models.PNGInfoRequest): if not req.image.strip(): - return PNGInfoResponse(info="") + return models.PNGInfoResponse(info="") image = decode_base64_to_image(req.image.strip()) if image is None: - return PNGInfoResponse(info="") + return models.PNGInfoResponse(info="") geninfo, items = images.read_info_from_image(image) if geninfo is None: @@ -340,13 +340,13 @@ class Api: items = {**{'parameters': geninfo}, **items} - return PNGInfoResponse(info=geninfo, items=items) + return models.PNGInfoResponse(info=geninfo, items=items) - def progressapi(self, req: ProgressRequest = Depends()): + def progressapi(self, req: models.ProgressRequest = Depends()): # copy from check_progress_call of ui.py if shared.state.job_count == 0: - return ProgressResponse(progress=0, eta_relative=0, state=shared.state.dict(), textinfo=shared.state.textinfo) + return models.ProgressResponse(progress=0, eta_relative=0, state=shared.state.dict(), textinfo=shared.state.textinfo) # avoid dividing zero progress = 0.01 @@ -368,9 +368,9 @@ class Api: if shared.state.current_image and not req.skip_current_image: current_image = encode_pil_to_base64(shared.state.current_image) - return ProgressResponse(progress=progress, eta_relative=eta_relative, state=shared.state.dict(), current_image=current_image, textinfo=shared.state.textinfo) + return models.ProgressResponse(progress=progress, eta_relative=eta_relative, state=shared.state.dict(), current_image=current_image, textinfo=shared.state.textinfo) - def interrogateapi(self, interrogatereq: InterrogateRequest): + def interrogateapi(self, interrogatereq: models.InterrogateRequest): image_b64 = interrogatereq.image if image_b64 is None: raise HTTPException(status_code=404, detail="Image not found") @@ -387,7 +387,7 @@ class Api: else: raise HTTPException(status_code=404, detail="Model not found") - return InterrogateResponse(caption=processed) + return models.InterrogateResponse(caption=processed) def interruptapi(self): shared.state.interrupt() @@ -493,36 +493,36 @@ class Api: filename = create_embedding(**args) # create empty embedding sd_hijack.model_hijack.embedding_db.load_textual_inversion_embeddings() # reload embeddings so new one can be immediately used shared.state.end() - return CreateResponse(info = f"create embedding filename: {filename}") + return models.CreateResponse(info = f"create embedding filename: {filename}") except AssertionError as e: shared.state.end() - return TrainResponse(info = f"create embedding error: {e}") + return models.TrainResponse(info = f"create embedding error: {e}") def create_hypernetwork(self, args: dict): try: shared.state.begin() filename = create_hypernetwork(**args) # create empty embedding # pylint: disable=E1111 shared.state.end() - return CreateResponse(info = f"create hypernetwork filename: {filename}") + return models.CreateResponse(info = f"create hypernetwork filename: {filename}") except AssertionError as e: shared.state.end() - return TrainResponse(info = f"create hypernetwork error: {e}") + return models.TrainResponse(info = f"create hypernetwork error: {e}") def preprocess(self, args: dict): try: shared.state.begin() preprocess(**args) # quick operation unless blip/booru interrogation is enabled shared.state.end() - return PreprocessResponse(info = 'preprocess complete') + return models.PreprocessResponse(info = 'preprocess complete') except KeyError as e: shared.state.end() - return PreprocessResponse(info = f"preprocess error: invalid token: {e}") + return models.PreprocessResponse(info = f"preprocess error: invalid token: {e}") except AssertionError as e: shared.state.end() - return PreprocessResponse(info = f"preprocess error: {e}") + return models.PreprocessResponse(info = f"preprocess error: {e}") except FileNotFoundError as e: shared.state.end() - return PreprocessResponse(info = f'preprocess error: {e}') + return models.PreprocessResponse(info = f'preprocess error: {e}') def train_embedding(self, args: dict): try: @@ -540,10 +540,10 @@ class Api: if not apply_optimizations: sd_hijack.apply_optimizations() shared.state.end() - return TrainResponse(info = f"train embedding complete: filename: {filename} error: {error}") + return models.TrainResponse(info = f"train embedding complete: filename: {filename} error: {error}") except AssertionError as msg: shared.state.end() - return TrainResponse(info = f"train embedding error: {msg}") + return models.TrainResponse(info = f"train embedding error: {msg}") def train_hypernetwork(self, args: dict): try: @@ -564,10 +564,10 @@ class Api: if not apply_optimizations: sd_hijack.apply_optimizations() shared.state.end() - return TrainResponse(info=f"train embedding complete: filename: {filename} error: {error}") + return models.TrainResponse(info=f"train embedding complete: filename: {filename} error: {error}") except AssertionError: shared.state.end() - return TrainResponse(info=f"train embedding error: {error}") + return models.TrainResponse(info=f"train embedding error: {error}") def shutdown(self): shared.log.info('Shutdown request received') @@ -628,7 +628,7 @@ class Api: cuda = { 'error': 'unavailable' } except Exception as err: cuda = { 'error': f'{err}' } - return MemoryResponse(ram = ram, cuda = cuda) + return models.MemoryResponse(ram = ram, cuda = cuda) def launch(self, server_name, port): self.app.include_router(self.router) diff --git a/modules/api/models.py b/modules/api/models.py index 498d8f07c..1d547dad1 100644 --- a/modules/api/models.py +++ b/modules/api/models.py @@ -220,7 +220,7 @@ for key in _options: _type = str if _options[key].default is not None: _type = type(_options[key].default) - flags.update({flag.dest: (_type,Field(default=flag.default, description=flag.help))}) + flags.update({flag.dest: (_type, Field(default=flag.default, description=flag.help))}) FlagsModel = create_model("Flags", **flags) diff --git a/modules/codeformer/codeformer_arch.py b/modules/codeformer/codeformer_arch.py index ef83c2f75..22c0e37d1 100644 --- a/modules/codeformer/codeformer_arch.py +++ b/modules/codeformer/codeformer_arch.py @@ -7,7 +7,7 @@ from torch import nn, Tensor import torch.nn.functional as F from typing import Optional, List -from modules.codeformer.vqgan_arch import * +from modules.codeformer.vqgan_arch import VQAutoEncoder, ResBlock from basicsr.utils import get_root_logger from basicsr.utils.registry import ARCH_REGISTRY @@ -160,12 +160,12 @@ class Fuse_sft_block(nn.Module): @ARCH_REGISTRY.register() class CodeFormer(VQAutoEncoder): - def __init__(self, dim_embd=512, n_head=8, n_layers=9, + def __init__(self, dim_embd=512, n_head=8, n_layers=9, codebook_size=1024, latent_size=256, - connect_list=['32', '64', '128', '256'], - fix_modules=['quantize','generator']): + connect_list=('32', '64', '128', '256'), + fix_modules=('quantize', 'generator')): super(CodeFormer, self).__init__(512, 64, [1, 2, 2, 4, 4, 8], 'nearest',2, [16], codebook_size) - + if fix_modules is not None: for module in fix_modules: for param in getattr(self, module).parameters(): @@ -180,14 +180,14 @@ class CodeFormer(VQAutoEncoder): self.feat_emb = nn.Linear(256, self.dim_embd) # transformer - self.ft_layers = nn.Sequential(*[TransformerSALayer(embed_dim=dim_embd, nhead=n_head, dim_mlp=self.dim_mlp, dropout=0.0) + self.ft_layers = nn.Sequential(*[TransformerSALayer(embed_dim=dim_embd, nhead=n_head, dim_mlp=self.dim_mlp, dropout=0.0) for _ in range(self.n_layers)]) # logits_predict head self.idx_pred_layer = nn.Sequential( nn.LayerNorm(dim_embd), nn.Linear(dim_embd, codebook_size, bias=False)) - + self.channels = { '16': 512, '32': 256, diff --git a/modules/codeformer/vqgan_arch.py b/modules/codeformer/vqgan_arch.py index e72936838..6e72d341b 100644 --- a/modules/codeformer/vqgan_arch.py +++ b/modules/codeformer/vqgan_arch.py @@ -328,7 +328,7 @@ class Generator(nn.Module): @ARCH_REGISTRY.register() class VQAutoEncoder(nn.Module): - def __init__(self, img_size, nf, ch_mult, quantizer="nearest", res_blocks=2, attn_resolutions=[16], codebook_size=1024, emb_dim=256, + def __init__(self, img_size, nf, ch_mult, quantizer="nearest", res_blocks=2, attn_resolutions=None, codebook_size=1024, emb_dim=256, beta=0.25, gumbel_straight_through=False, gumbel_kl_weight=1e-8, model_path=None): super().__init__() logger = get_root_logger() @@ -339,7 +339,7 @@ class VQAutoEncoder(nn.Module): self.embed_dim = emb_dim self.ch_mult = ch_mult self.resolution = img_size - self.attn_resolutions = attn_resolutions + self.attn_resolutions = attn_resolutions or [16] self.quantizer_type = quantizer self.encoder = Encoder( self.in_channels, diff --git a/modules/codeformer_model.py b/modules/codeformer_model.py index 944dedfcd..a57e1ee49 100644 --- a/modules/codeformer_model.py +++ b/modules/codeformer_model.py @@ -91,7 +91,7 @@ def setup_model(dirname): self.face_helper.get_face_landmarks_5(only_center_face=False, resize=640, eye_dist_threshold=5) self.face_helper.align_warp_face() - for _idx, cropped_face in enumerate(self.face_helper.cropped_faces): + for cropped_face in self.face_helper.cropped_faces: cropped_face_t = img2tensor(cropped_face / 255., bgr2rgb=True, float32=True) normalize(cropped_face_t, (0.5, 0.5, 0.5), (0.5, 0.5, 0.5), inplace=True) cropped_face_t = cropped_face_t.unsqueeze(0).to(devices.device_codeformer) diff --git a/modules/deepbooru.py b/modules/deepbooru.py index 1c4554a20..547e1b4c6 100644 --- a/modules/deepbooru.py +++ b/modules/deepbooru.py @@ -78,7 +78,7 @@ class DeepDanbooru: res = [] - filtertags = set([x.strip().replace(' ', '_') for x in shared.opts.deepbooru_filter_tags.split(",")]) + filtertags = {x.strip().replace(' ', '_') for x in shared.opts.deepbooru_filter_tags.split(",")} for tag in [x for x in tags if x not in filtertags]: probability = probability_dict[tag] diff --git a/modules/devices.py b/modules/devices.py index f888e57ee..12a0dfbdd 100644 --- a/modules/devices.py +++ b/modules/devices.py @@ -68,14 +68,14 @@ def torch_gc(force=False): try: with torch.xpu.device(get_cuda_device_string()): torch.xpu.empty_cache() - except: + except Exception: pass elif cuda_ok: try: with torch.cuda.device(get_cuda_device_string()): torch.cuda.empty_cache() torch.cuda.ipc_collect() - except: + except Exception: pass shared.log.debug(f'gc: collected={collected} device={torch.device(get_optimal_device_name())} {memstats.memory_stats()}') @@ -89,7 +89,7 @@ def test_fp16(): _y = layerNorm(x) shared.log.debug('Torch FP16 test passed') return True - except: + except Exception: shared.log.warning('Torch FP16 test failed: Forcing FP32 operations') shared.opts.cuda_dtype = 'FP32' shared.opts.no_half = True @@ -104,7 +104,7 @@ def test_bf16(): image = torch.randn(1, 4, 32, 32).to(device=device, dtype=torch.bfloat16) _out = F.interpolate(image, size=(64, 64), mode="nearest") return True - except: + except Exception: shared.log.warning('Torch BF16 test failed: Fallback to FP16 operations') return False @@ -116,7 +116,7 @@ def set_cuda_params(): torch.backends.cuda.matmul.allow_tf32 = shared.opts.cuda_allow_tf32 torch.backends.cuda.matmul.allow_fp16_reduced_precision_reduction = shared.opts.cuda_allow_tf16_reduced torch.backends.cuda.matmul.allow_bf16_reduced_precision_reduction = shared.opts.cuda_allow_tf16_reduced - except: + except Exception: pass if torch.backends.cudnn.is_available(): try: @@ -124,7 +124,7 @@ def set_cuda_params(): if shared.opts.cudnn_benchmark: torch.backends.cudnn.benchmark_limit = 0 torch.backends.cudnn.allow_tf32 = shared.opts.cuda_allow_tf32 - except: + except Exception: pass global dtype, dtype_vae, dtype_unet, unet_needs_upcast # pylint: disable=global-statement if shared.cmd_opts.use_directml and not shared.cmd_opts.experimental: # TODO DirectML does not have full autocast capabilities diff --git a/modules/dml/__init__.py b/modules/dml/__init__.py index 46501d9cc..3dc89173a 100644 --- a/modules/dml/__init__.py +++ b/modules/dml/__init__.py @@ -23,7 +23,7 @@ class DirectML(): else: return UnknownOptimizer return optimizer - except: + except Exception: return UnknownOptimizer def memory_stats(device: torch.device): diff --git a/modules/dml/hijack/plms.py b/modules/dml/hijack/plms.py index 49979db28..5a9570454 100644 --- a/modules/dml/hijack/plms.py +++ b/modules/dml/hijack/plms.py @@ -20,7 +20,7 @@ def p_sample_plms(self, x, c, t, index, repeat_noise=False, use_original_steps=F if isinstance(c, dict): assert isinstance(unconditional_conditioning, dict) - c_in = dict() + c_in = {} for k in c: if isinstance(c[k], list): c_in[k] = [ diff --git a/modules/esrgan_model.py b/modules/esrgan_model.py index b685711ef..caff8624a 100644 --- a/modules/esrgan_model.py +++ b/modules/esrgan_model.py @@ -16,9 +16,7 @@ def mod2normal(state_dict): # this code is copied from https://github.com/victorca25/iNNfer if 'conv_first.weight' in state_dict: crt_net = {} - items = [] - for k, _v in state_dict.items(): - items.append(k) + items = list(state_dict) crt_net['model.0.weight'] = state_dict['conv_first.weight'] crt_net['model.0.bias'] = state_dict['conv_first.bias'] @@ -52,9 +50,7 @@ def resrgan2normal(state_dict, nb=23): if "conv_first.weight" in state_dict and "body.0.rdb1.conv1.weight" in state_dict: re8x = 0 crt_net = {} - items = [] - for k, _v in state_dict.items(): - items.append(k) + items = list(state_dict) crt_net['model.0.weight'] = state_dict['conv_first.weight'] crt_net['model.0.bias'] = state_dict['conv_first.bias'] diff --git a/modules/esrgan_model_arch.py b/modules/esrgan_model_arch.py index af7660ec9..a2e7e1dc0 100644 --- a/modules/esrgan_model_arch.py +++ b/modules/esrgan_model_arch.py @@ -437,9 +437,11 @@ def conv_block(in_nc, out_nc, kernel_size, stride=1, dilation=1, groups=1, bias= padding = padding if pad_type == 'zero' else 0 if convtype=='PartialConv2D': + from torchvision.ops import PartialConv2d c = PartialConv2d(in_nc, out_nc, kernel_size=kernel_size, stride=stride, padding=padding, dilation=dilation, bias=bias, groups=groups) elif convtype=='DeformConv2D': + from torchvision.ops import DeformConv2d c = DeformConv2d(in_nc, out_nc, kernel_size=kernel_size, stride=stride, padding=padding, dilation=dilation, bias=bias, groups=groups) elif convtype=='Conv3D': diff --git a/modules/extensions.py b/modules/extensions.py index 65474592b..2783de129 100644 --- a/modules/extensions.py +++ b/modules/extensions.py @@ -86,7 +86,7 @@ class Extension: def check_updates(self): try: repo = git.Repo(self.path) - except: + except Exception: self.can_update = False return for fetch in repo.remote().fetch(dry_run=True): diff --git a/modules/extra_networks.py b/modules/extra_networks.py index 9e886219a..e02d1cc07 100644 --- a/modules/extra_networks.py +++ b/modules/extra_networks.py @@ -91,7 +91,7 @@ def deactivate(p, extra_network_data): """call deactivate for extra networks in extra_network_data in specified order, then call deactivate for all remaining registered networks""" - for extra_network_name, _extra_network_args in extra_network_data.items(): + for extra_network_name in extra_network_data: extra_network = extra_network_registry.get(extra_network_name, None) if extra_network is None: continue diff --git a/modules/generation_parameters_copypaste.py b/modules/generation_parameters_copypaste.py index 5abd7cfc4..55d92f954 100644 --- a/modules/generation_parameters_copypaste.py +++ b/modules/generation_parameters_copypaste.py @@ -20,14 +20,14 @@ registered_param_bindings = [] class ParamBinding: - def __init__(self, paste_button, tabname, source_text_component=None, source_image_component=None, source_tabname=None, override_settings_component=None, paste_field_names=[]): + def __init__(self, paste_button, tabname, source_text_component=None, source_image_component=None, source_tabname=None, override_settings_component=None, paste_field_names=None): self.paste_button = paste_button self.tabname = tabname self.source_text_component = source_text_component self.source_image_component = source_image_component self.source_tabname = source_tabname self.override_settings_component = override_settings_component - self.paste_field_names = paste_field_names + self.paste_field_names = paste_field_names or [] def reset(): @@ -254,7 +254,7 @@ Steps: 20, Sampler: Euler a, CFG scale: 7, Seed: 965400086, Size: 512x512, Model if len(re_param.findall(lastline)) < 3: lines.append(lastline) lastline = '' - for _i, line in enumerate(lines): + for line in lines: line = line.strip() if line.startswith("Negative prompt:"): done_with_prompt = True diff --git a/modules/hypernetworks/hypernetwork.py b/modules/hypernetworks/hypernetwork.py index c8f1d59da..e56b02399 100644 --- a/modules/hypernetworks/hypernetwork.py +++ b/modules/hypernetworks/hypernetwork.py @@ -174,34 +174,34 @@ class Hypernetwork: def weights(self): res = [] - for k, layers in self.layers.items(): + for layers in self.layers.values(): for layer in layers: res += layer.parameters() return res def train(self, mode=True): - for k, layers in self.layers.items(): + for layers in self.layers.values(): for layer in layers: layer.train(mode=mode) for param in layer.parameters(): param.requires_grad = mode def to(self, device): - for k, layers in self.layers.items(): + for layers in self.layers.values(): for layer in layers: layer.to(device) return self def set_multiplier(self, multiplier): - for k, layers in self.layers.items(): + for layers in self.layers.values(): for layer in layers: layer.multiplier = multiplier return self def eval(self): - for k, layers in self.layers.items(): + for layers in self.layers.values(): for layer in layers: layer.eval() for param in layer.parameters(): @@ -400,7 +400,7 @@ def attention_CrossAttention_forward(self, x, context=None, mask=None): k = self.to_k(context_k) v = self.to_v(context_v) - q, k, v = map(lambda t: rearrange(t, 'b n (h d) -> (b h) n d', h=h), (q, k, v)) + q, k, v = (rearrange(t, 'b n (h d) -> (b h) n d', h=h) for t in (q, k, v)) sim = einsum('b i d, b j d -> b i j', q, k) * self.scale @@ -619,7 +619,7 @@ def train_hypernetwork(id_task, hypernetwork_name, learn_rate, batch_size, gradi try: sd_hijack_checkpoint.add() - for i in range((steps-initial_step) * gradient_step): + for _i in range((steps-initial_step) * gradient_step): if scheduler.finished: break if shared.state.interrupted: @@ -811,7 +811,7 @@ def save_hypernetwork(hypernetwork, checkpoint, hypernetwork_name, filename): hypernetwork.sd_checkpoint_name = checkpoint.model_name hypernetwork.name = hypernetwork_name hypernetwork.save(filename) - except: + except Exception: hypernetwork.sd_checkpoint = old_sd_checkpoint hypernetwork.sd_checkpoint_name = old_sd_checkpoint_name hypernetwork.name = old_hypernetwork_name diff --git a/modules/hypernetworks/ui.py b/modules/hypernetworks/ui.py index 593f1c745..9b62769e3 100644 --- a/modules/hypernetworks/ui.py +++ b/modules/hypernetworks/ui.py @@ -7,25 +7,20 @@ import modules.hypernetworks.hypernetwork from modules import devices, sd_hijack, shared not_available = ["hardswish", "multiheadattention"] -keys = list(x for x in modules.hypernetworks.hypernetwork.HypernetworkModule.activation_dict if x not in not_available) +keys = [x for x in modules.hypernetworks.hypernetwork.HypernetworkModule.activation_dict.keys() if x not in not_available] def create_hypernetwork(name, enable_sizes, overwrite_old, layer_structure=None, activation_func=None, weight_init=None, add_layer_norm=False, use_dropout=False, dropout_structure=None): filename = modules.hypernetworks.hypernetwork.create_hypernetwork(name, enable_sizes, overwrite_old, layer_structure, activation_func, weight_init, add_layer_norm, use_dropout, dropout_structure) - - return gr.Dropdown.update(choices=sorted([x for x in shared.hypernetworks])), f"Created: {filename}", "" + return gr.Dropdown.update(choices=sorted(shared.hypernetworks)), f"Created: {filename}", "" def train_hypernetwork(*args): shared.loaded_hypernetworks = [] - assert not shared.cmd_opts.lowvram, 'Training models with lowvram is not possible' - try: sd_hijack.undo_optimizations() - hypernetwork, filename = modules.hypernetworks.hypernetwork.train_hypernetwork(*args) - res = f""" Training {'interrupted' if shared.state.interrupted else 'finished'} at {hypernetwork.step} steps. Hypernetwork saved to {html.escape(filename)} @@ -37,4 +32,3 @@ Hypernetwork saved to {html.escape(filename)} shared.sd_model.cond_stage_model.to(devices.device) shared.sd_model.first_stage_model.to(devices.device) sd_hijack.apply_optimizations() - diff --git a/modules/images.py b/modules/images.py index 6e2b60acd..2e9d7f2a8 100644 --- a/modules/images.py +++ b/modules/images.py @@ -150,7 +150,7 @@ def draw_grid_annotations(im, width, height, hor_texts, ver_texts, margin=0): return ImageFont.truetype('html/roboto.ttf', fontsize) def draw_texts(drawing, draw_x, draw_y, lines, initial_fnt, initial_fontsize): - for _i, line in enumerate(lines): + for line in lines: fnt = initial_fnt fontsize = initial_fontsize while drawing.multiline_textsize(line.text, font=fnt)[0] > line.allowed_width and fontsize > 0: @@ -373,7 +373,7 @@ class FilenameGenerator: time_zone_time = time_datetime.astimezone(time_zone) try: formatted_time = time_zone_time.strftime(time_format) - except (ValueError, TypeError) as _: + except (ValueError, TypeError): formatted_time = time_zone_time.strftime(self.default_time_format) return sanitize_filename_part(formatted_time, replace_spaces=False) @@ -418,9 +418,9 @@ def get_next_sequence_number(path, basename): prefix_length = len(basename) for p in os.listdir(path): if p.startswith(basename): - l = os.path.splitext(p[prefix_length:])[0].split('-') # splits the filename (removing the basename first if one is defined, so the sequence number is always the first element) + parts = os.path.splitext(p[prefix_length:])[0].split('-') # splits the filename (removing the basename first if one is defined, so the sequence number is always the first element) try: - result = max(int(l[0]), result) + result = max(int(parts[0]), result) except ValueError: pass return result + 1 @@ -600,7 +600,7 @@ def safe_decode_string(s: bytes): if len(val) == 0: # remove empty strings val = None return val - except: + except Exception: pass return None diff --git a/modules/img2img.py b/modules/img2img.py index 421c47957..2e2ccd9eb 100644 --- a/modules/img2img.py +++ b/modules/img2img.py @@ -2,11 +2,9 @@ import os import numpy as np from PIL import Image, ImageOps, ImageFilter, ImageEnhance, ImageChops, UnidentifiedImageError import modules.scripts -from modules import sd_samplers, shared +from modules import sd_samplers, shared, processing from modules.generation_parameters_copypaste import create_override_settings_dict -from modules.processing import Processed, StableDiffusionProcessingImg2Img, process_images from modules.ui import plaintext_to_html, infotext_to_html -import modules.processing as processing from modules.memstats import memory_stats @@ -51,7 +49,7 @@ def process_batch(p, input_dir, output_dir, inpaint_mask_dir, args): proc = modules.scripts.scripts_img2img.run(p, *args) if proc is None: - proc = process_images(p) + proc = processing.process_images(p) for n, processed_image in enumerate(proc.images): filename = os.path.basename(image) if n > 0: @@ -126,7 +124,7 @@ def img2img(id_task: str, mode: int, prompt: str, negative_prompt: str, prompt_s assert 0. <= denoising_strength <= 1., 'can only work with strength in [0.0, 1.0]' - p = StableDiffusionProcessingImg2Img( + p = processing.StableDiffusionProcessingImg2Img( sd_model=shared.sd_model, outpath_samples=shared.opts.outdir_samples or shared.opts.outdir_img2img_samples, outpath_grids=shared.opts.outdir_grids or shared.opts.outdir_img2img_grids, @@ -167,11 +165,11 @@ def img2img(id_task: str, mode: int, prompt: str, negative_prompt: str, prompt_s p.extra_generation_params["Mask blur"] = mask_blur if is_batch: process_batch(p, img2img_batch_input_dir, img2img_batch_output_dir, img2img_batch_inpaint_mask_dir, args) - processed = Processed(p, [], p.seed, "") + processed = processing.Processed(p, [], p.seed, "") else: processed = modules.scripts.scripts_img2img.run(p, *args) if processed is None: - processed = process_images(p) + processed = processing.process_images(p) p.close() generation_info_js = processed.js() shared.log.debug(f'Processed: {len(processed.images)} Memory: {memory_stats()} img') diff --git a/modules/interrogate.py b/modules/interrogate.py index 0a9613b4b..be465d9b2 100644 --- a/modules/interrogate.py +++ b/modules/interrogate.py @@ -3,15 +3,13 @@ import sys from collections import namedtuple from pathlib import Path import re - import torch import torch.hub # pylint: disable=ungrouped-imports - from torchvision import transforms from torchvision.transforms.functional import InterpolationMode - from modules import devices, paths, shared, lowvram, modelloader, errors + blip_image_eval_size = 384 clip_model_name = 'ViT-L/14' @@ -157,7 +155,7 @@ class InterrogateModels: text_array = text_array[0:int(shared.opts.interrogate_clip_dict_limit)] top_count = min(top_count, len(text_array)) - text_tokens = clip.tokenize([text for text in text_array], truncate=True).to(devices.device_interrogate) + text_tokens = clip.tokenize(list(text_array), truncate=True).to(devices.device_interrogate) text_features = self.clip_model.encode_text(text_tokens).type(self.dtype) text_features /= text_features.norm(dim=-1, keepdim=True) diff --git a/modules/memmon.py b/modules/memmon.py index 080c051af..1f79ce590 100644 --- a/modules/memmon.py +++ b/modules/memmon.py @@ -78,7 +78,7 @@ class MemUsageMonitor(threading.Thread): self.data["reserved"] = torch_stats["reserved_bytes.all.current"] self.data["reserved_peak"] = torch_stats["reserved_bytes.all.peak"] self.data["system_peak"] = total - self.data["min_free"] - except: + except Exception: self.disabled = True return self.data diff --git a/modules/memstats.py b/modules/memstats.py index 792d1fdc5..ea3a772f7 100644 --- a/modules/memstats.py +++ b/modules/memstats.py @@ -27,7 +27,7 @@ def memory_stats(): 'oom': s['num_ooms'] }) return mem - except: + except Exception: pass try: gpu = { 'used': gb(torch.xpu.memory_allocated()), 'total': gb(torch.xpu.get_device_properties(shared.device).total_memory) } @@ -40,6 +40,6 @@ def memory_stats(): if s['num_ooms'] > 0: shared.state.oom = True return mem - except: + except Exception: pass return mem diff --git a/modules/modelloader.py b/modules/modelloader.py index aa68b5701..17bb471f8 100644 --- a/modules/modelloader.py +++ b/modules/modelloader.py @@ -79,7 +79,7 @@ def load_models(model_path: str, model_url: str = None, command_path: str = None if os.path.islink(full_path) and not os.path.exists(full_path): print(f"Skipping broken symlink: {full_path}") continue - if ext_blacklist is not None and any([full_path.endswith(x) for x in ext_blacklist]): + if ext_blacklist is not None and any(full_path.endswith(x) for x in ext_blacklist): continue if full_path not in output: output.append(full_path) @@ -147,19 +147,18 @@ def move_files(src_path: str, dest_path: str, ext_filter: str = None): print(f"Moving {file} from {src_path} to {dest_path}.") try: shutil.move(fullpath, dest_path) - except: + except Exception: pass if len(os.listdir(src_path)) == 0: print(f"Removing empty folder: {src_path}") shutil.rmtree(src_path, True) - except: + except Exception: pass def load_upscalers(): - # We can only do this 'magic' method to dynamically load upscalers if they are referenced, - # so we'll try to import any _model.py files before looking in __subclasses__ + # We can only do this 'magic' method to dynamically load upscalers if they are referenced, so we'll try to import any _model.py files before looking in __subclasses__ modules_dir = os.path.join(shared.script_path, "modules") for file in os.listdir(modules_dir): if "_model.py" in file: @@ -167,14 +166,12 @@ def load_upscalers(): full_model = f"modules.{model_name}_model" try: importlib.import_module(full_model) - except: + except Exception: pass datas = [] commandline_options = vars(shared.cmd_opts) - # some of upscaler classes will not go away after reloading their modules, and we'll end - # up with two copies of those classes. The newest copy will always be the last in the list, - # so we go from end to beginning and ignore duplicates + # some of upscaler classes will not go away after reloading their modules, and we'll end up with two copies of those classes. The newest copy will always be the last in the list, so we go from end to beginning and ignore duplicates used_classes = {} for cls in reversed(Upscaler.__subclasses__()): classname = str(cls) diff --git a/modules/models/diffusion/ddpm_edit.py b/modules/models/diffusion/ddpm_edit.py index f880bc3c7..7dc66d15e 100644 --- a/modules/models/diffusion/ddpm_edit.py +++ b/modules/models/diffusion/ddpm_edit.py @@ -52,7 +52,7 @@ class DDPM(pl.LightningModule): beta_schedule="linear", loss_type="l2", ckpt_path=None, - ignore_keys=[], + ignore_keys=None, load_only_unet=False, monitor="val/loss", use_ema=True, @@ -107,7 +107,7 @@ class DDPM(pl.LightningModule): print(f"Keeping EMAs of {len(list(self.model_ema.buffers()))}.") if ckpt_path is not None: - self.init_from_ckpt(ckpt_path, ignore_keys=ignore_keys, only_model=load_only_unet) + self.init_from_ckpt(ckpt_path, ignore_keys=ignore_keys or [], only_model=load_only_unet) # If initialing from EMA-only checkpoint, create EMA model after loading. if self.use_ema and not load_ema: @@ -194,7 +194,8 @@ class DDPM(pl.LightningModule): if context is not None: print(f"{context}: Restored training weights") - def init_from_ckpt(self, path, ignore_keys=list(), only_model=False): + def init_from_ckpt(self, path, ignore_keys=None, only_model=False): + ignore_keys = ignore_keys or [] sd = torch.load(path, map_location="cpu") if "state_dict" in list(sd.keys()): sd = sd["state_dict"] @@ -403,7 +404,7 @@ class DDPM(pl.LightningModule): @torch.no_grad() def log_images(self, batch, N=8, n_row=2, sample=True, return_keys=None, **kwargs): - log = dict() + log = {} x = self.get_input(batch, self.first_stage_key) N = min(x.shape[0], N) n_row = min(x.shape[0], n_row) @@ -411,7 +412,7 @@ class DDPM(pl.LightningModule): log["inputs"] = x # get diffusion row - diffusion_row = list() + diffusion_row = [] x_start = x[:n_row] for t in range(self.num_timesteps): @@ -473,13 +474,13 @@ class LatentDiffusion(DDPM): conditioning_key = None ckpt_path = kwargs.pop("ckpt_path", None) ignore_keys = kwargs.pop("ignore_keys", []) - super().__init__(conditioning_key=conditioning_key, *args, load_ema=load_ema, **kwargs) + super().__init__(*args, conditioning_key=conditioning_key, load_ema=load_ema, **kwargs) self.concat_mode = concat_mode self.cond_stage_trainable = cond_stage_trainable self.cond_stage_key = cond_stage_key try: self.num_downs = len(first_stage_config.params.ddconfig.ch_mult) - 1 - except: + except Exception: self.num_downs = 0 if not scale_by_std: self.scale_factor = scale_factor @@ -891,16 +892,6 @@ class LatentDiffusion(DDPM): c = self.q_sample(x_start=c, t=tc, noise=torch.randn_like(c.float())) return self.p_losses(x, c, t, *args, **kwargs) - def _rescale_annotations(self, bboxes, crop_coordinates): # TODO: move to dataset - def rescale_bbox(bbox): - x0 = clamp((bbox[0] - crop_coordinates[0]) / crop_coordinates[2]) - y0 = clamp((bbox[1] - crop_coordinates[1]) / crop_coordinates[3]) - w = min(bbox[2] / crop_coordinates[2], 1 - x0) - h = min(bbox[3] / crop_coordinates[3], 1 - y0) - return x0, y0, w, h - - return [rescale_bbox(b) for b in bboxes] - def apply_model(self, x_noisy, t, cond, return_ids=False): if isinstance(cond, dict): @@ -1140,7 +1131,7 @@ class LatentDiffusion(DDPM): if cond is not None: if isinstance(cond, dict): cond = {key: cond[key][:batch_size] if not isinstance(cond[key], list) else - list(map(lambda x: x[:batch_size], cond[key])) for key in cond} + [x[:batch_size] for x in cond[key]] for key in cond} else: cond = [c[:batch_size] for c in cond] if isinstance(cond, list) else cond[:batch_size] @@ -1171,8 +1162,10 @@ class LatentDiffusion(DDPM): if i % log_every_t == 0 or i == timesteps - 1: intermediates.append(x0_partial) - if callback: callback(i) - if img_callback: img_callback(img, i) + if callback: + callback(i) + if img_callback: + img_callback(img, i) return img, intermediates @torch.no_grad() @@ -1235,7 +1228,7 @@ class LatentDiffusion(DDPM): if cond is not None: if isinstance(cond, dict): cond = {key: cond[key][:batch_size] if not isinstance(cond[key], list) else - list(map(lambda x: x[:batch_size], cond[key])) for key in cond} + [x[:batch_size] for x in cond[key]] for key in cond} else: cond = [c[:batch_size] for c in cond] if isinstance(cond, list) else cond[:batch_size] return self.p_sample_loop(cond, @@ -1267,7 +1260,7 @@ class LatentDiffusion(DDPM): use_ddim = False - log = dict() + log = {} z, c, x, xrec, xc = self.get_input(batch, self.first_stage_key, return_first_stage_outputs=True, force_c_encode=True, @@ -1337,7 +1330,7 @@ class LatentDiffusion(DDPM): if inpaint: # make a simple center square - b, h, w = z.shape[0], z.shape[2], z.shape[3] + h, w = z.shape[2], z.shape[3] mask = torch.ones(N, h, w).to(self.device) # zeros will be filled in mask[:, h // 4:3 * h // 4, w // 4:3 * w // 4] = 0. @@ -1439,10 +1432,10 @@ class Layout2ImgDiffusion(LatentDiffusion): # TODO: move all layout-specific hacks to this class def __init__(self, cond_stage_key, *args, **kwargs): assert cond_stage_key == 'coordinates_bbox', 'Layout2ImgDiffusion only for cond_stage_key="coordinates_bbox"' - super().__init__(cond_stage_key=cond_stage_key, *args, **kwargs) + super().__init__(*args, cond_stage_key=cond_stage_key, **kwargs) def log_images(self, batch, N=8, *args, **kwargs): - logs = super().log_images(batch=batch, N=N, *args, **kwargs) + logs = super().log_images(*args, batch=batch, N=N, **kwargs) key = 'train' if self.training else 'validation' dset = self.trainer.datamodule.datasets[key] diff --git a/modules/models/diffusion/uni_pc/sampler.py b/modules/models/diffusion/uni_pc/sampler.py index b46848183..7d7a8e641 100644 --- a/modules/models/diffusion/uni_pc/sampler.py +++ b/modules/models/diffusion/uni_pc/sampler.py @@ -147,7 +147,8 @@ class UniPCSampler(object): if conditioning is not None: if isinstance(conditioning, dict): ctmp = conditioning[list(conditioning.keys())[0]] - while isinstance(ctmp, list): ctmp = ctmp[0] + while isinstance(ctmp, list): + ctmp = ctmp[0] cbs = ctmp.shape[0] if cbs != batch_size: print(f"Warning: Got {cbs} conditionings but batch-size is {batch_size}") diff --git a/modules/models/diffusion/uni_pc/uni_pc.py b/modules/models/diffusion/uni_pc/uni_pc.py index 5b10b35ac..433ab07ee 100644 --- a/modules/models/diffusion/uni_pc/uni_pc.py +++ b/modules/models/diffusion/uni_pc/uni_pc.py @@ -181,13 +181,13 @@ def model_wrapper( model, noise_schedule, model_type="noise", - model_kwargs={}, + model_kwargs=None, guidance_type="uncond", #condition=None, #unconditional_condition=None, guidance_scale=1., classifier_fn=None, - classifier_kwargs={}, + classifier_kwargs=None, ): """Create a wrapper function for the noise prediction model. @@ -346,7 +346,7 @@ def model_wrapper( t_in = torch.cat([t_continuous] * 2) if isinstance(condition, dict): assert isinstance(unconditional_condition, dict) - c_in = dict() + c_in = {} for k in condition: if isinstance(condition[k], list): c_in[k] = [torch.cat([ @@ -357,7 +357,7 @@ def model_wrapper( unconditional_condition[k], condition[k]]) elif isinstance(condition, list): - c_in = list() + c_in = [] assert isinstance(unconditional_condition, list) for i in range(len(condition)): c_in.append(torch.cat([unconditional_condition[i], condition[i]])) diff --git a/modules/paths.py b/modules/paths.py index b1bd3ee90..966567563 100644 --- a/modules/paths.py +++ b/modules/paths.py @@ -57,8 +57,7 @@ def create_paths(opts): if not os.path.exists(folder): try: os.makedirs(folder, exist_ok=True) - # print('Creating folder:', folder) - except: + except Exception: pass def fix_path(folder): diff --git a/modules/processing.py b/modules/processing.py index 386ec9985..ab1e4d6a7 100644 --- a/modules/processing.py +++ b/modules/processing.py @@ -471,7 +471,7 @@ def create_infotext(p: StableDiffusionProcessing, all_prompts, all_seeds, all_su def print_profile(profile, msg: str): try: from rich import print # pylint: disable=redefined-builtin - except: + except Exception: pass lines = profile.key_averages().table(sort_by="cuda_time_total", row_limit=20) lines = lines.split('\n') @@ -485,7 +485,7 @@ def print_profile(profile, msg: str): import pstats try: from rich import print # pylint: disable=redefined-builtin - except: + except Exception: pass profile.disable() stream = io.StringIO() @@ -645,7 +645,7 @@ def process_images_inner(p: StableDiffusionProcessing) -> Processed: if not shared.opts.dont_fix_second_order_samplers_schedule: try: step_multiplier = 2 if sd_samplers.all_samplers_map.get(p.sampler_name).aliases[0] in ['k_dpmpp_2s_a', 'k_dpmpp_2s_a_ka', 'k_dpmpp_sde', 'k_dpmpp_sde_ka', 'k_dpm_2', 'k_dpm_2_a', 'k_heun'] else 1 - except: + except Exception: pass if p.n_iter > 1: shared.state.job = f"Batch {n+1} out of {p.n_iter}" diff --git a/modules/prompt_parser.py b/modules/prompt_parser.py index 1aa48754f..25fa779f0 100644 --- a/modules/prompt_parser.py +++ b/modules/prompt_parser.py @@ -102,18 +102,18 @@ def get_learned_conditioning_prompt_schedules(prompts, steps): """ def collect_steps(steps, tree): - l = [steps] + res = [steps] class CollectSteps(lark.Visitor): def scheduled(self, tree): tree.children[-1] = float(tree.children[-1]) if tree.children[-1] < 1: tree.children[-1] *= steps tree.children[-1] = min(steps, int(tree.children[-1])) - l.append(tree.children[-1]) + res.append(tree.children[-1]) def alternate(self, tree): # pylint: disable=unused-argument - l.extend(range(1, steps+1)) + res.extend(range(1, steps+1)) CollectSteps().visit(tree) - return sorted(set(l)) + return sorted(set(res)) def at_step(step, tree): class AtStep(lark.Transformer): @@ -243,12 +243,12 @@ def reconstruct_multicond_batch(c: MulticondLearnedConditioning, current_step): param = c.batch[0][0].schedules[0].cond tensors = [] conds_list = [] - for _batch_no, composable_prompts in enumerate(c.batch): + for composable_prompts in c.batch: conds_for_batch = [] - for _cond_index, composable_prompt in enumerate(composable_prompts): + for composable_prompt in composable_prompts: target_index = 0 - for current, (end_at, _cond) in enumerate(composable_prompt.schedules): - if current_step <= end_at: + for current, entry in enumerate(composable_prompt.schedules): + if current_step <= entry.end_at_step: target_index = current break conds_for_batch.append((len(tensors), composable_prompt.weight)) diff --git a/modules/realesrgan_model.py b/modules/realesrgan_model.py index db05e8b1a..b90ef96a1 100644 --- a/modules/realesrgan_model.py +++ b/modules/realesrgan_model.py @@ -42,7 +42,7 @@ class UpscalerRealESRGAN(Upscaler): try: from realesrgan import RealESRGANer - except: + except Exception: print("Error importing Real-ESRGAN:", file=sys.stderr) return img diff --git a/modules/safe.py b/modules/safe.py index 4cc5a10f5..c68e87aaa 100644 --- a/modules/safe.py +++ b/modules/safe.py @@ -102,7 +102,7 @@ def check_pt(filename, extra_handler): def load(filename, *args, **kwargs): - return load_with_extra(filename, extra_handler=global_extra_handler, *args, **kwargs) + return load_with_extra(filename, *args, extra_handler=global_extra_handler, **kwargs) def load_with_extra(filename, extra_handler=None, *args, **kwargs): # pylint: disable=keyword-arg-before-vararg diff --git a/modules/scripts.py b/modules/scripts.py index 150f3156e..79c1bfc78 100644 --- a/modules/scripts.py +++ b/modules/scripts.py @@ -222,7 +222,7 @@ def load_scripts(): time_load = {} def register_scripts_from_module(module, scriptfile): - for _key, script_class in module.__dict__.items(): + for script_class in module.__dict__.values(): if type(script_class) != type: continue # log.debug(f'Registering script: {scriptfile.path}') @@ -487,7 +487,7 @@ class ScriptRunner: if module is None: module = script_loading.load_module(script.filename) cache[filename] = module - for _key, script_class in module.__dict__.items(): + for script_class in module.__dict__.values(): if type(script_class) == type and issubclass(script_class, Script): self.scripts[si] = script_class() self.scripts[si].filename = filename diff --git a/modules/scripts_auto_postprocessing.py b/modules/scripts_auto_postprocessing.py index bdcffa52c..eda6ee779 100644 --- a/modules/scripts_auto_postprocessing.py +++ b/modules/scripts_auto_postprocessing.py @@ -17,7 +17,7 @@ class ScriptPostprocessingForMainUI(scripts.Script): return self.postprocessing_controls.values() def postprocess_image(self, p, script_pp, *args): # pylint: disable=arguments-differ - args_dict = {k: v for k, v in zip(self.postprocessing_controls, args)} + args_dict = dict(zip(self.postprocessing_controls, args)) pp = scripts_postprocessing.PostprocessedImage(script_pp.image) pp.info = {} diff --git a/modules/sd_hijack_inpainting.py b/modules/sd_hijack_inpainting.py index 02691b705..7b392b4f4 100644 --- a/modules/sd_hijack_inpainting.py +++ b/modules/sd_hijack_inpainting.py @@ -24,7 +24,7 @@ def p_sample_plms(self, x, c, t, index, repeat_noise=False, use_original_steps=F if isinstance(c, dict): assert isinstance(unconditional_conditioning, dict) - c_in = dict() + c_in = {} for k in c: if isinstance(c[k], list): c_in[k] = [ diff --git a/modules/sd_hijack_optimizations.py b/modules/sd_hijack_optimizations.py index 49519ea2a..435aef60e 100644 --- a/modules/sd_hijack_optimizations.py +++ b/modules/sd_hijack_optimizations.py @@ -44,7 +44,7 @@ def get_available_vram(): mem_free_cuda, _ = torch.cuda.mem_get_info(torch.cuda.current_device()) mem_free_torch = mem_reserved - mem_active mem_free_total = mem_free_cuda + mem_free_torch - except: + except Exception: mem_free_total = 1024 * 1024 * 1024 return mem_free_total @@ -206,7 +206,7 @@ def einsum_op_cuda(q, k, v): mem_free_cuda, _ = torch.cuda.mem_get_info(q.device) mem_free_torch = mem_reserved - mem_active mem_free_total = mem_free_cuda + mem_free_torch - except: + except Exception: mem_free_total = 1024 * 1024 * 1024 # Divide factor of safety as there's copying and fragmentation return einsum_op_tensor_mem(q, k, v, mem_free_total / 3.3 / (1 << 20)) @@ -319,7 +319,6 @@ def sub_quad_attention(q, k, v, q_chunk_size=1024, kv_chunk_size=None, kv_chunk_ if chunk_threshold_bytes is not None and qk_matmul_size_bytes <= chunk_threshold_bytes: # the big matmul fits into our memory limit; do everything in 1 chunk, # i.e. send it down the unchunked fast-path - query_chunk_size = q_tokens # pylint: disable=unused-variable kv_chunk_size = k_tokens with devices.without_autocast(disable=q.dtype == v.dtype): diff --git a/modules/sd_models.py b/modules/sd_models.py index aa2d39d5b..e56dbdcba 100644 --- a/modules/sd_models.py +++ b/modules/sd_models.py @@ -2,9 +2,11 @@ import collections import os.path import re import io +import json import threading from os import mkdir from urllib import request +import filelock from rich import progress # pylint: disable=redefined-builtin import torch import safetensors.torch @@ -28,6 +30,7 @@ checkpoints_loaded = collections.OrderedDict() skip_next_load = False sd_metadata_file = os.path.join(paths.data_path, "metadata.json") sd_metadata = None +sd_metadata_pending = 0 class CheckpointInfo: @@ -188,7 +191,7 @@ def model_hash(filename): return m.hexdigest()[0:8] except FileNotFoundError: return 'NOFILE' - except: + except Exception: return 'NOHASH' @@ -237,40 +240,62 @@ def get_state_dict_from_checkpoint(pl_sd): return pl_sd +def write_metadata(): + def default(obj): + shared.log.debug(f"Model metadata not a valid object: {obj}") + return str(obj) + + global sd_metadata_pending # pylint: disable=global-statement + if sd_metadata_pending == 0: + shared.log.debug(f"Model metadata: {sd_metadata_file} no changes") + return + with filelock.FileLock(f"{sd_metadata_file}.lock"): + try: + with open(sd_metadata_file, "w", encoding="utf8") as file: + json.dump(sd_metadata, file, indent=4, skipkeys=True, ensure_ascii=True, check_circular=True, allow_nan=True, default=default) + except Exception as e: + shared.log.error(f"Model metadata save error: {sd_metadata_file} {e}") + shared.log.info(f"Model metadata saved: {sd_metadata_file} {sd_metadata_pending}") + sd_metadata_pending = 0 + + def read_metadata_from_safetensors(filename): - import json global sd_metadata # pylint: disable=global-statement if sd_metadata is None: - if not os.path.isfile(sd_metadata_file): - sd_metadata = {} - else: - try: - with open(sd_metadata_file, "r", encoding="utf8") as file: - sd_metadata = json.load(file) - except: + with filelock.FileLock(f"{sd_metadata_file}.lock"): + if not os.path.isfile(sd_metadata_file): sd_metadata = {} + else: + try: + with open(sd_metadata_file, "r", encoding="utf8") as file: + sd_metadata = json.load(file) + except Exception: + sd_metadata = {} res = sd_metadata.get(filename, None) if res is not None: return res - res = {} - with open(filename, mode="rb") as file: - metadata_len = file.read(8) - metadata_len = int.from_bytes(metadata_len, "little") - json_start = file.read(2) - assert metadata_len > 2 and json_start in (b'{"', b"{'"), f"{filename} is not a safetensors file" - json_data = json_start + file.read(metadata_len-2) - json_obj = json.loads(json_data) - for k, v in json_obj.get("__metadata__", {}).items(): - res[k] = v - if isinstance(v, str) and v[0:1] == '{': - try: - res[k] = json.loads(v) - except Exception: - pass - sd_metadata[filename] = res - with open(sd_metadata_file, "w", encoding="utf8") as file: - json.dump(sd_metadata, file, indent=4) + try: + with open(filename, mode="rb") as file: + metadata_len = file.read(8) + metadata_len = int.from_bytes(metadata_len, "little") + json_start = file.read(2) + if metadata_len <= 2 or json_start not in (b'{"', b"{'"): + shared.log.error(f"Not a valid safetensors file: {filename}") + json_data = json_start + file.read(metadata_len-2) + json_obj = json.loads(json_data) + for k, v in json_obj.get("__metadata__", {}).items(): + res[k] = v + if isinstance(v, str) and v[0:1] == '{': + try: + res[k] = json.loads(v) + except Exception: + pass + sd_metadata[filename] = res + global sd_metadata_pending # pylint: disable=global-statement + sd_metadata_pending += 1 + except Exception as e: + shared.log.error(f"Error reading metadata from: {filename} {e}") return res diff --git a/modules/sd_samplers_kdiffusion.py b/modules/sd_samplers_kdiffusion.py index 43cd9a95c..203880447 100644 --- a/modules/sd_samplers_kdiffusion.py +++ b/modules/sd_samplers_kdiffusion.py @@ -329,7 +329,7 @@ class KDiffusionSampler: if cmd_opts.use_ipex: #Remove this after Intel adds support for torch.Generator() try: return BrownianTreeNoiseSampler(x.to("cpu"), sigma_min, sigma_max, seed=current_iter_seeds, transform=lambda x: x.to("cpu"), transform_last=lambda x: x.to(shared.device)) # pylint: disable=E1123 - except: + except Exception: print("ERROR Please apply this patch to repositories/k-diffusion/k_diffusion/sampling.py: https://github.com/crowsonkb/k-diffusion/pull/68/files") return None else: diff --git a/modules/shared.py b/modules/shared.py index b53f2c5f3..2fd01c172 100644 --- a/modules/shared.py +++ b/modules/shared.py @@ -269,7 +269,7 @@ def refresh_themes(): f.write(json.dumps(res)) else: log.error('Error refreshing UI themes') - except: + except Exception: log.error('Exception refreshing UI themes') @@ -288,6 +288,7 @@ else: # cuda options_templates.update(options_section(('sd', "Stable Diffusion"), { "sd_model_checkpoint": OptionInfo(default_checkpoint, "Stable Diffusion checkpoint", gr.Dropdown, lambda: {"choices": list_checkpoint_tiles()}, refresh=refresh_checkpoints), + "sd_checkpoint_autoload": OptionInfo(True, "Stable Diffusion checkpoint autoload on server start"), "sd_checkpoint_cache": OptionInfo(0, "Number of cached model checkpoints", gr.Slider, {"minimum": 0, "maximum": 10, "step": 1}), "sd_vae_checkpoint_cache": OptionInfo(0, "Number of cached VAE checkpoints", gr.Slider, {"minimum": 0, "maximum": 10, "step": 1}), "sd_vae": OptionInfo("Automatic", "Select VAE", gr.Dropdown, lambda: {"choices": shared_items.sd_vae_items()}, refresh=shared_items.refresh_vae_list), @@ -660,10 +661,10 @@ class Options: """reorder settings so that all items related to section always go together""" section_ids = {} settings_items = self.data_labels.items() - for k, item in settings_items: + for _k, item in settings_items: if item.section not in section_ids: section_ids[item.section] = len(section_ids) - self.data_labels = {k: v for k, v in sorted(settings_items, key=lambda x: section_ids[x[1].section])} + self.data_labels = dict(sorted(settings_items, key=lambda x: section_ids[x[1].section])) def cast_value(self, key, value): """casts an arbitrary to the same type as this setting's value with key @@ -719,7 +720,7 @@ def reload_gradio_theme(theme_name=None): try: req = urllib.request.Request("https://fonts.googleapis.com/css2?family=IBM+Plex+Mono", method="HEAD") res = urllib.request.urlopen(req, timeout=3.0).status - except: + except Exception: res = 0 if res != 200: log.info('No internet access detected, using default fonts') @@ -743,7 +744,7 @@ def reload_gradio_theme(theme_name=None): else: try: gradio_theme = gr.themes.ThemeClass.from_hub(theme_name) - except: + except Exception: log.error("Theme download error accessing HuggingFace") gradio_theme = gr.themes.Default(**default_font_params) log.info(f'Loading UI theme: name={theme_name} style={opts.theme_style}') @@ -794,7 +795,7 @@ def restart_server(restart=True): demo.close(verbose=False) demo.server.close() demo.fns = [] - except: + except Exception: pass if restart: log.info('Server will restart') @@ -804,9 +805,6 @@ def restore_defaults(restart=True): if os.path.exists(cmd_opts.config): log.info('Restoring server defaults') os.remove(cmd_opts.config) - if os.path.exists(cmd_opts.ui_config): - log.info('Restoring UI defaults') - os.remove(cmd_opts.ui_config) restart_server(restart) @@ -859,7 +857,7 @@ def get_version(): 'hash': githash, 'url': origin.replace('\n', '') + '/tree/' + branch.replace('\n', '') } - except: + except Exception: version = { 'app': 'sd.next' } return version diff --git a/modules/styles.py b/modules/styles.py index 74a7d2e96..2bc0053da 100644 --- a/modules/styles.py +++ b/modules/styles.py @@ -56,7 +56,7 @@ class StyleDatabase: prompt = row["prompt"] if "prompt" in row else row["text"] negative_prompt = row.get("negative_prompt", "") self.styles[row["name"]] = PromptStyle(row["name"], prompt, negative_prompt) - except: + except Exception: pass def get_style_prompts(self, styles): diff --git a/modules/sub_quadratic_attention.py b/modules/sub_quadratic_attention.py index bab11d411..206bea8b3 100644 --- a/modules/sub_quadratic_attention.py +++ b/modules/sub_quadratic_attention.py @@ -16,6 +16,7 @@ from typing import Optional, NamedTuple, List import torch from torch import Tensor from torch.utils.checkpoint import checkpoint +import numpy as np def narrow_trunc( @@ -201,13 +202,14 @@ def efficient_dot_product_attention( value=value, ) - # maybe we should use torch.empty_like(query) to allocate storage in-advance, - # and pass slices to be mutated, instead of torch.cat()ing the returned slices - res = torch.cat([ - compute_query_chunk_attn( + res = torch.zeros_like(query) + for i in range(math.ceil(q_tokens / query_chunk_size)): + attn_scores = compute_query_chunk_attn( query=get_query_chunk(i * query_chunk_size), key=key, value=value, - ) for i in range(math.ceil(q_tokens / query_chunk_size)) - ], dim=1) + ) + + res[:, i * query_chunk_size:i * query_chunk_size + attn_scores.shape[1], :] = attn_scores + return res diff --git a/modules/textual_inversion/autocrop.py b/modules/textual_inversion/autocrop.py index 7097ecd36..31abd782d 100644 --- a/modules/textual_inversion/autocrop.py +++ b/modules/textual_inversion/autocrop.py @@ -183,7 +183,7 @@ def image_face_points(im, settings): try: faces = classifier.detectMultiScale(gray, scaleFactor=1.1, minNeighbors=7, minSize=(minsize, minsize), flags=cv2.CASCADE_SCALE_IMAGE) - except: + except Exception: continue if len(faces) > 0: diff --git a/modules/textual_inversion/image_embedding.py b/modules/textual_inversion/image_embedding.py index d4bf8d872..7ef9b0d68 100644 --- a/modules/textual_inversion/image_embedding.py +++ b/modules/textual_inversion/image_embedding.py @@ -16,7 +16,7 @@ class EmbeddingEncoder(json.JSONEncoder): class EmbeddingDecoder(json.JSONDecoder): def __init__(self, *args, **kwargs): - json.JSONDecoder.__init__(self, object_hook=self.object_hook, *args, **kwargs) + json.JSONDecoder.__init__(self, *args, object_hook=self.object_hook, **kwargs) def object_hook(self, d): if 'TORCHTENSOR' in d: diff --git a/modules/textual_inversion/learn_schedule.py b/modules/textual_inversion/learn_schedule.py index 5938a7ebb..e1a7f3db6 100644 --- a/modules/textual_inversion/learn_schedule.py +++ b/modules/textual_inversion/learn_schedule.py @@ -1,6 +1,3 @@ -import tqdm - - class LearnScheduleIterator: def __init__(self, learn_rate, max_steps, cur_step=0): """ @@ -12,7 +9,7 @@ class LearnScheduleIterator: self.it = 0 self.maxit = 0 try: - for i, pair in enumerate(pairs): + for pair in pairs: if not pair.strip(): continue tmp = pair.split(':') @@ -32,8 +29,8 @@ class LearnScheduleIterator: self.maxit += 1 return assert self.rates - except (ValueError, AssertionError): - raise Exception('Invalid learning rate schedule. It should be a number or, for example, like "0.001:100, 0.00001:1000, 1e-5:10000" to have lr of 0.001 until step 100, 0.00001 until 1000, and 1e-5 until 10000.') + except (ValueError, AssertionError) as e: + raise Exception('Invalid learning rate schedule. It should be a number or, for example, like "0.001:100, 0.00001:1000, 1e-5:10000" to have lr of 0.001 until step 100, 0.00001 until 1000, and 1e-5 until 10000.') from e def __iter__(self): diff --git a/modules/textual_inversion/textual_inversion.py b/modules/textual_inversion/textual_inversion.py index 9f9b68c7d..253f396e1 100644 --- a/modules/textual_inversion/textual_inversion.py +++ b/modules/textual_inversion/textual_inversion.py @@ -210,7 +210,7 @@ class EmbeddingDatabase: return if not force_reload: need_reload = False - for _path, embdir in self.embedding_dirs.items(): + for embdir in self.embedding_dirs.values(): if embdir.has_changed(): need_reload = True break @@ -223,7 +223,7 @@ class EmbeddingDatabase: self.skipped_embeddings.clear() self.expected_shape = self.get_expected_shape() - for _path, embdir in self.embedding_dirs.items(): + for embdir in self.embedding_dirs.values(): self.load_from_dir(embdir) embdir.update() @@ -620,7 +620,7 @@ def save_embedding(embedding, optimizer, checkpoint, embedding_name, filename, r embedding.name = embedding_name embedding.optimizer_state_dict = optimizer.state_dict() embedding.save(filename) - except: + except Exception: embedding.sd_checkpoint = old_sd_checkpoint embedding.sd_checkpoint_name = old_sd_checkpoint_name embedding.name = old_embedding_name diff --git a/modules/txt2img.py b/modules/txt2img.py index 7a55da30c..25ff30fde 100644 --- a/modules/txt2img.py +++ b/modules/txt2img.py @@ -1,8 +1,6 @@ import modules.scripts -from modules import sd_samplers, shared +from modules import sd_samplers, shared, processing from modules.generation_parameters_copypaste import create_override_settings_dict -from modules.processing import StableDiffusionProcessingTxt2Img, process_images -# from modules.shared import opts, sd_model, debug from modules.ui import plaintext_to_html, infotext_to_html from modules.memstats import memory_stats @@ -19,7 +17,7 @@ def txt2img(id_task: str, prompt: str, negative_prompt: str, prompt_styles, step shared.log.warning('Model not loaded') return - p = StableDiffusionProcessingTxt2Img( + p = processing.StableDiffusionProcessingTxt2Img( sd_model=shared.sd_model, outpath_samples=shared.opts.outdir_samples or shared.opts.outdir_txt2img_samples, outpath_grids=shared.opts.outdir_grids or shared.opts.outdir_txt2img_grids, @@ -55,7 +53,7 @@ def txt2img(id_task: str, prompt: str, negative_prompt: str, prompt_styles, step p.script_args = args processed = modules.scripts.scripts_txt2img.run(p, *args) if processed is None: - processed = process_images(p) + processed = processing.process_images(p) p.close() generation_info_js = processed.js() shared.log.debug(f'Processed: {len(processed.images)} Memory: {memory_stats()} txt') diff --git a/modules/ui.py b/modules/ui.py index e89815379..fbfb1d642 100644 --- a/modules/ui.py +++ b/modules/ui.py @@ -10,7 +10,7 @@ import numpy as np from PIL import Image from modules.call_queue import wrap_gradio_gpu_call, wrap_queued_call, wrap_gradio_call -from modules import sd_hijack, sd_models, script_callbacks, ui_extensions, deepbooru, sd_vae, extra_networks, ui_common, ui_postprocessing +from modules import sd_hijack, sd_models, script_callbacks, ui_extensions, deepbooru, sd_vae, extra_networks, ui_common, ui_postprocessing, ui_loadsave from modules.ui_components import FormRow, FormColumn, FormGroup, ToolButton, FormHTML # pylint: disable=unused-import from modules.paths import script_path, data_path from modules.shared import opts, cmd_opts, backend, Backend @@ -73,17 +73,6 @@ def send_gradio_gallery_to_image(x): return parameters_copypaste.image_from_url_text(x[0]) -def visit(x, func, path=""): - if hasattr(x, 'children'): - if isinstance(x, gr.Tabs) and x.elem_id is not None: - # Tabs element can't have a label, have to use elem_id instead - func(f"{path}/Tabs@{x.elem_id}", x) - for c in x.children: - visit(c, func, path) - elif x.label is not None: - func(f"{path}/{x.label}", x) - - def add_style(name: str, prompt: str, negative_prompt: str): if name is None: return [gr_show() for x in range(4)] @@ -599,7 +588,6 @@ def create_ui(): img2img_batch_inpaint_mask_dir = gr.Textbox(label="Inpaint batch mask directory", **modules.shared.hide_dirs, elem_id="img2img_batch_inpaint_mask_dir") img2img_tabs = [tab_img2img, tab_sketch, tab_inpaint, tab_inpaint_color, tab_inpaint_upload, tab_batch] - img2img_image_inputs = [init_img, sketch, init_img_with_mask, inpaint_color_sketch] # pylint: disable=unused-variable for i, tab in enumerate(img2img_tabs): tab.select(fn=lambda tabnum=i: tabnum, inputs=[], outputs=[img2img_selected_tab]) @@ -900,7 +888,7 @@ def create_ui(): with gr.Blocks(analytics_enabled=False) as train_interface: with gr.Column(elem_id='ti_train_container'): with gr.Tabs(elem_id="train_tabs"): - with gr.Tab(label="Merge models") as modelmerger_interface: + with gr.Tab(label="Merge models"): with gr.Row().style(equal_height=False): with gr.Column(variant='compact'): with FormRow(elem_id="modelmerger_models"): @@ -1040,7 +1028,7 @@ def create_ui(): ) def get_textual_inversion_template_names(): - return sorted([x for x in textual_inversion.textual_inversion_templates]) + return sorted(textual_inversion.textual_inversion_templates) with gr.Tab(label="Train", id="train"): gr.HTML(value="

Train an embedding or Hypernetwork; you must specify a directory with a set of 1:1 ratio images

") @@ -1100,8 +1088,8 @@ def create_ui(): with gr.Column(elem_id='ti_gallery_container'): ti_output = gr.Text(elem_id="ti_output", value="", show_label=False) - _ti_gallery = gr.Gallery(label='Output', show_label=False, elem_id='ti_gallery').style(columns=4) - _ti_progress = gr.HTML(elem_id="ti_progress", value="") + gr.Gallery(label='Output', show_label=False, elem_id='ti_gallery').style(columns=4) + gr.HTML(elem_id="ti_progress", value="") ti_outcome = gr.HTML(elem_id="ti_error", value="") create_embedding.click( @@ -1316,6 +1304,7 @@ def create_ui(): indicator.click(fn=get_opt_values, outputs=elements_to_reset, show_progress=False) return indicator + loadsave = ui_loadsave.UiLoadsave(cmd_opts.ui_config) components = [] component_dict = {} modules.shared.settings_components = component_dict @@ -1402,6 +1391,9 @@ def create_ui(): current_tab.__exit__() request_notifications = gr.Button(value='Request browser notifications', elem_id="request_notifications", visible=False) + with gr.TabItem("User interface defaults", id="defaults", elem_id="settings_tab_defaults"): + loadsave.create_ui() + create_dirty_indicator("tab_defaults", [], interactive=False) with gr.TabItem("Licenses", id="licenses", elem_id="settings_tab_licenses"): gr.HTML(modules.shared.html("licenses.html"), elem_id="licenses") create_dirty_indicator("tab_licenses", [], interactive=False) @@ -1472,7 +1464,12 @@ def create_ui(): continue with gr.TabItem(label, id=ifid, elem_id=f"tab_{ifid}"): interface.render() - + for interface, _label, ifid in interfaces: + if ifid in ["extensions", "settings"]: + continue + loadsave.add_block(interface, ifid) + loadsave.add_component(f"webui/Tabs@{tabs.elem_id}", tabs) + loadsave.setup_ui() if opts.notification_audio_enable and os.path.exists(os.path.join(script_path, opts.notification_audio_path)): gr.Audio(interactive=False, value=os.path.join(script_path, opts.notification_audio_path), elem_id="audio_notification", visible=False) @@ -1561,95 +1558,9 @@ def create_ui(): ) model_checkhash.click(fn=sd_models.update_model_hashes, inputs=[], outputs=[modelmerger_result]) - ui_config_file = cmd_opts.ui_config - ui_settings = {} - settings_count = len(ui_settings) - error_loading = False - - try: - if os.path.exists(ui_config_file): - with open(ui_config_file, "r", encoding="utf8") as file: - ui_settings = json.load(file) - except Exception as e: - error_loading = True - modules.errors.display(e, 'loading ui settings') - - def loadsave(path, x): - def apply_field(obj, field, condition=None, init_field=None): - key = f"{path}/{field}" - - if getattr(obj, 'custom_script_source', None) is not None: - key = f"customscript/{obj.custom_script_source}/{key}" - - if getattr(obj, 'do_not_save_to_config', False): - return - - saved_value = ui_settings.get(key, None) - if saved_value is None: - ui_settings[key] = getattr(obj, field) - elif condition and not condition(saved_value): - pass - else: - setattr(obj, field, saved_value) - if init_field is not None: - init_field(saved_value) - - if type(x) in [gr.Slider, gr.Radio, gr.Checkbox, gr.Textbox, gr.Number, gr.Dropdown, ToolButton] and x.visible: - apply_field(x, 'visible') - - if type(x) == gr.Slider: - apply_field(x, 'value') - apply_field(x, 'minimum') - apply_field(x, 'maximum') - apply_field(x, 'step') - - if type(x) == gr.Radio: - apply_field(x, 'value', lambda val: val in x.choices) - - if type(x) == gr.Checkbox: - apply_field(x, 'value') - - if type(x) == gr.Textbox: - apply_field(x, 'value') - - if type(x) == gr.Number: - apply_field(x, 'value') - - if type(x) == gr.Dropdown: - def check_dropdown(val): - if getattr(x, 'multiselect', False): - return all([value in x.choices for value in val]) - else: - return val in x.choices - - apply_field(x, 'value', check_dropdown, getattr(x, 'init_field', None)) - - def check_tab_id(tab_id): - tab_items = list(filter(lambda e: isinstance(e, gr.TabItem), x.children)) - if type(tab_id) == str: - tab_ids = [t.id for t in tab_items] - return tab_id in tab_ids - elif type(tab_id) == int: - return tab_id >= 0 and tab_id < len(tab_items) - else: - return False - - if type(x) == gr.Tabs: - apply_field(x, 'selected', check_tab_id) - - visit(txt2img_interface, loadsave, "txt2img") - visit(img2img_interface, loadsave, "img2img") - visit(extras_interface, loadsave, "extras") - visit(modelmerger_interface, loadsave, "modelmerger") - visit(train_interface, loadsave, "train") - loadsave(f"webui/Tabs@{tabs.elem_id}", tabs) - - if not error_loading and (not os.path.exists(ui_config_file) or settings_count != len(ui_settings)): - with open(ui_config_file, "w", encoding="utf8") as file: - json.dump(ui_settings, file, indent=4) - - # Required as a workaround for change() event not triggering when loading values from ui-config.json - interp_description.value = update_interp_description(interp_method.value) + loadsave.dump_defaults() + demo.ui_loadsave = loadsave + interp_description.value = update_interp_description(interp_method.value) # Required as a workaround for change() event not triggering when loading values from ui-config.json return demo diff --git a/modules/ui_extensions.py b/modules/ui_extensions.py index f2fe6edd4..99c25daa5 100644 --- a/modules/ui_extensions.py +++ b/modules/ui_extensions.py @@ -34,7 +34,7 @@ def update_extension_list(): with open(os.path.join(paths.script_path, "html", "extensions.json"), "r", encoding="utf-8") as f: extensions_list = json.loads(f.read()) shared.log.debug(f'Extensions list loaded: {os.path.join(paths.script_path, "html", "extensions.json")}') - except: + except Exception: shared.log.debug(f'Extensions list failed to load: {os.path.join(paths.script_path, "html", "extensions.json")}') found = [] for ext in extensions.extensions: diff --git a/modules/ui_extra_networks.py b/modules/ui_extra_networks.py index 5119f2301..d75077222 100644 --- a/modules/ui_extra_networks.py +++ b/modules/ui_extra_networks.py @@ -23,7 +23,7 @@ def register_page(page): def fetch_file(filename: str = ""): from starlette.responses import FileResponse, JSONResponse - if not any([Path(x).absolute() in Path(filename).absolute().parents for x in allowed_dirs]): + if not any(Path(x).absolute() in Path(filename).absolute().parents for x in allowed_dirs): return JSONResponse({"error": f"File cannot be fetched: {filename}. Must be in one of directories registered by extra pages."}) if os.path.splitext(filename)[1].lower() not in (".png", ".jpg", ".webp"): return JSONResponse({"error": f"File cannot be fetched: {filename}. Only png and jpg and webp."}) @@ -284,7 +284,7 @@ def setup_ui(ui, gallery): image = image_from_url_text(img_info) is_allowed = False for extra_page in ui.stored_extra_pages: - if any([path_is_parent(x, filename) for x in extra_page.allowed_directories_for_previews()]): + if any(path_is_parent(x, filename) for x in extra_page.allowed_directories_for_previews()): is_allowed = True break assert is_allowed, f'writing to {filename} is not allowed' diff --git a/modules/ui_loadsave.py b/modules/ui_loadsave.py new file mode 100644 index 000000000..78ff6ccaa --- /dev/null +++ b/modules/ui_loadsave.py @@ -0,0 +1,176 @@ +import json +import os + +import gradio as gr + +from modules import errors +from modules.ui_components import ToolButton + + +class UiLoadsave: + """allows saving and restorig default values for gradio components""" + + def __init__(self, filename): + self.filename = filename + self.ui_settings = {} + self.component_mapping = {} + self.error_loading = False + self.finalized_ui = False + self.ui_defaults_view = None + self.ui_defaults_apply = None + self.ui_defaults_review = None + self.ui_defaults_restore = None + try: + if os.path.exists(self.filename): + self.ui_settings = self.read_from_file() + except Exception as e: + self.error_loading = True + errors.display(e, "loading settings") + + def add_component(self, path, x): + """adds component to the registry of tracked components""" + assert not self.finalized_ui + def apply_field(obj, field, condition=None, init_field=None): + key = f"{path}/{field}" + if getattr(obj, 'custom_script_source', None) is not None: + key = f"customscript/{obj.custom_script_source}/{key}" + if getattr(obj, 'do_not_save_to_config', False): + return + saved_value = self.ui_settings.get(key, None) + if saved_value is None: + self.ui_settings[key] = getattr(obj, field) + elif condition and not condition(saved_value): + pass + else: + setattr(obj, field, saved_value) + if init_field is not None: + init_field(saved_value) + if field == 'value' and key not in self.component_mapping: + self.component_mapping[key] = x + if type(x) in [gr.Slider, gr.Radio, gr.Checkbox, gr.Textbox, gr.Number, gr.Dropdown, ToolButton, gr.Button] and x.visible: + apply_field(x, 'visible') + if type(x) == gr.Slider: + apply_field(x, 'value') + apply_field(x, 'minimum') + apply_field(x, 'maximum') + apply_field(x, 'step') + if type(x) == gr.Radio: + apply_field(x, 'value', lambda val: val in x.choices) + if type(x) == gr.Checkbox: + apply_field(x, 'value') + if type(x) == gr.Textbox: + apply_field(x, 'value') + if type(x) == gr.Number: + apply_field(x, 'value') + if type(x) == gr.Dropdown: + def check_dropdown(val): + if getattr(x, 'multiselect', False): + return all(value in x.choices for value in val) + else: + return val in x.choices + apply_field(x, 'value', check_dropdown, getattr(x, 'init_field', None)) + + def check_tab_id(tab_id): + tab_items = list(filter(lambda e: isinstance(e, gr.TabItem), x.children)) + if type(tab_id) == str: + tab_ids = [t.id for t in tab_items] + return tab_id in tab_ids + elif type(tab_id) == int: + return 0 <= tab_id < len(tab_items) + else: + return False + + if type(x) == gr.Tabs: + apply_field(x, 'selected', check_tab_id) + + def add_block(self, x, path=""): + """adds all components inside a gradio block x to the registry of tracked components""" + if hasattr(x, 'children'): + if isinstance(x, gr.Tabs) and x.elem_id is not None: + # Tabs element can't have a label, have to use elem_id instead + self.add_component(f"{path}/Tabs@{x.elem_id}", x) + for c in x.children: + self.add_block(c, path) + elif x.label is not None: + self.add_component(f"{path}/{x.label}", x) + elif isinstance(x, gr.Button) and x.value is not None: + self.add_component(f"{path}/{x.value}", x) + + def read_from_file(self): + with open(self.filename, "r", encoding="utf8") as file: + return json.load(file) + + def write_to_file(self, current_ui_settings): + with open(self.filename, "w", encoding="utf8") as file: + json.dump(current_ui_settings, file, indent=4) + + def dump_defaults(self): + """saves default values to a file unless tjhe file is present and there was an error loading default values at start""" + if self.error_loading and os.path.exists(self.filename): + return + self.write_to_file(self.ui_settings) + + def iter_changes(self, current_ui_settings, values): + """ + given a dictionary with defaults from a file and current values from gradio elements, returns + an iterator over tuples of values that are not the same between the file and the current; + tuple contents are: path, old value, new value + """ + for (path, component), new_value in zip(self.component_mapping.items(), values): + old_value = current_ui_settings.get(path) + choices = getattr(component, 'choices', None) + if isinstance(new_value, int) and choices: + if new_value >= len(choices): + continue + new_value = choices[new_value] + if new_value == old_value: + continue + if old_value is None and new_value == '' or new_value == []: + continue + yield path, old_value, new_value + + def ui_view(self, *values): + text = [""] + for path, old_value, new_value in self.iter_changes(self.read_from_file(), values): + if old_value is None: + old_value = "None" + text.append(f"") + if len(text) == 1: + text.append("") + text.append("") + return "".join(text) + + def ui_apply(self, *values): + num_changed = 0 + current_ui_settings = self.read_from_file() + for path, _, new_value in self.iter_changes(current_ui_settings.copy(), values): + num_changed += 1 + current_ui_settings[path] = new_value + if num_changed == 0: + return "No changes" + self.write_to_file(current_ui_settings) + errors.log.info(f'UI defaults saved: {self.filename}') + return f"Wrote {num_changed} changes" + + def ui_restore(self): + if os.path.exists(self.filename): + os.remove(self.filename) + errors.log.info(f'UI defaults reset: {self.filename}') + return "Restored system defaults for user interface" + + def create_ui(self): + """creates ui elements for editing defaults UI, without adding any logic to them""" + gr.HTML(f"Review changed values and apply them as new user interface defaults
Config file: {self.filename}") + with gr.Row(): + self.ui_defaults_view = gr.Button(value='View changes', elem_id="ui_defaults_view", variant="secondary") + self.ui_defaults_apply = gr.Button(value='Set new defaults', elem_id="ui_defaults_apply", variant="primary") + self.ui_defaults_restore = gr.Button(value='Restore system defaults', elem_id="ui_defaults_restore", variant="primary") + self.ui_defaults_review = gr.HTML("") + + def setup_ui(self): + """adds logic to elements created with create_ui; all add_block class must be made before this""" + assert not self.finalized_ui + self.finalized_ui = True + self.ui_defaults_view.click(fn=self.ui_view, inputs=list(self.component_mapping.values()), outputs=[self.ui_defaults_review]) + self.ui_defaults_apply.click(fn=self.ui_apply, inputs=list(self.component_mapping.values()), outputs=[self.ui_defaults_review]) + self.ui_defaults_restore.click(fn=self.ui_restore, inputs=[], outputs=[self.ui_defaults_review]) diff --git a/modules/ui_postprocessing.py b/modules/ui_postprocessing.py index 208cffe43..d4e0b342e 100644 --- a/modules/ui_postprocessing.py +++ b/modules/ui_postprocessing.py @@ -1,6 +1,6 @@ import json import gradio as gr -from modules import scripts_postprocessing, scripts, shared, gfpgan_model, codeformer_model, ui_common, postprocessing, call_queue # pylint: disable=unused-import +from modules import scripts, shared, ui_common, postprocessing, call_queue import modules.generation_parameters_copypaste as parameters_copypaste from modules.call_queue import wrap_gradio_gpu_call, wrap_queued_call, wrap_gradio_call # pylint: disable=unused-import from modules.extras import run_pnginfo diff --git a/modules/ui_tempdir.py b/modules/ui_tempdir.py index f8d80d63e..945a004b6 100644 --- a/modules/ui_tempdir.py +++ b/modules/ui_tempdir.py @@ -18,7 +18,7 @@ def register_tmp_file(gradio, filename): def check_tmp_file(gradio, filename): ok = False if hasattr(gradio, 'temp_file_sets'): - ok = ok or any([filename in fileset for fileset in gradio.temp_file_sets]) + ok = ok or any(filename in fileset for fileset in gradio.temp_file_sets) if shared.opts.outdir_samples != '': ok = ok or Path(shared.opts.outdir_samples).resolve() in Path(filename).resolve().parents else: diff --git a/modules/xlmr.py b/modules/xlmr.py index 146b0a2e6..fc9093bc0 100644 --- a/modules/xlmr.py +++ b/modules/xlmr.py @@ -1,7 +1,7 @@ from typing import Optional import torch import torch.nn as nn -from transformers import XLMRobertaModel,XLMRobertaTokenizer, BertPreTrainedModel, BertModel, BertConfig # pylint: disable=unused-import +from transformers import XLMRobertaModel,XLMRobertaTokenizer, BertPreTrainedModel, BertConfig from transformers.models.xlm_roberta.configuration_xlm_roberta import XLMRobertaConfig class BertSeriesConfig(BertConfig): diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 000000000..7fdb6e960 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,40 @@ +[tool.ruff] + +target-version = "py39" + +extend-select = [ + "B", + "C", + "I", + "W", +] + +exclude = [ + "extensions", + "extensions-disabled", + "extensions-builtin", + "modules/lora", + "modules/lycoris", + "modules/dml", +] + +ignore = [ + "C408", # Rewrite as a literal + "C901", # Function is too complex + "E501", # Line too long + "E731", # Do not assign a `lambda` expression, use a `def` + "I001", # Import block is un-sorted or un-formatted + "W605", # invalid escape sequence, messes with some docstrings + "E402", # Module level import not at top of file + "F401", # Imported but unused +] + +[tool.ruff.per-file-ignores] +"webui.py" = ["E402"] # Module level import not at top of file + +[tool.ruff.flake8-bugbear] +# Allow default arguments like, e.g., `data: List[str] = fastapi.Query(None)`. +extend-immutable-calls = ["fastapi.Depends", "fastapi.security.HTTPBasic"] + +[tool.pytest.ini_options] +base_url = "http://127.0.0.1:7860" diff --git a/requirements.txt b/requirements.txt index a0184f3d9..37cd496a4 100644 --- a/requirements.txt +++ b/requirements.txt @@ -11,8 +11,6 @@ easydev extcolors facexlib filetype -font-roboto -fonts future gdown gfpgan @@ -47,7 +45,7 @@ basicsr compel requests==2.31.0 tqdm==4.65.0 -accelerate==0.18.0 +accelerate==0.20.3 opencv-python==4.7.0.72 diffusers==0.16.1 einops==0.4.1 diff --git a/scripts/prompts_from_file.py b/scripts/prompts_from_file.py index 05fef64cc..11cd8c2bc 100644 --- a/scripts/prompts_from_file.py +++ b/scripts/prompts_from_file.py @@ -149,7 +149,7 @@ class Script(scripts.Script): images = [] all_prompts = [] infotexts = [] - for n, args in enumerate(jobs): + for args in jobs: state.job = f"{state.job_no + 1} out of {state.job_count}" copy_p = copy.copy(p) diff --git a/scripts/xyz_grid.py b/scripts/xyz_grid.py index 0c145a1b1..a1a2b2404 100644 --- a/scripts/xyz_grid.py +++ b/scripts/xyz_grid.py @@ -319,7 +319,6 @@ def draw_xyz_grid(p, xs, ys, zs, x_labels, y_labels, z_labels, cell, draw_legend return Processed(p, []) z_count = len(zs) - # sub_grids = [None] * z_count for i in range(z_count): start_index = (i * len(xs) * len(ys)) + i end_index = start_index + len(xs) * len(ys) diff --git a/webui.py b/webui.py index 1771c5f74..9c7b23a2a 100644 --- a/webui.py +++ b/webui.py @@ -15,7 +15,7 @@ errors.log.debug('Loading Torch') import torch # pylint: disable=C0411 try: import intel_extension_for_pytorch as ipex # pylint: disable=import-error, unused-import -except: +except Exception: pass import torchvision # pylint: disable=W0611,C0411 import pytorch_lightning # pytorch_lightning should be imported after torch, but it re-enables warnings on import so import once to disable them # pylint: disable=W0611,C0411 @@ -153,18 +153,12 @@ def initialize(): def load_model(): shared.state.begin() shared.state.job = 'load model' - Thread(target=lambda: shared.sd_model).start() - # TODO delay load model - """ - if shared.sd_model is None: - log.warning("No stable diffusion model loaded") - # exit(1) - else: - shared.opts.data["sd_model_checkpoint"] = shared.sd_model.sd_checkpoint_info.title - """ + thread = Thread(target=lambda: shared.sd_model) + thread.start() shared.opts.onchange("sd_model_checkpoint", wrap_queued_call(lambda: modules.sd_models.reload_model_weights()), call=False) shared.opts.onchange("sd_model_dict", wrap_queued_call(lambda: modules.sd_models.reload_model_weights()), call=False) shared.state.end() + thread.join() startup_timer.record("checkpoint") @@ -284,7 +278,7 @@ def start_ui(): setup_middleware(app, cmd_opts) if cmd_opts.subpath: - _mounted_app = gradio.mount_gradio_app(app, shared.demo, path=f"/{cmd_opts.subpath}") + gradio.mount_gradio_app(app, shared.demo, path=f"/{cmd_opts.subpath}") shared.log.info(f'Redirector mounted: /{cmd_opts.subpath}') startup_timer.record("launch") @@ -305,7 +299,12 @@ def start_ui(): def webui(): start_common() start_ui() - load_model() + modules.sd_models.write_metadata() + if opts.sd_checkpoint_autoload: + load_model() + else: + log.debug('Model auto load disabled') + log.info(f"Startup time: {startup_timer.summary()}") # override all loggers to use the same handlers as the main logger @@ -329,6 +328,7 @@ def api_only(): api = create_api(app) api.wants_restart = False modules.script_callbacks.app_started_callback(None, app) + modules.sd_models.write_metadata() log.info(f"Startup time: {startup_timer.summary()}") api.launch(server_name="0.0.0.0" if cmd_opts.listen else "127.0.0.1", port=cmd_opts.port if cmd_opts.port else 7861) return api diff --git a/wiki b/wiki index 383fa467c..34913c882 160000 --- a/wiki +++ b/wiki @@ -1 +1 @@ -Subproject commit 383fa467c3caf63b4dc3d6c88126dd0b855bba8d +Subproject commit 34913c88242c82302424651f6e44414276886017
PathOld valueNew value
{path}{old_value}{new_value}
No changes