diff --git a/.gitignore b/.gitignore index 24d025a..3be255a 100644 --- a/.gitignore +++ b/.gitignore @@ -19,10 +19,11 @@ wheels/ # Packed bundles bundle/* -# Input/output files -input/* -!input/.gitkeep +# User inputs, run outputs, and model caches. scripts/bundle.sh packs +# untracked/input/ explicitly into pod bundles; everything else stays local. untracked/* !untracked/.gitkeep -output/* +!untracked/input/ +untracked/input/* +!untracked/input/.gitkeep diff --git a/AGENTS.md b/AGENTS.md index 04ce373..765b270 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -54,7 +54,7 @@ uv run dltb-similarity # DreamSim perceptual drift/converg uv run python src/dltb/analyze_drift.py # CPU-only drift metrics ``` -The drivers read their input files (`IMG`/`CLIP`) from `input/inputs.env`, +The drivers read their input files (`IMG`/`CLIP`) from `untracked/input/inputs.env`, falling back to the tracked `input_example/inputs.env`; environment variables win (see `scripts/inputs.sh`). @@ -77,7 +77,7 @@ in `pyproject.toml`): | --- | --- | | `models.py` | `ModelSpec`/`MODELS` table (5 models), `load_pipeline`, fast-fail checks, geometry rules | | `imaging.py` | `run_pass` (one model pass), `prepare_frame`, optical-flow reprojection | -| `output.py` | run-directory layout (`output_/_/`), timelapse assembly | +| `output.py` | run-directory layout (`untracked/output_/_/`), timelapse assembly | | `args.py` | argparse flag groups shared by the tools | | `oneshot.py` / `iterate.py` | single pass / free-running self-iteration | | `continuous.py` | video loop: anchored boil test vs stateful blend, reproject, freeze/free/black tails | @@ -133,13 +133,13 @@ Key invariants: - **Any tar creation needs `COPYFILE_DISABLE=1`** or macOS pollutes archives with `._*` AppleDouble members (`bundle.sh` does this + a python3 `tarfile` verification guard; never verify with `tar -t`, it hides them). -- Bundles ship **tracked files only**, with one exception: gitignored `input/` - (user inputs) is packed explicitly by `bundle.sh`. `git add` new scripts - before `just bundle`, or the pod silently misses them (the bundle script - warns). -- `.gitignore` covers `output/`, `bundle/`, `untracked/` (DreamSim weight - cache), `._*`, `.DS_Store`, `.pi/` — keep - generated artifacts out of git. +- Bundles ship **tracked files only**, with one exception: gitignored + `untracked/input/` (user inputs) is packed explicitly by `bundle.sh`. + `git add` new scripts before `just bundle`, or the pod silently misses them + (the bundle script warns). +- `.gitignore` covers `untracked/` (user inputs, run outputs, DreamSim weight + cache), `bundle/`, `._*`, `.DS_Store`, `.pi/` — keep generated artifacts out + of git. ### MPS (Apple Silicon) runs @@ -150,8 +150,8 @@ Key invariants: - Some ops are unimplemented on MPS: `PYTORCH_ENABLE_MPS_FALLBACK=1` runs them on CPU (silently slow; escape hatch only). - Local and pod outputs must not share a tree: run tags do not encode the - device. Use `--output-dir` subtrees (`output_` locally vs - `output/pod-*` on the pod) — same rule as other non-tag knobs. + device. Use `--output-dir` subtrees (`untracked/output_` locally vs + `untracked/output/pod-*` on the pod) — same rule as other non-tag knobs. - MPS ≠ CUDA pixel parity is not a goal; compare frames only within one device (same as any other kernel change). @@ -174,7 +174,7 @@ scripts/smoke.sh && scripts/sweep.sh `/workspace/imgiter` so `.venv` and outputs survive new bundle extracts. - `just` and `runpodctl` are NOT in the pod image — use `scripts/*.sh` directly. - 48 GB VRAM recommended; `--offload` for the two big models on smaller cards. -- Container disk is **ephemeral on stop AND restart** — copy `output/` out +- Container disk is **ephemeral on stop AND restart** — copy `untracked/output/` out before stopping. Pod sshd isn't started by default (NOTES.md has the fix). - HF cache: swept models are kept by default (all five ≈ 87.5 GB fit the 150 GB pod disk); `EVICT_CACHE=1` (env or `inputs.env`, like `IMG`/`CLIP`) restores diff --git a/NOTES.md b/NOTES.md index 819dd7b..d78820e 100644 --- a/NOTES.md +++ b/NOTES.md @@ -367,12 +367,12 @@ state and the fresh frame can both be conditioning inputs: **Suggested first runs:** - uv run dltb-klein --model flux2-klein-4b --input input/video_cropped.mp4 \ + uv run dltb-klein --model flux2-klein-4b --input untracked/input/video_cropped.mp4 \ --conditioning dual-ref --prompt "slightly enhance the fine details" \ --max-frames 30 --tail-frames 10 --save-every 1 # order A/B (2 frames each, compare): EXTRA_ARGS='--reproject' etc. - uv run dltb-klein --model flux2-klein-4b --input input/video_cropped.mp4 \ + uv run dltb-klein --model flux2-klein-4b --input untracked/input/video_cropped.mp4 \ --conditioning dual-ref --ref-order state-first --max-frames 2 Remaining follow-ups: none in-tree — the `SMOKE_KLEIN=1` smoke leg, the @@ -424,7 +424,7 @@ it only modulates texture anyway. **Reference-gain readout** (4b, 5 source frames then 10-frame tails freeze/free/black branching from ONE shared end state, empty prompt, fixed -seed; pod `output/debug/refweight`). MAD between tail videos, t=1 → t=10: +seed; pod `untracked/output/debug/refweight`). MAD between tail videos, t=1 → t=10: frz-free 4.21 → 33.71 ([P, last_source] vs [P] alone) frz-black 1.65 → 13.01 ([P, last_source] vs [P, black]) @@ -509,7 +509,7 @@ plateau ~50). fbmask cuts zone error −44% and halves the saturation excursion on 9b. **Neutral-prompt control & line concluded (2026-09-13; quantified from -`output/pod-20260913_debug-flux2_4`).** Two separable findings: +`untracked/output/pod-20260913_debug-flux2_4`).** Two separable findings: - GLOBAL compounding drift is prompt-INDEPENDENT: analyze_drift delta_original (last-10 mean) neutral 88.5/89.0 (plain/fbmask) vs @@ -608,7 +608,7 @@ disk is wiped on stop and restart), so the whole optimization was noise. - Bundles extract into a **fixed dir** (`/workspace/imgiter`, `--strip-components=1`), so the project `.venv` (uv's default location, - created by `uv sync`) and `output/` survive new bundle extracts; re-running + created by `uv sync`) and `untracked/output/` survive new bundle extracts; re-running `scripts/setup-pod.sh` after each extract re-points the editable install (seconds when `uv.lock` is unchanged). This replaces the image's `UV_PROJECT_ENVIRONMENT=/opt/imgiter/.venv` env var, which cannot be @@ -685,8 +685,8 @@ the single-frame smoke list, out of video runs. `flux-schnell` (~34 GB) and keep/clean` still refuse to run without `HF_HOME` set — do not relax that guard just because the local cache now matters. - Local and pod outputs must not share a tree: run tags do not encode the - device, so use `--output-dir` subtrees (`output_` locally vs - `output/pod-*` on the pod). + device, so use `--output-dir` subtrees (`untracked/output_` locally vs + `untracked/output/pod-*` on the pod). - Fixed a pre-existing `scripts/smoke.sh` bug found during local validation: the dltb-iterate artifact check used `frame_${ITERATIONS}.png` but frames are written zero-padded (`frame_0003.png`), so the step could never pass; @@ -715,7 +715,7 @@ frames with DreamSim and reports two distances per frame: - `dreamsim_to_prev` — to the previous analyzed frame: perceptual fixed-point detection. ~0 means the two frames are indistinguishable. -Validated on `output/computer-enhance_sd-turbo/free-running/frames` (200 +Validated on `untracked/output/computer-enhance_sd-turbo/free-running/frames` (200 frames, every 5th, ensemble): `analyze_drift` reported CONVERGED (delta_prev 0.119) with delta_original 97.3/255; DreamSim reported `dreamsim_to_ref` 0.789 (a stable image that is perceptually nothing like the source) and @@ -750,7 +750,7 @@ frames, every 5th, ensemble): `analyze_drift` reported CONVERGED (delta_prev check only looks at extracted checkpoints — so switching `--dreamsim-type` re-downloads the ~1.2 GB zip. Full ensemble cache: 3.8 GB. - Cache default is `--cache-dir untracked/models` (gitignored, cwd-relative). - `untracked/` is **not** packed into pod bundles (tracked files + `input/` + `untracked/` is **not** packed into pod bundles (tracked files + `untracked/input/` only), so a fresh pod re-downloads ~2.7 GB — that is why the smoke leg is gated behind `SMOKE_SIMILARITY=1` and runs on the frames step 2 already produced (no extra model pass). diff --git a/README.md b/README.md index c352a44..b4a0169 100644 --- a/README.md +++ b/README.md @@ -106,7 +106,7 @@ uv run dltb-oneshot --model sd-turbo --input input_example/test_512.png \ download); `scripts/smoke-local.sh` runs a single-frame pass for every model that fits (sd-turbo, sdxl-turbo, flux2-klein-4b) and reports wall clock. - Keep local and pod runs in separate `--output-dir` subtrees (run tags do - not encode the device; `output_` is the local default). + not encode the device; `untracked/output_` is the local default). - If an op is unimplemented on MPS, `PYTORCH_ENABLE_MPS_FALLBACK=1` runs it on CPU (silently slow; use only if an op errors). - MPS is not bit-identical to CUDA: compare frames only within one device. @@ -150,11 +150,11 @@ uv run dltb-klein --input clip.mp4 --conditioning dual-ref \ uv run dltb-iterate --model flux-schnell --input menu.png --offload # Result analysis: pixel drift (CPU-only) and perceptual drift (DreamSim) -uv run python src/dltb/analyze_drift.py output_sd_turbo/menu_free-running/frames -uv run dltb-similarity output_sd_turbo/menu_free-running/frames --every 5 --json sim.json +uv run python src/dltb/analyze_drift.py untracked/output_sd_turbo/menu_free-running/frames +uv run dltb-similarity untracked/output_sd_turbo/menu_free-running/frames --every 5 --json sim.json ``` -Runs land in `output_/_/` (e.g. `menu_free-running/`, +Runs land in `untracked/output_/_/` (e.g. `menu_free-running/`, `clip_stateful-a0.3_tailsfreeze-free-black60/`): the untouched input frame, the saved frames, and the output video(s). @@ -166,7 +166,8 @@ resolution, prompt, save frequency, video FPS, ...). Sample inputs (a test image and a short clip, provenance in `SOURCES.txt`) live in `input_example/`. The tools take any `--input` path, but the sweep and smoke scripts read theirs from a config: copy -`input_example/inputs.env` to `input/inputs.env` (gitignored), point `IMG=` -and `CLIP=` at your files under `input/`, and every script picks them up. +`input_example/inputs.env` to `untracked/input/inputs.env` (gitignored), point +`IMG=` and `CLIP=` at your files under `untracked/input/`, and every script +picks them up. An environment variable (`CLIP=... scripts/sweep.sh`) still wins over the file; see `scripts/inputs.sh`. diff --git a/README_RUNPOD.md b/README_RUNPOD.md index 1356547..36ebfe1 100644 --- a/README_RUNPOD.md +++ b/README_RUNPOD.md @@ -87,7 +87,8 @@ the number of frames, not steps. /workspace <- container disk (ephemeral), 150 GB imgiter/ <- extracted bundle (fixed dir, reused across bundles) .venv/ <- locked deps (scripts/setup-pod.sh; ~7 GB) - output/ <- results, sweep logs + untracked/input/ <- user input files (packed into bundles) + untracked/output/ <- results, sweep logs .cache/huggingface/ <- HF_HOME (base image default) hub/models----/ <- model weights xet/ <- xet chunk cache, hard-capped at 10 GB @@ -97,7 +98,7 @@ the number of frames, not steps. Dependencies live in `/workspace/imgiter/.venv`, created by `scripts/setup-pod.sh` (it installs uv 0.12.13 and provisions CPython 3.13 — `runpod/base` ships neither). The fixed extraction dir keeps `.venv` and -`output/` alive across bundle updates. +`untracked/output/` alive across bundle updates. The image itself does **not** count against the container disk (`df /workspace` showed ~85 MB used next to a 12 GB image). @@ -119,7 +120,7 @@ weights in `untracked/models` when `dltb-similarity` / `SMOKE_SIMILARITY=1` is exercised (not part of bundles, so every fresh pod re-downloads them) — comfortable on the 150 GB disk, and revisiting an earlier model costs no re-download. With -`EVICT_CACHE=1` (keep-one, `input/inputs.env`-configurable) the steady-state +`EVICT_CACHE=1` (keep-one, `untracked/input/inputs.env`-configurable) the steady-state requirement drops to one model (~33 GB max) + xet + outputs ≈ **45 GB**, for smaller container disks. @@ -155,7 +156,7 @@ Bucket = network volume ID; endpoint and region = datacenter. Credentials: ```bash aws s3 cp --recursive \ --region US-KS-2 --endpoint-url https://s3api-us-ks-2.runpod.io/ \ - s3:///output ./output + s3:///untracked/output ./untracked/output ``` ## 3. Pod setup @@ -279,7 +280,7 @@ succeeds. `/start.sh` auto-starts Jupyter Lab on port 8888 (preferred dir `/workspace`, login token = the password) whenever `JUPYTER_PASSWORD` is set in the pod env -— zero image change, and handy for browsing `output/` frames and timelapses +— zero image change, and handy for browsing `untracked/output/` frames and timelapses on a running pod. Verified on a pod 2026-09-13 (NOTES.md). The `imgiter` template wires the variable to the `RUNPOD_SECRET_JUPYTER_PASSWORD` secret. @@ -306,7 +307,7 @@ after the edit. ```bash cd /workspace -mkdir -p imgiter # fixed dir: .venv and output/ survive bundle updates +mkdir -p imgiter # fixed dir: .venv and untracked/output/ survive bundle updates tar xzf imgiter-.tar.gz --strip-components=1 -C imgiter cd imgiter scripts/setup-pod.sh # uv 0.12.13 + uv sync --frozen; re-run after every bundle @@ -330,13 +331,15 @@ scripts/sweep-prompt.sh # free-running prompt (x strength) sweep on one image re-loaded from disk per run. For a 32 GB model that load is ~15–30 s per run, times ~6 runs per model. This is inherent to `sweep.sh`'s per-run invocation. -Inputs: the run scripts read their input files from `input/inputs.env` +Inputs: the run scripts read their input files from `untracked/input/inputs.env` (`IMG=`, `CLIP=`); without one they fall back to the tracked examples in -`input_example/` (provenance in `SOURCES.txt`). Your own files under `input/` -ride in the bundle, so the usual flow is: drop files into `input/`, copy -`input_example/inputs.env` to `input/inputs.env`, point it at them, `just -bundle`, send. A one-off run with a different clip does not need the file: -`CLIP=input/other.mp4 scripts/sweep.sh` (the environment beats the file). +`input_example/` (provenance in `SOURCES.txt`). Your own files under +`untracked/input/` ride in the bundle, so the usual flow is: drop files into +`untracked/input/`, copy `input_example/inputs.env` to +`untracked/input/inputs.env`, point it at them, `just bundle`, send. A one-off +run with a different clip does not need the file: +`CLIP=untracked/input/other.mp4 scripts/sweep.sh` (the environment beats the +file). Smoke test after deploying a new bundle — one tiny run of every tool (`dltb-oneshot`, `dltb-iterate`, `dltb-continuous` both modes + tails, and the @@ -363,7 +366,7 @@ default, or `dual-ref`), `REF_ORDER` (`state-first`, default; dual-ref only), with and without reprojection, the A/B), `BLEND` (default `0.1`), `STEPS` (default "2 8", bracketing the default 4), `OUT_PREFIX` (default none; an extra path component for the per-run dirs, e.g. `statefirst` → -`output//statefirst/prompt-/` — needed for the `REF_ORDER` A/B, +`untracked/output//statefirst/prompt-/` — needed for the `REF_ORDER` A/B, since ref-order is not encoded in the run tag and the two runs would otherwise overwrite each other), plus the shared `CLIP`/`MAX_FRAMES`/`TAIL_FRAMES`/`TAIL_MODES`/`SAVE_EVERY`/`EXTRA_ARGS`/ @@ -390,7 +393,7 @@ DRY_RUN=1 DEBUG=1 scripts/hf-cache.sh keep flux-schnell # preview - With `EVICT_CACHE=1` (off by default — see `input_example/inputs.env`), `sweep.sh` calls `keep ` at the top of every model iteration, so the disk only ever holds the model being swept. All lines are prefixed `hf-cache:` - and go into `output/sweep_*.log`. With the default `EVICT_CACHE=0` the cache + and go into `untracked/output/sweep_*.log`. With the default `EVICT_CACHE=0` the cache keeps every swept model (~87.5 GB for all five, fits the 150 GB disk). - Eviction happens **only at model boundaries**, never between the separate runs of one model — otherwise the same multi-GB weights would be re-downloaded once @@ -412,9 +415,9 @@ disk. ## 6. Getting data in and out - Input files do not need a separate transfer: `just bundle` packs the - gitignored `input/` directory into every bundle (tracked sample inputs live - in `input_example/`). Alternatively `runpodctl send`/`scp` files into - `input/` on the pod after extracting. + gitignored `untracked/input/` directory into every bundle (tracked sample + inputs live in `input_example/`). Alternatively `runpodctl send`/`scp` files + into `untracked/input/` on the pod after extracting. - `scp`/`rsync` work over the direct-SSH mapping from `runpodctl ssh info` (see [SSH access](#3-pod-setup) — register an account key once; rsync measured ~14 MB/s). Use `rsync -rtP` (see §3): re-runs are incremental and @@ -423,7 +426,7 @@ disk. Sync before stopping — the container disk is wiped on stop/restart. - Or `runpodctl send ` locally and `runpodctl receive ` on the pod (install runpodctl there first). -- Outputs live under `output//_/`. +- Outputs live under `untracked/output//_/`. - There is **no S3 path in or out** without a network volume; with volume 0 the only way to retrieve results is from the running pod. diff --git a/input_example/inputs.env b/input_example/inputs.env index 4c6f9a9..d92f99a 100644 --- a/input_example/inputs.env +++ b/input_example/inputs.env @@ -1,12 +1,12 @@ # inputs.env -- default input files for the run scripts # (scripts/sweep.sh, scripts/sweep-klein.sh, scripts/smoke.sh). # -# The scripts source input/inputs.env when it exists, otherwise this file. -# input/ is gitignored, but scripts/bundle.sh packs it into pod bundles, so a -# copy of this file there travels with your runs. +# The scripts source untracked/input/inputs.env when it exists, otherwise this +# file. untracked/input/ is gitignored, but scripts/bundle.sh packs it into +# pod bundles, so a copy of this file there travels with your runs. # # The ${VAR:-...} guards keep one-off environment overrides working: -# CLIP=input/other.mp4 scripts/sweep.sh +# CLIP=untracked/input/other.mp4 scripts/sweep.sh # Plain assignments (CLIP=input/my.mp4) work too, but then the file wins over # the environment for that variable. diff --git a/scripts/bundle.sh b/scripts/bundle.sh index 0cfc763..b4ccbed 100755 --- a/scripts/bundle.sh +++ b/scripts/bundle.sh @@ -35,16 +35,16 @@ bundle_file="${out_dir}/${top}.tar.gz" mkdir -p "${stage}" git ls-files -z | tar --no-xattrs --null -T - -cf - | tar -xf - -C "${stage}" -# User inputs ride along: input/ is gitignored (tracked sample files live in -# input_example/), but pod runs need it -- the one exception to tracked-files- -# only. The untracked-file warning below cannot cover this, because `git -# ls-files --others` never lists ignored paths, so the files are added -# explicitly here. AppleDouble/DS_Store litter is skipped by name; .gitkeep is -# already staged via git ls-files. +# User inputs ride along: untracked/input/ is gitignored (tracked sample files +# live in input_example/), but pod runs need it -- the one exception to +# tracked-files-only. The untracked-file warning below cannot cover this, +# because `git ls-files --others` never lists ignored paths, so the files are +# added explicitly here. AppleDouble/DS_Store litter is skipped by name; +# .gitkeep is already staged via git ls-files. user_inputs=() while IFS= read -r -d '' f; do user_inputs+=("$f") -done < <(find input -type f ! -name '._*' ! -name '.DS_Store' ! -name '.gitkeep' -print0 2>/dev/null) +done < <(find untracked/input -type f ! -name '._*' ! -name '.DS_Store' ! -name '.gitkeep' -print0 2>/dev/null) if [[ ${#user_inputs[@]} -gt 0 ]]; then printf '%s\n' "${user_inputs[@]}" | tar --no-xattrs -T - -cf - | tar -xf - -C "${stage}" printf 'bundle: added user input: %s\n' "${user_inputs[@]}" diff --git a/scripts/inputs.sh b/scripts/inputs.sh index 133a002..32d242d 100755 --- a/scripts/inputs.sh +++ b/scripts/inputs.sh @@ -18,15 +18,16 @@ # smoke.sh): # source scripts/inputs.sh # -# Sources input/inputs.env (user config: KEY=VALUE lines, IMG= and CLIP=) when -# present, otherwise the tracked input_example/inputs.env. input/ is -# gitignored, but scripts/bundle.sh packs it into pod bundles, so user inputs -# travel with the code. +# Sources untracked/input/inputs.env (user config: KEY=VALUE lines, IMG= and +# CLIP=) when present, otherwise the tracked input_example/inputs.env. +# untracked/input/ is gitignored, but scripts/bundle.sh packs it into pod +# bundles, so user inputs travel with the code. # -# Precedence for a variable: environment > input/inputs.env > example -# defaults -- provided the conf file assigns with ${VAR:-value} guards, as -# input_example/inputs.env does. Plain assignments in a user file work too; -# they just make the file win over the environment for that variable. +# Precedence for a variable: environment > untracked/input/inputs.env > +# example defaults -- provided the conf file assigns with ${VAR:-value} +# guards, as input_example/inputs.env does. Plain assignments in a user file +# work too; they just make the file win over the environment for that +# variable. # # Callers still apply their own ${VAR:-...} fallbacks after sourcing, so a # missing conf file only costs the built-in defaults. @@ -40,8 +41,8 @@ if [[ "${DRY_RUN:-0}" != "1" && ! -d .venv ]]; then exit 1 fi -if [[ -f input/inputs.env ]]; then - source input/inputs.env +if [[ -f untracked/input/inputs.env ]]; then + source untracked/input/inputs.env elif [[ -f input_example/inputs.env ]]; then source input_example/inputs.env fi diff --git a/scripts/smoke-local.sh b/scripts/smoke-local.sh index b549fb3..87bdb9e 100755 --- a/scripts/smoke-local.sh +++ b/scripts/smoke-local.sh @@ -44,19 +44,19 @@ # Environment: # MODELS model keys to smoke (default: "sd-turbo sdxl-turbo # flux2-klein-4b") -# IMG input image (default: input/inputs.env if +# IMG input image (default: untracked/input/inputs.env if # present, else the tracked # input_example/test_512.png) # OFFLOAD=1 pass --offload to every run (smaller unified memory) # SKIP_GPU_CHECK=1 bypass the accelerator preflight # -# Log: output/smoke-local_.log +# Log: untracked/output/smoke-local_.log set -euo pipefail cd "$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" -# Input files: env > input/inputs.env (user) > input_example/inputs.env. +# Input files: env > untracked/input/inputs.env (user) > input_example/inputs.env. source scripts/inputs.sh MODELS="${MODELS:-sd-turbo sdxl-turbo flux2-klein-4b}" @@ -72,9 +72,9 @@ if [[ "${SKIP_GPU_CHECK:-0}" != "1" ]]; then fi fi -mkdir -p output -LOG="output/smoke-local_$(date -u +%Y%m%d-%H%M%S).log" -OUT="output/smoke-local" +mkdir -p untracked/output +LOG="untracked/output/smoke-local_$(date -u +%Y%m%d-%H%M%S).log" +OUT="untracked/output/smoke-local" rm -rf "$OUT" mkdir -p "$OUT" diff --git a/scripts/smoke.sh b/scripts/smoke.sh index 8e037de..ce9ee80 100755 --- a/scripts/smoke.sh +++ b/scripts/smoke.sh @@ -15,7 +15,7 @@ # smoke.sh -- post-deploy smoke test: one tiny run of every tool. # # Verifies the console scripts and the cache helper against a real accelerator -# (CUDA or Apple MPS) using the cheapest model, inputs from input/inputs.env +# (CUDA or Apple MPS) using the cheapest model, inputs from untracked/input/inputs.env # (falling back to the tracked input_example/ files), and minimal budgets: # # 0. scripts/hf-cache.sh status (dltb.models import + cache probe) @@ -36,7 +36,7 @@ # because the first call downloads ~2.7 GB # of weights # -# Every step writes under output/smoke/ (wiped at start); the expected +# Every step writes under untracked/output/smoke/ (wiped at start); the expected # artifacts are checked for existence and non-emptiness afterwards. Any # failing step aborts via set -e with its output above it. # @@ -52,7 +52,7 @@ # # Environment: # MODEL model key to smoke (default sd-turbo) -# IMG / CLIP input files (default: input/inputs.env if +# IMG / CLIP input files (default: untracked/input/inputs.env if # present, else the tracked # input_example/ files; see # scripts/inputs.sh) @@ -63,13 +63,13 @@ # KLEIN_MODEL klein model for that leg (default flux2-klein-4b) # SKIP_GPU_CHECK=1 bypass the accelerator preflight # -# Log: output/smoke_.log +# Log: untracked/output/smoke_.log set -euo pipefail cd "$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" -# Input files: env > input/inputs.env (user) > input_example/inputs.env. +# Input files: env > untracked/input/inputs.env (user) > input_example/inputs.env. source scripts/inputs.sh MODEL="${MODEL:-sd-turbo}" @@ -100,9 +100,9 @@ if [[ "${SKIP_GPU_CHECK:-0}" != "1" ]]; then fi fi -mkdir -p output -LOG="output/smoke_$(date -u +%Y%m%d-%H%M%S).log" -OUT="output/smoke" +mkdir -p untracked/output +LOG="untracked/output/smoke_$(date -u +%Y%m%d-%H%M%S).log" +OUT="untracked/output/smoke" rm -rf "$OUT" mkdir -p "$OUT" diff --git a/scripts/sweep-klein-mask.sh b/scripts/sweep-klein-mask.sh index 68a686c..2af869e 100755 --- a/scripts/sweep-klein-mask.sh +++ b/scripts/sweep-klein-mask.sh @@ -30,7 +30,7 @@ # Both legs: --mode stateful --conditioning dual-ref --reproject, identical # prompt/steps/seed/geometry. The fbmask leg runs FIRST so the new variant # is on disk early for mid-sweep inspection. Legs land in separate subtrees -# (output//[/prefix/]mask-ab/{fbmask,plain}/_dualref[-fbmask]_...) +# (untracked/output//[/prefix/]mask-ab/{fbmask,plain}/_dualref[-fbmask]_...) # so nothing collides. # # Usage (from any directory inside the repo): @@ -41,7 +41,7 @@ # # Environment overrides: # MODEL klein model key (default flux2-klein-9b; 4b ungated) -# CLIP source video (default: input/inputs.env if +# CLIP source video (default: untracked/input/inputs.env if # present, else input_example/ # video_cropped.mp4; scripts/inputs.sh) # PROMPT edit prompt (default: role-naming enhance-slight; EMPTY @@ -57,14 +57,14 @@ # DRY_RUN=1 print commands without executing anything # SKIP_GPU_CHECK=1 bypass the accelerator preflight # -# Log: output/sweep_klein_mask_.log +# Log: untracked/output/sweep_klein_mask_.log # Stops at the first failing run (set -euo pipefail). set -euo pipefail cd "$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" -# Input files: env > input/inputs.env (user) > input_example/inputs.env. +# Input files: env > untracked/input/inputs.env (user) > input_example/inputs.env. source scripts/inputs.sh MODEL="${MODEL:-flux2-klein-9b}" @@ -98,7 +98,7 @@ DEFAULT_PROMPT="image ${FRAME_IMG} is the current frame; keep the appearance of PROMPT="${PROMPT-${DEFAULT_PROMPT}}" OUT_PREFIX="${OUT_PREFIX#/}"; OUT_PREFIX="${OUT_PREFIX%/}" -OUT_ROOT="output/$MODEL${OUT_PREFIX:+/$OUT_PREFIX}/mask-ab" +OUT_ROOT="untracked/output/$MODEL${OUT_PREFIX:+/$OUT_PREFIX}/mask-ab" # -------------------------------------------------------------- preflight ---- if [[ "$DRY_RUN" != "1" ]]; then @@ -121,8 +121,8 @@ if [[ "$DRY_RUN" != "1" ]]; then fi fi -mkdir -p output -LOG="output/sweep_klein_mask_$(date -u +%Y%m%d-%H%M%S).log" +mkdir -p untracked/output +LOG="untracked/output/sweep_klein_mask_$(date -u +%Y%m%d-%H%M%S).log" common=(--model "$MODEL" --input "$CLIP" --save-every "$SAVE_EVERY" --mode stateful --conditioning dual-ref --ref-order "$REF_ORDER" diff --git a/scripts/sweep-klein.sh b/scripts/sweep-klein.sh index 908bccd..e184466 100755 --- a/scripts/sweep-klein.sh +++ b/scripts/sweep-klein.sh @@ -52,7 +52,7 @@ # removed 2026-09-13: --guidance-scale > 1 is provably # inert for step-wise distilled klein; see NOTES.md.) # -# Each prompt gets its own --output-dir subtree (output//prompt-/), +# Each prompt gets its own --output-dir subtree (untracked/output//prompt-/), # because dltb-klein's directory tag encodes only mode/blend/tails - without # the subtree, prompt runs would silently overwrite each other. (Dual-ref runs # are tagged ..._dualref[-norepro] instead of ..._stateful-a.) Variants @@ -72,7 +72,7 @@ # # Environment overrides: # MODEL klein model key (default flux2-klein-9b; 4b is ungated) -# CLIP source video (default: input/inputs.env if +# CLIP source video (default: untracked/input/inputs.env if # present, else the tracked # input_example/video_cropped.mp4; # see scripts/inputs.sh) @@ -93,14 +93,14 @@ # STEPS steps-probe values (default "2 8", bracketing the default 4; # empty = skip the probe) # OUT_PREFIX extra path component before the per-run dirs (default -# none; e.g. statefirst -> output//statefirst/ +# none; e.g. statefirst -> untracked/output//statefirst/ # prompt-/). Use it to keep same-tag variants apart, # notably the --ref-order A/B (REF_ORDER is not in the run tag) # EXTRA_ARGS extra flags, word-split, appended to every run # DRY_RUN=1 print commands without executing anything # SKIP_GPU_CHECK=1 bypass the accelerator preflight # -# Log: output/sweep_klein_.log +# Log: untracked/output/sweep_klein_.log # Stops at the first failing run (set -euo pipefail). # # NOTE: unlike scripts/sweep.sh this is single-model, so it does not run the @@ -111,7 +111,7 @@ set -euo pipefail cd "$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" -# Input files: env > input/inputs.env (user) > input_example/inputs.env. +# Input files: env > untracked/input/inputs.env (user) > input_example/inputs.env. source scripts/inputs.sh MODEL="${MODEL:-flux2-klein-9b}" @@ -151,10 +151,10 @@ if [[ "$REPROJECT" == "ab" ]]; then REPROJECT_LIST="1 0"; else REPROJECT_LIST="$ # Extra path component for runs that differ in a knob not encoded in the run # tag (--ref-order), so same-tag variants cannot overwrite each other: -# OUT_PREFIX=statefirst -> output//statefirst/prompt-/ +# OUT_PREFIX=statefirst -> untracked/output//statefirst/prompt-/ # Leading/trailing slashes are tolerated; the default keeps the old layout. OUT_PREFIX="${OUT_PREFIX#/}"; OUT_PREFIX="${OUT_PREFIX%/}" -OUT_ROOT="output/$MODEL${OUT_PREFIX:+/$OUT_PREFIX}" +OUT_ROOT="untracked/output/$MODEL${OUT_PREFIX:+/$OUT_PREFIX}" # ---------------------------------------------------------------- prompts ---- # slug|prompt pairs. The slug becomes the output subdirectory; keep slugs short, @@ -220,8 +220,8 @@ if [[ "$DRY_RUN" != "1" ]]; then fi fi -mkdir -p output -LOG="output/sweep_klein_$(date -u +%Y%m%d-%H%M%S).log" +mkdir -p untracked/output +LOG="untracked/output/sweep_klein_$(date -u +%Y%m%d-%H%M%S).log" # Flags shared by every run. common=(--model "$MODEL" --input "$CLIP" --save-every "$SAVE_EVERY" diff --git a/scripts/sweep-prompt.sh b/scripts/sweep-prompt.sh index 65465e9..b607129 100755 --- a/scripts/sweep-prompt.sh +++ b/scripts/sweep-prompt.sh @@ -36,8 +36,8 @@ # is a constant _free-running, so without subtrees the legs would # silently overwrite each other): # -# output//prompt-/ no strength axis -# output//prompt-/strength/... with the axis +# untracked/output//prompt-/ no strength axis +# untracked/output//prompt-/strength/... with the axis # # Every subtree is complete the moment its run finishes, so partial results # can be copied off the pod while the sweep keeps going. @@ -50,7 +50,7 @@ # # Environment overrides: # MODEL model key (default sd-turbo, cheapest) -# IMG input image (default: input/inputs.env if +# IMG input image (default: untracked/input/inputs.env if # present, else the tracked # input_example/test_512.png; # see scripts/inputs.sh) @@ -65,14 +65,14 @@ # DRY_RUN=1 print commands without executing anything # SKIP_GPU_CHECK=1 bypass the accelerator preflight # -# Log: output/sweep_prompt_.log +# Log: untracked/output/sweep_prompt_.log # Stops at the first failing run (set -euo pipefail). set -euo pipefail cd "$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" -# Input files: env > input/inputs.env (user) > input_example/inputs.env. +# Input files: env > untracked/input/inputs.env (user) > input_example/inputs.env. source scripts/inputs.sh MODEL="${MODEL:-sd-turbo}" @@ -128,8 +128,8 @@ if [[ "$STRENGTH_AXIS" != "1" ]]; then STRENGTHS="" # klein et al.: no --strength semantics; prompts only fi -mkdir -p output -LOG="output/sweep_prompt_$(date -u +%Y%m%d-%H%M%S).log" +mkdir -p untracked/output +LOG="untracked/output/sweep_prompt_$(date -u +%Y%m%d-%H%M%S).log" log() { echo "$@" | tee -a "$LOG"; } @@ -162,7 +162,7 @@ for entry in "${PROMPT_TABLE[@]}"; do for S in ${strengths:-default}; do [[ "$S" == "default" ]] && S="" - out="output/$MODEL/prompt-$slug" + out="untracked/output/$MODEL/prompt-$slug" args=(--model "$MODEL" --input "$IMG" --iterations "$ITERATIONS" --save-every "$SAVE_EVERY" --video-fps "$VIDEO_FPS") if [[ -n "$S" ]]; then diff --git a/scripts/sweep.sh b/scripts/sweep.sh index 01e5d52..f7b9526 100755 --- a/scripts/sweep.sh +++ b/scripts/sweep.sh @@ -36,10 +36,10 @@ # dltb-continuous tags those directories with a -norepro suffix so the two # variants never collide. # -# All runs write under the gitignored output/ tree, using --output-dir: -# output//_/ e.g. video_cropped_stateful-a0.3_tailsfreeze60 -# output//prompt/... semantic-anchor variant -# output//strength/... strength variant +# All runs write under the gitignored untracked/output/ tree, using --output-dir: +# untracked/output//_/ e.g. video_cropped_stateful-a0.3_tailsfreeze60 +# untracked/output//prompt/... semantic-anchor variant +# untracked/output//strength/... strength variant # dltb-continuous's directory tag encodes only mode/blend/tails, so the prompt # and strength runs get their own --output-dir subtrees; without that they # would silently overwrite the baseline run's frames and videos. @@ -55,7 +55,7 @@ # MODELS="sd-turbo" MAX_FRAMES=20 TAIL_FRAMES=5 scripts/sweep.sh # smoke test # # Environment overrides: -# CLIP source video (default: input/inputs.env if +# CLIP source video (default: untracked/input/inputs.env if # present, else the tracked # input_example/video_cropped.mp4; # see scripts/inputs.sh) @@ -79,14 +79,14 @@ # DRY_RUN=1 print commands without executing anything # SKIP_GPU_CHECK=1 bypass the accelerator preflight # -# Log: output/sweep_.log (config header + all run output). +# Log: untracked/output/sweep_.log (config header + all run output). # Stops at the first failing run (set -euo pipefail). set -euo pipefail cd "$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" -# Input files: env > input/inputs.env (user) > input_example/inputs.env. +# Input files: env > untracked/input/inputs.env (user) > input_example/inputs.env. source scripts/inputs.sh CLIP="${CLIP:-input_example/video_cropped.mp4}" @@ -136,8 +136,8 @@ if [[ "$DRY_RUN" != "1" ]]; then fi fi -mkdir -p output -LOG="output/sweep_$(date -u +%Y%m%d-%H%M%S).log" +mkdir -p untracked/output +LOG="untracked/output/sweep_$(date -u +%Y%m%d-%H%M%S).log" # Flags shared by every run. Arrays are expanded with the ${arr[@]+...} form so # an empty array is safe under `set -u` on bash 3.2 (macOS). @@ -192,7 +192,7 @@ for MODEL in $MODELS; do log "sweep: cache eviction off (EVICT_CACHE=0) -- swept models stay cached" fi - out_base="output/$MODEL" + out_base="untracked/output/$MODEL" # 1. Boil test: every frame processed independently (no carried state). # No tail -- tail phases use the stateful blend semantics. diff --git a/src/dltb/analyze_drift.py b/src/dltb/analyze_drift.py index 5acdf9a..03f6817 100644 --- a/src/dltb/analyze_drift.py +++ b/src/dltb/analyze_drift.py @@ -12,8 +12,8 @@ For each frame it computes two mean-absolute-pixel-difference metrics (0-255 sca input image. Slope = drift rate; plateau = bounded change. Usage: - python analyze_drift.py output_sdxl_turbo/free-running/frames - python analyze_drift.py output_flux_schnell/free-running/frames --every 1 + python analyze_drift.py untracked/output_sdxl_turbo/free-running/frames + python analyze_drift.py untracked/output_flux_schnell/free-running/frames --every 1 Outputs drift_metrics.csv next to the frames dir and prints a summary. """ diff --git a/src/dltb/analyze_similarity.py b/src/dltb/analyze_similarity.py index ebbab37..7c43cff 100644 --- a/src/dltb/analyze_similarity.py +++ b/src/dltb/analyze_similarity.py @@ -38,9 +38,9 @@ but the package only checks for extracted checkpoint files, so switching --dreamsim-type re-downloads the ~1.2 GB zip. Usage: - uv run dltb-similarity output_sd_turbo/free-running/frames - uv run dltb-similarity output/.../frames --every 2 --dreamsim-type clip_vitb32 - uv run dltb-similarity output/.../frames --reference input/test_512.png --json sim.json + uv run dltb-similarity untracked/output_sd_turbo/free-running/frames + uv run dltb-similarity untracked/output/.../frames --every 2 --dreamsim-type clip_vitb32 + uv run dltb-similarity untracked/output/.../frames --reference untracked/input/test_512.png --json sim.json Outputs similarity_metrics.csv next to the frames dir and prints a summary. diff --git a/src/dltb/args.py b/src/dltb/args.py index 6d0c9a9..189081d 100644 --- a/src/dltb/args.py +++ b/src/dltb/args.py @@ -74,7 +74,7 @@ def add_device_arg(p: argparse.ArgumentParser) -> None: def add_output_args(p: argparse.ArgumentParser) -> None: """Output location, compute-backend selection, and device placement.""" p.add_argument("--output-dir", default=None, - help="Output directory (default: output_)") + help="Output directory (default: untracked/output_)") add_device_arg(p) p.add_argument("--offload", action="store_true", help="CPU model offloading for smaller accelerators (slower)") diff --git a/src/dltb/assemble.py b/src/dltb/assemble.py index d3e8c0b..3d71aee 100644 --- a/src/dltb/assemble.py +++ b/src/dltb/assemble.py @@ -38,8 +38,8 @@ stride is printed per video; pass a proportionally lower --fps (e.g. --fps 3 for stride 10 saved from 30 fps source) for real-time pacing. Example: - uv run dltb-assemble output_flux2_klein_4b/ --fps 30 - uv run dltb-assemble output_sdxl_turbo//frames --fps 12 --every 2 + uv run dltb-assemble untracked/output_flux2_klein_4b/ --fps 30 + uv run dltb-assemble untracked/output_sdxl_turbo//frames --fps 12 --every 2 python3 src/dltb/assemble.py --fps 24 # no install """ diff --git a/src/dltb/output.py b/src/dltb/output.py index 40cb682..6b31f4e 100644 --- a/src/dltb/output.py +++ b/src/dltb/output.py @@ -11,11 +11,11 @@ """Output-directory layout, input-type sniffing, and timelapse assembly. -All tools write runs under output_/ (or an explicit --output-dir) in -one subdirectory per run, tagged so that different configurations never -collide: +All tools write runs under untracked/output_/ (or an explicit +--output-dir) in one subdirectory per run, tagged so that different +configurations never collide: - output_/_/frames/frame_NNNN.png + untracked/output_/_/frames/frame_NNNN.png """ from __future__ import annotations @@ -31,8 +31,8 @@ def is_video(path: str | Path) -> bool: def run_dir(output_dir: str | None, model: str, tag: str) -> Path: - """Create and return >/.""" - base = Path(output_dir or f"output_{model.replace('-', '_')}") + """Create and return >/.""" + base = Path(output_dir or f"untracked/output_{model.replace('-', '_')}") d = base / tag d.mkdir(parents=True, exist_ok=True) return d diff --git a/input/.gitkeep b/untracked/input/.gitkeep similarity index 100% rename from input/.gitkeep rename to untracked/input/.gitkeep