Buckets:
| Name | Size | Uploaded | Xet hash |
|---|---|---|---|
| Camera-Dataset | 10,009 items | ||
| Camera-Dataset-Val | 101 items | ||
| Depth-Dataset | 10,005 items | ||
| Depth-Dataset-wan-latents | 6,001 items | ||
| Inpainting-Dataset | 10,009 items | ||
| Pose-Dataset | 10,009 items | ||
| Pose-Dataset-Legacy | 10,007 items | ||
| Pose-Dataset-wan-latents | 6,001 items | ||
| Pose-No-Face-Dataset-Legacy | 10,009 items | ||
| cameraman | 167 items | ||
| old | 109,379 items | ||
| README.md | 35.8 kB xet | 3e256993 |
LTX-2 — how the IC-LoRA training sets were built
Reconstructed 2026-08-21 from the build scripts, the shell history, and the data itself. Everything stated here was checked against the files unless marked inferred.
This directory holds locally built training sets for LTX-2 IC-LoRA (in-context LoRA)
video-to-video training. Nothing here is downloaded — each set is derived from a raw
dataset that lives in a sibling folder of /mnt/dataset/xinyuy/datasets/.
| Set | Task | Pairs | Built from | Built |
|---|---|---|---|---|
Pose-Dataset |
pose → video | 2,000 | HumanVID/selected_videos_dedup |
2026-07-09 |
Depth-Dataset |
depth → video | 2,000 | VIDGEN-1M/selected_videos |
2026-07-07 |
Inpainting-Dataset |
in/outpainting → video | 2,000 | VPData/{inpainting,outpainting} |
2026-07-08 |
Camera-Dataset |
camera motion → video | 2,000 | CameraClone-Dataset/data |
2026-08-19 |
Camera-Dataset-Val |
↑ held-out split | 50 | same, disjoint from train | 2026-08-19 |
Pose-Dataset-Legacy |
pose → video | 2,000 | HumanVID/selected_videos (pre-dedup) |
2026-07-09 |
Pose-No-Face-Dataset-Legacy |
pose (no face) → video | 2,000 | HumanVID/selected_videos |
2026-07-08 |
Plus two re-encodings of existing sets for a different backbone (*-wan-latents), a
snapshot of the older /mnt/data LTX directory (old/), and reference LoRAs
(cameraman/). Those are at the bottom.
Two further sets condition on a reference image rather than a reference video. They
belong to the earlier /mnt/data/xinyuy/datasets/LTX/ generation and are built elsewhere,
but they feed the same trainer and are documented here too — see
Image-reference sets:
| Set | Task | Pairs | Built from | Built |
|---|---|---|---|---|
Style-Image-Dataset |
style image → video | 1,900 | OpenVE-3M global_style.csv |
2026-08-02 |
Subject2Video-Dataset |
face crop → video | 2,997 | ConsisID-preview-Data | 2026-05-05 |
Subject2Video-MaskedRef-Dataset |
masked person / head crop → video | 2,182 | ↑ same, remixed | 2026-05-05 |
The shared contract
Every set has the same flat layout, so any of them drops into the same trainer:
<Dataset>/
├── <stem>.mp4 target — the video the model learns to generate
├── <stem>_<kind>.mp4 reference — the control signal (kind = pose|depth|painting|camera)
├── … × 2,000 pairs
├── dataset.json [{caption, media_path, reference_path}, …]
└── .precomputed/ written by the LTX-2 trainer, not by the build scripts
├── latents/ <stem>.pt target VAE latents
├── reference_latents/ <stem>.pt reference VAE latents
├── conditions/ <stem>.pt Gemma3 text embeddings
└── multi_gpu_logs/ shard_N.log
dataset.json entries are exactly three keys, paths relative to the dataset dir:
{
"caption": "A woman with blue body paint on her face …",
"media_path": "10026939-hd_1920_1080_30fps.mp4",
"reference_path": "10026939-hd_1920_1080_30fps_pose.mp4"
}
The trainer's preprocessed_data_root points at the dataset root, not at
.precomputed — PRECOMPUTED_DIR_NAME = ".precomputed" is appended automatically
(packages/ltx-trainer/src/ltx_trainer/datasets.py:12).
File counts are 4001 per set (2,000 pairs + dataset.json) and ~6,00x files under
.precomputed.
The image-reference sets use the same contract, with reference_path naming a .png
or .jpg instead of an .mp4; Style-Image-Dataset adds a fourth key, style_prompt.
The pipeline, in five stages
Every reference-video set follows the same shape; only stages 1–3 differ per task. (The image-reference sets swap stage 2 for a frame-cropping step — see their own section.)
1. SELECT & TRIM raw corpus ──► N clips of exactly 81 frames
2. REFERENCE clips ──────► the control video (depth / pose / mask / camera-twin)
3. CAPTION clips ──────► one caption per clip
4. BUILD ────────────► flat {stem}.mp4 + {stem}_<kind>.mp4 + dataset.json
5. PRECOMPUTE ────────────► .precomputed/{latents,reference_latents,conditions}
Stages 1–4 run in the source dataset folder (<Source>/processing/*.py), under
conda env flexcombine-data. Stage 5 runs in ~/flexvideo/LTX-2 under its uv
environment. The tooling for stage 2 is shared:
~/dataset_processing/flexcombine-bench/tools/compute_reference.py.
Every build script takes --seed 0 and samples with random.Random(seed).sample(...)
over a sorted eligible list — so selections are exactly reproducible. Verified: re-running
the selection logic for both Pose-Dataset and Depth-Dataset reproduces the shipped
2,000 stems identically.
Pose-Dataset
Source: HumanVID/ — 11,403 horizontal Pexels videos downloaded with aria2c
(download_videos.sh, URL list pexels-horizontal-urls-new.txt; failed_videos.txt
records what never landed).
1. Select & trim
cd /mnt/dataset/xinyuy/datasets/HumanVID
python ./processing/select_and_trim_videos.py --output-dir selected_videos_dedup --dedup
Keeps the first 81 frames of each selected video. Frame counts come from ffprobe
container metadata and the trim is ffmpeg -c copy, so nothing is ever decoded or
re-encoded — the stage stays I/O-bound.
--dedup is the important flag and the reason this set exists twice. Pexels clips whose
filenames share the first four characters are shoots of the same person; without the
flag the same human recurs across the training set. Dedup collapses those groups to one
clip each, which is why selected_videos_dedup/ holds 2,415 files against
selected_videos/'s 3,003 (the target was 3,000 either way — dedup ran out of distinct
groups). This is the note in ../Notes.md.
2. Pose reference — DWPose
cd ~/dataset_processing/flexcombine-bench/tools
export CUDA_VISIBLE_DEVICES=0,1,2,3,4,5,6,7
python compute_reference.py /mnt/dataset/xinyuy/datasets/HumanVID/selected_videos_dedup \
--type pose --dwpose-repo-path DWPose \
--output-path /mnt/dataset/xinyuy/datasets/HumanVID/selected_videos_dedup/pose \
--num-workers 8
Writes <stem>_pose.mp4 skeleton videos — 2,413 of 2,415 clips succeeded.
Adding --no-face renders skeletons without facial keypoints, into a parallel
pose_no_face/ folder. That was only ever done for the pre-dedup selected_videos/, and
fed Pose-No-Face-Dataset-Legacy. selected_videos_dedup/ has no pose_no_face/.
3. Caption — Gemini
python processing/caption.py selected_videos_dedup --model gemini-2.5-flash --concurrency 8
Writes selected_videos_dedup/captions.json — a flat {stem: caption} dict, 2,402 entries.
Needs $GEMINI_API_KEY. The built-in prompt asks for a 35–40 word factual caption
covering people count, appearance, scene, broad activity, and mood, and explicitly forbids
describing limb positions or pose sequences — the pose skeleton carries that, so putting it
in the text too would teach the model to read it from the wrong place.
4. Build
Inferred — this exact invocation is not in shell history (it ran inside a claude
session), but the resulting selection reproduces bit-for-bit from these arguments:
python processing/build_pose_dataset.py \
--videos-dir selected_videos_dedup \
--pose-dir selected_videos_dedup/pose \
--pose-no-face-dir selected_videos_dedup/pose \
--reference-path selected_videos_dedup/pose \
--output /mnt/dataset/xinyuy/datasets/LTX-2/Pose-Dataset \
--num-videos 2000 --link-mode copy
--pose-no-face-dir has to be given something that exists — the script validates it even
when it isn't the reference — hence pointing it at pose/. Eligible pool: 2,402 stems
(present in the videos dir and captions.json and pose/), sample 2,000 at seed 0.
--link-mode copy because the destination is a different concern from the source; the
script defaults to hardlink and falls back to a copy across filesystems.
Result: 4.5 GB of media, references are byte-identical copies of
selected_videos_dedup/pose/ (verified by md5).
Legacy variants
Pose-Dataset-Legacy and Pose-No-Face-Dataset-Legacy were built 2026-07-07/09 from the
pre-dedup selected_videos/, and renamed with mv on 2026-07-09 21:01 when the
duplicate-human problem surfaced:
python processing/build_pose_dataset.py --output …/LTX-2/Pose-Dataset \
--num-videos 2000 --reference-path selected_videos/pose --link-mode copy
python processing/build_pose_dataset.py --output …/LTX-2/Pose-No-Face-Dataset \
--num-videos 2000 --reference-path selected_videos/pose_no_face --link-mode copy
The two legacy sets share the same 2,000 stems and the same captions — they differ only
in whether the skeleton includes the face. The current Pose-Dataset overlaps them by
1,145 clips.
Depth-Dataset
Source: VIDGEN-1M/ — Fudan-FUXI/VIDGEN-1M, 2,048 zips extracted to ~1.01 M clips,
with VidGen_1M_video_caption.json shipped upstream.
1. Select & trim
cd /mnt/dataset/xinyuy/datasets/VIDGEN-1M
python ./processing/select_and_trim_videos.py --output-dir selected_videos \
--caption-file VidGen_1M_video_caption.json
This is a different implementation from the HumanVID one, and deliberately so: it
decodes with PyAV and re-encodes the 81 kept frames at the source fps, instead of
ffmpeg -c copy. Stream-copy trims on this corpus produce container timestamp / edit-list
oddities; a single decode pass avoids them. --caption-file restricts the candidate pool
to clips that actually have an upstream caption. Result: 3,000 clips.
2. Depth reference — Video-Depth-Anything
cd ~/dataset_processing/flexcombine-bench/tools
python compute_reference.py \
/mnt/dataset/xinyuy/datasets/VIDGEN-1M/selected_videos \
--type depth --depth-repo-path Video-Depth-Anything --encoder vitl \
--output-path /mnt/dataset/xinyuy/datasets/VIDGEN-1M/selected_videos/depth \
--num-workers 8
3,000 <stem>_depth.mp4 written — full coverage.
3. Caption
None. Captions come straight from upstream VidGen_1M_video_caption.json
(a list of {vid, caption}), loaded by the builder.
4. Build
python processing/build_depth_dataset.py \
--output /mnt/dataset/xinyuy/datasets/LTX-2/Depth-Dataset \
--num-videos 2000 --reference-path selected_videos/depth --link-mode copy
Eligible pool: all 3,000; sample 2,000 at seed 0. Result: 2.4 GB of media.
Note the flag churn in history —
--depth-pathand--depth-dirwere both tried and rejected before--reference-pathstuck. The script's option is--depth-dir; the command that actually ran used--reference-path, which argparse accepts as an unambiguous prefix of nothing else. Use--depth-dirif rebuilding.
Inpainting-Dataset
Source: VPData/ (TencentARC VideoPainter) via the VPdata_processing/ pipeline.
This one is the most involved, because the control clips cover only a sub-range of their
raw video.
Full upstream-processing documentation lives in
../VPdata_processing/README.md — mask extraction, download_pexels.py,
overlay_masks.py, outpaint_masks.py. Summary of what feeds this set:
VPData/selected_videos/— 3,000 raw Pexels videosVPData/inpainting/— 3,404 control clips, object interior blacked outVPData/outpainting/— 3,000 control clips, everything outside a box blacked outVPData/pexels_videovo_train_dataset.csv— 391,416 rows ofpath, start_frame, end_frame, fps, mask_id, caption
Control clips are named {12-digit index}_{videoId}_{start}-{end}.mp4 and cover only
frames [start, end] of the raw video.
Build
cd /mnt/dataset/xinyuy/datasets/VPData
python processing/build_inpainting_outpainting_dataset.py \
--output /mnt/dataset/xinyuy/datasets/LTX-2/Inpainting-Dataset \
--csv pexels_videovo_train_dataset.csv --workers 32
Two things make this script different from the pose/depth builders:
- The target is re-encoded, not linked. Because the control clip covers only
[start, end], the{stem}.mp4target is freshly trimmed out ofselected_videos/<videoId>.mp4to that exact frame range (PyAV, libx264, yuv420p,preset=veryfast) so the pair stays frame-aligned. Only{stem}_painting.mp4is hardlinked. - Distinct-videoId allocation across the two pools. Every outpainting clip's videoId
also has an inpainting clip, so a naive 50/50 draw would ship the same footage twice.
allocate()fills the smaller pool first and excludes its videoIds from the other pool's candidates.
Verified in the shipped set: exactly 1,000 references hardlinked from
VPData/inpainting/ and 1,000 from VPData/outpainting/ (checked by inode), no
overlap. Default --inpaint-ratio 0.5, seed 0.
Result: 141 GB — by far the largest set here, because these are full-resolution Pexels
clips, not 81-frame trims. The _painting.mp4 half costs no extra disk (143 GB of
hardlinks into VPData/); deleting either copy frees nothing.
Camera-Dataset / Camera-Dataset-Val
Source: CameraClone-Dataset/ (KwaiVGI CamCloneMaster). Different in kind from the
other three: there is no reference extractor. Inside one
data/<date>/traj_<group>_<cam>/ directory every video was rendered with the same camera
trajectory at a different 3D location — so a pair of videos from one directory already
is a (target, same-motion reference) pair, by construction. 1,154,819 CSV rows were
checked: the reference is in the same traj_* dir 100 % of the time and never the same
scene file.
The build script is CameraClone-Dataset/processing/build_camera_dataset.py, and it has
its own detailed README at ../CameraClone-Dataset/processing/README.md — read that
one for the motion estimator, the caption-clustering diversity scheme, and the artifact
files. Short version:
cd /mnt/dataset/xinyuy/datasets/CameraClone-Dataset/processing
python3 build_camera_dataset.py --stage all # train, ~2 min
python3 build_camera_dataset.py --split val --stage all # val, ~1 min (needs train first)
python3 build_camera_dataset.py --split val --stage verify
Stages index → select → measure → trim → encode → emit → verify, each individually
runnable and resumable.
Points worth remembering:
- Video is remuxed, not re-encoded (
NATIVE = True):ffmpeg -c:v copy -an, verified bit-identical on 24 sampled clips. HEVC, 15 fps, 77 frames, 1344×768 (batches 0316,- or 1008×576 (the rest). 77 is not
8n+1, so the trainer buckets/truncates — the precompute below used 73 frames.NATIVE = Falseswitches to a normalised 1280×720 / h264 / 73-frame path instead (~10 min, ~9.2 GB).
- or 1008×576 (the rest). 77 is not
- Diversity comes from captions, not scene ids — TF-IDF +
MiniBatchKMeans(k=60)over 40,767 candidate captions, then round-robin across clusters. Hard constraints: one pair per trajectory group, each target location once, each reference location once. - Motion was measured, not assumed. The camera index (
c07) is not a motion type — trajectories are generated per group. ORB +estimateAffinePartial2D(RANSAC)on every 4th frame at 320 px. Farneback optical flow was tried first and is too contaminated by character motion — do not go back to it. - Train and val are disjoint in trajectory group, target location, reference location,
and file;
verifyasserts all three both ways. - The caption describes the target, so the prompt supplies the scene and the reference supplies only the motion.
Result: 2.8 GB train / 65 MB val. Camera-Dataset-Val/ currently has no
.precomputed/ — it was built, then deleted on 2026-08-19 19:47 in favour of
precomputing the train split.
Stage 5 — precompute LTX-2 latents
Run from ~/flexvideo/LTX-2 (its own uv env, source .venv/bin/activate):
export CUDA_VISIBLE_DEVICES=0,1,2,3,4,5,6,7
uv run python packages/ltx-trainer/scripts/process_dataset_multi_gpu.py --num-gpus 8 \
/mnt/dataset/xinyuy/datasets/LTX-2/<Dataset>/dataset.json \
--resolution-buckets "960x544x81" \
--model-path /home/xinyuy/flexvideo/LTX-2/ckpts/LTX-2.3/ltx-2.3-22b-dev.safetensors \
--text-encoder-path /mnt/data/xinyuy/models/Gemma3 \
--reference-column "reference_path"
Writes into <Dataset>/.precomputed/. Resolution bucket per set:
| Dataset | bucket | why |
|---|---|---|
Pose-Dataset, Pose-*-Legacy |
960x544x81 |
clips trimmed to 81 frames |
Depth-Dataset |
960x544x81 |
same |
Inpainting-Dataset |
960x544x81 |
same |
Camera-Dataset, -Val |
960x544x73 |
source clips are 77 frames; 73 is the nearest 8n+1 below |
The single-GPU process_dataset.py takes the same arguments minus --num-gpus.
--reference-downscale-factor N encodes the reference at 1/N resolution and must match
validation.reference_downscale_factor in the training config; all four sets here used
the default 1.
To re-run cleanly, delete .precomputed/ first — the multi-GPU script does not
invalidate stale shards. Shard logs land in .precomputed/multi_gpu_logs/shard_N.log.
Consumed by
~/flexvideo/LTX-2/packages/ltx-trainer/configs*/ltx2_v2v_ic_lora_*.yaml, e.g.
data:
preprocessed_data_root: "/mnt/dataset/xinyuy/datasets/LTX-2/Camera-Dataset"
training_strategy:
name: "video_to_video"
reference_latents_dir: "reference_latents"
configs/ = single-condition runs, configs_scale_up/ = the 2,000-pair versions,
configs_size_abalation/ = the pose 100/1000/2000 × rank 32/64 sweep.
The *-wan-latents folders
Depth-Dataset-wan-latents/ and Pose-Dataset-wan-latents/ are not new datasets —
they are the same Depth-Dataset / Pose-Dataset manifests re-encoded with the Wan 2.1
T2V-1.3B VAE + umT5, for the Wan port of IC-LoRA at
~/flexvideo/wan_ic_lora/wan-ic-lora (see its IC_LORA.md).
torchrun --nproc_per_node=8 scripts/precompute_ic_lora.py \
--dataset /mnt/dataset/xinyuy/datasets/LTX-2/Depth-Dataset/dataset.json \
--ckpt_dir /mnt/dataset/xinyuy/models/wan/Wan2.1-T2V-1.3B \
--out /mnt/dataset/xinyuy/datasets/LTX-2/Depth-Dataset-wan-latents \
--size 832*480 --frame_num 81
Output is a separate directory (the source dataset is read-only to it), with
latents/, reference_latents/, conditions/ and a meta.json recording exactly what
everything was encoded with. Re-running skips finished samples.
Recorded settings for both (from meta.json): task v2v-1.3B, size 832×480,
frame_num 81, reference_downscale 1, vae_stride [4,8,8],
latent_shape [16, 21, 60, 104]. 2,000 files in each of the three subdirs, 17–18 GB each.
Timeline
| When | What |
|---|---|
| 2026-05-05 12:15 | ConsisID crops cut (head, person); Subject2Video-Dataset materialized 12:31 |
| 2026-05-05 21:49 | masked crops cut; create_masked_ref_dataset.py run 22:01 |
| 2026-07-07 12:05 | Pose-Dataset (pre-dedup) + Pose-No-Face-Dataset built |
| 2026-07-07 21:04 | Depth-Dataset built; depth references computed in parallel |
| 2026-07-08 11:29 | Inpainting-Dataset built |
| 2026-07-09 09:18 | pre-dedup Pose-Dataset rebuilt |
| 2026-07-09 21:01 | duplicate humans spotted → both pose sets renamed *-Legacy |
| 2026-07-09 21:11 | selected_videos_dedup selected, DWPose + Gemini re-run |
| 2026-07-09 23:14 | current Pose-Dataset finished |
| 2026-08-02 18:25 | style-transfer-reference built; linked into LTX/ as Style-Image-Dataset 18:42 |
| 2026-08-17 15:20 | /mnt/data/xinyuy/datasets/LTX snapshotted into old/ |
| 2026-08-18 16:13 | Wan latents for Depth, then Pose (23:10) |
| 2026-08-19 19:42 | Camera-Dataset-Val precomputed, then discarded for the train split |
| 2026-08-19 20:02 | Camera-Dataset precomputed |
Rebuilding and verifying
Selections are seeded and deterministic. To confirm a set still matches its recipe without touching disk:
# Pose-Dataset — reproduces the shipped 2,000 stems exactly
import json, random
from pathlib import Path
root = Path('/mnt/dataset/xinyuy/datasets/HumanVID/selected_videos_dedup')
caps = json.loads((root / 'captions.json').read_text())
elig = [p.stem for p in sorted(root.glob('*.mp4'))
if p.stem in caps and (root / 'pose' / f'{p.stem}_pose.mp4').exists()]
assert len(elig) == 2402
sel = sorted(random.Random(0).sample(elig, 2000))
Same shape for Depth-Dataset (eligible pool 3,000, sample 2,000, seed 0). Both were
re-run on 2026-08-21 and matched the shipped stems exactly.
For Camera-Dataset, use the script's own stage:
python3 build_camera_dataset.py [--split val] --stage verify.
Image-reference sets — Style-Image and Subject2Video
The four sets above condition on a reference video. Two earlier sets condition on a
reference image instead, and they live in the previous-generation directory
/mnt/data/xinyuy/datasets/LTX/, where both entries are symlinks out to the folder that
actually built them:
Entry in /mnt/data/…/LTX/ |
Symlink target | Size | Linked |
|---|---|---|---|
Style-Image-Dataset |
~/dataset_processing/OpenVE-3M/style-transfer-reference |
30 G | 2026-08-02 |
Subject2Video-Dataset |
/mnt/data/…/ConsisID-preview-Data/Subject2Video-Dataset |
41 G | 2026-05-05 |
Subject2Video-MaskedRef-Dataset |
/mnt/data/…/ConsisID-preview-Data/Subject2Video-MaskedRef-Dataset |
28 G | 2026-05-05 |
Dereferenced copies of all three are frozen in old/ (see below). Both sets keep the same
dataset.json contract — {caption, media_path, reference_path} — the only difference is
that reference_path names a .png / .jpg, not an .mp4.
Style-Image-Dataset
Source: OpenVE-3M — /mnt/data/xinyuy/datasets/OpenVE-3M/csv_files/global_style.csv
over OpenVE-3M/videos/. Scripts in ~/dataset_processing/OpenVE-3M/.
The task is (style reference image + prompt) → stylized video, and the one design decision that matters is where the reference frame comes from:
The stylized clip is the generation target (
media_path). Its conditioning is a single frame sampled at random from a different stylized clip of the same style (reference_path) — drawing the frame from a foreign clip is what keeps the pair honest, since a model cannot then solve the task by copying content out of its own reference.
Verified in manifest.csv: 1,900 / 1,900 rows have
reference_source_video != renamed_video. Row 0, for instance, pairs target
abstract_000.mp4 with abstract_000_ref.png = frame 32 of abstract_063.mp4.
1. Build
cd ~/dataset_processing/OpenVE-3M
python build_style_transfer_reference.py
Defaults are what shipped: --per-style 100, --sample-seed 42 (clip selection),
--seed 20260802 (donor clip + frame choice), --ext png. Style labels are parsed out of
the CSV prompt text and filtered to a canonical 19 taxonomy (Abstract Art, Ancient
Style, Cartoon, Chinese Ink Wash, Cubist, Cyberpunk, Ghibli, Gongbi, Impressionist, Oil
Painting, Pixel Art, Pointillist, Pop Art, Sketch, Steampunk, Surrealist, Thick-Paint
Hand-Drawn, Ukiyoe, Watercolor). Confirmed in the manifest: 19 styles × exactly 100 =
1,900, and no original_video is shared across styles.
The _org (unstylized) source clips are deliberately not copied — they have no role
once the conditioning is an image — but every manifest row keeps original_org so they can
be recovered from the CSV.
--horizontal-only restricts sampling to landscape clips and writes to
style-transfer-reference-horizontal/ instead. Because references are cut from another
clip of the same style, filtering the clips is enough to make every reference landscape too.
2. Caption
python caption_transfer_reference.py style-transfer-reference \
--model gemini-2.5-flash --concurrency 8
This one is not a plain captioner. In manifest mode it captions the original, unstylized
clip behind each target (the manifest's original_org column) and then rewrites
dataset.json so caption describes the video content, moving the original
style-transfer instruction into a separate style_prompt field. So entries here have
four keys, not three:
{
"caption": "A young boy in a red shirt rows a red and yellow boat on a tranquil lake…",
"reference_path": "abstract_000_ref.png",
"media_path": "abstract_000.mp4",
"style_prompt": "Apply the Abstract Art style to this video, ensuring seamless temporal…"
}
Useful flags: --limit 5 for a smoke test, --update-only to rewrite dataset.json from
an existing captions file without calling Gemini, --no-update-dataset to caption only.
Raw captions are kept in source_captions.json, and the pre-rewrite manifest in
dataset.json.bak.
3. Precompute
uv run python packages/ltx-trainer/scripts/process_dataset_multi_gpu.py --num-gpus 8 \
/home/xinyuy/dataset_processing/OpenVE-3M/style-transfer-reference/dataset.json \
--resolution-buckets "960x544x33" \
--model-path /home/xinyuy/flexvideo/LTX-2/ckpts/LTX-2.3/ltx-2.3-22b-dev.safetensors \
--text-encoder-path /mnt/data/xinyuy/models/Gemma3 \
--reference-column "reference_path"
Source clips are 1280×720, 30 fps, 57 frames. The first run used
960x544x37; it was re-run three minutes later at 960x544x33, which is the value
that stuck — 33 satisfies frames % 8 == 1, 37 does not.
Consumed by configs/ltx2_v2v_ic_lora_style_image.yaml
(preprocessed_data_root: /mnt/data/xinyuy/datasets/LTX/Style-Image-Dataset, W&B project
ltx-2-trainer-style).
Sibling variants
Same builder, same 1,900-row shape, precomputed the same way at 960x544x33:
| Directory | What differs |
|---|---|
style-transfer-reference-horizontal/ |
--horizontal-only — landscape clips only |
style-transfer-reference-long-cap/ |
a copy of the base set re-captioned with longer captions |
style-transfer-reference-validate/ |
38-row held-out set, build_style_transfer_reference_validate.py |
Not to be confused with Style-Transfer-OpenVE-3M-Dataset/ (5,700 rows), which is the
older video→video style-transfer set — reference is a clip, not an image.
Subject2Video-Dataset
Source: BestWishYsh/ConsisID-preview-Data,
downloaded to /mnt/data/xinyuy/datasets/ConsisID-preview-Data/. That folder has its own
README.md documenting the HF bucket export; the build itself is below. Scripts are kept in
both the folder root and processing_codes/.
Upstream ships videos/videos/ (51,242 clips), bboxes/refine_bbox_jsons/ (31,947
per-clip bbox JSONs), masks/track_masks_data/ (31,947 tracking-mask dirs) and
video_caption_train.json (28 MB of captions).
1. Crop reference images from bbox annotations
cd /mnt/data/xinyuy/datasets/ConsisID-preview-Data
python generate_reference_images.py --type all
Samples --num 3000 clips at --seed 42 from the video/bbox intersection, picks one
random frame in which every requested type has a detection, takes the highest-confidence
box per type, and writes <output>/<type>/<stem>.jpg. Result: reference_images/head/
and reference_images/person/, 2,997 each (3 of the 3,000 had no frame valid for all
three types).
A second run adds background masking:
python generate_reference_images.py --type all \
--masks masks/track_masks_data --output ref_imgs_masked
With --masks, valid frames are additionally intersected with the tracking data's
valid_frame.json, and every pixel outside the tracked mask is set to white. That
constraint is much tighter — ref_imgs_masked/{face,head,person} hold 1,091 each.
2. Materialize Subject2Video-Dataset
The 2,997 selected clips were moved out of videos/videos/ into
Subject2Video-Dataset/<stem>.mp4 (original 2024 mtimes preserved; the stems are no longer
present in videos/videos/, and all 2,997 still have their bbox JSON), each paired with
<stem>_reference.jpg and indexed by a dataset.json whose captions come from
video_caption_train.json.
The shipped reference is the face crop, not head or
person. Inferred from a build step not in shell history, but pinned down: the
reference for --37UfNPPlw.5_segment_0_67-… is 89×134, which matches no head (181×132)
or person (347×238) crop, and matches a face box in that clip's bbox JSON exactly.
reference_images/face/ is empty today, consistent with those crops having been moved into
the dataset.
3. Materialize the masked-reference variant
python create_masked_ref_dataset.py
Hard-coded, no CLI. Builds a deliberate 50/50 mix of two reference kinds at SEED = 42:
- 1,091 masked-person references from
ref_imgs_masked/person, videos symlinked fromvideos/videos/— the whole pool, since it is the smaller one; - 1,091 head references from
reference_images/head, videos symlinked fromSubject2Video-Dataset/, sampled down from 2,997 to match.
2,182 pairs total. Verified on disk: all 2,182 videos are symlinks (into
videos/videos/ or Subject2Video-Dataset/), the two reference files spot-checked are
byte-identical to their ref_imgs_masked/person and reference_images/head sources, and
the two stem pools are disjoint — no clip appears with both a masked-person and a head
reference.
Two things the script does not do: it writes to Subject2Video-Dataset-MaskedRef (the
directory was renamed to Subject2Video-MaskedRef-Dataset afterwards) and it writes no
dataset.json — captions were joined on in a later step, and the shipped manifest has
2,182 entries.
4. Precompute
uv run python packages/ltx-trainer/scripts/process_dataset.py \
/mnt/data/xinyuy/datasets/LTX/Subject2Video-Dataset/dataset.json \
--resolution-buckets "960x544x33" \
--model-path /home/xinyuy/flexvideo/LTX-2/ckpts/LTX-2.3/ltx-2.3-22b-dev.safetensors \
--text-encoder-path /mnt/data/xinyuy/models/Gemma3 \
--reference-column "reference_path"
Clips are 1280×720, 24 fps, ~60 frames; bucket 960x544x33. Same command for
Subject2Video-MaskedRef-Dataset. Adding --reference-only re-encodes just
reference_latents/ — used when the reference images changed but the target clips did not,
which is exactly what happens when swapping crop types.
Both sets are fully precomputed: 2,997 × 3 and 2,182 × 3 tensors.
Consumed by configs/ltx2_v2v_ic_lora_subject.yaml
(preprocessed_data_root: /mnt/data/xinyuy/datasets/LTX/Subject2Video-MaskedRef-Dataset,
W&B project ltx-2-trainer-subject), plus the
ltx2_v2v_ic_lora_subject_{tiling,no_tiling}_{offset,no_offset}.yaml ablation grid and
configs_scale_up/ltx2_v2v_ic_lora_subject.yaml.
Backup
hf://buckets/fishxinyu/ConsisID-preview-Data — 35,167 files, ~70.4 GiB: both datasets
with their .precomputed/, the two crop folders, and the three scripts. Raw intermediates
(masks/, videos/, bboxes/, video_caption_train.json — ~137 GB) are local only.
The style sets sync to hf://buckets/fishxinyu/OpenVE-3M and
…/OpenVE-3M-process.
The other folders
old/ — 74 GB
A rsync -aL snapshot of /mnt/data/xinyuy/datasets/LTX, taken 2026-08-17. Eight of its
sixteen entries were symlinks into Senorita / ConsisID / OpenVE-3M; they were
dereferenced into real files, so this copy is self-contained. Provenance table, per-directory
file counts, and the original_symlinks.tsv mapping are in old/README.md. These are
the previous generation of training sets (Canny, Depth-Prediction, Object-{Addition,
Removal,Swap}, Style-Transfer, Subject2Video, …) — kept for reference, not fed by anything
here.
Three of its entries are the image-reference sets documented above:
old/Style-Image-Dataset (9,512 files), old/Subject2Video-Dataset (14,986) and
old/Subject2Video-MaskedRef-Dataset (10,911). All three were symlinks in the source and
are real files here, .precomputed/ included — so this is the one self-contained copy
of them, and the only one that survives if the live build folders are cleaned. The training
configs still point at the live /mnt/data/…/LTX/ symlinks, not at these.
cameraman/ — 1.8 GB
Reference material gathered while designing Camera-Dataset, not training data:
LTX2.3-22B_IC-LoRA-Cameraman_v1/v2 (the released camera IC-LoRAs — v2's hand-curated
motion distribution is the 27 % → 7 % baseline the README compares against),
LTX-2.3-3DREAL-LoRA, and ComfyUI-CameraReference3D.
Backup
This whole directory syncs to hf://buckets/fishxinyu/LTX-2-training — note the
-training suffix; the bucket plainly named LTX-2 is /mnt/data/xinyuy/outputs/LTX-2,
a different thing. Last full sync succeeded 2026-08-17, 181,697 files / 758,606,143,719 B,
exact match.
The sync is driven by a retry supervisor at ../.hf-sync/ltx2-sync.sh — hf buckets sync
dies on 429s and connection resets, and the supervisor restarts it with exponential backoff
(30 s → 300 s cap), treating any attempt over 10 min as progress and bailing out after 10
consecutive sub-30 s failures as a sign of a real auth/quota/path error. State in
../.hf-sync/status.json, per-attempt logs in ../.hf-sync/attempts/.
Gotchas worth keeping
--dedupmatters for Pexels-sourced data. Same first four filename chars = same shoot = same human. This is the only reasonPose-Dataset-Legacyexists.build_pose_dataset.pyvalidates--pose-no-face-direven when it isn't the reference. With a dedup folder that has nopose_no_face/, point it atpose/.- The two
select_and_trim_videos.pyare not the same script. HumanVID's uses ffprobe + stream copy; VIDGEN's uses a single PyAV decode pass, on purpose. - Inpainting targets are re-encoded, not linked — the control clip covers a sub-range, so the target must be trimmed to match or the pair desyncs.
Inpainting-Dataset/*_painting.mp4are hardlinks intoVPData/. 143 GB that exists once. Deleting one side frees nothing.- Camera clips are 77 frames, not
8n+1. Precompute used bucket…x73. - Delete
.precomputed/before re-precomputing — stale shards are not invalidated. - The style reference frame must come from a different clip. Same style, foreign clip. Cut it from the target's own frames and the task collapses into copying.
Subject2Video-Dataset's clips were moved, not copied, out ofvideos/videos/. Their stems are gone from the raw pool, so anything that re-scans it (includinggenerate_reference_images.py) can no longer see them — which is why the masked-crop pool is disjoint from the main set.create_masked_ref_dataset.pywrites symlinks and the wrong directory name (Subject2Video-Dataset-MaskedRef), and writes nodataset.json. Rename after, and join the captions separately.- LTX-2 needs
frames % 8 == 1. The first style precompute used bucket…x37and was re-run at…x33minutes later. PyAVis used for encoding everywhere instead ofcv2.VideoWriter, whose bundled FFmpeg can only open themp4vfourcc that most players refuse.
- Total size
- 759 GB
- Files
- 181,698
- Last updated
- Aug 21
- Pre-warmed CDN
- US EU US EU