创建自定义评估器
创建自定义评估器
FreeEval的模块化架构使创建自定义评估方法变得简单。本指南将指导您实现自己的评估步骤并将其集成到框架中。
概述
在FreeEval中创建自定义评估器涉及:
- 实现自定义评估步骤类
- 向框架注册您的步骤
- 在评估配置中使用您的自定义步骤
这种可扩展性允许您添加专门的评估指标,整合特定领域知识,或实现超出FreeEval内置功能的新型评估技术。
步骤1:实现自定义步骤
让我们创建一个简单的自定义评估器,用于评估模型识别质数的能力。我们将文件命名为custom_evaluator.py并放在freeeval/steps目录中。
from typing import Dict, Any, List, Optionalfrom freeeval.steps.base_step import BaseEvaluationStepfrom freeeval.data.dataset import Datasetfrom freeeval.models.base_model import BaseModelimport sympy # 用于质数检查import numpy as np
class PrimeNumberIdentificationStep(BaseEvaluationStep): """评估模型识别数字是否为质数能力的步骤。"""
def __init__(self, name: str, save_dataset: bool = False, save_path: Optional[str] = None, **kwargs): """初始化质数识别步骤。""" super().__init__(name, save_dataset, save_path, **kwargs)
def prepare_dataset(self, dataset: Dataset) -> Dataset: """准备评估数据集。""" # 此步骤需要包含待检查数字的数据集 # 如需添加任何预处理,请在此处进行 return dataset
def format_prompt(self, example: Dict[str, Any]) -> str: """为模型格式化提示。""" return f"{example['number']}是质数吗?请回答'是'或'否'。"
def evaluate_example(self, example: Dict[str, Any], model_response: str) -> Dict[str, Any]: """评估模型对单个示例的响应。""" number = example['number'] is_prime = sympy.isprime(number)
# 清理和规范化模型的响应 response_text = model_response.strip().lower() predicted_prime = ("是" in response_text) and ("否" not in response_text)
# 计算正确性 is_correct = (is_prime == predicted_prime)
return { "number": number, "is_prime": is_prime, "model_prediction": predicted_prime, "is_correct": is_correct, }
def aggregate_results(self, results: List[Dict[str, Any]]) -> Dict[str, Any]: """汇总所有评估示例的结果。""" correct_count = sum(result["is_correct"] for result in results) total_count = len(results) accuracy = correct_count / total_count if total_count > 0 else 0
# 分别计算质数和非质数的表现 prime_results = [r for r in results if r["is_prime"]] nonprime_results = [r for r in results if not r["is_prime"]]
prime_accuracy = sum(r["is_correct"] for r in prime_results) / len(prime_results) if prime_results else 0 nonprime_accuracy = sum(r["is_correct"] for r in nonprime_results) / len(nonprime_results) if nonprime_results else 0
return { "accuracy": accuracy, "prime_accuracy": prime_accuracy, "nonprime_accuracy": nonprime_accuracy, "num_examples": total_count, }
def run(self, dataset: Dataset, model: BaseModel, context: Dict[str, Any]) -> Dict[str, Any]: """运行评估步骤。""" # 准备数据集 prepared_dataset = self.prepare_dataset(dataset)
# 存储每个示例的结果 results = []
# 处理每个示例 for example in prepared_dataset: # 格式化提示 prompt = self.format_prompt(example)
# 获取模型的响应 model_response = model.generate(prompt)
# 评估响应 evaluation_result = self.evaluate_example(example, model_response)
# 存储结果 results.append(evaluation_result)
# 汇总结果 aggregated_results = self.aggregate_results(results)
# 将结果添加到上下文 context[self.name] = aggregated_results
return context步骤2:注册您的自定义步骤
接下来,您需要将自定义评估步骤注册到FreeEval中,以便在配置文件中引用它。将您的步骤添加到freeeval/steps/__init__.py文件中:
from freeeval.steps.simple_multiple_choice import SimpleMCPStepfrom freeeval.steps.cloze_prompt import ClozePromptStep# 导入其他内置步骤...
# 导入您的自定义步骤from freeeval.steps.custom_evaluator import PrimeNumberIdentificationStep
# 更新类型到步骤的映射TYPE_TO_STEP = { "simple_multiple_choice": SimpleMCPStep, "cloze_prompt": ClozePromptStep, # 其他内置步骤...
# 注册您的自定义步骤 "prime_number_identification": PrimeNumberIdentificationStep,}步骤3:创建数据集
您的自定义评估器需要一个数据集来工作。您可以:
- 使用现有数据集并针对您的需求进行调整
- 为您的评估器创建专门的自定义数据集
对于我们的质数识别示例,让我们在freeeval/datasets/prime_dataset.py中创建一个简单的数据集类:
from typing import Dict, Any, Listfrom freeeval.data.dataset import BaseDataset, DatasetKwargsimport random
class PrimeDatasetKwargs(DatasetKwargs): """质数数据集的参数。""" min_number: int = 1 max_number: int = 1000 num_examples: int = 100 seed: int = 42
class PrimeDataset(BaseDataset): """质数识别数据集。"""
def __init__(self, kwargs: PrimeDatasetKwargs): """初始化质数数据集。""" super().__init__(kwargs) self.min = kwargs.min_number self.max = kwargs.max_number self.num_examples = kwargs.num_examples
# 设置随机种子以确保可重现性 random.seed(kwargs.seed)
# 生成数据集 self.data = self._generate_dataset()
def _generate_dataset(self) -> List[Dict[str, Any]]: """生成质数识别示例。""" examples = [] for _ in range(self.num_examples): number = random.randint(self.min, self.max) examples.append({"number": number}) return examples
def __len__(self) -> int: """返回数据集中示例的数量。""" return len(self.data)
def __getitem__(self, idx: int) -> Dict[str, Any]: """通过索引获取示例。""" return self.data[idx]然后在freeeval/datasets/__init__.py中注册您的数据集:
from freeeval.datasets.mmlu import MMLUDatasetfrom freeeval.datasets.arc import ARCDataset# 其他内置数据集...
# 导入您的自定义数据集from freeeval.datasets.prime_dataset import PrimeDataset
# 更新类型到数据集的映射TYPE_TO_DATASET = { "mmlu": MMLUDataset, "arc_easy": lambda kwargs: ARCDataset(kwargs, "ARC-Easy"), "arc_challenge": lambda kwargs: ARCDataset(kwargs, "ARC-Challenge"), # 其他内置数据集...
# 注册您的自定义数据集 "prime": PrimeDataset,}步骤4:使用您的自定义评估器
现在您已经实现并注册了自定义评估器和数据集,可以在配置文件中使用它们:
{ "results_output_path": "./result/prime_number_test.json", "steps": [ { "step_type": "prime_number_identification", "step_name": "prime_test", "save_dataset": true, "dataset_config": { "type": "prime", "dataset_kwargs": { "min_number": 1, "max_number": 1000, "num_examples": 50, "seed": 42 } }, "inference_config": { "type": "remote_hf", "output_path": "./result", "inference_kwargs": { "model_name": "your-model-name", "base_url": ["http://your-model-endpoint:port"], "timeout": 60, "num_workers": 4 } } } ]}将此配置保存为prime_evaluation.json并运行:
python run.py -c prime_evaluation.json高级:在自定义步骤中使用模型推理
如果您的自定义评估器需要与模型进行更复杂的交互,可以在run方法中直接使用模型的方法。以下是展示更高级用法的示例:
def run(self, dataset: Dataset, model: BaseModel, context: Dict[str, Any]) -> Dict[str, Any]: """运行更复杂的评估,每个示例多次调用模型。""" prepared_dataset = self.prepare_dataset(dataset) results = []
for example in prepared_dataset: # 第一次模型调用:询问数字是否为质数 initial_prompt = self.format_prompt(example) initial_response = model.generate(initial_prompt)
# 第二次模型调用:要求解释 explanation_prompt = f"解释为什么{example['number']}{'不' if '否' in initial_response.lower() else ''}是质数。" explanation = model.generate(explanation_prompt)
# 评估两个响应 evaluation_result = self.evaluate_with_explanation( example, initial_response, explanation ) results.append(evaluation_result)
aggregated_results = self.aggregate_results(results) context[self.name] = aggregated_results return context自定义评估器的最佳实践
创建自定义评估器时,请考虑以下最佳实践:
- 确保可重现性:始终使用种子控制随机性,并记录任何非确定性行为。
- 处理边缘情况:预见并妥善处理意外的模型响应或数据集条目。
- 文档化您的步骤:包含清晰的文档字符串,解释您的评估器测量什么以及其工作原理。
- 分离逻辑:将提示格式化、响应评估和结果汇总保持在独立的方法中。
- 添加日志:包含用于调试和监控的信息性日志。
- 考虑效率:对于大型数据集,适当实现批处理或采样。
- 验证输入:检查数据集示例是否具有预期的格式和字段。
结论
在FreeEval中创建自定义评估器允许您扩展框架以满足特定的评估需求。通过遵循本指南中概述的步骤,您可以实现、注册和使用自定义评估方法,这些方法与FreeEval的评估流水线无缝集成。
对于更复杂的评估器,您可能需要实现自定义评分指标,集成外部工具,或创建更复杂的数据集预处理。FreeEval的可扩展架构使得可以将框架适应广泛的评估场景,同时保持其标准化基础设施的优势。