Nunchaku FLUX.2 Klein Enhancer
Prompt weighting is dead in Klein — this is how you get emphasis back
- conditioning
- CONDITIONING
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 -
devicedefaults to auto (GPU). If you forcecpu, 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.
Inputs (11)
| Name | Type | Default | Description |
|---|---|---|---|
| conditioning | CONDITIONING | — | |
| active_scale | FLOAT | 1.000–10 | Multiplier 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_whiten | FLOAT | 0.00-1–5 | Amplifies per-token deviation from the sequence mean: (x - mean)*(1+w) + mean. >0 widens spread, <0 compresses. Was called 'contrast' in v1. |
| norm_equalize | FLOAT | 0.000–1 | Blend each token toward the per-sequence mean L2 norm. Flattens magnitude variance — fights Qwen3's natural emphasis. 0 = no effect. |
| early_layer_scaleopt | FLOAT | 1.000–5 | Klein-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_scaleopt | FLOAT | 1.000–5 | Klein-specific. Scale the middle Qwen3 layer slice (intermediate semantic features). |
| late_layer_scaleopt | FLOAT | 1.000–5 | Klein-specific. Scale the last Qwen3 layer slice (high-level / abstract semantic features). |
| preserve_originalopt | FLOAT | 0.000–1 | Linear blend back the unmodified active region. 0.0 = full enhancement, 1.0 = no change. |
| active_end_overrideopt | INT | 00–512 | Override the active-region end. 0 = auto-detect from attention_mask, falls back to full sequence length if mask missing. |
| deviceopt | COMBO | auto | 2 options: auto, cpu |
| debugopt | BOOLEAN | false | — |
Outputs (1)
| Name | Type | Description |
|---|---|---|
| CONDITIONING | CONDITIONING | — |