Nodes/Concept Steer/Layer Steer
ComfyUI Node

Layer Steer

Steer only the transformer layers where your concept actually lives

By Nynxz·Created 6 months ago·Updated 6 months ago· 4
Layer Steer
  • model
  • MODEL
lensNone
strength1.00
layer_presetall
layer_mask0-5:0.2, 6-18:1.0, 19-23:0.5
num_layers48
normalizetrue
report_statstrue
report_interval5
custom_lens_path

Concept Steer adds its direction to the conditioning, which the model then projects through every cross-attention layer identically. Layer Steer is the surgical version: it hooks into the output of each cross-attention block and injects a per-layer-scaled concept direction. That buys you three things the docstring spells out - interpretability (which layers actually respond to your concept?), precision (only steer where the concept manifests), and fewer artifacts (don't push a concept into layers that don't "understand" it, which causes incoherence).

How it works

It uses ComfyUI's set_model_attn2_output_patch() to intercept each cross-attention block's output and add a scaled concept direction before the residual stream continues. The per-block strength comes from a layer mask - a compact string format like 0-5:0.2, 6-18:1.0, 19-23:0.5 - or from a preset (all, early, middle, late, custom) computed over num_layers.

The presets encode the community heuristic about what each band of the network handles: early layers = composition/layout, middle = subject/object features, late = texture/detail/lighting. So "moody lighting" is a late-layer concern and "minimalist composition" is an early one; Layer Steer lets you steer precisely where each lives instead of everywhere at once.

Bonus: report_stats prints per-layer steering statistics to the console every report_interval denoising steps. That's the interpretability payoff - you can literally watch which layers are most affected by your concept injection and learn where the concept "lives" in the model.

The inputs that matter

  • model - a MODEL; you get a patched MODEL back for the KSampler.
  • lens - dropdown (or custom_lens_path).
  • strength - global strength, multiplied by the per-layer mask.
  • layer_preset - all / early / middle / late / custom.
  • layer_mask - used when preset is custom. Format: range:strength, range:strength, .... 6-18 means layers 6–18 at 1.0; 10,11,12:1.5 targets individual layers; unspecified layers default to 0.0.
  • num_layers - total transformer layers, for preset math. 48 for Lumina2/Z Image Turbo, 24 for SD 1.5, 70 for SDXL. This is the one input beginners get wrong.
  • normalize - scale the direction relative to cross-attention output norms; leave on.
  • report_stats / report_interval - console diagnostics.

Output is a single MODEL. Wire [Load Model] → Layer Steer → KSampler.

Installing

Pack-standard: ComfyUI Manager search "Concept Steer", or git clone https://github.com/Nynxz/ComfyUI-ConceptSteer into custom_nodes/ and restart. Same as the rest of the pack - a trained lens, transformers/safetensors for training, no new model downloads.

Common gotchas

  • num_layers wrong = presets in the wrong place. The presets divide the layer count into thirds, so a wrong count silently steers the wrong band. Check the model's real depth (48 for Z Image Turbo, 24 for SD 1.5, 70 for SDXL per the tooltip).
  • Layer mask syntax is exact. Ranges with :strength, commas between entries, layers you don't mention get 0.0 - a stray space or missing colon turns the whole mask into noise.
  • Use the patched MODEL. Same trap as Timestep Steer - the output of this node is the model to sample with; wiring the original loader model to the KSampler gives you nothing.
  • Report stats are console output, not a node output. If you're looking for them in the graph, you won't find them. They print to the ComfyUI terminal.
CategoryConcept Steer/Advanced

Inputs (10)

NameTypeDefaultDescription
modelMODEL
lensCOMBONoneSelect a concept lens to apply
strengthFLOAT1.00-10–10Global steering strength (multiplied by per-layer mask)
layer_presetCOMBOallWhich layers to steer: • all — every layer at full strength • early — first third of layers (composition/layout) • middle — middle third (subject/object features) • late — last third (texture/detail/lighting) • custom — use layer_mask input for fine control
layer_maskSTRING0-5:0.2, 6-18:1.0, 19-23:0.5Fine-grained per-layer strength (only used when preset='custom'). Format: 'range:strength, range:strength, ...' Examples: '6-18' → layers 6-18 at 1.0 '0-5:0.2, 6-18:1.0, 19-23:0.5' → graduated '10,11,12:1.5' → individual layers Layers not specified default to 0.0 (no steering).
num_layersINT481–200Total number of transformer layers in the model. Used for preset calculations. 48 for Lumina2/Z Image Turbo, 24 for SD 1.5, 70 for SDXL.
normalizeBOOLEANtrueScale direction relative to cross-attention output norms
report_statsBOOLEANtruePrint per-layer steering statistics to console. Shows which layers are most affected by the concept injection — useful for understanding where concepts 'live' in the model.
report_intervalINT51–100Print layer report every N denoising steps
custom_lens_pathSTRINGOverride: absolute path to a .pt lens file

Outputs (1)

NameTypeDescription
MODELMODEL