Nodes/ComfyUI-ppm/Temperature Sampling (PPM)
ComfyUI Node

Temperature Sampling (PPM)

The knob that makes one seed give you several good images

By pamparamm·Created 2 years ago·Updated about 21 hours ago· 272
Temperature Sampling (PPM)
  • model
  • MODEL
◄gamma0.80►
◄start_percent0.000►
◄end_percent0.333►

You found a prompt and a seed that produced something you actually like. Now you want three more like it, and rerolling the seed throws the composition away - the pose's gone, the lighting changed, the character is somebody else. Temperature Sampling is aimed at exactly that gap: same prompt, same seed, nudged diversity.

It's a MODEL patch. No sampler, no latent, no image comes out of it. You feed it a model, it hands a slightly modified model back.

What it actually changes

Props for honesty: the source names its paper - Diversify Diffusion with Temperature Sampling and Variance-Corrective Time Shifting (Li et al., 2026, arXiv 2607.10853). Not a repackaged trick from another pack.

The mechanism is simpler than the title. The node clones your ModelPatcher, reads its model_sampling, and installs an APPLY_MODEL wrapper. Each time the sampler calls the model at a noise level sigma, the wrapper checks whether that sigma lands inside your window. It doesn't - pass straight through. It does - the model gets called at a lower noise level, sigma * sqrt(gamma). Gamma tops out at 1.0, so that shrinks sigma, and a smaller effective noise level at the same nominal step means the sampler isn't committing as hard to one denoising path. That's where the variation comes from.

Flow models get the second half, the variance-corrective time shift: shifting sigma alone would leave latent and timestep out of register, so the input gets rescaled too, x / d with d = 1 - (1 - sqrt(gamma)) * sigma. Non-flow models (SD1.5/SDXL, EDM) just take the sigma swap.

gamma = 1.0 short-circuits before any wrapping happens and returns the model untouched. An honest off switch - you can leave the node wired in and A/B it with one slider.

The inputs you'll touch

gamma is the inverse temperature: default 0.8, range 0.01–1.0. Below 1.0 adds diversity, 1.0 disables the node. The default is a mild nudge, so if you flip it on, run the same seed, and see no change, drop it to 0.6 before concluding the node is a dud.

start_percent and end_percent are the window, and this is where people get it wrong. Defaults are 0.0 and 0.3333 - the first third of denoising, the highest-noise stretch. Percent is progress, so 0 is pure noise and 1.0 is the finished latent. The tooltips carry the paper's presets: early 0.0 → 0.3333, middle 0.3333 → 0.6667, late 0.6667 → 1.0. Early is where I'd start, since that's the part of the trajectory deciding composition and pose; a late window mostly reshuffles texture. It's also the author's default, which is rarely an accident.

Two silent no-ops worth knowing. start_percent >= end_percent makes the wrapper bail out entirely, so start 0.6667, end 0.3333 does nothing and won't complain. And a window that never overlaps the sigmas your sampler visits - narrow windows at low step counts - gives you an unchanged model with no warning.

The single output is MODEL. Wire it into KSampler's model input, or SamplerCustomAdvanced's model socket, after the checkpoint loader and before the sampler.

Installing it

ComfyUI Manager, search ComfyUI-ppm, install, restart. Or by hand:

cd ComfyUI/custom_nodes
git clone https://github.com/pamparamm/ComfyUI-ppm

Then restart ComfyUI. No requirements.txt and no install script in the repo - the only declared dependencies are the pack's own dev tooling (ruff, pyrefly), and runtime needs nothing beyond what ComfyUI already ships (torch, kornia). Genuinely a clone and a restart: no pip step, no model downloads. The one requirement is a reasonably current ComfyUI, because this node is written against the newer backend authoring API (from comfy_api.latest import io, io.ComfyNode). On an old install the pack can fail to register its nodes at all rather than failing when you run a graph.

Where it bites

Chaining model patches? Put this after anything that changes the sampling math - ModelSamplingFlux / AuraFlow shift, CFG++ patches, the rest of the ppm lineup. The node turns your percent window into sigmas from whatever model_sampling the model carries when it executes, so place it before a shift node and your window gets measured against the wrong schedule.

Model support is deliberate rather than universal. The code accepts ModelSamplingDiscrete, ModelSamplingContinuousEDM, ModelSamplingDiscreteFlow and ModelSamplingFlux, and raises ValueError: Unsupported model sampling: <class> for anything else. SD1.5/SDXL and their fine-tunes, Flux and the AuraFlow-lineage flow models are covered; on something exotic, at least the error names the class you'd need handled. The node is flagged experimental in its own schema, and the README has a standing line worth remembering: if a node starts throwing errors after an update, delete it from the graph and re-add it.

The honest caveat: this is a fresh paper implementation in a pack that mostly ships fixed-up versions of other people's work (CFG++ samplers, Guidance Limiter, AttentionCouple, NegPiP - that's what ppm is known for). There's effectively no community discussion of this node yet, so nobody's handing you tested settings. Treat it as a controlled-exploration knob: lock the seed, change gamma only, compare at the same step count. It isn't a quality booster, and it isn't a substitute for trying another seed - it's for variations that stay on-model.

Categorymodel_patches/unet

Inputs (4)

NameTypeDefaultDescription
modelMODEL—
gammaFLOAT0.800.01–1Inverse temperature. < 1.0 increases sampling diversity, 1.0 disables temperature sampling.
start_percentFLOAT0.0000–1Presets from original paper: early=0.0, middle=0.3333, late=0.6667.
end_percentFLOAT0.3330–1Presets from original paper: early=0.3333, middle=0.6667, late=1.0.

Outputs (1)

NameTypeDescription
MODELMODEL—