diff --git a/CHANGELOG.md b/CHANGELOG.md index 1721e40d5..414b964d1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,13 @@ # Change Log for SD.Next +## Update for 2024-12-25 + +### Post release + +- Add granular VAE tiling options in *settings -> variable auto encoder* +- Add legacy option to use old LoRA loader in *settings -> networks* +- Add sigma calculation to VAE preview, thanks @Disty0 + ## Update for 2024-12-24 ### Highlights for 2024-12-24 diff --git a/extensions-builtin/Lora/extra_networks_lora.py b/extensions-builtin/Lora/extra_networks_lora.py index 307d8cc13..76d490eda 100644 --- a/extensions-builtin/Lora/extra_networks_lora.py +++ b/extensions-builtin/Lora/extra_networks_lora.py @@ -129,7 +129,7 @@ class ExtraNetworkLora(extra_networks.ExtraNetwork): if len(networks.loaded_networks) > 0 and step == 0: self.infotext(p) self.prompt(p) - shared.log.info(f'Load network: type=LoRA apply={[n.name for n in networks.loaded_networks]} te={te_multipliers} unet={unet_multipliers} dims={dyn_dims} load={t1-t0:.2f}') + shared.log.info(f'Load network: type=LoRA apply={[n.name for n in networks.loaded_networks]} method=legacy te={te_multipliers} unet={unet_multipliers} dims={dyn_dims} load={t1-t0:.2f}') def deactivate(self, p): t0 = time.time() diff --git a/extensions-builtin/Lora/networks.py b/extensions-builtin/Lora/networks.py index fd6287c62..1f02f3846 100644 --- a/extensions-builtin/Lora/networks.py +++ b/extensions-builtin/Lora/networks.py @@ -182,11 +182,11 @@ def load_network(name, network_on_disk) -> network.Network: else: net.modules[key] = net_module if len(keys_failed_to_match) > 0: - shared.log.warning(f'LoRA name="{name}" type={set(network_types)} unmatched={len(keys_failed_to_match)} matched={len(matched_networks)}') + shared.log.warning(f'Load network: type=LoRA name="{name}" type={set(network_types)} unmatched={len(keys_failed_to_match)} matched={len(matched_networks)}') if debug: - shared.log.debug(f'LoRA name="{name}" unmatched={keys_failed_to_match}') + shared.log.debug(f'Load network: type=LoRA name="{name}" unmatched={keys_failed_to_match}') else: - shared.log.debug(f'LoRA name="{name}" type={set(network_types)} keys={len(matched_networks)}') + shared.log.debug(f'Load network: type=LoRA name="{name}" type={set(network_types)} keys={len(matched_networks)}') if len(matched_networks) == 0: return None lora_cache[name] = net diff --git a/extensions-builtin/Lora/scripts/lora_script.py b/extensions-builtin/Lora/scripts/lora_script.py index 24723dd7f..5e833aced 100644 --- a/extensions-builtin/Lora/scripts/lora_script.py +++ b/extensions-builtin/Lora/scripts/lora_script.py @@ -57,7 +57,8 @@ def infotext_pasted(infotext, d): # pylint: disable=unused-argument d["Prompt"] = re.sub(re_lora, network_replacement, d["Prompt"]) -if not shared.native: +if shared.opts.lora_legacy: + shared.log.debug('Register network: type=LoRA method=legacy') script_callbacks.on_app_started(api_networks) script_callbacks.on_before_ui(before_ui) script_callbacks.on_model_loaded(networks.assign_network_names_to_compvis_modules) diff --git a/modules/extensions.py b/modules/extensions.py index ccd92dbf0..c2e8dceb7 100644 --- a/modules/extensions.py +++ b/modules/extensions.py @@ -154,4 +154,4 @@ def list_extensions(): for dirname, path, is_builtin in extension_paths: extension = Extension(name=dirname, path=path, enabled=dirname not in disabled_extensions, is_builtin=is_builtin) extensions.append(extension) - shared.log.debug(f'Disabled extensions: {[e.name for e in extensions if not e.enabled]}') + shared.log.debug(f'Extensions disabled: {[e.name for e in extensions if not e.enabled]}') diff --git a/modules/extra_networks.py b/modules/extra_networks.py index fe141cca1..8bd742ce0 100644 --- a/modules/extra_networks.py +++ b/modules/extra_networks.py @@ -18,7 +18,7 @@ def register_extra_network(extra_network): def register_default_extra_networks(): from modules.ui_extra_networks_styles import ExtraNetworkStyles register_extra_network(ExtraNetworkStyles()) - if shared.native: + if not shared.opts.lora_legacy: from modules.lora.networks import extra_network_lora register_extra_network(extra_network_lora) if shared.opts.hypernetwork_enabled: diff --git a/modules/lora/networks.py b/modules/lora/networks.py index edb826080..9103fee37 100644 --- a/modules/lora/networks.py +++ b/modules/lora/networks.py @@ -131,11 +131,11 @@ def load_safetensors(name, network_on_disk) -> Union[network.Network, None]: else: net.modules[key] = net_module if len(keys_failed_to_match) > 0: - shared.log.warning(f'LoRA name="{name}" type={set(network_types)} unmatched={len(keys_failed_to_match)} matched={len(matched_networks)}') + shared.log.warning(f'Load network: type=LoRA name="{name}" type={set(network_types)} unmatched={len(keys_failed_to_match)} matched={len(matched_networks)}') if debug: - shared.log.debug(f'LoRA name="{name}" unmatched={keys_failed_to_match}') + shared.log.debug(f'Load network: type=LoRA name="{name}" unmatched={keys_failed_to_match}') else: - shared.log.debug(f'LoRA name="{name}" type={set(network_types)} keys={len(matched_networks)} direct={shared.opts.lora_fuse_diffusers}') + shared.log.debug(f'Load network: type=LoRA name="{name}" type={set(network_types)} keys={len(matched_networks)} direct={shared.opts.lora_fuse_diffusers}') if len(matched_networks) == 0: return None lora_cache[name] = net @@ -311,8 +311,14 @@ def network_backup_weights(self: Union[torch.nn.Conv2d, torch.nn.Linear, torch.n t0 = time.time() weights_backup = getattr(self, "network_weights_backup", None) - if (shared.opts.lora_fuse_diffusers and not isinstance(weights_backup, bool)) or (not shared.opts.lora_fuse_diffusers and isinstance(weights_backup, bool)): - weights_backup = None # invalidate so we can change direct/backup on-the-fly + bias_backup = getattr(self, "network_bias_backup", None) + if weights_backup is not None or bias_backup is not None: + if (shared.opts.lora_fuse_diffusers and not isinstance(weights_backup, bool)) or (not shared.opts.lora_fuse_diffusers and isinstance(weights_backup, bool)): # invalidate so we can change direct/backup on-the-fly + weights_backup = None + bias_backup = None + self.network_weights_backup = weights_backup + self.network_bias_backup = bias_backup + if weights_backup is None and wanted_names != (): # pylint: disable=C1803 weight = getattr(self, 'weight', None) self.network_weights_backup = None @@ -340,7 +346,6 @@ def network_backup_weights(self: Union[torch.nn.Conv2d, torch.nn.Linear, torch.n else: self.network_weights_backup = weight.clone().to(devices.cpu) - bias_backup = getattr(self, "network_bias_backup", None) if bias_backup is None: if getattr(self, 'bias', None) is not None: if shared.opts.lora_fuse_diffusers: @@ -407,6 +412,10 @@ def network_calc_weights(self: Union[torch.nn.Conv2d, torch.nn.Linear, torch.nn. def network_apply_direct(self: Union[torch.nn.Conv2d, torch.nn.Linear, torch.nn.GroupNorm, torch.nn.LayerNorm, diffusers.models.lora.LoRACompatibleLinear, diffusers.models.lora.LoRACompatibleConv], updown: torch.Tensor, ex_bias: torch.Tensor, deactivate: bool = False): weights_backup = getattr(self, "network_weights_backup", False) bias_backup = getattr(self, "network_bias_backup", False) + if not isinstance(weights_backup, bool): + weights_backup = True + if not isinstance(bias_backup, bool): + bias_backup = True if not weights_backup and not bias_backup: return None, None t0 = time.time() diff --git a/modules/sd_models.py b/modules/sd_models.py index a52e15e7e..184a242af 100644 --- a/modules/sd_models.py +++ b/modules/sd_models.py @@ -226,15 +226,7 @@ def copy_diffuser_options(new_pipe, orig_pipe): set_accelerate(new_pipe) -def set_diffuser_options(sd_model, vae = None, op: str = 'model', offload=True): - if sd_model is None: - shared.log.warning(f'{op} is not loaded') - return - - if hasattr(sd_model, "watermark"): - sd_model.watermark = NoWatermark() - if not (hasattr(sd_model, "has_accelerate") and sd_model.has_accelerate): - sd_model.has_accelerate = False +def set_vae_options(sd_model, vae = None, op: str = 'model'): if hasattr(sd_model, "vae"): if vae is not None: sd_model.vae = vae @@ -254,7 +246,13 @@ def set_diffuser_options(sd_model, vae = None, op: str = 'model', offload=True): sd_model.disable_vae_slicing() if hasattr(sd_model, "enable_vae_tiling"): if shared.opts.diffusers_vae_tiling: - shared.log.debug(f'Setting {op}: component=VAE tiling=True') + if hasattr(sd_model, 'vae') and hasattr(sd_model.vae, 'config') and hasattr(sd_model.vae.config, 'sample_size') and isinstance(sd_model.vae.config.sample_size, int): + sd_model.vae.tile_sample_min_size = int(shared.opts.diffusers_vae_tile_size) + sd_model.vae.tile_latent_min_size = int(sd_model.vae.config.sample_size / (2 ** (len(sd_model.vae.config.block_out_channels) - 1))) + sd_model.vae.tile_overlap_factor = float(shared.opts.diffusers_vae_tile_overlap) + shared.log.debug(f'Setting {op}: component=VAE tiling=True tile={sd_model.vae.tile_sample_min_size} overlap={sd_model.vae.tile_overlap_factor}') + else: + shared.log.debug(f'Setting {op}: component=VAE tiling=True') sd_model.enable_vae_tiling() else: sd_model.disable_vae_tiling() @@ -262,6 +260,18 @@ def set_diffuser_options(sd_model, vae = None, op: str = 'model', offload=True): shared.log.debug(f'Setting {op}: component=VQVAE upcast=True') sd_model.vqvae.to(torch.float32) # vqvae is producing nans in fp16 + +def set_diffuser_options(sd_model, vae = None, op: str = 'model', offload=True): + if sd_model is None: + shared.log.warning(f'{op} is not loaded') + return + + if hasattr(sd_model, "watermark"): + sd_model.watermark = NoWatermark() + if not (hasattr(sd_model, "has_accelerate") and sd_model.has_accelerate): + sd_model.has_accelerate = False + + set_vae_options(sd_model, vae, op) set_diffusers_attention(sd_model) if shared.opts.diffusers_fuse_projections and hasattr(sd_model, 'fuse_qkv_projections'): diff --git a/modules/shared.py b/modules/shared.py index 31429e076..791bbe67f 100644 --- a/modules/shared.py +++ b/modules/shared.py @@ -366,7 +366,7 @@ def list_samplers(): def temp_disable_extensions(): disable_safe = ['sd-webui-controlnet', 'multidiffusion-upscaler-for-automatic1111', 'a1111-sd-webui-lycoris', 'sd-webui-agent-scheduler', 'clip-interrogator-ext', 'stable-diffusion-webui-rembg', 'sd-extension-chainner', 'stable-diffusion-webui-images-browser'] - disable_diffusers = ['sd-webui-controlnet', 'multidiffusion-upscaler-for-automatic1111', 'a1111-sd-webui-lycoris', 'sd-webui-animatediff', 'Lora'] + disable_diffusers = ['sd-webui-controlnet', 'multidiffusion-upscaler-for-automatic1111', 'a1111-sd-webui-lycoris', 'sd-webui-animatediff'] disable_themes = ['sd-webui-lobe-theme', 'cozy-nest', 'sdnext-modernui'] disable_original = [] disabled = [] @@ -422,6 +422,8 @@ def temp_disable_extensions(): for ext in disable_original: if ext.lower() not in opts.disabled_extensions: disabled.append(ext) + if not opts.lora_legacy: + disabled.append('Lora') cmd_opts.controlnet_loglevel = 'WARNING' return disabled @@ -504,6 +506,8 @@ options_templates.update(options_section(('vae_encoder', "Variable Auto Encoder" "no_half_vae": OptionInfo(False if not cmd_opts.use_openvino else True, "Full precision (--no-half-vae)"), "diffusers_vae_slicing": OptionInfo(True, "VAE slicing", gr.Checkbox, {"visible": native}), "diffusers_vae_tiling": OptionInfo(cmd_opts.lowvram or cmd_opts.medvram, "VAE tiling", gr.Checkbox, {"visible": native}), + "diffusers_vae_tile_size": OptionInfo(1024, "VAE tile size", gr.Slider, {"minimum": 256, "maximum": 4096, "step": 8 }), + "diffusers_vae_tile_overlap": OptionInfo(0.1, "VAE tile overlap", gr.Slider, {"minimum": 0, "maximum": 0.9, "step": 0.1 }), "sd_vae_sliced_encode": OptionInfo(False, "VAE sliced encode", gr.Checkbox, {"visible": not native}), "nan_skip": OptionInfo(False, "Skip Generation if NaN found in latents", gr.Checkbox), "rollback_vae": OptionInfo(False, "Attempt VAE roll back for NaN values"), @@ -924,8 +928,9 @@ options_templates.update(options_section(('extra_networks', "Networks"), { "lora_preferred_name": OptionInfo("filename", "LoRA preferred name", gr.Radio, {"choices": ["filename", "alias"], "visible": False}), "lora_add_hashes_to_infotext": OptionInfo(False, "LoRA add hash info to metadata"), "lora_fuse_diffusers": OptionInfo(True, "LoRA fuse directly to model"), - "lora_force_diffusers": OptionInfo(False if not cmd_opts.use_openvino else True, "LoRA force loading of all models using Diffusers"), - "lora_maybe_diffusers": OptionInfo(False, "LoRA force loading of specific models using Diffusers"), + "lora_legacy": OptionInfo(not native, "LoRA load using legacy method"), + "lora_force_diffusers": OptionInfo(False if not cmd_opts.use_openvino else True, "LoRA load using Diffusers method"), + "lora_maybe_diffusers": OptionInfo(False, "LoRA load using Diffusers method for selected models"), "lora_apply_tags": OptionInfo(0, "LoRA auto-apply tags", gr.Slider, {"minimum": -1, "maximum": 32, "step": 1}), "lora_in_memory_limit": OptionInfo(0, "LoRA memory cache", gr.Slider, {"minimum": 0, "maximum": 24, "step": 1}), "lora_quant": OptionInfo("NF4","LoRA precision when quantized", gr.Radio, {"choices": ["NF4", "FP4"]}), diff --git a/webui.py b/webui.py index 4eb6e89ce..85725efe4 100644 --- a/webui.py +++ b/webui.py @@ -100,7 +100,7 @@ def initialize(): modules.sd_models.setup_model() timer.startup.record("models") - if shared.native: + if not shared.opts.lora_legacy: import modules.lora.networks as lora_networks lora_networks.list_available_networks() timer.startup.record("lora") diff --git a/wiki b/wiki index 22951c981..b2b403682 160000 --- a/wiki +++ b/wiki @@ -1 +1 @@ -Subproject commit 22951c9818e44f3bfeecfd06b1c154230f711ea7 +Subproject commit b2b4036823c82e487fb5529c731a57b3fe77a1a3