LSNet Features → Artist Tags
Hand the LSNet Classifier a Vector Instead of a Picture
- features
- model
- tag_string
- json_output
- probs
- logits
If you run the LSNet / Kaloscope artist classifier, you already have image → artist tags. What you could never do is go the other direction and hand the classifier a vector. This node is that door.
Artist strings are the whole game on the Illustrious / NoobAI / Anima line - a well-chosen artist tag does more than a stack of style LoRAs, and the ecosystem had to build style explorers precisely because artist tags work superbly and are almost undocumented. The classifier inverts that lookup; this node makes the inversion computable. Now you can classify the average of five reference images, a 30/70 blend of two styles, or a vector you pushed around by hand in an expression.
How it actually works
LSNet 2.0's forward pass is: 448×448 image → backbone + pooling → 768 → projection (BN_Linear(768→2048) + ReLU) → f, a 2048-dim "style vector" → head (BN_Linear(2048→39261)) → logits.
The head is a standalone submodule whose input is f. Calling head(f) yourself is bit-identical to the plugin's own image classification - the author measured logit and probability error of exactly 0.00e+00, identical top-20 ordering. And because BN and Linear are affine in eval mode, head(mean(f)) == mean(head(f)) within float noise, so averaging a batch of vectors and classifying the average is a real logit-space ensemble, not an approximation.
The inputs you'll actually touch
- features - the tensor to classify. It must be the post-projection 2048-dim output of
LSNet Common Features. Feeding the 768-dim backbone features throws a dimension error that names the size the head expected. - model - the
LSNET_MODELhandle fromLSNet Model Loader. - top_k (10, up to 2000) and threshold (0.0) - how many names, and a probability floor. On a saturated image that floor leaves you top-1 and nothing else, so leave it at 0.
- aggregate -
mean_logits(default) ormean_probs. Only matters whenfeatureshas multiple rows. The two are genuinely different results;mean_logitsis the affine-equivalent one described above. - temperature (1.0) - divides logits before softmax. When top-1 lands at
1.0000and everything else at zero, this is the knob: some images need1e5–1e6before any spread appears. - l2_normalize - leave this off.
head.bn.running_meanhas a norm of 48.13 while a typical feature norm is 49, so squashing the vector to unit length hands the head a constant. Same image, author's test:poki_(j0ch3fvj6nd)raw,uni_matenormalized - and every image collapsed to that same name.
Outputs
tag_string is raw class names (poki_(j0ch3fvj6nd), underscores and all) - run it through Artist Tags → Prompt before it reaches CLIPTextEncode. json_output gives you name→probability but only for the top-k, so don't expect it to sum to 1. probs is all 39261 classes and does sum to 1. logits is the raw pre-softmax tensor, shape (N, C).
Prefer logits when you're ranking or comparing: on one out-of-distribution image the author measured 39260 of 39261 probabilities at exactly 0.0, so softmax ranking degrades into ties. Use probs when you need something bounded and addable.
LoadImage → LSNet Common Features ─┐
LSNet Model Loader ────────────────┴→ LSNet Features → Artist Tags → Artist Tags → Prompt → CLIPTextEncode
And the version that earns the node its keep - blending styles in feature space instead of fighting with prompt weights:
Common Features → Vector Math "mix(V0, V1, 0.3)" → LSNet Features → Artist Tags
Install
cd ComfyUI/custom_nodes
git clone https://github.com/let-the-name-be-x1/Computational-LSNet.git
# restart ComfyUI, then search the category "Computational LSNet"
The pack has no Python dependencies of its own - requirements.txt is deliberately empty and pyproject.toml declares dependencies = [] so ComfyUI Manager can't pip-install a torch that replaces your CUDA build. Once it's in the Registry, the README also offers comfy node install computational-lsnet.
The real prerequisite is upstream: spawner1145/comfyui-kaloscope, legacy branch - the lsnet 1.0.8 package in ComfyUI Manager. Plus the model directory models/lsnet/kaloscope2.0/ holding best_checkpoint.pth (≈2.94 GB), class_mapping.csv, and config.json.
Where people get burned
Kaloscope 3.0 is not supported, and it fails loudly rather than subtly. 3.0 renames the handle to KALOSCOPE_MODEL, switches to a 1536-dim head input, and splits the style vector into two branches. The model port here will refuse the connection outright. This is an architecture difference, not a config problem - stay on the 2.0 line (the legacy branch / Manager's lsnet 1.0.8).
Passing the wrong tensor. LSNet Common Features gives you 2048 dims; the 768-dim backbone features are not it.
Trying to eyeball the outputs. Show Text 🐍 refuses TENSOR links outright, and core Preview Any truncates at head-6 / ... / tail-6. Use Vector → Text / txt - plain STRING, no ellipsis.
And one expectation to set, because the community's own verdict on Kaloscope is that it sometimes nails a style and often can't tell at all: read the top 10–20 names, not top-1.
Inputs (7)
| Name | Type | Default | Description |
|---|---|---|---|
| features | TENSOR | — | |
| model | LSNET_MODEL | — | |
| top_k | INT | 101–2000 | — |
| threshold | FLOAT | 0.00000–1 | — |
| aggregate | COMBO | mean_logits | 2 options: mean_logits, mean_probs |
| temperature | FLOAT | 1.000.01–1000000 | — |
| l2_normalize | BOOLEAN | false | ⚠ 实测:归一化会把 ‖f‖≈49 压到 1,而 head.bn.running_mean 的范数本身就是 48.13,图像信息被 BN 常数项淹没,所有图片都会退化成同一个画师(同一张图归一化后 top1 从 poki_(...) 变成 uni_mate)。除非你同时把尺度乘回去,否则请保持关闭 |
Outputs (4)
| Name | Type | Description |
|---|---|---|
| tag_string | STRING | — |
| json_output | STRING | — |
| probs | TENSOR | — |
| logits | TENSOR | — |