ComfyUI Sampler Configuration and Scheduling: A Complete Technical Guide
ComfyUI separates the sampler algorithm (the ODE/SDE integrator) from the noise schedule (sigma values), with the KSampler class in comfy/samplers.py orchestrating both components at runtime.
ComfyUI's sampling pipeline is a two-layer architecture that decouples the numerical integration method from the noise schedule generation. Understanding how sampler configuration and scheduling interact is essential for customizing diffusion workflows in the Comfy-Org/ComfyUI repository. The system uses modular handlers and factory functions to assemble these components dynamically based on UI selections.
Sampler Selection: Mapping Names to Algorithms
The sampler determines the numerical method used to solve the diffusion ODE or SDE. ComfyUI implements a factory pattern to resolve sampler names into executable functions.
sampler_object(name) serves as the primary factory function in comfy/samplers.py (lines 100-112). It accepts a string identifier such as "euler", "dpm_fast", or "uni_pc" and returns a KSAMPLER instance. This object wraps the low-level sampling function imported from k_diffusion.sampling and stores any extra options or inpaint-specific configurations.
The KSAMPLER class (lines 28-55 in comfy/samplers.py) inherits from the base Sampler class and holds the concrete sampler_function attribute. Its sample() method prepares the model wrapper, initializes noise tensors, and invokes the wrapped function. Supported identifiers are maintained in the SAMPLER_NAMES list (lines 22-27), which acts as a whitelist for the UI dropdown.
Scheduler Configuration: Generating Sigma Schedules
While the sampler defines how to step through the diffusion process, the scheduler defines when by producing the sigma (σ) values that control noise levels.
SCHEDULER_HANDLERS (lines 78-90 in comfy/samplers.py) maps human-readable names like "simple", "karras", and "ddim_uniform" to SchedulerHandler objects. Each handler encapsulates a scheduling function and a flag indicating whether it requires the full model_sampling object (use_ms=True) or raw (n, sigma_min, sigma_max) arguments.
Concrete implementations include:
simple_scheduler(lines 5-12): Linear interpolation between sigma max and minddim_scheduler(lines 84-88): Uniform steps compatible with DDIM samplingnormal_scheduler(lines 131-151): Standard log-normal spacing used by many legacy models
The calculate_sigmas function (lines 92-100) looks up the appropriate handler and returns a torch.FloatTensor of sigma values. The KSampler.calculate_sigmas method extends this with logic to discard penultimate sigmas for specific samplers (like dpm_2 and uni_pc) and applies user-defined denoise factors that truncate the schedule.
End-to-End Sampling Execution
When a workflow node executes, the system follows this precise pipeline:
- Configuration: The
KSamplerclass stores the selectedsamplerandschedulernames during initialization. - Sigma Generation:
KSampler.calculate_sigmasbuilds the sigma tensor by queryingSCHEDULER_HANDLERSand invokes the scheduling function. - Sampler Instantiation:
sampler_object()creates theKSAMPLERwrapper around the low-level function (e.g.,k_diffusion_sampling.sample_euler). - Conditioning Preparation: The
sampling_functionincomfy/samplers.pymerges positive and negative conditionings and applies classifier-free guidance viacfg_function. - Iteration: The low-level sampler in
comfy/k_diffusion/sampling.pyiterates over the sigma list, computing denoised predictions and advancing the latent state using the appropriate ODE/SDE step.
Practical Code Examples
Creating a KSampler Programmatically
import torch
from comfy.samplers import KSampler, sampler_object
device = torch.device("cuda")
steps = 20
sampler_name = "euler"
scheduler_name = "karras"
# Initialize the high-level KSampler
k = KSampler(model, steps, device, sampler=sampler_name, scheduler=scheduler_name)
# Generate noise and sample
noise = torch.randn(1, 4, 64 // 8, 64 // 8, device=device)
latent = k.sample(noise, positive, negative, cfg=7.5, seed=42)
This example demonstrates how KSampler.__init__ automatically calls calculate_sigmas to build the schedule, while k.sample handles the CFGGuider instantiation and conditioning preparation.
Adding a Custom Scheduler
from comfy.samplers import SCHEDULER_HANDLERS, SchedulerHandler
import torch
def my_linear_scheduler(model_sampling, steps):
sigma_max = model_sampling.sigma_max
sigma_min = model_sampling.sigma_min
return torch.linspace(sigma_max, sigma_min, steps + 1)
# Register with use_ms=True to receive model_sampling object
SCHEDULER_HANDLERS["my_linear"] = SchedulerHandler(my_linear_scheduler)
# Use in subsequent KSampler instances
k = KSampler(model, steps=30, device=device, sampler="dpm_fast", scheduler="my_linear")
Inspecting Generated Sigma Values
k = KSampler(model, steps=10, device=device, sampler="euler", scheduler="ddim_uniform")
print(k.sigmas) # Shape [11], ending with 0.0
Key Source Files
Understanding the repository structure helps navigate the codebase:
comfy/samplers.py: Core dispatcher containingKSampler,sampler_object,calculate_sigmas,SAMPLER_NAMES,SCHEDULER_HANDLERS, and CFG handling logic.comfy/sampler_helpers.py: Utilities for conditioning preparation (process_conds,prepare_sampling), model loading bookkeeping, and memory estimation.comfy/k_diffusion/sampling.py: Low-level diffusion step implementations includingsample_euler,sample_heun, andsample_dpm_2.comfy/model_sampling.py: Provides theModelSamplingobject supplyingsigma_min,sigma_max, andpercent_to_sigmautilities used by schedulers.
Summary
- ComfyUI sampler configuration relies on
sampler_object()to map names toKSAMPLERinstances that wrap low-level ODE/SDE solvers. - Scheduling is handled by
SCHEDULER_HANDLERS, which dispatch to functions likesimple_schedulerorkarras_schedulerto generate sigma tensors. - The
KSamplerclass orchestrates both components, managing sigma calculation, classifier-free guidance, and the iterative sampling loop. - Custom schedulers register via
SchedulerHandlerobjects inSCHEDULER_HANDLERSfor immediate integration with existing samplers. - Low-level sampling algorithms reside in
comfy/k_diffusion/sampling.py, completely decoupled from schedule generation logic.
Frequently Asked Questions
What is the difference between a sampler and a scheduler in ComfyUI?
A sampler is the numerical algorithm that solves the diffusion equation (such as Euler or DPM-Solver), while a scheduler generates the sequence of noise levels (sigma values) that the sampler uses to guide the denoising process. The sampler determines how to step, and the scheduler determines where to step in the noise space.
How do I add a custom noise scheduler to ComfyUI?
Define a function that accepts model_sampling and steps arguments and returns a torch.FloatTensor of sigma values. Wrap this function in a SchedulerHandler with use_ms=True and register it in SCHEDULER_HANDLERS under a unique name. The scheduler becomes immediately available to all KSampler instances without modifying core code.
Where are the low-level sampling algorithms implemented in ComfyUI?
The actual diffusion step implementations reside in comfy/k_diffusion/sampling.py, which contains functions like sample_euler, sample_heun, and sample_dpm_2. These functions operate on the sigma schedule provided by KSampler and are wrapped by the KSAMPLER class for integration with ComfyUI's conditioning and guidance systems.
How does ComfyUI handle classifier-free guidance (CFG) during sampling?
CFG is applied in the sampling_function within comfy/samplers.py before the sampler executes each step. The system uses cfg_function to combine positive and negative conditionings based on the user-provided cfg scale, then passes the conditioned prediction to the low-level sampler algorithm for the actual latent update.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →