From 2cd5964c9b9e5326f9aaa669a5905a5232c59597 Mon Sep 17 00:00:00 2001 From: Vladimir Mandic Date: Wed, 27 Sep 2023 12:06:14 -0400 Subject: [PATCH] add sigma min/max --- README.md | 6 +-- extensions-builtin/LDSR/preload.py | 6 --- installer.py | 2 +- .../LDSR => modules/ldsr}/ldsr_model_arch.py | 4 +- .../ldsr}/sd_hijack_autoencoder.py | 8 ++-- .../ldsr}/sd_hijack_ddpm_v1.py | 8 ++-- modules/lora_diffusers.py | 17 +++------ modules/lycoris | 2 +- .../postprocess}/ldsr_model.py | 10 ++--- modules/processing.py | 16 ++++---- modules/sd_samplers_diffusers.py | 2 +- modules/sd_samplers_kdiffusion.py | 9 +++-- modules/shared.py | 9 +++-- scripts/xyz_grid.py | 38 ++++++++++--------- 14 files changed, 65 insertions(+), 72 deletions(-) delete mode 100644 extensions-builtin/LDSR/preload.py rename {extensions-builtin/LDSR => modules/ldsr}/ldsr_model_arch.py (99%) rename {extensions-builtin/LDSR => modules/ldsr}/sd_hijack_autoencoder.py (99%) rename {extensions-builtin/LDSR => modules/ldsr}/sd_hijack_ddpm_v1.py (99%) rename {extensions-builtin/LDSR/scripts => modules/postprocess}/ldsr_model.py (91%) diff --git a/README.md b/README.md index bc1f07692..0e6422aa2 100644 --- a/README.md +++ b/README.md @@ -15,9 +15,6 @@ -This project started as a fork from [Automatic1111 WebUI](https://github.com/AUTOMATIC1111/stable-diffusion-webui/) and it grew significantly since then, -but although it diverged considerably, any substantial features to original work is ported to this repository as well. - ## Top-13 Features (10 wasn't enough) All Individual features are not listed here, instead check [ChangeLog](CHANGELOG.md) for full list of changes. @@ -138,6 +135,9 @@ This should be fully cross-platform, but I would really love to have additional ### **Goals** +This project started as a fork from [Automatic1111 WebUI](https://github.com/AUTOMATIC1111/stable-diffusion-webui/) and it grew significantly since then, +but although it diverged considerably, any substantial features to original work is ported to this repository as well. + 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".* diff --git a/extensions-builtin/LDSR/preload.py b/extensions-builtin/LDSR/preload.py deleted file mode 100644 index cfd478d54..000000000 --- a/extensions-builtin/LDSR/preload.py +++ /dev/null @@ -1,6 +0,0 @@ -import os -from modules import paths - - -def preload(parser): - parser.add_argument("--ldsr-models-path", type=str, help="Path to directory with LDSR model file(s).", default=os.path.join(paths.models_path, 'LDSR')) diff --git a/installer.py b/installer.py index f18754e69..55af08dd7 100644 --- a/installer.py +++ b/installer.py @@ -399,7 +399,7 @@ def check_torch(): torch_command = os.environ.get('TORCH_COMMAND', f'torchvision --pre --index-url https://download.pytorch.org/whl/nightly/rocm{rocm_ver}') elif rocm_ver in ['5.7']: # there is no torch nightly for rocm 5.7 yet - torch_command = os.environ.get('TORCH_COMMAND', f'torchvision --pre --index-url https://download.pytorch.org/whl/nightly/rocm5.6') + torch_command = os.environ.get('TORCH_COMMAND', 'torchvision --pre --index-url https://download.pytorch.org/whl/nightly/rocm5.6') else: torch_command = os.environ.get('TORCH_COMMAND', 'torch==2.0.1 torchvision==0.15.2 --index-url https://download.pytorch.org/whl/rocm5.4.2') xformers_package = os.environ.get('XFORMERS_PACKAGE', 'none') diff --git a/extensions-builtin/LDSR/ldsr_model_arch.py b/modules/ldsr/ldsr_model_arch.py similarity index 99% rename from extensions-builtin/LDSR/ldsr_model_arch.py rename to modules/ldsr/ldsr_model_arch.py index 407241e65..55a217589 100644 --- a/extensions-builtin/LDSR/ldsr_model_arch.py +++ b/modules/ldsr/ldsr_model_arch.py @@ -1,7 +1,5 @@ import os -import gc import time - import numpy as np import torch import torchvision @@ -9,7 +7,6 @@ from PIL import Image from einops import rearrange, repeat from omegaconf import OmegaConf import safetensors.torch - from ldm.models.diffusion.ddim import DDIMSampler from ldm.util import instantiate_from_config, ismap from modules import devices, shared, sd_hijack @@ -133,6 +130,7 @@ class LDSR: if shared.opts.upscaler_unload: del model + global cached_ldsr_model # pylint: disable=global-statement cached_ldsr_model = None shared.log.debug(f"Upscaler unloaded: type=LDSR model={self.modelPath}") devices.torch_gc(force=True) diff --git a/extensions-builtin/LDSR/sd_hijack_autoencoder.py b/modules/ldsr/sd_hijack_autoencoder.py similarity index 99% rename from extensions-builtin/LDSR/sd_hijack_autoencoder.py rename to modules/ldsr/sd_hijack_autoencoder.py index a0e8fefe0..6722c190a 100644 --- a/extensions-builtin/LDSR/sd_hijack_autoencoder.py +++ b/modules/ldsr/sd_hijack_autoencoder.py @@ -1,14 +1,14 @@ # The content of this file comes from the ldm/models/autoencoder.py file of the compvis/stable-diffusion repo # The VQModel & VQModelInterface were subsequently removed from ldm/models/autoencoder.py when we moved to the stability-ai/stablediffusion repo # As the LDSR upscaler relies on VQModel & VQModelInterface, the hijack aims to put them back into the ldm.models.autoencoder +from contextlib import contextmanager import numpy as np import torch import pytorch_lightning as pl import torch.nn.functional as F -from contextlib import contextmanager from torch.optim.lr_scheduler import LambdaLR -from ldm.modules.ema import LitEma from taming.modules.vqvae.quantize import VectorQuantizer2 as VectorQuantizer +from ldm.modules.ema import LitEma from ldm.modules.diffusionmodules.model import Encoder, Decoder from ldm.util import instantiate_from_config @@ -85,7 +85,7 @@ class VQModel(pl.LightningModule): for k in keys: for ik in ignore_keys or []: if k.startswith(ik): - print("Deleting key {} from state_dict.".format(k)) + print(f"Deleting key {k} from state_dict.") del sd[k] missing, unexpected = self.load_state_dict(sd, strict=False) print(f"Restored from {path} with {len(missing)} missing and {len(unexpected)} unexpected keys") @@ -137,7 +137,7 @@ class VQModel(pl.LightningModule): # do the first few batches with max size to avoid later oom new_resize = upper_size else: - new_resize = np.random.choice(np.arange(lower_size, upper_size+16, 16)) + new_resize = np.random.choice(np.arange(lower_size, upper_size+16, 16)) # noqa: NPY002 if new_resize != x.shape[2]: x = F.interpolate(x, size=new_resize, mode="bicubic") x = x.detach() diff --git a/extensions-builtin/LDSR/sd_hijack_ddpm_v1.py b/modules/ldsr/sd_hijack_ddpm_v1.py similarity index 99% rename from extensions-builtin/LDSR/sd_hijack_ddpm_v1.py rename to modules/ldsr/sd_hijack_ddpm_v1.py index 053be8290..fe86425fd 100644 --- a/extensions-builtin/LDSR/sd_hijack_ddpm_v1.py +++ b/modules/ldsr/sd_hijack_ddpm_v1.py @@ -15,14 +15,12 @@ from functools import partial from tqdm import tqdm from torchvision.utils import make_grid from pytorch_lightning.utilities.distributed import rank_zero_only - from ldm.util import log_txt_as_img, exists, default, ismap, isimage, mean_flat, count_params, instantiate_from_config from ldm.modules.ema import LitEma from ldm.modules.distributions.distributions import normal_kl, DiagonalGaussianDistribution from ldm.models.autoencoder import VQModelInterface, IdentityFirstStage, AutoencoderKL from ldm.modules.diffusionmodules.util import make_beta_schedule, extract_into_tensor, noise_like from ldm.models.diffusion.ddim import DDIMSampler - import ldm.models.diffusion.ddpm __conditioning_keys__ = {'concat': 'c_concat', @@ -1010,7 +1008,7 @@ class LatentDiffusionV1(DDPMV1): elif self.parameterization == "eps": target = noise else: - raise NotImplementedError() + raise NotImplementedError loss_simple = self.get_loss(model_output, target, mean=False).mean([1, 2, 3]) loss_dict.update({f'{prefix}/loss_simple': loss_simple.mean()}) @@ -1049,7 +1047,7 @@ class LatentDiffusionV1(DDPMV1): elif self.parameterization == "x0": x_recon = model_out else: - raise NotImplementedError() + raise NotImplementedError if clip_denoised: x_recon.clamp_(-1., 1.) @@ -1408,7 +1406,7 @@ class DiffusionWrapperV1(pl.LightningModule): cc = c_crossattn[0] out = self.diffusion_model(x, t, y=cc) else: - raise NotImplementedError() + raise NotImplementedError return out diff --git a/modules/lora_diffusers.py b/modules/lora_diffusers.py index c25fdceb3..75700b6f6 100644 --- a/modules/lora_diffusers.py +++ b/modules/lora_diffusers.py @@ -252,7 +252,7 @@ class LoRAModule(torch.nn.Module): def forward(self, x, scale = 1.0): if not self.enabled: return self.org_forward(x) - return self.org_forward(x, scale = 1.0) + self.lora_up(self.lora_down(x)) * self.multiplier * self.scale + return self.org_forward(x) + self.lora_up(self.lora_down(x)) * self.multiplier * self.scale def set_network(self, network): self.network = network @@ -373,12 +373,8 @@ class LoRANetwork(torch.nn.Module): # pylint: disable=abstract-method super().__init__() self.multiplier = multiplier - # shared.log.debug("create LoRA network from weights") - # convert SDXL Stability AI's U-Net modules to Diffusers - converted = self.convert_unet_modules(modules_dim, modules_alpha) - if converted: - shared.log.debug(f"LoRA convert: modules={converted} SDXL SAI/SGM to Diffusers") + self.convert_unet_modules(modules_dim, modules_alpha) # create module instances def create_modules( @@ -463,10 +459,8 @@ class LoRANetwork(torch.nn.Module): # pylint: disable=abstract-method def convert_unet_modules(self, modules_dim, modules_alpha): converted_count = 0 not_converted_count = 0 - map_keys = list(UNET_CONVERSION_MAP.keys()) map_keys.sort() - for key in list(modules_dim.keys()): if key.startswith(LoRANetwork.LORA_PREFIX_UNET + "_"): search_key = key.replace(LoRANetwork.LORA_PREFIX_UNET + "_", "") @@ -481,10 +475,9 @@ class LoRANetwork(torch.nn.Module): # pylint: disable=abstract-method converted_count += 1 else: not_converted_count += 1 - assert ( - converted_count == 0 or not_converted_count == 0 - ), f"some modules are not converted: {converted_count} converted, {not_converted_count} not converted" - return converted_count + if not_converted_count > 0: + shared.log.warning(f'LoRA modules not converted: {not_converted_count}') + def set_multiplier(self, multiplier): self.multiplier = multiplier diff --git a/modules/lycoris b/modules/lycoris index 3549fdef8..e4259b870 160000 --- a/modules/lycoris +++ b/modules/lycoris @@ -1 +1 @@ -Subproject commit 3549fdef8f564761d68b695a08ef88b1122fdedc +Subproject commit e4259b870d3354a9615a96be61cb5d07455c58ea diff --git a/extensions-builtin/LDSR/scripts/ldsr_model.py b/modules/postprocess/ldsr_model.py similarity index 91% rename from extensions-builtin/LDSR/scripts/ldsr_model.py rename to modules/postprocess/ldsr_model.py index 50eb9f2b7..f9ddb357a 100644 --- a/extensions-builtin/LDSR/scripts/ldsr_model.py +++ b/modules/postprocess/ldsr_model.py @@ -3,10 +3,10 @@ import sys import traceback from modules.upscaler import Upscaler, UpscalerData -from ldsr_model_arch import LDSR +from modules.ldsr.ldsr_model_arch import LDSR from modules import shared, script_callbacks -import sd_hijack_autoencoder # noqa: F401 -import sd_hijack_ddpm_v1 # noqa: F401 +import modules.ldsr.sd_hijack_autoencoder # pylint: disable=unused-import +import modules.ldsr.sd_hijack_ddpm_v1 # pylint: disable=unused-import class UpscalerLDSR(Upscaler): @@ -56,8 +56,8 @@ class UpscalerLDSR(Upscaler): print(traceback.format_exc(), file=sys.stderr) return None - def do_upscale(self, img, path): - ldsr = self.load_model(path) + def do_upscale(self, img, selected_model): + ldsr = self.load_model(selected_model) if ldsr is None: print("NO LDSR!") return img diff --git a/modules/processing.py b/modules/processing.py index 75ea9d11a..96b21b719 100644 --- a/modules/processing.py +++ b/modules/processing.py @@ -94,7 +94,7 @@ class StableDiffusionProcessing: """ The first set of paramaters: sd_models -> do_not_reload_embeddings represent the minimum required to create a StableDiffusionProcessing """ - def __init__(self, sd_model=None, outpath_samples=None, outpath_grids=None, prompt: str = "", styles: List[str] = None, seed: int = -1, subseed: int = -1, subseed_strength: float = 0, seed_resize_from_h: int = -1, seed_resize_from_w: int = -1, seed_enable_extras: bool = True, sampler_name: str = None, latent_sampler: str = None, batch_size: int = 1, n_iter: int = 1, steps: int = 50, cfg_scale: float = 7.0, image_cfg_scale: float = None, clip_skip: int = 1, width: int = 512, height: int = 512, full_quality: bool = True, restore_faces: bool = False, tiling: bool = False, do_not_save_samples: bool = False, do_not_save_grid: bool = False, extra_generation_params: Dict[Any, Any] = None, overlay_images: Any = None, negative_prompt: str = None, eta: float = None, do_not_reload_embeddings: bool = False, denoising_strength: float = 0, diffusers_guidance_rescale: float = 0.7, ddim_discretize: str = None, s_min_uncond: float = 0.0, s_churn: float = 0.0, s_tmax: float = None, s_tmin: float = 0.0, s_noise: float = 1.0, override_settings: Dict[str, Any] = None, override_settings_restore_afterwards: bool = True, sampler_index: int = None, script_args: list = None): # pylint: disable=unused-argument + def __init__(self, sd_model=None, outpath_samples=None, outpath_grids=None, prompt: str = "", styles: List[str] = None, seed: int = -1, subseed: int = -1, subseed_strength: float = 0, seed_resize_from_h: int = -1, seed_resize_from_w: int = -1, seed_enable_extras: bool = True, sampler_name: str = None, latent_sampler: str = None, batch_size: int = 1, n_iter: int = 1, steps: int = 50, cfg_scale: float = 7.0, image_cfg_scale: float = None, clip_skip: int = 1, width: int = 512, height: int = 512, full_quality: bool = True, restore_faces: bool = False, tiling: bool = False, do_not_save_samples: bool = False, do_not_save_grid: bool = False, extra_generation_params: Dict[Any, Any] = None, overlay_images: Any = None, negative_prompt: str = None, eta: float = None, do_not_reload_embeddings: bool = False, denoising_strength: float = 0, diffusers_guidance_rescale: float = 0.7, override_settings: Dict[str, Any] = None, override_settings_restore_afterwards: bool = True, sampler_index: int = None, script_args: list = None): # pylint: disable=unused-argument self.outpath_samples: str = outpath_samples self.outpath_grids: str = outpath_grids @@ -130,12 +130,6 @@ class StableDiffusionProcessing: self.paste_to = None self.color_corrections = None self.denoising_strength: float = denoising_strength - self.ddim_discretize = ddim_discretize or shared.opts.ddim_discretize - self.s_min_uncond = s_min_uncond or shared.opts.s_min_uncond - self.s_churn = s_churn or shared.opts.s_churn - self.s_tmin = s_tmin or shared.opts.s_tmin - self.s_tmax = s_tmax or float('inf') # not representable as a standard ui option - self.s_noise = s_noise or shared.opts.s_noise self.override_settings = {k: v for k, v in (override_settings or {}).items() if k not in shared.restricted_opts} self.override_settings_restore_afterwards = override_settings_restore_afterwards self.is_using_inpainting_conditioning = False @@ -162,6 +156,14 @@ class StableDiffusionProcessing: self.refiner_steps = 5 self.refiner_start = 0 self.ops = [] + self.ddim_discretize = shared.opts.ddim_discretize + self.s_min_uncond = shared.opts.s_min_uncond + self.s_churn = shared.opts.s_churn + self.s_noise = shared.opts.s_noise + self.s_min = shared.opts.s_min + self.s_max = shared.opts.s_max + self.s_tmin = shared.opts.s_tmin + self.s_tmax = float('inf') # not representable as a standard ui option shared.opts.data['clip_skip'] = clip_skip @property diff --git a/modules/sd_samplers_diffusers.py b/modules/sd_samplers_diffusers.py index 8d3fd6407..fb9bf0f82 100644 --- a/modules/sd_samplers_diffusers.py +++ b/modules/sd_samplers_diffusers.py @@ -26,7 +26,7 @@ config = { # beta_start, beta_end are typically per-scheduler, but we don't want them as they should be taken from the model itself as those are values model was trained on # prediction_type is ideally set in model as well, but it maybe needed that we do auto-detect of model type in the future 'All': { 'num_train_timesteps': 1000, 'beta_start': 0.0001, 'beta_end': 0.02, 'beta_schedule': 'linear', 'prediction_type': 'epsilon' }, - 'DDIM': { 'clip_sample': True, 'set_alpha_to_one': True, 'steps_offset': 0, 'thresholding': False, 'clip_sample_range': 1.0, 'sample_max_value': 1.0, 'timestep_spacing': 'linspace', 'rescale_betas_zero_snr': False }, + 'DDIM': { 'clip_sample': True, 'set_alpha_to_one': True, 'steps_offset': 0, 'clip_sample_range': 1.0, 'sample_max_value': 1.0, 'timestep_spacing': 'linspace', 'rescale_betas_zero_snr': False }, 'DDPM': { 'variance_type': "fixed_small", 'clip_sample': True, 'thresholding': False, 'clip_sample_range': 1.0, 'sample_max_value': 1.0, 'timestep_spacing': 'linspace'}, 'DEIS': { 'solver_order': 2, 'thresholding': False, 'sample_max_value': 1.0, 'algorithm_type': "deis", 'solver_type': "logrho", 'lower_order_final': True }, 'DPM 1S++': { 'solver_order': 2, 'thresholding': False, 'sample_max_value': 1.0, 'algorithm_type': "dpmsolver++", 'solver_type': "midpoint", 'lower_order_final': True, 'use_karras_sigmas': False }, diff --git a/modules/sd_samplers_kdiffusion.py b/modules/sd_samplers_kdiffusion.py index 8b424d200..8e5bfb086 100644 --- a/modules/sd_samplers_kdiffusion.py +++ b/modules/sd_samplers_kdiffusion.py @@ -306,13 +306,16 @@ class KDiffusionSampler: if self.config.options.get('scheduler', None) == 'default' or self.config.options.get('scheduler', None) is None: sigmas = self.model_wrap.get_sigmas(steps) elif self.config.options.get('scheduler', None) == 'karras': - sigma_min, sigma_max = self.model_wrap.sigmas[0].item(), self.model_wrap.sigmas[-1].item() + sigma_min = p.s_min if p.s_min > 0 else self.model_wrap.sigmas[0].item() + sigma_max = p.s_max if p.s_max > 0 else self.model_wrap.sigmas[-1].item() sigmas = k_diffusion.sampling.get_sigmas_karras(n=steps, sigma_min=sigma_min, sigma_max=sigma_max, device=shared.device) elif self.config.options.get('scheduler', None) == 'exponential': - sigma_min, sigma_max = self.model_wrap.sigmas[0].item(), self.model_wrap.sigmas[-1].item() + sigma_min = p.s_min if p.s_min > 0 else self.model_wrap.sigmas[0].item() + sigma_max = p.s_max if p.s_max > 0 else self.model_wrap.sigmas[-1].item() sigmas = k_diffusion.sampling.get_sigmas_exponential(n=steps, sigma_min=sigma_min, sigma_max=sigma_max, device=shared.device) elif self.config.options.get('scheduler', None) == 'polyexponential': - sigma_min, sigma_max = self.model_wrap.sigmas[0].item(), self.model_wrap.sigmas[-1].item() + sigma_min = p.s_min if p.s_min > 0 else self.model_wrap.sigmas[0].item() + sigma_max = p.s_max if p.s_max > 0 else self.model_wrap.sigmas[-1].item() sigmas = k_diffusion.sampling.get_sigmas_polyexponential(n=steps, sigma_min=sigma_min, sigma_max=sigma_max, device=shared.device) elif self.config.options.get('scheduler', None) == 'vp': sigmas = k_diffusion.sampling.get_sigmas_vp(n=steps, device=shared.device) diff --git a/modules/shared.py b/modules/shared.py index 58daa6726..9ce5d7db3 100644 --- a/modules/shared.py +++ b/modules/shared.py @@ -566,7 +566,7 @@ options_templates.update(options_section(('sampler-params', "Sampler Settings"), # managed from ui.py for backend original "schedulers_brownian_noise": OptionInfo(True, "Use Brownian noise", gr.Checkbox, {"visible": False}), "schedulers_discard_penultimate": OptionInfo(True, "Discard penultimate sigma", gr.Checkbox, {"visible": False}), - "schedulers_sigma": OptionInfo("default", "Sigma algorithm", gr.Radio, {"choices": ['default', 'karras', 'exponential', 'polyexponential', 'vp'], "visible": False}), + "schedulers_sigma": OptionInfo("default", "Sigma algorithm", gr.Radio, {"choices": ['default', 'karras', 'exponential', 'polyexponential'], "visible": False}), # managed from ui.py for backend diffusers "schedulers_use_karras": OptionInfo(True, "Use Karras sigmas", gr.Checkbox, {"visible": False}), "schedulers_use_thresholding": OptionInfo(False, "Use dynamic thresholding", gr.Checkbox, {"visible": False}), @@ -586,6 +586,8 @@ options_templates.update(options_section(('sampler-params', "Sampler Settings"), 's_min_uncond': OptionInfo(0.0, "Sigma negative guidance minimum ", gr.Slider, {"minimum": 0.0, "maximum": 4.0, "step": 0.01}), 's_tmin': OptionInfo(0.0, "Sigma tmin", gr.Slider, {"minimum": 0.0, "maximum": 1.0, "step": 0.01}), 's_noise': OptionInfo(1.0, "Sigma noise", gr.Slider, {"minimum": 0.0, "maximum": 1.0, "step": 0.01}), + 's_min': OptionInfo(0.0, "Sigma min", gr.Slider, {"minimum": 0.0, "maximum": 1.0, "step": 0.01}), + 's_max': OptionInfo(0.0, "Sigma max", gr.Slider, {"minimum": 0.0, "maximum": 100.0, "step": 1.0}), # 'discard_next_to_last_sigma': OptionInfo("default", "Discard penultimate sigma", gr.Radio, lambda: {"choices": ['default', 'always', 'never']}), # 'always_discard_next_to_last_sigma': OptionInfo(False, "Always discard next-to-last sigma"), # 'never_discard_next_to_last_sigma': OptionInfo(False, "Never discard next-to-last sigma"), @@ -834,9 +836,8 @@ if cmd_opts.backend is None: else: backend = Backend.DIFFUSERS if cmd_opts.use_openvino or cmd_opts.backend.lower() == 'diffusers' else Backend.ORIGINAL opts.data['sd_backend'] = 'diffusers' if backend == Backend.DIFFUSERS else 'original' -opts.data['uni_pc_lower_order_final'] = opts.schedulers_use_loworder -opts.data['uni_pc_order'] = opts.schedulers_solver_order -# opts.data['diffusers_lora_loader'] = 'diffusers' # TODO broken in diffusers=0.21 +opts.data['uni_pc_lower_order_final'] = opts.schedulers_use_loworder # compatibility +opts.data['uni_pc_order'] = opts.schedulers_solver_order # compatibility log.info(f'Engine: backend={backend} compute={devices.backend} mode={devices.inference_context.__name__} device={devices.get_optimal_device_name()}') log.info(f'Device: {print_dict(devices.get_gpu_info())}') diff --git a/scripts/xyz_grid.py b/scripts/xyz_grid.py index 16e448996..bcf999b92 100644 --- a/scripts/xyz_grid.py +++ b/scripts/xyz_grid.py @@ -24,6 +24,12 @@ def apply_field(field): return fun +def apply_setting(field): + def fun(p, x, xs): + shared.opts.data[field] = x + return fun + + def apply_prompt(p, x, xs): if xs[0] not in p.prompt and xs[0] not in p.negative_prompt: shared.log.warning(f"XYZ grid: prompt S/R did not find {xs[0]} in prompt or negative prompt.") @@ -120,10 +126,6 @@ def apply_styles(p: StableDiffusionProcessingTxt2Img, x: str, _): p.styles.extend(x.split(',')) -def apply_schedulers_solver_order(p, x, xs): - shared.opts.data["schedulers_solver_order"] = min(x, p.steps - 1) - - def apply_upscaler(p: StableDiffusionProcessingTxt2Img, opt, x): p.enable_hr = True p.hr_force = True @@ -219,23 +221,25 @@ axis_options = [ AxisOption("Prompt order", str_permutations, apply_order, fmt=format_value_join_list), AxisOption("Upscaler", str, apply_upscaler, choices=lambda: [x.name for x in shared.sd_upscalers][1:]), AxisOption("Face restore", str, apply_face_restore, fmt=format_value), + AxisOption("Token merging ratio high-res", float, apply_override('token_merging_ratio_hr')), AxisOption("Token merging ratio", float, apply_override('token_merging_ratio')), - # AxisOption("Sampler Sigma Churn", float, apply_field("s_churn")), - # AxisOption("Sampler Sigma min", float, apply_field("s_tmin")), - # AxisOption("Sampler Sigma max", float, apply_field("s_tmax")), - # AxisOption("Sampler Sigma noise", float, apply_field("s_noise")), - # AxisOption("Sampler Eta", float, apply_field("eta")), - # AxisOption("Sampler Solver Order", int, apply_schedulers_solver_order, cost=0.5), - # AxisOption("Token merging ratio high-res", float, apply_override('token_merging_ratio_hr')), 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("SecondPass Upscaler", str, apply_field("hr_upscaler"), choices=lambda: [*shared.latent_upscale_modes, *[x.name for x in shared.sd_upscalers]]), - AxisOption("SecondPass Sampler", str, apply_latent_sampler, fmt=format_value, confirm=confirm_samplers, choices=lambda: [x.name for x in sd_samplers.samplers]), - AxisOption("SecondPass Denoising Strength", float, apply_field("denoising_strength")), - AxisOption("SecondPass 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("SecondPass upscaler", str, apply_field("hr_upscaler"), choices=lambda: [*shared.latent_upscale_modes, *[x.name for x in shared.sd_upscalers]]), + AxisOption("SecondPass sampler", str, apply_latent_sampler, fmt=format_value, confirm=confirm_samplers, choices=lambda: [x.name for x in sd_samplers.samplers]), + AxisOption("SecondPass denoising Strength", float, apply_field("denoising_strength")), + AxisOption("SecondPass steps", int, apply_field("hr_second_pass_steps")), AxisOption("SecondPass CFG scale", float, apply_field("image_cfg_scale")), - AxisOption("SecondPass Guidance Rescale", float, apply_field("diffusers_guidance_rescale")), - AxisOption("SecondPass Refiner Start", float, apply_field("refiner_start")), + AxisOption("SecondPass guidance rescale", float, apply_field("diffusers_guidance_rescale")), + AxisOption("SecondPass refiner start", float, apply_field("refiner_start")), ]