Measure DeMemWM inference noise-route pruning
Browse files
.exp_artifact/dememwm_noise_route_inference_pruning/diagnostic.py
CHANGED
|
@@ -1,6 +1,7 @@
|
|
| 1 |
from pathlib import Path
|
| 2 |
from types import SimpleNamespace
|
| 3 |
import sys
|
|
|
|
| 4 |
|
| 5 |
import torch
|
| 6 |
|
|
@@ -23,6 +24,8 @@ STREAM_VALUES = {"anchor": 20.0, "dynamic": 30.0, "revisit": 40.0}
|
|
| 23 |
STREAM_NOISE_BASE = {"anchor": 200, "dynamic": 300, "revisit": 400}
|
| 24 |
BATCH_SIZE = 2
|
| 25 |
TARGET_LENGTH = 3
|
|
|
|
|
|
|
| 26 |
|
| 27 |
|
| 28 |
def _make_inputs(stream_masks):
|
|
@@ -86,6 +89,22 @@ def _target_proxy(packed_latents, frame_memory_segments, frame_memory_masks):
|
|
| 86 |
return target + contribution.unsqueeze(0)
|
| 87 |
|
| 88 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 89 |
def _full_proxy_inputs(inputs, routed_masks):
|
| 90 |
packed_latents = torch.cat(
|
| 91 |
[inputs["target_latents"], *[inputs["stream_latents_by_key"][key] for key in _DEMEMWM_STREAM_KEYS]],
|
|
@@ -142,6 +161,8 @@ def _run_case(name, sampler_index, stream_masks, expected_active, expected_prune
|
|
| 142 |
)
|
| 143 |
|
| 144 |
full_segments = {"target": TARGET_LENGTH, **{key: STREAM_LENGTHS[key] for key in _DEMEMWM_STREAM_KEYS}}
|
|
|
|
|
|
|
| 145 |
full_memory_tokens = sum(full_segments[key] for key in _DEMEMWM_STREAM_KEYS)
|
| 146 |
pruned_memory_tokens = sum(active_segments[key] for key in _DEMEMWM_STREAM_KEYS)
|
| 147 |
|
|
@@ -156,7 +177,7 @@ def _run_case(name, sampler_index, stream_masks, expected_active, expected_prune
|
|
| 156 |
_check(active_segments[key] == STREAM_LENGTHS[key], f"{name}: active {key} segment length changed")
|
| 157 |
_check(torch.equal(active_masks[key], routed_masks[key]), f"{name}: active {key} mask changed")
|
| 158 |
|
| 159 |
-
expected_total_len =
|
| 160 |
_check(active_packed_latents.shape == (expected_total_len, BATCH_SIZE, 2), f"{name}: packed latent shape mismatch")
|
| 161 |
_check(active_packed_conditions.shape == (expected_total_len, BATCH_SIZE, 4), f"{name}: packed condition shape mismatch")
|
| 162 |
_check(active_frame_memory_pose.shape == (expected_total_len, BATCH_SIZE, 3), f"{name}: packed pose shape mismatch")
|
|
@@ -180,14 +201,30 @@ def _run_case(name, sampler_index, stream_masks, expected_active, expected_prune
|
|
| 180 |
)
|
| 181 |
|
| 182 |
full_latents, full_proxy_segments, full_proxy_masks = _full_proxy_inputs(inputs, routed_masks)
|
| 183 |
-
full_output
|
| 184 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 185 |
target_max_abs_diff = (full_output - pruned_output).abs().max().item()
|
| 186 |
_check(target_max_abs_diff == 0.0, f"{name}: proxy target output changed by {target_max_abs_diff}")
|
|
|
|
|
|
|
| 187 |
|
| 188 |
print(f"case={name}")
|
| 189 |
print(f" route=anchor:high,dynamic:low,revisit:all")
|
| 190 |
print(f" denoising_step={sampler_index} noise_level={_sampler_index_noise(sampler_index)}")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 191 |
print(f" active_streams={active_streams}")
|
| 192 |
print(f" pruned_streams={pruned_streams}")
|
| 193 |
print(f" full_memory_token_count={full_memory_tokens}")
|
|
|
|
| 1 |
from pathlib import Path
|
| 2 |
from types import SimpleNamespace
|
| 3 |
import sys
|
| 4 |
+
import time
|
| 5 |
|
| 6 |
import torch
|
| 7 |
|
|
|
|
| 24 |
STREAM_NOISE_BASE = {"anchor": 200, "dynamic": 300, "revisit": 400}
|
| 25 |
BATCH_SIZE = 2
|
| 26 |
TARGET_LENGTH = 3
|
| 27 |
+
TIMING_WARMUP = 20
|
| 28 |
+
TIMING_ITERS = 1000
|
| 29 |
|
| 30 |
|
| 31 |
def _make_inputs(stream_masks):
|
|
|
|
| 89 |
return target + contribution.unsqueeze(0)
|
| 90 |
|
| 91 |
|
| 92 |
+
def _time_proxy_call(fn, timing_tensor):
|
| 93 |
+
backend = "cuda_proxy" if timing_tensor.is_cuda else "cpu_proxy"
|
| 94 |
+
with torch.no_grad():
|
| 95 |
+
for _ in range(TIMING_WARMUP):
|
| 96 |
+
output = fn()
|
| 97 |
+
if timing_tensor.is_cuda:
|
| 98 |
+
torch.cuda.synchronize(timing_tensor.device)
|
| 99 |
+
start = time.perf_counter()
|
| 100 |
+
for _ in range(TIMING_ITERS):
|
| 101 |
+
output = fn()
|
| 102 |
+
if timing_tensor.is_cuda:
|
| 103 |
+
torch.cuda.synchronize(timing_tensor.device)
|
| 104 |
+
elapsed_ms = (time.perf_counter() - start) * 1000.0 / TIMING_ITERS
|
| 105 |
+
return output, elapsed_ms, backend
|
| 106 |
+
|
| 107 |
+
|
| 108 |
def _full_proxy_inputs(inputs, routed_masks):
|
| 109 |
packed_latents = torch.cat(
|
| 110 |
[inputs["target_latents"], *[inputs["stream_latents_by_key"][key] for key in _DEMEMWM_STREAM_KEYS]],
|
|
|
|
| 161 |
)
|
| 162 |
|
| 163 |
full_segments = {"target": TARGET_LENGTH, **{key: STREAM_LENGTHS[key] for key in _DEMEMWM_STREAM_KEYS}}
|
| 164 |
+
full_tokens = sum(full_segments.values())
|
| 165 |
+
pruned_tokens = sum(active_segments.values())
|
| 166 |
full_memory_tokens = sum(full_segments[key] for key in _DEMEMWM_STREAM_KEYS)
|
| 167 |
pruned_memory_tokens = sum(active_segments[key] for key in _DEMEMWM_STREAM_KEYS)
|
| 168 |
|
|
|
|
| 177 |
_check(active_segments[key] == STREAM_LENGTHS[key], f"{name}: active {key} segment length changed")
|
| 178 |
_check(torch.equal(active_masks[key], routed_masks[key]), f"{name}: active {key} mask changed")
|
| 179 |
|
| 180 |
+
expected_total_len = pruned_tokens
|
| 181 |
_check(active_packed_latents.shape == (expected_total_len, BATCH_SIZE, 2), f"{name}: packed latent shape mismatch")
|
| 182 |
_check(active_packed_conditions.shape == (expected_total_len, BATCH_SIZE, 4), f"{name}: packed condition shape mismatch")
|
| 183 |
_check(active_frame_memory_pose.shape == (expected_total_len, BATCH_SIZE, 3), f"{name}: packed pose shape mismatch")
|
|
|
|
| 201 |
)
|
| 202 |
|
| 203 |
full_latents, full_proxy_segments, full_proxy_masks = _full_proxy_inputs(inputs, routed_masks)
|
| 204 |
+
full_output, full_step_ms, full_backend = _time_proxy_call(
|
| 205 |
+
lambda: _target_proxy(full_latents, full_proxy_segments, full_proxy_masks),
|
| 206 |
+
full_latents,
|
| 207 |
+
)
|
| 208 |
+
pruned_output, pruned_step_ms, pruned_backend = _time_proxy_call(
|
| 209 |
+
lambda: _target_proxy(active_packed_latents, active_segments, active_masks),
|
| 210 |
+
active_packed_latents,
|
| 211 |
+
)
|
| 212 |
+
_check(full_backend == pruned_backend, f"{name}: timing backend changed across proxy calls")
|
| 213 |
target_max_abs_diff = (full_output - pruned_output).abs().max().item()
|
| 214 |
_check(target_max_abs_diff == 0.0, f"{name}: proxy target output changed by {target_max_abs_diff}")
|
| 215 |
+
token_reduction_pct = 100.0 * (1.0 - float(pruned_tokens) / float(full_tokens))
|
| 216 |
+
speedup_ratio = full_step_ms / pruned_step_ms if pruned_step_ms > 0.0 else float("inf")
|
| 217 |
|
| 218 |
print(f"case={name}")
|
| 219 |
print(f" route=anchor:high,dynamic:low,revisit:all")
|
| 220 |
print(f" denoising_step={sampler_index} noise_level={_sampler_index_noise(sampler_index)}")
|
| 221 |
+
print(f" timing_backend={full_backend} timing_iters={TIMING_ITERS}")
|
| 222 |
+
print(f" full_tokens={full_tokens}")
|
| 223 |
+
print(f" pruned_tokens={pruned_tokens}")
|
| 224 |
+
print(f" token_reduction_pct={token_reduction_pct:.2f}")
|
| 225 |
+
print(f" full_step_ms={full_step_ms:.6f}")
|
| 226 |
+
print(f" pruned_step_ms={pruned_step_ms:.6f}")
|
| 227 |
+
print(f" speedup_ratio={speedup_ratio:.3f}")
|
| 228 |
print(f" active_streams={active_streams}")
|
| 229 |
print(f" pruned_streams={pruned_streams}")
|
| 230 |
print(f" full_memory_token_count={full_memory_tokens}")
|