PixRestore Restore (512x512, 1 step)
One forward pass, 512×512, and a seed that decides what it invents
- model
- image
- image
- report
This is the node you came for. It takes a degraded 512×512 RGB image and hands back a repaired one - noise removed, blur sharpened, JPEG mush cleaned up - using a single denoiser call. On a 5090 the author measures about 0.11 s per image once the model is loaded, and the model allocates roughly 342 MiB of VRAM while doing it. That is absurdly cheap, and it's the reason to care: this is a restoration pass you can run on twenty seeds to find one you like, not a five-minute commitment.
Be clear about which job this is, though. It does not upscale - no scale factor, no target size, and the input must already be 512×512. It sits with the generative detail-adders like SUPIR and SeedVR2 rather than the ESRGAN interpolators: it can put back fine texture and sharp edges that were never in the file. Which means it can invent the wrong thing.
The mechanism, in one pass
The released config sets fixed_train_t: 1.0, so the sampler starts at t=1 - pure noise - and PixRestore-S is trained to jump from that straight to the clean image, guided by a low-quality conditioning path. Concretely: your image is converted to 8-bit and normalised to [-1, 1]; the DINOv2 ViT-S/14 encoder extracts features from six transformer layers (1, 2, 4, 6, 8, 10) at 448 px input; the pixel-space DiT takes cat([lq, noise]) and runs sample_multistep_fm(n_steps=1), CFG 1.0, bf16 autocast. One pass, no VAE anywhere, output clamped and written back to 8-bit.
Because the starting point is drawn noise, the seed is a real input, not decoration. Same image, same seed, same output (it's deterministic per device and seed). Different seed, different invented texture. That's the whole practical workflow: fix the seed, sweep adjacents, keep the one where the model didn't hallucinate ribs on your lantern.
Inputs and outputs that matter
model-PIXRESTORE_MODEL, straight from PixRestore Loader. Nothing else produces this type.image- a regular ComfyUIIMAGE, up to 64 in a batch. Images are processed one at a time, and image i usesseed + i- the same convention as the official script walking a folder.seed- default 0 (the officialinference.pydefault), range 0 to 2⁶⁴−1. The control-after-generate widget is set to fixed, which is what you want for comparing one change at a time. Sweeping seeds by hand works, but set ComfyUI's "widget control mode" to Before first: otherwise the number in the box is the next seed, not the one that made the image you're looking at.preprocess- a two-option combo, and both options are spelled out by the author:exact 512x512 (refuse other sizes)- the default. Anything else is an error, with a message that tells you the size it got.center crop to 512 (official --test-mode center_crop)- short side resized to 512 with bicubic, then the centre 512×512 is kept. The output is that crop. If you needed the rest of the frame, you've just thrown it away.
Outputs: image (IMAGE - SaveImage, a preview, or straight into your upscaler) and report (STRING, JSON). The report is where you confirm you're on the official path: n_steps: 1, cfg_scale: 1.0, denoiser_calls: 1, per-image SHA-256s for the input, the noise, each DINOv2 feature layer, the float result and the final 8-bit output, plus timings and cuda_max_allocated_mib.
Wiring it up
The graph is tiny: LoadImage → PixRestoreRestore → SaveImage, with the report into PreviewAny. The pack ships that exact workflow (workflows/gui/pixrestore_restore.json) plus a center-crop-then-unload variant and a sample 512×512 JPEG - copy workflows/input/pixrestore_sample_512_jpeg.png into ComfyUI/input first.
Because the output is 512×512, treat it as the repair step and put resolution after it: restore, then a pixel upscaler or SeedVR2. Fix defects first, upscale last; the reverse bakes the defects in.
Install
cd ComfyUI/custom_nodes
git clone https://github.com/hiroki-abe-58/ComfyUI-PixRestore
python -m pip install -r ComfyUI-PixRestore/requirements.txt # timm>=0.9,<1.1
python ComfyUI-PixRestore/tools/setup_pixrestore.py --models-dir ../models
Restart ComfyUI after. Manager can install the code; the ~0.22 GB of weights and pinned upstream source come from that last command and nothing else. Windows 11 + RTX 5090 on ComfyUI v0.38.0 is the tested configuration, and CUDA is mandatory - no CPU, no Apple MPS.
Where it bites
PixRestore-S restores 512x512 images; this one is 800x600- the exact-size refusal. Either switchpreprocessor resize upstream, and accept that you're feeding it something resampled.- Batch size over 64 throws, and so does an image containing NaN or infinity - stated limits, not bugs. A monster seed plus a big batch can also trip the
seed + index < 2**64guard. - Feeding it a non-8-bit image silently rounds to 8-bit, exactly as the official pipeline does;
input_rounding_maxin the report says how much. The upside is that SaveImage writes the same bytes the official script's PNG holds, which is the pack's whole sales pitch.
The honest verdict on quality
The parity claim is real and verifiable: the author reproduces the official one-step output bit-exactly in eager mode across 16 test images, and documents the gap against the torch.compile path (11% of 8-bit values differ, by at most 5/255). Unusually careful work - the numbers you get are the paper's numbers.
The quality evidence is much thinner, and the README says so itself. The PSNR table - noise from 20.7–21.4 up to 29.7–32.4 dB, blur and JPEG improving by less - comes from twelve synthetic images the author generated, and it explicitly warns that twelve synthetic examples say nothing general. There's an upstream issue titled 实测效果很差 ("results are poor in practice") that the repo neither reproduces nor refutes. And you can go looking for community reports: the model has essentially no footprint in the big Stable Diffusion / ComfyUI discussion spaces. You are early here.
So treat it as what it is: a cheap, exact, 512-only, generative pre-cleaner. Good as a first pass before a real upscaler, good for bulk de-noising where you can eyeball twenty outputs in a second. Not the tool for a run of photos where identity has to survive - generative restoration rewrites faces, and that's design, not a setting.
Inputs (4)
| Name | Type | Default | Description |
|---|---|---|---|
| model | PIXRESTORE_MODEL | — | |
| image | IMAGE | — | |
| seed | INT | 00–18446744073709550000 | Seed of the initial noise (the official inference.py default is 0). The output depends on it. Kept fixed after each run unless you change the control. |
| preprocess | COMBO | exact 512x512 (refuse other sizes) | Other sizes are refused unless you choose the official center crop (short side resized to 512 with bicubic, then the centre 512x512 is used). |
Outputs (2)
| Name | Type | Description |
|---|---|---|
| image | IMAGE | — |
| report | STRING | — |