Downloads · 30 days
0
songyiren/ltx-v2v-reference-conditioning
ltx-v2v-reference-conditioning is a machine learning model from songyiren. Use it for the machine learning task on the model card, and read the license before you ship it in a product.
Video-to-video generation on top of LTX-2 (Lightricks' DiT-based video+audio diffusion model): given a source video (structure/motion signal) and a first-frame reference image (target identity/appearance), generate an…
Downloads · 30 days
0
Access
Public
Updated Jul 22, 2026
Repo size
—
Likes
2
Public
Click a slice to open those files.
.lock1.5 MB · 46%
From the Hugging Face model README
Video-to-video generation on top of LTX-2 (Lightricks' DiT-based video+audio diffusion model): given a source video (structure/motion signal) and a first-frame reference image (target identity/appearance), generate an output video that follows the source video's motion while adopting the reference image's look.
This repo is a trimmed-down, sharable fork containing:
packages/ltx-core, packages/ltx-pipelines — the LTX-2 inference stack,
with a small local patch to the reference-conditioning position logic (see
below) that is not in upstream Lightricks/LTX-2.packages/ltx-trainer — LTX-2's LoRA/IC-LoRA training stack, with a matching
patch on the training side, plus a reference_image dataset column so you
can train on (video, reference_image, caption) triples.scripts/infer_v2v.py — new inference script for the video+ref-image →
video workflow described above.configs/*.yaml, scripts/train_ic_lora.sh — training configs and launcher
for the two custom IC-LoRA variants this workflow needs.data/ — dataset format documentation and example JSONL rows.Not included: pretrained IC-LoRA checkpoints. The ones we trained
internally were trained on licensed movie footage, so we're not redistributing
the weights — train your own with scripts/train_ic_lora.sh on your own data
(see data/README.md).
./setup.sh # uv sync + download ~90GB of base-model weights
source .venv/bin/activate
# 1. Prepare your data (see data/README.md for the JSONL schema)
scripts/preprocess_dataset.sh data/dataset.jsonl "1920x1024x233"
# 2. Train an IC-LoRA (defaults to configs/v2v_reference_ic_lora.yaml)
scripts/train_ic_lora.sh --config configs/v2v_reference_ic_lora.yaml
# 3. Run inference with your trained checkpoint
python scripts/infer_v2v.py \
--input-video my_source_video.mp4 \
--ref-image my_reference.png \
--prompt "A woman in a red dress walks through a garden, camera tracking steadily." \
--structure-lora packages/ltx-trainer/outputs/v2v_reference_ic_lora/checkpoints/lora_weights_step_08000.safetensors \
--output out.mp4
setup.sh downloads gated/large weights from HuggingFace — if a download
401s, run huggingface-cli login (or set HF_TOKEN) first.
The source video is never fed to the transformer as raw pixels through a
special "V2V" code path — there isn't one. It goes through the exact same
video_conditioning mechanism IC-LoRA uses for any reference signal
(ICLoraPipeline.__call__'s video_conditioning: list[tuple[path, strength]]
parameter, in packages/ltx-pipelines/src/ltx_pipelines/ic_lora.py): it's
VAE-encoded, patchified into tokens exactly like the noisy video latent, and
appended to the same self-attention token sequence the denoiser attends
over (VideoConditionByReferenceLatent,
packages/ltx-core/src/ltx_core/conditioning/types/reference_video_cond.py).
A LoRA (--structure-lora) is what actually teaches the model to use those
extra tokens meaningfully — the base model has no opinion on what an arbitrary
appended video means.
Important: reference_video/--input-video is not necessarily raw source
footage — it's whatever structure/motion signal your LoRA was trained to
condition on (pose render, edge map, or the raw video itself, if that's what
you trained with). See data/README.md → "About reference_video".
This is the part that's easy to get subtly wrong, so it's exposed as an
explicit --pos-mode flag in scripts/infer_v2v.py rather than being baked in
silently:
--pos-mode first-frame (default) — the reference image reuses the
denoised video's own frame-0 RoPE position. Implemented via ICLoraPipeline's
native images: list[(path, frame_idx, strength)] parameter → this is a
base-model capability, no LoRA required. Code path:
combined_image_conditionings() in
packages/ltx-pipelines/src/ltx_pipelines/utils/helpers.py →
VideoConditionByLatentIndex / VideoConditionByKeyframeIndex in
packages/ltx-core/src/ltx_core/conditioning/types/. Because the reference
image is placed at the exact same absolute time position as frame 0, RoPE's
relative-rotation attention naturally treats it as "this is what frame 0 looks
like" rather than as a separate signal.
--pos-mode reference — the reference image gets its own, disjoint
RoPE position range instead of sharing frame 0's. Implemented via
video_conditioning → VideoConditionByReferenceLatent
(packages/ltx-core/src/ltx_core/conditioning/types/reference_video_cond.py).
This is the path our custom IC-LoRAs (configs/ref_image_ic_lora.yaml,
configs/v2v_reference_ic_lora.yaml) are actually trained against, and is
generally the better-performing option once you have a matching LoRA — the
base model alone doesn't know what to do with a disjoint-position reference
block; it has to be taught.
Why "disjoint" instead of just also using t=0: giving the reference image the
same absolute position as the target's frame 0 means RoPE's relative rotation
between them is zero — the attention mechanism can't tell the reference
token and the target's own frame-0 token apart by position alone. The fix
(originally a local patch on top of upstream LTX-2, in
reference_video_cond.py):
# packages/ltx-core/src/ltx_core/conditioning/types/reference_video_cond.py
REF_POSITION_TICK_SECONDS = 1e-3
current_min_time = latent_state.positions[:, 0, ...].min()
ref_max_time = positions[:, 0, ...].max()
positions[:, 0, ...] = positions[:, 0, ...] - ref_max_time + current_min_time - REF_POSITION_TICK_SECONDS
This shifts the whole reference block to end 1ms before whatever's
already the earliest time position in the sequence — a strictly ordered,
non-overlapping range. The training side
(packages/ltx-trainer/src/ltx_trainer/training_strategies/flexible.py,
_apply_reference_condition) applies the identical tick-offset logic, so a
LoRA trained with this code sees the same position layout at train and
inference time. If you ever modify one side, modify the other — they must stay
in parity.
When two reference-type conditions are stacked (as in
configs/v2v_reference_ic_lora.yaml, which uses both reference_video and
reference_image), each additional block is slotted immediately before
whatever range is already occupied, so every block — target frames, structure
reference, appearance reference — ends up in its own strictly-ordered slice of
time, none of them aliasing.
Two independent knobs control how strongly a reference item affects the output, orthogonal to which position mode you use:
--ref-strength / --structure-strength (denoise strength, strength
in ConditioningItem): controls how much noise the conditioning latent
itself gets mixed with during denoising (GaussianNoiser.torch.lerp, in
packages/ltx-core/src/ltx_core/components/noisers.py). 1.0 = the
reference stays exactly at its clean VAE-encoded value; lower values let the
model deviate from it.--conditioning-attention-strength: scales how strongly conditioning
tokens attend to/from the noisy tokens in self-attention, independent of the
noise blending above.setup.sh one-click env + weights setup
pyproject.toml, uv.lock workspace definition (uv)
packages/
ltx-core/ LTX-2 model + conditioning + RoPE (patched)
ltx-pipelines/ ICLoraPipeline and friends
ltx-trainer/ LoRA / IC-LoRA training stack (patched)
configs/
v2v_reference_ic_lora.yaml train on (video, reference_video, reference_image, caption)
ref_image_ic_lora.yaml simpler: train on (video, reference_image, caption) only
accelerate/ accelerate configs referenced by the trainer docs
scripts/
train_ic_lora.sh resolves __REPO_ROOT__ in a config, launches training
preprocess_dataset.sh wraps packages/ltx-trainer/scripts/process_dataset.py
infer_v2v.py video + reference image -> video, --pos-mode switch
data/
README.md dataset JSONL schema, resolution buckets, etc.
dataset.jsonl example rows: video + reference_video + reference_image + caption
dataset_image_only.jsonl example rows: video + reference_image + caption
weights/ populated by setup.sh (gitignored — large binaries)
configs/v2v_reference_ic_lora.yaml — trains one LoRA that uses both
--input-video and --ref-image at inference.configs/ref_image_ic_lora.yaml — simpler, doesn't need --input-video at
all (pass an empty/no-op structure conditioning, or adapt
scripts/infer_v2v.py to drop --structure-lora/--input-video for this
case).See data/README.md for the exact JSONL schema, column-to-encoder mapping, and
resolution-bucket rules.
LTX-2.3-22b-IC-LoRA-Union-Control LoRA expects raw source video or a
preprocessed control map (depth/pose/edge) for its video_conditioning
input — its model card (not vendored here) would be the source of truth if
you want to use it instead of training your own structure-control LoRA.reference_video/--input-video preprocessing (pose/edge/depth extraction)
is out of scope for this repo — bring your own, or use the basic Canny-edge
compute_reference() in packages/ltx-trainer/scripts/process_videos.py as
a starting point.