| """FSampler nodes for ComfyUI.""" |
| import time |
| import torch |
| import comfy.sample |
| import comfy.samplers |
| import comfy.utils |
| import latent_preview |
| from comfy.cli_args import args, LatentPreviewMethod |
|
|
| def _make_safe_preview_callback(model_or_patcher, total_steps, x0_output_dict=None): |
| """Create a preview callback that respects ComfyUI's preview setting.""" |
| pbar = comfy.utils.ProgressBar(total_steps) |
|
|
| if args.preview_method == LatentPreviewMethod.NoPreviews: |
| def safe_callback(step, x0, x, total): |
| pbar.update_absolute(step + 1, total) |
| return safe_callback |
|
|
| inner_cb = latent_preview.prepare_callback(model_or_patcher, total_steps, x0_output_dict) |
|
|
| def safe_callback(step, x0, x, total): |
| try: |
| inner_cb(step, x0, x, total) |
| except Exception: |
| pbar.update_absolute(step + 1, total) |
| return safe_callback |
| from .comfy_copy import k_diffusion_sampling |
| from .sampling.fibonacci_scheduler import get_fsampler_sigmas, FSAMPLER_SCHEDULERS |
| from .sampling.engine import sample_fsampler, create_fsampler_ksampler |
|
|
|
|
| |
| FSAMPLER_AVAILABLE_SCHEDULERS = [ |
| |
| "simple", |
| "normal", |
| "sgm_uniform", |
| "ddim_uniform", |
| "beta", |
| "linear_quadratic", |
| "karras", |
| "exponential", |
| "polyexponential", |
| "vp", |
| "laplace", |
| "kl_optimal", |
| |
| "beta57", |
| |
| "bong_tangent", |
| "bong_tangent_2", |
| "bong_tangent_2_simple", |
| "constant", |
| |
| "fibonacci", |
| "fibonacci_rev" |
| ] |
|
|
|
|
| def get_sigma_schedule(model, scheduler_name, num_steps): |
| """Get sigma schedule using model-aware ranges. |
| """ |
| try: |
| import comfy.samplers as _samplers |
| model_sampling = model.get_model_object("model_sampling") |
| if scheduler_name in FSAMPLER_SCHEDULERS: |
| sigma_min = float(model_sampling.sigma_min) |
| sigma_max = float(model_sampling.sigma_max) |
| return get_fsampler_sigmas(scheduler_name, num_steps, sigma_min, sigma_max) |
| else: |
| return _samplers.calculate_sigmas(model_sampling, scheduler_name, num_steps) |
| except Exception: |
| |
| return k_diffusion_sampling.get_sigmas(scheduler_name, num_steps, 0.03, 14.6) |
|
|
|
|
| class FSamplerAdvanced: |
| @classmethod |
| def INPUT_TYPES(s): |
| return { |
| "required": { |
| "model": ("MODEL",), |
| "positive": ("CONDITIONING",), |
| "negative": ("CONDITIONING",), |
| "latent_image": ("LATENT",), |
| "seed": ("INT", {"default": 0, "min": 0, "max": 0xffffffffffffffff}), |
| "steps": ("INT", {"default": 25, "min": 1, "max": 150}), |
| "cfg": ("FLOAT", {"default": 1.00, "min": 0.00, "max": 100.0, "step": 0.05}), |
| "scheduler": (FSAMPLER_AVAILABLE_SCHEDULERS, {"default": "simple"}), |
| "sampler": (["euler", "res_2m", "res_2s", "ddim", "dpmpp_2m", "dpmpp_2s", "lms", "res_multistep", "res_multistep_ancestral", "heun", "gradient_estimation"], { |
| "default": "euler", |
| "tooltip": "Sampling method" |
| }), |
| "protect_first_steps": ("INT", { |
| "default": 2, |
| "min": 0, |
| "max": 20, |
| "tooltip": "Number of initial steps never skipped (warmup)." |
| }), |
| "protect_last_steps": ("INT", { |
| "default": 2, |
| "min": 1, |
| "max": 100, |
| "tooltip": "Number of final steps never skipped (quality safeguard)." |
| }), |
| "adaptive_mode": (["none", "learning", "grad_est", "learn+grad_est"], { |
| "default": "none", |
| "tooltip": "Adaptive skip corrections: none=off; learning=EMA L stabilizer scales predicted epsilon on SKIP (smoothed by smoothing_beta); grad_est=gradient-estimation correction on SKIP only (directional, clamped to ≤25% of step); learn+grad_est=apply both (L scaling + grad correction)." |
| }), |
| "smoothing_beta": ("FLOAT", { |
| "default": 0.9990, |
| "min": 0.0, |
| "max": 0.9999, |
| "step": 0.0001, |
| "tooltip": "EMA smoothing for learning mode (0.9=balanced, 0.99-0.999=high stability, 0.9999=extreme dampening). Set to 0.0 for instant reaction. Only used when adaptive_mode is learning." |
| }), |
| "skip_mode": ([ |
| "none", |
| |
| "h2/s2", "h2/s3", "h2/s4", "h2/s5", |
| |
| "h3/s3", "h3/s4", "h3/s5", |
| |
| "h4/s4", "h4/s5", |
| "adaptive" |
| ], { |
| "default": "none", |
| "tooltip": "Skipping: hN/sK with N=history (2=linear,3=Richardson,4=cubic) and K=calls before skip. Supported: h2/s2..s6, h3/s3..s6, h4/s4..s6." |
| }), |
| "skip_indices": ("STRING", {"default": "", "multiline": False, "tooltip": "Explicit Skip Mode: indices to skip, e.g. 'h2, 3, 4, 7'. First hN selects predictor (defaults to h2). Indices are 0-based after slicing (start/end), 0/1 never skipped; final step may be. When non-empty, this overrides and nullifies other skip/adaptive/history controls."}), |
| "anchor_interval": ("INT", {"default": 4, "min": 0, "max": 100, "tooltip": "Absolute cadence: force a REAL call on every Nth step index counted from the end of the protected warmup (protect_first_steps). Set 0 to disable anchors. (adaptive only)"}), |
| "max_consecutive_skips": ("INT", {"default": 4, "min": 1, "max": 100, "tooltip": "Local cap: maximum back-to-back skips allowed; resets immediately after any REAL call. (adaptive only)"}), |
| |
| "start_at_step": ("INT", {"default": -1, "min": -1, "max": 10000, "tooltip": "Start denoising at this step index (−1 = start from 0)."}), |
| "end_at_step": ("INT", {"default": -1, "min": -1, "max": 10000, "tooltip": "End denoising at this step index inclusive (−1 = use full schedule). When set and less than last step, forces final sigma to 0."}), |
| "add_noise": ("FLOAT", { |
| "default": 0.0, |
| "min": 0.0, |
| "max": 1.0, |
| "step": 0.01, |
| "tooltip": "Add per-step stochastic noise. 0.0 = no noise (deterministic). 1.0 = maximum ancestral noise for the step. Values in between scale the amount of new noise injected each step." |
| }), |
| "noise_type": (["whitened", "gaussian"], { |
| "default": "whitened", |
| "tooltip": "Noise sampler for add_noise: 'whitened' (res4lyf style: normalize to unit variance each step) or 'gaussian' (official KSampler style: raw randn). Ratio still controls σ_up." |
| }), |
| "denoise": ("FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0}), |
| "verbose": ("BOOLEAN", {"default": False, "tooltip": "Verbose debug logging (per-step sampler details). Timing is always shown."}), |
| |
| "no_grad": ("BOOLEAN", {"default": True, "tooltip": "Run sampling under torch.no_grad (Comfy parity). Disable only for debugging/experiments."}), |
| "official_comfy": ("BOOLEAN", {"default": True, "tooltip": "When enabled, use algorithms that mirror official Comfy samplers/schedulers; when disabled, use res4lyf or other variants."}), |
| "sigma_aware": ("BOOLEAN", {"default": False, "tooltip": "Use actual sigma coordinates for extrapolation instead of assuming uniform step spacing. May improve prediction accuracy with non-uniform schedulers (karras, bong_tangent, exponential, etc.)."}), |
| "extrapolate_denoised": ("BOOLEAN", {"default": False, "tooltip": "Extrapolate the model's denoised output instead of epsilon. Denoised converges smoothly toward the clean image, potentially improving skip predictions."}), |
| }, |
| } |
|
|
| RETURN_TYPES = ("LATENT", "STRING") |
| RETURN_NAMES = ("samples", "metadata") |
| FUNCTION = "sample" |
| CATEGORY = "sampling/custom_sampling" |
|
|
| def sample(self, model, positive, negative, latent_image, seed, steps, cfg, |
| scheduler, sampler, adaptive_mode, smoothing_beta, skip_mode, skip_indices, anchor_interval, max_consecutive_skips, protect_first_steps, protect_last_steps, start_at_step, end_at_step, add_noise, noise_type, denoise, verbose, no_grad, official_comfy, sigma_aware=False, extrapolate_denoised=False): |
| |
| def _build_sigmas(n_steps: int): |
| if scheduler == "bong_tangent": |
| |
| if official_comfy: |
| from .comfy_copy.official_schedulers import get_bong_tangent_sigmas_official |
| s = get_bong_tangent_sigmas_official(model, n_steps) |
| else: |
| from .comfy_copy.res4lyf_schedulers import get_bong_tangent_sigmas |
| s = get_bong_tangent_sigmas(model, n_steps) |
| |
| try: |
| if float(s[-1]) != 0.0: |
| import torch as _torch |
| s = _torch.cat([s, _torch.tensor([0.0], dtype=s.dtype)]) |
| except Exception: |
| pass |
| return s |
| elif scheduler == "bong_tangent_2": |
| from .comfy_copy.res4lyf_schedulers import get_bong_tangent_2_sigmas |
| s = get_bong_tangent_2_sigmas(model, n_steps) |
| try: |
| if float(s[-1]) != 0.0: |
| import torch as _torch |
| s = _torch.cat([s, _torch.tensor([0.0], dtype=s.dtype)]) |
| except Exception: |
| pass |
| return s |
| elif scheduler == "bong_tangent_2_simple": |
| from .comfy_copy.res4lyf_schedulers import get_bong_tangent_2_simple_sigmas |
| s = get_bong_tangent_2_simple_sigmas(model, n_steps) |
| try: |
| if float(s[-1]) != 0.0: |
| import torch as _torch |
| s = _torch.cat([s, _torch.tensor([0.0], dtype=s.dtype)]) |
| except Exception: |
| pass |
| return s |
| elif scheduler == "constant": |
| from .comfy_copy.res4lyf_schedulers import get_constant_sigmas |
| s = get_constant_sigmas(model, n_steps) |
| try: |
| if float(s[-1]) != 0.0: |
| import torch as _torch |
| s = _torch.cat([s, _torch.tensor([0.0], dtype=s.dtype)]) |
| except Exception: |
| pass |
| return s |
| else: |
| return get_sigma_schedule(model, scheduler, n_steps) |
|
|
| |
| if denoise < 1.0: |
| if denoise <= 0.0: |
| return (latent_image,) |
| |
| total_steps_for_schedule = int(steps / denoise) |
| if total_steps_for_schedule <= 0: |
| return (latent_image,) |
| sigmas_full = _build_sigmas(total_steps_for_schedule) |
| |
| if len(sigmas_full) >= (steps + 1): |
| sigmas = sigmas_full[-(steps + 1):] |
| else: |
| sigmas = sigmas_full |
| else: |
| sigmas = _build_sigmas(steps) |
|
|
| if len(sigmas) == 0: |
| return (latent_image,) |
|
|
| |
| if end_at_step is not None and end_at_step >= 0: |
| if end_at_step < (len(sigmas) - 1): |
| sigmas = sigmas[:end_at_step + 1] |
| |
| if len(sigmas) > 0: |
| sigmas[-1] = 0.0 |
|
|
| |
| if start_at_step is not None and start_at_step >= 0: |
| if start_at_step < (len(sigmas) - 1): |
| sigmas = sigmas[start_at_step:] |
| else: |
| |
| return (latent_image,) |
|
|
| |
| latent = comfy.sample.fix_empty_latent_channels(model, latent_image["samples"]) |
|
|
| |
| torch.manual_seed(seed) |
| noise = torch.randn_like(latent) |
|
|
| |
| total_steps = max(0, len(sigmas) - 1) |
| preview_callback = _make_safe_preview_callback(model, total_steps) |
|
|
| timestamp_start = time.time() |
|
|
| samples = sample_fsampler( |
| model_patcher=model, |
| noise=noise, |
| sigmas=sigmas, |
| positive_conditioning=positive, |
| negative_conditioning=negative, |
| cfg_scale=cfg, |
| latent_image=latent, |
| sampler=sampler, |
| adaptive_mode=adaptive_mode, |
| smoothing_beta=smoothing_beta, |
| skip_mode=skip_mode, |
| skip_indices=skip_indices, |
| add_noise_ratio=add_noise, |
| add_noise_type=noise_type, |
| scheduler=scheduler, |
| start_at_step=start_at_step, |
| end_at_step=end_at_step, |
| denoise=denoise, |
| debug=bool(verbose), |
| callback=preview_callback, |
| protect_first_steps=protect_first_steps, |
| protect_last_steps=protect_last_steps, |
| anchor_interval=anchor_interval, |
| max_consecutive_skips=max_consecutive_skips, |
| use_no_grad=bool(no_grad), |
| official_comfy=bool(official_comfy), |
| seed=seed, |
| timestamp_start=timestamp_start, |
| sigma_aware=bool(sigma_aware), |
| extrapolate_denoised=bool(extrapolate_denoised), |
| ) |
|
|
| |
| if isinstance(samples, tuple): |
| samples, metadata = samples |
| else: |
| metadata = {} |
|
|
| |
| import json |
| metadata_json = json.dumps(metadata) if metadata else "" |
|
|
| return ({"samples": samples}, metadata_json) |
|
|
|
|
| class FSampler: |
| @classmethod |
| def INPUT_TYPES(s): |
| return { |
| "required": { |
| "model": ("MODEL",), |
| "positive": ("CONDITIONING",), |
| "negative": ("CONDITIONING",), |
| "latent_image": ("LATENT",), |
| "seed": ("INT", {"default": 0, "min": 0, "max": 0xffffffffffffffff}), |
| "steps": ("INT", {"default": 25, "min": 1, "max": 150}), |
| "cfg": ("FLOAT", {"default": 1.00, "min": 0.00, "max": 100.00, "step": 0.05}), |
| "scheduler": (FSAMPLER_AVAILABLE_SCHEDULERS, {"default": "simple"}), |
| "sampler": (["euler", "res_2m", "res_2s", "ddim", "dpmpp_2m", "dpmpp_2s", "lms", "res_multistep", "res_multistep_ancestral", "heun", "gradient_estimation"], {"default": "euler"}), |
| "skip_mode": ([ |
| "none", |
| |
| "h2/s2", "h2/s3", "h2/s4", "h2/s5", |
| |
| "h3/s3", "h3/s4", "h3/s5", |
| |
| "h4/s4", "h4/s5", |
| "adaptive" |
| ], {"default": "none"}), |
| "add_noise": ("FLOAT", {"default": 0.0, "min": 0.0, "max": 1.0, "step": 0.05, "tooltip": "Ancestral noise ratio (eta). 0.0 = ODE (no noise), >0 enables ancestral noise with dynamic sigma_up each step. Noise type is fixed to gaussian in this simple node."}), |
| "denoise": ("FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01, "tooltip": "Denoise fraction (KSampler-style). 1.0 = full schedule; <1.0 samples the last portion of the schedule only."}), |
| "verbose": ("BOOLEAN", {"default": False}), |
| } |
| } |
|
|
| RETURN_TYPES = ("LATENT",) |
| FUNCTION = "sample" |
| CATEGORY = "sampling/custom_sampling" |
|
|
| def sample(self, model, positive, negative, latent_image, seed, steps, cfg, |
| scheduler, sampler, skip_mode, add_noise, denoise, verbose): |
| |
| def _build_sigmas(n_steps: int): |
| if scheduler == "bong_tangent": |
| from .comfy_copy.res4lyf_schedulers import get_bong_tangent_sigmas |
| s = get_bong_tangent_sigmas(model, n_steps) |
| try: |
| if float(s[-1]) != 0.0: |
| import torch as _torch |
| s = _torch.cat([s, _torch.tensor([0.0], dtype=s.dtype)]) |
| except Exception: |
| pass |
| return s |
| elif scheduler == "bong_tangent_2": |
| from .comfy_copy.res4lyf_schedulers import get_bong_tangent_2_sigmas |
| s = get_bong_tangent_2_sigmas(model, n_steps) |
| try: |
| if float(s[-1]) != 0.0: |
| import torch as _torch |
| s = _torch.cat([s, _torch.tensor([0.0], dtype=s.dtype)]) |
| except Exception: |
| pass |
| return s |
| elif scheduler == "bong_tangent_2_simple": |
| from .comfy_copy.res4lyf_schedulers import get_bong_tangent_2_simple_sigmas |
| s = get_bong_tangent_2_simple_sigmas(model, n_steps) |
| try: |
| if float(s[-1]) != 0.0: |
| import torch as _torch |
| s = _torch.cat([s, _torch.tensor([0.0], dtype=s.dtype)]) |
| except Exception: |
| pass |
| return s |
| elif scheduler == "constant": |
| from .comfy_copy.res4lyf_schedulers import get_constant_sigmas |
| s = get_constant_sigmas(model, n_steps) |
| try: |
| if float(s[-1]) != 0.0: |
| import torch as _torch |
| s = _torch.cat([s, _torch.tensor([0.0], dtype=s.dtype)]) |
| except Exception: |
| pass |
| return s |
| else: |
| return get_sigma_schedule(model, scheduler, n_steps) |
|
|
| |
| if denoise < 1.0: |
| if denoise <= 0.0: |
| return (latent_image,) |
| total_steps_for_schedule = int(steps / denoise) |
| if total_steps_for_schedule <= 0: |
| return (latent_image,) |
| sigmas_full = _build_sigmas(total_steps_for_schedule) |
| |
| if len(sigmas_full) >= (steps + 1): |
| sigmas = sigmas_full[-(steps + 1):] |
| else: |
| sigmas = sigmas_full |
| else: |
| sigmas = _build_sigmas(steps) |
| if len(sigmas) == 0: |
| return (latent_image,) |
|
|
| |
| latent = comfy.sample.fix_empty_latent_channels(model, latent_image["samples"]) |
|
|
| torch.manual_seed(seed) |
| noise = torch.randn_like(latent) |
|
|
| |
| adaptive_mode = "learning" |
| smoothing_beta = 0.9999 |
| protect_first_steps = 2 |
| protect_last_steps = 3 |
| add_noise_ratio = float(add_noise) |
| add_noise_type = "gaussian" |
| denoise = float(denoise) |
| anchor_interval = 4 |
| max_consecutive_skips = 4 |
|
|
| |
| total_steps = max(0, len(sigmas) - 1) |
| preview_callback = _make_safe_preview_callback(model, total_steps) |
|
|
| samples = sample_fsampler( |
| model_patcher=model, |
| noise=noise, |
| sigmas=sigmas, |
| positive_conditioning=positive, |
| negative_conditioning=negative, |
| cfg_scale=cfg, |
| latent_image=latent, |
| sampler=sampler, |
| adaptive_mode=adaptive_mode, |
| smoothing_beta=smoothing_beta, |
| skip_mode=skip_mode, |
| add_noise_ratio=add_noise_ratio, |
| add_noise_type=add_noise_type, |
| scheduler=scheduler, |
| start_at_step=None, |
| end_at_step=None, |
| denoise=denoise, |
| debug=bool(verbose), |
| callback=preview_callback, |
| protect_first_steps=protect_first_steps, |
| protect_last_steps=protect_last_steps, |
| anchor_interval=anchor_interval, |
| max_consecutive_skips=max_consecutive_skips, |
| use_no_grad=True, |
| official_comfy=True, |
| sigma_aware=True, |
| extrapolate_denoised=True, |
| ) |
|
|
| |
| if isinstance(samples, tuple): |
| samples, metadata = samples |
|
|
| return ({"samples": samples},) |
|
|
|
|
| class FSamplerSelect: |
| """Outputs SAMPLER + SIGMAS for use with KSamplerCustom (SamplerCustom). |
| |
| Plug SAMPLER into KSamplerCustom's 'sampler' input and SIGMAS into 'sigmas'. |
| KSamplerCustom handles model, conditioning, cfg, noise, and latent. |
| """ |
|
|
| @classmethod |
| def INPUT_TYPES(s): |
| return { |
| "required": { |
| "model": ("MODEL", {"tooltip": "Model (needed to compute sigma schedule)."}), |
| "steps": ("INT", {"default": 25, "min": 1, "max": 150}), |
| "scheduler": (FSAMPLER_AVAILABLE_SCHEDULERS, {"default": "simple"}), |
| "sampler": (["euler", "res_2m", "res_2s", "ddim", "dpmpp_2m", "dpmpp_2s", "lms", "res_multistep", "res_multistep_ancestral", "heun", "gradient_estimation"], { |
| "default": "euler", |
| "tooltip": "Sampling method" |
| }), |
| "denoise": ("FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}), |
| "skip_mode": ([ |
| "none", |
| "h2/s2", "h2/s3", "h2/s4", "h2/s5", |
| "h3/s3", "h3/s4", "h3/s5", |
| "h4/s4", "h4/s5", |
| "adaptive" |
| ], { |
| "default": "none", |
| "tooltip": "Skipping: hN/sK with N=history (2=linear,3=Richardson,4=cubic) and K=calls before skip." |
| }), |
| "skip_indices": ("STRING", {"default": "", "multiline": False, "tooltip": "Explicit skip indices (e.g. 'h2, 3, 4, 7'). Overrides skip_mode when non-empty."}), |
| "adaptive_mode": (["none", "learning", "grad_est", "learn+grad_est"], { |
| "default": "none", |
| "tooltip": "Adaptive skip corrections: none=off; learning=EMA L stabilizer; grad_est=gradient-estimation correction; learn+grad_est=both." |
| }), |
| "smoothing_beta": ("FLOAT", { |
| "default": 0.9990, |
| "min": 0.0, |
| "max": 0.9999, |
| "step": 0.0001, |
| "tooltip": "EMA smoothing for learning mode." |
| }), |
| "protect_first_steps": ("INT", {"default": 2, "min": 0, "max": 20, "tooltip": "Initial steps never skipped (warmup)."}), |
| "protect_last_steps": ("INT", {"default": 2, "min": 1, "max": 100, "tooltip": "Final steps never skipped."}), |
| "anchor_interval": ("INT", {"default": 4, "min": 0, "max": 100, "tooltip": "Force REAL call every Nth step (adaptive only). 0=disable."}), |
| "max_consecutive_skips": ("INT", {"default": 4, "min": 1, "max": 100, "tooltip": "Max back-to-back skips (adaptive only)."}), |
| "add_noise": ("FLOAT", {"default": 0.0, "min": 0.0, "max": 1.0, "step": 0.01, "tooltip": "Per-step stochastic noise ratio. 0=deterministic."}), |
| "noise_type": (["whitened", "gaussian"], {"default": "whitened", "tooltip": "Noise sampling method for add_noise."}), |
| "verbose": ("BOOLEAN", {"default": False, "tooltip": "Verbose debug logging."}), |
| "no_grad": ("BOOLEAN", {"default": True, "tooltip": "Run under torch.no_grad (Comfy parity)."}), |
| "official_comfy": ("BOOLEAN", {"default": True, "tooltip": "Use official Comfy algorithm variants."}), |
| "sigma_aware": ("BOOLEAN", {"default": False, "tooltip": "Use actual sigma coordinates for extrapolation instead of assuming uniform step spacing. May improve prediction accuracy with non-uniform schedulers (karras, bong_tangent, exponential, etc.)."}), |
| "extrapolate_denoised": ("BOOLEAN", {"default": False, "tooltip": "Extrapolate the model's denoised output instead of epsilon. Denoised converges smoothly toward the clean image, potentially improving skip predictions."}), |
| } |
| } |
|
|
| RETURN_TYPES = ("SAMPLER", "SIGMAS") |
| RETURN_NAMES = ("sampler", "sigmas") |
| FUNCTION = "get_sampler" |
| CATEGORY = "sampling/custom_sampling" |
|
|
| def get_sampler(self, model, steps, scheduler, sampler, denoise, |
| skip_mode, skip_indices, adaptive_mode, smoothing_beta, |
| protect_first_steps, protect_last_steps, |
| anchor_interval, max_consecutive_skips, |
| add_noise, noise_type, verbose, no_grad, official_comfy, |
| sigma_aware=False, extrapolate_denoised=False): |
|
|
| |
| def _build_sigmas(n_steps): |
| if scheduler == "bong_tangent": |
| if official_comfy: |
| from .comfy_copy.official_schedulers import get_bong_tangent_sigmas_official |
| s = get_bong_tangent_sigmas_official(model, n_steps) |
| else: |
| from .comfy_copy.res4lyf_schedulers import get_bong_tangent_sigmas |
| s = get_bong_tangent_sigmas(model, n_steps) |
| try: |
| if float(s[-1]) != 0.0: |
| s = torch.cat([s, torch.tensor([0.0], dtype=s.dtype)]) |
| except Exception: |
| pass |
| return s |
| elif scheduler == "bong_tangent_2": |
| from .comfy_copy.res4lyf_schedulers import get_bong_tangent_2_sigmas |
| s = get_bong_tangent_2_sigmas(model, n_steps) |
| try: |
| if float(s[-1]) != 0.0: |
| s = torch.cat([s, torch.tensor([0.0], dtype=s.dtype)]) |
| except Exception: |
| pass |
| return s |
| elif scheduler == "bong_tangent_2_simple": |
| from .comfy_copy.res4lyf_schedulers import get_bong_tangent_2_simple_sigmas |
| s = get_bong_tangent_2_simple_sigmas(model, n_steps) |
| try: |
| if float(s[-1]) != 0.0: |
| s = torch.cat([s, torch.tensor([0.0], dtype=s.dtype)]) |
| except Exception: |
| pass |
| return s |
| elif scheduler == "constant": |
| from .comfy_copy.res4lyf_schedulers import get_constant_sigmas |
| s = get_constant_sigmas(model, n_steps) |
| try: |
| if float(s[-1]) != 0.0: |
| s = torch.cat([s, torch.tensor([0.0], dtype=s.dtype)]) |
| except Exception: |
| pass |
| return s |
| else: |
| return get_sigma_schedule(model, scheduler, n_steps) |
|
|
| if denoise < 1.0 and denoise > 0.0: |
| total_steps_for_schedule = int(steps / denoise) |
| if total_steps_for_schedule <= 0: |
| total_steps_for_schedule = 1 |
| sigmas_full = _build_sigmas(total_steps_for_schedule) |
| if len(sigmas_full) >= (steps + 1): |
| sigmas = sigmas_full[-(steps + 1):] |
| else: |
| sigmas = sigmas_full |
| else: |
| sigmas = _build_sigmas(steps) |
|
|
| |
| timestamp_start = time.time() |
| ksampler = create_fsampler_ksampler( |
| sampler=sampler, |
| adaptive_mode=adaptive_mode, |
| smoothing_beta=smoothing_beta, |
| skip_mode=skip_mode, |
| skip_indices=skip_indices, |
| add_noise_ratio=add_noise, |
| add_noise_type=noise_type, |
| scheduler=scheduler, |
| denoise=denoise, |
| debug=bool(verbose), |
| protect_first_steps=protect_first_steps, |
| protect_last_steps=protect_last_steps, |
| anchor_interval=anchor_interval, |
| max_consecutive_skips=max_consecutive_skips, |
| use_no_grad=bool(no_grad), |
| official_comfy=bool(official_comfy), |
| timestamp_start=timestamp_start, |
| sigma_aware=bool(sigma_aware), |
| extrapolate_denoised=bool(extrapolate_denoised), |
| ) |
|
|
| return (ksampler, sigmas) |
|
|
|
|
| NODE_CLASS_MAPPINGS = { |
| "FSamplerAdvanced": FSamplerAdvanced, |
| "FSampler": FSampler, |
| "FSamplerSelect": FSamplerSelect, |
| } |
|
|
| NODE_DISPLAY_NAME_MAPPINGS = { |
| "FSamplerAdvanced": "FSampler Advanced", |
| "FSampler": "FSampler", |
| "FSamplerSelect": "FSampler Select", |
| } |
|
|