From 39a37597b5be531322fcfb7f2a565d4fbaf1deb4 Mon Sep 17 00:00:00 2001 From: AI-Casanova <54461896+AI-Casanova@users.noreply.github.com> Date: Fri, 3 Nov 2023 14:55:57 -0500 Subject: [PATCH 01/84] Further UI Work --- modules/extras.py | 106 +++++++++++++++++++++++++++++++ modules/ui_common.py | 4 +- modules/ui_models.py | 147 ++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 254 insertions(+), 3 deletions(-) diff --git a/modules/extras.py b/modules/extras.py index a84b9b28e..0d5fc2c76 100644 --- a/modules/extras.py +++ b/modules/extras.py @@ -8,6 +8,7 @@ import torch import tqdm import gradio as gr import safetensors.torch +from sd_meh.merge import merge_models from modules import shared, images, sd_models, sd_vae, sd_models_config @@ -239,6 +240,111 @@ def run_modelmerger(id_task, primary_model_name, secondary_model_name, tertiary_ shared.state.end() return [*[gr.Dropdown.update(choices=sd_models.checkpoint_tiles()) for _ in range(4)], "Checkpoint saved to " + output_modelname] + +def run_MEHmodelmerger(id_task, primary_model_name, secondary_model_name, tertiary_model_name, merge_mode,base_alpha, + base_beta, weights_alpha, + weights_beta, precision, custom_name, checkpoint_format, save_metadata, preset, weights_clip, prune, + re_basin, re_basin_iterations, device): # pylint: disable=unused-argument + shared.state.begin('model-merge') + models = { + "model_a": sd_models.checkpoints_list[primary_model_name].filename, + "model_b": sd_models.checkpoints_list[secondary_model_name].filename, + } + if tertiary_model_name is not None: + models |= {"model_c": sd_models.checkpoints_list[tertiary_model_name].filename} + work_device = device + threads = 1 + preset = preset if preset != "None" else None + block_weights_preset_alpha = block_weights_preset_beta = block_weights_preset_alpha_b = block_weights_preset_beta_b = preset if preset is not None else None + presets_alpha_lambda = presets_beta_lambda = None + logging_level = "INFO" + + + def fail(message): + shared.state.textinfo = message + shared.state.end() + return [*[gr.update() for _ in range(4)], message] + + + + theta_0 = main( + model_a, + model_b, + model_c, + merge_mode, + weights_clip, + precision, + str(weights_alpha), + base_alpha, + str(weights_beta), + base_beta, + re_basin, + re_basin_iterations, + device, + work_device, + prune, + block_weights_preset_alpha, + block_weights_preset_beta, + threads, + block_weights_preset_alpha_b, + block_weights_preset_beta_b, + presets_alpha_lambda, + presets_beta_lambda, + logging_level, + ) + ckpt_dir = shared.opts.ckpt_dir or sd_models.model_path + filename = custom_name + filename += "." + checkpoint_format + output_modelname = os.path.join(ckpt_dir, filename) + shared.state.textinfo = "Saving" + metadata = None + if save_metadata: + metadata = {"format": "pt", "sd_merge_models": {}} + merge_recipe = { + "type": "webui", # indicate this model was merged with webui's built-in merger + "primary_model_hash": primary_model_info.sha256, + "secondary_model_hash": secondary_model_info.sha256 if secondary_model_info else None, + "tertiary_model_hash": tertiary_model_info.sha256 if tertiary_model_info else None, + "interp_method": interp_method, + "multiplier": multiplier, + "save_as_half": save_as_half, + "custom_name": custom_name, + } + metadata["sd_merge_recipe"] = json.dumps(merge_recipe) + + def add_model_metadata(checkpoint_info): + checkpoint_info.calculate_shorthash() + metadata["sd_merge_models"][checkpoint_info.sha256] = { + "name": checkpoint_info.name, + "legacy_hash": checkpoint_info.hash, + "sd_merge_recipe": checkpoint_info.metadata.get("sd_merge_recipe", None) + } + metadata["sd_merge_models"].update(checkpoint_info.metadata.get("sd_merge_models", {})) + + add_model_metadata(primary_model_info) + if secondary_model_info: + add_model_metadata(secondary_model_info) + if tertiary_model_info: + add_model_metadata(tertiary_model_info) + metadata["sd_merge_models"] = json.dumps(metadata["sd_merge_models"]) + + _, extension = os.path.splitext(output_modelname) + if extension.lower() == ".safetensors": + safetensors.torch.save_file(theta_0, output_modelname, metadata=metadata) + else: + torch.save(theta_0, output_modelname) + + sd_models.list_models() + created_model = next((ckpt for ckpt in sd_models.checkpoints_list.values() if ckpt.name == filename), None) + if created_model: + created_model.calculate_shorthash() + create_config(output_modelname, config_source, primary_model_info, secondary_model_info, tertiary_model_info) + shared.log.info(f"Model merge saved: {output_modelname}.") + shared.state.textinfo = "Checkpoint saved" + shared.state.end() + return [*[gr.Dropdown.update(choices=sd_models.checkpoint_tiles()) for _ in range(4)], + "Checkpoint saved to " + output_modelname] + def run_modelconvert(model, checkpoint_formats, precision, conv_type, custom_name, unet_conv, text_encoder_conv, vae_conv, others_conv, fix_clip): # position_ids in clip is int64. model_ema.num_updates is int32 diff --git a/modules/ui_common.py b/modules/ui_common.py index c5d1fe62e..8b4733b73 100644 --- a/modules/ui_common.py +++ b/modules/ui_common.py @@ -231,7 +231,7 @@ def create_output_panel(tabname): return result_gallery, generation_info, html_info, html_info_formatted, html_log -def create_refresh_button(refresh_component, refresh_method, refreshed_args, elem_id): +def create_refresh_button(refresh_component, refresh_method, refreshed_args, elem_id, visible: bool = True): def refresh(): refresh_method() @@ -241,7 +241,7 @@ def create_refresh_button(refresh_component, refresh_method, refreshed_args, ele return gr.update(**(args or {})) from modules.ui_components import ToolButton - refresh_button = ToolButton(value=symbols.refresh, elem_id=elem_id) + refresh_button = ToolButton(value=symbols.refresh, elem_id=elem_id, visible=visible) refresh_button.click(fn=refresh, inputs=[], outputs=[refresh_component]) return refresh_button diff --git a/modules/ui_models.py b/modules/ui_models.py index e84300963..e5115662c 100644 --- a/modules/ui_models.py +++ b/modules/ui_models.py @@ -3,12 +3,16 @@ import json from datetime import datetime import gradio as gr from modules import sd_models, sd_vae, extras -from modules.ui_components import FormRow, ToolButton +from modules.ui_components import FormRow, ToolButton, InputAccordion from modules.ui_common import create_refresh_button from modules.call_queue import wrap_gradio_gpu_call from modules.shared import opts, log, req import modules.errors import modules.hashes +from sd_meh import merge_methods +from sd_meh.utils import BETA_METHODS, TRIPLE_METHODS, interpolate +from sd_meh.presets import BLOCK_WEIGHTS_PRESETS + search_metadata_civit = None @@ -136,6 +140,147 @@ def create_ui(): models_outcome, ] ) + with gr.Tab(label="MEH Merge"): + def sd_model_choices(): + return ['None'] + sd_models.checkpoint_tiles() + with gr.Row(equal_height=False): + with gr.Column(variant='compact'): + with FormRow(): + custom_name = gr.Textbox(label="New model name") + with FormRow(): + merge_mode = gr.Dropdown(choices=merge_methods.__all__, value="weighted_sum", label="Interpolation Method") + with FormRow(): + primary_model_name = gr.Dropdown(sd_model_choices(), label="Primary model", value="None") + create_refresh_button(primary_model_name, sd_models.list_models, lambda: {"choices": sd_model_choices()}, "refresh_checkpoint_A") + secondary_model_name = gr.Dropdown(sd_model_choices(), label="Secondary model", value="None") + create_refresh_button(secondary_model_name, sd_models.list_models, lambda: {"choices": sd_model_choices()}, "refresh_checkpoint_B") + tertiary_model_name = gr.Dropdown(sd_model_choices(), label="Tertiary model", value="None", visible=False) + tertiary_refresh = create_refresh_button(tertiary_model_name, sd_models.list_models, lambda: {"choices": sd_model_choices()}, "refresh_checkpoint_C",visible=False) + with FormRow(): + alpha = gr.Slider(minimum=0.0, maximum=1.0, step=0.05, label='Alpha Ratio', value=0.5) + beta = gr.Slider(minimum=0.0, maximum=1.0, step=0.05, label='Beta Ratio', value=None, visible=False) + with InputAccordion(False, label="Block Merge", elem_id=f"block_merge") as block_accordion: + with FormRow(): + alpha_label = gr.Markdown("# Alpha") + with FormRow(): + preset = gr.Dropdown(choices=["None"]+list(BLOCK_WEIGHTS_PRESETS.keys()), value=None, label="Block Weight Preset", multiselect=True, max_choices=2) + preset_lambda = gr.Slider(minimum=0.0, maximum=1.0, step=0.05, label='Preset Interpolation Ratio', value=None, visible=False) + apply_preset = ToolButton('⇩', visible=True) + with FormRow(): + base = gr.Textbox(value=None, label="Base", scale=1) + in_blocks = gr.Textbox(value=None, label="In Blocks", scale=10) + mid_block = gr.Textbox(value=None, label="Mid Block", scale=1) + out_blocks = gr.Textbox(value=None, label="Out Block", scale=10) + with FormRow(): + beta_label = gr.Markdown("# Beta", visible=False) + with FormRow(): + beta_preset = gr.Dropdown(choices=["None"]+list(BLOCK_WEIGHTS_PRESETS.keys()), value=None, label="Block Weight Preset", multiselect=True, max_choices=2, interactive=True, visible=False) + beta_preset_lambda = gr.Slider(minimum=0.0, maximum=1.0, step=0.05, label='Preset Interpolation Ratio', value=None, interactive=True, visible=False) + beta_apply_preset = ToolButton('⇩', interactive=True, visible=False) + with FormRow(): + beta_base = gr.Textbox(value=None, label="Base", scale=1, interactive=True, visible=False) + beta_in_blocks = gr.Textbox(value=None, label="In Blocks", interactive=True, scale=10, visible=False) + beta_mid_block = gr.Textbox(value=None, label="Mid Block", interactive=True, scale=1, visible=False) + beta_out_blocks = gr.Textbox(value=None, label="Out Block", interactive=True, scale=10, visible=False) + with FormRow(): + weights_clip = gr.Checkbox(label="Weights Clip") + prune = gr.Checkbox(label="Prune") + re_basin = gr.Checkbox(label="ReBasin") + with FormRow(): + re_basin_iterations = gr.Slider(minimum=0, maximum=25, step=1, label='Number of ReBasin Iterations', value=None, visible=False) + with FormRow(): + checkpoint_format = gr.Radio(choices=["ckpt", "safetensors"], value="safetensors", label="Model format") + with FormRow(): + precision = gr.Radio(choices=["fp16", "fp32"], value="fp16", label="Model precision") + with FormRow(): + device = gr.Radio(choices=["cpu", "cuda"], value="cpu", label="Device") + with FormRow(): + bake_in_vae = gr.Dropdown(choices=["None"] + list(sd_vae.vae_dict), value="None", label="Bake in VAE") + create_refresh_button(bake_in_vae, sd_vae.refresh_vae_list, lambda: {"choices": ["None"] + list(sd_vae.vae_dict)}, "modelmerger_refresh_bake_in_vae") + with FormRow(): + save_metadata = gr.Checkbox(value=True, label="Save metadata") + with gr.Row(): + MEHmodelmerger_merge = gr.Button(value="Merge", variant='primary') + + def MEHmodelmerger(*args): + try: + results = extras.run_MEHmodelmerger(*args) + except Exception as e: + modules.errors.display(e, 'model merge') + sd_models.list_models() # to remove the potentially missing models from the list + return [*[gr.Dropdown.update(choices=sd_models.checkpoint_tiles()) for _ in range(4)], f"Error merging checkpoints: {e}"] + return results + + def tertiary(mode): + if mode in TRIPLE_METHODS: + return [gr.update(visible=True) for _ in range(2)] + else: + return [gr.update(visible=False) for _ in range(2)] + + def beta_visibility(mode): + if mode in BETA_METHODS: + return [gr.update(visible=True) for _ in range(9)] + else: + return [gr.update(visible=False) for _ in range(9)] + def show_iters(show): + if show: + return gr.Slider.update(value=5, visible=True) + else: + return gr.Slider.update(value=None, visible=False) + def preset_visiblility(x): + if len(x) == 2: + return gr.Slider.update(value=0.5, visible=True) + else: + return gr.Slider.update(value=None, visible=False) + + def load_presets(presets,ratio): + for i, p in enumerate(presets): + presets[i] = BLOCK_WEIGHTS_PRESETS[p] + if len(presets) == 2: + preset = interpolate(presets, ratio) + else: + preset = presets[0] + preset = [str(x) for x in preset] + preset = [preset[0],",".join(preset[1:13]),preset[13],",".join(preset[14:])] + print(preset) + return [gr.update(value=x) for x in preset] + + preset.change(fn=preset_visiblility, inputs=preset, outputs=preset_lambda) + beta_preset.change(fn=preset_visiblility, inputs=preset, outputs=beta_preset_lambda) + merge_mode.input(fn=tertiary, inputs=merge_mode, outputs=[tertiary_model_name, tertiary_refresh]) + merge_mode.input(fn=beta_visibility, inputs=merge_mode, outputs=[beta, alpha_label, beta_label, beta_apply_preset, beta_preset, beta_base, beta_in_blocks, beta_mid_block, beta_out_blocks]) + re_basin.change(fn=show_iters, inputs=re_basin,outputs=re_basin_iterations) + apply_preset.click(fn=load_presets,inputs=[preset, preset_lambda], outputs=[base,in_blocks,mid_block,out_blocks]) + MEHmodelmerger_merge.click( + fn=wrap_gradio_gpu_call(MEHmodelmerger, extra_outputs=lambda: [gr.update() for _ in range(4)]), + _js='modelmerger', + inputs=[ + dummy_component, + primary_model_name, + secondary_model_name, + tertiary_model_name, + merge_mode, + alpha, + beta, + precision, + custom_name, + checkpoint_format, + save_metadata, + preset, + weights_clip, + prune, + re_basin, + re_basin_iterations, + device + ], + outputs=[ + primary_model_name, + secondary_model_name, + tertiary_model_name, + dummy_component, + models_outcome, + ] + ) with gr.Tab(label="Validate"): model_headers = ['name', 'type', 'filename', 'hash', 'added', 'size', 'metadata'] From 685f3929676ddf82505f6a05a362d112d6ef0e75 Mon Sep 17 00:00:00 2001 From: AI-Casanova <54461896+AI-Casanova@users.noreply.github.com> Date: Sun, 5 Nov 2023 07:10:05 -0600 Subject: [PATCH 02/84] Added Tabs --- modules/extras.py | 117 +++++++++++++++++++------------------ modules/ui_models.py | 134 ++++++++++++++++++++++++++++++------------- 2 files changed, 155 insertions(+), 96 deletions(-) diff --git a/modules/extras.py b/modules/extras.py index 0d5fc2c76..ae7b9af8a 100644 --- a/modules/extras.py +++ b/modules/extras.py @@ -12,7 +12,6 @@ from sd_meh.merge import merge_models from modules import shared, images, sd_models, sd_vae, sd_models_config - checkpoint_dict_skip_on_merge = ["cond_stage_model.transformer.text_model.embeddings.position_ids"] @@ -32,6 +31,7 @@ def create_config(ckpt_result, config_source, a, b, c): def config(x): res = sd_models_config.find_checkpoint_config_near_filename(x) if x else None return res if res != shared.sd_default_config else None + if config_source == 0: cfg = config(a) or config(b) or config(c) elif config_source == 1: @@ -54,7 +54,9 @@ def to_half(tensor, enable): return tensor -def run_modelmerger(id_task, primary_model_name, secondary_model_name, tertiary_model_name, interp_method, multiplier, save_as_half, custom_name, checkpoint_format, config_source, bake_in_vae, discard_weights, save_metadata): # pylint: disable=unused-argument +def run_modelmerger(id_task, primary_model_name, secondary_model_name, tertiary_model_name, interp_method, multiplier, + save_as_half, custom_name, checkpoint_format, config_source, bake_in_vae, discard_weights, + save_metadata): # pylint: disable=unused-argument shared.state.begin('merge') save_as_half = save_as_half == 0 @@ -148,14 +150,18 @@ def run_modelmerger(id_task, primary_model_name, secondary_model_name, tertiary_ # have another 4 channels for unmasked picture's latent space, plus one channel for mask, for a total of 9 if a.shape != b.shape and a.shape[0:1] + a.shape[2:] == b.shape[0:1] + b.shape[2:]: if a.shape[1] == 4 and b.shape[1] == 9: - raise RuntimeError("When merging inpainting model with a normal one, A must be the inpainting model.") + raise RuntimeError( + "When merging inpainting model with a normal one, A must be the inpainting model.") if a.shape[1] == 4 and b.shape[1] == 8: - raise RuntimeError("When merging instruct-pix2pix model with a normal one, A must be the instruct-pix2pix model.") - if a.shape[1] == 8 and b.shape[1] == 4:#If we have an Instruct-Pix2Pix model... - theta_0[key][:, 0:4, :, :] = theta_func2(a[:, 0:4, :, :], b, multiplier)#Merge only the vectors the models have in common. Otherwise we get an error due to dimension mismatch. + raise RuntimeError( + "When merging instruct-pix2pix model with a normal one, A must be the instruct-pix2pix model.") + if a.shape[1] == 8 and b.shape[1] == 4: # If we have an Instruct-Pix2Pix model... + theta_0[key][:, 0:4, :, :] = theta_func2(a[:, 0:4, :, :], b, + multiplier) # Merge only the vectors the models have in common. Otherwise we get an error due to dimension mismatch. result_is_instruct_pix2pix_model = True else: - assert a.shape[1] == 9 and b.shape[1] == 4, f"Bad dimensions for merged layer {key}: A={a.shape}, B={b.shape}" + assert a.shape[1] == 9 and b.shape[ + 1] == 4, f"Bad dimensions for merged layer {key}: A={a.shape}, B={b.shape}" theta_0[key][:, 0:4, :, :] = theta_func2(a[:, 0:4, :, :], b, multiplier) result_is_inpainting_model = True else: @@ -193,7 +199,7 @@ def run_modelmerger(id_task, primary_model_name, secondary_model_name, tertiary_ if save_metadata: metadata = {"format": "pt", "sd_merge_models": {}} merge_recipe = { - "type": "webui", # indicate this model was merged with webui's built-in merger + "type": "webui", # indicate this model was merged with webui's built-in merger "primary_model_hash": primary_model_info.sha256, "secondary_model_hash": secondary_model_info.sha256 if secondary_model_info else None, "tertiary_model_hash": tertiary_model_info.sha256 if tertiary_model_info else None, @@ -238,70 +244,68 @@ def run_modelmerger(id_task, primary_model_name, secondary_model_name, tertiary_ shared.log.info(f"Model merge saved: {output_modelname}.") shared.state.textinfo = "Checkpoint saved" shared.state.end() - return [*[gr.Dropdown.update(choices=sd_models.checkpoint_tiles()) for _ in range(4)], "Checkpoint saved to " + output_modelname] + return [*[gr.Dropdown.update(choices=sd_models.checkpoint_tiles()) for _ in range(4)], + "Checkpoint saved to " + output_modelname] -def run_MEHmodelmerger(id_task, primary_model_name, secondary_model_name, tertiary_model_name, merge_mode,base_alpha, - base_beta, weights_alpha, - weights_beta, precision, custom_name, checkpoint_format, save_metadata, preset, weights_clip, prune, - re_basin, re_basin_iterations, device): # pylint: disable=unused-argument +def run_MEHmodelmerger(id_task, **kwargs): # pylint: disable=unused-argument shared.state.begin('model-merge') - models = { - "model_a": sd_models.checkpoints_list[primary_model_name].filename, - "model_b": sd_models.checkpoints_list[secondary_model_name].filename, - } - if tertiary_model_name is not None: - models |= {"model_c": sd_models.checkpoints_list[tertiary_model_name].filename} - work_device = device - threads = 1 - preset = preset if preset != "None" else None - block_weights_preset_alpha = block_weights_preset_beta = block_weights_preset_alpha_b = block_weights_preset_beta_b = preset if preset is not None else None - presets_alpha_lambda = presets_beta_lambda = None - logging_level = "INFO" + kwargs["models"] = { + "model_a": sd_models.checkpoints_list[kwargs.get("primary_model_name", None)].filename, + "model_b": sd_models.checkpoints_list[kwargs.get("secondary_model_name", None)].filename, + } + del kwargs["primary_model_name"] + del kwargs["secondary_model_name"] + if kwargs.get("tertiary_model_name", None) is not None: + kwargs["models"] |= {"model_c": sd_models.checkpoints_list[kwargs.get("tertiary_model_name", None)].filename} + del kwargs["tertiary_model_name"] + try: + alpha = [float(x) for x in [kwargs["alpha_base"]] + kwargs["alpha_in_blocks"].split(",") + [kwargs["alpha_mid_block"]] + kwargs["alpha_out_blocks"].split(",")] + assert len(alpha) == 26 or len(alpha) == 20, "Alpha Block Weights are wrong length (26 or 20 for SDXL) falling back" + kwargs["alpha"] = alpha + except Exception as e: + kwargs["alpha"] = kwargs.get("alpha_preset", kwargs["alpha"]) + print(e) + finally: + kwargs.pop("alpha_base", None) + kwargs.pop("alpha_in_blocks", None) + kwargs.pop("alpha_mid_block", None) + kwargs.pop("alpha_out_blocks", None) + kwargs.pop("alpha_preset", None) + if kwargs.get("beta", False): + try: + beta = [float(x) for x in [kwargs["beta_base"]] + kwargs["beta_in_blocks"].split(",") + [kwargs["beta_mid_block"]] + kwargs["beta_out_blocks"].split(",")] + assert len(beta) == 26 or len(beta) == 20, "Beta Block Weights are wrong length (26 or 20 for SDXL) falling back" + kwargs["beta"] = beta + except Exception as e: + kwargs["beta"] = kwargs.get("beta_preset", kwargs["beta"]) + print(e) + finally: + kwargs.pop("beta_base", None) + kwargs.pop("beta_in_blocks", None) + kwargs.pop("beta_mid_block", None) + kwargs.pop("beta_out_blocks", None) + kwargs.pop("beta_preset", None) + + return [*[gr.update() for _ in range(4)], f"{kwargs}"] def fail(message): shared.state.textinfo = message shared.state.end() return [*[gr.update() for _ in range(4)], message] - - - theta_0 = main( - model_a, - model_b, - model_c, - merge_mode, - weights_clip, - precision, - str(weights_alpha), - base_alpha, - str(weights_beta), - base_beta, - re_basin, - re_basin_iterations, - device, - work_device, - prune, - block_weights_preset_alpha, - block_weights_preset_beta, - threads, - block_weights_preset_alpha_b, - block_weights_preset_beta_b, - presets_alpha_lambda, - presets_beta_lambda, - logging_level, - ) + theta_0 = merge_models(**kwargs) ckpt_dir = shared.opts.ckpt_dir or sd_models.model_path filename = custom_name - filename += "." + checkpoint_format + filename += "." + kwargs.get("checkpoint_format", None) output_modelname = os.path.join(ckpt_dir, filename) shared.state.textinfo = "Saving" metadata = None if save_metadata: metadata = {"format": "pt", "sd_merge_models": {}} merge_recipe = { - "type": "webui", # indicate this model was merged with webui's built-in merger + "type": "SDNext", # indicate this model was merged with webui's built-in merger "primary_model_hash": primary_model_info.sha256, "secondary_model_hash": secondary_model_info.sha256 if secondary_model_info else None, "tertiary_model_hash": tertiary_model_info.sha256 if tertiary_model_info else None, @@ -345,8 +349,9 @@ def run_MEHmodelmerger(id_task, primary_model_name, secondary_model_name, tertia return [*[gr.Dropdown.update(choices=sd_models.checkpoint_tiles()) for _ in range(4)], "Checkpoint saved to " + output_modelname] -def run_modelconvert(model, checkpoint_formats, precision, conv_type, custom_name, unet_conv, text_encoder_conv, vae_conv, others_conv, fix_clip): +def run_modelconvert(model, checkpoint_formats, precision, conv_type, custom_name, unet_conv, text_encoder_conv, + vae_conv, others_conv, fix_clip): # position_ids in clip is int64. model_ema.num_updates is int32 dtypes_to_fp16 = {torch.float32, torch.float64, torch.bfloat16} dtypes_to_bf16 = {torch.float32, torch.float64, torch.float16} @@ -384,7 +389,6 @@ def run_modelconvert(model, checkpoint_formats, precision, conv_type, custom_nam state_dict = m["state_dict"] if "state_dict" in m else m return state_dict - def fix_model(model, fix_clip=False): # code from model-toolkit nai_keys = { @@ -446,6 +450,7 @@ def run_modelconvert(model, checkpoint_formats, precision, conv_type, custom_nam ok[wk] = t elif conv_t == "delete": return + shared.log.info("Model convert: running") if conv_type == "ema-only": for k in tqdm.tqdm(state_dict): diff --git a/modules/ui_models.py b/modules/ui_models.py index e5115662c..abcb9bce1 100644 --- a/modules/ui_models.py +++ b/modules/ui_models.py @@ -1,5 +1,6 @@ import os import json +import inspect from datetime import datetime import gradio as gr from modules import sd_models, sd_vae, extras @@ -140,9 +141,9 @@ def create_ui(): models_outcome, ] ) - with gr.Tab(label="MEH Merge"): + with gr.Tab(label="Advanced Merge"): def sd_model_choices(): - return ['None'] + sd_models.checkpoint_tiles() + return ['None'] + sd_models.checkpoint_tiles() with gr.Row(equal_height=False): with gr.Column(variant='compact'): with FormRow(): @@ -157,31 +158,35 @@ def create_ui(): tertiary_model_name = gr.Dropdown(sd_model_choices(), label="Tertiary model", value="None", visible=False) tertiary_refresh = create_refresh_button(tertiary_model_name, sd_models.list_models, lambda: {"choices": sd_model_choices()}, "refresh_checkpoint_C",visible=False) with FormRow(): - alpha = gr.Slider(minimum=0.0, maximum=1.0, step=0.05, label='Alpha Ratio', value=0.5) - beta = gr.Slider(minimum=0.0, maximum=1.0, step=0.05, label='Beta Ratio', value=None, visible=False) - with InputAccordion(False, label="Block Merge", elem_id=f"block_merge") as block_accordion: - with FormRow(): - alpha_label = gr.Markdown("# Alpha") - with FormRow(): - preset = gr.Dropdown(choices=["None"]+list(BLOCK_WEIGHTS_PRESETS.keys()), value=None, label="Block Weight Preset", multiselect=True, max_choices=2) - preset_lambda = gr.Slider(minimum=0.0, maximum=1.0, step=0.05, label='Preset Interpolation Ratio', value=None, visible=False) - apply_preset = ToolButton('⇩', visible=True) - with FormRow(): - base = gr.Textbox(value=None, label="Base", scale=1) - in_blocks = gr.Textbox(value=None, label="In Blocks", scale=10) - mid_block = gr.Textbox(value=None, label="Mid Block", scale=1) - out_blocks = gr.Textbox(value=None, label="Out Block", scale=10) - with FormRow(): - beta_label = gr.Markdown("# Beta", visible=False) - with FormRow(): - beta_preset = gr.Dropdown(choices=["None"]+list(BLOCK_WEIGHTS_PRESETS.keys()), value=None, label="Block Weight Preset", multiselect=True, max_choices=2, interactive=True, visible=False) - beta_preset_lambda = gr.Slider(minimum=0.0, maximum=1.0, step=0.05, label='Preset Interpolation Ratio', value=None, interactive=True, visible=False) - beta_apply_preset = ToolButton('⇩', interactive=True, visible=False) - with FormRow(): - beta_base = gr.Textbox(value=None, label="Base", scale=1, interactive=True, visible=False) - beta_in_blocks = gr.Textbox(value=None, label="In Blocks", interactive=True, scale=10, visible=False) - beta_mid_block = gr.Textbox(value=None, label="Mid Block", interactive=True, scale=1, visible=False) - beta_out_blocks = gr.Textbox(value=None, label="Out Block", interactive=True, scale=10, visible=False) + with gr.Tabs() as tabs: + with gr.TabItem(label="Simple Merge", id=0): + with FormRow(): + alpha = gr.Slider(minimum=0.0, maximum=1.0, step=0.05, label='Alpha Ratio', value=0.5) + beta = gr.Slider(minimum=0.0, maximum=1.0, step=0.05, label='Beta Ratio', value=None, visible=False) + with gr.TabItem(label="Preset Block Merge", id=1): + with FormRow(): + alpha_preset = gr.Dropdown(choices=["None"]+list(BLOCK_WEIGHTS_PRESETS.keys()), value=None, label="ALPHA Block Weight Preset", multiselect=True, max_choices=2) + alpha_preset_lambda = gr.Slider(minimum=0.0, maximum=1.0, step=0.05, label='Preset Interpolation Ratio', value=None, visible=False) + apply_preset = ToolButton('⇩', visible=True) + with FormRow(): + beta_preset = gr.Dropdown(choices=["None"]+list(BLOCK_WEIGHTS_PRESETS.keys()), value=None, label="BETA Block Weight Preset", multiselect=True, max_choices=2, interactive=True, visible=False) + beta_preset_lambda = gr.Slider(minimum=0.0, maximum=1.0, step=0.05, label='Preset Interpolation Ratio', value=None, interactive=True, visible=False) + beta_apply_preset = ToolButton('⇩', interactive=True, visible=False) + with gr.TabItem(label="Manual Block Merge", id=2): + with FormRow(): + alpha_label = gr.Markdown("# Alpha") + with FormRow(): + alpha_base = gr.Textbox(value=None, label="Base", min_width=70, scale=1) + alpha_in_blocks = gr.Textbox(value=None, label="In Blocks", scale=15) + alpha_mid_block = gr.Textbox(value=None, label="Mid Block", min_width=80, scale=1) + alpha_out_blocks = gr.Textbox(value=None, label="Out Block", scale=15) + with FormRow(): + beta_label = gr.Markdown("# Beta", visible=False) + with FormRow(): + beta_base = gr.Textbox(value=None, label="Base", min_width=70, scale=1, interactive=True, visible=False) + beta_in_blocks = gr.Textbox(value=None, label="In Blocks", interactive=True, scale=15, visible=False) + beta_mid_block = gr.Textbox(value=None, label="Mid Block", min_width=80, interactive=True, scale=1, visible=False) + beta_out_blocks = gr.Textbox(value=None, label="Out Block", interactive=True, scale=15, visible=False) with FormRow(): weights_clip = gr.Checkbox(label="Weights Clip") prune = gr.Checkbox(label="Prune") @@ -189,22 +194,59 @@ def create_ui(): with FormRow(): re_basin_iterations = gr.Slider(minimum=0, maximum=25, step=1, label='Number of ReBasin Iterations', value=None, visible=False) with FormRow(): - checkpoint_format = gr.Radio(choices=["ckpt", "safetensors"], value="safetensors", label="Model format") + checkpoint_format = gr.Radio(choices=["ckpt", "safetensors"], value="safetensors", visible=False, label="Model format") with FormRow(): precision = gr.Radio(choices=["fp16", "fp32"], value="fp16", label="Model precision") with FormRow(): device = gr.Radio(choices=["cpu", "cuda"], value="cpu", label="Device") with FormRow(): - bake_in_vae = gr.Dropdown(choices=["None"] + list(sd_vae.vae_dict), value="None", label="Bake in VAE") + bake_in_vae = gr.Dropdown(choices=["None"] + list(sd_vae.vae_dict), value="None", interactive=True, label="Bake in VAE") create_refresh_button(bake_in_vae, sd_vae.refresh_vae_list, lambda: {"choices": ["None"] + list(sd_vae.vae_dict)}, "modelmerger_refresh_bake_in_vae") with FormRow(): save_metadata = gr.Checkbox(value=True, label="Save metadata") with gr.Row(): MEHmodelmerger_merge = gr.Button(value="Merge", variant='primary') - def MEHmodelmerger(*args): + def MEHmodelmerger(dummy_component, + primary_model_name, + secondary_model_name, + tertiary_model_name, + merge_mode, + alpha, + beta, + alpha_preset, + alpha_preset_lambda, + alpha_base, + alpha_in_blocks, + alpha_mid_block, + alpha_out_blocks, + beta_preset, + beta_preset_lambda, + beta_base, + beta_in_blocks, + beta_mid_block, + beta_out_blocks, + precision, + custom_name, + checkpoint_format, + save_metadata, + weights_clip, + prune, + re_basin, + re_basin_iterations, + device, + bake_in_vae): + kwargs = {} + for x in inspect.getfullargspec(MEHmodelmerger)[0]: + kwargs[x] = locals()[x] + for key in list(kwargs.keys()): + if kwargs[key] in [None,"None","",0,[]]: + del kwargs[key] + + # return [*[gr.Dropdown.update(choices=sd_models.checkpoint_tiles()) for _ in range(4)], f"{kwargs}"] + try: - results = extras.run_MEHmodelmerger(*args) + results = extras.run_MEHmodelmerger(dummy_component, **kwargs) except Exception as e: modules.errors.display(e, 'model merge') sd_models.list_models() # to remove the potentially missing models from the list @@ -240,17 +282,17 @@ def create_ui(): preset = interpolate(presets, ratio) else: preset = presets[0] - preset = [str(x) for x in preset] - preset = [preset[0],",".join(preset[1:13]),preset[13],",".join(preset[14:])] - print(preset) - return [gr.update(value=x) for x in preset] + preset = ['%.3f' % x for x in preset] + preset = [preset[0], ",".join(preset[1:13]),preset[13], ",".join(preset[14:])] + return [gr.update(value=x) for x in preset]+[gr.update(selected=2)] - preset.change(fn=preset_visiblility, inputs=preset, outputs=preset_lambda) - beta_preset.change(fn=preset_visiblility, inputs=preset, outputs=beta_preset_lambda) + alpha_preset.change(fn=preset_visiblility, inputs=alpha_preset, outputs=alpha_preset_lambda) + beta_preset.change(fn=preset_visiblility, inputs=alpha_preset, outputs=beta_preset_lambda) merge_mode.input(fn=tertiary, inputs=merge_mode, outputs=[tertiary_model_name, tertiary_refresh]) merge_mode.input(fn=beta_visibility, inputs=merge_mode, outputs=[beta, alpha_label, beta_label, beta_apply_preset, beta_preset, beta_base, beta_in_blocks, beta_mid_block, beta_out_blocks]) re_basin.change(fn=show_iters, inputs=re_basin,outputs=re_basin_iterations) - apply_preset.click(fn=load_presets,inputs=[preset, preset_lambda], outputs=[base,in_blocks,mid_block,out_blocks]) + apply_preset.click(fn=load_presets,inputs=[alpha_preset, alpha_preset_lambda], outputs=[alpha_base,alpha_in_blocks,alpha_mid_block,alpha_out_blocks,tabs]) + beta_apply_preset.click(fn=load_presets,inputs=[beta_preset, beta_preset_lambda], outputs=[beta_base,beta_in_blocks,beta_mid_block,beta_out_blocks,tabs]) MEHmodelmerger_merge.click( fn=wrap_gradio_gpu_call(MEHmodelmerger, extra_outputs=lambda: [gr.update() for _ in range(4)]), _js='modelmerger', @@ -262,16 +304,28 @@ def create_ui(): merge_mode, alpha, beta, + alpha_preset, + alpha_preset_lambda, + alpha_base, + alpha_in_blocks, + alpha_mid_block, + alpha_out_blocks, + beta_preset, + beta_preset_lambda, + beta_base, + beta_in_blocks, + beta_mid_block, + beta_out_blocks, precision, custom_name, checkpoint_format, save_metadata, - preset, weights_clip, prune, re_basin, re_basin_iterations, - device + device, + bake_in_vae, ], outputs=[ primary_model_name, From 020d8ed1dc25f018348ce17f15b7457e6c7f0d73 Mon Sep 17 00:00:00 2001 From: AI-Casanova <54461896+AI-Casanova@users.noreply.github.com> Date: Sun, 5 Nov 2023 19:45:15 -0600 Subject: [PATCH 03/84] Add Merge Files Natively --- modules/extras.py | 66 +- modules/merging/merge.py | 443 ++++++ modules/merging/merge_methods.py | 211 +++ modules/merging/model.py | 56 + modules/merging/presets.py | 62 + modules/merging/rebasin.py | 2287 ++++++++++++++++++++++++++++++ modules/merging/utils.py | 115 ++ modules/ui_models.py | 373 +++-- requirements.txt | 1 + 9 files changed, 3461 insertions(+), 153 deletions(-) create mode 100644 modules/merging/merge.py create mode 100644 modules/merging/merge_methods.py create mode 100644 modules/merging/model.py create mode 100644 modules/merging/presets.py create mode 100644 modules/merging/rebasin.py create mode 100644 modules/merging/utils.py diff --git a/modules/extras.py b/modules/extras.py index ae7b9af8a..fe02f002a 100644 --- a/modules/extras.py +++ b/modules/extras.py @@ -8,7 +8,8 @@ import torch import tqdm import gradio as gr import safetensors.torch -from sd_meh.merge import merge_models +from modules.merging.merge import merge_models +from modules.merging.utils import TRIPLE_METHODS from modules import shared, images, sd_models, sd_vae, sd_models_config @@ -232,6 +233,7 @@ def run_modelmerger(id_task, primary_model_name, secondary_model_name, tertiary_ metadata["sd_merge_models"] = json.dumps(metadata["sd_merge_models"]) _, extension = os.path.splitext(output_modelname) + theta_0 = theta_0.to_dict() if extension.lower() == ".safetensors": safetensors.torch.save_file(theta_0, output_modelname, metadata=metadata) else: @@ -249,11 +251,29 @@ def run_modelmerger(id_task, primary_model_name, secondary_model_name, tertiary_ def run_MEHmodelmerger(id_task, **kwargs): # pylint: disable=unused-argument - shared.state.begin('model-merge') + shared.state.begin('merge') + + def fail(message): + shared.state.textinfo = message + shared.state.end() + return [*[gr.update() for _ in range(4)], message] + kwargs["models"] = { "model_a": sd_models.checkpoints_list[kwargs.get("primary_model_name", None)].filename, "model_b": sd_models.checkpoints_list[kwargs.get("secondary_model_name", None)].filename, } + + if kwargs.get("primary_model_name", None) in [None, 'None']: + return fail("Failed: Merging requires a primary model.") + primary_model_info = sd_models.checkpoints_list[kwargs.get("primary_model_name", None)] + if kwargs.get("secondary_model_name", None) in [None, 'None']: + return fail("Failed: Merging requires a secondary model.") + secondary_model_info = sd_models.checkpoints_list[kwargs.get("secondary_model_name", None)] + if kwargs.get("tertiary_model_name", None) in [None, 'None'] and kwargs.get("merge_mode", None) in TRIPLE_METHODS: + return fail(f"Failed: Interpolation method ({kwargs.get('merge_mode', None)}) requires a tertiary model.") + tertiary_model_info = sd_models.checkpoints_list[tertiary_model_name] if kwargs.get("merge_mode", + None) in TRIPLE_METHODS else None + del kwargs["primary_model_name"] del kwargs["secondary_model_name"] if kwargs.get("tertiary_model_name", None) is not None: @@ -261,12 +281,14 @@ def run_MEHmodelmerger(id_task, **kwargs): # pylint: disable=unused-argument del kwargs["tertiary_model_name"] try: - alpha = [float(x) for x in [kwargs["alpha_base"]] + kwargs["alpha_in_blocks"].split(",") + [kwargs["alpha_mid_block"]] + kwargs["alpha_out_blocks"].split(",")] - assert len(alpha) == 26 or len(alpha) == 20, "Alpha Block Weights are wrong length (26 or 20 for SDXL) falling back" + alpha = [float(x) for x in + [kwargs["alpha_base"]] + kwargs["alpha_in_blocks"].split(",") + [kwargs["alpha_mid_block"]] + kwargs[ + "alpha_out_blocks"].split(",")] + assert len(alpha) == 26 or len( + alpha) == 20, "Alpha Block Weights are wrong length (26 or 20 for SDXL) falling back" kwargs["alpha"] = alpha except Exception as e: kwargs["alpha"] = kwargs.get("alpha_preset", kwargs["alpha"]) - print(e) finally: kwargs.pop("alpha_base", None) kwargs.pop("alpha_in_blocks", None) @@ -275,12 +297,14 @@ def run_MEHmodelmerger(id_task, **kwargs): # pylint: disable=unused-argument kwargs.pop("alpha_preset", None) if kwargs.get("beta", False): try: - beta = [float(x) for x in [kwargs["beta_base"]] + kwargs["beta_in_blocks"].split(",") + [kwargs["beta_mid_block"]] + kwargs["beta_out_blocks"].split(",")] - assert len(beta) == 26 or len(beta) == 20, "Beta Block Weights are wrong length (26 or 20 for SDXL) falling back" + beta = [float(x) for x in + [kwargs["beta_base"]] + kwargs["beta_in_blocks"].split(",") + [kwargs["beta_mid_block"]] + kwargs[ + "beta_out_blocks"].split(",")] + assert len(beta) == 26 or len( + beta) == 20, "Beta Block Weights are wrong length (26 or 20 for SDXL) falling back" kwargs["beta"] = beta except Exception as e: kwargs["beta"] = kwargs.get("beta_preset", kwargs["beta"]) - print(e) finally: kwargs.pop("beta_base", None) kwargs.pop("beta_in_blocks", None) @@ -288,31 +312,29 @@ def run_MEHmodelmerger(id_task, **kwargs): # pylint: disable=unused-argument kwargs.pop("beta_out_blocks", None) kwargs.pop("beta_preset", None) - return [*[gr.update() for _ in range(4)], f"{kwargs}"] + try: + theta_0 = merge_models(**kwargs) + except Exception as e: + return fail(f"{e}") - def fail(message): - shared.state.textinfo = message - shared.state.end() - return [*[gr.update() for _ in range(4)], message] - - theta_0 = merge_models(**kwargs) ckpt_dir = shared.opts.ckpt_dir or sd_models.model_path - filename = custom_name + filename = kwargs.get("custom_name", "Unamed_Merge") filename += "." + kwargs.get("checkpoint_format", None) output_modelname = os.path.join(ckpt_dir, filename) shared.state.textinfo = "Saving" metadata = None - if save_metadata: + if kwargs.get("save_metadata", False): metadata = {"format": "pt", "sd_merge_models": {}} merge_recipe = { "type": "SDNext", # indicate this model was merged with webui's built-in merger "primary_model_hash": primary_model_info.sha256, "secondary_model_hash": secondary_model_info.sha256 if secondary_model_info else None, "tertiary_model_hash": tertiary_model_info.sha256 if tertiary_model_info else None, - "interp_method": interp_method, - "multiplier": multiplier, - "save_as_half": save_as_half, - "custom_name": custom_name, + "merge_mode": kwargs.get('merge_mode', None), + "alpha": kwargs.get('alpha', None), + "beta": kwargs.get('beta', None), + "precision": kwargs.get('precision', None), + "custom_name": kwargs.get("custom_name", "Unamed_Merge"), } metadata["sd_merge_recipe"] = json.dumps(merge_recipe) @@ -333,6 +355,7 @@ def run_MEHmodelmerger(id_task, **kwargs): # pylint: disable=unused-argument metadata["sd_merge_models"] = json.dumps(metadata["sd_merge_models"]) _, extension = os.path.splitext(output_modelname) + theta_0 = theta_0.to_dict() if extension.lower() == ".safetensors": safetensors.torch.save_file(theta_0, output_modelname, metadata=metadata) else: @@ -342,7 +365,6 @@ def run_MEHmodelmerger(id_task, **kwargs): # pylint: disable=unused-argument created_model = next((ckpt for ckpt in sd_models.checkpoints_list.values() if ckpt.name == filename), None) if created_model: created_model.calculate_shorthash() - create_config(output_modelname, config_source, primary_model_info, secondary_model_info, tertiary_model_info) shared.log.info(f"Model merge saved: {output_modelname}.") shared.state.textinfo = "Checkpoint saved" shared.state.end() diff --git a/modules/merging/merge.py b/modules/merging/merge.py new file mode 100644 index 000000000..e55433d86 --- /dev/null +++ b/modules/merging/merge.py @@ -0,0 +1,443 @@ +import gc +import os +from concurrent.futures import ThreadPoolExecutor +from contextlib import contextmanager +from pathlib import Path +from typing import Dict, Optional, Tuple + +import safetensors.torch +import torch +from tqdm import tqdm + +from modules.merging import merge_methods +from modules.merging.utils import WeightClass +from modules.merging.model import SDModel +from modules.merging.rebasin import ( + apply_permutation, + sdunet_permutation_spec, + update_model_a, + weight_matching, +) + +# logging.getLogger("sd_meh").addHandler(logging.NullHandler()) + +MAX_TOKENS = 77 + + +KEY_POSITION_IDS = ".".join( + [ + "cond_stage_model", + "transformer", + "text_model", + "embeddings", + "position_ids", + ] +) + + +NAI_KEYS = { + "cond_stage_model.transformer.embeddings.": "cond_stage_model.transformer.text_model.embeddings.", + "cond_stage_model.transformer.encoder.": "cond_stage_model.transformer.text_model.encoder.", + "cond_stage_model.transformer.final_layer_norm.": "cond_stage_model.transformer.text_model.final_layer_norm.", +} + + +def fix_clip(model: Dict) -> Dict: + if KEY_POSITION_IDS in model.keys(): + model[KEY_POSITION_IDS] = torch.tensor( + [list(range(MAX_TOKENS))], + dtype=torch.int64, + device=model[KEY_POSITION_IDS].device, + ) + + return model + + +def fix_key(model: Dict, key: str) -> Dict: + for nk in NAI_KEYS: + if key.startswith(nk): + model[key.replace(nk, NAI_KEYS[nk])] = model[key] + del model[key] + + return model + + +# https://github.com/j4ded/sdweb-merge-block-weighted-gui/blob/master/scripts/mbw/merge_block_weighted.py#L115 +def fix_model(model: Dict) -> Dict: + for k in model.keys(): + model = fix_key(model, k) + return fix_clip(model) + + +def load_sd_model(model: os.PathLike | str, device: str = "cpu") -> Dict: + if isinstance(model, str): + model = Path(model) + + return SDModel(model, device).load_model() + + +def prune_sd_model(model: Dict) -> Dict: + keys = list(model.keys()) + for k in keys: + if ( + not k.startswith("model.diffusion_model.") + and not k.startswith("first_stage_model.") + and not k.startswith("cond_stage_model.") + ): + del model[k] + return model + + +def restore_sd_model(original_model: Dict, merged_model: Dict) -> Dict: + for k in original_model: + if k not in merged_model: + merged_model[k] = original_model[k] + return merged_model + + +def log_vram(txt=""): + alloc = torch.cuda.memory_allocated(0) + # logging.debug(f"{txt} VRAM: {alloc*1e-9:5.3f}GB") + + +def load_thetas( + models: Dict[str, os.PathLike | str], + prune: bool, + device: str, + precision: str, +) -> Dict: + log_vram("before loading models") + if prune: + thetas = {k: prune_sd_model(load_sd_model(m, "cpu")) for k, m in models.items()} + else: + thetas = {k: load_sd_model(m, device) for k, m in models.items()} + + if device == "cuda": + for model_key, model in thetas.items(): + for key, block in model.items(): + if precision == "fp16": + thetas[model_key].update({key: block.to(device).half()}) + else: + thetas[model_key].update({key: block.to(device)}) + + log_vram("models loaded") + return thetas + + +def merge_models( + models: Dict[str, os.PathLike | str], + merge_mode: str, + precision: str = "full", + weights_clip: bool = False, + re_basin: bool = False, + iterations: int = 1, + device: str = "cpu", + work_device: Optional[str] = None, + prune: bool = False, + threads: int = 1, + **kwargs, +) -> Dict: + thetas = load_thetas(models, prune, device, precision) + + # logging.info(f"start merging with {merge_mode} method") + weight_matcher = WeightClass(thetas["model_a"], **kwargs) + if re_basin: + merged = rebasin_merge( + thetas, + weight_matcher, + merge_mode, + precision=precision, + weights_clip=weights_clip, + iterations=iterations, + device=device, + work_device=work_device, + threads=threads, + ) + else: + merged = simple_merge( + thetas, + weight_matcher, + merge_mode, + precision=precision, + weights_clip=weights_clip, + device=device, + work_device=work_device, + threads=threads, + ) + + return un_prune_model(merged, thetas, models, device, prune, precision) + + +def un_prune_model( + merged: Dict, + thetas: Dict, + models: Dict, + device: str, + prune: bool, + precision: str, +) -> Dict: + if prune: + # logging.info("Un-pruning merged model") + del thetas + gc.collect() + log_vram("remove thetas") + original_a = load_sd_model(models["model_a"], device) + for key in tqdm(original_a.keys(), desc="un-prune model a"): + if KEY_POSITION_IDS in key: + continue + if "model" in key and key not in merged.keys(): + merged.update({key: original_a[key]}) + if precision == "fp16": + merged.update({key: merged[key].half()}) + del original_a + gc.collect() + log_vram("remove original_a") + original_b = load_sd_model(models["model_b"], device) + for key in tqdm(original_b.keys(), desc="un-prune model b"): + if KEY_POSITION_IDS in key: + continue + if "model" in key and key not in merged.keys(): + merged.update({key: original_b[key]}) + if precision == "fp16": + merged.update({key: merged[key].half()}) + del original_b + + return fix_model(merged) + + +def simple_merge( + thetas: Dict[str, Dict], + weight_matcher: WeightClass, + merge_mode: str, + precision: str = "fp16", + weights_clip: bool = False, + device: str = "cpu", + work_device: Optional[str] = None, + threads: int = 1, +) -> Dict: + futures = [] + with tqdm(thetas["model_a"].keys(), desc="stage 1") as progress: + with ThreadPoolExecutor(max_workers=threads) as executor: + for key in thetas["model_a"].keys(): + future = executor.submit( + simple_merge_key, + progress, + key, + thetas, + weight_matcher, + merge_mode, + precision, + weights_clip, + device, + work_device, + ) + futures.append(future) + + for res in futures: + res.result() + + log_vram("after stage 1") + + for key in tqdm(thetas["model_b"].keys(), desc="stage 2"): + if KEY_POSITION_IDS in key: + continue + if "model" in key and key not in thetas["model_a"].keys(): + thetas["model_a"].update({key: thetas["model_b"][key]}) + if precision == 16: + thetas["model_a"].update({key: thetas["model_a"][key].half()}) + + log_vram("after stage 2") + + return fix_model(thetas["model_a"]) + + +def rebasin_merge( + thetas: Dict[str, os.PathLike | str], + weight_matcher: WeightClass, + merge_mode: str, + precision: str = "fp16", + weights_clip: bool = False, + iterations: int = 1, + device="cpu", + work_device=None, + threads: int = 1, +): + # WARNING: not sure how this does when 3 models are involved... + + model_a = thetas["model_a"].clone() + perm_spec = sdunet_permutation_spec() + + print("Init rebasin iterations") + for it in range(iterations): + print(f"Rebasin iteration {it}") + log_vram(f"{it} iteration start") + weight_matcher.set_it(it) + log_vram("weights & bases, before simple merge") + + # normal block merge we already know and love + thetas["model_a"] = simple_merge( + thetas, + weight_matcher, + merge_mode, + precision, + False, + device, + work_device, + threads, + ) + + log_vram("simple merge done") + + # find permutations + perm_1, y = weight_matching( + perm_spec, + model_a, + thetas["model_a"], + max_iter=it, + init_perm=None, + usefp16=precision == 16, + device=device, + ) + + log_vram("weight matching #1 done") + + thetas["model_a"] = apply_permutation(perm_spec, perm_1, thetas["model_a"]) + + log_vram("apply perm 1 done") + + perm_2, z = weight_matching( + perm_spec, + thetas["model_b"], + thetas["model_a"], + max_iter=it, + init_perm=None, + usefp16=precision == 16, + device=device, + ) + + log_vram("weight matching #2 done") + + new_alpha = torch.nn.functional.normalize( + torch.sigmoid(torch.Tensor([y, z])), p=1, dim=0 + ).tolist()[0] + thetas["model_a"] = update_model_a( + perm_spec, perm_2, thetas["model_a"], new_alpha + ) + + log_vram("model a updated") + + if weights_clip: + clip_thetas = thetas.copy() + clip_thetas["model_a"] = model_a + thetas["model_a"] = clip_weights(thetas, thetas["model_a"]) + + return thetas["model_a"] + + +def simple_merge_key(progress, key, thetas, *args, **kwargs): + with merge_key_context(key, thetas, *args, **kwargs) as result: + if result is not None: + thetas["model_a"].update({key: result.detach().clone()}) + + progress.update() + + +def merge_key( + key: str, + thetas: Dict, + weight_matcher: WeightClass, + merge_mode: str, + precision: int = 16, + weights_clip: bool = False, + device: str = "cpu", + work_device: Optional[str] = None, +) -> Optional[Tuple[str, Dict]]: + if work_device is None: + work_device = device + + if KEY_POSITION_IDS in key: + return + + for theta in thetas.values(): + if key not in theta.keys(): + return + + current_bases = weight_matcher(key) + try: + merge_method = getattr(merge_methods, merge_mode) + except AttributeError as e: + raise ValueError(f"{merge_mode} not implemented, aborting merge!") from e + + merge_args = get_merge_method_args(current_bases, thetas, key, work_device) + + # dealing with pix2pix and inpainting models + if (a_size := merge_args["a"].size()) != (b_size := merge_args["b"].size()): + if a_size[1] > b_size[1]: + merged_key = merge_args["a"] + else: + merged_key = merge_args["b"] + else: + merged_key = merge_method(**merge_args).to(device) + + if weights_clip: + merged_key = clip_weights_key(thetas, merged_key, key) + + if precision == 16: + merged_key = merged_key.half() + + return merged_key + + +def clip_weights(thetas, merged): + for k in thetas["model_a"].keys(): + if k in thetas["model_b"].keys(): + merged.update({k: clip_weights_key(thetas, merged[k], k)}) + return merged + + +def clip_weights_key(thetas, merged_weights, key): + t0 = thetas["model_a"][key] + t1 = thetas["model_b"][key] + maximums = torch.maximum(t0, t1) + minimums = torch.minimum(t0, t1) + return torch.minimum(torch.maximum(merged_weights, minimums), maximums) + + +@contextmanager +def merge_key_context(*args, **kwargs): + result = merge_key(*args, **kwargs) + try: + yield result + finally: + if result is not None: + del result + + +def get_merge_method_args( + current_bases: Dict, + thetas: Dict, + key: str, + work_device: str, +) -> Dict: + merge_method_args = { + "a": thetas["model_a"][key].to(work_device), + "b": thetas["model_b"][key].to(work_device), + **current_bases, + } + + if "model_c" in thetas: + merge_method_args["c"] = thetas["model_c"][key].to(work_device) + + return merge_method_args + + +def save_model(model, output_file, file_format) -> None: + # logging.info(f"Saving {output_file}") + if file_format == "safetensors": + safetensors.torch.save_file( + model if type(model) == dict else model.to_dict(), + f"{output_file}.safetensors", + metadata={"format": "pt"}, + ) + else: + torch.save({"state_dict": model}, f"{output_file}.ckpt") diff --git a/modules/merging/merge_methods.py b/modules/merging/merge_methods.py new file mode 100644 index 000000000..c10c459f0 --- /dev/null +++ b/modules/merging/merge_methods.py @@ -0,0 +1,211 @@ +import math +from typing import Tuple + +import torch +from torch import Tensor + +__all__ = [ + "weighted_sum", + "weighted_subtraction", + "tensor_sum", + "add_difference", + "sum_twice", + "triple_sum", + "euclidean_add_difference", + "multiply_difference", + "top_k_tensor_sum", + "similarity_add_difference", + "distribution_crossover", + "ties_add_difference", +] + + +EPSILON = 1e-10 # Define a small constant EPSILON to prevent division by zero + + +def weighted_sum(a: Tensor, b: Tensor, alpha: float, **kwargs) -> Tensor: + return (1 - alpha) * a + alpha * b + + +def weighted_subtraction( + a: Tensor, b: Tensor, alpha: float, beta: float, **kwargs +) -> Tensor: + # Adjust beta if both alpha and beta are 1.0 to avoid division by zero + if alpha == 1.0 and beta == 1.0: + beta -= EPSILON + + return (a - alpha * beta * b) / (1 - alpha * beta) + + +def tensor_sum(a: Tensor, b: Tensor, alpha: float, beta: float, **kwargs) -> Tensor: + if alpha + beta <= 1: + tt = a.clone() + talphas = int(a.shape[0] * beta) + talphae = int(a.shape[0] * (alpha + beta)) + tt[talphas:talphae] = b[talphas:talphae].clone() + else: + talphas = int(a.shape[0] * (alpha + beta - 1)) + talphae = int(a.shape[0] * beta) + tt = b.clone() + tt[talphas:talphae] = a[talphas:talphae].clone() + return tt + + +def add_difference(a: Tensor, b: Tensor, c: Tensor, alpha: float, **kwargs) -> Tensor: + return a + alpha * (b - c) + + +def sum_twice( + a: Tensor, b: Tensor, c: Tensor, alpha: float, beta: float, **kwargs +) -> Tensor: + return (1 - beta) * ((1 - alpha) * a + alpha * b) + beta * c + + +def triple_sum( + a: Tensor, b: Tensor, c: Tensor, alpha: float, beta: float, **kwargs +) -> Tensor: + return (1 - alpha - beta) * a + alpha * b + beta * c + + +def euclidean_add_difference( + a: Tensor, b: Tensor, c: Tensor, alpha: float, **kwargs +) -> Tensor: + a_diff = a.float() - c.float() + b_diff = b.float() - c.float() + a_diff = torch.nan_to_num(a_diff / torch.linalg.norm(a_diff)) + b_diff = torch.nan_to_num(b_diff / torch.linalg.norm(b_diff)) + + distance = (1 - alpha) * a_diff**2 + alpha * b_diff**2 + distance = torch.sqrt(distance) + sum_diff = weighted_sum(a.float(), b.float(), alpha) - c.float() + distance = torch.copysign(distance, sum_diff) + + target_norm = torch.linalg.norm(sum_diff) + return c + distance / torch.linalg.norm(distance) * target_norm + + +def multiply_difference( + a: Tensor, b: Tensor, c: Tensor, alpha: float, beta: float, **kwargs +) -> Tensor: + diff_a = torch.pow(torch.abs(a.float() - c), (1 - alpha)) + diff_b = torch.pow(torch.abs(b.float() - c), alpha) + difference = torch.copysign(diff_a * diff_b, weighted_sum(a, b, beta) - c) + return c + difference.to(c.dtype) + + +def top_k_tensor_sum( + a: Tensor, b: Tensor, alpha: float, beta: float, **kwargs +) -> Tensor: + a_flat = torch.flatten(a) + a_dist = torch.msort(a_flat) + b_indices = torch.argsort(torch.flatten(b), stable=True) + redist_indices = torch.argsort(b_indices) + + start_i, end_i, region_is_inverted = ratio_to_region(alpha, beta, torch.numel(a)) + start_top_k = kth_abs_value(a_dist, start_i) + end_top_k = kth_abs_value(a_dist, end_i) + + indices_mask = (start_top_k < torch.abs(a_dist)) & (torch.abs(a_dist) <= end_top_k) + if region_is_inverted: + indices_mask = ~indices_mask + indices_mask = torch.gather(indices_mask.float(), 0, redist_indices) + + a_redist = torch.gather(a_dist, 0, redist_indices) + a_redist = (1 - indices_mask) * a_flat + indices_mask * a_redist + return a_redist.reshape_as(a) + + +def kth_abs_value(a: Tensor, k: int) -> Tensor: + if k <= 0: + return torch.tensor(-1, device=a.device) + else: + return torch.kthvalue(torch.abs(a.float()), k)[0] + + +def ratio_to_region(width: float, offset: float, n: int) -> Tuple[int, int, bool]: + if width < 0: + offset += width + width = -width + width = min(width, 1) + + if offset < 0: + offset = 1 + offset - int(offset) + offset = math.fmod(offset, 1.0) + + if width + offset <= 1: + inverted = False + start = offset * n + end = (width + offset) * n + else: + inverted = True + start = (width + offset - 1) * n + end = offset * n + + return round(start), round(end), inverted + + +def similarity_add_difference( + a: Tensor, b: Tensor, c: Tensor, alpha: float, beta: float, **kwargs +) -> Tensor: + threshold = torch.maximum(torch.abs(a), torch.abs(b)) + similarity = ((a * b / threshold**2) + 1) / 2 + similarity = torch.nan_to_num(similarity * beta, nan=beta) + + ab_diff = a + alpha * (b - c) + ab_sum = (1 - alpha / 2) * a + (alpha / 2) * b + return (1 - similarity) * ab_diff + similarity * ab_sum + + +def distribution_crossover( + a: Tensor, b: Tensor, c: Tensor, alpha: float, beta: float, **kwargs +): + if a.shape == (): + return alpha * a + (1 - alpha) * b + + c_indices = torch.argsort(torch.flatten(c)) + a_dist = torch.gather(torch.flatten(a), 0, c_indices) + b_dist = torch.gather(torch.flatten(b), 0, c_indices) + + a_dft = torch.fft.rfft(a_dist.float()) + b_dft = torch.fft.rfft(b_dist.float()) + + dft_filter = torch.arange(0, torch.numel(a_dft), device=a_dft.device).float() + dft_filter /= torch.numel(a_dft) + if beta > EPSILON: + dft_filter = (dft_filter - alpha) / beta + 1 / 2 + dft_filter = torch.clamp(dft_filter, 0.0, 1.0) + else: + dft_filter = (dft_filter >= alpha).float() + + x_dft = (1 - dft_filter) * a_dft + dft_filter * b_dft + x_dist = torch.fft.irfft(x_dft, a_dist.shape[0]) + x_values = torch.gather(x_dist, 0, torch.argsort(c_indices)) + return x_values.reshape_as(a) + + +def ties_add_difference( + a: Tensor, b: Tensor, c: Tensor, alpha: float, beta: float, **kwargs +) -> Tensor: + deltas = [] + signs = [] + for m in [a, b]: + deltas.append(filter_top_k(m - c, beta)) + signs.append(torch.sign(deltas[-1])) + + signs = torch.stack(signs, dim=0) + final_sign = torch.sign(torch.sum(signs, dim=0)) + delta_filters = (signs == final_sign).float() + + res = torch.zeros_like(c, device=c.device) + for delta_filter, delta in zip(delta_filters, deltas): + res += delta_filter * delta + + param_count = torch.sum(delta_filters, dim=0) + return c + alpha * torch.nan_to_num(res / param_count) + + +def filter_top_k(a: Tensor, k: float): + k = max(int((1 - k) * torch.numel(a)), 1) + k_value, _ = torch.kthvalue(torch.abs(a.flatten()).float(), k) + top_k_filter = (torch.abs(a) >= k_value).float() + return a * top_k_filter diff --git a/modules/merging/model.py b/modules/merging/model.py new file mode 100644 index 000000000..d2d6470ec --- /dev/null +++ b/modules/merging/model.py @@ -0,0 +1,56 @@ +# import logging +import os +from dataclasses import dataclass + +import safetensors +import torch +from tensordict import TensorDict + +# logging.getLogger("sd_meh").addHandler(logging.NullHandler()) + + +@dataclass +class SDModel: + model_path: os.PathLike + device: str + + def load_model(self): + # logging.info(f"Loading: {self.model_path}") + if self.model_path.suffix == ".safetensors": + ckpt = safetensors.torch.load_file( + self.model_path, + device=self.device, + ) + else: + ckpt = torch.load(self.model_path, map_location=self.device) + + return TensorDict.from_dict(get_state_dict_from_checkpoint(ckpt)) + + +# TODO: tidy up +# from: stable-diffusion-webui/modules/sd_models.py +def get_state_dict_from_checkpoint(pl_sd): + pl_sd = pl_sd.pop("state_dict", pl_sd) + pl_sd.pop("state_dict", None) + sd = {} + for k, v in pl_sd.items(): + if new_key := transform_checkpoint_dict_key(k): + sd[new_key] = v + + pl_sd.clear() + pl_sd.update(sd) + return pl_sd + + +chckpoint_dict_replacements = { + "cond_stage_model.transformer.embeddings.": "cond_stage_model.transformer.text_model.embeddings.", + "cond_stage_model.transformer.encoder.": "cond_stage_model.transformer.text_model.encoder.", + "cond_stage_model.transformer.final_layer_norm.": "cond_stage_model.transformer.text_model.final_layer_norm.", +} + + +def transform_checkpoint_dict_key(k): + for text, replacement in chckpoint_dict_replacements.items(): + if k.startswith(text): + k = replacement + k[len(text):] + return k diff --git a/modules/merging/presets.py b/modules/merging/presets.py new file mode 100644 index 000000000..40ec85010 --- /dev/null +++ b/modules/merging/presets.py @@ -0,0 +1,62 @@ +BLOCK_WEIGHTS_PRESETS = { + "GRAD_V": [0, 1, 0.9166666667, 0.8333333333, 0.75, 0.6666666667, 0.5833333333, 0.5, 0.4166666667, 0.3333333333, 0.25, 0.1666666667, 0.0833333333, 0, 0.0833333333, 0.1666666667, 0.25, 0.3333333333, 0.4166666667, 0.5, 0.5833333333, 0.6666666667, 0.75, 0.8333333333, 0.9166666667, 1.0], + "GRAD_A": [0, 0, 0.0833333333, 0.1666666667, 0.25, 0.3333333333, 0.4166666667, 0.5, 0.5833333333, 0.6666666667, 0.75, 0.8333333333, 0.9166666667, 1.0, 0.9166666667, 0.8333333333, 0.75, 0.6666666667, 0.5833333333, 0.5, 0.4166666667, 0.3333333333, 0.25, 0.1666666667, 0.0833333333, 0], + "FLAT_25": [0, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25], + "FLAT_75": [0, 0.75, 0.75, 0.75, 0.75, 0.75, 0.75, 0.75, 0.75, 0.75, 0.75, 0.75, 0.75, 0.75, 0.75, 0.75, 0.75, 0.75, 0.75, 0.75, 0.75, 0.75, 0.75, 0.75, 0.75, 0.75], + "WRAP08": [0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1], + "WRAP12": [0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1], + "WRAP14": [0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1], + "WRAP16": [0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1], + "MID12_50": [0, 0, 0, 0, 0, 0, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0, 0, 0, 0, 0, 0], + "OUT07": [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1], + "OUT12": [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], + "OUT12_5": [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.5, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], + "RING08_SOFT": [0, 0, 0, 0, 0, 0, 0.5, 1, 1, 1, 0.5, 0, 0, 0, 0, 0, 0.5, 1, 1, 1, 0.5, 0, 0, 0, 0, 0], + "RING08_5": [0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0], + "RING10_5": [0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0], + "RING10_3": [0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0], + "SMOOTHSTEP": [0, 0, 0.00506365740740741, 0.0196759259259259, 0.04296875, 0.0740740740740741, 0.112123842592593, 0.15625, 0.205584490740741, 0.259259259259259, 0.31640625, 0.376157407407407, 0.437644675925926, 0.5, 0.562355324074074, 0.623842592592592, 0.68359375, 0.740740740740741, 0.794415509259259, 0.84375, 0.887876157407408, 0.925925925925926, 0.95703125, 0.980324074074074, 0.994936342592593, 1], + "REVERSE_SMOOTHSTEP": [0, 1, 0.994936342592593, 0.980324074074074, 0.95703125, 0.925925925925926, 0.887876157407407, 0.84375, 0.794415509259259, 0.740740740740741, 0.68359375, 0.623842592592593, 0.562355324074074, 0.5, 0.437644675925926, 0.376157407407408, 0.31640625, 0.259259259259259, 0.205584490740741, 0.15625, 0.112123842592592, 0.0740740740740742, 0.0429687499999996, 0.0196759259259258, 0.00506365740740744, 0], + "2SMOOTHSTEP": [0, 0, 0.0101273148148148, 0.0393518518518519, 0.0859375, 0.148148148148148, 0.224247685185185, 0.3125, 0.411168981481482, 0.518518518518519, 0.6328125, 0.752314814814815, 0.875289351851852, 1.0, 0.875289351851852, 0.752314814814815, 0.6328125, 0.518518518518519, 0.411168981481481, 0.3125, 0.224247685185184, 0.148148148148148, 0.0859375, 0.0393518518518512, 0.0101273148148153, 0], + "2R_SMOOTHSTEP": [0, 1, 0.989872685185185, 0.960648148148148, 0.9140625, 0.851851851851852, 0.775752314814815, 0.6875, 0.588831018518519, 0.481481481481481, 0.3671875, 0.247685185185185, 0.124710648148148, 0.0, 0.124710648148148, 0.247685185185185, 0.3671875, 0.481481481481481, 0.588831018518519, 0.6875, 0.775752314814816, 0.851851851851852, 0.9140625, 0.960648148148149, 0.989872685185185, 1], + "3SMOOTHSTEP": [0, 0, 0.0151909722222222, 0.0590277777777778, 0.12890625, 0.222222222222222, 0.336371527777778, 0.46875, 0.616753472222222, 0.777777777777778, 0.94921875, 0.871527777777778, 0.687065972222222, 0.5, 0.312934027777778, 0.128472222222222, 0.0507812500000004, 0.222222222222222, 0.383246527777778, 0.53125, 0.663628472222223, 0.777777777777778, 0.87109375, 0.940972222222222, 0.984809027777777, 1], + "3R_SMOOTHSTEP": [0, 1, 0.984809027777778, 0.940972222222222, 0.87109375, 0.777777777777778, 0.663628472222222, 0.53125, 0.383246527777778, 0.222222222222222, 0.05078125, 0.128472222222222, 0.312934027777778, 0.5, 0.687065972222222, 0.871527777777778, 0.94921875, 0.777777777777778, 0.616753472222222, 0.46875, 0.336371527777777, 0.222222222222222, 0.12890625, 0.0590277777777777, 0.0151909722222232, 0], + "4SMOOTHSTEP": [0, 0, 0.0202546296296296, 0.0787037037037037, 0.171875, 0.296296296296296, 0.44849537037037, 0.625, 0.822337962962963, 0.962962962962963, 0.734375, 0.49537037037037, 0.249421296296296, 0.0, 0.249421296296296, 0.495370370370371, 0.734375000000001, 0.962962962962963, 0.822337962962962, 0.625, 0.448495370370369, 0.296296296296297, 0.171875, 0.0787037037037024, 0.0202546296296307, 0], + "4R_SMOOTHSTEP": [0, 1, 0.97974537037037, 0.921296296296296, 0.828125, 0.703703703703704, 0.55150462962963, 0.375, 0.177662037037037, 0.0370370370370372, 0.265625, 0.50462962962963, 0.750578703703704, 1.0, 0.750578703703704, 0.504629629629629, 0.265624999999999, 0.0370370370370372, 0.177662037037038, 0.375, 0.551504629629631, 0.703703703703703, 0.828125, 0.921296296296298, 0.979745370370369, 1], + "HALF_SMOOTHSTEP": [0, 0, 0.0196759259259259, 0.0740740740740741, 0.15625, 0.259259259259259, 0.376157407407407, 0.5, 0.623842592592593, 0.740740740740741, 0.84375, 0.925925925925926, 0.980324074074074, 1.0, 0.980324074074074, 0.925925925925926, 0.84375, 0.740740740740741, 0.623842592592593, 0.5, 0.376157407407407, 0.259259259259259, 0.15625, 0.0740740740740741, 0.0196759259259259, 0], + "HALF_R_SMOOTHSTEP": [0, 1, 0.980324074074074, 0.925925925925926, 0.84375, 0.740740740740741, 0.623842592592593, 0.5, 0.376157407407407, 0.259259259259259, 0.15625, 0.0740740740740742, 0.0196759259259256, 0.0, 0.0196759259259256, 0.0740740740740742, 0.15625, 0.259259259259259, 0.376157407407407, 0.5, 0.623842592592593, 0.740740740740741, 0.84375, 0.925925925925926, 0.980324074074074, 1], + "ONE_THIRD_SMOOTHSTEP": [0, 0, 0.04296875, 0.15625, 0.31640625, 0.5, 0.68359375, 0.84375, 0.95703125, 1.0, 0.95703125, 0.84375, 0.68359375, 0.5, 0.31640625, 0.15625, 0.04296875, 0.0, 0.04296875, 0.15625, 0.31640625, 0.5, 0.68359375, 0.84375, 0.95703125, 1], + "ONE_THIRD_R_SMOOTHSTEP": [0, 1, 0.95703125, 0.84375, 0.68359375, 0.5, 0.31640625, 0.15625, 0.04296875, 0.0, 0.04296875, 0.15625, 0.31640625, 0.5, 0.68359375, 0.84375, 0.95703125, 1.0, 0.95703125, 0.84375, 0.68359375, 0.5, 0.31640625, 0.15625, 0.04296875, 0], + "ONE_FOURTH_SMOOTHSTEP": [0, 0, 0.0740740740740741, 0.259259259259259, 0.5, 0.740740740740741, 0.925925925925926, 1.0, 0.925925925925926, 0.740740740740741, 0.5, 0.259259259259259, 0.0740740740740741, 0.0, 0.0740740740740741, 0.259259259259259, 0.5, 0.740740740740741, 0.925925925925926, 1.0, 0.925925925925926, 0.740740740740741, 0.5, 0.259259259259259, 0.0740740740740741, 0], + "ONE_FOURTH_R_SMOOTHSTEP": [0, 1, 0.925925925925926, 0.740740740740741, 0.5, 0.259259259259259, 0.0740740740740742, 0.0, 0.0740740740740742, 0.259259259259259, 0.5, 0.740740740740741, 0.925925925925926, 1.0, 0.925925925925926, 0.740740740740741, 0.5, 0.259259259259259, 0.0740740740740742, 0.0, 0.0740740740740742, 0.259259259259259, 0.5, 0.740740740740741, 0.925925925925926, 1], + "COSINE": [0, 1, 0.995722430686905, 0.982962913144534, 0.961939766255643, 0.933012701892219, 0.896676670145617, 0.853553390593274, 0.80438071450436, 0.75, 0.691341716182545, 0.62940952255126, 0.565263096110026, 0.5, 0.434736903889974, 0.37059047744874, 0.308658283817455, 0.25, 0.195619285495639, 0.146446609406726, 0.103323329854382, 0.0669872981077805, 0.0380602337443566, 0.0170370868554658, 0.00427756931309475, 0], + "REVERSE_COSINE": [0, 0, 0.00427756931309475, 0.0170370868554659, 0.0380602337443566, 0.0669872981077808, 0.103323329854383, 0.146446609406726, 0.19561928549564, 0.25, 0.308658283817455, 0.37059047744874, 0.434736903889974, 0.5, 0.565263096110026, 0.62940952255126, 0.691341716182545, 0.75, 0.804380714504361, 0.853553390593274, 0.896676670145618, 0.933012701892219, 0.961939766255643, 0.982962913144534, 0.995722430686905, 1], + "CUBIC_HERMITE": [0, 0, 0.157576195987654, 0.28491512345679, 0.384765625, 0.459876543209877, 0.512996720679012, 0.546875, 0.564260223765432, 0.567901234567901, 0.560546875, 0.544945987654321, 0.523847415123457, 0.5, 0.476152584876543, 0.455054012345679, 0.439453125, 0.432098765432099, 0.435739776234568, 0.453125, 0.487003279320987, 0.540123456790124, 0.615234375, 0.71508487654321, 0.842423804012347, 1], + "REVERSE_CUBIC_HERMITE": [0, 1, 0.842423804012346, 0.71508487654321, 0.615234375, 0.540123456790123, 0.487003279320988, 0.453125, 0.435739776234568, 0.432098765432099, 0.439453125, 0.455054012345679, 0.476152584876543, 0.5, 0.523847415123457, 0.544945987654321, 0.560546875, 0.567901234567901, 0.564260223765432, 0.546875, 0.512996720679013, 0.459876543209876, 0.384765625, 0.28491512345679, 0.157576195987653, 0], + "ALL_A": [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + "ALL_B": [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], +} + + +SDXL_BLOCK_WEIGHTS_PRESETS = { + "SDXL_GRAD_V": [0, 1.0, 0.888889, 0.777778, 0.666667, 0.555556, 0.444444, 0.333333, 0.222222, 0.111111, 0.0, 0.111111, 0.222222, 0.333333, 0.444444, 0.555556, 0.666667, 0.777778, 0.888889, 1.0], + "SDXL_GRAD_A": [0, 0.0, 0.111111, 0.222222, 0.333333, 0.444444, 0.555556, 0.666667, 0.777778, 0.888889, 1.0, 0.888889, 0.777778, 0.666667, 0.555556, 0.444444, 0.333333, 0.222222, 0.111111, 0.0], + "SDXL_FLAT_25": [0, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25], + "SDXL_FLAT_75": [0, 0.75, 0.75, 0.75, 0.75, 0.75, 0.75, 0.75, 0.75, 0.75, 0.75, 0.75, 0.75, 0.75, 0.75, 0.75, 0.75, 0.75, 0.75, 0.75], + "SDXL_WRAP08": [0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1], + "SDXL_WRAP12": [0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1], + "SDXL_WRAP14": [0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1], + "SDXL_OUT07": [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1], + "SDXL_SMOOTHSTEP": [0, 0, 0.008916, 0.034294, 0.074074, 0.126200, 0.188615, 0.259259, 0.336077, 0.417010, 0.500000, 0.582990, 0.663923, 0.740741, 0.811385, 0.873800, 0.925926, 0.965706, 0.991084, 1], + "SDXL_REVERSE_SMOOTHSTEP": [0, 1, 0.991084, 0.965706, 0.925926, 0.873800, 0.811385, 0.740741, 0.663923, 0.582990, 0.500000, 0.417010, 0.336077, 0.259259, 0.188615, 0.126200, 0.074074, 0.034294, 0.008916, 0], + "SDXL_HALF_SMOOTHSTEP": [0, 0, 0.034294, 0.126200, 0.259259, 0.417010, 0.582990, 0.740741, 0.873800, 0.965706, 1, 0.965706, 0.873800, 0.740741, 0.582990, 0.417010, 0.259259, 0.126200, 0.034294, 0], + "SDXL_HALF_R_SMOOTHSTEP": [0, 1, 0.965706, 0.873800, 0.740741, 0.582990, 0.417010, 0.259259, 0.126200, 0.034294, 0, 0.034294, 0.126200, 0.259259, 0.417010, 0.582990, 0.740741, 0.873800, 0.965706, 1], + "SDXL_ONE_THIRD_SMOOTHSTEP": [0, 0, 0.074074, 0.259259, 0.500000, 0.740741, 0.925926, 1, 0.907407, 0.592593, 0, 0.592593, 0.907407, 1, 0.925926, 0.740741, 0.500000, 0.259259, 0.074074, 0], + "SDXL_ONE_THIRD_R_SMOOTHSTEP": [0, 1, 0.925926, 0.740741, 0.500000, 0.259259, 0.074074, 0, 0.092593, 0.407407, 1, 0.407407, 0.092593, 0, 0.074074, 0.259259, 0.500000, 0.740741, 0.925926, 1], + "SDXL_COSINE": [0, 1, 0.992404, 0.969846, 0.933013, 0.883022, 0.821394, 0.750000, 0.671010, 0.586824, 0.500000, 0.413176, 0.328990, 0.250000, 0.178606, 0.116978, 0.066987, 0.030154, 0.007596, 0], + "SDXL_REVERSE_COSINE": [0, 0, 0.007596, 0.030154, 0.066987, 0.116978, 0.178606, 0.250000, 0.328990, 0.413176, 0.500000, 0.586824, 0.671010, 0.750000, 0.821394, 0.883022, 0.933013, 0.969846, 0.992404, 1], + "SDXL_CUBIC_HERMITE": [0, 0, 0.268023, 0.461058, 0.588477, 0.659656, 0.683966, 0.670782, 0.629477, 0.569425, 0.500000, 0.430575, 0.370523, 0.329218, 0.316034, 0.340344, 0.411523, 0.538942, 0.731977, 1], + "SDXL_REVERSE_CUBIC_HERMITE": [0, 1, 0.731977, 0.538942, 0.411523, 0.340344, 0.316034, 0.329218, 0.370523, 0.430575, 0.500000, 0.569425, 0.629477, 0.670782, 0.683966, 0.659656, 0.588477, 0.461058, 0.268023, 0], + "SDXL_ALL_A": [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + "SDXL_ALL_B": [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], +} diff --git a/modules/merging/rebasin.py b/modules/merging/rebasin.py new file mode 100644 index 000000000..a0ef80d49 --- /dev/null +++ b/modules/merging/rebasin.py @@ -0,0 +1,2287 @@ +# https://github.com/ogkalu2/Merge-Stable-Diffusion-models-without-distortion +from collections import defaultdict +from random import shuffle +from typing import NamedTuple +import torch +from scipy.optimize import linear_sum_assignment + +SPECIAL_KEYS = [ + "first_stage_model.decoder.norm_out.weight", + "first_stage_model.decoder.norm_out.bias", + "first_stage_model.encoder.norm_out.weight", + "first_stage_model.encoder.norm_out.bias", + "model.diffusion_model.out.0.weight", + "model.diffusion_model.out.0.bias", +] + + +class PermutationSpec(NamedTuple): + perm_to_axes: dict + axes_to_perm: dict + + +def permutation_spec_from_axes_to_perm(axes_to_perm: dict) -> PermutationSpec: + perm_to_axes = defaultdict(list) + for wk, axis_perms in axes_to_perm.items(): + for axis, perm in enumerate(axis_perms): + if perm is not None: + perm_to_axes[perm].append((wk, axis)) + return PermutationSpec(perm_to_axes=dict(perm_to_axes), axes_to_perm=axes_to_perm) + + +def sdunet_permutation_spec() -> PermutationSpec: + conv = lambda name, p_in, p_out: { + f"{name}.weight": ( + p_out, + p_in, + ), + f"{name}.bias": (p_out,), + } + norm = lambda name, p: {f"{name}.weight": (p,), f"{name}.bias": (p,)} + dense = ( + lambda name, p_in, p_out, bias=True: { + f"{name}.weight": (p_out, p_in), + f"{name}.bias": (p_out,), + } + if bias + else {f"{name}.weight": (p_out, p_in)} + ) + skip = lambda name, p_in, p_out: { + f"{name}": ( + p_out, + p_in, + None, + None, + ) + } + + # Unet Res blocks + easyblock = lambda name, p_in, p_out: { + **norm(f"{name}.in_layers.0", p_in), + **conv(f"{name}.in_layers.2", p_in, f"P_{name}_inner"), + **dense( + f"{name}.emb_layers.1", f"P_{name}_inner2", f"P_{name}_inner3", bias=True + ), + **norm(f"{name}.out_layers.0", f"P_{name}_inner4"), + **conv(f"{name}.out_layers.3", f"P_{name}_inner4", p_out), + } + + # Text Encoder blocks + easyblock2 = lambda name, p: { + **norm(f"{name}.norm1", p), + **conv(f"{name}.conv1", p, f"P_{name}_inner"), + **norm(f"{name}.norm2", f"P_{name}_inner"), + **conv(f"{name}.conv2", f"P_{name}_inner", p), + } + + # This is for blocks that use a residual connection, but change the number of channels via a Conv. + shortcutblock = lambda name, p_in, p_out: { + **norm(f"{name}.norm1", p_in), + **conv(f"{name}.conv1", p_in, f"P_{name}_inner"), + **norm(f"{name}.norm2", f"P_{name}_inner"), + **conv(f"{name}.conv2", f"P_{name}_inner", p_out), + **conv(f"{name}.nin_shortcut", p_in, p_out), + **norm(f"{name}.nin_shortcut", p_out), + } + + return permutation_spec_from_axes_to_perm( + { + # Skipped Layers + **skip("betas", None, None), + **skip("alphas_cumprod", None, None), + **skip("alphas_cumprod_prev", None, None), + **skip("sqrt_alphas_cumprod", None, None), + **skip("sqrt_one_minus_alphas_cumprod", None, None), + **skip("log_one_minus_alphas_cumprods", None, None), + **skip("sqrt_recip_alphas_cumprod", None, None), + **skip("sqrt_recipm1_alphas_cumprod", None, None), + **skip("posterior_variance", None, None), + **skip("posterior_log_variance_clipped", None, None), + **skip("posterior_mean_coef1", None, None), + **skip("posterior_mean_coef2", None, None), + **skip("log_one_minus_alphas_cumprod", None, None), + **skip("model_ema.decay", None, None), + **skip("model_ema.num_updates", None, None), + # initial + **dense("model.diffusion_model.time_embed.0", None, "P_bg0", bias=True), + **dense("model.diffusion_model.time_embed.2", "P_bg0", "P_bg1", bias=True), + **conv("model.diffusion_model.input_blocks.0.0", "P_bg2", "P_bg3"), + # input blocks + **easyblock("model.diffusion_model.input_blocks.1.0", "P_bg4", "P_bg5"), + **norm("model.diffusion_model.input_blocks.1.1.norm", "P_bg6"), + **conv("model.diffusion_model.input_blocks.1.1.proj_in", "P_bg6", "P_bg7"), + **dense( + "model.diffusion_model.input_blocks.1.1.transformer_blocks.0.attn1.to_q", + "P_bg8", + "P_bg9", + bias=False, + ), + **dense( + "model.diffusion_model.input_blocks.1.1.transformer_blocks.0.attn1.to_k", + "P_bg8", + "P_bg9", + bias=False, + ), + **dense( + "model.diffusion_model.input_blocks.1.1.transformer_blocks.0.attn1.to_v", + "P_bg8", + "P_bg9", + bias=False, + ), + **dense( + "model.diffusion_model.input_blocks.1.1.transformer_blocks.0.attn1.to_out.0", + "P_bg8", + "P_bg9", + bias=True, + ), + **dense( + "model.diffusion_model.input_blocks.1.1.transformer_blocks.0.ff.net.0.proj", + "P_bg10", + "P_bg11", + bias=True, + ), + **dense( + "model.diffusion_model.input_blocks.1.1.transformer_blocks.0.ff.net.2", + "P_bg12", + "P_bg13", + bias=True, + ), + **dense( + "model.diffusion_model.input_blocks.1.1.transformer_blocks.0.attn2.to_q", + "P_bg14", + "P_bg15", + bias=False, + ), + **dense( + "model.diffusion_model.input_blocks.1.1.transformer_blocks.0.attn2.to_k", + "P_bg16", + "P_bg17", + bias=False, + ), + **dense( + "model.diffusion_model.input_blocks.1.1.transformer_blocks.0.attn2.to_v", + "P_bg16", + "P_bg17", + bias=False, + ), + **dense( + "model.diffusion_model.input_blocks.1.1.transformer_blocks.0.attn2.to_out.0", + "P_bg18", + "P_bg19", + bias=True, + ), + **norm( + "model.diffusion_model.input_blocks.1.1.transformer_blocks.0.norm1", + "P_bg19", + ), + **norm( + "model.diffusion_model.input_blocks.1.1.transformer_blocks.0.norm2", + "P_bg19", + ), + **norm( + "model.diffusion_model.input_blocks.1.1.transformer_blocks.0.norm3", + "P_bg19", + ), + **conv( + "model.diffusion_model.input_blocks.1.1.proj_out", "P_bg19", "P_bg20" + ), + **easyblock("model.diffusion_model.input_blocks.2.0", "P_bg21", "P_bg22"), + **norm("model.diffusion_model.input_blocks.2.1.norm", "P_bg23"), + **conv( + "model.diffusion_model.input_blocks.2.1.proj_in", "P_bg23", "P_bg24" + ), + **dense( + "model.diffusion_model.input_blocks.2.1.transformer_blocks.0.attn1.to_q", + "P_bg25", + "P_bg26", + bias=False, + ), + **dense( + "model.diffusion_model.input_blocks.2.1.transformer_blocks.0.attn1.to_k", + "P_bg25", + "P_bg26", + bias=False, + ), + **dense( + "model.diffusion_model.input_blocks.2.1.transformer_blocks.0.attn1.to_v", + "P_bg25", + "P_bg26", + bias=False, + ), + **dense( + "model.diffusion_model.input_blocks.2.1.transformer_blocks.0.attn1.to_out.0", + "P_bg25", + "P_bg26", + bias=True, + ), + **dense( + "model.diffusion_model.input_blocks.2.1.transformer_blocks.0.ff.net.0.proj", + "P_bg27", + "P_bg28", + bias=True, + ), + **dense( + "model.diffusion_model.input_blocks.2.1.transformer_blocks.0.ff.net.2", + "P_bg29", + "P_bg30", + bias=True, + ), + **dense( + "model.diffusion_model.input_blocks.2.1.transformer_blocks.0.attn2.to_q", + "P_bg31", + "P_bg32", + bias=False, + ), + **dense( + "model.diffusion_model.input_blocks.2.1.transformer_blocks.0.attn2.to_k", + "P_bg33", + "P_bg34", + bias=False, + ), + **dense( + "model.diffusion_model.input_blocks.2.1.transformer_blocks.0.attn2.to_v", + "P_bg33", + "P_bg34", + bias=False, + ), + **dense( + "model.diffusion_model.input_blocks.2.1.transformer_blocks.0.attn2.to_out.0", + "P_bg35", + "P_bg36", + bias=True, + ), + **norm( + "model.diffusion_model.input_blocks.2.1.transformer_blocks.0.norm1", + "P_bg36", + ), + **norm( + "model.diffusion_model.input_blocks.2.1.transformer_blocks.0.norm2", + "P_bg36", + ), + **norm( + "model.diffusion_model.input_blocks.2.1.transformer_blocks.0.norm3", + "P_bg36", + ), + **conv( + "model.diffusion_model.input_blocks.2.1.proj_out", "P_bg36", "P_bg37" + ), + **conv("model.diffusion_model.input_blocks.3.0.op", "P_bg38", "P_bg39"), + **easyblock("model.diffusion_model.input_blocks.4.0", "P_bg40", "P_bg41"), + **conv( + "model.diffusion_model.input_blocks.4.0.skip_connection", + "P_bg42", + "P_bg43", + ), + **norm("model.diffusion_model.input_blocks.4.1.norm", "P_bg44"), + **conv( + "model.diffusion_model.input_blocks.4.1.proj_in", "P_bg44", "P_bg45" + ), + **dense( + "model.diffusion_model.input_blocks.4.1.transformer_blocks.0.attn1.to_q", + "P_bg46", + "P_bg47", + bias=False, + ), + **dense( + "model.diffusion_model.input_blocks.4.1.transformer_blocks.0.attn1.to_k", + "P_bg46", + "P_bg47", + bias=False, + ), + **dense( + "model.diffusion_model.input_blocks.4.1.transformer_blocks.0.attn1.to_v", + "P_bg46", + "P_bg47", + bias=False, + ), + **dense( + "model.diffusion_model.input_blocks.4.1.transformer_blocks.0.attn1.to_out.0", + "P_bg46", + "P_bg47", + bias=True, + ), + **dense( + "model.diffusion_model.input_blocks.4.1.transformer_blocks.0.ff.net.0.proj", + "P_bg48", + "P_bg49", + bias=True, + ), + **dense( + "model.diffusion_model.input_blocks.4.1.transformer_blocks.0.ff.net.2", + "P_bg50", + "P_bg51", + bias=True, + ), + **dense( + "model.diffusion_model.input_blocks.4.1.transformer_blocks.0.attn2.to_q", + "P_bg52", + "P_bg53", + bias=False, + ), + **dense( + "model.diffusion_model.input_blocks.4.1.transformer_blocks.0.attn2.to_k", + "P_bg54", + "P_bg55", + bias=False, + ), + **dense( + "model.diffusion_model.input_blocks.4.1.transformer_blocks.0.attn2.to_v", + "P_bg54", + "P_bg55", + bias=False, + ), + **dense( + "model.diffusion_model.input_blocks.4.1.transformer_blocks.0.attn2.to_out.0", + "P_bg56", + "P_bg57", + bias=True, + ), + **norm( + "model.diffusion_model.input_blocks.4.1.transformer_blocks.0.norm1", + "P_bg57", + ), + **norm( + "model.diffusion_model.input_blocks.4.1.transformer_blocks.0.norm2", + "P_bg57", + ), + **norm( + "model.diffusion_model.input_blocks.4.1.transformer_blocks.0.norm3", + "P_bg57", + ), + **conv( + "model.diffusion_model.input_blocks.4.1.proj_out", "P_bg57", "P_bg58" + ), + **easyblock("model.diffusion_model.input_blocks.5.0", "P_bg59", "P_bg60"), + **norm("model.diffusion_model.input_blocks.5.1.norm", "P_bg61"), + **conv( + "model.diffusion_model.input_blocks.5.1.proj_in", "P_bg61", "P_bg62" + ), + **dense( + "model.diffusion_model.input_blocks.5.1.transformer_blocks.0.attn1.to_q", + "P_bg63", + "P_bg64", + bias=False, + ), + **dense( + "model.diffusion_model.input_blocks.5.1.transformer_blocks.0.attn1.to_k", + "P_bg63", + "P_bg64", + bias=False, + ), + **dense( + "model.diffusion_model.input_blocks.5.1.transformer_blocks.0.attn1.to_v", + "P_bg63", + "P_bg64", + bias=False, + ), + **dense( + "model.diffusion_model.input_blocks.5.1.transformer_blocks.0.attn1.to_out.0", + "P_bg63", + "P_bg64", + bias=True, + ), + **dense( + "model.diffusion_model.input_blocks.5.1.transformer_blocks.0.ff.net.0.proj", + "P_bg65", + "P_bg66", + bias=True, + ), + **dense( + "model.diffusion_model.input_blocks.5.1.transformer_blocks.0.ff.net.2", + "P_bg67", + "P_bg68", + bias=True, + ), + **dense( + "model.diffusion_model.input_blocks.5.1.transformer_blocks.0.attn2.to_q", + "P_bg69", + "P_bg70", + bias=False, + ), + **dense( + "model.diffusion_model.input_blocks.5.1.transformer_blocks.0.attn2.to_k", + "P_bg71", + "P_bg72", + bias=False, + ), + **dense( + "model.diffusion_model.input_blocks.5.1.transformer_blocks.0.attn2.to_v", + "P_bg71", + "P_bg72", + bias=False, + ), + **dense( + "model.diffusion_model.input_blocks.5.1.transformer_blocks.0.attn2.to_out.0", + "P_bg73", + "P_bg74", + bias=True, + ), + **norm( + "model.diffusion_model.input_blocks.5.1.transformer_blocks.0.norm1", + "P_bg74", + ), + **norm( + "model.diffusion_model.input_blocks.5.1.transformer_blocks.0.norm2", + "P_bg74", + ), + **norm( + "model.diffusion_model.input_blocks.5.1.transformer_blocks.0.norm3", + "P_bg74", + ), + **conv( + "model.diffusion_model.input_blocks.5.1.proj_out", "P_bg74", "P_bg75" + ), + **conv("model.diffusion_model.input_blocks.6.0.op", "P_bg76", "P_bg77"), + **easyblock("model.diffusion_model.input_blocks.7.0", "P_bg78", "P_bg79"), + **conv( + "model.diffusion_model.input_blocks.7.0.skip_connection", + "P_bg80", + "P_bg81", + ), + **norm("model.diffusion_model.input_blocks.7.1.norm", "P_bg82"), + **conv( + "model.diffusion_model.input_blocks.7.1.proj_in", "P_bg82", "P_bg83" + ), + **dense( + "model.diffusion_model.input_blocks.7.1.transformer_blocks.0.attn1.to_q", + "P_bg84", + "P_bg85", + bias=False, + ), + **dense( + "model.diffusion_model.input_blocks.7.1.transformer_blocks.0.attn1.to_k", + "P_bg84", + "P_bg85", + bias=False, + ), + **dense( + "model.diffusion_model.input_blocks.7.1.transformer_blocks.0.attn1.to_v", + "P_bg84", + "P_bg85", + bias=False, + ), + **dense( + "model.diffusion_model.input_blocks.7.1.transformer_blocks.0.attn1.to_out.0", + "P_bg84", + "P_bg85", + bias=True, + ), + **dense( + "model.diffusion_model.input_blocks.7.1.transformer_blocks.0.ff.net.0.proj", + "P_bg86", + "P_bg87", + bias=True, + ), + **dense( + "model.diffusion_model.input_blocks.7.1.transformer_blocks.0.ff.net.2", + "P_bg88", + "P_bg89", + bias=True, + ), + **dense( + "model.diffusion_model.input_blocks.7.1.transformer_blocks.0.attn2.to_q", + "P_bg90", + "P_bg91", + bias=False, + ), + **dense( + "model.diffusion_model.input_blocks.7.1.transformer_blocks.0.attn2.to_k", + "P_bg92", + "P_bg93", + bias=False, + ), + **dense( + "model.diffusion_model.input_blocks.7.1.transformer_blocks.0.attn2.to_v", + "P_bg92", + "P_bg93", + bias=False, + ), + **dense( + "model.diffusion_model.input_blocks.7.1.transformer_blocks.0.attn2.to_out.0", + "P_bg94", + "P_bg95", + bias=True, + ), + **norm( + "model.diffusion_model.input_blocks.7.1.transformer_blocks.0.norm1", + "P_bg95", + ), + **norm( + "model.diffusion_model.input_blocks.7.1.transformer_blocks.0.norm2", + "P_bg95", + ), + **norm( + "model.diffusion_model.input_blocks.7.1.transformer_blocks.0.norm3", + "P_bg95", + ), + **conv( + "model.diffusion_model.input_blocks.7.1.proj_out", "P_bg95", "P_bg96" + ), + **easyblock("model.diffusion_model.input_blocks.8.0", "P_bg97", "P_bg98"), + **norm("model.diffusion_model.input_blocks.8.1.norm", "P_bg99"), + **conv( + "model.diffusion_model.input_blocks.8.1.proj_in", "P_bg99", "P_bg100" + ), + **dense( + "model.diffusion_model.input_blocks.8.1.transformer_blocks.0.attn1.to_q", + "P_bg101", + "P_bg102", + bias=False, + ), + **dense( + "model.diffusion_model.input_blocks.8.1.transformer_blocks.0.attn1.to_k", + "P_bg101", + "P_bg102", + bias=False, + ), + **dense( + "model.diffusion_model.input_blocks.8.1.transformer_blocks.0.attn1.to_v", + "P_bg101", + "P_bg102", + bias=False, + ), + **dense( + "model.diffusion_model.input_blocks.8.1.transformer_blocks.0.attn1.to_out.0", + "P_bg101", + "P_bg102", + bias=True, + ), + **dense( + "model.diffusion_model.input_blocks.8.1.transformer_blocks.0.ff.net.0.proj", + "P_bg103", + "P_bg104", + bias=True, + ), + **dense( + "model.diffusion_model.input_blocks.8.1.transformer_blocks.0.ff.net.2", + "P_bg105", + "P_bg106", + bias=True, + ), + **dense( + "model.diffusion_model.input_blocks.8.1.transformer_blocks.0.attn2.to_q", + "P_bg107", + "P_bg108", + bias=False, + ), + **dense( + "model.diffusion_model.input_blocks.8.1.transformer_blocks.0.attn2.to_k", + "P_bg109", + "P_bg110", + bias=False, + ), + **dense( + "model.diffusion_model.input_blocks.8.1.transformer_blocks.0.attn2.to_v", + "P_bg109", + "P_bg110", + bias=False, + ), + **dense( + "model.diffusion_model.input_blocks.8.1.transformer_blocks.0.attn2.to_out.0", + "P_bg111", + "P_bg112", + bias=True, + ), + **norm( + "model.diffusion_model.input_blocks.8.1.transformer_blocks.0.norm1", + "P_bg112", + ), + **norm( + "model.diffusion_model.input_blocks.8.1.transformer_blocks.0.norm2", + "P_bg112", + ), + **norm( + "model.diffusion_model.input_blocks.8.1.transformer_blocks.0.norm3", + "P_bg112", + ), + **conv( + "model.diffusion_model.input_blocks.8.1.proj_out", "P_bg112", "P_bg113" + ), + **conv("model.diffusion_model.input_blocks.9.0.op", "P_bg114", "P_bg115"), + **easyblock( + "model.diffusion_model.input_blocks.10.0", "P_bg115", "P_bg116" + ), + **easyblock( + "model.diffusion_model.input_blocks.11.0", "P_bg116", "P_bg117" + ), + # middle blocks + **easyblock("model.diffusion_model.middle_block.0", "P_bg117", "P_bg118"), + **norm("model.diffusion_model.middle_block.1.norm", "P_bg119"), + **conv( + "model.diffusion_model.middle_block.1.proj_in", "P_bg119", "P_bg120" + ), + **dense( + "model.diffusion_model.middle_block.1.transformer_blocks.0.attn1.to_q", + "P_bg121", + "P_bg122", + bias=False, + ), + **dense( + "model.diffusion_model.middle_block.1.transformer_blocks.0.attn1.to_k", + "P_bg121", + "P_bg122", + bias=False, + ), + **dense( + "model.diffusion_model.middle_block.1.transformer_blocks.0.attn1.to_v", + "P_bg121", + "P_bg122", + bias=False, + ), + **dense( + "model.diffusion_model.middle_block.1.transformer_blocks.0.attn1.to_out.0", + "P_bg121", + "P_bg122", + bias=True, + ), + **dense( + "model.diffusion_model.middle_block.1.transformer_blocks.0.ff.net.0.proj", + "P_bg123", + "P_bg124", + bias=True, + ), + **dense( + "model.diffusion_model.middle_block.1.transformer_blocks.0.ff.net.2", + "P_bg125", + "P_bg126", + bias=True, + ), + **dense( + "model.diffusion_model.middle_block.1.transformer_blocks.0.attn2.to_q", + "P_bg127", + "P_bg128", + bias=False, + ), + **dense( + "model.diffusion_model.middle_block.1.transformer_blocks.0.attn2.to_k", + "P_bg129", + "P_bg130", + bias=False, + ), + **dense( + "model.diffusion_model.middle_block.1.transformer_blocks.0.attn2.to_v", + "P_bg129", + "P_bg130", + bias=False, + ), + **dense( + "model.diffusion_model.middle_block.1.transformer_blocks.0.attn2.to_out.0", + "P_bg131", + "P_bg132", + bias=True, + ), + **norm( + "model.diffusion_model.middle_block.1.transformer_blocks.0.norm1", + "P_bg132", + ), + **norm( + "model.diffusion_model.middle_block.1.transformer_blocks.0.norm2", + "P_bg132", + ), + **norm( + "model.diffusion_model.middle_block.1.transformer_blocks.0.norm3", + "P_bg132", + ), + **conv( + "model.diffusion_model.middle_block.1.proj_out", "P_bg132", "P_bg133" + ), + **easyblock("model.diffusion_model.middle_block.2", "P_bg134", "P_bg135"), + # output blocks + **easyblock( + "model.diffusion_model.output_blocks.0.0", "P_bg136", "P_bg137" + ), + **conv( + "model.diffusion_model.output_blocks.0.0.skip_connection", + "P_bg138", + "P_bg139", + ), + **easyblock( + "model.diffusion_model.output_blocks.1.0", "P_bg140", "P_bg141" + ), + **conv( + "model.diffusion_model.output_blocks.1.0.skip_connection", + "P_bg142", + "P_bg143", + ), + **easyblock( + "model.diffusion_model.output_blocks.2.0", "P_bg144", "P_bg145" + ), + **conv( + "model.diffusion_model.output_blocks.2.0.skip_connection", + "P_bg146", + "P_bg147", + ), + **conv( + "model.diffusion_model.output_blocks.2.1.conv", "P_bg148", "P_bg149" + ), + **easyblock( + "model.diffusion_model.output_blocks.3.0", "P_bg150", "P_bg151" + ), + **conv( + "model.diffusion_model.output_blocks.3.0.skip_connection", + "P_bg152", + "P_bg153", + ), + **norm("model.diffusion_model.output_blocks.3.1.norm", "P_bg154"), + **conv( + "model.diffusion_model.output_blocks.3.1.proj_in", "P_bg154", "P_bg155" + ), + **dense( + "model.diffusion_model.output_blocks.3.1.transformer_blocks.0.attn1.to_q", + "P_bg156", + "P_bg157", + bias=False, + ), + **dense( + "model.diffusion_model.output_blocks.3.1.transformer_blocks.0.attn1.to_k", + "P_bg156", + "P_bg157", + bias=False, + ), + **dense( + "model.diffusion_model.output_blocks.3.1.transformer_blocks.0.attn1.to_v", + "P_bg156", + "P_bg157", + bias=False, + ), + **dense( + "model.diffusion_model.output_blocks.3.1.transformer_blocks.0.attn1.to_out.0", + "P_bg156", + "P_bg157", + bias=True, + ), + **dense( + "model.diffusion_model.output_blocks.3.1.transformer_blocks.0.ff.net.0.proj", + "P_bg158", + "P_bg159", + bias=True, + ), + **dense( + "model.diffusion_model.output_blocks.3.1.transformer_blocks.0.ff.net.2", + "P_bg160", + "P_bg161", + bias=True, + ), + **dense( + "model.diffusion_model.output_blocks.3.1.transformer_blocks.0.attn2.to_q", + "P_bg162", + "P_bg163", + bias=False, + ), + **dense( + "model.diffusion_model.output_blocks.3.1.transformer_blocks.0.attn2.to_k", + "P_bg164", + "P_bg165", + bias=False, + ), + **dense( + "model.diffusion_model.output_blocks.3.1.transformer_blocks.0.attn2.to_v", + "P_bg164", + "P_bg165", + bias=False, + ), + **dense( + "model.diffusion_model.output_blocks.3.1.transformer_blocks.0.attn2.to_out.0", + "P_bg166", + "P_bg167", + bias=True, + ), + **norm( + "model.diffusion_model.output_blocks.3.1.transformer_blocks.0.norm1", + "P_bg167", + ), + **norm( + "model.diffusion_model.output_blocks.3.1.transformer_blocks.0.norm2", + "P_bg167", + ), + **norm( + "model.diffusion_model.output_blocks.3.1.transformer_blocks.0.norm3", + "P_bg167", + ), + **conv( + "model.diffusion_model.output_blocks.3.1.proj_out", "P_bg167", "P_bg168" + ), + **easyblock( + "model.diffusion_model.output_blocks.4.0", "P_bg169", "P_bg170" + ), + **conv( + "model.diffusion_model.output_blocks.4.0.skip_connection", + "P_bg171", + "P_bg172", + ), + **norm("model.diffusion_model.output_blocks.4.1.norm", "P_bg173"), + **conv( + "model.diffusion_model.output_blocks.4.1.proj_in", "P_bg173", "P_bg174" + ), + **dense( + "model.diffusion_model.output_blocks.4.1.transformer_blocks.0.attn1.to_q", + "P_bg175", + "P_bg176", + bias=False, + ), + **dense( + "model.diffusion_model.output_blocks.4.1.transformer_blocks.0.attn1.to_k", + "P_bg175", + "P_bg176", + bias=False, + ), + **dense( + "model.diffusion_model.output_blocks.4.1.transformer_blocks.0.attn1.to_v", + "P_bg175", + "P_bg176", + bias=False, + ), + **dense( + "model.diffusion_model.output_blocks.4.1.transformer_blocks.0.attn1.to_out.0", + "P_bg175", + "P_bg176", + bias=True, + ), + **dense( + "model.diffusion_model.output_blocks.4.1.transformer_blocks.0.ff.net.0.proj", + "P_bg177", + "P_bg178", + bias=True, + ), + **dense( + "model.diffusion_model.output_blocks.4.1.transformer_blocks.0.ff.net.2", + "P_bg179", + "P_bg180", + bias=True, + ), + **dense( + "model.diffusion_model.output_blocks.4.1.transformer_blocks.0.attn2.to_q", + "P_bg181", + "P_bg182", + bias=False, + ), + **dense( + "model.diffusion_model.output_blocks.4.1.transformer_blocks.0.attn2.to_k", + "P_bg183", + "P_bg184", + bias=False, + ), + **dense( + "model.diffusion_model.output_blocks.4.1.transformer_blocks.0.attn2.to_v", + "P_bg183", + "P_bg184", + bias=False, + ), + **dense( + "model.diffusion_model.output_blocks.4.1.transformer_blocks.0.attn2.to_out.0", + "P_bg185", + "P_bg186", + bias=True, + ), + **norm( + "model.diffusion_model.output_blocks.4.1.transformer_blocks.0.norm1", + "P_bg186", + ), + **norm( + "model.diffusion_model.output_blocks.4.1.transformer_blocks.0.norm2", + "P_bg186", + ), + **norm( + "model.diffusion_model.output_blocks.4.1.transformer_blocks.0.norm3", + "P_bg186", + ), + **conv( + "model.diffusion_model.output_blocks.4.1.proj_out", "P_bg186", "P_bg187" + ), + **easyblock( + "model.diffusion_model.output_blocks.5.0", "P_bg188", "P_bg189" + ), + **conv( + "model.diffusion_model.output_blocks.5.0.skip_connection", + "P_bg190", + "P_bg191", + ), + **norm("model.diffusion_model.output_blocks.5.1.norm", "P_bg192"), + **conv( + "model.diffusion_model.output_blocks.5.1.proj_in", "P_bg192", "P_bg193" + ), + **dense( + "model.diffusion_model.output_blocks.5.1.transformer_blocks.0.attn1.to_q", + "P_bg194", + "P_bg195", + bias=False, + ), + **dense( + "model.diffusion_model.output_blocks.5.1.transformer_blocks.0.attn1.to_k", + "P_bg194", + "P_bg195", + bias=False, + ), + **dense( + "model.diffusion_model.output_blocks.5.1.transformer_blocks.0.attn1.to_v", + "P_bg194", + "P_bg195", + bias=False, + ), + **dense( + "model.diffusion_model.output_blocks.5.1.transformer_blocks.0.attn1.to_out.0", + "P_bg194", + "P_bg195", + bias=True, + ), + **dense( + "model.diffusion_model.output_blocks.5.1.transformer_blocks.0.ff.net.0.proj", + "P_bg196", + "P_bg197", + bias=True, + ), + **dense( + "model.diffusion_model.output_blocks.5.1.transformer_blocks.0.ff.net.2", + "P_bg198", + "P_bg199", + bias=True, + ), + **dense( + "model.diffusion_model.output_blocks.5.1.transformer_blocks.0.attn2.to_q", + "P_bg200", + "P_bg201", + bias=False, + ), + **dense( + "model.diffusion_model.output_blocks.5.1.transformer_blocks.0.attn2.to_k", + "P_bg202", + "P_bg203", + bias=False, + ), + **dense( + "model.diffusion_model.output_blocks.5.1.transformer_blocks.0.attn2.to_v", + "P_bg202", + "P_bg203", + bias=False, + ), + **dense( + "model.diffusion_model.output_blocks.5.1.transformer_blocks.0.attn2.to_out.0", + "P_bg204", + "P_bg205", + bias=True, + ), + **norm( + "model.diffusion_model.output_blocks.5.1.transformer_blocks.0.norm1", + "P_bg205", + ), + **norm( + "model.diffusion_model.output_blocks.5.1.transformer_blocks.0.norm2", + "P_bg205", + ), + **norm( + "model.diffusion_model.output_blocks.5.1.transformer_blocks.0.norm3", + "P_bg205", + ), + **conv( + "model.diffusion_model.output_blocks.5.1.proj_out", "P_bg205", "P_bg206" + ), + **conv( + "model.diffusion_model.output_blocks.5.2.conv", "P_bg206", "P_bg207" + ), + **easyblock( + "model.diffusion_model.output_blocks.6.0", "P_bg208", "P_bg209" + ), + **conv( + "model.diffusion_model.output_blocks.6.0.skip_connection", + "P_bg210", + "P_bg211", + ), + **norm("model.diffusion_model.output_blocks.6.1.norm", "P_bg212"), + **conv( + "model.diffusion_model.output_blocks.6.1.proj_in", "P_bg212", "P_bg213" + ), + **dense( + "model.diffusion_model.output_blocks.6.1.transformer_blocks.0.attn1.to_q", + "P_bg214", + "P_bg215", + bias=False, + ), + **dense( + "model.diffusion_model.output_blocks.6.1.transformer_blocks.0.attn1.to_k", + "P_bg214", + "P_bg215", + bias=False, + ), + **dense( + "model.diffusion_model.output_blocks.6.1.transformer_blocks.0.attn1.to_v", + "P_bg214", + "P_bg215", + bias=False, + ), + **dense( + "model.diffusion_model.output_blocks.6.1.transformer_blocks.0.attn1.to_out.0", + "P_bg214", + "P_bg215", + bias=True, + ), + **dense( + "model.diffusion_model.output_blocks.6.1.transformer_blocks.0.ff.net.0.proj", + "P_bg216", + "P_bg217", + bias=True, + ), + **dense( + "model.diffusion_model.output_blocks.6.1.transformer_blocks.0.ff.net.2", + "P_bg218", + "P_bg219", + bias=True, + ), + **dense( + "model.diffusion_model.output_blocks.6.1.transformer_blocks.0.attn2.to_q", + "P_bg220", + "P_bg221", + bias=False, + ), + **dense( + "model.diffusion_model.output_blocks.6.1.transformer_blocks.0.attn2.to_k", + "P_bg222", + "P_bg223", + bias=False, + ), + **dense( + "model.diffusion_model.output_blocks.6.1.transformer_blocks.0.attn2.to_v", + "P_bg222", + "P_bg223", + bias=False, + ), + **dense( + "model.diffusion_model.output_blocks.6.1.transformer_blocks.0.attn2.to_out.0", + "P_bg224", + "P_bg225", + bias=True, + ), + **norm( + "model.diffusion_model.output_blocks.6.1.transformer_blocks.0.norm1", + "P_bg225", + ), + **norm( + "model.diffusion_model.output_blocks.6.1.transformer_blocks.0.norm2", + "P_bg225", + ), + **norm( + "model.diffusion_model.output_blocks.6.1.transformer_blocks.0.norm3", + "P_bg225", + ), + **conv( + "model.diffusion_model.output_blocks.6.1.proj_out", "P_bg225", "P_bg226" + ), + **easyblock( + "model.diffusion_model.output_blocks.7.0", "P_bg227", "P_bg228" + ), + **conv( + "model.diffusion_model.output_blocks.7.0.skip_connection", + "P_bg229", + "P_bg230", + ), + **norm("model.diffusion_model.output_blocks.7.1.norm", "P_bg231"), + **conv( + "model.diffusion_model.output_blocks.7.1.proj_in", "P_bg231", "P_bg232" + ), + **dense( + "model.diffusion_model.output_blocks.7.1.transformer_blocks.0.attn1.to_q", + "P_bg233", + "P_bg234", + bias=False, + ), + **dense( + "model.diffusion_model.output_blocks.7.1.transformer_blocks.0.attn1.to_k", + "P_bg233", + "P_bg234", + bias=False, + ), + **dense( + "model.diffusion_model.output_blocks.7.1.transformer_blocks.0.attn1.to_v", + "P_bg233", + "P_bg234", + bias=False, + ), + **dense( + "model.diffusion_model.output_blocks.7.1.transformer_blocks.0.attn1.to_out.0", + "P_bg233", + "P_bg234", + bias=True, + ), + **dense( + "model.diffusion_model.output_blocks.7.1.transformer_blocks.0.ff.net.0.proj", + "P_bg235", + "P_bg236", + bias=True, + ), + **dense( + "model.diffusion_model.output_blocks.7.1.transformer_blocks.0.ff.net.2", + "P_bg237", + "P_bg238", + bias=True, + ), + **dense( + "model.diffusion_model.output_blocks.7.1.transformer_blocks.0.attn2.to_q", + "P_bg239", + "P_bg240", + bias=False, + ), + **dense( + "model.diffusion_model.output_blocks.7.1.transformer_blocks.0.attn2.to_k", + "P_bg241", + "P_bg242", + bias=False, + ), + **dense( + "model.diffusion_model.output_blocks.7.1.transformer_blocks.0.attn2.to_v", + "P_bg241", + "P_bg242", + bias=False, + ), + **dense( + "model.diffusion_model.output_blocks.7.1.transformer_blocks.0.attn2.to_out.0", + "P_bg243", + "P_bg244", + bias=True, + ), + **norm( + "model.diffusion_model.output_blocks.7.1.transformer_blocks.0.norm1", + "P_bg244", + ), + **norm( + "model.diffusion_model.output_blocks.7.1.transformer_blocks.0.norm2", + "P_bg244", + ), + **norm( + "model.diffusion_model.output_blocks.7.1.transformer_blocks.0.norm3", + "P_bg244", + ), + **conv( + "model.diffusion_model.output_blocks.7.1.proj_out", "P_bg244", "P_bg245" + ), + **easyblock( + "model.diffusion_model.output_blocks.8.0", "P_bg246", "P_bg247" + ), + **conv( + "model.diffusion_model.output_blocks.8.0.skip_connection", + "P_bg248", + "P_bg249", + ), + **norm("model.diffusion_model.output_blocks.8.1.norm", "P_bg250"), + **conv( + "model.diffusion_model.output_blocks.8.1.proj_in", "P_bg250", "P_bg251" + ), + **dense( + "model.diffusion_model.output_blocks.8.1.transformer_blocks.0.attn1.to_q", + "P_bg252", + "P_bg253", + bias=False, + ), + **dense( + "model.diffusion_model.output_blocks.8.1.transformer_blocks.0.attn1.to_k", + "P_bg252", + "P_bg253", + bias=False, + ), + **dense( + "model.diffusion_model.output_blocks.8.1.transformer_blocks.0.attn1.to_v", + "P_bg252", + "P_bg253", + bias=False, + ), + **dense( + "model.diffusion_model.output_blocks.8.1.transformer_blocks.0.attn1.to_out.0", + "P_bg252", + "P_bg253", + bias=True, + ), + **dense( + "model.diffusion_model.output_blocks.8.1.transformer_blocks.0.ff.net.0.proj", + "P_bg254", + "P_bg255", + bias=True, + ), + **dense( + "model.diffusion_model.output_blocks.8.1.transformer_blocks.0.ff.net.2", + "P_bg256", + "P_bg257", + bias=True, + ), + **dense( + "model.diffusion_model.output_blocks.8.1.transformer_blocks.0.attn2.to_q", + "P_bg258", + "P_bg259", + bias=False, + ), + **dense( + "model.diffusion_model.output_blocks.8.1.transformer_blocks.0.attn2.to_k", + "P_bg260", + "P_bg261", + bias=False, + ), + **dense( + "model.diffusion_model.output_blocks.8.1.transformer_blocks.0.attn2.to_v", + "P_bg260", + "P_bg261", + bias=False, + ), + **dense( + "model.diffusion_model.output_blocks.8.1.transformer_blocks.0.attn2.to_out.0", + "P_bg262", + "P_bg263", + bias=True, + ), + **norm( + "model.diffusion_model.output_blocks.8.1.transformer_blocks.0.norm1", + "P_bg263", + ), + **norm( + "model.diffusion_model.output_blocks.8.1.transformer_blocks.0.norm2", + "P_bg263", + ), + **norm( + "model.diffusion_model.output_blocks.8.1.transformer_blocks.0.norm3", + "P_bg263", + ), + **conv( + "model.diffusion_model.output_blocks.8.1.proj_out", "P_bg263", "P_bg264" + ), + **conv( + "model.diffusion_model.output_blocks.8.2.conv", "P_bg265", "P_bg266" + ), + **easyblock( + "model.diffusion_model.output_blocks.9.0", "P_bg267", "P_bg268" + ), + **conv( + "model.diffusion_model.output_blocks.9.0.skip_connection", + "P_bg269", + "P_bg270", + ), + **norm("model.diffusion_model.output_blocks.9.1.norm", "P_bg271"), + **conv( + "model.diffusion_model.output_blocks.9.1.proj_in", "P_bg271", "P_bg272" + ), + **dense( + "model.diffusion_model.output_blocks.9.1.transformer_blocks.0.attn1.to_q", + "P_bg273", + "P_bg274", + bias=False, + ), + **dense( + "model.diffusion_model.output_blocks.9.1.transformer_blocks.0.attn1.to_k", + "P_bg273", + "P_bg274", + bias=False, + ), + **dense( + "model.diffusion_model.output_blocks.9.1.transformer_blocks.0.attn1.to_v", + "P_bg273", + "P_bg274", + bias=False, + ), + **dense( + "model.diffusion_model.output_blocks.9.1.transformer_blocks.0.attn1.to_out.0", + "P_bg273", + "P_bg274", + bias=True, + ), + **dense( + "model.diffusion_model.output_blocks.9.1.transformer_blocks.0.ff.net.0.proj", + "P_bg275", + "P_bg276", + bias=True, + ), + **dense( + "model.diffusion_model.output_blocks.9.1.transformer_blocks.0.ff.net.2", + "P_bg277", + "P_bg278", + bias=True, + ), + **dense( + "model.diffusion_model.output_blocks.9.1.transformer_blocks.0.attn2.to_q", + "P_bg279", + "P_bg280", + bias=False, + ), + **dense( + "model.diffusion_model.output_blocks.9.1.transformer_blocks.0.attn2.to_k", + "P_bg281", + "P_bg282", + bias=False, + ), + **dense( + "model.diffusion_model.output_blocks.9.1.transformer_blocks.0.attn2.to_v", + "P_bg281", + "P_bg282", + bias=False, + ), + **dense( + "model.diffusion_model.output_blocks.9.1.transformer_blocks.0.attn2.to_out.0", + "P_bg283", + "P_bg284", + bias=True, + ), + **norm( + "model.diffusion_model.output_blocks.9.1.transformer_blocks.0.norm1", + "P_bg284", + ), + **norm( + "model.diffusion_model.output_blocks.9.1.transformer_blocks.0.norm2", + "P_bg284", + ), + **norm( + "model.diffusion_model.output_blocks.9.1.transformer_blocks.0.norm3", + "P_bg284", + ), + **conv( + "model.diffusion_model.output_blocks.9.1.proj_out", "P_bg284", "P_bg285" + ), + **easyblock( + "model.diffusion_model.output_blocks.10.0", "P_bg286", "P_bg287" + ), + **conv( + "model.diffusion_model.output_blocks.10.0.skip_connection", + "P_bg288", + "P_bg289", + ), + **norm("model.diffusion_model.output_blocks.10.1.norm", "P_bg290"), + **conv( + "model.diffusion_model.output_blocks.10.1.proj_in", "P_bg290", "P_bg291" + ), + **dense( + "model.diffusion_model.output_blocks.10.1.transformer_blocks.0.attn1.to_q", + "P_bg292", + "P_bg293", + bias=False, + ), + **dense( + "model.diffusion_model.output_blocks.10.1.transformer_blocks.0.attn1.to_k", + "P_bg292", + "P_bg293", + bias=False, + ), + **dense( + "model.diffusion_model.output_blocks.10.1.transformer_blocks.0.attn1.to_v", + "P_bg292", + "P_bg293", + bias=False, + ), + **dense( + "model.diffusion_model.output_blocks.10.1.transformer_blocks.0.attn1.to_out.0", + "P_bg292", + "P_bg293", + bias=True, + ), + **dense( + "model.diffusion_model.output_blocks.10.1.transformer_blocks.0.ff.net.0.proj", + "P_b294", + "P_bg295", + bias=True, + ), + **dense( + "model.diffusion_model.output_blocks.10.1.transformer_blocks.0.ff.net.2", + "P_bg296", + "P_bg297", + bias=True, + ), + **dense( + "model.diffusion_model.output_blocks.10.1.transformer_blocks.0.attn2.to_q", + "P_bg298", + "P_bg299", + bias=False, + ), + **dense( + "model.diffusion_model.output_blocks.10.1.transformer_blocks.0.attn2.to_k", + "P_bg300", + "P_bg301", + bias=False, + ), + **dense( + "model.diffusion_model.output_blocks.10.1.transformer_blocks.0.attn2.to_v", + "P_bg300", + "P_bg301", + bias=False, + ), + **dense( + "model.diffusion_model.output_blocks.10.1.transformer_blocks.0.attn2.to_out.0", + "P_bg302", + "P_bg303", + bias=True, + ), + **norm( + "model.diffusion_model.output_blocks.10.1.transformer_blocks.0.norm1", + "P_bg303", + ), + **norm( + "model.diffusion_model.output_blocks.10.1.transformer_blocks.0.norm2", + "P_bg303", + ), + **norm( + "model.diffusion_model.output_blocks.10.1.transformer_blocks.0.norm3", + "P_bg303", + ), + **conv( + "model.diffusion_model.output_blocks.10.1.proj_out", + "P_bg303", + "P_bg304", + ), + **easyblock( + "model.diffusion_model.output_blocks.11.0", "P_bg305", "P_bg306" + ), + **conv( + "model.diffusion_model.output_blocks.11.0.skip_connection", + "P_bg307", + "P_bg308", + ), + **norm("model.diffusion_model.output_blocks.11.1.norm", "P_bg309"), + **conv( + "model.diffusion_model.output_blocks.11.1.proj_in", "P_bg309", "P_bg310" + ), + **dense( + "model.diffusion_model.output_blocks.11.1.transformer_blocks.0.attn1.to_q", + "P_bg311", + "P_bg312", + bias=False, + ), + **dense( + "model.diffusion_model.output_blocks.11.1.transformer_blocks.0.attn1.to_k", + "P_bg311", + "P_bg312", + bias=False, + ), + **dense( + "model.diffusion_model.output_blocks.11.1.transformer_blocks.0.attn1.to_v", + "P_bg311", + "P_bg312", + bias=False, + ), + **dense( + "model.diffusion_model.output_blocks.11.1.transformer_blocks.0.attn1.to_out.0", + "P_bg311", + "P_bg312", + bias=True, + ), + **dense( + "model.diffusion_model.output_blocks.11.1.transformer_blocks.0.ff.net.0.proj", + "P_bg313", + "P_bg314", + bias=True, + ), + **dense( + "model.diffusion_model.output_blocks.11.1.transformer_blocks.0.ff.net.2", + "P_bg315", + "P_bg316", + bias=True, + ), + **dense( + "model.diffusion_model.output_blocks.11.1.transformer_blocks.0.attn2.to_q", + "P_bg317", + "P_bg318", + bias=False, + ), + **dense( + "model.diffusion_model.output_blocks.11.1.transformer_blocks.0.attn2.to_k", + "P_bg319", + "P_bg320", + bias=False, + ), + **dense( + "model.diffusion_model.output_blocks.11.1.transformer_blocks.0.attn2.to_v", + "P_bg319", + "P_bg320", + bias=False, + ), + **dense( + "model.diffusion_model.output_blocks.11.1.transformer_blocks.0.attn2.to_out.0", + "P_bg321", + "P_bg322", + bias=True, + ), + **norm( + "model.diffusion_model.output_blocks.11.1.transformer_blocks.0.norm1", + "P_bg322", + ), + **norm( + "model.diffusion_model.output_blocks.11.1.transformer_blocks.0.norm2", + "P_bg322", + ), + **norm( + "model.diffusion_model.output_blocks.11.1.transformer_blocks.0.norm3", + "P_bg322", + ), + **conv( + "model.diffusion_model.output_blocks.11.1.proj_out", + "P_bg322", + "P_bg323", + ), + **norm("model.diffusion_model.out.0", "P_bg324"), + **conv("model.diffusion_model.out.2", "P_bg325", "P_bg326"), + # Text Encoder + # encoder down + **conv("first_stage_model.encoder.conv_in", "P_bg327", "P_bg328"), + **easyblock2("first_stage_model.encoder.down.0.block.0", "P_bg328"), + **easyblock2("first_stage_model.encoder.down.0.block.1", "P_bg328"), + **conv( + "first_stage_model.encoder.down.0.downsample.conv", "P_bg328", "P_bg329" + ), + **shortcutblock( + "first_stage_model.encoder.down.1.block.0", "P_bg330", "P_bg331" + ), + **easyblock2("first_stage_model.encoder.down.1.block.1", "P_bg331"), + **conv( + "first_stage_model.encoder.down.1.downsample.conv", "P_bg331", "P_bg332" + ), + **shortcutblock( + "first_stage_model.encoder.down.2.block.0", "P_bg332", "P_bg333" + ), + **easyblock2("first_stage_model.encoder.down.2.block.1", "P_bg333"), + **conv( + "first_stage_model.encoder.down.2.downsample.conv", "P_bg333", "P_bg334" + ), + **easyblock2("first_stage_model.encoder.down.3.block.0", "P_bg334"), + **easyblock2("first_stage_model.encoder.down.3.block.1", "P_bg334"), + # encoder mid-block + **easyblock2("first_stage_model.encoder.mid.block_1", "P_bg334"), + **norm("first_stage_model.encoder.mid.attn_1.norm", "P_bg334"), + **conv("first_stage_model.encoder.mid.attn_1.q", "P_bg334", "P_bg335"), + **conv("first_stage_model.encoder.mid.attn_1.k", "P_bg334", "P_bg335"), + **conv("first_stage_model.encoder.mid.attn_1.v", "P_bg334", "P_bg335"), + **conv( + "first_stage_model.encoder.mid.attn_1.proj_out", "P_bg335", "P_bg336" + ), + **easyblock2("first_stage_model.encoder.mid.block_2", "P_bg336"), + **norm("first_stage_model.encoder.norm_out", "P_bg337"), + **conv("first_stage_model.encoder.conv_out", "P_bg338", "P_bg339"), + **conv("first_stage_model.decoder.conv_in", "P_bg340", "P_bg341"), + # decoder mid-block + **easyblock2("first_stage_model.decoder.mid.block_1", "P_bg342"), + **norm("first_stage_model.decoder.mid.attn_1.norm", "P_bg342"), + **conv("first_stage_model.decoder.mid.attn_1.q", "P_bg342", "P_bg343"), + **conv("first_stage_model.decoder.mid.attn_1.k", "P_bg342", "P_bg343"), + **conv("first_stage_model.decoder.mid.attn_1.v", "P_bg342", "P_bg343"), + **conv( + "first_stage_model.decoder.mid.attn_1.proj_out", "P_bg343", "P_bg344" + ), + **easyblock2("first_stage_model.decoder.mid.block_2", "P_bg345"), + # decoder up + **shortcutblock( + "first_stage_model.decoder.up.0.block.0", "P_bg346", "P_bg347" + ), + **easyblock2("first_stage_model.decoder.up.0.block.1", "P_bg348"), + **easyblock2("first_stage_model.decoder.up.0.block.2", "P_bg349"), + **shortcutblock( + "first_stage_model.decoder.up.1.block.0", "P_bg350", "P_bg351" + ), + **easyblock2("first_stage_model.decoder.up.1.block.1", "P_bg352"), + **easyblock2("first_stage_model.decoder.up.1.block.2", "P_bg353"), + **conv( + "first_stage_model.decoder.up.1.upsample.conv", "P_bg353", "P_bg354" + ), + **easyblock2("first_stage_model.decoder.up.2.block.0", "P_bg355"), + **easyblock2("first_stage_model.decoder.up.2.block.1", "P_bg355"), + **easyblock2("first_stage_model.decoder.up.2.block.2", "P_bg355"), + **conv( + "first_stage_model.decoder.up.2.upsample.conv", "P_bg355", "P_bg356" + ), + **easyblock2("first_stage_model.decoder.up.3.block.0", "P_bg356"), + **easyblock2("first_stage_model.decoder.up.3.block.1", "P_bg356"), + **easyblock2("first_stage_model.decoder.up.3.block.2", "P_bg356"), + **conv( + "first_stage_model.decoder.up.3.upsample.conv", "P_bg356", "P_bg357" + ), + **norm("first_stage_model.decoder.norm_out", "P_bg358"), + **conv("first_stage_model.decoder.conv_out", "P_bg359", "P_bg360"), + **conv("first_stage_model.quant_conv", "P_bg361", "P_bg362"), + **conv("first_stage_model.post_quant_conv", "P_bg363", "P_bg364"), + **skip( + "cond_stage_model.transformer.text_model.embeddings.position_ids", + None, + None, + ), + **dense( + "cond_stage_model.transformer.text_model.embeddings.token_embedding", + "P_bg365", + "P_bg366", + bias=False, + ), + **dense( + "cond_stage_model.transformer.text_model.embeddings.token_embedding", + None, + None, + ), + **dense( + "cond_stage_model.transformer.text_model.embeddings.position_embedding", + "P_bg367", + "P_bg368", + bias=False, + ), + # cond stage text encoder + **dense( + "cond_stage_model.transformer.text_model.encoder.layers.0.self_attn.k_proj", + "P_bg369", + "P_bg370", + bias=True, + ), + **dense( + "cond_stage_model.transformer.text_model.encoder.layers.0.self_attn.v_proj", + "P_bg369", + "P_bg370", + bias=True, + ), + **dense( + "cond_stage_model.transformer.text_model.encoder.layers.0.self_attn.q_proj", + "P_bg369", + "P_bg370", + bias=True, + ), + **dense( + "cond_stage_model.transformer.text_model.encoder.layers.0.self_attn.out_proj", + "P_bg369", + "P_bg370", + bias=True, + ), + **norm( + "cond_stage_model.transformer.text_model.encoder.layers.0.layer_norm1", + "P_bg370", + ), + **dense( + "cond_stage_model.transformer.text_model.encoder.layers.0.mlp.fc1", + "P_bg370", + "P_bg371", + bias=True, + ), + **dense( + "cond_stage_model.transformer.text_model.encoder.layers.0.mlp.fc2", + "P_bg371", + "P_bg372", + bias=True, + ), + **norm( + "cond_stage_model.transformer.text_model.encoder.layers.0.layer_norm2", + "P_bg372", + ), + **dense( + "cond_stage_model.transformer.text_model.encoder.layers.1.self_attn.k_proj", + "P_bg372", + "P_bg373", + bias=True, + ), + **dense( + "cond_stage_model.transformer.text_model.encoder.layers.1.self_attn.v_proj", + "P_bg372", + "P_bg373", + bias=True, + ), + **dense( + "cond_stage_model.transformer.text_model.encoder.layers.1.self_attn.q_proj", + "P_bg372", + "P_bg373", + bias=True, + ), + **dense( + "cond_stage_model.transformer.text_model.encoder.layers.1.self_attn.out_proj", + "P_bg372", + "P_bg373", + bias=True, + ), + **norm( + "cond_stage_model.transformer.text_model.encoder.layers.1.layer_norm1", + "P_bg373", + ), + **dense( + "cond_stage_model.transformer.text_model.encoder.layers.1.mlp.fc1", + "P_bg373", + "P_bg374", + bias=True, + ), + **dense( + "cond_stage_model.transformer.text_model.encoder.layers.1.mlp.fc2", + "P_bg374", + "P_bg375", + bias=True, + ), + **norm( + "cond_stage_model.transformer.text_model.encoder.layers.1.layer_norm2", + "P_bg375", + ), + **dense( + "cond_stage_model.transformer.text_model.encoder.layers.2.self_attn.k_proj", + "P_bg375", + "P_bg376", + bias=True, + ), + **dense( + "cond_stage_model.transformer.text_model.encoder.layers.2.self_attn.v_proj", + "P_bg375", + "P_bg376", + bias=True, + ), + **dense( + "cond_stage_model.transformer.text_model.encoder.layers.2.self_attn.q_proj", + "P_bg375", + "P_bg376", + bias=True, + ), + **dense( + "cond_stage_model.transformer.text_model.encoder.layers.2.self_attn.out_proj", + "P_bg375", + "P_bg376", + bias=True, + ), + **norm( + "cond_stage_model.transformer.text_model.encoder.layers.2.layer_norm1", + "P_bg376", + ), + **dense( + "cond_stage_model.transformer.text_model.encoder.layers.2.mlp.fc1", + "P_bg376", + "P_bg377", + bias=True, + ), + **dense( + "cond_stage_model.transformer.text_model.encoder.layers.2.mlp.fc2", + "P_bg377", + "P_bg378", + bias=True, + ), + **norm( + "cond_stage_model.transformer.text_model.encoder.layers.2.layer_norm2", + "P_bg378", + ), + **dense( + "cond_stage_model.transformer.text_model.encoder.layers.3.self_attn.k_proj", + "P_bg378", + "P_bg379", + bias=True, + ), + **dense( + "cond_stage_model.transformer.text_model.encoder.layers.3.self_attn.v_proj", + "P_bg378", + "P_bg379", + bias=True, + ), + **dense( + "cond_stage_model.transformer.text_model.encoder.layers.3.self_attn.q_proj", + "P_bg378", + "P_bg379", + bias=True, + ), + **dense( + "cond_stage_model.transformer.text_model.encoder.layers.3.self_attn.out_proj", + "P_bg378", + "P_bg379", + bias=True, + ), + **norm( + "cond_stage_model.transformer.text_model.encoder.layers.3.layer_norm1", + "P_bg379", + ), + **dense( + "cond_stage_model.transformer.text_model.encoder.layers.3.mlp.fc1", + "P_bg379", + "P_bg380", + bias=True, + ), + **dense( + "cond_stage_model.transformer.text_model.encoder.layers.3.mlp.fc2", + "P_bg380", + "P_b381", + bias=True, + ), + **norm( + "cond_stage_model.transformer.text_model.encoder.layers.3.layer_norm2", + "P_bg381", + ), + **dense( + "cond_stage_model.transformer.text_model.encoder.layers.4.self_attn.k_proj", + "P_bg381", + "P_bg382", + bias=True, + ), + **dense( + "cond_stage_model.transformer.text_model.encoder.layers.4.self_attn.v_proj", + "P_bg381", + "P_bg382", + bias=True, + ), + **dense( + "cond_stage_model.transformer.text_model.encoder.layers.4.self_attn.q_proj", + "P_bg381", + "P_bg382", + bias=True, + ), + **dense( + "cond_stage_model.transformer.text_model.encoder.layers.4.self_attn.out_proj", + "P_bg381", + "P_bg382", + bias=True, + ), + **norm( + "cond_stage_model.transformer.text_model.encoder.layers.4.layer_norm1", + "P_bg382", + ), + **dense( + "cond_stage_model.transformer.text_model.encoder.layers.4.mlp.fc1", + "P_bg382", + "P_bg383", + bias=True, + ), + **dense( + "cond_stage_model.transformer.text_model.encoder.layers.4.mlp.fc2", + "P_bg383", + "P_bg384", + bias=True, + ), + **norm( + "cond_stage_model.transformer.text_model.encoder.layers.4.layer_norm2", + "P_bg384", + ), + **dense( + "cond_stage_model.transformer.text_model.encoder.layers.5.self_attn.k_proj", + "P_bg384", + "P_bg385", + bias=True, + ), + **dense( + "cond_stage_model.transformer.text_model.encoder.layers.5.self_attn.v_proj", + "P_bg384", + "P_bg385", + bias=True, + ), + **dense( + "cond_stage_model.transformer.text_model.encoder.layers.5.self_attn.q_proj", + "P_bg384", + "P_bg385", + bias=True, + ), + **dense( + "cond_stage_model.transformer.text_model.encoder.layers.5.self_attn.out_proj", + "P_bg384", + "P_bg385", + bias=True, + ), + **norm( + "cond_stage_model.transformer.text_model.encoder.layers.5.layer_norm1", + "P_bg385", + ), + **dense( + "cond_stage_model.transformer.text_model.encoder.layers.5.mlp.fc1", + "P_bg385", + "P_bg386", + bias=True, + ), + **dense( + "cond_stage_model.transformer.text_model.encoder.layers.5.mlp.fc2", + "P_bg386", + "P_bg387", + bias=True, + ), + **norm( + "cond_stage_model.transformer.text_model.encoder.layers.5.layer_norm2", + "P_bg387", + ), + **dense( + "cond_stage_model.transformer.text_model.encoder.layers.6.self_attn.k_proj", + "P_bg387", + "P_bg388", + bias=True, + ), + **dense( + "cond_stage_model.transformer.text_model.encoder.layers.6.self_attn.v_proj", + "P_bg387", + "P_bg388", + bias=True, + ), + **dense( + "cond_stage_model.transformer.text_model.encoder.layers.6.self_attn.q_proj", + "P_bg387", + "P_bg388", + bias=True, + ), + **dense( + "cond_stage_model.transformer.text_model.encoder.layers.6.self_attn.out_proj", + "P_bg387", + "P_bg388", + bias=True, + ), + **norm( + "cond_stage_model.transformer.text_model.encoder.layers.6.layer_norm1", + "P_bg389", + ), + **dense( + "cond_stage_model.transformer.text_model.encoder.layers.6.mlp.fc1", + "P_bg389", + "P_bg390", + bias=True, + ), + **dense( + "cond_stage_model.transformer.text_model.encoder.layers.6.mlp.fc2", + "P_bg390", + "P_bg391", + bias=True, + ), + **norm( + "cond_stage_model.transformer.text_model.encoder.layers.6.layer_norm2", + "P_bg391", + ), + **dense( + "cond_stage_model.transformer.text_model.encoder.layers.7.self_attn.k_proj", + "P_bg391", + "P_bg392", + bias=True, + ), + **dense( + "cond_stage_model.transformer.text_model.encoder.layers.7.self_attn.v_proj", + "P_bg391", + "P_bg392", + bias=True, + ), + **dense( + "cond_stage_model.transformer.text_model.encoder.layers.7.self_attn.q_proj", + "P_bg391", + "P_bg392", + bias=True, + ), + **dense( + "cond_stage_model.transformer.text_model.encoder.layers.7.self_attn.out_proj", + "P_bg391", + "P_bg392", + bias=True, + ), + **norm( + "cond_stage_model.transformer.text_model.encoder.layers.7.layer_norm1", + "P_bg392", + ), + **dense( + "cond_stage_model.transformer.text_model.encoder.layers.7.mlp.fc1", + "P_bg392", + "P_bg393", + bias=True, + ), + **dense( + "cond_stage_model.transformer.text_model.encoder.layers.7.mlp.fc2", + "P_bg393", + "P_bg394", + bias=True, + ), + **norm( + "cond_stage_model.transformer.text_model.encoder.layers.7.layer_norm2", + "P_bg394", + ), + **dense( + "cond_stage_model.transformer.text_model.encoder.layers.8.self_attn.k_proj", + "P_bg394", + "P_bg395", + bias=True, + ), + **dense( + "cond_stage_model.transformer.text_model.encoder.layers.8.self_attn.v_proj", + "P_bg394", + "P_bg395", + bias=True, + ), + **dense( + "cond_stage_model.transformer.text_model.encoder.layers.8.self_attn.q_proj", + "P_bg394", + "P_bg395", + bias=True, + ), + **dense( + "cond_stage_model.transformer.text_model.encoder.layers.8.self_attn.out_proj", + "P_bg394", + "P_bg395", + bias=True, + ), + **norm( + "cond_stage_model.transformer.text_model.encoder.layers.8.layer_norm1", + "P_bg395", + ), + **dense( + "cond_stage_model.transformer.text_model.encoder.layers.8.mlp.fc1", + "P_bg395", + "P_bg396", + bias=True, + ), + **dense( + "cond_stage_model.transformer.text_model.encoder.layers.8.mlp.fc2", + "P_bg396", + "P_bg397", + bias=True, + ), + **norm( + "cond_stage_model.transformer.text_model.encoder.layers.8.layer_norm2", + "P_bg397", + ), + **dense( + "cond_stage_model.transformer.text_model.encoder.layers.9.self_attn.k_proj", + "P_bg397", + "P_bg398", + bias=True, + ), + **dense( + "cond_stage_model.transformer.text_model.encoder.layers.9.self_attn.v_proj", + "P_bg397", + "P_bg398", + bias=True, + ), + **dense( + "cond_stage_model.transformer.text_model.encoder.layers.9.self_attn.q_proj", + "P_bg397", + "P_bg398", + bias=True, + ), + **dense( + "cond_stage_model.transformer.text_model.encoder.layers.9.self_attn.out_proj", + "P_bg397", + "P_bg398", + bias=True, + ), + **norm( + "cond_stage_model.transformer.text_model.encoder.layers.9.layer_norm1", + "P_bg398", + ), + **dense( + "cond_stage_model.transformer.text_model.encoder.layers.9.mlp.fc1", + "P_bg398", + "P_bg399", + bias=True, + ), + **dense( + "cond_stage_model.transformer.text_model.encoder.layers.9.mlp.fc2", + "P_bg400", + "P_bg401", + bias=True, + ), + **norm( + "cond_stage_model.transformer.text_model.encoder.layers.9.layer_norm2", + "P_bg401", + ), + **dense( + "cond_stage_model.transformer.text_model.encoder.layers.10.self_attn.k_proj", + "P_bg401", + "P_bg402", + bias=True, + ), + **dense( + "cond_stage_model.transformer.text_model.encoder.layers.10.self_attn.v_proj", + "P_bg401", + "P_bg402", + bias=True, + ), + **dense( + "cond_stage_model.transformer.text_model.encoder.layers.10.self_attn.q_proj", + "P_bg401", + "P_bg402", + bias=True, + ), + **dense( + "cond_stage_model.transformer.text_model.encoder.layers.10.self_attn.out_proj", + "P_bg401", + "P_bg402", + bias=True, + ), + **norm( + "cond_stage_model.transformer.text_model.encoder.layers.10.layer_norm1", + "P_bg402", + ), + **dense( + "cond_stage_model.transformer.text_model.encoder.layers.10.mlp.fc1", + "P_bg402", + "P_bg403", + bias=True, + ), + **dense( + "cond_stage_model.transformer.text_model.encoder.layers.10.mlp.fc2", + "P_bg403", + "P_bg404", + bias=True, + ), + **norm( + "cond_stage_model.transformer.text_model.encoder.layers.10.layer_norm2", + "P_bg404", + ), + **dense( + "cond_stage_model.transformer.text_model.encoder.layers.11.self_attn.k_proj", + "P_bg404", + "P_bg405", + bias=True, + ), + **dense( + "cond_stage_model.transformer.text_model.encoder.layers.11.self_attn.v_proj", + "P_bg404", + "P_bg405", + bias=True, + ), + **dense( + "cond_stage_model.transformer.text_model.encoder.layers.11.self_attn.q_proj", + "P_bg404", + "P_bg405", + bias=True, + ), + **dense( + "cond_stage_model.transformer.text_model.encoder.layers.11.self_attn.out_proj", + "P_bg404", + "P_bg405", + bias=True, + ), + **norm( + "cond_stage_model.transformer.text_model.encoder.layers.11.layer_norm1", + "P_bg405", + ), + **dense( + "cond_stage_model.transformer.text_model.encoder.layers.11.mlp.fc1", + "P_bg405", + "P_bg406", + bias=True, + ), + **dense( + "cond_stage_model.transformer.text_model.encoder.layers.11.mlp.fc2", + "P_bg406", + "P_bg407", + bias=True, + ), + **norm( + "cond_stage_model.transformer.text_model.encoder.layers.11.layer_norm2", + "P_bg407", + ), + **norm( + "cond_stage_model.transformer.text_model.final_layer_norm", "P_bg407" + ), + } + ) + + +def get_permuted_param(ps: PermutationSpec, perm, k: str, params, except_axis=None): + """Get parameter `k` from `params`, with the permutations applied.""" + w = params[k] + for axis, p in enumerate(ps.axes_to_perm[k]): + # Skip the axis we're trying to permute. + if axis == except_axis: + continue + + # None indicates that there is no permutation relevant to that axis. + if p: + w = torch.index_select(w, axis, perm[p].int()) + + return w + + +def apply_permutation(ps: PermutationSpec, perm, params): + """Apply a `perm` to `params`.""" + return {k: get_permuted_param(ps, perm, k, params) for k in params.keys()} + + +def update_model_a(ps: PermutationSpec, perm, model_a, new_alpha): + for k in model_a: + try: + perm_params = get_permuted_param( + ps, perm, k, model_a + ) + model_a[k] = model_a[k] * (1 - new_alpha) + new_alpha * perm_params + except RuntimeError: # dealing with pix2pix and inpainting models + continue + return model_a + + +def inner_matching( + n, + ps, + p, + params_a, + params_b, + usefp16, + progress, + number, + linear_sum, + perm, + device, +): + A = torch.zeros((n, n), dtype=torch.float16) if usefp16 else torch.zeros((n, n)) + A = A.to(device) + + for wk, axis in ps.perm_to_axes[p]: + w_a = params_a[wk] + w_b = get_permuted_param(ps, perm, wk, params_b, except_axis=axis) + w_a = torch.moveaxis(w_a, axis, 0).reshape((n, -1)).to(device) + w_b = torch.moveaxis(w_b, axis, 0).reshape((n, -1)).T.to(device) + + if usefp16: + w_a = w_a.half().to(device) + w_b = w_b.half().to(device) + + try: + A += torch.matmul(w_a, w_b) + except RuntimeError: + A += torch.matmul(torch.dequantize(w_a), torch.dequantize(w_b)) + + A = A.cpu() + ri, ci = linear_sum_assignment(A.detach().numpy(), maximize=True) + A = A.to(device) + + assert (torch.tensor(ri) == torch.arange(len(ri))).all() + + eye_tensor = torch.eye(n).to(device) + + oldL = torch.vdot( + torch.flatten(A).float(), torch.flatten(eye_tensor[perm[p].long()]) + ) + newL = torch.vdot(torch.flatten(A).float(), torch.flatten(eye_tensor[ci, :])) + + if usefp16: + oldL = oldL.half() + newL = newL.half() + + if newL - oldL != 0: + linear_sum += abs((newL - oldL).item()) + number += 1 + logging.info(f" permutation {p}: {newL - oldL}") + + progress = progress or newL > oldL + 1e-12 + + perm[p] = torch.Tensor(ci).to(device) + + return linear_sum, number, perm, progress + + +def weight_matching( + ps: PermutationSpec, + params_a, + params_b, + max_iter=1, + init_perm=None, + usefp16=False, + device="cpu", +): + perm_sizes = { + p: params_a[axes[0][0]].shape[axes[0][1]] + for p, axes in ps.perm_to_axes.items() + if axes[0][0] in params_a.keys() + } + perm = {} + perm = ( + {p: torch.arange(n).to(device) for p, n in perm_sizes.items()} + if init_perm is None + else init_perm + ) + + linear_sum = 0 + number = 0 + + special_layers = ["P_bg324", "P_bg358", "P_bg337"] + for _ in range(max_iter): + progress = False + shuffle(special_layers) + for p in special_layers: + n = perm_sizes[p] + + linear_sum, number, perm, progress = inner_matching( + n, + ps, + p, + params_a, + params_b, + usefp16, + progress, + number, + linear_sum, + perm, + device, + ) + if not progress: + break + + average = linear_sum / number if number > 0 else 0 + return perm, average diff --git a/modules/merging/utils.py b/modules/merging/utils.py new file mode 100644 index 000000000..4cee23db1 --- /dev/null +++ b/modules/merging/utils.py @@ -0,0 +1,115 @@ +import inspect +# import logging +import re +from modules.merging import merge_methods +from modules.merging.presets import BLOCK_WEIGHTS_PRESETS, SDXL_BLOCK_WEIGHTS_PRESETS + +BLOCK_WEIGHTS_PRESETS |= SDXL_BLOCK_WEIGHTS_PRESETS +MERGE_METHODS = dict(inspect.getmembers(merge_methods, inspect.isfunction)) +BETA_METHODS = [ + name + for name, fn in MERGE_METHODS.items() + if "beta" in inspect.getfullargspec(fn)[0] +] +TRIPLE_METHODS = [ + name + for name, fn in MERGE_METHODS.items() + if "c" in inspect.getfullargspec(fn)[0] +] + + +def interpolate(values, interp_lambda): + interpolated = [] + for i in range(len(values[0])): + interpolated.append((1 - interp_lambda) * values[0][i] + interp_lambda * values[1][i]) + return interpolated + + +class WeightClass: + def __init__(self, + model_a, + **kwargs, + ): + self.SDXL = True if "model.diffusion_model.middle_block.1.transformer_blocks.9.norm3.weight" in model_a.keys() else False + self.NUM_INPUT_BLOCKS = 12 if not self.SDXL else 9 + self.NUM_MID_BLOCK = 1 + self.NUM_OUTPUT_BLOCKS = 12 if not self.SDXL else 9 + self.NUM_TOTAL_BLOCKS = self.NUM_INPUT_BLOCKS + self.NUM_MID_BLOCK + self.NUM_OUTPUT_BLOCKS + self.iterations = kwargs.get("iterations", 1) + self.it = 0 + self.re_basin = kwargs.get("re_basin", False) + self.ratioDict = {} + for key, value in kwargs.items(): + if isinstance(value, list) or (key.lower() not in ["alpha", "beta"]): + self.ratioDict[key.lower()] = value + else: + self.ratioDict[key.lower()] = [value] + + for key, value in self.ratioDict.items(): + if key in ["alpha", "beta"]: + for i, v in enumerate(value): + if isinstance(v, str) and v.upper() in BLOCK_WEIGHTS_PRESETS.keys(): + value[i] = BLOCK_WEIGHTS_PRESETS[v.upper()] + else: + value[i] = [float(x) for x in v.split(",")] if isinstance(v, str) else v + if not isinstance(value[i], list): + value[i] = [value[i]] * (self.NUM_TOTAL_BLOCKS + 1) + if len(value) > 1 and isinstance(value[0], list): + self.ratioDict[key] = interpolate(value, self.ratioDict.get(key + "_lambda", 0)) + else: + self.ratioDict[key] = self.ratioDict[key][0] + + + def __call__(self, key, it=0): + current_bases = {} + if self.ratioDict.get("alpha", None): + current_bases["alpha"] = self.step_weights_and_bases(self.ratioDict["alpha"], it) + if self.ratioDict.get("beta", None): + current_bases["beta"] = self.step_weights_and_bases(self.ratioDict["beta"], it) + + weight_index = 0 + if "model" in key: + + if "model.diffusion_model." in key: + weight_index = -1 + + re_inp = re.compile(r"\.input_blocks\.(\d+)\.") # 12 + re_mid = re.compile(r"\.middle_block\.(\d+)\.") # 1 + re_out = re.compile(r"\.output_blocks\.(\d+)\.") # 12 + + if "time_embed" in key: + weight_index = 0 # before input blocks + elif ".out." in key: + weight_index = self.NUM_TOTAL_BLOCKS - 1 # after output blocks + elif m := re_inp.search(key): + weight_index = int(m.groups()[0]) + elif re_mid.search(key): + weight_index = self.NUM_INPUT_BLOCKS + elif m := re_out.search(key): + weight_index = self.NUM_INPUT_BLOCKS + self.NUM_MID_BLOCK + int(m.groups()[0]) + + if weight_index >= self.NUM_TOTAL_BLOCKS: + raise ValueError(f"illegal block index {key}") + + current_bases = {k: w[weight_index] for k, w in current_bases.items()} + if self.re_basin: + current_bases = self.step_weights_and_bases(current_bases,self.it) + return current_bases + + def step_weights_and_bases(self, + ratio, + it: int = 0, + ): + new_ratio = { + k: + 1 - (1 - (1 + it) * v / self.iterations) / (1 - it * v / self.iterations) + if it > 0 + else v / self.iterations + for k, v in ratio.items() + } + + return new_ratio + + def set_it(self, it): + self.it = it + return diff --git a/modules/ui_models.py b/modules/ui_models.py index abcb9bce1..87c1c2898 100644 --- a/modules/ui_models.py +++ b/modules/ui_models.py @@ -10,11 +10,9 @@ from modules.call_queue import wrap_gradio_gpu_call from modules.shared import opts, log, req import modules.errors import modules.hashes -from sd_meh import merge_methods -from sd_meh.utils import BETA_METHODS, TRIPLE_METHODS, interpolate -from sd_meh.presets import BLOCK_WEIGHTS_PRESETS - - +from modules.merging import merge_methods +from modules.merging.utils import BETA_METHODS, TRIPLE_METHODS, interpolate +from modules.merging.presets import BLOCK_WEIGHTS_PRESETS, SDXL_BLOCK_WEIGHTS_PRESETS search_metadata_civit = None @@ -37,14 +35,17 @@ def create_ui(): with gr.Tab(label="Convert"): with gr.Row(): model_name = gr.Dropdown(sd_models.checkpoint_tiles(), label="Original model") - create_refresh_button(model_name, sd_models.list_models, lambda: {"choices": sd_models.checkpoint_tiles()}, "refresh_checkpoint_Z") + create_refresh_button(model_name, sd_models.list_models, + lambda: {"choices": sd_models.checkpoint_tiles()}, "refresh_checkpoint_Z") with gr.Row(): custom_name = gr.Textbox(label="New model name") with gr.Row(): precision = gr.Radio(choices=["fp32", "fp16", "bf16"], value="fp16", label="Model precision") - m_type = gr.Radio(choices=["disabled", "no-ema", "ema-only"], value="disabled", label="Model pruning methods") + m_type = gr.Radio(choices=["disabled", "no-ema", "ema-only"], value="disabled", + label="Model pruning methods") with gr.Row(): - checkpoint_formats = gr.CheckboxGroup(choices=["ckpt", "safetensors"], value=["safetensors"], label="Model Format") + checkpoint_formats = gr.CheckboxGroup(choices=["ckpt", "safetensors"], value=["safetensors"], + label="Model Format") with gr.Row(): show_extra_options = gr.Checkbox(label="Show extra options", value=False) fix_clip = gr.Checkbox(label="Fix clip", value=False) @@ -81,24 +82,37 @@ def create_ui(): with FormRow(): def sd_model_choices(): return ['None'] + sd_models.checkpoint_tiles() + primary_model_name = gr.Dropdown(sd_model_choices(), label="Primary model", value="None") - create_refresh_button(primary_model_name, sd_models.list_models, lambda: {"choices": sd_model_choices()}, "refresh_checkpoint_A") - secondary_model_name = gr.Dropdown(sd_model_choices(), label="Secondary model", value="None") - create_refresh_button(secondary_model_name, sd_models.list_models, lambda: {"choices": sd_model_choices()}, "refresh_checkpoint_B") + create_refresh_button(primary_model_name, sd_models.list_models, + lambda: {"choices": sd_model_choices()}, "refresh_checkpoint_A") + secondary_model_name = gr.Dropdown(sd_model_choices(), label="Secondary model", + value="None") + create_refresh_button(secondary_model_name, sd_models.list_models, + lambda: {"choices": sd_model_choices()}, "refresh_checkpoint_B") tertiary_model_name = gr.Dropdown(sd_model_choices(), label="Tertiary model", value="None") - create_refresh_button(tertiary_model_name, sd_models.list_models, lambda: {"choices": sd_model_choices()}, "refresh_checkpoint_C") + create_refresh_button(tertiary_model_name, sd_models.list_models, + lambda: {"choices": sd_model_choices()}, "refresh_checkpoint_C") with FormRow(): - interp_method = gr.Radio(choices=["No interpolation", "Weighted sum", "Add difference"], value="Weighted sum", label="Interpolation Method") - interp_amount = gr.Slider(minimum=0.0, maximum=1.0, step=0.05, label='Interpolation ratio from Primary to Secondary', value=0.5) + interp_method = gr.Radio(choices=["No interpolation", "Weighted sum", "Add difference"], + value="Weighted sum", label="Interpolation Method") + interp_amount = gr.Slider(minimum=0.0, maximum=1.0, step=0.05, + label='Interpolation ratio from Primary to Secondary', value=0.5) with FormRow(): - checkpoint_format = gr.Radio(choices=["ckpt", "safetensors"], value="safetensors", label="Model format") + checkpoint_format = gr.Radio(choices=["ckpt", "safetensors"], value="safetensors", + label="Model format") with gr.Box(): - save_as_half = gr.Radio(choices=["fp16", "fp32"], value="fp16", label="Model precision", type="index") + save_as_half = gr.Radio(choices=["fp16", "fp32"], value="fp16", label="Model precision", + type="index") with FormRow(): - config_source = gr.Radio(choices=["Primary", "Secondary", "Tertiary", "None"], value="Primary", label="Model configuration", type="index") + config_source = gr.Radio(choices=["Primary", "Secondary", "Tertiary", "None"], + value="Primary", label="Model configuration", type="index") with FormRow(): - bake_in_vae = gr.Dropdown(choices=["None"] + list(sd_vae.vae_dict), value="None", label="Bake in VAE") - create_refresh_button(bake_in_vae, sd_vae.refresh_vae_list, lambda: {"choices": ["None"] + list(sd_vae.vae_dict)}, "modelmerger_refresh_bake_in_vae") + bake_in_vae = gr.Dropdown(choices=["None"] + list(sd_vae.vae_dict), value="None", + label="Bake in VAE") + create_refresh_button(bake_in_vae, sd_vae.refresh_vae_list, + lambda: {"choices": ["None"] + list(sd_vae.vae_dict)}, + "modelmerger_refresh_bake_in_vae") with FormRow(): discard_weights = gr.Textbox(value="", label="Discard weights with matching name") with FormRow(): @@ -112,7 +126,8 @@ def create_ui(): except Exception as e: modules.errors.display(e, 'model merge') sd_models.list_models() # to remove the potentially missing models from the list - return [*[gr.Dropdown.update(choices=sd_models.checkpoint_tiles()) for _ in range(4)], f"Error merging checkpoints: {e}"] + return [*[gr.Dropdown.update(choices=sd_models.checkpoint_tiles()) for _ in range(4)], + f"Error merging checkpoints: {e}"] return results modelmerger_merge.click( @@ -144,103 +159,135 @@ def create_ui(): with gr.Tab(label="Advanced Merge"): def sd_model_choices(): return ['None'] + sd_models.checkpoint_tiles() + with gr.Row(equal_height=False): with gr.Column(variant='compact'): with FormRow(): custom_name = gr.Textbox(label="New model name") with FormRow(): - merge_mode = gr.Dropdown(choices=merge_methods.__all__, value="weighted_sum", label="Interpolation Method") + merge_mode = gr.Dropdown(choices=merge_methods.__all__, value="weighted_sum", + label="Interpolation Method") with FormRow(): primary_model_name = gr.Dropdown(sd_model_choices(), label="Primary model", value="None") - create_refresh_button(primary_model_name, sd_models.list_models, lambda: {"choices": sd_model_choices()}, "refresh_checkpoint_A") - secondary_model_name = gr.Dropdown(sd_model_choices(), label="Secondary model", value="None") - create_refresh_button(secondary_model_name, sd_models.list_models, lambda: {"choices": sd_model_choices()}, "refresh_checkpoint_B") - tertiary_model_name = gr.Dropdown(sd_model_choices(), label="Tertiary model", value="None", visible=False) - tertiary_refresh = create_refresh_button(tertiary_model_name, sd_models.list_models, lambda: {"choices": sd_model_choices()}, "refresh_checkpoint_C",visible=False) + create_refresh_button(primary_model_name, sd_models.list_models, + lambda: {"choices": sd_model_choices()}, "refresh_checkpoint_A") + secondary_model_name = gr.Dropdown(sd_model_choices(), label="Secondary model", + value="None") + create_refresh_button(secondary_model_name, sd_models.list_models, + lambda: {"choices": sd_model_choices()}, "refresh_checkpoint_B") + tertiary_model_name = gr.Dropdown(sd_model_choices(), label="Tertiary model", value="None", + visible=False) + tertiary_refresh = create_refresh_button(tertiary_model_name, sd_models.list_models, + lambda: {"choices": sd_model_choices()}, + "refresh_checkpoint_C", visible=False) with FormRow(): with gr.Tabs() as tabs: with gr.TabItem(label="Simple Merge", id=0): with FormRow(): - alpha = gr.Slider(minimum=0.0, maximum=1.0, step=0.05, label='Alpha Ratio', value=0.5) - beta = gr.Slider(minimum=0.0, maximum=1.0, step=0.05, label='Beta Ratio', value=None, visible=False) + alpha = gr.Slider(minimum=0.0, maximum=1.0, step=0.05, label='Alpha Ratio', + value=0.5) + beta = gr.Slider(minimum=0.0, maximum=1.0, step=0.05, label='Beta Ratio', + value=None, visible=False) with gr.TabItem(label="Preset Block Merge", id=1): with FormRow(): - alpha_preset = gr.Dropdown(choices=["None"]+list(BLOCK_WEIGHTS_PRESETS.keys()), value=None, label="ALPHA Block Weight Preset", multiselect=True, max_choices=2) - alpha_preset_lambda = gr.Slider(minimum=0.0, maximum=1.0, step=0.05, label='Preset Interpolation Ratio', value=None, visible=False) - apply_preset = ToolButton('⇩', visible=True) + sdxl = gr.Checkbox(label="SDXL") with FormRow(): - beta_preset = gr.Dropdown(choices=["None"]+list(BLOCK_WEIGHTS_PRESETS.keys()), value=None, label="BETA Block Weight Preset", multiselect=True, max_choices=2, interactive=True, visible=False) - beta_preset_lambda = gr.Slider(minimum=0.0, maximum=1.0, step=0.05, label='Preset Interpolation Ratio', value=None, interactive=True, visible=False) - beta_apply_preset = ToolButton('⇩', interactive=True, visible=False) + alpha_preset = gr.Dropdown( + choices=["None"] + list(BLOCK_WEIGHTS_PRESETS.keys()), value=None, + label="ALPHA Block Weight Preset", multiselect=True, max_choices=2) + alpha_preset_lambda = gr.Slider(minimum=0.0, maximum=1.0, step=0.05, + label='Preset Interpolation Ratio', value=None, + visible=False) + apply_preset = ToolButton('⇨', visible=True) + with FormRow(): + beta_preset = gr.Dropdown(choices=["None"] + list(BLOCK_WEIGHTS_PRESETS.keys()), + value=None, label="BETA Block Weight Preset", + multiselect=True, max_choices=2, interactive=True, + visible=False) + beta_preset_lambda = gr.Slider(minimum=0.0, maximum=1.0, step=0.05, + label='Preset Interpolation Ratio', value=None, + interactive=True, visible=False) + beta_apply_preset = ToolButton('⇨', interactive=True, visible=False) with gr.TabItem(label="Manual Block Merge", id=2): with FormRow(): alpha_label = gr.Markdown("# Alpha") with FormRow(): alpha_base = gr.Textbox(value=None, label="Base", min_width=70, scale=1) alpha_in_blocks = gr.Textbox(value=None, label="In Blocks", scale=15) - alpha_mid_block = gr.Textbox(value=None, label="Mid Block", min_width=80, scale=1) + alpha_mid_block = gr.Textbox(value=None, label="Mid Block", min_width=80, + scale=1) alpha_out_blocks = gr.Textbox(value=None, label="Out Block", scale=15) with FormRow(): beta_label = gr.Markdown("# Beta", visible=False) with FormRow(): - beta_base = gr.Textbox(value=None, label="Base", min_width=70, scale=1, interactive=True, visible=False) - beta_in_blocks = gr.Textbox(value=None, label="In Blocks", interactive=True, scale=15, visible=False) - beta_mid_block = gr.Textbox(value=None, label="Mid Block", min_width=80, interactive=True, scale=1, visible=False) - beta_out_blocks = gr.Textbox(value=None, label="Out Block", interactive=True, scale=15, visible=False) + beta_base = gr.Textbox(value=None, label="Base", min_width=70, scale=1, + interactive=True, visible=False) + beta_in_blocks = gr.Textbox(value=None, label="In Blocks", interactive=True, + scale=15, visible=False) + beta_mid_block = gr.Textbox(value=None, label="Mid Block", min_width=80, + interactive=True, scale=1, visible=False) + beta_out_blocks = gr.Textbox(value=None, label="Out Block", interactive=True, + scale=15, visible=False) with FormRow(): weights_clip = gr.Checkbox(label="Weights Clip") - prune = gr.Checkbox(label="Prune") + prune = gr.Checkbox(label="Prune", value=True, visible=False) re_basin = gr.Checkbox(label="ReBasin") with FormRow(): - re_basin_iterations = gr.Slider(minimum=0, maximum=25, step=1, label='Number of ReBasin Iterations', value=None, visible=False) + re_basin_iterations = gr.Slider(minimum=0, maximum=25, step=1, + label='Number of ReBasin Iterations', value=None, + visible=False) with FormRow(): - checkpoint_format = gr.Radio(choices=["ckpt", "safetensors"], value="safetensors", visible=False, label="Model format") + checkpoint_format = gr.Radio(choices=["ckpt", "safetensors"], value="safetensors", + visible=False, label="Model format") with FormRow(): precision = gr.Radio(choices=["fp16", "fp32"], value="fp16", label="Model precision") with FormRow(): device = gr.Radio(choices=["cpu", "cuda"], value="cpu", label="Device") with FormRow(): - bake_in_vae = gr.Dropdown(choices=["None"] + list(sd_vae.vae_dict), value="None", interactive=True, label="Bake in VAE") - create_refresh_button(bake_in_vae, sd_vae.refresh_vae_list, lambda: {"choices": ["None"] + list(sd_vae.vae_dict)}, "modelmerger_refresh_bake_in_vae") + bake_in_vae = gr.Dropdown(choices=["None"] + list(sd_vae.vae_dict), value="None", + interactive=True, label="Bake in VAE") + create_refresh_button(bake_in_vae, sd_vae.refresh_vae_list, + lambda: {"choices": ["None"] + list(sd_vae.vae_dict)}, + "modelmerger_refresh_bake_in_vae") with FormRow(): save_metadata = gr.Checkbox(value=True, label="Save metadata") with gr.Row(): MEHmodelmerger_merge = gr.Button(value="Merge", variant='primary') def MEHmodelmerger(dummy_component, - primary_model_name, - secondary_model_name, - tertiary_model_name, - merge_mode, - alpha, - beta, - alpha_preset, - alpha_preset_lambda, - alpha_base, - alpha_in_blocks, - alpha_mid_block, - alpha_out_blocks, - beta_preset, - beta_preset_lambda, - beta_base, - beta_in_blocks, - beta_mid_block, - beta_out_blocks, - precision, - custom_name, - checkpoint_format, - save_metadata, - weights_clip, - prune, - re_basin, - re_basin_iterations, - device, - bake_in_vae): + primary_model_name, + secondary_model_name, + tertiary_model_name, + merge_mode, + alpha, + beta, + alpha_preset, + alpha_preset_lambda, + alpha_base, + alpha_in_blocks, + alpha_mid_block, + alpha_out_blocks, + beta_preset, + beta_preset_lambda, + beta_base, + beta_in_blocks, + beta_mid_block, + beta_out_blocks, + precision, + custom_name, + checkpoint_format, + save_metadata, + weights_clip, + prune, + re_basin, + re_basin_iterations, + device, + bake_in_vae): kwargs = {} for x in inspect.getfullargspec(MEHmodelmerger)[0]: kwargs[x] = locals()[x] for key in list(kwargs.keys()): - if kwargs[key] in [None,"None","",0,[]]: + if kwargs[key] in [None, "None", "", 0, []]: del kwargs[key] # return [*[gr.Dropdown.update(choices=sd_models.checkpoint_tiles()) for _ in range(4)], f"{kwargs}"] @@ -250,7 +297,8 @@ def create_ui(): except Exception as e: modules.errors.display(e, 'model merge') sd_models.list_models() # to remove the potentially missing models from the list - return [*[gr.Dropdown.update(choices=sd_models.checkpoint_tiles()) for _ in range(4)], f"Error merging checkpoints: {e}"] + return [*[gr.Dropdown.update(choices=sd_models.checkpoint_tiles()) for _ in range(4)], + f"Error merging checkpoints: {e}"] return results def tertiary(mode): @@ -264,18 +312,20 @@ def create_ui(): return [gr.update(visible=True) for _ in range(9)] else: return [gr.update(visible=False) for _ in range(9)] + def show_iters(show): if show: return gr.Slider.update(value=5, visible=True) else: return gr.Slider.update(value=None, visible=False) + def preset_visiblility(x): if len(x) == 2: return gr.Slider.update(value=0.5, visible=True) else: return gr.Slider.update(value=None, visible=False) - def load_presets(presets,ratio): + def load_presets(presets, ratio): for i, p in enumerate(presets): presets[i] = BLOCK_WEIGHTS_PRESETS[p] if len(presets) == 2: @@ -283,16 +333,28 @@ def create_ui(): else: preset = presets[0] preset = ['%.3f' % x for x in preset] - preset = [preset[0], ",".join(preset[1:13]),preset[13], ",".join(preset[14:])] - return [gr.update(value=x) for x in preset]+[gr.update(selected=2)] + preset = [preset[0], ",".join(preset[1:13]), preset[13], ",".join(preset[14:])] + return [gr.update(value=x) for x in preset] + [gr.update(selected=2)] + def preset_choices(sdxl): + if sdxl: + return [gr.update(choices=["None"] + list(SDXL_BLOCK_WEIGHTS_PRESETS.keys())) for _ in range(2)] + else: + return [gr.update(choices=["None"] + list(BLOCK_WEIGHTS_PRESETS.keys())) for _ in range(2)] + + sdxl.change(fn=preset_choices, inputs=sdxl, outputs=[alpha_preset, beta_preset]) alpha_preset.change(fn=preset_visiblility, inputs=alpha_preset, outputs=alpha_preset_lambda) beta_preset.change(fn=preset_visiblility, inputs=alpha_preset, outputs=beta_preset_lambda) merge_mode.input(fn=tertiary, inputs=merge_mode, outputs=[tertiary_model_name, tertiary_refresh]) - merge_mode.input(fn=beta_visibility, inputs=merge_mode, outputs=[beta, alpha_label, beta_label, beta_apply_preset, beta_preset, beta_base, beta_in_blocks, beta_mid_block, beta_out_blocks]) - re_basin.change(fn=show_iters, inputs=re_basin,outputs=re_basin_iterations) - apply_preset.click(fn=load_presets,inputs=[alpha_preset, alpha_preset_lambda], outputs=[alpha_base,alpha_in_blocks,alpha_mid_block,alpha_out_blocks,tabs]) - beta_apply_preset.click(fn=load_presets,inputs=[beta_preset, beta_preset_lambda], outputs=[beta_base,beta_in_blocks,beta_mid_block,beta_out_blocks,tabs]) + merge_mode.input(fn=beta_visibility, inputs=merge_mode, + outputs=[beta, alpha_label, beta_label, beta_apply_preset, beta_preset, beta_base, + beta_in_blocks, beta_mid_block, beta_out_blocks]) + re_basin.change(fn=show_iters, inputs=re_basin, outputs=re_basin_iterations) + apply_preset.click(fn=load_presets, inputs=[alpha_preset, alpha_preset_lambda], + outputs=[alpha_base, alpha_in_blocks, alpha_mid_block, alpha_out_blocks, tabs]) + beta_apply_preset.click(fn=load_presets, inputs=[beta_preset, beta_preset_lambda], + outputs=[beta_base, beta_in_blocks, beta_mid_block, beta_out_blocks, tabs]) + MEHmodelmerger_merge.click( fn=wrap_gradio_gpu_call(MEHmodelmerger, extra_outputs=lambda: [gr.update() for _ in range(4)]), _js='modelmerger', @@ -346,14 +408,14 @@ def create_ui(): model_checkhash_btn.click(fn=sd_models.update_model_hashes, inputs=[], outputs=[models_outcome]) with gr.Row(): model_table = gr.DataFrame( - value = None, - headers = model_headers, - label = 'Model data', - show_label = True, - interactive = False, - wrap = True, - overflow_row_behaviour = 'paginate', - max_rows = 50, + value=None, + headers=model_headers, + label='Model data', + show_label=True, + interactive=False, + wrap=True, + overflow_row_behaviour='paginate', + max_rows=50, ) def list_models(): @@ -392,11 +454,15 @@ def create_ui(): # task='text-to-image', library=['diffusers'], ) - models = hf_api.list_models(filter=model_filter, full=True, limit=50, sort="downloads", direction=-1) + models = hf_api.list_models(filter=model_filter, full=True, limit=50, sort="downloads", + direction=-1) data.clear() for model in models: - tags = [t for t in model.tags if not t.startswith('diffusers') and not t.startswith('license') and not t.startswith('arxiv') and len(t) > 2] - data.append([model.modelId, model.pipeline_tag, tags, model.downloads, model.lastModified, f'https://huggingface.co/{model.modelId}']) + tags = [t for t in model.tags if + not t.startswith('diffusers') and not t.startswith('license') and not t.startswith( + 'arxiv') and len(t) > 2] + data.append([model.modelId, model.pipeline_tag, tags, model.downloads, model.lastModified, + f'https://huggingface.co/{model.modelId}']) return data def hf_select(evt: gr.SelectData, data): @@ -404,8 +470,9 @@ def create_ui(): def hf_download_model(hub_id: str, token, variant, revision, mirror, custom_pipeline): from modules.modelloader import download_diffusers_model - download_diffusers_model(hub_id, cache_dir=opts.diffusers_dir, token=token, variant=variant, revision=revision, mirror=mirror, custom_pipeline=custom_pipeline) - from modules.sd_models import list_models # pylint: disable=W0621 + download_diffusers_model(hub_id, cache_dir=opts.diffusers_dir, token=token, variant=variant, + revision=revision, mirror=mirror, custom_pipeline=custom_pipeline) + from modules.sd_models import list_models # pylint: disable=W0621 list_models() log.info(f'Diffuser model downloaded: model="{hub_id}"') return f'Diffuser model downloaded: model="{hub_id}"' @@ -413,20 +480,25 @@ def create_ui(): with gr.Column(scale=6): gr.HTML('

Search for models

Select a model from the search results to download

') with gr.Row(): - hf_search_text = gr.Textbox('', label = 'Search models', placeholder='search huggingface models') + hf_search_text = gr.Textbox('', label='Search models', placeholder='search huggingface models') hf_search_btn = ToolButton(value="🔍", label="Search") with gr.Row(): with gr.Column(scale=2): with gr.Row(): - hf_selected = gr.Textbox('', label = 'Select model', placeholder='select model from search results or enter model name manually') + hf_selected = gr.Textbox('', label='Select model', + placeholder='select model from search results or enter model name manually') with gr.Column(scale=1): with gr.Row(): - hf_variant = gr.Textbox(opts.cuda_dtype.lower(), label = 'Specify model variant', placeholder='') - hf_revision = gr.Textbox('', label = 'Specify model revision', placeholder='') + hf_variant = gr.Textbox(opts.cuda_dtype.lower(), label='Specify model variant', + placeholder='') + hf_revision = gr.Textbox('', label='Specify model revision', placeholder='') with gr.Row(): - hf_token = gr.Textbox('', label = 'Huggingface token', placeholder='optional access token for private or gated models') - hf_mirror = gr.Textbox('', label = 'Huggingface mirror', placeholder='optional mirror site for downloads') - hf_custom_pipeline = gr.Textbox('', label = 'Custom pipeline', placeholder='optional pipeline for downloads') + hf_token = gr.Textbox('', label='Huggingface token', + placeholder='optional access token for private or gated models') + hf_mirror = gr.Textbox('', label='Huggingface mirror', + placeholder='optional mirror site for downloads') + hf_custom_pipeline = gr.Textbox('', label='Custom pipeline', + placeholder='optional pipeline for downloads') with gr.Column(scale=1): gr.HTML('
') hf_download_model_btn = gr.Button(value="Download model", variant='primary') @@ -434,12 +506,16 @@ def create_ui(): with gr.Row(): hf_headers = ['Name', 'Pipeline', 'Tags', 'Downloads', 'Updated', 'URL'] hf_types = ['str', 'str', 'str', 'number', 'date', 'markdown'] - hf_results = gr.DataFrame(None, label = 'Search results', show_label = True, interactive = False, wrap = True, overflow_row_behaviour = 'paginate', max_rows = 10, headers = hf_headers, datatype = hf_types, type='array') + hf_results = gr.DataFrame(None, label='Search results', show_label=True, interactive=False, + wrap=True, overflow_row_behaviour='paginate', max_rows=10, + headers=hf_headers, datatype=hf_types, type='array') hf_search_text.submit(fn=hf_search, inputs=[hf_search_text], outputs=[hf_results]) hf_search_btn.click(fn=hf_search, inputs=[hf_search_text], outputs=[hf_results]) hf_results.select(fn=hf_select, inputs=[hf_results], outputs=[hf_selected]) - hf_download_model_btn.click(fn=hf_download_model, inputs=[hf_selected, hf_token, hf_variant, hf_revision, hf_mirror, hf_custom_pipeline], outputs=[models_outcome]) + hf_download_model_btn.click(fn=hf_download_model, + inputs=[hf_selected, hf_token, hf_variant, hf_revision, hf_mirror, + hf_custom_pipeline], outputs=[models_outcome]) with gr.Tab(label="CivitAI"): data = [] @@ -482,7 +558,8 @@ def create_ui(): model['stats']['rating'] ]) res = f'Search result: name={name} tag={tag or "none"} type={model_type} models={len(data1)}' - return res, gr.update(visible=len(data1) > 0, value=data1 if len(data1) > 0 else []), gr.update(visible=False, value=None), gr.update(visible=False, value=None) + return res, gr.update(visible=len(data1) > 0, value=data1 if len(data1) > 0 else []), gr.update( + visible=False, value=None), gr.update(visible=False, value=None) def civit_select1(evt: gr.SelectData, in_data): model_id = in_data[evt.index[0]][0] @@ -491,7 +568,8 @@ def create_ui(): for model in data: if model['id'] == model_id: for d in model['modelVersions']: - if d.get('images') is not None and len(d['images']) > 0 and len(d['images'][0]['url']) > 0: + if d.get('images') is not None and len(d['images']) > 0 and len( + d['images'][0]['url']) > 0: preview_img = d['images'][0]['url'] data2.append([ d['id'], @@ -513,7 +591,8 @@ def create_ui(): if variant['id'] == variant_id: for f in variant['files']: try: - if os.path.splitext(f['name'])[1].lower() in ['.safetensors', '.ckpt', '.pt', '.pth', '.bin']: + if os.path.splitext(f['name'])[1].lower() in ['.safetensors', '.ckpt', + '.pt', '.pth', '.bin']: data3.append([ f['name'], round(f['sizeKB']), @@ -529,7 +608,8 @@ def create_ui(): log.debug(f'CivitAI select: variant={in_data[evt.index[0]]}') return in_data[evt.index[0]][3], in_data[evt.index[0]][0], gr.update(interactive=True) - def civit_download_model(model_url: str, model_name: str, model_path: str, model_type: str, image_url: str): + def civit_download_model(model_url: str, model_name: str, model_path: str, model_type: str, + image_url: str): if model_url is None or len(model_url) == 0: return 'No model selected' try: @@ -539,7 +619,7 @@ def create_ui(): res = f"CivitAI model downloaded error: model={model_url} {e}" log.error(res) return res - from modules.sd_models import list_models # pylint: disable=W0621 + from modules.sd_models import list_models # pylint: disable=W0621 list_models() return res @@ -556,12 +636,14 @@ def create_ui(): continue for item in page.list_items(): meta = os.path.splitext(item['filename'])[0] + '.json' - if ('card-no-preview.png' in item['preview'] or not os.path.isfile(meta)) and os.path.isfile(item['filename']): + if ('card-no-preview.png' in item['preview'] or not os.path.isfile( + meta)) and os.path.isfile(item['filename']): sha = item.get('hash', None) found = False if sha is not None and len(sha) > 0: r = req(f'https://civitai.com/api/v1/model-versions/by-hash/{sha}') - log.debug(f'CivitAI search: name="{item["name"]}" hash={sha} status={r.status_code}') + log.debug( + f'CivitAI search: name="{item["name"]}" hash={sha} status={r.status_code}') if r.status_code == 200: d = r.json() res.append(download_civit_meta(item['filename'], d['modelId'])) @@ -573,10 +655,12 @@ def create_ui(): if 'error' not in img_res: found = True break - if not found and civit_previews_rehash and os.stat(item['filename']).st_size < (1024 * 1024 * 1024): + if not found and civit_previews_rehash and os.stat(item['filename']).st_size < ( + 1024 * 1024 * 1024): sha = modules.hashes.calculate_sha256(item['filename'], quiet=True)[:10] r = req(f'https://civitai.com/api/v1/model-versions/by-hash/{sha}') - log.debug(f'CivitAI search: name="{item["name"]}" hash={sha} status={r.status_code}') + log.debug( + f'CivitAI search: name="{item["name"]}" hash={sha} status={r.status_code}') if r.status_code == 200: d = r.json() res.append(download_civit_meta(item['filename'], d['modelId'])) @@ -591,11 +675,12 @@ def create_ui(): txt = '
'.join([r for r in res if len(r) > 0]) return txt - global search_metadata_civit # pylint: disable=global-statement + global search_metadata_civit # pylint: disable=global-statement search_metadata_civit = civit_search_metadata with gr.Row(): - gr.HTML('

Fetch information

Fetches preview and metadata information for all models with missing information
Models with existing previews and information are not updated
') + gr.HTML( + '

Fetch information

Fetches preview and metadata information for all models with missing information
Models with existing previews and information are not updated
') with gr.Row(): civit_previews_btn = gr.Button(value="Start", variant='primary') with gr.Row(): @@ -605,11 +690,12 @@ def create_ui(): gr.HTML('

Search for models

') with gr.Row(): with gr.Column(scale=1): - civit_model_type = gr.Dropdown(label='Model type', choices=['SD 1.5', 'SD XL', 'LoRA', 'Other'], value='LoRA') + civit_model_type = gr.Dropdown(label='Model type', choices=['SD 1.5', 'SD XL', 'LoRA', 'Other'], + value='LoRA') with gr.Column(scale=15): with gr.Row(): - civit_search_text = gr.Textbox('', label = 'Search models', placeholder='keyword') - civit_search_tag = gr.Textbox('', label = '', placeholder='tags') + civit_search_text = gr.Textbox('', label='Search models', placeholder='keyword') + civit_search_tag = gr.Textbox('', label='', placeholder='tags') civit_search_btn = ToolButton(value="🔍", label="Search", interactive=False) with gr.Row(): civit_search_res = gr.HTML('') @@ -617,39 +703,64 @@ def create_ui(): gr.HTML('

Download model

') with gr.Row(): civit_download_model_btn = gr.Button(value="Download", variant='primary') - gr.HTML('Select a model, model version and and model variant from the search results to download or enter model URL manually
') + gr.HTML( + 'Select a model, model version and and model variant from the search results to download or enter model URL manually
') with gr.Row(): - civit_name = gr.Textbox('', label = 'Model name', placeholder='select model from search results', visible=True) - civit_selected = gr.Textbox('', label = 'Model URL', placeholder='select model from search results', visible=True) - civit_path = gr.Textbox('', label = 'Download path', placeholder='optional subfolder path where to save model', visible=True) + civit_name = gr.Textbox('', label='Model name', placeholder='select model from search results', + visible=True) + civit_selected = gr.Textbox('', label='Model URL', placeholder='select model from search results', + visible=True) + civit_path = gr.Textbox('', label='Download path', + placeholder='optional subfolder path where to save model', visible=True) with gr.Row(): gr.HTML('

Search results

') with gr.Row(): civit_headers1 = ['ID', 'Name', 'Tags', 'Downloads', 'Rating'] civit_types1 = ['number', 'str', 'str', 'number', 'number'] - civit_results1 = gr.DataFrame(value = None, label = None, show_label = False, interactive = False, wrap = True, overflow_row_behaviour = 'paginate', max_rows = 10, headers = civit_headers1, datatype = civit_types1, type='array', visible=False) + civit_results1 = gr.DataFrame(value=None, label=None, show_label=False, interactive=False, + wrap=True, overflow_row_behaviour='paginate', max_rows=10, + headers=civit_headers1, datatype=civit_types1, type='array', + visible=False) with gr.Row(): with gr.Column(): civit_headers2 = ['ID', 'ModelID', 'Name', 'Base', 'Created', 'Preview'] civit_types2 = ['number', 'number', 'str', 'str', 'date', 'str'] - civit_results2 = gr.DataFrame(value = None, label = 'Model versions', show_label = True, interactive = False, wrap = True, overflow_row_behaviour = 'paginate', max_rows = 10, headers = civit_headers2, datatype = civit_types2, type='array', visible=False) + civit_results2 = gr.DataFrame(value=None, label='Model versions', show_label=True, + interactive=False, wrap=True, overflow_row_behaviour='paginate', + max_rows=10, headers=civit_headers2, datatype=civit_types2, + type='array', visible=False) with gr.Column(): civit_headers3 = ['Name', 'Size', 'Metadata', 'URL'] civit_types3 = ['str', 'number', 'str', 'str'] - civit_results3 = gr.DataFrame(value = None, label = 'Model variants', show_label = True, interactive = False, wrap = True, overflow_row_behaviour = 'paginate', max_rows = 10, headers = civit_headers3, datatype = civit_types3, type='array', visible=False) + civit_results3 = gr.DataFrame(value=None, label='Model variants', show_label=True, + interactive=False, wrap=True, overflow_row_behaviour='paginate', + max_rows=10, headers=civit_headers3, datatype=civit_types3, + type='array', visible=False) def is_visible(component): visible = len(component) > 0 if component is not None else False return gr.update(visible=visible) - civit_search_text.submit(fn=civit_search_model, inputs=[civit_search_text, civit_search_tag, civit_model_type], outputs=[civit_search_res, civit_results1, civit_results2, civit_results3]) - civit_search_tag.submit(fn=civit_search_model, inputs=[civit_search_text, civit_search_tag, civit_model_type], outputs=[civit_search_res, civit_results1, civit_results2, civit_results3]) - civit_search_btn.click(fn=civit_search_model, inputs=[civit_search_text, civit_search_tag, civit_model_type], outputs=[civit_search_res, civit_results1, civit_results2, civit_results3]) - civit_results1.select(fn=civit_select1, inputs=[civit_results1], outputs=[civit_results2, civit_results3, models_image]) + civit_search_text.submit(fn=civit_search_model, + inputs=[civit_search_text, civit_search_tag, civit_model_type], + outputs=[civit_search_res, civit_results1, civit_results2, civit_results3]) + civit_search_tag.submit(fn=civit_search_model, + inputs=[civit_search_text, civit_search_tag, civit_model_type], + outputs=[civit_search_res, civit_results1, civit_results2, civit_results3]) + civit_search_btn.click(fn=civit_search_model, + inputs=[civit_search_text, civit_search_tag, civit_model_type], + outputs=[civit_search_res, civit_results1, civit_results2, civit_results3]) + civit_results1.select(fn=civit_select1, inputs=[civit_results1], + outputs=[civit_results2, civit_results3, models_image]) civit_results2.select(fn=civit_select2, inputs=[civit_results2], outputs=[civit_results3]) - civit_results3.select(fn=civit_select3, inputs=[civit_results3], outputs=[civit_selected, civit_name, civit_search_btn]) + civit_results3.select(fn=civit_select3, inputs=[civit_results3], + outputs=[civit_selected, civit_name, civit_search_btn]) civit_results1.change(fn=is_visible, inputs=[civit_results1], outputs=[civit_results1]) civit_results2.change(fn=is_visible, inputs=[civit_results2], outputs=[civit_results2]) civit_results3.change(fn=is_visible, inputs=[civit_results3], outputs=[civit_results3]) - civit_download_model_btn.click(fn=civit_download_model, inputs=[civit_selected, civit_name, civit_path, civit_model_type, models_image], outputs=[models_outcome]) - civit_previews_btn.click(fn=civit_search_metadata, inputs=[civit_previews_rehash, civit_previews_rehash], outputs=[models_outcome]) + civit_download_model_btn.click(fn=civit_download_model, + inputs=[civit_selected, civit_name, civit_path, civit_model_type, + models_image], outputs=[models_outcome]) + civit_previews_btn.click(fn=civit_search_metadata, + inputs=[civit_previews_rehash, civit_previews_rehash], + outputs=[models_outcome]) diff --git a/requirements.txt b/requirements.txt index 3cd2b7fe9..68b614704 100644 --- a/requirements.txt +++ b/requirements.txt @@ -33,6 +33,7 @@ rich safetensors scipy tb_nightly +tensordict toml torchdiffeq voluptuous From 515a546a91b0bcc36020189b16855482ede35680 Mon Sep 17 00:00:00 2001 From: AI-Casanova <54461896+AI-Casanova@users.noreply.github.com> Date: Mon, 6 Nov 2023 08:19:50 -0600 Subject: [PATCH 04/84] Fix rebasin --- modules/merging/utils.py | 29 ++++++++++++----------------- 1 file changed, 12 insertions(+), 17 deletions(-) diff --git a/modules/merging/utils.py b/modules/merging/utils.py index 4cee23db1..7feff1393 100644 --- a/modules/merging/utils.py +++ b/modules/merging/utils.py @@ -30,7 +30,7 @@ class WeightClass: model_a, **kwargs, ): - self.SDXL = True if "model.diffusion_model.middle_block.1.transformer_blocks.9.norm3.weight" in model_a.keys() else False + self.SDXL = "model.diffusion_model.middle_block.1.transformer_blocks.9.norm3.weight" in model_a.keys() self.NUM_INPUT_BLOCKS = 12 if not self.SDXL else 9 self.NUM_MID_BLOCK = 1 self.NUM_OUTPUT_BLOCKS = 12 if not self.SDXL else 9 @@ -59,13 +59,12 @@ class WeightClass: else: self.ratioDict[key] = self.ratioDict[key][0] - def __call__(self, key, it=0): current_bases = {} if self.ratioDict.get("alpha", None): - current_bases["alpha"] = self.step_weights_and_bases(self.ratioDict["alpha"], it) + current_bases["alpha"] = self.step_weights_and_bases(self.ratioDict["alpha"]) if self.ratioDict.get("beta", None): - current_bases["beta"] = self.step_weights_and_bases(self.ratioDict["beta"], it) + current_bases["beta"] = self.step_weights_and_bases(self.ratioDict["beta"]) weight_index = 0 if "model" in key: @@ -92,22 +91,18 @@ class WeightClass: raise ValueError(f"illegal block index {key}") current_bases = {k: w[weight_index] for k, w in current_bases.items()} - if self.re_basin: - current_bases = self.step_weights_and_bases(current_bases,self.it) return current_bases - def step_weights_and_bases(self, - ratio, - it: int = 0, - ): - new_ratio = { - k: - 1 - (1 - (1 + it) * v / self.iterations) / (1 - it * v / self.iterations) - if it > 0 - else v / self.iterations - for k, v in ratio.items() - } + def step_weights_and_bases(self, ratio): + if not self.re_basin: + return ratio + new_ratio = [ + 1 - (1 - (1 + self.it) * v / self.iterations) / (1 - self.it * v / self.iterations) + if self.it > 0 + else v / self.iterations + for v in ratio + ] return new_ratio def set_it(self, it): From 864fc898face90451faba46aa6f4e1fe16a6d4bf Mon Sep 17 00:00:00 2001 From: AI-Casanova <54461896+AI-Casanova@users.noreply.github.com> Date: Fri, 10 Nov 2023 06:51:38 -0600 Subject: [PATCH 05/84] Bugfix --- modules/extras.py | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/modules/extras.py b/modules/extras.py index fe02f002a..044fc74ba 100644 --- a/modules/extras.py +++ b/modules/extras.py @@ -271,8 +271,7 @@ def run_MEHmodelmerger(id_task, **kwargs): # pylint: disable=unused-argument secondary_model_info = sd_models.checkpoints_list[kwargs.get("secondary_model_name", None)] if kwargs.get("tertiary_model_name", None) in [None, 'None'] and kwargs.get("merge_mode", None) in TRIPLE_METHODS: return fail(f"Failed: Interpolation method ({kwargs.get('merge_mode', None)}) requires a tertiary model.") - tertiary_model_info = sd_models.checkpoints_list[tertiary_model_name] if kwargs.get("merge_mode", - None) in TRIPLE_METHODS else None + tertiary_model_info = sd_models.checkpoints_list[kwargs.get("tertiary_model_name", None)] if kwargs.get("merge_mode", None) in TRIPLE_METHODS else None del kwargs["primary_model_name"] del kwargs["secondary_model_name"] @@ -287,7 +286,7 @@ def run_MEHmodelmerger(id_task, **kwargs): # pylint: disable=unused-argument assert len(alpha) == 26 or len( alpha) == 20, "Alpha Block Weights are wrong length (26 or 20 for SDXL) falling back" kwargs["alpha"] = alpha - except Exception as e: + except: kwargs["alpha"] = kwargs.get("alpha_preset", kwargs["alpha"]) finally: kwargs.pop("alpha_base", None) @@ -295,6 +294,7 @@ def run_MEHmodelmerger(id_task, **kwargs): # pylint: disable=unused-argument kwargs.pop("alpha_mid_block", None) kwargs.pop("alpha_out_blocks", None) kwargs.pop("alpha_preset", None) + if kwargs.get("beta", False): try: beta = [float(x) for x in @@ -303,7 +303,7 @@ def run_MEHmodelmerger(id_task, **kwargs): # pylint: disable=unused-argument assert len(beta) == 26 or len( beta) == 20, "Beta Block Weights are wrong length (26 or 20 for SDXL) falling back" kwargs["beta"] = beta - except Exception as e: + except: kwargs["beta"] = kwargs.get("beta_preset", kwargs["beta"]) finally: kwargs.pop("beta_base", None) @@ -355,7 +355,11 @@ def run_MEHmodelmerger(id_task, **kwargs): # pylint: disable=unused-argument metadata["sd_merge_models"] = json.dumps(metadata["sd_merge_models"]) _, extension = os.path.splitext(output_modelname) - theta_0 = theta_0.to_dict() + try: + theta_0 = theta_0.to_dict() + except: + pass + if extension.lower() == ".safetensors": safetensors.torch.save_file(theta_0, output_modelname, metadata=metadata) else: From 02a32e71088401bb6b0629f674f13eb866e589b3 Mon Sep 17 00:00:00 2001 From: AI-Casanova <54461896+AI-Casanova@users.noreply.github.com> Date: Fri, 10 Nov 2023 07:02:17 -0600 Subject: [PATCH 06/84] Add Logging --- modules/merging/merge.py | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/modules/merging/merge.py b/modules/merging/merge.py index e55433d86..76c5b036d 100644 --- a/modules/merging/merge.py +++ b/modules/merging/merge.py @@ -9,6 +9,7 @@ import safetensors.torch import torch from tqdm import tqdm +from modules.shared import log from modules.merging import merge_methods from modules.merging.utils import WeightClass from modules.merging.model import SDModel @@ -19,8 +20,6 @@ from modules.merging.rebasin import ( weight_matching, ) -# logging.getLogger("sd_meh").addHandler(logging.NullHandler()) - MAX_TOKENS = 77 @@ -97,7 +96,7 @@ def restore_sd_model(original_model: Dict, merged_model: Dict) -> Dict: def log_vram(txt=""): alloc = torch.cuda.memory_allocated(0) - # logging.debug(f"{txt} VRAM: {alloc*1e-9:5.3f}GB") + log.info(f"{txt} VRAM: {alloc*1e-9:5.3f}GB") def load_thetas( @@ -130,16 +129,16 @@ def merge_models( precision: str = "full", weights_clip: bool = False, re_basin: bool = False, - iterations: int = 1, device: str = "cpu", work_device: Optional[str] = None, prune: bool = False, threads: int = 1, **kwargs, ) -> Dict: + iterations = kwargs.get("iterations", 1) thetas = load_thetas(models, prune, device, precision) - # logging.info(f"start merging with {merge_mode} method") + log.info(f"start merging with {merge_mode} method") weight_matcher = WeightClass(thetas["model_a"], **kwargs) if re_basin: merged = rebasin_merge( @@ -177,7 +176,7 @@ def un_prune_model( precision: str, ) -> Dict: if prune: - # logging.info("Un-pruning merged model") + log.info("Un-pruning merged model") del thetas gc.collect() log_vram("remove thetas") @@ -432,7 +431,7 @@ def get_merge_method_args( def save_model(model, output_file, file_format) -> None: - # logging.info(f"Saving {output_file}") + log.info(f"Saving {output_file}") if file_format == "safetensors": safetensors.torch.save_file( model if type(model) == dict else model.to_dict(), From b65dfae35ad70e7989f4f1db2227c3fefca19d58 Mon Sep 17 00:00:00 2001 From: AI-Casanova <54461896+AI-Casanova@users.noreply.github.com> Date: Fri, 10 Nov 2023 07:21:24 -0600 Subject: [PATCH 07/84] Fix rebasin --- modules/extras.py | 2 +- modules/merging/merge.py | 9 +++------ 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/modules/extras.py b/modules/extras.py index 044fc74ba..b91010958 100644 --- a/modules/extras.py +++ b/modules/extras.py @@ -318,7 +318,7 @@ def run_MEHmodelmerger(id_task, **kwargs): # pylint: disable=unused-argument return fail(f"{e}") ckpt_dir = shared.opts.ckpt_dir or sd_models.model_path - filename = kwargs.get("custom_name", "Unamed_Merge") + filename = kwargs.get("custom_name", "Unnamed_Merge") filename += "." + kwargs.get("checkpoint_format", None) output_modelname = os.path.join(ckpt_dir, filename) shared.state.textinfo = "Saving" diff --git a/modules/merging/merge.py b/modules/merging/merge.py index 76c5b036d..6b00afe2b 100644 --- a/modules/merging/merge.py +++ b/modules/merging/merge.py @@ -135,7 +135,7 @@ def merge_models( threads: int = 1, **kwargs, ) -> Dict: - iterations = kwargs.get("iterations", 1) + iterations = kwargs.get("re_basin_iterations", 1) thetas = load_thetas(models, prune, device, precision) log.info(f"start merging with {merge_mode} method") @@ -190,7 +190,7 @@ def un_prune_model( merged.update({key: merged[key].half()}) del original_a gc.collect() - log_vram("remove original_a") + # log_vram("remove original_a") original_b = load_sd_model(models["model_b"], device) for key in tqdm(original_b.keys(), desc="un-prune model b"): if KEY_POSITION_IDS in key: @@ -266,12 +266,9 @@ def rebasin_merge( model_a = thetas["model_a"].clone() perm_spec = sdunet_permutation_spec() - print("Init rebasin iterations") for it in range(iterations): - print(f"Rebasin iteration {it}") - log_vram(f"{it} iteration start") + log_vram(f"Rebasin iteration {it}") weight_matcher.set_it(it) - log_vram("weights & bases, before simple merge") # normal block merge we already know and love thetas["model_a"] = simple_merge( From 39acd0af662c15950f55c57640f062be94a72830 Mon Sep 17 00:00:00 2001 From: AI-Casanova <54461896+AI-Casanova@users.noreply.github.com> Date: Fri, 10 Nov 2023 07:38:37 -0600 Subject: [PATCH 08/84] Add VAE bake --- modules/extras.py | 11 +++++++++++ modules/merging/rebasin.py | 3 ++- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/modules/extras.py b/modules/extras.py index b91010958..d5293f2f6 100644 --- a/modules/extras.py +++ b/modules/extras.py @@ -317,6 +317,17 @@ def run_MEHmodelmerger(id_task, **kwargs): # pylint: disable=unused-argument except Exception as e: return fail(f"{e}") + bake_in_vae_filename = sd_vae.vae_dict.get(kwargs.get("bake_in_vae", None), None) + if bake_in_vae_filename is not None: + shared.log.info(f"Model merge: baking in VAE: {bake_in_vae_filename}") + shared.state.textinfo = 'Baking in VAE' + vae_dict = sd_vae.load_vae_dict(bake_in_vae_filename) + for key in vae_dict.keys(): + theta_0_key = 'first_stage_model.' + key + if theta_0_key in theta_0: + theta_0[theta_0_key] = to_half(vae_dict[key], kwargs.get("precision", "fp16") == "fp16") + del vae_dict + ckpt_dir = shared.opts.ckpt_dir or sd_models.model_path filename = kwargs.get("custom_name", "Unnamed_Merge") filename += "." + kwargs.get("checkpoint_format", None) diff --git a/modules/merging/rebasin.py b/modules/merging/rebasin.py index a0ef80d49..26aac9964 100644 --- a/modules/merging/rebasin.py +++ b/modules/merging/rebasin.py @@ -4,6 +4,7 @@ from random import shuffle from typing import NamedTuple import torch from scipy.optimize import linear_sum_assignment +from modules.shared import log SPECIAL_KEYS = [ "first_stage_model.decoder.norm_out.weight", @@ -2227,7 +2228,7 @@ def inner_matching( if newL - oldL != 0: linear_sum += abs((newL - oldL).item()) number += 1 - logging.info(f" permutation {p}: {newL - oldL}") + log.info(f" permutation {p}: {newL - oldL}") progress = progress or newL > oldL + 1e-12 From a0b8bcf63bf75b510e3254e16b12eb5ab122a42a Mon Sep 17 00:00:00 2001 From: Vladimir Mandic Date: Mon, 13 Nov 2023 12:25:45 -0500 Subject: [PATCH 09/84] refactor model compile and add stable-fast --- CHANGELOG.md | 11 ++- cli/run-benchmark.py | 3 +- extensions-builtin/sd-webui-controlnet | 2 +- modules/sd_hijack.py | 4 +- modules/sd_models.py | 84 +++------------- modules/sd_models_compile.py | 130 +++++++++++++++++++++++++ modules/shared.py | 5 +- wiki | 2 +- 8 files changed, 163 insertions(+), 78 deletions(-) create mode 100644 modules/sd_models_compile.py diff --git a/CHANGELOG.md b/CHANGELOG.md index 96e95314d..11ec7cf84 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,6 @@ # Change Log for SD.Next -## Update for 2023-11-11 +## Update for 2023-11-13 - **Diffusers** - **LCM** support for any *SD 1.5* or *SD-XL* model! @@ -13,6 +13,10 @@ - set cfg to 1 or 2 - Add `cli/lcm-convert.py` script to convert any SD 1.5 or SD-XL model to LCM model by baking in LORA and uploading to Huggingface, thanks @Disty0 + - Support for [Stable Fast](https://github.com/chengzeyi/stable-fast) model compile on *Windows/Linux/WSL2* with *CUDA* + See [Wiki:Benchmark](https://github.com/vladmandic/automatic/wiki/Benchmark) for details and comparisment + of different backends, precision modes, advanced settings and compile modes + hint: **100+ it/s** on RTX4090 with no special tweaks - Add additional pipeline types for manual model loads when loading from `safetensors` - Updated logic for calculating **steps** when using base/hires/refiner workflows - Safe model offloading for non-standard models @@ -25,6 +29,7 @@ - **General**: - Reworked parser when pasting previously generated images/prompts includes all `txt2img`, `img2img` and `override` params + - Reworked **model compile** - Add refiner options to XYZ Grid - Support custom upscalers in subfolders - Support `--ckpt none` to skip loading a model @@ -35,8 +40,8 @@ - Fix img2img init image save - More uniform models paths - Safe scripts callback execution - - Improve extension compatibility - - Improve BF16 support + - Improved extension compatibility + - Improved BF16 support ## Update for 2023-11-06 diff --git a/cli/run-benchmark.py b/cli/run-benchmark.py index 340ba4cf8..ed02026d8 100755 --- a/cli/run-benchmark.py +++ b/cli/run-benchmark.py @@ -28,8 +28,7 @@ options = Map({ # batch = [1, 1, 2, 4, 8, 12, 16, 24, 32, 48, 64, 96, 128] -# batch = [1, 1, 2, 4, 8, 12, 16] -batch = [4, 4] +batch = [1, 1, 2, 4, 8, 12, 16] oom = 0 diff --git a/extensions-builtin/sd-webui-controlnet b/extensions-builtin/sd-webui-controlnet index 05ef0b1cd..c1f3d6f85 160000 --- a/extensions-builtin/sd-webui-controlnet +++ b/extensions-builtin/sd-webui-controlnet @@ -1 +1 @@ -Subproject commit 05ef0b1cd1374cf285dd8d5ccd7db9997549893c +Subproject commit c1f3d6f8505074d73b13eaf67f331bf869d7b940 diff --git a/modules/sd_hijack.py b/modules/sd_hijack.py index b07edb412..36c8846e1 100644 --- a/modules/sd_hijack.py +++ b/modules/sd_hijack.py @@ -178,7 +178,7 @@ class StableDiffusionModelHijack: except Exception as err: shared.log.warning(f"IPEX Optimize not supported: {err}") - if opts.cuda_compile and opts.cuda_compile_backend != 'none' and shared.backend == shared.Backend.ORIGINAL: + if (opts.cuda_compile or opts.cuda_compile_vae or opts.cuda_compile_upscaler) and shared.opts.cuda_compile_backend != 'none' and shared.backend == shared.Backend.ORIGINAL: try: import logging shared.log.info(f"Compiling pipeline={m.model.__class__.__name__} mode={opts.cuda_compile_backend}") @@ -199,6 +199,8 @@ class StableDiffusionModelHijack: hidet.torch.dynamo_config.use_tensor_core(True) hidet.torch.dynamo_config.search_space(2) m.model = torch.compile(m.model, mode=opts.cuda_compile_mode, backend=opts.cuda_compile_backend, fullgraph=opts.cuda_compile_fullgraph, dynamic=False) + from installer import setup_logging + setup_logging() shared.log.info("Model complilation done.") except Exception as err: shared.log.warning(f"Model compile not supported: {err}") diff --git a/modules/sd_models.py b/modules/sd_models.py index fbdfc1424..145c76766 100644 --- a/modules/sd_models.py +++ b/modules/sd_models.py @@ -20,8 +20,7 @@ import tomesd from transformers import logging as transformers_logging import ldm.modules.midas as midas from ldm.util import instantiate_from_config -from modules import paths, shared, shared_items, shared_state, modelloader, devices, script_callbacks, sd_vae, sd_disable_initialization, errors, hashes, sd_models_config -from modules.sd_hijack_inpainting import do_inpainting_hijack +from modules import paths, shared, shared_items, shared_state, modelloader, devices, script_callbacks, sd_vae, sd_disable_initialization, errors, hashes, sd_models_config, sd_models_compile, sd_hijack_inpainting from modules.timer import Timer from modules.memstats import memory_stats from modules.paths import models_path, script_path @@ -119,18 +118,6 @@ class CheckpointInfo: return self.shorthash -#Used by OpenVINO, can be used with TensorRT or Olive -class CompiledModelState: - def __init__(self): - self.first_pass = True - self.height = 512 - self.width = 512 - self.batch_size = 1 - self.partition_id = 0 - self.cn_model = [] - self.lora_model = [] - - class NoWatermark: def apply_watermark(self, img): return img @@ -594,7 +581,7 @@ model_data = ModelData() def change_backend(): shared.log.info(f'Backend changed: {shared.backend}') - shared.log.warning('Server restart required to apply all changes') + shared.log.warning('Full server restart required to apply all changes') if shared.backend == shared.Backend.ORIGINAL: change_from = shared.Backend.DIFFUSERS else: @@ -673,55 +660,6 @@ def detect_pipeline(f: str, op: str = 'model'): return pipeline, guess -def compile_diffusers(sd_model): - try: - if shared.opts.ipex_optimize: - import intel_extension_for_pytorch as ipex # pylint: disable=import-error, unused-import - sd_model.unet.training = False - sd_model.unet = ipex.optimize(sd_model.unet, dtype=devices.dtype_unet, inplace=True, weights_prepack=False) # pylint: disable=attribute-defined-outside-init - if hasattr(sd_model, 'vae'): - sd_model.vae.training = False - sd_model.vae = ipex.optimize(sd_model.vae, dtype=devices.dtype_vae, inplace=True, weights_prepack=False) # pylint: disable=attribute-defined-outside-init - if hasattr(sd_model, 'movq'): - sd_model.movq.training = False - sd_model.movq = ipex.optimize(sd_model.movq, dtype=devices.dtype_vae, inplace=True, weights_prepack=False) # pylint: disable=attribute-defined-outside-init - shared.log.info("Applied IPEX Optimize.") - except Exception as err: - shared.log.warning(f"IPEX Optimize not supported: {err}") - - try: - if (shared.opts.cuda_compile or shared.opts.cuda_compile_vae or shared.opts.cuda_compile_upscaler) and shared.opts.cuda_compile_backend != 'none': - shared.log.info(f"Compiling pipeline={sd_model.__class__.__name__} shape={8 * sd_model.unet.config.sample_size} mode={shared.opts.cuda_compile_backend}") - import torch._dynamo # pylint: disable=unused-import,redefined-outer-name - if shared.opts.cuda_compile_backend == "openvino_fx": - torch._dynamo.reset() # pylint: disable=protected-access - from modules.intel.openvino import openvino_fx, openvino_clear_caches # pylint: disable=unused-import - openvino_clear_caches() - torch._dynamo.eval_frame.check_if_dynamo_supported = lambda: True # pylint: disable=protected-access - if shared.compiled_model_state is None: - shared.compiled_model_state = CompiledModelState() - shared.compiled_model_state.first_pass = True if not shared.opts.cuda_compile_precompile else False - log_level = logging.WARNING if shared.opts.cuda_compile_verbose else logging.CRITICAL # pylint: disable=protected-access - if hasattr(torch, '_logging'): - torch._logging.set_logs(dynamo=log_level, aot=log_level, inductor=log_level) # pylint: disable=protected-access - torch._dynamo.config.verbose = shared.opts.cuda_compile_verbose # pylint: disable=protected-access - torch._dynamo.config.suppress_errors = shared.opts.cuda_compile_errors # pylint: disable=protected-access - if shared.opts.cuda_compile: - sd_model.unet = torch.compile(sd_model.unet, mode=shared.opts.cuda_compile_mode, backend=shared.opts.cuda_compile_backend, fullgraph=shared.opts.cuda_compile_fullgraph) # pylint: disable=attribute-defined-outside-init - if shared.opts.cuda_compile_vae: - if hasattr(sd_model, 'vae'): - sd_model.vae.decode = torch.compile(sd_model.vae.decode, mode=shared.opts.cuda_compile_mode, backend=shared.opts.cuda_compile_backend, fullgraph=shared.opts.cuda_compile_fullgraph) # pylint: disable=attribute-defined-outside-init - if hasattr(sd_model, 'movq'): - sd_model.movq.decode = torch.compile(sd_model.movq.decode, mode=shared.opts.cuda_compile_mode, backend=shared.opts.cuda_compile_backend, fullgraph=shared.opts.cuda_compile_fullgraph) # pylint: disable=attribute-defined-outside-init - from installer import setup_logging - setup_logging() - if shared.opts.cuda_compile_precompile: - sd_model("dummy prompt") - shared.log.info("Complilation done.") - except Exception as err: - shared.log.warning(f"Model compile not supported: {err}") - - def set_diffuser_options(sd_model, vae, op: str): if sd_model is None: shared.log.warning(f'{op} is not loaded') @@ -778,10 +716,8 @@ def set_diffuser_options(sd_model, vae, op: str): sd_model.vae = vae if shared.opts.diffusers_vae_upcast != 'default': if shared.opts.diffusers_vae_upcast == 'true': - # sd_model.vae.config["force_upcast"] = True sd_model.vae.config.force_upcast = True else: - # sd_model.vae.config["force_upcast"] = False sd_model.vae.config.force_upcast = False if shared.opts.no_half_vae: devices.dtype_vae = torch.float32 @@ -789,6 +725,18 @@ def set_diffuser_options(sd_model, vae, op: str): shared.log.debug(f'Setting {op} VAE: name={sd_vae.loaded_vae_file} upcast={sd_model.vae.config.get("force_upcast", None)}') if shared.opts.cross_attention_optimization == "xFormers" and hasattr(sd_model, 'enable_xformers_memory_efficient_attention'): sd_model.enable_xformers_memory_efficient_attention() + + if shared.opts.diffusers_eval: + if hasattr(sd_model, "unet"): + sd_model.unet.requires_grad_(False) + sd_model.unet.eval() + if hasattr(sd_model, "vae"): + sd_model.vae.requires_grad_(False) + sd_model.vae.eval() + if hasattr(sd_model, "text_encoder"): + sd_model.text_encoder.requires_grad_(False) + sd_model.text_encoder.eval() + if shared.opts.opt_channelslast and hasattr(sd_model, 'unet'): shared.log.debug(f'Setting {op}: enable channels last') sd_model.unet.to(memory_format=torch.channels_last) @@ -976,7 +924,7 @@ def load_diffuser(checkpoint_info=None, already_loaded_state_dict=None, timer=No elif not getattr(sd_model, 'has_accelerate', False): sd_model.to(devices.device) - compile_diffusers(sd_model) + sd_models_compile.compile_diffusers(sd_model) if sd_model is None: shared.log.error('Diffuser model not loaded') @@ -1106,7 +1054,7 @@ def load_model(checkpoint_info=None, already_loaded_state_dict=None, timer=None, current_checkpoint_info = model_data.sd_refiner.sd_checkpoint_info unload_model_weights(op=op) - do_inpainting_hijack() + sd_hijack_inpainting.do_inpainting_hijack() devices.set_cuda_params() if already_loaded_state_dict is not None: state_dict = already_loaded_state_dict diff --git a/modules/sd_models_compile.py b/modules/sd_models_compile.py new file mode 100644 index 000000000..b373f902e --- /dev/null +++ b/modules/sd_models_compile.py @@ -0,0 +1,130 @@ +import time +import logging +import torch +from modules import shared, devices +from installer import setup_logging + + +#Used by OpenVINO, can be used with TensorRT or Olive +class CompiledModelState: + def __init__(self): + self.first_pass = True + self.height = 512 + self.width = 512 + self.batch_size = 1 + self.partition_id = 0 + self.cn_model = [] + self.lora_model = [] + + +def optimize_ipex(sd_model): + try: + t0 = time.time() + import intel_extension_for_pytorch as ipex # pylint: disable=import-error, unused-import + sd_model.unet.training = False + sd_model.unet = ipex.optimize(sd_model.unet, dtype=devices.dtype_unet, inplace=True, weights_prepack=False) # pylint: disable=attribute-defined-outside-init + if hasattr(sd_model, 'vae'): + sd_model.vae.training = False + sd_model.vae = ipex.optimize(sd_model.vae, dtype=devices.dtype_vae, inplace=True, weights_prepack=False) # pylint: disable=attribute-defined-outside-init + if hasattr(sd_model, 'movq'): + sd_model.movq.training = False + sd_model.movq = ipex.optimize(sd_model.movq, dtype=devices.dtype_vae, inplace=True, weights_prepack=False) # pylint: disable=attribute-defined-outside-init + t1 = time.time() + shared.log.info(f"Model compile: mode=IPEX-optimize time={t1-t0:.2f}") + except Exception as e: + shared.log.warning(f"Model compile: task=IPEX-optimize error: {e}") + + +def optimize_openvino(): + try: + from modules.intel.openvino import openvino_fx, openvino_clear_caches # pylint: disable=unused-import + openvino_clear_caches() + torch._dynamo.eval_frame.check_if_dynamo_supported = lambda: True # pylint: disable=protected-access + if shared.compiled_model_state is None: + shared.compiled_model_state = CompiledModelState() + shared.compiled_model_state.first_pass = True if not shared.opts.cuda_compile_precompile else False + except Exception as e: + shared.log.warning(f"Model compile: task=OpenVINO: {e}") + + +def compile_stablefast(sd_model): + try: + import sfast.compilers.stable_diffusion_pipeline_compiler as sf + except Exception as e: + shared.log.warning(f'Model compile using stable-fast: {e}') + return sd_model + config = sf.CompilationConfig.Default() + try: + import xformers # pylint: disable=unused-import + config.enable_xformers = True + except Exception: + pass + try: + import triton # pylint: disable=unused-import + config.enable_triton = True + except Exception: + pass + import warnings + warnings.filterwarnings("ignore", category=torch.jit.TracerWarning) + config.enable_cuda_graph = shared.opts.cuda_compile_fullgraph + config.enable_jit_freeze = shared.opts.diffusers_eval + try: + t0 = time.time() + sd_model = sf.compile(sd_model, config) + setup_logging() # compile messes with logging so reset is needed + if shared.opts.cuda_compile_precompile: + sd_model("dummy prompt") + t1 = time.time() + shared.log.info(f"Model compile: task=Stable-fast config={config.__dict__} time={t1-t0:.2f}") + except Exception as e: + shared.log.info(f"Model compile: task=Stable-fast error: {e}") + return sd_model + + +def compile_torch(sd_model): + try: + import torch._dynamo # pylint: disable=unused-import,redefined-outer-name + torch._dynamo.reset() # pylint: disable=protected-access + if shared.opts.ipex_optimize: + optimize_ipex(sd_model) + if shared.opts.cuda_compile_backend == "openvino_fx": + optimize_openvino() + log_level = logging.WARNING if shared.opts.cuda_compile_verbose else logging.CRITICAL # pylint: disable=protected-access + if hasattr(torch, '_logging'): + torch._logging.set_logs(dynamo=log_level, aot=log_level, inductor=log_level) # pylint: disable=protected-access + torch._dynamo.config.verbose = shared.opts.cuda_compile_verbose # pylint: disable=protected-access + torch._dynamo.config.suppress_errors = shared.opts.cuda_compile_errors # pylint: disable=protected-access + t0 = time.time() + if shared.opts.cuda_compile: + sd_model.unet = torch.compile(sd_model.unet, mode=shared.opts.cuda_compile_mode, backend=shared.opts.cuda_compile_backend, fullgraph=shared.opts.cuda_compile_fullgraph) + if shared.opts.cuda_compile_vae: + if hasattr(sd_model, 'vae'): + sd_model.vae.decode = torch.compile(sd_model.vae.decode, mode=shared.opts.cuda_compile_mode, backend=shared.opts.cuda_compile_backend, fullgraph=shared.opts.cuda_compile_fullgraph) + if hasattr(sd_model, 'movq'): + sd_model.movq.decode = torch.compile(sd_model.movq.decode, mode=shared.opts.cuda_compile_mode, backend=shared.opts.cuda_compile_backend, fullgraph=shared.opts.cuda_compile_fullgraph) + setup_logging() # compile messes with logging so reset is needed + if shared.opts.cuda_compile_precompile: + sd_model("dummy prompt") + t1 = time.time() + shared.log.info(f"Model compile: time={t1-t0:.2f}") + except Exception as e: + shared.log.warning(f"Model compile error: {e}") + return sd_model + + +def compile_diffusers(sd_model): + if not (shared.opts.cuda_compile or shared.opts.cuda_compile_vae or shared.opts.cuda_compile_upscaler): + return + if not hasattr(sd_model, 'unet') or not hasattr(sd_model.unet, 'config'): + shared.log.warning('Model compile enabled but model has no Unet') + return + if shared.opts.cuda_compile_backend == 'none': + shared.log.warning('Model compile enabled but no backend specified') + return + size = 8*getattr(sd_model.unet.config, 'sample_size', 0) + shared.log.info(f"Model compile: pipeline={sd_model.__class__.__name__} shape={size} mode={shared.opts.cuda_compile_mode} backend={shared.opts.cuda_compile_backend} fullgraph={shared.opts.cuda_compile_fullgraph} unet={shared.opts.cuda_compile} vae={shared.opts.cuda_compile_vae} upscaler={shared.opts.cuda_compile_upscaler}") + if shared.opts.cuda_compile_backend == 'stable-fast': + sd_model = compile_stablefast(sd_model) + else: + sd_model = compile_torch(sd_model) + return sd_model diff --git a/modules/shared.py b/modules/shared.py index ba8c7c4ff..770466c54 100644 --- a/modules/shared.py +++ b/modules/shared.py @@ -288,10 +288,10 @@ options_templates.update(options_section(('cuda', "Compute Settings"), { "cuda_compile": OptionInfo(True if cmd_opts.use_openvino else False, "Compile UNet"), "cuda_compile_vae": OptionInfo(True if cmd_opts.use_openvino else False, "Compile VAE"), "cuda_compile_upscaler": OptionInfo(True if cmd_opts.use_openvino else False, "Compile upscaler"), - "cuda_compile_backend": OptionInfo("openvino_fx" if cmd_opts.use_openvino else "none", "Model compile backend", gr.Radio, {"choices": ['none', 'inductor', 'cudagraphs', 'aot_ts_nvfuser', 'hidet', 'ipex', 'openvino_fx']}), + "cuda_compile_backend": OptionInfo("openvino_fx" if cmd_opts.use_openvino else "none", "Model compile backend", gr.Radio, {"choices": ['none', 'inductor', 'cudagraphs', 'aot_ts_nvfuser', 'hidet', 'ipex', 'openvino_fx', 'stable-fast']}), "cuda_compile_mode": OptionInfo("default", "Model compile mode", gr.Radio, {"choices": ['default', 'reduce-overhead', 'max-autotune']}), "cuda_compile_fullgraph": OptionInfo(False, "Model compile fullgraph"), - "cuda_compile_precompile": OptionInfo(False, "Model compile precompile"), + "cuda_compile_precompile": OptionInfo(True, "Model compile precompile"), "cuda_compile_verbose": OptionInfo(False, "Model compile verbose mode"), "cuda_compile_errors": OptionInfo(True, "Model compile suppress errors"), @@ -348,6 +348,7 @@ options_templates.update(options_section(('diffusers', "Diffusers Settings"), { "diffusers_vae_load_variant": OptionInfo("default", "Diffusers VAE loading variant", gr.Radio, {"choices": ['default', 'fp32', 'fp16']}), "custom_diffusers_pipeline": OptionInfo('', 'Load custom Diffusers pipeline'), "diffusers_lora_loader": OptionInfo("diffusers" if cmd_opts.use_openvino else "sequential apply", "Diffusers LoRA loading variant", gr.Radio, {"choices": ['diffusers', 'sequential apply', 'merge and apply']}), + "diffusers_eval": OptionInfo(True, "Force model eval"), "diffusers_force_zeros": OptionInfo(True, "Force zeros for prompts when empty"), "diffusers_aesthetics_score": OptionInfo(False, "Require aesthetics score"), "diffusers_force_inpaint": OptionInfo(False, 'Diffusers force inpaint pipeline'), diff --git a/wiki b/wiki index c2267ae1f..7d0daac42 160000 --- a/wiki +++ b/wiki @@ -1 +1 @@ -Subproject commit c2267ae1f84489926b0c79cc82b416f30d7b93b0 +Subproject commit 7d0daac4212d97c9ecbf30a7b06fe77bc3cc5bab From 7d6ace5a4c62b3b388a5de4ff596f02a1f63efa5 Mon Sep 17 00:00:00 2001 From: Disty0 Date: Mon, 13 Nov 2023 20:29:49 +0300 Subject: [PATCH 10/84] Disable precompile for OpenVINO --- modules/shared.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/shared.py b/modules/shared.py index 770466c54..c571c299d 100644 --- a/modules/shared.py +++ b/modules/shared.py @@ -291,7 +291,7 @@ options_templates.update(options_section(('cuda', "Compute Settings"), { "cuda_compile_backend": OptionInfo("openvino_fx" if cmd_opts.use_openvino else "none", "Model compile backend", gr.Radio, {"choices": ['none', 'inductor', 'cudagraphs', 'aot_ts_nvfuser', 'hidet', 'ipex', 'openvino_fx', 'stable-fast']}), "cuda_compile_mode": OptionInfo("default", "Model compile mode", gr.Radio, {"choices": ['default', 'reduce-overhead', 'max-autotune']}), "cuda_compile_fullgraph": OptionInfo(False, "Model compile fullgraph"), - "cuda_compile_precompile": OptionInfo(True, "Model compile precompile"), + "cuda_compile_precompile": OptionInfo(False if cmd_opts.use_openvino else True, "Model compile precompile"), "cuda_compile_verbose": OptionInfo(False, "Model compile verbose mode"), "cuda_compile_errors": OptionInfo(True, "Model compile suppress errors"), From 35cd05b72184fe7369ec0ca080626139bd911c99 Mon Sep 17 00:00:00 2001 From: Vladimir Mandic Date: Mon, 13 Nov 2023 12:34:58 -0500 Subject: [PATCH 11/84] fix model compile --- modules/upscaler.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/upscaler.py b/modules/upscaler.py index 52c50ff45..4887ce1a7 100644 --- a/modules/upscaler.py +++ b/modules/upscaler.py @@ -230,7 +230,7 @@ def compile_upscaler(model, name=""): if modules.shared.opts.cuda_compile_backend == "openvino_fx": from modules.intel.openvino import openvino_fx, openvino_clear_caches # pylint: disable=unused-import - from modules.sd_models import CompiledModelState + from modules.sd_models_compile import CompiledModelState openvino_clear_caches() torch._dynamo.eval_frame.check_if_dynamo_supported = lambda: True # pylint: disable=protected-access From d6aefd046ced4a92479ec924214f3a0637f146ac Mon Sep 17 00:00:00 2001 From: Vladimir Mandic Date: Mon, 13 Nov 2023 16:20:21 -0500 Subject: [PATCH 12/84] reference match previews --- CHANGELOG.md | 1 + extensions-builtin/sd-webui-agent-scheduler | 2 +- html/reference.json | 10 +++++----- ...-i-m-v1.0.jpg => DeepFloyd--IF-I-M-v1.0.jpg} | Bin ...pg => PixArt-alpha--PixArt-XL-2-1024-MS.jpg} | Bin ...pg => PixArt-alpha--PixArt-XL-2-512x512.jpg} | Bin ...v7.jpg => SimianLuo--LCM_Dreamshaper_v7.jpg} | Bin .../Reference/deepfloyd--if-i-m-v1.0.thumb.jpg | Bin 36903 -> 0 bytes ...kandinsky-community--kandinsky-2-1.thumb.jpg | Bin 44063 -> 0 bytes .../pixart-alpha--pixart-xl-2-1024-ms.thumb.jpg | Bin 31193 -> 0 bytes ...{segmind--ssd-1b.jpg => segmind--SSD-1B.jpg} | Bin models/Reference/segmind--ssd-1b.thumb.jpg | Bin 43319 -> 0 bytes models/Reference/segmind--tiny-sd.thumb.jpg | Bin 29722 -> 0 bytes .../simianluo--lcm_dreamshaper_v7.thumb.jpg | Bin 27600 -> 0 bytes modules/modelloader.py | 2 ++ modules/sd_vae.py | 2 ++ modules/ui_extra_networks.py | 6 +++--- 17 files changed, 14 insertions(+), 9 deletions(-) rename models/Reference/{deepfloyd--if-i-m-v1.0.jpg => DeepFloyd--IF-I-M-v1.0.jpg} (100%) rename models/Reference/{pixart-alpha--pixart-xl-2-1024-ms.jpg => PixArt-alpha--PixArt-XL-2-1024-MS.jpg} (100%) rename models/Reference/{pixart-alpha--pixart-xl-2-512x512.jpg => PixArt-alpha--PixArt-XL-2-512x512.jpg} (100%) rename models/Reference/{simianluo--lcm_dreamshaper_v7.jpg => SimianLuo--LCM_Dreamshaper_v7.jpg} (100%) delete mode 100644 models/Reference/deepfloyd--if-i-m-v1.0.thumb.jpg delete mode 100644 models/Reference/kandinsky-community--kandinsky-2-1.thumb.jpg delete mode 100644 models/Reference/pixart-alpha--pixart-xl-2-1024-ms.thumb.jpg rename models/Reference/{segmind--ssd-1b.jpg => segmind--SSD-1B.jpg} (100%) delete mode 100644 models/Reference/segmind--ssd-1b.thumb.jpg delete mode 100644 models/Reference/segmind--tiny-sd.thumb.jpg delete mode 100644 models/Reference/simianluo--lcm_dreamshaper_v7.thumb.jpg diff --git a/CHANGELOG.md b/CHANGELOG.md index 11ec7cf84..b6a4bbb4b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -42,6 +42,7 @@ - Safe scripts callback execution - Improved extension compatibility - Improved BF16 support + - Match previews for reference models with downloaded models ## Update for 2023-11-06 diff --git a/extensions-builtin/sd-webui-agent-scheduler b/extensions-builtin/sd-webui-agent-scheduler index 8970f485b..b6965ad05 160000 --- a/extensions-builtin/sd-webui-agent-scheduler +++ b/extensions-builtin/sd-webui-agent-scheduler @@ -1 +1 @@ -Subproject commit 8970f485b767929cb36b5fee0df1d98840023f2a +Subproject commit b6965ad05d25b383468ea0289bd6d0e0a92aad82 diff --git a/html/reference.json b/html/reference.json index 86a3dab9f..d1b2884dc 100644 --- a/html/reference.json +++ b/html/reference.json @@ -17,7 +17,7 @@ "Segmind SSD-1B": { "path": "segmind/SSD-1B", "desc": "The Segmind Stable Diffusion Model (SSD-1B) offers a compact, efficient, and distilled version of the SDXL model. At 50% smaller and 60% faster than Stable Diffusion XL (SDXL), it provides quick and seamless performance without sacrificing image quality.", - "preview": "segmind--ssd-1b.jpg" + "preview": "segmind--SSD-1B.jpg" }, "Segmind Tiny": { "path": "segmind/tiny-sd", @@ -27,17 +27,17 @@ "LCM SD-1.5 Dreamshaper 7": { "path": "SimianLuo/LCM_Dreamshaper_v7", "desc": "Latent Consistencey Models enable swift inference with minimal steps on any pre-trained LDMs, including Stable Diffusion. By distilling classifier-free guidance into the model's input, LCM can generate high-quality images in very short inference time. LCM can generate quality images in as few as 3-4 steps, making it blazingly fast.", - "preview": "simianluo--lcm_dreamshaper_v7.jpg" + "preview": "SimianLuo--LCM_Dreamshaper_v7.jpg" }, "Pixart-α XL 2 Medium 512": { "path": "PixArt-alpha/PixArt-XL-2-512x512", "desc": "PixArt-α is a Transformer-based T2I diffusion model whose image generation quality is competitive with state-of-the-art image generators (e.g., Imagen, SDXL, and even Midjourney), and the training speed markedly surpasses existing large-scale T2I models. Extensive experiments demonstrate that PIXART-α excels in image quality, artistry, and semantic control. It can directly generate 512px images from text prompts within a single sampling process.", - "preview": "pixart-alpha--pixart-xl-2-512x512.jpg" + "preview": "PixArt-alpha--PixArt-XL-2-512x512.jpg" }, "Pixart-α XL 2 Large 1024": { "path": "PixArt-alpha/PixArt-XL-2-1024-MS", "desc": "PixArt-α is a Transformer-based T2I diffusion model whose image generation quality is competitive with state-of-the-art image generators (e.g., Imagen, SDXL, and even Midjourney), and the training speed markedly surpasses existing large-scale T2I models. Extensive experiments demonstrate that PIXART-α excels in image quality, artistry, and semantic control. It can directly generate 1024px images from text prompts within a single sampling process.", - "preview": "pixart-alpha--pixart-xl-2-1024-ms.jpg" + "preview": "PixArt-alpha--PixArt-XL-2-1024-MS.jpg" }, "Warp Wuerstchen": { "path": "warp-ai/wuerstchen", @@ -57,7 +57,7 @@ "DeepFloyd IF Medium": { "path": "DeepFloyd/IF-I-M-v1.0", "desc": "DeepFloyd-IF is a pixel-based text-to-image triple-cascaded diffusion model, that can generate pictures with new state-of-the-art for photorealism and language understanding. The result is a highly efficient model that outperforms current state-of-the-art models, achieving a zero-shot FID-30K score of 6.66 on the COCO dataset. It is modular and composed of frozen text mode and three pixel cascaded diffusion modules, each designed to generate images of increasing resolution: 64x64, 256x256, and 1024x1024.", - "preview": "deepfloyd--if-i-m-v1.0.jpg" + "preview": "DeepFloyd--IF-I-M-v1.0.jpg" }, "Tsinghua UniDiffuser": { "path": "thu-ml/unidiffuser-v1", diff --git a/models/Reference/deepfloyd--if-i-m-v1.0.jpg b/models/Reference/DeepFloyd--IF-I-M-v1.0.jpg similarity index 100% rename from models/Reference/deepfloyd--if-i-m-v1.0.jpg rename to models/Reference/DeepFloyd--IF-I-M-v1.0.jpg diff --git a/models/Reference/pixart-alpha--pixart-xl-2-1024-ms.jpg b/models/Reference/PixArt-alpha--PixArt-XL-2-1024-MS.jpg similarity index 100% rename from models/Reference/pixart-alpha--pixart-xl-2-1024-ms.jpg rename to models/Reference/PixArt-alpha--PixArt-XL-2-1024-MS.jpg diff --git a/models/Reference/pixart-alpha--pixart-xl-2-512x512.jpg b/models/Reference/PixArt-alpha--PixArt-XL-2-512x512.jpg similarity index 100% rename from models/Reference/pixart-alpha--pixart-xl-2-512x512.jpg rename to models/Reference/PixArt-alpha--PixArt-XL-2-512x512.jpg diff --git a/models/Reference/simianluo--lcm_dreamshaper_v7.jpg b/models/Reference/SimianLuo--LCM_Dreamshaper_v7.jpg similarity index 100% rename from models/Reference/simianluo--lcm_dreamshaper_v7.jpg rename to models/Reference/SimianLuo--LCM_Dreamshaper_v7.jpg diff --git a/models/Reference/deepfloyd--if-i-m-v1.0.thumb.jpg b/models/Reference/deepfloyd--if-i-m-v1.0.thumb.jpg deleted file mode 100644 index 4d1a9af95d84e0c5b985416d4949e6538413908d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 36903 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 diff --git a/models/Reference/kandinsky-community--kandinsky-2-1.thumb.jpg b/models/Reference/kandinsky-community--kandinsky-2-1.thumb.jpg deleted file mode 100644 index 29ec42651e229096f0bd9606c8cb565580a26e13..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 44063 zcmbSyWl&tf_vIvbAQ0RcEWrs7T!RiyaCdiypc5dtyF+k?;10pv-QC?`28QMLU#r?r zyL(@~Pu*DJs;FGk3lmy`2I{@I_+XHxA0f+)Vp`xLqefWg_5giNj z6E*=Y5dj_^0V~yKQd-_`0{lGRxVgSd>d1c=Qy1sr{$Z=Au5V;+VJ;}==;2`UQ^(ZY z_&Y;|Jh#u0Wgu@oxBIYy`u!Y$9xBe`R=tB0DRjg!n^-6 z!2hs!@8RGP5Rs5kKA^r$sQ(0b{|*lBJv4h#wo2@Q*jPe@EkPDxG6&C4$+EGjN3t*Nc6Z)j|4 zZt3pn?du;H92%aUnVp+oSX^4(+TPjS+dnuwI=;HTxxKr8czlBV2iLndod47QJFx!) z7v>wT_wev=@JRo`_3pj<+Y5&Yk3hkSh$XCuWax-Z$>xWQBNCfa-GxH+P3aQX$Z6^W z9yR;c=d1rf`!8hwcfkDrzmWYeVE-G}G5`(k-P_^8VFH8zdwWS=pUgkJNEQyfvrlaz zOElvK2+=1A)>AaDj21bbhU;cDu6FNAk^`>?d0yygeu59uUT{>RN#a?=32qe?@UB*3 zKJ$Rj(G~W@{r8l(b}&o7mYm3M*t8L>MOWx+LE#wWLVS^j80o6p@bV$PqYMJtnBSsP5BGj4%6~N*2*MpJE)&{c{+o zIL3E2Jur}-{fL>*wFi4thlJ@JzHA}HbwZlqyv);#HEVpfNA3u5_>1LLkp=q`na{D$ z&j*^v7{r)+wY@KizCd<~9BUot@r2F=Ew^vL7&soU082+m7@1W3zT|hZ;-%a{=0We2 zfsGsNW4a?->{mcpqSWn|{Ad-1>(SpBI%eg;HO)XbEbv9V9PQs$y7s(cXep?8jMd0M z;e4t+v;s(pv;UP9yyi=nA2i5}eCt{?7&tmCMh?B-^BItaSDSdyN1Dt~^%pb0_$BZS z#z8LQ;d>pu2ckz!h%Bbs+jw+VY_F|aGkgWS$1P+(99(TpJ_L8iEU$tdK2v*gkCFI| zny|$B-WrqT=ABH1+;fxa+%YDxbkyd3I4xQ4Bom2sCcTD{Koi%XKoH(Y0~ z%J$j&O&SuB9`bl_%FvWB)^s8ulJ(N>_h|`CRL2JwRZOa`#G@bNETrsR!hFRYz%9-y zI)))XHGB|gh(EHXZ|S#H`jk{S1fPrKos7wZbRMMpvUh$pDfxS@_Oy|^b4agf2X$xt zS0c)?r;bx`Lo)mbJgEOb%Pba~N{pNjP5aw$*y)wwij%8bb}gYKq};{6n%XozcZ(}U z%}~QO6|{wYRfM2+8YU3PaUZmVwL7!@?q~l#J75dVIK%wpUnvx=(#?SOBCO>K(3I*A zx6)j|60F0l>V=`@-H6YstAwMU;xC}^CGGT=5jPTaLK)fAeTB#XvP11dKdNO_vi8L^ zelm-8&)%R#!s@#Tf9Ixu(6uplm+`r^i>1g?l9p#S9j3`QG3FlE0!YhO*a$8xX8EMe!i5JZ;a;E+xG3NUn(iN#1w^(K&oz}QLc<<6HzoH=%8H)CQ=$GAT}pHzNYM2}Wy zKTJ2SFS6}gYLZpUWbdi!a%Og#v?$n|zkEbT#u;WA@9Z{@CP3&DvvT9pC?lMm+YjRpF87bW{K@w*b;svtWmTR6Z`(3 zti*{-9)Z?LUo8>E@ntzggJLOfK6X8Sq|&m&LgbQ>DPzw;ETI_d@qZ}R(ZUz=(2?FmT_z2g4ZxKp$ee~cQ_Yr zYOr(hGhK&wh|tdtD@c{1Qhx}-Kl^rK3|F2aMA4}PC`(sKEYrarI!5s^9T6cmw5F=_ zak`dtGCdJA9)VP~jFdJ555@OD3;?pU!eo#t+6VKPMhcc2zoT2cbhGd2@0^s7lpdDdU3r|EA5hT3!K% zswQhC(8Yd7SZ@4sisD_K$xrL zruYvNn`~h*ho{Iu(P&{+Gr7qTFY|QnCrVPO5`X$VgH5n+Ik(F9&pySxl(W=w4sIf? zSf%s0=O7Zr@>I9gf!VpkZ8irKxMos?M@3ts*oLl~k+pUPE$+OA5d4X;Nn^(T5+)Rz z5__vthtO(I16Pi3ZE6*}J-}tV=u3>2POa+H><35YB?9LtH;iK|3-;6)n+RKK)4y*4 z-H&WTI&|(gyA94~CRwjmXNrw7Jv^#{HUXqtToT4op{a_v^{-Ed9>$N^N4hwAWD-8- z?#6{6xXaSz#L8?dn9gwBnP) z$q@x(ce?=ZGd7IPOpoV}6m^^tTmv3f;I;@2Rj8=bNJ1K4KEL4t(jgdfdqHr{q;bOG zf2O*fY>cs)U`KfS3b<1`!MnFD(vdX6YotH{_$&zqLzLsj35i{h4Vo`74>zQ3Pgtia zr}e;Y(($L@lyaKSG(X!Tu^iV3-!C%>xa$a-3Uy;}kjOEfi??YD!@k1W1?RhEl5WnU z=1y)@ci?M5yGxbot+&8z&m+m9nt)Yp%Tw<UF*7y7jR=@s|Ube`UP6 zK_Al&)O4dtRaxbn;NqsrA`vE z6>y@|W48dBXt9ln3TVE6Uml)X37%qK>}B!0X_Oa`%8yx8u>V;7et&aS2RuRhG_WIi z->Sl~^Yp<(13OtrU)rE4XoAiPb@(S+><#uQpCV~~9QNmtGo;Kv*S>|tv4#%%BejhH zNR-01m3t^QOt5Hm;PKObdH}^WQxK9v+q*mVu)n=~IKigSvnjRGc}zp9%jOzehwmP;AKEHCmqL4lW^NN3JmXY=G!Ss&iS-$QiFoLV2z@dn*iMFYgg4$=bJX z+k_Do#z(hP&`bg^D-P>^#)|5Uvhc;%i&H1JFokXMq_$J(34N0*v+Eo4iQwnMh(jU1 zEV#CtSgRXYNbCF>x}_vu@1HGlz@a1uR!slR+AWY&cy+E?uxM4V?b@i&s~nL`Qx1S4 z= zDYUJY;j!0|%I@ihv~)HuZ9CDDhPxkd{tHx#sjyafuoox(K!}qs2A*9%SQgKlGzxDr zA;>gSa16rfvBoKK!4`uJ?6KP#uuX~6-id~ZG${0D*)SbTfDS;#*b-(Twl{>}rT7>y zk+ZzuS?~8~$AJS?*ciF~t#v`H&o{Xnvv3A>P0~xcRW(Mi`HGG+9KptPPTcbSM)Y0T zp*X9ojWb#h=dE3$oq&V|OS0lq=*!j^6M@waRQL$wv9^x(Qc>!VE<0s#e#o2KIhoIC zterJpL#4A9?ZTDN<_p&;CNlxA+8>EVHV~P71jIkYa-O>D5%^e6tx5s0s?s|0Dk$0T zHc!FlJOjJn{&JsGW zCD!h**dP}nKD@Kd-b9BJLqG+VxkMuUaV zWGoFs;dpL}1T?Pk8qT&Qalkkglb+B84jbvP$>~gn>U+-Id8Sjg-AxkZCw1ifj0OxL zkIsMYC4?bpJ8{|c2d!kcD;%rPe#gkNV#aT|7Yo5d^^k{C@BC;S$R1DoLvHTV9&v^((w|%4j<%2Cw3=UV?fzUw#@-Y;f7};?wpfx`TY$gW6IRcNtywS_=JH8a0sgY;aX#Tb=^<6qh_798VAoTX zr*19|?mad)sZn|mP*m-TwYb^z54}$1VLeBUbdzZpDe{R1?=Z$`YmJ7vAz^&#_D2g@)h9n3Xm?^X02JaG@{5&Wm!DLs4$e1#>Hx$Jfm%m5jJNWJJ9dI z^}s|AI8pstY1V2K7+IfoiGz`PVnr~|AaKpOEwL?Upp%?Ar1xzG_hQJxLvb!Kzcp%& zzs%y^90n26GGQ@!s=Z!Iezxj$tM0i0rnbw8^Jn6?awN80TA7T}0f)H0pYZO;at z>zsqE{I_?;6AYd31La4QQv7L?AR_Y(EeD@s>>AWhq=V?OYec5mpii+;#iC zOgkWLsgglNTA3DxqE||uEkjXjlE`;jfj49LP33xAoIeaGIeMZ}x4`sL91KUl0Ocr) z=&Xv%OG8wq>Q;~g+zNvR%whg%(qP$JniFZIz36Ww#-pbZW{pkh`!Baegqzr^upt)W z2ntYnP&?Z?%e_;|k}(4EI~)hrg$0ftUCR^d;E~ZhA&=Ep0HZp`hxPR{Dy^7%yU}q; zV;Z*cKc3_z-Y1embE55??NkPeUs4%G-Qx-bL{+RwM9V0F_X!IU#S@PG+uJ+zwT#wB z1O>Vrz~t1FnQlX0sV%C-?KDxcMtYFhD%;RcVG4CFhJUKnh>slqB`;nMk!9mp{Scl0dKXO`52?9O zlK0$?V9IbcitBd-KX#sH)tEF9mfKT-Pred8t5ZxPXTHxjrONWi-WUc93HC4kqeM&J z*YgAqo#=91^$63+>dhF!@eaul1()?ZP?rO)7 zQYxwYv4+;aDRsC?WTfC|ChPR&5n6^8Aij)SY2y<#p(rvxO&u_kgDY_$(^d;?eVTzr z4wjCfDNF4i%@BJ)o=mHsh+2_CzS>MA7O$kL7kUC=?R=HFwc5DGv&+CZ)3~qpZJn`Y zl9#L3{_Dzz=rd15&HEOR(k&B>w^KxYE-YF5X&HYISksZ0#&J}v>pBT)2mzPZ#rpgk zEPf6byli^@$VxF=5k-|*eUz4>XO;IZQTsSIS_Q}=c{=M|-CTkc`^t$ard@-y{#$#d6iSM z;)C)ZpfE@vDQB2-dX^3Nm1X4>fK&0X3sI}6qpd!RiPp6_GrT36t?J0`y#~;6@t223ePxN{^sgu>D!F&9e_y_f(h50-;WP*~V ztcuxsO{bWiX#4Tfas{6CRrEPmgY8+ho$!t-Bi!Y2^zPL=<2b9K#>ih30QRf*Xzm;& z4V$}VyxI41W(hfEbVFP@sCJFsF(X;ONlG9Pr3)!xO$o;dsOZM3SD4w;j^0c^@6H<; zem_8o7Z9Z9cnB^~it|cXP%11csu=Z(BCNg^s;Y)11{4dvV4aMT1k&$Jb#1~prt>$G z)O9PKEsq7n4Xk6IIFmC>O~P-eaw?97N@#0l?eWwZ7qVOADdbT|j}ul@G6SLl*6YZX zapS}S9%|jl5=AahnR}n2*8rXiGv9i}-T9jM>Cu{VyD>jcWV5_1doSJzl=f(!Mu2AT zjE^l%N3BVu1wGImpG$3L%VK0FT%CGv$8{hW(#0w=f?z*BPpDeMAOGn^k-V&f**QK9 zVfdXeIcvkBKOqsjAcCGj56WbvSlb4zz6ayI_A!g)(iPFqGg05W15PyWlQ4>P2~D7> zLp1FlE&s%ye^aRb7VqrXYn)}pSF$^6C&pO@t=swzb9L5eUf=Ft_^sbDm$5*m@ zKW}Jtww39Fx@SB#Vpb~!1IL6r47WJ1A#QJ^K{s06E@8#XsF(Dus5$E%HUy`W(IBW1 ztSrZH{&B_7pr*l}ivQ7+bV8wLJ}bm-QTiAQ7aF?*3@vqFUrzj&=1U=Z{pU!=%OegK zWtn@h{CMt%7LiiH1d|+qDIeIL9{v5_hiZZvRVt{k3fN^U_@+`N0`r>Ee4#?qzuzND zQ6u_Zsja1L#yuh0C@umw2fJ#<75S_XZd?<4POHwIy;WEG8%KUP+Cb*W;N=QuK*{-*r&Ot9Ip6)?zf6?pInJD)$gNp%L zvYmd}^<1oo*fZYIZ|3)ztV}Vzrj4KNEfay5{B2P71l|)wPv>p?jI0~Wwp3AeM=%m^ z#hAL!9xhNbe~Tw=UYzvJQq&G#{Dkj*s0&S}{r#>mhV~C)kNYu_a(_@g`7QbMxukIHoVn92Bvk+%3Nww7wO1C z?b*M9J`pM3o(eIlEZ#6H`vqyngvxEl_4|J+Cp73C^)gv|5D z#|rL_I=drvKF-gK)xwu7f(bXDO0Snc0ziA{6ShZ z4j)C-*KNbJ0v@PZ)7n4#Nwwc>h)rqA55@#INfp)Yaafx^g~xo{<5cn*(1$X7Y;jAA z5j zShz<`#b2M&h^~)?p+|+wJ{oVi4kzCqmYPbCQ?TW8i&|t0ibrECHO(W5!Msz=p*_Ob zY}l|kIYUueULIVK{=l=f7OLaJB;(PlF}h%0=a!0ixt{qLPSUk!k#y_(F-+oLsYq8e zXbf3-9RoU)(;T)9gMuQ|igUylUnlQyjWw(Bmw%)xk0)U!P9P*VL1vhCu;_<>OT7`B z;2o_bw5>2KUF2g4WC-NNidJQ}IJGNGXDEZIqv&HR@^0Mz!qS50ynn1q>$bLb)z1}U zUsY=je*$JQz7!M*9`w8j9|k-*%6a2`4Y~S(2V$h_s{C+UT`~q~NVv=VVIK`tyw+3F zZ{emix1a7QqVH=PQ++3u@=KX=J(&)adHbkA_28!TJk4k3z2B+1030wO+gOx{;Qpr9 zS4tFIO}n3K5ZO1Dmjip&nM?L6Gu+d|V8vK7BTj&E5b5-g_%SO<&b};tI>1RIfc|85 zJD;gXSOZMurH#DPH>kpYCkF-z9Cstq(de6kpxUXvE*DZ zR3B>Xd0J=cI zcaa)cU5+7D#wszlHr^HDtqA|5%!{MoR&=6#gUWPQlD7{~$)SxXlP^AWcDK#By-9t8 zdJ-6;ouccRmc@*n&FwmWcg7S09;2`6o>*?gU1rVe1m&)us_z}X^$Ao^Hrdx%&e-@i zAr`gPCQYG*_>qGg1-TK5s6;`RdSp$ zt3bAC*{mic>*%Y(FZslHkPPa3EZSY=-I>wQ1I^Kzs)yuaNSJz)4KLq|$Vd?7HtQ_+ zuIiwxt>DFOQ)I5QX1Eu%EL9tb`*5fDjh82^tgMxotkAT1vp_1?p>Vomel|bs8)Kw^ zZ)MC6qWt9B7CXv^J-Fd$?nxEtQonzJQMe5sRVU7n3!lDjTVyw{bd@BiG$OcIQ3=l( z{}2$D*&m4NtS~|)Fd5MrM}kI2Pp8?|!$Xs!qwoJ(h@_ei*di zATg~>iLRvQs%cK_^k8|uw(L*z8*Ewr_3?TOR7R#SUC~9KyV*GU;!*BeEgAJPK^66T z)`EC~x|xRbL|#$nXtOt>IFr{{psd6XZ+Vpth8eGu{X00D`QQKzQ800C?B z{(QLX6KmG#fKY1bzDSyXj({-SU0G5nG{x^2uk8+RS>i^gYypN`x>A|`603xL&GV42 z5jK9d6v$^k2x_;<;}c2^xA?V^9D?Zd=X&v6fKG*ydGHt9q;e&(RYnG7L}O>Yun}R* z@QX$qf;oF~OSrmYE6tBEx4;os_RIX}R2;LA#~}gFv?3p;`^!-5j7FN}`e^!^FJtYf zSp6qAJ>$GNhgP(jgc95m+yf5^1p<}d!+4NJ%ile-$|mB7Glu*$Y`r2q;n9>4$!jP; zJ>(SJ6g(<_QHX?7jJU-FUg37S5+toQpT8@Yv;AO^JU~J~;46`V-%+u;Hjx%D+iMz9 zl{zI|Eu`hAgWAOW?K(RlTRK91!@wMl4|qWKYtEw5J1cx&S$(ObUo1#+yL6JDD`{s$(COW9c1QM(447t^T2FPdYMZWdx1;YPh4)B$YP2d6 zuF)c1bpm?jW2svlvGz8`s%JaFwdvbhfloMjfA^XbJ;yi>k^&waBb&}7t8EGGGOcd3 z7_BB2Xez|n&IuG}Z_boQX3L^xn4X7v{_c8jY^hVYTAC!b!hR_oF~kcZiT^9c^!*_q z#a*UFNmg!y{DA+F;j8j>RlV@f6O(exP$QXdWcg_=(;mLYE|Lq3ASW+1gwaSx2W%cQ z{sr_e>fV`Ar|dS(u*~tjn_g zg2DB6%PD(+>)@&AJK%h^t?Y__vU2tXhmBVEnp?C}g^sKIqBmdqr|;h~PJIVzeL$X_ z$R;+iE5{hqC0d!`)z`xk4j_f@O2&|;&mE#070&Dqs;wqkeN`)rZHxUT5$4ByVY_6= z)Xr_Vj?XeZ7*~}C;AHZNHT%J^{rWPE3cCm!#DS-nTcJR&CZgw)IPJXA3RJJb!6cb7 zm63NI_9xFG=|oyq$lggxUIR2pH)XMPk}RhVUJs=UX(D4#s1y$O0loEg+x5Ejt`?G5vCiC|QhUQbX&fJ#IU$f30Z4{w#wwwU(?Tdqyf zoe#mYN?JA;x?|-v0}XqEQ%II7Ceg*Px+U`XVJ5rnec*X^8w35u*@rCGh;osa-3iJ{ z;SzBwqhl(xJeZaQXLhe@iB3|g9*>dSn!z%x(B&FiaZX>mtKl*kNS(U(g>S4h-t(x;J+qi)B$`N5x>4v=P! zr0SCXB#upBX!SW==?)<(kdyt{{p1@|b0>gudXXR3EfH878_-o5w@#Ui*##W_gy)oD z8VyVo-ByVst?jwy0(9EKV_>81$PhwTXL=rqX#!{7V?e_TG2ISQKp(_9xN+7!^bc=JQX7;NO; zLt%3KAtOMBtT2v6<}r-xVJ3{Z!O*VQ+fe}@QWmEUtz@Ia%@~G{DdvHWs2iznB?eUvr%Az-(kAzyKh~DUmw9*wYfw4S_F%`B~;ncn}sjC?y8YT zG>dbCI8BAX7P^1C>IL}jW)8TO+iW1p1LB0RGIJpauicLQAZ%d1F2$@^prwzB_oaWU z&q2M&QkS?}Y9KM*oKTIQL)^oF*;ehd4Zv9`GKk+{-OTW<8v3}YxvtP?@M|H)$eJ;sT9ZmUz z#cl0@_AM%7hi1A0J=OZgDtIZ$T)z48Q1(JlR{k?F~ ztk53WHMf_*IUSh9`|e>lYt{Rqj8MAwj~g312ZlpT-dssml4xx+Jv3=?V34{ zWDZ>IXV!r~9n7j2oWoI3t>-HaEiXdmu`i7 zmi^Tls%2e$pLMF1D?5*>bk@cPSltMS=`65Zc>=x5RG9fvL+LLj#Hj#H;mCo@_x5AU z{)0Qh?$)iPF%y}C6uAReDOqOGtxC_X{HrnPwCpD)&pZ`xfPh>l@t*?nuqV}IBSlRDmz^)B4Ug+srqm!dC7rB685xn zgnBz)tfnJYKaaMM%&|OQxv}NXROTq%U+mMKW%j%^5c~kS6Agv-XiL4^K?_@KJ*T<- z*S?dgKCR)yd(HEF*^`W;y)cH03$S^k(I+d5+vCj4ql9KZA9$I1%^#j^&BB1z6L+EQjHD3kiu%!9(cQ9t zCBLJ=i$bxMVp-dEerWf*cs`c#itEdDFiLP7g!$&Jm+~*DrD_ktX7DXzp4XS|o-H>l zHRDIo&Bb6Wtkhsd5S#Gu67E>l#o`~Rz_N248E{qQO1I$Dh_9>0bW;k(zPsY-Ps9BR z$Z~o&^DLN1&H4FiKhXL&HSZ32)WC_xY{du923z^x$45Avd|y1eZA{Z6D>G02R7bkp zU5}v9K*t}qybQeV$5a{_Y_jA!;eGaD7q0-ly0eOVa-X)6C*kvfqCGuM27LOC<0-O4 zerii*%j1y-%vgrjH-Dl30^U=7mYgam_c}*|kArgz7!bkGnreuUXmgHW_Dzi5_OGY%W%3^scs`H6ZExY7aig8nkeGAik-v~132u)AK8cCwDQUcl z5Qe?-Om}I8-A%-o(ze(c3e5QMb(Lumd@p;6$?^O74o<*Ik^}2H-(6}~r{95?0BI4T z9NU(_MP!X1T=sAE45FHA%b_7mjsn;b0K=&y8*;5Ck!M-ci0lx9b-;lx4a%uDc`*$p z!F%@JE<%Y;ioGY8aw`$KLT&Zc1#5|}jEKNJuU&f^-CX7 z>1zb?@!{1bvozLN@16oB%SoNktx#g!->+g$M$OfGFsm|Hn3DFlx7j#HkUete^8MU_ zmOb6b-7FDXGhdxd&ieoC43&h0ZAr5&rFEG2Er5s7kvw(sC6UBQ5fFd=I#FalnPvWd zq4H!nE5*r8CR^hm^jpn5G^HZ|d`Q6qnd`$~^q1mRd{C=xQ~3HUdGW*LI?88^R{ln> zfIGudJCf7rz9Qj*5SD0#S|%V|b8z}VRuqxe$XG_LXBlb!`xP)E`7|)=R*H3WzW{Q< z3bb2^zN;#$Z{Tm;a9S}+*OehJzNR1DjH1<2YnR+|9-tp=#U zr@7_7bG(;{8V}x^xXs-%z?89V0yWVc2Pbm;Xitbza$(^rCQ)5T{xKuZ{7JWKX+X!v z@<=eTm{zHq26mdEG!>Eal1b@*?~J6pq;Oj#W+JiVNT}pVq8iHnBU_-Yh^*B42it1b zjf_Jds6xiOrMk*XOgm02gbd%!{k@mhy!guqdqneaqv&k5XJTbd>%Qvda~>pZB+ckt z+mZT#<6zt_zj8t%1DDpL8iVQ3YUR0s9^;BjC{Rgxf`7k4=M#CT=RsO>3-ecrK^0?u z6EC7vq>;?P;6@G{>)3?=1tf!>_<*Tu7!E6CH?MnOM{|j>t8&76@GMaf8zRao$cCt< z213Xh9K68n|or8lz))#u&uYxKm_ulht zVdi4gQFW@J&#Z@l6~T;}79 zB)Txb9moa~=wp@$muEb#yT{gO&#!1jZAK<-FB3fOqA)Rea$>6~`S<2aRCRf`DwvH; zHqoV7H=}mRg6j2D!laB0Th`K}@4=9{A62{xqW&F((t3p)qh6WbcP6R6r&pIfCnt&{ z6fT&@tSEUxZu=C^eb%E_y?*8jY%7K51p)*0JT`AtmL#^P*r7?X;Ae2A=cj?bvLO=e zu3Y1}j2cLJbq7;7&gdAO*asyeBhX>SN*X z8qvV*Q4H#l{)^+>mNL#*`@@6^>8MZk55Mjn5Hr-Ia+Fy=(sHkJuL`^zYc8ug1&>5} z?lhM}!zVs>sNd)}czzhyXqMSjaCsgK(~sx*PiPT~*@Xm?aecCJ{)r1@K?F^NYgb|}=gRwh3e z(I|@qX+qK)Jt%ob5N=}6F#=K>@4a1Vi6*Sz{-cqzm>1vYT-LDEr&Z*eAL~!0uU9{I z;#8OB$7=PXyZHT?s{p8TzOkxuyY_cm4Wog>HyzX7oFRr%Nu;v(;+~HLR(sd{!xK5I zKEf(3#C-L7tr$WDA`AE9oO;V`NVAb6azQ*=e80XL+Vmv4{v!`o{*lUI(CTdK*3Pmx z=2=pkHkepBHD#XH`%_3!r84GE-?MPcB~66mV_0P6^1N(&{=EH$IXxIoz2f3e zt8QzuBT0k<_=CGFhlEXx6q=?IO@lx*cVQP#J)!J~jqk1PoYn6Ag_&%_YTw-UG3&8F zX&yZi7AP`$1)>7Mkp(+b%Gj;sCKr18eB_lfCb} z)?kmqsGm&8ax=TT`%nU2D5o96*(T)=Qvx% zFY*0zioU6;E^NRibcI`CY5tw99H51#j>^v$kJ{=l)H0_nnWC$avb$RZ50ozZWGi?T z+d11QdbV<1z~SnGa?2;f6Fxw)b3wPfp|t`+{}bKcEXTQHX!{&Q;COP*AjQ1C{sV<3 z3d2nQsuHC~`RCxG0rGMW`K+MEKs*iIGtG1+{MBmVkAvmx4AP26qTLL+_|qR*L((-( zn-6!TB?l|nOu^|uQ<~UYj`~w8I&u&JgN}3ld^K03EfZzF0wt%R4W$2>sI9X03!!wj zs7gVNDX=wWXYxiw&iVb;4%^r2F;$*xXw9NhSW>k~M4ZURhQ4pzT?z{{@=3+khfL7* zCoDIQ3vVKOqjOWTTnEed&}ryAobecGwGbtt0igJ}U$%|6r@FBg3acBcoJOE8g~MDl z2kt1BNaIgo%Q;n7>8IS5N4jL6GHegTW4<{VwZOWMv~0NKS>*%SuzIB{Z0&)Z^*=G+ zQU(EJclAU{33D-W-Ix}8y~;f-TYoa%O0gu2*^{&G*a*h=gM`E|&z|e-KC7S9aok}m zEo&?8{t9jNW^{%bwh_DT{`PG`YaDlY{Nbrb)RDm9?qi_p*1~1!v{tY(HHfNNFYlOs zuRpEBFm5s>AL&sZ84^}GBLj!gAkx(;hffHZ_BH)VN&D5FaluOP@fFb0LmAvrn++3W z`p{TzR>&2@@-+1YxUO8?N#r7Ba+Wck3cK|R-lz8=7|g*#10}oi(@b3>$T_|jX}*yy zTM9QJ`fDT(XGiFmkvMRqnHKS6{}~b2vGqR{WTO3E84IeikEHv<&cmiQ=6lbzsuN7N zB_HT<`UuCV$sw4cSd%qn0~my4sklbm4?as<`er_z97<-4#zYHm$d}|l1UY3gG>9Y=mZRZY$k&TQ;T|8_W1J##Br0 zlAEV&BntVJeOlqe{M^<>JudC}CXSa43+hgF){=mElV~#xp2Rh7X|1To3~@%T_{dQi z4KbA0*?hoDf_DYqoQWg0#YkL_y2$QCP-YFO*Y@9yOJF<_HR8kw)QHuf@p}tkRS`3e9uT=cpRGp!bEBFJOI*tXsVT8|+$nE7TbhLE zYvFE=B7*YJUjaKJGfu0XNrrQu>zc0D9*U3zQhlu5h|@h9f`9yuh!zoubeO8G(*_Ef z@cXFMGgZC+R~->oMA0r#BF)KGBCMjWor!QCYwMDqKsaEvdnbf3@`(xg2GP?vRu{M7 z54>g2vce_n;4{W;+2sV2v{hsz!o-Cm#)W4yQKd>ba%sCU(K=5HJ>9)&g^(&FVTZQOiv%pJm1ZJ4 zMm;L2{}nDT=?)lBZTjY+B3pO^uvJWcY=6>gkE` zPxW*c`oYEmQ=Tu&@}=aniAQ|$x8~pq{zzKMJ=*tMzY_6pIYv9OOk$FosN?G7bG?qGB46~^)Ogk54zBSrgz+Bpbgq_Kt z6l|^$n{PW*7Ntm4OEtb~I^-4L{T>Dk6vCDon?4#OUy^h9535+AEs z$Dn^qb&#~Z4CY8<24azIs%H(zl>$iOaPx%$XgjM@`V@ZLHtka$eHSwFh^bSV5L+5& zwlv@wq#ohm;8VtGf)$ZW0W$htLS$;di39JZCnuA;_va~&$sYa}(n*@c@;k-`j5k zHXrO~tMbO_7?DeGOS^R;fh2Q~d|hkO1kN7N1uU#UQ{FDo)E2W?g5ie@R&!z;J3Q?6P*1GD-8d+Udlc`Y(k& z7)LlVTQ#GnY0B*K?fLH z2NmX@`4zJd`QoOYHJecA5>qY26RRgV9J$CqVq}ia2>O+b|Ted z0*B0FIq>?dCKav7P&Vu6o2YuA73*M^jje8_BZ+Sm>>__pAY91=c`J@F77Yeab8#+{|z8P-@ZSe2Bnp9 zL2Dd%^Y5+D{{VJ2X&e6l9T@#;c&;r#+P60@J$!}7>eT|;6vow8_QnlQZetslb4I}Q zDl0i^YZmTIrJI|3*pI5phBN&~>sAG|?2G0Y8d5vP>VK6H^PI@6HtruNAdk|cQv_G4 z#vhdMMo;Hhv#nh#rYkeA%W(vQ+Egd?sDc5Oic=Z?0A;wX6_KI25wz#YlkRUh$F(v@ zq7pL5f+hzAm!LoGFQ>SuxvX8tg!0D+`a+i&`G_2W>*z&GY_V=J1DK^8XP`9-q_E0k z0~};0QT1O?eJUAZ-wMlbkdM>@_ZWJAo`#i*HCbG;hGl0X2+h(#{nPF}Y6!@RP|1~C z;g`A^hTikck8>vVI1@xV=ljd=S6U%FB3PfyIN|Zbk3;S%8n)w$OGZJcz*1zpLC$dC z5A)Wch?wp|00?eWDTQts3-TM?*Y-r_|sCh zjPq;Z*T)TwFS10e%%}lllkRC&Frc4uY0yjNDbKGJE;+?%?4v(=Cli#mWMFUwGEDhR zhuCm_Y-b+zF#C$&nV)Y297Ie9eeVIg;(X;_@+DuDhxnvy8&?a;Zm zR|Bg%oDam}t6p6sQW$NbGf(}_p?}^#(0(S84I=jGgx9XDM^7`5zQIQo??oJpmGvcN zBGT3jpW;~eex{hxU$T~xc8Nz`LJ!id&W~pnMZ$Vypd9)DI-hFIdpYj^0DY-S=?Cz~ z(VOrcD@AUEYEzNk@#EWx$@v-?gW|^q4R}iN;KczZJQrbPEnGYn2WC%ewGxEpoie5wW zCc1yJ>1zQ009hwmb&&F`1byFqu#Nc_P~)%Op=@ms z=1ax@0D#o;Ai1|J@-R8LiBGTws|&VXw~{xqC>2M}(%{C@?tYZxipFxrM{wUmS(!T zVV%wHe(3xvwe60}8Re0;GNyi&Hp|jSn;~XDz=ELEAh}y9noX*qdNcF+Rm)~2xT!6c zteaRZz1N}ptw<8;(Y%=>-oBsUYd-G6MI^7^AFuxaUW;8~;@k+Q9&BT?^&dl1&1dfq zmg_>y@I!D&+Ex7zTB=}{BicpuZfihXTHY_n+aJ-XhjdSgQ*i9Un@Q>kv{$!PZ0=2* z;{XrmQrtI@7To?hsg^Z%82i0zFI2eSBLH|`lzX1$xiJq_1a;xo^JPUl-J3k-q;rUs zeO%KZUOMBwF^=W{bWxA-tU8?wL@9ml&+2jbRB{}!1EAuSj@1HiHA~#Laq!I~3|JhmMhB%? zWJy=dfbI1izJ{QU*dLz+jt+bMYE(iqC8@{vqdltH>T@PUAyUI{?%(rMS7MLk+E;`8 zNH?kaj?~bllt_OcZ?E{&v551QL;m`l5%|_`Qq!=5bVx8aC;KNO{6#U;OY_9aSa$ya zJu3I_F_kMSj?Kdl#;MCJdx@GRMhA%#hF`C(MY|ftcHd$on8P3`lwrwM?0=}K9#xYg zAP%EFSN{O5Opr%19nvh`j+`+1il{-(H)n509Y@r9Qnk(0tZ79jp9zLeT}D^lu3Jg= z+hPl1;t{ovc2Us#+MZJ?0X+^DPw}i9 z=ya&9$fSr{%vg=U3@{(Yz5f8lq>1IzrV}P+wv^?7@9*qtV67|-Y=NlT$d<`zd1sK`8up??ao$OCJS%o^z-tAWYjgXdFH9V= z`X2SHtQZ11Ru!UbgqJ&)8z1ZI`BtrwB0Yrizo_k5QJtl3=N))0(P$jid*~kK+`^I= z!*I;Kap)>x@{>;LE4mVGYq`qNf|haFe&){9Gyed6hE#i#-2Rl=1c6w|C!F4y+N0`6 z@)fUgSPUs4vHUBz{#A>2X$Z^Q2^{C6$XNdX-z$JWI_Zq>xs0M`UEkYVKKEskU@!^j zzRIGp=eoPSbFp1l`^06B&<>Tnu^~Gxtit#C6+!$?4nI1jE&4?55RqM%szJzKtDY;S zHZylKMwuW@@((3@w5R6$1yi0_t@Bw|TUs;8zED}uMgIUAu{+0V*^uv>vW|;U+-gY}Fxd^xcrt&5EuNa>`L_q= zJmb9!vIpIX4025-_5_-<1+pZdG2JQc=~KrXk~fuXy!0*DRK&qy8C7l4pS=G7(yrDf zs8=Y3vGW>iWX$D=;-zv}VMa*f*ieK=w+H~`nwZK^gXS`@>?vfsg3N6s z$tmgwT5NJlGVW;BBtMy_aIl8ss94d@sT9KM!}r#i9;upHZV`S}8@~#u_k}aLw)=Of zY@~|<-ogI><&>HC%>oS|HYLLS3C&lH?yd;(qLNQ`JbqPaG>gXhrjk2weSkE#=smiT z%MOe_<4gD{H32pt{_fs){{VR6uQs1=0`8XPS3ae-3P^-+pCT>)0PUWinWDnES|F~& z%eD*dd8;pR3;=nry}!7pr{hhYSia%9P=C1)+-b4e!x!&7re{3^^2hM)PThmllw7of zD<1D|ia*AqmQ;Q&u1O#B&MtqIA-0}&%)cssae7s_t$d}*qM-F^c4E3IB+DNbT5B_Z zeolW%80xcUa;h(;c8bwdl2e3saq7Ge&W49*JEcH<7v?l_`Gw4{v+88w9yLD3tKHd6 z6fXByid+s59Fl8U?dG^}kj*Gl)RT|UQeWv7)_P^cj!Q}q?Iic8lF+2}C`WrGzwYl4 zx)0+WMLy=%-tj!xnL+;W=zqY|AiIWPvRp6M{ApgwSR2i>Y-f_akKs>s+&Y>60A_ff zp4DY%mOLsqm^}!oqMjyTCqo(b}OmcmxC1rFr@41}!Op!Ab2*GiW zQhHVl-!z`p)%cDWh0;d|!m5J&ahl~qpE;vFtIu^6NjV+rn}iZ2kAl9-nu!M)J?dWCuC^bt0VM(BX%@Q@4|6$m}+s#}y!u z2K(TDS|aVCok;aYtW$>T!Sw>3!2*_3u>Sye{6E6865|bwW8XN`KZJrvwh4HZfKquu+h?BidR{sz$NHNXk-Kapt3_ z{s~9&H8e5=Vda*E#~J&}{y6;WTkHjJVrf^~fByhlnAU)tN~*yB0DS=cMP};7n#O}$ z4Tbpqr?Txr?+XLnpnvFV8CmRf zE85a6vm}ZdJmh*D)KfW`_Z$cB+b7g|8i8XnV64nX`)kkUDpR%;EYp#WyRrR6D;2U7 zJkUEdeCO|}A1nPwW9}-&w1`g710m}ZADIuatl2eaV{Af=EB^qo(xJS)xQP+wvWXe~ zWjst!2+{8-Zk=FE zYuQdcT;%>$N!vtAU0E&OvGN!!BPkz3_~ojUG2KZf=R>#D@mmnYk^HvMWd8tt>QsX# zEXGFm=|!#=NP-l~;0^~+4H^0YsC-2+O*iy@%Z&<5@R)l$Q;N@)UHc zxa^Fw2wA%N1ns)8iKS4=v9HBN_1%@&Ar0x0lr5Dk{#vMHj z^PjyhQ~CCz&4-dNO>!+G^Cv599ymqi&-hj(+O^Hol(CCq{{VdQ-<>*iwvGJlN^d%2 z$cYYVUhJeH+69U;{;naxZ?Cl`?g?0iD<>q&GkL5#xyTer8q9M&%eoKYL-LR5QOW1d z>TVdjAGr!}1zd{BV%sg@+~2_x^c0f0P1v5oC{{A@#j$_9dYZH`g3B2LyPoxG2tr04 zWgEJzW3@wZcBVk8pJ z^ik9Bq>-9IkGP|^dWlKwibxvaBRgS2?T@^BR&K4i>@FSKCubR};xo_;3WrsJW700& z+vYKlx%I4@vMp|BTxm%E05W`p_v~uCX?JFE_t176ii#O7Er<|YxL-#3maZl2(toVA zNe}m-d>_iS(49qeifDxLAzXdz3VoTgX(LFcC5sFXT0tt@t3*VL#&$U5)r%#D)@bEq zRUqUjUc!g4B0WM+wB1}0jP3&-mCbd#mHQ|)v*%{|zM6t2U2j zPVkExk17Q%_n4NbSML_@QcnJ4haCq3nxi-ay=aVHuR%e;$l{Y}IVADi(zY3~(M2(v z@D#+!H{bxjDE&|PQXWSgDPe@jbI?_v-N108d;9dMZpEm!uE?FN@l(eHAmBEBidz($v2lg;85lxG-eP+WYWyZZM#vFK?#Cql0-`1;(}j__ z=uXl4Q_|v0VFJc6&d=(4n#xVHctJ$9`_gvHDO3H#UbP}y=W#IOJ>1k#2O}W4AME_1 ztj01A$e7Rfvt07JJD`&gMi&6AKZQ!MM8xF)$93YIvE%P7Kzb9JlVanAP)Pn0ipjHG z1&m0e3gws4x&Hv`)bZRM#7c_DdV+ti_|+L_k}?A;k@Tb!!pciINBl?grDjWtdza=| zkdG)f)6NecuS$$ti;SWZk^DUf`c-eVZ3D}kjxY%7Dn;|y41nNskT6HTwHC0sT3e7y z4dMbVWGdsTxEVh~SnC7aTpjGr%y4%eYp;Z@!T~E1-HG7m>+4WWrUkr7k#Ef;BNLK6zLjH8vLW;6aBG#d zmF=z)RO$_PP|TN>k;*V~E6%SDNpmCD!c*&h$dK*ML#{`@ zKl02Xs}O1Tj1wf} z`&AzeBgJgW=vO;VKMK~kh)6I?4{&i&Q6}{0#~mJ~4a>yjv0Q!t{-(30p4u`?4a9aP zwyvygm>kUey$cG;lFr#r%vAkbKgzvqGmMspC0nPdpC+nVc0m9>+~e}73>TM;nNHRI z=oka=t)*Dgh+y1)m=xJTRVL^itMqC%=oS0wdetFQ&wS#r)-5S{?Vj2ntXhq z5@YzB;cBhcyAI8}nr}$r8&~l?O&3Tk*`j=WIj~48VqyD6g-o+t}vpn{hk{r zeCfzh+jsOG=|0zMWPFPVMa|Daft6p!y)omC8GhBQ&Lz117?+*DhiWz$*x6pbIqrF-=pLgU zJH14SZ=~`q$K8o|AC)P0WcxOqAC{fp)}>UI@yp0|pzD*+RCDS{5c@u!o@AXj0muIU zUY>{qHgH(sr2Xvdcm(oIEXX|NGq&lUg+b2Rj0UkjWUOVslzgN6zu```hDb?}{Pz$1 zXZU`Ut_AS0SPiJ5?i<&i&Y5W(mlr#;xx2CLOjtZQ=4^<&RTViD5In z#Ght`h(W_YcJ>uz78@9`7#q8j+M!Y{l!5-Rj!*YRGB9R4RnLju)SLQJ49dN=Mfn3HLsN ztIIr-4=&&3L);8!=}N;TmhCN@Vh=Wcm>mUT>h})uO0WCbcKq1;v5#+hl4*7~+3h}Q z58ji~soap3b4Ljqar3$A$Iwh$DUF<%R3}f-D zBg%O^yU0Wm9)}r2Q;jQ}Br3r4E8e;iW=)`k63DDlU{6$TMK@BHYA{Z$FsL}{NQc}F6R+e)c6VN@6Ggv;EQfpGs0o<(s`Q=rp*PggNtKA&zF{7stVYt7>J)ncSzl{Vyt(=TflN2QH_C;+yw+}; zXF{%*Q+!N;d67;#9)FcQ&k0ZAA54$ySSxcgVB`VlF^Zec`9Nkx_wH*qMAkT)nl1Bx zt9dx|aZFc{Wcirje|Q5~jdBJEl+ugB0X}16(3*b9ht?u$`GkxYQV(J(&79IkKXzF@ zgK+$-A}R6#Fs9Sp#xqx8Xfcw35Bo1sC|K4t6wZd)_9h``jB~+d`F}%OQ9}j9Aw-!y zROgXgrM=Nm6=ct*=Fju3D@oYn3WVpd$MUXc8#|d+qT0M!zizJ+ks##%01)Wk;A-Ic zh7D)Ka@ZLRRQ~|Lhw05+M+`DJtEVLs%c!08GBte$8`#_h`H173VAm~qr>>D=`|+Km z4ttvP8HA4u2ug`D#^I4%HnF8#-QF>}x-P?_d1NTArF+@GbWwg?(KR7& z`=-fKat?Y`sXRTClFZ*k{{RZ9CYc?yn}f0ZFt_yxOpur9@ROnTb(|Ks0UDvaB+^czRHtCQPeV?$B=8! zbi1Ibmy;ZHHP-1mke3lVWr+DtsG<+qPhFYjVyIvDkTj7M3vC$5$)vdfqCEp+jGR=s z`GM_O+P~V`Al8cm?LRU~nayiTH*3$CVt?cVulX^uHu?%P+J`Rqiy~rTOk=ir?O8 zGT)V5@;pI#!^z|!>Jtl1O$OQ{zVhTVcjmU$k+F>M+ADnbl3X{WNOAd^y=!Z5z>S|R~vWSH{q;I_a&#06p)MQuZLAYfCD;VlsIqjtsX+|!OB9AnJt zPh}J-5UC{m?fO&Vv@X7F!P^+;9=}>_k|?9|zGldXbCcDo)KN9dg^h5d@)Y=Cd$$-H zAzp*lu1hjn#3FzV-TkRIZ4kF2lgqSSsyE7b9;Tyc)*<$b#>*eNqxuR}#5tN@nnvg< z7cS0S&gpx4D5#XIQjNw;?K6QOD!oKt{;gE5C3)Q2+j0Hpqc1BwaW@D3WQV0wyt-6F zZ)=^u#NF7|6RB+$=J1DBM?8rLHumQ~-hWzx;BB;#K*`(rfA#6s@UdVQmOcF{&E>d@ zOq}=I*06F>Hc@gX`(*K{k5INUC;at{XY&;_EKqrtcO*yGjzIqa3a=X?;3Tre?0#jb zVfo}{0ybc$=23(Aiu9YZIIVLs{&OtHC!yeHIR5}V)?M73j2z?n)yY0-pQlnds&m8g zofl9vbv%t@py z$D9QorlSl4WDm}zR3zoOJ%^6Gq zc%;fjh~{;0P6wbon$U{j`s{P>z#pw=#Uo?{TzX(sglCy$RX<#s#!*b`r#7}`s@*EK zHnBd;KcK6Yw|H@g8|%0l!i>e72@8L`aa$Hrg&(^SgY2ZA*16{tk=Y5kZgf_c3_$r9 z`=G6;pL+6)zwcKuZ95<18UFx3THUp{`9|aU@%mRT#||c+R9_hfB8gEXOfrHgBVgk_ zsyoZ5?Vx9n;B*7lx?yDpslt z`efAy+}RsW?Dg6ODoWd)-z!i^jyFUjX~soGb2jV}MtW2BvJkG|XVaRFdu`Ytli!ie zZj!ysWhSF!LX#CICj+HwY1)HAia|IBrg{7;4m)Y?E|w@1w2atP10>f`W8rX-hSaqf zp+ED^EHNKb(ynleTAb0uH0*XZH>r7Q8C(X(KE|1K70X44+$;6m6cFD~YMrK^rrXE+ zyNSAWFZ$M`QGlu=oSrz}&TEY(q`6sy)K^$TghK%Pmkv6J?{Q7OkKkiqvN^@yl95Re=p_L`!m;H6^)1O6*)H_xF z?Y!(iy)$hUq;FP3@>pD-_y`o`X2wmD#ywk&=qQaOxH}+Sk&dU}Eo zH2FqkJ)h#y*oSf98D9a!`f z7XbX6p6-980#3!HF(}NE4`4D)NV6i4VnpM+{{V$kTw^?+Qh28cf@f(N_Nj3+Q#1tb zPtPloe}xwUt=nAeIAO=XHHa=`9XO}P(mCA3x7VPoBzzC-Yu&0}Qj;yMr_htgHbYjijMr{VLH9W{@nl>D$4b*h z3;ogf(d4PY1+qE;Q|%cql;kxSUefafGXDT{kMX3o`)%~X2nqK;-5%z<88ql`ki{|# zbQ$U^J_{$%uL8HvXFFgq>W$kz)zYySjh5$~Iw@4&LdCVXv4%T%*t5C$ob^7n(p$6K zPJ|4s3&p~nh5rDihiZ?)t~$dEU|im)QU3re;1yg$bvfsDJzV4T>sBJt z<6IdtBYJeEgv#RdG1+BpxBaI1oBsfJF@H9^&Fjr03>;LD6bK_KiYTD5X^OW<2BTT2^{&ae>C; zQ>!aPRljRIx?nfyhDn)Zi+DPs+ZhsjAq9?kXLiBy00_ z1E8UqAa9uYvmS~%3U8Y85|-<=d$;(|1a|6hcRA|+0O3;DBq&y9Eg{Pv)7qaLer`bd zP<`g8S9HHSosf>F)}x;9%mOGuScgIV>dI2FXq|Al z+C{jW$a)IP^B9vfhb(^Ru36N%(+Xs>+<6cf(B?@#`+rJ`2y@GRCZJH#OgphW59?Yi z7AV34!0KxWyJ^(vryJ|gYdDEAKMF`VEY5j6lj%_tpWZO`MW?^YyEE?92^A(a0h(hc zb~sV!DVof=w2~zB$@&VJ97PjM-#{v)<8GUCG~apDs{Kt`w>A3`@5^rGC47+~%uH8Ad{5-ZPQ;R2N9G#7eMikUb50bu@#q!A{O<=4^}s zEP9@5zu!BU@lwywd+|(F-Op;_M|0JOBy+%^e8d63r!dT5^v^XI;1lb|;XpkJP=2GS-v0pXsN$NR>drW(j!03|&^zcRdb@o9rjMBBoh~;7UW>&(B?S9ZCf9Zm&e-<% zYH0aXdzvLVlAM4vqd#>=G>5w_KM)PvU}XJjC6D)N&FP#{ZZk*}{m^o1YneoAw0-97 z=~J%8x;;vy7k#3hcJ2xX3)YbcSj+c33TESh+xpcR=!Z!B@IG(lN{g{K9$56Isu%Bo zDRYViexuYZXmiWA@~Bv6mf?E}nE+5p1)aD8q*wwr`N#}=dVUnIVy$u!3p#?|D)tof z7+iE;cI)|6r;KtCdY-?PHx}wiXJd%_sNUt+5Yla5?#3}i*jgx&ZKIFD^^{XqWD3Ap}s5+6>u?(Dq<(T#rcFG*!mdg{@ z_(#*$vXm9B&WKcP*%#LSNf@jse=fBwYda5~Tq)xK_4cUuB0B{ok4%bGlmHtZyw(kN zI#-!#Kux`mU>2uYWF+lgdzLj<%_R_(Ac4D%xb6OZ>PYiB3)5)MbAeFMnW<-!f`0c( zmt3|J=+i56ftsss5xX z65Nnasp@O9>MJ8ijbek#1bYnDvLBRJP8xjEmzl?ica^(nXKHcYvgXo680xMD4RiN4 zmp26crrEMTiWWHhvt1SZ7H)HK8ZkdypUSg8vo!hCwYz|S*>X9qs#1hbStiU=rZS(B z8Hw~^{w99-330)k`ShBXZ5r7_V zIfrHG`c;IEFux#J*0W8`l8v!X5+7EKvHo=gliQF?x|Hw!%u($XrOC0WEyNb*u|E7} zp?98dy@+EyhYUxs{{R}LY|QWehi4!k^U?nC{7*`rL|D}QrbJQQROdfa-krr_E1S

tD|(5+BL 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 diff --git a/models/Reference/pixart-alpha--pixart-xl-2-1024-ms.thumb.jpg b/models/Reference/pixart-alpha--pixart-xl-2-1024-ms.thumb.jpg deleted file mode 100644 index f28d4810283a6b8a555362aa77e655e9e4a22565..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 31193 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

#^q01>7>008O~4< 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 diff --git a/models/Reference/segmind--tiny-sd.thumb.jpg b/models/Reference/segmind--tiny-sd.thumb.jpg deleted file mode 100644 index fea9e5c4dd6c4b1a0b191386e73d2321a5ceec11..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 29722 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 z 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 a7KHg#oT_O)xR<*4FUlm};~~o5h5rMww-uuR diff --git a/models/Reference/simianluo--lcm_dreamshaper_v7.thumb.jpg b/models/Reference/simianluo--lcm_dreamshaper_v7.thumb.jpg deleted file mode 100644 index bdb265473811e90872d94aa1de7054f35717ca71..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 27600 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ⅇE7;$B+%8??fDaFUck0F<=d!=xNYe&sWl@ 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 Qf{airmdgx`QLrEX*-Ks5`Tzg` diff --git a/modules/modelloader.py b/modules/modelloader.py index f0fd4241e..d7bbe5f97 100644 --- a/modules/modelloader.py +++ b/modules/modelloader.py @@ -274,6 +274,8 @@ def load_diffusers_models(model_path: str, command_path: str = None, clear=True) try: if "--" not in folder: continue + if folder.endswith("-prior"): + continue _, name = folder.split("--", maxsplit=1) name = name.replace("--", "/") folder = os.path.join(place, folder) diff --git a/modules/sd_vae.py b/modules/sd_vae.py index eeffcef44..36aac1df0 100644 --- a/modules/sd_vae.py +++ b/modules/sd_vae.py @@ -91,6 +91,8 @@ def refresh_vae_list(): candidates += glob.iglob(path, recursive=True) for filepath in candidates: name = get_filename(filepath) + if name == 'VAE': + continue if shared.backend == shared.Backend.ORIGINAL: vae_dict[name] = filepath else: diff --git a/modules/ui_extra_networks.py b/modules/ui_extra_networks.py index 4815e8210..4150fc022 100644 --- a/modules/ui_extra_networks.py +++ b/modules/ui_extra_networks.py @@ -329,10 +329,10 @@ class ExtraNetworksPage: else: files = listdir(os.path.dirname(path)) fn = os.path.splitext(path)[0] - preview_extensions = ["jpg", "jpeg", "png", "webp", "tiff", "jp2"] - for file in [f'{fn}{mid}{ext}' for ext in preview_extensions for mid in ['.thumb.', '.', '.preview.']]: + exts = ["jpg", "jpeg", "png", "webp", "tiff", "jp2"] + for file in [f'{fn}{mid}{ext}' for ext in exts for mid in ['.thumb.', '.', '.preview.']]: if file in files: - if '.thumb.' not in file: + if 'Reference' not in file and '.thumb.' not in file: self.missing_thumbs.append(file) return file return 'html/card-no-preview.png' From 39e5d614ff6449a2cb9f237e09f2f4e37ffbecac Mon Sep 17 00:00:00 2001 From: Vladimir Mandic Date: Mon, 13 Nov 2023 16:37:41 -0500 Subject: [PATCH 13/84] consistency decoder --- CHANGELOG.md | 3 ++- modules/processing_diffusers.py | 2 +- modules/sd_vae.py | 10 ++++++++-- 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b6a4bbb4b..b8111bfc7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,7 +21,8 @@ - Updated logic for calculating **steps** when using base/hires/refiner workflows - Safe model offloading for non-standard models - Fix **DPM SDE** scheduler - - Better support for SD 1.5 **inpainting** models + - Better support for SD 1.5 **inpainting** models + - Add support for **OpenAI Consistency decoder VAE** - Update to `diffusers==0.23.0` - **Extra networks** - Use multi-threading for 5x load speedup diff --git a/modules/processing_diffusers.py b/modules/processing_diffusers.py index 0ea8292ac..9a56fc028 100644 --- a/modules/processing_diffusers.py +++ b/modules/processing_diffusers.py @@ -98,7 +98,7 @@ def process_diffusers(p: StableDiffusionProcessing, seeds, prompts, negative_pro model.vae.to(devices.device) latents.to(model.vae.device) - upcast = (model.vae.dtype == torch.float16) and model.vae.config.force_upcast and hasattr(model, 'upcast_vae') + upcast = (model.vae.dtype == torch.float16) and getattr(model.vae.config, 'force_upcast', False) and hasattr(model, 'upcast_vae') if upcast: # this is done by diffusers automatically if output_type != 'latent' model.upcast_vae() latents = latents.to(next(iter(model.vae.post_quant_conv.parameters())).dtype) diff --git a/modules/sd_vae.py b/modules/sd_vae.py index 36aac1df0..9e28e4c73 100644 --- a/modules/sd_vae.py +++ b/modules/sd_vae.py @@ -203,10 +203,16 @@ def load_vae_diffusers(model_file, vae_file=None, vae_source="unknown-source"): if os.path.isfile(vae_file): _pipeline, model_type = sd_models.detect_pipeline(model_file, 'vae') diffusers_load_config = { "config_file": paths.sd_default_config if model_type != 'Stable Diffusion XL' else os.path.join(paths.sd_configs_path, 'sd_xl_base.yaml')} - vae = diffusers.AutoencoderKL.from_single_file(vae_file, **diffusers_load_config) + if os.path.getsize(vae_file) > 1310944880: + vae = diffusers.ConsistencyDecoderVAE.from_pretrained('openai/consistency-decoder', **diffusers_load_config) # consistency decoder does not have from single file, so we'll just download it once more + else: + vae = diffusers.AutoencoderKL.from_single_file(vae_file, **diffusers_load_config) vae = vae.to(devices.dtype_vae) else: - vae = diffusers.AutoencoderKL.from_pretrained(vae_file, **diffusers_load_config) + if 'consistency-decoder' in vae_file: + vae = diffusers.ConsistencyDecoderVAE.from_pretrained(vae_file, **diffusers_load_config) + else: + vae = diffusers.AutoencoderKL.from_pretrained(vae_file, **diffusers_load_config) global loaded_vae_file # pylint: disable=global-statement loaded_vae_file = os.path.basename(vae_file) # shared.log.debug(f'Diffusers VAE config: {vae.config}') From 69c5cff112e8b868feced025b398596f35ea248b Mon Sep 17 00:00:00 2001 From: Vladimir Mandic Date: Mon, 13 Nov 2023 17:49:56 -0500 Subject: [PATCH 14/84] diffusers prompt handle BREAK --- CHANGELOG.md | 1 + modules/processing_diffusers.py | 2 ++ modules/prompt_parser_diffusers.py | 22 ++++++++++++++++++---- 3 files changed, 21 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b8111bfc7..aedf129b8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,6 +23,7 @@ - Fix **DPM SDE** scheduler - Better support for SD 1.5 **inpainting** models - Add support for **OpenAI Consistency decoder VAE** + - Enhance prompt parsing with long prompts and support for *BREAK* keyword - Update to `diffusers==0.23.0` - **Extra networks** - Use multi-threading for 5x load speedup diff --git a/modules/processing_diffusers.py b/modules/processing_diffusers.py index 9a56fc028..bf3b6d430 100644 --- a/modules/processing_diffusers.py +++ b/modules/processing_diffusers.py @@ -183,6 +183,8 @@ def process_diffusers(p: StableDiffusionProcessing, seeds, prompts, negative_pro negative_prompts = [negative_prompts] while len(negative_prompts) < len(prompts): negative_prompts.append(negative_prompts[-1]) + while len(prompts) < len(negative_prompts): + prompts.append(prompts[-1]) if type(prompts_2) is str: prompts_2 = [prompts_2] if type(prompts_2) is list: diff --git a/modules/prompt_parser_diffusers.py b/modules/prompt_parser_diffusers.py index 600c66d4a..b9fbf8908 100644 --- a/modules/prompt_parser_diffusers.py +++ b/modules/prompt_parser_diffusers.py @@ -69,7 +69,7 @@ def encode_prompts(pipeline, prompts: list, negative_prompts: list, clip_skip: t negative_embeds = [] negative_pooleds = [] for i in range(len(prompts)): - prompt_embed, positive_pooled, negative_embed, negative_pooled = get_weighted_text_embeddings_sdxl(pipeline,prompts[i], negative_prompts[i], clip_skip) + prompt_embed, positive_pooled, negative_embed, negative_pooled = get_weighted_text_embeddings(pipeline,prompts[i], negative_prompts[i], clip_skip) prompt_embeds.append(prompt_embed) positive_pooleds.append(positive_pooled) negative_embeds.append(negative_embed) @@ -113,6 +113,7 @@ def prepare_embedding_providers(pipe, clip_skip): embeddings_providers.append(embedding) return embeddings_providers + def pad_to_same_length(embeds): try: #SDXL empty_embed = shared.sd_model.encode_prompt("") @@ -127,7 +128,8 @@ def pad_to_same_length(embeds): embeds[i] = embed return embeds -def get_weighted_text_embeddings_sdxl(pipe, prompt: str = "", neg_prompt: str = "", clip_skip: int = None): + +def get_weighted_text_embeddings(pipe, prompt: str = "", neg_prompt: str = "", clip_skip: int = None): prompt_2 = prompt.split("TE2:")[-1] neg_prompt_2 = neg_prompt.split("TE2:")[-1] prompt = prompt.split("TE2:")[0] @@ -152,8 +154,20 @@ def get_weighted_text_embeddings_sdxl(pipe, prompt: str = "", neg_prompt: str = negative_pooled_prompt_embeds = None for i in range(len(embedding_providers)): - embed, ptokens = embedding_providers[i].get_embeddings_for_weighted_prompt_fragments(text_batch=[positives[i]], fragment_weights_batch=[positive_weights[i]], device=pipe.device, should_return_tokens=True) - prompt_embeds.append(embed) + # add BREAK keyword that splits the prompt into multiple fragments + text = positives[i] + weights = positive_weights[i] + text.append('BREAK') + weights.append(-1) + provider_embed = [] + while 'BREAK' in text: + pos = text.index('BREAK') + embed, ptokens = embedding_providers[i].get_embeddings_for_weighted_prompt_fragments(text_batch=[text[:pos]], fragment_weights_batch=[weights[:pos]], device=pipe.device, should_return_tokens=True) + provider_embed.append(embed) + text = text[pos+1:] + weights = weights[pos+1:] + prompt_embeds.append(torch.cat(provider_embed, dim=1)) + # negative prompt has no keywords embed, ntokens = embedding_providers[i].get_embeddings_for_weighted_prompt_fragments(text_batch=[negatives[i]], fragment_weights_batch=[negative_weights[i]],device=pipe.device, should_return_tokens=True) negative_prompt_embeds.append(embed) From 3f6c0d843c78c6a912dacfe980b201b7e11d94cb Mon Sep 17 00:00:00 2001 From: Vladimir Mandic Date: Mon, 13 Nov 2023 18:08:07 -0500 Subject: [PATCH 15/84] new line means break --- CHANGELOG.md | 3 ++- modules/prompt_parser.py | 7 +++++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index aedf129b8..ac8236271 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,7 +23,8 @@ - Fix **DPM SDE** scheduler - Better support for SD 1.5 **inpainting** models - Add support for **OpenAI Consistency decoder VAE** - - Enhance prompt parsing with long prompts and support for *BREAK* keyword + - Enhance prompt parsing with long prompts and support for *BREAK* keyword + Change-in-behavior: new line in prompt now means *BREAK* - Update to `diffusers==0.23.0` - **Extra networks** - Use multi-threading for 5x load speedup diff --git a/modules/prompt_parser.py b/modules/prompt_parser.py index 09e763408..5a950d443 100644 --- a/modules/prompt_parser.py +++ b/modules/prompt_parser.py @@ -14,7 +14,7 @@ from typing import List import lark import torch from compel import Compel -from modules.shared import opts, log +from modules.shared import opts, log, backend, Backend # a prompt like this: "fantasy landscape with a [mountain:lake:0.25] and [an oak:a christmas tree:0.75][ in foreground::0.6][ in background:0.25] [shoddy:masterful:0.5]" # will be represented with prompt_schedule like this (assuming steps=100): @@ -320,7 +320,10 @@ def parse_prompt_attention(text): whitespace = '' else: re_attention = re_attention_v1 - text = text.replace('\\n', ' ') + if backend == Backend.DIFFUSERS: + text = text.replace('\n', ' BREAK ') + else: + text = text.replace('\n', ' ') whitespace = ' ' def multiply_range(start_position, multiplier): From 8a27e1433b91098a35499b831d60ef137604759e Mon Sep 17 00:00:00 2001 From: Midcoastal Date: Mon, 13 Nov 2023 18:37:34 -0500 Subject: [PATCH 16/84] Enable grid overall title. --- modules/images.py | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/modules/images.py b/modules/images.py index 38e7ebbcb..7c958c0e7 100644 --- a/modules/images.py +++ b/modules/images.py @@ -122,7 +122,7 @@ class GridAnnotation: self.size = None -def draw_grid_annotations(im, width, height, hor_texts, ver_texts, margin=0): +def draw_grid_annotations(im, width, height, hor_texts, ver_texts, margin=0, title=None): def wrap(drawing, text, font, line_length): lines = [''] for word in text.split(): @@ -163,7 +163,8 @@ def draw_grid_annotations(im, width, height, hor_texts, ver_texts, margin=0): assert rows == len(ver_texts), f'bad number of vertical texts: {len(ver_texts)}; must be {rows}' calc_img = Image.new("RGB", (1, 1), "white") calc_d = ImageDraw.Draw(calc_img) - for texts, allowed_width in zip(hor_texts + ver_texts, [width] * len(hor_texts) + [pad_left] * len(ver_texts)): + title_texts = [title] if title else [[GridAnnotation()]] + for texts, allowed_width in zip(hor_texts + ver_texts + title_texts, [width] * len(hor_texts) + [pad_left] * len(ver_texts) + [(width+margin)*cols]): items = [] + texts texts.clear() for line in items: @@ -176,19 +177,27 @@ def draw_grid_annotations(im, width, height, hor_texts, ver_texts, margin=0): hor_text_heights = [sum([line.size[1] + line_spacing for line in lines]) - line_spacing for lines in hor_texts] ver_text_heights = [sum([line.size[1] + line_spacing for line in lines]) - line_spacing * len(lines) for lines in ver_texts] pad_top = 0 if sum(hor_text_heights) == 0 else max(hor_text_heights) + line_spacing * 2 - result = Image.new("RGB", (im.width + pad_left + margin * (cols-1), im.height + pad_top + margin * (rows-1)), "white") + title_pad = 0 + if title: + title_text_heights = [sum([line.size[1] + line_spacing for line in lines]) - line_spacing for lines in title_texts] + title_pad = 0 if sum(title_text_heights) == 0 else max(title_text_heights) + line_spacing * 2 + result = Image.new("RGB", (im.width + pad_left + margin * (cols-1), im.height + pad_top + title_pad + margin * (rows-1)), "white") for row in range(rows): for col in range(cols): cell = im.crop((width * col, height * row, width * (col+1), height * (row+1))) - result.paste(cell, (pad_left + (width + margin) * col, pad_top + (height + margin) * row)) + result.paste(cell, (pad_left + (width + margin) * col, pad_top + title_pad + (height + margin) * row)) d = ImageDraw.Draw(result) + if title: + x = pad_left + ((width+margin)*cols) / 2 + y = title_pad / 2 - title_text_heights[0] / 2 + draw_texts(d, x, y, title_texts[0], fnt, fontsize) for col in range(cols): x = pad_left + (width + margin) * col + width / 2 - y = pad_top / 2 - hor_text_heights[col] / 2 + y = (pad_top / 2 - hor_text_heights[col] / 2) + title_pad draw_texts(d, x, y, hor_texts[col], fnt, fontsize) for row in range(rows): x = pad_left / 2 - y = pad_top + (height + margin) * row + height / 2 - ver_text_heights[row] / 2 + y = (pad_top + (height + margin) * row + height / 2 - ver_text_heights[row] / 2) + title_pad draw_texts(d, x, y, ver_texts[row], fnt, fontsize) return result From 740cd5d701bb293106dfc5e1916989ddd61dabe8 Mon Sep 17 00:00:00 2001 From: Midcoastal Date: Mon, 13 Nov 2023 18:38:11 -0500 Subject: [PATCH 17/84] Impliment skipping Main Grid, and just generating sub-grids. --- scripts/xyz_grid.py | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/scripts/xyz_grid.py b/scripts/xyz_grid.py index 4c632a4ce..a8b809f93 100644 --- a/scripts/xyz_grid.py +++ b/scripts/xyz_grid.py @@ -345,10 +345,10 @@ def draw_xyz_grid(p, xs, ys, zs, x_labels, y_labels, z_labels, cell, draw_legend for i in range(z_count): start_index = (i * len(xs) * len(ys)) + i end_index = start_index + len(xs) * len(ys) - if not no_grid and images.check_grid_size(processed_result.images[start_index:end_index]): + if (not no_grid or include_sub_grids) and images.check_grid_size(processed_result.images[start_index:end_index]): grid = images.image_grid(processed_result.images[start_index:end_index], rows=len(ys)) if draw_legend: - grid = images.draw_grid_annotations(grid, processed_result.images[start_index].size[0], processed_result.images[start_index].size[1], hor_texts, ver_texts, margin_size) + grid = images.draw_grid_annotations(grid, processed_result.images[start_index].size[0], processed_result.images[start_index].size[1], hor_texts, ver_texts, margin_size, title=title_texts[i]) processed_result.images.insert(i, grid) processed_result.all_prompts.insert(i, processed_result.all_prompts[start_index]) processed_result.all_seeds.insert(i, processed_result.all_seeds[start_index]) @@ -357,7 +357,7 @@ def draw_xyz_grid(p, xs, ys, zs, x_labels, y_labels, z_labels, cell, draw_legend if not no_grid and images.check_grid_size(processed_result.images[:z_count]): z_grid = images.image_grid(processed_result.images[:z_count], rows=1) if draw_legend: - z_grid = images.draw_grid_annotations(z_grid, sub_grid_size[0], sub_grid_size[1], title_texts, [[images.GridAnnotation()]]) + z_grid = images.draw_grid_annotations(z_grid, sub_grid_size[0], sub_grid_size[1], [[images.GridAnnotation()] for _ in z_labels], [[images.GridAnnotation()]]) processed_result.images.insert(0, z_grid) #processed_result.all_prompts.insert(0, processed_result.all_prompts[0]) #processed_result.all_seeds.insert(0, processed_result.all_seeds[0]) @@ -699,9 +699,13 @@ class Script(scripts.Script): z_count = len(zs) processed.infotexts[:1+z_count] = grid_infotext[:1+z_count] # Set the grid infotexts to the real ones with extra_generation_params (1 main grid + z_count sub-grids) if not include_lone_images: - processed.images = processed.images[:z_count+1] # Don't need sub-images anymore, drop from list: + # Don't need sub-images anymore, drop from list: + if no_grid and include_sub_grids: + processed.images = processed.images[:z_count] # we don't have the main grid image, and need zero additional sub-images + else: + processed.images = processed.images[:z_count+1] # we either have the main grid image, or need one sub-images if shared.opts.grid_save: # Auto-save main and sub-grids: - grid_count = z_count + 1 if z_count > 1 else 1 + grid_count = z_count + ( 1 if not no_grid and z_count > 1 else 0 ) for g in range(grid_count): adj_g = g-1 if g > 0 else g images.save_image(processed.images[g], p.outpath_grids, "xyz_grid", info=processed.infotexts[g], extension=shared.opts.grid_format, prompt=processed.all_prompts[adj_g], seed=processed.all_seeds[adj_g], grid=True, p=processed) @@ -711,4 +715,9 @@ class Script(scripts.Script): del processed.all_prompts[1] del processed.all_seeds[1] del processed.infotexts[1] + elif no_grid: + ##del processed.images[0] + #del processed.all_prompts[0] + #del processed.all_seeds[0] + del processed.infotexts[0] return processed From 882da270e9cf9e0c96e5fc74d6662b866c5dae1b Mon Sep 17 00:00:00 2001 From: Vladimir Mandic Date: Mon, 13 Nov 2023 18:42:02 -0500 Subject: [PATCH 18/84] add SD_LORA_DIFFUSERS --- .../Lora/extra_networks_lora.py | 2 ++ extensions-builtin/Lora/networks.py | 23 ++++++++++++++++++- modules/generation_parameters_copypaste.py | 1 - modules/shared.py | 1 - 4 files changed, 24 insertions(+), 3 deletions(-) diff --git a/extensions-builtin/Lora/extra_networks_lora.py b/extensions-builtin/Lora/extra_networks_lora.py index 708e1f1e5..40ac8b909 100644 --- a/extensions-builtin/Lora/extra_networks_lora.py +++ b/extensions-builtin/Lora/extra_networks_lora.py @@ -64,6 +64,8 @@ class ExtraNetworkLora(extra_networks.ExtraNetwork): self.active = False def deactivate(self, p): + if shared.backend == shared.Backend.DIFFUSERS: + shared.sd_model.unload_lora_weights() if not self.active and getattr(networks, "originals", None ) is not None: networks.originals.undo() # remove patches if networks.debug: diff --git a/extensions-builtin/Lora/networks.py b/extensions-builtin/Lora/networks.py index 3f83e7f3f..974d9faac 100644 --- a/extensions-builtin/Lora/networks.py +++ b/extensions-builtin/Lora/networks.py @@ -74,6 +74,24 @@ def assign_network_names_to_compvis_modules(sd_model): sd_model.network_layer_mapping = network_layer_mapping +def load_diffusers(name, network_on_disk): + t0 = time.time() + cached = lora_cache.get(name, None) + if debug: + shared.log.debug(f'LoRA load: name={name} file={network_on_disk.filename} {"cached" if cached else ""}') + if cached is not None: + return cached + if shared.backend != shared.Backend.DIFFUSERS: + return None + shared.sd_model.load_lora_weights(network_on_disk.filename) + net = network.Network(name, network_on_disk) + net.mtime = os.path.getmtime(network_on_disk.filename) + lora_cache[name] = net + t1 = time.time() + timer['load'] += t1 - t0 + return net + + def load_network(name, network_on_disk): t0 = time.time() cached = lora_cache.get(name, None) @@ -142,7 +160,10 @@ def load_networks(names, te_multipliers=None, unet_multipliers=None, dyn_dims=No net = None if network_on_disk is not None: try: - net = load_network(name, network_on_disk) + if shared.backend == shared.Backend.DIFFUSERS and os.environ.get('SD_LORA_DIFFUSERS', None): + net = load_diffusers(name, network_on_disk) + else: + net = load_network(name, network_on_disk) except Exception as e: shared.log.error(f"LoRA load failed: file={network_on_disk.filename}") if debug: diff --git a/modules/generation_parameters_copypaste.py b/modules/generation_parameters_copypaste.py index 3d6090398..7aba397a6 100644 --- a/modules/generation_parameters_copypaste.py +++ b/modules/generation_parameters_copypaste.py @@ -247,7 +247,6 @@ infotext_to_setting_name_mapping = [ ('VAE', 'sd_vae'), ('Parser', 'prompt_attention'), ('Color correction', 'img2img_color_correction'), - ('LoRA method', 'diffusers_lora_loader'), # Samplers ('Sampler Eta', 'scheduler_eta'), ('Sampler ENSD', 'eta_noise_seed_delta'), diff --git a/modules/shared.py b/modules/shared.py index c571c299d..17ce2bd54 100644 --- a/modules/shared.py +++ b/modules/shared.py @@ -347,7 +347,6 @@ options_templates.update(options_section(('diffusers', "Diffusers Settings"), { "diffusers_model_load_variant": OptionInfo("default", "Diffusers model loading variant", gr.Radio, {"choices": ['default', 'fp32', 'fp16']}), "diffusers_vae_load_variant": OptionInfo("default", "Diffusers VAE loading variant", gr.Radio, {"choices": ['default', 'fp32', 'fp16']}), "custom_diffusers_pipeline": OptionInfo('', 'Load custom Diffusers pipeline'), - "diffusers_lora_loader": OptionInfo("diffusers" if cmd_opts.use_openvino else "sequential apply", "Diffusers LoRA loading variant", gr.Radio, {"choices": ['diffusers', 'sequential apply', 'merge and apply']}), "diffusers_eval": OptionInfo(True, "Force model eval"), "diffusers_force_zeros": OptionInfo(True, "Force zeros for prompts when empty"), "diffusers_aesthetics_score": OptionInfo(False, "Require aesthetics score"), From de62100cfabe851136129fcf4a2dc8f028160443 Mon Sep 17 00:00:00 2001 From: Vladimir Mandic Date: Mon, 13 Nov 2023 18:47:40 -0500 Subject: [PATCH 19/84] update changelog --- CHANGELOG.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ac8236271..f97a7a0e8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,7 +10,7 @@ - set **sampler** to **LCM** - set number of steps to some low number, for SD-XL 6-7 steps is normally sufficient note: LCM scheduler does not support steps higher than 50 - - set cfg to 1 or 2 + - set CFG to 1-2 - Add `cli/lcm-convert.py` script to convert any SD 1.5 or SD-XL model to LCM model by baking in LORA and uploading to Huggingface, thanks @Disty0 - Support for [Stable Fast](https://github.com/chengzeyi/stable-fast) model compile on *Windows/Linux/WSL2* with *CUDA* @@ -25,6 +25,7 @@ - Add support for **OpenAI Consistency decoder VAE** - Enhance prompt parsing with long prompts and support for *BREAK* keyword Change-in-behavior: new line in prompt now means *BREAK* + - Add alternative Lora loading algorithm, triggered if `SD_LORA_DIFFUSERS` is set - Update to `diffusers==0.23.0` - **Extra networks** - Use multi-threading for 5x load speedup From e46661f6f9ce24516476e6e6b5a1aa4e94d6ead7 Mon Sep 17 00:00:00 2001 From: Vladimir Mandic Date: Tue, 14 Nov 2023 14:23:13 -0500 Subject: [PATCH 20/84] handle lcm lora loader separately --- extensions-builtin/Lora/networks.py | 8 +++++--- extensions-builtin/sd-webui-agent-scheduler | 2 +- wiki | 2 +- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/extensions-builtin/Lora/networks.py b/extensions-builtin/Lora/networks.py index 974d9faac..83df1699d 100644 --- a/extensions-builtin/Lora/networks.py +++ b/extensions-builtin/Lora/networks.py @@ -77,8 +77,8 @@ def assign_network_names_to_compvis_modules(sd_model): def load_diffusers(name, network_on_disk): t0 = time.time() cached = lora_cache.get(name, None) - if debug: - shared.log.debug(f'LoRA load: name={name} file={network_on_disk.filename} {"cached" if cached else ""}') + # if debug: + shared.log.debug(f'LoRA load: name={name} file={network_on_disk.filename} type=diffusers {"cached" if cached else ""}') if cached is not None: return cached if shared.backend != shared.Backend.DIFFUSERS: @@ -160,7 +160,9 @@ def load_networks(names, te_multipliers=None, unet_multipliers=None, dyn_dims=No net = None if network_on_disk is not None: try: - if shared.backend == shared.Backend.DIFFUSERS and os.environ.get('SD_LORA_DIFFUSERS', None): + if shared.backend == shared.Backend.DIFFUSERS and (os.environ.get('SD_LORA_DIFFUSERS', None) + or getattr(network_on_disk, 'shorthash', None) == 'aaebf6360f7d' # lcm sd15 + or getattr(network_on_disk, 'shorthash', None) == '3d18b05e4f56'): # lcm sdxl net = load_diffusers(name, network_on_disk) else: net = load_network(name, network_on_disk) diff --git a/extensions-builtin/sd-webui-agent-scheduler b/extensions-builtin/sd-webui-agent-scheduler index b6965ad05..7a03f4e67 160000 --- a/extensions-builtin/sd-webui-agent-scheduler +++ b/extensions-builtin/sd-webui-agent-scheduler @@ -1 +1 @@ -Subproject commit b6965ad05d25b383468ea0289bd6d0e0a92aad82 +Subproject commit 7a03f4e6786b00b99607a13b362961dd80d6cacf diff --git a/wiki b/wiki index 7d0daac42..6f0a39eda 160000 --- a/wiki +++ b/wiki @@ -1 +1 @@ -Subproject commit 7d0daac4212d97c9ecbf30a7b06fe77bc3cc5bab +Subproject commit 6f0a39edad41d6d13b2822c7f93fab22d706c693 From 1de913f9848cc03aa2157d9a83da8e00b2392ad6 Mon Sep 17 00:00:00 2001 From: Vladimir Mandic Date: Tue, 14 Nov 2023 17:16:33 -0500 Subject: [PATCH 21/84] auto refresh styles on change --- CHANGELOG.md | 3 ++- javascript/extraNetworks.js | 25 +++++++++++++++++++++-- modules/images.py | 11 +++++++++- modules/processing.py | 2 +- modules/ui_extra_networks.py | 39 ++++++++++++++++++------------------ 5 files changed, 56 insertions(+), 24 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f97a7a0e8..c6b560f0b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,7 +6,7 @@ - **LCM** support for any *SD 1.5* or *SD-XL* model! - download [lcm-lora-sd15](https://huggingface.co/latent-consistency/lcm-lora-sdv1-5/tree/main) and/or [lcm-lora-sdxl](https://huggingface.co/latent-consistency/lcm-lora-sdxl/tree/main) - load for favorite *SD 1.5* or *SD-XL* model *(original LCM was SD 1.5 only, this is both)* - - load **lcm lora** + - load **lcm lora** *(note: lcm lora is processed differently than any other lora)* - set **sampler** to **LCM** - set number of steps to some low number, for SD-XL 6-7 steps is normally sufficient note: LCM scheduler does not support steps higher than 50 @@ -36,6 +36,7 @@ - Reworked **model compile** - Add refiner options to XYZ Grid - Support custom upscalers in subfolders + - Add additional image info when loading image in process tab - Support `--ckpt none` to skip loading a model - **Fixes** - Fix `params.txt` saved before actual image diff --git a/javascript/extraNetworks.js b/javascript/extraNetworks.js index 8415d2d11..9261ffb7d 100644 --- a/javascript/extraNetworks.js +++ b/javascript/extraNetworks.js @@ -40,7 +40,7 @@ const setENState = (state) => { // methods function showCardDetails(event) { - console.log('showCardDetails', event) + console.log('showCardDetails', event); const tabname = getENActiveTab(); const btn = gradioApp().getElementById(`${tabname}_extra_details_btn`); btn.click(); @@ -183,7 +183,7 @@ function sortExtraNetworks() { return `sort page ${pagename} cards ${num} by ${desc}`; } -function refreshExtraNetworks(tabname) { +function refreshENInput(tabname) { log('refreshExtraNetworks', tabname, gradioApp().querySelector(`#${tabname}_extra_networks textarea`)?.value); gradioApp().querySelector(`#${tabname}_extra_networks textarea`)?.dispatchEvent(new Event('input')); } @@ -234,6 +234,27 @@ function quickSaveStyle() { if (btnSave) btnSave.click(); } +let enDirty = false; +function closeDetailsEN(args) { + // log('closeDetailsEN'); + enDirty = true; + const tabname = getENActiveTab(); + const btnClose = gradioApp().getElementById(`${tabname}_extra_details_close`); + if (btnClose) setTimeout(() => btnClose.click(), 100); + const btnRefresh = gradioApp().getElementById(`${tabname}_extra_refresh`); + if (btnRefresh && enDirty) setTimeout(() => btnRefresh.click(), 100); + return args; +} + +function refeshDetailsEN(args) { + log(`refeshDetailsEN: ${enDirty}`); + const tabname = getENActiveTab(); + const btnRefresh = gradioApp().getElementById(`${tabname}_extra_refresh`); + if (btnRefresh && enDirty) setTimeout(() => btnRefresh.click(), 100); + enDirty = false; + return args; +} + // init function setupExtraNetworksForTab(tabname) { diff --git a/modules/images.py b/modules/images.py index 38e7ebbcb..2a02f60bd 100644 --- a/modules/images.py +++ b/modules/images.py @@ -204,6 +204,7 @@ def draw_prompt_matrix(im, width, height, all_prompts, margin=0): def resize_image(resize_mode, im, width, height, upscaler_name=None, output_type='image'): + # shared.log.debug(f'Image resize: mode={resize_mode} resolution={width}x{height} upscaler={upscaler_name}') """ Resizes an image with the specified resize_mode, width, and height. Args: @@ -628,7 +629,7 @@ def safe_decode_string(s: bytes): return None -def read_info_from_image(image): +def read_info_from_image(image: Image): items = image.info or {} geninfo = items.pop('parameters', None) if geninfo is None: @@ -680,6 +681,14 @@ Negative prompt: {json_info["uc"]} Steps: {json_info["steps"]}, Sampler: {sampler}, CFG scale: {json_info["scale"]}, Seed: {json_info["seed"]}, Size: {image.width}x{image.height}, Clip skip: 2, ENSD: 31337""" except Exception as e: errors.display(e, 'novelai image parser') + + try: + items['width'] = image.width + items['height'] = image.height + items['mode'] = image.mode + except Exception as e: + pass + return geninfo, items diff --git a/modules/processing.py b/modules/processing.py index 8a87ea68a..a68e113f8 100644 --- a/modules/processing.py +++ b/modules/processing.py @@ -58,7 +58,7 @@ def apply_color_correction(correction, original_image): return image -def apply_overlay(image, paste_loc, index, overlays): +def apply_overlay(image: Image, paste_loc, index, overlays): if overlays is None or index >= len(overlays): return image overlay = overlays[index] diff --git a/modules/ui_extra_networks.py b/modules/ui_extra_networks.py index 4150fc022..3cd5cdecd 100644 --- a/modules/ui_extra_networks.py +++ b/modules/ui_extra_networks.py @@ -440,6 +440,7 @@ class ExtraNetworksUi: self.details_components: list = [] self.last_item: dict = None self.last_page: ExtraNetworksPage = None + self.state: gr.State = None def create_ui(container, button_parent, tabname, skip_indexing = False): @@ -505,18 +506,18 @@ def create_ui(container, button_parent, tabname, skip_indexing = False): desc = gr.Textbox('', show_label=False, lines=8, placeholder="Extra network description...") ui.details_components.append(desc) with gr.Row(): - btn_save_desc = gr.Button('Save', elem_classes=['small-button']) - btn_delete_desc = gr.Button('Delete', elem_classes=['small-button']) - btn_close_info = gr.Button('Close', elem_classes=['small-button']) - btn_close_info.click(fn=lambda: gr.update(visible=False), inputs=[], outputs=[ui.details]) + btn_save_desc = gr.Button('Save', elem_classes=['small-button'], elem_id=f'{tabname}_extra_details_save_desc') + btn_delete_desc = gr.Button('Delete', elem_classes=['small-button'], elem_id=f'{tabname}_extra_details_delete_desc') + btn_close_desc = gr.Button('Close', elem_classes=['small-button'], elem_id=f'{tabname}_extra_details_close_desc') + btn_close_desc.click(fn=lambda: gr.update(visible=False), _js='refeshDetailsEN', inputs=[], outputs=[ui.details]) with gr.Tab('Model metadata'): info = gr.JSON({}, show_label=False) ui.details_components.append(info) with gr.Row(): - btn_save_info = gr.Button('Save', elem_classes=['small-button']) - btn_delete_info = gr.Button('Delete', elem_classes=['small-button']) - btn_close_info = gr.Button('Close', elem_classes=['small-button']) - btn_close_info.click(fn=lambda: gr.update(visible=False), inputs=[], outputs=[ui.details]) + btn_save_info = gr.Button('Save', elem_classes=['small-button'], elem_id=f'{tabname}_extra_details_save_info') + btn_delete_info = gr.Button('Delete', elem_classes=['small-button'], elem_id=f'{tabname}_extra_details_delete_info') + btn_close_info = gr.Button('Close', elem_classes=['small-button'], elem_id=f'{tabname}_extra_details_close_info') + btn_close_info.click(fn=lambda: gr.update(visible=False), _js='refeshDetailsEN', inputs=[], outputs=[ui.details]) with gr.Tab('Embedded metadata'): meta = gr.JSON({}, show_label=False) ui.details_components.append(meta) @@ -559,7 +560,7 @@ def create_ui(container, button_parent, tabname, skip_indexing = False): tab.select(ui_tab_change, _js="getENActivePage", inputs=[ui.button_details], outputs=[ui.button_scan, ui.button_save, ui.button_model]) # ui.tabs.change(fn=ui_tab_change, inputs=[], outputs=[ui.button_scan, ui.button_save]) - def fn_save_img(): + def fn_save_img(image): if ui.last_item is None or ui.last_item.local_preview is None: return 'html/card-no-preview.png' images = list(ui.gallery.temp_files) # gallery cannot be used as input component so looking at most recently registered temp files @@ -572,7 +573,7 @@ def create_ui(container, button_parent, tabname, skip_indexing = False): except Exception as e: shared.log.error(f'Extra network error opening image: item={ui.last_item.name} {e}') return 'html/card-no-preview.png' - fn_delete_img() + fn_delete_img(image) if image.width > 512 or image.height > 512: image = image.convert('RGB') image.thumbnail((512, 512), Image.HAMMING) @@ -583,7 +584,7 @@ def create_ui(container, button_parent, tabname, skip_indexing = False): shared.log.error(f'Extra network save image: item={ui.last_item.name} filename="{ui.last_item.local_preview}" {e}') return image - def fn_delete_img(): + def fn_delete_img(_image): preview_extensions = ["jpg", "jpeg", "png", "webp", "tiff", "jp2"] fn = os.path.splitext(ui.last_item.filename)[0] for file in [f'{fn}{mid}{ext}' for ext in preview_extensions for mid in ['.thumb.', '.preview.', '.']]: @@ -633,12 +634,12 @@ def create_ui(container, button_parent, tabname, skip_indexing = False): return '' return info - btn_save_img.click(fn=fn_save_img, inputs=[], outputs=[img]) - btn_delete_img.click(fn=fn_delete_img, inputs=[], outputs=[img]) - btn_save_desc.click(fn=fn_save_desc, inputs=[desc], outputs=[desc]) - btn_delete_desc.click(fn=fn_delete_desc, inputs=[desc], outputs=[desc]) - btn_save_info.click(fn=fn_save_info, inputs=[info], outputs=[info]) - btn_delete_info.click(fn=fn_delete_info, inputs=[info], outputs=[info]) + btn_save_img.click(fn=fn_save_img, _js='closeDetailsEN', inputs=[img], outputs=[img]) + btn_delete_img.click(fn=fn_delete_img, _js='closeDetailsEN', inputs=[img], outputs=[img]) + btn_save_desc.click(fn=fn_save_desc, _js='closeDetailsEN', inputs=[desc], outputs=[desc]) + btn_delete_desc.click(fn=fn_delete_desc, _js='closeDetailsEN', inputs=[desc], outputs=[desc]) + btn_save_info.click(fn=fn_save_info, _js='closeDetailsEN', inputs=[info], outputs=[info]) + btn_delete_info.click(fn=fn_delete_info, _js='closeDetailsEN', inputs=[info], outputs=[info]) def show_details(text, img, desc, info, meta, params): page, item = get_item(state, params) @@ -797,7 +798,7 @@ def create_ui(container, button_parent, tabname, skip_indexing = False): shared.log.debug(f'Extra networks: {msg}') return msg - dummy_state = gr.State(value=False) # pylint: disable=abstract-class-instantiated + dummy = gr.State(value=False) # pylint: disable=abstract-class-instantiated button_parent.click(fn=toggle_visibility, inputs=[ui.visible], outputs=[ui.visible, container, button_parent]) ui.button_close.click(fn=toggle_visibility, inputs=[ui.visible], outputs=[ui.visible, container]) ui.button_sort.click(fn=ui_sort_cards, _js='sortExtraNetworks', inputs=[ui.search], outputs=[ui.description]) @@ -806,7 +807,7 @@ def create_ui(container, button_parent, tabname, skip_indexing = False): ui.button_scan.click(fn=ui_scan_click, _js='getENActivePage', inputs=[ui.search], outputs=ui.pages) ui.button_save.click(fn=ui_save_click, inputs=[], outputs=ui.details_components + [ui.details]) ui.button_quicksave.click(fn=ui_quicksave_click, _js="() => prompt('Prompt name', '')", inputs=[ui.search], outputs=[]) - ui.button_details.click(show_details, _js="getCardDetails", inputs=ui.details_components + [dummy_state], outputs=ui.details_components + [ui.details]) + ui.button_details.click(show_details, _js="getCardDetails", inputs=ui.details_components + [dummy], outputs=ui.details_components + [ui.details]) ui.state.change(state_change, inputs=[ui.state], outputs=[]) return ui From fac360398ea645c5aa9f2e065ac957fa5f763756 Mon Sep 17 00:00:00 2001 From: Vladimir Mandic Date: Tue, 14 Nov 2023 17:16:59 -0500 Subject: [PATCH 22/84] update changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index c6b560f0b..1a52d1983 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -30,6 +30,7 @@ - **Extra networks** - Use multi-threading for 5x load speedup - Better Lora trigger words support + - Auto refresh styles on change - **General**: - Reworked parser when pasting previously generated images/prompts includes all `txt2img`, `img2img` and `override` params From 2f7e387246c5d4341ecef5b995cd7e312bb88688 Mon Sep 17 00:00:00 2001 From: Disty0 Date: Wed, 15 Nov 2023 01:20:36 +0300 Subject: [PATCH 23/84] Fix missing import --- extensions-builtin/Lora/networks.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/extensions-builtin/Lora/networks.py b/extensions-builtin/Lora/networks.py index 83df1699d..34b8af088 100644 --- a/extensions-builtin/Lora/networks.py +++ b/extensions-builtin/Lora/networks.py @@ -14,7 +14,7 @@ import network_norm import lora_convert import torch import diffusers.models.lora -from modules import shared, devices, sd_models, errors, scripts, sd_hijack +from modules import shared, devices, sd_models, sd_models_compile, errors, scripts, sd_hijack debug = os.environ.get('SD_LORA_DEBUG', None) @@ -193,7 +193,7 @@ def load_networks(names, te_multipliers=None, unet_multipliers=None, dyn_dims=No if recompile_model: shared.log.info("LoRA recompiling model") - sd_models.compile_diffusers(shared.sd_model) + sd_models_compile.compile_diffusers(shared.sd_model) def network_restore_weights_from_backup(self: Union[torch.nn.Conv2d, torch.nn.Linear, torch.nn.GroupNorm, torch.nn.LayerNorm, torch.nn.MultiheadAttention, diffusers.models.lora.LoRACompatibleLinear, diffusers.models.lora.LoRACompatibleConv]): From eb98547ab81226781882c0a50ad638b251c251b2 Mon Sep 17 00:00:00 2001 From: Vladimir Mandic Date: Tue, 14 Nov 2023 17:23:10 -0500 Subject: [PATCH 24/84] lint updates --- CHANGELOG.md | 1 + modules/images.py | 4 ++-- scripts/xyz_grid.py | 18 ++++++++++++++---- 3 files changed, 17 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1a52d1983..640b4c896 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -36,6 +36,7 @@ includes all `txt2img`, `img2img` and `override` params - Reworked **model compile** - Add refiner options to XYZ Grid + - Add option to create only subimages in XYZ grid, thanks @midcoastal - Support custom upscalers in subfolders - Add additional image info when loading image in process tab - Support `--ckpt none` to skip loading a model diff --git a/modules/images.py b/modules/images.py index 3987360b7..1cbc2d622 100644 --- a/modules/images.py +++ b/modules/images.py @@ -179,7 +179,7 @@ def draw_grid_annotations(im, width, height, hor_texts, ver_texts, margin=0, tit pad_top = 0 if sum(hor_text_heights) == 0 else max(hor_text_heights) + line_spacing * 2 title_pad = 0 if title: - title_text_heights = [sum([line.size[1] + line_spacing for line in lines]) - line_spacing for lines in title_texts] + title_text_heights = [sum([line.size[1] + line_spacing for line in lines]) - line_spacing for lines in title_texts] # pylint: disable=unsubscriptable-object title_pad = 0 if sum(title_text_heights) == 0 else max(title_text_heights) + line_spacing * 2 result = Image.new("RGB", (im.width + pad_left + margin * (cols-1), im.height + pad_top + title_pad + margin * (rows-1)), "white") for row in range(rows): @@ -695,7 +695,7 @@ Steps: {json_info["steps"]}, Sampler: {sampler}, CFG scale: {json_info["scale"]} items['width'] = image.width items['height'] = image.height items['mode'] = image.mode - except Exception as e: + except Exception: pass return geninfo, items diff --git a/scripts/xyz_grid.py b/scripts/xyz_grid.py index a8b809f93..ed3a2f388 100644 --- a/scripts/xyz_grid.py +++ b/scripts/xyz_grid.py @@ -1,4 +1,4 @@ - # pylint: disable=unused-argument, attribute-defined-outside-init +# pylint: disable=unused-argument import re import csv @@ -366,6 +366,14 @@ def draw_xyz_grid(p, xs, ys, zs, x_labels, y_labels, z_labels, cell, draw_legend class SharedSettingsStackHelper(object): + vae = None + schedulers_solver_order = None + token_merging_ratio_hr = None + token_merging_ratio = None + sd_model_checkpoint = None + sd_model_dict = None + sd_vae_checkpoint = None + def __enter__(self): #Save overridden settings so they can be restored later. self.vae = shared.opts.sd_vae @@ -398,6 +406,8 @@ re_range_count = re.compile(r"\s*([+-]?\s*\d+)\s*-\s*([+-]?\s*\d+)(?:\s*\[(\d+)\ re_range_count_float = re.compile(r"\s*([+-]?\s*\d+(?:.\d*)?)\s*-\s*([+-]?\s*\d+(?:.\d*)?)(?:\s*\[(\d+(?:.\d*)?)\s*])?\s*") class Script(scripts.Script): + current_axis_options = [] + def title(self): return "X/Y/Z Grid" @@ -716,8 +726,8 @@ class Script(scripts.Script): del processed.all_seeds[1] del processed.infotexts[1] elif no_grid: - ##del processed.images[0] - #del processed.all_prompts[0] - #del processed.all_seeds[0] + # del processed.images[0] + # del processed.all_prompts[0] + # del processed.all_seeds[0] del processed.infotexts[0] return processed From f3aa5ade133db0f86b6234aad7943784378e3ddb Mon Sep 17 00:00:00 2001 From: Vladimir Mandic Date: Tue, 14 Nov 2023 17:35:25 -0500 Subject: [PATCH 25/84] update changelog --- CHANGELOG.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 640b4c896..633d94f58 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,6 @@ # Change Log for SD.Next -## Update for 2023-11-13 +## Update for 2023-11-14 - **Diffusers** - **LCM** support for any *SD 1.5* or *SD-XL* model! @@ -9,14 +9,14 @@ - load **lcm lora** *(note: lcm lora is processed differently than any other lora)* - set **sampler** to **LCM** - set number of steps to some low number, for SD-XL 6-7 steps is normally sufficient - note: LCM scheduler does not support steps higher than 50 - - set CFG to 1-2 + note: LCM scheduler does not support steps higher than 50 + - set CFG to between 1 and 2 - Add `cli/lcm-convert.py` script to convert any SD 1.5 or SD-XL model to LCM model by baking in LORA and uploading to Huggingface, thanks @Disty0 - Support for [Stable Fast](https://github.com/chengzeyi/stable-fast) model compile on *Windows/Linux/WSL2* with *CUDA* See [Wiki:Benchmark](https://github.com/vladmandic/automatic/wiki/Benchmark) for details and comparisment of different backends, precision modes, advanced settings and compile modes - hint: **100+ it/s** on RTX4090 with no special tweaks + *Hint*: **100+ it/s** is possible on *RTX4090* with no special tweaks - Add additional pipeline types for manual model loads when loading from `safetensors` - Updated logic for calculating **steps** when using base/hires/refiner workflows - Safe model offloading for non-standard models From 69f0d41b995aa9268817d77b8dbf55cbbc8e0438 Mon Sep 17 00:00:00 2001 From: Disty0 Date: Wed, 15 Nov 2023 19:10:44 +0300 Subject: [PATCH 26/84] OpenVINO fix Lora caching --- extensions-builtin/Lora/networks.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/extensions-builtin/Lora/networks.py b/extensions-builtin/Lora/networks.py index 34b8af088..1e6f18b5c 100644 --- a/extensions-builtin/Lora/networks.py +++ b/extensions-builtin/Lora/networks.py @@ -149,7 +149,7 @@ def load_networks(names, te_multipliers=None, unet_multipliers=None, dyn_dims=No break else: recompile_model = True - shared.compiled_model_state.lora_model = [] + shared.compiled_model_state.lora_model = [] if recompile_model: sd_models.unload_model_weights(op='model') shared.opts.cuda_compile = False @@ -160,6 +160,8 @@ def load_networks(names, te_multipliers=None, unet_multipliers=None, dyn_dims=No net = None if network_on_disk is not None: try: + if recompile_model: + shared.compiled_model_state.lora_model.append(f"{name}:{te_multipliers[i] if te_multipliers else 1.0}") if shared.backend == shared.Backend.DIFFUSERS and (os.environ.get('SD_LORA_DIFFUSERS', None) or getattr(network_on_disk, 'shorthash', None) == 'aaebf6360f7d' # lcm sd15 or getattr(network_on_disk, 'shorthash', None) == '3d18b05e4f56'): # lcm sdxl From 1b9ca52afab17ea43f792c4750dc8b0d3824a68c Mon Sep 17 00:00:00 2001 From: Disty0 Date: Wed, 15 Nov 2023 19:44:33 +0300 Subject: [PATCH 27/84] OpenVINO use Diffusers Lora loading --- extensions-builtin/Lora/networks.py | 3 ++- installer.py | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/extensions-builtin/Lora/networks.py b/extensions-builtin/Lora/networks.py index 1e6f18b5c..9158143e2 100644 --- a/extensions-builtin/Lora/networks.py +++ b/extensions-builtin/Lora/networks.py @@ -164,7 +164,8 @@ def load_networks(names, te_multipliers=None, unet_multipliers=None, dyn_dims=No shared.compiled_model_state.lora_model.append(f"{name}:{te_multipliers[i] if te_multipliers else 1.0}") if shared.backend == shared.Backend.DIFFUSERS and (os.environ.get('SD_LORA_DIFFUSERS', None) or getattr(network_on_disk, 'shorthash', None) == 'aaebf6360f7d' # lcm sd15 - or getattr(network_on_disk, 'shorthash', None) == '3d18b05e4f56'): # lcm sdxl + or getattr(network_on_disk, 'shorthash', None) == '3d18b05e4f56' # lcm sdxl + or (shared.opts.cuda_compile and shared.opts.cuda_compile_backend == "openvino_fx")): net = load_diffusers(name, network_on_disk) else: net = load_network(name, network_on_disk) diff --git a/installer.py b/installer.py index adb57121f..590331323 100644 --- a/installer.py +++ b/installer.py @@ -516,7 +516,7 @@ def check_torch(): install('hidet', 'hidet') if args.use_openvino or opts.get('cuda_compile_backend', '') == 'openvino_fx': uninstall('openvino') - install('openvino-nightly==2023.2.0.dev20231102', 'openvino-nightly') + install('openvino-nightly==2023.3.0.dev20231114', 'openvino-nightly') install('onnxruntime-openvino', 'onnxruntime-openvino', ignore=True) # TODO numpy version conflicts with tensorflow and doesn't support Python 3.11 os.environ.setdefault('PYTORCH_TRACING_MODE', 'TORCHFX') os.environ.setdefault('NEOReadDebugKeys', '1') From b10cdb9d3e1c3a84ad32d9291b28db9ad08a96ab Mon Sep 17 00:00:00 2001 From: Vladimir Mandic Date: Wed, 15 Nov 2023 12:08:51 -0500 Subject: [PATCH 28/84] multiple cleanups --- modules/images.py | 4 ++-- modules/processing.py | 17 +++++++------- modules/processing_diffusers.py | 36 +++++++++++++++++++++++++---- modules/ui.py | 8 +++---- requirements.txt | 4 ++-- scripts/xyz_grid.py | 40 ++++++++++++++++----------------- 6 files changed, 68 insertions(+), 41 deletions(-) diff --git a/modules/images.py b/modules/images.py index 1cbc2d622..0d5d74de9 100644 --- a/modules/images.py +++ b/modules/images.py @@ -255,7 +255,7 @@ def resize_image(resize_mode, im, width, height, upscaler_name=None, output_type src_w = width if ratio > src_ratio else im.width * height // im.height src_h = height if ratio <= src_ratio else im.height * width // im.width resized = resize(im, src_w, src_h) - res = Image.new("RGB", (width, height)) + res = Image.new(im.mode, (width, height)) res.paste(resized, box=(width // 2 - src_w // 2, height // 2 - src_h // 2)) else: ratio = width / height @@ -263,7 +263,7 @@ def resize_image(resize_mode, im, width, height, upscaler_name=None, output_type src_w = width if ratio < src_ratio else im.width * height // im.height src_h = height if ratio >= src_ratio else im.height * width // im.width resized = resize(im, src_w, src_h) - res = Image.new("RGB", (width, height)) + res = Image.new(im.mode, (width, height)) res.paste(resized, box=(width // 2 - src_w // 2, height // 2 - src_h // 2)) if ratio < src_ratio: fill_height = height // 2 - src_h // 2 diff --git a/modules/processing.py b/modules/processing.py index a68e113f8..3c3faada5 100644 --- a/modules/processing.py +++ b/modules/processing.py @@ -686,6 +686,7 @@ def process_images(p: StableDiffusionProcessing) -> Processed: p.override_settings.pop(k, None) for k in p.override_settings.keys(): stored_opts[k] = shared.opts.data.get(k, None) or shared.opts.data_labels[k].default + res = None try: # if no checkpoint override or the override checkpoint can't be found, remove override entry and load opts checkpoint if p.override_settings.get('sd_model_checkpoint', None) is not None and modules.sd_models.checkpoint_aliases.get(p.override_settings.get('sd_model_checkpoint')) is None: @@ -1210,7 +1211,6 @@ class StableDiffusionProcessingImg2Img(StableDiffusionProcessing): def init(self, all_prompts, all_seeds, all_subseeds): if shared.backend == shared.Backend.DIFFUSERS and self.image_mask is not None: shared.sd_model = modules.sd_models.set_diffuser_pipe(self.sd_model, modules.sd_models.DiffusersTaskType.INPAINTING) - # self.sd_model.dtype = self.sd_model.unet.dtype elif shared.backend == shared.Backend.DIFFUSERS and self.image_mask is None: shared.sd_model = modules.sd_models.set_diffuser_pipe(self.sd_model, modules.sd_models.DiffusersTaskType.IMAGE_2_IMAGE) @@ -1225,6 +1225,7 @@ class StableDiffusionProcessingImg2Img(StableDiffusionProcessing): else: self.ops.append('img2img') crop_region = None + image_mask = self.image_mask if image_mask is not None: if type(image_mask) == list: @@ -1250,6 +1251,7 @@ class StableDiffusionProcessingImg2Img(StableDiffusionProcessing): self.mask_for_overlay = Image.fromarray(np_mask) self.overlay_images = [] latent_mask = self.latent_mask if self.latent_mask is not None else image_mask + add_color_corrections = shared.opts.img2img_color_correction and self.color_corrections is None if add_color_corrections: self.color_corrections = [] @@ -1280,14 +1282,12 @@ class StableDiffusionProcessingImg2Img(StableDiffusionProcessing): if crop_region is not None: image = image.crop(crop_region) image = images.resize_image(3, image, self.width, self.height) - if shared.backend == shared.Backend.DIFFUSERS: - unprocessed.append(image) - self.init_images = [image] # assign early for diffusers - if image_mask is not None: - if self.inpainting_fill != 1: - image = modules.masking.fill(image, latent_mask) + if image_mask is not None and self.inpainting_fill != 1: + image = modules.masking.fill(image, latent_mask) if add_color_corrections: self.color_corrections.append(setup_color_correction(image)) + if shared.backend == shared.Backend.DIFFUSERS: + unprocessed.append(image) # assign early for diffusers image = np.array(image).astype(np.float32) / 255.0 image = np.moveaxis(image, 2, 0) imgs.append(image) @@ -1304,8 +1304,7 @@ class StableDiffusionProcessingImg2Img(StableDiffusionProcessing): else: raise RuntimeError(f"bad number of images passed: {len(imgs)}; expecting {self.batch_size} or less") if shared.backend == shared.Backend.DIFFUSERS: - # we've already set self.init_images and self.mask and we dont need any more processing - return + return # we've already set self.init_images and self.mask and we dont need any more processing image = torch.from_numpy(batch_images) image = 2. * image - 1. diff --git a/modules/processing_diffusers.py b/modules/processing_diffusers.py index bf3b6d430..e3f330189 100644 --- a/modules/processing_diffusers.py +++ b/modules/processing_diffusers.py @@ -31,10 +31,10 @@ def process_diffusers(p: StableDiffusionProcessing, seeds, prompts, negative_pro p.height = tgt_height p.width = tgt_width hypertile_set(p) - if getattr(p, 'mask', None) is not None: - p.mask = images.resize_image(1, p.mask, tgt_width, tgt_height, upscaler_name=None) - if getattr(p, 'mask_for_overlay', None) is not None: - p.mask_for_overlay = images.resize_image(1, p.mask_for_overlay, tgt_width, tgt_height, upscaler_name=None) + if getattr(p, 'mask', None) is not None and p.mask.size != (tgt_width, tgt_height): + p.mask = images.resize_image(1, p.mask, tgt_width, tgt_height, upscaler_name=None) + if getattr(p, 'mask_for_overlay', None) is not None and p.mask_for_overlay.size != (tgt_width, tgt_height): + p.mask_for_overlay = images.resize_image(1, p.mask_for_overlay, tgt_width, tgt_height, upscaler_name=None) def hires_resize(latents): # input=latents output=pil latent_upscaler = shared.latent_upscale_modes.get(p.hr_upscaler, None) @@ -215,7 +215,30 @@ def process_diffusers(p: StableDiffusionProcessing, seeds, prompts, negative_pro p.mask = TF.to_pil_image(torch.ones_like(TF.to_tensor(p.init_images[0]))).convert("L") width = 8 * math.ceil(p.init_images[0].width / 8) height = 8 * math.ceil(p.init_images[0].height / 8) + + # option-1: use images as inputs task_args = {"image": p.init_images, "mask_image": p.mask, "strength": p.denoising_strength, "height": height, "width": width} + + """ # option-2: preprocess images into latents using diffusers + vae_scale_factor = 2 ** (len(model.vae.config.block_out_channels) - 1) + image_processor = diffusers.image_processor.VaeImageProcessor(vae_scale_factor=vae_scale_factor) + mask_processor = diffusers.image_processor.VaeImageProcessor(vae_scale_factor=vae_scale_factor, do_normalize=False, do_binarize=True, do_convert_grayscale=True) + init_image = image_processor.preprocess(p.init_images[0], width=width, height=height) + mask_image = mask_processor.preprocess(p.mask, width=width, height=height) + task_args = {"image": p.init_images, "mask_image": p.mask, "strength": p.denoising_strength, "height": height, "width": width} + """ + + """ # option-2: manually assemble masked image latents + masked_image_latents = [] + mask_image = TF.to_tensor(p.mask) + for init_image in p.init_images: + init_image = TF.to_tensor(p.init_images[0]) + masked_image = init_image * (mask_image > 0.5) + masked_image_latents.append(torch.cat([masked_image, mask_image], dim=0)) + masked_image_latents = torch.stack(masked_image_latents, dim=0).to(shared.device) + task_args = {"image": p.init_images, "mask_image": mask_image, "masked_image_latents": masked_image_latents, "strength": p.denoising_strength, "height": height, "width": width} + """ + if model.__class__.__name__ == 'LatentConsistencyModelPipeline' and hasattr(p, 'init_images') and len(p.init_images) > 0: init_latents = [vae_encode(image, model=shared.sd_model, full_quality=p.full_quality).squeeze(dim=0) for image in p.init_images] init_latent = torch.stack(init_latents, dim=0).to(shared.device) @@ -307,6 +330,8 @@ def process_diffusers(p: StableDiffusionProcessing, seeds, prompts, negative_pro clean['image'] = type(clean['image']) if 'mask_image' in clean: clean['mask_image'] = type(clean['mask_image']) + if 'masked_image_latents' in clean: + clean['masked_image_latents'] = type(clean['masked_image_latents']) if 'prompt' in clean: clean['prompt'] = len(clean['prompt']) if 'negative_prompt' in clean: @@ -408,6 +433,9 @@ def process_diffusers(p: StableDiffusionProcessing, seeds, prompts, negative_pro shared.log.debug(f'Steps: type=refiner input={p.refiner_steps} output={steps} start={p.refiner_start} denoise={p.denoising_strength}') return max(2, int(steps)) + a = 1 + a = (a * 2) + # pipeline type is set earlier in processing, but check for sanity if sd_models.get_diffusers_task(shared.sd_model) != sd_models.DiffusersTaskType.TEXT_2_IMAGE and len(getattr(p, 'init_images' ,[])) == 0: shared.sd_model = sd_models.set_diffuser_pipe(shared.sd_model, sd_models.DiffusersTaskType.TEXT_2_IMAGE) # reset pipeline diff --git a/modules/ui.py b/modules/ui.py index 507e628f6..0dcf9c25f 100644 --- a/modules/ui.py +++ b/modules/ui.py @@ -421,7 +421,7 @@ def create_ui(startup_timer = None): cfg_scale = gr.Slider(minimum=1.0, maximum=30.0, step=0.1, label='CFG scale', value=6.0, elem_id="txt2img_cfg_scale") clip_skip = gr.Slider(label='CLIP skip', value=1, minimum=1, maximum=14, step=1, elem_id='txt2img_clip_skip', interactive=True) with FormRow(): - image_cfg_scale = gr.Slider(minimum=1.1, maximum=30.0, step=0.1, label='Secondary CFG scale', value=6.0, elem_id="txt2img_image_cfg_scale") + image_cfg_scale = gr.Slider(minimum=1.0, maximum=30.0, step=0.1, label='Secondary CFG scale', value=6.0, elem_id="txt2img_image_cfg_scale") diffusers_guidance_rescale = gr.Slider(minimum=0.0, maximum=1.0, step=0.05, label='Guidance rescale', value=0.7, elem_id="txt2img_image_cfg_rescale") with FormRow(): full_quality = gr.Checkbox(label='Full quality', value=True, elem_id="txt2img_full_quality") @@ -711,8 +711,8 @@ def create_ui(startup_timer = None): with gr.Accordion(open=False, label="Advanced", elem_classes=["small-accordion"], elem_id="img2img_advanced_group"): with FormRow(): - cfg_scale = gr.Slider(minimum=1.0, maximum=30.0, step=0.5, label='CFG scale', value=6.0, elem_id="img2img_cfg_scale") - image_cfg_scale = gr.Slider(minimum=0, maximum=30.0, step=0.05, label='Image CFG scale', value=1.5, elem_id="img2img_image_cfg_scale") + cfg_scale = gr.Slider(minimum=1.0, maximum=30.0, step=0.1, label='CFG scale', value=6.0, elem_id="img2img_cfg_scale") + image_cfg_scale = gr.Slider(minimum=1.0, maximum=30.0, step=0.15, label='Image CFG scale', value=1.5, elem_id="img2img_image_cfg_scale") with FormRow(): clip_skip = gr.Slider(label='CLIP skip', value=1, minimum=1, maximum=4, step=1, elem_id='img2img_clip_skip', interactive=True) diffusers_guidance_rescale = gr.Slider(minimum=0.0, maximum=1.0, step=0.05, label='Guidance rescale', value=0.7, elem_id="txt2img_image_cfg_rescale") @@ -729,7 +729,7 @@ def create_ui(startup_timer = None): with gr.Column(): inpainting_mask_invert = gr.Radio(label='Mask mode', choices=['Inpaint masked', 'Inpaint not masked'], value='Inpaint masked', type="index", elem_id="img2img_mask_mode") with gr.Column(): - inpainting_fill = gr.Radio(label='Masked content', choices=['fill', 'original', 'latent noise', 'latent nothing'], value='original', type="index", elem_id="img2img_inpainting_fill") + inpainting_fill = gr.Radio(label='Masked content', choices=['fill', 'original', 'noise', 'nothing'], value='original', type="index", elem_id="img2img_inpainting_fill") with FormRow(): with gr.Column(): inpaint_full_res = gr.Radio(label="Inpaint area", choices=["Whole picture", "Only masked"], type="index", value="Whole picture", elem_id="img2img_inpaint_full_res") diff --git a/requirements.txt b/requirements.txt index b62ebcb89..4207bf910 100644 --- a/requirements.txt +++ b/requirements.txt @@ -53,14 +53,14 @@ opencv-python-headless==4.7.0.72 diffusers==0.23.0 einops==0.4.1 gradio==3.43.2 -huggingface_hub==0.18.0 +huggingface_hub==0.19.2 numexpr==2.8.4 numpy==1.24.4 numba==0.57.1 pandas==1.5.3 protobuf==3.20.3 pytorch_lightning==1.9.4 -transformers==4.34.1 +transformers==4.35.1 tomesd==0.1.3 urllib3==1.26.15 Pillow==9.5.0 diff --git a/scripts/xyz_grid.py b/scripts/xyz_grid.py index ed3a2f388..ad8cb65af 100644 --- a/scripts/xyz_grid.py +++ b/scripts/xyz_grid.py @@ -236,29 +236,29 @@ axis_options = [ AxisOption("Clip skip", int, apply_clip_skip), AxisOption("Denoising strength", float, apply_field("denoising_strength")), AxisOption("Prompt order", str_permutations, apply_order, fmt=format_value_join_list), + AxisOption("Model dictionary", str, apply_dict, fmt=format_value, cost=1.0, choices=lambda: ['None'] + list(sd_models.checkpoints_list)), + AxisOptionImg2Img("Image mask weight", float, apply_field("inpainting_mask_weight")), AxisOption("[Postprocess] Upscaler", str, apply_upscaler, choices=lambda: [x.name for x in shared.sd_upscalers][1:]), AxisOption("[Postprocess] Face restore", str, apply_face_restore, fmt=format_value), - AxisOptionImg2Img("Image mask weight", float, apply_field("inpainting_mask_weight")), - AxisOption("Model dictionary", str, apply_dict, fmt=format_value, cost=1.0, choices=lambda: ['None'] + list(sd_models.checkpoints_list)), - AxisOption("[Sampler] sigma min", float, apply_field("s_min")), - AxisOption("[Sampler] sigma max", float, apply_field("s_max")), - AxisOption("[Sampler] sigma tmin", float, apply_field("s_tmin")), - AxisOption("[Sampler] sigma tmax", float, apply_field("s_tmax")), - AxisOption("[Sampler] sigma Churn", float, apply_field("s_churn")), - AxisOption("[Sampler] sigma noise", float, apply_field("s_noise")), - AxisOption("[Sampler] eta", float, apply_field("eta")), - AxisOption("[Sampler] solver order", int, apply_setting("schedulers_solver_order")), - AxisOption("[Second pass] upscaler", str, apply_field("hr_upscaler"), choices=lambda: [*shared.latent_upscale_modes, *[x.name for x in shared.sd_upscalers]]), - AxisOption("[Second pass] sampler", str, apply_latent_sampler, fmt=format_value, confirm=confirm_samplers, choices=lambda: [x.name for x in sd_samplers.samplers]), - AxisOption("[Second pass] denoising Strength", float, apply_field("denoising_strength")), - AxisOption("[Second pass] hires steps", int, apply_field("hr_second_pass_steps")), + AxisOption("[Sampler] Sigma min", float, apply_field("s_min")), + AxisOption("[Sampler] Sigma max", float, apply_field("s_max")), + AxisOption("[Sampler] Sigma tmin", float, apply_field("s_tmin")), + AxisOption("[Sampler] Sigma tmax", float, apply_field("s_tmax")), + AxisOption("[Sampler] Sigma Churn", float, apply_field("s_churn")), + AxisOption("[Sampler] Sigma noise", float, apply_field("s_noise")), + AxisOption("[Sampler] ETA", float, apply_field("eta")), + AxisOption("[Sampler] Solver order", int, apply_setting("schedulers_solver_order")), + AxisOption("[Second pass] Upscaler", str, apply_field("hr_upscaler"), choices=lambda: [*shared.latent_upscale_modes, *[x.name for x in shared.sd_upscalers]]), + AxisOption("[Second pass] Sampler", str, apply_latent_sampler, fmt=format_value, confirm=confirm_samplers, choices=lambda: [x.name for x in sd_samplers.samplers]), + AxisOption("[Second pass] Denoising Strength", float, apply_field("denoising_strength")), + AxisOption("[Second pass] Hires steps", int, apply_field("hr_second_pass_steps")), AxisOption("[Second pass] CFG scale", float, apply_field("image_cfg_scale")), - AxisOption("[Second pass] guidance rescale", float, apply_field("diffusers_guidance_rescale")), - AxisOption("[Refiner] model", str, apply_refiner, fmt=format_value, cost=1.0, choices=lambda: ['None'] + sorted(sd_models.checkpoints_list)), - AxisOption("[Refiner] refiner start", float, apply_field("refiner_start")), - AxisOption("[Refiner] refiner steps", float, apply_field("refiner_steps")), - AxisOption("[TOME] Token merging ratio (txt2img)", float, apply_override('token_merging_ratio')), - AxisOption("[TOME] Token merging ratio (hires)", float, apply_override('token_merging_ratio_hr')), + AxisOption("[Second pass] Guidance rescale", float, apply_field("diffusers_guidance_rescale")), + AxisOption("[Refiner] Model", str, apply_refiner, fmt=format_value, cost=1.0, choices=lambda: ['None'] + sorted(sd_models.checkpoints_list)), + AxisOption("[Refiner] Refiner start", float, apply_field("refiner_start")), + AxisOption("[Refiner] Refiner steps", float, apply_field("refiner_steps")), + AxisOption("[ToMe] Token merging ratio (txt2img)", float, apply_override('token_merging_ratio')), + AxisOption("[ToMe] Token merging ratio (hires)", float, apply_override('token_merging_ratio_hr')), AxisOption("[FreeU] 1st stage backbone factor", float, apply_setting('freeu_b1')), AxisOption("[FreeU] 2nd stage backbone factor", float, apply_setting('freeu_b2')), AxisOption("[FreeU] 1st stage skip factor", float, apply_setting('freeu_s1')), From f5f14282fbf5ea52efe08c692a8e267711d392f1 Mon Sep 17 00:00:00 2001 From: Disty0 Date: Wed, 15 Nov 2023 20:35:50 +0300 Subject: [PATCH 29/84] OpenVINO move caches to compiled_model_state --- modules/intel/openvino/__init__.py | 25 ++++++------------------- modules/sd_models_compile.py | 5 +++-- modules/upscaler.py | 12 +----------- 3 files changed, 10 insertions(+), 32 deletions(-) diff --git a/modules/intel/openvino/__init__.py b/modules/intel/openvino/__init__.py index 34f575e3e..e1bafb0a7 100644 --- a/modules/intel/openvino/__init__.py +++ b/modules/intel/openvino/__init__.py @@ -33,10 +33,7 @@ def BUILD_MAP_UNPACK(self, inst): ) tmp_torch = sys.modules["torch"] tmp_torch.BUILD_MAP_UNPACK_WITH_CALL = BUILD_MAP_UNPACK - -compiled_cache = {} max_openvino_partitions = 0 -partitioned_modules = {} DEFAULT_OPENVINO_PYTHON_CONFIG = MappingProxyType( { @@ -180,13 +177,6 @@ def execute_cached(compiled_model, *args): result = [torch.from_numpy(res[out]) for out in compiled_model.outputs] return result -def openvino_clear_caches(): - global partitioned_modules - global compiled_cache - - compiled_cache.clear() - partitioned_modules.clear() - def openvino_compile(gm: GraphModule, *args, model_hash_str: str = None, file_name=""): core = Core() @@ -279,21 +269,20 @@ def openvino_execute(gm: GraphModule, *args, executor_parameters=None, partition "use_python_fusion_cache", DEFAULT_OPENVINO_PYTHON_CONFIG["use_python_fusion_cache"], ) - global compiled_cache model_hash_str = executor_parameters.get("model_hash_str", None) if model_hash_str is not None: model_hash_str = model_hash_str + str(partition_id) - if use_cache and (partition_id in compiled_cache): - compiled = compiled_cache[partition_id] + if use_cache and (partition_id in shared.compiled_model_state.compiled_cache): + compiled = shared.compiled_model_state.compiled_cache[partition_id] else: if (shared.compiled_model_state.cn_model != [] and file_name is not None and os.path.isfile(file_name + ".xml") and os.path.isfile(file_name + ".bin")): compiled = openvino_compile_cached_model(file_name, *args) else: compiled = openvino_compile(gm, *args, model_hash_str=model_hash_str, file_name=file_name) - compiled_cache[partition_id] = compiled + shared.compiled_model_state.compiled_cache[partition_id] = compiled flat_args, _ = tree_flatten(args) ov_inputs = [a.detach().cpu().numpy() for a in flat_args] @@ -308,8 +297,6 @@ def openvino_execute(gm: GraphModule, *args, executor_parameters=None, partition def openvino_execute_partitioned(gm: GraphModule, *args, executor_parameters=None, file_name=""): executor_parameters = executor_parameters or DEFAULT_OPENVINO_PYTHON_CONFIG - global partitioned_modules - use_python_fusion_cache = executor_parameters.get( "use_python_fusion_cache", DEFAULT_OPENVINO_PYTHON_CONFIG["use_python_fusion_cache"], @@ -323,11 +310,11 @@ def openvino_execute_partitioned(gm: GraphModule, *args, executor_parameters=Non else: signature = signature + "_" + str(idx) + ":" + type(input_data).__name__ + ":val(" + str(input_data) + ")" - if signature not in partitioned_modules: - partitioned_modules[signature] = partition_graph(gm, use_python_fusion_cache=use_python_fusion_cache, + if signature not in shared.compiled_model_state.partitioned_modules: + shared.compiled_model_state.partitioned_modules[signature] = partition_graph(gm, use_python_fusion_cache=use_python_fusion_cache, model_hash_str=model_hash_str, file_name=file_name) - return partitioned_modules[signature](*args) + return shared.compiled_model_state.partitioned_modules[signature](*args) def partition_graph(gm: GraphModule, use_python_fusion_cache: bool, model_hash_str: str = None, file_name=""): global max_openvino_partitions diff --git a/modules/sd_models_compile.py b/modules/sd_models_compile.py index b373f902e..a086409fe 100644 --- a/modules/sd_models_compile.py +++ b/modules/sd_models_compile.py @@ -15,6 +15,8 @@ class CompiledModelState: self.partition_id = 0 self.cn_model = [] self.lora_model = [] + self.compiled_cache = {} + self.partitioned_modules = {} def optimize_ipex(sd_model): @@ -37,8 +39,7 @@ def optimize_ipex(sd_model): def optimize_openvino(): try: - from modules.intel.openvino import openvino_fx, openvino_clear_caches # pylint: disable=unused-import - openvino_clear_caches() + from modules.intel.openvino import openvino_fx # pylint: disable=unused-import torch._dynamo.eval_frame.check_if_dynamo_supported = lambda: True # pylint: disable=protected-access if shared.compiled_model_state is None: shared.compiled_model_state = CompiledModelState() diff --git a/modules/upscaler.py b/modules/upscaler.py index 4887ce1a7..e9ec14a54 100644 --- a/modules/upscaler.py +++ b/modules/upscaler.py @@ -226,20 +226,12 @@ def compile_upscaler(model, name=""): modules.shared.log.info(f"Upscaler Compiling: {name} mode={modules.shared.opts.cuda_compile_backend}") import logging import torch._dynamo # pylint: disable=unused-import,redefined-outer-name - use_old_compiled_model_state = False if modules.shared.opts.cuda_compile_backend == "openvino_fx": - from modules.intel.openvino import openvino_fx, openvino_clear_caches # pylint: disable=unused-import + from modules.intel.openvino import openvino_fx # pylint: disable=unused-import from modules.sd_models_compile import CompiledModelState - - openvino_clear_caches() torch._dynamo.eval_frame.check_if_dynamo_supported = lambda: True # pylint: disable=protected-access - if modules.shared.compiled_model_state is not None: - use_old_compiled_model_state = True - old_compiled_model_state = modules.shared.compiled_model_state - modules.shared.compiled_model_state = CompiledModelState() - log_level = logging.WARNING if modules.shared.opts.cuda_compile_verbose else logging.CRITICAL # pylint: disable=protected-access if hasattr(torch, '_logging'): torch._logging.set_logs(dynamo=log_level, aot=log_level, inductor=log_level) # pylint: disable=protected-access @@ -248,8 +240,6 @@ def compile_upscaler(model, name=""): torch._dynamo.config.suppress_errors = modules.shared.opts.cuda_compile_errors # pylint: disable=protected-access model = torch.compile(model, mode=modules.shared.opts.cuda_compile_mode, backend=modules.shared.opts.cuda_compile_backend, fullgraph=modules.shared.opts.cuda_compile_fullgraph) # pylint: disable=attribute-defined-outside-init - if use_old_compiled_model_state: - modules.shared.compiled_model_state = old_compiled_model_state modules.shared.log.info("Upscaler: Complilation done.") except Exception as err: modules.shared.log.warning(f"Model compile not supported: {err}") From bb0430f5c10abe262dee694d12a27872ae0e536f Mon Sep 17 00:00:00 2001 From: Disty0 Date: Wed, 15 Nov 2023 22:33:13 +0300 Subject: [PATCH 30/84] OpenVINO downgrade PyTorch --- extensions-builtin/Lora/networks.py | 2 +- installer.py | 31 ++++++++++++++++++++++++++++- 2 files changed, 31 insertions(+), 2 deletions(-) diff --git a/extensions-builtin/Lora/networks.py b/extensions-builtin/Lora/networks.py index 9158143e2..bf64d3171 100644 --- a/extensions-builtin/Lora/networks.py +++ b/extensions-builtin/Lora/networks.py @@ -149,7 +149,7 @@ def load_networks(names, te_multipliers=None, unet_multipliers=None, dyn_dims=No break else: recompile_model = True - shared.compiled_model_state.lora_model = [] + shared.compiled_model_state.lora_model = [] if recompile_model: sd_models.unload_model_weights(op='model') shared.opts.cuda_compile = False diff --git a/installer.py b/installer.py index 590331323..78b530bc0 100644 --- a/installer.py +++ b/installer.py @@ -447,7 +447,36 @@ def check_torch(): install('onnxruntime-openvino', 'onnxruntime-openvino', ignore=True) # TODO numpy version conflicts with tensorflow and doesn't support Python 3.11 elif allow_openvino and args.use_openvino: log.info('Using OpenVINO') - torch_command = os.environ.get('TORCH_COMMAND', 'torch==2.1.0 torchvision==0.16.0 --index-url https://download.pytorch.org/whl/cpu') + if "linux" in sys.platform: + if sys.version_info[1] == 11: + pytorch_pip = 'https://github.com/Disty0/automatic/releases/download/openvino_pre_release_pytorch/torch-2.1.0.dev20230820+cpu-cp311-cp311-linux_x86_64.whl' + torchvision_pip = 'https://github.com/Disty0/automatic/releases/download/openvino_pre_release_pytorch/torchvision-0.16.0.dev20230820+cpu-cp311-cp311-linux_x86_64.whl' + elif sys.version_info[1] == 10: + pytorch_pip = 'https://github.com/Disty0/automatic/releases/download/openvino_pre_release_pytorch/torch-2.1.0.dev20230820+cpu-cp310-cp310-linux_x86_64.whl' + torchvision_pip = 'https://github.com/Disty0/automatic/releases/download/openvino_pre_release_pytorch/torchvision-0.16.0.dev20230820+cpu-cp310-cp310-linux_x86_64.whl' + elif sys.version_info[1] == 8: + pytorch_pip = 'https://github.com/Disty0/automatic/releases/download/openvino_pre_release_pytorch/torch-2.1.0.dev20230820+cpu-cp38-cp38-linux_x86_64.whl' + torchvision_pip = 'https://github.com/Disty0/automatic/releases/download/openvino_pre_release_pytorch/torchvision-0.16.0.dev20230820+cpu-cp38-cp38-linux_x86_64.whl' + else: + pytorch_pip = 'torch==2.1.0' + torchvision_pip = 'torchvision==0.16.0 --index-url https://download.pytorch.org/whl/cpu' + elif sys.platform == 'darwin': + pytorch_pip = 'torch==2.1.0' + torchvision_pip = 'torchvision==0.16.0 --index-url https://download.pytorch.org/whl/cpu' + else: + if sys.version_info[1] == 11: + pytorch_pip = 'https://github.com/Disty0/automatic/releases/download/openvino_pre_release_pytorch/torch-2.1.0.dev20230820+cpu-cp311-cp311-win_amd64.whl' + torchvision_pip = 'https://github.com/Disty0/automatic/releases/download/openvino_pre_release_pytorch/torchvision-0.16.0.dev20230820+cpu-cp311-cp311-win_amd64.whl' + elif sys.version_info[1] == 10: + pytorch_pip = 'https://github.com/Disty0/automatic/releases/download/openvino_pre_release_pytorch/torch-2.1.0.dev20230820+cpu-cp310-cp310-win_amd64.whl' + torchvision_pip = 'https://github.com/Disty0/automatic/releases/download/openvino_pre_release_pytorch/torchvision-0.16.0.dev20230820+cpu-cp310-cp310-win_amd64.whl' + elif sys.version_info[1] == 8: + pytorch_pip = 'https://github.com/Disty0/automatic/releases/download/openvino_pre_release_pytorch/torch-2.1.0.dev20230820+cpu-cp38-cp38-win_amd64.whl' + torchvision_pip = 'https://github.com/Disty0/automatic/releases/download/openvino_pre_release_pytorch/torchvision-0.16.0.dev20230820+cpu-cp38-cp38-win_amd64.whl' + else: + pytorch_pip = 'torch==2.1.0' + torchvision_pip = 'torchvision==0.16.0 --index-url https://download.pytorch.org/whl/cpu' + torch_command = os.environ.get('TORCH_COMMAND', f'{pytorch_pip} {torchvision_pip}') else: machine = platform.machine() if sys.platform == 'darwin': From e9b31096500477fe51fb10e15f58596a196a4c30 Mon Sep 17 00:00:00 2001 From: Vladimir Mandic Date: Wed, 15 Nov 2023 15:00:46 -0500 Subject: [PATCH 31/84] fix invalid tags --- extensions-builtin/Lora/ui_extra_networks_lora.py | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/extensions-builtin/Lora/ui_extra_networks_lora.py b/extensions-builtin/Lora/ui_extra_networks_lora.py index ffc0d95ee..f029aaf05 100644 --- a/extensions-builtin/Lora/ui_extra_networks_lora.py +++ b/extensions-builtin/Lora/ui_extra_networks_lora.py @@ -56,7 +56,8 @@ class ExtraNetworksPageLora(ui_extra_networks.ExtraNetworksPage): words = [str(w).replace('.json', '') for w in words] if words[0] == '{}': words[0] = 0 - tags[' '.join(words[1:])] = words[0] + tag = ' '.join(words[1:]) + tags[tag] = words[0] versions = info.get('modelVersions', []) # trigger words from info json for v in versions: possible_tags = v.get('trainedWords', []) @@ -73,9 +74,15 @@ class ExtraNetworksPageLora(ui_extra_networks.ExtraNetworksPage): if len(list(tags)) == 0: tags = search + bad_chars = [';', ':', '<', ">", "*", '?', '\'', '\"'] + clean_tags = {} + for k, v in tags.items(): + tag = ''.join(i for i in k if not i in bad_chars) + clean_tags[tag] = v + item["info"] = info item["description"] = self.find_description(l.filename, info) # use existing info instead of double-read - item["tags"] = tags + item["tags"] = clean_tags item["search_term"] = f'{self.search_terms_from_path(l.filename)} {" ".join(tags.keys())} {" ".join(search.keys())}' return item From 247a30a42c9302f78f31b39d458f74662598e11a Mon Sep 17 00:00:00 2001 From: Disty0 Date: Wed, 15 Nov 2023 23:45:53 +0300 Subject: [PATCH 32/84] OpenVINO disable model caching --- modules/sd_models_compile.py | 3 +++ modules/shared.py | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/modules/sd_models_compile.py b/modules/sd_models_compile.py index a086409fe..9b8fe912a 100644 --- a/modules/sd_models_compile.py +++ b/modules/sd_models_compile.py @@ -43,6 +43,9 @@ def optimize_openvino(): torch._dynamo.eval_frame.check_if_dynamo_supported = lambda: True # pylint: disable=protected-access if shared.compiled_model_state is None: shared.compiled_model_state = CompiledModelState() + else: + shared.compiled_model_state.compiled_cache.clear() + shared.compiled_model_state.partitioned_modules.clear() shared.compiled_model_state.first_pass = True if not shared.opts.cuda_compile_precompile else False except Exception as e: shared.log.warning(f"Model compile: task=OpenVINO: {e}") diff --git a/modules/shared.py b/modules/shared.py index 17ce2bd54..817ffef5f 100644 --- a/modules/shared.py +++ b/modules/shared.py @@ -300,7 +300,7 @@ options_templates.update(options_section(('cuda', "Compute Settings"), { "ipex_optimize_upscaler": OptionInfo(True if devices.backend == "ipex" else False, "Enable IPEX Optimize for Intel GPUs with Upscalers"), "directml_memory_provider": OptionInfo(default_memory_provider, 'DirectML memory stats provider', gr.Radio, {"choices": memory_providers}), "directml_catch_nan": OptionInfo(False, "DirectML retry specific operation when NaN is produced if possible. (makes generation slower)"), - "openvino_disable_model_caching": OptionInfo(False, "OpenVINO disable model caching"), + "openvino_disable_model_caching": OptionInfo(True, "OpenVINO disable model caching"), "openvino_hetero_gpu": OptionInfo(False, "OpenVINO use Hetero Device for single inference with multiple devices"), "openvino_remove_cpu_from_hetero": OptionInfo(False, "OpenVINO remove CPU from Hetero Device"), "openvino_remove_igpu_from_hetero": OptionInfo(False, "OpenVINO remove iGPU from Hetero Device"), From d7410655cf7c467b653d75780ec2ff73908f4bb1 Mon Sep 17 00:00:00 2001 From: Disty0 Date: Thu, 16 Nov 2023 00:19:32 +0300 Subject: [PATCH 33/84] Cleanup --- extensions-builtin/Lora/networks.py | 6 +++++- modules/shared.py | 2 +- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/extensions-builtin/Lora/networks.py b/extensions-builtin/Lora/networks.py index bf64d3171..1db5c25df 100644 --- a/extensions-builtin/Lora/networks.py +++ b/extensions-builtin/Lora/networks.py @@ -146,11 +146,15 @@ def load_networks(names, te_multipliers=None, unet_multipliers=None, dyn_dims=No for i, name in enumerate(names): if shared.compiled_model_state.lora_model[i] != f"{name}:{te_multipliers[i] if te_multipliers else 1.0}": recompile_model = True + shared.compiled_model_state.lora_model = [] break else: recompile_model = True - shared.compiled_model_state.lora_model = [] + shared.compiled_model_state.lora_model = [] if recompile_model: + if not shared.opts.openvino_disable_model_caching: + shared.log.warning("LoRa: Disabling OpenVINO model caching") + shared.opts.openvino_disable_model_caching = True sd_models.unload_model_weights(op='model') shared.opts.cuda_compile = False sd_models.reload_model_weights(op='model') diff --git a/modules/shared.py b/modules/shared.py index 817ffef5f..17ce2bd54 100644 --- a/modules/shared.py +++ b/modules/shared.py @@ -300,7 +300,7 @@ options_templates.update(options_section(('cuda', "Compute Settings"), { "ipex_optimize_upscaler": OptionInfo(True if devices.backend == "ipex" else False, "Enable IPEX Optimize for Intel GPUs with Upscalers"), "directml_memory_provider": OptionInfo(default_memory_provider, 'DirectML memory stats provider', gr.Radio, {"choices": memory_providers}), "directml_catch_nan": OptionInfo(False, "DirectML retry specific operation when NaN is produced if possible. (makes generation slower)"), - "openvino_disable_model_caching": OptionInfo(True, "OpenVINO disable model caching"), + "openvino_disable_model_caching": OptionInfo(False, "OpenVINO disable model caching"), "openvino_hetero_gpu": OptionInfo(False, "OpenVINO use Hetero Device for single inference with multiple devices"), "openvino_remove_cpu_from_hetero": OptionInfo(False, "OpenVINO remove CPU from Hetero Device"), "openvino_remove_igpu_from_hetero": OptionInfo(False, "OpenVINO remove iGPU from Hetero Device"), From 6e994ff110a2108ca408584c204223f2aac5b1d4 Mon Sep 17 00:00:00 2001 From: Disty0 Date: Thu, 16 Nov 2023 01:07:09 +0300 Subject: [PATCH 34/84] OpenVINO fix Lora not loading on model change --- extensions-builtin/Lora/networks.py | 1 + modules/sd_models_compile.py | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/extensions-builtin/Lora/networks.py b/extensions-builtin/Lora/networks.py index 1db5c25df..9897decab 100644 --- a/extensions-builtin/Lora/networks.py +++ b/extensions-builtin/Lora/networks.py @@ -155,6 +155,7 @@ def load_networks(names, te_multipliers=None, unet_multipliers=None, dyn_dims=No if not shared.opts.openvino_disable_model_caching: shared.log.warning("LoRa: Disabling OpenVINO model caching") shared.opts.openvino_disable_model_caching = True + shared.compiled_model_state.lora_compile = True sd_models.unload_model_weights(op='model') shared.opts.cuda_compile = False sd_models.reload_model_weights(op='model') diff --git a/modules/sd_models_compile.py b/modules/sd_models_compile.py index 9b8fe912a..711245754 100644 --- a/modules/sd_models_compile.py +++ b/modules/sd_models_compile.py @@ -15,6 +15,7 @@ class CompiledModelState: self.partition_id = 0 self.cn_model = [] self.lora_model = [] + self.lora_compile = False self.compiled_cache = {} self.partitioned_modules = {} @@ -44,6 +45,9 @@ def optimize_openvino(): if shared.compiled_model_state is None: shared.compiled_model_state = CompiledModelState() else: + if not shared.compiled_model_state.lora_compile: + shared.compiled_model_state.lora_compile = False + shared.compiled_model_state.lora_model = [] shared.compiled_model_state.compiled_cache.clear() shared.compiled_model_state.partitioned_modules.clear() shared.compiled_model_state.first_pass = True if not shared.opts.cuda_compile_precompile else False From 4ea908ccd4a18309688dc812bb081c8f56072bfc Mon Sep 17 00:00:00 2001 From: Vladimir Mandic Date: Thu, 16 Nov 2023 09:55:15 -0500 Subject: [PATCH 35/84] cleanup --- extensions-builtin/Lora/networks.py | 2 +- modules/processing_diffusers.py | 3 --- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/extensions-builtin/Lora/networks.py b/extensions-builtin/Lora/networks.py index 9897decab..6b638fcda 100644 --- a/extensions-builtin/Lora/networks.py +++ b/extensions-builtin/Lora/networks.py @@ -175,7 +175,7 @@ def load_networks(names, te_multipliers=None, unet_multipliers=None, dyn_dims=No else: net = load_network(name, network_on_disk) except Exception as e: - shared.log.error(f"LoRA load failed: file={network_on_disk.filename}") + shared.log.error(f"LoRA load failed: file={network_on_disk.filename} {e}") if debug: errors.display(e, f"LoRA load failed file={network_on_disk.filename}") continue diff --git a/modules/processing_diffusers.py b/modules/processing_diffusers.py index e3f330189..fc18fa8b9 100644 --- a/modules/processing_diffusers.py +++ b/modules/processing_diffusers.py @@ -433,9 +433,6 @@ def process_diffusers(p: StableDiffusionProcessing, seeds, prompts, negative_pro shared.log.debug(f'Steps: type=refiner input={p.refiner_steps} output={steps} start={p.refiner_start} denoise={p.denoising_strength}') return max(2, int(steps)) - a = 1 - a = (a * 2) - # pipeline type is set earlier in processing, but check for sanity if sd_models.get_diffusers_task(shared.sd_model) != sd_models.DiffusersTaskType.TEXT_2_IMAGE and len(getattr(p, 'init_images' ,[])) == 0: shared.sd_model = sd_models.set_diffuser_pipe(shared.sd_model, sd_models.DiffusersTaskType.TEXT_2_IMAGE) # reset pipeline From cc19925baed7cebe6556b0df1f815a0d220672e4 Mon Sep 17 00:00:00 2001 From: Disty0 Date: Thu, 16 Nov 2023 19:22:04 +0300 Subject: [PATCH 36/84] Fix Diffusers steps logic --- modules/processing_diffusers.py | 34 +++++++++++++++++++++++---------- 1 file changed, 24 insertions(+), 10 deletions(-) diff --git a/modules/processing_diffusers.py b/modules/processing_diffusers.py index fc18fa8b9..59ec22a41 100644 --- a/modules/processing_diffusers.py +++ b/modules/processing_diffusers.py @@ -408,27 +408,41 @@ def process_diffusers(p: StableDiffusionProcessing, seeds, prompts, negative_pro use_denoise_start = bool(is_img2img and p.refiner_start > 0 and p.refiner_start < 1) def calculate_base_steps(): - steps = p.steps - if use_refiner_start: - steps = (p.steps // (1.0 - p.refiner_start)) if shared.sd_model_type == 'sdxl' else p.steps + if is_img2img: + if use_denoise_start and shared.sd_model_type == 'sdxl': + steps = p.steps // (1 - p.refiner_start) + else: + steps = (p.steps // p.denoising_strength) + 1 + elif use_refiner_start and shared.sd_model_type == 'sdxl': + steps = (p.steps // p.refiner_start) + 1 + else: + steps = p.steps + if os.environ.get('SD_STEPS_DEBUG', None) is not None: shared.log.debug(f'Steps: type=base input={p.steps} output={steps} refiner={use_refiner_start}') return max(2, int(steps)) def calculate_hires_steps(): - # denoising strength is applied to steps by diffusers so this is no-op - # steps = (p.hr_second_pass_steps * p.denoising_strength) if p.hr_second_pass_steps > 0 else (p.steps * p.denoising_strength) - steps = p.hr_second_pass_steps if p.hr_second_pass_steps > 0 else p.steps + if p.hr_second_pass_steps > 0: + steps = (p.hr_second_pass_steps // p.denoising_strength) + 1 + else: + steps = (p.steps // p.denoising_strength) + 1 + if os.environ.get('SD_STEPS_DEBUG', None) is not None: shared.log.debug(f'Steps: type=hires input={p.hr_second_pass_steps} output={steps} denoise={p.denoising_strength}') return max(2, int(steps)) def calculate_refiner_steps(): - # diffusers apply additional math to refiner steps, but we leave numbers as-is without correction - if p.refiner_start > 0 and p.refiner_start < 1: - steps = ((1 - p.refiner_start) * p.refiner_steps) if p.refiner_steps > 0 else ((1 - p.refiner_start) * p.steps) + if "StableDiffusionXL" in shared.sd_refiner.__class__.__name__: + if p.refiner_start > 0 and p.refiner_start < 1: + #steps = p.refiner_steps // (1 - p.refiner_start) # SDXL with denoise strenght + steps = (p.refiner_steps // (1 - p.refiner_start) // 2) + 1 + else: + steps = (p.refiner_steps // p.denoising_strength) + 1 else: - steps = (p.denoising_strength * p.refiner_steps) if p.refiner_steps > 0 else (p.denoising_strength * p.steps) + #steps = p.refiner_steps # SD 1.5 with denoise strenght + steps = (p.refiner_steps * 1.25) + 1 + if os.environ.get('SD_STEPS_DEBUG', None) is not None: shared.log.debug(f'Steps: type=refiner input={p.refiner_steps} output={steps} start={p.refiner_start} denoise={p.denoising_strength}') return max(2, int(steps)) From 12cf688cbe3ece45b22e95b979d6e0010597f5a9 Mon Sep 17 00:00:00 2001 From: Vladimir Mandic Date: Thu, 16 Nov 2023 15:26:34 -0500 Subject: [PATCH 37/84] authentication and locking improvements --- CHANGELOG.md | 3 ++ modules/api/api.py | 9 +++-- modules/hashes.py | 2 +- modules/middleware.py | 9 +++-- modules/sd_hijack.py | 7 ++-- modules/sd_models.py | 2 +- modules/sd_models_compile.py | 1 + modules/shared.py | 72 ++++++++++++++++++++++-------------- modules/upscaler.py | 1 - webui.py | 2 + 10 files changed, 68 insertions(+), 40 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 633d94f58..c4d97ffee 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -39,6 +39,9 @@ - Add option to create only subimages in XYZ grid, thanks @midcoastal - Support custom upscalers in subfolders - Add additional image info when loading image in process tab + - Better file locking when sharing config and/or models between multiple instances + - Handle custom API endpoints when using auth + - Show logged in user in log when accessing via UI and/or API - Support `--ckpt none` to skip loading a model - **Fixes** - Fix `params.txt` saved before actual image diff --git a/modules/api/api.py b/modules/api/api.py index 09ee1e116..ef0825926 100644 --- a/modules/api/api.py +++ b/modules/api/api.py @@ -145,7 +145,7 @@ class Api: self.add_api_route("/sdapi/v1/reload-checkpoint", self.reloadapi, methods=["POST"]) self.add_api_route("/sdapi/v1/scripts", self.get_scripts_list, methods=["GET"], response_model=models.ScriptsList) self.add_api_route("/sdapi/v1/script-info", self.get_script_info, methods=["GET"], response_model=List[models.ScriptInfo]) - self.add_api_route("/sdapi/v1/log", self.get_log_buffer, methods=["GET"], response_model=List) # bypass auth + self.add_api_route("/sdapi/v1/log", self.get_log_buffer, methods=["GET"], response_model=List) self.add_api_route("/sdapi/v1/start", self.session_start, methods=["GET"]) self.add_api_route("/sdapi/v1/motd", self.get_motd, methods=["GET"], response_model=str) self.add_api_route("/sdapi/v1/extra-networks", self.get_extra_networks, methods=["GET"], response_model=List[models.ExtraNetworkItem]) @@ -153,11 +153,12 @@ class Api: self.default_script_arg_img2img = [] def add_api_route(self, path: str, endpoint, **kwargs): - if shared.cmd_opts.auth or shared.cmd_opts.auth_file: + if (shared.cmd_opts.auth or shared.cmd_opts.auth_file) and shared.cmd_opts.api_only: return self.app.add_api_route(path, endpoint, dependencies=[Depends(self.auth)], **kwargs) return self.app.add_api_route(path, endpoint, **kwargs) def auth(self, credentials: HTTPBasicCredentials = Depends(HTTPBasic())): + # this is only needed for api-only since otherwise auth is handled in gradio/routes.py if credentials.username in self.credentials: if compare_digest(credentials.password, self.credentials[credentials.username]): return True @@ -170,7 +171,9 @@ class Api: return lines def session_start(self, req: Request, agent: Optional[str] = None): - shared.log.info(f'Browser session: client={req.client.host} agent={agent}') + token = req.cookies.get("access-token") or req.cookies.get("access-token-unsecure") + user = self.app.tokens.get(token) + shared.log.info(f'Browser session: user={user} client={req.client.host} agent={agent}') return {} def get_motd(self): diff --git a/modules/hashes.py b/modules/hashes.py index e4d13f2e3..892368d3c 100644 --- a/modules/hashes.py +++ b/modules/hashes.py @@ -16,7 +16,7 @@ def dump_cache(): def cache(subsection): global cache_data # pylint: disable=global-statement if cache_data is None: - cache_data = {} if not os.path.isfile(cache_filename) else shared.readfile(cache_filename) + cache_data = {} if not os.path.isfile(cache_filename) else shared.readfile(cache_filename, lock=True) s = cache_data.get(subsection, {}) cache_data[subsection] = s return s diff --git a/modules/middleware.py b/modules/middleware.py index e188b4a3d..b119a9c4f 100644 --- a/modules/middleware.py +++ b/modules/middleware.py @@ -1,6 +1,5 @@ import ssl import time -import datetime import logging from asyncio.exceptions import CancelledError import anyio @@ -14,6 +13,7 @@ from fastapi.encoders import jsonable_encoder from installer import log import modules.errors as errors + errors.install() @@ -42,11 +42,12 @@ def setup_middleware(app: FastAPI, cmd_opts): duration = str(round(time.time() - ts, 4)) res.headers["X-Process-Time"] = duration endpoint = req.scope.get('path', 'err') + token = req.cookies.get("access-token") or req.cookies.get("access-token-unsecure") if (cmd_opts.api_log or cmd_opts.api_only) and endpoint.startswith('/sdapi'): - if endpoint.endswith('/sdapi/v1/log'): + if '/sdapi/v1/log' in endpoint: return res - log.info('API {t} {code} {prot}/{ver} {method} {endpoint} {cli} {duration}'.format( # pylint: disable=consider-using-f-string, logging-format-interpolation - t = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S.%f"), + log.info('API {user} {code} {prot}/{ver} {method} {endpoint} {cli} {duration}'.format( # pylint: disable=consider-using-f-string, logging-format-interpolation + user = app.tokens.get(token), code = res.status_code, ver = req.scope.get('http_version', '0.0'), cli = req.scope.get('client', ('0:0.0.0', 0))[0], diff --git a/modules/sd_hijack.py b/modules/sd_hijack.py index 36c8846e1..dd5c68f7c 100644 --- a/modules/sd_hijack.py +++ b/modules/sd_hijack.py @@ -185,7 +185,7 @@ class StableDiffusionModelHijack: import torch._dynamo # pylint: disable=unused-import,redefined-outer-name if shared.opts.cuda_compile_backend == "openvino_fx": torch._dynamo.reset() # pylint: disable=protected-access - from modules.intel.openvino import openvino_fx, openvino_clear_caches # pylint: disable=unused-import + from modules.intel.openvino import openvino_fx, openvino_clear_caches # pylint: disable=unused-import, no-name-in-module openvino_clear_caches() torch._dynamo.eval_frame.check_if_dynamo_supported = lambda: True # pylint: disable=protected-access log_level = logging.WARNING if opts.cuda_compile_verbose else logging.CRITICAL # pylint: disable=protected-access @@ -199,11 +199,12 @@ class StableDiffusionModelHijack: hidet.torch.dynamo_config.use_tensor_core(True) hidet.torch.dynamo_config.search_space(2) m.model = torch.compile(m.model, mode=opts.cuda_compile_mode, backend=opts.cuda_compile_backend, fullgraph=opts.cuda_compile_fullgraph, dynamic=False) - from installer import setup_logging - setup_logging() shared.log.info("Model complilation done.") except Exception as err: shared.log.warning(f"Model compile not supported: {err}") + finally: + from installer import setup_logging + setup_logging() self.optimization_method = apply_optimizations() self.clip = m.cond_stage_model diff --git a/modules/sd_models.py b/modules/sd_models.py index 145c76766..fc96b00c5 100644 --- a/modules/sd_models.py +++ b/modules/sd_models.py @@ -327,7 +327,7 @@ def read_metadata_from_safetensors(filename): if not os.path.isfile(sd_metadata_file): sd_metadata = {} else: - sd_metadata = shared.readfile(sd_metadata_file) + sd_metadata = shared.readfile(sd_metadata_file, lock=True) res = sd_metadata.get(filename, None) if res is not None: return res diff --git a/modules/sd_models_compile.py b/modules/sd_models_compile.py index 711245754..fe9f355d1 100644 --- a/modules/sd_models_compile.py +++ b/modules/sd_models_compile.py @@ -93,6 +93,7 @@ def compile_torch(sd_model): try: import torch._dynamo # pylint: disable=unused-import,redefined-outer-name torch._dynamo.reset() # pylint: disable=protected-access + shared.log.debug(f"Model compile available backends: {torch._dynamo.list_backends()}") # pylint: disable=protected-access if shared.opts.ipex_optimize: optimize_ipex(sd_model) if shared.opts.cuda_compile_backend == "openvino_fx": diff --git a/modules/shared.py b/modules/shared.py index 17ce2bd54..2ab35e858 100644 --- a/modules/shared.py +++ b/modules/shared.py @@ -181,51 +181,69 @@ def temp_disable_extensions(): return disabled -def readfile(filename, silent=False): +def readfile(filename, silent=False, lock=False): data = {} + lock_file = None + locked = False try: if not os.path.exists(filename): return {} - with fasteners.InterProcessLock(f"{filename}.lock"): - with open(filename, "r", encoding="utf8") as file: - data = json.load(file) - if type(data) is str: - data = json.loads(data) - if not silent: - log.debug(f'Read: file="{filename}" len={len(data)}') + if lock: + lock_file = fasteners.InterProcessReaderWriterLock(f"{filename}.lock", logger=log) + locked = lock_file.acquire_read_lock(blocking=True, timeout=3) + with open(filename, "r", encoding="utf8") as file: + data = json.load(file) + if type(data) is str: + data = json.loads(data) + if not silent: + log.debug(f'Read: file="{filename}" json={len(data)} bytes={os.path.getsize(filename)}') except Exception as e: if not silent: log.error(f'Reading failed: {filename} {e}') return {} + finally: + if lock_file is not None: + lock_file.release_read_lock() + if locked and os.path.exists(f"{filename}.lock"): + os.remove(f"{filename}.lock") return data def writefile(data, filename, mode='w', silent=False): + lock = None + locked = False + def default(obj): log.error(f"Saving: {filename} not a valid object: {obj}") return str(obj) try: - with fasteners.InterProcessLock(f"{filename}.lock"): - # skipkeys=True, ensure_ascii=True, check_circular=True, allow_nan=True - if type(data) == dict: - output = json.dumps(data, indent=2, default=default) - elif type(data) == list: - output = json.dumps(data, indent=2, default=default) - elif isinstance(data, object): - simple = {} - for k in data.__dict__: - if data.__dict__[k] is not None: - simple[k] = data.__dict__[k] - output = json.dumps(simple, indent=2, default=default) - else: - raise ValueError('not a valid object') - if not silent: - log.debug(f'Save: file="{filename}" len={len(output)}') - with open(filename, mode, encoding="utf8") as file: - file.write(output) + # skipkeys=True, ensure_ascii=True, check_circular=True, allow_nan=True + if type(data) == dict: + output = json.dumps(data, indent=2, default=default) + elif type(data) == list: + output = json.dumps(data, indent=2, default=default) + elif isinstance(data, object): + simple = {} + for k in data.__dict__: + if data.__dict__[k] is not None: + simple[k] = data.__dict__[k] + output = json.dumps(simple, indent=2, default=default) + else: + raise ValueError('not a valid object') + lock = fasteners.InterProcessReaderWriterLock(f"{filename}.lock", logger=log) + locked = lock.acquire_write_lock(blocking=True, timeout=3) + with open(filename, mode, encoding="utf8") as file: + file.write(output) + if not silent: + log.debug(f'Save: file="{filename}" json={len(data)} bytes={len(output)}') except Exception as e: log.error(f'Saving failed: {filename} {e}') + finally: + if lock is not None: + lock.release_read_lock() + if locked and os.path.exists(f"{filename}.lock"): + os.remove(f"{filename}.lock") if devices.backend == "cpu": @@ -699,7 +717,7 @@ class Options: log.debug(f'Created default config: {filename}') self.save(filename) return - self.data = readfile(filename) + self.data = readfile(filename, lock=True) if self.data.get('quicksettings') is not None and self.data.get('quicksettings_list') is None: self.data['quicksettings_list'] = [i.strip() for i in self.data.get('quicksettings').split(',')] unknown_settings = [] diff --git a/modules/upscaler.py b/modules/upscaler.py index e9ec14a54..9228bc658 100644 --- a/modules/upscaler.py +++ b/modules/upscaler.py @@ -66,7 +66,6 @@ class Upscaler: scalers.append(scaler) loaded.append(file_name) modules.shared.log.debug(f'Upscaler type={self.name} folder="{folder}" model="{model_name}" path="{file_name}"') - print(f'Upscaler type={self.name} folder="{folder}" model="{model_name}" path="{file_name}"') def find_scalers(self): scalers = [] diff --git a/webui.py b/webui.py index 5b0692ed2..103d78ec7 100644 --- a/webui.py +++ b/webui.py @@ -247,6 +247,8 @@ def start_ui(): with open(cmd_opts.auth_file, 'r', encoding="utf8") as file: for line in file.readlines(): gradio_auth_creds += [x.strip() for x in line.split(',') if x.strip()] + if len(gradio_auth_creds) > 0: + log.info(f'Authentication enabled: {gradio_auth_creds}') global local_url # pylint: disable=global-statement stdout = io.StringIO() From 53691c993e0ac508e5a6d06b6a885ec0b53c6fab Mon Sep 17 00:00:00 2001 From: Vladimir Mandic Date: Thu, 16 Nov 2023 15:52:33 -0500 Subject: [PATCH 38/84] xyz formatting --- CHANGELOG.md | 8 +++++--- modules/images.py | 31 +++++++++++++++---------------- modules/shared.py | 4 +++- 3 files changed, 23 insertions(+), 20 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c4d97ffee..3ce6e547a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -31,18 +31,20 @@ - Use multi-threading for 5x load speedup - Better Lora trigger words support - Auto refresh styles on change -- **General**: +- **General** - Reworked parser when pasting previously generated images/prompts includes all `txt2img`, `img2img` and `override` params - Reworked **model compile** - - Add refiner options to XYZ Grid - - Add option to create only subimages in XYZ grid, thanks @midcoastal - Support custom upscalers in subfolders - Add additional image info when loading image in process tab - Better file locking when sharing config and/or models between multiple instances - Handle custom API endpoints when using auth - Show logged in user in log when accessing via UI and/or API - Support `--ckpt none` to skip loading a model +- **XYZ grid** + - Add refiner options to XYZ Grid + - Add option to create only subimages in XYZ grid, thanks @midcoastal + - Allow custom font, background and text color in settings - **Fixes** - Fix `params.txt` saved before actual image - Fix inpaint diff --git a/modules/images.py b/modules/images.py index 0d5d74de9..652551b08 100644 --- a/modules/images.py +++ b/modules/images.py @@ -56,7 +56,7 @@ def image_grid(imgs, batch_size=1, rows=None): params = script_callbacks.ImageGridLoopParams(imgs, cols, rows) script_callbacks.image_grid_callback(params) w, h = imgs[0].size - grid = Image.new('RGB', size=(params.cols * w, params.rows * h), color='black') + grid = Image.new('RGB', size=(params.cols * w, params.rows * h), color=shared.opts.grid_background) for i, img in enumerate(params.imgs): grid.paste(img, box=(i % params.cols * w, i // params.cols * h)) return grid @@ -141,37 +141,36 @@ def draw_grid_annotations(im, width, height, hor_texts, ver_texts, margin=0, tit def draw_texts(drawing: ImageDraw, draw_x, draw_y, lines, initial_fnt, initial_fontsize): for line in lines: - fnt = initial_fnt + font = initial_fnt fontsize = initial_fontsize - while drawing.multiline_textsize(line.text, font=fnt)[0] > line.allowed_width and fontsize > 0: - fontsize -= 1 - fnt = get_font(fontsize) - drawing.multiline_text((draw_x, draw_y + line.size[1] / 2), line.text, font=fnt, fill=color_active if line.is_active else color_inactive, anchor="mm", align="center") + while drawing.multiline_textsize(line.text, font=font)[0] > line.allowed_width and fontsize > 0: + fontsize -= 2 + font = get_font(fontsize) + drawing.multiline_text((draw_x, draw_y + line.size[1] / 2), line.text, font=font, fill=shared.opts.font_color if line.is_active else color_inactive, anchor="mm", align="center") if not line.is_active: drawing.line((draw_x - line.size[0] // 2, draw_y + line.size[1] // 2, draw_x + line.size[0] // 2, draw_y + line.size[1] // 2), fill=color_inactive, width=4) draw_y += line.size[1] + line_spacing fontsize = (width + height) // 25 line_spacing = fontsize // 2 - fnt = get_font(fontsize) - color_active = (0, 0, 0) - color_inactive = (153, 153, 153) + font = get_font(fontsize) + color_inactive = (127, 127, 127) pad_left = 0 if sum([sum([len(line.text) for line in lines]) for lines in ver_texts]) == 0 else width * 3 // 4 cols = im.width // width rows = im.height // height assert cols == len(hor_texts), f'bad number of horizontal texts: {len(hor_texts)}; must be {cols}' assert rows == len(ver_texts), f'bad number of vertical texts: {len(ver_texts)}; must be {rows}' - calc_img = Image.new("RGB", (1, 1), "white") + calc_img = Image.new("RGB", (1, 1), shared.opts.grid_background) calc_d = ImageDraw.Draw(calc_img) title_texts = [title] if title else [[GridAnnotation()]] for texts, allowed_width in zip(hor_texts + ver_texts + title_texts, [width] * len(hor_texts) + [pad_left] * len(ver_texts) + [(width+margin)*cols]): items = [] + texts texts.clear() for line in items: - wrapped = wrap(calc_d, line.text, fnt, allowed_width) + wrapped = wrap(calc_d, line.text, font, allowed_width) texts += [GridAnnotation(x, line.is_active) for x in wrapped] for line in texts: - bbox = calc_d.multiline_textbbox((0, 0), line.text, font=fnt) + bbox = calc_d.multiline_textbbox((0, 0), line.text, font=font) line.size = (bbox[2] - bbox[0], bbox[3] - bbox[1]) line.allowed_width = allowed_width hor_text_heights = [sum([line.size[1] + line_spacing for line in lines]) - line_spacing for lines in hor_texts] @@ -181,7 +180,7 @@ def draw_grid_annotations(im, width, height, hor_texts, ver_texts, margin=0, tit if title: title_text_heights = [sum([line.size[1] + line_spacing for line in lines]) - line_spacing for lines in title_texts] # pylint: disable=unsubscriptable-object title_pad = 0 if sum(title_text_heights) == 0 else max(title_text_heights) + line_spacing * 2 - result = Image.new("RGB", (im.width + pad_left + margin * (cols-1), im.height + pad_top + title_pad + margin * (rows-1)), "white") + result = Image.new("RGB", (im.width + pad_left + margin * (cols-1), im.height + pad_top + title_pad + margin * (rows-1)), shared.opts.grid_background) for row in range(rows): for col in range(cols): cell = im.crop((width * col, height * row, width * (col+1), height * (row+1))) @@ -190,15 +189,15 @@ def draw_grid_annotations(im, width, height, hor_texts, ver_texts, margin=0, tit if title: x = pad_left + ((width+margin)*cols) / 2 y = title_pad / 2 - title_text_heights[0] / 2 - draw_texts(d, x, y, title_texts[0], fnt, fontsize) + draw_texts(d, x, y, title_texts[0], font, fontsize) for col in range(cols): x = pad_left + (width + margin) * col + width / 2 y = (pad_top / 2 - hor_text_heights[col] / 2) + title_pad - draw_texts(d, x, y, hor_texts[col], fnt, fontsize) + draw_texts(d, x, y, hor_texts[col], font, fontsize) for row in range(rows): x = pad_left / 2 y = (pad_top + (height + margin) * row + height / 2 - ver_text_heights[row] / 2) + title_pad - draw_texts(d, x, y, ver_texts[row], fnt, fontsize) + draw_texts(d, x, y, ver_texts[row], font, fontsize) return result diff --git a/modules/shared.py b/modules/shared.py index 2ab35e858..2b28f5eb5 100644 --- a/modules/shared.py +++ b/modules/shared.py @@ -419,6 +419,9 @@ options_templates.update(options_section(('saving-images', "Image Options"), { "grid_save": OptionInfo(True, "Always save all generated image grids"), "grid_format": OptionInfo('jpg', 'File format for grids', gr.Dropdown, {"choices": ["jpg", "png", "webp", "tiff", "jp2"]}), "n_rows": OptionInfo(-1, "Grid row count", gr.Slider, {"minimum": -1, "maximum": 16, "step": 1}), + "grid_background": OptionInfo("#000000", "Grid background color", ui_components.FormColorPicker, {}), + "font": OptionInfo("", "Font file"), + "font_color": OptionInfo("#FFFFFF", "Font color", ui_components.FormColorPicker, {}), "save_sep_options": OptionInfo("

Intermediate Image Saving

", "", gr.HTML), "save_init_img": OptionInfo(False, "Save copy of img2img init images"), @@ -470,7 +473,6 @@ options_templates.update(options_section(('ui', "User Interface"), { "disable_weights_auto_swap": OptionInfo(True, "Do not change selected model when reading generation parameters"), "send_seed": OptionInfo(True, "Send seed when sending prompt or image to other interface"), "send_size": OptionInfo(True, "Send size when sending prompt or image to another interface"), - "font": OptionInfo("", "Font for image grids that have text"), "keyedit_precision_attention": OptionInfo(0.1, "Ctrl+up/down precision when editing (attention:1.1)", gr.Slider, {"minimum": 0.01, "maximum": 0.2, "step": 0.001, "visible": False}), "keyedit_precision_extra": OptionInfo(0.05, "Ctrl+up/down precision when editing ", gr.Slider, {"minimum": 0.01, "maximum": 0.2, "step": 0.001, "visible": False}), "keyedit_delimiters": OptionInfo(".,\/!?%^*;:{}=`~()", "Ctrl+up/down word delimiters", gr.Textbox, { "visible": False }), # pylint: disable=anomalous-backslash-in-string From db20da7b1a52d988b09c380a1f8b03cf6449513e Mon Sep 17 00:00:00 2001 From: AI-Casanova <54461896+AI-Casanova@users.noreply.github.com> Date: Thu, 16 Nov 2023 19:01:03 -0600 Subject: [PATCH 39/84] Fixes --- modules/merging/merge.py | 10 +++++----- modules/merging/{model.py => merge_model.py} | 0 modules/merging/{presets.py => merge_presets.py} | 0 modules/merging/{rebasin.py => merge_rebasin.py} | 0 modules/merging/{utils.py => merge_utils.py} | 7 +++++-- modules/ui_models.py | 12 +++++------- 6 files changed, 15 insertions(+), 14 deletions(-) rename modules/merging/{model.py => merge_model.py} (100%) rename modules/merging/{presets.py => merge_presets.py} (100%) rename modules/merging/{rebasin.py => merge_rebasin.py} (100%) rename modules/merging/{utils.py => merge_utils.py} (95%) diff --git a/modules/merging/merge.py b/modules/merging/merge.py index 6b00afe2b..fe0097da9 100644 --- a/modules/merging/merge.py +++ b/modules/merging/merge.py @@ -9,11 +9,12 @@ import safetensors.torch import torch from tqdm import tqdm +import modules.memstats from modules.shared import log from modules.merging import merge_methods -from modules.merging.utils import WeightClass -from modules.merging.model import SDModel -from modules.merging.rebasin import ( +from modules.merging.merge_utils import WeightClass +from modules.merging.merge_model import SDModel +from modules.merging.merge_rebasin import ( apply_permutation, sdunet_permutation_spec, update_model_a, @@ -95,8 +96,7 @@ def restore_sd_model(original_model: Dict, merged_model: Dict) -> Dict: def log_vram(txt=""): - alloc = torch.cuda.memory_allocated(0) - log.info(f"{txt} VRAM: {alloc*1e-9:5.3f}GB") + log.info(f"{txt} VRAM: {modules.memstats.memory_stats()}") def load_thetas( diff --git a/modules/merging/model.py b/modules/merging/merge_model.py similarity index 100% rename from modules/merging/model.py rename to modules/merging/merge_model.py diff --git a/modules/merging/presets.py b/modules/merging/merge_presets.py similarity index 100% rename from modules/merging/presets.py rename to modules/merging/merge_presets.py diff --git a/modules/merging/rebasin.py b/modules/merging/merge_rebasin.py similarity index 100% rename from modules/merging/rebasin.py rename to modules/merging/merge_rebasin.py diff --git a/modules/merging/utils.py b/modules/merging/merge_utils.py similarity index 95% rename from modules/merging/utils.py rename to modules/merging/merge_utils.py index 7feff1393..41b6f7442 100644 --- a/modules/merging/utils.py +++ b/modules/merging/merge_utils.py @@ -2,9 +2,12 @@ import inspect # import logging import re from modules.merging import merge_methods -from modules.merging.presets import BLOCK_WEIGHTS_PRESETS, SDXL_BLOCK_WEIGHTS_PRESETS +from modules.merging.merge_presets import BLOCK_WEIGHTS_PRESETS, SDXL_BLOCK_WEIGHTS_PRESETS + +ALL_PRESETS = {} +ALL_PRESETS.update(BLOCK_WEIGHTS_PRESETS) +ALL_PRESETS.update(SDXL_BLOCK_WEIGHTS_PRESETS) -BLOCK_WEIGHTS_PRESETS |= SDXL_BLOCK_WEIGHTS_PRESETS MERGE_METHODS = dict(inspect.getmembers(merge_methods, inspect.isfunction)) BETA_METHODS = [ name diff --git a/modules/ui_models.py b/modules/ui_models.py index 87c1c2898..a9c99e8e3 100644 --- a/modules/ui_models.py +++ b/modules/ui_models.py @@ -11,8 +11,8 @@ from modules.shared import opts, log, req import modules.errors import modules.hashes from modules.merging import merge_methods -from modules.merging.utils import BETA_METHODS, TRIPLE_METHODS, interpolate -from modules.merging.presets import BLOCK_WEIGHTS_PRESETS, SDXL_BLOCK_WEIGHTS_PRESETS +from modules.merging.merge_utils import BETA_METHODS, TRIPLE_METHODS, interpolate +from modules.merging.merge_presets import BLOCK_WEIGHTS_PRESETS, SDXL_BLOCK_WEIGHTS_PRESETS search_metadata_civit = None @@ -242,7 +242,7 @@ def create_ui(): with FormRow(): precision = gr.Radio(choices=["fp16", "fp32"], value="fp16", label="Model precision") with FormRow(): - device = gr.Radio(choices=["cpu", "cuda"], value="cpu", label="Device") + work_device = gr.Radio(choices=["cpu", "cuda"], value="cpu", label="Device") with FormRow(): bake_in_vae = gr.Dropdown(choices=["None"] + list(sd_vae.vae_dict), value="None", interactive=True, label="Bake in VAE") @@ -281,7 +281,7 @@ def create_ui(): prune, re_basin, re_basin_iterations, - device, + work_device, bake_in_vae): kwargs = {} for x in inspect.getfullargspec(MEHmodelmerger)[0]: @@ -290,8 +290,6 @@ def create_ui(): if kwargs[key] in [None, "None", "", 0, []]: del kwargs[key] - # return [*[gr.Dropdown.update(choices=sd_models.checkpoint_tiles()) for _ in range(4)], f"{kwargs}"] - try: results = extras.run_MEHmodelmerger(dummy_component, **kwargs) except Exception as e: @@ -386,7 +384,7 @@ def create_ui(): prune, re_basin, re_basin_iterations, - device, + work_device, bake_in_vae, ], outputs=[ From 26f6e717f67d7e89c4318c9e0c695c363c59a2e9 Mon Sep 17 00:00:00 2001 From: AI-Casanova <54461896+AI-Casanova@users.noreply.github.com> Date: Thu, 16 Nov 2023 19:17:13 -0600 Subject: [PATCH 40/84] Update extras.py --- modules/extras.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/extras.py b/modules/extras.py index d5293f2f6..467946166 100644 --- a/modules/extras.py +++ b/modules/extras.py @@ -9,7 +9,7 @@ import tqdm import gradio as gr import safetensors.torch from modules.merging.merge import merge_models -from modules.merging.utils import TRIPLE_METHODS +from modules.merging.merge_utils import TRIPLE_METHODS from modules import shared, images, sd_models, sd_vae, sd_models_config From 6c34317a576f66b4e3fa137c3d8cf25f3e2007f1 Mon Sep 17 00:00:00 2001 From: AI-Casanova <54461896+AI-Casanova@users.noreply.github.com> Date: Thu, 16 Nov 2023 19:31:36 -0600 Subject: [PATCH 41/84] fix precision --- modules/merging/merge.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/modules/merging/merge.py b/modules/merging/merge.py index fe0097da9..ae68fba15 100644 --- a/modules/merging/merge.py +++ b/modules/merging/merge.py @@ -126,7 +126,7 @@ def load_thetas( def merge_models( models: Dict[str, os.PathLike | str], merge_mode: str, - precision: str = "full", + precision: str = "fp16", weights_clip: bool = False, re_basin: bool = False, device: str = "cpu", @@ -242,7 +242,7 @@ def simple_merge( continue if "model" in key and key not in thetas["model_a"].keys(): thetas["model_a"].update({key: thetas["model_b"][key]}) - if precision == 16: + if precision == "fp16": thetas["model_a"].update({key: thetas["model_a"][key].half()}) log_vram("after stage 2") @@ -291,7 +291,7 @@ def rebasin_merge( thetas["model_a"], max_iter=it, init_perm=None, - usefp16=precision == 16, + usefp16=precision == "fp16", device=device, ) @@ -307,7 +307,7 @@ def rebasin_merge( thetas["model_a"], max_iter=it, init_perm=None, - usefp16=precision == 16, + usefp16=precision == "fp16", device=device, ) @@ -343,7 +343,7 @@ def merge_key( thetas: Dict, weight_matcher: WeightClass, merge_mode: str, - precision: int = 16, + precision: str = "fp16", weights_clip: bool = False, device: str = "cpu", work_device: Optional[str] = None, @@ -378,7 +378,7 @@ def merge_key( if weights_clip: merged_key = clip_weights_key(thetas, merged_key, key) - if precision == 16: + if precision == "fp16": merged_key = merged_key.half() return merged_key From 17d5b152246d7b42bc601a04e7e9d9dc3dcc5479 Mon Sep 17 00:00:00 2001 From: AI-Casanova <54461896+AI-Casanova@users.noreply.github.com> Date: Thu, 16 Nov 2023 21:00:27 -0600 Subject: [PATCH 42/84] Doc Strings for Merge Methods --- modules/merging/merge_methods.py | 90 ++++++++++++++++++++++---------- 1 file changed, 63 insertions(+), 27 deletions(-) diff --git a/modules/merging/merge_methods.py b/modules/merging/merge_methods.py index c10c459f0..a80a18106 100644 --- a/modules/merging/merge_methods.py +++ b/modules/merging/merge_methods.py @@ -24,12 +24,20 @@ EPSILON = 1e-10 # Define a small constant EPSILON to prevent division by zero def weighted_sum(a: Tensor, b: Tensor, alpha: float, **kwargs) -> Tensor: + """ + Basic Merge: + alpha 0 returns Primary Model + alpha 1 returns Secondary Model + """ return (1 - alpha) * a + alpha * b -def weighted_subtraction( - a: Tensor, b: Tensor, alpha: float, beta: float, **kwargs -) -> Tensor: +def weighted_subtraction(a: Tensor, b: Tensor, alpha: float, beta: float, **kwargs) -> Tensor: + """ + The inverse of a Weighted Sum Merge + Returns Primary Model when alpha*beta = 0 + High values of alpha*beta are likely to break the merged model + """ # Adjust beta if both alpha and beta are 1.0 to avoid division by zero if alpha == 1.0 and beta == 1.0: beta -= EPSILON @@ -38,6 +46,12 @@ def weighted_subtraction( def tensor_sum(a: Tensor, b: Tensor, alpha: float, beta: float, **kwargs) -> Tensor: + """ + Takes a slice of Secondary Model and pastes it into Primary Model + Alpha sets the width of the slice + Beta sets the start point of the slice + ie Alpha = 0.5 Beta = 0.25 is (ABBA) Alpha = 0.25 Beta = 0 is (BAAA) + """ if alpha + beta <= 1: tt = a.clone() talphas = int(a.shape[0] * beta) @@ -52,24 +66,37 @@ def tensor_sum(a: Tensor, b: Tensor, alpha: float, beta: float, **kwargs) -> Ten def add_difference(a: Tensor, b: Tensor, c: Tensor, alpha: float, **kwargs) -> Tensor: + """ + Classic Add Difference Merge + """ return a + alpha * (b - c) -def sum_twice( - a: Tensor, b: Tensor, c: Tensor, alpha: float, beta: float, **kwargs -) -> Tensor: +def sum_twice(a: Tensor, b: Tensor, c: Tensor, alpha: float, beta: float, **kwargs) -> Tensor: + """ + Stacked Basic Merge: + Equivalent to Merging Primary and Secondary @ alpha + Then merging the result with Tertiary @ beta + """ return (1 - beta) * ((1 - alpha) * a + alpha * b) + beta * c -def triple_sum( - a: Tensor, b: Tensor, c: Tensor, alpha: float, beta: float, **kwargs -) -> Tensor: +def triple_sum(a: Tensor, b: Tensor, c: Tensor, alpha: float, beta: float, **kwargs) -> Tensor: + """ + Weights Secondary and Tertiary at alpha and beta respectively + Fills in the rest with Primary + Expect odd results if alpha + beta > 1 as Primary will be merged with a negative ratio + """ return (1 - alpha - beta) * a + alpha * b + beta * c -def euclidean_add_difference( - a: Tensor, b: Tensor, c: Tensor, alpha: float, **kwargs -) -> Tensor: +def euclidean_add_difference(a: Tensor, b: Tensor, c: Tensor, alpha: float, **kwargs) -> Tensor: + """ + Subtract Primary and Secondary from Tertiary + Compare the remainders via Euclidean distance + Add to Tertiary + Note: Slow + """ a_diff = a.float() - c.float() b_diff = b.float() - c.float() a_diff = torch.nan_to_num(a_diff / torch.linalg.norm(a_diff)) @@ -84,18 +111,20 @@ def euclidean_add_difference( return c + distance / torch.linalg.norm(distance) * target_norm -def multiply_difference( - a: Tensor, b: Tensor, c: Tensor, alpha: float, beta: float, **kwargs -) -> Tensor: +def multiply_difference(a: Tensor, b: Tensor, c: Tensor, alpha: float, beta: float, **kwargs) -> Tensor: + """ + Similar to Add Difference but with geometric mean instead of arithmatic mean + """ diff_a = torch.pow(torch.abs(a.float() - c), (1 - alpha)) diff_b = torch.pow(torch.abs(b.float() - c), alpha) difference = torch.copysign(diff_a * diff_b, weighted_sum(a, b, beta) - c) return c + difference.to(c.dtype) -def top_k_tensor_sum( - a: Tensor, b: Tensor, alpha: float, beta: float, **kwargs -) -> Tensor: +def top_k_tensor_sum(a: Tensor, b: Tensor, alpha: float, beta: float, **kwargs) -> Tensor: + """ + Redistributes the largest weights of Secondary Model into Primary Model + """ a_flat = torch.flatten(a) a_dist = torch.msort(a_flat) b_indices = torch.argsort(torch.flatten(b), stable=True) @@ -144,9 +173,10 @@ def ratio_to_region(width: float, offset: float, n: int) -> Tuple[int, int, bool return round(start), round(end), inverted -def similarity_add_difference( - a: Tensor, b: Tensor, c: Tensor, alpha: float, beta: float, **kwargs -) -> Tensor: +def similarity_add_difference(a: Tensor, b: Tensor, c: Tensor, alpha: float, beta: float, **kwargs) -> Tensor: + """ + Weighted Sum where A and B are similar and Add Difference where A and B are dissimilar + """ threshold = torch.maximum(torch.abs(a), torch.abs(b)) similarity = ((a * b / threshold**2) + 1) / 2 similarity = torch.nan_to_num(similarity * beta, nan=beta) @@ -156,9 +186,14 @@ def similarity_add_difference( return (1 - similarity) * ab_diff + similarity * ab_sum -def distribution_crossover( - a: Tensor, b: Tensor, c: Tensor, alpha: float, beta: float, **kwargs -): +def distribution_crossover(a: Tensor, b: Tensor, c: Tensor, alpha: float, beta: float, **kwargs): + """ + From the creator: + It's Primary high-passed + Secondary low-passed. Takes the fourrier transform of the weights of + Primary and Secondary when ordered with respect to Tertiary. Split the frequency domain + using a linear function. Alpha is the split frequency and Beta is the inclination of the line. + add everything under the line as the contribution of Primary and everything over the line as the contribution of Secondary + """ if a.shape == (): return alpha * a + (1 - alpha) * b @@ -183,9 +218,10 @@ def distribution_crossover( return x_values.reshape_as(a) -def ties_add_difference( - a: Tensor, b: Tensor, c: Tensor, alpha: float, beta: float, **kwargs -) -> Tensor: +def ties_add_difference(a: Tensor, b: Tensor, c: Tensor, alpha: float, beta: float, **kwargs) -> Tensor: + """ + An implementation of arXiv:2306.01708 + """ deltas = [] signs = [] for m in [a, b]: From 9b80d5163099136c110ca3f820fddf6f1932a9f5 Mon Sep 17 00:00:00 2001 From: AI-Casanova <54461896+AI-Casanova@users.noreply.github.com> Date: Thu, 16 Nov 2023 21:21:52 -0600 Subject: [PATCH 43/84] Add Doc Strings to UI --- modules/merging/merge.py | 2 +- modules/ui_models.py | 8 +++++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/modules/merging/merge.py b/modules/merging/merge.py index ae68fba15..e0ed32145 100644 --- a/modules/merging/merge.py +++ b/modules/merging/merge.py @@ -96,7 +96,7 @@ def restore_sd_model(original_model: Dict, merged_model: Dict) -> Dict: def log_vram(txt=""): - log.info(f"{txt} VRAM: {modules.memstats.memory_stats()}") + log.debug(f"{txt} VRAM: {modules.memstats.memory_stats()}") def load_thetas( diff --git a/modules/ui_models.py b/modules/ui_models.py index a9c99e8e3..41d691e30 100644 --- a/modules/ui_models.py +++ b/modules/ui_models.py @@ -167,6 +167,8 @@ def create_ui(): with FormRow(): merge_mode = gr.Dropdown(choices=merge_methods.__all__, value="weighted_sum", label="Interpolation Method") + merge_mode_help = ToolButton('❔', visible=True) + merge_mode_docs = gr.Textbox(value=None, visible=False) with FormRow(): primary_model_name = gr.Dropdown(sd_model_choices(), label="Primary model", value="None") create_refresh_button(primary_model_name, sd_models.list_models, @@ -323,6 +325,10 @@ def create_ui(): else: return gr.Slider.update(value=None, visible=False) + def show_help(mode): + doc = getattr(merge_methods, mode).__doc__ + return gr.update(value=doc, visible=True, interactive=False) + def load_presets(presets, ratio): for i, p in enumerate(presets): presets[i] = BLOCK_WEIGHTS_PRESETS[p] @@ -339,7 +345,7 @@ def create_ui(): return [gr.update(choices=["None"] + list(SDXL_BLOCK_WEIGHTS_PRESETS.keys())) for _ in range(2)] else: return [gr.update(choices=["None"] + list(BLOCK_WEIGHTS_PRESETS.keys())) for _ in range(2)] - + merge_mode_help.click(fn=show_help, inputs=merge_mode, outputs=merge_mode_docs) sdxl.change(fn=preset_choices, inputs=sdxl, outputs=[alpha_preset, beta_preset]) alpha_preset.change(fn=preset_visiblility, inputs=alpha_preset, outputs=alpha_preset_lambda) beta_preset.change(fn=preset_visiblility, inputs=alpha_preset, outputs=beta_preset_lambda) From 17dfcc97eb55965ccf31d0abbb169d28e7010326 Mon Sep 17 00:00:00 2001 From: Disty0 Date: Fri, 17 Nov 2023 12:24:38 +0300 Subject: [PATCH 44/84] Update OpenVINO --- installer.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/installer.py b/installer.py index 78b530bc0..04a160b5c 100644 --- a/installer.py +++ b/installer.py @@ -442,7 +442,6 @@ def check_torch(): torchvision_pip = 'https://github.com/Nuullll/intel-extension-for-pytorch/releases/download/v2.0.110%2Bxpu-master%2Bdll-bundle/torchvision-0.15.2a0+fa99a53-cp310-cp310-win_amd64.whl' ipex_pip = 'https://github.com/Nuullll/intel-extension-for-pytorch/releases/download/v2.0.110%2Bxpu-master%2Bdll-bundle/intel_extension_for_pytorch-2.0.110+gitc6ea20b-cp310-cp310-win_amd64.whl' torch_command = os.environ.get('TORCH_COMMAND', f'{pytorch_pip} {torchvision_pip} {ipex_pip}') - uninstall('openvino-nightly') install('openvino', 'openvino', ignore=True) install('onnxruntime-openvino', 'onnxruntime-openvino', ignore=True) # TODO numpy version conflicts with tensorflow and doesn't support Python 3.11 elif allow_openvino and args.use_openvino: @@ -544,8 +543,8 @@ def check_torch(): if opts.get('cuda_compile_backend', '') == 'hidet': install('hidet', 'hidet') if args.use_openvino or opts.get('cuda_compile_backend', '') == 'openvino_fx': - uninstall('openvino') - install('openvino-nightly==2023.3.0.dev20231114', 'openvino-nightly') + uninstall('openvino-nightly') # TODO remove after people had enough time upgrading + install('openvino==2023.2.0', 'openvino') install('onnxruntime-openvino', 'onnxruntime-openvino', ignore=True) # TODO numpy version conflicts with tensorflow and doesn't support Python 3.11 os.environ.setdefault('PYTORCH_TRACING_MODE', 'TORCHFX') os.environ.setdefault('NEOReadDebugKeys', '1') From 378c16782038c7d279d356e316350a7b092d8966 Mon Sep 17 00:00:00 2001 From: Vladimir Mandic Date: Fri, 17 Nov 2023 08:38:13 -0500 Subject: [PATCH 45/84] update pillow --- javascript/loader.js | 5 ++++- javascript/logMonitor.js | 2 +- javascript/sdnext.css | 1 + launch.py | 2 +- modules/images.py | 12 +++++------- modules/sd_models.py | 23 ++++++++++++----------- requirements.txt | 6 +++--- 7 files changed, 27 insertions(+), 24 deletions(-) diff --git a/javascript/loader.js b/javascript/loader.js index 9b8ef4b3e..4fb85462f 100644 --- a/javascript/loader.js +++ b/javascript/loader.js @@ -39,7 +39,10 @@ async function createSplash() { document.getElementById('splash').insertAdjacentHTML('afterbegin', imgEl); fetch('/sdapi/v1/motd') .then((res) => res.text()) - .then((text) => document.getElementById('motd').innerHTML = text.replace(/["]+/g, '')) + .then((text) => { + const motdEl = document.getElementById('motd'); + if (motdEl) motdEl.innerHTML = text.replace(/["]+/g, ''); + }) .catch((err) => console.error('getMOTD:', err)); } diff --git a/javascript/logMonitor.js b/javascript/logMonitor.js index bca665672..7677cfced 100644 --- a/javascript/logMonitor.js +++ b/javascript/logMonitor.js @@ -39,7 +39,7 @@ async function initLogMonitor() { - + diff --git a/javascript/sdnext.css b/javascript/sdnext.css index 94652f34f..31b8a8f5c 100644 --- a/javascript/sdnext.css +++ b/javascript/sdnext.css @@ -234,6 +234,7 @@ table.settings-value-table td { padding: 0.4em; border: 1px solid #ccc; max-widt .extras { gap: 0.2em 1em !important } #extras_generate, #extras_interrupt, #extras_skip { display: block !important; position: relative; height: 36px; } #extras_upscale { margin-top: 10px } +#pnginfo_html_info { line-height: 1.5em; } /* log monitor */ .log-monitor { display: none; justify-content: unset !important; overflow: hidden; padding: 0; margin-top: auto; font-family: monospace; font-size: 0.85em; } diff --git a/launch.py b/launch.py index aeb3a1475..f47876240 100755 --- a/launch.py +++ b/launch.py @@ -233,7 +233,7 @@ if __name__ == "__main__": if round(time.time()) % 120 == 0: state = f'job="{instance.state.job}" {instance.state.job_no}/{instance.state.job_count}' if instance.state.job != '' or instance.state.job_no != 0 or instance.state.job_count != 0 else 'idle' uptime = round(time.time() - instance.state.server_start) - installer.log.debug(f'Server: alive={alive} jobs={instance.state.total_jobs} requests={requests} uptime={uptime} memory={get_memory_stats()} backend={instance.backend} {state}') + installer.log.debug(f'Server: alive={alive} jobs={instance.state.total_jobs} requests={requests} uptime={uptime} memory={get_memory_stats()} backend={instance.backend} state={state}') if not alive: if uv is not None and uv.wants_restart: installer.log.info('Server restarting...') diff --git a/modules/images.py b/modules/images.py index 652551b08..9c8def630 100644 --- a/modules/images.py +++ b/modules/images.py @@ -18,10 +18,8 @@ import piexif.helper from PIL import Image, ImageFont, ImageDraw, PngImagePlugin, ExifTags from modules import sd_samplers, shared, script_callbacks, errors, paths -LANCZOS = (Image.Resampling.LANCZOS if hasattr(Image, 'Resampling') else Image.LANCZOS) + debug = errors.log.info if os.environ.get('SD_PATH_DEBUG', None) is not None else lambda *args, **kwargs: None - - try: from pi_heif import register_heif_opener register_heif_opener() @@ -143,8 +141,8 @@ def draw_grid_annotations(im, width, height, hor_texts, ver_texts, margin=0, tit for line in lines: font = initial_fnt fontsize = initial_fontsize - while drawing.multiline_textsize(line.text, font=font)[0] > line.allowed_width and fontsize > 0: - fontsize -= 2 + while drawing.multiline_textbbox((0,0), text=line.text, font=font)[0] > line.allowed_width and fontsize > 0: + fontsize -= 1 font = get_font(fontsize) drawing.multiline_text((draw_x, draw_y + line.size[1] / 2), line.text, font=font, fill=shared.opts.font_color if line.is_active else color_inactive, anchor="mm", align="center") if not line.is_active: @@ -230,7 +228,7 @@ def resize_image(resize_mode, im, width, height, upscaler_name=None, output_type def resize(im, w, h): if upscaler_name is None or upscaler_name == "None" or im.mode == 'L': - return im.resize((w, h), resample=LANCZOS) + return im.resize((w, h), resample=Image.Resampling.LANCZOS) 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] @@ -241,7 +239,7 @@ def resize_image(resize_mode, im, width, height, upscaler_name=None, output_type upscaler = upscalers[0] im = upscaler.scaler.upscale(im, scale, upscaler.data_path) if im.width != w or im.height != h: - im = im.resize((w, h), resample=LANCZOS) + im = im.resize((w, h), resample=Image.Resampling.LANCZOS) return im if resize_mode == 0: diff --git a/modules/sd_models.py b/modules/sd_models.py index fc96b00c5..e0a9d359b 100644 --- a/modules/sd_models.py +++ b/modules/sd_models.py @@ -595,51 +595,52 @@ def change_backend(): refresh_vae_list() -def detect_pipeline(f: str, op: str = 'model'): +def detect_pipeline(f: str, op: str = 'model', warning=True): if not f.endswith('.safetensors'): return None, None guess = shared.opts.diffusers_pipeline + warn = shared.log.warning if warning else lambda *args, **kwargs: None if guess == 'Autodetect': try: size = round(os.path.getsize(f) / 1024 / 1024) if size < 128: - shared.log.warning(f'Model size smaller than expected: {f} size={size} MB') + warn(f'Model size smaller than expected: {f} size={size} MB') elif (size >= 316 and size <= 324) or (size >= 156 and size <= 164): # 320 or 160 - shared.log.warning(f'Model detected as VAE model, but attempting to load as model: {op}={f} size={size} MB') + warn(f'Model detected as VAE model, but attempting to load as model: {op}={f} size={size} MB') guess = 'VAE' elif size >= 5351 and size <= 5359: # 5353 guess = 'Stable Diffusion' # SD v2 elif size >= 5791 and size <= 5799: # 5795 if shared.backend == shared.Backend.ORIGINAL: - shared.log.warning(f'Model detected as SD-XL refiner model, but attempting to load using backend=original: {op}={f} size={size} MB') + warn(f'Model detected as SD-XL refiner model, but attempting to load using backend=original: {op}={f} size={size} MB') if op == 'model': - shared.log.warning(f'Model detected as SD-XL refiner model, but attempting to load a base model: {op}={f} size={size} MB') + warn(f'Model detected as SD-XL refiner model, but attempting to load a base model: {op}={f} size={size} MB') guess = 'Stable Diffusion XL' elif (size >= 6611 and size <= 6619) or (size >= 6771 and size <= 6779): # 6617, HassakuXL is 6776 if shared.backend == shared.Backend.ORIGINAL: - shared.log.warning(f'Model detected as SD-XL base model, but attempting to load using backend=original: {op}={f} size={size} MB') + warn(f'Model detected as SD-XL base model, but attempting to load using backend=original: {op}={f} size={size} MB') guess = 'Stable Diffusion XL' elif size >= 3361 and size <= 3369: # 3368 if shared.backend == shared.Backend.ORIGINAL: - shared.log.warning(f'Model detected as SD upscale model, but attempting to load using backend=original: {op}={f} size={size} MB') + warn(f'Model detected as SD upscale model, but attempting to load using backend=original: {op}={f} size={size} MB') guess = 'Stable Diffusion Upscale' elif size >= 4891 and size <= 4899: # 4897 if shared.backend == shared.Backend.ORIGINAL: - shared.log.warning(f'Model detected as SD XL inpaint model, but attempting to load using backend=original: {op}={f} size={size} MB') + warn(f'Model detected as SD XL inpaint model, but attempting to load using backend=original: {op}={f} size={size} MB') guess = 'Stable Diffusion XL Inpaint' elif size >= 9791 and size <= 9799: # 9794 if shared.backend == shared.Backend.ORIGINAL: - shared.log.warning(f'Model detected as SD XL instruct pix2pix model, but attempting to load using backend=original: {op}={f} size={size} MB') + warn(f'Model detected as SD XL instruct pix2pix model, but attempting to load using backend=original: {op}={f} size={size} MB') guess = 'Stable Diffusion XL Instruct' else: guess = 'Stable Diffusion' if 'LCM_' in f or 'LCM-' in f: if shared.backend == shared.Backend.ORIGINAL: - shared.log.warning(f'Model detected as LCM model, but attempting to load using backend=original: {op}={f} size={size} MB') + warn(f'Model detected as LCM model, but attempting to load using backend=original: {op}={f} size={size} MB') guess = 'Latent Consistency Model' if 'PixArt' in f: if shared.backend == shared.Backend.ORIGINAL: - shared.log.warning(f'Model detected as PixArt Alpha model, but attempting to load using backend=original: {op}={f} size={size} MB') + warn(f'Model detected as PixArt Alpha model, but attempting to load using backend=original: {op}={f} size={size} MB') guess = 'PixArt Alpha' pipeline = shared_items.get_pipelines().get(guess, None) shared.log.info(f'Autodetect: {op}="{guess}" class={pipeline.__name__} file="{f}" size={size}MB') diff --git a/requirements.txt b/requirements.txt index 4207bf910..04dd5360f 100644 --- a/requirements.txt +++ b/requirements.txt @@ -50,10 +50,10 @@ requests==2.31.0 tqdm==4.66.1 accelerate==0.20.3 opencv-python-headless==4.7.0.72 -diffusers==0.23.0 +diffusers==0.23.1 einops==0.4.1 gradio==3.43.2 -huggingface_hub==0.19.2 +huggingface_hub==0.19.4 numexpr==2.8.4 numpy==1.24.4 numba==0.57.1 @@ -63,7 +63,7 @@ pytorch_lightning==1.9.4 transformers==4.35.1 tomesd==0.1.3 urllib3==1.26.15 -Pillow==9.5.0 +Pillow==10.1.0 timm==0.9.7 pydantic==1.10.13 typing-extensions==4.8.0 From 75af4087e81009627c392f7f4d5beec9e8973414 Mon Sep 17 00:00:00 2001 From: Vladimir Mandic Date: Fri, 17 Nov 2023 10:53:21 -0500 Subject: [PATCH 46/84] formatting --- javascript/sdnext.css | 4 ++-- modules/processing_diffusers.py | 1 - modules/ui_common.py | 21 ++++++++++++++------- 3 files changed, 16 insertions(+), 10 deletions(-) diff --git a/javascript/sdnext.css b/javascript/sdnext.css index 31b8a8f5c..f07228cf0 100644 --- a/javascript/sdnext.css +++ b/javascript/sdnext.css @@ -94,7 +94,8 @@ div#extras_scale_to_tab div.form{ flex-direction: row; } #mode_img2img .gradio-image > div.fixed-height, #mode_img2img .gradio-image > div.fixed-height img{ height: 480px !important; max-height: 480px !important; min-height: 480px !important; } #img2img_sketch, #img2maskimg, #inpaint_sketch { overflow: overlay !important; resize: auto; background: var(--panel-background-fill); z-index: 5; } .image-buttons button{ min-width: auto; } -.infotext { overflow-wrap: break-word; } +.infotext { overflow-wrap: break-word; line-height: 1.5em; } +.infotext > p { padding-left: 1em; text-indent: -1em; } .tooltip { display: block; position: fixed; top: 1em; right: 1em; padding: 0.5em; background: var(--input-background-fill); color: var(--body-text-color); border: 1pt solid var(--button-primary-border-color); width: 22em; min-height: 1.3em; font-size: 0.8em; transition: opacity 0.2s ease-in; pointer-events: none; opacity: 0; z-index: 999; } .tooltip-show { opacity: 0.9; } @@ -234,7 +235,6 @@ table.settings-value-table td { padding: 0.4em; border: 1px solid #ccc; max-widt .extras { gap: 0.2em 1em !important } #extras_generate, #extras_interrupt, #extras_skip { display: block !important; position: relative; height: 36px; } #extras_upscale { margin-top: 10px } -#pnginfo_html_info { line-height: 1.5em; } /* log monitor */ .log-monitor { display: none; justify-content: unset !important; overflow: hidden; padding: 0; margin-top: auto; font-family: monospace; font-size: 0.85em; } diff --git a/modules/processing_diffusers.py b/modules/processing_diffusers.py index 59ec22a41..00b22055d 100644 --- a/modules/processing_diffusers.py +++ b/modules/processing_diffusers.py @@ -470,7 +470,6 @@ def process_diffusers(p: StableDiffusionProcessing, seeds, prompts, negative_pro desc='Base', ) shared.state.sampling_steps = base_args['num_inference_steps'] - p.extra_generation_params['CFG rescale'] = p.diffusers_guidance_rescale p.extra_generation_params["Sampler Eta"] = shared.opts.scheduler_eta if shared.opts.scheduler_eta is not None and shared.opts.scheduler_eta > 0 and shared.opts.scheduler_eta < 1 else None try: output = shared.sd_model(**base_args) # pylint: disable=not-callable diff --git a/modules/ui_common.py b/modules/ui_common.py index 9206c6c59..a2b8aa1ee 100644 --- a/modules/ui_common.py +++ b/modules/ui_common.py @@ -6,7 +6,7 @@ import platform import subprocess import gradio as gr from modules import call_queue, shared -from modules.generation_parameters_copypaste import image_from_url_text +from modules.generation_parameters_copypaste import image_from_url_text, parse_generation_parameters import modules.ui_symbols as symbols import modules.images import modules.script_callbacks @@ -34,12 +34,19 @@ def plaintext_to_html(text): def infotext_to_html(text): - res = '

Prompt: ' + html.escape(text or '').replace('\n', '
') + '

' - sections = res.split('Steps:') # before and after prompt+negprompt' - if len(sections) > 1: - res = sections[0] + '
Steps: ' + sections[1].strip().replace(', ', ' | ') - res = res.replace('

', '
') - return res + res = parse_generation_parameters(text) + prompt = res.get('Prompt', None) + negative = res.get('Negative prompt', None) + res.pop('Prompt', None) + res.pop('Negative prompt', None) + params = [f'{k}: {v}' for k, v in res.items() if v is not None] + params = '| '.join(params) + code = f''' +

Prompt: {prompt}

+

Negative: {negative}

+

Parameters: {params}

+ ''' + return code def delete_files(js_data, images, _html_info, index): From 7ef41af090276de5b226474b62c2c238e89ab124 Mon Sep 17 00:00:00 2001 From: Disty0 Date: Fri, 17 Nov 2023 23:32:12 +0300 Subject: [PATCH 47/84] Fix AnimateDiff is_sdxl error --- modules/sd_models.py | 1 + 1 file changed, 1 insertion(+) diff --git a/modules/sd_models.py b/modules/sd_models.py index e0a9d359b..6a5a40fef 100644 --- a/modules/sd_models.py +++ b/modules/sd_models.py @@ -1088,6 +1088,7 @@ def load_model(checkpoint_info=None, already_loaded_state_dict=None, timer=None, shared.log.debug(f"Model created from config: {checkpoint_config}") sd_model.used_config = checkpoint_config sd_model.has_accelerate = False + sd_model.is_sdxl = False # a1111 compatibility item timer.record("create") ok = load_model_weights(sd_model, checkpoint_info, state_dict, timer) if not ok: From d46dddd02467ef5632dbd9619839d0849eac16a8 Mon Sep 17 00:00:00 2001 From: Vladimir Mandic Date: Fri, 17 Nov 2023 16:59:30 -0500 Subject: [PATCH 48/84] fix upscale and add some compile options --- CHANGELOG.md | 3 ++- installer.py | 24 ++++++++++++------------ modules/processing_diffusers.py | 18 ++++++++---------- modules/sd_models_compile.py | 3 +++ modules/shared.py | 2 +- modules/upscaler.py | 2 +- 6 files changed, 27 insertions(+), 25 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3ce6e547a..0807b2c2c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -43,13 +43,14 @@ - Support `--ckpt none` to skip loading a model - **XYZ grid** - Add refiner options to XYZ Grid - - Add option to create only subimages in XYZ grid, thanks @midcoastal + - Add option to create only subgrids in XYZ grid, thanks @midcoastal - Allow custom font, background and text color in settings - **Fixes** - Fix `params.txt` saved before actual image - Fix inpaint - Fix manual grid image save - Fix img2img init image save + - Fix upscale in txt2img for batch counts when no hires is used - More uniform models paths - Safe scripts callback execution - Improved extension compatibility diff --git a/installer.py b/installer.py index 04a160b5c..5e7f4bc7c 100644 --- a/installer.py +++ b/installer.py @@ -775,26 +775,26 @@ def install_requirements(): # set environment variables controling the behavior of various libraries def set_environment(): log.debug('Setting environment tuning') - os.environ.setdefault('USE_TORCH', '1') - os.environ.setdefault('TF_CPP_MIN_LOG_LEVEL', '2') os.environ.setdefault('ACCELERATE', 'True') - os.environ.setdefault('FORCE_CUDA', '1') os.environ.setdefault('ATTN_PRECISION', 'fp16') - os.environ.setdefault('PYTORCH_CUDA_ALLOC_CONF', 'garbage_collection_threshold:0.8,max_split_size_mb:512') - os.environ.setdefault('CUDA_LAUNCH_BLOCKING', '0') - os.environ.setdefault('CUDA_CACHE_DISABLE', '0') os.environ.setdefault('CUDA_AUTO_BOOST', '1') - os.environ.setdefault('CUDA_MODULE_LOADING', 'LAZY') + os.environ.setdefault('CUDA_CACHE_DISABLE', '0') os.environ.setdefault('CUDA_DEVICE_DEFAULT_PERSISTING_L2_CACHE_PERCENTAGE_LIMIT', '0') + os.environ.setdefault('CUDA_LAUNCH_BLOCKING', '0') + os.environ.setdefault('CUDA_MODULE_LOADING', 'LAZY') + os.environ.setdefault('FORCE_CUDA', '1') os.environ.setdefault('GRADIO_ANALYTICS_ENABLED', 'False') - os.environ.setdefault('SAFETENSORS_FAST_GPU', '1') + os.environ.setdefault('HF_HUB_DISABLE_EXPERIMENTAL_WARNING', '1') + os.environ.setdefault('HF_HUB_DISABLE_TELEMETRY', '1') + os.environ.setdefault('K_DIFFUSION_USE_COMPILE', '0') os.environ.setdefault('NUMEXPR_MAX_THREADS', '16') os.environ.setdefault('PYTHONHTTPSVERIFY', '0') - os.environ.setdefault('HF_HUB_DISABLE_TELEMETRY', '1') - os.environ.setdefault('HF_HUB_DISABLE_EXPERIMENTAL_WARNING', '1') - os.environ.setdefault('UVICORN_TIMEOUT_KEEP_ALIVE', '60') - os.environ.setdefault('K_DIFFUSION_USE_COMPILE', '0') + os.environ.setdefault('PYTORCH_CUDA_ALLOC_CONF', 'garbage_collection_threshold:0.8,max_split_size_mb:512') + os.environ.setdefault('SAFETENSORS_FAST_GPU', '1') + os.environ.setdefault('TF_CPP_MIN_LOG_LEVEL', '2') os.environ.setdefault('TF_ENABLE_ONEDNN_OPTS', '0') + os.environ.setdefault('USE_TORCH', '1') + os.environ.setdefault('UVICORN_TIMEOUT_KEEP_ALIVE', '60') if sys.platform == 'darwin': os.environ.setdefault('PYTORCH_ENABLE_MPS_FALLBACK', '1') diff --git a/modules/processing_diffusers.py b/modules/processing_diffusers.py index 00b22055d..f491fa58b 100644 --- a/modules/processing_diffusers.py +++ b/modules/processing_diffusers.py @@ -42,16 +42,14 @@ def process_diffusers(p: StableDiffusionProcessing, seeds, prompts, negative_pro if latent_upscaler is not None: latents = torch.nn.functional.interpolate(latents, size=(p.hr_upscale_to_y // 8, p.hr_upscale_to_x // 8), mode=latent_upscaler["mode"], antialias=latent_upscaler["antialias"]) first_pass_images = vae_decode(latents=latents, model=shared.sd_model, full_quality=p.full_quality, output_type='pil') - p.init_images = [] + resized_images = [] for img in first_pass_images: if latent_upscaler is None: - init_image = images.resize_image(1, img, p.hr_upscale_to_x, p.hr_upscale_to_y, upscaler_name=p.hr_upscaler) + resized_image = images.resize_image(1, img, p.hr_upscale_to_x, p.hr_upscale_to_y, upscaler_name=p.hr_upscaler) else: - init_image = img - # if is_refiner_enabled: - # init_image = vae_encode(init_image, model=shared.sd_model, full_quality=p.full_quality) - p.init_images.append(init_image) - return p.init_images + resized_image = img + resized_images.append(resized_image) + return resized_images def save_intermediate(latents, suffix): for i in range(len(latents)): @@ -489,7 +487,7 @@ def process_diffusers(p: StableDiffusionProcessing, seeds, prompts, negative_pro return results # optional hires pass - if p.enable_hr and p.hr_upscaler != 'None' and p.denoising_strength > 0 and len(getattr(p, 'init_images', [])) == 0: + if p.enable_hr and getattr(p, 'hr_upscaler', 'None') != 'None' and len(getattr(p, 'init_images', [])) == 0: p.is_hr_pass = True latent_scale_mode = shared.latent_upscale_modes.get(p.hr_upscaler, None) if (hasattr(p, "hr_upscaler") and p.hr_upscaler is not None) else shared.latent_upscale_modes.get(shared.latent_upscale_default_mode, "None") if p.is_hr_pass: @@ -501,7 +499,7 @@ def process_diffusers(p: StableDiffusionProcessing, seeds, prompts, negative_pro save_intermediate(latents=output.images, suffix="-before-hires") shared.state.job = 'upscale' output.images = hires_resize(latents=output.images) - if latent_scale_mode is not None or p.hr_force: + if (latent_scale_mode is not None or p.hr_force) and p.denoising_strength > 0: p.ops.append('hires') shared.sd_model = sd_models.set_diffuser_pipe(shared.sd_model, sd_models.DiffusersTaskType.IMAGE_2_IMAGE) recompile_model(hires=True) @@ -518,7 +516,7 @@ def process_diffusers(p: StableDiffusionProcessing, seeds, prompts, negative_pro guidance_rescale=p.diffusers_guidance_rescale, output_type='latent' if hasattr(shared.sd_model, 'vae') else 'np', clip_skip=p.clip_skip, - image=p.init_images, + image=output.images, strength=p.denoising_strength, desc='Hires', ) diff --git a/modules/sd_models_compile.py b/modules/sd_models_compile.py index fe9f355d1..353171435 100644 --- a/modules/sd_models_compile.py +++ b/modules/sd_models_compile.py @@ -76,6 +76,9 @@ def compile_stablefast(sd_model): warnings.filterwarnings("ignore", category=torch.jit.TracerWarning) config.enable_cuda_graph = shared.opts.cuda_compile_fullgraph config.enable_jit_freeze = shared.opts.diffusers_eval + config.memory_format = torch.channels_last if shared.opts.opt_channelslast else torch.contiguous_format + # config.enable_cnn_optimization + # config.prefer_lowp_gemm try: t0 = time.time() sd_model = sf.compile(sd_model, config) diff --git a/modules/shared.py b/modules/shared.py index 2b28f5eb5..0cb16deb8 100644 --- a/modules/shared.py +++ b/modules/shared.py @@ -307,7 +307,7 @@ options_templates.update(options_section(('cuda', "Compute Settings"), { "cuda_compile_vae": OptionInfo(True if cmd_opts.use_openvino else False, "Compile VAE"), "cuda_compile_upscaler": OptionInfo(True if cmd_opts.use_openvino else False, "Compile upscaler"), "cuda_compile_backend": OptionInfo("openvino_fx" if cmd_opts.use_openvino else "none", "Model compile backend", gr.Radio, {"choices": ['none', 'inductor', 'cudagraphs', 'aot_ts_nvfuser', 'hidet', 'ipex', 'openvino_fx', 'stable-fast']}), - "cuda_compile_mode": OptionInfo("default", "Model compile mode", gr.Radio, {"choices": ['default', 'reduce-overhead', 'max-autotune']}), + "cuda_compile_mode": OptionInfo("default", "Model compile mode", gr.Radio, {"choices": ['default', 'reduce-overhead', 'max-autotune', 'max-autotune-no-cudagraphs']}), "cuda_compile_fullgraph": OptionInfo(False, "Model compile fullgraph"), "cuda_compile_precompile": OptionInfo(False if cmd_opts.use_openvino else True, "Model compile precompile"), "cuda_compile_verbose": OptionInfo(False, "Model compile verbose mode"), diff --git a/modules/upscaler.py b/modules/upscaler.py index 9228bc658..d15f44ad3 100644 --- a/modules/upscaler.py +++ b/modules/upscaler.py @@ -228,7 +228,7 @@ def compile_upscaler(model, name=""): if modules.shared.opts.cuda_compile_backend == "openvino_fx": from modules.intel.openvino import openvino_fx # pylint: disable=unused-import - from modules.sd_models_compile import CompiledModelState + from modules.sd_models_compile import CompiledModelState # pylint: disable=unused-import torch._dynamo.eval_frame.check_if_dynamo_supported = lambda: True # pylint: disable=protected-access log_level = logging.WARNING if modules.shared.opts.cuda_compile_verbose else logging.CRITICAL # pylint: disable=protected-access From 19257bbfe232b9dce4494825905f5b78533846bb Mon Sep 17 00:00:00 2001 From: Vladimir Mandic Date: Fri, 17 Nov 2023 18:20:45 -0500 Subject: [PATCH 49/84] fix auth logging --- webui.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/webui.py b/webui.py index 103d78ec7..46e3d7156 100644 --- a/webui.py +++ b/webui.py @@ -248,7 +248,7 @@ def start_ui(): for line in file.readlines(): gradio_auth_creds += [x.strip() for x in line.split(',') if x.strip()] if len(gradio_auth_creds) > 0: - log.info(f'Authentication enabled: {gradio_auth_creds}') + log.info(f'Authentication enabled: users={len(list(gradio_auth_creds))}') global local_url # pylint: disable=global-statement stdout = io.StringIO() From 2515b832515d8b8995ec333f6ab6007178b6d8ad Mon Sep 17 00:00:00 2001 From: AI-Casanova <54461896+AI-Casanova@users.noreply.github.com> Date: Fri, 17 Nov 2023 19:30:33 -0600 Subject: [PATCH 50/84] GUI Improvement --- html/locale_en.json | 10 +++++++++- modules/ui_models.py | 18 +++++++++++------- 2 files changed, 20 insertions(+), 8 deletions(-) diff --git a/html/locale_en.json b/html/locale_en.json index 65f239e10..daf5785a9 100644 --- a/html/locale_en.json +++ b/html/locale_en.json @@ -14,6 +14,7 @@ {"id":"","label":"⊗","localized":"","hint":"Clear prompt"}, {"id":"","label":"🗁","localized":"","hint":"Show/hide extra networks"}, {"id":"","label":"⇰","localized":"","hint":"Apply selected styles to current prompt"}, + {"id":"","label":"⇨","localized":"","hint":"Apply preset to Manual Block Merge tab"}, {"id":"","label":"⇩","localized":"","hint":"Save parameters from last generated image as style template"}, {"id":"","label":"🕮","localized":"","hint":"Save parameters from last generated image as style template"}, {"id":"","label":"⇕","localized":"","hint":"Sort by: Name asc/desc, Size largest/smallest, Time newest/oldest"}, @@ -255,7 +256,14 @@ {"id":"","label":"specify model variant","localized":"","hint":""}, {"id":"","label":"specify model revision","localized":"","hint":""}, {"id":"","label":"huggingface token","localized":"","hint":""}, - {"id":"","label":"huggingface mirror","localized":"","hint":""} + {"id":"","label":"huggingface mirror","localized":"","hint":""}, + {"id":"","label":"Weights Clip","localized":"","hint":"Forced merged weights to be no heavier than the original model, preventing burn in and overly saturated models"}, + {"id":"","label":"ReBasin","localized":"","hint":"Performs multiple merges with permutations in order to keep more features from both models"}, + {"id":"","label":"Number of ReBasin Iterations","localized":"","hint":"Number of times to merge and permute the model before saving"}, + {"id":"","label":"Base","localized":"","hint":"Text Encoder and a few unaligned keys (1 value)"}, + {"id":"","label":"In Blocks","localized":"","hint":"Downsampling Blocks of the UNet (12 values for SD1.5, 9 values for SDXL)"}, + {"id":"","label":"Mid Block","localized":"","hint":"Central Block of the UNet (1 value)"}, + {"id":"","label":"Out Block","localized":"","hint":"Upsampling Blocks of the UNet (12 values for SD1.5, 9 values for SDXL)"} ], "train tabs": [ {"id":"","label":"Preprocess","localized":"","hint":""}, diff --git a/modules/ui_models.py b/modules/ui_models.py index 41d691e30..16697df7c 100644 --- a/modules/ui_models.py +++ b/modules/ui_models.py @@ -167,8 +167,8 @@ def create_ui(): with FormRow(): merge_mode = gr.Dropdown(choices=merge_methods.__all__, value="weighted_sum", label="Interpolation Method") - merge_mode_help = ToolButton('❔', visible=True) - merge_mode_docs = gr.Textbox(value=None, visible=False) + with FormRow(): + merge_mode_docs = gr.HTML(value=None, visible=False) with FormRow(): primary_model_name = gr.Dropdown(sd_model_choices(), label="Primary model", value="None") create_refresh_button(primary_model_name, sd_models.list_models, @@ -244,7 +244,7 @@ def create_ui(): with FormRow(): precision = gr.Radio(choices=["fp16", "fp32"], value="fp16", label="Model precision") with FormRow(): - work_device = gr.Radio(choices=["cpu", "cuda"], value="cpu", label="Device") + device = gr.Radio(choices=["cpu", "shuffle", "cuda"], value="cpu", label="Merge Device") with FormRow(): bake_in_vae = gr.Dropdown(choices=["None"] + list(sd_vae.vae_dict), value="None", interactive=True, label="Bake in VAE") @@ -283,7 +283,7 @@ def create_ui(): prune, re_basin, re_basin_iterations, - work_device, + device, bake_in_vae): kwargs = {} for x in inspect.getfullargspec(MEHmodelmerger)[0]: @@ -291,6 +291,9 @@ def create_ui(): for key in list(kwargs.keys()): if kwargs[key] in [None, "None", "", 0, []]: del kwargs[key] + if kwargs["device"] == "shuffle": + kwargs["device"] = "cpu" + kwargs["work_device"] = "cuda" try: results = extras.run_MEHmodelmerger(dummy_component, **kwargs) @@ -327,7 +330,7 @@ def create_ui(): def show_help(mode): doc = getattr(merge_methods, mode).__doc__ - return gr.update(value=doc, visible=True, interactive=False) + return gr.update(value=doc, visible=True) def load_presets(presets, ratio): for i, p in enumerate(presets): @@ -345,7 +348,8 @@ def create_ui(): return [gr.update(choices=["None"] + list(SDXL_BLOCK_WEIGHTS_PRESETS.keys())) for _ in range(2)] else: return [gr.update(choices=["None"] + list(BLOCK_WEIGHTS_PRESETS.keys())) for _ in range(2)] - merge_mode_help.click(fn=show_help, inputs=merge_mode, outputs=merge_mode_docs) + + merge_mode.change(fn=show_help, inputs=merge_mode, outputs=merge_mode_docs) sdxl.change(fn=preset_choices, inputs=sdxl, outputs=[alpha_preset, beta_preset]) alpha_preset.change(fn=preset_visiblility, inputs=alpha_preset, outputs=alpha_preset_lambda) beta_preset.change(fn=preset_visiblility, inputs=alpha_preset, outputs=beta_preset_lambda) @@ -390,7 +394,7 @@ def create_ui(): prune, re_basin, re_basin_iterations, - work_device, + device, bake_in_vae, ], outputs=[ From abb4739590e117b937c4ca26a47e93ee4c742b68 Mon Sep 17 00:00:00 2001 From: AI-Casanova <54461896+AI-Casanova@users.noreply.github.com> Date: Fri, 17 Nov 2023 20:18:55 -0600 Subject: [PATCH 51/84] More UI Improvements --- html/locale_en.json | 4 ++++ modules/extras.py | 3 +++ modules/ui_models.py | 13 +++++++------ 3 files changed, 14 insertions(+), 6 deletions(-) diff --git a/html/locale_en.json b/html/locale_en.json index daf5785a9..e7289c456 100644 --- a/html/locale_en.json +++ b/html/locale_en.json @@ -260,10 +260,14 @@ {"id":"","label":"Weights Clip","localized":"","hint":"Forced merged weights to be no heavier than the original model, preventing burn in and overly saturated models"}, {"id":"","label":"ReBasin","localized":"","hint":"Performs multiple merges with permutations in order to keep more features from both models"}, {"id":"","label":"Number of ReBasin Iterations","localized":"","hint":"Number of times to merge and permute the model before saving"}, + {"id":"","label":"cpu","localized":"","hint":"Uses cpu and RAM only: slowest but least likely to OOM"}, + {"id":"","label":"shuffle","localized":"","hint":"Loads full model in RAM and calculates on VRAM: Less speedup, suggested for SDXL merges"}, + {"id":"","label":"cuda","localized":"","hint":"Loads models into VRAM automatically unloading current model: fastest option but unlikely to handle SDXL Models without OOM"}, {"id":"","label":"Base","localized":"","hint":"Text Encoder and a few unaligned keys (1 value)"}, {"id":"","label":"In Blocks","localized":"","hint":"Downsampling Blocks of the UNet (12 values for SD1.5, 9 values for SDXL)"}, {"id":"","label":"Mid Block","localized":"","hint":"Central Block of the UNet (1 value)"}, {"id":"","label":"Out Block","localized":"","hint":"Upsampling Blocks of the UNet (12 values for SD1.5, 9 values for SDXL)"} + {"id":"","label":"Preset Interpolation Ratio","localized":"","hint":"If two presets are selected, interpolate between them"} ], "train tabs": [ {"id":"","label":"Preprocess","localized":"","hint":""}, diff --git a/modules/extras.py b/modules/extras.py index 467946166..3dee5f6a2 100644 --- a/modules/extras.py +++ b/modules/extras.py @@ -311,6 +311,9 @@ def run_MEHmodelmerger(id_task, **kwargs): # pylint: disable=unused-argument kwargs.pop("beta_mid_block", None) kwargs.pop("beta_out_blocks", None) kwargs.pop("beta_preset", None) + + if kwargs["device"] == "cuda": + sd_models.unload_model_weights() try: theta_0 = merge_models(**kwargs) diff --git a/modules/ui_models.py b/modules/ui_models.py index 16697df7c..95fbe1522 100644 --- a/modules/ui_models.py +++ b/modules/ui_models.py @@ -160,6 +160,7 @@ def create_ui(): def sd_model_choices(): return ['None'] + sd_models.checkpoint_tiles() + with gr.Row(equal_height=False): with gr.Column(variant='compact'): with FormRow(): @@ -167,8 +168,7 @@ def create_ui(): with FormRow(): merge_mode = gr.Dropdown(choices=merge_methods.__all__, value="weighted_sum", label="Interpolation Method") - with FormRow(): - merge_mode_docs = gr.HTML(value=None, visible=False) + merge_mode_docs = gr.HTML(value=getattr(merge_methods, "weighted_sum").__doc__.replace("\n", "
")) with FormRow(): primary_model_name = gr.Dropdown(sd_model_choices(), label="Primary model", value="None") create_refresh_button(primary_model_name, sd_models.list_models, @@ -322,15 +322,16 @@ def create_ui(): else: return gr.Slider.update(value=None, visible=False) + def show_help(mode): + doc = getattr(merge_methods, mode).__doc__.replace("\n", "
") + return gr.update(value=doc, visible=True) + def preset_visiblility(x): if len(x) == 2: return gr.Slider.update(value=0.5, visible=True) else: return gr.Slider.update(value=None, visible=False) - def show_help(mode): - doc = getattr(merge_methods, mode).__doc__ - return gr.update(value=doc, visible=True) def load_presets(presets, ratio): for i, p in enumerate(presets): @@ -339,7 +340,7 @@ def create_ui(): preset = interpolate(presets, ratio) else: preset = presets[0] - preset = ['%.3f' % x for x in preset] + preset = ['%.3f' % x if int(x) != x else str(x) for x in preset] preset = [preset[0], ",".join(preset[1:13]), preset[13], ",".join(preset[14:])] return [gr.update(value=x) for x in preset] + [gr.update(selected=2)] From cb8be0fc6e99f66c7b8c3d570a9fd4c835ea8cec Mon Sep 17 00:00:00 2001 From: AI-Casanova <54461896+AI-Casanova@users.noreply.github.com> Date: Fri, 17 Nov 2023 20:35:06 -0600 Subject: [PATCH 52/84] Add torch.device --- modules/extras.py | 2 +- modules/merging/merge.py | 41 +++++++++++++++++----------------- modules/merging/merge_model.py | 6 ++--- 3 files changed, 23 insertions(+), 26 deletions(-) diff --git a/modules/extras.py b/modules/extras.py index 3dee5f6a2..c60568bf6 100644 --- a/modules/extras.py +++ b/modules/extras.py @@ -311,7 +311,7 @@ def run_MEHmodelmerger(id_task, **kwargs): # pylint: disable=unused-argument kwargs.pop("beta_mid_block", None) kwargs.pop("beta_out_blocks", None) kwargs.pop("beta_preset", None) - + if kwargs["device"] == "cuda": sd_models.unload_model_weights() diff --git a/modules/merging/merge.py b/modules/merging/merge.py index e0ed32145..2330d50d5 100644 --- a/modules/merging/merge.py +++ b/modules/merging/merge.py @@ -1,4 +1,3 @@ -import gc import os from concurrent.futures import ThreadPoolExecutor from contextlib import contextmanager @@ -10,6 +9,7 @@ import torch from tqdm import tqdm import modules.memstats +import modules.devices as devices from modules.shared import log from modules.merging import merge_methods from modules.merging.merge_utils import WeightClass @@ -69,7 +69,7 @@ def fix_model(model: Dict) -> Dict: return fix_clip(model) -def load_sd_model(model: os.PathLike | str, device: str = "cpu") -> Dict: +def load_sd_model(model: os.PathLike | str, device: torch.device = None) -> Dict: if isinstance(model, str): model = Path(model) @@ -102,7 +102,7 @@ def log_vram(txt=""): def load_thetas( models: Dict[str, os.PathLike | str], prune: bool, - device: str, + device: torch.device, precision: str, ) -> Dict: log_vram("before loading models") @@ -111,13 +111,12 @@ def load_thetas( else: thetas = {k: load_sd_model(m, device) for k, m in models.items()} - if device == "cuda": - for model_key, model in thetas.items(): - for key, block in model.items(): - if precision == "fp16": - thetas[model_key].update({key: block.to(device).half()}) - else: - thetas[model_key].update({key: block.to(device)}) + for model_key, model in thetas.items(): + for key, block in model.items(): + if precision == "fp16": + thetas[model_key].update({key: block.to(device).half()}) + else: + thetas[model_key].update({key: block.to(device)}) log_vram("models loaded") return thetas @@ -129,8 +128,8 @@ def merge_models( precision: str = "fp16", weights_clip: bool = False, re_basin: bool = False, - device: str = "cpu", - work_device: Optional[str] = None, + device: torch.device = None, + work_device: torch.device = None, prune: bool = False, threads: int = 1, **kwargs, @@ -178,7 +177,7 @@ def un_prune_model( if prune: log.info("Un-pruning merged model") del thetas - gc.collect() + devices.torch_gc(force=True) log_vram("remove thetas") original_a = load_sd_model(models["model_a"], device) for key in tqdm(original_a.keys(), desc="un-prune model a"): @@ -189,7 +188,7 @@ def un_prune_model( if precision == "fp16": merged.update({key: merged[key].half()}) del original_a - gc.collect() + devices.torch_gc(force=True) # log_vram("remove original_a") original_b = load_sd_model(models["model_b"], device) for key in tqdm(original_b.keys(), desc="un-prune model b"): @@ -210,8 +209,8 @@ def simple_merge( merge_mode: str, precision: str = "fp16", weights_clip: bool = False, - device: str = "cpu", - work_device: Optional[str] = None, + device: torch.device = None, + work_device: torch.device = None, threads: int = 1, ) -> Dict: futures = [] @@ -257,8 +256,8 @@ def rebasin_merge( precision: str = "fp16", weights_clip: bool = False, iterations: int = 1, - device="cpu", - work_device=None, + device: torch.device = None, + work_device: torch.device = None, threads: int = 1, ): # WARNING: not sure how this does when 3 models are involved... @@ -345,8 +344,8 @@ def merge_key( merge_mode: str, precision: str = "fp16", weights_clip: bool = False, - device: str = "cpu", - work_device: Optional[str] = None, + device: torch.device = None, + work_device: torch.device = None, ) -> Optional[Tuple[str, Dict]]: if work_device is None: work_device = device @@ -413,7 +412,7 @@ def get_merge_method_args( current_bases: Dict, thetas: Dict, key: str, - work_device: str, + work_device: torch.device, ) -> Dict: merge_method_args = { "a": thetas["model_a"][key].to(work_device), diff --git a/modules/merging/merge_model.py b/modules/merging/merge_model.py index d2d6470ec..15e617808 100644 --- a/modules/merging/merge_model.py +++ b/modules/merging/merge_model.py @@ -1,4 +1,3 @@ -# import logging import os from dataclasses import dataclass @@ -6,17 +5,16 @@ import safetensors import torch from tensordict import TensorDict -# logging.getLogger("sd_meh").addHandler(logging.NullHandler()) @dataclass class SDModel: model_path: os.PathLike - device: str + device: torch.device def load_model(self): # logging.info(f"Loading: {self.model_path}") - if self.model_path.suffix == ".safetensors": + if os.path.splitext(self.model_path) == ".safetensors": ckpt = safetensors.torch.load_file( self.model_path, device=self.device, From 6aa859198f7fdea96e0e3d4c02fbd0087779edf3 Mon Sep 17 00:00:00 2001 From: AI-Casanova <54461896+AI-Casanova@users.noreply.github.com> Date: Fri, 17 Nov 2023 21:10:56 -0600 Subject: [PATCH 53/84] device fixes --- modules/extras.py | 9 ++++++++- modules/ui_models.py | 5 ----- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/modules/extras.py b/modules/extras.py index c60568bf6..6f990cac8 100644 --- a/modules/extras.py +++ b/modules/extras.py @@ -11,7 +11,7 @@ import safetensors.torch from modules.merging.merge import merge_models from modules.merging.merge_utils import TRIPLE_METHODS -from modules import shared, images, sd_models, sd_vae, sd_models_config +from modules import shared, images, sd_models, sd_vae, sd_models_config, devices checkpoint_dict_skip_on_merge = ["cond_stage_model.transformer.text_model.embeddings.position_ids"] @@ -313,7 +313,14 @@ def run_MEHmodelmerger(id_task, **kwargs): # pylint: disable=unused-argument kwargs.pop("beta_preset", None) if kwargs["device"] == "cuda": + kwargs["device"] == devices.device sd_models.unload_model_weights() + elif kwargs["device"] == "shuffle": + kwargs["device"] = torch.device("cpu") + kwargs["work_device"] = devices.device + else: + kwargs["device"] = torch.device("cpu") + try: theta_0 = merge_models(**kwargs) diff --git a/modules/ui_models.py b/modules/ui_models.py index 95fbe1522..8f9746316 100644 --- a/modules/ui_models.py +++ b/modules/ui_models.py @@ -160,7 +160,6 @@ def create_ui(): def sd_model_choices(): return ['None'] + sd_models.checkpoint_tiles() - with gr.Row(equal_height=False): with gr.Column(variant='compact'): with FormRow(): @@ -291,9 +290,6 @@ def create_ui(): for key in list(kwargs.keys()): if kwargs[key] in [None, "None", "", 0, []]: del kwargs[key] - if kwargs["device"] == "shuffle": - kwargs["device"] = "cpu" - kwargs["work_device"] = "cuda" try: results = extras.run_MEHmodelmerger(dummy_component, **kwargs) @@ -332,7 +328,6 @@ def create_ui(): else: return gr.Slider.update(value=None, visible=False) - def load_presets(presets, ratio): for i, p in enumerate(presets): presets[i] = BLOCK_WEIGHTS_PRESETS[p] From c93d6c7e2669650ec3f90787daa25b72a753786b Mon Sep 17 00:00:00 2001 From: AI-Casanova <54461896+AI-Casanova@users.noreply.github.com> Date: Fri, 17 Nov 2023 21:47:33 -0600 Subject: [PATCH 54/84] typos --- html/locale_en.json | 2 +- modules/merging/merge_model.py | 2 +- modules/ui_models.py | 1 - 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/html/locale_en.json b/html/locale_en.json index e7289c456..45074cb63 100644 --- a/html/locale_en.json +++ b/html/locale_en.json @@ -266,7 +266,7 @@ {"id":"","label":"Base","localized":"","hint":"Text Encoder and a few unaligned keys (1 value)"}, {"id":"","label":"In Blocks","localized":"","hint":"Downsampling Blocks of the UNet (12 values for SD1.5, 9 values for SDXL)"}, {"id":"","label":"Mid Block","localized":"","hint":"Central Block of the UNet (1 value)"}, - {"id":"","label":"Out Block","localized":"","hint":"Upsampling Blocks of the UNet (12 values for SD1.5, 9 values for SDXL)"} + {"id":"","label":"Out Block","localized":"","hint":"Upsampling Blocks of the UNet (12 values for SD1.5, 9 values for SDXL)"}, {"id":"","label":"Preset Interpolation Ratio","localized":"","hint":"If two presets are selected, interpolate between them"} ], "train tabs": [ diff --git a/modules/merging/merge_model.py b/modules/merging/merge_model.py index 15e617808..37427c44b 100644 --- a/modules/merging/merge_model.py +++ b/modules/merging/merge_model.py @@ -14,7 +14,7 @@ class SDModel: def load_model(self): # logging.info(f"Loading: {self.model_path}") - if os.path.splitext(self.model_path) == ".safetensors": + if os.path.splitext(self.model_path)[1] == ".safetensors": ckpt = safetensors.torch.load_file( self.model_path, device=self.device, diff --git a/modules/ui_models.py b/modules/ui_models.py index 8f9746316..e2c13a287 100644 --- a/modules/ui_models.py +++ b/modules/ui_models.py @@ -290,7 +290,6 @@ def create_ui(): for key in list(kwargs.keys()): if kwargs[key] in [None, "None", "", 0, []]: del kwargs[key] - try: results = extras.run_MEHmodelmerger(dummy_component, **kwargs) except Exception as e: From ed31a16708031e52c6debdf96fdddd012081a948 Mon Sep 17 00:00:00 2001 From: QuantumSoul Date: Sat, 18 Nov 2023 13:29:05 +0100 Subject: [PATCH 55/84] Update README.md --- README.md | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index fbd47c366..cab425bd6 100644 --- a/README.md +++ b/README.md @@ -1,30 +1,29 @@
- + # SD.Next **Stable Diffusion implementation with advanced features** -
- [![](https://img.shields.io/static/v1?label=Sponsor&message=%E2%9D%A4&logo=GitHub&color=%23fe8e86)](https://github.com/sponsors/vladmandic) ![Last Commit](https://img.shields.io/github/last-commit/vladmandic/automatic?svg=true) ![License](https://img.shields.io/github/license/vladmandic/automatic?svg=true) [![Discord](https://img.shields.io/discord/1101998836328697867?logo=Discord&svg=true)](https://discord.gg/VjvR2tabEX) -### [Wiki](https://github.com/vladmandic/automatic/wiki) | [Discord](https://discord.gg/VjvR2tabEX) | [Changelog](CHANGELOG.md) +[Wiki](https://github.com/vladmandic/automatic/wiki) | [Discord](https://discord.gg/VjvR2tabEX) | [Changelog](CHANGELOG.md)
+
-## Top-13 Features (10 wasn't enough) +## Notable features -All Individual features are not listed here, instead check [ChangeLog](CHANGELOG.md) for full list of changes. - -- Support for multiple backends! - **original** and **diffusers** -- Support for multiple diffusion models! - **Stable Diffusion, SD-XL, LCM, Segmind, Kandinsky, Pixart-α, Wuerstchen, DeepFloyd IF, UniDiffusion, SD-Distilled, etc.** -- Fully multiplatform with platform specific autodetection and tuning performed on install - **Windows / Linux / MacOS with CPU / nVidia / AMD / IntelArc / DirectML / OpenVINO / ONNX+Olive** +All individual features are not listed here, instead check [ChangeLog](CHANGELOG.md) for full list of changes. +- Broad support + - Multiple backends! + **Original | Diffusers** + - Multiple diffusion models! + **Stable Diffusion | SD-XL | LCM | Segmind | Kandinsky | Pixart-α | Würstchen | DeepFloyd IF | UniDiffusion | SD-Distilled | etc.** + - Multiplatform with platform specific autodetection and tuning performed on install + **Windows | Linux | MacOS with CPU | nVidia | AMD | IntelArc | DirectML | OpenVINO | ONNX+Olive** - Optimized processing with latest **torch** developments Including built-in support for `torch.compile` - Improved prompt parser From bdc4bd846f48c14148937bd22af8983a1faeb787 Mon Sep 17 00:00:00 2001 From: Disty0 Date: Sat, 18 Nov 2023 15:42:53 +0300 Subject: [PATCH 56/84] IPEX fix torch.load --- modules/intel/ipex/hijacks.py | 7 ++++--- modules/upscaler.py | 1 - 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/modules/intel/ipex/hijacks.py b/modules/intel/ipex/hijacks.py index 34342f84c..432e805de 100644 --- a/modules/intel/ipex/hijacks.py +++ b/modules/intel/ipex/hijacks.py @@ -103,9 +103,6 @@ def ipex_hijacks(): CondFunc('torch.empty', lambda orig_func, *args, device=None, **kwargs: orig_func(*args, device=return_xpu(device), **kwargs), lambda orig_func, *args, device=None, **kwargs: check_device(device)) - CondFunc('torch.load', - lambda orig_func, *args, map_location=None, **kwargs: orig_func(*args, return_xpu(map_location), **kwargs), - lambda orig_func, *args, map_location=None, **kwargs: map_location is None or check_device(map_location)) CondFunc('torch.randn', lambda orig_func, *args, device=None, **kwargs: orig_func(*args, device=return_xpu(device), **kwargs), lambda orig_func, *args, device=None, **kwargs: check_device(device)) @@ -121,6 +118,10 @@ def ipex_hijacks(): CondFunc('torch.linspace', lambda orig_func, *args, device=None, **kwargs: orig_func(*args, device=return_xpu(device), **kwargs), lambda orig_func, *args, device=None, **kwargs: check_device(device)) + CondFunc('torch.load', + lambda orig_func, f, map_location=None, pickle_module=None, *, weights_only=False, mmap=None, **kwargs: + orig_func(orig_func, f, map_location=return_xpu(map_location), pickle_module=pickle_module, weights_only=weights_only, mmap=mmap, **kwargs), + lambda orig_func, f, map_location=None, pickle_module=None, *, weights_only=False, mmap=None, **kwargs: check_device(map_location)) CondFunc('torch.Generator', lambda orig_func, device=None: torch.xpu.Generator(device), diff --git a/modules/upscaler.py b/modules/upscaler.py index d15f44ad3..fa23ddaa9 100644 --- a/modules/upscaler.py +++ b/modules/upscaler.py @@ -228,7 +228,6 @@ def compile_upscaler(model, name=""): if modules.shared.opts.cuda_compile_backend == "openvino_fx": from modules.intel.openvino import openvino_fx # pylint: disable=unused-import - from modules.sd_models_compile import CompiledModelState # pylint: disable=unused-import torch._dynamo.eval_frame.check_if_dynamo_supported = lambda: True # pylint: disable=protected-access log_level = logging.WARNING if modules.shared.opts.cuda_compile_verbose else logging.CRITICAL # pylint: disable=protected-access From 1a64b32ef99079b6ade043ef05879abd1c662c8d Mon Sep 17 00:00:00 2001 From: QuantumSoul Date: Sat, 18 Nov 2023 14:31:55 +0100 Subject: [PATCH 57/84] Update README.md --- README.md | 43 ++++++++++++++++++++----------------------- 1 file changed, 20 insertions(+), 23 deletions(-) diff --git a/README.md b/README.md index cab425bd6..2c20ac89c 100644 --- a/README.md +++ b/README.md @@ -17,15 +17,14 @@ ## Notable features All individual features are not listed here, instead check [ChangeLog](CHANGELOG.md) for full list of changes. -- Broad support - - Multiple backends! - **Original | Diffusers** - - Multiple diffusion models! - **Stable Diffusion | SD-XL | LCM | Segmind | Kandinsky | Pixart-α | Würstchen | DeepFloyd IF | UniDiffusion | SD-Distilled | etc.** - - Multiplatform with platform specific autodetection and tuning performed on install - **Windows | Linux | MacOS with CPU | nVidia | AMD | IntelArc | DirectML | OpenVINO | ONNX+Olive** -- Optimized processing with latest **torch** developments - Including built-in support for `torch.compile` +- Multiple backends! + ▹ *Original | Diffusers* +- Multiple diffusion models! + ▹ *Stable Diffusion | SD-XL | LCM | Segmind | Kandinsky | Pixart-α | Würstchen | DeepFloyd IF | UniDiffusion | SD-Distilled | etc.* +- Multiplatform! + ▹ *Windows | Linux | MacOS with CPU | nVidia | AMD | IntelArc | DirectML | OpenVINO | ONNX+Olive* +- Platform specific autodetection and tuning performed on install +- Optimized processing with latest `torch` developments with built-in support for `torch.compile` - Improved prompt parser - Enhanced *Lora*/*Locon*/*Lyco* code supporting latest trends in training - Built-in queue management @@ -65,11 +64,11 @@ Additional models will be added as they become available and there is public int - [DeepFloyd IF](https://github.com/deep-floyd/IF) Medium and Large - [Segmind SD Distilled](https://huggingface.co/blog/sd_distillation) *(all variants)* -*Notes*: -- Loading any model other than standard SD 1.x / SD 2.x requires use of backend **Diffusers** - Loading any other models using **Original** backend is not supproted -- Loading manually download model `.safetensors` files is supported for SD 1.x / SD 2.x / SD-XL models only - For all other model types, use backend **Diffusers** and use built in Model downloader or +> [!IMPORTANT] +> - Loading any model other than standard SD 1.x / SD 2.x requires use of backend **Diffusers** +> - Loading any other models using **Original** backend is not supproted +> - Loading manually download model `.safetensors` files is supported for SD 1.x / SD 2.x / SD-XL models only +> - For all other model types, use backend **Diffusers** and use built in Model downloader or select model from Networks -> Models -> Reference list in which case it will be auto-downloaded and loaded ## Platform support @@ -85,20 +84,18 @@ Additional models will be added as they become available and there is public int - *ONNX/Olive* (experimental) ## Install & Run - +## Install - [Step-by-step install guide](https://github.com/vladmandic/automatic/wiki/Installation) - [Advanced install notes](https://github.com/vladmandic/automatic/wiki/Advanced-Install) - -### Installation Notes - - [Common installation errors](https://github.com/vladmandic/automatic/discussions/1627) - [FAQ](https://github.com/vladmandic/automatic/discussions/1011) -- Server can run without virtual environment, - but it is recommended to use it to avoid library version conflicts with other applications -- **nVidia/CUDA** / **AMD/ROCm** / **Intel/OneAPI** are auto-detected if present and available, + +> [!TIP] +> - Server can run without virtual environment,but it is recommended to use it to avoid library version conflicts with other applications +> - **nVidia/CUDA** / **AMD/ROCm** / **Intel/OneAPI** are auto-detected if present and available, For any other use case such as **DirectML**, **ONNX/Olive**, **OpenVINO** specify required parameter explicitly or wrong packages may be installed as installer will assume CPU-only environment -- Full startup sequence is logged in `sdnext.log`, so if you encounter any issues, please check it first +> - Full startup sequence is logged in `sdnext.log`, so if you encounter any issues, please check it first ### Run @@ -171,7 +168,7 @@ but although it diverged considerably, any substantial features to original work The idea behind the fork is to enable latest technologies and advances in text-to-image generation. -> *Sometimes this is not the same as "as simple as possible to use".* +*Sometimes this is not the same as "as simple as possible to use".* General goals: From 606e4d5c08ff94408142bf6bf17216c7c8aa324a Mon Sep 17 00:00:00 2001 From: Vladimir Mandic Date: Sat, 18 Nov 2023 08:46:57 -0500 Subject: [PATCH 58/84] configurable hf cache --- CHANGELOG.md | 2 ++ installer.py | 2 ++ modules/processing_diffusers.py | 3 ++- modules/sd_models_compile.py | 6 +++--- modules/shared.py | 1 + modules/ui_extra_networks.py | 4 ++-- modules/upscaler.py | 4 ++-- 7 files changed, 14 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0807b2c2c..cbf05ab03 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -32,6 +32,8 @@ - Better Lora trigger words support - Auto refresh styles on change - **General** + - Configurable location for HF cache folder + Default is standard `~/.cache/huggingface/hub` - Reworked parser when pasting previously generated images/prompts includes all `txt2img`, `img2img` and `override` params - Reworked **model compile** diff --git a/installer.py b/installer.py index 5e7f4bc7c..531d111db 100644 --- a/installer.py +++ b/installer.py @@ -795,6 +795,8 @@ def set_environment(): os.environ.setdefault('TF_ENABLE_ONEDNN_OPTS', '0') os.environ.setdefault('USE_TORCH', '1') os.environ.setdefault('UVICORN_TIMEOUT_KEEP_ALIVE', '60') + os.environ.setdefault('HF_HUB_CACHE', opts.get('hfcache_dir', os.path.join(os.path.expanduser('~'), '.cache', 'huggingface', 'hub'))) + log.debug(f'Cache folder: {os.environ.get("HF_HUB_CACHE")}') if sys.platform == 'darwin': os.environ.setdefault('PYTORCH_ENABLE_MPS_FALLBACK', '1') diff --git a/modules/processing_diffusers.py b/modules/processing_diffusers.py index f491fa58b..a36fed906 100644 --- a/modules/processing_diffusers.py +++ b/modules/processing_diffusers.py @@ -155,7 +155,8 @@ def process_diffusers(p: StableDiffusionProcessing, seeds, prompts, negative_pro decoded = full_vae_decode(latents=latents, model=shared.sd_model) else: decoded = taesd_vae_decode(latents=latents) - # decoded = validate_sample(decoded) # TODO validate sample + # TODO validate decoded sample diffusers + # decoded = validate_sample(decoded) imgs = model.image_processor.postprocess(decoded, output_type=output_type) shared.state.job = prev_job return imgs diff --git a/modules/sd_models_compile.py b/modules/sd_models_compile.py index 353171435..67fc32740 100644 --- a/modules/sd_models_compile.py +++ b/modules/sd_models_compile.py @@ -126,13 +126,13 @@ def compile_torch(sd_model): def compile_diffusers(sd_model): if not (shared.opts.cuda_compile or shared.opts.cuda_compile_vae or shared.opts.cuda_compile_upscaler): - return + return sd_model if not hasattr(sd_model, 'unet') or not hasattr(sd_model.unet, 'config'): shared.log.warning('Model compile enabled but model has no Unet') - return + return sd_model if shared.opts.cuda_compile_backend == 'none': shared.log.warning('Model compile enabled but no backend specified') - return + return sd_model size = 8*getattr(sd_model.unet.config, 'sample_size', 0) shared.log.info(f"Model compile: pipeline={sd_model.__class__.__name__} shape={size} mode={shared.opts.cuda_compile_mode} backend={shared.opts.cuda_compile_backend} fullgraph={shared.opts.cuda_compile_fullgraph} unet={shared.opts.cuda_compile} vae={shared.opts.cuda_compile_vae} upscaler={shared.opts.cuda_compile_upscaler}") if shared.opts.cuda_compile_backend == 'stable-fast': diff --git a/modules/shared.py b/modules/shared.py index 0cb16deb8..259b04e34 100644 --- a/modules/shared.py +++ b/modules/shared.py @@ -377,6 +377,7 @@ options_templates.update(options_section(('system-paths', "System Paths"), { "models_dir": OptionInfo('models', "Base path where all models are stored", folder=True), "ckpt_dir": OptionInfo(os.path.join(paths.models_path, 'Stable-diffusion'), "Folder with stable diffusion models", folder=True), "diffusers_dir": OptionInfo(os.path.join(paths.models_path, 'Diffusers'), "Folder with Hugggingface models", folder=True), + "hfcache_dir": OptionInfo(os.path.join(os.path.expanduser('~'), '.cache', 'huggingface', 'hub'), "Folder for Hugggingface cache", folder=True), "vae_dir": OptionInfo(os.path.join(paths.models_path, 'VAE'), "Folder with VAE files", folder=True), "sd_lora": OptionInfo("", "Add LoRA to prompt", gr.Textbox, {"visible": False}), "lora_dir": OptionInfo(os.path.join(paths.models_path, 'Lora'), "Folder with LoRA network(s)", folder=True), diff --git a/modules/ui_extra_networks.py b/modules/ui_extra_networks.py index 3cd5cdecd..3a61f90f4 100644 --- a/modules/ui_extra_networks.py +++ b/modules/ui_extra_networks.py @@ -203,7 +203,7 @@ class ExtraNetworksPage: os.remove(f) elif img.width > 1024 or img.height > 1024 or os.path.getsize(f) > 65536: img = img.convert('RGB') - img.thumbnail((512, 512), Image.HAMMING) + img.thumbnail((512, 512), Image.Resampling.HAMMING) img.save(fn, quality=50) img.close() created += 1 @@ -576,7 +576,7 @@ def create_ui(container, button_parent, tabname, skip_indexing = False): fn_delete_img(image) if image.width > 512 or image.height > 512: image = image.convert('RGB') - image.thumbnail((512, 512), Image.HAMMING) + image.thumbnail((512, 512), Image.Resampling.HAMMING) try: image.save(ui.last_item.local_preview, quality=50) shared.log.debug(f'Extra network save image: item={ui.last_item.name} filename="{ui.last_item.local_preview}"') diff --git a/modules/upscaler.py b/modules/upscaler.py index fa23ddaa9..575dfdc12 100644 --- a/modules/upscaler.py +++ b/modules/upscaler.py @@ -7,8 +7,8 @@ import modules.shared from modules import modelloader -LANCZOS = (Image.Resampling.LANCZOS if hasattr(Image, 'Resampling') else Image.LANCZOS) -NEAREST = (Image.Resampling.NEAREST if hasattr(Image, 'Resampling') else Image.NEAREST) +LANCZOS = (Image.Resampling.LANCZOS if hasattr(Image, 'Resampling') else Image.Resampling.LANCZOS) +NEAREST = (Image.Resampling.NEAREST if hasattr(Image, 'Resampling') else Image.Resampling.NEAREST) models = None class Upscaler: From 53019de30f371cf7d95ddf37af823fc86e5f11fe Mon Sep 17 00:00:00 2001 From: Vladimir Mandic Date: Sat, 18 Nov 2023 09:22:10 -0500 Subject: [PATCH 59/84] todo cleanup --- modules/sd_models.py | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/modules/sd_models.py b/modules/sd_models.py index 6a5a40fef..ab1188c60 100644 --- a/modules/sd_models.py +++ b/modules/sd_models.py @@ -989,6 +989,26 @@ def set_diffuser_pipe(pipe, new_pipe_type): has_accelerate = getattr(pipe, "has_accelerate", None) embedding_db = getattr(pipe, "embedding_db", None) + # TODO implement alternative diffusion pipelines + """ + from collections import OrderedDict + AUTO_TEXT2IMAGE_PIPELINES_MAPPING = OrderedDict( + [ + ("stable-diffusion", diffusers.StableDiffusionPipeline), + ("stable-diffusion-xl", diffusers.StableDiffusionXLPipeline), + ("if", diffusers.IFPipeline), + ("kandinsky", diffusers.KandinskyCombinedPipeline), + ("kandinsky22", diffusers.KandinskyV22CombinedPipeline), + ("stable-diffusion-controlnet", diffusers.StableDiffusionControlNetPipeline), + ("stable-diffusion-xl-controlnet", diffusers.StableDiffusionXLControlNetPipeline), + ("wuerstchen", diffusers.WuerstchenCombinedPipeline), + ("lcm", diffusers.LatentConsistencyModelPipeline), + ("pixart", diffusers.PixArtAlphaPipeline), + ] + ) + diffusers.pipelines.auto_pipeline.AUTO_TEXT2IMAGE_PIPELINES_MAPPING = AUTO_TEXT2IMAGE_PIPELINES_MAPPING + """ + if shared.opts.diffusers_force_inpaint: if new_pipe_type == DiffusersTaskType.IMAGE_2_IMAGE: new_pipe_type = DiffusersTaskType.INPAINTING # sdxl may work better with init mask From 801b88c5804aec9e4013bd76e9d528839047fd8e Mon Sep 17 00:00:00 2001 From: Vladimir Mandic Date: Sat, 18 Nov 2023 10:31:11 -0500 Subject: [PATCH 60/84] add torch 2.1.1 --- CHANGELOG.md | 1 + README.md | 24 +++++++++++++----------- installer.py | 1 + 3 files changed, 15 insertions(+), 11 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index cbf05ab03..7c45847be 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -32,6 +32,7 @@ - Better Lora trigger words support - Auto refresh styles on change - **General** + - Support for **Torch 2.1.1** with CUDA 12.1 or CUDA 11.8 - Configurable location for HF cache folder Default is standard `~/.cache/huggingface/hub` - Reworked parser when pasting previously generated images/prompts diff --git a/README.md b/README.md index 2c20ac89c..3bc3b6074 100644 --- a/README.md +++ b/README.md @@ -16,35 +16,35 @@ ## Notable features -All individual features are not listed here, instead check [ChangeLog](CHANGELOG.md) for full list of changes. +All individual features are not listed here, instead check [ChangeLog](CHANGELOG.md) for full list of changes - Multiple backends! - ▹ *Original | Diffusers* + ▹ **Original | Diffusers** - Multiple diffusion models! - ▹ *Stable Diffusion | SD-XL | LCM | Segmind | Kandinsky | Pixart-α | Würstchen | DeepFloyd IF | UniDiffusion | SD-Distilled | etc.* + ▹ **Stable Diffusion | SD-XL | LCM | Segmind | Kandinsky | Pixart-α | Würstchen | DeepFloyd IF | UniDiffusion | SD-Distilled | etc.** - Multiplatform! - ▹ *Windows | Linux | MacOS with CPU | nVidia | AMD | IntelArc | DirectML | OpenVINO | ONNX+Olive* + ▹ **Windows | Linux | MacOS with CPU | nVidia | AMD | IntelArc | DirectML | OpenVINO | ONNX+Olive** - Platform specific autodetection and tuning performed on install -- Optimized processing with latest `torch` developments with built-in support for `torch.compile` +- Optimized processing with latest `torch` developments with built-in support for `torch.compile` and multiple compile backends - Improved prompt parser -- Enhanced *Lora*/*Locon*/*Lyco* code supporting latest trends in training +- Enhanced *Lora*/*LoCon*/*Lyco* code supporting latest trends in training - Built-in queue management - Advanced metadata caching and handling to speed up operations - Enterprise level logging and hardened API - Modern localization and hints engine - Broad compatibility with existing extensions ecosystem and new extensions manager - Built in installer with automatic updates and dependency management -- Modernized UI with theme support and number of built-in themes +- Modernized UI with theme support and number of built-in themes *(dark and light)*
![screenshot](html/black-teal.jpg)
## Backend support -**SD.Next** supports two main backends: *Original* and *Diffusers* which can be switched on-the-fly: +**SD.Next** supports two main backends: *Original* and *Diffusers*: - **Original**: Based on [LDM](https://github.com/Stability-AI/stablediffusion) reference implementation and significantly expanded on by [A1111](https://github.com/AUTOMATIC1111/stable-diffusion-webui) This is the default backend and it is fully compatible with all existing functionality and extensions It supports **SD 1.x** and **SD 2.x** models - All other model types such as SD-XL, LCM, PixArt, Segmind, Kandinsky, etc. require backend **Diffusers** + All other model types such as *SD-XL, LCM, PixArt, Segmind, Kandinsky, etc.* require backend **Diffusers** - **Diffusers**: Based on new [Huggingface Diffusers](https://huggingface.co/docs/diffusers/index) implementation It supports *original* SD models as well as *all* models listed below See [wiki article](https://github.com/vladmandic/automatic/wiki/Diffusers) for more information @@ -91,11 +91,13 @@ Additional models will be added as they become available and there is public int - [FAQ](https://github.com/vladmandic/automatic/discussions/1011) > [!TIP] -> - Server can run without virtual environment,but it is recommended to use it to avoid library version conflicts with other applications +> - Server can run without virtual environment, + Recommended to use `VENV` to avoid library version conflicts with other applications > - **nVidia/CUDA** / **AMD/ROCm** / **Intel/OneAPI** are auto-detected if present and available, For any other use case such as **DirectML**, **ONNX/Olive**, **OpenVINO** specify required parameter explicitly or wrong packages may be installed as installer will assume CPU-only environment -> - Full startup sequence is logged in `sdnext.log`, so if you encounter any issues, please check it first +> - Full startup sequence is logged in `sdnext.log`, + so if you encounter any issues, please check it first ### Run diff --git a/installer.py b/installer.py index 531d111db..7fe48a4ef 100644 --- a/installer.py +++ b/installer.py @@ -782,6 +782,7 @@ def set_environment(): os.environ.setdefault('CUDA_DEVICE_DEFAULT_PERSISTING_L2_CACHE_PERCENTAGE_LIMIT', '0') os.environ.setdefault('CUDA_LAUNCH_BLOCKING', '0') os.environ.setdefault('CUDA_MODULE_LOADING', 'LAZY') + os.environ.setdefault('TORCH_CUDNN_V8_API_ENABLED', '1') os.environ.setdefault('FORCE_CUDA', '1') os.environ.setdefault('GRADIO_ANALYTICS_ENABLED', 'False') os.environ.setdefault('HF_HUB_DISABLE_EXPERIMENTAL_WARNING', '1') From f4e2aa5c9210c15a66056cf75f8464768456d56c Mon Sep 17 00:00:00 2001 From: Vladimir Mandic Date: Sat, 18 Nov 2023 10:34:48 -0500 Subject: [PATCH 61/84] update readme --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 3bc3b6074..54fd1bf04 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ **Stable Diffusion implementation with advanced features** -[![](https://img.shields.io/static/v1?label=Sponsor&message=%E2%9D%A4&logo=GitHub&color=%23fe8e86)](https://github.com/sponsors/vladmandic) +[![Sponsors](https://img.shields.io/static/v1?label=Sponsor&message=%E2%9D%A4&logo=GitHub&color=%23fe8e86)](https://github.com/sponsors/vladmandic) ![Last Commit](https://img.shields.io/github/last-commit/vladmandic/automatic?svg=true) ![License](https://img.shields.io/github/license/vladmandic/automatic?svg=true) [![Discord](https://img.shields.io/discord/1101998836328697867?logo=Discord&svg=true)](https://discord.gg/VjvR2tabEX) @@ -83,8 +83,8 @@ Additional models will be added as they become available and there is public int - *Apple M1/M2* on *OSX* using built-in support in Torch with **MPS** optimizations - *ONNX/Olive* (experimental) -## Install & Run ## Install + - [Step-by-step install guide](https://github.com/vladmandic/automatic/wiki/Installation) - [Advanced install notes](https://github.com/vladmandic/automatic/wiki/Advanced-Install) - [Common installation errors](https://github.com/vladmandic/automatic/discussions/1627) From b647fb84e95f3692eb4d0ead40795ad2e5e2660a Mon Sep 17 00:00:00 2001 From: Vladimir Mandic Date: Sat, 18 Nov 2023 11:20:31 -0500 Subject: [PATCH 62/84] fix non-sd pipeline --- README.md | 5 ++++- .../Lora/extra_networks_lora.py | 2 +- html/light-teal.jpg | Bin 123350 -> 260783 bytes modules/theme.py | 2 +- modules/ui_extra_networks.py | 6 ++++-- 5 files changed, 10 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 54fd1bf04..5a2a3ebfe 100644 --- a/README.md +++ b/README.md @@ -35,7 +35,10 @@ All individual features are not listed here, instead check [ChangeLog](CHANGELOG - Built in installer with automatic updates and dependency management - Modernized UI with theme support and number of built-in themes *(dark and light)* -
![screenshot](html/black-teal.jpg)
+
+![Screenshot-Dark](html/black-teal.jpg) +![Screenshot-Light](html/light-teal.jpg) +
## Backend support diff --git a/extensions-builtin/Lora/extra_networks_lora.py b/extensions-builtin/Lora/extra_networks_lora.py index 40ac8b909..82aa82454 100644 --- a/extensions-builtin/Lora/extra_networks_lora.py +++ b/extensions-builtin/Lora/extra_networks_lora.py @@ -64,7 +64,7 @@ class ExtraNetworkLora(extra_networks.ExtraNetwork): self.active = False def deactivate(self, p): - if shared.backend == shared.Backend.DIFFUSERS: + if shared.backend == shared.Backend.DIFFUSERS and hasattr(shared.sd_model, "unload_lora_weights"): shared.sd_model.unload_lora_weights() if not self.active and getattr(networks, "originals", None ) is not None: networks.originals.undo() # remove patches diff --git a/html/light-teal.jpg b/html/light-teal.jpg index 2b6292c6e01ddaa246ab89752b0b1e36d25588a2..f09546a02d2d654950c2f8bb0542c7e6e5832eb8 100644 GIT binary patch literal 260783 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�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
#7$$w+9pwEQmZ60fs0iGnOC-`c)V%v_HP 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 literal 123350 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 OFOR?fyC0+enfV|0W8EeI diff --git a/modules/theme.py b/modules/theme.py index 1b29ef630..83a14c902 100644 --- a/modules/theme.py +++ b/modules/theme.py @@ -64,7 +64,7 @@ def reload_gradio_theme(theme_name=None): 'font_mono':['IBM Plex Mono', 'ui-monospace', 'Consolas', 'monospace'] } is_builtin = theme_name in list_builtin_themes() - modules.shared.log.info(f'Load UI theme: name="{theme_name}" style={modules.shared.opts.theme_style} base={"style.css" if is_builtin else "base.css"}') + modules.shared.log.info(f'Load UI theme: name="{theme_name}" style={modules.shared.opts.theme_style} base={"sdnext.css" if is_builtin else "base.css"}') if is_builtin: gradio_theme = gr.themes.Base(**default_font_params) elif theme_name.startswith("gradio/"): diff --git a/modules/ui_extra_networks.py b/modules/ui_extra_networks.py index 3a61f90f4..5fa0e1aa6 100644 --- a/modules/ui_extra_networks.py +++ b/modules/ui_extra_networks.py @@ -253,8 +253,10 @@ class ExtraNetworksPage: subdir = tgt[len(parentdir):].replace("\\", "/") while subdir.startswith("/"): subdir = subdir[1:] - if not self.is_empty(tgt): + # if not self.is_empty(tgt): + if not subdir.startswith("."): subdirs[subdir] = 1 + debug(f"Extra networks: page='{self.name}' subfolders={list(subdirs)}") subdirs = OrderedDict(sorted(subdirs.items())) if shared.backend == shared.Backend.DIFFUSERS and self.name == 'model': subdirs['Reference'] = 1 @@ -279,7 +281,7 @@ class ExtraNetworksPage: self.html = f"
{subdirs_html}
{self.html}
" else: return '' - shared.log.debug(f"Extra networks: page='{self.name}' items={len(self.items)} subdirs={len(subdirs)} tab={tabname} dirs={self.allowed_directories_for_previews()} list={self.list_time:.2f} desc={self.desc_time:.2f} info={self.info_time:.2f}") + shared.log.debug(f"Extra networks: page='{self.name}' items={len(self.items)} subfolders={len(subdirs)} tab={tabname} folders={self.allowed_directories_for_previews()} list={self.list_time:.2f} desc={self.desc_time:.2f} info={self.info_time:.2f}") if len(self.missing_thumbs) > 0: threading.Thread(target=self.create_thumb).start() return self.html From 93bde61f724029d8ce9584bc06c28e6a750fcd30 Mon Sep 17 00:00:00 2001 From: Vladimir Mandic Date: Sat, 18 Nov 2023 11:23:26 -0500 Subject: [PATCH 63/84] update screenshots --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 5a2a3ebfe..72f8032e4 100644 --- a/README.md +++ b/README.md @@ -36,8 +36,10 @@ All individual features are not listed here, instead check [ChangeLog](CHANGELOG - Modernized UI with theme support and number of built-in themes *(dark and light)*
+ ![Screenshot-Dark](html/black-teal.jpg) ![Screenshot-Light](html/light-teal.jpg) +
## Backend support From cea7464553461faf3364574082db22e8464b89b9 Mon Sep 17 00:00:00 2001 From: AI-Casanova <54461896+AI-Casanova@users.noreply.github.com> Date: Sat, 18 Nov 2023 10:45:54 -0600 Subject: [PATCH 64/84] Use Internal read_state_dict --- modules/merging/merge.py | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/modules/merging/merge.py b/modules/merging/merge.py index 2330d50d5..92446b2a8 100644 --- a/modules/merging/merge.py +++ b/modules/merging/merge.py @@ -1,7 +1,7 @@ import os from concurrent.futures import ThreadPoolExecutor from contextlib import contextmanager -from pathlib import Path +# from pathlib import Path from typing import Dict, Optional, Tuple import safetensors.torch @@ -11,9 +11,10 @@ from tqdm import tqdm import modules.memstats import modules.devices as devices from modules.shared import log +from modules.sd_models import read_state_dict from modules.merging import merge_methods from modules.merging.merge_utils import WeightClass -from modules.merging.merge_model import SDModel +# from modules.merging.merge_model import SDModel from modules.merging.merge_rebasin import ( apply_permutation, sdunet_permutation_spec, @@ -69,11 +70,11 @@ def fix_model(model: Dict) -> Dict: return fix_clip(model) -def load_sd_model(model: os.PathLike | str, device: torch.device = None) -> Dict: - if isinstance(model, str): - model = Path(model) - - return SDModel(model, device).load_model() +# def load_sd_model(model: os.PathLike | str, device: torch.device = None) -> Dict: +# if isinstance(model, str): +# model = Path(model) +# +# return SDModel(model, device).load_model() def prune_sd_model(model: Dict) -> Dict: @@ -107,9 +108,9 @@ def load_thetas( ) -> Dict: log_vram("before loading models") if prune: - thetas = {k: prune_sd_model(load_sd_model(m, "cpu")) for k, m in models.items()} + thetas = {k: prune_sd_model(read_state_dict(m, "cpu")) for k, m in models.items()} else: - thetas = {k: load_sd_model(m, device) for k, m in models.items()} + thetas = {k: read_state_dict(m, device) for k, m in models.items()} for model_key, model in thetas.items(): for key, block in model.items(): @@ -170,7 +171,7 @@ def un_prune_model( merged: Dict, thetas: Dict, models: Dict, - device: str, + device: torch.device, prune: bool, precision: str, ) -> Dict: @@ -179,7 +180,7 @@ def un_prune_model( del thetas devices.torch_gc(force=True) log_vram("remove thetas") - original_a = load_sd_model(models["model_a"], device) + original_a = read_state_dict(models["model_a"], device) for key in tqdm(original_a.keys(), desc="un-prune model a"): if KEY_POSITION_IDS in key: continue @@ -190,7 +191,7 @@ def un_prune_model( del original_a devices.torch_gc(force=True) # log_vram("remove original_a") - original_b = load_sd_model(models["model_b"], device) + original_b = read_state_dict(models["model_b"], device) for key in tqdm(original_b.keys(), desc="un-prune model b"): if KEY_POSITION_IDS in key: continue From d2d54af7aca1d4868b98ada8f2d516f0359f2432 Mon Sep 17 00:00:00 2001 From: AI-Casanova <54461896+AI-Casanova@users.noreply.github.com> Date: Sat, 18 Nov 2023 11:04:43 -0600 Subject: [PATCH 65/84] Cleanup and Credits --- modules/merging/merge.py | 42 +++++--------------------- modules/merging/merge_model.py | 54 ---------------------------------- modules/merging/merge_utils.py | 1 - 3 files changed, 7 insertions(+), 90 deletions(-) delete mode 100644 modules/merging/merge_model.py diff --git a/modules/merging/merge.py b/modules/merging/merge.py index 92446b2a8..a057ed015 100644 --- a/modules/merging/merge.py +++ b/modules/merging/merge.py @@ -1,26 +1,27 @@ import os from concurrent.futures import ThreadPoolExecutor from contextlib import contextmanager -# from pathlib import Path from typing import Dict, Optional, Tuple - import safetensors.torch import torch from tqdm import tqdm - import modules.memstats import modules.devices as devices from modules.shared import log from modules.sd_models import read_state_dict from modules.merging import merge_methods from modules.merging.merge_utils import WeightClass -# from modules.merging.merge_model import SDModel from modules.merging.merge_rebasin import ( apply_permutation, sdunet_permutation_spec, update_model_a, weight_matching, ) +########################################################## +# Files in modules.merging are heavily modified +# versions of sd-meh by @s1dxl used with his blessing +# orginal code can be found @ https://github.com/s1dlx/meh +########################################################## MAX_TOKENS = 77 @@ -36,12 +37,6 @@ KEY_POSITION_IDS = ".".join( ) -NAI_KEYS = { - "cond_stage_model.transformer.embeddings.": "cond_stage_model.transformer.text_model.embeddings.", - "cond_stage_model.transformer.encoder.": "cond_stage_model.transformer.text_model.encoder.", - "cond_stage_model.transformer.final_layer_norm.": "cond_stage_model.transformer.text_model.final_layer_norm.", -} - def fix_clip(model: Dict) -> Dict: if KEY_POSITION_IDS in model.keys(): @@ -54,29 +49,6 @@ def fix_clip(model: Dict) -> Dict: return model -def fix_key(model: Dict, key: str) -> Dict: - for nk in NAI_KEYS: - if key.startswith(nk): - model[key.replace(nk, NAI_KEYS[nk])] = model[key] - del model[key] - - return model - - -# https://github.com/j4ded/sdweb-merge-block-weighted-gui/blob/master/scripts/mbw/merge_block_weighted.py#L115 -def fix_model(model: Dict) -> Dict: - for k in model.keys(): - model = fix_key(model, k) - return fix_clip(model) - - -# def load_sd_model(model: os.PathLike | str, device: torch.device = None) -> Dict: -# if isinstance(model, str): -# model = Path(model) -# -# return SDModel(model, device).load_model() - - def prune_sd_model(model: Dict) -> Dict: keys = list(model.keys()) for k in keys: @@ -201,7 +173,7 @@ def un_prune_model( merged.update({key: merged[key].half()}) del original_b - return fix_model(merged) + return fix_clip(merged) def simple_merge( @@ -247,7 +219,7 @@ def simple_merge( log_vram("after stage 2") - return fix_model(thetas["model_a"]) + return fix_clip(thetas["model_a"]) def rebasin_merge( diff --git a/modules/merging/merge_model.py b/modules/merging/merge_model.py deleted file mode 100644 index 37427c44b..000000000 --- a/modules/merging/merge_model.py +++ /dev/null @@ -1,54 +0,0 @@ -import os -from dataclasses import dataclass - -import safetensors -import torch -from tensordict import TensorDict - - - -@dataclass -class SDModel: - model_path: os.PathLike - device: torch.device - - def load_model(self): - # logging.info(f"Loading: {self.model_path}") - if os.path.splitext(self.model_path)[1] == ".safetensors": - ckpt = safetensors.torch.load_file( - self.model_path, - device=self.device, - ) - else: - ckpt = torch.load(self.model_path, map_location=self.device) - - return TensorDict.from_dict(get_state_dict_from_checkpoint(ckpt)) - - -# TODO: tidy up -# from: stable-diffusion-webui/modules/sd_models.py -def get_state_dict_from_checkpoint(pl_sd): - pl_sd = pl_sd.pop("state_dict", pl_sd) - pl_sd.pop("state_dict", None) - sd = {} - for k, v in pl_sd.items(): - if new_key := transform_checkpoint_dict_key(k): - sd[new_key] = v - - pl_sd.clear() - pl_sd.update(sd) - return pl_sd - - -chckpoint_dict_replacements = { - "cond_stage_model.transformer.embeddings.": "cond_stage_model.transformer.text_model.embeddings.", - "cond_stage_model.transformer.encoder.": "cond_stage_model.transformer.text_model.encoder.", - "cond_stage_model.transformer.final_layer_norm.": "cond_stage_model.transformer.text_model.final_layer_norm.", -} - - -def transform_checkpoint_dict_key(k): - for text, replacement in chckpoint_dict_replacements.items(): - if k.startswith(text): - k = replacement + k[len(text):] - return k diff --git a/modules/merging/merge_utils.py b/modules/merging/merge_utils.py index 41b6f7442..da0059967 100644 --- a/modules/merging/merge_utils.py +++ b/modules/merging/merge_utils.py @@ -1,5 +1,4 @@ import inspect -# import logging import re from modules.merging import merge_methods from modules.merging.merge_presets import BLOCK_WEIGHTS_PRESETS, SDXL_BLOCK_WEIGHTS_PRESETS From 026790fe4c746b13ca2b0f41298f54f873abec12 Mon Sep 17 00:00:00 2001 From: AI-Casanova <54461896+AI-Casanova@users.noreply.github.com> Date: Sat, 18 Nov 2023 11:14:15 -0600 Subject: [PATCH 66/84] Cleanup and optimization --- modules/extras.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/modules/extras.py b/modules/extras.py index 6f990cac8..672db16e4 100644 --- a/modules/extras.py +++ b/modules/extras.py @@ -286,7 +286,8 @@ def run_MEHmodelmerger(id_task, **kwargs): # pylint: disable=unused-argument assert len(alpha) == 26 or len( alpha) == 20, "Alpha Block Weights are wrong length (26 or 20 for SDXL) falling back" kwargs["alpha"] = alpha - except: + except AssertionError as e: + shared.log.info(e) kwargs["alpha"] = kwargs.get("alpha_preset", kwargs["alpha"]) finally: kwargs.pop("alpha_base", None) @@ -303,7 +304,8 @@ def run_MEHmodelmerger(id_task, **kwargs): # pylint: disable=unused-argument assert len(beta) == 26 or len( beta) == 20, "Beta Block Weights are wrong length (26 or 20 for SDXL) falling back" kwargs["beta"] = beta - except: + except AssertionError as e: + shared.log.info(e) kwargs["beta"] = kwargs.get("beta_preset", kwargs["beta"]) finally: kwargs.pop("beta_base", None) @@ -313,7 +315,7 @@ def run_MEHmodelmerger(id_task, **kwargs): # pylint: disable=unused-argument kwargs.pop("beta_preset", None) if kwargs["device"] == "cuda": - kwargs["device"] == devices.device + kwargs["device"] = devices.device sd_models.unload_model_weights() elif kwargs["device"] == "shuffle": kwargs["device"] = torch.device("cpu") @@ -321,7 +323,6 @@ def run_MEHmodelmerger(id_task, **kwargs): # pylint: disable=unused-argument else: kwargs["device"] = torch.device("cpu") - try: theta_0 = merge_models(**kwargs) except Exception as e: @@ -390,6 +391,7 @@ def run_MEHmodelmerger(id_task, **kwargs): # pylint: disable=unused-argument created_model = next((ckpt for ckpt in sd_models.checkpoints_list.values() if ckpt.name == filename), None) if created_model: created_model.calculate_shorthash() + devices.torch_gc(force=True) shared.log.info(f"Model merge saved: {output_modelname}.") shared.state.textinfo = "Checkpoint saved" shared.state.end() From d9d3c2e7fce159514be487c2c2e370afa2d3309a Mon Sep 17 00:00:00 2001 From: AI-Casanova <54461896+AI-Casanova@users.noreply.github.com> Date: Sat, 18 Nov 2023 11:33:20 -0600 Subject: [PATCH 67/84] Replace Original Merge Method Major Cleanup --- modules/extras.py | 204 +-------------------------------------- modules/merging/merge.py | 11 +-- modules/ui_models.py | 155 +++++++---------------------- 3 files changed, 46 insertions(+), 324 deletions(-) diff --git a/modules/extras.py b/modules/extras.py index 672db16e4..2b2852844 100644 --- a/modules/extras.py +++ b/modules/extras.py @@ -1,5 +1,4 @@ import os -import re import html import json import shutil @@ -13,8 +12,6 @@ from modules.merging.merge_utils import TRIPLE_METHODS from modules import shared, images, sd_models, sd_vae, sd_models_config, devices -checkpoint_dict_skip_on_merge = ["cond_stage_model.transformer.text_model.embeddings.position_ids"] - def run_pnginfo(image): if image is None: @@ -55,202 +52,7 @@ def to_half(tensor, enable): return tensor -def run_modelmerger(id_task, primary_model_name, secondary_model_name, tertiary_model_name, interp_method, multiplier, - save_as_half, custom_name, checkpoint_format, config_source, bake_in_vae, discard_weights, - save_metadata): # pylint: disable=unused-argument - shared.state.begin('merge') - save_as_half = save_as_half == 0 - - def fail(message): - shared.state.textinfo = message - shared.state.end() - return [*[gr.update() for _ in range(4)], message] - - def weighted_sum(theta0, theta1, alpha): - return ((1 - alpha) * theta0) + (alpha * theta1) - - def get_difference(theta1, theta2): - return theta1 - theta2 - - def add_difference(theta0, theta1_2_diff, alpha): - return theta0 + (alpha * theta1_2_diff) - - def filename_weighted_sum(): - a = primary_model_info.model_name - b = secondary_model_info.model_name - Ma = round(1 - multiplier, 2) - Mb = round(multiplier, 2) - return f"{Ma}({a}) + {Mb}({b})" - - def filename_add_difference(): - a = primary_model_info.model_name - b = secondary_model_info.model_name - c = tertiary_model_info.model_name - M = round(multiplier, 2) - return f"{a} + {M}({b} - {c})" - - def filename_nothing(): - return primary_model_info.model_name - - theta_funcs = { - "Weighted sum": (filename_weighted_sum, None, weighted_sum), - "Add difference": (filename_add_difference, get_difference, add_difference), - "No interpolation": (filename_nothing, None, None), - } - filename_generator, theta_func1, theta_func2 = theta_funcs[interp_method] - shared.state.job_count = (1 if theta_func1 else 0) + (1 if theta_func2 else 0) - if not primary_model_name or primary_model_name == 'None': - return fail("Failed: Merging requires a primary model.") - primary_model_info = sd_models.checkpoints_list[primary_model_name] - if theta_func2 and (not secondary_model_name or secondary_model_name == 'None'): - return fail("Failed: Merging requires a secondary model.") - secondary_model_info = sd_models.checkpoints_list[secondary_model_name] if theta_func2 else None - if theta_func1 and (not tertiary_model_name or tertiary_model_name == 'None'): - return fail(f"Failed: Interpolation method ({interp_method}) requires a tertiary model.") - tertiary_model_info = sd_models.checkpoints_list[tertiary_model_name] if theta_func1 else None - result_is_inpainting_model = False - result_is_instruct_pix2pix_model = False - if theta_func2: - shared.state.textinfo = "Loading B" - shared.log.info(f"Model merge loading secondary model: {secondary_model_info.filename}") - theta_1 = sd_models.read_state_dict(secondary_model_info.filename) - else: - theta_1 = None - if theta_func1: - shared.state.textinfo = "Loading C" - shared.log.info(f"Model merge loading tertiary model: {tertiary_model_info.filename}") - theta_2 = sd_models.read_state_dict(tertiary_model_info.filename) - shared.state.textinfo = 'Merging B and C' - shared.state.sampling_steps = len(theta_1.keys()) - for key in tqdm.tqdm(theta_1.keys()): - if key in checkpoint_dict_skip_on_merge: - continue - if 'model' in key: - if key in theta_2: - t2 = theta_2.get(key, torch.zeros_like(theta_1[key])) - theta_1[key] = theta_func1(theta_1[key], t2) - else: - theta_1[key] = torch.zeros_like(theta_1[key]) - shared.state.sampling_step += 1 - del theta_2 - shared.state.nextjob() - shared.state.textinfo = f"Loading {primary_model_info.filename}..." - shared.log.info(f"Model merge loading primary model: {primary_model_info.filename}") - theta_0 = sd_models.read_state_dict(primary_model_info.filename) - shared.log.info("Model merge: running") - shared.state.textinfo = 'Merging A and B' - shared.state.sampling_steps = len(theta_0.keys()) - for key in tqdm.tqdm(theta_0.keys()): - if theta_1 and 'model' in key and key in theta_1: - if key in checkpoint_dict_skip_on_merge: - continue - a = theta_0[key] - b = theta_1[key] - # this enables merging an inpainting model (A) with another one (B); - # where normal model would have 4 channels, for latenst space, inpainting model would - # have another 4 channels for unmasked picture's latent space, plus one channel for mask, for a total of 9 - if a.shape != b.shape and a.shape[0:1] + a.shape[2:] == b.shape[0:1] + b.shape[2:]: - if a.shape[1] == 4 and b.shape[1] == 9: - raise RuntimeError( - "When merging inpainting model with a normal one, A must be the inpainting model.") - if a.shape[1] == 4 and b.shape[1] == 8: - raise RuntimeError( - "When merging instruct-pix2pix model with a normal one, A must be the instruct-pix2pix model.") - if a.shape[1] == 8 and b.shape[1] == 4: # If we have an Instruct-Pix2Pix model... - theta_0[key][:, 0:4, :, :] = theta_func2(a[:, 0:4, :, :], b, - multiplier) # Merge only the vectors the models have in common. Otherwise we get an error due to dimension mismatch. - result_is_instruct_pix2pix_model = True - else: - assert a.shape[1] == 9 and b.shape[ - 1] == 4, f"Bad dimensions for merged layer {key}: A={a.shape}, B={b.shape}" - theta_0[key][:, 0:4, :, :] = theta_func2(a[:, 0:4, :, :], b, multiplier) - result_is_inpainting_model = True - else: - theta_0[key] = theta_func2(a, b, multiplier) - theta_0[key] = to_half(theta_0[key], save_as_half) - shared.state.sampling_step += 1 - del theta_1 - bake_in_vae_filename = sd_vae.vae_dict.get(bake_in_vae, None) - if bake_in_vae_filename is not None: - shared.log.info(f"Model merge: baking in VAE: {bake_in_vae_filename}") - shared.state.textinfo = 'Baking in VAE' - vae_dict = sd_vae.load_vae_dict(bake_in_vae_filename) - for key in vae_dict.keys(): - theta_0_key = 'first_stage_model.' + key - if theta_0_key in theta_0: - theta_0[theta_0_key] = to_half(vae_dict[key], save_as_half) - del vae_dict - if save_as_half and not theta_func2: - for key in theta_0.keys(): - theta_0[key] = to_half(theta_0[key], save_as_half) - if discard_weights: - regex = re.compile(discard_weights) - for key in list(theta_0): - if re.search(regex, key): - theta_0.pop(key, None) - ckpt_dir = shared.opts.ckpt_dir or sd_models.model_path - filename = filename_generator() if custom_name == '' else custom_name - filename += ".inpainting" if result_is_inpainting_model else "" - filename += ".instruct-pix2pix" if result_is_instruct_pix2pix_model else "" - filename += "." + checkpoint_format - output_modelname = os.path.join(ckpt_dir, filename) - shared.state.nextjob() - shared.state.textinfo = "Saving" - metadata = None - if save_metadata: - metadata = {"format": "pt", "sd_merge_models": {}} - merge_recipe = { - "type": "webui", # indicate this model was merged with webui's built-in merger - "primary_model_hash": primary_model_info.sha256, - "secondary_model_hash": secondary_model_info.sha256 if secondary_model_info else None, - "tertiary_model_hash": tertiary_model_info.sha256 if tertiary_model_info else None, - "interp_method": interp_method, - "multiplier": multiplier, - "save_as_half": save_as_half, - "custom_name": custom_name, - "config_source": config_source, - "bake_in_vae": bake_in_vae, - "discard_weights": discard_weights, - "is_inpainting": result_is_inpainting_model, - "is_instruct_pix2pix": result_is_instruct_pix2pix_model - } - metadata["sd_merge_recipe"] = json.dumps(merge_recipe) - - def add_model_metadata(checkpoint_info): - checkpoint_info.calculate_shorthash() - metadata["sd_merge_models"][checkpoint_info.sha256] = { - "name": checkpoint_info.name, - "legacy_hash": checkpoint_info.hash, - "sd_merge_recipe": checkpoint_info.metadata.get("sd_merge_recipe", None) - } - metadata["sd_merge_models"].update(checkpoint_info.metadata.get("sd_merge_models", {})) - - add_model_metadata(primary_model_info) - if secondary_model_info: - add_model_metadata(secondary_model_info) - if tertiary_model_info: - add_model_metadata(tertiary_model_info) - metadata["sd_merge_models"] = json.dumps(metadata["sd_merge_models"]) - - _, extension = os.path.splitext(output_modelname) - theta_0 = theta_0.to_dict() - if extension.lower() == ".safetensors": - safetensors.torch.save_file(theta_0, output_modelname, metadata=metadata) - else: - torch.save(theta_0, output_modelname) - sd_models.list_models() - created_model = next((ckpt for ckpt in sd_models.checkpoints_list.values() if ckpt.name == filename), None) - if created_model: - created_model.calculate_shorthash() - create_config(output_modelname, config_source, primary_model_info, secondary_model_info, tertiary_model_info) - shared.log.info(f"Model merge saved: {output_modelname}.") - shared.state.textinfo = "Checkpoint saved" - shared.state.end() - return [*[gr.Dropdown.update(choices=sd_models.checkpoint_tiles()) for _ in range(4)], - "Checkpoint saved to " + output_modelname] - - -def run_MEHmodelmerger(id_task, **kwargs): # pylint: disable=unused-argument +def run_modelmerger(id_task, **kwargs): # pylint: disable=unused-argument shared.state.begin('merge') def fail(message): @@ -377,6 +179,7 @@ def run_MEHmodelmerger(id_task, **kwargs): # pylint: disable=unused-argument metadata["sd_merge_models"] = json.dumps(metadata["sd_merge_models"]) _, extension = os.path.splitext(output_modelname) + try: theta_0 = theta_0.to_dict() except: @@ -391,7 +194,8 @@ def run_MEHmodelmerger(id_task, **kwargs): # pylint: disable=unused-argument created_model = next((ckpt for ckpt in sd_models.checkpoints_list.values() if ckpt.name == filename), None) if created_model: created_model.calculate_shorthash() - devices.torch_gc(force=True) + if kwargs["device"].type != "cpu": + devices.torch_gc(force=True) shared.log.info(f"Model merge saved: {output_modelname}.") shared.state.textinfo = "Checkpoint saved" shared.state.end() diff --git a/modules/merging/merge.py b/modules/merging/merge.py index a057ed015..f0cb89ce5 100644 --- a/modules/merging/merge.py +++ b/modules/merging/merge.py @@ -4,6 +4,7 @@ from contextlib import contextmanager from typing import Dict, Optional, Tuple import safetensors.torch import torch +from tensordict import TensorDict from tqdm import tqdm import modules.memstats import modules.devices as devices @@ -37,7 +38,6 @@ KEY_POSITION_IDS = ".".join( ) - def fix_clip(model: Dict) -> Dict: if KEY_POSITION_IDS in model.keys(): model[KEY_POSITION_IDS] = torch.tensor( @@ -80,9 +80,9 @@ def load_thetas( ) -> Dict: log_vram("before loading models") if prune: - thetas = {k: prune_sd_model(read_state_dict(m, "cpu")) for k, m in models.items()} + thetas = {k: prune_sd_model(TensorDict.from_dict(read_state_dict(m, "cpu"))) for k, m in models.items()} else: - thetas = {k: read_state_dict(m, device) for k, m in models.items()} + thetas = {k: TensorDict.from_dict(read_state_dict(m, device)) for k, m in models.items()} for model_key, model in thetas.items(): for key, block in model.items(): @@ -152,7 +152,7 @@ def un_prune_model( del thetas devices.torch_gc(force=True) log_vram("remove thetas") - original_a = read_state_dict(models["model_a"], device) + original_a = TensorDict.from_dict(read_state_dict(models["model_a"], device)) for key in tqdm(original_a.keys(), desc="un-prune model a"): if KEY_POSITION_IDS in key: continue @@ -162,8 +162,7 @@ def un_prune_model( merged.update({key: merged[key].half()}) del original_a devices.torch_gc(force=True) - # log_vram("remove original_a") - original_b = read_state_dict(models["model_b"], device) + original_b = TensorDict.from_dict(read_state_dict(models["model_b"], device)) for key in tqdm(original_b.keys(), desc="un-prune model b"): if KEY_POSITION_IDS in key: continue diff --git a/modules/ui_models.py b/modules/ui_models.py index e2c13a287..509e828a6 100644 --- a/modules/ui_models.py +++ b/modules/ui_models.py @@ -4,7 +4,7 @@ import inspect from datetime import datetime import gradio as gr from modules import sd_models, sd_vae, extras -from modules.ui_components import FormRow, ToolButton, InputAccordion +from modules.ui_components import FormRow, ToolButton from modules.ui_common import create_refresh_button from modules.call_queue import wrap_gradio_gpu_call from modules.shared import opts, log, req @@ -75,88 +75,6 @@ def create_ui(): ) with gr.Tab(label="Merge"): - with gr.Row(equal_height=False): - with gr.Column(variant='compact'): - with FormRow(): - custom_name = gr.Textbox(label="New model name") - with FormRow(): - def sd_model_choices(): - return ['None'] + sd_models.checkpoint_tiles() - - primary_model_name = gr.Dropdown(sd_model_choices(), label="Primary model", value="None") - create_refresh_button(primary_model_name, sd_models.list_models, - lambda: {"choices": sd_model_choices()}, "refresh_checkpoint_A") - secondary_model_name = gr.Dropdown(sd_model_choices(), label="Secondary model", - value="None") - create_refresh_button(secondary_model_name, sd_models.list_models, - lambda: {"choices": sd_model_choices()}, "refresh_checkpoint_B") - tertiary_model_name = gr.Dropdown(sd_model_choices(), label="Tertiary model", value="None") - create_refresh_button(tertiary_model_name, sd_models.list_models, - lambda: {"choices": sd_model_choices()}, "refresh_checkpoint_C") - with FormRow(): - interp_method = gr.Radio(choices=["No interpolation", "Weighted sum", "Add difference"], - value="Weighted sum", label="Interpolation Method") - interp_amount = gr.Slider(minimum=0.0, maximum=1.0, step=0.05, - label='Interpolation ratio from Primary to Secondary', value=0.5) - with FormRow(): - checkpoint_format = gr.Radio(choices=["ckpt", "safetensors"], value="safetensors", - label="Model format") - with gr.Box(): - save_as_half = gr.Radio(choices=["fp16", "fp32"], value="fp16", label="Model precision", - type="index") - with FormRow(): - config_source = gr.Radio(choices=["Primary", "Secondary", "Tertiary", "None"], - value="Primary", label="Model configuration", type="index") - with FormRow(): - bake_in_vae = gr.Dropdown(choices=["None"] + list(sd_vae.vae_dict), value="None", - label="Bake in VAE") - create_refresh_button(bake_in_vae, sd_vae.refresh_vae_list, - lambda: {"choices": ["None"] + list(sd_vae.vae_dict)}, - "modelmerger_refresh_bake_in_vae") - with FormRow(): - discard_weights = gr.Textbox(value="", label="Discard weights with matching name") - with FormRow(): - save_metadata = gr.Checkbox(value=True, label="Save metadata") - with gr.Row(): - modelmerger_merge = gr.Button(value="Merge", variant='primary') - - def modelmerger(*args): - try: - results = extras.run_modelmerger(*args) - except Exception as e: - modules.errors.display(e, 'model merge') - sd_models.list_models() # to remove the potentially missing models from the list - return [*[gr.Dropdown.update(choices=sd_models.checkpoint_tiles()) for _ in range(4)], - f"Error merging checkpoints: {e}"] - return results - - modelmerger_merge.click( - fn=wrap_gradio_gpu_call(modelmerger, extra_outputs=lambda: [gr.update() for _ in range(4)]), - _js='modelmerger', - inputs=[ - dummy_component, - primary_model_name, - secondary_model_name, - tertiary_model_name, - interp_method, - interp_amount, - save_as_half, - custom_name, - checkpoint_format, - config_source, - bake_in_vae, - discard_weights, - save_metadata, - ], - outputs=[ - primary_model_name, - secondary_model_name, - tertiary_model_name, - dummy_component, - models_outcome, - ] - ) - with gr.Tab(label="Advanced Merge"): def sd_model_choices(): return ['None'] + sd_models.checkpoint_tiles() @@ -167,7 +85,8 @@ def create_ui(): with FormRow(): merge_mode = gr.Dropdown(choices=merge_methods.__all__, value="weighted_sum", label="Interpolation Method") - merge_mode_docs = gr.HTML(value=getattr(merge_methods, "weighted_sum").__doc__.replace("\n", "
")) + merge_mode_docs = gr.HTML( + value=getattr(merge_methods, "weighted_sum").__doc__.replace("\n", "
")) with FormRow(): primary_model_name = gr.Dropdown(sd_model_choices(), label="Primary model", value="None") create_refresh_button(primary_model_name, sd_models.list_models, @@ -253,45 +172,45 @@ def create_ui(): with FormRow(): save_metadata = gr.Checkbox(value=True, label="Save metadata") with gr.Row(): - MEHmodelmerger_merge = gr.Button(value="Merge", variant='primary') + modelmerger_merge = gr.Button(value="Merge", variant='primary') - def MEHmodelmerger(dummy_component, - primary_model_name, - secondary_model_name, - tertiary_model_name, - merge_mode, - alpha, - beta, - alpha_preset, - alpha_preset_lambda, - alpha_base, - alpha_in_blocks, - alpha_mid_block, - alpha_out_blocks, - beta_preset, - beta_preset_lambda, - beta_base, - beta_in_blocks, - beta_mid_block, - beta_out_blocks, - precision, - custom_name, - checkpoint_format, - save_metadata, - weights_clip, - prune, - re_basin, - re_basin_iterations, - device, - bake_in_vae): + def modelmerger(dummy_component, + primary_model_name, + secondary_model_name, + tertiary_model_name, + merge_mode, + alpha, + beta, + alpha_preset, + alpha_preset_lambda, + alpha_base, + alpha_in_blocks, + alpha_mid_block, + alpha_out_blocks, + beta_preset, + beta_preset_lambda, + beta_base, + beta_in_blocks, + beta_mid_block, + beta_out_blocks, + precision, + custom_name, + checkpoint_format, + save_metadata, + weights_clip, + prune, + re_basin, + re_basin_iterations, + device, + bake_in_vae): kwargs = {} - for x in inspect.getfullargspec(MEHmodelmerger)[0]: + for x in inspect.getfullargspec(modelmerger)[0]: kwargs[x] = locals()[x] for key in list(kwargs.keys()): if kwargs[key] in [None, "None", "", 0, []]: del kwargs[key] try: - results = extras.run_MEHmodelmerger(dummy_component, **kwargs) + results = extras.run_modelmerger(dummy_component, **kwargs) except Exception as e: modules.errors.display(e, 'model merge') sd_models.list_models() # to remove the potentially missing models from the list @@ -358,8 +277,8 @@ def create_ui(): beta_apply_preset.click(fn=load_presets, inputs=[beta_preset, beta_preset_lambda], outputs=[beta_base, beta_in_blocks, beta_mid_block, beta_out_blocks, tabs]) - MEHmodelmerger_merge.click( - fn=wrap_gradio_gpu_call(MEHmodelmerger, extra_outputs=lambda: [gr.update() for _ in range(4)]), + modelmerger_merge.click( + fn=wrap_gradio_gpu_call(modelmerger, extra_outputs=lambda: [gr.update() for _ in range(4)]), _js='modelmerger', inputs=[ dummy_component, From f2b66b8720f8b9f3005a7cb6d7c0c5d945ee3209 Mon Sep 17 00:00:00 2001 From: AI-Casanova <54461896+AI-Casanova@users.noreply.github.com> Date: Sat, 18 Nov 2023 11:45:54 -0600 Subject: [PATCH 68/84] Error handling --- modules/extras.py | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/modules/extras.py b/modules/extras.py index 2b2852844..cc57de2db 100644 --- a/modules/extras.py +++ b/modules/extras.py @@ -85,11 +85,10 @@ def run_modelmerger(id_task, **kwargs): # pylint: disable=unused-argument alpha = [float(x) for x in [kwargs["alpha_base"]] + kwargs["alpha_in_blocks"].split(",") + [kwargs["alpha_mid_block"]] + kwargs[ "alpha_out_blocks"].split(",")] - assert len(alpha) == 26 or len( - alpha) == 20, "Alpha Block Weights are wrong length (26 or 20 for SDXL) falling back" + assert len(alpha) == 26 or len(alpha) == 20, "Alpha Block Weights are wrong length (26 or 20 for SDXL) falling back" kwargs["alpha"] = alpha - except AssertionError as e: - shared.log.info(e) + except Exception as e: + shared.log.warn(f"Merge: {e}") kwargs["alpha"] = kwargs.get("alpha_preset", kwargs["alpha"]) finally: kwargs.pop("alpha_base", None) @@ -101,13 +100,11 @@ def run_modelmerger(id_task, **kwargs): # pylint: disable=unused-argument if kwargs.get("beta", False): try: beta = [float(x) for x in - [kwargs["beta_base"]] + kwargs["beta_in_blocks"].split(",") + [kwargs["beta_mid_block"]] + kwargs[ - "beta_out_blocks"].split(",")] - assert len(beta) == 26 or len( - beta) == 20, "Beta Block Weights are wrong length (26 or 20 for SDXL) falling back" + [kwargs["beta_base"]] + kwargs["beta_in_blocks"].split(",") + [kwargs["beta_mid_block"]] + kwargs["beta_out_blocks"].split(",")] + assert len(beta) == 26 or len(beta) == 20, "Beta Block Weights are wrong length (26 or 20 for SDXL) falling back" kwargs["beta"] = beta - except AssertionError as e: - shared.log.info(e) + except Exception as e: + shared.log.warn(f"Merge: {e}") kwargs["beta"] = kwargs.get("beta_preset", kwargs["beta"]) finally: kwargs.pop("beta_base", None) @@ -132,7 +129,7 @@ def run_modelmerger(id_task, **kwargs): # pylint: disable=unused-argument bake_in_vae_filename = sd_vae.vae_dict.get(kwargs.get("bake_in_vae", None), None) if bake_in_vae_filename is not None: - shared.log.info(f"Model merge: baking in VAE: {bake_in_vae_filename}") + shared.log.info(f"Merge: baking in VAE: {bake_in_vae_filename}") shared.state.textinfo = 'Baking in VAE' vae_dict = sd_vae.load_vae_dict(bake_in_vae_filename) for key in vae_dict.keys(): @@ -196,7 +193,7 @@ def run_modelmerger(id_task, **kwargs): # pylint: disable=unused-argument created_model.calculate_shorthash() if kwargs["device"].type != "cpu": devices.torch_gc(force=True) - shared.log.info(f"Model merge saved: {output_modelname}.") + shared.log.info(f"Merge saved: {output_modelname}.") shared.state.textinfo = "Checkpoint saved" shared.state.end() return [*[gr.Dropdown.update(choices=sd_models.checkpoint_tiles()) for _ in range(4)], From c5371a5087bb5bf72901cb5f83d06cbe0eca4535 Mon Sep 17 00:00:00 2001 From: AI-Casanova <54461896+AI-Casanova@users.noreply.github.com> Date: Sat, 18 Nov 2023 12:05:15 -0600 Subject: [PATCH 69/84] pylint fixes --- modules/merging/merge.py | 2 +- modules/merging/merge_methods.py | 24 ++++++++++++------------ modules/merging/merge_rebasin.py | 14 +++++++------- modules/merging/merge_utils.py | 1 - 4 files changed, 20 insertions(+), 21 deletions(-) diff --git a/modules/merging/merge.py b/modules/merging/merge.py index f0cb89ce5..289d069af 100644 --- a/modules/merging/merge.py +++ b/modules/merging/merge.py @@ -309,7 +309,7 @@ def simple_merge_key(progress, key, thetas, *args, **kwargs): progress.update() -def merge_key( +def merge_key( # pylint: disable=inconsistent-return-statements key: str, thetas: Dict, weight_matcher: WeightClass, diff --git a/modules/merging/merge_methods.py b/modules/merging/merge_methods.py index a80a18106..3f704c20f 100644 --- a/modules/merging/merge_methods.py +++ b/modules/merging/merge_methods.py @@ -23,7 +23,7 @@ __all__ = [ EPSILON = 1e-10 # Define a small constant EPSILON to prevent division by zero -def weighted_sum(a: Tensor, b: Tensor, alpha: float, **kwargs) -> Tensor: +def weighted_sum(a: Tensor, b: Tensor, alpha: float, **kwargs) -> Tensor: # pylint: disable=unused-argument """ Basic Merge: alpha 0 returns Primary Model @@ -32,7 +32,7 @@ def weighted_sum(a: Tensor, b: Tensor, alpha: float, **kwargs) -> Tensor: return (1 - alpha) * a + alpha * b -def weighted_subtraction(a: Tensor, b: Tensor, alpha: float, beta: float, **kwargs) -> Tensor: +def weighted_subtraction(a: Tensor, b: Tensor, alpha: float, beta: float, **kwargs) -> Tensor: # pylint: disable=unused-argument """ The inverse of a Weighted Sum Merge Returns Primary Model when alpha*beta = 0 @@ -45,7 +45,7 @@ def weighted_subtraction(a: Tensor, b: Tensor, alpha: float, beta: float, **kwar return (a - alpha * beta * b) / (1 - alpha * beta) -def tensor_sum(a: Tensor, b: Tensor, alpha: float, beta: float, **kwargs) -> Tensor: +def tensor_sum(a: Tensor, b: Tensor, alpha: float, beta: float, **kwargs) -> Tensor: # pylint: disable=unused-argument """ Takes a slice of Secondary Model and pastes it into Primary Model Alpha sets the width of the slice @@ -65,14 +65,14 @@ def tensor_sum(a: Tensor, b: Tensor, alpha: float, beta: float, **kwargs) -> Ten return tt -def add_difference(a: Tensor, b: Tensor, c: Tensor, alpha: float, **kwargs) -> Tensor: +def add_difference(a: Tensor, b: Tensor, c: Tensor, alpha: float, **kwargs) -> Tensor: # pylint: disable=unused-argument """ Classic Add Difference Merge """ return a + alpha * (b - c) -def sum_twice(a: Tensor, b: Tensor, c: Tensor, alpha: float, beta: float, **kwargs) -> Tensor: +def sum_twice(a: Tensor, b: Tensor, c: Tensor, alpha: float, beta: float, **kwargs) -> Tensor: # pylint: disable=unused-argument """ Stacked Basic Merge: Equivalent to Merging Primary and Secondary @ alpha @@ -81,7 +81,7 @@ def sum_twice(a: Tensor, b: Tensor, c: Tensor, alpha: float, beta: float, **kwar return (1 - beta) * ((1 - alpha) * a + alpha * b) + beta * c -def triple_sum(a: Tensor, b: Tensor, c: Tensor, alpha: float, beta: float, **kwargs) -> Tensor: +def triple_sum(a: Tensor, b: Tensor, c: Tensor, alpha: float, beta: float, **kwargs) -> Tensor: # pylint: disable=unused-argument """ Weights Secondary and Tertiary at alpha and beta respectively Fills in the rest with Primary @@ -90,7 +90,7 @@ def triple_sum(a: Tensor, b: Tensor, c: Tensor, alpha: float, beta: float, **kwa return (1 - alpha - beta) * a + alpha * b + beta * c -def euclidean_add_difference(a: Tensor, b: Tensor, c: Tensor, alpha: float, **kwargs) -> Tensor: +def euclidean_add_difference(a: Tensor, b: Tensor, c: Tensor, alpha: float, **kwargs) -> Tensor: # pylint: disable=unused-argument """ Subtract Primary and Secondary from Tertiary Compare the remainders via Euclidean distance @@ -111,7 +111,7 @@ def euclidean_add_difference(a: Tensor, b: Tensor, c: Tensor, alpha: float, **kw return c + distance / torch.linalg.norm(distance) * target_norm -def multiply_difference(a: Tensor, b: Tensor, c: Tensor, alpha: float, beta: float, **kwargs) -> Tensor: +def multiply_difference(a: Tensor, b: Tensor, c: Tensor, alpha: float, beta: float, **kwargs) -> Tensor: # pylint: disable=unused-argument """ Similar to Add Difference but with geometric mean instead of arithmatic mean """ @@ -121,7 +121,7 @@ def multiply_difference(a: Tensor, b: Tensor, c: Tensor, alpha: float, beta: flo return c + difference.to(c.dtype) -def top_k_tensor_sum(a: Tensor, b: Tensor, alpha: float, beta: float, **kwargs) -> Tensor: +def top_k_tensor_sum(a: Tensor, b: Tensor, alpha: float, beta: float, **kwargs) -> Tensor: # pylint: disable=unused-argument """ Redistributes the largest weights of Secondary Model into Primary Model """ @@ -173,7 +173,7 @@ def ratio_to_region(width: float, offset: float, n: int) -> Tuple[int, int, bool return round(start), round(end), inverted -def similarity_add_difference(a: Tensor, b: Tensor, c: Tensor, alpha: float, beta: float, **kwargs) -> Tensor: +def similarity_add_difference(a: Tensor, b: Tensor, c: Tensor, alpha: float, beta: float, **kwargs) -> Tensor: # pylint: disable=unused-argument """ Weighted Sum where A and B are similar and Add Difference where A and B are dissimilar """ @@ -186,7 +186,7 @@ def similarity_add_difference(a: Tensor, b: Tensor, c: Tensor, alpha: float, bet return (1 - similarity) * ab_diff + similarity * ab_sum -def distribution_crossover(a: Tensor, b: Tensor, c: Tensor, alpha: float, beta: float, **kwargs): +def distribution_crossover(a: Tensor, b: Tensor, c: Tensor, alpha: float, beta: float, **kwargs): # pylint: disable=unused-argument """ From the creator: It's Primary high-passed + Secondary low-passed. Takes the fourrier transform of the weights of @@ -218,7 +218,7 @@ def distribution_crossover(a: Tensor, b: Tensor, c: Tensor, alpha: float, beta: return x_values.reshape_as(a) -def ties_add_difference(a: Tensor, b: Tensor, c: Tensor, alpha: float, beta: float, **kwargs) -> Tensor: +def ties_add_difference(a: Tensor, b: Tensor, c: Tensor, alpha: float, beta: float, **kwargs) -> Tensor: # pylint: disable=unused-argument """ An implementation of arXiv:2306.01708 """ diff --git a/modules/merging/merge_rebasin.py b/modules/merging/merge_rebasin.py index 26aac9964..2606a52f9 100644 --- a/modules/merging/merge_rebasin.py +++ b/modules/merging/merge_rebasin.py @@ -31,23 +31,23 @@ def permutation_spec_from_axes_to_perm(axes_to_perm: dict) -> PermutationSpec: def sdunet_permutation_spec() -> PermutationSpec: - conv = lambda name, p_in, p_out: { + conv = lambda name, p_in, p_out: { # pylint: disable=unnecessary-lambda-assignment f"{name}.weight": ( p_out, p_in, ), f"{name}.bias": (p_out,), } - norm = lambda name, p: {f"{name}.weight": (p,), f"{name}.bias": (p,)} + norm = lambda name, p: {f"{name}.weight": (p,), f"{name}.bias": (p,)} # pylint: disable=unnecessary-lambda-assignment dense = ( - lambda name, p_in, p_out, bias=True: { + lambda name, p_in, p_out, bias=True: { # pylint: disable=unnecessary-lambda-assignment f"{name}.weight": (p_out, p_in), f"{name}.bias": (p_out,), } if bias else {f"{name}.weight": (p_out, p_in)} ) - skip = lambda name, p_in, p_out: { + skip = lambda name, p_in, p_out: { # pylint: disable=unnecessary-lambda-assignment f"{name}": ( p_out, p_in, @@ -57,7 +57,7 @@ def sdunet_permutation_spec() -> PermutationSpec: } # Unet Res blocks - easyblock = lambda name, p_in, p_out: { + easyblock = lambda name, p_in, p_out: { # pylint: disable=unnecessary-lambda-assignment **norm(f"{name}.in_layers.0", p_in), **conv(f"{name}.in_layers.2", p_in, f"P_{name}_inner"), **dense( @@ -68,7 +68,7 @@ def sdunet_permutation_spec() -> PermutationSpec: } # Text Encoder blocks - easyblock2 = lambda name, p: { + easyblock2 = lambda name, p: { # pylint: disable=unnecessary-lambda-assignment **norm(f"{name}.norm1", p), **conv(f"{name}.conv1", p, f"P_{name}_inner"), **norm(f"{name}.norm2", f"P_{name}_inner"), @@ -76,7 +76,7 @@ def sdunet_permutation_spec() -> PermutationSpec: } # This is for blocks that use a residual connection, but change the number of channels via a Conv. - shortcutblock = lambda name, p_in, p_out: { + shortcutblock = lambda name, p_in, p_out: { # pylint: disable=unnecessary-lambda-assignment **norm(f"{name}.norm1", p_in), **conv(f"{name}.conv1", p_in, f"P_{name}_inner"), **norm(f"{name}.norm2", f"P_{name}_inner"), diff --git a/modules/merging/merge_utils.py b/modules/merging/merge_utils.py index da0059967..5bdfee246 100644 --- a/modules/merging/merge_utils.py +++ b/modules/merging/merge_utils.py @@ -109,4 +109,3 @@ class WeightClass: def set_it(self, it): self.it = it - return From 581ab58bdd26420a9cad88fa84c91a9c2cc0bbad Mon Sep 17 00:00:00 2001 From: AI-Casanova <54461896+AI-Casanova@users.noreply.github.com> Date: Sun, 19 Nov 2023 12:03:13 -0600 Subject: [PATCH 70/84] Fix item 1,2,3,5,6 --- modules/extras.py | 26 ++++++++++++++------------ modules/merging/merge.py | 14 +++++++++++--- modules/ui_models.py | 16 +++++++++++++--- 3 files changed, 38 insertions(+), 18 deletions(-) diff --git a/modules/extras.py b/modules/extras.py index cc57de2db..a0c048b4e 100644 --- a/modules/extras.py +++ b/modules/extras.py @@ -61,24 +61,24 @@ def run_modelmerger(id_task, **kwargs): # pylint: disable=unused-argument return [*[gr.update() for _ in range(4)], message] kwargs["models"] = { - "model_a": sd_models.checkpoints_list[kwargs.get("primary_model_name", None)].filename, - "model_b": sd_models.checkpoints_list[kwargs.get("secondary_model_name", None)].filename, + "model_a": sd_models.get_closet_checkpoint_match(kwargs.get("primary_model_name", None)).filename, + "model_b": sd_models.get_closet_checkpoint_match(kwargs.get("secondary_model_name", None)).filename, } if kwargs.get("primary_model_name", None) in [None, 'None']: return fail("Failed: Merging requires a primary model.") - primary_model_info = sd_models.checkpoints_list[kwargs.get("primary_model_name", None)] + primary_model_info = sd_models.get_closet_checkpoint_match(kwargs.get("primary_model_name", None)) if kwargs.get("secondary_model_name", None) in [None, 'None']: return fail("Failed: Merging requires a secondary model.") - secondary_model_info = sd_models.checkpoints_list[kwargs.get("secondary_model_name", None)] + secondary_model_info = sd_models.get_closet_checkpoint_match(kwargs.get("secondary_model_name", None)) if kwargs.get("tertiary_model_name", None) in [None, 'None'] and kwargs.get("merge_mode", None) in TRIPLE_METHODS: return fail(f"Failed: Interpolation method ({kwargs.get('merge_mode', None)}) requires a tertiary model.") - tertiary_model_info = sd_models.checkpoints_list[kwargs.get("tertiary_model_name", None)] if kwargs.get("merge_mode", None) in TRIPLE_METHODS else None + tertiary_model_info = sd_models.get_closet_checkpoint_match(kwargs.get("tertiary_model_name", None)) if kwargs.get("merge_mode", None) in TRIPLE_METHODS else None del kwargs["primary_model_name"] del kwargs["secondary_model_name"] if kwargs.get("tertiary_model_name", None) is not None: - kwargs["models"] |= {"model_c": sd_models.checkpoints_list[kwargs.get("tertiary_model_name", None)].filename} + kwargs["models"] |= {"model_c": sd_models.get_closet_checkpoint_match(kwargs.get("tertiary_model_name", None)).filename} del kwargs["tertiary_model_name"] try: @@ -113,20 +113,26 @@ def run_modelmerger(id_task, **kwargs): # pylint: disable=unused-argument kwargs.pop("beta_out_blocks", None) kwargs.pop("beta_preset", None) - if kwargs["device"] == "cuda": + if kwargs["device"] == "gpu": kwargs["device"] = devices.device - sd_models.unload_model_weights() elif kwargs["device"] == "shuffle": kwargs["device"] = torch.device("cpu") kwargs["work_device"] = devices.device else: kwargs["device"] = torch.device("cpu") + if kwargs.pop("unload", False): + sd_models.unload_model_weights() try: theta_0 = merge_models(**kwargs) except Exception as e: return fail(f"{e}") + try: + theta_0 = theta_0.to_dict() #TensorDict -> Dict if necessary + except: + pass + bake_in_vae_filename = sd_vae.vae_dict.get(kwargs.get("bake_in_vae", None), None) if bake_in_vae_filename is not None: shared.log.info(f"Merge: baking in VAE: {bake_in_vae_filename}") @@ -177,10 +183,6 @@ def run_modelmerger(id_task, **kwargs): # pylint: disable=unused-argument _, extension = os.path.splitext(output_modelname) - try: - theta_0 = theta_0.to_dict() - except: - pass if extension.lower() == ".safetensors": safetensors.torch.save_file(theta_0, output_modelname, metadata=metadata) diff --git a/modules/merging/merge.py b/modules/merging/merge.py index 289d069af..09d03685b 100644 --- a/modules/merging/merge.py +++ b/modules/merging/merge.py @@ -54,7 +54,7 @@ def prune_sd_model(model: Dict) -> Dict: for k in keys: if ( not k.startswith("model.diffusion_model.") - and not k.startswith("first_stage_model.") + # and not k.startswith("first_stage_model.") and not k.startswith("cond_stage_model.") ): del model[k] @@ -153,23 +153,31 @@ def un_prune_model( devices.torch_gc(force=True) log_vram("remove thetas") original_a = TensorDict.from_dict(read_state_dict(models["model_a"], device)) - for key in tqdm(original_a.keys(), desc="un-prune model a"): + unpruned = 0 + for key in original_a.keys(): if KEY_POSITION_IDS in key: continue if "model" in key and key not in merged.keys(): merged.update({key: original_a[key]}) + unpruned += 1 if precision == "fp16": merged.update({key: merged[key].half()}) + if unpruned != 0: + log.info(f"Merge: {unpruned} unmerged keys restored from Primary Model") + unpruned = 0 del original_a devices.torch_gc(force=True) original_b = TensorDict.from_dict(read_state_dict(models["model_b"], device)) - for key in tqdm(original_b.keys(), desc="un-prune model b"): + for key in original_b.keys(): if KEY_POSITION_IDS in key: continue if "model" in key and key not in merged.keys(): merged.update({key: original_b[key]}) + unpruned += 1 if precision == "fp16": merged.update({key: merged[key].half()}) + if unpruned != 0: + log.info(f"Merge: {unpruned} unmerged keys restored from Secondary Model") del original_b return fix_clip(merged) diff --git a/modules/ui_models.py b/modules/ui_models.py index 509e828a6..9141dc9bb 100644 --- a/modules/ui_models.py +++ b/modules/ui_models.py @@ -162,10 +162,11 @@ def create_ui(): with FormRow(): precision = gr.Radio(choices=["fp16", "fp32"], value="fp16", label="Model precision") with FormRow(): - device = gr.Radio(choices=["cpu", "shuffle", "cuda"], value="cpu", label="Merge Device") + device = gr.Radio(choices=["cpu", "shuffle", "gpu"], value="cpu", label="Merge Device") + unload = gr.Checkbox(label="Unload Current Model from VRAM", value=False, visible=False) with FormRow(): bake_in_vae = gr.Dropdown(choices=["None"] + list(sd_vae.vae_dict), value="None", - interactive=True, label="Bake in VAE") + interactive=True, label="Replace VAE") create_refresh_button(bake_in_vae, sd_vae.refresh_vae_list, lambda: {"choices": ["None"] + list(sd_vae.vae_dict)}, "modelmerger_refresh_bake_in_vae") @@ -202,6 +203,7 @@ def create_ui(): re_basin, re_basin_iterations, device, + unload, bake_in_vae): kwargs = {} for x in inspect.getfullargspec(modelmerger)[0]: @@ -240,6 +242,13 @@ def create_ui(): doc = getattr(merge_methods, mode).__doc__.replace("\n", "
") return gr.update(value=doc, visible=True) + def show_unload(device): + if device == "gpu": + return gr.update(visble=True) + else: + return gr.update(visble=False) + + def preset_visiblility(x): if len(x) == 2: return gr.Slider.update(value=0.5, visible=True) @@ -262,7 +271,7 @@ def create_ui(): return [gr.update(choices=["None"] + list(SDXL_BLOCK_WEIGHTS_PRESETS.keys())) for _ in range(2)] else: return [gr.update(choices=["None"] + list(BLOCK_WEIGHTS_PRESETS.keys())) for _ in range(2)] - + device.change(fn=show_unload, inputs=device, outputs=unload) merge_mode.change(fn=show_help, inputs=merge_mode, outputs=merge_mode_docs) sdxl.change(fn=preset_choices, inputs=sdxl, outputs=[alpha_preset, beta_preset]) alpha_preset.change(fn=preset_visiblility, inputs=alpha_preset, outputs=alpha_preset_lambda) @@ -309,6 +318,7 @@ def create_ui(): re_basin, re_basin_iterations, device, + unload, bake_in_vae, ], outputs=[ From 564b67bcd8c23ff39a7b99200a4480fed0448ce0 Mon Sep 17 00:00:00 2001 From: AI-Casanova <54461896+AI-Casanova@users.noreply.github.com> Date: Sun, 19 Nov 2023 13:47:02 -0600 Subject: [PATCH 71/84] Merge: Typo and error handling (#2527) * Typo and error handling * typo typo * error logging * fix alpha vs beta * Don't log VAE keys in unpruning --- modules/extras.py | 10 ++++++++-- modules/merging/merge.py | 6 +++--- modules/ui_models.py | 4 ++-- 3 files changed, 13 insertions(+), 7 deletions(-) diff --git a/modules/extras.py b/modules/extras.py index a0c048b4e..7bf9f8ad6 100644 --- a/modules/extras.py +++ b/modules/extras.py @@ -87,7 +87,10 @@ def run_modelmerger(id_task, **kwargs): # pylint: disable=unused-argument "alpha_out_blocks"].split(",")] assert len(alpha) == 26 or len(alpha) == 20, "Alpha Block Weights are wrong length (26 or 20 for SDXL) falling back" kwargs["alpha"] = alpha - except Exception as e: + except KeyError as ke: + shared.log.warn(f"Merge: Malformed manual block weight at {ke} falling back") + kwargs["alpha"] = kwargs.get("alpha_preset", kwargs["alpha"]) + except AssertionError as e: shared.log.warn(f"Merge: {e}") kwargs["alpha"] = kwargs.get("alpha_preset", kwargs["alpha"]) finally: @@ -103,7 +106,10 @@ def run_modelmerger(id_task, **kwargs): # pylint: disable=unused-argument [kwargs["beta_base"]] + kwargs["beta_in_blocks"].split(",") + [kwargs["beta_mid_block"]] + kwargs["beta_out_blocks"].split(",")] assert len(beta) == 26 or len(beta) == 20, "Beta Block Weights are wrong length (26 or 20 for SDXL) falling back" kwargs["beta"] = beta - except Exception as e: + except KeyError as ke: + shared.log.warn(f"Merge: Malformed manual block weight at {ke} falling back") + kwargs["beta"] = kwargs.get("beta_preset", kwargs["beta"]) + except AssertionError as e: shared.log.warn(f"Merge: {e}") kwargs["beta"] = kwargs.get("beta_preset", kwargs["beta"]) finally: diff --git a/modules/merging/merge.py b/modules/merging/merge.py index 09d03685b..c7118b11a 100644 --- a/modules/merging/merge.py +++ b/modules/merging/merge.py @@ -162,9 +162,9 @@ def un_prune_model( unpruned += 1 if precision == "fp16": merged.update({key: merged[key].half()}) - if unpruned != 0: - log.info(f"Merge: {unpruned} unmerged keys restored from Primary Model") - unpruned = 0 + if unpruned > 248: # VAE has 248 keys, and we are purposely restoring it here + log.info(f"Merge: {unpruned - 248} unmerged keys restored from Primary Model") + unpruned = 0 del original_a devices.torch_gc(force=True) original_b = TensorDict.from_dict(read_state_dict(models["model_b"], device)) diff --git a/modules/ui_models.py b/modules/ui_models.py index 9141dc9bb..ae28825f1 100644 --- a/modules/ui_models.py +++ b/modules/ui_models.py @@ -244,9 +244,9 @@ def create_ui(): def show_unload(device): if device == "gpu": - return gr.update(visble=True) + return gr.update(visible=True) else: - return gr.update(visble=False) + return gr.update(visible=False) def preset_visiblility(x): From 00b246c052de7e9d2583fdab5893f53fe588e3b9 Mon Sep 17 00:00:00 2001 From: Vladimir Mandic Date: Mon, 20 Nov 2023 11:43:30 -0500 Subject: [PATCH 72/84] update advanced merging --- .git-blame-ignore-revs | 1 - CHANGELOG.md | 7 ++ extensions-builtin/sd-webui-controlnet | 2 +- modules/extras.py | 75 +++++++++--------- modules/merging/merge.py | 76 ++++++++---------- modules/merging/merge_rebasin.py | 6 +- modules/sd_models.py | 2 +- modules/ui_models.py | 102 ++++++++++++++----------- 8 files changed, 135 insertions(+), 136 deletions(-) delete mode 100644 .git-blame-ignore-revs diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs deleted file mode 100644 index e6cb02607..000000000 --- a/.git-blame-ignore-revs +++ /dev/null @@ -1 +0,0 @@ -4c7792ed011b233cdb6e9e42327085f4d66701f2 diff --git a/CHANGELOG.md b/CHANGELOG.md index 7c45847be..e4f6ca5bf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -27,6 +27,13 @@ Change-in-behavior: new line in prompt now means *BREAK* - Add alternative Lora loading algorithm, triggered if `SD_LORA_DIFFUSERS` is set - Update to `diffusers==0.23.0` +- **Model merge** + - completely redesigned, now based on best-of-class `meh` by @s1dlx + and heavily modified for additional functionality and fully integrated by @AI-Casanova (thanks!) + - merge SD or SD-XL models using *simple merge* (12 methods), + using one of *presets* (20 built-in presets) or custom block merge values + - merge with ReBasin permuatations and/or clipping protection + - fully multithreaded for fastest merge possible - **Extra networks** - Use multi-threading for 5x load speedup - Better Lora trigger words support diff --git a/extensions-builtin/sd-webui-controlnet b/extensions-builtin/sd-webui-controlnet index c1f3d6f85..0efcf8c99 160000 --- a/extensions-builtin/sd-webui-controlnet +++ b/extensions-builtin/sd-webui-controlnet @@ -1 +1 @@ -Subproject commit c1f3d6f8505074d73b13eaf67f331bf869d7b940 +Subproject commit 0efcf8c99345a67b62b6f54683bc046a7627698b diff --git a/modules/extras.py b/modules/extras.py index 7bf9f8ad6..7772e39db 100644 --- a/modules/extras.py +++ b/modules/extras.py @@ -1,6 +1,7 @@ import os import html import json +import time import shutil import torch @@ -54,6 +55,7 @@ def to_half(tensor, enable): def run_modelmerger(id_task, **kwargs): # pylint: disable=unused-argument shared.state.begin('merge') + t0 = time.time() def fail(message): shared.state.textinfo = message @@ -81,43 +83,39 @@ def run_modelmerger(id_task, **kwargs): # pylint: disable=unused-argument kwargs["models"] |= {"model_c": sd_models.get_closet_checkpoint_match(kwargs.get("tertiary_model_name", None)).filename} del kwargs["tertiary_model_name"] - try: - alpha = [float(x) for x in - [kwargs["alpha_base"]] + kwargs["alpha_in_blocks"].split(",") + [kwargs["alpha_mid_block"]] + kwargs[ - "alpha_out_blocks"].split(",")] - assert len(alpha) == 26 or len(alpha) == 20, "Alpha Block Weights are wrong length (26 or 20 for SDXL) falling back" - kwargs["alpha"] = alpha - except KeyError as ke: - shared.log.warn(f"Merge: Malformed manual block weight at {ke} falling back") + if hasattr(kwargs, "alpha_base") and hasattr(kwargs, "alpha_in_blocks") and hasattr(kwargs, "alpha_mid_block") and hasattr(kwargs, "alpha_out_blocks"): + try: + alpha = [float(x) for x in + [kwargs["alpha_base"]] + kwargs["alpha_in_blocks"].split(",") + [kwargs["alpha_mid_block"]] + kwargs["alpha_out_blocks"].split(",")] + assert len(alpha) == 26 or len(alpha) == 20, "Alpha Block Weights are wrong length (26 or 20 for SDXL) falling back" + kwargs["alpha"] = alpha + except KeyError as ke: + shared.log.warning(f"Merge: Malformed manual block weight: {ke}") + elif hasattr(kwargs, "alpha_preset") or hasattr(kwargs, "alpha"): kwargs["alpha"] = kwargs.get("alpha_preset", kwargs["alpha"]) - except AssertionError as e: - shared.log.warn(f"Merge: {e}") - kwargs["alpha"] = kwargs.get("alpha_preset", kwargs["alpha"]) - finally: - kwargs.pop("alpha_base", None) - kwargs.pop("alpha_in_blocks", None) - kwargs.pop("alpha_mid_block", None) - kwargs.pop("alpha_out_blocks", None) - kwargs.pop("alpha_preset", None) - if kwargs.get("beta", False): + kwargs.pop("alpha_base", None) + kwargs.pop("alpha_in_blocks", None) + kwargs.pop("alpha_mid_block", None) + kwargs.pop("alpha_out_blocks", None) + kwargs.pop("alpha_preset", None) + + if hasattr(kwargs, "beta_base") and hasattr(kwargs, "beta_in_blocks") and hasattr(kwargs, "beta_mid_block") and hasattr(kwargs, "beta_out_blocks"): try: beta = [float(x) for x in [kwargs["beta_base"]] + kwargs["beta_in_blocks"].split(",") + [kwargs["beta_mid_block"]] + kwargs["beta_out_blocks"].split(",")] assert len(beta) == 26 or len(beta) == 20, "Beta Block Weights are wrong length (26 or 20 for SDXL) falling back" kwargs["beta"] = beta except KeyError as ke: - shared.log.warn(f"Merge: Malformed manual block weight at {ke} falling back") - kwargs["beta"] = kwargs.get("beta_preset", kwargs["beta"]) - except AssertionError as e: - shared.log.warn(f"Merge: {e}") - kwargs["beta"] = kwargs.get("beta_preset", kwargs["beta"]) - finally: - kwargs.pop("beta_base", None) - kwargs.pop("beta_in_blocks", None) - kwargs.pop("beta_mid_block", None) - kwargs.pop("beta_out_blocks", None) - kwargs.pop("beta_preset", None) + shared.log.warning(f"Merge: Malformed manual block weight: {ke}") + elif hasattr(kwargs, "beta_preset") or hasattr(kwargs, "beta"): + kwargs["beta"] = kwargs.get("beta_preset", kwargs["beta"]) + + kwargs.pop("beta_base", None) + kwargs.pop("beta_in_blocks", None) + kwargs.pop("beta_mid_block", None) + kwargs.pop("beta_out_blocks", None) + kwargs.pop("beta_preset", None) if kwargs["device"] == "gpu": kwargs["device"] = devices.device @@ -141,8 +139,8 @@ def run_modelmerger(id_task, **kwargs): # pylint: disable=unused-argument bake_in_vae_filename = sd_vae.vae_dict.get(kwargs.get("bake_in_vae", None), None) if bake_in_vae_filename is not None: - shared.log.info(f"Merge: baking in VAE: {bake_in_vae_filename}") - shared.state.textinfo = 'Baking in VAE' + shared.log.info(f"Merge VAE='{bake_in_vae_filename}'") + shared.state.textinfo = 'Merge VAE' vae_dict = sd_vae.load_vae_dict(bake_in_vae_filename) for key in vae_dict.keys(): theta_0_key = 'first_stage_model.' + key @@ -154,7 +152,7 @@ def run_modelmerger(id_task, **kwargs): # pylint: disable=unused-argument filename = kwargs.get("custom_name", "Unnamed_Merge") filename += "." + kwargs.get("checkpoint_format", None) output_modelname = os.path.join(ckpt_dir, filename) - shared.state.textinfo = "Saving" + shared.state.textinfo = "merge saving" metadata = None if kwargs.get("save_metadata", False): metadata = {"format": "pt", "sd_merge_models": {}} @@ -189,23 +187,22 @@ def run_modelmerger(id_task, **kwargs): # pylint: disable=unused-argument _, extension = os.path.splitext(output_modelname) - + if os.path.exists(output_modelname) and not kwargs.get("overwrite", False): + return [*[gr.Dropdown.update(choices=sd_models.checkpoint_tiles()) for _ in range(4)], f"Model alredy exists: {output_modelname}"] if extension.lower() == ".safetensors": safetensors.torch.save_file(theta_0, output_modelname, metadata=metadata) else: torch.save(theta_0, output_modelname) + t1 = time.time() + shared.log.info(f"Merge complete: saved='{output_modelname}' time={t1-t0:.2f}") sd_models.list_models() created_model = next((ckpt for ckpt in sd_models.checkpoints_list.values() if ckpt.name == filename), None) if created_model: created_model.calculate_shorthash() - if kwargs["device"].type != "cpu": - devices.torch_gc(force=True) - shared.log.info(f"Merge saved: {output_modelname}.") - shared.state.textinfo = "Checkpoint saved" + devices.torch_gc(force=True) shared.state.end() - return [*[gr.Dropdown.update(choices=sd_models.checkpoint_tiles()) for _ in range(4)], - "Checkpoint saved to " + output_modelname] + return [*[gr.Dropdown.update(choices=sd_models.checkpoint_tiles()) for _ in range(4)], f"Model saved to {output_modelname}"] def run_modelconvert(model, checkpoint_formats, precision, conv_type, custom_name, unet_conv, text_encoder_conv, diff --git a/modules/merging/merge.py b/modules/merging/merge.py index c7118b11a..68d4b2c21 100644 --- a/modules/merging/merge.py +++ b/modules/merging/merge.py @@ -5,10 +5,9 @@ from typing import Dict, Optional, Tuple import safetensors.torch import torch from tensordict import TensorDict -from tqdm import tqdm import modules.memstats import modules.devices as devices -from modules.shared import log +from modules.shared import log, console from modules.sd_models import read_state_dict from modules.merging import merge_methods from modules.merging.merge_utils import WeightClass @@ -69,7 +68,7 @@ def restore_sd_model(original_model: Dict, merged_model: Dict) -> Dict: def log_vram(txt=""): - log.debug(f"{txt} VRAM: {modules.memstats.memory_stats()}") + log.debug(f"Merge {txt}: {modules.memstats.memory_stats()}") def load_thetas( @@ -78,7 +77,6 @@ def load_thetas( device: torch.device, precision: str, ) -> Dict: - log_vram("before loading models") if prune: thetas = {k: prune_sd_model(TensorDict.from_dict(read_state_dict(m, "cpu"))) for k, m in models.items()} else: @@ -104,13 +102,11 @@ def merge_models( device: torch.device = None, work_device: torch.device = None, prune: bool = False, - threads: int = 1, + threads: int = 4, **kwargs, ) -> Dict: - iterations = kwargs.get("re_basin_iterations", 1) thetas = load_thetas(models, prune, device, precision) - - log.info(f"start merging with {merge_mode} method") + # log.info(f'Merge start: models={models.values()} precision={precision} clip={weights_clip} rebasin={re_basin} prune={prune} threads={threads}') weight_matcher = WeightClass(thetas["model_a"], **kwargs) if re_basin: merged = rebasin_merge( @@ -119,7 +115,7 @@ def merge_models( merge_mode, precision=precision, weights_clip=weights_clip, - iterations=iterations, + iterations=kwargs.get("re_basin_iterations", 1), device=device, work_device=work_device, threads=threads, @@ -148,10 +144,9 @@ def un_prune_model( precision: str, ) -> Dict: if prune: - log.info("Un-pruning merged model") + log.info("Merge restoring pruned keys") del thetas - devices.torch_gc(force=True) - log_vram("remove thetas") + devices.torch_gc(force=False) original_a = TensorDict.from_dict(read_state_dict(models["model_a"], device)) unpruned = 0 for key in original_a.keys(): @@ -163,10 +158,9 @@ def un_prune_model( if precision == "fp16": merged.update({key: merged[key].half()}) if unpruned > 248: # VAE has 248 keys, and we are purposely restoring it here - log.info(f"Merge: {unpruned - 248} unmerged keys restored from Primary Model") + log.debug(f"Merge restored from primary model: keys={unpruned - 248}") unpruned = 0 del original_a - devices.torch_gc(force=True) original_b = TensorDict.from_dict(read_state_dict(models["model_b"], device)) for key in original_b.keys(): if KEY_POSITION_IDS in key: @@ -177,8 +171,9 @@ def un_prune_model( if precision == "fp16": merged.update({key: merged[key].half()}) if unpruned != 0: - log.info(f"Merge: {unpruned} unmerged keys restored from Secondary Model") + log.debug(f"Merge restored from secondary model: keys={unpruned}") del original_b + devices.torch_gc(force=False) return fix_clip(merged) @@ -191,15 +186,19 @@ def simple_merge( weights_clip: bool = False, device: torch.device = None, work_device: torch.device = None, - threads: int = 1, + threads: int = 4, ) -> Dict: futures = [] - with tqdm(thetas["model_a"].keys(), desc="stage 1") as progress: + # with tqdm(thetas["model_a"].keys(), desc="Merge") as progress: + import rich.progress as p + with p.Progress(p.TextColumn('[cyan]{task.description}'), p.BarColumn(), p.TaskProgressColumn(), p.TimeRemainingColumn(), p.TimeElapsedColumn(), p.TextColumn('[cyan]keys={task.fields[keys]}'), console=console) as progress: + task = progress.add_task(description="Merging", total=len(thetas["model_a"].keys()), keys=len(thetas["model_a"].keys())) with ThreadPoolExecutor(max_workers=threads) as executor: for key in thetas["model_a"].keys(): future = executor.submit( simple_merge_key, progress, + task, key, thetas, weight_matcher, @@ -214,17 +213,15 @@ def simple_merge( for res in futures: res.result() - log_vram("after stage 1") - - for key in tqdm(thetas["model_b"].keys(), desc="stage 2"): - if KEY_POSITION_IDS in key: - continue - if "model" in key and key not in thetas["model_a"].keys(): - thetas["model_a"].update({key: thetas["model_b"][key]}) - if precision == "fp16": - thetas["model_a"].update({key: thetas["model_a"][key].half()}) - - log_vram("after stage 2") + if len(thetas["model_b"]) > 0: + log.debug(f'Merge update thetas: keys={len(thetas["model_b"])}') + for key in thetas["model_b"].keys(): + if KEY_POSITION_IDS in key: + continue + if "model" in key and key not in thetas["model_a"].keys(): + thetas["model_a"].update({key: thetas["model_b"][key]}) + if precision == "fp16": + thetas["model_a"].update({key: thetas["model_a"][key].half()}) return fix_clip(thetas["model_a"]) @@ -240,13 +237,12 @@ def rebasin_merge( work_device: torch.device = None, threads: int = 1, ): - # WARNING: not sure how this does when 3 models are involved... - + # not sure how this does when 3 models are involved... model_a = thetas["model_a"].clone() perm_spec = sdunet_permutation_spec() for it in range(iterations): - log_vram(f"Rebasin iteration {it}") + log_vram(f"rebasin: iteration={it}") weight_matcher.set_it(it) # normal block merge we already know and love @@ -261,8 +257,6 @@ def rebasin_merge( threads, ) - log_vram("simple merge done") - # find permutations perm_1, y = weight_matching( perm_spec, @@ -273,13 +267,8 @@ def rebasin_merge( usefp16=precision == "fp16", device=device, ) - - log_vram("weight matching #1 done") - thetas["model_a"] = apply_permutation(perm_spec, perm_1, thetas["model_a"]) - log_vram("apply perm 1 done") - perm_2, z = weight_matching( perm_spec, thetas["model_b"], @@ -290,8 +279,6 @@ def rebasin_merge( device=device, ) - log_vram("weight matching #2 done") - new_alpha = torch.nn.functional.normalize( torch.sigmoid(torch.Tensor([y, z])), p=1, dim=0 ).tolist()[0] @@ -299,8 +286,6 @@ def rebasin_merge( perm_spec, perm_2, thetas["model_a"], new_alpha ) - log_vram("model a updated") - if weights_clip: clip_thetas = thetas.copy() clip_thetas["model_a"] = model_a @@ -309,12 +294,11 @@ def rebasin_merge( return thetas["model_a"] -def simple_merge_key(progress, key, thetas, *args, **kwargs): +def simple_merge_key(progress, task, key, thetas, *args, **kwargs): with merge_key_context(key, thetas, *args, **kwargs) as result: if result is not None: thetas["model_a"].update({key: result.detach().clone()}) - - progress.update() + progress.update(task, advance=1) def merge_key( # pylint: disable=inconsistent-return-statements @@ -407,7 +391,7 @@ def get_merge_method_args( def save_model(model, output_file, file_format) -> None: - log.info(f"Saving {output_file}") + log.info(f"Merge saving: model='{output_file}'") if file_format == "safetensors": safetensors.torch.save_file( model if type(model) == dict else model.to_dict(), diff --git a/modules/merging/merge_rebasin.py b/modules/merging/merge_rebasin.py index 2606a52f9..0feff986f 100644 --- a/modules/merging/merge_rebasin.py +++ b/modules/merging/merge_rebasin.py @@ -2228,7 +2228,7 @@ def inner_matching( if newL - oldL != 0: linear_sum += abs((newL - oldL).item()) number += 1 - log.info(f" permutation {p}: {newL - oldL}") + log.debug(f"Merge Rebasin permutation: {p}={newL-oldL}") progress = progress or newL > oldL + 1e-12 @@ -2262,12 +2262,11 @@ def weight_matching( number = 0 special_layers = ["P_bg324", "P_bg358", "P_bg337"] - for _ in range(max_iter): + for _i in range(max_iter): progress = False shuffle(special_layers) for p in special_layers: n = perm_sizes[p] - linear_sum, number, perm, progress = inner_matching( n, ps, @@ -2281,6 +2280,7 @@ def weight_matching( perm, device, ) + progress = True if not progress: break diff --git a/modules/sd_models.py b/modules/sd_models.py index ab1188c60..1a18a249e 100644 --- a/modules/sd_models.py +++ b/modules/sd_models.py @@ -387,7 +387,7 @@ def read_state_dict(checkpoint_file, map_location=None): # pylint: disable=unuse return None try: pl_sd = None - with progress.open(checkpoint_file, 'rb', description=f'[cyan]Loading weights: [yellow]{checkpoint_file}', auto_refresh=True, console=shared.console) as f: + with progress.open(checkpoint_file, 'rb', description=f'[cyan]Loading model: [yellow]{checkpoint_file}', auto_refresh=True, console=shared.console) as f: _, extension = os.path.splitext(checkpoint_file) if extension.lower() == ".ckpt" and shared.opts.sd_disable_ckpt: shared.log.warning(f"Checkpoint loading disabled: {checkpoint_file}") diff --git a/modules/ui_models.py b/modules/ui_models.py index ae28825f1..a6afbce5f 100644 --- a/modules/ui_models.py +++ b/modules/ui_models.py @@ -38,7 +38,7 @@ def create_ui(): create_refresh_button(model_name, sd_models.list_models, lambda: {"choices": sd_models.checkpoint_tiles()}, "refresh_checkpoint_Z") with gr.Row(): - custom_name = gr.Textbox(label="New model name") + custom_name = gr.Textbox(label="Output model name") with gr.Row(): precision = gr.Radio(choices=["fp32", "fp16", "bf16"], value="fp16", label="Model precision") m_type = gr.Radio(choices=["disabled", "no-ema", "ema-only"], value="disabled", @@ -149,10 +149,14 @@ def create_ui(): beta_out_blocks = gr.Textbox(value=None, label="Out Block", interactive=True, scale=15, visible=False) with FormRow(): - weights_clip = gr.Checkbox(label="Weights Clip") - prune = gr.Checkbox(label="Prune", value=True, visible=False) - re_basin = gr.Checkbox(label="ReBasin") + overwrite = gr.Checkbox(label="Overwrite model") with FormRow(): + save_metadata = gr.Checkbox(value=True, label="Save metadata") + with FormRow(): + weights_clip = gr.Checkbox(label="Weights clip") + prune = gr.Checkbox(label="Prune", value=True, visible=False) + with FormRow(): + re_basin = gr.Checkbox(label="ReBasin") re_basin_iterations = gr.Slider(minimum=0, maximum=25, step=1, label='Number of ReBasin Iterations', value=None, visible=False) @@ -170,55 +174,62 @@ def create_ui(): create_refresh_button(bake_in_vae, sd_vae.refresh_vae_list, lambda: {"choices": ["None"] + list(sd_vae.vae_dict)}, "modelmerger_refresh_bake_in_vae") - with FormRow(): - save_metadata = gr.Checkbox(value=True, label="Save metadata") with gr.Row(): modelmerger_merge = gr.Button(value="Merge", variant='primary') - def modelmerger(dummy_component, - primary_model_name, - secondary_model_name, - tertiary_model_name, - merge_mode, - alpha, - beta, - alpha_preset, - alpha_preset_lambda, - alpha_base, - alpha_in_blocks, - alpha_mid_block, - alpha_out_blocks, - beta_preset, - beta_preset_lambda, - beta_base, - beta_in_blocks, - beta_mid_block, - beta_out_blocks, - precision, - custom_name, - checkpoint_format, - save_metadata, - weights_clip, - prune, - re_basin, - re_basin_iterations, - device, - unload, - bake_in_vae): + def modelmerger(dummy_component, # dummy function just to get argspec later + overwrite, # pylint: disable=unused-argument + primary_model_name, # pylint: disable=unused-argument + secondary_model_name, # pylint: disable=unused-argument + tertiary_model_name, # pylint: disable=unused-argument + merge_mode, # pylint: disable=unused-argument + alpha, # pylint: disable=unused-argument + beta, # pylint: disable=unused-argument + alpha_preset, # pylint: disable=unused-argument + alpha_preset_lambda, # pylint: disable=unused-argument + alpha_base, # pylint: disable=unused-argument + alpha_in_blocks, # pylint: disable=unused-argument + alpha_mid_block, # pylint: disable=unused-argument + alpha_out_blocks, # pylint: disable=unused-argument + beta_preset, # pylint: disable=unused-argument + beta_preset_lambda, # pylint: disable=unused-argument + beta_base, # pylint: disable=unused-argument + beta_in_blocks, # pylint: disable=unused-argument + beta_mid_block, # pylint: disable=unused-argument + beta_out_blocks, # pylint: disable=unused-argument + precision, # pylint: disable=unused-argument + custom_name, # pylint: disable=unused-argument + checkpoint_format, # pylint: disable=unused-argument + save_metadata, # pylint: disable=unused-argument + weights_clip, # pylint: disable=unused-argument + prune, # pylint: disable=unused-argument + re_basin, # pylint: disable=unused-argument + re_basin_iterations, # pylint: disable=unused-argument + device, # pylint: disable=unused-argument + unload, # pylint: disable=unused-argument + bake_in_vae): # pylint: disable=unused-argument kwargs = {} for x in inspect.getfullargspec(modelmerger)[0]: kwargs[x] = locals()[x] for key in list(kwargs.keys()): if kwargs[key] in [None, "None", "", 0, []]: del kwargs[key] - try: - results = extras.run_modelmerger(dummy_component, **kwargs) - except Exception as e: - modules.errors.display(e, 'model merge') - sd_models.list_models() # to remove the potentially missing models from the list - return [*[gr.Dropdown.update(choices=sd_models.checkpoint_tiles()) for _ in range(4)], - f"Error merging checkpoints: {e}"] - return results + del kwargs['dummy_component'] + if kwargs.get("custom_name", None) is None: + log.error('Merge: no output model specified') + return [*[gr.Dropdown.update(choices=sd_models.checkpoint_tiles()) for _ in range(4)], "No output model specified"] + elif kwargs.get("primary_model_name", None) is None or kwargs.get("secondary_model_name", None) is None: + log.error('Merge: no models selected') + return [*[gr.Dropdown.update(choices=sd_models.checkpoint_tiles()) for _ in range(4)], "No models selected"] + else: + log.debug(f'Merge start: {kwargs}') + try: + results = extras.run_modelmerger(dummy_component, **kwargs) + except Exception as e: + modules.errors.display(e, 'Merge') + sd_models.list_models() # to remove the potentially missing models from the list + return [*[gr.Dropdown.update(choices=sd_models.checkpoint_tiles()) for _ in range(4)], f"Error merging checkpoints: {e}"] + return results def tertiary(mode): if mode in TRIPLE_METHODS: @@ -262,7 +273,7 @@ def create_ui(): preset = interpolate(presets, ratio) else: preset = presets[0] - preset = ['%.3f' % x if int(x) != x else str(x) for x in preset] + preset = ['%.3f' % x if int(x) != x else str(x) for x in preset] # pylint: disable=consider-using-f-string preset = [preset[0], ",".join(preset[1:13]), preset[13], ",".join(preset[14:])] return [gr.update(value=x) for x in preset] + [gr.update(selected=2)] @@ -291,6 +302,7 @@ def create_ui(): _js='modelmerger', inputs=[ dummy_component, + overwrite, primary_model_name, secondary_model_name, tertiary_model_name, From d07765852490bf2686cd0860915f46ef2e15a58d Mon Sep 17 00:00:00 2001 From: AI-Casanova <54461896+AI-Casanova@users.noreply.github.com> Date: Mon, 20 Nov 2023 14:34:15 -0600 Subject: [PATCH 73/84] Fix rebasin --- modules/merging/merge_rebasin.py | 81 +------------------------------- 1 file changed, 2 insertions(+), 79 deletions(-) diff --git a/modules/merging/merge_rebasin.py b/modules/merging/merge_rebasin.py index 0feff986f..dd8d28b44 100644 --- a/modules/merging/merge_rebasin.py +++ b/modules/merging/merge_rebasin.py @@ -67,7 +67,7 @@ def sdunet_permutation_spec() -> PermutationSpec: **conv(f"{name}.out_layers.3", f"P_{name}_inner4", p_out), } - # Text Encoder blocks + # VAE blocks - Unused easyblock2 = lambda name, p: { # pylint: disable=unnecessary-lambda-assignment **norm(f"{name}.norm1", p), **conv(f"{name}.conv1", p, f"P_{name}_inner"), @@ -1510,83 +1510,6 @@ def sdunet_permutation_spec() -> PermutationSpec: ), **norm("model.diffusion_model.out.0", "P_bg324"), **conv("model.diffusion_model.out.2", "P_bg325", "P_bg326"), - # Text Encoder - # encoder down - **conv("first_stage_model.encoder.conv_in", "P_bg327", "P_bg328"), - **easyblock2("first_stage_model.encoder.down.0.block.0", "P_bg328"), - **easyblock2("first_stage_model.encoder.down.0.block.1", "P_bg328"), - **conv( - "first_stage_model.encoder.down.0.downsample.conv", "P_bg328", "P_bg329" - ), - **shortcutblock( - "first_stage_model.encoder.down.1.block.0", "P_bg330", "P_bg331" - ), - **easyblock2("first_stage_model.encoder.down.1.block.1", "P_bg331"), - **conv( - "first_stage_model.encoder.down.1.downsample.conv", "P_bg331", "P_bg332" - ), - **shortcutblock( - "first_stage_model.encoder.down.2.block.0", "P_bg332", "P_bg333" - ), - **easyblock2("first_stage_model.encoder.down.2.block.1", "P_bg333"), - **conv( - "first_stage_model.encoder.down.2.downsample.conv", "P_bg333", "P_bg334" - ), - **easyblock2("first_stage_model.encoder.down.3.block.0", "P_bg334"), - **easyblock2("first_stage_model.encoder.down.3.block.1", "P_bg334"), - # encoder mid-block - **easyblock2("first_stage_model.encoder.mid.block_1", "P_bg334"), - **norm("first_stage_model.encoder.mid.attn_1.norm", "P_bg334"), - **conv("first_stage_model.encoder.mid.attn_1.q", "P_bg334", "P_bg335"), - **conv("first_stage_model.encoder.mid.attn_1.k", "P_bg334", "P_bg335"), - **conv("first_stage_model.encoder.mid.attn_1.v", "P_bg334", "P_bg335"), - **conv( - "first_stage_model.encoder.mid.attn_1.proj_out", "P_bg335", "P_bg336" - ), - **easyblock2("first_stage_model.encoder.mid.block_2", "P_bg336"), - **norm("first_stage_model.encoder.norm_out", "P_bg337"), - **conv("first_stage_model.encoder.conv_out", "P_bg338", "P_bg339"), - **conv("first_stage_model.decoder.conv_in", "P_bg340", "P_bg341"), - # decoder mid-block - **easyblock2("first_stage_model.decoder.mid.block_1", "P_bg342"), - **norm("first_stage_model.decoder.mid.attn_1.norm", "P_bg342"), - **conv("first_stage_model.decoder.mid.attn_1.q", "P_bg342", "P_bg343"), - **conv("first_stage_model.decoder.mid.attn_1.k", "P_bg342", "P_bg343"), - **conv("first_stage_model.decoder.mid.attn_1.v", "P_bg342", "P_bg343"), - **conv( - "first_stage_model.decoder.mid.attn_1.proj_out", "P_bg343", "P_bg344" - ), - **easyblock2("first_stage_model.decoder.mid.block_2", "P_bg345"), - # decoder up - **shortcutblock( - "first_stage_model.decoder.up.0.block.0", "P_bg346", "P_bg347" - ), - **easyblock2("first_stage_model.decoder.up.0.block.1", "P_bg348"), - **easyblock2("first_stage_model.decoder.up.0.block.2", "P_bg349"), - **shortcutblock( - "first_stage_model.decoder.up.1.block.0", "P_bg350", "P_bg351" - ), - **easyblock2("first_stage_model.decoder.up.1.block.1", "P_bg352"), - **easyblock2("first_stage_model.decoder.up.1.block.2", "P_bg353"), - **conv( - "first_stage_model.decoder.up.1.upsample.conv", "P_bg353", "P_bg354" - ), - **easyblock2("first_stage_model.decoder.up.2.block.0", "P_bg355"), - **easyblock2("first_stage_model.decoder.up.2.block.1", "P_bg355"), - **easyblock2("first_stage_model.decoder.up.2.block.2", "P_bg355"), - **conv( - "first_stage_model.decoder.up.2.upsample.conv", "P_bg355", "P_bg356" - ), - **easyblock2("first_stage_model.decoder.up.3.block.0", "P_bg356"), - **easyblock2("first_stage_model.decoder.up.3.block.1", "P_bg356"), - **easyblock2("first_stage_model.decoder.up.3.block.2", "P_bg356"), - **conv( - "first_stage_model.decoder.up.3.upsample.conv", "P_bg356", "P_bg357" - ), - **norm("first_stage_model.decoder.norm_out", "P_bg358"), - **conv("first_stage_model.decoder.conv_out", "P_bg359", "P_bg360"), - **conv("first_stage_model.quant_conv", "P_bg361", "P_bg362"), - **conv("first_stage_model.post_quant_conv", "P_bg363", "P_bg364"), **skip( "cond_stage_model.transformer.text_model.embeddings.position_ids", None, @@ -2261,7 +2184,7 @@ def weight_matching( linear_sum = 0 number = 0 - special_layers = ["P_bg324", "P_bg358", "P_bg337"] + special_layers = ["P_bg324"] for _i in range(max_iter): progress = False shuffle(special_layers) From e6a8a43bdc1a3d782707b0004eec8183f714b903 Mon Sep 17 00:00:00 2001 From: Vladimir Mandic Date: Mon, 20 Nov 2023 16:49:46 -0500 Subject: [PATCH 74/84] fix controlnet compatibility --- modules/sd_models.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/modules/sd_models.py b/modules/sd_models.py index 1a18a249e..427a94d7d 100644 --- a/modules/sd_models.py +++ b/modules/sd_models.py @@ -551,6 +551,8 @@ class ModelData: self.sd_model = reload_model_weights(op='model') if self.sd_model is not None: self.sd_model.is_sdxl = False # a1111 compatibility item + self.sd_model.is_sd2 = False # a1111 compatibility item + self.sd_model.is_sd1 = True # a1111 compatibility item self.initial = False except Exception as e: shared.log.error("Failed to load stable diffusion model") From 1793c2e1163932f0517d41faa1c2d492e45361a1 Mon Sep 17 00:00:00 2001 From: Disty0 Date: Tue, 21 Nov 2023 14:22:55 +0300 Subject: [PATCH 75/84] OpenVINO fix LoRa and Update to Torch 2.1.1 --- extensions-builtin/Lora/lora_patches.py | 7 +++--- extensions-builtin/Lora/networks.py | 10 ++++---- installer.py | 31 +------------------------ modules/intel/openvino/__init__.py | 2 +- 4 files changed, 10 insertions(+), 40 deletions(-) diff --git a/extensions-builtin/Lora/lora_patches.py b/extensions-builtin/Lora/lora_patches.py index 7eba99e18..7085d251b 100644 --- a/extensions-builtin/Lora/lora_patches.py +++ b/extensions-builtin/Lora/lora_patches.py @@ -1,7 +1,6 @@ import torch import networks -from modules import patches - +from modules import patches, shared class LoraPatches: def __init__(self): @@ -18,7 +17,7 @@ class LoraPatches: self.MultiheadAttention_load_state_dict = None def apply(self): - if self.active: + if self.active or (shared.opts.cuda_compile and shared.opts.cuda_compile_backend == "openvino_fx"): # OpenVINO only works with Diffusers LoRa loading return self.Linear_forward = patches.patch(__name__, torch.nn.Linear, 'forward', networks.network_Linear_forward) self.Linear_load_state_dict = patches.patch(__name__, torch.nn.Linear, '_load_from_state_dict', networks.network_Linear_load_state_dict) @@ -36,7 +35,7 @@ class LoraPatches: self.active = True def undo(self): - if not self.active: + if not self.active or (shared.opts.cuda_compile and shared.opts.cuda_compile_backend == "openvino_fx"): # OpenVINO only works with Diffusers LoRa loading return self.Linear_forward = patches.undo(__name__, torch.nn.Linear, 'forward') # pylint: disable=E1128 self.Linear_load_state_dict = patches.undo(__name__, torch.nn.Linear, '_load_from_state_dict') # pylint: disable=E1128 diff --git a/extensions-builtin/Lora/networks.py b/extensions-builtin/Lora/networks.py index 6b638fcda..b01c75c7a 100644 --- a/extensions-builtin/Lora/networks.py +++ b/extensions-builtin/Lora/networks.py @@ -74,7 +74,7 @@ def assign_network_names_to_compvis_modules(sd_model): sd_model.network_layer_mapping = network_layer_mapping -def load_diffusers(name, network_on_disk): +def load_diffusers(name, network_on_disk, lora_scale=1.0): t0 = time.time() cached = lora_cache.get(name, None) # if debug: @@ -84,6 +84,8 @@ def load_diffusers(name, network_on_disk): if shared.backend != shared.Backend.DIFFUSERS: return None shared.sd_model.load_lora_weights(network_on_disk.filename) + if shared.opts.cuda_compile and shared.opts.cuda_compile_backend == "openvino_fx": + shared.sd_model.fuse_lora(lora_scale=lora_scale) net = network.Network(name, network_on_disk) net.mtime = os.path.getmtime(network_on_disk.filename) lora_cache[name] = net @@ -152,9 +154,6 @@ def load_networks(names, te_multipliers=None, unet_multipliers=None, dyn_dims=No recompile_model = True shared.compiled_model_state.lora_model = [] if recompile_model: - if not shared.opts.openvino_disable_model_caching: - shared.log.warning("LoRa: Disabling OpenVINO model caching") - shared.opts.openvino_disable_model_caching = True shared.compiled_model_state.lora_compile = True sd_models.unload_model_weights(op='model') shared.opts.cuda_compile = False @@ -171,7 +170,8 @@ def load_networks(names, te_multipliers=None, unet_multipliers=None, dyn_dims=No or getattr(network_on_disk, 'shorthash', None) == 'aaebf6360f7d' # lcm sd15 or getattr(network_on_disk, 'shorthash', None) == '3d18b05e4f56' # lcm sdxl or (shared.opts.cuda_compile and shared.opts.cuda_compile_backend == "openvino_fx")): - net = load_diffusers(name, network_on_disk) + # OpenVINO only works with Diffusers LoRa loading. + net = load_diffusers(name, network_on_disk, lora_scale=te_multipliers[i] if te_multipliers else 1.0) else: net = load_network(name, network_on_disk) except Exception as e: diff --git a/installer.py b/installer.py index 7fe48a4ef..d81f9a141 100644 --- a/installer.py +++ b/installer.py @@ -446,36 +446,7 @@ def check_torch(): install('onnxruntime-openvino', 'onnxruntime-openvino', ignore=True) # TODO numpy version conflicts with tensorflow and doesn't support Python 3.11 elif allow_openvino and args.use_openvino: log.info('Using OpenVINO') - if "linux" in sys.platform: - if sys.version_info[1] == 11: - pytorch_pip = 'https://github.com/Disty0/automatic/releases/download/openvino_pre_release_pytorch/torch-2.1.0.dev20230820+cpu-cp311-cp311-linux_x86_64.whl' - torchvision_pip = 'https://github.com/Disty0/automatic/releases/download/openvino_pre_release_pytorch/torchvision-0.16.0.dev20230820+cpu-cp311-cp311-linux_x86_64.whl' - elif sys.version_info[1] == 10: - pytorch_pip = 'https://github.com/Disty0/automatic/releases/download/openvino_pre_release_pytorch/torch-2.1.0.dev20230820+cpu-cp310-cp310-linux_x86_64.whl' - torchvision_pip = 'https://github.com/Disty0/automatic/releases/download/openvino_pre_release_pytorch/torchvision-0.16.0.dev20230820+cpu-cp310-cp310-linux_x86_64.whl' - elif sys.version_info[1] == 8: - pytorch_pip = 'https://github.com/Disty0/automatic/releases/download/openvino_pre_release_pytorch/torch-2.1.0.dev20230820+cpu-cp38-cp38-linux_x86_64.whl' - torchvision_pip = 'https://github.com/Disty0/automatic/releases/download/openvino_pre_release_pytorch/torchvision-0.16.0.dev20230820+cpu-cp38-cp38-linux_x86_64.whl' - else: - pytorch_pip = 'torch==2.1.0' - torchvision_pip = 'torchvision==0.16.0 --index-url https://download.pytorch.org/whl/cpu' - elif sys.platform == 'darwin': - pytorch_pip = 'torch==2.1.0' - torchvision_pip = 'torchvision==0.16.0 --index-url https://download.pytorch.org/whl/cpu' - else: - if sys.version_info[1] == 11: - pytorch_pip = 'https://github.com/Disty0/automatic/releases/download/openvino_pre_release_pytorch/torch-2.1.0.dev20230820+cpu-cp311-cp311-win_amd64.whl' - torchvision_pip = 'https://github.com/Disty0/automatic/releases/download/openvino_pre_release_pytorch/torchvision-0.16.0.dev20230820+cpu-cp311-cp311-win_amd64.whl' - elif sys.version_info[1] == 10: - pytorch_pip = 'https://github.com/Disty0/automatic/releases/download/openvino_pre_release_pytorch/torch-2.1.0.dev20230820+cpu-cp310-cp310-win_amd64.whl' - torchvision_pip = 'https://github.com/Disty0/automatic/releases/download/openvino_pre_release_pytorch/torchvision-0.16.0.dev20230820+cpu-cp310-cp310-win_amd64.whl' - elif sys.version_info[1] == 8: - pytorch_pip = 'https://github.com/Disty0/automatic/releases/download/openvino_pre_release_pytorch/torch-2.1.0.dev20230820+cpu-cp38-cp38-win_amd64.whl' - torchvision_pip = 'https://github.com/Disty0/automatic/releases/download/openvino_pre_release_pytorch/torchvision-0.16.0.dev20230820+cpu-cp38-cp38-win_amd64.whl' - else: - pytorch_pip = 'torch==2.1.0' - torchvision_pip = 'torchvision==0.16.0 --index-url https://download.pytorch.org/whl/cpu' - torch_command = os.environ.get('TORCH_COMMAND', f'{pytorch_pip} {torchvision_pip}') + torch_command = os.environ.get('TORCH_COMMAND', 'torch==2.1.1 torchvision==0.16.1 --index-url https://download.pytorch.org/whl/cpu') else: machine = platform.machine() if sys.platform == 'darwin': diff --git a/modules/intel/openvino/__init__.py b/modules/intel/openvino/__init__.py index e1bafb0a7..500bfd73b 100644 --- a/modules/intel/openvino/__init__.py +++ b/modules/intel/openvino/__init__.py @@ -194,7 +194,7 @@ def openvino_compile(gm: GraphModule, *args, model_hash_str: str = None, file_na for input_data in args: if isinstance(input_data, torch.SymInt): input_types.append(torch.SymInt) - input_shapes.append([1]) + input_shapes.append(1) else: input_types.append(input_data.type()) input_shapes.append(input_data.size()) From bd141bbfeb6ea70ed237606f2fd0a48a4ff37c63 Mon Sep 17 00:00:00 2001 From: Disty0 Date: Tue, 21 Nov 2023 16:47:35 +0300 Subject: [PATCH 76/84] IPEX decrease Torch GC Threshold to 80 --- extensions-builtin/Lora/lora_patches.py | 1 + modules/devices.py | 2 +- modules/shared.py | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/extensions-builtin/Lora/lora_patches.py b/extensions-builtin/Lora/lora_patches.py index 7085d251b..12986e8f9 100644 --- a/extensions-builtin/Lora/lora_patches.py +++ b/extensions-builtin/Lora/lora_patches.py @@ -2,6 +2,7 @@ import torch import networks from modules import patches, shared + class LoraPatches: def __init__(self): self.active = False diff --git a/modules/devices.py b/modules/devices.py index 1102b9a74..78a20c4e6 100644 --- a/modules/devices.py +++ b/modules/devices.py @@ -134,7 +134,7 @@ def torch_gc(force=False): if oom > previous_oom: previous_oom = oom log.warning(f'GPU out-of-memory error: {mem}') - if used > shared.opts.torch_gc_threshold: + if used >= shared.opts.torch_gc_threshold: log.info(f'GPU high memory utilization: {used}% {mem}') force = True if not force: diff --git a/modules/shared.py b/modules/shared.py index 259b04e34..04a03d9b4 100644 --- a/modules/shared.py +++ b/modules/shared.py @@ -300,7 +300,7 @@ options_templates.update(options_section(('cuda', "Compute Settings"), { "other_sep": OptionInfo("

Execution precision

", "", gr.HTML), "opt_channelslast": OptionInfo(False, "Use channels last as torch memory format "), "cudnn_benchmark": OptionInfo(False, "Enable full-depth cuDNN benchmark feature"), - "torch_gc_threshold": OptionInfo(90, "VRAM usage threshold before running Torch GC to clear up VRAM", gr.Slider, {"minimum": 0, "maximum": 100, "step": 1}), + "torch_gc_threshold": OptionInfo(80 if devices.backend == "ipex" else 90, "VRAM usage threshold before running Torch GC to clear up VRAM", gr.Slider, {"minimum": 0, "maximum": 100, "step": 1}), "cuda_compile_sep": OptionInfo("

Model Compile

", "", gr.HTML), "cuda_compile": OptionInfo(True if cmd_opts.use_openvino else False, "Compile UNet"), From 15503a7e0c14afe89c626788a6d4b0d27b514414 Mon Sep 17 00:00:00 2001 From: Vladimir Mandic Date: Tue, 21 Nov 2023 12:25:15 -0500 Subject: [PATCH 77/84] add experimental model update --- .github/ISSUE_TEMPLATE/bug_report.yml | 39 ++- CHANGELOG.md | 21 +- extensions-builtin/sd-webui-agent-scheduler | 2 +- extensions-builtin/sd-webui-controlnet | 2 +- modules/modelloader.py | 7 +- modules/ui_extra_networks.py | 39 +-- modules/ui_models.py | 303 ++++++++++---------- 7 files changed, 223 insertions(+), 190 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml index 023fc1005..fc5783a01 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yml +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -38,18 +38,18 @@ body: - type: markdown attributes: value: | - If issue is setup, installation or startup related, please check `sdnext.log` before reporting - - type: markdown - attributes: - value: | - If you have additional extensions installed, try to reproduce the issue with user extensions disabled - And if the issue is with compatibility with specific extension, mark it as such when creating the issue - Try running with `--safe` command line flag with disables loading of user-installed extensions - - type: markdown - attributes: - value: | - If possible update to latest version before reporting the issue as older versions cannot be properly supported - And search existing **issues** and **discussions** before creating a new one + Please follow these guidelines when creating an issue: + - If possible update to latest version before reporting the issue as older versions cannot be properly supported + And search existing **issues** and **discussions** before creating a new one + - If issue cannot be clearly seen in the provided log, run SD.Next with debug logging enabled by adding `--debug` to your command line parameters + - If issue is setup, installation or startup related, please check `sdnext.log` before reporting + And if possible, perform reinstallation of required dependencies by running SD.Next with `--reinstall` command line flag + - If issue is after recent update of SD.Next, try to reproduce it using clean installation to avoid issues due to old configuration + - If you have additional extensions installed, try to reproduce the issue with user extensions disabled + And if the issue is with compatibility with specific extension, mark it as such when creating the issue + Try running with `--safe` command line flag with disables loading of user-installed extensions + - If issue is in functionality marked as *experimental* or relates to *dev* branch, reach out on Discord before creating an issue + To see which issues are new/updated/experimental, check [CHANGELOG](https://github.com/vladmandic/automatic/blob/master/CHANGELOG.md) - type: textarea id: logs attributes: @@ -72,6 +72,17 @@ body: default: 0 validations: required: true + - type: dropdown + id: branch + attributes: + label: Branch + description: What is the branch you're using? + options: + - Master + - Dev + default: 0 + validations: + required: true - type: dropdown id: model attributes: @@ -79,7 +90,11 @@ body: description: What is the model type you're using? options: - SD 1.5 + - SD 2.1 - SD-XL + - LCM + - PixArt + - SSD - Kandinsky - Other default: 0 diff --git a/CHANGELOG.md b/CHANGELOG.md index e4f6ca5bf..f9a69c98b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,6 @@ # Change Log for SD.Next -## Update for 2023-11-14 +## Update for 2023-11-21 - **Diffusers** - **LCM** support for any *SD 1.5* or *SD-XL* model! @@ -27,13 +27,18 @@ Change-in-behavior: new line in prompt now means *BREAK* - Add alternative Lora loading algorithm, triggered if `SD_LORA_DIFFUSERS` is set - Update to `diffusers==0.23.0` -- **Model merge** - - completely redesigned, now based on best-of-class `meh` by @s1dlx - and heavily modified for additional functionality and fully integrated by @AI-Casanova (thanks!) - - merge SD or SD-XL models using *simple merge* (12 methods), - using one of *presets* (20 built-in presets) or custom block merge values - - merge with ReBasin permuatations and/or clipping protection - - fully multithreaded for fastest merge possible +- **Models** + - **Model merge** + - completely redesigned, now based on best-of-class `meh` by @s1dlx + and heavily modified for additional functionality and fully integrated by @AI-Casanova (thanks!) + - merge SD or SD-XL models using *simple merge* (12 methods), + using one of *presets* (20 built-in presets) or custom block merge values + - merge with ReBasin permuatations and/or clipping protection + - fully multithreaded for fastest merge possible + - **Model update** *(experimental)* + - under UI -> Models - Update + - scan existing models for updated metadata on CivitAI and + provide download functionality for models with available - **Extra networks** - Use multi-threading for 5x load speedup - Better Lora trigger words support diff --git a/extensions-builtin/sd-webui-agent-scheduler b/extensions-builtin/sd-webui-agent-scheduler index 7a03f4e67..a8d527b26 160000 --- a/extensions-builtin/sd-webui-agent-scheduler +++ b/extensions-builtin/sd-webui-agent-scheduler @@ -1 +1 @@ -Subproject commit 7a03f4e6786b00b99607a13b362961dd80d6cacf +Subproject commit a8d527b269358595bd7f9c839f266b1db5bea468 diff --git a/extensions-builtin/sd-webui-controlnet b/extensions-builtin/sd-webui-controlnet index 0efcf8c99..aa4747ab5 160000 --- a/extensions-builtin/sd-webui-controlnet +++ b/extensions-builtin/sd-webui-controlnet @@ -1 +1 @@ -Subproject commit 0efcf8c99345a67b62b6f54683bc046a7627698b +Subproject commit aa4747ab5f949b5d7aa1ccae238571ddca6ef33f diff --git a/modules/modelloader.py b/modules/modelloader.py index d7bbe5f97..4195e6905 100644 --- a/modules/modelloader.py +++ b/modules/modelloader.py @@ -58,13 +58,11 @@ def walk(top, onerror:callable=None): def download_civit_meta(model_path: str, model_id): fn = os.path.splitext(model_path)[0] + '.json' - if os.path.exists(fn): - return '' url = f'https://civitai.com/api/v1/models/{model_id}' r = shared.req(url) if r.status_code == 200: try: - shared.writefile(r.json(), fn, silent=True) + shared.writefile(r.json(), filename=fn, mode='w', silent=True) msg = f'CivitAI download: id={model_id} url={url} file={fn}' shared.log.info(msg) return msg @@ -72,7 +70,8 @@ def download_civit_meta(model_path: str, model_id): msg = f'CivitAI download error: id={model_id} url={url} file={fn} {e}' shared.log.error(msg) return msg - return '' + return f'CivitAI download error: id={model_id} url={url} code={r.status_code}' + def download_civit_preview(model_path: str, preview_url: str): ext = os.path.splitext(preview_url)[1] diff --git a/modules/ui_extra_networks.py b/modules/ui_extra_networks.py index 5fa0e1aa6..9727b8752 100644 --- a/modules/ui_extra_networks.py +++ b/modules/ui_extra_networks.py @@ -60,17 +60,6 @@ def listdir(path): return dir_cache[path][1] -def register_page(page): - # registers extra networks page for the UI; recommend doing it in on_before_ui() callback for extensions - debug(f'EN register-page: {page}') - shared.extra_networks.append(page) - allowed_dirs.clear() - for pg in shared.extra_networks: - for folder in pg.allowed_directories_for_previews(): - if folder not in allowed_dirs: - allowed_dirs.append(os.path.abspath(folder)) - - def init_api(app): def fetch_file(filename: str = ""): @@ -390,6 +379,17 @@ def initialize(): shared.extra_networks.clear() +def register_page(page: ExtraNetworksPage): + # registers extra networks page for the UI; recommend doing it in on_before_ui() callback for extensions + debug(f'EN register-page: {page}') + shared.extra_networks.append(page) + allowed_dirs.clear() + for pg in shared.extra_networks: + for folder in pg.allowed_directories_for_previews(): + if folder not in allowed_dirs: + allowed_dirs.append(os.path.abspath(folder)) + + def register_pages(): from modules.ui_extra_networks_textual_inversion import ExtraNetworksPageTextualInversion from modules.ui_extra_networks_hypernets import ExtraNetworksPageHypernetworks @@ -403,18 +403,25 @@ def register_pages(): register_page(ExtraNetworksPageVAEs()) -def get_pages(): +def get_pages(title=None): pages = [] if 'All' in shared.opts.extra_networks: pages = shared.extra_networks else: titles = [page.title for page in shared.extra_networks] - for page in shared.opts.extra_networks: + if title is None: + for page in shared.opts.extra_networks: + try: + idx = titles.index(page) + pages.append(shared.extra_networks[idx]) + except ValueError: + continue + else: try: - idx = titles.index(page) + idx = titles.index(title) + pages.append(shared.extra_networks[idx]) except ValueError: - continue - pages.append(shared.extra_networks[idx]) + pass return pages diff --git a/modules/ui_models.py b/modules/ui_models.py index a6afbce5f..ffaf66137 100644 --- a/modules/ui_models.py +++ b/modules/ui_models.py @@ -7,7 +7,7 @@ from modules import sd_models, sd_vae, extras from modules.ui_components import FormRow, ToolButton from modules.ui_common import create_refresh_button from modules.call_queue import wrap_gradio_gpu_call -from modules.shared import opts, log, req +from modules.shared import opts, log, req, readfile import modules.errors import modules.hashes from modules.merging import merge_methods @@ -35,17 +35,14 @@ def create_ui(): with gr.Tab(label="Convert"): with gr.Row(): model_name = gr.Dropdown(sd_models.checkpoint_tiles(), label="Original model") - create_refresh_button(model_name, sd_models.list_models, - lambda: {"choices": sd_models.checkpoint_tiles()}, "refresh_checkpoint_Z") + create_refresh_button(model_name, sd_models.list_models, lambda: {"choices": sd_models.checkpoint_tiles()}, "refresh_checkpoint_Z") with gr.Row(): custom_name = gr.Textbox(label="Output model name") with gr.Row(): precision = gr.Radio(choices=["fp32", "fp16", "bf16"], value="fp16", label="Model precision") - m_type = gr.Radio(choices=["disabled", "no-ema", "ema-only"], value="disabled", - label="Model pruning methods") + m_type = gr.Radio(choices=["disabled", "no-ema", "ema-only"], value="disabled", label="Model pruning methods") with gr.Row(): - checkpoint_formats = gr.CheckboxGroup(choices=["ckpt", "safetensors"], value=["safetensors"], - label="Model Format") + checkpoint_formats = gr.CheckboxGroup(choices=["ckpt", "safetensors"], value=["safetensors"], label="Model Format") with gr.Row(): show_extra_options = gr.Checkbox(label="Show extra options", value=False) fix_clip = gr.Checkbox(label="Fix clip", value=False) @@ -83,31 +80,21 @@ def create_ui(): with FormRow(): custom_name = gr.Textbox(label="New model name") with FormRow(): - merge_mode = gr.Dropdown(choices=merge_methods.__all__, value="weighted_sum", - label="Interpolation Method") - merge_mode_docs = gr.HTML( - value=getattr(merge_methods, "weighted_sum").__doc__.replace("\n", "
")) + merge_mode = gr.Dropdown(choices=merge_methods.__all__, value="weighted_sum", label="Interpolation Method") + merge_mode_docs = gr.HTML(value=getattr(merge_methods, "weighted_sum").__doc__.replace("\n", "
")) with FormRow(): primary_model_name = gr.Dropdown(sd_model_choices(), label="Primary model", value="None") - create_refresh_button(primary_model_name, sd_models.list_models, - lambda: {"choices": sd_model_choices()}, "refresh_checkpoint_A") - secondary_model_name = gr.Dropdown(sd_model_choices(), label="Secondary model", - value="None") - create_refresh_button(secondary_model_name, sd_models.list_models, - lambda: {"choices": sd_model_choices()}, "refresh_checkpoint_B") - tertiary_model_name = gr.Dropdown(sd_model_choices(), label="Tertiary model", value="None", - visible=False) - tertiary_refresh = create_refresh_button(tertiary_model_name, sd_models.list_models, - lambda: {"choices": sd_model_choices()}, - "refresh_checkpoint_C", visible=False) + create_refresh_button(primary_model_name, sd_models.list_models, lambda: {"choices": sd_model_choices()}, "refresh_checkpoint_A") + secondary_model_name = gr.Dropdown(sd_model_choices(), label="Secondary model", value="None") + create_refresh_button(secondary_model_name, sd_models.list_models, lambda: {"choices": sd_model_choices()}, "refresh_checkpoint_B") + tertiary_model_name = gr.Dropdown(sd_model_choices(), label="Tertiary model", value="None", visible=False) + tertiary_refresh = create_refresh_button(tertiary_model_name, sd_models.list_models, lambda: {"choices": sd_model_choices()}, "refresh_checkpoint_C", visible=False) with FormRow(): with gr.Tabs() as tabs: with gr.TabItem(label="Simple Merge", id=0): with FormRow(): - alpha = gr.Slider(minimum=0.0, maximum=1.0, step=0.05, label='Alpha Ratio', - value=0.5) - beta = gr.Slider(minimum=0.0, maximum=1.0, step=0.05, label='Beta Ratio', - value=None, visible=False) + alpha = gr.Slider(minimum=0.0, maximum=1.0, step=0.05, label='Alpha Ratio', value=0.5) + beta = gr.Slider(minimum=0.0, maximum=1.0, step=0.05, label='Beta Ratio', value=None, visible=False) with gr.TabItem(label="Preset Block Merge", id=1): with FormRow(): sdxl = gr.Checkbox(label="SDXL") @@ -115,18 +102,11 @@ def create_ui(): alpha_preset = gr.Dropdown( choices=["None"] + list(BLOCK_WEIGHTS_PRESETS.keys()), value=None, label="ALPHA Block Weight Preset", multiselect=True, max_choices=2) - alpha_preset_lambda = gr.Slider(minimum=0.0, maximum=1.0, step=0.05, - label='Preset Interpolation Ratio', value=None, - visible=False) + alpha_preset_lambda = gr.Slider(minimum=0.0, maximum=1.0, step=0.05, label='Preset Interpolation Ratio', value=None, visible=False) apply_preset = ToolButton('⇨', visible=True) with FormRow(): - beta_preset = gr.Dropdown(choices=["None"] + list(BLOCK_WEIGHTS_PRESETS.keys()), - value=None, label="BETA Block Weight Preset", - multiselect=True, max_choices=2, interactive=True, - visible=False) - beta_preset_lambda = gr.Slider(minimum=0.0, maximum=1.0, step=0.05, - label='Preset Interpolation Ratio', value=None, - interactive=True, visible=False) + beta_preset = gr.Dropdown(choices=["None"] + list(BLOCK_WEIGHTS_PRESETS.keys()), value=None, label="BETA Block Weight Preset", multiselect=True, max_choices=2, interactive=True, visible=False) + beta_preset_lambda = gr.Slider(minimum=0.0, maximum=1.0, step=0.05, label='Preset Interpolation Ratio', value=None, interactive=True, visible=False) beta_apply_preset = ToolButton('⇨', interactive=True, visible=False) with gr.TabItem(label="Manual Block Merge", id=2): with FormRow(): @@ -134,20 +114,15 @@ def create_ui(): with FormRow(): alpha_base = gr.Textbox(value=None, label="Base", min_width=70, scale=1) alpha_in_blocks = gr.Textbox(value=None, label="In Blocks", scale=15) - alpha_mid_block = gr.Textbox(value=None, label="Mid Block", min_width=80, - scale=1) + alpha_mid_block = gr.Textbox(value=None, label="Mid Block", min_width=80, scale=1) alpha_out_blocks = gr.Textbox(value=None, label="Out Block", scale=15) with FormRow(): beta_label = gr.Markdown("# Beta", visible=False) with FormRow(): - beta_base = gr.Textbox(value=None, label="Base", min_width=70, scale=1, - interactive=True, visible=False) - beta_in_blocks = gr.Textbox(value=None, label="In Blocks", interactive=True, - scale=15, visible=False) - beta_mid_block = gr.Textbox(value=None, label="Mid Block", min_width=80, - interactive=True, scale=1, visible=False) - beta_out_blocks = gr.Textbox(value=None, label="Out Block", interactive=True, - scale=15, visible=False) + beta_base = gr.Textbox(value=None, label="Base", min_width=70, scale=1, interactive=True, visible=False) + beta_in_blocks = gr.Textbox(value=None, label="In Blocks", interactive=True, scale=15, visible=False) + beta_mid_block = gr.Textbox(value=None, label="Mid Block", min_width=80, interactive=True, scale=1, visible=False) + beta_out_blocks = gr.Textbox(value=None, label="Out Block", interactive=True, scale=15, visible=False) with FormRow(): overwrite = gr.Checkbox(label="Overwrite model") with FormRow(): @@ -157,20 +132,16 @@ def create_ui(): prune = gr.Checkbox(label="Prune", value=True, visible=False) with FormRow(): re_basin = gr.Checkbox(label="ReBasin") - re_basin_iterations = gr.Slider(minimum=0, maximum=25, step=1, - label='Number of ReBasin Iterations', value=None, - visible=False) + re_basin_iterations = gr.Slider(minimum=0, maximum=25, step=1, label='Number of ReBasin Iterations', value=None, visible=False) with FormRow(): - checkpoint_format = gr.Radio(choices=["ckpt", "safetensors"], value="safetensors", - visible=False, label="Model format") + checkpoint_format = gr.Radio(choices=["ckpt", "safetensors"], value="safetensors", visible=False, label="Model format") with FormRow(): precision = gr.Radio(choices=["fp16", "fp32"], value="fp16", label="Model precision") with FormRow(): device = gr.Radio(choices=["cpu", "shuffle", "gpu"], value="cpu", label="Merge Device") unload = gr.Checkbox(label="Unload Current Model from VRAM", value=False, visible=False) with FormRow(): - bake_in_vae = gr.Dropdown(choices=["None"] + list(sd_vae.vae_dict), value="None", - interactive=True, label="Replace VAE") + bake_in_vae = gr.Dropdown(choices=["None"] + list(sd_vae.vae_dict), value="None", interactive=True, label="Replace VAE") create_refresh_button(bake_in_vae, sd_vae.refresh_vae_list, lambda: {"choices": ["None"] + list(sd_vae.vae_dict)}, "modelmerger_refresh_bake_in_vae") @@ -288,14 +259,10 @@ def create_ui(): alpha_preset.change(fn=preset_visiblility, inputs=alpha_preset, outputs=alpha_preset_lambda) beta_preset.change(fn=preset_visiblility, inputs=alpha_preset, outputs=beta_preset_lambda) merge_mode.input(fn=tertiary, inputs=merge_mode, outputs=[tertiary_model_name, tertiary_refresh]) - merge_mode.input(fn=beta_visibility, inputs=merge_mode, - outputs=[beta, alpha_label, beta_label, beta_apply_preset, beta_preset, beta_base, - beta_in_blocks, beta_mid_block, beta_out_blocks]) + merge_mode.input(fn=beta_visibility, inputs=merge_mode, outputs=[beta, alpha_label, beta_label, beta_apply_preset, beta_preset, beta_base, beta_in_blocks, beta_mid_block, beta_out_blocks]) re_basin.change(fn=show_iters, inputs=re_basin, outputs=re_basin_iterations) - apply_preset.click(fn=load_presets, inputs=[alpha_preset, alpha_preset_lambda], - outputs=[alpha_base, alpha_in_blocks, alpha_mid_block, alpha_out_blocks, tabs]) - beta_apply_preset.click(fn=load_presets, inputs=[beta_preset, beta_preset_lambda], - outputs=[beta_base, beta_in_blocks, beta_mid_block, beta_out_blocks, tabs]) + apply_preset.click(fn=load_presets, inputs=[alpha_preset, alpha_preset_lambda], outputs=[alpha_base, alpha_in_blocks, alpha_mid_block, alpha_out_blocks, tabs]) + beta_apply_preset.click(fn=load_presets, inputs=[beta_preset, beta_preset_lambda], outputs=[beta_base, beta_in_blocks, beta_mid_block, beta_out_blocks, tabs]) modelmerger_merge.click( fn=wrap_gradio_gpu_call(modelmerger, extra_outputs=lambda: [gr.update() for _ in range(4)]), @@ -393,20 +360,12 @@ def create_ui(): def hf_search(keyword): import huggingface_hub as hf hf_api = hf.HfApi() - model_filter = hf.ModelFilter( - model_name=keyword, - # task='text-to-image', - library=['diffusers'], - ) - models = hf_api.list_models(filter=model_filter, full=True, limit=50, sort="downloads", - direction=-1) + model_filter = hf.ModelFilter(model_name=keyword, library=['diffusers']) + models = hf_api.list_models(filter=model_filter, full=True, limit=50, sort="downloads", direction=-1) data.clear() for model in models: - tags = [t for t in model.tags if - not t.startswith('diffusers') and not t.startswith('license') and not t.startswith( - 'arxiv') and len(t) > 2] - data.append([model.modelId, model.pipeline_tag, tags, model.downloads, model.lastModified, - f'https://huggingface.co/{model.modelId}']) + tags = [t for t in model.tags if not t.startswith('diffusers') and not t.startswith('license') and not t.startswith('arxiv') and len(t) > 2] + data.append([model.modelId, model.pipeline_tag, tags, model.downloads, model.lastModified, f'https://huggingface.co/{model.modelId}']) return data def hf_select(evt: gr.SelectData, data): @@ -414,8 +373,7 @@ def create_ui(): def hf_download_model(hub_id: str, token, variant, revision, mirror, custom_pipeline): from modules.modelloader import download_diffusers_model - download_diffusers_model(hub_id, cache_dir=opts.diffusers_dir, token=token, variant=variant, - revision=revision, mirror=mirror, custom_pipeline=custom_pipeline) + download_diffusers_model(hub_id, cache_dir=opts.diffusers_dir, token=token, variant=variant, revision=revision, mirror=mirror, custom_pipeline=custom_pipeline) from modules.sd_models import list_models # pylint: disable=W0621 list_models() log.info(f'Diffuser model downloaded: model="{hub_id}"') @@ -429,20 +387,15 @@ def create_ui(): with gr.Row(): with gr.Column(scale=2): with gr.Row(): - hf_selected = gr.Textbox('', label='Select model', - placeholder='select model from search results or enter model name manually') + hf_selected = gr.Textbox('', label='Select model', placeholder='select model from search results or enter model name manually') with gr.Column(scale=1): with gr.Row(): - hf_variant = gr.Textbox(opts.cuda_dtype.lower(), label='Specify model variant', - placeholder='') + hf_variant = gr.Textbox(opts.cuda_dtype.lower(), label='Specify model variant', placeholder='') hf_revision = gr.Textbox('', label='Specify model revision', placeholder='') with gr.Row(): - hf_token = gr.Textbox('', label='Huggingface token', - placeholder='optional access token for private or gated models') - hf_mirror = gr.Textbox('', label='Huggingface mirror', - placeholder='optional mirror site for downloads') - hf_custom_pipeline = gr.Textbox('', label='Custom pipeline', - placeholder='optional pipeline for downloads') + hf_token = gr.Textbox('', label='Huggingface token', placeholder='optional access token for private or gated models') + hf_mirror = gr.Textbox('', label='Huggingface mirror', placeholder='optional mirror site for downloads') + hf_custom_pipeline = gr.Textbox('', label='Custom pipeline', placeholder='optional pipeline for downloads') with gr.Column(scale=1): gr.HTML('
') hf_download_model_btn = gr.Button(value="Download model", variant='primary') @@ -450,16 +403,12 @@ def create_ui(): with gr.Row(): hf_headers = ['Name', 'Pipeline', 'Tags', 'Downloads', 'Updated', 'URL'] hf_types = ['str', 'str', 'str', 'number', 'date', 'markdown'] - hf_results = gr.DataFrame(None, label='Search results', show_label=True, interactive=False, - wrap=True, overflow_row_behaviour='paginate', max_rows=10, - headers=hf_headers, datatype=hf_types, type='array') + hf_results = gr.DataFrame(None, label='Search results', show_label=True, interactive=False, wrap=True, overflow_row_behaviour='paginate', max_rows=10, headers=hf_headers, datatype=hf_types, type='array') hf_search_text.submit(fn=hf_search, inputs=[hf_search_text], outputs=[hf_results]) hf_search_btn.click(fn=hf_search, inputs=[hf_search_text], outputs=[hf_results]) hf_results.select(fn=hf_select, inputs=[hf_results], outputs=[hf_selected]) - hf_download_model_btn.click(fn=hf_download_model, - inputs=[hf_selected, hf_token, hf_variant, hf_revision, hf_mirror, - hf_custom_pipeline], outputs=[models_outcome]) + hf_download_model_btn.click(fn=hf_download_model, inputs=[hf_selected, hf_token, hf_variant, hf_revision, hf_mirror, hf_custom_pipeline], outputs=[models_outcome]) with gr.Tab(label="CivitAI"): data = [] @@ -512,16 +461,9 @@ def create_ui(): for model in data: if model['id'] == model_id: for d in model['modelVersions']: - if d.get('images') is not None and len(d['images']) > 0 and len( - d['images'][0]['url']) > 0: + if d.get('images') is not None and len(d['images']) > 0 and len(d['images'][0]['url']) > 0: preview_img = d['images'][0]['url'] - data2.append([ - d['id'], - d['modelId'], - d['name'], - d['baseModel'], - d['createdAt'], - ]) + data2.append([d['id'], d['modelId'], d['name'], d['baseModel'], d['createdAt']]) log.debug(f'CivitAI select: model="{in_data[evt.index[0]]}" versions={len(data2)}') return data2, None, preview_img @@ -535,14 +477,8 @@ def create_ui(): if variant['id'] == variant_id: for f in variant['files']: try: - if os.path.splitext(f['name'])[1].lower() in ['.safetensors', '.ckpt', - '.pt', '.pth', '.bin']: - data3.append([ - f['name'], - round(f['sizeKB']), - json.dumps(f['metadata']), - f['downloadUrl'], - ]) + if os.path.splitext(f['name'])[1].lower() in ['.safetensors', '.ckpt', '.pt', '.pth', '.bin']: + data3.append([f['name'], round(f['sizeKB']), json.dumps(f['metadata']), f['downloadUrl']]) except Exception: pass log.debug(f'CivitAI select: model="{in_data[evt.index[0]]}" files={len(data3)}') @@ -552,8 +488,7 @@ def create_ui(): log.debug(f'CivitAI select: variant={in_data[evt.index[0]]}') return in_data[evt.index[0]][3], in_data[evt.index[0]][0], gr.update(interactive=True) - def civit_download_model(model_url: str, model_name: str, model_path: str, model_type: str, - image_url: str): + def civit_download_model(model_url: str, model_name: str, model_path: str, model_type: str, image_url: str): if model_url is None or len(model_url) == 0: return 'No model selected' try: @@ -580,14 +515,12 @@ def create_ui(): continue for item in page.list_items(): meta = os.path.splitext(item['filename'])[0] + '.json' - if ('card-no-preview.png' in item['preview'] or not os.path.isfile( - meta)) and os.path.isfile(item['filename']): + if ('card-no-preview.png' in item['preview'] or not os.path.isfile(meta)) and os.path.isfile(item['filename']): sha = item.get('hash', None) found = False if sha is not None and len(sha) > 0: r = req(f'https://civitai.com/api/v1/model-versions/by-hash/{sha}') - log.debug( - f'CivitAI search: name="{item["name"]}" hash={sha} status={r.status_code}') + log.debug(f'CivitAI search: name="{item["name"]}" hash={sha} status={r.status_code}') if r.status_code == 200: d = r.json() res.append(download_civit_meta(item['filename'], d['modelId'])) @@ -599,12 +532,10 @@ def create_ui(): if 'error' not in img_res: found = True break - if not found and civit_previews_rehash and os.stat(item['filename']).st_size < ( - 1024 * 1024 * 1024): + if not found and civit_previews_rehash and os.stat(item['filename']).st_size < (1024 * 1024 * 1024): sha = modules.hashes.calculate_sha256(item['filename'], quiet=True)[:10] r = req(f'https://civitai.com/api/v1/model-versions/by-hash/{sha}') - log.debug( - f'CivitAI search: name="{item["name"]}" hash={sha} status={r.status_code}') + log.debug(f'CivitAI search: name="{item["name"]}" hash={sha} status={r.status_code}') if r.status_code == 200: d = r.json() res.append(download_civit_meta(item['filename'], d['modelId'])) @@ -623,8 +554,7 @@ def create_ui(): search_metadata_civit = civit_search_metadata with gr.Row(): - gr.HTML( - '

Fetch information

Fetches preview and metadata information for all models with missing information
Models with existing previews and information are not updated
') + gr.HTML('

Fetch information

Fetches preview and metadata information for all models with missing information
Models with existing previews and information are not updated
') with gr.Row(): civit_previews_btn = gr.Button(value="Start", variant='primary') with gr.Row(): @@ -634,8 +564,7 @@ def create_ui(): gr.HTML('

Search for models

') with gr.Row(): with gr.Column(scale=1): - civit_model_type = gr.Dropdown(label='Model type', choices=['SD 1.5', 'SD XL', 'LoRA', 'Other'], - value='LoRA') + civit_model_type = gr.Dropdown(label='Model type', choices=['SD 1.5', 'SD XL', 'LoRA', 'Other'], value='LoRA') with gr.Column(scale=15): with gr.Row(): civit_search_text = gr.Textbox('', label='Search models', placeholder='keyword') @@ -647,15 +576,11 @@ def create_ui(): gr.HTML('

Download model

') with gr.Row(): civit_download_model_btn = gr.Button(value="Download", variant='primary') - gr.HTML( - 'Select a model, model version and and model variant from the search results to download or enter model URL manually
') + gr.HTML('Select a model, model version and and model variant from the search results to download or enter model URL manually
') with gr.Row(): - civit_name = gr.Textbox('', label='Model name', placeholder='select model from search results', - visible=True) - civit_selected = gr.Textbox('', label='Model URL', placeholder='select model from search results', - visible=True) - civit_path = gr.Textbox('', label='Download path', - placeholder='optional subfolder path where to save model', visible=True) + civit_name = gr.Textbox('', label='Model name', placeholder='select model from search results', visible=True) + civit_selected = gr.Textbox('', label='Model URL', placeholder='select model from search results', visible=True) + civit_path = gr.Textbox('', label='Download path', placeholder='optional subfolder path where to save model', visible=True) with gr.Row(): gr.HTML('

Search results

') with gr.Row(): @@ -685,26 +610,108 @@ def create_ui(): visible = len(component) > 0 if component is not None else False return gr.update(visible=visible) - civit_search_text.submit(fn=civit_search_model, - inputs=[civit_search_text, civit_search_tag, civit_model_type], - outputs=[civit_search_res, civit_results1, civit_results2, civit_results3]) - civit_search_tag.submit(fn=civit_search_model, - inputs=[civit_search_text, civit_search_tag, civit_model_type], - outputs=[civit_search_res, civit_results1, civit_results2, civit_results3]) - civit_search_btn.click(fn=civit_search_model, - inputs=[civit_search_text, civit_search_tag, civit_model_type], - outputs=[civit_search_res, civit_results1, civit_results2, civit_results3]) - civit_results1.select(fn=civit_select1, inputs=[civit_results1], - outputs=[civit_results2, civit_results3, models_image]) + civit_search_text.submit(fn=civit_search_model, inputs=[civit_search_text, civit_search_tag, civit_model_type], outputs=[civit_search_res, civit_results1, civit_results2, civit_results3]) + civit_search_tag.submit(fn=civit_search_model, inputs=[civit_search_text, civit_search_tag, civit_model_type], outputs=[civit_search_res, civit_results1, civit_results2, civit_results3]) + civit_search_btn.click(fn=civit_search_model, inputs=[civit_search_text, civit_search_tag, civit_model_type], outputs=[civit_search_res, civit_results1, civit_results2, civit_results3]) + civit_results1.select(fn=civit_select1, inputs=[civit_results1], outputs=[civit_results2, civit_results3, models_image]) civit_results2.select(fn=civit_select2, inputs=[civit_results2], outputs=[civit_results3]) - civit_results3.select(fn=civit_select3, inputs=[civit_results3], - outputs=[civit_selected, civit_name, civit_search_btn]) + civit_results3.select(fn=civit_select3, inputs=[civit_results3], outputs=[civit_selected, civit_name, civit_search_btn]) civit_results1.change(fn=is_visible, inputs=[civit_results1], outputs=[civit_results1]) civit_results2.change(fn=is_visible, inputs=[civit_results2], outputs=[civit_results2]) civit_results3.change(fn=is_visible, inputs=[civit_results3], outputs=[civit_results3]) - civit_download_model_btn.click(fn=civit_download_model, - inputs=[civit_selected, civit_name, civit_path, civit_model_type, - models_image], outputs=[models_outcome]) - civit_previews_btn.click(fn=civit_search_metadata, - inputs=[civit_previews_rehash, civit_previews_rehash], - outputs=[models_outcome]) + civit_download_model_btn.click(fn=civit_download_model, inputs=[civit_selected, civit_name, civit_path, civit_model_type, models_image], outputs=[models_outcome]) + civit_previews_btn.click(fn=civit_search_metadata, inputs=[civit_previews_rehash, civit_previews_rehash], outputs=[models_outcome]) + + with gr.Tab(label="Update"): + with gr.Row(): + gr.HTML('Fetch most recent information about all installed models
') + with gr.Row(): + civit_update_btn = gr.Button(value="Update", variant='primary') + + with gr.Row(): + civit_headers4 = ['ID', 'File', 'Name', 'Versions', 'Current', 'Latest', 'Update available'] + civit_types4 = ['number', 'str', 'str', 'number', 'str', 'str', 'bool'] + civit_results4 = gr.DataFrame(value=None, label=None, show_label=False, interactive=False, wrap=True, overflow_row_behaviour='paginate', max_rows=100, headers=civit_headers4, datatype=civit_types4, type='array', visible=True) + + with gr.Row(): + civit_update_download_btn = gr.Button(value="Download", variant='primary', visible=False) + + class CivitModel: + def __init__(self, name, fn, sha = None, meta = {}): + self.name = name + self.id = meta.get('id', 0) + self.fn = fn + self.sha = sha + self.meta = meta + self.versions = 0 + self.vername = '' + self.latest = '' + self.url = None + self.status = False + def array(self): + return [self.id, self.fn, self.name, self.versions, self.vername, self.latest, self.status] + + selected_model: CivitModel = None + update_data = [] + + def civit_update_metadata(): + nonlocal update_data + log.debug('CivitAI update metadata: models') + from modules.ui_extra_networks import get_pages + from modules.modelloader import download_civit_meta + res = [] + page: modules.ui_extra_networks.ExtraNetworksPage = get_pages('model')[0] + table_data = [] + update_data.clear() + for item in page.list_items(): + model = CivitModel(name=item['name'], fn=item['filename'], sha=item.get('hash', None), meta=item.get('metadata', {})) + if model.sha is None or len(model.sha) == 0: + res.append(f'CivitAI skip search: name="{model.name}" hash=None') + else: + r = req(f'https://civitai.com/api/v1/model-versions/by-hash/{model.sha}') + res.append(f'CivitAI search: name="{model.name}" hash={model.sha} status={r.status_code}') + if r.status_code == 200: + d = r.json() + model.id = d['modelId'] + download_civit_meta(model.fn, model.id) + fn = os.path.splitext(item['filename'])[0] + '.json' + model.meta = readfile(fn, silent=True) + model.name = model.meta.get('name', model.name) + model.versions = len(model.meta.get('modelVersions', [])) + versions = model.meta.get('modelVersions', []) + if len(versions) > 0: + model.latest = versions[0].get('name', '') + for ver in versions: + for f in ver.get('files', []): + for h in f.get('hashes', {}).values(): + if h[:8].upper() == model.sha[:8].upper(): + model.vername = ver.get('name', '') + model.url = f.get('downloadUrl', None) + model.status = model.vername != model.latest + break + log.debug(res[-1]) + update_data.append(model) + table_data.append(model.array()) + yield gr.update(value=table_data), '
'.join([r for r in res if len(r) > 0]) + return '
'.join([r for r in res if len(r) > 0]) + + def civit_update_select(evt: gr.SelectData, in_data): + nonlocal selected_model, update_data + try: + selected_model = [m for m in update_data if m.fn == in_data[evt.index[0]][1]][0] + except: + selected_model = None + if selected_model is None or selected_model.url is None or not selected_model.status: + return [gr.update(value='Model update not available'), gr.update(visible=False)] + else: + return [gr.update(), gr.update(visible=True)] + + def civit_update_download(): + if selected_model is None or selected_model.url is None or not selected_model.status: + return 'Model update not available' + model_name = f'{selected_model.name} {selected_model.latest}' + return civit_download_model(selected_model.url, model_name, model_path='', model_type='Model', image_url=None) + + civit_update_btn.click(fn=civit_update_metadata, inputs=[], outputs=[civit_results4, models_outcome]) + civit_results4.select(fn=civit_update_select, inputs=[civit_results4], outputs=[models_outcome, civit_update_download_btn]) + civit_update_download_btn.click(fn=civit_update_download, inputs=[], outputs=[models_outcome]) From d660b288f87aead9f8eb70606f884028067a0085 Mon Sep 17 00:00:00 2001 From: Vladimir Mandic Date: Wed, 22 Nov 2023 11:53:41 -0500 Subject: [PATCH 78/84] model update check if latest exists --- CHANGELOG.md | 6 +-- cli/train.py | 9 +++- .../kandinsky-community--kandinsky-3.jpg | Bin 0 -> 121217 bytes modules/generation_parameters_copypaste.py | 2 +- modules/shared_items.py | 1 + modules/ui_models.py | 40 +++++++++++++----- 6 files changed, 42 insertions(+), 16 deletions(-) create mode 100644 models/Reference/kandinsky-community--kandinsky-3.jpg diff --git a/CHANGELOG.md b/CHANGELOG.md index f9a69c98b..85ee74860 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,6 @@ # Change Log for SD.Next -## Update for 2023-11-21 +## Update for 2023-11-22 - **Diffusers** - **LCM** support for any *SD 1.5* or *SD-XL* model! @@ -35,8 +35,8 @@ using one of *presets* (20 built-in presets) or custom block merge values - merge with ReBasin permuatations and/or clipping protection - fully multithreaded for fastest merge possible - - **Model update** *(experimental)* - - under UI -> Models - Update + - **Model update** + - under UI -> Models - Update - scan existing models for updated metadata on CivitAI and provide download functionality for models with available - **Extra networks** diff --git a/cli/train.py b/cli/train.py index 2193b5f85..9e551ddf5 100755 --- a/cli/train.py +++ b/cli/train.py @@ -109,7 +109,7 @@ def parse_args(): group_train.add_argument('--algo', type=str, default=None, choices=['locon', 'loha', 'lokr', 'ia3'], required=False, help='alternative lyco algoritm, default: %(default)s') group_train.add_argument('--args', type=str, default=None, required=False, help='lora/lyco additional network arguments, default: %(default)s') group_train.add_argument('--optimizer', type=str, default='AdamW', required=False, help='optimizer type, default: %(default)s') - group_train.add_argument('--precision', type=str, choices=['fp16', 'fp32'], default='fp16', required=True, help='training precision, default: %(default)s') + group_train.add_argument('--precision', type=str, choices=['fp16', 'fp32'], default='fp16', required=False, help='training precision, default: %(default)s') group_train.add_argument('--sdxl', default = False, action='store_true', help = "run sdxl training, default: %(default)s") # AdamW (default), AdamW8bit, PagedAdamW8bit, Lion8bit, PagedLion8bit, Lion, SGDNesterov, SGDNesterov8bit, DAdaptation(DAdaptAdamPreprint), DAdaptAdaGrad, DAdaptAdam, DAdaptAdan, DAdaptAdanIP, DAdaptLion, DAdaptSGD, AdaFactor @@ -164,8 +164,13 @@ def verify_args(): exit(1) base_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) if args.type == 'lora' and not server_ok and not args.dir: - log.error('offline lora training requires lora') + log.error('offline lora training requires --dir ') exit(1) + if args.type == 'lora': + import transformers + if transformers.__version__ != '4.30.2': + log.error(f'lora training requires specific transformers version: current {transformers.__version__} required transformers==4.30.2') + exit(1) args.lora_dir = server_options.options.lora_dir or args.dir if not os.path.isabs(args.lora_dir): args.lora_dir = os.path.join(base_dir, args.lora_dir) diff --git a/models/Reference/kandinsky-community--kandinsky-3.jpg b/models/Reference/kandinsky-community--kandinsky-3.jpg new file mode 100644 index 0000000000000000000000000000000000000000..96570921af9a398e2ffc598b2308e795048a2af8 GIT binary patch literal 121217 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
AE+7Lq;A|;EL<* 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
-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 literal 0 HcmV?d00001 diff --git a/modules/generation_parameters_copypaste.py b/modules/generation_parameters_copypaste.py index 7aba397a6..8dd589772 100644 --- a/modules/generation_parameters_copypaste.py +++ b/modules/generation_parameters_copypaste.py @@ -212,7 +212,7 @@ def parse_generation_parameters(x: str): remaining = x[7:] if x.startswith('Prompt: ') else x remaining = x[11:] if x.startswith('parameters: ') else x if 'Steps: ' in remaining and 'Negative prompt: ' not in remaining: - remaining = remaining.replace('Steps: ', 'Negative prompt: , Steps: ') + remaining = remaining.replace('Steps: ', 'Negative prompt: Steps: ') prompt, remaining = remaining.strip().split('Negative prompt: ', maxsplit=1) if 'Negative prompt: ' in remaining else (remaining, '') res["Prompt"] = prompt.strip() negative, remaining = remaining.strip().split('Steps: ', maxsplit=1) if 'Steps: ' in remaining else (remaining, None) diff --git a/modules/shared_items.py b/modules/shared_items.py index 49387e56e..72d8cbfca 100644 --- a/modules/shared_items.py +++ b/modules/shared_items.py @@ -43,6 +43,7 @@ def get_pipelines(): 'Wuerstchen': getattr(diffusers, 'WuerstchenCombinedPipeline', None), 'Kandinsky 2.1': getattr(diffusers, 'KandinskyPipeline', None), 'Kandinsky 2.2': getattr(diffusers, 'KandinskyV22Pipeline', None), + # 'Kandinsky 3': getattr(diffusers, 'KandinskyV3Pipeline', None), 'DeepFloyd IF': getattr(diffusers, 'IFPipeline', None), 'Custom Diffusers Pipeline': getattr(diffusers, 'DiffusionPipeline', None), # Segmind SSD-1B, Segmind Tiny diff --git a/modules/ui_models.py b/modules/ui_models.py index ffaf66137..be338c23d 100644 --- a/modules/ui_models.py +++ b/modules/ui_models.py @@ -627,12 +627,16 @@ def create_ui(): gr.HTML('Fetch most recent information about all installed models
') with gr.Row(): civit_update_btn = gr.Button(value="Update", variant='primary') - with gr.Row(): - civit_headers4 = ['ID', 'File', 'Name', 'Versions', 'Current', 'Latest', 'Update available'] - civit_types4 = ['number', 'str', 'str', 'number', 'str', 'str', 'bool'] - civit_results4 = gr.DataFrame(value=None, label=None, show_label=False, interactive=False, wrap=True, overflow_row_behaviour='paginate', max_rows=100, headers=civit_headers4, datatype=civit_types4, type='array', visible=True) - + gr.HTML('

Update scan results

') + with gr.Row(): + civit_headers4 = ['ID', 'File', 'Name', 'Versions', 'Current', 'Latest', 'Update'] + civit_types4 = ['number', 'str', 'str', 'number', 'str', 'str', 'str'] + civit_widths4 = ['10%', '25%', '25%', '5%', '10%', '10%', '15%'] + civit_results4 = gr.DataFrame(value=None, label=None, show_label=False, interactive=False, wrap=True, overflow_row_behaviour='paginate', + row_count=20, max_rows=100, headers=civit_headers4, datatype=civit_types4, type='array', column_widths=civit_widths4) + with gr.Row(): + gr.HTML('

Select model from the list and download update if available

') with gr.Row(): civit_update_download_btn = gr.Button(value="Download", variant='primary', visible=False) @@ -646,8 +650,10 @@ def create_ui(): self.versions = 0 self.vername = '' self.latest = '' + self.latest_hashes = [] + self.latest_name = '' self.url = None - self.status = False + self.status = 'Not found' def array(self): return [self.id, self.fn, self.name, self.versions, self.vername, self.latest, self.status] @@ -663,6 +669,7 @@ def create_ui(): page: modules.ui_extra_networks.ExtraNetworksPage = get_pages('model')[0] table_data = [] update_data.clear() + all_hashes = [(item.get('hash', None) or 'XXXXXXXX').upper()[:8] for item in page.list_items()] for item in page.list_items(): model = CivitModel(name=item['name'], fn=item['filename'], sha=item.get('hash', None), meta=item.get('metadata', {})) if model.sha is None or len(model.sha) == 0: @@ -681,13 +688,23 @@ def create_ui(): versions = model.meta.get('modelVersions', []) if len(versions) > 0: model.latest = versions[0].get('name', '') + model.latest_hashes.clear() + for v in versions[0].get('files', []): + for h in v.get('hashes', {}).values(): + model.latest_hashes.append(h[:8].upper()) for ver in versions: for f in ver.get('files', []): for h in f.get('hashes', {}).values(): if h[:8].upper() == model.sha[:8].upper(): model.vername = ver.get('name', '') model.url = f.get('downloadUrl', None) - model.status = model.vername != model.latest + model.latest_name = f.get('name', '') + if model.vername == model.latest: + model.status = 'Latest' + elif any(map(lambda v: v in model.latest_hashes, all_hashes)): + model.status = 'Downloaded' + else: + model.status = 'Available' break log.debug(res[-1]) update_data.append(model) @@ -701,15 +718,18 @@ def create_ui(): selected_model = [m for m in update_data if m.fn == in_data[evt.index[0]][1]][0] except: selected_model = None - if selected_model is None or selected_model.url is None or not selected_model.status: + if selected_model is None or selected_model.url is None or selected_model.status != 'Available': return [gr.update(value='Model update not available'), gr.update(visible=False)] else: return [gr.update(), gr.update(visible=True)] def civit_update_download(): - if selected_model is None or selected_model.url is None or not selected_model.status: + if selected_model is None or selected_model.url is None or selected_model.status != 'Available': return 'Model update not available' - model_name = f'{selected_model.name} {selected_model.latest}' + if selected_model.latest_name is None or len(selected_model.latest_name) == 0: + model_name = f'{selected_model.name} {selected_model.latest}.safetensors' + else: + model_name = selected_model.latest_name return civit_download_model(selected_model.url, model_name, model_path='', model_type='Model', image_url=None) civit_update_btn.click(fn=civit_update_metadata, inputs=[], outputs=[civit_results4, models_outcome]) From fd9d747a47e46b77a9fd5659cfa10fcaa4c762c2 Mon Sep 17 00:00:00 2001 From: Vladimir Mandic Date: Wed, 22 Nov 2023 12:28:35 -0500 Subject: [PATCH 79/84] force inpaint --- modules/processing_diffusers.py | 4 ---- modules/sd_models.py | 4 ---- modules/shared.py | 5 ++--- 3 files changed, 2 insertions(+), 11 deletions(-) diff --git a/modules/processing_diffusers.py b/modules/processing_diffusers.py index a36fed906..28f1a553d 100644 --- a/modules/processing_diffusers.py +++ b/modules/processing_diffusers.py @@ -214,10 +214,8 @@ def process_diffusers(p: StableDiffusionProcessing, seeds, prompts, negative_pro p.mask = TF.to_pil_image(torch.ones_like(TF.to_tensor(p.init_images[0]))).convert("L") width = 8 * math.ceil(p.init_images[0].width / 8) height = 8 * math.ceil(p.init_images[0].height / 8) - # option-1: use images as inputs task_args = {"image": p.init_images, "mask_image": p.mask, "strength": p.denoising_strength, "height": height, "width": width} - """ # option-2: preprocess images into latents using diffusers vae_scale_factor = 2 ** (len(model.vae.config.block_out_channels) - 1) image_processor = diffusers.image_processor.VaeImageProcessor(vae_scale_factor=vae_scale_factor) @@ -226,7 +224,6 @@ def process_diffusers(p: StableDiffusionProcessing, seeds, prompts, negative_pro mask_image = mask_processor.preprocess(p.mask, width=width, height=height) task_args = {"image": p.init_images, "mask_image": p.mask, "strength": p.denoising_strength, "height": height, "width": width} """ - """ # option-2: manually assemble masked image latents masked_image_latents = [] mask_image = TF.to_tensor(p.mask) @@ -237,7 +234,6 @@ def process_diffusers(p: StableDiffusionProcessing, seeds, prompts, negative_pro masked_image_latents = torch.stack(masked_image_latents, dim=0).to(shared.device) task_args = {"image": p.init_images, "mask_image": mask_image, "masked_image_latents": masked_image_latents, "strength": p.denoising_strength, "height": height, "width": width} """ - if model.__class__.__name__ == 'LatentConsistencyModelPipeline' and hasattr(p, 'init_images') and len(p.init_images) > 0: init_latents = [vae_encode(image, model=shared.sd_model, full_quality=p.full_quality).squeeze(dim=0) for image in p.init_images] init_latent = torch.stack(init_latents, dim=0).to(shared.device) diff --git a/modules/sd_models.py b/modules/sd_models.py index 427a94d7d..dc74a17c1 100644 --- a/modules/sd_models.py +++ b/modules/sd_models.py @@ -1010,10 +1010,6 @@ def set_diffuser_pipe(pipe, new_pipe_type): ) diffusers.pipelines.auto_pipeline.AUTO_TEXT2IMAGE_PIPELINES_MAPPING = AUTO_TEXT2IMAGE_PIPELINES_MAPPING """ - - if shared.opts.diffusers_force_inpaint: - if new_pipe_type == DiffusersTaskType.IMAGE_2_IMAGE: - new_pipe_type = DiffusersTaskType.INPAINTING # sdxl may work better with init mask try: if new_pipe_type == DiffusersTaskType.TEXT_2_IMAGE: new_pipe = diffusers.AutoPipelineForText2Image.from_pipe(pipe) diff --git a/modules/shared.py b/modules/shared.py index 04a03d9b4..176bd4690 100644 --- a/modules/shared.py +++ b/modules/shared.py @@ -368,7 +368,6 @@ options_templates.update(options_section(('diffusers', "Diffusers Settings"), { "diffusers_eval": OptionInfo(True, "Force model eval"), "diffusers_force_zeros": OptionInfo(True, "Force zeros for prompts when empty"), "diffusers_aesthetics_score": OptionInfo(False, "Require aesthetics score"), - "diffusers_force_inpaint": OptionInfo(False, 'Diffusers force inpaint pipeline'), "diffusers_pooled": OptionInfo("default", "Diffusers SDXL pooled embeds (experimental)", gr.Radio, {"choices": ['default', 'weighted']}), })) @@ -531,9 +530,9 @@ options_templates.update(options_section(('sampler-params', "Sampler Settings"), 'uni_pc_variant': OptionInfo("bh1", "UniPC variant", gr.Radio, {"choices": ["bh1", "bh2", "vary_coeff"]}), 'uni_pc_skip_type': OptionInfo("time_uniform", "UniPC skip type", gr.Radio, {"choices": ["time_uniform", "time_quadratic", "logSNR"]}), "ddim_discretize": OptionInfo('uniform', "DDIM discretize img2img", gr.Radio, {"choices": ['uniform', 'quad']}), - # TODO pad_cond_uncond implementation missing + # TODO pad_cond_uncond implementation missing for original backend "pad_cond_uncond": OptionInfo(True, "Pad prompt and negative prompt to be same length", gr.Checkbox, {"visible": False}), - # TODO batch_cond-uncond implementation missing + # TODO batch_cond-uncond implementation missing for original backend "batch_cond_uncond": OptionInfo(True, "Do conditional and unconditional denoising in one batch", gr.Checkbox, {"visible": False}), })) From 0b576c646d938936c8dc19dcb3009e5e5e43845e Mon Sep 17 00:00:00 2001 From: Redacted Date: Wed, 22 Nov 2023 16:09:38 -0600 Subject: [PATCH 80/84] Various mobile UI fixes -second quality pass for the entire ui to fix any issues, eg items being pushed off screen, non selectable items, radio buttons being pushed off of the display. --- javascript/sdnext.css | 137 ++++++++++++++++++++++++++++++++++-------- 1 file changed, 113 insertions(+), 24 deletions(-) diff --git a/javascript/sdnext.css b/javascript/sdnext.css index f07228cf0..f3576f091 100644 --- a/javascript/sdnext.css +++ b/javascript/sdnext.css @@ -9,7 +9,7 @@ tr { border-bottom: none !important; padding: 0.1em 0.5em !important; } textarea { overflow-y: auto !important; } /* gradio elements */ -.block .padded:not(.gradio-accordion) { padding: 0 !important; margin-right: 0; min-width: 90px !important; } +.block .padded:not(.gradio-accordion) {padding: 0 !important;margin-right: 0;min-width: 90px !important;} .compact { gap: 1em 0.2em; background: transparent !important; padding: 0 !important; } .flex-break { flex-basis: 100% !important; } .form { border-width: 0; box-shadow: none; background: transparent; overflow: visible; gap: 0.5em 1em; flex-grow: 1 !important; } @@ -27,12 +27,12 @@ textarea { overflow-y: auto !important; } .gradio-button.secondary-down:hover { background: var(--button-secondary-background-fill-hover); color: var(--button-secondary-text-color-hover); } .gradio-button.tool { max-width: min-content; min-width: min-content !important; align-self: end; font-size: 1.4em; color: var(--body-text-color) !important; margin-top: auto; margin-bottom: var(--spacing-md); align-self: center; } .gradio-checkbox { margin: 0.75em 1.5em 0 0; align-self: center; } -.gradio-column { min-width: min(160px, 100%) !important; } +.gradio-column {min-width: min(160px, 100%) !important;} .gradio-container { max-width: unset !important; padding: var(--block-label-padding) !important; } .gradio-container .prose a, .gradio-container .prose a:visited{ color: unset; text-decoration: none; } .gradio-dropdown { margin-right: var(--spacing-sm) !important; min-width:160px; max-width:fit-content } -.gradio-dropdown ul.options { z-index: 1000; min-width: fit-content; max-height: 33vh !important; white-space: nowrap; } -.gradio-dropdown ul.options li.item { padding: var(--spacing-xs); } +.gradio-dropdown ul.options {z-index: 1000;min-width: fit-content;max-height: 33vh !important;white-space: nowrap;} +.gradio-dropdown ul.options li.item {padding: var(--spacing-xs);} .gradio-dropdown ul.options li.item:not(:has(.hide)) { background-color: var(--primary-500); } .gradio-dropdown .token { padding: var(--spacing-xs); } .gradio-dropdown span { margin-bottom: 0 !important; font-size: 0.9em; } @@ -48,8 +48,8 @@ textarea { overflow-y: auto !important; } /* custom gradio elements */ .accordion-compact { padding: 8px 0px 4px 0px !important; } -.settings-accordion > div { flex-flow: wrap; } -.small-accordion .form { min-width: var(--left-column) !important; max-width: max-content; } +.settings-accordion > div {flex-flow: wrap;} +.small-accordion .form {min-width: var(--left-column) !important;max-width: max-content;} .small-accordion .label-wrap .icon { margin-right: 1.6em; margin-left: 0.6em; color: var(--button-primary-border-color); } .small-accordion .label-wrap { padding: 16px 0px 8px 0px; margin: 0; border-top: 2px solid var(--button-secondary-border-color); } .small-accordion { width: fit-content !important; padding-left: 0 !important; } @@ -105,16 +105,16 @@ div#extras_scale_to_tab div.form{ flex-direction: row; } #si-sparkline-memo, #si-sparkline-load { background-color: #111; } #quicksettings { width: fit-content; } #quicksettings > button { padding: 0 1em 0 0; align-self: end; margin-bottom: var(--text-sm); } -#settings { display: flex; gap: var(--layout-gap); } -#settings div { border: none; gap: 0; margin: 0 0 var(--layout-gap) 0px; padding: 0; } -#settings > div.tab-content { flex: 10 0 75%; display: grid; } +#settings {display: flex;gap: var(--layout-gap);} +#settings div {border: none;gap: 0;margin: 0 0 var(--layout-gap) 0px;padding: 0;} +#settings > div.tab-content {flex: 10 0 75%;display: grid;} #settings > div.tab-content > div { border: none; padding: 0; } -#settings > div.tab-content > div > div > div > div > div { flex-direction: unset; } -#settings > div.tab-nav { display: grid; grid-template-columns: repeat(auto-fill, .5em minmax(10em, 1fr)); flex: 1 0 auto; width: 12em; align-self: flex-start; gap: var(--spacing-xxl); } +#settings > div.tab-content > div > div > div > div > div {flex-direction: unset;} +#settings > div.tab-nav {display: grid;grid-template-columns: repeat(auto-fill, .5em minmax(10em, 1fr));flex: 1 0 auto;width: 12em;align-self: flex-start;gap: var(--spacing-xxl);} #settings > div.tab-nav button { display: block; border: none; text-align: left; white-space: initial; padding: 0; } #settings > div.tab-nav > #settings_show_all_pages { padding: var(--size-2) var(--size-4); } #settings .block.gradio-checkbox { margin: 0; width: auto; } -#settings .dirtyable { gap: .5em; } +#settings .dirtyable {gap: .5em;:;} #settings .dirtyable.hidden { display: none; } #settings .modification-indicator { height: 1.2em; border-radius: 1em !important; padding: 0; width: 0; margin-right: 0.5em; } #settings .modification-indicator:disabled { visibility: hidden; } @@ -280,25 +280,114 @@ table.settings-value-table td { padding: 0.4em; border: 1px solid #ccc; max-widt --spacing-xxl: 6px; } - /* Apply different styles for devices with coarse pointers dependant on screen resolution */ @media (hover: none) and (pointer: coarse) { /* Screens 400px and smaller */ - @media (max-width: 425px) { + @media (max-width: 399px) { :root, .light, .dark { --left-column: 100%; } - #settings {display: flex;gap: var(--layout-gap);flex-wrap: wrap;flex-direction: row;} - #txt2img_results, #img2img_results, #extras_results { background-color: var(--background-color); padding: 0; min-width: calc(min(320px, 100%)) !important;} + /* maintain single column for from image operations on larger mobile devices */ + #txt2img_results, #img2img_results, #extras_results { min-width: calc(min(320px, 100%)) !important;} + /* maintain single column for from image operations on larger mobile devices */ + #img2img_settings, #img2img_results { min-width: 100% !important; max-width: 100% !important;} + /* fix inpaint image display being too large for mobile displays */ + #img2img_sketch, #img2maskimg, #inpaint_sketch {display: flex;alignment-baseline:after-edge !important;overflow: auto !important;resize: none !important;} + #img2maskimg canvas { width: 100% !important; max-height: 100% !important; height: auto !important; } + + /* fix from text/image UI elements to prevent them from moving around within the UI */ + #txt2img_sampler, #txt2img_batch, #txt2img_seed_group, #txt2img_advanced, #txt2img_second_pass, #img2img_sampling_group, #img2img_resize_group, #img2img_batch_group, #img2img_seed_group, #img2img_denoise_group, #img2img_advanced_group { width: 100% !important; } + + /* adjust slider input fields as they were too large for mobile devices. */ .gradio-slider input[type="number"] { width: 4em; font-size: 0.8rem; height: 16px; text-align: center; } + + /* Various interface elements default to row, this breaks UI placement on mobile. */ + #component-886, #component-1915, #component-2018 div, #component-2044 div > div, #component-2087 div, #component-2091 div, #component-2140 div, #component-2144 div, #component-3435 div { display:flex; flex-wrap: wrap; align-content:flex-start; flex-direction: column; } + + /* move image preview/output to bottom of page */ + #models_tab { flex-direction: column-reverse !important; } + #component-3464 div { display: flex; flex-direction: row; justify-content: flex-start; flex-wrap: wrap; } + #enqueue_keyboard_shortcut_modifiers, #enqueue_keyboard_shortcut_key div { max-width: 40% !important;} + #component-2906, #component-2953, #component-2957 {max-width: 85%;} + #settings > div.tab-nav {gap: var(--layout-gap);display: flex;flex-wrap: wrap;flex-direction: column;align-content: flex-start;align-items: flex-start;justify-content: flex-start;} + #settings { gap: var(--layout-gap); display: flex; flex-wrap: wrap; flex-direction: row; } + + /* enable scrolling on extensions tab */ + #tab_extensions table, #tab_config table{ border-collapse: collapse; display: block; overflow-x:auto;} + + /* increase scrollbar size to make it finger friendly */ + ::-webkit-scrollbar { width: 25px !important; height:25px; } + } - /* Screens 400px and larger up to 1080px */ - @media (max-width: 1080px) and (min-width:425px) { - :root, .light, .dark { --left-column: 39%; } - #scripts_alwayson_txt2img div { max-width: 99%; } - #settings {display: flex;gap: var(--layout-gap);flex-wrap: wrap;flex-direction: row;} - #txt2img_results, #img2img_results, #extras_results { background-color: var(--background-color); padding: 0;} - .gradio-slider input[type="number"] { width: 4em; font-size: 0.8rem; height: 16px; text-align: center; } - } +/* Apply different styles for devices with coarse pointers dependant on screen resolution */ +@media (hover: none) and (pointer: coarse) { + /* Do not affect displays larger than 1024px wide. */ + @media (max-width: 1024px) { + + /* Screens smaller than 424px wide */ + @media (max-width: 399px) { + :root, .light, .dark { --left-column: 100%; } + + /* maintain single column for from image operations on larger mobile devices */ + #txt2img_results, #img2img_results, #extras_results { min-width: calc(min(320px, 100%)) !important;} + } + + /* Screens larger than 425px wide */ + @media (min-width: 425px) { + :root, .light, .dark {--left-column: 50% ;} + + /* adjust extension panel to fit within resized sidebar */ + #scripts_alwayson_txt2img div { max-width: 99%; } + + /* maintain side by side split on larger mobile displays for from text */ + #txt2img_results, #extras_results { min-width: 50% !important;} + } + + #txt2img_prompt_container, #img2img_prompt_container { resize:vertical !important; } + + /* make generate and enqueue buttons take up the entire width of their rows. */ + #txt2img_generate_box, #txt2img_enqueue_wrapper { min-width: 100% !important;} + + /*make interrogate buttons take up appropriate space. */ + #img2img_toprow > div.gradio-column {flex-grow: 1 !important;} + #img2img_actions_column {display: flex; min-width: fit-content !important; flex-direction: row;justify-content: space-evenly; align-items: center;} + #txt2img_generate_box, #img2img_generate_box, #txt2img_enqueue_wrapper,#img2img_enqueue_wrapper {display: flex;flex-direction: column;height: 4em !important;align-items: stretch;justify-content: space-evenly;} + + /* maintain single column for from image operations on larger mobile devices */ + #img2img_settings, #img2img_results { min-width: 100% !important; max-width: 100% !important;} + /* fix inpaint image display being too large for mobile displays */ + #img2img_sketch, #img2maskimg, #inpaint_sketch {display: flex;alignment-baseline:after-edge !important;overflow: auto !important;resize: none !important;} + #img2maskimg canvas { width: 100% !important; max-height: 100% !important; height: auto !important; } + + /* fix from text/image UI elements to prevent them from moving around within the UI */ + #txt2img_sampler, #txt2img_batch, #txt2img_seed_group, #txt2img_advanced, #txt2img_second_pass, #img2img_sampling_group, #img2img_resize_group, #img2img_batch_group, #img2img_seed_group, #img2img_denoise_group, #img2img_advanced_group { width: 100% !important; } + #img2img_resize_group .gradio-radio > div { display: flex; flex-direction: column; width: unset !important; } + #inpaint_controls div {display:flex;flex-direction: row;} + #inpaint_controls .gradio-radio > div { display: flex; flex-direction: column !important; } + + /* move image preview/output on models page to bottom of page */ + #models_tab { flex-direction: column-reverse !important; } + /* fix settings for agent scheduler */ + #enqueue_keyboard_shortcut_modifiers, #enqueue_keyboard_shortcut_key div { max-width: 40% !important;} + + /* adjust width of certain settings item to allow aligning as row, but not have it go off the screen */ + #settings { display: flex; flex-direction: row; flex-wrap: wrap; max-width: 100% !important; } + #settings div.tab-content > div > div > div { max-width: 80% !important;} + #settings div .gradio-radio { width: unset !important; } + + /* enable scrolling on extensions tab */ + #tab_extensions table { border-collapse: collapse; display: block; overflow-x:auto !important;} + + /* increase scrollbar size to make it finger friendly */ + ::-webkit-scrollbar { width: 25px !important; height:25px; } + + /* adjust dropdown size to make them easier to select individual items on mobile. */ + .gradio-dropdown ul.options {max-height: 41vh !important; } + .gradio-dropdown ul.options li.item {height: 40px !important; display: flex; align-items: center;} + + /* adjust slider input fields as they were too large for mobile devices. */ + .gradio-slider input[type="number"] { width: 4em; font-size: 0.8rem; height: 16px; text-align: center; } + #txt2img_settings .block .padded:not(.gradio-accordion) {padding: 0 !important;margin-right: 0; min-width: 100% !important; width:100% !important;} + } } From a867b96202ff1d5138577012496f136cfaa7fffa Mon Sep 17 00:00:00 2001 From: Redacted Date: Wed, 22 Nov 2023 16:25:57 -0600 Subject: [PATCH 81/84] Update sdnext.css removed unintended changes caused by the editor, removed extra mediaquery section --- javascript/sdnext.css | 64 +++++++++---------------------------------- 1 file changed, 13 insertions(+), 51 deletions(-) diff --git a/javascript/sdnext.css b/javascript/sdnext.css index f3576f091..88bb60cc5 100644 --- a/javascript/sdnext.css +++ b/javascript/sdnext.css @@ -9,7 +9,7 @@ tr { border-bottom: none !important; padding: 0.1em 0.5em !important; } textarea { overflow-y: auto !important; } /* gradio elements */ -.block .padded:not(.gradio-accordion) {padding: 0 !important;margin-right: 0;min-width: 90px !important;} +.block .padded:not(.gradio-accordion) { padding: 0 !important; margin-right: 0; min-width: 90px !important; } .compact { gap: 1em 0.2em; background: transparent !important; padding: 0 !important; } .flex-break { flex-basis: 100% !important; } .form { border-width: 0; box-shadow: none; background: transparent; overflow: visible; gap: 0.5em 1em; flex-grow: 1 !important; } @@ -27,12 +27,12 @@ textarea { overflow-y: auto !important; } .gradio-button.secondary-down:hover { background: var(--button-secondary-background-fill-hover); color: var(--button-secondary-text-color-hover); } .gradio-button.tool { max-width: min-content; min-width: min-content !important; align-self: end; font-size: 1.4em; color: var(--body-text-color) !important; margin-top: auto; margin-bottom: var(--spacing-md); align-self: center; } .gradio-checkbox { margin: 0.75em 1.5em 0 0; align-self: center; } -.gradio-column {min-width: min(160px, 100%) !important;} +.gradio-column { min-width: min(160px, 100%) !important; } .gradio-container { max-width: unset !important; padding: var(--block-label-padding) !important; } .gradio-container .prose a, .gradio-container .prose a:visited{ color: unset; text-decoration: none; } .gradio-dropdown { margin-right: var(--spacing-sm) !important; min-width:160px; max-width:fit-content } -.gradio-dropdown ul.options {z-index: 1000;min-width: fit-content;max-height: 33vh !important;white-space: nowrap;} -.gradio-dropdown ul.options li.item {padding: var(--spacing-xs);} +.gradio-dropdown ul.options { z-index: 1000; min-width: fit-content; max-height: 33vh !important; white-space: nowrap; } +.gradio-dropdown ul.options li.item { padding: var(--spacing-xs); } .gradio-dropdown ul.options li.item:not(:has(.hide)) { background-color: var(--primary-500); } .gradio-dropdown .token { padding: var(--spacing-xs); } .gradio-dropdown span { margin-bottom: 0 !important; font-size: 0.9em; } @@ -48,8 +48,8 @@ textarea { overflow-y: auto !important; } /* custom gradio elements */ .accordion-compact { padding: 8px 0px 4px 0px !important; } -.settings-accordion > div {flex-flow: wrap;} -.small-accordion .form {min-width: var(--left-column) !important;max-width: max-content;} +.settings-accordion > div { flex-flow: wrap; } +.small-accordion .form { min-width: var(--left-column) !important; max-width: max-content; } .small-accordion .label-wrap .icon { margin-right: 1.6em; margin-left: 0.6em; color: var(--button-primary-border-color); } .small-accordion .label-wrap { padding: 16px 0px 8px 0px; margin: 0; border-top: 2px solid var(--button-secondary-border-color); } .small-accordion { width: fit-content !important; padding-left: 0 !important; } @@ -105,16 +105,16 @@ div#extras_scale_to_tab div.form{ flex-direction: row; } #si-sparkline-memo, #si-sparkline-load { background-color: #111; } #quicksettings { width: fit-content; } #quicksettings > button { padding: 0 1em 0 0; align-self: end; margin-bottom: var(--text-sm); } -#settings {display: flex;gap: var(--layout-gap);} -#settings div {border: none;gap: 0;margin: 0 0 var(--layout-gap) 0px;padding: 0;} -#settings > div.tab-content {flex: 10 0 75%;display: grid;} +#settings { display: flex; gap: var(--layout-gap); } +#settings div { border: none; gap: 0; margin: 0 0 var(--layout-gap) 0px; padding: 0; } +#settings > div.tab-content { flex: 10 0 75%; display: grid; } #settings > div.tab-content > div { border: none; padding: 0; } -#settings > div.tab-content > div > div > div > div > div {flex-direction: unset;} -#settings > div.tab-nav {display: grid;grid-template-columns: repeat(auto-fill, .5em minmax(10em, 1fr));flex: 1 0 auto;width: 12em;align-self: flex-start;gap: var(--spacing-xxl);} +#settings > div.tab-content > div > div > div > div > div { flex-direction: unset; } +#settings > div.tab-nav { display: grid; grid-template-columns: repeat(auto-fill, .5em minmax(10em, 1fr)); flex: 1 0 auto; width: 12em; align-self: flex-start; gap: var(--spacing-xxl); } #settings > div.tab-nav button { display: block; border: none; text-align: left; white-space: initial; padding: 0; } #settings > div.tab-nav > #settings_show_all_pages { padding: var(--size-2) var(--size-4); } #settings .block.gradio-checkbox { margin: 0; width: auto; } -#settings .dirtyable {gap: .5em;:;} +#settings .dirtyable { gap: .5em; } #settings .dirtyable.hidden { display: none; } #settings .modification-indicator { height: 1.2em; border-radius: 1em !important; padding: 0; width: 0; margin-right: 0.5em; } #settings .modification-indicator:disabled { visibility: hidden; } @@ -280,45 +280,6 @@ table.settings-value-table td { padding: 0.4em; border: 1px solid #ccc; max-widt --spacing-xxl: 6px; } -/* Apply different styles for devices with coarse pointers dependant on screen resolution */ -@media (hover: none) and (pointer: coarse) { - - /* Screens 400px and smaller */ - @media (max-width: 399px) { - :root, .light, .dark { --left-column: 100%; } - /* maintain single column for from image operations on larger mobile devices */ - #txt2img_results, #img2img_results, #extras_results { min-width: calc(min(320px, 100%)) !important;} - /* maintain single column for from image operations on larger mobile devices */ - #img2img_settings, #img2img_results { min-width: 100% !important; max-width: 100% !important;} - /* fix inpaint image display being too large for mobile displays */ - #img2img_sketch, #img2maskimg, #inpaint_sketch {display: flex;alignment-baseline:after-edge !important;overflow: auto !important;resize: none !important;} - #img2maskimg canvas { width: 100% !important; max-height: 100% !important; height: auto !important; } - - /* fix from text/image UI elements to prevent them from moving around within the UI */ - #txt2img_sampler, #txt2img_batch, #txt2img_seed_group, #txt2img_advanced, #txt2img_second_pass, #img2img_sampling_group, #img2img_resize_group, #img2img_batch_group, #img2img_seed_group, #img2img_denoise_group, #img2img_advanced_group { width: 100% !important; } - - /* adjust slider input fields as they were too large for mobile devices. */ - .gradio-slider input[type="number"] { width: 4em; font-size: 0.8rem; height: 16px; text-align: center; } - - /* Various interface elements default to row, this breaks UI placement on mobile. */ - #component-886, #component-1915, #component-2018 div, #component-2044 div > div, #component-2087 div, #component-2091 div, #component-2140 div, #component-2144 div, #component-3435 div { display:flex; flex-wrap: wrap; align-content:flex-start; flex-direction: column; } - - /* move image preview/output to bottom of page */ - #models_tab { flex-direction: column-reverse !important; } - #component-3464 div { display: flex; flex-direction: row; justify-content: flex-start; flex-wrap: wrap; } - #enqueue_keyboard_shortcut_modifiers, #enqueue_keyboard_shortcut_key div { max-width: 40% !important;} - #component-2906, #component-2953, #component-2957 {max-width: 85%;} - #settings > div.tab-nav {gap: var(--layout-gap);display: flex;flex-wrap: wrap;flex-direction: column;align-content: flex-start;align-items: flex-start;justify-content: flex-start;} - #settings { gap: var(--layout-gap); display: flex; flex-wrap: wrap; flex-direction: row; } - - /* enable scrolling on extensions tab */ - #tab_extensions table, #tab_config table{ border-collapse: collapse; display: block; overflow-x:auto;} - - /* increase scrollbar size to make it finger friendly */ - ::-webkit-scrollbar { width: 25px !important; height:25px; } - - } - /* Apply different styles for devices with coarse pointers dependant on screen resolution */ @media (hover: none) and (pointer: coarse) { @@ -390,4 +351,5 @@ table.settings-value-table td { padding: 0.4em; border: 1px solid #ccc; max-widt .gradio-slider input[type="number"] { width: 4em; font-size: 0.8rem; height: 16px; text-align: center; } #txt2img_settings .block .padded:not(.gradio-accordion) {padding: 0 !important;margin-right: 0; min-width: 100% !important; width:100% !important;} } + } From 2ab4b512c8d4bc33ab71be7d6f25dfcbae4ba35d Mon Sep 17 00:00:00 2001 From: Vladimir Mandic Date: Wed, 22 Nov 2023 18:30:26 -0500 Subject: [PATCH 82/84] update changelog --- CHANGELOG.md | 3 ++- README.md | 8 ++++---- cli/process.py | 2 +- cli/requirements.txt | 2 -- extensions-builtin/sd-webui-controlnet | 2 +- 5 files changed, 8 insertions(+), 9 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 85ee74860..2f1e330cc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,7 +16,7 @@ - Support for [Stable Fast](https://github.com/chengzeyi/stable-fast) model compile on *Windows/Linux/WSL2* with *CUDA* See [Wiki:Benchmark](https://github.com/vladmandic/automatic/wiki/Benchmark) for details and comparisment of different backends, precision modes, advanced settings and compile modes - *Hint*: **100+ it/s** is possible on *RTX4090* with no special tweaks + *Hint*: **70+ it/s** is possible on *RTX4090* with no special tweaks - Add additional pipeline types for manual model loads when loading from `safetensors` - Updated logic for calculating **steps** when using base/hires/refiner workflows - Safe model offloading for non-standard models @@ -44,6 +44,7 @@ - Better Lora trigger words support - Auto refresh styles on change - **General** + - Many **mobile UI** optimizations, thanks @iDeNoh - Support for **Torch 2.1.1** with CUDA 12.1 or CUDA 11.8 - Configurable location for HF cache folder Default is standard `~/.cache/huggingface/hub` diff --git a/README.md b/README.md index 72f8032e4..ac2085039 100644 --- a/README.md +++ b/README.md @@ -48,10 +48,10 @@ All individual features are not listed here, instead check [ChangeLog](CHANGELOG - **Original**: Based on [LDM](https://github.com/Stability-AI/stablediffusion) reference implementation and significantly expanded on by [A1111](https://github.com/AUTOMATIC1111/stable-diffusion-webui) This is the default backend and it is fully compatible with all existing functionality and extensions - It supports **SD 1.x** and **SD 2.x** models + Supports **SD 1.x** and **SD 2.x** models All other model types such as *SD-XL, LCM, PixArt, Segmind, Kandinsky, etc.* require backend **Diffusers** - **Diffusers**: Based on new [Huggingface Diffusers](https://huggingface.co/docs/diffusers/index) implementation - It supports *original* SD models as well as *all* models listed below + Supports *original* SD models as well as *all* models listed below See [wiki article](https://github.com/vladmandic/automatic/wiki/Diffusers) for more information ## Model support @@ -164,9 +164,9 @@ SD.Next comes with several extensions pre-installed: ### **Collab** -- To avoid having this repo rely just on me, I'd love to have additional maintainers with full admin rights. If you're interested, ping me! +- We'd love to have additional maintainers with full admin rights. If you're interested, ping us! - In addition to general cross-platform code, desire is to have a lead for each of the main platforms. -This should be fully cross-platform, but I would really love to have additional contributors and/or maintainers to join and help lead the efforts on different platforms. +This should be fully cross-platform, but we'd really love to have additional contributors and/or maintainers to join and help lead the efforts on different platforms. ### **Goals** diff --git a/cli/process.py b/cli/process.py index d03e6cb16..3bcd97ed9 100644 --- a/cli/process.py +++ b/cli/process.py @@ -182,7 +182,7 @@ def interrogate_image(res: Result, tag: str = None): def resize_image(res: Result): resized = res.image - resized.thumbnail((options.process.target_size, options.process.target_size), Image.HAMMING) + resized.thumbnail((options.process.target_size, options.process.target_size), Image.Resampling.HAMMING) res.image = resized res.ops.append('resize') return res diff --git a/cli/requirements.txt b/cli/requirements.txt index 9452617f0..a63adae95 100644 --- a/cli/requirements.txt +++ b/cli/requirements.txt @@ -2,5 +2,3 @@ mediapipe colormap filetype albumentations -accelerate==0.19.0 -diffusers==0.10.2 diff --git a/extensions-builtin/sd-webui-controlnet b/extensions-builtin/sd-webui-controlnet index aa4747ab5..10bd9b25f 160000 --- a/extensions-builtin/sd-webui-controlnet +++ b/extensions-builtin/sd-webui-controlnet @@ -1 +1 @@ -Subproject commit aa4747ab5f949b5d7aa1ccae238571ddca6ef33f +Subproject commit 10bd9b25f62deab9acb256301bbf3363c42645e7 From 096fd04f53d1c9c9c174e934e190ff64082d0757 Mon Sep 17 00:00:00 2001 From: Vladimir Mandic Date: Thu, 23 Nov 2023 09:42:24 -0500 Subject: [PATCH 83/84] fix model offload on long prompts and update requirements --- CHANGELOG.md | 2 +- modules/interrogate.py | 36 +----------------------------- modules/prompt_parser_diffusers.py | 8 +++---- modules/sd_models.py | 1 - requirements.txt | 4 ++-- 5 files changed, 7 insertions(+), 44 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2f1e330cc..0c6d98907 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,6 @@ # Change Log for SD.Next -## Update for 2023-11-22 +## Update for 2023-11-23 - **Diffusers** - **LCM** support for any *SD 1.5* or *SD-XL* model! diff --git a/modules/interrogate.py b/modules/interrogate.py index 76685dae9..5e7d249de 100644 --- a/modules/interrogate.py +++ b/modules/interrogate.py @@ -12,27 +12,23 @@ from modules import devices, paths, shared, lowvram, modelloader, errors blip_image_eval_size = 384 clip_model_name = 'ViT-L/14' - Category = namedtuple("Category", ["name", "topn", "items"]) - re_topn = re.compile(r"\.top(\d+)\.") + def category_types(): return [f.stem for f in Path(shared.interrogator.content_dir).glob('*.txt')] def download_default_clip_interrogate_categories(content_dir): shared.log.info("Downloading CLIP categories...") - tmpdir = f"{content_dir}_tmp" cat_types = ["artists", "flavors", "mediums", "movements"] - try: os.makedirs(tmpdir, exist_ok=True) for category_type in cat_types: torch.hub.download_url_to_file(f"https://raw.githubusercontent.com/pharmapsychotic/clip-interrogator/main/clip_interrogator/data/{category_type}.txt", os.path.join(tmpdir, f"{category_type}.txt")) os.rename(tmpdir, content_dir) - except Exception as e: errors.display(e, "downloading default CLIP interrogate categories") finally: @@ -56,10 +52,8 @@ class InterrogateModels: def categories(self): if not os.path.exists(self.content_dir): download_default_clip_interrogate_categories(self.content_dir) - if self.loaded_categories is not None and self.skip_categories == shared.opts.interrogate_clip_skip_categories: return self.loaded_categories - self.loaded_categories = [] if os.path.exists(self.content_dir): @@ -74,14 +68,12 @@ class InterrogateModels: with open(filename, "r", encoding="utf8") as file: lines = [x.strip() for x in file.readlines()] self.loaded_categories.append(Category(name=filename.stem, topn=topn, items=lines)) - return self.loaded_categories def create_fake_fairscale(self): class FakeFairscale: def checkpoint_wrapper(self): pass - sys.modules["fairscale.nn.checkpoint.checkpoint_activations"] = FakeFairscale def load_blip_model(self): @@ -95,7 +87,6 @@ class InterrogateModels: ext_filter=[".pth"], download_name='model_base_caption_capfilt_large.pth', ) - blip_model = models.blip.blip_decoder(pretrained=files[0], image_size=blip_image_eval_size, vit='base', med_config=os.path.join(paths.paths["BLIP"], "configs", "med_config.json")) # pylint: disable=c-extension-no-member blip_model.eval() @@ -103,15 +94,12 @@ class InterrogateModels: def load_clip_model(self): import clip - if self.running_on_cpu: model, preprocess = clip.load(clip_model_name, device="cpu", download_root=shared.opts.clip_models_path) else: model, preprocess = clip.load(clip_model_name, download_root=shared.opts.clip_models_path) - model.eval() model = model.to(devices.device_interrogate) - return model, preprocess def load(self): @@ -119,16 +107,12 @@ class InterrogateModels: self.blip_model = self.load_blip_model() if not shared.opts.no_half and not self.running_on_cpu: self.blip_model = self.blip_model.half() - self.blip_model = self.blip_model.to(devices.device_interrogate) - if self.clip_model is None: self.clip_model, self.clip_preprocess = self.load_clip_model() if not shared.opts.no_half and not self.running_on_cpu: self.clip_model = self.clip_model.half() - self.clip_model = self.clip_model.to(devices.device_interrogate) - self.dtype = next(self.clip_model.parameters()).dtype def send_clip_to_ram(self): @@ -144,27 +128,21 @@ class InterrogateModels: def unload(self): self.send_clip_to_ram() self.send_blip_to_ram() - devices.torch_gc() def rank(self, image_features, text_array, top_count=1): import clip - devices.torch_gc() - if shared.opts.interrogate_clip_dict_limit != 0: text_array = text_array[0:int(shared.opts.interrogate_clip_dict_limit)] - top_count = min(top_count, len(text_array)) text_tokens = clip.tokenize(list(text_array), truncate=True).to(devices.device_interrogate) text_features = self.clip_model.encode_text(text_tokens).type(self.dtype) text_features /= text_features.norm(dim=-1, keepdim=True) - similarity = torch.zeros((1, len(text_array))).to(devices.device_interrogate) for i in range(image_features.shape[0]): similarity += (100.0 * image_features[i].unsqueeze(0) @ text_features.T).softmax(dim=-1) similarity /= image_features.shape[0] - top_probs, top_labels = similarity.cpu().topk(top_count, dim=-1) return [(text_array[top_labels[0][i].numpy()], (top_probs[0][i].numpy()*100)) for i in range(top_count)] @@ -174,10 +152,8 @@ class InterrogateModels: transforms.ToTensor(), transforms.Normalize((0.48145466, 0.4578275, 0.40821073), (0.26862954, 0.26130258, 0.27577711)) ])(pil_image).unsqueeze(0).type(self.dtype).to(devices.device_interrogate) - with devices.inference_context(): caption = self.blip_model.generate(gpu_image, sample=False, num_beams=shared.opts.interrogate_clip_num_beams, min_length=shared.opts.interrogate_clip_min_length, max_length=shared.opts.interrogate_clip_max_length) - return caption[0] def interrogate(self, pil_image): @@ -187,22 +163,15 @@ class InterrogateModels: if shared.cmd_opts.lowvram or shared.cmd_opts.medvram: lowvram.send_everything_to_cpu() devices.torch_gc() - self.load() - caption = self.generate_caption(pil_image) self.send_blip_to_ram() devices.torch_gc() - res = caption - clip_image = self.clip_preprocess(pil_image).unsqueeze(0).type(self.dtype).to(devices.device_interrogate) - with devices.inference_context(), devices.autocast(): image_features = self.clip_model.encode_image(clip_image).type(self.dtype) - image_features /= image_features.norm(dim=-1, keepdim=True) - for _name, topn, items in self.categories(): matches = self.rank(image_features, items, top_count=topn) for match, score in matches: @@ -210,12 +179,9 @@ class InterrogateModels: res += f", ({match}:{score/100:.3f})" else: res += f", {match}" - except Exception as e: errors.display(e, 'interrogate') res += "" - self.unload() shared.state.end() - return res diff --git a/modules/prompt_parser_diffusers.py b/modules/prompt_parser_diffusers.py index b9fbf8908..124bbb41d 100644 --- a/modules/prompt_parser_diffusers.py +++ b/modules/prompt_parser_diffusers.py @@ -69,7 +69,7 @@ def encode_prompts(pipeline, prompts: list, negative_prompts: list, clip_skip: t negative_embeds = [] negative_pooleds = [] for i in range(len(prompts)): - prompt_embed, positive_pooled, negative_embed, negative_pooled = get_weighted_text_embeddings(pipeline,prompts[i], negative_prompts[i], clip_skip) + prompt_embed, positive_pooled, negative_embed, negative_pooled = get_weighted_text_embeddings(pipeline, prompts[i], negative_prompts[i], clip_skip) prompt_embeds.append(prompt_embed) positive_pooleds.append(positive_pooled) negative_embeds.append(negative_embed) @@ -119,8 +119,7 @@ def pad_to_same_length(embeds): empty_embed = shared.sd_model.encode_prompt("") except Exception: #SD1.5 empty_embed = shared.sd_model.encode_prompt("",shared.sd_model.device, 1, False) - - empty_batched = torch.cat([empty_embed[0]] * embeds[0].shape[0]) + empty_batched = torch.cat([empty_embed[0].to(embeds[0].device)] * embeds[0].shape[0]) max_token_count = max([embed.shape[1] for embed in embeds]) for i, embed in enumerate(embeds): while embed.shape[1] < max_token_count: @@ -152,7 +151,6 @@ def get_weighted_text_embeddings(pipe, prompt: str = "", neg_prompt: str = "", c negative_prompt_embeds = [] pooled_prompt_embeds = None negative_pooled_prompt_embeds = None - for i in range(len(embedding_providers)): # add BREAK keyword that splits the prompt into multiple fragments text = positives[i] @@ -168,7 +166,7 @@ def get_weighted_text_embeddings(pipe, prompt: str = "", neg_prompt: str = "", c weights = weights[pos+1:] prompt_embeds.append(torch.cat(provider_embed, dim=1)) # negative prompt has no keywords - embed, ntokens = embedding_providers[i].get_embeddings_for_weighted_prompt_fragments(text_batch=[negatives[i]], fragment_weights_batch=[negative_weights[i]],device=pipe.device, should_return_tokens=True) + embed, ntokens = embedding_providers[i].get_embeddings_for_weighted_prompt_fragments(text_batch=[negatives[i]], fragment_weights_batch=[negative_weights[i]], device=pipe.device, should_return_tokens=True) negative_prompt_embeds.append(embed) if prompt_embeds[-1].shape[-1] > 768: diff --git a/modules/sd_models.py b/modules/sd_models.py index dc74a17c1..dccba9fe8 100644 --- a/modules/sd_models.py +++ b/modules/sd_models.py @@ -1106,7 +1106,6 @@ def load_model(checkpoint_info=None, already_loaded_state_dict=None, timer=None, shared.log.debug(f"Model created from config: {checkpoint_config}") sd_model.used_config = checkpoint_config sd_model.has_accelerate = False - sd_model.is_sdxl = False # a1111 compatibility item timer.record("create") ok = load_model_weights(sd_model, checkpoint_info, state_dict, timer) if not ok: diff --git a/requirements.txt b/requirements.txt index 7e5eaefc0..bbe4874e4 100644 --- a/requirements.txt +++ b/requirements.txt @@ -49,7 +49,7 @@ clip-interrogator==0.6.0 antlr4-python3-runtime==4.9.3 requests==2.31.0 tqdm==4.66.1 -accelerate==0.20.3 +accelerate==0.24.1 opencv-python-headless==4.7.0.72 diffusers==0.23.1 einops==0.4.1 @@ -61,7 +61,7 @@ numba==0.57.1 pandas==1.5.3 protobuf==3.20.3 pytorch_lightning==1.9.4 -transformers==4.35.1 +transformers==4.35.2 tomesd==0.1.3 urllib3==1.26.15 Pillow==10.1.0 From 567b9dd4359610445ba4186d3e413b36f7f6764e Mon Sep 17 00:00:00 2001 From: Vladimir Mandic Date: Thu, 23 Nov 2023 10:31:46 -0500 Subject: [PATCH 84/84] offloading deal with meta tensors --- CHANGELOG.md | 2 +- installer.py | 2 +- modules/prompt_parser_diffusers.py | 31 ++++++++++++++++-------------- 3 files changed, 19 insertions(+), 16 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0c6d98907..a836912cd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,6 +19,7 @@ *Hint*: **70+ it/s** is possible on *RTX4090* with no special tweaks - Add additional pipeline types for manual model loads when loading from `safetensors` - Updated logic for calculating **steps** when using base/hires/refiner workflows + - Improve **model offloading** for both model and sequential cpu offload when dealing with meta tensors - Safe model offloading for non-standard models - Fix **DPM SDE** scheduler - Better support for SD 1.5 **inpainting** models @@ -26,7 +27,6 @@ - Enhance prompt parsing with long prompts and support for *BREAK* keyword Change-in-behavior: new line in prompt now means *BREAK* - Add alternative Lora loading algorithm, triggered if `SD_LORA_DIFFUSERS` is set - - Update to `diffusers==0.23.0` - **Models** - **Model merge** - completely redesigned, now based on best-of-class `meh` by @s1dlx diff --git a/installer.py b/installer.py index d81f9a141..e5aaeceed 100644 --- a/installer.py +++ b/installer.py @@ -190,7 +190,7 @@ def installed(package, friendly: str = None, reload = False, quiet = False): if args.experimental: log.warning(f"Package allowing experimental: {p[0]} {package_version} required {p[1]}") else: - log.warning(f"Package wrong version: {p[0]} {package_version} required {p[1]}") + log.warning(f"Package version mismatch: {p[0]} {package_version} required {p[1]}") else: if not quiet: log.debug(f"Package not found: {p[0]}") diff --git a/modules/prompt_parser_diffusers.py b/modules/prompt_parser_diffusers.py index 124bbb41d..735cf995a 100644 --- a/modules/prompt_parser_diffusers.py +++ b/modules/prompt_parser_diffusers.py @@ -3,7 +3,7 @@ import typing import torch from compel import ReturnedEmbeddingsType from compel.embeddings_provider import BaseTextualInversionManager, EmbeddingsProvider -from modules import shared, prompt_parser +from modules import shared, prompt_parser, devices debug = shared.log.info if os.environ.get('SD_PROMPT_DEBUG', None) is not None else lambda *args, **kwargs: None @@ -97,6 +97,7 @@ def get_prompts_with_weights(prompt: str): def prepare_embedding_providers(pipe, clip_skip): + device = pipe.device if str(pipe.device) != 'meta' else devices.device embeddings_providers = [] if 'XL' in pipe.__class__.__name__: embedding_type = ReturnedEmbeddingsType.PENULTIMATE_HIDDEN_STATES_NON_NORMALIZED @@ -106,19 +107,20 @@ def prepare_embedding_providers(pipe, clip_skip): clip_skip = 2 embedding_type = CLIP_SKIP_MAPPING[clip_skip] if getattr(pipe, "tokenizer", None) is not None and getattr(pipe, "text_encoder", None) is not None: - embedding = EmbeddingsProvider(tokenizer=pipe.tokenizer, text_encoder=pipe.text_encoder, truncate=False, returned_embeddings_type=embedding_type, device=pipe.device) + embedding = EmbeddingsProvider(tokenizer=pipe.tokenizer, text_encoder=pipe.text_encoder, truncate=False, returned_embeddings_type=embedding_type, device=device) embeddings_providers.append(embedding) if getattr(pipe, "tokenizer_2", None) is not None and getattr(pipe, "text_encoder_2", None) is not None: - embedding = EmbeddingsProvider(tokenizer=pipe.tokenizer_2, text_encoder=pipe.text_encoder_2, truncate=False, returned_embeddings_type=embedding_type, device=pipe.device) + embedding = EmbeddingsProvider(tokenizer=pipe.tokenizer_2, text_encoder=pipe.text_encoder_2, truncate=False, returned_embeddings_type=embedding_type, device=device) embeddings_providers.append(embedding) return embeddings_providers -def pad_to_same_length(embeds): +def pad_to_same_length(pipe, embeds): + device = pipe.device if str(pipe.device) != 'meta' else devices.device try: #SDXL empty_embed = shared.sd_model.encode_prompt("") except Exception: #SD1.5 - empty_embed = shared.sd_model.encode_prompt("",shared.sd_model.device, 1, False) + empty_embed = shared.sd_model.encode_prompt("", device, 1, False) empty_batched = torch.cat([empty_embed[0].to(embeds[0].device)] * embeds[0].shape[0]) max_token_count = max([embed.shape[1] for embed in embeds]) for i, embed in enumerate(embeds): @@ -129,6 +131,7 @@ def pad_to_same_length(embeds): def get_weighted_text_embeddings(pipe, prompt: str = "", neg_prompt: str = "", clip_skip: int = None): + device = pipe.device if str(pipe.device) != 'meta' else devices.device prompt_2 = prompt.split("TE2:")[-1] neg_prompt_2 = neg_prompt.split("TE2:")[-1] prompt = prompt.split("TE2:")[0] @@ -160,35 +163,35 @@ def get_weighted_text_embeddings(pipe, prompt: str = "", neg_prompt: str = "", c provider_embed = [] while 'BREAK' in text: pos = text.index('BREAK') - embed, ptokens = embedding_providers[i].get_embeddings_for_weighted_prompt_fragments(text_batch=[text[:pos]], fragment_weights_batch=[weights[:pos]], device=pipe.device, should_return_tokens=True) + embed, ptokens = embedding_providers[i].get_embeddings_for_weighted_prompt_fragments(text_batch=[text[:pos]], fragment_weights_batch=[weights[:pos]], device=device, should_return_tokens=True) provider_embed.append(embed) text = text[pos+1:] weights = weights[pos+1:] prompt_embeds.append(torch.cat(provider_embed, dim=1)) # negative prompt has no keywords - embed, ntokens = embedding_providers[i].get_embeddings_for_weighted_prompt_fragments(text_batch=[negatives[i]], fragment_weights_batch=[negative_weights[i]], device=pipe.device, should_return_tokens=True) + embed, ntokens = embedding_providers[i].get_embeddings_for_weighted_prompt_fragments(text_batch=[negatives[i]], fragment_weights_batch=[negative_weights[i]], device=device, should_return_tokens=True) negative_prompt_embeds.append(embed) if prompt_embeds[-1].shape[-1] > 768: if shared.opts.diffusers_pooled == "weighted": pooled_prompt_embeds = prompt_embeds[-1][ - torch.arange(prompt_embeds[-1].shape[0], device=pipe.device), - (ptokens.to(dtype=torch.int, device=pipe.device) == 49407) + torch.arange(prompt_embeds[-1].shape[0], device=device), + (ptokens.to(dtype=torch.int, device=device) == 49407) .int() .argmax(dim=-1), ] negative_pooled_prompt_embeds = negative_prompt_embeds[-1][ - torch.arange(negative_prompt_embeds[-1].shape[0], device=pipe.device), - (ntokens.to(dtype=torch.int, device=pipe.device) == 49407) + torch.arange(negative_prompt_embeds[-1].shape[0], device=device), + (ntokens.to(dtype=torch.int, device=device) == 49407) .int() .argmax(dim=-1), ] else: - pooled_prompt_embeds = embedding_providers[-1].get_pooled_embeddings(texts=[prompt_2], device=pipe.device) if prompt_embeds[-1].shape[-1] > 768 else None - negative_pooled_prompt_embeds = embedding_providers[-1].get_pooled_embeddings(texts=[neg_prompt_2], device=pipe.device) if negative_prompt_embeds[-1].shape[-1] > 768 else None + pooled_prompt_embeds = embedding_providers[-1].get_pooled_embeddings(texts=[prompt_2], device=device) if prompt_embeds[-1].shape[-1] > 768 else None + negative_pooled_prompt_embeds = embedding_providers[-1].get_pooled_embeddings(texts=[neg_prompt_2], device=device) if negative_prompt_embeds[-1].shape[-1] > 768 else None prompt_embeds = torch.cat(prompt_embeds, dim=-1) if len(prompt_embeds) > 1 else prompt_embeds[0] negative_prompt_embeds = torch.cat(negative_prompt_embeds, dim=-1) if len(negative_prompt_embeds) > 1 else negative_prompt_embeds[0] if prompt_embeds.shape[1] != negative_prompt_embeds.shape[1]: - [prompt_embeds, negative_prompt_embeds] = pad_to_same_length([prompt_embeds, negative_prompt_embeds]) + [prompt_embeds, negative_prompt_embeds] = pad_to_same_length(pipe, [prompt_embeds, negative_prompt_embeds]) return prompt_embeds, pooled_prompt_embeds, negative_prompt_embeds, negative_pooled_prompt_embeds
TimeTime Level Facility Module