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 = Truemakescreate_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_samplerandhr_scheduler. The default is "Use same sampler" / "Use same scheduler" — seeget_hr_sampler_and_scheduler()inmodules/sd_samplers.py.
Integration points
processing.pycallscreate_sampler(p.sampler_name, model).cfg_denoisercallback (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/samplersand/sdapi/v1/schedulersendpoints expose the registries to clients.
Entry points for modification
- Add a new sampler — append a
SamplerData("MyName", MySamplerClass, aliases=[], options={})to one of thesamplers_data_*lists, or register from an extension at import time. - Add a new scheduler — append a
Scheduler(name=..., label=..., function=...)tosd_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_cfgcallbacks; do not subclassCFGDenoiserdirectly unless you're upstreaming a change. - Profile a sampler — toggle
opts.profile_torchand inspect the resultingtrace.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.
Previous
Models
Next
SD hijack