maliang / scripts /bench_fast704.py
teawhite's picture
Add files using upload-large-folder tool
51ac7cc verified
Raw History Blame Contribute Delete
6 kB
#!/usr/bin/env python3
"""部署加速引擎(ref/gc25d-live-demo 的 FastStream:静态 KV 环形缓冲 + torch.compile + CUDA graph)在 480p / 704p 下的
每格耗时。耗时与权重数值无关,所以直接用包里的 v8 DMD 权重(ids 版 GcDiT):只换 lat_hw / 滑窗长度 / 去噪步数。
稳态 = 缓存已满(n = cap):每格 = 历史 K 旋转 1 次 + N 趟去噪 + 1 趟提交,另测 TAEHV 解 1 格(4 帧)。
不含:语义条件嵌入(每格 1 次,很小)、文本 K/V(按 prompt 缓存,换按键组合那格多 6–7 ms)、代码世界、网络。
只 import 包里的代码(PYTHONPATH 只放包,见 usage),不碰 maliang 的 gc25d。
usage:
R=ref/gc25d-live-demo; CUDA_VISIBLE_DEVICES=7 PYTHONPATH=$R/code/gc25d:$R/code/arope:$R/code/diffsynth_src AROPE_ROOT=$R/code/arope \
TAEHV_DIR=$R/code/taehv DIFFSYNTH_SKIP_DOWNLOAD=True TMPDIR=.tmp TORCHINDUCTOR_CACHE_DIR=.tmp/inductor TRITON_CACHE_DIR=.tmp/triton \
.venv/bin/python scripts/bench_fast704.py --out outputs/bench_fast/run.json"""
import argparse
import json
import os
import statistics
import subprocess
import time
import torch
from codeworld.fast_live import FastStream
from codeworld.live import TinyStreamVAE, empty_wan_dit
from gcdistill.gc_dit import GcDiT, load_gc_ckpt
M = "/opt/dlami/nvme/zhiyangdeng/maliang"
R = f"{M}/ref/gc25d-live-demo"
RES = {"480p": (30, 52), "704p": (44, 80)} # 832×480 / 1280×704 的 latent 网格(VAE ×16)
T_GRID = (1000.0, 750.0, 500.0, 250.0)
def gpu_apps():
"""本卡上的计算进程(判断测的时候有没有别的进程在抢卡)。"""
try:
idx = os.environ.get("CUDA_VISIBLE_DEVICES", "0").split(",")[0]
q = subprocess.run(["nvidia-smi", "-i", idx, "--query-compute-apps=pid,used_memory", "--format=csv,noheader"],
capture_output=True, text=True, timeout=30).stdout.strip()
return [ln for ln in q.splitlines() if ln and str(os.getpid()) not in ln]
except Exception as e: # noqa: BLE001
return [f"nvidia-smi failed: {e}"]
def cell_ms(fs, x, steps, n_cells):
out = []
for _ in range(n_cells):
torch.cuda.synchronize()
t0 = time.perf_counter()
fs._rotate()
for t in T_GRID[:steps]:
fs.forward(x, t, False)
fs.forward(x, 0.0, True)
torch.cuda.synchronize()
out.append((time.perf_counter() - t0) * 1e3)
return out
def summ(v):
v = sorted(v)
return {"median": round(statistics.median(v), 1), "p90": round(v[int(0.9 * (len(v) - 1))], 1), "min": round(v[0], 1),
"n": len(v)}
def main():
ap = argparse.ArgumentParser()
ap.add_argument("--ckpt", default=f"{R}/weights/gc25d_v8_dmd_ema500.safetensors")
ap.add_argument("--tae", default=f"{R}/weights/taew2_2_super.pth")
ap.add_argument("--configs", default="480p:17:4,704p:17:4,704p:17:3,704p:11:4,704p:11:3",
help="res:window:steps,逗号分隔;sink 固定 3")
ap.add_argument("--cells", type=int, default=30)
ap.add_argument("--out", required=True)
a = ap.parse_args()
dev = "cuda"
rep = {"gpu": torch.cuda.get_device_name(0), "others_on_gpu_before": gpu_apps(), "configs": {}, "taehv": {}}
print(rep, flush=True)
model = GcDiT(dit=empty_wan_dit(), causal=True).to(dev).eval().requires_grad_(False)
model.move_rope_table(dev)
load_gc_ckpt(model, a.ckpt)
model.to(torch.bfloat16)
g = torch.Generator(device=dev).manual_seed(0)
fs_cache = {}
for spec in a.configs.split(","):
res, win, steps = spec.split(":")
win, steps = int(win), int(steps)
key = (res, win)
if key not in fs_cache:
fs_cache.clear()
torch.cuda.empty_cache()
t0 = time.time()
fs = FastStream(model, kv_window=win, sink_size=3, rope_cap=3 + win, lat_hw=RES[res], graphs=True, compile=True)
fs.ktxt.normal_(generator=g).mul_(0.5)
fs.vtxt.normal_(generator=g).mul_(0.5)
fs.order, fs.n = list(range(fs.cap)), fs.cap # 稳态:缓存已满(之后每格提交驱逐最老的非 sink 格)
fs.pos.copy_(torch.arange(fs.cap, device=dev))
fs.kraw.normal_(generator=g).mul_(0.5)
fs.vbuf.normal_(generator=g).mul_(0.5)
x = torch.randn(1, 48, 1, *RES[res], generator=g, device=dev, dtype=torch.bfloat16)
cell_ms(fs, x, 4, 3) # 编译 + 录 graph((cap, 不提交) / (cap, 提交))
fs_cache[key] = (fs, x)
print(f"[{res} w{win}] build+compile+capture {time.time() - t0:.1f}s bufs {fs.nbytes() / 2**30:.2f} GiB", flush=True)
fs, x = fs_cache[key]
cell_ms(fs, x, steps, 3)
v = cell_ms(fs, x, steps, a.cells)
rep["configs"][spec] = {**summ(v), "tokens_per_cell": fs.hw, "kv_cells": fs.cap,
"mem_reserved_GiB": round(torch.cuda.memory_reserved() / 2**30, 1)}
print(spec, rep["configs"][spec], flush=True)
fs_cache.clear()
torch.cuda.empty_cache()
vae = TinyStreamVAE(a.tae, dev)
for res, hw in RES.items():
vae.reset()
z = torch.randn(1, 48, 1, *hw, generator=g, device=dev, dtype=torch.bfloat16)
for _ in range(4):
vae.decode_one(z)
v = []
for _ in range(a.cells):
torch.cuda.synchronize()
t0 = time.perf_counter()
fr = vae.decode_one(z)
torch.cuda.synchronize()
v.append((time.perf_counter() - t0) * 1e3)
rep["taehv"][res] = {**summ(v), "frames": list(fr.shape)}
print("taehv", res, rep["taehv"][res], flush=True)
rep["others_on_gpu_after"] = gpu_apps()
os.makedirs(os.path.dirname(os.path.abspath(a.out)), exist_ok=True)
json.dump(rep, open(a.out, "w"), indent=1)
print(json.dumps(rep, indent=1))
if __name__ == "__main__":
main()