Nodes/koo-nodes-pack/KoO Noise Statistics
ComfyUI Node

KoO Noise Statistics

Measuring What You Actually Changed

By kooailab·Created 15 days ago·Updated 4 days ago· 0
KoO Noise Statistics
  • latent_before
  • latent_after
  • noise
  • mask
  • report
  • mean_absolute_difference
  • root_mean_square_difference
  • latent_std_before
  • latent_std_after
  • effective_noise_strength
  • masked_area_ratio

The most useful debugging question in diffusion work is also the least asked: did that node actually do anything? You nudged a strength from 0.08 to 0.12, the image looks slightly different, and you have no idea whether the difference is the change you made or the seed. KoO Noise Statistics is a measuring instrument for exactly that, and it's the least glamorous node in the pack and possibly the most useful.

Two latents in, seven outputs out. It computes the difference and reports it as numbers instead of vibes.

What it measures

Required inputs are latent_before and latent_after (both LATENT). They must match in shape - the node raises with both shapes if they don't, which is a genuinely helpful error compared to a broadcast failure somewhere downstream. Optional: noise (NOISE) and mask (MASK), which unlock extra report lines.

Outputs:

  • report (STRING) - a multi-line dump with shape, before/after min/max/mean/std, mean absolute difference, RMS difference, effective strength, mask coverage, and noise RMS plus the diff/noise ratio if you supplied a noise input.
  • mean_absolute_difference and root_mean_square_difference (FLOAT) - how far the latent moved, in latent-space units.
  • latent_std_before and latent_std_after (FLOAT) - the spread of each. If your injector changed the standard deviation, that's a red flag, because it means it shifted overall noise energy rather than redistributing it.
  • effective_noise_strength (FLOAT) - the RMS difference divided by latent_std_before. This is the useful one: a scale-free number you can compare across different images and resolutions.
  • masked_area_ratio (FLOAT) - mean mask coverage, or 1.0 with a note if no mask was supplied.

The float outputs are what make it more than a log printer. Wire effective_noise_strength into a conditional, a debug label, or feed it back into a strength widget on the injection node and you've built a crude feedback loop. Wire root_mean_square_difference into a node that refuses to save below a threshold and you've built a change-detector for a batch pipeline.

The workflow it's for

Canonical use: latent → injector → latent_after; latent → statistics → latent_before. Now every run prints exactly how hard you hit the latent, and whether the mean and spread survived - which they should, if preserve_mean and preserve_std are on in the injector.

Where this earns its place is masked work. A mask covering 4% of the frame at strength 0.3 will produce a global RMS difference that looks tiny, and it's easy to conclude nothing happened. masked_area_ratio next to mean_absolute_difference lets you see that the change is concentrated. And if you pass the same noise object you injected, the report prints diff/noise RMS, which tells you how much of the drawn noise actually landed in the latent after blending and stats restoration - a ratio near 1 means nearly all of it, and a low ratio means the blend mode ate most of it.

What it can't tell you

Whether the result is good. It has no opinions about images, only tensors. A high effective strength isn't bad and a low one isn't safe; the numbers are for detecting surprises, not for picking settings. What they're great at is killing the two failure modes that cost the most time: the change that did nothing (all outputs near zero, and you go looking for a broken wire) and the change that quietly rewrote your latent's statistics (std before and after diverge, and you go re-check the preserve flags).

One structural note: this node compares two points in one graph. It's not a stateful logger - it doesn't remember last run, doesn't plot, doesn't accumulate. If you want a history, run the workflow a few times and keep the report strings somewhere. Crude, and enough.

Installing it

cd ComfyUI/custom_nodes
git clone https://github.com/kevintronchin-blip/koo-nodes-pack

Restart ComfyUI. Nothing extra to install - the pack's requirements.txt is torch, numpy, Pillow and aiohttp, all already provided by ComfyUI - and no models involved. It sits in KoO/Noise Lab beside the injector, mask builder and preview nodes it's designed to partner with. No frontend component, so renderer choice is irrelevant here.

Manager/Registry availability at v1.0.3 depends on moderation approval; the reliable route is the README's source ZIP extracted as ComfyUI/custom_nodes/koo-nodes-pack, __init__.py directly inside.

Troubleshooting

"must match." The two latents have different shapes - usually because one passed through a resize or an adapter between them. That's the node working; it doesn't try to reconcile them.

All zeros. You passed the same latent to both inputs, or the injector's output isn't wired. A genuine no-op is a useful diagnosis, in fairness.

effective_noise_strength looks enormous. Your latent_std_before is tiny - a latent with very little variance. The ratio divides by it, so it explodes. Read the std outputs alongside the ratio and the number makes sense again.

CategoryKoO/Noise Lab

Inputs (4)

NameTypeDefaultDescription
latent_beforeLATENT—
latent_afterLATENT—
noiseoptNOISE—
maskoptMASK—

Outputs (7)

NameTypeDescription
reportSTRING—
mean_absolute_differenceFLOAT—
root_mean_square_differenceFLOAT—
latent_std_beforeFLOAT—
latent_std_afterFLOAT—
effective_noise_strengthFLOAT—
masked_area_ratioFLOAT—