Nodes/Computational LSNet/LSNet Features → Artist Tags
ComfyUI Node

LSNet Features → Artist Tags

Hand the LSNet Classifier a Vector Instead of a Picture

By let-the-name-be-x1·Created 24 days ago·Updated 24 days ago· 2
LSNet Features → Artist Tags
  • features
  • model
  • tag_string
  • json_output
  • probs
  • logits
◄top_k10►
◄threshold0.0000►
◄aggregatemean_logits►
◄temperature1.00►
◄l2_normalizefalse►

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_MODEL handle from LSNet 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) or mean_probs. Only matters when features has multiple rows. The two are genuinely different results; mean_logits is the affine-equivalent one described above.
  • temperature (1.0) - divides logits before softmax. When top-1 lands at 1.0000 and everything else at zero, this is the knob: some images need 1e5–1e6 before any spread appears.
  • l2_normalize - leave this off. head.bn.running_mean has 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_mate normalized - 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.

CategoryComputational LSNet

Inputs (7)

NameTypeDefaultDescription
featuresTENSOR—
modelLSNET_MODEL—
top_kINT101–2000—
thresholdFLOAT0.00000–1—
aggregateCOMBOmean_logits2 options: mean_logits, mean_probs
temperatureFLOAT1.000.01–1000000—
l2_normalizeBOOLEANfalse⚠ 实测:归一化会把 ‖f‖≈49 压到 1,而 head.bn.running_mean 的范数本身就是 48.13,图像信息被 BN 常数项淹没,所有图片都会退化成同一个画师(同一张图归一化后 top1 从 poki_(...) 变成 uni_mate)。除非你同时把尺度乘回去,否则请保持关闭

Outputs (4)

NameTypeDescription
tag_stringSTRING—
json_outputSTRING—
probsTENSOR—
logitsTENSOR—