ApacheOne's picture
Upload Wan Animate-2 OrbitQuant packed W4A4 model
f2c0505 verified
Raw
History Blame Contribute Delete
2.84 kB
from __future__ import annotations
import re
_BLOCK_RE = re.compile(r"^(blocks\.\d+)\.(?!block\.)")
def _insert_block_wrapper(key: str) -> str:
if key.startswith("blocks.") and ".block." not in key:
return _BLOCK_RE.sub(r"\1.block.", key, count=1)
return key
def _remove_block_wrapper(key: str) -> str:
if key.startswith("blocks."):
return key.replace(".block.", ".", 1)
return key
def diffusers_to_official_key(key: str) -> str:
"""Map WanAnimate2 Diffusers/refactor keyspace to Wan-Video/Wan-Animate-2 keyspace.
OrbitQuant Project-A was repaired into the current Diffusers WanAnimate2 keyspace:
blocks.0.self_attn.to_q.weight
The official Wan-Animate-2 repo uses:
blocks.0.block.self_attn.q.weight
"""
k = key
if k.startswith("model.diffusion_model."):
k = k[len("model.diffusion_model.") :]
# Only attention projection names differ. FFN names stay ffn.0 / ffn.2.
replacements = (
(".self_attn.to_out.0.", ".self_attn.o."),
(".cross_attn.to_out.0.", ".cross_attn.o."),
(".self_attn.to_q.", ".self_attn.q."),
(".self_attn.to_k.", ".self_attn.k."),
(".self_attn.to_v.", ".self_attn.v."),
(".cross_attn.to_q.", ".cross_attn.q."),
(".cross_attn.to_k.", ".cross_attn.k."),
(".cross_attn.to_v.", ".cross_attn.v."),
(".cross_attn.add_k_proj.", ".cross_attn.k_img."),
(".cross_attn.add_v_proj.", ".cross_attn.v_img."),
(".cross_attn.norm_added_k.", ".cross_attn.norm_k_img."),
)
for old, new in replacements:
k = k.replace(old, new)
return _insert_block_wrapper(k)
def official_to_diffusers_key(key: str) -> str:
"""Inverse of diffusers_to_official_key for Wan-Animate-2 transformer keys."""
k = _remove_block_wrapper(key)
replacements = (
(".self_attn.o.", ".self_attn.to_out.0."),
(".cross_attn.o.", ".cross_attn.to_out.0."),
(".self_attn.q.", ".self_attn.to_q."),
(".self_attn.k.", ".self_attn.to_k."),
(".self_attn.v.", ".self_attn.to_v."),
(".cross_attn.q.", ".cross_attn.to_q."),
(".cross_attn.k.", ".cross_attn.to_k."),
(".cross_attn.v.", ".cross_attn.to_v."),
(".cross_attn.k_img.", ".cross_attn.add_k_proj."),
(".cross_attn.v_img.", ".cross_attn.add_v_proj."),
(".cross_attn.norm_k_img.", ".cross_attn.norm_added_k."),
)
for old, new in replacements:
k = k.replace(old, new)
return k
def target_key_for_module(module_name: str, keyspace: str = "official") -> str:
key = f"{module_name}.weight" if module_name else "weight"
if keyspace == "official":
return key
if keyspace == "diffusers":
return official_to_diffusers_key(key)
raise ValueError(f"Unsupported keyspace: {keyspace}")