Hub documentation

Webhook 指南:为模型和数据集设置自动元数据质量审查

Hugging Face's logo
Join the Hugging Face community

and get access to the augmented documentation experience

to get started

Webhook 指南:为模型和数据集设置自动元数据质量审查

本指南将指导您创建一个系统,该系统会响应 Hub 上用户或组织的模型或数据集的变更,并为发生变化的仓库创建“元数据审查”。

我们要构建什么,以及为什么要构建它?

在深入探讨此特定工作流的技术细节之前,我们将快速概述我们要创建的内容及其原因。

模型卡片和数据集卡片是记录机器学习模型和数据集的重要工具。Hugging Face Hub 使用包含 YAML 头部块的 README.md 文件来生成模型和数据集卡片。此 YAML 部分定义了与模型或数据集相关的元数据。例如:

---
language: 
  - "List of ISO 639-1 code for your language"
  - lang1
  - lang2
tags:
- tag1
- tag2
license: "any valid license identifier"
datasets:
- dataset1
---

此元数据包含潜在用户需要了解的有关您的模型或数据集的关键信息。例如,许可证定义了使用模型或数据集的条款。Hub 用户还可以使用 YAML 元数据中定义的字段作为筛选条件,以查找符合特定标准的模型或数据集。

由于此块中定义的元数据对于模型和数据集的潜在用户至关重要,因此完善此部分非常重要。在团队或组织环境中,向 Hub 推送模型和数据集的用户对该 YAML 元数据块重要性的熟悉程度可能各不相同。虽然团队中的某个人可以负责审查此元数据,但我们也可以采用一些自动化手段来解决这个问题。其结果将是一份元数据审查报告,当 Hub 上的仓库发生变更时,该报告会自动发布或更新。就元数据质量而言,此系统的工作方式类似于 CI/CD。

Metadata review

您还可以在此处找到示例评审:这里。

使用 Hub 客户端库创建模型审查卡片

huggingface_hub 是一个 Python 库,可用于与 Hub 进行交互。我们可以使用 DatasetCard.load 或 ModelCard.load 方法,通过该库从 Hub 下载模型和数据集卡片。具体来说,我们将使用这些方法加载一个 Python 字典,其中包含在模型或数据集卡片的 YAML 中定义的元数据。我们将创建一个小型 Python 函数来封装这些方法,并执行一些异常处理。

from huggingface_hub import DatasetCard, ModelCard
from huggingface_hub.utils import EntryNotFoundError 

def load_repo_card_metadata(repo_type, repo_name):
    if repo_type == "dataset":
        try:
            return DatasetCard.load(repo_name).data.to_dict()
        except EntryNotFoundError:
            return {}
    if repo_type == "model":
        try:
            return ModelCard.load(repo_name).data.to_dict()
        except EntryNotFoundError:
            return {}

此函数将返回一个 Python 字典,其中包含与该仓库关联的元数据(如果没有元数据,则返回空字典)。

{'license': 'afl-3.0'}

创建我们的元数据审查报告

一旦我们获得了一个包含与某个仓库关联的元数据的 Python 字典,我们就会为元数据审查创建一份“成绩单”。在此特定场景中,我们将通过定义一些希望其具有值的元数据字段来审查元数据。例如,我们可能希望确保 license 字段始终已填写。为了对元数据进行评分,我们将统计期望字段中实际存在的元数据字段数量,并根据我们期望看到值的必需元数据字段的覆盖率返回一个百分比分数。

由于我们有一个包含元数据的 Python 字典,可以遍历该字典来检查所需的键是否存在。如果缺少某个所需的元数据字段(即字典中的某个键),我们将将其值赋为 None。

def create_metadata_key_dict(card_data, repo_type: str):
    shared_keys = ["tags", "license"]
    if repo_type == "model":
        model_keys = ["library_name", "datasets", "metrics", "co2", "pipeline_tag"]
        shared_keys.extend(model_keys)
        keys = shared_keys
        return {key: card_data.get(key) for key in keys}
    if repo_type == "dataset":
        # [...]

此函数将返回一个字典,其中包含表示我们模型或数据集所需元数据字段的键。字典的值将包含为该字段输入的元数据,或者如果YAML中缺少该元数据字段,则为None。

{'tags': None,
 'license': 'afl-3.0',
 'library_name': None,
 'datasets': None,
 'metrics': None,
 'co2': None,
 'pipeline_tag': None}

获得该字典后,我们即可创建元数据报告。为简洁起见,此处不展示完整代码,但此 Webhook 的 Hugging Face Spaces 仓库 中包含完整代码。

我们创建一个函数,用于生成 Markdown 表格,以呈现元数据覆盖字典中数据的更美观版本。

def create_metadata_breakdown_table(desired_metadata_dictionary):
    # [...]
    return tabulate(
        table_data, tablefmt="github", headers=("Metadata Field", "Provided Value")
    )

我们还有一个 Python 函数,用于生成一个分数(表示所需元数据字段中存在的百分比)

def calculate_grade(desired_metadata_dictionary):
    # [...]
    return round(score, 2)

以及一个用于创建元数据审查 Markdown 报告的 Python 函数。该报告包含评分和元数据表格,并附有对报告内容的说明。

def create_markdown_report(
    desired_metadata_dictionary, repo_name, repo_type, score, update: bool = False
):
    # [...]
    return report

如何自动发布评论?

我们现在拥有一份 Markdown 格式的元数据审查报告。我们将使用 huggingface_hub 库来发布此审查报告。我们定义了一个函数,用于接收从 Hub 获取的 Webhook 数据,解析该数据并创建元数据报告。根据之前是否已创建过报告,该函数会创建一份新报告,或在现有的元数据审查线程中发布一个新 issue。

def create_or_update_report(data):
    if parsed_post := parse_webhook_post(data):
        repo_type, repo_name = parsed_post
    else:
        return Response("Unable to parse webhook data", status_code=400)
    # [...]
    return True

:= 是 Python 3.8 版本中引入的赋值表达式运算符(俗称海象运算符)。人们对这种语法褒贬不一,而且如果你不使用它,Python 的代码求值方式并不会因此改变。你可以在这篇 Real Python 文章 中了解更多关于该运算符的信息。

创建 Webhook 以响应 Hub 上的更改

我们现在已经具备了为模型或数据集创建元数据审查报告的核心功能。下一步是使用 Webhooks 自动响应变更。

在您的用户资料中创建一个 Webhook

首先,前往 https://huggingface.co/settings/webhooks 创建你的 Webhook。

  • 输入几个目标仓库,您的 Webhook 将监听这些仓库(您可能希望将其限制为您自己的仓库或您所属组织的仓库)。
  • 输入一个密钥以增强 Webhook 的安全性(如果您不知道该选择什么,可以使用密码生成器为您的密钥生成一个足够长的随机字符串)。
  • 目前,我们可以为 Webhook URL 参数传入一个占位 URL。

您的 Webhook 将如下所示:

webhook settings

创建新的 Bot 用户配置文件

本指南将创建一个独立的用户账户,用于发布元数据审核。

Bot user account

在创建将在 Hub 上与其他用户交互的机器人时,我们要求您明确将该账户标记为“Bot”(参见个人资料截图)。

创建 Webhook 监听器

现在我们需要一种方式来监听 Webhook 事件。有许多可用的工具可以监听 Webhook 事件。许多现有服务,例如 Zapier 和 IFTTT,都可以使用 Webhook 来触发操作(例如,每次模型更新时发布一条推文)。在这种情况下,我们将使用 FastAPI 来实现我们的 Webhook 监听器。

FastAPI 是一个 Python Web 框架。我们将使用 FastAPI 来创建一个 Webhook 监听器。具体来说,我们需要实现一个路由,用于接收 /webhook 上的 POST 请求。在身份验证方面,我们将把 X-Webhook-Secret 请求头与一个 WEBHOOK_SECRET 密钥进行比较,该密钥可以在运行时传递给我们的 Docker 容器。

from fastapi import FastAPI, Request, Response
import os

KEY = os.environ.get("WEBHOOK_SECRET")

app = FastAPI()

@app.post("/webhook")
async def webhook(request: Request):
    if request.method == "POST":
        if request.headers.get("X-Webhook-Secret") != KEY:
            return Response("Invalid secret", status_code=401)
        data = await request.json()
        result = create_or_update_report(data)
        return "Webhook received!" if result else result

上述函数将接收 Webhook 事件,并为发生更改的仓库创建或更新元数据审查报告。

使用 Spaces 部署我们的 Webhook 应用

我们的 main.py 文件包含了 Webhook 应用所需的全部代码。要部署它,我们将使用一个 Space。

对于我们的 Space,我们将使用 Docker 来运行应用。Dockerfile 会复制我们的应用文件,安装所需的依赖项,并运行该应用。为了填充 KEY 变量,我们还将为 Space 设置一个 WEBHOOK_SECRET 密钥,其值为我们之前生成的密钥。有关 Docker Spaces 的更多信息,请参见此处。

最后,我们需要将 Webhook 设置中的 URL 更新为我们 Space 的 URL。我们可以从上下文菜单中获取我们 Space 的“直接 URL”。点击“嵌入此 Space”,然后复制“直接 URL”。

direct url

获取此 URL 后,我们可以将其传入 Webhook 设置中的 Webhook URL 参数。现在,当被监控的仓库发生变更时,我们的机器人应该会开始发布评论!

结论与后续步骤

我们现在有一个自动元数据审查机器人!以下是一些基于此指南进行扩展的创意:

  • 我们机器人执行的元数据审查相对粗糙;您可以添加更复杂的规则来审查元数据。
  • 您可以使用完整的 README.md 文件来进行审查。
  • 您可能希望定义一些对您的组织特别重要的“规则”,并使用 webhook 来检查这些规则是否得到遵守。

如果您使用 Webhooks 构建元数据质量应用,请通过 @davanstrien 标签联系我;我非常乐意了解相关信息!

Update on GitHub