Nodes/ComfyUI-Nunchaku-Klein/Nunchaku FLUX.2 Klein Enhancer
ComfyUI Node

Nunchaku FLUX.2 Klein Enhancer

Prompt weighting is dead in Klein — this is how you get emphasis back

By tom-m-2020·Created 2 months ago·Updated 17 days ago· 2
Nunchaku FLUX.2 Klein Enhancer
  • conditioning
  • CONDITIONING
active_scale1.00
per_token_whiten0.00
norm_equalize0.00
early_layer_scale1.00
mid_layer_scale1.00
late_layer_scale1.00
preserve_original0.00
active_end_override0
deviceauto
debugfalse

Here's the thing nobody tells you about FLUX.2 Klein: ((face:1.4)) does nothing. Its text encoder is a Qwen3 LLM, not CLIP, so all the emphasis syntax you learned in the SDXL era is silently ignored - the model reads your prompt as a chat turn. This node is the workaround. It reaches into the conditioning stream after encoding and explicitly scales the tokens, giving you back a real emphasis control that the model actually feels.

It's the flagship of this pack and a port of the original ComfyUI-Flux2Klein-Enhancer by capitan01R, rebuilt to work against the Nunchaku backend. "Rebuilt" is doing work there: the author is upfront that behavior is close to the original, not identical. Still experimental, still worth it.

How it works

Klein doesn't encode text the way Flux.1 did. It stacks hidden states from Qwen3 layers 9, 18, and 27 into one conditioning vector - early layers carry structural/low-level features, middle layers intermediate semantics, late layers the abstract meaning. This node operates on that conditioning directly. Four knobs matter:

  • active_scale - multiplier on every active token's embedding. 1.0 is identity. The tooltip is blunt: the model was trained on Qwen3's natural distribution and values far from 1.0 push it off-distribution. Translation: a little goes a long way, and "a lot" turns your image to soup.
  • per_token_whiten - amplifies each token's deviation from the sequence mean. Positive widens the spread (sharper differences between tokens), negative compresses it. Called "contrast" in v1, and that's the mental model.
  • norm_equalize - blends every token toward the sequence mean L2 norm. Flattens magnitude variance, which fights Qwen3's natural emphasis. Good for evening out a prompt that's over-pronouncing one token.
  • early_layer_scale / mid_layer_scale / late_layer_scale - the Klein-specific ones. Scale each of the three stacked layer slices independently. If you want to pump up "abstract concept" without touching structure, late_layer_scale is your friend.

preserve_original linearly blends the modified region back toward the untouched conditioning - a safe way to test "is this actually doing anything" by running 1.0 → 0.9 → 0.8.

Wiring and install

In: conditioning (from a Klein text encoder). Out: conditioning, straight into the KSampler. If you're running this whole pack, install is the standard dance:

cd ComfyUI/custom_nodes
git clone https://github.com/tom-m-2020/ComfyUI-Nunchaku-Klein

Backend first, though: the Vitoom Nunchaku wheel from huggingface.co/tonera/vitoom-nunchaku, then tonera's Klein checkpoint into diffusion_models/. No pip deps in the pack itself.

Common issues

  • Set everything to 1.0 and got the same image - correct, that's the point; 1.0 is identity.
  • "Enhanced" image looks burned/plastic - you overshot. Values far from 1.0 are off-distribution by design; dial active_scale toward 1.0 and lean on per-token_whiten in the 0.1-0.3 range.
  • Runs on CPU anyway - device defaults to auto (GPU). If you force cpu, expect slow, and remember this is a conditioning-time op, so it adds a fixed cost per run, not per step.
  • Same seed, different result across runs - Nunchaku nondeterminism, documented in the README, not your settings.
CategoryNunchaku/FLUX.2 Klein/Enhancer/Text

Inputs (11)

NameTypeDefaultDescription
conditioningCONDITIONING
active_scaleFLOAT1.000–10Multiplier on every active-token embedding. 1.0 = unchanged. The model was trained on Qwen3's natural distribution; values far from 1.0 push it off-distribution.
per_token_whitenFLOAT0.00-1–5Amplifies per-token deviation from the sequence mean: (x - mean)*(1+w) + mean. >0 widens spread, <0 compresses. Was called 'contrast' in v1.
norm_equalizeFLOAT0.000–1Blend each token toward the per-sequence mean L2 norm. Flattens magnitude variance — fights Qwen3's natural emphasis. 0 = no effect.
early_layer_scaleoptFLOAT1.000–5Klein-specific. Scale the first Qwen3 layer slice (low-level / structural features). Klein conditioning stacks 3 layers along the embed dim; this targets the first.
mid_layer_scaleoptFLOAT1.000–5Klein-specific. Scale the middle Qwen3 layer slice (intermediate semantic features).
late_layer_scaleoptFLOAT1.000–5Klein-specific. Scale the last Qwen3 layer slice (high-level / abstract semantic features).
preserve_originaloptFLOAT0.000–1Linear blend back the unmodified active region. 0.0 = full enhancement, 1.0 = no change.
active_end_overrideoptINT00–512Override the active-region end. 0 = auto-detect from attention_mask, falls back to full sequence length if mask missing.
deviceoptCOMBOauto2 options: auto, cpu
debugoptBOOLEANfalse

Outputs (1)

NameTypeDescription
CONDITIONINGCONDITIONING