mirror of
https://github.com/vladmandic/automatic
synced 2026-09-19 01:04:32 +02:00
feat(ltx): canonical LTX-2.x Stage 2 recipe (LoRA + guidance + connectors)
Implement the Lightricks two-stage recipe (diffusers PR #13217) for the LTX-2.x Dev family: Stage 1 at half-res with full four-way guidance, 2x latent upsample, Stage 2 with distilled LoRA + scheduler swap + identity guidance on STAGE_2_DISTILLED_SIGMA_VALUES. Extends to both LTX-2.0 and LTX-2.3 Dev via per-family distilled-LoRA repos carried on the caps; Distilled variants take the same flow minus the LoRA swap. Auto-couples Refine with a fixed 2x upsample on any Dev variant with a known LoRA when the user enables Refine without Upsample. - caps: is_ltx_2_3, use_cross_timestep, default_dynamic_shift, stage2_dev_lora_repo, supports_canonical_stage2, modality_default_scale, guidance_rescale_default; LTX-2.x defaults realigned to canonical cfg=3.0 / steps=30; per-variant STG block and four-way guidance wired for non-distilled 2.x - process: canonical Stage 1/Stage 2 helpers, scheduler + opts snapshot under try/finally, per-family upsampler repo, audio latents threaded from Stage 1 into Stage 2, use_cross_timestep gated per caps - overrides: skip the redundant unsharded LTX-2.3 connectors blob and share LTX2TextConnectors weights across 2.3 variants when te_shared_t5 - load: Gemma3 shared-TE path for LTX-2.3; gate use_dynamic_shifting=False override to 0.9.x only so LTX-2.x stays on its canonical token-count dynamic shift
This commit is contained in:
@@ -10,23 +10,34 @@ class LTXCaps:
|
||||
repo_cls_name: str
|
||||
family: str # '0.9' or '2.x'
|
||||
is_distilled: bool
|
||||
is_ltx_2_3: bool
|
||||
is_i2v: bool
|
||||
supports_input_media: bool # accordion visible for any pipeline that accepts image/video input
|
||||
supports_multi_condition: bool # uses conditions=[LTX(2)VideoCondition(...)] kwarg; Condition classes only
|
||||
supports_input_media: bool
|
||||
supports_multi_condition: bool
|
||||
supports_image_cond_noise_scale: bool
|
||||
supports_decode_timestep: bool
|
||||
supports_stg: bool
|
||||
supports_audio: bool
|
||||
supports_frame_rate_kwarg: bool
|
||||
# 2.3 transformer cross-attn reads the other modality's sigma; unset falls back to 2.0's
|
||||
# independent-sigma path, which is a joint-distribution mismatch for 2.3 weights.
|
||||
use_cross_timestep: bool
|
||||
default_cfg: float
|
||||
default_steps: int
|
||||
default_sampler_shift: float
|
||||
default_dynamic_shift: bool
|
||||
default_width: int
|
||||
default_height: int
|
||||
default_frames: int
|
||||
default_frame_rate: int
|
||||
stg_default_scale: float = 0.0
|
||||
stg_default_blocks: list = field(default_factory=list)
|
||||
# Dev 2.x trained under cfg + stg + modality + rescale four-way composition;
|
||||
# distilled bakes these into its sigma schedule and stays at pipeline identity.
|
||||
modality_default_scale: float = 1.0
|
||||
guidance_rescale_default: float = 0.0
|
||||
supports_canonical_stage2: bool = False
|
||||
stage2_dev_lora_repo: Optional[str] = None
|
||||
|
||||
|
||||
CONDITION_CLASSES = {'LTXConditionPipeline', 'LTX2ConditionPipeline'}
|
||||
@@ -69,12 +80,14 @@ def get_caps(model_name: str) -> Optional[LTXCaps]:
|
||||
is_i2v = 'I2V' in model_name or cls_name in ('LTXImageToVideoPipeline', 'LTX2ImageToVideoPipeline')
|
||||
is_condition_cls = cls_name in CONDITION_CLASSES
|
||||
supports_input_media = is_i2v or is_condition_cls
|
||||
is_ltx_2_3 = is_ltx2 and '2.3' in model_name
|
||||
|
||||
caps = LTXCaps(
|
||||
name=model_name,
|
||||
repo_cls_name=cls_name,
|
||||
family=family,
|
||||
is_distilled=is_distilled,
|
||||
is_ltx_2_3=is_ltx_2_3,
|
||||
is_i2v=is_i2v,
|
||||
supports_input_media=supports_input_media,
|
||||
supports_multi_condition=is_condition_cls,
|
||||
@@ -83,9 +96,11 @@ def get_caps(model_name: str) -> Optional[LTXCaps]:
|
||||
supports_stg=is_ltx2,
|
||||
supports_audio=is_ltx2,
|
||||
supports_frame_rate_kwarg=is_ltx2,
|
||||
default_cfg=4.0 if is_ltx2 else 3.0,
|
||||
default_steps=40 if is_ltx2 else 50,
|
||||
use_cross_timestep=is_ltx_2_3,
|
||||
default_cfg=3.0,
|
||||
default_steps=30 if is_ltx2 else 50,
|
||||
default_sampler_shift=-1.0,
|
||||
default_dynamic_shift=is_ltx2,
|
||||
default_width=768,
|
||||
default_height=512,
|
||||
default_frames=121 if is_ltx2 else 161,
|
||||
@@ -96,6 +111,13 @@ def get_caps(model_name: str) -> Optional[LTXCaps]:
|
||||
caps.default_cfg = 1.0
|
||||
caps.default_steps = 8
|
||||
|
||||
if is_ltx2 and not is_distilled:
|
||||
if is_ltx_2_3:
|
||||
caps.stage2_dev_lora_repo = 'CalamitousFelicitousness/LTX-2.3-distilled-lora-384-Diffusers'
|
||||
elif '2.0' in model_name:
|
||||
caps.stage2_dev_lora_repo = 'CalamitousFelicitousness/LTX-2.0-distilled-lora-384-Diffusers'
|
||||
caps.supports_canonical_stage2 = caps.stage2_dev_lora_repo is not None
|
||||
|
||||
if is_ltx2:
|
||||
if '2.3' in model_name:
|
||||
caps.stg_default_blocks = [28]
|
||||
@@ -103,6 +125,10 @@ def get_caps(model_name: str) -> Optional[LTXCaps]:
|
||||
caps.stg_default_blocks = [29]
|
||||
else:
|
||||
caps.stg_default_blocks = [28]
|
||||
caps.stg_default_scale = 0.0
|
||||
if not is_distilled:
|
||||
# canonical T2V composition from huggingface/diffusers#13217
|
||||
caps.stg_default_scale = 1.0
|
||||
caps.modality_default_scale = 3.0
|
||||
caps.guidance_rescale_default = 0.7
|
||||
|
||||
return caps
|
||||
|
||||
Reference in New Issue
Block a user