Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
|
@@ -407,6 +407,60 @@ def status() -> str:
|
|
| 407 |
f"conditioner `{CONDITIONER_SPACE}`"
|
| 408 |
)
|
| 409 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 410 |
|
| 411 |
def load_models() -> str | None:
|
| 412 |
"""Load the denoising half at startup, plus FILM.
|
|
@@ -437,10 +491,12 @@ def load_models() -> str | None:
|
|
| 437 |
if CUSTOM_TRANSFORMER_REPO:
|
| 438 |
# `load_config` fetches only `transformer/config.json` (a few KB) — not the 61.7 GiB of weights
|
| 439 |
# `load_components` would otherwise pull from MODEL_REPO. Constructed on `torch.device("meta")` so
|
| 440 |
-
# the architecture exists with no real memory behind it
|
| 441 |
-
#
|
|
|
|
|
|
|
| 442 |
from huggingface_hub import hf_hub_download
|
| 443 |
-
from safetensors
|
| 444 |
|
| 445 |
from diffusers.models import MiniMaxH3Transformer3DModel
|
| 446 |
|
|
@@ -449,8 +505,13 @@ def load_models() -> str | None:
|
|
| 449 |
)
|
| 450 |
with torch.device("meta"):
|
| 451 |
custom_transformer = MiniMaxH3Transformer3DModel.from_config(config)
|
|
|
|
|
|
|
| 452 |
custom_path = hf_hub_download(CUSTOM_TRANSFORMER_REPO, CUSTOM_TRANSFORMER_FILE)
|
| 453 |
-
|
|
|
|
|
|
|
|
|
|
| 454 |
pipe.update_components(transformer=custom_transformer)
|
| 455 |
print(f"[gen] transformer replaced with {CUSTOM_TRANSFORMER_REPO}/{CUSTOM_TRANSFORMER_FILE}", flush=True)
|
| 456 |
|
|
|
|
| 407 |
f"conditioner `{CONDITIONER_SPACE}`"
|
| 408 |
)
|
| 409 |
|
| 410 |
+
def _convert_full_checkpoint(raw: dict, base_shapes: dict) -> dict:
|
| 411 |
+
"""Rename a `diffusion_model.blocks.*`-family (original-checkpoint) full transformer state dict onto
|
| 412 |
+
`MiniMaxH3Transformer3DModel`'s (`transformer_blocks.*`) naming — the full-weight sibling of
|
| 413 |
+
`_convert_diffusion_model_lora`'s renaming: no A/B factors, no network_alphas, no fc1 swap, just every real
|
| 414 |
+
weight tensor renamed (and, for the fused `qkv_proj`, split) onto its diffusers-side target. `base_shapes` is
|
| 415 |
+
the target model's own shapes — safe to read straight off a `torch.device("meta")`-constructed instance,
|
| 416 |
+
since shape is metadata, not data, and costs nothing to have before any real weights are loaded.
|
| 417 |
+
"""
|
| 418 |
+
out: dict = {}
|
| 419 |
+
|
| 420 |
+
def rename_base(name: str) -> str:
|
| 421 |
+
if name.startswith("token_refiner.blocks."):
|
| 422 |
+
name = "token_refiner.refiner_blocks." + name[len("token_refiner.blocks."):]
|
| 423 |
+
elif name.startswith("blocks."):
|
| 424 |
+
name = "transformer_blocks." + name[len("blocks."):]
|
| 425 |
+
name = name.replace("final_layer.adaln_proj.linear", "norm_out.linear")
|
| 426 |
+
name = name.replace("final_layer.norm", "norm_out.norm")
|
| 427 |
+
name = name.replace("final_layer.video_out", "proj_out")
|
| 428 |
+
name = name.replace("final_layer.audio_out", "audio_proj_out")
|
| 429 |
+
name = name.replace(".attn.out_proj", ".attn.to_out.0")
|
| 430 |
+
name = name.replace(".attn.q_norm", ".attn.norm_q")
|
| 431 |
+
name = name.replace(".attn.k_norm", ".attn.norm_k")
|
| 432 |
+
name = name.replace(".mlp.fc2", ".ff.net.2")
|
| 433 |
+
name = name.replace(".mlp.fc1", ".ff.net.0.proj")
|
| 434 |
+
name = name.replace("video_patch_proj", "proj_in")
|
| 435 |
+
name = name.replace("audio_patch_proj", "audio_proj_in")
|
| 436 |
+
name = name.replace("condition_proj", "context_embedder")
|
| 437 |
+
name = name.replace("time_embedder.proj_in", "time_embedder.linear_1")
|
| 438 |
+
name = name.replace("time_embedder.proj_out", "time_embedder.linear_2")
|
| 439 |
+
return name
|
| 440 |
+
|
| 441 |
+
for key, tensor in raw.items():
|
| 442 |
+
if key == "rope.inv_freq":
|
| 443 |
+
# A registered buffer computed from `rope_theta`/`rope_freq_dim` at construction, never loaded —
|
| 444 |
+
# its presence here isn't a sign anything else is wrong.
|
| 445 |
+
continue
|
| 446 |
+
|
| 447 |
+
if key.endswith(".attn.qkv_proj.weight"):
|
| 448 |
+
prefix = key[: -len(".attn.qkv_proj.weight")]
|
| 449 |
+
renamed_prefix = rename_base(prefix)
|
| 450 |
+
q_out = base_shapes[f"{renamed_prefix}.attn.to_q.weight"][0]
|
| 451 |
+
k_out = base_shapes[f"{renamed_prefix}.attn.to_k.weight"][0]
|
| 452 |
+
v_out = base_shapes[f"{renamed_prefix}.attn.to_v.weight"][0]
|
| 453 |
+
assert tensor.shape[0] == q_out + k_out + v_out, (
|
| 454 |
+
f"{key}: expected {q_out + k_out + v_out} rows (q{q_out}+k{k_out}+v{v_out}), got {tensor.shape[0]}"
|
| 455 |
+
)
|
| 456 |
+
out[f"{renamed_prefix}.attn.to_q.weight"] = tensor[:q_out].clone()
|
| 457 |
+
out[f"{renamed_prefix}.attn.to_k.weight"] = tensor[q_out:q_out + k_out].clone()
|
| 458 |
+
out[f"{renamed_prefix}.attn.to_v.weight"] = tensor[q_out + k_out:].clone()
|
| 459 |
+
continue
|
| 460 |
+
|
| 461 |
+
out[rename_base(key)] = tensor
|
| 462 |
+
|
| 463 |
+
return out
|
| 464 |
|
| 465 |
def load_models() -> str | None:
|
| 466 |
"""Load the denoising half at startup, plus FILM.
|
|
|
|
| 491 |
if CUSTOM_TRANSFORMER_REPO:
|
| 492 |
# `load_config` fetches only `transformer/config.json` (a few KB) — not the 61.7 GiB of weights
|
| 493 |
# `load_components` would otherwise pull from MODEL_REPO. Constructed on `torch.device("meta")` so
|
| 494 |
+
# the architecture exists with no real memory behind it; `base_shapes` is read off that meta
|
| 495 |
+
# instance (shape is metadata, not data) purely so `_convert_full_checkpoint` knows the real
|
| 496 |
+
# to_q/to_k/to_v split points before any real weights exist. `load_state_dict(assign=True)`
|
| 497 |
+
# materializes real tensors straight from the converted dict — the only real allocation here.
|
| 498 |
from huggingface_hub import hf_hub_download
|
| 499 |
+
from safetensors import safe_open
|
| 500 |
|
| 501 |
from diffusers.models import MiniMaxH3Transformer3DModel
|
| 502 |
|
|
|
|
| 505 |
)
|
| 506 |
with torch.device("meta"):
|
| 507 |
custom_transformer = MiniMaxH3Transformer3DModel.from_config(config)
|
| 508 |
+
base_shapes = {k: tuple(v.shape) for k, v in custom_transformer.state_dict().items()}
|
| 509 |
+
|
| 510 |
custom_path = hf_hub_download(CUSTOM_TRANSFORMER_REPO, CUSTOM_TRANSFORMER_FILE)
|
| 511 |
+
with safe_open(custom_path, framework="pt") as handle:
|
| 512 |
+
raw = {k: handle.get_tensor(k) for k in handle.keys()}
|
| 513 |
+
converted = _convert_full_checkpoint(raw, base_shapes)
|
| 514 |
+
custom_transformer.load_state_dict(converted, strict=True, assign=True)
|
| 515 |
pipe.update_components(transformer=custom_transformer)
|
| 516 |
print(f"[gen] transformer replaced with {CUSTOM_TRANSFORMER_REPO}/{CUSTOM_TRANSFORMER_FILE}", flush=True)
|
| 517 |
|