😺NKD Sigmas Calibrate
Your scheduler dropdown is a guess — this node measures one for your model
- model
- positive
- negative
- latent_image
- vae
- profile
- latent
- image
Every scheduler in that dropdown is somebody else's average. Karras was tuned to correct a curved DDPM trajectory, which is why it still earns its keep on SDXL finetunes and falls flat on anything flow-matching - a reshaped sigma curve on a near-straight path distorts rather than corrects. So you sweep. Twenty steps, then thirty, beta, simple, sgm_uniform, one eye on the clock.
NKD Sigmas Calibrate does something dumber and better: it runs one long pass on the model you actually loaded and records how much the prediction moves at each noise level. Then a second node, Sigmas Equalize, spreads your steps over that measurement.
What it's actually measuring
The node takes your model, your positive and negative conditioning, and your scheduler and calib_steps, and runs one plain Euler pass. At every step it compares the predicted clean image (x0) against the previous step's, takes the RMS difference per sample, and averages over the batch. What comes out is a profile: the reference sigma list plus one number per interval, "how much did the image change here."
No pixels are decoded, no VAE needed, nothing trained. It only reads the model's own denoised prediction, which is why it works on any model ComfyUI can sample - including DiT and flow models that ship no Align Your Steps table to copy from. That's the real selling point. AYS tables exist for a handful of named checkpoints; this works on the one you fine-tuned last Tuesday with three LoRAs stacked on it.
The console prints the measured change for every step, and the shape is what you'd expect: big early moves, a long quiet tail. That asymmetry is why Equalize has a knob instead of a fixed answer.
The inputs that matter
latent_image sets the size of the measurement, and it needs to be the size you'll actually sample at. Its tooltip spells out the useful trick: a batch larger than 1 averages the profile over several seeds instead of trusting one.
cfg and the model input matter more than they look. The profile depends on your shift, your LoRAs, your CFG and your resolution, because all of those change how the model denoises. Calibrate with the same patches and settings you'll render with, or you're measuring a different model.
calib_steps (default 50) is the resolution of the measurement - more steps give a finer profile and take longer. scheduler is the reference schedule the pass runs on, and it's also exactly what you get back out of Equalize at equalize 0, which makes it a clean A/B.
There's no randomize control on seed, on purpose. A seed that rolled every run would throw the cached calibration away each time you touched anything.
Outputs
profile is a custom NKD_SIGMA_PROFILE type - only Sigmas Equalize, from this same pack, will eat it. Wire it there and you're done with this node.
latent and image are the result of the reference pass, so you have a baseline to eyeball your final render against. image needs the optional vae connected; without it you get a black placeholder, which is the intended behaviour, not a bug.
Install
ComfyUI Manager, search NKD Sigmas Curve, install, restart. Or by hand:
cd ComfyUI/custom_nodes
git clone https://github.com/Nekodificador/ComfyUI-NKD-Sigmas-Curve
No extra Python dependencies - the pack's pyproject.toml declares an empty dependency list and the code only imports torch and ComfyUI's own comfy modules. The fancy curve widget in the sibling node is pre-built and committed, so there's no npm step on install. Python 3.10+, and it uses the V3 node API, so keep ComfyUI reasonably current.
Where people get burned
- The cache is the feature, and it's also the trap. Calibrate re-runs whenever any input changes, including latent resolution, CFG and calib_steps. Change your size mid-session and you've silently bought another full reference pass. Budget for it once, then tune on Equalize.
- It's a probe, not an oracle. The per-step change is latent RMS, where fine detail at low sigma registers as almost nothing next to the early composition moves. Trust the profile, but don't hand it 100% of the decision - that's why Equalize defaults to
0.5rather than full equalisation. - Distilled models gain little. Lightning, Turbo and DMD variants have their schedule baked into the training; re-measuring it tends to just confirm
sgm_uniform. Same for their LoRAs. - Feed it your shift. On flow-matching models the timestep shift is where sampling effort actually goes, and it arrives as a model patch - so put
ModelSamplingAuraFlow(or whatever sets your shift) upstream ofmodelhere, or you're calibrating the wrong behavior.
Inputs (9)
| Name | Type | Default | Description |
|---|---|---|---|
| model | MODEL | — | |
| positive | CONDITIONING | — | |
| negative | CONDITIONING | — | |
| latent_image | LATENT | Same size you will sample at. A batch > 1 averages several seeds. | |
| seed | INT | 00–18446744073709550000 | — |
| cfg | FLOAT | 3.00–100 | — |
| scheduler | COMBO | simple | Reference schedule for the calibration pass; also the result at equalize 0 |
| calib_steps | INT | 504–500 | Steps of the reference pass. More = finer profile, slower |
| vaeopt | VAE | Connect to get the reference pass decoded on the image output |
Outputs (3)
| Name | Type | Description |
|---|---|---|
| profile | NKD_SIGMA_PROFILE | — |
| latent | LATENT | Result of the reference pass |
| image | IMAGE | Reference pass decoded (needs vae; black without it) |