multiple fixes

This commit is contained in:
Vladimir Mandic
2023-11-09 09:04:50 -05:00
parent e3cd9e473c
commit f6dd495eb3
13 changed files with 129 additions and 95 deletions
+5 -1
View File
@@ -5,11 +5,15 @@
- **Extra networks**
- Use multi-threading for 5x load speedup
- **General**:
- Reworked parser when pasting previously generated images/prompts
- Reworked parser when pasting previously generated images/prompts
includes all `txt2img`, `img2img` and `override` params
- **Diffusers**
- Fix DPM SDE scheduler
- Add additional pipeline types for manual model loads when loading from `safetensors`
- **Fixes**
- Fix inpaint
- Fix manual grid image save
- Fix img2img init image save
- More uniform models paths
- Improve extension compatibility
- Improve BF16 support
+1 -1
View File
@@ -61,7 +61,7 @@
{"id":"","label":"Skip","localized":"","hint":"Stop processing current job and continue processing"},
{"id":"","label":"Interrupt","localized":"","hint":"Interrupt current processing job"},
{"id":"","label":"Pause","localized":"","hint":"Pause processing"},
{"id":"","label":"Restore","localized":"","hint":"Restore parameters from last known generated image"},
{"id":"","label":"Restore","localized":"","hint":"Restore parameters from current prompt or last known generated image"},
{"id":"","label":"Clear","localized":"","hint":"Clear prompts"},
{"id":"","label":"Networks","localized":"","hint":"Open extra network interface"},
{"id":"","label":"Interrogate\nCLIP","localized":"","hint":"Run interrogate using CLIP model"},
+13 -17
View File
@@ -210,14 +210,15 @@ def parse_generation_parameters(x: str):
if len(remaining) == 0:
return res
remaining = x[7:] if x.startswith('Prompt: ') else x
prompt, remaining = remaining.split('Negative prompt: ', maxsplit=1) if 'Negative prompt: ' in remaining else (remaining, '')
remaining = x[11:] if x.startswith('parameters: ') else x
prompt, remaining = remaining.strip().split('Negative prompt: ', maxsplit=1) if 'Negative prompt: ' in remaining else (remaining, '')
res["Prompt"] = prompt.strip()
negative, remaining = remaining.split('Steps: ', maxsplit=1) if 'Steps: ' in remaining else (remaining, None)
negative, remaining = remaining.strip().split('Steps: ', maxsplit=1) if 'Steps: ' in remaining else (remaining, None)
res["Negative prompt"] = negative.strip()
if remaining is None:
return res
remaining = f'Steps: {remaining}'
for k, v in re_param.findall(remaining):
for k, v in re_param.findall(remaining.strip()):
try:
if v[0] == '"' and v[-1] == '"':
v = unquote(v)
@@ -230,8 +231,7 @@ def parse_generation_parameters(x: str):
except Exception:
pass
res["Full quality"] = res.get('VAE', None) != 'TAESD'
for k, v in res.items():
debug(f"Parse prompt: '{k}'={v}")
debug(f"Parse prompt: {res}")
return res
@@ -239,7 +239,7 @@ settings_map = {}
infotext_to_setting_name_mapping = [
('Backed', 'sd_backend'),
('Backend', 'sd_backend'),
('Model hash', 'sd_model_checkpoint'),
('Refiner', 'sd_model_refiner'),
('VAE', 'sd_vae'),
@@ -282,13 +282,6 @@ infotext_to_setting_name_mapping = [
def create_override_settings_dict(text_pairs):
"""creates processing's override_settings parameters from gradio's multiselect
Example input:
['Clip skip: 2', 'Model hash: e6e99610c4', 'ENSD: 31337']
Example output:
{'CLIP_stop_at_last_layers': 2, 'sd_model_checkpoint': 'e6e99610c4', 'eta_noise_seed_delta': 31337}
"""
res = {}
params = {}
for pair in text_pairs:
@@ -310,25 +303,25 @@ def connect_paste(button, local_paste_fields, input_comp, override_settings_comp
if os.path.exists(filename):
with open(filename, "r", encoding="utf8") as file:
prompt = file.read()
shared.log.debug(f'Paste prompt last: {prompt}')
shared.log.debug(f'Paste prompt: type="params" prompt="{prompt}"')
else:
prompt = ''
else:
shared.log.debug(f'Paste prompt current: {prompt}')
shared.log.debug(f'Paste prompt: type="current" prompt="{prompt}"')
params = parse_generation_parameters(prompt)
script_callbacks.infotext_pasted_callback(prompt, params)
res = []
applied = {}
for output, key in local_paste_fields:
if callable(key):
v = key(params)
else:
v = params.get(key, None)
if v is not None:
debug(f"Parse apply: '{key}'={v}")
if v is None:
res.append(gr.update())
elif isinstance(v, type_of_gr_update):
res.append(v)
applied[key] = v
else:
try:
valtype = type(output.value)
@@ -337,8 +330,10 @@ def connect_paste(button, local_paste_fields, input_comp, override_settings_comp
else:
val = valtype(v)
res.append(gr.update(value=val))
applied[key] = val
except Exception:
res.append(gr.update())
debug(f"Parse apply: {applied}")
return res
if override_settings_component is not None:
@@ -359,6 +354,7 @@ def connect_paste(button, local_paste_fields, input_comp, override_settings_comp
continue
vals[param_name] = v
vals_pairs = [f"{k}: {v}" for k, v in vals.items()]
shared.log.debug(f'Settings overrides: {vals_pairs}')
return gr.Dropdown.update(value=vals_pairs, choices=vals_pairs, visible=len(vals_pairs) > 0)
local_paste_fields = local_paste_fields + [(override_settings_component, paste_settings)]
+8 -5
View File
@@ -547,7 +547,7 @@ save_thread = threading.Thread(target=atomically_save_image, daemon=True)
save_thread.start()
def save_image(image, path, basename = '', seed=None, prompt=None, extension=shared.opts.samples_format, 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): # pylint: disable=unused-argument
def save_image(image, path, basename='', seed=None, prompt=None, extension=shared.opts.samples_format, 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): # pylint: disable=unused-argument
if image is None:
shared.log.warning('Image is none')
return None, None
@@ -556,27 +556,30 @@ def save_image(image, path, basename = '', seed=None, prompt=None, extension=sha
if path is None or len(path) == 0: # set default path to avoid errors when functions are triggered manually or via api and param is not set
path = shared.opts.outdir_save
namegen = FilenameGenerator(p, seed, prompt, image, grid=grid)
suffix = suffix if suffix is not None else ''
basename = basename if basename is not None else ''
if shared.opts.save_to_dirs:
dirname = namegen.apply(shared.opts.directories_filename_pattern or "[prompt_words]")
path = os.path.join(path, dirname)
file_decoration = ''
if forced_filename is None:
if shared.opts.samples_filename_pattern and len(shared.opts.samples_filename_pattern) > 0:
file_decoration = shared.opts.samples_filename_pattern
else:
file_decoration = "[seq]-[prompt_words]"
file_decoration = namegen.apply(file_decoration)
file_decoration += suffix
file_decoration += suffix if suffix is not None else ''
filename = os.path.join(path, f"{file_decoration}.{extension}") if basename == '' else os.path.join(path, f"{basename}-{file_decoration}.{extension}")
else:
filename = forced_filename
forced_filename += suffix if suffix is not None else ''
filename = os.path.join(path, f"{forced_filename}.{extension}") if basename == '' else os.path.join(path, f"{basename}-{forced_filename}.{extension}")
pnginfo = existing_info or {}
if info is not None:
pnginfo[pnginfo_section_name] = info
params = script_callbacks.ImageSaveParams(image, p, filename, pnginfo)
params.filename = namegen.sanitize(filename)
dirname = os.path.dirname(params.filename)
os.makedirs(dirname, exist_ok=True)
if dirname is not None and len(dirname) > 0:
os.makedirs(dirname, exist_ok=True)
# sequence
if shared.opts.save_images_add_number or '[seq]' in params.filename:
if '[seq]' not in params.filename:
+5
View File
@@ -211,6 +211,11 @@ def img2img(id_task: str, mode: int, prompt: str, negative_prompt: str, prompt_s
p.extra_generation_params['Resize mode'] = resize_mode
if mask:
p.extra_generation_params["Mask blur"] = mask_blur
p.extra_generation_params["Mask alpha"] = mask_alpha
p.extra_generation_params["Mask invert"] = inpainting_mask_invert
p.extra_generation_params["Mask content"] = inpainting_fill
p.extra_generation_params["Mask area"] = inpaint_full_res
p.extra_generation_params["Mask padding"] = inpaint_full_res_padding
p.is_batch = mode == 5
if p.is_batch:
process_batch(p, img2img_batch_files, img2img_batch_input_dir, img2img_batch_output_dir, img2img_batch_inpaint_mask_dir, args)
+1 -5
View File
@@ -166,11 +166,6 @@ class StableDiffusionProcessing:
self.disable_extra_networks = False
self.token_merging_ratio = 0
self.token_merging_ratio_hr = 0
if not seed_enable_extras:
self.subseed = -1
self.subseed_strength = 0
self.seed_resize_from_h = 0
self.seed_resize_from_w = 0
self.scripts = None
self.script_args = script_args or []
self.per_script_args = {}
@@ -603,6 +598,7 @@ def create_infotext(p: StableDiffusionProcessing, all_prompts=None, all_seeds=No
args["Init image hash"] = getattr(p, 'init_img_hash', None)
args["Mask weight"] = getattr(p, "inpainting_mask_weight", shared.opts.inpainting_mask_weight) if p.is_using_inpainting_conditioning else None
args['Resize mode'] = getattr(p, 'resize_mode', None)
args['Resize scale'] = getattr(p, 'scale_by', None)
args["Mask blur"] = p.mask_blur if getattr(p, 'mask', None) is not None and getattr(p, 'mask_blur', 0) > 0 else None
args["Denoising strength"] = getattr(p, 'denoising_strength', None)
if 'face' in p.ops:
+9 -3
View File
@@ -27,7 +27,7 @@ def list_crossattention():
def get_pipelines():
import diffusers
from installer import log
pipelines = {
pipelines = { # note: not all pipelines can be used manually as they require prior pipeline next to decoder pipeline
'Autodetect': None,
'Stable Diffusion': getattr(diffusers, 'StableDiffusionPipeline', None),
'Stable Diffusion Img2Img': getattr(diffusers, 'StableDiffusionImg2ImgPipeline', None),
@@ -37,9 +37,15 @@ def get_pipelines():
'Stable Diffusion XL Img2Img': getattr(diffusers, 'StableDiffusionXLImg2ImgPipeline', None),
'Stable Diffusion XL Inpaint': getattr(diffusers, 'StableDiffusionXLInpaintPipeline', None),
'Stable Diffusion XL Instruct': getattr(diffusers, 'StableDiffusionXLInstructPix2PixPipeline', None),
'Latent Consistency Model': getattr(diffusers, 'LatentConsistencyModelPipeline', None),
'PixArt Alpha': getattr(diffusers, 'PixArtAlphaPipeline', None),
'UniDiffuser': getattr(diffusers, 'UniDiffuserPipeline', None),
'Wuerstchen': getattr(diffusers, 'WuerstchenCombinedPipeline', None),
'Kandinsky 2.1': getattr(diffusers, 'KandinskyPipeline', None),
'Kandinsky 2.2': getattr(diffusers, 'KandinskyV22Pipeline', None),
'DeepFloyd IF': getattr(diffusers, 'IFPipeline', None),
'Custom Diffusers Pipeline': getattr(diffusers, 'DiffusionPipeline', None),
# 'Test': getattr(diffusers, 'TestPipeline', None),
# 'Kandinsky V1', 'Kandinsky V2', 'DeepFloyd IF', 'Shap-E', 'Kandinsky V1 Img2Img', 'Kandinsky V2 Img2Img', 'DeepFloyd IF Img2Img', 'Shap-E Img2Img',
# Segmind SSD-1B, Segmind Tiny
}
for k, v in pipelines.items():
if k != 'Autodetect' and v is None:
+25 -4
View File
@@ -136,18 +136,33 @@ class StyleDatabase:
return found[0] if len(found) > 0 else self.no_style
def get_style_prompts(self, styles):
if styles is None or not isinstance(styles, list):
log.error(f'Invalid styles: {styles}')
return []
return [self.find_style(x).prompt for x in styles]
def get_negative_style_prompts(self, styles):
if styles is None or not isinstance(styles, list):
log.error(f'Invalid styles: {styles}')
return []
return [self.find_style(x).negative_prompt for x in styles]
def apply_styles_to_prompt(self, prompt, styles):
if styles is None or not isinstance(styles, list):
log.error(f'Invalid styles: {styles}')
return prompt
return apply_styles_to_prompt(prompt, [self.find_style(x).prompt for x in styles])
def apply_negative_styles_to_prompt(self, prompt, styles):
if styles is None or not isinstance(styles, list):
log.error(f'Invalid styles: {styles}')
return prompt
return apply_styles_to_prompt(prompt, [self.find_style(x).negative_prompt for x in styles])
def apply_styles_to_extra(self, p):
if p.styles is None or not isinstance(p.styles, list):
log.error(f'Invalid styles: {p.styles}')
return
for style in p.styles:
s = self.find_style(style)
apply_styles_to_extra(p, s)
@@ -173,19 +188,25 @@ class StyleDatabase:
log.error(f'Failed to save style: name={name} file={path} error={e}')
count = len(list(self.styles))
if count > 0:
log.debug(f'Saved styles: {path} {count}')
log.debug(f'Saved styles: folder="{path}" items={count}')
def load_csv(self, legacy_file):
if not os.path.isfile(legacy_file):
return
with open(legacy_file, "r", encoding="utf-8-sig", newline='') as file:
reader = csv.DictReader(file, skipinitialspace=True)
num = 0
for row in reader:
try:
self.styles[row["name"]] = Style(row["name"], row["prompt"] if "prompt" in row else row["text"], row.get("negative_prompt", ""))
name = row["name"]
prompt = row["prompt"] if "prompt" in row else row["text"]
negative = row.get("negative_prompt", "") if "negative_prompt" in row else row.get("negative", "")
self.styles[name] = Style(name, desc=name, prompt=prompt, negative_prompt=negative, extra="")
log.debug(f'Migrated style: {self.styles[name].__dict__}')
num += 1
except Exception:
log.error(f'Styles error: file={legacy_file} row={row}')
log.debug(f'Load legacy styles: file={legacy_file} items={len(self.styles.keys())}')
log.error(f'Styles error: file="{legacy_file}" row={row}')
log.info(f'Load legacy styles: file="{legacy_file}" loaded={num} created={len(list(self.styles))}')
"""
def save_csv(self, path: str) -> None:
+57 -54
View File
@@ -511,44 +511,48 @@ def create_ui(startup_timer = None):
txt_prompt_img.change(fn=modules.images.image_data, inputs=[txt_prompt_img], outputs=[txt2img_prompt, txt_prompt_img])
txt2img_paste_fields = [
# prompt
(txt2img_prompt, "Prompt"),
(txt2img_negative_prompt, "Negative prompt"),
(txt2img_prompt_styles, "Styles"),
(steps, "Steps"),
(seed, "Seed"),
(sampler_index, "Sampler"),
(cfg_scale, "CFG scale"),
# main
(width, "Size-1"),
(height, "Size-2"),
(subseed, "Variation seed"),
(subseed_strength, "Variation strength"),
(clip_skip, "Clip skip"),
(latent_index, "Latent sampler"),
(latent_index, "Secondary sampler"),
(denoising_strength, "Denoising strength"),
(refiner_steps, "Refiner steps"),
(refiner_start, "Refiner start"),
(full_quality, "Full quality"),
(restore_faces, "Face restoration"),
# sampler
(sampler_index, "Sampler"),
(steps, "Steps"),
# batch
(batch_count, "Batch-1"),
(batch_size, "Batch-2"),
(seed_resize_from_w, "Seed resize from-1"),
(seed_resize_from_h, "Seed resize from-2"),
# seed
(seed, "Seed"),
(subseed, "Variation seed"),
(subseed_strength, "Variation strength"),
# advanced
(cfg_scale, "CFG scale"),
(clip_skip, "Clip skip"),
(image_cfg_scale, "Image CFG scale"),
(diffusers_guidance_rescale, "CFG rescale"),
(full_quality, "Full quality"),
(restore_faces, "Face restoration"),
(tiling, "Tiling"),
# second pass
(enable_hr, "Second pass"),
(hr_force, "Hires force"),
(hr_scale, "Hires upscale"),
(latent_index, "Latent sampler"),
(denoising_strength, "Denoising strength"),
(hr_upscaler, "Hires upscaler"),
(hr_force, "Hires force"),
(hr_second_pass_steps, "Hires steps"),
(hr_scale, "Hires upscale"),
(hr_resize_x, "Hires resize-1"),
(hr_resize_y, "Hires resize-2"),
(diffusers_guidance_rescale, "CFG rescale"),
(image_cfg_scale, "Image CFG scale"),
(refiner_steps, "Refiner steps"),
# refiner
(refiner_start, "Refiner start"),
(tiling, "Tiling"),
(refiner_negative, "Negative2"),
(refiner_steps, "Refiner steps"),
(refiner_prompt, "Prompt2"),
# TODO restore params complete list
(refiner_negative, "Negative2"),
# hidden
(seed_resize_from_w, "Seed resize from-1"),
(seed_resize_from_h, "Seed resize from-2"),
*modules.scripts.scripts_txt2img.infotext_fields
]
parameters_copypaste.add_paste_fields("txt2img", None, txt2img_paste_fields, override_settings)
@@ -839,46 +843,45 @@ def create_ui(startup_timer = None):
ui_extra_networks.setup_ui(extra_networks_ui_img2img, img2img_gallery)
img2img_paste_fields = [
# prompt
(img2img_prompt, "Prompt"),
(img2img_negative_prompt, "Negative prompt"),
# (img2img_prompt_styles, "Styles"),
(steps, "Steps"),
(seed, "Seed"),
# sampler
(sampler_index, "Sampler"),
(cfg_scale, "CFG scale"),
(steps, "Steps"),
# resize
(resize_mode, "Resize mode"),
(width, "Size-1"),
(height, "Size-2"),
(scale_by, "Resize scale"),
# batch
(batch_count, "Batch-1"),
(batch_size, "Batch-2"),
# seed
(seed, "Seed"),
(subseed, "Variation seed"),
(subseed_strength, "Variation strength"),
(full_quality, "Full quality"),
(clip_skip, "Clip skip"),
(latent_index, "Latent sampler"),
(latent_index, "Secondary sampler"),
# denoise
(denoising_strength, "Denoising strength"),
(refiner_start, "Refiner start"),
# advanced
(cfg_scale, "CFG scale"),
(image_cfg_scale, "Image CFG scale"),
(clip_skip, "Clip skip"),
(diffusers_guidance_rescale, "CFG rescale"),
(full_quality, "Full quality"),
(restore_faces, "Face restoration"),
(batch_size, "Batch size"),
(batch_count, "Batch count"),
(tiling, "Tiling"),
# inpaint
(mask_blur, "Mask blur"),
(mask_alpha, "Mask alpha"),
(inpainting_mask_invert, "Mask invert"),
(inpainting_fill, "Masked content"),
(inpaint_full_res, "Mask area"),
(inpaint_full_res_padding, "Masked padding"),
# hidden
(seed_resize_from_w, "Seed resize from-1"),
(seed_resize_from_h, "Seed resize from-2"),
(resize_mode, "Resize mode"),
(image_cfg_scale, "Image CFG scale"),
(diffusers_guidance_rescale, "CFG rescale"),
(tiling, "Tiling"),
(mask_blur, "Mask blur"),
# TODO scale_by add to paste fields
(scale_by, "UNKNOWN"),
# from txt2img
(hr_force, "Hires force"),
(hr_scale, "Hires upscale"),
(hr_upscaler, "Hires upscaler"),
(hr_second_pass_steps, "Hires steps"),
(hr_second_pass_steps, "Hires steps"),
(hr_resize_x, "Hires resize-1"),
(hr_resize_y, "Hires resize-2"),
(refiner_steps, "Refiner steps"),
(refiner_start, "Refiner start"),
(refiner_prompt, "Prompt2"),
(refiner_negative, "Negative2"),
*modules.scripts.scripts_img2img.infotext_fields
]
parameters_copypaste.add_paste_fields("img2img", init_img, img2img_paste_fields, override_settings)
+1 -1
View File
@@ -93,7 +93,7 @@ def save_files(js_data, images, html_info, index):
self.index_of_first_image = getattr(self, 'index_of_first_image', 0)
self.infotexts = getattr(self, 'infotexts', [html_info])
self.infotext = self.infotexts[0] if len(self.infotexts) > 0 else html_info
self.outpath_grids = None
self.outpath_grids = shared.opts.outdir_grids or shared.opts.outdir_txt2img_grids
try:
data = json.loads(js_data)
except Exception:
+1 -1
View File
@@ -321,7 +321,7 @@ class ExtraNetworksPage:
return 'html/card-no-preview.png'
if shared.opts.diffusers_dir in path:
path = os.path.relpath(path, shared.opts.diffusers_dir)
ref = os.path.join(paths.models_path, 'Reference')
ref = os.path.join('models', 'Reference')
fn = os.path.join(ref, path.replace('models--', '').replace('\\', '/').split('/')[0])
files = listdir(ref)
else:
+2 -2
View File
@@ -2,10 +2,10 @@ import os
import html
import json
import concurrent
from modules import shared, ui_extra_networks, sd_models, paths
from modules import shared, ui_extra_networks, sd_models
reference_dir = os.path.join(paths.models_path, 'Reference')
reference_dir = os.path.join('models', 'Reference')
class ExtraNetworksPageCheckpoints(ui_extra_networks.ExtraNetworksPage):
def __init__(self):
+1 -1
Submodule wiki updated: e999774e30...c0b5cb2672