BonanDing commited on
Commit
89a11f1
·
1 Parent(s): ec7413f

Simplify DeMemWM memory noise modes

Browse files
algorithms/dememwm/df_video.py CHANGED
@@ -237,17 +237,6 @@ def _select_online_dynamic_indices(start_frame: int, count: int) -> np.ndarray:
237
  return np.arange(start, int(start_frame), dtype=np.int64)[-count:]
238
 
239
 
240
- def _shift_memory_noise_levels(levels, shift: float, diffusion_model, bounds):
241
- if levels.numel() == 0 or float(shift) == 0.0 or not hasattr(diffusion_model, "snr"):
242
- return levels
243
-
244
- log_snr = diffusion_model.snr.to(device=levels.device, dtype=torch.float32).clamp_min(1e-20).log()
245
- shifted_log_snr = log_snr[levels.clamp(0, log_snr.numel() - 1)] + float(shift)
246
- table = log_snr.view(*((1,) * shifted_log_snr.ndim), -1)
247
- shifted = (table - shifted_log_snr.unsqueeze(-1)).abs().argmin(dim=-1).to(dtype=levels.dtype)
248
- return torch.minimum(shifted, bounds.reshape(1, -1).expand_as(shifted))
249
-
250
-
251
  def _memory_noise_levels_for_streams(cfg, diffusion_model, query_noise_levels, stream_lengths, mode: str):
252
  is_training = str(mode) == "training"
253
  noise_cfg = _cfg_get(cfg, "memory_noise")
@@ -258,15 +247,26 @@ def _memory_noise_levels_for_streams(cfg, diffusion_model, query_noise_levels, s
258
  for key in _DEMEMWM_STREAM_KEYS
259
  }
260
 
261
- if str(_cfg_get(noise_cfg, "mode", "random_cleaner_fraction")) != "random_cleaner_fraction":
262
- raise ValueError("memory_noise.mode must be random_cleaner_fraction")
 
263
  noisy_memory = bool(_cfg_get(noise_cfg, "enabled", True)) and (
264
  is_training or bool(_cfg_get(noise_cfg, "validation_noisy_memory", False))
265
  )
266
- snr_cfg = _cfg_get(noise_cfg, "snr_shift")
267
- snr_enabled = is_training and noisy_memory and bool(_cfg_get(snr_cfg, "enabled", False))
268
  query = query_noise_levels[:, None] if query_noise_levels.ndim == 1 else query_noise_levels
269
- bounds = query.to(dtype=torch.long).clamp_min(0).min(dim=0).values
 
 
 
 
 
 
 
 
 
 
 
 
270
  defaults = {"anchor": 0.25, "dynamic": 0.50, "revisit": 0.25}
271
  levels_by_stream = {}
272
  for key in _DEMEMWM_STREAM_KEYS:
@@ -274,14 +274,25 @@ def _memory_noise_levels_for_streams(cfg, diffusion_model, query_noise_levels, s
274
  if count == 0:
275
  levels_by_stream[key] = bounds.new_zeros((0, bounds.numel()))
276
  continue
277
- fraction = float(_cfg_get(noise_cfg, f"{key}_max_fraction", defaults[key])) if noisy_memory else 0.0
278
- max_levels = torch.floor(bounds.to(dtype=torch.float32) * fraction).to(dtype=torch.long).clamp_min(0)
279
- if is_training and noisy_memory:
 
 
 
 
 
 
 
 
 
 
 
 
280
  levels = torch.floor(torch.rand((count, bounds.numel()), device=bounds.device) * (max_levels[None].float() + 1)).to(dtype=torch.long)
281
  else:
282
  levels = max_levels.reshape(1, -1).expand(count, -1).contiguous()
283
- shift = float(_cfg_get(snr_cfg, key, 0.0)) if snr_enabled else 0.0
284
- levels_by_stream[key] = _shift_memory_noise_levels(levels, shift, diffusion_model, bounds)
285
  return levels_by_stream
286
 
287
 
 
237
  return np.arange(start, int(start_frame), dtype=np.int64)[-count:]
238
 
239
 
 
 
 
 
 
 
 
 
 
 
 
240
  def _memory_noise_levels_for_streams(cfg, diffusion_model, query_noise_levels, stream_lengths, mode: str):
241
  is_training = str(mode) == "training"
242
  noise_cfg = _cfg_get(cfg, "memory_noise")
 
247
  for key in _DEMEMWM_STREAM_KEYS
248
  }
249
 
250
+ noise_mode = str(_cfg_get(noise_cfg, "mode", "random_cleaner_fraction"))
251
+ if noise_mode not in {"random_cleaner_fraction", "independent"}:
252
+ raise ValueError("memory_noise.mode must be random_cleaner_fraction or independent")
253
  noisy_memory = bool(_cfg_get(noise_cfg, "enabled", True)) and (
254
  is_training or bool(_cfg_get(noise_cfg, "validation_noisy_memory", False))
255
  )
 
 
256
  query = query_noise_levels[:, None] if query_noise_levels.ndim == 1 else query_noise_levels
257
+ query_bounds = query.to(dtype=torch.long).clamp_min(0).min(dim=0).values
258
+ if noise_mode == "independent":
259
+ if is_training:
260
+ max_level = int(getattr(diffusion_model, "timesteps", 0) or 0) - 1
261
+ else:
262
+ max_level = int(
263
+ getattr(diffusion_model, "sampling_timesteps", 0)
264
+ or getattr(diffusion_model, "timesteps", 0)
265
+ or 1
266
+ )
267
+ bounds = query_bounds.new_full(query_bounds.shape, max(0, max_level))
268
+ else:
269
+ bounds = query_bounds
270
  defaults = {"anchor": 0.25, "dynamic": 0.50, "revisit": 0.25}
271
  levels_by_stream = {}
272
  for key in _DEMEMWM_STREAM_KEYS:
 
274
  if count == 0:
275
  levels_by_stream[key] = bounds.new_zeros((0, bounds.numel()))
276
  continue
277
+ if noise_mode == "independent":
278
+ max_levels = bounds if noisy_memory else bounds.new_zeros(bounds.shape)
279
+ else:
280
+ fraction = float(_cfg_get(noise_cfg, f"{key}_max_fraction", defaults[key])) if noisy_memory else 0.0
281
+ max_levels = torch.floor(bounds.to(dtype=torch.float32) * fraction).to(dtype=torch.long).clamp_min(0)
282
+ if is_training and noisy_memory and noise_mode == "independent":
283
+ levels = torch.randint(
284
+ 0,
285
+ int(bounds.max().item()) + 1,
286
+ (count, bounds.numel()),
287
+ device=bounds.device,
288
+ dtype=torch.long,
289
+ )
290
+ levels = torch.minimum(levels, max_levels.reshape(1, -1).expand_as(levels))
291
+ elif is_training and noisy_memory:
292
  levels = torch.floor(torch.rand((count, bounds.numel()), device=bounds.device) * (max_levels[None].float() + 1)).to(dtype=torch.long)
293
  else:
294
  levels = max_levels.reshape(1, -1).expand(count, -1).contiguous()
295
+ levels_by_stream[key] = levels
 
296
  return levels_by_stream
297
 
298
 
algorithms/dememwm/models/dit.py CHANGED
@@ -171,7 +171,8 @@ class FrameMemoryReferenceAttention(nn.Module):
171
  relative_rays = geometry_cache["relative_rays"].to(device=target_hidden.device, dtype=target_hidden.dtype)
172
  else:
173
  query_rays = None
174
-
 
175
  q_input = target_hidden
176
  if query_rays is not None:
177
  # Values stay visual-only; Plucker features only steer Q/K matching.
 
171
  relative_rays = geometry_cache["relative_rays"].to(device=target_hidden.device, dtype=target_hidden.dtype)
172
  else:
173
  query_rays = None
174
+ relative_rays = None
175
+
176
  q_input = target_hidden
177
  if query_rays is not None:
178
  # Values stay visual-only; Plucker features only steer Q/K matching.
configurations/algorithm/dememwm_base.yaml CHANGED
@@ -8,11 +8,11 @@ memory_selection: ${dataset.memory_selection}
8
 
9
  memory_noise:
10
  enabled: true
 
11
  mode: random_cleaner_fraction
12
  anchor_max_fraction: 0.25
13
  dynamic_max_fraction: 0.50
14
  revisit_max_fraction: 0.25
15
- snr_shift: {enabled: true, anchor: 0.0, dynamic: 0.0, revisit: 0.0}
16
  noise_route: {anchor: all, dynamic: all, revisit: all}
17
  trainability:
18
  freeze_vae: true
 
8
 
9
  memory_noise:
10
  enabled: true
11
+ # Options: random_cleaner_fraction (query-bounded), independent (full schedule).
12
  mode: random_cleaner_fraction
13
  anchor_max_fraction: 0.25
14
  dynamic_max_fraction: 0.50
15
  revisit_max_fraction: 0.25
 
16
  noise_route: {anchor: all, dynamic: all, revisit: all}
17
  trainability:
18
  freeze_vae: true
tests/test_dememwm_latent_dataset.py CHANGED
@@ -436,15 +436,14 @@ class DeMemWMLatentDatasetTests(unittest.TestCase):
436
  with self.assertRaisesRegex(TypeError, "latent dict batch contract"):
437
  DeMemWMMinecraft.training_step(Harness(), (None, None, None, None), 0)
438
 
439
- def test_memory_noise_helpers_route_shift_and_keep_validation_clean(self):
440
  from algorithms.dememwm.df_video import _apply_memory_route_masks, _memory_noise_levels_for_streams
441
 
442
  class Diffusion:
443
  stabilization_level, timesteps, sampling_timesteps = 7, 10, 4
444
- snr = torch.exp(torch.linspace(5.0, -4.0, 10))
445
 
446
  cfg = OmegaConf.create({
447
- "memory_noise": {"enabled": True, "anchor_max_fraction": 1.0, "dynamic_max_fraction": 0.5, "revisit_max_fraction": 0.25, "snr_shift": {"enabled": True, "anchor": 100.0}},
448
  "noise_route": {"anchor": "high", "dynamic": "low", "revisit": "all"},
449
  })
450
  query_noise = torch.tensor([[9, 1], [7, 1]], dtype=torch.long)
@@ -452,7 +451,7 @@ class DeMemWMLatentDatasetTests(unittest.TestCase):
452
  torch.manual_seed(0)
453
 
454
  levels = _memory_noise_levels_for_streams(cfg, Diffusion, query_noise, stream_lengths, mode="training")
455
- self.assertEqual(levels["anchor"].tolist(), [[0, 0]])
456
  self.assertTrue(bool((levels["dynamic"] <= torch.tensor([[3, 0]])).all()))
457
  self.assertTrue(bool((levels["revisit"] <= torch.tensor([[1, 0]])).all()))
458
  validation_levels = _memory_noise_levels_for_streams(cfg, Diffusion, query_noise, stream_lengths, mode="validation")
@@ -462,6 +461,34 @@ class DeMemWMLatentDatasetTests(unittest.TestCase):
462
  routed = _apply_memory_route_masks(masks, query_noise, cfg, Diffusion, mode="training")
463
  self.assertEqual({key: routed[key].tolist() for key in stream_lengths}, {"anchor": [[True], [False]], "dynamic": [[False], [True]], "revisit": [[True], [True]]})
464
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
465
  def test_trainability_controls_memory_groups_full_dit_ramp_and_vae_freeze(self):
466
  from algorithms.dememwm.df_video import (
467
  _apply_dememwm_trainability,
 
436
  with self.assertRaisesRegex(TypeError, "latent dict batch contract"):
437
  DeMemWMMinecraft.training_step(Harness(), (None, None, None, None), 0)
438
 
439
+ def test_memory_noise_helpers_route_and_keep_validation_clean(self):
440
  from algorithms.dememwm.df_video import _apply_memory_route_masks, _memory_noise_levels_for_streams
441
 
442
  class Diffusion:
443
  stabilization_level, timesteps, sampling_timesteps = 7, 10, 4
 
444
 
445
  cfg = OmegaConf.create({
446
+ "memory_noise": {"enabled": True, "anchor_max_fraction": 1.0, "dynamic_max_fraction": 0.5, "revisit_max_fraction": 0.25},
447
  "noise_route": {"anchor": "high", "dynamic": "low", "revisit": "all"},
448
  })
449
  query_noise = torch.tensor([[9, 1], [7, 1]], dtype=torch.long)
 
451
  torch.manual_seed(0)
452
 
453
  levels = _memory_noise_levels_for_streams(cfg, Diffusion, query_noise, stream_lengths, mode="training")
454
+ self.assertTrue(bool((levels["anchor"] <= torch.tensor([[7, 1]])).all()))
455
  self.assertTrue(bool((levels["dynamic"] <= torch.tensor([[3, 0]])).all()))
456
  self.assertTrue(bool((levels["revisit"] <= torch.tensor([[1, 0]])).all()))
457
  validation_levels = _memory_noise_levels_for_streams(cfg, Diffusion, query_noise, stream_lengths, mode="validation")
 
461
  routed = _apply_memory_route_masks(masks, query_noise, cfg, Diffusion, mode="training")
462
  self.assertEqual({key: routed[key].tolist() for key in stream_lengths}, {"anchor": [[True], [False]], "dynamic": [[False], [True]], "revisit": [[True], [True]]})
463
 
464
+ def test_memory_noise_independent_mode_ignores_query_bounds(self):
465
+ from algorithms.dememwm.df_video import _memory_noise_levels_for_streams
466
+
467
+ class Diffusion:
468
+ stabilization_level, timesteps, sampling_timesteps = 7, 10, 4
469
+
470
+ cfg = OmegaConf.create({
471
+ "memory_noise": {
472
+ "enabled": True,
473
+ "mode": "independent",
474
+ },
475
+ })
476
+ query_noise = torch.ones((2, 2), dtype=torch.long)
477
+ stream_lengths = {"anchor": 3, "dynamic": 0, "revisit": 0}
478
+
479
+ def fake_randint(low, high, size, device=None, dtype=None):
480
+ self.assertEqual((low, high, size), (0, 10, (3, 2)))
481
+ return torch.full(size, high - 1, device=device, dtype=dtype)
482
+
483
+ with mock.patch("algorithms.dememwm.df_video.torch.randint", side_effect=fake_randint):
484
+ levels = _memory_noise_levels_for_streams(cfg, Diffusion, query_noise, stream_lengths, mode="training")
485
+
486
+ self.assertEqual(levels["anchor"].tolist(), [[9, 9], [9, 9], [9, 9]])
487
+ self.assertTrue(bool((levels["anchor"] > query_noise.max()).all()))
488
+
489
+ validation_levels = _memory_noise_levels_for_streams(cfg, Diffusion, query_noise, stream_lengths, mode="validation")
490
+ self.assertEqual(sum(int(v.sum().item()) for v in validation_levels.values()), 0)
491
+
492
  def test_trainability_controls_memory_groups_full_dit_ramp_and_vae_freeze(self):
493
  from algorithms.dememwm.df_video import (
494
  _apply_dememwm_trainability,