| """기존과 federated 0.6을 전체 P-source holdout에서 동일 분모로 비교한다.""" |
|
|
| from __future__ import annotations |
|
|
| import argparse |
| import json |
| import sys |
| from pathlib import Path |
|
|
| PROJECT_ROOT = Path(__file__).parents[1] |
| SOURCE_ROOT = PROJECT_ROOT / "src" |
| if str(SOURCE_ROOT) not in sys.path: |
| sys.path.insert(0, str(SOURCE_ROOT)) |
| if str(PROJECT_ROOT / "scripts") not in sys.path: |
| sys.path.insert(0, str(PROJECT_ROOT / "scripts")) |
|
|
| from math_grid_drawer.research.ink06_federation import load_product_federation06, resolve_training_device06 |
| from math_grid_drawer.research.math_ink_06 import MathInk06Engine |
| from train_math_ink_06_federated_online import _evaluate_source |
|
|
|
|
| def main() -> None: |
| """필요 변수: base/candidate·세 source. 작동 원리: UCI 공식 test와 HWRT train-writer holdout 전체를 비교한다.""" |
|
|
| parser = argparse.ArgumentParser(description="Evaluate federated Math Ink 0.6") |
| parser.add_argument("--baseline", type=Path, required=True) |
| parser.add_argument("--candidate", type=Path, required=True) |
| parser.add_argument("--registry", type=Path, default=PROJECT_ROOT / "research/dataset_registry.json") |
| parser.add_argument("--source-registry", type=Path, default=PROJECT_ROOT / "research/math_ink_06_source_registry.json") |
| parser.add_argument("--commercial", type=Path, default=PROJECT_ROOT / "research/data/external_trajectory_v1/commercial_ccby4.jsonl.gz") |
| parser.add_argument("--hwrt", type=Path, default=PROJECT_ROOT / "research/data/open_pretrain/hwrt_expanded_v2/hwrt_expanded.jsonl.gz") |
| parser.add_argument("--approval", type=Path, default=PROJECT_ROOT / "research/approvals/HWRT-ODBL-USE-APPROVAL-v1.json") |
| parser.add_argument("--output", type=Path, required=True) |
| parser.add_argument("--batch-size", type=int, default=64) |
| parser.add_argument("--source", action="append", default=[], help="지정한 source만 평가한다. 반복 사용 가능") |
| parser.add_argument("--device", default="auto", help="auto|cpu|cuda[:index]") |
| args = parser.parse_args() |
|
|
| device = resolve_training_device06(args.device) |
| baseline = MathInk06Engine(args.baseline, device=device) |
| candidate = MathInk06Engine(args.candidate, device=device) |
| if baseline.labels != candidate.labels: |
| raise ValueError("baseline과 candidate vocabulary가 다릅니다.") |
| exact_to_index = {label: index for index, label in enumerate(candidate.labels)} |
| family_to_index = {label: index for index, label in enumerate(candidate.family_labels)} |
| sources = load_product_federation06( |
| registry_path=args.registry, commercial_path=args.commercial, hwrt_path=args.hwrt, |
| approval_path=args.approval, allowed_labels=candidate.labels, source_registry_path=args.source_registry, |
| ) |
| groups = {} |
| contracts = {} |
| for source in sources: |
| if args.source and source.source_id not in args.source: |
| continue |
| if source.source_id == "hwrt": |
| groups[source.source_id] = [row for row in source.records if row.get("split") == "test"] |
| contracts[source.source_id] = "HWRT approved train의 AIFlow writer-disjoint test; official test excluded" |
| elif source.source_id == "uci-uji-pen-v1": |
| groups[source.source_id] = [row for row in source.records if row.get("split") == "test"] |
| contracts[source.source_id] = "AIFlow project writer-disjoint w10-w11 test; official UCI task is 11-fold LOOW" |
| else: |
| groups[source.source_id] = [row for row in source.records if row.get("split") == "test"] |
| contracts[source.source_id] = "official UCI writer-independent test" |
| report = { |
| "baseline": str(args.baseline), "candidate": str(args.candidate), "sources": {}, |
| "hwrt_official_test_used": False, "product_validation": False, |
| } |
| for source_id, records in groups.items(): |
| base_metrics = _evaluate_source( |
| baseline, records, exact_to_index, family_to_index, args.batch_size, |
| ) |
| candidate_metrics = _evaluate_source( |
| candidate, records, exact_to_index, family_to_index, args.batch_size, |
| ) |
| report["sources"][source_id] = { |
| "contract": contracts[source_id], "baseline": base_metrics, "candidate": candidate_metrics, |
| "delta": { |
| metric: candidate_metrics[metric] - base_metrics[metric] |
| for metric in ("online_top1", "online_top5", "raster_top1", "raster_top5") |
| }, |
| } |
| args.output.mkdir(parents=True, exist_ok=True) |
| (args.output / "federated_evaluation.json").write_text( |
| json.dumps(report, ensure_ascii=False, indent=2) + "\n", encoding="utf-8", |
| ) |
| print(json.dumps(report, ensure_ascii=False, indent=2)) |
|
|
|
|
| if __name__ == "__main__": |
| main() |
|
|