diff --git a/extensions-builtin/multidiffusion-upscaler-for-automatic1111 b/extensions-builtin/multidiffusion-upscaler-for-automatic1111
index 0f55e98e2..f54a8fc50 160000
--- a/extensions-builtin/multidiffusion-upscaler-for-automatic1111
+++ b/extensions-builtin/multidiffusion-upscaler-for-automatic1111
@@ -1 +1 @@
-Subproject commit 0f55e98e27235984a31fbd38287ba6584c4884c5
+Subproject commit f54a8fc506600340f7955a7251fce0a8fb90185e
diff --git a/extensions-builtin/sd-webui-controlnet b/extensions-builtin/sd-webui-controlnet
index 11d33e181..817155ea7 160000
--- a/extensions-builtin/sd-webui-controlnet
+++ b/extensions-builtin/sd-webui-controlnet
@@ -1 +1 @@
-Subproject commit 11d33e181523c509c235d1278e94ce61d2d8d366
+Subproject commit 817155ea7a43a78982202a2456088acd6ffd95d5
diff --git a/extensions-builtin/stable-diffusion-webui-images-browser b/extensions-builtin/stable-diffusion-webui-images-browser
index 806902a2c..708bd5860 160000
--- a/extensions-builtin/stable-diffusion-webui-images-browser
+++ b/extensions-builtin/stable-diffusion-webui-images-browser
@@ -1 +1 @@
-Subproject commit 806902a2c6d049308b1f8efd9eaf1fc1c64ac018
+Subproject commit 708bd5860e2432a0021d3aa66fc8fdbff33b2d1a
diff --git a/modules/api/api.py b/modules/api/api.py
index b3eb04f05..1405c7a63 100644
--- a/modules/api/api.py
+++ b/modules/api/api.py
@@ -13,9 +13,6 @@ import piexif
import piexif.helper
import uvicorn
import gradio as gr
-# from gradio.processing_utils import decode_base64_to_file # gradio 3.23
-# from gradio_client.utils import decode_base64_to_file # gradio 3.28
-
from modules import errors, shared, sd_samplers, deepbooru, sd_hijack, images, scripts, ui, postprocessing
from modules.api.models import * # pylint: disable=unused-wildcard-import, wildcard-import
from modules.processing import StableDiffusionProcessingTxt2Img, StableDiffusionProcessingImg2Img, process_images
@@ -33,7 +30,7 @@ def upscaler_to_index(name: str):
try:
return [x.name.lower() for x in shared.sd_upscalers].index(name.lower())
except Exception as e:
- raise HTTPException(status_code=400, detail=f"Invalid upscaler, needs to be one of these: {' , '.join([x.name for x in sd_upscalers])}") from e
+ raise HTTPException(status_code=400, detail=f"Invalid upscaler, needs to be one of these: {' , '.join([x.name for x in shared.sd_upscalers])}") from e
def script_name_to_index(name, scripts_list):
try:
@@ -64,24 +61,24 @@ def decode_base64_to_image(encoding):
def encode_pil_to_base64(image):
with io.BytesIO() as output_bytes:
- if opts.samples_format.lower() == 'png':
+ if shared.opts.samples_format.lower() == 'png':
use_metadata = False
encoded_metadata = PngImagePlugin.PngInfo()
for k, v in image.info.items():
if isinstance(k, str) and isinstance(v, str):
encoded_metadata.add_text(k, v)
use_metadata = True
- image.save(output_bytes, format="PNG", pnginfo=(encoded_metadata if use_metadata else None), quality=opts.jpeg_quality)
+ image.save(output_bytes, format="PNG", pnginfo=(encoded_metadata if use_metadata else None), quality=shared.opts.jpeg_quality)
- elif opts.samples_format.lower() in ("jpg", "jpeg", "webp"):
+ elif shared.opts.samples_format.lower() in ("jpg", "jpeg", "webp"):
parameters = image.info.get('parameters', None)
exif_bytes = piexif.dump({
"Exif": { piexif.ExifIFD.UserComment: piexif.helper.UserComment.dump(parameters or "", encoding="unicode") }
})
- if opts.samples_format.lower() in ("jpg", "jpeg"):
- image.save(output_bytes, format="JPEG", exif = exif_bytes, quality=opts.jpeg_quality)
+ if shared.opts.samples_format.lower() in ("jpg", "jpeg"):
+ image.save(output_bytes, format="JPEG", exif = exif_bytes, quality=shared.opts.jpeg_quality)
else:
- image.save(output_bytes, format="WEBP", exif = exif_bytes, quality=opts.jpeg_quality)
+ image.save(output_bytes, format="WEBP", exif = exif_bytes, quality=shared.opts.jpeg_quality)
else:
raise HTTPException(status_code=500, detail="Invalid image format")
bytes_data = output_bytes.getvalue()
@@ -230,8 +227,8 @@ class Api:
with self.queue_lock:
p = StableDiffusionProcessingTxt2Img(sd_model=shared.sd_model, **args)
p.scripts = script_runner
- p.outpath_grids = opts.outdir_grids or opts.outdir_txt2img_grids
- p.outpath_samples = opts.outdir_samples or opts.outdir_txt2img_samples
+ p.outpath_grids = shared.opts.outdir_grids or shared.opts.outdir_txt2img_grids
+ p.outpath_samples = shared.opts.outdir_samples or shared.opts.outdir_txt2img_samples
shared.state.begin()
script_args = self.init_script_args(p, txt2imgreq, self.default_script_arg_txt2img, selectable_scripts, selectable_script_idx, script_runner)
if selectable_scripts is not None:
@@ -278,8 +275,8 @@ class Api:
p = StableDiffusionProcessingImg2Img(sd_model=shared.sd_model, **args)
p.init_images = [decode_base64_to_image(x) for x in init_images]
p.scripts = script_runner
- p.outpath_grids = opts.outdir_img2img_grids
- p.outpath_samples = opts.outdir_img2img_samples
+ p.outpath_grids = shared.opts.outdir_img2img_grids
+ p.outpath_samples = shared.opts.outdir_img2img_samples
shared.state.begin()
script_args = self.init_script_args(p, img2imgreq, self.default_script_arg_img2img, selectable_scripts, selectable_script_idx, script_runner)
if selectable_scripts is not None:
@@ -297,12 +294,9 @@ class Api:
def extras_single_image_api(self, req: ExtrasSingleImageRequest):
reqDict = setUpscalers(req)
-
reqDict['image'] = decode_base64_to_image(reqDict['image'])
-
with self.queue_lock:
result = postprocessing.run_extras(extras_mode=0, image_folder="", input_dir="", output_dir="", save_output=False, **reqDict)
-
return ExtrasSingleImageResponse(image=encode_pil_to_base64(result[0][0]), html_info=result[1])
def extras_batch_images_api(self, req: ExtrasBatchImagesRequest):
diff --git a/modules/api/models.py b/modules/api/models.py
index 21d2c2663..498d8f07c 100644
--- a/modules/api/models.py
+++ b/modules/api/models.py
@@ -4,7 +4,7 @@ from pydantic import BaseModel, Field, create_model # pylint: disable=no-name-in
from typing_extensions import Literal
from inflection import underscore
from modules.processing import StableDiffusionProcessingTxt2Img, StableDiffusionProcessingImg2Img
-from modules.shared import sd_upscalers, opts, parser
+import modules.shared as shared
API_NOT_ALLOWED = [
"self",
@@ -142,8 +142,8 @@ class ExtrasBaseRequest(BaseModel):
upscaling_resize_w: int = Field(default=512, title="Target Width", ge=1, description="Target width for the upscaler to hit. Only used when resize_mode=1.")
upscaling_resize_h: int = Field(default=512, title="Target Height", ge=1, description="Target height for the upscaler to hit. Only used when resize_mode=1.")
upscaling_crop: bool = Field(default=True, title="Crop to fit", description="Should the upscaler crop the image to fit in the chosen size?")
- upscaler_1: str = Field(default="None", title="Main upscaler", description=f"The name of the main upscaler to use, it has to be one of this list: {' , '.join([x.name for x in sd_upscalers])}")
- upscaler_2: str = Field(default="None", title="Secondary upscaler", description=f"The name of the secondary upscaler to use, it has to be one of this list: {' , '.join([x.name for x in sd_upscalers])}")
+ upscaler_1: str = Field(default="None", title="Main upscaler", description=f"The name of the main upscaler to use, it has to be one of this list: {' , '.join([x.name for x in shared.sd_upscalers])}")
+ upscaler_2: str = Field(default="None", title="Secondary upscaler", description=f"The name of the secondary upscaler to use, it has to be one of this list: {' , '.join([x.name for x in shared.sd_upscalers])}")
extras_upscaler_2_visibility: float = Field(default=0, title="Secondary upscaler visibility", ge=0, le=1, allow_inf_nan=False, description="Sets the visibility of secondary upscaler, values should be between 0 and 1.")
upscale_first: bool = Field(default=False, title="Upscale first", description="Should the upscaler run before restoring faces?")
@@ -200,9 +200,9 @@ class PreprocessResponse(BaseModel):
info: str = Field(title="Preprocess info", description="Response string from preprocessing task.")
fields = {}
-for key, metadata in opts.data_labels.items():
- value = opts.data.get(key)
- optType = opts.typemap.get(type(metadata.default), type(value))
+for key, metadata in shared.opts.data_labels.items():
+ value = shared.opts.data.get(key)
+ optType = shared.opts.typemap.get(type(metadata.default), type(value))
if metadata is not None:
fields.update({key: (Optional[optType], Field(
@@ -213,7 +213,7 @@ for key, metadata in opts.data_labels.items():
OptionsModel = create_model("Options", **fields)
flags = {}
-_options = vars(parser)['_option_string_actions']
+_options = vars(shared.parser)['_option_string_actions']
for key in _options:
if _options[key].dest != 'help':
flag = _options[key]
diff --git a/modules/call_queue.py b/modules/call_queue.py
index f8c4a9ce7..2ea136a19 100644
--- a/modules/call_queue.py
+++ b/modules/call_queue.py
@@ -22,26 +22,21 @@ def wrap_queued_call(func):
def wrap_gradio_gpu_call(func, extra_outputs=None):
def f(*args, **kwargs):
-
# if the first argument is a string that says "task(...)", it is treated as a job id
if len(args) > 0 and type(args[0]) == str and args[0][0:5] == "task(" and args[0][-1] == ")":
id_task = args[0]
progress.add_task_to_queue(id_task)
else:
id_task = None
-
with queue_lock:
shared.state.begin()
progress.start_task(id_task)
-
try:
res = func(*args, **kwargs)
progress.record_results(id_task, res)
finally:
progress.finish_task(id_task)
-
shared.state.end()
-
return res
return wrap_gradio_call(f, extra_outputs=extra_outputs, add_stats=True)
@@ -56,7 +51,13 @@ def wrap_gradio_call(func, extra_outputs=None, add_stats=False):
if shared.cmd_opts.profile:
pr = cProfile.Profile()
pr.enable()
- res = list(func(*args, **kwargs))
+ res = func(*args, **kwargs)
+ if res is None:
+ msg = "No result returned from function"
+ shared.log.warning(msg)
+ res = [None, '', '', f"
{html.escape(msg)}
"]
+ else:
+ res = list(res)
if shared.cmd_opts.profile:
pr.disable()
s = io.StringIO()
diff --git a/modules/devices.py b/modules/devices.py
index 40dc6548d..7f66f0d54 100644
--- a/modules/devices.py
+++ b/modules/devices.py
@@ -72,6 +72,18 @@ def torch_gc():
torch.cuda.ipc_collect()
+def test_fp16():
+ try:
+ x = torch.tensor([[1.5,.0,.0,.0]]).to(device).half()
+ layerNorm = torch.nn.LayerNorm(4, eps=0.00001, elementwise_affine=True, dtype=torch.float16, device=device)
+ _y = layerNorm(x)
+ except:
+ shared.log.warning('Torch FP16 test failed: Forcing FP32 operations')
+ shared.opts.cuda_dtype = 'FP32'
+ shared.opts.no_half = True
+ shared.opts.no_half_vae = True
+
+
def set_cuda_params():
if torch.cuda.is_available():
try:
@@ -89,6 +101,7 @@ def set_cuda_params():
pass
global dtype, dtype_vae, dtype_unet, unet_needs_upcast # pylint: disable=global-statement
# set dtype
+ test_fp16()
if shared.opts.cuda_dtype == 'FP16':
dtype = torch.float16
dtype_vae = torch.float16
@@ -105,6 +118,7 @@ def set_cuda_params():
dtype_vae = torch.float32
unet_needs_upcast = shared.opts.upcast_sampling
+
args = cmd_args.parser.parse_args()
if args.use_ipex:
cpu = torch.device("xpu") #Use XPU instead of CPU. %20 Perf improvement on weak CPUs.
diff --git a/modules/dml/hijack/kdiffusion.py b/modules/dml/hijack/kdiffusion.py
index 2eced885f..78bc9f2b5 100644
--- a/modules/dml/hijack/kdiffusion.py
+++ b/modules/dml/hijack/kdiffusion.py
@@ -1,8 +1,8 @@
import torch
from tqdm.auto import tqdm
-
-from modules.shared import device
from k_diffusion import sampling
+from modules.shared import device
+
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):
noise_sampler = sampling.default_noise_sampler(x) if noise_sampler is None else noise_sampler
@@ -86,4 +86,4 @@ def sample_dpm_adaptive(model, x, sigma_min, sigma_max, extra_args=None, callbac
sampling.DPMSolver.dpm_solver_adaptive = dpm_solver_adaptive
sampling.sample_dpm_fast = sample_dpm_fast
-sampling.sample_dpm_adaptive = sample_dpm_adaptive
\ No newline at end of file
+sampling.sample_dpm_adaptive = sample_dpm_adaptive
diff --git a/modules/images.py b/modules/images.py
index f23232225..c73c1fd13 100644
--- a/modules/images.py
+++ b/modules/images.py
@@ -473,7 +473,7 @@ def get_next_sequence_number(path, basename):
return result + 1
-def save_image(image, path, basename, seed=None, prompt=None, extension='png', info=None, short_filename=False, no_prompt=False, grid=False, pnginfo_section_name='parameters', p=None, existing_info=None, forced_filename=None, suffix="", save_to_dirs=None):
+def save_image(image, path, basename, seed=None, prompt=None, extension='jpg', info=None, short_filename=False, no_prompt=False, grid=False, pnginfo_section_name='parameters', p=None, existing_info=None, forced_filename=None, suffix="", save_to_dirs=None):
"""Save an image.
Args:
@@ -510,16 +510,12 @@ def save_image(image, path, basename, seed=None, prompt=None, extension='png', i
if path is None: # set default path to avoid errors when functions are triggered manually or via api and param is not set
path = opts.outdir_save
-
if save_to_dirs is None:
save_to_dirs = (grid and opts.grid_save_to_dirs) or (not grid and opts.save_to_dirs and not no_prompt)
-
if save_to_dirs:
dirname = namegen.apply(opts.directories_filename_pattern or "[prompt_words]").lstrip(' ').rstrip('\\ /')
path = os.path.join(path, dirname)
-
os.makedirs(path, exist_ok=True)
-
if forced_filename is None:
if short_filename or seed is None:
file_decoration = ""
@@ -527,14 +523,10 @@ def save_image(image, path, basename, seed=None, prompt=None, extension='png', i
file_decoration = opts.samples_filename_pattern or "[seed]"
else:
file_decoration = opts.samples_filename_pattern or "[seed]-[prompt_spaces]"
-
add_number = opts.save_images_add_number or file_decoration == ''
-
if file_decoration != "" and add_number:
file_decoration = "-" + file_decoration
-
file_decoration = namegen.apply(file_decoration) + suffix
-
if add_number:
basecount = get_next_sequence_number(path, basename)
fullfn = None
@@ -547,68 +539,71 @@ def save_image(image, path, basename, seed=None, prompt=None, extension='png', i
fullfn = os.path.join(path, f"{file_decoration}.{extension}")
else:
fullfn = os.path.join(path, f"{forced_filename}.{extension}")
-
pnginfo = existing_info or {}
if info is not None:
pnginfo[pnginfo_section_name] = info
-
params = script_callbacks.ImageSaveParams(image, p, fullfn, pnginfo)
script_callbacks.before_image_saved_callback(params)
image = params.image
fullfn = params.filename
-
exifinfo_data = params.pnginfo.get('UserComment', '')
if len(exifinfo_data) > 0:
exifinfo_data = exifinfo_data + ', ' + params.pnginfo.get(pnginfo_section_name, '')
else:
exifinfo_data = params.pnginfo.get(pnginfo_section_name, '')
- def _atomically_save_image(image_to_save, filename_without_extension, extension):
+ def atomically_save_image(image_to_save, filename_without_extension, extension):
# save image with .tmp extension to avoid race condition when another process detects new image in the directory
temp_file_path = filename_without_extension + ".tmp"
image_format = Image.registered_extensions()[extension]
- if extension.lower() == '.png':
+ if image_format == 'PNG':
pnginfo_data = PngImagePlugin.PngInfo()
if opts.enable_pnginfo:
for k, v in params.pnginfo.items():
pnginfo_data.add_text(k, str(v))
image_to_save.save(temp_file_path, format=image_format, quality=opts.jpeg_quality, pnginfo=pnginfo_data)
- elif extension.lower() in (".jpg", ".jpeg", ".webp"):
+ elif image_format == 'JPEG':
if image_to_save.mode == 'RGBA':
+ shared.log.warning('Saving RGBA image as JPEG: Alpha channel will be lost')
image_to_save = image_to_save.convert("RGB")
elif image_to_save.mode == 'I;16':
- image_to_save = image_to_save.point(lambda p: p * 0.0038910505836576).convert("RGB" if extension.lower() == ".webp" else "L")
+ image_to_save = image_to_save.point(lambda p: p * 0.0038910505836576).convert("L")
+ image_to_save.save(temp_file_path, format=image_format, quality=opts.jpeg_quality)
+ if opts.enable_pnginfo:
+ exif_bytes = piexif.dump({ "Exif": { piexif.ExifIFD.UserComment: piexif.helper.UserComment.dump(exifinfo_data or "", encoding="unicode") } })
+ piexif.insert(exif_bytes, temp_file_path)
+ elif image_format == 'WEBP':
+ if image_to_save.mode == 'I;16':
+ image_to_save = image_to_save.point(lambda p: p * 0.0038910505836576).convert("RGB")
image_to_save.save(temp_file_path, format=image_format, quality=opts.jpeg_quality, lossless=opts.webp_lossless)
if opts.enable_pnginfo:
exif_bytes = piexif.dump({ "Exif": { piexif.ExifIFD.UserComment: piexif.helper.UserComment.dump(exifinfo_data or "", encoding="unicode") } })
piexif.insert(exif_bytes, temp_file_path)
else:
+ shared.log.warning(f'Unrecognized image format: {extension} attempting save as {image_format}')
image_to_save.save(temp_file_path, format=image_format, quality=opts.jpeg_quality)
+ os.replace(temp_file_path, filename_without_extension + extension) # atomically rename the file with correct extension
- # atomically rename the file with correct extension
- os.replace(temp_file_path, filename_without_extension + extension)
-
- fullfn_without_extension, extension = os.path.splitext(params.filename)
+ filename, extension = os.path.splitext(params.filename)
if hasattr(os, 'statvfs'):
max_name_len = os.statvfs(path).f_namemax
- fullfn_without_extension = fullfn_without_extension[:max_name_len - max(4, len(extension))]
- params.filename = fullfn_without_extension + extension
+ filename = filename[:max_name_len - max(4, len(extension))]
+ params.filename = filename + extension
fullfn = params.filename
- _atomically_save_image(image, fullfn_without_extension, extension)
+ atomically_save_image(image, filename, extension)
image.already_saved_as = fullfn
-
if opts.save_txt and len(exifinfo_data) > 0:
- txt_fullfn = f"{fullfn_without_extension}.txt"
- with open(txt_fullfn, "w", encoding="utf8") as file:
+ filename_txt = f"{filename}.txt"
+ with open(filename_txt, "w", encoding="utf8") as file:
file.write(exifinfo_data + "\n")
else:
txt_fullfn = None
script_callbacks.image_saved_callback(params)
-
return fullfn, txt_fullfn
+
def safe_decode_string(s: bytes):
remove_prefix = lambda text, prefix: text[len(prefix):] if text.startswith(prefix) else text # pylint: disable=unnecessary-lambda-assignment
for encoding in ['utf-8', 'utf-16', 'ascii', 'latin_1', 'cp1252', 'cp437']: # try different encodings
@@ -629,6 +624,8 @@ def safe_decode_string(s: bytes):
def read_info_from_image(image):
items = image.info or {}
geninfo = items.pop('parameters', None)
+ if geninfo is not None and len(geninfo) > 0:
+ items['UserComment'] = geninfo
if "exif" in items:
exif = piexif.load(items["exif"])
@@ -662,6 +659,7 @@ Negative prompt: {json_info["uc"]}
Steps: {json_info["steps"]}, Sampler: {sampler}, CFG scale: {json_info["scale"]}, Seed: {json_info["seed"]}, Size: {image.width}x{image.height}, Clip skip: 2, ENSD: 31337"""
except Exception as e:
errors.display(e, 'novelai image parser')
+
return geninfo, items
diff --git a/modules/lora b/modules/lora
index ad5f318d0..e6ad3cbc6 160000
--- a/modules/lora
+++ b/modules/lora
@@ -1 +1 @@
-Subproject commit ad5f318d066c52e5b27306b399bc87e41f2eef2b
+Subproject commit e6ad3cbc66130fdc3bf9ecd1e0272969b1d613f7
diff --git a/modules/postprocessing.py b/modules/postprocessing.py
index 4e0ee9489..d975f50f8 100644
--- a/modules/postprocessing.py
+++ b/modules/postprocessing.py
@@ -10,28 +10,27 @@ from modules.shared import opts
def run_postprocessing(extras_mode, image, image_folder: List[tempfile.NamedTemporaryFile], input_dir, output_dir, show_extras_results, *args, save_output: bool = True):
devices.torch_gc()
-
shared.state.begin()
shared.state.job = 'extras'
-
image_data = []
image_names = []
+ image_ext = []
outputs = []
-
if extras_mode == 1:
for img in image_folder:
if isinstance(img, Image.Image):
image = img
fn = ''
+ ext = None
else:
image = Image.open(os.path.abspath(img.name))
- fn = os.path.splitext(img.orig_name)[0]
+ fn, ext = os.path.splitext(img.orig_name)
image_data.append(image)
image_names.append(fn)
+ image_ext.append(ext)
elif extras_mode == 2:
assert not shared.cmd_opts.hide_ui_dir_config, '--hide-ui-dir-config option must be disabled'
assert input_dir, 'input directory not selected'
-
image_list = shared.listfiles(input_dir)
for filename in image_list:
try:
@@ -40,47 +39,38 @@ def run_postprocessing(extras_mode, image, image_folder: List[tempfile.NamedTemp
continue
image_data.append(image)
image_names.append(filename)
+ image_ext.append(None)
else:
image_data.append(image)
image_names.append(None)
-
+ image_ext.append(None)
if extras_mode == 2 and output_dir != '':
outpath = output_dir
else:
outpath = opts.outdir_samples or opts.outdir_extras_samples
-
infotext = ''
-
- for image, name in zip(image_data, image_names):
+ for image, name, ext in zip(image_data, image_names, image_ext):
if image is None:
continue
shared.state.textinfo = name
-
pp = scripts_postprocessing.PostprocessedImage(image.convert("RGB"))
-
scripts.scripts_postproc.run(pp, args)
-
if opts.use_original_name_batch and name is not None:
basename = os.path.splitext(os.path.basename(name))[0]
else:
basename = ''
-
infotext = ", ".join([k if k == v else f'{k}: {generation_parameters_copypaste.quote(v)}' for k, v in pp.info.items() if v is not None])
-
if opts.enable_pnginfo:
_geninfo, items = images.read_info_from_image(image)
for k, v in items.items():
pp.image.info[k] = v
pp.image.info["postprocessing"] = infotext
-
if save_output:
- images.save_image(pp.image, path=outpath, basename=basename, seed=None, prompt=None, extension=opts.samples_format, info=infotext, short_filename=True, no_prompt=True, grid=False, pnginfo_section_name="extras", existing_info=pp.image.info, forced_filename=None)
-
+ images.save_image(pp.image, path=outpath, basename=basename, seed=None, prompt=None, extension=ext or opts.samples_format, info=infotext, short_filename=True, no_prompt=True, grid=False, pnginfo_section_name="extras", existing_info=pp.image.info, forced_filename=None)
if extras_mode != 2 or show_extras_results:
outputs.append(pp.image)
devices.torch_gc()
-
return outputs, ui_common.plaintext_to_html(infotext), ''
diff --git a/modules/processing.py b/modules/processing.py
index efba7f01e..0d1b52ae9 100644
--- a/modules/processing.py
+++ b/modules/processing.py
@@ -17,7 +17,7 @@ from blendmodes.blend import blendLayers, BlendType
import modules.sd_hijack
from modules import devices, prompt_parser, masking, sd_samplers, lowvram, generation_parameters_copypaste, script_callbacks, extra_networks, sd_vae_approx, scripts # pylint: disable=unused-import
from modules.sd_hijack import model_hijack
-from modules.shared import opts, cmd_opts, state, log # pylint: disable=unused-import
+from modules.shared import opts, cmd_opts, state, log
import modules.shared as shared
import modules.paths as paths
import modules.face_restoration
@@ -611,8 +611,6 @@ def process_images_inner(p: StableDiffusionProcessing) -> Processed:
with torch.no_grad(), p.sd_model.ema_scope():
with devices.autocast():
p.init(p.all_prompts, p.all_seeds, p.all_subseeds)
-
- # for OSX, loading the model during sampling changes the generated picture, so it is loaded here
if shared.opts.live_previews_enable and opts.show_progress_type == "Approx NN":
sd_vae_approx.model()
diff --git a/modules/sd_models.py b/modules/sd_models.py
index e5f4fb6a2..78e1e222d 100644
--- a/modules/sd_models.py
+++ b/modules/sd_models.py
@@ -101,10 +101,13 @@ def list_models():
checkpoints_list.clear()
checkpoint_aliases.clear()
model_list = modelloader.load_models(model_path=model_path, model_url=None, command_path=shared.opts.ckpt_dir, ext_filter=[".ckpt", ".safetensors"], download_name=None, ext_blacklist=[".vae.ckpt", ".vae.safetensors"])
- if shared.cmd_opts.ckpt is not None and os.path.exists(shared.cmd_opts.ckpt):
- checkpoint_info = CheckpointInfo(shared.cmd_opts.ckpt)
- checkpoint_info.register()
- shared.opts.data['sd_model_checkpoint'] = checkpoint_info.title
+ if shared.cmd_opts.ckpt is not None:
+ if not os.path.exists(shared.cmd_opts.ckpt):
+ shared.log.warning(f"Requested checkpoint not found: {shared.cmd_opts.ckpt}")
+ else:
+ checkpoint_info = CheckpointInfo(shared.cmd_opts.ckpt)
+ checkpoint_info.register()
+ shared.opts.data['sd_model_checkpoint'] = checkpoint_info.title
elif shared.cmd_opts.ckpt != shared.default_sd_model_file and shared.cmd_opts.ckpt is not None:
shared.log.warning(f"Checkpoint not found: {shared.cmd_opts.ckpt}")
for filename in sorted(model_list, key=str.lower):
@@ -157,7 +160,8 @@ def select_checkpoint():
exit(1)
checkpoint_info = next(iter(checkpoints_list.values()))
if model_checkpoint is not None:
- shared.log.warning(f"Checkpoint {model_checkpoint} not found; loading fallback {checkpoint_info.title}")
+ shared.log.warning(f"Default checkpoint not found: {model_checkpoint}")
+ shared.log.warning(f"Loading fallback checkpoint: {checkpoint_info.title}")
return checkpoint_info
@@ -346,6 +350,8 @@ def load_model(checkpoint_info=None, already_loaded_state_dict=None, timer=None)
shared.debug(f'Load model: {checkpoint_info} {already_loaded_state_dict}')
from modules import lowvram, sd_hijack
checkpoint_info = checkpoint_info or select_checkpoint()
+ if checkpoint_info is None:
+ return
if timer is None:
timer = Timer()
current_checkpoint_info = None
@@ -389,7 +395,7 @@ def load_model(checkpoint_info=None, already_loaded_state_dict=None, timer=None)
if shared.cmd_opts.lowvram or shared.cmd_opts.medvram:
lowvram.setup_for_low_vram(sd_model, shared.cmd_opts.medvram)
else:
- sd_model.to(shared.device)
+ sd_model.to(devices.device)
timer.record("move")
shared.debug(f'Model weights moved: {memory_stats()}')
sd_hijack.model_hijack.hijack(sd_model)
diff --git a/webui.py b/webui.py
index 311927b13..1decd4ef7 100644
--- a/webui.py
+++ b/webui.py
@@ -157,7 +157,8 @@ def load_model():
if shared.sd_model is None:
log.error("No stable diffusion model loaded")
exit(1)
- shared.opts.data["sd_model_checkpoint"] = shared.sd_model.sd_checkpoint_info.title
+ 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()))
shared.state.end()
startup_timer.record("checkpoint")