ViSS-8B / code /experiments /analyze_uncertainty_temporal_escalation.py
mis2's picture
Release ViSS-8B weights, processors and source code
78ac017 verified
Raw History Blame Contribute Delete
16.6 kB
#!/usr/bin/env python3
"""Audit a task-agnostic recent-to-temporal escalation policy.
The online policy sees only the recent-view first-token generation margin. Gold labels are
used offline to fit one global threshold on a deterministic calibration split
and to score the disjoint exploratory split. Task, group, benchmark identity,
and answer-space semantics are never policy inputs.
"""
from __future__ import annotations
import argparse
import hashlib
import json
from collections import defaultdict
from pathlib import Path
from typing import Any
def parse_args() -> argparse.Namespace:
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("--recent", type=Path, required=True)
parser.add_argument("--temporal", type=Path, required=True)
parser.add_argument("--output", type=Path, required=True)
parser.add_argument(
"--calibration-modulus",
type=int,
default=2,
help="SHA256(uid) modulo this value; bucket zero fits the threshold.",
)
return parser.parse_args()
def load_result(path: Path) -> dict[str, Any]:
value = json.loads(path.read_text(encoding="utf-8"))
if not isinstance(value, dict) or not isinstance(value.get("rows"), list):
raise ValueError(f"{path}: expected benchmark result with rows")
if int(value.get("num_errors", 0)) != 0:
raise ValueError(f"{path}: result contains inference errors")
return value
def index_rows(result: dict[str, Any]) -> dict[str, dict[str, Any]]:
indexed = {str(row.get("uid")): row for row in result["rows"]}
if "" in indexed or len(indexed) != len(result["rows"]):
raise ValueError("result contains missing or duplicate UIDs")
return indexed
def index_scores(result: dict[str, Any]) -> dict[str, dict[str, Any]]:
rows = (result.get("score") or {}).get("rows")
if not isinstance(rows, list):
raise ValueError("result is missing score.rows")
indexed = {str(row.get("query_id")): row for row in rows}
if "" in indexed or len(indexed) != len(rows):
raise ValueError("score rows contain missing or duplicate query IDs")
return indexed
def index_temporal_scores(result: dict[str, Any]) -> dict[str, dict[str, Any]]:
score_rows = (result.get("score") or {}).get("rows")
if isinstance(score_rows, list):
return index_scores(result)
rows = result.get("rows")
if not isinstance(rows, list) or any("correct" not in row for row in rows):
raise ValueError("temporal result lacks official or inherited correctness")
indexed = {str(row.get("uid")): row for row in rows}
if "" in indexed or len(indexed) != len(rows):
raise ValueError("temporal score rows contain missing or duplicate UIDs")
return indexed
def calibration_bucket(uid: str, modulus: int) -> int:
if modulus < 2:
raise ValueError("calibration modulus must be at least two")
return int(hashlib.sha256(uid.encode("utf-8")).hexdigest(), 16) % modulus
def choice_margin(row: dict[str, Any]) -> float:
# New confirmatory runs use the same full-vocabulary first-token margin for
# MCQ and open-ended questions. Older exploratory artifacts contain only
# the option-letter diagnostic and remain readable for historical audits.
confidence = row.get("generation_confidence") or row.get("choice_confidence")
if not isinstance(confidence, dict):
raise ValueError(f"{row.get('uid')}: missing generation confidence")
if confidence.get("task_or_group_used") is not False:
raise ValueError(f"{row.get('uid')}: confidence provenance is not task blind")
value = float(confidence.get("top2_margin"))
if not 0.0 <= value <= 1.0:
raise ValueError(f"{row.get('uid')}: invalid generation margin")
return value
def select_prediction(
recent_row: dict[str, Any], temporal_row: dict[str, Any], threshold: float
) -> tuple[str, bool]:
escalate = choice_margin(recent_row) <= threshold
source = temporal_row if escalate else recent_row
return str(
source.get("prediction") or source.get("selected_prediction") or ""
), escalate
def confidence_gain(
recent_row: dict[str, Any], temporal_row: dict[str, Any]
) -> float:
"""Return the task-blind confidence change after acquiring the temporal view."""
return choice_margin(temporal_row) - choice_margin(recent_row)
def select_acquire_commit_prediction(
recent_row: dict[str, Any],
temporal_row: dict[str, Any],
acquire_threshold: float,
commit_threshold: float,
) -> tuple[str, bool, bool, float]:
"""Apply one shared acquire threshold and one shared safe-commit threshold."""
acquired = choice_margin(recent_row) <= acquire_threshold
recent_prediction = str(
recent_row.get("prediction") or recent_row.get("selected_prediction") or ""
)
temporal_prediction = str(
temporal_row.get("prediction")
or temporal_row.get("selected_prediction")
or ""
)
gain = confidence_gain(recent_row, temporal_row)
committed = bool(
acquired
and temporal_prediction != recent_prediction
and gain > commit_threshold
)
return (
temporal_prediction if committed else recent_prediction,
acquired,
committed,
gain,
)
def evaluate_threshold(
uids: list[str],
*,
recent: dict[str, dict[str, Any]],
temporal: dict[str, dict[str, Any]],
recent_scores: dict[str, dict[str, Any]],
temporal_scores: dict[str, dict[str, Any]],
threshold: float,
) -> tuple[int, int]:
correct = 0
escalated = 0
for uid in uids:
_, did_escalate = select_prediction(
recent[uid], temporal[uid], threshold
)
official = temporal_scores[uid] if did_escalate else recent_scores[uid]
correct += int(bool(official["correct"]))
escalated += int(did_escalate)
return correct, escalated
def fit_threshold(
calibration_uids: list[str],
*,
recent: dict[str, dict[str, Any]],
temporal: dict[str, dict[str, Any]],
recent_scores: dict[str, dict[str, Any]],
temporal_scores: dict[str, dict[str, Any]],
) -> tuple[float, list[dict[str, Any]]]:
margins = sorted({choice_margin(recent[uid]) for uid in calibration_uids})
candidates = [-1.0, *margins, 1.0]
sweep = []
for threshold in candidates:
correct, escalated = evaluate_threshold(
calibration_uids,
recent=recent,
temporal=temporal,
recent_scores=recent_scores,
temporal_scores=temporal_scores,
threshold=threshold,
)
sweep.append(
{
"threshold": threshold,
"correct": correct,
"total": len(calibration_uids),
"accuracy": correct / len(calibration_uids),
"escalated": escalated,
}
)
best = max(
sweep,
key=lambda row: (
int(row["correct"]),
-int(row["escalated"]),
-float(row["threshold"]),
),
)
return float(best["threshold"]), sweep
def evaluate_acquire_commit_thresholds(
uids: list[str],
*,
recent: dict[str, dict[str, Any]],
temporal: dict[str, dict[str, Any]],
recent_scores: dict[str, dict[str, Any]],
temporal_scores: dict[str, dict[str, Any]],
acquire_threshold: float,
commit_threshold: float,
) -> tuple[int, int, int]:
correct = 0
acquired = 0
committed = 0
for uid in uids:
_, did_acquire, did_commit, _ = select_acquire_commit_prediction(
recent[uid],
temporal[uid],
acquire_threshold,
commit_threshold,
)
official = temporal_scores[uid] if did_commit else recent_scores[uid]
correct += int(bool(official["correct"]))
acquired += int(did_acquire)
committed += int(did_commit)
return correct, acquired, committed
def fit_acquire_commit_thresholds(
calibration_uids: list[str],
*,
recent: dict[str, dict[str, Any]],
temporal: dict[str, dict[str, Any]],
recent_scores: dict[str, dict[str, Any]],
temporal_scores: dict[str, dict[str, Any]],
) -> tuple[float, float, list[dict[str, Any]]]:
acquire_candidates = [
-1.000001,
*sorted({choice_margin(recent[uid]) for uid in calibration_uids}),
1.000001,
]
commit_candidates = [
-1.000001,
*sorted(
{confidence_gain(recent[uid], temporal[uid]) for uid in calibration_uids}
),
1.000001,
]
sweep = []
for acquire_threshold in acquire_candidates:
for commit_threshold in commit_candidates:
correct, acquired, committed = evaluate_acquire_commit_thresholds(
calibration_uids,
recent=recent,
temporal=temporal,
recent_scores=recent_scores,
temporal_scores=temporal_scores,
acquire_threshold=acquire_threshold,
commit_threshold=commit_threshold,
)
sweep.append(
{
"acquire_threshold": acquire_threshold,
"commit_threshold": commit_threshold,
"correct": correct,
"total": len(calibration_uids),
"accuracy": correct / len(calibration_uids),
"acquired": acquired,
"committed": committed,
}
)
best = max(
sweep,
key=lambda row: (
int(row["correct"]),
-int(row["acquired"]),
-int(row["committed"]),
-float(row["acquire_threshold"]),
float(row["commit_threshold"]),
),
)
return (
float(best["acquire_threshold"]),
float(best["commit_threshold"]),
sweep,
)
def main() -> None:
args = parse_args()
recent_result = load_result(args.recent)
temporal_result = load_result(args.temporal)
for field in ("benchmark", "model_manifest_sha256", "samples_sha256"):
if recent_result.get(field) != temporal_result.get(field):
raise ValueError(f"recent/temporal identity mismatch: {field}")
recent = index_rows(recent_result)
temporal = index_rows(temporal_result)
recent_scores = index_scores(recent_result)
temporal_scores = index_temporal_scores(temporal_result)
if (
set(recent) != set(temporal)
or set(recent) != set(recent_scores)
or set(recent) != set(temporal_scores)
):
raise ValueError("recent, temporal, and score UID sets must match exactly")
if any(row.get("task") is None for row in recent_scores.values()):
raise ValueError("score rows require task labels for reporting only")
ordered_uids = [str(row["uid"]) for row in recent_result["rows"]]
calibration_uids = [
uid
for uid in ordered_uids
if calibration_bucket(uid, args.calibration_modulus) == 0
]
evaluation_uids = [uid for uid in ordered_uids if uid not in calibration_uids]
if not calibration_uids or not evaluation_uids:
raise ValueError("deterministic split produced an empty partition")
acquire_threshold, commit_threshold, sweep = fit_acquire_commit_thresholds(
calibration_uids,
recent=recent,
temporal=temporal,
recent_scores=recent_scores,
temporal_scores=temporal_scores,
)
rows = []
calibration_set = set(calibration_uids)
by_task: dict[str, list[int]] = defaultdict(lambda: [0, 0])
for uid in ordered_uids:
prediction, escalated, committed, gain = select_acquire_commit_prediction(
recent[uid], temporal[uid], acquire_threshold, commit_threshold
)
official = temporal_scores[uid] if committed else recent_scores[uid]
correct = bool(official["correct"])
partition = "calibration" if uid in calibration_set else "evaluation"
task = str(recent_scores[uid]["task"])
if partition == "evaluation":
by_task[task][0] += int(correct)
by_task[task][1] += 1
rows.append(
{
"uid": uid,
"partition": partition,
"margin": choice_margin(recent[uid]),
"temporal_margin": choice_margin(temporal[uid]),
"confidence_gain": gain,
"acquire_threshold": acquire_threshold,
"commit_threshold": commit_threshold,
"escalated": escalated,
"committed": committed,
"joint_required_after_escalation": bool(
escalated and temporal[uid].get("joint_required", False)
),
"prediction": prediction,
"correct": correct,
"task": task,
"task_used_by_policy": False,
}
)
def partition_summary(partition: str) -> dict[str, Any]:
chosen = [row for row in rows if row["partition"] == partition]
correct = sum(int(row["correct"]) for row in chosen)
escalated = sum(int(row["escalated"]) for row in chosen)
committed = sum(int(row["committed"]) for row in chosen)
joint_calls = sum(
int(row["joint_required_after_escalation"]) for row in chosen
)
return {
"correct": correct,
"total": len(chosen),
"accuracy": correct / len(chosen),
"escalated": escalated,
"escalation_rate": escalated / len(chosen),
"committed": committed,
"commit_rate": committed / len(chosen),
"joint_calls": joint_calls,
"mean_model_calls": (len(chosen) + escalated + joint_calls)
/ len(chosen),
}
internal_calibration = (
recent_result.get("benchmark") == "internal_policy_holdout"
and recent_result.get("status")
== "source_disjoint_internal_controller_calibration"
and temporal_result.get("status")
== "source_disjoint_internal_controller_calibration"
)
output = {
"format": "streameva.uncertainty_temporal_escalation_audit.v0",
"status": (
"source_disjoint_internal_threshold_calibration"
if internal_calibration
else "benchmark_selected_exploratory_not_confirmatory"
),
"eligible_as_frozen_benchmark_controller_config": internal_calibration,
"benchmark": recent_result.get("benchmark"),
"model_manifest_sha256": recent_result.get("model_manifest_sha256"),
"policy": {
"first_view": (
"recorded_initial_causal_view" if internal_calibration else "recent"
),
"second_view": (
"all_recorded_causal_views"
if internal_calibration
else temporal_result.get("inference_policy")
),
"trigger": "recent_first_step_generation_top2_margin_leq_global_threshold",
"threshold": acquire_threshold,
"acquire_threshold": acquire_threshold,
"commit_threshold": commit_threshold,
"commit_signal": "temporal_minus_recent_full_vocabulary_top2_margin",
"commit_rule": "changed_answer_and_confidence_gain_gt_global_threshold",
"task_group_or_question_router": False,
"gold_available_at_runtime": False,
},
"split": {
"method": "sha256(uid) modulo calibration_modulus",
"calibration_modulus": args.calibration_modulus,
"calibration_bucket": 0,
},
"calibration": partition_summary("calibration"),
"evaluation": partition_summary("evaluation"),
"evaluation_by_task_reporting_only": {
task: {"correct": values[0], "total": values[1], "accuracy": values[0] / values[1]}
for task, values in sorted(by_task.items())
},
"calibration_sweep": sweep,
"rows": rows,
}
args.output.parent.mkdir(parents=True, exist_ok=True)
args.output.write_text(
json.dumps(output, indent=2, sort_keys=True) + "\n", encoding="utf-8"
)
print(
json.dumps(
{
"acquire_threshold": acquire_threshold,
"commit_threshold": commit_threshold,
**output["evaluation"],
},
sort_keys=True,
)
)
if __name__ == "__main__":
main()