BonanDing commited on
Commit
f53385e
·
1 Parent(s): 7a609df

Fix DeMemWM noise-route pruning review findings

Browse files
.exp_artifact/dememwm_noise_route_inference_pruning/diagnostic.py CHANGED
@@ -25,7 +25,9 @@ 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,8 +91,116 @@ def _target_proxy(packed_latents, frame_memory_segments, frame_memory_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()
@@ -110,8 +220,26 @@ def _full_proxy_inputs(inputs, routed_masks):
110
  [inputs["target_latents"], *[inputs["stream_latents_by_key"][key] for key in _DEMEMWM_STREAM_KEYS]],
111
  dim=0,
112
  )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
113
  segments = {"target": TARGET_LENGTH, **{key: STREAM_LENGTHS[key] for key in _DEMEMWM_STREAM_KEYS}}
114
- return packed_latents, segments, {"target": inputs["target_mask"], **routed_masks}
115
 
116
 
117
  def _expected_noise(memory_noise_levels_by_key, active_streams):
@@ -200,18 +328,45 @@ def _run_case(name, sampler_index, stream_masks, expected_active, expected_prune
200
  f"{name}: denoising noise-level shape contract 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
 
@@ -219,6 +374,8 @@ def _run_case(name, sampler_index, stream_masks, expected_active, expected_prune
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}")
 
25
  BATCH_SIZE = 2
26
  TARGET_LENGTH = 3
27
  TIMING_WARMUP = 20
28
+ TIMING_ITERS = 200
29
+ PROXY_PATCHES_PER_FRAME = 8
30
+ PROXY_WIDTH = 32
31
 
32
 
33
  def _make_inputs(stream_masks):
 
91
  return target + contribution.unsqueeze(0)
92
 
93
 
94
+ def _make_proxy_weights(tensor):
95
+ dtype = tensor.dtype
96
+ device = tensor.device
97
+ in_dim = tensor.shape[-1] + 4 + 3 + 1
98
+ frame_proj = torch.linspace(
99
+ -0.17,
100
+ 0.19,
101
+ steps=in_dim * PROXY_WIDTH,
102
+ dtype=dtype,
103
+ device=device,
104
+ ).reshape(in_dim, PROXY_WIDTH)
105
+ patch_embed = torch.linspace(-0.11, 0.13, steps=PROXY_PATCHES_PER_FRAME * PROXY_WIDTH, dtype=dtype, device=device).reshape(
106
+ PROXY_PATCHES_PER_FRAME,
107
+ PROXY_WIDTH,
108
+ )
109
+ q_proj = torch.linspace(-0.09, 0.10, steps=PROXY_WIDTH * PROXY_WIDTH, dtype=dtype, device=device).reshape(
110
+ PROXY_WIDTH,
111
+ PROXY_WIDTH,
112
+ )
113
+ k_proj = torch.linspace(0.08, -0.07, steps=PROXY_WIDTH * PROXY_WIDTH, dtype=dtype, device=device).reshape(
114
+ PROXY_WIDTH,
115
+ PROXY_WIDTH,
116
+ )
117
+ v_proj = torch.linspace(-0.05, 0.06, steps=PROXY_WIDTH * PROXY_WIDTH, dtype=dtype, device=device).reshape(
118
+ PROXY_WIDTH,
119
+ PROXY_WIDTH,
120
+ )
121
+ out_proj = torch.linspace(0.04, -0.03, steps=PROXY_WIDTH * PROXY_WIDTH, dtype=dtype, device=device).reshape(
122
+ PROXY_WIDTH,
123
+ PROXY_WIDTH,
124
+ )
125
+ return {
126
+ "frame_proj": frame_proj,
127
+ "patch_embed": patch_embed,
128
+ "q_proj": q_proj,
129
+ "k_proj": k_proj,
130
+ "v_proj": v_proj,
131
+ "out_proj": out_proj,
132
+ }
133
+
134
+
135
+ def _packed_frame_valid_mask(frame_memory_segments, frame_memory_masks):
136
+ chunks = []
137
+ for key in ("target", *_DEMEMWM_STREAM_KEYS):
138
+ length = frame_memory_segments[key]
139
+ if length == 0:
140
+ continue
141
+ chunks.append(frame_memory_masks[key])
142
+ return torch.cat(chunks, dim=1)
143
+
144
+
145
+ def _expand_frame_tokens(frame_tokens, frame_valid, patch_embed):
146
+ batch, frame_count, width = frame_tokens.shape
147
+ patch_tokens = frame_tokens[:, :, None, :] + patch_embed[None, None, :, :]
148
+ patch_tokens = patch_tokens.reshape(batch, frame_count * PROXY_PATCHES_PER_FRAME, width)
149
+ patch_valid = frame_valid[:, :, None].expand(batch, frame_count, PROXY_PATCHES_PER_FRAME).reshape(batch, -1)
150
+ return patch_tokens, patch_valid
151
+
152
+
153
+ def _masked_attention(query, key, value, key_valid):
154
+ logits = torch.matmul(query, key.transpose(-1, -2)) / (query.shape[-1] ** 0.5)
155
+ logits = logits.masked_fill(~key_valid[:, None, :], torch.finfo(logits.dtype).min)
156
+ weights = torch.softmax(logits, dim=-1)
157
+ weights = torch.where(key_valid[:, None, :], weights, torch.zeros_like(weights))
158
+ return torch.matmul(weights, value)
159
+
160
+
161
+ def _dit_like_inference_proxy(
162
+ packed_latents,
163
+ packed_conditions,
164
+ packed_poses,
165
+ packed_frame_indices,
166
+ frame_memory_segments,
167
+ frame_memory_masks,
168
+ proxy_weights,
169
+ ):
170
+ # Small deterministic stand-in for one DiT sample_step: frame features become
171
+ # patch tokens, then packed temporal attention and target-to-memory reads run
172
+ # over the same canonical segment/mask contract as the real call.
173
+ frame_index_feat = packed_frame_indices.to(dtype=packed_latents.dtype).unsqueeze(-1) / 100.0
174
+ frame_features = torch.cat([packed_latents, packed_conditions, packed_poses, frame_index_feat], dim=-1)
175
+ frame_tokens = torch.matmul(frame_features, proxy_weights["frame_proj"]).permute(1, 0, 2)
176
+ frame_valid = _packed_frame_valid_mask(frame_memory_segments, frame_memory_masks)
177
+ patch_tokens, patch_valid = _expand_frame_tokens(frame_tokens, frame_valid, proxy_weights["patch_embed"])
178
+
179
+ query = torch.matmul(patch_tokens, proxy_weights["q_proj"])
180
+ key = torch.matmul(patch_tokens, proxy_weights["k_proj"])
181
+ value = torch.matmul(patch_tokens, proxy_weights["v_proj"])
182
+ temporal = _masked_attention(query, key, value, patch_valid)
183
+ temporal = torch.matmul(torch.tanh(temporal), proxy_weights["out_proj"])
184
+
185
+ target_patch_count = frame_memory_segments["target"] * PROXY_PATCHES_PER_FRAME
186
+ target_tokens = temporal[:, :target_patch_count]
187
+ cursor = target_patch_count
188
+ memory_reads = []
189
+ for key_name in _DEMEMWM_STREAM_KEYS:
190
+ stream_patch_count = frame_memory_segments[key_name] * PROXY_PATCHES_PER_FRAME
191
+ stream_tokens = temporal[:, cursor : cursor + stream_patch_count]
192
+ stream_valid = patch_valid[:, cursor : cursor + stream_patch_count]
193
+ cursor += stream_patch_count
194
+ if stream_patch_count == 0:
195
+ continue
196
+ memory_reads.append(_masked_attention(target_tokens, stream_tokens, stream_tokens, stream_valid))
197
+ if memory_reads:
198
+ target_tokens = target_tokens + torch.stack(memory_reads, dim=0).sum(dim=0)
199
+ return target_tokens.mean(dim=(1, 2))
200
+
201
+
202
  def _time_proxy_call(fn, timing_tensor):
203
+ backend = "cuda_dit_like_proxy" if timing_tensor.is_cuda else "cpu_dit_like_proxy"
204
  with torch.no_grad():
205
  for _ in range(TIMING_WARMUP):
206
  output = fn()
 
220
  [inputs["target_latents"], *[inputs["stream_latents_by_key"][key] for key in _DEMEMWM_STREAM_KEYS]],
221
  dim=0,
222
  )
223
+ packed_conditions = torch.cat(
224
+ [
225
+ inputs["target_conditions"],
226
+ *[
227
+ torch.zeros((STREAM_LENGTHS[key], BATCH_SIZE, inputs["target_conditions"].shape[-1]))
228
+ for key in _DEMEMWM_STREAM_KEYS
229
+ ],
230
+ ],
231
+ dim=0,
232
+ )
233
+ packed_poses = torch.cat(
234
+ [inputs["target_poses"], *[inputs["stream_poses_by_key"][key] for key in _DEMEMWM_STREAM_KEYS]],
235
+ dim=0,
236
+ )
237
+ packed_frame_indices = torch.cat(
238
+ [inputs["target_frame_indices"], *[inputs["stream_frame_indices_by_key"][key] for key in _DEMEMWM_STREAM_KEYS]],
239
+ dim=0,
240
+ )
241
  segments = {"target": TARGET_LENGTH, **{key: STREAM_LENGTHS[key] for key in _DEMEMWM_STREAM_KEYS}}
242
+ return packed_latents, packed_conditions, packed_poses, packed_frame_indices, segments, {"target": inputs["target_mask"], **routed_masks}
243
 
244
 
245
  def _expected_noise(memory_noise_levels_by_key, active_streams):
 
328
  f"{name}: denoising noise-level shape contract mismatch",
329
  )
330
 
331
+ (
332
+ full_latents,
333
+ full_conditions,
334
+ full_poses,
335
+ full_frame_indices,
336
+ full_proxy_segments,
337
+ full_proxy_masks,
338
+ ) = _full_proxy_inputs(inputs, routed_masks)
339
+ full_target_output = _target_proxy(full_latents, full_proxy_segments, full_proxy_masks)
340
+ pruned_target_output = _target_proxy(active_packed_latents, active_segments, active_masks)
341
+ target_max_abs_diff = (full_target_output - pruned_target_output).abs().max().item()
342
+ _check(target_max_abs_diff == 0.0, f"{name}: proxy target output changed by {target_max_abs_diff}")
343
+
344
+ proxy_weights = _make_proxy_weights(full_latents)
345
+ _, full_step_ms, full_backend = _time_proxy_call(
346
+ lambda: _dit_like_inference_proxy(
347
+ full_latents,
348
+ full_conditions,
349
+ full_poses,
350
+ full_frame_indices,
351
+ full_proxy_segments,
352
+ full_proxy_masks,
353
+ proxy_weights,
354
+ ),
355
  full_latents,
356
  )
357
+ _, pruned_step_ms, pruned_backend = _time_proxy_call(
358
+ lambda: _dit_like_inference_proxy(
359
+ active_packed_latents,
360
+ active_packed_conditions,
361
+ active_frame_memory_pose,
362
+ active_frame_indices,
363
+ active_segments,
364
+ active_masks,
365
+ proxy_weights,
366
+ ),
367
  active_packed_latents,
368
  )
369
  _check(full_backend == pruned_backend, f"{name}: timing backend changed across proxy calls")
 
 
370
  token_reduction_pct = 100.0 * (1.0 - float(pruned_tokens) / float(full_tokens))
371
  speedup_ratio = full_step_ms / pruned_step_ms if pruned_step_ms > 0.0 else float("inf")
372
 
 
374
  print(f" route=anchor:high,dynamic:low,revisit:all")
375
  print(f" denoising_step={sampler_index} noise_level={_sampler_index_noise(sampler_index)}")
376
  print(f" timing_backend={full_backend} timing_iters={TIMING_ITERS}")
377
+ print(" timing_scope=synthetic_dit_like_proxy_not_real_sample_step")
378
+ print(" speedup_ratio_scope=synthetic_proxy_only_not_measured_inference_speed")
379
  print(f" full_tokens={full_tokens}")
380
  print(f" pruned_tokens={pruned_tokens}")
381
  print(f" token_reduction_pct={token_reduction_pct:.2f}")