Nodes/ComfyUI-pyiqa-toolbox/(Down)load pyiqa Model
ComfyUI Node

(Down)load pyiqa Model

One loader for every image-quality metric pyiqa knows

By AnsteinHuynh·Created 7 days ago·Updated 6 days ago· 0
(Down)load pyiqa Model
    • model
    • model_name
    • variant_label
    ◄architectureLPIPS►
    ◄variantLPIPS | LPIPS (AlexNet) - FR, lower better, 0-1►

    You have 400 images from a LoRA you just trained, or two upscalers fighting over the same 512px source, and you're doing the thing we all do: flipping between them with the compare slider until your eyes glaze over. A number would be better. That's what this loader is for - it's the front door to pyiqa, the Python image-quality library, and it hands you any one of its metrics as a wireable model.

    One calibration note: a search of a large r/comfyui and r/StableDiffusion corpus turns up exactly two threads mentioning pyiqa, one of them a request for pyiqa nodes. You're early.

    Why it exists as one node instead of forty

    PyIQA isn't a model, it's a catalogue. The pack's own numbers: 53 architectures, 103 variants, from twenty-year-old classics (SSIM, PSNR) to 2026 vision-language scorers. The obvious design is one node per metric, and the pack actually shipped that first - then deleted 23 of those nodes, because every new pyiqa release would have meant more dead-end nodes.

    So: architecture picks the family, variant picks the weights inside it. That's the whole UI. LPIPS, TOPIQ (CFANet), DISTS, MS-SWD, MUSIQ, NIQE, BRISQUE, Q-Align, A-FINE, the lot.

    How it actually works

    The architecture list isn't hardcoded in a chart someone forgot to update - it's read from pyiqa's own DEFAULT_CONFIGS registry table, and the same table supplies each entry's mode (FR or NR), its direction (higher or lower is better) and its score range. That's why the variant labels read like sentences:

    LPIPS | LPIPS (AlexNet) - FR, lower better, 0-1
    A-FINE | NR head - NR, lower better, -2-2
    ARNIQA | default regressor (KonIQ-10k) - NR, higher better, 0-1
    

    Read the label before you wire anything. "Lower better" on LPIPS and DISTS means a good result is a small number, and if you assume every score is a grade out of ten you will spend an afternoon optimising in the wrong direction. When pyiqa adds a metric in a future release, it appears in these dropdowns with no update to this pack needed.

    The variant combo filters to the selected architecture through a small web extension the pack ships. Lose that extension (headless API calls, some frontends) and you get the flat list with every variant prefixed by its architecture - uglier, still works.

    Two dropdown entries are deliberately not loadable - Q-ReAlign and inception_score are signposts whose label says where to go instead. CLIP Score and FID do load, but the generic score nodes refuse them with a pointer to the dedicated nodes, because neither scores a single image.

    The outputs

    model is the thing you wire into pyiqa FR Score or pyiqa NR Score - or into a family node. Model sockets are union types, so a FGResQ model works in both FGResQ nodes as well as the generic NR score, and a wiring mistake gets you a message naming the node that would have worked rather than a shape error.

    model_name is the raw registry string (topiq_fr, lpips-vgg). Use it in filenames and logs; it doesn't change when display names do.

    variant_label echoes the human label. Handy to save next to a batch of scores, so future-you knows which metric produced them.

    Install

    Manager: Install Custom Nodes → search pyiqa-toolbox (the registry id drops the ComfyUI- prefix). Manual:

    cd ComfyUI/custom_nodes
    git clone https://github.com/AnsteinHuynh/ComfyUI-pyiqa-toolbox
    python -m pip install -r ComfyUI-pyiqa-toolbox/requirements.txt
    

    Restart. Ten nodes appear under pyiqa/. Two ready-made graphs ship with it: Workflow → Browse Templates → ComfyUI-pyiqa-toolbox.

    The install side effects are worth knowing before you commit: the pack pins only pyiqa, and pyiqa drags in torch, transformers>=5, accelerate, bitsandbytes and openai-clip. That transformers 5 requirement is the one that bites - custom nodes pinned to transformers 4.x can break after this install. It's the same "no isolation between packs" problem the whole ecosystem has, just with a named culprit this time.

    Weights are not bundled. They land in ComfyUI/models/pyiqa on first use, or in any folder you register as pyiqa in extra_model_paths.yaml - including your existing HuggingFace and torch-hub caches, so nothing downloads twice.

    Common issues

    The metric loaded before my sampler and OOM'd. This was real, and it's fixed: the loader feeding a score node is now lazily evaluated, so the metric builds after the image exists, not during graph setup. If you're on an old version, that's the upgrade.

    A custom fine-tune doesn't show up. Custom weights only count inside an architecture folder: models/pyiqa/LPIPS/my-ft.safetensors, not loose in models/pyiqa/. Refresh ComfyUI (no restart needed) and it appears as an extra variant entry. Larger files (.pth, .ckpt) go through pyiqa's own loader, .safetensors through the pack's.

    One loader slot per node. Switching architecture or variant on the same loader node evicts the previous metric. Two metrics in one graph means two loader nodes.

    First run is slow and looks hung. It's downloading. Watch the console - the size is logged before big loads.

    Categorypyiqa/Generic

    Inputs (2)

    NameTypeDefaultDescription
    architectureCOMBOLPIPSThe network family - LPIPS, TOPIQ (CFANet), ARNIQA, ... The variant dropdown beside it filters to this architecture's entries (needs this pack's web extension; without it the variant list shows every architecture, prefixed by its name).
    variantCOMBOLPIPS | LPIPS (AlexNet) - FR, lower better, 0-1Which weights of that architecture: its head (FR/NR/aesthetic), training set and backbone, then mode, direction and score range - plus any custom checkpoint from models/pyiqa/<architecture>/, labeled with the variant it loads onto. Set-level and text-conditioned metrics (fid/sfid/fid_dinov2, inception_score, clipscore) are listed too - the per-image score nodes refuse them and point at the node that takes them (FID Score, CLIP Score).

    Outputs (3)

    NameTypeDescription
    modelPYIQA_ANYThe loaded pyiqa metric. Wire it into pyiqa FR Score (variants tagged FR) or pyiqa NR Score (variants tagged NR) - or into a family score node, which checks that the model is one it can score.
    model_nameSTRINGThe pyiqa registry name the metric was created from, e.g. 'topiq_fr' (for a custom checkpoint: the variant it was loaded onto, e.g. 'lpips-vgg'). Stable, so it is what you want for filenames, notes or logging.
    variant_labelSTRINGThe variant as shown in the dropdown, e.g. 'NR · SPAQ (ResNet50) - NR, higher better, ~0-~1'.