ComfyUI Node
⬡ Polyhedron Power Upscale
MoE-aware tiled upscaler: one node in place of a chained double upscale setup, mirroring the sampler's Single / High+Low split. Tile size is chosen against free VRAM rather than a fixed guess, the pixel model can sit in front of the stages or behind the last decode (which is where it earns its time) - and there the output canvas is YOUR factor, not the model's native one, so swapping pixel models changes their imprint, never the file size. Every stage reports its own seconds so the slow one is visible instead of merely suspected.
⬡ Polyhedron Power Upscale
- model
- positive
- negative
- vae
- upscale_model
- image
- video
- model_low
- upscale_model_low
- image
- video
◄dual_moefalse►
◄upscale_by1.10►
◄denoise0.19►
◄steps3►
◄cfg1.6►
◄upscale_by_low1.30►
◄denoise_low0.25►
◄steps_low5►
◄cfg_low1.9►
◄seed0►
◄sampler_name▾►
◄scheduler▾►
◄tile_size1024►
◄tile_overlap64►
◄sigma_shift0.00►
◄sampler_lowsame as high►
◄scheduler_lowsame as high►
◄result_previewtrue►
◄process_previewOff►
◄mute_staging_logstrue►
◄resize_methodlanczos (cpu)►
◄per_batch8►
◄vae_tilingOff►
◄pixel_stagemodel + fit►
◄final_upscale_by1.00►
◄sigma_shift_low-1.00►
CategoryPolyhedron/Upscaling
Inputs (35)
| Name | Type | Default | Description |
|---|---|---|---|
| model | MODEL | The diffusion model refining the tiles. In High + Low this is the HIGH-noise expert (structure); the LOW expert plugs into 'model_low'. | |
| positive | CONDITIONING | Conditioning to include (shared by both stages). | |
| negative | CONDITIONING | Conditioning to exclude (shared by both stages). | |
| vae | VAE | The VAE encoding/decoding every tile. A Wan VAE turns the whole frame stack of a tile into ONE 5D video latent, so the video model itself keeps time consistent inside the tile. | |
| upscale_model | UPSCALE_MODEL | Pixel upscale model for the stage pre-pass (ESRGAN family via core/spandrel). In High + Low this serves the HIGH stage; the LOW stage uses 'upscale_model_low' when wired, else this one. | |
| dual_moe | BOOLEAN | false | Upscaling architecture. Single: one stage — ESRGAN x upscale_by, then a tiled refine on 'model'. High + Low: the mixture-of-experts STAGE CHAIN — stage H (the HIGH-noise expert, 'model') shapes structure at upscale_by/denoise/steps/cfg, then stage L (the LOW-noise expert, 'model_low') polishes detail at the *_low values, each stage with its own upscale model. This is the correct MoE translation for refine-strength denoises: a sigma-boundary split (the sampler's Handoff) would hand the HIGH expert zero steps below the boundary. |
| upscale_by | FLOAT | 1.101–8 | Stage-H size factor (Single: the whole factor). The stage canvas snaps to the VAE /8 grid. |
| denoise | FLOAT | 0.190–1 | Stage-H refine strength. ~0.2 keeps the input and adds detail; higher re-imagines. |
| steps | INT | 31–10000 | Stage-H steps per tile (Lightning/distilled experts need few). |
| cfg | FLOAT | 1.60–100 | Stage-H CFG. Distilled / Lightning LoRAs live near 1. |
| upscale_by_low | FLOAT | 1.301–8 | High + Low: stage-L size factor (total = product of both). |
| denoise_low | FLOAT | 0.250–1 | High + Low: stage-L refine strength (detail polish). |
| steps_low | INT | 51–10000 | High + Low: stage-L steps per tile. |
| cfg_low | FLOAT | 1.90–100 | High + Low: stage-L CFG. |
| seed | INT | 00–18446744073709550000 | Base seed. Every tile derives its noise seed from (seed, tile index) — deliberately NOT from the frame number, so a video batch keeps the same noise structure per tile over time (less flicker). |
| sampler_name | COMBO | Sampling algorithm — the full list, no per-model subset. | |
| scheduler | COMBO | Sigma schedule — the full list. | |
| tile_size | INT | 102464–4096 | Tile edge for the refine (constant per axis — uniform tiles are what diffusion models like). Clamped to the canvas. |
| tile_overlap | INT | 640–1024 | Target overlap between neighbouring tiles. Tiles are stitched as a weighted sum with smoothstep feathers whose accumulated weight is EXACTLY 1 everywhere — the reason this node has no seam-fix family: none is needed. When a canvas can't host the requested overlap safely, the planner narrows it (correct beats wide). |
| sigma_shift | FLOAT | 0.000–20 | Flow-matching sigma shift, the sampler's own mechanism (0 = off). Wan 2.2 wants its native shift (typically 8.0) or the tile schedules are mis-scaled. Applied to both experts in High + Low. |
| sampler_low | COMBO | same as high | High + Low: sampling ALGORITHM for stage L ('sampler_name' drives stage H). The stages are independent runs, so this is always honoured. Ancestral / SDE samplers (*_a, *_sde) inject fresh noise per step — at refine strengths that changes the grain. |
| scheduler_low | COMBO | same as high | High + Low: sigma SCHEDULE for stage L. Always honoured — stage L builds its own schedule from steps_low / denoise_low anyway, so a second scheduler breaks nothing (no handoff, no seam). |
| result_preview | BOOLEAN | true | Show the finished frames inside the node (small temp JPEGs; multi-frame runs play as a flipbook at the source frame rate). Never touches the outputs. |
| process_preview | COMBO | Off | Watch the refine LIVE: the tile being sampled right now, a minimap locating it on the stage canvas, and stage/tile/step counters. Off = zero overhead (the probe is never built). latent2rgb = free, but it reads the LATENT's grid (/8 - a 768 tile is 96px, and it looks it). vae (sharp) = a real decode of one frame per event: full resolution, at the cost of one vae forward - measured against the stage clock and dropped back to latent2rgb on its own if it starts eating the pass. |
| mute_staging_logs | BOOLEAN | true | Silence ComfyUI's per-tile staging INFO lines ('prepared for dynamic VRAM loading', 'x models unloaded') while a stage runs. Restored byte-exactly after. Turn Off when debugging VRAM. |
| resize_method | COMBO | lanczos (cpu) | Fit onto the stage canvas after the pixel upscale. 'lanczos (cpu)' = the historic path, byte-identical. bicubic/bilinear/area/nearest run chunked on the GPU (fast). nvidia_rtx_vsr = Maxine VideoSuperRes (needs nvvfx + RTX). |
| per_batch | INT | 81–256 | Frames per chunk for the ESRGAN pass and its fit (the upscale + fit are FUSED per chunk, so the peak holds only this many frames at the intermediate size). 129 frames through a 4x model is a ~15 GB tensor in one go - this is the OOM guard. There is no 0 any more: it meant 'whole batch', which is exactly the 14.7 GB path this node removed. For the old behaviour set 256. |
| vae_tiling | COMBO | Off | Spatial VAE tiling for each tile's encode/decode. Off = the historic path (byte-identical). A size (512/640/768) cuts the VAE peak on big canvases, at the cost of a tiny internal blend at the VAE tile borders. NEVER temporal: a Wan VAE compresses time 4:1, so time tiles would stutter. |
| pixel_stage | COMBO | model + fit | How each stage reaches its canvas. 'model + fit' = the wired UPSCALE_MODEL runs first, the fit lands it on the exact stage size (the classic recipe). 'fit only' IGNORES the wired model; resize_method does the whole upscale -- seconds instead of minutes, and the refine paints the detail anyway. 'model only' = the canvas IS the model factor; upscale_by is ignored (loudly), the fit only corrects to the /8 snap. 'model final' = the stages run pure fit and the last stage's pixel model runs ONCE behind the final decode -- the measured place for it: no VAE follows, its detail goes straight to the file (resize_method='none' keeps the raw model result; a kernel supersamples it back to the dialled canvas). Measured: a pixel model in FRONT of a VAE round trip is nearly free of effect -- the /8 compression cannot carry its fine detail. Switch without unplugging. |
| final_upscale_by | FLOAT | 1.000.25–8 | Canvas of the FINAL pixel pass (pixel_stage='model final'), as a factor of the stage result. The model always computes its native factor; the kernel then lands it on THIS canvas -- the model's imprint reaches the file while the size stays yours (swap a 2x/4x/8x model: the imprint changes, the size never). 1.0 = the stage canvas (classic supersample refine); below 1.0 = supersampled DOWNscale (sprite work). Ignored (loudly) when resize_method='none', which keeps the raw model result. |
| sigma_shift_low | FLOAT | -1.00-1–20 | Flow-matching sigma shift for stage L (the LOW-noise expert). -1 = 'same as high': stage L follows sigma_shift, so both stages are shifted alike. 0 = OFF for stage L only -- its model_sampling is left alone even when sigma_shift is set. Any positive value gives stage L its OWN shift (e.g. sigma_shift 8.0 with sigma_shift_low 5.0). Always honoured: the stages are independent runs, so unlike the Sampler there is no mode in which this goes inert. Works with or without a wired 'model_low' -- without one, stage L falls back to the 'model' input and gets its own shifted copy of it. |
| imageopt | IMAGE | Frame input [N,H,W,C] — stills or an unpacked video. Wire EXACTLY one of image / video. | |
| videoopt | VIDEO | Native VIDEO input (green). Its frames are upscaled; its audio and frame rate ride through losslessly into the VIDEO output. Wire EXACTLY one of image / video. | |
| model_lowopt | MODEL | High + Low: the LOW-noise expert for stage L. Unwired -> stage L falls back to 'model'. | |
| upscale_model_lowopt | UPSCALE_MODEL | High + Low: stage-L pixel upscale model - and, with pixel_stage='model final', the model of the FINAL pass behind the last decode. Unwired -> stage L runs a plain fit (the H model is NOT inherited) and a 'model final' run says so and skips the final pass. |
Outputs (2)
| Name | Type | Description |
|---|---|---|
| image | IMAGE | — |
| video | VIDEO | — |