Frox-nano / Model /scripts /evaluate.py
Hritik045678's picture
Initial commit: Frox Morph Nano 1 (XL) Space
bd97ee9
Raw
History Blame Contribute Delete
5.07 kB
#!/usr/bin/env python3
"""
Frox AI Morph 1.1 — Evaluation Harness
Runs three checks any time you finish a training phase:
1. Perplexity on WikiText-2 (language modeling quality)
2. Sanity generations on a fixed prompt set (coherence spot-check)
3. Throughput benchmark (tokens/sec at a few sequence lengths)
Usage:
python scripts/evaluate.py --model ./frox-morph-1-1-output/sft_final
python scripts/evaluate.py --model ./frox-morph-1-1-output/sft_final --skip-generation
"""
from __future__ import annotations
import argparse
import json
import sys
import time
from pathlib import Path
sys.path.insert(0, str(Path(__file__).resolve().parent.parent))
import torch
from inference.engine.morph_engine import MorphInferenceEngine
from training.pipeline.trainer import evaluate_perplexity
from utils.common import print_banner, timer
SANITY_PROMPTS = [
"What is the capital of France?",
"Write a haiku about the ocean.",
"Explain what a neural network is in two sentences.",
"def fibonacci(n):\n # Complete this function",
"What's 17 times 23?",
"Give me three tips for staying focused while studying.",
]
def run_perplexity(engine: MorphInferenceEngine) -> float:
print("\n📊 Perplexity (WikiText-2)")
ppl = evaluate_perplexity(
engine.model.language_model, engine.tokenizer, engine.device,
max_samples=500, seq_len=512,
use_amp=engine.device.type == "cuda", amp_dtype=engine.dtype,
)
print(f" Perplexity: {ppl}")
return ppl
def run_sanity_generations(engine: MorphInferenceEngine) -> list:
print("\n🧪 Sanity Generations")
results = []
for prompt in SANITY_PROMPTS:
response = engine.generate(
[{"role": "user", "content": prompt}],
max_new_tokens=150, temperature=0.7,
)
has_content = len(response.strip()) > 5
has_repetition = _check_repetition(response)
status = "✓" if has_content and not has_repetition else "⚠"
print(f"\n {status} Q: {prompt}")
print(f" A: {response[:200]}{'...' if len(response) > 200 else ''}")
results.append({
"prompt": prompt, "response": response,
"has_content": has_content, "has_repetition": has_repetition,
})
return results
def _check_repetition(text: str, min_repeat: int = 4) -> bool:
"""Flag degenerate repetition (a common failure mode of undertrained models)."""
words = text.split()
if len(words) < min_repeat * 2:
return False
for i in range(len(words) - min_repeat):
window = tuple(words[i:i + min_repeat])
rest = words[i + min_repeat:i + min_repeat * 2]
if tuple(rest[:min_repeat]) == window:
return True
return False
def run_throughput_benchmark(engine: MorphInferenceEngine) -> dict:
print("\n⚡ Throughput Benchmark")
results = {}
for max_tokens in (50, 200, 500):
t0 = time.perf_counter()
_ = engine.generate(
[{"role": "user", "content": "Tell me a short story about a robot."}],
max_new_tokens=max_tokens, temperature=0.7,
)
elapsed = time.perf_counter() - t0
tok_s = max_tokens / elapsed
results[f"{max_tokens}_tokens"] = {"elapsed_s": round(elapsed, 2), "tok_per_s": round(tok_s, 1)}
print(f" {max_tokens:>4} tokens: {elapsed:.2f}s ({tok_s:.1f} tok/s)")
return results
def main():
parser = argparse.ArgumentParser(description="Evaluate Frox AI Morph 1.1")
parser.add_argument("--model", type=str, required=True)
parser.add_argument("--skip-perplexity", action="store_true")
parser.add_argument("--skip-generation", action="store_true")
parser.add_argument("--skip-throughput", action="store_true")
parser.add_argument("--output", type=str, default="./eval_results.json")
args = parser.parse_args()
print_banner()
engine = MorphInferenceEngine.from_pretrained(args.model)
report = {"model_path": args.model, "stats": engine.stats()}
if not args.skip_perplexity:
with timer("Perplexity eval"):
report["perplexity"] = run_perplexity(engine)
if not args.skip_generation:
with timer("Sanity generations"):
report["sanity_generations"] = run_sanity_generations(engine)
n_ok = sum(1 for r in report["sanity_generations"]
if r["has_content"] and not r["has_repetition"])
report["sanity_pass_rate"] = f"{n_ok}/{len(SANITY_PROMPTS)}"
if not args.skip_throughput:
with timer("Throughput benchmark"):
report["throughput"] = run_throughput_benchmark(engine)
Path(args.output).write_text(json.dumps(report, indent=2, default=str))
print(f"\n✅ Full report saved to {args.output}")
if "perplexity" in report:
print(f"\n{'='*50}")
print(f"SUMMARY: perplexity={report['perplexity']} | "
f"sanity={report.get('sanity_pass_rate', 'skipped')}")
print(f"{'='*50}")
if __name__ == "__main__":
main()