Adaptive Sampler Custom
The sampler that decides its own step count
- noise
- guider
- sampler
- latent_image
- output
- denoised
- sigmas
Every sampler you've ever used works on a sigma schedule you hand it: 20 steps, 30 steps, spread evenly. Adaptive Sampler Custom throws that out. It decides its own step count as it goes, taking tiny steps when the denoising direction is changing fast and leaping forward when it's settled. If you've ever stared at a 40-step Anima render and suspected the last 25 steps did almost nothing - this node is aimed squarely at you.
It's a niche tool, built and tested by one person against one model, but the idea is genuinely useful for flow-matching models (Anima, Qwen-Image and friends) whose sampling trajectories have "easy" and "hard" regions that a fixed schedule can't know about in advance. You get precision where it matters and speed where it doesn't, from one sampler instead of a grid of step counts.
How it actually works
Adaptive Sampler Custom isn't a sampler in its own right - it's a wrapper. You give it a regular sampler (the sampler input), and it calls that sampler one step at a time inside a loop, deciding how big each step should be. That's why it lives in sampling/custom_sampling: wire it like you would SamplerCustom, not like a KSampler.
At each step it computes the "velocity" v = denoised - x - the direction the latent is being pushed. Then it compares that velocity to the previous step's:
- cosine (
error_typedefault): measures how much the direction changed - mse: measures how much the magnitude changed
Big change means the model is actively working - so the next step shrinks. Stable velocity means it's coasting - so the step grows. The formula is new_step_size = base_step_size / (error + error_bias), blended with the old value via smoothing_coef (0.0 default = trust the new value entirely), and clamped between min_step_size and max_step_size. The loop runs until sigma bottoms out or max_steps is hit.
The inputs that matter
You'll actually touch four of these:
- error_type - cosine or mse. Start with cosine (the default); it reacts to turns, not just speed.
- min_step_size / max_step_size - the guardrails. These clamp how fine or coarse the adaptive logic can get.
- max_steps - your real budget. The loop stops here even if sigma hasn't bottomed out, so this is what protects your render time.
- smoothing_coef - an EMA. 0.0 reacts instantly (default), 1.0 never changes. A little smoothing (0.3–0.5) stops the step size from sawtoothing on noisy error readings.
One trap hiding in the defaults: base_step_size is 0.0004, which is smaller than min_step_size (0.005). Run the math on base / (error + bias) and you'll find most steps land on the minimum. The defaults basically mean "fine steps, always" - if you want the adaptive part to actually breathe, raise base_step_size or raise max_steps and lower min_step_size. The shipped example workflow (in anima_00321_.png in the repo) runs euler on Anima at all defaults, so defaults do work - they just lean cautious.
Outputs and wiring
Three outputs: output (the finished latent - wire it to VAEDecode), denoised (the model's predicted clean latent, handy for preview nodes), and sigmas (the sigma schedule it actually used - the author's example wires this into a SigmasPreview so you can watch it adapt).
Installing
No dependencies, no model downloads, nothing to pip. It's one Python file wrapping ComfyUI's own sampler internals. Either:
- ComfyUI Manager - search "ComfyUI-Sampler-Adaptive" and install, or
cd ComfyUI/custom_nodes && git clone https://github.com/levzzz5154/ComfyUI-Sampler-Adaptive
then restart ComfyUI. That's it.
What will bite you
The README is admirably honest about the limits, and they're real. Ancestral samplers (euler_ancestral, dpmpp_2s_ancestral) don't work correctly. Multistep/stateful samplers (dpmpp_2m, lms, ipndm, dpmpp_2m_sde) degrade to first-order behavior - use stateless ones like euler, heun, or dpm_2. RES4LYF samplers aren't supported - worth knowing since RES4LYF is the 2026 sampler-tuning mainstream, but this node's whole pitch is "no tuning", so it's not as contradictory as it sounds.
Also: the code reaches into ComfyUI internals (KSAMPLER, latent_preview, comfy.sample), so a ComfyUI update can quietly break it, and it prints a Step N: sigma=…, step_size=… line to the console on every single step - that wall of text is normal, not a crash. And remember it was "mainly tested with the Anima model." On SDXL it should run, but the defaults were tuned against flow-matching sigma ranges, so treat your results with suspicion until you've eyeballed the SigmasPreview.
Inputs (12)
| Name | Type | Default | Description |
|---|---|---|---|
| noise | NOISE | — | |
| guider | GUIDER | — | |
| sampler | SAMPLER | — | |
| latent_image | LATENT | — | |
| denoise | FLOAT | 1.000–1 | Denoising strength (1.0 = full) |
| error_type | COMBO | cosine | cosine: measure direction change, mse: measure magnitude change |
| base_step_size | FLOAT | 0.00040.0001–1 | Base multiplier for step size calculation |
| min_step_size | FLOAT | 0.00500.0001–1 | Minimum allowed step size |
| max_step_size | FLOAT | 0.2000.001–1 | Maximum allowed step size |
| max_steps | INT | 1001–10000 | Maximum number of adaptive steps |
| smoothing_coef | FLOAT | 0.000–1 | EMA coefficient: 0 = new value only, 1 = keep old value |
| error_bias | FLOAT | 0.000–1 | Bias added to error. Higher values = smaller steps |
Outputs (3)
| Name | Type | Description |
|---|---|---|
| output | LATENT | — |
| denoised | LATENT | — |
| sigmas | SIGMAS | — |