Download scripts/run_math_ink_06_p_formula_release.py from cwLeeDev/aiflow-math-ink-06-intermediate: direct link, hf CLI and curl.
- Browser
- Download file 11 kB
-
https://huggingface.co/cwLeeDev/aiflow-math-ink-06-intermediate/resolve/main/scripts/run_math_ink_06_p_formula_release.py
- Command line
-
hf download hf://cwLeeDev/aiflow-math-ink-06-intermediate/scripts/run_math_ink_06_p_formula_release.py
-
curl -L -o run_math_ink_06_p_formula_release.py https://huggingface.co/cwLeeDev/aiflow-math-ink-06-intermediate/resolve/main/scripts/run_math_ink_06_p_formula_release.py
11 kB
| """P Formula 3-seed ํ์ต๋ถํฐ single-student export๊น์ง ์คํจ ํ์๋ก ์ค์ผ์คํธ๋ ์ด์ ํ๋ค.""" | |
| from __future__ import annotations | |
| import argparse | |
| from datetime import datetime, timezone | |
| import json | |
| from pathlib import Path | |
| import subprocess | |
| import sys | |
| from typing import Any, Sequence | |
| PROJECT_ROOT = Path(__file__).parents[1] | |
| SOURCE_ROOT = PROJECT_ROOT / "src" | |
| for path in (PROJECT_ROOT, SOURCE_ROOT): | |
| if str(path) not in sys.path: | |
| sys.path.insert(0, str(path)) | |
| from math_grid_drawer.research.external_corpus import read_jsonl | |
| from math_grid_drawer.research.p_formula_gate06 import audit_p_formula_records06 | |
| from scripts.train_math_ink_06_p_formula_adapter import _file_sha25606 | |
| REQUIRED_SEEDS06 = (17, 31, 47) | |
| def parse_seed_adapters06(values: Sequence[str]) -> dict[int, Path]: | |
| """ํ์ ๋ณ์: `seed=checkpoint` ๋ฌธ์์ด. ์๋ ์๋ฆฌ: 17ยท31ยท47์ ์ค๋ณต ์๋ adapter mapping์ ๋ง๋ ๋ค.""" | |
| adapters: dict[int, Path] = {} | |
| for value in values: | |
| seed_text, separator, path_text = value.partition("=") | |
| if not separator or not path_text: | |
| raise ValueError("adapter๋ `17=path/to/adapter.pt` ํ์์ด์ด์ผ ํฉ๋๋ค.") | |
| try: | |
| seed = int(seed_text) | |
| except ValueError as error: | |
| raise ValueError(f"adapter seed๊ฐ ์ ์๊ฐ ์๋๋๋ค: {seed_text}") from error | |
| if seed in adapters: | |
| raise ValueError(f"adapter seed๊ฐ ์ค๋ณต๋์์ต๋๋ค: {seed}") | |
| adapters[seed] = Path(path_text) | |
| if set(adapters) != set(REQUIRED_SEEDS06): | |
| raise ValueError("seed 17ยท31ยท47 adapter๊ฐ ์ ํํ ํ๋์ฉ ํ์ํฉ๋๋ค.") | |
| return adapters | |
| def build_p_formula_release_commands06( | |
| *, | |
| python: Path, | |
| data: Path, | |
| adapters: dict[int, Path], | |
| output: Path, | |
| recipe: dict[str, Any], | |
| convert_litert: bool, | |
| ) -> list[list[str]]: | |
| """ํ์ ๋ณ์: ์คํ๊ธฐยท๋์ผ P corpusยทseed adapterยทrecipe. ์๋ ์๋ฆฌ: ํ์ตโ์์ฝโ์ฆ๋ฅโexport ์์์ argv๋ฅผ ๊ณ ์ ํ๋ค.""" | |
| training = recipe["training"] | |
| seed_gate = recipe["seed_gate"] | |
| source_minimum = int(recipe["input"]["minimum_independent_sources"]) | |
| commands: list[list[str]] = [] | |
| for seed in REQUIRED_SEEDS06: | |
| commands.append([ | |
| str(python), | |
| str(PROJECT_ROOT / "scripts/train_math_ink_06_p_formula_adapter.py"), | |
| "--data", str(data), | |
| "--adapter", str(adapters[seed]), | |
| "--output", str(output / f"seed{seed}"), | |
| "--seed", str(seed), | |
| "--epochs", str(training["epochs"]), | |
| "--batch-size", str(training["batch_size"]), | |
| "--learning-rate", str(training["learning_rate"]), | |
| "--weight-decay", str(training["weight_decay"]), | |
| "--exact-loss-weight", str(training["exact_loss_weight"]), | |
| "--context-dropout", str(training["context_dropout"]), | |
| "--hidden-size", str(recipe["model"]["hidden_size"]), | |
| "--patience", str(training["patience"]), | |
| "--minimum-independent-sources", str(source_minimum), | |
| "--top1-minimum", str(seed_gate["exact_top1_minimum"]), | |
| "--top5-minimum", str(seed_gate["exact_top5_minimum"]), | |
| "--macro-f1-minimum", str(seed_gate["macro_f1_minimum"]), | |
| "--writer-floor-minimum", str(seed_gate["writer_floor_minimum"]), | |
| "--missing-drop-maximum-pp", | |
| str(seed_gate["missing_metadata_drop_maximum_pp"]), | |
| "--device", str(training["device"]), | |
| ]) | |
| summary = output / "three_seed_summary.json" | |
| summary_command = [ | |
| str(python), | |
| str(PROJECT_ROOT / "scripts/summarize_math_ink_06_p_formula_seeds.py"), | |
| ] | |
| for seed in REQUIRED_SEEDS06: | |
| summary_command.extend(["--report", str(output / f"seed{seed}/report.json")]) | |
| summary_command.extend(["--output", str(summary)]) | |
| commands.append(summary_command) | |
| distillation = recipe["distillation"] | |
| student_dir = output / "student" | |
| distill_command = [ | |
| str(python), | |
| str(PROJECT_ROOT / "scripts/distill_math_ink_06_p_formula_student.py"), | |
| "--data", str(data), | |
| ] | |
| for seed in REQUIRED_SEEDS06: | |
| distill_command.extend([ | |
| "--teacher-report", | |
| str(output / f"seed{seed}/report.json"), | |
| ]) | |
| distill_command.extend([ | |
| "--summary", str(summary), | |
| "--student-adapter", str(adapters[int(distillation["student_seed"])]), | |
| "--output", str(student_dir), | |
| "--seed", str(distillation["student_seed"]), | |
| "--epochs", str(training["epochs"]), | |
| "--batch-size", str(training["batch_size"]), | |
| "--learning-rate", str(training["learning_rate"]), | |
| "--weight-decay", str(training["weight_decay"]), | |
| "--hidden-size", str(distillation["student_formula_adapter_hidden_size"]), | |
| "--temperature", str(distillation["temperature"]), | |
| "--teacher-exact-weight", str(distillation["teacher_exact_weight"]), | |
| "--teacher-family-weight", str(distillation["teacher_family_weight"]), | |
| "--hard-exact-weight", str(distillation["hard_exact_weight"]), | |
| "--hard-family-weight", str(distillation["hard_family_weight"]), | |
| "--patience", str(training["patience"]), | |
| "--minimum-independent-sources", str(source_minimum), | |
| "--distillation-regression-maximum-pp", | |
| str(distillation["maximum_teacher_to_student_regression_pp"]), | |
| "--device", str(training["device"]), | |
| ]) | |
| commands.append(distill_command) | |
| export_command = [ | |
| str(python), | |
| str(PROJECT_ROOT / "scripts/export_math_ink_06_p_formula_student.py"), | |
| "--student-checkpoint", str(student_dir / "p_formula_student_adapter.pt"), | |
| "--data", str(data), | |
| "--output", str(output / "export"), | |
| ] | |
| if convert_litert: | |
| export_command.append("--convert-litert") | |
| commands.append(export_command) | |
| return commands | |
| def _write_json06(path: Path, value: dict[str, Any]) -> None: | |
| """ํ์ ๋ณ์: ๋ชฉํ ๊ฒฝ๋กยทJSON ๊ฐ. ์๋ ์๋ฆฌ: UTF-8 ์์ ํ์ผ์ ์์์ ์ผ๋ก ๊ต์ฒดํ๋ค.""" | |
| path.parent.mkdir(parents=True, exist_ok=True) | |
| temporary = path.with_suffix(path.suffix + ".part") | |
| temporary.write_text( | |
| json.dumps(value, ensure_ascii=False, indent=2) + "\n", | |
| encoding="utf-8", | |
| ) | |
| temporary.replace(path) | |
| def _require_gate06(path: Path, keys: Sequence[str]) -> dict[str, Any]: | |
| """ํ์ ๋ณ์: ๋จ๊ณ reportยท์ค์ฒฉ boolean ๊ฒฝ๋ก. ์๋ ์๋ฆฌ: ์ฐ์ถ๋ฌผ ๋ถ์ฌ๋ false gate์์ ์ฆ์ ์ค๋จํ๋ค.""" | |
| if not path.is_file(): | |
| raise RuntimeError(f"๋จ๊ณ report๊ฐ ์์ฑ๋์ง ์์์ต๋๋ค: {path}") | |
| report = json.loads(path.read_text(encoding="utf-8")) | |
| value: Any = report | |
| for key in keys: | |
| value = value[key] | |
| if value is not True: | |
| raise RuntimeError(f"์ ์ release gate๊ฐ ์คํจํ์ต๋๋ค: {path} / {'.'.join(keys)}") | |
| return report | |
| def _parse_args() -> argparse.Namespace: | |
| """ํ์ ๋ณ์: ์ค์ P corpusยท์ธ adapterยท์ถ๋ ฅ. ์๋ ์๋ฆฌ: ์ ์ ๋๋ dry-run release CLI๋ฅผ ๋ง๋ ๋ค.""" | |
| parser = argparse.ArgumentParser(description="Run Math Ink 0.6 P Formula release loop") | |
| parser.add_argument("--data", type=Path, required=True) | |
| parser.add_argument("--adapter", action="append", required=True) | |
| parser.add_argument("--output", type=Path, required=True) | |
| parser.add_argument( | |
| "--recipe", | |
| type=Path, | |
| default=PROJECT_ROOT / "research/configs/MATH-INK-06-P-FORMULA-v1.json", | |
| ) | |
| parser.add_argument("--python", type=Path, default=Path(sys.executable)) | |
| parser.add_argument("--convert-litert", action="store_true") | |
| parser.add_argument("--dry-run", action="store_true") | |
| return parser.parse_args() | |
| def main() -> None: | |
| """ํ์ ๋ณ์: ์น์ธ P corpus์ seed๋ณ ์ ํ adapter. ์๋ ์๋ฆฌ: ๊ฐ gate๋ฅผ ํ์ธํ ๋ค์๋ง ๋ค์ ์ธ๋ถ ํ๋ก์ธ์ค๋ฅผ ์คํํ๋ค.""" | |
| args = _parse_args() | |
| adapters = parse_seed_adapters06(args.adapter) | |
| missing = [str(path) for path in (args.data, args.recipe, args.python, *adapters.values()) if not path.is_file()] | |
| if missing: | |
| raise FileNotFoundError(f"release ์ ๋ ฅ ํ์ผ์ด ์์ต๋๋ค: {missing}") | |
| recipe = json.loads(args.recipe.read_text(encoding="utf-8")) | |
| if recipe.get("recipe_id") != "MATH-INK-06-P-FORMULA-v1": | |
| raise ValueError("์ง์ํ์ง ์๋ P Formula release recipe์ ๋๋ค.") | |
| records = list(read_jsonl(args.data)) | |
| audit = audit_p_formula_records06( | |
| records, | |
| minimum_independent_sources=int(recipe["input"]["minimum_independent_sources"]), | |
| ) | |
| if not audit["eligible_for_product_evaluation"]: | |
| raise ValueError("P Formula corpus๊ฐ ์ ์ release preflight๋ฅผ ํต๊ณผํ์ง ๋ชปํ์ต๋๋ค.") | |
| commands = build_p_formula_release_commands06( | |
| python=args.python, | |
| data=args.data, | |
| adapters=adapters, | |
| output=args.output, | |
| recipe=recipe, | |
| convert_litert=args.convert_litert, | |
| ) | |
| plan = { | |
| "schema": "aiflow-math-ink-06-p-formula-release-plan-v1", | |
| "generated_at": datetime.now(timezone.utc).isoformat(), | |
| "data": str(args.data), | |
| "data_sha256": _file_sha25606(args.data), | |
| "recipe": str(args.recipe), | |
| "adapters": {str(seed): str(path) for seed, path in adapters.items()}, | |
| "commands": commands, | |
| "dry_run": bool(args.dry_run), | |
| "product_validation": False, | |
| } | |
| _write_json06(args.output / "release_plan.json", plan) | |
| if args.dry_run: | |
| print(json.dumps(plan, ensure_ascii=False, indent=2)) | |
| return | |
| for index, command in enumerate(commands): | |
| subprocess.run(command, cwd=PROJECT_ROOT, check=True) | |
| if index < 3: | |
| seed = REQUIRED_SEEDS06[index] | |
| _require_gate06(args.output / f"seed{seed}/report.json", ("seed_gate", "passed")) | |
| elif index == 3: | |
| _require_gate06( | |
| args.output / "three_seed_summary.json", | |
| ("decision", "student_distillation_allowed"), | |
| ) | |
| elif index == 4: | |
| _require_gate06( | |
| args.output / "student/report.json", | |
| ("distillation_gate_passed",), | |
| ) | |
| elif index == 5: | |
| _require_gate06( | |
| args.output / "export/export_manifest.json", | |
| ("torch_export_gate_passed",), | |
| ) | |
| final = { | |
| **plan, | |
| "dry_run": False, | |
| "completed": True, | |
| "torch_export_gate_passed": True, | |
| "litert_requested": bool(args.convert_litert), | |
| "android_validation": False, | |
| "product_validation": False, | |
| "next_gate": "LiteRT parity and Android low/mid/high tier benchmark", | |
| } | |
| _write_json06(args.output / "release_report.json", final) | |
| if __name__ == "__main__": | |
| main() | |