Nodes/comfyui-lsnet/Kaloscope Feature Comparison
ComfyUI Node

Kaloscope Feature Comparison

Which of my three style groups is this closest to?

By spawner1145·Created 12 months ago·Updated 2 days ago· 104
Kaloscope Feature Comparison
  • image
  • model
  • group_1
  • group_2
  • group_3
  • comparison_json

This is the payoff node for the whole group-comparison side of Kaloscope. You've built three average style vectors - say, one artist you're aiming for, one you keep accidentally drifting toward, and your own baseline style - and now you want the node to just tell you which one a new render resembles. That's exactly what Feature Comparison does, and it does it in one line of JSON.

It's a small node with a snappy job: query image in, up to three group vectors in, similarity per group plus a best_group_index out. If your workflow is "check every third render against my style reference," this is the node you hang the branch off.

How it works

The image goes through the model exactly like it does in Artist Similarity: first frame, back to PIL, the checkpoint's own training transform, one forward pass with return_features to get a pooled global vector. Each connected group_* input is then compared against that query vector by cosine similarity - dot product over the product of norms - the same measure Artist Similarity uses, so the two nodes give you numbers on the same scale.

The output is a JSON string with three fields: all_similarities (a list, in the order the groups were read, i.e. only the ones you actually connected), best_similarity, and best_group_index. Two groups connected means a two-element list and an index of 0 or 1 - so if your node graph names are artist_a, artist_b, artist_c, the index maps to the connection order, not to the group number you skipped. Connect them in a fixed order and label them in your own notes, because the JSON won't do it for you.

Cosines are in the range you'd expect: near 1 is "same neighbourhood," around 0.5–0.8 is the zone most real comparisons land in because these embeddings are dense and rarely orthogonal, and negatives mean opposite. There's no threshold baked in. You decide what counts as a match, and you should decide it from a control - score a few images you know belong to each group and see where the numbers sit before you trust a verdict on something new.

Wiring it up

Each group_* wants a [D] tensor, which is precisely what Kaloscope Common Features outputs. Typical graph:

artist_a images → Kaloscope Common Features → group_1 ┐
artist_b images → Kaloscope Common Features → group_2 ├→ Kaloscope Feature Comparison → comparison_json
artist_c images → Kaloscope Common Features → group_3 ┘        ↑
                                        new render → image ────┘
                                        model ────────────────┘

Leaving a group slot empty is fine - the optional inputs are only read when connected. Connect nothing and you get a JSON error object back rather than a crash, which is a polite way of saying "you forgot the groups."

Install

cd ComfyUI/custom_nodes
git clone https://github.com/spawner1145/comfyui-kaloscope
cd comfyui-kaloscope
python -m pip install -r requirements.txt

Weights into ComfyUI/models/kaloscope/<folder>/ alongside config.json; Kaloscope v2 is what's public today. Same loader node feeds this one.

The traps

Everything in this node assumes the group vectors and the query image came out of the same model configuration. Different checkpoint, different architecture, different pooling - the cosine still returns a number, and the number is meaningless. There's no consistency check anywhere in the pack, so this one is on you.

Group means are also only as good as the group. A [D] average from twenty curated pieces by one artist is a usable fingerprint; the same average computed over a folder that happens to contain three art styles is a fingerprint of nothing. And because means are means, they sit closer to the centre of the feature space than individual images do, which tends to make all your group similarities bunch up in a narrow band - another reason to calibrate with known-group examples rather than reading 0.72 versus 0.68 as a decisive gap.

Last thing, easy to miss: the node only ever uses the first image of the image batch. If you want scores for ten renders, that's ten executions or a batch-aware loop - this node gives you one verdict per run.

CategoryKaloscope

Inputs (5)

NameTypeDefaultDescription
imageIMAGE—
modelKALOSCOPE_MODEL—
group_1optTENSOR—
group_2optTENSOR—
group_3optTENSOR—

Outputs (1)

NameTypeDescription
comparison_jsonSTRING—