Nodes/Whirlpool Upscaler/Whirlpool Upscaler
ComfyUI Node

Whirlpool Upscaler

The upscaler that sneaks up on 2x one pass at a time

By rainlizard·Created about a year ago·Updated about a year ago· 2
Whirlpool Upscaler
  • image
  • model
  • positive
  • negative
  • vae
  • upscale_model
  • image
seed0
upscale_by2.00
upscale_curve1.00
iterations4
steps_start17
steps_end7
cfg_start7.0
cfg_end1.0
denoise_start1.00
denoise_end0.15
add_noise0.0
fix_vae_colortrue
sampler_nameres_2m
schedulerbong_tangent
resize_filterlanczos
decode_size1024

One node that does the whole multi-pass upscale dance

Most upscaling in ComfyUI is a chain: generate small, hi-res fix to 1.5–2x, maybe a tiled pass for the last mile, maybe a face fix. Whirlpool Upscaler folds the middle of that chain into a single node. It's a rework of Impact Pack's iterative upscaler, built on the idea that dumping all your compute into one giant high-res pass is wasteful - so instead it walks the image up to your target resolution across several small sampling passes, easing CFG, steps, and denoise down as it goes.

That's a different job from the restoration upscalers. It's not SeedVR2 or SUPIR (it won't invent pores or repair a damaged photo), and it's not a plain ESRGAN-style pixel upscale. It's generative "more detail" upscaling in the hi-res-fix family, except the fix is spread over N passes so each one only does a small, cheap increment. On a 6GB card it's noticeably friendlier than jumping straight to 2x in one img2img pass, because it never asks the VAE to handle a huge image until the last iteration.

How it works

The core loop is simple: for each of iterations passes, it upscales the current pixels to the next resolution, encodes them to a latent, runs a short sampling step, and decodes back to pixels - one encode and one decode per iteration. What makes it interesting is the easing. All four progression values (resolution, CFG, steps, denoise) move from their _start to their _end values, and upscale_curve shapes how linear that journey is.

With upscale_by = 2.0 and 4 iterations, a linear curve (upscale_curve = 1.0) gives 1.25x → 1.5x → 1.75x → 2.0x. Bump the curve to 2.0 and you get 1.13x → 1.42x → 1.69x → 2.0x - the early passes stay cheap and the heavy work lands at the end. The defaults lean that way already (17 steps down to 7, CFG 7 down to 1, denoise 1.0 down to 0.15), which is a sensible "refine, don't rewrite" arc. There's also fix_vae_color (on by default), which does LAB histogram matching back to the original image after each pass so color doesn't drift across all that encode/decode churn - a real failure mode this design would otherwise hit hard.

The inputs that matter

You'll fiddle with maybe five of these:

  • upscale_by - the final multiplier. 2.0 doubles width and height.
  • upscale_curve - how the resolution/CFG/steps/denoise progress. Higher = cheaper early passes, closer to the base image, less body horror. Lower = more time at high res, more detail, more chance of horror. The README's blunt summary: strike a balance, and if you change upscale_by you should change the curve too.
  • iterations - how many passes. More is finer-grained and slower.
  • decode_size - tile size for the VAE ops. If you're getting lag or OOM, drop it (320 minimum).
  • upscale_model (optional) - plug in any UPSCALE_MODEL from the standard UpscaleModelLoader (4x-UltraSharp, Remacri, an anime ESRGAN) and it replaces Lanczos as the per-iteration pixel scaler.

The rest - sampler_name (default res_2m) and scheduler (default bong_tangent) - come straight from ComfyUI's built-in lists, so anything you know from a KSampler works. You also wire in the model, positive/negative conditioning, a seed, and the VAE like you would any sampler. Output is a single image tensor, ready to feed a save node or another upscale stage.

Installing it

No models to download, no extra weights - which is a relief after SUPIR's multi-gigabyte download. The only code dependency beyond ComfyUI itself is scipy (for the color matching), which the portable install already ships. Through ComfyUI Manager, search "Whirlpool Upscaler" and install. Manually:

cd ComfyUI/custom_nodes
git clone https://github.com/rainlizard/ComfyUI-WhirlpoolUpscaler

Restart ComfyUI. If you're on a bare venv rather than the portable build and the color-matching import chokes, pip install scipy fixes it.

Gotchas

  • Cancelling isn't instant. The node checks for interruption but only between iterations, so you'll wait for the current pass to finish. Annoying on a 6+ iteration run; the README itself asks for a better solution.
  • Body horror (extra fingers, warped anatomy): lower denoise_start, feed it a smaller base image, or raise upscale_curve. Per the README, the Skimmed CFG trick is the enthusiast move - route the model through a Skimmed CFG node with a high cfg_start and the results usually improve.
  • Artifacts: reduce CFG, raise steps, or same Skimmed CFG path.

It's a niche node with a niche audience - community talk about it is almost nonexistent - but if you're already an Impact Pack iterative-upscale fan and want the same idea with built-in color correction and an ESRGAN hook, it's a tidy single-node drop-in.

CategoryWhirlpool Upscaler

Inputs (22)

NameTypeDefaultDescription
imageIMAGE
modelMODEL
seedINT00–18446744073709550000
upscale_byFLOAT2.000.1–10000Final resolution multiplier (e.g., 2.0 = double width and height).
upscale_curveFLOAT1.000–10Progression curve for all parameters. 1.0 = linear. >1.0: resolution accelerates, CFG/steps/denoise front-loaded. <1.0: resolution front-loaded, CFG/steps/denoise accelerate.
iterationsINT40–20Number of complete sampling cycles to perform.
steps_startINT171–10000Number of sampling steps for the first iteration.
steps_endINT71–10000Number of sampling steps for the last iteration.
cfg_startFLOAT7.00–10000CFG scale for the first iteration.
cfg_endFLOAT1.00–10000CFG scale for the last iteration.
denoise_startFLOAT1.000–1Denoise strength for the first iteration.
denoise_endFLOAT0.150–1Denoise strength for the last iteration.
add_noiseFLOAT0.00–100Adds noise before denoising each iteration. The amount added is relative to the current denoise.
fix_vae_colorBOOLEANtrueApply color correction after each iteration to maintain color consistency with the original image.
sampler_nameCOMBOres_2m44 options: euler, euler_cfg_pp, euler_ancestral, euler_ancestral_cfg_pp, heun, heunpp2, +38
schedulerCOMBObong_tangent9 options: simple, sgm_uniform, karras, exponential, ddim_uniform, beta, +3
positiveCONDITIONING
negativeCONDITIONING
resize_filterCOMBOlanczosImage resizing filter algorithm.
decode_sizeINT1024320–2048Decode size for VAE operations.
vaeVAE
upscale_modeloptUPSCALE_MODELOptional AI upscaling model (e.g., ESRGAN, Real-ESRGAN) for enhanced image quality during upscaling.

Outputs (1)

NameTypeDescription
imageIMAGE