HearmemanAI Upscale Model
Your upscale node is the bottleneck — this drop-in fixes it
- upscale_model
- image
- IMAGE
HearmemanAI Upscale Model ships no weights. Set that expectation down before you click install. It's not a new upscaler - it's a drop-in replacement for ComfyUI's stock Upscale Image (using Model) node, built by the same HearmemanAI who makes the one-click Wan templates and Wan 2.2 LoRA trainer people run on RunPod. You keep the exact upscale models you already load, the same wiring, the same output. It just stops doing three things the stock node does badly, and that turns a ~15-second upscale into a ~1.6-second one (measured on an H200, SPAN x2, 16 frames at 720p).
Why stock is slow - and none of it is your GPU
The README names the culprits, and the source backs every one of them up:
- Stock blends tiles on the CPU.
output_deviceisintermediate_device()- CPU - so every tile gets copied GPU→CPU, and a 128-iteration Python loop builds a feather mask for each tile. - It runs one frame at a time.
for b in range(samples.shape[0])means a 16-frame batch is 16 sequential passes. - It hardcodes
tile=512and only ever halves it on OOM, never raises it. A 720p frame that fits in VRAM whole gets cut up anyway.
That last one costs you quality, not just time: the README measured seam blending ~16 dB PSNR below an untiled pass. So stock isn't just slower, it's lossier. This node keeps the loop on the GPU, batches frames, builds each feather mask once per tile shape, and leaves tiling off by default - faster and closer to a correct reference (74.9 dB vs 58.4 dB in the same test).
That's squarely the "more pixels, source already sharp" job from the upscaling playbook - ESRGAN/SPAN family, no invented detail. This node just makes that answer fast enough to run per-frame on video, which is usually where the stock node made you wait.
The inputs that matter
upscale_model- feed it fromLoad Upscale Model, exactly like stock. Any spandrel model works.image- your batch of frames. This is where the batching payoff shows up.precision- defaultautomeans fp32 on CUDA, and that's deliberate. These small upscalers are bandwidth-bound and fp32 convolutions already hit tensor cores at TF32 rate, so fp16 and bf16 both measured slower. Leave it. On Apple Silicon it drops to fp16 for you, which genuinely does help there.batch_size- frames per forward pass, default 8. VRAM scales linearly. If you OOM, lower this first; the node also halves it and retries automatically.tile_size- default 0, meaning no tiling at all. Only raise it if a frame genuinely won't fit. The source's OOM backoff triesbatch_sizebefore it ever touches tiling, which is the right order.overlap- default 32, only read whentile_size > 0. Leave it.
One output: IMAGE, the upscaled frames, ready to feed your Save Image node or anything downstream.
Install
Through ComfyUI Manager (search "Fast Upscale Model") or the registry, or the old-fashioned way:
cd ComfyUI/custom_nodes
git clone https://github.com/Hearmeman24/ComfyUI-HearmemanAI-Upscale
Restart, and it shows up as HearmemanAI Upscale Model under the HearmemanAI category. There are no extra dependencies - pyproject.toml lists none, and it leans on comfy.utils and spandrel, which ComfyUI already ships. MIT license.
Gotchas
Don't "optimize" it to fp16 hoping for speed - the author measured it, and fp16 is the slower option on CUDA. The precision knob exists to buy VRAM headroom, not performance. And when you do hit OOM, drop batch_size, not tile_size; tiling is the lossy path and should be the last resort. One correctness nicety worth knowing: the node calls the spandrel descriptor, not the raw .model, so architectures that need input padding get it handled automatically - bypassing that is the kind of shortcut that quietly breaks things.
Inputs (6)
| Name | Type | Default | Description |
|---|---|---|---|
| upscale_model | UPSCALE_MODEL | — | |
| image | IMAGE | — | |
| precision | COMBO | auto | auto = fp32 on CUDA (TF32 tensor cores already make it the fastest AND most accurate option for these small archs). Drop to fp16/bf16 only to save VRAM — both measured slower. |
| batch_size | INT | 81–512 | Frames per forward pass. Stock does one at a time. VRAM scales linearly with this — lower it if you OOM (the node also backs off automatically). |
| tile_size | INT | 00–8192 | 0 = no tiling, whole frame in one pass. Tiling is not just slower, it is lossy: seam blending measured ~16 dB PSNR below an untiled pass. Only use it if you cannot fit the frame. |
| overlap | INT | 320–256 | Only used when tile_size > 0. |
Outputs (1)
| Name | Type | Description |
|---|---|---|
| IMAGE | IMAGE | — |