Ltx2TrapezoidalMask1d is correctly rounded; torch.linspace is not, and the blend masks differ in the last f32 bit
Nobody has claimed this yet.
- Dominant language
- C++
- Stars
- 423
- Forks
- 53
- Avg merge
- 20h 26m
- Merged PRs (30d)
- 310
Description
Row: LTX25-A24-VIDEO-VAE-BF16
Ltx2TrapezoidalMask1d (src/vllm/model_executor/models/ltx2_tiling.cpp:157)
builds its ramps with a double linspace and narrows once, so every sample is
the correctly-rounded f32. Upstream builds them with torch.linspace on a
float32 tensor (Lightricks/LTX-2 @ fd4ded7f,
packages/ltx-core/src/ltx_core/tiling.py:39-47), and torch's CPU kernel is NOT
correctly rounded: it computes the first part of the range as
start + step * i and the tail as end - step * (n - 1 - i), where the boundary
between the two depends on the vectorization width, so for some lengths one
sample lands one f32 ulp below the correctly-rounded value.
Swept over n = 2..32 against the port's own Linspace
(src/vllm/model_executor/models/ltx2_tiling.cpp:26-40), narrowed to f32 once:
torch f32 != port double-narrowed, at steps:
[4, 7, 8, 12, 13, 14, 15, 16, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32]
port double-narrowed != correctly-rounded, at steps: []
So they disagree at 21 of the 31 lengths in that range and agree at ten:
n = 2, 3, 5, 6, 9, 10, 11, 17, 18, 19. torch.linspace(1, 0, n) — the right-hand
ramp — disagrees on exactly the same set. The second line is the polarity claim,
measured rather than argued: the port's value is the correctly-rounded f32 at
every n in the sweep, and torch's is not. At n = 4 torch gives
0.6666666269302368 where the correctly-rounded value is 0.6666666865348816.
The earlier form of this paragraph named only n = 4, 7 and 13 (agreeing at 3, 5,
6, 9). That was a spot check written as a measurement, and it is wrong in the
one direction that costs something: an author choosing a fixture geometry from
"avoid 4, 7 and 13" would pick a ramp of 6, whose linspace has 8 steps
(ramp + 2, Ltx2TrapezoidalMask1d), and land on a disagreeing length. Use the
swept set above, not a short list.
Consequences:
- At f32 it is invisible. The relative error is ~6e-8 and the suite's golden band
is 5e-6, sotests/vllm/models/test_ltx2_tiling.cpp's mask case and every
tiled-decode case pass. - At upstream's own bfloat16 it is a whole word. On a shallow tiling fixture
whose temporal overlap produces an n = 4 ramp, 2 of 3888 blended outputs land
one bf16 ulp away from upstream.
The bf16 tiled gate added for #2786 therefore uses a fixture geometry
(frames = (8, 4)) whose ramps do not reach a disagreeing length, so that it
measures the accumulation buffer's width rather than this. Named in that row's
spec under ## Owed.
Deciding what to do needs its own row: mirroring torch's vectorized boundary pins
this port to a torch build detail, and accepting the divergence needs the mask
case tightened from a band to a bit-exact comparison with the disagreement
recorded. Not fixed here.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Read src/vllm/model_executor/models/ltx2_tiling.cpp:26-40 and :157, then compare the port's Linspace with torch.linspace across the reported n = 2..32 sweep. Review tests/vllm/models/test_ltx2_tiling.cpp and the #2786 fixture; done requires a recorded decision on whether to mirror torch or accept the divergence, with the relevant test behavior updated accordingly.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- cpp, pytorch
- Domain
- machine-learning, testing-qa
- Issue type
- Bug
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100