Mike0021 commited on
Commit
93f5879
·
verified ·
1 Parent(s): a153eed

exp4: decode timers + H3_PROFILE profiler hook

Browse files
Files changed (1) hide show
  1. app.py +67 -20
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
- state = PIPE(
340
- prompt_embeds=prompt_embeds.to("cuda"),
341
- text_token_tags=text_token_tags,
342
- height=height,
343
- width=width,
344
- num_frames=num_frames,
345
- num_inference_steps=SIGMA_GRID_POINTS,
346
- generator=torch.Generator("cpu").manual_seed(int(seed)),
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
- print(f"[gen] pipeline {gen_s:.2f}s · forwards {forwards} · peak {peak_gib:.2f} GiB", flush=True)
352
- return state.get("videos")[0], state.get("audio")[0].cpu(), state.get("sampling_rate"), gen_s, peak_gib, forwards
 
 
 
 
 
 
 
 
 
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, decode+other "
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
  )