跳转到内容

创建自定义评估器

创建自定义评估器

FreeEval的模块化架构使创建自定义评估方法变得简单。本指南将指导您实现自己的评估步骤并将其集成到框架中。

概述

在FreeEval中创建自定义评估器涉及:

  1. 实现自定义评估步骤类
  2. 向框架注册您的步骤
  3. 在评估配置中使用您的自定义步骤

这种可扩展性允许您添加专门的评估指标,整合特定领域知识,或实现超出FreeEval内置功能的新型评估技术。

步骤1:实现自定义步骤

让我们创建一个简单的自定义评估器,用于评估模型识别质数的能力。我们将文件命名为custom_evaluator.py并放在freeeval/steps目录中。

from typing import Dict, Any, List, Optional
from freeeval.steps.base_step import BaseEvaluationStep
from freeeval.data.dataset import Dataset
from freeeval.models.base_model import BaseModel
import 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 SimpleMCPStep
from 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:创建数据集

您的自定义评估器需要一个数据集来工作。您可以:

  1. 使用现有数据集并针对您的需求进行调整
  2. 为您的评估器创建专门的自定义数据集

对于我们的质数识别示例,让我们在freeeval/datasets/prime_dataset.py中创建一个简单的数据集类:

from typing import Dict, Any, List
from freeeval.data.dataset import BaseDataset, DatasetKwargs
import 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 MMLUDataset
from 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并运行:

Terminal window
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

自定义评估器的最佳实践

创建自定义评估器时,请考虑以下最佳实践:

  1. 确保可重现性:始终使用种子控制随机性,并记录任何非确定性行为。
  2. 处理边缘情况:预见并妥善处理意外的模型响应或数据集条目。
  3. 文档化您的步骤:包含清晰的文档字符串,解释您的评估器测量什么以及其工作原理。
  4. 分离逻辑:将提示格式化、响应评估和结果汇总保持在独立的方法中。
  5. 添加日志:包含用于调试和监控的信息性日志。
  6. 考虑效率:对于大型数据集,适当实现批处理或采样。
  7. 验证输入:检查数据集示例是否具有预期的格式和字段。

结论

在FreeEval中创建自定义评估器允许您扩展框架以满足特定的评估需求。通过遵循本指南中概述的步骤,您可以实现、注册和使用自定义评估方法,这些方法与FreeEval的评估流水线无缝集成。

对于更复杂的评估器,您可能需要实现自定义评分指标,集成外部工具,或创建更复杂的数据集预处理。FreeEval的可扩展架构使得可以将框架适应广泛的评估场景,同时保持其标准化基础设施的优势。