使用 `evaluator`
Evaluator
类允许评估模型、数据集和指标的三元组。模型封装在一个管道中,负责处理所有预处理和后处理,并且开箱即用的 Evaluator
支持受支持任务的转换器管道,但也可以传递自定义管道,如 使用 `evaluator` 与自定义管道 部分所示。
当前支持的任务包括:
"text-classification"
:将使用 TextClassificationEvaluator。"token-classification"
:将使用 TokenClassificationEvaluator。"question-answering"
:将使用 QuestionAnsweringEvaluator。"image-classification"
:将使用 ImageClassificationEvaluator。"text-generation"
:将使用 TextGenerationEvaluator。"text2text-generation"
:将使用 Text2TextGenerationEvaluator。"summarization"
:将使用 SummarizationEvaluator。"translation"
:将使用 TranslationEvaluator。"automatic-speech-recognition"
:将使用 AutomaticSpeechRecognitionEvaluator。
要在一个调用中使用多个任务运行 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。