Allow noncausal DeMemWM dynamic events
Browse files
.exp_artifact/dememwm_future_memory_selection_plan.md
CHANGED
|
@@ -274,7 +274,7 @@ Allow noncausal DeMemWM revisit selection
|
|
| 274 |
|
| 275 |
## Substep 3: Enable Future Event-Triggered Dynamic Selection
|
| 276 |
|
| 277 |
-
Status: `[
|
| 278 |
|
| 279 |
Goal:
|
| 280 |
|
|
|
|
| 274 |
|
| 275 |
## Substep 3: Enable Future Event-Triggered Dynamic Selection
|
| 276 |
|
| 277 |
+
Status: `[x]`
|
| 278 |
|
| 279 |
Goal:
|
| 280 |
|
datasets/video/memory_selection.py
CHANGED
|
@@ -883,12 +883,21 @@ def select_memory_indices(
|
|
| 883 |
)
|
| 884 |
|
| 885 |
if policy == "event_triggered":
|
|
|
|
| 886 |
if dynamic_stream is not None:
|
| 887 |
-
|
| 888 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 889 |
stream = np.asarray(dynamic_stream, dtype=np.int64)
|
| 890 |
-
|
| 891 |
-
|
|
|
|
|
|
|
|
|
|
| 892 |
else:
|
| 893 |
dynamic = _select_dynamic_by_policy(
|
| 894 |
target_start,
|
|
@@ -898,8 +907,7 @@ def select_memory_indices(
|
|
| 898 |
latents=latents,
|
| 899 |
actions=actions,
|
| 900 |
min_candidate_frame=min_candidate_frame,
|
| 901 |
-
reference_frames=
|
| 902 |
-
excluded=np.concatenate([anchor, revisit]) if len(anchor) or len(revisit) else None,
|
| 903 |
)
|
| 904 |
|
| 905 |
_write_segment(indices, masks, "anchor", anchor)
|
|
|
|
| 883 |
)
|
| 884 |
|
| 885 |
if policy == "event_triggered":
|
| 886 |
+
dynamic_references = revisit if len(revisit) > 0 else target_positions
|
| 887 |
if dynamic_stream is not None:
|
| 888 |
+
candidates = _memory_candidate_frames(
|
| 889 |
+
len(poses),
|
| 890 |
+
target_positions,
|
| 891 |
+
cfg,
|
| 892 |
+
split,
|
| 893 |
+
min_candidate_frame=min_candidate_frame,
|
| 894 |
+
)
|
| 895 |
stream = np.asarray(dynamic_stream, dtype=np.int64)
|
| 896 |
+
if len(candidates) > 0:
|
| 897 |
+
eligible_stream = stream[np.isin(stream, candidates)]
|
| 898 |
+
else:
|
| 899 |
+
eligible_stream = np.empty((0,), dtype=np.int64)
|
| 900 |
+
dynamic = _select_dynamic_from_stream(eligible_stream, dynamic_references, counts["dynamic"])
|
| 901 |
else:
|
| 902 |
dynamic = _select_dynamic_by_policy(
|
| 903 |
target_start,
|
|
|
|
| 907 |
latents=latents,
|
| 908 |
actions=actions,
|
| 909 |
min_candidate_frame=min_candidate_frame,
|
| 910 |
+
reference_frames=dynamic_references,
|
|
|
|
| 911 |
)
|
| 912 |
|
| 913 |
_write_segment(indices, masks, "anchor", anchor)
|
tests/test_dememwm_latent_dataset.py
CHANGED
|
@@ -384,6 +384,120 @@ class MemorySelectionTests(unittest.TestCase):
|
|
| 384 |
self.assertEqual(indices["anchor"].tolist(), [2, 5])
|
| 385 |
self.assertEqual(masks["anchor"].tolist(), [True, True])
|
| 386 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 387 |
|
| 388 |
def test_event_triggered_dynamic_selects_first_stable_post_event_frame(self):
|
| 389 |
poses = np.zeros((10, 5), dtype=np.float32)
|
|
|
|
| 384 |
self.assertEqual(indices["anchor"].tolist(), [2, 5])
|
| 385 |
self.assertEqual(masks["anchor"].tolist(), [True, True])
|
| 386 |
|
| 387 |
+
def test_event_triggered_dynamic_causal_stream_stays_before_target(self):
|
| 388 |
+
poses = _poses(12)
|
| 389 |
+
cfg = _selection_cfg(
|
| 390 |
+
max_anchor_frames=0,
|
| 391 |
+
max_dynamic_frames=3,
|
| 392 |
+
max_revisit_frames=0,
|
| 393 |
+
dynamic=_dynamic_cfg("event_triggered"),
|
| 394 |
+
)
|
| 395 |
+
|
| 396 |
+
indices, masks = select_memory_indices(
|
| 397 |
+
poses,
|
| 398 |
+
np.array([5]),
|
| 399 |
+
cfg,
|
| 400 |
+
split="training",
|
| 401 |
+
dynamic_stream=np.asarray([1, 4, 5, 7, 9], dtype=np.int64),
|
| 402 |
+
)
|
| 403 |
+
|
| 404 |
+
selected = indices["dynamic"][masks["dynamic"]]
|
| 405 |
+
self.assertEqual(selected.tolist(), [1, 4])
|
| 406 |
+
self.assertTrue(np.all(selected < 5))
|
| 407 |
+
|
| 408 |
+
def test_event_triggered_dynamic_noncausal_stream_can_select_future(self):
|
| 409 |
+
poses = _poses(12)
|
| 410 |
+
cfg = _selection_cfg(
|
| 411 |
+
causal=False,
|
| 412 |
+
max_anchor_frames=0,
|
| 413 |
+
max_dynamic_frames=3,
|
| 414 |
+
max_revisit_frames=0,
|
| 415 |
+
dynamic=_dynamic_cfg("event_triggered"),
|
| 416 |
+
)
|
| 417 |
+
|
| 418 |
+
indices, masks = select_memory_indices(
|
| 419 |
+
poses,
|
| 420 |
+
np.array([5]),
|
| 421 |
+
cfg,
|
| 422 |
+
split="training",
|
| 423 |
+
dynamic_stream=np.asarray([1, 4, 5, 7, 9], dtype=np.int64),
|
| 424 |
+
)
|
| 425 |
+
|
| 426 |
+
selected = indices["dynamic"][masks["dynamic"]]
|
| 427 |
+
self.assertEqual(selected.tolist(), [4, 5, 7])
|
| 428 |
+
self.assertTrue(np.any(selected > 5))
|
| 429 |
+
|
| 430 |
+
def test_event_triggered_dynamic_eval_stream_stays_past_when_noncausal(self):
|
| 431 |
+
poses = _poses(12)
|
| 432 |
+
cfg = _selection_cfg(
|
| 433 |
+
causal=False,
|
| 434 |
+
max_anchor_frames=0,
|
| 435 |
+
max_dynamic_frames=3,
|
| 436 |
+
max_revisit_frames=0,
|
| 437 |
+
dynamic=_dynamic_cfg("event_triggered"),
|
| 438 |
+
)
|
| 439 |
+
|
| 440 |
+
for split in ("validation", "test"):
|
| 441 |
+
with self.subTest(split=split):
|
| 442 |
+
indices, masks = select_memory_indices(
|
| 443 |
+
poses,
|
| 444 |
+
np.array([5]),
|
| 445 |
+
cfg,
|
| 446 |
+
split=split,
|
| 447 |
+
dynamic_stream=np.asarray([1, 4, 5, 7, 9], dtype=np.int64),
|
| 448 |
+
)
|
| 449 |
+
|
| 450 |
+
selected = indices["dynamic"][masks["dynamic"]]
|
| 451 |
+
self.assertEqual(selected.tolist(), [1, 4])
|
| 452 |
+
self.assertTrue(np.all(selected < 5))
|
| 453 |
+
|
| 454 |
+
def test_event_triggered_dynamic_can_duplicate_anchor_and_revisit(self):
|
| 455 |
+
import datasets.video.memory_selection as memory_selection
|
| 456 |
+
|
| 457 |
+
poses = _poses(8)
|
| 458 |
+
cfg = _selection_cfg(
|
| 459 |
+
max_anchor_frames=1,
|
| 460 |
+
max_dynamic_frames=2,
|
| 461 |
+
max_revisit_frames=2,
|
| 462 |
+
anchor_diverse_selection=False,
|
| 463 |
+
dynamic=_dynamic_cfg("event_triggered"),
|
| 464 |
+
)
|
| 465 |
+
|
| 466 |
+
with mock.patch.object(memory_selection, "_select_revisit", return_value=np.asarray([0, 5], dtype=np.int64)):
|
| 467 |
+
indices, masks = select_memory_indices(
|
| 468 |
+
poses,
|
| 469 |
+
np.array([6]),
|
| 470 |
+
cfg,
|
| 471 |
+
split="training",
|
| 472 |
+
dynamic_stream=np.asarray([0, 5], dtype=np.int64),
|
| 473 |
+
)
|
| 474 |
+
|
| 475 |
+
self.assertEqual(indices["anchor"].tolist(), [0])
|
| 476 |
+
self.assertEqual(indices["revisit"].tolist(), [0, 5])
|
| 477 |
+
self.assertEqual(indices["dynamic"].tolist(), [0, 5])
|
| 478 |
+
self.assertTrue(masks["dynamic"].all())
|
| 479 |
+
|
| 480 |
+
def test_recent_dynamic_remains_past_only_when_memory_selection_is_noncausal(self):
|
| 481 |
+
poses = _poses(10)
|
| 482 |
+
cfg = _selection_cfg(
|
| 483 |
+
causal=False,
|
| 484 |
+
max_anchor_frames=0,
|
| 485 |
+
max_dynamic_frames=2,
|
| 486 |
+
max_revisit_frames=0,
|
| 487 |
+
dynamic=_dynamic_cfg("recent"),
|
| 488 |
+
)
|
| 489 |
+
|
| 490 |
+
indices, masks = select_memory_indices(
|
| 491 |
+
poses,
|
| 492 |
+
np.array([6]),
|
| 493 |
+
cfg,
|
| 494 |
+
split="training",
|
| 495 |
+
dynamic_stream=np.asarray([6, 7, 8, 9], dtype=np.int64),
|
| 496 |
+
)
|
| 497 |
+
|
| 498 |
+
self.assertEqual(indices["dynamic"].tolist(), [4, 5])
|
| 499 |
+
self.assertEqual(masks["dynamic"].tolist(), [True, True])
|
| 500 |
+
self.assertTrue(np.all(indices["dynamic"][masks["dynamic"]] < 6))
|
| 501 |
|
| 502 |
def test_event_triggered_dynamic_selects_first_stable_post_event_frame(self):
|
| 503 |
poses = np.zeros((10, 5), dtype=np.float32)
|