From 7a7cea3b4518d8583e3907194824be8647b90c89 Mon Sep 17 00:00:00 2001 From: Seunghoon Lee Date: Wed, 29 May 2024 12:42:40 +0900 Subject: [PATCH 01/24] [HOTFIX] Lock torch-directml==0.2.0.dev230426 --- installer.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/installer.py b/installer.py index e312c4f38..157f98961 100644 --- a/installer.py +++ b/installer.py @@ -610,7 +610,7 @@ def check_torch(): torch_command = os.environ.get('TORCH_COMMAND', 'torch torchvision') elif allow_directml and args.use_directml and ('arm' not in machine and 'aarch' not in machine): log.info('Using DirectML Backend') - torch_command = os.environ.get('TORCH_COMMAND', 'torch-directml') + torch_command = os.environ.get('TORCH_COMMAND', 'torch==2.0.0 torchvision torch-directml') if 'torch' in torch_command and not args.version: install(torch_command, 'torch torchvision') install('onnxruntime-directml', 'onnxruntime-directml', ignore=True) From 0fb1cf4d1f97bda7c813da7d81182ed901342612 Mon Sep 17 00:00:00 2001 From: Vladimir Mandic Date: Wed, 29 May 2024 08:48:10 -0400 Subject: [PATCH 02/24] fix ti --- TODO.md | 16 ++++++++++++++++ modules/textual_inversion/textual_inversion.py | 2 +- wiki | 2 +- 3 files changed, 18 insertions(+), 2 deletions(-) diff --git a/TODO.md b/TODO.md index 1f1838914..8ff8b6edc 100644 --- a/TODO.md +++ b/TODO.md @@ -2,6 +2,10 @@ Main ToDo list can be found at [GitHub projects](https://github.com/users/vladmandic/projects) +## Fix + +- ultralytics package install + ## Future Candidates - stable diffusion 3.0: unreleased @@ -10,10 +14,22 @@ Main ToDo list can be found at [GitHub projects](https://github.com/users/vladma - async lowvram: - fp8: - profiling: +- kohya-hires-fix: +- hunyuan-dit: - init latents: variations, img2img - diffusers public callbacks - include reference styles - lora: sc lora, dora, etc + +## Experimental + +- [MuLan](https://github.com/mulanai/MuLan) Multi-langunage prompts - wirte your prompts in ~110 auto-detected languages! + Compatible with SD15 and SDXL + Enable in scripts -> MuLan and set encoder to `InternVL-14B-224px` encoder + (that is currently only supported encoder, but others will be added) + Note: Model will be auto-downloaded on first use: note its huge size of 27GB + Even executing it in FP16 context will require ~16GB of VRAM for text encoder alone + *Note*: Uses fixed prompt parser, so no prompt attention will be used - [SDXL Flash Mini](https://huggingface.co/sd-community/sdxl-flash-mini) SDXL type that weighs less, consumes less video memory, and the quality has not dropped much to use, simply select from *networks -> models -> reference -> SDXL Flash Mini* diff --git a/modules/textual_inversion/textual_inversion.py b/modules/textual_inversion/textual_inversion.py index e2d720663..bf3e19a44 100644 --- a/modules/textual_inversion/textual_inversion.py +++ b/modules/textual_inversion/textual_inversion.py @@ -140,7 +140,7 @@ class EmbeddingDatabase: def get_expected_shape(self): if shared.backend == shared.Backend.DIFFUSERS: return 0 - if shared.sd_loaded: + if not shared.sd_loaded: shared.log.error('Model not loaded') return 0 vec = shared.sd_model.cond_stage_model.encode_embedding_init_text(",", 1) diff --git a/wiki b/wiki index f17d12033..55192d57d 160000 --- a/wiki +++ b/wiki @@ -1 +1 @@ -Subproject commit f17d12033e99505865763e32ce9a87bc7b422043 +Subproject commit 55192d57d92235e7bfc8e713a47c220091b2404a From 07b9c553b6d9a5dc5ecd71a2fa4a4bf578a3cd13 Mon Sep 17 00:00:00 2001 From: Vladimir Mandic Date: Wed, 29 May 2024 08:54:29 -0400 Subject: [PATCH 03/24] fix gallery extended chars in fn --- modules/ui_gallery.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/modules/ui_gallery.py b/modules/ui_gallery.py index 1170f1371..eead66c8d 100644 --- a/modules/ui_gallery.py +++ b/modules/ui_gallery.py @@ -4,9 +4,10 @@ import gradio as gr from PIL import Image from modules import shared, ui_symbols, ui_common, images, ui_control_helpers from modules.ui_components import ToolButton - +from urllib.parse import unquote def read_media(fn): + fn = unquote(fn).replace('%3A', ':') if not os.path.isfile(fn): shared.log.error(f'Gallery not found: file="{fn}"') return [[], None, '', '', f'Media not found: {fn}'] From d9ab46218bdbc21608a1a3465424f3fb46c954aa Mon Sep 17 00:00:00 2001 From: Vladimir Mandic Date: Wed, 29 May 2024 09:00:31 -0400 Subject: [PATCH 04/24] fix gallery mtime display --- javascript/gallery.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/javascript/gallery.js b/javascript/gallery.js index 90f50b1e8..545a65726 100644 --- a/javascript/gallery.js +++ b/javascript/gallery.js @@ -163,7 +163,7 @@ class GalleryFile extends HTMLElement { this.width = cache.width; this.height = cache.height; this.size = cache.size; - this.mtime = new Date(1000 * cache.mtime); + this.mtime = new Date(cache.mtime); } else { try { const json = await delayFetchThumb(this.src); @@ -175,7 +175,7 @@ class GalleryFile extends HTMLElement { this.width = json.width; this.height = json.height; this.size = json.size; - this.mtime = new Date(1000 * json.mtime); + this.mtime = new Date(json.mtime); await idbAdd({ hash: this.hash, folder: this.folder, From 042cac8846946a92231580e05287256dc61a20c6 Mon Sep 17 00:00:00 2001 From: Disty0 Date: Wed, 29 May 2024 16:48:41 +0300 Subject: [PATCH 05/24] Stable Cascade fix NNCF compress --- modules/sd_models_compile.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/modules/sd_models_compile.py b/modules/sd_models_compile.py index 113335931..c6006db25 100644 --- a/modules/sd_models_compile.py +++ b/modules/sd_models_compile.py @@ -27,7 +27,7 @@ class CompiledModelState: deepcache_worker = None -def apply_compile_to_model(sd_model, function, options): +def apply_compile_to_model(sd_model, function, options, op=None): if "Model" in options: if hasattr(sd_model, 'unet') and hasattr(sd_model.unet, 'config'): sd_model.unet = function(sd_model.unet) @@ -38,7 +38,11 @@ def apply_compile_to_model(sd_model, function, options): sd_model.decoder = sd_model.decoder_pipe.decoder = function(sd_model.decoder_pipe.decoder) if hasattr(sd_model, 'prior_pipe') and hasattr(sd_model, 'prior_prior'): sd_model.prior_prior = None + if op == "nncf" and "StableCascade" in sd_model.__class__.__name__: # fixes dtype errors + backup_clip_txt_pooled_mapper = copy.deepcopy(sd_model.prior_pipe.prior.clip_txt_pooled_mapper) sd_model.prior_prior = sd_model.prior_pipe.prior = function(sd_model.prior_pipe.prior) + if op == "nncf" and "StableCascade" in sd_model.__class__.__name__: + sd_model.prior_prior.clip_txt_pooled_mapper = sd_model.prior_pipe.prior.clip_txt_pooled_mapper = backup_clip_txt_pooled_mapper if "VAE" in options: if hasattr(sd_model, 'vae') and hasattr(sd_model.vae, 'decode'): sd_model.vae = function(sd_model.vae) @@ -88,7 +92,7 @@ def ipex_optimize(sd_model): devices.torch_gc() return model - sd_model = apply_compile_to_model(sd_model, ipex_optimize_model, shared.opts.ipex_optimize) + sd_model = apply_compile_to_model(sd_model, ipex_optimize_model, shared.opts.ipex_optimize, op="ipex") t1 = time.time() shared.log.info(f"IPEX Optimize: time={t1-t0:.2f}") @@ -120,7 +124,7 @@ def nncf_compress_weights(sd_model): shared.compiled_model_state = CompiledModelState() shared.compiled_model_state.is_compiled = True - sd_model = apply_compile_to_model(sd_model, nncf_compress_model, shared.opts.nncf_compress_weights) + sd_model = apply_compile_to_model(sd_model, nncf_compress_model, shared.opts.nncf_compress_weights, op="nncf") t1 = time.time() shared.log.info(f"Compress Weights: time={t1-t0:.2f}") @@ -267,7 +271,7 @@ def compile_torch(sd_model): except Exception as e: shared.log.error(f"Torch inductor config error: {e}") - sd_model = apply_compile_to_model(sd_model, torch_compile_model, shared.opts.cuda_compile) + sd_model = apply_compile_to_model(sd_model, torch_compile_model, shared.opts.cuda_compile, op="compile") setup_logging() # compile messes with logging so reset is needed if shared.opts.cuda_compile_precompile: From 2a8f0656821b833b01060015a10438213b821865 Mon Sep 17 00:00:00 2001 From: Vladimir Mandic Date: Wed, 29 May 2024 11:30:57 -0400 Subject: [PATCH 06/24] workaround for resize with modernui --- CHANGELOG.md | 11 +++++++---- extensions-builtin/sdnext-modernui | 2 +- modules/control/run.py | 13 +++++++++++++ modules/ui_sections.py | 8 ++++---- wiki | 2 +- 5 files changed, 26 insertions(+), 10 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 75d99a748..4a1fca627 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,12 @@ # Change Log for SD.Next +## Update for 2024-05-29 + +- fix textual inversion loading +- fix gallery mtime display +- fix extra network scrollable area +- lock torch-directml version + ## Update for 2024-05-28 ### Highlights for 2024-05-28 @@ -11,10 +18,6 @@ For details on how to enable and use it, see [Home](https://github.com/BinaryQua **ModernUI** is still in early development and not all features are available yet, please report [issues and feedback](https://github.com/BinaryQuantumSoul/sdnext-modernui/issues) Thanks to @BinaryQuantumSoul for his hard work on this project! -![Screenshot-ModernUI](html/screenshot-modernui.jpg) -![Screenshot-ModernUI-Img](html/screenshot-modernui-img2img.jpg) -![Screenshot-ModernUI-Control](html/screenshot-modernui-control.jpg) - *What else?* #### New built-in features diff --git a/extensions-builtin/sdnext-modernui b/extensions-builtin/sdnext-modernui index c79be7ffe..0b56557c1 160000 --- a/extensions-builtin/sdnext-modernui +++ b/extensions-builtin/sdnext-modernui @@ -1 +1 @@ -Subproject commit c79be7ffebfe9e186655f08f21cdab183d005f6b +Subproject commit 0b56557c15467d6c86b9ef1d6cbfd55bd2f52928 diff --git a/modules/control/run.py b/modules/control/run.py index 73eadeafb..352e1370a 100644 --- a/modules/control/run.py +++ b/modules/control/run.py @@ -129,6 +129,19 @@ def control_run(units: List[unit.Unit] = [], inputs: List[Image.Image] = [], ini outpath_grids=shared.opts.outdir_grids or shared.opts.outdir_control_grids, ) processing.process_init(p) + resize_mode_before = resize_mode_before if resize_name_before != 'None' and inputs is not None and len(inputs) > 0 else 0 + + # TODO monkey-patch for modernui missing tabs.select event + if selected_scale_tab_before == 0 and resize_name_before != 'None' and scale_by_before != 1 and inputs is not None and len(inputs) > 0: + shared.log.debug('Control: override resize mode=before') + selected_scale_tab_before = 1 + if selected_scale_tab_after == 0 and resize_name_after != 'None' and scale_by_after != 1: + shared.log.debug('Control: override resize mode=after') + selected_scale_tab_after = 1 + if selected_scale_tab_mask == 0 and resize_name_mask != 'None' and scale_by_mask != 1: + shared.log.debug('Control: override resize mode=mask') + selected_scale_tab_mask = 1 + # set initial resolution if resize_mode_before != 0 or inputs is None or inputs == [None]: p.width, p.height = width_before, height_before # pylint: disable=attribute-defined-outside-init diff --git a/modules/ui_sections.py b/modules/ui_sections.py index d83a7472d..724d9487f 100644 --- a/modules/ui_sections.py +++ b/modules/ui_sections.py @@ -316,10 +316,10 @@ def create_resize_inputs(tab, images, accordion=True, latent=False): with gr.Row(visible=True) as _resize_group: with gr.Column(elem_id=f"{tab}_column_size"): selected_scale_tab = gr.State(value=0) # pylint: disable=abstract-class-instantiated - with gr.Tabs(): - with gr.Tab(label="Fixed") as tab_scale_to: + with gr.Tabs(elem_id=f"{tab}_scale_tabs"): + with gr.Tab(label="Fixed", elem_id=f"{tab}_scale_tab_fixed") as tab_scale_to: with gr.Row(): - with gr.Column(elem_id=f"{tab}_column_size"): + with gr.Column(elem_id=f"{tab}_column_size_fixed"): with gr.Row(): width = gr.Slider(minimum=64, maximum=8192, step=8, label="Width", value=512, elem_id=f"{tab}_width") height = gr.Slider(minimum=64, maximum=8192, step=8, label="Height", value=512, elem_id=f"{tab}_height") @@ -332,7 +332,7 @@ def create_resize_inputs(tab, images, accordion=True, latent=False): detect_image_size_btn = ToolButton(value=ui_symbols.detect, elem_id=f"{tab}_detect_image_size_btn") el = tab.split('_')[0] detect_image_size_btn.click(fn=lambda w, h, _: (w or gr.update(), h or gr.update()), _js=f'currentImageResolution{el}', inputs=[dummy_component, dummy_component, dummy_component], outputs=[width, height], show_progress=False) - with gr.Tab(label="Scale") as tab_scale_by: + with gr.Tab(label="Scale", elem_id=f"{tab}_scale_tab_scale") as tab_scale_by: scale_by = gr.Slider(minimum=0.05, maximum=8.0, step=0.05, label="Scale", value=1.0, elem_id=f"{tab}_scale") for component in images: component.change(fn=lambda: None, _js="updateImg2imgResizeToTextAfterChangingImage", inputs=[], outputs=[], show_progress=False) diff --git a/wiki b/wiki index 55192d57d..75d2dedce 160000 --- a/wiki +++ b/wiki @@ -1 +1 @@ -Subproject commit 55192d57d92235e7bfc8e713a47c220091b2404a +Subproject commit 75d2dedce70ba19da26da0a1f16ccc40411f5c49 From d19fc8c7ab9751f11cf1b648818e095ee4a2c2e9 Mon Sep 17 00:00:00 2001 From: Vladimir Mandic Date: Wed, 29 May 2024 11:59:32 -0400 Subject: [PATCH 07/24] improve xformers triton and ultralytics installers --- CHANGELOG.md | 5 ++++- installer.py | 17 ++++++----------- scripts/face-details.py | 2 +- 3 files changed, 11 insertions(+), 13 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4a1fca627..222ece6aa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,8 +4,11 @@ - fix textual inversion loading - fix gallery mtime display -- fix extra network scrollable area +- fix extra network scrollable area when using modernui +- workaround for scale-by when using modernui - lock torch-directml version +- improve xformers installer +- improve ultralytics installer ## Update for 2024-05-28 diff --git a/installer.py b/installer.py index 157f98961..33d5c8b8a 100644 --- a/installer.py +++ b/installer.py @@ -434,7 +434,8 @@ def check_torch(): log.debug(f'Torch overrides: cuda={args.use_cuda} rocm={args.use_rocm} ipex={args.use_ipex} diml={args.use_directml} openvino={args.use_openvino}') log.debug(f'Torch allowed: cuda={allow_cuda} rocm={allow_rocm} ipex={allow_ipex} diml={allow_directml} openvino={allow_openvino}') torch_command = os.environ.get('TORCH_COMMAND', '') - xformers_package = os.environ.get('XFORMERS_PACKAGE', 'none') + xformers_package = os.environ.get('XFORMERS_PACKAGE', '--pre xformers') if opts.get('cross_attention_optimization', '') == 'xFormers' or args.use_xformers else 'none' + triton_command = os.environ.get('TRITON_COMMAND', 'triton') if sys.platform == 'linux' else None def is_rocm_available(): if not allow_rocm: @@ -452,14 +453,7 @@ def check_torch(): pass elif allow_cuda and (shutil.which('nvidia-smi') is not None or args.use_xformers 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: nvidia-smi present') - if not args.use_xformers: - torch_command = os.environ.get('TORCH_COMMAND', 'torch torchvision --index-url https://download.pytorch.org/whl/cu121') - xformers_package = os.environ.get('XFORMERS_PACKAGE', '--pre triton xformers --index-url https://download.pytorch.org/whl/cu121') - else: - torch_command = os.environ.get('TORCH_COMMAND', 'torch torchvision --index-url https://download.pytorch.org/whl/cu118') - xformers_package = os.environ.get('XFORMERS_PACKAGE', '--pre triton xformers --index-url https://download.pytorch.org/whl/cu118') - if opts.get('cross_attention_optimization', '') != 'xFormers': - xformers_package = 'none' + torch_command = os.environ.get('TORCH_COMMAND', 'torch torchvision --index-url https://download.pytorch.org/whl/cu121') install('onnxruntime-gpu', 'onnxruntime-gpu', ignore=True) elif is_rocm_available(): is_windows = platform.system() == 'Windows' @@ -555,7 +549,6 @@ def check_torch(): ort_version = os.environ.get('ONNXRUNTIME_VERSION', None) ort_package = os.environ.get('ONNXRUNTIME_PACKAGE', f"--pre onnxruntime-training{'' if ort_version is None else ('==' + ort_version)} --index-url https://pypi.lsh.sh/{rocm_ver[0]}{rocm_ver[2]} --extra-index-url https://pypi.org/simple") install(ort_package, 'onnxruntime-training') - xformers_package = os.environ.get('XFORMERS_PACKAGE', 'none') elif allow_ipex and (args.use_ipex or shutil.which('sycl-ls') is not None or shutil.which('sycl-ls.exe') is not None or os.environ.get('ONEAPI_ROOT') is not None or os.path.exists('/opt/intel/oneapi') or os.path.exists("C:/Program Files (x86)/Intel/oneAPI") or os.path.exists("C:/oneAPI")): args.use_ipex = True # pylint: disable=attribute-defined-outside-init log.info('Intel OneAPI Toolkit detected') @@ -623,6 +616,8 @@ def check_torch(): if not installed('torch', quiet=True): log.debug(f'Installing torch: {torch_command}') install(torch_command, 'torch torchvision') + if triton_command is not None: + install(triton_command, 'triton') else: try: import torch @@ -666,7 +661,7 @@ def check_torch(): install(f'--no-deps {xformers_package}', ignore=True) import torch import xformers # pylint: disable=unused-import - elif not args.experimental and not args.use_xformers: + elif not args.experimental and not args.use_xformers and opts.get('cross_attention_optimization', '') != 'xFormers': uninstall('xformers') except Exception as e: log.debug(f'Cannot install xformers package: {e}') diff --git a/scripts/face-details.py b/scripts/face-details.py index 57fa0e361..849461c77 100644 --- a/scripts/face-details.py +++ b/scripts/face-details.py @@ -32,7 +32,7 @@ class FaceRestorerYolo(FaceRestoration): def dependencies(self): import installer - installer.install('ultralytics', ignore=False) + installer.install('ultralytics', ignore=True) def predict( self, From 99bddca5c1092348b2051bad97abcd4b2c454455 Mon Sep 17 00:00:00 2001 From: Vladimir Mandic Date: Wed, 29 May 2024 13:48:07 -0400 Subject: [PATCH 08/24] fix control prompt lists --- CHANGELOG.md | 2 ++ README.md | 1 + TODO.md | 1 + modules/control/run.py | 2 +- modules/face/__init__.py | 1 - modules/face/instantid.py | 2 -- modules/shared.py | 2 +- scripts/xyz_grid.py | 1 + 8 files changed, 7 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 222ece6aa..6e83018bf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,10 +5,12 @@ - fix textual inversion loading - fix gallery mtime display - fix extra network scrollable area when using modernui +- fix control prompts list handling - workaround for scale-by when using modernui - lock torch-directml version - improve xformers installer - improve ultralytics installer +- improve triton installer ## Update for 2024-05-28 diff --git a/README.md b/README.md index de51559bf..c9280c410 100644 --- a/README.md +++ b/README.md @@ -142,6 +142,7 @@ Also supported are modifiers such as: - [Step-by-step install guide](https://github.com/vladmandic/automatic/wiki/Installation) - [Advanced install notes](https://github.com/vladmandic/automatic/wiki/Advanced-Install) +- [Video: install and use](https://www.youtube.com/watch?v=nWTnTyFTuAs) - [Common installation errors](https://github.com/vladmandic/automatic/discussions/1627) - [FAQ](https://github.com/vladmandic/automatic/discussions/1011) diff --git a/TODO.md b/TODO.md index 8ff8b6edc..971f865f5 100644 --- a/TODO.md +++ b/TODO.md @@ -20,6 +20,7 @@ Main ToDo list can be found at [GitHub projects](https://github.com/users/vladma - diffusers public callbacks - include reference styles - lora: sc lora, dora, etc +- controlnet: additional models ## Experimental diff --git a/modules/control/run.py b/modules/control/run.py index 352e1370a..5734c10b9 100644 --- a/modules/control/run.py +++ b/modules/control/run.py @@ -128,7 +128,7 @@ def control_run(units: List[unit.Unit] = [], inputs: List[Image.Image] = [], ini outpath_samples=shared.opts.outdir_samples or shared.opts.outdir_control_samples, outpath_grids=shared.opts.outdir_grids or shared.opts.outdir_control_grids, ) - processing.process_init(p) + # processing.process_init(p) resize_mode_before = resize_mode_before if resize_name_before != 'None' and inputs is not None and len(inputs) > 0 else 0 # TODO monkey-patch for modernui missing tabs.select event diff --git a/modules/face/__init__.py b/modules/face/__init__.py index 5b4c3a31c..289bdb8e2 100644 --- a/modules/face/__init__.py +++ b/modules/face/__init__.py @@ -112,7 +112,6 @@ class Script(scripts.Script): input_images[i] = Image.open(image['name']) processed = None - processing.process_init(p) if mode == 'FaceID': # faceid runs as ipadapter in its own pipeline from modules.face.insightface import get_app app = get_app('buffalo_l') diff --git a/modules/face/instantid.py b/modules/face/instantid.py index e519218df..8c2d91002 100644 --- a/modules/face/instantid.py +++ b/modules/face/instantid.py @@ -43,8 +43,6 @@ def instant_id(p: processing.StableDiffusionProcessing, app, source_images, stre controlnet_model = ControlNetModel.from_pretrained(REPO_ID, subfolder="ControlNetModel", torch_dtype=devices.dtype, cache_dir=shared.opts.diffusers_dir) sd_models.move_model(controlnet_model, devices.device) - processing.process_init(p) - # create new pipeline orig_pipeline = shared.sd_model # backup current pipeline definition shared.sd_model = StableDiffusionXLInstantIDPipeline( diff --git a/modules/shared.py b/modules/shared.py index 2608feea7..d71efd5df 100644 --- a/modules/shared.py +++ b/modules/shared.py @@ -754,7 +754,7 @@ options_templates.update(options_section(('postprocessing', "Postprocessing"), { "facehires_max_size": OptionInfo(0, "Max face size", gr.Slider, {"minimum": 0, "maximum": 1024, "step": 1}), "facehires_padding": OptionInfo(10, "Face padding", gr.Slider, {"minimum": 0, "maximum": 100, "step": 1}), "face_restoration_unload": OptionInfo(False, "Move model to CPU when complete"), - "facehires_strength": OptionInfo(0.0, "Face HiRes strength", gr.Slider, {"minimum": 0, "maximum": 1, "step": 0.01}), + "facehires_strength": OptionInfo(0.0, "Face restore strength", gr.Slider, {"minimum": 0, "maximum": 1, "step": 0.01}), "code_former_weight": OptionInfo(0.2, "CodeFormer weight parameter", gr.Slider, {"minimum": 0, "maximum": 1, "step": 0.01}), "postprocessing_sep_upscalers": OptionInfo("

Upscaling

", "", gr.HTML), diff --git a/scripts/xyz_grid.py b/scripts/xyz_grid.py index ea0494bc7..a7ff92532 100644 --- a/scripts/xyz_grid.py +++ b/scripts/xyz_grid.py @@ -554,6 +554,7 @@ class Script(scripts.Script): processing.fix_seed(p) if not shared.opts.return_grid: p.batch_size = 1 + def process_axis(opt, vals, vals_dropdown): if opt.label == 'Nothing': return [0] From 3b004f4bcbf6c984ac3268f1839a54c289a3121e Mon Sep 17 00:00:00 2001 From: Vladimir Mandic Date: Wed, 29 May 2024 14:14:16 -0400 Subject: [PATCH 09/24] fix variation seed with hires pass --- CHANGELOG.md | 1 + modules/processing_args.py | 3 ++- wiki | 2 +- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6e83018bf..77c21ff32 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ - fix gallery mtime display - fix extra network scrollable area when using modernui - fix control prompts list handling +- fix variation seed with hires pass - workaround for scale-by when using modernui - lock torch-directml version - improve xformers installer diff --git a/modules/processing_args.py b/modules/processing_args.py index b3bc69c35..d16a6a245 100644 --- a/modules/processing_args.py +++ b/modules/processing_args.py @@ -150,7 +150,8 @@ def set_pipeline_args(p, model, prompts: list, negative_prompts: list, prompts_2 if 'generator' in possible: args['generator'] = get_generator(p) if 'latents' in possible and getattr(p, "init_latent", None) is not None: - args['latents'] = p.init_latent + if sd_models.get_diffusers_task(model) == sd_models.DiffusersTaskType.TEXT_2_IMAGE: + args['latents'] = p.init_latent if 'output_type' in possible: if not hasattr(model, 'vae'): args['output_type'] = 'np' # only set latent if model has vae diff --git a/wiki b/wiki index 75d2dedce..04cfbf213 160000 --- a/wiki +++ b/wiki @@ -1 +1 @@ -Subproject commit 75d2dedce70ba19da26da0a1f16ccc40411f5c49 +Subproject commit 04cfbf2132c6d5f5e5f5e5667934694e7dd36dd3 From 032018abf0daa5ecf43d2da856ecfaf93010d524 Mon Sep 17 00:00:00 2001 From: Vladimir Mandic Date: Wed, 29 May 2024 14:21:39 -0400 Subject: [PATCH 10/24] silent install checks --- installer.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/installer.py b/installer.py index 33d5c8b8a..da955d49f 100644 --- a/installer.py +++ b/installer.py @@ -253,7 +253,7 @@ def install(package, friendly: str = None, ignore: bool = False): if args.reinstall or args.upgrade: global quick_allowed # pylint: disable=global-statement quick_allowed = False - if args.reinstall or not installed(package, friendly): + if args.reinstall or not installed(package, friendly, quiet=True): res = pip(f"install --upgrade {package}", ignore=ignore) try: import imp # pylint: disable=deprecated-module @@ -440,7 +440,7 @@ def check_torch(): def is_rocm_available(): if not allow_rocm: return False - if installed('torch-directml'): + if installed('torch-directml', quiet=True): log.debug('DirectML installation is detected. Skipping HIP SDK check.') return False if platform.system() == 'Windows': From 84d813bad4b58d1f06f707b9d67784e3ccdc1418 Mon Sep 17 00:00:00 2001 From: Vladimir Mandic Date: Thu, 30 May 2024 09:45:39 -0400 Subject: [PATCH 11/24] fix faceid and improve insightface installer --- CHANGELOG.md | 3 +- installer.py | 13 ++++++--- modules/face/faceid.py | 56 +++++++++++++++++++++---------------- modules/face/insightface.py | 17 +++++------ modules/face/instantid.py | 4 +-- modules/face/photomaker.py | 2 +- modules/processing.py | 2 +- modules/ui_gallery.py | 2 +- 8 files changed, 57 insertions(+), 42 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 77c21ff32..beecb380e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,6 @@ # Change Log for SD.Next -## Update for 2024-05-29 +## Update for 2024-05-30 - fix textual inversion loading - fix gallery mtime display @@ -12,6 +12,7 @@ - improve xformers installer - improve ultralytics installer - improve triton installer +- improve insightface installer ## Update for 2024-05-28 diff --git a/installer.py b/installer.py index da955d49f..4c268cac8 100644 --- a/installer.py +++ b/installer.py @@ -1,3 +1,4 @@ +from functools import lru_cache import os import sys import json @@ -171,6 +172,7 @@ def print_profile(profiler: cProfile.Profile, msg: str): # check if package is installed +@lru_cache() def installed(package, friendly: str = None, reload = False, quiet = False): ok = True try: @@ -201,12 +203,12 @@ def installed(package, friendly: str = None, reload = False, quiet = False): # log.debug(f"Package version found: {p[0]} {package_version}") if len(p) > 1: exact = package_version == p[1] - ok = ok and (exact or args.experimental) if not exact and not quiet: if args.experimental: log.warning(f"Package allowing experimental: {p[0]} {package_version} required {p[1]}") else: log.warning(f"Package version mismatch: {p[0]} {package_version} required {p[1]}") + ok = ok and (exact or args.experimental) else: if not quiet: log.debug(f"Package not found: {p[0]}") @@ -227,6 +229,7 @@ def uninstall(package, quiet = False): return res +@lru_cache() def pip(arg: str, ignore: bool = False, quiet: bool = False): arg = arg.replace('>=', '==') if not quiet: @@ -248,12 +251,13 @@ def pip(arg: str, ignore: bool = False, quiet: bool = False): # install package using pip if not already installed -def install(package, friendly: str = None, ignore: bool = False): +@lru_cache() +def install(package, friendly: str = None, ignore: bool = False, reinstall: bool = False): res = '' if args.reinstall or args.upgrade: global quick_allowed # pylint: disable=global-statement quick_allowed = False - if args.reinstall or not installed(package, friendly, quiet=True): + if args.reinstall or reinstall or not installed(package, friendly, quiet=False): res = pip(f"install --upgrade {package}", ignore=ignore) try: import imp # pylint: disable=deprecated-module @@ -264,6 +268,7 @@ def install(package, friendly: str = None, ignore: bool = False): # execute git command +@lru_cache() def git(arg: str, folder: str = None, ignore: bool = False): if args.skip_git: return '' @@ -858,7 +863,7 @@ def install_requirements(): with open('requirements.txt', 'r', encoding='utf8') as f: lines = [line.strip() for line in f.readlines() if line.strip() != '' and not line.startswith('#') and line is not None] for line in lines: - install(line) + _res = install(line) if args.profile: print_profile(pr, 'Requirements') diff --git a/modules/face/faceid.py b/modules/face/faceid.py index 283594f54..4bfa9a94b 100644 --- a/modules/face/faceid.py +++ b/modules/face/faceid.py @@ -75,7 +75,6 @@ def face_id( script_callbacks.before_process_callback(p) with context_hypertile_vae(p), context_hypertile_unet(p), devices.inference_context(): - p.init(p.all_prompts, p.all_seeds, p.all_subseeds) ip_ckpt = FACEID_MODELS[model] folder, filename = os.path.split(ip_ckpt) basename, _ext = os.path.splitext(filename) @@ -83,23 +82,13 @@ def face_id( if model_path is None: shared.log.error(f"FaceID download failed: model={model} file={ip_ckpt}") return None - if override: - shared.sd_model.scheduler = diffusers.DDIMScheduler( - num_train_timesteps=1000, - beta_start=0.00085, - beta_end=0.012, - beta_schedule="scaled_linear", - clip_sample=False, - set_alpha_to_one=False, - steps_offset=1, - ) if faceid_model_weights is None or faceid_model_name != model or not cache: shared.log.debug(f"FaceID load: model={model} file={ip_ckpt}") faceid_model_weights = torch.load(model_path, map_location="cpu") else: shared.log.debug(f"FaceID cached: model={model} file={ip_ckpt}") - if "XL Plus" in model: + if "XL Plus" in model and shared.sd_model_type == 'sd': image_encoder_path = "laion/CLIP-ViT-H-14-laion2B-s32B-b79K" original_load_ip_adapter = IPAdapterFaceIDPlusXL.load_ip_adapter IPAdapterFaceIDPlusXL.load_ip_adapter = hijack_load_ip_adapter @@ -112,7 +101,7 @@ def face_id( device=devices.device, torch_dtype=devices.dtype, ) - elif "XL" in model: + elif "XL" in model and shared.sd_model_type == 'sdxl': original_load_ip_adapter = IPAdapterFaceIDXL.load_ip_adapter IPAdapterFaceIDXL.load_ip_adapter = hijack_load_ip_adapter faceid_model = IPAdapterFaceIDXL( @@ -123,7 +112,7 @@ def face_id( device=devices.device, torch_dtype=devices.dtype, ) - elif "Plus" in model: + elif "Plus" in model and shared.sd_model_type == 'sd': original_load_ip_adapter = IPAdapterFaceIDPlus.load_ip_adapter IPAdapterFaceIDPlus.load_ip_adapter = hijack_load_ip_adapter image_encoder_path = "laion/CLIP-ViT-H-14-laion2B-s32B-b79K" @@ -136,7 +125,7 @@ def face_id( device=devices.device, torch_dtype=devices.dtype, ) - elif "Portrait" in model: + elif "Portrait" in model and shared.sd_model_type == 'sd': original_load_ip_adapter = IPAdapterFaceIDPortrait.load_ip_adapter IPAdapterFaceIDPortrait.load_ip_adapter = hijack_load_ip_adapter faceid_model = IPAdapterFaceIDPortrait( @@ -147,7 +136,7 @@ def face_id( device=devices.device, torch_dtype=devices.dtype, ) - else: + elif "Base" in model and shared.sd_model_type == 'sd': original_load_ip_adapter = IPAdapterFaceID.load_ip_adapter IPAdapterFaceID.load_ip_adapter = hijack_load_ip_adapter faceid_model = IPAdapterFaceID( @@ -158,11 +147,26 @@ def face_id( device=devices.device, torch_dtype=devices.dtype, ) + else: + shared.log.error(f'FaceID model not supported: model="{model}" class={shared.sd_model.__class__.__name__}') + return None + + if override: + shared.sd_model.scheduler = diffusers.DDIMScheduler( + num_train_timesteps=1000, + beta_start=0.00085, + beta_end=0.012, + beta_schedule="scaled_linear", + clip_sample=False, + set_alpha_to_one=False, + steps_offset=1, + ) shortcut = "v2" in model faceid_model_name = model face_embeds = [] face_images = [] + for i, source_image in enumerate(source_images): np_image = cv2.cvtColor(np.array(source_image), cv2.COLOR_RGB2BGR) faces = app.get(np_image) @@ -201,19 +205,23 @@ def face_id( faceid_model.set_scale(scale) extra_network_data = None - for i in range(p.n_iter): - p.iteration = i - p.prompts = p.all_prompts[i * p.batch_size:(i + 1) * p.batch_size] - p.negative_prompts = p.all_negative_prompts[i * p.batch_size:(i + 1) * p.batch_size] + processing.process_init(p) + p.init(p.all_prompts, p.all_seeds, p.all_subseeds) + for n in range(p.n_iter): + p.iteration = n + p.prompts = p.all_prompts[n * p.batch_size:(n+1) * p.batch_size] + p.negative_prompts = p.all_negative_prompts[n * p.batch_size:(n+1) * p.batch_size] + p.seeds = p.all_seeds[n * p.batch_size:(n+1) * p.batch_size] + p.subseeds = p.all_subseeds[n * p.batch_size:(n+1) * p.batch_size] p.prompts, extra_network_data = extra_networks.parse_prompts(p.prompts) - p.seeds = p.all_seeds[i * p.batch_size:(i + 1) * p.batch_size] + if not p.disable_extra_networks: with devices.autocast(): extra_networks.activate(p, extra_network_data) ip_model_dict.update({ - "prompt": p.prompts, - "negative_prompt": p.negative_prompts, - "seed": int(p.seeds[0]), + "prompt": p.prompts[0], + "negative_prompt": p.negative_prompts[0], + "seed": p.seeds[0], }) debug(f"FaceID: {ip_model_dict}") res = faceid_model.generate(**ip_model_dict) diff --git a/modules/face/insightface.py b/modules/face/insightface.py index 655dd72e6..3eb7171bf 100644 --- a/modules/face/insightface.py +++ b/modules/face/insightface.py @@ -9,14 +9,15 @@ instightface_mp = None def get_app(mp_name): global insightface_app, instightface_mp # pylint: disable=global-statement - from installer import installed, install - packages = [ - ('insightface', 'insightface'), - ('git+https://github.com/tencent-ailab/IP-Adapter.git', 'ip_adapter'), - ] - for pkg in packages: - if not installed(pkg[1], reload=False, quiet=True): - install(pkg[0], pkg[1], ignore=False) + + from installer import install, installed + if not installed('insightface', reload=False, quiet=True): + install('insightface', 'insightface', ignore=False) + install('albumentations==1.4.3', 'albumentations', ignore=False, reinstall=True) + install('pydantic==1.10.15', 'pydantic', ignore=False, reinstall=True) + if not installed('ip_adapter', reload=False, quiet=True): + install('git+https://github.com/tencent-ailab/IP-Adapter.git', 'ip_adapter', ignore=False) + if insightface_app is None or mp_name != instightface_mp: from insightface.app import FaceAnalysis import huggingface_hub as hf diff --git a/modules/face/instantid.py b/modules/face/instantid.py index 8c2d91002..1835e8e80 100644 --- a/modules/face/instantid.py +++ b/modules/face/instantid.py @@ -71,8 +71,8 @@ def instant_id(p: processing.StableDiffusionProcessing, app, source_images, stre p.task_args['controlnet_conditioning_scale'] = float(conditioning) p.task_args['ip_adapter_scale'] = float(strength) shared.log.debug(f"InstantID args: {p.task_args}") - p.task_args['prompt'] = p.all_prompts[0] # override all logic - p.task_args['negative_prompt'] = p.all_negative_prompts[0] + p.task_args['prompt'] = p.all_prompts[0] if p.all_prompts is not None else p.prompt + p.task_args['negative_prompt'] = p.all_negative_prompts[0] if p.all_negative_prompts is not None else p.negative_prompt p.task_args['image_embeds'] = face_embeds[0] # overwrite placeholder # run processing diff --git a/modules/face/photomaker.py b/modules/face/photomaker.py index 9e86316b0..219b6497d 100644 --- a/modules/face/photomaker.py +++ b/modules/face/photomaker.py @@ -49,7 +49,7 @@ def photo_maker(p: processing.StableDiffusionProcessing, input_images, trigger, shared.opts.data['prompt_attention'] = 'Fixed attention' # otherwise need to deal with class_tokens_mask p.task_args['input_id_images'] = input_images p.task_args['start_merge_step'] = int(start * p.steps) - p.task_args['prompt'] = p.all_prompts[0] # override all logic + p.task_args['prompt'] = p.all_prompts[0] if p.all_prompts is not None else p.prompt photomaker_path = hf.hf_hub_download(repo_id="TencentARC/PhotoMaker", filename="photomaker-v1.bin", repo_type="model", cache_dir=shared.opts.diffusers_dir) shared.log.debug(f'PhotoMaker: model={photomaker_path} images={len(input_images)} trigger={trigger} args={p.task_args}') diff --git a/modules/processing.py b/modules/processing.py index ae81ce833..8a44d9477 100644 --- a/modules/processing.py +++ b/modules/processing.py @@ -223,7 +223,7 @@ def process_init(p: StableDiffusionProcessing): if p.all_seeds is None: reset_prompts = True if type(seed) == list: - p.all_seeds = seed + p.all_seeds = [int(s) for s in seed] else: if shared.opts.sequential_seed: p.all_seeds = [int(seed) + (x if p.subseed_strength == 0 else 0) for x in range(len(p.all_prompts))] diff --git a/modules/ui_gallery.py b/modules/ui_gallery.py index eead66c8d..a1f317caa 100644 --- a/modules/ui_gallery.py +++ b/modules/ui_gallery.py @@ -1,10 +1,10 @@ import os from datetime import datetime +from urllib.parse import unquote import gradio as gr from PIL import Image from modules import shared, ui_symbols, ui_common, images, ui_control_helpers from modules.ui_components import ToolButton -from urllib.parse import unquote def read_media(fn): fn = unquote(fn).replace('%3A', ':') From 885f272cdd6f4fe61470f15752cfc9136d95e161 Mon Sep 17 00:00:00 2001 From: Seunghoon Lee Date: Fri, 31 May 2024 13:26:31 +0900 Subject: [PATCH 12/24] zluda fix recursion --- modules/zluda.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/modules/zluda.py b/modules/zluda.py index 71f870267..033b7c93a 100644 --- a/modules/zluda.py +++ b/modules/zluda.py @@ -5,6 +5,7 @@ import torch from torch._prims_common import DeviceLikeType import onnxruntime as ort from modules import shared, devices +from modules.onnx_impl.execution_providers import available_execution_providers, ExecutionProvider PLATFORM = sys.platform @@ -61,10 +62,10 @@ def initialize_zluda(): shared.opts.sdp_options = ['Math attention'] # ONNX Runtime is not supported - ort.capi._pybind_state.get_available_providers = lambda: [v for v in ort.get_available_providers() if v != 'CUDAExecutionProvider'] # pylint: disable=protected-access + ort.capi._pybind_state.get_available_providers = lambda: [v for v in available_execution_providers if v != ExecutionProvider.CUDA] # pylint: disable=protected-access ort.get_available_providers = ort.capi._pybind_state.get_available_providers # pylint: disable=protected-access - if shared.opts.onnx_execution_provider == 'CUDAExecutionProvider': - shared.opts.onnx_execution_provider = 'CPUExecutionProvider' + if shared.opts.onnx_execution_provider == ExecutionProvider.CUDA: + shared.opts.onnx_execution_provider = ExecutionProvider.CPU devices.device_codeformer = devices.cpu From 887de74d22b39d318de7865c617ed29047774cdc Mon Sep 17 00:00:00 2001 From: Disty0 Date: Fri, 31 May 2024 18:40:39 +0300 Subject: [PATCH 13/24] Fix Cascade overcooking with more than 75 tokens --- modules/prompt_parser_diffusers.py | 1 + 1 file changed, 1 insertion(+) diff --git a/modules/prompt_parser_diffusers.py b/modules/prompt_parser_diffusers.py index 4d242458f..bfe267e2e 100644 --- a/modules/prompt_parser_diffusers.py +++ b/modules/prompt_parser_diffusers.py @@ -230,6 +230,7 @@ def pad_to_same_length(pipe, embeds): try: if getattr(pipe, "prior_pipe", None) and getattr(pipe.prior_pipe, "text_encoder", None) is not None: # Cascade empty_embed = pipe.prior_pipe.encode_prompt(device, 1, 1, False, "") + empty_embed = [torch.zeros(empty_embed[0].shape, device=empty_embed[0].device, dtype=empty_embed[0].dtype)] else: # SDXL empty_embed = pipe.encode_prompt("") except TypeError: # SD1.5 From fdb5e240c67901599379dd7c49a1ccbfcf7b53f0 Mon Sep 17 00:00:00 2001 From: Vladimir Mandic Date: Fri, 31 May 2024 14:45:55 -0400 Subject: [PATCH 14/24] fix face scripts --- TODO.md | 1 + modules/face/faceid.py | 5 +++-- modules/face/instantid.py | 3 +++ modules/face/photomaker.py | 3 +++ 4 files changed, 10 insertions(+), 2 deletions(-) diff --git a/TODO.md b/TODO.md index 971f865f5..14dc2c73a 100644 --- a/TODO.md +++ b/TODO.md @@ -21,6 +21,7 @@ Main ToDo list can be found at [GitHub projects](https://github.com/users/vladma - include reference styles - lora: sc lora, dora, etc - controlnet: additional models +- resadapter: ## Experimental diff --git a/modules/face/faceid.py b/modules/face/faceid.py index 4bfa9a94b..f400f038a 100644 --- a/modules/face/faceid.py +++ b/modules/face/faceid.py @@ -205,8 +205,9 @@ def face_id( faceid_model.set_scale(scale) extra_network_data = None - processing.process_init(p) - p.init(p.all_prompts, p.all_seeds, p.all_subseeds) + if p.all_prompts is None or len(p.all_prompts) == 0: + processing.process_init(p) + p.init(p.all_prompts, p.all_seeds, p.all_subseeds) for n in range(p.n_iter): p.iteration = n p.prompts = p.all_prompts[n * p.batch_size:(n+1) * p.batch_size] diff --git a/modules/face/instantid.py b/modules/face/instantid.py index 1835e8e80..9c7c16f61 100644 --- a/modules/face/instantid.py +++ b/modules/face/instantid.py @@ -64,6 +64,9 @@ def instant_id(p: processing.StableDiffusionProcessing, app, source_images, stre shared.sd_model.to(dtype=devices.dtype) # pipeline specific args + if p.all_prompts is None or len(p.all_prompts) == 0: + processing.process_init(p) + p.init(p.all_prompts, p.all_seeds, p.all_subseeds) orig_prompt_attention = shared.opts.prompt_attention shared.opts.data['prompt_attention'] = 'Fixed attention' # otherwise need to deal with class_tokens_mask p.task_args['image_embeds'] = face_embeds[0].shape # placeholder diff --git a/modules/face/photomaker.py b/modules/face/photomaker.py index 219b6497d..c8f58b42a 100644 --- a/modules/face/photomaker.py +++ b/modules/face/photomaker.py @@ -17,6 +17,9 @@ def photo_maker(p: processing.StableDiffusionProcessing, input_images, trigger, return None # validate prompt + if p.all_prompts is None or len(p.all_prompts) == 0: + processing.process_init(p) + p.init(p.all_prompts, p.all_seeds, p.all_subseeds) trigger_ids = shared.sd_model.tokenizer.encode(trigger) + shared.sd_model.tokenizer_2.encode(trigger) prompt_ids1 = shared.sd_model.tokenizer.encode(p.all_prompts[0]) prompt_ids2 = shared.sd_model.tokenizer_2.encode(p.all_prompts[0]) From 2bcada4755b665f5cd62b9b4a663b37ee9b66709 Mon Sep 17 00:00:00 2001 From: Vladimir Mandic Date: Sat, 1 Jun 2024 07:31:00 -0400 Subject: [PATCH 15/24] fix restore variation seed for txt2img and img2img --- CHANGELOG.md | 3 ++- modules/processing.py | 1 - modules/ui_common.py | 24 +++++++++++++++--------- modules/ui_img2img.py | 2 +- modules/ui_sections.py | 2 +- modules/ui_txt2img.py | 2 +- wiki | 2 +- 7 files changed, 21 insertions(+), 15 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index beecb380e..ee35c2b85 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,12 +1,13 @@ # Change Log for SD.Next -## Update for 2024-05-30 +## Update for 2024-06-01 - fix textual inversion loading - fix gallery mtime display - fix extra network scrollable area when using modernui - fix control prompts list handling - fix variation seed with hires pass +- fix restore variation seed and strength - workaround for scale-by when using modernui - lock torch-directml version - improve xformers installer diff --git a/modules/processing.py b/modules/processing.py index 8a44d9477..b9a9f2edc 100644 --- a/modules/processing.py +++ b/modules/processing.py @@ -239,7 +239,6 @@ def process_init(p: StableDiffusionProcessing): if reset_prompts: p.all_prompts, p.all_negative_prompts = shared.prompt_styles.apply_styles_to_prompts(p.all_prompts, p.all_negative_prompts, p.styles, p.all_seeds) - def process_images_inner(p: StableDiffusionProcessing) -> Processed: """this is the main loop that both txt2img and img2img use; it calls func_init once inside all the scopes and func_sample once per batch""" if type(p.prompt) == list: diff --git a/modules/ui_common.py b/modules/ui_common.py index 1b8aea378..ec1d7f505 100644 --- a/modules/ui_common.py +++ b/modules/ui_common.py @@ -348,31 +348,37 @@ def create_override_inputs(tab): # pylint: disable=unused-argument return override_settings -def connect_reuse_seed(seed: gr.Number, reuse_seed: gr.Button, generation_info: gr.Textbox, is_subseed): +def connect_reuse_seed(seed: gr.Number, reuse_seed: gr.Button, generation_info: gr.Textbox, is_subseed, subseed_strength=None): """ Connects a 'reuse (sub)seed' button's click event so that it copies last used (sub)seed value from generation info the to the seed field. If copying subseed and subseed strength was 0, i.e. no variation seed was used, it copies the normal seed value instead.""" def copy_seed(gen_info_string: str, index: int): - res = -1 + restore_seed = -1 + restore_strength = -1 try: gen_info = json.loads(gen_info_string) shared.log.debug(f'Reuse: info={gen_info}') index -= gen_info.get('index_of_first_image', 0) index = int(index) - - if is_subseed and gen_info.get('subseed_strength', 0) > 0: + if is_subseed: all_subseeds = gen_info.get('all_subseeds', [-1]) - res = all_subseeds[index if 0 <= index < len(all_subseeds) else 0] + restore_seed = all_subseeds[index if 0 <= index < len(all_subseeds) else 0] + restore_strength = gen_info.get('subseed_strength', 0) else: all_seeds = gen_info.get('all_seeds', [-1]) - res = all_seeds[index if 0 <= index < len(all_seeds) else 0] + restore_seed = all_seeds[index if 0 <= index < len(all_seeds) else 0] except json.decoder.JSONDecodeError: if gen_info_string != '': shared.log.error(f"Error parsing JSON generation info: {gen_info_string}") - return [res, gr_show(False)] - + if is_subseed is not None: + return [restore_seed, gr_show(False), restore_strength] + else: + return [restore_seed, gr_show(False)] dummy_component = gr.Number(visible=False, value=0) - reuse_seed.click(fn=copy_seed, _js="(x, y) => [x, selected_gallery_index()]", show_progress=False, inputs=[generation_info, dummy_component], outputs=[seed, dummy_component]) + if subseed_strength is None: + reuse_seed.click(fn=copy_seed, _js="(x, y) => [x, selected_gallery_index()]", show_progress=False, inputs=[generation_info, dummy_component], outputs=[seed, dummy_component]) + else: + reuse_seed.click(fn=copy_seed, _js="(x, y) => [x, selected_gallery_index()]", show_progress=False, inputs=[generation_info, dummy_component], outputs=[seed, dummy_component, subseed_strength]) def update_token_counter(text, steps): diff --git a/modules/ui_img2img.py b/modules/ui_img2img.py index c8d82358a..09d0c5022 100644 --- a/modules/ui_img2img.py +++ b/modules/ui_img2img.py @@ -157,7 +157,7 @@ def create_ui(): img2img_gallery, img2img_generation_info, img2img_html_info, _img2img_html_info_formatted, img2img_html_log = ui_common.create_output_panel("img2img", prompt=img2img_prompt) ui_common.connect_reuse_seed(seed, reuse_seed, img2img_generation_info, is_subseed=False) - ui_common.connect_reuse_seed(subseed, reuse_subseed, img2img_generation_info, is_subseed=True) + ui_common.connect_reuse_seed(subseed, reuse_subseed, img2img_generation_info, is_subseed=True, subseed_strength=subseed_strength) img2img_prompt_img.change(fn=modules.images.image_data, inputs=[img2img_prompt_img], outputs=[img2img_prompt, img2img_prompt_img]) dummy_component1 = gr.Textbox(visible=False, value='dummy') diff --git a/modules/ui_sections.py b/modules/ui_sections.py index 724d9487f..b6082e839 100644 --- a/modules/ui_sections.py +++ b/modules/ui_sections.py @@ -136,7 +136,7 @@ def create_seed_inputs(tab, reuse_visible=True): with gr.Row(visible=False): seed_resize_from_w = gr.Slider(minimum=0, maximum=4096, step=8, label="Resize seed from width", value=0, elem_id=f"{tab}_seed_resize_from_w") seed_resize_from_h = gr.Slider(minimum=0, maximum=4096, step=8, label="Resize seed from height", value=0, elem_id=f"{tab}_seed_resize_from_h") - random_seed.click(fn=lambda: [-1, -1], show_progress=False, inputs=[], outputs=[seed, subseed]) + random_seed.click(fn=lambda: -1, show_progress=False, inputs=[], outputs=[seed]) random_subseed.click(fn=lambda: -1, show_progress=False, inputs=[], outputs=[subseed]) return seed, reuse_seed, subseed, reuse_subseed, subseed_strength, seed_resize_from_h, seed_resize_from_w diff --git a/modules/ui_txt2img.py b/modules/ui_txt2img.py index ab6545b8c..27d93fb7b 100644 --- a/modules/ui_txt2img.py +++ b/modules/ui_txt2img.py @@ -56,7 +56,7 @@ def create_ui(): txt2img_gallery, txt2img_generation_info, txt2img_html_info, _txt2img_html_info_formatted, txt2img_html_log = ui_common.create_output_panel("txt2img", preview=True, prompt=txt2img_prompt) ui_common.connect_reuse_seed(seed, reuse_seed, txt2img_generation_info, is_subseed=False) - ui_common.connect_reuse_seed(subseed, reuse_subseed, txt2img_generation_info, is_subseed=True) + ui_common.connect_reuse_seed(subseed, reuse_subseed, txt2img_generation_info, is_subseed=True, subseed_strength=subseed_strength) dummy_component = gr.Textbox(visible=False, value='dummy') txt2img_args = [ diff --git a/wiki b/wiki index 04cfbf213..b308811ab 160000 --- a/wiki +++ b/wiki @@ -1 +1 @@ -Subproject commit 04cfbf2132c6d5f5e5f5e5667934694e7dd36dd3 +Subproject commit b308811ab96e6eec771155c59bb295bebb6740df From 5a075f420e14c0d54d2488a6e598143dac0b1484 Mon Sep 17 00:00:00 2001 From: Vladimir Mandic Date: Sat, 1 Jun 2024 09:06:54 -0400 Subject: [PATCH 16/24] update schedulers --- CHANGELOG.md | 2 ++ modules/control/run.py | 7 +++++++ modules/generation_parameters_copypaste.py | 2 ++ modules/images.py | 5 +++-- modules/img2img.py | 1 + modules/processing_helpers.py | 1 + modules/sd_samplers.py | 1 + modules/sd_samplers_diffusers.py | 21 +++++++++++++-------- modules/txt2img.py | 2 ++ 9 files changed, 32 insertions(+), 10 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ee35c2b85..15a6d0cf1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,12 +8,14 @@ - fix control prompts list handling - fix variation seed with hires pass - fix restore variation seed and strength +- fix negative prompt parsing from metadata - workaround for scale-by when using modernui - lock torch-directml version - improve xformers installer - improve ultralytics installer - improve triton installer - improve insightface installer +- add dpm++ 1s and dpm++ 3m aliases for dpm++ 2m scheduler with different orders ## Update for 2024-05-28 diff --git a/modules/control/run.py b/modules/control/run.py index 5734c10b9..1357be713 100644 --- a/modules/control/run.py +++ b/modules/control/run.py @@ -86,6 +86,13 @@ def control_run(units: List[unit.Unit] = [], inputs: List[Image.Image] = [], ini if mask is not None and input_type == 0: input_type = 1 # inpaint always requires control_image + if sampler_index is None: + shared.log.warning('Sampler: invalid') + sampler_index = 0 + if hr_sampler_index is None: + shared.log.warning('Sampler: invalid') + hr_sampler_index = 0 + p = StableDiffusionProcessingControl( prompt = prompt, negative_prompt = negative, diff --git a/modules/generation_parameters_copypaste.py b/modules/generation_parameters_copypaste.py index 93b5d3dd1..97cf6d38f 100644 --- a/modules/generation_parameters_copypaste.py +++ b/modules/generation_parameters_copypaste.py @@ -217,6 +217,8 @@ def parse_generation_parameters(infotext, no_prompt=False): params.pop(next(iter(params))) params_idx = sanitized.find(f'{first_param}:') if first_param else -1 negative_idx = infotext.find("Negative prompt:") + if 'Steps:' in sanitized: + params_idx = max(params_idx, sanitized.find('Steps:')) if negative_idx == -1: # prompt can be without negative prompt prompt = infotext[:params_idx] if params_idx > 0 else infotext diff --git a/modules/images.py b/modules/images.py index 77bdb6f10..caf3a7cc4 100644 --- a/modules/images.py +++ b/modules/images.py @@ -231,7 +231,7 @@ def resize_image(resize_mode, im, width, height, upscaler_name=None, output_type return im.resize((w, h), resample=Image.Resampling.LANCZOS) # force for mask scale = max(w / im.width, h / im.height) if scale > 1.0: - upscalers = [x for x in shared.sd_upscalers if x.name == upscaler_name] + upscalers = [x for x in shared.sd_upscalers if x.name.lower().replace('-', ' ') == upscaler_name.lower().replace('-', ' ')] if len(upscalers) > 0: upscaler = upscalers[0] im = upscaler.scaler.upscale(im, scale, upscaler.data_path) @@ -240,8 +240,9 @@ def resize_image(resize_mode, im, width, height, upscaler_name=None, output_type if upscaler is not None: im = latent(im, w, h, upscaler) else: - upscaler = upscalers[0] + upscaler = shared.sd_upscalers[0] shared.log.warning(f"Resize upscaler: invalid={upscaler_name} fallback={upscaler.name}") + shared.log.debug(f"Resize upscaler: available={[u.name for u in shared.sd_upscalers]}") if im.width != w or im.height != h: # probably downsample after upscaler created larger image im = im.resize((w, h), resample=Image.Resampling.LANCZOS) return im diff --git a/modules/img2img.py b/modules/img2img.py index 210ec002a..319d02171 100644 --- a/modules/img2img.py +++ b/modules/img2img.py @@ -152,6 +152,7 @@ def img2img(id_task: str, mode: int, shared.log.debug('Init image not set') if sampler_index is None: + shared.log.warning('Sampler: invalid') sampler_index = 0 override_settings = create_override_settings_dict(override_settings_texts) diff --git a/modules/processing_helpers.py b/modules/processing_helpers.py index 3d4ae2a43..dd8d6faf5 100644 --- a/modules/processing_helpers.py +++ b/modules/processing_helpers.py @@ -526,6 +526,7 @@ def update_sampler(p, sd_model, second_pass=False): if hasattr(sd_model, 'scheduler') and sampler_selection != 'Default': sampler = sd_samplers.all_samplers_map.get(sampler_selection, None) if sampler is None: + shared.log.warning(f'Sampler: sampler="{sampler_selection}" not found') sampler = sd_samplers.all_samplers_map.get("UniPC") if len(getattr(p, 'timesteps', [])) > 0: if 'schedulers_use_karras' in shared.opts.data: diff --git a/modules/sd_samplers.py b/modules/sd_samplers.py index 6ae5a5fe2..8379ac3c9 100644 --- a/modules/sd_samplers.py +++ b/modules/sd_samplers.py @@ -55,6 +55,7 @@ def create_sampler(name, model): return model.scheduler config = find_sampler_config(name) if config is None or config.constructor is None: + shared.log.warning(f'Sampler: sampler="{name}" not found') return None if shared.backend == shared.Backend.ORIGINAL: sampler = config.constructor(model) diff --git a/modules/sd_samplers_diffusers.py b/modules/sd_samplers_diffusers.py index be6aedb42..fbf40c9e6 100644 --- a/modules/sd_samplers_diffusers.py +++ b/modules/sd_samplers_diffusers.py @@ -46,7 +46,9 @@ config = { 'UniPC': { 'solver_order': 2, 'thresholding': False, 'sample_max_value': 1.0, 'predict_x0': 'bh2', 'lower_order_final': True, 'timestep_spacing': 'linspace' }, 'DEIS': { 'solver_order': 2, 'thresholding': False, 'sample_max_value': 1.0, 'algorithm_type': "deis", 'solver_type': "logrho", 'lower_order_final': True, 'timestep_spacing': 'linspace' }, 'DPM++': { 'solver_order': 2, 'thresholding': False, 'sample_max_value': 1.0, 'algorithm_type': "dpmsolver++", 'solver_type': "midpoint", 'lower_order_final': True, 'use_karras_sigmas': False, 'final_sigmas_type': 'sigma_min' }, - 'DPM++ 2M': { 'thresholding': False, 'sample_max_value': 1.0, 'algorithm_type': "dpmsolver++", 'solver_type': "midpoint", 'lower_order_final': True, 'use_karras_sigmas': False, 'final_sigmas_type': 'zero', 'timestep_spacing': 'linspace' }, + 'DPM++ 1S': { 'thresholding': False, 'sample_max_value': 1.0, 'algorithm_type': "dpmsolver++", 'solver_type': "midpoint", 'lower_order_final': True, 'use_karras_sigmas': False, 'final_sigmas_type': 'zero', 'timestep_spacing': 'linspace', 'solver_order': 1 }, + 'DPM++ 2M': { 'thresholding': False, 'sample_max_value': 1.0, 'algorithm_type': "dpmsolver++", 'solver_type': "midpoint", 'lower_order_final': True, 'use_karras_sigmas': False, 'final_sigmas_type': 'zero', 'timestep_spacing': 'linspace', 'solver_order': 2 }, + 'DPM++ 3M': { 'thresholding': False, 'sample_max_value': 1.0, 'algorithm_type': "dpmsolver++", 'solver_type': "midpoint", 'lower_order_final': True, 'use_karras_sigmas': False, 'final_sigmas_type': 'zero', 'timestep_spacing': 'linspace', 'solver_order': 3 }, 'DPM SDE': { 'use_karras_sigmas': False, 'noise_sampler_seed': None, 'timestep_spacing': 'linspace', 'steps_offset': 0 }, 'Euler a': { 'rescale_betas_zero_snr': False, 'timestep_spacing': 'linspace' }, 'Euler': { 'interpolation_type': "linear", 'use_karras_sigmas': False, 'rescale_betas_zero_snr': False, 'timestep_spacing': 'linspace' }, @@ -77,7 +79,9 @@ samplers_data_diffusers = [ sd_samplers_common.SamplerData('Euler', lambda model: DiffusionSampler('Euler', EulerDiscreteScheduler, model), [], {}), sd_samplers_common.SamplerData('Euler a', lambda model: DiffusionSampler('Euler a', EulerAncestralDiscreteScheduler, model), [], {}), sd_samplers_common.SamplerData('DPM++', lambda model: DiffusionSampler('DPM++', DPMSolverSinglestepScheduler, model), [], {}), + sd_samplers_common.SamplerData('DPM++ 1S', lambda model: DiffusionSampler('DPM++ 1S', DPMSolverMultistepScheduler, model), [], {}), sd_samplers_common.SamplerData('DPM++ 2M', lambda model: DiffusionSampler('DPM++ 2M', DPMSolverMultistepScheduler, model), [], {}), + sd_samplers_common.SamplerData('DPM++ 3M', lambda model: DiffusionSampler('DPM++ 3M', DPMSolverMultistepScheduler, model), [], {}), sd_samplers_common.SamplerData('DPM SDE', lambda model: DiffusionSampler('DPM SDE', DPMSolverSDEScheduler, model), [], {}), sd_samplers_common.SamplerData('PNDM', lambda model: DiffusionSampler('PNDM', PNDMScheduler, model), [], {}), @@ -107,10 +111,7 @@ class DiffusionSampler: return for key, value in config.get('All', {}).items(): # apply global defaults self.config[key] = value - # shared.log.debug(f'Sampler: name={name} type=all config={self.config}') - for key, value in config.get(name, {}).items(): # apply diffusers per-scheduler defaults - self.config[key] = value - # shared.log.debug(f'Sampler: name={name} type=scheduler config={self.config}') + print('HERE1', name, self.config.get('solver_order', None)) if hasattr(model.scheduler, 'scheduler_config'): # find model defaults orig_config = model.scheduler.scheduler_config else: @@ -118,11 +119,14 @@ class DiffusionSampler: for key, value in orig_config.items(): # apply model defaults if key in self.config: self.config[key] = value - # shared.log.debug(f'Sampler: name={name} type=model config={self.config}') + print('HERE2', name, self.config.get('solver_order', None)) + for key, value in config.get(name, {}).items(): # apply diffusers per-scheduler defaults + self.config[key] = value + print('HERE3', name, self.config.get('solver_order', None)) for key, value in kwargs.items(): # apply user args, if any if key in self.config: self.config[key] = value - # shared.log.debug(f'Sampler: name={name} type=user config={self.config}') + print('HERE4', name, self.config.get('solver_order', None)) # finally apply user preferences if shared.opts.schedulers_prediction_type != 'default': self.config['prediction_type'] = shared.opts.schedulers_prediction_type @@ -136,7 +140,7 @@ class DiffusionSampler: self.config['thresholding'] = shared.opts.schedulers_use_thresholding if 'lower_order_final' in self.config: self.config['lower_order_final'] = shared.opts.schedulers_use_loworder - if 'solver_order' in self.config: + if 'solver_order' in self.config and 'DPM' not in name: self.config['solver_order'] = shared.opts.schedulers_solver_order if 'predict_x0' in self.config: self.config['predict_x0'] = shared.opts.uni_pc_variant @@ -165,6 +169,7 @@ class DiffusionSampler: del self.config['prediction_type'] if 'SGM' in name: self.config['timestep_spacing'] = 'trailing' + print('HERE5', name, self.config.get('solver_order', None)) # validate all config params signature = inspect.signature(constructor, follow_wrapped=True) possible = signature.parameters.keys() diff --git a/modules/txt2img.py b/modules/txt2img.py index d0d1d8b9a..56abf3de4 100644 --- a/modules/txt2img.py +++ b/modules/txt2img.py @@ -32,8 +32,10 @@ def txt2img(id_task, override_settings = create_override_settings_dict(override_settings_texts) if sampler_index is None: + shared.log.warning('Sampler: invalid') sampler_index = 0 if hr_sampler_index is None: + shared.log.warning('Sampler: invalid') hr_sampler_index = 0 p = processing.StableDiffusionProcessingTxt2Img( From 5596947ba477e6949c298bdf2d6e13cce2ced059 Mon Sep 17 00:00:00 2001 From: Vladimir Mandic Date: Sat, 1 Jun 2024 09:16:47 -0400 Subject: [PATCH 17/24] update notes --- TODO.md | 1 + 1 file changed, 1 insertion(+) diff --git a/TODO.md b/TODO.md index 14dc2c73a..dfac1d65b 100644 --- a/TODO.md +++ b/TODO.md @@ -22,6 +22,7 @@ Main ToDo list can be found at [GitHub projects](https://github.com/users/vladma - lora: sc lora, dora, etc - controlnet: additional models - resadapter: +- t-gate: ## Experimental From 7998f405da03233ca934f41d9b0834dc4e8a4512 Mon Sep 17 00:00:00 2001 From: Vladimir Mandic Date: Sat, 1 Jun 2024 09:44:53 -0400 Subject: [PATCH 18/24] fix subseed if seed is set --- modules/processing.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/modules/processing.py b/modules/processing.py index b9a9f2edc..211f790b8 100644 --- a/modules/processing.py +++ b/modules/processing.py @@ -232,8 +232,9 @@ def process_init(p: StableDiffusionProcessing): for i in range(len(p.all_prompts)): seed = get_fixed_seed(p.seed) p.all_seeds.append(int(seed) + (i if p.subseed_strength == 0 else 0)) + if p.all_subseeds is None: if type(subseed) == list: - p.all_subseeds = subseed + p.all_subseeds = [int(s) for s in subseed] else: p.all_subseeds = [int(subseed) + x for x in range(len(p.all_prompts))] if reset_prompts: From 06f9d6b6e441f0eba4b4cf8ad995a52ad4fcb5dd Mon Sep 17 00:00:00 2001 From: Disty0 Date: Sat, 1 Jun 2024 17:52:19 +0300 Subject: [PATCH 19/24] Cascade fix progress bar --- modules/processing_diffusers.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/modules/processing_diffusers.py b/modules/processing_diffusers.py index 9eddf3fba..5b2361431 100644 --- a/modules/processing_diffusers.py +++ b/modules/processing_diffusers.py @@ -103,7 +103,7 @@ def process_diffusers(p: processing.StableDiffusionProcessing): clip_skip=p.clip_skip, desc='Base', ) - shared.state.sampling_steps = base_args.get('num_inference_steps', None) or p.steps + shared.state.sampling_steps = base_args.get('prior_num_inference_steps', None) or base_args.get('num_inference_steps', None) or p.steps p.extra_generation_params['Pipeline'] = shared.sd_model.__class__.__name__ if shared.opts.scheduler_eta is not None and shared.opts.scheduler_eta > 0 and shared.opts.scheduler_eta < 1: p.extra_generation_params["Sampler Eta"] = shared.opts.scheduler_eta @@ -211,7 +211,7 @@ def process_diffusers(p: processing.StableDiffusionProcessing): desc='Hires', ) shared.state.job = 'HiRes' - shared.state.sampling_steps = hires_args.get('num_inference_steps', None) or p.steps + shared.state.sampling_steps = hires_args.get('prior_num_inference_steps', None) or hires_args.get('num_inference_steps', None) or p.steps try: sd_models_compile.check_deepcache(enable=True) output = shared.sd_model(**hires_args) # pylint: disable=not-callable @@ -276,7 +276,7 @@ def process_diffusers(p: processing.StableDiffusionProcessing): clip_skip=p.clip_skip, desc='Refiner', ) - shared.state.sampling_steps = refiner_args.get('num_inference_steps', None) or p.steps + shared.state.sampling_steps = refiner_args.get('prior_num_inference_steps', None) or refiner_args.get('num_inference_steps', None) or p.steps try: if 'requires_aesthetics_score' in shared.sd_refiner.config: # sdxl-model needs false and sdxl-refiner needs true shared.sd_refiner.register_to_config(requires_aesthetics_score = getattr(shared.sd_refiner, 'tokenizer', None) is None) From e084d5095672eec134132bb4e524358d9b1f61d2 Mon Sep 17 00:00:00 2001 From: Vladimir Mandic Date: Sat, 1 Jun 2024 14:00:49 -0400 Subject: [PATCH 20/24] cleanup sampler debug code --- modules/sd_samplers_diffusers.py | 5 ----- 1 file changed, 5 deletions(-) diff --git a/modules/sd_samplers_diffusers.py b/modules/sd_samplers_diffusers.py index fbf40c9e6..d7c2e5d0f 100644 --- a/modules/sd_samplers_diffusers.py +++ b/modules/sd_samplers_diffusers.py @@ -111,7 +111,6 @@ class DiffusionSampler: return for key, value in config.get('All', {}).items(): # apply global defaults self.config[key] = value - print('HERE1', name, self.config.get('solver_order', None)) if hasattr(model.scheduler, 'scheduler_config'): # find model defaults orig_config = model.scheduler.scheduler_config else: @@ -119,14 +118,11 @@ class DiffusionSampler: for key, value in orig_config.items(): # apply model defaults if key in self.config: self.config[key] = value - print('HERE2', name, self.config.get('solver_order', None)) for key, value in config.get(name, {}).items(): # apply diffusers per-scheduler defaults self.config[key] = value - print('HERE3', name, self.config.get('solver_order', None)) for key, value in kwargs.items(): # apply user args, if any if key in self.config: self.config[key] = value - print('HERE4', name, self.config.get('solver_order', None)) # finally apply user preferences if shared.opts.schedulers_prediction_type != 'default': self.config['prediction_type'] = shared.opts.schedulers_prediction_type @@ -169,7 +165,6 @@ class DiffusionSampler: del self.config['prediction_type'] if 'SGM' in name: self.config['timestep_spacing'] = 'trailing' - print('HERE5', name, self.config.get('solver_order', None)) # validate all config params signature = inspect.signature(constructor, follow_wrapped=True) possible = signature.parameters.keys() From f55e14be9abe523b107d45f79c6c3d78c50b74d2 Mon Sep 17 00:00:00 2001 From: Vladimir Mandic Date: Sat, 1 Jun 2024 14:14:51 -0400 Subject: [PATCH 21/24] add variation seed to metadata --- CHANGELOG.md | 4 +++- modules/processing_info.py | 2 -- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 15a6d0cf1..67d38df12 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,9 +6,11 @@ - fix gallery mtime display - fix extra network scrollable area when using modernui - fix control prompts list handling -- fix variation seed with hires pass - fix restore variation seed and strength - fix negative prompt parsing from metadata +- fix stable cascade progress monitoring +- fix variation seed with hires pass +- add variation seed info to metadata - workaround for scale-by when using modernui - lock torch-directml version - improve xformers installer diff --git a/modules/processing_info.py b/modules/processing_info.py index 5f60fb1a1..809d87115 100644 --- a/modules/processing_info.py +++ b/modules/processing_info.py @@ -64,8 +64,6 @@ def create_infotext(p: StableDiffusionProcessing, all_prompts=None, all_seeds=No "Operations": '; '.join(ops).replace('"', '') if len(p.ops) > 0 else 'none', } if 'txt2img' in p.ops: - pass - if shared.backend == shared.Backend.ORIGINAL: args["Variation seed"] = all_subseeds[index] if p.subseed_strength > 0 else None args["Variation strength"] = p.subseed_strength if p.subseed_strength > 0 else None if 'hires' in p.ops or 'upscale' in p.ops: From 1015dcc76bc99ecc227df369494f3f71977f4fba Mon Sep 17 00:00:00 2001 From: Vladimir Mandic Date: Sat, 1 Jun 2024 15:18:47 -0400 Subject: [PATCH 22/24] cleanup --- modules/sd_samplers.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/sd_samplers.py b/modules/sd_samplers.py index 8379ac3c9..e93998d9d 100644 --- a/modules/sd_samplers.py +++ b/modules/sd_samplers.py @@ -55,7 +55,7 @@ def create_sampler(name, model): return model.scheduler config = find_sampler_config(name) if config is None or config.constructor is None: - shared.log.warning(f'Sampler: sampler="{name}" not found') + # shared.log.warning(f'Sampler: sampler="{name}" not found') return None if shared.backend == shared.Backend.ORIGINAL: sampler = config.constructor(model) From 7ea81450ba3b02cb1c41ba1dea21f280cbb2a4af Mon Sep 17 00:00:00 2001 From: Vladimir Mandic Date: Sun, 2 Jun 2024 11:18:39 -0400 Subject: [PATCH 23/24] update mim installer --- CHANGELOG.md | 9 +++++---- installer.py | 5 +++-- modules/control/proc/dwpose/__init__.py | 16 +++++++++++++--- wiki | 2 +- 4 files changed, 22 insertions(+), 10 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 67d38df12..1df6a537c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,6 @@ # Change Log for SD.Next -## Update for 2024-06-01 +## Update for 2024-06-02 - fix textual inversion loading - fix gallery mtime display @@ -14,9 +14,10 @@ - workaround for scale-by when using modernui - lock torch-directml version - improve xformers installer -- improve ultralytics installer -- improve triton installer -- improve insightface installer +- improve ultralytics installer (face-hires) +- improve triton installer (compile) +- improve insightface installer (faceip) +- improve mim installer (dwpose) - add dpm++ 1s and dpm++ 3m aliases for dpm++ 2m scheduler with different orders ## Update for 2024-05-28 diff --git a/installer.py b/installer.py index 4c268cac8..88f50e5d4 100644 --- a/installer.py +++ b/installer.py @@ -252,13 +252,14 @@ def pip(arg: str, ignore: bool = False, quiet: bool = False): # install package using pip if not already installed @lru_cache() -def install(package, friendly: str = None, ignore: bool = False, reinstall: bool = False): +def install(package, friendly: str = None, ignore: bool = False, reinstall: bool = False, no_deps: bool = False): res = '' if args.reinstall or args.upgrade: global quick_allowed # pylint: disable=global-statement quick_allowed = False if args.reinstall or reinstall or not installed(package, friendly, quiet=False): - res = pip(f"install --upgrade {package}", ignore=ignore) + deps = '' if not no_deps else '--no-deps' + res = pip(f"install --upgrade {deps} {package}", ignore=ignore) try: import imp # pylint: disable=deprecated-module imp.reload(pkg_resources) diff --git a/modules/control/proc/dwpose/__init__.py b/modules/control/proc/dwpose/__init__.py index 45039e920..4ae62c133 100644 --- a/modules/control/proc/dwpose/__init__.py +++ b/modules/control/proc/dwpose/__init__.py @@ -9,6 +9,7 @@ os.environ["KMP_DUPLICATE_LIB_OK"]="TRUE" import cv2 import numpy as np from PIL import Image +from installer import installed, install, log from modules.control.util import HWC3, resize_image from .draw import draw_bodypose, draw_handpose, draw_facepose checked_ok = False @@ -16,11 +17,17 @@ checked_ok = False def check_dependencies(): global checked_ok # pylint: disable=global-statement - from installer import installed, install, log - packages = [('openmim', 'openmim'), ('mmengine', 'mmengine'), ('mmcv', 'mmcv'), ('mmpose', 'mmpose'), ('mmdet', 'mmdet')] + packages = [ + ('openmim==0.3.9', 'openmim'), + ('mmengine==0.10.4', 'mmengine'), + ('mmcv==2.1.0', 'mmcv'), + ('mmpose==1.3.1', 'mmpose'), + ('mmdet==3.3.0', 'mmdet'), + ] + packages = [] for pkg in packages: if not installed(pkg[1], reload=True, quiet=True): - install(pkg[0], pkg[1], ignore=False) + install(pkg[0], pkg[1], ignore=False, no_deps=True) try: import mmcv # pylint: disable=unused-import checked_ok = True @@ -46,6 +53,7 @@ def draw_pose(pose, H, W): class DWposeDetector: def __init__(self, det_config=None, det_ckpt=None, pose_config=None, pose_ckpt=None, device="cpu"): + self.pose_estimation = None if not checked_ok: if not check_dependencies(): return @@ -57,6 +65,8 @@ class DWposeDetector: return self def __call__(self, input_image, detect_resolution=512, image_resolution=512, output_type="pil", min_confidence=0.3, **kwargs): + if self.pose_estimation is None: + log.error("DWPose: not loaded") input_image = cv2.cvtColor(np.array(input_image, dtype=np.uint8), cv2.COLOR_RGB2BGR) input_image = HWC3(input_image) diff --git a/wiki b/wiki index b308811ab..709796f97 160000 --- a/wiki +++ b/wiki @@ -1 +1 @@ -Subproject commit b308811ab96e6eec771155c59bb295bebb6740df +Subproject commit 709796f9753081ebe74d723118b2482bf633fae5 From 3cd12c51f5edcdd64e6156e8e19724c21c613c36 Mon Sep 17 00:00:00 2001 From: Vladimir Mandic Date: Sun, 2 Jun 2024 11:51:42 -0400 Subject: [PATCH 24/24] fix loading models --- CHANGELOG.md | 1 + modules/processing_helpers.py | 3 ++- modules/sd_models.py | 4 +++- modules/styles.py | 6 +++++- 4 files changed, 11 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1df6a537c..fda471333 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ - fix negative prompt parsing from metadata - fix stable cascade progress monitoring - fix variation seed with hires pass +- fix loading models trained with onetrainer - add variation seed info to metadata - workaround for scale-by when using modernui - lock torch-directml version diff --git a/modules/processing_helpers.py b/modules/processing_helpers.py index dd8d6faf5..bf86f1e24 100644 --- a/modules/processing_helpers.py +++ b/modules/processing_helpers.py @@ -216,7 +216,8 @@ def decode_first_stage(model, x, full_quality=True): def get_fixed_seed(seed): if seed is None or seed == '' or seed == -1: - return int(random.randrange(4294967294)) + random.seed() + seed = int(random.randrange(4294967294)) return seed diff --git a/modules/sd_models.py b/modules/sd_models.py index d78a5a6b9..607606a94 100644 --- a/modules/sd_models.py +++ b/modules/sd_models.py @@ -12,10 +12,11 @@ import os.path from os import mkdir from urllib import request from enum import Enum +import diffusers +import diffusers.loaders.single_file_utils from rich import progress # pylint: disable=redefined-builtin import torch import safetensors.torch -import diffusers from omegaconf import OmegaConf from transformers import logging as transformers_logging from ldm.util import instantiate_from_config @@ -1056,6 +1057,7 @@ def load_diffuser(checkpoint_info=None, already_loaded_state_dict=None, timer=No else: diffusers_load_config['config'] = get_load_config(checkpoint_info.path, model_type, config_type='json') if hasattr(pipeline, 'from_single_file'): + diffusers.loaders.single_file_utils.CHECKPOINT_KEY_NAMES["clip"] = "cond_stage_model.transformer.text_model.embeddings.position_embedding.weight" # TODO patch for diffusers==0.28.0 diffusers_load_config['use_safetensors'] = True diffusers_load_config['cache_dir'] = shared.opts.hfcache_dir # use hfcache instead of diffusers dir as this is for config only in case of single-file if shared.opts.disable_accelerate: diff --git a/modules/styles.py b/modules/styles.py index 4e3b55a41..511cfc425 100644 --- a/modules/styles.py +++ b/modules/styles.py @@ -81,8 +81,10 @@ def apply_file_wildcards(prompt, replaced = [], not_found = [], recursion=0, see def apply_wildcards_to_prompt(prompt, all_wildcards, seed=-1, silent=False): if len(prompt) == 0: return prompt - if seed > 0: + old_state = None + if seed > 0 and len(all_wildcards) > 0: random.seed(seed) + old_state = random.getstate() replaced = {} t0 = time.time() for style_wildcards in all_wildcards: @@ -104,6 +106,8 @@ def apply_wildcards_to_prompt(prompt, all_wildcards, seed=-1, silent=False): shared.log.debug(f'Wildcards applied: {replaced} path="{shared.opts.wildcards_dir}" type=style time={t1-t0:.2f}') if (len(replaced_file) > 0 or len(not_found) > 0) and not silent: shared.log.debug(f'Wildcards applied: {replaced_file} missing: {not_found} path="{shared.opts.wildcards_dir}" type=file time={t2-t2:.2f} ') + if old_state is not None: + random.setstate(old_state) return prompt