default_video_generation_params fell back to a hardcoded LTX 40/4.0 when no identifier matched.
A Wan model loaded from an opaque local path under an explicit family_override (none of
gguf_filename / repo_id / base_repo carrying a wan token) then ran 40/4.0 instead of Wan's 50/5.0.
Add a fallback param and pass the resolved family's own default_steps/default_guidance from both
call sites, so the fallback tracks the actual family.
Verified against diffusers 0.39 source + the HF configs/safetensors headers:
- The Wan VAE decodes in float32 (WanPipeline loads AutoencoderKLWan at torch.float32
while the pipe runs bf16); the loader cast every component to bf16, degrading every
clip. Add vae_force_fp32 (both Wan families) and pin pipe.vae back to fp32 after build.
- The Wan transformers ship FP32 on disk (safetensors headers are F32; A14B index =
57.15 GB per expert = 14.3B x 4, TI2V = 20.0 GB = 5B x 4), so bf16_components_gb held
the fp32 on-disk sums (114.3 / 20.0) instead of the documented bf16-resident sizes.
Halve to 57.2 (two A14B experts) and 10.0 (TI2V), so the plan no longer over-budgets
the DiTs ~2x and forces needless offload on an 80 GB GPU.
- TI2V-5B's VAE is 16x spatial (vae/config.json), so WanPipeline floors H/W to 16*2 = 32.
Snap TI2V to /32 (was /16) so the recorded size matches the generated clip (a 720
request was recorded but rendered at 704). A14B keeps /16 (Wan2.1 8x VAE).
apply_step_cache on the video load path omitted quant_active, so a quantized video
transformer (an engaged dense transformer_quant, or a GGUF checkpoint) that also
enabled First-Block-Cache without an explicit threshold used the dense bf16 threshold
(0.08) instead of the higher quantized threshold (0.12) the cache helper documents as
needed for quantized transformers to trigger. The advertised quant plus FBCache path
therefore cached far less than intended. Thread quant_active through exactly as the
image path (diffusion.py) does: an engaged transformer_quant or a GGUF transformer both
count as quant-active here.
Ideogram 4 assembles two DiTs per-component (a conditional transformer plus a
separate unconditional_transformer), so there is no transformer-only single-file
or GGUF artifact that could supply both. Add a pipeline_only family flag and
reject the gguf/single_file kinds in validate_load_request, before a load evicts
the current model, instead of assembling a pipeline missing its second DiT.
Extend the fp8 bf16-resident size override to a LOCAL directory mirror of the
ideogram-4-fp8 base: such a path never string-matches base_repo, so detect the
fp8 layout from the transformer shard headers (a *.weight_scale marker) and
reserve the bf16 footprint, matching the remote-base behaviour. A local nf4
mirror has no fp8 scales and correctly stays planned against its compressed bytes.
After the upstream cascade generalised _apply_group_offload to stream every
DiT it finds on the pipe (transformer AND transformer_2), apply_memory_plan's
group tier already block-streams both A14B experts, and model/sequential
offload hook every top-level module. The explicit per-expert pass this branch
added is therefore redundant: on a real group-tier load it re-registers the
group-offload hooks transformer_2 already carries, which diffusers rejects with
a duplicate-hook ValueError. That was swallowed by the helper's try/except and
surfaced as a misleading "second expert stays resident" warning even though the
expert was in fact streamed. Remove the pass and document why MoE needs none.
A successful on-demand wheel install writes into site-packages after the
import system already cached that directory's listing, so the very next
find_spec / import in the same process can miss the freshly installed
package when the install lands within the directory mtime's resolution.
That silently falls set_attention_backend back to native on first use.
Call importlib.invalidate_caches() after a successful install so the
kernel is picked up immediately, and cover both the success and failure
paths in the attention installer tests.