Evaluate 文档

使用评估器

Hugging Face's logo
加入 Hugging Face 社区

并获得增强的文档体验

开始使用

使用评估器

Evaluator 类允许对模型、数据集和指标三元组进行评估。这些模型被封装在一个管道中,负责处理所有预处理和后处理。开箱即用的 Evaluator 支持已支持任务的 transformers 管道,但也可以传递自定义管道,如 使用 evaluator 与自定义管道 部分所示。

目前支持的任务有:

要在单次调用中运行一个包含多个任务的 Evaluator,请使用 EvaluationSuite,它对一组 SubTask 进行评估。

每个任务对数据集格式和管道输出都有自己的要求,请确保为您的自定义用例检查这些要求。让我们看一些例子,了解如何使用评估器同时评估单个或多个模型、数据集和指标。

文本分类

文本分类评估器可用于评估文本模型在分类数据集(如 IMDb)上的表现。除了模型、数据和指标输入外,它还接受以下可选输入:

  • input_column="text":此参数用于指定包含管道数据的列。
  • label_column="label":此参数用于指定包含用于评估的标签的列。
  • label_mapping=None:标签映射将管道输出中的标签与评估所需的标签对齐。例如,label_column 中的标签可能是整数(0/1),而管道可能产生标签名称,如 "positive"/"negative"。通过这个字典,管道输出被映射到标签。

默认情况下,计算 "accuracy" 指标。

评估 Hub 上的模型

有多种方法可以将模型传递给评估器:您可以传递 Hub 上模型的名称,可以加载一个 transformers 模型并将其传递给评估器,或者可以传递一个已初始化的 transformers.Pipeline。此外,您还可以传递任何行为类似于该任务的 pipeline 调用的可调用函数,无论使用何种框架。

因此,以下任何一种方式都可行:

from datasets import load_dataset
from evaluate import evaluator
from transformers import AutoModelForSequenceClassification, pipeline

data = load_dataset("imdb", split="test").shuffle(seed=42).select(range(1000))
task_evaluator = evaluator("text-classification")

# 1. Pass a model name or path
eval_results = task_evaluator.compute(
    model_or_pipeline="lvwerra/distilbert-imdb",
    data=data,
    label_mapping={"NEGATIVE": 0, "POSITIVE": 1}
)

# 2. Pass an instantiated model
model = AutoModelForSequenceClassification.from_pretrained("lvwerra/distilbert-imdb")

eval_results = task_evaluator.compute(
    model_or_pipeline=model,
    data=data,
    label_mapping={"NEGATIVE": 0, "POSITIVE": 1}
)

# 3. Pass an instantiated pipeline
pipe = pipeline("text-classification", model="lvwerra/distilbert-imdb")

eval_results = task_evaluator.compute(
    model_or_pipeline=pipe,
    data=data,
    label_mapping={"NEGATIVE": 0, "POSITIVE": 1}
)
print(eval_results)

如果不指定设备,模型推理的默认设备将是机器上的第一个 GPU(如果有),否则为 CPU。如果您想使用特定设备,可以向 compute 传递 device,其中 -1 将使用 GPU,而正整数(从 0 开始)将使用相应的 CUDA 设备。

结果将如下所示:

{
    'accuracy': 0.918,
    'latency_in_seconds': 0.013,
    'samples_per_second': 78.887,
    'total_time_in_seconds': 12.676
}

请注意,评估结果不仅包括所请求的指标,还包括通过管道获得预测所需的时间信息。

时间性能可以为模型推理速度提供有用的指示,但应谨慎对待:它们包括管道中进行的所有处理。这可能包括分词、后处理等,这些过程可能因模型而异。此外,它很大程度上取决于您运行评估的硬件,您或许可以通过优化批量大小等来提高性能。

评估多个指标

通过 combine() 函数,可以将多个指标捆绑到一个行为类似于单个指标的对象中。我们可以利用这一点同时使用评估器评估多个指标。

import evaluate

eval_results = task_evaluator.compute(
    model_or_pipeline="lvwerra/distilbert-imdb",
    data=data,
    metric=evaluate.combine(["accuracy", "recall", "precision", "f1"]),
    label_mapping={"NEGATIVE": 0, "POSITIVE": 1}
)
print(eval_results)

结果将如下所示:

{
    'accuracy': 0.918,
    'f1': 0.916,
    'precision': 0.9147,
    'recall': 0.9187,
    'latency_in_seconds': 0.013,
    'samples_per_second': 78.887,
    'total_time_in_seconds': 12.676
}

接下来,让我们看看分词分类。

分词分类

使用分词分类评估器,可以评估用于 NER 或 POS 标注等任务的模型。它具有以下特定参数:

  • input_column="text":此参数用于指定包含管道数据的列。
  • label_column="label":此参数用于指定包含用于评估的标签的列。
  • label_mapping=None:标签映射将管道输出中的标签与评估所需的标签对齐。例如,label_column 中的标签可能是整数(0/1),而管道可能产生标签名称,如 "positive"/"negative"。通过这个字典,管道输出被映射到标签。
  • join_by=" ":虽然大多数数据集已经分词,但管道期望输入为字符串。因此,在传递给管道之前需要将分词连接起来。默认情况下,它们用空格连接。

让我们看看如何使用评估器对多个模型进行基准测试。

对多个模型进行基准测试

这是一个示例,展示了如何借助 evaluator 在几行代码内比较多个模型,它抽象了预处理、推理、后处理和指标计算等过程。

import pandas as pd
from datasets import load_dataset
from evaluate import evaluator
from transformers import pipeline

models = [
    "xlm-roberta-large-finetuned-conll03-english",
    "dbmdz/bert-large-cased-finetuned-conll03-english",
    "elastic/distilbert-base-uncased-finetuned-conll03-english",
    "dbmdz/electra-large-discriminator-finetuned-conll03-english",
    "gunghio/distilbert-base-multilingual-cased-finetuned-conll2003-ner",
    "philschmid/distilroberta-base-ner-conll2003",
    "Jorgeutd/albert-base-v2-finetuned-ner",
]

data = load_dataset("conll2003", split="validation").shuffle().select(range(1000))
task_evaluator = evaluator("token-classification")

results = []
for model in models:
    results.append(
        task_evaluator.compute(
            model_or_pipeline=model, data=data, metric="seqeval"
            )
        )

df = pd.DataFrame(results, index=models)
df[["overall_f1", "overall_accuracy", "total_time_in_seconds", "samples_per_second", "latency_in_seconds"]]

结果是一个如下所示的表格:

模型 overall_f1 overall_accuracy total_time_in_seconds samples_per_second latency_in_seconds
Jorgeutd/albert-base-v2-finetuned-ner 0.941 0.989 4.515 221.468 0.005
dbmdz/bert-large-cased-finetuned-conll03-english 0.962 0.881 11.648 85.850 0.012
dbmdz/electra-large-discriminator-finetuned-conll03-english 0.965 0.881 11.456 87.292 0.011
elastic/distilbert-base-uncased-finetuned-conll03-english 0.940 0.989 2.318 431.378 0.002
gunghio/distilbert-base-multilingual-cased-finetuned-conll2003-ner 0.947 0.991 2.376 420.873 0.002
philschmid/distilroberta-base-ner-conll2003 0.961 0.994 2.436 410.579 0.002
xlm-roberta-large-finetuned-conll03-english 0.969 0.882 11.996 83.359 0.012

可视化结果

您可以将上述 results 列表输入到 plot_radar() 函数中,以可视化其性能的不同方面,并根据与您的用例相关的指标选择最适合的模型。

import evaluate
from evaluate.visualization import radar_plot

>>> plot = radar_plot(data=results, model_names=models, invert_range=["latency_in_seconds"])
>>> plot.show()

对于值越小越好的指标(例如秒级延迟),请不要忘记指定 invert_range

如果您想将图表保存在本地,可以使用 plot.savefig() 函数,并带有 bbox_inches='tight' 选项,以确保图像的任何部分都不会被裁剪掉。

问答

使用问答评估器,可以评估 QA 模型,而无需担心这些模型所需的复杂预处理和后处理。它具有以下特定参数:

  • question_column="question":数据集中包含问题的列的名称。
  • context_column="context":包含上下文的列的名称。
  • id_column="id":包含问答对标识字段的列的名称。
  • label_column="answers":包含答案的列的名称。
  • squad_v2_format=None:数据集是否遵循 squad_v2 数据集格式,其中问题可能在上下文中没有答案。如果未提供此参数,将自动推断格式。

让我们看看如何评估 QA 模型并同时计算置信区间。

置信区间

每个评估器都提供了使用自助法计算置信区间的选项。只需传递 strategy="bootstrap" 并使用 n_resamples 设置重采样次数即可。

from datasets import load_dataset
from evaluate import evaluator

task_evaluator = evaluator("question-answering")

data = load_dataset("squad", split="validation[:1000]")
eval_results = task_evaluator.compute(
    model_or_pipeline="distilbert-base-uncased-distilled-squad",
    data=data,
    metric="squad",
    strategy="bootstrap",
    n_resamples=30
)

结果包括置信区间和误差估计,如下所示:

{
    'exact_match':
    {
        'confidence_interval': (79.67, 84.54),
        'score': 82.30,
        'standard_error': 1.28
    },
    'f1':
    {
        'confidence_interval': (85.30, 88.88),
        'score': 87.23,
        'standard_error': 0.97
    },
    'latency_in_seconds': 0.0085,
    'samples_per_second': 117.31,
    'total_time_in_seconds': 8.52
 }

图像分类

通过图像分类评估器,我们可以评估任何图像分类器。它使用与文本分类器相同的关键字参数:

  • input_column="image":包含 PIL ImageFile 格式图像的列的名称。
  • label_column="label":包含标签的列的名称。
  • label_mapping=None:我们希望将管道中模型定义的类标签映射为与 label_column 中定义的值一致的值。

让我们看看如何在大型数据集上评估图像分类模型。

处理大型数据集

评估器可以在大型数据集上使用!下面是一个示例,展示了如何在 ImageNet-1k 数据集上进行图像分类。请注意,此示例需要下载约 150 GB 的数据。

data = load_dataset("imagenet-1k", split="validation", token=True)

pipe = pipeline(
    task="image-classification",
    model="facebook/deit-small-distilled-patch16-224"
)

task_evaluator = evaluator("image-classification")
eval_results = task_evaluator.compute(
    model_or_pipeline=pipe,
    data=data,
    metric="accuracy",
    label_mapping=pipe.model.config.label2id
)

由于我们使用 datasets 来存储数据,我们利用了一种称为内存映射的技术。这意味着数据集永远不会完全加载到内存中,从而节省了大量 RAM。运行上述代码仅使用约 1.5 GB 的 RAM,而验证集的大小超过 30 GB。

< > 在 GitHub 上更新