diff --git a/extensions-builtin/sd-extension-system-info b/extensions-builtin/sd-extension-system-info index 9d3c0ca0f..19d190e71 160000 --- a/extensions-builtin/sd-extension-system-info +++ b/extensions-builtin/sd-extension-system-info @@ -1 +1 @@ -Subproject commit 9d3c0ca0f2dc8f8973b3d08f5ec1fa8bbd726155 +Subproject commit 19d190e71b2f1399623519db741d2a6bf8d2c86c diff --git a/extensions-builtin/sd-webui-controlnet b/extensions-builtin/sd-webui-controlnet index 5ae9b4a1a..4b815cc35 160000 --- a/extensions-builtin/sd-webui-controlnet +++ b/extensions-builtin/sd-webui-controlnet @@ -1 +1 @@ -Subproject commit 5ae9b4a1a0c7d9a2938e75aaf052ab078623066f +Subproject commit 4b815cc351ca5eeec489f573a9a6c2dbd47374d7 diff --git a/modules/processing.py b/modules/processing.py index 7b83f2fc3..7a24d156f 100644 --- a/modules/processing.py +++ b/modules/processing.py @@ -86,7 +86,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, 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, 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, quality: bool = True, 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 @@ -151,6 +151,7 @@ class StableDiffusionProcessing: self.is_hr_pass = False self.enable_hr = None self.refiner_start = 0 + self.quality = quality self.ops = [] shared.opts.data['clip_skip'] = clip_skip diff --git a/modules/sd_models.py b/modules/sd_models.py index d010ffd6b..f5c35b95f 100644 --- a/modules/sd_models.py +++ b/modules/sd_models.py @@ -534,10 +534,7 @@ def change_backend(): def load_diffuser(checkpoint_info=None, already_loaded_state_dict=None, timer=None, op='model'): # pylint: disable=unused-argument - if op != 'model' and checkpoint_info is None and (shared.cmd_opts.ckpt is None or shared.cmd_opts.ckpt.lower() == 'none'): - return import torch # pylint: disable=reimported,redefined-outer-name - devices.set_cuda_params() if timer is None: timer = Timer() import logging @@ -570,7 +567,6 @@ def load_diffuser(checkpoint_info=None, already_loaded_state_dict=None, timer=No if (model_data.sd_refiner is not None) and (checkpoint_info is not None) and (checkpoint_info.hash == model_data.sd_refiner.sd_checkpoint_info.hash): # trying to load the same model return - shared.log.debug(f'Diffusers load {op} config: {diffusers_load_config}') sd_model = None try: @@ -580,7 +576,9 @@ def load_diffuser(checkpoint_info=None, already_loaded_state_dict=None, timer=No if model_name is not None: shared.log.info(f'Loading diffuser {op}: {model_name}') model_file = modelloader.download_diffusers_model(hub_id=model_name) + devices.set_cuda_params() try: + shared.log.debug(f'Diffusers load {op} config: {diffusers_load_config}') sd_model = diffusers.DiffusionPipeline.from_pretrained(model_file, **diffusers_load_config) except Exception as e: shared.log.error(f'Diffusers failed loading model: {model_file} {e}') @@ -592,8 +590,8 @@ def load_diffuser(checkpoint_info=None, already_loaded_state_dict=None, timer=No if checkpoint_info is None: unload_model_weights(op=op) return - shared.log.info(f'Loading diffuser {op}: {checkpoint_info.filename}') + devices.set_cuda_params() vae = None if op == 'model' or op == 'refiner': vae_file, vae_source = sd_vae.resolve_vae(checkpoint_info.filename) @@ -601,8 +599,10 @@ def load_diffuser(checkpoint_info=None, already_loaded_state_dict=None, timer=No if vae is not None: diffusers_load_config["vae"] = vae + shared.log.info(f'Loading diffuser {op}: {checkpoint_info.filename}') if not os.path.isfile(checkpoint_info.path): try: + shared.log.debug(f'Diffusers load {op} config: {diffusers_load_config}') sd_model = diffusers.DiffusionPipeline.from_pretrained(checkpoint_info.path, **diffusers_load_config) except Exception as e: shared.log.error(f'Diffusers {op} failed loading model: {checkpoint_info.path} {e}') diff --git a/modules/sd_samplers.py b/modules/sd_samplers.py index 21777c800..4f298fbce 100644 --- a/modules/sd_samplers.py +++ b/modules/sd_samplers.py @@ -23,9 +23,7 @@ def list_samplers(backend_name = shared.backend): samplers = all_samplers samplers_for_img2img = all_samplers samplers_map = {} - shared.log.debug(f'Samplers enumerated: {[x.name for x in all_samplers]}') - -list_samplers() + shared.log.debug(f'Available samplers: {[x.name for x in all_samplers]}') def find_sampler_config(name): diff --git a/modules/sd_samplers_common.py b/modules/sd_samplers_common.py index 40b16d50b..a18667d47 100644 --- a/modules/sd_samplers_common.py +++ b/modules/sd_samplers_common.py @@ -2,17 +2,16 @@ from collections import namedtuple import numpy as np import torch from PIL import Image -from modules import devices, processing, images, sd_vae_approx, sd_samplers, sd_vae_taesd -from modules.shared import opts, state +from modules import devices, processing, images, sd_vae_approx, sd_samplers import modules.shared as shared - +import modules.taesd.sd_vae_taesd as sd_vae_taesd SamplerData = namedtuple('SamplerData', ['name', 'constructor', 'aliases', 'options']) approximation_indexes = {"Full VAE": 0, "Approximate NN": 1, "Approximate simple": 2, "TAESD": 3} def setup_img2img_steps(p, steps=None): - if opts.img2img_fix_steps or steps is not None: + if shared.opts.img2img_fix_steps or steps is not None: requested_steps = (steps or p.steps) steps = int(requested_steps / min(p.denoising_strength, 0.999)) if p.denoising_strength > 0 else 0 t_enc = requested_steps - 1 @@ -25,7 +24,7 @@ def setup_img2img_steps(p, steps=None): def single_sample_to_image(sample, approximation=None): if approximation is None: - approximation = approximation_indexes.get(opts.show_progress_type, 0) + approximation = approximation_indexes.get(shared.opts.show_progress_type, 0) if approximation == 0: x_sample = processing.decode_first_stage(shared.sd_model, sample.unsqueeze(0))[0] * 0.5 + 0.5 elif approximation == 1: @@ -33,8 +32,9 @@ def single_sample_to_image(sample, approximation=None): elif approximation == 2: x_sample = sd_vae_approx.cheap_approximation(sample) * 0.5 + 0.5 elif approximation == 3: - x_sample = sample * 1.5 - x_sample = sd_vae_taesd.model()(x_sample.to(devices.device, devices.dtype).unsqueeze(0))[0].detach() + # x_sample = sample * 1.5 + # x_sample = sd_vae_taesd.model()(x_sample.to(devices.device, devices.dtype).unsqueeze(0))[0].detach() + x_sample = sd_vae_taesd.decode(sample, 'sd') else: shared.log.warning(f"Unknown image decode type: {approximation}") return Image.new(mode="RGB", size=(512, 512)) @@ -52,10 +52,11 @@ def samples_to_image_grid(samples, approximation=None): def store_latent(decoded): - state.current_latent = decoded - if opts.live_previews_enable and opts.show_progress_every_n_steps > 0 and shared.state.sampling_step % opts.show_progress_every_n_steps == 0: + shared.state.current_latent = decoded + if shared.opts.live_previews_enable and shared.opts.show_progress_every_n_steps > 0 and shared.state.sampling_step % shared.opts.show_progress_every_n_steps == 0: if not shared.parallel_processing_allowed: - shared.state.assign_current_image(sample_to_image(decoded)) + image = sample_to_image(decoded) + shared.state.assign_current_image(image) def is_sampler_using_eta_noise_seed_delta(p): diff --git a/modules/sd_vae_taesd.py b/modules/sd_vae_taesd.py deleted file mode 100644 index 74ad13926..000000000 --- a/modules/sd_vae_taesd.py +++ /dev/null @@ -1,88 +0,0 @@ -""" -Tiny AutoEncoder for Stable Diffusion -(DNN for encoding / decoding SD's latent space) - -https://github.com/madebyollin/taesd -""" -import os -import torch -import torch.nn as nn - -from modules import devices, paths_internal - -sd_vae_taesd = None - - -def conv(n_in, n_out, **kwargs): - return nn.Conv2d(n_in, n_out, 3, padding=1, **kwargs) - - -class Clamp(nn.Module): - @staticmethod - def forward(x): - return torch.tanh(x / 3) * 3 - - -class Block(nn.Module): - def __init__(self, n_in, n_out): - super().__init__() - self.conv = nn.Sequential(conv(n_in, n_out), nn.ReLU(), conv(n_out, n_out), nn.ReLU(), conv(n_out, n_out)) - self.skip = nn.Conv2d(n_in, n_out, 1, bias=False) if n_in != n_out else nn.Identity() - self.fuse = nn.ReLU() - - def forward(self, x): - return self.fuse(self.conv(x) + self.skip(x)) - - -def decoder(): - return nn.Sequential( - Clamp(), conv(4, 64), nn.ReLU(), - Block(64, 64), Block(64, 64), Block(64, 64), nn.Upsample(scale_factor=2), conv(64, 64, bias=False), - Block(64, 64), Block(64, 64), Block(64, 64), nn.Upsample(scale_factor=2), conv(64, 64, bias=False), - Block(64, 64), Block(64, 64), Block(64, 64), nn.Upsample(scale_factor=2), conv(64, 64, bias=False), - Block(64, 64), conv(64, 3), - ) - - -class TAESD(nn.Module): # pylint: disable=abstract-method - latent_magnitude = 3 - latent_shift = 0.5 - - def __init__(self, decoder_path="taesd_decoder.pth"): - """Initialize pretrained TAESD on the given device from the given checkpoints.""" - super().__init__() - self.decoder = decoder() - self.decoder.load_state_dict( - torch.load(decoder_path, map_location='cpu' if devices.device.type != 'cuda' else None)) - - @staticmethod - def unscale_latents(x): - """[0, 1] -> raw latents""" - return x.sub(TAESD.latent_shift).mul(2 * TAESD.latent_magnitude) - - -def download_model(model_path): - model_url = 'https://github.com/madebyollin/taesd/raw/main/taesd_decoder.pth' - - if not os.path.exists(model_path): - os.makedirs(os.path.dirname(model_path), exist_ok=True) - - print(f'Downloading TAESD decoder to: {model_path}') - torch.hub.download_url_to_file(model_url, model_path) - - -def model(): - global sd_vae_taesd # pylint: disable=global-statement - - if sd_vae_taesd is None: - model_path = os.path.join(paths_internal.models_path, "VAE-taesd", "taesd_decoder.pth") - download_model(model_path) - - if os.path.exists(model_path): - sd_vae_taesd = TAESD(model_path) - sd_vae_taesd.eval() - sd_vae_taesd.to(devices.device, devices.dtype) - else: - raise FileNotFoundError('TAESD model not found') - - return sd_vae_taesd.decoder diff --git a/modules/shared.py b/modules/shared.py index 3a3ce09f3..8b0ff3109 100644 --- a/modules/shared.py +++ b/modules/shared.py @@ -171,13 +171,11 @@ class State: return import modules.sd_samplers # pylint: disable=W0621 try: - if opts.show_progress_grid: - self.assign_current_image(modules.sd_samplers.samples_to_image_grid(self.current_latent)) - else: - self.assign_current_image(modules.sd_samplers.sample_to_image(self.current_latent)) - except Exception: - pass - self.current_image_sampling_step = self.sampling_step + image = modules.sd_samplers.samples_to_image_grid(self.current_latent) if opts.show_progress_grid else modules.sd_samplers.sample_to_image(self.current_latent) + self.assign_current_image(image) + self.current_image_sampling_step = self.sampling_step + except Exception as e: + log.error(f'Error setting current image: step={self.sampling_step} {e}') def assign_current_image(self, image): self.current_image = image @@ -984,6 +982,22 @@ class Shared(sys.modules[__name__].__class__): # this class is here to provide s def backend(self): return Backend.ORIGINAL if opts.data['sd_backend'] == 'original' else Backend.DIFFUSERS + @property + def sd_model_type(self): + try: + if backend == Backend.ORIGINAL: + model_type = 'ldm' + elif "StableDiffusionXL" in self.sd_model.__class__.__name__: + model_type = 'sdxl' + elif "StableDiffusion" in self.sd_model.__class__.__name__: + model_type = 'sd' + elif "Kandinsky" in self.sd_model.__class__.__name__: + model_type = 'kandinsky' + else: + model_type = self.sd_model.__class__.__name__ + except Exception: + model_type = 'unknown' + return model_type sd_model = None sd_refiner = None diff --git a/modules/taesd/sd_vae_taesd.py b/modules/taesd/sd_vae_taesd.py new file mode 100644 index 000000000..17a7bceee --- /dev/null +++ b/modules/taesd/sd_vae_taesd.py @@ -0,0 +1,57 @@ +""" +Tiny AutoEncoder for Stable Diffusion +(DNN for encoding / decoding SD's latent space) + +https://github.com/madebyollin/taesd +""" +import os +from modules import devices, paths_internal +from modules.taesd.taesd import TAESD + +taesd_models = { 'sd-decoder': None, 'sd-encoder': None, 'sdxl-decoder': None, 'sdxl-encoder': None } + +def download_model(model_path): + model_name = os.path.basename(model_path) + model_url = f'https://github.com/madebyollin/taesd/raw/main/{model_name}' + if not os.path.exists(model_path): + os.makedirs(os.path.dirname(model_path), exist_ok=True) + from modules.shared import log + log.info(f'Downloading TAESD decoder: {model_path}') + import torch + torch.hub.download_url_to_file(model_url, model_path) + + +def model(model_class = 'sd', model_type = 'decoder'): + vae = taesd_models[f'{model_class}-{model_type}'] + if vae is None: + model_path = os.path.join(paths_internal.models_path, "TAESD", f"tae{model_class}_{model_type}.pth") + download_model(model_path) + if os.path.exists(model_path): + taesd_models[f'{model_class}-{model_type}'] = TAESD(decoder_path=model_path, encoder_path=None) if model_type == 'decoder' else TAESD(encoder_path=model_path, decoder_path=None) + vae = taesd_models[f'{model_class}-{model_type}'] + vae.eval() + vae.to(devices.device, devices.dtype_vae) + else: + raise FileNotFoundError('TAESD model not found') + if vae is None: + return None + else: + return vae.decoder if model_type == 'decoder' else vae.encoder + + +def decode(latents): + from modules import shared + model_class = shared.sd_model_type + if 'sd' not in model_class: + return None + vae = taesd_models[f'{model_class}-decoder'] + if vae is None: + model_path = os.path.join(paths_internal.models_path, "TAESD", f"tae{model_class}_decoder.pth") + download_model(model_path) + if os.path.exists(model_path): + taesd_models[f'{model_class}-decoder'] = TAESD(decoder_path=model_path, encoder_path=None) + vae = taesd_models[f'{model_class}-decoder'] + vae.to(devices.device, devices.dtype_vae) + enc = latents.unsqueeze(0).to(devices.device, devices.dtype_vae) + image = vae.decoder(enc).clamp(0, 1).detach() + return image[0] diff --git a/modules/taesd/taesd.py b/modules/taesd/taesd.py new file mode 100644 index 000000000..0355a81ff --- /dev/null +++ b/modules/taesd/taesd.py @@ -0,0 +1,93 @@ +#!/usr/bin/env python3 +""" +Tiny AutoEncoder for Stable Diffusion +(DNN for encoding / decoding SD's latent space) +""" +import torch +import torch.nn as nn + +def conv(n_in, n_out, **kwargs): + return nn.Conv2d(n_in, n_out, 3, padding=1, **kwargs) + +class Clamp(nn.Module): + def forward(self, x): + return torch.tanh(x / 3) * 3 + +class Block(nn.Module): + def __init__(self, n_in, n_out): + super().__init__() + self.conv = nn.Sequential(conv(n_in, n_out), nn.ReLU(), conv(n_out, n_out), nn.ReLU(), conv(n_out, n_out)) + self.skip = nn.Conv2d(n_in, n_out, 1, bias=False) if n_in != n_out else nn.Identity() + self.fuse = nn.ReLU() + def forward(self, x): + return self.fuse(self.conv(x) + self.skip(x)) + +def Encoder(): + return nn.Sequential( + conv(3, 64), Block(64, 64), + conv(64, 64, stride=2, bias=False), Block(64, 64), Block(64, 64), Block(64, 64), + conv(64, 64, stride=2, bias=False), Block(64, 64), Block(64, 64), Block(64, 64), + conv(64, 64, stride=2, bias=False), Block(64, 64), Block(64, 64), Block(64, 64), + conv(64, 4), + ) + +def Decoder(): + return nn.Sequential( + Clamp(), conv(4, 64), nn.ReLU(), + Block(64, 64), Block(64, 64), Block(64, 64), nn.Upsample(scale_factor=2), conv(64, 64, bias=False), + Block(64, 64), Block(64, 64), Block(64, 64), nn.Upsample(scale_factor=2), conv(64, 64, bias=False), + Block(64, 64), Block(64, 64), Block(64, 64), nn.Upsample(scale_factor=2), conv(64, 64, bias=False), + Block(64, 64), conv(64, 3), + ) + +class TAESD(nn.Module): + latent_magnitude = 3 + latent_shift = 0.5 + + def __init__(self, encoder_path="taesd_encoder.pth", decoder_path="taesd_decoder.pth"): + """Initialize pretrained TAESD on the given device from the given checkpoints.""" + super().__init__() + self.encoder = Encoder() + self.decoder = Decoder() + if encoder_path is not None: + self.encoder.load_state_dict(torch.load(encoder_path, map_location="cpu")) + if decoder_path is not None: + self.decoder.load_state_dict(torch.load(decoder_path, map_location="cpu")) + + @staticmethod + def scale_latents(x): + """raw latents -> [0, 1]""" + return x.div(2 * TAESD.latent_magnitude).add(TAESD.latent_shift).clamp(0, 1) + + @staticmethod + def unscale_latents(x): + """[0, 1] -> raw latents""" + return x.sub(TAESD.latent_shift).mul(2 * TAESD.latent_magnitude) + + +@torch.no_grad() +def main(): + from PIL import Image + import sys + import torchvision.transforms.functional as TF + dev = torch.device("cuda" if torch.cuda.is_available() else "mps" if torch.backends.mps.is_available() else "cpu") + print("Using device", dev) + taesd = TAESD().to(dev) + for im_path in sys.argv[1:]: + im = TF.to_tensor(Image.open(im_path).convert("RGB")).unsqueeze(0).to(dev) + + # encode image, quantize, and save to file + im_enc = taesd.scale_latents(taesd.encoder(im)).mul_(255).round_().byte() + enc_path = im_path + ".encoded.png" + TF.to_pil_image(im_enc[0]).save(enc_path) + print(f"Encoded {im_path} to {enc_path}") + + # load the saved file, dequantize, and decode + im_enc = taesd.unscale_latents(TF.to_tensor(Image.open(enc_path)).unsqueeze(0).to(dev)) + im_dec = taesd.decoder(im_enc).clamp(0, 1) + dec_path = im_path + ".decoded.png" + print(f"Decoded {enc_path} to {dec_path}") + TF.to_pil_image(im_dec[0]).save(dec_path) + +if __name__ == "__main__": + main() diff --git a/modules/txt2img.py b/modules/txt2img.py index 64cb978ac..b9c0add2f 100644 --- a/modules/txt2img.py +++ b/modules/txt2img.py @@ -5,9 +5,9 @@ from modules.ui import plaintext_to_html from modules.memstats import memory_stats -def txt2img(id_task: str, prompt: str, negative_prompt: str, prompt_styles, steps: int, sampler_index: int, latent_index: int, restore_faces: bool, tiling: bool, n_iter: int, batch_size: int, cfg_scale: float, image_cfg_scale: float, diffusers_guidance_rescale: float, clip_skip: int, seed: int, subseed: int, subseed_strength: float, seed_resize_from_h: int, seed_resize_from_w: int, height: int, width: int, enable_hr: bool, denoising_strength: float, hr_scale: float, hr_upscaler: str, hr_second_pass_steps: int, hr_resize_x: int, hr_resize_y: int, refiner_start: int, refiner_prompt: str, refiner_negative: str, override_settings_texts, *args): # pylint: disable=unused-argument +def txt2img(id_task: str, prompt: str, negative_prompt: str, prompt_styles, steps: int, sampler_index: int, latent_index: int, restore_faces: bool, tiling: bool, n_iter: int, batch_size: int, cfg_scale: float, image_cfg_scale: float, diffusers_guidance_rescale: float, clip_skip: int, seed: int, subseed: int, subseed_strength: float, seed_resize_from_h: int, seed_resize_from_w: int, height: int, width: int, enable_hr: bool, denoising_strength: float, hr_scale: float, hr_upscaler: str, hr_second_pass_steps: int, hr_resize_x: int, hr_resize_y: int, refiner_start: int, refiner_prompt: str, refiner_negative: str, quality: bool, override_settings_texts, *args): # pylint: disable=unused-argument - shared.log.debug(f'txt2img: id_task={id_task}|prompt={prompt}|negative_prompt={negative_prompt}|prompt_styles={prompt_styles}|steps={steps}|sampler_index={sampler_index}|latent_index={latent_index}|restore_faces={restore_faces}|tiling={tiling}|n_iter={n_iter}|batch_size={batch_size}|cfg_scale={cfg_scale}|clip_skip={clip_skip}|seed={seed}|subseed={subseed}|subseed_strength={subseed_strength}|seed_resize_from_h={seed_resize_from_h}|seed_resize_from_w={seed_resize_from_w}||height={height}|width={width}|enable_hr={enable_hr}|denoising_strength={denoising_strength}|hr_scale={hr_scale}|hr_upscaler={hr_upscaler}|hr_second_pass_steps={hr_second_pass_steps}|hr_resize_x={hr_resize_x}|hr_resize_y={hr_resize_y}|image_cfg_scale={image_cfg_scale}|diffusers_guidance_rescale={diffusers_guidance_rescale}|refiner_start={refiner_start}||refiner_prompt={refiner_prompt}|refiner_negative={refiner_negative}|override_settings_texts={override_settings_texts}args={args}') + shared.log.debug(f'txt2img: id_task={id_task}|prompt={prompt}|negative_prompt={negative_prompt}|prompt_styles={prompt_styles}|steps={steps}|sampler_index={sampler_index}|latent_index={latent_index}|restore_faces={restore_faces}|tiling={tiling}|n_iter={n_iter}|batch_size={batch_size}|cfg_scale={cfg_scale}|clip_skip={clip_skip}|seed={seed}|subseed={subseed}|subseed_strength={subseed_strength}|seed_resize_from_h={seed_resize_from_h}|seed_resize_from_w={seed_resize_from_w}||height={height}|width={width}|enable_hr={enable_hr}|denoising_strength={denoising_strength}|hr_scale={hr_scale}|hr_upscaler={hr_upscaler}|hr_second_pass_steps={hr_second_pass_steps}|hr_resize_x={hr_resize_x}|hr_resize_y={hr_resize_y}|image_cfg_scale={image_cfg_scale}|diffusers_guidance_rescale={diffusers_guidance_rescale}|refiner_start={refiner_start}||refiner_prompt={refiner_prompt}|refiner_negative={refiner_negative}|quality={quality}|override_settings_texts={override_settings_texts}|args={args}') if shared.sd_model is None: shared.log.warning('Model not loaded') @@ -55,6 +55,7 @@ def txt2img(id_task: str, prompt: str, negative_prompt: str, prompt_styles, step refiner_start=refiner_start, refiner_prompt=refiner_prompt, refiner_negative=refiner_negative, + quality=quality, override_settings=override_settings, ) p.scripts = modules.scripts.scripts_txt2img diff --git a/modules/ui.py b/modules/ui.py index 7ca1261ca..aaf1cdf68 100644 --- a/modules/ui.py +++ b/modules/ui.py @@ -379,6 +379,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(elem_classes="checkboxes-row", variant="compact"): + quality = gr.Checkbox(label='Decode quality', value=True, elem_id="txt2img_quality") restore_faces = gr.Checkbox(label='Face restore', value=False, visible=len(modules.shared.face_restorers) > 1, elem_id="txt2img_restore_faces") tiling = gr.Checkbox(label='Tiling', value=False, elem_id="txt2img_tiling") @@ -445,6 +446,7 @@ def create_ui(startup_timer = None): show_second_pass, denoising_strength, hr_scale, hr_upscaler, hr_second_pass_steps, hr_resize_x, hr_resize_y, refiner_start, refiner_prompt, refiner_negative, + quality, override_settings, ] + custom_inputs, outputs=[ diff --git a/webui.py b/webui.py index 72e878c40..7119f1238 100644 --- a/webui.py +++ b/webui.py @@ -105,6 +105,9 @@ def initialize(): shared.disable_extensions() check_rollback_vae() + modules.sd_samplers.list_samplers() + startup_timer.record("samplers") + modules.sd_vae.refresh_vae_list() startup_timer.record("vae")