modular guiders and other stuff

Signed-off-by: Vladimir Mandic <mandic00@live.com>
This commit is contained in:
Vladimir Mandic
2026-08-30 11:51:19 +02:00
parent 7f430aae4e
commit 34d9d304db
32 changed files with 300 additions and 298 deletions
+9 -4
View File
@@ -20,12 +20,17 @@
*note*: this is a breaking change - if you had custom attention settings in previous releases, you will need to re-apply them in the new settings section
- new `sparse-attention` method that can be combined with other attention methods
to reduce memory usage and improve performance on large models
- **Modular Pipelines**
- *TODO*: see [Modular Pipelines docs](https://vladmandic.github.io/sdnext-docs/Modular-Pipelines) for details and usage instructions
- implement progress and preview
- intercept and profiling hooks
- full modular guidance
- on-demand convert standard model on-demand
- **Internal**
- modular pipelines intercept and profiling hooks
- modular pipelines convert standard model on-demand
- modular pipelines previews
- modular pipelines basic guidance
- attention mechanisms decision tree and apply method refactor
- **Fixes**
- unnecessary secondary prompt
- js fetch exception handling
## Update for 2026-08-26
+8 -14
View File
@@ -3,14 +3,18 @@
## Short-term
- MiniMax LoRA: native loader for MiniMax-H3: fl2va, ref2va, pruned, @CalamitousFelicitousness
- MiniMax TAESD: need to unpack latents, @vladmandic
- MiniMax: Create pre-quant for MiniMax-H3-Turbo
- MiniMax TAESD: unpack latents, @vladmandic
- MiniMax: Create pre-quants for MiniMax-H3-Turbo, MiniMax-H3-Pruned-Turbo
- Benchmark tool productize: @CalamitousFelicitousness
- Inpaint: https://discord.com/channels/1101998836328697867/1130536562422186044/1506850651035144322, @vladmandic
- Control tab verify overrides handling, @vladmandic
- LTX: Create pre-quant for LTX-2.5
- Modular guiders, @vladmandic
- ROCm: v10
- Modular: cache hooks, @vladmandic
- Modular: disable legacy PAG, etc., @vladmandic
## Issues
- Inpaint: https://discord.com/channels/1101998836328697867/1130536562422186044/1506850651035144322, @vladmandic
## Features
@@ -27,7 +31,6 @@
- Video upscaling: LTX-Upscaler
- Video capabilities to processing tab, add RIFE, upscaling (once available)
- Distraction-free UI mode with prompt-only, chat-based interface
- Revisit transformer caching for modular pipelines
- Video models: support finetunes
- Incorporate [prompting guides](https://github.com/CalamitousFelicitousness/ai-prompting-guides)
- Video models: use Networks/Reference instead of custom
@@ -49,15 +52,6 @@
- Unify *huggingface* and *diffusers* model folders
- JSON image metadata
### Modular
- Switch to modular pipelines
- Feature: Transformers unified cache handler
- [MagCache](https://github.com/huggingface/diffusers/pull/12744)
- [SmoothCache](https://github.com/huggingface/diffusers/issues/11135)
- [STG](https://github.com/huggingface/diffusers/blob/main/examples/community/README.md#spatiotemporal-skip-guidance)
- [TextKVCache](https://huggingface.co/NucleusAI/Nucleus-Image#quick-start), @vladmandic
## New models / Pipelines
TODO: Investigate which models are diffusers-compatible and prioritize!
+8 -13
View File
@@ -350,9 +350,8 @@ def control_run(state: str = '', # pylint: disable=keyword-arg-before-vararg
styles: list[str] | None = None,
steps: int = 20, sampler_index: int | None = None,
seed: int = -1, subseed: int = -1, subseed_strength: float = 0, seed_resize_from_h: int = -1, seed_resize_from_w: int = -1,
guidance_name: str = 'Default', guidance_scale: float = 6.0, guidance_rescale: float = 0.0, guidance_start: float = 0.0, guidance_stop: float = 1.0,
cfg_scale: float = 6.0, clip_skip: float = 1.0, cfg_image: float = 6.0, cfg_rescale: float = 0.7, cfg_true: float = 0.0, cfg_adaptive: float = 0.5, cfg_end: float = 1.0,
vae_type: str = 'Full', tiling: bool = False, hidiffusion: bool = False,
cfg_name: str = 'Default', cfg_scale: float = 6.0, cfg_image: float = 6.0, cfg_rescale: float = 0.0, cfg_start: float = 0.0, cfg_stop: float = 1.0, cfg_true: float = 0.0, cfg_adaptive: float = 0.5,
clip_skip: float = 1.0, vae_type: str = 'Full', tiling: bool = False, hidiffusion: bool = False,
detailer_enabled: bool = False, detailer_prompt: str = '', detailer_negative: str = '', detailer_steps: int = 10, detailer_strength: float = 0.3, detailer_resolution: int = 1024, detailer_classes: str = '',
hdr_mode: int = 0, hdr_brightness: float = 0, hdr_color: float = 0, hdr_sharpen: float = 0, hdr_clamp: bool = False, hdr_boundary: float = 4.0, hdr_threshold: float = 0.95,
hdr_maximize: bool = False, hdr_max_center: float = 0.6, hdr_max_boundary: float = 1.0, hdr_color_picker: str | None = None, hdr_tint_ratio: float = 0, hdr_apply_hires: bool = True,
@@ -465,21 +464,17 @@ def control_run(state: str = '', # pylint: disable=keyword-arg-before-vararg
seed_resize_from_w = seed_resize_from_w,
denoising_strength = denoising_strength,
skip_processing = skip_processing,
# modular guidance
guidance_name = guidance_name,
guidance_scale = guidance_scale,
guidance_rescale = guidance_rescale,
guidance_start = guidance_start,
guidance_stop = guidance_stop,
# legacy guidance
# guidance
cfg_name = cfg_name,
cfg_scale = cfg_scale,
cfg_end = cfg_end,
clip_skip = clip_skip,
cfg_image = cfg_image,
cfg_rescale = cfg_rescale,
cfg_start = cfg_start,
cfg_stop = cfg_stop,
cfg_true = cfg_true,
cfg_adaptive = cfg_adaptive,
# advanced
clip_skip = clip_skip,
vae_type = vae_type,
tiling = tiling,
hidiffusion = hidiffusion,
@@ -852,7 +847,7 @@ def control_run(state: str = '', # pylint: disable=keyword-arg-before-vararg
debug_log(f'Ready: {image_txt}')
html_txt = f'<p>Ready {image_txt}</p>' if image_txt != '' else ''
if len(info_txt) > 0:
if (info_txt is not None) and (len(info_txt) > 0):
html_txt = html_txt + infotext_to_html(info_txt[0])
result = (output_images, blended_image, html_txt, output_filename)
if is_generator:
+10 -13
View File
@@ -163,8 +163,7 @@ def img2img(id_task: str, state: str, mode: int,
vae_type, tiling, hidiffusion,
detailer_enabled, detailer_prompt, detailer_negative, detailer_steps, detailer_strength, detailer_resolution, detailer_classes,
n_iter, batch_size,
guidance_name, guidance_scale, guidance_rescale, guidance_start, guidance_stop,
cfg_scale, cfg_image, cfg_rescale, cfg_true, cfg_adaptive, cfg_end,
cfg_name, cfg_scale, cfg_image, cfg_rescale, cfg_start, cfg_stop, cfg_true, cfg_adaptive,
refiner_start,
clip_skip,
denoising_strength,
@@ -261,13 +260,6 @@ def img2img(id_task: str, state: str, mode: int,
batch_size=batch_size,
n_iter=n_iter,
steps=steps,
guidance_name=guidance_name,
guidance_scale=guidance_scale,
guidance_rescale=guidance_rescale,
guidance_start=guidance_start,
guidance_stop=guidance_stop,
cfg_scale=cfg_scale,
cfg_end=cfg_end,
clip_skip=clip_skip,
width=width,
height=height,
@@ -289,10 +281,6 @@ def img2img(id_task: str, state: str, mode: int,
resize_context=resize_context,
scale_by=scale_by,
denoising_strength=denoising_strength,
cfg_image=cfg_image,
cfg_rescale=cfg_rescale,
cfg_true=cfg_true,
cfg_adaptive=cfg_adaptive,
refiner_start=refiner_start,
inpaint_full_res=inpaint_full_res != 0,
inpaint_full_res_padding=inpaint_full_res_padding,
@@ -306,6 +294,15 @@ def img2img(id_task: str, state: str, mode: int,
grading_shadows_tint=grading_shadows_tint, grading_highlights_tint=grading_highlights_tint, grading_split_tone_balance=grading_split_tone_balance,
grading_vignette=grading_vignette, grading_grain=grading_grain,
grading_lut_file=grading_lut_file.name if grading_lut_file is not None else '', grading_lut_strength=grading_lut_strength,
# guidance
cfg_name=cfg_name,
cfg_scale=cfg_scale,
cfg_image=cfg_image,
cfg_rescale=cfg_rescale,
cfg_start=cfg_start,
cfg_stop=cfg_stop,
cfg_true=cfg_true,
cfg_adaptive=cfg_adaptive,
# refiner
enable_hr=enable_hr,
hr_denoising_strength=hr_denoising_strength,
+7 -1
View File
@@ -1,15 +1,20 @@
import os
import diffusers
from modules import shared, sd_hijack_modular
from modules import shared, sd_hijack_modular, sd_models
from modules.logger import log
debug = os.environ.get('SD_MODULAR_DEBUG', None) is not None
exclude = ['Krea2']
def get_modular_class(diffusion_pipeline: diffusers.DiffusionPipeline):
name = diffusion_pipeline.__class__.__name__
name = name.replace('Pipeline', '').replace('Img2Img', '').replace('Inpaint', '').replace('ImageToVideo', '')
if name in exclude:
if debug:
log.trace(f'Modular lookup: key={name} source={diffusion_pipeline.__class__.__name__} excluded')
return None
name = f'{name}AutoBlocks'
modular_cls = getattr(diffusers, name, None)
if debug:
@@ -46,6 +51,7 @@ def convert_to_modular(diffusion_pipeline: diffusers.DiffusionPipeline) -> diffu
except Exception as e:
log.error(f'Modular: {e}')
raise e
sd_models.copy_diffuser_options(modular_pipe, diffusion_pipeline)
sd_hijack_modular.install_state_hook(modular_pipe)
sd_hijack_modular.register_callbacks(modular_pipe)
return modular_pipe
+94 -72
View File
@@ -19,91 +19,113 @@ guiders = {
}
def set_guider(p: processing.StableDiffusionProcessing):
guidance_name = p.guidance_name or 'Default'
def get_layers(layer_str: str):
if not layer_str:
return []
try:
# layers can be comma separated, e.g. "7, 8, 9" or range "7-9" or mixed "7, 8-10, 12"
layers = []
for part in layer_str.split(','):
part = part.strip()
if '-' in part:
start, end = part.split('-')
layers.extend(range(int(start), int(end) + 1))
elif part.isdigit():
layers.append(int(part))
layers = sorted(set(layers)) # remove duplicates and sort
return layers
except Exception as e:
log.error(f'Guiders layers: {e}')
return []
def set_args(guidance_name: str):
args = {}
import modules.ui_guidance
inputs = modules.ui_guidance.get_modular_args()
# for k, v in inputs.items():
# log.trace(f'Guiders: arg={k} value={v}')
if guidance_name.startswith('Default'):
pass
if guidance_name.startswith('CFG:'):
pass
if guidance_name.startswith('Auto:'):
args['dropout'] = float(inputs.get('autoguidance_dropout', 1.0))
args['auto_guidance_layers'] = get_layers(inputs.get('autoguidance_layers', []))
if guidance_name.startswith('Zero:'):
args['zero_init_steps'] = int(inputs.get('zerostar_init_steps', 1))
if guidance_name.startswith('PAG:'):
args['perturbed_guidance_scale'] = float(inputs.get('pag_scale', 1.0))
args['perturbed_guidance_start'] = float(inputs.get('pag_start', 0.01))
args['perturbed_guidance_stop'] = float(inputs.get('pag_stop', 0.2))
args['perturbed_guidance_layers'] = get_layers(inputs.get('pag_layers', []))
if guidance_name.startswith('APG:'):
args['adaptive_projected_guidance_momentum'] = float(inputs.get('apg_momentum', None)) if inputs.get('apg_momentum', -1) >= 0 else None
args['adaptive_projected_guidance_rescale'] = float(inputs.get('apg_rescale', 15.0))
if guidance_name.startswith('SLG:'):
args['skip_layer_guidance_scale'] = float(inputs.get('slg_scale', 1.0))
args['skip_layer_guidance_start'] = float(inputs.get('slg_start', 0.01))
args['skip_layer_guidance_stop'] = float(inputs.get('slg_stop', 0.2))
args['skip_layer_guidance_layers'] = get_layers(inputs.get('slg_layers', []))
if guidance_name.startswith('SEG:'):
args['seg_guidance_scale'] = float(inputs.get('seg_scale', 3.0))
args['seg_blur_sigma'] = float(inputs.get('seg_blur_sigma', 9999999.0))
args['seg_blur_threshold_inf'] = float(inputs.get('seg_blur_threshold_inf', 9999.0))
args['seg_guidance_start'] = float(inputs.get('seg_start', 0.0))
args['seg_guidance_stop'] = float(inputs.get('seg_stop', 1.0))
args['seg_guidance_layers'] = get_layers(inputs.get('seg_layers', []))
if guidance_name.startswith('TCFG:'):
pass
if guidance_name.startswith('FDG:'):
args['guidance_scales'] = [float(x.strip()) for x in inputs.get('fdg_scales', '5.0').split(',')]
args['parallel_weights'] = float(inputs.get('fdg_weights', 1.0))
args['guidance_rescale_space'] = inputs.get('fdg_rescale_space', 'data')
log.trace(f'Guiders: args={args}')
return args
def set_guider(p: processing.StableDiffusionProcessing, phase: str | None = None):
guidance_name = p.cfg_name or 'Default'
if guidance_name not in guiders:
return
if guidance_name == 'Default':
if hasattr(shared.sd_model, 'default_guider'):
guider_info = shared.sd_model.default_guider
guider_cls = guider_info.type_hint if hasattr(guider_info, 'type_hint') else type(guider_info)
shared.sd_model.update_components(guider=guider_info)
elif hasattr(shared.sd_model, 'get_component_spec'):
guider_info = shared.sd_model.get_component_spec("guider")
guider_cls = guider_info.type_hint if hasattr(guider_info, 'type_hint') else type(guider_info)
shared.sd_model.default_guider = guider_info
elif hasattr(shared.sd_model, 'guider') and hasattr(shared.sd_model.guider, 'config'):
guider_info = shared.sd_model.guider
guider_cls = type(shared.sd_model.guider)
# shared.sd_model.default_guider = guider_info
else:
guider_info = None
guider_cls = None
if guider_info is not None and guider_cls is not None and guider_info.config is not None:
guider_args = {k: v for k, v in guider_info.config.items() if not k.startswith('_') and v is not None}
else:
guider_args = {}
log.info(f'Guider: name="{guidance_name}" cls={guider_cls.__name__ if guider_cls is not None else None} args={guider_args}')
return
if not hasattr(shared.sd_model, 'default_guider'): # store default guider
guider_info = shared.sd_model.get_component_spec("guider")
guider_cls = guider_info.type_hint if hasattr(guider_info, 'type_hint') else type(guider_info)
shared.sd_model.default_guider = guider_cls
if guidance_name == 'None':
shared.sd_model.update_components(guider=None) # breaks the pipeline
log.info(f'Guider: name="{guidance_name}"')
log.info(f'Pipeline: guidance="{guidance_name}"')
return
elif guidance_name == 'Default':
guider_cls = shared.sd_model.default_guider
else:
guider_info = guiders[guidance_name]
guider_cls = guider_info['cls']
guider_info = guiders[guidance_name]
guider_cls = guider_info['cls']
guider_args = set_args(guidance_name)
possible = inspect.signature(guider_cls.__init__).parameters if guider_cls is not None else []
if 'guidance_scale' in list(possible):
if (phase == 'hires' or phase == 'refine') and p.cfg_image >= 0.0:
guider_args['guidance_scale'] = float(p.cfg_image)
elif p.cfg_scale >= 0.0:
guider_args['guidance_scale'] = float(p.cfg_scale)
if p.cfg_rescale >= 0.0 and 'guidance_rescale' in list(possible):
guider_args['guidance_rescale'] = float(p.cfg_rescale)
if p.cfg_start >= 0.0 and 'start' in list(possible):
guider_args['start'] = float(p.cfg_start)
if p.cfg_stop >= 0.0 and 'stop' in list(possible):
guider_args['stop'] = float(p.cfg_stop)
guider_args = {}
possible = list(inspect.signature(guider_cls.__init__).parameters) if guider_cls is not None else []
if p.guidance_scale >= 0.0 and 'guidance_scale' in possible:
guider_args['guidance_scale'] = float(p.guidance_scale)
if p.guidance_rescale >= 0.0 and 'guidance_rescale' in possible:
guider_args['guidance_rescale'] = float(p.guidance_rescale)
if p.guidance_start >= 0.0 and 'start' in possible:
guider_args['start'] = float(p.guidance_start)
if p.guidance_stop >= 0.0 and 'stop' in possible:
guider_args['stop'] = float(p.guidance_stop)
"""
import modules.ui_guidance
for k, v in modules.ui_guidance.get_modular_args().items():
log.trace(f'Guiders: arg={k} value={v}')
"""
log.warning('Guiders: advanced parameters are not yet implemented') # TODO: guiders
"""
for k, v in guider_info['args'].items():
try:
if k is None:
pass
elif k.endswith('_layers') and isinstance(v, str):
guider_args[k] = [int(x.strip()) for x in v.split(',') if x.strip().isdigit()]
elif k.endswith('_config'):
# if lsc_enabled
# guider_args[k] = diffusers.LayerSkipConfig(...)
pass
elif isinstance(v, list) and len(v) > 0:
guider_args[k] = v
elif isinstance(v, int) and (v >= 0):
guider_args[k] = int(v)
elif isinstance(v, float) and (v >= 0.0):
guider_args[k] = float(v)
elif isinstance(v, str) and (len(v) > 0):
guider_args[k] = v
except Exception as e:
log.error(f'Guiders: arg={k} value={v} error={e}')
errors.display(e, 'Guiders')
# guider_args.update(guider_info['args'])
"""
if guider_cls is not None:
try:
guider_instance: diffusers.BaseGuidance = guider_cls(**guider_args)
log.info(f'Guider: name="{guidance_name}" cls={guider_cls.__name__} args={guider_args}')
log.info(f'Pipeline: guidance="{guidance_name}" cls={guider_cls.__name__} args={guider_args}')
shared.sd_model.update_components(guider=guider_instance)
except Exception as e:
log.error(f'Guider: name="{guidance_name}" cls={guider_cls.__name__} args={guider_args} {e}')
log.error(f'Pipeline: guidance="{guidance_name}" cls={guider_cls.__name__} args={guider_args} {e}')
errors.display(e, 'Guiders')
return
else:
log.warning(f'Guider: name="{guidance_name}" cls=None args={guider_args}')
log.warning(f'Pipeline: guidance="{guidance_name}" cls=None args={guider_args}')
+11 -2
View File
@@ -53,9 +53,14 @@ class Processed:
self.height = p.height if hasattr(p, 'height') else (self.images[0].height if len(self.images) > 0 else 0)
self.sampler_name = p.sampler_name or ''
self.cfg_name = p.cfg_name if (p.cfg_name is not None and p.cfg_name != 'Default') else None
self.cfg_scale = p.cfg_scale if (p.cfg_scale is not None and p.cfg_scale > -1) else None
self.cfg_end = p.cfg_end if p.cfg_end < 1 else None
self.cfg_rescale = p.cfg_rescale if (p.cfg_rescale is not None and p.cfg_rescale > -1) else None
self.cfg_image = p.cfg_image if (p.cfg_image is not None and p.cfg_image > -1) else None
self.cfg_start = p.cfg_start if p.cfg_start > 0 else None
self.cfg_stop = p.cfg_stop if p.cfg_stop < 1 else None
self.steps = p.steps or 0
self.batch_size = max(1, p.batch_size)
self.denoising_strength = p.denoising_strength
@@ -103,8 +108,12 @@ class Processed:
"width": self.width,
"height": self.height,
"sampler_name": self.sampler_name,
"cfg_name": self.cfg_name,
"cfg_scale": self.cfg_scale,
"cfg_end": self.cfg_end,
"cfg_rescale": self.cfg_rescale,
"cfg_image": self.cfg_image,
"cfg_start": self.cfg_start,
"cfg_stop": self.cfg_stop,
"steps": self.steps,
"batch_size": self.batch_size,
"detailer": self.detailer,
+7 -4
View File
@@ -31,6 +31,9 @@ def task_modular_kwargs(p, model):
if len(getattr(p, 'init_images', [])) > 0:
task_args['image'] = p.init_images
task_args['strength'] = p.denoising_strength
if (shared.sd_model_type == 'sdxl') and hasattr(model, 'register_to_config') and (model_cls not in sd_models.i2i_pipes):
model.register_to_config(requires_aesthetics_score = False)
mask_image = p.task_args.get('image_mask', None) or getattr(p, 'image_mask', None) or getattr(p, 'mask', None)
if mask_image is not None:
task_args['mask_image'] = mask_image
@@ -68,8 +71,8 @@ def task_specific_kwargs(p, model):
'width': width,
'height': height,
}
elif (task_type == sd_models.DiffusersTaskType.IMAGE_2_IMAGE or is_img2img_model) and len(getattr(p, 'init_images', [])) > 0:
if shared.sd_model_type == 'sdxl' and hasattr(model, 'register_to_config'):
elif (task_type == sd_models.DiffusersTaskType.IMAGE_2_IMAGE or task_type == sd_models.DiffusersTaskType.MODULAR or is_img2img_model) and (len(getattr(p, 'init_images', [])) > 0):
if (shared.sd_model_type == 'sdxl') and hasattr(model, 'register_to_config'):
if model_cls in sd_models.i2i_pipes:
pass
else:
@@ -115,7 +118,7 @@ def task_specific_kwargs(p, model):
'image': p.init_images,
'strength': p.denoising_strength,
}
elif (task_type == sd_models.DiffusersTaskType.INPAINTING or is_img2img_model) and len(getattr(p, 'init_images', [])) > 0:
elif (task_type == sd_models.DiffusersTaskType.INPAINTING or task_type == sd_models.DiffusersTaskType.MODULAR or is_img2img_model) and len(getattr(p, 'init_images', [])) > 0:
if shared.sd_model_type == 'sdxl' and hasattr(model, 'register_to_config'):
if model_cls in [sd_models.i2i_pipes]:
pass
@@ -255,7 +258,7 @@ def set_pipeline_args(p, model, prompts:list, negative_prompts:list, prompts_2:l
possible = get_params(model)
log.debug(f'Pipeline: cls={cls} possible={possible}')
debug_log(f'Pipeline: cls={cls} possible={possible}')
steps = kwargs.get("num_inference_steps", None) or len(getattr(p, 'timesteps', ['1']))
clip_skip = kwargs.pop("clip_skip", 1)
+3 -3
View File
@@ -120,11 +120,11 @@ def diffusers_callback(pipe, step: int = 0, timestep: int = 0, kwargs: dict | No
if step == 0:
pipe._cfg_end_applied = False # pylint: disable=protected-access
cfg_end = getattr(p, "cfg_end", 1.0) or 1.0
cfg_stop = getattr(p, "cfg_stop", None) or getattr(p, "cfg_end", None) or 1.0
total_steps = getattr(pipe, "num_timesteps", 0)
target_step = int(total_steps * cfg_end) if total_steps else 0
target_step = int(total_steps * cfg_stop) if total_steps else 0
if (cfg_end < 1.0) and not getattr(pipe, "_cfg_end_applied", False) and (step >= target_step):
if (cfg_stop < 1.0) and not getattr(pipe, "_cfg_end_applied", False) and (step >= target_step):
pipe._cfg_end_applied = True # pylint: disable=protected-access
if "PAG" in shared.sd_model.__class__.__name__:
pipe._guidance_scale = 1.001 if pipe._guidance_scale > 1 else pipe._guidance_scale # pylint: disable=protected-access
+13 -18
View File
@@ -45,15 +45,11 @@ class StableDiffusionProcessing:
sampler_name: str | None = None,
hr_sampler_name: str | None = None,
eta: float | None = None,
# modular guidance
guidance_name: str = 'Default',
guidance_scale: float = 6.0,
guidance_rescale: float = 0.0,
guidance_start: float = 0.0,
guidance_stop: float = 1.0,
# legacy guidance
# guidance
cfg_name: str = 'Default',
cfg_scale: float = 6.0,
cfg_end: float = 1,
cfg_start: float = 0.0,
cfg_stop: float = 1,
cfg_rescale: float = 0.0,
cfg_true: float = 0.0,
cfg_adaptive: float = 0.5,
@@ -457,16 +453,6 @@ class StableDiffusionProcessing:
self.do_not_save_grid = do_not_save_grid
self.override_settings_restore_afterwards = override_settings_restore_afterwards
self.eta = eta
self.guidance_name = guidance_name
self.guidance_scale = guidance_scale
self.guidance_rescale = guidance_rescale
self.guidance_start = guidance_start
self.guidance_stop = guidance_stop
self.cfg_scale = cfg_scale
self.cfg_end = cfg_end
self.cfg_rescale = cfg_rescale
self.cfg_true = cfg_true
self.cfg_adaptive = cfg_adaptive
self.selected_scale_tab = selected_scale_tab
self.mask_for_overlay = mask_for_overlay
self.paste_to = paste_to
@@ -510,6 +496,15 @@ class StableDiffusionProcessing:
log.error(f'Override: {override_settings} {e}')
self.override_settings = {}
# guidance
self.cfg_name = cfg_name
self.cfg_scale = cfg_scale
self.cfg_start = cfg_start
self.cfg_stop = cfg_stop
self.cfg_rescale = cfg_rescale
self.cfg_true = cfg_true
self.cfg_adaptive = cfg_adaptive
# scheduler/noise overrides
self.schedulers_prediction_type = schedulers_prediction_type
self.schedulers_beta_schedule = schedulers_beta_schedule
+11 -16
View File
@@ -3,8 +3,9 @@ import os
import time
import numpy as np
import torch
import diffusers
from PIL import Image
from modules import shared, processing, sd_models, errors, sd_hijack_hypertile, processing_vae, sd_models_compile, timer, modelstats, extra_networks, attention
from modules import shared, processing, sd_models, errors, sd_hijack_hypertile, processing_vae, sd_models_compile, timer, modelstats, extra_networks, attention, modular
from modules.logger import log
from modules.processing_helpers import resize_hires, calculate_base_steps, calculate_hires_steps, calculate_refiner_steps, save_intermediate, update_sampler, is_txt2img, is_refiner_enabled, get_job_name
from modules.processing_args import set_pipeline_args
@@ -14,6 +15,7 @@ from modules.image import convert
debug = os.environ.get('SD_DIFFUSERS_DEBUG', None) is not None
modular_debug = os.environ.get('SD_MODULAR_DEBUG', None) is not None
output_type = 'np' if os.environ.get('SD_VAE_DEFAULT', None) is not None else 'latent'
last_p = None
orig_pipeline = shared.sd_model
@@ -68,12 +70,12 @@ def restore_state(p: processing.StableDiffusionProcessing):
return p
def process_pre(p: processing.StableDiffusionProcessing):
def process_pre(p: processing.StableDiffusionProcessing, phase: str | None = None):
from modules import ipadapter, sd_hijack_freeu, para_attention, teacache, hidiffusion, ras, pag, cfgzero, transformer_cache, token_merge, linfusion, cachedit
if shared.sd_model is None:
log.warning('Processing modifiers: model not loaded')
return
log.info('Processing modifiers: apply')
log.info(f'Processing modifiers: phase={phase} apply')
try:
# apply-with-unapply
# sd_hijack_compile.install()
@@ -97,19 +99,10 @@ def process_pre(p: processing.StableDiffusionProcessing):
errors.display(e, 'apply')
shared.sd_model = sd_models.apply_balanced_offload(shared.sd_model)
# if hasattr(shared.sd_model, 'unet'):
# sd_models.move_model(shared.sd_model.unet, devices.device)
# if hasattr(shared.sd_model, 'transformer'):
# sd_models.move_model(shared.sd_model.transformer, devices.device)
from modules import modular
if modular.is_compatible(shared.sd_model):
modular_pipe = modular.convert_to_modular(shared.sd_model)
if modular_pipe is not None:
shared.sd_model = modular_pipe
if modular.is_guider(shared.sd_model):
from modules import modular_guiders
modular_guiders.set_guider(p)
modular_guiders.set_guider(p, phase)
timer.process.record('pre')
@@ -143,7 +136,7 @@ def process_base(p: processing.StableDiffusionProcessing):
shared.sd_model = update_pipeline(shared.sd_model, p)
update_sampler(p, shared.sd_model)
timer.process.record('prepare')
process_pre(p)
process_pre(p, 'base')
sched_eta = p.scheduler_eta if p.scheduler_eta is not None else shared.opts.scheduler_eta
desc = 'Base'
if 'detailer' in p.ops:
@@ -186,6 +179,8 @@ def process_base(p: processing.StableDiffusionProcessing):
taskid = shared.state.begin('Inference')
output = shared.sd_model(**base_args)
shared.state.end(taskid)
if isinstance(output, diffusers.modular_pipelines.PipelineState) and modular_debug:
log.trace(f'Pipeline: output={output}')
if isinstance(output, dict):
output = SimpleNamespace(**output)
if isinstance(output, list):
@@ -194,7 +189,7 @@ def process_base(p: processing.StableDiffusionProcessing):
output = SimpleNamespace(images=[output])
if not hasattr(output, 'frames') and hasattr(output, 'videos'):
output.frames = output.videos # modular video pipelines emit videos, not frames
if hasattr(output, 'image'):
if hasattr(output, 'image') and getattr(output, 'images', None) is None: # for modular output.image may be input and output.images may be output so we dont want to overwrite output
output.images = output.image
if hasattr(output, 'images'):
shared.history.add(output.images, info=processing.create_infotext(p), ops=p.ops)
@@ -303,7 +298,7 @@ def process_hires(p: processing.StableDiffusionProcessing, output):
orig_denoise = p.denoising_strength
p.denoising_strength = strength
orig_image = p.task_args.pop('image', None) # remove image override from hires
process_pre(p)
process_pre(p, 'hires')
prompts = p.prompts
reset_prompts = False
+3 -1
View File
@@ -59,9 +59,11 @@ def create_infotext(p: StableDiffusionProcessing, all_prompts=None, all_seeds=No
"Scheduler": shared.sd_model.scheduler.__class__.__name__ if getattr(shared.sd_model, 'scheduler', None) is not None else None,
"Seed": all_seeds[index],
"Seed resize from": None if p.seed_resize_from_w <= 0 or p.seed_resize_from_h <= 0 else f"{p.seed_resize_from_w}x{p.seed_resize_from_h}",
"CFG name": p.cfg_name if p.cfg_name != 'Default' else None,
"CFG scale": p.cfg_scale if p.cfg_scale > -1 else None,
"CFG rescale": p.cfg_rescale if p.cfg_rescale > -1 else None,
"CFG end": p.cfg_end if p.cfg_end < 1.0 else None,
"CFG start": p.cfg_start if p.cfg_start > 0.0 else None,
"CFG stop": p.cfg_stop if p.cfg_stop < 1.0 else None,
"CFG true": p.cfg_true if p.cfg_true > 0 else None,
"CFG adaptive": p.cfg_adaptive if p.cfg_adaptive != 0.5 else None,
"CLiP-skip": p.clip_skip if p.clip_skip > 1 else None,
+6 -4
View File
@@ -68,11 +68,13 @@ def set_fallback_prompt(args: dict, possible: list[str], prompts, negative_promp
debug_log(f'Prompt fallback: negative_prompt={negative_prompts}')
args['negative_prompt'] = negative_prompts
if ('prompt_2' in possible) and ('prompt_2' not in args) and (prompts_2 is not None) and len(prompts_2) > 0:
debug_log(f'Prompt fallback: prompt_2={prompts_2}')
args['prompt_2'] = prompts_2
if (prompts_2 != prompts) and (prompts_2 != args.get('prompt', None)):
debug_log(f'Prompt fallback: prompt_2={prompts_2}')
args['prompt_2'] = prompts_2
if ('negative_prompt_2' in possible) and ('negative_prompt_2' not in args) and (negative_prompts_2 is not None) and len(negative_prompts_2) > 0:
debug_log(f'Prompt fallback: negative_prompt_2={negative_prompts_2}')
args['negative_prompt_2'] = negative_prompts_2
if (negative_prompts_2 != negative_prompts) and (negative_prompts_2 != args.get('negative_prompt', None)):
debug_log(f'Prompt fallback: negative_prompt_2={negative_prompts_2}')
args['negative_prompt_2'] = negative_prompts_2
return args
+1 -1
View File
@@ -5,9 +5,9 @@ import collections
import zipfile
import re
import _codecs
import torch
import numpy as np
import _codecs
# PyTorch 1.13 and later have _TypedStorage renamed to TypedStorage
TypedStorage = torch.storage.TypedStorage if hasattr(torch.storage, 'TypedStorage') else torch.storage._TypedStorage # pylint: disable=protected-access
+7 -1
View File
@@ -1034,6 +1034,12 @@ def load_diffuser(checkpoint_info: CheckpointInfo | None = None, op='model', rev
if debug_load:
log.trace(f'Model components: {list(get_signature(sd_model).values())}')
from modules import modular
if modular.is_compatible(shared.sd_model):
modular_pipe = modular.convert_to_modular(shared.sd_model)
if modular_pipe is not None:
shared.sd_model = modular_pipe
from modules import textual_inversion
sd_model.embedding_db = textual_inversion.EmbeddingDatabase()
sd_model.embedding_db.add_embedding_dir(shared.opts.embeddings_dir)
@@ -1244,7 +1250,7 @@ def switch_pipe(cls: type[diffusers.DiffusionPipeline] | str, pipeline: diffuser
def clean_diffuser_pipe(pipe):
if pipe is not None and shared.sd_model_type == 'sdxl' and hasattr(pipe, 'config') and 'requires_aesthetics_score' in pipe.config and hasattr(pipe, '_internal_dict'):
if (pipe is not None) and (shared.sd_model_type == 'sdxl') and hasattr(pipe, 'config') and ('requires_aesthetics_score' in pipe.config) and hasattr(pipe, '_internal_dict'):
debug_process(f'Pipeline clean: {pipe.__class__.__name__}')
# diffusers adds requires_aesthetics_score with img2img and complains if requires_aesthetics_score exist in txt2img
internal_dict = dict(pipe._internal_dict) # pylint: disable=protected-access
+2
View File
@@ -337,6 +337,8 @@ class TAEHV(nn.Module):
def decode(self, x, parallel=True, show_progress_bar=False, return_dict=False): # pylint: disable=unused-argument
"""Decode a sequence of frames."""
if x.ndim == 4:
x = x.unsqueeze(0)
return self.decode_video(x, parallel=False, show_progress_bar=False)
def encode(self, x, parallel=True, show_progress_bar=False, return_dict=False): # pylint: disable=unused-argument
+4 -8
View File
@@ -16,8 +16,7 @@ def txt2img(id_task, state,
vae_type, tiling, hidiffusion,
detailer_enabled, detailer_prompt, detailer_negative, detailer_steps, detailer_strength, detailer_resolution, detailer_classes,
n_iter, batch_size,
guidance_name, guidance_scale, guidance_rescale, guidance_start, guidance_stop,
cfg_scale, cfg_image, cfg_rescale, cfg_true, cfg_adaptive, cfg_end,
cfg_name, cfg_scale, cfg_image, cfg_rescale, cfg_start, cfg_stop, cfg_true, cfg_adaptive,
clip_skip,
seed, subseed, subseed_strength, seed_resize_from_h, seed_resize_from_w,
height, width,
@@ -62,17 +61,14 @@ def txt2img(id_task, state,
batch_size=batch_size,
n_iter=n_iter,
steps=steps,
guidance_name=guidance_name,
guidance_scale=guidance_scale,
guidance_rescale=guidance_rescale,
guidance_start=guidance_start,
guidance_stop=guidance_stop,
cfg_name=cfg_name,
cfg_scale=cfg_scale,
cfg_image=cfg_image,
cfg_rescale=cfg_rescale,
cfg_start=cfg_start,
cfg_stop=cfg_stop,
cfg_true=cfg_true,
cfg_adaptive=cfg_adaptive,
cfg_end=cfg_end,
clip_skip=clip_skip,
width=width,
height=height,
+10 -11
View File
@@ -201,7 +201,7 @@ def create_ui(_blocks: gr.Blocks=None):
mask_controls = masking.create_segment_ui()
guidance_name, guidance_scale, guidance_rescale, guidance_start, guidance_stop, cfg_scale, cfg_image, cfg_rescale, cfg_true, cfg_adaptive, cfg_end = ui_guidance.create_guidance_inputs('control')
cfg_name, cfg_scale, cfg_image, cfg_rescale, cfg_start, cfg_stop, cfg_true, cfg_adaptive = ui_guidance.create_guidance_inputs('control')
vae_type, tiling, hidiffusion, clip_skip = ui_sections.create_advanced_inputs('control')
grading_brightness, grading_contrast, grading_saturation, grading_hue, grading_gamma, grading_sharpness, grading_color_temp, grading_shadows, grading_midtones, grading_highlights, grading_clahe_clip, grading_clahe_grid, grading_shadows_tint, grading_highlights_tint, grading_split_tone_balance, grading_vignette, grading_grain, grading_lut_file, grading_lut_strength = ui_sections.create_color_inputs('control')
hdr_mode, hdr_brightness, hdr_color, hdr_sharpen, hdr_clamp, hdr_boundary, hdr_threshold, hdr_maximize, hdr_max_center, hdr_max_boundary, hdr_color_picker, hdr_tint_ratio, hdr_apply_hires = ui_sections.create_latent_inputs('control')
@@ -316,8 +316,8 @@ def create_ui(_blocks: gr.Blocks=None):
prompt, negative, styles,
steps, sampler_index,
seed, subseed, subseed_strength, seed_resize_from_h, seed_resize_from_w,
guidance_name, guidance_scale, guidance_rescale, guidance_start, guidance_stop,
cfg_scale, clip_skip, cfg_image, cfg_rescale, cfg_true, cfg_adaptive, cfg_end, vae_type, tiling, hidiffusion,
cfg_name, cfg_scale, cfg_image, cfg_rescale, cfg_start, cfg_stop, cfg_true, cfg_adaptive,
clip_skip, vae_type, tiling, hidiffusion,
detailer_enabled, detailer_prompt, detailer_negative, detailer_steps, detailer_strength, detailer_resolution, detailer_classes,
hdr_mode, hdr_brightness, hdr_color, hdr_sharpen, hdr_clamp, hdr_boundary, hdr_threshold, hdr_maximize, hdr_max_center, hdr_max_boundary, hdr_color_picker, hdr_tint_ratio, hdr_apply_hires,
grading_brightness, grading_contrast, grading_saturation, grading_hue, grading_gamma, grading_sharpness, grading_color_temp,
@@ -411,18 +411,17 @@ def create_ui(_blocks: gr.Blocks=None):
(mask_controls[5], "Mask dilate"),
(mask_controls[6], "Mask auto"),
# guidance
(guidance_name, "Guidance"),
(guidance_scale, "Guidance scale"),
(guidance_rescale, "Guidance rescale"),
(guidance_start, "Guidance start"),
(guidance_stop, "Guidance stop"),
# advanced
(cfg_name, "CFG name"),
(cfg_scale, "CFG scale"),
(cfg_end, "CFG end"),
(clip_skip, "CLiP-skip"),
(cfg_start, "CFG start"),
(cfg_stop, "CFG stop"),
(cfg_stop, "CFG end"),
(cfg_image, "CFG image"),
(cfg_image, "Image CFG scale"),
(cfg_image, "Hires CFG scale"),
(cfg_rescale, "CFG rescale"),
# other
(clip_skip, "CLiP-skip"),
(vae_type, "VAE type"),
(tiling, "Tiling"),
(hidiffusion, "HiDiffusion"),
+40 -63
View File
@@ -17,74 +17,54 @@ def create_guidance_inputs(tab):
with gr.Group():
with gr.Row(elem_id=f"{tab}_guider_row", elem_classes=['flexbox'], visible=shared.opts.model_modular_enable):
guidance_name = gr.Dropdown(choices=guiders.keys(), value='Default', label='Guider', elem_id=f"{tab}_guider")
guidance_btn = ui_components.ToolButton(value=ui_symbols.info, elem_id=f"{tab}_guider_docs")
guidance_btn.click(fn=None, _js='getGuidanceDocs', inputs=[guidance_name], outputs=[])
cfg_name = gr.Dropdown(choices=guiders.keys(), value='Default', label='Guider', elem_id=f"{tab}_guider")
cfg_name_btn = ui_components.ToolButton(value=ui_symbols.info, elem_id=f"{tab}_guider_docs")
cfg_name_btn.click(fn=None, _js='getGuidanceDocs', inputs=[cfg_name], outputs=[])
base_group = gr.Group(visible=False) # default inherits from model
base_group = gr.Group()
with base_group:
with gr.Row(visible=shared.opts.model_modular_enable):
guidance_scale = gr.Slider(minimum=-1.0, maximum=30.0, step=0.1, label='Guidance scale', value=-1.0, elem_id=f"{tab}_guidance_scale")
guidance_rescale = gr.Slider(minimum=-1.0, maximum=1.0, step=0.05, label='Guidance rescale', value=-1.0, elem_id=f"{tab}_guidance_rescale")
with gr.Row(visible=shared.opts.model_modular_enable):
guidance_start = gr.Slider(minimum=0.0, maximum=1.0, step=0.05, label='Guidance start', value=0.0, elem_id=f"{tab}_guidance_start")
guidance_stop = gr.Slider(minimum=0.0, maximum=1.0, step=0.1, label='Guidance stop', value=1.0, elem_id=f"{tab}_guidance_stop")
guidance_args = [guidance_name, guidance_scale, guidance_rescale, guidance_start, guidance_stop]
lsc_group = gr.Accordion(open=False, label='Layer skip guidance', elem_classes=["small-accordion"], visible=shared.opts.model_modular_enable)
with lsc_group:
with gr.Row():
guidance_lsc_enabled = gr.Checkbox(label='Enable LayerSkipConfig', value=False)
guidance_lsc_label = gr.Label(value='LSC: LayerSkipConfig', elem_id=f"{tab}_lsc_label", visible=False)
guidance_lsc_btn = ui_components.ToolButton(value=ui_symbols.info, elem_id=f"{tab}_lsc_docs", elem_classes=["guidance-docs"])
guidance_lsc_btn.click(fn=None, _js='getGuidanceDocs', inputs=[guidance_lsc_label], outputs=[])
cfg_scale = gr.Slider(minimum=-1.0, maximum=30.0, step=0.1, label='Guidance scale', value=-1.0, elem_id=f"{tab}_guidance_scale")
cfg_image = gr.Slider(minimum=-1.0, maximum=30.0, step=0.1, label='Guidance image', value=-1.0, elem_id=f"{tab}_guidance_image")
with gr.Row():
guidance_lsc_indices = gr.Textbox(label='LSC layer indices', value='1, 2, 3', placeholder='Comma-separated layer indices to skip')
cfg_rescale = gr.Slider(minimum=-1.0, maximum=1.0, step=0.05, label='Guidance rescale', value=-1.0, elem_id=f"{tab}_guidance_rescale")
with gr.Row():
guidance_lsc_fqn = gr.Textbox(label='LSC fully qualified name', value='transformer_blocks', placeholder='Fully qualified name of the layer stack')
with gr.Row():
guidance_lsc_skip_attention = gr.Checkbox(label='LSC skip attention blocks', value=True)
guidance_lsc_skip_ff = gr.Checkbox(label='LSC skip feed-forward blocks', value=True)
guidance_lsc_skip_attention_scores = gr.Checkbox(label='LSC skip attention scores', value=False)
with gr.Row():
guidance_lsc_dropout = gr.Slider(minimum=0.0, maximum=1.0, step=0.05, label='LSC dropout rate', value=1.0)
lsc_args = [guidance_lsc_enabled, guidance_lsc_indices, guidance_lsc_fqn, guidance_lsc_skip_attention, guidance_lsc_skip_ff, guidance_lsc_skip_attention_scores, guidance_lsc_dropout]
cfg_start = gr.Slider(minimum=0.0, maximum=1.0, step=0.05, label='Guidance start', value=0.0, elem_id=f"{tab}_guidance_start")
cfg_stop = gr.Slider(minimum=0.0, maximum=1.0, step=0.1, label='Guidance stop', value=1.0, elem_id=f"{tab}_guidance_stop")
args_base = [cfg_name, cfg_scale, cfg_image, cfg_rescale, cfg_start, cfg_stop]
auto_group = gr.Accordion(open=True, label='Advanced guidance params', elem_classes=["small-accordion"], visible=False)
with auto_group:
guidance_auto_dropout = gr.Slider(minimum=0.0, maximum=1.0, step=0.05, label='AutoGuidance dropout', value=0.1)
guidance_auto_layers = gr.Textbox(label='AutoGuidance layers', value='7, 8, 9', placeholder='Comma-separated layer indices, e.g. 7,8,9')
guidance_auto_config = gr.Dropdown(choices=[None, 'config1', 'config2'], value=None, label='AutoGuidance config')
guidance_auto_args = [guidance_auto_dropout, guidance_auto_layers, guidance_auto_config]
guidance_auto_dropout = gr.Slider(minimum=0.0, maximum=1.0, step=0.05, label='AutoGuidance dropout', value=1.0)
guidance_auto_layers = gr.Textbox(label='AutoGuidance layers', value='', placeholder='layer indices, e.g. 7,8,9 or ranges, e.g. 7-9')
args_auto = [guidance_auto_dropout, guidance_auto_layers]
zero_group = gr.Accordion(open=True, label='Advanced guidance params', elem_classes=["small-accordion"], visible=False)
with zero_group:
guidance_zero_init_steps = gr.Slider(minimum=0, maximum=10, step=1, label='ZeroStar init steps', value=1)
guidance_zero_args = [guidance_zero_init_steps]
args_zero = [guidance_zero_init_steps]
pag_group = gr.Accordion(open=True, label='Advanced guidance params', elem_classes=["small-accordion"], visible=False)
with pag_group:
guidance_cfg_true = gr.Slider(minimum=0.0, maximum=30.0, step=0.05, label='PAG scale', value=2.8)
guidance_pag_scale = gr.Slider(minimum=0.0, maximum=30.0, step=0.05, label='PAG scale', value=7.5)
guidance_pag_start = gr.Slider(minimum=0.0, maximum=1.0, step=0.01, label='PAG start', value=0.01)
guidance_pag_stop = gr.Slider(minimum=0.0, maximum=1.0, step=0.01, label='PAG stop', value=0.2)
guidance_pag_layers = gr.Textbox(label='PAG layers', value='7, 8, 9', placeholder='Comma-separated layer indices, e.g. 7,8,9')
guidance_pag_config = gr.Dropdown(choices=[None, 'config1', 'config2'], value=None, label='PAG config')
guidance_pag_args = [guidance_cfg_true, guidance_pag_start, guidance_pag_stop, guidance_pag_layers, guidance_pag_config]
guidance_pag_layers = gr.Textbox(label='PAG layers', value='', placeholder='layer indices, e.g. 7,8,9 or ranges, e.g. 7-9')
args_pag = [guidance_pag_scale, guidance_pag_start, guidance_pag_stop, guidance_pag_layers]
apg_group = gr.Accordion(open=True, label='Advanced guidance params', elem_classes=["small-accordion"], visible=False)
with apg_group:
guidance_apg_momentum = gr.Slider(minimum=-1.0, maximum=1.0, step=0.05, label='APG momentum', value=-1.0)
guidance_apg_rescale = gr.Slider(minimum=0.0, maximum=30.0, step=0.1, label='APG rescale', value=15.0)
guidance_apg_args = [guidance_apg_momentum, guidance_apg_rescale]
args_apg = [guidance_apg_momentum, guidance_apg_rescale]
slg_group = gr.Accordion(open=True, label='Advanced guidance params', elem_classes=["small-accordion"], visible=False)
with slg_group:
guidance_slg_scale = gr.Slider(minimum=0.0, maximum=30.0, step=0.1, label='SLG scale', value=2.8)
guidance_slg_start = gr.Slider(minimum=0.0, maximum=1.0, step=0.1, label='SLG start', value=0.01)
guidance_slg_stop = gr.Slider(minimum=0.0, maximum=1.0, step=0.1, label='SLG stop', value=0.2)
guidance_slg_layers = gr.Textbox(label='SLG layers', value='7, 8, 9', placeholder='Comma-separated layer indices, e.g. 7,8,9')
guidance_slg_config = gr.Dropdown(choices=[None, 'config1', 'config2'], value=None, label='SLG config')
guidance_slg_args = [guidance_slg_scale, guidance_slg_start, guidance_slg_stop, guidance_slg_layers, guidance_slg_config]
guidance_slg_layers = gr.Textbox(label='SLG layers', value='', placeholder='layer indices, e.g. 7,8,9 or ranges, e.g. 7-9')
args_slg = [guidance_slg_scale, guidance_slg_start, guidance_slg_stop, guidance_slg_layers]
seg_group = gr.Accordion(open=True, label='Advanced guidance params', elem_classes=["small-accordion"], visible=False)
with seg_group:
@@ -93,20 +73,19 @@ def create_guidance_inputs(tab):
guidance_seg_blur_threshold_inf = gr.Number(label='SEG blur threshold inf', value=9999.0)
guidance_seg_start = gr.Slider(minimum=0.0, maximum=1.0, step=0.1, label='SEG start', value=0.0)
guidance_seg_stop = gr.Slider(minimum=0.0, maximum=1.0, step=0.1, label='SEG stop', value=1.0)
guidance_seg_layers = gr.Textbox(label='SEG layers', value='7, 8, 9', placeholder='Comma-separated layer indices, e.g. 7,8,9')
guidance_seg_config = gr.Dropdown(choices=[None, 'config1', 'config2'], value=None, label='SEG config')
guidance_seg_args = [guidance_seg_scale, guidance_seg_blur_sigma, guidance_seg_blur_threshold_inf, guidance_seg_start, guidance_seg_stop, guidance_seg_layers, guidance_seg_config]
guidance_seg_layers = gr.Textbox(label='SEG layers', value='', placeholder='layer indices, e.g. 7,8,9 or ranges, e.g. 7-9')
args_seg = [guidance_seg_scale, guidance_seg_blur_sigma, guidance_seg_blur_threshold_inf, guidance_seg_start, guidance_seg_stop, guidance_seg_layers]
tcfg_group = gr.Accordion(open=True, label='Advanced guidance params', elem_classes=["small-accordion"], visible=False)
with tcfg_group:
pass
args_tcfg = []
fdg_group = gr.Accordion(open=True, label='Advanced guidance params', elem_classes=["small-accordion"], visible=False)
with fdg_group:
guidance_fdg_scales = gr.Textbox(label='FDG scales', value='10.0, 5.0', placeholder='Comma-separated scales, e.g. 10.0,5.0')
guidance_fdg_weights = gr.Textbox(label='FDG weights', value='1.0', placeholder='Single float or comma-separated weights, e.g. 1.0 or 1.0,0.5')
guidance_fdg_scales = gr.Textbox(label='FDG scales', value='10.0, 5.0', placeholder='descending scales, e.g. 10.0,5.0')
guidance_fdg_weights = gr.Slider(minimum=0.0, maximum=1.0, step=0.01, label='FDG weights', value=1.0)
guidance_fdg_rescale_space = gr.Dropdown(choices=['data', 'freq'], value='data', label='FDG rescale space')
guidance_fdg_args = [guidance_fdg_scales, guidance_fdg_weights, guidance_fdg_rescale_space]
args_fdg = [guidance_fdg_scales, guidance_fdg_weights, guidance_fdg_rescale_space]
def adv_visibility(guidance_name):
return [
@@ -120,26 +99,24 @@ def create_guidance_inputs(tab):
gr.update(visible=guidance_name.startswith('TCFG')),
gr.update(visible=guidance_name.startswith('FDG')),
]
guidance_name.change(fn=adv_visibility, inputs=[guidance_name], outputs=[base_group, auto_group, zero_group, pag_group, apg_group, slg_group, seg_group, tcfg_group, fdg_group])
cfg_name.change(fn=adv_visibility, inputs=[cfg_name], outputs=[base_group, auto_group, zero_group, pag_group, apg_group, slg_group, seg_group, tcfg_group, fdg_group])
with gr.Row(elem_id=f"{tab}_cfg_row", elem_classes=['flexbox'], visible=not shared.opts.model_modular_enable):
cfg_scale = gr.Slider(minimum=-1.0, maximum=30.0, step=0.1, label='Guidance scale', value=-1.0, elem_id=f"{tab}_cfg_scale")
cfg_end = gr.Slider(minimum=0.0, maximum=1.0, step=0.1, label='Guidance end', value=1.0, elem_id=f"{tab}_cfg_end")
with gr.Row(visible=not shared.opts.model_modular_enable):
cfg_rescale = gr.Slider(minimum=-1.0, maximum=1.0, step=0.05, label='Guidance rescale', value=-1.0, elem_id=f"{tab}_image_cfg_rescale")
cfg_image = gr.Slider(minimum=-1.0, maximum=30.0, step=0.1, label='Refine guidance', value=-1.0, elem_id=f"{tab}_cfg_image")
with gr.Row(visible=not shared.opts.model_modular_enable):
legacy_group = gr.Row(visible=not shared.opts.model_modular_enable)
with legacy_group:
cfg_true = gr.Slider(minimum=-1.0, maximum=30.0, step=0.05, label='Attention guidance', value=-1.0, elem_id=f"{tab}_cfg_true")
cfg_adaptive = gr.Slider(minimum=0.0, maximum=1.0, step=0.05, label='Adaptive scaling', value=0.5, elem_id=f"{tab}_cfg_adaptive")
args_legacy = [cfg_true, cfg_adaptive]
_modular_args = guidance_args + lsc_args + guidance_auto_args + guidance_zero_args + guidance_pag_args + guidance_apg_args + guidance_slg_args + guidance_seg_args + guidance_fdg_args # TODO modular: guidance args are not implemented
def update_stored(component, label):
_stored_args[label] = component
for component in _modular_args:
modular_args = args_auto + args_zero + args_pag + args_apg + args_slg + args_seg + args_tcfg + args_fdg
standard_args = args_base + args_legacy
def update_stored(component, name):
_stored_args[name] = component
for component in modular_args:
label = getattr(component, 'label', None)
value = getattr(component, 'value', None)
_stored_args[label] = value
component.change(fn=partial(update_stored, label=label), inputs=[component], outputs=[])
name = label.lower().replace(' ', '_') if label is not None else None
_stored_args[name] = value
component.change(fn=partial(update_stored, name=name), inputs=[component], outputs=[])
standard_args = [cfg_scale, cfg_image, cfg_rescale, cfg_true, cfg_adaptive, cfg_end]
return guidance_args + standard_args
return standard_args
+11 -15
View File
@@ -137,7 +137,7 @@ def create_ui():
denoising_strength = gr.Slider(minimum=0.00, maximum=0.99, step=0.01, label='Denoising strength', value=0.30, elem_id="img2img_denoising_strength")
refiner_start = gr.Slider(minimum=0.0, maximum=1.0, step=0.05, label='Denoise start', value=0.0, elem_id="img2img_refiner_start")
guidance_name, guidance_scale, guidance_rescale, guidance_start, guidance_stop, cfg_scale, cfg_image, cfg_rescale, cfg_true, cfg_adaptive, cfg_end = ui_guidance.create_guidance_inputs('img2img')
cfg_name, cfg_scale, cfg_image, cfg_rescale, cfg_start, cfg_stop, cfg_true, cfg_adaptive = ui_guidance.create_guidance_inputs('img2img')
vae_type, tiling, hidiffusion, clip_skip = ui_sections.create_advanced_inputs('img2img')
grading_brightness, grading_contrast, grading_saturation, grading_hue, grading_gamma, grading_sharpness, grading_color_temp, grading_shadows, grading_midtones, grading_highlights, grading_clahe_clip, grading_clahe_grid, grading_shadows_tint, grading_highlights_tint, grading_split_tone_balance, grading_vignette, grading_grain, grading_lut_file, grading_lut_strength = ui_sections.create_color_inputs('img2img')
hdr_mode, hdr_brightness, hdr_color, hdr_sharpen, hdr_clamp, hdr_boundary, hdr_threshold, hdr_maximize, hdr_max_center, hdr_max_boundary, hdr_color_picker, hdr_tint_ratio, hdr_apply_hires = ui_sections.create_latent_inputs('img2img')
@@ -183,8 +183,7 @@ def create_ui():
vae_type, tiling, hidiffusion,
detailer_enabled, detailer_prompt, detailer_negative, detailer_steps, detailer_strength, detailer_resolution, detailer_classes,
batch_count, batch_size,
guidance_name, guidance_scale, guidance_rescale, guidance_start, guidance_stop,
cfg_scale, cfg_image, cfg_rescale, cfg_true, cfg_adaptive, cfg_end,
cfg_name, cfg_scale, cfg_image, cfg_rescale, cfg_start, cfg_stop, cfg_true, cfg_adaptive,
refiner_start,
clip_skip,
denoising_strength,
@@ -266,19 +265,8 @@ def create_ui():
(seed, "Seed"),
(subseed, "Variation seed"),
(subseed_strength, "Variation strength"),
# guidance
(guidance_name, "Guidance"),
(guidance_scale, "Guidance scale"),
(guidance_rescale, "Guidance rescale"),
(guidance_start, "Guidance start"),
(guidance_stop, "Guidance stop"),
# advanced
(cfg_scale, "CFG scale"),
(cfg_end, "CFG end"),
(cfg_image, "Image CFG scale"),
(cfg_image, "Hires CFG scale"),
(clip_skip, "CLiP-skip"),
(cfg_rescale, "CFG rescale"),
(vae_type, "VAE type"),
(tiling, "Tiling"),
(hidiffusion, "HiDiffusion"),
@@ -309,7 +297,15 @@ def create_ui():
(refiner_steps, "Refiner steps"),
(refiner_prompt, "refiner prompt"),
(refiner_negative, "Refiner negative"),
# pag
# guidance
(cfg_name, "CFG name"),
(cfg_scale, "CFG scale"),
(cfg_image, "CFG image"),
(cfg_image, "Image CFG scale"),
(cfg_image, "Hires CFG scale"),
(cfg_rescale, "CFG rescale"),
(cfg_start, "CFG start"),
(cfg_stop, "CFG stop"),
(cfg_true, "CFG true"),
(cfg_adaptive, "CFG adaptive"),
# inpaint
+11 -15
View File
@@ -33,7 +33,7 @@ def create_ui():
with gr.Accordion(open=False, label="Samplers", elem_classes=["small-accordion"], elem_id="txt2img_sampler_group"):
ui_sections.create_sampler_options('txt2img')
seed, reuse_seed, subseed, reuse_subseed, subseed_strength, seed_resize_from_h, seed_resize_from_w = ui_sections.create_seed_inputs('txt2img')
guidance_name, guidance_scale, guidance_rescale, guidance_start, guidance_stop, cfg_scale, cfg_image, cfg_rescale, cfg_true, cfg_adaptive, cfg_end = ui_guidance.create_guidance_inputs('txt2img')
cfg_name, cfg_scale, cfg_image, cfg_rescale, cfg_start, cfg_stop, cfg_true, cfg_adaptive = ui_guidance.create_guidance_inputs('txt2img')
vae_type, tiling, hidiffusion, clip_skip = ui_sections.create_advanced_inputs('txt2img')
grading_brightness, grading_contrast, grading_saturation, grading_hue, grading_gamma, grading_sharpness, grading_color_temp, grading_shadows, grading_midtones, grading_highlights, grading_clahe_clip, grading_clahe_grid, grading_shadows_tint, grading_highlights_tint, grading_split_tone_balance, grading_vignette, grading_grain, grading_lut_file, grading_lut_strength = ui_sections.create_color_inputs('txt2img')
hdr_mode, hdr_brightness, hdr_color, hdr_sharpen, hdr_clamp, hdr_boundary, hdr_threshold, hdr_maximize, hdr_max_center, hdr_max_boundary, hdr_color_picker, hdr_tint_ratio, hdr_apply_hires = ui_sections.create_latent_inputs('txt2img')
@@ -58,8 +58,7 @@ def create_ui():
vae_type, tiling, hidiffusion,
detailer_enabled, detailer_prompt, detailer_negative, detailer_steps, detailer_strength, detailer_resolution, detailer_classes,
batch_count, batch_size,
guidance_name, guidance_scale, guidance_rescale, guidance_start, guidance_stop,
cfg_scale, cfg_image, cfg_rescale, cfg_true, cfg_adaptive, cfg_end,
cfg_name, cfg_scale, cfg_image, cfg_rescale, cfg_start, cfg_stop, cfg_true, cfg_adaptive,
clip_skip,
seed, subseed, subseed_strength, seed_resize_from_h, seed_resize_from_w,
height, width,
@@ -114,19 +113,8 @@ def create_ui():
(seed, "Seed"),
(subseed, "Variation seed"),
(subseed_strength, "Variation strength"),
# guidance
(guidance_name, "Guidance"),
(guidance_scale, "Guidance scale"),
(guidance_rescale, "Guidance rescale"),
(guidance_start, "Guidance start"),
(guidance_stop, "Guidance stop"),
# advanced
(cfg_scale, "CFG scale"),
(cfg_end, "CFG end"),
(clip_skip, "CLiP-skip"),
(cfg_image, "Image CFG scale"),
(cfg_image, "Hires CFG scale"),
(cfg_rescale, "CFG rescale"),
(vae_type, "VAE type"),
(tiling, "Tiling"),
(hidiffusion, "HiDiffusion"),
@@ -156,7 +144,15 @@ def create_ui():
(refiner_steps, "Refiner steps"),
(refiner_prompt, "refiner prompt"),
(refiner_negative, "Refiner negative"),
# pag
# guidance
(cfg_name, "CFG name"),
(cfg_scale, "CFG scale"),
(cfg_image, "CFG image"),
(cfg_image, "Image CFG scale"),
(cfg_image, "Hires CFG scale"),
(cfg_rescale, "CFG rescale"),
(cfg_start, "CFG start"),
(cfg_stop, "CFG stop"),
(cfg_true, "CFG true"),
(cfg_adaptive, "CFG adaptive"),
# hidden
+2 -1
View File
@@ -220,7 +220,8 @@ def decode(latents, fast=False):
image = image[0]
else:
image = vae.decode(tensor, return_dict=False)[0]
image = (image / 2.0 + 0.5).clamp(0, 1).detach()
# image = (image / 2.0 + 0.5).clamp(0, 1).detach()
image = image.clamp(0, 1).detach()
image = restore_preview_size(image, vae)
t1 = time.time()
if (t1 - t0) > 5.0 and not first_run:
+5 -3
View File
@@ -47,7 +47,7 @@ from scripts.xyz.xyz_grid_shared import ( # pylint: disable=no-name-in-module, u
format_nothing,
str_permutations,
)
from modules import shared, shared_items, sd_samplers, ipadapter, sd_models, sd_vae, sd_unet, attention
from modules import shared, shared_items, sd_samplers, ipadapter, sd_models, sd_vae, sd_unet, attention, modular_guiders
from modules.control.units import controlnet, t2iadapter
from modules.control import processor
@@ -260,10 +260,12 @@ axis_options = [
AxisOption("[Sampler] Max shift", float, apply_setting("schedulers_max_shift")),
AxisOption("[Sampler] ETA delta", float, apply_setting("eta_noise_seed_delta")),
AxisOption("[Sampler] ETA multiplier", float, apply_setting("scheduler_eta")),
AxisOption("[Guidance] Name", str, apply_field("cfg_name"), cost=0.2, choices=lambda: list(modular_guiders.guiders.keys())),
AxisOption("[Guidance] Scale", float, apply_field("cfg_scale")),
AxisOption("[Guidance] End", float, apply_field("cfg_end")),
AxisOption("[Guidance] Image scale", float, apply_field("cfg_image")),
AxisOption("[Guidance] Rescale", float, apply_field("cfg_rescale")),
AxisOption("[Guidance] Start", float, apply_field("cfg_start")),
AxisOption("[Guidance] Stop", float, apply_field("cfg_stop")),
AxisOption("[Guidance] Image scale", float, apply_field("cfg_image")),
AxisOption("[Refine] Upscaler", str, apply_field("hr_upscaler"), cost=0.3, choices=lambda: [x.name for x in shared.sd_upscalers]),
AxisOption("[Refine] Sampler", str, apply_hr_sampler_name, fmt=format_value_add_label, confirm=confirm_samplers, choices=lambda: [x.name for x in sd_samplers.visible_samplers()]),
AxisOption("[Refine] Denoising strength", float, apply_field("denoising_strength")),
+1 -1
View File
@@ -239,7 +239,7 @@ const engine = {
await Promise.all(toLoad.map(async (name) => {
try {
const resp = await authFetch(`${window.api}/autocomplete/${name}`);
if (!resp.ok) throw new Error(`${resp.status}`);
if (!resp?.ok) throw new Error(`${resp?.status}`);
const data = await resp.json();
this.indices.set(name, new TagIndex(data));
// Extract category colors from first loaded file
+1 -1
View File
@@ -88,7 +88,7 @@ export const xnEngine: XnEngine = {
try {
// const resp = await fetch(`${window.api}${path}`, { credentials: 'include' });
const resp = await authFetch(`${window.api}${path}`);
if (!resp.ok) throw new Error(`${resp.status}`);
if (!resp?.ok) throw new Error(`${resp?.status}`);
return await resp.json();
} catch (e) {
log('autoComplete', { xnFetchFailed: path, error: String(e) });
+7 -6
View File
@@ -11231,7 +11231,7 @@ async function updateUI(model) {
}
async function updateModel() {
const req = await authFetch2(`${window.api}/checkpoint`);
if (req.ok) {
if (req && req.ok) {
const model = await req.json();
if (model?.type?.length > 0) updateUI(model);
}
@@ -11348,7 +11348,7 @@ async function setTheme(val, old) {
for (const link of links) {
const href = link.href.replace(old, val);
const res = await authFetch2(href);
if (res.ok) {
if (res?.ok) {
log("setTheme", old, val);
link.href = link.href.replace(old, val);
} else {
@@ -12445,7 +12445,7 @@ async function initModels() {
const en = gradioApp().getElementById("txt2img_extra_networks");
if (!el2 || !en) return;
const req = await authFetch2(`${window.api}/sd-models`);
const res = req.ok ? await req.json() : [];
const res = req && req.ok ? await req.json() : [];
log("initModels", res.length);
const ready = () => `
<p style='color: white'>Ready</p>
@@ -13493,7 +13493,7 @@ async function delayFetchThumb(fn, signal) {
outstanding++;
const ts = t0.toString();
const res = await authFetch2(`${window.api}/browser/thumb?file=${encodeURI(fn)}&ts=${ts}&exif=false`, { priority: "low" });
if (!res.ok) {
if (!res?.ok) {
error(`fetchThumb: ${res.statusText}`);
return void 0;
}
@@ -14260,6 +14260,7 @@ async function observeImageError(img) {
img.src = loadingSvg;
const { default: heic2any } = await import("https://esm.sh/heic2any@0.0.4");
const res = await authFetch2(origSrc);
if (!res || res.status !== 200) return;
const imageBlob = await res.blob();
if (!imageBlob || imageBlob.size <= 1024) {
error("imageHEIC", { src: origSrc, res, blob: imageBlob });
@@ -14735,7 +14736,7 @@ var xnEngine = {
async fetchJson(path) {
try {
const resp = await authFetch(`${window.api}${path}`);
if (!resp.ok) throw new Error(`${resp.status}`);
if (!resp?.ok) throw new Error(`${resp?.status}`);
return await resp.json();
} catch (e) {
log("autoComplete", { xnFetchFailed: path, error: String(e) });
@@ -14984,7 +14985,7 @@ var engine = {
await Promise.all(toLoad.map(async (name) => {
try {
const resp = await authFetch(`${window.api}/autocomplete/${name}`);
if (!resp.ok) throw new Error(`${resp.status}`);
if (!resp?.ok) throw new Error(`${resp?.status}`);
const data = await resp.json();
this.indices.set(name, new TagIndex(data));
if (data.categories) {
+2 -2
View File
File diff suppressed because one or more lines are too long
+1 -1
View File
@@ -18,7 +18,7 @@ async function updateUI(model: Model) {
export async function updateModel() {
const req = await authFetch(`${window.api}/checkpoint`);
if (req.ok) {
if (req && req.ok) {
const model = await req.json() as Model;
if (model?.type?.length > 0) updateUI(model);
}
+2 -1
View File
@@ -503,7 +503,7 @@ async function delayFetchThumb(fn, signal) {
outstanding++;
const ts = t0.toString();
const res = await authFetch(`${window.api}/browser/thumb?file=${encodeURI(fn)}&ts=${ts}&exif=false`, { priority: 'low' });
if (!res.ok) {
if (!res?.ok) {
error(`fetchThumb: ${res.statusText}`);
return undefined;
}
@@ -1466,6 +1466,7 @@ async function observeImageError(img: HTMLImageElement) {
// eslint-disable-next-line import-x/no-unresolved
const { default: heic2any } = await import('https://esm.sh/heic2any@0.0.4');
const res = await authFetch(origSrc);
if (!res || res.status !== 200) return;
const imageBlob = await res.blob();
if (!imageBlob || imageBlob.size <= 1024) {
error('imageHEIC', { src: origSrc, res, blob: imageBlob });
+1 -1
View File
@@ -201,7 +201,7 @@ export async function initModels() {
const en = gradioApp().getElementById('txt2img_extra_networks');
if (!el || !en) return;
const req = await authFetch(`${window.api}/sd-models`);
const res = req.ok ? await req.json() : [];
const res = (req && req.ok) ? await req.json() : [];
log('initModels', res.length);
const ready = () => `
<p style='color: white'>Ready</p>
+1 -1
View File
@@ -130,7 +130,7 @@ export async function setTheme(val, old) {
for (const link of links) {
const href = link.href.replace(old, val);
const res = await authFetch(href);
if (res.ok) {
if (res?.ok) {
log('setTheme', old, val);
link.href = link.href.replace(old, val);
} else {