Download scripts/run_comprehensive_evaluation.py from augustocsc/test_base_infix_1epoch: direct link, hf CLI and curl.
- Browser
- Download file 16 kB
-
https://huggingface.co/augustocsc/test_base_infix_1epoch/resolve/main/scripts/run_comprehensive_evaluation.py
- Command line
-
hf download hf://augustocsc/test_base_infix_1epoch/scripts/run_comprehensive_evaluation.py
-
curl -L -o run_comprehensive_evaluation.py https://huggingface.co/augustocsc/test_base_infix_1epoch/resolve/main/scripts/run_comprehensive_evaluation.py
16 kB
| #!/usr/bin/env python3 | |
| """ | |
| Comprehensive Evaluation Suite for Symbolic Regression Models | |
| Evaluates all models on Nguyen benchmarks with PPO and GRPO algorithms | |
| """ | |
| import os | |
| import sys | |
| import json | |
| import argparse | |
| import logging | |
| import subprocess | |
| import datetime | |
| from pathlib import Path | |
| from typing import Dict, List | |
| import time | |
| logging.basicConfig( | |
| level=logging.INFO, | |
| format='%(asctime)s - %(levelname)s - %(message)s' | |
| ) | |
| logger = logging.getLogger(__name__) | |
| class ComprehensiveEvaluator: | |
| """Orchestrates evaluation of all models on all benchmarks.""" | |
| def __init__(self, output_dir: str = "./evaluation_results"): | |
| self.output_dir = Path(output_dir) | |
| self.output_dir.mkdir(parents=True, exist_ok=True) | |
| self.timestamp = datetime.datetime.now().strftime("%Y%m%d_%H%M%S") | |
| # Define models | |
| self.models = { | |
| "base_prefix": { | |
| "path": "./output/gpt2_base_prefix_682k", | |
| "is_prefix": True, | |
| "size": "124M" | |
| }, | |
| "medium_prefix": { | |
| "path": "./output/gpt2_medium_prefix_682k", | |
| "is_prefix": True, | |
| "size": "355M" | |
| }, | |
| "large_prefix": { | |
| "path": "./output/gpt2_large_prefix_682k", | |
| "is_prefix": True, | |
| "size": "774M" | |
| }, | |
| "base_infix": { | |
| "path": "augustocsc/Se124M_700K_infix_v3_json", | |
| "is_prefix": False, | |
| "size": "124M" | |
| } | |
| } | |
| # Define benchmarks | |
| self.benchmarks = {} | |
| for i in range(1, 13): | |
| self.benchmarks[f"nguyen_{i}"] = f"./data/benchmarks/nguyen/nguyen_{i}.csv" | |
| # Algorithms to evaluate | |
| self.algorithms = ["ppo", "grpo"] | |
| # Unified prompt for all models | |
| self.unified_prompt = self._build_unified_prompt() | |
| def _build_unified_prompt(self) -> Dict[str, str]: | |
| """Build unified prompts for prefix and infix models.""" | |
| all_ops = ["*", "+", "-", "/", "sin", "cos", "tan", "exp", "log", "sqrt", "abs"] | |
| # Prefix prompt (max 5 variables to cover all benchmarks) | |
| prefix_prompt = f"vars: x_1, x_2, x_3, x_4, x_5\noper: {', '.join(all_ops)}\ncons: C\nexpr: " | |
| # JSON prompt for infix | |
| json_prompt = json.dumps({ | |
| "vars": ["x_1", "x_2", "x_3", "x_4", "x_5"], | |
| "ops": all_ops, | |
| "cons": "C", | |
| "expr": "" | |
| })[:-2] # Remove closing "} | |
| return { | |
| "prefix": prefix_prompt, | |
| "infix": json_prompt | |
| } | |
| def run_experiment( | |
| self, | |
| model_name: str, | |
| model_info: dict, | |
| benchmark_name: str, | |
| benchmark_path: str, | |
| algorithm: str, | |
| epochs: int = 20, | |
| samples_per_epoch: int = 32 | |
| ) -> Dict: | |
| """Run a single experiment.""" | |
| logger.info(f"Running: {model_name} + {benchmark_name} + {algorithm.upper()}") | |
| # Determine output directory | |
| exp_output_dir = self.output_dir / f"{self.timestamp}" / model_name / benchmark_name / algorithm | |
| exp_output_dir.mkdir(parents=True, exist_ok=True) | |
| # Select appropriate prompt | |
| prompt = self.unified_prompt["prefix"] if model_info["is_prefix"] else self.unified_prompt["infix"] | |
| # Build command | |
| if algorithm == "ppo": | |
| script = "scripts/ppo_symbolic_enhanced.py" | |
| cmd = [ | |
| sys.executable, script, | |
| "--model_path", model_info["path"], | |
| "--dataset", benchmark_path, | |
| "--output_dir", str(exp_output_dir), | |
| "--epochs", str(epochs), | |
| "--samples_per_epoch", str(samples_per_epoch), | |
| "--custom_prompt", prompt, | |
| "--learning_rate", "3e-5" | |
| ] | |
| else: # grpo | |
| script = "scripts/grpo_symbolic_enhanced.py" | |
| cmd = [ | |
| sys.executable, script, | |
| "--model_path", model_info["path"], | |
| "--dataset", benchmark_path, | |
| "--output_dir", str(exp_output_dir), | |
| "--epochs", str(epochs), | |
| "--samples_per_group", "8", | |
| "--groups_per_epoch", str(samples_per_epoch // 8), | |
| "--custom_prompt", prompt, | |
| "--learning_rate", "5e-5" | |
| ] | |
| # Add prefix flag if needed | |
| if model_info["is_prefix"]: | |
| cmd.append("--is_prefix") | |
| # Run experiment | |
| start_time = time.time() | |
| try: | |
| result = subprocess.run( | |
| cmd, | |
| capture_output=True, | |
| text=True, | |
| timeout=1800 # 30 minute timeout | |
| ) | |
| duration = time.time() - start_time | |
| # Load results | |
| summary_path = exp_output_dir / "summary.json" | |
| history_path = exp_output_dir / "full_history.json" | |
| if summary_path.exists(): | |
| with open(summary_path) as f: | |
| summary = json.load(f) | |
| else: | |
| summary = { | |
| "error": "No summary file found", | |
| "stdout": result.stdout[-1000:], | |
| "stderr": result.stderr[-1000:] | |
| } | |
| if history_path.exists(): | |
| with open(history_path) as f: | |
| history = json.load(f) | |
| else: | |
| history = [] | |
| return { | |
| "success": result.returncode == 0, | |
| "duration": duration, | |
| "summary": summary, | |
| "history": history, | |
| "model": model_name, | |
| "benchmark": benchmark_name, | |
| "algorithm": algorithm | |
| } | |
| except subprocess.TimeoutExpired: | |
| logger.error(f"Timeout for {model_name} + {benchmark_name} + {algorithm}") | |
| return { | |
| "success": False, | |
| "error": "Timeout", | |
| "duration": time.time() - start_time, | |
| "model": model_name, | |
| "benchmark": benchmark_name, | |
| "algorithm": algorithm | |
| } | |
| except Exception as e: | |
| logger.error(f"Error in {model_name} + {benchmark_name} + {algorithm}: {e}") | |
| return { | |
| "success": False, | |
| "error": str(e), | |
| "duration": time.time() - start_time, | |
| "model": model_name, | |
| "benchmark": benchmark_name, | |
| "algorithm": algorithm | |
| } | |
| def run_full_suite( | |
| self, | |
| models_to_run: List[str] = None, | |
| benchmarks_to_run: List[str] = None, | |
| algorithms_to_run: List[str] = None, | |
| epochs: int = 20, | |
| samples_per_epoch: int = 32 | |
| ): | |
| """Run complete evaluation suite.""" | |
| # Use all if not specified | |
| if models_to_run is None: | |
| models_to_run = list(self.models.keys()) | |
| if benchmarks_to_run is None: | |
| benchmarks_to_run = list(self.benchmarks.keys()) | |
| if algorithms_to_run is None: | |
| algorithms_to_run = self.algorithms | |
| total_experiments = len(models_to_run) * len(benchmarks_to_run) * len(algorithms_to_run) | |
| logger.info(f"Starting evaluation suite: {total_experiments} experiments") | |
| logger.info(f"Models: {models_to_run}") | |
| logger.info(f"Benchmarks: {benchmarks_to_run}") | |
| logger.info(f"Algorithms: {algorithms_to_run}") | |
| results = [] | |
| completed = 0 | |
| for model_name in models_to_run: | |
| if model_name not in self.models: | |
| logger.warning(f"Model {model_name} not found, skipping") | |
| continue | |
| model_info = self.models[model_name] | |
| # Check if model exists | |
| if not model_info["path"].startswith("augustocsc/"): # Local model | |
| if not Path(model_info["path"]).exists(): | |
| logger.warning(f"Model path {model_info['path']} not found, skipping") | |
| continue | |
| for benchmark_name in benchmarks_to_run: | |
| if benchmark_name not in self.benchmarks: | |
| logger.warning(f"Benchmark {benchmark_name} not found, skipping") | |
| continue | |
| benchmark_path = self.benchmarks[benchmark_name] | |
| for algorithm in algorithms_to_run: | |
| completed += 1 | |
| logger.info(f"\n[{completed}/{total_experiments}] " | |
| f"{model_name} + {benchmark_name} + {algorithm}") | |
| logger.info("-" * 60) | |
| result = self.run_experiment( | |
| model_name=model_name, | |
| model_info=model_info, | |
| benchmark_name=benchmark_name, | |
| benchmark_path=benchmark_path, | |
| algorithm=algorithm, | |
| epochs=epochs, | |
| samples_per_epoch=samples_per_epoch | |
| ) | |
| results.append(result) | |
| # Save intermediate results | |
| self.save_results(results) | |
| # Generate final report | |
| self.generate_report(results) | |
| return results | |
| def save_results(self, results: List[Dict]): | |
| """Save intermediate results.""" | |
| output_path = self.output_dir / f"{self.timestamp}" / "raw_results.json" | |
| output_path.parent.mkdir(exist_ok=True) | |
| with open(output_path, "w") as f: | |
| json.dump(results, f, indent=2) | |
| def generate_report(self, results: List[Dict]): | |
| """Generate comprehensive report.""" | |
| report = { | |
| "timestamp": self.timestamp, | |
| "total_experiments": len(results), | |
| "successful": sum(1 for r in results if r.get("success", False)), | |
| "failed": sum(1 for r in results if not r.get("success", False)), | |
| "summary_table": [], | |
| "best_per_benchmark": {}, | |
| "best_per_model": {} | |
| } | |
| # Build summary table | |
| for result in results: | |
| if result.get("success") and "summary" in result: | |
| summary = result["summary"] | |
| report["summary_table"].append({ | |
| "model": result["model"], | |
| "benchmark": result["benchmark"], | |
| "algorithm": result["algorithm"], | |
| "best_r2": summary.get("best_r2", -1), | |
| "best_expression": summary.get("best_expression", ""), | |
| "best_epoch": summary.get("best_epoch", -1), | |
| "final_valid_rate": summary.get("final_valid_rate", 0), | |
| "duration": result.get("duration", 0) | |
| }) | |
| # Track best per benchmark | |
| bench = result["benchmark"] | |
| if bench not in report["best_per_benchmark"] or \ | |
| summary.get("best_r2", -1) > report["best_per_benchmark"][bench]["r2"]: | |
| report["best_per_benchmark"][bench] = { | |
| "r2": summary.get("best_r2", -1), | |
| "expression": summary.get("best_expression", ""), | |
| "model": result["model"], | |
| "algorithm": result["algorithm"], | |
| "epoch": summary.get("best_epoch", -1) | |
| } | |
| # Track best per model | |
| model = result["model"] | |
| if model not in report["best_per_model"]: | |
| report["best_per_model"][model] = {} | |
| if bench not in report["best_per_model"][model] or \ | |
| summary.get("best_r2", -1) > report["best_per_model"][model][bench]["r2"]: | |
| report["best_per_model"][model][bench] = { | |
| "r2": summary.get("best_r2", -1), | |
| "expression": summary.get("best_expression", ""), | |
| "algorithm": result["algorithm"], | |
| "epoch": summary.get("best_epoch", -1) | |
| } | |
| # Save report | |
| report_path = self.output_dir / f"{self.timestamp}" / "report.json" | |
| with open(report_path, "w") as f: | |
| json.dump(report, f, indent=2) | |
| # Generate markdown report | |
| self.generate_markdown_report(report) | |
| logger.info(f"Report saved to {report_path}") | |
| def generate_markdown_report(self, report: Dict): | |
| """Generate human-readable markdown report.""" | |
| md_lines = [] | |
| md_lines.append("# Comprehensive Symbolic Regression Evaluation Report") | |
| md_lines.append(f"\n**Date**: {report['timestamp']}") | |
| md_lines.append(f"**Total Experiments**: {report['total_experiments']}") | |
| md_lines.append(f"**Successful**: {report['successful']}") | |
| md_lines.append(f"**Failed**: {report['failed']}") | |
| # Best per benchmark table | |
| md_lines.append("\n## Best Results per Benchmark\n") | |
| md_lines.append("| Benchmark | Best R² | Model | Algorithm | Expression | Epoch |") | |
| md_lines.append("|-----------|---------|-------|-----------|------------|-------|") | |
| for bench in sorted(report["best_per_benchmark"].keys()): | |
| data = report["best_per_benchmark"][bench] | |
| expr = data["expression"][:50] + "..." if len(data["expression"]) > 50 else data["expression"] | |
| md_lines.append(f"| {bench} | {data['r2']:.4f} | {data['model']} | " | |
| f"{data['algorithm']} | {expr} | {data['epoch']} |") | |
| # Model comparison table | |
| md_lines.append("\n## Model Comparison\n") | |
| for model in sorted(report["best_per_model"].keys()): | |
| md_lines.append(f"\n### {model}\n") | |
| md_lines.append("| Benchmark | Best R² | Algorithm | Expression | Epoch |") | |
| md_lines.append("|-----------|---------|-----------|------------|-------|") | |
| for bench in sorted(report["best_per_model"][model].keys()): | |
| data = report["best_per_model"][model][bench] | |
| expr = data["expression"][:50] + "..." if len(data["expression"]) > 50 else data["expression"] | |
| md_lines.append(f"| {bench} | {data['r2']:.4f} | {data['algorithm']} | {expr} | {data['epoch']} |") | |
| # Save markdown | |
| md_path = self.output_dir / f"{self.timestamp}" / "report.md" | |
| with open(md_path, "w") as f: | |
| f.write("\n".join(md_lines)) | |
| logger.info(f"Markdown report saved to {md_path}") | |
| def main(): | |
| parser = argparse.ArgumentParser() | |
| parser.add_argument("--output_dir", default="./evaluation_results") | |
| parser.add_argument("--models", nargs="+", help="Models to evaluate") | |
| parser.add_argument("--benchmarks", nargs="+", help="Benchmarks to run") | |
| parser.add_argument("--algorithms", nargs="+", default=["ppo", "grpo"]) | |
| parser.add_argument("--epochs", type=int, default=20) | |
| parser.add_argument("--samples_per_epoch", type=int, default=32) | |
| parser.add_argument("--quick_test", action="store_true", help="Run quick test with subset") | |
| args = parser.parse_args() | |
| evaluator = ComprehensiveEvaluator(output_dir=args.output_dir) | |
| if args.quick_test: | |
| # Quick test with subset | |
| results = evaluator.run_full_suite( | |
| models_to_run=["base_prefix"], | |
| benchmarks_to_run=["nguyen_1"], | |
| algorithms_to_run=["ppo"], | |
| epochs=2, | |
| samples_per_epoch=8 | |
| ) | |
| else: | |
| results = evaluator.run_full_suite( | |
| models_to_run=args.models, | |
| benchmarks_to_run=args.benchmarks, | |
| algorithms_to_run=args.algorithms, | |
| epochs=args.epochs, | |
| samples_per_epoch=args.samples_per_epoch | |
| ) | |
| logger.info("Evaluation complete!") | |
| if __name__ == "__main__": | |
| main() |