anhtld commited on
Commit
731f75a
·
verified ·
1 Parent(s): b4c3cd3

auto-sync 2026-07-03T10:26:01Z workspace (part 2)

Browse files
Files changed (1) hide show
  1. workspace/scripts/train_ctt.py +40 -3
workspace/scripts/train_ctt.py CHANGED
@@ -19,6 +19,7 @@ if str(PROJECT_ROOT) not in sys.path:
19
  import numpy as np # noqa: E402
20
  import torch # noqa: E402
21
 
 
22
  from cil.models import CTTConfig, CausalTangentTransport, ChartEncoder, TangentNormalizer, UtilityEnergy # noqa: E402
23
  from cil.models.ctt import chamfer_to_target_set, diversity_loss, negative_boundary_loss # noqa: E402
24
  from cil.models.utility_energy import listwise_ranking_loss, pairwise_ranking_loss # noqa: E402
@@ -57,6 +58,12 @@ def main(argv: list[str] | None = None) -> int:
57
  parser.add_argument("--negative-margin", type=float, default=0.2)
58
  parser.add_argument("--transport-samples-per-pair", type=int, default=4)
59
  parser.add_argument("--diversity-temperature", type=float, default=1.0)
 
 
 
 
 
 
60
  args = parser.parse_args(argv)
61
  if args.config:
62
  args = _merge_config(args, _load_simple_yaml(args.config))
@@ -68,7 +75,11 @@ def main(argv: list[str] | None = None) -> int:
68
  out_dir = args.out_dir
69
  out_dir.mkdir(parents=True, exist_ok=True)
70
  _write_run_provenance(out_dir, args)
71
- charts, index = load_charts(args.dataset, max_charts=args.max_charts)
 
 
 
 
72
  if len(charts) < 2:
73
  raise SystemExit("CTT training requires at least two charts with positive tangents")
74
 
@@ -164,6 +175,7 @@ def main(argv: list[str] | None = None) -> int:
164
  "source_index": str(args.dataset),
165
  "data_hash": index.get("content_hash"),
166
  "split_hash": index.get("split_hash"),
 
167
  }
168
  torch.save(checkpoint, out_dir / "model.pt")
169
  metrics = {
@@ -175,6 +187,7 @@ def main(argv: list[str] | None = None) -> int:
175
  "final_mean_loss": mean_loss,
176
  "data_hash": index.get("content_hash"),
177
  "split_hash": index.get("split_hash"),
 
178
  "loss_weights": {
179
  "pos_alignment": args.pos_alignment,
180
  "negative_boundary": args.negative_boundary,
@@ -198,7 +211,12 @@ def main(argv: list[str] | None = None) -> int:
198
  return 0
199
 
200
 
201
- def load_charts(index_path: Path, *, max_charts: int | None = None) -> tuple[list[Chart], dict[str, Any]]:
 
 
 
 
 
202
  index = json.loads(index_path.read_text())
203
  if not index.get("include_outcomes", False):
204
  raise SystemExit(f"{index_path} does not include outcomes; CTT training requires train split")
@@ -215,14 +233,17 @@ def load_charts(index_path: Path, *, max_charts: int | None = None) -> tuple[lis
215
  utilities = data["utility"]
216
  outcomes = data["outcome_vector"]
217
  seeds = data["seed"]
 
218
  for row in range(chart_ids.shape[0]):
219
  chart_id = str(chart_ids[row])
 
220
  item = grouped.setdefault(
221
  chart_id,
222
  {
223
  "task_id": str(task_ids[row]),
224
  "seed": str(seeds[row]),
225
  "base": None,
 
226
  "positives": [],
227
  "negatives": [],
228
  "tangents": [],
@@ -232,6 +253,7 @@ def load_charts(index_path: Path, *, max_charts: int | None = None) -> tuple[lis
232
  )
233
  if bool(is_base[row]):
234
  item["base"] = base_actions[row].astype("float32")
 
235
  label = str(labels[row])
236
  tangent = spline_codes[row].astype("float32")
237
  if label == "positive":
@@ -256,7 +278,14 @@ def load_charts(index_path: Path, *, max_charts: int | None = None) -> tuple[lis
256
  chart_id=chart_id,
257
  task_id=str(item["task_id"]),
258
  seed=str(item["seed"]),
259
- feature=torch.as_tensor(item["base"], dtype=torch.float32),
 
 
 
 
 
 
 
260
  positives=positives,
261
  negatives=negatives,
262
  tangents=tangents,
@@ -269,6 +298,14 @@ def load_charts(index_path: Path, *, max_charts: int | None = None) -> tuple[lis
269
  return charts, index
270
 
271
 
 
 
 
 
 
 
 
 
272
  def _neighbor_pairs(charts: list[Chart], *, neighbors: int) -> list[tuple[int, int]]:
273
  pairs: list[tuple[int, int]] = []
274
  for target_idx, target in enumerate(charts):
 
19
  import numpy as np # noqa: E402
20
  import torch # noqa: E402
21
 
22
+ from cil.chart_features import CHART_FEATURE_MODES, build_chart_feature # noqa: E402
23
  from cil.models import CTTConfig, CausalTangentTransport, ChartEncoder, TangentNormalizer, UtilityEnergy # noqa: E402
24
  from cil.models.ctt import chamfer_to_target_set, diversity_loss, negative_boundary_loss # noqa: E402
25
  from cil.models.utility_energy import listwise_ranking_loss, pairwise_ranking_loss # noqa: E402
 
58
  parser.add_argument("--negative-margin", type=float, default=0.2)
59
  parser.add_argument("--transport-samples-per-pair", type=int, default=4)
60
  parser.add_argument("--diversity-temperature", type=float, default=1.0)
61
+ parser.add_argument(
62
+ "--chart-feature-mode",
63
+ choices=CHART_FEATURE_MODES,
64
+ default="base",
65
+ help="Deployment-visible chart feature family used by ChartEncoder.",
66
+ )
67
  args = parser.parse_args(argv)
68
  if args.config:
69
  args = _merge_config(args, _load_simple_yaml(args.config))
 
75
  out_dir = args.out_dir
76
  out_dir.mkdir(parents=True, exist_ok=True)
77
  _write_run_provenance(out_dir, args)
78
+ charts, index = load_charts(
79
+ args.dataset,
80
+ max_charts=args.max_charts,
81
+ chart_feature_mode=args.chart_feature_mode,
82
+ )
83
  if len(charts) < 2:
84
  raise SystemExit("CTT training requires at least two charts with positive tangents")
85
 
 
175
  "source_index": str(args.dataset),
176
  "data_hash": index.get("content_hash"),
177
  "split_hash": index.get("split_hash"),
178
+ "chart_feature_mode": args.chart_feature_mode,
179
  }
180
  torch.save(checkpoint, out_dir / "model.pt")
181
  metrics = {
 
187
  "final_mean_loss": mean_loss,
188
  "data_hash": index.get("content_hash"),
189
  "split_hash": index.get("split_hash"),
190
+ "chart_feature_mode": args.chart_feature_mode,
191
  "loss_weights": {
192
  "pos_alignment": args.pos_alignment,
193
  "negative_boundary": args.negative_boundary,
 
211
  return 0
212
 
213
 
214
+ def load_charts(
215
+ index_path: Path,
216
+ *,
217
+ max_charts: int | None = None,
218
+ chart_feature_mode: str = "base",
219
+ ) -> tuple[list[Chart], dict[str, Any]]:
220
  index = json.loads(index_path.read_text())
221
  if not index.get("include_outcomes", False):
222
  raise SystemExit(f"{index_path} does not include outcomes; CTT training requires train split")
 
233
  utilities = data["utility"]
234
  outcomes = data["outcome_vector"]
235
  seeds = data["seed"]
236
+ metadata_values = data["metadata_json"]
237
  for row in range(chart_ids.shape[0]):
238
  chart_id = str(chart_ids[row])
239
+ metadata = _json_loads(str(metadata_values[row]))
240
  item = grouped.setdefault(
241
  chart_id,
242
  {
243
  "task_id": str(task_ids[row]),
244
  "seed": str(seeds[row]),
245
  "base": None,
246
+ "metadata": metadata,
247
  "positives": [],
248
  "negatives": [],
249
  "tangents": [],
 
253
  )
254
  if bool(is_base[row]):
255
  item["base"] = base_actions[row].astype("float32")
256
+ item["metadata"] = metadata
257
  label = str(labels[row])
258
  tangent = spline_codes[row].astype("float32")
259
  if label == "positive":
 
278
  chart_id=chart_id,
279
  task_id=str(item["task_id"]),
280
  seed=str(item["seed"]),
281
+ feature=torch.as_tensor(
282
+ build_chart_feature(
283
+ item["base"],
284
+ item.get("metadata", {}),
285
+ mode=chart_feature_mode,
286
+ ),
287
+ dtype=torch.float32,
288
+ ),
289
  positives=positives,
290
  negatives=negatives,
291
  tangents=tangents,
 
298
  return charts, index
299
 
300
 
301
+ def _json_loads(value: str) -> dict[str, Any]:
302
+ try:
303
+ payload = json.loads(value)
304
+ except json.JSONDecodeError:
305
+ return {}
306
+ return payload if isinstance(payload, dict) else {}
307
+
308
+
309
  def _neighbor_pairs(charts: list[Chart], *, neighbors: int) -> list[tuple[int, int]]:
310
  pairs: list[tuple[int, int]] = []
311
  for target_idx, target in enumerate(charts):