ApacheOne's picture
Upload Wan Animate-2 OrbitQuant packed W4A4 model
f2c0505 verified
Raw
History Blame Contribute Delete
5.3 kB
from __future__ import annotations
import json
import os
from pathlib import Path
import shutil
import subprocess
import sys
import site
ROOT = Path(__file__).resolve().parents[1]
PINS = json.loads((ROOT / "source_pins.json").read_text())
CONTENT = Path("/content")
def run(cmd, *, cwd=None):
print("+", " ".join(map(str, cmd)), flush=True)
subprocess.run(list(map(str, cmd)), cwd=cwd, check=True)
def clone_at(name: str, destination: Path):
spec = PINS[name]
sha = spec["commit"]
if destination.exists():
shutil.rmtree(destination)
run(["git", "init", "-q", destination])
run(["git", "-C", destination, "remote", "add", "origin", spec["url"]])
run(["git", "-C", destination, "fetch", "-q", "--depth=1", "origin", sha])
run(["git", "-C", destination, "checkout", "-q", "FETCH_HEAD"])
got = subprocess.check_output(["git", "-C", destination, "rev-parse", "HEAD"], text=True).strip()
if got != sha:
raise RuntimeError(f"{name} pin mismatch: expected {sha}, got {got}")
print(f"✓ {name} {got}")
def version_tuple(text: str):
base = text.split("+")[0].split("rc")[0]
vals = []
for x in base.split(".")[:3]:
try:
vals.append(int(x))
except Exception:
vals.append(0)
return tuple(vals + [0] * (3 - len(vals)))
def main():
import torch
print("Torch:", torch.__version__)
print("CUDA :", torch.version.cuda)
if version_tuple(torch.__version__) < (2, 10, 0):
raise RuntimeError(
"Sol-Attn's pinned sol-engine backend requires PyTorch >= 2.10. "
"Use a Colab runtime with Torch 2.10+ rather than silently replacing the CUDA stack here."
)
if not torch.cuda.is_available():
raise RuntimeError("CUDA GPU is required")
if torch.version.cuda is None or version_tuple(torch.version.cuda) < (12, 8, 0):
raise RuntimeError(
f"Pinned Sol-Attn requires CUDA >= 12.8; current Torch CUDA runtime is {torch.version.cuda!r}. "
"Use a newer Colab GPU runtime instead of silently replacing PyTorch/CUDA."
)
cc = torch.cuda.get_device_capability()
print("GPU :", torch.cuda.get_device_name())
print("CC :", cc)
if cc[0] < 8:
raise RuntimeError("Sol-Attn supports NVIDIA SM80+ in this package")
# Install runtime Python dependencies without replacing PyTorch.
deps = [
"triton>=3.6", "safetensors==0.7.0", "numpy>=1.26", "PyYAML", "easydict",
"huggingface_hub==0.36.0", "transformers==4.57.6", "accelerate==1.13.0",
"diffusers==0.36.0", "imageio", "imageio-ffmpeg", "decord", "opencv-python-headless",
"moviepy", "loguru", "einops", "tqdm", "psutil", "omegaconf", "addict", "ftfy",
"scipy", "sentencepiece", "protobuf", "packaging", "pillow"
]
run([sys.executable, "-m", "pip", "install", "-q", "-U", *deps])
wan = CONTENT / "Wan-Animate-2"
sana = CONTENT / "Sana-sol-engine"
para = CONTENT / "ParaAttention"
clone_at("Wan-Video/Wan-Animate-2", wan)
clone_at("NVlabs/Sana", sana)
clone_at("chengzeyi/ParaAttention", para)
# Verify the exact upstream Animate-2 distilled contract we patch into.
import yaml
source_cfg = yaml.safe_load((wan / "infer" / "wan_animate_2_distillation.yaml").read_text())
tr = source_cfg["model"]["transformer"]
expected = {
"in_dim": 36,
"dim": 5120,
"ffn_dim": 13824,
"num_heads": 40,
"num_layers": 40,
"log_scale": -1.3,
}
for key, value in expected.items():
if tr.get(key) != value:
raise RuntimeError(f"official Animate-2 source contract changed: {key}={tr.get(key)!r}, expected {value!r}")
if source_cfg["model"].get("flow_solver") != "euler" or float(source_cfg["test_cfg"].get("sample_shift")) != 5.0:
raise RuntimeError("official distilled Euler/shift-5 contract changed")
print("✓ official Animate-2 architecture + distilled Euler contract")
# These integrations are pure Python/Triton at runtime. Put the exact
# checked-out source directories on sys.path via one .pth file instead of
# invoking setuptools-scm/editable builds that can drift or pull deps.
paths = [
str(ROOT),
str(wan),
str(sana / "techniques" / "sparse_backends"),
str(para / "src"),
]
site_dir = Path(site.getsitepackages()[0])
pth = site_dir / "orbitquant_wan_a2_third_party.pth"
pth.write_text("\n".join(paths) + "\n")
for path in reversed(paths):
if path not in sys.path:
sys.path.insert(0, path)
# Import gates catch namespace/path mistakes immediately.
import orbitquant_wan_a2 # noqa: F401
from sol_attn import sol_attn # noqa: F401
import para_attn.primitives # noqa: F401
from wanxiang.models.wan_animate_2_model import WanAnimate2Transformer # noqa: F401
print("\nBOOTSTRAP PASS")
print(" official source :", wan)
print(" Sol-Attn :", sana / "techniques" / "sparse_backends")
print(" ParaAttention :", para)
print(" runtime package :", ROOT)
print(" path file :", pth)
print("\nNext: python", ROOT / "scripts" / "kernel_selftest.py")
if __name__ == "__main__":
main()