LTX Attn — Head Freeze
Pin a head's attention map at one step and see what breaks
- model
- steered_model
The profiling nodes tell you what attention is; Head Freeze lets you change it and observe the consequence. The intervention: during a generation, lock one or more heads' attention maps to the exact pattern they produced at a chosen earlier step, from a chosen step onward. Freeze head 24-8 at step 3 and the rest of the denoise keeps reusing that historical map - so you can answer "what does the model lose when this head stops evolving?" That's the cleanest way to attribute a behavior to a head, and it's the pack's flagship experiment node.
It requires a prior capture run with full maps: store_mode=full_fp16, or hybrid with the block in full_blocks (or full_targets for per-head capture - Head Freeze only reads a single head either way).
How it works
On each attention call for a targeted block, it checks the current denoising step against freeze_from_step; from that point on, instead of the freshly computed softmax map, it injects the stored map from freeze_step_source. blend_weight controls how hard: 1.0 = pure frozen map, 0.5 = half-and-half blend with the live one. The stored map is replayed against the current run's V, so it's "the historical attention pattern" driving this run's output, not the original output.
targets accepts multiple (block, head) pairs in a single node instance - paste Head Candidates' candidates_csv (one block,head per line) or type block:head | block:h1,h2 | block:all. But freeze_from_step, freeze_step_source, and blend_weight are shared across every target - no per-head override yet. If two heads need different pivots, chain two Head Freeze nodes.
The inputs that matter
targets- the (block, head) list. This is the whole experiment.freeze_from_step- the denoising step at which freezing activates.freeze_step_source- which captured step's map to freeze in.blend_weight- 1.0 pure frozen → 0.0 no-op.attn_type- self-attention only (sais the only choice).store_handle- optional; blank = current active store.
Output is a single steered_model MODEL, wired into the KSampler in place of the plain model.
The disable-by-blanking rule - read this twice
To turn Head Freeze off, clear the targets field - do not use ComfyUI's bypass/mute. This node patches the diffusion model's _forward directly, and that underlying model object is shared across every model.clone() in your session. A normal run unwraps the patch before reapplying it, but bypass/mute skips the node's function entirely, so a stale patch from an earlier run stays in effect even though the node looks disabled. Empty targets still runs the node's code, which reliably unwraps and passes the model through. If you ever suspect a stale patch from a deleted node, run LTX Reset Patches.
Install
cd ComfyUI/custom_nodes
git clone https://github.com/g-raw/ComfyUI-LTX-Attention-Toolkit.git
Restart ComfyUI. No extra dependencies or model files; works with the LTX-2.3 weights you already have. The pack is work-in-progress - node I/O and store formats can change between versions.
Common issues
Most Head Freeze failures are really capture failures: no full map for the targeted block (capture was reduced), or the geometry of the stored map doesn't match the current run (different resolution - re-capture at the same settings you'll freeze at). And the stale-patch trap above is the one that silently wastes hours - when in doubt, blank the targets, or reset.
Inputs (7)
| Name | Type | Default | Description |
|---|---|---|---|
| model | MODEL | — | |
| targets | STRING | 24:8 | One or more (block, head) pairs to freeze in the same run. Paste Head Candidates' candidates_csv directly (one 'block,head' per line), or type manually as 'block:head | block:head | ...' (or 'block:h1,h2,h3' for several heads of one block in a single entry). Use 'block:all' to freeze every captured head of that block. Leave blank to disable the freeze entirely -- this is the reliable way to turn it off; ComfyUI's node bypass/mute skips this node's cleanup, so the diffusion_model (shared across runs) can be left patched from a previous run. |
| freeze_from_step | INT | 30–255 | — |
| freeze_step_source | INT | 30–255 | — |
| attn_type | COMBO | sa | 1 options: sa |
| blend_weight | FLOAT | 1.000–1 | Shared across all targets — no per-head override yet. |
| store_handle | STRING | — |
Outputs (1)
| Name | Type | Description |
|---|---|---|
| steered_model | MODEL | — |