anhtld commited on
Commit
26eaed5
·
verified ·
1 Parent(s): 960cff9

manual-sync 2026-07-02T21:01:54Z workspace/dovla_cil/generation

Browse files
workspace/dovla_cil/generation/tangent_local_atlas.py CHANGED
@@ -25,6 +25,8 @@ class LocalAtlasConfig:
25
  neighbor_pool: int = 16
26
  utility_weight: float = 0.0
27
  diversity_weight: float = 0.0
 
 
28
  same_task_only: bool = True
29
 
30
  def __post_init__(self) -> None:
@@ -40,6 +42,10 @@ class LocalAtlasConfig:
40
  raise ValueError("utility_weight must be non-negative")
41
  if self.diversity_weight < 0:
42
  raise ValueError("diversity_weight must be non-negative")
 
 
 
 
43
 
44
 
45
  def evaluate_local_atlas_retrieval(
@@ -65,9 +71,16 @@ def evaluate_local_atlas_retrieval(
65
  ]
66
  if not train_positive:
67
  raise ValueError("no train positive tangents")
 
 
 
 
68
  train_positive_by_task: dict[str, list[SplineTangentRow]] = {}
69
  for row in train_positive:
70
  train_positive_by_task.setdefault(row.example.task_id, []).append(row)
 
 
 
71
 
72
  max_k = max(int(k) for k in k_values)
73
  val_by_group: dict[str, list[SplineTangentRow]] = {}
@@ -90,6 +103,8 @@ def evaluate_local_atlas_retrieval(
90
  group_rows[0],
91
  train_positive=train_positive,
92
  train_positive_by_task=train_positive_by_task,
 
 
93
  config=config,
94
  max_k=max_k,
95
  )
@@ -124,12 +139,17 @@ def evaluate_local_atlas_retrieval(
124
  "num_train_examples": len(split["train"]),
125
  "num_val_examples": len(split["val"]),
126
  "num_train_positive": len(train_positive),
 
127
  "num_val_groups_with_positive": len(groups),
128
  "label_counts": dict(Counter(row.example.tangent_label for row in rows)),
129
  "train_positive_by_task": {
130
  task_id: len(train_positive_by_task.get(task_id, []))
131
  for task_id in task_ids
132
  },
 
 
 
 
133
  "overall": _aggregate_rows(groups, k_values=k_values, thresholds=thresholds),
134
  "per_task": {
135
  task_id: _aggregate_rows(
@@ -148,6 +168,8 @@ def _select_local_positive_tangents(
148
  *,
149
  train_positive: Sequence[SplineTangentRow],
150
  train_positive_by_task: dict[str, list[SplineTangentRow]],
 
 
151
  config: LocalAtlasConfig,
152
  max_k: int,
153
  ) -> list[SplineTangentRow]:
@@ -155,6 +177,20 @@ def _select_local_positive_tangents(
155
  pool = train_positive_by_task.get(query.example.task_id, []) or list(train_positive)
156
  else:
157
  pool = list(train_positive)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
158
  ranked = sorted(
159
  (
160
  (_condition_distance(query.condition, row.condition), row)
@@ -166,24 +202,40 @@ def _select_local_positive_tangents(
166
  selected: list[tuple[float, SplineTangentRow]] = []
167
  remaining = list(candidates)
168
  while remaining and len(selected) < max_k:
169
- if not selected:
170
- chosen = remaining[0]
171
- else:
172
- chosen = max(
173
- remaining,
174
- key=lambda item: (
175
- -item[0]
176
- + float(config.utility_weight) * item[1].example.delta_utility
177
- + float(config.diversity_weight)
178
- * _nearest_action_distance(item[1], [row for _, row in selected]),
179
- item[1].example.delta_utility,
180
  ),
181
- )
 
 
182
  selected.append(chosen)
183
  remaining = [item for item in remaining if item is not chosen]
184
  return [row for _, row in selected]
185
 
186
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
187
  def _condition_distance(left: Sequence[float], right: Sequence[float]) -> float:
188
  return _rms_distance(left, right)
189
 
 
25
  neighbor_pool: int = 16
26
  utility_weight: float = 0.0
27
  diversity_weight: float = 0.0
28
+ negative_margin_weight: float = 0.0
29
+ negative_pool: int = 64
30
  same_task_only: bool = True
31
 
32
  def __post_init__(self) -> None:
 
42
  raise ValueError("utility_weight must be non-negative")
43
  if self.diversity_weight < 0:
44
  raise ValueError("diversity_weight must be non-negative")
45
+ if self.negative_margin_weight < 0:
46
+ raise ValueError("negative_margin_weight must be non-negative")
47
+ if self.negative_pool <= 0:
48
+ raise ValueError("negative_pool must be positive")
49
 
50
 
51
  def evaluate_local_atlas_retrieval(
 
71
  ]
72
  if not train_positive:
73
  raise ValueError("no train positive tangents")
74
+ train_negative = [
75
+ row for row in split["train"]
76
+ if row.example.tangent_label == "negative"
77
+ ]
78
  train_positive_by_task: dict[str, list[SplineTangentRow]] = {}
79
  for row in train_positive:
80
  train_positive_by_task.setdefault(row.example.task_id, []).append(row)
81
+ train_negative_by_task: dict[str, list[SplineTangentRow]] = {}
82
+ for row in train_negative:
83
+ train_negative_by_task.setdefault(row.example.task_id, []).append(row)
84
 
85
  max_k = max(int(k) for k in k_values)
86
  val_by_group: dict[str, list[SplineTangentRow]] = {}
 
103
  group_rows[0],
104
  train_positive=train_positive,
105
  train_positive_by_task=train_positive_by_task,
106
+ train_negative=train_negative,
107
+ train_negative_by_task=train_negative_by_task,
108
  config=config,
109
  max_k=max_k,
110
  )
 
139
  "num_train_examples": len(split["train"]),
140
  "num_val_examples": len(split["val"]),
141
  "num_train_positive": len(train_positive),
142
+ "num_train_negative": len(train_negative),
143
  "num_val_groups_with_positive": len(groups),
144
  "label_counts": dict(Counter(row.example.tangent_label for row in rows)),
145
  "train_positive_by_task": {
146
  task_id: len(train_positive_by_task.get(task_id, []))
147
  for task_id in task_ids
148
  },
149
+ "train_negative_by_task": {
150
+ task_id: len(train_negative_by_task.get(task_id, []))
151
+ for task_id in task_ids
152
+ },
153
  "overall": _aggregate_rows(groups, k_values=k_values, thresholds=thresholds),
154
  "per_task": {
155
  task_id: _aggregate_rows(
 
168
  *,
169
  train_positive: Sequence[SplineTangentRow],
170
  train_positive_by_task: dict[str, list[SplineTangentRow]],
171
+ train_negative: Sequence[SplineTangentRow],
172
+ train_negative_by_task: dict[str, list[SplineTangentRow]],
173
  config: LocalAtlasConfig,
174
  max_k: int,
175
  ) -> list[SplineTangentRow]:
 
177
  pool = train_positive_by_task.get(query.example.task_id, []) or list(train_positive)
178
  else:
179
  pool = list(train_positive)
180
+ if config.same_task_only:
181
+ negative_pool = train_negative_by_task.get(query.example.task_id, []) or list(train_negative)
182
+ else:
183
+ negative_pool = list(train_negative)
184
+ local_negatives = [
185
+ row
186
+ for _, row in sorted(
187
+ (
188
+ (_condition_distance(query.condition, row.condition), row)
189
+ for row in negative_pool
190
+ ),
191
+ key=lambda item: (item[0], item[1].example.group_id),
192
+ )[: int(config.negative_pool)]
193
+ ]
194
  ranked = sorted(
195
  (
196
  (_condition_distance(query.condition, row.condition), row)
 
202
  selected: list[tuple[float, SplineTangentRow]] = []
203
  remaining = list(candidates)
204
  while remaining and len(selected) < max_k:
205
+ chosen = max(
206
+ remaining,
207
+ key=lambda item: (
208
+ _candidate_score(
209
+ item,
210
+ selected=[row for _, row in selected],
211
+ local_negatives=local_negatives,
212
+ config=config,
 
 
 
213
  ),
214
+ item[1].example.delta_utility,
215
+ ),
216
+ )
217
  selected.append(chosen)
218
  remaining = [item for item in remaining if item is not chosen]
219
  return [row for _, row in selected]
220
 
221
 
222
+ def _candidate_score(
223
+ item: tuple[float, SplineTangentRow],
224
+ *,
225
+ selected: Sequence[SplineTangentRow],
226
+ local_negatives: Sequence[SplineTangentRow],
227
+ config: LocalAtlasConfig,
228
+ ) -> float:
229
+ condition_distance, row = item
230
+ score = -float(condition_distance)
231
+ score += float(config.utility_weight) * row.example.delta_utility
232
+ if config.diversity_weight > 0.0 and selected:
233
+ score += float(config.diversity_weight) * _nearest_action_distance(row, selected)
234
+ if config.negative_margin_weight > 0.0 and local_negatives:
235
+ score += float(config.negative_margin_weight) * _nearest_action_distance(row, local_negatives)
236
+ return score
237
+
238
+
239
  def _condition_distance(left: Sequence[float], right: Sequence[float]) -> float:
240
  return _rms_distance(left, right)
241