BonanDing commited on
Commit
e5cba93
·
1 Parent(s): 537f6f3

Fix DeMemWM revisit metric import

Browse files
Files changed (1) hide show
  1. algorithms/dememwm/df_video.py +156 -2
algorithms/dememwm/df_video.py CHANGED
@@ -1,5 +1,6 @@
1
- from collections.abc import Mapping
2
  import csv
 
3
  import os
4
  import random
5
  import time
@@ -27,7 +28,6 @@ from datasets.video.memory_selection import (
27
  _select_revisit,
28
  )
29
  from utils.logging_utils import log_video, get_validation_metrics_for_videos
30
- from algorithms.worldmem.revisit_consistency import RevisitPair, compute_frame_metric_rows
31
  from .df_base import DiffusionForcingBase
32
  from .models.vae import VAE_models
33
  from .models.diffusion import Diffusion
@@ -42,6 +42,160 @@ _DEMEMWM_GEOMETRY_PROJ_MARKERS = (".query_pose_proj.", ".key_pose_proj.", ".time
42
  _DEMEMWM_ADALN_MLP_MARKERS = (".r_adaLN_modulation.", ".r_mlp.")
43
 
44
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
45
  def _cfg_get(cfg, key: str, default=None):
46
  if cfg is None:
47
  return default
 
1
+ from collections.abc import Mapping, Sequence
2
  import csv
3
+ from dataclasses import dataclass
4
  import os
5
  import random
6
  import time
 
28
  _select_revisit,
29
  )
30
  from utils.logging_utils import log_video, get_validation_metrics_for_videos
 
31
  from .df_base import DiffusionForcingBase
32
  from .models.vae import VAE_models
33
  from .models.diffusion import Diffusion
 
42
  _DEMEMWM_ADALN_MLP_MARKERS = (".r_adaLN_modulation.", ".r_mlp.")
43
 
44
 
45
+ @dataclass(frozen=True)
46
+ class RevisitPair:
47
+ clip_id: str
48
+ source_index: int
49
+ target_index: int
50
+ source_frame: int
51
+ target_frame: int
52
+ gap: int
53
+ fov_overlap: float
54
+ plucker_overlap: float
55
+ position_distance: float
56
+ yaw_delta_deg: float
57
+ pitch_delta_deg: float
58
+ positional: bool
59
+
60
+
61
+ def _best_revisit_pair_by_target(pairs: Sequence[RevisitPair]) -> dict[int, RevisitPair]:
62
+ best: dict[int, RevisitPair] = {}
63
+ for pair in pairs:
64
+ rank = (float(pair.fov_overlap), float(pair.plucker_overlap), int(pair.gap), -int(pair.source_index))
65
+ current = best.get(int(pair.target_index))
66
+ if current is None:
67
+ best[int(pair.target_index)] = pair
68
+ continue
69
+ current_rank = (
70
+ float(current.fov_overlap),
71
+ float(current.plucker_overlap),
72
+ int(current.gap),
73
+ -int(current.source_index),
74
+ )
75
+ if rank > current_rank:
76
+ best[int(pair.target_index)] = pair
77
+ return best
78
+
79
+
80
+ def _metric_psnr_from_mse(mse: torch.Tensor) -> torch.Tensor:
81
+ return 10.0 * torch.log10(1.0 / mse.clamp_min(torch.finfo(mse.dtype).eps))
82
+
83
+
84
+ def _metric_central_crop(tensor: torch.Tensor, crop_fraction: float) -> torch.Tensor:
85
+ crop_fraction = float(crop_fraction)
86
+ if crop_fraction == 1.0:
87
+ return tensor
88
+ h = int(tensor.shape[-2])
89
+ w = int(tensor.shape[-1])
90
+ crop_h = max(1, int(round(h * crop_fraction)))
91
+ crop_w = max(1, int(round(w * crop_fraction)))
92
+ top = max(0, (h - crop_h) // 2)
93
+ left = max(0, (w - crop_w) // 2)
94
+ return tensor[..., top : top + crop_h, left : left + crop_w]
95
+
96
+
97
+ def _metric_lpips_scalar(lpips_model, pred: torch.Tensor, target: torch.Tensor) -> float:
98
+ if lpips_model is None:
99
+ return float("nan")
100
+ pred = torch.clamp(pred.float(), 0.0, 1.0)
101
+ target = torch.clamp(target.float(), 0.0, 1.0).to(device=pred.device)
102
+ if hasattr(lpips_model, "reset"):
103
+ lpips_model.reset()
104
+ with torch.no_grad():
105
+ try:
106
+ value = lpips_model(pred, target)
107
+ except TypeError:
108
+ lpips_model.update(pred, target)
109
+ value = lpips_model.compute()
110
+ if hasattr(lpips_model, "reset"):
111
+ lpips_model.reset()
112
+ if torch.is_tensor(value):
113
+ return float(value.detach().float().mean().cpu().item())
114
+ return float(value)
115
+
116
+
117
+ def compute_frame_metric_rows(
118
+ *,
119
+ branch: str,
120
+ clip_id: str,
121
+ pred: torch.Tensor,
122
+ gt: torch.Tensor | None,
123
+ poses: torch.Tensor | None,
124
+ pairs: Sequence[RevisitPair],
125
+ context_frames: int,
126
+ lpips_model=None,
127
+ self_crop_fraction: float = 0.50,
128
+ focal_length: float = 0.35,
129
+ compute_plucker_similarity: bool = True,
130
+ ) -> list[dict[str, object]]:
131
+ if pred.ndim == 5:
132
+ pred = pred[:, 0]
133
+ if gt is not None and gt.ndim == 5:
134
+ gt = gt[:, 0]
135
+ pred = pred.detach()
136
+ gt = None if gt is None else gt.detach().to(device=pred.device)
137
+
138
+ best_pairs = _best_revisit_pair_by_target(pairs)
139
+ gt_psnr_values = None
140
+ if gt is not None:
141
+ gt_mse = (torch.clamp(pred.float(), 0.0, 1.0) - torch.clamp(gt.float(), 0.0, 1.0)).square()
142
+ gt_psnr_values = _metric_psnr_from_mse(gt_mse.flatten(start_dim=1).mean(dim=1)).detach().cpu().tolist()
143
+
144
+ rows: list[dict[str, object]] = []
145
+ for out_index in range(int(pred.shape[0])):
146
+ frame_index = int(context_frames) + out_index
147
+ pair = best_pairs.get(frame_index)
148
+ gt_lpips = float("nan")
149
+ gt_psnr = float("nan")
150
+ if gt is not None and gt_psnr_values is not None:
151
+ gt_psnr = float(gt_psnr_values[out_index])
152
+ gt_lpips = _metric_lpips_scalar(lpips_model, pred[out_index : out_index + 1], gt[out_index : out_index + 1])
153
+
154
+ self_psnr = float("nan")
155
+ self_lpips = float("nan")
156
+ source_index = ""
157
+ gap = ""
158
+ fov_overlap = ""
159
+ plucker_overlap = ""
160
+ self_status = "not_revisit"
161
+ if pair is not None:
162
+ source_index = int(pair.source_index)
163
+ gap = int(pair.gap)
164
+ fov_overlap = float(pair.fov_overlap)
165
+ plucker_overlap = float(pair.plucker_overlap)
166
+ source_out_index = int(pair.source_index) - int(context_frames)
167
+ if 0 <= source_out_index < int(pred.shape[0]):
168
+ pred_source = _metric_central_crop(pred[source_out_index : source_out_index + 1], self_crop_fraction)
169
+ pred_target = _metric_central_crop(pred[out_index : out_index + 1], self_crop_fraction)
170
+ self_mse = (torch.clamp(pred_source.float(), 0.0, 1.0) - torch.clamp(pred_target.float(), 0.0, 1.0)).square().mean()
171
+ self_psnr = float(_metric_psnr_from_mse(self_mse.reshape(1))[0].detach().cpu().item())
172
+ self_lpips = _metric_lpips_scalar(lpips_model, pred_target, pred_source)
173
+ self_status = "central_crop"
174
+ else:
175
+ self_status = "source_before_prediction_horizon"
176
+
177
+ rows.append(
178
+ {
179
+ "branch": str(branch),
180
+ "clip_id": str(clip_id),
181
+ "frame_index": int(frame_index),
182
+ "output_index": int(out_index),
183
+ "is_revisit": pair is not None,
184
+ "source_index": source_index,
185
+ "gap": gap,
186
+ "fov_overlap": fov_overlap,
187
+ "plucker_overlap": plucker_overlap,
188
+ "gt_lpips": gt_lpips,
189
+ "gt_psnr": gt_psnr,
190
+ "self_lpips": self_lpips,
191
+ "self_psnr": self_psnr,
192
+ "self_plucker_similarity": float("nan"),
193
+ "self_consistency_status": self_status,
194
+ }
195
+ )
196
+ return rows
197
+
198
+
199
  def _cfg_get(cfg, key: str, default=None):
200
  if cfg is None:
201
  return default