Flow Matching Progressive Upscaler
The upscaler that rewinds the clock instead of dumping noise on your image
- model
- positive
- negative
- latent
- latent
- next_seed
- model
- positive
- negative
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) andstages(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.
Inputs (28)
| Name | Type | Default | Description |
|---|---|---|---|
| model | MODEL | Flow-matching diffusion model to drive refinement. | |
| positive | CONDITIONING | Positive conditioning for CFG. | |
| negative | CONDITIONING | Negative conditioning for CFG. | |
| latent | LATENT | Low resolution latent to progressively upscale. | |
| seed | INT | 00–18446744073709550000 | Base seed controlling the re-noising at each stage. |
| steps_per_stage | INT | 161–256 | Denoising steps executed at every progressive stage. |
| cfg | FLOAT | 4.50–20 | Classifier Free Guidance strength per stage. |
| sampler_name | COMBO | Sampler backend leveraged during refinement. | |
| scheduler | COMBO | Noise schedule applied during denoising. | |
| total_scale | FLOAT | 4.001–16 | Overall scale factor from the input latent to the final output. |
| stages | INT | 21–5 | Number of progressive stages to reach the total scale. |
| renoise_start | FLOAT | 0.350–1 | Noise ratio applied at the first stage. |
| renoise_end | FLOAT | 0.150–1 | Noise ratio applied at the last stage (interpolated in-between). |
| skip_blend_start | FLOAT | 0.800–1 | Blend weight for the upsampled latent at the first stage. |
| skip_blend_end | FLOAT | 0.050–1 | Blend weight for the upsampled latent at the last stage. |
| upscale_method | COMBO | bicubic | Algorithm used when resizing the latents between stages. |
| noise_schedule_overrideopt | STRING | Comma-separated override for per-stage noise ratios. Empty uses interpolated start/end. | |
| skip_schedule_overrideopt | STRING | Comma-separated override for per-stage skip blend weights. | |
| denoiseopt | FLOAT | 1.000–1 | Denoising strength supplied to the sampler per stage. |
| enable_dilated_samplingopt | COMBO | enable | Optionally run a dilated refinement pass for global coherence. |
| dilated_downscaleopt | FLOAT | 2.001–4 | Factor used when downscaling for the dilated pass (>=1.0). |
| dilated_blendopt | FLOAT | 0.250–1 | Blend weight of the dilated refinement result. |
| dilated_min_stepsopt | INT | 11–256 | Minimum 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_modeopt | COMBO | derive | Seed mode for dilated sampling. 'derive' adds 10,000 to base seed, 'same' uses identical seed. |
| dilated_denoiseopt | FLOAT | 0.500–1 | Denoising strength for dilated sampling. Lower values preserve more spatial structure from the original. |
| cleanup_stageopt | COMBO | disable | Run an extra non-scaling clean-up denoise pass at the end. |
| cleanup_noiseopt | FLOAT | 0.000–1 | Noise ratio for the optional clean-up stage (set to 0 to disable re-noising). |
| cleanup_denoiseopt | FLOAT | 0.400–1 | Denoising strength used during the clean-up stage. |
Outputs (5)
| Name | Type | Description |
|---|---|---|
| latent | LATENT | — |
| next_seed | INT | — |
| model | MODEL | — |
| positive | CONDITIONING | — |
| negative | CONDITIONING | — |