LTX Attn — Compare Runs
Diff two generations head by head
- diff_heatmap
- stats_text
Say you ran the same video prompt with two different setups - dev vs. distilled, prompt A vs. prompt B, a LoRA on vs. off - and you want to know which attention heads actually changed. That's precisely what Compare Runs does: it takes two captures, diffs one metric per (block, head) pair, and hands you a heatmap of the differences plus a ranked table of the heads that moved the most. It's the "what's structurally different between these two generations" machine, and it's the natural follow-up once Metrics Heatmap has told you each run's landscape separately.
How it works
It reads both stores live from the registry by handle, extracts the chosen metric for sa or ca, and computes A - B per head. The sign convention matters: positive (red) = run A is higher, negative (blue) = run B is higher, and the stats_text output prints which handle is A and which is B so you never have to guess from the image. Blocks are aligned by actual index, so the two runs don't even need identical target_blocks.
The subtle part is diff_mode, because the four metric families don't share a scale. sink is roughly a bounded probability; temporal/spatial are raw scores that range much wider. A raw A - B of 0.3 can mean "huge change" on one metric and "noise" on another:
absolute(default) -A - Bin the metric's own units. Fine for one metric in isolation.relative_pct-(A-B)/max(|A|,|B|) * 100, a scale-free percentage.zscore-(A-B)/std(A and B combined), diff in units of the combined spread. This is the most apples-to-apples way to ask whether one metric moved proportionally more than another.
norm_percentile (default 0.98) clips the color scale at that percentile so a couple of outlier heads don't wash every other cell to white; set it to 1.0 if you want the true max. The heatmap also stamps a numeric colorbar with the actual -clip / 0 / +clip values.
The inputs that matter
store_handle_a/store_handle_b- the two captures to compare.metric- one of the 12; use the_normvariants if the runs don't share the same frame count/resolution.attn_type,step_idx(-1= averaged across all steps),top_k,diff_mode,colormap,norm_percentile.
Outputs are diff_heatmap (IMAGE) and stats_text (STRING) - the text carries the full top-top_k ranked table plus per-run min/max/mean/std, so run one Compare per metric and cross-reference which (block, head) pairs recur. Recurring pairs across metrics are your real structural differences; one-metric-only pairs are often noise.
Install
cd ComfyUI/custom_nodes
git clone https://github.com/g-raw/ComfyUI-LTX-Attention-Toolkit.git
Restart ComfyUI. No extra dependencies, no model downloads. Work-in-progress pack - pinned repos advised.
Common issues
To compare a dumped .pt file rather than live captures, load it into a handle first with Store Load, then reference that handle here. Handles that don't exist resolve to empty, so double-check both names. And the classic trap: comparing raw frame_dist_*/spatial_dist_* across runs with different frame counts or resolutions gives you garbage comparisons - reach for the _norm variants, which were designed exactly for this.
Inputs (10)
| Name | Type | Default | Description |
|---|---|---|---|
| store_handle_a | STRING | — | |
| store_handle_b | STRING | — | |
| attn_type | COMBO | sa | 2 options: sa, ca |
| metric | COMBO | entropy | 12 options: entropy, temporal, spatial, sink, frame_dist_mean, frame_dist_std, +6 |
| step_idx | INT | -1-1–255 | — |
| colormap | COMBO | diverging | diverging: 0 = black, so identical cells read as neutral instead of coolwarm's near-white midpoint. |
| cell_size | INT | 164–64 | — |
| top_k | INT | 151–1536 | How many (block, head) pairs to list, ranked by the diff_mode score. |
| norm_percentile | FLOAT | 0.980.5–1 | Clip the diff_mode score beyond this percentile before mapping to color, so a few outlier cells don't wash out the rest of the heatmap to white. 1.0 = no clipping (use the true max). |
| diff_mode | COMBO | absolute | absolute: A - B, in the metric's own units. Not comparable across metrics with different intrinsic scales (e.g. sink in [0,1] vs raw temporal/spatial scores). relative_pct: (A-B) / max(|A|,|B|) * 100 -- % change, scale-free. zscore: (A-B) / std(A and B combined) -- diff in units of the metric's own spread, the most apples-to-apples way to ask whether one metric moved proportionally more than another. |
Outputs (2)
| Name | Type | Description |
|---|---|---|
| diff_heatmap | IMAGE | — |
| stats_text | STRING | — |