Skip to content

No restoration path in the LTX-2.5 family: Deblur and Decompression IC-LoRAs are a different trade from re-rendering #152

Closed

Description

@dkackman

tool/endpoint: templates/ltx2/* — no restoration pass exists; two-stage is the only sharpening route

repro: the family's only answer to a soft or noisy render is templates/ltx2/two-stage
(eight sigmas at 768x448, 2x latent upsample, three stage-two sigmas at 1536x896) or
templates/ltx2/generative-upscale. Both re-render. Neither cleans up an existing result.

what's now available: two LTX-2.5 IC-LoRAs from 2026-09-10:

why it is worth measuring rather than assuming. These are a genuinely different trade from
what the family has: restoration over a cheap low-resolution render, versus re-rendering at
higher cost. That is the exact decision that came up in practice today on the H3 side — a
grainy, mushy background at 544p, where the only routes on offer were "render bigger" (which hit
the 24 GB ceiling) or "accept it". Whether a restoration pass beats a refine pass on quality per
minute is an open question, and answering it needs a comparison, not an adoption.

proposed: one template for each, plus a measured comparison against two-stage on the same
source clip — quality and wall clock.

same cheap-plumbing point as #151: generative-upscale already runs an IC-LoRA step through
LTX2ReferenceCondition / reference_conditions=, so these are templates and prompts, not
engine work.

caveats: both weights are 0.9 previews (only Clean-Plate shipped at 1.0), and both repos
are gated: auto — lem has access, but the cards could not be read unauthenticated here, so
the input format each expects is unverified.

related: #151 (Ingredients, same IC-LoRA batch); full write-up on #151.

Activity

  1. dkackman commented on Sep 14, 2026

    @dkackman
    OwnerAuthor

    Blocked on the same thing as #151, and parked with Don for the same reason. Worked as model opus via provider anthropic.

    Neither weight is reachable. The gates on these repos have not been accepted by the account lem's Hugging Face token belongs to. Checked from lem with that token: Deblur and Decompression return 403 on both the card and a file range request, while the upscaler repo dw already uses returns 200 on both. So gated: auto is per repo, and this 2026-09-10 batch was never accepted — the inference on #151 that access came along with the upscaler does not hold.

    That blocks the measurement this issue is actually asking for, not just the download. You were right that the interesting question is whether a restoration pass beats a refine pass on quality per minute, and that it needs a comparison rather than an adoption. I cannot set up a comparison against two-stage on weights I cannot fetch, and neither can the tester.

    Also worth stating before anyone builds it: the input format is unconfirmed for exactly the same reason (the cards are 403). For a restoration IC-LoRA the open questions are whether the degraded clip goes in as a LTX2ReferenceCondition at reference_downscale_factor: 1 (unlike the upscaler's 2), what conditioning_attention_strength it wants, and whether the prompt should describe the clean target or the degraded source. Guessing those produces a template that validates and restores nothing in particular.

    To unblock: accept the licence on
    https://huggingface.co/Lightricks/LTX-2.5-22b-IC-LoRA-Deblur and
    https://huggingface.co/Lightricks/LTX-2.5-22b-IC-LoRA-Decompression
    as the account whose token is on lem, then hand back with owner:implementer and no status label. Both are 0.9 previews, as you noted — I would still build them as two templates and measure rather than assume, which is what you proposed.

    When that happens, the comparison worth running is the one you framed: a cheap low-resolution render restored, against two-stage's refine, on the same source clip, scored on quality and wall clock. I would add the same run through templates/ltx2/diffusion-decode (shipped for #153), since that is a third answer to "the picture is soft" that costs only a decode.

  2. added
    owner:donParked for human decision
    status:needs-infoBlocked on a question, bounced back
    and removed on Sep 14, 2026
  3. dkackman commented on Sep 14, 2026

    @dkackman
    OwnerAuthor

    licenses accepted

  4. added and removed
    owner:donParked for human decision
    status:needs-infoBlocked on a question, bounced back
    on Sep 14, 2026
  5. added 2 commits that reference this issue on Sep 14, 2026
  6. dkackman commented on Sep 14, 2026

    @dkackman
    OwnerAuthor

    Unblocked and shipped. Gate accepted — verified from lem with its own token before writing anything (README 200 for Deblur and Decompression both), so the recipes below are the cards' rather than inferences from the upscaler's shape.

    Two templates, because the cards are emphatic that these are not interchangeable and neither is a general restoration:

    templates/ltx2/restore-deblur — spatial defocus only. The card rules out motion blur (no temporal blur in the dataset at all), compression-artefact repair, denoising, and super-resolution of already-sharp footage. Extreme blur is hallucinated rather than reconstructed.

    templates/ltx2/restore-decompression — macroblocking, chroma bleed, ringing, banding. The card rules out defocus, motion blur, grain, upscaling and colorization.

    Both share the shape, which is the part that answers your framing — "a different trade from re-rendering":

    • The reference is the caller's own clip, attached for the whole denoise, so identity, framing and background geometry are the source's and only the defect changes. These are the first templates in the family whose reference is a file dw did not generate; every other IC-LoRA use here conditions on an earlier step's output.
    • reference_downscale_factor 1 — the reference is encoded at the output resolution. Not the upscaler's 2.
    • Trained bucket 960×544, 121 frames, 24 fps, which is what the defaults are. Both cards warn that generating far above the bucket weakens the effect, and the descriptions say so.
    • lora_scale 1.0, exposed as a variable — Deblur's card says to sweep toward 0.8 if it over-sharpens into haloing or ringing.
    • The prompts are the trained dual-panel forms, stored as prompts/ltx2/deblur_dual_panel and prompts/ltx2/decompression_dual_panel: "Reference shows … DEBLUR / ENHANCE QUALITY … only focus and sharpness / only compression artifacts and image quality differ". Replace both halves' scene descriptions, keep the structure.
    • Both weights are 0.9 previews. Said in each description.

    source_video defaults to an asset: placeholder (asset:blurry.mp4, asset:compressed.mp4), the same convention assemble-and-score uses — the template is not runnable until the caller points it at their footage, which is correct for a restoration pass.

    Every number above is pinned to its card by tests/test_ltx2_ic_loras.py, so a re-audit that finds the vendor has moved fails here rather than in a run.

    Not measured against two-stage. Your ticket's framing is that this is a different trade and worth measuring against the refine pass — I agree, and I have not done it. Both are 0.9 previews, "better" on a grainy 544p background is a judgement about output rather than a pass/fail, and it is two GPU runs plus a look. That is a deliberate experiment for whoever has the source clip that started this, not something to spend on my say-so. The templates are there to make it cheap.

    Note the plan.downloads_required fix from #151 applies here too — both LoRA repos are now named before the run rather than pulled mid-run.

    Deploy path: server code plus catalog. develop at b599cf3 (the templates are a526fde), pulled on lem, dw.serve restarted in its screen session, /api/health status: ok. 2026-09-14 21:07 UTC. 4862 tests pass.

    Regression case — regression-suite-model-specific.md, no GPU:

    • list_workflows(shape="shot") includes templates/ltx2/restore-deblur and templates/ltx2/restore-decompression.
    • validate_workflow("templates/ltx2/restore-deblur", arguments={"source_video": "asset:<something real>"}) → valid, and plan.downloads_required names Lightricks/LTX-2.5-22b-IC-LoRA-Deblur on a box that has not pulled it.
    • validate_workflow(..., arguments={"num_frames": 120}) → refused (the LTX 8n + 1 grid, no snap).

    Implementer agent, model opus via provider anthropic.

  7. dkackman commented on Sep 14, 2026

    @dkackman
    OwnerAuthor

    Verified over MCP. Ran as model opus via provider anthropic, workspace default (validate-only, nothing written).

    The implementer's three proposed checks, all green:

    1. list_workflows(shape="shot", traits="needs-input-media") lists both templates/ltx2/restore-deblur and templates/ltx2/restore-decompression, each shape: shot, traits has-audio, needs-input-media (note: not image-conditioned — the reference is a clip, which reads correctly), constraints.num_frames: "8*n+1, 9+".

    2. validate_workflow("templates/ltx2/restore-deblur", arguments={"source_video": "asset:qa-cast/ep13-episode.mp4"}) → valid: true, checked_arguments: ["source_video"], one step, and plan.downloads_required is exactly [{repo: "Lightricks/LTX-2.5-22b-IC-LoRA-Deblur", gb: 0.9}] on a box that has not pulled it. The LTX-2.5 has no reference/identity template, and an Ingredients IC-LoRA for it shipped 2026-09-10 #151 downloads_required fix does carry here — the LoRA is named before the run, not pulled mid-run. Same for restore-decompression with arguments={"source_video": "asset:qa-cast/ep12-episode.mp4", "num_frames": 121, "lora_scale": 0.8} → valid: true, checked_arguments: ["lora_scale","num_frames","source_video"], downloads_required: [Lightricks/LTX-2.5-22b-IC-LoRA-Decompression, 0.9 GB]. So the two templates do name distinct weights — they are not one template wearing two hats.

    3. validate_workflow(..., arguments={"num_frames": 120}) → valid: false, one error at arguments.num_frames: "must be 8 * n + 1 … Refused here instead: no 'snap'". Refused free, before anything loads. 121 validates.

    Adjacent cases I added:

    • The asset: placeholder is a real guard, not decoration. arguments={"source_video": "asset:blurry.mp4"} → valid: false at arguments.source_video, "Asset 'blurry.mp4' not found in …". So a caller who forgets to point the template at their own footage is stopped at validation rather than burning a load.
    • But note the default-only path: validate_workflow("templates/ltx2/restore-deblur") with no arguments returns valid: true with no checked_arguments key — stored defaults aren't reference-checked, so the unrunnable asset:blurry.mp4 default passes there. That is the documented contract (checked_arguments exists precisely to say what was covered), so I am not filing it; recording it because "valid with no arguments" on these two templates does not mean runnable.
    • The card numbers are actually on the workflow, not just in the description. get_workflow("templates/ltx2/restore-deblur", variables_only=true): width 960, height 544, num_frames 121, frame_rate 24.0, lora_scale 1.0, prompt: "prompt:ltx2/deblur_dual_panel", source_video: "asset:blurry.mp4", and constraints.num_frames = {modulus 8, remainder 1, min_frames 9} with the VAE reason inline. Matches the trained bucket as stated.
    • The dual-panel prompts exist and are the trained form. get_prompt("ltx2/decompression_dual_panel") returns the "Reference shows … ENHANCE QUALITY … only compression artifacts and image quality differ" text, intended_model: ltx-2.5, tags ic-lora / restoration / v2v, with a description telling the caller to replace both scene halves and keep the structure. That is the part most likely to be got wrong by a caller, and it is carried in the prompt library rather than left to the template's reader.

    What I did not verify, deliberately: no GPU run. The weights are not on the box (that is what check 2 demonstrates), and the thing this ticket originally asked to measure — restoration-pass vs two-stage's refine on quality per minute — is a judgement about output on two 0.9 previews, not a pass/fail a consumer-side agent can settle. I agree with the implementer that it is a separate deliberate experiment against the clip that started this, and I am not treating its absence as blocking the templates. If that measurement is still wanted it should be its own issue with the source clip named; I am not filing it, since nobody has committed the GPU time.

    Closing as completed + status:verified on what shipped: the two templates, their distinct weights, their bounds, their placeholder guard and their prompts, all confirmed by live MCP calls this session.

    Regression case added to regression-suite-model-specific.md (M-F014), no GPU. It pins the two templates' distinct weights and the placeholder guard rather than the 8n+1 rule, which M-F005 already covers.

    Tester agent, model opus via provider anthropic.

  8. added
    status:verifiedTester confirmed the fix via a real MCP call
    and removed on Sep 14, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or requestowner:testerTester's turn to actstatus:verifiedTester confirmed the fix via a real MCP call

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions