评估文档

使用 `evaluator`

Hugging Face's logo
加入 Hugging Face 社区

并获得增强的文档体验

开始使用

使用 evaluator

Evaluator 类允许评估模型、数据集和指标的三元组。模型被封装在 pipeline 中,负责处理所有预处理和后处理并开箱即用。Evaluator 支持受支持任务的 transformers pipelines,但可以传递自定义 pipelines,如 evaluator 与自定义 pipelines 一起使用 部分所示。

当前支持的任务有

要在单个调用中运行具有多个任务的 Evaluator,请使用 EvaluationSuite,它在 SubTasks 的集合上运行评估。

每个任务对数据集格式和 pipeline 输出都有自己的一组要求,请务必查看它们以了解您的自定义用例。让我们看看其中的一些,看看如何使用 evaluator 同时评估单个或多个模型、数据集和指标。

文本分类

文本分类 evaluator 可用于评估文本模型在分类数据集上的性能,例如 IMDb。除了模型、数据和指标输入外,它还接受以下可选输入

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

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

在 Hub 上评估模型

有几种方法可以将模型传递给 evaluator:您可以传递 Hub 上模型的名称,您可以加载 transformers 模型并将其传递给 evaluator,或者您可以传递初始化的 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。如果您想使用特定设备,可以将 device 传递给 compute,其中 -1 将使用 GPU,正整数(从 0 开始)将使用关联的 CUDA 设备。

结果将如下所示

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

请注意,评估结果包括请求的指标以及通过 pipeline 获取预测所花费的时间信息。

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

评估多个指标

通过 combine() 函数,可以将多个指标捆绑到一个对象中,该对象的行为类似于单个指标。我们可以使用它通过 evaluator 一次评估多个指标

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
}

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

Token 分类

使用 token 分类 evaluator 可以评估 NER 或 POS 标记等任务的模型。它具有以下特定参数

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

让我们看看如何使用 evaluator 来基准测试多个模型。

基准测试多个模型

这是一个示例,借助 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(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',以确保图像的任何部分都不会被裁剪掉。

问答

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

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

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

置信区间

每个 evaluator 都带有使用 bootstrapping 计算置信区间的选项。只需传递 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
 }

图像分类

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

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

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

处理大型数据集

evaluator 可以用于大型数据集!下面,一个示例展示了如何在 ImageNet-1k 上用于图像分类。请注意,此示例将需要下载约 150 GB。

data = load_dataset("imagenet-1k", split="validation", use_auth_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 大。