samplers expose base/max seq len, improve sampler options save, copy defaults

Signed-off-by: Vladimir Mandic <[email protected]>
This commit is contained in:
Vladimir Mandic
2026-09-30 18:37:05 +02:00
parent b3e5093f18
commit c6bf7b4368
13 changed files with 84 additions and 22 deletions
+5 -1
View File
@@ -63,6 +63,9 @@ Plus quite a few other improvements and inevitable bug-fixes, see full changelog
- processors: `DWPose`, `RTMW`, `RTMO`: image processor updates, thanks @kirtasshh
refactored to use `ONNX` instead of obsolete `mmpose` lib and with additional configurable settings
- lora: extend support for more model types
- scheduler: expose base and max image sequence lengths
recommended to change when target resolution is significantly different from the base resolution
- detailer: add option to skip specific classes using `[SKIP=name]` in the detailer prompt, thanks @kirtasshh
- **UI**
- massive improvement to built-in tooltips/hints
over 1,000 new entries, now at zero missing ui controls or settings
@@ -94,7 +97,8 @@ Plus quite a few other improvements and inevitable bug-fixes, see full changelog
- pixelsmith: vae tiling, thanks @li-lizhe
- preview: remove flicker when finishing generation
- prompt cache: bypass when condition images are encoded
- sampler: when creating sampler, copy all valid options from default sampler
- scheduler: when creating sampler, copy all valid options from default sampler
- scheduler: debounce sampler options save
- seedvr: handle temporal overap
- styles: fix infotext parsing, thanks @obelisk-complex
- temp file: gradio temp file error handling
+2
View File
@@ -397,6 +397,7 @@ def control_run(state: str = '', # pylint: disable=keyword-arg-before-vararg
schedulers_base_shift: float | None = None, schedulers_max_shift: float | None = None, schedulers_rescale_betas: bool | None = None,
schedulers_timestep_spacing: str | None = None, schedulers_timesteps_range: int | None = None,
schedulers_sigma_adjust: float | None = None, schedulers_sigma_adjust_min: float | None = None, schedulers_sigma_adjust_max: float | None = None,
schedulers_base_image_seq_len: int | None = None, schedulers_max_image_seq_len: int | None = None,
scheduler_eta: float | None = None, eta_noise_seed_delta: int | None = None, enable_batch_seeds: bool | None = None,
diffusers_generator_device: str | None = None, nan_skip: bool | None = None,
sequential_seed: bool | None = None,
@@ -573,6 +574,7 @@ def control_run(state: str = '', # pylint: disable=keyword-arg-before-vararg
schedulers_base_shift=schedulers_base_shift, schedulers_max_shift=schedulers_max_shift,
schedulers_rescale_betas=schedulers_rescale_betas, schedulers_timestep_spacing=schedulers_timestep_spacing,
schedulers_timesteps_range=schedulers_timesteps_range,
schedulers_base_image_seq_len=schedulers_base_image_seq_len, schedulers_max_image_seq_len=schedulers_max_image_seq_len,
schedulers_sigma_adjust=schedulers_sigma_adjust, schedulers_sigma_adjust_min=schedulers_sigma_adjust_min,
schedulers_sigma_adjust_max=schedulers_sigma_adjust_max,
scheduler_eta=scheduler_eta, eta_noise_seed_delta=eta_noise_seed_delta,
+2
View File
@@ -123,6 +123,8 @@ mapping = [
('Sampler beta end', 'schedulers_beta_end'),
('Sampler range', 'schedulers_timesteps_range'),
('Sampler shift', 'schedulers_shift'),
('Sampler base seq', 'schedulers_base_image_seq_len'),
('Sampler max seq', 'schedulers_max_image_seq_len'),
('Sampler dynamic shift', 'schedulers_dynamic_shift'),
# Token Merging
('Mask weight', 'inpainting_mask_weight'),
+3 -3
View File
@@ -22,7 +22,7 @@ def options_section(section_identifier: tuple[str, str], options_dict: dict[str,
class OptionInfo:
def __init__(
self,
self, # pylint: disable=unused-argument
default: Any = None,
label="",
component: type[Component] | type[DropdownEditable] | None = None,
@@ -35,8 +35,8 @@ class OptionInfo:
comment_before='',
comment_after='',
category_id=None, # pylint: disable=unused-argument
*args, # pylint: disable=unused-argument
**kwargs, # pylint: disable=unused-argument
*args,
**kwargs,
): # pylint: disable=keyword-arg-before-vararg
self.default = default
self.label = label
+4
View File
@@ -239,6 +239,8 @@ class StableDiffusionProcessing:
schedulers_sigma_adjust: float | None = None,
schedulers_sigma_adjust_min: float | None = None,
schedulers_sigma_adjust_max: float | None = None,
schedulers_base_image_seq_len: int | None = None,
schedulers_max_image_seq_len: int | None = None,
scheduler_eta: float | None = None,
eta_noise_seed_delta: int | None = None,
enable_batch_seeds: bool | None = None,
@@ -526,6 +528,8 @@ class StableDiffusionProcessing:
self.schedulers_sigma_adjust = schedulers_sigma_adjust
self.schedulers_sigma_adjust_min = schedulers_sigma_adjust_min
self.schedulers_sigma_adjust_max = schedulers_sigma_adjust_max
self.schedulers_base_image_seq_len = schedulers_base_image_seq_len
self.schedulers_max_image_seq_len = schedulers_max_image_seq_len
self.scheduler_eta = scheduler_eta
self.eta_noise_seed_delta = eta_noise_seed_delta
self.enable_batch_seeds = enable_batch_seeds
+8 -5
View File
@@ -516,10 +516,10 @@ class DiffusionSampler:
if 'beta_end' in self.config and get_override('schedulers_beta_end') > 0:
self.config['beta_end'] = get_override('schedulers_beta_end')
sched_shift = get_override('schedulers_shift')
if 'shift' in self.config:
self.config['shift'] = sched_shift if sched_shift > 0 else 3
if 'flow_shift' in self.config:
self.config['flow_shift'] = sched_shift if sched_shift > 0 else 3
if 'shift' in self.config and sched_shift > 0:
self.config['shift'] = sched_shift
if 'flow_shift' in self.config and sched_shift > 0:
self.config['flow_shift'] = sched_shift
if 'use_dynamic_shifting' in self.config:
self.config['use_dynamic_shifting'] = True if sched_shift == 0 else get_override('schedulers_dynamic_shift')
if 'base_shift' in self.config:
@@ -530,6 +530,10 @@ class DiffusionSampler:
self.config['use_beta_sigmas'] = 'StableDiffusion3' in model.__class__.__name__
if 'rescale_betas_zero_snr' in self.config:
self.config['rescale_betas_zero_snr'] = get_override('schedulers_rescale_betas')
if 'base_image_seq_len' in self.config and get_override('schedulers_base_image_seq_len') > 0:
self.config['base_image_seq_len'] = get_override('schedulers_base_image_seq_len')
if 'max_image_seq_len' in self.config and get_override('schedulers_max_image_seq_len') > 0:
self.config['max_image_seq_len'] = get_override('schedulers_max_image_seq_len')
sched_ts_spacing = get_override('schedulers_timestep_spacing')
if 'timestep_spacing' in self.config and sched_ts_spacing != 'default' and sched_ts_spacing is not None:
self.config['timestep_spacing'] = sched_ts_spacing
@@ -558,7 +562,6 @@ class DiffusionSampler:
for key in self.config.copy().keys():
if key not in possible:
del self.config[key]
self.config['shift_terminal'] = 0.0
debug_log(f'Sampler: name="{name}"')
debug_log(f'Sampler: config={self.config}')
debug_log(f'Sampler: signature={possible}')
+2
View File
@@ -858,6 +858,8 @@ def create_settings(cmd_opts):
"schedulers_shift": OptionInfo(3, "Sampler shift", gr.Slider, {"minimum": 0.1, "maximum": 10, "step": 0.1, "visible": False}),
"schedulers_fallback": OptionInfo(True, "Sampler fallback on invalid", gr.Checkbox, {"visible": False}),
"schedulers_dynamic_shift": OptionInfo(False, "Sampler dynamic shift", gr.Checkbox, {"visible": False}),
"schedulers_base_image_seq_len": OptionInfo(0, "Sampler base seq", gr.Slider, {"minimum": 0, "maximum": 1024, "step": 16, "visible": False}),
"schedulers_max_image_seq_len": OptionInfo(0, "Sampler max seq", gr.Slider, {"minimum": 0, "maximum": 16384, "step": 16, "visible": False}),
"schedulers_sigma_adjust": OptionInfo(1.0, "Sigma adjust", gr.Slider, {"minimum": 0.5, "maximum": 1.5, "step": 0.01, "visible": False}),
"schedulers_sigma_adjust_min": OptionInfo(0.2, "Sigma adjust start", gr.Slider, {"minimum": 0.0, "maximum": 1.0, "step": 0.01, "visible": False}),
"schedulers_sigma_adjust_max": OptionInfo(0.8, "Sigma adjust end", gr.Slider, {"minimum": 0.0, "maximum": 1.0, "step": 0.01, "visible": False}),
+45 -10
View File
@@ -1,3 +1,4 @@
import threading
import gradio as gr
from modules import shared, modelloader, ui_symbols, ui_common, sd_samplers
from modules.logger import log
@@ -5,6 +6,10 @@ from modules.ui_components import ToolButton
from modules.caption import caption
_save_timer = None
_save_lock = threading.Lock()
def create_toprow(is_img2img: bool = False, id_part: str | None = None, generate_visible: bool = True, negative_visible: bool = True, reprocess_visible: bool = True):
def apply_styles(prompt, prompt_neg, styles):
prompt = shared.prompt_styles.apply_styles_to_prompt(prompt, styles, wildcards=not shared.opts.extra_networks_apply_unparsed)
@@ -251,63 +256,88 @@ def create_sampler_and_steps_selection(choices, tabname, default_steps:int=20):
return steps, sampler_index
def save_with_debounce(delay=0.5):
global _save_timer # pylint: disable=global-statement
with _save_lock:
try:
if _save_timer is not None and _save_timer.is_alive():
_save_timer.cancel()
except Exception as e:
log.error(f'Sampler: save debounce cancel error: {e}')
def _do_save():
try:
shared.opts.save(silent=True)
except Exception as e:
log.error(f'Sampler: save execution error: {e}')
_save_timer = threading.Timer(delay, _do_save)
_save_timer.start()
def create_sampler_options(tabname):
def set_sampler_options(sampler_options):
shared.opts.data['schedulers_dynamic_shift'] = 'dynamic' in sampler_options
shared.opts.data['schedulers_use_thresholding'] = 'thresholding' in sampler_options
shared.opts.data['schedulers_use_loworder'] = 'low order' in sampler_options
shared.opts.data['schedulers_rescale_betas'] = 'rescale' in sampler_options
log.debug(f'Sampler set options: {sampler_options}')
shared.opts.save(silent=True)
save_with_debounce()
def set_sampler_fallback(fallback):
log.debug(f'Sampler set options: fallback={fallback}')
shared.opts.schedulers_fallback = fallback
shared.opts.save(silent=True)
save_with_debounce()
def set_sampler_timesteps(timesteps):
log.debug(f'Sampler set options: timesteps={timesteps}')
shared.opts.schedulers_timesteps = timesteps
shared.opts.save(silent=True)
save_with_debounce()
def set_sampler_spacing(spacing):
log.debug(f'Sampler set options: spacing={spacing}')
shared.opts.schedulers_timestep_spacing = spacing
shared.opts.save(silent=True)
save_with_debounce()
def set_sampler_sigma(sampler_sigma):
log.debug(f'Sampler set options: sigma={sampler_sigma}')
shared.opts.schedulers_sigma = sampler_sigma
shared.opts.save(silent=True)
save_with_debounce()
def set_sampler_order(sampler_order):
log.debug(f'Sampler set options: order={sampler_order}')
shared.opts.schedulers_solver_order = sampler_order
shared.opts.save(silent=True)
save_with_debounce()
def set_sampler_prediction(sampler_prediction):
log.debug(f'Sampler set options: prediction={sampler_prediction}')
shared.opts.schedulers_prediction_type = sampler_prediction
shared.opts.save(silent=True)
save_with_debounce()
def set_sampler_beta(sampler_beta):
log.debug(f'Sampler set options: beta={sampler_beta}')
shared.opts.schedulers_beta_schedule = sampler_beta
shared.opts.save(silent=True)
save_with_debounce()
def set_sampler_shift(sampler_shift, sampler_base_shift, sampler_max_shift):
log.debug(f'Sampler set options: shift={sampler_shift} base={sampler_base_shift} max={sampler_max_shift}')
shared.opts.schedulers_shift = sampler_shift
shared.opts.schedulers_base_shift = sampler_base_shift
shared.opts.schedulers_max_shift = sampler_max_shift
shared.opts.save(silent=True)
save_with_debounce()
def set_sampler_seq_lens(base_image_seq_len, max_image_seq_len):
log.debug(f'Sampler set options: base_image_seq_len={base_image_seq_len} max_image_seq_len={max_image_seq_len}')
shared.opts.schedulers_base_image_seq_len = base_image_seq_len
shared.opts.schedulers_max_image_seq_len = max_image_seq_len
save_with_debounce()
def set_sigma_adjust(val, start, end):
log.debug(f'Sampler set options: sigma={val} min={start} max={end}')
shared.opts.schedulers_sigma_adjust = val
shared.opts.schedulers_sigma_adjust_min = start
shared.opts.schedulers_sigma_adjust_max = end
shared.opts.save(silent=True)
save_with_debounce()
# 'linear', 'scaled_linear', 'squaredcos_cap_v2'
def set_sampler_preset(preset):
@@ -336,6 +366,9 @@ def create_sampler_options(tabname):
sampler_shift = gr.Slider(minimum=0, maximum=10, step=0.1, label="Flow shift", value=shared.opts.schedulers_shift, elem_id=f"{tabname}_sampler_shift")
sampler_base_shift = gr.Slider(minimum=0, maximum=10, step=0.01, label="Base shift", value=shared.opts.schedulers_base_shift, elem_id=f"{tabname}_sampler_base_shift")
sampler_max_shift = gr.Slider(minimum=0, maximum=10, step=0.01, label="Max shift", value=shared.opts.schedulers_max_shift, elem_id=f"{tabname}_sampler_max_shift")
with gr.Row(elem_classes=['flex-break']):
sampler_base_image_seq_len = gr.Slider(minimum=0, maximum=1024, step=16, label='Sampler base seq', value=shared.opts.schedulers_base_image_seq_len, elem_id=f"{tabname}_sampler_base_image_seq_len")
sampler_max_image_seq_len = gr.Slider(minimum=0, maximum=16284, step=16, label='Sampler max seq', value=shared.opts.schedulers_max_image_seq_len, elem_id=f"{tabname}_sampler_max_image_seq_len")
with gr.Row(elem_classes=['flex-break']):
options = ['low order', 'thresholding', 'dynamic', 'rescale']
values = []
@@ -362,6 +395,8 @@ def create_sampler_options(tabname):
sampler_sigma_adjust_val.change(fn=set_sigma_adjust, inputs=[sampler_sigma_adjust_val, sampler_sigma_adjust_min, sampler_sigma_adjust_max], outputs=[])
sampler_sigma_adjust_min.change(fn=set_sigma_adjust, inputs=[sampler_sigma_adjust_val, sampler_sigma_adjust_min, sampler_sigma_adjust_max], outputs=[])
sampler_sigma_adjust_max.change(fn=set_sigma_adjust, inputs=[sampler_sigma_adjust_val, sampler_sigma_adjust_min, sampler_sigma_adjust_max], outputs=[])
sampler_base_image_seq_len.change(fn=set_sampler_seq_lens, inputs=[sampler_base_image_seq_len, sampler_max_image_seq_len], outputs=[])
sampler_max_image_seq_len.change(fn=set_sampler_seq_lens, inputs=[sampler_base_image_seq_len, sampler_max_image_seq_len], outputs=[])
def create_hires_inputs(tab):
+1 -1
View File
@@ -393,6 +393,6 @@ def apply_patch():
pretrained_model_name_or_path_or_dict = apply_lora_alphas(sd)
except Exception:
pass
return original_lora_state_dict(cls, pretrained_model_name_or_path_or_dict, **kwargs)
return original_lora_state_dict(cls, pretrained_model_name_or_path_or_dict, **kwargs) # pylint: disable=too-many-function-args
Flux2LoraLoaderMixin.lora_state_dict = patched_lora_state_dict
@@ -69,6 +69,8 @@ class Krea2InpaintPipeline(Krea2Img2ImgPipeline):
latents: Optional[torch.Tensor] = None,
output_type: str = "pil",
return_dict: bool = True,
dense_mask: bool = False,
attention_kwargs: dict | None = None,
callback_on_step_end: Optional[Union[Callable[[int, int, Dict], None], PipelineCallback, MultiPipelineCallbacks]] = None,
callback_on_step_end_tensor_inputs: List[str] = ["latents"],
):
+8
View File
@@ -115,13 +115,17 @@ class LensImg2ImgPipeline(LensPipeline):
strength: float = 0.8,
height: int = 1024,
width: int = 1024,
base_resolution: Optional[int] = None,
aspect_ratio: Optional[str] = None,
num_inference_steps: int = 50,
guidance_scale: float = 4.0,
num_images_per_prompt: int = 1,
generator: Optional[Union[torch.Generator, List[torch.Generator]]] = None,
latents: Optional[torch.Tensor] = None,
prompt_embeds: Optional[List[torch.Tensor]] = None,
prompt_mask: Optional[torch.Tensor] = None,
negative_prompt_embeds: Optional[List[torch.Tensor]] = None,
negative_prompt_mask: Optional[torch.Tensor] = None,
output_type: str = "pil",
return_dict: bool = True,
callback_on_step_end: Optional[Union[Callable[[int, int, Dict], None], PipelineCallback, MultiPipelineCallbacks]] = None,
@@ -186,13 +190,17 @@ class LensInpaintPipeline(LensImg2ImgPipeline):
strength: float = 0.8,
height: int = 1024,
width: int = 1024,
base_resolution: Optional[int] = None,
aspect_ratio: Optional[str] = None,
num_inference_steps: int = 50,
guidance_scale: float = 4.0,
num_images_per_prompt: int = 1,
generator: Optional[Union[torch.Generator, List[torch.Generator]]] = None,
latents: Optional[torch.Tensor] = None,
prompt_embeds: Optional[List[torch.Tensor]] = None,
prompt_mask: Optional[torch.Tensor] = None,
negative_prompt_embeds: Optional[List[torch.Tensor]] = None,
negative_prompt_mask: Optional[torch.Tensor] = None,
output_type: str = "pil",
return_dict: bool = True,
callback_on_step_end: Optional[Union[Callable[[int, int, Dict], None], PipelineCallback, MultiPipelineCallbacks]] = None,
+1 -1
View File
@@ -1229,4 +1229,4 @@
}
}
}
}
}
+1 -1
Submodule wiki updated: aa79b78a5c...e73ebd8c79