评估文档

快速导览

Hugging Face's logo
加入 Hugging Face 社区

并获得增强的文档体验

开始使用

快速导览

🤗 Evaluate 提供了对各种评估工具的访问。它涵盖了文本、计算机视觉、音频等多种模态,以及评估模型或数据集的工具。这些工具分为三个类别。

评估类型

典型的机器学习 pipeline 有不同的方面可以进行评估,对于每个方面,🤗 Evaluate 都提供了工具

  • 指标:指标用于评估模型的性能,通常涉及模型的预测以及一些 ground truth 标签。您可以在 evaluate-metric 中找到所有集成的指标。
  • 比较:比较用于比较两个模型。例如,可以通过比较它们对 ground truth 标签的预测并计算它们的一致性来完成此操作。您可以在 evaluate-comparison 中找到所有集成的比较。
  • 测量:数据集与在其上训练的模型同等重要。通过测量,可以调查数据集的属性。您可以在 evaluate-measurement 中找到所有集成的测量。

这些评估模块中的每一个都作为 Space 驻留在 Hugging Face Hub 上。它们都带有交互式小部件和文档卡片,记录其使用和限制。例如 accuracy

每个指标、比较和测量都是一个单独的 Python 模块,但对于使用它们中的任何一个,都有一个单一的入口点:evaluate.load()

加载

任何指标、比较或测量都使用 evaluate.load 函数加载

>>> import evaluate
>>> accuracy = evaluate.load("accuracy")

如果您想确保加载正确类型的评估(尤其是在存在名称冲突的情况下),您可以显式传递类型

>>> word_length = evaluate.load("word_length", module_type="measurement")

社区模块

除了在 🤗 Evaluate 中实现的模块外,您还可以通过指定指标实现的存储库 ID 来加载任何社区模块

>>> element_count = evaluate.load("lvwerra/element_count", module_type="measurement")

有关上传自定义指标的信息,请参阅创建和共享指南

列出可用模块

使用 list_evaluation_modules() 您可以检查 hub 上有哪些模块可用。您还可以过滤特定模块,并根据需要跳过社区指标。您还可以查看其他信息,例如点赞数

>>> evaluate.list_evaluation_modules(
...   module_type="comparison",
...   include_community=False,
...   with_details=True)

[{'name': 'mcnemar', 'type': 'comparison', 'community': False, 'likes': 1},
 {'name': 'exact_match', 'type': 'comparison', 'community': False, 'likes': 0}]

模块属性

所有评估模块都带有一系列有用的属性,这些属性有助于使用存储在 EvaluationModuleInfo 对象中的模块。

属性 描述
description 评估模块的简短描述。
citation 可用时用于引用的 BibTex 字符串。
features 定义输入格式的 Features 对象。
inputs_description 这等效于模块的文档字符串。
homepage 模块的主页。
license 模块的许可证。
codebase_urls 指向模块背后代码的链接。
reference_urls 其他参考 URL。

让我们看几个例子。首先,让我们看看 accuracy 指标的 description 属性

>>> accuracy = evaluate.load("accuracy")
>>> accuracy.description
Accuracy is the proportion of correct predictions among the total number of cases processed. It can be computed with:
Accuracy = (TP + TN) / (TP + TN + FP + FN)
 Where:
TP: True positive
TN: True negative
FP: False positive
FN: False negative

您可以看到它描述了该指标在理论上的工作原理。如果您在工作中使用此指标,尤其是在学术出版物中,您需要正确引用它。为此,您可以查看 citation 属性

>>> accuracy.citation
@article{scikit-learn,
  title={Scikit-learn: Machine Learning in {P}ython},
  author={Pedregosa, F. and Varoquaux, G. and Gramfort, A. and Michel, V.
         and Thirion, B. and Grisel, O. and Blondel, M. and Prettenhofer, P.
         and Weiss, R. and Dubourg, V. and Vanderplas, J. and Passos, A. and
         Cournapeau, D. and Brucher, M. and Perrot, M. and Duchesnay, E.},
  journal={Journal of Machine Learning Research},
  volume={12},
  pages={2825--2830},
  year={2011}
}

在我们可以将指标或其他评估模块应用于用例之前,我们需要知道指标的输入格式是什么

>>> accuracy.features
{
    'predictions': Value(dtype='int32', id=None),
    'references': Value(dtype='int32', id=None)
}

请注意,features 始终描述单个输入元素的类型。通常,我们将添加元素列表,因此您可以始终将 features 中的类型视为列表。Evaluate 接受各种输入格式(Python 列表、NumPy 数组、PyTorch 张量等),并将其转换为适合存储和计算的格式。

计算

现在我们知道了评估模块的工作原理以及应该放入什么内容,我们想要实际使用它!当涉及到计算实际分数时,有两种主要方法可以做到

  1. 一体化
  2. 增量式

在增量方法中,必要的输入通过 EvaluationModule.add()EvaluationModule.add_batch() 添加到模块中,并且分数在最后使用 EvaluationModule.compute() 计算。或者,可以一次性将所有输入传递给 compute()。让我们看一下这两种方法。

如何计算

计算评估模块分数的zui简单方法是直接使用必要的输入调用 compute()。只需将 features 中看到的输入传递给 compute() 方法即可。

>>> accuracy.compute(references=[0,1,0,1], predictions=[1,0,0,1])
{'accuracy': 0.5}

评估模块以字典形式返回结果。但是,在某些情况下,您会迭代或以分布式方式构建预测,在这种情况下,add()add_batch() 非常有用。

计算单个指标或一批指标

在许多评估 pipeline 中,您会迭代地构建预测,例如在 for 循环中。在这种情况下,您可以将预测存储在列表中,并在zui后将它们传递给 compute()。使用 add()add_batch(),您可以绕过单独存储预测的步骤。如果您一次只创建单个预测,则可以使用 add()

>>> for ref, pred in zip([0,1,0,1], [1,0,0,1]):
>>>     accuracy.add(references=ref, predictions=pred)
>>> accuracy.compute()
{'accuracy': 0.5}

收集所有预测后,您可以调用 compute() 以基于所有存储的值计算分数。当批量获取预测和参考时,可以使用 add_batch(),它会添加元素列表以供以后处理。其余工作方式与 add() 相同

>>> for refs, preds in zip([[0,1],[0,1]], [[1,0],[0,1]]):
>>>     accuracy.add_batch(references=refs, predictions=preds)
>>> accuracy.compute()
{'accuracy': 0.5}

当您需要批量从模型中获取预测时,这尤其有用

>>> for model_inputs, gold_standards in evaluation_dataset:
>>>     predictions = model(model_inputs)
>>>     metric.add_batch(references=gold_standards, predictions=predictions)
>>> metric.compute()

分布式评估

在分布式环境中计算指标可能很棘手。指标评估在单独的 Python 进程或节点上执行,针对数据集的不同子集。通常,当指标分数是可加的 (f(AuB) = f(A) + f(B)) 时,您可以使用分布式 reduce 操作来收集数据集每个子集的分数。但是当指标是非加性的 (f(AuB) ≠ f(A) + f(B)) 时,情况就没那么简单了。例如,您不能将每个数据子集的 F1 分数之和作为您的 最终指标

克服此问题的一种常见方法是回退到单进程评估。指标在单个 GPU 上评估,这变得效率低下。

🤗 Evaluate 通过仅在zui初节点上计算最终指标来解决此问题。预测和参考分别为每个节点计算并提供给指标。这些临时存储在 Apache Arrow 表中,避免了 GPU 或 CPU 内存的混乱。当您准备好 compute() 最终指标时,zui初节点能够访问存储在所有其他节点上的预测和参考。一旦它收集了所有预测和参考,compute() 将执行最终指标评估。

此解决方案允许 🤗 Evaluate 执行分布式预测,这对于分布式设置中的评估速度非常重要。同时,您也可以使用复杂的非加性指标,而不会浪费宝贵的 GPU 或 CPU 内存。

组合多个评估

通常,人们不仅要评估单个指标,还要评估一系列不同的指标,这些指标捕获模型的不同方面。例如,对于分类,通常最好在准确率的基础上计算 F1 分数、召回率和精确率,以便更好地了解模型性能。当然,您可以加载一堆指标并按顺序调用它们。但是,更方便的方法是使用 combine() 函数将它们捆绑在一起

>>> clf_metrics = evaluate.combine(["accuracy", "f1", "precision", "recall"])

combine 函数接受指标名称列表以及实例化的模块。然后 compute 调用计算每个指标

>>> clf_metrics.compute(predictions=[0, 1, 0], references=[0, 1, 1])

{
  'accuracy': 0.667,
  'f1': 0.667,
  'precision': 1.0,
  'recall': 0.5
}

保存并推送到 Hub

保存和共享评估结果是一个重要的步骤。我们提供了 evaluate.save() 函数,可以轻松保存指标结果。您可以传递特定的文件名或目录。在后一种情况下,结果将保存在具有自动创建的文件名的文件中。除了目录或文件名外,该函数还接受任何键值对作为输入,并将它们存储在 JSON 文件中。

>>> result = accuracy.compute(references=[0,1,0,1], predictions=[1,0,0,1])

>>> hyperparams = {"model": "bert-base-uncased"}
>>> evaluate.save("./results/"experiment="run 42", **result, **hyperparams)
PosixPath('results/result-2022_05_30-22_09_11.json')

JSON 文件的内容如下所示

{
    "experiment": "run 42",
    "accuracy": 0.5,
    "model": "bert-base-uncased",
    "_timestamp": "2022-05-30T22:09:11.959469",
    "_git_commit_hash": "123456789abcdefghijkl",
    "_evaluate_version": "0.1.0",
    "_python_version": "3.9.12 (main, Mar 26 2022, 15:51:15) \n[Clang 13.1.6 (clang-1316.0.21.2)]",
    "_interpreter_path": "/Users/leandro/git/evaluate/env/bin/python"
}

除了指定的字段外,它还包含用于重现结果的有用系统信息。

除了在本地存储结果外,您还应在 Hub 上模型的存储库中报告它们。使用 evaluate.push_to_hub() 函数,您可以轻松地将评估结果报告给模型的存储库

evaluate.push_to_hub(
  model_id="huggingface/gpt2-wikitext2",  # model repository on hub
  metric_value=0.5,                       # metric value
  metric_type="bleu",                     # metric name, e.g. accuracy.name
  metric_name="BLEU",                     # pretty name which is displayed
  dataset_type="wikitext",                # dataset name on the hub
  dataset_name="WikiText",                # pretty name
  dataset_split="test",                   # dataset split used
  task_type="text-generation",            # task id, see https://github.com/huggingface/datasets/blob/master/src/datasets/utils/resources/tasks.json
  task_name="Text Generation"             # pretty name for task
)

评估器

evaluate.evaluator() 提供了自动化评估,并且只需要模型、数据集、指标,这与 EvaluationModule 中的指标形成对比,后者需要模型的预测。因此,使用给定的指标评估数据集上的模型更容易,因为推理在内部处理。为了实现这一点,它使用了来自 transformerspipeline 抽象。但是,只要您的框架遵循 pipeline 接口,您就可以使用自己的框架。

为了使用 evaluator 进行评估,让我们加载一个 transformers pipeline(但您可以为任何框架传递您自己的自定义推理类,只要它遵循 pipeline 调用 API),其中包含在 IMDb 上训练的模型、IMDb 测试集和准确率指标。

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

pipe = pipeline("text-classification", model="lvwerra/distilbert-imdb", device=0)
data = load_dataset("imdb", split="test").shuffle().select(range(1000))
metric = evaluate.load("accuracy")

然后,您可以为文本分类创建一个评估器,并将这三个对象传递给 compute() 方法。通过标签映射,evaluate 提供了一种将 pipeline 输出与数据集中的标签列对齐的方法

>>> task_evaluator = evaluator("text-classification")

>>> results = task_evaluator.compute(model_or_pipeline=pipe, data=data, metric=metric,
...                        label_mapping={"NEGATIVE": 0, "POSITIVE": 1},)

>>> print(results)
{'accuracy': 0.934}

仅计算指标的值通常不足以了解模型是否比另一个模型表现明显更好。通过自举法evaluate 计算置信区间和标准误差,这有助于估计分数的稳定性

>>> results = eval.compute(model_or_pipeline=pipe, data=data, metric=metric,
...                        label_mapping={"NEGATIVE": 0, "POSITIVE": 1},
...                        strategy="bootstrap", n_resamples=200)

>>> print(results)
{'accuracy':
    {
      'confidence_interval': (0.906, 0.9406749892841922),
      'standard_error': 0.00865213251082787,
      'score': 0.923
    }
}

评估器期望数据输入具有 "text""label" 列。如果您的数据集不同,您可以使用关键字 input_column="text"label_column="label" 提供列。目前仅支持 "text-classification",未来将添加更多任务。

可视化

在比较多个模型时,有时很难仅通过查看它们的分数来发现它们性能的差异。而且通常没有zui佳模型,而是在例如延迟和准确率之间进行权衡,因为较大的模型可能具有更好的性能,但也更慢。我们正在逐步添加不同的可视化方法(例如绘图),以使为用例选择zui佳模型变得更容易。

例如,如果您有来自多个模型的结果列表(作为字典),则可以将它们馈送到 radar_plot() 函数中

import evaluate
from evaluate.visualization import radar_plot

>>> data = [
   {"accuracy": 0.99, "precision": 0.8, "f1": 0.95, "latency_in_seconds": 33.6},
   {"accuracy": 0.98, "precision": 0.87, "f1": 0.91, "latency_in_seconds": 11.2},
   {"accuracy": 0.98, "precision": 0.78, "f1": 0.88, "latency_in_seconds": 87.6}, 
   {"accuracy": 0.88, "precision": 0.78, "f1": 0.81, "latency_in_seconds": 101.6}
   ]
>>> model_names = ["Model 1", "Model 2", "Model 3", "Model 4"]
>>> plot = radar_plot(data=data, model_names=model_names)
>>> plot.show()

这使您可以直观地比较 4 个模型,并根据一个或多个指标为您选择zui优的模型

在一组任务上运行评估

在各种不同的任务上评估模型以了解其下游性能可能很有用。EvaluationSuite 允许在一系列任务上评估模型。任务可以构建为 (evaluator, 数据集, 指标) 元组,并传递给存储在 Hugging Face Hub 上作为 Space 的 EvaluationSuite,或者在本地作为 Python 脚本。有关当前支持的任务列表,请参阅 evaluator 文档

EvaluationSuite 脚本可以定义如下,并支持用于数据预处理的 Python 代码。

import evaluate
from evaluate.evaluation_suite import SubTask

class Suite(evaluate.EvaluationSuite):

    def __init__(self, name):
        super().__init__(name)

        self.suite = [
            SubTask(
                task_type="text-classification",
                data="imdb",
                split="test[:1]",
                args_for_task={
                    "metric": "accuracy",
                    "input_column": "text",
                    "label_column": "label",
                    "label_mapping": {
                        "LABEL_0": 0.0,
                        "LABEL_1": 1.0
                    }
                }
            ),
            SubTask(
                task_type="text-classification",
                data="sst2",
                split="test[:1]",
                args_for_task={
                    "metric": "accuracy",
                    "input_column": "sentence",
                    "label_column": "label",
                    "label_mapping": {
                        "LABEL_0": 0.0,
                        "LABEL_1": 1.0
                    }
                }
            )
        ]

可以通过加载 EvaluationSuite 并使用模型或 pipeline 调用 run() 方法来运行评估。

>>> from evaluate import EvaluationSuite
>>> suite = EvaluationSuite.load('mathemakitten/sentiment-evaluation-suite')
>>> results = suite.run("huggingface/prunebert-base-uncased-6-finepruned-w-distil-mnli")
准确率 总耗时(秒) 每秒样本数 延迟(秒) 任务名称
0.3 4.62804 2.16074 0.462804 imdb
0 0.686388 14.569 0.0686388 sst2