Nodes/ComfyUI Neo Sampler (Forge Neo)/Neo 高清修复放大 (Forge Neo)
ComfyUI Node

Neo 高清修复放大 (Forge Neo)

The second pass that forgot to be a second pass

By wangjue520·Created 23 days ago·Updated 23 days ago· 3
Neo 高清修复放大 (Forge Neo)
  • latent
  • vae
  • upscale_model
  • LATENT
◄upscaler放大模型(接 upscale_model)►
◄scale1.50►
◄resize_width0►
◄resize_height0►
◄res_step64►
◄tile_size256►
◄tile_overlap16►

Hires fix is the oldest trick in the book and still the best one: generate small, then run a second pass at a larger size with a low denoise so the model fills in detail instead of hallucinating a new image. Skip it and anything above the model's native resolution turns into repeated tiles - you know the look.

The annoying part is that the "upscale" step in the middle isn't standardized. A1111 and Forge Neo do it their way; ComfyUI gives you a grab bag of Upscale Latent variants and a separate Upscale Image (using Model) node. Swap them and your second pass doesn't match Neo's, even though the idea is the same. This node replicates Neo's version of that middle step so a two-pass workflow in ComfyUI behaves like the one in Neo.

What it does

You give it a LATENT from your first pass, it works out the target size Neo would, resizes the latent there, and hands you a LATENT for a second Neo KSampler.

Two paths, chosen by the upscaler widget. In the latent paths it interpolates the latent samples directly - cheap, memory-light, slightly soft. In the image paths it decodes to pixels, resizes, then re-encodes to latent: a destructive round trip through the VAE, which is exactly why picking a real upscale model there gets you crisp detail pure latent interpolation can't. Neo's tiling is reproduced for the upscale model, and the pixel resize lands with Lanczos after it.

The target size is computed with Neo's resolution rounding: scale multiplies your current size, then the result gets snapped to the res_step grid (64 by default). That's the same rounding Neo applies, and it's why 1.5× on 1024 doesn't give you 1536 - it gives you the nearest sensible multiple. If you want an exact size, set resize_width / resize_height instead; setting only one of them computes the other from the current aspect ratio.

The inputs

  • latent - first-pass output. Use a Neo KSampler, not something else, if you care about the seed carrying over.
  • vae - required even in pure latent mode, because the pixel paths need it.
  • upscaler - Latent, Latent (antialiased), Latent (bicubic), Latent (bicubic antialiased), Latent (nearest), Latent (nearest-exact), 放大模型(接 upscale_model), None(Lanczos). Default is the upscale-model option. If you pick that and don't wire upscale_model, it raises rather than silently doing something else.
  • scale - default 1.5. The tooltip says Anima wants ≤1.5 per pass; if you need more, stack passes rather than jump.
  • resize_width / resize_height - 0 means "use the scale factor".
  • upscale_model (optional) - the UPSCALE_MODEL loader output, e.g. a 4x ESRGAN-style model.
  • res_step - Neo's Resolution Step, 64 by default. Match Neo's settings page.
  • tile_size / tile_overlap - Neo's Tile Size for Upscalers (256) and overlap (16). The tile size halves automatically on an out-of-memory error and retries, down to a floor of 64 - Neo itself would just fail here, so this is a ComfyUI-side courtesy.

Output: one LATENT, into a second Neo KSampler set to Hires.fix.

Wiring

Neo KSampler (pass 1) ─→ Neo Hires Upscale ─→ Neo KSampler (pass 2)
                                                 denoise_mode = Hires.fix(精确步数)
                                                 denoise = your redraw strength (0.3–0.5)

The RNG state rides inside the LATENT dictionary, so the second sampler picks up the same seeds and regenerates noise at the new size - Neo's behaviour, and the reason the graph stays reproducible. The first pass also records its step count in the latent so the second pass can run prompt schedules with Neo's offset rules.

Install

ComfyUI Manager → ComfyUI Neo Sampler, or:

cd ComfyUI/custom_nodes
git clone https://github.com/wangjue520/ComfyUI-Neo-Sampler

Restart. lark, torchsde and scipy are installed automatically into the Python that runs ComfyUI; the console prints the manual pip command if the auto-install fails. You need an upscale model file of your own if you want the upscale-model path - nothing is bundled.

Things that will annoy you

Choosing an upscale model but leaving upscale_model unwired is a hard error ("selected an upscale model but no upscale_model is connected"), which is the right call but reads as cryptic if you forgot.

The pixel paths drop any noise_mask from the latent. Combined with the sampler ignoring masks too, that means this whole pipeline is not an inpainting pipeline - do your hires pass on a clean latent.

VRAM is the real constraint. The pixel path decodes, holds the frames, tiles the upscale model, then re-encodes - a 4x model on a big latent will push you into the tiling fallback, and heavy tiling at a small tile_size shows up as seams rather than a crash. If your output has visible grid lines, raise tile_size. And if you want resolution doubling without the model pass, Latent (bicubic antialiased) at 2.0 is the boring, fast, surprisingly-fine choice.

CategoryNeo (Forge Neo 复刻)

Inputs (10)

NameTypeDefaultDescription
latentLATENT—
vaeVAE—
upscalerCOMBO放大模型(接 upscale_model)8 options: Latent, Latent (antialiased), Latent (bicubic), Latent (bicubic antialiased), Latent (nearest), Latent (nearest-exact), +2
scaleFLOAT1.501–8Hires upscale by(Anima 单次建议 ≤1.5)
resize_widthINT00–16384Resize width to(0 = 按倍数)
resize_heightINT00–16384Resize height to(0 = 按倍数)
upscale_modeloptUPSCALE_MODEL—
res_stepoptINT648–256Neo 设置 → Resolution Step(默认 64)
tile_sizeoptINT2560–2048Neo 设置 → Tile Size for Upscalers;显存不足时会自动减半
tile_overlapoptINT160–256—

Outputs (1)

NameTypeDescription
LATENTLATENT—