ComfyUI Node

Actual Denoise

Stop re-tuning denoise every time you switch schedulers

By mozhaa·Created 7 months ago·Updated 6 months ago· 20
Actual Denoise
  • model
  • scheduler
  • denoise
  • model
scheduler
actual_denoise1.000

If you've ever built an img2img workflow, swapped the scheduler from euler beta to kl_optimal, and watched the output change way more than the sampler swap alone explains, you already know the pain this node removes. Actual Denoise replaces the "denoise" value with an honest number - the actual amount of noise added to your image - that stays the same no matter which scheduler you pick. You stop re-finding the sweet spot every time you tinker.

The misconception that makes you retune

Here's the part the README beats you over the head with, and it's right: denoise is not "how much noise you add." KSampler uses it as a step-fraction. Set steps to 20 and denoise to 0.5 and ComfyUI computes total_steps = steps / denoise (40), then starts denoising at step 40 − 20. It skipped the first half of the trajectory.

The problem: what "halfway through the trajectory" looks like is different per scheduler. karras concentrates noise removal in the middle steps, exponential front-loads it, kl_optimal spends its early steps mostly polishing low-noise detail. So a denoise of 0.5 can genuinely mean "add half your maximum noise" on one scheduler and "add maybe a quarter" on another. That's why your 0.55 sweet spot on euler beta suddenly wants 0.6 on uni_pc kl_optimal. You weren't crazy; the number was lying to you.

What Actual Denoise does instead

It maps the other way. You pick actual_denoise - literally "start where the noise is at X% of its maximum" - and the node computes the denoise that gets KSampler to that exact point on the current scheduler's curve.

Under the hood it's small and clean: it builds a 1000-point sigma schedule for your model and scheduler via comfy.samplers.calculate_sigmas, finds the first step whose sigma drops below actual_denoise × max_sigma, and returns denoise = 1 − (that step / 1000). Same curve math ComfyUI itself uses, so no reimplementation drift. It reads the model's model_sampling and the scheduler's curve, does one lookup, hands you a number. That's the whole node - which is also why there's nothing to tune and nothing to break.

The inputs and outputs that matter

  • model - your checkpoint. This is what defines the sigma curve, so the mapping is model-specific.
  • scheduler - one of the nine stock schedulers (simple, sgm_uniform, karras, exponential, ddim_uniform, beta, normal, linear_quadratic, kl_optimal).
  • actual_denoise - 0 to 1, step 0.001. 1.0 is full noise (no change from txt2img); 0.5 means "half the maximum noise."

Outputs: scheduler, denoise, and model - wire all three straight into your KSampler's matching inputs and you're done. Yes, it passes the model through so you can keep the graph tidy; you never touch the model's own connection.

Installing it

No dependencies, no model files, no Python packages - this pack is a single nodes.py that only calls ComfyUI's own sampling code. Either route works:

  • ComfyUI Manager: open Manager → Custom Nodes Manager, search "Actual Denoise" (it's published on the Comfy registry), install, restart.
  • Manual clone:
cd ComfyUI/custom_nodes
git clone https://github.com/mozhaa/ComfyUI-Actual-Denoise

Then restart ComfyUI. The node shows up under sampling/custom_sampling/schedulers.

Gotchas and honest limits

First, actual_denoise is not your old denoise. 0.5 denoise maps to roughly 0.5 actual on a linear-ish schedule but closer to 0.2 on exponential and higher on karras. Don't guess - chain this with Actual Denoise Inverse once to translate a value you already trust. Second, the mapping is model-dependent: sigmas come from the checkpoint's model_sampling, so swap SDXL for a v-prediction or flow-matching model and a given actual_denoise isn't the same noise anymore. It still computes fine, but the "actual" framing gets fuzzier off DDPM models - the author built and tuned it on SDXL.

And it stabilizes the noise, not the whole render. Same actual noise with a different sampler still gives a different image, because samplers carve the trajectory differently. The author's r/comfyui post on this got a warm +78, and a top comment rightly pointed out RES4LYF ships DENOISE_ALT, which does adjacent math by multiplying the sigma schedule instead of splitting it - slightly different results, same spirit. For the day-to-day "I just want my img2img to survive a scheduler swap," this is the one you'll actually reach for.

Categorysampling/custom_sampling/schedulers

Inputs (3)

NameTypeDefaultDescription
modelMODEL
schedulerCOMBO9 options: simple, sgm_uniform, karras, exponential, ddim_uniform, beta, +3
actual_denoiseFLOAT1.0000–1

Outputs (3)

NameTypeDescription
schedulersimple,sgm_uniform,karras,exponential,ddim_uniform,beta,normal,linear_quadratic,kl_optimal
denoiseFLOAT
modelMODEL