diff --git a/extensions-builtin/multidiffusion-upscaler-for-automatic1111 b/extensions-builtin/multidiffusion-upscaler-for-automatic1111
index 50f5f8894..2473d6b00 160000
--- a/extensions-builtin/multidiffusion-upscaler-for-automatic1111
+++ b/extensions-builtin/multidiffusion-upscaler-for-automatic1111
@@ -1 +1 @@
-Subproject commit 50f5f88944427a1f7e1321917790dbd9a5ddbed8
+Subproject commit 2473d6b005a516fb4bd51b331abd04b0289fdf07
diff --git a/extensions-builtin/sd-webui-controlnet b/extensions-builtin/sd-webui-controlnet
index a83a26060..0d1c252ca 160000
--- a/extensions-builtin/sd-webui-controlnet
+++ b/extensions-builtin/sd-webui-controlnet
@@ -1 +1 @@
-Subproject commit a83a260605fe3da01bc15993c6a7f7d1aa82865d
+Subproject commit 0d1c252cad9c37a75e839d52f9ea8207adb8aa46
diff --git a/extensions-builtin/stable-diffusion-webui-images-browser b/extensions-builtin/stable-diffusion-webui-images-browser
index 7da8aec62..c61fae964 160000
--- a/extensions-builtin/stable-diffusion-webui-images-browser
+++ b/extensions-builtin/stable-diffusion-webui-images-browser
@@ -1 +1 @@
-Subproject commit 7da8aec62bc263acd47d76ec9cabdb658b01fc91
+Subproject commit c61fae964ac94bc369fd0e346805e3e2885c69b4
diff --git a/javascript/ui.js b/javascript/ui.js
index 7035f7497..9313c75c6 100644
--- a/javascript/ui.js
+++ b/javascript/ui.js
@@ -1,6 +1,7 @@
/* global gradioApp, onUiUpdate, opts */
window.opts = {};
+window.localization = {};
let tabSelected = '';
function set_theme(theme) {
@@ -192,6 +193,22 @@ function recalculate_prompts_inpaint(...args) {
return args_to_array(args);
}
+function register_drag_drop() {
+ const qs = gradioApp().getElementById('quicksettings');
+ if (!qs) return;
+ qs.addEventListener('dragover', (evt) => {
+ evt.preventDefault();
+ evt.dataTransfer.dropEffect = 'copy';
+ });
+ qs.addEventListener('drop', (evt) => {
+ evt.preventDefault();
+ evt.dataTransfer.dropEffect = 'copy';
+ for (const f of evt.dataTransfer.files) {
+ console.log('QuickSettingsDrop', f);
+ }
+ });
+}
+
onUiUpdate(() => {
sort_ui_elements();
if (Object.keys(opts).length !== 0) return;
@@ -202,6 +219,7 @@ onUiUpdate(() => {
const jsdata = textarea.value;
opts = JSON.parse(jsdata);
executeCallbacks(optionsChangedCallbacks);
+ register_drag_drop();
Object.defineProperty(textarea, 'value', {
set(newValue) {
diff --git a/modules/call_queue.py b/modules/call_queue.py
index 3cfe3c50d..0de523f66 100644
--- a/modules/call_queue.py
+++ b/modules/call_queue.py
@@ -65,10 +65,7 @@ def wrap_gradio_call(func, extra_outputs=None, add_stats=False):
if shared.cmd_opts.profile:
pr.disable()
s = io.StringIO()
- ps = pstats.Stats(pr, stream=s)
- ps.sort_stats(pstats.SortKey.CUMULATIVE)
- # ps.strip_dirs()
- ps.print_stats(15)
+ pstats.Stats(pr, stream=s).sort_stats(pstats.SortKey.CUMULATIVE).print_stats(15)
print('Profile Exec:', s.getvalue())
except Exception as e:
errors.display(e, 'gradio call')
diff --git a/modules/errors.py b/modules/errors.py
index 6b1efabc7..067cccdb7 100644
--- a/modules/errors.py
+++ b/modules/errors.py
@@ -34,7 +34,7 @@ def print_error_explanation(message):
def display(e: Exception, task, suppress=[]):
log.error(f"{task or 'error'}: {type(e).__name__}")
- console.print_exception(show_locals=False, max_frames=2, extra_lines=1, suppress=suppress, theme="ansi_dark", word_wrap=False, width=min([console.width, 200]))
+ console.print_exception(show_locals=False, max_frames=5, extra_lines=1, suppress=suppress, theme="ansi_dark", word_wrap=False, width=min([console.width, 200]))
def display_once(e: Exception, task):
diff --git a/modules/images.py b/modules/images.py
index 3065205bb..40c369652 100644
--- a/modules/images.py
+++ b/modules/images.py
@@ -642,18 +642,27 @@ Steps: {json_info["steps"]}, Sampler: {sampler}, CFG scale: {json_info["scale"]}
def image_data(data):
import gradio as gr
+ if data is None:
+ return gr.update(), None
+ err1 = None
+ err2 = None
try:
image = Image.open(io.BytesIO(data))
+ errors.log.debug(f'Decoded object: image={image}')
textinfo, _ = read_info_from_image(image)
return textinfo, None
- except Exception:
- pass
+ except Exception as e:
+ err1 = e
try:
+ if len(data) > 1024 * 10:
+ errors.log.warning(f'Error decoding object: data too long: {len(data)}')
+ return gr.update(), None
text = data.decode('utf8')
- assert len(text) < 10000
+ errors.log.debug(f'Decoded object: size={len(text)}')
return text, None
- except Exception:
- pass
+ except Exception as e:
+ err2 = e
+ errors.log.error(f'Error decoding object: {err1 or err2}')
return gr.update(), None
diff --git a/modules/img2img.py b/modules/img2img.py
index 9433fd899..9a6370760 100644
--- a/modules/img2img.py
+++ b/modules/img2img.py
@@ -70,6 +70,9 @@ def img2img(id_task: str, mode: int, prompt: str, negative_prompt: str, prompt_s
if shared.sd_model is None:
shared.log.warning('Model not loaded')
return
+ if init_img is None:
+ shared.log.warning('Init image not set')
+ return
shared.log.debug(f'img2img: id_task={id_task}|mode={mode}|prompt={prompt}|negative_prompt={negative_prompt}|prompt_styles={prompt_styles}|init_img={init_img}|sketch={sketch}|init_img_with_mask={init_img_with_mask}|inpaint_color_sketch={inpaint_color_sketch}|inpaint_color_sketch_orig={inpaint_color_sketch_orig}|init_img_inpaint={init_img_inpaint}|init_mask_inpaint={init_mask_inpaint}|steps={steps}|sampler_index={sampler_index}|mask_blur={mask_blur}|mask_alpha={mask_alpha}|inpainting_fill={inpainting_fill}|restore_faces={restore_faces}|tiling={tiling}|n_iter={n_iter}|batch_size={batch_size}|cfg_scale={cfg_scale}|image_cfg_scale={image_cfg_scale}|clip_skip={clip_skip}|denoising_strength={denoising_strength}|seed={seed}|subseed{subseed}|subseed_strength={subseed_strength}|seed_resize_from_h={seed_resize_from_h}|seed_resize_from_w={seed_resize_from_w}|seed_enable_extras={seed_enable_extras}|selected_scale_tab={selected_scale_tab}|height={height}|width={width}|scale_by={scale_by}|resize_mode={resize_mode}|inpaint_full_res={inpaint_full_res}|inpaint_full_res_padding={inpaint_full_res_padding}|inpainting_mask_invert={inpainting_mask_invert}|img2img_batch_input_dir={img2img_batch_input_dir}|img2img_batch_output_dir={img2img_batch_output_dir}|img2img_batch_inpaint_mask_dir={img2img_batch_inpaint_mask_dir}|override_settings_texts={override_settings_texts}|args={args}')
if sampler_index is None:
diff --git a/modules/modelloader.py b/modules/modelloader.py
index 09a3a3f3e..fc8dc7ab4 100644
--- a/modules/modelloader.py
+++ b/modules/modelloader.py
@@ -8,7 +8,7 @@ from modules.upscaler import Upscaler, UpscalerLanczos, UpscalerNearest, Upscale
from modules.paths import script_path, models_path
-def load_models(model_path: str, model_url: str = None, command_path: str = None, ext_filter=None, download_name=None, ext_blacklist=None) -> list:
+def load_models(model_path: str, model_url: str = None, command_path: str = None, ext_filter=None, download_name=None, ext_blacklist=None, diffusors=False) -> list:
"""
A one-and done loader to try finding the desired models in specified directories.
@@ -19,32 +19,45 @@ def load_models(model_path: str, model_url: str = None, command_path: str = None
@param ext_filter: An optional list of filename extensions to filter by
@return: A list of paths containing the desired model(s)
"""
- output = []
- try:
- places = []
- places.append(model_path)
- if command_path is not None and command_path != model_path and os.path.isdir(command_path):
- places.append(command_path)
- for place in places:
- for full_path in shared.walk_files(place, allowed_extensions=ext_filter):
- if os.path.islink(full_path) and not os.path.exists(full_path):
- print(f"Skipping broken symlink: {full_path}")
- continue
- if ext_blacklist is not None and any([full_path.endswith(x) for x in ext_blacklist]):
- continue
- if full_path not in output:
- output.append(full_path)
- if model_url is not None and len(output) == 0:
- if download_name is not None:
- from basicsr.utils.download_util import load_file_from_url
- dl = load_file_from_url(model_url, model_path, True, download_name)
- output.append(dl)
- else:
- output.append(model_url)
- except Exception:
- pass
+ places = []
+ places.append(model_path)
+ if command_path is not None and command_path != model_path and os.path.isdir(command_path):
+ places.append(command_path)
- return output
+ def get_checkpoints():
+ output = []
+ try:
+ for place in places:
+ for full_path in shared.walk_files(place, allowed_extensions=ext_filter):
+ if os.path.islink(full_path) and not os.path.exists(full_path):
+ print(f"Skipping broken symlink: {full_path}")
+ continue
+ if ext_blacklist is not None and any([full_path.endswith(x) for x in ext_blacklist]):
+ continue
+ if full_path not in output:
+ output.append(full_path)
+ if model_url is not None and len(output) == 0:
+ if download_name is not None:
+ from basicsr.utils.download_util import load_file_from_url
+ dl = load_file_from_url(model_url, model_path, True, download_name)
+ output.append(dl)
+ else:
+ output.append(model_url)
+ except Exception:
+ pass
+ return output
+
+ def get_diffusors():
+ output = []
+ for place in places:
+ output = os.listdir(place)
+ output = [os.path.join(place, x) for x in output]
+ return output
+
+ if not diffusors:
+ return get_checkpoints()
+ else:
+ return get_diffusors()
def friendly_name(file: str):
diff --git a/modules/processing.py b/modules/processing.py
index 7ba5f6f20..f46eb65fe 100644
--- a/modules/processing.py
+++ b/modules/processing.py
@@ -3,11 +3,13 @@ import math
import os
import hashlib
import random
+from contextlib import nullcontext
from typing import Any, Dict, List
import torch
import numpy as np
from PIL import Image, ImageFilter, ImageOps
import cv2
+import tomesd
from skimage import exposure
from ldm.data.util import AddMiDaS
from ldm.models.diffusion.ddpm import LatentDepth2ImageDiffusion
@@ -25,7 +27,7 @@ import modules.images as images
import modules.styles
import modules.sd_models as sd_models
import modules.sd_vae as sd_vae
-import tomesd # pylint: disable=wrong-import-order
+
opt_C = 4
opt_f = 8
@@ -218,6 +220,8 @@ class StableDiffusionProcessing:
source_image = devices.cond_cast_float(source_image)
# HACK: Using introspection as the Depth2Image model doesn't appear to uniquely
# identify itself with a field common to all models. The conditioning_key is also hybrid.
+ if opts.sd_backend == 'Diffusers': # TODO: img2img_image_conditioning
+ return latent_image.new_zeros(latent_image.shape[0], 5, 1, 1)
if isinstance(self.sd_model, LatentDepth2ImageDiffusion):
return self.depth2img_image_conditioning(source_image)
if self.sd_model.cond_stage_key == "edit":
@@ -456,9 +460,19 @@ def create_infotext(p: StableDiffusionProcessing, all_prompts, all_seeds, all_su
return f"{all_prompts[index]}{negative_prompt_text}\n{generation_params_text}".strip()
+def print_profile(profile, msg: str):
+ try:
+ from rich import print # pylint: disable=redefined-builtin
+ except:
+ pass
+ lines = profile.key_averages().table(sort_by="cuda_time_total", row_limit=20)
+ lines = lines.split('\n')
+ lines = [l for l in lines if '/profiler' not in l]
+ print(f'Profile {msg}:', '\n'.join(lines))
+
+
def process_images(p: StableDiffusionProcessing) -> Processed:
stored_opts = {k: opts.data[k] for k in p.override_settings.keys()}
-
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 sd_models.checkpoint_aliases.get(p.override_settings.get('sd_model_checkpoint')) is None:
@@ -471,28 +485,24 @@ def process_images(p: StableDiffusionProcessing) -> Processed:
if k == 'sd_vae':
sd_vae.reload_vae_weights()
- """
- import torch.profiler
- with torch.profiler.profile(activities=[torch.profiler.ProfilerActivity.CPU, torch.profiler.ProfilerActivity.CUDA], record_shapes=True, with_modules=True) as prof:
- with torch.profiler.record_function("process_images"):
- res = process_images_inner(p)
- print(prof.key_averages().table(sort_by="cuda_time_total", row_limit=15))
- """
-
if (opts.token_merging or cmd_opts.token_merging) and not opts.token_merging_hr_only:
sd_models.apply_token_merging(sd_model=p.sd_model, hr=False)
log.debug('Token merging applied')
- res = process_images_inner(p)
-
+ if cmd_opts.profile:
+ import torch.profiler # pylint: disable=redefined-outer-name
+ # activities=[torch.profiler.ProfilerActivity.CPU, torch.profiler.ProfilerActivity.CUDA]
+ with torch.profiler.profile(profile_memory=True, with_modules=True) as prof:
+ with torch.profiler.record_function("process_images"):
+ res = process_images_inner(p)
+ print_profile(prof, 'process_images')
+ else:
+ res = process_images_inner(p)
finally:
- # undo model optimizations made by tomesd
if opts.token_merging or cmd_opts.token_merging:
tomesd.remove_patch(p.sd_model)
log.debug('Token merging model optimizations removed')
-
- # restore opts to original state
- if p.override_settings_restore_afterwards:
+ if p.override_settings_restore_afterwards: # restore opts to original state
for k, v in stored_opts.items():
setattr(opts, k, v)
if k == 'sd_model_checkpoint':
@@ -500,7 +510,6 @@ def process_images(p: StableDiffusionProcessing) -> Processed:
if k == 'sd_vae':
sd_vae.reload_vae_weights()
-
return res
@@ -513,8 +522,9 @@ def process_images_inner(p: StableDiffusionProcessing) -> Processed:
assert p.prompt is not None
seed = get_fixed_seed(p.seed)
subseed = get_fixed_seed(p.subseed)
- modules.sd_hijack.model_hijack.apply_circular(p.tiling)
- modules.sd_hijack.model_hijack.clear_comments()
+ if opts.sd_backend == 'Original':
+ modules.sd_hijack.model_hijack.apply_circular(p.tiling)
+ modules.sd_hijack.model_hijack.clear_comments()
comments = {}
if type(p.prompt) == list:
p.all_prompts = [shared.prompt_styles.apply_styles_to_prompt(x, p.styles) for x in p.prompt]
@@ -563,10 +573,11 @@ def process_images_inner(p: StableDiffusionProcessing) -> Processed:
cache[0] = (required_prompts, steps)
return cache[1]
- with torch.no_grad(), p.sd_model.ema_scope():
+ ema_scope_context = p.sd_model.ema_scope if opts.sd_backend == 'Original' else nullcontext
+ with torch.no_grad(), ema_scope_context():
with devices.autocast():
p.init(p.all_prompts, p.all_seeds, p.all_subseeds)
- if shared.opts.live_previews_enable and opts.show_progress_type == "Approx NN":
+ if shared.opts.live_previews_enable and opts.show_progress_type == "Approx NN" and opts.sd_backend == 'Original':
sd_vae_approx.model()
if state.job_count == -1:
state.job_count = p.n_iter
@@ -604,42 +615,67 @@ def process_images_inner(p: StableDiffusionProcessing) -> Processed:
step_multiplier = 2 if sd_samplers.all_samplers_map.get(p.sampler_name).aliases[0] in ['k_dpmpp_2s_a', 'k_dpmpp_2s_a_ka', 'k_dpmpp_sde', 'k_dpmpp_sde_ka', 'k_dpm_2', 'k_dpm_2_a', 'k_heun'] else 1
except:
pass
- uc = get_conds_with_caching(prompt_parser.get_learned_conditioning, negative_prompts, p.steps * step_multiplier, cached_uc)
- c = get_conds_with_caching(prompt_parser.get_multicond_learned_conditioning, prompts, p.steps * step_multiplier, cached_c)
- if len(model_hijack.comments) > 0:
- for comment in model_hijack.comments:
- comments[comment] = 1
if p.n_iter > 1:
shared.state.job = f"Batch {n+1} out of {p.n_iter}"
- with devices.without_autocast() if devices.unet_needs_upcast else devices.autocast():
- samples_ddim = p.sample(conditioning=c, unconditional_conditioning=uc, seeds=seeds, subseeds=subseeds, subseed_strength=p.subseed_strength, prompts=prompts)
- x_samples_ddim = [decode_first_stage(p.sd_model, samples_ddim[i:i+1].to(dtype=devices.dtype_vae))[0].cpu() for i in range(samples_ddim.size(0))]
- try:
- for x in x_samples_ddim:
- devices.test_for_nans(x, "vae")
- except devices.NansException as e:
- if not shared.opts.no_half and not shared.opts.no_half_vae and shared.cmd_opts.rollback_vae:
- log.warning('Tensor with all NaNs was produced in VAE')
- devices.dtype_vae = torch.bfloat16
- vae_file, vae_source = sd_vae.resolve_vae(p.sd_model.sd_model_checkpoint)
- sd_vae.load_vae(p.sd_model, vae_file, vae_source)
- x_samples_ddim = [decode_first_stage(p.sd_model, samples_ddim[i:i+1].to(dtype=devices.dtype_vae))[0].cpu() for i in range(samples_ddim.size(0))]
+
+ if opts.sd_backend == 'Original':
+ uc = get_conds_with_caching(prompt_parser.get_learned_conditioning, negative_prompts, p.steps * step_multiplier, cached_uc)
+ c = get_conds_with_caching(prompt_parser.get_multicond_learned_conditioning, prompts, p.steps * step_multiplier, cached_c)
+ if len(model_hijack.comments) > 0:
+ for comment in model_hijack.comments:
+ comments[comment] = 1
+ with devices.without_autocast() if devices.unet_needs_upcast else devices.autocast():
+ samples_ddim = p.sample(conditioning=c, unconditional_conditioning=uc, seeds=seeds, subseeds=subseeds, subseed_strength=p.subseed_strength, prompts=prompts)
+ x_samples_ddim = [decode_first_stage(p.sd_model, samples_ddim[i:i+1].to(dtype=devices.dtype_vae))[0].cpu() for i in range(samples_ddim.size(0))]
+ try:
for x in x_samples_ddim:
devices.test_for_nans(x, "vae")
- else:
- raise e
- x_samples_ddim = torch.stack(x_samples_ddim).float()
- x_samples_ddim = torch.clamp((x_samples_ddim + 1.0) / 2.0, min=0.0, max=1.0)
- del samples_ddim
- if shared.cmd_opts.lowvram or shared.cmd_opts.medvram:
- lowvram.send_everything_to_cpu()
- devices.torch_gc()
- if p.scripts is not None:
- p.scripts.postprocess_batch(p, x_samples_ddim, batch_number=n)
+ except devices.NansException as e:
+ if not shared.opts.no_half and not shared.opts.no_half_vae and shared.cmd_opts.rollback_vae:
+ log.warning('Tensor with all NaNs was produced in VAE')
+ devices.dtype_vae = torch.bfloat16
+ vae_file, vae_source = sd_vae.resolve_vae(p.sd_model.sd_model_checkpoint)
+ sd_vae.load_vae(p.sd_model, vae_file, vae_source)
+ x_samples_ddim = [decode_first_stage(p.sd_model, samples_ddim[i:i+1].to(dtype=devices.dtype_vae))[0].cpu() for i in range(samples_ddim.size(0))]
+ for x in x_samples_ddim:
+ devices.test_for_nans(x, "vae")
+ else:
+ raise e
+ x_samples_ddim = torch.stack(x_samples_ddim).float()
+ x_samples_ddim = torch.clamp((x_samples_ddim + 1.0) / 2.0, min=0.0, max=1.0)
+ del samples_ddim
+ if shared.cmd_opts.lowvram or shared.cmd_opts.medvram:
+ lowvram.send_everything_to_cpu()
+ devices.torch_gc()
+ if p.scripts is not None:
+ p.scripts.postprocess_batch(p, x_samples_ddim, batch_number=n)
+ else: # TODO Diffusers
+ generator = [torch.Generator(device="cpu").manual_seed(s) for s in seeds]
+ if shared.sd_model.scheduler.name != p.sampler_name:
+ sampler = sd_samplers.all_samplers_map.get(p.sampler_name, None)
+ if sampler is None:
+ sampler = sd_samplers.all_samplers_map.get("UniPC")
+ scheduler = sampler.constructor(shared.sd_model.sd_checkpoint_info.filename)
+ shared.sd_model.scheduler = scheduler.sampler
+ output = shared.sd_model(
+ prompt=prompts,
+ negative_prompt=negative_prompts,
+ num_inference_steps=p.steps,
+ guidance_scale=p.cfg_scale,
+ height=p.height,
+ width=p.width,
+ generator=generator,
+ output_type="np",
+ )
+ x_samples_ddim = output.images
+
for i, x_sample in enumerate(x_samples_ddim):
p.batch_index = i
- x_sample = 255. * np.moveaxis(x_sample.cpu().numpy(), 0, 2)
- x_sample = x_sample.astype(np.uint8)
+ if opts.sd_backend == 'Original':
+ x_sample = 255. * np.moveaxis(x_sample.cpu().numpy(), 0, 2)
+ x_sample = x_sample.astype(np.uint8)
+ else:
+ x_sample = (255. * x_sample).astype(np.uint8)
if p.restore_faces:
if opts.save and not p.do_not_save_samples and opts.save_images_before_face_restoration:
orig = p.restore_faces
@@ -891,7 +927,7 @@ class StableDiffusionProcessingImg2Img(StableDiffusionProcessing):
self.init_images = init_images
self.resize_mode: int = resize_mode
self.denoising_strength: float = denoising_strength
- self.image_cfg_scale: float = image_cfg_scale if shared.sd_model.cond_stage_key == "edit" else None
+ self.image_cfg_scale: float = image_cfg_scale if (shared.sd_model is not None) and hasattr(shared.sd_model, 'cond_stage_key') and (shared.sd_model.cond_stage_key == "edit") else None
self.init_latent = None
self.image_mask = mask
self.latent_mask = None
diff --git a/modules/script_loading.py b/modules/script_loading.py
index 2bc9b6fda..6827515fc 100644
--- a/modules/script_loading.py
+++ b/modules/script_loading.py
@@ -12,10 +12,7 @@ def load_module(path, detailed=False):
try:
module_spec.loader.exec_module(module)
except Exception as e:
- if detailed:
- errors.display(e, f'Module load: {path}')
- else:
- errors.log.error(f'Module load: {path}')
+ errors.display(e, f'Module load: {path}')
return module
@@ -31,11 +28,8 @@ def preload_extensions(extensions_dir, parser, detailed=False):
if not os.path.isfile(preload_script):
continue
try:
- module = load_module(preload_script)
+ module = load_module(preload_script, detailed)
if hasattr(module, 'preload'):
module.preload(parser)
except Exception as e:
- if detailed:
- errors.display(e, f'Extension preload: {preload_script}')
- else:
- errors.log.error(f'Extension preload: {preload_script}')
+ errors.display(e, f'Extension preload: {preload_script}')
diff --git a/modules/sd_hijack_clip.py b/modules/sd_hijack_clip.py
index 4d79cd3fa..aa38c3f77 100644
--- a/modules/sd_hijack_clip.py
+++ b/modules/sd_hijack_clip.py
@@ -136,7 +136,6 @@ class FrozenCLIPEmbedderWithCustomWordsBase(torch.nn.Module):
position += embedding_length_in_tokens
if len(chunk.tokens) > 0 or len(chunks) == 0:
next_chunk(is_last=True)
- # print('CHUNKS', [vars(c) for c in chunks]) # TODO
return chunks, token_count
def process_texts(self, texts):
diff --git a/modules/sd_models.py b/modules/sd_models.py
index cc460fb52..bfbb7eb82 100644
--- a/modules/sd_models.py
+++ b/modules/sd_models.py
@@ -27,7 +27,7 @@ checkpoints_loaded = collections.OrderedDict()
skip_next_load = False
-class CheckpointInfo:
+class CheckpointInfo: # TODO Diffusers
def __init__(self, filename):
self.filename = filename
abspath = os.path.abspath(filename)
@@ -42,8 +42,13 @@ class CheckpointInfo:
self.name = name
self.name_for_extra = os.path.splitext(os.path.basename(filename))[0]
self.model_name = os.path.splitext(name.replace("/", "_").replace("\\", "_"))[0]
- self.hash = model_hash(filename)
- self.sha256 = hashes.sha256_from_cache(self.filename, f"checkpoint/{name}")
+ if shared.opts.sd_backend == 'Original':
+ self.hash = model_hash(self.filename)
+ self.sha256 = hashes.sha256_from_cache(self.filename, f"checkpoint/{name}")
+ else: # TODO Diffusers calculate hash
+ # sd_model.unet.config._name_or_path.split("/")[-2]
+ self.hash = 'ABCDEFGH'
+ self.sha256 = 'ABCDEFGH'
self.shorthash = self.sha256[0:10] if self.sha256 else None
self.title = name if self.shorthash is None else f'{name} [{self.shorthash}]'
self.ids = [self.hash, self.model_name, self.title, name, f'{name} [{self.hash}]'] + ([self.shorthash, self.sha256, f'{self.name} [{self.shorthash}]'] if self.shorthash else [])
@@ -99,9 +104,12 @@ def checkpoint_tiles():
def list_models():
checkpoints_list.clear()
checkpoint_aliases.clear()
- model_list = modelloader.load_models(model_path=os.path.join(models_path, 'Stable-diffusion'), model_url=None, command_path=shared.opts.ckpt_dir, ext_filter=[".ckpt", ".safetensors"], download_name=None, ext_blacklist=[".vae.ckpt", ".vae.safetensors"])
+ if shared.opts.sd_backend == 'Original':
+ model_list = modelloader.load_models(model_path=os.path.join(models_path, 'Stable-diffusion'), model_url=None, command_path=shared.opts.ckpt_dir, ext_filter=[".ckpt", ".safetensors"], download_name=None, ext_blacklist=[".vae.ckpt", ".vae.safetensors"])
+ else:
+ model_list = modelloader.load_models(model_path=os.path.join(models_path, 'Diffusers'), model_url=None, command_path=shared.opts.diffusers_dir, ext_filter=[".ckpt", ".safetensors"], download_name=None, ext_blacklist=[".vae.ckpt", ".vae.safetensors"])
if shared.cmd_opts.ckpt is not None:
- if not os.path.exists(shared.cmd_opts.ckpt):
+ if not os.path.exists(shared.cmd_opts.ckpt) and shared.opts.sd_backend == 'Original':
if shared.cmd_opts.ckpt.lower() != "none":
shared.log.warning(f"Requested checkpoint not found: {shared.cmd_opts.ckpt}")
else:
@@ -363,7 +371,12 @@ class SdModelData:
if self.sd_model is None:
with self.lock:
try:
- load_model()
+ if shared.opts.sd_backend == 'Original':
+ load_model()
+ elif shared.opts.sd_backend == 'Diffusers':
+ load_diffusers()
+ else:
+ shared.log.error(f"Unknown Stable Diffusion backend: {shared.opts.sd_backend}")
except Exception as e:
shared.log.error("Failed to load stable diffusion model")
errors.display(e, "loading stable diffusion model")
@@ -377,6 +390,39 @@ class SdModelData:
model_data = SdModelData()
+def load_diffusers(checkpoint_info=None, already_loaded_state_dict=None, timer=None):
+ if timer is None:
+ timer = Timer()
+ import diffusers
+ timer.record("diffusers")
+ diffusor_config = {
+ "force_download": False,
+ "safety_checker": None,
+ "resume_download": True,
+ "low_cpu_mem_usage": True,
+ "use_safetensors": True,
+ "cache_dir": shared.opts.diffusers_dir,
+ "torch_dtype": devices.dtype,
+ }
+ shared.log.warning("Using experimental Diffusers backend for Stable Diffusion")
+ if shared.opts.data['sd_model_checkpoint'] == 'model.ckpt':
+ shared.opts.data['sd_model_checkpoint'] = "runwayml/stable-diffusion-v1-5"
+ sd_model = None
+ try:
+ checkpoint_info = checkpoint_info or select_checkpoint()
+ scheduler = diffusers.UniPCMultistepScheduler.from_pretrained(checkpoint_info.filename, subfolder="scheduler")
+ scheduler.name = 'UniPC'
+ sd_model = diffusers.DiffusionPipeline.from_pretrained(checkpoint_info.filename, scheduler=scheduler, **diffusor_config)
+ sd_model.to(devices.device)
+ sd_model.sd_checkpoint_info = checkpoint_info
+ sd_model.sd_model_hash = checkpoint_info.hash
+ except Exception as e:
+ shared.log.error("Failed to load diffusers model")
+ errors.display(e, "loading Diffusers model")
+ shared.sd_model = sd_model
+ timer.record("load")
+
+
def load_model(checkpoint_info=None, already_loaded_state_dict=None, timer=None):
from modules import lowvram, sd_hijack
checkpoint_info = checkpoint_info or select_checkpoint()
diff --git a/modules/sd_samplers.py b/modules/sd_samplers.py
index bc82371c8..2a13f5030 100644
--- a/modules/sd_samplers.py
+++ b/modules/sd_samplers.py
@@ -1,10 +1,16 @@
-from modules import sd_samplers_compvis, sd_samplers_kdiffusion, shared
+from modules import sd_samplers_compvis, sd_samplers_kdiffusion, sd_samplers_diffusors, shared
from modules.sd_samplers_common import samples_to_image_grid, sample_to_image # pylint: disable=unused-import
+from modules.shared import opts
-all_samplers = [
- *sd_samplers_kdiffusion.samplers_data_k_diffusion,
- *sd_samplers_compvis.samplers_data_compvis,
-]
+if opts.sd_backend == 'Original':
+ all_samplers = [
+ *sd_samplers_kdiffusion.samplers_data_k_diffusion,
+ *sd_samplers_compvis.samplers_data_compvis,
+ ]
+else:
+ all_samplers = [
+ *sd_samplers_diffusors.samplers_data_diffusors,
+ ]
all_samplers_map = {x.name: x for x in all_samplers}
samplers = all_samplers
samplers_for_img2img = all_samplers
@@ -17,9 +23,14 @@ def create_sampler(name, model):
else:
config = all_samplers[0]
assert config is not None, f'bad sampler name: {name}'
- sampler = config.constructor(model)
- sampler.config = config
- return sampler
+ if opts.sd_backend == 'Original':
+ sampler = config.constructor(model)
+ sampler.config = config
+ return sampler
+ else:
+ sampler = config.constructor(model.sd_checkpoint_info.filename)
+ model.scheduler = sampler.sampler
+ return sampler.sampler
def set_samplers():
diff --git a/modules/sd_samplers_diffusors.py b/modules/sd_samplers_diffusors.py
new file mode 100644
index 000000000..3d102dca4
--- /dev/null
+++ b/modules/sd_samplers_diffusors.py
@@ -0,0 +1,45 @@
+from diffusers import (
+ DDIMScheduler,
+ DDPMScheduler,
+ DEISMultistepScheduler,
+ DPMSolverMultistepScheduler,
+ EulerAncestralDiscreteScheduler,
+ EulerDiscreteScheduler,
+ HeunDiscreteScheduler,
+ IPNDMScheduler,
+ KDPM2AncestralDiscreteScheduler,
+ PNDMScheduler,
+ UniPCMultistepScheduler,
+ # KarrasVeScheduler,
+ # RePaintScheduler,
+ # ScoreSdeVeScheduler,
+ # UnCLIPScheduler,
+ # VQDiffusionScheduler,
+)
+from modules import sd_samplers_common
+ # scheduler = diffusers.UniPCMultistepScheduler.from_pretrained(shared.cmd_opts.ckpt, subfolder="scheduler")
+
+samplers_data_diffusors = [
+ sd_samplers_common.SamplerData('UniPC', lambda model: DiffusionSampler('UniPC', UniPCMultistepScheduler, model), [], {}),
+ sd_samplers_common.SamplerData('DDIM', lambda model: DiffusionSampler('DDIM', DDIMScheduler, model), [], {}),
+ sd_samplers_common.SamplerData('DDPMS', lambda model: DiffusionSampler('DDPMS', DDPMScheduler, model), [], {}),
+ sd_samplers_common.SamplerData('DEIS', lambda model: DiffusionSampler('DEIS', DEISMultistepScheduler, model), [], {}),
+ sd_samplers_common.SamplerData('DPMSolver', lambda model: DiffusionSampler('DPMSolver', DPMSolverMultistepScheduler, model), [], {}),
+ sd_samplers_common.SamplerData('Euler', lambda model: DiffusionSampler('Euler', EulerDiscreteScheduler, model), [], {}),
+ sd_samplers_common.SamplerData('EulerAncestral', lambda model: DiffusionSampler('EulerAncestral', EulerAncestralDiscreteScheduler, model), [], {}),
+ sd_samplers_common.SamplerData('Heun', lambda model: DiffusionSampler('Heun', HeunDiscreteScheduler, model), [], {}),
+ sd_samplers_common.SamplerData('IPNDM', lambda model: DiffusionSampler('IPNDM', IPNDMScheduler, model), [], {}),
+ sd_samplers_common.SamplerData('KDPM2Ancestral', lambda model: DiffusionSampler('KDPM2Ancestral', KDPM2AncestralDiscreteScheduler, model), [], {}),
+ sd_samplers_common.SamplerData('PNDMS', lambda model: DiffusionSampler('PNDMS', PNDMScheduler, model), [], {}),
+ # sd_samplers_common.SamplerData('KarrasVe', lambda model: DiffusionSampler('KarrasVe', KarrasVeScheduler, model), [], {}),
+ # sd_samplers_common.SamplerData('RePaint', lambda model: DiffusionSampler('RePaint', RePaintScheduler, model), [], {}),
+ # sd_samplers_common.SamplerData('ScoreSdeVe', lambda model: DiffusionSampler('ScoreSdeVe', ScoreSdeVeScheduler, model), [], {}),
+ # sd_samplers_common.SamplerData('UnCLIP', lambda model: DiffusionSampler('UnCLIP', UnCLIPScheduler, model), [], {}),
+ # sd_samplers_common.SamplerData('VQDiffusion', lambda model: DiffusionSampler('VQDiffusion', VQDiffusionScheduler, model), [], {}),
+]
+
+
+class DiffusionSampler:
+ def __init__(self, name, constructor, sd_model):
+ self.sampler = constructor.from_pretrained(sd_model, subfolder="scheduler")
+ self.sampler.name = name
diff --git a/modules/sd_samplers_kdiffusion.py b/modules/sd_samplers_kdiffusion.py
index 3dbc9498f..bb8ad4d06 100644
--- a/modules/sd_samplers_kdiffusion.py
+++ b/modules/sd_samplers_kdiffusion.py
@@ -82,7 +82,7 @@ class CFGDenoiser(torch.nn.Module):
# at self.image_cfg_scale == 1.0 produced results for edit model are the same as with normal sampling,
# so is_edit_model is set to False to support AND composition.
- is_edit_model = shared.sd_model.cond_stage_key == "edit" and self.image_cfg_scale is not None and self.image_cfg_scale != 1.0
+ is_edit_model = (shared.sd_model is not None) and hasattr(shared.sd_model, 'cond_stage_key') and (shared.sd_model.cond_stage_key == "edit") and (self.image_cfg_scale is not None) and (self.image_cfg_scale != 1.0)
conds_list, tensor = prompt_parser.reconstruct_multicond_batch(cond, self.step)
uncond = prompt_parser.reconstruct_cond_batch(uncond, self.step)
diff --git a/modules/shared.py b/modules/shared.py
index a24fb3631..40f7e6a8d 100644
--- a/modules/shared.py
+++ b/modules/shared.py
@@ -192,6 +192,7 @@ def list_checkpoint_tiles():
import modules.sd_models # pylint: disable=W0621
return modules.sd_models.checkpoint_tiles()
+
default_checkpoint = list_checkpoint_tiles()[0] if len(list_checkpoint_tiles()) > 0 else "model.ckpt"
@@ -251,29 +252,24 @@ options_templates.update(options_section(('sd', "Stable Diffusion"), {
"sd_vae": OptionInfo("Automatic", "Select VAE", gr.Dropdown, lambda: {"choices": shared_items.sd_vae_items()}, refresh=shared_items.refresh_vae_list),
"stream_load": OptionInfo(False, "When loading models attempt stream loading optimized for slow or network storage"),
"model_reuse_dict": OptionInfo(False, "When loading models attempt to reuse previous model dictionary"),
- "inpainting_mask_weight": OptionInfo(1.0, "Inpainting conditioning mask strength", gr.Slider, {"minimum": 0.0, "maximum": 1.0, "step": 0.01}),
- "initial_noise_multiplier": OptionInfo(1.0, "Noise multiplier for img2img", gr.Slider, {"minimum": 0.1, "maximum": 1.5, "step": 0.01}),
- "img2img_color_correction": OptionInfo(False, "Apply color correction to img2img results to match original colors"),
- "img2img_fix_steps": OptionInfo(False, "For image processing do exactly the amount of steps as specified"),
- "img2img_background_color": OptionInfo("#ffffff", "With img2img fill image's transparent parts with this color", ui_components.FormColorPicker, {}),
- "enable_quantization": OptionInfo(True, "Enable quantization in K samplers for sharper and cleaner results"),
- "comma_padding_backtrack": OptionInfo(20, "Increase coherency by padding from the last comma within n tokens when using more than 75 tokens", gr.Slider, {"minimum": 0, "maximum": 74, "step": 1 }),
- "CLIP_stop_at_last_layers": OptionInfo(1, "Clip skip", gr.Slider, {"minimum": 1, "maximum": 8, "step": 1, "visible": False}),
- "upcast_attn": OptionInfo(False, "Upcast cross attention layer to FP32"),
"cross_attention_optimization": OptionInfo(cross_attention_optimization_default, "Cross-attention optimization method", gr.Radio, lambda: {"choices": shared_items.list_crossattention() }),
"cross_attention_options": OptionInfo([], "Cross-attention advanced options", gr.CheckboxGroup, lambda: {"choices": ['xFormers enable flash Attention', 'SDP disable memory attention']}),
"sub_quad_q_chunk_size": OptionInfo(512, "Sub-quadratic cross-attention query chunk size for the layer optimization to use", gr.Slider, {"minimum": 16, "maximum": 8192, "step": 8}),
"sub_quad_kv_chunk_size": OptionInfo(512, "Sub-quadratic cross-attentionkv chunk size for the sub-quadratic cross-attention layer optimization to use", gr.Slider, {"minimum": 0, "maximum": 8192, "step": 8}),
"sub_quad_chunk_threshold": OptionInfo(80, "Sub-quadratic cross-attention percentage of VRAM chunking threshold", gr.Slider, {"minimum": 0, "maximum": 100, "step": 1}),
- "always_batch_cond_uncond": OptionInfo(False, "Disables cond/uncond batching that is enabled to save memory with --medvram or --lowvram"),
"prompt_attention": OptionInfo("Full parser", "Prompt attention parser", gr.Radio, lambda: {"choices": ["Full parser", "Compel parser", "A1111 parser", "Fixed attention"] }),
"prompt_mean_norm": OptionInfo(True, "Prompt attention mean normalization"),
+ "always_batch_cond_uncond": OptionInfo(False, "Disables cond/uncond batching that is enabled to save memory with --medvram or --lowvram"),
+ "enable_quantization": OptionInfo(True, "Enable quantization in K samplers for sharper and cleaner results"),
+ "comma_padding_backtrack": OptionInfo(20, "Increase coherency by padding from the last comma within n tokens when using more than 75 tokens", gr.Slider, {"minimum": 0, "maximum": 74, "step": 1 }),
+ "sd_backend": OptionInfo("Original", "Stable Diffusion backend (experimental)", gr.Radio, lambda: {"choices": ["Original", "Diffusers"] }),
}))
options_templates.update(options_section(('system-paths', "System Paths"), {
- "temp_dir": OptionInfo("", "Directory for temporary images; leave empty for default"),
+ "temp_dir": OptionInfo("", "Directory for temporary images; leave empty for default"),
"clean_temp_dir_at_start": OptionInfo(True, "Cleanup non-default temporary directory when starting webui"),
"ckpt_dir": OptionInfo(os.path.join(paths.models_path, 'Stable-diffusion'), "Path to directory with stable diffusion checkpoints"),
+ "diffusers_dir": OptionInfo(os.path.join(paths.models_path, 'Diffusers'), "Path to directory with stable diffusion diffusers"),
"vae_dir": OptionInfo(os.path.join(paths.models_path, 'VAE'), "Path to directory with VAE files"),
"embeddings_dir": OptionInfo(os.path.join(paths.models_path, 'embeddings'), "Embeddings directory for textual inversion"),
"hypernetwork_dir": OptionInfo(os.path.join(paths.models_path, 'hypernetworks'), "Hypernetwork directory"),
@@ -289,10 +285,9 @@ options_templates.update(options_section(('system-paths', "System Paths"), {
"lora_dir": OptionInfo(os.path.join(paths.models_path, 'Lora'), "Path to directory with Lora network(s)"),
"lyco_dir": OptionInfo(os.path.join(paths.models_path, 'LyCORIS'), "Path to directory with LyCORIS network(s)"),
"styles_dir": OptionInfo(os.path.join(paths.data_path, 'styles.csv'), "Path to user-defined styles file"),
- # "gfpgan_model": OptionInfo("", "GFPGAN model file name"),
}))
-options_templates.update(options_section(('saving-images', "Image options"), {
+options_templates.update(options_section(('saving-images', "Image Options"), {
"samples_save": OptionInfo(True, "Always save all generated images"),
"samples_format": OptionInfo('jpg', 'File format for images'),
"samples_filename_pattern": OptionInfo("[seed]-[prompt_spaces]", "Images filename pattern", component_args=hide_dirs),
@@ -324,6 +319,16 @@ options_templates.update(options_section(('saving-images', "Image options"), {
"directories_max_prompt_words": OptionInfo(8, "Max prompt words for [prompt_words] pattern", gr.Slider, {"minimum": 1, "maximum": 20, "step": 1, **hide_dirs}),
}))
+options_templates.update(options_section(('image-processing', "Image Processing"), {
+ "img2img_color_correction": OptionInfo(False, "Apply color correction to img2img results to match original colors"),
+ "img2img_fix_steps": OptionInfo(False, "For image processing do exactly the amount of steps as specified"),
+ "img2img_background_color": OptionInfo("#ffffff", "With img2img fill image's transparent parts with this color", ui_components.FormColorPicker, {}),
+ "inpainting_mask_weight": OptionInfo(1.0, "Inpainting conditioning mask strength", gr.Slider, {"minimum": 0.0, "maximum": 1.0, "step": 0.01}),
+ "initial_noise_multiplier": OptionInfo(1.0, "Noise multiplier for img2img", gr.Slider, {"minimum": 0.1, "maximum": 1.5, "step": 0.01}),
+ "CLIP_stop_at_last_layers": OptionInfo(1, "Clip skip", gr.Slider, {"minimum": 1, "maximum": 8, "step": 1, "visible": False}),
+}))
+
+
options_templates.update(options_section(('saving-paths', "Image Paths"), {
"outdir_samples": OptionInfo("", "Output directory for images; if empty, defaults to three directories below", component_args=hide_dirs),
"outdir_txt2img_samples": OptionInfo("outputs/text", 'Output directory for txt2img images', component_args=hide_dirs),
@@ -342,11 +347,12 @@ options_templates.update(options_section(('cuda', "Compute Settings"), {
"cuda_dtype": OptionInfo("FP32" if sys.platform == "darwin" else "FP16", "Device precision type", gr.Radio, lambda: {"choices": ["FP32", "FP16", "BF16"]}),
"no_half": OptionInfo(False, "Use full precision for model (--no-half)", None, None, None),
"no_half_vae": OptionInfo(False, "Use full precision for VAE (--no-half-vae)"),
- "upcast_sampling": OptionInfo(True if sys.platform == "darwin" or cmd_opts.use_ipex else False, "Enable upcast sampling. Usually produces similar results to --no-half with better performance while using less memory"),
- "disable_nan_check": OptionInfo(True, "Do not check if produced images/latent spaces have NaN values"),
+ "upcast_sampling": OptionInfo(True if sys.platform == "darwin" or cmd_opts.use_ipex else False, "Enable upcast sampling"),
+ "upcast_attn": OptionInfo(False, "Enable upcast cross attention layer"),
+ "disable_nan_check": OptionInfo(True, "Disable NaN check in produced images/latent spaces"),
"rollback_vae": OptionInfo(False, "Attempt to roll back VAE when produced NaN values, requires NaN check (experimental)"),
"opt_channelslast": OptionInfo(False, "Use channels last as torch memory format "),
- "cudnn_benchmark": OptionInfo(False, "Enable cuDNN benchmark feature"),
+ "cudnn_benchmark": OptionInfo(False, "Enable full-depth cuDNN benchmark feature"),
"cuda_allow_tf32": OptionInfo(True, "Allow TF32 math ops"),
"cuda_allow_tf16_reduced": OptionInfo(True, "Allow TF16 reduced precision math ops"),
"cuda_compile": OptionInfo(False, "Enable model compile (experimental)"),
@@ -778,7 +784,7 @@ def get_version():
try:
import subprocess
res = subprocess.run('git log --pretty=format:"%h %ad" -1 --date=short', stdout = subprocess.PIPE, stderr = subprocess.PIPE, shell=True, check=True)
- ver = res.stdout.decode(encoding = 'utf8', errors='ignore') if len(res.stdout) > 0 else ''
+ ver = res.stdout.decode(encoding = 'utf8', errors='ignore') if len(res.stdout) > 0 else ' '
githash, updated = ver.split(' ')
res = subprocess.run('git remote get-url origin', stdout = subprocess.PIPE, stderr = subprocess.PIPE, shell=True, check=True)
origin = res.stdout.decode(encoding = 'utf8', errors='ignore') if len(res.stdout) > 0 else ''
@@ -792,7 +798,6 @@ def get_version():
}
except:
version = { 'app': 'sd.next' }
- pass
return version
diff --git a/modules/textual_inversion/textual_inversion.py b/modules/textual_inversion/textual_inversion.py
index 485bf0b23..137309d4d 100644
--- a/modules/textual_inversion/textual_inversion.py
+++ b/modules/textual_inversion/textual_inversion.py
@@ -207,6 +207,8 @@ class EmbeddingDatabase:
continue
def load_textual_inversion_embeddings(self, force_reload=False):
+ if shared.opts.sd_backend == 'Diffusers': # TODO Diffusers
+ return
if not force_reload:
need_reload = False
for _path, embdir in self.embedding_dirs.items():
diff --git a/modules/ui.py b/modules/ui.py
index cae271429..5b61ae83b 100644
--- a/modules/ui.py
+++ b/modules/ui.py
@@ -28,6 +28,7 @@ import modules.textual_inversion.ui
import modules.sd_samplers
from modules.textual_inversion import textual_inversion
+
modules.errors.install()
mimetypes.init()
mimetypes.add_type('application/javascript', '.js')
@@ -203,7 +204,13 @@ def update_token_counter(text, steps):
prompt_schedules = [[[steps, text]]]
flat_prompts = reduce(lambda list1, list2: list1+list2, prompt_schedules)
prompts = [prompt_text for step, prompt_text in flat_prompts]
- token_count, max_length = max([sd_hijack.model_hijack.get_prompt_lengths(prompt) for prompt in prompts], key=lambda args: args[0])
+ if opts.sd_backend == 'Original':
+ token_count, max_length = max([sd_hijack.model_hijack.get_prompt_lengths(prompt) for prompt in prompts], key=lambda args: args[0])
+ else:
+ tokenizer = modules.shared.sd_model.tokenizer
+ has_bos_token, has_eos_token = tokenizer.bos_token_id is not None, tokenizer.eos_token_id is not None
+ token_count = max([len(modules.shared.sd_model.tokenizer(prompt)) for prompt in prompts]) - int(has_bos_token) - int(has_eos_token)
+ max_length = tokenizer.model_max_length - int(has_bos_token) - int(has_eos_token)
return f"{token_count}/{max_length}"
@@ -299,13 +306,12 @@ def create_output_panel(tabname, outdir):
def create_sampler_and_steps_selection(choices, tabname):
with FormRow(elem_id=f"sampler_selection_{tabname}"):
if 'UniPC' in [sampler.name for sampler in choices]:
- chosen_sampler_name = 'UniPC'
+ default_sampler_name = 'UniPC'
elif 'Euler a' in [sampler.name for sampler in choices]:
- chosen_sampler_name = 'Euler a'
+ default_sampler_name = 'Euler a'
else:
- chosen_sampler_name = modules.sd_samplers.samplers[0].name
-
- sampler_index = gr.Dropdown(label='Sampling method', elem_id=f"{tabname}_sampling", choices=[x.name for x in choices], value=chosen_sampler_name if tabname == 'txt2img' else "Euler a", type="index")
+ default_sampler_name = modules.sd_samplers.samplers[0].name
+ sampler_index = gr.Dropdown(label='Sampling method', elem_id=f"{tabname}_sampling", choices=[x.name for x in choices], value=default_sampler_name, type="index")
steps = gr.Slider(minimum=1, maximum=99, step=1, elem_id=f"{tabname}_steps", label="Sampling steps", value=20)
return steps, sampler_index
@@ -1452,9 +1458,9 @@ def create_ui():
show_progress=info.refresh is not None,
)
- update_image_cfg_scale_visibility = lambda: gr.update(visible=modules.shared.sd_model and modules.shared.sd_model.cond_stage_key == "edit") # pylint: disable=unnecessary-lambda-assignment
- text_settings.change(fn=update_image_cfg_scale_visibility, inputs=[], outputs=[image_cfg_scale])
- demo.load(fn=update_image_cfg_scale_visibility, inputs=[], outputs=[image_cfg_scale])
+ image_cfg_scale_visibility = (modules.shared.sd_model is not None) and hasattr(modules.shared.sd_model, 'cond_stage_key') and (modules.shared.sd_model.cond_stage_key == "edit") # pix2pix
+ text_settings.change(fn=lambda: gr.update(visible=image_cfg_scale_visibility), inputs=[], outputs=[image_cfg_scale])
+ demo.load(fn=lambda: gr.update(visible=image_cfg_scale_visibility), inputs=[], outputs=[image_cfg_scale])
button_set_checkpoint = gr.Button('Change checkpoint', elem_id='change_checkpoint', visible=False)
button_set_checkpoint.click(
diff --git a/scripts/postprocessing_upscale.py b/scripts/postprocessing_upscale.py
index 55c43fc41..fd9ccd893 100644
--- a/scripts/postprocessing_upscale.py
+++ b/scripts/postprocessing_upscale.py
@@ -79,29 +79,25 @@ class ScriptPostprocessingUpscale(scripts_postprocessing.ScriptPostprocessing):
return image
def process(self, pp: scripts_postprocessing.PostprocessedImage, upscale_mode=1, upscale_by=2.0, upscale_to_width=None, upscale_to_height=None, upscale_crop=False, upscaler_1_name=None, upscaler_2_name=None, upscaler_2_visibility=0.0): # pylint: disable=arguments-differ
+
if upscaler_1_name == "None":
upscaler_1_name = None
-
upscaler1 = next(iter([x for x in shared.sd_upscalers if x.name == upscaler_1_name]), None)
if not upscaler1:
- shared.log.warning(f"Could not find upscaler: {upscaler_1_name or ''}")
+ if upscaler_1_name is not None:
+ shared.log.warning(f"Could not find upscaler: {upscaler_1_name or ''}")
return
-
- if upscaler_2_name == "None":
- upscaler_2_name = None
-
- upscaler2 = next(iter([x for x in shared.sd_upscalers if x.name == upscaler_2_name and x.name != "None"]), None)
- if not upscaler2 and (upscaler_2_name is not None):
- shared.log.warning(f"Could not find upscaler: {upscaler_2_name or ''}")
- return
-
upscaled_image = self.upscale(pp.image, pp.info, upscaler1, upscale_mode, upscale_by, upscale_to_width, upscale_to_height, upscale_crop)
pp.info["Postprocess upscaler"] = upscaler1.name
+ if upscaler_2_name == "None":
+ upscaler_2_name = None
+ upscaler2 = next(iter([x for x in shared.sd_upscalers if x.name == upscaler_2_name and x.name != "None"]), None)
+ if not upscaler2 and (upscaler_2_name is not None):
+ shared.log.warning(f"Could not find upscaler: {upscaler_2_name or ''}")
if upscaler2 and upscaler_2_visibility > 0:
second_upscale = self.upscale(pp.image, pp.info, upscaler2, upscale_mode, upscale_by, upscale_to_width, upscale_to_height, upscale_crop)
upscaled_image = Image.blend(upscaled_image, second_upscale, upscaler_2_visibility)
-
pp.info["Postprocess upscaler 2"] = upscaler2.name
pp.image = upscaled_image
@@ -130,7 +126,7 @@ class ScriptPostprocessingUpscaleSimple(ScriptPostprocessingUpscale):
upscaler1 = next(iter([x for x in shared.sd_upscalers if x.name == upscaler_name]), None)
if upscaler1 is None:
- shared.log.warning(f"Could not find upscaler: {upscaler_name or ''}")
+ shared.log.debug(f"Upscaler not found: {upscaler_name}")
pp.image = self.upscale(pp.image, pp.info, upscaler1, 0, upscale_by, 0, 0, False)
pp.info["Postprocess upscaler"] = upscaler1.name
diff --git a/webui.py b/webui.py
index dee75fa4e..89f1b13a9 100644
--- a/webui.py
+++ b/webui.py
@@ -150,25 +150,13 @@ def initialize():
def load_model():
shared.state.begin()
shared.state.job = 'load model'
-
- """
- try:
- modules.sd_models.load_model()
- modules.sd_models.skip_next_load = True
- except Exception as e:
- errors.display(e, "loading stable diffusion model")
- log.error("Stable diffusion model failed to load")
- exit(1)
- """
Thread(target=lambda: shared.sd_model).start()
-
if shared.sd_model is None:
log.warning("No stable diffusion model loaded")
# exit(1)
else:
shared.opts.data["sd_model_checkpoint"] = shared.sd_model.sd_checkpoint_info.title
shared.opts.onchange("sd_model_checkpoint", wrap_queued_call(lambda: modules.sd_models.reload_model_weights()), call=False)
-
shared.state.end()
startup_timer.record("checkpoint")