Skip to content

Commit 54898a3

Browse files
Merge pull request #402 from AI-Hypercomputer:ltx23
PiperOrigin-RevId: 914334549
2 parents afb1e74 + cb9ad39 commit 54898a3

16 files changed

Lines changed: 1671 additions & 276 deletions

src/maxdiffusion/common_types.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@
5252
WAN2_1 = "wan2.1"
5353
WAN2_2 = "wan2.2"
5454
LTX2_VIDEO = "ltx2_video"
55+
LTX2_3 = "ltx2.3"
5556

5657
WAN_MODEL = WAN2_1
5758

Lines changed: 161 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,161 @@
1+
#hardware
2+
hardware: 'tpu'
3+
skip_jax_distributed_system: False
4+
attention: 'flash'
5+
a2v_attention_kernel: 'flash'
6+
v2a_attention_kernel: 'dot_product'
7+
attention_sharding_uniform: True
8+
precision: 'bf16'
9+
scan_layers: True
10+
names_which_can_be_saved: []
11+
names_which_can_be_offloaded: []
12+
remat_policy: "NONE"
13+
14+
jax_cache_dir: ''
15+
weights_dtype: 'bfloat16'
16+
activations_dtype: 'bfloat16'
17+
18+
run_name: 'ltx2_inference'
19+
output_dir: ''
20+
config_path: ''
21+
save_config_to_gcs: False
22+
23+
#Checkpoints
24+
max_sequence_length: 1024
25+
sampler: "from_checkpoint"
26+
27+
# Generation parameters (aligned with Diffusers LTX-2.3 docs: use_cross_timestep, modality + audio CFG)
28+
global_batch_size_to_train_on: 1
29+
num_inference_steps: 40
30+
guidance_scale: 3.0
31+
guidance_rescale: 0.7
32+
audio_guidance_scale: 7.0
33+
audio_guidance_rescale: 0.7
34+
stg_scale: 1.0
35+
audio_stg_scale: 1.0
36+
modality_scale: 3.0
37+
audio_modality_scale: 3.0
38+
use_cross_timestep: true
39+
spatio_temporal_guidance_blocks: [28]
40+
fps: 24
41+
pipeline_type: multi-scale
42+
prompt: "A man in a brightly lit room talks on a vintage telephone. In a low, heavy voice, he says, 'I understand. I won't call again. Goodbye.' He hangs up the receiver and looks down with a sad expression. He holds the black rotary phone to his right ear with his right hand, his left hand holding a rocks glass with amber liquid. He wears a brown suit jacket over a white shirt, and a gold ring on his left ring finger. His short hair is neatly combed, and he has light skin with visible wrinkles around his eyes. The camera remains stationary, focused on his face and upper body. The room is brightly lit by a warm light source off-screen to the left, casting shadows on the wall behind him. The scene appears to be from a dramatic movie."
43+
negative_prompt: "shaky, glitchy, low quality, worst quality, deformed, distorted, disfigured, motion smear, motion artifacts, fused fingers, bad anatomy, weird hand, ugly, transition, static."
44+
height: 512
45+
width: 768
46+
decode_timestep: 0.05
47+
decode_noise_scale: 0.025
48+
noise_scale: 0.0
49+
num_frames: 121
50+
quantization: "int8"
51+
scan_diffusion_loop: True
52+
use_bwe: True
53+
#parallelism
54+
mesh_axes: ['data', 'fsdp', 'context', 'tensor']
55+
logical_axis_rules: [
56+
['batch', ['data', 'fsdp']],
57+
['activation_batch', ['data', 'fsdp']],
58+
['activation_self_attn_heads', ['context', 'tensor']],
59+
['activation_cross_attn_q_length', ['context', 'tensor']],
60+
['activation_length', 'context'],
61+
['activation_heads', 'tensor'],
62+
['mlp','tensor'],
63+
['embed', ['context', 'fsdp']],
64+
['heads', 'tensor'],
65+
['norm', 'tensor'],
66+
['conv_batch', ['data', 'context', 'fsdp']],
67+
['out_channels', 'tensor'],
68+
['conv_out', 'context'],
69+
]
70+
data_sharding: ['data', 'fsdp', 'context', 'tensor']
71+
72+
dcn_data_parallelism: 1 # recommended DCN axis to be auto-sharded
73+
dcn_fsdp_parallelism: -1
74+
75+
flash_block_sizes: {
76+
block_q: 2048,
77+
block_kv: 2048,
78+
block_kv_compute: 1024,
79+
block_q_dkv: 2048,
80+
block_kv_dkv: 2048,
81+
block_kv_dkv_compute: 2048,
82+
use_fused_bwd_kernel: True,
83+
}
84+
flash_min_seq_length: 4096
85+
dcn_context_parallelism: 1
86+
dcn_tensor_parallelism: 1
87+
ici_data_parallelism: 1
88+
ici_fsdp_parallelism: 1
89+
ici_context_parallelism: -1 # recommended ICI axis to be auto-sharded
90+
ici_tensor_parallelism: 1
91+
enable_profiler: False
92+
93+
# ML Diagnostics settings
94+
enable_ml_diagnostics: True
95+
profiler_gcs_path: ""
96+
enable_ondemand_xprof: True
97+
skip_first_n_steps_for_profiler: 0
98+
profiler_steps: 5
99+
100+
replicate_vae: False
101+
102+
allow_split_physical_axes: False
103+
learning_rate_schedule_steps: -1
104+
max_train_steps: 500
105+
pretrained_model_name_or_path: 'dg845/LTX-2.3-Diffusers'
106+
model_name: "ltx2.3"
107+
model_type: "T2V"
108+
unet_checkpoint: ''
109+
checkpoint_dir: ""
110+
dataset_name: ''
111+
train_split: 'train'
112+
dataset_type: 'tfrecord'
113+
cache_latents_text_encoder_outputs: True
114+
per_device_batch_size: 1.0
115+
compile_topology_num_slices: -1
116+
quantization_local_shard_count: -1
117+
use_qwix_quantization: False
118+
weight_quantization_calibration_method: "absmax"
119+
act_quantization_calibration_method: "absmax"
120+
bwd_quantization_calibration_method: "absmax"
121+
qwix_module_path: ".*"
122+
jit_initializers: True
123+
enable_single_replica_ckpt_restoring: False
124+
seed: 10
125+
audio_format: "s16"
126+
127+
# LoRA parameters
128+
enable_lora: False
129+
130+
# Distilled LoRA
131+
# lora_config: {
132+
# lora_model_name_or_path: ["Lightricks/LTX-2"],
133+
# weight_name: ["ltx-2-19b-distilled-lora-384.safetensors"],
134+
# adapter_name: ["distilled-lora-384"],
135+
# rank: [384]
136+
# }
137+
138+
# Standard LoRA
139+
lora_config: {
140+
lora_model_name_or_path: ["Lightricks/LTX-2-19b-LoRA-Camera-Control-Dolly-In"],
141+
weight_name: ["ltx-2-19b-lora-camera-control-dolly-in.safetensors"],
142+
adapter_name: ["camera-control-dolly-in"],
143+
rank: [32]
144+
}
145+
146+
147+
# LTX-2 Latent Upsampler
148+
run_latent_upsampler: False
149+
upsampler_model_path: "Lightricks/LTX-2.3"
150+
# Following upsampler files are supported:
151+
# ltx-2.3-spatial-upscaler-x2-1.0.safetensors
152+
# ltx-2.3-spatial-upscaler-x2-1.1.safetensors
153+
# ltx-2.3-spatial-upscaler-x1.5-1.0.safetensors
154+
# ltx-2.3-temporal-upscaler-x2-1.0.safetensors
155+
upsampler_filename: "ltx-2.3-spatial-upscaler-x2-1.0.safetensors"
156+
upsampler_spatial_patch_size: 1
157+
upsampler_temporal_patch_size: 1
158+
upsampler_adain_factor: 0.0
159+
upsampler_tone_map_compression_ratio: 0.0
160+
upsampler_rational_spatial_scale: 2.0
161+
upsampler_output_type: "pil"

src/maxdiffusion/configs/ltx2_video.yml

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,16 @@ sampler: "from_checkpoint"
3434
global_batch_size_to_train_on: 1
3535
num_inference_steps: 40
3636
guidance_scale: 3.0
37+
guidance_rescale: 0.0
38+
audio_guidance_scale: 0.0
39+
audio_guidance_rescale: 0.0
40+
stg_scale: 0.0
41+
audio_stg_scale: 0.0
42+
modality_scale: 1.0
43+
audio_modality_scale: 1.0
44+
use_cross_timestep: false
45+
spatio_temporal_guidance_blocks: []
46+
noise_scale: 1.0
3747
fps: 24
3848
pipeline_type: multi-scale
3949
prompt: "A man in a brightly lit room talks on a vintage telephone. In a low, heavy voice, he says, 'I understand. I won't call again. Goodbye.' He hangs up the receiver and looks down with a sad expression. He holds the black rotary phone to his right ear with his right hand, his left hand holding a rocks glass with amber liquid. He wears a brown suit jacket over a white shirt, and a gold ring on his left ring finger. His short hair is neatly combed, and he has light skin with visible wrinkles around his eyes. The camera remains stationary, focused on his face and upper body. The room is brightly lit by a warm light source off-screen to the left, casting shadows on the wall behind him. The scene appears to be from a dramatic movie."
@@ -87,13 +97,15 @@ enable_profiler: False
8797

8898
# ML Diagnostics settings
8999
enable_ml_diagnostics: True
90-
profiler_gcs_path: "gs://mehdy/profiler/ml_diagnostics"
100+
profiler_gcs_path: ""
91101
enable_ondemand_xprof: True
92102
skip_first_n_steps_for_profiler: 0
93103
profiler_steps: 5
94104

95105
replicate_vae: False
96106

107+
use_bwe: False
108+
97109
allow_split_physical_axes: False
98110
learning_rate_schedule_steps: -1
99111
max_train_steps: 500

src/maxdiffusion/generate_ltx2.py

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,11 +93,20 @@ def call_pipeline(config, pipeline, prompt, negative_prompt):
9393
num_frames=config.num_frames,
9494
num_inference_steps=config.num_inference_steps,
9595
guidance_scale=guidance_scale,
96+
guidance_rescale=getattr(config, "guidance_rescale", 0.0),
9697
generator=generator,
9798
frame_rate=getattr(config, "fps", 24.0),
9899
decode_timestep=getattr(config, "decode_timestep", 0.0),
99100
decode_noise_scale=getattr(config, "decode_noise_scale", None),
100101
max_sequence_length=getattr(config, "max_sequence_length", 1024),
102+
audio_guidance_scale=getattr(config, "audio_guidance_scale", None),
103+
audio_guidance_rescale=getattr(config, "audio_guidance_rescale", None),
104+
stg_scale=getattr(config, "stg_scale", 0.0),
105+
audio_stg_scale=getattr(config, "audio_stg_scale", None),
106+
modality_scale=getattr(config, "modality_scale", 1.0),
107+
audio_modality_scale=getattr(config, "audio_modality_scale", None),
108+
use_cross_timestep=getattr(config, "use_cross_timestep", None),
109+
noise_scale=getattr(config, "noise_scale", 1.0),
101110
dtype=jnp.bfloat16 if getattr(config, "activations_dtype", "bfloat16") == "bfloat16" else jnp.float32,
102111
output_type=getattr(config, "upsampler_output_type", "pil"),
103112
)
@@ -220,7 +229,9 @@ def run(config, pipeline=None, filename_prefix="", commit_hash=None):
220229

221230
saved_video_path = []
222231
audio_sample_rate = (
223-
getattr(pipeline.vocoder.config, "output_sampling_rate", 24000) if hasattr(pipeline, "vocoder") else 24000
232+
getattr(pipeline.vocoder.config, "output_sampling_rate", 24000)
233+
if getattr(pipeline, "vocoder", None) is not None
234+
else 24000
224235
)
225236
fps = getattr(config, "fps", 24)
226237

src/maxdiffusion/models/ltx2/attention_ltx2.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -353,6 +353,7 @@ def __init__(
353353
qkv_sharding_spec: Optional[tuple] = None,
354354
out_sharding_spec: Optional[tuple] = None,
355355
out_bias_sharding_spec: Optional[tuple] = None,
356+
gated_attn: bool = False,
356357
):
357358
self.heads = heads
358359
self.rope_type = rope_type
@@ -444,6 +445,17 @@ def __init__(
444445
else:
445446
self.dropout_layer = None
446447

448+
if gated_attn:
449+
self.to_gate_logits = nnx.Linear(
450+
query_dim,
451+
heads,
452+
use_bias=True,
453+
kernel_init=nnx.with_partitioning(nnx.initializers.lecun_normal(), ("embed", "heads")),
454+
bias_init=nnx.with_partitioning(nnx.initializers.zeros_init(), ("heads",)),
455+
rngs=rngs,
456+
dtype=dtype,
457+
)
458+
447459
self.attention_op = NNXAttentionOp(
448460
mesh=mesh,
449461
attention_kernel=attention_kernel,
@@ -464,6 +476,7 @@ def __call__(
464476
attention_mask: Optional[Array] = None,
465477
rotary_emb: Optional[Tuple[Array, Array]] = None,
466478
k_rotary_emb: Optional[Tuple[Array, Array]] = None,
479+
perturbation_mask: Optional[Array] = None,
467480
) -> Array:
468481
# Determine context (Self or Cross)
469482
context = encoder_hidden_states if encoder_hidden_states is not None else hidden_states
@@ -507,6 +520,19 @@ def __call__(
507520
# NNXAttentionOp expects flattened input [B, S, InnerDim] for flash kernel
508521
attn_output = self.attention_op.apply_attention(query=query, key=key, value=value, attention_mask=attention_mask)
509522

523+
if perturbation_mask is not None:
524+
# value is [B, S, InnerDim]
525+
# attn_output is [B, S, InnerDim]
526+
attn_output = value + perturbation_mask * (attn_output - value)
527+
528+
if getattr(self, "to_gate_logits", None) is not None:
529+
gate_logits = self.to_gate_logits(hidden_states)
530+
b, s, _ = attn_output.shape
531+
attn_output = attn_output.reshape(b, s, self.heads, self.dim_head)
532+
gates = 2.0 * jax.nn.sigmoid(gate_logits)
533+
attn_output = attn_output * jnp.expand_dims(gates, axis=-1)
534+
attn_output = attn_output.reshape(b, s, -1)
535+
510536
# 7. Output Projection
511537
hidden_states = self.to_out(attn_output)
512538

0 commit comments

Comments
 (0)