Nodes/ComfyUI_LucidNFT/LucidNFT DiffBIR (SwinIR)
ComfyUI Node

LucidNFT DiffBIR (SwinIR)

The Primer That Tells the Model What 'Bad' Looks Like

By smthemex·Created 7 months ago·Updated 6 days ago· 21
LucidNFT DiffBIR (SwinIR)
  • image
  • ldr
  • lq
◄swinir▾►
◄width1024►
◄height1024►

What it's for

Every restoration workflow has to answer the same question: how does the model know what it's fixing? Point a diffusion model at a soft, blocky, over-compressed JPEG and ask it to make it beautiful and it will happily invent a different photo for you.

LucidNFT DiffBIR answers that with two images instead of one. It runs a SwinIR restoration model over your source to get a clean-ish version - the ldr - and passes that alongside the resized degraded original, the lq. The sampler's dual condition branches then see the before and the after, which is what the whole LucidNFT design is built around. Skip this node and the rest of the graph has nothing to condition on.

It isn't an upscaler and it doesn't produce your final pixels. It's the primer.

How it works

SwinIR is the classic pre-diffusion restorer: non-generative, fast, predictable, incapable of hallucinating a new face. DiffBIR bolted a diffusion stage on top of it; this pack borrows the first half and uses it as a prior.

The node builds the exact SwinIR variant the official repo expects: embed_dim 180, eight residual Swin-Transformer blocks, window 8, sf=8, and - this matters - unshuffle=True with unshuffle_scale=8. It's the unshuffle form, meaning the model does its 8× work in pixel-shuffled space at the input's own resolution rather than the usual "8× upscale then downsample" trick. The architecture is built with strict=True, which is why only general_swinir_v1.ckpt from lxq007/DiffBIR loads.

One oddity that looks like a bug: the node round-trips the input through bfloat16 before mapping it to −1..1. That's deliberate, mimicking the official pipeline, and it discards precision on purpose. Your input gets subtly quantised before restoration. It's part of the recipe, not a mistake.

SwinIR runs on the GPU under no_grad, then gets pushed back to CPU with the cache emptied - so it doesn't squat in VRAM while your DiT samples. That round trip is also where the second or two of per-run overhead goes.

Inputs and the two outputs

  • image - your source. LoadImage, or an image from anywhere upstream.
  • swinir - the dropdown, filtered to files with "swinir" in the name in models/LucidFlux/. Pick general_swinir_v1.ckpt.
  • width / height - default 1024 × 1024, step 8. These are in latent × 8 terms: a 128×128 latent wants 1024. Set them to 0 and the node keeps the source's own size.

The outputs are named, which is the trap:

  • ldr - the SwinIR restoration. This is your colour reference and your second condition image.
  • lq - your input, resized to width × height. The degraded twin.

ldr is slot 0, lq is slot 1. Both go into LucidNFT Condition - lq into its lq input, ldr into its ldr. And ldr also goes to LucidNFT Color Align's reference at the very end of the graph, which is the cheapest quality trick in the whole pack.

The node stretches rather than crops - no aspect guard. Give it a 4:3 photo and a 1024×1024 request and you get a squashed restoration, not a centre crop.

Installing it

ComfyUI Manager, search LucidNFT, install, restart - or clone it:

cd ComfyUI/custom_nodes
git clone https://github.com/smthemex/ComfyUI_LucidNFT

No pip dependencies beyond torch and einops; SwinIR is vendored in swinir_model.py.

You need this one file for this node:

ComfyUI/models/LucidFlux/general_swinir_v1.ckpt   # from lxq007/DiffBIR on HF

models/LucidFlux/ is created on first launch and shared with ComfyUI_LucidFlux, so you may already have it. The other files in there are the Condition node's problem, but the pipeline doesn't run without them.

Where people get burned

Wrong checkpoint, confusing error. DiffBIR has several releases and the README doesn't enumerate them. This wants general_swinir_v1.ckpt - the general-purpose one. A task-specific or v2 checkpoint gives you a load-state-dict failure that reads like a broken install rather than the wrong file. It's the exact complaint that shows up in threads about the author's LucidFlux pack.

Sizing that quietly ruins the condition. The Condition node resamples lq/ldr to latent×8 with bilinear if they don't match, and nothing errors - you just feed the dual branch a blurry upscale and wonder why the result looks soft. Keep width/height at latent × 8: 1024 for a 1024 run, and still 1024 for a 2K run whose latent is 128.

It is not your final image. Run it alone and you get a slightly soft, slightly denoised photo, which is how people conclude the pack is overhyped. The SwinIR pass is deliberately conservative: it gives the diffusion stage a target. The output that matters comes after Color Align.

CategoryLucidNFT

Inputs (4)

NameTypeDefaultDescription
imageIMAGE—
swinirCOMBO1 options: none
widthINT10240–8192—
heightINT10240–8192—

Outputs (2)

NameTypeDescription
ldrIMAGE—
lqIMAGE—