exp4: decode timers + H3_PROFILE profiler hook
Browse files
app.py
CHANGED
|
@@ -139,6 +139,8 @@ VSA_BLOCKS = 0
|
|
| 139 |
VSA_GATES = 0
|
| 140 |
# Wall seconds of the last request's transformer forwards (reset by every `_generate` call).
|
| 141 |
FORWARD_TIMES: list[float] = []
|
|
|
|
|
|
|
| 142 |
|
| 143 |
|
| 144 |
def status() -> str:
|
|
@@ -203,13 +205,8 @@ def load_models() -> str | None:
|
|
| 203 |
else:
|
| 204 |
pipe.transformer.set_attention_backend(ATTENTION)
|
| 205 |
|
| 206 |
-
# The video VAE ships fp32 (`_keep_in_fp32_modules` over every module); decode it in bf16 instead —
|
| 207 |
-
# half the decode FLOPs and traffic on Blackwell. The audio VAE keeps its fp32 modules: a bf16
|
| 208 |
-
# audio VAE decodes the soundtrack roughly 20 dB too quiet (see the module docstring).
|
| 209 |
-
pipe.vae.to(torch.bfloat16)
|
| 210 |
-
print(f"[gen] video VAE cast to {next(pipe.vae.parameters()).dtype}", flush=True)
|
| 211 |
-
|
| 212 |
_install_forward_timing(pipe)
|
|
|
|
| 213 |
|
| 214 |
if PLACEMENT == "offload":
|
| 215 |
manager.enable_auto_cpu_offload(device="cuda")
|
|
@@ -227,6 +224,27 @@ def load_models() -> str | None:
|
|
| 227 |
return LOAD_ERROR
|
| 228 |
|
| 229 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 230 |
def _install_forward_timing(pipe) -> None:
|
| 231 |
"""Record the wall time of every transformer forward, so each request can report where its seconds went.
|
| 232 |
|
|
@@ -335,21 +353,49 @@ def _generate(prompt_embeds, text_token_tags, height: int, width: int, num_frame
|
|
| 335 |
|
| 336 |
torch.cuda.reset_peak_memory_stats()
|
| 337 |
FORWARD_TIMES.clear()
|
|
|
|
| 338 |
started = time.perf_counter()
|
| 339 |
-
|
| 340 |
-
|
| 341 |
-
|
| 342 |
-
|
| 343 |
-
|
| 344 |
-
|
| 345 |
-
|
| 346 |
-
|
| 347 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 348 |
gen_s = time.perf_counter() - started
|
| 349 |
peak_gib = torch.cuda.max_memory_allocated() / 1024**3
|
| 350 |
forwards = [round(t, 2) for t in FORWARD_TIMES]
|
| 351 |
-
|
| 352 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 353 |
|
| 354 |
|
| 355 |
@spaces.GPU(duration=120, size=GPU_SIZE)
|
|
@@ -462,7 +508,7 @@ def generate(
|
|
| 462 |
refined = plan.get("refined_prompt") or ""
|
| 463 |
|
| 464 |
progress(0.2, desc=f"{NUM_FORWARDS} transformer forwards at {width}x{height}, {num_frames} frames ...")
|
| 465 |
-
frames, audio, sampling_rate, gen_s, peak_gib, forwards = _generate(
|
| 466 |
prompt_embeds, text_token_tags, height, width, num_frames, seed
|
| 467 |
)
|
| 468 |
|
|
@@ -474,10 +520,11 @@ def generate(
|
|
| 474 |
|
| 475 |
forward_total = sum(forwards) if forwards else float("nan")
|
| 476 |
forward_detail = "+".join(f"{t:.1f}" for t in forwards) if forwards else "n/a"
|
|
|
|
| 477 |
report = (
|
| 478 |
f"`{width}x{height}`, {num_frames} frames @ {FPS} fps, {NUM_FORWARDS} transformer forwards · "
|
| 479 |
-
f"pipeline **{gen_s:.1f}s** (forwards {forward_detail} = {forward_total:.1f}s,
|
| 480 |
-
f"{gen_s - forward_total:.1f}s) · peak {peak_gib:.1f} GiB · "
|
| 481 |
f"conditioner {condition_seconds:.0f}s ({plan['num_text_tokens']} tokens"
|
| 482 |
f"{', rewritten' if refined else ''}) · seed {int(seed)} · req {request_id}"
|
| 483 |
)
|
|
|
|
| 139 |
VSA_GATES = 0
|
| 140 |
# Wall seconds of the last request's transformer forwards (reset by every `_generate` call).
|
| 141 |
FORWARD_TIMES: list[float] = []
|
| 142 |
+
# Wall seconds of the last request's two VAE decodes, appended by the wrappers `_arm_decode_timers` arms.
|
| 143 |
+
DECODE_TIMES: dict[str, float] = {}
|
| 144 |
|
| 145 |
|
| 146 |
def status() -> str:
|
|
|
|
| 205 |
else:
|
| 206 |
pipe.transformer.set_attention_backend(ATTENTION)
|
| 207 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 208 |
_install_forward_timing(pipe)
|
| 209 |
+
_arm_decode_timers(pipe)
|
| 210 |
|
| 211 |
if PLACEMENT == "offload":
|
| 212 |
manager.enable_auto_cpu_offload(device="cuda")
|
|
|
|
| 224 |
return LOAD_ERROR
|
| 225 |
|
| 226 |
|
| 227 |
+
def _arm_decode_timers(pipe) -> None:
|
| 228 |
+
"""Time each VAE's `decode` call, so a request can report the video/audio decode split.
|
| 229 |
+
|
| 230 |
+
Instance-attribute wrapper, like `_arm_decode_hooks`; only meaningful with `PLACEMENT=lazy` (no offload hook in
|
| 231 |
+
front). The video VAE decode runs tiled under fp16 autocast over fp32 weights inside the pipeline's decode
|
| 232 |
+
block; this just measures it.
|
| 233 |
+
"""
|
| 234 |
+
for name in ("vae", "audio_vae"):
|
| 235 |
+
module = getattr(pipe, name)
|
| 236 |
+
inner = module.decode
|
| 237 |
+
|
| 238 |
+
def timed(*args, _name=name, _decode=inner, **kwargs):
|
| 239 |
+
started = time.perf_counter()
|
| 240 |
+
try:
|
| 241 |
+
return _decode(*args, **kwargs)
|
| 242 |
+
finally:
|
| 243 |
+
DECODE_TIMES[_name] = DECODE_TIMES.get(_name, 0.0) + time.perf_counter() - started
|
| 244 |
+
|
| 245 |
+
module.decode = timed
|
| 246 |
+
|
| 247 |
+
|
| 248 |
def _install_forward_timing(pipe) -> None:
|
| 249 |
"""Record the wall time of every transformer forward, so each request can report where its seconds went.
|
| 250 |
|
|
|
|
| 353 |
|
| 354 |
torch.cuda.reset_peak_memory_stats()
|
| 355 |
FORWARD_TIMES.clear()
|
| 356 |
+
DECODE_TIMES.clear()
|
| 357 |
started = time.perf_counter()
|
| 358 |
+
if os.environ.get("H3_PROFILE") == "1":
|
| 359 |
+
from torch.profiler import ProfilerActivity, profile
|
| 360 |
+
|
| 361 |
+
with profile(activities=[ProfilerActivity.CPU, ProfilerActivity.CUDA]) as prof:
|
| 362 |
+
state = PIPE(
|
| 363 |
+
prompt_embeds=prompt_embeds.to("cuda"),
|
| 364 |
+
text_token_tags=text_token_tags,
|
| 365 |
+
height=height,
|
| 366 |
+
width=width,
|
| 367 |
+
num_frames=num_frames,
|
| 368 |
+
num_inference_steps=SIGMA_GRID_POINTS,
|
| 369 |
+
generator=torch.Generator("cpu").manual_seed(int(seed)),
|
| 370 |
+
)
|
| 371 |
+
print(
|
| 372 |
+
prof.key_averages().table(sort_by="cuda_time_total", row_limit=40, max_name_column_width=60),
|
| 373 |
+
flush=True,
|
| 374 |
+
)
|
| 375 |
+
else:
|
| 376 |
+
state = PIPE(
|
| 377 |
+
prompt_embeds=prompt_embeds.to("cuda"),
|
| 378 |
+
text_token_tags=text_token_tags,
|
| 379 |
+
height=height,
|
| 380 |
+
width=width,
|
| 381 |
+
num_frames=num_frames,
|
| 382 |
+
num_inference_steps=SIGMA_GRID_POINTS,
|
| 383 |
+
generator=torch.Generator("cpu").manual_seed(int(seed)),
|
| 384 |
+
)
|
| 385 |
gen_s = time.perf_counter() - started
|
| 386 |
peak_gib = torch.cuda.max_memory_allocated() / 1024**3
|
| 387 |
forwards = [round(t, 2) for t in FORWARD_TIMES]
|
| 388 |
+
decodes = {name: round(t, 2) for name, t in DECODE_TIMES.items()}
|
| 389 |
+
print(f"[gen] pipeline {gen_s:.2f}s · forwards {forwards} · decodes {decodes} · peak {peak_gib:.2f} GiB", flush=True)
|
| 390 |
+
return (
|
| 391 |
+
state.get("videos")[0],
|
| 392 |
+
state.get("audio")[0].cpu(),
|
| 393 |
+
state.get("sampling_rate"),
|
| 394 |
+
gen_s,
|
| 395 |
+
peak_gib,
|
| 396 |
+
forwards,
|
| 397 |
+
decodes,
|
| 398 |
+
)
|
| 399 |
|
| 400 |
|
| 401 |
@spaces.GPU(duration=120, size=GPU_SIZE)
|
|
|
|
| 508 |
refined = plan.get("refined_prompt") or ""
|
| 509 |
|
| 510 |
progress(0.2, desc=f"{NUM_FORWARDS} transformer forwards at {width}x{height}, {num_frames} frames ...")
|
| 511 |
+
frames, audio, sampling_rate, gen_s, peak_gib, forwards, decodes = _generate(
|
| 512 |
prompt_embeds, text_token_tags, height, width, num_frames, seed
|
| 513 |
)
|
| 514 |
|
|
|
|
| 520 |
|
| 521 |
forward_total = sum(forwards) if forwards else float("nan")
|
| 522 |
forward_detail = "+".join(f"{t:.1f}" for t in forwards) if forwards else "n/a"
|
| 523 |
+
decode_detail = " + ".join(f"{k} {v:.1f}s" for k, v in decodes.items()) if decodes else "n/a"
|
| 524 |
report = (
|
| 525 |
f"`{width}x{height}`, {num_frames} frames @ {FPS} fps, {NUM_FORWARDS} transformer forwards · "
|
| 526 |
+
f"pipeline **{gen_s:.1f}s** (forwards {forward_detail} = {forward_total:.1f}s, {decode_detail}, "
|
| 527 |
+
f"other {gen_s - forward_total - sum(decodes.values()):.1f}s) · peak {peak_gib:.1f} GiB · "
|
| 528 |
f"conditioner {condition_seconds:.0f}s ({plan['num_text_tokens']} tokens"
|
| 529 |
f"{', rewritten' if refined else ''}) · seed {int(seed)} · req {request_id}"
|
| 530 |
)
|