"""End-to-end model evaluation pipeline."""
import argparse
import json
import logging
import sys
from datetime import datetime
from pathlib import Path
sys.path.insert(0, str(Path(__file__).parent.parent.parent))
from src.utils.logger import setup_logger
from src.utils.visualization import (
plot_confusion_matrix,
plot_label_distribution,
)
logger = setup_logger("evaluation_pipeline")
def evaluate_model(model_path: str, test_data: str, output_dir: str) -> dict:
"""Evaluate a trained model."""
logger.info(f"Evaluating model: {model_path}")
# Run evaluation
import subprocess
result = subprocess.run([
"python", "src/models/evaluate.py",
"--model_path", model_path,
"--data_path", test_data,
"--output_path", f"{output_dir}/results.json",
], capture_output=True, text=True)
logger.info(result.stdout)
if result.returncode != 0:
logger.error(result.stderr)
raise RuntimeError("Evaluation failed")
# Load results
with open(f"{output_dir}/results.json", "r") as f:
results = json.load(f)
return results
def generate_report(results: dict, output_dir: str) -> str:
"""Generate evaluation report with visualizations."""
logger.info("Generating evaluation report...")
report_path = f"{output_dir}/report.html"
# Create visualizations
cm = results["confusion_matrix"]
class_names = results["class_names"]
plot_confusion_matrix(
cm, class_names,
title="Sentiment Classification Confusion Matrix",
output_path=f"{output_dir}/confusion_matrix.png",
)
# Create HTML report
html = f"""
Myanmar Ghost Evaluation Report
🇲🇲 Myanmar Ghost Evaluation Report
Generated: {datetime.now().strftime("%Y-%m-%d %H:%M:%S")}
📊 Metrics
{results['metrics']['accuracy']:.2%}
Accuracy
{results['metrics']['f1_weighted']:.2%}
F1 (weighted)
{results['metrics']['precision_weighted']:.2%}
Precision
{results['metrics']['recall_weighted']:.2%}
Recall
📈 Confusion Matrix
📋 Per-Class Performance
| Class |
F1 Score |
"""
for name in class_names:
f1_key = f"f1_{name}"
if f1_key in results["metrics"]:
html += f"""
| {name} |
{results['metrics'][f1_key]:.4f} |
"""
html += """
"""
with open(report_path, "w", encoding="utf-8") as f:
f.write(html)
logger.info(f"Report saved to {report_path}")
return report_path
def compare_models(model_results: list, output_dir: str) -> dict:
"""Compare multiple model evaluations."""
logger.info(f"Comparing {len(model_results)} models...")
comparison = {
"models": [],
"best_model": None,
"best_f1": 0,
}
for result in model_results:
model_name = result.get("model_name", "unknown")
metrics = result.get("metrics", {})
comparison["models"].append({
"name": model_name,
"accuracy": metrics.get("accuracy", 0),
"f1_weighted": metrics.get("f1_weighted", 0),
"f1_macro": metrics.get("f1_macro", 0),
})
if metrics.get("f1_weighted", 0) > comparison["best_f1"]:
comparison["best_f1"] = metrics.get("f1_weighted", 0)
comparison["best_model"] = model_name
# Save comparison
with open(f"{output_dir}/model_comparison.json", "w") as f:
json.dump(comparison, f, indent=2)
logger.info(f"Best model: {comparison['best_model']} (F1: {comparison['best_f1']:.4f})")
return comparison
def run_evaluation_pipeline(
model_path: str,
test_data: str,
output_dir: str = "outputs/evaluation",
) -> dict:
"""Run full evaluation pipeline."""
Path(output_dir).mkdir(parents=True, exist_ok=True)
# Evaluate model
results = evaluate_model(model_path, test_data, output_dir)
# Generate report
report_path = generate_report(results, output_dir)
return {
"results": results,
"report": report_path,
}
if __name__ == "__main__":
parser = argparse.ArgumentParser()
parser.add_argument("--model_path", type=str, required=True)
parser.add_argument("--test_data", type=str, required=True)
parser.add_argument("--output_dir", type=str, default="outputs/evaluation")
args = parser.parse_args()
run_evaluation_pipeline(args.model_path, args.test_data, args.output_dir)