Nodes/ComfyUI-FlowMatching-Upscaler/Flow Matching Progressive Upscaler
ComfyUI Node

Flow Matching Progressive Upscaler

The upscaler that rewinds the clock instead of dumping noise on your image

By ttulttul·Created 10 months ago·Updated 7 months ago· 62
Flow Matching Progressive Upscaler
  • model
  • positive
  • negative
  • latent
  • latent
  • next_seed
  • model
  • positive
  • negative
seed0
steps_per_stage16
cfg4.5
sampler_name
scheduler
total_scale4.00
stages2
renoise_start0.35
renoise_end0.15
skip_blend_start0.80
skip_blend_end0.05
upscale_methodbicubic
noise_schedule_override
skip_schedule_override
denoise1.00
enable_dilated_samplingenable
dilated_downscale2.00
dilated_blend0.25
dilated_min_steps1
dilated_seed_modederive
dilated_denoise0.50
cleanup_stagedisable
cleanup_noise0.00
cleanup_denoise0.40

This is the headline node of the ttulttul/ComfyUI-FlowMatching-Upscaler pack, and it's built around a genuinely different idea: instead of stretching your latent and blasting random noise over it (the standard img2img upscale move), it rewinds the clock. You finish a low-res image at flow time t=0; the node resizes the latent up, then re-noises it back to somewhere like t=0.6 - back onto the model's flow trajectory - and lets the sampler walk forward again at the higher resolution. Same journey, bigger canvas. Because it resumes an existing path rather than starting fresh, it fills in high-frequency detail instead of hallucinating a new composition.

The author (ttulttul, who also did the damofusion-style ComfyUI-Iterative-Mixer) ships this in a pack that now focuses on exactly this: the progressive upscaler, its modular stage nodes, the DyPE patchers, and a latent upscaler. Everything flow-matching, nothing else.

Why you'd reach for it. Flow models like Qwen Image and Flux2 don't obey the old SDXL rules - they expect a straight-line trajectory, and old advice like "denoise 0.35 with Karras" actively fails on them (Karras concentrates sampling in the middle of the path, which distorts a straight flow). This node handles the re-noising the flow-consistent way and gives you the knobs in one place: it's the "generate at native res, then climb" strategy from the upscaling playbook, but staged so each doubling gets its own denoise pass. And upscaling is genuinely optional here - set total_scale to 1.0 and it becomes a pure refinement pass, a second chance to add detail without changing resolution.

How it works, stage by stage. Each stage: (1) upscale the latent, (2) re-noise with a linear mix of fresh noise (renoise_start 0.35 tapering to renoise_end 0.15), (3) denoise with your sampler, (4) blend the skip residual back in to hold composition (skip_blend_start 0.8 → skip_blend_end 0.05), and (5) optionally run a dilated refinement lap - downscale, short sample pass, and blend back in the frequency domain (FFT-based, so it pulls low frequencies from the dilated pass and keeps high-frequency detail from the base). That dilated pass is your weapon against the over-sharpened "hallucinated pores" artifact. There's also a cleanup_stage toggle for a final no-scaling polish pass. If you run out of VRAM mid-stage, it automatically drops into a LOW_VRAM streaming fallback - slower, but it won't crash. Inpaint masks ride along and get resized in lockstep, so masked workflows stay aligned.

Inputs that matter:

  • model, positive, negative, latent - the four you already know from any sampler.
  • seed - base seed controlling per-stage re-noising.
  • steps_per_stage (16), cfg (4.5), sampler_name, scheduler - per-stage sampler settings. For flow models, stick with the Euler family; avoid the classic DDPM-era scheduler choices unless you're testing.
  • total_scale (4.0) and stages (2) - where you're going and how many doublings to get there.
  • upscale_method (bicubic) - the inter-stage resize kernel.

The noise_schedule_override and skip_schedule_override strings let you hand-write per-stage values as comma-separated lists; denoise is a global multiplier. Skip those until you're chasing a specific artifact.

Outputs. latent is the result, next_seed chains deterministically into another stage, and model, positive, negative pass through so you can keep wiring downstream.

Install. ComfyUI Manager, search "ComfyUI-FlowMatching-Upscaler", install, restart. Or:

cd ComfyUI/custom_nodes
git clone https://github.com/ttulttul/ComfyUI-FlowMatching-Upscaler

Dependencies are numpy, torch, einops, aiohttp - nothing heavy, no model downloads. Restart and it's under latent/upscaling.

Gotchas. The pack's own README warns that noise isn't random here - it's what makes the latent statistically valid at that timestep, so fight the urge to crank renoise_start down to zero (you get waxy, plastic output). And if you're on a lightning/distilled flow model that samples in 4 steps, raise dilated_min_steps - the default dilated pass may be too short to do anything. Start with defaults, get one clean upscale, then tune.

Categorylatent/upscaling

Inputs (28)

NameTypeDefaultDescription
modelMODELFlow-matching diffusion model to drive refinement.
positiveCONDITIONINGPositive conditioning for CFG.
negativeCONDITIONINGNegative conditioning for CFG.
latentLATENTLow resolution latent to progressively upscale.
seedINT00–18446744073709550000Base seed controlling the re-noising at each stage.
steps_per_stageINT161–256Denoising steps executed at every progressive stage.
cfgFLOAT4.50–20Classifier Free Guidance strength per stage.
sampler_nameCOMBOSampler backend leveraged during refinement.
schedulerCOMBONoise schedule applied during denoising.
total_scaleFLOAT4.001–16Overall scale factor from the input latent to the final output.
stagesINT21–5Number of progressive stages to reach the total scale.
renoise_startFLOAT0.350–1Noise ratio applied at the first stage.
renoise_endFLOAT0.150–1Noise ratio applied at the last stage (interpolated in-between).
skip_blend_startFLOAT0.800–1Blend weight for the upsampled latent at the first stage.
skip_blend_endFLOAT0.050–1Blend weight for the upsampled latent at the last stage.
upscale_methodCOMBObicubicAlgorithm used when resizing the latents between stages.
noise_schedule_overrideoptSTRINGComma-separated override for per-stage noise ratios. Empty uses interpolated start/end.
skip_schedule_overrideoptSTRINGComma-separated override for per-stage skip blend weights.
denoiseoptFLOAT1.000–1Denoising strength supplied to the sampler per stage.
enable_dilated_samplingoptCOMBOenableOptionally run a dilated refinement pass for global coherence.
dilated_downscaleoptFLOAT2.001–4Factor used when downscaling for the dilated pass (>=1.0).
dilated_blendoptFLOAT0.250–1Blend weight of the dilated refinement result.
dilated_min_stepsoptINT11–256Minimum sampling steps for dilated refinement. Actual steps = max(min_steps, steps // 2). Increase for lightning models to ensure adequate sampling (e.g., 4).
dilated_seed_modeoptCOMBOderiveSeed mode for dilated sampling. 'derive' adds 10,000 to base seed, 'same' uses identical seed.
dilated_denoiseoptFLOAT0.500–1Denoising strength for dilated sampling. Lower values preserve more spatial structure from the original.
cleanup_stageoptCOMBOdisableRun an extra non-scaling clean-up denoise pass at the end.
cleanup_noiseoptFLOAT0.000–1Noise ratio for the optional clean-up stage (set to 0 to disable re-noising).
cleanup_denoiseoptFLOAT0.400–1Denoising strength used during the clean-up stage.

Outputs (5)

NameTypeDescription
latentLATENT
next_seedINT
modelMODEL
positiveCONDITIONING
negativeCONDITIONING