Skip to content

feat(LTX25-TILED-DECODE): tiled + STREAMING Conv VAE decode, and the 60 GiB is not in the decode (#644) - #656

Open
localai-bot wants to merge 3 commits into
mainfrom
row/LTX25-TILED-DECODE
Open

feat(LTX25-TILED-DECODE): tiled + STREAMING Conv VAE decode, and the 60 GiB is not in the decode (#644)#656
localai-bot wants to merge 3 commits into
mainfrom
row/LTX25-TILED-DECODE

Conversation

@localai-bot

Copy link
Copy Markdown
Collaborator

Row 2 of the LTX-2.5 full port. Issue: #644.
Spec: .agents/specs/ltx25-tiled-decode.md (committed at 9e9fd0e5c, before any code).

What landed

ConvVideoDecoder.tiled_decode (conv_video_decoder.py:383-484) with
_accumulate_temporal_group_into_buffer (:508-557), the interval algebra and
separable trapezoidal blend (tiling.py:13-49, 174-361, 423-491, 494-571, 619-841),
both axis mappers (video_vae.py:549-592), and the CONV AUTO layout
(ltx_pipelines/utils/helpers.py:59-88). Upstream pin fd4ded7f.

ltx2_video.cpp now decodes through Ltx2VideoDecodeStreaming and writes each PPM
frame as its temporal chunk arrives, mirroring ti2vid_two_stages.py:365-376. The
full pixel volume is never materialized.

Read this part first: the dispatching premise is refuted, twice

This row was dispatched with "448x256/25f stops because upstream's default decode is
tiled and we call the untiled path; MemAvailable falls 60 GiB in 24 s in the decode."

Measured before building, as the brief required:

1. Upstream's own AUTO layout is a NO-OP at 448x256/25f. split_by_size returns one
interval when dim <= size (tiling.py:199-200). The latent is 8x14 against a 14x24
grid tile and 4 frames against a 10-latent-frame temporal tile. Executed at the pin and
emitted as a golden (kLtx2AutoCases, asserted in test_ltx2_tiling):

request latent tiles groups
320x192/25f 4,6,10 1 1
448x256/25f 4,8,14 1 1
896x512/25f 4,16,28 4 1
1280x704/121f 16,22,40 8 2

Tiling first binds at 896x512 spatially and 121 frames temporally. The size that failed
is a size upstream does not tile either.

2. The decode's own memory is 170x too small to be the 60 GiB. Real shipped conv VAE,
real 448x256/25f latent decoded to completion ([3, 25, 256, 448]), with the global
operator new/delete replaced by an exact live/peak counter:

64x64/9f (model validation) 448x256/25f
largest single allocation 1.74 MiB (predicted 1.74) 99.20 MiB (predicted 99.3)
heap peak live, exact 5.13 MiB 361.72 MiB
decode-attributed RSS 6.13 MiB 362.23 MiB

The analytic ladder model predicted the largest allocation to three significant figures
at both scales, so this is not one run's artefact. Flat process RSS while MemAvailable
fell 60 GiB is itself consistent with the decode not being the consumer.
The 60 GiB is NOT attributed by this row and the axis stays open, with next steps
named in the spec's ## Outcome.

Also newly measured: that decode took 2681 s (44.7 min) of single-threaded
double-precision convolution, so the reported 24-second window cannot have been a
completed decode. Separate row; phase L6 already owes the production-dtype arm.

The probes are committed as scripts/probe_ltx2_* so a reviewer can re-run them.

The equivalence gate the brief asked for does not exist, and was not fabricated

Swept across tile sizes, latent extents and both causality arms, upstream's own
max|tiled - untiled| is 0.67-1.29 times the whole output range and does not
converge as the tile grows — the decoder's receptive field in latent units is wider than
the overlap the layout uses (768 px tile, 64 px overlap on a 32x grid: two latent
cells). Upstream accepts that seam and blends it.

What holds instead, and is what this suite gates:

  • A — our tiled output == upstream's tiled output at the same 5e-6 band every
    other LTX-2.5 golden uses.
  • B — our untiled output == upstream's untiled, same band.
  • B'the ONE-TILE CONTROL is EXACT. A config whose splits all short-circuit
    reproduces forward bit for bit; upstream's own value is 0 on every arm, emitted as
    a golden, and the port is held to == 0.0. This is what makes the pipeline routing
    safe at every size the AUTO layout does not tile — today, every resolution this project
    has run.
  • C — the tiled-vs-untiled gap is upstream's own number, held to the golden band.

Gates

  • BUILD_EXIT=0 clean rebuild, no No space left / BFD assertion, df -h / 91%.
  • ctest -N 416; full ctest -j 6 416/416 after merging origin/main
    (test_engine_core_proc starved once under -j and passes serially — the known
    parallel-starvation set).
  • Focused, with COUNTS: test_ltx2_tiling 9/9, 830 assertions (new);
    test_ltx2_vae 36/36, 3039; test_ltx2_video 30/30, 502.
  • agent-ready.py: all gates green, including the new check-oracle-pins.

Blend mutation — RED, then restored byte-for-byte

Linear ramp replaced by a hard cut at the ramp midpoint in a scratch copy:

  • 9 cases -> 3 passed / 6 failed; 830 assertions -> 39 failed. Case and assertion
    COUNTS unchanged — only the verdicts moved.
  • tiled output moved from <= 5e-6 to max|diff| = 1.11411 (causal) / 1.16359
    (non-causal): five orders of magnitude past the band.
  • caught in four independent places (tiled parity, the gap, complementarity, the mapper
    masks), not one.
  • restored: md5 e734ee2e3503e10ea111305a33574293 before and after, git diff empty,
    rebuild GREEN 9/9 830/830.

Owed, recorded not dropped

  • the 60 GiB attribution (open, next hypotheses named);
  • the reference decoder's throughput (newly quantified, belongs with L6);
  • memory_efficient_decode.py:1-43 — deliberately not ported, since peak decode memory
    measures 362 MiB and it is a second rewrite of CausalConv3d;
  • one fixture header for the LTX-2.5 deterministic stream: test_ltx2_tiling.cpp
    duplicates ~120 lines of test_ltx2_vae.cpp's helpers rather than hoisting them,
    because two other rows are editing that file concurrently and a relocation is the one
    merge shape this protocol has been bitten by.

🤖 Generated with Claude Code

mudler added 3 commits August 13, 2026 17:04
…emise it refutes (#644)

Spec before code, per AGENTS.md.

The row was dispatched on "448x256/25f stops because upstream's default decode
is tiled and we call the untiled path". Executed against the pinned upstream
(fd4ded7f), that half of the premise does not hold: TileSizeConfig.from_long_side
with the Conv auto layout (helpers.py:62-63) resolves to ONE tile and ONE
temporal group at 448x256/25f, because split_by_size short-circuits when
dim <= size (tiling.py:199-200) and the latent is 8x14 against a 14x24 grid tile,
4 frames against a 10-latent-frame temporal tile. Upstream calls forward() once
on the whole volume at that size too. Tiling first binds at 896x512 (spatial)
and 121 frames (temporal).

The decoder's own buffers at that shape are ~2 orders of magnitude too small to
be the 60 GiB: the shipped ladder read from the checkpoint's own metadata gives
a peak on the order of hundreds of MB, and the whole pixel tensor is 32.8 MiB.

The structural port is still owed (ltx2_video_vae.cpp:17-18 records it) and this
spec carries it, together with the derived — not rounded — equivalence bound, the
blend mutation that must RED, and the memory measurement that decides the
attribution.

FOLLOWING_AGENTS_PROTOCOL

Following-Agents-Protocol: true
AI-Assisted: true
Assisted-by: AGENT:claude-opus-5 [Claude Code]
…60 GiB is not there (#644)

Ports `ConvVideoDecoder.tiled_decode` (conv_video_decoder.py:383-484) with
`_accumulate_temporal_group_into_buffer` (:508-557), the interval algebra and
separable trapezoidal blend (tiling.py:13-49, 174-361, 423-491, 494-571,
619-841), both axis mappers (video_vae.py:549-592) and the CONV AUTO layout
(ltx_pipelines/utils/helpers.py:59-88). Upstream pin fd4ded7f.

`ltx2_video.cpp` now decodes through `Ltx2VideoDecodeStreaming` and writes each
PPM frame as its temporal chunk arrives, mirroring ti2vid_two_stages.py:365-376.
The full pixel volume is never materialized.

MEASURED BEFORE BUILDING, and it refutes the dispatching premise twice.

1. Upstream's own AUTO layout is a NO-OP at 448x256/25f. `split_by_size` returns
   one interval when `dim <= size` (tiling.py:199-200); the latent is 8x14
   against a 14x24 grid tile and 4 frames against a 10-latent-frame temporal
   tile. Executed at the pin and emitted as a golden: 1 tile, 1 group. Tiling
   first binds at 896x512 spatially and 121 frames temporally. So the size that
   failed is a size upstream does not tile either.

2. The decode's own memory is 170x too small to be the 60 GiB. Real shipped conv
   VAE, real 448x256/25f latent decoded to completion, exact operator new
   accounting: heap peak live 361.72 MiB, largest single allocation 99.20 MiB,
   decode-attributed RSS 362.23 MiB. The analytic ladder model predicted the
   largest allocation to three significant figures at two scales. The 60 GiB is
   NOT attributed by this row and the axis stays open with named next steps.

Also newly measured: that decode takes 2681 s (44.7 min) of single-threaded
double-precision convolution, so the reported 24-second window cannot have been
a completed decode. Separate row; phase L6 owes the production-dtype arm.

The equivalence gate the brief asked for does not exist and was not fabricated.
Swept across tile sizes and both causality arms, upstream's own
max|tiled - untiled| is 0.67-1.29 TIMES the output range and does not converge —
the receptive field is wider than the 2-latent-cell overlap. What IS exact is the
ONE-TILE CONTROL: a config whose splits all short-circuit reproduces `forward`
bit for bit, upstream measures 0 and the port is held to == 0.0. That is what
makes the pipeline routing safe at every size run so far.

Gates: BUILD_EXIT=0 clean, no ENOSPC/BFD, ctest -N 416, full ctest 416/416.
test_ltx2_tiling 9/9 830 assertions; test_ltx2_vae 36/36 3039; test_ltx2_video
30/30 502. Blend mutation (linear ramp -> hard cut) REDs 6/9 cases and 39/830
assertions with tiled max|diff| 1.11411 vs a 5e-6 band, and is caught in four
independent places; restored byte-for-byte (md5 e734ee2e35..., rebuild GREEN).

FOLLOWING_AGENTS_PROTOCOL

Following-Agents-Protocol: true
AI-Assisted: true
Assisted-by: AGENT:claude-opus-5 [Claude Code]
FOLLOWING_AGENTS_PROTOCOL

Following-Agents-Protocol: true
AI-Assisted: true
Assisted-by: AGENT:claude-opus-5 [Claude Code]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants