BonanDing commited on
Commit
072e8f7
·
1 Parent(s): 0b42a66

Implement DeMemWM batch contract

Browse files
algorithms/dememwm/df_video.py CHANGED
@@ -1,3 +1,4 @@
 
1
  import os
2
  import random
3
  import math
@@ -24,6 +25,53 @@ from .models.pose_prediction import PosePredictionNet
24
  import glob
25
 
26
  # Utility Functions
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
27
  def euler_to_rotation_matrix(pitch, yaw):
28
  """
29
  Convert pitch and yaw angles (in radians) to a 3x3 rotation matrix.
@@ -417,7 +465,12 @@ class WorldMemMinecraft(DiffusionForcingBase):
417
  Returns:
418
  dict: A dictionary containing the training loss.
419
  """
420
- xs, conditions, pose_conditions, c2w_mat, frame_idx = self._preprocess_batch(batch)
 
 
 
 
 
421
 
422
  if self.use_plucker:
423
  if self.relative_embedding:
@@ -551,6 +604,8 @@ class WorldMemMinecraft(DiffusionForcingBase):
551
  self.validation_step_outputs.clear()
552
 
553
  def _preprocess_batch(self, batch):
 
 
554
 
555
  xs, conditions, pose_conditions, frame_index = batch
556
 
@@ -715,7 +770,12 @@ class WorldMemMinecraft(DiffusionForcingBase):
715
  """
716
  # Preprocess the input batch
717
  memory_condition_length = self.memory_condition_length
718
- xs_raw, conditions, pose_conditions, c2w_mat, frame_idx = self._preprocess_batch(batch)
 
 
 
 
 
719
 
720
 
721
  # Encode frames in chunks if necessary
 
1
+ from collections.abc import Mapping
2
  import os
3
  import random
4
  import math
 
25
  import glob
26
 
27
  # Utility Functions
28
+ _DEMEMWM_SEGMENT_KEYS = ("target", "anchor", "dynamic", "revisit")
29
+
30
+
31
+ def _segment_value_to_int(value, key):
32
+ if torch.is_tensor(value):
33
+ flat = value.reshape(-1)
34
+ if flat.numel() == 0:
35
+ raise ValueError(f"memory_segments['{key}'] is empty")
36
+ first = flat[0]
37
+ if flat.numel() > 1 and not bool(torch.all(flat == first).item()):
38
+ raise ValueError(f"memory_segments['{key}'] must be identical across the batch")
39
+ return int(first.item())
40
+ if isinstance(value, (list, tuple)):
41
+ values = [_segment_value_to_int(item, key) for item in value]
42
+ if not values:
43
+ raise ValueError(f"memory_segments['{key}'] is empty")
44
+ if any(item != values[0] for item in values[1:]):
45
+ raise ValueError(f"memory_segments['{key}'] must be identical across the batch")
46
+ return values[0]
47
+ return int(value)
48
+
49
+
50
+ def _preprocess_dememwm_latent_batch(batch):
51
+ memory_segments = {
52
+ key: _segment_value_to_int(batch["memory_segments"][key], key)
53
+ for key in _DEMEMWM_SEGMENT_KEYS
54
+ }
55
+ memory_masks = {key: batch["memory_masks"][key] for key in _DEMEMWM_SEGMENT_KEYS}
56
+
57
+ # Latent dataset batches are already VAE-encoded: B x T_all x C x H_lat x W_lat.
58
+ latents = rearrange(batch["latents"], "b t c ... -> t b c ...").contiguous()
59
+ actions = rearrange(batch["actions"], "b t d -> t b d").contiguous()
60
+ poses = rearrange(batch["poses"], "b t d -> t b d").contiguous()
61
+ frame_indices = rearrange(batch["frame_indices"], "b t -> t b").contiguous()
62
+
63
+ # Keep original image H/W for later ray geometry; latent H/W is not a substitute.
64
+ return {
65
+ "latents": latents,
66
+ "actions": actions,
67
+ "poses": poses,
68
+ "frame_indices": frame_indices,
69
+ "memory_segments": memory_segments,
70
+ "memory_masks": memory_masks,
71
+ "image_hw": batch["image_hw"],
72
+ }
73
+
74
+
75
  def euler_to_rotation_matrix(pitch, yaw):
76
  """
77
  Convert pitch and yaw angles (in radians) to a 3x3 rotation matrix.
 
465
  Returns:
466
  dict: A dictionary containing the training loss.
467
  """
468
+ preprocessed = self._preprocess_batch(batch)
469
+ if isinstance(preprocessed, Mapping):
470
+ raise NotImplementedError(
471
+ "DeMemWM latent training_step needs Step 5.2/5.5 target/memory split before diffusion forward."
472
+ )
473
+ xs, conditions, pose_conditions, c2w_mat, frame_idx = preprocessed
474
 
475
  if self.use_plucker:
476
  if self.relative_embedding:
 
604
  self.validation_step_outputs.clear()
605
 
606
  def _preprocess_batch(self, batch):
607
+ if isinstance(batch, Mapping):
608
+ return _preprocess_dememwm_latent_batch(batch)
609
 
610
  xs, conditions, pose_conditions, frame_index = batch
611
 
 
770
  """
771
  # Preprocess the input batch
772
  memory_condition_length = self.memory_condition_length
773
+ preprocessed = self._preprocess_batch(batch)
774
+ if isinstance(preprocessed, Mapping):
775
+ raise NotImplementedError(
776
+ "DeMemWM latent validation needs Step 5.6 target-only sampling before evaluation."
777
+ )
778
+ xs_raw, conditions, pose_conditions, c2w_mat, frame_idx = preprocessed
779
 
780
 
781
  # Encode frames in chunks if necessary
tests/test_dememwm_latent_dataset.py CHANGED
@@ -182,6 +182,22 @@ class DeMemWMLatentDatasetTests(unittest.TestCase):
182
  self.assertTrue(sample["memory_masks"]["revisit"].all().item())
183
  self.assertEqual(sample["image_hw"].tolist(), [360, 640])
184
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
185
 
186
  if __name__ == "__main__":
187
  unittest.main()
 
182
  self.assertTrue(sample["memory_masks"]["revisit"].all().item())
183
  self.assertEqual(sample["image_hw"].tolist(), [360, 640])
184
 
185
+ from torch.utils.data import default_collate
186
+ from algorithms.dememwm.df_video import _preprocess_dememwm_latent_batch
187
+
188
+ preprocessed = _preprocess_dememwm_latent_batch(default_collate([sample]))
189
+ self.assertEqual(tuple(preprocessed["latents"].shape), (9, 1, 1, 1, 2))
190
+ self.assertEqual(tuple(preprocessed["actions"].shape), (9, 1, 25))
191
+ self.assertEqual(tuple(preprocessed["poses"].shape), (9, 1, 5))
192
+ self.assertEqual(tuple(preprocessed["frame_indices"].shape), (9, 1))
193
+ self.assertEqual(preprocessed["memory_segments"], sample["memory_segments"])
194
+ self.assertTrue(all(isinstance(value, int) for value in preprocessed["memory_segments"].values()))
195
+ self.assertEqual(tuple(preprocessed["memory_masks"]["target"].shape), (1, 3))
196
+ self.assertEqual(tuple(preprocessed["memory_masks"]["anchor"].shape), (1, 2))
197
+ self.assertEqual(tuple(preprocessed["memory_masks"]["dynamic"].shape), (1, 2))
198
+ self.assertEqual(tuple(preprocessed["memory_masks"]["revisit"].shape), (1, 2))
199
+ self.assertEqual(preprocessed["image_hw"].tolist(), [[360, 640]])
200
+
201
 
202
  if __name__ == "__main__":
203
  unittest.main()