BonanDing commited on
Commit
b093f25
·
1 Parent(s): dbadd71

Optimize DeMemWM dynamic selection defaults

Browse files
algorithms/dememwm/df_video.py CHANGED
@@ -2005,9 +2005,14 @@ class DeMemWMMinecraft(DiffusionForcingBase):
2005
  curr_frame,
2006
  memory_selection_cfg,
2007
  )
 
 
 
 
 
2008
  selected["dynamic"] = _select_online_event_dynamic_from_cache(
2009
  cache,
2010
- start_frame,
2011
  dynamic_count,
2012
  memory_selection_cfg,
2013
  reference_frames=selected["revisit"] if len(selected["revisit"]) > 0 else None,
 
2005
  curr_frame,
2006
  memory_selection_cfg,
2007
  )
2008
+ dynamic_stop = max(
2009
+ 0,
2010
+ int(target_positions[0])
2011
+ - max(0, int(_cfg_get(memory_selection_cfg, "local_context_exclusion_frames", self.n_tokens))),
2012
+ )
2013
  selected["dynamic"] = _select_online_event_dynamic_from_cache(
2014
  cache,
2015
+ dynamic_stop,
2016
  dynamic_count,
2017
  memory_selection_cfg,
2018
  reference_frames=selected["revisit"] if len(selected["revisit"]) > 0 else None,
configurations/dataset/video_minecraft_dememwm_latent.yaml CHANGED
@@ -31,8 +31,8 @@ memory_selection:
31
  local_context_exclusion_frames: 8
32
  plucker_moment_radius: 30.0
33
  anchor_diverse_selection: true
34
- pose_preselect_topk: 64
35
- candidate_chunk_size: 64
36
  dynamic:
37
  selection_policy: multiview
38
  multiview_selector: fov_greedy
 
31
  local_context_exclusion_frames: 8
32
  plucker_moment_radius: 30.0
33
  anchor_diverse_selection: true
34
+ pose_preselect_topk: 32
35
+ candidate_chunk_size: 0
36
  dynamic:
37
  selection_policy: multiview
38
  multiview_selector: fov_greedy
datasets/video/memory_selection.py CHANGED
@@ -15,6 +15,8 @@ _FOV_NUM_POINTS = 10000
15
  _FOV_RADIUS = 30.0
16
  _FOV_HALF_H = 105.0 / 2.0
17
  _FOV_HALF_V = 75.0 / 2.0
 
 
18
  _POSE_DISTANCE_SCALE = 30.0
19
  _ANGLE_DISTANCE_SCALE = 180.0
20
  _DETERMINISTIC_UNIT_BALL_CACHE: Dict[Tuple[int, str, torch.dtype], torch.Tensor] = {}
@@ -35,7 +37,7 @@ def _memory_candidate_frames(num_frames, target_positions, cfg, split, min_candi
35
  return np.arange(min_candidate_frame, stop, dtype=np.int64)
36
 
37
 
38
- def _exclude_revisit_local_context(candidates: np.ndarray, target_positions: np.ndarray, cfg) -> np.ndarray:
39
  exclusion = max(0, int(cfg_get(cfg, "local_context_exclusion_frames", 8)))
40
  if exclusion <= 0 or len(candidates) == 0 or len(target_positions) == 0:
41
  return candidates
@@ -46,6 +48,10 @@ def _exclude_revisit_local_context(candidates: np.ndarray, target_positions: np.
46
  return candidates[(candidates < local_start) | (candidates >= target_stop)]
47
 
48
 
 
 
 
 
49
  def _as_pose_array(poses) -> np.ndarray:
50
  poses = np.asarray(poses, dtype=np.float32)
51
  if poses.ndim != 2 or poses.shape[1] < 5:
@@ -135,11 +141,17 @@ def _inside_fov_points(points: torch.Tensor, poses: torch.Tensor) -> torch.Tenso
135
  x = vectors[..., 0]
136
  y = vectors[..., 1]
137
  z = vectors[..., 2]
138
- azimuth = torch.rad2deg(torch.atan2(x, z))
139
- elevation = torch.rad2deg(torch.atan2(y, torch.sqrt(x * x + z * z)))
140
- yaw_diff = _wrap_degrees(azimuth - poses[:, None, 4])
141
- pitch_diff = _wrap_degrees(elevation - poses[:, None, 3])
142
- return (yaw_diff < _FOV_HALF_H) & (pitch_diff < _FOV_HALF_V)
 
 
 
 
 
 
143
 
144
 
145
  def _target_fov_points(target_poses: torch.Tensor) -> torch.Tensor:
@@ -162,7 +174,7 @@ def _pose_preselect(
162
  *,
163
  extra_topk: int = 0,
164
  ) -> np.ndarray:
165
- topk = cfg_get(cfg, "pose_preselect_topk", 64)
166
  if topk is None:
167
  return candidates
168
  topk = int(topk)
@@ -196,7 +208,7 @@ def _candidate_fov_masks(poses_t: torch.Tensor, candidates: np.ndarray, target_p
196
  )
197
 
198
  candidates_t = torch.as_tensor(candidates, device=poses_t.device, dtype=torch.long)
199
- chunk_size = int(cfg_get(cfg, "candidate_chunk_size", 64))
200
  chunk_size = len(candidates) if chunk_size <= 0 else chunk_size
201
  inside_parts = []
202
  score_parts = []
@@ -358,10 +370,11 @@ def _build_shared_fov_candidate_pool(
358
  poses_t = _as_pose_tensor(poses)
359
  dynamic_candidates = None
360
  if int(dynamic_count) > 0:
 
361
  # Revisit frames are excluded after selection; include replacement rows
362
  # that can enter dynamic's pose-preselected top-k after that exclusion.
363
  dynamic_candidates = _pose_preselect(
364
- base_candidates,
365
  poses_t,
366
  target_positions,
367
  cfg,
@@ -556,7 +569,7 @@ def _select_dynamic_multiview_pose_plucker_fps(
556
  seed_ids: np.ndarray | None = None,
557
  ) -> np.ndarray:
558
  ranked_ids, ranked_poses, _ = _rank_pose_plucker_candidates(poses, candidates, target_positions, cfg)
559
- topk = cfg_get(cfg, "pose_preselect_topk", 64)
560
  if topk is not None:
561
  topk = int(topk)
562
  if topk > 0:
@@ -846,6 +859,7 @@ def _select_dynamic_multiview(
846
  split,
847
  min_candidate_frame=min_candidate_frame,
848
  )
 
849
  if excluded is not None and len(excluded) > 0 and len(candidates) > 0:
850
  candidates = candidates[~np.isin(candidates, np.asarray(excluded, dtype=np.int64))]
851
  if len(candidates) == 0:
@@ -1240,6 +1254,7 @@ def _select_event_triggered_dynamic(
1240
  actions=actions,
1241
  min_candidate_frame=min_candidate_frame,
1242
  )
 
1243
  if excluded is not None and len(excluded) > 0 and len(event_anchors) > 0:
1244
  event_anchors = event_anchors[~np.isin(event_anchors, np.asarray(excluded, dtype=np.int64))]
1245
  if len(event_anchors) == 0:
@@ -1268,7 +1283,11 @@ def _select_dynamic_by_policy(
1268
 
1269
  policy = _dynamic_policy(cfg)
1270
  if policy == "recent":
1271
- return _select_dynamic(target_start, count, min_candidate_frame)
 
 
 
 
1272
  if policy == "event_triggered":
1273
  return _select_event_triggered_dynamic(
1274
  target_start,
@@ -1421,6 +1440,7 @@ def select_memory_indices(
1421
  counts["dynamic"],
1422
  cfg,
1423
  min_candidate_frame=min_candidate_frame,
 
1424
  )
1425
  elif policy == "event_triggered":
1426
  dynamic_references = revisit if len(revisit) > 0 else target_positions
@@ -1432,6 +1452,7 @@ def select_memory_indices(
1432
  split,
1433
  min_candidate_frame=min_candidate_frame,
1434
  )
 
1435
  stream = np.asarray(dynamic_stream, dtype=np.int64)
1436
  if len(candidates) > 0:
1437
  eligible_stream = stream[np.isin(stream, candidates)]
 
15
  _FOV_RADIUS = 30.0
16
  _FOV_HALF_H = 105.0 / 2.0
17
  _FOV_HALF_V = 75.0 / 2.0
18
+ _FOV_COS_HALF_H = float(np.cos(np.deg2rad(_FOV_HALF_H)))
19
+ _FOV_COS_HALF_V = float(np.cos(np.deg2rad(_FOV_HALF_V)))
20
  _POSE_DISTANCE_SCALE = 30.0
21
  _ANGLE_DISTANCE_SCALE = 180.0
22
  _DETERMINISTIC_UNIT_BALL_CACHE: Dict[Tuple[int, str, torch.dtype], torch.Tensor] = {}
 
37
  return np.arange(min_candidate_frame, stop, dtype=np.int64)
38
 
39
 
40
+ def _exclude_local_context(candidates: np.ndarray, target_positions: np.ndarray, cfg) -> np.ndarray:
41
  exclusion = max(0, int(cfg_get(cfg, "local_context_exclusion_frames", 8)))
42
  if exclusion <= 0 or len(candidates) == 0 or len(target_positions) == 0:
43
  return candidates
 
48
  return candidates[(candidates < local_start) | (candidates >= target_stop)]
49
 
50
 
51
+ def _exclude_revisit_local_context(candidates: np.ndarray, target_positions: np.ndarray, cfg) -> np.ndarray:
52
+ return _exclude_local_context(candidates, target_positions, cfg)
53
+
54
+
55
  def _as_pose_array(poses) -> np.ndarray:
56
  poses = np.asarray(poses, dtype=np.float32)
57
  if poses.ndim != 2 or poses.shape[1] < 5:
 
141
  x = vectors[..., 0]
142
  y = vectors[..., 1]
143
  z = vectors[..., 2]
144
+ horizontal = torch.sqrt((x * x + z * z).clamp_min(0.0))
145
+ ray_norm = torch.sqrt((horizontal * horizontal + y * y).clamp_min(0.0))
146
+
147
+ yaw = torch.deg2rad(poses[:, 4])[:, None]
148
+ pitch = torch.deg2rad(poses[:, 3])[:, None]
149
+ yaw_aligned = x * torch.sin(yaw) + z * torch.cos(yaw)
150
+ pitch_aligned = horizontal * torch.cos(pitch) + y * torch.sin(pitch)
151
+
152
+ # Same yaw/elevation half-angle convention as the previous atan2 path,
153
+ # but without per-point inverse trig or degree wrapping.
154
+ return (yaw_aligned > horizontal * _FOV_COS_HALF_H) & (pitch_aligned > ray_norm * _FOV_COS_HALF_V)
155
 
156
 
157
  def _target_fov_points(target_poses: torch.Tensor) -> torch.Tensor:
 
174
  *,
175
  extra_topk: int = 0,
176
  ) -> np.ndarray:
177
+ topk = cfg_get(cfg, "pose_preselect_topk", 32)
178
  if topk is None:
179
  return candidates
180
  topk = int(topk)
 
208
  )
209
 
210
  candidates_t = torch.as_tensor(candidates, device=poses_t.device, dtype=torch.long)
211
+ chunk_size = int(cfg_get(cfg, "candidate_chunk_size", 0))
212
  chunk_size = len(candidates) if chunk_size <= 0 else chunk_size
213
  inside_parts = []
214
  score_parts = []
 
370
  poses_t = _as_pose_tensor(poses)
371
  dynamic_candidates = None
372
  if int(dynamic_count) > 0:
373
+ dynamic_base_candidates = _exclude_local_context(base_candidates, target_positions, cfg)
374
  # Revisit frames are excluded after selection; include replacement rows
375
  # that can enter dynamic's pose-preselected top-k after that exclusion.
376
  dynamic_candidates = _pose_preselect(
377
+ dynamic_base_candidates,
378
  poses_t,
379
  target_positions,
380
  cfg,
 
569
  seed_ids: np.ndarray | None = None,
570
  ) -> np.ndarray:
571
  ranked_ids, ranked_poses, _ = _rank_pose_plucker_candidates(poses, candidates, target_positions, cfg)
572
+ topk = cfg_get(cfg, "pose_preselect_topk", 32)
573
  if topk is not None:
574
  topk = int(topk)
575
  if topk > 0:
 
859
  split,
860
  min_candidate_frame=min_candidate_frame,
861
  )
862
+ candidates = _exclude_local_context(candidates, target_positions, cfg)
863
  if excluded is not None and len(excluded) > 0 and len(candidates) > 0:
864
  candidates = candidates[~np.isin(candidates, np.asarray(excluded, dtype=np.int64))]
865
  if len(candidates) == 0:
 
1254
  actions=actions,
1255
  min_candidate_frame=min_candidate_frame,
1256
  )
1257
+ event_anchors = _exclude_local_context(event_anchors, np.asarray([target_start], dtype=np.int64), cfg)
1258
  if excluded is not None and len(excluded) > 0 and len(event_anchors) > 0:
1259
  event_anchors = event_anchors[~np.isin(event_anchors, np.asarray(excluded, dtype=np.int64))]
1260
  if len(event_anchors) == 0:
 
1283
 
1284
  policy = _dynamic_policy(cfg)
1285
  if policy == "recent":
1286
+ dynamic_stop = int(target_start)
1287
+ if target_positions is not None:
1288
+ exclusion = max(0, int(cfg_get(cfg, "local_context_exclusion_frames", 8)))
1289
+ dynamic_stop = max(min_candidate_frame, dynamic_stop - exclusion) if exclusion > 0 else dynamic_stop
1290
+ return _select_dynamic(dynamic_stop, count, min_candidate_frame)
1291
  if policy == "event_triggered":
1292
  return _select_event_triggered_dynamic(
1293
  target_start,
 
1440
  counts["dynamic"],
1441
  cfg,
1442
  min_candidate_frame=min_candidate_frame,
1443
+ target_positions=target_positions,
1444
  )
1445
  elif policy == "event_triggered":
1446
  dynamic_references = revisit if len(revisit) > 0 else target_positions
 
1452
  split,
1453
  min_candidate_frame=min_candidate_frame,
1454
  )
1455
+ candidates = _exclude_local_context(candidates, target_positions, cfg)
1456
  stream = np.asarray(dynamic_stream, dtype=np.int64)
1457
  if len(candidates) > 0:
1458
  eligible_stream = stream[np.isin(stream, candidates)]
tests/test_dememwm_latent_dataset.py CHANGED
@@ -53,8 +53,8 @@ def _selection_cfg(**overrides):
53
  "local_context_exclusion_frames": 2,
54
  "plucker_moment_radius": 30.0,
55
  "anchor_diverse_selection": False,
56
- "pose_preselect_topk": 64,
57
- "candidate_chunk_size": 64,
58
  "dynamic": _dynamic_cfg(),
59
  }
60
  cfg.update(overrides)
@@ -217,8 +217,8 @@ class MemorySelectionTests(unittest.TestCase):
217
  self.assertIs(cfg.memory_selection.causal, True)
218
  self.assertEqual(cfg.memory_selection.dynamic.selection_policy, "multiview")
219
  self.assertEqual(cfg.memory_selection.dynamic.multiview_selector, "fov_greedy")
220
- self.assertEqual(cfg.memory_selection.pose_preselect_topk, 64)
221
- self.assertEqual(cfg.memory_selection.candidate_chunk_size, 64)
222
 
223
  def test_revisit_uses_sampled_fov_selection(self):
224
  poses = np.array(
@@ -551,7 +551,7 @@ class MemorySelectionTests(unittest.TestCase):
551
  def test_dynamic_multiview_provided_fov_pool_keeps_excluded_reference_coverage(self):
552
  import datasets.video.memory_selection as memory_selection
553
 
554
- poses = _poses(6)
555
  cfg = _selection_cfg(dynamic=_dynamic_cfg("multiview", multiview_selector="fov_greedy"))
556
  pool = _fov_pool(
557
  [0, 2, 3],
@@ -569,7 +569,7 @@ class MemorySelectionTests(unittest.TestCase):
569
  ):
570
  selected = memory_selection._select_dynamic_multiview(
571
  poses,
572
- np.asarray([5], dtype=np.int64),
573
  cfg,
574
  count=1,
575
  excluded=np.asarray([0], dtype=np.int64),
@@ -587,10 +587,10 @@ class MemorySelectionTests(unittest.TestCase):
587
  default_cfg = _selection_cfg(dynamic=_dynamic_cfg("multiview", multiview_selector="fov_greedy"))
588
  noncausal_cfg = _selection_cfg(causal=False, dynamic=_dynamic_cfg("multiview", multiview_selector="fov_greedy"))
589
  cases = [
590
- (default_cfg, "training", np.asarray([5], dtype=np.int64), [1, 2, 3, 4], [3, 4]),
591
- (noncausal_cfg, "training", np.asarray([3], dtype=np.int64), [1, 2, 3, 4, 5, 6, 7], [6, 7]),
592
- (noncausal_cfg, "validation", np.asarray([3], dtype=np.int64), [1, 2], [1, 2]),
593
- (noncausal_cfg, "test", np.asarray([3], dtype=np.int64), [1, 2], [1, 2]),
594
  ]
595
 
596
  def fake_select(pool, count, **kwargs):
@@ -619,7 +619,7 @@ class MemorySelectionTests(unittest.TestCase):
619
  first = memory_selection._select_dynamic_multiview(provided_poses, np.asarray([5], dtype=np.int64), default_cfg, count=2, **kwargs)
620
  second = memory_selection._select_dynamic_multiview(provided_poses, np.asarray([5], dtype=np.int64), default_cfg, count=2, **kwargs)
621
 
622
- self.assertEqual(first.tolist(), [2, 3])
623
  self.assertEqual(second.tolist(), first.tolist())
624
  self.assertTrue(set(first.tolist()).isdisjoint({0, 1}))
625
 
@@ -785,11 +785,11 @@ class MemorySelectionTests(unittest.TestCase):
785
  indices, masks = select_memory_indices(poses, np.array([6, 7, 8]), _selection_cfg())
786
 
787
  self.assertEqual(indices["anchor"].tolist(), [0, 1])
788
- self.assertEqual(indices["dynamic"].tolist(), [4, 5])
789
  for key in ("anchor", "dynamic", "revisit"):
790
  self.assertTrue(np.all(indices[key][masks[key]] < 6))
791
 
792
- def test_anchor_can_duplicate_recent_dynamic_when_selected(self):
793
  poses = _poses(8)
794
  cfg = _selection_cfg(
795
  max_anchor_frames=1,
@@ -808,7 +808,7 @@ class MemorySelectionTests(unittest.TestCase):
808
  )
809
 
810
  self.assertEqual(indices["anchor"].tolist(), [5])
811
- self.assertEqual(indices["dynamic"].tolist(), [5])
812
  self.assertEqual(masks["anchor"].tolist(), [True])
813
  self.assertEqual(masks["dynamic"].tolist(), [True])
814
  self.assertTrue(np.all(indices["dynamic"][masks["dynamic"]] < 6))
@@ -851,7 +851,7 @@ class MemorySelectionTests(unittest.TestCase):
851
  )
852
 
853
  selected = indices["dynamic"][masks["dynamic"]]
854
- self.assertEqual(selected.tolist(), [1, 4])
855
  self.assertTrue(np.all(selected < 5))
856
 
857
  def test_event_triggered_dynamic_noncausal_stream_can_select_future(self):
@@ -873,7 +873,7 @@ class MemorySelectionTests(unittest.TestCase):
873
  )
874
 
875
  selected = indices["dynamic"][masks["dynamic"]]
876
- self.assertEqual(selected.tolist(), [4, 5, 7])
877
  self.assertTrue(np.any(selected > 5))
878
 
879
  def test_event_triggered_dynamic_eval_stream_stays_past_when_noncausal(self):
@@ -897,7 +897,7 @@ class MemorySelectionTests(unittest.TestCase):
897
  )
898
 
899
  selected = indices["dynamic"][masks["dynamic"]]
900
- self.assertEqual(selected.tolist(), [1, 4])
901
  self.assertTrue(np.all(selected < 5))
902
 
903
  def test_event_triggered_dynamic_can_duplicate_anchor_and_revisit(self):
@@ -923,8 +923,8 @@ class MemorySelectionTests(unittest.TestCase):
923
 
924
  self.assertEqual(indices["anchor"].tolist(), [0])
925
  self.assertEqual(indices["revisit"].tolist(), [0, 5])
926
- self.assertEqual(indices["dynamic"].tolist(), [0, 5])
927
- self.assertTrue(masks["dynamic"].all())
928
 
929
  def test_recent_dynamic_remains_past_only_when_memory_selection_is_noncausal(self):
930
  poses = _poses(10)
@@ -944,7 +944,7 @@ class MemorySelectionTests(unittest.TestCase):
944
  dynamic_stream=np.asarray([6, 7, 8, 9], dtype=np.int64),
945
  )
946
 
947
- self.assertEqual(indices["dynamic"].tolist(), [4, 5])
948
  self.assertEqual(masks["dynamic"].tolist(), [True, True])
949
  self.assertTrue(np.all(indices["dynamic"][masks["dynamic"]] < 6))
950
 
@@ -2194,7 +2194,7 @@ class DeMemWMLatentDatasetTests(unittest.TestCase):
2194
 
2195
  self.assertEqual(dataset.context_length, 4)
2196
  self.assertEqual(len(dataset), 112 - (100 + 4 + 3) + 1)
2197
- self.assertEqual(sample["frame_indices"].tolist(), [106, 107, 108, 102, 105, 104, 105])
2198
  self.assertTrue(sample["memory_masks"]["anchor"].all().item())
2199
  self.assertTrue(sample["memory_masks"]["dynamic"].all().item())
2200
  self.assertEqual(tuple(sample["memory_masks"]["revisit"].shape), (0,))
@@ -2302,7 +2302,7 @@ class DeMemWMLatentDatasetTests(unittest.TestCase):
2302
  self.assertEqual(tuple(sample["latents"].shape), (9, 1, 1, 2))
2303
  self.assertEqual(sample["frame_indices"][:3].tolist(), [106, 107, 108])
2304
  self.assertEqual(sample["frame_indices"][3:5].tolist(), [100, 101])
2305
- self.assertEqual(sample["frame_indices"][5:7].tolist(), [104, 105])
2306
  revisit_frames = sample["frame_indices"][7:9].numpy()
2307
  self.assertEqual(revisit_frames.tolist(), [102, 103])
2308
  self.assertEqual(len(np.unique(revisit_frames)), 2)
@@ -2326,7 +2326,7 @@ class DeMemWMLatentDatasetTests(unittest.TestCase):
2326
  self.assertTrue(torch.equal(preprocessed["actions"][5:], torch.ones_like(preprocessed["actions"][5:])))
2327
  self.assertEqual(tuple(preprocessed["poses"].shape), (9, 1, 5))
2328
  self.assertIs(preprocessed["frame_memory_pose"], preprocessed["poses"])
2329
- self.assertEqual(preprocessed["frame_memory_pose"][:7, 0, 0].tolist(), [0.0, 1.0, 2.0, -6.0, -5.0, -2.0, -1.0])
2330
  self.assertEqual(tuple(preprocessed["frame_indices"].shape), (9, 1))
2331
  self.assertEqual(preprocessed["memory_segments"], sample["memory_segments"])
2332
  self.assertEqual(preprocessed["segment_lengths"], sample["memory_segments"])
@@ -2344,7 +2344,7 @@ class DeMemWMLatentDatasetTests(unittest.TestCase):
2344
  )
2345
  self.assertEqual(preprocessed["target_tensors"]["frame_indices"][:, 0].tolist(), [106, 107, 108])
2346
  self.assertEqual(preprocessed["stream_tensors"]["anchor"]["frame_indices"][:, 0].tolist(), [100, 101])
2347
- self.assertEqual(preprocessed["stream_tensors"]["dynamic"]["frame_indices"][:, 0].tolist(), [104, 105])
2348
  self.assertEqual(preprocessed["stream_tensors"]["revisit"]["frame_indices"].shape[0], 2)
2349
  self.assertEqual(tuple(preprocessed["memory_masks"]["target"].shape), (1, 3))
2350
  self.assertEqual(tuple(preprocessed["memory_masks"]["anchor"].shape), (1, 2))
 
53
  "local_context_exclusion_frames": 2,
54
  "plucker_moment_radius": 30.0,
55
  "anchor_diverse_selection": False,
56
+ "pose_preselect_topk": 32,
57
+ "candidate_chunk_size": 0,
58
  "dynamic": _dynamic_cfg(),
59
  }
60
  cfg.update(overrides)
 
217
  self.assertIs(cfg.memory_selection.causal, True)
218
  self.assertEqual(cfg.memory_selection.dynamic.selection_policy, "multiview")
219
  self.assertEqual(cfg.memory_selection.dynamic.multiview_selector, "fov_greedy")
220
+ self.assertEqual(cfg.memory_selection.pose_preselect_topk, 32)
221
+ self.assertEqual(cfg.memory_selection.candidate_chunk_size, 0)
222
 
223
  def test_revisit_uses_sampled_fov_selection(self):
224
  poses = np.array(
 
551
  def test_dynamic_multiview_provided_fov_pool_keeps_excluded_reference_coverage(self):
552
  import datasets.video.memory_selection as memory_selection
553
 
554
+ poses = _poses(8)
555
  cfg = _selection_cfg(dynamic=_dynamic_cfg("multiview", multiview_selector="fov_greedy"))
556
  pool = _fov_pool(
557
  [0, 2, 3],
 
569
  ):
570
  selected = memory_selection._select_dynamic_multiview(
571
  poses,
572
+ np.asarray([7], dtype=np.int64),
573
  cfg,
574
  count=1,
575
  excluded=np.asarray([0], dtype=np.int64),
 
587
  default_cfg = _selection_cfg(dynamic=_dynamic_cfg("multiview", multiview_selector="fov_greedy"))
588
  noncausal_cfg = _selection_cfg(causal=False, dynamic=_dynamic_cfg("multiview", multiview_selector="fov_greedy"))
589
  cases = [
590
+ (default_cfg, "training", np.asarray([5], dtype=np.int64), [1, 2], [1, 2]),
591
+ (noncausal_cfg, "training", np.asarray([3], dtype=np.int64), [4, 5, 6, 7], [6, 7]),
592
+ (noncausal_cfg, "validation", np.asarray([5], dtype=np.int64), [1, 2], [1, 2]),
593
+ (noncausal_cfg, "test", np.asarray([5], dtype=np.int64), [1, 2], [1, 2]),
594
  ]
595
 
596
  def fake_select(pool, count, **kwargs):
 
619
  first = memory_selection._select_dynamic_multiview(provided_poses, np.asarray([5], dtype=np.int64), default_cfg, count=2, **kwargs)
620
  second = memory_selection._select_dynamic_multiview(provided_poses, np.asarray([5], dtype=np.int64), default_cfg, count=2, **kwargs)
621
 
622
+ self.assertEqual(first.tolist(), [2])
623
  self.assertEqual(second.tolist(), first.tolist())
624
  self.assertTrue(set(first.tolist()).isdisjoint({0, 1}))
625
 
 
785
  indices, masks = select_memory_indices(poses, np.array([6, 7, 8]), _selection_cfg())
786
 
787
  self.assertEqual(indices["anchor"].tolist(), [0, 1])
788
+ self.assertEqual(indices["dynamic"].tolist(), [2, 3])
789
  for key in ("anchor", "dynamic", "revisit"):
790
  self.assertTrue(np.all(indices[key][masks[key]] < 6))
791
 
792
+ def test_recent_dynamic_excludes_anchor_inside_local_context(self):
793
  poses = _poses(8)
794
  cfg = _selection_cfg(
795
  max_anchor_frames=1,
 
808
  )
809
 
810
  self.assertEqual(indices["anchor"].tolist(), [5])
811
+ self.assertEqual(indices["dynamic"].tolist(), [3])
812
  self.assertEqual(masks["anchor"].tolist(), [True])
813
  self.assertEqual(masks["dynamic"].tolist(), [True])
814
  self.assertTrue(np.all(indices["dynamic"][masks["dynamic"]] < 6))
 
851
  )
852
 
853
  selected = indices["dynamic"][masks["dynamic"]]
854
+ self.assertEqual(selected.tolist(), [1])
855
  self.assertTrue(np.all(selected < 5))
856
 
857
  def test_event_triggered_dynamic_noncausal_stream_can_select_future(self):
 
873
  )
874
 
875
  selected = indices["dynamic"][masks["dynamic"]]
876
+ self.assertEqual(selected.tolist(), [1, 7, 9])
877
  self.assertTrue(np.any(selected > 5))
878
 
879
  def test_event_triggered_dynamic_eval_stream_stays_past_when_noncausal(self):
 
897
  )
898
 
899
  selected = indices["dynamic"][masks["dynamic"]]
900
+ self.assertEqual(selected.tolist(), [1])
901
  self.assertTrue(np.all(selected < 5))
902
 
903
  def test_event_triggered_dynamic_can_duplicate_anchor_and_revisit(self):
 
923
 
924
  self.assertEqual(indices["anchor"].tolist(), [0])
925
  self.assertEqual(indices["revisit"].tolist(), [0, 5])
926
+ self.assertEqual(indices["dynamic"].tolist(), [0, -1])
927
+ self.assertEqual(masks["dynamic"].tolist(), [True, False])
928
 
929
  def test_recent_dynamic_remains_past_only_when_memory_selection_is_noncausal(self):
930
  poses = _poses(10)
 
944
  dynamic_stream=np.asarray([6, 7, 8, 9], dtype=np.int64),
945
  )
946
 
947
+ self.assertEqual(indices["dynamic"].tolist(), [2, 3])
948
  self.assertEqual(masks["dynamic"].tolist(), [True, True])
949
  self.assertTrue(np.all(indices["dynamic"][masks["dynamic"]] < 6))
950
 
 
2194
 
2195
  self.assertEqual(dataset.context_length, 4)
2196
  self.assertEqual(len(dataset), 112 - (100 + 4 + 3) + 1)
2197
+ self.assertEqual(sample["frame_indices"].tolist(), [106, 107, 108, 102, 105, 102, 103])
2198
  self.assertTrue(sample["memory_masks"]["anchor"].all().item())
2199
  self.assertTrue(sample["memory_masks"]["dynamic"].all().item())
2200
  self.assertEqual(tuple(sample["memory_masks"]["revisit"].shape), (0,))
 
2302
  self.assertEqual(tuple(sample["latents"].shape), (9, 1, 1, 2))
2303
  self.assertEqual(sample["frame_indices"][:3].tolist(), [106, 107, 108])
2304
  self.assertEqual(sample["frame_indices"][3:5].tolist(), [100, 101])
2305
+ self.assertEqual(sample["frame_indices"][5:7].tolist(), [102, 103])
2306
  revisit_frames = sample["frame_indices"][7:9].numpy()
2307
  self.assertEqual(revisit_frames.tolist(), [102, 103])
2308
  self.assertEqual(len(np.unique(revisit_frames)), 2)
 
2326
  self.assertTrue(torch.equal(preprocessed["actions"][5:], torch.ones_like(preprocessed["actions"][5:])))
2327
  self.assertEqual(tuple(preprocessed["poses"].shape), (9, 1, 5))
2328
  self.assertIs(preprocessed["frame_memory_pose"], preprocessed["poses"])
2329
+ self.assertEqual(preprocessed["frame_memory_pose"][:7, 0, 0].tolist(), [0.0, 1.0, 2.0, -6.0, -5.0, -4.0, -3.0])
2330
  self.assertEqual(tuple(preprocessed["frame_indices"].shape), (9, 1))
2331
  self.assertEqual(preprocessed["memory_segments"], sample["memory_segments"])
2332
  self.assertEqual(preprocessed["segment_lengths"], sample["memory_segments"])
 
2344
  )
2345
  self.assertEqual(preprocessed["target_tensors"]["frame_indices"][:, 0].tolist(), [106, 107, 108])
2346
  self.assertEqual(preprocessed["stream_tensors"]["anchor"]["frame_indices"][:, 0].tolist(), [100, 101])
2347
+ self.assertEqual(preprocessed["stream_tensors"]["dynamic"]["frame_indices"][:, 0].tolist(), [102, 103])
2348
  self.assertEqual(preprocessed["stream_tensors"]["revisit"]["frame_indices"].shape[0], 2)
2349
  self.assertEqual(tuple(preprocessed["memory_masks"]["target"].shape), (1, 3))
2350
  self.assertEqual(tuple(preprocessed["memory_masks"]["anchor"].shape), (1, 2))