diff --git a/NOTES.md b/NOTES.md index 4828bf4..71679d8 100644 --- a/NOTES.md +++ b/NOTES.md @@ -149,6 +149,10 @@ cross-model comparison. No conclusion yet on whether the model is suitable at all, or whether a different conditioning/topology is needed (`flux2-klein-9b` is a reference-image editor: no `--strength`, full 4-step regeneration). +2026-09-21: that topology redesign is now in the tree as `dltb-klein` + +`scripts/sweep-klein.sh` (prompt-as-strength ladder, guidance probes). The +pre-restructure scripts they were derived from live under `reference/`. + Preview settings for reference: stateful, `--reproject`, `--max-frames 30 --tail-frames 10 --tail-modes freeze`. diff --git a/README.md b/README.md index 951457d..4bb540f 100644 --- a/README.md +++ b/README.md @@ -24,6 +24,12 @@ Three scripts share the library code in `src/dltb/` (`models`, `imaging`, state blended into each new frame (`--mode stateful`, optical-flow reprojection on by default), plus failure tails that branch from the shared end-of-video state (`--tail-modes freeze,free,black`). +- `dltb-klein` — the same video loop, restricted to the FLUX.2 klein editors + (`flux2-klein-4b`, ungated, default / `flux2-klein-9b`, gated). Klein is a + reference-image editor: no `--strength`, per-pass change scales ~linearly + with the blend (default `0.1`, far below the img2img models), and the prompt + is the de-facto per-pass edit-strength knob. `scripts/sweep-klein.sh` walks + its prompt ladder and `--guidance-scale` probes. ## Models @@ -67,6 +73,10 @@ uv run dltb-iterate --model sd-turbo --input menu.png --iterations 200 uv run dltb-continuous --model flux-schnell --input clip.mp4 --mode stateful \ --anchor-blend 0.3 --max-frames 300 --tail-frames 60 --tail-modes freeze,free,black +# Klein editors: prompt is the per-pass edit-strength knob +uv run dltb-klein --input clip.mp4 --prompt "slightly enhance the fine details" \ + --tail-frames 60 --tail-modes freeze + # FLUX.1-schnell, CPU-offloaded to fit a 24 GB card uv run dltb-iterate --model flux-schnell --input menu.png --offload ``` diff --git a/README_RUNPOD.md b/README_RUNPOD.md index 9aabcf8..0f34636 100644 --- a/README_RUNPOD.md +++ b/README_RUNPOD.md @@ -200,6 +200,7 @@ cd imgiter- uv sync --frozen # re-points the editable install from /opt/imgiter to this tree scripts/sweep.sh # full sweep; add OFFLOAD=1 on <48 GB GPUs for the big models +scripts/sweep-klein.sh # klein prompt ladder + guidance probes (single model) ``` - Dependencies are baked into the image at `/opt/imgiter/.venv` @@ -228,6 +229,12 @@ Useful `sweep.sh` env overrides: `MODELS`, `BLENDS`, `BASELINE`, `MAX_FRAMES`, `TAIL_FRAMES`, `SAVE_EVERY`, `STRENGTH`, `STRENGTH_MODELS`, `DESC`, `OFFLOAD`, `REPROJECT`, `CLIP`, `EXTRA_ARGS`, `DRY_RUN`, `SKIP_GPU_CHECK`. +Klein regime (`scripts/sweep-klein.sh`, drives `dltb-klein`): `MODEL` +(default `flux2-klein-9b`; `4b` is ungated), `BLEND` (default `0.1`), +`GUIDANCES` (default "2.0 4.0"), plus the shared `CLIP`/`MAX_FRAMES`/ +`TAIL_FRAMES`/`TAIL_MODES`/`SAVE_EVERY`/`EXTRA_ARGS`/`DRY_RUN`/ +`SKIP_GPU_CHECK`. Single-model, so no hf-cache eviction between runs. + ## 5. Model cache management `scripts/hf-cache.sh`: diff --git a/pyproject.toml b/pyproject.toml index 4ad7e46..9e6e99c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -25,6 +25,7 @@ dependencies = [ dltb-oneshot = "dltb.oneshot:main" dltb-iterate = "dltb.iterate:main" dltb-continuous = "dltb.continuous:main" +dltb-klein = "dltb.klein:main" [build-system] requires = ["uv_build>=0.12.7,<0.13.0"] diff --git a/scripts/bundle.sh b/scripts/bundle.sh index dc99408..063f587 100755 --- a/scripts/bundle.sh +++ b/scripts/bundle.sh @@ -38,7 +38,7 @@ git ls-files -z | tar --no-xattrs --null -T - -cf - | tar -xf - -C "${stage}" # Guard against staging something broken. for f in pyproject.toml uv.lock \ src/dltb/models.py src/dltb/imaging.py src/dltb/output.py src/dltb/args.py \ - src/dltb/oneshot.py src/dltb/iterate.py src/dltb/continuous.py; do + src/dltb/oneshot.py src/dltb/iterate.py src/dltb/continuous.py src/dltb/klein.py; do [[ -f "${stage}/$f" ]] || { echo "bundle: missing $f" >&2; exit 1; } done diff --git a/scripts/image-build.sh b/scripts/image-build.sh index f5ebbee..3f72477 100755 --- a/scripts/image-build.sh +++ b/scripts/image-build.sh @@ -35,7 +35,7 @@ cp image/Dockerfile "${stage}/Dockerfile" # Guard against building something broken. for f in pyproject.toml uv.lock \ src/dltb/models.py src/dltb/imaging.py src/dltb/output.py src/dltb/args.py \ - src/dltb/oneshot.py src/dltb/iterate.py src/dltb/continuous.py \ + src/dltb/oneshot.py src/dltb/iterate.py src/dltb/continuous.py src/dltb/klein.py \ Dockerfile; do [[ -f "${stage}/$f" ]] || { echo "image-build: missing $f" >&2; exit 1; } done diff --git a/scripts/sweep-klein.sh b/scripts/sweep-klein.sh new file mode 100755 index 0000000..2345005 --- /dev/null +++ b/scripts/sweep-klein.sh @@ -0,0 +1,160 @@ +#!/usr/bin/env bash +# +# sweep-klein.sh -- prompt-ladder sweep for FLUX.2 klein (editing-model regime). +# Drives dltb-klein (the klein-restricted dltb-continuous). +# +# Klein is a reference-image EDITOR: it regenerates from pure noise attending to +# pristine reference tokens, ignores --strength, and is trained to preserve +# everything the prompt does not target. Per-pass change therefore scales with +# the blend alpha (~linear, no constant rewrite bias like the img2img models), +# and the PROMPT is the de-facto per-pass edit-strength knob. +# +# What this sweep runs (all --mode stateful, one source pass per prompt): +# +# 1. Prompt ladder : neutral -> slight -> photo -> dramatic enhancement, +# i.e. rising per-pass edit intensity. The freeze tail +# shows whether the edit keeps compounding on static +# input (the generative-ratchet / static-menu case). +# 2. Semantic attractor : a THEMATIC instruction (weathering). If klein works +# as trained, the loop converges toward "maximally +# weathered" instead of melting - directed attractor +# vs. undirected collapse. +# 3. Guidance probes : the mild prompt at --guidance-scale 2.0 / 4.0. +# Experimental: klein's guidance is an embedded +# conditioning signal (card default 1.0); higher values +# may strengthen prompt adherence per pass. +# +# Each prompt gets its own --output-dir subtree (output//prompt-/), +# because dltb-klein's directory tag encodes only mode/blend/tails - without +# the subtree, prompt runs would silently overwrite each other. +# +# Usage (from any directory inside the repo): +# scripts/sweep-klein.sh +# DRY_RUN=1 scripts/sweep-klein.sh +# MODEL=flux2-klein-4b BLEND=0.2 scripts/sweep-klein.sh +# +# Environment overrides: +# MODEL klein model key (default flux2-klein-9b; 4b is ungated) +# CLIP source video (default input/video_cropped.mp4) +# BLEND anchor-blend for all runs (default 0.1 - klein's active range +# is far below the img2img models; try 0.03 0.05 0.2 manually) +# MAX_FRAMES source frames per run (default 300; empty = whole clip) +# TAIL_FRAMES frames per tail (default 60; 0 = no tails) +# TAIL_MODES tail scenario list (default freeze; "freeze,free" etc.) +# SAVE_EVERY save every Nth frame (default 10) +# GUIDANCES guidance probe values (default "2.0 4.0"; empty = skip) +# EXTRA_ARGS extra flags, word-split, appended to every run +# DRY_RUN=1 print commands without executing anything +# SKIP_GPU_CHECK=1 bypass the CUDA preflight +# +# Log: 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 +# hf-cache keep-one eviction -- if it follows a multi-model sweep, the disk +# briefly holds two models (still well within the 150 GB pod disk). + +set -euo pipefail + +cd "$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" + +MODEL="${MODEL:-flux2-klein-9b}" +CLIP="${CLIP:-input/video_cropped.mp4}" +BLEND="${BLEND:-0.1}" +MAX_FRAMES="${MAX_FRAMES-300}" +TAIL_FRAMES="${TAIL_FRAMES:-60}" +TAIL_MODES="${TAIL_MODES:-freeze}" +SAVE_EVERY="${SAVE_EVERY:-10}" +GUIDANCES="${GUIDANCES-2.0 4.0}" +EXTRA_ARGS="${EXTRA_ARGS:-}" +DRY_RUN="${DRY_RUN:-0}" + +# ---------------------------------------------------------------- prompts ---- +# slug|prompt pairs. The slug becomes the output subdirectory; keep slugs short, +# lowercase, hyphenated. Empty prompt = preservation baseline (no flag passed). +PROMPT_TABLE=( + "neutral|" + "enhance-slight|slightly enhance the fine details" + "enhance-photo|enhance details and lighting, make it photorealistic" + "enhance-dramatic|dramatically enhance every texture and surface detail" + "weathering|add more weathering, moss and water stains to the stone" +) + +# Guidance probes reuse the mild-enhancement prompt. +GUIDANCE_SLUG="enhance-slight" +GUIDANCE_PROMPT="slightly enhance the fine details" + +# -------------------------------------------------------------- preflight ---- +if [[ "$DRY_RUN" != "1" ]]; then + [[ -f "$CLIP" ]] || { echo "sweep-klein: clip not found: $CLIP" >&2; exit 1; } + command -v uv >/dev/null || { echo "sweep-klein: 'uv' not on PATH" >&2; exit 1; } + + if [[ "$MODEL" == "flux2-klein-9b" && -z "${HF_TOKEN:-}" ]]; then + echo "sweep-klein: HF_TOKEN is not set (required for flux2-klein-9b)." >&2 + echo " Accept the license at https://huggingface.co/black-forest-labs/FLUX.2-klein-9B" >&2 + echo " then: export HF_TOKEN=hf_... and re-run." >&2 + exit 1 + fi + + if [[ "${SKIP_GPU_CHECK:-0}" != "1" ]]; then + if ! uv run python -c 'import sys, torch; sys.exit(0 if torch.cuda.is_available() else 1)'; then + echo "sweep-klein: torch reports no CUDA device -- run this on a GPU pod" >&2 + echo " (SKIP_GPU_CHECK=1 to bypass, DRY_RUN=1 to preview)." >&2 + exit 1 + fi + fi +fi + +mkdir -p output +LOG="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" + --mode stateful --anchor-blend "$BLEND") +if [[ -n "$MAX_FRAMES" ]]; then common+=(--max-frames "$MAX_FRAMES"); fi +if [[ "$TAIL_FRAMES" -gt 0 ]]; then + common+=(--tail-frames "$TAIL_FRAMES" --tail-modes "$TAIL_MODES") +fi + +log() { echo "$@" | tee -a "$LOG"; } + +run() { + log "" + log "== $(date -u +%Y-%m-%dT%H:%M:%SZ) dltb-klein $*" + if [[ "$DRY_RUN" == "1" ]]; then + log "DRY RUN" + return 0 + fi + uv run dltb-klein "$@" 2>&1 | tee -a "$LOG" +} + +log "sweep-klein: model=$MODEL clip=$CLIP blend=$BLEND" +log "sweep-klein: max_frames=${MAX_FRAMES:-} tail=${TAIL_FRAMES}x${TAIL_MODES} guidances='${GUIDANCES:-}'" +log "sweep-klein: log=$LOG" + +# ------------------------------------------------------- 1+2. prompt ladder ---- +for entry in "${PROMPT_TABLE[@]}"; do + slug="${entry%%|*}" + prompt="${entry#*|}" + + args=(${common[@]+"${common[@]}"} --output-dir "output/$MODEL/prompt-$slug") + if [[ -n "$prompt" ]]; then args+=(--prompt "$prompt"); fi + + log "" + log "########## prompt '$slug': ${prompt:-} ##########" + run "${args[@]}" ${EXTRA_ARGS:+$EXTRA_ARGS} +done + +# ------------------------------------------------------- 3. guidance probe ---- +if [[ -n "${GUIDANCES:-}" ]]; then + for G in $GUIDANCES; do + log "" + log "########## guidance probe: '$GUIDANCE_SLUG' @ guidance=$G ##########" + run ${common[@]+"${common[@]}"} \ + --prompt "$GUIDANCE_PROMPT" --guidance-scale "$G" \ + --output-dir "output/$MODEL/guidance$G" ${EXTRA_ARGS:+$EXTRA_ARGS} + done +fi + +log "" +log "sweep-klein: done -- log: $LOG" diff --git a/src/dltb/__init__.py b/src/dltb/__init__.py index 7842ec9..6ede318 100644 --- a/src/dltb/__init__.py +++ b/src/dltb/__init__.py @@ -12,4 +12,6 @@ Tools (installed as console scripts; see pyproject.toml): dltb-oneshot single image, single model pass (the anchored fixed point) dltb-iterate free-running image self-iteration + mp4 timelapse dltb-continuous video pipeline simulation (anchored/stateful, tails) + dltb-klein the continuous loop restricted to the FLUX.2 klein editors + (no --strength; prompt = per-pass edit strength) """ diff --git a/src/dltb/args.py b/src/dltb/args.py index 227a0d1..6438c31 100644 --- a/src/dltb/args.py +++ b/src/dltb/args.py @@ -1,18 +1,10 @@ -# Permission to use, copy, modify, and/or distribute this software for -# any purpose with or without fee is hereby granted. -# -# THE SOFTWARE IS PROVIDED “AS IS” AND THE AUTHOR DISCLAIMS ALL -# WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES -# OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE -# FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY -# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN -# AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT -# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -"""argparse flag groups shared by every dltb-* tool. +"""argparse flag groups shared by the dltb-* tools. Tool-specific flags (--input, --iterations, --mode, tails, ...) are added by each tool on top of these; help texts here apply verbatim everywhere. +dltb-klein composes the same groups but swaps in its own --model (restricted +to the klein pair, with a default), which is why model selection lives in +its own adder. """ from __future__ import annotations @@ -22,21 +14,32 @@ import argparse from .models import MODELS, model_key -def add_common_args(p: argparse.ArgumentParser) -> None: - """Model selection, per-pass inference, geometry, seeding, offloading.""" +def add_model_args(p: argparse.ArgumentParser) -> None: + """--model over the full table (required).""" p.add_argument("--model", required=True, type=model_key, choices=sorted(MODELS), help="Which model to run") - p.add_argument("--output-dir", default=None, - help="Output directory (default: output_)") + + +def add_pass_args(p: argparse.ArgumentParser) -> None: + """Per-pass inference settings.""" p.add_argument("--strength", type=float, default=0.4, help="img2img denoising strength per pass (sd/sdxl-turbo and " "flux-schnell only). Keep num_inference_steps * strength >= 1.") p.add_argument("--num-inference-steps", type=int, default=4, help="Denoise schedule length (all models distilled for 1-4 steps)") + p.add_argument("--guidance-scale", type=float, default=None, + help="Override the model's default guidance scale. Experimental: " + "klein takes guidance as an embedded conditioning signal " + "(card default 1.0), so raising it may strengthen prompt " + "adherence per pass.") p.add_argument("--prompt", default="", help="Optional text prompt. A faithful description acts as a " "semantic anchor (analogue of DLSS 5's artistic-direction " "conditioning).") + + +def add_geometry_args(p: argparse.ArgumentParser) -> None: + """Output geometry and seeding.""" p.add_argument("--width", type=int, default=None, help="Output width (multiple of 16; frames center-cropped to this " "aspect, then resized)") @@ -46,5 +49,19 @@ def add_common_args(p: argparse.ArgumentParser) -> None: p.add_argument("--fixed-seed", action=argparse.BooleanOptionalAction, default=True, help="Same noise every pass/frame (deterministic, DLSS 5-like). " "--no-fixed-seed draws fresh noise per pass/frame.") + + +def add_output_args(p: argparse.ArgumentParser) -> None: + """Output location and device placement.""" + p.add_argument("--output-dir", default=None, + help="Output directory (default: output_)") p.add_argument("--offload", action="store_true", help="CPU model offloading for smaller GPUs (slower)") + + +def add_common_args(p: argparse.ArgumentParser) -> None: + """Model selection, per-pass inference, geometry, seeding, offloading.""" + add_model_args(p) + add_pass_args(p) + add_geometry_args(p) + add_output_args(p) diff --git a/src/dltb/continuous.py b/src/dltb/continuous.py index 1ed2c37..fd55063 100644 --- a/src/dltb/continuous.py +++ b/src/dltb/continuous.py @@ -162,7 +162,8 @@ def run(args: argparse.Namespace) -> None: settings = PassSettings(prompt=args.prompt, num_inference_steps=args.num_inference_steps, - strength=args.strength) + strength=args.strength, + guidance_scale=args.guidance_scale) current = None # previous PROCESSED frame (carried state) prev_source = None # previous SOURCE frame (for flow estimation) diff --git a/src/dltb/imaging.py b/src/dltb/imaging.py index 9af6c10..f1c3f0f 100644 --- a/src/dltb/imaging.py +++ b/src/dltb/imaging.py @@ -27,6 +27,7 @@ class PassSettings: prompt: str = "" num_inference_steps: int = 4 strength: float = 0.4 + guidance_scale: float | None = None # None -> the model's default def make_generator(seed: int, fixed_seed: bool, i: int = 0): @@ -47,7 +48,8 @@ def run_pass(pipe, spec, settings: PassSettings, source, generator, prompt=settings.prompt, image=source, num_inference_steps=settings.num_inference_steps, - guidance_scale=spec.guidance_scale, + guidance_scale=(settings.guidance_scale if settings.guidance_scale is not None + else spec.guidance_scale), generator=generator, output_type="pil", ) diff --git a/src/dltb/iterate.py b/src/dltb/iterate.py index d68545e..1c829a7 100644 --- a/src/dltb/iterate.py +++ b/src/dltb/iterate.py @@ -80,7 +80,8 @@ def run(args: argparse.Namespace) -> None: pipe = load_pipeline(spec, args.offload) settings = PassSettings(prompt=args.prompt, num_inference_steps=args.num_inference_steps, - strength=args.strength) + strength=args.strength, + guidance_scale=args.guidance_scale) from PIL import Image original = prepare_frame(Image.open(args.input), width, height) diff --git a/src/dltb/klein.py b/src/dltb/klein.py new file mode 100644 index 0000000..9f84bd8 --- /dev/null +++ b/src/dltb/klein.py @@ -0,0 +1,97 @@ +"""dltb-klein: video pipeline simulation with the FLUX.2 klein editors. + +Klein (FLUX.2-klein-4B / -9B) is a reference-image EDITOR, not a partial-noise +img2img model: it regenerates from pure noise attending to pristine reference +tokens, so there is NO --strength, and per-pass change scales with the blend +alpha (roughly linear -- no constant rewrite bias like sd/sdxl-turbo and +flux-schnell). Consequences for the loop: + + --anchor-blend klein's active range is far below the img2img models + (default here 0.1; try 0.03 / 0.05 / 0.2) + --prompt the de-facto per-pass edit-strength knob: an empty or + neutral prompt preserves, an edit instruction compounds + every pass (scripts/sweep-klein.sh walks that ladder) + --guidance-scale klein takes guidance as an embedded conditioning signal + (model card default 1.0); raising it may strengthen prompt + adherence per pass. Experimental. + +This runs the same loop topologies as dltb-continuous (anchored boil test / +stateful blend with optical-flow reprojection / failure tails), restricted to +the klein pair, with the klein-appropriate blend default. It shares +continuous.run() -- only argument defaults and model choice differ. + +Refinement idea: pass [P_{n-1}, N] as two separate reference images instead +of pixel-blending. + +Example: + uv run dltb-klein --model flux2-klein-4b --input clip.mp4 \\ + --prompt "slightly enhance the fine details" \\ + --tail-frames 60 --tail-modes freeze +""" + +from __future__ import annotations + +import argparse + +from .args import add_geometry_args, add_output_args, add_pass_args +from .continuous import _parse_tail_modes, run as run_continuous +from .models import model_key + +KLEIN_MODELS = ("flux2-klein-4b", "flux2-klein-9b") + + +def parse_args(argv: list[str] | None = None) -> argparse.Namespace: + p = argparse.ArgumentParser( + description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter + ) + p.add_argument("--model", type=model_key, choices=KLEIN_MODELS, + default="flux2-klein-4b", + help="Klein model to run (4b: Apache-2.0, ungated; 9b: FLUX " + "Non-Commercial, gated -- accept the license and set HF_TOKEN)") + add_pass_args(p) + add_geometry_args(p) + add_output_args(p) + p.add_argument("--input", required=True, + help="Input video (mp4/mov/mkv/webm/avi)") + p.add_argument("--mode", choices=["anchored", "stateful"], default="stateful", + help="Loop topology (see module docstring). anchored = " + "independent per-frame boil test; stateful = carried " + "state blended with each new frame.") + p.add_argument("--anchor-blend", type=float, default=0.1, + help="stateful mode: weight alpha of the fresh frame in the blend " + "(1-a)*previous_output + a*new_frame. Klein's active range " + "is far below the img2img models (try 0.03/0.05/0.2); " + "0.0 = free-running, 1.0 = fully re-anchored every frame") + p.add_argument("--reproject", action=argparse.BooleanOptionalAction, default=True, + help="stateful mode only: warp the carried state by optical flow " + "estimated between consecutive source frames before blending " + "(emulates engine motion vectors; needs opencv-python-headless). " + "--no-reproject gives the naive history blend (ghosting).") + p.add_argument("--max-frames", type=int, default=None, + help="Stop after this many SOURCE frames (tail phases, if " + "any, come after)") + p.add_argument("--tail-frames", type=int, default=0, + help="Generate this many extra frames per tail mode after " + "the source video ends") + p.add_argument("--tail-modes", type=_parse_tail_modes, default=_parse_tail_modes("freeze"), + help="comma-separated list of tail scenarios, each branching from " + "the same end-of-video state: freeze (re-submit last frame), " + "free (anchor dropped), black (black frames)") + p.add_argument("--save-every", type=int, default=10, + help="Also save every Nth processed frame as PNG (10 keeps disk " + "usage sane on video runs)") + return p.parse_args(argv) + + +def run(args: argparse.Namespace) -> None: + # Identical loop to dltb-continuous; only the argument surface above + # differs (model restriction, klein blend default, guidance emphasis). + run_continuous(args) + + +def main(argv: list[str] | None = None) -> None: + run(parse_args(argv)) + + +if __name__ == "__main__": + main() diff --git a/src/dltb/oneshot.py b/src/dltb/oneshot.py index b3c1ec7..bd01125 100644 --- a/src/dltb/oneshot.py +++ b/src/dltb/oneshot.py @@ -69,7 +69,8 @@ def run(args: argparse.Namespace) -> None: settings = PassSettings(prompt=args.prompt, num_inference_steps=args.num_inference_steps, - strength=args.strength) + strength=args.strength, + guidance_scale=args.guidance_scale) result = run_pass(pipe, spec, settings, source, make_generator(args.seed, args.fixed_seed), width, height) result_path = frames_dir / "frame_0001.png"