From 029216029f4d64254cd0e562c25ebb045ca5b56d Mon Sep 17 00:00:00 2001 From: Shao Duan <46639847+shaoxiongduan@users.noreply.github.com> Date: Thu, 22 Jan 2026 06:11:39 +0800 Subject: [PATCH] Added LTX-2 Distilled T2V Generation (#1016) Co-authored-by: Will Lin --- examples/inference/basic/basic_ltx2.py | 34 + fastvideo/configs/models/__init__.py | 13 +- fastvideo/configs/models/audio/__init__.py | 13 + .../configs/models/audio/ltx2_audio_vae.py | 31 + fastvideo/configs/models/dits/__init__.py | 3 +- fastvideo/configs/models/dits/ltx2.py | 84 + fastvideo/configs/models/encoders/__init__.py | 3 +- fastvideo/configs/models/encoders/gemma.py | 48 + fastvideo/configs/models/vaes/__init__.py | 2 + fastvideo/configs/models/vaes/ltx2vae.py | 45 + fastvideo/configs/pipelines/__init__.py | 4 +- fastvideo/configs/pipelines/ltx2.py | 50 + fastvideo/configs/pipelines/registry.py | 7 + fastvideo/configs/sample/ltx2.py | 20 + fastvideo/configs/sample/registry.py | 53 +- fastvideo/entrypoints/video_generator.py | 100 + fastvideo/fastvideo_args.py | 82 + fastvideo/models/audio/__init__.py | 9 + fastvideo/models/audio/ltx2_audio_vae.py | 1327 ++++++++++++ fastvideo/models/dits/ltx2.py | 1800 ++++++++++++++++ fastvideo/models/encoders/gemma.py | 563 +++++ fastvideo/models/loader/component_loader.py | 197 +- fastvideo/models/registry.py | 12 +- fastvideo/models/vaes/ltx2vae.py | 1804 +++++++++++++++++ fastvideo/pipelines/basic/ltx2/__init__.py | 0 .../pipelines/basic/ltx2/ltx2_pipeline.py | 150 ++ fastvideo/pipelines/pipeline_registry.py | 1 + fastvideo/pipelines/stages/__init__.py | 7 + .../pipelines/stages/ltx2_audio_decoding.py | 67 + fastvideo/pipelines/stages/ltx2_denoising.py | 308 +++ .../stages/ltx2_latent_preparation.py | 189 ++ fastvideo/pipelines/stages/text_encoding.py | 18 +- fastvideo/tests/modal/pr_test.py | 34 +- ...sting with the energetic background of.mp4 | Bin 0 -> 278241 bytes ...sting with the energetic background of.mp4 | Bin 0 -> 278898 bytes .../tests/ssim/test_inference_similarity.py | 49 +- fastvideo/worker/multiproc_executor.py | 9 +- pyproject.toml | 1 + .../convert_ltx2_weights.py | 444 ++++ tests/README.md | 7 + tests/__init__.py | 0 tests/local_tests/README.md | 7 + tests/local_tests/__init__.py | 0 tests/local_tests/encoders/__init__.py | 0 .../encoders/test_ltx2_gemma_encoder.py | 126 ++ .../encoders/test_ltx2_gemma_parity.py | 378 ++++ tests/local_tests/pipelines/__init__.py | 0 .../pipelines/test_ltx2_pipeline_smoke.py | 296 +++ tests/local_tests/transformers/__init__.py | 0 tests/local_tests/transformers/test_ltx2.py | 343 ++++ .../transformers/test_ltx2_audio.py | 280 +++ tests/local_tests/vaes/__init__.py | 0 tests/local_tests/vaes/test_ltx2_audio_vae.py | 272 +++ tests/local_tests/vaes/test_ltx2_vae.py | 190 ++ .../vaes/test_ltx2_vae_official.py | 132 ++ 55 files changed, 9547 insertions(+), 65 deletions(-) create mode 100644 examples/inference/basic/basic_ltx2.py create mode 100644 fastvideo/configs/models/audio/__init__.py create mode 100644 fastvideo/configs/models/audio/ltx2_audio_vae.py create mode 100644 fastvideo/configs/models/dits/ltx2.py create mode 100644 fastvideo/configs/models/encoders/gemma.py create mode 100644 fastvideo/configs/models/vaes/ltx2vae.py create mode 100644 fastvideo/configs/pipelines/ltx2.py create mode 100644 fastvideo/configs/sample/ltx2.py create mode 100644 fastvideo/models/audio/__init__.py create mode 100644 fastvideo/models/audio/ltx2_audio_vae.py create mode 100644 fastvideo/models/dits/ltx2.py create mode 100644 fastvideo/models/encoders/gemma.py create mode 100644 fastvideo/models/vaes/ltx2vae.py create mode 100644 fastvideo/pipelines/basic/ltx2/__init__.py create mode 100644 fastvideo/pipelines/basic/ltx2/ltx2_pipeline.py create mode 100644 fastvideo/pipelines/stages/ltx2_audio_decoding.py create mode 100644 fastvideo/pipelines/stages/ltx2_denoising.py create mode 100644 fastvideo/pipelines/stages/ltx2_latent_preparation.py create mode 100644 fastvideo/tests/ssim/L40S_reference_videos/ltx2_diffusers/FLASH_ATTN/Will Smith casually eats noodles, his relaxed demeanor contrasting with the energetic background of.mp4 create mode 100644 fastvideo/tests/ssim/L40S_reference_videos/ltx2_diffusers/TORCH_SDPA/Will Smith casually eats noodles, his relaxed demeanor contrasting with the energetic background of.mp4 create mode 100644 scripts/checkpoint_conversion/convert_ltx2_weights.py create mode 100644 tests/README.md create mode 100644 tests/__init__.py create mode 100644 tests/local_tests/README.md create mode 100644 tests/local_tests/__init__.py create mode 100644 tests/local_tests/encoders/__init__.py create mode 100644 tests/local_tests/encoders/test_ltx2_gemma_encoder.py create mode 100644 tests/local_tests/encoders/test_ltx2_gemma_parity.py create mode 100644 tests/local_tests/pipelines/__init__.py create mode 100644 tests/local_tests/pipelines/test_ltx2_pipeline_smoke.py create mode 100644 tests/local_tests/transformers/__init__.py create mode 100644 tests/local_tests/transformers/test_ltx2.py create mode 100644 tests/local_tests/transformers/test_ltx2_audio.py create mode 100644 tests/local_tests/vaes/__init__.py create mode 100644 tests/local_tests/vaes/test_ltx2_audio_vae.py create mode 100644 tests/local_tests/vaes/test_ltx2_vae.py create mode 100644 tests/local_tests/vaes/test_ltx2_vae_official.py diff --git a/examples/inference/basic/basic_ltx2.py b/examples/inference/basic/basic_ltx2.py new file mode 100644 index 000000000..d8acd56bc --- /dev/null +++ b/examples/inference/basic/basic_ltx2.py @@ -0,0 +1,34 @@ +from fastvideo import VideoGenerator + +PROMPT = ( + "A warm sunny backyard. The camera starts in a tight cinematic close-up " + "of a woman and a man in their 30s, facing each other with serious " + "expressions. The woman, emotional and dramatic, says softly, \"That's " + "it... Dad's lost it. And we've lost Dad.\" The man exhales, slightly " + "annoyed: \"Stop being so dramatic, Jess.\" A beat. He glances aside, " + "then mutters defensively, \"He's just having fun.\" The camera slowly " + "pans right, revealing the grandfather in the garden wearing enormous " + "butterfly wings, waving his arms in the air like he's trying to take " + "off. He shouts, \"Wheeeew!\" as he flaps his wings with full commitment. " + "The woman covers her face, on the verge of tears. The tone is deadpan, " + "absurd, and quietly tragic." +) + + +def main() -> None: + generator = VideoGenerator.from_pretrained( + "FastVideo/LTX2-Distilled-Diffusers", + num_gpus=1, + ) + + output_path = "outputs_video/ltx2_basic/output_ltx2_distilled_t2v.mp4" + generator.generate_video( + prompt=PROMPT, + output_path=output_path, + save_video=True, + ) + generator.shutdown() + + +if __name__ == "__main__": + main() diff --git a/fastvideo/configs/models/__init__.py b/fastvideo/configs/models/__init__.py index 286c6b9dd..aa05ba62e 100644 --- a/fastvideo/configs/models/__init__.py +++ b/fastvideo/configs/models/__init__.py @@ -2,5 +2,16 @@ from fastvideo.configs.models.base import ModelConfig from fastvideo.configs.models.dits.base import DiTConfig from fastvideo.configs.models.encoders.base import EncoderConfig from fastvideo.configs.models.vaes.base import VAEConfig +from fastvideo.configs.models.audio import (LTX2AudioDecoderConfig, + LTX2AudioEncoderConfig, + LTX2VocoderConfig) -__all__ = ["ModelConfig", "VAEConfig", "DiTConfig", "EncoderConfig"] +__all__ = [ + "ModelConfig", + "VAEConfig", + "DiTConfig", + "EncoderConfig", + "LTX2AudioEncoderConfig", + "LTX2AudioDecoderConfig", + "LTX2VocoderConfig", +] diff --git a/fastvideo/configs/models/audio/__init__.py b/fastvideo/configs/models/audio/__init__.py new file mode 100644 index 000000000..ad1035536 --- /dev/null +++ b/fastvideo/configs/models/audio/__init__.py @@ -0,0 +1,13 @@ +# SPDX-License-Identifier: Apache-2.0 + +from fastvideo.configs.models.audio.ltx2_audio_vae import ( + LTX2AudioDecoderConfig, + LTX2AudioEncoderConfig, + LTX2VocoderConfig, +) + +__all__ = [ + "LTX2AudioEncoderConfig", + "LTX2AudioDecoderConfig", + "LTX2VocoderConfig", +] diff --git a/fastvideo/configs/models/audio/ltx2_audio_vae.py b/fastvideo/configs/models/audio/ltx2_audio_vae.py new file mode 100644 index 000000000..829f65a07 --- /dev/null +++ b/fastvideo/configs/models/audio/ltx2_audio_vae.py @@ -0,0 +1,31 @@ +# SPDX-License-Identifier: Apache-2.0 +""" +LTX-2 audio VAE and vocoder configuration. +""" + +from dataclasses import dataclass, field + +from fastvideo.configs.models.base import ArchConfig, ModelConfig + + +@dataclass +class LTX2AudioArchConfig(ArchConfig): + architectures: list[str] = field(default_factory=list) + + +@dataclass +class LTX2AudioEncoderConfig(ModelConfig): + arch_config: ArchConfig = field(default_factory=lambda: LTX2AudioArchConfig( + architectures=["LTX2AudioEncoder"])) + + +@dataclass +class LTX2AudioDecoderConfig(ModelConfig): + arch_config: ArchConfig = field(default_factory=lambda: LTX2AudioArchConfig( + architectures=["LTX2AudioDecoder"])) + + +@dataclass +class LTX2VocoderConfig(ModelConfig): + arch_config: ArchConfig = field(default_factory=lambda: LTX2AudioArchConfig( + architectures=["LTX2Vocoder"])) diff --git a/fastvideo/configs/models/dits/__init__.py b/fastvideo/configs/models/dits/__init__.py index 958e9bc71..c4b21a714 100644 --- a/fastvideo/configs/models/dits/__init__.py +++ b/fastvideo/configs/models/dits/__init__.py @@ -3,11 +3,12 @@ from fastvideo.configs.models.dits.cosmos2_5 import Cosmos25VideoConfig from fastvideo.configs.models.dits.hunyuanvideo import HunyuanVideoConfig from fastvideo.configs.models.dits.hunyuanvideo15 import HunyuanVideo15Config from fastvideo.configs.models.dits.longcat import LongCatVideoConfig +from fastvideo.configs.models.dits.ltx2 import LTX2VideoConfig from fastvideo.configs.models.dits.stepvideo import StepVideoConfig from fastvideo.configs.models.dits.wanvideo import WanVideoConfig __all__ = [ "HunyuanVideoConfig", "HunyuanVideo15Config", "WanVideoConfig", "StepVideoConfig", "CosmosVideoConfig", "Cosmos25VideoConfig", - "LongCatVideoConfig" + "LongCatVideoConfig", "LTX2VideoConfig" ] diff --git a/fastvideo/configs/models/dits/ltx2.py b/fastvideo/configs/models/dits/ltx2.py new file mode 100644 index 000000000..2c280a38a --- /dev/null +++ b/fastvideo/configs/models/dits/ltx2.py @@ -0,0 +1,84 @@ +# SPDX-License-Identifier: Apache-2.0 +""" +LTX-2 Transformer configuration for native FastVideo integration. +""" + +from dataclasses import dataclass, field + +from fastvideo.configs.models.dits.base import DiTArchConfig, DiTConfig + + +def is_ltx2_blocks(name: str, _module) -> bool: + """FSDP shard condition for LTX-2 transformer blocks.""" + return "transformer_blocks" in name + + +@dataclass +class LTX2VideoArchConfig(DiTArchConfig): + """Architecture configuration for LTX-2 video transformer.""" + + _fsdp_shard_conditions: list = field( + default_factory=lambda: [is_ltx2_blocks]) + _compile_conditions: list = field(default_factory=lambda: [is_ltx2_blocks]) + + # Parameter name mapping for weight conversion (hf/comfy -> FastVideo) + param_names_mapping: dict = field( + default_factory=lambda: { + r"^model\.diffusion_model\.(.*)$": r"model.\1", + r"^diffusion_model\.(.*)$": r"model.\1", + r"^model\.(.*)$": r"model.\1", + r"^(.*)$": r"model.\1", + }) + + reverse_param_names_mapping: dict = field(default_factory=lambda: {}) + lora_param_names_mapping: dict = field(default_factory=lambda: {}) + + # Core transformer settings (defaults from LTX-2 metadata) + num_attention_heads: int = 32 + attention_head_dim: int = 128 + num_layers: int = 48 + cross_attention_dim: int = 4096 + caption_channels: int = 3840 + norm_eps: float = 1e-6 + attention_type: str = "default" + rope_type: str = "split" + double_precision_rope: bool = True + + positional_embedding_theta: float = 10000.0 + positional_embedding_max_pos: list[int] = field( + default_factory=lambda: [20, 2048, 2048]) + timestep_scale_multiplier: int = 1000 + use_middle_indices_grid: bool = True + + # Patchification (video-only path) + patch_size: tuple[int, int, int] = (1, 1, 1) + num_channels_latents: int = 128 + in_channels: int | None = None + out_channels: int | None = None + + # Audio defaults (reserved for joint AV ports) + audio_num_attention_heads: int = 32 + audio_attention_head_dim: int = 64 + audio_in_channels: int = 128 + audio_out_channels: int = 128 + audio_cross_attention_dim: int = 2048 + audio_positional_embedding_max_pos: list[int] = field( + default_factory=lambda: [20]) + av_ca_timestep_scale_multiplier: int = 1 + + def __post_init__(self): + super().__post_init__() + patch_volume = self.patch_size[0] * self.patch_size[ + 1] * self.patch_size[2] + if self.in_channels is None: + self.in_channels = self.num_channels_latents * patch_volume + if self.out_channels is None: + self.out_channels = self.in_channels + + +@dataclass +class LTX2VideoConfig(DiTConfig): + """Main configuration for LTX-2 transformer.""" + + arch_config: DiTArchConfig = field(default_factory=LTX2VideoArchConfig) + prefix: str = "ltx2" diff --git a/fastvideo/configs/models/encoders/__init__.py b/fastvideo/configs/models/encoders/__init__.py index f943114e8..778b15237 100644 --- a/fastvideo/configs/models/encoders/__init__.py +++ b/fastvideo/configs/models/encoders/__init__.py @@ -8,10 +8,11 @@ from fastvideo.configs.models.encoders.llama import LlamaConfig from fastvideo.configs.models.encoders.t5 import T5Config, T5LargeConfig from fastvideo.configs.models.encoders.qwen2_5 import Qwen2_5_VLConfig from fastvideo.configs.models.encoders.reason1 import Reason1ArchConfig, Reason1Config +from fastvideo.configs.models.encoders.gemma import LTX2GemmaConfig __all__ = [ "EncoderConfig", "TextEncoderConfig", "ImageEncoderConfig", "BaseEncoderOutput", "CLIPTextConfig", "CLIPVisionConfig", "WAN2_1ControlCLIPVisionConfig", "LlamaConfig", "T5Config", "T5LargeConfig", - "Qwen2_5_VLConfig", "Reason1ArchConfig", "Reason1Config" + "Qwen2_5_VLConfig", "Reason1ArchConfig", "Reason1Config", "LTX2GemmaConfig" ] diff --git a/fastvideo/configs/models/encoders/gemma.py b/fastvideo/configs/models/encoders/gemma.py new file mode 100644 index 000000000..73c51dd03 --- /dev/null +++ b/fastvideo/configs/models/encoders/gemma.py @@ -0,0 +1,48 @@ +# SPDX-License-Identifier: Apache-2.0 +from dataclasses import dataclass, field + +from fastvideo.configs.models.encoders.base import ( + TextEncoderArchConfig, + TextEncoderConfig, +) + + +@dataclass +class LTX2GemmaArchConfig(TextEncoderArchConfig): + architectures: list[str] = field( + default_factory=lambda: ["LTX2GemmaTextEncoderModel"]) + hidden_size: int = 3840 + num_hidden_layers: int = 48 + num_attention_heads: int = 30 + text_len: int = 1024 + pad_token_id: int = 0 + eos_token_id: int = 2 + + gemma_model_path: str = "" + gemma_dtype: str = "bfloat16" + padding_side: str = "left" + + feature_extractor_in_features: int = 3840 * 49 + feature_extractor_out_features: int = 3840 + + connector_num_attention_heads: int = 30 + connector_attention_head_dim: int = 128 + connector_num_layers: int = 2 + connector_positional_embedding_theta: float = 10000.0 + connector_positional_embedding_max_pos: list[int] = field( + default_factory=lambda: [4096]) + connector_rope_type: str = "split" + connector_double_precision_rope: bool = False + connector_num_learnable_registers: int | None = 128 + + def __post_init__(self) -> None: + super().__post_init__() + self.tokenizer_kwargs["padding"] = "max_length" + + +@dataclass +class LTX2GemmaConfig(TextEncoderConfig): + arch_config: TextEncoderArchConfig = field( + default_factory=LTX2GemmaArchConfig) + + prefix: str = "ltx2_gemma" diff --git a/fastvideo/configs/models/vaes/__init__.py b/fastvideo/configs/models/vaes/__init__.py index ad1b2f206..2e6cc023f 100644 --- a/fastvideo/configs/models/vaes/__init__.py +++ b/fastvideo/configs/models/vaes/__init__.py @@ -2,6 +2,7 @@ from fastvideo.configs.models.vaes.cosmosvae import CosmosVAEConfig from fastvideo.configs.models.vaes.cosmos2_5vae import Cosmos25VAEConfig from fastvideo.configs.models.vaes.hunyuanvae import HunyuanVAEConfig from fastvideo.configs.models.vaes.hunyuan15vae import Hunyuan15VAEConfig +from fastvideo.configs.models.vaes.ltx2vae import LTX2VAEConfig from fastvideo.configs.models.vaes.stepvideovae import StepVideoVAEConfig from fastvideo.configs.models.vaes.wanvae import WanVAEConfig @@ -12,4 +13,5 @@ __all__ = [ "CosmosVAEConfig", "Cosmos25VAEConfig", "Hunyuan15VAEConfig", + "LTX2VAEConfig", ] diff --git a/fastvideo/configs/models/vaes/ltx2vae.py b/fastvideo/configs/models/vaes/ltx2vae.py new file mode 100644 index 000000000..d659b9d2a --- /dev/null +++ b/fastvideo/configs/models/vaes/ltx2vae.py @@ -0,0 +1,45 @@ +# SPDX-License-Identifier: Apache-2.0 +""" +LTX-2 VAE configuration. +""" + +from dataclasses import dataclass, field + +from fastvideo.configs.models.vaes.base import VAEArchConfig, VAEConfig + + +@dataclass +class LTX2VAEArchConfig(VAEArchConfig): + # Mirrors LTX-2 safetensors metadata config under "vae" + _class_name: str = "CausalVideoAutoencoder" + dims: int = 3 + in_channels: int = 3 + out_channels: int = 3 + latent_channels: int = 128 + encoder_blocks: list = field(default_factory=list) + decoder_blocks: list = field(default_factory=list) + patch_size: int = 4 + norm_layer: str = "pixel_norm" + latent_log_var: str = "uniform" + encoder_spatial_padding_mode: str = "zeros" + decoder_spatial_padding_mode: str = "reflect" + causal_decoder: bool = False + timestep_conditioning: bool = True + use_quant_conv: bool = False + scaling_factor: float = 1.0 + normalize_latent_channels: bool = False + + # Match FastVideo naming for compression ratios (LTX-2 default) + temporal_compression_ratio: int = 8 + spatial_compression_ratio: int = 32 + + +@dataclass +class LTX2VAEConfig(VAEConfig): + arch_config: VAEArchConfig = field(default_factory=LTX2VAEArchConfig) + + # LTX-2 tiling defaults (match ltx_core.video_vae.TilingConfig.default()). + ltx2_spatial_tile_size_in_pixels: int = 512 + ltx2_spatial_tile_overlap_in_pixels: int = 64 + ltx2_temporal_tile_size_in_frames: int = 64 + ltx2_temporal_tile_overlap_in_frames: int = 24 diff --git a/fastvideo/configs/pipelines/__init__.py b/fastvideo/configs/pipelines/__init__.py index 8120ed53e..296ffa8a6 100644 --- a/fastvideo/configs/pipelines/__init__.py +++ b/fastvideo/configs/pipelines/__init__.py @@ -4,6 +4,7 @@ from fastvideo.configs.pipelines.cosmos import CosmosConfig from fastvideo.configs.pipelines.cosmos2_5 import Cosmos25Config from fastvideo.configs.pipelines.hunyuan import FastHunyuanConfig, HunyuanConfig from fastvideo.configs.pipelines.hunyuan15 import Hunyuan15T2V480PConfig, Hunyuan15T2V720PConfig +from fastvideo.configs.pipelines.ltx2 import LTX2T2VConfig from fastvideo.configs.pipelines.registry import ( get_pipeline_config_cls_from_name) from fastvideo.configs.pipelines.stepvideo import StepVideoT2VConfig @@ -16,5 +17,6 @@ __all__ = [ "Hunyuan15T2V480PConfig", "Hunyuan15T2V720PConfig", "SlidingTileAttnConfig", "WanT2V480PConfig", "WanI2V480PConfig", "WanT2V720PConfig", "WanI2V720PConfig", "StepVideoT2VConfig", "SelfForcingWanT2V480PConfig", - "CosmosConfig", "Cosmos25Config", "get_pipeline_config_cls_from_name" + "CosmosConfig", "Cosmos25Config", "LTX2T2VConfig", + "get_pipeline_config_cls_from_name" ] diff --git a/fastvideo/configs/pipelines/ltx2.py b/fastvideo/configs/pipelines/ltx2.py new file mode 100644 index 000000000..e08952882 --- /dev/null +++ b/fastvideo/configs/pipelines/ltx2.py @@ -0,0 +1,50 @@ +# SPDX-License-Identifier: Apache-2.0 +from collections.abc import Callable +from dataclasses import dataclass, field + +import torch + +from fastvideo.configs.models import (DiTConfig, EncoderConfig, ModelConfig, + LTX2AudioDecoderConfig, LTX2VocoderConfig, + VAEConfig) +from fastvideo.configs.models.dits import LTX2VideoConfig +from fastvideo.configs.models.encoders import BaseEncoderOutput, LTX2GemmaConfig +from fastvideo.configs.models.vaes import LTX2VAEConfig +from fastvideo.configs.pipelines.base import PipelineConfig, preprocess_text + + +def ltx2_postprocess_text(outputs: BaseEncoderOutput) -> torch.Tensor: + return outputs.last_hidden_state + + +@dataclass +class LTX2T2VConfig(PipelineConfig): + """Configuration for LTX-2 T2V pipeline.""" + + dit_config: DiTConfig = field(default_factory=LTX2VideoConfig) + vae_config: VAEConfig = field(default_factory=LTX2VAEConfig) + vae_tiling: bool = True + vae_sp: bool = False + + text_encoder_configs: tuple[EncoderConfig, ...] = field( + default_factory=lambda: (LTX2GemmaConfig(), )) + preprocess_text_funcs: tuple[Callable[[str], str], ...] = field( + default_factory=lambda: (preprocess_text, )) + postprocess_text_funcs: tuple[Callable[[BaseEncoderOutput], torch.Tensor], + ...] = field(default_factory=lambda: + (ltx2_postprocess_text, )) + + dit_precision: str = "bf16" + vae_precision: str = "bf16" + text_encoder_precisions: tuple[str, ...] = field( + default_factory=lambda: ("bf16", )) + + audio_decoder_config: ModelConfig = field( + default_factory=LTX2AudioDecoderConfig) + vocoder_config: ModelConfig = field(default_factory=LTX2VocoderConfig) + audio_decoder_precision: str = "bf16" + vocoder_precision: str = "bf16" + + def __post_init__(self) -> None: + self.vae_config.load_encoder = False + self.vae_config.load_decoder = True diff --git a/fastvideo/configs/pipelines/registry.py b/fastvideo/configs/pipelines/registry.py index 0b4c148df..baade6da1 100644 --- a/fastvideo/configs/pipelines/registry.py +++ b/fastvideo/configs/pipelines/registry.py @@ -9,6 +9,7 @@ from fastvideo.configs.pipelines.cosmos import CosmosConfig from fastvideo.configs.pipelines.cosmos2_5 import Cosmos25Config from fastvideo.configs.pipelines.hunyuan import FastHunyuanConfig, HunyuanConfig from fastvideo.configs.pipelines.hunyuan15 import Hunyuan15T2V480PConfig, Hunyuan15T2V720PConfig +from fastvideo.configs.pipelines.ltx2 import LTX2T2VConfig from fastvideo.configs.pipelines.stepvideo import StepVideoT2VConfig from fastvideo.configs.pipelines.longcat import LongCatT2V480PConfig from fastvideo.configs.pipelines.turbodiffusion import ( @@ -64,6 +65,9 @@ PIPE_NAME_TO_CONFIG: dict[str, type[PipelineConfig]] = { "FastVideo/LongCat-Video-T2V-Diffusers": LongCatT2V480PConfig, "FastVideo/LongCat-Video-I2V-Diffusers": LongCatT2V480PConfig, "FastVideo/LongCat-Video-VC-Diffusers": LongCatT2V480PConfig, + # LTX-2 models + "Lightricks/LTX-2": LTX2T2VConfig, + "converted/ltx2_diffusers": LTX2T2VConfig, # TurboDiffusion models "loayrashid/TurboWan2.1-T2V-1.3B-Diffusers": TurboDiffusionT2V_1_3B_Config, "loayrashid/TurboWan2.1-T2V-14B-Diffusers": TurboDiffusionT2V_14B_Config, @@ -102,6 +106,8 @@ PIPELINE_DETECTOR: dict[str, Callable[[str], bool]] = { lambda id: "cosmos25" in id.lower(), "turbodiffusion": lambda id: "turbodiffusion" in id.lower() or "turbowan" in id.lower(), + "ltx2": + lambda id: "ltx2" in id.lower() or "ltx-2" in id.lower(), # Add other pipeline architecture detectors } @@ -123,6 +129,7 @@ PIPELINE_FALLBACK_CONFIG: dict[str, type[PipelineConfig]] = { "wancausaldmdpipeline": SelfForcingWanT2V480PConfig, "stepvideo": StepVideoT2VConfig, "turbodiffusion": TurboDiffusionT2V_1_3B_Config, + "ltx2": LTX2T2VConfig, # Other fallbacks by architecture } diff --git a/fastvideo/configs/sample/ltx2.py b/fastvideo/configs/sample/ltx2.py new file mode 100644 index 000000000..4be8d40bd --- /dev/null +++ b/fastvideo/configs/sample/ltx2.py @@ -0,0 +1,20 @@ +# SPDX-License-Identifier: Apache-2.0 +from dataclasses import dataclass + +from fastvideo.configs.sample.base import SamplingParam + + +@dataclass +class LTX2SamplingParam(SamplingParam): + """Default sampling parameters for LTX-2 distilled T2V. + """ + + seed: int = 10 + num_frames: int = 121 + height: int = 1024 + width: int = 1536 + fps: int = 24 + num_inference_steps: int = 8 + guidance_scale: float = 1.0 + # No default negative_prompt for distilled models + negative_prompt: str = "" diff --git a/fastvideo/configs/sample/registry.py b/fastvideo/configs/sample/registry.py index 89673bed8..6b26133d2 100644 --- a/fastvideo/configs/sample/registry.py +++ b/fastvideo/configs/sample/registry.py @@ -10,6 +10,7 @@ from fastvideo.configs.sample.stepvideo import StepVideoT2VSamplingParam from fastvideo.configs.sample.cosmos import Cosmos_Predict2_2B_Video2World_SamplingParam from fastvideo.configs.sample.cosmos2_5 import Cosmos_Predict2_5_2B_Diffusers_SamplingParam +from fastvideo.configs.sample.ltx2 import LTX2SamplingParam # isort: off from fastvideo.configs.sample.wan import ( @@ -40,48 +41,36 @@ from fastvideo.utils import (maybe_download_model_index, logger = init_logger(__name__) # Registry maps specific model weights to their config classes SAMPLING_PARAM_REGISTRY: dict[str, Any] = { - "FastVideo/FastHunyuan-diffusers": - FastHunyuanSamplingParam, - "hunyuanvideo-community/HunyuanVideo": - HunyuanSamplingParam, + "FastVideo/FastHunyuan-diffusers": FastHunyuanSamplingParam, + "hunyuanvideo-community/HunyuanVideo": HunyuanSamplingParam, "hunyuanvideo-community/HunyuanVideo-1.5-Diffusers-480p_t2v": Hunyuan15_480P_SamplingParam, "hunyuanvideo-community/HunyuanVideo-1.5-Diffusers-720p_t2v": Hunyuan15_720P_SamplingParam, - "FastVideo/stepvideo-t2v-diffusers": - StepVideoT2VSamplingParam, + "FastVideo/stepvideo-t2v-diffusers": StepVideoT2VSamplingParam, # Wan2.1 - "Wan-AI/Wan2.1-T2V-1.3B-Diffusers": - WanT2V_1_3B_SamplingParam, - "Wan-AI/Wan2.1-T2V-14B-Diffusers": - WanT2V_14B_SamplingParam, - "Wan-AI/Wan2.1-I2V-14B-480P-Diffusers": - WanI2V_14B_480P_SamplingParam, - "Wan-AI/Wan2.1-I2V-14B-720P-Diffusers": - WanI2V_14B_720P_SamplingParam, + "Wan-AI/Wan2.1-T2V-1.3B-Diffusers": WanT2V_1_3B_SamplingParam, + "Wan-AI/Wan2.1-T2V-14B-Diffusers": WanT2V_14B_SamplingParam, + "Wan-AI/Wan2.1-I2V-14B-480P-Diffusers": WanI2V_14B_480P_SamplingParam, + "Wan-AI/Wan2.1-I2V-14B-720P-Diffusers": WanI2V_14B_720P_SamplingParam, "weizhou03/Wan2.1-Fun-1.3B-InP-Diffusers": Wan2_1_Fun_1_3B_InP_SamplingParam, "IRMChen/Wan2.1-Fun-1.3B-Control-Diffusers": Wan2_1_Fun_1_3B_Control_SamplingParam, # Wan2.2 - "Wan-AI/Wan2.2-TI2V-5B-Diffusers": - Wan2_2_TI2V_5B_SamplingParam, + "Wan-AI/Wan2.2-TI2V-5B-Diffusers": Wan2_2_TI2V_5B_SamplingParam, "FastVideo/FastWan2.2-TI2V-5B-FullAttn-Diffusers": Wan2_2_TI2V_5B_SamplingParam, - "Wan-AI/Wan2.2-T2V-A14B-Diffusers": - Wan2_2_T2V_A14B_SamplingParam, - "Wan-AI/Wan2.2-I2V-A14B-Diffusers": - Wan2_2_I2V_A14B_SamplingParam, + "Wan-AI/Wan2.2-T2V-A14B-Diffusers": Wan2_2_T2V_A14B_SamplingParam, + "Wan-AI/Wan2.2-I2V-A14B-Diffusers": Wan2_2_I2V_A14B_SamplingParam, # FastWan2.1 - "FastVideo/FastWan2.1-T2V-1.3B-Diffusers": - FastWanT2V480P_SamplingParam, + "FastVideo/FastWan2.1-T2V-1.3B-Diffusers": FastWanT2V480P_SamplingParam, # FastWan2.2 - "FastVideo/FastWan2.2-TI2V-5B-Diffusers": - Wan2_2_TI2V_5B_SamplingParam, + "FastVideo/FastWan2.2-TI2V-5B-Diffusers": Wan2_2_TI2V_5B_SamplingParam, # Causal Self-Forcing Wan2.1 "wlsaidhi/SFWan2.1-T2V-1.3B-Diffusers": @@ -102,12 +91,9 @@ SAMPLING_PARAM_REGISTRY: dict[str, Any] = { Cosmos_Predict2_5_2B_Diffusers_SamplingParam, # MatrixGame2.0 models - "FastVideo/Matrix-Game-2.0-Base-Diffusers": - MatrixGame2_SamplingParam, - "FastVideo/Matrix-Game-2.0-GTA-Diffusers": - MatrixGame2_SamplingParam, - "FastVideo/Matrix-Game-2.0-TempleRun-Diffusers": - MatrixGame2_SamplingParam, + "FastVideo/Matrix-Game-2.0-Base-Diffusers": MatrixGame2_SamplingParam, + "FastVideo/Matrix-Game-2.0-GTA-Diffusers": MatrixGame2_SamplingParam, + "FastVideo/Matrix-Game-2.0-TempleRun-Diffusers": MatrixGame2_SamplingParam, # TurboDiffusion models "loayrashid/TurboWan2.1-T2V-1.3B-Diffusers": @@ -117,6 +103,10 @@ SAMPLING_PARAM_REGISTRY: dict[str, Any] = { "loayrashid/TurboWan2.2-I2V-A14B-Diffusers": TurboDiffusionI2V_A14B_SamplingParam, + # LTX-2 models + "Lightricks/LTX-2": LTX2SamplingParam, + "FastVideo/LTX2-Distilled-Diffusers": LTX2SamplingParam, + # Add other specific weight variants } @@ -144,6 +134,8 @@ SAMPLING_PARAM_DETECTOR: dict[str, Callable[[str], bool]] = { lambda id: "cosmos2_5" in id.lower(), "cosmos": lambda id: "cosmos" in id.lower() and "2_5" not in id.lower(), + "ltx2": + lambda id: "ltx2" in id.lower() or "ltx-2" in id.lower(), # Add other pipeline architecture detectors } @@ -164,6 +156,7 @@ SAMPLING_FALLBACK_PARAM: dict[str, Any] = { TurboDiffusionT2V_1_3B_SamplingParam, # Default to T2V for fallback "cosmos25": Cosmos_Predict2_5_2B_Diffusers_SamplingParam, "cosmos": Cosmos_Predict2_2B_Video2World_SamplingParam, + "ltx2": LTX2SamplingParam, # Other fallbacks by architecture } diff --git a/fastvideo/entrypoints/video_generator.py b/fastvideo/entrypoints/video_generator.py index d14b7a73d..d586d9215 100644 --- a/fastvideo/entrypoints/video_generator.py +++ b/fastvideo/entrypoints/video_generator.py @@ -18,6 +18,8 @@ import numpy as np import torch import torchvision from einops import rearrange +import shutil +import tempfile from fastvideo.configs.sample import SamplingParam from fastvideo.fastvideo_args import FastVideoArgs @@ -389,6 +391,11 @@ class VideoGenerator: if batch.save_video: imageio.mimsave(output_path, frames, fps=batch.fps, format="mp4") logger.info("Saved video to %s", output_path) + audio = output_batch.extra.get("audio") + audio_sample_rate = output_batch.extra.get("audio_sample_rate") + if (audio is not None and audio_sample_rate is not None and + not self._mux_audio(output_path, audio, audio_sample_rate)): + logger.warning("Audio mux failed; saved video without audio.") if batch.return_frames: return frames @@ -396,6 +403,7 @@ class VideoGenerator: return { "samples": samples, "frames": frames, + "audio": output_batch.extra.get("audio"), "prompts": prompt, "size": (target_height, target_width, batch.num_frames), "generation_time": gen_time, @@ -405,6 +413,98 @@ class VideoGenerator: "trajectory_decoded": output_batch.trajectory_decoded, } + @staticmethod + def _mux_audio( + video_path: str, + audio: torch.Tensor | np.ndarray, + sample_rate: int, + ) -> bool: + """Mux audio into video using PyAV.""" + try: + import av + except ImportError: + logger.warning("PyAV not installed; cannot mux audio. " + "Install with: pip install av") + return False + + if torch.is_tensor(audio): + audio_np = audio.detach().cpu().float().numpy() + else: + audio_np = np.asarray(audio, dtype=np.float32) + + if audio_np.ndim == 1: + audio_np = audio_np[:, None] + elif audio_np.ndim == 2: + if audio_np.shape[0] <= 8 and audio_np.shape[1] > audio_np.shape[0]: + audio_np = audio_np.T + else: + logger.warning("Unexpected audio shape %s; skipping mux.", + audio_np.shape) + return False + + audio_np = np.clip(audio_np, -1.0, 1.0) + audio_int16 = (audio_np * 32767.0).astype(np.int16) + num_channels = audio_int16.shape[1] + layout = "stereo" if num_channels == 2 else "mono" + + try: + import wave + with tempfile.TemporaryDirectory() as tmpdir: + out_path = os.path.join(tmpdir, "muxed.mp4") + wav_path = os.path.join(tmpdir, "audio.wav") + + # Write audio to WAV file + with wave.open(wav_path, "wb") as wav_file: + wav_file.setnchannels(num_channels) + wav_file.setsampwidth(2) + wav_file.setframerate(sample_rate) + wav_file.writeframes(audio_int16.tobytes()) + + # Open input video and audio + input_video = av.open(video_path) + input_audio = av.open(wav_path) + + # Create output with both streams + output = av.open(out_path, mode="w") + + # Add video stream (copy codec from input) + in_video_stream = input_video.streams.video[0] + out_video_stream = output.add_stream( + codec_name=in_video_stream.codec_context.name, + rate=in_video_stream.average_rate, + ) + out_video_stream.width = in_video_stream.width + out_video_stream.height = in_video_stream.height + out_video_stream.pix_fmt = in_video_stream.pix_fmt + + # Add audio stream (AAC) + out_audio_stream = output.add_stream("aac", rate=sample_rate) + out_audio_stream.layout = layout + + # Remux video (decode and re-encode to be safe) + for frame in input_video.decode(video=0): + for packet in out_video_stream.encode(frame): + output.mux(packet) + for packet in out_video_stream.encode(): + output.mux(packet) + + # Encode audio + for frame in input_audio.decode(audio=0): + frame.pts = None # Let encoder assign PTS + for packet in out_audio_stream.encode(frame): + output.mux(packet) + for packet in out_audio_stream.encode(): + output.mux(packet) + + input_video.close() + input_audio.close() + output.close() + shutil.move(out_path, video_path) + return True + except Exception as e: + logger.warning("Audio mux failed: %s", e) + return False + def set_lora_adapter(self, lora_nickname: str, lora_path: str | None = None) -> None: diff --git a/fastvideo/fastvideo_args.py b/fastvideo/fastvideo_args.py index c2afc9f3a..33c06efcc 100644 --- a/fastvideo/fastvideo_args.py +++ b/fastvideo/fastvideo_args.py @@ -166,6 +166,14 @@ class FastVideoArgs: # Prompt text file for batch processing prompt_txt: str | None = None + # LTX-2 VAE tiling overrides + ltx2_vae_tiling: bool | None = None + ltx2_vae_spatial_tile_size_in_pixels: int | None = None + ltx2_vae_spatial_tile_overlap_in_pixels: int | None = None + ltx2_vae_temporal_tile_size_in_frames: int | None = None + ltx2_vae_temporal_tile_overlap_in_frames: int | None = None + ltx2_initial_latent_path: str | None = None + # model paths for correct deallocation model_paths: dict[str, str] = field(default_factory=dict) model_loaded: dict[str, bool] = field(default_factory=lambda: { @@ -203,8 +211,44 @@ class FastVideoArgs: logger.error("Failed to load V-MoBA config from %s: %s", self.moba_config_path, e) raise + self._apply_ltx2_vae_overrides() self.check_fastvideo_args() + def _apply_ltx2_vae_overrides(self) -> None: + if self.pipeline_config is None: + return + vae_config = self.pipeline_config.vae_config + has_any = any(value is not None for value in ( + self.ltx2_vae_spatial_tile_size_in_pixels, + self.ltx2_vae_spatial_tile_overlap_in_pixels, + self.ltx2_vae_temporal_tile_size_in_frames, + self.ltx2_vae_temporal_tile_overlap_in_frames, + )) + if self.ltx2_vae_tiling is not None and hasattr(self.pipeline_config, + "vae_tiling"): + self.pipeline_config.vae_tiling = self.ltx2_vae_tiling + elif has_any and hasattr(self.pipeline_config, "vae_tiling"): + self.pipeline_config.vae_tiling = True + + if hasattr(vae_config, "ltx2_spatial_tile_size_in_pixels" + ) and self.ltx2_vae_spatial_tile_size_in_pixels is not None: + vae_config.ltx2_spatial_tile_size_in_pixels = ( + self.ltx2_vae_spatial_tile_size_in_pixels) + if hasattr( + vae_config, "ltx2_spatial_tile_overlap_in_pixels" + ) and self.ltx2_vae_spatial_tile_overlap_in_pixels is not None: + vae_config.ltx2_spatial_tile_overlap_in_pixels = ( + self.ltx2_vae_spatial_tile_overlap_in_pixels) + if hasattr(vae_config, "ltx2_temporal_tile_size_in_frames" + ) and self.ltx2_vae_temporal_tile_size_in_frames is not None: + vae_config.ltx2_temporal_tile_size_in_frames = ( + self.ltx2_vae_temporal_tile_size_in_frames) + if hasattr( + vae_config, "ltx2_temporal_tile_overlap_in_frames" + ) and self.ltx2_vae_temporal_tile_overlap_in_frames is not None: + vae_config.ltx2_temporal_tile_overlap_in_frames = ( + self.ltx2_vae_temporal_tile_overlap_in_frames) + @staticmethod def add_cli_args(parser: FlexibleArgumentParser) -> FlexibleArgumentParser: # Model and path configuration @@ -325,6 +369,44 @@ class FastVideoArgs: "Path to a text file containing prompts (one per line) for batch processing", ) + # LTX-2 VAE tiling overrides + parser.add_argument( + "--ltx2-vae-tiling", + action=StoreBoolean, + default=FastVideoArgs.ltx2_vae_tiling, + help="Enable LTX-2 VAE tiling overrides.", + ) + parser.add_argument( + "--ltx2-vae-spatial-tile-size-in-pixels", + type=int, + default=FastVideoArgs.ltx2_vae_spatial_tile_size_in_pixels, + help="LTX-2 VAE spatial tile size in pixels.", + ) + parser.add_argument( + "--ltx2-vae-spatial-tile-overlap-in-pixels", + type=int, + default=FastVideoArgs.ltx2_vae_spatial_tile_overlap_in_pixels, + help="LTX-2 VAE spatial tile overlap in pixels.", + ) + parser.add_argument( + "--ltx2-vae-temporal-tile-size-in-frames", + type=int, + default=FastVideoArgs.ltx2_vae_temporal_tile_size_in_frames, + help="LTX-2 VAE temporal tile size in frames.", + ) + parser.add_argument( + "--ltx2-vae-temporal-tile-overlap-in-frames", + type=int, + default=FastVideoArgs.ltx2_vae_temporal_tile_overlap_in_frames, + help="LTX-2 VAE temporal tile overlap in frames.", + ) + parser.add_argument( + "--ltx2-initial-latent-path", + type=str, + default=FastVideoArgs.ltx2_initial_latent_path, + help="Path to load/save a precomputed LTX-2 initial latent.", + ) + # LoRA parameters (inference-time adapter loading) parser.add_argument( "--lora-path", diff --git a/fastvideo/models/audio/__init__.py b/fastvideo/models/audio/__init__.py new file mode 100644 index 000000000..9ba265f8e --- /dev/null +++ b/fastvideo/models/audio/__init__.py @@ -0,0 +1,9 @@ +# SPDX-License-Identifier: Apache-2.0 + +from fastvideo.models.audio.ltx2_audio_vae import ( + LTX2AudioDecoder, + LTX2AudioEncoder, + LTX2Vocoder, +) + +__all__ = ["LTX2AudioEncoder", "LTX2AudioDecoder", "LTX2Vocoder"] diff --git a/fastvideo/models/audio/ltx2_audio_vae.py b/fastvideo/models/audio/ltx2_audio_vae.py new file mode 100644 index 000000000..fcc047f6c --- /dev/null +++ b/fastvideo/models/audio/ltx2_audio_vae.py @@ -0,0 +1,1327 @@ +# SPDX-License-Identifier: Apache-2.0 +""" +Native LTX-2 Audio VAE and Vocoder implementation for FastVideo. +""" + +from __future__ import annotations + +import math +from enum import Enum +from typing import Any, List, NamedTuple, Set, Tuple + +import einops +import torch +import torch.nn as nn +import torch.nn.functional as F + + +# ============================================================================= +# Enums +# ============================================================================= + + +class NormType(Enum): + """Normalization layer types: GROUP (GroupNorm) or PIXEL (per-location RMS norm).""" + GROUP = "group" + PIXEL = "pixel" + + +class AttentionType(Enum): + """Enum for specifying the attention mechanism type.""" + VANILLA = "vanilla" + LINEAR = "linear" + NONE = "none" + + +class CausalityAxis(Enum): + """Enum for specifying the causality axis in causal convolutions.""" + NONE = None + WIDTH = "width" + HEIGHT = "height" + WIDTH_COMPATIBILITY = "width-compatibility" + + +# ============================================================================= +# Audio Latent Shape +# ============================================================================= + + +class AudioLatentShape(NamedTuple): + """Shape of audio in VAE latent space: (batch, channels, frames, mel_bins).""" + batch: int + channels: int + frames: int + mel_bins: int + + def to_torch_shape(self) -> torch.Size: + return torch.Size([self.batch, self.channels, self.frames, self.mel_bins]) + + @staticmethod + def from_torch_shape(shape: torch.Size) -> AudioLatentShape: + return AudioLatentShape( + batch=shape[0], + channels=shape[1], + frames=shape[2], + mel_bins=shape[3], + ) + + +# ============================================================================= +# Constants +# ============================================================================= + + +LATENT_DOWNSAMPLE_FACTOR = 4 +LRELU_SLOPE = 0.1 + + +# ============================================================================= +# Normalization Layers +# ============================================================================= + + +class PixelNorm(nn.Module): + """ + Per-pixel (per-location) RMS normalization layer. + """ + + def __init__(self, dim: int = 1, eps: float = 1e-8) -> None: + super().__init__() + self.dim = dim + self.eps = eps + + def forward(self, x: torch.Tensor) -> torch.Tensor: + mean_sq = torch.mean(x ** 2, dim=self.dim, keepdim=True) + rms = torch.sqrt(mean_sq + self.eps) + return x / rms + + +def build_normalization_layer( + in_channels: int, + *, + num_groups: int = 32, + normtype: NormType = NormType.GROUP, +) -> nn.Module: + """Create a normalization layer based on the normalization type.""" + if normtype == NormType.GROUP: + return nn.GroupNorm( + num_groups=num_groups, num_channels=in_channels, eps=1e-6, affine=True + ) + if normtype == NormType.PIXEL: + return PixelNorm(dim=1, eps=1e-6) + raise ValueError(f"Invalid normalization type: {normtype}") + + +# ============================================================================= +# Per-Channel Statistics +# ============================================================================= + + +class PerChannelStatistics(nn.Module): + """ + Per-channel statistics for normalizing and denormalizing the latent representation. + """ + + def __init__(self, latent_channels: int = 128) -> None: + super().__init__() + self.register_buffer("std-of-means", torch.empty(latent_channels)) + self.register_buffer("mean-of-means", torch.empty(latent_channels)) + + def un_normalize(self, x: torch.Tensor) -> torch.Tensor: + return (x * self.get_buffer("std-of-means").to(x)) + self.get_buffer( + "mean-of-means" + ).to(x) + + def normalize(self, x: torch.Tensor) -> torch.Tensor: + return (x - self.get_buffer("mean-of-means").to(x)) / self.get_buffer( + "std-of-means" + ).to(x) + + +# ============================================================================= +# Audio Patchifier +# ============================================================================= + + +class AudioPatchifier: + """Simple patchifier for audio latents.""" + + def __init__( + self, + patch_size: int = 1, + sample_rate: int = 16000, + hop_length: int = 160, + audio_latent_downsample_factor: int = 4, + is_causal: bool = True, + ): + self.patch_size = patch_size + self.sample_rate = sample_rate + self.hop_length = hop_length + self.audio_latent_downsample_factor = audio_latent_downsample_factor + self.is_causal = is_causal + + def patchify(self, audio_latents: torch.Tensor) -> torch.Tensor: + """Flatten audio latent tensor along time: (B, C, T, F) -> (B, T, C*F).""" + return einops.rearrange(audio_latents, "b c t f -> b t (c f)") + + def unpatchify( + self, audio_latents: torch.Tensor, output_shape: AudioLatentShape + ) -> torch.Tensor: + """Restore (B, C, T, F) from flattened patches: (B, T, C*F) -> (B, C, T, F).""" + return einops.rearrange( + audio_latents, + "b t (c f) -> b c t f", + c=output_shape.channels, + f=output_shape.mel_bins, + ) + + +# ============================================================================= +# Causal 2D Convolution +# ============================================================================= + + +class CausalConv2d(nn.Module): + """ + A causal 2D convolution. + Ensures output at time t only depends on inputs at time t and earlier. + """ + + def __init__( + self, + in_channels: int, + out_channels: int, + kernel_size: int | Tuple[int, int], + stride: int = 1, + dilation: int | Tuple[int, int] = 1, + groups: int = 1, + bias: bool = True, + causality_axis: CausalityAxis = CausalityAxis.HEIGHT, + ) -> None: + super().__init__() + + self.causality_axis = causality_axis + + # Ensure kernel_size and dilation are tuples + kernel_size = nn.modules.utils._pair(kernel_size) + dilation = nn.modules.utils._pair(dilation) + + # Calculate padding dimensions + pad_h = (kernel_size[0] - 1) * dilation[0] + pad_w = (kernel_size[1] - 1) * dilation[1] + + # The padding tuple for F.pad is (pad_left, pad_right, pad_top, pad_bottom) + if self.causality_axis == CausalityAxis.NONE: + self.padding = (pad_w // 2, pad_w - pad_w // 2, pad_h // 2, pad_h - pad_h // 2) + elif self.causality_axis in (CausalityAxis.WIDTH, CausalityAxis.WIDTH_COMPATIBILITY): + self.padding = (pad_w, 0, pad_h // 2, pad_h - pad_h // 2) + elif self.causality_axis == CausalityAxis.HEIGHT: + self.padding = (pad_w // 2, pad_w - pad_w // 2, pad_h, 0) + else: + raise ValueError(f"Invalid causality_axis: {causality_axis}") + + # The internal convolution layer uses no padding, as we handle it manually + self.conv = nn.Conv2d( + in_channels, + out_channels, + kernel_size, + stride=stride, + padding=0, + dilation=dilation, + groups=groups, + bias=bias, + ) + + def forward(self, x: torch.Tensor) -> torch.Tensor: + x = F.pad(x, self.padding) + return self.conv(x) + + +def make_conv2d( + in_channels: int, + out_channels: int, + kernel_size: int | Tuple[int, int], + stride: int = 1, + padding: Tuple[int, int, int, int] | None = None, + dilation: int = 1, + groups: int = 1, + bias: bool = True, + causality_axis: CausalityAxis | None = None, +) -> nn.Module: + """Create a 2D convolution layer that can be either causal or non-causal.""" + if causality_axis is not None: + return CausalConv2d( + in_channels, out_channels, kernel_size, stride, dilation, groups, bias, causality_axis + ) + else: + if padding is None: + padding = kernel_size // 2 if isinstance(kernel_size, int) else tuple(k // 2 for k in kernel_size) + return nn.Conv2d( + in_channels, + out_channels, + kernel_size, + stride, + padding, + dilation, + groups, + bias, + ) + + +# ============================================================================= +# Attention Blocks +# ============================================================================= + + +class AttnBlock(nn.Module): + """Vanilla self-attention block for 2D features.""" + + def __init__( + self, + in_channels: int, + norm_type: NormType = NormType.GROUP, + ) -> None: + super().__init__() + self.in_channels = in_channels + + self.norm = build_normalization_layer(in_channels, normtype=norm_type) + self.q = nn.Conv2d(in_channels, in_channels, kernel_size=1, stride=1, padding=0) + self.k = nn.Conv2d(in_channels, in_channels, kernel_size=1, stride=1, padding=0) + self.v = nn.Conv2d(in_channels, in_channels, kernel_size=1, stride=1, padding=0) + self.proj_out = nn.Conv2d(in_channels, in_channels, kernel_size=1, stride=1, padding=0) + + def forward(self, x: torch.Tensor) -> torch.Tensor: + h_ = x + h_ = self.norm(h_) + q = self.q(h_) + k = self.k(h_) + v = self.v(h_) + + # Compute attention + b, c, h, w = q.shape + q = q.reshape(b, c, h * w).contiguous() + q = q.permute(0, 2, 1).contiguous() # b, hw, c + k = k.reshape(b, c, h * w).contiguous() # b, c, hw + w_ = torch.bmm(q, k).contiguous() # b, hw, hw + w_ = w_ * (int(c) ** (-0.5)) + w_ = F.softmax(w_, dim=2) + + # Attend to values + v = v.reshape(b, c, h * w).contiguous() + w_ = w_.permute(0, 2, 1).contiguous() # b, hw, hw + h_ = torch.bmm(v, w_).contiguous() # b, c, hw + h_ = h_.reshape(b, c, h, w).contiguous() + + h_ = self.proj_out(h_) + + return x + h_ + + +def make_attn( + in_channels: int, + attn_type: AttentionType = AttentionType.VANILLA, + norm_type: NormType = NormType.GROUP, +) -> nn.Module: + """Factory function for attention blocks.""" + if attn_type == AttentionType.VANILLA: + return AttnBlock(in_channels, norm_type=norm_type) + elif attn_type == AttentionType.NONE: + return nn.Identity() + elif attn_type == AttentionType.LINEAR: + raise NotImplementedError(f"Attention type {attn_type.value} is not supported yet.") + else: + raise ValueError(f"Unknown attention type: {attn_type}") + + +# ============================================================================= +# ResNet Blocks (2D for Audio VAE) +# ============================================================================= + + +class ResnetBlock(nn.Module): + """2D ResNet block for audio VAE.""" + + def __init__( + self, + *, + in_channels: int, + out_channels: int | None = None, + conv_shortcut: bool = False, + dropout: float = 0.0, + temb_channels: int = 512, + norm_type: NormType = NormType.GROUP, + causality_axis: CausalityAxis = CausalityAxis.HEIGHT, + ) -> None: + super().__init__() + self.causality_axis = causality_axis + + if self.causality_axis != CausalityAxis.NONE and norm_type == NormType.GROUP: + raise ValueError("Causal ResnetBlock with GroupNorm is not supported.") + + self.in_channels = in_channels + out_channels = in_channels if out_channels is None else out_channels + self.out_channels = out_channels + self.use_conv_shortcut = conv_shortcut + + self.norm1 = build_normalization_layer(in_channels, normtype=norm_type) + self.non_linearity = nn.SiLU() + self.conv1 = make_conv2d( + in_channels, out_channels, kernel_size=3, stride=1, causality_axis=causality_axis + ) + if temb_channels > 0: + self.temb_proj = nn.Linear(temb_channels, out_channels) + self.norm2 = build_normalization_layer(out_channels, normtype=norm_type) + self.dropout = nn.Dropout(dropout) + self.conv2 = make_conv2d( + out_channels, out_channels, kernel_size=3, stride=1, causality_axis=causality_axis + ) + if self.in_channels != self.out_channels: + if self.use_conv_shortcut: + self.conv_shortcut = make_conv2d( + in_channels, out_channels, kernel_size=3, stride=1, causality_axis=causality_axis + ) + else: + self.nin_shortcut = make_conv2d( + in_channels, out_channels, kernel_size=1, stride=1, causality_axis=causality_axis + ) + + def forward( + self, + x: torch.Tensor, + temb: torch.Tensor | None = None, + ) -> torch.Tensor: + h = x + h = self.norm1(h) + h = self.non_linearity(h) + h = self.conv1(h) + + if temb is not None: + h = h + self.temb_proj(self.non_linearity(temb))[:, :, None, None] + + h = self.norm2(h) + h = self.non_linearity(h) + h = self.dropout(h) + h = self.conv2(h) + + if self.in_channels != self.out_channels: + x = self.conv_shortcut(x) if self.use_conv_shortcut else self.nin_shortcut(x) + + return x + h + + +# ============================================================================= +# Vocoder ResBlocks (1D) +# ============================================================================= + + +class ResBlock1(nn.Module): + """1D ResBlock for vocoder with dilated convolutions.""" + + def __init__( + self, + channels: int, + kernel_size: int = 3, + dilation: Tuple[int, int, int] = (1, 3, 5), + ): + super().__init__() + self.convs1 = nn.ModuleList( + [ + nn.Conv1d(channels, channels, kernel_size, 1, dilation=dilation[0], padding="same"), + nn.Conv1d(channels, channels, kernel_size, 1, dilation=dilation[1], padding="same"), + nn.Conv1d(channels, channels, kernel_size, 1, dilation=dilation[2], padding="same"), + ] + ) + self.convs2 = nn.ModuleList( + [ + nn.Conv1d(channels, channels, kernel_size, 1, dilation=1, padding="same"), + nn.Conv1d(channels, channels, kernel_size, 1, dilation=1, padding="same"), + nn.Conv1d(channels, channels, kernel_size, 1, dilation=1, padding="same"), + ] + ) + + def forward(self, x: torch.Tensor) -> torch.Tensor: + for conv1, conv2 in zip(self.convs1, self.convs2, strict=True): + xt = F.leaky_relu(x, LRELU_SLOPE) + xt = conv1(xt) + xt = F.leaky_relu(xt, LRELU_SLOPE) + xt = conv2(xt) + x = xt + x + return x + + +class ResBlock2(nn.Module): + """1D ResBlock for vocoder (simpler version).""" + + def __init__( + self, + channels: int, + kernel_size: int = 3, + dilation: Tuple[int, int] = (1, 3), + ): + super().__init__() + self.convs = nn.ModuleList( + [ + nn.Conv1d(channels, channels, kernel_size, 1, dilation=dilation[0], padding="same"), + nn.Conv1d(channels, channels, kernel_size, 1, dilation=dilation[1], padding="same"), + ] + ) + + def forward(self, x: torch.Tensor) -> torch.Tensor: + for conv in self.convs: + xt = F.leaky_relu(x, LRELU_SLOPE) + xt = conv(xt) + x = xt + x + return x + + +# ============================================================================= +# Downsampling +# ============================================================================= + + +class Downsample(nn.Module): + """Downsampling layer with strided convolution or average pooling.""" + + def __init__( + self, + in_channels: int, + with_conv: bool, + causality_axis: CausalityAxis = CausalityAxis.WIDTH, + ) -> None: + super().__init__() + self.with_conv = with_conv + self.causality_axis = causality_axis + + if self.causality_axis != CausalityAxis.NONE and not self.with_conv: + raise ValueError("causality is only supported when `with_conv=True`.") + + if self.with_conv: + self.conv = nn.Conv2d(in_channels, in_channels, kernel_size=3, stride=2, padding=0) + + def forward(self, x: torch.Tensor) -> torch.Tensor: + if self.with_conv: + # Padding tuple is in the order: (left, right, top, bottom) + if self.causality_axis == CausalityAxis.NONE: + pad = (0, 1, 0, 1) + elif self.causality_axis == CausalityAxis.WIDTH: + pad = (2, 0, 0, 1) + elif self.causality_axis == CausalityAxis.HEIGHT: + pad = (0, 1, 2, 0) + elif self.causality_axis == CausalityAxis.WIDTH_COMPATIBILITY: + pad = (1, 0, 0, 1) + else: + raise ValueError(f"Invalid causality_axis: {self.causality_axis}") + + x = F.pad(x, pad, mode="constant", value=0) + x = self.conv(x) + else: + x = F.avg_pool2d(x, kernel_size=2, stride=2) + + return x + + +def build_downsampling_path( + *, + ch: int, + ch_mult: Tuple[int, ...], + num_resolutions: int, + num_res_blocks: int, + resolution: int, + temb_channels: int, + dropout: float, + norm_type: NormType, + causality_axis: CausalityAxis, + attn_type: AttentionType, + attn_resolutions: Set[int], + resamp_with_conv: bool, +) -> Tuple[nn.ModuleList, int]: + """Build the downsampling path with residual blocks, attention, and downsampling layers.""" + down_modules = nn.ModuleList() + curr_res = resolution + in_ch_mult = (1, *tuple(ch_mult)) + block_in = ch + + for i_level in range(num_resolutions): + block = nn.ModuleList() + attn = nn.ModuleList() + block_in = ch * in_ch_mult[i_level] + block_out = ch * ch_mult[i_level] + + for _ in range(num_res_blocks): + block.append( + ResnetBlock( + in_channels=block_in, + out_channels=block_out, + temb_channels=temb_channels, + dropout=dropout, + norm_type=norm_type, + causality_axis=causality_axis, + ) + ) + block_in = block_out + if curr_res in attn_resolutions: + attn.append(make_attn(block_in, attn_type=attn_type, norm_type=norm_type)) + + down = nn.Module() + down.block = block + down.attn = attn + if i_level != num_resolutions - 1: + down.downsample = Downsample(block_in, resamp_with_conv, causality_axis=causality_axis) + curr_res = curr_res // 2 + down_modules.append(down) + + return down_modules, block_in + + +# ============================================================================= +# Upsampling +# ============================================================================= + + +class Upsample(nn.Module): + """Upsampling layer with nearest-neighbor interpolation and optional convolution.""" + + def __init__( + self, + in_channels: int, + with_conv: bool, + causality_axis: CausalityAxis = CausalityAxis.HEIGHT, + ) -> None: + super().__init__() + self.with_conv = with_conv + self.causality_axis = causality_axis + if self.with_conv: + self.conv = make_conv2d( + in_channels, in_channels, kernel_size=3, stride=1, causality_axis=causality_axis + ) + + def forward(self, x: torch.Tensor) -> torch.Tensor: + x = F.interpolate(x, scale_factor=2.0, mode="nearest") + if self.with_conv: + x = self.conv(x) + # Drop FIRST element in the causal axis to undo encoder's padding + if self.causality_axis == CausalityAxis.NONE: + pass + elif self.causality_axis == CausalityAxis.HEIGHT: + x = x[:, :, 1:, :] + elif self.causality_axis == CausalityAxis.WIDTH: + x = x[:, :, :, 1:] + elif self.causality_axis == CausalityAxis.WIDTH_COMPATIBILITY: + pass + else: + raise ValueError(f"Invalid causality_axis: {self.causality_axis}") + + return x + + +def build_upsampling_path( + *, + ch: int, + ch_mult: Tuple[int, ...], + num_resolutions: int, + num_res_blocks: int, + resolution: int, + temb_channels: int, + dropout: float, + norm_type: NormType, + causality_axis: CausalityAxis, + attn_type: AttentionType, + attn_resolutions: Set[int], + resamp_with_conv: bool, + initial_block_channels: int, +) -> Tuple[nn.ModuleList, int]: + """Build the upsampling path with residual blocks, attention, and upsampling layers.""" + up_modules = nn.ModuleList() + block_in = initial_block_channels + curr_res = resolution // (2 ** (num_resolutions - 1)) + + for level in reversed(range(num_resolutions)): + stage = nn.Module() + stage.block = nn.ModuleList() + stage.attn = nn.ModuleList() + block_out = ch * ch_mult[level] + + for _ in range(num_res_blocks + 1): + stage.block.append( + ResnetBlock( + in_channels=block_in, + out_channels=block_out, + temb_channels=temb_channels, + dropout=dropout, + norm_type=norm_type, + causality_axis=causality_axis, + ) + ) + block_in = block_out + if curr_res in attn_resolutions: + stage.attn.append(make_attn(block_in, attn_type=attn_type, norm_type=norm_type)) + + if level != 0: + stage.upsample = Upsample(block_in, resamp_with_conv, causality_axis=causality_axis) + curr_res *= 2 + + up_modules.insert(0, stage) + + return up_modules, block_in + + +# ============================================================================= +# Mid Block +# ============================================================================= + + +def build_mid_block( + channels: int, + temb_channels: int, + dropout: float, + norm_type: NormType, + causality_axis: CausalityAxis, + attn_type: AttentionType, + add_attention: bool, +) -> nn.Module: + """Build the middle block with two ResNet blocks and optional attention.""" + mid = nn.Module() + mid.block_1 = ResnetBlock( + in_channels=channels, + out_channels=channels, + temb_channels=temb_channels, + dropout=dropout, + norm_type=norm_type, + causality_axis=causality_axis, + ) + mid.attn_1 = ( + make_attn(channels, attn_type=attn_type, norm_type=norm_type) + if add_attention + else nn.Identity() + ) + mid.block_2 = ResnetBlock( + in_channels=channels, + out_channels=channels, + temb_channels=temb_channels, + dropout=dropout, + norm_type=norm_type, + causality_axis=causality_axis, + ) + return mid + + +def run_mid_block(mid: nn.Module, features: torch.Tensor) -> torch.Tensor: + """Run features through the middle block.""" + features = mid.block_1(features, temb=None) + features = mid.attn_1(features) + return mid.block_2(features, temb=None) + + +# ============================================================================= +# Audio Encoder +# ============================================================================= + + +class AudioEncoder(nn.Module): + """ + Encoder that compresses audio spectrograms into latent representations. + """ + + def __init__( + self, + *, + ch: int, + ch_mult: Tuple[int, ...] = (1, 2, 4, 8), + num_res_blocks: int, + attn_resolutions: Set[int], + dropout: float = 0.0, + resamp_with_conv: bool = True, + in_channels: int, + resolution: int, + z_channels: int, + double_z: bool = True, + attn_type: AttentionType = AttentionType.VANILLA, + mid_block_add_attention: bool = True, + norm_type: NormType = NormType.GROUP, + causality_axis: CausalityAxis = CausalityAxis.WIDTH, + sample_rate: int = 16000, + mel_hop_length: int = 160, + n_fft: int = 1024, + is_causal: bool = True, + mel_bins: int = 64, + **_ignore_kwargs, + ) -> None: + super().__init__() + + self.per_channel_statistics = PerChannelStatistics(latent_channels=ch) + self.sample_rate = sample_rate + self.mel_hop_length = mel_hop_length + self.n_fft = n_fft + self.is_causal = is_causal + self.mel_bins = mel_bins + + self.patchifier = AudioPatchifier( + patch_size=1, + audio_latent_downsample_factor=LATENT_DOWNSAMPLE_FACTOR, + sample_rate=sample_rate, + hop_length=mel_hop_length, + is_causal=is_causal, + ) + + self.ch = ch + self.temb_ch = 0 + self.num_resolutions = len(ch_mult) + self.num_res_blocks = num_res_blocks + self.resolution = resolution + self.in_channels = in_channels + self.z_channels = z_channels + self.double_z = double_z + self.norm_type = norm_type + self.causality_axis = causality_axis + self.attn_type = attn_type + + # Input convolution + self.conv_in = make_conv2d( + in_channels, + self.ch, + kernel_size=3, + stride=1, + causality_axis=self.causality_axis, + ) + + self.non_linearity = nn.SiLU() + + # Downsampling path + self.down, block_in = build_downsampling_path( + ch=ch, + ch_mult=ch_mult, + num_resolutions=self.num_resolutions, + num_res_blocks=num_res_blocks, + resolution=resolution, + temb_channels=self.temb_ch, + dropout=dropout, + norm_type=self.norm_type, + causality_axis=self.causality_axis, + attn_type=self.attn_type, + attn_resolutions=attn_resolutions, + resamp_with_conv=resamp_with_conv, + ) + + # Mid block + self.mid = build_mid_block( + channels=block_in, + temb_channels=self.temb_ch, + dropout=dropout, + norm_type=self.norm_type, + causality_axis=self.causality_axis, + attn_type=self.attn_type, + add_attention=mid_block_add_attention, + ) + + # Output layers + self.norm_out = build_normalization_layer(block_in, normtype=self.norm_type) + self.conv_out = make_conv2d( + block_in, + 2 * z_channels if double_z else z_channels, + kernel_size=3, + stride=1, + causality_axis=self.causality_axis, + ) + + def forward(self, spectrogram: torch.Tensor) -> torch.Tensor: + """ + Encode audio spectrogram into latent representations. + Args: + spectrogram: Input spectrogram of shape (batch, channels, time, frequency) + Returns: + Encoded latent representation of shape (batch, channels, frames, mel_bins) + """ + h = self.conv_in(spectrogram) + h = self._run_downsampling_path(h) + h = run_mid_block(self.mid, h) + h = self._finalize_output(h) + + return self._normalize_latents(h) + + def _run_downsampling_path(self, h: torch.Tensor) -> torch.Tensor: + for level in range(self.num_resolutions): + stage = self.down[level] + for block_idx in range(self.num_res_blocks): + h = stage.block[block_idx](h, temb=None) + if stage.attn: + h = stage.attn[block_idx](h) + + if level != self.num_resolutions - 1: + h = stage.downsample(h) + + return h + + def _finalize_output(self, h: torch.Tensor) -> torch.Tensor: + h = self.norm_out(h) + h = self.non_linearity(h) + return self.conv_out(h) + + def _normalize_latents(self, latent_output: torch.Tensor) -> torch.Tensor: + """Normalize encoder latents using per-channel statistics.""" + means = torch.chunk(latent_output, 2, dim=1)[0] + latent_shape = AudioLatentShape( + batch=means.shape[0], + channels=means.shape[1], + frames=means.shape[2], + mel_bins=means.shape[3], + ) + latent_patched = self.patchifier.patchify(means) + latent_normalized = self.per_channel_statistics.normalize(latent_patched) + return self.patchifier.unpatchify(latent_normalized, latent_shape) + + +# ============================================================================= +# Audio Decoder +# ============================================================================= + + +class AudioDecoder(nn.Module): + """ + Symmetric decoder that reconstructs audio spectrograms from latent features. + """ + + def __init__( + self, + *, + ch: int, + out_ch: int, + ch_mult: Tuple[int, ...] = (1, 2, 4, 8), + num_res_blocks: int, + attn_resolutions: Set[int], + resolution: int, + z_channels: int, + norm_type: NormType = NormType.GROUP, + causality_axis: CausalityAxis = CausalityAxis.WIDTH, + dropout: float = 0.0, + mid_block_add_attention: bool = True, + sample_rate: int = 16000, + mel_hop_length: int = 160, + is_causal: bool = True, + mel_bins: int | None = None, + ) -> None: + super().__init__() + + # Internal behavioural defaults + resamp_with_conv = True + attn_type = AttentionType.VANILLA + + # Per-channel statistics for denormalizing latents + self.per_channel_statistics = PerChannelStatistics(latent_channels=ch) + self.sample_rate = sample_rate + self.mel_hop_length = mel_hop_length + self.is_causal = is_causal + self.mel_bins = mel_bins + self.patchifier = AudioPatchifier( + patch_size=1, + audio_latent_downsample_factor=LATENT_DOWNSAMPLE_FACTOR, + sample_rate=sample_rate, + hop_length=mel_hop_length, + is_causal=is_causal, + ) + + self.ch = ch + self.temb_ch = 0 + self.num_resolutions = len(ch_mult) + self.num_res_blocks = num_res_blocks + self.resolution = resolution + self.out_ch = out_ch + self.give_pre_end = False + self.tanh_out = False + self.norm_type = norm_type + self.z_channels = z_channels + self.channel_multipliers = ch_mult + self.attn_resolutions = attn_resolutions + self.causality_axis = causality_axis + self.attn_type = attn_type + + base_block_channels = ch * self.channel_multipliers[-1] + base_resolution = resolution // (2 ** (self.num_resolutions - 1)) + self.z_shape = (1, z_channels, base_resolution, base_resolution) + + self.conv_in = make_conv2d( + z_channels, base_block_channels, kernel_size=3, stride=1, causality_axis=self.causality_axis + ) + self.non_linearity = nn.SiLU() + + self.mid = build_mid_block( + channels=base_block_channels, + temb_channels=self.temb_ch, + dropout=dropout, + norm_type=self.norm_type, + causality_axis=self.causality_axis, + attn_type=self.attn_type, + add_attention=mid_block_add_attention, + ) + + self.up, final_block_channels = build_upsampling_path( + ch=ch, + ch_mult=ch_mult, + num_resolutions=self.num_resolutions, + num_res_blocks=num_res_blocks, + resolution=resolution, + temb_channels=self.temb_ch, + dropout=dropout, + norm_type=self.norm_type, + causality_axis=self.causality_axis, + attn_type=self.attn_type, + attn_resolutions=attn_resolutions, + resamp_with_conv=resamp_with_conv, + initial_block_channels=base_block_channels, + ) + + self.norm_out = build_normalization_layer(final_block_channels, normtype=self.norm_type) + self.conv_out = make_conv2d( + final_block_channels, out_ch, kernel_size=3, stride=1, causality_axis=self.causality_axis + ) + + def forward(self, sample: torch.Tensor) -> torch.Tensor: + """ + Decode latent features back to audio spectrograms. + Args: + sample: Encoded latent representation of shape (batch, channels, frames, mel_bins) + Returns: + Reconstructed audio spectrogram of shape (batch, channels, time, frequency) + """ + sample, target_shape = self._denormalize_latents(sample) + + h = self.conv_in(sample) + h = run_mid_block(self.mid, h) + h = self._run_upsampling_path(h) + h = self._finalize_output(h) + + return self._adjust_output_shape(h, target_shape) + + def _denormalize_latents( + self, sample: torch.Tensor + ) -> Tuple[torch.Tensor, AudioLatentShape]: + latent_shape = AudioLatentShape( + batch=sample.shape[0], + channels=sample.shape[1], + frames=sample.shape[2], + mel_bins=sample.shape[3], + ) + + sample_patched = self.patchifier.patchify(sample) + sample_denormalized = self.per_channel_statistics.un_normalize(sample_patched) + sample = self.patchifier.unpatchify(sample_denormalized, latent_shape) + + target_frames = latent_shape.frames * LATENT_DOWNSAMPLE_FACTOR + if self.causality_axis != CausalityAxis.NONE: + target_frames = max(target_frames - (LATENT_DOWNSAMPLE_FACTOR - 1), 1) + + target_shape = AudioLatentShape( + batch=latent_shape.batch, + channels=self.out_ch, + frames=target_frames, + mel_bins=self.mel_bins if self.mel_bins is not None else latent_shape.mel_bins, + ) + + return sample, target_shape + + def _adjust_output_shape( + self, + decoded_output: torch.Tensor, + target_shape: AudioLatentShape, + ) -> torch.Tensor: + """Adjust output shape to match target dimensions for variable-length audio.""" + _, _, current_time, current_freq = decoded_output.shape + target_channels = target_shape.channels + target_time = target_shape.frames + target_freq = target_shape.mel_bins + + # Crop first + decoded_output = decoded_output[ + :, :target_channels, : min(current_time, target_time), : min(current_freq, target_freq) + ] + + # Calculate padding needed + time_padding_needed = target_time - decoded_output.shape[2] + freq_padding_needed = target_freq - decoded_output.shape[3] + + # Apply padding if needed + if time_padding_needed > 0 or freq_padding_needed > 0: + padding = ( + 0, + max(freq_padding_needed, 0), + 0, + max(time_padding_needed, 0), + ) + decoded_output = F.pad(decoded_output, padding) + + # Final safety crop + decoded_output = decoded_output[:, :target_channels, :target_time, :target_freq] + + return decoded_output + + def _run_upsampling_path(self, h: torch.Tensor) -> torch.Tensor: + for level in reversed(range(self.num_resolutions)): + stage = self.up[level] + for block_idx, block in enumerate(stage.block): + h = block(h, temb=None) + if stage.attn: + h = stage.attn[block_idx](h) + + if level != 0 and hasattr(stage, "upsample"): + h = stage.upsample(h) + + return h + + def _finalize_output(self, h: torch.Tensor) -> torch.Tensor: + if self.give_pre_end: + return h + + h = self.norm_out(h) + h = self.non_linearity(h) + h = self.conv_out(h) + return torch.tanh(h) if self.tanh_out else h + + +# ============================================================================= +# Vocoder +# ============================================================================= + + +class Vocoder(nn.Module): + """ + Vocoder model for synthesizing audio from Mel spectrograms. + """ + + def __init__( + self, + resblock_kernel_sizes: List[int] | None = None, + upsample_rates: List[int] | None = None, + upsample_kernel_sizes: List[int] | None = None, + resblock_dilation_sizes: List[List[int]] | None = None, + upsample_initial_channel: int = 1024, + stereo: bool = True, + resblock: str = "1", + output_sample_rate: int = 24000, + ): + super().__init__() + + # Initialize default values + if resblock_kernel_sizes is None: + resblock_kernel_sizes = [3, 7, 11] + if upsample_rates is None: + upsample_rates = [6, 5, 2, 2, 2] + if upsample_kernel_sizes is None: + upsample_kernel_sizes = [16, 15, 8, 4, 4] + if resblock_dilation_sizes is None: + resblock_dilation_sizes = [[1, 3, 5], [1, 3, 5], [1, 3, 5]] + + self.output_sample_rate = output_sample_rate + self.num_kernels = len(resblock_kernel_sizes) + self.num_upsamples = len(upsample_rates) + in_channels = 128 if stereo else 64 + self.conv_pre = nn.Conv1d(in_channels, upsample_initial_channel, 7, 1, padding=3) + resblock_class = ResBlock1 if resblock == "1" else ResBlock2 + + self.ups = nn.ModuleList() + for i, (stride, kernel_size) in enumerate(zip(upsample_rates, upsample_kernel_sizes, strict=True)): + self.ups.append( + nn.ConvTranspose1d( + upsample_initial_channel // (2**i), + upsample_initial_channel // (2 ** (i + 1)), + kernel_size, + stride, + padding=(kernel_size - stride) // 2, + ) + ) + + self.resblocks = nn.ModuleList() + for i, _ in enumerate(self.ups): + ch = upsample_initial_channel // (2 ** (i + 1)) + for kernel_size, dilations in zip(resblock_kernel_sizes, resblock_dilation_sizes, strict=True): + self.resblocks.append(resblock_class(ch, kernel_size, dilations)) + + out_channels = 2 if stereo else 1 + final_channels = upsample_initial_channel // (2**self.num_upsamples) + self.conv_post = nn.Conv1d(final_channels, out_channels, 7, 1, padding=3) + + self.upsample_factor = math.prod(layer.stride[0] for layer in self.ups) + + def forward(self, x: torch.Tensor) -> torch.Tensor: + """ + Forward pass of the vocoder. + Args: + x: Input Mel spectrogram tensor of shape (batch, channels, time, mel_bins) + Returns: + Audio waveform tensor of shape (batch, out_channels, audio_length) + """ + x = x.transpose(2, 3) # (batch, channels, time, mel_bins) -> (batch, channels, mel_bins, time) + + if x.dim() == 4: # stereo + assert x.shape[1] == 2, "Input must have 2 channels for stereo" + x = einops.rearrange(x, "b s c t -> b (s c) t") + + x = self.conv_pre(x) + + for i in range(self.num_upsamples): + x = F.leaky_relu(x, LRELU_SLOPE) + x = self.ups[i](x) + start = i * self.num_kernels + end = start + self.num_kernels + + # Evaluate all resblocks and average + block_outputs = torch.stack( + [self.resblocks[idx](x) for idx in range(start, end)], + dim=0, + ) + + x = block_outputs.mean(dim=0) + + x = self.conv_post(F.leaky_relu(x)) + return torch.tanh(x) + + +# ============================================================================= +# Configurators +# ============================================================================= + + +class AudioEncoderConfigurator: + """Factory for AudioEncoder from checkpoint config.""" + + @classmethod + def from_config(cls, config: dict) -> AudioEncoder: + audio_vae_cfg = config.get("audio_vae", {}) + model_cfg = audio_vae_cfg.get("model", {}) + model_params = model_cfg.get("params", {}) + ddconfig = model_params.get("ddconfig", {}) + preprocessing_cfg = audio_vae_cfg.get("preprocessing", {}) + stft_cfg = preprocessing_cfg.get("stft", {}) + mel_cfg = preprocessing_cfg.get("mel", {}) + variables_cfg = audio_vae_cfg.get("variables", {}) + + sample_rate = model_params.get("sampling_rate", 16000) + mel_hop_length = stft_cfg.get("hop_length", 160) + n_fft = stft_cfg.get("filter_length", 1024) + is_causal = stft_cfg.get("causal", True) + mel_bins = ddconfig.get("mel_bins") or mel_cfg.get("n_mel_channels") or variables_cfg.get("mel_bins") + + return AudioEncoder( + ch=ddconfig.get("ch", 128), + ch_mult=tuple(ddconfig.get("ch_mult", (1, 2, 4))), + num_res_blocks=ddconfig.get("num_res_blocks", 2), + attn_resolutions=set(ddconfig.get("attn_resolutions", {8, 16, 32})), + resolution=ddconfig.get("resolution", 256), + z_channels=ddconfig.get("z_channels", 8), + double_z=ddconfig.get("double_z", True), + dropout=ddconfig.get("dropout", 0.0), + resamp_with_conv=ddconfig.get("resamp_with_conv", True), + in_channels=ddconfig.get("in_channels", 2), + attn_type=AttentionType(ddconfig.get("attn_type", "vanilla")), + mid_block_add_attention=ddconfig.get("mid_block_add_attention", True), + norm_type=NormType(ddconfig.get("norm_type", "pixel")), + causality_axis=CausalityAxis(ddconfig.get("causality_axis", "height")), + sample_rate=sample_rate, + mel_hop_length=mel_hop_length, + n_fft=n_fft, + is_causal=is_causal, + mel_bins=mel_bins, + ) + + +class AudioDecoderConfigurator: + """Factory for AudioDecoder from checkpoint config.""" + + @classmethod + def from_config(cls, config: dict) -> AudioDecoder: + audio_vae_cfg = config.get("audio_vae", {}) + model_cfg = audio_vae_cfg.get("model", {}) + model_params = model_cfg.get("params", {}) + ddconfig = model_params.get("ddconfig", {}) + preprocessing_cfg = audio_vae_cfg.get("preprocessing", {}) + stft_cfg = preprocessing_cfg.get("stft", {}) + mel_cfg = preprocessing_cfg.get("mel", {}) + variables_cfg = audio_vae_cfg.get("variables", {}) + + sample_rate = model_params.get("sampling_rate", 16000) + mel_hop_length = stft_cfg.get("hop_length", 160) + is_causal = stft_cfg.get("causal", True) + mel_bins = ddconfig.get("mel_bins") or mel_cfg.get("n_mel_channels") or variables_cfg.get("mel_bins") + + return AudioDecoder( + ch=ddconfig.get("ch", 128), + out_ch=ddconfig.get("out_ch", 2), + ch_mult=tuple(ddconfig.get("ch_mult", (1, 2, 4))), + num_res_blocks=ddconfig.get("num_res_blocks", 2), + attn_resolutions=set(ddconfig.get("attn_resolutions", {8, 16, 32})), + resolution=ddconfig.get("resolution", 256), + z_channels=ddconfig.get("z_channels", 8), + norm_type=NormType(ddconfig.get("norm_type", "pixel")), + causality_axis=CausalityAxis(ddconfig.get("causality_axis", "height")), + dropout=ddconfig.get("dropout", 0.0), + mid_block_add_attention=ddconfig.get("mid_block_add_attention", True), + sample_rate=sample_rate, + mel_hop_length=mel_hop_length, + is_causal=is_causal, + mel_bins=mel_bins, + ) + + +class VocoderConfigurator: + """Factory for Vocoder from checkpoint config.""" + + @classmethod + def from_config(cls, config: dict) -> Vocoder: + vocoder_cfg = config.get("vocoder", {}) + return Vocoder( + resblock_kernel_sizes=vocoder_cfg.get("resblock_kernel_sizes", [3, 7, 11]), + upsample_rates=vocoder_cfg.get("upsample_rates", [6, 5, 2, 2, 2]), + upsample_kernel_sizes=vocoder_cfg.get("upsample_kernel_sizes", [16, 15, 8, 4, 4]), + resblock_dilation_sizes=vocoder_cfg.get("resblock_dilation_sizes", [[1, 3, 5], [1, 3, 5], [1, 3, 5]]), + upsample_initial_channel=vocoder_cfg.get("upsample_initial_channel", 1024), + stereo=vocoder_cfg.get("stereo", True), + resblock=vocoder_cfg.get("resblock", "1"), + output_sample_rate=vocoder_cfg.get("output_sample_rate", 24000), + ) + + +# ============================================================================= +# Public API Wrappers +# ============================================================================= + + +class LTX2AudioEncoder(nn.Module): + """Public wrapper for Audio Encoder with native FastVideo implementation.""" + + def __init__(self, config: dict[str, Any]): + super().__init__() + self.model: AudioEncoder = AudioEncoderConfigurator.from_config(config) + + def forward(self, spectrogram: torch.Tensor) -> torch.Tensor: + return self.model(spectrogram) + + +class LTX2AudioDecoder(nn.Module): + """Public wrapper for Audio Decoder with native FastVideo implementation.""" + + def __init__(self, config: dict[str, Any]): + super().__init__() + self.model: AudioDecoder = AudioDecoderConfigurator.from_config(config) + + def forward(self, sample: torch.Tensor) -> torch.Tensor: + return self.model(sample) + + +class LTX2Vocoder(nn.Module): + """Public wrapper for Vocoder with native FastVideo implementation.""" + + def __init__(self, config: dict[str, Any]): + super().__init__() + self.model: Vocoder = VocoderConfigurator.from_config(config) + + def forward(self, spectrogram: torch.Tensor) -> torch.Tensor: + return self.model(spectrogram) + + +def decode_audio( + latent: torch.Tensor, audio_decoder: AudioDecoder, vocoder: Vocoder +) -> torch.Tensor: + """ + Decode an audio latent representation using the provided audio decoder and vocoder. + """ + decoded_audio = audio_decoder(latent) + decoded_audio = vocoder(decoded_audio).squeeze(0).float() + return decoded_audio diff --git a/fastvideo/models/dits/ltx2.py b/fastvideo/models/dits/ltx2.py new file mode 100644 index 000000000..b8e0aecc7 --- /dev/null +++ b/fastvideo/models/dits/ltx2.py @@ -0,0 +1,1800 @@ +# SPDX-License-Identifier: Apache-2.0 +""" +LTX-2 transformer implementation +""" + +from dataclasses import dataclass, replace +from enum import Enum +import functools +import math +import os +from pathlib import Path +from typing import Any, Optional, Tuple, Callable + +import numpy as np + +import torch +import torch.nn as nn +from einops import rearrange, repeat + +from fastvideo.attention.backends.sdpa import SDPAMetadata +from fastvideo.attention.layer import LocalAttention +from fastvideo.configs.models.dits import LTX2VideoConfig +from fastvideo.forward_context import get_forward_context, set_forward_context +from fastvideo.models.dits.base import CachableDiT +from fastvideo.platforms import AttentionBackendEnum + + +def get_timestep_embedding( + timesteps: torch.Tensor, + embedding_dim: int, + flip_sin_to_cos: bool = False, + downscale_freq_shift: float = 1, + scale: float = 1, + max_period: int = 10000, +) -> torch.Tensor: + """Sinusoidal timestep embedding used by LTX-2 AdaLN.""" + if len(timesteps.shape) != 1: + raise ValueError("Timesteps should be a 1d-array") + + half_dim = embedding_dim // 2 + exponent = -math.log(max_period) * torch.arange(start=0, end=half_dim, dtype=torch.float32, device=timesteps.device) + exponent = exponent / (half_dim - downscale_freq_shift) + + emb = torch.exp(exponent) + emb = timesteps[:, None].float() * emb[None, :] + emb = scale * emb + emb = torch.cat([torch.sin(emb), torch.cos(emb)], dim=-1) + + if flip_sin_to_cos: + emb = torch.cat([emb[:, half_dim:], emb[:, :half_dim]], dim=-1) + + if embedding_dim % 2 == 1: + emb = torch.nn.functional.pad(emb, (0, 1, 0, 0)) + return emb + + +class TimestepEmbedding(torch.nn.Module): + """Two-layer MLP to project timestep embeddings.""" + def __init__( + self, + in_channels: int, + time_embed_dim: int, + out_dim: int | None = None, + post_act_fn: str | None = None, + cond_proj_dim: int | None = None, + sample_proj_bias: bool = True, + ): + super().__init__() + self.linear_1 = torch.nn.Linear(in_channels, time_embed_dim, sample_proj_bias) + self.cond_proj = torch.nn.Linear(cond_proj_dim, in_channels, bias=False) if cond_proj_dim is not None else None + self.act = torch.nn.SiLU() + time_embed_dim_out = out_dim if out_dim is not None else time_embed_dim + self.linear_2 = torch.nn.Linear(time_embed_dim, time_embed_dim_out, sample_proj_bias) + self.post_act = None if post_act_fn is None else None + + def forward(self, sample: torch.Tensor, condition: torch.Tensor | None = None) -> torch.Tensor: + if condition is not None: + sample = sample + self.cond_proj(condition) + sample = self.linear_1(sample) + if self.act is not None: + sample = self.act(sample) + sample = self.linear_2(sample) + if self.post_act is not None: + sample = self.post_act(sample) + return sample + + +class Timesteps(torch.nn.Module): + """Sinusoidal timestep embedding wrapper with scaling knobs.""" + def __init__(self, num_channels: int, flip_sin_to_cos: bool, downscale_freq_shift: float, scale: int = 1): + super().__init__() + self.num_channels = num_channels + self.flip_sin_to_cos = flip_sin_to_cos + self.downscale_freq_shift = downscale_freq_shift + self.scale = scale + + def forward(self, timesteps: torch.Tensor) -> torch.Tensor: + return get_timestep_embedding( + timesteps, + self.num_channels, + flip_sin_to_cos=self.flip_sin_to_cos, + downscale_freq_shift=self.downscale_freq_shift, + scale=self.scale, + ) + + +class PixArtAlphaCombinedTimestepSizeEmbeddings(torch.nn.Module): + """PixArt-Alpha timestep embedding used by LTX-2 AdaLN.""" + def __init__(self, embedding_dim: int, size_emb_dim: int): + super().__init__() + self.outdim = size_emb_dim + self.time_proj = Timesteps(num_channels=256, flip_sin_to_cos=True, downscale_freq_shift=0) + self.timestep_embedder = TimestepEmbedding(in_channels=256, time_embed_dim=embedding_dim) + + def forward(self, timestep: torch.Tensor, hidden_dtype: torch.dtype) -> torch.Tensor: + timesteps_proj = self.time_proj(timestep) + timesteps_emb = self.timestep_embedder(timesteps_proj.to(dtype=hidden_dtype)) + return timesteps_emb + + +class AdaLayerNormSingle(torch.nn.Module): + """AdaLN-single modulation that emits scale/shift/gates for LTX-2.""" + def __init__(self, embedding_dim: int, embedding_coefficient: int = 6): + super().__init__() + self.emb = PixArtAlphaCombinedTimestepSizeEmbeddings( + embedding_dim, + size_emb_dim=embedding_dim // 3, + ) + self.silu = torch.nn.SiLU() + self.linear = torch.nn.Linear(embedding_dim, embedding_coefficient * embedding_dim, bias=True) + + def forward( + self, + timestep: torch.Tensor, + hidden_dtype: Optional[torch.dtype] = None, + ) -> Tuple[torch.Tensor, torch.Tensor]: + embedded_timestep = self.emb(timestep, hidden_dtype=hidden_dtype) + return self.linear(self.silu(embedded_timestep)), embedded_timestep + + +class PixArtAlphaTextProjection(torch.nn.Module): + """Caption projection MLP used by LTX-2.""" + def __init__(self, in_features: int, hidden_size: int, out_features: int | None = None, act_fn: str = "gelu_tanh"): + super().__init__() + if out_features is None: + out_features = hidden_size + self.linear_1 = torch.nn.Linear(in_features=in_features, out_features=hidden_size, bias=True) + if act_fn == "gelu_tanh": + self.act_1 = torch.nn.GELU(approximate="tanh") + elif act_fn == "silu": + self.act_1 = torch.nn.SiLU() + else: + raise ValueError(f"Unknown activation function: {act_fn}") + self.linear_2 = torch.nn.Linear(in_features=hidden_size, out_features=out_features, bias=True) + + def forward(self, caption: torch.Tensor) -> torch.Tensor: + hidden_states = self.linear_1(caption) + hidden_states = self.act_1(hidden_states) + hidden_states = self.linear_2(hidden_states) + return hidden_states + + +class GELUApprox(nn.Module): + """Linear + tanh-approximate GELU used by LTX-2 FFN.""" + def __init__(self, in_features: int, out_features: int): + super().__init__() + self.proj = nn.Linear(in_features, out_features) + self.act = nn.GELU(approximate="tanh") + + def forward(self, x: torch.Tensor) -> torch.Tensor: + return self.act(self.proj(x)) + + +class FeedForward(nn.Module): + """LTX-2 FFN: GELUApprox -> Identity -> Linear.""" + def __init__(self, dim: int, dim_out: int, mult: int = 4) -> None: + super().__init__() + inner_dim = int(dim * mult) + project_in = GELUApprox(dim, inner_dim) + self.net = nn.Sequential(project_in, nn.Identity(), nn.Linear(inner_dim, dim_out)) + + def forward(self, x: torch.Tensor) -> torch.Tensor: + return self.net(x) + + +class VideoLatentShape(tuple): + """Helper for (B, C, T, H, W) latent shapes.""" + @property + def batch(self) -> int: + return self[0] + + @property + def channels(self) -> int: + return self[1] + + @property + def frames(self) -> int: + return self[2] + + @property + def height(self) -> int: + return self[3] + + @property + def width(self) -> int: + return self[4] + + @staticmethod + def from_torch_shape(shape: torch.Size) -> "VideoLatentShape": + return VideoLatentShape(shape) + + def to_torch_shape(self) -> torch.Size: + return torch.Size(self) + + +class AudioLatentShape(tuple): + """Helper for (B, C, T, F) audio latent shapes.""" + + @property + def batch(self) -> int: + return self[0] + + @property + def channels(self) -> int: + return self[1] + + @property + def frames(self) -> int: + return self[2] + + @property + def mel_bins(self) -> int: + return self[3] + + def to_torch_shape(self) -> torch.Size: + return torch.Size(self) + + @staticmethod + def from_torch_shape(shape: torch.Size) -> "AudioLatentShape": + return AudioLatentShape(shape) + + @staticmethod + def from_duration( + batch: int, + duration: float, + channels: int, + mel_bins: int, + sample_rate: int, + hop_length: int, + audio_latent_downsample_factor: int, + ) -> "AudioLatentShape": + latents_per_second = float(sample_rate) / float( + hop_length) / float(audio_latent_downsample_factor) + return AudioLatentShape( + (batch, channels, round(duration * latents_per_second), mel_bins)) + + +class VideoLatentPatchifier: + """Patchify/unpatchify latent tokens for LTX-2.""" + def __init__(self, patch_size: int): + self._patch_size = (1, patch_size, patch_size) + + @property + def patch_size(self) -> Tuple[int, int, int]: + return self._patch_size + + def get_token_count(self, tgt_shape: VideoLatentShape) -> int: + return math.prod(tgt_shape.to_torch_shape()[2:]) // math.prod(self._patch_size) + + def patchify(self, latents: torch.Tensor) -> torch.Tensor: + return rearrange( + latents, + "b c (f p1) (h p2) (w p3) -> b (f h w) (c p1 p2 p3)", + p1=self._patch_size[0], + p2=self._patch_size[1], + p3=self._patch_size[2], + ) + + def unpatchify(self, latents: torch.Tensor, output_shape: VideoLatentShape) -> torch.Tensor: + patch_grid_frames = output_shape.frames // self._patch_size[0] + patch_grid_height = output_shape.height // self._patch_size[1] + patch_grid_width = output_shape.width // self._patch_size[2] + return rearrange( + latents, + "b (f h w) (c p q) -> b c f (h p) (w q)", + f=patch_grid_frames, + h=patch_grid_height, + w=patch_grid_width, + p=self._patch_size[1], + q=self._patch_size[2], + ) + + def get_patch_grid_bounds( + self, + output_shape: VideoLatentShape, + device: Optional[torch.device] = None, + ) -> torch.Tensor: + frames = output_shape.frames + height = output_shape.height + width = output_shape.width + batch_size = output_shape.batch + + grid_coords = torch.meshgrid( + torch.arange(start=0, end=frames, step=self._patch_size[0], device=device), + torch.arange(start=0, end=height, step=self._patch_size[1], device=device), + torch.arange(start=0, end=width, step=self._patch_size[2], device=device), + indexing="ij", + ) + + patch_starts = torch.stack(grid_coords, dim=0) + patch_size_delta = torch.tensor( + self._patch_size, + device=patch_starts.device, + dtype=patch_starts.dtype, + ).view(3, 1, 1, 1) + patch_ends = patch_starts + patch_size_delta + latent_coords = torch.stack((patch_starts, patch_ends), dim=-1) + latent_coords = repeat( + latent_coords, + "c f h w bounds -> b c (f h w) bounds", + b=batch_size, + bounds=2, + ) + return latent_coords + + +class AudioLatentPatchifier: + """Patchify/unpatchify audio latents and compute timing bounds.""" + + def __init__( + self, + patch_size: int, + sample_rate: int, + hop_length: int, + audio_latent_downsample_factor: int, + is_causal: bool = True, + shift: int = 0, + ) -> None: + self.hop_length = hop_length + self.sample_rate = sample_rate + self.audio_latent_downsample_factor = audio_latent_downsample_factor + self.is_causal = is_causal + self.shift = shift + self._patch_size = (1, patch_size, patch_size) + + def get_token_count(self, tgt_shape: AudioLatentShape) -> int: + return tgt_shape.frames + + def patchify(self, latents: torch.Tensor) -> torch.Tensor: + return rearrange(latents, "b c t f -> b t (c f)") + + def unpatchify( + self, + latents: torch.Tensor, + output_shape: AudioLatentShape, + ) -> torch.Tensor: + return rearrange( + latents, + "b t (c f) -> b c t f", + c=output_shape.channels, + f=output_shape.mel_bins, + ) + + def get_patch_grid_bounds( + self, + output_shape: AudioLatentShape, + device: Optional[torch.device] = None, + ) -> torch.Tensor: + start_timings = self._get_audio_latent_time_in_sec( + self.shift, + output_shape.frames + self.shift, + torch.float32, + device, + ) + start_timings = start_timings.unsqueeze(0).expand(output_shape.batch, + -1).unsqueeze(1) + + end_timings = self._get_audio_latent_time_in_sec( + self.shift + 1, + output_shape.frames + self.shift + 1, + torch.float32, + device, + ) + end_timings = end_timings.unsqueeze(0).expand(output_shape.batch, + -1).unsqueeze(1) + + return torch.stack([start_timings, end_timings], dim=-1) + + def _get_audio_latent_time_in_sec( + self, + start_latent: int, + end_latent: int, + dtype: torch.dtype, + device: Optional[torch.device], + ) -> torch.Tensor: + resolved_device = device or torch.device("cpu") + audio_latent_frame = torch.arange( + start_latent, end_latent, dtype=dtype, device=resolved_device) + audio_mel_frame = audio_latent_frame * self.audio_latent_downsample_factor + if self.is_causal: + causal_offset = 1 + audio_mel_frame = ( + audio_mel_frame + causal_offset - + self.audio_latent_downsample_factor).clamp(min=0) + return audio_mel_frame * self.hop_length / self.sample_rate + + +def _get_pixel_coords( + latent_coords: torch.Tensor, + scale_factors: tuple[int, int, int], + fps: float | None, + causal_fix: bool = True, +) -> torch.Tensor: + broadcast_shape = [1] * latent_coords.ndim + broadcast_shape[1] = -1 + scale_tensor = torch.tensor( + scale_factors, + device=latent_coords.device, + dtype=torch.float32, + ).view(*broadcast_shape) + pixel_coords = latent_coords.to(torch.float32) * scale_tensor + if causal_fix: + pixel_coords[:, 0, ...] = ( + pixel_coords[:, 0, ...] + 1 - scale_factors[0]).clamp(min=0) + if fps: + pixel_coords[:, 0, ...] = pixel_coords[:, 0, ...] / fps + return pixel_coords + + +def _to_denoised( + sample: torch.Tensor, + velocity: torch.Tensor, + sigma: torch.Tensor, + calc_dtype: torch.dtype = torch.float32, +) -> torch.Tensor: + if isinstance(sigma, torch.Tensor): + sigma = sigma.to(calc_dtype) + while sigma.ndim < sample.ndim: + sigma = sigma.unsqueeze(-1) + return (sample.to(calc_dtype) - velocity.to(calc_dtype) * sigma).to(sample.dtype) + + +def _debug_block_log_line(message: str) -> None: + if os.getenv("LTX2_PIPELINE_DEBUG_LOG", "0") != "1": + return + log_path = os.getenv("LTX2_PIPELINE_DEBUG_PATH", "") + if not log_path: + return + log_dir = os.path.dirname(log_path) + if log_dir: + os.makedirs(log_dir, exist_ok=True) + with open(log_path, "a", encoding="utf-8") as f: + f.write(message + "\n") + + +def _debug_transformer_args(prefix: str, args: "TransformerArgs | None") -> None: + if os.getenv("LTX2_PIPELINE_DEBUG_LOG", "0") != "1" or args is None: + return + pe_cos, pe_sin = args.positional_embeddings + cross_cos = None + cross_sin = None + if args.cross_positional_embeddings is not None: + cross_cos, cross_sin = args.cross_positional_embeddings + mask = args.context_mask + if mask is None: + mask_summary = "mask=None" + else: + finite = torch.isfinite(mask) + finite_sum = mask[finite].sum().item() if finite.any() else 0.0 + mask_summary = ( + f"mask_min={mask.min().item():.6f} " + f"mask_max={mask.max().item():.6f} " + f"mask_finite_sum={finite_sum:.6f} " + f"mask_finite_count={finite.sum().item()}" + ) + _debug_block_log_line( + f"{prefix}:x_sum={args.x.float().sum().item():.6f} " + f"context_sum={args.context.float().sum().item():.6f} " + f"t_sum={args.timesteps.float().sum().item():.6f} " + f"emb_sum={args.embedded_timestep.float().sum().item():.6f} " + f"pe_cos_sum={pe_cos.float().sum().item():.6f} " + f"pe_sin_sum={pe_sin.float().sum().item():.6f} " + f"cross_pe_cos_sum={(cross_cos.float().sum().item() if cross_cos is not None else 0.0):.6f} " + f"cross_pe_sin_sum={(cross_sin.float().sum().item() if cross_sin is not None else 0.0):.6f} " + f"{mask_summary}" + ) + + +class LTXRopeType(Enum): + """LTX-2 rotary variants (interleaved vs split).""" + INTERLEAVED = "interleaved" + SPLIT = "split" + + +DEFAULT_LTX2_SCALE_FACTORS = (8, 32, 32) +DEFAULT_LTX2_AUDIO_CHANNELS = 8 +DEFAULT_LTX2_AUDIO_MEL_BINS = 16 +DEFAULT_LTX2_AUDIO_SAMPLE_RATE = 16000 +DEFAULT_LTX2_AUDIO_HOP_LENGTH = 160 +DEFAULT_LTX2_AUDIO_DOWNSAMPLE = 4 +# The vocoder upsamples from mel spectrograms (16kHz sample rate) to 24kHz audio +DEFAULT_LTX2_VOCODER_OUTPUT_SAMPLE_RATE = 24000 + + +def apply_ltx_rotary_emb( + input_tensor: torch.Tensor, + freqs_cis: tuple[torch.Tensor, torch.Tensor], + rope_type: LTXRopeType = LTXRopeType.INTERLEAVED, +) -> torch.Tensor: + """Apply LTX-2 rotary embeddings to a tensor.""" + if rope_type == LTXRopeType.INTERLEAVED: + return _apply_ltx_interleaved_rotary_emb(input_tensor, *freqs_cis) + if rope_type == LTXRopeType.SPLIT: + return _apply_ltx_split_rotary_emb(input_tensor, *freqs_cis) + raise ValueError(f"Invalid rope type: {rope_type}") + + +def _apply_ltx_interleaved_rotary_emb( + input_tensor: torch.Tensor, cos_freqs: torch.Tensor, sin_freqs: torch.Tensor +) -> torch.Tensor: + t_dup = rearrange(input_tensor, "... (d r) -> ... d r", r=2) + t1, t2 = t_dup.unbind(dim=-1) + t_dup = torch.stack((-t2, t1), dim=-1) + input_tensor_rot = rearrange(t_dup, "... d r -> ... (d r)") + return input_tensor * cos_freqs + input_tensor_rot * sin_freqs + + +def _apply_ltx_split_rotary_emb( + input_tensor: torch.Tensor, cos_freqs: torch.Tensor, sin_freqs: torch.Tensor +) -> torch.Tensor: + needs_reshape = False + if input_tensor.ndim != 4 and cos_freqs.ndim == 4: + b, h, t, _ = cos_freqs.shape + input_tensor = input_tensor.reshape(b, t, h, -1).swapaxes(1, 2) + needs_reshape = True + + split_input = rearrange(input_tensor, "... (d r) -> ... d r", d=2) + first_half_input = split_input[..., :1, :] + second_half_input = split_input[..., 1:, :] + + output = split_input * cos_freqs.unsqueeze(-2) + first_half_output = output[..., :1, :] + second_half_output = output[..., 1:, :] + + first_half_output.addcmul_(-sin_freqs.unsqueeze(-2), second_half_input) + second_half_output.addcmul_(sin_freqs.unsqueeze(-2), first_half_input) + + output = rearrange(output, "... d r -> ... (d r)") + if needs_reshape: + output = output.swapaxes(1, 2).reshape(b, t, -1) + return output + + +@functools.lru_cache(maxsize=5) +def generate_ltx_freq_grid_np( + positional_embedding_theta: float, positional_embedding_max_pos_count: int, inner_dim: int +) -> torch.Tensor: + """Generate LTX-2 rotary frequencies with high-precision numpy.""" + theta = positional_embedding_theta + start = 1 + end = theta + n_elem = 2 * positional_embedding_max_pos_count + pow_indices = np.power( + theta, + np.linspace( + np.log(start) / np.log(theta), + np.log(end) / np.log(theta), + inner_dim // n_elem, + dtype=np.float64, + ), + ) + return torch.tensor(pow_indices * math.pi / 2, dtype=torch.float32) + + +@functools.lru_cache(maxsize=5) +def generate_ltx_freq_grid_pytorch( + positional_embedding_theta: float, positional_embedding_max_pos_count: int, inner_dim: int +) -> torch.Tensor: + """Generate LTX-2 rotary frequencies in torch for speed.""" + theta = positional_embedding_theta + start = 1 + end = theta + n_elem = 2 * positional_embedding_max_pos_count + indices = theta ** ( + torch.linspace( + math.log(start, theta), + math.log(end, theta), + inner_dim // n_elem, + dtype=torch.float32, + ) + ) + indices = indices.to(dtype=torch.float32) + return indices * math.pi / 2 + + +def _ltx_get_fractional_positions(indices_grid: torch.Tensor, max_pos: list[int]) -> torch.Tensor: + n_pos_dims = indices_grid.shape[1] + if n_pos_dims != len(max_pos): + raise ValueError( + f"Number of position dimensions ({n_pos_dims}) must match max_pos length ({len(max_pos)})" + ) + return torch.stack( + [indices_grid[:, i] / max_pos[i] for i in range(n_pos_dims)], + dim=-1, + ) + + +def _ltx_generate_freqs( + indices: torch.Tensor, indices_grid: torch.Tensor, max_pos: list[int], use_middle_indices_grid: bool +) -> torch.Tensor: + if use_middle_indices_grid: + indices_grid_start, indices_grid_end = indices_grid[..., 0], indices_grid[..., 1] + indices_grid = (indices_grid_start + indices_grid_end) / 2.0 + elif len(indices_grid.shape) == 4: + indices_grid = indices_grid[..., 0] + + fractional_positions = _ltx_get_fractional_positions(indices_grid, max_pos) + indices = indices.to(device=fractional_positions.device) + freqs = (indices * (fractional_positions.unsqueeze(-1) * 2 - 1)).transpose(-1, -2).flatten(2) + return freqs + + +def _ltx_split_freqs_cis( + freqs: torch.Tensor, pad_size: int, num_attention_heads: int +) -> tuple[torch.Tensor, torch.Tensor]: + cos_freq = freqs.cos() + sin_freq = freqs.sin() + + if pad_size != 0: + cos_padding = torch.ones_like(cos_freq[:, :, :pad_size]) + sin_padding = torch.zeros_like(sin_freq[:, :, :pad_size]) + cos_freq = torch.concatenate([cos_padding, cos_freq], axis=-1) + sin_freq = torch.concatenate([sin_padding, sin_freq], axis=-1) + + b = cos_freq.shape[0] + t = cos_freq.shape[1] + cos_freq = cos_freq.reshape(b, t, num_attention_heads, -1) + sin_freq = sin_freq.reshape(b, t, num_attention_heads, -1) + cos_freq = torch.swapaxes(cos_freq, 1, 2) + sin_freq = torch.swapaxes(sin_freq, 1, 2) + return cos_freq, sin_freq + + +def _ltx_interleaved_freqs_cis(freqs: torch.Tensor, pad_size: int) -> tuple[torch.Tensor, torch.Tensor]: + cos_freq = freqs.cos().repeat_interleave(2, dim=-1) + sin_freq = freqs.sin().repeat_interleave(2, dim=-1) + if pad_size != 0: + cos_padding = torch.ones_like(cos_freq[:, :, :pad_size]) + sin_padding = torch.zeros_like(cos_freq[:, :, :pad_size]) + cos_freq = torch.cat([cos_padding, cos_freq], dim=-1) + sin_freq = torch.cat([sin_padding, sin_freq], dim=-1) + return cos_freq, sin_freq + + +def precompute_ltx_freqs_cis( + indices_grid: torch.Tensor, + dim: int, + out_dtype: torch.dtype, + theta: float = 10000.0, + max_pos: list[int] | None = None, + use_middle_indices_grid: bool = False, + num_attention_heads: int = 32, + rope_type: LTXRopeType = LTXRopeType.INTERLEAVED, + freq_grid_generator: Callable[[float, int, int], torch.Tensor] = generate_ltx_freq_grid_pytorch, +) -> tuple[torch.Tensor, torch.Tensor]: + """Precompute LTX-2 rotary cos/sin grids for (t, x, y) positions.""" + if max_pos is None: + max_pos = [20, 2048, 2048] + + indices = freq_grid_generator(theta, indices_grid.shape[1], dim) + freqs = _ltx_generate_freqs(indices, indices_grid, max_pos, use_middle_indices_grid) + + if rope_type == LTXRopeType.SPLIT: + expected_freqs = dim // 2 + current_freqs = freqs.shape[-1] + pad_size = expected_freqs - current_freqs + cos_freq, sin_freq = _ltx_split_freqs_cis(freqs, pad_size, num_attention_heads) + else: + n_elem = 2 * indices_grid.shape[1] + cos_freq, sin_freq = _ltx_interleaved_freqs_cis(freqs, dim % n_elem) + return cos_freq.to(out_dtype), sin_freq.to(out_dtype) + + +@dataclass(frozen=True) +class TransformerArgs: + """Pack transformer inputs for LTX-2 blocks.""" + x: torch.Tensor + context: torch.Tensor + context_mask: torch.Tensor | None + timesteps: torch.Tensor + embedded_timestep: torch.Tensor + positional_embeddings: torch.Tensor + cross_positional_embeddings: torch.Tensor | None + cross_scale_shift_timestep: torch.Tensor | None + cross_gate_timestep: torch.Tensor | None + enabled: bool + + +@dataclass(frozen=True) +class Modality: + """Lightweight modality container for LTX-2 inputs.""" + enabled: bool + latent: torch.Tensor + timesteps: torch.Tensor + positions: torch.Tensor + context: torch.Tensor + context_mask: torch.Tensor | None = None + + +class TransformerArgsPreprocessor: + """Prepare LTX-2 transformer inputs (patchify, AdaLN, rope).""" + def __init__( # noqa: PLR0913 + self, + patchify_proj: torch.nn.Linear, + adaln: AdaLayerNormSingle, + caption_projection: PixArtAlphaTextProjection, + inner_dim: int, + max_pos: list[int], + num_attention_heads: int, + use_middle_indices_grid: bool, + timestep_scale_multiplier: int, + double_precision_rope: bool, + positional_embedding_theta: float, + rope_type: LTXRopeType, + ) -> None: + self.patchify_proj = patchify_proj + self.adaln = adaln + self.caption_projection = caption_projection + self.inner_dim = inner_dim + self.max_pos = max_pos + self.num_attention_heads = num_attention_heads + self.use_middle_indices_grid = use_middle_indices_grid + self.timestep_scale_multiplier = timestep_scale_multiplier + self.double_precision_rope = double_precision_rope + self.positional_embedding_theta = positional_embedding_theta + self.rope_type = rope_type + + def _prepare_timestep( + self, timestep: torch.Tensor, batch_size: int, hidden_dtype: torch.dtype + ) -> tuple[torch.Tensor, torch.Tensor]: + timestep = timestep * self.timestep_scale_multiplier + timestep, embedded_timestep = self.adaln(timestep.flatten(), hidden_dtype=hidden_dtype) + timestep = timestep.view(batch_size, -1, timestep.shape[-1]) + embedded_timestep = embedded_timestep.view(batch_size, -1, embedded_timestep.shape[-1]) + return timestep, embedded_timestep + + def _prepare_context( + self, + context: torch.Tensor, + x: torch.Tensor, + attention_mask: torch.Tensor | None = None, + ) -> tuple[torch.Tensor, torch.Tensor | None]: + batch_size = x.shape[0] + if context.device != x.device: + context = context.to(x.device) + if attention_mask is not None and attention_mask.device != x.device: + attention_mask = attention_mask.to(x.device) + context = self.caption_projection(context) + context = context.view(batch_size, -1, x.shape[-1]) + return context, attention_mask + + def _prepare_attention_mask(self, attention_mask: torch.Tensor | None, x_dtype: torch.dtype) -> torch.Tensor | None: + if attention_mask is None or torch.is_floating_point(attention_mask): + return attention_mask + return (attention_mask - 1).to(x_dtype).reshape( + (attention_mask.shape[0], 1, -1, attention_mask.shape[-1]) + ) * torch.finfo(x_dtype).max + + def _prepare_positional_embeddings( + self, + positions: torch.Tensor, + inner_dim: int, + max_pos: list[int], + use_middle_indices_grid: bool, + num_attention_heads: int, + x_dtype: torch.dtype, + ) -> torch.Tensor: + if self.double_precision_rope: + freq_grid_generator = generate_ltx_freq_grid_np + else: + freq_grid_generator = generate_ltx_freq_grid_pytorch + return precompute_ltx_freqs_cis( + positions, + dim=inner_dim, + out_dtype=x_dtype, + theta=self.positional_embedding_theta, + max_pos=max_pos, + use_middle_indices_grid=use_middle_indices_grid, + num_attention_heads=num_attention_heads, + rope_type=self.rope_type, + freq_grid_generator=freq_grid_generator, + ) + + def prepare(self, modality: Modality) -> TransformerArgs: + x = self.patchify_proj(modality.latent) + timestep, embedded_timestep = self._prepare_timestep(modality.timesteps, x.shape[0], modality.latent.dtype) + context, attention_mask = self._prepare_context(modality.context, x, modality.context_mask) + attention_mask = self._prepare_attention_mask(attention_mask, modality.latent.dtype) + pe = self._prepare_positional_embeddings( + positions=modality.positions, + inner_dim=self.inner_dim, + max_pos=self.max_pos, + use_middle_indices_grid=self.use_middle_indices_grid, + num_attention_heads=self.num_attention_heads, + x_dtype=modality.latent.dtype, + ) + return TransformerArgs( + x=x, + context=context, + context_mask=attention_mask, + timesteps=timestep, + embedded_timestep=embedded_timestep, + positional_embeddings=pe, + cross_positional_embeddings=None, + cross_scale_shift_timestep=None, + cross_gate_timestep=None, + enabled=modality.enabled, + ) + + +class MultiModalTransformerArgsPreprocessor: + """Prepare transformer args for audio/video cross-attention paths.""" + + def __init__( # noqa: PLR0913 + self, + patchify_proj: torch.nn.Linear, + adaln: AdaLayerNormSingle, + caption_projection: PixArtAlphaTextProjection, + cross_scale_shift_adaln: AdaLayerNormSingle, + cross_gate_adaln: AdaLayerNormSingle, + inner_dim: int, + max_pos: list[int], + num_attention_heads: int, + cross_pe_max_pos: int, + use_middle_indices_grid: bool, + audio_cross_attention_dim: int, + timestep_scale_multiplier: int, + double_precision_rope: bool, + positional_embedding_theta: float, + rope_type: LTXRopeType, + av_ca_timestep_scale_multiplier: int, + ) -> None: + self.simple_preprocessor = TransformerArgsPreprocessor( + patchify_proj=patchify_proj, + adaln=adaln, + caption_projection=caption_projection, + inner_dim=inner_dim, + max_pos=max_pos, + num_attention_heads=num_attention_heads, + use_middle_indices_grid=use_middle_indices_grid, + timestep_scale_multiplier=timestep_scale_multiplier, + double_precision_rope=double_precision_rope, + positional_embedding_theta=positional_embedding_theta, + rope_type=rope_type, + ) + self.cross_scale_shift_adaln = cross_scale_shift_adaln + self.cross_gate_adaln = cross_gate_adaln + self.cross_pe_max_pos = cross_pe_max_pos + self.audio_cross_attention_dim = audio_cross_attention_dim + self.av_ca_timestep_scale_multiplier = av_ca_timestep_scale_multiplier + + def prepare(self, modality: Modality) -> TransformerArgs: + transformer_args = self.simple_preprocessor.prepare(modality) + cross_pe = self.simple_preprocessor._prepare_positional_embeddings( + positions=modality.positions[:, 0:1, :], + inner_dim=self.audio_cross_attention_dim, + max_pos=[self.cross_pe_max_pos], + use_middle_indices_grid=True, + num_attention_heads=self.simple_preprocessor.num_attention_heads, + x_dtype=modality.latent.dtype, + ) + + cross_scale_shift_timestep, cross_gate_timestep = self._prepare_cross_attention_timestep( + timestep=modality.timesteps, + timestep_scale_multiplier=self.simple_preprocessor.timestep_scale_multiplier, + batch_size=transformer_args.x.shape[0], + hidden_dtype=modality.latent.dtype, + ) + + return replace( + transformer_args, + cross_positional_embeddings=cross_pe, + cross_scale_shift_timestep=cross_scale_shift_timestep, + cross_gate_timestep=cross_gate_timestep, + ) + + def _prepare_cross_attention_timestep( + self, + timestep: torch.Tensor, + timestep_scale_multiplier: int, + batch_size: int, + hidden_dtype: torch.dtype, + ) -> tuple[torch.Tensor, torch.Tensor]: + timestep = timestep * timestep_scale_multiplier + + av_ca_factor = self.av_ca_timestep_scale_multiplier / timestep_scale_multiplier + + scale_shift_timestep, _ = self.cross_scale_shift_adaln( + timestep.flatten(), + hidden_dtype=hidden_dtype, + ) + scale_shift_timestep = scale_shift_timestep.view(batch_size, -1, scale_shift_timestep.shape[-1]) + gate_noise_timestep, _ = self.cross_gate_adaln( + timestep.flatten() * av_ca_factor, + hidden_dtype=hidden_dtype, + ) + gate_noise_timestep = gate_noise_timestep.view(batch_size, -1, gate_noise_timestep.shape[-1]) + + return scale_shift_timestep, gate_noise_timestep + + +@dataclass +class TransformerConfig: + """Attention/FFN dims for LTX-2 transformer blocks.""" + dim: int + heads: int + d_head: int + context_dim: int + + +class LTXSelfAttention(nn.Module): + """LTX-2 attention block with RMSNorm + FastVideo LocalAttention.""" + def __init__( + self, + query_dim: int, + context_dim: int | None, + heads: int, + dim_head: int, + norm_eps: float, + rope_type: LTXRopeType, + supported_attention_backends: tuple[AttentionBackendEnum, ...], + ) -> None: + super().__init__() + inner_dim = dim_head * heads + context_dim = query_dim if context_dim is None else context_dim + + self.heads = heads + self.dim_head = dim_head + self.rope_type = rope_type + + self.q_norm = torch.nn.RMSNorm(inner_dim, eps=norm_eps) + self.k_norm = torch.nn.RMSNorm(inner_dim, eps=norm_eps) + self.to_q = nn.Linear(query_dim, inner_dim, bias=True) + self.to_k = nn.Linear(context_dim, inner_dim, bias=True) + self.to_v = nn.Linear(context_dim, inner_dim, bias=True) + self.to_out = nn.Sequential(nn.Linear(inner_dim, query_dim, bias=True), nn.Identity()) + + self.attn = LocalAttention( + num_heads=heads, + head_size=dim_head, + dropout_rate=0, + softmax_scale=None, + causal=False, + supported_attention_backends=supported_attention_backends, + ) + self.attn_masked = LocalAttention( + num_heads=heads, + head_size=dim_head, + dropout_rate=0, + softmax_scale=None, + causal=False, + supported_attention_backends=(AttentionBackendEnum.TORCH_SDPA,), + ) + + def forward( + self, + x: torch.Tensor, + context: torch.Tensor | None = None, + mask: torch.Tensor | None = None, + pe: tuple[torch.Tensor, torch.Tensor] | None = None, + k_pe: tuple[torch.Tensor, torch.Tensor] | None = None, + ) -> torch.Tensor: + q = self.to_q(x) + context = x if context is None else context + k = self.to_k(context) + v = self.to_v(context) + + q = self.q_norm(q) + k = self.k_norm(k) + + if pe is not None: + q = apply_ltx_rotary_emb(q, pe, self.rope_type) + k = apply_ltx_rotary_emb(k, pe if k_pe is None else k_pe, self.rope_type) + + b, q_len, _ = q.shape + k_len = k.shape[1] + q = q.view(b, q_len, self.heads, self.dim_head) + k = k.view(b, k_len, self.heads, self.dim_head) + v = v.view(b, k_len, self.heads, self.dim_head) + if mask is not None: + if mask.ndim == 2: + mask = mask.unsqueeze(0) + if mask.ndim == 3: + mask = mask.unsqueeze(1) + try: + forward_ctx = get_forward_context() + current_timestep = forward_ctx.current_timestep + forward_batch = forward_ctx.forward_batch + except AssertionError: + current_timestep = 0 + forward_batch = None + attn_metadata = SDPAMetadata( + current_timestep=current_timestep, + attn_mask=mask, + ) + with set_forward_context( + current_timestep=current_timestep, + attn_metadata=attn_metadata, + forward_batch=forward_batch, + ): + out = self.attn_masked(q, k, v) + else: + out = self.attn(q, k, v) + out = out.reshape(b, q_len, -1) + return self.to_out(out) + + +class BasicAVTransformerBlock(torch.nn.Module): + """LTX-2 transformer block (audio/video + cross attention + FFN).""" + + def __init__( + self, + idx: int, + video: TransformerConfig | None = None, + audio: TransformerConfig | None = None, + rope_type: LTXRopeType = LTXRopeType.INTERLEAVED, + norm_eps: float = 1e-6, + ): + super().__init__() + self.idx = idx + + if video is not None: + self.attn1 = LTXSelfAttention( + query_dim=video.dim, + context_dim=None, + heads=video.heads, + dim_head=video.d_head, + norm_eps=norm_eps, + rope_type=rope_type, + supported_attention_backends=(AttentionBackendEnum.FLASH_ATTN, AttentionBackendEnum.TORCH_SDPA), + ) + self.attn2 = LTXSelfAttention( + query_dim=video.dim, + context_dim=video.context_dim, + heads=video.heads, + dim_head=video.d_head, + norm_eps=norm_eps, + rope_type=rope_type, + supported_attention_backends=(AttentionBackendEnum.FLASH_ATTN, AttentionBackendEnum.TORCH_SDPA), + ) + self.ff = FeedForward(video.dim, dim_out=video.dim) + self.scale_shift_table = torch.nn.Parameter(torch.empty(6, video.dim)) + + if audio is not None: + self.audio_attn1 = LTXSelfAttention( + query_dim=audio.dim, + context_dim=None, + heads=audio.heads, + dim_head=audio.d_head, + norm_eps=norm_eps, + rope_type=rope_type, + supported_attention_backends=(AttentionBackendEnum.FLASH_ATTN, AttentionBackendEnum.TORCH_SDPA), + ) + self.audio_attn2 = LTXSelfAttention( + query_dim=audio.dim, + context_dim=audio.context_dim, + heads=audio.heads, + dim_head=audio.d_head, + norm_eps=norm_eps, + rope_type=rope_type, + supported_attention_backends=(AttentionBackendEnum.FLASH_ATTN, AttentionBackendEnum.TORCH_SDPA), + ) + self.audio_ff = FeedForward(audio.dim, dim_out=audio.dim) + self.audio_scale_shift_table = torch.nn.Parameter(torch.empty(6, audio.dim)) + + if audio is not None and video is not None: + self.audio_to_video_attn = LTXSelfAttention( + query_dim=video.dim, + context_dim=audio.dim, + heads=audio.heads, + dim_head=audio.d_head, + norm_eps=norm_eps, + rope_type=rope_type, + supported_attention_backends=(AttentionBackendEnum.FLASH_ATTN, AttentionBackendEnum.TORCH_SDPA), + ) + self.video_to_audio_attn = LTXSelfAttention( + query_dim=audio.dim, + context_dim=video.dim, + heads=audio.heads, + dim_head=audio.d_head, + norm_eps=norm_eps, + rope_type=rope_type, + supported_attention_backends=(AttentionBackendEnum.FLASH_ATTN, AttentionBackendEnum.TORCH_SDPA), + ) + self.scale_shift_table_a2v_ca_audio = torch.nn.Parameter(torch.empty(5, audio.dim)) + self.scale_shift_table_a2v_ca_video = torch.nn.Parameter(torch.empty(5, video.dim)) + + self.norm_eps = norm_eps + + def get_ada_values( + self, scale_shift_table: torch.Tensor, batch_size: int, timestep: torch.Tensor, indices: slice + ) -> tuple[torch.Tensor, ...]: + num_ada_params = scale_shift_table.shape[0] + ada_values = ( + scale_shift_table[indices].unsqueeze(0).unsqueeze(0).to(device=timestep.device, dtype=timestep.dtype) + + timestep.reshape(batch_size, timestep.shape[1], num_ada_params, -1)[:, :, indices, :] + ).unbind(dim=2) + return ada_values + + def get_av_ca_ada_values( + self, + scale_shift_table: torch.Tensor, + batch_size: int, + scale_shift_timestep: torch.Tensor, + gate_timestep: torch.Tensor, + num_scale_shift_values: int = 4, + ) -> tuple[torch.Tensor, torch.Tensor, torch.Tensor, torch.Tensor, torch.Tensor]: + scale_shift_ada_values = self.get_ada_values( + scale_shift_table[:num_scale_shift_values, :], batch_size, scale_shift_timestep, slice(None, None) + ) + gate_ada_values = self.get_ada_values( + scale_shift_table[num_scale_shift_values:, :], batch_size, gate_timestep, slice(None, None) + ) + + scale_shift_chunks = [t.squeeze(2) for t in scale_shift_ada_values] + gate_ada_values = [t.squeeze(2) for t in gate_ada_values] + + return (*scale_shift_chunks, *gate_ada_values) + + def forward( + self, + video: TransformerArgs | None, + audio: TransformerArgs | None, + ) -> tuple[TransformerArgs | None, TransformerArgs | None]: + vx = video.x if video is not None else None + ax = audio.x if audio is not None else None + + run_vx = video is not None and video.enabled and vx.numel() > 0 + run_ax = audio is not None and audio.enabled and ax.numel() > 0 + run_a2v = run_vx and run_ax + run_v2a = run_ax and run_vx + + if run_vx: + vshift_msa, vscale_msa, vgate_msa = self.get_ada_values( + self.scale_shift_table, vx.shape[0], video.timesteps, slice(0, 3) + ) + norm_vx = torch.nn.functional.rms_norm(vx, (vx.shape[-1],), eps=self.norm_eps) * (1 + vscale_msa) + vshift_msa + vx = vx + self.attn1(norm_vx, pe=video.positional_embeddings) * vgate_msa + vx = vx + self.attn2( + torch.nn.functional.rms_norm(vx, (vx.shape[-1],), eps=self.norm_eps), + context=video.context, + mask=video.context_mask, + ) + + if run_ax: + ashift_msa, ascale_msa, agate_msa = self.get_ada_values( + self.audio_scale_shift_table, ax.shape[0], audio.timesteps, slice(0, 3) + ) + norm_ax = torch.nn.functional.rms_norm(ax, (ax.shape[-1],), eps=self.norm_eps) * (1 + ascale_msa) + ashift_msa + ax = ax + self.audio_attn1(norm_ax, pe=audio.positional_embeddings) * agate_msa + ax = ax + self.audio_attn2( + torch.nn.functional.rms_norm(ax, (ax.shape[-1],), eps=self.norm_eps), + context=audio.context, + mask=audio.context_mask, + ) + + if run_a2v or run_v2a: + vx_norm3 = torch.nn.functional.rms_norm(vx, (vx.shape[-1],), eps=self.norm_eps) + ax_norm3 = torch.nn.functional.rms_norm(ax, (ax.shape[-1],), eps=self.norm_eps) + + ( + scale_ca_audio_hidden_states_a2v, + shift_ca_audio_hidden_states_a2v, + scale_ca_audio_hidden_states_v2a, + shift_ca_audio_hidden_states_v2a, + gate_out_v2a, + ) = self.get_av_ca_ada_values( + self.scale_shift_table_a2v_ca_audio, + ax.shape[0], + audio.cross_scale_shift_timestep, + audio.cross_gate_timestep, + ) + + ( + scale_ca_video_hidden_states_a2v, + shift_ca_video_hidden_states_a2v, + scale_ca_video_hidden_states_v2a, + shift_ca_video_hidden_states_v2a, + gate_out_a2v, + ) = self.get_av_ca_ada_values( + self.scale_shift_table_a2v_ca_video, + vx.shape[0], + video.cross_scale_shift_timestep, + video.cross_gate_timestep, + ) + + if run_a2v: + vx_scaled = vx_norm3 * (1 + scale_ca_video_hidden_states_a2v) + shift_ca_video_hidden_states_a2v + ax_scaled = ax_norm3 * (1 + scale_ca_audio_hidden_states_a2v) + shift_ca_audio_hidden_states_a2v + vx = vx + ( + self.audio_to_video_attn( + vx_scaled, + context=ax_scaled, + pe=video.cross_positional_embeddings, + k_pe=audio.cross_positional_embeddings, + ) + * gate_out_a2v + ) + + if run_v2a: + ax_scaled = ax_norm3 * (1 + scale_ca_audio_hidden_states_v2a) + shift_ca_audio_hidden_states_v2a + vx_scaled = vx_norm3 * (1 + scale_ca_video_hidden_states_v2a) + shift_ca_video_hidden_states_v2a + ax = ax + ( + self.video_to_audio_attn( + ax_scaled, + context=vx_scaled, + pe=audio.cross_positional_embeddings, + k_pe=video.cross_positional_embeddings, + ) + * gate_out_v2a + ) + + if run_vx: + vshift_mlp, vscale_mlp, vgate_mlp = self.get_ada_values( + self.scale_shift_table, vx.shape[0], video.timesteps, slice(3, None) + ) + vx_scaled = torch.nn.functional.rms_norm(vx, (vx.shape[-1],), eps=self.norm_eps) * (1 + vscale_mlp) + vshift_mlp + vx = vx + self.ff(vx_scaled) * vgate_mlp + + if run_ax: + ashift_mlp, ascale_mlp, agate_mlp = self.get_ada_values( + self.audio_scale_shift_table, ax.shape[0], audio.timesteps, slice(3, None) + ) + ax_scaled = torch.nn.functional.rms_norm(ax, (ax.shape[-1],), eps=self.norm_eps) * (1 + ascale_mlp) + ashift_mlp + ax = ax + self.audio_ff(ax_scaled) * agate_mlp + + if os.getenv("LTX2_PIPELINE_DEBUG_LOG", "0") == "1": + video_sum = vx.float().sum().item() if vx is not None else 0.0 + audio_sum = ax.float().sum().item() if ax is not None else 0.0 + _debug_block_log_line( + f"fastvideo:block={self.idx}:video_sum={video_sum:.6f} " + f"audio_sum={audio_sum:.6f}" + ) + + return ( + replace(video, x=vx) if video is not None else None, + replace(audio, x=ax) if audio is not None else None, + ) + + +class LTXModelType(Enum): + """Model type flags for LTX-2.""" + AudioVideo = "ltx av model" + VideoOnly = "ltx video only model" + AudioOnly = "ltx audio only model" + + def is_video_enabled(self) -> bool: + return self in (LTXModelType.AudioVideo, LTXModelType.VideoOnly) + + def is_audio_enabled(self) -> bool: + return self in (LTXModelType.AudioVideo, LTXModelType.AudioOnly) + + +class LTXModel(torch.nn.Module): + """Core LTX-2 transformer stack for audio/video latents.""" + + def __init__( # noqa: PLR0913 + self, + *, + model_type: LTXModelType = LTXModelType.AudioVideo, + num_attention_heads: int = 32, + attention_head_dim: int = 128, + in_channels: int = 128, + out_channels: int = 128, + num_layers: int = 48, + cross_attention_dim: int = 4096, + norm_eps: float = 1e-06, + caption_channels: int = 3840, + positional_embedding_theta: float = 10000.0, + positional_embedding_max_pos: list[int] | None = None, + timestep_scale_multiplier: int = 1000, + use_middle_indices_grid: bool = True, + audio_num_attention_heads: int = 32, + audio_attention_head_dim: int = 64, + audio_in_channels: int = 128, + audio_out_channels: int = 128, + audio_cross_attention_dim: int = 2048, + audio_positional_embedding_max_pos: list[int] | None = None, + av_ca_timestep_scale_multiplier: int = 1, + rope_type: LTXRopeType = LTXRopeType.INTERLEAVED, + double_precision_rope: bool = False, + ): + super().__init__() + self._enable_gradient_checkpointing = False + self.use_middle_indices_grid = use_middle_indices_grid + self.rope_type = rope_type + self.double_precision_rope = double_precision_rope + self.timestep_scale_multiplier = timestep_scale_multiplier + self.positional_embedding_theta = positional_embedding_theta + self.model_type = model_type + cross_pe_max_pos = None + + if model_type.is_video_enabled(): + if positional_embedding_max_pos is None: + positional_embedding_max_pos = [20, 2048, 2048] + self.positional_embedding_max_pos = positional_embedding_max_pos + self.num_attention_heads = num_attention_heads + self.inner_dim = num_attention_heads * attention_head_dim + self._init_video( + in_channels=in_channels, + out_channels=out_channels, + caption_channels=caption_channels, + norm_eps=norm_eps, + ) + + if model_type.is_audio_enabled(): + if audio_positional_embedding_max_pos is None: + audio_positional_embedding_max_pos = [20] + self.audio_positional_embedding_max_pos = audio_positional_embedding_max_pos + self.audio_num_attention_heads = audio_num_attention_heads + self.audio_inner_dim = self.audio_num_attention_heads * audio_attention_head_dim + self._init_audio( + in_channels=audio_in_channels, + out_channels=audio_out_channels, + caption_channels=caption_channels, + norm_eps=norm_eps, + ) + + if model_type.is_video_enabled() and model_type.is_audio_enabled(): + cross_pe_max_pos = max(self.positional_embedding_max_pos[0], self.audio_positional_embedding_max_pos[0]) + self.av_ca_timestep_scale_multiplier = av_ca_timestep_scale_multiplier + self.audio_cross_attention_dim = audio_cross_attention_dim + self._init_audio_video(num_scale_shift_values=4) + + self._init_preprocessors(cross_pe_max_pos) + self._init_transformer_blocks( + num_layers=num_layers, + attention_head_dim=attention_head_dim if model_type.is_video_enabled() else 0, + cross_attention_dim=cross_attention_dim, + audio_attention_head_dim=audio_attention_head_dim if model_type.is_audio_enabled() else 0, + audio_cross_attention_dim=audio_cross_attention_dim, + norm_eps=norm_eps, + ) + + def _init_video( + self, + in_channels: int, + out_channels: int, + caption_channels: int, + norm_eps: float, + ) -> None: + self.patchify_proj = torch.nn.Linear(in_channels, self.inner_dim, bias=True) + self.adaln_single = AdaLayerNormSingle(self.inner_dim) + self.caption_projection = PixArtAlphaTextProjection( + in_features=caption_channels, + hidden_size=self.inner_dim, + ) + self.scale_shift_table = torch.nn.Parameter(torch.empty(2, self.inner_dim)) + self.norm_out = torch.nn.LayerNorm(self.inner_dim, elementwise_affine=False, eps=norm_eps) + self.proj_out = torch.nn.Linear(self.inner_dim, out_channels) + + def _init_audio( + self, + in_channels: int, + out_channels: int, + caption_channels: int, + norm_eps: float, + ) -> None: + self.audio_patchify_proj = torch.nn.Linear(in_channels, self.audio_inner_dim, bias=True) + self.audio_adaln_single = AdaLayerNormSingle(self.audio_inner_dim) + self.audio_caption_projection = PixArtAlphaTextProjection( + in_features=caption_channels, + hidden_size=self.audio_inner_dim, + ) + self.audio_scale_shift_table = torch.nn.Parameter(torch.empty(2, self.audio_inner_dim)) + self.audio_norm_out = torch.nn.LayerNorm(self.audio_inner_dim, elementwise_affine=False, eps=norm_eps) + self.audio_proj_out = torch.nn.Linear(self.audio_inner_dim, out_channels) + + def _init_audio_video(self, num_scale_shift_values: int) -> None: + self.av_ca_video_scale_shift_adaln_single = AdaLayerNormSingle( + self.inner_dim, + embedding_coefficient=num_scale_shift_values, + ) + self.av_ca_audio_scale_shift_adaln_single = AdaLayerNormSingle( + self.audio_inner_dim, + embedding_coefficient=num_scale_shift_values, + ) + self.av_ca_a2v_gate_adaln_single = AdaLayerNormSingle( + self.inner_dim, + embedding_coefficient=1, + ) + self.av_ca_v2a_gate_adaln_single = AdaLayerNormSingle( + self.audio_inner_dim, + embedding_coefficient=1, + ) + + def _init_preprocessors(self, cross_pe_max_pos: int | None = None) -> None: + if self.model_type.is_video_enabled() and self.model_type.is_audio_enabled(): + self.video_args_preprocessor = MultiModalTransformerArgsPreprocessor( + patchify_proj=self.patchify_proj, + adaln=self.adaln_single, + caption_projection=self.caption_projection, + cross_scale_shift_adaln=self.av_ca_video_scale_shift_adaln_single, + cross_gate_adaln=self.av_ca_a2v_gate_adaln_single, + inner_dim=self.inner_dim, + max_pos=self.positional_embedding_max_pos, + num_attention_heads=self.num_attention_heads, + cross_pe_max_pos=cross_pe_max_pos, + use_middle_indices_grid=self.use_middle_indices_grid, + audio_cross_attention_dim=self.audio_cross_attention_dim, + timestep_scale_multiplier=self.timestep_scale_multiplier, + double_precision_rope=self.double_precision_rope, + positional_embedding_theta=self.positional_embedding_theta, + rope_type=self.rope_type, + av_ca_timestep_scale_multiplier=self.av_ca_timestep_scale_multiplier, + ) + self.audio_args_preprocessor = MultiModalTransformerArgsPreprocessor( + patchify_proj=self.audio_patchify_proj, + adaln=self.audio_adaln_single, + caption_projection=self.audio_caption_projection, + cross_scale_shift_adaln=self.av_ca_audio_scale_shift_adaln_single, + cross_gate_adaln=self.av_ca_v2a_gate_adaln_single, + inner_dim=self.audio_inner_dim, + max_pos=self.audio_positional_embedding_max_pos, + num_attention_heads=self.audio_num_attention_heads, + cross_pe_max_pos=cross_pe_max_pos, + use_middle_indices_grid=self.use_middle_indices_grid, + audio_cross_attention_dim=self.audio_cross_attention_dim, + timestep_scale_multiplier=self.timestep_scale_multiplier, + double_precision_rope=self.double_precision_rope, + positional_embedding_theta=self.positional_embedding_theta, + rope_type=self.rope_type, + av_ca_timestep_scale_multiplier=self.av_ca_timestep_scale_multiplier, + ) + elif self.model_type.is_video_enabled(): + self.video_args_preprocessor = TransformerArgsPreprocessor( + patchify_proj=self.patchify_proj, + adaln=self.adaln_single, + caption_projection=self.caption_projection, + inner_dim=self.inner_dim, + max_pos=self.positional_embedding_max_pos, + num_attention_heads=self.num_attention_heads, + use_middle_indices_grid=self.use_middle_indices_grid, + timestep_scale_multiplier=self.timestep_scale_multiplier, + double_precision_rope=self.double_precision_rope, + positional_embedding_theta=self.positional_embedding_theta, + rope_type=self.rope_type, + ) + elif self.model_type.is_audio_enabled(): + self.audio_args_preprocessor = TransformerArgsPreprocessor( + patchify_proj=self.audio_patchify_proj, + adaln=self.audio_adaln_single, + caption_projection=self.audio_caption_projection, + inner_dim=self.audio_inner_dim, + max_pos=self.audio_positional_embedding_max_pos, + num_attention_heads=self.audio_num_attention_heads, + use_middle_indices_grid=self.use_middle_indices_grid, + timestep_scale_multiplier=self.timestep_scale_multiplier, + double_precision_rope=self.double_precision_rope, + positional_embedding_theta=self.positional_embedding_theta, + rope_type=self.rope_type, + ) + + def _init_transformer_blocks( + self, + num_layers: int, + attention_head_dim: int, + cross_attention_dim: int, + audio_attention_head_dim: int, + audio_cross_attention_dim: int, + norm_eps: float, + ) -> None: + video_config = ( + TransformerConfig( + dim=self.inner_dim, + heads=self.num_attention_heads, + d_head=attention_head_dim, + context_dim=cross_attention_dim, + ) + if self.model_type.is_video_enabled() + else None + ) + audio_config = ( + TransformerConfig( + dim=self.audio_inner_dim, + heads=self.audio_num_attention_heads, + d_head=audio_attention_head_dim, + context_dim=audio_cross_attention_dim, + ) + if self.model_type.is_audio_enabled() + else None + ) + self.transformer_blocks = torch.nn.ModuleList( + [ + BasicAVTransformerBlock( + idx=idx, + video=video_config, + audio=audio_config, + rope_type=self.rope_type, + norm_eps=norm_eps, + ) + for idx in range(num_layers) + ] + ) + + def _process_transformer_blocks( + self, + video: TransformerArgs | None, + audio: TransformerArgs | None, + ) -> tuple[TransformerArgs | None, TransformerArgs | None]: + for block in self.transformer_blocks: + video, audio = block(video=video, audio=audio) + return video, audio + + def _process_output( + self, + scale_shift_table: torch.Tensor, + norm_out: torch.nn.LayerNorm, + proj_out: torch.nn.Linear, + x: torch.Tensor, + embedded_timestep: torch.Tensor, + ) -> torch.Tensor: + scale_shift_values = ( + scale_shift_table[None, None].to(device=x.device, dtype=x.dtype) + embedded_timestep[:, :, None] + ) + shift, scale = scale_shift_values[:, :, 0], scale_shift_values[:, :, 1] + x = norm_out(x) + x = x * (1 + scale) + shift + x = proj_out(x) + return x + + def forward( + self, + video: Modality | None, + audio: Modality | None, + ) -> tuple[torch.Tensor | None, torch.Tensor | None]: + if os.getenv("LTX2_PIPELINE_DEBUG_LOG", "0") == "1": + _debug_block_log_line( + "fastvideo:patchify_proj" + f":video_w_sum={self.patchify_proj.weight.float().sum().item():.6f} " + f"video_b_sum={self.patchify_proj.bias.float().sum().item():.6f} " + f"audio_w_sum={self.audio_patchify_proj.weight.float().sum().item():.6f} " + f"audio_b_sum={self.audio_patchify_proj.bias.float().sum().item():.6f}" + ) + if not self.model_type.is_video_enabled() and video is not None: + raise ValueError("Video is not enabled for this model") + if not self.model_type.is_audio_enabled() and audio is not None: + raise ValueError("Audio is not enabled for this model") + + video_args = self.video_args_preprocessor.prepare(video) if video is not None else None + audio_args = self.audio_args_preprocessor.prepare(audio) if audio is not None else None + _debug_transformer_args("fastvideo:prep_video", video_args) + _debug_transformer_args("fastvideo:prep_audio", audio_args) + video_out, audio_out = self._process_transformer_blocks(video_args, audio_args) + + vx = ( + self._process_output( + self.scale_shift_table, self.norm_out, self.proj_out, video_out.x, video_out.embedded_timestep + ) + if video_out is not None + else None + ) + ax = ( + self._process_output( + self.audio_scale_shift_table, + self.audio_norm_out, + self.audio_proj_out, + audio_out.x, + audio_out.embedded_timestep, + ) + if audio_out is not None + else None + ) + return vx, ax + + +class LTX2Transformer3DModel(CachableDiT): + """ + LTX-2 transformer using native FastVideo LTX-2 modules. + """ + + param_names_mapping = LTX2VideoConfig().param_names_mapping + reverse_param_names_mapping = LTX2VideoConfig().reverse_param_names_mapping + lora_param_names_mapping = LTX2VideoConfig().lora_param_names_mapping + + def __init__(self, config: LTX2VideoConfig, hf_config: dict[str, Any]): + super().__init__(config=config, hf_config=hf_config) + + arch = config.arch_config + + model_type = LTXModelType.AudioVideo + self.model = LTXModel( + model_type=model_type, + num_attention_heads=arch.num_attention_heads, + attention_head_dim=arch.attention_head_dim, + in_channels=arch.in_channels, + out_channels=arch.out_channels, + num_layers=arch.num_layers, + cross_attention_dim=arch.cross_attention_dim, + norm_eps=arch.norm_eps, + caption_channels=arch.caption_channels, + positional_embedding_theta=arch.positional_embedding_theta, + positional_embedding_max_pos=arch.positional_embedding_max_pos, + timestep_scale_multiplier=arch.timestep_scale_multiplier, + use_middle_indices_grid=arch.use_middle_indices_grid, + rope_type=LTXRopeType(arch.rope_type), + double_precision_rope=arch.double_precision_rope, + audio_num_attention_heads=arch.audio_num_attention_heads, + audio_attention_head_dim=arch.audio_attention_head_dim, + audio_in_channels=arch.audio_in_channels, + audio_out_channels=arch.audio_out_channels, + audio_cross_attention_dim=arch.audio_cross_attention_dim, + audio_positional_embedding_max_pos=arch.audio_positional_embedding_max_pos, + av_ca_timestep_scale_multiplier=arch.av_ca_timestep_scale_multiplier, + ) + + self.patchifier = VideoLatentPatchifier(patch_size=arch.patch_size[1]) + self.audio_patchifier = AudioLatentPatchifier( + patch_size=DEFAULT_LTX2_AUDIO_MEL_BINS, + sample_rate=DEFAULT_LTX2_AUDIO_SAMPLE_RATE, + hop_length=DEFAULT_LTX2_AUDIO_HOP_LENGTH, + audio_latent_downsample_factor=DEFAULT_LTX2_AUDIO_DOWNSAMPLE, + is_causal=True, + shift=0, + ) + + self.hidden_size = arch.num_attention_heads * arch.attention_head_dim + self.num_attention_heads = arch.num_attention_heads + self.num_channels_latents = arch.num_channels_latents + + if os.getenv("LTX2_DEBUG_DETAIL", "0") == "1": + detail_path = os.getenv("LTX2_PIPELINE_DEBUG_DETAIL_PATH", "") + if detail_path: + self._attach_debug_detail_hooks(detail_path) + + def _attach_debug_detail_hooks(self, log_path: str) -> None: + path = Path(log_path) + path.parent.mkdir(parents=True, exist_ok=True) + if path.exists(): + path.unlink() + + def _format_sum(tensor: torch.Tensor | None) -> str: + if tensor is None: + return "None" + return f"{tensor.float().sum().item():.6f}" + + def _hook_factory(block_idx: int, name: str): + def _hook(_module, _inputs, outputs): # noqa: ANN001 + if isinstance(outputs, tuple): + out = outputs[0] + else: + out = outputs + out_sum = _format_sum(out if torch.is_tensor(out) else None) + with path.open("a", encoding="utf-8") as f: + f.write(f"fastvideo:{block_idx}:{name}:out_sum={out_sum}\n") + return _hook + + for block in self.model.transformer_blocks: + idx = block.idx + for name in ( + "attn1", + "attn2", + "ff", + "audio_attn1", + "audio_attn2", + "audio_ff", + "audio_to_video_attn", + "video_to_audio_attn", + ): + if hasattr(block, name): + getattr(block, name).register_forward_hook( + _hook_factory(idx, name)) + + def _output_hook(label: str): + def _hook(_module, _inputs, outputs): # noqa: ANN001 + out = outputs[0] if isinstance(outputs, tuple) else outputs + out_sum = _format_sum(out if torch.is_tensor(out) else None) + with path.open("a", encoding="utf-8") as f: + f.write(f"fastvideo:output:{label}:out_sum={out_sum}\n") + return _hook + + if hasattr(self.model, "proj_out"): + self.model.proj_out.register_forward_hook(_output_hook("proj_out")) + if hasattr(self.model, "audio_proj_out"): + self.model.audio_proj_out.register_forward_hook( + _output_hook("audio_proj_out")) + + def forward( + self, + hidden_states: torch.Tensor, + encoder_hidden_states: torch.Tensor | list[torch.Tensor], + timestep: torch.LongTensor, + encoder_hidden_states_image: torch.Tensor | list[torch.Tensor] | None = None, + encoder_attention_mask: torch.Tensor | None = None, + guidance=None, + audio_hidden_states: torch.Tensor | None = None, + audio_encoder_hidden_states: torch.Tensor | None = None, + audio_timestep: torch.Tensor | None = None, + audio_encoder_attention_mask: torch.Tensor | None = None, + **kwargs, + ) -> torch.Tensor: + if isinstance(encoder_hidden_states, list): + encoder_hidden_states = encoder_hidden_states[0] + + video_shape = VideoLatentShape.from_torch_shape(hidden_states.shape) + positions = self.patchifier.get_patch_grid_bounds( + video_shape, device=hidden_states.device + ) + fps = None + try: + forward_ctx = get_forward_context() + except AssertionError: + forward_ctx = None + if forward_ctx is not None and forward_ctx.forward_batch is not None: + fps_value = forward_ctx.forward_batch.fps + if isinstance(fps_value, list): + fps_value = fps_value[0] if fps_value else None + if fps_value is not None: + fps = float(fps_value) + positions = _get_pixel_coords( + positions, + DEFAULT_LTX2_SCALE_FACTORS, + fps=fps, + causal_fix=True, + ).to(hidden_states.dtype) + latents = self.patchifier.patchify(hidden_states) + video_modality = Modality( + enabled=True, + latent=latents, + timesteps=timestep, + positions=positions, + context=encoder_hidden_states, + context_mask=encoder_attention_mask, + ) + if os.getenv("LTX2_PIPELINE_DEBUG_LOG", "0") == "1": + video_head = latents.flatten()[:8].float().tolist() + video_flat = latents.float().flatten() + video_checksum = (video_flat * torch.arange(video_flat.numel(), device=video_flat.device)).sum().item() + _debug_block_log_line( + "fastvideo:modality_video" + f":latent_sum={latents.float().sum().item():.6f} " + f"latent_shape={tuple(latents.shape)} " + f"positions_sum={positions.float().sum().item():.6f} " + f"positions_shape={tuple(positions.shape)} " + f"latent_head={video_head} " + f"latent_checksum={video_checksum:.6f}" + ) + audio_modality = None + audio_shape = None + if audio_hidden_states is not None and audio_encoder_hidden_states is not None and audio_timestep is not None: + audio_shape = AudioLatentShape.from_torch_shape( + audio_hidden_states.shape) + audio_positions = self.audio_patchifier.get_patch_grid_bounds( + audio_shape, device=audio_hidden_states.device) + audio_latents = self.audio_patchifier.patchify( + audio_hidden_states) + audio_modality = Modality( + enabled=True, + latent=audio_latents, + timesteps=audio_timestep, + positions=audio_positions, + context=audio_encoder_hidden_states, + context_mask=audio_encoder_attention_mask, + ) + if os.getenv("LTX2_PIPELINE_DEBUG_LOG", "0") == "1": + audio_head = audio_latents.flatten()[:8].float().tolist() + audio_flat = audio_latents.float().flatten() + audio_checksum = (audio_flat * torch.arange(audio_flat.numel(), device=audio_flat.device)).sum().item() + _debug_block_log_line( + "fastvideo:modality_audio" + f":latent_sum={audio_latents.float().sum().item():.6f} " + f"latent_shape={tuple(audio_latents.shape)} " + f"positions_sum={audio_positions.float().sum().item():.6f} " + f"positions_shape={tuple(audio_positions.shape)} " + f"latent_head={audio_head} " + f"latent_checksum={audio_checksum:.6f}" + ) + video_out, audio_out = self.model( + video=video_modality, + audio=audio_modality, + ) + if video_out is not None and video_modality is not None: + video_out = _to_denoised( + video_modality.latent, + video_out, + video_modality.timesteps, + ) + if audio_out is not None and audio_modality is not None: + audio_out = _to_denoised( + audio_modality.latent, + audio_out, + audio_modality.timesteps, + ) + video_out = self.patchifier.unpatchify( + video_out, output_shape=video_shape) + if audio_out is None or audio_shape is None: + return video_out + audio_out = self.audio_patchifier.unpatchify( + audio_out, output_shape=audio_shape) + return video_out, audio_out diff --git a/fastvideo/models/encoders/gemma.py b/fastvideo/models/encoders/gemma.py new file mode 100644 index 000000000..a279e1669 --- /dev/null +++ b/fastvideo/models/encoders/gemma.py @@ -0,0 +1,563 @@ +# SPDX-License-Identifier: Apache-2.0 +from __future__ import annotations + +from dataclasses import dataclass +import os +from typing import Iterable + +import torch +from torch import nn +from transformers import Gemma3ForConditionalGeneration + +from fastvideo.configs.models.encoders import BaseEncoderOutput, TextEncoderConfig +from fastvideo.models.encoders.base import TextEncoder +from fastvideo.models.dits.ltx2 import ( + FeedForward, + LTXRopeType, + apply_ltx_rotary_emb, + generate_ltx_freq_grid_np, + generate_ltx_freq_grid_pytorch, + precompute_ltx_freqs_cis, +) +from fastvideo.models.loader.weight_utils import default_weight_loader +from fastvideo.platforms import AttentionBackendEnum + + +def _debug_log_line(message: str) -> None: + if os.getenv("LTX2_PIPELINE_DEBUG_LOG", "0") != "1": + return + log_path = os.getenv("LTX2_PIPELINE_DEBUG_PATH", "") + if not log_path: + return + log_dir = os.path.dirname(log_path) + if log_dir: + os.makedirs(log_dir, exist_ok=True) + with open(log_path, "a", encoding="utf-8") as f: + f.write(message + "\n") + + +def _debug_gemma_log_line(message: str) -> None: + log_path = os.getenv("LTX2_FASTVIDEO_GEMMA_LOG", "") + if not log_path: + return + log_dir = os.path.dirname(log_path) + if log_dir: + os.makedirs(log_dir, exist_ok=True) + with open(log_path, "a", encoding="utf-8") as f: + f.write(message + "\n") + + +@dataclass(frozen=True) +class GemmaConnectorConfig: + num_attention_heads: int + attention_head_dim: int + num_layers: int + positional_embedding_theta: float + positional_embedding_max_pos: list[int] + rope_type: LTXRopeType + double_precision_rope: bool + num_learnable_registers: int | None + + +class GemmaFeaturesExtractorProjLinear(nn.Module): + """Linear projection that aggregates stacked Gemma hidden states.""" + + def __init__(self, in_features: int, out_features: int) -> None: + super().__init__() + self.aggregate_embed = nn.Linear(in_features, out_features, bias=False) + + def forward(self, x: torch.Tensor) -> torch.Tensor: + return self.aggregate_embed(x) + + +class _BasicTransformerBlock1D(nn.Module): + """1D transformer block for connector processing.""" + + def __init__( + self, + dim: int, + heads: int, + dim_head: int, + rope_type: LTXRopeType, + norm_eps: float = 1e-6, + ) -> None: + super().__init__() + self.attn1 = _GemmaAttention( + query_dim=dim, + context_dim=None, + heads=heads, + dim_head=dim_head, + norm_eps=norm_eps, + rope_type=rope_type, + ) + self.ff = FeedForward(dim, dim_out=dim) + self.norm_eps = norm_eps + + def forward( + self, + hidden_states: torch.Tensor, + attention_mask: torch.Tensor | None = None, + pe: tuple[torch.Tensor, torch.Tensor] | None = None, + ) -> torch.Tensor: + norm_hidden_states = torch.nn.functional.rms_norm( + hidden_states, (hidden_states.shape[-1],), eps=self.norm_eps + ) + if norm_hidden_states.ndim == 4: + norm_hidden_states = norm_hidden_states.squeeze(1) + + attn_output = self.attn1( + norm_hidden_states, + mask=attention_mask, + pe=pe, + ) + hidden_states = attn_output + hidden_states + if hidden_states.ndim == 4: + hidden_states = hidden_states.squeeze(1) + + norm_hidden_states = torch.nn.functional.rms_norm( + hidden_states, (hidden_states.shape[-1],), eps=self.norm_eps + ) + ff_output = self.ff(norm_hidden_states) + hidden_states = ff_output + hidden_states + if hidden_states.ndim == 4: + hidden_states = hidden_states.squeeze(1) + return hidden_states + + +class _GemmaAttention(nn.Module): + """Attention implementation aligned with LTX-2 text encoder.""" + + def __init__( + self, + query_dim: int, + context_dim: int | None, + heads: int, + dim_head: int, + norm_eps: float, + rope_type: LTXRopeType, + ) -> None: + super().__init__() + inner_dim = dim_head * heads + context_dim = query_dim if context_dim is None else context_dim + + self.heads = heads + self.dim_head = dim_head + self.rope_type = rope_type + + self.q_norm = torch.nn.RMSNorm(inner_dim, eps=norm_eps) + self.k_norm = torch.nn.RMSNorm(inner_dim, eps=norm_eps) + self.to_q = nn.Linear(query_dim, inner_dim, bias=True) + self.to_k = nn.Linear(context_dim, inner_dim, bias=True) + self.to_v = nn.Linear(context_dim, inner_dim, bias=True) + self.to_out = nn.Sequential(nn.Linear(inner_dim, query_dim, bias=True), nn.Identity()) + + def forward( + self, + x: torch.Tensor, + context: torch.Tensor | None = None, + mask: torch.Tensor | None = None, + pe: tuple[torch.Tensor, torch.Tensor] | None = None, + k_pe: tuple[torch.Tensor, torch.Tensor] | None = None, + ) -> torch.Tensor: + q = self.to_q(x) + context = x if context is None else context + k = self.to_k(context) + v = self.to_v(context) + + q = self.q_norm(q) + k = self.k_norm(k) + + if pe is not None: + q = apply_ltx_rotary_emb(q, pe, self.rope_type) + k = apply_ltx_rotary_emb(k, pe if k_pe is None else k_pe, self.rope_type) + + b, q_len, _ = q.shape + k_len = k.shape[1] + q = q.view(b, q_len, self.heads, self.dim_head).transpose(1, 2) + k = k.view(b, k_len, self.heads, self.dim_head).transpose(1, 2) + v = v.view(b, k_len, self.heads, self.dim_head).transpose(1, 2) + + if mask is not None: + if mask.ndim == 2: + mask = mask.unsqueeze(0) + if mask.ndim == 3: + mask = mask.unsqueeze(1) + + out = torch.nn.functional.scaled_dot_product_attention( + q, + k, + v, + attn_mask=mask, + dropout_p=0.0, + is_causal=False, + ) + out = out.transpose(1, 2).reshape(b, q_len, -1) + return self.to_out(out) + + +class Embeddings1DConnector(nn.Module): + """Transformer connector that refines Gemma embeddings for LTX-2.""" + + _supports_gradient_checkpointing = True + + def __init__(self, config: GemmaConnectorConfig) -> None: + super().__init__() + self.num_attention_heads = config.num_attention_heads + self.inner_dim = config.num_attention_heads * config.attention_head_dim + self.positional_embedding_theta = config.positional_embedding_theta + self.positional_embedding_max_pos = config.positional_embedding_max_pos + self.rope_type = config.rope_type + self.double_precision_rope = config.double_precision_rope + self.transformer_1d_blocks = nn.ModuleList( + [ + _BasicTransformerBlock1D( + dim=self.inner_dim, + heads=config.num_attention_heads, + dim_head=config.attention_head_dim, + rope_type=config.rope_type, + ) + for _ in range(config.num_layers) + ] + ) + self.num_learnable_registers = config.num_learnable_registers + if self.num_learnable_registers: + self.learnable_registers = nn.Parameter( + torch.rand( + self.num_learnable_registers, + self.inner_dim, + dtype=torch.bfloat16, + ) + * 2.0 + - 1.0 + ) + + def _replace_padded_with_learnable_registers( + self, + hidden_states: torch.Tensor, + attention_mask: torch.Tensor, + ) -> tuple[torch.Tensor, torch.Tensor]: + assert hidden_states.shape[1] % self.num_learnable_registers == 0, ( + f"Hidden states sequence length {hidden_states.shape[1]} must be divisible by " + f"num_learnable_registers {self.num_learnable_registers}." + ) + + num_registers_duplications = ( + hidden_states.shape[1] // self.num_learnable_registers + ) + learnable_registers = torch.tile( + self.learnable_registers, (num_registers_duplications, 1) + ) + attention_mask_binary = ( + attention_mask.squeeze(1).squeeze(1).unsqueeze(-1) >= -9000.0 + ).int() + + non_zero_hidden_states = hidden_states[ + :, attention_mask_binary.squeeze().bool(), : + ] + non_zero_nums = non_zero_hidden_states.shape[1] + pad_length = hidden_states.shape[1] - non_zero_nums + adjusted_hidden_states = torch.nn.functional.pad( + non_zero_hidden_states, pad=(0, 0, 0, pad_length), value=0 + ) + flipped_mask = torch.flip(attention_mask_binary, dims=[1]) + hidden_states = flipped_mask * adjusted_hidden_states + ( + 1 - flipped_mask + ) * learnable_registers + + attention_mask = torch.full_like( + attention_mask, + 0.0, + dtype=attention_mask.dtype, + device=attention_mask.device, + ) + + return hidden_states, attention_mask + + def forward( + self, + hidden_states: torch.Tensor, + attention_mask: torch.Tensor | None = None, + ) -> tuple[torch.Tensor, torch.Tensor]: + if self.num_learnable_registers: + hidden_states, attention_mask = ( + self._replace_padded_with_learnable_registers( + hidden_states, attention_mask + ) + ) + + indices_grid = torch.arange( + hidden_states.shape[1], + dtype=torch.float32, + device=hidden_states.device, + ) + indices_grid = indices_grid[None, None, :] + freq_grid_generator = ( + generate_ltx_freq_grid_np + if self.double_precision_rope + else generate_ltx_freq_grid_pytorch + ) + freqs_cis = precompute_ltx_freqs_cis( + indices_grid=indices_grid, + dim=self.inner_dim, + out_dtype=hidden_states.dtype, + theta=self.positional_embedding_theta, + max_pos=self.positional_embedding_max_pos, + num_attention_heads=self.num_attention_heads, + rope_type=self.rope_type, + freq_grid_generator=freq_grid_generator, + ) + + for block in self.transformer_1d_blocks: + hidden_states = block( + hidden_states, attention_mask=attention_mask, pe=freqs_cis + ) + + hidden_states = torch.nn.functional.rms_norm( + hidden_states, (hidden_states.shape[-1],), eps=1e-6 + ) + + return hidden_states, attention_mask + + +class LTX2GemmaTextEncoderModel(TextEncoder): + _supported_attention_backends = ( + AttentionBackendEnum.FLASH_ATTN, + AttentionBackendEnum.TORCH_SDPA, + ) + + def __init__(self, config: TextEncoderConfig) -> None: + super().__init__(config) + arch = config.arch_config + + self.feature_extractor_linear = GemmaFeaturesExtractorProjLinear( + in_features=arch.feature_extractor_in_features, + out_features=arch.feature_extractor_out_features, + ) + + connector_config = GemmaConnectorConfig( + num_attention_heads=arch.connector_num_attention_heads, + attention_head_dim=arch.connector_attention_head_dim, + num_layers=arch.connector_num_layers, + positional_embedding_theta=arch.connector_positional_embedding_theta, + positional_embedding_max_pos=arch.connector_positional_embedding_max_pos, + rope_type=LTXRopeType(arch.connector_rope_type), + double_precision_rope=arch.connector_double_precision_rope, + num_learnable_registers=arch.connector_num_learnable_registers, + ) + self.embeddings_connector = Embeddings1DConnector(connector_config) + self.audio_embeddings_connector = Embeddings1DConnector(connector_config) + + self.gemma_model_path = arch.gemma_model_path + self.gemma_dtype = arch.gemma_dtype + self.padding_side = arch.padding_side + self._gemma_model: Gemma3ForConditionalGeneration | None = None + + def named_parameters(self, prefix: str = "", recurse: bool = True): + for name, param in super().named_parameters( + prefix=prefix, recurse=recurse + ): + if name.startswith("gemma_model."): + continue + yield name, param + + @property + def gemma_model(self) -> Gemma3ForConditionalGeneration: + if self._gemma_model is None: + gemma_path = self.gemma_model_path + if not gemma_path: + raise ValueError( + "gemma_model_path must be set (expected text_encoder/gemma)." + ) + dtype = getattr(torch, self.gemma_dtype, torch.bfloat16) + self._gemma_model = Gemma3ForConditionalGeneration.from_pretrained( + gemma_path, + local_files_only=True, + torch_dtype=dtype, + ) + # Configure model-level attention implementation when using TORCH_SDPA. + # Note: torch.backends.cuda.enable_*_sdp() settings should be configured + # at application/pipeline initialization level, not here, to avoid + # unexpected side effects across the application. + if os.getenv("FASTVIDEO_ATTENTION_BACKEND") == "TORCH_SDPA": + if hasattr(self._gemma_model.config, "attn_implementation"): + self._gemma_model.config.attn_implementation = "sdpa" + if hasattr(self._gemma_model.config, "_attn_implementation"): + self._gemma_model.config._attn_implementation = "sdpa" + device = next(self.feature_extractor_linear.parameters()).device + self._gemma_model.to(device=device) + self._gemma_model.eval() + return self._gemma_model + + def _run_feature_extractor( + self, + hidden_states: tuple[torch.Tensor, ...], + attention_mask: torch.Tensor, + padding_side: str, + ) -> torch.Tensor: + encoded_text_features = torch.stack(hidden_states, dim=-1) + if os.getenv("LTX2_FASTVIDEO_GEMMA_LOG", ""): + for idx, layer in enumerate(hidden_states): + _debug_gemma_log_line( + f"fastvideo:gemma_hidden_state_{idx}" + f":sum={layer.float().sum().item():.6f}" + ) + _debug_gemma_log_line( + "fastvideo:gemma_hidden_states_stack" + f":sum={encoded_text_features.float().sum().item():.6f}" + ) + encoded_text_features_dtype = encoded_text_features.dtype + sequence_lengths = attention_mask.sum(dim=-1) + normed_text_features = _norm_and_concat_padded_batch( + encoded_text_features, sequence_lengths, padding_side=padding_side + ) + return self.feature_extractor_linear( + normed_text_features.to(encoded_text_features_dtype) + ) + + def _convert_to_additive_mask( + self, attention_mask: torch.Tensor, dtype: torch.dtype + ) -> torch.Tensor: + return (attention_mask - 1).to(dtype).reshape( + (attention_mask.shape[0], 1, -1, attention_mask.shape[-1]) + ) * torch.finfo(dtype).max + + def _run_connectors( + self, + encoded_input: torch.Tensor, + attention_mask: torch.Tensor, + ) -> tuple[torch.Tensor, torch.Tensor, torch.Tensor]: + connector_attention_mask = self._convert_to_additive_mask( + attention_mask, encoded_input.dtype + ) + encoded, encoded_connector_attention_mask = self.embeddings_connector( + encoded_input, connector_attention_mask + ) + + attention_mask = (encoded_connector_attention_mask < 0.000001).to( + torch.int64 + ) + attention_mask = attention_mask.reshape( + [encoded.shape[0], encoded.shape[1], 1] + ) + encoded = encoded * attention_mask + + encoded_for_audio, _ = self.audio_embeddings_connector( + encoded_input, connector_attention_mask + ) + + return encoded, encoded_for_audio, attention_mask.squeeze(-1) + + def forward( + self, + input_ids: torch.Tensor | None, + position_ids: torch.Tensor | None = None, + attention_mask: torch.Tensor | None = None, + inputs_embeds: torch.Tensor | None = None, + output_hidden_states: bool | None = None, + **kwargs, + ) -> BaseEncoderOutput: + if input_ids is None: + raise ValueError("input_ids is required for Gemma text encoding.") + if attention_mask is None: + attention_mask = torch.ones_like(input_ids) + + model = self.gemma_model + input_ids = input_ids.to(device=model.device) + attention_mask = attention_mask.to(device=model.device) + outputs = model( + input_ids=input_ids, + attention_mask=attention_mask, + output_hidden_states=True, + return_dict=True, + ) + + encoded_inputs = self._run_feature_extractor( + outputs.hidden_states, + attention_mask, + padding_side=self.padding_side, + ) + if os.getenv("LTX2_PIPELINE_DEBUG_LOG", "0") == "1": + _debug_log_line( + "fastvideo:gemma_feature" + f":sum={encoded_inputs.float().sum().item():.6f} " + f"shape={tuple(encoded_inputs.shape)}" + ) + video_encoding, audio_encoding, attention_mask = self._run_connectors( + encoded_inputs, attention_mask + ) + if os.getenv("LTX2_PIPELINE_DEBUG_LOG", "0") == "1": + _debug_log_line( + "fastvideo:gemma_video_encoding" + f":sum={video_encoding.float().sum().item():.6f} " + f"shape={tuple(video_encoding.shape)}" + ) + _debug_log_line( + "fastvideo:gemma_audio_encoding" + f":sum={audio_encoding.float().sum().item():.6f} " + f"shape={tuple(audio_encoding.shape)}" + ) + + hidden_states = (audio_encoding, ) if output_hidden_states else None + return BaseEncoderOutput( + last_hidden_state=video_encoding, + hidden_states=hidden_states, + attention_mask=attention_mask, + ) + + def load_weights( + self, weights: Iterable[tuple[str, torch.Tensor]] + ) -> set[str]: + params_dict = dict(self.named_parameters()) + loaded_params: set[str] = set() + for name, loaded_weight in weights: + if name == "aggregate_embed.weight": + name = "feature_extractor_linear.aggregate_embed.weight" + if name not in params_dict: + continue + param = params_dict[name] + weight_loader = getattr(param, "weight_loader", default_weight_loader) + weight_loader(param, loaded_weight) + loaded_params.add(name) + return loaded_params + + +def _norm_and_concat_padded_batch( + encoded_text: torch.Tensor, + sequence_lengths: torch.Tensor, + padding_side: str = "right", +) -> torch.Tensor: + b, t, d, l = encoded_text.shape + device = encoded_text.device + + token_indices = torch.arange(t, device=device)[None, :] + if padding_side == "right": + mask = token_indices < sequence_lengths[:, None] + elif padding_side == "left": + start_indices = t - sequence_lengths[:, None] + mask = token_indices >= start_indices + else: + raise ValueError( + f"padding_side must be 'left' or 'right', got {padding_side}" + ) + + mask = mask.reshape(b, t, 1, 1) + eps = 1e-6 + + masked = encoded_text.masked_fill(~mask, 0.0) + denom = (sequence_lengths * d).view(b, 1, 1, 1) + mean = masked.sum(dim=(1, 2), keepdim=True) / (denom + eps) + + x_min = encoded_text.masked_fill(~mask, float("inf")).amin( + dim=(1, 2), keepdim=True + ) + x_max = encoded_text.masked_fill(~mask, float("-inf")).amax( + dim=(1, 2), keepdim=True + ) + range_ = x_max - x_min + + normed = 8 * (encoded_text - mean) / (range_ + eps) + normed = normed.reshape(b, t, -1) + + mask_flattened = mask.reshape(b, t, 1).expand(-1, -1, d * l) + normed = normed.masked_fill(~mask_flattened, 0.0) + return normed diff --git a/fastvideo/models/loader/component_loader.py b/fastvideo/models/loader/component_loader.py index d61c574fa..37c542375 100644 --- a/fastvideo/models/loader/component_loader.py +++ b/fastvideo/models/loader/component_loader.py @@ -80,6 +80,9 @@ class ComponentLoader(ABC): "transformer": (TransformerLoader, "diffusers"), "transformer_2": (TransformerLoader, "diffusers"), "vae": (VAELoader, "diffusers"), + "audio_vae": (AudioDecoderLoader, "diffusers"), + "audio_decoder": (AudioDecoderLoader, "diffusers"), + "vocoder": (VocoderLoader, "diffusers"), "text_encoder": (TextEncoderLoader, "transformers"), "text_encoder_2": (TextEncoderLoader, "transformers"), "tokenizer": (TokenizerLoader, "transformers"), @@ -242,6 +245,47 @@ class TextEncoderLoader(ComponentLoader): model_config.pop("model_type", None) model_config.pop("tokenizer_class", None) model_config.pop("torch_dtype", None) + repo_root = os.path.dirname(model_path) + index_path = os.path.join(repo_root, "model_index.json") + gemma_path = "" + gemma_path_from_candidate = False + if os.path.isfile(index_path): + try: + with open(index_path, encoding="utf-8") as f: + model_index = json.load(f) + gemma_path = model_index.get("gemma_model_path", "") + except json.JSONDecodeError: + gemma_path = "" + if not gemma_path: + candidate = os.path.normpath(os.path.join(model_path, "gemma")) + if os.path.isdir(candidate): + gemma_path = candidate + gemma_path_from_candidate = True + model_config["gemma_model_path"] = gemma_path + if gemma_path and not gemma_path_from_candidate: + if not os.path.isabs(gemma_path): + model_config["gemma_model_path"] = os.path.normpath( + os.path.join(repo_root, gemma_path) + ) + transformer_config_path = os.path.join( + repo_root, "transformer", "config.json" + ) + if os.path.isfile(transformer_config_path): + try: + with open(transformer_config_path, encoding="utf-8") as f: + transformer_config = json.load(f) + if ( + "connector_double_precision_rope" not in model_config + or not model_config["connector_double_precision_rope"] + ): + if transformer_config.get("double_precision_rope") is True: + model_config["connector_double_precision_rope"] = True + if "connector_rope_type" not in model_config: + rope_type = transformer_config.get("rope_type") + if rope_type is not None: + model_config["connector_rope_type"] = rope_type + except json.JSONDecodeError: + pass logger.info("HF Model config: %s", model_config) # @TODO(Wei): Better way to handle this? @@ -489,8 +533,20 @@ class TokenizerLoader(ComponentLoader): # in v0, this was same string as encoder_name "ClipTextModel" # TODO(will): pass these tokenizer kwargs from inference args? Maybe # other method of config? - padding_size="right", ) + padding_side = None + if hasattr(fastvideo_args.pipeline_config, "text_encoder_configs"): + try: + arch_config = fastvideo_args.pipeline_config.text_encoder_configs[ + 0 + ].arch_config + padding_side = getattr(arch_config, "padding_side", None) + except Exception: + padding_side = None + if padding_side: + tokenizer.padding_side = padding_side + if tokenizer.pad_token is None and tokenizer.eos_token is not None: + tokenizer.pad_token = tokenizer.eos_token logger.info("Loaded tokenizer: %s", tokenizer.__class__.__name__) return tokenizer @@ -501,15 +557,12 @@ class VAELoader(ComponentLoader): def load(self, model_path: str, fastvideo_args: FastVideoArgs): """Load the VAE based on the model path, and inference args.""" config = get_diffusers_config(model=model_path) - class_name = config.pop("_class_name") + class_name = config.get("_class_name") assert class_name is not None, ( "Model config does not contain a _class_name attribute. Only diffusers format is supported." ) fastvideo_args.model_paths["vae"] = model_path - vae_config = fastvideo_args.pipeline_config.vae_config - vae_config.update_model_arch(config) - from fastvideo.platforms import current_platform if fastvideo_args.vae_cpu_offload: @@ -543,8 +596,29 @@ class VAELoader(ComponentLoader): vae.load_state_dict(sd, strict=False) return vae.eval() - vae_cls, _ = ModelRegistry.resolve_model_cls(class_name) - vae = vae_cls(vae_config).to(target_device) + # LTX-2 uses CausalVideoAutoencoder with nested "vae" config + if class_name == "CausalVideoAutoencoder" and "vae" in config: + vae_cls, _ = ModelRegistry.resolve_model_cls(class_name) + vae = vae_cls(config).to(target_device) + if hasattr(vae, "set_tiling_config"): + vae_config = fastvideo_args.pipeline_config.vae_config + vae.set_tiling_config( + spatial_tile_size_in_pixels=getattr( + vae_config, "ltx2_spatial_tile_size_in_pixels", 512), + spatial_tile_overlap_in_pixels=getattr( + vae_config, "ltx2_spatial_tile_overlap_in_pixels", 64), + temporal_tile_size_in_frames=getattr( + vae_config, "ltx2_temporal_tile_size_in_frames", 64), + temporal_tile_overlap_in_frames=getattr( + vae_config, + "ltx2_temporal_tile_overlap_in_frames", 24), + ) + else: + config.pop("_class_name", None) + vae_config = fastvideo_args.pipeline_config.vae_config + vae_config.update_model_arch(config) + vae_cls, _ = ModelRegistry.resolve_model_cls(class_name) + vae = vae_cls(vae_config).to(target_device) # Find all safetensors files safetensors_list = glob.glob( @@ -553,17 +627,101 @@ class VAELoader(ComponentLoader): raise ValueError(f"No safetensors files found in {model_path}") # Common case: a single `.safetensors` checkpoint file. # Some models may be sharded into multiple files; in that case we merge. - if len(safetensors_list) == 1: - loaded = safetensors_load_file(safetensors_list[0]) - else: - loaded = {} - for sf_file in safetensors_list: - loaded.update(safetensors_load_file(sf_file)) + loaded = {} + for sf_file in safetensors_list: + loaded.update(safetensors_load_file(sf_file)) + + # LTX-2 CausalVideoAutoencoder needs per_channel_statistics remapping + if class_name == "CausalVideoAutoencoder" and "vae" in config: + per_channel_prefixes = ( + "per_channel_statistics.", + "vae.per_channel_statistics.", + ) + remapped = {} + for key, tensor in loaded.items(): + remapped[key] = tensor + for prefix in per_channel_prefixes: + if key.startswith(prefix): + suffix = key[len(prefix):] + remapped.setdefault( + f"encoder.per_channel_statistics.{suffix}", + tensor, + ) + remapped.setdefault( + f"decoder.per_channel_statistics.{suffix}", + tensor, + ) + break + loaded = remapped + vae.load_state_dict(loaded, strict=False) return vae.eval() +class AudioDecoderLoader(ComponentLoader): + """Loader for LTX-2 audio decoder (audio_vae component).""" + + def load(self, model_path: str, fastvideo_args: FastVideoArgs): + config = get_diffusers_config(model=model_path) + class_name = config.pop("_class_name", None) or "LTX2AudioDecoder" + + model_cls, _ = ModelRegistry.resolve_model_cls(class_name) + target_device = get_local_torch_device() + + precision = getattr( + fastvideo_args.pipeline_config, "audio_decoder_precision", "bf16" + ) + with set_default_torch_dtype(PRECISION_TO_TYPE[precision]): + audio_decoder = model_cls(config).to(target_device) + + safetensors_list = glob.glob( + os.path.join(str(model_path), "*.safetensors") + ) + loaded: dict[str, torch.Tensor] = {} + for sf_file in safetensors_list: + loaded.update(safetensors_load_file(sf_file)) + + decoder_state = {} + for name, tensor in loaded.items(): + if name.startswith("decoder."): + decoder_state[name.replace("decoder.", "")] = tensor + elif name.startswith("per_channel_statistics."): + decoder_state[name] = tensor + + target_module = getattr(audio_decoder, "model", audio_decoder) + target_module.load_state_dict(decoder_state, strict=False) + return audio_decoder.eval() + + +class VocoderLoader(ComponentLoader): + """Loader for LTX-2 vocoder.""" + + def load(self, model_path: str, fastvideo_args: FastVideoArgs): + config = get_diffusers_config(model=model_path) + class_name = config.pop("_class_name", None) or "LTX2Vocoder" + + model_cls, _ = ModelRegistry.resolve_model_cls(class_name) + target_device = get_local_torch_device() + + precision = getattr( + fastvideo_args.pipeline_config, "vocoder_precision", "bf16" + ) + with set_default_torch_dtype(PRECISION_TO_TYPE[precision]): + vocoder = model_cls(config).to(target_device) + + safetensors_list = glob.glob( + os.path.join(str(model_path), "*.safetensors") + ) + loaded: dict[str, torch.Tensor] = {} + for sf_file in safetensors_list: + loaded.update(safetensors_load_file(sf_file)) + + target_module = getattr(vocoder, "model", vocoder) + target_module.load_state_dict(loaded, strict=False) + return vocoder.eval() + + class TransformerLoader(ComponentLoader): """Loader for transformer.""" @@ -679,7 +837,18 @@ class TransformerLoader(ComponentLoader): model = model.eval() if fastvideo_args.inference_mode and fastvideo_args.dit_layerwise_offload: - enable_layerwise_offload(model) + # Check if model has nn.ModuleList for layerwise offload compatibility + has_module_list = any( + isinstance(m, nn.ModuleList) for m in model.children() + ) + if has_module_list: + enable_layerwise_offload(model) + else: + logger.warning( + "Layerwise offload requested but model %s does not have " + "nn.ModuleList structure. Skipping layerwise offload.", + cls_name + ) return model diff --git a/fastvideo/models/registry.py b/fastvideo/models/registry.py index 4fe9b1f39..2bf86ab3a 100644 --- a/fastvideo/models/registry.py +++ b/fastvideo/models/registry.py @@ -33,6 +33,7 @@ _TEXT_TO_VIDEO_DIT_MODELS = { "Cosmos25Transformer3DModel": ("dits", "cosmos2_5", "Cosmos25Transformer3DModel"), "LongCatVideoTransformer3DModel": ("dits", "longcat_video_dit", "LongCatVideoTransformer3DModel"), # Wrapper (Phase 1) "LongCatTransformer3DModel": ("dits", "longcat", "LongCatTransformer3DModel"), # Native (Phase 2) + "LTX2Transformer3DModel": ("dits", "ltx2", "LTX2Transformer3DModel"), } _IMAGE_TO_VIDEO_DIT_MODELS = { @@ -54,6 +55,7 @@ _TEXT_ENCODER_MODELS = { "Reason1TextEncoder": ("encoders", "reason1", "Reason1TextEncoder"), "Qwen2_5_VLForConditionalGeneration": ("encoders", "reason1", "Reason1TextEncoder"), + "LTX2GemmaTextEncoderModel": ("encoders", "gemma", "LTX2GemmaTextEncoderModel"), } _IMAGE_ENCODER_MODELS: dict[str, tuple] = { @@ -67,7 +69,14 @@ _VAE_MODELS = { ("vaes", "hunyuanvae", "AutoencoderKLHunyuanVideo"), "AutoencoderKLHunyuanVideo15": ("vaes", "hunyuan15vae", "AutoencoderKLHunyuanVideo15"), "AutoencoderKLWan": ("vaes", "wanvae", "AutoencoderKLWan"), - "AutoencoderKLStepvideo": ("vaes", "stepvideovae", "AutoencoderKLStepvideo") + "AutoencoderKLStepvideo": ("vaes", "stepvideovae", "AutoencoderKLStepvideo"), + "CausalVideoAutoencoder": ("vaes", "ltx2vae", "LTX2CausalVideoAutoencoder"), +} + +_AUDIO_MODELS = { + "LTX2AudioEncoder": ("audio", "ltx2_audio_vae", "LTX2AudioEncoder"), + "LTX2AudioDecoder": ("audio", "ltx2_audio_vae", "LTX2AudioDecoder"), + "LTX2Vocoder": ("audio", "ltx2_audio_vae", "LTX2Vocoder"), } _SCHEDULERS = { @@ -91,6 +100,7 @@ _FAST_VIDEO_MODELS = { **_TEXT_ENCODER_MODELS, **_IMAGE_ENCODER_MODELS, **_VAE_MODELS, + **_AUDIO_MODELS, **_SCHEDULERS, } diff --git a/fastvideo/models/vaes/ltx2vae.py b/fastvideo/models/vaes/ltx2vae.py new file mode 100644 index 000000000..e0a01db83 --- /dev/null +++ b/fastvideo/models/vaes/ltx2vae.py @@ -0,0 +1,1804 @@ +# SPDX-License-Identifier: Apache-2.0 +""" +LTX-2 Video VAE implementation +""" + +from __future__ import annotations + +import itertools +import math +from dataclasses import dataclass, replace +from enum import Enum +from typing import Any, Callable, Iterator, List, NamedTuple, Tuple + +import torch +import torch.nn as nn +import torch.nn.functional as F +from einops import rearrange + +from fastvideo.models.vaes.common import DiagonalGaussianDistribution + + +# ============================================================================= +# Enums +# ============================================================================= + + +class NormLayerType(Enum): + GROUP_NORM = "group_norm" + PIXEL_NORM = "pixel_norm" + + +class LogVarianceType(Enum): + PER_CHANNEL = "per_channel" + UNIFORM = "uniform" + CONSTANT = "constant" + NONE = "none" + + +class PaddingModeType(Enum): + ZEROS = "zeros" + REFLECT = "reflect" + REPLICATE = "replicate" + CIRCULAR = "circular" + + +# ============================================================================= +# Tiling Data Structures +# ============================================================================= + + +@dataclass(frozen=True) +class SpatialTilingConfig: + """Configuration for dividing each frame into spatial tiles with optional overlap.""" + tile_size_in_pixels: int + tile_overlap_in_pixels: int = 0 + + def __post_init__(self) -> None: + if self.tile_size_in_pixels < 64: + raise ValueError(f"tile_size_in_pixels must be at least 64, got {self.tile_size_in_pixels}") + if self.tile_size_in_pixels % 32 != 0: + raise ValueError(f"tile_size_in_pixels must be divisible by 32, got {self.tile_size_in_pixels}") + if self.tile_overlap_in_pixels % 32 != 0: + raise ValueError(f"tile_overlap_in_pixels must be divisible by 32, got {self.tile_overlap_in_pixels}") + if self.tile_overlap_in_pixels >= self.tile_size_in_pixels: + raise ValueError( + f"Overlap must be less than tile size, got {self.tile_overlap_in_pixels} and {self.tile_size_in_pixels}" + ) + + +@dataclass(frozen=True) +class TemporalTilingConfig: + """Configuration for dividing a video into temporal tiles (chunks of frames) with optional overlap.""" + tile_size_in_frames: int + tile_overlap_in_frames: int = 0 + + def __post_init__(self) -> None: + if self.tile_size_in_frames < 16: + raise ValueError(f"tile_size_in_frames must be at least 16, got {self.tile_size_in_frames}") + if self.tile_size_in_frames % 8 != 0: + raise ValueError(f"tile_size_in_frames must be divisible by 8, got {self.tile_size_in_frames}") + if self.tile_overlap_in_frames % 8 != 0: + raise ValueError(f"tile_overlap_in_frames must be divisible by 8, got {self.tile_overlap_in_frames}") + if self.tile_overlap_in_frames >= self.tile_size_in_frames: + raise ValueError( + f"Overlap must be less than tile size, got {self.tile_overlap_in_frames} and {self.tile_size_in_frames}" + ) + + +@dataclass(frozen=True) +class TilingConfig: + """Configuration for splitting video into tiles with optional overlap.""" + spatial_config: SpatialTilingConfig | None = None + temporal_config: TemporalTilingConfig | None = None + + @classmethod + def default(cls) -> "TilingConfig": + return cls( + spatial_config=SpatialTilingConfig(tile_size_in_pixels=512, tile_overlap_in_pixels=64), + temporal_config=TemporalTilingConfig(tile_size_in_frames=64, tile_overlap_in_frames=24), + ) + + +@dataclass(frozen=True) +class DimensionIntervals: + """Intervals which a single dimension of the latent space is split into.""" + starts: List[int] + ends: List[int] + left_ramps: List[int] + right_ramps: List[int] + + +@dataclass(frozen=True) +class LatentIntervals: + """Intervals which the latent tensor of given shape is split into.""" + original_shape: torch.Size + dimension_intervals: Tuple[DimensionIntervals, ...] + + +class VideoLatentShape(NamedTuple): + """Shape of the tensor representing video in VAE latent space.""" + batch: int + channels: int + frames: int + height: int + width: int + + def to_torch_shape(self) -> torch.Size: + return torch.Size([self.batch, self.channels, self.frames, self.height, self.width]) + + @staticmethod + def from_torch_shape(shape: torch.Size) -> "VideoLatentShape": + return VideoLatentShape( + batch=shape[0], + channels=shape[1], + frames=shape[2], + height=shape[3], + width=shape[4], + ) + + def upscale(self, time_scale: int, spatial_scale: int) -> "VideoLatentShape": + return self._replace( + channels=3, + frames=(self.frames - 1) * time_scale + 1, + height=self.height * spatial_scale, + width=self.width * spatial_scale, + ) + + +# Operation to split a single dimension of the tensor into intervals based on the length along the dimension. +SplitOperation = Callable[[int], DimensionIntervals] +# Operation to map the intervals in input dimension to slices and masks along a corresponding output dimension. +MappingOperation = Callable[[DimensionIntervals], Tuple[List[slice], List[torch.Tensor | None]]] + + +class Tile(NamedTuple): + """Represents a single tile.""" + in_coords: Tuple[slice, ...] + out_coords: Tuple[slice, ...] + masks_1d: Tuple[torch.Tensor | None, ...] + + @property + def blend_mask(self) -> torch.Tensor: + num_dims = len(self.out_coords) + per_dimension_masks: List[torch.Tensor] = [] + + for dim_idx in range(num_dims): + mask_1d = self.masks_1d[dim_idx] + view_shape = [1] * num_dims + if mask_1d is None: + one = torch.ones(1) + view_shape[dim_idx] = 1 + per_dimension_masks.append(one.view(*view_shape)) + continue + + view_shape[dim_idx] = mask_1d.shape[0] + per_dimension_masks.append(mask_1d.view(*view_shape)) + + combined_mask = per_dimension_masks[0] + for mask in per_dimension_masks[1:]: + combined_mask = combined_mask * mask + + return combined_mask + + +# ============================================================================= +# Tiling Helper Functions +# ============================================================================= + + +def compute_trapezoidal_mask_1d( + length: int, + ramp_left: int, + ramp_right: int, + left_starts_from_0: bool = False, +) -> torch.Tensor: + """Generate a 1D trapezoidal blending mask with linear ramps.""" + if length <= 0: + raise ValueError("Mask length must be positive.") + + ramp_left = max(0, min(ramp_left, length)) + ramp_right = max(0, min(ramp_right, length)) + + mask = torch.ones(length) + + if ramp_left > 0: + interval_length = ramp_left + 1 if left_starts_from_0 else ramp_left + 2 + fade_in = torch.linspace(0.0, 1.0, interval_length)[:-1] + if not left_starts_from_0: + fade_in = fade_in[1:] + mask[:ramp_left] *= fade_in + + if ramp_right > 0: + fade_out = torch.linspace(1.0, 0.0, steps=ramp_right + 2)[1:-1] + mask[-ramp_right:] *= fade_out + + return mask.clamp_(0, 1) + + +def default_split_operation(length: int) -> DimensionIntervals: + return DimensionIntervals(starts=[0], ends=[length], left_ramps=[0], right_ramps=[0]) + + +DEFAULT_SPLIT_OPERATION: SplitOperation = default_split_operation + + +def default_mapping_operation( + _intervals: DimensionIntervals, +) -> Tuple[List[slice], List[torch.Tensor | None]]: + return [slice(0, None)], [None] + + +DEFAULT_MAPPING_OPERATION: MappingOperation = default_mapping_operation + + +def split_in_spatial(size: int, overlap: int) -> SplitOperation: + def split(dimension_size: int) -> DimensionIntervals: + if dimension_size <= size: + return DEFAULT_SPLIT_OPERATION(dimension_size) + amount = (dimension_size + size - 2 * overlap - 1) // (size - overlap) + starts = [i * (size - overlap) for i in range(amount)] + ends = [start + size for start in starts] + ends[-1] = dimension_size + left_ramps = [0] + [overlap] * (amount - 1) + right_ramps = [overlap] * (amount - 1) + [0] + return DimensionIntervals(starts=starts, ends=ends, left_ramps=left_ramps, right_ramps=right_ramps) + + return split + + +def split_in_temporal(size: int, overlap: int) -> SplitOperation: + non_causal_split = split_in_spatial(size, overlap) + + def split(dimension_size: int) -> DimensionIntervals: + if dimension_size <= size: + return DEFAULT_SPLIT_OPERATION(dimension_size) + intervals = non_causal_split(dimension_size) + starts = list(intervals.starts) + starts[1:] = [s - 1 for s in starts[1:]] + left_ramps = list(intervals.left_ramps) + left_ramps[1:] = [r + 1 for r in left_ramps[1:]] + return replace(intervals, starts=starts, left_ramps=left_ramps) + + return split + + +def map_temporal_slice(begin: int, end: int, left_ramp: int, right_ramp: int, scale: int) -> Tuple[slice, torch.Tensor]: + start = begin * scale + stop = 1 + (end - 1) * scale + left_ramp_scaled = 1 + (left_ramp - 1) * scale + right_ramp_scaled = right_ramp * scale + + return slice(start, stop), compute_trapezoidal_mask_1d(stop - start, left_ramp_scaled, right_ramp_scaled, True) + + +def map_spatial_slice(begin: int, end: int, left_ramp: int, right_ramp: int, scale: int) -> Tuple[slice, torch.Tensor]: + start = begin * scale + stop = end * scale + left_ramp_scaled = left_ramp * scale + right_ramp_scaled = right_ramp * scale + + return slice(start, stop), compute_trapezoidal_mask_1d(stop - start, left_ramp_scaled, right_ramp_scaled, False) + + +def to_mapping_operation( + map_func: Callable[[int, int, int, int, int], Tuple[slice, torch.Tensor]], + scale: int, +) -> MappingOperation: + def map_op(intervals: DimensionIntervals) -> Tuple[List[slice], List[torch.Tensor | None]]: + output_slices: List[slice] = [] + masks_1d: List[torch.Tensor | None] = [] + number_of_slices = len(intervals.starts) + for i in range(number_of_slices): + start = intervals.starts[i] + end = intervals.ends[i] + left_ramp = intervals.left_ramps[i] + right_ramp = intervals.right_ramps[i] + output_slice, mask_1d = map_func(start, end, left_ramp, right_ramp, scale) + output_slices.append(output_slice) + masks_1d.append(mask_1d) + return output_slices, masks_1d + + return map_op + + +def create_tiles_from_intervals_and_mappers( + intervals: LatentIntervals, + mappers: List[MappingOperation], +) -> List[Tile]: + full_dim_input_slices = [] + full_dim_output_slices = [] + full_dim_masks_1d = [] + for axis_index in range(len(intervals.original_shape)): + dimension_intervals = intervals.dimension_intervals[axis_index] + starts = dimension_intervals.starts + ends = dimension_intervals.ends + input_slices = [slice(s, e) for s, e in zip(starts, ends, strict=True)] + output_slices, masks_1d = mappers[axis_index](dimension_intervals) + full_dim_input_slices.append(input_slices) + full_dim_output_slices.append(output_slices) + full_dim_masks_1d.append(masks_1d) + + tiles = [] + tile_in_coords = list(itertools.product(*full_dim_input_slices)) + tile_out_coords = list(itertools.product(*full_dim_output_slices)) + tile_mask_1ds = list(itertools.product(*full_dim_masks_1d)) + for in_coord, out_coord, mask_1d in zip(tile_in_coords, tile_out_coords, tile_mask_1ds, strict=True): + tiles.append( + Tile( + in_coords=in_coord, + out_coords=out_coord, + masks_1d=mask_1d, + ) + ) + return tiles + + +def create_tiles( + latent_shape: torch.Size, + splitters: List[SplitOperation], + mappers: List[MappingOperation], +) -> List[Tile]: + if len(splitters) != len(latent_shape): + raise ValueError( + f"Number of splitters must be equal to number of dimensions in latent shape, " + f"got {len(splitters)} and {len(latent_shape)}" + ) + if len(mappers) != len(latent_shape): + raise ValueError( + f"Number of mappers must be equal to number of dimensions in latent shape, " + f"got {len(mappers)} and {len(latent_shape)}" + ) + intervals = [splitter(length) for splitter, length in zip(splitters, latent_shape, strict=True)] + latent_intervals = LatentIntervals(original_shape=latent_shape, dimension_intervals=tuple(intervals)) + return create_tiles_from_intervals_and_mappers(latent_intervals, mappers) + + +# ============================================================================= +# Utility Functions +# ============================================================================= + + +def patchify(x: torch.Tensor, patch_size_hw: int, patch_size_t: int = 1) -> torch.Tensor: + """ + Rearrange spatial dimensions into channels (space-to-depth). + + Args: + x: Input tensor (4D or 5D) + patch_size_hw: Spatial patch size for height and width. + patch_size_t: Temporal patch size. Default=1 (no temporal patching). + + For 5D: (B, C, F, H, W) -> (B, C*patch_size_hw^2*patch_size_t, F/patch_size_t, H/patch_size_hw, W/patch_size_hw) + """ + if patch_size_hw == 1 and patch_size_t == 1: + return x + if x.dim() == 4: + x = rearrange(x, "b c (h q) (w r) -> b (c r q) h w", q=patch_size_hw, r=patch_size_hw) + elif x.dim() == 5: + x = rearrange( + x, + "b c (f p) (h q) (w r) -> b (c p r q) f h w", + p=patch_size_t, + q=patch_size_hw, + r=patch_size_hw, + ) + else: + raise ValueError(f"Invalid input shape: {x.shape}") + return x + + +def unpatchify(x: torch.Tensor, patch_size_hw: int, patch_size_t: int = 1) -> torch.Tensor: + """ + Rearrange channels back into spatial dimensions (depth-to-space). + + Args: + x: Input tensor (4D or 5D) + patch_size_hw: Spatial patch size for height and width. + patch_size_t: Temporal patch size. Default=1 (no temporal expansion). + + For 5D: (B, C*patch_size_hw^2*patch_size_t, F, H, W) -> (B, C, F*patch_size_t, H*patch_size_hw, W*patch_size_hw) + """ + if patch_size_hw == 1 and patch_size_t == 1: + return x + + if x.dim() == 4: + x = rearrange(x, "b (c r q) h w -> b c (h q) (w r)", q=patch_size_hw, r=patch_size_hw) + elif x.dim() == 5: + x = rearrange( + x, + "b (c p r q) f h w -> b c (f p) (h q) (w r)", + p=patch_size_t, + q=patch_size_hw, + r=patch_size_hw, + ) + return x + + +# ============================================================================= +# Normalization Layers +# ============================================================================= + + +class PixelNorm(nn.Module): + """ + Per-pixel (per-location) RMS normalization layer. + Normalizes along the channel dimension using root-mean-square. + """ + + def __init__(self, dim: int = 1, eps: float = 1e-8) -> None: + super().__init__() + self.dim = dim + self.eps = eps + + def forward(self, x: torch.Tensor) -> torch.Tensor: + mean_sq = torch.mean(x**2, dim=self.dim, keepdim=True) + return x / torch.sqrt(mean_sq + self.eps) + + +# ============================================================================= +# Per-Channel Statistics for Latent Normalization +# ============================================================================= + + +class PerChannelStatistics(nn.Module): + """ + Per-channel statistics for normalizing and denormalizing the latent representation. + Statistics are computed over the dataset and stored in the model checkpoint. + """ + + def __init__(self, latent_channels: int = 128): + super().__init__() + self.register_buffer("std-of-means", torch.ones(latent_channels)) + self.register_buffer("mean-of-means", torch.zeros(latent_channels)) + self.register_buffer("mean-of-stds", torch.ones(latent_channels)) + self.register_buffer("mean-of-stds_over_std-of-means", torch.ones(latent_channels)) + self.register_buffer("channel", torch.arange(latent_channels, dtype=torch.float32)) + + def un_normalize(self, x: torch.Tensor) -> torch.Tensor: + std = self.get_buffer("std-of-means").view(1, -1, 1, 1, 1).to(x) + mean = self.get_buffer("mean-of-means").view(1, -1, 1, 1, 1).to(x) + return x * std + mean + + def normalize(self, x: torch.Tensor) -> torch.Tensor: + std = self.get_buffer("std-of-means").view(1, -1, 1, 1, 1).to(x) + mean = self.get_buffer("mean-of-means").view(1, -1, 1, 1, 1).to(x) + return (x - mean) / std + + +# ============================================================================= +# Causal 3D Convolution +# ============================================================================= + + +class CausalConv3d(nn.Module): + """ + Causal 3D convolution that pads temporally by repeating the first frame. + """ + + def __init__( + self, + in_channels: int, + out_channels: int, + kernel_size: int = 3, + stride: int | Tuple[int, int, int] = 1, + dilation: int = 1, + groups: int = 1, + bias: bool = True, + spatial_padding_mode: PaddingModeType = PaddingModeType.ZEROS, + ) -> None: + super().__init__() + + self.in_channels = in_channels + self.out_channels = out_channels + + kernel_size = (kernel_size, kernel_size, kernel_size) + self.time_kernel_size = kernel_size[0] + + dilation = (dilation, 1, 1) + + height_pad = kernel_size[1] // 2 + width_pad = kernel_size[2] // 2 + padding = (0, height_pad, width_pad) + + self.conv = nn.Conv3d( + in_channels, + out_channels, + kernel_size, + stride=stride, + dilation=dilation, + padding=padding, + padding_mode=spatial_padding_mode.value, + groups=groups, + bias=bias, + ) + + def forward(self, x: torch.Tensor, causal: bool = True) -> torch.Tensor: + if causal: + first_frame_pad = x[:, :, :1, :, :].repeat((1, 1, self.time_kernel_size - 1, 1, 1)) + x = torch.cat((first_frame_pad, x), dim=2) + else: + first_frame_pad = x[:, :, :1, :, :].repeat((1, 1, (self.time_kernel_size - 1) // 2, 1, 1)) + last_frame_pad = x[:, :, -1:, :, :].repeat((1, 1, (self.time_kernel_size - 1) // 2, 1, 1)) + x = torch.cat((first_frame_pad, x, last_frame_pad), dim=2) + x = self.conv(x) + return x + + @property + def weight(self) -> torch.Tensor: + return self.conv.weight + + +def make_conv_nd( + dims: int, + in_channels: int, + out_channels: int, + kernel_size: int, + stride: int | Tuple[int, int, int] = 1, + padding: int = 0, + dilation: int = 1, + groups: int = 1, + bias: bool = True, + causal: bool = False, + spatial_padding_mode: PaddingModeType = PaddingModeType.ZEROS, +) -> nn.Module: + """Create a convolution layer (2D or 3D, causal or not).""" + if dims == 2: + return nn.Conv2d( + in_channels=in_channels, + out_channels=out_channels, + kernel_size=kernel_size, + stride=stride, + padding=padding, + dilation=dilation, + groups=groups, + bias=bias, + padding_mode=spatial_padding_mode.value, + ) + elif dims == 3: + if causal: + return CausalConv3d( + in_channels=in_channels, + out_channels=out_channels, + kernel_size=kernel_size, + stride=stride, + dilation=dilation, + groups=groups, + bias=bias, + spatial_padding_mode=spatial_padding_mode, + ) + return nn.Conv3d( + in_channels=in_channels, + out_channels=out_channels, + kernel_size=kernel_size, + stride=stride, + padding=padding, + dilation=dilation, + groups=groups, + bias=bias, + padding_mode=spatial_padding_mode.value, + ) + else: + raise ValueError(f"unsupported dimensions: {dims}") + + +def make_linear_nd( + dims: int, + in_channels: int, + out_channels: int, + bias: bool = True, +) -> nn.Module: + """Create a 1x1 convolution (pointwise linear).""" + if dims == 2: + return nn.Conv2d(in_channels=in_channels, out_channels=out_channels, kernel_size=1, bias=bias) + elif dims == 3: + return nn.Conv3d(in_channels=in_channels, out_channels=out_channels, kernel_size=1, bias=bias) + else: + raise ValueError(f"unsupported dimensions: {dims}") + + +# ============================================================================= +# ResNet Blocks +# ============================================================================= + + +class ResnetBlock3D(nn.Module): + """A 3D ResNet block with optional timestep conditioning and noise injection.""" + + def __init__( + self, + dims: int, + in_channels: int, + out_channels: int | None = None, + dropout: float = 0.0, + groups: int = 32, + eps: float = 1e-6, + norm_layer: NormLayerType = NormLayerType.PIXEL_NORM, + inject_noise: bool = False, + timestep_conditioning: bool = False, + spatial_padding_mode: PaddingModeType = PaddingModeType.ZEROS, + ): + super().__init__() + self.in_channels = in_channels + out_channels = in_channels if out_channels is None else out_channels + self.out_channels = out_channels + self.inject_noise = inject_noise + + if norm_layer == NormLayerType.GROUP_NORM: + self.norm1 = nn.GroupNorm(num_groups=groups, num_channels=in_channels, eps=eps, affine=True) + elif norm_layer == NormLayerType.PIXEL_NORM: + self.norm1 = PixelNorm() + + self.non_linearity = nn.SiLU() + + self.conv1 = make_conv_nd( + dims, + in_channels, + out_channels, + kernel_size=3, + stride=1, + padding=1, + causal=True, + spatial_padding_mode=spatial_padding_mode, + ) + + if inject_noise: + self.per_channel_scale1 = nn.Parameter(torch.zeros((in_channels, 1, 1))) + + if norm_layer == NormLayerType.GROUP_NORM: + self.norm2 = nn.GroupNorm(num_groups=groups, num_channels=out_channels, eps=eps, affine=True) + elif norm_layer == NormLayerType.PIXEL_NORM: + self.norm2 = PixelNorm() + + self.dropout = nn.Dropout(dropout) + + self.conv2 = make_conv_nd( + dims, + out_channels, + out_channels, + kernel_size=3, + stride=1, + padding=1, + causal=True, + spatial_padding_mode=spatial_padding_mode, + ) + + if inject_noise: + self.per_channel_scale2 = nn.Parameter(torch.zeros((in_channels, 1, 1))) + + self.conv_shortcut = ( + make_linear_nd(dims=dims, in_channels=in_channels, out_channels=out_channels) + if in_channels != out_channels + else nn.Identity() + ) + + self.norm3 = ( + nn.GroupNorm(num_groups=1, num_channels=in_channels, eps=eps, affine=True) + if in_channels != out_channels + else nn.Identity() + ) + + self.timestep_conditioning = timestep_conditioning + + if timestep_conditioning: + self.scale_shift_table = nn.Parameter(torch.randn(4, in_channels) / in_channels**0.5) + + def _feed_spatial_noise( + self, + hidden_states: torch.Tensor, + per_channel_scale: torch.Tensor, + generator: torch.Generator | None = None, + ) -> torch.Tensor: + spatial_shape = hidden_states.shape[-2:] + device = hidden_states.device + dtype = hidden_states.dtype + + spatial_noise = torch.randn(spatial_shape, device=device, dtype=dtype, generator=generator)[None] + scaled_noise = (spatial_noise * per_channel_scale)[None, :, None, ...] + hidden_states = hidden_states + scaled_noise + return hidden_states + + def forward( + self, + input_tensor: torch.Tensor, + causal: bool = True, + timestep: torch.Tensor | None = None, + generator: torch.Generator | None = None, + ) -> torch.Tensor: + hidden_states = input_tensor + batch_size = hidden_states.shape[0] + + hidden_states = self.norm1(hidden_states) + if self.timestep_conditioning: + if timestep is None: + raise ValueError("'timestep' must be provided when 'timestep_conditioning' is True") + ada_values = self.scale_shift_table[None, ..., None, None, None].to( + device=hidden_states.device, dtype=hidden_states.dtype + ) + timestep.reshape( + batch_size, + 4, + -1, + timestep.shape[-3], + timestep.shape[-2], + timestep.shape[-1], + ) + shift1, scale1, shift2, scale2 = ada_values.unbind(dim=1) + hidden_states = hidden_states * (1 + scale1) + shift1 + + hidden_states = self.non_linearity(hidden_states) + hidden_states = self.conv1(hidden_states, causal=causal) + + if self.inject_noise: + hidden_states = self._feed_spatial_noise( + hidden_states, + self.per_channel_scale1.to(device=hidden_states.device, dtype=hidden_states.dtype), + generator=generator, + ) + + hidden_states = self.norm2(hidden_states) + + if self.timestep_conditioning: + hidden_states = hidden_states * (1 + scale2) + shift2 + + hidden_states = self.non_linearity(hidden_states) + hidden_states = self.dropout(hidden_states) + hidden_states = self.conv2(hidden_states, causal=causal) + + if self.inject_noise: + hidden_states = self._feed_spatial_noise( + hidden_states, + self.per_channel_scale2.to(device=hidden_states.device, dtype=hidden_states.dtype), + generator=generator, + ) + + input_tensor = self.norm3(input_tensor) + input_tensor = self.conv_shortcut(input_tensor) + output_tensor = input_tensor + hidden_states + return output_tensor + + +class UNetMidBlock3D(nn.Module): + """A 3D UNet mid-block with multiple residual blocks.""" + + def __init__( + self, + dims: int, + in_channels: int, + dropout: float = 0.0, + num_layers: int = 1, + resnet_eps: float = 1e-6, + resnet_groups: int = 32, + norm_layer: NormLayerType = NormLayerType.GROUP_NORM, + inject_noise: bool = False, + timestep_conditioning: bool = False, + spatial_padding_mode: PaddingModeType = PaddingModeType.ZEROS, + attention_head_dim: int | None = None, # unused, for compatibility + ): + super().__init__() + resnet_groups = resnet_groups if resnet_groups is not None else min(in_channels // 4, 32) + + self.timestep_conditioning = timestep_conditioning + + if timestep_conditioning: + self.time_embedder = PixArtAlphaCombinedTimestepSizeEmbeddings( + embedding_dim=in_channels * 4, size_emb_dim=0 + ) + + self.res_blocks = nn.ModuleList( + [ + ResnetBlock3D( + dims=dims, + in_channels=in_channels, + out_channels=in_channels, + eps=resnet_eps, + groups=resnet_groups, + dropout=dropout, + norm_layer=norm_layer, + inject_noise=inject_noise, + timestep_conditioning=timestep_conditioning, + spatial_padding_mode=spatial_padding_mode, + ) + for _ in range(num_layers) + ] + ) + + def forward( + self, + hidden_states: torch.Tensor, + causal: bool = True, + timestep: torch.Tensor | None = None, + generator: torch.Generator | None = None, + ) -> torch.Tensor: + timestep_embed = None + if self.timestep_conditioning: + if timestep is None: + raise ValueError("'timestep' must be provided when 'timestep_conditioning' is True") + batch_size = hidden_states.shape[0] + timestep_embed = self.time_embedder( + timestep=timestep.flatten(), + hidden_dtype=hidden_states.dtype, + ) + timestep_embed = timestep_embed.view(batch_size, timestep_embed.shape[-1], 1, 1, 1) + + for resnet in self.res_blocks: + hidden_states = resnet( + hidden_states, + causal=causal, + timestep=timestep_embed, + generator=generator, + ) + + return hidden_states + + +# ============================================================================= +# Timestep Embedding (simplified version for decoder conditioning) +# ============================================================================= + + +class PixArtAlphaCombinedTimestepSizeEmbeddings(nn.Module): + """Timestep embeddings for decoder conditioning.""" + + def __init__(self, embedding_dim: int, size_emb_dim: int = 0): + super().__init__() + self.time_proj = Timesteps(num_channels=256, flip_sin_to_cos=True, downscale_freq_shift=0) + self.timestep_embedder = TimestepEmbedding(in_channels=256, time_embed_dim=embedding_dim) + + def forward(self, timestep: torch.Tensor, hidden_dtype: torch.dtype) -> torch.Tensor: + timesteps_proj = self.time_proj(timestep) + timesteps_emb = self.timestep_embedder(timesteps_proj.to(dtype=hidden_dtype)) + return timesteps_emb + + +class Timesteps(nn.Module): + """Sinusoidal timestep embeddings.""" + + def __init__(self, num_channels: int, flip_sin_to_cos: bool = True, downscale_freq_shift: float = 0): + super().__init__() + self.num_channels = num_channels + self.flip_sin_to_cos = flip_sin_to_cos + self.downscale_freq_shift = downscale_freq_shift + + def forward(self, timesteps: torch.Tensor) -> torch.Tensor: + half_dim = self.num_channels // 2 + exponent = -math.log(10000) * torch.arange( + start=0, end=half_dim, dtype=torch.float32, device=timesteps.device + ) + exponent = exponent / (half_dim - self.downscale_freq_shift) + emb = torch.exp(exponent) + emb = timesteps[:, None].float() * emb[None, :] + emb = torch.cat([torch.sin(emb), torch.cos(emb)], dim=-1) + if self.flip_sin_to_cos: + emb = torch.cat([emb[:, half_dim:], emb[:, :half_dim]], dim=-1) + return emb + + +class TimestepEmbedding(nn.Module): + """MLP for timestep embeddings.""" + + def __init__(self, in_channels: int, time_embed_dim: int): + super().__init__() + self.linear_1 = nn.Linear(in_channels, time_embed_dim) + self.act = nn.SiLU() + self.linear_2 = nn.Linear(time_embed_dim, time_embed_dim) + + def forward(self, sample: torch.Tensor) -> torch.Tensor: + sample = self.linear_1(sample) + sample = self.act(sample) + sample = self.linear_2(sample) + return sample + + +# ============================================================================= +# Sampling Blocks (Downsampling / Upsampling) +# ============================================================================= + + +class SpaceToDepthDownsample(nn.Module): + """Downsampling via space-to-depth with residual connection.""" + + def __init__( + self, + dims: int, + in_channels: int, + out_channels: int, + stride: Tuple[int, int, int], + spatial_padding_mode: PaddingModeType = PaddingModeType.ZEROS, + ): + super().__init__() + self.stride = stride + self.group_size = in_channels * math.prod(stride) // out_channels + self.conv = make_conv_nd( + dims=dims, + in_channels=in_channels, + out_channels=out_channels // math.prod(stride), + kernel_size=3, + stride=1, + causal=True, + spatial_padding_mode=spatial_padding_mode, + ) + + def forward(self, x: torch.Tensor, causal: bool = True) -> torch.Tensor: + if self.stride[0] == 2: + x = torch.cat([x[:, :, :1, :, :], x], dim=2) + + x_in = rearrange( + x, + "b c (d p1) (h p2) (w p3) -> b (c p1 p2 p3) d h w", + p1=self.stride[0], + p2=self.stride[1], + p3=self.stride[2], + ) + x_in = rearrange(x_in, "b (c g) d h w -> b c g d h w", g=self.group_size) + x_in = x_in.mean(dim=2) + + x = self.conv(x, causal=causal) + x = rearrange( + x, + "b c (d p1) (h p2) (w p3) -> b (c p1 p2 p3) d h w", + p1=self.stride[0], + p2=self.stride[1], + p3=self.stride[2], + ) + + x = x + x_in + return x + + +class DepthToSpaceUpsample(nn.Module): + """Upsampling via depth-to-space (pixel shuffle).""" + + def __init__( + self, + dims: int, + in_channels: int, + stride: Tuple[int, int, int], + residual: bool = False, + out_channels_reduction_factor: int = 1, + spatial_padding_mode: PaddingModeType = PaddingModeType.ZEROS, + ): + super().__init__() + self.stride = stride + self.out_channels = math.prod(stride) * in_channels // out_channels_reduction_factor + self.conv = make_conv_nd( + dims=dims, + in_channels=in_channels, + out_channels=self.out_channels, + kernel_size=3, + stride=1, + causal=True, + spatial_padding_mode=spatial_padding_mode, + ) + self.residual = residual + self.out_channels_reduction_factor = out_channels_reduction_factor + + def forward(self, x: torch.Tensor, causal: bool = True) -> torch.Tensor: + if self.residual: + x_in = rearrange( + x, + "b (c p1 p2 p3) d h w -> b c (d p1) (h p2) (w p3)", + p1=self.stride[0], + p2=self.stride[1], + p3=self.stride[2], + ) + num_repeat = math.prod(self.stride) // self.out_channels_reduction_factor + x_in = x_in.repeat(1, num_repeat, 1, 1, 1) + if self.stride[0] == 2: + x_in = x_in[:, :, 1:, :, :] + + x = self.conv(x, causal=causal) + x = rearrange( + x, + "b (c p1 p2 p3) d h w -> b c (d p1) (h p2) (w p3)", + p1=self.stride[0], + p2=self.stride[1], + p3=self.stride[2], + ) + if self.stride[0] == 2: + x = x[:, :, 1:, :, :] + if self.residual: + x = x + x_in + return x + + +# ============================================================================= +# Block Factory Functions +# ============================================================================= + + +def _make_encoder_block( + block_name: str, + block_config: dict[str, Any], + in_channels: int, + convolution_dimensions: int, + norm_layer: NormLayerType, + norm_num_groups: int, + spatial_padding_mode: PaddingModeType, +) -> Tuple[nn.Module, int]: + """Create an encoder block based on the block name and config.""" + out_channels = in_channels + + if block_name == "res_x": + block = UNetMidBlock3D( + dims=convolution_dimensions, + in_channels=in_channels, + num_layers=block_config["num_layers"], + resnet_eps=1e-6, + resnet_groups=norm_num_groups, + norm_layer=norm_layer, + spatial_padding_mode=spatial_padding_mode, + ) + elif block_name == "res_x_y": + out_channels = in_channels * block_config.get("multiplier", 2) + block = ResnetBlock3D( + dims=convolution_dimensions, + in_channels=in_channels, + out_channels=out_channels, + eps=1e-6, + groups=norm_num_groups, + norm_layer=norm_layer, + spatial_padding_mode=spatial_padding_mode, + ) + elif block_name == "compress_time": + block = make_conv_nd( + dims=convolution_dimensions, + in_channels=in_channels, + out_channels=out_channels, + kernel_size=3, + stride=(2, 1, 1), + causal=True, + spatial_padding_mode=spatial_padding_mode, + ) + elif block_name == "compress_space": + block = make_conv_nd( + dims=convolution_dimensions, + in_channels=in_channels, + out_channels=out_channels, + kernel_size=3, + stride=(1, 2, 2), + causal=True, + spatial_padding_mode=spatial_padding_mode, + ) + elif block_name == "compress_all": + block = make_conv_nd( + dims=convolution_dimensions, + in_channels=in_channels, + out_channels=out_channels, + kernel_size=3, + stride=(2, 2, 2), + causal=True, + spatial_padding_mode=spatial_padding_mode, + ) + elif block_name == "compress_all_x_y": + out_channels = in_channels * block_config.get("multiplier", 2) + block = make_conv_nd( + dims=convolution_dimensions, + in_channels=in_channels, + out_channels=out_channels, + kernel_size=3, + stride=(2, 2, 2), + causal=True, + spatial_padding_mode=spatial_padding_mode, + ) + elif block_name == "compress_all_res": + out_channels = in_channels * block_config.get("multiplier", 2) + block = SpaceToDepthDownsample( + dims=convolution_dimensions, + in_channels=in_channels, + out_channels=out_channels, + stride=(2, 2, 2), + spatial_padding_mode=spatial_padding_mode, + ) + elif block_name == "compress_space_res": + out_channels = in_channels * block_config.get("multiplier", 2) + block = SpaceToDepthDownsample( + dims=convolution_dimensions, + in_channels=in_channels, + out_channels=out_channels, + stride=(1, 2, 2), + spatial_padding_mode=spatial_padding_mode, + ) + elif block_name == "compress_time_res": + out_channels = in_channels * block_config.get("multiplier", 2) + block = SpaceToDepthDownsample( + dims=convolution_dimensions, + in_channels=in_channels, + out_channels=out_channels, + stride=(2, 1, 1), + spatial_padding_mode=spatial_padding_mode, + ) + else: + raise ValueError(f"unknown block: {block_name}") + + return block, out_channels + + +def _make_decoder_block( + block_name: str, + block_config: dict[str, Any], + in_channels: int, + convolution_dimensions: int, + norm_layer: NormLayerType, + timestep_conditioning: bool, + norm_num_groups: int, + spatial_padding_mode: PaddingModeType, +) -> Tuple[nn.Module, int]: + """Create a decoder block based on the block name and config.""" + out_channels = in_channels + + if block_name == "res_x": + block = UNetMidBlock3D( + dims=convolution_dimensions, + in_channels=in_channels, + num_layers=block_config["num_layers"], + resnet_eps=1e-6, + resnet_groups=norm_num_groups, + norm_layer=norm_layer, + inject_noise=block_config.get("inject_noise", False), + timestep_conditioning=timestep_conditioning, + spatial_padding_mode=spatial_padding_mode, + ) + elif block_name == "attn_res_x": + block = UNetMidBlock3D( + dims=convolution_dimensions, + in_channels=in_channels, + num_layers=block_config["num_layers"], + resnet_groups=norm_num_groups, + norm_layer=norm_layer, + inject_noise=block_config.get("inject_noise", False), + timestep_conditioning=timestep_conditioning, + attention_head_dim=block_config["attention_head_dim"], + spatial_padding_mode=spatial_padding_mode, + ) + elif block_name == "res_x_y": + out_channels = in_channels // block_config.get("multiplier", 2) + block = ResnetBlock3D( + dims=convolution_dimensions, + in_channels=in_channels, + out_channels=out_channels, + eps=1e-6, + groups=norm_num_groups, + norm_layer=norm_layer, + inject_noise=block_config.get("inject_noise", False), + timestep_conditioning=False, + spatial_padding_mode=spatial_padding_mode, + ) + elif block_name == "compress_time": + block = DepthToSpaceUpsample( + dims=convolution_dimensions, + in_channels=in_channels, + stride=(2, 1, 1), + spatial_padding_mode=spatial_padding_mode, + ) + elif block_name == "compress_space": + block = DepthToSpaceUpsample( + dims=convolution_dimensions, + in_channels=in_channels, + stride=(1, 2, 2), + spatial_padding_mode=spatial_padding_mode, + ) + elif block_name == "compress_all": + out_channels = in_channels // block_config.get("multiplier", 1) + block = DepthToSpaceUpsample( + dims=convolution_dimensions, + in_channels=in_channels, + stride=(2, 2, 2), + residual=block_config.get("residual", False), + out_channels_reduction_factor=block_config.get("multiplier", 1), + spatial_padding_mode=spatial_padding_mode, + ) + else: + raise ValueError(f"unknown layer: {block_name}") + + return block, out_channels + + +# ============================================================================= +# Video Encoder +# ============================================================================= + + +class VideoEncoder(nn.Module): + """ + LTX-2 Video Encoder. Encodes video frames into a latent representation. + """ + + _DEFAULT_NORM_NUM_GROUPS = 32 + + def __init__( + self, + convolution_dimensions: int = 3, + in_channels: int = 3, + out_channels: int = 128, + encoder_blocks: list[tuple[str, int]] | list[tuple[str, dict[str, Any]]] = [], + patch_size: int = 4, + norm_layer: NormLayerType = NormLayerType.PIXEL_NORM, + latent_log_var: LogVarianceType = LogVarianceType.UNIFORM, + encoder_spatial_padding_mode: PaddingModeType = PaddingModeType.ZEROS, + ): + super().__init__() + + self.patch_size = patch_size + self.norm_layer = norm_layer + self.latent_channels = out_channels + self.latent_log_var = latent_log_var + self._norm_num_groups = self._DEFAULT_NORM_NUM_GROUPS + + self.per_channel_statistics = PerChannelStatistics(latent_channels=out_channels) + + in_channels = in_channels * patch_size**2 + feature_channels = out_channels + + self.conv_in = make_conv_nd( + dims=convolution_dimensions, + in_channels=in_channels, + out_channels=feature_channels, + kernel_size=3, + stride=1, + padding=1, + causal=True, + spatial_padding_mode=encoder_spatial_padding_mode, + ) + + self.down_blocks = nn.ModuleList([]) + + for block_name, block_params in encoder_blocks: + block_config = {"num_layers": block_params} if isinstance(block_params, int) else block_params + + block, feature_channels = _make_encoder_block( + block_name=block_name, + block_config=block_config, + in_channels=feature_channels, + convolution_dimensions=convolution_dimensions, + norm_layer=norm_layer, + norm_num_groups=self._norm_num_groups, + spatial_padding_mode=encoder_spatial_padding_mode, + ) + + self.down_blocks.append(block) + + if norm_layer == NormLayerType.GROUP_NORM: + self.conv_norm_out = nn.GroupNorm( + num_channels=feature_channels, num_groups=self._norm_num_groups, eps=1e-6 + ) + elif norm_layer == NormLayerType.PIXEL_NORM: + self.conv_norm_out = PixelNorm() + + self.conv_act = nn.SiLU() + + conv_out_channels = out_channels + if latent_log_var == LogVarianceType.PER_CHANNEL: + conv_out_channels *= 2 + elif latent_log_var in {LogVarianceType.UNIFORM, LogVarianceType.CONSTANT}: + conv_out_channels += 1 + elif latent_log_var != LogVarianceType.NONE: + raise ValueError(f"Invalid latent_log_var: {latent_log_var}") + + self.conv_out = make_conv_nd( + dims=convolution_dimensions, + in_channels=feature_channels, + out_channels=conv_out_channels, + kernel_size=3, + padding=1, + causal=True, + spatial_padding_mode=encoder_spatial_padding_mode, + ) + + def forward(self, sample: torch.Tensor) -> torch.Tensor: + frames_count = sample.shape[2] + if ((frames_count - 1) % 8) != 0: + raise ValueError( + "Invalid number of frames: Encode input must have 1 + 8 * x frames " + "(e.g., 1, 9, 17, ...). Please check your input." + ) + + sample = patchify(sample, patch_size_hw=self.patch_size, patch_size_t=1) + sample = self.conv_in(sample) + + for down_block in self.down_blocks: + sample = down_block(sample) + + sample = self.conv_norm_out(sample) + sample = self.conv_act(sample) + sample = self.conv_out(sample) + + if self.latent_log_var == LogVarianceType.UNIFORM: + if sample.shape[1] < 2: + raise ValueError( + f"Invalid channel count for UNIFORM mode: expected at least 2, got {sample.shape[1]}" + ) + means = sample[:, :-1, ...] + logvar = sample[:, -1:, ...] + num_channels = means.shape[1] + repeat_shape = [1, num_channels] + [1] * (sample.ndim - 2) + repeated_logvar = logvar.repeat(*repeat_shape) + sample = torch.cat([means, repeated_logvar], dim=1) + elif self.latent_log_var == LogVarianceType.CONSTANT: + sample = sample[:, :-1, ...] + approx_ln_0 = -30 + sample = torch.cat( + [sample, torch.ones_like(sample, device=sample.device) * approx_ln_0], + dim=1, + ) + + means, _ = torch.chunk(sample, 2, dim=1) + return self.per_channel_statistics.normalize(means) + + +# ============================================================================= +# Video Decoder +# ============================================================================= + + +class VideoDecoder(nn.Module): + """ + LTX-2 Video Decoder. Decodes latent representation into video frames. + """ + + _DEFAULT_NORM_NUM_GROUPS = 32 + + def __init__( + self, + convolution_dimensions: int = 3, + in_channels: int = 128, + out_channels: int = 3, + decoder_blocks: list[tuple[str, int | dict]] = [], + patch_size: int = 4, + norm_layer: NormLayerType = NormLayerType.PIXEL_NORM, + causal: bool = False, + timestep_conditioning: bool = False, + decoder_spatial_padding_mode: PaddingModeType = PaddingModeType.REFLECT, + ): + super().__init__() + + self.patch_size = patch_size + out_channels = out_channels * patch_size**2 + self.causal = causal + self.timestep_conditioning = timestep_conditioning + self._norm_num_groups = self._DEFAULT_NORM_NUM_GROUPS + + self.per_channel_statistics = PerChannelStatistics(latent_channels=in_channels) + + self.decode_noise_scale = 0.025 + self.decode_timestep = 0.05 + + feature_channels = in_channels + for block_name, block_params in list(reversed(decoder_blocks)): + block_config = block_params if isinstance(block_params, dict) else {} + if block_name == "res_x_y": + feature_channels = feature_channels * block_config.get("multiplier", 2) + if block_name == "compress_all": + feature_channels = feature_channels * block_config.get("multiplier", 1) + + self.conv_in = make_conv_nd( + dims=convolution_dimensions, + in_channels=in_channels, + out_channels=feature_channels, + kernel_size=3, + stride=1, + padding=1, + causal=True, + spatial_padding_mode=decoder_spatial_padding_mode, + ) + + self.up_blocks = nn.ModuleList([]) + + for block_name, block_params in list(reversed(decoder_blocks)): + block_config = {"num_layers": block_params} if isinstance(block_params, int) else block_params + + block, feature_channels = _make_decoder_block( + block_name=block_name, + block_config=block_config, + in_channels=feature_channels, + convolution_dimensions=convolution_dimensions, + norm_layer=norm_layer, + timestep_conditioning=timestep_conditioning, + norm_num_groups=self._norm_num_groups, + spatial_padding_mode=decoder_spatial_padding_mode, + ) + + self.up_blocks.append(block) + + if norm_layer == NormLayerType.GROUP_NORM: + self.conv_norm_out = nn.GroupNorm( + num_channels=feature_channels, num_groups=self._norm_num_groups, eps=1e-6 + ) + elif norm_layer == NormLayerType.PIXEL_NORM: + self.conv_norm_out = PixelNorm() + + self.conv_act = nn.SiLU() + self.conv_out = make_conv_nd( + dims=convolution_dimensions, + in_channels=feature_channels, + out_channels=out_channels, + kernel_size=3, + padding=1, + causal=True, + spatial_padding_mode=decoder_spatial_padding_mode, + ) + + if timestep_conditioning: + self.timestep_scale_multiplier = nn.Parameter(torch.tensor(1000.0)) + self.last_time_embedder = PixArtAlphaCombinedTimestepSizeEmbeddings( + embedding_dim=feature_channels * 2, size_emb_dim=0 + ) + self.last_scale_shift_table = nn.Parameter(torch.empty(2, feature_channels)) + + def forward( + self, + sample: torch.Tensor, + timestep: torch.Tensor | None = None, + generator: torch.Generator | None = None, + ) -> torch.Tensor: + batch_size = sample.shape[0] + + if self.timestep_conditioning: + noise = ( + torch.randn( + sample.size(), + generator=generator, + dtype=sample.dtype, + device=sample.device, + ) + * self.decode_noise_scale + ) + sample = noise + (1.0 - self.decode_noise_scale) * sample + + sample = self.per_channel_statistics.un_normalize(sample) + + if timestep is None and self.timestep_conditioning: + timestep = torch.full((batch_size,), self.decode_timestep, device=sample.device, dtype=sample.dtype) + + sample = self.conv_in(sample, causal=self.causal) + + scaled_timestep = None + if self.timestep_conditioning: + if timestep is None: + raise ValueError("'timestep' must be provided when 'timestep_conditioning' is True") + scaled_timestep = timestep * self.timestep_scale_multiplier.to(sample) + + for up_block in self.up_blocks: + if isinstance(up_block, UNetMidBlock3D): + block_kwargs = { + "causal": self.causal, + "timestep": scaled_timestep if self.timestep_conditioning else None, + "generator": generator, + } + sample = up_block(sample, **block_kwargs) + elif isinstance(up_block, ResnetBlock3D): + sample = up_block(sample, causal=self.causal, generator=generator) + else: + sample = up_block(sample, causal=self.causal) + + sample = self.conv_norm_out(sample) + + if self.timestep_conditioning: + embedded_timestep = self.last_time_embedder( + timestep=scaled_timestep.flatten(), + hidden_dtype=sample.dtype, + ) + embedded_timestep = embedded_timestep.view(batch_size, embedded_timestep.shape[-1], 1, 1, 1) + ada_values = self.last_scale_shift_table[None, ..., None, None, None].to( + device=sample.device, dtype=sample.dtype + ) + embedded_timestep.reshape( + batch_size, + 2, + -1, + embedded_timestep.shape[-3], + embedded_timestep.shape[-2], + embedded_timestep.shape[-1], + ) + shift, scale = ada_values.unbind(dim=1) + sample = sample * (1 + scale) + shift + + sample = self.conv_act(sample) + sample = self.conv_out(sample, causal=self.causal) + sample = unpatchify(sample, patch_size_hw=self.patch_size, patch_size_t=1) + + return sample + + +# ============================================================================= +# Configurators (for loading from config dict) +# ============================================================================= + + +class VideoEncoderConfigurator: + """Configurator for creating a video VAE Encoder from a configuration dictionary.""" + + @classmethod + def from_config(cls, config: dict) -> VideoEncoder: + config = config.get("vae", config) + convolution_dimensions = config.get("dims", 3) + in_channels = config.get("in_channels", 3) + latent_channels = config.get("latent_channels", 128) + encoder_spatial_padding_mode = PaddingModeType(config.get("encoder_spatial_padding_mode", "zeros")) + encoder_blocks = config.get("encoder_blocks", []) + patch_size = config.get("patch_size", 4) + norm_layer_str = config.get("norm_layer", "pixel_norm") + latent_log_var_str = config.get("latent_log_var", "uniform") + + return VideoEncoder( + convolution_dimensions=convolution_dimensions, + in_channels=in_channels, + out_channels=latent_channels, + encoder_blocks=encoder_blocks, + patch_size=patch_size, + norm_layer=NormLayerType(norm_layer_str), + latent_log_var=LogVarianceType(latent_log_var_str), + encoder_spatial_padding_mode=encoder_spatial_padding_mode, + ) + + +class VideoDecoderConfigurator: + """Configurator for creating a video VAE Decoder from a configuration dictionary.""" + + @classmethod + def from_config(cls, config: dict) -> VideoDecoder: + config = config.get("vae", config) + convolution_dimensions = config.get("dims", 3) + latent_channels = config.get("latent_channels", 128) + decoder_spatial_padding_mode = PaddingModeType(config.get("decoder_spatial_padding_mode", "reflect")) + out_channels = config.get("out_channels", 3) + decoder_blocks = config.get("decoder_blocks", []) + patch_size = config.get("patch_size", 4) + norm_layer_str = config.get("norm_layer", "pixel_norm") + causal = config.get("causal_decoder", False) + timestep_conditioning = config.get("timestep_conditioning", True) + + return VideoDecoder( + convolution_dimensions=convolution_dimensions, + in_channels=latent_channels, + out_channels=out_channels, + decoder_blocks=decoder_blocks, + patch_size=patch_size, + norm_layer=NormLayerType(norm_layer_str), + causal=causal, + timestep_conditioning=timestep_conditioning, + decoder_spatial_padding_mode=decoder_spatial_padding_mode, + ) + + +# ============================================================================= +# Public API (Wrapper Classes) +# ============================================================================= + + +class LTX2VideoEncoder(nn.Module): + """LTX-2 Video Encoder wrapper for FastVideo compatibility.""" + + def __init__(self, config: dict[str, Any]): + super().__init__() + self.model: VideoEncoder = VideoEncoderConfigurator.from_config(config) + + def forward(self, sample: torch.Tensor) -> torch.Tensor: + return self.model(sample) + + +class LTX2VideoDecoder(nn.Module): + """LTX-2 Video Decoder wrapper for FastVideo compatibility.""" + + def __init__(self, config: dict[str, Any]): + super().__init__() + self.model: VideoDecoder = VideoDecoderConfigurator.from_config(config) + + def forward( + self, + sample: torch.Tensor, + timestep: torch.Tensor | None = None, + generator: torch.Generator | None = None, + ) -> torch.Tensor: + return self.model(sample, timestep=timestep, generator=generator) + + +class LTX2CausalVideoAutoencoder(nn.Module): + """ + LTX-2 VAE that exposes FastVideo's VAE encode/decode interface. + Supports tiled decoding to reduce memory usage for high-resolution videos. + """ + + # LTX-2 VAE scale factors + TIME_SCALE: int = 8 + SPATIAL_SCALE: int = 32 + + def __init__(self, config: dict[str, Any]): + super().__init__() + self.config = config + self.encoder = VideoEncoderConfigurator.from_config(config) + self.decoder = VideoDecoderConfigurator.from_config(config) + self._use_tiling: bool = False + + def encode(self, x: torch.Tensor) -> DiagonalGaussianDistribution: + means = self.encoder(x) + zeros = torch.zeros_like(means) + return DiagonalGaussianDistribution(torch.cat([means, zeros], dim=1), deterministic=True) + + def decode( + self, + z: torch.Tensor, + timestep: torch.Tensor | None = None, + generator: torch.Generator | None = None, + ) -> torch.Tensor: + """Decode latents to video, using tiling if enabled.""" + if self._use_tiling: + # Collect all chunks from tiled decode and concatenate + chunks = list(self.tiled_decode(z, TilingConfig.default(), timestep, generator)) + return torch.cat(chunks, dim=2) # Concatenate along temporal dimension + return self.decoder(z, timestep=timestep, generator=generator) + + def enable_tiling(self) -> None: + """Enable tiled decoding with default configuration.""" + self._use_tiling = True + + def disable_tiling(self) -> None: + """Disable tiled decoding.""" + self._use_tiling = False + + def _prepare_tiles( + self, + latent: torch.Tensor, + tiling_config: TilingConfig | None, + ) -> List[Tile]: + """Prepare tiles for tiled decoding based on tiling configuration.""" + splitters: List[SplitOperation] = [DEFAULT_SPLIT_OPERATION] * 5 + mappers: List[MappingOperation] = [DEFAULT_MAPPING_OPERATION] * 5 + + if tiling_config is not None and tiling_config.spatial_config is not None: + cfg = tiling_config.spatial_config + tile_size = cfg.tile_size_in_pixels // self.SPATIAL_SCALE + overlap = cfg.tile_overlap_in_pixels // self.SPATIAL_SCALE + splitters[3] = split_in_spatial(tile_size, overlap) + splitters[4] = split_in_spatial(tile_size, overlap) + mappers[3] = to_mapping_operation(map_spatial_slice, self.SPATIAL_SCALE) + mappers[4] = to_mapping_operation(map_spatial_slice, self.SPATIAL_SCALE) + + if tiling_config is not None and tiling_config.temporal_config is not None: + cfg = tiling_config.temporal_config + tile_size = cfg.tile_size_in_frames // self.TIME_SCALE + overlap = cfg.tile_overlap_in_frames // self.TIME_SCALE + splitters[2] = split_in_temporal(tile_size, overlap) + mappers[2] = to_mapping_operation(map_temporal_slice, self.TIME_SCALE) + + return create_tiles(latent.shape, splitters, mappers) + + def _group_tiles_by_temporal_slice(self, tiles: List[Tile]) -> List[List[Tile]]: + """Group tiles by their temporal output slice.""" + if not tiles: + return [] + + groups = [] + current_slice = tiles[0].out_coords[2] + current_group = [] + + for tile in tiles: + tile_slice = tile.out_coords[2] + if tile_slice == current_slice: + current_group.append(tile) + else: + groups.append(current_group) + current_slice = tile_slice + current_group = [tile] + + if current_group: + groups.append(current_group) + + return groups + + def _accumulate_temporal_group_into_buffer( + self, + group_tiles: List[Tile], + buffer: torch.Tensor, + latent: torch.Tensor, + timestep: torch.Tensor | None, + generator: torch.Generator | None, + ) -> torch.Tensor: + """Decode and accumulate all tiles of a temporal group into a local buffer.""" + temporal_slice = group_tiles[0].out_coords[2] + weights = torch.zeros_like(buffer) + + for tile in group_tiles: + decoded_tile = self.decoder(latent[tile.in_coords], timestep, generator) + mask = tile.blend_mask.to(device=buffer.device, dtype=buffer.dtype) + temporal_offset = tile.out_coords[2].start - temporal_slice.start + expected_temporal_len = tile.out_coords[2].stop - tile.out_coords[2].start + decoded_temporal_len = decoded_tile.shape[2] + + actual_temporal_len = min(expected_temporal_len, decoded_temporal_len, buffer.shape[2] - temporal_offset) + + chunk_coords = ( + slice(None), # batch + slice(None), # channels + slice(temporal_offset, temporal_offset + actual_temporal_len), + tile.out_coords[3], # height + tile.out_coords[4], # width + ) + + decoded_slice = decoded_tile[:, :, :actual_temporal_len, :, :] + mask_slice = mask[:, :, :actual_temporal_len, :, :] if mask.shape[2] > 1 else mask + + buffer[chunk_coords] += decoded_slice * mask_slice + weights[chunk_coords] += mask_slice + + return weights + + def tiled_decode( + self, + latent: torch.Tensor, + tiling_config: TilingConfig | None = None, + timestep: torch.Tensor | None = None, + generator: torch.Generator | None = None, + ) -> Iterator[torch.Tensor]: + """ + Decode a latent tensor into video frames using tiled processing. + Splits the latent tensor into tiles, decodes each tile individually, + and yields video chunks as they become available. + + Args: + latent: Input latent tensor (B, C, F', H', W'). + tiling_config: Tiling configuration for the latent tensor. + timestep: Optional timestep for decoder conditioning. + generator: Optional random generator for deterministic decoding. + + Yields: + Video chunks (B, C, T, H, W) by temporal slices. + """ + full_video_shape = VideoLatentShape.from_torch_shape(latent.shape).upscale( + self.TIME_SCALE, self.SPATIAL_SCALE + ) + tiles = self._prepare_tiles(latent, tiling_config) + temporal_groups = self._group_tiles_by_temporal_slice(tiles) + + previous_chunk = None + previous_weights = None + previous_temporal_slice = None + + for temporal_group_tiles in temporal_groups: + curr_temporal_slice = temporal_group_tiles[0].out_coords[2] + + temporal_tile_buffer_shape = full_video_shape._replace( + frames=curr_temporal_slice.stop - curr_temporal_slice.start, + ) + + buffer = torch.zeros( + temporal_tile_buffer_shape.to_torch_shape(), + device=latent.device, + dtype=latent.dtype, + ) + + curr_weights = self._accumulate_temporal_group_into_buffer( + group_tiles=temporal_group_tiles, + buffer=buffer, + latent=latent, + timestep=timestep, + generator=generator, + ) + + # Blend with previous temporal chunk if it exists + if previous_chunk is not None: + if previous_temporal_slice.stop > curr_temporal_slice.start: + overlap_len = previous_temporal_slice.stop - curr_temporal_slice.start + temporal_overlap_slice = slice(curr_temporal_slice.start - previous_temporal_slice.start, None) + + previous_chunk[:, :, temporal_overlap_slice, :, :] += buffer[:, :, slice(0, overlap_len), :, :] + previous_weights[:, :, temporal_overlap_slice, :, :] += curr_weights[ + :, :, slice(0, overlap_len), :, : + ] + + buffer[:, :, slice(0, overlap_len), :, :] = previous_chunk[:, :, temporal_overlap_slice, :, :] + curr_weights[:, :, slice(0, overlap_len), :, :] = previous_weights[ + :, :, temporal_overlap_slice, :, : + ] + + # Yield the non-overlapping part of the previous chunk + previous_weights = previous_weights.clamp(min=1e-8) + yield_len = curr_temporal_slice.start - previous_temporal_slice.start + yield (previous_chunk / previous_weights)[:, :, :yield_len, :, :] + + # Update state for next iteration + previous_chunk = buffer + previous_weights = curr_weights + previous_temporal_slice = curr_temporal_slice + + # Yield any remaining chunk + if previous_chunk is not None: + previous_weights = previous_weights.clamp(min=1e-8) + yield previous_chunk / previous_weights diff --git a/fastvideo/pipelines/basic/ltx2/__init__.py b/fastvideo/pipelines/basic/ltx2/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/fastvideo/pipelines/basic/ltx2/ltx2_pipeline.py b/fastvideo/pipelines/basic/ltx2/ltx2_pipeline.py new file mode 100644 index 000000000..72f51e735 --- /dev/null +++ b/fastvideo/pipelines/basic/ltx2/ltx2_pipeline.py @@ -0,0 +1,150 @@ +# SPDX-License-Identifier: Apache-2.0 +""" +LTX-2 text-to-video pipeline. +""" + +import os +from typing import Any + +from transformers import AutoTokenizer + +from fastvideo.fastvideo_args import FastVideoArgs +from fastvideo.logger import init_logger +from fastvideo.models.loader.component_loader import PipelineComponentLoader +from fastvideo.pipelines.composed_pipeline_base import ComposedPipelineBase +from fastvideo.pipelines.stages import (DecodingStage, InputValidationStage, + LTX2AudioDecodingStage, + LTX2DenoisingStage, + LTX2LatentPreparationStage, + TextEncodingStage) + +logger = init_logger(__name__) + + +class LTX2Pipeline(ComposedPipelineBase): + + _required_config_modules = [ + "text_encoder", + "tokenizer", + "transformer", + "vae", + "audio_vae", + "vocoder", + ] + + def create_pipeline_stages(self, fastvideo_args: FastVideoArgs): + self.add_stage( + stage_name="input_validation_stage", + stage=InputValidationStage(), + ) + + self.add_stage( + stage_name="prompt_encoding_stage", + stage=TextEncodingStage( + text_encoders=[self.get_module("text_encoder")], + tokenizers=[self.get_module("tokenizer")], + ), + ) + + self.add_stage( + stage_name="latent_preparation_stage", + stage=LTX2LatentPreparationStage( + transformer=self.get_module("transformer"), ), + ) + + self.add_stage( + stage_name="denoising_stage", + stage=LTX2DenoisingStage( + transformer=self.get_module("transformer"), ), + ) + + self.add_stage( + stage_name="audio_decoding_stage", + stage=LTX2AudioDecodingStage( + audio_decoder=self.get_module("audio_vae"), + vocoder=self.get_module("vocoder"), + ), + ) + + self.add_stage( + stage_name="decoding_stage", + stage=DecodingStage(vae=self.get_module("vae")), + ) + + def initialize_pipeline(self, fastvideo_args: FastVideoArgs): + tokenizer = self.get_module("tokenizer") + if tokenizer is not None: + tokenizer.padding_side = "left" + if tokenizer.pad_token is None: + tokenizer.pad_token = tokenizer.eos_token + + def load_modules( + self, + fastvideo_args: FastVideoArgs, + loaded_modules: dict[str, Any] | None = None, + ) -> dict[str, Any]: + model_index = self._load_config(self.model_path) + logger.info("Loading pipeline modules from config: %s", model_index) + + model_index.pop("_class_name") + model_index.pop("_diffusers_version") + model_index.pop("workload_type", None) + + if len(model_index) <= 1: + raise ValueError( + "model_index.json must contain at least one pipeline module") + + required_modules = self.required_config_modules + modules: dict[str, Any] = {} + + for module_name, module_spec in model_index.items(): + if not isinstance(module_spec, list) or len(module_spec) < 1: + continue + transformers_or_diffusers = module_spec[0] + if transformers_or_diffusers is None: + if module_name in self.required_config_modules: + self.required_config_modules.remove(module_name) + continue + if module_name not in required_modules: + continue + if loaded_modules is not None and module_name in loaded_modules: + modules[module_name] = loaded_modules[module_name] + continue + + component_model_path = os.path.join(self.model_path, module_name) + if module_name == "tokenizer" and not os.path.isdir( + component_model_path): + gemma_path = os.path.join(self.model_path, "text_encoder", + "gemma") + if os.path.isdir(gemma_path): + component_model_path = gemma_path + else: + raise ValueError( + "Tokenizer directory missing and Gemma weights were not found." + ) + + module = PipelineComponentLoader.load_module( + module_name=module_name, + component_model_path=component_model_path, + transformers_or_diffusers=transformers_or_diffusers, + fastvideo_args=fastvideo_args, + ) + logger.info("Loaded module %s from %s", module_name, + component_model_path) + modules[module_name] = module + + if "tokenizer" in required_modules and "tokenizer" not in modules: + gemma_path = os.path.join(self.model_path, "text_encoder", "gemma") + if os.path.isdir(gemma_path): + modules["tokenizer"] = AutoTokenizer.from_pretrained( + gemma_path, local_files_only=True) + + for module_name in required_modules: + if module_name not in modules or modules[module_name] is None: + raise ValueError( + f"Required module {module_name} was not loaded properly") + + return modules + + +EntryClass = LTX2Pipeline diff --git a/fastvideo/pipelines/pipeline_registry.py b/fastvideo/pipelines/pipeline_registry.py index a2f325dd2..a2e027854 100644 --- a/fastvideo/pipelines/pipeline_registry.py +++ b/fastvideo/pipelines/pipeline_registry.py @@ -35,6 +35,7 @@ _PIPELINE_NAME_TO_ARCHITECTURE_NAME: dict[str, str] = { "LongCatPipeline": "longcat", "LongCatImageToVideoPipeline": "longcat", "LongCatVideoContinuationPipeline": "longcat", + "LTX2Pipeline": "ltx2", } _PREPROCESS_WORKLOAD_TYPE_TO_PIPELINE_NAME: dict[WorkloadType, str] = { diff --git a/fastvideo/pipelines/stages/__init__.py b/fastvideo/pipelines/stages/__init__.py index a8136bafe..4a4164f43 100644 --- a/fastvideo/pipelines/stages/__init__.py +++ b/fastvideo/pipelines/stages/__init__.py @@ -22,6 +22,10 @@ from fastvideo.pipelines.stages.input_validation import InputValidationStage from fastvideo.pipelines.stages.latent_preparation import ( Cosmos25LatentPreparationStage, CosmosLatentPreparationStage, LatentPreparationStage) +from fastvideo.pipelines.stages.ltx2_audio_decoding import LTX2AudioDecodingStage +from fastvideo.pipelines.stages.ltx2_denoising import LTX2DenoisingStage +from fastvideo.pipelines.stages.ltx2_latent_preparation import ( + LTX2LatentPreparationStage) from fastvideo.pipelines.stages.matrixgame_denoising import ( MatrixGameCausalDenoisingStage) from fastvideo.pipelines.stages.stepvideo_encoding import ( @@ -44,6 +48,8 @@ __all__ = [ "LatentPreparationStage", "CosmosLatentPreparationStage", "Cosmos25LatentPreparationStage", + "LTX2LatentPreparationStage", + "LTX2AudioDecodingStage", "ConditioningStage", "DenoisingStage", "DmdDenoisingStage", @@ -51,6 +57,7 @@ __all__ = [ "MatrixGameCausalDenoisingStage", "CosmosDenoisingStage", "Cosmos25DenoisingStage", + "LTX2DenoisingStage", "EncodingStage", "DecodingStage", "ImageEncodingStage", diff --git a/fastvideo/pipelines/stages/ltx2_audio_decoding.py b/fastvideo/pipelines/stages/ltx2_audio_decoding.py new file mode 100644 index 000000000..6248ba062 --- /dev/null +++ b/fastvideo/pipelines/stages/ltx2_audio_decoding.py @@ -0,0 +1,67 @@ +# SPDX-License-Identifier: Apache-2.0 +""" +Audio decoding stage for LTX-2 pipelines. +""" + +from __future__ import annotations + +import os + +import torch + +from fastvideo.models.dits.ltx2 import DEFAULT_LTX2_VOCODER_OUTPUT_SAMPLE_RATE + +from fastvideo.distributed import get_local_torch_device +from fastvideo.fastvideo_args import FastVideoArgs +from fastvideo.logger import init_logger +from fastvideo.pipelines.pipeline_batch_info import ForwardBatch +from fastvideo.pipelines.stages.base import PipelineStage +from fastvideo.pipelines.stages.validators import StageValidators as V +from fastvideo.pipelines.stages.validators import VerificationResult + +logger = init_logger(__name__) + + +class LTX2AudioDecodingStage(PipelineStage): + """Decode LTX-2 audio latents into a waveform.""" + + def __init__(self, audio_decoder, vocoder) -> None: + super().__init__() + self.audio_decoder = audio_decoder + self.vocoder = vocoder + + def forward( + self, + batch: ForwardBatch, + fastvideo_args: FastVideoArgs, + ) -> ForwardBatch: + audio_latents = batch.extra.get("ltx2_audio_latents") + if audio_latents is None: + return batch + + device = get_local_torch_device() + self.audio_decoder = self.audio_decoder.to(device) + self.vocoder = self.vocoder.to(device) + audio_latents = audio_latents.to(device) + + disable_autocast = os.getenv("LTX2_DISABLE_AUDIO_AUTOCAST", "1") == "1" + with torch.no_grad(), torch.autocast( + device_type="cuda", + dtype=audio_latents.dtype, + enabled=not disable_autocast, + ): + decoded_spec = self.audio_decoder(audio_latents) + audio_wave = self.vocoder(decoded_spec).squeeze(0).float() + + # Move to CPU for pickling across process boundary + batch.extra["audio"] = audio_wave.cpu() + batch.extra[ + "audio_sample_rate"] = DEFAULT_LTX2_VOCODER_OUTPUT_SAMPLE_RATE + return batch + + def verify_input(self, batch: ForwardBatch, + fastvideo_args: FastVideoArgs) -> VerificationResult: + result = VerificationResult() + result.add_check("audio_latents", batch.extra.get("ltx2_audio_latents"), + V.none_or_tensor) + return result diff --git a/fastvideo/pipelines/stages/ltx2_denoising.py b/fastvideo/pipelines/stages/ltx2_denoising.py new file mode 100644 index 000000000..98d04f6e1 --- /dev/null +++ b/fastvideo/pipelines/stages/ltx2_denoising.py @@ -0,0 +1,308 @@ +# SPDX-License-Identifier: Apache-2.0 +""" +LTX-2 denoising stage using the native sigma schedule. +""" + +from __future__ import annotations + +import math +import os + +import torch +from tqdm.auto import tqdm + +from fastvideo.fastvideo_args import FastVideoArgs +from fastvideo.forward_context import set_forward_context +from fastvideo.pipelines.pipeline_batch_info import ForwardBatch +from fastvideo.pipelines.stages.base import PipelineStage +from fastvideo.pipelines.stages.validators import StageValidators as V +from fastvideo.pipelines.stages.validators import VerificationResult +from fastvideo.logger import init_logger +from fastvideo.models.dits.ltx2 import ( + AudioLatentShape, DEFAULT_LTX2_AUDIO_CHANNELS, + DEFAULT_LTX2_AUDIO_DOWNSAMPLE, DEFAULT_LTX2_AUDIO_HOP_LENGTH, + DEFAULT_LTX2_AUDIO_MEL_BINS, DEFAULT_LTX2_AUDIO_SAMPLE_RATE, + VideoLatentShape) +from fastvideo.utils import PRECISION_TO_TYPE + +BASE_SHIFT_ANCHOR = 1024 +MAX_SHIFT_ANCHOR = 4096 + +# Official distilled sigma schedule (8 denoising steps) +# From LTX-2/packages/ltx-pipelines/src/ltx_pipelines/utils/constants.py +DISTILLED_SIGMA_VALUES = [ + 1.0, 0.99375, 0.9875, 0.98125, 0.975, 0.909375, 0.725, 0.421875, 0.0 +] + +logger = init_logger(__name__) + + +def _ltx2_sigmas( + steps: int, + latent: torch.Tensor | None, + device: torch.device, + max_shift: float = 2.05, + base_shift: float = 0.95, + stretch: bool = True, + terminal: float = 0.1, +) -> torch.Tensor: + tokens = math.prod( + latent.shape[2:]) if latent is not None else MAX_SHIFT_ANCHOR + sigmas = torch.linspace(1.0, + 0.0, + steps + 1, + device=device, + dtype=torch.float32) + + mm = (max_shift - base_shift) / (MAX_SHIFT_ANCHOR - BASE_SHIFT_ANCHOR) + b = base_shift - mm * BASE_SHIFT_ANCHOR + sigma_shift = tokens * mm + b + + numerator = math.exp(sigma_shift) + sigmas = torch.where( + sigmas != 0, + numerator / (numerator + (1 / sigmas - 1)), + torch.zeros_like(sigmas), + ) + + if stretch: + non_zero_mask = sigmas != 0 + non_zero_sigmas = sigmas[non_zero_mask] + one_minus_z = 1.0 - non_zero_sigmas + scale_factor = one_minus_z[-1] / (1.0 - terminal) + stretched = 1.0 - (one_minus_z / scale_factor) + sigmas = sigmas.clone() + sigmas[non_zero_mask] = stretched + + return sigmas + + +class LTX2DenoisingStage(PipelineStage): + """Run the LTX-2 denoising loop over the sigma schedule.""" + + def __init__(self, transformer) -> None: + super().__init__() + self.transformer = transformer + + def forward( + self, + batch: ForwardBatch, + fastvideo_args: FastVideoArgs, + ) -> ForwardBatch: + if batch.latents is None: + raise ValueError("Latents must be provided before denoising.") + + latents = batch.latents + prompt_embeds = batch.prompt_embeds[0] + prompt_mask = None + + neg_prompt_embeds = None + neg_prompt_mask = None + # Only load negative prompts if CFG is actually enabled + if batch.do_classifier_free_guidance: + assert batch.negative_prompt_embeds is not None, ( + "CFG is enabled but negative_prompt_embeds is None") + neg_prompt_embeds = batch.negative_prompt_embeds[0] + + # Ensure text conditioning is on the same device as latents. + if prompt_embeds.device != latents.device: + prompt_embeds = prompt_embeds.to(latents.device) + if prompt_mask is not None and prompt_mask.device != latents.device: + prompt_mask = prompt_mask.to(latents.device) + if neg_prompt_embeds is not None and neg_prompt_embeds.device != latents.device: + neg_prompt_embeds = neg_prompt_embeds.to(latents.device) + if neg_prompt_mask is not None and neg_prompt_mask.device != latents.device: + neg_prompt_mask = neg_prompt_mask.to(latents.device) + + target_dtype = PRECISION_TO_TYPE[ + fastvideo_args.pipeline_config.dit_precision] + disable_autocast = os.getenv("LTX2_DISABLE_AUTOCAST", "1") == "1" + autocast_enabled = (target_dtype != torch.float32 + ) and not fastvideo_args.disable_autocast and ( + not disable_autocast) + + # Use official distilled sigma schedule for 8 steps (distilled models) + use_distilled_sigmas = os.getenv("LTX2_USE_DISTILLED_SIGMAS", + "1") == "1" + if use_distilled_sigmas and batch.num_inference_steps == 8: + sigmas = torch.tensor( + DISTILLED_SIGMA_VALUES, + device=latents.device, + dtype=torch.float32, + ) + logger.info("[LTX2] Using official distilled sigma schedule") + else: + sigmas = _ltx2_sigmas( + steps=batch.num_inference_steps, + latent=None, + device=latents.device, + ) + if hasattr(self.transformer, "patchifier"): + video_shape = VideoLatentShape.from_torch_shape(latents.shape) + token_count = self.transformer.patchifier.get_token_count( + video_shape) + else: + token_count = 1 + timestep_template = torch.ones( + (latents.shape[0], token_count), + device=latents.device, + dtype=torch.float32, + ) + audio_prompt_embeds = batch.extra.get("ltx2_audio_prompt_embeds") + audio_neg_embeds = batch.extra.get("ltx2_audio_negative_embeds") + audio_context_p = audio_prompt_embeds[0] if audio_prompt_embeds else None + audio_context_n = audio_neg_embeds[0] if audio_neg_embeds else None + audio_latents = None + audio_timestep_template = None + if audio_context_p is not None: + fps_value = batch.fps + if isinstance(fps_value, list): + fps_value = fps_value[0] if fps_value else None + if fps_value is None: + fps_value = 1.0 + duration = float(batch.num_frames) / float(fps_value) + audio_shape = AudioLatentShape.from_duration( + batch=latents.shape[0], + duration=duration, + channels=DEFAULT_LTX2_AUDIO_CHANNELS, + mel_bins=DEFAULT_LTX2_AUDIO_MEL_BINS, + sample_rate=DEFAULT_LTX2_AUDIO_SAMPLE_RATE, + hop_length=DEFAULT_LTX2_AUDIO_HOP_LENGTH, + audio_latent_downsample_factor=DEFAULT_LTX2_AUDIO_DOWNSAMPLE, + ) + audio_generator = None + if fastvideo_args.ltx2_initial_latent_path and batch.seed is not None: + audio_generator = torch.Generator( + device=latents.device).manual_seed(batch.seed) + elif batch.generator is not None: + if isinstance(batch.generator, list): + audio_generator = batch.generator[0] + else: + audio_generator = batch.generator + if audio_generator is not None and audio_generator.device.type != latents.device.type: + if batch.seed is None: + audio_generator = torch.Generator(device=latents.device) + else: + audio_generator = torch.Generator( + device=latents.device).manual_seed(batch.seed) + audio_patch_shape = ( + audio_shape.batch, + audio_shape.frames, + audio_shape.channels * audio_shape.mel_bins, + ) + audio_latents_patch = torch.randn( + audio_patch_shape, + generator=audio_generator, + device=latents.device, + dtype=latents.dtype, + ) + if hasattr(self.transformer, "audio_patchifier"): + audio_latents = self.transformer.audio_patchifier.unpatchify( + audio_latents_patch, audio_shape) + else: + audio_latents = audio_latents_patch.view( + audio_shape.batch, + audio_shape.frames, + audio_shape.channels, + audio_shape.mel_bins, + ).permute(0, 2, 1, 3).contiguous() + audio_timestep_template = torch.ones( + (latents.shape[0], audio_shape.frames), + device=latents.device, + dtype=torch.float32, + ) + logger.info( + "[LTX2] Denoising start: steps=%d dtype=%s guidance=%s " + "sigmas_shape=%s latents_shape=%s", + batch.num_inference_steps, + target_dtype, + batch.guidance_scale, + tuple(sigmas.shape), + tuple(latents.shape), + ) + + for step_index in tqdm(range(len(sigmas) - 1)): + sigma = sigmas[step_index] + sigma_next = sigmas[step_index + 1] + timestep = timestep_template * sigma + audio_timestep = (audio_timestep_template * sigma + if audio_timestep_template is not None else None) + + with torch.autocast( + device_type="cuda", + dtype=target_dtype, + enabled=autocast_enabled, + ), set_forward_context( + current_timestep=sigma.item(), + attn_metadata=None, + forward_batch=batch, + ): + pos_outputs = self.transformer( + hidden_states=latents.to(target_dtype), + encoder_hidden_states=prompt_embeds, + encoder_attention_mask=prompt_mask, + timestep=timestep, + audio_hidden_states=audio_latents, + audio_encoder_hidden_states=audio_context_p, + audio_timestep=audio_timestep, + ) + if isinstance(pos_outputs, tuple): + pos_denoised, pos_audio = pos_outputs + else: + pos_denoised = pos_outputs + pos_audio = None + + # Only run negative pass if CFG is enabled + if batch.do_classifier_free_guidance: + neg_outputs = self.transformer( + hidden_states=latents.to(target_dtype), + encoder_hidden_states=neg_prompt_embeds, + encoder_attention_mask=neg_prompt_mask, + timestep=timestep, + audio_hidden_states=audio_latents, + audio_encoder_hidden_states=audio_context_n, + audio_timestep=audio_timestep, + ) + if isinstance(neg_outputs, tuple): + neg_denoised, neg_audio = neg_outputs + else: + neg_denoised = neg_outputs + neg_audio = None + pos_denoised = pos_denoised + (batch.guidance_scale - 1) * ( + pos_denoised - neg_denoised) + if pos_audio is not None and neg_audio is not None: + pos_audio = pos_audio + (batch.guidance_scale - + 1) * (pos_audio - neg_audio) + + sigma_value = sigma.to(torch.float32) if isinstance( + sigma, torch.Tensor) else torch.tensor( + float(sigma), + device=latents.device, + dtype=torch.float32, + ) + dt = sigma_next - sigma + velocity = ((latents.float() - pos_denoised.float()) / + sigma_value).to(latents.dtype) + latents = (latents.float() + velocity.float() * dt).to( + latents.dtype) + if pos_audio is not None and audio_latents is not None: + audio_velocity = ((audio_latents.float() - pos_audio.float()) / + sigma_value).to(audio_latents.dtype) + audio_latents = (audio_latents.float() + + audio_velocity.float() * dt).to( + audio_latents.dtype) + + batch.latents = latents + batch.extra["ltx2_audio_latents"] = audio_latents + logger.info("[LTX2] Denoising done.") + return batch + + def verify_input(self, batch: ForwardBatch, + fastvideo_args: FastVideoArgs) -> VerificationResult: + result = VerificationResult() + result.add_check("latents", batch.latents, + [V.is_tensor, V.with_dims(5)]) + result.add_check("prompt_embeds", batch.prompt_embeds, V.list_not_empty) + result.add_check("num_inference_steps", batch.num_inference_steps, + V.positive_int) + return result diff --git a/fastvideo/pipelines/stages/ltx2_latent_preparation.py b/fastvideo/pipelines/stages/ltx2_latent_preparation.py new file mode 100644 index 000000000..3459f5f28 --- /dev/null +++ b/fastvideo/pipelines/stages/ltx2_latent_preparation.py @@ -0,0 +1,189 @@ +# SPDX-License-Identifier: Apache-2.0 +""" +Latent preparation stage for LTX-2 pipelines. +""" + +from pathlib import Path + +import torch +from diffusers.utils.torch_utils import randn_tensor + +from fastvideo.distributed import get_local_torch_device +from fastvideo.fastvideo_args import FastVideoArgs +from fastvideo.logger import init_logger +from fastvideo.pipelines.pipeline_batch_info import ForwardBatch +from fastvideo.pipelines.stages.base import PipelineStage +from fastvideo.pipelines.stages.validators import StageValidators as V +from fastvideo.pipelines.stages.validators import VerificationResult + +logger = init_logger(__name__) + + +class LTX2LatentPreparationStage(PipelineStage): + """Prepare initial LTX-2 latents without relying on a diffusers scheduler.""" + + def __init__(self, transformer) -> None: + super().__init__() + self.transformer = transformer + + def forward( + self, + batch: ForwardBatch, + fastvideo_args: FastVideoArgs, + ) -> ForwardBatch: + latent_num_frames = self._adjust_video_length(batch, fastvideo_args) + + if not batch.prompt_embeds: + batch_size = 1 + elif isinstance(batch.prompt, list): + batch_size = len(batch.prompt) + elif batch.prompt is not None: + batch_size = 1 + else: + batch_size = batch.prompt_embeds[0].shape[0] + + batch_size *= batch.num_videos_per_prompt + + if not batch.prompt_embeds: + transformer_dtype = next(self.transformer.parameters()).dtype + device = get_local_torch_device() + dummy_prompt = torch.zeros( + batch_size, + 0, + self.transformer.hidden_size, + device=device, + dtype=transformer_dtype, + ) + batch.prompt_embeds = [dummy_prompt] + batch.negative_prompt_embeds = [] + batch.do_classifier_free_guidance = False + + dtype = batch.prompt_embeds[0].dtype + device = get_local_torch_device() + generator = batch.generator + latents = batch.latents + num_frames = latent_num_frames if latent_num_frames is not None else batch.num_frames + height = batch.height + width = batch.width + latent_path = fastvideo_args.ltx2_initial_latent_path + + if height is None or width is None: + raise ValueError("Height and width must be provided") + + spatial_ratio = fastvideo_args.pipeline_config.vae_config.arch_config.spatial_compression_ratio + if height % spatial_ratio != 0 or width % spatial_ratio != 0: + raise ValueError( + f"Height and width must be divisible by {spatial_ratio} " + f"but are {height} and {width}.") + shape = ( + batch_size, + self.transformer.num_channels_latents, + num_frames, + height // spatial_ratio, + width // spatial_ratio, + ) + + if isinstance(generator, list) and len(generator) != batch_size: + raise ValueError( + f"You have passed a list of generators of length {len(generator)}, " + f"but requested an effective batch size of {batch_size}.") + + if latents is None: + if latent_path: + loaded_latents = self._load_initial_latent( + latent_path, device, dtype) + if loaded_latents is not None: + latents = loaded_latents + else: + latents = randn_tensor( + shape, + generator=generator, + device=device, + dtype=dtype, + ) + self._save_initial_latent(latent_path, latents) + else: + latents = randn_tensor( + shape, + generator=generator, + device=device, + dtype=dtype, + ) + else: + latents = latents.to(device) + + batch.latents = latents + batch.raw_latent_shape = shape + return batch + + def _adjust_video_length(self, batch: ForwardBatch, + fastvideo_args: FastVideoArgs) -> int | None: + if not fastvideo_args.pipeline_config.vae_config.use_temporal_scaling_frames: + return None + temporal_scale_factor = (fastvideo_args.pipeline_config.vae_config. + arch_config.temporal_compression_ratio) + video_length = batch.num_frames + return int((video_length - 1) // temporal_scale_factor + 1) + + def _load_initial_latent( + self, + latent_path: str, + device: torch.device, + dtype: torch.dtype, + ) -> torch.Tensor | None: + path = Path(latent_path) + if not path.exists(): + return None + payload = torch.load(path, map_location=device) + if isinstance(payload, dict): + if "video_latent" in payload: + latent = payload["video_latent"] + elif "latent" in payload: + latent = payload["latent"] + else: + latent = None + else: + latent = payload + if not torch.is_tensor(latent): + raise TypeError(f"Expected tensor for initial latent in {path}") + logger.info("[LTX2] Loaded initial latent from %s", path) + return latent.to(device=device, dtype=dtype) + + def _save_initial_latent(self, latent_path: str, + latents: torch.Tensor) -> None: + path = Path(latent_path) + path.parent.mkdir(parents=True, exist_ok=True) + if path.exists(): + return + torch.save({"video_latent": latents.detach().cpu()}, path) + logger.info("[LTX2] Saved initial latent to %s", path) + + def verify_input(self, batch: ForwardBatch, + fastvideo_args: FastVideoArgs) -> VerificationResult: + result = VerificationResult() + result.add_check( + "prompt_or_embeds", + None, + lambda _: V.string_or_list_strings(batch.prompt) or not batch. + prompt_embeds or V.list_not_empty(batch.prompt_embeds), + ) + if batch.prompt_embeds: + result.add_check("prompt_embeds", batch.prompt_embeds, + V.list_of_tensors) + result.add_check("num_videos_per_prompt", batch.num_videos_per_prompt, + V.positive_int) + result.add_check("generator", batch.generator, + V.generator_or_list_generators) + result.add_check("num_frames", batch.num_frames, V.positive_int) + result.add_check("height", batch.height, V.positive_int) + result.add_check("width", batch.width, V.positive_int) + result.add_check("latents", batch.latents, V.none_or_tensor) + return result + + def verify_output(self, batch: ForwardBatch, + fastvideo_args: FastVideoArgs) -> VerificationResult: + result = VerificationResult() + result.add_check("latents", batch.latents, + [V.is_tensor, V.with_dims(5)]) + result.add_check("raw_latent_shape", batch.raw_latent_shape, V.is_tuple) + return result diff --git a/fastvideo/pipelines/stages/text_encoding.py b/fastvideo/pipelines/stages/text_encoding.py index 74b115ff0..87252fde2 100644 --- a/fastvideo/pipelines/stages/text_encoding.py +++ b/fastvideo/pipelines/stages/text_encoding.py @@ -11,14 +11,11 @@ from typing import Any from fastvideo.distributed import get_local_torch_device from fastvideo.fastvideo_args import FastVideoArgs from fastvideo.forward_context import set_forward_context -from fastvideo.logger import init_logger from fastvideo.pipelines.pipeline_batch_info import ForwardBatch from fastvideo.pipelines.stages.base import PipelineStage from fastvideo.pipelines.stages.validators import StageValidators as V from fastvideo.pipelines.stages.validators import VerificationResult -logger = init_logger(__name__) - class TextEncodingStage(PipelineStage): """ @@ -39,6 +36,7 @@ class TextEncodingStage(PipelineStage): super().__init__() self.tokenizers = tokenizers self.text_encoders = text_encoders + self._last_audio_embeds: list[torch.Tensor] | None = None @torch.no_grad() def forward( @@ -70,6 +68,8 @@ class TextEncodingStage(PipelineStage): encoder_index=all_indices, return_attention_mask=True, ) + if self._last_audio_embeds is not None: + batch.extra["ltx2_audio_prompt_embeds"] = self._last_audio_embeds for pe in prompt_embeds_list: batch.prompt_embeds.append(pe) @@ -86,6 +86,9 @@ class TextEncodingStage(PipelineStage): encoder_index=all_indices, return_attention_mask=True, ) + if self._last_audio_embeds is not None: + batch.extra[ + "ltx2_audio_negative_embeds"] = self._last_audio_embeds assert batch.negative_prompt_embeds is not None for ne in neg_embeds_list: @@ -184,10 +187,13 @@ class TextEncodingStage(PipelineStage): embeds_list: list[torch.Tensor] = [] attn_masks_list: list[torch.Tensor] = [] + audio_embeds_list: list[torch.Tensor] = [] preprocess_funcs = fastvideo_args.pipeline_config.preprocess_text_funcs postprocess_funcs = fastvideo_args.pipeline_config.postprocess_text_funcs encoder_cfgs = fastvideo_args.pipeline_config.text_encoder_configs + is_ltx2 = getattr(fastvideo_args.pipeline_config.dit_config, "prefix", + "") == "ltx2" if return_type not in ("list", "dict", "stack"): raise ValueError( @@ -259,6 +265,11 @@ class TextEncodingStage(PipelineStage): except Exception: prompt_embeds, attention_mask = postprocess_func( outputs, attention_mask) + if is_ltx2 and getattr(outputs, "hidden_states", None): + audio_embed = outputs.hidden_states[0] + if dtype is not None: + audio_embed = audio_embed.to(dtype=dtype) + audio_embeds_list.append(audio_embed) if dtype is not None: prompt_embeds = prompt_embeds.to(dtype=dtype) @@ -266,6 +277,7 @@ class TextEncodingStage(PipelineStage): if return_attention_mask: attn_masks_list.append(attention_mask) + self._last_audio_embeds = audio_embeds_list if is_ltx2 else None return self.return_embeds(embeds_list, attn_masks_list, return_type, return_attention_mask, indices) diff --git a/fastvideo/tests/modal/pr_test.py b/fastvideo/tests/modal/pr_test.py index dbeb49821..714630968 100644 --- a/fastvideo/tests/modal/pr_test.py +++ b/fastvideo/tests/modal/pr_test.py @@ -67,17 +67,23 @@ def run_test(pytest_command: str): sys.exit(result.returncode) -@app.function(gpu="H100:1", image=image, timeout=1200, secrets=[modal.Secret.from_dict({"HF_API_KEY": os.environ.get("HF_API_KEY", "")})]) +@app.function(gpu="H100:1", + image=image, + timeout=1200, + secrets=[modal.Secret.from_dict({"HF_API_KEY": os.environ.get("HF_API_KEY", "")})], + volumes={"/root/data": model_vol}) def run_encoder_tests(): - run_test("hf auth login --token $HF_API_KEY && pytest ./fastvideo/tests/encoders -vs") + run_test("export HF_HOME='/root/data/.cache' && hf auth login --token $HF_API_KEY && pytest ./fastvideo/tests/encoders -vs") -@app.function(gpu="L40S:1", image=image, timeout=1200, secrets=[modal.Secret.from_dict({"HF_API_KEY": os.environ.get("HF_API_KEY", "")})]) +@app.function(gpu="L40S:1", image=image, timeout=1200, secrets=[modal.Secret.from_dict({"HF_API_KEY": os.environ.get("HF_API_KEY", "")})], + volumes={"/root/data": model_vol}) def run_vae_tests(): - run_test("hf auth login --token $HF_API_KEY && pytest ./fastvideo/tests/vaes -vs") + run_test("export HF_HOME='/root/data/.cache' && hf auth login --token $HF_API_KEY && pytest ./fastvideo/tests/vaes -vs") -@app.function(gpu="L40S:1", image=image, timeout=900, secrets=[modal.Secret.from_dict({"HF_API_KEY": os.environ.get("HF_API_KEY", "")})]) +@app.function(gpu="L40S:1", image=image, timeout=900, secrets=[modal.Secret.from_dict({"HF_API_KEY": os.environ.get("HF_API_KEY", "")})], + volumes={"/root/data": model_vol}) def run_transformer_tests(): - run_test("hf auth login --token $HF_API_KEY && pytest ./fastvideo/tests/transformers -vs") + run_test("export HF_HOME='/root/data/.cache' && hf auth login --token $HF_API_KEY && pytest ./fastvideo/tests/transformers -vs") @app.function( gpu="L40S:4", @@ -89,13 +95,21 @@ def run_transformer_tests(): def run_ssim_tests(): run_test("export HF_HOME='/root/data/.cache' && export PYTORCH_CUDA_ALLOC_CONF=expandable_segments:True && hf auth login --token $HF_API_KEY && pytest ./fastvideo/tests/ssim -vs") -@app.function(gpu="L40S:4", image=image, timeout=900, secrets=[modal.Secret.from_dict({"WANDB_API_KEY": os.environ.get("WANDB_API_KEY", "")})]) +@app.function(gpu="L40S:4", + image=image, + timeout=900, + secrets=[modal.Secret.from_dict({"WANDB_API_KEY": os.environ.get("WANDB_API_KEY", "")})], + volumes={"/root/data": model_vol}) def run_training_tests(): - run_test("wandb login $WANDB_API_KEY && pytest ./fastvideo/tests/training/Vanilla -srP") + run_test("export HF_HOME='/root/data/.cache' && wandb login $WANDB_API_KEY && pytest ./fastvideo/tests/training/Vanilla -srP") -@app.function(gpu="L40S:2", image=image, timeout=900, secrets=[modal.Secret.from_dict({"WANDB_API_KEY": os.environ.get("WANDB_API_KEY", "")})]) +@app.function(gpu="L40S:2", + image=image, + timeout=900, + secrets=[modal.Secret.from_dict({"WANDB_API_KEY": os.environ.get("WANDB_API_KEY", "")})], + volumes={"/root/data": model_vol}) def run_training_lora_tests(): - run_test("wandb login $WANDB_API_KEY && pytest ./fastvideo/tests/training/lora/test_lora_training.py -srP") + run_test("export HF_HOME='/root/data/.cache' && wandb login $WANDB_API_KEY && pytest ./fastvideo/tests/training/lora/test_lora_training.py -srP") @app.function(gpu="H100:2", image=image, timeout=900, secrets=[modal.Secret.from_dict({"WANDB_API_KEY": os.environ.get("WANDB_API_KEY", "")})]) def run_training_tests_VSA(): diff --git a/fastvideo/tests/ssim/L40S_reference_videos/ltx2_diffusers/FLASH_ATTN/Will Smith casually eats noodles, his relaxed demeanor contrasting with the energetic background of.mp4 b/fastvideo/tests/ssim/L40S_reference_videos/ltx2_diffusers/FLASH_ATTN/Will Smith casually eats noodles, his relaxed demeanor contrasting with the energetic background of.mp4 new file mode 100644 index 0000000000000000000000000000000000000000..7acf878af34943bd61beb28c9635f5cd3859e62d GIT binary patch literal 278241 zcmX_mQ($IIux)HlIGH40Y}>YN+qP}nwrv{|Pi))f&413l_hENeSFKfDRoxH0_ii8{ zAb^RJyPdhCtu+u32+)81&%>baVn}ao$3zbV1O#Q`U~CKo#vEg9r0?{Dsf7Ul{;u2* zKJ7kQ6>CkQS^=yQUR}E}urL9r0fx2?#sGR|c7Ou|J3Bpqo|To}fSLKnAV%{8pp}*r z7Nuqa@T&;^AdQR-e++`QcJ5ZjCQbkbIyy#b20D87AElX-lN|>wt*fgmjf=UFv8|Q9 z4UMgXDeZr=(3m+{Tm4{c?VQYQZ5%lOhWZBjhTQZ32V)a%Mu3sAft9VHB{w|>9S0pi z-$vic-O-qv&W(|S&W)a)5nyf1ZD#BSaCA2KkyrtCj_yCypH|nwh?|~;6#b0ZtCaR#xVYKN6c8n~|Z@k6>tT%}w_c zg1(W5t&K4^13eWzJ-|fY(Mi|N(bC-RKg9n!u(#8-H8F8CcH*XH063XB{4jnTu>h=W zZ7uc9enz_gPsspqv@$pR3FiMP=m0hj|1*i9xwXF2e}S0WI2k)w>HmO!^afVW4*Kr8 zhPKvr`c6M%!=D;CIp~|){J8i5I_Uq0F>%nhHg^1}mVvIF`;TmH#Le&{>l^9Y{g;M; zu7SC}!CV;fylTe~0Y|0?Z%sFud=KfbvcnCbqnsB3L* z!_B}1a5OZwF*bB|;%1`zFH8sh|7z-B>}d8wcQDlb|LOi`cQE8ObT9!}8~haZzqEb^ z+zgB~bO8JRlHsPKVfhj5{&W04y}lba3;U14(aG43n+afU_p?erJK|>%e|+iN|7?K& zmJ`Si2q?YMI4lS#*SP*Z|JF@L1Ds3g5N$MK#Z5=7*Az<-7z$`ym#JFxJb!z2W$l`i zuMSq-Yxq0W=iJk}xv15b57kevw0Q?+!{IvxEwrxFLj>OW+K2^R6+TJYE8dJANiRHX zpUQng1Xv(GQy4$~z=eb8%?BI4Q;vaH!}J};`ci3f8Lm56k(>1?Ry8c670EEp)Yi?d?a@-&vRx4fJ9-V&&8)HhwHFLQ76 zY4)Wi6<20|l`b;jCa(;IX7(gtYJhG>M9(T`uG&QH#k1?6-u zAQJC?fh}mY;?v32v@t9hVa|kKm(rMpsuw~zRS+q;S28(81@WNUjGFsMJ$&JJXVKMc zm#-as^F{$8juVHoj3W?KPK)eI&61!-?qx@c20ro{3xX>pP?5xrST@9y1G^ zr*~20PFQTX*EmT;ZGG)Vn0xk5)|Ao#HS>6O8?HQ6G^iB!P3&A^E zbEFMfd>0qQ;)%3_JhT2ZcKlHKaw={eru6>!4u>KGm8Gb~_1keKG@%po+i_7-EC{9m z^L}eLNuspJ*|_*bGO%nAk6z70PwJK%_9?h;mEXXwnV~5E^u(x($CHl z^yLKP&?WCZBlMVelstActN{)JZacC1H}R2E$k?J1%~kn20_EcTNq^Lj`d5dM<)0y~ zX?O@)!S>uE5NF47wT$LR#Qncb9XrUg2mCTZ5&cjzca>d2OW&E9-D*td7b@US+>aPJ zzU)1DCCx)pOTwFY8c6}u>_;h-?DdP0CqS;#iXqcQ53^qnyJR!yzri|mY;Qzm^M;Vv zKECrfm}rHJjI`1Dq54q8Q{j^9V+0CkyqeuXa^cekn(KWb|Lha$86=;Wbj?#1zLWkv zrbfcj*utX{OEd#FBY-HF?*#hm3M%f+wR1HCDG!$9i)}*;8-ZK z5YE&VD_=0@@yiowiWqnbiK}na{y}ogQx>GqNN`yzTr@72I@3Pg8{uZ~{jrH!tFXbs z(OWDh%=eNk}}m> zuR>xnxE1OY0jdMcO*KdLf z!avM8_;>sDFKR zL}!jf#%qBAFTPBaPwzlUQ#{syW zeiy)TgTQLb;5(EPz*1DEnt6PLy5REWjXIt3{GPC=sL+lV^ik+h3 z1q8pfa^5`4NI~JwvGvobn2@qpy|Q9^OF5x>&@1yY=^UJ^3}LI)zum(1!9kknhb;J2 z%!pn<6CXef@_YS13th{iEcHqgVJiZ!Mz3e_y#Y*p1BtdvN=n(Dq{C8ya9>u_;xpfV zHLaUUk3f$U*NeS3A{a+m{*5HqG&)>BIlPSXbVKUB5q{*lWr7$4(k^Bq*pjVoEKSM$mL;%|qoDO@BMLNe3;8 zf0&U7;*7qPHWE|%E{i3MS4!WCQc_Caa>NEy@Zb!MWicv<98r(g;b(D?tn?C4Z6qyH z)N;GLowwux5quUOl#gDE4+=7F=bfR{#Xzd(S_&JLh7S60tv`(%JQCUV1_DPmX?VS) zvD$RRi29uZM+zRvqKX^OC`wD%yCzsx9i+83rHL{lbOkJFtKa&xshVNL$OHEkdA}_u z*P3a+WakFwMrg+ZU)$}+|=_yl(p7X20tOtgGN@cU{p?%xrN9i2bA_%oi zjQ@UgXU3h^)9+s%+|)Zkhx1mOcy{b>?OPFz9!`Qe)M+j%t43{|p^M#nhXUw2orsNC zPXS|5N4#F1n(TGko5x>NSY22EP~QMoOztPe0n>QJ$`w7&*hV=40c3?kfwTf9ak8GT zd=#U`t$Ur^BJ={`pa8{=HVDsdOGRO}mnRHO^|P8V-C_X%m#g~`Ec6N*E8i@ zZ|uj?K%8|9vR2K>(?!uWX#$^t`-pG_6mBL<3RFn>(t1BeR^%oXQCFWA<6b8_(`VhOc1`(8C&Z$B;Z{JM5)i_d~b{bJlxCVw{5eQc? zeCIVu!R9=iozbX&^urU%ewUyrOeOfLY)^mm`p*pIllc0zVy|oEJ;BLVf$W6w5@#9-7_eW@|QZ2EW z@oyg<%3*rRow#DjWXC@w#}044V-Zy_i-+ZgiXzD>#=N?CyyExy6GgfoT zpm~vC7wRMtxipG0T8iODdS{cFr@&OeFF^ntGE({lr0AZMb~SsOueMwV4O>7_{OeBZ zBvPcJKUwxW+hoqEbJ~>otLix*OS&Wd=|N&P$Wb=~O=B&mbSlu!O=Sgc9yI+>VSG{+rdiszGQ+h5Ym$3z>kKBx9g=#s#fU zaP(n!@W(iDerScBYJ8(dpwG^pB+X9#w1`oQi5bH~fXtEAhEvlzK1CYraxO1@Zmj?| z1BjrDs)2+?6*f%CilpUX@>J0@H&i`%?!#bU;)?chhf0#Ss9T;u?g3}a75DFWiJi>9 zA>}L`pfuEe^tg5A>@&s2aL`neDb2RBQg_9Nj@LE?g16fS-m?^dNvl?(CC@T7>Ewug zrX(tA^9*qBgzhFccW4qGXXa?a`+j?3ljAnmR=pk|^2H3@7Cbd~=eHfnIQg-ka^bp1 z*NtuloaWs%K?21fS|ELY-Rt_4Z)=M^*-}(?@!FL|7-YmSrTLmWKX57>IDk5N6eU&h zE+Vjv+sJb^g3&XXq`An12FcOTvUS*GQ02rB)u}4Z3B2(ZB|v*Kqw=oR25T0Y^Lr5H zSE&IuM~gP4NBp~O^mtZ=Ni(2YndS#Rt1<5HKX1@7>OS2A5ny@j3tI7K9^JhbS*;ku ze-Tk5{SzZ~**3j^IEBzeP}TH7m!@;W=9+=JM{JUtzbWlzvIjHGMi|-x)>5-1WWAMzoc{uc~ zf^ip=0=aI6zc|Y%j5c6(AjKx8U^7Vl`^O4B30spoh=q72+c~Em@7|#ehCwE{EAyNT z@B0c575`2_hi{_qIBQ6Xy9h+bsD3;SYzt};q_~jI zOKrL$sYUkD;bx8yn6wa79@9@Q2PeP})maS3G&7NlULyHH>3)&NZ^%RX`TzvxW1@g0Q|_4nrKAABIKV@t#K5E`z;PHLPYCB*vu`RTGR{khW=*b_PwV zW7DrzYSLGB_OW0jVp$~~rq&B~@2p~4qAxBFW0k~z zyh-cC8hX_-;C(`E7XuhveyKtu`at!tVW7++un0e-Rl|$HI}wOb6U@(mPO@UMOMkGA z-63tU<)@m)QvEvxcryTtN>O`ziJr39VV{$k&PJDHa!t8+1!iEMDBa(r)KdR!03 z>xM-X+~=V89R}}_fjp9yC8NN57k@HCB)|kA!C)X7^=3z$0Al*2B2GeevIs}gNuc+SU0mu zsC>weAEtl4DP1mr(O-1daO?@wNg#o&wy!+)MT5iT-+F&QkY} z-?gdxDMtHipdy(N(gEn;%Ua(v|3RnrMVtZas2r&o0fU@esE z7sx{K4%+aIw#O3bZf8~vMO2|;M5G2xh`sMu!3m&^xijafis|kNc#LOV1X)Itq|2QK zB9FLHUI{-b7Kmqhp;X|0esw=uD**^Gn4Q z0j3RH3I$6hkUwCb`|YZXuQGQ|>c2Z|Sw&mOko}5yG3Q^`w;J%YZupfrM%-y_Ldxj~ zk9cc+uh9dKmLhhkG7Yk;c3R86{hU za<3S;ketQ!g~-j!r8yE}T8;c2emQNxf7PziaklKq*X+P1qCO?Uq{?U}dS`i~=KK78 z^(^t~Ppjkd#JPe**zDj@=!A^adC1+=-Phdt_pyKJi7b|v;H3P*kWns3e{anI2@wp5 z=9b?gfv3V3ulEeKLFd;aHq_I{A^`;Mi^-l=d2}qqTN+Kxzt#XmcQ{=BU$Jg};F$2P zG|~$*Z10*4?s-m%Dq-6gfqiqpD?DLoLitl+gPrTqe4En`h{9-*lKJb^2$Pc0;L^;w zO^o`!sVv|DT(`AKKnMFUe`cosjWJKT~ zoC{-b!s3dQqXcTmMHzU+5dvg?w;I-kn`rRk=r=O_+rglV1Zg}HSUV3KR8N$GE*DXu z`;M|Yx2zXoP1C;b*_H=mprDLeJeU`+U2D098kd2&J^K|=?A&Tfwk7#TYNO56il(C8($6Lsf83fm=a=7&?OeuY}!NvvHA7xI%!hDz7jl#6I-c)fC# zud%-8Wq;P(&m1s#NM{;|dcBb=P{+r42*-wrei8yuGYXi$i$rF=d^Ma-?R7>|wJK@2 zz%*z&Jd6QAfCF(6P_N}1HkLokA<+%RpIyen##If5g{s|EYI-F5`c`>XVfAqR#yQtg zh*W?c9)ZD4{8LO^SH%d!-!~2z3q7>#fu{ty@7PyySqGxkQ7Ifx@6J8A41IhTH|L_X2@|>Mv{@yIuE=!GOtFh`6DU^!R zj$?7(?QY8(Iro~6zV+TEat5zdEv7(}$}Z%Fm(#d}^3^^;x5OaZ$Wl_lJYO3A1e-}S z+D;wq0qS3|oYh=@UrY7*H%yk=P9Hlp;rB*ldp-lPaYu+(&(V`q{K9@Q#<_Jl)7RD< zYHL!{V#v!+S(7;u(Fj`H(hc5z6byJn!{b)5JfKRP{)mC8LX?I(%rb`$-7vHh+u{Kc zV;Y^G_;l)gjGXO3NSucU=%WIgLc!vdZ!N*fyI79F8wx({3HgJNLsi-3u;cmARmYl%UCVGb4RWPTNR%-6 zK&DO8vc>I@q$yqz7^k4rL?uV)Uz%Uuci|gxu^#(H_i!yZS{@$q9lY$ToMR)ma7imi z4A)s}ISo&Qx8i%p_d z5&rekhLTCftCl)?lSUi;tJmQ)DPej^pX2FN(~J4L3kN0FG81rfVqo0)sl6BVraNkpTx0d3Q0%C9cJErihF8-I5*}LW8RuLIIFyCw*^DBT1{q(xAZ-Y70ZTG z^R=Q}Iz}~wqL?O#Hc(8pmP0ZgYZ4{>;be_JrUK)GddyM5u0VYnCfQIaN@JgDO;oEP z2pQrgNmRg{ZZmbodx9zp>lj5+;IZ`SQJ@~Fx_TofeP9kwS2rr>?#uacs#h@1=Ig;4 ziKUA4x*v!MB)k>$x;sxV^Mv(ZS9|IA-=x-)z>Sy(e2*`4W)hU%QHEs zlUw(RMS-hI30(0~QkOlK>=N=xQ?RDVj&P>7psc+cVa2oHCDek#9ShGIpYh=yQ|H)& zt*8(Cuf3JI?T`<6XDn~obSs39%f<<@!VJ)6czXpcBKNj^@LcV09LWZdvue>JcfG#W zBQ)#5a=30A7JrGlTjdWBznJmkBMbF z(ru3--Ze!jh|3ePUAzi3=IOIuNeD*(L*~`XPf+3^>Q}I8?{mzuE7hUNMjlv?b`WK6v6^j)ep%dgJe_=9+2a<77Pp zmOu3GeY~oKy*HNC*PAM|UNsCIXYp>Ysw%@-J+D1V@C}U@ZXffp2FK_$G&ENo`Y}s4 zvQME|r#T4Y;L~`996@t{{a4$;o`c=g2O8e@bILUBY1YS;!C0!XD+p4^2%ol8u;2c$&Ew3!)=PR=7dZ?RCpSw*IpRcJ8DaRFlfc3Ns%_!R163RCY z`e-Rt2jCb^`V0MtlKN#9YrsNsv#SXnXCzU~MXOTP7pZcz`F1fYPE#fI&kv+7->qoa zY=I8geQ20FI9RY_qs8k1DQ<4O5vGC2pJ{8Hf3^c?*dIGC9JJrqmeEFgD3wNaoohBkmb#35(lR^Xt8=s{ zj|y)c>YL!n}0DP1cOoe74^zV-kY$8E>Qg60e@Oe~PK0`t7WQEKXk#UuK|bJ$o# zVH8RNN8Rek6+D(Nl#)g}7%diX729n2K=d0lWMyQyLmeERIp=iwZ#LS?r^p=@qNE`b z{VCSED>uWrIu{MG{BzPl=W<* z?;kyDP_!USN_ed31#jARHKf$ETG2TGJfXm;q!a1}@VogEbx2*)KE(rQPws>zMuOb) zJF}!SKMGtJl3`hy;T(q{>agOc2#(o=e$M2(HAiOhc+T2%YclA z3$%nnz*#~dt7k)5 zDAW8zcP&78lSQf0gZ+-HY(nA)P0P;vHpxhRewzHL8JcP(Jo(m_Q6k>7vwm53x#Tj3 zS8vii#&+3ga!>PnwNQ3hr**Y~)*oGYYBcsp&M*hgo}X01mCeVEvlc5Z z_IjI>**SlY%>D_-*Zi&9h*SY7;4|Uf5EW_{N*Fm_AaNDKEb}smWJ1-06!}CC5_sfSy z@qc?O3qwfS3t8|BN25)GJ7$pxMIL)Q-dRzHA5E*=N;?Iz`$T}Uy1?GHZV!FiKetMg z^m5(PCuQcIKD4MfCnAjAC3W$MzFR24h(D9$VF*Z6dX|XvaKa#hJ~uX0#Eu0!jw{_W zo=eJFQK#~wAUZXSIJUU2Uzdd4@|V`fr#&~trI#Ir8A}qaf4)z1;!kVIXE+2ZTPJab za-}$~!-04|Wvs#Y01n+JvGaJIh$A~fW(V1o{3Kb$t3ArF{S%Sc8-#-;x$SA2^g@w@ z;XSq^EkZBik({$qhfpQ*`O;N$qL$ozbrDAXqL$b1;o;pb5dg%W@g%1veDH5H5!Fh@ zUn7!EhQ+YFCY5^p@K4QELDv6X*NuZTRUey+^eml5b4eF}gqb@nFt@C?>Wn~4tiscd zMSWZJ_*i4%8E>^>NCgDYYbaVyxE+B2z+wa-NCJ3hdd!_s?&sA4cJ`RQ?GHyg zqV^Z`_-Mlk(X};>Fh&-ppjEa|PIz0~wnX@rD|1op8$#eLLQO^jZ>_1V`B5S`7--m~ zk$zp{6B2BSOpZg6cum(kufm^fKt7~o!@?U3(@51Yb-AEK`0K?CrxUc;WZ2u zK4Db{q-<-Qfo&}$A+bds?okup+Is5@c$?W3^*JnY9(pN>b)k2b$@W0$CHPzAe#*Y4 z;9ta4FCmnZkJm8d0(l69T+5o43pzCfsLv}gE|a&7%J0h~Kv8VHWOmCq)CQa(B6HE| zkZgY8-nN@2rtQ?c>Iyp>92Hg&*0&+QBch-N?o#^H8B@AyQfL}9dA41Gv>4i&&CYW6 zYv!=c?H{!&pre804(?)m0z#uoDlcMs)lS#);%eV-vp8wr)m$&cTW1m5MK&f&7sL`L zb-zJ@1oO6YyPH^Z(FlBLAC`^vI1LV(MF~MtKBodlTJ^BQ+@PmL3q>kg*t`xO%^Yl% z>M>BNeNKzah$XO3i-;~VutKYWQ8btIdf|4nShPsAdcy--C&L4>XDa(r>vlwG94&U4 zS3P63%z6t}yi(}9OL>cj#fQ5s1ZK9kdj0k|bei!}GzRl<+zv)I_{)izAPioaW*roh z5sL#E-Yly1og*8(X_Vx>d!i*@hp8>nf<27~gmOr|*6C!V5XnZ42WY^)`Fldza;$!d zB94754h%svfQo_T&Yxpk^X)>ZhO6X{PE+YQti*9J%C2PXhHWCoYP>sBpFnzlhPIw` zQe~D#o)_(h+!qs+2AA#8J~WyLL$3WA!hBuO=kMu84J(62@V^##WtK3Cw+=cS2hVgk z;)W@0l!*!H!PwXj#ZkoDpLWzf(`r{4s8B3R6}V&v4&N*Ajpa9ow`-sjR}RCvBz<-1 zQ?9*nKQ}ZALJgCT2^_UONN1NP*;w@6`4qzXUT-Mvo-N$+@_N<7DAFq3^q55-*ob(Z z0RV1{#q_gujBxY(qm-hXI0V^{cv8JZ6{$yXT-bc5oA5r9(7fwljD;8$55z%#G1r3P zQn9I79xK-d^9f$pTlO6UdE|nifCjm0Hx?TPGqXCXU;<#>y^df*KYHELbOaWpU`Za! zLtAVX*{15Ar5z0n?(!KYhZ1c2=?A_E%uy|2zon3r@YIROi z)4Y25;g9cEY0d#%3;`2&4 z-Q``=uCWfi7*8#}e}l?8nwY4vDsE%kif*}IBe;!HR6~#QO~=6OvUAC@Ts3$*d<84pa78OD`C#QSzl}moE%Ez{1*6hFz z@SA92&?gs95Z@|HEz=F3xyR;GAA#+vV%H`FV6HG`2z6f@hYIIr#d#q6XN?ey(7et| z8JfSc^M=IOR^b+9nEOc6`6wuD^=4X=>&SIH32Mu3!9>ttcK4y&l&Z2WWtIT9)sMNC zVJ9$jQjg9Q#Oi0{8l+{iQ)HF64yE?}W2l@T`U^Yi1^0H}qGc-I?~JT-n;L}Ol*d9S zUV5Ewfz%<>%h3t?_JhUT_kQVm$HQ51~hj09_M07=m$nCdOFZKrB zOY+t#86n-C*bsR9YMo3!K~bgQ^`GuF#EJ4Jq04!NkiU>Ji@zPjf@E}I7 zVmaJ|K$05yRA71=Rg=7Lzku4Yn7`gq=Q^?<+c7Bs95>f*7xDyIWY(Z@SlA}5L1OXM zv+K>Q91C4XpJzRM=4K|Z*5Zxizc13n`61)}GQWSU7IgT9dMRtyLf)tKR!%2cMqW`9qY0at>M~5_?&Is8Ce1_5H$}!od3)wd@`*+~2 zEbOcIMc6&3l2xJUooNWR$@h+YAgF4Cm)6feOj;f{EyB|~&^dUXJnmQWoqF=Y6Konn4grS9`p+ltQ++jT;62bI>#l*o_yIz}Q%$>3c8SCxyLm`@loqQw629d|k zrhTt~gi42`k1CxiASECqD)r!LnG?RAR}kkqYhYHrMQ^~l9kBj(y$5q8TKZUkuD3wn za>(^1Te<^=p)DJjYj7ZP05I^V@Rr^tKbZr}nDf5e?tmDa^=U>E={!KJM$=J(yE<}vy?*P`&oN=Z>1St%6`W2CkD#%a>8d_5$TJCk19>5DAs{Z0cIhs$ zW4P8G2f~xmehP7sUQqPSL4IZHX!k2}F-D)%bCt0JR*w1=NF3{Rh;hIa`tYVVVm zVi&4`Uw55U)U89jYdE>VfTHBvtCH?iZ1M4zI-pO%c$bT2^w^hNxgjF6sV}>4w2D^Q z{qpO#0XjMX;zJfW+&xa*@``ex$g!9qGfM~){A(bjV&F?O(NR{A7MSG#s{rO%(?{CH z6FNuY<3vOI54Gmxb)-*-z01`OVRG_veX(6j_jW1t0x@gCy%lWc-$*Amwax7M2=hVb z#nuUz{>axpBR@_(^cj5p+l1ReHC%nHlN*SR?XQs2J&=nBFnGiISK zrmLHn2xhftPUm@T-L%*gm>Cz)j9c66`P?q0I{)?$GK%ywv3lpT&Uw#rgS2Ig53L8=&v7}$bQNC z{h`)l1) zofKv%%gjvfA(oR4*JBSTY?^~hg8@2rbLIoLnsV9^)9?`2#3#8Ud|>5Vk9In1nD$&S zV*mx&z$?|VWtC+v#iSWnGXJ*lW`SZPXO-o3MM{QeQ9YGE^V??*$sj=u6F<#cGyeq0 zm6I$BEXZ;7paPH6R%gI@t$Lk8ld&K4u}-A>N$3J3lBNFi{H9Uz{y5*SaSjPTh*vw2 z`G!Rb)p`Qvn_qi!)G3*7hjo&Jw_6-fkA}P?8i@g2%5A{04AgZL*J=q0GfP)I@7!R| z%ohi6D4O&cI3nNvV8MuV#(G0r*6?WLD0oC zKr+gl`*HhM`KFjW8&dRhm-W!YFFlGn?wvc7frbN$@t_IF^AC>#U~eCw-+Yu(70gFp zGa>>?=3xvu@e}cb_2lE-vnoLt8!2b>pK@hKpEi^I;b%uwSaD3=4DWjY4k(qLUltv2rc_4}OfhH@K~>7}3Np2M}v5o{Lx2y`LfB@QqQ^(Mu1SWY}& zw02grYnR2F1!q7d2rt?sLAi8y6o&^6-gk-At3kUH8kt&taE1gnxQ34ad!(kqPdT^m9KZRx`?1A|c?V#24IS5f6le8tN(8WW`QMy|xg*$3 zcg1`58Ur~SZdo#oq@mUEQKRGxe#OQKRz52TCe-L8CHd86Sq6I_A!8)f;DlJIh9)Q0 zieML>#)4l+jI|!9h7clQ0eeiUY{ct;OdHWwiXQ(nqvmk|MRZaF!Td6=oVSMOl76`> zL}a~?e7CV8U&IF*W(0)^frpPDIr6hwZIe8FvpRu%aPE#fpol}8Nj7PfY{~9eU-74T z?O1x>jErgE)_KL(&cXTcG83=sGS(_bVr;SKU{|)XbcyFrc_a1?62pHD6$&H`*5oYQ zEK00ZUK%L#zHiseTYY-PQ#5G;i50KDm=8>3LhrE2RA?i4Oa1aqU1K3Js8P07lr${F z1D!hn&X&@Yb~ManbmKO>h5AhfoEtIt1PevRxvRj12z#-sh-AmFJyY5DWu1cH{~8-@ zUDniwy1Zu6c<@9E?W{1cE%t<;Hn{XmO0tFN`?rbnumPACvt?Hj92>-gr5zz^KUoCI zGO%#e20evS$3`y99og>7E`xrG!akb<{3AZZ;smZF3n@)@ZZ~y*umnN$b4nZd;x-A za+^W{PPcW@C|wmQX3|tBX<&Av>+?d!MywoyE}T=s3u1?0S(pi;v46A!3|=K5YsGi% z(^J6~c&S!WgNx4$S#ZzU80`~bZy?c9-kNZckT3L4K~!0C^fl8KFNu)k+x zn}j*IsXlB9u9!at+E&u?ebiIwm0?l1Agj$0=f5gSTT0QDwb9VqZu_F;>=Vu9ACZq8 zK=$=PaC#KCz(sX#Y!gjYc+N_85|;Yc7KrJ! z2ZuffNxZc*4J$Kl<?k?G^jmP1W@#yv`Vsp z?c>oRzF5;aKq+t9vtR!j8{2vzD^oYjE1!7xjn7YhOjQS^KpZvuY!@uFKVf=ew>MYj zQ=k_=GN85bDB0Oc|E8RFxB>x4oV3}JB3LGqBXr8h-~Lkj{GxpP9--a{?o23=#GlZf zj^U~?7n4Y&c^F1@BgLPZ0g2mqBrw{Y^Ih7;l=A+|CotA?VYJjf+47oWi#wf+0$~kfyB1 z-v|S7tfCG$GofdRR?jW1PnOZi80rNH+pIJ{jyGu-q&;y}TT{p>nZ|}-oG}W$giQU= z&5p$@=gdkLw|@YaM|nhNm7sf7h|Po6yn88?Bm?opvn}d|qLZh(z_zYXLF8-J$~(nf z>X?cTC5d}#7Gr-$@{OH23y%lvRs4%rVjfgEa_fWjH6F7$Zc;S)#^@UK0yQqo5fY=n^(#Z!HiO+J zGSJKSg2aC`3VxTc?)7w$b!|)^hsImMQNlqNQZ`0i63#AoR$E%Mn|FCaTU&KH0oQtk z6?TL(Z-;3!p|5p57j$A<5XBkb>u@wKdvg{9UM(r5n9(CUZTo;vjWrJ^r!eK^lu4E{ zDD%ZZ?TkV`JH0dS8b%h$ketwwF<`@2oJ5dFG~Hp?*NIrX<96et%XU$C#pXvHf*ARu zv+K z+=ro%etsz>Wn$V%+k|N{PyYF6}Bk^fm@m@?5@s-wo5MXgwXqsvX2YxXJ_tp4Xd_G?|)}gZ^BQeTyL+1-_mo2KO z6=gD`kVCwYiiFA$7z;@hgT5tCW31qk*4>TRiBd2H$P>Jn(>~pBr4!uX*<3}{bbd1g zEOXQFiS1(-@&T$HBBqNvDKxblTW^ypuewc>q>g~mGnQLkTj5DpJkA-bU$aXoERhKq z==W=sg~nsS9Ddn|nEmxK&72@*orK(@AIkF+`m;2z0LdCz!wJ@zLHpcF+OcMnp`IkY zr30NK%j7{)*p5;$tdx9+p4ZpmgALMG55sF$Z&>`jS>NRUkHrb+?Q?yF*q$LA;~a~5 z=eKv<55^eF6_XXl?$F8n zCSWn*w!v7S`vm?WW*Uef@ZiWEv(Y=kmgv0bo67`dsx>f&661d&7Fz0+0dO=_lb(Ng zSU|%%B?X7MkS9ZX-02jft2Bt*&{+%YcuRGM)+rBKx-;Rj3I&*7n;9Th8b}zX0!KRT zmk`kfZi%`(SbM(8bwPINxgJ+r9UXZThEs>};~b8SkokpgWbJykn7vi@yHq@oi;68KJX!+& zF>jBmX!l{Fzm#;=M-kyU=7?Y2zav#}FFIUdU`~IaLF^^h)G(ISYhm^?oBcjFkwM=m zyI!)v95RkDuZd9fA6>Puq9ZZZ_W{j$a(dig!<^xkdNsldHva7O0(79r2OU1dB(UwE zM+{R}R#}>TzLpmga_rCPSIU*nyTTYDm-yhYECPh{=bOEHds24^U|L)ZIqo_BHUNb? zfL4%S>)QPD!v>hWM5PMGSQq~t<(s34j1o52%ECW2V(#Z9hbxiwUT>@O78_F#{VXSi zpo!s1%nw_VsHnuqP%@vT*wT63_ZFD=lT}-$PSPM+svu$2)%@45+B(-H(g7|=tb_!) zur@Jcl->bg~XEek-L8;Z2BbxD4ybAx9C zC1pf+NfYjMdYf@jhEI;eMDu+w!f5qpR{Arb8Q4vlw_=6ggr%8yl*U7+P<;3PSgLCF z!E`2N=2BABcQDe=2rbe2M^;s>OMH3gXf+~(svObPg#-C;8zv?r4jXMgH!!P#g7l77 z76mxZJfHxl1 zf+-TU38Hf4QVJXiE*O^&pQio&Uu(}BZWVA2g|MH26%gxAy;v*;>BwJ)A}XOFGQMn` z+vMPMZNHYO{R+vVORikNO8GT6+Zx8`?o8PU3xn90L;~o1QoeM9&^gj3g#y#YD)2sg zk&yR6T2{vecGUgHpcx>4%R^0}Za+wqo3??dSiAggV0;Xyn0a!@W7I~zqjFCethOty z#c;vgv@!}fH{Z3plxvdO1g#>lKwZFfRheFlTt9Boh$p<`|B#q# zZYE&biBU?h=+bi5hX}^=&o-A*pMCpiOS-|*c9Cv*c{q{oR8nrDO*O;wEl+COWcO3d zf0mZh0a~zZdTL3g?;h=&(L_7bOe8-9Cv*U$wG#QSwSNEWog3oSO5f32V2;7vd!`RBuP!hML&aV`vN~qfU zmHYXmBhEZ<<5A*H8J8ClfXs=x2l`LiPf?X|5BS)V^b?sD&?%G$(icM3{zu;|aG^pN z^)#Q;AeM$s)kQo5TY783ULY~LQ9E(tFL$5gw-Yw2&iU(RZ)EIyAA-TyQkwg} zA1#n}5}Psy&n}xT1_FpQ?e#It!Or49r}$KP^#S_`Fu=5y$KI>P&}qAB8Gn1-mMI)s z57Z^0U;hsPH$ce0%BqhG0AFrENoxSf&G#i3;28J~qt?SbRr^-xfp%A2yQtBNGw91R zXH=rI)Myo9M-W0->Jlxg-CbqP5Nf$l7ee!WnANG*Y+;ztdU3k&pcl)3_L*lBUQ)iw zN>qZ_3atX|N&;BNTp1+jJ_s(kF~?2#uzPI2RhJ0XV572mNQu|q`||Nz-`7J<>g7=4 zGQWVowovrMDy*0FR7e-VY!-pA=2HP4_qkv#vnhS9ZmGvRT|{d@ZSN%9U~Sj6a-#}9 zO`^5VxppsD0(T(CIGA*Xd7#AM42)@~_#Op?j@O}+uPxxEO<-zo=Rzy`-#(w`3{XGU zgg@-J@~?OYc%OwYB#*vOW+D)JCXJxmpU%)Gcyu^zhwePj)#6Re)p<)MHp6!e#S&v2 za4%Hs5*QAZou6U`#RmHWEITV?GL7Y|lBe$q0C5PrPzKgN^pf21GEKR9wLBVU3!dPF zQyn}zi3=9^_6S%(dz$aqg1DC__q>X)2h0b;$JGm-A`r`yJ0nrl2BJBC=NM5q@Qf4| zJ+Yh^QQ>wD_yOaA^W})F%33JVm;5@CMT^yOV3$6Cm%gB^9$w>o_=V@mZw}D32gDi! z`iTRv0*G{uXWAc*{NtcmwNUcdX_l-}x3B9@W*DExiM#?1R(ooNuo;zX=Miz!AiLf3 z9kO(5dGIOh-RBal)ROgvaUu>9oanm9HZ#a~A|wl66FfE7I_Z8tG&O=J55@nDKXP*@_~$4|mr#~;Yf zwG-MQMSxq~#Pg3$KWe5)^t6CoUY|r$(Qp68=H|og6E|m~aN2y-$09b!=YzPMU&$69 z!r8yygS_yjJrXY>hzzztF@sNpfH~#pCqVAr!5?joK&+!{j_JT8x)E1Twk7HEq%!k! z^yZTkmuIoKGoLQm(Y2hVYy;-WqTrHQeBGfjOH?@D7KbKJ_xj8V#!wZWMu6O1af)p} z34kj6DC|!&&s(`jXRj8m{j`Bh#Wty>4V9&)s-qwQuGbIUHRS zLZykZ2?*;lRac3^K%9+b$z{RDlJ7hZFUUiC zf_AOvH{3!;%LcafWa0NUWAeoH3WU zs(t{gQ4A^df7g|uaTOfLXM?wO(@cL58hz&&E9&twsEcP(_s#b{?M$J@Gm5v>m6S#I zhkEmaf*_^R;v{ve-P)mB_E@Bj=hxP{6I(Td&+wRJr?Hle&oT=dD{IP2>_hPIq(P|j zYtXF}Xk_5D!6=33&>j3JSuA}JfR6mvIH+l#rv7{+EgQ|V*(1+AT2PcZ9uLw!&Yca$ zvYusVuZ{U?*~S639_dha<&QG4=ctX|SX{7LzD@4RydZsl25dvnH7_KwB7rIe%zHlM zofuwu9*cTX5lhMkvcX%mWn*hG30StK*$(&2LcP>moA;#uzy%~?0h>u9!QY+tsXZhP zKWPsbvA0*n`Wg4CH^5X$T&|qD<@vMP8M82=o_?DAXEKv!9P=YHL$@u@?tMQ*NqQE@ z!&fCF3Oa(3&FS<=YijyL=KTmGjq&@nO|`+SqR9TKN+K}hL$f@D_a?dpBL~Up!X9Sq zp4M5E@c+u!u5mr{2m6%k(!e+#+3o$}(DFdn%!rM}JFcnIv+@QKTa?L;GZLD2T^4ZK zNzr|D$G~HW!{(TT7AXCY$^!Me8U0a2A8FlX+LZndDs52|i#S3YF3nBR4zIy%TFRev z>=nvz^Q1#OyEku7zsyyb`QcUB>vct;Nq@AA%P8~TgVA~$*wjG>fBt=pG(`_bco3j95%2yl+-Fhm0N zt&k)Y0c>x%M|pe32LA1_KaUbcvn-6OPtiqPP~1d@`zd8$*}z&>!09 zAKT0=uT;`%T7nd65+r6Xt3}I*WTezp?swb`0sTW%!60BnZb*->qGEe-EJdzo3dNY@ zypM&;)|upOZ%;$N#n2*G0I2{I&p!0VdTSmdqM){o2lL1@=gjB56Sixm6R@CFUT^rs<7U$PTz)`!hVGdJ)8 zLnx4|4o<8hUsIyL(P?CMb}?z|`lkXNH#3BJj!oLT@DKEu%M<-NFi4qjgZ4Vfee z@cyduP;l8ZQ57&vg9PEh3p@0u(s$OM*3ceMSiqcuQwOv!rMxnduehX8tE4ClzW>fi zPNVwgyi){vE4F|gvMvOiF8Vzm zpZiOwFT+Jyotb^dgJ|d=;y@QzR>pn_yM@n2DpbFi_x~dYgH`V-mvoqz>sv z(p+3gYXVt7_fuDSKm*%~Y+{9|P~aFG7e@k5=R*0Y3#D0cgkG_pE~ooTg1Pj* zKrAQ_X9RzFNmacutve07>jB}N%P5(MzXu{?`ae-_e|M@vS(67uyfb>QFYB!)m74?! zx|~S>N)YSnHIDljCuL%UR_BG47)2ta=k8^jfo%w-*;A@$yIW7Ew+MtDigRk1GvC3+ zdI@2bh)?aP$d$0W5r-T2W$>AiuU%;@m)G>Gu(M@~=(NTCDtc+?bCB5=obkxvSVV9* z=_MA?m@QG82n0$2e9nKa(lSjqh<^}}#$??(C}0~FG2!_5)TXkmf&-Dd;E{4g8s+lB zA^NCDO8h5vG3{Tg1(48UK^h#F_S^d`2EPyR?3fPjZ~cYtv<^r;Fxs6^I96I@87PAlqOm?mFDs=Z|2>(cjHipPJ;38pK!~&5RXIk(X<;a6& zUQP>rBX7l~dRK3`HjdlHJD@bZT@#$nH=FC3DFOOpfh|Z%_!HhN=mX3h{a5}UPRyzQlq5U~{t-^p+&aWuN)7()V;_%1H{cp2Z3@_Y!hfac;N5-G+~1Y^?C5SK z&Kar#vJ|`iNn0w#h~(?$m37G*&%QN&@45-Q(miv_AvgD{)vX~@;9fRFeUMO_RpP}h zA2_$$Ct27S=Tw$II31dF6Pfu-VW>W#dkZ&WLUM~9sB69T4_5&M#Am?k*g-<8;A~Ww^mP) zW%@M6!Xs=BmIgr(kD7uP{zlkBh^t@mYWjKN@_2JB()xicwz8Q%t$skO5wEn-@mF%U4=`N&LK(icn8r-&d)>Aj5w4XBO*jDe| z+@^<_vPj`H0b}`P z^s6``3MN;sLgC*t`xo1*R5w6)j%)iMFOOmZUit!R(?C3I$Zc*Bd9|4cX_8tzD4)te z5a0|1R!LuiHzuD(;$*aJVrz+&t@j>C2K#D(6dQ6}#^S_wG)`O47e7=qf_&Q70U9Ne1k6&xw1FWR!25pDPRKa;z2IgR%FmEu_>1lW9T3$bq<%A<+fP zl;kgzmOyP9qWr~mVUkjo*VP`te9GC zTQPDSlWW^qiviMhuvlau3&~$E6}!85fybG2y3a==p6D!aFS2%|*&YM$mTHT8q+f}W z(Ogn~Sh6?2Op1c*J38nh+&y{GEpL4VB)IHCFlQS`HPM4jY2O_}eIO!xWNy#uAnJ9F zBVp1%wilfb^@w}Ex*bVH(sgOzkk}cq6hTHeA)&pqXA(=0^*3jL^0DEmSb66;*{Dve zXHoqSi{7nO#eJH<(zaL#GI}LMZc+CW`NtH_PV-+(ZZ#hO>C6~Lys#!7MuKJ727~Dy=O|wqu^}FXDN{U$x#`_Lu zYg1>BDRmTTE49Z5*yd$vQgxuvtvY+mMpW@lW2+0~ity%51_m zlHJ;iZ0d|kb8BzXKkIRu3GH~7x#S=YBzZkb`Tq>z{?Pj1u{Zrr?6-eH)@y)I5^VT6 zl}JQpbo9m+qj`W}ds>l*@meb;eUMKI7t&n(9VIe8_1c(wAreAE9Ah_J4d7wI%K*R{ z9Ya7o=GdzG^JrR;sIuWy<)%>2!CbXvP0k6uBhSGO)bQnHxSiD!MduJzyC>if#_Y=D z6;CjCb~*o?iV!CCsRLO1fU5@wu+u|V!YH)Gsx$Ek$D&-rDfb?JNMOt!Xuar>i{mo_ z5#w^nR1He)T9ex$$oKh>r(7}-K;nA~stZ({vPgEKA5KfNQ|N+nt1Amia_9SsbpQG4Z zX_eKrGqHk@D;N#`H6ZXk(8pdm@^fU=OvhZJ+eDIEUyhB@&LEx&z}m zOZ<7f%inUE{peaRZNhC+1-0);`4Kc72#nUhF?BVPYOA7eiiv1LdRXhE)zE8=vI~s6 znbC(oD{IY=(Lnzdd5Vi!sB-uoHu*zY7_CumLiRFG_IoxQ2^}pU+}i7an{|=_eGWS$ z#gymq@&n~Ic+tA>YJ5`OB>#wYK!UdLCq$GS#890;A1 z>wgYQ-`M4*YBgK%so#U|xgA5Ra*(joqs#itMIRvnB+e*sL3RgnIb_;6+;k$J1svTF z96gMS#qj?&5Yc+-R%q&wVy_kkS3yHo30Z*-g2(U8&m zkb{DGx6{#`{kuB^TNAW}+$G*g7dkw7A_2P^o-@~FK~3)K@d7JVmWHA-&o6f!D4olS zmzc6g1x4WUKr`cP zYImPVmi(afU5O5;>WtB`)z)P!JXFP#XxSdJYus(LXU!~Lz8W>hRZwS4dj}mLMx`2tR z{?kn_op$LLa2*FOR-De)HQHuArL64>?`It3eLbE_b9 zdmcR;N;Ic{XLzGxZ?wnSqFK=(F;tN=M8Hr~~nNsKwb)B3*t4 zO$M(M`wsKh^ z3}M(mgJBnD@!9|6%40N>Af(A*dBA`R20nK5tCl?$c0Iw^{L}#ljTv`wg=mI-S^hBl zagG5<+9!vvB3B68aE<056AGeSvJgQZ_=a#8-%PF_c+hAy&GNxJQvt%HV#)B9=&DkN zR-S6cY0;@*(2`Lw7lQ}zW^tx1bBm_4vgku+nOQ?-Q7J~{NFZ`VHVqyLQo_;J@_iz>O|(riumUacyjmslHz z#*;zXE6+`XL+49xX{Z~9belf-kjsEvVJ_1_Vq9CDBxf~v7m)r3DNF?{M=#I8+fW0! zj-U-^_|;x2Ry{p+R837W-1W6wZU=g|f-yY{VSZ;4g*PCspyWQrY|j!LtuPc$9Tg?aEy+ zQgQ6EcD}|Ft{^}vxCaTz2R*SV^Pu4pyH|rFE0UNc@>0GD}MF%lHZ7O*{c#fU(Wd;Wm zR22dPX~qfCuT}1_UK&U&j|MP=RXisK+jV`K7>d)g&*m8W(0zsKYz3ku zSoNNC#++S6Lhg@(w%0|!(XI(^v1#KOqr!^XE_Gmps&3Yxwz|wXx2nd5Yab`6VX7KS5=-bN3H)vz z*VK8d*3{2`M4Pid>1~j}aKTAUV=fEk2D^dO>?f{W05J^aS(6amB(|DAtG_3xa4>jK@?@KV_!>}W8*&j zFos*1<7Q0O`nqx6nUY4{O-E$(`#))iq+m-z4KRMWP)8-0Wax&L059HI05T6|1ue}% zu^rOTFb2j?X_!;|M2$(8S;swySThIRCEUqM3-S?3N4w=448@Y^n^Cc#014eu|9puT6- zvIas4I?hQr<(?(tk&XzS5BEgArXi{HKhpsI#|6LTC-&EO3dhhxmG7U`yYC(^k%4f} zJOXBM|IF%QD5SUsl<)M<1+oYa8*saTF(ew8cZ)nC)-Ev$1kz@>LF&iZ z^S)I#h8I_?UyBO3-x&M9Aj*UKQb~McKOCn8#tKG=W+CCHR6S=0C8N21s?NaSwGoHi zTT{viPFk z6{r##Rfo6v?l7qV0TKk7j5~1JRI+kQ>X%B67H4Xe`G@te{cV$2xoiDh>p)@;e(VGs zmEIO{6Zi1b2ePU(WS6*@i0#O@PALMVS1{=$nNfV*G0f%!_PkCX@j$+`7d~C!>0&F+ zN!64wq>(F{eVu7yG?cpJvwMo(-F`}3N;^OYGy}NI9y!8Ol|mzNP#v6~ilIsw?o7jYw4+dkM;^O5>>E8YdA)L!8cKSlkIUMQfN{AG=x zaIu?6amN-7^uc)X=TI-cU>&N7v*bylOio;8ZGbn|X~6ThxAXF4ru(gJl|IePlcVf5 z*vOPKUM(r8=J(?kRi`DiEDtH8@U`Q2sXK7hU{}^vM>lqWO~q@I53t^|oVwg%UCYh% zC{E|q$LgTH)ylx1iUdvBsj~*q<;eWomSu*fr&BAeb`wFxj9Db;U^7ItbVq@`UDh*T zUu{T@!hiE$L!M5K)WlmlG$Oifj+<}iEg%)iI*GcK$RG!}32i6>(vA~}t7L7Kchv;* zydDduJMEI*dghEODAN5v+yE(Y8oSIFMT zE_Ctw)b=;C*Y;WQ&XE$yW*+`OIeCUv2Q8d`(f@+-#`Hj|#Z$u-TlgXeDfXIiA(iW~ zaJ(l9ea?(H-~MKO9zf91p{ks%hW21_XHw$;Z_L2K1T@2oP65edvCp=nDAyjYW2d2K zjwk6nNNLEAlvbyiE{|^E$3CiFliQ=7XP=zDp=8HFH@+ck!TedweHwHID4`e9Q;F_T~5+daw!cj1Ll8CyKN}Ote0ytn(t|`oLDmQlgNY;Tr`#3ibN6S)b-MAAKjT1ayFe1P~bPo5?Gl$c0Re{ z->TnO3CU&f*+0fEH!OU+JGTgN(myV$VCBT=iO}lYu4M#LvTT1C0P%`U8!Xe2%rn7U_EiZy* zB5{y7{G5Hg>OP8mC#gZjVZ!*szF~wuanK0nA+g~&gWHn4ec=D_5obhgHHYccE1WlO z@6y_^q*Q2P>`DE;@R3^c(vS4R$PF#W8g-O6tr^`_OO#Onq0A=4QoJ-i9G<6R6?)Gv zh$0?BK$cv$cvb}rPykNEwRYjVW;*h3lw@wT)2D(N>(9t|a1zgo%;ftSb?+v+PGMu6 za58@LtcRu+mDcrr1m_tA0ysiT?XOyZBDdyOrz3XGHx^aFk0ybZ3ltb>wH#w6#8mYr zfCQk1t(50ppDFtukw=pr2_5QGJHpt1E3QFn-M=)Fx`-xuU&sv=495cfTh6~Mb$6?};MTB1mU44@BEkz|FMl)$!_ z0pw?ds(W|YnRMsQ1K3}Z$)m1}X-(W}zyh#IOX&rPJ;?t|nMk6O3#BVHZ>UtgyQ^MA z66pK5JXjD6`D7A>jjP)U=4pnH^Fd`!(_B` zBB8CwR7PFVz%ywawX?=EkXxxvpSu0g$GG;iKf*d=IcjS)+$oSwjS9PXep{)CfL4&n z$xE{YB+UBrpAOtkEU4ThDpSo~HLeU{M_@loC_IT}a27*V2kbpBRiR4{3R?QiRLo4q56YvDN3qOY*Eap3RhW}Y<-81fsZZ**-{SJGd$|U zKi6Ykx<{f*!$3BJYxy!2$GMrzTy~}#B&Cp}Da#ved_*l*&*?~bcm5~CdX4;U=Y(&UR-w- zMfOUA;#=F|yh0i*i`no-PJu`&xJTw5knn@p!**)TY(OVc>R$<;v7ay^fs&YEs1;H7qxYJq7#79XOe?%AmfFsb8cbsb#3Zi#9? zLb3SmVp5>BSF;C-)S!l>0>9B4G+d8~3pB|P_`1+nElk8+Jgm-A?NO(-)P77ZD8bv< zeqs#bTqco)D7{T%IHqbT>RM%77WF8wIZM5uoblz+=}f(y?B5*s?D!?AL^+aXF6^~uNRc*AJ69}M)<(XmZ_B(*I6q+N(H!OuN77vP!gA{uIdF0n>c2`pm+@)~y9 zlpw{Uk@P#*_&V0<6C>f~dJ9BAI$DNdM*0Nlu{2@ec%kJv=(58V@K>8A=nZ=vI2 zFX4Qt;o}NP{_j3|3r-R=hO5Pr2syQ->0%=x?=UEelt#NAf6eI@vh;USx|)N;LmsT% zQyhM$>U;fqIYuuAbZ`$^eqIA$i5<_XGLI*`g37W`3gVcP6h-AP`rh8Btd=DsvBB_e z(CXjdmkS5^W&MC|;Qbg!w}th(2?RlVN&vATt!?}rfzDcLS3=P%k3@Wc;YRzvI6twVSv z=Iz`ytLS(>kR2yQm10`g%8FiCQt9fDh*;pndFMCyUKoF)KLEHK=z+gH$!jke3KiIC zh-xY%rz4J2oD_AW(*39M?ikR(%J#$eRD*x#s}fn`x2Ujj+07!rmG|){@J;c)fcGQY zD4t6dr<%Y1{Y@2$o5hR?c%t1$0s+##fvuH*W@#Z5E}V(15dEgdUFgn?qe7?)bc{lK zB2BSZ7qos`l+YjSuok?9D_)*#=qI2bGZDJ&+iz0Tf*sb~6(%bo@u8d_0q$NlF|&ph zYEzCpKj}B)*WdiU3Lewt?^HM*sd<3A&kE1Nxc?Kbb>)Wl$ErWEiCpqQ66sq|gf_`B zTfN&(@@VV6#<9#`}WBRvLSBpHo$k4h8LzK83tJZ7mh^J0U-ZV-HKK#>YCD>(_&E zocHnK8e8JRFE!VQH1~nM2*rp9@IFAOZqcf(s|$*+9_HzOS0{WLl=*i6SkNCh^vW6a zJFW9=;^^7Vd0AamAtn&jjFLE5{BU_xcbZoJ)1tLKDVO2RNjznstP+5>mXsDj55(+T z`&9JiCUYXn!mQETWqiV%48u(v8%dhAjlcmh!B1?M2?JqQwNmz)O$q_^yR|S}Ibg>p z9|{`h5V60NA-z}r*GY+adh0)aeNQ2;b^oD3GxFtaj_D9~^FP6mdE}>gtQm{#nJ%Ak;U}gb^^4f|D7pYDxH=Kn%|nkm`v)nMkUsGj7xncooIYO~z zy!xrL15L|^Ng!vI=(XyiOv{k>jBGSiYNpir7}y^bbtfaXQ}|JOXrD!;{n0vjVn5YH zp_-TB7}B~R-zAF{g|Cg=F-A$wHnsrnMMxfGE@hytLwo{-1yUwf3szuzyccQ&i8bIP{Ee|bk~q+vqGBml&Ev{f7vm47Lop2~ zEHKLy?K2^{&=U4-i#;ndB{M8_&Rb3)6xW0d1>(i#!B0S%p3?MXA zT%lT^s83JtN~ojPh-=FfGWY9~T%$lD0Y|Q%Kg7$7VI)~8z5n%ti|Np|+JYpfHOFqW&J^Rk(Bh77n zVVPIz-tIl=PeLrlPd}l$y z^&@0gG^*azSYcWXW*W*R#sc2>u}04_GL_GBvck}sS^>fk5Hk^iQ?PeEVDg6)9s>~a zQ>lfOVn?V751CqV4e}q!^~hWOQaiwY&o}O^kX`#bf54^GKLsUBvB5GFe2RM-9ju zB5+PXYzfGro{MB<5oEEFY8JgfgP6axN74rX%8ru9ad zByI{42E=|M1`^t5lGUXys3|P56R}>_)b+dZ5}zHL(G*nIE{u(RIFqRs$>(J|rr`Js zZL$ODMOg-~E7_SC{~myfXsTUjY^0J&bqw`bGo4EukHT85a=Q9U(;xTI81!DiIqX=BnYiloKQ(mf~JDI_=Qg6tEEpCpy zhaI{Xd3MC$>L!l!ZE$>pWA4}KHcoAAy@M*S0GmGlwPd}`B=dlE)H$h8+>J=fhM`I0 zb0&HKpoLgLQrl5}@PCwo>&k;1rRc&vprGWjelqd`D?l=J7U14^rVa4|ioiZoK^kBh zvF2-svL~~xIm_<_wTxF@PUQg&XrQzV4d5dyuOgy1204Ipn*rhHWEi}B-HdJ{;q106 zb<~aiKG$DqNFjM#8~@k_eCI>7u&vYLf!F1W1s;@bj6_)#5z4wubZ#aNxHC8q%psZq zm3;_SpHwGk%q$tOj%L}L0SP>}FRb13Og zar?5IETMv1@G3f^jkQ#TCbUh5@CLZOjIYt(9>Q_??vCi7;;1;J6juJb%v7oyp8vS=rlqIVpm+yG z#T+6~amT5@ctmBFioj$8YesyS z)3`xc$)*>apxkRW_gk$C@7SUX+K77{>|$J8|D>_Rp&$R#1l}a#3kh>_d-EMrMA`<+ z(E4`rV8s($=+&wje@pV9lxU9@?$c_a{eAf2bCL za?JVzjj!>XUjv_+$FXSWZ{2=M@ne297CkySo3TF+PTPrN(@xwxVcSTe=dNz`?J@tj z61Uxc>Thn;szAmg!cXfa>o9Q0vG}b+J244+Y zK@{h)N6wBd2>k1ja^OytouC!o#kBZ?tU)63s(Z`bwId40UbKoanRV1FzvWG<8v-yT zT%zU&uJ+emsqs?MX*i0IkGDT{)jk8G)M9u~EVaOlJRi-lLWIbarOS0mcxE1o=);6x z;PKL5!@+&C&`7}Um%GLMECoD8wi4U$HkC8RSP3giXfs)QQt{AX4LmMl=ifjv(%0Ug z9YNNJvd_HyU(dXfRo%vb=6hktVqq_^9w4!e>A6^gw?P!1!v{I75*;^b`{^Wi5WrO~yO=DHtwSlf)ON&4o zc5$t zrEC&m-4Q!QfNvgk#JS%EM+KNXhVcU!#Kg3kc3xaLS1jCH3Wo&|XQAPGnZ}?H@Z-xD zen}Q&uLFPq-(rf>ms114cIOSHKlW^omR zlM<9Wqfz+xI;c3fq4ZeasaKqm*qYJp#tMLGcYvt*7W%`+w3rTlvl*31NB_5gMMZoo zVJ*YjgAS5eIQ#(`IPqNKOMb>Kwj#7I`)7Szw!*}tPKz8AkN!O%%vdM^cSVUvdXlM^ zHibpsa&JPBA^*DI-C06S^)*s0_xA#lnT!bdonr(;U|lKkzkR#%ZlcHH;`p%YxvbQK z;4Zq8!zs{)rNw7~x}L2Dor{0!HJhV+w1=G$@!y)%q+W)mvwlHSOdOm#tZI%<~Ug~ z+P|^7Tka5mdnjS%A1{3!;0afhvi2lOipcUQ6hf>9fOt=f9QcwLH_`<8_C4YtHBq}rP4IMe>^7wr*t#U;r?b;(BQdb^qjrs2!3MCC zZ#F5N!^yMkFMpf;)8Iwn8J?Zr?29-80&XvRfV_Gq&4z2O;LSWlJI5~qjQ>*7paxDD z=PF>Qp1qty_2pTmirC|(_UIe<#c8*RZ_(nvBQkj+GR(=jbHBN%x22)Wj&sp9F?La4$;k9Cv3_c6_<0=a%9?v8R2WazcNABzt5PH6 z2xIEyV0IxSiowHrVgjcAp@nn8YnW%t!v&V}Su>e2NWF*h1n_NaS9z8P9c()P^=yUh zcwke2m&d7|is?soeEN%f#3%o@O^^2_ZBa7Ji-p^)oMRzdTvZ#|anydPLZrq*aTbP=)c2v)Y-W)52k>hej>{L)J6pP6cl&L}%ARQL?qR zzF!1?Q8G1D%$mz6_yL^}!gD=jHt6N8D`8HPdY0K z!_l|zk}tLioQhXn(3NAoABJ*uXFujfiDM+k5qF)OTL^^4eh*ax2ZLVPT&h!#M0=pH?liuUc#)e3o}(kdgV1j zeRb$l`SN=3n*YHIj)I0D}mD} zvUva*+L|C1P^D@bBU=)|3zV~8YfPoi&nYWiv;Qq`OIC-0a0F6e3Q(}Cf1R<*jGaD| zr9>^rX%eS(w;v&x3rgprzHA9%uiwFufl)~t8DQCnW>-k^kRauE;{Dr_&}3`-a;Od= zEnMI6uLh9Xgl_s48cSUdK;j8G+YFxvfKf?Ya_r@uun3@0bW7i;Z6n&~n9vP=lFHj6 zRmnh=2r7_p6899%f|6O3#JYwPXw~}EsX?Fuvb6&dTV8S=7!Sv7F1K!}NMN{^z>BqX zj6z5_~64!0N5gEgtr!d81nB{>9e-aO4?Iv#a5g3{Enk zqq(a^6=fNCmBg95Lafg(X^3*@xEjT{onpUk{mck8Cz?#qgxp#CTCng_b5Ij2)1VLk zs|yJ^`wP+K2CXjA4H`{uS$q8>RTXm3Z;Im|#KGJIxO3nA^oyr-Xas)#S8ilX3e=pn z_iyYFYrA}QNA&}a$rF48VD;j`rk_o9T4p*mI}79_;OPn2?2(7;uX6$0!UhQRuPXS^ ztT3d13FH7`h>-g2V-i(fCH`=bsAEr#nvSH-Q9{MdAH6{opLaQ1>zvVo@ciz{O1NYx zdI@=cld-5<%ti+K4O>{!TD#M=2?1N$R>qkN3w0i3G{vUId`hn>;Q+(X^SCc@s9)&; zm`9l8sto-BeA@|UZp7V#Q%L#Pjd2e+w`?Ih}@vG($ig)AK@1^->9;nfAoz z9VVB=LY$AUA>DU)Dy5mz;weL(HYX$ErCU+sNmSCPaok3*lYutsjVHboRbSYDKb{lj|59 zc3(MSf>EncaS*?LwJ!2syw1vLg^-FELuDv_KyCV6l8^@$xbk}7JAYc8G>7ck(z>gE zb9rbwTk{6ALuS_~Go+(} z*|$Pnr%dN|vx_jZH^8ZQJdX}{vTt-uBND%G`F$Zr804Y+jD72$MJ2mv=}0wkx03zJ!wkZo;XO0Qq|3IM0D?@8=30g)#tGueGzJdNR9rv02ZoU8Abt9*)yf_ejCC zEIZ3<+qb)7;rcgOe`!wn&(1%gGUOE)hPqkDzFy$Kt#p@YDf4Z_mM>hR;}@KjULKN+ zh2li`uaihDaY$$}DhZqRY!gWdjfkXNQA37)?L;D1mJt>31me$Oe7?lZT@m_S>ygQ3 ztCGOp`iNf2u^_;nz$%ZL=!k{3sHdV|goV`i6GP&1)d0sO3c%I6x77#t@W{NHrz^J! zE%e%w3E012-sJ3Ku@5~#RRJuTe9Sh9`|B~hecuV89T&AGI?=%mrdBmw0w3`L;Fk{q z0@QS7q)v4Sw~PUFGMJMO0ToREXF!<0!=$7sd>*ThFeR49@p|7^@qhusjp7wRTn~H! zC)xBxb;}4S^YcJOq>sY`-#C+Xc>1WbN%n6`hHy1x*5Cx-{qc$VO^=%$)xsG4m7xB2 zGubiGlUY}X@X}NGWsrWrlrG;Ou45497h$uBZSK3C)k2p~fb{|Qevy0qQ0Para*I7B zy1IPWX}o(=;&U*9G7Tr7hqD&#sQ7_B-;+uA^1Rqv8A!0Vcp+Ls$x19WlE~Y0&$;5M zV$RdA%4y3Z9(tLZ&@r9l2L%_6{n$|3;cNVbgWrJwY&`7a2aB-hr&udQGKF10t?aXW z@~*n&3d|B7$5G^OUWn@c{k;JO*!Wo7LBlB}>U#ny|UelST%a^D{2!`AK%~B(xUZgJ^ zoVd721SE_2ZTX!iDXk{?n~bUNC$#-Ks^8bjU9m(Tu~-g>Qc(Sl!l7Y9EXtw=_(;yx zKoCXZXcuYz+2TW2`_G_z86q3h?(Dn9&JKEOxQ#ZCC2d81Wn5#<-xBf=R`Fc7!2}t9 z91P_r!D)28obN}B105h~pnL$^d={y(uaw!Cxn7i>Q!(~UWq)HM4ouF{EKI+Xp#Fz0 zUcZ(xdg)h=4ENqD+1K=;xGKI!fk~i6Pt5bfAj*K~??i|u7>#dF1*mpML8 z5FqSzt%FEonRx#D>6nvhf}HkbjapM$T_F?H-@$sSEw=9Hd~j8!t_LkL8l~9)QdWYJ zfO;X}R%i0}Mo-jQIICgPj{P=W&5rdINF^V21u)W(Xy{KN!mC-X2~4aekL`+@YZi{w%8xu8*1Qo&p76^`AOb)^i5PoVW8aP(}fPX z%w9V2LQE!OSK*koav)5kLut>0oqji((Ctb3t{ z4Z>n4?mru5S0k|>&zajJjADtalSERi%jy5R5RXpK%e*x5mbo>Wa8Eb5I1z&!k!SZ! z*vJ=vkE$kBX$<-Q7$6)!Y9+O`tk^ESe0#SNy6_vNcWG|RWPL2(qpM<;jhGG3W0oE6 zh|9LuwuK-UQ|P)WV5;nEKRZZGD=GxJYrwA)b@sGz<*MvcO(wFzWO{OHS8T@gFyCz6%| z9EVC#ITsnUw+7hSWPEQ)wR;XTccHDj9a7djutb!I4YB0Fd0XS5ZnX#ind2FQ5sFZl zR78@=5yxzKFQq+es7ZKb*(9flWpG&L9(4A>eVt&S3yf&y626HwUIK8oE!5w5U-r0HWyj;#RpaB*IX4@uBw z&J(#@+n81A&6ADaEB}pqgbAuD?G`xIVaJBZp-%)1@JJg%vwgJ|G0S$~T5m{0^p;P% zwSE`&b4iAkaVo z0(j?BIM#l?6eSG7qOr!*$KM@pDO@ zXncnb+E>`x73$-KmF5x_a_FW*GVoW)+7$Ea!ahCq1U3Jz3)2=&@B8tDCa~hXY&=_P zIeAA+$x3a%FcWfn&p`x1$wyoyFE-AIZgGpYJ@d1DS~!KCqUb?*eatzUgkg;FOQnkT zIAAIUL2-lJe+Mw{>3=Rb#hhR;9~~fyicVXXQwTH$E)D!ULcsvrl1QFR*>zt_Neiz! z0~Iv&`3)qoF`q8wN9zb5h70_>VN#9!5jIOej?w?VXPliyE9P5!Kqfa{{Sje;Kj9Jz zFeE_I)v6f|FY>AoXAUh17npm#*sY&>j-(7H^s`T;U(F{UH(gyTe~NG&4B<(Px2H zU|Y6IO9hp<6&qd52)cng@(d_oIu!A@gIPY{_HyVCp*Hj9K(DhYd!FTM-TyI`-lZ;qaQ0 z+n~m3_@bj!ViGLAnqiz+C@=m7kwrO6hW~<4%nFB7@ec;0JDq3!bVE`1VC~By{vsDKIgmma0{cY>{Y&3 znW00QB|T*i5pQwUFYYKIzaMC2dh#BC+(OtIf1`69pLN$VPJ48G z`X5v_Fn#?uY6veVQ+oettK91nOqvjY+sr4M*J@!GnJZaj!2&Pa3)h|q?9-m&Y6}eX-mVuRf{kJSYQabWy<({VU zN%FXWFV96IF!mk+;1`>o#6Hgz)wJGd9p?6?k;uHo*VvtYMfo8Kiy@B`i%4Q#@|Hse z0s`WrOtScR5h07E(GQRpqQ(y*EUW}h_k;v>gj=?cN5a4DB7es>O8W5%y5W|#zJjLI z;n&xD(@Rdav^fq&V>j3y~?3S9%^zCBxeCsoB zpIKuBG^FDd7IPhgj)d#X45S$% zigy_ZGsk!om;wfb=lLaX$!7R8Fe5{FgAlmT_Z!P)SA>{dZ@aVJ)Y!Y!%|JW*<)oJ; z&MofbFkj|%>WXXBoKK_Fm5b?0l_8aDVx3M{DK1~DIlTF)kV1J^yK}iuo8@kpO=NtKss0un^OtE z81fG%bO%H*OLL2ygRQd-JvDD}^{I~glD`qh+h7eq$#j%SdG`{nzaI^gH=)qB!nLzvxb$U+TWSXOwsQ}4o3H)W_6HBtWnOyF;Y6)yrbJR_KcaeDVd z6<^x9V$dt`#LI@NqGQLIyAg`a@6aZQvgVklu8@#0-#VoqnerF`;S+c>V3B3_JUtlD z89nGR$F6|z6E{T~D4sVNO9luwA@h!r3sfE&@1}$sOKK%rmB*r#1?+Z1*Y&j2zfi*- zUa@f-a%Z|f!K9MuCmpR$CTsbb#xf%$CHl0I@t0WPV;Wj|yd-=OW6t%6Pf|tBAWRH7k1a zPeR{*&I#$T;0u)q>|ZdT7U1(r%v<|pX%_*1dUJ`&45D|mXKU`y{%j>i8DioK1b{l) zZF+s&3A6lIGX_b&e#PrCYgMvr5ZfY81cu2yMG9qKMj*<;uSBCj>B3WL*7d`5ytO*E zLK;|l4}NB>+OmVjHSUdVM5U@BYV16WkU;DLeGQFtkhMy17m*`@D(?af7&U-H)40C6 zCw-q`85)8K3I=+Jb@Fw)Z(Ey=YKocW<+d$1T&OTlcec9m$%3#=o$JOPhu&1vyDv(T zj2Uoyb4XY0V%KMPL!MOrlAIWg;zltIGQQ3SW~b&{gd7#ttAqDXP3h}#0Hu`poUL6* zdA2xt1ft82sow6wf<^=*-#aQ$`v?C{ohdJTVDYDAI_gzi^c_l(TNU0PW#I<8xx|9e z|1E3bO9RNGIwLCAs7BueAkysXpo+hq1XoEfQocp`Vd#l{+S5oCAz$BbbFY(+crPye z|A@s!P(Wvn5U~GD+%TZZD1-ET-G0Trsre%CN>u1<@t{qb0~!xAn>>j=?3q%@+m97rkg0ON0g-XXdn~i#2P%U6ciWx4(KK+jR-hJEIj5*KnPI0TNFHhI1 zsab-|W>ede&KHyYioOo{AGM5gj`fY*p_ler1gKnv5(hvbPi4`Ts zKvi#P_YfoYq(l&*(%8*@LghE`MtZP9mk#~y{cV; zA%C!$1KS1e479tLNTS(>vr8SLtpR4+;KtFt+65ulhK|wQp?)H3<4T>2hN?%*a|A;% z-ilnOVfwR%{6wr+bjdf=!2aI8ADc+D7uwcv;>re}S9WR85Y;x(fI3h2`PV#XUx;4X zlt)o0+o}RUO!D5zdQ`U1cIIvRdK@^-1-OMswy~$$sg{P72km2|A`JBGC_sY>E;zPH{>DMdu4u>DiMYIcNq;?2mIzBQL z6)oq49nan6nV_SW?_KPI=-w}!Fr!)IH33g@DN?Jwe^y3`^4=ldDM)!04gjC;4rV0w za@C;@&?e|MxewK}VtuXTjtT*^Eng^_KNUv$3lvH0@j^(8Y_zGk-<|h;ZJXN)ZmL-a z(PG8(=6$Orc9&9J>93rL<}s;s<0d9ysRRqpN=Z7@TsXl$bLcH z=p_6eu1JiX2H_8j(=#)1kHuuIO#&FeU{_+v+qAExkzU$qW_Zw7a?u>Fj>w!qrl_ra zYK{frsykM*iWTT;@V!HW4%HD6v*G$-Bc7aJ7GV{;B*jv<13`^qZ1zgxjbVaN1^mBe z^$H?^^M$H-{C1D$6XT`UQ^s1cBk1^|H9_&D3=&k(Y z0;x`Yf!`F6i>~w^u$t(CZgAKDJL-|DNbttX)rwDnOhb`g9eSCk9)Kdu5Kz=QoO-lr zqaf1#+nHRyTXqX^fl<~}MF7$ckj{Oe>jhiRF1b;P7~s9pZCmrugNbK6?AO#uGmmN{ zi;(8*I7&IN$4rSJhZM>b`h*PU)U)3Q%Ws)(oAsoi`2tTYU)wUppXPvF`U5Nm_AqgUE^+*!o;wDL%KNHH zU`Ub}jUc7NEcvsDF%Mosw7|uTvR-7v)xUA!ER{F;Q&*;KWpD>v1l_M!P#3q5Is&qe z)y)i;t}G2+gOOL>rKO_Jw;ywRj%G>df{LiqN7Y?kJekb7CygNK@BxTA9YgB90J$2x?Pf z$h$*|A*qTurYT|l1y~_Cs>T>A-=uDJ5`n4vmqXP2soSMSUY=CarhR}=wn90`t}+n` zsH+9XkQ$Ay_iO+{KxRqxxM_|k4{hh1>8PVtf;YwfnHRn;RhlK)Qj58mJ0}|Kh(&z# z)Crd$(Vh@7{8B&zwZuJYLS0-O`3t=Rc^9R~NrDuh;*#H?N`OBkLlsmp)jI%?N(&3q zlCvArXjag+yUEe^0I?gTAY!-4;Ch?-evT@L+zjFpzCXt;j%Z(u>gA1sEwQhVq}o2G*fxZg?@BS>s!%{!WZ8gZhpVnxF+6n zhG-OJ-F7F`@Xw2x3cuh)8EzO3KH#v;0)qYXVQR(<6A$mD@DfdYb#sL4fN?9N3 zHx_*_>8H<4=;=4`idzuuZ5A>to*qQxJ;TxpqGNfLv0cC7Cjqr%Pi&In`tLIy1rs@MlRe}go2YM2N_k-GM?Avv`n12Vg8nP(7w8?*th#Id{x4^_3(g8jHF*> zmSALT6&7ymR7vLjel4!E00ClIIbEUmL@0ipLCo(g^=2v8%dk9+HePG$zsRz&XbR|7 z-Co5z)mSbPiyhX@1HkysEkyVF3BLaoaSF#J0Sp`Dpm$-64h|gzt8#oZm`QZAIn7qS zN$mBe%YY|Bh^sn&?l7ksAi&yuAZ8F%K1afLhm$lk?acO@NaIHJxd*7d4(HH0n>qFz9^lUMjXczZ#PN3sLx zypH0o>0EyDNq#MH{^07)Mwy=<%+0W!`PB@-PPtmCDOejPF{C*0Udv5CIzA>0!^X8X z9ED>b>Ms>I&ln|V?wl?mX|WBa4*BjS$Fxmm)OBfC4nw8um+!(gwp-m_bXX3;?x>Ug zYN+QA1rR~CCgfN0F>))A9R`iMtzk^1+vUFZbmlSh=XyRPaCd>$o&<-&WU_Nc1(p6~ zjZggf;4%YFDZfz%1nF>aBzf=cC%UTEnX4e`1381=z-0A>(pt3z;AU3wa#2 zP|Y~>(gT|_%>_ubW2yunUf8S2RRBI2t7zKqp6KqE`lpdZfp2z)%WMn%I`oTdw^e#? zZ=-2-7k~ELo0;aC+2T5YB3$CbtktZDuVn!-to@OwYQz2>%jPp#f5|pNfov4)dmsS* z47NaCcGhpeUNHd(yY_lLncI7nau?-WsXc-dp<(<0W@?z}03JSoS?YRVa0}Ckw7Nj9 zX{dD1pPL|TivdARTOmu$>=b{aexA1OQB7c4IX-E-^DSE-^4L075sP|NsBL{4ewtax|2|A)z2A99_Tw z00001<`Y<8-K3gLoibIb`8d@$&h!gARYg=)IL>7k=JcLD4?&rg8JT(+lv)l@IeHiw zkT5i8%%hbU8Za{;U}*it6iSSF(cj+n+I08HrRScLzxKzT?|J5TN&9)`Jo0w- zu8%q>Pn`)pEg0P05^jhXcrhSk(FwX3_wu>QrvSLgwzq1ZqK)Wu+-Uzp&x~U zamCyK00N)@=9SRL?zSh|V&^uzM%T1;elgbir&roGyhbk(i?Cwx7CQx=a(;4sqj<*c z8_qXq-J^Dm+AC1qp|*z1D^RVcmprq}JhRI@v&%fQ%RIA*XU^>Bmnm|xC7(R3jN({W zS>?%RS=J?t;>cX?SXj;%C|FpQ78Vv378WIig$xV~3=9km3=9km3=G3g20(c5Vn_oI z1_lNmm@qK*jDYZCX#*fV@y>u525B2F@y%cQOV}iAGooqCJ~$bGVc@{P%E5twjh+lV z7}@EP1~!m0Fu=$r3=9km3=9k`897g0y?WEvu1U^wBqjoBrbwKb^`t|PdBUJG(!N-+hU1 zo~4B=_+|u|@|s2JiFMRtHSh6@5e~(yf#Z}B+ITl<-IB)^?a^rt3k1Za(bR!pmvbG> z5xj-<4UX|{v63qGR&Y3Dwz-Q3Y9)l1qrqJY9*hxr_G>J7s=)g*xA;1HDHZ-ErPBD+ z4dvc{oZlNmG+Y)lNgZJwl){*#Ue9x8d_(*)hiHqMJIj%Jghrr&?IjL}_A=8HFE}*~MX3m(-BzHmGLK{;a{A8K&8t8`XARmWR;u9&JS>X!bvrjgF_L z`{H?EfI4mH&43B|s8W`Vcq-mB;`sDby`#+^m<$rpw>?p8BhkHu-{&=G33N>Hy&$;6|%#Du= zhO^d76^bt6_|TTf>kd=9F6AXB@NIsm4c-v5$ND8@t2}T=EBisof=y0a)b}C@lm`_E z*I@6?U@Vr5C?(EnxPg;;&eOk-o$0zGS4z<(X9vcHMbH*Ww9ch%(9J!Zp5^|oo#<_? zP*Z3XN+X`&o47^}MM4JAGBkLYbr>R4oIXIADr0-cdQYMfEOvCC?OGHk~cI~(qL7Qt~# z??1NhNnsOxHg`HuaRA)HHMt9^WnDsUa6dQZNp*9kAGKfR*rKF^8TyPRUOEOk5T}?9 zId`@zoY~)RaOLN0F>q=LT!B~c* zz{Bty6%62qg7)Xmi1HUb$zxRVOfI1W^7P8s+_@|^(kw>L>fVJ@Dhag>fosAxiQ~)5 zqMkHxNP;KvkJyQ{nI_+`*M>66yj``3nkga`N21$l;c@ET^@w|l(WdE_Kj^1afoR40 zQfyE`pvQh7%a|?*{(axhngp$?S}C$Ze!@6`az!KL#%^PfEy$O%M|Q^+o|8^Bzv|*+ z>}(Jc&C%?w0`5qBX;aZ)UdTuv2eLR>J8|rg+lb~p?xJy>=Eq90BGf)j>5}2 z95aPzWcdbO+dpOwO-Pc3t5zqZy4%Q)qr+{=5V05(u}0U%x^2=L=aN+qe-I`yywUB% zc|WVxYJXlFB3HWcjEwOtEoW>7ynYa;ZGA2)Yx!eJF^vbx_E1wLcG8?UK}JgAVqIha*yH=&g}S+fj^edFHCc~M>OLVrO`eUz0ZE$TIj>bmvg$nucvME^>X2eTwH zhjJGhqD@cRbpXENa`4G*m)+BW;)?gKY(k!fW^X15mZp_OO?4z{f0GH=xrxZCIchmB z@6M=kNJJIg*e}>vzqpZ6ou0{om~eCFs~>kiI~B$jzK@&0*}(=v!SU=LW}3O)kStxv2&Me zS8}KgnI;1yOLJROfOiNfx5+Z@q^NN(sDlOl=FeNpkL5r`w~;>1+u9Ef_SvUu9`eA8 zVh4JRv{1$!@z6yzqbnZ~r|Sd69PotQb+f9p=_R|wc~*^~dWP;g*-sW;93nwITdRRE zSq{%7NO>f(f1CDE6>A&#qitI`dOBMckQTLYU^rcR?oHIhWqek5(1(ah0pbP?Rfly_ zx0HnwXj9~-&Dhcy(vPubcH=W(_2@$IdWxHur6h^if)}sxbBVb_vyQ+R*@wLZizW!0 zatu9xMI>-C?SxD^W^g$FdZOoW&}n0&6*%b-N*?&cQhna zZ)gYAc|$!ZUE9b3KK=78XT(C)LT`V-n*2Wp^qBm<=YIny-ZIO3p*DNHw0-|yTGo9; zw)}n2u{Ue)jKWO+QvH88o+MuCNA=L0-W&Gc+CU)5-T@L@C~r%cQQd`_ho{1e%3t3S zw>61Zb)e;*?&|2lfJ&0X(Y}aOG&jT7`q`OfYKR*cSZmo#643NW$^#X_V;ujHTLKCz zF=OC&AJvBMz}vK{U$CvS-U7NnZlH++UZ0D;00V#lh?^T9^8gOJCGDwBetfSNx-C5anzWo++Nzy9KjMtrK$__w=#a@mUuG1|mtTPI4i>6Yb385z0LOIV zA(FAz5{%Pm;TEnT&-b@OP2h@$qSD8@J|3TUT=}TJ3h_)Ol(cS9COszLQI(w3xY(7J zJ>*M0ay0frc=W~(fcqAu{-PEGUZUY9+jt{{&AOGLWKeuKEH~wFd&EE>rjZuBK|98X zp8Uzw`hJs&SW^}a?%k`da-WX@XoWEFl*yCfyt`p-7y`R5dW3d+7!AHm7UV^c?J-Wo zf6xaMJDsUv#LpF*I+Da+bD8F=LIVs*M*<84Km(3r57g(~pC|yHw!d#!cZ*-IzzBh_ znLgGV-@^OpMr5pqhO&tWYtx3ox#|$bkuiLjxV`QH$-5=6!{gAR~Yf8 zLXZUtaCot45#LNebKkZSig{WB@LAm7ZrK)YGdz4>dg7#r+^%&m7ov6>)qvAB!YH7%cup;k`d;VWjM^igW^to{PHdC}LHx zoLncSQg1xoE% z7HjQ{kCyVtsSk0&&sn4qnLi5t_4YIu_PnoH&a^KVe4OIWDF+h!Niy}pVludw$BNx` zSRS<5v;IP2-*P3rz&e_arR1RAvo+ol(0XOi|MAqxoPx-~STddt5a27qWv6ix{r2i_ zrJLNejWIh??3ip7x zl^KC)fpvUk;kdDftr>Z%gz)CF9#OJ?x#O*y+!n0gavSK6)RivFbPqjTgj(Gz^rP%= zcXaUa$naDS3}z95?dnTFF=NGU#c((3hWG;vB)Tig2JHnRH|KSSGp2}!PC*5Iz+&+F zVkJ%kImi&0HAo1EfOHq5;>_^252<;Ietqtq#p-7xj{H3QXkjYOw%; zfD}cR1P!SOjC1?eFZQ4NYIOSh78Ui#a(S61?1t%YN6ruAR2i8JUYA1eZ}=fME^`hw zQFlEI6E_&q3m}&la%^iTe3VEp&DOV+2#FJw`gnGEJ~)@Ss7;h{*mB{{s}|-Q+M94m zOrjN+xQbn~gG>ey!ce&tMa`h!tJVJPH&3xo6ThMcj@ICl%pArweog63UhCYJ>4G2(LqJU}sv^F(Ynn zi?0})NsFGF-jc$a%^#*TjXHD(jdabCu>+@%qR#uaIkC`hfu*{atsLHM3^i_6nhjF~ zspDG#d_xZy8?@Y%>Rsk=jkRkuJMf}s5HCQVnCu+DJDPq@k=$@l5~GVoJiIJ)5Eff_ zCOT1DjIo!_+us_>4rote3Nl>_Sw6`B4aFe&x%Xq)&}TKHQTtwB6fxBBy}s&draDrH zA%|$jcgT59gZwCj1LQTCrFjH-gC6$owcO$tSsR4>jBWxnGC1TC_kHokUzh#eW9L&} z^EI95UZfxBmZC$z`gk)etmD+WcNPggxI51DDZ4lnK!_&? zW7cR&L-;&BxFKx1lk;>DH zZ`tLon3Ej_nOIl-9w1E_f;S;7j48@wbtSZecu12kX(PNW_Ms74IlI@H2jKgtdmUet zoF--GR^tQnP-C3{;Tbw+z>7_GoaJlkQ&mSvNXurm9(F3=f}#-Zb9xkPhWH%|YC}Z*U=d?<@(U4(l~!Tac!h zji0UVX0k>Qr5VR>G9h|0P=n`y0`^_y@MK@0;w z0DoJSkjj?WHaal5grVj8&u5nwl&U5!oQdn|r~RA^5I_gciZG&y(C?alIfLoL+oU|| z;6TC-;u`tFj&qD*S(;EB7Lw|N$n z_67lnQ<52zLvsWT6#e!URZty@3~q)ql1GJJ`pn(ML2HA6ekEkeWn@Mi`mK+ zrX1%gNb}Zu0c*kCur&cWH9{&drh;tvwtFsXX=d~@v zXhXIQ%J?D}tmkJp8&J7WkGlTh2Wx=FccUG;k|w4~jO#z!7m3OjSZ7b1j7$~eJ_{Nl z_o}ziO&!L$JP+B*fgpgzkA^3HBq#Y0LAMuNr)^`vpGAL<1MAExqL5Z#z_;+kG2tLV z?d5M=Bg%ycfp;Dsz&)_vq5BZY&()Hdkz~q44zjUdP zL*b!$GxPbiP@n!ot!x+g2lH*IkPlTTyF3Kvb^tL|q^OO*Z~7|HnBCp6pBQ?Dl_@GY+Nh%u~O|=rF>=L7`4E_tZVeN<2jcJRVfCgAw1Ppm6 zI&$WXMLcNPF|LI|3-B!f9Q&HJorRn#__!j4fS^U1S|R)2aWMz8taN$Z{Wr`nC1E|`3!}Sjy5hSo zeSN0qyWgm@bd5(4){K~u0f(OWa7j_!&sAuZU$z*U1q- zGQYLBbCJO+j+}h=0Zt5;hMz)C6igbbE#CrIIG+$Ua!^)<$FPonBw^>}L!4~v_atHv z+5vlNXw3M*s_K&Cxqs+_n?lI=d;i)@5TOT=wEuJW9|0eBkb5LtcS^PkhNmzwF|nG zJ(&9d_3YWgbvXf#cLmo*m!J~gQ+so%+|V5QUX>ht^*Txs^|iJR?9?Kfx_?4kYiGD~ zNTGft9e&M7k_TyL8T|8X@fBo8pB^(IEO(vOx4Gr~--V{$76eo&^m32MnS zxg@gcJ5%K!LV{C;hX=iqHk>=jGBd3@%JQ0K{{M1lM3wE6jY=H{L!jov@>+Zrxyb*3 z%lAQbVQI)#b+ksPT*NmYvp`i4Y$#xWHlUwt_t*jJ&rukhbr7Jnl;_$ovia?eUgN#{~KL1rsyzv^Z>7~bCpzK)+J6bBM#Hs8%t+?fr zL$qXNx;n}-IxQ&+!mRU+DM&q;Y{(T74wS zysdW$DshYZKRHIPO|D@hR_@v>sR?~8YXX&O&mgtyP(yPET3oV@w|f#zh-EeVS_ciw zcj~&#V@WWUGchQ28RANS!oAras0)Ne?L6c3$Zu5u{|4qi8`gfO_)502*Zi2wi;UIi z%;08$tB+^h>i-c0#wMql>K|w<>tCn$P7yBxYmW6e)cV9n&q*mV6@E%+{B3`#{M3I) zM_i7o*?Coj4x8mC>fBsFwbT6cszK+&Pvdr`*Agel*E`e#FYJ-;D`(%M8?IoWNx<@W zgN!Mi2CnwFZ%Z1owct2hpBt+WU!sPbZ7G@fjLOUn*)~g12HqOG+77gr z{p!NOXD`d;uX`NNlrE+*Sg=F4;sYJ~8M1jR068G&JO`G(eAd`&vN92mVFBO6lZtzz zdD;_L9nVmvHx0h2@#Gx$t}6#rWSi$*8hu#q-~HP?vptvGQU9@(#;@l0(8$Nn-W$tU z2652;3Q2Vvrt_#?TzYOPb-9#u#deL0DP1TNP3$6w{{S<^8PwDfI7{CzTI$@x5u%3r z=<29}NS418ixUC!h3Z;YL=7H=Wy{S^YBMM8Uvf`qHNj7u?C+@01rX99ST(=2o6`Rn z3jr>&jt}3`EqeOW)SbvK32F?J3b-;=1wPy}Ev?tU#6p){Ib>zNCtr8J&>C^w>lZ%u zu}n?ys%;0=^+?lJLyq&m7|31jBiMRX-4pjwTVG0GBlv<->{Jkt#j@ZYi#Mq=ZY@8j zR0=y(^6*ATkO+MLTHTnuFgV(xCWV+x=&~p<>-Rsm&dy~4N}QQJ3Wy*(ru@83YB$l%A+fb z()$~)u+8(GPl!+Jo_;a-doe0U!&NLJsp%6qzHHc}TK0$gwt*M^0!?A}w}ydCsK0!Y8Ahq5B^-q}!5+8W`(n>X? z*HmdCrmeH7aj;x6s4Im5f60vrTom+@EcMnz@Y#a=vIENsyb`|jnpoE{Iz@~rD9}5N zTm|uflyKx{34=HFw0~pB%!p^(zhbgwuTjx!BC~agm09a*lZ0ypHP_%d!pO>oH62gF z$vP`N6m-G;dmc&_ftO(NWuxBKVVzD3JId&saesk{L!G-?ZNHW)lu@w{rDj;6V)w;t z-!{)K1>L{`SroOP3guFs%Qc=@!F%Ukq3%L7Epk&YeAQs#nHoo*h8H?Kpv+oL5^p$a zoVF06>4o7CgU?m&vozHAvobI3eOk`_Dbx%@yh3Q^sd_R|`3_-^R?4pWayI03+BlIK zwKy<)zURKj-Ua(^j$xSqC1^~jeX@G(#)LR?q03iV+3hCE_X9?~{@}1FPgB+TD-dR! z?5MDuA)=q^VHObi_{*(DePzJK$kd%IhA6g;YrIj1ZG@QJAf64)cCQW?!CxxZPhus+ zGAE&`$s(9T2^^Hg??g95)+d8`?u$-_`wjvO+>fl{FKxtpcFJBjxnGwtxQ`QMz`E3f z(YjC{AWF>({aDDD8VKJ*m4z-$;mYARr?8a?sVhGi+o>cvo`tdA)vhJBt|I5JXPh6n z&&Ab`x`W}we`jHte?gG8ojEcJRcQUimwKiJCRDI7$svA>hGIUfnL;?E{V}G3cc?8q zrJxm~k`8$N8Xsa{2jw6HD!OTa-<A$`_Sm79Qq&l zs)?IeyRQe1KqoE);ujax9zT8=Vo79r)`tOqQhx-}qKqxs}imXU2N7g1uW_G{~Lh^^Fp)#DI@P$3?} zG3Pbkf*T>}#YWaRIqd)r;j6!HEehIy8|H*_l1P< zdvb6>ls!L04U1wqVo`7|q!p=Ni2Q(yHk6Y*FdtUXL2E0YZ@D(fm8$69dgUo4=Dfn? zz9^3~wJwx;(j3!_U^WI|5KVL;o*zkb4jTQ{v0{hIAq%8%L;mcSs zLi-Ls$%P8RVP012y{~(xoP12iD&KR2Mgnt7)k%lJjHEFtKXpE}jmp8;3w{q`RSV5k z#w4O9L4zW34@RMfVNvH+k48e2Q;0?uP(^LJu5b~3(yWl5xYr^?m2F7Bc6xeiFbx6Z zIcl@V%DMhQi9&&4U|Mw>viZL0%+tA3yq3 zY{$yYkBhk60st~PZXLaYh^I!=PS$V69iuN5+&55RE3|(b#U@pgfeph)$W<)j$8ilEQa{;_A{oAUhI=3b zTS_3=#Lr03*rG1_=>q~_CXG8D2W~dkj(g11H}iJvlbz7F2wD@)j|#7Cx;UvSB2Ge| zfX{pQ=bbJXJSTwdWqvbKa_5SB`E8$n^pRNrIzYw0WohGO)XA5sBa6$C+f-QD0f`z( z-mZ%)rpuN)=Km8FdA*7`_O8=6SSiNCQR;{JG>V#1{1AYqy+f3rb>AK;@&4aezb3Z8+|An?jalePSq&XJsE5DF^HU!ORd!9$` z;=|Vs;h<`-0d#!vZz9s$!G|KkrIU-$aLahYT0rKNfYUIqreI;wZx&vuKL7+H3oa-h zZ^7KAcUp@^KEEe#ZHf1;rNya)<4&WL=rw{?fj5ToTKgn?+Ula`S}bP%4_3kQf2wiD zWjrHB@wdh&HYB4`_`lJWK_)35w_!IE>NqSibq_eVNkN0J?pygV4WGh6vz!C_(VxB* z7$9tVjR(1pT3&JND-9U&131QY4!p0*Sm?JLAPJVsx+d{rVHAiv{M$tJh#MK(XG|Yc zlbUuy*L*n4kAK;A*d7bs$vfuR_Rxw{QOKO4?uXjh{j~r?CPhD~j_i#7yrIJ(uR@RN zJ@2R|m(hw*_@`Hf{x$d%ao2h@?yeA;CqOsb1lxjltjN3XjLaaJlxd+TG$heiS;!<->KF_)1 z?$2C7tBhhmys-Y8ZLDE;JxgDMcun7^oAUIk3IcaV+E^$G61MN~EfaKF$uy5(MLAyR zyfMkaPeGUwAgU!5*aXB_GheFhHlGf+h{yh+EE2mQ0rRywoA?$r+@uIdy=rtl#+c9r zfvD%a+M>DX+TNW+2!+=E^F3J{Qlr)1#x!xmHq*Fu9Zb1wP}iWWFLIHYERY ziKkRoMFCZwAxXnIMbW38q?NzFtMyw%xem>o5*EuF?B7xha%e8!@ZA}FRT{w!E9zd) zlrSrlT_OQ-d67<7hUt z(*TN48ftQo#aSFI6%P>msLDgg<|sj`{EyA4h1Y;FHbHg`hpV~)_n24>wnzN0R}3fe zC3peJ!s)VW(*4islRYoyy+OLV~c^ z5JW5JXPuj`R^tR)blNpkX~GUUGq<=h*)B2FAl5B3uVb|Q!!@YUZQrzcsbrj2WEvJ^ z!-eo7_Q}a9S$p#sd^_G?)@)5{9kkBlsFxN?x>f@f^lCuKjWL#E=UqULXPo8~C@L2h zH0@Ud>O*a}`%?^8*Bf=lR?@fa#bl|9o0&aEN zo6SwjP9Z4)g0#`*T!XuQh;B3bbXd^=p2Tux#b=et&&#I-owC(b)7!rgv<3`@=SMvl zbu1!U1X*aqlM%u1$2SWe9 zHwFz`I%x|o-y@l%rWYyAY4#gdzQFOCU#fG9m|asmXxcSun}x``h;Uusa9=;%l-3R; z&Xils!vlzVaMK`v@n>SR2>Q>;w1pjtLes9pFCoIVL;`2`(B#cE&xJk}39>T+_Bt{T zB6%W?gzBM8FEinFIr+CN%&NoJEW<75VXxP4n3Um%$?+DkH*Y%PsFN?$2#S31>XFnD zb|m$zPMG%Y`_rMRP?-e}qTkSI$s%YnTG@PJhqyi(d!4A_$%D(75J3OC36PYsF&J?& zQS3D}&=9zJZ33xBxXr3R7 z*HXh#-Lu&j5rMQ!|DBe5F_fiJqd20-NOvyN-=v!WdkVqhX`!LCH;AA*H99@~Cq z0hO~M`ao@>Upi1NNxP0r2n8w)_ybvsnznhsN*!c{->9(k+13KI|gNPC0q8 z?FpTH0S|AFU;P5gtTJs6beAC|A3{A?0&&_sCq(farbdGTP-U^5Uy6p6k@oC)ka>IA z-z5MQsI>u%!U6asJoD_&5&-AK{JDqI>>46pt)ClN4UtydkH`36HwI(fLk8X!tbyCF zY?Pl$9|fM>(IMzZuMOfC~ct_ENhtUP8^l7zfYZ;|Fxo#URh1 zPNo&hGZ39~X1h#qgWjeGy+Ubwhc1N8$Kh9lN9xqM9N8Q;!ByDhWh02A0CvgQ>)_?7hb%Ru-s)^Rg3$&XFn+i*Gy-+A}GiQ^92zgPS1dPQ{>K9D`{zwV*b^g?X%u{1kMEGwrzhs;kK`_4}f((lg zq{P*BMP$$b3Hzwp#?rQ-i*l1Xwm6F3f>f^O1{ZtPe|oW%i%S)7wF`~n3(e0s9**Qh z2G8)0b{Ec$Fc?}U{t0qrfPiFE*ss47p1Q3T(qJ2%`4aIr4WfXgh|Wuqj~zLt{%YDD zGhTFlRnS0?FV8bgW=6s3Jb*v-#?02RmM(!^jvX?wz0#gjx_)KcK&Um9WY7D%pzg?t zm@euYzlPA}n|JFlbxudj)1Mb2CZ4HjYZ^1gENhOEH_S4G%!6%G>iYz$uP@YCy zL$aF1#}j^WO?g|~{~vJO^1MTJ6}x)7A7^7Zs1gen20qv6pJIWslof(|^m!(%+~T65 zK;+(J)Ay3!<-ywZ2^O_+HddFd<_v1L>RdkTzx6>DO^s*i_O`fPB!+{_rK-!z2f@nTr>ZCjYcc@pX ze#GJwdTh@G0R${A-Y8yD*T@G)UyS3QG~5QHVlTac8D&X$Pm6|ETEg0`*7G7+3WO5N z{f*@|waqV|)vs6{fFSk*05B)s>d8Ze0-V;Uy6cXfSvoj}d1c1DT?8K#>9g5bZNbIl zXe<&kqV15#?u&>#e&$S5^}n+|3!Z7lvhIM)z~QjJ__A^V@kCL5s~+Wm{ikobcEA!0 zrP{XrG#c@wK>M+)avi*$6pNDQ=Srtey52rSgs>xr>1*D>0OY93#G7aYoWrl{CPiYb z+HR{3tXf;4mX9TQPKbg}l4gj@)#oWbkUMU_Ikx=SQYW*GUvIW~?Gxw6B+ML9b5wov z7<6$=rdnqyyvl_vI3ZHkay2OAu#e}!*8iy3BXzJW^XQAb$^-;*hm<*;**&_X*w<8g zX7#%-zM`nr*wWZ<;xnq7*aZ2sLH)y-5_Ej*TYe|Yk=;UMrJW|l)#f%!PmN>FTaSu2 zsy~W+^YZj}i4ZgL7=VZf0H$p1$u0s*oSolh+TO+ZJ9b1zSc5SM*C(zcYT^r0hsirq zc)nmOl-L}31Y$7ZKq*WC27hviQalG?Je^ytfl$|gg=tRz?F5X2RTnEy5Mmfz(b|&+VkhCA1(E*P6sevG8gt zdvnLTB}h4&UCJ9Uq{)wwbNH56yDJAjOB%&wkbzsHzN`$;b-XEfPYVGQ*fM+xZRam5 z`h^}0RodH|n62+YyhWAWBH_sY);w}GQZX$U#K2}gu*UL|f)8<{VgQWtZsFwG-(^RO zQ6dfH0g_^wUApKKHlmCTd74Or#LQc@KO3T)m3G5qh|1Y_$+_%ejIAI1j?dgtl^|I@ z@k$e@ByrSeozAs??&$1oUq?k~3u+EXJpvbPl(2dimeX_mNe$IHBG;|#@X5O1Z19nt z=;XIRk?b(j8FbQ&{#UcBW<{SxVkdZ5aE5X!+Y;~s} za*7OSMDH8Y+oi8E8`ilW z9>u=mVMlEDq_uaVS8} zlo2ee1f6TyJ1g!1UUWjY~7mMQD2p@>e{T zH4`~OfI=od^sX$mT;qo}yJzC-7ksgnS1W{QA=ti)g};WyWr8k{LUm+=ogi@QPHGeI zs^Ih(utoFgW6c+-I2c~(_XI&!?vE#CR(XhW`NMx#n)`%nYy`Sit3$eCM^r}w4w$4E z@f;!l+13@}rAPqFI#z4jrM1>djpB`Iq4Ivv74rzVp+GzGayB}zFgfFh29A~`F1WmE z83gxNBp{AW?fAtRGs`svXp9<6Q^w&D@xhiHrSTVVh!=Hu>Swhip(1Es+0%XlO2(Wr zjW2C2catunPR^bKr-m2VSs=rFgRQFYktPDlrw;GF7|KWxoh6*N*qy%DiK~=En=)qr z#}~H=)D%0)S>*u2w6U!a01nI^`RId7eh&N5Hl5}%?i7xJmJVWmoy8sJp~UoW1uNYI z7^fJI565s{9qAnOk6Aw=yo4)1WXu5zZUQoGjhqAZy(Sl=K-_(hm36YfQm(Nl8V-#i zz!hr542tkuZKS`%y5`|n2=k1$QgWcWRv>aOjD9cW%12Kv& zgqkau42o16igX6!QpXYYhMK*uu$)6@{4_D!9*-cllI?c8j$TktAlMYHX#tvVN?G3{rE+N>b=u zTg%&IVLg!cZDI8*c|#jI9qw4I&Hhab=@a^> z3vvwp7ZE6A(p>&T@TIbgUXD%G3)KZ3LtrmmEwyYa(o%wuc5d z7$Y1Q8{Fus)}6$T*R^%=&^RG(h}*^6DgPbbh(Y&XDVzyx$EO!b?J~#EM_F^uU;$*x zBqvX6Qf-E|+#lqj436JM!9iWs-NtC-8=9^aK15e1{>lnxnTpj_2?D}22xMOQmpT&T zQR6>4a;!1`ge=kwwc@4KaF`t<&{(yb1@Crv;?FX3{DW!9=vB$11$X{zm-nk27{&W$9aRZx6%wCV;MlSZRn|-GxIC6$c-Jhb)w6oPGFp^- zy<=0AZ9s7skRJRj?YNqW19ciehz~+_IbBGdP+13EqGNch`g0V>)#P&xLd%3c06Kh5 zte5QE(8ZISJBZDlziXrTDNH5)qL zc%;$>B(W4QAux*h)tYn;0p^!Ke6o8;hGB>kDRB{p1nBMNG>ku2Y*;&pCN?(r` zi)Nxc^koM(6s9y6ioCV})ODiNn(8+-(b5`fyOFWBho~z)`$5EXj98nd#N4`EcYK&dKV~?Oo3Ft&qFbzzR!4Syqt=4|X10LuMD1t;cF{OS z!@7Qax8!qK#zVNu;d0tR@U#T$s4S$)>I;`?zW!g&gwpawnwb*st^-Iw6gZwACi_ z@4n!j%qK+W+Y@0?>p||FhsNnMy9vAb z5VTPb^+lIZQWlDlbV;tdAk{9Se7iTI;*NNTFw(s)6`6DB#m{OzU$(8Vyo0FvW zT?SYbCxdl^VJnNK-a+dCFetW!=u`n$C0q>5m*xHDPBhcBZLZg;_RfwXB)AD|`)q^% zI1iy}L2ak>YX6>dhU05d~TW{qLW&8VP*vD}lZY1?5@H9=6Cs`0S!&BcGw0PGpO zcZcT-jSL%YCjRq!K_2id3jrm`$oZ!HzqF$lR9PNB@srg5#NZz z+|g7wZ>d-dAxP++=EGeO#{d8m-9es0c!WRsl+*6br2RcEN#hz(L$jMjumqvjIh@I+ zNaj|QWH|RtKnP+fM=yxaLc@S8jdgqWhqSR-kNi3g$CZfu8Mdg28Bgt zac<)sORcoQ92)ibw55v2Vekl2RhCgXz^71KnQw6CR%H zoTVzHa@ismu>^~Ag2g{>l2B_;9BkU==-RZI@HW(S~F;HvNP__Mxz+zdu(?h%$OCVut8&r24TqxXyf#&T1ifW*z0-@k>my0%$}y zzu0;l%#iH7za`FAh|yO*%nJW74P=>^4{S=WGy3y`qYyQ)^Fi^`tRpKrIeh~k00P^9 z&dcQ(XEd{@g=JMo^cZD>x zI5_^f%7O_+N7!Vsv?#n*n|xFK*-mNZfx7X~rbw+B>E5}v4dnKDvY&;}cmEp%P#rBL z>Gd!*I4FUD_%Rnz2U3ctd!(*(=ZH_OtHXj;h7Jw&b_V}cA~^!p+P$i6x32*TK<`gu}-$G zE?t}@Pk>Eh_POB&hBS$=*QhvL76uz%WSnE^Xql(~ekzf#&`FsMb09rZnkgvJRrgWR z-@qc%3%38ch3bd~_p93$THR0;sKRL5ij;?LesnpMSeXLom{MoBJirqS9?;1eSS#v7 z-H75bhhyasq~Zy0hNOe15Mb!nV}B6g)kao>SgEmD?OiV3 zfPk-EO<9TD7BTR~PRYJ9_ohTFdDxFgo6t>W>H?_xBrHTV@$xKM+8_q@Y#)NMN3ABi zCRU^L{ot{qybr#Vy#pU}YvK6w`lKHY0w_@D&M@+Yyk`m9+Rj8WCQMZDzvRC_l# z(Je0~zPn{kS=aT0ivvVSvUu7^p5SiC9Q?&2dS$vxNB`ICeW@W#d50AI^LGI<1hQkXLQL)Cuq{?n2xKwkTeB|;Rb~~R1hi3lXNL8D zbLUN>PIk$BpWH+QgtrkT4d?dU_ru{_%au!iYGoh@v1J4dNL7Qnhzf}3lRd*U(H4&M zd=x`SX2_&ahIZ^}92j!od%}E`M1WG;^XFUSpKmt9*8&DgeLEgz8D}O~DY8bzyzG)D z+jocNtR$M#BweW64#G9W%|y()UAiKTv|Vgr#G1E3D|4D6voSvqYa7X#HqjJ4 zruXwP3`gyM%Kl1=EGJ3p8O*XxIQ0MwQ0EBRo_LeiRK3xRTm6sCZ|%BJ!e(a5r0L~o zY=$#EyAu5eLIU|-$CWI@46XFlT|ypuxorAs0Qs%|QaD4*M{a06}uICdJYBwudNnvN>(BzvBa6Bq86 z0XB-C7^2bXO&cUF{ts(Ce^%!kpwTTDBlG?xCBBWew6v-8@45a){rqqmYn5Ma z&XycL=@g-&5zuj4F3nr*Qr{ofa2#3Qvndh~oUL!Oy?0ORnDfJ{-V^J08IP z!igy>SHs^erGt4S%&Pso7!3p`PoI;5Ztjq5w0i8K+*c{I=tdvbhi!B=6?L8nZBBXRC}VJAm%S&Z)F6q7%tV4M&Vz@ZJ0kRu zNDZY{-jE+hWDZvc58dXfZVs$mG<6##dLMLLmWHyzlKO2S22j!>^>dqok{cjt1P zZE9HZI&Ws*KF<~|Lp)?EJRE9|_7CLk1<2YWUXu%8N>OsrmTpNIwum27(z9v9x4O6Saoqa=?`Z-GI3A{ioQw=4ZmSM6{ zkofY?5v6~wItD0zV;8ROBG;-FwX98j8rXt{cel8SL5vXDfdIC>I1hq+E1HDNg`n_W_OV`f2tg)@6lSUsM}RiD>o?)yq3}dGbhD( zww3x2QzFjYs?)|+;K?&P!xVHi^T@id6uWo4zUn#DUOAMU&&zl=7)Mm=%Pq3MDO{d3 zWpxQ1Kcmf#+l90#`QT=hNtLV9y}_=%FO1UdRuewL!G86DR*!>@T*CNqR=k4*`vr~D z6COqJT&7zGGqF-2EUPk=uu-wH&vuYTNA1k)&Kz$QKI1rBq!Yp~n4F?vUuTvhqci4K zlXGl@C2Mb}Xe(5AKtg$t*HBN`g0F;s*R^J|7=1xUa}aQ?4J*bk&b&BIWJaT37&E@P|%SdUt9AyRzqA2BL0KOOGT9-Ohwj+pHWrvq*ZUU z?~g}_62pejFRI{?K$>hf0QnhWGZYkMyV&2}+39 zi`P&p3is;Z9W&@OJ=#0+VgW~8%Kgump$-3y@&II31WUF|U z;{0TSdW~U`0z9;Xz0@SnmbuC$!+c4)uk<5je?OsU$D@KJfa6k@`|iI24Y@uoIiLo5 z&cX(2cqQ+d;DIbjdfJHi7qhJeL($7d=~IU&XIkCe9 zX6)gV5re6J-_$YqALP^fyjCa4bBnR!rj%IkZ~sC0pTX05k|wzo$a#w zGbT1gC3=ERbN^TU5t2_#sg)pvAcBvx)`5rm_+&`Ztf>2WmkwbJ=x{)N^9;P;KggcY>h0ka=&i}iY~N#^0NJ2eX9*@=|%6MFHH~GMR0O#AEE~q zY-zpKeICXSl*x?>9n{O&&o?v`i6le3^Sdks8$K!~7|&%6wD6 zohe0#_(hr~`8Imn))4kVM%TsZk*lE{82vBZrjJYBUMUfhBJL$#BD4Ewn#|LghL62NjWpYvaIIhMJE zX?DkP`T+m8KO;S^K@(&B{ky3&G3CH@FpY2@HBf6*O4``Xw8=7Rg&ghZt3|m8F?@_! zPUYD`)=>fv8q%V0?{9fy!yoIqem7o9$PATtrXKHOe*>^ql~oe-^ZzEwnCIfh=4)RQ zeStiYVUT|c5eI5gc5Bi4#+y(wh6q}{@zZQDK9NGLhjN7Zbo*j0QtFAD%gj|#(nkdx zs=-HjzP?k^c~Jqx7CF0uEZ2NSs@tU-bB_)MSsxw~N1Mc}<|PF0FEmoJaq8v8oSLlP zikJ%i1XW2;R-RKDWXZAPkQ15CR6HxVJVygNx@JaAR`y|jca8k=bkAJL*w#VJY2ru`-er}lYI^K_n^yyYLY$oJp9|thJ&WJtsnuf#f85rQeK2myGdhMv)$mP^gX_<-X0&5s z3fYf&LgnS9^MGT9*06AKvK)w3P|xR+7?AFBuDLt$r?96|1Ilv%d0QKCc-d}tW1$hQ zA=aonn{4a#L3MVRMaCItYW9c`ynY=7dltGwlUu^nKlZyWW4byjQMEt;=??!Lz zo&ls=W6|yrh^R&ZN_eN@v>2Zja1Er9sROF`=>S6cs!{NL+4b)JLA$Qm*jb+tu2Jr_ z-umSnQ{P&80GOuB9(Hd~pUJoNGR{yUUxB&Kcutga(SDT3el}1CpgUFWa~ML@TrDkA zw99}I^S`3Sep&fh$UkO52+b!Yz(Jgp=i(|k$`-eKX$H4?D@yskp($;RnYa?^4uH7; z&Xg<-ipZ^&`gtK6%m4rY1ONy72yjcRFu!rjwYtq+TOE$AcrHW&3IdU^007Iq|HXf> zhrlA%zkkcCcb+|`TgN?#njC%r2LJ#F&C1H?Gav`+HYq} z!>EoahiE?wS+lmbX1bA0PgS_0S9m&t8@KkP9s=E~*N*fKA)T^}pHZE>o<`o$>=%&R z4d3`?T!Yw8+61LI8^T%{*I)KIIW_4R>cIAFOySb)fZU~*1L1^qAhT4OL!b+f8c%vc zOTjtEtf@(jl!I^+XaSk{zN;l5t&m7DyP_Eq*c;mGpIKP6!!RC`jjz`6dsiD7*5ltV z)Hq=r#U(u(z>gl=aWEB9U8}&GWU526NU!+mVL^XRz36I8cNsFCKA~gLsrD7vV z@aZSGj{^HMtHcP2B<`a|00o(o1eeXX`x&D0q{~6nD8U-PW*|QMf!IfI9;8xN&FBwE2|v<^T1>n!8@*()4iKXBf#1dQNmWaD?9~F{#>c z7-OgURjM)x;<|b2!EnIqMYi7l?_Xo4Z0?nd-a7}PVbsvzb4!JX*keotRsS}ruop#^ zay-~D4-wBO-8QHg!d8asDyYlk;-R0ZfJ-V+BvLI_*>A=fPW&Z}9rfPi^lKOI2r=^c zBM(bM`VA&a1{ASAVFfnT218#P$P_CqOGMdBZ-#EZ{~(8ZUZpud{&8HbNCWsdIPHzG zCwfGSXtNA&*_{c{05Pd@Q+>i5wmMiEsA3p_Sh7LVKcM+i>?M^=m-#NfB?=}9EIZa) zJ57Ni4lsm3L`q=jqid69G#S~lyL}id$5=C3u!EPN9yHyo#Blv1YqcL?4sx$K#2N*~ z{>71mpjc8M8Ua8Qvz*Z99{{NEQPd{x5;P=#K1a{y7Dh0DKe^RvKtzUN4b-|bYoM}q z*cz=mxN|BZbJei8tP(wqtGJ@!G?X%G4jj*j?W|@N+N_HfHWv$Uc;P#Klqw&(o-F3B z8SNc~iJFg!yhN!mCWXfJM_#84r@)}bKz*5;W$NWTrEVLY+^L)^?M5-PQC2@edch$C zIGBnBrym>lQ4vQf$KSy+sYd-fd8v@u#Y&3#&H@LKI0HCdzjDuwZFDQTAYX!iL~VvQ zc8jNwsu+_s-wxh4FkUUIRMr!yX?WZBynaH+x(2+I!5dlZNhRf<0)#w;4lv)+Wx=rc znUAOq!KT<=Yk^9EaeU{nGRCw-(0&EV*!J~I!ZCtpv-RnfEKERV^C=hhtS z;Z%y(G`5;_r}ZMUGM1I2>);I0HS4%h0ImXAQpC zi78L^Q!`e_78u})vC7Rnr?{k?DnCORCt0V=WyLk~%Lj&zDCqbo!we1Bd1hE0w%J8W z^0C6q$EyiG)luy#8!Z9O<+hbeSXJT24gHaUgvU%};eg&Hv8Nj|+F7q8!q%i)pfamA zy(x1(0R5^`IV7!^=PLm1b%@B3*2=rjo8=EqQJ!4LXhO0w15yY3k(KkNYerKYt0#}p zlP>|7DTf&4X9vS$BSt zZV53bD)juNAX>^BTL`3O3@puPQMc4?uNT3?{RwB^t5JX07l$|Fbt2)n%O=kKJeSgK z6Y&oUaXQ7V!;fg!P%qEK39PQa45W*6z}#(yqAM#%>?=`gwDuD*ipw6VQU)L+P3i7D=S~FlCs?l zCGB!*j!~;kStVkX37Tj}Za%Ze)m0;{KHLy5u-V|g`z zlD06ko>^^tMhX(gwGaV0)u28|E4;v4T=+k6rSPfziBf&-8AKKnA~Ar~ZHDHTvm&*5 zXUL9%jL?Hk33J7M8YMlut1xs|oM6S+|I|Y64W+SPVLI`>j2xon3~q0iXZ7XL>fb;U z8c4K}%eu~FA{O$DQ4=>Z@G&g@^xt7qe}#3tRn%)CNCDZ6|8L{jZ%eP_R>)&B znw8o$#IM5aiZ*T$w!o@^MZ-A=AsavUssm3k37@#yrk#lanjNDnZY1X(#JiauDM_HU zo5i~b{}frFei?_HZqDcp^t@x0ekT1o?v~bm#yktaAsAIUWM&?EOF5Mio1_4AgXW&G zD&j9IfFv}P-VXdyPiJWdpn#R*#Mtya($wPbW8`FKwlu(-I11ihtGZA?v9=J6=H2lZ zy$Z**D6W5FJhh`G-F`@-OTF=1lXLQ`{`j8BSR}KC55O&IwLM5xi^Sw`S2fV$^@{lN z>*@r03FdiA_KKP2oGmL&gN`4YjV0qE8r*C*9WUcUn(n(GnhXy6XDc@op|C{U@CEsz z{)=q>P-qi5lzXAvUAc15(vzMUXx67!O)!iQtIg`p{U3wz%jg{I9M?8(?I?Z*2CV68B25&lEZ|aOT(Q;ds_+c~ zz;y)G3RHG4`xp^^M0=x;eqsUlCuz>wWBGzaaYE;+lXEdK%NXn=1X{TzZBy+NDx?m5 zXBE6Q#+c|5=rNG4y%?AF1QUI{0i>d~A(kUdL-;tOuCJfW4O~AXe7cqrgM?^PaN6yz zLsgS!cTV}0TtGu6btL@+R#SkmQ2Ney+_X-?t&MC8A`M=Rbt((fe|N0U+Dk-5ydT3~!-ER;@ z@B8Pq%7^3(D_qqlz1T) z427X$Tv)gi(kZ@4hmES0#pCrU$I*h1%SQY?CBGAjh|N$u#VTABM?UPT7fvSgg{uf4 z9h)dtAq=J8AJPJ3rf#7ybYlw)*Kt172!3DP?>DDN;!@HpgZU-dJkT{g1+r!X=`v@2Er*4!IT* zWS79_7}q8G%ULq{C;tqZ*qy%0#LwlxtTZYLrqyR^4V{*Y^n12D``^mzfM=wiasXb+ z$3L#32CXXQYAyJT{BKEL8_jH=*|)SM>0((K%uZ%EkwYf z*0kWG;av4~Qv&MmrQc@dhZl*f10a)H_xfA|wo)(%W9B03)>4-J{d4fSNoF1eN1>0> z#QlDK!k5nG@vURB=GbpJ-E%;u4N0y`ql^J%`gUW`0Q~N4jF|mfDt9Xhk9Dk~us6%b z0R`0V#n)}* zQxa$@+A1LCHjFK086mAYOb@_#Igu3m-0LcutU_#Nblv7!9MS{nYqt=h z6x*2|6izxiWtk5bpd;RR)wh3)`HH}fS#|Jh#xqUTpXkxikTUjql(^CK@WFpH$NdTD_6faMWSfNysgh;axjxC&ObAKX`g5}$n^}1P= z2M<(#kZo9pUB0XO2>TxH83Wp`Tq2F>MNr?*Wh!mlFZWTY@Bnjh2Iw=;maeMKM} zhk>j5?z}w&ucr&xt}vpOn3q9b)gPXGg44BjrwfVFn@07&d3`VtanB1ph!*MK5lv14 zO(p;iHsNFWM^V&{CC&Oh!e^PX!Kl=llwK-RSwx=!yul1i%pTlP0HDoBW2A4%P16SW zr|gMbqtwvok2&SlyysOr5H>2dH^JnoY|a{su#NtZiijm?baMSFFOI3T*FljMZMW2Pm~# zFJ)S-IF8~Z>s;XJE^^7F#7Cn&8BqkHu7_f}00&}}a=w+67eSTiBnoXkZ(>9|Y>NGU z!IX?E;KH}DKa$fo?B~H}z{@++;-SL)Q#v~myNW30gb;`_#FKJ90*(;zt{?|5vLc5h zjGv!_EB-3N7%~YbdLJ}zGI}sGUgg{Fe<043IAuz2M!##{y1pym$D%x1zjDpG-N?^` z5Lh8O?_yqC4wTo!Jfaiv(e>RnJWIRg`-lX3WHUlk5cUs8^0WU=Px2KvhLZNl8gt2Z z;_C_XhhH-*tC&&Klhbmpr@#8Gh(y|92 zEzjSF{3W)yC_GQS_X76BFRl~VlFXUS2bl%?)k8BkA$k0AgzmjFu?}c!_eF9(W$O8TFZ{c0{siWSzaD5YzhVpIFTsb z6HahvBp~wBj;$rAzSDVWt7Ml=7?(@@%wQ!cK8L&9TE3)&1>~k^B9g!KCY|>KS&F@r z_xgZ$DvH5qsKRiT0ju>UqDO_Gou&0MHdWv@zY+F^Xmul4)yCEma&k&BxF)(92kv6n z{l<(MbK4&Fx}^;6b`RL%46f9+Bv#JZmeSJ}cz|BkCsWb?GMmkjw#RjKA_AEa<PU2SEtYUZEl>r5mcm+oSlkro7Pp1j-E_3Ab(P4^j_0 zmBZ6T?5Hw*hpC)sSzf%+`_4-8efueD0*UYnY`}7zbRnOEI*-?#zZ8+)Wp)5mrr*ar zFia{A0%aaAe(v#>mYB?A)S&zQ=|PQ&Q9zk~@r{QB#N`284H2wtwAxuA8^isCHYV1- z`WWtw<=o~*#H_d3kxBU>C`xQBtb(at6$I8l*hB9MCRRw`0023cL7Heus6l9%ObNf# z7nu3O@R2ia-yn-%xDC}SG9kf|SD=8)>TC@QS^n6In|*!RPBQNS8cvRUoO-TGK{d%g=ftCPP*}aJLp_n_ z40L3dNb^B#!@F#EEjf296yODJ5z7>3|G@D1JcF5YNW9{y;=+r%6Q_Muh9MoB z;2u$=aWNZjNXc}66^%%k`agy_Y95o1?J!s;=rUUuQ@d6O=VQwquqz1>hMbJ2J-P%h zLcH8`jl0!MgA|WeGzng}pwh6(G&~4>?!lag1vu%!|9(0->0@wp8PDqs>X0NTL*ljC z0_|hB$ARK8T+fEk?6*tQX*c**osGNg-)|Y?>PnsDG)YY8i1nr|=CnCahcV2<@6MKI zwLJXse4iQcW+=gXGm(3m7K1J-k_|bEP))W(7^se~!;Z(2t?r2otA8s?1yVGUsP})G z)RFqAt?v=>^+mB+8nV*KhX_?qB$}(N>xYt5Ow)>`)(brlgx#0n@uYtCf*nvKOA3El z>x=AtR8+S=s)k3L;AR$6#h{HgCz?YjCe+Y<{853|)3`Uga2Kr=&ne`b@(Xi%ZuS6~ zn0EL8w|tqKUm7{q*BX{GX^0i!BqjAQ+&y5Hf5W$`dv5UOtj`s+h{1;;egkGV++1+U zlFrG|&9M>1)^*>5FuO`oD7w)D%XK7J9@x|_-@1sZuLjJK1=T?pMcVdiRccxgctLY5Q z1CJQfrEmgv@lwad9F89s z9UMoZ-c)C~)?Uavb>49N3|FJi0ErhLR1E#(=yH3Bi+TJp zc&@(q28{EOt$CZ+6rsjZcO&VI#OaQv57zahLrF8l1bi~=nfoQH*nE_~vD`sZVzu>ac!9n1Q? z0UNMNAOs^1jitBK$SOKM#kRSkh^`K00#r9~BmCu3Mn0=N`sLG&?H9~O?zd>r55#*e zk$>;oQAF=4#;rkE%6wksG~Q?mv6=b`glT2q($xv#0VkWw)7|QW2ZUddGwk4@UU~b& z;l>oK7$hr#mLC%>#~e)%$sbD(35kj4hFn)=q=Oa{yrenXyC+ghNp7zpMF5U}>CFB~ zxYWEvC{>Vd1c~1fCJ(i-EKH}vyHWX(c$=WeCXFnIB7J@EWLL{)wQL2{j|B!Xjr2N& zTb=WO&WDykM(EdN)i-PnuBFWOs9&rH*OPE4qa?zs^njLY+k&QzMOkNs2=E2p*@TuX zFgEKGZ&>*n$CL)UMKSBPvcyIB=8-oU{TGDY`h~yMA#Y7!DT3oHunVJF*~y>OplQjG z7)wyT;A`sHcTpTs{yka{{$@ZtB?D;hi-J2vQ366z>#T-{YZDxY59! zCWEtMV`*e`dmYAC;~8KOj1pgEKglZ?i-`b2ckUhV0sw~4T^ZTkSC)=^s<3OX0(}Cj zwOn&Bwa3=$9^+Ien9Yzs-r42}dN4$c$jfH_qD=*}yD9mibHd z&rd+u)!nU46fxT5tQIG>@K}%ym2iD>ZdA(i3I!tY^J$%#>yTa2VUy^uZ;>0gt!b}% z(ES7>h>IYku_0aC}n&oVGb0;{e4tuz~2NLzf59XxjX3s)`bilb+L zl0r|d>ojDlS$7;K9<&c9%H|{(dI)$)sldM(*Lm}}9@+9x$Mk-yNE4aC`M#!|OAgRu zR0)wg6}krNniZnyiyRwbLcu}kA!XP{{=};=bKlQ~i#ev=oWuSuhh2sEY7B7V+!%=r zU+oxK&$;NX3DM^AY76b02798n!+)P9S%Z@0>Xp)Z?!JAU0B!sXa+ z@8+qRx#9aI$qHm#5WNoalJRLurdzw;par*#ZV95mogMVC=h$rcV-hNvZ@Dlb+$vVR zf>4OzYh|GzSj+iK#a+7&n#Urck$nm!U18UQw1h?TAS70 z%A5J}`tf1>bpN#0c{8ohBa{R$L{&I9-L!ytgweF*9$94JFTMS;0_Wh98>YUcEG+Nn zc4lg?Ws=Re1M1R5w~GskTa>Gqm#49cT*mrzIrs{N<;!daKcpo+XpYmKzo(OF?Y8Cw zisD99KUjEhIe+rxBy`SFp*`o)5f^N5Ihl}>go-T|WRR1~$#e}GdU8HkvrTLWnkt@j zjc%7@0j)D_Z!Ec(&-7XxL}$7ph;%Awwso-3fTDAfMSHl)A;&dKd;0Qj2XH0YDP^TS zYf9m~h1#vg#h8j9sSCBS=(G;y(ZKx6=kK#f2DIdkP@j;O12f&P_M>kC*CE(-?mZFF zdyAZuo6G43V9v%}RsD&)T~r_Ko8up4wqRpaRCJ-^-6a(3lx%XF!a`Ez&{wyu2f)X? z0tR-=Z6lZmx5=0+V@tmi<#oy!;BXEv=TU4+-YxjnJ9$|y^Q6K7%L-d5Zh9wvNA*@1 z`rZhr1uIFYG%eS}u-D-{ADM^b#?0<&sc9s~zk;n<{#!tYhA~KfT=l%jpeL-r^!AIv z{T#OSt;H%;7ph!78STG~N51DXjK=zSaH}-^5iyB7TtyOb+D5y|4Kp>sa^z8i1KEJ} z@%5<)g;lGFx20eifaXz6zybcMe{(`AL?cLi`J|PI(fB8kA)X2xckk!UBMv}{jz}tf zHSOwcT_5b~As2=^776qvtVXO+h70?6Z<8W~T!_hWCaTdD2C!)DP|?kIr+PSur%|1e z6cAD^?zpGVVz5-R%lsmJ+oPFj5ie#ApE#6?2*X|LKfH~dSTEXR*3{7@8;`P|v-^)k zfZ1d$X?3CI_NV+9evv+|JnB-)B&hAuTA4XSfDS%Cus-M@w&QyksH|UMhJ_7lTkRn7x-ZF}r?&9hNyKRYKPzS#g6Smb5#IpFNqa8GZg| zigQ8LvcdVEAwPXH8)5fje~D7;Ih`5*ol|;t!u7>k@v@R`Pez>?X000)RgAkuPYHD zsIWHvVO)$knFz)mOHHfM{kw~0ZE1fIaz7jYJHuQx%6$;BS5_=7}T!`Q4OWe_8#D__k!+=4r=Atk{rH*li$G>mE8im ziEcdmRw;LLjUT zPn~nbmwk*OC4HQ*i?j?A5fZZ;d`r_y>jW8x7jhTlhuYEXRRM7I5vp=jdTdAfEvaz8 zI%U5Hw5^U?em291Mv>;y4mYMeJP!-g{!bS1uOWNXgQaOWT8~UqTVjz2$GIu_0?GmJ z0mNjAQ^C|0-1w8Imw>G&X5XlOVKLMoZOp1EgBh@M$lf_o zT-7WYyb}JX?E!xbanm8vOc(3IYnW0+v-;FojDVr}c_*89M$d8CFUV5G=HN^bdwR|-7FMIz710UknT_OrlyPdNG4?1x^YrIbPER+zcL^HR~0gi@?;(@hIjbQR)Z_1D{4 zVCzZPhZ!2q2ZLrUe)hv&L13CpJo44NEdd9dK^Nvi1=CS(BBk1{+M|KM)=dbyy2_Ie zV$VnSnX?vy!ekuKkC=q=wzg2HeZFEQ!6dRDbFeR_y8uFn!2R9@~ zJY!8t7uz^eH2&V{gmq=)6|po^VuM1pfYSKfi&Wuh!~i!^4aWRzBVV2+Jf7@=Hy5I=WT1P z|8%$(T7gv9BvH$IB7%`ws!6jdKk%MvDenfRs`xD0P!wlq!%Vey0&Z&Z60vSMp7|h(`$mN9eS5)355*ea zo<3yIq3@ymxURztoC?K9C2^`i2lrpMB|Ro)9UHS(f#we>#e2>R!~;Ec0P0#2UIuR2 zB}ylmt$}=DCSK{GK#Yu6=vIR_=l-We#XQLllx)=WiE%LjoG*_%v*3*<>hcn61RgnW zs8!h;E#?oTnF$}jW`6GWwHZUQ{a*Lmb#LQ1dC@+zJhhT!2YfSXS()*hSuV?>pd;Z0 z+)@GFBf4fQ=?%HyejIGR9(nxR3_gl+miKEkETtya05M)buR(Wt12!2SSJaGJd!Ql* zd^O^T-@M_bl!K8f^moZ%=J+tDiETKzt-Xs@$}}LH>TKsG!rkX4`@X;62aVnvJGDv% zprEVCWSMrcIUYCV#ev{yj8_?<4MwO=H-CYUEDATTP!8LF6WFCwlDcqd^4v@e8VFRb zgi})`ICh+8sxW@|;3<<%(*YlHq)SBXqzO;Ehuz{%;7Bx8@$*3Vv+QX)N9=4MOj*+) zvk7c|F8t*cqyA@L1yth#0o7Sx)`}O92f8E^ zjJ^v{5>&&AeOXM<1w*X3 zPZk!N2*zFAD$RTr9kU6AZj=DD9snm$XB&DhZZUB?e3I?aHO9Tih;my>xig!F;_egb zhINIFG1(}|O{HF&&Zu^{GBmEfo{q)!^Jj%65R#ign5*qSM*bfmj<+V>iNX!1Or5+e zW`iaDHQtdkj7_{ne7IvxBr89`<%$=trn3Q^6QfLHYyR!<;y#-NFbcE@)L#skA z|M^8_0lX$G)D(9T=lJDx#u2em8+RD7?O<0^u2;He*8(s<&=A0#5$7Z%wqOYTgT?G( zsnv-1vQLDH*>bo@T<@mKdtaYP$cH-M6aXXJcnaLsw5wyK^Bl-~_(;y3ru^_a(z&h| zPp_n0fBzZ5NgSw(Y#M-0Us_IYP*lUI0JEdL8eEp{6?@R4t$g4%PRmIeaab#_!eO@L zK2u9!eN=pdH;wKQxSD1G0i{Jtnfu^BE~LL#c6|^&$DP9F7C?R6j%Tz!o$#Wxx5z?O z$St0S4=;M{-jTVCbVuPz5-j#O8$&50-@Tqt@lm>7-qD6zTLk2n0}AD6tqUGCwM z6vP2=j|wW7S}((MCKwR(2&kg=)82AWb5SKpzL#f49ienx7?yEDuvNxkeM0N9-(Fw$i!(g+OdFhzv@!v?5vyRKp z%9yV>zi=cy(Uozk$gNXna6W;XGmiE;BDUy25qylBr`@==kMYZo7wm@atv*_q%ETwI z`JHe?uo+DKzZzfh{KV93so9B>?ez6uR>~ zw@?&@kpPBLWaOxw&r2j6&ei7LwQk#{Z{81$$G%cS#+ z8>2rrO-lI*Hj=~tEST2nu@qIawWD6_qoe0zwscy(+}9RO8xBWGlBPvcT&(Vi6EEY< zRHS|a9`-9jQ8hXKITV!;!)s|2tse4>31!XlMhnI6)RDOh6v#FeS?+4mgG`3qet&OYdk9wd z)I;r%@{^+qZ^^x(z@6AF7I0(RDjJbrZ57Kt+e;0AUVEfzzH*RoL)zjvcdYH1A<%35 zF^&XMQN6bmNf;{f%kPLEGL)BEgR)0ot0W;UUu<7eU51R4%K@l#x9vVV&s!!oLGyo? zer_G5J}BE%7;mA2`+TT&TI!MRH@#6OOE zg=%*gCMYp!JhOr(dOaU4gCV_YDb*Z!b93jbX#h`FO%$;7QNiMs944{|CK3=5cRJf0 zYRX`SYA}Ij*_(k?s=5!L$1Y(*bRvy7Y|L}Er-N3@d64bp<+dYRm~$pK+^j|`qFdkU zd~@HYo<%o8yDH;|Z{KCR+nzBC685Dr_OJ;Z9FFJJckKu;jXHN7_7RvD_tK_@^-qYv zj5Vby*Xi9^MVaIt#mB@Owg-Zymwlv*0Am2__`UaKCd1M0BbwD+7rP~buWi8`IWV!M zdk0g(9FXYv?sumoKy=lG5Cct{kL8!xh(I1A2jAy;dxnk2^fWEpOTnCydox3>C zr_Kpk1)5(Y^ufh0_f(aL;`hs;Mq!H@i!-#t-5;)KUg1B%Ae+lO3H*#B0%#wIr(^eO zd2IAso*WcMKX~9#IaUO^_5eM7l!t>KqIui@n(g1hf$VB}GABFX5Qd$AsPZrtW?Zz- zubESoiBTh$_$b_4YQMb~1 z4Cc!jxMKKrhZG!ltXHtdUv5Y(b}>Qp9fVDUo=4)PSeG#75%fJCi8AFf#~ZduJL! z+@}UPUf||aMLF!rErphcT2$Fhsr6YrUlK8J)$y#0;c3b^pzEqIVYmd6=gKu!F-(|6 z&%uGgShiG@BUBqxf}ho1mO`3DwSO+l3$vzB9Sz?3Mwb(Av0|pR@SO?(>EFoK1jJ%e z2T+8~KMFme7PEpiKeyn?;ON&=HX4evt993&D znGQao(0Tfnk5gnukIR37XdcV2R&Vq2WK1*Mj?_c4;N@_ZD>Wm7j6=R;QuyazpDrER z#hdAw-pO2;YTBgldMAw6;^qzeWN#s&3r!=#%++n^DXA_YPvF?SX)<^)Zfp=di4;y4 zaGJ5{gi_=(XG>2&p#y)lVm84pTx}b%nbv5Gzo)b36~;mI*+3=Xi02ZdpLiub7$Lel z@x=vE0)TZLB={be%Sz43F{rD}_VX9OitSF zsiW+mMm5b^Qzub(T?jiyvNq?D!{tMuDf<64*{Fr~=8*3_{oA=CI!k@XU>SyRvRo_8 zbt3=3_AsQDW|&lmidLAx-?($hviq2@hA3DhaB6NanA~`7Q7>8o}_{1(4>%4 zN`#o8zf-1O7Q1&TJMPa?xR2v6%2(36$Z9B5=&}FEW3jDpG7D_b)($cM>Ww#;YbrP&7?o=-sh5{S?E zHketJVLxH5*fz-_$FKkim%k2b-wn}a|4tP(kY~w;I|{+69kGH39jE+PMb78$^=37E z4D9OffCX2>{XVgiw1C;U1K?FfH(oauGpmPH*2+>H1V};Mj+-e>VpEB11T^maE0ag9 zNHg}Tds?W>l0JnZ{1q*}1-KtM^vtKR>2_@FqsKHQkR*LLtr5&O;)v5Dq9?_7uA`0l zEsUx+0>6`9L;U&^_L!=)D|_}bM*PR}8xL`8Ko`ZK3)u4saWQpSR;2G}f&{B*2&kjS zM2%3NPH^BR0+|g#(DNU}foo}b&W?_6f(*1?>a<5go#f4;0FrIKwz=*%hU+aR994Vv z6+nU{Jkr>=KOqB)_f|p{(J@T?uT`mZJGQQ!JEU)Ku79MBa&Qjd>&=YRx}M?If4iAp zkys*%gKxSdz1>o*-` z@)rlA*>c3%yDGEA-t3#KNV8EjOQEc_v81aWf{F1nlzj^LC9amo|Oyi{nUizz7;vbF!3~X|P%d%Is*nyvaPRBthv8BFt4)rOta(4Kjh^wziyToS)6FGAJ^Ku(G zg>w1|lx(zukTq93W0+pw3q^08P@SHZQyGBYi;@kj5jYANxVCR4Cd9i8@J+>oNeN|( z*A73qT=FvLr$*eVk>!6gzjrS47Cw9wA+HVBQQGr&eR~Gc9If8$OB30T<@&7r6YyWr zs+Q4H+T>l^$N%92q-N?^3!TBmXBChA$u>q(E@#@FnbqejpF^KH=8j0Wb9_b)dsU@{ zK|!KQ%CXGu#aju`<0r>WI@iOdbTOc;#BF@O9n0@ihL2=}W6=)_jP{b3E^BoN*<0bL z>G_g7H)LI5&=ZgEDLWV5z+_a=$xNF721VaX%+Q`UNXrY_9Z*w!P1-P;kk+7>&-0V8 zVnd354^2QVywS*k9@O)?2WAyDRX#tbTdfxpDmSR*d<2Fcs4VB(|C_OXWzS@I6yri4)QRxEVEpwaZBi{I(R#a6K4$r%$s27k5hEzDs8KwJ98*wt_=7^wa^}}Fn!m*1Nv)8)Ga012E>U-7 zg2ye($(0Ut*m$3EB7HmB-f+57vOM-& zSYR+O@0rPWjsdV&Ta#;uWv1c^9=26{i_)H1eaE;W|LNRT*#yGoFGQr&Oq#FTx%D{| zU~o8vU?{0V4%m(8awv6fQrN|WNf*Wyd)JZ50X}2fU7(1ooK+F#P*4U4>-jfo zRD-c}4mP^A0PIwO26D@psaa{<_F%UZFb1_*HH^$w8gXfMr9rP>AfeeLQSkb|DCE%I z&UVuCmr9v95}UXhDm~YTBN!|BaiRF21 zZo`!cs#HVWhu_h5j8CC6&%idDau)#^V}Szy`WHQ{Dz=xA>%^u4I+4QVYnu(~>-*c4 zH2`0f)nYNTdeeF+nm){h`EjHvSZAu&6Z_IH0f{cl4D<++ zSTZ?#120#_Fs3B=8@kOC=ja;yZdfxHuuny7Su3hccRsMbRMt^5GXl2R+c}X0v<@^M zE7Am2O~_FRkM^3Py(T?+L%)H{ku4+q&p#YkH{68XrGkC?uWhOl48WX??nSp&Rlss~ z7|UKJ=ooF4uht%YPn78`-VGnis~Fmge_bDSNdZfJd8Wbaln zC(-|9K!w#XFMR8m0oEpH%-w*EX8z9kPPD^;f(_9TJ9XxErSJsfXeY`*pFH-l@v!q1 z1o_(6PIIekb}yFzTZNgYb76ijk+d}K-y3n%e-eYU87^vi`9P$oJ(D}5b~0~59tr$G ziSPI=vo+d>Y&$ynLIk&$7RndJ8@-|w9cQ->PLC_JDHR5{Qr|$BAjM_cglkNs@0$f0KhS)+dHr!V$(BA^kYl$0;vwZBZk-t0weX7tY z2eA!AKM7Bgo4~<-dBn;q>-FTIUHiu+tXyZa|7k3l;xs!${f2aj=sF^%3ElKk4+A5b zDCm>j={@ZIu&rVnHD5foGjjh9h`~-hrgU82K3A~ro@ns3ftU~-bkep!Gt5k=uiu+Z zK{~|u_v%au9$$zH8spFrVx6fR$b+@3Ax>k%LR0kIfeKl#{v%D3?s1!12+RZ{P3~GT zQPwpr+wgd}5o%8X`Bx|pLxWDi#@{KXJEkbVTiH-hHuvx)F+TH`f$^T4uZ|B)1`JV` zwTGGxK%j+>otC-VkOWLIm=HkYFg4ToX|r`;mk$g^a_WO+v(D;&hZ^LP$sHczx^+MH zlkJwKtAz{YZj();5!VW4Cx^08Z&SzmmH%@D)YS|`u>1jK(exvoSz?w|T`1&`h2G-O zhtr~FrBwzzg3%R=M($#@L@vt?`a{X#Y*AB;ZY1o^XL$mSI&1;VZm6V6 zf1ZHml{Q~)|G=qusRiDQ>I1?+L6Tl-xy0ERc0+V0utQrBu<`gPH&9 zO4~S?Dz@%LWclcx$a}rz#TyH9s|NnU5OHA0hQlAWiWS6mY)vUHiOMrr%cMHYGZFh? zE?5r&RS-^J9HdCUBMctd}1q=T1P z=7bQNaI#g|C`KMdf^`1fL1C00;I?hyQw=(6GLL1^LhkCQY(F*l0T+zs3x;^CGUhDb z0q_Rc7b!D6fS5ZDkJtpZ|Y^JYdkH4iApv4ch- zaZGeRZ8nm$(~t73G$o(931SY~Y9pMH#Q258E-Vw?yQ-6qOuanO-{5s?J|{?z(5Ox` zb;Q1&OC&aU561`-S2MBDe_c->wMQry?MK0-f^op@MXW0-zXa^dut+@c=E$i@rO~-~ zCR0`8YvBT1zZXS(%nkSJ7x6Hfl%l0&J}F@)=#>-qkp?k!-n@jq$br4KjFzZ??B4y2ihy0)KWDx0+@kev8@%{VIbpsKN$D`Z(T;>Jpq`mM|( zt;UX$0HMBV!|ecv`j}1MN};$#&LAfW)&I>nL*$Q+6WJ_-a#WS^h=_=hf z>P}TB;^n&0$sWwG*%Csj;wPQ7-PQ~;LkZ_G{@Cyww2&hQYiHNQ(gVuOr(Ux(kEhE%3SQcF1`wEz!_;yN$ zfL`i^a6j|8obB$npxJ_Di|6W1Go^24=;Lcn@P3|jpd3K--^Z|T);ow_ z??)VRBcYGKQ)R1G0qpHh^LnFwF3HyL+sfI>{yx`?ieL5-Ek?ksJ%)RpuEi+OQ<7B+ z+8}H>Um9HYq~?ues>#>B5Ft7UbzmSg^1};w@@b%(^llWjR!DR^hZ!+~aG_}Nrcb*M z3J2IgPduI-ZXJ%aFPC#AH~xsizy(084&GCXeb^&fXT#o_OA zR~lzq-TDNAcsP+-lWF@c6{`P#0`nyMLobY57K*#f5mQ`AvlDnC(&RarScxSHw|syd zJiMnpgO`0Q8Q1^9?3N;hH!~qGN0{m3m*l4#fHDo)BYEnq7+BRr(9wHph^< zqhvJrOQ5~g90PN-#Xi=PIJ*K#xpTkE%t#w(PhA#9mb8`dzl9>gb!#NymObbLO>aZH z(M3!#W$Z-oy=AeDqXir26Qx47f(8`HYtjsR&tfwp7JK-aidWbUs#D*l8EOhdkQ-!N zhyLDypK>eC6<)#-Uwx*>W5_@Sk9qBxse;@`}1oGh+10wdrMf zj>e~L92-qm(nUalJ{YlBPAWC2b1z>Xp`F(H$L73d`8#qzL}$VymSUH|TeN%P+-7uu z2r9Se*rE>{h>QE*dww~3z8sI8K`JY2Kdi!+$U|6J{H_IyuVm3xO+djK(hu!?j-$1F z7XN0Td-L%D`Rx#d@jI50-Q@1~8|IVz>a+(um0^lFSY|cl5-9??uU2b6`LwA|$EmPN ze8ZZnpPsNr1%XN7ed7Y#0DZ?zJQ|KC=IZ#Dzb-)rOC22FiMN0#Eh^!M(V?^wkX={g+QYM;jrh4V?O@m;k09l6Ik;;3UkT+(VM z^z(0|0v5b3X@S+o=QI)2e{Mb_-F8d}qzS0}>Y< zZel-mqm_!3cveSKx9$bL3CIr{H^MNo<5&lUd7dj_r>&Fs3x&Lt?FfxJlJKK7ctm~k zTB|Ip!_yV5E3VKrkB=M>q6*F&N4_>LDr`X|C zzMO4lO>KGob7&s`FgC_M)UOc@EwF3z{1kLxbUp}X&Z$T(LYlk(agV~cLEH8|CT>a( zHW&=3uFFtS7am(Q2U3lPCT7f?FF(zTCN9OFoOd)ew>s@l$SAY+K6`ZSt$`8jwCBuv zMnY{geAaON{T}dxt^!A}6WltlJu>LE^8w=NbH1~V^8~{8e)!5Udc0y(Z>!fHlZ}>? z8uH>%6Y1+sM9H13N+0M5FiKBCS#6vTgGul@#$`PdV5B$$|FBvDWWw_bsi#<{Y{B1Q zxTX6@adQ&|`pI;_&+_wEu9>+Wf)K{Xsts*7*tTJBH00{%Z-0W#f#0}DtdkxU#GWQK zK~r4s_q=w#({{8UgNdpmyzP^bvuI{KH7NIbNJ3ON-n3j5yiMgl)nq`$p>ruo`cfx< z2Zn%)=clF`uexF6Mlu~Z(T2KX+pF=PW+m9Kweii}S4LholZlOw5HXV7sPiQ6mzR--*Lr;M8ni zrU(MSi`jG)Z$+n8z?oY%w-f8B({-ydL86%)Qqymhztg!F3Bw`_%^;Gir5yQ6g@Og& zi-TQ~;QW~8khxeu{c*%0F`!oNC1Ag(=J!pU)Kv?dIDo|Cb9hu%0$>#EnE5lHntgqD zxUo*(Q=O7o%YRxfga0+~MpoGP)YV4PTt)r$h?)RfsW`BTJ&mF|kRqdSu^F+!7TY0_ z^!EVPin^_5Rpc5SpyYhK%PC%Hd#zy`$SvKWM-9V~L*Z0lKm{myGEj)%}O^9mH!IN%*+Q0bY;zn zB!)-6@FCq*;4}={3D!i(BJSq(+ok#Cbwr24A~^6O@&;RB%8xAkd?D)Gs=2e$+a)=M z1@=^u8*IN%yIf<6{)F7B-=-6hBgZa4#%0TwNl!e}n&3R9ynvw~kO~8!y^FlDxD(IG zNjiARH>L4ZI`NqQnhl=wo4;F`cyJYflQp4sD#-;+f}c*6Hbq}*aV!{#zv(`GjK|Qw zmFLetwvT04*SyYEd1-0gJN?C7>2<1)93T8oUrg0)XkYG&v3c!VO9=;53WMd1NOLUS(IN!Jw00tiD#_! zvEYpi$H~Xw%Wejj+)kq*(tok5aba#M)=x5q8JG|5S^QFr80q?ALqv*bpF=!ULWtC9 z4C!gK(@PrbcBF*)Y6L!ej8TI^rT}DQ)YwTa=)y?1X8hYh%C(alJ`;Euzh6^$O=vrp z@-C$&PZ{v(8j$vgzC7Kq_o9*Vbj~B%nuVx9)cKkUiEk?ry}7Er3MdixfGI zy^x!+v`HbJYuUJLA-rb9eKm`Ht+Xq{o3$W?o@t>(?t9m^m`v)cFfUyGYlS97lHjTy z##|q>Z|~6s6tTfwQ5}8!W|k%(%RxHfD(&i_G=bQ{)ts-8qmnMO*Y8{)tLg~KxY;*!fuBb6^#iXG&|9mbH$ zf*y)>f*|w5y3I$D!SeF`eQ_pcA@Rc+rI{rN|8*Wi9vFgJj@!C`FR4Je0r7ueko)Pt z-o$Hh$t{%TGWPc=pLH5H?`2j8AsfT}gg7GsYhSqR%A{(kTN1M0cItJ!7&l(lm85^L zhu#!StdYO~01?7Lo`yvcEG7T`eRS-cVU1#CkI&OgpQZwDyK;a?OHLxj+v7hA))iBs z;>M`08OB}n{!iN!Yf>e9$*`86!+%iu#>ugf_qtgFfu;77dteA!$6Hf2;04}g&)I*Y znuRI0j6s(nF=||m9j}AYPaRm>PvjYkPrg(}u8P2qJVHs3g4>t&SVWYy?0?ngt8^Mq zQQyt7-0of`B%quM;!<2_josQ7qEHhV)RZ|}!D~bpm3?0_p;?ry*RsvtyHb1;&J7jK z(R0{D!JiPLOrm^G1`vmY8FMp0PFxO}Ux3y%(nTs6uxgQ|+|Z~;1w0$WyYr4vcHTSs@=mulm1)^c!Pgn*UBa*X5q;8@p6C>h6hwFw=;?qm)y_raJIF`;uEf@LDYU*a z_eU<#k>E!XNBdj@B}W=AL1}Es+5)>MKUXh&^s4NtsTQN&|0Ao(_RNu$0ZMW|BAao1 z{-d6*#k;J+-r+4eg&DzBJNB(0?A|ZAP##l>G0+ARZ!&}#C9~m@9_-V6f#sUj)~#>I zGR9$kPGZyq8&Vka6umn>M`s%rTrR)-)qa_$DI)*e-zbtb3TAXG@DC0Nod%&()I)pJ`hx9BA(p-qcDiGM%9fe;0Qh< zPWoi$e!!dT?ls6}PXk%&>E?7ta-p0Uwf&+#_lG!qyvr_}+{Rts8Qbo|;jn*GovO^y zw7!iHqs!t!Zg{9NG%rc?8}6MAI8M>)IJ1!DX3RsN1oX`pf_$Bp38>wUENw(fg~|Pb z#W+oB7fRUMogH_?;R_oEP?AJjB$>D_0fg#mQ2*QR#LNq-MuHu5$gUXO8m!yfW(&K9 z7u=qdM#td{2sJ#;=K0qq%;)qL&U;$*YOz*FHedLMzgQm9QQVrfL`q`A>?{Eq`cM2 zwk&bWC(aA-PE%cjB1Kt)1=~aO^+6S6vS_ero1b;N{uC}<4Vi^x zGmwtTB>F%-j>X};hgo`dDJ5gr!-?E+D4A@#Z;(M7%-2%<>t=hM zv4!e-;Jg9G9f^qnyUuwzoOW|sPf>Z4SRpLYN*@>7WqZ`BHP^;Q@fu{^8_lJmmcqlQ zqblu&BZ`5~qBSDJBNMz!;qv|A4pZU#cXvCgw6=@1C{0}CqE)s%BKbVwSIVk7d;JeA zQbjwUrV10Vsk5nK(?A@>DLqEp-D36Pl7_ONu?p7qW?oIUJf6k^U3St!KzW-tnJ81B zZ~I)*>I{?P&J*1$5R?bEmDTjlLHsdnEWmx9ITkyu*DTZ$eG!z?UmAlM@C}Ft*gKw^ zCYO6y0~uRHUW#j%Hp(Q_PHz90K5S^Bn0gFYC7f#1J6RfSbw@Pcp^Zbg4<8Ux(nkL- z`ACD+iu+>lS@dLd`8{TQZTbo@4Glkmf;bCt{<)2Fp5vCh7@D!oOpwFra|BNH-TTQYJ` zCYZP2s1;%rN@DagV1ff$4U5m??DVWc&U8hdef`8UVzK@FaUN5>*(2AlV7Vqa9M=n- z-=CrBz*=j?c6y_!>DBF@foOn4vhY^lHeBJpzk#$u!e^$e(W=^&uUW@MY z8aGXmlc4Z=-T0N=h;Dy1Jp4rVu3Fv7O$g+%fzEUWB@Mg_FUGDDm=^0jERN2x3`TJ) z2Uc_uA5QsQmOumtJ`EZ?7W0x%u}eWdoHlm`tZa{6vG=YZu6)uuE#Q5j+ zorb5`FRlQV@Hk0VXrWkOVry0%PdRfp-t|GSFKjyP!m}v{^6dM4tu`6(4X%v2J&Soq zNsk!0SZVO;vux-<% zt&WF(5VoN8YlJ+4ieNxr78={>(O?YV%J1T- zBwXMWO)s9lhS;m7gp^8?=_7vF?&T@UIJJDnF}LA)mveoE2x704FqNje$p0IRB)%MP ziN4YPXlXF_9YAr`Uj*g>wUU+}dws9eIrCXQ2Kt5an&b9t-BEK_?Z~Zc%O2i@=bHoh zm$rp-15+L^DTA{I6<++5Ilj|4(Ne$Rhd3!%y#X!)D1zWZ&)e@+CxML7FnVav13nuj z2a5sE;4^-=@HxfQ!>$nHwm)VbXw<~eIiLQykXc}cpO|FGIjLJ$XpB3 ztM*XEx>+a*K=&JL{l57CZEOKGNNu?h zffJ9f!F!KNt&pMdbLhG>tdV*yVAH0@ka_l;iM%~Gz@q_J%lg&`qEJCvsPmxWy$t}e zsGRxzFQ|)GLdGV#x5+B!qs9F!?ec(w7+CVDFSykSL=cKdTMA}bVO!s*qvy<>b)`mh zOigr89EwOH{4C?m)%Ia}5tqEUc^PjFuCUaiXFdbRpka5;fPKzBtU$9>fg7chn8X}Fr_h-7b?N0j4Y9cFLy=Yb3#5jBxl`KLOy(=?a;z|wSg~W z{;YfD&MI5yQ%jRf2~c*{<&G>=*;pL&M4h}}#84TjX9t%y;#-n5X22ThWH>ZO`GXSz ziF7jXE?JJ>VLLHoux;E<0_AC9P}w+JEEB)5{n`4r<-0yKe_)CwW{%6tmrhfEvZKpp zDYcfaz%w+Y0L&=^y_BB88C%0VeeUUd=4x+tH$DnYZA1<3^%oBxV8Q>&IOUz3VESxF zxZ~RSIjl)ur9@C8?GEGN5&~tdu&#f1mn4&(5J)xdFp{oF8d8t_OP#_OU|?m3f%Bw! zDcJ_IAAOm1`QZw>voKGGr>z?rcZ~Lc^v>F(M#5PW7jvXj4G0Myv(K2t2de(B8`MTM zDF-Km3y>~S?I{)5Kz^%WOsD9U#)gfcLUp%28cV54DrRExNb~KXhebA@OLfRgdJvW5 zpBE~|cwKg%lMa_@x&P|Xr>JT_=+Otcw#QHt4F&%%Jn<}cU>v~QYxmt))GJrj;M<;+3Wu5 zlW{?@mGc;F_pwXz+1flkt6*yM@&=k4Yc?W|sFkbQ6N%m;+%#J19gn87$RhIxg>K~r zBMgZXmLmvf7DVW_m>kJMgoU*B|1>`>Y8&knT7w%tfSWjT>vGLz2pUqVCV3aL6F ztl6u6VpR%YzynkvHifaq@SY-A?p{t}OH{0ro4k-_^SS^qg^GuhmkoID>=;hESHqYY z4@xVXe#Wa`6 z@;*A_BN`vYsbd!Zhc2NM_>!ut{;C`2+;Z4nn;PfhYCbu|S9mUQQCY9)%!-Xx3PtQu zthWXu;xtMzi6z8XLkH zRO6XBW!Mw>P}t^vlkJZkoZffk7E@86*CQQ0UQ8t}fveYS=!Hx$S*w<5Uix3YWBuh4 z!s~w7$UdGv<~ujqM9*A*B_)fM;01jiI!3H5E*4mqMpbgpb|v*4CcGd0rUr#w9%5-7zz zR8y1WMG^wlP=JLduh9__eFCo*8>B`0^c))A;BUpuf}8_*3TJg#sxPVt<{hge+WR;= zfThGfpF-ptECR$C&%=x11no*3Q-qEDc%ShATXbnKcAodvgvsRI{dtC<$lnkxx*W)T=9GWfMZK4%u{R z?;g1fH}SVuNDYk8_a@$mrLAGo(-vR5PIa&K6EPGdFD49900D$)zHA1eWEEfUfuWkU zcQv=*@n06TlJ`(0?DTKT12zwFKpHo~DUb@CDUpB`eCD8hdAi+f$RmhY{ob(!skQYM z=7CFI&~#8WG{UL~p z^>T;e<)b|>V}jr-^02-Bb`Qr%s1#QwvN^xslr6XpdCC@SGh&n-j|g5Ojyek4hnRX! zO@3KXcduR(c3&d;iEahKYQ4$N)W)~^bI$|Diz8HFtl5fmafwrNpsA$i$$c$f^vH1Q z6f9B(b60=t-LZ*O(a+yuNF``pg^L-$pEop26y&A9Z2)lEHkm9L&hJP?lMfj?+HoYO z#y-5Rzv=B3VYp)ViJ+qfNvG=mRFfO0oD05J}?S5~Pj1 zS`2`i^Ec8vNXcT@rL6Mc1bqcY85GtnS>0R~wPpyDC?I}YV|{nvn35vb?GykNS$uS% zPjoj^I0G+owuxuwWT0(V-)+iXmNN!{v;)aKg-vFd;KeaRl<2Z?n`;19PLbxY+f(I) zpg&50=$ZD$lF^?B>gW-{neWBsDw8AVcIh|ySPS-0zkb>>Orq`Y&5k%`m9440J*lYI z0$>Glo^1F3U_%+59vj320C-v%-XEfoQMxE`>nB8gz?BKQ6U?5O5?jzFYTCp<;N_vG z{HqK%LAQr6?zmWGetbPH?_a#5Z!P5jm*-mu{-js=B&? zmONoj#QXbm$Ku*cYmNqd4ISfz?<^X}On?Q0Dl0F)K@~?v(!h|q@pa#TUN#AvT0{)C zD0{mDz=n>ggBVkFuU8hm9E03(3*P*RcYgOJ)CB8ce2}urUA;Ac4nVM6GM1jNKuJ4q zgMDU!x0=;<{J~b*WySJ!(X{y^PYtQ^)?BRFdN<3eX;*6y`^OYEa)`m5h0|}<8}sTu zQ0bvp2|zp;0OS$@i&$xZ)l*}vmiP)1dB!*0L%r3Zm{(XbiUJ^zJ?}J=4<@)-`%9gm zh9uKGq- zH3#!Zc%GoTs?`rqM4P3-8=3<(G6RH&!Si7t#8Z@(7B|xr7s>fdDbJelLr$-=Y#PQ< z)Ks=Z6;h}=bJQsE-ccTs7y$w5>BDeR`;#e$nh5Bb3#n*?sSMfmn5LiQD>OQ|t)w%@2unARyy#M}~9g-U%9%r_e zm=8HquE}+*%DU6ime-%g_=qOH!MR*;qmZJw)6g|9M1%*`ZqIbBlW!s%Ly(jj={<;? z(2Y7y0nqDpN;uDH*Vd7E{`DOE~NO?1#8B??xaaE-%4A2_1MOm_L8 z>Y{&j&ns8_p4k0RLr}_;q?@WdGsQ)wg8hif0diGtl-C8lKw;i#6Uve%kPU&MPMUri z`UM=)(GwLG_=F!IG%lbs+GoohoW=aeP{ZrS`oEgZ>3OD6P@{K$IF^P&6Xw4nvs%FO zNt7+PeF;jfW+F(Px`9Db0+3?v=73h}r$CN?wqIFJyo`nK@3v5ER z2~JS(@6|&s{K$@yhu&L0Rvr{Sn^7|w;$tiESXm< zk{4dE{3|{e@*t$Fbs?4(!@?iMhVv_ecb%-BwYRlbe#=SgTqXx;^me^q5`>8n zRcK#Db95dVS5C58blog)_Q`zZnDWT>%&?Nc0*ZocHw)8zj~^XA4GHp1qd%w zAbd4I!}SI8oB}8xi)d>G$ZdFv^E&fzlf3_9!(xxuGTUcEESY16hA<3j1h9CPWK-b< zW$X!u4)9&WC@KNnm|m9{n1*bx;Gu2&EbC<*mOCcXJmNwX$ox7Fa;vA9>X}Eme;5sn zh}#O$q&tY#pSLv#!*SlKZ3d($E&{edE`~KnwySMto}~ddYHaS2m6U?fgsnsiUo`~V zKfMr-?vo5Y)M>fl*&0x$sSd*+2hNfg{UIB}{e(Cr*1vJfuQL-<7rlvDZ?ys|pxPo_ z06*A6?+PYXNZA584%di$a_q54!RnA>eNe4yR- zSaAApt0_do0nvq@!-Ih_-8-N-aLc#|9(T$f{cJ^J0_qOI- zENi;`0YVJr{70(&{WSQ9n+qnOeEOeLIiwh2L#5YUk!Rdrhs{9PB``8S@95_CYY{^A zZZa!}1C+A;M4|BdD`ychou~3&n;`OZpilp#vlWFVL?%4vcgS^HKBaZU=5NT#HRly>7ox&*tl@*;qVM+;S{6SL*#X9PvL72sX7kuMFdZs zJ-JyrYa}8lmGjHcA@@Z4NTrPe`$_*Bjn1DTipp_?BBuMIr}@(#)19?AuemB0ViVa! zfIGXgpx8KPl0ySX#{H_7DKy}*EzDjZ%eB4R+4;7g?ssz?GRr~fiHU$|NfY$G!T2cSdiXyo*=eyF*D)b`S8y%e<|wZR z*uwzXG}Q%>+jIwt2=*>xkBVzd+LHA|3kC_jo7)P2a|L$1<^b)J{$x^NEJIpT)s8aR zTxcmyXF6%yc1!H8yPiPml1K6$>9e;=`GzwCQd>VZBvmU+cTMU4D|q-nxenPaf*7?E z-L!RiezvVpo7&fBl5NJy*3NUzwzRfvhSK=S1lIN$N6!wkaw+VPw+kxGVcKC{avA9s z*U(>BI(!t0U24Se(%!QZl*#A#XDLGze^B@u9kaKUA{gA>eskK+AHC-_LqHYgw*+^=O3!r> ztX)rV`QA-_QB17PmOxqOMEaHmQ%lV6gM!^+V>eGuN#!a93Om|d4;>uwkj1?a(JF)L z2i{|6g%E?XO;SQ*WK0Y9S}Jo< zp`rE#AFuaAK2%ODz-6taB~F-R!Wa5u*0Wof#G8y=e-A$UMZ7 zJjeCMl2D|Hs`0EznN^QgQF*Gda2JeAGQNQr{+u(A9wJJDV$D~g5+A$$Ledz@R;`Su z*lXB>IAZ4^913evaiQURImeVE?xk0Vme(o3O_ju1UqPh-8`h=G z)*=Dagcx`{DSLVWNk<4N;do`LzkG94R^`%7g)UllLGo6i2na1Tr`=eEZKR>(<@#4^ zP-boJ%n@uE(AJdleU5BGE*55a4G#k=PE~Z{>lA(_XNCYa5t={YYx-u>>vgpU7bATc zu-@;I5Kzb_u=uU>kntS~B2;hy2f_KVv(+EUtQ9v+XC}Hfu)QAVa(zyyi1n|jNHDnymIbVr zL$j+!;`nWov6aaDE?m?$`kPzRGFo2k$t=Ue5HB`N&Y!{sykMGu2kjX@#wUVsfXNpX zbpVZn%jnX&(nUo2k2AVa+%>xi(pB>Zuz5r#iDmbJCQ;07C?s{@9T7WocPoChLU9*# z`<+Gv=6%l^-mL%gWbwt+4<}f!7mD{|j@_uL<`aZUMfg7W7lQ;j@o?Us`~40Sh))+*!Lb`|!_eBVtzyhef3MTA@UC00elQHqXF$q1d@ar6>mop_FLh z3|1`W@kj(`<4w43ATqs_J*PN1j4?WFCQok` zhbO26;g*|bwOTy(!a?0$Bus+`r4i12b>WKUWj({~Dxe+Cmi(inxNJJG5gX6%chd5R zy(S4h+L{fZ-vS`>&DJ!4WE90SB&&>Ej5*!Rc4a{ee2Dwmd2Mm$(`KI7{u22boIM)F zQzY{L^oP3(#XlXJw_SE{^&gZLU3g`5909RXj=h_DJ=YH|qYxbk7k8b-Pb7N}v6T!h zPnd4Ai@(_ox)5nT>_3-!?Sx(E(NbcPAq!IMDQN_Ok4=HO$)Ul&gNYSMYx8c#YjNbz zH=2pQ)Q~YCu@8|^8^oR>E>;Czl)1%n>L`vWWUkxr^{pn{d&Sx9f#{JT{4yuX5VHPD z$N2K*Tv=PDHhC<|ZW)}DniJb*DZO@-mepBfP-JR)Rw{_2h#dMTF+xmF-thU^ej zlVAu;f?H*mrw(-7#=@Bs+0tsjB*mQO3bTi!;*-u3x{#++59lM9wnSmaulWas`mfCQ zuY?dVd$uk!nszZyzoUpX)VOr>apS6Xh9e|ZFd-Ym{e(6q*1r}G=-NrNV3n5p$lj`? z8Iy(>*=E&MAejOF!XJ21GO|Yi05gk0nyg8vL2Q{!3BUNgRC);oLGyCJN+*Z|l;9KC zi>qVs8kRO>3VUd+61meTf7?G}nZNA@$-tGTTu;ntQ7T;epoeRf$&Oi7>NQZRvA@tEBwFP*X%d6ND$I!y+#z%aQMtjIXb@3TvnW`}e%VQ2qgL&eOi zs(Vi6eF)Xy%8_ySk3Iu#&!8DF4E1oi8{|p62ctx%Z?ydcqus1W_Yh6A>l`SjCt{ni z+n|2`9AxuxCtpGGuTKK)47!a~XcCIR=$~g%-apzJOu zr-&DZ3amPC1ER&^OF)YoF;bcA~sY{Wv= zc4?(IJShFzNq+MLmFAGiGu|k|3-@TC+Jdh4m!bBQNL;2KgjKz>8{kZ>z}(U$F-Wz?hdI!!*B5%f_5oa9^1Ep*0vtk)Q1y}!hh42+NI^Z0$x{qiYYnf5LP8h zC$6i5=E`?~>-52jI-{rHWtC?s6Z#xL0Pgfvj2XojG7QF8?Kk zi3`LXC&|}35dNMR2W&0+2^$^uj8}R@OP~5DQ@6;K;r6YPBFofOXmtfRtX+H9bUk0t z9NF1jr)ZGr(HAOm~#BDYdB;1)-Psip?v zY+Lq|C`Ef~%|T<$+kSOF_TGPQ7c;1r6tp|Q8GNiN;PEqP_0-t;ZrJL43?3HTF8&#k z1y6+<>BSe<0$ts5+(TmD?`pP|Yx7DY_okLkY+!)nkQk`c;p!A|ZyeK?IVb;C3D?Tl zc)l%>Txi9sgpYf)+!fTgu&(&8MZ85&G_VaHfD9&`9B#nBZEUpv$j&D2@Tl08F4~Fv zbmKDN!t0GdOATsId|Kyq88{9ei1|}1z@7%lb&PW7Z0)jB1vA|2)n#AX>MHtd zW4kZ;>w9WBf@#|)5-sRa4JRtc2Xy(kN9jMTFM2D*7Dt~XKVV#LO$1ek68o<+@cCc! zCNVNvuV5kj^o>Sw5w(WttGOY?&Nq!udWRWbZH75GSnv(n=w%i>u1Ma~8GuX^U*5EZ zTa)}&_x=?6AUMR?_w!gaEgME7j{s(%A}`8{dD0aluBkPc$GWeEH1U56U=z9hzibhS^9zB+94KFH%lOljQYy+xAPJpiD)uc9LRu4 z$h_?mjUDC80x{S8xgX{#0~Wp$i2OQpcP`Cop_}=%h1!#^MUuTw@T5T zJn`V>;8_@s0ATJ;Y;dEekdBnBo9)H*%bo}PW6QmFd1s2?P41){Qt!~WE25G2v}q67 zOL;H}Nlc?U4Khd(}$$ylet#bBe z6e&PQy}wnw=ulQ}JUPm6?+e+lFnhOeU~G(r`t`CxSbF`RYbqHPNTx4KX`E-TxAa)` zA^o}N$PpYLXGVVv9f(D|qeP%w5RDO$os{3MB+m2KnIiBWI%Vy_-VO~B{#s?G4-^g150KtNbFU@f&GUgSl)Aagh6H$wMFW)5Wo(P| zWn-8Hbbon_Qxb-jl!c+e+zzZPO&=?fdJiV`q=?+szLzdC4m9%!%Sp_v=iLhs$Y^|d zS_j7L-g1fz+BR+=SC>bygEXtOg@J4sO~snP~MjwwmsViS}U z&^FG+M+Te|JO!44l9v+MLk)5=Z{TW+u3=lSL2L>7EGKZ|C&jf#75Y|4rv|V$+K6Z* z*n5gp3mf~`(ELy(r*G-qY)_ZBh#x6@6F%Qk@^S48CLe2aeZ2RB8#HGgiv(370svI) zxq@%aQmqk8>^DnrQ4Iu7|2B5XgBO>(l3LCw%C(cS5o7SJ<+F9rkS_J(S#*yYc3is{ zLGku$iCh~qQ$n|^pJNh(&sIs+L0b^0!HSJ~YoId7D8(I!h=nQqfNR{v0*Oj95qI=f z4?9U}%=l(@W&x`<9T$g8-qsu9+ekENK#=h{Yt3W?`NuU8@*zy{I2W^$Rkm)83;!b> z6l7lIjidB3+wS4sj_6edC%c(?mf!%LJ`W!>j7v(F8T{X8kf5Y;;F=hV~i^ ztq`-Nyu}=KE;uby+Al7`IHA?^3=%+{g-^Os#tjtJ3i4ucyJx@aCmmB(2psJmxL_Fw z5fF%pvEmd*ktn$)U`1%!&U%vp8&nJ*29+tac8}-w@Z&)6-tur-5Wp@%g(^lTWuj5nu*URGV2QqeU-?Bc@cW(as?gTHBu@oeX*+J0#81AKd19_c^ny-Su#R|;I*Jb%D)C9BukV3Jb^ z24~(0!ktlJqZ3i2a_s6vmc66YaWJGUaY{QY8IqeLGNn&_qN$~DGfBcNxiEQFj8t+l zkl)LFO{0+?n^nIQ3g9#8Z3a?ZQuc>Q(6ilOloTPyC^rhDb@X+Ip~7ucIy9Vju);d; zKAM5hFfDX4&Wk#?cM_3)hfaEYde4#V%kTbvI_|lyg@35tac|Za|GKHHm6sp#YR&d3 zrz}V>yR|X;i=1&4PGjDHr3BcRLdBZdPUA%^TG?&6lE1H9v^*b!+yamz#_wOtLIB5d1K7vf&_1mnA* zamMK#`R#@b2B2En<5N(6X-U-xud_1q_L%ZEZG=MEf0f!ghAnA}(jsle)8+ZdKA%0A zS4EJ;)$ppMD@o+SMW4isog5hyr00+Z5LAojBP(vEIxqmOcX<^%61+I>rV+4N(k|do z#GOs&Y1XVNkDu`8g*OTKENWX&!&K*&HS{Ov22Bg*A-F}Ws{hN`Az3=YIG|X0svgc8 zEJgr=aJhhzLLZMx5e;FeENQt;=!L{T0=Ay5VKFj!cZBYDG%gwX`1iv&`0k+Bd*VYt zc@W7mgRPabAD}Kc+I@4b+F`G82aMKrygmi(zSV>k=|^yy>JPYvxzcA7S}~rIA7GT0KWl&y zlZmPWy$|i-p;#pv&K0cuv9-6*S7XlPH~SbrL^*}{GIMaNF{SYNIsp--Q}#JNAX0}P zw~@IOr?bee>9GGr#A6-&$jNQ13O4CX3^{!IC7GMmM`y5&ZKWCRE z2j}DQ5f5FQW=hivKMyqx0L3Qy$Ro+Z!{EO$u^di<6(srtcL3dM6O`9X!DNOaGyqrY zU}%K`6Wtl_`dPX?lSt<4+YELuM^J`eq}@J`8+jj!YOFZxHpRR2;{|fCAFiFmiyat+ zdl92If&3!LVsa`IsvbV=EyMky>G@a}NyLAe-7q(QI^hsc&n<7`bP}73t9@I>o?#D# zUg(%8oJ(!kw;ZCGmgGBDMr-mIlr+V1;uYpP7YQl7#u_;obs+4A<=JV*EP?1d(sTr} zIf%zESbEWC@UDt6fA{-iJu4L5m}=e8!4!A+5}dr@YX@koVJ>QF6IP4u%{tKOko7WU zC_xI)1@s@UR-4KVr)R9n!ez-QQ!{gTlBT?=79M2+gR_Br5A8x#oD<)dSjo&CerM?$ ziz99L+Oo-Blrdts`<+cx4NArLUp}tY|1+75BELSl(KEnAw_4lrY4Ql zR1Kp4f{@#ttL>kQbjhJ#-^Eb<#K3@B3*BY}E5eg$`+c|!#ns>;!R@Q24 z({>g(Rao?>&rtAIV5<|F1)?v;u5`k_Pst2g0!Zar#+Al)>u#?FT|WnAwmo|~)&-=l zD91WTfH?cA!~GbU%Ii1(MgR{SBaIP7XH+Zp`*N~f`-6zeZ~2r z^aU0~i8}#a;p*ShllNh^=xkRqDA)Ao*aH0OPS(dZX0A@)VIJ`C*JV3ehi_$)jxaUv z%zhHRV-QF;*?3*zYy|u2gY5?zitHeyL^tiD9E`&fWd#yC!$+43?`ChvI4{e(tpJwU zNe$1Q+L1?oPk0R)xc(9h(=3fnpUM1Ew6IiB!IiFoMgYJ?!#!a7lbR`6zA(q4JYlfz zpS)3iTe)`!5hrkr76ErFpWs^u_RP{|dhM(<#;P#23kMvSe`0ex`l;w$I(KZ_k_)o* z_0mcP*VhNG9nYB4k>Bux0YwuSBUo*#IB?p#pX#)o?>R^$XQ*_=yj;MoZSBXY@vG%8 z$X`SSQJIRUQJl3}iES43(K$@(xcVq>VR6*75sqpL7hrOK2W& zZwjWjuu+?=e5F`9E0~~h*$C`^nbBA$Ii*V+x)dY6pTTHUFN{ddZlnF!q0;zGCvEwg#-aGiJOCZ0cG|dj5aBlZ zZlh~UgzMnN@vTKk?OBB=qzv<)SzuTyC`vAy6c!Bq=0^sY5acS|@R3?>bqq-&lB8$Hh*{^8N!~1g#oeQg9(+ zBeXnf+P^DQr&a2OtVI4OI_?7KmEB?JaMN>k?VY8?iME4gkb1QbzCZjwqJjrYP6D|9 zZ;|=ta7GhpWPu9^&$G-Ij!mQO716ez{H#hR$_O6_8BF?O->XK z@8)6Ydd&^2T79>CM#}qQm({iwoGq^p1RWr}Z7c#pe)Akmwu5Ln9ZzQBc_SeP|%Mk!W zZA?&Il%l1qybbby9Bu!qMEkq?y{$<49MsWfXEg2xP|LC_BRoZ(mst8)J7z$zAL#?> z@rI4-Sj#E7?&=T}aKMz&o6&?7m~d z^CO)1l^jc#ZR)J17FY1O5$>8^;SDef?2I~yfjt+ zguhINxk3KzIC^A?guG&2-(|ZpIA6RH23QE*`eP%LLvV$M>;Dk14@+nA9Si#=x=_Yq zT}x7<@^|2UX3S$r^|#bG)E8y1wf*MzNt_B{@mBE;s3EAS80@*DT7OowXW6g9^-{Q6 z%e$}zdc47|F|IZ|?@svjuU}(>#Q(T$qPPo%;==>ScnNm}63rRkrIA#FjR}OBGZ2;1^PS|4_0dCFw^7t-BR$P76VzW@33YHxyXEVp|0T$E< zJmn~Nb}ro!3+9JJ5HeG2hp|N(yo`5GF5gL%uhumqG%lAdq3{u(;KzoLcsHkxyaeivtQGzD>G0_Lp9dz^>^tvvulM?V=CJD0p93 zVp3U)@M8S;(7Py=qB8i%r+(PMl{utYgtR3fYSWGWPxpAwzfVp5Vl1iCrEjs@KA3!) zrhxWiuluSAyjs3cba$)C#^L-24In7saNSst_Q2MuM6m@L;&8ph;>_?-d;J$y$w@>& z-stic_(%M&c7sXKmHD2FR<56|)jq655jiFk#mtg?Ns3-G*0f(kFjBA%Y=eM2RDmK$ zfPpqcq@!w}`Jy{PZ&|2|rDvoN5hG}TbBw@x-SyRyJszpXDVXN4OmSfZTpFw6s;`AP z@7>?CMzyFjKw=l~UNkfFwPSDGDkx*$z1b4@Y)*H^>!lq{b9C&$19A9DOo=l`(OJ-u z3duFMxDL0Wh}j#9Fh5Tex@EC7XfyW0wig=SE7(J(h}J8jA(Uc(j$)jqaWi6{D!P{E ztpt6>1tA2aOpWx}o+4zvZ-FBM98Xq$fi ze`(6VoiM_=$u0)rNb-JrMiL@(u98C7Jx%PKyvmqYsijqy% z-L_!wD_x)jcN5*fkKEcaz_Qac4pwsiHWudh63<>k-mxF@OprEGUJYj+LV-CgI_S|G z{w_~97RP<693ur>z?$+h_T=6TvuqHnypXmf zAgtvNHm)^6+J zkW+{Y@+;3FA6xy8wRV|IdBeFGSAfldR{p;@i=Rx(;Z`nAbP0s4SIMNy%>(QwFE-HO zU-_t;{aI@q_k#C4Py(lCsoB0hN3fC6I8MDJL<~4ItMfQ7BUknp7V7&Ga*WoJpqgSl zBN9RE_EIOKxY!qKm!abQqOScd zjvJKIB#Aj(0o=~tQj||L7BF@fWK8e$N*I9~Sa*799J=%(<`Sty*vIGp6tmTSBoP!o z9@BCKVuSy}vHiZImt5P+MXkb@uM`U=V#WX_3B;=8EKu~}dDvv=uPO`svMDsNHO?AF z@op%noseZRvQq>&3iJw7%F(T$o(S8aW>TZe?fk%ik(aF(oc~Wpa4VO<@ZuKZnih8x zYmKzN-58Q0O;b%Qnog=y0xj2@<-wblHIh>&rS;NxeHnC;nO^yI=wW0%*06&4 zkP=Y_&DAi-7`_{TQPChuyfe%C-m`oNxjfMK`L4s*3_Wc<3iP5ipZW$MEa(PIFdQ8~ zexK)LWNNs$<8YnTXhx#sfBhZXB9p*znwd|#Xd{cPJExNU$y)?TDpQC0dK|kp;`ce= zZW2S(lKfenL{D>Gj8|oFobBVpeb!;WW%E_Gc?Wj6JV$(1m_@lV873c7yR{$1pTwBi zd*R=3%mW0qP;t*}K zP#ocv+$~BCSAuen_TNjwhYU+6QtMEOgPOoOvP9K(-z5Bq2JZ|`{z*B#3O{iB6{EHO zhtmDO$fr6xBmzG9G1EGmk9Bemc#?a%k0 zE)h}Gjo+9^w!*VkZ{Bw@Rjrq#G{8DBmB}^b8QSV*t}L|Os<3IKDvcFiR#y(Rn`xMp z3RAM#=Mp@PYjK8^c()@h$y(LM$530dXXYLD7 zpHe#7#HMde0^)?hZ)U^E$puMy`Lp_7h;r5v8C*~H|IS%}U@_c&lXsitf_x*A41XSZ zpIq@rb$B5spr~SKH614_xXit`osIs&H9Tr~fv1>5hbt<*K?YAe${TKaHLDGCV7k;a zH?^|JzF@Ux*KlNzrS9>p@b(~zWL{EnqZ<7OWB)@hs5mQ&xyN$1L{u^APlQX&$|BbE zj2Q_PuC_G3sE2wB>jSib$_%%%kY4rEBxSvc5Mrw`2SSO+`rZ`M zRy3aUXEag2aKR8|E^MOad_8`yy8cEoI$WY_lpG6|-4&0K-|7Jc zjx9;U!AQ(daEQAzZAcJGY|O^JH`+uNM8T?SL<-}*g%^2(foHU*h8Pp~I>62Cp4PXb z7>_hod8{Mw-px*N!bqa^COiW4?CMxsBcm(dOaW)u(eW+k8{;6&b1JB z*}aPQ@uMkB4<;rZ=4x!N+|0i*!+1|EEMi%oTZ85Nl9e9_`2V#f zOq21(c15>w92xm6TX`*ikQX8OI}KoTF)Coa{4~C(tn~-yt97X0Ze^Xa{CETx$FWs@ zN0-lRBYH7DL9fHnm5oigNPz)#s1k8@*XO!bz)LU(s>h8|;;L$hNb()Xo|&o}M|VBv2;mT;lhfjDabkSc zYx?&zMM#Z=hoQE%nAl^=6eXGbQ~_MVFZ}?bI|pE7pvdd!vWt}d{mAJAZ0ux>0{b15 zy&YLk%JxmbP+`#PYpuR8!lt;Z=~I0gedFSisVn@NYamwNQo&1rpFi01FFZzJ)`^!N z+{-hpc@R~3mh+PsHLEi`p?yGCRGX@F2kaGXLkv(k5(8>8OC!5tVmtS2;3;{r8L`9) z_Ufanx5go;VodP4l2U!qywfIv}DMH(T> z`?{wF`m`pq_dG`3D{E&Yl~szvIaB3w{!WMUTaNNe`wuG%|EZWp=wYFYMnp zqG^sTD)38Q)6GF1fzn0RtHX-^LMOu#5<`V8ZaV(DT*%Mu;E|)(* zv6hratn7kDsf=~J^yeHP$}BSH1xtWCOt6Zfi6bB_k_XiBmpt84%?m=aKN8lJsEJ_- z>Ph)Nh$eB8GPQj(d@a_A>7Wty;eLzf9=Fp=JYs4msAnL5W`=)%Ow@}cu!g$4xNx)P45ovt}QN@O2b z?F4UI38O>LL9lE%GHdlpw9_y6sg$@L;GqF029zaF(chjA4pzjsd<;BsVZbm`Qq(dX zYfLVGGZOb_7MJDKIHGJhNQ%M=hpWL!6Q@EbD2~z}j&NFcHKB9zW8X(<@D_OKoS3+k z+jT%hSeEIK6?~?kmm5-z_^D-Go<21t6d}d>0aW~Erv34i>@pJbPmLW6vM{Xe+IGq> znz@YbQ?>C0RIc310VKT;oZ&!I?s=6BJ^1}Cu98?2cv!O`qo$+eQ$&1!QYuoa^L^|e z1joXVj?*GM-g02-jZA5c(LcPmE|NH8B$>MHh69(_6 z=H?sPmG>$BX3G(p)Hm`>abMW&ZXoeqk!@%FA1Xr()~7 zk8yLE@U<5anN=N%g!3GT+MN?5NwB6G?DnxOfi38gVVqcx!cm%@r=!+HxIZTe_#v<4N{H z2juAj5e1+820f2*G?;Yy+z;Uy{OEh4%W&eM=}{!_Y!O54qq~m7|5_KYQLN$PoYE%^InL1q*w}Buqy29h4gUo zD=^0kA0?@~qK;kRjDD3;n^r7khRLSpz#6Pq@BQeW*e)3rSmlK9Aqo5H*5zO;epGIx zX0saPSOM!uMS~-_Xy>U=oOcKuNt4jE1N*g3*y}WxaMt)>ugCJY3>Bzt;9uQ9Iz2$z z960GCS40hO5*1JcU;YBS3L1#aszVx?2$66nB~tL6@JIJz-#5W3-#wQVQMyoP1(?SC zxK>3Y(|8rAdR_4?>GivK8qCzbdl;KESdDJdq-q&t&;7?rk9suQ87nn*b&af~3S>!^ z%Bv>Qx5TFDKQ;XAq*AX-zi=k=N|jN1zg9I+dvNCu_cgORY4_K2%$do(Lhb z_T?Oto5$?UF^M~UJK8A+y+@)Yyp5)efY8yq0e0_K?5&S33u0RpMX0HuOg+w1N|!xM zHzo(*BTkwNn~L20N%;em)~OgC4LUpx<7qz2<85$2fgcboV>k^McX(|q?6T+kA5VfC zu+>K2Yg%mww4Ek2A8yIuz;=r8TJ$X)3N9_1`bg4l(`<5!Km3yA03lGHa*P;NosVaz zn0qc_VdNb4M8Y;GmAyk04vTC*RY|z0!Xv(vGa0bbO7DQA6~!H*1!Xn3?W;b?8^kNb zRI!HcQ{~W87HK}M_>TCZQEC!e=G$=9p1#&yLJs;5JF^7~pG~k`F^JbX;FRXh_Gxb4 z1*gLe;V?;+HfvN<(ArOJ8I^~o)_8Dt(!gA~!bXF09?7=Z!?fuJu-Yj78qyDQd;#fh z2l=o(E1adj-}=r7IM(e<0rcOJea%aq13(FgopR@bE0txSGrwRp2ps*EObiz!{w#SD4;xB<`HyP zm3~#(MQF9xiE&{~Vs@ux5i=VgT+_Q=WD@GW>4JA6>ND+nZsfBzBOCWCu;A7}p|`J_0Zge0Bwh8?aY@kZ6nBdIL$P2jBFeaS=8l z7B++)Yn-IhV~z;cS0s2OsfDx=9PX#Z!%p8}@?|xqyZ@vW-mlxy-Z5RTZv04=rG!r7opT^hy4T` zECz<^hug+oMsx*M6c^zAJLK@Pjr?uWY<60i4rsH_6Iyc`k<|7SIhc=OM6G@N{#8S4G16umNnTb&2byGf*I`=Wg~DO zpN|Ln%}EU~yX3M8CT=*kf%l|9SEkHoA-G@K^q-7p4Awn|Zf?i}9~oyP3%4v6z);vI zMP1MadIc8`2%Jld!{3u!|DWih{`}8IC3!0uhTGw#e$L5Bw`ezJCc&%Pml-YEQDpT> zvbd8O`*^w*#HXtcMHaeRqw`9$QWHIqUC80g6q1uUrr@jZX%~@OJk#QGzODuoLL5u91SvADGJSvF*=Ho*fs`MJQGbNbZ1zv+IApM0OEXZ${8BSt+VZ< zr&kTXQa&H;@p^}blTfWHEd6wUY+G@G`@$EIhc9NxCN4Gdl0<{%uW_`AwD(ssc<3&} zFnbbMR)`;87xd)M@JWtCeDVhPNoi?Cjf{oW<$Ue*+I1R5&pF!BmV(xIl|Q;5)T;$F z5#`{ZA80xF_L@^G7F>lbDN~UBHY4D1}wK{sWkAgyX#U z#w!Ict*#9{nR#W%285sRgS`OcauP-iM*~U-2xnGP@;% zBH!&GD5p{TgL4{?xK`lp1CcJT^A{6CT6y#y#UXvs1k4@nI)9FV8l_45U6U0%YThOZ zx~*_dWYkH3qmZpEMIzQcJ&jJ5N(H=fHf7=ze|{S1Tpvgdb*4GzYWhM5T|C^x^llx8u?!4p5+hfLx?Xuiz3rw zqX%M#F=%i1-A6uw&Xth7g+_cK1;HMi9@jRCa3#%wXiQI&;IP)i$DBk=!$Y7)3;WZ$unV@!~?<1TGP|G_N7-4uK|MO5P z;UoH+PGy@`t)lgkp@Ztm#+-X6F#Mohx=2$T7e}El<6thXS={st;VadMYJF7C$ub?m zpfh3%(z5ci4D(@fFPg6~6r{kHx;vGM8x{$M=c{0XEk8pMCv!fU(Es`lo%m3>u~1$h zXjSUsa&Oonk(MSe+dl zA|M8#fuH)4LqSUq-H6agTivZtMI~!CAbRFhjEqNEob+Kz(b$omkN`5k8VD5FnEl*} z8y)h!RNQvN=k;K5YpWZ}(&?j@onnVhk$9J zS)PR^kc~(J$QF*ixidqI>!Vkvasn~Q2tduy^$CFvD}G2@`##g7$6pBk4FO}_GCb$fM(9} zSxb<6>JH~6jC*6D!kF*v*XDXA^>R&;URIHfY(jSC|=E2i5y#gi(Y9>7)Q8@Q&=}~G% zpOG2N_C|cN;F1QQ?OO<3PcT#-u3WP0xW?gQJa~Sx1nwjP+2uZ{XsL{PeugdZS--2W z+Gcdk_HQ=sHtL}*06J1b*z+*Xf1FL z_7MBRiItK#000q+L7vJ*6)YwH^YNRG@l%PqpD|JgYygEmAJ4Y5m`Cimo6Rv%JK6Hj zU8yZTXe4(72XSQP|2ti;m0L>Hj50aJiS9_ByF;ByyQfx|b@0IB9+Qq1t1SZQ5Y;FA z3nudK_WA<))td(yyjE2FZ6o5eoyEB?w9_6~VxlFLdK`K-y`vwscNeR{2%lG#`U;$g zHH&G}GfkSv@z2tRC(d2z1}N)YILlNNXv3OBSEI9o zyo57$tRLE^@y+}Q3vmp>wuX8aLi0pZeZpFVTS4O#U%hI_ov>jZZxqmv=3O)xE+*}j zzm!RZZ(hCVWPZjZz}HdJ)~F*%??)MzKzxN^k=1b3*kCrWMYD7#K-!V)7Z659<@$2{ z0>AAe^x%X%BP+*1%~%~J5nz1&fG{W#>Cq<1JR5=8G!_kwky#ELFfw!o_3vezET@=E z-d3DxscsZx>DLm%V|Nvki-=WG(O_REUKp1o%#DrF$-%r=Fju^EyMjbVvRzHazQ8a| zZLfyHsHkc?G;NDTWfw)dX~_~5Fq*0JRV!*S*}uw^0~^2|VQOq9#v=9rlO!BtB~gFH zUJ79b9#fM@olug5VQ1;|85sNi3OdE`mN%nW17p>u#M{+2CB;k8G{p0w_QeHEo-wav z&^$0DPkG?J)XOjq2{JFNOotEA*#&sDtB>Sr2gYyAuwdbWIXOU|(qG7|uX% z*39P85#3L3i)`y{8hokXL2=)wK=;AHL%_OkB%7vL?BJrpUQnM@ejH?D`!FN<`R-L} z-d3davh0lgFXZt*t3wE*wjT*9cs}Dt6y;CGf{u(D&iFV4m?f{(N%Jt3z&+Zs46T#k z=C_Vs-*6G62p-^Y#Limv_7?q7V6NpnK$1#>O`V`g#i97va8IhfVWDX(V;|2ts|tr# zN_F=j7lx-To;4RsK$FD^f|G_)N0e%Kv+SfvFJQ5hle;$n&|>(RR607ar)9;07Xrem zvh}$rC0gw3)<1=&|6&}#2y}cl_q`Oixo?-hbRjYw=4Pn1v$5AM_t5ug*R7EF(z6xkv+H{L!;IgC|Nb=2VSvoFvVRnln?ii^TOo(z*tu1 zBX>%VoPD7}oR=|BBn*$1C84|zj~R)=oE|rrGG=;a_D1Ui+GbdTqA@fdjqIW8r`-?OVABb_=Nb*a*4R;A#;<$T|?M83R#vC*_46|0@^CC zN%x#93Q|UuuBvrxD4Hao6M;{EzOnSb1ZEh122ef?AzTfyR_I;2dgW<@+a9D?IyG1w zU{R}ea=HQq_4!Vl2P-{BtvCTM5k>JWOUvyvqEnkCJBT{Ka2@z{3AS3?k`!PxmYn(Z z8-ynjON%Wq>uIoa;hUjSD^=Xop>S0HhcXB%MUEYDMhEL62N(ZhmmBeNAd#ek+}zeV zUl2h;$)8qTvAgC@8}EaAhl?aV?R;fD4R{ehf6BxPr7QhURy$~+1$bVgTU5T)F167C zvdS(Yj|Af97ui*U!r;4rBw&cAwr9z&)*Y(G4|S?F#gx_A#g;kmheJo1+^J508Utg4$D3C2{k97_scKFkwTzrI}%@6Oe02- z^bj@J5C8~a2TV& zwec+duGm%se)=A*5JSA@01?tX7$?Cc!S|#s= zlbgSfFv80YjCyA-oDux_hzsJ^ItQMu-E5dSU;sWe{F!%moj@b;W!TSfA}B=xDijMP>5NCVbA z3roLiE;u5*9*KdL(Bdt8&oYueBH-ghBDR*-M1&d3stjB;F?hHd22`Ar!wJ|Lh-3c)s+){){@Dji6t~s~MG21^LVH-g8&t+;xc&+`( zB<0vQ+15CWPL>RyAW6RM8B7}ZGJH21uqDyhxfIM_WBJk^**Is->xV#Lg9UT+3pVZo z2QUWZwjE_U%^NHoo$c@A{8EI=z+wj@%qe6oLUu5k_P^Q!y;u2~T(di(=70VJnFtvi z6mBhd>597J>M6tCzD|l<1RkGW1=^JJia|L^1pZfb=^YLx*VeY}yk~eLs8ZYytnhi7 zQpuD9D374}b0fY;iccKSnkfagKRamD-q%y%Z(d(EZWKkiBq-SuQ-oZp3xd4<6w%g3 zzcYv)_qHm(j{N$NdTdGaeK^-e1yY%;2gE^VRC%meff3pdt(}|1WAmT@^4cu}A6cX`0atJf*7>;q0>UUQreEpMQ)e~$8JIb{z$}VJL z1|=2Kv5JMNuRnq|K>n}O&HYSaQa{W326h@(&8hpQ z+&cvkPS^5Qz|fUN>Hn`C7*6;8F$)q)`k#JK>fd;nL?+jTTrofP>|r$q2H#(^?Zvwi z`jMy}?OEmYlG!Vo=M1wNLr*g15jnnF)h|`6CVNB96KnI=nFfCjYH+DW%&UgP24b(P zK5&=G?0QrPJy@-*%(Oi=z+xKlWp80f_0-2CbMw!D7qh)2SZo#TiN$x?M*shT*vW4J zN9W31z7;QH;dP-Mk^Md65knUQrT>)|RSA5T%Bnfnwxg&H zf*2STEYRW^(8Pv4a782i{DxM*l_i`JA(w0b1~t*wMH}7QMXo{H>CJ3K!rR+Q($j1l zAF!@@GTPDlshL)KghQ4+l)EGDi5cQPaFPKpy3BW0UD8y70cru?QT>GWdB8SadjzA4P&g0_*Ma!?K)C)2brFq^w?~zuW-Ut#-z%`_{V4nT-+0x% z?rH!JmJ(HAFefJt+^b!cdHolWc1HqHq21*q0PTw_pxZ^CrRw!pfqMlpP+Q4S(3cqb z+tQ0SPe#RF_OS&F8}-X(Zqu6_j&DcxQuxo4__v!S$8{g6sRqj0v!cWeOnZgS3AiV) zcFGD>hyzQL@Bq!7=r!J=P+q!LSO`}4ajhkv`%PJDjF4E8>&p1#yx)uLci6LBrnZd; zJSD01N;=*evy!KubaNXh_vWV-mpVG~acbo|ZacE&($jNCTII(_t|($(|MRjnIg#j& z1WArSXsnhe*cwK5--M_lt&+X-h1a&Z+ElJJ-c9+4jRuWg5e1zuYCWKh+)9|Is0YU|AjP zXB*WS%Af(aH_^@KmxS*EySsrk z@g?|jUv2anu#jCS+Rl>sAac2AYU0{z0Sl5Nk9`l^I0#p(yGW7yD};**x>(n3ivcpu zwk?-i8kIS;eizy`;adEJy4@o;fbZ8Cu-WPMdoCs$QbwHjcGeq{(p8U80VsA7d!Bt& z3@;;xBfqCPbCn9azbfef!mC<|fILjQ6tYkvCPrA>>pL06B}iO2>vuosuUcL-wj{%g zh@SzGKi{6ad$~4!{wfavVN^a#t_}DS@z3$HUIGgvCeGnGV z9B%{VeW2yjv!jOiO&vtx?D`UBC14J?Aatt|OJ1w-V}JPHr#iCc6-TOQ`!uWO{5?N2M zE&iD;#1qaaw!9%;`qnVVgIxnojslILL|#igR<({B6776wovWPmjR8Z@$30{@{p(T& zi9(6`^+SkPGoJIRtJBw!W~AWOK=EqF@VJT`fbL)^CXqViGj*|Tl;qL3g~WyIz;-d8 zOy5f9^-!SzaITZ#;0!X4zuXtZD?TF5-icVkCy+|MzKFkRvnSSg^N+-p2s6|U={!_) z=^a6awlt@j_t{CC&jxFiKX0>&f~|65u8Y3BnY*Er?vCXe~^~%F+e<*SGkD^I#UU2 zfN6S2Yqu5qNvL8Vf%jZ1vXRGAuLC8wlZZ4*NJ^k@aa=L5>^4<(6HxN>IPvkB)2C;# zwG))TE?WD?@oyxD?q_Ek6{q@3?f-dQOs^~*=h(cl8eK?W)hY;m#Gwv;?bl=AMS9JB7-Mc}NP6-$wX&wDSpd27zu>*ikn9>oQ? zofUxu?fGCeJ^}MmyE84}4$23JVPZ8{(^T-~aqvSu958buEmc!Uo$6fp431_~ybo>7 zCUlzKeA_w2igs1eYbQE>DO|I3@})Y@qkL;ln$B~=2=dVUkTM$zp~jhGZzmoyl_l&Y4j`gJutG%XBplM$!BKzqCn$a&kF6!+;Br}H*=2(!koPH+n~<> zE$yS}!UqEbrTLG9xW)RUy}snaegSMbb`$#!**zf}!~KLdX4bzJ4%Ke88CtE0S#P?m zy3w2^jyN94Mzbgt6qc)}2C&n>&!;-Ng*?ch=|6tU68#Unfqyowu2xBvRhOt*?ffzr_scy_kqk=c z!0!+bGW9zo$+YIrqi>(nd9`BzM?r<`_vt7rhF72gKj7K;SKo)}5 zv`8Nms#Y8e7iyR$avs?V6)(z)lS*`Xi%mQf#1$Sk$_W<}3%zzQxdX$D#Vb{+G!2=B z0kwFrSG6BmRYyF;>JRkT*vH05Fp;LX5xo3z~zYAUN!T>1wb5} zf0q88q2!8vk5J0z9mlED2^kz!9%5u5Vr;PPAI9lAn^ioeNvL=T;sOa-Li#8 z&aXWongwzl*o0Wx{kjpsS&^>4ZN3FG8^&+^{zw{OWsJYv3R)UMDC`AID}U!OR4c@r ztIp_I)Lq6D8Id=?SVp#8dW<}_mtgj=1b?_q+9$er3unU+F%wARAKJ|!=9wKbDB&1I z3qtUrni_nHT~bN|k)aPj>%7IdOae{>Fdez29l?LvvP;FbzlxzeJjp(Q#w;j4BiT^o zE9e!Hp`&1hm-|_r*x|bd7QMwn>y$>}cV8onF4~cjS5uVKtfRG=ySRo&MkT6q4vhoQ z@Z=&~1X4G|d;b>722$Y?E|d~Ngj5xRr|E@cFDM=4?V_R9NSMK*me9AdmE&rRi|}xX zf7xGrNxQVoSA}Vc8kdnP)OI_QTQ3+u6f4$%@`Rm(m1A8hZ=JgKwyz-8`kC@JYrAlu z@7TfEHI^pFHxgM(r-}ye`K%L9GP??gMoigs{>&&X+rOw_;h3jI;$R`I=>>DoJvN5( z?_&DbPj95{FoLU`)S^6cYH1r+AK=YS1l!EZ3|DkJnwuI|mv(rQX1RdV9y;(~HXhX< zzMk~;hYztsvef09gGZmFSgvoxxeU4ud1hi#4E|Qw2``LD2B?;0{+CQEuF{nGgfO8RyH> z)*0$-7faSU{o@^6Am}ix<0@GDM@VAB4LO}8Hwj+YQGZwl{@ew4>lgMWt|sbou*3WT zs>%%U+Mgup%{i>1x2!S3qn=$OCQ(7SaefC_=e;8B0amE7fg)jwPI5iUM-F&(^Vyfw zDPZ&%>1vF*%PruPF5g3dwn)&v*RlwK91-AfYKRCWC&H;yg<#7Uef1>bNZ{bSFP+~= z`|z1kLU`QA@rJA+5|t5USX4Wm{Aw(+e!4jnl{FJb0K@P5aL8BYmLWxKnEN&TZA%^u zQ4)!hFeTOLK@n%NLB!vT^FUHi?UrraTI=Sb8CvalFnKv2aKirCX@wg@_Gsndjel5r z=OepAj9WK;c5HkRlYygo=NY`*~bWo4fL?YVtdm7aa204)ipy(#%3r4 zJr)mD1$t*$AgcX-%-1b&ArVOs>@Sifknc?Fbk6uC99vgpPvL8hg#A50Q8jPSwhvBJ zR{XAInv~2Q80QUUV>8;wz+fanp9V%J<(%T$$D?-5D_|d87tNqKKQuSub13 zshvSl1wl8`OO&7Du~dKm06iuG%F?RLIUFbLA;2s~F_ zWX~`!*P5PG*Aab4F*zuhOCa=jqqySm{I@ye$UZXC|Ca+Fh^vxe5!&ab8oyyQp)s4e z?kx2;smh3$E|;V=b0;pT9u3+SY=Qn&801t@wSa~vGH$MbxZvuXdq7C1vZv-3NIOW- zX-N!XfMA^CePkEkDBixIRp!kt+wPlCS-`jjmrp(I9LUqp=$|egkBN6lEALeKcSBv; z7H=tgoPC4|D8I$;6g3*jVb0&G^aJIG;EKN^kPHktcHaEJ({ymVEUHy<8T$p@aP5uX zz?Et>AqSfr;yWQ5!~KLdCf2_e4%u6-Dsv>*m6rR`#XC8Lezq;%$Y&i;dlh9K@I<;I{dVU@tdcYbfuC{J#lc>3o=~?p zH;`CK2Y<(9ewj>&iaY-&_B1f9wl)aE+2>&f_YZO!71V*3%CdPjj#t`3IHg)S+l+%P z=%QqrKw`aeWIq~uXwQ^X5JPYe`-7c3R(*;`2z}AY6(5nwn7~9^Tn&^x5hTAVj!y}9Erc`s zk;o81d?4mr1Z$FodB)^oBjJ|a-#4y;}zz)qx*P8BMY}xXg zUz5*72+==*ajR~1hZg-7ut{k00?W8dm_I*^rY16F4ByxOz$jsX(lmZGEm35#+?eCT z`eDaUt2iF|+|r)?>ue7FB8(a^r!(uxKC7=bkO$G+Sav=d-Q5)%7B_$!PO}nCmhq*#$=rYx7dGc#A+-ukU15pcyOHA8Beqf8BZS1)0xu4{x@c69f(pn#po)jP zOqLk45zYENSs$r`F$X8&-3RjMZ!8f2JuqGKmy2pcL0?#FJU-7AyUo3kCYC$(+q=wt zDuVcky-p_+6g6ANw6pAT(s6$nNn(F$Yu8!V20TaewKo_bZy3Mge@G`S#EwlBrATaI znbB2%@R!`1>X<%#DUOMGh#+1K#+@0j33V^V5>b41VKrxb+m_#AyS3SNE&Pfxjc@Yz;G$4Do{I(Yz(5!|GC^hdwBkDD?@sbAj?#{L~PQf@yFQQx+w&q_^ZKu zni4TmnCQzhVCYq2XbaJghq2#DTJLu22PP9CYup@li<=Ca^HPh!26=ppWpA}=!OjIo z&8*4iL;;TP&thgDuj)_Q(6CO24(pX1U^oQBpaMHEhKh_}n?MCt&9s&C9U|o3?!5Eo zicxAn+(E0&D~^+>a61(inHfidzhEy%%Xfa_C;Lez6RzY+qzg)F>A-3K z)$(U6hs-lm&WyDZmv{R@SOgzrxY-1l`m&6WnLj(#mn`!uYgdkR*!^YEs#}f=ZReQJ zOdkxtX7{H@Xuq==1CFFQVmeD0?AQu2Hrc@x@Rm>biCf%NPN=53bWrs`AN<775+D-& z3$<4bgwN{=#C&MYv7fix#4;MG(?A{yMW2d&n~4IH51D{yX$SItYO1@j<@qXRP1zDV zOt`*)=XIK&z8fB{bW}J4FdI9$;zL`Z?v)5eH2GA^u}3fIo|b4bMCIaT!e6snv9X9K z@QgsL&C603S(AZ)kY*LOzRW0h*a#ucjc%)UPCtGKP^y73$2(NaVG#jKIVf=EdT`j| zk9ENYTOHyiEFaTLJoTe~ntv0)EveAM?^?XPQjg<d!iVZ`L#EX?3KbN(E zzZ6$z1ll@55W}bNTduvghtoOc*?2{OX&Os@{ZN6EF@cZ%SxC`^nKcaugxI}Q)NqaP z34%wi-NjTWdz8x|@!U2VH~1d;5FUM+BRR)G9voLDk|i8^J5!5HV1VV}nF2PqXU69< zLs*P$M5cw5K5p|W@x}LCJ91WHe%OR2rtgVOFGK0lodUmv@05>#w+(Q+sqs5`*Ie3l z*fV6vt6pdFWyr7Q%gF*1JJz*+?dv6%i1@0hA@@Mggnaf94@@KeOtw<*tjT4g%HUr@lkP-BbI=fy2@VJ85^&5;sJ00R9#?QPgYQG=f!7iuK;j=--!Ns0*O_)_sKv$leV@EY~)1pGfyq~Bdu0NPLr!Uqpo?u!ka%yG+yhr3MRMlm*4#BbR8s>vFk(LH+utr1y1C#=%YBtqo)UvIGHhZ`_7MBRiItK#001^nL7MPMs6lL* zObNg8e?OEidekC9?5hSECP!r&sOczCxUTU2$8RDcg*i$PgCWe`d>Ll%V)y5uL7WJ6 zp8xj6c{MCY(MyF<=nR%c_9 z*#~;J;w%xwPljIgTK_Rb&$;BSC9Nu3IgpHIb-CBeqG|lVzd>l`cZb)-9KLX^GHlHId>~Z z#A6Dfglgj7X1)#|7SEU)kdh2lC!TFWa|HFq#)+2-QIxLgUVjL=@-aG|6FeLS=7_2l zF_Zmt`y0^QZlWZ;Hm^MSugDDGReiR}#C^KOgdvX=dsxv>7+L7JFq?UFSep=`^>A?0 zYp=c$(I|SNd=Hfz^_pKoI+99+ZszRQG@zxB-Jm+Y?G8$KpY+XxG|jH=Mv>qDQ)nD; z3!pvw-}|1gn~LN@)sV)+u8ws2>-iS}MZCm9-GIQ6BWu~E~${+Akvf=(IL8O6%d;ceM| zz^5Nyn_&7<5z%#|C8hFPD@%q34i*0hp@qJc!-J|JH6Hb^^=xN={io>R<a)RWLY8F&&j#v&UR;$<`7?^SNI#>r*yHTr?>xr89f(iE;?YF87&;AHk zcr~Wl-j5aZLy6CuEA-;83QF0Ti%(g#&?P2-FwB0&%U#I!O_@_em61d)RcBm|T@Ay# zMyTyEE`g>2{L(t{eWM|>g5jo!99dFDLwP23ipLQ%<+RQM5)R{8Ea2A|wi?uLMchG| zp$Rm<@R0#CBo#*+ZXpJXZHsex=kZ?$%Y6OJYin=*xxUdi#of?-$|QwDj2XE*FQfe1 zr^zOF4jeM5tpDr5%<^(x8(!X?kZ=R_Vf#cRW;vP$MGLStmL)POz&l?5{$uMqB@kZ# zkb(b$CukxmC|(Za@8ET5 zLSQc=oU9?RxR;CF^%O3n)jR9mBav@MojYAu&HKcSxydZP?IR?p!tzI@Dv(vk&%vOp zq`zL|k^$m>CI3DNx&amFEp4!{(VRt3Dat_*YD{*dot0P(-`3bBi}BQ50JzNAafNa4 z)1G$~p^RTIP1l^}rZAA3l7MFt2XRCCLQQ}MJb0tpi_cCbTqNiaO`EbU^60{jmZ@hd zqVm!3k(Bf7#!plz&g%U_V4V_}fy=`T7VY0hiUnS z#c9BPVspfB63zEF-e4l_-wjq*20 zj{q5$=|ODQ0#n2B?r14d(-Fk3@Z}?)FJ1(gacJoclU}2JkJr!vw_mD=LQ12w%1?vH zr^h^*z$J<_?ZvZ&_wEN4aFzlo_#6*chy8QiYF360)|=`e`tRQ^N#3waAv{{!)nRq7R5gTckc|0w8ApywWRGz&<4ziX-EJBGR|ROvb3H@qbUr2Acg!1 zDJe*FFF5w(8b0MJ@lCH&$MLxi$JY&;%1j*{>0J!f5S);HLYop*O5JT{@HbSv0ZxnM z<%o{Dw~xvnA-X-i-Y6`(1%hQDjN?xnbS<=q4pvtnNlGRSQ860wA9M(=^%#mnW|>XJ z6PCR8Wsmc$s27GiWU_~$UYGj&9z8;6F+ZQjMK2^MO+h-fq z6_~7t1}$TyX{Ubh)O0jtr1>IU)d|I@(DovXK>_Tj<7V3?`pBjTFh~M* zgb`D1jQ}wvjyj~hInQRJ9B!FfNwF&@Wp6em|&d>XzO^~+naYznsg z*F2UcQ`rk2;s+But!P^gY(0T!x~{?tq@gSUwL=?^o^6+)5X@Bu)Ivv%6mkly-|(Dbn?+W_~7gWiOhb9<`K z(i3`kT_tr2SYcf#5D1rA0ZE|SNL;mM-^&gCl?i(ODLb=IBrSI&(0n%m$T+k3yij8w zb64r_(pF0Uz**C8$A8cUbu{Dl!EfGM)B@E?zoiT?a-Bv^TPqULQQ4_TcgOKXpblkp zbj-pviK$|Hxb0*4!s=(=BOFV{-tV&M8*+3}gHwJDPIHkvYKh2e{+kxZNyXTGH+4Fl zPk&WqRt2RqQ=^TIiRK>mTE1Gb5M6Hc2&mRkrzLwRUBcV0gC_!FfR<~#DX43Uf{yRv zvtMqBiCZx^Dx-W$g5ZjOP^q}U2-P$kVOq!2qu`%(aZXzJdyf5}Als)@{HPn}9J}xw z7+|6`dyPVmbG<3YwAIjxY2am3v2>~K&1D1TXMOJ)cpLHuPQFyIPbQ9(@aF8kAr&M% zusJA|SZ8`9`SpXrT_qf^5Tbe8t!*QMX;z*pU&bf^iy4MdX>b@hGx6p7kCPuq6@NS} zMjUasDYk_U=xSc`5ciSLNK(3Dt%5d7=wf~H03S378ua|WOP+qOy%iRN){dIQCunL#dH24B(;6N^L{A7s0J&C78u;}@2`0DDdU#g|yAS88nx3RXoP5U(ng|A?S?5iL%D}*&uQh5%p z+f{{upKP!Nwf!Y4>b(hxNaIv>EU(1K!HmNToiyioNpjxs(@@g6mY?decE|uda2lDD zFx7K$H&B2q8WxV6Aju@mj#v*E#XXhRX=m7#o7(=^=s^{eeKhRL)q0OJ(Bq<8Ip2&O zj=t3jLS?yNVf5NLc5MM)pdP|}c*QAt9pS%uGy1byG}_7!pc$i_=&p;y8&41kqi}Pt zshV#RA|NrvRHj@ft;bpTa?(v^6$c>Ik)o8+coiL486g;g8%ynF)sd3RF|x}!))VAG z-Z$^@+_2-1gHw>`JPlf8ZV*A98e}(s{Ik;V7T?l4By#EKsJrWt9<-j-(4VHa=)b&_JqW zMV0lucvjZ5(7{T7Xysqw};PqnX8^pgExbSxGmjkkNiHkE+`)on94 zxE66+EWhygf$!!%-_7>Mi;N|@JB_VFwQye@&rX5^=F|>NWy}}g9x0Tn_W-AD>gOlQcd!Sq|{*-90PIo3fvV!`enzlSV z-TpFbbj3O1yZ`%b_i1`yH)2{;NIv1wxBM9hjDSrH>4ZMkGV=IlHb5ezmxc}k8nsVjHfQYn2YbMOq>Jch4jk9$=0UGW z4;D+(Tgcgp)|mZuU!GtgtLL>Qd_c74KY6H*3L_>8#H?YaD{o|E*n3@To%OeArZ$uO z!`=;B-`VJZfW)XU>}61Lrg8?H>v#dthzh=g=ddK62C&kYJ=h?(Bt8Y6Jx|>>;u?R?H9Y;qwnSyfb4+hCSOgiY;%IC*bO zlwa^JcKK{W%pbkLp*rO|pq@0>`IId^&JeFWlp6>)pyq&oFuU|c8rlr6~3E~AMw7-(HDBZ~Xi}`G{%a>i#krZ<*W#! zhhBXC3W-ubUjt!p7D+^f`MT6w+Vaf2A?k7pJVV>PG8&(>YUfhiU(m)!d!+(#g*(Dj zc%veBK*QT*0{qaR-DV9A2T8-m+KvkVPL-wJo2dYjbmLH8!~?wO$Pa5ahro&{Ksgv} zZyO-ScWV@-&#sY!26*XW*JC zs;(uH&pp7$%r{L(XED(7rF=a#E#R#807h;em#YD&80qc~pkSbO6tUnx{xD4|fSARH zL8oFwsjidqW)6j$htxugAAGmoV*qwQiN9FgJB{Sz42NnrU~y|6i?>H>m2wAY(?ItA z<6v-GX8u8JyV>{DA1l3pFL?J!kltMy{=2$kT(+IlmhB;G3FWQTuG(gFJG1tMbC|L! zGoq#=2p9r|()R-#=VK%Co9}UyEA;w9{m!vhOXa)}bViJ(fnv@VzY3kED^X?(c1^^_ z1e&Eku!CA#zck{?+{m+U%%OF$bcRec)O$_A�Uw5M9GXcW`ORJiU;y7tU}{&ctqf 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 z%0D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

(rs9`T0OBCgQ;dCXJksRZO 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 literal 0 HcmV?d00001 diff --git a/fastvideo/tests/ssim/L40S_reference_videos/ltx2_diffusers/TORCH_SDPA/Will Smith casually eats noodles, his relaxed demeanor contrasting with the energetic background of.mp4 b/fastvideo/tests/ssim/L40S_reference_videos/ltx2_diffusers/TORCH_SDPA/Will Smith casually eats noodles, his relaxed demeanor contrasting with the energetic background of.mp4 new file mode 100644 index 0000000000000000000000000000000000000000..545fb2d6926503b3f366700da641a65e723aea0f GIT binary patch literal 278898 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�lB(kh4f=(S%z9uVT6*=W;#D1yJS*<7 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 z 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 eyH}4wWNh%K@T);U*1*-2<2}=0.33.1", "torch>=2.9.1", "torchvision", + "torchaudio", # Acceleration & Optimization "accelerate==1.0.1", diff --git a/scripts/checkpoint_conversion/convert_ltx2_weights.py b/scripts/checkpoint_conversion/convert_ltx2_weights.py new file mode 100644 index 000000000..bfcbf58e2 --- /dev/null +++ b/scripts/checkpoint_conversion/convert_ltx2_weights.py @@ -0,0 +1,444 @@ +# SPDX-License-Identifier: Apache-2.0 +""" +Convert LTX-2 weights to FastVideo naming conventions and split by component. +""" + +from __future__ import annotations + +import argparse +import glob +import json +import os +import re +import shutil +from collections import OrderedDict +from pathlib import Path + +import torch +from safetensors import safe_open +from safetensors.torch import load_file, save_file + +try: + from huggingface_hub import snapshot_download +except ImportError: # pragma: no cover - optional dependency + snapshot_download = None + + +PARAM_NAME_MAP: dict[str, str] = { + r"^model\.diffusion_model\.(.*)$": r"\1", +} + +COMPONENT_PREFIXES: dict[str, tuple[str, ...]] = { + "transformer": ("model.diffusion_model.",), + "vae": ("vae.",), + "audio_vae": ("audio_vae.",), + "vocoder": ("vocoder.",), + "text_embedding_projection": ("text_embedding_projection.", "model.text_embedding_projection."), +} + + +def _find_shards(model_path: Path) -> list[Path]: + if model_path.is_file(): + return [model_path] + + index_files = list(model_path.glob("*.safetensors.index.json")) + if index_files: + with index_files[0].open("r", encoding="utf-8") as f: + index = json.load(f) + return sorted({model_path / shard for shard in index["weight_map"].values()}) + return sorted(Path(p) for p in glob.glob(str(model_path / "*.safetensors"))) + + +def _apply_mapping(key: str) -> str: + for pattern, replacement in PARAM_NAME_MAP.items(): + if re.match(pattern, key): + return re.sub(pattern, replacement, key) + return key + + +def _load_weights(shards: list[Path]) -> dict[str, torch.Tensor]: + weights: dict[str, torch.Tensor] = {} + for shard in shards: + weights.update(load_file(str(shard))) + return weights + + +def _read_metadata_config(path: Path) -> dict: + with safe_open(str(path), framework="pt") as f: + metadata = f.metadata() + if not metadata or "config" not in metadata: + return {} + return json.loads(metadata["config"]) + + +def _filter_transformer_config(config: dict) -> dict: + transformer = config.get("transformer", {}) + allowed = { + "num_attention_heads", + "attention_head_dim", + "num_layers", + "cross_attention_dim", + "caption_channels", + "norm_eps", + "attention_type", + "positional_embedding_theta", + "positional_embedding_max_pos", + "timestep_scale_multiplier", + "use_middle_indices_grid", + "rope_type", + "frequencies_precision", + "in_channels", + "out_channels", + "audio_num_attention_heads", + "audio_attention_head_dim", + "audio_in_channels", + "audio_out_channels", + "audio_cross_attention_dim", + "audio_positional_embedding_max_pos", + "av_ca_timestep_scale_multiplier", + } + filtered = {k: v for k, v in transformer.items() if k in allowed} + if "frequencies_precision" in filtered: + filtered["double_precision_rope"] = filtered["frequencies_precision"] == "float64" + del filtered["frequencies_precision"] + return filtered + + +def _build_text_embedding_projection_config( + gemma_model_path: str = "", +) -> dict: + return { + "architectures": ["LTX2GemmaTextEncoderModel"], + "hidden_size": 3840, + "num_hidden_layers": 48, + "num_attention_heads": 30, + "text_len": 1024, + "pad_token_id": 0, + "eos_token_id": 2, + "gemma_model_path": gemma_model_path, + "gemma_dtype": "bfloat16", + "padding_side": "left", + "feature_extractor_in_features": 3840 * 49, + "feature_extractor_out_features": 3840, + "connector_num_attention_heads": 30, + "connector_attention_head_dim": 128, + "connector_num_layers": 2, + "connector_positional_embedding_theta": 10000.0, + "connector_positional_embedding_max_pos": [4096], + "connector_rope_type": "split", + "connector_double_precision_rope": True, + "connector_num_learnable_registers": 128, + } + + +def _wrap_component_config( + component_name: str, + component_config: dict | None, + class_name: str | None = None, +) -> dict | None: + if component_config is None: + return None + wrapped = {component_name: component_config} + if class_name is not None: + wrapped["_class_name"] = class_name + return wrapped + + +def _split_component_weights(weights: dict[str, torch.Tensor]) -> dict[str, OrderedDict]: + components: dict[str, OrderedDict] = {name: OrderedDict() for name in COMPONENT_PREFIXES} + for key, value in weights.items(): + if key.startswith("model.diffusion_model.audio_embeddings_connector."): + new_key = key.replace("model.diffusion_model.audio_embeddings_connector.", "audio_embeddings_connector.") + components["text_embedding_projection"][new_key] = value + continue + if key.startswith("model.diffusion_model.video_embeddings_connector."): + new_key = key.replace("model.diffusion_model.video_embeddings_connector.", "embeddings_connector.") + components["text_embedding_projection"][new_key] = value + continue + + matched = False + for component, prefixes in COMPONENT_PREFIXES.items(): + for prefix in prefixes: + if key.startswith(prefix): + new_key = key[len(prefix):] + components[component][new_key] = value + matched = True + break + if matched: + break + return {name: weights for name, weights in components.items() if weights} + + +def _write_component( + output_dir: Path, + name: str, + weights: OrderedDict, + config: dict | None, + dir_name: str | None = None, +) -> None: + component_dir = output_dir / (dir_name or name) + component_dir.mkdir(parents=True, exist_ok=True) + output_file = component_dir / "model.safetensors" + save_file(weights, str(output_file)) + print(f"Saved {name} weights to {output_file}") + + if config is not None: + config_path = component_dir / "config.json" + with config_path.open("w", encoding="utf-8") as f: + json.dump(config, f, indent=2) + f.write("\n") + print(f"Saved {name} config to {config_path}") + + +def _build_model_index( + transformer_class_name: str, + vae_class_name: str, + pipeline_class_name: str, + diffusers_version: str, +) -> dict: + return { + "_class_name": pipeline_class_name, + "_diffusers_version": diffusers_version, + "transformer": ["diffusers", transformer_class_name], + "vae": ["diffusers", vae_class_name], + "text_encoder": ["transformers", "LTX2GemmaTextEncoderModel"], + "tokenizer": ["transformers", "AutoTokenizer"], + "audio_vae": ["diffusers", "LTX2AudioDecoder"], + "vocoder": ["diffusers", "LTX2Vocoder"], + } + + +def _write_model_index(output_dir: Path, model_index: dict) -> None: + output_dir.mkdir(parents=True, exist_ok=True) + model_index_path = output_dir / "model_index.json" + with model_index_path.open("w", encoding="utf-8") as f: + json.dump(model_index, f, indent=2) + f.write("\n") + print(f"Saved model_index.json to {model_index_path}") + + +def convert_components( + source_path: Path, + output_dir: Path, + metadata_config: dict, + transformer_class_name: str, + components_to_write: set[str] | None = None, + emit_diffusers_repo: bool = True, + pipeline_class_name: str = "LTX2Pipeline", + diffusers_version: str = "0.33.0.dev0", + gemma_model_path: str = "", +) -> None: + shards = _find_shards(source_path) + if not shards: + raise FileNotFoundError(f"No safetensors found in {source_path}") + + weights = _load_weights(shards) + split_weights = _split_component_weights(weights) + if components_to_write is not None: + split_weights = {name: weights for name, weights in split_weights.items() if name in components_to_write} + + transformer_weights = split_weights.get("transformer", OrderedDict()) + converted_transformer = OrderedDict() + for key, value in transformer_weights.items(): + new_key = _apply_mapping(f"model.diffusion_model.{key}") + converted_transformer[new_key] = value + split_weights["transformer"] = converted_transformer + + transformer_config = _filter_transformer_config(metadata_config) + if transformer_config: + transformer_config["_class_name"] = transformer_class_name + + component_configs: dict[str, dict | None] = { + "transformer": transformer_config or None, + "vae": _wrap_component_config( + "vae", + metadata_config.get("vae"), + class_name="CausalVideoAutoencoder", + ), + "audio_vae": _wrap_component_config( + "audio_vae", + metadata_config.get("audio_vae"), + class_name="LTX2AudioDecoder", + ), + "vocoder": _wrap_component_config( + "vocoder", + metadata_config.get("vocoder"), + class_name="LTX2Vocoder", + ), + "text_embedding_projection": _build_text_embedding_projection_config( + gemma_model_path=gemma_model_path + ), + } + + output_dir.mkdir(parents=True, exist_ok=True) + for name, component_weights in split_weights.items(): + _write_component(output_dir, name, component_weights, component_configs.get(name)) + if emit_diffusers_repo and name == "text_embedding_projection": + _write_component( + output_dir, + name, + component_weights, + component_configs.get(name), + dir_name="text_encoder", + ) + if emit_diffusers_repo: + required_for_index = { + "transformer", + "vae", + "audio_vae", + "vocoder", + "text_embedding_projection", + } + if components_to_write is not None and not required_for_index.issubset(components_to_write): + print("Skipping model_index.json; not all diffusers components were written.") + return + if not required_for_index.issubset(split_weights.keys()): + print("Skipping model_index.json; missing diffusers components in weights.") + return + vae_class_name = (component_configs.get("vae") or {}).get( + "_class_name", "CausalVideoAutoencoder" + ) + model_index = _build_model_index( + transformer_class_name=transformer_class_name, + vae_class_name=vae_class_name, + pipeline_class_name=pipeline_class_name, + diffusers_version=diffusers_version, + ) + _write_model_index(output_dir, model_index) + + +def update_transformer_config(config_path: Path, class_name: str) -> None: + if not config_path.exists(): + print(f"Config file not found: {config_path}") + return + + with config_path.open("r", encoding="utf-8") as f: + config = json.load(f) + + config["_class_name"] = class_name + with config_path.open("w", encoding="utf-8") as f: + json.dump(config, f, indent=2) + f.write("\n") + print(f"Updated _class_name in {config_path} -> {class_name}") + + +def maybe_download(repo_id: str, target_dir: Path, token: str | None, allow_patterns: str | None) -> Path: + if snapshot_download is None: + raise RuntimeError("huggingface_hub is required for --download") + target_dir.mkdir(parents=True, exist_ok=True) + snapshot_download( + repo_id=repo_id, + local_dir=str(target_dir), + local_dir_use_symlinks=False, + token=token, + allow_patterns=allow_patterns, + ) + return target_dir + + +def main() -> None: + parser = argparse.ArgumentParser(description="Convert LTX-2 weights to FastVideo format") + parser.add_argument("--source", type=str, help="Path to transformer weights directory") + parser.add_argument("--output", type=str, required=True, help="Output directory for converted weights") + parser.add_argument("--download", type=str, help="HF repo id to download before conversion") + parser.add_argument("--allow-patterns", type=str, help="Limit HF download to matching files") + parser.add_argument("--token", type=str, default=os.getenv("HF_TOKEN"), help="HF token (or set HF_TOKEN)") + parser.add_argument("--update-config", action="store_true", help="Update source config.json _class_name") + parser.add_argument("--class-name", type=str, default="LTX2Transformer3DModel") + parser.add_argument( + "--diffusers-repo", + action=argparse.BooleanOptionalAction, + default=True, + help="Emit a diffusers-style repo layout with model_index.json.", + ) + parser.add_argument( + "--pipeline-class-name", + type=str, + default="LTX2Pipeline", + help="Pipeline class name for model_index.json.", + ) + parser.add_argument( + "--diffusers-version", + type=str, + default="0.33.0.dev0", + help="Diffusers version for model_index.json.", + ) + parser.add_argument( + "--transformer-only", + action="store_true", + help="Only convert transformer weights (no component split).", + ) + parser.add_argument( + "--components", + type=str, + default="", + help=( + "Comma-separated component list to write " + "(transformer,vae,audio_vae,vocoder,text_embedding_projection)." + ), + ) + parser.add_argument( + "--gemma-path", + type=str, + default="", + help="Optional local Gemma model path to copy into the output repo.", + ) + + args = parser.parse_args() + + if args.download: + if args.source: + raise ValueError("Use either --download or --source, not both.") + source_dir = maybe_download(args.download, Path(args.output) / "download", args.token, args.allow_patterns) + else: + if not args.source: + raise ValueError("--source is required when not using --download") + source_dir = Path(args.source) + + output_dir = Path(args.output) + shards = _find_shards(source_dir) + if not shards: + raise FileNotFoundError(f"No safetensors found in {source_dir}") + metadata_path = shards[0] + metadata_config = _read_metadata_config(metadata_path) + components_to_write: set[str] | None = None + if args.transformer_only: + components_to_write = {"transformer"} + elif args.components: + components_to_write = { + component.strip() + for component in args.components.split(",") + if component.strip() + } + + gemma_model_path = "" + if args.gemma_path: + gemma_src = Path(args.gemma_path) + if not gemma_src.is_dir(): + raise ValueError(f"--gemma-path must be a directory: {gemma_src}") + gemma_dest = output_dir / "text_encoder" / "gemma" + if gemma_dest.exists(): + shutil.rmtree(gemma_dest) + gemma_dest.parent.mkdir(parents=True, exist_ok=True) + shutil.copytree(gemma_src, gemma_dest) + gemma_model_path = "gemma" + + convert_components( + source_dir, + output_dir, + metadata_config, + args.class_name, + components_to_write=components_to_write, + emit_diffusers_repo=args.diffusers_repo, + pipeline_class_name=args.pipeline_class_name, + diffusers_version=args.diffusers_version, + gemma_model_path=gemma_model_path, + ) + + if args.update_config: + if source_dir.is_dir(): + update_transformer_config(source_dir / "config.json", args.class_name) + + +if __name__ == "__main__": + main() diff --git a/tests/README.md b/tests/README.md new file mode 100644 index 000000000..6fc6b9d8a --- /dev/null +++ b/tests/README.md @@ -0,0 +1,7 @@ +# Tests + +- `tests/local_tests/` are local-only tests that require a checked-out `LTX-2/` + directory under the repo root (`FastVideo/LTX-2`). Without that repo, they + will skip or fail. +- The CI-backed test suite still lives in `fastvideo/tests/`. +- Eventually, all tests will move under `tests/`. diff --git a/tests/__init__.py b/tests/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/tests/local_tests/README.md b/tests/local_tests/README.md new file mode 100644 index 000000000..c6b976d54 --- /dev/null +++ b/tests/local_tests/README.md @@ -0,0 +1,7 @@ +# Local LTX-2 Tests + +These tests depend on a checked-out `LTX-2/` directory under the repo root +(`FastVideo/LTX-2`). Without that local repo, the tests will skip or fail. + +For the CI-backed test suite, see `fastvideo/tests/`. Those are the tests +currently exercised in CI. (Eventually all tests will move to `tests/`.) diff --git a/tests/local_tests/__init__.py b/tests/local_tests/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/tests/local_tests/encoders/__init__.py b/tests/local_tests/encoders/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/tests/local_tests/encoders/test_ltx2_gemma_encoder.py b/tests/local_tests/encoders/test_ltx2_gemma_encoder.py new file mode 100644 index 000000000..8fbd65c08 --- /dev/null +++ b/tests/local_tests/encoders/test_ltx2_gemma_encoder.py @@ -0,0 +1,126 @@ +# SPDX-License-Identifier: Apache-2.0 +import os +import sys +from pathlib import Path + +import pytest +import torch +from safetensors.torch import load_file +from torch.testing import assert_close + +from fastvideo.configs.models.encoders import LTX2GemmaConfig +from fastvideo.configs.pipelines import PipelineConfig +from fastvideo.fastvideo_args import FastVideoArgs +from fastvideo.forward_context import set_forward_context +from fastvideo.models.loader.component_loader import TextEncoderLoader + +repo_root = Path(__file__).resolve().parents[3] +ltx_core_path = repo_root / "LTX-2" / "packages" / "ltx-core" / "src" +if ltx_core_path.exists() and str(ltx_core_path) not in sys.path: + sys.path.insert(0, str(ltx_core_path)) + + +def _load_connector_weights(path: str) -> dict[str, torch.Tensor]: + weights = load_file(path) + mapped: dict[str, torch.Tensor] = {} + for name, tensor in weights.items(): + if name == "aggregate_embed.weight": + mapped["feature_extractor_linear.aggregate_embed.weight"] = tensor + elif name.startswith("embeddings_connector."): + mapped[name] = tensor + elif name.startswith("audio_embeddings_connector."): + mapped[name] = tensor + return mapped + + +@pytest.mark.skipif( + not torch.cuda.is_available(), + reason="LTX-2 Gemma encoder parity test requires CUDA.", +) +def test_ltx2_gemma_text_encoder_parity(): + diffusers_root = Path( + os.getenv("LTX2_DIFFUSERS_PATH", "converted/ltx2_diffusers") + ) + text_encoder_path = os.getenv( + "LTX2_TEXT_ENCODER_PATH", + str(diffusers_root / "text_encoder"), + ) + gemma_model_path = str(Path(text_encoder_path) / "gemma") + if not os.path.isdir(text_encoder_path): + pytest.skip(f"LTX-2 text encoder weights not found at {text_encoder_path}") + if not gemma_model_path or not os.path.isdir(gemma_model_path): + pytest.skip("Gemma weights not found in text_encoder/gemma.") + + try: + from ltx_core.text_encoders.gemma.embeddings_connector import ( + Embeddings1DConnector, + ) + from ltx_core.text_encoders.gemma.encoders.av_encoder import ( + AVGemmaTextEncoderModel, + ) + from ltx_core.text_encoders.gemma.feature_extractor import ( + GemmaFeaturesExtractorProjLinear, + ) + from ltx_core.text_encoders.gemma.tokenizer import LTXVGemmaTokenizer + from transformers import Gemma3ForConditionalGeneration + except Exception as exc: + pytest.skip(f"LTX-2 Gemma import failed: {exc}") + + device = torch.device("cuda:0") + precision = torch.bfloat16 + + tokenizer = LTXVGemmaTokenizer(gemma_model_path, max_length=1024) + gemma_model = Gemma3ForConditionalGeneration.from_pretrained( + gemma_model_path, + local_files_only=True, + torch_dtype=precision, + ).to(device) + gemma_model.eval() + + ref_model = AVGemmaTextEncoderModel( + feature_extractor_linear=GemmaFeaturesExtractorProjLinear(), + embeddings_connector=Embeddings1DConnector(), + audio_embeddings_connector=Embeddings1DConnector(), + tokenizer=tokenizer, + model=gemma_model, + dtype=precision, + ).to(device) + ref_model.eval() + + connector_weights = _load_connector_weights( + os.path.join(text_encoder_path, "model.safetensors") + ) + ref_model.load_state_dict(connector_weights, strict=False) + + prompt = "A fast moving train in a snowy landscape." + token_pairs = tokenizer.tokenize_with_weights(prompt)["gemma"] + input_ids = torch.tensor( + [[t[0] for t in token_pairs]], device=device, dtype=torch.long + ) + attention_mask = torch.tensor( + [[t[1] for t in token_pairs]], device=device, dtype=torch.long + ) + + args = FastVideoArgs( + model_path=text_encoder_path, + pipeline_config=PipelineConfig( + text_encoder_configs=(LTX2GemmaConfig(),), + text_encoder_precisions=("bf16",), + ), + ) + loader = TextEncoderLoader() + fastvideo_model = loader.load(text_encoder_path, args).to(device) + fastvideo_model.eval() + + with torch.no_grad(): + ref_video, ref_audio, ref_mask = ref_model(prompt, padding_side="left") + with set_forward_context(current_timestep=0, attn_metadata=None): + fastvideo_out = fastvideo_model( + input_ids=input_ids, + attention_mask=attention_mask, + output_hidden_states=True, + ) + + assert_close(ref_video, fastvideo_out.last_hidden_state, atol=1e-2, rtol=1e-2) + assert_close(ref_audio, fastvideo_out.hidden_states[0], atol=1e-2, rtol=1e-2) + assert torch.equal(ref_mask, fastvideo_out.attention_mask) diff --git a/tests/local_tests/encoders/test_ltx2_gemma_parity.py b/tests/local_tests/encoders/test_ltx2_gemma_parity.py new file mode 100644 index 000000000..5f8de5c94 --- /dev/null +++ b/tests/local_tests/encoders/test_ltx2_gemma_parity.py @@ -0,0 +1,378 @@ +# SPDX-License-Identifier: Apache-2.0 +import os +from pathlib import Path +import sys + +import pytest +import torch +from torch.testing import assert_close + +from safetensors.torch import load_file + +from fastvideo.configs.models.encoders import LTX2GemmaConfig +from fastvideo.models.encoders.gemma import LTX2GemmaTextEncoderModel +from fastvideo.models.loader.component_loader import get_diffusers_config + + +repo_root = Path(__file__).resolve().parents[3] +ltx_core_path = repo_root / "LTX-2" / "packages" / "ltx-core" / "src" +if ltx_core_path.exists() and str(ltx_core_path) not in sys.path: + sys.path.insert(0, str(ltx_core_path)) + + +def _init_log_paths() -> tuple[Path, Path]: + base_dir = Path(os.getenv("LTX2_DEBUG_DIR", "ltx2_debug")) + fastvideo_log = Path(os.getenv("LTX2_FASTVIDEO_GEMMA_LOG", base_dir / "fastvideo_gemma.log")) + reference_log = Path(os.getenv("LTX2_REFERENCE_GEMMA_LOG", base_dir / "reference_gemma.log")) + fastvideo_log.parent.mkdir(parents=True, exist_ok=True) + reference_log.parent.mkdir(parents=True, exist_ok=True) + fastvideo_log.write_text("") + reference_log.write_text("") + return fastvideo_log, reference_log + + +def _log_line(path: Path, message: str) -> None: + with path.open("a", encoding="utf-8") as f: + f.write(message + "\n") + + +def _attach_encoder_logging( + encoder: torch.nn.Module, + log_path: Path, + label: str, +) -> None: + def _format_sum(tensor: torch.Tensor | None) -> str: + if tensor is None: + return "None" + return f"{tensor.float().sum().item():.6f}" + + def _hook_factory(name: str): + def _hook(_module, _inputs, outputs): # noqa: ANN001 + out = outputs[0] if isinstance(outputs, tuple) else outputs + out_sum = _format_sum(out if torch.is_tensor(out) else None) + _log_line(log_path, f"{label}:{name}:sum={out_sum}") + return _hook + + def _pre_hook_factory(name: str): + def _hook(_module, inputs): # noqa: ANN001 + tensor = inputs[0] if inputs else None + in_sum = _format_sum(tensor if torch.is_tensor(tensor) else None) + _log_line(log_path, f"{label}:{name}:in_sum={in_sum}") + return _hook + + def _attach_block_detail(block: torch.nn.Module, prefix: str) -> None: + block.register_forward_pre_hook(_pre_hook_factory(f"{prefix}:input")) + block.register_forward_hook(_hook_factory(f"{prefix}:output")) + if hasattr(block, "attn1"): + block.attn1.register_forward_hook( + _hook_factory(f"{prefix}:attn1")) + if hasattr(block, "ff"): + block.ff.register_forward_hook(_hook_factory(f"{prefix}:ff")) + + if hasattr(encoder, "feature_extractor_linear"): + encoder.feature_extractor_linear.register_forward_pre_hook( + _pre_hook_factory("feature_extractor_linear")) + encoder.feature_extractor_linear.register_forward_hook(_hook_factory("feature_extractor_linear")) + if hasattr(encoder, "embeddings_connector"): + encoder.embeddings_connector.register_forward_hook(_hook_factory("embeddings_connector")) + for idx, block in enumerate(encoder.embeddings_connector.transformer_1d_blocks): + _attach_block_detail(block, f"embeddings_block_{idx}") + if hasattr(encoder, "audio_embeddings_connector"): + encoder.audio_embeddings_connector.register_forward_hook(_hook_factory("audio_embeddings_connector")) + for idx, block in enumerate(encoder.audio_embeddings_connector.transformer_1d_blocks): + _attach_block_detail(block, f"audio_embeddings_block_{idx}") + + +def _log_register_sums(encoder: torch.nn.Module, log_path: Path, label: str) -> None: + def _sum_param(module: torch.nn.Module, name: str) -> float | None: + if not hasattr(module, "learnable_registers"): + return None + param = getattr(module, "learnable_registers") + if not torch.is_tensor(param): + return None + return param.float().sum().item() + + if hasattr(encoder, "embeddings_connector"): + reg_sum = _sum_param(encoder.embeddings_connector, "learnable_registers") + if reg_sum is not None: + _log_line(log_path, f"{label}:embeddings_registers:sum={reg_sum:.6f}") + if hasattr(encoder, "audio_embeddings_connector"): + reg_sum = _sum_param(encoder.audio_embeddings_connector, "learnable_registers") + if reg_sum is not None: + _log_line(log_path, f"{label}:audio_registers:sum={reg_sum:.6f}") + + +def _log_param_sums(encoder: torch.nn.Module, log_path: Path, label: str) -> None: + def _log_param(name: str, tensor: torch.Tensor | None) -> None: + if tensor is None: + _log_line(log_path, f"{label}:param:{name}:sum=None") + return + _log_line(log_path, f"{label}:param:{name}:sum={tensor.float().sum().item():.6f}") + + if hasattr(encoder, "feature_extractor_linear"): + _log_param( + "feature_extractor_linear.aggregate_embed.weight", + encoder.feature_extractor_linear.aggregate_embed.weight, + ) + if hasattr(encoder, "embeddings_connector"): + block0 = encoder.embeddings_connector.transformer_1d_blocks[0] + _log_param("embeddings_block0.attn1.to_q.weight", block0.attn1.to_q.weight) + _log_param("embeddings_block0.attn1.to_k.weight", block0.attn1.to_k.weight) + _log_param("embeddings_block0.attn1.to_v.weight", block0.attn1.to_v.weight) + _log_param("embeddings_block0.ff.net.0.proj.weight", block0.ff.net[0].proj.weight) + if hasattr(encoder, "audio_embeddings_connector"): + block0 = encoder.audio_embeddings_connector.transformer_1d_blocks[0] + _log_param("audio_block0.attn1.to_q.weight", block0.attn1.to_q.weight) + _log_param("audio_block0.attn1.to_k.weight", block0.attn1.to_k.weight) + _log_param("audio_block0.attn1.to_v.weight", block0.attn1.to_v.weight) + _log_param("audio_block0.ff.net.0.proj.weight", block0.ff.net[0].proj.weight) + + +def _log_gemma_param_sums( + gemma_model: torch.nn.Module | None, + log_path: Path, + label: str, +) -> None: + if gemma_model is None: + _log_line(log_path, f"{label}:gemma_param:embed_tokens.weight:sum=None") + return + tokens = None + if hasattr(gemma_model, "get_input_embeddings"): + try: + tokens = gemma_model.get_input_embeddings() + except Exception: + tokens = None + if tokens is None: + embed = getattr(gemma_model, "model", None) + if embed is not None: + tokens = getattr(embed, "embed_tokens", None) + if tokens is None or not hasattr(tokens, "weight"): + _log_line(log_path, f"{label}:gemma_param:embed_tokens.weight:sum=None") + return + _log_line( + log_path, + f"{label}:gemma_param:embed_tokens.weight:sum={tokens.weight.float().sum().item():.6f}", + ) + + +@pytest.mark.skipif( + not torch.cuda.is_available(), + reason="LTX-2 Gemma parity test requires CUDA.", +) +def test_ltx2_gemma_parity(): + os.environ["FASTVIDEO_ATTENTION_BACKEND"] = "TORCH_SDPA" + torch.backends.cuda.enable_flash_sdp(False) + torch.backends.cuda.enable_mem_efficient_sdp(False) + torch.backends.cuda.enable_math_sdp(True) + fastvideo_log, reference_log = _init_log_paths() + diffusers_root = Path( + os.getenv("LTX2_DIFFUSERS_PATH", "converted/ltx2_diffusers") + ) + official_path = Path( + os.getenv( + "LTX2_OFFICIAL_PATH", + "official_ltx_weights/ltx-2-19b-distilled.safetensors", + ) + ) + text_encoder_path = diffusers_root / "text_encoder" + gemma_path = text_encoder_path / "gemma" + + if not official_path.exists(): + pytest.skip(f"LTX-2 weights not found at {official_path}") + if not text_encoder_path.exists(): + pytest.skip(f"LTX-2 text encoder not found at {text_encoder_path}") + if not gemma_path.exists(): + pytest.skip(f"LTX-2 Gemma weights not found at {gemma_path}") + + try: + from ltx_core.loader.single_gpu_model_builder import SingleGPUModelBuilder + from ltx_core.model.transformer.attention import Attention, AttentionFunction + from ltx_core.text_encoders.gemma import ( + AV_GEMMA_TEXT_ENCODER_KEY_OPS, + AVGemmaTextEncoderModelConfigurator, + module_ops_from_gemma_root, + ) + except ImportError as exc: + pytest.skip(f"LTX-2 import failed: {exc}") + + device = torch.device("cuda:0") + precision = torch.bfloat16 + + reference_builder = SingleGPUModelBuilder( + model_path=str(official_path), + model_class_configurator=AVGemmaTextEncoderModelConfigurator, + model_sd_ops=AV_GEMMA_TEXT_ENCODER_KEY_OPS, + module_ops=module_ops_from_gemma_root(str(gemma_path)), + ) + reference_encoder = reference_builder.build( + device=device, dtype=precision + ).to(device=device, dtype=precision) + if hasattr(reference_encoder.model, "config"): + if hasattr(reference_encoder.model.config, "attn_implementation"): + reference_encoder.model.config.attn_implementation = "sdpa" + if hasattr(reference_encoder.model.config, "_attn_implementation"): + reference_encoder.model.config._attn_implementation = "sdpa" + for module in reference_encoder.modules(): + if isinstance(module, Attention): + module.attention_function = AttentionFunction.PYTORCH + reference_encoder.eval() + _attach_encoder_logging(reference_encoder, reference_log, "reference") + _log_register_sums(reference_encoder, reference_log, "reference") + _log_param_sums(reference_encoder, reference_log, "reference") + _log_gemma_param_sums(reference_encoder.model, reference_log, "reference") + _log_line( + reference_log, + "reference:gemma_config:attn_impl=" + f"{getattr(reference_encoder.model.config, 'attn_implementation', None)} " + f"dtype={reference_encoder.model.dtype}", + ) + + diffusers_config = get_diffusers_config(model=str(text_encoder_path)) + encoder_config = LTX2GemmaConfig() + encoder_config.update_model_arch(diffusers_config) + encoder_config.arch_config.gemma_model_path = str(gemma_path) + fastvideo_encoder = LTX2GemmaTextEncoderModel(encoder_config).to( + device=device, dtype=precision + ) + if hasattr(fastvideo_encoder.gemma_model, "config"): + if hasattr(fastvideo_encoder.gemma_model.config, "attn_implementation"): + fastvideo_encoder.gemma_model.config.attn_implementation = "sdpa" + if hasattr(fastvideo_encoder.gemma_model.config, "_attn_implementation"): + fastvideo_encoder.gemma_model.config._attn_implementation = "sdpa" + + official_weights = load_file(str(official_path)) + fastvideo_weights: dict[str, torch.Tensor] = {} + for name, tensor in official_weights.items(): + mapped_name = AV_GEMMA_TEXT_ENCODER_KEY_OPS.apply_to_key(name) + if mapped_name is None: + continue + fastvideo_weights[mapped_name] = tensor + fastvideo_encoder.load_weights(fastvideo_weights.items()) + fastvideo_encoder.eval() + _attach_encoder_logging(fastvideo_encoder, fastvideo_log, "fastvideo") + _log_register_sums(fastvideo_encoder, fastvideo_log, "fastvideo") + _log_param_sums(fastvideo_encoder, fastvideo_log, "fastvideo") + _log_gemma_param_sums(fastvideo_encoder.gemma_model, fastvideo_log, "fastvideo") + _log_line( + fastvideo_log, + "fastvideo:gemma_config:attn_impl=" + f"{getattr(fastvideo_encoder.gemma_model.config, 'attn_implementation', None)} " + f"dtype={fastvideo_encoder.gemma_model.dtype}", + ) + + prompt = "A curious raccoon peers through a vibrant field of yellow sunflowers." + ref_tokenizer = reference_encoder.tokenizer + if ref_tokenizer is None: + pytest.skip("Reference tokenizer is not initialized.") + token_pairs = ref_tokenizer.tokenize_with_weights(prompt)["gemma"] + input_ids = torch.tensor([[t[0] for t in token_pairs]], device=device) + attention_mask = torch.tensor([[w[1] for w in token_pairs]], device=device) + + with torch.no_grad(), torch.backends.cuda.sdp_kernel( + enable_flash=False, + enable_mem_efficient=False, + enable_math=True, + ): + ref_outputs = reference_encoder.model( + input_ids=input_ids, + attention_mask=attention_mask, + output_hidden_states=True, + return_dict=True, + use_cache=False, + ) + _log_line( + reference_log, + "reference:gemma_hidden_last:sum=" + f"{ref_outputs.hidden_states[-1].float().sum().item():.6f}", + ) + ref_projected = reference_encoder._run_feature_extractor( + ref_outputs.hidden_states, + attention_mask=attention_mask, + padding_side="left", + ) + # Compare rotary embeddings between implementations. + from ltx_core.model.transformer.rope import precompute_freqs_cis + from fastvideo.models.dits.ltx2 import precompute_ltx_freqs_cis + + seq_len = ref_projected.shape[1] + indices_grid = torch.arange(seq_len, device=device, dtype=torch.float32)[None, None, :] + ref_cos, ref_sin = precompute_freqs_cis( + indices_grid=indices_grid, + dim=reference_encoder.embeddings_connector.inner_dim, + out_dtype=ref_projected.dtype, + theta=reference_encoder.embeddings_connector.positional_embedding_theta, + max_pos=reference_encoder.embeddings_connector.positional_embedding_max_pos, + num_attention_heads=reference_encoder.embeddings_connector.num_attention_heads, + rope_type=reference_encoder.embeddings_connector.rope_type, + ) + fast_cos, fast_sin = precompute_ltx_freqs_cis( + indices_grid=indices_grid, + dim=fastvideo_encoder.embeddings_connector.inner_dim, + out_dtype=ref_projected.dtype, + theta=fastvideo_encoder.embeddings_connector.positional_embedding_theta, + max_pos=fastvideo_encoder.embeddings_connector.positional_embedding_max_pos, + num_attention_heads=fastvideo_encoder.embeddings_connector.num_attention_heads, + rope_type=fastvideo_encoder.embeddings_connector.rope_type, + ) + _log_line( + reference_log, + "reference:rope:cos_sum=" + f"{ref_cos.float().sum().item():.6f} sin_sum={ref_sin.float().sum().item():.6f} " + f"theta={reference_encoder.embeddings_connector.positional_embedding_theta} " + f"max_pos={reference_encoder.embeddings_connector.positional_embedding_max_pos} " + f"rope_type={reference_encoder.embeddings_connector.rope_type}" + ) + _log_line( + fastvideo_log, + "fastvideo:rope:cos_sum=" + f"{fast_cos.float().sum().item():.6f} sin_sum={fast_sin.float().sum().item():.6f} " + f"theta={fastvideo_encoder.embeddings_connector.positional_embedding_theta} " + f"max_pos={fastvideo_encoder.embeddings_connector.positional_embedding_max_pos} " + f"rope_type={fastvideo_encoder.embeddings_connector.rope_type}" + ) + ref_video, ref_audio, _ = reference_encoder._run_connectors( + ref_projected, attention_mask + ) + fast_video_from_ref, fast_audio_from_ref, _ = fastvideo_encoder._run_connectors( + ref_projected, attention_mask + ) + _log_line( + fastvideo_log, + "fastvideo:connector_on_ref:video_sum=" + f"{fast_video_from_ref.float().sum().item():.6f}", + ) + _log_line( + fastvideo_log, + "fastvideo:connector_on_ref:audio_sum=" + f"{fast_audio_from_ref.float().sum().item():.6f}", + ) + + fast_outputs = fastvideo_encoder.gemma_model( + input_ids=input_ids, + attention_mask=attention_mask, + output_hidden_states=True, + return_dict=True, + use_cache=False, + ) + _log_line( + fastvideo_log, + "fastvideo:gemma_hidden_last:sum=" + f"{fast_outputs.hidden_states[-1].float().sum().item():.6f}", + ) + fast_projected = fastvideo_encoder._run_feature_extractor( + fast_outputs.hidden_states, + attention_mask=attention_mask, + padding_side=fastvideo_encoder.padding_side, + ) + fast_video, fast_audio, _ = fastvideo_encoder._run_connectors( + fast_projected, attention_mask + ) + + assert ref_video.shape == fast_video.shape + assert ref_audio.shape == fast_audio.shape + assert torch.isfinite(ref_video).all(), "Reference Gemma produced non-finite video embeddings." + assert torch.isfinite(ref_audio).all(), "Reference Gemma produced non-finite audio embeddings." + assert torch.isfinite(fast_video).all(), "FastVideo Gemma produced non-finite video embeddings." + assert torch.isfinite(fast_audio).all(), "FastVideo Gemma produced non-finite audio embeddings." + assert_close(ref_video, fast_video, atol=3e-1, rtol=5e-2) + assert_close(ref_audio, fast_audio, atol=3e-1, rtol=5e-2) diff --git a/tests/local_tests/pipelines/__init__.py b/tests/local_tests/pipelines/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/tests/local_tests/pipelines/test_ltx2_pipeline_smoke.py b/tests/local_tests/pipelines/test_ltx2_pipeline_smoke.py new file mode 100644 index 000000000..1369934f6 --- /dev/null +++ b/tests/local_tests/pipelines/test_ltx2_pipeline_smoke.py @@ -0,0 +1,296 @@ +# SPDX-License-Identifier: Apache-2.0 +import os +from pathlib import Path +import sys +import tempfile + +import pytest +import torch + +from torch.testing import assert_close + +from fastvideo import VideoGenerator +from fastvideo.models.dits.ltx2 import ( + AudioLatentShape, + DEFAULT_LTX2_AUDIO_CHANNELS, + DEFAULT_LTX2_AUDIO_DOWNSAMPLE, + DEFAULT_LTX2_AUDIO_HOP_LENGTH, + DEFAULT_LTX2_AUDIO_MEL_BINS, + DEFAULT_LTX2_AUDIO_SAMPLE_RATE, +) +from fastvideo.models.loader.component_loader import PipelineComponentLoader + + +def _log_tensor_stats(label: str, tensor: torch.Tensor) -> None: + tensor_f32 = tensor.float() + print( + f"[LTX2 SMOKE] {label}: shape={tuple(tensor.shape)} " + f"dtype={tensor.dtype} device={tensor.device} " + f"min={tensor_f32.min().item():.6f} max={tensor_f32.max().item():.6f} " + f"mean={tensor_f32.mean().item():.6f} sum={tensor_f32.sum().item():.6f}" + ) + +def _truncate_debug_logs() -> None: + for env_var in ( + "LTX2_PIPELINE_DEBUG_PATH", + "LTX2_REFERENCE_DEBUG_PATH", + "LTX2_PIPELINE_DEBUG_DETAIL_PATH", + "LTX2_REFERENCE_DEBUG_DETAIL_PATH", + ): + log_path = os.getenv(env_var, "") + if not log_path: + continue + log_dir = os.path.dirname(log_path) + if log_dir: + os.makedirs(log_dir, exist_ok=True) + with open(log_path, "w", encoding="utf-8") as f: + f.write("") + + +def _run_audio_decode_smoke( + diffusers_path: str, + fastvideo_args, + device: torch.device, + num_frames: int, + fps: float, +) -> None: + audio_decoder_path = os.path.join(diffusers_path, "audio_vae") + vocoder_path = os.path.join(diffusers_path, "vocoder") + if not os.path.isdir(audio_decoder_path): + pytest.skip(f"Missing LTX-2 audio decoder at {audio_decoder_path}") + if not os.path.isdir(vocoder_path): + pytest.skip(f"Missing LTX-2 vocoder at {vocoder_path}") + + audio_decoder = PipelineComponentLoader.load_module( + module_name="audio_decoder", + component_model_path=audio_decoder_path, + transformers_or_diffusers="diffusers", + fastvideo_args=fastvideo_args, + ) + vocoder = PipelineComponentLoader.load_module( + module_name="vocoder", + component_model_path=vocoder_path, + transformers_or_diffusers="diffusers", + fastvideo_args=fastvideo_args, + ) + + duration = float(num_frames) / float(fps) + audio_shape = AudioLatentShape.from_duration( + batch=1, + duration=duration, + channels=DEFAULT_LTX2_AUDIO_CHANNELS, + mel_bins=DEFAULT_LTX2_AUDIO_MEL_BINS, + sample_rate=DEFAULT_LTX2_AUDIO_SAMPLE_RATE, + hop_length=DEFAULT_LTX2_AUDIO_HOP_LENGTH, + audio_latent_downsample_factor=DEFAULT_LTX2_AUDIO_DOWNSAMPLE, + ) + audio_dtype = next(audio_decoder.parameters()).dtype + audio_latents = torch.randn( + audio_shape.to_torch_shape(), + device=device, + dtype=audio_dtype, + ) + + with torch.no_grad(): + decoded_spec = audio_decoder(audio_latents) + audio_wave = vocoder(decoded_spec) + + assert audio_wave.ndim == 3 + + +@pytest.mark.skipif( + not torch.cuda.is_available(), + reason="LTX-2 pipeline smoke test requires CUDA.", +) +def test_ltx2_pipeline_smoke(): + repo_root = Path(__file__).resolve().parents[3] + debug_dir = repo_root / "ltx2_debug" + os.environ.setdefault( + "LTX2_PIPELINE_DEBUG_PATH", + str(debug_dir / "fastvideo_pipeline.log"), + ) + os.environ.setdefault( + "LTX2_REFERENCE_DEBUG_PATH", + str(debug_dir / "reference_pipeline.log"), + ) + os.environ.setdefault( + "LTX2_PIPELINE_DEBUG_DETAIL_PATH", + str(debug_dir / "fastvideo_pipeline_detail.log"), + ) + os.environ.setdefault( + "LTX2_REFERENCE_DEBUG_DETAIL_PATH", + str(debug_dir / "reference_pipeline_detail.log"), + ) + os.environ.setdefault("FASTVIDEO_ATTENTION_BACKEND", "TORCH_SDPA") + os.environ.setdefault("LTX2_REFERENCE_ATTN", "pytorch") + torch.backends.cuda.enable_flash_sdp(False) + torch.backends.cuda.enable_mem_efficient_sdp(False) + torch.backends.cuda.enable_math_sdp(True) + _truncate_debug_logs() + + ltx_core_path = repo_root / "LTX-2" / "packages" / "ltx-core" / "src" + if ltx_core_path.exists() and str(ltx_core_path) not in sys.path: + sys.path.insert(0, str(ltx_core_path)) + ltx_pipelines_path = repo_root / "LTX-2" / "packages" / "ltx-pipelines" / "src" + if ltx_pipelines_path.exists() and str(ltx_pipelines_path) not in sys.path: + sys.path.insert(0, str(ltx_pipelines_path)) + os.environ["PYTHONPATH"] = str(repo_root) + + diffusers_path = os.getenv("LTX2_DIFFUSERS_PATH", "converted/ltx2_diffusers") + gemma_model_path = os.path.join(diffusers_path, "text_encoder", "gemma") + official_path = os.getenv( + "LTX2_OFFICIAL_PATH", + "official_ltx_weights/ltx-2-19b-distilled.safetensors", + ) + + if not os.path.isdir(diffusers_path): + pytest.skip(f"Missing LTX-2 diffusers repo at {diffusers_path}") + if not os.path.isfile(os.path.join(diffusers_path, "model_index.json")): + pytest.skip(f"Missing model_index.json in {diffusers_path}") + + if not gemma_model_path or not os.path.isdir(gemma_model_path): + pytest.skip("Gemma weights not found in text_encoder/gemma.") + if not os.path.isfile(official_path): + pytest.skip(f"Missing LTX-2 official weights at {official_path}") + + try: + from ltx_pipelines.ti2vid_one_stage import TI2VidOneStagePipeline + from ltx_core.model.transformer import attention as ltx_attention + except ImportError as exc: + pytest.skip(f"LTX-2 pipeline import failed: {exc}") + ltx_attention.memory_efficient_attention = None + ltx_attention.flash_attn_interface = None + + device = torch.device("cuda:0") + prompt = "A curious raccoon peers through a vibrant field of yellow sunflowers." + negative_prompt = "low quality, blurry, distorted, artifacts, jpeg compression" + seed = 42 + height = 64 + width = 96 + num_frames = 9 + fps = 12.0 + steps = 4 + guidance_scale = 4.0 + + with tempfile.TemporaryDirectory() as tmpdir: + latent_path = str(Path(tmpdir) / "ltx2_initial_latent.pt") + + generator = VideoGenerator.from_pretrained( + diffusers_path, + num_gpus=1, + use_fsdp_inference=False, + dit_cpu_offload=False, + vae_cpu_offload=False, + text_encoder_cpu_offload=False, + pin_cpu_memory=False, + ltx2_vae_tiling=False, + ltx2_initial_latent_path=latent_path, + ) + result = generator.generate_video( + prompt=prompt, + negative_prompt=negative_prompt, + output_path="outputs_video/ltx2_smoke", + save_video=False, + height=height, + width=width, + num_frames=num_frames, + fps=fps, + num_inference_steps=steps, + guidance_scale=guidance_scale, + seed=seed, + ) + generator.shutdown() + _run_audio_decode_smoke( + diffusers_path=diffusers_path, + fastvideo_args=generator.fastvideo_args, + device=device, + num_frames=num_frames, + fps=fps, + ) + + fastvideo_out = result["samples"] + fastvideo_out = fastvideo_out.to(device=device, dtype=torch.float32) + _log_tensor_stats("fastvideo_video", fastvideo_out) + + ref_pipeline = TI2VidOneStagePipeline( + checkpoint_path=official_path, + gemma_root=gemma_model_path, + loras=[], + device=device, + fp8transformer=False, + ) + original_text_encoder = ref_pipeline.model_ledger.text_encoder + original_transformer = ref_pipeline.model_ledger.transformer + original_video_decoder = ref_pipeline.model_ledger.video_decoder + + def _patched_text_encoder(): + encoder = original_text_encoder() + try: + from ltx_core.model.transformer.attention import ( # type: ignore + Attention, + AttentionFunction, + ) + except ImportError: + return encoder + if hasattr(encoder, "model") and hasattr(encoder.model, "config"): + if hasattr(encoder.model.config, "attn_implementation"): + encoder.model.config.attn_implementation = "sdpa" + if hasattr(encoder.model.config, "_attn_implementation"): + encoder.model.config._attn_implementation = "sdpa" + for module in encoder.modules(): + if isinstance(module, Attention): + module.attention_function = AttentionFunction.PYTORCH + return encoder + + ref_pipeline.model_ledger.text_encoder = _patched_text_encoder + if os.getenv("LTX2_DISABLE_VAE_NOISE", "1") == "1": + def _patched_video_decoder(): + decoder = original_video_decoder() + if hasattr(decoder, "decode_noise_scale"): + decoder.decode_noise_scale = 0.0 + return decoder + + ref_pipeline.model_ledger.video_decoder = _patched_video_decoder + if os.getenv("LTX2_DEBUG_DETAIL", "0") == "1": + from ..transformers.test_ltx2 import ( + _attach_block_detail_logging, + ) + + def _patched_transformer(): + model = original_transformer() + core = getattr(model, "velocity_model", model) + _attach_block_detail_logging( + core, + Path(os.environ["LTX2_REFERENCE_DEBUG_DETAIL_PATH"]), + "reference", + True, + ) + return model + + ref_pipeline.model_ledger.transformer = _patched_transformer + with torch.no_grad(): + ref_video_iter, _ = ref_pipeline( + prompt=prompt, + negative_prompt=negative_prompt, + seed=seed, + height=height, + width=width, + num_frames=num_frames, + frame_rate=fps, + num_inference_steps=steps, + cfg_guidance_scale=guidance_scale, + images=[], + enhance_prompt=False, + initial_video_latent_path=latent_path, + ) + ref_chunks = list(ref_video_iter) + ref_video = torch.cat( + [chunk if torch.is_tensor(chunk) else torch.from_numpy(chunk) for chunk in ref_chunks], + dim=0, + ) + ref_video = ref_video.to(torch.float32) / 255.0 + ref_video = ref_video.permute(3, 0, 1, 2).unsqueeze(0) + _log_tensor_stats("reference_video", ref_video) + + assert ref_video.shape == fastvideo_out.shape + assert_close(ref_video, fastvideo_out, atol=2 / 255, rtol=1e-3) diff --git a/tests/local_tests/transformers/__init__.py b/tests/local_tests/transformers/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/tests/local_tests/transformers/test_ltx2.py b/tests/local_tests/transformers/test_ltx2.py new file mode 100644 index 000000000..14a3d8366 --- /dev/null +++ b/tests/local_tests/transformers/test_ltx2.py @@ -0,0 +1,343 @@ +# SPDX-License-Identifier: Apache-2.0 +import os +from pathlib import Path +import sys + +import pytest +import torch +from torch.testing import assert_close + +os.environ.setdefault("MASTER_ADDR", "localhost") +os.environ.setdefault("MASTER_PORT", "29513") + +repo_root = Path(__file__).resolve().parents[3] +ltx_core_path = repo_root / "LTX-2" / "packages" / "ltx-core" / "src" +if ltx_core_path.exists() and str(ltx_core_path) not in sys.path: + sys.path.insert(0, str(ltx_core_path)) + +from fastvideo.configs.models.dits import LTX2VideoConfig +from fastvideo.configs.pipelines import PipelineConfig +from fastvideo.fastvideo_args import FastVideoArgs +from fastvideo.forward_context import set_forward_context +from fastvideo.models.loader.component_loader import TransformerLoader + + +def _read_transformer_config(config: dict) -> dict: + transformer_config = config.get("transformer", {}) + if not transformer_config: + raise ValueError("Missing transformer config in LTX-2 metadata.") + return transformer_config + + +def _infer_patch_params(in_channels: int) -> tuple[int, int]: + patch_size = 1 + num_channels_latents = 128 + for candidate in (8, 16, 32, 64, 128): + if in_channels % candidate != 0: + continue + patch_volume = in_channels // candidate + root = int(round(patch_volume**0.5)) + if root * root == patch_volume: + patch_size = root + num_channels_latents = candidate + break + print( + f"[LTX2 TEST] Inferred patch_size={patch_size}, " + f"num_channels_latents={num_channels_latents}" + ) + return patch_size, num_channels_latents + + +def _attach_block_sum_logging( + model: torch.nn.Module, + log_path: Path, + label: str, + enabled: bool, +) -> None: + if not enabled: + return + + log_path.parent.mkdir(parents=True, exist_ok=True) + if log_path.exists(): + log_path.unlink() + + def _format_sum(tensor: torch.Tensor | None) -> str: + if tensor is None: + return "None" + return f"{tensor.float().sum().item():.6f}" + + def _hook(module, inputs, outputs): # noqa: ANN001 + if isinstance(outputs, tuple): + video_args, audio_args = outputs + video_sum = _format_sum(video_args.x if video_args is not None else None) + audio_sum = _format_sum(audio_args.x if audio_args is not None else None) + else: + video_sum = _format_sum(outputs) + audio_sum = "None" + with log_path.open("a", encoding="utf-8") as f: + f.write(f"{label}:{module.idx}:video_sum={video_sum},audio_sum={audio_sum}\n") + + for block in model.transformer_blocks: + block.register_forward_hook(_hook) + + +def _attach_block_detail_logging( + model: torch.nn.Module, + log_path: Path, + label: str, + enabled: bool, +) -> None: + if not enabled: + return + + log_path.parent.mkdir(parents=True, exist_ok=True) + if log_path.exists(): + log_path.unlink() + + def _format_sum(tensor: torch.Tensor | None) -> str: + if tensor is None: + return "None" + return f"{tensor.float().sum().item():.6f}" + + def _hook_factory(block_idx: int, name: str): + def _hook(_module, _inputs, outputs): # noqa: ANN001 + if isinstance(outputs, tuple): + out = outputs[0] + else: + out = outputs + out_sum = _format_sum(out if torch.is_tensor(out) else None) + with log_path.open("a", encoding="utf-8") as f: + f.write(f"{label}:{block_idx}:{name}:out_sum={out_sum}\n") + return _hook + + for block in model.transformer_blocks: + idx = block.idx + for name in ( + "attn1", + "attn2", + "ff", + "audio_attn1", + "audio_attn2", + "audio_ff", + "audio_to_video_attn", + "video_to_audio_attn", + ): + if hasattr(block, name): + getattr(block, name).register_forward_hook(_hook_factory(idx, name)) + + def _output_hook(name: str): + def _hook(_module, _inputs, outputs): # noqa: ANN001 + out = outputs[0] if isinstance(outputs, tuple) else outputs + out_sum = _format_sum(out if torch.is_tensor(out) else None) + with log_path.open("a", encoding="utf-8") as f: + f.write(f"{label}:output:{name}:out_sum={out_sum}\n") + return _hook + + for name in ("proj_out", "audio_proj_out"): + if hasattr(model, name): + getattr(model, name).register_forward_hook(_output_hook(name)) + + +def test_ltx2_transformer_parity(): + torch.manual_seed(42) + diffusers_root = Path( + os.getenv("LTX2_DIFFUSERS_PATH", "converted/ltx2_diffusers") + ) + official_path = Path( + os.getenv( + "LTX2_OFFICIAL_PATH", + "official_ltx_weights/ltx-2-19b-distilled.safetensors", + ) + ) + fastvideo_path = Path( + os.getenv( + "LTX2_FASTVIDEO_PATH", + str(diffusers_root / "transformer"), + ) + ) + if not official_path.exists(): + pytest.skip(f"LTX-2 official weights not found at {official_path}") + if not fastvideo_path.exists(): + pytest.skip(f"FastVideo converted weights not found at {fastvideo_path}") + + try: + from ltx_core.components.patchifiers import VideoLatentPatchifier + from ltx_core.guidance.perturbations import BatchedPerturbationConfig + from ltx_core.loader.sft_loader import SafetensorsModelStateDictLoader + from ltx_core.loader.single_gpu_model_builder import SingleGPUModelBuilder + from ltx_core.model.transformer import (LTXModelConfigurator, + LTXV_MODEL_COMFY_RENAMING_MAP) + from ltx_core.model.transformer.modality import Modality + from ltx_core.types import VideoLatentShape + except ImportError as exc: + pytest.skip(f"LTX-2 import failed: {exc}") + + config_loader = SafetensorsModelStateDictLoader() + metadata = config_loader.metadata(str(official_path)) + transformer_config = _read_transformer_config(metadata) + + config = LTX2VideoConfig() + cfg = config.arch_config + cfg.num_attention_heads = transformer_config.get("num_attention_heads", + cfg.num_attention_heads) + cfg.attention_head_dim = transformer_config.get("attention_head_dim", + cfg.attention_head_dim) + cfg.num_layers = transformer_config.get("num_layers", cfg.num_layers) + cfg.cross_attention_dim = transformer_config.get( + "cross_attention_dim", cfg.cross_attention_dim) + cfg.caption_channels = transformer_config.get("caption_channels", + cfg.caption_channels) + cfg.norm_eps = transformer_config.get("norm_eps", cfg.norm_eps) + cfg.attention_type = transformer_config.get("attention_type", + cfg.attention_type) + cfg.positional_embedding_theta = transformer_config.get( + "positional_embedding_theta", cfg.positional_embedding_theta) + cfg.positional_embedding_max_pos = transformer_config.get( + "positional_embedding_max_pos", cfg.positional_embedding_max_pos) + cfg.timestep_scale_multiplier = transformer_config.get( + "timestep_scale_multiplier", cfg.timestep_scale_multiplier) + cfg.use_middle_indices_grid = transformer_config.get( + "use_middle_indices_grid", cfg.use_middle_indices_grid) + cfg.rope_type = transformer_config.get("rope_type", cfg.rope_type) + cfg.double_precision_rope = transformer_config.get( + "double_precision_rope", + transformer_config.get("frequencies_precision", "") + == "float64", + ) + cfg.audio_num_attention_heads = transformer_config.get( + "audio_num_attention_heads", cfg.audio_num_attention_heads) + cfg.audio_attention_head_dim = transformer_config.get( + "audio_attention_head_dim", cfg.audio_attention_head_dim) + cfg.audio_in_channels = transformer_config.get("audio_in_channels", + cfg.audio_in_channels) + cfg.audio_out_channels = transformer_config.get("audio_out_channels", + cfg.audio_out_channels) + cfg.audio_cross_attention_dim = transformer_config.get( + "audio_cross_attention_dim", cfg.audio_cross_attention_dim) + cfg.audio_positional_embedding_max_pos = transformer_config.get( + "audio_positional_embedding_max_pos", + cfg.audio_positional_embedding_max_pos, + ) + cfg.av_ca_timestep_scale_multiplier = transformer_config.get( + "av_ca_timestep_scale_multiplier", cfg.av_ca_timestep_scale_multiplier) + cfg.in_channels = transformer_config.get("in_channels", cfg.in_channels) + cfg.out_channels = transformer_config.get("out_channels", cfg.out_channels) + + patch_size, num_channels_latents = _infer_patch_params(cfg.in_channels) + cfg.patch_size = (1, patch_size, patch_size) + cfg.num_channels_latents = num_channels_latents + + if not torch.cuda.is_available(): + pytest.skip("LTX-2 transformer parity test requires CUDA for attention backends.") + + device = torch.device("cuda:0") + precision = torch.bfloat16 + precision_str = "bf16" + + args = FastVideoArgs( + model_path=str(fastvideo_path), + dit_cpu_offload=True, + use_fsdp_inference=False, + pipeline_config=PipelineConfig(dit_config=config, dit_precision=precision_str), + ) + args.device = device + + loader = TransformerLoader() + fastvideo_model = loader.load(str(fastvideo_path), args).to(device=device, dtype=precision) + + reference_builder = SingleGPUModelBuilder( + model_class_configurator=LTXModelConfigurator, + model_path=str(official_path), + model_sd_ops=LTXV_MODEL_COMFY_RENAMING_MAP, + ) + reference_model = reference_builder.build( + device=device, dtype=precision).to(device=device, dtype=precision) + reference_model.set_gradient_checkpointing(False) + + fastvideo_model.eval() + reference_model.eval() + + debug_logs = os.getenv("LTX2_DEBUG_LOGS", "0") == "1" + _attach_block_sum_logging( + fastvideo_model.model, + repo_root / "ltx2_debug" / "fastvideo.log", + "fastvideo", + debug_logs, + ) + _attach_block_sum_logging( + reference_model, + repo_root / "ltx2_debug" / "reference.log", + "reference", + debug_logs, + ) + _attach_block_detail_logging( + fastvideo_model.model, + repo_root / "ltx2_debug" / "fastvideo_detail.log", + "fastvideo", + os.getenv("LTX2_DEBUG_DETAIL", "0") == "1", + ) + _attach_block_detail_logging( + reference_model, + repo_root / "ltx2_debug" / "reference_detail.log", + "reference", + os.getenv("LTX2_DEBUG_DETAIL", "0") == "1", + ) + + patchifier = VideoLatentPatchifier(patch_size=cfg.patch_size[1]) + batch_size = 1 + frames = 4 + height = cfg.patch_size[1] * 4 + width = cfg.patch_size[2] * 4 + hidden_states = torch.randn( + batch_size, + cfg.num_channels_latents, + frames, + height, + width, + device=device, + dtype=precision, + ) + encoder_hidden_states = torch.randn( + batch_size, + 16, + cfg.caption_channels, + device=device, + dtype=precision, + ) + timestep = torch.tensor([500], device=device, dtype=precision) + + video_shape = VideoLatentShape.from_torch_shape(hidden_states.shape) + positions = patchifier.get_patch_grid_bounds(video_shape, device=hidden_states.device) + latents = patchifier.patchify(hidden_states) + + video = Modality( + enabled=True, + latent=latents, + timesteps=timestep, + positions=positions, + context=encoder_hidden_states, + context_mask=None, + ) + + with torch.no_grad(): + ref_out, _ = reference_model( + video=video, + audio=None, + perturbations=BatchedPerturbationConfig.empty(batch_size), + ) + ref_out = patchifier.unpatchify(ref_out, output_shape=video_shape) + print(f"[LTX2 TEST] Reference model output shape: {ref_out.shape}") + with set_forward_context( + current_timestep=0, + attn_metadata=None, + forward_batch=None, + ): + fastvideo_out = fastvideo_model( + hidden_states=hidden_states, + encoder_hidden_states=encoder_hidden_states, + timestep=timestep, + ) + print(f"[LTX2 TEST] FastVideo model output shape: {fastvideo_out.shape}") + assert ref_out.shape == fastvideo_out.shape + assert ref_out.dtype == fastvideo_out.dtype + assert_close(ref_out, fastvideo_out, atol=1e-4, rtol=1e-4) diff --git a/tests/local_tests/transformers/test_ltx2_audio.py b/tests/local_tests/transformers/test_ltx2_audio.py new file mode 100644 index 000000000..c67c8cb74 --- /dev/null +++ b/tests/local_tests/transformers/test_ltx2_audio.py @@ -0,0 +1,280 @@ +# SPDX-License-Identifier: Apache-2.0 +import os +from pathlib import Path +import sys + +import pytest +import torch +from torch.testing import assert_close + +os.environ.setdefault("MASTER_ADDR", "localhost") +os.environ.setdefault("MASTER_PORT", "29513") +# Force TORCH_SDPA backend for parity testing - both FastVideo and LTX-2 reference +# will use PyTorch's scaled_dot_product_attention for consistent results +os.environ.setdefault("FASTVIDEO_ATTENTION_BACKEND", "TORCH_SDPA") + +repo_root = Path(__file__).resolve().parents[3] +ltx_core_path = repo_root / "LTX-2" / "packages" / "ltx-core" / "src" +if ltx_core_path.exists() and str(ltx_core_path) not in sys.path: + sys.path.insert(0, str(ltx_core_path)) + +from fastvideo.configs.models.dits import LTX2VideoConfig +from fastvideo.configs.pipelines import PipelineConfig +from fastvideo.fastvideo_args import FastVideoArgs +from fastvideo.forward_context import set_forward_context +from fastvideo.models.dits.ltx2 import Modality as FastVideoModality +from fastvideo.models.loader.component_loader import TransformerLoader +from .test_ltx2 import ( + _attach_block_detail_logging, + _attach_block_sum_logging, + _infer_patch_params, + _read_transformer_config, +) + + +def test_ltx2_transformer_audio_parity(): + torch.manual_seed(42) + diffusers_root = Path( + os.getenv("LTX2_DIFFUSERS_PATH", "converted/ltx2_diffusers") + ) + official_path = Path( + os.getenv( + "LTX2_OFFICIAL_PATH", + "official_ltx_weights/ltx-2-19b-distilled.safetensors", + ) + ) + fastvideo_path = Path( + os.getenv( + "LTX2_FASTVIDEO_PATH", + str(diffusers_root / "transformer"), + ) + ) + if not official_path.exists(): + pytest.skip(f"LTX-2 official weights not found at {official_path}") + if not fastvideo_path.exists(): + pytest.skip(f"FastVideo converted weights not found at {fastvideo_path}") + + try: + from ltx_core.components.patchifiers import AudioPatchifier, VideoLatentPatchifier + from ltx_core.guidance.perturbations import BatchedPerturbationConfig + from ltx_core.loader.sft_loader import SafetensorsModelStateDictLoader + from ltx_core.loader.single_gpu_model_builder import SingleGPUModelBuilder + from ltx_core.model.transformer import (LTXModelConfigurator, + LTXV_MODEL_COMFY_RENAMING_MAP) + from ltx_core.model.transformer.modality import Modality + from ltx_core.types import AudioLatentShape, VideoLatentShape + except ImportError as exc: + pytest.skip(f"LTX-2 import failed: {exc}") + + # Load config from metadata using same approach as test_ltx2.py + config_loader = SafetensorsModelStateDictLoader() + metadata = config_loader.metadata(str(official_path)) + transformer_config = _read_transformer_config(metadata) + + config = LTX2VideoConfig() + cfg = config.arch_config + cfg.num_attention_heads = transformer_config.get("num_attention_heads", + cfg.num_attention_heads) + cfg.attention_head_dim = transformer_config.get("attention_head_dim", + cfg.attention_head_dim) + cfg.num_layers = transformer_config.get("num_layers", cfg.num_layers) + cfg.cross_attention_dim = transformer_config.get( + "cross_attention_dim", cfg.cross_attention_dim) + cfg.caption_channels = transformer_config.get("caption_channels", + cfg.caption_channels) + cfg.norm_eps = transformer_config.get("norm_eps", cfg.norm_eps) + cfg.attention_type = transformer_config.get("attention_type", + cfg.attention_type) + cfg.positional_embedding_theta = transformer_config.get( + "positional_embedding_theta", cfg.positional_embedding_theta) + cfg.positional_embedding_max_pos = transformer_config.get( + "positional_embedding_max_pos", cfg.positional_embedding_max_pos) + cfg.timestep_scale_multiplier = transformer_config.get( + "timestep_scale_multiplier", cfg.timestep_scale_multiplier) + cfg.use_middle_indices_grid = transformer_config.get( + "use_middle_indices_grid", cfg.use_middle_indices_grid) + cfg.rope_type = transformer_config.get("rope_type", cfg.rope_type) + cfg.double_precision_rope = transformer_config.get( + "double_precision_rope", + transformer_config.get("frequencies_precision", "") + == "float64", + ) + cfg.audio_num_attention_heads = transformer_config.get( + "audio_num_attention_heads", cfg.audio_num_attention_heads) + cfg.audio_attention_head_dim = transformer_config.get( + "audio_attention_head_dim", cfg.audio_attention_head_dim) + cfg.audio_in_channels = transformer_config.get("audio_in_channels", + cfg.audio_in_channels) + cfg.audio_out_channels = transformer_config.get("audio_out_channels", + cfg.audio_out_channels) + cfg.audio_cross_attention_dim = transformer_config.get( + "audio_cross_attention_dim", cfg.audio_cross_attention_dim) + cfg.audio_positional_embedding_max_pos = transformer_config.get( + "audio_positional_embedding_max_pos", + cfg.audio_positional_embedding_max_pos, + ) + cfg.av_ca_timestep_scale_multiplier = transformer_config.get( + "av_ca_timestep_scale_multiplier", cfg.av_ca_timestep_scale_multiplier) + cfg.in_channels = transformer_config.get("in_channels", cfg.in_channels) + cfg.out_channels = transformer_config.get("out_channels", cfg.out_channels) + + patch_size, num_channels_latents = _infer_patch_params(cfg.in_channels) + cfg.patch_size = (1, patch_size, patch_size) + cfg.num_channels_latents = num_channels_latents + + if not torch.cuda.is_available(): + pytest.skip("LTX-2 transformer parity test requires CUDA for attention backends.") + + device = torch.device("cuda:0") + precision = torch.bfloat16 + precision_str = "bf16" + + args = FastVideoArgs( + model_path=str(fastvideo_path), + dit_cpu_offload=True, + use_fsdp_inference=False, + pipeline_config=PipelineConfig(dit_config=config, dit_precision=precision_str), + ) + args.device = device + + loader = TransformerLoader() + fastvideo_model = loader.load(str(fastvideo_path), args).to(device=device, dtype=precision) + + # Use SingleGPUModelBuilder to load the reference model (same as test_ltx2.py) + reference_builder = SingleGPUModelBuilder( + model_class_configurator=LTXModelConfigurator, + model_path=str(official_path), + model_sd_ops=LTXV_MODEL_COMFY_RENAMING_MAP, + ) + reference_model = reference_builder.build( + device=device, dtype=precision).to(device=device, dtype=precision) + reference_model.set_gradient_checkpointing(False) + + fastvideo_model.eval() + reference_model.eval() + + debug_logs = os.getenv("LTX2_DEBUG_LOGS", "0") == "1" + _attach_block_sum_logging( + fastvideo_model.model, + repo_root / "ltx2_debug" / "fastvideo_audio.log", + "fastvideo", + debug_logs, + ) + _attach_block_sum_logging( + reference_model, + repo_root / "ltx2_debug" / "reference_audio.log", + "reference", + debug_logs, + ) + _attach_block_detail_logging( + fastvideo_model.model, + repo_root / "ltx2_debug" / "fastvideo_audio_detail.log", + "fastvideo", + os.getenv("LTX2_DEBUG_DETAIL", "0") == "1", + ) + _attach_block_detail_logging( + reference_model, + repo_root / "ltx2_debug" / "reference_audio_detail.log", + "reference", + os.getenv("LTX2_DEBUG_DETAIL", "0") == "1", + ) + + patchifier = VideoLatentPatchifier(patch_size=cfg.patch_size[1]) + audio_patchifier = AudioPatchifier(patch_size=1) + batch_size = 1 + frames = 4 + height = cfg.patch_size[1] * 4 + width = cfg.patch_size[2] * 4 + hidden_states = torch.randn( + batch_size, + cfg.num_channels_latents, + frames, + height, + width, + device=device, + dtype=precision, + ) + encoder_hidden_states = torch.randn( + batch_size, + 16, + cfg.caption_channels, + device=device, + dtype=precision, + ) + timestep = torch.tensor([500], device=device, dtype=precision) + + video_shape = VideoLatentShape.from_torch_shape(hidden_states.shape) + positions = patchifier.get_patch_grid_bounds(video_shape, device=hidden_states.device) + latents = patchifier.patchify(hidden_states) + + audio_frames = 16 + audio_channels = 8 + audio_mel_bins = 16 + audio_latents = torch.randn( + batch_size, + audio_channels, + audio_frames, + audio_mel_bins, + device=device, + dtype=precision, + ) + audio_shape = AudioLatentShape.from_torch_shape(audio_latents.shape) + audio_positions = audio_patchifier.get_patch_grid_bounds(audio_shape, device=audio_latents.device) + audio_tokens = audio_patchifier.patchify(audio_latents) + + video = Modality( + enabled=True, + latent=latents, + timesteps=timestep, + positions=positions, + context=encoder_hidden_states, + context_mask=None, + ) + audio = Modality( + enabled=True, + latent=audio_tokens, + timesteps=timestep, + positions=audio_positions, + context=encoder_hidden_states, + context_mask=None, + ) + + fastvideo_video = FastVideoModality( + enabled=True, + latent=latents, + timesteps=timestep, + positions=positions, + context=encoder_hidden_states, + context_mask=None, + ) + fastvideo_audio = FastVideoModality( + enabled=True, + latent=audio_tokens, + timesteps=timestep, + positions=audio_positions, + context=encoder_hidden_states, + context_mask=None, + ) + + with torch.no_grad(): + _, ref_audio_out = reference_model( + video=video, + audio=audio, + perturbations=BatchedPerturbationConfig.empty(batch_size), + ) + ref_audio_out = audio_patchifier.unpatchify(ref_audio_out, output_shape=audio_shape) + with set_forward_context( + current_timestep=0, + attn_metadata=None, + forward_batch=None, + ): + _, fastvideo_audio_out = fastvideo_model.model( + video=fastvideo_video, + audio=fastvideo_audio, + ) + fastvideo_audio_out = audio_patchifier.unpatchify(fastvideo_audio_out, output_shape=audio_shape) + + assert ref_audio_out.shape == fastvideo_audio_out.shape + assert ref_audio_out.dtype == fastvideo_audio_out.dtype + # With TORCH_SDPA backend for both, use same tolerance as video parity test + assert_close(ref_audio_out, fastvideo_audio_out, atol=1e-4, rtol=1e-4) diff --git a/tests/local_tests/vaes/__init__.py b/tests/local_tests/vaes/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/tests/local_tests/vaes/test_ltx2_audio_vae.py b/tests/local_tests/vaes/test_ltx2_audio_vae.py new file mode 100644 index 000000000..e29f8b884 --- /dev/null +++ b/tests/local_tests/vaes/test_ltx2_audio_vae.py @@ -0,0 +1,272 @@ +# SPDX-License-Identifier: Apache-2.0 +import json +import os +from pathlib import Path +import sys + +import pytest +import torch +from safetensors import safe_open +from safetensors.torch import load_file +from torch.testing import assert_close + + +repo_root = Path(__file__).resolve().parents[3] +ltx_core_path = repo_root / "LTX-2" / "packages" / "ltx-core" / "src" +if ltx_core_path.exists() and str(ltx_core_path) not in sys.path: + sys.path.insert(0, str(ltx_core_path)) + +from fastvideo.models.audio.ltx2_audio_vae import ( + LTX2AudioDecoder, + LTX2AudioEncoder, + LTX2Vocoder, +) + + +def _load_metadata(path: Path) -> dict: + with safe_open(str(path), framework="pt") as f: + meta = f.metadata() + if not meta or "config" not in meta: + raise KeyError("Missing config metadata in safetensors file.") + return json.loads(meta["config"]) + + +def _load_weights(path: Path) -> dict[str, torch.Tensor]: + print(f"[LTX2 AUDIO VAE TEST] Loading weights from {path}") + return load_file(str(path)) + + +def _select_audio_vae_weights( + weights: dict[str, torch.Tensor], prefix: str +) -> dict[str, torch.Tensor]: + filtered: dict[str, torch.Tensor] = {} + alt_prefix = prefix.replace("audio_vae.", "") + for name, tensor in weights.items(): + if name.startswith(prefix): + filtered[name.replace(prefix, "")] = tensor + elif alt_prefix and name.startswith(alt_prefix): + filtered[name.replace(alt_prefix, "")] = tensor + elif name.startswith("audio_vae.per_channel_statistics."): + filtered[name.replace("audio_vae.", "")] = tensor + elif name.startswith("per_channel_statistics."): + filtered[name] = tensor + print(f"[LTX2 AUDIO VAE TEST] Selected {len(filtered)} tensors for {prefix}") + return filtered + + +def _select_vocoder_weights( + weights: dict[str, torch.Tensor] +) -> dict[str, torch.Tensor]: + if any(name.startswith("vocoder.") for name in weights): + filtered = { + name.replace("vocoder.", ""): tensor + for name, tensor in weights.items() + if name.startswith("vocoder.") + } + else: + filtered = dict(weights) + print(f"[LTX2 AUDIO VAE TEST] Selected {len(filtered)} tensors for vocoder.") + return filtered + + +def _load_into_model( + model: torch.nn.Module, weights: dict[str, torch.Tensor] +) -> tuple[int, list[str]]: + model_state = model.state_dict() + filtered = { + k: v + for k, v in weights.items() + if k in model_state and model_state[k].shape == v.shape + } + missing = [k for k in model_state.keys() if k not in filtered] + print( + f"[LTX2 AUDIO VAE TEST] Loading {len(filtered)} / {len(model_state)} tensors " + f"from {len(weights)} available" + ) + if not filtered: + return 0, missing + model.load_state_dict(filtered, strict=False) + return len(filtered), missing + + +def test_ltx2_audio_vae_vocoder_parity(): + diffusers_root = Path( + os.getenv("LTX2_DIFFUSERS_PATH", "converted/ltx2_diffusers") + ) + official_path = Path( + os.getenv( + "LTX2_OFFICIAL_PATH", + "official_ltx_weights/ltx-2-19b-distilled.safetensors", + ) + ) + audio_vae_path = Path( + os.getenv("LTX2_AUDIO_VAE_PATH", str(diffusers_root / "audio_vae")) + ) + vocoder_path = Path( + os.getenv("LTX2_VOCODER_PATH", str(diffusers_root / "vocoder")) + ) + if not official_path.exists(): + pytest.skip(f"LTX-2 weights not found at {official_path}") + if not audio_vae_path.exists(): + pytest.skip(f"LTX-2 audio VAE weights not found at {audio_vae_path}") + if not vocoder_path.exists(): + pytest.skip(f"LTX-2 vocoder weights not found at {vocoder_path}") + + config = _load_metadata(official_path) + if "audio_vae" not in config or "vocoder" not in config: + pytest.skip("Audio VAE or vocoder config not found in safetensors metadata.") + + try: + from ltx_core.model.audio_vae import ( + AudioDecoderConfigurator, + AudioEncoderConfigurator, + VocoderConfigurator, + ) + except ImportError as exc: + pytest.skip(f"LTX-2 import failed: {exc}") + + ref_weights = _load_weights(official_path) + encoder_weights = _select_audio_vae_weights(ref_weights, "audio_vae.encoder.") + decoder_weights = _select_audio_vae_weights(ref_weights, "audio_vae.decoder.") + vocoder_weights = _select_vocoder_weights(ref_weights) + if not encoder_weights or not decoder_weights or not vocoder_weights: + pytest.skip("Audio VAE or vocoder weights not found in safetensors file.") + + fastvideo_audio_weights_path = audio_vae_path / "model.safetensors" + fastvideo_vocoder_weights_path = vocoder_path / "model.safetensors" + if not fastvideo_audio_weights_path.exists(): + pytest.skip( + f"FastVideo audio VAE weights not found at {fastvideo_audio_weights_path}" + ) + if not fastvideo_vocoder_weights_path.exists(): + pytest.skip( + f"FastVideo vocoder weights not found at {fastvideo_vocoder_weights_path}" + ) + fastvideo_audio_weights = _load_weights(fastvideo_audio_weights_path) + fastvideo_encoder_weights = _select_audio_vae_weights( + fastvideo_audio_weights, "encoder." + ) + fastvideo_decoder_weights = _select_audio_vae_weights( + fastvideo_audio_weights, "decoder." + ) + fastvideo_vocoder_weights = _select_vocoder_weights( + _load_weights(fastvideo_vocoder_weights_path) + ) + if (not fastvideo_encoder_weights or not fastvideo_decoder_weights + or not fastvideo_vocoder_weights): + pytest.skip("FastVideo audio VAE/vocoder weights not found in diffusers files.") + + device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu") + precision = torch.bfloat16 if torch.cuda.is_available() else torch.float32 + + fastvideo_encoder = LTX2AudioEncoder(config).to(device=device, dtype=precision) + fastvideo_decoder = LTX2AudioDecoder(config).to(device=device, dtype=precision) + fastvideo_vocoder = LTX2Vocoder(config).to(device=device, dtype=precision) + + ref_encoder = AudioEncoderConfigurator.from_config(config).to( + device=device, dtype=precision + ) + ref_decoder = AudioDecoderConfigurator.from_config(config).to( + device=device, dtype=precision + ) + ref_vocoder = VocoderConfigurator.from_config(config).to( + device=device, dtype=precision + ) + + loaded_fastvideo_encoder, missing_fastvideo_encoder = _load_into_model( + fastvideo_encoder.model, fastvideo_encoder_weights + ) + loaded_ref_encoder, missing_ref_encoder = _load_into_model( + ref_encoder, encoder_weights + ) + loaded_fastvideo_decoder, missing_fastvideo_decoder = _load_into_model( + fastvideo_decoder.model, fastvideo_decoder_weights + ) + loaded_ref_decoder, missing_ref_decoder = _load_into_model( + ref_decoder, decoder_weights + ) + loaded_fastvideo_vocoder, missing_fastvideo_vocoder = _load_into_model( + fastvideo_vocoder.model, fastvideo_vocoder_weights + ) + loaded_ref_vocoder, missing_ref_vocoder = _load_into_model( + ref_vocoder, vocoder_weights + ) + + if min( + loaded_fastvideo_encoder, + loaded_ref_encoder, + loaded_fastvideo_decoder, + loaded_ref_decoder, + loaded_fastvideo_vocoder, + loaded_ref_vocoder, + ) == 0: + pytest.skip("Failed to load audio VAE or vocoder weights.") + if ( + missing_fastvideo_encoder + or missing_ref_encoder + or missing_fastvideo_decoder + or missing_ref_decoder + or missing_fastvideo_vocoder + or missing_ref_vocoder + ): + print( + f"[LTX2 AUDIO VAE TEST] Missing encoder keys: {len(missing_fastvideo_encoder)}" + ) + print( + f"[LTX2 AUDIO VAE TEST] Missing decoder keys: {len(missing_fastvideo_decoder)}" + ) + print( + f"[LTX2 AUDIO VAE TEST] Missing vocoder keys: {len(missing_fastvideo_vocoder)}" + ) + pytest.skip("Missing audio VAE/vocoder keys; cannot ensure parity.") + + fastvideo_encoder.model.eval() + fastvideo_decoder.model.eval() + fastvideo_vocoder.model.eval() + ref_encoder.eval() + ref_decoder.eval() + ref_vocoder.eval() + + ddconfig = config["audio_vae"]["model"]["params"]["ddconfig"] + in_channels = ddconfig.get("in_channels", 2) + resolution = ddconfig.get("resolution", 256) + mel_bins = ddconfig.get("mel_bins", 64) + batch_size = 1 + spectrogram = torch.randn( + batch_size, + in_channels, + resolution, + mel_bins, + device=device, + dtype=precision, + ) + + with torch.no_grad(): + ref_latents = ref_encoder(spectrogram) + fast_latents = fastvideo_encoder(spectrogram) + + assert ref_latents.shape == fast_latents.shape + assert ref_latents.dtype == fast_latents.dtype + assert torch.isfinite(ref_latents).all(), "Reference encoder produced non-finite latents." + assert torch.isfinite(fast_latents).all(), "FastVideo encoder produced non-finite latents." + assert_close(ref_latents, fast_latents, atol=1e-2, rtol=1e-2) + + with torch.no_grad(): + ref_decoded = ref_decoder(ref_latents) + fast_decoded = fastvideo_decoder(ref_latents) + + assert ref_decoded.shape == fast_decoded.shape + assert ref_decoded.dtype == fast_decoded.dtype + assert torch.isfinite(ref_decoded).all(), "Reference decoder produced non-finite output." + assert torch.isfinite(fast_decoded).all(), "FastVideo decoder produced non-finite output." + assert_close(ref_decoded, fast_decoded, atol=1e-2, rtol=1e-2) + + with torch.no_grad(): + ref_audio = ref_vocoder(ref_decoded) + fast_audio = fastvideo_vocoder(ref_decoded) + + assert ref_audio.shape == fast_audio.shape + assert ref_audio.dtype == fast_audio.dtype + assert torch.isfinite(ref_audio).all(), "Reference vocoder produced non-finite audio." + assert torch.isfinite(fast_audio).all(), "FastVideo vocoder produced non-finite audio." + assert_close(ref_audio, fast_audio, atol=1e-2, rtol=1e-2) diff --git a/tests/local_tests/vaes/test_ltx2_vae.py b/tests/local_tests/vaes/test_ltx2_vae.py new file mode 100644 index 000000000..cff218203 --- /dev/null +++ b/tests/local_tests/vaes/test_ltx2_vae.py @@ -0,0 +1,190 @@ +# SPDX-License-Identifier: Apache-2.0 +import json +import os +from pathlib import Path +import sys + +import pytest +import torch +from safetensors import safe_open +from safetensors.torch import load_file +from torch.testing import assert_close + + +repo_root = Path(__file__).resolve().parents[3] +ltx_core_path = repo_root / "LTX-2" / "packages" / "ltx-core" / "src" +if ltx_core_path.exists() and str(ltx_core_path) not in sys.path: + sys.path.insert(0, str(ltx_core_path)) + +from fastvideo.models.vaes.ltx2vae import LTX2VideoDecoder, LTX2VideoEncoder + + +def _load_metadata(path: Path) -> dict: + with safe_open(str(path), framework="pt") as f: + meta = f.metadata() + if not meta or "config" not in meta: + raise KeyError("Missing config metadata in safetensors file.") + return json.loads(meta["config"]) + + +def _load_weights(path: Path) -> dict[str, torch.Tensor]: + print(f"[LTX2 VAE TEST] Loading weights from {path}") + return load_file(str(path)) + + +def _select_vae_weights(weights: dict[str, torch.Tensor], prefix: str) -> dict[str, torch.Tensor]: + filtered: dict[str, torch.Tensor] = {} + alt_prefix = prefix.replace("vae.", "") + for name, tensor in weights.items(): + if name.startswith(prefix): + filtered[name.replace(prefix, "")] = tensor + elif alt_prefix and name.startswith(alt_prefix): + filtered[name.replace(alt_prefix, "")] = tensor + elif name.startswith("vae.per_channel_statistics."): + filtered[name.replace("vae.", "")] = tensor + elif name.startswith("per_channel_statistics."): + filtered[name] = tensor + print(f"[LTX2 VAE TEST] Selected {len(filtered)} tensors for {prefix}") + return filtered + + +def _load_into_model(model: torch.nn.Module, weights: dict[str, torch.Tensor]) -> tuple[int, list[str]]: + model_state = model.state_dict() + filtered = { + k: v + for k, v in weights.items() + if k in model_state and model_state[k].shape == v.shape + } + missing = [k for k in model_state.keys() if k not in filtered] + print( + f"[LTX2 VAE TEST] Loading {len(filtered)} / {len(model_state)} tensors " + f"from {len(weights)} available" + ) + if not filtered: + return 0, missing + model.load_state_dict(filtered, strict=False) + return len(filtered), missing + + +def test_ltx2_vae_parity(): + diffusers_root = Path( + os.getenv("LTX2_DIFFUSERS_PATH", "converted/ltx2_diffusers") + ) + official_path = Path( + os.getenv( + "LTX2_OFFICIAL_PATH", + "official_ltx_weights/ltx-2-19b-distilled.safetensors", + ) + ) + fastvideo_path = Path( + os.getenv("LTX2_VAE_PATH", str(diffusers_root / "vae")) + ) + if not official_path.exists(): + pytest.skip(f"LTX-2 weights not found at {official_path}") + if not fastvideo_path.exists(): + pytest.skip(f"LTX-2 diffusers VAE not found at {fastvideo_path}") + + config = _load_metadata(official_path) + if "vae" not in config: + pytest.skip("VAE config not found in safetensors metadata.") + + try: + from ltx_core.model.video_vae import VideoDecoderConfigurator, VideoEncoderConfigurator + except ImportError as exc: + pytest.skip(f"LTX-2 import failed: {exc}") + + ref_weights = _load_weights(official_path) + encoder_weights = _select_vae_weights(ref_weights, "vae.encoder.") + decoder_weights = _select_vae_weights(ref_weights, "vae.decoder.") + if not encoder_weights or not decoder_weights: + pytest.skip("VAE weights not found in safetensors file.") + + fastvideo_weights_path = fastvideo_path / "model.safetensors" + if not fastvideo_weights_path.exists(): + pytest.skip(f"FastVideo VAE weights not found at {fastvideo_weights_path}") + fastvideo_weights = _load_weights(fastvideo_weights_path) + fastvideo_encoder_weights = _select_vae_weights( + fastvideo_weights, "encoder." + ) + fastvideo_decoder_weights = _select_vae_weights( + fastvideo_weights, "decoder." + ) + if not fastvideo_encoder_weights or not fastvideo_decoder_weights: + pytest.skip("FastVideo VAE weights not found in diffusers file.") + + device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu") + precision = torch.bfloat16 if torch.cuda.is_available() else torch.float32 + + fastvideo_encoder = LTX2VideoEncoder(config).to(device=device, dtype=precision) + fastvideo_decoder = LTX2VideoDecoder(config).to(device=device, dtype=precision) + ref_encoder = VideoEncoderConfigurator.from_config(config).to(device=device, dtype=precision) + ref_decoder = VideoDecoderConfigurator.from_config(config).to(device=device, dtype=precision) + + loaded_fastvideo_encoder, missing_fastvideo_encoder = _load_into_model( + fastvideo_encoder.model, fastvideo_encoder_weights + ) + loaded_ref_encoder, missing_ref_encoder = _load_into_model(ref_encoder, encoder_weights) + loaded_fastvideo_decoder, missing_fastvideo_decoder = _load_into_model( + fastvideo_decoder.model, fastvideo_decoder_weights + ) + loaded_ref_decoder, missing_ref_decoder = _load_into_model(ref_decoder, decoder_weights) + + if min( + loaded_fastvideo_encoder, + loaded_ref_encoder, + loaded_fastvideo_decoder, + loaded_ref_decoder, + ) == 0: + pytest.skip("Failed to load VAE weights into one or more models.") + if ( + missing_fastvideo_encoder + or missing_ref_encoder + or missing_fastvideo_decoder + or missing_ref_decoder + ): + print(f"[LTX2 VAE TEST] Missing encoder keys: {len(missing_fastvideo_encoder)}") + print(f"[LTX2 VAE TEST] Missing decoder keys: {len(missing_fastvideo_decoder)}") + pytest.skip("Missing VAE keys; cannot ensure parity.") + + fastvideo_encoder.model.eval() + fastvideo_decoder.model.eval() + ref_encoder.eval() + ref_decoder.eval() + + fastvideo_decoder.model.decode_noise_scale = 0.0 + ref_decoder.decode_noise_scale = 0.0 + + batch_size = 1 + frames = 9 + height = 64 + width = 64 + video = torch.randn( + batch_size, + 3, + frames, + height, + width, + device=device, + dtype=precision, + ) + + with torch.no_grad(): + ref_latents = ref_encoder(video) + fast_latents = fastvideo_encoder(video) + + assert ref_latents.shape == fast_latents.shape + assert ref_latents.dtype == fast_latents.dtype + assert torch.isfinite(ref_latents).all(), "Reference encoder produced non-finite latents." + assert torch.isfinite(fast_latents).all(), "FastVideo encoder produced non-finite latents." + assert_close(ref_latents, fast_latents, atol=1e-2, rtol=1e-2) + + timestep = torch.tensor([0.05], device=device, dtype=precision) + with torch.no_grad(): + ref_decoded = ref_decoder(ref_latents, timestep=timestep) + fast_decoded = fastvideo_decoder(fast_latents, timestep=timestep) + + assert ref_decoded.shape == fast_decoded.shape + assert ref_decoded.dtype == fast_decoded.dtype + assert torch.isfinite(ref_decoded).all(), "Reference decoder produced non-finite output." + assert torch.isfinite(fast_decoded).all(), "FastVideo decoder produced non-finite output." + assert_close(ref_decoded, fast_decoded, atol=1e-2, rtol=1e-2) diff --git a/tests/local_tests/vaes/test_ltx2_vae_official.py b/tests/local_tests/vaes/test_ltx2_vae_official.py new file mode 100644 index 000000000..c02da5875 --- /dev/null +++ b/tests/local_tests/vaes/test_ltx2_vae_official.py @@ -0,0 +1,132 @@ +# SPDX-License-Identifier: Apache-2.0 +import os +from pathlib import Path +import sys + +import pytest +import torch +from torch.testing import assert_close + +repo_root = Path(__file__).resolve().parents[3] +ltx_core_path = repo_root / "LTX-2" / "packages" / "ltx-core" / "src" +if ltx_core_path.exists() and str(ltx_core_path) not in sys.path: + sys.path.insert(0, str(ltx_core_path)) + +from fastvideo.configs.models.vaes import LTX2VAEConfig +from fastvideo.configs.pipelines import PipelineConfig +from fastvideo.fastvideo_args import FastVideoArgs +from fastvideo.models.loader.component_loader import VAELoader + + +@pytest.mark.skipif( + not torch.cuda.is_available(), + reason="LTX-2 VAE parity test requires CUDA.", +) +def test_ltx2_vae_parity_official(): + diffusers_root = Path( + os.getenv("LTX2_DIFFUSERS_PATH", "converted/ltx2_diffusers") + ) + official_path = Path( + os.getenv( + "LTX2_OFFICIAL_PATH", + "official_ltx_weights/ltx-2-19b-distilled.safetensors", + ) + ) + fastvideo_path = Path( + os.getenv("LTX2_VAE_PATH", str(diffusers_root / "vae")) + ) + if not official_path.exists(): + pytest.skip(f"LTX-2 weights not found at {official_path}") + if not fastvideo_path.exists(): + pytest.skip(f"LTX-2 diffusers VAE not found at {fastvideo_path}") + + try: + from ltx_core.loader.single_gpu_model_builder import SingleGPUModelBuilder + from ltx_core.model.video_vae import ( + VAE_DECODER_COMFY_KEYS_FILTER, + VAE_ENCODER_COMFY_KEYS_FILTER, + VideoDecoderConfigurator, + VideoEncoderConfigurator, + ) + except ImportError as exc: + pytest.skip(f"LTX-2 import failed: {exc}") + + device = torch.device("cuda:0") + precision = torch.bfloat16 + precision_str = "bf16" + + args = FastVideoArgs( + model_path=str(fastvideo_path), + vae_cpu_offload=False, + pipeline_config=PipelineConfig( + vae_config=LTX2VAEConfig(), + vae_precision=precision_str, + ), + ) + + loader = VAELoader() + fastvideo_vae = loader.load(str(fastvideo_path), args).to( + device=device, dtype=precision + ) + + encoder_builder = SingleGPUModelBuilder( + model_class_configurator=VideoEncoderConfigurator, + model_path=str(official_path), + model_sd_ops=VAE_ENCODER_COMFY_KEYS_FILTER, + ) + decoder_builder = SingleGPUModelBuilder( + model_class_configurator=VideoDecoderConfigurator, + model_path=str(official_path), + model_sd_ops=VAE_DECODER_COMFY_KEYS_FILTER, + ) + ref_encoder = encoder_builder.build( + device=device, dtype=precision + ).to(device=device, dtype=precision) + ref_decoder = decoder_builder.build( + device=device, dtype=precision + ).to(device=device, dtype=precision) + + fastvideo_vae.encoder.eval() + fastvideo_vae.decoder.eval() + ref_encoder.eval() + ref_decoder.eval() + + if hasattr(fastvideo_vae.decoder, "decode_noise_scale"): + fastvideo_vae.decoder.decode_noise_scale = 0.0 + if hasattr(ref_decoder, "decode_noise_scale"): + ref_decoder.decode_noise_scale = 0.0 + + batch_size = 1 + frames = 9 + height = 64 + width = 64 + video = torch.randn( + batch_size, + 3, + frames, + height, + width, + device=device, + dtype=precision, + ) + + with torch.no_grad(): + ref_latents = ref_encoder(video) + fast_latents = fastvideo_vae.encoder(video) + + assert ref_latents.shape == fast_latents.shape + assert ref_latents.dtype == fast_latents.dtype + assert torch.isfinite(ref_latents).all(), "Reference encoder produced non-finite latents." + assert torch.isfinite(fast_latents).all(), "FastVideo encoder produced non-finite latents." + assert_close(ref_latents, fast_latents, atol=1e-2, rtol=1e-2) + + timestep = torch.tensor([0.05], device=device, dtype=precision) + with torch.no_grad(): + ref_decoded = ref_decoder(ref_latents, timestep=timestep) + fast_decoded = fastvideo_vae.decoder(fast_latents, timestep=timestep) + + assert ref_decoded.shape == fast_decoded.shape + assert ref_decoded.dtype == fast_decoded.dtype + assert torch.isfinite(ref_decoded).all(), "Reference decoder produced non-finite output." + assert torch.isfinite(fast_decoded).all(), "FastVideo decoder produced non-finite output." + assert_close(ref_decoded, fast_decoded, atol=1e-2, rtol=1e-2)