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 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 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 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 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()
|