Factory.ai

Open-Source Wikis

/

Stable Diffusion WebUI

/

Systems

/

Samplers and schedulers

AUTOMATIC1111/stable-diffusion-webui

Samplers and schedulers

Active contributors: AUTOMATIC1111, Kohaku-Blueleaf, brkirch, catboxanon, v0xie

Purpose

Wraps the various diffusion sampling algorithms (k-diffusion, LCM, DDIM-style timesteps, native DDPM) behind a uniform Sampler interface, and provides a separate set of "schedulers" — sigma-schedule strategies layered on top of the samplers. Both are driven from dropdowns in the UI and from Sampler / Schedule type keys in the API.

Until v1.9, sampler and scheduler were a single concept (Euler a Karras, DPM++ 2M Karras). v1.9 split them: any sampler can now be combined with any scheduler.

Directory layout

modules/
├── sd_samplers.py              # aggregate registry, lookup by name + scheduler resolution
├── sd_samplers_common.py       # shared base class, helpers, decode_first_stage
├── sd_samplers_kdiffusion.py   # the k-diffusion family (Euler, DPM++, UniPC, Restart, …)
├── sd_samplers_timesteps.py    # native UNet samplers (DDIM, PLMS, DDIM CFG++)
├── sd_samplers_timesteps_impl.py
├── sd_samplers_lcm.py          # Latent Consistency Model sampler
├── sd_samplers_extra.py        # Restart sampler (lambertae)
├── sd_samplers_cfg_denoiser.py # the CFG-applying wrapper around the UNet
├── sd_samplers_compvis.py      # legacy stub (empty file for back-compat)
└── sd_schedulers.py            # sigma schedules: Karras, Exponential, Polyexp, AYS, KL Optimal, …

Key abstractions

Type File Description
SamplerData modules/sd_samplers_common.py Tuple-like (name, constructor, aliases, options). Stored in the samplers_data_* lists.
Sampler (base) same Owns model_wrap_cfg, step, sample, sample_img2img. Subclasses fill in the actual algorithm.
KDiffusionSampler modules/sd_samplers_kdiffusion.py Uses the upstream k-diffusion library; per-algorithm subclass selected by name.
CompVisSampler modules/sd_samplers_timesteps.py DDIM/PLMS-style with explicit timesteps.
CFGDenoiser modules/sd_samplers_cfg_denoiser.py Wraps the UNet to apply classifier-free guidance, AND-composable diffusion, and the cfg_denoiser/cfg_denoised/cfg_after_cfg callbacks.
Scheduler modules/sd_schedulers.py Dataclass with name, label, function (sigma generator), aliases.
all_samplers, samplers, samplers_for_img2img modules/sd_samplers.py Public registries. samplers_for_img2img exists because some samplers don't make sense for img2img (e.g., LCM single-step).
create_sampler(name, model) same Factory used by processing.py.

Built-in samplers

From modules/sd_samplers_kdiffusion.py (most populated) and the timestep/LCM modules:

Sampler Source Notes
Euler / Euler a k-diffusion "a" = ancestral; the most common default
LMS, Heun k-diffusion Older second-order methods
DPM2, DPM2 a k-diffusion
DPM++ 2S a, DPM++ 2M, DPM++ SDE, DPM++ 2M SDE, DPM++ 3M SDE k-diffusion The "DPM-Solver" family; 2M is widely recommended for SDXL
DPM fast, DPM adaptive k-diffusion Auto-step variants
LMS Karras, DPM2 Karras, etc. k-diffusion Same algorithm + Karras schedule (legacy combined names; still parsed for back-compat)
Restart modules/sd_samplers_extra.py Periodic noise re-injection
UniPC k-diffusion Wenliang Zhao's unified predictor-corrector
DDIM, PLMS timesteps Original ldm samplers
DDIM CFG++ timesteps v1.10 addition (#16035)
LCM LCM module Single-step / few-step latent consistency

Schedulers

modules/sd_schedulers.py ships with:

Scheduler Notes
Automatic Fall back to whatever the sampler considers default
Uniform Linear in step index
Karras k-diffusion's Karras schedule, the long-standing default
Exponential Exponential decay
Polyexponential Polynomial-exponential blend
SGM Uniform SGM-style spacing
KL Optimal v1.10 (#15608)
Align Your Steps (AYS) v1.10 (#15751)
Simple v1.10 (#16142)
Normal v1.10 (#16149)
DDIM v1.10 (#16149)
Beta v1.10 (#16235)

The Schedule type is sent through the API as scheduler and stored in infotext as Schedule type:. For backward compatibility with old infotext strings like Sampler: Euler a Karras, sd_samplers.get_sampler_and_scheduler() parses the trailing scheduler suffix at read time.

How a sampler runs

graph LR
    subgraph processing.py
        A[StableDiffusionProcessing.sample] --> B[create_sampler]
    end

    B --> S[Sampler instance]
    S -->|uses| CFG[CFGDenoiser]
    CFG -->|inner| UNet[UNet forward]
    S -->|sigmas| Sched[Scheduler.function]
    S -->|step loop| Step
    Step -->|on_callback| EXT[script_callbacks.cfg_denoiser /<br/>cfg_denoised / cfg_after_cfg]

Sampler.sample(p, x, conditioning, ...) is invoked once per batch. It builds the sigma schedule from the chosen scheduler, runs the algorithm, and returns the denoised latents. CFGDenoiser is the bridge: at each step it combines conditional and unconditional UNet predictions, mixes in any AND-composable prompts, and fires the cfg_* callbacks so extensions can edit the prediction.

Extensions and custom samplers

Extensions can register additional samplers and schedulers via two callbacks in modules/script_callbacks.py:

  • on_list_optimizers — register a new attention optimisation (different from samplers, but related).
  • A new sampler is added by extending samplers_data_k_diffusion (or another list) at import time. For example, the LCM sampler ships as a built-in but uses the same registration pattern an extension would.

For schedulers, extensions can append to sd_schedulers.schedulers directly. This is how extensions-builtin/Lora/ does not currently work — Lora is purely a UNet patcher, not a sampler — but third-party extensions like AnimateDiff add new samplers this way.

Special handling

  • SDXL exclusion: SamplerData.options.no_sdxl = True makes create_sampler() raise. PLMS is excluded from SDXL because the model conditioning shape differs.
  • Sampler aliases: each sampler exposes aliases = [...] for old names. The API accepts any alias and translates to the canonical name. Until v1.10 the API returned 404 for unknown sampler names; v1.10 changed that to 400 (#16140).
  • Hires sampler: txt2img has a hr_sampler and hr_scheduler. The default is "Use same sampler" / "Use same scheduler" — see get_hr_sampler_and_scheduler() in modules/sd_samplers.py.

Integration points

  • processing.py calls create_sampler(p.sampler_name, model).
  • cfg_denoiser callback (in script-callbacks.md) is the primary extension point for "modify the noise prediction at every step" features (ControlNet, free-u, hyper-tile, …).
  • process_before_every_sampling (v1.10) lets extensions react each time a sampler is created (hires fix and refiner each create a new sampler).
  • The /sdapi/v1/samplers and /sdapi/v1/schedulers endpoints expose the registries to clients.

Entry points for modification

  • Add a new sampler — append a SamplerData("MyName", MySamplerClass, aliases=[], options={}) to one of the samplers_data_* lists, or register from an extension at import time.
  • Add a new scheduler — append a Scheduler(name=..., label=..., function=...) to sd_schedulers.schedulers. The function takes (n, sigma_min, sigma_max, device) and returns a 1-D tensor of sigmas.
  • Hook into denoising — use the cfg_denoiser / cfg_denoised / cfg_after_cfg callbacks; do not subclass CFGDenoiser directly unless you're upstreaming a change.
  • Profile a sampler — toggle opts.profile_torch and inspect the resulting trace.json. See how-to-contribute/debugging.md.

Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.

Samplers and schedulers – Stable Diffusion WebUI wiki | Factory