Review follow-ups on the video inference backend:
- validate_load_request now rejects a -GGUF repo picked as a diffusers
pipeline (no gguf_filename) up front, instead of failing minutes later
in from_pretrained after the GPU owner was already evicted.
- New _detect_load_family helper shared by validate_load_request and
_run_load: when the repo id alone does not carry the family, fall back
to detecting it from the picked GGUF filename, so both paths agree.
- routes/video.py now threads base_repo into validate_load_request so an
untrusted companion repo is refused before the arbiter handoff.
- unload() now drains _generate_lock before _teardown_state so a
cancelled clip actually exits the denoise loop before the VRAM is
reported free.
- load_pipeline re-checks the load token after the generate-lock barrier
and raises if the load was superseded while waiting.
- Pre-commit global mutations (backend flags, gguf compile installs) are
registered per load token and rolled back in _run_load's error path
via _rollback_precommit_globals, so a failed load no longer leaks
process-wide state.
- fp32 memory estimates now apply a 2x dtype scale on non-CPU devices
for pipeline, single-file and companion sizes (bf16 tables assume
2 bytes/param); GGUF quant estimates stay unscaled.
Tests: GGUF-repo-as-pipeline rejection, _detect_load_family fallback and
override semantics; fake route backend accepts base_repo. 66 passed
across test_video_backend, test_video_routes, test_video_families,
test_video_gallery.
The latent cache holds two fp32 posterior tensors per crop/flip variant per
image, pinned on CUDA hosts, so datasets with thousands of images can exhaust
host or pinned memory with no fallback. Estimate the cache size from the first
real encoded latent and fall back to per-step VAE encoding when it exceeds a
4 GiB budget. UNSLOTH_DIFFUSION_FORCE_LATENT_CACHE bypasses the gate; the
existing UNSLOTH_DIFFUSION_NO_LATENT_CACHE opt-out is unchanged.
Replace the with-replacement per-batch index draw in the SDXL and DiT LoRA
trainers with a shared PermutationBatchSampler that visits every image once per
cycle before repeating, so short runs cover the whole dataset. The sampler
reshuffles from the run's rng so the index stream stays seed-deterministic.
Guard the diffusion run detail route against a valid-JSON non-object record,
which previously raised TypeError and returned a 500; it now 404s like the list
path's shape check.
Add regression tests for both.
The latest huggingface-hub release added the Sandboxes feature. Its
bootstrap (_sandbox.py) fetches the static sbx-server binary into /tmp with
an Authorization header and marks it executable, which is exactly the
staged-dropper pattern the scanner hunts, and three while True polling loops
in _sandbox.py / hf_api.py / utils/_http.py match the beaconing heuristic.
All four verified against the official huggingface/huggingface_hub
repository: the snippet is the documented sandbox server injection and the
loops are deadline-style job and sandbox polling. Entries generated with
--write-baseline and reviewed line by line; scan_packages.py huggingface-hub
now exits 0 with the four findings suppressed.
The load tail re-ran the already-filtered speed_optims tuple through
.items() as if it were still the raw applied dict from apply_speed_optims.
An empty tuple short-circuited to {} so CPU test runs passed, but on a real
GPU at least channels_last engages, the tuple is truthy, and every load
failed with 'tuple' object has no attribute 'items'. Store the filtered
tuple directly and add a regression test that forces one optimisation to
engage.
The run detail route built DiffusionTrainingRunDetail(**rec) unguarded, so a
valid-JSON-but-wrong-shape record (hand-edited or an older schema) would 500
instead of reading as absent. Catch ValidationError and 404, matching how the
list route skips malformed records.
tokenizer/chat_template.jinja ships as its own file in the LTX-2 and
HunyuanVideo-1.5 repos and apply_chat_template reads it at generation
time, so a scoped snapshot without it loads fine and then crashes the
first generation.
A dual-DiT pipeline (Ideogram 4's unconditional tower) placed its second
denoiser resident under the group tier, which defeats the tier since the
pair rarely fits where one alone did not. Stream transformer_2 and
unconditional_transformer alongside the transformer and keep only the
smaller companions resident.
The perf rewrite dropped the bf16 capability guard, so a pre-Ampere CUDA
device (T4/V100/RTX 20xx) would die deep in model load with an opaque dtype
error instead of a clear message. Restores parity with the SDXL trainer.
A warm-cache predownload sweep never consults the cancel event (each cached
file returns instantly), so an unload during it was ignored until a cold
file hit the network. The 2.3 detection also only probed bare-file local
repos; resolve directory repos through the same child resolver the loader
uses so their base pull is scoped too.