ResShift SR Upscale (1-step)
One stochastic step from 512px to 2048px — no sampler, no CFG
- rsd_model
- image
- IMAGE
This is where the Distilled ResShift pack does its party trick: it upscales any RGB image ×4 or ×2 in one diffusion step. Not fifteen, not eight - one. There's no sampler dropdown, no CFG, no scheduler anywhere in the node. You feed it a RESSHIFT_MODEL (from ResShiftLoader) and an IMAGE, and it hands back the upscaled IMAGE. That's the whole interface.
What it actually is
The student is distilled from a 15-step ResShift teacher into a single stochastic step. That's the trade you should know going in: distillation collapses the whole denoising trajectory into one jump, and distilled models always give up some refinement for the speed. So this won't rebuild a face the way a heavy restoration model will - which, for most upscaling jobs, is a feature, not a bug. In the upscaling taxonomy (more pixels vs. more detail vs. video), this is a detail model that's fast enough to feel like an ESRGAN-class upscaler: seconds, not the multi-minute grind of a SeedVR2 pass.
It's also genuinely model-agnostic. Because it's a pixel-space IMAGE → IMAGE node, it doesn't care what generated the image. Drop it after VAEDecode and before SaveImage, and it'll happily upscale anime, photos, or a random PNG you loaded from disk.
How the one step works
The student runs at the same spatial resolution - the upscale lives in the residual-shift, not in a spatial resize. The image gets bicubic-upsampled ×scale, encoded to the vq-f4 latent, pushed through one student step (z_T = z_y + κ·randn, plus injected noise ε), and decoded. Large images are split into tiles with overlap-averaged blending, and each tile is reflect-padded to a multiple of the Swin alignment (256 px at ×4, 128 px at ×2).
The inputs that matter
Most of the defaults are fine to leave alone. The ones you'll actually touch:
seed(default 0) - the step is stochastic, so the same seed plus the same input gives the same output. Change it if you want a different rendering of detail; keep it if you want reproducibility.chop(default 512) - tile size for large images, snapped to the 256 alignment. An image at or underchopruns as a single tile. This is your VRAM lever - if you're OOM, lower it. Bigger tiles mean more context per tile and weaker seams.overlap(default 64) - the seam overlap between tiles (tile stride =chop - overlap), and also the feather ramp the tile weights blend across. Larger = fewer seams but more redundant compute; 0 gives hard-abutted tiles.tile_batch(default 4) - how many tiles go into one forward pass. Small tiles underfill the GPU one at a time, so batching amortizes launch overhead. VRAM scales roughly linearly with it; tune to your card.
The one optional input, shared_noise (default true), draws a single full-image noise field and shares it across overlapping tiles so the seam-average is discontinuity-free - it kills the faint tile-block seams you'd otherwise see in flat regions. Leave it on; it only matters when the image is actually tiled.
Output is IMAGE at ×scale, ready for SaveImage or further processing.
Installing it
Same pack, same install as the loader:
# ComfyUI Manager: search "Distilled ResShift SR"
# ...or by hand:
cd ComfyUI/custom_nodes
git clone https://github.com/sorryhyun/ComfyUI-Distilled-ResShift
Restart, and the first load auto-downloads the student (~478 MB) and the vq-f4 VQGAN (~211 MB) into ComfyUI/models/resshift/. Dependencies (einops, timm, omegaconf, huggingface_hub) auto-install from pyproject.toml, and there's no xformers requirement. Keep the loader's dtype on bf16 - it's ~2x faster and half the VRAM, and it matches how the student was trained.
Common issues
- Out of VRAM on big images - lower
chop, thentile_batch, before touching anything else. That's the whole story. - Faint seams in flat skies/gradients - make sure
shared_noiseis on and raiseoverlapa bit. - Output keeps changing - that's the stochastic step. Same
seed+ same input = same output; different seed = different detail. - Wrong scale factor - that's a loader-side
scale/student mismatch, not this node. CheckResShiftLoader.
One step, no sampler, no CFG, no key. It's the rare distilled model that just works out of the box.
Inputs (7)
| Name | Type | Default | Description |
|---|---|---|---|
| rsd_model | RESSHIFT_MODEL | — | |
| image | IMAGE | — | |
| seed | INT | 00–18446744073709550000 | Seeds the stochastic step (z_T = z_y + κ·randn and the injected ε). Same seed + input = reproducible output. |
| chop | INT | 512256–4096 | Tile size in px for large images (snapped to a multiple of the Swin align stride, 256). Lower it if VRAM-bound; a whole image ≤ chop runs single-tile. Bigger tiles = more context per tile = weaker seams. |
| overlap | INT | 640–512 | Tile seam overlap in px. Tile stride = chop - overlap (must be >0). Also the feather ramp width (tile weights blend with a raised-cosine across the overlap); 0 = hard-abutted box tiles. Larger = fewer seams, more redundant compute. |
| tile_batch | INT | 41–32 | Tiles stacked into one forward — small tiles underfill the GPU one-at-a-time, so batching amortizes launch overhead. VRAM scales ~linearly; tune to the card. |
| shared_noiseopt | BOOLEAN | true | Draw one full-image noise field and share it across overlapping tiles so the seam-average is discontinuity-free (removes faint tile-block seams in flat regions). A few MB, quality-neutral; only matters when tiled (image > chop). Off = independent per-tile noise (old). |
Outputs (1)
| Name | Type | Description |
|---|---|---|
| IMAGE | IMAGE | — |