anhtld commited on
Commit
8bc4ad0
·
verified ·
1 Parent(s): 770049b

Auto-sync: 2026-06-28 01:47:01

Browse files
dovla_cil/eval/maniskill_policy_rollout.py CHANGED
@@ -60,6 +60,7 @@ def evaluate_maniskill_policy_rollout(
60
  field_optim_trust_radius: float = 0.5,
61
  field_optim_l2_penalty: float = 0.0,
62
  retrieval_neighbors: int = 1,
 
63
  retrieval_residual_scale: float = 1.0,
64
  lattice_exclude_types: tuple[str, ...] = (),
65
  ) -> dict[str, Any]:
@@ -85,7 +86,9 @@ def evaluate_maniskill_policy_rollout(
85
  When ``selection_mode == 'retrieval_lattice'`` action proposals come from the nearest
86
  training-split state with the same task rather than the evaluated state's own lattice. This
87
  tests whether the field can use reusable intervention proposals without same-state proposal
88
- leakage.
 
 
89
 
90
  When ``selection_mode == 'retrieval_residual'`` the evaluator retrieves counterfactual
91
  action residuals (candidate minus expert action) from the nearest training-split state(s),
@@ -135,6 +138,8 @@ def evaluate_maniskill_policy_rollout(
135
  raise ValueError("field_optim_l2_penalty must be non-negative")
136
  if retrieval_neighbors <= 0:
137
  raise ValueError("retrieval_neighbors must be positive")
 
 
138
  if retrieval_residual_scale < 0:
139
  raise ValueError("retrieval_residual_scale must be non-negative")
140
  if selection_mode == "policy":
@@ -184,6 +189,7 @@ def evaluate_maniskill_policy_rollout(
184
  obs_dim=model_config.obs_dim,
185
  observation_mode=model_config.observation_mode,
186
  retrieval_neighbors=retrieval_neighbors,
 
187
  )
188
  else:
189
  cases = _attach_retrieved_residual_candidates(
@@ -193,6 +199,7 @@ def evaluate_maniskill_policy_rollout(
193
  obs_dim=model_config.obs_dim,
194
  observation_mode=model_config.observation_mode,
195
  retrieval_neighbors=retrieval_neighbors,
 
196
  )
197
  by_task: dict[str, list[_RolloutCase]] = defaultdict(list)
198
  for case in cases:
@@ -265,6 +272,9 @@ def evaluate_maniskill_policy_rollout(
265
  "retrieval_neighbors": retrieval_neighbors
266
  if selection_mode in {"retrieval_lattice", "retrieval_residual"}
267
  else 0,
 
 
 
268
  "retrieval_residual_scale": retrieval_residual_scale
269
  if selection_mode == "retrieval_residual"
270
  else 0.0,
@@ -355,6 +365,7 @@ def _attach_retrieved_lattice_candidates(
355
  obs_dim: int,
356
  observation_mode: str,
357
  retrieval_neighbors: int,
 
358
  ) -> list[_RolloutCase]:
359
  if observation_mode != "state":
360
  raise ValueError("retrieval_lattice currently supports state observations only")
@@ -394,10 +405,12 @@ def _attach_retrieved_lattice_candidates(
394
  vectorize_toy_observation(case.observation, obs_dim=obs_dim),
395
  dtype=np.float32,
396
  )
397
- nearest = sorted(
398
  candidates,
399
- key=lambda item: float(np.mean((item[1] - query) ** 2)),
400
- )[:retrieval_neighbors]
 
 
401
  source_group_ids: list[str] = []
402
  actions: list[list[list[float]]] = []
403
  candidate_types: list[str] = []
@@ -424,6 +437,7 @@ def _attach_retrieved_residual_candidates(
424
  obs_dim: int,
425
  observation_mode: str,
426
  retrieval_neighbors: int,
 
427
  ) -> list[_RolloutCase]:
428
  if observation_mode != "state":
429
  raise ValueError("retrieval_residual currently supports state observations only")
@@ -474,10 +488,12 @@ def _attach_retrieved_residual_candidates(
474
  vectorize_toy_observation(case.observation, obs_dim=obs_dim),
475
  dtype=np.float32,
476
  )
477
- nearest = sorted(
478
  candidates,
479
- key=lambda item: float(np.mean((item[1] - query) ** 2)),
480
- )[:retrieval_neighbors]
 
 
481
  source_group_ids: list[str] = []
482
  residuals: list[list[list[float]]] = []
483
  candidate_types: list[str] = []
@@ -496,6 +512,30 @@ def _attach_retrieved_residual_candidates(
496
  return output
497
 
498
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
499
  def _evaluate_task_cases(
500
  task_id: str,
501
  cases: list[_RolloutCase],
 
60
  field_optim_trust_radius: float = 0.5,
61
  field_optim_l2_penalty: float = 0.0,
62
  retrieval_neighbors: int = 1,
63
+ retrieval_metric: str = "raw",
64
  retrieval_residual_scale: float = 1.0,
65
  lattice_exclude_types: tuple[str, ...] = (),
66
  ) -> dict[str, Any]:
 
86
  When ``selection_mode == 'retrieval_lattice'`` action proposals come from the nearest
87
  training-split state with the same task rather than the evaluated state's own lattice. This
88
  tests whether the field can use reusable intervention proposals without same-state proposal
89
+ leakage. ``retrieval_metric='zscore'`` standardizes state features by the train-bank
90
+ statistics for each task before nearest-neighbor lookup; the default ``raw`` metric
91
+ preserves earlier results exactly.
92
 
93
  When ``selection_mode == 'retrieval_residual'`` the evaluator retrieves counterfactual
94
  action residuals (candidate minus expert action) from the nearest training-split state(s),
 
138
  raise ValueError("field_optim_l2_penalty must be non-negative")
139
  if retrieval_neighbors <= 0:
140
  raise ValueError("retrieval_neighbors must be positive")
141
+ if retrieval_metric not in {"raw", "zscore"}:
142
+ raise ValueError("retrieval_metric must be 'raw' or 'zscore'")
143
  if retrieval_residual_scale < 0:
144
  raise ValueError("retrieval_residual_scale must be non-negative")
145
  if selection_mode == "policy":
 
189
  obs_dim=model_config.obs_dim,
190
  observation_mode=model_config.observation_mode,
191
  retrieval_neighbors=retrieval_neighbors,
192
+ retrieval_metric=retrieval_metric,
193
  )
194
  else:
195
  cases = _attach_retrieved_residual_candidates(
 
199
  obs_dim=model_config.obs_dim,
200
  observation_mode=model_config.observation_mode,
201
  retrieval_neighbors=retrieval_neighbors,
202
+ retrieval_metric=retrieval_metric,
203
  )
204
  by_task: dict[str, list[_RolloutCase]] = defaultdict(list)
205
  for case in cases:
 
272
  "retrieval_neighbors": retrieval_neighbors
273
  if selection_mode in {"retrieval_lattice", "retrieval_residual"}
274
  else 0,
275
+ "retrieval_metric": retrieval_metric
276
+ if selection_mode in {"retrieval_lattice", "retrieval_residual"}
277
+ else "none",
278
  "retrieval_residual_scale": retrieval_residual_scale
279
  if selection_mode == "retrieval_residual"
280
  else 0.0,
 
365
  obs_dim: int,
366
  observation_mode: str,
367
  retrieval_neighbors: int,
368
+ retrieval_metric: str = "raw",
369
  ) -> list[_RolloutCase]:
370
  if observation_mode != "state":
371
  raise ValueError("retrieval_lattice currently supports state observations only")
 
405
  vectorize_toy_observation(case.observation, obs_dim=obs_dim),
406
  dtype=np.float32,
407
  )
408
+ nearest = _nearest_retrieval_entries(
409
  candidates,
410
+ query,
411
+ retrieval_neighbors=retrieval_neighbors,
412
+ retrieval_metric=retrieval_metric,
413
+ )
414
  source_group_ids: list[str] = []
415
  actions: list[list[list[float]]] = []
416
  candidate_types: list[str] = []
 
437
  obs_dim: int,
438
  observation_mode: str,
439
  retrieval_neighbors: int,
440
+ retrieval_metric: str = "raw",
441
  ) -> list[_RolloutCase]:
442
  if observation_mode != "state":
443
  raise ValueError("retrieval_residual currently supports state observations only")
 
488
  vectorize_toy_observation(case.observation, obs_dim=obs_dim),
489
  dtype=np.float32,
490
  )
491
+ nearest = _nearest_retrieval_entries(
492
  candidates,
493
+ query,
494
+ retrieval_neighbors=retrieval_neighbors,
495
+ retrieval_metric=retrieval_metric,
496
+ )
497
  source_group_ids: list[str] = []
498
  residuals: list[list[list[float]]] = []
499
  candidate_types: list[str] = []
 
512
  return output
513
 
514
 
515
+ def _nearest_retrieval_entries(
516
+ candidates: list[tuple[Any, np.ndarray, Any, Any]],
517
+ query: np.ndarray,
518
+ *,
519
+ retrieval_neighbors: int,
520
+ retrieval_metric: str,
521
+ ) -> list[tuple[Any, np.ndarray, Any, Any]]:
522
+ if retrieval_metric == "raw":
523
+ return sorted(
524
+ candidates,
525
+ key=lambda item: float(np.mean((item[1] - query) ** 2)),
526
+ )[:retrieval_neighbors]
527
+ if retrieval_metric != "zscore":
528
+ raise ValueError("retrieval_metric must be 'raw' or 'zscore'")
529
+ features = np.stack([np.asarray(item[1], dtype=np.float32) for item in candidates], axis=0)
530
+ mean = features.mean(axis=0, dtype=np.float64).astype(np.float32)
531
+ std = features.std(axis=0, dtype=np.float64).astype(np.float32)
532
+ scale = np.where(std > 1e-6, std, 1.0).astype(np.float32)
533
+ normalized_features = (features - mean) / scale
534
+ normalized_query = (np.asarray(query, dtype=np.float32) - mean) / scale
535
+ order = np.argsort(np.mean((normalized_features - normalized_query) ** 2, axis=1))
536
+ return [candidates[int(index)] for index in order[:retrieval_neighbors]]
537
+
538
+
539
  def _evaluate_task_cases(
540
  task_id: str,
541
  cases: list[_RolloutCase],