dagloop5 commited on
Commit
ac4ddbb
·
verified ·
1 Parent(s): 740923d

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +65 -4
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, then `load_state_dict(assign=True)`
441
- # materializes real tensors straight from the finetune's own file the only real allocation here.
 
 
442
  from huggingface_hub import hf_hub_download
443
- from safetensors.torch import load_file
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
- custom_transformer.load_state_dict(load_file(custom_path), strict=True, assign=True)
 
 
 
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