Source code for llmp.components.evaluation.engine

from llmp.components.base import BaseEvaluationEngine
from llmp.data_model import JobRecord, ExampleRecord
from llmp.components.generator import SequentialAsyncGenerator
from llmp.data_model.events import Event
from llmp.types import GenOutput
import llmp.components.evaluation.metrics as metrics


[docs]class EvaluationEngine(BaseEvaluationEngine): """ The EvaluationEngine is responsible for evaluating the generated examples and updating the job accordingly. """
[docs] def __init__(self, job: JobRecord, num_runs: int = 5): """Initialize the EvaluationEngine with a job and job settings. Args: job: JobRecord num_runs: int """ super().__init__(job) self._num_runs = num_runs
[docs] def evaluate(self, records: list[ExampleRecord], job_settings: dict = None): """Evaluate the generated examples for a specific job.""" generator = SequentialAsyncGenerator(self.job, job_settings, self._num_runs) # generate outputs results = generator.generate(input_data=[record.input for record in records]) assert len(results) == len(records) sample_metrics = [] for outputs_metrics, sample_record in zip(results, records): sample_metric = self.compute_sample_metrics(outputs_metrics, sample_record.output, sample_record.input) sample_metrics.append(sample_metric) self.job.log_event( Event.from_sample_metric(sample_metric, job_settings, example_id=sample_record.idx) ) aggregated_metrics = self.compute_metrics(sample_metrics) self.job.log_event( Event.from_evaluation_metric(aggregated_metrics, job_settings, example_ids=[r.idx for r in records]) ) return aggregated_metrics
[docs] def compute_sample_metrics(self, outputs_metrics: list[GenOutput], ideal_output: dict, sample_input: dict) -> dict: """Compute metrics for a single generation sample from multiple runs.""" # unpack outputs and metrics outputs, run_metrics = [o for o, _ in outputs_metrics], [m for _, m in outputs_metrics] # Compute accuracy if self.job.is_explicit: accuracy_metrics = metrics.explicit_accuracy(outputs, ideal_output) else: accuracy_metrics = metrics.implicit_accuracy(outputs, ideal_output, self.job, sample_input) # Aggregate metrics return { "accuracy": accuracy_metrics, "execution_time": metrics.avg_efficiency(run_metrics), "failure_rate": metrics.avg_failure_rate(run_metrics), "token_usage": metrics.avg_token_usage(run_metrics), "num_runs": len(run_metrics), "model_name": run_metrics[0]["model_name"], "model_config": run_metrics[0]["model_config"], "errors": [e for m in run_metrics for e in m["errors"] if m["errors"] is not None] }
[docs] def compute_metrics(self, sample_metrics: list[dict]) -> dict: """Compute metrics for a single generation sample from multiple runs.""" return { "accuracy": metrics.avg_accuracy(sample_metrics), "execution_time": metrics.avg_efficiency(sample_metrics), "failure_rate": metrics.avg_failure_rate(sample_metrics), "token_usage": metrics.avg_token_usage(sample_metrics), "num_runs": metrics.avg_num_runs(sample_metrics), "model_name": sample_metrics[0]["model_name"], "model_config": sample_metrics[0]["model_config"], "errors": [e for m in sample_metrics for e in m["errors"] if m["errors"] is not None] }