mirror of
https://github.com/vladmandic/automatic
synced 2026-09-19 09:14:35 +02:00
jumbo merge part two
This commit is contained in:
@@ -81,7 +81,6 @@ def compatibility_args(opts, args):
|
||||
group.add_argument("--opt-channelslast", help=argparse.SUPPRESS, default=opts.opt_channelslast)
|
||||
group.add_argument("--xformers", default = (opts.cross_attention_optimization == "xFormers"), action='store_true', help=argparse.SUPPRESS)
|
||||
group.add_argument("--disable-nan-check", help=argparse.SUPPRESS, default=opts.disable_nan_check)
|
||||
group.add_argument("--token-merging", help=argparse.SUPPRESS, default=opts.token_merging)
|
||||
group.add_argument("--rollback-vae", help=argparse.SUPPRESS, default=opts.rollback_vae)
|
||||
group.add_argument("--no-half", help=argparse.SUPPRESS, default=opts.no_half)
|
||||
group.add_argument("--no-half-vae", help=argparse.SUPPRESS, default=opts.no_half_vae)
|
||||
|
||||
@@ -154,7 +154,7 @@ class UpscalerESRGAN(Upscaler):
|
||||
if "http" in path:
|
||||
filename = load_file_from_url(
|
||||
url=self.model_url,
|
||||
model_dir=self.model_path,
|
||||
model_dir=self.model_download_path,
|
||||
file_name=f"{self.model_name}.pth",
|
||||
progress=True,
|
||||
)
|
||||
|
||||
@@ -126,8 +126,6 @@ def list_extensions():
|
||||
extension_paths = []
|
||||
extension_names = []
|
||||
extension_folders = [extensions_builtin_dir] if shared.cmd_opts.safe else [extensions_builtin_dir, extensions_dir]
|
||||
if shared.cmd_opts.base:
|
||||
extension_folders = []
|
||||
for dirname in extension_folders:
|
||||
if not os.path.isdir(dirname):
|
||||
return
|
||||
|
||||
+2
-1
@@ -188,8 +188,9 @@ def run_modelmerger(id_task, primary_model_name, secondary_model_name, tertiary_
|
||||
output_modelname = os.path.join(ckpt_dir, filename)
|
||||
shared.state.nextjob()
|
||||
shared.state.textinfo = "Saving"
|
||||
metadata = {"format": "pt", "sd_merge_models": {}, "sd_merge_recipe": None}
|
||||
metadata = None
|
||||
if save_metadata:
|
||||
metadata = {"format": "pt", "sd_merge_models": {}}
|
||||
merge_recipe = {
|
||||
"type": "webui", # indicate this model was merged with webui's built-in merger
|
||||
"primary_model_hash": primary_model_info.sha256,
|
||||
|
||||
@@ -275,7 +275,6 @@ Steps: 20, Sampler: Euler a, CFG scale: 7, Seed: 965400086, Size: 512x512, Model
|
||||
else:
|
||||
res[k] = v
|
||||
|
||||
|
||||
# Missing CLIP skip means it was set to 1 (the default)
|
||||
if "Clip skip" not in res:
|
||||
res["Clip skip"] = "1"
|
||||
@@ -285,28 +284,6 @@ Steps: 20, Sampler: Euler a, CFG scale: 7, Seed: 965400086, Size: 512x512, Model
|
||||
if "Hires resize-1" not in res:
|
||||
res["Hires resize-1"] = 0
|
||||
res["Hires resize-2"] = 0
|
||||
# Infer additional override settings for token merging
|
||||
token_merging_ratio = res.get("Token merging ratio", None)
|
||||
token_merging_ratio_hr = res.get("Token merging ratio hr", None)
|
||||
if token_merging_ratio is not None or token_merging_ratio_hr is not None:
|
||||
res["Token merging"] = 'True'
|
||||
if token_merging_ratio is None:
|
||||
res["Token merging hr only"] = 'True'
|
||||
else:
|
||||
res["Token merging hr only"] = 'False'
|
||||
if res.get("Token merging random", None) is None:
|
||||
res["Token merging random"] = 'False'
|
||||
if res.get("Token merging merge attention", None) is None:
|
||||
res["Token merging merge attention"] = 'True'
|
||||
if res.get("Token merging merge cross attention", None) is None:
|
||||
res["Token merging merge cross attention"] = 'False'
|
||||
if res.get("Token merging merge mlp", None) is None:
|
||||
res["Token merging merge mlp"] = 'False'
|
||||
if res.get("Token merging stride x", None) is None:
|
||||
res["Token merging stride x"] = '2'
|
||||
if res.get("Token merging stride y", None) is None:
|
||||
res["Token merging stride y"] = '2'
|
||||
|
||||
restore_old_hires_fix_params(res)
|
||||
return res
|
||||
|
||||
@@ -326,17 +303,8 @@ infotext_to_setting_name_mapping = [
|
||||
('UniPC skip type', 'uni_pc_skip_type'),
|
||||
('UniPC order', 'uni_pc_order'),
|
||||
('UniPC lower order final', 'uni_pc_lower_order_final'),
|
||||
('Token merging', 'token_merging'),
|
||||
('Token merging ratio', 'token_merging_ratio'),
|
||||
('Token merging hr only', 'token_merging_hr_only'),
|
||||
('Token merging ratio hr', 'token_merging_ratio_hr'),
|
||||
('Token merging random', 'token_merging_random'),
|
||||
('Token merging merge attention', 'token_merging_merge_attention'),
|
||||
('Token merging merge cross attention', 'token_merging_merge_cross_attention'),
|
||||
('Token merging merge mlp', 'token_merging_merge_mlp'),
|
||||
('Token merging maximum downsampling', 'token_merging_maximum_down_sampling'),
|
||||
('Token merging stride x', 'token_merging_stride_x'),
|
||||
('Token merging stride y', 'token_merging_stride_y')
|
||||
]
|
||||
|
||||
|
||||
|
||||
@@ -86,7 +86,7 @@ def load_models(model_path: str, model_url: str = None, command_path: str = None
|
||||
if model_url is not None and len(output) == 0:
|
||||
if download_name is not None:
|
||||
from basicsr.utils.download_util import load_file_from_url
|
||||
dl = load_file_from_url(model_url, model_path, True, download_name)
|
||||
dl = load_file_from_url(model_url, places[0], True, download_name)
|
||||
output.append(dl)
|
||||
else:
|
||||
output.append(model_url)
|
||||
@@ -181,7 +181,10 @@ def load_upscalers():
|
||||
for cls in reversed(used_classes.values()):
|
||||
name = cls.__name__
|
||||
cmd_name = f"{name.lower().replace('upscaler', '')}_models_path"
|
||||
scaler = cls(commandline_options.get(cmd_name, None))
|
||||
commandline_model_path = commandline_options.get(cmd_name, None)
|
||||
scaler = cls(commandline_model_path)
|
||||
scaler.user_path = commandline_model_path
|
||||
scaler.model_download_path = commandline_model_path or scaler.model_path
|
||||
datas += scaler.scalers
|
||||
|
||||
shared.sd_upscalers = sorted(
|
||||
|
||||
+29
-31
@@ -9,7 +9,6 @@ import torch
|
||||
import numpy as np
|
||||
from PIL import Image, ImageFilter, ImageOps
|
||||
import cv2
|
||||
import tomesd
|
||||
from skimage import exposure
|
||||
from ldm.data.util import AddMiDaS
|
||||
from ldm.models.diffusion.ddpm import LatentDepth2ImageDiffusion
|
||||
@@ -130,6 +129,8 @@ class StableDiffusionProcessing:
|
||||
self.override_settings_restore_afterwards = override_settings_restore_afterwards
|
||||
self.is_using_inpainting_conditioning = False
|
||||
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
|
||||
@@ -145,7 +146,7 @@ class StableDiffusionProcessing:
|
||||
self.clip_skip = clip_skip
|
||||
self.iteration = 0
|
||||
self.is_hr_pass = False
|
||||
opts.data['clip_skip'] = clip_skip
|
||||
# opts.data['clip_skip'] = clip_skip # todo is this necessary?
|
||||
|
||||
|
||||
@property
|
||||
@@ -243,6 +244,11 @@ class StableDiffusionProcessing:
|
||||
def close(self):
|
||||
self.sampler = None # pylint: disable=attribute-defined-outside-init
|
||||
|
||||
def get_token_merging_ratio(self, for_hr=False):
|
||||
if for_hr:
|
||||
return self.token_merging_ratio_hr or opts.token_merging_ratio_hr or self.token_merging_ratio or opts.token_merging_ratio
|
||||
return self.token_merging_ratio or opts.token_merging_ratio
|
||||
|
||||
|
||||
class Processed:
|
||||
def __init__(self, p: StableDiffusionProcessing, images_list, seed=-1, info="", subseed=None, all_prompts=None, all_negative_prompts=None, all_seeds=None, all_subseeds=None, index_of_first_image=0, infotexts=None, comments=""):
|
||||
@@ -278,6 +284,7 @@ class Processed:
|
||||
self.s_tmin = p.s_tmin
|
||||
self.s_tmax = p.s_tmax
|
||||
self.s_noise = p.s_noise
|
||||
self.s_min_uncond = p.s_min_uncond
|
||||
self.sampler_noise_scheduler_override = p.sampler_noise_scheduler_override
|
||||
self.prompt = self.prompt if type(self.prompt) != list else self.prompt[0]
|
||||
self.negative_prompt = self.negative_prompt if type(self.negative_prompt) != list else self.negative_prompt[0]
|
||||
@@ -288,6 +295,8 @@ class Processed:
|
||||
self.all_negative_prompts = all_negative_prompts or p.all_negative_prompts or [self.negative_prompt]
|
||||
self.all_seeds = all_seeds or p.all_seeds or [self.seed]
|
||||
self.all_subseeds = all_subseeds or p.all_subseeds or [self.subseed]
|
||||
self.token_merging_ratio = p.token_merging_ratio
|
||||
self.token_merging_ratio_hr = p.token_merging_ratio_hr
|
||||
self.infotexts = infotexts or [info]
|
||||
|
||||
def js(self):
|
||||
@@ -326,6 +335,9 @@ class Processed:
|
||||
def infotext(self, p: StableDiffusionProcessing, index):
|
||||
return create_infotext(p, self.all_prompts, self.all_seeds, self.all_subseeds, comments=[], position_in_batch=index % self.batch_size, iteration=index // self.batch_size)
|
||||
|
||||
def get_token_merging_ratio(self, for_hr=False):
|
||||
return self.token_merging_ratio_hr if for_hr else self.token_merging_ratio
|
||||
|
||||
|
||||
# from https://discuss.pytorch.org/t/help-regarding-slerp-function-for-generative-model-sampling/32475/3
|
||||
def slerp(val, low, high):
|
||||
@@ -426,6 +438,9 @@ def fix_seed(p):
|
||||
def create_infotext(p: StableDiffusionProcessing, all_prompts, all_seeds, all_subseeds, comments=None, iteration=0, position_in_batch=0): # pylint: disable=unused-argument
|
||||
index = position_in_batch + iteration * p.batch_size
|
||||
|
||||
enable_hr = getattr(p, 'enable_hr', False)
|
||||
token_merging_ratio = p.get_token_merging_ratio()
|
||||
token_merging_ratio_hr = p.get_token_merging_ratio(for_hr=True)
|
||||
uses_ensd = opts.eta_noise_seed_delta != 0
|
||||
if uses_ensd:
|
||||
uses_ensd = sd_samplers_common.is_sampler_using_eta_noise_seed_delta(p)
|
||||
@@ -451,14 +466,8 @@ def create_infotext(p: StableDiffusionProcessing, all_prompts, all_seeds, all_su
|
||||
"ENSD": opts.eta_noise_seed_delta if uses_ensd else None,
|
||||
"Init image hash": getattr(p, 'init_img_hash', None),
|
||||
"Version": git_commit,
|
||||
"Token merging ratio": None if not (opts.token_merging or cmd_opts.token_merging) or opts.token_merging_hr_only else opts.token_merging_ratio,
|
||||
"Token merging ratio hr": None if not (opts.token_merging or cmd_opts.token_merging) else opts.token_merging_ratio_hr,
|
||||
"Token merging random": None if opts.token_merging_random is False else opts.token_merging_random,
|
||||
"Token merging merge attention": None if opts.token_merging_merge_attention is True else opts.token_merging_merge_attention,
|
||||
"Token merging merge cross attention": None if opts.token_merging_merge_cross_attention is False else opts.token_merging_merge_cross_attention,
|
||||
"Token merging merge mlp": None if opts.token_merging_merge_mlp is False else opts.token_merging_merge_mlp,
|
||||
"Token merging stride x": None if opts.token_merging_stride_x == 2 else opts.token_merging_stride_x,
|
||||
"Token merging stride y": None if opts.token_merging_stride_y == 2 else opts.token_merging_stride_y,
|
||||
"Token merging ratio": None if token_merging_ratio == 0 else token_merging_ratio,
|
||||
"Token merging ratio hr": None if not enable_hr or token_merging_ratio_hr == 0 else token_merging_ratio_hr,
|
||||
"Parser": opts.prompt_attention,
|
||||
}
|
||||
generation_params.update(p.extra_generation_params)
|
||||
@@ -511,9 +520,7 @@ def process_images(p: StableDiffusionProcessing) -> Processed:
|
||||
if k == 'sd_vae':
|
||||
sd_vae.reload_vae_weights()
|
||||
|
||||
if (opts.token_merging or cmd_opts.token_merging) and not opts.token_merging_hr_only:
|
||||
sd_models.apply_token_merging(sd_model=p.sd_model, hr=False)
|
||||
log.debug('Token merging applied')
|
||||
sd_models.apply_token_merging(p.sd_model, p.get_token_merging_ratio())
|
||||
|
||||
if cmd_opts.profile:
|
||||
"""
|
||||
@@ -531,9 +538,7 @@ def process_images(p: StableDiffusionProcessing) -> Processed:
|
||||
else:
|
||||
res = process_images_inner(p)
|
||||
finally:
|
||||
if opts.token_merging or cmd_opts.token_merging:
|
||||
tomesd.remove_patch(p.sd_model)
|
||||
log.debug('Token merging model optimizations removed')
|
||||
sd_models.apply_token_merging(p.sd_model, 0)
|
||||
if p.override_settings_restore_afterwards: # restore opts to original state
|
||||
for k, v in stored_opts.items():
|
||||
setattr(opts, k, v)
|
||||
@@ -642,11 +647,8 @@ def process_images_inner(p: StableDiffusionProcessing) -> Processed:
|
||||
processed = Processed(p, [], p.seed, "")
|
||||
file.write(processed.infotext(p, 0))
|
||||
step_multiplier = 1
|
||||
if not shared.opts.dont_fix_second_order_samplers_schedule:
|
||||
try:
|
||||
step_multiplier = 2 if sd_samplers.all_samplers_map.get(p.sampler_name).aliases[0] in ['k_dpmpp_2s_a', 'k_dpmpp_2s_a_ka', 'k_dpmpp_sde', 'k_dpmpp_sde_ka', 'k_dpm_2', 'k_dpm_2_a', 'k_heun'] else 1
|
||||
except Exception:
|
||||
pass
|
||||
sampler_config = sd_samplers.find_sampler_config(p.sampler_name)
|
||||
step_multiplier = 2 if sampler_config and sampler_config.options.get("second_order", False) else 1
|
||||
if p.n_iter > 1:
|
||||
shared.state.job = f"Batch {n+1} out of {p.n_iter}"
|
||||
|
||||
@@ -774,7 +776,7 @@ def process_images_inner(p: StableDiffusionProcessing) -> Processed:
|
||||
images_list=output_images,
|
||||
seed=p.all_seeds[0],
|
||||
info=infotext(),
|
||||
comments="".join(f"\n\n{comment}" for comment in comments),
|
||||
comments="\n".join(comments),
|
||||
subseed=p.all_subseeds[0],
|
||||
index_of_first_image=index_of_first_image,
|
||||
infotexts=infotexts,
|
||||
@@ -943,16 +945,9 @@ class StableDiffusionProcessingTxt2Img(StableDiffusionProcessing):
|
||||
noise = create_random_tensors(samples.shape[1:], seeds=seeds, subseeds=subseeds, subseed_strength=subseed_strength, p=self)
|
||||
x = None
|
||||
devices.torch_gc() # GC now before running the next img2img to prevent running out of memory
|
||||
# apply token merging optimizations from tomesd for high-res pass
|
||||
if (cmd_opts.token_merging or opts.token_merging) and (opts.token_merging_hr_only or opts.token_merging_ratio_hr != opts.token_merging_ratio):
|
||||
# case where user wants to use separate merge ratios
|
||||
if not opts.token_merging_hr_only:
|
||||
# clean patch done by first pass. (clobbering the first patch might be fine? this might be excessive)
|
||||
tomesd.remove_patch(self.sd_model)
|
||||
log.debug('Temporarily removed token merging optimizations in preparation for next pass')
|
||||
sd_models.apply_token_merging(sd_model=self.sd_model, hr=True)
|
||||
log.debug('Applied token merging for high-res pass')
|
||||
sd_models.apply_token_merging(self.sd_model, self.get_token_merging_ratio(for_hr=True))
|
||||
samples = self.sampler.sample_img2img(self, samples, noise, conditioning, unconditional_conditioning, steps=self.hr_second_pass_steps or self.steps, image_conditioning=image_conditioning)
|
||||
sd_models.apply_token_merging(self.sd_model, self.get_token_merging_ratio())
|
||||
self.is_hr_pass = False
|
||||
return samples
|
||||
|
||||
@@ -1081,3 +1076,6 @@ class StableDiffusionProcessingImg2Img(StableDiffusionProcessing):
|
||||
del x
|
||||
devices.torch_gc()
|
||||
return samples
|
||||
|
||||
def get_token_merging_ratio(self, for_hr=False):
|
||||
return self.token_merging_ratio or ("token_merging_ratio" in self.override_settings and opts.token_merging_ratio) or opts.token_merging_ratio_img2img or opts.token_merging_ratio
|
||||
|
||||
@@ -73,7 +73,7 @@ class UpscalerRealESRGAN(Upscaler):
|
||||
print(f"Unable to find model info: {path}")
|
||||
return None
|
||||
if info.local_data_path.startswith("http"):
|
||||
info.local_data_path = load_file_from_url(url=info.data_path, model_dir=self.model_path, progress=True)
|
||||
info.local_data_path = load_file_from_url(url=info.data_path, model_dir=self.model_download_path, progress=True)
|
||||
return info
|
||||
except Exception as e:
|
||||
errors.display(e, 'real-esrgan model list')
|
||||
|
||||
@@ -76,10 +76,6 @@ class AfterCFGCallbackParams:
|
||||
self.total_sampling_steps = total_sampling_steps
|
||||
"""Total number of sampling steps planned"""
|
||||
|
||||
self.output_altered = False
|
||||
"""A flag for CFGDenoiser indicating whether the output has been altered by the callback"""
|
||||
|
||||
|
||||
|
||||
class UiTrainTabParams:
|
||||
def __init__(self, txt2img_preview_params):
|
||||
|
||||
+17
-21
@@ -637,7 +637,6 @@ def reload_model_weights(sd_model=None, info=None, reuse_dict=False):
|
||||
timer.record("config")
|
||||
if sd_model is None or checkpoint_config != sd_model.used_config:
|
||||
del sd_model
|
||||
checkpoints_loaded.clear()
|
||||
if shared.backend == shared.Backend.ORIGINAL:
|
||||
load_model(checkpoint_info, already_loaded_state_dict=state_dict, timer=timer)
|
||||
else:
|
||||
@@ -676,26 +675,23 @@ def unload_model_weights(sd_model=None, _info=None):
|
||||
return sd_model
|
||||
|
||||
|
||||
def apply_token_merging(sd_model, hr: bool):
|
||||
def apply_token_merging(sd_model, token_merging_ratio):
|
||||
"""
|
||||
Applies speed and memory optimizations from tomesd.
|
||||
|
||||
Args:
|
||||
hr (bool): True if called in the context of a high-res pass
|
||||
"""
|
||||
|
||||
ratio = shared.opts.token_merging_ratio
|
||||
if hr:
|
||||
ratio = shared.opts.token_merging_ratio_hr
|
||||
|
||||
tomesd.apply_patch(
|
||||
sd_model,
|
||||
ratio=ratio,
|
||||
max_downsample=shared.opts.token_merging_maximum_down_sampling,
|
||||
sx=shared.opts.token_merging_stride_x,
|
||||
sy=shared.opts.token_merging_stride_y,
|
||||
use_rand=shared.opts.token_merging_random,
|
||||
merge_attn=shared.opts.token_merging_merge_attention,
|
||||
merge_crossattn=shared.opts.token_merging_merge_cross_attention,
|
||||
merge_mlp=shared.opts.token_merging_merge_mlp
|
||||
)
|
||||
current_token_merging_ratio = getattr(sd_model, 'applied_token_merged_ratio', 0)
|
||||
shared.log.debug(f'Appplying token merging: current={current_token_merging_ratio} target={token_merging_ratio}')
|
||||
if current_token_merging_ratio == token_merging_ratio:
|
||||
return
|
||||
if current_token_merging_ratio > 0:
|
||||
tomesd.remove_patch(sd_model)
|
||||
if token_merging_ratio > 0:
|
||||
tomesd.apply_patch(
|
||||
sd_model,
|
||||
ratio=token_merging_ratio,
|
||||
use_rand=False, # can cause issues with some samplers
|
||||
merge_attn=True,
|
||||
merge_crossattn=False,
|
||||
merge_mlp=False
|
||||
)
|
||||
sd_model.applied_token_merged_ratio = token_merging_ratio
|
||||
|
||||
@@ -26,7 +26,7 @@ approximation_indexes = {"Full VAE": 0, "Approximate NN": 1, "Approximate simple
|
||||
|
||||
|
||||
def single_sample_to_image(sample, approximation=None):
|
||||
if approximation is None:
|
||||
if approximation is None or approximation not in approximation_indexes.keys():
|
||||
approximation = approximation_indexes.get(opts.show_progress_type, 0)
|
||||
if approximation == 0:
|
||||
x_sample = processing.decode_first_stage(shared.sd_model, sample.unsqueeze(0))[0] * 0.5 + 0.5
|
||||
|
||||
+3
-9
@@ -93,17 +93,11 @@ def resolve_vae(checkpoint_file):
|
||||
return shared.cmd_opts.vae, 'forced'
|
||||
is_automatic = shared.opts.sd_vae in {"Automatic", "auto"} # "auto" for people with old config
|
||||
vae_near_checkpoint = find_vae_near_checkpoint(checkpoint_file)
|
||||
if vae_near_checkpoint is not None and (shared.opts.sd_vae_as_default):
|
||||
if vae_near_checkpoint is not None:
|
||||
return vae_near_checkpoint, 'near checkpoint'
|
||||
if is_automatic:
|
||||
for named_vae_location in [
|
||||
os.path.join(vae_path, os.path.splitext(os.path.basename(checkpoint_file))[0] + ".pt"),
|
||||
os.path.join(vae_path, os.path.splitext(os.path.basename(checkpoint_file))[0] + ".ckpt"),
|
||||
os.path.join(vae_path, os.path.splitext(os.path.basename(checkpoint_file))[0] + ".safetensors"),
|
||||
os.path.join(vae_path, os.path.splitext(os.path.basename(checkpoint_file))[0] + ".vae.pt"),
|
||||
os.path.join(vae_path, os.path.splitext(os.path.basename(checkpoint_file))[0] + ".vae.ckpt"),
|
||||
os.path.join(vae_path, os.path.splitext(os.path.basename(checkpoint_file))[0] + ".vae.safetensors"),
|
||||
]:
|
||||
basename = os.path.join(vae_path, os.path.splitext(os.path.basename(checkpoint_file))[0])
|
||||
for named_vae_location in [basename + ".pt", basename + ".ckpt", basename + ".safetensors", basename + ".vae.pt", basename + ".vae.ckpt", basename + ".vae.safetensors"]:
|
||||
if os.path.isfile(named_vae_location):
|
||||
return named_vae_location, 'in VAE dir'
|
||||
if shared.opts.sd_vae == "None":
|
||||
|
||||
+17
-31
@@ -293,20 +293,24 @@ options_templates.update(options_section(('sd', "Stable Diffusion"), {
|
||||
"sd_vae_checkpoint_cache": OptionInfo(0, "Number of cached VAE checkpoints", gr.Slider, {"minimum": 0, "maximum": 10, "step": 1}),
|
||||
"sd_vae": OptionInfo("Automatic", "Select VAE", gr.Dropdown, lambda: {"choices": shared_items.sd_vae_items()}, refresh=shared_items.refresh_vae_list),
|
||||
"sd_model_dict": OptionInfo('None', "Stable Diffusion checkpoint dict", gr.Dropdown, lambda: {"choices": ['None'] + list_checkpoint_tiles()}, refresh=refresh_checkpoints),
|
||||
"sd_vae_sliced_encode": OptionInfo(False, "Enable splitting of hires batch processing"),
|
||||
"stream_load": OptionInfo(False, "When loading models attempt stream loading optimized for slow or network storage"),
|
||||
"model_reuse_dict": OptionInfo(False, "When loading models attempt to reuse previous model dictionary"),
|
||||
"prompt_attention": OptionInfo("Full parser", "Prompt attention parser", gr.Radio, lambda: {"choices": ["Full parser", "Compel parser", "A1111 parser", "Fixed attention"] }),
|
||||
"prompt_mean_norm": OptionInfo(True, "Prompt attention mean normalization"),
|
||||
"comma_padding_backtrack": OptionInfo(20, "Prompt padding for long prompts", gr.Slider, {"minimum": 0, "maximum": 74, "step": 1 }),
|
||||
"sd_backend": OptionInfo("Original", "Stable Diffusion backend (experimental)", gr.Radio, lambda: {"choices": ["Original", "Diffusers"] }),
|
||||
}))
|
||||
|
||||
options_templates.update(options_section(('optimizations', "Optimizations"), {
|
||||
"cross_attention_optimization": OptionInfo(cross_attention_optimization_default, "Cross-attention optimization method", gr.Radio, lambda: {"choices": shared_items.list_crossattention() }),
|
||||
"cross_attention_options": OptionInfo([], "Cross-attention advanced options", gr.CheckboxGroup, lambda: {"choices": ['xFormers enable flash Attention', 'SDP disable memory attention']}),
|
||||
"sub_quad_q_chunk_size": OptionInfo(512, "Sub-quadratic cross-attention query chunk size", gr.Slider, {"minimum": 16, "maximum": 8192, "step": 8}),
|
||||
"sub_quad_kv_chunk_size": OptionInfo(512, "Sub-quadratic cross-attention kv chunk size", gr.Slider, {"minimum": 0, "maximum": 8192, "step": 8}),
|
||||
"sub_quad_chunk_threshold": OptionInfo(80, "Sub-quadratic cross-attention chunking threshold", gr.Slider, {"minimum": 0, "maximum": 100, "step": 1}),
|
||||
"prompt_attention": OptionInfo("Full parser", "Prompt attention parser", gr.Radio, lambda: {"choices": ["Full parser", "Compel parser", "A1111 parser", "Fixed attention"] }),
|
||||
"prompt_mean_norm": OptionInfo(True, "Prompt attention mean normalization"),
|
||||
"always_batch_cond_uncond": OptionInfo(False, "Disable conditional batching enabled on low memory systems"),
|
||||
"enable_quantization": OptionInfo(True, "Enable samplers quantization for sharper and cleaner results"),
|
||||
"comma_padding_backtrack": OptionInfo(20, "Increase coherency by padding from the last comma within n tokens when using more than 75 tokens", gr.Slider, {"minimum": 0, "maximum": 74, "step": 1 }),
|
||||
"sd_backend": OptionInfo("Original", "Stable Diffusion backend (experimental)", gr.Radio, lambda: {"choices": ["Original", "Diffusers"] }),
|
||||
"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}),
|
||||
"sd_vae_sliced_encode": OptionInfo(False, "Enable splitting of hires batch processing"),
|
||||
}))
|
||||
|
||||
options_templates.update(options_section(('cuda', "Compute Settings"), {
|
||||
@@ -444,6 +448,8 @@ options_templates.update(options_section(('sampler-params', "Sampler Settings"),
|
||||
"show_samplers": OptionInfo(["Euler a", "UniPC", "DDIM", "DPM++ 2M SDE", "DPM++ 2M SDE Karras", "DPM2 Karras", "DPM++ 2M Karras"], "Show samplers in user interface", gr.CheckboxGroup, lambda: {"choices": [x.name for x in list_samplers() if x.name != "PLMS"]}),
|
||||
"fallback_sampler": OptionInfo("Euler a", "Secondary sampler", gr.Dropdown, lambda: {"choices": ["None"] + [x.name for x in list_samplers()]}),
|
||||
"force_latent_sampler": OptionInfo("None", "Force latent upscaler sampler", gr.Dropdown, lambda: {"choices": ["None"] + [x.name for x in list_samplers()]}),
|
||||
"always_batch_cond_uncond": OptionInfo(False, "Disable conditional batching enabled on low memory systems"),
|
||||
"enable_quantization": OptionInfo(True, "Enable samplers quantization for sharper and cleaner results"),
|
||||
"eta_ancestral": OptionInfo(1.0, "Noise multiplier for ancestral samplers (eta)", gr.Slider, {"minimum": 0.0, "maximum": 1.0, "step": 0.01}),
|
||||
"eta_ddim": OptionInfo(0.0, "Noise multiplier for DDIM (eta)", gr.Slider, {"minimum": 0.0, "maximum": 1.0, "step": 0.01}),
|
||||
"ddim_discretize": OptionInfo('uniform', "DDIM discretize img2img", gr.Radio, {"choices": ['uniform', 'quad']}),
|
||||
@@ -496,6 +502,9 @@ options_templates.update(options_section(('interrogate', "Interrogate"), {
|
||||
}))
|
||||
|
||||
options_templates.update(options_section(('upscaling', "Upscaling"), {
|
||||
"face_restoration_model": OptionInfo("CodeFormer", "Face restoration model", gr.Radio, lambda: {"choices": [x.name() for x in face_restorers]}),
|
||||
"code_former_weight": OptionInfo(0.2, "CodeFormer weight parameter; 0 = maximum effect; 1 = minimum effect", gr.Slider, {"minimum": 0, "maximum": 1, "step": 0.01}),
|
||||
"face_restoration_unload": OptionInfo(False, "Move face restoration model from VRAM into RAM after processing"),
|
||||
"upscaler_for_img2img": OptionInfo("None", "Default upscaler for image resize operations", gr.Dropdown, lambda: {"choices": [x.name for x in sd_upscalers]}),
|
||||
"realesrgan_enabled_models": OptionInfo(["R-ESRGAN 4x+", "R-ESRGAN 4x+ Anime6B"], "Real-ESRGAN available models", gr.CheckboxGroup, lambda: {"choices": shared_items.realesrgan_models_names()}),
|
||||
"ESRGAN_tile": OptionInfo(192, "Tile size for ESRGAN upscalers (0 = no tiling)", gr.Slider, {"minimum": 0, "maximum": 512, "step": 16}),
|
||||
@@ -506,19 +515,10 @@ options_templates.update(options_section(('upscaling', "Upscaling"), {
|
||||
"dont_fix_second_order_samplers_schedule": OptionInfo(False, "Do not fix prompt schedule for second order samplers"),
|
||||
}))
|
||||
|
||||
options_templates.update(options_section(('lora', "Lora"), {
|
||||
options_templates.update(options_section(('extra_networks', "Extra Networks"), {
|
||||
"lyco_patch_lora": OptionInfo(False, "Use LyCoris handler for all Lora types", gr.Checkbox, { "visible": True }),
|
||||
"lora_disable": OptionInfo(False, "Disable built-in Lora handler", gr.Checkbox, { "visible": True }, onchange=lora_disable),
|
||||
"lora_functional": OptionInfo(False, "Use Kohya method for handling multiple Loras", gr.Checkbox, { "visible": True }),
|
||||
}))
|
||||
|
||||
options_templates.update(options_section(('face-restoration', "Face restoration"), {
|
||||
"face_restoration_model": OptionInfo("CodeFormer", "Face restoration model", gr.Radio, lambda: {"choices": [x.name() for x in face_restorers]}),
|
||||
"code_former_weight": OptionInfo(0.2, "CodeFormer weight parameter; 0 = maximum effect; 1 = minimum effect", gr.Slider, {"minimum": 0, "maximum": 1, "step": 0.01}),
|
||||
"face_restoration_unload": OptionInfo(False, "Move face restoration model from VRAM into RAM after processing"),
|
||||
}))
|
||||
|
||||
options_templates.update(options_section(('extra_networks', "Extra Networks"), {
|
||||
"extra_networks_default_view": OptionInfo("cards", "Default view for Extra Networks", gr.Dropdown, {"choices": ["cards", "thumbs"]}),
|
||||
"extra_networks_default_multiplier": OptionInfo(1.0, "Multiplier for extra networks", gr.Slider, {"minimum": 0.0, "maximum": 1.0, "step": 0.01}),
|
||||
"extra_networks_card_width": OptionInfo(0, "Card width for Extra Networks (px)"),
|
||||
@@ -527,20 +527,6 @@ options_templates.update(options_section(('extra_networks', "Extra Networks"), {
|
||||
"sd_hypernetwork": OptionInfo("None", "Add hypernetwork to prompt", gr.Dropdown, lambda: {"choices": ["None"] + list(hypernetworks.keys())}, refresh=reload_hypernetworks),
|
||||
}))
|
||||
|
||||
options_templates.update(options_section(('token_merging', 'Token Merging'), {
|
||||
"token_merging": OptionInfo(False, "Enable redundant token merging via tomesd for speed and memory improvements", gr.Checkbox),
|
||||
"token_merging_ratio": OptionInfo(0.5, "Token merging Ratio. Higher merging ratio = faster generation, smaller VRAM usage, lower quality", gr.Slider, {"minimum": 0, "maximum": 0.9, "step": 0.1}),
|
||||
"token_merging_hr_only": OptionInfo(True, "Apply only to high-res fix pass. Disabling can yield a ~20-35% speedup on contemporary resolutions", gr.Checkbox),
|
||||
"token_merging_ratio_hr": OptionInfo(0.5, "Merging Ratio for high-res pass", gr.Slider, {"minimum": 0, "maximum": 0.9, "step": 0.1}),
|
||||
"token_merging_random": OptionInfo(False, "Use random perturbations - Can improve outputs for certain samplers. For others, it may cause visual artifacting", gr.Checkbox),
|
||||
"token_merging_merge_attention": OptionInfo(True, "Merge attention (Recommend on)", gr.Checkbox),
|
||||
"token_merging_merge_cross_attention": OptionInfo(False, "Merge cross attention (Recommend off)", gr.Checkbox),
|
||||
"token_merging_merge_mlp": OptionInfo(False, "Merge mlp (Strongly recommend off)", gr.Checkbox),
|
||||
"token_merging_maximum_down_sampling": OptionInfo(1, "Maximum down sampling", gr.Radio, lambda: {"choices": [1, 2, 4, 8]}),
|
||||
"token_merging_stride_x": OptionInfo(2, "Stride - X", gr.Slider, {"minimum": 2, "maximum": 8, "step": 2}),
|
||||
"token_merging_stride_y": OptionInfo(2, "Stride - Y", gr.Slider, {"minimum": 2, "maximum": 8, "step": 2})
|
||||
}))
|
||||
|
||||
options_templates.update(options_section((None, "Hidden options"), {
|
||||
"disabled_extensions": OptionInfo([], "Disable these extensions"),
|
||||
"disable_all_extensions": OptionInfo("none", "Disable all extensions (preserves the list of disabled extensions)", gr.Radio, {"choices": ["none", "user", "all"]}),
|
||||
|
||||
+1
-1
@@ -50,7 +50,7 @@ class StyleDatabase:
|
||||
self.save_styles(self.path)
|
||||
|
||||
with open(self.path, "r", encoding="utf-8-sig", newline='') as file:
|
||||
reader = csv.DictReader(file)
|
||||
reader = csv.DictReader(file, skipinitialspace=True)
|
||||
for row in reader:
|
||||
try:
|
||||
prompt = row["prompt"] if "prompt" in row else row["text"]
|
||||
|
||||
@@ -16,16 +16,15 @@ from typing import Optional, NamedTuple, List
|
||||
import torch
|
||||
from torch import Tensor
|
||||
from torch.utils.checkpoint import checkpoint
|
||||
import numpy as np
|
||||
|
||||
|
||||
def narrow_trunc(
|
||||
input: Tensor, # pylint: disable=redefined-builtin
|
||||
tensor: Tensor,
|
||||
dim: int,
|
||||
start: int,
|
||||
length: int
|
||||
) -> Tensor:
|
||||
return torch.narrow(input, dim, start, length if input.shape[dim] >= start + length else input.shape[dim] - start)
|
||||
return torch.narrow(tensor, dim, start, length if tensor.shape[dim] >= start + length else tensor.shape[dim] - start)
|
||||
|
||||
|
||||
class AttnChunk(NamedTuple):
|
||||
@@ -81,7 +80,7 @@ def _query_chunk_attention(
|
||||
kv_chunk_size: int,
|
||||
) -> Tensor:
|
||||
_batch_x_heads, k_tokens, _k_channels_per_head = key.shape
|
||||
_, _, _v_channels_per_head = value.shape
|
||||
# _, _, v_channels_per_head = value.shape
|
||||
|
||||
def chunk_scanner(chunk_idx: int) -> AttnChunk:
|
||||
key_chunk = narrow_trunc(
|
||||
@@ -202,14 +201,11 @@ def efficient_dot_product_attention(
|
||||
value=value,
|
||||
)
|
||||
|
||||
res = torch.zeros_like(query)
|
||||
for i in range(math.ceil(q_tokens / query_chunk_size)):
|
||||
attn_scores = compute_query_chunk_attn(
|
||||
res = torch.cat([
|
||||
compute_query_chunk_attn(
|
||||
query=get_query_chunk(i * query_chunk_size),
|
||||
key=key,
|
||||
value=value,
|
||||
)
|
||||
|
||||
res[:, i * query_chunk_size:i * query_chunk_size + attn_scores.shape[1], :] = attn_scores
|
||||
|
||||
) for i in range(math.ceil(q_tokens / query_chunk_size))
|
||||
], dim=1)
|
||||
return res
|
||||
|
||||
@@ -122,7 +122,9 @@ def make_commit_link(commit_hash, remote, text=None):
|
||||
if text is None:
|
||||
text = commit_hash[:8]
|
||||
if remote.startswith("https://github.com/"):
|
||||
href = os.path.join(remote, "commit", commit_hash)
|
||||
if remote.endswith(".git"):
|
||||
remote = remote[:-4]
|
||||
href = remote + "/commit/" + commit_hash
|
||||
return f'<a href="{href}" target="_blank">{text}</a>'
|
||||
else:
|
||||
return text
|
||||
|
||||
@@ -175,7 +175,7 @@ class ExtraNetworksPage:
|
||||
"""
|
||||
Find a preview PNG for a given path (without extension) and call link_preview on it.
|
||||
"""
|
||||
preview_extensions = ["jpg", "png", "webp", "tiff", "jp2"]
|
||||
preview_extensions = ["jpg", "jpeg", "png", "webp", "tiff", "jp2"]
|
||||
potential_files = sum([[path + "." + ext, path + ".preview." + ext] for ext in preview_extensions], [])
|
||||
for file in potential_files:
|
||||
if os.path.isfile(file):
|
||||
|
||||
Reference in New Issue
Block a user