在 Hugging Face Hub 上进行超级搜索
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 后端托管服务交互的类。通过它,我们可以与模型、数据集等进行交互。同时,我们还会导入几个辅助类:ModelFilter
和 ModelSearchArguments
。
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
(数据集):GLUElibrary
(库):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')
更进一步
我们已经了解了如何使用 ModelSearchArguments
和 DatasetSearchArguments
来消除搜索 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_c
的 AttributeDictionary
。
>>> 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
可能会派上用场的地方。