Nodes/ComfyUI-LossTesting/Measure Timestep Loss
ComfyUI Node

Measure Timestep Loss

The graph that shows where a model actually does its work

By spacepxl·Created 2 years ago·Updated 2 years ago· 3
Measure Timestep Loss
  • model
  • conditioning
  • latent
  • graph
seed0
steps30
repeats4
scheduler
log_y_scalefalse
limit_y_scale18.00

If you've ever stared at two checkpoints that look equally capable and wondered which one actually understands your prompt, this is the node for you. Measure Timestep Loss doesn't generate anything - it draws you a graph. Feed it a model, a conditioning, and an encoded image, and it plots how much error the model leaves at each step of the denoising schedule. It's an autopsy tool, not a paintbrush, and that's the point.

The author is spacepxl, who got real community attention in early 2025 for his work on stable validation loss for LoRA training - the idea that you can stop eyeballing sample images and read a curve instead. This node is that philosophy applied to sampling rather than training: instead of asking "does this render look good," it asks "how much reconstruction error does this model carry at every step." Different question, same discipline.

How it works

Under the hood it's deceptively simple, and worth understanding before you read the output. For each step i in the schedule, the node runs a single denoising step from pure noise (denoise=1.0, start_step=i, last_step=i+1), then measures the MSE between that partially-denoised latent and your original encoded image. Higher loss at step i means the model - with your exact conditioning - is further from the target after one step at that point in the schedule. That's a proxy for "how hard this part of the schedule is working" and "how well the conditioning matches the image."

Two details matter. First, repeats re-runs each step with fresh seeds and averages the results - same trick as spacepxl's "stable loss," smoothing out noise so you read the trend, not the luck of one seed. Second, it runs at cfg=1 with the negative conditioning set to the positive, so you're measuring the raw denoiser, not the classifier-free-guidance amplification you actually generate with. Don't be shocked that the numbers don't match your usual render settings; that's by design.

The inputs that matter

  • model, conditioning, latent - your checkpoint, your prompt (as a Conditioning node), and a VAE-encoded image from a VAEEncode node. The latent is both the target and what the single-step sample tries to reconstruct toward.
  • seed - the starting seed for the noise, with repeats adding successive seeds on top of it. Lock it when you're comparing models so the difference in your curves is the model, not the noise.
  • steps - how many points along the schedule to sample (default 30).
  • repeats - how many seeds to average per step (default 4). Bump it if your curve looks jittery.
  • scheduler - the standard ComfyUI list of nine. It controls how much noise is removed per step, so it reshapes where the loss lands; Karras, for instance, concentrates effort in the middle of the schedule.
  • log_y_scale and limit_y_scale - cosmetic: log-scale the y-axis, and cap the y-axis height (default 18). If your curve flattens against the top of the plot, raise the limit.

The single output, graph, is an IMAGE - a matplotlib PNG with one line per image in your batch. Save it, view it in a preview node, don't try to wire it into anything that expects a generated picture.

Installing it

This one's a two-minute install with no model files to chase:

cd ComfyUI/custom_nodes
git clone https://github.com/spacepxl/ComfyUI-LossTesting

Then restart ComfyUI. Or use ComfyUI Manager and search for "ComfyUI-LossTesting" - it's the one-node pack that lands in a "LossTesting" menu. The only Python dependency is matplotlib, which Manager installs for you if it's missing; there's nothing else in requirements.txt.

Where people get burned

  • It's slow. Each step is a full single-step denoise of your latent, so 30 steps × 4 repeats is 120 model passes on top of noise prep. At high resolution that's not a coffee-break wait. Use 512px test latents and cut steps/repeats while you're iterating.
  • Feed it a real latent, not a noise latent. The latent input is an image you encoded, not a blank EmptyLatentImage - the whole measurement is the reconstruction gap against it.
  • The curve is relative, not absolute. It's a comparison tool: model A vs model B, caption A vs caption B, same seed and steps. Absolute loss values don't mean much in isolation.

If you're choosing between two checkpoints for a project, run both through with the same image and prompt and compare the curves - one line consistently closer to zero tells you more than a weekend of staring at samples. It's niche, it's nerdy, and if you've ever tuned a caption until the output "felt right," it's also the tool that finally tells you why.

CategoryLossTesting

Inputs (9)

NameTypeDefaultDescription
modelMODELThe model used for denoising the input latent.
seedINT00–18446744073709550000The random seed used for creating the noise.
stepsINT303–1000The number of timesteps used to evaluate
repeatsINT41–1000The number of times to repeat each step with new seeds (averaged)
schedulerCOMBOThe scheduler controls how noise is gradually removed to form the image.
conditioningCONDITIONINGThe conditioning describing the attributes you want to include in the image.
latentLATENTThe latent image to test
log_y_scaleBOOLEANfalse
limit_y_scaleFLOAT18.00

Outputs (1)

NameTypeDescription
graphIMAGE