LTX Attn — Setup Capture
The node everything else in this pack is downstream of
- model
- patched_model
- handle
If you landed on this node, you're not making a video - you're dissecting one. LTX Attn - Setup Capture is the front door of the LTX Attention Profiler pack (g-raw/ComfyUI-LTX-Attention-Toolkit): it patches an LTX-2.3 model so that every attention call gets logged, and every other node in the suite reads the data it records. Nothing happens until this node runs a generation.
The pitch, in one line: capture per-head attention metrics, reduced key/query maps, optionally full attention maps, and optionally raw Q/K/V - all in one node. LTX-2.3 (Lightricks' 22B flow-matching video model, the one that finally made LTX competitive with Wan) has 48 transformer blocks and 32 heads per block, and this node is your way to see what those 1,536 heads are actually doing while they denoise.
How it works
It installs a single universal hook on ComfyUI's optimized_attention (and its masked variant), plus a wrapper on the diffusion model's _forward. Each transformer block makes two attention calls per step - self-attention (call 0) and cross-attention (call 1) - and the hook counts calls per block to tell them apart. When a call matches your target_blocks and target_heads, it computes the metrics (chunked on GPU, moved to CPU so they don't eat your VRAM) and stores the reduced key/query maps. The geometry - number of frames, latent height and width - is auto-detected from the live latent, so you don't fill in resolution widgets here.
The one setting that decides how much RAM you eat is store_mode:
reduced- metrics plus key/query maps only. Roughly 332 MB for all 48 blocks. This is your "profile everything" mode.full_fp16- adds the full[heads, Sq, Sk]attention map for every target block. That's ~16 GB for 5 blocks at 1280×720/16 frames. Painful but real.hybrid- full maps for the blocks infull_blocks, reduced elsewhere (~16.3 GB with 5 full blocks). The sensible middle.
Full maps are what Head Freeze, Query Map, Key Map, and Zone Analysis need; metrics and key/query maps work from reduced alone. If RAM is your constraint, map_downsample and hybrid's full_targets (per-head selection for specific blocks) are how you survive - a full native map is ~25 MB per head.
capture_qkv is a separate track: it stores raw Q/K/V per head into an independent QKV store, which only QKV Transfer uses. It's much more expensive, so it has its own qkv_targets list, independent of target_blocks. Don't turn it on unless you're planning a transfer.
The inputs that matter
For a first profiling run, honestly: leave almost everything default and flip target_blocks to "all" with store_mode=reduced. The two outputs - patched_model and handle - matter more than any widget. Plug patched_model between your LTX loader and the KSampler.
Here's the gotcha that trips everyone: handle is a plain STRING, not a wireable socket, and that's deliberate. The store is only populated during the KSampler run, after this node has already returned. If the viz nodes were wired sockets, ComfyUI would schedule them too early and they'd always read empty stores. So you type the handle into a viz node's store_handle widget in a later, separate queue run (or use Store Load to wire it in after loading). Blank handle = whichever store is currently active.
Install
cd ComfyUI/custom_nodes
git clone https://github.com/g-raw/ComfyUI-LTX-Attention-Toolkit.git
Restart ComfyUI. There are no extra dependencies beyond what ComfyUI already ships (torch, numpy), and no model files to download - it works with the LTX-2.3 weights you already load. ComfyUI Manager may not list this one (it's a niche, research-focused pack), so the clone is the reliable path.
Common issues
This pack is marked work in progress, and it means it: node inputs/outputs, store formats, and naming can change with breaking changes, and saved .pt files may stop loading after an update. Pin the repo if you rely on it. It's also LTX-2.3 only - 48 blocks, 32 heads, patch_size=1; it won't profile other models, and audio isn't captured (video stream only).
The most common real mistake is capturing in full_fp16 mode with all 48 blocks and wondering why you ran out of RAM. Use reduced to explore, hybrid when you know which blocks matter.
Inputs (14)
| Name | Type | Default | Description |
|---|---|---|---|
| model | MODEL | — | |
| capture_sa | BOOLEAN | true | — |
| capture_ca | BOOLEAN | true | — |
| target_blocks | STRING | 0,8,16,24,32,40,47 | — |
| target_heads | STRING | all | — |
| capture_steps | STRING | all | — |
| store_mode | COMBO | reduced | reduced: metrics + key/query maps only full_fp16: + full attention map for every target block hybrid: full map only for full_blocks, reduced elsewhere |
| full_blocks | STRING | 8,16,24,32,40 | Blocks stored at full resolution (every head) in hybrid mode. A block also listed in full_targets uses full_targets' per-head selection instead (full_targets wins for that one block); full_blocks still applies normally to any block it doesn't cover -- the two can be combined: coarse whole-block capture for exploration (Query Map/Key Map/Zone Analysis) alongside fine per-head capture for Head Freeze targets. |
| full_targets | STRING | Optional, hybrid mode only: for the specific blocks listed here, restrict full-map storage to specific (block, head) pairs instead of every head -- saves RAM when you already know which heads you'll feed into Head Freeze. Paste Head Candidates' candidates_csv directly (one 'block,head' per line), or type manually as 'block:head | block:head | ...' (also accepts 'block:h1,h2,...' and 'block:all'). Heads not listed for a block covered here won't have a full map available, so Query Map/Key Map/Zone Analysis on them will error or skip -- use Head Freeze/QKV Transfer for those, or add that block to full_blocks instead (not here) for full multi-head coverage. | |
| map_downsample | INT | 11–64 | — |
| capture_qkv | BOOLEAN | false | Also capture raw Q/K/V per head into a separate QKV store, for QKV Transfer. Not redundant with store_mode's full attention map: the map only replays the exact historical pattern, raw Q/K/V lets QKV Transfer recombine components from two different generations into a new pattern. |
| qkv_targets | STRING | Only used when capture_qkv is on. Same format as full_targets/Head Freeze's targets: paste Head Candidates' candidates_csv directly (one 'block,head' per line), or type manually as 'block:head | block:h1,h2,... | block:all | ...'. A whole-string 'all' (or 'all:all') captures every block and head. Independent from target_blocks/target_heads above -- raw Q/K/V is much more expensive than the metrics/key/query maps, so this needs its own explicit list. | |
| store_name | STRING | — | |
| reset_store | BOOLEAN | true | — |
Outputs (2)
| Name | Type | Description |
|---|---|---|
| patched_model | MODEL | — |
| handle | STRING | — |