在 Hugging Face Hub 上进行超级搜索

发布于 2022 年 1 月 25 日
在 GitHub 上更新
Open In Colab

huggingface_hub 库是一个轻量级接口,它提供了一种以编程方式探索 Hugging Face 托管端点的方法,这些端点包括:模型、数据集和 Spaces。

到目前为止,通过这个接口在 Hub 上进行搜索是一件棘手的事情,用户需要“凭感觉”去了解和适应它的许多方面。

在本文中,我们将介绍 huggingface_hub 中新增的一些激动人心的新功能,这些功能有助于降低使用门槛,并为用户提供一个友好的 API,让他们无需离开 Jupyter 或 Python 界面即可搜索想要使用的模型和数据集。

在我们开始之前,如果你的系统上没有最新版本的 huggingface_hub 库,请运行以下单元格

!pip install huggingface_hub -U

提出问题:

首先,让我们想象一下你所处的场景。你想在 Hugging Face Hub 上找到所有用于文本分类、在 GLUE 数据集上训练过、并且与 PyTorch 兼容的模型。

你或许会直接打开 https://huggingface.co/models 并使用那里的筛选小部件。但这需要离开你的 IDE 并浏览这些结果,所有这些都需要点击几次按钮才能获得所需信息。

如果有一种无需离开 IDE 的解决方案呢?通过编程接口,也很容易将其集成到探索 Hub 的工作流程中。

这就是 huggingface_hub 发挥作用的地方。

对于熟悉该库的用户来说,你可能已经知道我们可以搜索这类模型。然而,要正确构建查询却是一个痛苦的反复试验过程。

我们能简化这个过程吗?让我们一探究竟!

找到我们所需

首先,我们导入 HfApi,这是一个帮助我们与 Hugging Face 后端托管服务交互的类。通过它,我们可以与模型、数据集等进行交互。同时,我们还会导入几个辅助类:ModelFilterModelSearchArguments

from huggingface_hub import HfApi, ModelFilter, ModelSearchArguments

api = HfApi()

这两个类可以帮助我们为上述问题构建解决方案。ModelSearchArguments 类类似于一个命名空间,包含了我们可以搜索的每一个有效参数!

让我们来看一看。

>>> model_args = ModelSearchArguments()

>>> model_args
Available Attributes or Keys:
 * author
 * dataset
 * language
 * library
 * license
 * model_name
 * pipeline_tag

我们可以看到有多种可用的属性(稍后会详细介绍这背后的魔法)。如果我们要对我们想要的东西进行分类,大概可以分为:

  • pipeline_tag (或任务):文本分类
  • dataset (数据集):GLUE
  • library (库):PyTorch

鉴于这样的分类,我们很自然地会在我们声明的 model_args 中找到它们。

>>> model_args.pipeline_tag.TextClassification
'text-classification'
>>> model_args.dataset.glue
'dataset:glue'
>>> model_args.library.PyTorch
'pytorch'

不过,我们开始注意到这里进行的一些便利性封装。ModelSearchArguments(以及与之配套的 DatasetSearchArguments)提供了一个人类可读的接口,其中包含了 API 期望的格式化输出,例如 GLUE 数据集应该用 dataset:glue 进行搜索。

这一点至关重要,因为如果没有这张关于某些参数应该如何书写的“备忘单”,你在尝试使用 API 搜索模型时很容易会陷入沮丧!

现在我们知道了正确的参数是什么,就可以轻松地搜索 API了。

>>> models = api.list_models(filter = (
>>>     model_args.pipeline_tag.TextClassification, 
>>>     model_args.dataset.glue, 
>>>     model_args.library.PyTorch)
>>> )
>>> print(len(models))
    140

我们发现有 **140** 个模型符合我们的标准!(在撰写本文时)。如果我们仔细看其中一个,会发现它确实看起来是正确的。

>>> models[0]
    ModelInfo: {
        modelId: Jiva/xlm-roberta-large-it-mnli
        sha: c6e64469ec4aa17fedbd1b2522256f90a90b5b86
        lastModified: 2021-12-10T14:56:38.000Z
        tags: ['pytorch', 'xlm-roberta', 'text-classification', 'it', 'dataset:multi_nli', 'dataset:glue', 'arxiv:1911.02116', 'transformers', 'tensorflow', 'license:mit', 'zero-shot-classification']
        pipeline_tag: zero-shot-classification
        siblings: [ModelFile(rfilename='.gitattributes'), ModelFile(rfilename='README.md'), ModelFile(rfilename='config.json'), ModelFile(rfilename='pytorch_model.bin'), ModelFile(rfilename='sentencepiece.bpe.model'), ModelFile(rfilename='special_tokens_map.json'), ModelFile(rfilename='tokenizer.json'), ModelFile(rfilename='tokenizer_config.json')]
        config: None
        private: False
        downloads: 680
        library_name: transformers
        likes: 1
    }

这更具可读性,而且无需猜测“我这个参数写对了吗?”

你知道吗?你还可以通过模型 ID 以编程方式获取该模型的信息。方法如下:

api.model_info('Jiva/xlm-roberta-large-it-mnli')

更进一步

我们已经了解了如何使用 ModelSearchArgumentsDatasetSearchArguments 来消除搜索 Hub 时的猜测,但如果我们有一个非常复杂、混乱的查询呢?

例如:我想搜索所有同时为 text-classification(文本分类)和 zero-shot(零样本)分类任务训练的模型,这些模型在 MultiNLI 和 GLUE 数据集上训练过,并且同时兼容 PyTorch 和 TensorFlow(这是一个更精确的查询,以获取上述模型)。

为了构建这个查询,我们将使用 ModelFilter 类。它专门设计用来处理这类情况,因此我们无需为此伤脑筋。

>>> filt = ModelFilter(
>>>     task = ["text-classification", "zero-shot-classification"],
>>>     trained_dataset = [model_args.dataset.multi_nli, model_args.dataset.glue],
>>>     library = ['pytorch', 'tensorflow']
>>> )
>>> api.list_models(filt)
    [ModelInfo: {
         modelId: Jiva/xlm-roberta-large-it-mnli
         sha: c6e64469ec4aa17fedbd1b2522256f90a90b5b86
         lastModified: 2021-12-10T14:56:38.000Z
         tags: ['pytorch', 'xlm-roberta', 'text-classification', 'it', 'dataset:multi_nli', 'dataset:glue', 'arxiv:1911.02116', 'transformers', 'tensorflow', 'license:mit', 'zero-shot-classification']
         pipeline_tag: zero-shot-classification
         siblings: [ModelFile(rfilename='.gitattributes'), ModelFile(rfilename='README.md'), ModelFile(rfilename='config.json'), ModelFile(rfilename='pytorch_model.bin'), ModelFile(rfilename='sentencepiece.bpe.model'), ModelFile(rfilename='special_tokens_map.json'), ModelFile(rfilename='tokenizer.json'), ModelFile(rfilename='tokenizer_config.json')]
         config: None
         private: False
         downloads: 680
         library_name: transformers
         likes: 1
     }]

我们很快就能看到,这是一种更加协调的 API 搜索方法,不会给你增加任何麻烦!

魔法何在?

我们来简要谈谈其背后运作的魔法,它为我们提供了这种类似枚举-字典的数据类型——AttributeDictionary

它深受 fastcore 库中 AttrDict 类的启发,其核心思想是我们将一个普通字典进行“超级充电”,通过为字典中的每个键提供 Tab 补全功能,来支持_探索式编程_。

正如我们之前所见,当我们拥有可以探索的嵌套字典时,例如 model_args.dataset.glue,这个功能会变得更加强大!

对于熟悉 JavaScript 的人来说,我们模仿了 object 类的运作方式。

这个简单的实用工具类在探索嵌套数据类型并试图理解其中内容时,例如 API 请求的返回结果,可以提供一种更加以用户为中心的体验!

如前所述,我们在几个关键方面对 AttrDict 进行了扩展:

  • 你可以使用 del model_args[key] _或_ del model_args.key 来删除键。
  • 我们之前看到的那个简洁的 __repr__ 表示。

然而,需要注意一个非常重要的概念:如果一个键包含数字或特殊字符,它**必须**像字典一样通过索引访问,而**不能**像对象一样访问。

>>> from huggingface_hub.utils.endpoint_helpers import AttributeDictionary

一个简短的例子是,如果我们有一个键为 3_cAttributeDictionary

>>> d = {"a":2, "b":3, "3_c":4}
>>> ad = AttributeDictionary(d)
>>> # As an attribute
>>> ad.3_c
 File "<ipython-input-6-c0fe109cf75d>", line 2
    ad.3_c
        ^
SyntaxError: invalid token
>>> # As a dictionary key
>>> ad["3_c"]
4

总结

希望现在你对这个新的搜索 API 如何直接影响你的工作流程和 Hub 探索有了一个初步的了解!同时,也许你也想到了在你的代码中,AttributeDictionary 可能会派上用场的地方。

接下来,请务必查看关于高效搜索 Hub的官方文档,也别忘了给我们一个 star

社区

注册登录以发表评论