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 |
-
|
| 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:
|
| 35 |
-
candidate_chunk_size:
|
| 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
|
| 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 |
-
|
| 139 |
-
|
| 140 |
-
|
| 141 |
-
|
| 142 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 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",
|
| 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",
|
| 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 |
-
|
| 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",
|
| 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 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 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":
|
| 57 |
-
"candidate_chunk_size":
|
| 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,
|
| 221 |
-
self.assertEqual(cfg.memory_selection.candidate_chunk_size,
|
| 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(
|
| 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([
|
| 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
|
| 591 |
-
(noncausal_cfg, "training", np.asarray([3], dtype=np.int64), [
|
| 592 |
-
(noncausal_cfg, "validation", np.asarray([
|
| 593 |
-
(noncausal_cfg, "test", np.asarray([
|
| 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
|
| 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(), [
|
| 789 |
for key in ("anchor", "dynamic", "revisit"):
|
| 790 |
self.assertTrue(np.all(indices[key][masks[key]] < 6))
|
| 791 |
|
| 792 |
-
def
|
| 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(), [
|
| 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
|
| 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(), [
|
| 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
|
| 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,
|
| 927 |
-
self.
|
| 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(), [
|
| 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,
|
| 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(), [
|
| 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, -
|
| 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(), [
|
| 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))
|