评估文档

使用 `evaluator`

Hugging Face's logo
加入 Hugging Face 社区

并获得增强型文档体验

开始使用

使用 `evaluator`

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

当前支持的任务包括:

要在一个调用中使用多个任务运行 Evaluator,请使用 EvaluationSuite,它在一组 SubTask 上运行评估。

每个任务都有自己的一套关于数据集格式和管道输出的要求,请务必针对您的自定义用例检查它们。让我们看看其中的一些,并了解如何使用评估器同时评估一个或多个模型、数据集和指标。

文本分类

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

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

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

在集线器上评估模型

有多种方法可以将模型传递给评估器:您可以传递集线器上模型的名称,可以加载 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。如果要使用特定设备,可以将 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
}

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

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

评估多个指标

使用 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(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"]]

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

模型 整体F1 整体准确率 总时间(秒) 每秒样本数 延迟时间(秒)
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", 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。