Instructions to use Lightricks/LTX-2.5-Diffusers with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- Diffusers
How to use Lightricks/LTX-2.5-Diffusers with Diffusers:
pip install -U diffusers transformers accelerate
import torch from diffusers import DiffusionPipeline # switch to "mps" for apple devices pipe = DiffusionPipeline.from_pretrained("Lightricks/LTX-2.5-Diffusers", dtype=torch.bfloat16, device_map="cuda") prompt = "Astronaut in a jungle, cold color palette, muted colors, detailed, 8k" image = pipe(prompt).images[0] - Notebooks
- Google Colab
- Kaggle
pip install -U diffusers transformers accelerate
import torch
from diffusers import DiffusionPipeline
# switch to "mps" for apple devices
pipe = DiffusionPipeline.from_pretrained("Lightricks/LTX-2.5-Diffusers", dtype=torch.bfloat16, device_map="cuda")
prompt = "Astronaut in a jungle, cold color palette, muted colors, detailed, 8k"
image = pipe(prompt).images[0]You need to agree to share your contact information to access this model
By clicking "Agree and Access" you acknowledge the Privacy Policy and consent to receive offers and updates including targeted and personalized advertisements. You can unsubscribe at any time.
Log in or Sign Up to review the conditions and access this model content.
Commercial and production use at no cost under the LTX-2.x Community License. Transfer of fine-tunes may require a paid license, in accordance with the LTX-2.x Community License.
Read the DocumentationPaid Commercial Use Agreement for LTX-2.x with full weights, engineering support, LoRAs, and flexible deployment options. To learn about all licensing options, talk to an expert.
Talk to a Commercial Licensing ExpertCommercial and production use at no cost under the LTX-2.x Community License. Transfer of fine-tunes may require a paid license, in accordance with the LTX-2.x Community License.
Read the DocumentationPaid Commercial Use Agreement for LTX-2.x with full weights, engineering support, LoRAs, and flexible deployment options. To learn about all licensing options, talk to an expert.
Talk to a Commercial Licensing ExpertDiffusers weights for LTX-2.5.
LTX-2.5 is an open world model with open weights, built for local execution and fine-tuning. Its established use is generating synchronized, high-fidelity video and audio from text, image, and video inputs; applicability to emerging domains such as robotics and physical AI is developing.
Full control and customization โ self-host on your own infrastructure. No per-generation billing, no per-seat lock-in, no forced API dependency. Revenue is measured across the whole entity, including subsidiaries and affiliates under common control. The full, binding terms live in LICENSE.
Layout
| Path | Component |
|---|---|
transformer/ |
Distilled DiT (default in model_index.json) |
transformer_full/ |
Full / SFT DiT |
vae/ |
Convolutional video VAE (encode + conv decode) |
diffusion_decoder/ |
Diffusion (DiT) video decoder, decoder-only |
latent_upsampler/ |
Spatial x2 latent upsampler, for the two-stage distilled recipe |
audio_vae/, vocoder/, connectors/, text_encoder/, tokenizer/, scheduler/, duration_head/ |
Shared |
Encoding always uses vae/, and LTX2Pipeline decodes with vae/ too. The diffusion decoder is a
diffusion model in its own right rather than a pipeline component, so it is driven by
LTX2VideoDiffusionDecodePipeline: run the pipeline with output_type="latent", then decode. Both
decoders consume the same latents.
scheduler/ is configured for the distilled transformer (use_dynamic_shifting: false,
shift_terminal: null) so that distilled sigma schedules are used exactly as given. See
Full / SFT transformer for the override the full DiT needs.
Install
LTX-2.5 support is not in a diffusers release yet, so install from main:
pip install git+https://github.com/huggingface/diffusers
Downloading only what you need
from_pretrained fetches just the components listed in model_index.json, so the distilled path never
pulls transformer_full/. If you snapshot the repo instead, exclude it explicitly โ 72 GB rather than
110 GB:
hf download Lightricks/LTX-2.5-Diffusers --exclude "transformer_full/*"
Quick start โ distilled, convolutional decode
Distilled inference is driven by an explicit sigma schedule, not a step count, and runs unguided โ
guidance_scale=1.0 plus STG and modality guidance zeroed, since the pipeline defaults are the SFT
values. Passing num_inference_steps instead would hand the model a generic linear
schedule and quietly cost quality.
import torch
from diffusers import LTX2Pipeline
from diffusers.pipelines.ltx2.utils import DEFAULT_NEGATIVE_PROMPT, DISTILLED_SIGMA_VALUES
from diffusers.utils import encode_video
MODEL_ID = "Lightricks/LTX-2.5-Diffusers"
pipe = LTX2Pipeline.from_pretrained(MODEL_ID, dtype=torch.bfloat16)
pipe.enable_model_cpu_offload()
video, audio = pipe(
prompt="A cinematic shot of a red fox walking through a snowy forest at dawn, "
"the camera tracking alongside, snow crunching underfoot.",
negative_prompt=DEFAULT_NEGATIVE_PROMPT,
width=960,
height=544,
num_frames=121,
frame_rate=24.0,
sigmas=DISTILLED_SIGMA_VALUES,
guidance_scale=1.0,
audio_guidance_scale=1.0,
stg_scale=0.0,
audio_stg_scale=0.0,
modality_scale=1.0,
audio_modality_scale=1.0,
generator=torch.Generator("cuda").manual_seed(42),
output_type="np",
return_dict=False,
)
encode_video(
video[0],
fps=24,
output_path="ltx25.mp4",
audio=audio[0].float().cpu(),
audio_sample_rate=pipe.vocoder.config.output_sampling_rate,
)
Video and audio are generated jointly. Read the audio rate off the vocoder rather than hardcoding it โ
this checkpoint ships LTX2VocoderWithBWE, whose output_sampling_rate is 48000.
Two-stage distilled generation
Better quality than the single-stage quick start: half resolution, x2 latent upsample, then a 3-sigma tail at full resolution. One generator across both calls, so stage 2 continues the noise stream.
import torch
from diffusers import LTX2LatentUpsamplePipeline, LTX2Pipeline
from diffusers.pipelines.ltx2.latent_upsampler import LTX2LatentUpsamplerModel
from diffusers.pipelines.ltx2.utils import (
DEFAULT_NEGATIVE_PROMPT,
DISTILLED_SIGMA_VALUES,
STAGE_2_DISTILLED_SIGMA_VALUES,
)
from diffusers.utils import encode_video
MODEL_ID = "Lightricks/LTX-2.5-Diffusers"
# Stage 1 resolution; stage 2 runs at 2x this.
HEIGHT, WIDTH, NUM_FRAMES, FRAME_RATE = 544, 960, 121, 24.0
pipe = LTX2Pipeline.from_pretrained(MODEL_ID, dtype=torch.bfloat16)
pipe.enable_model_cpu_offload()
pipe.vae.enable_tiling() # stage 2 decodes at 2x
latent_upsampler = LTX2LatentUpsamplerModel.from_pretrained(
MODEL_ID, subfolder="latent_upsampler", dtype=torch.bfloat16
).to("cuda")
upsample_pipe = LTX2LatentUpsamplePipeline(vae=pipe.vae, latent_upsampler=latent_upsampler)
generator = torch.Generator("cuda").manual_seed(42)
shared = dict(
prompt="A cinematic shot of a red fox walking through a snowy forest at dawn, "
"the camera tracking alongside, snow crunching underfoot.",
negative_prompt=DEFAULT_NEGATIVE_PROMPT,
frame_rate=FRAME_RATE,
guidance_scale=1.0,
audio_guidance_scale=1.0,
stg_scale=0.0,
audio_stg_scale=0.0,
modality_scale=1.0,
audio_modality_scale=1.0,
generator=generator,
return_dict=False,
)
stage_1_latents, audio_latents = pipe(
height=HEIGHT, width=WIDTH, num_frames=NUM_FRAMES,
sigmas=DISTILLED_SIGMA_VALUES, output_type="latent", **shared,
)
upsampled_latents = upsample_pipe(
latents=stage_1_latents, output_type="latent", return_dict=False
)[0]
# Stage 2 takes its size from the upsampled latents, so pass no height/width.
video, audio = pipe(
num_frames=NUM_FRAMES,
sigmas=STAGE_2_DISTILLED_SIGMA_VALUES,
latents=upsampled_latents,
audio_latents=audio_latents,
noise_scale=STAGE_2_DISTILLED_SIGMA_VALUES[0],
output_type="np",
**shared,
)
encode_video(
video[0],
fps=int(FRAME_RATE),
output_path="ltx25_two_stage.mp4",
audio=audio[0].float().cpu(),
audio_sample_rate=pipe.vocoder.config.output_sampling_rate,
)
To finish this with the diffusion decoder instead, ask stage 2 for output_type="latent" and follow the
next section โ including its by-hand audio decode, since latents skip the vocoder.
Decode with the diffusion decoder
Ask the pipeline for latents, then decode them. Two things differ from the snippet above:
output_type="latent" skips the vocoder, so the audio comes back as latents and has to be finished by
hand; and the decoder needs pip install kernels, which fetches the
NATTEN kernel from the Hub (a local natten install is not used).
import torch
from diffusers import LTX2Pipeline, LTX2VideoDiffusionDecoderModel
from diffusers.models.autoencoders.ltx2_diffusion_decoder import LTX2VideoVaeNeighborhoodNattenProcessor
from diffusers.pipelines.ltx2.pipeline_ltx2_diffusion_decode import LTX2VideoDiffusionDecodePipeline
from diffusers.pipelines.ltx2.utils import DEFAULT_NEGATIVE_PROMPT, DISTILLED_SIGMA_VALUES
from diffusers.utils import encode_video
MODEL_ID = "Lightricks/LTX-2.5-Diffusers"
pipe = LTX2Pipeline.from_pretrained(MODEL_ID, dtype=torch.bfloat16)
pipe.enable_model_cpu_offload()
generator = torch.Generator("cuda").manual_seed(42)
latents, audio_latents = pipe(
prompt="A cinematic shot of a red fox walking through a snowy forest at dawn, "
"the camera tracking alongside, snow crunching underfoot.",
negative_prompt=DEFAULT_NEGATIVE_PROMPT,
width=960, height=544, num_frames=121, frame_rate=24.0,
sigmas=DISTILLED_SIGMA_VALUES,
guidance_scale=1.0,
audio_guidance_scale=1.0,
stg_scale=0.0,
audio_stg_scale=0.0,
modality_scale=1.0,
audio_modality_scale=1.0,
generator=generator,
output_type="latent",
return_dict=False,
)
# `output_type="latent"` skips the vocoder, so finish the audio here. These latents are already
# denormalized, which is what `audio_vae.decode` expects.
mel = pipe.audio_vae.decode(audio_latents.to(pipe.audio_vae.dtype), return_dict=False)[0]
audio = pipe.vocoder(mel)
decoder = LTX2VideoDiffusionDecoderModel.from_pretrained(
MODEL_ID, subfolder="diffusion_decoder", dtype=torch.bfloat16
).to("cuda")
# The default FlexAttention processor is uncompiled, so it materialises the full score matrix and needs
# tens of GB at video resolutions. NATTEN's kernels are what the original implementation uses.
# `set_attention_backend` is not an alternative: no backend other than `flex` accepts the BlockMask.
# Every attention module in the decoder is the same neighborhood attention, so one call swaps them all.
decoder.set_attn_processor(LTX2VideoVaeNeighborhoodNattenProcessor())
# Decode in overlapping tiles so peak memory is bounded by the tile size, not the video size.
decoder.enable_tiling()
decode_pipe = LTX2VideoDiffusionDecodePipeline(diffusion_decoder=decoder, scheduler=pipe.scheduler)
# denormalize=False: `output_type="latent"` already applied the latent statistics, so applying them
# again would rescale every channel by its std a second time. The decoder draws its own noise, so pass
# a generator for reproducible decoding.
video = decode_pipe(
latents, generator=generator, output_type="np", denormalize=False, return_dict=False
)[0]
encode_video(
video[0],
fps=24,
output_path="ltx25_diffusion_decode.mp4",
audio=audio[0].float().cpu(),
audio_sample_rate=pipe.vocoder.config.output_sampling_rate,
)
enable_tiling() bounds peak memory by the tile size rather than by the size of the video. The cheap early
upsampling stages still see the full latent; only the last upsampling stage and the diffusion stage, which
dominate decode memory, run per tile, so tiling changes the output only near tile borders. Each tile is
denoised separately, so a tiled decode does not reproduce an untiled one exactly. The default tile and
overlap sizes match the reference implementation's and can be overridden with the tile_sample_min_* /
tile_sample_stride_* arguments.
Full / SFT transformer
transformer_full/ is not in model_index.json, so load it explicitly, and re-enable the shifting the
distilled scheduler/ turns off. The pipeline's guidance defaults are already the SFT values, so the only
other change is dropping the distilled overrides. As a diff against the quick start:
import torch
-from diffusers import LTX2Pipeline
-from diffusers.pipelines.ltx2.utils import DEFAULT_NEGATIVE_PROMPT, DISTILLED_SIGMA_VALUES
+from diffusers import FlowMatchEulerDiscreteScheduler, LTX2Pipeline, LTX2VideoTransformer3DModel
+from diffusers.pipelines.ltx2.utils import DEFAULT_NEGATIVE_PROMPT
from diffusers.utils import encode_video
MODEL_ID = "Lightricks/LTX-2.5-Diffusers"
-pipe = LTX2Pipeline.from_pretrained(MODEL_ID, dtype=torch.bfloat16)
+pipe = LTX2Pipeline.from_pretrained(
+ MODEL_ID,
+ transformer=LTX2VideoTransformer3DModel.from_pretrained(
+ MODEL_ID, subfolder="transformer_full", dtype=torch.bfloat16
+ ),
+ dtype=torch.bfloat16,
+)
pipe.enable_model_cpu_offload()
+pipe.scheduler = FlowMatchEulerDiscreteScheduler.from_config(
+ pipe.scheduler.config, use_dynamic_shifting=True, shift_terminal=0.1
+)
video, audio = pipe(
prompt="A cinematic shot of a red fox walking through a snowy forest at dawn, "
"the camera tracking alongside, snow crunching underfoot.",
negative_prompt=DEFAULT_NEGATIVE_PROMPT,
width=960,
height=544,
num_frames=121,
frame_rate=24.0,
- sigmas=DISTILLED_SIGMA_VALUES,
- guidance_scale=1.0,
- audio_guidance_scale=1.0,
- stg_scale=0.0,
- audio_stg_scale=0.0,
- modality_scale=1.0,
- audio_modality_scale=1.0,
generator=torch.Generator("cuda").manual_seed(42),
output_type="np",
return_dict=False,
)
Passing transformer= also keeps from_pretrained from fetching the distilled folder.
Prompting
The model was trained on long, single-paragraph audio-visual captions and degrades on short prompts.
Describe the shot, the motion, the light and the sound in one paragraph, as the examples above do.
Prompt enhancement for 2.5 uses a separate Gemma 4 checkpoint (e.g. google/gemma-4-E2B-it), not this
repo's fine-tuned text encoder.
Notes
- Distilled (
transformer/) is for few-step inference with an explicitsigmas=schedule and all guidance disabled; the full DiT (transformer_full/) uses step counts and real guidance. - The diffusion decoder denoises rather than decoding deterministically, so decoding is only
reproducible with a
generator. processorandprompt_enhancerappear inmodel_index.jsonbut are not shipped here; they load asNone.
- Downloads last month
- -
# Gated model: Login with a HF token with gated access permission hf auth login