From 9f95fcc46e8351cb339df626f37f838bd7d0472a Mon Sep 17 00:00:00 2001 From: Vladimir Mandic Date: Wed, 1 Jan 2025 09:49:08 -0500 Subject: [PATCH] first update in 2025 Signed-off-by: Vladimir Mandic --- CHANGELOG.md | 15 +++++++++++++++ installer.py | 13 +++++++------ modules/cmd_args.py | 2 -- modules/postprocess/yolo.py | 30 +++++++++++++++++------------- modules/progress.py | 2 ++ modules/sd_models.py | 17 ++++++++++++----- modules/shared.py | 1 + modules/timer.py | 20 +++++++++++++++----- modules/ui_control.py | 2 +- webui.py | 2 +- wiki | 2 +- 11 files changed, 72 insertions(+), 34 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b383a90c0..a8040f096 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,20 @@ # Change Log for SD.Next +## Update for 2025-01-01 + +- **Logging**: + - reverted enable debug by default + - updated [debug wiki](https://github.com/vladmandic/automatic/wiki/debug) + - sort logged timers by duration + - allow min duration env variable for timers: `SD_MIN_TIMER=0.1` (default) + - update installer messages +- **Detailer**: + - add explicit detailer steps setting +- **Fixes**: + - explict clear caches on model load + - lock adetailer commit: `#a89c01d` + - xyzgrid fix progress calculation + ## Update for 2024-12-31 NYE refresh release with quite a few optimizatios and bug fixes... diff --git a/installer.py b/installer.py index de76ce17e..11e7f1d94 100644 --- a/installer.py +++ b/installer.py @@ -54,7 +54,7 @@ class Dot(dict): # dot notation access to dictionary attributes diffusers_commit = "unknown" extensions_commit = { 'sd-webui-controlnet': 'ecd33eb', - # 'adetailer': 'a89c01d' + 'adetailer': 'a89c01d' # 'stable-diffusion-webui-images-browser': '27fe4a7', } @@ -230,16 +230,16 @@ def installed(package, friendly: str = None, reload = False, quiet = False): exact = pkg_version == p[1] if not exact and not quiet: if args.experimental: - log.warning(f"Package: {p[0]} installed={pkg_version} required={p[1]} allowing experimental") + log.warning(f'Install: package="{p[0]}" installed={pkg_version} required={p[1]} allowing experimental') else: - log.warning(f"Package: {p[0]} installed={pkg_version} required={p[1]} version mismatch") + log.warning(f'Install: package="{p[0]}" installed={pkg_version} required={p[1]} version mismatch') ok = ok and (exact or args.experimental) else: if not quiet: - log.debug(f"Package: {p[0]} not found") + log.debug(f'Install: package="{p[0]}" install required') return ok except Exception as e: - log.error(f"Package: {pkgs} {e}") + log.error(f'Install: package="{pkgs}" {e}') return False @@ -1342,9 +1342,10 @@ def add_args(parser): group_log = parser.add_argument_group('Logging') group_log.add_argument("--log", type=str, default=os.environ.get("SD_LOG", None), help="Set log file, default: %(default)s") - # group_log.add_argument('--debug', default=os.environ.get("SD_DEBUG",False), action='store_true', help="Run installer with debug logging, default: %(default)s") + group_log.add_argument('--debug', default=os.environ.get("SD_DEBUG",False), action='store_true', help="Run installer with debug logging, default: %(default)s") group_log.add_argument("--profile", default=os.environ.get("SD_PROFILE", False), action='store_true', help="Run profiler, default: %(default)s") group_log.add_argument('--docs', default=os.environ.get("SD_DOCS", False), action='store_true', help="Mount API docs, default: %(default)s") + group_log.add_argument("--api-log", default=os.environ.get("SD_APILOG", True), action='store_true', help="Log all API requests") def parse_args(parser): diff --git a/modules/cmd_args.py b/modules/cmd_args.py index 9fb5a3fb7..018d802ee 100644 --- a/modules/cmd_args.py +++ b/modules/cmd_args.py @@ -74,9 +74,7 @@ def compatibility_args(): group_compat.add_argument("--disable-extension-access", default=False, action='store_true', help=argparse.SUPPRESS) group_compat.add_argument("--api", action='store_true', help=argparse.SUPPRESS, default=True) group_compat.add_argument("--api-auth", type=str, help=argparse.SUPPRESS, default=None) - group_compat.add_argument("--api-log", default=os.environ.get("SD_APILOG", True), action='store_true', help=argparse.SUPPRESS) group_compat.add_argument("--disable-queue", default=os.environ.get("SD_DISABLEQUEUE", False), action='store_true', help=argparse.SUPPRESS) - group_compat.add_argument('--debug', default=os.environ.get("SD_DEBUG", True), action='store_true', help=argparse.SUPPRESS) diff --git a/modules/postprocess/yolo.py b/modules/postprocess/yolo.py index caa711651..3ee2406d1 100644 --- a/modules/postprocess/yolo.py +++ b/modules/postprocess/yolo.py @@ -231,7 +231,7 @@ def restore(self, np_image, p: processing.StableDiffusionProcessing = None): 'negative_prompt': negative, 'denoising_strength': shared.opts.detailer_strength, 'sampler_name': orig_p.get('hr_sampler_name', 'default'), - 'steps': orig_p.get('refiner_steps', 0), + 'steps': shared.opts.detailer_steps, 'styles': [], 'inpaint_full_res': True, 'inpainting_mask_invert': 0, @@ -308,7 +308,7 @@ def restore(self, np_image, p: processing.StableDiffusionProcessing = None): return np_image def ui(self, tab: str): - def ui_settings_change(detailers, classes, strength, padding, blur, min_confidence, max_detected, min_size, max_size, iou): + def ui_settings_change(detailers, classes, strength, padding, blur, min_confidence, max_detected, min_size, max_size, iou, steps): shared.opts.detailer_models = detailers shared.opts.detailer_classes = classes shared.opts.detailer_strength = strength @@ -319,8 +319,9 @@ def ui_settings_change(detailers, classes, strength, padding, blur, min_confiden shared.opts.detailer_min_size = min_size shared.opts.detailer_max_size = max_size shared.opts.detailer_iou = iou + shared.opts.detailer_steps = steps shared.opts.save(shared.config_filename, silent=True) - shared.log.debug(f'Detailer settings: models={shared.opts.detailer_models} classes={shared.opts.detailer_classes} strength={shared.opts.detailer_strength} conf={shared.opts.detailer_conf} max={shared.opts.detailer_max} iou={shared.opts.detailer_iou} size={shared.opts.detailer_min_size}-{shared.opts.detailer_max_size} padding={shared.opts.detailer_padding}') + shared.log.debug(f'Detailer settings: models={shared.opts.detailer_models} classes={shared.opts.detailer_classes} strength={shared.opts.detailer_strength} conf={shared.opts.detailer_conf} max={shared.opts.detailer_max} iou={shared.opts.detailer_iou} size={shared.opts.detailer_min_size}-{shared.opts.detailer_max_size} padding={shared.opts.detailer_padding} steps={shared.opts.detailer_steps}') with gr.Accordion(open=False, label="Detailer", elem_id=f"{tab}_detailer_accordion", elem_classes=["small-accordion"], visible=shared.native): with gr.Row(): @@ -331,7 +332,9 @@ def ui_settings_change(detailers, classes, strength, padding, blur, min_confiden with gr.Row(): classes = gr.Textbox(label="Classes", placeholder="Classes", elem_id=f"{tab}_detailer_classes") with gr.Row(): + steps = gr.Slider(label="Detailer steps", elem_id=f"{tab}_detailer_steps", value=shared.opts.detailer_steps, min=0, max=99, step=1) strength = gr.Slider(label="Detailer strength", elem_id=f"{tab}_detailer_strength", value=shared.opts.detailer_strength, minimum=0, maximum=1, step=0.01) + with gr.Row(): max_detected = gr.Slider(label="Max detected", elem_id=f"{tab}_detailer_max", value=shared.opts.detailer_max, min=1, maximum=10, step=1) with gr.Row(): padding = gr.Slider(label="Edge padding", elem_id=f"{tab}_detailer_padding", value=shared.opts.detailer_padding, minimum=0, maximum=100, step=1) @@ -344,16 +347,17 @@ def ui_settings_change(detailers, classes, strength, padding, blur, min_confiden min_size = gr.Slider(label="Min size", elem_id=f"{tab}_detailer_min_size", value=min_size, minimum=0.0, maximum=1.0, step=0.05) max_size = shared.opts.detailer_max_size if shared.opts.detailer_max_size < 1 and shared.opts.detailer_max_size > 0 else 1.0 max_size = gr.Slider(label="Max size", elem_id=f"{tab}_detailer_max_size", value=max_size, minimum=0.0, maximum=1.0, step=0.05) - detailers.change(fn=ui_settings_change, inputs=[detailers, classes, strength, padding, blur, min_confidence, max_detected, min_size, max_size, iou], outputs=[]) - classes.change(fn=ui_settings_change, inputs=[detailers, classes, strength, padding, blur, min_confidence, max_detected, min_size, max_size, iou], outputs=[]) - strength.change(fn=ui_settings_change, inputs=[detailers, classes, strength, padding, blur, min_confidence, max_detected, min_size, max_size, iou], outputs=[]) - padding.change(fn=ui_settings_change, inputs=[detailers, classes, strength, padding, blur, min_confidence, max_detected, min_size, max_size, iou], outputs=[]) - blur.change(fn=ui_settings_change, inputs=[detailers, classes, strength, padding, blur, min_confidence, max_detected, min_size, max_size, iou], outputs=[]) - min_confidence.change(fn=ui_settings_change, inputs=[detailers, classes, strength, padding, blur, min_confidence, max_detected, min_size, max_size, iou], outputs=[]) - max_detected.change(fn=ui_settings_change, inputs=[detailers, classes, strength, padding, blur, min_confidence, max_detected, min_size, max_size, iou], outputs=[]) - min_size.change(fn=ui_settings_change, inputs=[detailers, classes, strength, padding, blur, min_confidence, max_detected, min_size, max_size, iou], outputs=[]) - max_size.change(fn=ui_settings_change, inputs=[detailers, classes, strength, padding, blur, min_confidence, max_detected, min_size, max_size, iou], outputs=[]) - iou.change(fn=ui_settings_change, inputs=[detailers, classes, strength, padding, blur, min_confidence, max_detected, min_size, max_size, iou], outputs=[]) + detailers.change(fn=ui_settings_change, inputs=[detailers, classes, strength, padding, blur, min_confidence, max_detected, min_size, max_size, iou, steps], outputs=[]) + classes.change(fn=ui_settings_change, inputs=[detailers, classes, strength, padding, blur, min_confidence, max_detected, min_size, max_size, iou, steps], outputs=[]) + strength.change(fn=ui_settings_change, inputs=[detailers, classes, strength, padding, blur, min_confidence, max_detected, min_size, max_size, iou, steps], outputs=[]) + padding.change(fn=ui_settings_change, inputs=[detailers, classes, strength, padding, blur, min_confidence, max_detected, min_size, max_size, iou, steps], outputs=[]) + blur.change(fn=ui_settings_change, inputs=[detailers, classes, strength, padding, blur, min_confidence, max_detected, min_size, max_size, iou, steps], outputs=[]) + min_confidence.change(fn=ui_settings_change, inputs=[detailers, classes, strength, padding, blur, min_confidence, max_detected, min_size, max_size, iou, steps], outputs=[]) + max_detected.change(fn=ui_settings_change, inputs=[detailers, classes, strength, padding, blur, min_confidence, max_detected, min_size, max_size, iou, steps], outputs=[]) + min_size.change(fn=ui_settings_change, inputs=[detailers, classes, strength, padding, blur, min_confidence, max_detected, min_size, max_size, iou, steps], outputs=[]) + max_size.change(fn=ui_settings_change, inputs=[detailers, classes, strength, padding, blur, min_confidence, max_detected, min_size, max_size, iou, steps], outputs=[]) + iou.change(fn=ui_settings_change, inputs=[detailers, classes, strength, padding, blur, min_confidence, max_detected, min_size, max_size, iou, steps], outputs=[]) + steps.change(fn=ui_settings_change, inputs=[detailers, classes, strength, padding, blur, min_confidence, max_detected, min_size, max_size, iou, steps], outputs=[]) return enabled diff --git a/modules/progress.py b/modules/progress.py index b90981c3c..bc3e5500c 100644 --- a/modules/progress.py +++ b/modules/progress.py @@ -71,6 +71,8 @@ def progressapi(req: ProgressRequest): step_y = max(shared.state.sampling_steps, 1) current = step_y * batch_x + step_x total = step_y * batch_y + while total < current: + total += step_y progress = min(1, abs(current / total) if total > 0 else 0) elapsed = time.time() - shared.state.time_start if shared.state.time_start is not None else 0 predicted = elapsed / progress if progress > 0 else None diff --git a/modules/sd_models.py b/modules/sd_models.py index e00913092..46463a85a 100644 --- a/modules/sd_models.py +++ b/modules/sd_models.py @@ -270,6 +270,7 @@ def set_diffuser_options(sd_model, vae = None, op: str = 'model', offload=True): if not (hasattr(sd_model, "has_accelerate") and sd_model.has_accelerate): sd_model.has_accelerate = False + clear_caches() set_vae_options(sd_model, vae, op) set_diffusers_attention(sd_model) @@ -1605,6 +1606,17 @@ def disable_offload(sd_model): sd_model.has_accelerate = False +def clear_caches(): + shared.log.debug('Cache clear') + if not shared.opts.lora_legacy: + from modules.lora import networks + networks.loaded_networks.clear() + networks.previously_loaded_networks.clear() + networks.lora_cache.clear() + from modules import prompt_parser_diffusers + prompt_parser_diffusers.cache.clear() + + def unload_model_weights(op='model'): if shared.compiled_model_state is not None: shared.compiled_model_state.compiled_cache.clear() @@ -1622,11 +1634,6 @@ def unload_model_weights(op='model'): model_data.sd_model = None devices.torch_gc(force=True) shared.log.debug(f'Unload weights {op}: {memory_stats()}') - if not shared.opts.lora_legacy: - from modules.lora import networks - networks.loaded_networks.clear() - networks.previously_loaded_networks.clear() - networks.lora_cache.clear() elif op == 'refiner': if model_data.sd_refiner: if not shared.native: diff --git a/modules/shared.py b/modules/shared.py index 2be06eaff..719200ed6 100644 --- a/modules/shared.py +++ b/modules/shared.py @@ -861,6 +861,7 @@ def get_default_modes(): "detailer_max_size": OptionInfo(1.0, "Max object size", gr.Slider, {"minimum": 0.1, "maximum": 1, "step": 0.05, "visible": False}), "detailer_padding": OptionInfo(20, "Item padding", gr.Slider, {"minimum": 0, "maximum": 100, "step": 1, "visible": False}), "detailer_blur": OptionInfo(10, "Item edge blur", gr.Slider, {"minimum": 0, "maximum": 100, "step": 1, "visible": False}), + "detailer_steps": OptionInfo(10, "Detailer steps", gr.Slider, {"minimum": 0, "maximum": 99, "step": 1, "visible": False}), "detailer_strength": OptionInfo(0.5, "Detailer strength", gr.Slider, {"minimum": 0, "maximum": 1, "step": 0.01, "visible": False}), "detailer_models": OptionInfo(['face-yolo8n'], "Detailer models", gr.Dropdown, lambda: {"multiselect":True, "choices": list(yolo.list), "visible": False}), "detailer_unload": OptionInfo(False, "Move detailer model to CPU when complete"), diff --git a/modules/timer.py b/modules/timer.py index 43e859140..977206e06 100644 --- a/modules/timer.py +++ b/modules/timer.py @@ -1,7 +1,14 @@ +import os import time import sys +try: + default_min_time = float(os.environ.get('SD_MIN_TIMER', '0.05')) +except Exception: + default_min_time = 0.1 + + class Timer: def __init__(self): self.start = time.time() @@ -31,20 +38,23 @@ def record(self, category=None, extra_time=0, reset=True): self.records[category] += e + extra_time self.total += e + extra_time - def summary(self, min_time=0.05, total=True): + def summary(self, min_time=default_min_time, total=True): if self.profile: min_time = -1 - res = f"{self.total:.2f} " if total else '' + res = f"total={self.total:.2f} " if total else '' additions = [x for x in self.records.items() if x[1] >= min_time] + additions = sorted(additions, key=lambda x: x[1], reverse=True) if not additions: return res res += " ".join([f"{category}={time_taken:.2f}" for category, time_taken in additions]) return res - def dct(self, min_time=0.05): + def dct(self, min_time=default_min_time): if self.profile: - return {k: round(v, 4) for k, v in self.records.items()} - return {k: round(v, 2) for k, v in self.records.items() if v >= min_time} + res = {k: round(v, 4) for k, v in self.records.items()} + res = {k: round(v, 2) for k, v in self.records.items() if v >= min_time} + res = {k: v for k, v in sorted(res.items(), key=lambda x: x[1], reverse=True)} # noqa: C416 + return res def reset(self): self.__init__() diff --git a/modules/ui_control.py b/modules/ui_control.py index cd78313a7..c12a03130 100644 --- a/modules/ui_control.py +++ b/modules/ui_control.py @@ -29,7 +29,7 @@ def return_stats(t: float = None): elapsed_m = int(elapsed // 60) elapsed_s = elapsed % 60 elapsed_text = f"Time: {elapsed_m}m {elapsed_s:.2f}s |" if elapsed_m > 0 else f"Time: {elapsed_s:.2f}s |" - summary = timer.process.summary(min_time=0.25, total=False).replace('=', ' ') + summary = timer.process.summary(total=False).replace('=', ' ') gpu = '' cpu = '' if not shared.mem_mon.disabled: diff --git a/webui.py b/webui.py index 9c85fe426..3c8361ecf 100644 --- a/webui.py +++ b/webui.py @@ -244,7 +244,7 @@ def start_common(): def start_ui(): - log.info('UI start') + log.debug('UI start sequence') modules.script_callbacks.before_ui_callback() timer.startup.record("before-ui") shared.demo = modules.ui.create_ui(timer.startup) diff --git a/wiki b/wiki index fc38907c8..7bd8f8200 160000 --- a/wiki +++ b/wiki @@ -1 +1 @@ -Subproject commit fc38907c8336b7d172cca2ba056b3b55078fc0df +Subproject commit 7bd8f82008007bc7a766ca47b4dc1a54470397df