diff --git a/CHANGELOG.md b/CHANGELOG.md index a1ae0c998..0174c5bdc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,19 @@ ## Update for 2023-09-07 -Service release with many fixes +Mostly a service release +- tons of fixes +- new option **inference mode** + - default is standard `torch.no_grad` + new option is `torch.inference_only` which is slightly faster and uses less vram, but only works on some gpus +- cache samplers between run + reduces overhead between generate calls slightly +- clean-up logging + - capture system info in startup log + - capture extension output + - capture ldm output + - cleaner server restart + ## Update for 2023-09-06 diff --git a/installer.py b/installer.py index 435d2a654..6796cf7cf 100644 --- a/installer.py +++ b/installer.py @@ -108,6 +108,10 @@ def setup_logging(): # logging.getLogger("DeepSpeed").handlers = log.handlers +def print_dict(d): + return ' '.join([f'{k}={v}' for k, v in d.items()]) + + def print_profile(profile: cProfile.Profile, msg: str): try: from rich import print # pylint: disable=redefined-builtin @@ -265,6 +269,26 @@ def clone(url, folder, commithash=None): git(f'-C "{folder}" checkout {commithash}') +def get_platform(): + try: + if platform.system() == 'Windows': + release = platform.platform(aliased = True, terse = False) + else: + release = platform.release() + return { + # 'host': platform.node(), + 'arch': platform.machine(), + 'cpu': platform.processor(), + 'system': platform.system(), + 'release': release, + # 'platform': platform.platform(aliased = True, terse = False), + # 'version': platform.version(), + 'python': platform.python_version(), + } + except Exception as e: + return { 'error': e } + + # check python version def check_python(): supported_minors = [9, 10, 11] @@ -873,11 +897,13 @@ def extensions_preload(parser): from modules.script_loading import preload_extensions from modules.paths_internal import extensions_builtin_dir, extensions_dir extension_folders = [extensions_builtin_dir] if args.safe else [extensions_builtin_dir, extensions_dir] + preload_time = {} for ext_dir in extension_folders: t0 = time.time() preload_extensions(ext_dir, parser) t1 = time.time() - log.info(f'Extension preload: {round(t1 - t0, 1)}s {ext_dir}') + preload_time[ext_dir] = round(t1 - t0, 2) + log.info(f'Extension preload: {preload_time}') except Exception: log.error('Error running extension preloading') if args.profile: diff --git a/launch.py b/launch.py index a019d9356..773ad9ac6 100644 --- a/launch.py +++ b/launch.py @@ -40,7 +40,7 @@ def get_custom_args(): current = getattr(args, arg) if current != default: custom[arg] = getattr(args, arg) - installer.log.info(f'Command line args: {custom}') + installer.log.info(f'Command line args: {installer.print_dict(custom)}') @lru_cache() @@ -137,7 +137,8 @@ def start_server(immediate=True, server=None): collected = gc.collect() if not immediate: time.sleep(3) - installer.log.debug(f'Memory {get_memory_stats()} Collected {collected}') + if collected > 0: + installer.log.debug(f'Memory {get_memory_stats()} Collected {collected}') module_spec = importlib.util.spec_from_file_location('webui', 'webui.py') # installer.log.debug(f'Loading module: {module_spec}') server = importlib.util.module_from_spec(module_spec) @@ -174,6 +175,7 @@ if __name__ == "__main__": if args.skip_git: installer.log.info('Skipping GIT operations') installer.check_version() + installer.log.info(f'Platform: {installer.print_dict(installer.get_platform())}') installer.set_environment() installer.check_torch() installer.check_modified_files() diff --git a/modules/codeformer_model.py b/modules/codeformer_model.py index e6e75b219..34e3a7a5a 100644 --- a/modules/codeformer_model.py +++ b/modules/codeformer_model.py @@ -97,7 +97,7 @@ def setup_model(dirname): cropped_face_t = cropped_face_t.unsqueeze(0).to(devices.device_codeformer) try: - with torch.no_grad(): + with devices.inference_context(): output = self.net(cropped_face_t, w=w if w is not None else shared.opts.code_former_weight, adain=True)[0] restored_face = tensor2img(output, rgb2bgr=True, min_max=(-1, 1)) del output diff --git a/modules/deepbooru.py b/modules/deepbooru.py index 547e1b4c6..de50853d6 100644 --- a/modules/deepbooru.py +++ b/modules/deepbooru.py @@ -56,7 +56,7 @@ class DeepDanbooru: pic = images.resize_image(2, pil_image.convert("RGB"), 512, 512) a = np.expand_dims(np.array(pic, dtype=np.float32), 0) / 255 - with torch.no_grad(), devices.autocast(): + with devices.inference_context(), devices.autocast(): x = torch.from_numpy(a).to(devices.device) y = self.model(x)[0].detach().cpu().numpy() diff --git a/modules/devices.py b/modules/devices.py index 8f306adbe..db05ed39a 100644 --- a/modules/devices.py +++ b/modules/devices.py @@ -17,6 +17,51 @@ def has_mps() -> bool: return mac_specific.has_mps +def get_gpu_info(): + def get_driver(): + import os + import subprocess + if torch.cuda.is_available() and torch.version.cuda: + try: + result = subprocess.run('nvidia-smi --query-gpu=driver_version --format=csv,noheader', shell=True, check=False, env=os.environ, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + version = result.stdout.decode(encoding="utf8", errors="ignore").strip() + return version + except Exception: + return '' + else: + return '' + + if not torch.cuda.is_available(): + return {} + else: + try: + if torch.version.cuda: + return { + 'device': f'{torch.cuda.get_device_name(torch.cuda.current_device())} ({str(torch.cuda.device_count())}) ({torch.cuda.get_arch_list()[-1]}) {str(torch.cuda.get_device_capability(device))}', + 'cuda': torch.version.cuda, + 'cudnn': torch.backends.cudnn.version(), + 'driver': get_driver(), + } + elif torch.version.hip: + return { + 'device': f'{torch.cuda.get_device_name(torch.cuda.current_device())} ({str(torch.cuda.device_count())})', + 'hip': torch.version.hip, + } + else: + try: + import intel_extension_for_pytorch as ipex# pylint: disable=import-error, unused-import + return { + 'device': f'{torch.xpu.get_device_name(torch.xpu.current_device())} ({str(torch.xpu.device_count())})', + 'ipex': ipex.__version__, + } + except Exception: + return { + 'device': 'unknown' + } + except Exception as ex: + return { 'error': ex } + + def extract_device_id(args, name): # pylint: disable=redefined-outer-name for x in range(len(args)): if name in args[x]: @@ -95,8 +140,8 @@ def test_fp16(): _y = layerNorm(x) shared.log.debug('Torch FP16 test passed') return True - except Exception as e: - shared.log.warning(f'Torch FP16 test failed: Forcing FP32 operations: {e}') + except Exception as ex: + shared.log.warning(f'Torch FP16 test failed: Forcing FP32 operations: {ex}') shared.opts.cuda_dtype = 'FP32' shared.opts.no_half = True shared.opts.no_half_vae = True @@ -133,7 +178,7 @@ def set_cuda_params(): torch.backends.cudnn.allow_tf32 = True except Exception: pass - global dtype, dtype_vae, dtype_unet, unet_needs_upcast # pylint: disable=global-statement + global dtype, dtype_vae, dtype_unet, unet_needs_upcast, inference_context # pylint: disable=global-statement if shared.opts.cuda_dtype == 'FP32': dtype = torch.float32 dtype_vae = torch.float32 @@ -159,12 +204,14 @@ def set_cuda_params(): shared.log.info('Torch override VAE dtype: no-half set') dtype_vae = torch.float32 unet_needs_upcast = shared.opts.upcast_sampling + inference_context = torch.inference_mode if shared.opts.inference_mode == 'inference-mode' else torch.no_grad shared.log.debug(f'Desired Torch parameters: dtype={shared.opts.cuda_dtype} no-half={shared.opts.no_half} no-half-vae={shared.opts.no_half_vae} upscast={shared.opts.upcast_sampling}') - shared.log.info(f'Setting Torch parameters: dtype={dtype} vae={dtype_vae} unet={dtype_unet}') + shared.log.info(f'Setting Torch parameters: dtype={dtype} vae={dtype_vae} unet={dtype_unet} context={inference_context.__name__}') shared.log.debug(f'Torch default device: {torch.device(get_optimal_device_name())}') args = cmd_args.parser.parse_args() +backend = 'not set' if args.use_ipex or (hasattr(torch, 'xpu') and torch.xpu.is_available()): backend = 'ipex' from modules.intel.ipex import ipex_init @@ -188,6 +235,7 @@ elif sys.platform == 'darwin': else: backend = 'cpu' +inference_context = torch.no_grad cuda_ok = torch.cuda.is_available() cpu = torch.device("cpu") device = device_interrogate = device_gfpgan = device_esrgan = device_codeformer = None diff --git a/modules/dml/hijack/kdiffusion.py b/modules/dml/hijack/kdiffusion.py index 19e16b013..d772dc88f 100644 --- a/modules/dml/hijack/kdiffusion.py +++ b/modules/dml/hijack/kdiffusion.py @@ -1,7 +1,7 @@ import torch from tqdm.auto import tqdm from k_diffusion import sampling -from modules.shared import device +import modules.devices as devices def dpm_solver_adaptive(self, x, t_start, t_end, order=3, rtol=0.05, atol=0.0078, h_init=0.05, pcoeff=0., icoeff=1., dcoeff=0., accept_safety=0.81, eta=0., s_noise=1., noise_sampler=None): @@ -12,8 +12,8 @@ def dpm_solver_adaptive(self, x, t_start, t_end, order=3, rtol=0.05, atol=0.0078 if not forward and eta: raise ValueError('eta must be 0 for reverse sampling') h_init = abs(h_init) * (1 if forward else -1) - atol = torch.tensor(atol, device=device) - rtol = torch.tensor(rtol, device=device) + atol = torch.tensor(atol, device=devices.device) + rtol = torch.tensor(rtol, device=devices.device) s = t_start x_prev = x accept = True @@ -58,7 +58,7 @@ def dpm_solver_adaptive(self, x, t_start, t_end, order=3, rtol=0.05, atol=0.0078 return x, info -@torch.no_grad() +@devices.inference_context() def sample_dpm_fast(model, x, sigma_min, sigma_max, n, extra_args=None, callback=None, disable=None, eta=0., s_noise=1., noise_sampler=None): """DPM-Solver-Fast (fixed step size). See https://arxiv.org/abs/2206.00927.""" if sigma_min <= 0 or sigma_max <= 0: @@ -67,10 +67,10 @@ def sample_dpm_fast(model, x, sigma_min, sigma_max, n, extra_args=None, callback dpm_solver = sampling.DPMSolver(model, extra_args, eps_callback=pbar.update) if callback is not None: dpm_solver.info_callback = lambda info: callback({'sigma': dpm_solver.sigma(info['t']), 'sigma_hat': dpm_solver.sigma(info['t_up']), **info}) - return dpm_solver.dpm_solver_fast(x, dpm_solver.t(torch.tensor(sigma_max, device=device)), dpm_solver.t(torch.tensor(sigma_min, device=device)), n, eta, s_noise, noise_sampler) + return dpm_solver.dpm_solver_fast(x, dpm_solver.t(torch.tensor(sigma_max, device=devices.device)), dpm_solver.t(torch.tensor(sigma_min, device=devices.device)), n, eta, s_noise, noise_sampler) -@torch.no_grad() +@devices.inference_context() def sample_dpm_adaptive(model, x, sigma_min, sigma_max, extra_args=None, callback=None, disable=None, order=3, rtol=0.05, atol=0.0078, h_init=0.05, pcoeff=0., icoeff=1., dcoeff=0., accept_safety=0.81, eta=0., s_noise=1., noise_sampler=None, return_info=False): """DPM-Solver-12 and 23 (adaptive step size). See https://arxiv.org/abs/2206.00927.""" if sigma_min <= 0 or sigma_max <= 0: @@ -79,7 +79,7 @@ def sample_dpm_adaptive(model, x, sigma_min, sigma_max, extra_args=None, callbac dpm_solver = sampling.DPMSolver(model, extra_args, eps_callback=pbar.update) if callback is not None: dpm_solver.info_callback = lambda info: callback({'sigma': dpm_solver.sigma(info['t']), 'sigma_hat': dpm_solver.sigma(info['t_up']), **info}) - x, info = dpm_solver.dpm_solver_adaptive(x, dpm_solver.t(torch.tensor(sigma_max, device=device)), dpm_solver.t(torch.tensor(sigma_min, device=device)), order, rtol, atol, h_init, pcoeff, icoeff, dcoeff, accept_safety, eta, s_noise, noise_sampler) + x, info = dpm_solver.dpm_solver_adaptive(x, dpm_solver.t(torch.tensor(sigma_max, device=devices.device)), dpm_solver.t(torch.tensor(sigma_min, device=devices.device)), order, rtol, atol, h_init, pcoeff, icoeff, dcoeff, accept_safety, eta, s_noise, noise_sampler) if return_info: return x, info return x diff --git a/modules/dml/hijack/plms.py b/modules/dml/hijack/plms.py index 2baef815d..a8afcbd05 100644 --- a/modules/dml/hijack/plms.py +++ b/modules/dml/hijack/plms.py @@ -1,11 +1,10 @@ import torch - from ldm.models.diffusion.ddim import noise_like - import modules.sd_hijack_inpainting as plms_hijack +import modules.devices as devices -@torch.no_grad() +@devices.inference_context() def p_sample_plms(self, x, c, t, index, repeat_noise=False, use_original_steps=False, quantize_denoised=False, temperature=1., noise_dropout=0., score_corrector=None, corrector_kwargs=None, unconditional_guidance_scale=1., unconditional_conditioning=None, old_eps=None, t_next=None, dynamic_threshold=None): diff --git a/modules/dml/hijack/realesrgan_model.py b/modules/dml/hijack/realesrgan_model.py index 341e9aded..ad3b01cce 100644 --- a/modules/dml/hijack/realesrgan_model.py +++ b/modules/dml/hijack/realesrgan_model.py @@ -1,6 +1,5 @@ import math import torch - from realesrgan import RealESRGANer diff --git a/modules/dml/hijack/stablediffusion.py b/modules/dml/hijack/stablediffusion.py index b14b0ece1..3c634e802 100644 --- a/modules/dml/hijack/stablediffusion.py +++ b/modules/dml/hijack/stablediffusion.py @@ -1,9 +1,10 @@ import torch - from ldm.models.diffusion.ddim import DDIMSampler from ldm.modules.diffusionmodules.util import noise_like +import modules.devices as devices -@torch.no_grad() + +@devices.inference_context() def p_sample_ddim(self, x, c, t, index, repeat_noise=False, use_original_steps=False, quantize_denoised=False, temperature=1., noise_dropout=0., score_corrector=None, corrector_kwargs=None, unconditional_guidance_scale=1., unconditional_conditioning=None, diff --git a/modules/esrgan_model.py b/modules/esrgan_model.py index e0b79069d..a7656ad58 100644 --- a/modules/esrgan_model.py +++ b/modules/esrgan_model.py @@ -199,7 +199,7 @@ def upscale_without_tiling(model, img): img = np.ascontiguousarray(np.transpose(img, (2, 0, 1))) / 255 img = torch.from_numpy(img).float() img = img.unsqueeze(0).to(devices.device_esrgan) - with torch.no_grad(): + with devices.inference_context(): output = model(img) output = output.squeeze().float().cpu().clamp_(0, 1).numpy() output = 255. * np.moveaxis(output, 0, 2) diff --git a/modules/img2img.py b/modules/img2img.py index fcfc50d90..01304b509 100644 --- a/modules/img2img.py +++ b/modules/img2img.py @@ -83,7 +83,7 @@ def img2img(id_task: str, mode: int, prompt: str, negative_prompt: str, prompt_s shared.log.warning('Model not loaded') return [], '', '', 'Error: model not loaded' - 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}|latent_index={latent_index}|mask_blur={mask_blur}|mask_alpha={mask_alpha}|inpainting_fill={inpainting_fill}|full_quality={full_quality}|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}|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_files={img2img_batch_files}|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}') + 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}|latent_index={latent_index}|mask_blur={mask_blur}|mask_alpha={mask_alpha}|inpainting_fill={inpainting_fill}|full_quality={full_quality}|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}|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_files={img2img_batch_files}|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}') if init_img is None: shared.log.debug('Init image not set') diff --git a/modules/intel/openvino/__init__.py b/modules/intel/openvino/__init__.py index b39eb3cdb..b6bcec4ab 100644 --- a/modules/intel/openvino/__init__.py +++ b/modules/intel/openvino/__init__.py @@ -8,7 +8,7 @@ from torch._dynamo.backends.registry import register_backend from torch.fx.experimental.proxy_tensor import make_fx from torch._inductor.compile_fx import compile_fx from hashlib import sha256 -from modules import shared +from modules import shared, devices @register_backend @fake_tensor_unsupported @@ -89,7 +89,7 @@ def openvino_fx(subgraph, example_inputs): else: example_inputs.reverse() model = make_fx(subgraph)(*example_inputs) - with torch.no_grad(): + with devices.inference_context(): model.eval() partitioner = Partitioner() compiled_model = partitioner.make_partitions(model) diff --git a/modules/interrogate.py b/modules/interrogate.py index 61bb14cc9..d95209792 100644 --- a/modules/interrogate.py +++ b/modules/interrogate.py @@ -174,7 +174,7 @@ class InterrogateModels: transforms.Normalize((0.48145466, 0.4578275, 0.40821073), (0.26862954, 0.26130258, 0.27577711)) ])(pil_image).unsqueeze(0).type(self.dtype).to(devices.device_interrogate) - with torch.no_grad(): + with devices.inference_context(): caption = self.blip_model.generate(gpu_image, sample=False, num_beams=shared.opts.interrogate_clip_num_beams, min_length=shared.opts.interrogate_clip_min_length, max_length=shared.opts.interrogate_clip_max_length) return caption[0] @@ -197,7 +197,7 @@ class InterrogateModels: clip_image = self.clip_preprocess(pil_image).unsqueeze(0).type(self.dtype).to(devices.device_interrogate) - with torch.no_grad(), devices.autocast(): + with devices.inference_context(), devices.autocast(): image_features = self.clip_model.encode_image(clip_image).type(self.dtype) image_features /= image_features.norm(dim=-1, keepdim=True) diff --git a/modules/loader.py b/modules/loader.py index f9c68c5d4..54dafa9e4 100644 --- a/modules/loader.py +++ b/modules/loader.py @@ -8,7 +8,6 @@ from modules import timer, errors initialized = False logging.getLogger("DeepSpeed").disabled = True import torch # pylint: disable=C0411 -errors.log.debug(f'Loaded Torch=={torch.__version__}') try: import intel_extension_for_pytorch as ipex # pylint: disable=import-error, unused-import errors.log.debug(f'Loaded IPEX=={ipex.__version__}') @@ -29,10 +28,9 @@ timer.startup.record("torch") from fastapi import FastAPI # pylint: disable=W0611,C0411 import gradio # pylint: disable=W0611,C0411 -errors.log.debug(f'Loaded Gradio=={gradio.__version__}') timer.startup.record("gradio") errors.install([gradio]) import diffusers # pylint: disable=W0611,C0411 -errors.log.debug(f'Loaded Diffusers=={diffusers.__version__}') timer.startup.record("diffusers") +errors.log.debug(f'Loaded packages: torch={torch.__version__} diffusers={diffusers.__version__} gradio={gradio.__version__}') diff --git a/modules/models/diffusion/uni_pc/sampler.py b/modules/models/diffusion/uni_pc/sampler.py index 21991d2b9..1800b9c2a 100644 --- a/modules/models/diffusion/uni_pc/sampler.py +++ b/modules/models/diffusion/uni_pc/sampler.py @@ -21,7 +21,7 @@ class UniPCSampler(object): # persist steps so we can eventually find denoising strength self.inflated_steps = ddim_num_steps - @torch.no_grad() + @devices.inference_context() def stochastic_encode(self, x0, t, use_original_steps=False, noise=None): if noise is None: noise = torch.randn_like(x0) @@ -119,7 +119,7 @@ class UniPCSampler(object): self.after_sample = after_sample self.after_update = after_update - @torch.no_grad() + @devices.inference_context() def sample(self, S, batch_size, diff --git a/modules/models/diffusion/uni_pc/uni_pc.py b/modules/models/diffusion/uni_pc/uni_pc.py index 6dddbcfbd..56604a7b6 100644 --- a/modules/models/diffusion/uni_pc/uni_pc.py +++ b/modules/models/diffusion/uni_pc/uni_pc.py @@ -3,7 +3,7 @@ import torch.nn.functional as F import math import time from rich.progress import Progress, TextColumn, BarColumn, TaskProgressColumn, TimeRemainingColumn, TimeElapsedColumn -from modules import shared +from modules import shared, devices class NoiseScheduleVP: @@ -760,7 +760,7 @@ class UniPC: with Progress(TextColumn('[cyan]{task.description}'), BarColumn(), TaskProgressColumn(), TimeRemainingColumn(), TimeElapsedColumn()) as progress: task = progress.add_task(description="Initializing", total=steps) t = time.time() - with torch.no_grad(): + with devices.inference_context(): vec_t = timesteps[0].expand((x.shape[0])) model_prev_list = [self.model_fn(x, vec_t)] t_prev_list = [vec_t] diff --git a/modules/processing.py b/modules/processing.py index f1ccc4901..985773c80 100644 --- a/modules/processing.py +++ b/modules/processing.py @@ -707,7 +707,7 @@ def process_images_inner(p: StableDiffusionProcessing) -> Processed: return '' ema_scope_context = p.sd_model.ema_scope if shared.backend == shared.Backend.ORIGINAL else nullcontext - with torch.no_grad(), ema_scope_context(): + with devices.inference_context(), ema_scope_context(): t0 = time.time() with devices.autocast(): p.init(p.all_prompts, p.all_seeds, p.all_subseeds) @@ -894,7 +894,6 @@ def old_hires_fix_first_pass_dimensions(width, height): class StableDiffusionProcessingTxt2Img(StableDiffusionProcessing): - sampler = None def __init__(self, enable_hr: bool = False, denoising_strength: float = 0.75, firstphase_width: int = 0, firstphase_height: int = 0, hr_scale: float = 2.0, hr_upscaler: str = None, hr_second_pass_steps: int = 0, hr_resize_x: int = 0, hr_resize_y: int = 0, refiner_steps: int = 5, refiner_start: float = 0, refiner_prompt: str = '', refiner_negative: str = '', **kwargs): @@ -920,11 +919,11 @@ class StableDiffusionProcessingTxt2Img(StableDiffusionProcessing): self.refiner_start = refiner_start self.refiner_prompt = refiner_prompt self.refiner_negative = refiner_negative + self.sampler = None def init(self, all_prompts, all_seeds, all_subseeds): if shared.backend == shared.Backend.DIFFUSERS: modules.sd_models.set_diffuser_pipe(self.sd_model, modules.sd_models.DiffusersTaskType.TEXT_2_IMAGE) - self.width = self.width or 512 self.height = self.height or 512 @@ -1052,7 +1051,6 @@ class StableDiffusionProcessingTxt2Img(StableDiffusionProcessing): class StableDiffusionProcessingImg2Img(StableDiffusionProcessing): - sampler = None def __init__(self, init_images: list = None, resize_mode: int = 0, denoising_strength: float = 0.3, image_cfg_scale: float = None, mask: Any = None, mask_blur: int = 4, inpainting_fill: int = 0, inpaint_full_res: bool = True, inpaint_full_res_padding: int = 0, inpainting_mask_invert: int = 0, initial_noise_multiplier: float = None, refiner_steps: int = 5, refiner_start: float = 0, refiner_prompt: str = '', refiner_negative: str = '', **kwargs): super().__init__(**kwargs) @@ -1080,6 +1078,7 @@ class StableDiffusionProcessingImg2Img(StableDiffusionProcessing): self.enable_hr = None self.is_batch = False self.scale_by = 1.0 + self.sampler = None def init(self, all_prompts, all_seeds, all_subseeds): if shared.backend == shared.Backend.DIFFUSERS and self.image_mask is None: diff --git a/modules/script_loading.py b/modules/script_loading.py index b28f6b65d..49489c4ed 100644 --- a/modules/script_loading.py +++ b/modules/script_loading.py @@ -1,6 +1,9 @@ +import io import os +import contextlib import importlib.util import modules.errors as errors +from installer import setup_logging preloaded = [] @@ -10,13 +13,18 @@ def load_module(path): module_spec = importlib.util.spec_from_file_location(os.path.basename(path), path) module = importlib.util.module_from_spec(module_spec) try: - module_spec.loader.exec_module(module) + stdout = io.StringIO() + with contextlib.redirect_stdout(stdout): + module_spec.loader.exec_module(module) + setup_logging() # reset since scripts can hijaack logging + for line in stdout.getvalue().splitlines(): + if len(line) > 0: + errors.log.info(f'Extension: script={os.path.relpath(path)} {line.strip()}') except Exception as e: errors.display(e, f'Module load: {path}') return module - def preload_extensions(extensions_dir, parser): if not os.path.isdir(extensions_dir): return diff --git a/modules/sd_hijack_inpainting.py b/modules/sd_hijack_inpainting.py index 7b392b4f4..882560a1c 100644 --- a/modules/sd_hijack_inpainting.py +++ b/modules/sd_hijack_inpainting.py @@ -1,8 +1,11 @@ +import io +import contextlib import torch - -import ldm.models.diffusion.ddpm -import ldm.models.diffusion.ddim -import ldm.models.diffusion.plms +stdout = io.StringIO() +with contextlib.redirect_stdout(stdout): + import ldm.models.diffusion.ddpm + import ldm.models.diffusion.ddim + import ldm.models.diffusion.plms from ldm.models.diffusion.ddpm import LatentDiffusion # pylint: disable=unused-import from ldm.models.diffusion.plms import PLMSSampler # pylint: disable=unused-import diff --git a/modules/sd_models.py b/modules/sd_models.py index 72422b498..14b78921a 100644 --- a/modules/sd_models.py +++ b/modules/sd_models.py @@ -1,5 +1,3 @@ -import collections -import os.path import re import io import sys @@ -7,6 +5,9 @@ import json import time import logging import threading +import contextlib +import collections +import os.path from os import mkdir from urllib import request from enum import Enum @@ -990,13 +991,17 @@ def load_model(checkpoint_info=None, already_loaded_state_dict=None, timer=None, timer.record("config") shared.log.debug(f'Model config loaded: {memory_stats()}') sd_model = None - # shared.log.debug(f'Model config: {sd_config.model.get("params", dict())}') - try: - clip_is_included_into_sd = sd1_clip_weight in state_dict or sd2_clip_weight in state_dict - with sd_disable_initialization.DisableInitialization(disable_clip=clip_is_included_into_sd): + stdout = io.StringIO() + with contextlib.redirect_stdout(stdout): + try: + clip_is_included_into_sd = sd1_clip_weight in state_dict or sd2_clip_weight in state_dict + with sd_disable_initialization.DisableInitialization(disable_clip=clip_is_included_into_sd): + sd_model = instantiate_from_config(sd_config.model) + except Exception: sd_model = instantiate_from_config(sd_config.model) - except Exception: - sd_model = instantiate_from_config(sd_config.model) + for line in stdout.getvalue().splitlines(): + if len(line) > 0: + shared.log.info(f'LDM: {line.strip()}') shared.log.debug(f"Model created from config: {checkpoint_config}") sd_model.used_config = checkpoint_config timer.record("create") diff --git a/modules/sd_models_config.py b/modules/sd_models_config.py index 819bebd34..40a0ed638 100644 --- a/modules/sd_models_config.py +++ b/modules/sd_models_config.py @@ -2,7 +2,7 @@ import os import torch -from modules import paths, sd_disable_initialization +from modules import paths, sd_disable_initialization, devices sd_repo_configs_path = os.path.join(paths.paths['Stable Diffusion'], "configs", "stable-diffusion") config_default = paths.sd_default_config @@ -47,7 +47,7 @@ def is_using_v_parameterization_for_sd2(state_dict): ) unet.eval() - with torch.no_grad(): + with devices.inference_context(): unet_sd = {k.replace("model.diffusion_model.", ""): v for k, v in state_dict.items() if "model.diffusion_model." in k} unet.load_state_dict(unet_sd, strict=True) unet.to(device=device, dtype=torch.float) diff --git a/modules/sd_samplers.py b/modules/sd_samplers.py index e0f6493c8..c624ea8d7 100644 --- a/modules/sd_samplers.py +++ b/modules/sd_samplers.py @@ -34,10 +34,18 @@ def find_sampler_config(name): return config +last_sampler = None + + def create_sampler(name, model): + global last_sampler # pylint: disable=global-statement + if last_sampler is not None and last_sampler.name == name: + return last_sampler if name == 'Default' and hasattr(model, 'scheduler'): config = {k: v for k, v in model.scheduler.config.items() if not k.startswith('_')} shared.log.debug(f'Sampler default {type(model.scheduler).__name__}: {config}') + last_sampler = model.scheduler + last_sampler.name = type(model.scheduler).__name__ return model.scheduler config = find_sampler_config(name) if config is None: @@ -48,6 +56,8 @@ def create_sampler(name, model): sampler.config = config sampler.name = name shared.log.debug(f'Sampler: sampler={sampler.name} config={sampler.config.options}') + last_sampler = sampler + last_sampler.name = sampler.name return sampler elif shared.backend == shared.Backend.DIFFUSERS: sampler = config.constructor(model) @@ -55,6 +65,8 @@ def create_sampler(name, model): model.scheduler_config = sampler.sampler.config.copy() model.scheduler = sampler.sampler shared.log.debug(f'Sampler: sampler={sampler.name} config={sampler.config}') + last_sampler = sampler.sampler + last_sampler.name = sampler.name return sampler.sampler else: return None diff --git a/modules/sd_samplers_kdiffusion.py b/modules/sd_samplers_kdiffusion.py index 2134ed0d7..e39f6ab19 100644 --- a/modules/sd_samplers_kdiffusion.py +++ b/modules/sd_samplers_kdiffusion.py @@ -142,6 +142,16 @@ class CFGDenoiser(torch.nn.Module): else: cond_in = torch.cat([tensor, uncond]) + """ + adjusted_cond_scale = cond_scale # Adjusted cond_scale for uncond + last_uncond_steps = max(0, state.sampling_steps - 2) # Determine the last two steps before uncond stops + if self.step >= last_uncond_steps: # Check if we're in the last two steps before uncond stops + adjusted_cond_scale *= 1.5 # Apply uncond with 150% cond_scale + else: + if (self.step - last_uncond_steps) % 3 == 0: # Check if it's one of every three steps after uncond stops + adjusted_cond_scale *= 1.5 # Apply uncond with 150% cond_scale + """ + if shared.batch_cond_uncond: x_out = self.inner_model(x_in, sigma_in, cond=make_condition_dict([cond_in], image_cond_in)) else: diff --git a/modules/shared.py b/modules/shared.py index d68a744ce..86a8af86c 100644 --- a/modules/shared.py +++ b/modules/shared.py @@ -1,8 +1,10 @@ +import io import os import sys import time import json import datetime +import contextlib import urllib.request from urllib.parse import urlparse from enum import Enum @@ -17,6 +19,7 @@ import modules.memmon import modules.styles import modules.devices as devices # pylint: disable=R0402 import modules.paths_internal as paths +from installer import print_dict from installer import log as central_logger # pylint: disable=E0611 @@ -271,6 +274,7 @@ def temp_disable_extensions(): cmd_opts.lyco_dir = opts.lora_dir if 'Lora' not in opts.disabled_extensions: disabled.append('Lora') + cmd_opts.controlnet_loglevel = 'WARNING' return disabled @@ -358,6 +362,7 @@ elif devices.backend == "rocm": else: # cuda cross_attention_optimization_default ="Scaled-Dot-Product" + options_templates.update(options_section(('sd', "Execution & Models"), { "sd_backend": OptionInfo("diffusers" if cmd_opts.use_openvino else "original", "Execution backend", gr.Radio, lambda: {"choices": ["original", "diffusers"] }), "sd_checkpoint_autoload": OptionInfo(True, "Model autoload on server start"), @@ -384,6 +389,7 @@ options_templates.update(options_section(('optimizations', "Optimizations"), { "token_merging_ratio": OptionInfo(0.0, "Token merging ratio", gr.Slider, {"minimum": 0.0, "maximum": 0.9, "step": 0.1}), "token_merging_ratio_img2img": OptionInfo(0.0, "Token merging ratio for img2img", gr.Slider, {"minimum": 0.0, "maximum": 0.9, "step": 0.1}), "token_merging_ratio_hr": OptionInfo(0.0, "Token merging ratio for hires pass", gr.Slider, {"minimum": 0.0, "maximum": 0.9, "step": 0.1}), + "inference_mode": OptionInfo("no-grad", "Torch inference mode", gr.Radio, lambda: {"choices": ["no-grad", "inference-only"]}), "sd_vae_sliced_encode": OptionInfo(False, "VAE Slicing (original)"), })) @@ -400,8 +406,9 @@ options_templates.update(options_section(('cuda', "Compute Settings"), { "rollback_vae": OptionInfo(False, "Attempt VAE roll back when produced NaN values (experimental)"), "opt_channelslast": OptionInfo(False, "Use channels last as torch memory format "), "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"), + "ipex_optimize": OptionInfo(True if devices.backend == "ipex" else False, "Enable IPEX Optimize for Intel GPUs"), + "directml_memory_provider": OptionInfo(default_memory_provider, 'DirectML memory stats provider', gr.Radio, lambda: {"choices": memory_providers}), + "cuda_compile_sep": OptionInfo("

Model Compile

", "", gr.HTML), "cuda_compile": OptionInfo(True if cmd_opts.use_openvino else False, "Enable model compile"), "cuda_compile_backend": OptionInfo("openvino_fx" if cmd_opts.use_openvino else "none", "Model compile backend", gr.Radio, lambda: {"choices": ['none', 'inductor', 'cudagraphs', 'aot_ts_nvfuser', 'hidet', 'ipex', 'openvino_fx']}), "cuda_compile_mode": OptionInfo("default", "Model compile mode", gr.Radio, lambda: {"choices": ['default', 'reduce-overhead', 'max-autotune']}), @@ -409,8 +416,6 @@ options_templates.update(options_section(('cuda', "Compute Settings"), { "cuda_compile_precompile": OptionInfo(False, "Model compile precompile"), "cuda_compile_verbose": OptionInfo(False, "Model compile verbose mode"), "cuda_compile_errors": OptionInfo(True, "Model compile suppress errors"), - "ipex_optimize": OptionInfo(True if devices.backend == "ipex" else False, "Enable IPEX Optimize for Intel GPUs"), - "directml_memory_provider": OptionInfo(default_memory_provider, 'DirectML memory stats provider', gr.Dropdown, lambda: {"choices": memory_providers}), })) options_templates.update(options_section(('diffusers', "Diffusers Settings"), { @@ -439,7 +444,7 @@ options_templates.update(options_section(('system-paths', "System Paths"), { "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"), - "sd_lora": OptionInfo("", "Add LoRA to prompt", gr.Textbox, {"choices": [], "visible": False}), + "sd_lora": OptionInfo("", "Add LoRA to prompt", gr.Textbox, {"visible": False}), "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"), @@ -816,7 +821,6 @@ class Options: value = expected_type(value) return value - opts = Options() config_filename = cmd_opts.config opts.load(config_filename) @@ -828,7 +832,8 @@ else: 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 -log.info(f'Engine: backend={backend}') +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())}') prompt_styles = modules.styles.StyleDatabase(opts) cmd_opts.disable_extension_access = (cmd_opts.share or cmd_opts.listen or (cmd_opts.server_name or False)) and not cmd_opts.insecure @@ -917,14 +922,26 @@ total_tqdm = TotalTQDM() def restart_server(restart=True): if demo is None: return - log.info('Server shutdown requested') + log.warning('Server shutdown requested') try: - demo.server.wants_restart = restart - demo.server.should_exit = True - demo.server.force_exit = True - demo.close(verbose=False) - demo.server.close() - demo.fns = [] + sys.tracebacklimit = 0 + stdout = io.StringIO() + stderr = io.StringIO() + with contextlib.redirect_stdout(stdout), contextlib.redirect_stdout(stderr): + print('HERE1') + demo.server.wants_restart = restart + print('HERE2') + demo.server.should_exit = True + print('HERE3') + demo.server.force_exit = True + print('HERE4') + demo.close(verbose=False) + print('HERE5') + demo.server.close() + print('HERE6') + demo.fns = [] + time.sleep(1) + sys.tracebacklimit = 100 # os._exit(0) except (Exception, BaseException) as e: log.error(f'Server shutdown error: {e}') diff --git a/modules/taesd/taesd.py b/modules/taesd/taesd.py index 0355a81ff..4900a5ab0 100644 --- a/modules/taesd/taesd.py +++ b/modules/taesd/taesd.py @@ -5,6 +5,8 @@ Tiny AutoEncoder for Stable Diffusion """ import torch import torch.nn as nn +from modules import devices + def conv(n_in, n_out, **kwargs): return nn.Conv2d(n_in, n_out, 3, padding=1, **kwargs) @@ -65,7 +67,7 @@ class TAESD(nn.Module): return x.sub(TAESD.latent_shift).mul(2 * TAESD.latent_magnitude) -@torch.no_grad() +@devices.inference_context() def main(): from PIL import Image import sys diff --git a/modules/txt2img.py b/modules/txt2img.py index 648eb836a..51b09192e 100644 --- a/modules/txt2img.py +++ b/modules/txt2img.py @@ -6,7 +6,7 @@ from modules.ui import plaintext_to_html def txt2img(id_task: str, prompt: str, negative_prompt: str, prompt_styles, steps: int, sampler_index: int, latent_index: int, full_quality: bool, 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_steps: int, refiner_start: int, refiner_prompt: str, refiner_negative: str, 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}|full_quality={full_quality}|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_steps={refiner_steps}|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}|full_quality={full_quality}|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_steps={refiner_steps}|refiner_start={refiner_start}||refiner_prompt={refiner_prompt}|refiner_negative={refiner_negative}|override_settings_texts={override_settings_texts}') if shared.sd_model is None: shared.log.warning('Model not loaded') diff --git a/modules/ui_extra_networks.py b/modules/ui_extra_networks.py index 459851ada..b12b21859 100644 --- a/modules/ui_extra_networks.py +++ b/modules/ui_extra_networks.py @@ -364,10 +364,10 @@ def create_ui(container, button, tabname, skip_indexing = False): button.click(fn=toggle_visibility, inputs=[state_visible], outputs=[state_visible, container, button]) button_close.click(fn=toggle_visibility, inputs=[state_visible], outputs=[state_visible, container]) - def refresh(title): + def en_refresh(title): res = [] for page in extra_pages: - if title == '' or title == page.title or len(page.html) == 0: + if title is None or title == '' or title == page.title or len(page.html) == 0: page.refresh() page.refresh_time = None page.create_page(ui.tabname) @@ -376,7 +376,7 @@ def create_ui(container, button, tabname, skip_indexing = False): ui.search.update(value = ui.search.value) return res - button_refresh.click(_js='extraNetworksRefreshButton', fn=refresh, inputs=[ui.search], outputs=ui.pages) + button_refresh.click(_js='extraNetworksRefreshButton', fn=en_refresh, inputs=[ui.search], outputs=ui.pages) return ui diff --git a/webui.py b/webui.py index fb32f809f..48eb3c036 100644 --- a/webui.py +++ b/webui.py @@ -1,3 +1,4 @@ +import io import os import sys import glob @@ -5,19 +6,18 @@ import signal import asyncio import logging import importlib +import contextlib from threading import Thread import modules.loader import torch # pylint: disable=wrong-import-order from modules import timer, errors, paths # pylint: disable=unused-import local_url = None -if not modules.loader.initialized: - errors.log.debug('Loading modules') -from installer import log, setup_logging, git_commit +from installer import log, git_commit, print_dict import ldm.modules.encoders.modules # pylint: disable=W0611,C0411,E0401 -from modules.call_queue import queue_lock, wrap_queued_call, wrap_gradio_gpu_call # pylint: disable=W0611,C0411,C0412 +from modules import shared, extensions, extra_networks, ui_tempdir, ui_extra_networks, modelloader # pylint: disable=ungrouped-imports from modules.paths import create_paths -from modules import shared, extensions, extra_networks, ui_tempdir, ui_extra_networks, modelloader +from modules.call_queue import queue_lock, wrap_queued_call, wrap_gradio_gpu_call # pylint: disable=W0611,C0411,C0412 import modules.devices import modules.sd_samplers import modules.upscaler @@ -42,7 +42,6 @@ from modules.middleware import setup_middleware state = shared.state if not modules.loader.initialized: timer.startup.record("libraries") - log.info('Loaded librareis') log.setLevel(logging.DEBUG if cmd_opts.debug else logging.INFO) logging.disable(logging.NOTSET if cmd_opts.debug else logging.DEBUG) if cmd_opts.server_name: @@ -78,7 +77,7 @@ def check_rollback_vae(): def initialize(): - log.debug('Entering initialize') + log.debug('Initializing') check_rollback_vae() @@ -105,7 +104,6 @@ def initialize(): t_timer, t_total = modules.scripts.load_scripts() timer.startup.record("extensions") timer.startup.records["extensions"] = t_total # scripts can reset the time - setup_logging() # reset since scripts can hijaack logging log.info(f'Extensions time: {t_timer.summary()}') modelloader.load_upscalers() @@ -206,12 +204,12 @@ def async_policy(): def start_common(): log.debug('Entering start sequence') if cmd_opts.debug and hasattr(shared, 'get_version'): - log.debug(f'Version: {shared.get_version()}') + log.debug(f'Version: {print_dict(shared.get_version())}') logging.disable(logging.NOTSET if cmd_opts.debug else logging.DEBUG) if shared.cmd_opts.data_dir is not None and len(shared.cmd_opts.data_dir) > 0: log.info(f'Using data path: {shared.cmd_opts.data_dir}') - if shared.cmd_opts.models_dir is not None and len(shared.cmd_opts.models_dir) > 0: - log.info(f'Using models path: {shared.cmd_opts.data_dir}') + if shared.cmd_opts.models_dir is not None and len(shared.cmd_opts.models_dir) > 0 and shared.cmd_opts.models_dir != 'models': + log.info(f'Using models path: {shared.cmd_opts.models_dir}') create_paths(opts, log) async_policy() initialize() @@ -244,23 +242,25 @@ def start_ui(): gradio_auth_creds += [x.strip() for x in line.split(',') if x.strip()] global local_url # pylint: disable=global-statement - app, local_url, share_url = shared.demo.launch( # app is FastAPI(Starlette) instance - share=cmd_opts.share, - server_name=server_name, - server_port=cmd_opts.port if cmd_opts.port != 7860 else None, - ssl_keyfile=cmd_opts.tls_keyfile, - ssl_certfile=cmd_opts.tls_certfile, - ssl_verify=not cmd_opts.tls_selfsign, - debug=False, - auth=[tuple(cred.split(':')) for cred in gradio_auth_creds] if gradio_auth_creds else None, - prevent_thread_lock=True, - max_threads=64, - show_api=False, - quiet=True, - favicon_path='html/logo.ico', - allowed_paths=[os.path.dirname(__file__), cmd_opts.data_dir], - app_kwargs=fastapi_args, - ) + stdout = io.StringIO() + with contextlib.redirect_stdout(stdout): + app, local_url, share_url = shared.demo.launch( # app is FastAPI(Starlette) instance + share=cmd_opts.share, + server_name=server_name, + server_port=cmd_opts.port if cmd_opts.port != 7860 else None, + ssl_keyfile=cmd_opts.tls_keyfile, + ssl_certfile=cmd_opts.tls_certfile, + ssl_verify=not cmd_opts.tls_selfsign, + debug=False, + auth=[tuple(cred.split(':')) for cred in gradio_auth_creds] if gradio_auth_creds else None, + prevent_thread_lock=True, + max_threads=64, + show_api=False, + quiet=True, + favicon_path='html/logo.ico', + allowed_paths=[os.path.dirname(__file__), cmd_opts.data_dir], + app_kwargs=fastapi_args, + ) if cmd_opts.data_dir is not None: ui_tempdir.register_tmp_file(shared.demo, os.path.join(cmd_opts.data_dir, 'x')) shared.log.info(f'Local URL: {local_url}')