Restore revisit local context exclusion
Browse files
datasets/video/memory_selection.py
CHANGED
|
@@ -32,6 +32,17 @@ def _memory_candidate_frames(num_frames, target_positions, cfg, split, min_candi
|
|
| 32 |
return np.arange(min_candidate_frame, stop, dtype=np.int64)
|
| 33 |
|
| 34 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 35 |
def _as_pose_array(poses) -> np.ndarray:
|
| 36 |
poses = np.asarray(poses, dtype=np.float32)
|
| 37 |
if poses.ndim != 2 or poses.shape[1] < 5:
|
|
@@ -795,6 +806,10 @@ def _select_revisit(
|
|
| 795 |
if len(candidates) == 0:
|
| 796 |
return np.empty((0,), dtype=np.int64)
|
| 797 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 798 |
if len(excluded) > 0:
|
| 799 |
candidates = candidates[~np.isin(candidates, excluded)]
|
| 800 |
if len(candidates) == 0:
|
|
@@ -828,7 +843,7 @@ def select_memory_indices(
|
|
| 828 |
anchor_candidate_stop=None,
|
| 829 |
dynamic_stream=None,
|
| 830 |
):
|
| 831 |
-
"""Select
|
| 832 |
|
| 833 |
poses = _as_pose_array(poses)
|
| 834 |
target_positions = np.asarray(target_positions, dtype=np.int64)
|
|
|
|
| 32 |
return np.arange(min_candidate_frame, stop, dtype=np.int64)
|
| 33 |
|
| 34 |
|
| 35 |
+
def _exclude_revisit_local_context(candidates: np.ndarray, target_positions: np.ndarray, cfg) -> np.ndarray:
|
| 36 |
+
exclusion = max(0, int(cfg_get(cfg, "local_context_exclusion_frames", 8)))
|
| 37 |
+
if exclusion <= 0 or len(candidates) == 0 or len(target_positions) == 0:
|
| 38 |
+
return candidates
|
| 39 |
+
|
| 40 |
+
target_start = int(target_positions[0])
|
| 41 |
+
target_stop = int(target_positions[-1]) + 1
|
| 42 |
+
local_start = max(0, target_start - exclusion)
|
| 43 |
+
return candidates[(candidates < local_start) | (candidates >= target_stop)]
|
| 44 |
+
|
| 45 |
+
|
| 46 |
def _as_pose_array(poses) -> np.ndarray:
|
| 47 |
poses = np.asarray(poses, dtype=np.float32)
|
| 48 |
if poses.ndim != 2 or poses.shape[1] < 5:
|
|
|
|
| 806 |
if len(candidates) == 0:
|
| 807 |
return np.empty((0,), dtype=np.int64)
|
| 808 |
|
| 809 |
+
candidates = _exclude_revisit_local_context(candidates, target_positions, cfg)
|
| 810 |
+
if len(candidates) == 0:
|
| 811 |
+
return np.empty((0,), dtype=np.int64)
|
| 812 |
+
|
| 813 |
if len(excluded) > 0:
|
| 814 |
candidates = candidates[~np.isin(candidates, excluded)]
|
| 815 |
if len(candidates) == 0:
|
|
|
|
| 843 |
anchor_candidate_stop=None,
|
| 844 |
dynamic_stream=None,
|
| 845 |
):
|
| 846 |
+
"""Select memory indices and masks for [anchor][dynamic][revisit]."""
|
| 847 |
|
| 848 |
poses = _as_pose_array(poses)
|
| 849 |
target_positions = np.asarray(target_positions, dtype=np.int64)
|
tests/test_dememwm_latent_dataset.py
CHANGED
|
@@ -141,6 +141,30 @@ class MemorySelectionTests(unittest.TestCase):
|
|
| 141 |
|
| 142 |
self.assertEqual(candidates.tolist(), [1, 2])
|
| 143 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 144 |
def test_dememwm_latent_config_has_dataset_side_memory_causal_default(self):
|
| 145 |
config_path = Path(__file__).resolve().parents[1] / "configurations" / "dataset" / "video_minecraft_dememwm_latent.yaml"
|
| 146 |
|
|
@@ -279,11 +303,12 @@ class MemorySelectionTests(unittest.TestCase):
|
|
| 279 |
selected = indices["revisit"][masks["revisit"]]
|
| 280 |
self.assertIn(6, selected.tolist())
|
| 281 |
|
| 282 |
-
def
|
| 283 |
poses = np.zeros((8, 5), dtype=np.float32)
|
| 284 |
poses[:, 0] = 100.0
|
| 285 |
poses[:, 4] = 180.0
|
| 286 |
poses[4] = np.asarray([0, 0, 0, 0, 0], dtype=np.float32)
|
|
|
|
| 287 |
cfg = _selection_cfg(
|
| 288 |
causal=False,
|
| 289 |
max_anchor_frames=0,
|
|
@@ -300,7 +325,7 @@ class MemorySelectionTests(unittest.TestCase):
|
|
| 300 |
rng=np.random.default_rng(0),
|
| 301 |
)
|
| 302 |
|
| 303 |
-
self.assertEqual(indices["revisit"].tolist(), [
|
| 304 |
self.assertEqual(masks["revisit"].tolist(), [True])
|
| 305 |
|
| 306 |
def test_validation_and_test_noncausal_revisit_stays_past_only(self):
|
|
@@ -324,8 +349,8 @@ class MemorySelectionTests(unittest.TestCase):
|
|
| 324 |
with self.subTest(split=split), mock.patch.object(memory_selection, "_select_by_point_union", side_effect=fake_point_union):
|
| 325 |
indices, masks = select_memory_indices(poses, np.array([4]), cfg, split=split)
|
| 326 |
|
| 327 |
-
self.assertEqual([candidates.tolist() for candidates in seen_candidates], [[0, 1
|
| 328 |
-
self.assertEqual(indices["revisit"].tolist(), [
|
| 329 |
self.assertEqual(masks["revisit"].tolist(), [True])
|
| 330 |
|
| 331 |
def test_revisit_can_duplicate_anchor_and_dynamic_when_scored_best(self):
|
|
@@ -340,6 +365,7 @@ class MemorySelectionTests(unittest.TestCase):
|
|
| 340 |
max_dynamic_frames=1,
|
| 341 |
max_revisit_frames=2,
|
| 342 |
pose_similarity_threshold=0.95,
|
|
|
|
| 343 |
)
|
| 344 |
|
| 345 |
indices, masks = select_memory_indices(
|
|
|
|
| 141 |
|
| 142 |
self.assertEqual(candidates.tolist(), [1, 2])
|
| 143 |
|
| 144 |
+
def test_revisit_excludes_local_context_and_target_window_but_keeps_future(self):
|
| 145 |
+
import datasets.video.memory_selection as memory_selection
|
| 146 |
+
|
| 147 |
+
poses = _poses(12)
|
| 148 |
+
cfg = _selection_cfg(
|
| 149 |
+
causal=False,
|
| 150 |
+
max_anchor_frames=0,
|
| 151 |
+
max_dynamic_frames=0,
|
| 152 |
+
max_revisit_frames=2,
|
| 153 |
+
local_context_exclusion_frames=2,
|
| 154 |
+
)
|
| 155 |
+
seen_candidates = []
|
| 156 |
+
|
| 157 |
+
def fake_pose_similarity(poses_arg, candidates, target_positions, cfg_arg, count, rng=None):
|
| 158 |
+
seen_candidates.append(candidates.copy())
|
| 159 |
+
return np.asarray([1, 8], dtype=np.int64)
|
| 160 |
+
|
| 161 |
+
with mock.patch.object(memory_selection, "_select_by_pose_similarity", side_effect=fake_pose_similarity):
|
| 162 |
+
indices, masks = select_memory_indices(poses, np.array([4, 5, 6, 7]), cfg, split="training")
|
| 163 |
+
|
| 164 |
+
self.assertEqual([candidates.tolist() for candidates in seen_candidates], [[0, 1, 8, 9, 10, 11]])
|
| 165 |
+
self.assertEqual(indices["revisit"].tolist(), [1, 8])
|
| 166 |
+
self.assertEqual(masks["revisit"].tolist(), [True, True])
|
| 167 |
+
|
| 168 |
def test_dememwm_latent_config_has_dataset_side_memory_causal_default(self):
|
| 169 |
config_path = Path(__file__).resolve().parents[1] / "configurations" / "dataset" / "video_minecraft_dememwm_latent.yaml"
|
| 170 |
|
|
|
|
| 303 |
selected = indices["revisit"][masks["revisit"]]
|
| 304 |
self.assertIn(6, selected.tolist())
|
| 305 |
|
| 306 |
+
def test_training_noncausal_revisit_excludes_target_window_frame(self):
|
| 307 |
poses = np.zeros((8, 5), dtype=np.float32)
|
| 308 |
poses[:, 0] = 100.0
|
| 309 |
poses[:, 4] = 180.0
|
| 310 |
poses[4] = np.asarray([0, 0, 0, 0, 0], dtype=np.float32)
|
| 311 |
+
poses[6] = np.asarray([0, 0, 0, 0, 0], dtype=np.float32)
|
| 312 |
cfg = _selection_cfg(
|
| 313 |
causal=False,
|
| 314 |
max_anchor_frames=0,
|
|
|
|
| 325 |
rng=np.random.default_rng(0),
|
| 326 |
)
|
| 327 |
|
| 328 |
+
self.assertEqual(indices["revisit"].tolist(), [6])
|
| 329 |
self.assertEqual(masks["revisit"].tolist(), [True])
|
| 330 |
|
| 331 |
def test_validation_and_test_noncausal_revisit_stays_past_only(self):
|
|
|
|
| 349 |
with self.subTest(split=split), mock.patch.object(memory_selection, "_select_by_point_union", side_effect=fake_point_union):
|
| 350 |
indices, masks = select_memory_indices(poses, np.array([4]), cfg, split=split)
|
| 351 |
|
| 352 |
+
self.assertEqual([candidates.tolist() for candidates in seen_candidates], [[0, 1]])
|
| 353 |
+
self.assertEqual(indices["revisit"].tolist(), [1])
|
| 354 |
self.assertEqual(masks["revisit"].tolist(), [True])
|
| 355 |
|
| 356 |
def test_revisit_can_duplicate_anchor_and_dynamic_when_scored_best(self):
|
|
|
|
| 365 |
max_dynamic_frames=1,
|
| 366 |
max_revisit_frames=2,
|
| 367 |
pose_similarity_threshold=0.95,
|
| 368 |
+
local_context_exclusion_frames=0,
|
| 369 |
)
|
| 370 |
|
| 371 |
indices, masks = select_memory_indices(
|