Drop torch.compile from the upscale model; run eager (#50) (#70)
Browse filesDev-Space A/B via UPSCALE_COMPILE (#69), 53 frames, back-to-back runs:
- compiled (832x624 / 624x832): model_time 10.56-11.04s cold, 2.72-5.42s
warm, almost entirely the per-request first-call (compile/guard) penalty
- eager (544x832): model_time 0.96s cold and 0.96s warm, first call ~0.1s
Eager's steady compute is ~25% slower per pixel (~+0.2s per request at
832x624), far below the 1.9-10s compile penalty it removes. Remove the
compile path and the now-unneeded UPSCALE_COMPILE flag, and update the
profiler docstring that assumed compile.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
postprocess/upscale/profiling.py
CHANGED
|
@@ -1,10 +1,10 @@
|
|
| 1 |
"""Optional profiling for `upscale_frames()`, gated by `UPSCALE_PROFILE=1` (see `upscale.PROFILE`).
|
| 2 |
|
| 3 |
Buckets each tiled `model()` call into "first call at this (tile-shape, batch-size)" vs. "steady
|
| 4 |
-
call" (a repeat of a shape/batch-size combo already seen this run):
|
| 5 |
-
|
| 6 |
-
|
| 7 |
-
|
| 8 |
|
| 9 |
The memory line also reports what was already allocated when the run started (e.g. the diffusion
|
| 10 |
pipeline's weights, resident in the same process — `reset_peak_memory_stats` resets the peak, not
|
|
|
|
| 1 |
"""Optional profiling for `upscale_frames()`, gated by `UPSCALE_PROFILE=1` (see `upscale.PROFILE`).
|
| 2 |
|
| 3 |
Buckets each tiled `model()` call into "first call at this (tile-shape, batch-size)" vs. "steady
|
| 4 |
+
call" (a repeat of a shape/batch-size combo already seen this run): the first call at a new
|
| 5 |
+
shape is where one-off costs land (CUDA/cuDNN lazy init today; per-shape recompiles back when the
|
| 6 |
+
model was torch.compile'd — dropped per issue #50). Also tracks peak CUDA memory for the run. See
|
| 7 |
+
issue #48.
|
| 8 |
|
| 9 |
The memory line also reports what was already allocated when the run started (e.g. the diffusion
|
| 10 |
pipeline's weights, resident in the same process — `reset_peak_memory_stats` resets the peak, not
|
postprocess/upscale/upscale.py
CHANGED
|
@@ -78,12 +78,6 @@ dtype = torch.float16 if device.type == "cuda" else torch.float32
|
|
| 78 |
# for each upscale_frames() invocation — see profiling.py. Off by default.
|
| 79 |
PROFILE = os.environ.get("UPSCALE_PROFILE", "") not in ("", "0")
|
| 80 |
|
| 81 |
-
# Set UPSCALE_COMPILE=0 to run the eager model instead of torch.compile on CUDA. On by default.
|
| 82 |
-
# Compiling costs a per-request first-call penalty at each shape (~9.8s cold, ~1.9s even on a warm
|
| 83 |
-
# container) against ~0.06s/batch of steady compute, so eager may well be faster end to end —
|
| 84 |
-
# this flag exists to measure that on the dev Space (issue #50).
|
| 85 |
-
COMPILE = os.environ.get("UPSCALE_COMPILE", "1") != "0"
|
| 86 |
-
|
| 87 |
ProgressCallback = Callable[[int, int], None]
|
| 88 |
|
| 89 |
|
|
@@ -110,19 +104,10 @@ def _load_model() -> torch.nn.Module:
|
|
| 110 |
state_dict = load_file(_weights_path())
|
| 111 |
model.load_state_dict(state_dict, strict=True)
|
| 112 |
model.to(device=device, dtype=dtype).eval()
|
| 113 |
-
|
| 114 |
-
|
| 115 |
-
|
| 116 |
-
|
| 117 |
-
# handful of those per video, but recompiling per-shape would otherwise eat into the
|
| 118 |
-
# first frame's latency. Guarded: torch.compile can fail to initialize (e.g. missing
|
| 119 |
-
# or incompatible triton on the target GPU image), in which case the eager model is
|
| 120 |
-
# used as-is.
|
| 121 |
-
model = cast(torch.nn.Module, torch.compile(model, dynamic=True))
|
| 122 |
-
except Exception as e:
|
| 123 |
-
print(f"[upscale] torch.compile failed to initialize, using eager model: {e!r}", flush=True)
|
| 124 |
-
elif device.type == "cuda":
|
| 125 |
-
print("[upscale] UPSCALE_COMPILE=0: using eager model", flush=True)
|
| 126 |
return model
|
| 127 |
|
| 128 |
|
|
|
|
| 78 |
# for each upscale_frames() invocation — see profiling.py. Off by default.
|
| 79 |
PROFILE = os.environ.get("UPSCALE_PROFILE", "") not in ("", "0")
|
| 80 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 81 |
ProgressCallback = Callable[[int, int], None]
|
| 82 |
|
| 83 |
|
|
|
|
| 104 |
state_dict = load_file(_weights_path())
|
| 105 |
model.load_state_dict(state_dict, strict=True)
|
| 106 |
model.to(device=device, dtype=dtype).eval()
|
| 107 |
+
# Deliberately not torch.compile'd. Measured on the dev Space (issue #50), 53 frames:
|
| 108 |
+
# compiled model time was ~11s cold / 2.7-5.4s warm, almost all of it a per-request
|
| 109 |
+
# first-call (compile/guard) penalty, vs. ~0.96s cold *and* warm for eager. Eager's steady
|
| 110 |
+
# compute is ~25% slower per pixel (~+0.2s/request at 832x624), far less than that penalty.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 111 |
return model
|
| 112 |
|
| 113 |
|