add context learned dominance diagnostics
Browse files
workspace/scripts/eval_learned_dominance_selector.py
CHANGED
|
@@ -2,6 +2,7 @@
|
|
| 2 |
from __future__ import annotations
|
| 3 |
|
| 4 |
import argparse
|
|
|
|
| 5 |
import json
|
| 6 |
import math
|
| 7 |
import re
|
|
@@ -34,6 +35,7 @@ BASIC_FEATURE_NAMES = [
|
|
| 34 |
"num_candidates",
|
| 35 |
]
|
| 36 |
FEATURE_NAMES = BASIC_FEATURE_NAMES
|
|
|
|
| 37 |
|
| 38 |
|
| 39 |
def main(argv: list[str] | None = None) -> int:
|
|
@@ -56,7 +58,7 @@ def main(argv: list[str] | None = None) -> int:
|
|
| 56 |
parser.add_argument("--ridge-lambdas", default="0,0.01,0.1,1,10,100")
|
| 57 |
parser.add_argument(
|
| 58 |
"--feature-set",
|
| 59 |
-
choices=("basic", "tangent"),
|
| 60 |
default="basic",
|
| 61 |
help="Deployment-visible feature family for candidate-level dominance fitting.",
|
| 62 |
)
|
|
@@ -218,6 +220,7 @@ def _candidate_dataset(
|
|
| 218 |
successes = [float(bool(value)) for value in row.get("candidate_success", [])[:k]]
|
| 219 |
tangents = row.get("generated_tangents", [])[:k]
|
| 220 |
candidate_types = row.get("candidate_types", [])[:k]
|
|
|
|
| 221 |
if not scores or len(scores) != len(utilities):
|
| 222 |
continue
|
| 223 |
score_mean = sum(scores) / len(scores)
|
|
@@ -234,6 +237,13 @@ def _candidate_dataset(
|
|
| 234 |
score_std=score_std,
|
| 235 |
candidate_index=candidate_index,
|
| 236 |
candidate_type=candidate_types[candidate_index] if candidate_index < len(candidate_types) else "",
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 237 |
tangent=tangent,
|
| 238 |
num_candidates=len(scores),
|
| 239 |
feature_set=feature_set,
|
|
@@ -276,12 +286,24 @@ def _candidate_dataset(
|
|
| 276 |
def _feature_names(feature_set: str) -> list[str]:
|
| 277 |
if feature_set == "basic":
|
| 278 |
return list(BASIC_FEATURE_NAMES)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 279 |
if feature_set == "tangent":
|
| 280 |
-
return [
|
| 281 |
-
|
| 282 |
-
|
| 283 |
-
|
| 284 |
-
]
|
| 285 |
raise ValueError(f"unknown feature_set: {feature_set}")
|
| 286 |
|
| 287 |
|
|
@@ -296,6 +318,7 @@ def _candidate_feature(
|
|
| 296 |
tangent: np.ndarray,
|
| 297 |
num_candidates: int,
|
| 298 |
feature_set: str,
|
|
|
|
| 299 |
) -> np.ndarray:
|
| 300 |
tangent = np.asarray(tangent, dtype=float).reshape(-1)
|
| 301 |
if tangent.size < 21:
|
|
@@ -323,9 +346,42 @@ def _candidate_feature(
|
|
| 323 |
return basic
|
| 324 |
if feature_set == "tangent":
|
| 325 |
return np.concatenate([basic, tangent.astype(float), np.abs(tangent).astype(float)])
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 326 |
raise ValueError(f"unknown feature_set: {feature_set}")
|
| 327 |
|
| 328 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 329 |
def _target_value(
|
| 330 |
target: str,
|
| 331 |
*,
|
|
|
|
| 2 |
from __future__ import annotations
|
| 3 |
|
| 4 |
import argparse
|
| 5 |
+
import hashlib
|
| 6 |
import json
|
| 7 |
import math
|
| 8 |
import re
|
|
|
|
| 35 |
"num_candidates",
|
| 36 |
]
|
| 37 |
FEATURE_NAMES = BASIC_FEATURE_NAMES
|
| 38 |
+
CONTEXT_HASH_WIDTH = 8
|
| 39 |
|
| 40 |
|
| 41 |
def main(argv: list[str] | None = None) -> int:
|
|
|
|
| 58 |
parser.add_argument("--ridge-lambdas", default="0,0.01,0.1,1,10,100")
|
| 59 |
parser.add_argument(
|
| 60 |
"--feature-set",
|
| 61 |
+
choices=("basic", "tangent", "context", "context_tangent"),
|
| 62 |
default="basic",
|
| 63 |
help="Deployment-visible feature family for candidate-level dominance fitting.",
|
| 64 |
)
|
|
|
|
| 220 |
successes = [float(bool(value)) for value in row.get("candidate_success", [])[:k]]
|
| 221 |
tangents = row.get("generated_tangents", [])[:k]
|
| 222 |
candidate_types = row.get("candidate_types", [])[:k]
|
| 223 |
+
source_task_ids = row.get("candidate_source_task_ids", [])[:k]
|
| 224 |
if not scores or len(scores) != len(utilities):
|
| 225 |
continue
|
| 226 |
score_mean = sum(scores) / len(scores)
|
|
|
|
| 237 |
score_std=score_std,
|
| 238 |
candidate_index=candidate_index,
|
| 239 |
candidate_type=candidate_types[candidate_index] if candidate_index < len(candidate_types) else "",
|
| 240 |
+
context={
|
| 241 |
+
"target_task_id": row.get("task_id", ""),
|
| 242 |
+
"instruction": row.get("instruction", ""),
|
| 243 |
+
"source_task_id": source_task_ids[candidate_index]
|
| 244 |
+
if candidate_index < len(source_task_ids)
|
| 245 |
+
else "",
|
| 246 |
+
},
|
| 247 |
tangent=tangent,
|
| 248 |
num_candidates=len(scores),
|
| 249 |
feature_set=feature_set,
|
|
|
|
| 286 |
def _feature_names(feature_set: str) -> list[str]:
|
| 287 |
if feature_set == "basic":
|
| 288 |
return list(BASIC_FEATURE_NAMES)
|
| 289 |
+
context_names = [
|
| 290 |
+
*[f"target_task_hash_{index:02d}" for index in range(CONTEXT_HASH_WIDTH)],
|
| 291 |
+
*[f"source_task_hash_{index:02d}" for index in range(CONTEXT_HASH_WIDTH)],
|
| 292 |
+
*[f"instruction_hash_{index:02d}" for index in range(CONTEXT_HASH_WIDTH)],
|
| 293 |
+
"source_target_same_task",
|
| 294 |
+
"instruction_chars_per_128",
|
| 295 |
+
"instruction_words_per_32",
|
| 296 |
+
]
|
| 297 |
+
tangent_names = [
|
| 298 |
+
*[f"tangent_{index:02d}" for index in range(21)],
|
| 299 |
+
*[f"abs_tangent_{index:02d}" for index in range(21)],
|
| 300 |
+
]
|
| 301 |
if feature_set == "tangent":
|
| 302 |
+
return [*BASIC_FEATURE_NAMES, *tangent_names]
|
| 303 |
+
if feature_set == "context":
|
| 304 |
+
return [*BASIC_FEATURE_NAMES, *context_names]
|
| 305 |
+
if feature_set == "context_tangent":
|
| 306 |
+
return [*BASIC_FEATURE_NAMES, *context_names, *tangent_names]
|
| 307 |
raise ValueError(f"unknown feature_set: {feature_set}")
|
| 308 |
|
| 309 |
|
|
|
|
| 318 |
tangent: np.ndarray,
|
| 319 |
num_candidates: int,
|
| 320 |
feature_set: str,
|
| 321 |
+
context: dict[str, Any] | None = None,
|
| 322 |
) -> np.ndarray:
|
| 323 |
tangent = np.asarray(tangent, dtype=float).reshape(-1)
|
| 324 |
if tangent.size < 21:
|
|
|
|
| 346 |
return basic
|
| 347 |
if feature_set == "tangent":
|
| 348 |
return np.concatenate([basic, tangent.astype(float), np.abs(tangent).astype(float)])
|
| 349 |
+
if feature_set == "context":
|
| 350 |
+
return np.concatenate([basic, _context_feature(context or {})])
|
| 351 |
+
if feature_set == "context_tangent":
|
| 352 |
+
return np.concatenate(
|
| 353 |
+
[
|
| 354 |
+
basic,
|
| 355 |
+
_context_feature(context or {}),
|
| 356 |
+
tangent.astype(float),
|
| 357 |
+
np.abs(tangent).astype(float),
|
| 358 |
+
]
|
| 359 |
+
)
|
| 360 |
raise ValueError(f"unknown feature_set: {feature_set}")
|
| 361 |
|
| 362 |
|
| 363 |
+
def _context_feature(context: dict[str, Any]) -> np.ndarray:
|
| 364 |
+
target_task = str(context.get("target_task_id", ""))
|
| 365 |
+
source_task = str(context.get("source_task_id", ""))
|
| 366 |
+
instruction = str(context.get("instruction", ""))
|
| 367 |
+
return np.asarray(
|
| 368 |
+
[
|
| 369 |
+
*_stable_hash_features(target_task, CONTEXT_HASH_WIDTH),
|
| 370 |
+
*_stable_hash_features(source_task, CONTEXT_HASH_WIDTH),
|
| 371 |
+
*_stable_hash_features(instruction.lower(), CONTEXT_HASH_WIDTH),
|
| 372 |
+
float(bool(target_task) and target_task == source_task),
|
| 373 |
+
min(len(instruction) / 128.0, 4.0),
|
| 374 |
+
min(len(instruction.split()) / 32.0, 4.0),
|
| 375 |
+
],
|
| 376 |
+
dtype=float,
|
| 377 |
+
)
|
| 378 |
+
|
| 379 |
+
|
| 380 |
+
def _stable_hash_features(text: str, width: int) -> list[float]:
|
| 381 |
+
digest = hashlib.sha256(text.encode("utf-8")).digest()
|
| 382 |
+
return [((digest[index] / 127.5) - 1.0) for index in range(width)]
|
| 383 |
+
|
| 384 |
+
|
| 385 |
def _target_value(
|
| 386 |
target: str,
|
| 387 |
*,
|