Auto-sync: 2026-06-28 07:13:10
Browse files- dovla_cil/training/trainer.py +87 -12
dovla_cil/training/trainer.py
CHANGED
|
@@ -117,11 +117,14 @@ class DoVLATrainer:
|
|
| 117 |
self.output_dir = ensure_dir(config.output_dir)
|
| 118 |
self.dataset = CILDataset(config.dataset_dir)
|
| 119 |
self.policy_target_record_ids = _load_policy_target_map(config.policy_target_map)
|
|
|
|
|
|
|
|
|
|
| 120 |
self.train_group_ids, self.val_group_ids = _split_group_ids(
|
| 121 |
self.dataset.group_ids, val_fraction=config.val_fraction, seed=config.seed
|
| 122 |
)
|
| 123 |
self.policy_target_map_coverage = _policy_target_map_coverage(
|
| 124 |
-
self.policy_target_record_ids,
|
| 125 |
train_group_ids=self.train_group_ids,
|
| 126 |
val_group_ids=self.val_group_ids,
|
| 127 |
)
|
|
@@ -168,7 +171,7 @@ class DoVLATrainer:
|
|
| 168 |
|
| 169 |
def train(self) -> dict[str, Any]:
|
| 170 |
write_json(self._resolved_config(), self.output_dir / "resolved_config.json")
|
| 171 |
-
if self.policy_target_record_ids:
|
| 172 |
coverage = self.policy_target_map_coverage
|
| 173 |
print(
|
| 174 |
"policy_target_map_coverage "
|
|
@@ -292,13 +295,8 @@ class DoVLATrainer:
|
|
| 292 |
pred_reward, [record.group_id for record in records]
|
| 293 |
)
|
| 294 |
|
| 295 |
-
best_records =
|
| 296 |
-
records,
|
| 297 |
-
candidate_types=self.config.policy_target_types,
|
| 298 |
-
target_record_ids=self.policy_target_record_ids,
|
| 299 |
-
)
|
| 300 |
best_obs = self._obs_tensor(best_records)
|
| 301 |
-
best_actions = self._action_tensor(best_records)
|
| 302 |
best_instructions = [record.instruction for record in best_records]
|
| 303 |
pred_best_actions = self.model.forward_policy(best_obs, best_instructions)
|
| 304 |
|
|
@@ -362,6 +360,50 @@ class DoVLATrainer:
|
|
| 362 |
)
|
| 363 |
return total, metrics
|
| 364 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 365 |
def _rank_loss(self, pred_reward, target_reward, pair_indices: list[tuple[int, int]]):
|
| 366 |
assert torch is not None
|
| 367 |
if not pair_indices:
|
|
@@ -743,18 +785,51 @@ def _load_policy_target_map(path: str | Path | None) -> dict[str, str]:
|
|
| 743 |
return output
|
| 744 |
|
| 745 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 746 |
def _policy_target_map_coverage(
|
| 747 |
-
|
| 748 |
*,
|
| 749 |
train_group_ids: list[str],
|
| 750 |
val_group_ids: list[str],
|
| 751 |
) -> dict[str, float | int]:
|
| 752 |
-
|
| 753 |
-
|
|
|
|
| 754 |
train_groups = len(train_group_ids)
|
| 755 |
val_groups = len(val_group_ids)
|
| 756 |
return {
|
| 757 |
-
"num_targets": len(
|
| 758 |
"train_groups": train_groups,
|
| 759 |
"train_covered": train_covered,
|
| 760 |
"train_coverage": train_covered / train_groups if train_groups else 0.0,
|
|
|
|
| 117 |
self.output_dir = ensure_dir(config.output_dir)
|
| 118 |
self.dataset = CILDataset(config.dataset_dir)
|
| 119 |
self.policy_target_record_ids = _load_policy_target_map(config.policy_target_map)
|
| 120 |
+
self.policy_target_action_values = _load_policy_target_action_map(
|
| 121 |
+
config.policy_target_map
|
| 122 |
+
)
|
| 123 |
self.train_group_ids, self.val_group_ids = _split_group_ids(
|
| 124 |
self.dataset.group_ids, val_fraction=config.val_fraction, seed=config.seed
|
| 125 |
)
|
| 126 |
self.policy_target_map_coverage = _policy_target_map_coverage(
|
| 127 |
+
set(self.policy_target_record_ids) | set(self.policy_target_action_values),
|
| 128 |
train_group_ids=self.train_group_ids,
|
| 129 |
val_group_ids=self.val_group_ids,
|
| 130 |
)
|
|
|
|
| 171 |
|
| 172 |
def train(self) -> dict[str, Any]:
|
| 173 |
write_json(self._resolved_config(), self.output_dir / "resolved_config.json")
|
| 174 |
+
if self.policy_target_record_ids or self.policy_target_action_values:
|
| 175 |
coverage = self.policy_target_map_coverage
|
| 176 |
print(
|
| 177 |
"policy_target_map_coverage "
|
|
|
|
| 295 |
pred_reward, [record.group_id for record in records]
|
| 296 |
)
|
| 297 |
|
| 298 |
+
best_records, best_actions = self._policy_bc_targets(records)
|
|
|
|
|
|
|
|
|
|
|
|
|
| 299 |
best_obs = self._obs_tensor(best_records)
|
|
|
|
| 300 |
best_instructions = [record.instruction for record in best_records]
|
| 301 |
pred_best_actions = self.model.forward_policy(best_obs, best_instructions)
|
| 302 |
|
|
|
|
| 360 |
)
|
| 361 |
return total, metrics
|
| 362 |
|
| 363 |
+
def _policy_bc_targets(self, records: list[CILRecord]) -> tuple[list[CILRecord], Any]:
|
| 364 |
+
assert torch is not None
|
| 365 |
+
target_records: list[CILRecord] = []
|
| 366 |
+
target_values: list[list[list[float]]] = []
|
| 367 |
+
used_group_ids: set[str] = set()
|
| 368 |
+
grouped: dict[str, list[CILRecord]] = {}
|
| 369 |
+
for record in records:
|
| 370 |
+
grouped.setdefault(record.group_id, []).append(record)
|
| 371 |
+
|
| 372 |
+
for group_id, group_records in grouped.items():
|
| 373 |
+
mapped_action = self.policy_target_action_values.get(group_id)
|
| 374 |
+
if mapped_action is None:
|
| 375 |
+
continue
|
| 376 |
+
target_records.append(group_records[0])
|
| 377 |
+
target_values.append(
|
| 378 |
+
_coerce_policy_target_action(
|
| 379 |
+
mapped_action,
|
| 380 |
+
action_dim=self.config.action_dim,
|
| 381 |
+
action_horizon=self.config.action_horizon,
|
| 382 |
+
)
|
| 383 |
+
)
|
| 384 |
+
used_group_ids.add(group_id)
|
| 385 |
+
|
| 386 |
+
fallback_records = _best_records_by_group(
|
| 387 |
+
[record for record in records if record.group_id not in used_group_ids],
|
| 388 |
+
candidate_types=self.config.policy_target_types,
|
| 389 |
+
target_record_ids=self.policy_target_record_ids,
|
| 390 |
+
)
|
| 391 |
+
for record in fallback_records:
|
| 392 |
+
target_records.append(record)
|
| 393 |
+
target_values.append(
|
| 394 |
+
vectorize_toy_action(
|
| 395 |
+
record.action_chunk,
|
| 396 |
+
action_dim=self.config.action_dim,
|
| 397 |
+
action_horizon=self.config.action_horizon,
|
| 398 |
+
)
|
| 399 |
+
)
|
| 400 |
+
best_actions = torch.tensor(
|
| 401 |
+
target_values,
|
| 402 |
+
dtype=torch.float32,
|
| 403 |
+
device=self.device,
|
| 404 |
+
)
|
| 405 |
+
return target_records, best_actions
|
| 406 |
+
|
| 407 |
def _rank_loss(self, pred_reward, target_reward, pair_indices: list[tuple[int, int]]):
|
| 408 |
assert torch is not None
|
| 409 |
if not pair_indices:
|
|
|
|
| 785 |
return output
|
| 786 |
|
| 787 |
|
| 788 |
+
def _load_policy_target_action_map(path: str | Path | None) -> dict[str, list[list[float]]]:
|
| 789 |
+
if path is None:
|
| 790 |
+
return {}
|
| 791 |
+
payload = json.loads(Path(path).read_text())
|
| 792 |
+
raw_targets = payload.get("targets", payload)
|
| 793 |
+
output: dict[str, list[list[float]]] = {}
|
| 794 |
+
for group_id, value in raw_targets.items():
|
| 795 |
+
if not isinstance(value, dict):
|
| 796 |
+
continue
|
| 797 |
+
raw_action = value.get("action_values", value.get("action"))
|
| 798 |
+
if raw_action is None:
|
| 799 |
+
continue
|
| 800 |
+
output[str(group_id)] = [
|
| 801 |
+
[float(item) for item in row]
|
| 802 |
+
for row in raw_action
|
| 803 |
+
]
|
| 804 |
+
return output
|
| 805 |
+
|
| 806 |
+
|
| 807 |
+
def _coerce_policy_target_action(
|
| 808 |
+
action_values: list[list[float]],
|
| 809 |
+
*,
|
| 810 |
+
action_dim: int,
|
| 811 |
+
action_horizon: int,
|
| 812 |
+
) -> list[list[float]]:
|
| 813 |
+
return vectorize_toy_action(
|
| 814 |
+
action_values,
|
| 815 |
+
action_dim=action_dim,
|
| 816 |
+
action_horizon=action_horizon,
|
| 817 |
+
)
|
| 818 |
+
|
| 819 |
+
|
| 820 |
def _policy_target_map_coverage(
|
| 821 |
+
target_group_ids: set[str] | dict[str, Any],
|
| 822 |
*,
|
| 823 |
train_group_ids: list[str],
|
| 824 |
val_group_ids: list[str],
|
| 825 |
) -> dict[str, float | int]:
|
| 826 |
+
target_groups = set(target_group_ids)
|
| 827 |
+
train_covered = sum(1 for group_id in train_group_ids if group_id in target_groups)
|
| 828 |
+
val_covered = sum(1 for group_id in val_group_ids if group_id in target_groups)
|
| 829 |
train_groups = len(train_group_ids)
|
| 830 |
val_groups = len(val_group_ids)
|
| 831 |
return {
|
| 832 |
+
"num_targets": len(target_groups),
|
| 833 |
"train_groups": train_groups,
|
| 834 |
"train_covered": train_covered,
|
| 835 |
"train_coverage": train_covered / train_groups if train_groups else 0.0,
|