FST_code / src /lmr /benchmark /benchmark.py
jasonfan's picture
2026-03-19
3b2d368 verified
Raw
History Blame Contribute Delete
6.7 kB
import os
import sys
import subprocess
import json
from pathlib import Path
from typing import Optional
import torch
import traceback
from transformers import GPT2LMHeadModel, GPT2Tokenizer
class Benchmark:
def __init__(self, benchmark_config, model, tokenizer, checkpointing, output_dir, device=None):
self.benchmark_config = benchmark_config
self.model = model
self.tokenizer = tokenizer
self.checkpointing = checkpointing
self.device = device if device is not None else torch.device("cuda" if torch.cuda.is_available() else "cpu")
self.output_dir = Path(f"{benchmark_config.prefix if benchmark_config.prefix is not None else ''}{output_dir}")
self.output_dir.mkdir(parents=True, exist_ok=True)
self.lm_eval_dir = Path(__file__).resolve().parent / "lm-evaluation-harness"
self.results_dir = self.output_dir / "results"
self.summary_path = self.output_dir / "summary.json"
self.checkpointing.load_model_states("recent")
self._init_repo()
def _init_repo(self):
if not self.lm_eval_dir.exists():
print("Cloning lm-evaluation-harness...")
subprocess.run([
"git", "clone", "https://github.com/EleutherAI/lm-evaluation-harness", str(self.lm_eval_dir)
], check=True)
print("Installing lm-evaluation-harness...")
subprocess.run(
["pip", "install", "-e", "."],
cwd=str(self.lm_eval_dir),
check=True
)
else:
print("lm-evaluation-harness already installed.")
def run_benchmarks(self):
sys.path.insert(0, str(self.lm_eval_dir))
from lm_eval.evaluator import simple_evaluate
from .benchmark_wrapper import BenchmarkWrapper
summary = self._load_existing_summary()
status_report = {}
model = self.model
if self.benchmark_config.compile:
print(f"Compiling model with mode: {self.benchmark_config.compile_mode}")
model = torch.compile(model, mode=self.benchmark_config.compile_mode)
wrapped_model = BenchmarkWrapper(
model,
self.tokenizer,
device=self.device,
batch_size=self.benchmark_config.batch_size,
dtype=getattr(torch, self.benchmark_config.precision)
)
new_results = {}
for task in self.benchmark_config.tasks:
try:
if task in summary:
print(f"Skipping {task}, already benchmarked.")
status_report[task] = {"status": "cached", "result": summary[task]}
continue
print(f"Running benchmark for task: {task}")
result = simple_evaluate(
model=wrapped_model,
tasks=[task],
num_fewshot=self.benchmark_config.num_fewshot,
batch_size=self.benchmark_config.batch_size,
limit=self.benchmark_config.limit if hasattr(self.benchmark_config, "limit") else None,
bootstrap_iters=self.benchmark_config.bootstrap_iters,
device=self.device,
log_samples=False
)
self.results_dir.mkdir(parents=True, exist_ok=True)
def make_json_safe(obj):
if isinstance(obj, torch.device):
return str(obj)
elif isinstance(obj, dict):
return {k: make_json_safe(v) for k, v in obj.items()}
elif isinstance(obj, list):
return [make_json_safe(v) for v in obj]
elif isinstance(obj, tuple):
return tuple(make_json_safe(v) for v in obj)
else:
return obj
with open(self.results_dir / f"{task}.json", "w") as f:
json.dump(make_json_safe(result), f, indent=2)
task_result = result["results"].get(task, {})
summary[task] = task_result
new_results[task] = task_result
status_report[task] = {"status": "completed", "result": task_result}
except Exception as e:
print(f"⚠️ Warning: Benchmark for task '{task}' failed with error: {e}")
traceback.print_exc()
status_report[task] = {"status": "failed", "error": str(e)}
self._save_summary(summary)
self._print_status_report(status_report)
def _load_existing_summary(self) -> dict:
if self.summary_path.exists():
with open(self.summary_path, "r") as f:
return json.load(f)
return {}
def _save_summary(self, summary: dict):
with open(self.summary_path, "w") as f:
json.dump(summary, f, indent=2)
def _print_status_report(self, report):
def is_metric_key(k):
return any(key in k.lower() for key in ["acc", "f1", "loss", "perplexity", "exact", "score"])
def format_metric(k, v):
clean_key = k.replace(",none", "")
if "norm" in k:
return None
if isinstance(v, dict) and "value" in v:
val = v["value"]
stderr = v.get("stderr", None)
if stderr is not None:
return f"{clean_key}: {val:.5f} ± {stderr:.5f}"
else:
return f"{clean_key}: {val:.5f}"
elif isinstance(v, (float, int)):
return f"{clean_key}: {v:.5f}"
return None
print("\n=== Benchmark Summary Report ===")
for task, info in report.items():
status = info["status"]
if status in {"completed", "cached"}:
label = "✅" if status == "completed" else "📄"
metrics = info["result"]
filtered_metrics = {
k: v for k, v in metrics.items()
if is_metric_key(k)
}
formatted = [
format_metric(k, v)
for k, v in filtered_metrics.items()
if format_metric(k, v) is not None
]
metric_str = ", ".join(formatted)
print(f"{label} {task}: {status} | {metric_str}")
elif status == "failed":
print(f"❌ {task}: {status} | Error: {info['error']}")